summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Bolte <obo@openoffice.org>2009-03-03 15:05:33 +0000
committerOliver Bolte <obo@openoffice.org>2009-03-03 15:05:33 +0000
commit4304c7abdb3b7bb3a885fdbc51832daa2c4b0742 (patch)
tree0ccb305715a57e1664ca6ea2cccd94a0d63fc60f
parent14558e45e1f8bec3352443cd61ef0d1ddf6d927e (diff)
CWS-TOOLING: integrate CWS koheiformula02
2009-02-19 13:18:02 +0100 iha r268276 : #i99400# Missing value plotting broken 2009-02-11 03:39:50 +0100 kohei r267579 : forgot to add an in-line comment. 2009-02-11 00:26:03 +0100 kohei r267578 : Handle also the single cell references when exporting chart ranges. 2009-02-10 19:50:37 +0100 kohei r267576 : removed a compiler warning. 2009-02-10 06:48:55 +0100 kohei r267536 : got xls export filter to correctly write external references in charts. However, Excel doesn't entirely like my chart output if the chart contains external references. The data are all there, but it refuses to draw it. It works fine with charts with internal references. 2009-02-10 03:33:13 +0100 kohei r267533 : correctly import external references used in chart objects, by using a token array instead of a range list to represent the data ranges. 2009-02-04 15:22:30 +0100 kohei r267387 : return aRet instead of the sRangeRepresentation, just to be consistent with the rest of the code there. Both strings are empty so this is just for aesthetic reasons. 2009-02-04 15:07:49 +0100 kohei r267384 : #i98872# allow export of empty data range, in order to allow saving of documents with an empty chart. 2009-02-03 19:20:38 +0100 kohei r267340 : #i98801# added a special case handler for parsing range address syntax used by the older version of OOo. In the old syntax, the sheet name was dropped for the 2nd reference of a range if the 1st and 2nd references are on the same sheet. In the new syntax this is not the case. Also fixed unintential display of the sheet name for the end range address of a single-sheet range. 2009-01-28 20:46:11 +0100 kohei r267085 : call GetIndex() and GetString() only when the token is external ref, to avoid triggering assertions in a non-pro build. 2009-01-28 19:30:58 +0100 kohei r267080 : When listeners are being destroyed, don't bother unregistering them with the external ref manager if the document itself is being destroyed. 2009-01-28 18:56:52 +0100 kohei r267079 : fixed a heap corruption. The Table instance stores instances of FormulaToken type, not of ScAddress type. 2009-01-26 18:59:14 +0100 kohei r266945 : removed another warning on win32 build. 2009-01-26 18:50:56 +0100 kohei r266943 : removed warnings on windows build. 2009-01-26 17:16:09 +0100 kohei r266939 : added const to a returned reference value that is never used to modify its value. 2009-01-26 16:49:33 +0100 kohei r266937 : Assume that the document instance is not null, or else don't copy any data at all. 2009-01-26 16:19:50 +0100 kohei r266935 : create a clone of ScChart2DataSeqeunce without calling its copy constructor, since explicit definition of copy constructor would cause a serious compiler warning that's too ugly to fix. 2009-01-26 05:26:58 +0100 kohei r266894 : removed unused variable and changed function signature. 2009-01-26 05:02:58 +0100 kohei r266893 : removed unused variables to remove compiler warnings. 2009-01-25 18:07:31 +0100 kohei r266890 : fixed indentation inconsistencies in ctor initializers. 2009-01-25 18:01:41 +0100 kohei r266889 : * removed a compiler warning. * tab -> whitespace conversion in some code. 2009-01-25 03:57:37 +0100 kohei r266888 : removed a mis-leading comment. 2009-01-25 02:37:45 +0100 kohei r266887 : * moved the ref token join method from chart2uno local to ScRefTokenHelper. * a little code cleanup. 2009-01-24 09:29:26 +0100 kohei r266865 : Don't re-link external files if their link has been broken once. 2009-01-24 09:16:28 +0100 kohei r266864 : a typo in an in-line comment. 2009-01-24 09:14:29 +0100 kohei r266863 : Treat non-cached cells as empty cells only when the source document is not reachable. 2009-01-24 07:23:44 +0100 kohei r266862 : Don't purge the external ref cache when the link is broken. 2009-01-24 03:25:46 +0100 kohei r266861 : When a cell outside the cached range is queried, we should return an emtpy cell token instead of NULL, to be consistent with the old behavior. 2009-01-24 02:34:38 +0100 kohei r266860 : Remove corresponding listeners when an external doc link is broken. 2009-01-23 23:18:44 +0100 kohei r266856 : more work on handling external ref update listeners. 2009-01-23 18:10:09 +0100 kohei r266846 : Handle loading of chart objects when their external link is updated. 2009-01-23 06:57:34 +0100 kohei r266765 : more work on ref-tokenizing ScChartListener. 2009-01-22 22:57:52 +0100 kohei r266760 : More work on moving ref token helper code to reftokenhelper & ref-tokenizing ScChartListener. 2009-01-22 21:52:38 +0100 kohei r266758 : moved the code that converts XML range string into Calc's internal range string from chart2uno to rangeutl & compile the range string to generate ref tokens upon ods import. 2009-01-22 18:56:14 +0100 kohei r266749 : fixed a build breakage. 2009-01-22 18:53:43 +0100 kohei r266748 : Initial work toward using ref tokens in ScChartListener class. I'll start moving some of local ref token handling functions from chart2uno.cxx to ScRefTokenHelper class to make them available in other places. 2009-01-22 17:38:20 +0100 kohei r266746 : Add a big, fat warning against mixed use of ScSharedTokenRef and ScTokenRef. 2009-01-22 08:33:28 +0100 kohei r266711 : #i98338# fixed slicing of external ref token classes by adding their own Clone() method. 2009-01-22 05:02:25 +0100 kohei r266710 : Applied the same fix that npower/oj applied to fix a crasher (from #i98317#). 2009-01-21 23:02:42 +0100 kohei r266705 : fix build breakages as a result of rebase to m39. Mostly due to the new formula module and its associated changes esp. wrt token classes. 2009-01-21 19:14:40 +0100 kohei r266699 : CWS-TOOLING: rebase CWS koheiformula02 to trunk@266428 (milestone: DEV300:m39) 2009-01-21 17:55:10 +0100 kohei r266698 : moved the shared ScToken typedef to token.hxx, and use it instead of ScChart2TokenRef, since I need this typedef in the odf importer. In the future this can also replace the similar typedef in ScExternalRefManager. 2009-01-21 06:54:04 +0100 kohei r266627 : Added external ref listener framework so that objects listening to external ref changes can get notified when the link is updated. The work is not done yet. 2009-01-20 23:07:38 +0100 kohei r266626 : When exporting a range to ODF, we don't want to prepend a sheet name with '$' even for an external sheet. 2009-01-20 23:06:40 +0100 kohei r266625 : 1) code cleanup to remove compiler warnings. 2) fixed convertRangesToXML to convert ref tokens into correct ODF range format. 2009-01-20 19:40:45 +0100 kohei r266620 : extracted the code that fills cache from external ref into its own method. 2009-01-20 18:26:47 +0100 kohei r266616 : added javadoc parameter descriptions. 2009-01-20 18:01:17 +0100 kohei r266615 : disable ScChart2EmptyDataSequence entirely since that class doesn't appear to be used any more. 2009-01-20 17:42:59 +0100 kohei r266608 : fixed a crash when the data source range is empty at time of chart creation. 2009-01-20 17:13:34 +0100 kohei r266601 : a simple locale variable rename. 2009-01-20 16:57:04 +0100 kohei r266598 : #i97563# applied my patch, to fix incorrect export attempts of color values as a number formatter key, and change the condition of one assertion to prevent it from being triggered incorrectly in non-pro build. 2009-01-17 07:41:01 +0100 kohei r266458 : a little code cleanup. 2009-01-17 07:30:48 +0100 kohei r266457 : removed a method that it no longer used. 2009-01-17 07:29:15 +0100 kohei r266456 : fixed a crash when no external data is available for a given range. 2009-01-17 07:14:50 +0100 kohei r266455 : Even more work on range list to ref token migration. The chart now retains external data after editing of chart. 2009-01-16 18:54:35 +0100 kohei r266453 : More work on replacing flat ranges and addresses with ref tokens. 2009-01-16 17:07:51 +0100 kohei r266438 : extracted a large code block into its own local method. 2009-01-16 15:22:57 +0100 kohei r266423 : Initial work toward replacing the chart positioner and its related code in order to use reference tokens instead of range list. The basis of that code is the old ScChartPositioner and ScChartPositionMap duplicated to avoid breaking any existing legacy code that might still use it. It appears to be used by the StarOffice 1.0 filter only. Still not working with the external references. 2009-01-15 05:33:39 +0100 kohei r266334 : renamed chackRanges() to overlaps() to make it more descriptive of what it does. 2009-01-13 23:25:50 +0100 kohei r266260 : Moved the token-to-string conversion code up so that other parts of the code can use it. 2009-01-13 22:14:35 +0100 kohei r266256 : generateLabels() now uses reference token list. 2009-01-13 18:42:23 +0100 kohei r266246 : Finally, build data array for external data sources. This will now allow the data to be displayed in the diagram. 2009-01-13 16:34:03 +0100 kohei r266235 : We now need to verify range representation by compiling it instead of parsing it. 2009-01-13 15:41:48 +0100 kohei r266230 : cosmetic function name change & added javadoc comment for it. 2009-01-13 06:32:06 +0100 kohei r266194 : Fixed a typo. 2009-01-13 06:04:23 +0100 kohei r266193 : Generate data source range string by compiling reference tokens. This way we can also display external reference addresses correctly. 2009-01-13 05:55:44 +0100 kohei r266192 : moved compileRangeRepresentation from being a class member method to a local function. 2009-01-13 05:41:53 +0100 kohei r266191 : nuked one unused method & tab -> whitespace conversion. 2009-01-13 05:35:10 +0100 kohei r266190 : A little code cleanup & consolidated all range-joining code into a single function object class. 2009-01-13 03:58:51 +0100 kohei r266189 : removed the unused method. 2009-01-13 03:53:01 +0100 kohei r266188 : This time I (hopefully) fixed the range consolidation problem for real. I forgot to join the missing upper-left corner cell with the existing range list. Also, I needed to join ranges recursively instead of just doing it once. 2009-01-13 02:15:48 +0100 kohei r266187 : fixed the "add corner if missing" thing. 2009-01-12 23:36:19 +0100 kohei r266185 : More work on range list -> ref tokens. 2009-01-12 23:12:28 +0100 kohei r266184 : More work on switching to reference tokens from range list. Still in progress. 2009-01-10 08:15:39 +0100 kohei r266125 : More code change for switching to reference tokens, especially in ScChart2DataProvider. Created another addUpperLeftCornerIfMissing method that can take a list of reference tokens instead of range list. 2009-01-09 19:22:33 +0100 kohei r266110 : entirely removed the range list data member from ScChart2DataSequence class. From now on we will use a list of tokens to track data source ranges. Now, if I haven't introduced any bugs in the process, normal charts with no external references should work as before. But I still need to get the external refs to work. 2009-01-09 19:11:45 +0100 kohei r266108 : Convert ranges to token list before instantiating ScChart2DataSequence. 2009-01-09 18:27:13 +0100 kohei r266107 : Extracted a common code block into its own method. 2009-01-09 18:18:36 +0100 kohei r266106 : More progress on chart2uno implementation change. Still more to do. 2009-01-09 06:24:36 +0100 kohei r266043 : another place to swap the use of range list with token list. 2009-01-09 06:18:57 +0100 kohei r266042 : Started re-working the chart2uno implementation, to use a list of ScToken instances instead of ScRangeList, to keep track of data source ranges. This way, the chart2uno code can tell whether the ranges are external or internal, and act accordingly. I'm not finished with it yet. Some things are still not working. 2009-01-08 19:28:51 +0100 kohei r266034 : yet another place to hardcode CONV_OOO for cell range address parsing. 2009-01-08 19:19:21 +0100 kohei r266033 : transferred the BuildArray() method from the koheichart01 cws and its associated changes. I need to be changing code around this area, and I don't want to redo my changes once koheichart01 gets integrated for 3.2. 2009-01-08 18:07:08 +0100 kohei r266030 : Have convertRangeFromXML convert external ranges into the appropriate OOO A1 format. I also added a helper method to append a table name because this is useful in a lot of other places. 2009-01-07 06:57:52 +0100 kohei r265944 : These places also need a hard-coded CONV_OOO address convention, for Excel chart import and export to function properly. 2009-01-06 16:41:07 +0100 kohei r265932 : removed unused variable. 2009-01-06 16:30:36 +0100 kohei r265931 : removed unused ScDPCacheTable::GroupFilter::setMatchIfFound() method and its associated member variable (per Caolan's callcatcher output). I added that method to allow reverse matching in some code but later retracted that logic. I guess I forgot to remove the method itself afterwards... 2009-01-06 06:39:51 +0100 kohei r265891 : #i97735# Always write cell and cell range addresses using the OOo A1 (CONV_OOO) address convention when exporting to ODF, regardless of current address convention. Same for reading from ODF documents. 2009-01-06 05:46:40 +0100 kohei r265890 : #i94696# Use the current address convention in the chart wizard dialog.
-rw-r--r--sc/inc/chart2uno.hxx103
-rw-r--r--sc/inc/chartlis.hxx44
-rw-r--r--sc/inc/dpcachetable.hxx2
-rw-r--r--sc/inc/externalrefmgr.hxx78
-rw-r--r--sc/inc/rangeutl.hxx25
-rw-r--r--sc/inc/reftokenhelper.hxx82
-rw-r--r--sc/inc/token.hxx14
-rw-r--r--sc/inc/unonames.hxx1
-rw-r--r--sc/source/core/data/dpcachetable.cxx12
-rw-r--r--sc/source/core/tool/chartlis.cxx297
-rw-r--r--sc/source/core/tool/compiler.cxx27
-rw-r--r--sc/source/core/tool/makefile.mk2
-rw-r--r--sc/source/core/tool/rangeutl.cxx232
-rw-r--r--sc/source/core/tool/reftokenhelper.cxx440
-rw-r--r--sc/source/filter/excel/xechart.cxx119
-rw-r--r--sc/source/filter/excel/xeformula.cxx1
-rw-r--r--sc/source/filter/excel/xichart.cxx73
-rw-r--r--sc/source/filter/excel/xiformula.cxx26
-rw-r--r--sc/source/filter/inc/xichart.hxx10
-rw-r--r--sc/source/filter/inc/xiformula.hxx8
-rw-r--r--sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx2
-rw-r--r--sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx2
-rw-r--r--sc/source/filter/xml/XMLConsolidationContext.cxx4
-rw-r--r--sc/source/filter/xml/XMLDetectiveContext.cxx2
-rw-r--r--sc/source/filter/xml/XMLExportDataPilot.cxx8
-rw-r--r--sc/source/filter/xml/XMLExportDatabaseRanges.cxx8
-rw-r--r--sc/source/filter/xml/XMLStylesExportHelper.cxx2
-rw-r--r--sc/source/filter/xml/XMLTableShapeImportHelper.cxx2
-rw-r--r--sc/source/filter/xml/XMLTableShapeResizer.cxx71
-rw-r--r--sc/source/filter/xml/xmldpimp.cxx6
-rw-r--r--sc/source/filter/xml/xmldrani.cxx2
-rw-r--r--sc/source/filter/xml/xmlexprt.cxx20
-rw-r--r--sc/source/filter/xml/xmlfilti.cxx8
-rw-r--r--sc/source/filter/xml/xmlimprt.cxx13
-rw-r--r--sc/source/filter/xml/xmlsceni.cxx2
-rw-r--r--sc/source/filter/xml/xmlsorti.cxx2
-rw-r--r--sc/source/filter/xml/xmlstyle.cxx6
-rw-r--r--sc/source/filter/xml/xmltabi.cxx2
-rw-r--r--sc/source/ui/docshell/externalrefmgr.cxx165
-rw-r--r--sc/source/ui/unoobj/chart2uno.cxx3212
-rw-r--r--sc/source/ui/unoobj/docuno.cxx3
-rw-r--r--sc/source/ui/view/tabview3.cxx3
42 files changed, 4104 insertions, 1037 deletions
diff --git a/sc/inc/chart2uno.hxx b/sc/inc/chart2uno.hxx
index 7efd40e1e..288de0003 100644
--- a/sc/inc/chart2uno.hxx
+++ b/sc/inc/chart2uno.hxx
@@ -33,7 +33,11 @@
#include "cellsuno.hxx" // for XModifyListenerArr_Impl / ScLinkListener
#include "rangelst.hxx"
+#include "externalrefmgr.hxx"
+#include "token.hxx"
+
#include <svtools/lstner.hxx>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <com/sun/star/chart2/data/XDataProvider.hpp>
#include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
#include <com/sun/star/chart2/data/XDataSource.hpp>
@@ -57,8 +61,13 @@
#include <rtl/ustring.hxx>
#include <svtools/itemprop.hxx>
-#include <map>
+#include <hash_set>
#include <list>
+#include <vector>
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+#define USE_CHART2_EMPTYDATASEQUENCE 0
class ScDocument;
@@ -128,7 +137,23 @@ public:
getSupportedServiceNames() throw(
::com::sun::star::uno::RuntimeException);
- static bool addUpperLeftCornerIfMissing( ScRangeListRef& xRanges );//returns true if the corner was added
+ /**
+ * Check the current list of reference tokens, and add the upper left
+ * corner of the minimum range that encloses all ranges if certain
+ * conditions are met.
+ *
+ * @param rRefTokens list of reference tokens
+ *
+ * @return true if the corner was added, false otherwise.
+ */
+ static bool addUpperLeftCornerIfMissing(::std::vector<ScSharedTokenRef>& rRefTokens);
+
+private:
+
+ void detectRangesFromDataSource(::std::vector<ScSharedTokenRef>& rRefTokens,
+ ::com::sun::star::chart::ChartDataRowSource& rRowSource,
+ bool& rRowSourceDetected,
+ const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::data::XDataSource >& xDataSource);
private:
@@ -260,10 +285,10 @@ class ScChart2DataSequence : public
SfxListener
{
public:
-
explicit ScChart2DataSequence( ScDocument* pDoc,
const com::sun::star::uno::Reference< com::sun::star::chart2::data::XDataProvider >& xDP,
- const ScRangeListRef& rRangeList );
+ ::std::vector<ScSharedTokenRef>* pTokens);
+
virtual ~ScChart2DataSequence();
virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint );
@@ -381,28 +406,89 @@ public:
// Implementation --------------------------------------------------------
- ScRangeListRef GetRangeList() { return m_xRanges; }
-
void RefChanged();
DECL_LINK( ValueListenerHdl, SfxHint* );
private:
+ ScChart2DataSequence(); // disabled
+ ScChart2DataSequence(const ScChart2DataSequence& r); // disabled
+
+ class ExternalRefListener : public ScExternalRefManager::LinkListener
+ {
+ public:
+ ExternalRefListener(ScChart2DataSequence& rParent, ScDocument* pDoc);
+ virtual ~ExternalRefListener();
+ virtual void notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType);
+ void addFileId(sal_uInt16 nFileId);
+ void removeFileId(sal_uInt16 nFileId);
+ const ::std::hash_set<sal_uInt16>& getAllFileIds();
+
+ private:
+ ExternalRefListener();
+ ExternalRefListener(const ExternalRefListener& r);
+
+ ScChart2DataSequence& mrParent;
+ ::std::hash_set<sal_uInt16> maFileIds;
+ ScDocument* mpDoc;
+ };
+
+ /**
+ * Build an internal data array to cache the data ranges, and other
+ * information such as hidden values.
+ */
+ void BuildDataCache();
+
+ void RebuildDataCache();
+
+ sal_Int32 FillCacheFromExternalRef(const ScSharedTokenRef& pToken);
+
+ void UpdateTokensFromRanges(const ScRangeList& rRanges);
+
+ ExternalRefListener* GetExtRefListener();
+
+ void StopListeningToAllExternalRefs();
+
+ void CopyData(const ScChart2DataSequence& r);
+
+private:
+
+ // data array
+ struct Item
+ {
+ double mfValue;
+ ::rtl::OUString maString;
+ bool mbIsValue;
+ Item();
+ };
+
+ ::std::list<Item> m_aDataArray;
+ ::com::sun::star::uno::Sequence<sal_Int32> m_aHiddenValues;
// properties
::com::sun::star::chart2::data::DataSequenceRole m_aRole;
sal_Bool m_bHidden;
+
// internals
- ScRangeListRef m_xRanges;
+ typedef ::std::auto_ptr< ::std::vector<ScSharedTokenRef> > TokenListPtr;
+ typedef ::std::auto_ptr< ::std::vector<sal_uInt32> > RangeIndexMapPtr;
+ typedef ::std::auto_ptr<ExternalRefListener> ExtRefListenerPtr;
+
sal_Int64 m_nObjectId;
ScDocument* m_pDocument;
+ TokenListPtr m_pTokens;
+ RangeIndexMapPtr m_pRangeIndices;
+ ExtRefListenerPtr m_pExtRefListener;
com::sun::star::uno::Reference < com::sun::star::chart2::data::XDataProvider > m_xDataProvider;
SfxItemPropertySet m_aPropSet;
ScLinkListener* m_pValueListener;
- sal_Bool m_bGotDataChangedHint;
XModifyListenerArr_Impl m_aValueListeners;
+
+ bool m_bGotDataChangedHint;
+ bool m_bExtDataRebuildQueued;
};
+#if USE_CHART2_EMPTYDATASEQUENCE
// DataSequence ==============================================================
class ScChart2EmptyDataSequence : public
@@ -548,5 +634,6 @@ private:
sal_Bool m_bColumn; // defines the orientation to create the right labels
};
+#endif
#endif // SC_CHART2UNO_HXX
diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx
index 790071276..33650ddb4 100644
--- a/sc/inc/chartlis.hxx
+++ b/sc/inc/chartlis.hxx
@@ -36,6 +36,12 @@
#include <svtools/listener.hxx>
#include "collect.hxx"
#include "rangelst.hxx"
+#include "token.hxx"
+#include "externalrefmgr.hxx"
+
+#include <memory>
+#include <vector>
+#include <hash_set>
class ScDocument;
class ScChartUnoData;
@@ -44,8 +50,31 @@ class ScChartUnoData;
class ScChartListener : public StrData, public SvtListener
{
+public:
+ class ExternalRefListener : public ScExternalRefManager::LinkListener
+ {
+ public:
+ ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc);
+ virtual ~ExternalRefListener();
+ virtual void notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType);
+ void addFileId(sal_uInt16 nFileId);
+ void removeFileId(sal_uInt16 nFileId);
+ ::std::hash_set<sal_uInt16>& getAllFileIds();
+
+ private:
+ ExternalRefListener();
+ ExternalRefListener(const ExternalRefListener& r);
+
+ ScChartListener& mrParent;
+ ::std::hash_set<sal_uInt16> maFileIds;
+ ScDocument* mpDoc;
+ };
+
private:
- ScRangeListRef aRangeListRef;
+
+ ::std::auto_ptr<ExternalRefListener> mpExtRefListener;
+ ::std::auto_ptr< ::std::vector<ScSharedTokenRef> > mpTokens;
+
ScChartUnoData* pUnoData;
ScDocument* pDoc;
BOOL bUsed; // fuer ScChartListenerCollection::FreeUnused
@@ -57,9 +86,11 @@ private:
public:
ScChartListener( const String& rName, ScDocument* pDoc,
- const ScRange& rRange );
+ const ScRange& rRange );
+ ScChartListener( const String& rName, ScDocument* pDoc,
+ const ScRangeListRef& rRangeListRef );
ScChartListener( const String& rName, ScDocument* pDoc,
- const ScRangeListRef& rRangeListRef );
+ ::std::vector<ScSharedTokenRef>* pTokens );
ScChartListener( const ScChartListener& );
virtual ~ScChartListener();
virtual ScDataObject* Clone() const;
@@ -77,8 +108,8 @@ public:
void ChangeListening( const ScRangeListRef& rRangeListRef,
BOOL bDirty = FALSE );
void Update();
- const ScRangeListRef& GetRangeList() const { return aRangeListRef; }
- void SetRangeList( const ScRangeListRef& rNew ) { aRangeListRef = rNew; }
+ ScRangeListRef GetRangeList() const;
+ void SetRangeList( const ScRangeListRef& rNew );
void SetRangeList( const ScRange& rNew );
BOOL IsUsed() const { return bUsed; }
void SetUsed( BOOL bFlg ) { bUsed = bFlg; }
@@ -92,6 +123,9 @@ public:
void UpdateScheduledSeriesRanges();
void UpdateSeriesRanges();
+ ExternalRefListener* GetExtRefListener();
+ void SetUpdateQueue();
+
BOOL operator==( const ScChartListener& );
BOOL operator!=( const ScChartListener& r )
{ return !operator==( r ); }
diff --git a/sc/inc/dpcachetable.hxx b/sc/inc/dpcachetable.hxx
index 2b0afdcfe..051b87ed2 100644
--- a/sc/inc/dpcachetable.hxx
+++ b/sc/inc/dpcachetable.hxx
@@ -125,7 +125,6 @@ public:
virtual ~GroupFilter(){}
virtual bool match(const ScDPCacheCell& rCell) const;
- void setMatchIfFound(bool b);
void addMatchItem(const String& rStr, double fVal, bool bHasValue);
size_t getMatchItemCount() const;
@@ -134,7 +133,6 @@ public:
::std::vector<FilterItem> maItems;
ScSimpleSharedString mrSharedString;
- bool mbMatchIfFound;
};
/** single filtering criterion. */
diff --git a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx
index dacd6a8df..d20840f9d 100644
--- a/sc/inc/externalrefmgr.hxx
+++ b/sc/inc/externalrefmgr.hxx
@@ -160,16 +160,14 @@ public:
*
* @param nFileId file ID of an external document
* @param rTabName sheet name
- * @param nRow
* @param nCol
+ * @param nRow
*
- * @return pointer to the token instance in the cache. <i>The caller does
- * not need to delete this instance since its life cycle is
- * managed by this class.</i>
+ * @return pointer to the token instance in the cache.
*/
ScExternalRefCache::TokenRef getCellData(
- sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol,
- sal_uInt32* pnFmtIndex = NULL);
+ sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow,
+ bool bEmptyCellOnNull, sal_uInt32* pnFmtIndex = NULL);
/**
* Get a cached cell range data.
@@ -178,7 +176,8 @@ public:
* manage the life cycle of the returned instance</i>, which is
* guaranteed if the TokenArrayRef is properly used..
*/
- ScExternalRefCache::TokenArrayRef getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange);
+ ScExternalRefCache::TokenArrayRef getCellRangeData(
+ sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, bool bEmptyCellOnNull);
ScExternalRefCache::TokenArrayRef getRangeNameTokens(sal_uInt16 nFileId, const String& rName);
void setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray);
@@ -314,6 +313,29 @@ public:
::std::list<TabItemRef> maTables;
};
+ enum LinkUpdateType { LINK_MODIFIED, LINK_BROKEN };
+
+ /**
+ * Base class for objects that need to listen to link updates. When a
+ * link to a certain external file is updated, the notify() method gets
+ * called.
+ */
+ class LinkListener
+ {
+ public:
+ LinkListener();
+ virtual ~LinkListener() = 0;
+ virtual void notify(sal_uInt16 nFileId, LinkUpdateType eType) = 0;
+
+ struct Hash
+ {
+ size_t operator() (const LinkListener* p) const
+ {
+ return reinterpret_cast<size_t>(p);
+ }
+ };
+ };
+
private:
/** Shell instance for a source document. */
struct SrcShell
@@ -323,11 +345,15 @@ private:
};
typedef ::std::hash_map<sal_uInt16, SrcShell> DocShellMap;
- typedef ::std::hash_set<sal_uInt16> LinkedDocSet;
+ typedef ::std::hash_map<sal_uInt16, bool> LinkedDocMap;
typedef ::std::hash_map<sal_uInt16, RefCells> RefCellMap;
typedef ::std::hash_map<sal_uInt16, SvNumberFormatterMergeMap> NumFmtMap;
+
+ typedef ::std::hash_set<LinkListener*, LinkListener::Hash> LinkListeners;
+ typedef ::std::hash_map<sal_uInt16, LinkListeners> LinkListenerMap;
+
public:
/** Source document meta-data container. */
struct SrcFileData
@@ -367,7 +393,12 @@ public:
* XCT/CRN records.
*
* @param nFileId file ID
- * @param rTabName table name
+ * @param rTabName table name
+ * @param bCreateNew if true, create a new table instance if it's not
+ * already present. If false, it returns NULL if the
+ * specified table's cache doesn't exist.
+ * @param pnIndex if non-NULL pointer is passed, it stores the internal
+ * index of a cache table instance.
*
* @return shared_ptr to the cache table instance
*/
@@ -456,6 +487,7 @@ public:
const String* getRealTableName(sal_uInt16 nFileId, const String& rTabName) const;
const String* getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const;
void refreshNames(sal_uInt16 nFileId);
+ void breakLink(sal_uInt16 nFileId);
void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile);
void setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl);
@@ -470,7 +502,6 @@ public:
*/
void setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions);
- void removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink);
void clear();
bool hasExternalData() const;
@@ -510,6 +541,29 @@ public:
void updateRefDeleteTable(SCTAB nPos);
+ /**
+ * Register a new link listener to a specified external document. Note
+ * that the caller is responsible for managing the life cycle of the
+ * listener object.
+ */
+ void addLinkListener(sal_uInt16 nFileId, LinkListener* pListener);
+
+ /**
+ * Remove an existing link listener. Note that removing a listener
+ * pointer here does not delete the listener object instance.
+ */
+ void removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener);
+
+ void removeLinkListener(LinkListener* pListener);
+
+ /**
+ * Notify all listeners that are listening to a specified external
+ * document.
+ *
+ * @param nFileId file ID for an external document.
+ */
+ void notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType);
+
private:
ScExternalRefManager();
ScExternalRefManager(const ScExternalRefManager&);
@@ -549,7 +603,7 @@ private:
DocShellMap maDocShells;
/** list of source documents that are managed by the link manager. */
- LinkedDocSet maLinkedDocs;
+ LinkedDocMap maLinkedDocs;
/**
* List of referencing cells that may contain external names. There is
@@ -557,6 +611,8 @@ private:
*/
RefCellMap maRefCells;
+ LinkListenerMap maLinkListeners;
+
NumFmtMap maNumFormatMap;
/** original source file index. */
diff --git a/sc/inc/rangeutl.hxx b/sc/inc/rangeutl.hxx
index 7e74e51b5..1e8d5da1b 100644
--- a/sc/inc/rangeutl.hxx
+++ b/sc/inc/rangeutl.hxx
@@ -141,11 +141,17 @@ public:
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
+ static void AppendTableName(
+ ::rtl::OUStringBuffer& rBuf,
+ const ::rtl::OUString& rTabName,
+ sal_Unicode cQuote = '\'');
+
// String to Range core
static sal_Bool GetAddressFromString(
ScAddress& rAddress,
const ::rtl::OUString& rAddressStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -153,6 +159,7 @@ public:
ScRange& rRange,
const ::rtl::OUString& rRangeStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -160,6 +167,7 @@ public:
ScRangeList& rRangeList,
const ::rtl::OUString& rRangeListStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -167,6 +175,7 @@ public:
ScArea& rArea,
const ::rtl::OUString& rRangeStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -176,6 +185,7 @@ public:
::com::sun::star::table::CellAddress& rAddress,
const ::rtl::OUString& rAddressStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -183,6 +193,7 @@ public:
::com::sun::star::table::CellRangeAddress& rRange,
const ::rtl::OUString& rRangeStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -190,6 +201,7 @@ public:
::com::sun::star::uno::Sequence< ::com::sun::star::table::CellRangeAddress >& rRangeSeq,
const ::rtl::OUString& rRangeListStr,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Unicode cQuote = '\'');
@@ -198,6 +210,7 @@ public:
::rtl::OUString& rString,
const ScAddress& rAddress,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Bool bAppendStr = sal_False,
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
@@ -205,6 +218,7 @@ public:
::rtl::OUString& rString,
const ScRange& rRange,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Bool bAppendStr = sal_False,
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
@@ -212,6 +226,7 @@ public:
::rtl::OUString& rString,
const ScRangeList* pRangeList,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D));
@@ -219,6 +234,7 @@ public:
::rtl::OUString& rString,
const ScArea& rArea,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Bool bAppendStr = sal_False,
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
@@ -228,6 +244,7 @@ public:
::rtl::OUString& rString,
const ::com::sun::star::table::CellAddress& rAddress,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Bool bAppendStr = sal_False,
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
@@ -235,6 +252,7 @@ public:
::rtl::OUString& rString,
const ::com::sun::star::table::CellRangeAddress& rRange,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_Bool bAppendStr = sal_False,
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
@@ -242,8 +260,15 @@ public:
::rtl::OUString& rString,
const ::com::sun::star::uno::Sequence< ::com::sun::star::table::CellRangeAddress >& rRangeSeq,
const ScDocument* pDocument,
+ formula::FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator = ' ',
sal_uInt16 nFormatFlags = (SCA_VALID | SCA_TAB_3D) );
+
+// XML Range to Calc Range
+ static void GetStringFromXMLRangeString(
+ ::rtl::OUString& rString,
+ const ::rtl::OUString& rXMLRange,
+ ScDocument* pDoc );
};
//------------------------------------------------------------------------
diff --git a/sc/inc/reftokenhelper.hxx b/sc/inc/reftokenhelper.hxx
new file mode 100644
index 000000000..b1159cc4a
--- /dev/null
+++ b/sc/inc/reftokenhelper.hxx
@@ -0,0 +1,82 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: token.hxx,v $
+ * $Revision: 1.15.32.3 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SC_REFTOKENHELPER_HXX
+#define SC_REFTOKENHELPER_HXX
+
+#include "token.hxx"
+
+#include <vector>
+
+namespace rtl {
+ class OUString;
+}
+
+class ScDocument;
+class ScRange;
+class ScRangeList;
+
+class ScRefTokenHelper
+{
+private:
+ ScRefTokenHelper();
+ ScRefTokenHelper(const ScRefTokenHelper&);
+ ~ScRefTokenHelper();
+
+public:
+ /**
+ * Compile an array of reference tokens from a data source range string.
+ * The source range may consist of multiple ranges separated by ';'s.
+ */
+ static void compileRangeRepresentation(
+ ::std::vector<ScSharedTokenRef>& rRefTokens, const ::rtl::OUString& rRangeStr, ScDocument* pDoc);
+
+ static bool getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal = false);
+
+ static void getRangeListFromTokens(ScRangeList& rRangeList, const ::std::vector<ScSharedTokenRef>& pTokens);
+
+ /**
+ * Create a double reference token from a range object.
+ */
+ static void getTokenFromRange(ScSharedTokenRef& pToken, const ScRange& rRange);
+
+ static void getTokensFromRangeList(::std::vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges);
+
+ static bool isRef(const ScSharedTokenRef& pToken);
+ static bool isExternalRef(const ScSharedTokenRef& pToken);
+
+ static bool intersects(const ::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken);
+
+ static void join(::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken);
+
+ static bool getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken);
+};
+
+#endif
diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index ecbfb6934..bf804bd02 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -33,6 +33,8 @@
#include <memory>
#include <vector>
+#include <boost/shared_ptr.hpp>
+
#include "formula/opcode.hxx"
#include "refdata.hxx"
#include "scmatrix.hxx"
@@ -49,6 +51,15 @@ class ScToken;
typedef ::std::vector< ScComplexRefData > ScRefList;
typedef formula::SimpleIntrusiveReference< class ScToken > ScTokenRef;
+/**
+ * Another ref-counted token type using shared_ptr. <b>Be extra careful
+ * not to mix use of this smart pointer type with ScTokenRef</b>, since
+ * mixing them might cause a premature object deletion because the same
+ * object may be ref-counted by two different smart pointer wrappers.
+ *
+ * You have been warned.
+ */
+typedef ::boost::shared_ptr< ScToken > ScSharedTokenRef;
class SC_DLLPUBLIC ScToken : public formula::FormulaToken
{
@@ -195,6 +206,7 @@ public:
virtual const ScSingleRefData& GetSingleRef() const;
virtual ScSingleRefData& GetSingleRef();
virtual BOOL operator==( const formula::FormulaToken& rToken ) const;
+ virtual FormulaToken* Clone() const { return new ScExternalSingleRefToken(*this); }
};
@@ -220,6 +232,7 @@ public:
virtual const ScComplexRefData& GetDoubleRef() const;
virtual ScComplexRefData& GetDoubleRef();
virtual BOOL operator==( const formula::FormulaToken& rToken ) const;
+ virtual FormulaToken* Clone() const { return new ScExternalDoubleRefToken(*this); }
};
@@ -237,6 +250,7 @@ public:
virtual USHORT GetIndex() const;
virtual const String& GetString() const;
virtual BOOL operator==( const formula::FormulaToken& rToken ) const;
+ virtual FormulaToken* Clone() const { return new ScExternalNameToken(*this); }
};
diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx
index 0945c6738..20d9cb85b 100644
--- a/sc/inc/unonames.hxx
+++ b/sc/inc/unonames.hxx
@@ -610,6 +610,7 @@
// Chart2
#define SC_UNONAME_ISHIDDEN "IsHidden"
#define SC_UNONAME_ROLE "Role"
+#define SC_UNONAME_HIDDENVALUES "HiddenValues"
// Solver
#define SC_UNONAME_TIMEOUT "Timeout"
diff --git a/sc/source/core/data/dpcachetable.cxx b/sc/source/core/data/dpcachetable.cxx
index 2d4f2aa19..a27c16d9e 100644
--- a/sc/source/core/data/dpcachetable.cxx
+++ b/sc/source/core/data/dpcachetable.cxx
@@ -143,8 +143,7 @@ bool ScDPCacheTable::SingleFilter::hasValue() const
// ----------------------------------------------------------------------------
ScDPCacheTable::GroupFilter::GroupFilter(ScSimpleSharedString& rSharedString) :
- mrSharedString(rSharedString),
- mbMatchIfFound(true)
+ mrSharedString(rSharedString)
{
}
@@ -160,14 +159,9 @@ bool ScDPCacheTable::GroupFilter::match(const ScDPCacheCell& rCell) const
bMatch = (itr->mnMatchStrId == rCell.mnStrId);
if (bMatch)
- return mbMatchIfFound ? true : false;
+ return true;
}
- return mbMatchIfFound ? false : true;
-}
-
-void ScDPCacheTable::GroupFilter::setMatchIfFound(bool b)
-{
- mbMatchIfFound = b;
+ return false;
}
void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue)
diff --git a/sc/source/core/tool/chartlis.cxx b/sc/source/core/tool/chartlis.cxx
index 9bd50561d..8c4e87638 100644
--- a/sc/source/core/tool/chartlis.cxx
+++ b/sc/source/core/tool/chartlis.cxx
@@ -38,9 +38,14 @@
#include "chartlis.hxx"
#include "brdcst.hxx"
#include "document.hxx"
+#include "reftokenhelper.hxx"
using namespace com::sun::star;
-
+using ::std::vector;
+using ::std::hash_set;
+using ::std::auto_ptr;
+using ::std::unary_function;
+using ::std::for_each;
//2do: DocOption TimeOut?
//#define SC_CHARTTIMEOUT 1000 // eine Sekunde keine Aenderung/KeyEvent
@@ -70,9 +75,62 @@ public:
// === ScChartListener ================================================
+ScChartListener::ExternalRefListener::ExternalRefListener(ScChartListener& rParent, ScDocument* pDoc) :
+ mrParent(rParent), mpDoc(pDoc)
+{
+}
+
+ScChartListener::ExternalRefListener::~ExternalRefListener()
+{
+ if (!mpDoc || mpDoc->IsInDtorClear())
+ // The document is being destroyed. Do nothing.
+ return;
+
+ // Make sure to remove all pointers to this object.
+ mpDoc->GetExternalRefManager()->removeLinkListener(this);
+}
+
+void ScChartListener::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
+{
+ switch (eType)
+ {
+ case ScExternalRefManager::LINK_MODIFIED:
+ {
+ if (maFileIds.count(nFileId))
+ // We are listening to this external document. Send an update
+ // requst to the chart.
+ mrParent.SetUpdateQueue();
+ }
+ break;
+ case ScExternalRefManager::LINK_BROKEN:
+ removeFileId(nFileId);
+ break;
+ }
+}
+
+void ScChartListener::ExternalRefListener::addFileId(sal_uInt16 nFileId)
+{
+ maFileIds.insert(nFileId);
+}
+
+void ScChartListener::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
+{
+ maFileIds.erase(nFileId);
+}
+
+hash_set<sal_uInt16>& ScChartListener::ExternalRefListener::getAllFileIds()
+{
+ return maFileIds;
+}
+
+// ----------------------------------------------------------------------------
+
ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
const ScRange& rRange ) :
StrData( rName ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>),
pUnoData( NULL ),
pDoc( pDocP ),
bUsed( FALSE ),
@@ -85,7 +143,23 @@ ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
const ScRangeListRef& rRangeList ) :
StrData( rName ),
- aRangeListRef( rRangeList ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>),
+ pUnoData( NULL ),
+ pDoc( pDocP ),
+ bUsed( FALSE ),
+ bDirty( FALSE ),
+ bSeriesRangesScheduled( FALSE )
+{
+ ScRefTokenHelper::getTokensFromRangeList(*mpTokens, *rRangeList);
+}
+
+ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP, vector<ScSharedTokenRef>* pTokens ) :
+ StrData( rName ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(pTokens),
pUnoData( NULL ),
pDoc( pDocP ),
bUsed( FALSE ),
@@ -95,18 +169,34 @@ ScChartListener::ScChartListener( const String& rName, ScDocument* pDocP,
}
ScChartListener::ScChartListener( const ScChartListener& r ) :
- StrData( r ),
- SvtListener(),
- pUnoData( NULL ),
- pDoc( r.pDoc ),
- bUsed( FALSE ),
- bDirty( r.bDirty ),
- bSeriesRangesScheduled( r.bSeriesRangesScheduled )
+ StrData( r ),
+ SvtListener(),
+ mpExtRefListener(NULL),
+ mpTokens(new vector<ScSharedTokenRef>(*r.mpTokens)),
+ pUnoData( NULL ),
+ pDoc( r.pDoc ),
+ bUsed( FALSE ),
+ bDirty( r.bDirty ),
+ bSeriesRangesScheduled( r.bSeriesRangesScheduled )
{
if ( r.pUnoData )
pUnoData = new ScChartUnoData( *r.pUnoData );
- if ( r.aRangeListRef.Is() )
- aRangeListRef = new ScRangeList( *r.aRangeListRef );
+
+ if (r.mpExtRefListener.get())
+ {
+ // Re-register this new listener for the files that the old listener
+ // was listening to.
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const hash_set<sal_uInt16>& rFileIds = r.mpExtRefListener->getAllFileIds();
+ mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ pRefMgr->addLinkListener(*itr, mpExtRefListener.get());
+ mpExtRefListener->addFileId(*itr);
+ }
+ }
}
ScChartListener::~ScChartListener()
@@ -114,6 +204,16 @@ ScChartListener::~ScChartListener()
if ( HasBroadcaster() )
EndListeningTo();
delete pUnoData;
+
+ if (mpExtRefListener.get())
+ {
+ // Stop listening to all external files.
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const hash_set<sal_uInt16>& rFileIds = mpExtRefListener->getAllFileIds();
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ for (; itr != itrEnd; ++itr)
+ pRefMgr->removeLinkListener(*itr, mpExtRefListener.get());
+ }
}
ScDataObject* ScChartListener::Clone() const
@@ -144,14 +244,11 @@ uno::Reference< chart::XChartData > ScChartListener::GetUnoSource() const
return uno::Reference< chart::XChartData >();
}
-void __EXPORT ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
+void ScChartListener::Notify( SvtBroadcaster&, const SfxHint& rHint )
{
- const ScHint* p = PTR_CAST( ScHint, &rHint );
- if( p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)) )
- {
- bDirty = TRUE;
- pDoc->GetChartListenerCollection()->StartTimer();
- }
+ const ScHint* p = dynamic_cast<const ScHint*>(&rHint);
+ if (p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)))
+ SetUpdateQueue();
}
void ScChartListener::Update()
@@ -179,30 +276,109 @@ void ScChartListener::Update()
}
}
-void ScChartListener::StartListeningTo()
+ScRangeListRef ScChartListener::GetRangeList() const
+{
+ ScRangeListRef aRLRef(new ScRangeList);
+ ScRefTokenHelper::getRangeListFromTokens(*aRLRef, *mpTokens);
+ return aRLRef;
+}
+
+void ScChartListener::SetRangeList( const ScRangeListRef& rNew )
+{
+ vector<ScSharedTokenRef> aTokens;
+ ScRefTokenHelper::getTokensFromRangeList(aTokens, *rNew);
+ mpTokens->swap(aTokens);
+}
+
+void ScChartListener::SetRangeList( const ScRange& rRange )
+{
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken, rRange);
+ mpTokens->push_back(pToken);
+}
+
+namespace {
+
+class StartEndListening : public unary_function<ScSharedTokenRef, void>
{
- if ( aRangeListRef.Is() )
- for ( ScRangePtr pR = aRangeListRef->First(); pR;
- pR = aRangeListRef->Next() )
+public:
+ StartEndListening(ScDocument* pDoc, ScChartListener& rParent, bool bStart) :
+ mpDoc(pDoc), mrParent(rParent), mbStart(bStart) {}
+
+ void operator() (const ScSharedTokenRef& pToken)
+ {
+ if (!ScRefTokenHelper::isRef(pToken))
+ return;
+
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ if (bExternal)
+ {
+ sal_uInt16 nFileId = pToken->GetIndex();
+ ScExternalRefManager* pRefMgr = mpDoc->GetExternalRefManager();
+ ScChartListener::ExternalRefListener* pExtRefListener = mrParent.GetExtRefListener();
+ if (mbStart)
+ {
+ pRefMgr->addLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->addFileId(nFileId);
+ }
+ else
+ {
+ pRefMgr->removeLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->removeFileId(nFileId);
+ }
+ }
+ else
{
- if ( pR->aStart == pR->aEnd )
- pDoc->StartListeningCell( pR->aStart, this );
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal);
+ if (mbStart)
+ startListening(aRange);
else
- pDoc->StartListeningArea( *pR, this );
+ endListening(aRange);
}
+ }
+
+private:
+ void startListening(const ScRange& rRange)
+ {
+ if (rRange.aStart == rRange.aEnd)
+ mpDoc->StartListeningCell(rRange.aStart, &mrParent);
+ else
+ mpDoc->StartListeningArea(rRange, &mrParent);
+ }
+
+ void endListening(const ScRange& rRange)
+ {
+ if (rRange.aStart == rRange.aEnd)
+ mpDoc->EndListeningCell(rRange.aStart, &mrParent);
+ else
+ mpDoc->EndListeningArea(rRange, &mrParent);
+ }
+
+private:
+ ScDocument* mpDoc;
+ ScChartListener& mrParent;
+ bool mbStart;
+};
+
+}
+
+void ScChartListener::StartListeningTo()
+{
+ if (!mpTokens.get() || mpTokens->empty())
+ // no references to listen to.
+ return;
+
+ for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, true));
}
void ScChartListener::EndListeningTo()
{
- if ( aRangeListRef.Is() )
- for ( ScRangePtr pR = aRangeListRef->First(); pR;
- pR = aRangeListRef->Next() )
- {
- if ( pR->aStart == pR->aEnd )
- pDoc->EndListeningCell( pR->aStart, this );
- else
- pDoc->EndListeningArea( *pR, this );
- }
+ if (!mpTokens.get() || mpTokens->empty())
+ // no references to listen to.
+ return;
+
+ for_each(mpTokens->begin(), mpTokens->end(), StartEndListening(pDoc, *this, false));
}
@@ -217,13 +393,6 @@ void ScChartListener::ChangeListening( const ScRangeListRef& rRangeListRef,
}
-void ScChartListener::SetRangeList( const ScRange& rRange )
-{
- aRangeListRef = new ScRangeList;
- aRangeListRef->Append( rRange );
-}
-
-
void ScChartListener::UpdateScheduledSeriesRanges()
{
if ( bSeriesRangesScheduled )
@@ -236,7 +405,10 @@ void ScChartListener::UpdateScheduledSeriesRanges()
void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
{
- if ( aRangeListRef->Intersects( rRange ) )
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken, rRange);
+
+ if (ScRefTokenHelper::intersects(*mpTokens, pToken))
{
// force update (chart has to be loaded), don't use ScChartListener::Update
pDoc->UpdateChart( GetString());
@@ -246,23 +418,40 @@ void ScChartListener::UpdateChartIntersecting( const ScRange& rRange )
void ScChartListener::UpdateSeriesRanges()
{
- pDoc->SetChartRangeList( GetString(), aRangeListRef );
+ ScRangeListRef pRangeList(new ScRangeList);
+ ScRefTokenHelper::getRangeListFromTokens(*pRangeList, *mpTokens);
+ pDoc->SetChartRangeList(GetString(), pRangeList);
}
+ScChartListener::ExternalRefListener* ScChartListener::GetExtRefListener()
+{
+ if (!mpExtRefListener.get())
+ mpExtRefListener.reset(new ExternalRefListener(*this, pDoc));
+
+ return mpExtRefListener.get();
+}
+
+void ScChartListener::SetUpdateQueue()
+{
+ bDirty = true;
+ pDoc->GetChartListenerCollection()->StartTimer();
+}
BOOL ScChartListener::operator==( const ScChartListener& r )
{
- BOOL b1 = aRangeListRef.Is();
- BOOL b2 = r.aRangeListRef.Is();
- return
- pDoc == r.pDoc &&
- bUsed == r.bUsed &&
- bDirty == r.bDirty &&
- bSeriesRangesScheduled == r.bSeriesRangesScheduled &&
- GetString() == r.GetString() &&
- b1 == b2 &&
- ((!b1 && !b2) || (*aRangeListRef == *r.aRangeListRef))
- ;
+ bool b1 = (mpTokens.get() && !mpTokens->empty());
+ bool b2 = (r.mpTokens.get() && !r.mpTokens->empty());
+
+ if (pDoc != r.pDoc || bUsed != r.bUsed || bDirty != r.bDirty ||
+ bSeriesRangesScheduled != r.bSeriesRangesScheduled ||
+ GetString() != r.GetString() || b1 != b2)
+ return false;
+
+ if (!b1 && !b2)
+ // both token list instances are empty.
+ return true;
+
+ return *mpTokens == *r.mpTokens;
}
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index cf84307f2..60dad3041 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -72,6 +72,7 @@
#include "parclass.hxx"
#include "autonamecache.hxx"
#include "externalrefmgr.hxx"
+#include "rangeutl.hxx"
using namespace formula;
using namespace ::com::sun::star;
@@ -855,16 +856,6 @@ static bool lcl_getLastTabName( String& rTabName2, const String& rTabName1,
return true;
}
-static void lcl_appendTabName(::rtl::OUStringBuffer& rBuffer, const String& rTabName)
-{
- bool bQuote = (rTabName.Search(sal_Unicode(' '), 0) != STRING_NOTFOUND);
- if (bQuote)
- rBuffer.append(sal_Unicode('\''));
- rBuffer.append(rTabName);
- if (bQuote)
- rBuffer.append(sal_Unicode('\''));
-}
-
struct Convention_A1 : public ScCompiler::Convention
{
Convention_A1( FormulaGrammar::AddressConvention eConv ) : ScCompiler::Convention( eConv ) { }
@@ -1079,9 +1070,9 @@ struct ConventionOOO_A1 : public Convention_A1
rBuffer.append(sal_Unicode('\''));
rBuffer.append(sal_Unicode('#'));
- // external reference is always 3D and the sheet is absolute.
- rBuffer.append(sal_Unicode('$'));
- lcl_appendTabName(rBuffer, rTabName);
+ if (!rRef.IsTabRel())
+ rBuffer.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
rBuffer.append(sal_Unicode('.'));
}
@@ -1347,15 +1338,15 @@ struct ConventionXL
String aLastTabName;
if (!lcl_getLastTabName(aLastTabName, rTabName, rTabNames, rRef))
{
- rBuf.append(aLastTabName);
+ ScRangeStringConverter::AppendTableName(rBuf, aLastTabName);
return;
}
- lcl_appendTabName(rBuf, rTabName);
+ ScRangeStringConverter::AppendTableName(rBuf, rTabName);
if (rTabName != aLastTabName)
{
rBuf.append(sal_Unicode(':'));
- lcl_appendTabName(rBuf, aLastTabName);
+ ScRangeStringConverter::AppendTableName(rBuf, rTabName);
}
}
@@ -1542,7 +1533,7 @@ struct ConventionXL_A1 : public Convention_A1, public ConventionXL
aRef.CalcAbsIfRel(rCompiler.GetPos());
ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
- lcl_appendTabName(rBuffer, rTabName);
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
rBuffer.append(sal_Unicode('!'));
makeSingleCellStr(rBuffer, aRef);
@@ -1746,7 +1737,7 @@ struct ConventionXL_R1C1 : public ScCompiler::Convention, public ConventionXL
aRef.CalcAbsIfRel(rCompiler.GetPos());
ConventionXL::makeExternalDocStr(rBuffer, *pFullName);
- lcl_appendTabName(rBuffer, rTabName);
+ ScRangeStringConverter::AppendTableName(rBuffer, rTabName);
rBuffer.append(sal_Unicode('!'));
r1c1_add_row(rBuffer, aRef);
diff --git a/sc/source/core/tool/makefile.mk b/sc/source/core/tool/makefile.mk
index 1ad3af95a..1b5d46346 100644
--- a/sc/source/core/tool/makefile.mk
+++ b/sc/source/core/tool/makefile.mk
@@ -103,6 +103,7 @@ SLOFILES = \
$(SLO)$/refdata.obj \
$(SLO)$/reffind.obj \
$(SLO)$/refreshtimer.obj \
+ $(SLO)$/reftokenhelper.obj \
$(SLO)$/refupdat.obj \
$(SLO)$/scmatrix.obj \
$(SLO)$/sctictac.obj \
@@ -127,6 +128,7 @@ EXCEPTIONSFILES= \
$(SLO)$/interpr5.obj \
$(SLO)$/lookupcache.obj \
$(SLO)$/prnsave.obj \
+ $(SLO)$/reftokenhelper.obj \
$(SLO)$/token.obj
# [kh] POWERPC compiler problem
diff --git a/sc/source/core/tool/rangeutl.cxx b/sc/source/core/tool/rangeutl.cxx
index 5d2e6b0b1..e006e974e 100644
--- a/sc/source/core/tool/rangeutl.cxx
+++ b/sc/source/core/tool/rangeutl.cxx
@@ -45,8 +45,11 @@
#include "scresid.hxx"
#include "globstr.hrc"
#include "convuno.hxx"
+#include "externalrefmgr.hxx"
using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::formula::FormulaGrammar;
using namespace ::com::sun::star;
//------------------------------------------------------------------------
@@ -436,6 +439,16 @@ void ScRangeStringConverter::GetTokenByOffset(
}
}
+void ScRangeStringConverter::AppendTableName(OUStringBuffer& rBuf, const OUString& rTabName, sal_Unicode cQuote)
+{
+ bool bQuoted = rTabName.indexOf(sal_Unicode(' '), 0) >= 0;
+ if (bQuoted)
+ rBuf.append(cQuote);
+ rBuf.append(rTabName);
+ if (bQuoted)
+ rBuf.append(cQuote);
+}
+
sal_Int32 ScRangeStringConverter::GetTokenCount( const OUString& rString, sal_Unicode cSeperator, sal_Unicode cQuote )
{
OUString sToken;
@@ -456,6 +469,7 @@ sal_Bool ScRangeStringConverter::GetAddressFromString(
ScAddress& rAddress,
const OUString& rAddressStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator,
sal_Unicode cQuote )
@@ -463,7 +477,10 @@ sal_Bool ScRangeStringConverter::GetAddressFromString(
OUString sToken;
GetTokenByOffset( sToken, rAddressStr, nOffset, cSeperator, cQuote );
if( nOffset >= 0 )
- return ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), pDocument->GetAddressConvention() ) & SCA_VALID) == SCA_VALID);
+ {
+ if ((rAddress.Parse( sToken, const_cast<ScDocument*>(pDocument), eConv ) & SCA_VALID) == SCA_VALID)
+ return true;
+ }
return sal_False;
}
@@ -471,6 +488,7 @@ sal_Bool ScRangeStringConverter::GetRangeFromString(
ScRange& rRange,
const OUString& rRangeStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator,
sal_Unicode cQuote )
@@ -487,7 +505,7 @@ sal_Bool ScRangeStringConverter::GetRangeFromString(
{
if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
aUIString.Erase( 0, 1 );
- bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), pDocument->GetAddressConvention()) & SCA_VALID) == SCA_VALID);
+ bResult = ((rRange.aStart.Parse( aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
rRange.aEnd = rRange.aStart;
}
else
@@ -502,15 +520,17 @@ sal_Bool ScRangeStringConverter::GetRangeFromString(
aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
- bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument)) & SCA_VALID) == SCA_VALID);
+ bResult = ((rRange.Parse(aUIString, const_cast<ScDocument*> (pDocument), eConv) & SCA_VALID) == SCA_VALID);
// #i77703# chart ranges in the file format contain both sheet names, even for an external reference sheet.
// This isn't parsed by ScRange, so try to parse the two Addresses then.
if (!bResult)
+ {
bResult = ((rRange.aStart.Parse( aUIString.Copy(0, (xub_StrLen)nIndex), const_cast<ScDocument*>(pDocument),
- pDocument->GetAddressConvention()) & SCA_VALID) == SCA_VALID) &&
+ eConv) & SCA_VALID) == SCA_VALID) &&
((rRange.aEnd.Parse( aUIString.Copy((xub_StrLen)nIndex+1), const_cast<ScDocument*>(pDocument),
- pDocument->GetAddressConvention()) & SCA_VALID) == SCA_VALID);
+ eConv) & SCA_VALID) == SCA_VALID);
+ }
}
}
return bResult;
@@ -520,6 +540,7 @@ sal_Bool ScRangeStringConverter::GetRangeListFromString(
ScRangeList& rRangeList,
const OUString& rRangeListStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Unicode cQuote )
{
@@ -529,7 +550,7 @@ sal_Bool ScRangeStringConverter::GetRangeListFromString(
while( nOffset >= 0 )
{
ScRange* pRange = new ScRange;
- if( GetRangeFromString( *pRange, rRangeListStr, pDocument, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ if( GetRangeFromString( *pRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
rRangeList.Insert( pRange, LIST_APPEND );
else if (nOffset > -1)
bRet = sal_False;
@@ -544,13 +565,14 @@ sal_Bool ScRangeStringConverter::GetAreaFromString(
ScArea& rArea,
const OUString& rRangeStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator,
sal_Unicode cQuote )
{
ScRange aScRange;
sal_Bool bResult(sal_False);
- if( GetRangeFromString( aScRange, rRangeStr, pDocument, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
{
rArea.nTab = aScRange.aStart.Tab();
rArea.nColStart = aScRange.aStart.Col();
@@ -569,13 +591,14 @@ sal_Bool ScRangeStringConverter::GetAddressFromString(
table::CellAddress& rAddress,
const OUString& rAddressStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator,
sal_Unicode cQuote )
{
ScAddress aScAddress;
sal_Bool bResult(sal_False);
- if( GetAddressFromString( aScAddress, rAddressStr, pDocument, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ if( GetAddressFromString( aScAddress, rAddressStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
{
ScUnoConversion::FillApiAddress( rAddress, aScAddress );
bResult = sal_True;
@@ -587,13 +610,14 @@ sal_Bool ScRangeStringConverter::GetRangeFromString(
table::CellRangeAddress& rRange,
const OUString& rRangeStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Int32& nOffset,
sal_Unicode cSeperator,
sal_Unicode cQuote )
{
ScRange aScRange;
sal_Bool bResult(sal_False);
- if( GetRangeFromString( aScRange, rRangeStr, pDocument, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ if( GetRangeFromString( aScRange, rRangeStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
{
ScUnoConversion::FillApiRange( rRange, aScRange );
bResult = sal_True;
@@ -605,6 +629,7 @@ sal_Bool ScRangeStringConverter::GetRangeListFromString(
uno::Sequence< table::CellRangeAddress >& rRangeSeq,
const OUString& rRangeListStr,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Unicode cQuote )
{
@@ -614,7 +639,7 @@ sal_Bool ScRangeStringConverter::GetRangeListFromString(
sal_Int32 nOffset = 0;
while( nOffset >= 0 )
{
- if( GetRangeFromString( aRange, rRangeListStr, pDocument, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
+ if( GetRangeFromString( aRange, rRangeListStr, pDocument, eConv, nOffset, cSeperator, cQuote ) && (nOffset >= 0) )
{
rRangeSeq.realloc( rRangeSeq.getLength() + 1 );
rRangeSeq[ rRangeSeq.getLength() - 1 ] = aRange;
@@ -632,6 +657,7 @@ void ScRangeStringConverter::GetStringFromAddress(
OUString& rString,
const ScAddress& rAddress,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Bool bAppendStr,
sal_uInt16 nFormatFlags )
@@ -639,7 +665,7 @@ void ScRangeStringConverter::GetStringFromAddress(
if (pDocument && pDocument->HasTable(rAddress.Tab()))
{
String sAddress;
- rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, pDocument->GetAddressConvention() );
+ rAddress.Format( sAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
AssignString( rString, sAddress, bAppendStr, cSeperator );
}
}
@@ -648,6 +674,7 @@ void ScRangeStringConverter::GetStringFromRange(
OUString& rString,
const ScRange& rRange,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Bool bAppendStr,
sal_uInt16 nFormatFlags )
@@ -658,7 +685,6 @@ void ScRangeStringConverter::GetStringFromRange(
ScAddress aEndAddress( rRange.aEnd );
String sStartAddress;
String sEndAddress;
- formula::FormulaGrammar::AddressConvention eConv = pDocument->GetAddressConvention();
aStartAddress.Format( sStartAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
aEndAddress.Format( sEndAddress, nFormatFlags, (ScDocument*) pDocument, eConv );
OUString sOUStartAddress( sStartAddress );
@@ -672,6 +698,7 @@ void ScRangeStringConverter::GetStringFromRangeList(
OUString& rString,
const ScRangeList* pRangeList,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_uInt16 nFormatFlags )
{
@@ -683,7 +710,7 @@ void ScRangeStringConverter::GetStringFromRangeList(
{
const ScRange* pRange = pRangeList->GetObject( nIndex );
if( pRange )
- GetStringFromRange( sRangeListStr, *pRange, pDocument, cSeperator, sal_True, nFormatFlags );
+ GetStringFromRange( sRangeListStr, *pRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
}
}
rString = sRangeListStr;
@@ -696,12 +723,13 @@ void ScRangeStringConverter::GetStringFromArea(
OUString& rString,
const ScArea& rArea,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Bool bAppendStr,
sal_uInt16 nFormatFlags )
{
ScRange aRange( rArea.nColStart, rArea.nRowStart, rArea.nTab, rArea.nColEnd, rArea.nRowEnd, rArea.nTab );
- GetStringFromRange( rString, aRange, pDocument, cSeperator, bAppendStr, nFormatFlags );
+ GetStringFromRange( rString, aRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
}
@@ -711,31 +739,34 @@ void ScRangeStringConverter::GetStringFromAddress(
OUString& rString,
const table::CellAddress& rAddress,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Bool bAppendStr,
sal_uInt16 nFormatFlags )
{
ScAddress aScAddress( static_cast<SCCOL>(rAddress.Column), static_cast<SCROW>(rAddress.Row), rAddress.Sheet );
- GetStringFromAddress( rString, aScAddress, pDocument, cSeperator, bAppendStr, nFormatFlags );
+ GetStringFromAddress( rString, aScAddress, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
}
void ScRangeStringConverter::GetStringFromRange(
OUString& rString,
const table::CellRangeAddress& rRange,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_Bool bAppendStr,
sal_uInt16 nFormatFlags )
{
ScRange aScRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), rRange.Sheet,
static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), rRange.Sheet );
- GetStringFromRange( rString, aScRange, pDocument, cSeperator, bAppendStr, nFormatFlags );
+ GetStringFromRange( rString, aScRange, pDocument, eConv, cSeperator, bAppendStr, nFormatFlags );
}
void ScRangeStringConverter::GetStringFromRangeList(
OUString& rString,
const uno::Sequence< table::CellRangeAddress >& rRangeSeq,
const ScDocument* pDocument,
+ FormulaGrammar::AddressConvention eConv,
sal_Unicode cSeperator,
sal_uInt16 nFormatFlags )
{
@@ -744,11 +775,178 @@ void ScRangeStringConverter::GetStringFromRangeList(
for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
{
const table::CellRangeAddress& rRange = rRangeSeq[ nIndex ];
- GetStringFromRange( sRangeListStr, rRange, pDocument, cSeperator, sal_True, nFormatFlags );
+ GetStringFromRange( sRangeListStr, rRange, pDocument, eConv, cSeperator, sal_True, nFormatFlags );
}
rString = sRangeListStr;
}
+static void lcl_appendCellAddress(
+ rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell,
+ const ScAddress::ExternalInfo& rExtInfo)
+{
+ if (rExtInfo.mbExternal)
+ {
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo.mnFileId);
+ if (!pFilePath)
+ return;
+
+ sal_Unicode cQuote = '\'';
+ rBuf.append(cQuote);
+ rBuf.append(*pFilePath);
+ rBuf.append(cQuote);
+ rBuf.append(sal_Unicode('#'));
+ rBuf.append(sal_Unicode('$'));
+ ScRangeStringConverter::AppendTableName(rBuf, rExtInfo.maTabName);
+ rBuf.append(sal_Unicode('.'));
+
+ String aAddr;
+ rCell.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+ else
+ {
+ String aAddr;
+ rCell.Format(aAddr, SCA_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+}
+
+static void lcl_appendCellRangeAddress(
+ rtl::OUStringBuffer& rBuf, ScDocument* pDoc, const ScAddress& rCell1, const ScAddress& rCell2,
+ const ScAddress::ExternalInfo& rExtInfo1, const ScAddress::ExternalInfo& rExtInfo2)
+{
+ if (rExtInfo1.mbExternal)
+ {
+ DBG_ASSERT(rExtInfo2.mbExternal, "2nd address is not external!?");
+ DBG_ASSERT(rExtInfo1.mnFileId == rExtInfo2.mnFileId, "File IDs do not match between 1st and 2nd addresses.");
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ const String* pFilePath = pRefMgr->getExternalFileName(rExtInfo1.mnFileId);
+ if (!pFilePath)
+ return;
+
+ sal_Unicode cQuote = '\'';
+ rBuf.append(cQuote);
+ rBuf.append(*pFilePath);
+ rBuf.append(cQuote);
+ rBuf.append(sal_Unicode('#'));
+ rBuf.append(sal_Unicode('$'));
+ rBuf.append(rExtInfo1.maTabName);
+ rBuf.append(sal_Unicode('.'));
+
+ String aAddr;
+ rCell1.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+
+ rBuf.appendAscii(":");
+
+ if (rExtInfo1.maTabName != rExtInfo2.maTabName)
+ {
+ rBuf.append(sal_Unicode('$'));
+ rBuf.append(rExtInfo2.maTabName);
+ rBuf.append(sal_Unicode('.'));
+ }
+
+ rCell2.Format(aAddr, SCA_ABS, NULL, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+ else
+ {
+ ScRange aRange;
+ aRange.aStart = rCell1;
+ aRange.aEnd = rCell2;
+ String aAddr;
+ aRange.Format(aAddr, SCR_ABS_3D, pDoc, ::formula::FormulaGrammar::CONV_OOO);
+ rBuf.append(aAddr);
+ }
+}
+
+void ScRangeStringConverter::GetStringFromXMLRangeString( OUString& rString, const OUString& rXMLRange, ScDocument* pDoc )
+{
+ const sal_Unicode cSep = ' ';
+ const sal_Unicode cQuote = '\'';
+
+ OUStringBuffer aRetStr;
+ sal_Int32 nOffset = 0;
+ bool bFirst = true;
+
+ while (nOffset >= 0)
+ {
+ OUString aToken;
+ GetTokenByOffset(aToken, rXMLRange, nOffset, cSep, cQuote);
+ if (nOffset < 0)
+ break;
+
+ sal_Int32 nSepPos = IndexOf(aToken, ':', 0, cQuote);
+ if (nSepPos >= 0)
+ {
+ // Cell range
+ OUString aBeginCell = aToken.copy(0, nSepPos);
+ OUString aEndCell = aToken.copy(nSepPos+1);
+
+ if (!aBeginCell.getLength() || !aEndCell.getLength())
+ // both cell addresses must exist for this to work.
+ continue;
+
+ if (aEndCell.getStr()[0] == '.')
+ {
+ // workaround for old syntax (probably pre-chart2 age?)
+ // e.g. Sheet1.A1:.B2
+ sal_Int32 nDotPos = IndexOf(aBeginCell, sal_Unicode('.'), 0, cQuote);
+ OUString aTabName = aBeginCell.copy(0, nDotPos);
+ aEndCell = aTabName + aEndCell;
+ }
+
+ ScAddress::ExternalInfo aExtInfo1, aExtInfo2;
+ ScAddress aCell1, aCell2;
+ rtl::OUString aBuf;
+ USHORT nRet = aCell1.Parse(aBeginCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo1);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ // first cell is invalid.
+ continue;
+
+ nRet = aCell2.Parse(aEndCell, pDoc, FormulaGrammar::CONV_OOO, &aExtInfo2);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ // second cell is invalid.
+ continue;
+
+ if (aExtInfo1.mnFileId != aExtInfo2.mnFileId || aExtInfo1.mbExternal != aExtInfo2.mbExternal)
+ // external info inconsistency.
+ continue;
+
+ // All looks good!
+
+ if (bFirst)
+ bFirst = false;
+ else
+ aRetStr.appendAscii(";");
+
+ lcl_appendCellRangeAddress(aRetStr, pDoc, aCell1, aCell2, aExtInfo1, aExtInfo2);
+ }
+ else
+ {
+ // Chart always saves ranges using CONV_OOO convention.
+ ScAddress::ExternalInfo aExtInfo;
+ ScAddress aCell;
+ USHORT nRet = aCell.Parse(aToken, pDoc, ::formula::FormulaGrammar::CONV_OOO, &aExtInfo);
+ if ((nRet & SCA_VALID) != SCA_VALID)
+ continue;
+
+ // Looks good!
+
+ if (bFirst)
+ bFirst = false;
+ else
+ aRetStr.appendAscii(";");
+
+ lcl_appendCellAddress(aRetStr, pDoc, aCell, aExtInfo);
+ }
+ }
+
+ rString = aRetStr.makeStringAndClear();
+}
+
//========================================================================
ScArea::ScArea( SCTAB tab,
diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx
new file mode 100644
index 000000000..c8c978fa5
--- /dev/null
+++ b/sc/source/core/tool/reftokenhelper.cxx
@@ -0,0 +1,440 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: token.hxx,v $
+ * $Revision: 1.15.32.3 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+#include "reftokenhelper.hxx"
+#include "document.hxx"
+#include "rangeutl.hxx"
+#include "compiler.hxx"
+#include "tokenarray.hxx"
+
+#include "rtl/ustring.hxx"
+#include "formula/grammar.hxx"
+#include "formula/token.hxx"
+
+using namespace formula;
+
+using ::std::vector;
+using ::std::auto_ptr;
+using ::rtl::OUString;
+
+void ScRefTokenHelper::compileRangeRepresentation(
+ vector<ScSharedTokenRef>& rRefTokens, const OUString& rRangeStr, ScDocument* pDoc)
+{
+ const sal_Unicode cSep = ';';
+ const sal_Unicode cQuote = '\'';
+
+ sal_Int32 nOffset = 0;
+ while (nOffset >= 0)
+ {
+ OUString aToken;
+ ScRangeStringConverter::GetTokenByOffset(aToken, rRangeStr, nOffset, cSep, cQuote);
+ if (nOffset < 0)
+ break;
+
+ ScCompiler aCompiler(pDoc, ScAddress(0,0,0));
+ aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
+ auto_ptr<ScTokenArray> pArray(aCompiler.CompileString(aToken));
+
+ // There should only be one reference per range token.
+ pArray->Reset();
+ FormulaToken* p = pArray->GetNextReference();
+ if (!p)
+ continue;
+
+ rRefTokens.push_back(
+ ScSharedTokenRef(static_cast<ScToken*>(p->Clone())));
+#if 0
+ switch (p->GetType())
+ {
+ case svSingleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: single ref\n");
+ break;
+ case svDoubleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: double ref\n");
+ break;
+ case svExternalSingleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external single ref\n");
+ break;
+ case svExternalDoubleRef:
+ fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external double ref\n");
+ break;
+ default:
+ ;
+ }
+#endif
+ }
+}
+
+bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal)
+{
+ StackVar eType = pToken->GetType();
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ if ((eType == svExternalSingleRef && !bExternal) ||
+ (eType == svSingleRef && bExternal))
+ return false;
+
+ const ScSingleRefData& rRefData = pToken->GetSingleRef();
+ rRange.aStart.SetCol(rRefData.nCol);
+ rRange.aStart.SetRow(rRefData.nRow);
+ rRange.aStart.SetTab(rRefData.nTab);
+ rRange.aEnd = rRange.aStart;
+ return true;
+ }
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ if ((eType == svExternalDoubleRef && !bExternal) ||
+ (eType == svDoubleRef && bExternal))
+ return false;
+
+ const ScComplexRefData& rRefData = pToken->GetDoubleRef();
+ rRange.aStart.SetCol(rRefData.Ref1.nCol);
+ rRange.aStart.SetRow(rRefData.Ref1.nRow);
+ rRange.aStart.SetTab(rRefData.Ref1.nTab);
+ rRange.aEnd.SetCol(rRefData.Ref2.nCol);
+ rRange.aEnd.SetRow(rRefData.Ref2.nRow);
+ rRange.aEnd.SetTab(rRefData.Ref2.nTab);
+ return true;
+ }
+ break;
+ default:
+ ; // do nothing
+ }
+ return false;
+}
+
+void ScRefTokenHelper::getRangeListFromTokens(ScRangeList& rRangeList, const vector<ScSharedTokenRef>& rTokens)
+{
+ vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ ScRange aRange;
+ getRangeFromToken(aRange, *itr);
+ rRangeList.Append(aRange);
+ }
+}
+
+void ScRefTokenHelper::getTokenFromRange(ScSharedTokenRef& pToken, const ScRange& rRange)
+{
+ ScComplexRefData aData;
+ aData.InitFlags();
+ aData.Ref1.nCol = rRange.aStart.Col();
+ aData.Ref1.nRow = rRange.aStart.Row();
+ aData.Ref1.nTab = rRange.aStart.Tab();
+ aData.Ref1.SetColRel(false);
+ aData.Ref1.SetRowRel(false);
+ aData.Ref1.SetTabRel(false);
+ aData.Ref1.SetFlag3D(true);
+
+ aData.Ref2.nCol = rRange.aEnd.Col();
+ aData.Ref2.nRow = rRange.aEnd.Row();
+ aData.Ref2.nTab = rRange.aEnd.Tab();
+ aData.Ref2.SetColRel(false);
+ aData.Ref2.SetRowRel(false);
+ aData.Ref2.SetTabRel(false);
+ // Display sheet name on 2nd reference only when the 1st and 2nd refs are on
+ // different sheets.
+ aData.Ref2.SetFlag3D(aData.Ref1.nTab != aData.Ref2.nTab);
+
+ pToken.reset(new ScDoubleRefToken(aData));
+}
+
+void ScRefTokenHelper::getTokensFromRangeList(vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges)
+{
+ vector<ScSharedTokenRef> aTokens;
+ sal_uInt32 nCount = rRanges.Count();
+ aTokens.reserve(nCount);
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i));
+ if (!pRange)
+ // failed.
+ return;
+
+ ScSharedTokenRef pToken;
+ ScRefTokenHelper::getTokenFromRange(pToken,* pRange);
+ aTokens.push_back(pToken);
+ }
+ pTokens.swap(aTokens);
+}
+
+bool ScRefTokenHelper::isRef(const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool ScRefTokenHelper::isExternalRef(const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+bool ScRefTokenHelper::intersects(const vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+{
+ if (!isRef(pToken))
+ return false;
+
+ bool bExternal = isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+
+ ScRange aRange;
+ getRangeFromToken(aRange, pToken, bExternal);
+
+ vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ const ScSharedTokenRef& p = *itr;
+ if (!isRef(p))
+ continue;
+
+ if (bExternal != isExternalRef(p))
+ continue;
+
+ ScRange aRange2;
+ getRangeFromToken(aRange2, p, bExternal);
+
+ if (bExternal && nFileId != p->GetIndex())
+ // different external file
+ continue;
+
+ if (aRange.Intersects(aRange2))
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class JoinRefTokenRanges
+{
+public:
+ /**
+ * Insert a new reference token into the existing list of reference tokens,
+ * but in that process, try to join as many adjacent ranges as possible.
+ *
+ * @param rTokens existing list of reference tokens
+ * @param rToken new token
+ */
+ void operator() (vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+ {
+ join(rTokens, pToken);
+ }
+
+private:
+
+ /**
+ * Check two 1-dimensional ranges to see if they overlap each other.
+ *
+ * @param nMin1 min value of range 1
+ * @param nMax1 max value of range 1
+ * @param nMin2 min value of range 2
+ * @param nMax2 max value of range 2
+ * @param rNewMin min value of new range in case they overlap
+ * @param rNewMax max value of new range in case they overlap
+ */
+ template<typename T>
+ static bool overlaps(T nMin1, T nMax1, T nMin2, T nMax2, T& rNewMin, T& rNewMax)
+ {
+ bool bDisjoint1 = (nMin1 > nMax2) && (nMin1 - nMax2 > 1);
+ bool bDisjoint2 = (nMin2 > nMax1) && (nMin2 - nMax1 > 1);
+ if (bDisjoint1 && bDisjoint2)
+ // These two ranges cannot be joined. Move on.
+ return false;
+
+ T nMin = nMin1 < nMin2 ? nMin1 : nMin2;
+ T nMax = nMax1 > nMax2 ? nMax1 : nMax2;
+
+ rNewMin = nMin;
+ rNewMax = nMax;
+
+ return true;
+ }
+
+ bool isContained(const ScComplexRefData& aOldData, const ScComplexRefData& aData) const
+ {
+ // Check for containment.
+ bool bRowsContained = (aOldData.Ref1.nRow <= aData.Ref1.nRow) && (aData.Ref2.nRow <= aOldData.Ref2.nRow);
+ bool bColsContained = (aOldData.Ref1.nCol <= aData.Ref1.nCol) && (aData.Ref2.nCol <= aOldData.Ref2.nCol);
+ return (bRowsContained && bColsContained);
+ }
+
+ void join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+ {
+ // Normalize the token to a double reference.
+ ScComplexRefData aData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken))
+ return;
+
+ // Get the information of the new token.
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ String aTabName = bExternal ? pToken->GetString() : String();
+
+ bool bJoined = false;
+ vector<ScSharedTokenRef>::iterator itr = rTokens.begin(), itrEnd = rTokens.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ ScSharedTokenRef& pOldToken = *itr;
+
+ if (!ScRefTokenHelper::isRef(pOldToken))
+ // A non-ref token should not have been added here in the first
+ // place!
+ continue;
+
+ if (bExternal != ScRefTokenHelper::isExternalRef(pOldToken))
+ // External and internal refs don't mix.
+ continue;
+
+ if (bExternal)
+ {
+ if (nFileId != pOldToken->GetIndex())
+ // Different external files.
+ continue;
+
+ if (aTabName != pOldToken->GetString())
+ // Different table names.
+ continue;
+ }
+
+ ScComplexRefData aOldData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aOldData, pOldToken))
+ continue;
+
+ if (aData.Ref1.nTab != aOldData.Ref1.nTab || aData.Ref2.nTab != aOldData.Ref2.nTab)
+ // Sheet ranges differ.
+ continue;
+
+ if (isContained(aOldData, aData))
+ // This new range is part of an existing range. Skip it.
+ return;
+
+ bool bSameRows = (aData.Ref1.nRow == aOldData.Ref1.nRow) && (aData.Ref2.nRow == aOldData.Ref2.nRow);
+ bool bSameCols = (aData.Ref1.nCol == aOldData.Ref1.nCol) && (aData.Ref2.nCol == aOldData.Ref2.nCol);
+ ScComplexRefData aNewData = aOldData;
+ bool bJoinRanges = false;
+ if (bSameRows)
+ {
+ bJoinRanges = overlaps(
+ aData.Ref1.nCol, aData.Ref2.nCol, aOldData.Ref1.nCol, aOldData.Ref2.nCol,
+ aNewData.Ref1.nCol, aNewData.Ref2.nCol);
+ }
+ else if (bSameCols)
+ {
+ bJoinRanges = overlaps(
+ aData.Ref1.nRow, aData.Ref2.nRow, aOldData.Ref1.nRow, aOldData.Ref2.nRow,
+ aNewData.Ref1.nRow, aNewData.Ref2.nRow);
+ }
+
+ if (bJoinRanges)
+ {
+ if (bExternal)
+ pOldToken.reset(new ScExternalDoubleRefToken(nFileId, aTabName, aNewData));
+ else
+ pOldToken.reset(new ScDoubleRefToken(aNewData));
+
+ bJoined = true;
+ break;
+ }
+ }
+
+ if (bJoined)
+ {
+ if (rTokens.size() == 1)
+ // There is only one left. No need to do more joining.
+ return;
+
+ // Pop the last token from the list, and keep joining recursively.
+ ScSharedTokenRef p = rTokens.back();
+ rTokens.pop_back();
+ join(rTokens, p);
+ }
+ else
+ rTokens.push_back(pToken);
+ }
+};
+
+}
+
+void ScRefTokenHelper::join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
+{
+ JoinRefTokenRanges join;
+ join(rTokens, pToken);
+}
+
+bool ScRefTokenHelper::getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken)
+{
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& r = pToken->GetSingleRef();
+ rData.Ref1 = r;
+ rData.Ref1.SetFlag3D(true);
+ rData.Ref2 = r;
+ rData.Ref2.SetFlag3D(false); // Don't display sheet name on second reference.
+ }
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ rData = pToken->GetDoubleRef();
+ break;
+ default:
+ // Not a reference token. Bail out.
+ return false;
+ }
+ return true;
+}
diff --git a/sc/source/filter/excel/xechart.cxx b/sc/source/filter/excel/xechart.cxx
index eaf943791..211aed3fd 100644
--- a/sc/source/filter/excel/xechart.cxx
+++ b/sc/source/filter/excel/xechart.cxx
@@ -64,6 +64,9 @@
#include "xehelper.hxx"
#include "xepage.hxx"
#include "xestyle.hxx"
+#include "compiler.hxx"
+#include "tokenarray.hxx"
+#include "token.hxx"
using ::rtl::OUString;
using ::com::sun::star::uno::Any;
@@ -645,6 +648,40 @@ XclExpChFrameRef lclCreateFrame( const XclExpChRoot& rRoot,
return xFrame;
}
+void lclAddDoubleRefData(ScTokenArray& rArray, const ::formula::FormulaToken& rToken,
+ SCsTAB nTab1, SCsTAB nTab2, SCsCOL nCol1, SCsCOL nCol2, SCsROW nRow1, SCsROW nRow2)
+{
+ using namespace ::formula;
+
+ StackVar eType = rToken.GetType();
+ bool bExternal = (eType == svExternalDoubleRef);
+ DBG_ASSERT(eType == svDoubleRef || eType == svExternalDoubleRef, "not a double ref token!");
+
+ ScComplexRefData aData;
+
+ aData.InitFlags();
+ aData.Ref1.SetFlag3D(true);
+ aData.Ref1.SetTabRel(false);
+ aData.Ref1.SetColRel(false);
+ aData.Ref1.SetRowRel(false);
+ aData.Ref2.SetFlag3D(false);
+ aData.Ref2.SetTabRel(false);
+ aData.Ref2.SetColRel(false);
+ aData.Ref2.SetRowRel(false);
+
+ aData.Ref1.nTab = nTab1;
+ aData.Ref1.nCol = nCol1;
+ aData.Ref1.nRow = nRow1;
+ aData.Ref2.nTab = nTab2;
+ aData.Ref2.nCol = nCol2;
+ aData.Ref2.nRow = nRow2;
+
+ if (bExternal)
+ rArray.AddExternalDoubleReference(rToken.GetIndex(), rToken.GetString(), aData);
+ else
+ rArray.AddDoubleReference(aData);
+}
+
} // namespace
// Source links ===============================================================
@@ -659,39 +696,79 @@ XclExpChSourceLink::XclExpChSourceLink( const XclExpChRoot& rRoot, sal_uInt8 nDe
sal_uInt16 XclExpChSourceLink::ConvertDataSequence( Reference< XDataSequence > xDataSeq, bool bSplitToColumns, sal_uInt16 nDefCount )
{
+ using namespace ::formula;
+
mxLinkFmla.reset();
maData.mnLinkType = EXC_CHSRCLINK_DEFAULT;
sal_uInt16 nValueCount = nDefCount;
- if( xDataSeq.is() )
- {
- OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
- ScRangeList aScRanges;
- if( ScRangeStringConverter::GetRangeListFromString( aScRanges, aRangeRepr, GetDocPtr(), ';' ) )
+ if (!xDataSeq.is())
+ return nValueCount;
+
+ // Compile the range representation string into token array.
+ OUString aRangeRepr = xDataSeq->getSourceRangeRepresentation();
+ ScRangeList aScRanges;
+ ScCompiler aComp(GetDocPtr(), ScAddress());
+ aComp.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
+ ScTokenArray* pArray = aComp.CompileString(aRangeRepr);
+ if (!pArray)
+ return nValueCount;
+
+ ScTokenArray aArray;
+ pArray->Reset();
+ bool bFirst = true;
+ for (const FormulaToken* p = pArray->First(); p; p = pArray->Next())
+ {
+ StackVar eType = p->GetType();
+ if (eType == svSingleRef || eType == svExternalSingleRef)
+ {
+ // For a single ref token, just add it to the new token array as is.
+ if (bFirst)
+ bFirst = false;
+ else
+ aArray.AddOpCode(ocUnion);
+
+ aArray.AddToken(*p);
+ }
+
+ if (eType != svDoubleRef && eType != svExternalDoubleRef)
+ continue;
+
+ // split 3-dimensional ranges into single sheets.
+ const ScComplexRefData& r = static_cast<const ScToken*>(p)->GetDoubleRef();
+ const ScSingleRefData& s = r.Ref1;
+ const ScSingleRefData& e = r.Ref2;
+ for (SCsTAB nTab = s.nTab; nTab <= e.nTab; ++nTab)
{
- // split 3-dimensional ranges into single sheets
- ScRangeList aNewScRanges;
- for( const ScRange* pScRange = aScRanges.First(); pScRange; pScRange = aScRanges.Next() )
+ if (bSplitToColumns && (s.nRow != e.nRow))
{
- SCCOL nScCol1 = pScRange->aStart.Col();
- SCROW nScRow1 = pScRange->aStart.Row();
- SCCOL nScCol2 = pScRange->aEnd.Col();
- SCROW nScRow2 = pScRange->aEnd.Row();
- for( SCTAB nScTab = pScRange->aStart.Tab(); nScTab <= pScRange->aEnd.Tab(); ++nScTab )
+ // split 2-dimensional ranges into single columns.
+ for (SCsCOL nCol = s.nCol; nCol <= e.nCol; ++nCol)
{
- // split 2-dimensional ranges into single columns
- if( bSplitToColumns && (nScRow1 != nScRow2) )
- for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
- aNewScRanges.Append( ScRange( nScCol, nScRow1, nScTab, nScCol, nScRow2, nScTab ) );
+ if (bFirst)
+ bFirst = false;
else
- aNewScRanges.Append( ScRange( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab ) );
+ aArray.AddOpCode(ocUnion);
+
+ lclAddDoubleRefData(aArray, *p, nTab, nTab, nCol, nCol, s.nRow, e.nRow);
}
}
- mxLinkFmla = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CHART, aNewScRanges );
- maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
- nValueCount = ulimit_cast< sal_uInt16 >( aScRanges.GetCellCount(), EXC_CHDATAFORMAT_MAXPOINTCOUNT );
+ else
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ aArray.AddOpCode(ocUnion);
+
+ lclAddDoubleRefData(aArray, *p, nTab, nTab, s.nCol, e.nCol, s.nRow, e.nRow);
+ }
}
}
+
+ const ScAddress aBaseCell(0,0,0);
+ mxLinkFmla = GetFormulaCompiler().CreateFormula(EXC_FMLATYPE_CHART, aArray, &aBaseCell);
+ maData.mnLinkType = EXC_CHSRCLINK_WORKSHEET;
+ nValueCount = ulimit_cast< sal_uInt16 >( aScRanges.GetCellCount(), EXC_CHDATAFORMAT_MAXPOINTCOUNT );
return nValueCount;
}
diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 740d28c3a..6767ad295 100644
--- a/sc/source/filter/excel/xeformula.cxx
+++ b/sc/source/filter/excel/xeformula.cxx
@@ -609,6 +609,7 @@ void XclExpFmlaCompImpl::Init( XclFormulaType eType, const ScTokenArray& rScTokA
{
case EXC_FMLATYPE_CELL:
case EXC_FMLATYPE_MATRIX:
+ case EXC_FMLATYPE_CHART:
mbOk = pScBasePos != 0;
DBG_ASSERT( mbOk, "XclExpFmlaCompImpl::Init - missing cell address" );
mpScBasePos = pScBasePos;
diff --git a/sc/source/filter/excel/xichart.cxx b/sc/source/filter/excel/xichart.cxx
index 054da3a08..8364ccf9b 100644
--- a/sc/source/filter/excel/xichart.cxx
+++ b/sc/source/filter/excel/xichart.cxx
@@ -72,8 +72,12 @@
#include "xipage.hxx"
#include "xiview.hxx"
#include "xiescher.hxx"
+#include "tokenarray.hxx"
+#include "token.hxx"
+#include "compiler.hxx"
using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
@@ -111,6 +115,9 @@ using ::com::sun::star::chart2::data::XDataSink;
using ::com::sun::star::chart2::data::XLabeledDataSequence;
using ::com::sun::star::chart2::data::XDataSequence;
+using ::formula::FormulaToken;
+using ::formula::StackVar;
+
// Helpers ====================================================================
namespace {
@@ -626,7 +633,8 @@ Reference< XLabeledDataSequence > lclCreateLabeledDataSequence(
// ----------------------------------------------------------------------------
XclImpChSourceLink::XclImpChSourceLink( const XclImpChRoot& rRoot ) :
- XclImpChRoot( rRoot )
+ XclImpChRoot( rRoot ),
+ mpTokenArray(static_cast<ScTokenArray*>(NULL))
{
}
@@ -637,16 +645,18 @@ void XclImpChSourceLink::ReadChSourceLink( XclImpStream& rStrm )
>> maData.mnFlags
>> maData.mnNumFmtIdx;
- maScRanges.Clear();
-
if( GetLinkType() == EXC_CHSRCLINK_WORKSHEET )
{
// read token array
XclTokenArray aXclTokArr;
rStrm >> aXclTokArr;
- // convert token array to range list
- // FIXME: JEG : This is wrong. It should be a formula
- GetFormulaCompiler().CreateRangeList( maScRanges, EXC_FMLATYPE_CHART, aXclTokArr, rStrm );
+
+ // convert xcl formula tokens to Calc's.
+ const ScTokenArray* pTokenArray =
+ GetFormulaCompiler().CreateFormula(EXC_FMLATYPE_CHART, aXclTokArr);
+
+ if (pTokenArray)
+ mpTokenArray.reset(pTokenArray->Clone());
}
// try to read a following CHSTRING record
@@ -671,6 +681,41 @@ void XclImpChSourceLink::SetTextFormats( const XclFormatRunVec& rFormats )
mxString->SetFormats( rFormats );
}
+sal_uInt16 XclImpChSourceLink::GetCellCount() const
+{
+ using namespace ::formula;
+
+ sal_uInt32 nCellCount = 0;
+ mpTokenArray->Reset();
+ for (const FormulaToken* p = mpTokenArray->First(); p; p = mpTokenArray->Next())
+ {
+ switch (p->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ // single cell
+ ++nCellCount;
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ // cell range
+ const ScComplexRefData& rData = static_cast<const ScToken*>(p)->GetDoubleRef();
+ const ScSingleRefData& s = rData.Ref1;
+ const ScSingleRefData& e = rData.Ref2;
+ SCsTAB nTab = e.nTab - s.nTab;
+ SCsCOL nCol = e.nCol - s.nCol;
+ SCsROW nRow = e.nRow - s.nRow;
+ nCellCount += static_cast<sal_uInt32>(nCol+1) *
+ static_cast<sal_uInt32>(nRow+1) *
+ static_cast<sal_uInt32>(nTab+1);
+ }
+ break;
+ }
+ }
+ return limit_cast<sal_uInt16>(nCellCount);
+}
+
void XclImpChSourceLink::ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const
{
if( ::get_flag( maData.mnFlags, EXC_CHSRCLINK_NUMFMT ) )
@@ -693,16 +738,16 @@ Reference< XDataSequence > XclImpChSourceLink::CreateDataSequence( const OUStrin
Reference< XDataProvider > xDataProv = GetDataProvider();
if( xDataProv.is() )
{
- // create the string representation of the range list
- OUString aRangeRep;
- ScRangeStringConverter::GetStringFromRangeList( aRangeRep, &maScRanges, GetDocPtr(), ';' );
-
- // create the data sequence
- try
+ if (mpTokenArray)
{
- xDataSeq = xDataProv->createDataSequenceByRangeRepresentation( aRangeRep );
+ ScCompiler aComp(GetDocPtr(), ScAddress(), *mpTokenArray);
+ aComp.SetGrammar(::formula::FormulaGrammar::GRAM_ENGLISH);
+ OUStringBuffer aBuf;
+ aComp.CreateStringFromTokenArray(aBuf);
+ xDataSeq = xDataProv->createDataSequenceByRangeRepresentation(
+ aBuf.makeStringAndClear());
}
- catch( Exception& )
+ else
{
DBG_ERRORFILE( "XclImpChSourceLink::CreateDataSequence - cannot create data sequence" );
}
diff --git a/sc/source/filter/excel/xiformula.cxx b/sc/source/filter/excel/xiformula.cxx
index 7775cf3b7..240358e05 100644
--- a/sc/source/filter/excel/xiformula.cxx
+++ b/sc/source/filter/excel/xiformula.cxx
@@ -48,6 +48,8 @@ public:
ScRangeList& rScRanges, XclFormulaType eType,
const XclTokenArray& rXclTokArr, XclImpStream& rStrm );
+ const ScTokenArray* CreateFormula( XclFormulaType eType, const XclTokenArray& rXclTokArr );
+
// ------------------------------------------------------------------------
private:
XclFunctionProvider maFuncProv; /// Excel function data provider.
@@ -81,6 +83,24 @@ void XclImpFmlaCompImpl::CreateRangeList(
}
}
+const ScTokenArray* XclImpFmlaCompImpl::CreateFormula(
+ XclFormulaType /*eType*/, const XclTokenArray& rXclTokArr )
+{
+ if (rXclTokArr.Empty())
+ return NULL;
+
+ // evil hack! are we trying to phase out the old style formula converter ?
+ SvMemoryStream aMemStrm;
+ aMemStrm << EXC_ID_EOF << rXclTokArr.GetSize();
+ aMemStrm.Write( rXclTokArr.GetData(), rXclTokArr.GetSize() );
+ XclImpStream aFmlaStrm( aMemStrm, GetRoot() );
+ aFmlaStrm.StartNextRecord();
+ const ScTokenArray* pArray = NULL;
+ GetOldFmlaConverter().Reset();
+ GetOldFmlaConverter().Convert(pArray, aFmlaStrm, aFmlaStrm.GetRecSize(), true);
+ return pArray;
+}
+
// ----------------------------------------------------------------------------
XclImpFormulaCompiler::XclImpFormulaCompiler( const XclImpRoot& rRoot ) :
@@ -100,5 +120,11 @@ void XclImpFormulaCompiler::CreateRangeList(
mxImpl->CreateRangeList( rScRanges, eType, rXclTokArr, rStrm );
}
+const ScTokenArray* XclImpFormulaCompiler::CreateFormula(
+ XclFormulaType eType, const XclTokenArray& rXclTokArr )
+{
+ return mxImpl->CreateFormula(eType, rXclTokArr);
+}
+
// ============================================================================
diff --git a/sc/source/filter/inc/xichart.hxx b/sc/source/filter/inc/xichart.hxx
index 676e39461..0ec9ca48d 100644
--- a/sc/source/filter/inc/xichart.hxx
+++ b/sc/source/filter/inc/xichart.hxx
@@ -44,6 +44,8 @@
#include "xistring.hxx"
#include "xiroot.hxx"
+#include <boost/shared_ptr.hpp>
+
namespace com { namespace sun { namespace star {
namespace frame
{
@@ -79,6 +81,7 @@ struct XclObjFillData;
class ScfProgressBar;
class XclImpChRootData;
class XclImpChChart;
+class ScTokenArray;
/** Base class for complex chart classes, provides access to other components of the chart. */
class XclImpChRoot : public XclImpRoot
@@ -390,7 +393,7 @@ public:
/** Returns explicit string data or an empty string. */
inline const String& GetString() const { return mxString.is() ? mxString->GetText() : String::EmptyString(); }
/** Returns the number of data points of this source link. */
- inline sal_uInt16 GetCellCount() const { return limit_cast< sal_uInt16 >( maScRanges.GetCellCount() ); }
+ sal_uInt16 GetCellCount() const;
/** Converts and writes the contained number format to the passed property set. */
void ConvertNumFmt( ScfPropertySet& rPropSet, bool bPercent ) const;
@@ -404,7 +407,10 @@ public:
private:
XclChSourceLink maData; /// Contents of the CHSOURCELINK record.
XclImpStringRef mxString; /// Text data (CHSTRING record).
- ScRangeList maScRanges; /// Source ranges in the Calc document.
+
+ // Tokens representing data ranges. This must be ref-counted to allow the
+ // parent class to be stored in a STL container.
+ ::boost::shared_ptr<ScTokenArray> mpTokenArray;
};
typedef ScfRef< XclImpChSourceLink > XclImpChSourceLinkRef;
diff --git a/sc/source/filter/inc/xiformula.hxx b/sc/source/filter/inc/xiformula.hxx
index 0bcd5f70d..7ea809d9e 100644
--- a/sc/source/filter/inc/xiformula.hxx
+++ b/sc/source/filter/inc/xiformula.hxx
@@ -52,6 +52,14 @@ public:
ScRangeList& rScRanges, XclFormulaType eType,
const XclTokenArray& rXclTokArr, XclImpStream& rStrm );
+ /**
+ * Creates a formula token array from the Excel token array. Note that
+ * the caller must create a copy of the token array instance returend by
+ * this function if the caller needs to persistently store the array,
+ * because the pointer points to an array instance on the stack.
+ */
+ const ScTokenArray* CreateFormula( XclFormulaType eType, const XclTokenArray& rXclTokArr );
+
private:
typedef ScfRef< XclImpFmlaCompImpl > XclImpFmlaCompImplRef;
XclImpFmlaCompImplRef mxImpl;
diff --git a/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx b/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx
index d2fe56dd0..5ab22fb55 100644
--- a/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx
+++ b/sc/source/filter/xml/XMLChangeTrackingExportHelper.cxx
@@ -395,7 +395,7 @@ void ScChangeTrackingExportHelper::WriteFormulaCell(const ScBaseCell* pCell, con
{
rtl::OUString sAddress;
const ScDocument* pDoc = rExport.GetDocument();
- ScRangeStringConverter::GetStringFromAddress(sAddress, pFormulaCell->aPos, pDoc);
+ ScRangeStringConverter::GetStringFromAddress(sAddress, pFormulaCell->aPos, pDoc, ::formula::FormulaGrammar::CONV_OOO);
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CELL_ADDRESS, sAddress);
const formula::FormulaGrammar::Grammar eGrammar = pDoc->GetStorageGrammar();
sal_uInt16 nNamespacePrefix = (eGrammar == formula::FormulaGrammar::GRAM_ODFF ? XML_NAMESPACE_OF : XML_NAMESPACE_OOOC);
diff --git a/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
index e550f6181..566bea98d 100644
--- a/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
+++ b/sc/source/filter/xml/XMLChangeTrackingImportHelper.cxx
@@ -88,7 +88,7 @@ ScBaseCell* ScMyCellInfo::CreateCell(ScDocument* pDoc)
{
ScAddress aPos;
sal_Int32 nOffset(0);
- ScRangeStringConverter::GetAddressFromString(aPos, sFormulaAddress, pDoc, nOffset);
+ ScRangeStringConverter::GetAddressFromString(aPos, sFormulaAddress, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset);
pCell = new ScFormulaCell(pDoc, aPos, sFormula, eGrammar, nMatrixFlag);
static_cast<ScFormulaCell*>(pCell)->SetMatColsRows(static_cast<SCCOL>(nMatrixCols), static_cast<SCROW>(nMatrixRows));
}
diff --git a/sc/source/filter/xml/XMLConsolidationContext.cxx b/sc/source/filter/xml/XMLConsolidationContext.cxx
index 3eb18242f..985a2822a 100644
--- a/sc/source/filter/xml/XMLConsolidationContext.cxx
+++ b/sc/source/filter/xml/XMLConsolidationContext.cxx
@@ -84,7 +84,7 @@ ScXMLConsolidationContext::ScXMLConsolidationContext(
{
sal_Int32 nOffset(0);
bTargetAddr = ScRangeStringConverter::GetAddressFromString(
- aTargetAddr, sValue, GetScImport().GetDocument(), nOffset );
+ aTargetAddr, sValue, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset );
}
break;
case XML_TOK_CONSOLIDATION_ATTR_USE_LABEL:
@@ -130,7 +130,7 @@ void ScXMLConsolidationContext::EndElement()
{
ppAreas[ nIndex ] = new ScArea;
if ( !ScRangeStringConverter::GetAreaFromString(
- *ppAreas[ nIndex ], sSourceList, GetScImport().GetDocument(), nOffset ) )
+ *ppAreas[ nIndex ], sSourceList, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset ) )
{
bError = sal_True; //! handle error
}
diff --git a/sc/source/filter/xml/XMLDetectiveContext.cxx b/sc/source/filter/xml/XMLDetectiveContext.cxx
index 993bd6ff4..61a386a38 100644
--- a/sc/source/filter/xml/XMLDetectiveContext.cxx
+++ b/sc/source/filter/xml/XMLDetectiveContext.cxx
@@ -157,7 +157,7 @@ ScXMLDetectiveHighlightedContext::ScXMLDetectiveHighlightedContext(
{
sal_Int32 nOffset(0);
GetScImport().LockSolarMutex();
- bValid = ScRangeStringConverter::GetRangeFromString( aDetectiveObj.aSourceRange, sValue, GetScImport().GetDocument(), nOffset );
+ bValid = ScRangeStringConverter::GetRangeFromString( aDetectiveObj.aSourceRange, sValue, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset );
GetScImport().UnlockSolarMutex();
}
break;
diff --git a/sc/source/filter/xml/XMLExportDataPilot.cxx b/sc/source/filter/xml/XMLExportDataPilot.cxx
index d79981e0c..d4b36e60f 100644
--- a/sc/source/filter/xml/XMLExportDataPilot.cxx
+++ b/sc/source/filter/xml/XMLExportDataPilot.cxx
@@ -196,7 +196,7 @@ void ScXMLExportDataPilot::WriteDPFilter(const ScQueryParam& aQueryParam)
ScRange aConditionRange(aQueryParam.nCol1, aQueryParam.nRow1, aQueryParam.nTab,
aQueryParam.nCol2, aQueryParam.nRow2, aQueryParam.nTab);
rtl::OUString sConditionRange;
- ScRangeStringConverter::GetStringFromRange( sConditionRange, aConditionRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sConditionRange, aConditionRange, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONDITION_SOURCE_RANGE_ADDRESS, sConditionRange);
}
if (!aQueryParam.bDuplicate)
@@ -726,7 +726,7 @@ void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreads
{
ScRange aOutRange((*pDPs)[i]->GetOutRange());
rtl::OUString sTargetRangeAddress;
- ScRangeStringConverter::GetStringFromRange( sTargetRangeAddress, aOutRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sTargetRangeAddress, aOutRange, pDoc, ::formula::FormulaGrammar::CONV_OOO );
ScDocAttrIterator aAttrItr(pDoc, aOutRange.aStart.Tab(),
aOutRange.aStart.Col(), aOutRange.aStart.Row(),
aOutRange.aEnd.Col(), aOutRange.aEnd.Row());
@@ -743,7 +743,7 @@ void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreads
{
ScAddress aButtonAddr(nCol, nButtonRow, aOutRange.aStart.Tab());
ScRangeStringConverter::GetStringFromAddress(
- sOUButtonList, aButtonAddr, pDoc, ' ', sal_True );
+ sOUButtonList, aButtonAddr, pDoc, ::formula::FormulaGrammar::CONV_OOO, ' ', sal_True );
}
}
pAttr = aAttrItr.GetNext(nCol, nRow1, nRow2);
@@ -779,7 +779,7 @@ void ScXMLExportDataPilot::WriteDataPilots(const uno::Reference <sheet::XSpreads
{
const ScSheetSourceDesc* pSheetSource = (*pDPs)[i]->GetSheetDesc();
rtl::OUString sCellRangeAddress;
- ScRangeStringConverter::GetStringFromRange( sCellRangeAddress, pSheetSource->aSourceRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sCellRangeAddress, pSheetSource->aSourceRange, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sCellRangeAddress);
SvXMLElementExport aElemSCR(rExport, XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE, sal_True, sal_True);
rExport.CheckAttrList();
diff --git a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx
index a44d28cc0..ea4343635 100644
--- a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx
+++ b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx
@@ -282,7 +282,7 @@ void ScXMLExportDatabaseRanges::WriteFilterDescriptor(const uno::Reference <shee
if (xPropertySet->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_OUTPOS))) >>= aOutputPosition)
{
rtl::OUString sOUCellAddress;
- ScRangeStringConverter::GetStringFromAddress( sOUCellAddress, aOutputPosition, pDoc );
+ ScRangeStringConverter::GetStringFromAddress( sOUCellAddress, aOutputPosition, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, sOUCellAddress);
}
}
@@ -294,7 +294,7 @@ void ScXMLExportDatabaseRanges::WriteFilterDescriptor(const uno::Reference <shee
if (pDBData->GetAdvancedQuerySource(aAdvSource))
{
rtl::OUString sOUCellAddress;
- ScRangeStringConverter::GetStringFromRange( sOUCellAddress, aAdvSource, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sOUCellAddress, aAdvSource, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_CONDITION_SOURCE_RANGE_ADDRESS, sOUCellAddress);
}
@@ -437,7 +437,7 @@ void ScXMLExportDatabaseRanges::WriteSortDescriptor(const uno::Sequence <beans::
if (bCopyOutputData)
{
rtl::OUString sOUCellAddress;
- ScRangeStringConverter::GetStringFromAddress( sOUCellAddress, aOutputPosition, pDoc );
+ ScRangeStringConverter::GetStringFromAddress( sOUCellAddress, aOutputPosition, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, sOUCellAddress);
}
// no longer supported
@@ -612,7 +612,7 @@ void ScXMLExportDatabaseRanges::WriteDatabaseRanges(const com::sun::star::uno::R
rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, sDatabaseRangeName);
table::CellRangeAddress aRangeAddress(xDatabaseRange->getDataArea());
rtl::OUString sOUAddress;
- ScRangeStringConverter::GetStringFromRange( sOUAddress, aRangeAddress, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sOUAddress, aRangeAddress, pDoc, ::formula::FormulaGrammar::CONV_OOO );
rExport.AddAttribute (XML_NAMESPACE_TABLE, XML_TARGET_RANGE_ADDRESS, sOUAddress);
ScDBCollection* pDBCollection = pDoc->GetDBCollection();
sal_uInt16 nIndex;
diff --git a/sc/source/filter/xml/XMLStylesExportHelper.cxx b/sc/source/filter/xml/XMLStylesExportHelper.cxx
index fc5e9ddb9..fda3d2052 100644
--- a/sc/source/filter/xml/XMLStylesExportHelper.cxx
+++ b/sc/source/filter/xml/XMLStylesExportHelper.cxx
@@ -306,7 +306,7 @@ rtl::OUString ScMyValidationsContainer::GetCondition(ScXMLExport& rExport, const
rtl::OUString ScMyValidationsContainer::GetBaseCellAddress(ScDocument* pDoc, const table::CellAddress& aCell)
{
rtl::OUString sAddress;
- ScRangeStringConverter::GetStringFromAddress( sAddress, aCell, pDoc );
+ ScRangeStringConverter::GetStringFromAddress( sAddress, aCell, pDoc, ::formula::FormulaGrammar::CONV_OOO );
return sAddress;
}
diff --git a/sc/source/filter/xml/XMLTableShapeImportHelper.cxx b/sc/source/filter/xml/XMLTableShapeImportHelper.cxx
index f5a8eecec..359145e76 100644
--- a/sc/source/filter/xml/XMLTableShapeImportHelper.cxx
+++ b/sc/source/filter/xml/XMLTableShapeImportHelper.cxx
@@ -106,7 +106,7 @@ void XMLTableShapeImportHelper::finishShape(
if (IsXMLToken(aLocalName, XML_END_CELL_ADDRESS))
{
sal_Int32 nOffset(0);
- ScRangeStringConverter::GetAddressFromString(aEndCell, rValue, static_cast<ScXMLImport&>(mrImporter).GetDocument(), nOffset);
+ ScRangeStringConverter::GetAddressFromString(aEndCell, rValue, static_cast<ScXMLImport&>(mrImporter).GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset);
}
else if (IsXMLToken(aLocalName, XML_END_X))
static_cast<ScXMLImport&>(mrImporter).GetMM100UnitConverter().convertMeasure(nEndX, rValue);
diff --git a/sc/source/filter/xml/XMLTableShapeResizer.cxx b/sc/source/filter/xml/XMLTableShapeResizer.cxx
index 1eb0fa8ba..a32fba514 100644
--- a/sc/source/filter/xml/XMLTableShapeResizer.cxx
+++ b/sc/source/filter/xml/XMLTableShapeResizer.cxx
@@ -37,12 +37,19 @@
#include "chartlis.hxx"
#include "XMLConverter.hxx"
#include "rangeutl.hxx"
+#include "reftokenhelper.hxx"
#include <tools/debug.hxx>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/table/XColumnRowRange.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
+#include <memory>
+#include <vector>
+
using namespace ::com::sun::star;
+using ::std::auto_ptr;
+using ::std::vector;
+using ::rtl::OUString;
ScMyShapeResizer::ScMyShapeResizer(ScXMLImport& rTempImport)
: rImport(rTempImport),
@@ -64,38 +71,44 @@ void ScMyShapeResizer::CreateChartListener(ScDocument* pDoc,
const rtl::OUString& rName,
const rtl::OUString* pRangeList)
{
- if(pDoc)
+ if (!pDoc || !pRangeList)
+ // These are minimum required.
+ return;
+
+ if (!pRangeList->getLength())
{
- if (pRangeList)
- {
- if (pRangeList->getLength())
- {
- if (!pCollection)
- pCollection = pDoc->GetChartListenerCollection();//new ScChartListenerCollection(pDoc);
- if (pCollection)
- {
- ScRangeListRef aRangeListRef(new ScRangeList());
- ScRangeStringConverter::GetRangeListFromString(*aRangeListRef, *pRangeList, pDoc);
- if (aRangeListRef->Count())
- {
- ScChartListener* pCL(new ScChartListener(rName, pDoc, aRangeListRef ));
+ pDoc->AddOLEObjectToCollection(rName);
+ return;
+ }
- //for loading binary files e.g.
- //if we have the flat filter we need to set the dirty flag thus the visible charts get repainted
- //otherwise the charts keep their first visual representation which was created at a moment where the calc itself was not loaded completly and is incorect therefor
- if( (rImport.getImportFlags() & IMPORT_ALL) == IMPORT_ALL )
- pCL->SetDirty( TRUE );
+ OUString aRangeStr;
+ ScRangeStringConverter::GetStringFromXMLRangeString(aRangeStr, *pRangeList, pDoc);
+ if (!aRangeStr.getLength())
+ {
+ pDoc->AddOLEObjectToCollection(rName);
+ return;
+ }
- pCollection->Insert( pCL );
- pCL->StartListeningTo();
- }
- }
- }
- else
- {
- pDoc->AddOLEObjectToCollection(rName);
- }
- }
+ if (!pCollection)
+ pCollection = pDoc->GetChartListenerCollection();
+
+ if (!pCollection)
+ return;
+
+ auto_ptr< vector<ScSharedTokenRef> > pRefTokens(new vector<ScSharedTokenRef>);
+ ScRefTokenHelper::compileRangeRepresentation(*pRefTokens, aRangeStr, pDoc);
+ if (!pRefTokens->empty())
+ {
+ ScChartListener* pCL(new ScChartListener(rName, pDoc, pRefTokens.release()));
+
+ //for loading binary files e.g.
+ //if we have the flat filter we need to set the dirty flag thus the visible charts get repainted
+ //otherwise the charts keep their first visual representation which was created at a moment where the calc itself was not loaded completly and is incorect therefor
+ if( (rImport.getImportFlags() & IMPORT_ALL) == IMPORT_ALL )
+ pCL->SetDirty( TRUE );
+
+ pCollection->Insert( pCL );
+ pCL->StartListeningTo();
}
}
diff --git a/sc/source/filter/xml/xmldpimp.cxx b/sc/source/filter/xml/xmldpimp.cxx
index 24ab2dc13..470827bf5 100644
--- a/sc/source/filter/xml/xmldpimp.cxx
+++ b/sc/source/filter/xml/xmldpimp.cxx
@@ -174,7 +174,7 @@ ScXMLDataPilotTableContext::ScXMLDataPilotTableContext( ScXMLImport& rImport,
case XML_TOK_DATA_PILOT_TABLE_ATTR_TARGET_RANGE_ADDRESS :
{
sal_Int32 nOffset(0);
- bTargetRangeAddress = ScRangeStringConverter::GetRangeFromString( aTargetRangeAddress, sValue, pDoc, nOffset );
+ bTargetRangeAddress = ScRangeStringConverter::GetRangeFromString( aTargetRangeAddress, sValue, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset );
}
break;
case XML_TOK_DATA_PILOT_TABLE_ATTR_BUTTONS :
@@ -266,7 +266,7 @@ void ScXMLDataPilotTableContext::SetButtons()
{
ScAddress aScAddress;
sal_Int32 nAddrOffset(0);
- if (pDoc && ScRangeStringConverter::GetAddressFromString( aScAddress, sAddress, pDoc, nAddrOffset ))
+ if (pDoc && ScRangeStringConverter::GetAddressFromString( aScAddress, sAddress, pDoc, ::formula::FormulaGrammar::CONV_OOO, nAddrOffset ))
{
ScMergeFlagAttr aAttr( SC_MF_BUTTON );
pDoc->ApplyAttr( aScAddress.Col(), aScAddress.Row(), aScAddress.Tab(), aAttr );
@@ -668,7 +668,7 @@ ScXMLSourceCellRangeContext::ScXMLSourceCellRangeContext( ScXMLImport& rImport,
{
ScRange aSourceRangeAddress;
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aSourceRangeAddress, sValue, GetScImport().GetDocument(), nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aSourceRangeAddress, sValue, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset ))
pDataPilotTable->SetSourceCellRangeAddress(aSourceRangeAddress);
}
break;
diff --git a/sc/source/filter/xml/xmldrani.cxx b/sc/source/filter/xml/xmldrani.cxx
index 4c7622d00..382f1d755 100644
--- a/sc/source/filter/xml/xmldrani.cxx
+++ b/sc/source/filter/xml/xmldrani.cxx
@@ -292,7 +292,7 @@ void ScXMLDatabaseRangeContext::EndElement()
{
table::CellRangeAddress aCellRangeAddress;
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aCellRangeAddress, sRangeAddress, pDoc, nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aCellRangeAddress, sRangeAddress, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
{
sal_Bool bInsert(sal_True);
try
diff --git a/sc/source/filter/xml/xmlexprt.cxx b/sc/source/filter/xml/xmlexprt.cxx
index 54bd75a27..4346d2178 100644
--- a/sc/source/filter/xml/xmlexprt.cxx
+++ b/sc/source/filter/xml/xmlexprt.cxx
@@ -1390,7 +1390,7 @@ void ScXMLExport::GetColumnRowHeader(sal_Bool& rHasColumnHeader, table::CellRang
rRowHeaderRange = xPrintAreas->getTitleRows();
rColumnHeaderRange = xPrintAreas->getTitleColumns();
uno::Sequence< table::CellRangeAddress > aRangeList( xPrintAreas->getPrintAreas() );
- ScRangeStringConverter::GetStringFromRangeList( rPrintRanges, aRangeList, pDoc );
+ ScRangeStringConverter::GetStringFromRangeList( rPrintRanges, aRangeList, pDoc, FormulaGrammar::CONV_OOO );
}
}
@@ -2590,7 +2590,7 @@ void ScXMLExport::WriteShapes(const ScMyCell& rMyCell)
Rectangle aEndRec(pDoc->GetMMRect(aItr->aEndAddress.Col(), aItr->aEndAddress.Row(),
aItr->aEndAddress.Col(), aItr->aEndAddress.Row(), aItr->aEndAddress.Tab()));
rtl::OUString sEndAddress;
- ScRangeStringConverter::GetStringFromAddress(sEndAddress, aItr->aEndAddress, pDoc);
+ ScRangeStringConverter::GetStringFromAddress(sEndAddress, aItr->aEndAddress, pDoc, FormulaGrammar::CONV_OOO);
AddAttribute(XML_NAMESPACE_TABLE, XML_END_CELL_ADDRESS, sEndAddress);
if (bNegativePage)
aEndPoint.X = -aEndRec.Right();
@@ -2796,7 +2796,7 @@ void ScXMLExport::WriteDetective( const ScMyCell& rMyCell )
{
if( (aObjItr->eObjType == SC_DETOBJ_ARROW) || (aObjItr->eObjType == SC_DETOBJ_TOOTHERTAB))
{
- ScRangeStringConverter::GetStringFromRange( sString, aObjItr->aSourceRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sString, aObjItr->aSourceRange, pDoc, FormulaGrammar::CONV_OOO );
AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, sString );
}
ScXMLConverter::GetStringFromDetObjType( sString, aObjItr->eObjType );
@@ -3160,7 +3160,7 @@ void ScXMLExport::WriteScenario()
AddAttribute(XML_NAMESPACE_TABLE, XML_IS_ACTIVE, aBuffer.makeStringAndClear());
const ScRangeList* pRangeList = pDoc->GetScenarioRanges(static_cast<SCTAB>(nCurrentTable));
rtl::OUString sRangeListStr;
- ScRangeStringConverter::GetStringFromRangeList( sRangeListStr, pRangeList, pDoc );
+ ScRangeStringConverter::GetStringFromRangeList( sRangeListStr, pRangeList, pDoc, FormulaGrammar::CONV_OOO );
AddAttribute(XML_NAMESPACE_TABLE, XML_SCENARIO_RANGES, sRangeListStr);
if (sComment.Len())
AddAttribute(XML_NAMESPACE_TABLE, XML_COMMENT, rtl::OUString(sComment));
@@ -3202,10 +3202,10 @@ void ScXMLExport::WriteLabelRanges( const uno::Reference< container::XIndexAcces
{
OUString sRangeStr;
table::CellRangeAddress aCellRange( xRange->getLabelArea() );
- ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO );
AddAttribute( XML_NAMESPACE_TABLE, XML_LABEL_CELL_RANGE_ADDRESS, sRangeStr );
aCellRange = xRange->getDataArea();
- ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc );
+ ScRangeStringConverter::GetStringFromRange( sRangeStr, aCellRange, pDoc, FormulaGrammar::CONV_OOO );
AddAttribute( XML_NAMESPACE_TABLE, XML_DATA_CELL_RANGE_ADDRESS, sRangeStr );
AddAttribute( XML_NAMESPACE_TABLE, XML_ORIENTATION, bColumn ? XML_COLUMN : XML_ROW );
SvXMLElementExport aElem( *this, XML_NAMESPACE_TABLE, XML_LABEL_RANGE, sal_True, sal_True );
@@ -3246,7 +3246,7 @@ void ScXMLExport::WriteNamedExpressions(const com::sun::star::uno::Reference <co
OUString sOUBaseCellAddress;
ScRangeStringConverter::GetStringFromAddress( sOUBaseCellAddress,
- xNamedRange->getReferencePosition(), pDoc, ' ', sal_False, SCA_ABS_3D );
+ xNamedRange->getReferencePosition(), pDoc, FormulaGrammar::CONV_OOO, ' ', sal_False, SCA_ABS_3D );
AddAttribute(XML_NAMESPACE_TABLE, XML_BASE_CELL_ADDRESS, sOUBaseCellAddress);
sal_uInt16 nRangeIndex;
@@ -3520,10 +3520,10 @@ void ScXMLExport::WriteConsolidation()
sStrData = OUString();
for( sal_Int32 nIndex = 0; nIndex < pCons->nDataAreaCount; ++nIndex )
- ScRangeStringConverter::GetStringFromArea( sStrData, *pCons->ppDataAreas[ nIndex ], pDoc, sal_True );
+ ScRangeStringConverter::GetStringFromArea( sStrData, *pCons->ppDataAreas[ nIndex ], pDoc, FormulaGrammar::CONV_OOO, sal_True );
AddAttribute( XML_NAMESPACE_TABLE, XML_SOURCE_CELL_RANGE_ADDRESSES, sStrData );
- ScRangeStringConverter::GetStringFromAddress( sStrData, ScAddress( pCons->nCol, pCons->nRow, pCons->nTab ), pDoc );
+ ScRangeStringConverter::GetStringFromAddress( sStrData, ScAddress( pCons->nCol, pCons->nRow, pCons->nTab ), pDoc, FormulaGrammar::CONV_OOO );
AddAttribute( XML_NAMESPACE_TABLE, XML_TARGET_CELL_ADDRESS, sStrData );
if( pCons->bByCol && !pCons->bByRow )
@@ -3593,7 +3593,7 @@ void ScXMLExport::GetChangeTrackViewSettings(uno::Sequence<beans::PropertyValue>
pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowChangesByRanges"));
pChangeProps[SC_SHOW_CHANGES_BY_RANGES].Value <<= pViewSettings->HasRange();
rtl::OUString sRangeList;
- ScRangeStringConverter::GetStringFromRangeList(sRangeList, &(pViewSettings->GetTheRangeList()), GetDocument());
+ ScRangeStringConverter::GetStringFromRangeList(sRangeList, &(pViewSettings->GetTheRangeList()), GetDocument(), FormulaGrammar::CONV_OOO);
pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ShowChangesByRangesList"));
pChangeProps[SC_SHOW_CHANGES_BY_RANGES_LIST].Value <<= sRangeList;
diff --git a/sc/source/filter/xml/xmlfilti.cxx b/sc/source/filter/xml/xmlfilti.cxx
index ba2b16c61..26d4b2473 100644
--- a/sc/source/filter/xml/xmlfilti.cxx
+++ b/sc/source/filter/xml/xmlfilti.cxx
@@ -84,7 +84,7 @@ ScXMLFilterContext::ScXMLFilterContext( ScXMLImport& rImport,
{
ScRange aScRange;
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, pDoc, nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
{
ScUnoConversion::FillApiAddress( aOutputPosition, aScRange.aStart );
bCopyOutputData = sal_True;
@@ -94,7 +94,7 @@ ScXMLFilterContext::ScXMLFilterContext( ScXMLImport& rImport,
case XML_TOK_FILTER_ATTR_CONDITION_SOURCE_RANGE_ADDRESS :
{
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aConditionSourceRangeAddress, sValue, pDoc, nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aConditionSourceRangeAddress, sValue, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
bConditionSourceRange = sal_True;
}
break;
@@ -436,7 +436,7 @@ ScXMLDPFilterContext::ScXMLDPFilterContext( ScXMLImport& rImport,
{
ScRange aScRange;
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, pDoc, nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
{
aOutputPosition = aScRange.aStart;
bCopyOutputData = sal_True;
@@ -446,7 +446,7 @@ ScXMLDPFilterContext::ScXMLDPFilterContext( ScXMLImport& rImport,
case XML_TOK_FILTER_ATTR_CONDITION_SOURCE_RANGE_ADDRESS :
{
sal_Int32 nOffset(0);
- if(ScRangeStringConverter::GetRangeFromString( aConditionSourceRangeAddress, sValue, pDoc, nOffset ))
+ if(ScRangeStringConverter::GetRangeFromString( aConditionSourceRangeAddress, sValue, pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset ))
bConditionSourceRange = sal_True;
}
break;
diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx
index 05793158f..d37e62250 100644
--- a/sc/source/filter/xml/xmlimprt.cxx
+++ b/sc/source/filter/xml/xmlimprt.cxx
@@ -104,6 +104,7 @@
using namespace com::sun::star;
using namespace ::xmloff::token;
+using namespace ::formula;
using ::rtl::OUString;
OUString SAL_CALL ScXMLImport_getImplementationName() throw()
@@ -2121,7 +2122,8 @@ void ScXMLImport::SetChangeTrackingViewSettings(const com::sun::star::uno::Seque
if ((rChangeProps[i].Value >>= sRanges) && sRanges.getLength())
{
ScRangeList aRangeList;
- ScRangeStringConverter::GetRangeListFromString(aRangeList, sRanges, GetDocument());
+ ScRangeStringConverter::GetRangeListFromString(
+ aRangeList, sRanges, GetDocument(), FormulaGrammar::CONV_OOO);
pViewSettings->SetTheRangeList(aRangeList);
}
}
@@ -2619,9 +2621,10 @@ void ScXMLImport::SetLabelRanges()
{
sal_Int32 nOffset1(0);
sal_Int32 nOffset2(0);
+ FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
- if (ScRangeStringConverter::GetRangeFromString( aLabelRange, (*aItr)->sLabelRangeStr, GetDocument(), nOffset1 ) &&
- ScRangeStringConverter::GetRangeFromString( aDataRange, (*aItr)->sDataRangeStr, GetDocument(), nOffset2 ))
+ if (ScRangeStringConverter::GetRangeFromString( aLabelRange, (*aItr)->sLabelRangeStr, GetDocument(), eConv, nOffset1 ) &&
+ ScRangeStringConverter::GetRangeFromString( aDataRange, (*aItr)->sDataRangeStr, GetDocument(), eConv, nOffset2 ))
{
if ( (*aItr)->bColumnOrientation )
xColRanges->addNew( aLabelRange, aDataRange );
@@ -2656,7 +2659,7 @@ void ScXMLImport::SetNamedRanges()
{
sal_Int32 nOffset(0);
if (ScRangeStringConverter::GetAddressFromString(
- aCellAddress, (*aItr)->sBaseCellAddress, GetDocument(), nOffset ))
+ aCellAddress, (*aItr)->sBaseCellAddress, GetDocument(), FormulaGrammar::CONV_OOO, nOffset ))
{
try
{
@@ -2697,7 +2700,7 @@ void ScXMLImport::SetNamedRanges()
{
sal_Int32 nOffset(0);
if (ScRangeStringConverter::GetAddressFromString(
- aCellAddress, (*aItr)->sBaseCellAddress, GetDocument(), nOffset ))
+ aCellAddress, (*aItr)->sBaseCellAddress, GetDocument(), FormulaGrammar::CONV_OOO, nOffset ))
{
uno::Reference <sheet::XNamedRange> xNamedRange(xNamedRanges->getByName((*aItr)->sName), uno::UNO_QUERY);
if (xNamedRange.is())
diff --git a/sc/source/filter/xml/xmlsceni.cxx b/sc/source/filter/xml/xmlsceni.cxx
index 02ab35599..55e9969a2 100644
--- a/sc/source/filter/xml/xmlsceni.cxx
+++ b/sc/source/filter/xml/xmlsceni.cxx
@@ -114,7 +114,7 @@ ScXMLTableScenarioContext::ScXMLTableScenarioContext(
case XML_TOK_TABLE_SCENARIO_ATTR_SCENARIO_RANGES:
{
ScRangeStringConverter::GetRangeListFromString(
- aScenarioRanges, sValue, GetScImport().GetDocument() );
+ aScenarioRanges, sValue, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO );
}
break;
case XML_TOK_TABLE_SCENARIO_ATTR_COMMENT:
diff --git a/sc/source/filter/xml/xmlsorti.cxx b/sc/source/filter/xml/xmlsorti.cxx
index 193d98d4f..a70380d56 100644
--- a/sc/source/filter/xml/xmlsorti.cxx
+++ b/sc/source/filter/xml/xmlsorti.cxx
@@ -93,7 +93,7 @@ ScXMLSortContext::ScXMLSortContext( ScXMLImport& rImport,
{
ScRange aScRange;
sal_Int32 nOffset(0);
- if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, GetScImport().GetDocument(), nOffset ))
+ if (ScRangeStringConverter::GetRangeFromString( aScRange, sValue, GetScImport().GetDocument(), ::formula::FormulaGrammar::CONV_OOO, nOffset ))
{
ScUnoConversion::FillApiAddress( aOutputPosition, aScRange.aStart );
bCopyOutputData = sal_True;
diff --git a/sc/source/filter/xml/xmlstyle.cxx b/sc/source/filter/xml/xmlstyle.cxx
index 9bf9ee4d0..5a4449948 100644
--- a/sc/source/filter/xml/xmlstyle.cxx
+++ b/sc/source/filter/xml/xmlstyle.cxx
@@ -65,6 +65,7 @@
using namespace com::sun::star;
using namespace ::xmloff::token;
+using namespace ::formula;
using ::rtl::OUString;
#define MAP(name,prefix,token,type,context) { name, sizeof(name)-1, prefix, token, type, context, SvtSaveOptions::ODFVER_010 }
@@ -707,8 +708,9 @@ void ScXMLAutoStylePoolP::exportStyleContent(
rScXMLExport.AddAttribute(XML_NAMESPACE_STYLE, XML_CONDITION, sCondition);
rScXMLExport.AddAttribute(XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME, rScXMLExport.EncodeStyleName( sStyleName ));
OUString sOUBaseAddress;
+ ScDocument* pDoc = rScXMLExport.GetDocument();
ScRangeStringConverter::GetStringFromAddress( sOUBaseAddress,
- xSheetCondition->getSourcePosition(), rScXMLExport.GetDocument() );
+ xSheetCondition->getSourcePosition(), pDoc, FormulaGrammar::CONV_OOO );
rScXMLExport.AddAttribute(XML_NAMESPACE_STYLE, XML_BASE_CELL_ADDRESS, sOUBaseAddress);
SvXMLElementExport aMElem(rScXMLExport, XML_NAMESPACE_STYLE, XML_MAP, sal_True, sal_True);
}
@@ -761,7 +763,7 @@ void ScXMLAutoStylePoolP::exportStyleContent(
rScXMLExport.AddAttribute(XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME, rScXMLExport.EncodeStyleName( sStyleName ));
OUString sOUBaseAddress;
ScRangeStringConverter::GetStringFromAddress( sOUBaseAddress,
- xSheetCondition->getSourcePosition(), rScXMLExport.GetDocument() );
+ xSheetCondition->getSourcePosition(), rScXMLExport.GetDocument(), FormulaGrammar::CONV_OOO );
rScXMLExport.AddAttribute(XML_NAMESPACE_STYLE, XML_BASE_CELL_ADDRESS, sOUBaseAddress);
SvXMLElementExport aMElem(rScXMLExport, XML_NAMESPACE_STYLE, XML_MAP, sal_True, sal_True);
}
diff --git a/sc/source/filter/xml/xmltabi.cxx b/sc/source/filter/xml/xmltabi.cxx
index 7ba786d33..eec8423f4 100644
--- a/sc/source/filter/xml/xmltabi.cxx
+++ b/sc/source/filter/xml/xmltabi.cxx
@@ -331,7 +331,7 @@ void ScXMLTableContext::EndElement()
if( xPrintAreas.is() )
{
uno::Sequence< table::CellRangeAddress > aRangeList;
- ScRangeStringConverter::GetRangeListFromString( aRangeList, sPrintRanges, pDoc );
+ ScRangeStringConverter::GetRangeListFromString( aRangeList, sPrintRanges, pDoc, ::formula::FormulaGrammar::CONV_OOO );
xPrintAreas->setPrintAreas( aRangeList );
}
}
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 4fb1c3a57..4e7075cd1 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -77,6 +77,7 @@ using ::std::find_if;
using ::std::distance;
using ::std::pair;
using ::std::list;
+using ::std::unary_function;
using namespace formula;
#define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec)
@@ -84,7 +85,7 @@ using namespace formula;
namespace {
-class TabNameSearchPredicate : ::std::unary_function<bool, ScExternalRefCache::TableName>
+class TabNameSearchPredicate : public unary_function<bool, ScExternalRefCache::TableName>
{
public:
explicit TabNameSearchPredicate(const String& rSearchName) :
@@ -102,7 +103,7 @@ private:
String maSearchName;
};
-class FindSrcFileByName : public ::std::unary_function<ScExternalRefManager::SrcFileData, bool>
+class FindSrcFileByName : public unary_function<ScExternalRefManager::SrcFileData, bool>
{
public:
FindSrcFileByName(const String& rMatchName) :
@@ -119,6 +120,24 @@ private:
const String& mrMatchName;
};
+class NotifyLinkListener : public unary_function<ScExternalRefManager::LinkListener*, void>
+{
+public:
+ NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) :
+ mnFileId(nFileId), meType(eType) {}
+
+ NotifyLinkListener(const NotifyLinkListener& r) :
+ mnFileId(r.mnFileId), meType(r.meType) {}
+
+ void operator() (ScExternalRefManager::LinkListener* p) const
+ {
+ p->notify(mnFileId, meType);
+ }
+private:
+ sal_uInt16 mnFileId;
+ ScExternalRefManager::LinkUpdateType meType;
+};
+
}
// ============================================================================
@@ -297,7 +316,8 @@ const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const Str
}
ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
- sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, sal_uInt32* pnFmtIndex)
+ sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow,
+ bool bEmptyCellOnNull, sal_uInt32* pnFmtIndex)
{
DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
if (itrDoc == maDocs.end())
@@ -321,10 +341,15 @@ ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
// the table data is not instantiated yet.
return TokenRef();
}
- return pTableData->getCell(nCol, nRow, pnFmtIndex);
+
+ TokenRef pToken = pTableData->getCell(nCol, nRow, pnFmtIndex);
+ if (!pToken && bEmptyCellOnNull)
+ pToken.reset(new ScEmptyCellToken(false, false));
+ return pToken;
}
-ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
+ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
+ sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, bool bEmptyCellOnNull)
{
DocDataType::iterator itrDoc = maDocs.find(nFileId);
if (itrDoc == maDocs.end())
@@ -373,9 +398,14 @@ ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(sal_uInt1
{
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
{
- FormulaToken* pToken = pTab->getCell(nCol, nRow).get();
+ TokenRef pToken = pTab->getCell(nCol, nRow);
if (!pToken)
- return TokenArrayRef();
+ {
+ if (bEmptyCellOnNull)
+ pToken.reset(new ScEmptyCellToken(false, false));
+ else
+ return TokenArrayRef();
+ }
SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
switch (pToken->GetType())
@@ -755,7 +785,7 @@ ScExternalRefLink::~ScExternalRefLink()
void ScExternalRefLink::Closed()
{
ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
- pMgr->removeSrcDocument(mnFileId, true);
+ pMgr->breakLink(mnFileId);
}
void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
@@ -1208,6 +1238,16 @@ void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefM
// ----------------------------------------------------------------------------
+ScExternalRefManager::LinkListener::LinkListener()
+{
+}
+
+ScExternalRefManager::LinkListener::~LinkListener()
+{
+}
+
+// ----------------------------------------------------------------------------
+
void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
{
maRefCache.getAllTableNames(nFileId, rTabNames);
@@ -1262,7 +1302,7 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
// Check if the given table name and the cell position is cached.
sal_uInt32 nFmtIndex = 0;
ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
- nFileId, rTabName, rCell.Row(), rCell.Col(), &nFmtIndex);
+ nFileId, rTabName, rCell.Col(), rCell.Row(), false, &nFmtIndex);
if (pToken)
{
if (pFmt)
@@ -1282,7 +1322,12 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
ScDocument* pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
{
- return ScExternalRefCache::TokenRef();
+ // Source document is not reachable. Try to get data from the cache
+ // once again, but this time treat a non-cached cell as an empty cell
+ // as long as the table itself is cached.
+ pToken = maRefCache.getCellData(
+ nFileId, rTabName, rCell.Col(), rCell.Row(), true, &nFmtIndex);
+ return pToken;
}
ScBaseCell* pCell = NULL;
@@ -1331,13 +1376,18 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_u
maybeLinkExternalFile(nFileId);
// Check if the given table name and the cell position is cached.
- ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange);
+ ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange, false);
if (p.get())
return p;
ScDocument* pSrcDoc = getSrcDocument(nFileId);
if (!pSrcDoc)
- return ScExternalRefCache::TokenArrayRef();
+ {
+ // Source document is not reachable. Try to get data from the cache
+ // once again, but this time treat non-cached cells as empty cells as
+ // long as the table itself is cached.
+ return maRefCache.getCellRangeData(nFileId, rTabName, rRange, true);
+ }
SCTAB nTab1;
if (!pSrcDoc->GetTable(rTabName, nTab1))
@@ -1631,7 +1681,7 @@ bool ScExternalRefManager::isFileLoadable(const String& rFile) const
void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
{
if (maLinkedDocs.count(nFileId))
- // file alerady linked.
+ // file alerady linked, or the link has been broken.
return;
// Source document not linked yet. Link it now.
@@ -1650,7 +1700,7 @@ void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
pLink->Update();
pLink->SetDoReferesh(true);
- maLinkedDocs.insert(nFileId);
+ maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true));
}
bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell)
@@ -1771,10 +1821,30 @@ void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
{
- removeSrcDocument(nFileId, false);
+ maRefCache.clearCache(nFileId);
+ lcl_removeByFileId(nFileId, maDocShells);
+
+ if (maDocShells.empty())
+ maSrcDocTimer.Stop();
// Update all cells containing names from this source document.
refreshAllRefCells(nFileId);
+
+ notifyAllLinkListeners(nFileId, LINK_MODIFIED);
+}
+
+void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
+{
+ lcl_removeByFileId(nFileId, maDocShells);
+
+ if (maDocShells.empty())
+ maSrcDocTimer.Stop();
+
+ LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
+ if (itr != maLinkedDocs.end())
+ itr->second = false;
+
+ notifyAllLinkListeners(nFileId, LINK_BROKEN);
}
void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile)
@@ -1799,18 +1869,6 @@ void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilt
maSrcFiles[nFileId].maFilterOptions = rOptions;
}
-void ScExternalRefManager::removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink)
-{
- maRefCache.clearCache(nFileId);
- lcl_removeByFileId(nFileId, maDocShells);
-
- if (bBreakLink)
- maLinkedDocs.erase(nFileId);
-
- if (maDocShells.empty())
- maSrcDocTimer.Stop();
-}
-
void ScExternalRefManager::clear()
{
DocShellMap::iterator itrEnd = maDocShells.end();
@@ -1870,6 +1928,59 @@ void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos)
itr->second.removeTable(nPos);
}
+void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ {
+ pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert(
+ LinkListenerMap::value_type(nFileId, LinkListeners()));
+ if (!r.second)
+ {
+ DBG_ERROR("insertion of new link listener list failed");
+ return;
+ }
+
+ itr = r.first;
+ }
+
+ LinkListeners& rList = itr->second;
+ rList.insert(pListener);
+}
+
+void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ // no listeners for a specified file.
+ return;
+
+ LinkListeners& rList = itr->second;
+ rList.erase(pListener);
+
+ if (rList.empty())
+ // No more listeners for this file. Remove its entry.
+ maLinkListeners.erase(itr);
+}
+
+void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end();
+ for (; itr != itrEnd; ++itr)
+ itr->second.erase(pListener);
+}
+
+void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ // no listeners for a specified file.
+ return;
+
+ LinkListeners& rList = itr->second;
+ for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
+}
+
void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
{
DocShellMap aNewDocShells;
diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx
index 2d0502482..6eed44de6 100644
--- a/sc/source/ui/unoobj/chart2uno.cxx
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -43,15 +43,13 @@
#include "rangeutl.hxx"
#include "hints.hxx"
#include "unoreflist.hxx"
+#include "compiler.hxx"
+#include "reftokenhelper.hxx"
#include <sfx2/objsh.hxx>
+#include <tools/table.hxx>
-#ifndef _COM_SUN_STAR_BEANS_UNKNOWNPROPERTYEXCEPTION_HDL_
#include <com/sun/star/beans/UnknownPropertyException.hpp>
-#endif
-#ifndef _COM_SUN_STAR_CHART_DATAROWSOURCE_HPP_
-#include <com/sun/star/chart/ChartDataRowSource.hpp>
-#endif
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/table/XCellRange.hpp>
#include <com/sun/star/table/CellAddress.hpp>
@@ -70,10 +68,24 @@ SC_SIMPLE_SERVICE_INFO( ScChart2LabeledDataSequence, "ScChart2LabeledDataSequenc
"com.sun.star.chart2.data.LabeledDataSequence")
SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
"com.sun.star.chart2.data.DataSequence")
+#if USE_CHART2_EMPTYDATASEQUENCE
SC_SIMPLE_SERVICE_INFO( ScChart2EmptyDataSequence, "ScChart2EmptyDataSequence",
"com.sun.star.chart2.data.DataSequence")
+#endif
using namespace ::com::sun::star;
+using namespace ::formula;
+using ::rtl::OUString;
+using ::rtl::OUStringBuffer;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::std::auto_ptr;
+using ::std::vector;
+using ::std::list;
+using ::std::distance;
+using ::std::unary_function;
+using ::std::hash_set;
+using ::boost::shared_ptr;
namespace
{
@@ -191,6 +203,759 @@ uno::Reference< sheet::XSpreadsheetDocument > lcl_GetSpreadSheetDocument( ScDocu
return uno::Reference< sheet::XSpreadsheetDocument >( lcl_GetXModel( pDoc ), uno::UNO_QUERY );
}
+// ============================================================================
+
+class Chart2PositionMap
+{
+public:
+ Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
+ bool bColAdd, bool bRowAdd, Table& rCols);
+ ~Chart2PositionMap();
+
+ SCCOL getColCount() const { return static_cast<SCCOL>(maColHeaders.size()); }
+ SCROW getRowCount() const { return static_cast<SCROW>(maRowHeaders.size()); }
+
+ const FormulaToken* getColHeaderPosition(SCCOL nChartCol) const;
+ const FormulaToken* getRowHeaderPosition(SCROW nChartRow) const;
+
+ vector<ScSharedTokenRef>* getColRanges(SCCOL nCol) const;
+ vector<ScSharedTokenRef>* getRowRanges(SCROW nRow) const;
+
+
+private:
+ sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
+ {
+ return static_cast<sal_uInt32>(nCol*getRowCount() + nRow);
+ }
+
+private:
+ vector<FormulaToken*> maRowHeaders;
+ vector<FormulaToken*> maColHeaders;
+ vector<FormulaToken*> maData;
+};
+
+Chart2PositionMap::Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
+ bool bColAdd, bool bRowAdd, Table& rCols)
+{
+ // bColAdd is true when the first column serves as a row header. Likewise,
+ // when bRowAdd is true the first row serves as a column header.
+
+ maColHeaders.reserve(nColCount);
+ maRowHeaders.reserve(nRowCount);
+ maData.reserve(nColCount*nRowCount);
+
+ Table* pCol = static_cast<Table*>(rCols.First());
+ FormulaToken* pPos = static_cast<FormulaToken*>(pCol->First());
+
+ if (bRowAdd)
+ pPos = static_cast<FormulaToken*>(pCol->Next());
+
+ if (bColAdd)
+ {
+ // 1st column as a row header.
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
+ {
+ maRowHeaders.push_back(pPos);
+ pPos = static_cast<FormulaToken*>(pCol->Next());
+ }
+ pCol = static_cast<Table*>(rCols.Next()); // move to the next column.
+ }
+ else
+ {
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
+ {
+ // Make a copy.
+ maRowHeaders.push_back(pPos ? pPos->Clone() : NULL);
+ pPos = static_cast<FormulaToken*>(pCol->Next());
+ }
+ }
+
+ // Data in columns and in column headers.
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ if (pCol)
+ {
+ pPos = static_cast<FormulaToken*>(pCol->First());
+ if (bRowAdd)
+ {
+ // 1st row as a column header.
+ maColHeaders.push_back(pPos);
+ pPos = static_cast<FormulaToken*>(pCol->Next());
+ }
+ else
+ // Duplicate the 1st cell as a column header.
+ maColHeaders.push_back(pPos ? pPos->Clone() : NULL);
+
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
+ {
+ maData.push_back(pPos);
+ pPos = static_cast<FormulaToken*>(pCol->Next());
+ }
+ }
+ else
+ {
+ // the entire column is empty.
+ maColHeaders.push_back(NULL);
+ for (SCROW nRow = 0; nRow < nRowCount; ++nRow)
+ maData.push_back(NULL);
+ }
+ pCol = static_cast<Table*>(rCols.Next());
+ }
+}
+
+namespace {
+
+struct DeleteInstance : public unary_function<FormulaToken*, void>
+{
+ void operator() (FormulaToken* p) const
+ {
+ delete p;
+ }
+};
+
+}
+
+Chart2PositionMap::~Chart2PositionMap()
+{
+ for_each(maColHeaders.begin(), maColHeaders.end(), DeleteInstance());
+ for_each(maRowHeaders.begin(), maRowHeaders.end(), DeleteInstance());
+ for_each(maData.begin(), maData.end(), DeleteInstance());
+}
+
+const FormulaToken* Chart2PositionMap::getColHeaderPosition(SCCOL nCol) const
+{
+ if (nCol < getColCount())
+ return maColHeaders[nCol];
+ return NULL;
+}
+const FormulaToken* Chart2PositionMap::getRowHeaderPosition(SCROW nRow) const
+{
+ if (nRow < getRowCount())
+ return maRowHeaders[nRow];
+ return NULL;
+}
+
+vector<ScSharedTokenRef>* Chart2PositionMap::getColRanges(SCCOL nCol) const
+{
+ if (nCol >= getColCount())
+ return NULL;
+
+ auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>);
+ sal_uInt32 nStop = getIndex(nCol, getRowCount());
+ for (sal_uInt32 i = getIndex(nCol, 0); i < nStop; ++i)
+ {
+ FormulaToken* p = maData[i];
+ if (!p)
+ continue;
+
+ ScSharedTokenRef pCopy(static_cast<ScToken*>(p->Clone()));
+ ScRefTokenHelper::join(*pTokens, pCopy);
+ }
+ return pTokens.release();
+}
+
+vector<ScSharedTokenRef>* Chart2PositionMap::getRowRanges(SCROW nRow) const
+{
+ SCROW nRowCount = getRowCount();
+ if (nRow >= nRowCount)
+ return NULL;
+
+ auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>);
+ sal_uInt32 nStop = getIndex(getColCount(), nRow);
+ for (sal_uInt32 i = getIndex(0, nRow); i < nStop; i += nRowCount)
+ {
+ FormulaToken* p = maData[i];
+ if (!p)
+ continue;
+
+ ScSharedTokenRef p2(static_cast<ScToken*>(p->Clone()));
+ ScRefTokenHelper::join(*pTokens, p2);
+ }
+ return pTokens.release();
+}
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Designed to be a drop-in replacement for ScChartPositioner, in order to
+ * handle external references.
+ */
+class Chart2Positioner
+{
+ enum GlueType
+ {
+ GLUETYPE_NA,
+ GLUETYPE_NONE,
+ GLUETYPE_COLS,
+ GLUETYPE_ROWS,
+ GLUETYPE_BOTH
+ };
+
+public:
+ Chart2Positioner(ScDocument* pDoc, const vector<ScSharedTokenRef>& rRefTokens) :
+ mpRefTokens(new vector<ScSharedTokenRef>(rRefTokens)),
+ mpPositionMap(NULL),
+ meGlue(GLUETYPE_NA),
+ mpDoc(pDoc),
+ mbColHeaders(false),
+ mbRowHeaders(false),
+ mbDummyUpperLeft(false)
+ {
+ }
+
+ ~Chart2Positioner()
+ {
+ }
+
+ void setHeaders(bool bColHeaders, bool bRowHeaders)
+ {
+ mbColHeaders = bColHeaders;
+ mbRowHeaders = bRowHeaders;
+ }
+
+ bool hasColHeaders() const { return mbColHeaders; }
+ bool hasRowHeaders() const { return mbRowHeaders; }
+
+ Chart2PositionMap* getPositionMap()
+ {
+ createPositionMap();
+ return mpPositionMap.get();
+ }
+
+private:
+ Chart2Positioner(); // disabled
+
+ void invalidateGlue();
+ void glueState();
+ void createPositionMap();
+
+private:
+ shared_ptr< vector<ScSharedTokenRef> > mpRefTokens;
+ auto_ptr<Chart2PositionMap> mpPositionMap;
+ GlueType meGlue;
+ SCCOL mnStartCol;
+ SCROW mnStartRow;
+ ScDocument* mpDoc;
+ bool mbColHeaders:1;
+ bool mbRowHeaders:1;
+ bool mbDummyUpperLeft:1;
+};
+
+void Chart2Positioner::invalidateGlue()
+{
+ meGlue = GLUETYPE_NA;
+ mpPositionMap.reset(NULL);
+}
+
+void Chart2Positioner::glueState()
+{
+ if (meGlue != GLUETYPE_NA)
+ return;
+
+ mbDummyUpperLeft = false;
+ if (mpRefTokens->size() <= 1)
+ {
+ const ScSharedTokenRef& p = mpRefTokens->front();
+ ScComplexRefData aData;
+ if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
+ {
+ if (aData.Ref1.nTab == aData.Ref2.nTab)
+ meGlue = GLUETYPE_NONE;
+ else
+ meGlue = GLUETYPE_COLS;
+ mnStartCol = aData.Ref1.nCol;
+ mnStartRow = aData.Ref1.nRow;
+ }
+ else
+ {
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ }
+ return;
+ }
+
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, mpRefTokens->front());
+ mnStartCol = aData.Ref1.nCol;
+ mnStartRow = aData.Ref1.nRow;
+
+ SCCOL nMaxCols = 0, nEndCol = 0;
+ SCROW nMaxRows = 0, nEndRow = 0;
+ for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end()
+ ; itr != itrEnd; ++itr)
+ {
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
+ SCCOLROW n1 = aData.Ref1.nCol;
+ SCCOLROW n2 = aData.Ref2.nCol;
+ SCCOLROW nTmp = n2 - n1 + 1;
+ if (n1 < mnStartCol)
+ mnStartCol = static_cast<SCCOL>(n1);
+ if (n2 > nEndCol)
+ nEndCol = static_cast<SCCOL>(n2);
+ if (nTmp > nMaxCols)
+ nMaxCols = static_cast<SCCOL>(nTmp);
+
+ n1 = aData.Ref1.nRow;
+ n2 = aData.Ref2.nRow;
+ nTmp = n2 - n1 + 1;
+
+ if (n1 < mnStartRow)
+ mnStartRow = static_cast<SCCOL>(n1);
+ if (n2 > nEndRow)
+ nEndRow = static_cast<SCCOL>(n2);
+ if (nTmp > nMaxRows)
+ nMaxRows = static_cast<SCCOL>(nTmp);
+ }
+
+ // total column size ?
+ SCCOL nC = nEndCol - mnStartCol + 1;
+ if (nC == 1)
+ {
+ meGlue = GLUETYPE_ROWS;
+ return;
+ }
+ // total row size ?
+ SCROW nR = nEndRow - mnStartRow + 1;
+ if (nR == 1)
+ {
+ meGlue = GLUETYPE_COLS;
+ return;
+ }
+ sal_uInt32 nCR = static_cast<sal_uInt32>(nC*nR);
+
+ const sal_uInt8 nHole = 0;
+ const sal_uInt8 nOccu = 1;
+ const sal_uInt8 nFree = 2;
+ const sal_uInt8 nGlue = 3;
+
+ vector<sal_uInt8> aCellStates(nCR);
+ for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end();
+ itr != itrEnd; ++itr)
+ {
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
+ SCCOL nCol1 = static_cast<SCCOL>(aData.Ref1.nCol) - mnStartCol;
+ SCCOL nCol2 = static_cast<SCCOL>(aData.Ref2.nCol) - mnStartCol;
+ SCROW nRow1 = static_cast<SCROW>(aData.Ref1.nRow) - mnStartRow;
+ SCROW nRow2 = static_cast<SCROW>(aData.Ref2.nRow) - mnStartRow;
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ size_t i = nCol*nR + nRow;
+ aCellStates[i] = nOccu;
+ }
+ }
+ bool bGlue = true;
+
+ size_t i = 0;
+ bool bGlueCols = false;
+ for (SCCOL nCol = 0; bGlue && nCol < nC; ++nCol)
+ {
+ for (SCROW nRow = 0; bGlue && nRow < nR; ++nRow)
+ {
+ i = nCol*nR + nRow;
+ if (aCellStates[i] == nOccu)
+ {
+ if (nRow > 0 && nRow > 0)
+ bGlue = false;
+ else
+ nRow = nR;
+ }
+ else
+ aCellStates[i] = nFree;
+ }
+ i = (nCol+1)*nR - 1; // index for the last cell in the column.
+ if (bGlue && (aCellStates[i] == nFree))
+ {
+ aCellStates[i] = nGlue;
+ bGlueCols = true;
+ }
+ }
+
+ bool bGlueRows = false;
+ for (SCROW nRow = 0; bGlue && nRow < nR; ++nRow)
+ {
+ i = nRow;
+ for (SCCOL nCol = 0; bGlue && nCol < nC; ++nCol, i += nR)
+ {
+ if (aCellStates[i] == nOccu)
+ {
+ if (nCol > 0 && nRow > 0)
+ bGlue = false;
+ else
+ nCol = nC;
+ }
+ else
+ aCellStates[i] = nFree;
+ }
+ i = (nC-1)*nR + nRow; // index for the row position in the last column.
+ if (bGlue && aCellStates[i] == nFree)
+ {
+ aCellStates[i] = nGlue;
+ bGlueRows = true;
+ }
+ }
+
+ i = 1;
+ for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
+ if (aCellStates[i] == nHole)
+ bGlue = false;
+
+ if (bGlue)
+ {
+ if (bGlueCols && bGlueRows)
+ meGlue = GLUETYPE_BOTH;
+ else if (bGlueRows)
+ meGlue = GLUETYPE_ROWS;
+ else
+ meGlue = GLUETYPE_COLS;
+ if (aCellStates.front() != nOccu)
+ mbDummyUpperLeft = true;
+ }
+ else
+ meGlue = GLUETYPE_NONE;
+}
+
+void Chart2Positioner::createPositionMap()
+{
+ if (meGlue == GLUETYPE_NA && mpPositionMap.get())
+ mpPositionMap.reset(NULL);
+
+ if (mpPositionMap.get())
+ return;
+
+ glueState();
+
+ bool bNoGlue = (meGlue == GLUETYPE_NONE);
+ auto_ptr<Table> pCols(new Table);
+ auto_ptr<FormulaToken> pNewAddress;
+ auto_ptr<Table> pNewRowTable(new Table);
+ Table* pCol = NULL;
+ SCROW nNoGlueRow = 0;
+ for (vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end();
+ itr != itrEnd; ++itr)
+ {
+ const ScSharedTokenRef& pToken = *itr;
+
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ String aTabName = bExternal ? pToken->GetString() : String();
+
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, *itr);
+ const ScSingleRefData& s = aData.Ref1;
+ const ScSingleRefData& e = aData.Ref2;
+ SCCOL nCol1 = s.nCol, nCol2 = e.nCol;
+ SCROW nRow1 = s.nRow, nRow2 = e.nRow;
+ SCTAB nTab1 = s.nTab, nTab2 = e.nTab;
+
+ for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
+ {
+ // What's this for ???
+ sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
+ (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
+ {
+ if ((mpDoc->GetColFlags(nCol, nTab) & CR_HIDDEN) != 0)
+ continue;
+
+ if (bNoGlue || meGlue == GLUETYPE_ROWS)
+ {
+ pCol = static_cast<Table*>(pCols->Get(nInsCol));
+ if (!pCol)
+ {
+ pCol = pNewRowTable.get();
+ pCols->Insert(nInsCol, pNewRowTable.release());
+ pNewRowTable.reset(new Table);
+ }
+ }
+ else
+ {
+ if (pCols->Insert(nInsCol, pNewRowTable.get()))
+ {
+ pCol = pNewRowTable.release();
+ pNewRowTable.reset(new Table);
+ }
+ else
+ pCol = static_cast<Table*>(pCols->Get(nInsCol));
+ }
+
+ sal_uInt32 nInsRow = static_cast<sal_uInt32>(bNoGlue ? nNoGlueRow : nRow1);
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
+ {
+ if ((mpDoc->GetRowFlags(nRow, nTab) & CR_HIDDEN) != 0)
+ continue;
+
+ ScSingleRefData aCellData;
+ aCellData.InitFlags();
+ aCellData.SetFlag3D(true);
+ aCellData.SetColRel(false);
+ aCellData.SetRowRel(false);
+ aCellData.SetTabRel(false);
+ aCellData.nCol = nCol;
+ aCellData.nRow = nRow;
+ aCellData.nTab = nTab;
+
+ if (bExternal)
+ pNewAddress.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
+ else
+ pNewAddress.reset(new ScSingleRefToken(aCellData));
+
+ if (pCol->Insert(nInsRow, pNewAddress.get()))
+ pNewAddress.release(); // To prevent the instance from being destroyed.
+ }
+ }
+ }
+ nNoGlueRow += nRow2 - nRow1 + 1;
+ }
+ pNewAddress.reset(NULL);
+ pNewRowTable.reset(NULL);
+
+ bool bColAdd = mbRowHeaders;
+ bool bRowAdd = mbColHeaders;
+
+ SCSIZE nColCount = static_cast<SCSIZE>(pCols->Count());
+ SCSIZE nRowCount = 0;
+ pCol = static_cast<Table*>(pCols->First());
+ if (pCol)
+ {
+ if (mbDummyUpperLeft)
+ pCol->Insert(0, NULL); // Dummy fuer Beschriftung
+ nRowCount = static_cast<SCSIZE>(pCol->Count());
+ }
+ else
+ nRowCount = 0;
+
+ if (nColCount > 0 && bColAdd)
+ nColCount -= 1;
+ if (nRowCount > 0 && bRowAdd)
+ nRowCount -= 1;
+
+ if (nColCount == 0 || nRowCount == 0)
+ {
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, mpRefTokens->front());
+ if (pCols->Count() > 0)
+ pCol = static_cast<Table*>(pCols->First());
+ else
+ {
+ pCol = new Table;
+ pCols->Insert(0, pCol);
+ }
+ nColCount = 1;
+ if (pCol->Count() > 0)
+ {
+ FormulaToken* pPos = static_cast<FormulaToken*>(pCol->First());
+ if (pPos)
+ {
+ delete pPos;
+ pCol->Replace(pCol->GetCurKey(), NULL);
+ }
+ }
+ else
+ pCol->Insert(0, NULL);
+
+ nRowCount = 1;
+ bColAdd = false;
+ bRowAdd = false;
+ }
+ else
+ {
+ if (bNoGlue)
+ {
+ Table* pFirstCol = static_cast<Table*>(pCols->First());
+ sal_uInt32 nCount = pFirstCol->Count();
+ pFirstCol->First();
+ for (sal_uInt32 n = 0; n < nCount; ++n, pFirstCol->Next())
+ {
+ sal_uInt32 nKey = pFirstCol->GetCurKey();
+ pCols->First();
+ for (pCol = static_cast<Table*>(pCols->Next()); pCol; pCol = static_cast<Table*>(pCols->Next()))
+ pCol->Insert(nKey, NULL);
+ }
+ }
+ }
+ mpPositionMap.reset(
+ new Chart2PositionMap(
+ static_cast<SCCOL>(nColCount), static_cast<SCROW>(nRowCount),
+ bColAdd, bRowAdd, *pCols));
+
+ // Destroy all column instances.
+ for (pCol = static_cast<Table*>(pCols->First()); pCol; pCol = static_cast<Table*>(pCols->Next()))
+ delete pCol;
+}
+
+// ============================================================================
+
+/**
+ * Function object to create a range string from a token list.
+ */
+class Tokens2RangeString : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ Tokens2RangeString(ScDocument* pDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
+ mpRangeStr(new OUStringBuffer),
+ mpDoc(pDoc),
+ meGrammar(eGram),
+ mcRangeSep(cRangeSep),
+ mbFirst(true)
+ {
+ }
+
+ Tokens2RangeString(const Tokens2RangeString& r) :
+ mpRangeStr(r.mpRangeStr),
+ mpDoc(r.mpDoc),
+ meGrammar(r.meGrammar),
+ mcRangeSep(r.mcRangeSep),
+ mbFirst(r.mbFirst)
+ {
+ }
+
+ void operator() (const ScSharedTokenRef& rToken)
+ {
+ ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
+ aCompiler.SetGrammar(meGrammar);
+ String aStr;
+ aCompiler.CreateStringFromToken(aStr, rToken.get());
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+ mpRangeStr->append(aStr);
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ Tokens2RangeString(); // disabled
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ FormulaGrammar::Grammar meGrammar;
+ sal_Unicode mcRangeSep;
+ bool mbFirst;
+};
+
+/**
+ * Function object to convert a list of tokens into a string form suitable
+ * for ODF export. In ODF, a range is expressed as
+ *
+ * (start cell address):(end cell address)
+ *
+ * and each address doesn't include any '$' symbols.
+ */
+class Tokens2RangeStringXML : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ Tokens2RangeStringXML(ScDocument* pDoc) :
+ mpRangeStr(new OUStringBuffer),
+ mpDoc(pDoc),
+ mcRangeSep(' '),
+ mcAddrSep(':'),
+ mbFirst(true)
+ {
+ }
+
+ Tokens2RangeStringXML(const Tokens2RangeStringXML& r) :
+ mpRangeStr(r.mpRangeStr),
+ mpDoc(r.mpDoc),
+ mcRangeSep(r.mcRangeSep),
+ mcAddrSep(r.mcAddrSep),
+ mbFirst(r.mbFirst)
+ {
+ }
+
+ void operator() (const ScSharedTokenRef& rToken)
+ {
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+
+ ScSharedTokenRef aStart, aEnd;
+ splitRangeToken(rToken, aStart, aEnd);
+ ScCompiler aCompiler(mpDoc, ScAddress(0,0,0));
+ aCompiler.SetGrammar(FormulaGrammar::GRAM_ENGLISH);
+ {
+ String aStr;
+ aCompiler.CreateStringFromToken(aStr, aStart.get());
+ mpRangeStr->append(aStr);
+ }
+ mpRangeStr->append(mcAddrSep);
+ {
+ String aStr;
+ aCompiler.CreateStringFromToken(aStr, aEnd.get());
+ mpRangeStr->append(aStr);
+ }
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ Tokens2RangeStringXML(); // disabled
+
+ void splitRangeToken(const ScSharedTokenRef& pToken, ScSharedTokenRef& rStart, ScSharedTokenRef& rEnd) const
+ {
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ String aTabName = bExternal ? pToken->GetString() : String();
+
+ // In saving to XML, we don't prepend address with '$'.
+ setRelative(aData.Ref1);
+ setRelative(aData.Ref2);
+ if (bExternal)
+ rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
+ else
+ rStart.reset(new ScSingleRefToken(aData.Ref1));
+
+ if (bExternal)
+ rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
+ else
+ rEnd.reset(new ScSingleRefToken(aData.Ref2));
+ }
+
+ void setRelative(ScSingleRefData& rData) const
+ {
+ rData.SetColRel(true);
+ rData.SetRowRel(true);
+ rData.SetTabRel(true);
+ }
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ sal_Unicode mcRangeSep;
+ sal_Unicode mcAddrSep;
+ bool mbFirst;
+};
+
+void lcl_convertTokensToString(OUString& rStr, const vector<ScSharedTokenRef>& rTokens, ScDocument* pDoc)
+{
+ const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
+ FormulaGrammar::Grammar eGrammar = pDoc->GetGrammar();
+ Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
+ func = for_each(rTokens.begin(), rTokens.end(), func);
+ func.getString(rStr);
+}
+
+void lcl_convertTokenToString(OUString& rStr, const ScSharedTokenRef& rToken, ScDocument* pDoc,
+ FormulaGrammar::Grammar eGrammar)
+{
+ const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
+ Tokens2RangeString func(pDoc, eGrammar, cRangeSep);
+ func.operator() (rToken);
+ func.getString(rStr);
+}
+
} // anonymous namespace
// DataProvider ==============================================================
@@ -273,14 +1038,356 @@ void lcl_SeperateOneRowRange(ScRange aR, const ScAddress& rPos, ScRangeListRef&
}
}
- ScRangeList aRangeList;
- USHORT nResult = aRangeList.Parse( aRangeRepresentation, m_pDocument );
- //! if anything is missing, SCA_VALID shouldn't be set
- const USHORT nNeeded = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
- SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2;
- bool bValid = ( (nResult & nNeeded ) == nNeeded );
+ vector<ScSharedTokenRef> aTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aTokens, aRangeRepresentation, m_pDocument);
+ return !aTokens.empty();
+}
+
+namespace {
+
+class RemoveHeaderFromRanges : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ RemoveHeaderFromRanges(const ScSharedTokenRef& rHeaderCell, bool bOrientCol) :
+ mpTokens(new vector<ScSharedTokenRef>),
+ mpHeaderCell(rHeaderCell),
+ mbOrientCol(bOrientCol)
+ {
+ }
+
+ RemoveHeaderFromRanges(const RemoveHeaderFromRanges& r) :
+ mpTokens(r.mpTokens),
+ mpHeaderCell(r.mpHeaderCell),
+ mbOrientCol(r.mbOrientCol)
+ {
+ }
+
+ void operator() (const ScSharedTokenRef& pRange)
+ {
+ if (!isContained(pRange))
+ {
+ // header cell is not part of this range. Just add it to the
+ // range list and move on.
+ ScRefTokenHelper::join(*mpTokens, pRange);
+ return;
+ }
+
+ // This range contains the header cell.
+
+ ScComplexRefData aRange;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aRange, pRange);
+ const ScSingleRefData& s = aRange.Ref1;
+ const ScSingleRefData& e = aRange.Ref2;
+ const ScSingleRefData& h = mpHeaderCell->GetSingleRef();
+
+ if (equals(s, e))
+ // This range *only* contains the header cell. Skip it.
+ return;
+
+ if (s.nTab != e.nTab)
+ // 3D range has no business being here....
+ return;
+
+ if (mbOrientCol)
+ {
+ // column major
+
+ if (s.nCol == e.nCol)
+ {
+ // single column range.
+ splitSingleColRange(pRange, s, e);
+ }
+ else
+ {
+ if (s.nCol == h.nCol)
+ {
+ // header cell is in the first column.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(s.nCol, e.nRow, s.nTab);
+ splitSingleColRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(s.nCol + 1, s.nRow, s.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ else if (e.nCol == h.nCol)
+ {
+ // header cell is in the last column.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(e.nCol, s.nRow, s.nTab);
+ splitSingleColRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(e.nCol - 1, e.nRow, e.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ else
+ {
+ // header cell is somewhere between the first and last columns.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(h.nCol - 1, e.nRow, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(h.nCol, s.nRow, s.nTab);
+ r.Ref2.InitAddress(h.nCol, e.nRow, e.nTab);
+ splitSingleColRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(h.nCol + 1, s.nRow, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ }
+ }
+ else
+ {
+ // row major
+
+ if (s.nRow == e.nRow)
+ {
+ // Single row range.
+ splitSingleRowRange(pRange, s, e);
+ }
+ else
+ {
+ if (s.nRow == h.nRow)
+ {
+ // header cell is in the first row.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(e.nCol, s.nRow, s.nTab);
+ splitSingleRowRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(s.nCol, s.nRow + 1, s.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ else if (e.nRow == h.nRow)
+ {
+ // header cell is in the last row.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(s.nCol, e.nRow, s.nTab);
+ splitSingleRowRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(e.nCol, e.nRow - 1, e.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ else
+ {
+ // header cell is somewhere between the 1st and last rows.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(e.nCol, h.nRow - 1, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(s.nCol, h.nRow, s.nTab);
+ r.Ref2.InitAddress(e.nCol, h.nRow, e.nTab);
+ splitSingleRowRange(pNew, r.Ref1, r.Ref2);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(s.nCol, h.nRow + 1, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ }
+ }
+ }
+
+ void getNewTokens(vector<ScSharedTokenRef>& rTokens)
+ {
+ mpTokens->swap(rTokens);
+ }
+
+private:
+
+ void splitSingleColRange(const ScSharedTokenRef& pRange, const ScSingleRefData& s, const ScSingleRefData& e)
+ {
+ const ScSingleRefData& h = mpHeaderCell->GetSingleRef();
+
+ if (equals(s, h))
+ {
+ // header is at the top.
+
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.nRow += 1;
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ else if (equals(e, h))
+ {
+ // header is at the bottom.
+
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.nRow -= 1;
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ else
+ {
+ // header is somewhere in the middle.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(h.nCol, h.nRow - 1, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(h.nCol, h.nRow + 1, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ }
+
+ void splitSingleRowRange(const ScSharedTokenRef& pRange, const ScSingleRefData& s, const ScSingleRefData& e)
+ {
+ const ScSingleRefData& h = mpHeaderCell->GetSingleRef();
+
+ if (equals(s, h))
+ {
+ // header is at the top.
+
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.nCol += 1;
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ else if (equals(e, h))
+ {
+ // header is at the bottom.
+
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.nCol -= 1;
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ else
+ {
+ // header is somewhere in the middle.
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref2.InitAddress(h.nCol - 1, h.nRow, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+
+ {
+ ScSharedTokenRef pNew(static_cast<ScToken*>(pRange->Clone()));
+ ScComplexRefData& r = pNew->GetDoubleRef();
+ r.Ref1.InitAddress(h.nCol + 1, h.nRow, h.nTab);
+ ScRefTokenHelper::join(*mpTokens, pNew);
+ }
+ }
+ }
+
+ /**
+ * Compare two single ref data for equality, but only compare their
+ * absolute cell addresses while ignoring flags and relative addresses.
+ */
+ bool equals(const ScSingleRefData& r1, const ScSingleRefData& r2) const
+ {
+ return (r1.nCol == r2.nCol) && (r1.nRow == r2.nRow) && (r1.nTab == r2.nTab);
+ }
+
+ bool isContained(const ScSharedTokenRef& pRange)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(mpHeaderCell);
+ if (bExternal != ScRefTokenHelper::isExternalRef(pRange))
+ // internval vs external.
+ return false;
+
+ if (bExternal)
+ {
+ if (pRange->GetIndex() != mpHeaderCell->GetIndex())
+ // different external files.
+ return false;
+
+ if (pRange->GetString() != mpHeaderCell->GetString())
+ // different table.
+ return false;
+ }
+
+ ScComplexRefData aRange;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aRange, pRange);
+ const ScSingleRefData& rCell = mpHeaderCell->GetSingleRef();
+
+ bool bRowContained = (aRange.Ref1.nRow <= rCell.nRow) && (rCell.nRow <= aRange.Ref2.nRow);
+ bool bColContained = (aRange.Ref1.nCol <= rCell.nCol) && (rCell.nCol <= aRange.Ref2.nCol);
+ bool bTabContained = (aRange.Ref1.nTab <= rCell.nTab) && (rCell.nTab <= aRange.Ref2.nTab);
+
+ return (bRowContained && bColContained && bTabContained);
+ }
+
+private:
+ shared_ptr< vector<ScSharedTokenRef> > mpTokens;
+
+ /**
+ * Stores header cell position. Must be a single ref token i.e. either
+ * ScSingleRefToken or ScExternalSingleRefToken.
+ */
+ ScSharedTokenRef mpHeaderCell;
+
+ bool mbOrientCol;
+};
- return bValid;
+}
+
+static void lcl_removeHeaderFromRanges(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& rHeaderCell, bool bOrientCol)
+{
+ RemoveHeaderFromRanges func(rHeaderCell, bOrientCol);
+ func = for_each(rTokens.begin(), rTokens.end(), func);
+ func.getNewTokens(rTokens);
}
uno::Reference< chart2::data::XDataSource> SAL_CALL
@@ -293,9 +1400,8 @@ ScChart2DataProvider::createDataSource(
throw uno::RuntimeException();
uno::Reference< chart2::data::XDataSource> xResult;
- sal_Bool bLabel = sal_True;
-// sal_Bool bCat = sal_True;
- sal_Bool bOrientCol = sal_True;
+ bool bLabel = true;
+ bool bOrientCol = true;
::rtl::OUString aRangeRepresentation;
uno::Sequence< sal_Int32 > aSequenceMapping;
for(sal_Int32 i = 0; i < aArguments.getLength(); ++i)
@@ -324,369 +1430,206 @@ ScChart2DataProvider::createDataSource(
{
aArguments[i].Value >>= aSequenceMapping;
}
-/* else if (aArguments[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("HasCategories")))
- {
- bCat = ::cppu::any2bool(aArguments[i].Value);
- }*/
}
- ScRangeListRef aRangeList = new ScRangeList;
- USHORT nValid = aRangeList->Parse( aRangeRepresentation, m_pDocument);
- if ( (nValid & SCA_VALID) == SCA_VALID )
- {
- if(bLabel)
- addUpperLeftCornerIfMissing( aRangeList );
+ vector<ScSharedTokenRef> aRefTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aRefTokens, aRangeRepresentation, m_pDocument);
+ if (aRefTokens.empty())
+ // Invalid range representation. Bail out.
+ throw lang::IllegalArgumentException();
- ScChartPositioner aChartPositioner(m_pDocument, aRangeList);
- BOOL bColHeaders = (bOrientCol ? bLabel : FALSE );
- BOOL bRowHeaders = (bOrientCol ? FALSE : bLabel );
- aChartPositioner.SetHeaders( bColHeaders, bRowHeaders );
+ if (bLabel)
+ addUpperLeftCornerIfMissing(aRefTokens);
- const ScChartPositionMap* pChartMap = aChartPositioner.GetPositionMap();
+ bool bColHeaders = (bOrientCol ? bLabel : false );
+ bool bRowHeaders = (bOrientCol ? false : bLabel );
- ScChart2DataSource* pDS = NULL;
+ Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
+ aChPositioner.setHeaders(bColHeaders, bRowHeaders);
- if (pChartMap)
- {
- std::list < ScChart2LabeledDataSequence* > aSeqs;
+ const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
+ if (!pChartMap)
+ // No chart position map instance. Bail out.
+ return xResult;
+
+ ScChart2DataSource* pDS = NULL;
+ std::list < ScChart2LabeledDataSequence* > aSeqs;
- // Fill Categories
+ // Fill Categories
- ScChart2LabeledDataSequence* pHeader = NULL;
- if (bOrientCol ? aChartPositioner.HasRowHeaders() : aChartPositioner.HasColHeaders())
+ ScChart2LabeledDataSequence* pHeader = NULL;
+ if (bOrientCol ? aChPositioner.hasRowHeaders() : aChPositioner.hasColHeaders())
+ {
+ pHeader = new ScChart2LabeledDataSequence(m_pDocument);
+ sal_Int32 nCount = static_cast< sal_Int32 >( bOrientCol ? pChartMap->getRowCount() : pChartMap->getColCount() );
+ vector<ScSharedTokenRef> aRefTokens2;
+ ScSharedTokenRef pLabelToken;
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ const FormulaToken* pPos = bOrientCol ?
+ pChartMap->getRowHeaderPosition(static_cast<SCROW>(i)) :
+ pChartMap->getColHeaderPosition(static_cast<SCCOL>(i));
+ if (pPos)
{
- pHeader = new ScChart2LabeledDataSequence(m_pDocument);
- sal_Int32 nCount = static_cast< sal_Int32 >( bOrientCol ? pChartMap->GetRowCount() : pChartMap->GetColCount() );
- ScRangeList* pRanges = new ScRangeList;
- ScAddress aLabel;
- sal_Bool bLabelCell = sal_False;
- for (sal_Int32 i = 0; i < nCount; ++i)
+ ScSharedTokenRef p(static_cast<ScToken*>(pPos->Clone()));
+ ScRefTokenHelper::join(aRefTokens2, p);
+ if (!pLabelToken)
{
- const ScAddress* pPos = bOrientCol ?
- pChartMap->GetRowHeaderPosition( static_cast< SCROW >( i ) ) :
- pChartMap->GetColHeaderPosition( static_cast< SCCOL >( i ) );
- if (pPos)
+ pLabelToken = p;
+ StackVar eType = pLabelToken->GetType();
+ if (eType == svSingleRef || eType == svExternalSingleRef)
{
- pRanges->Join(ScRange(*pPos));
- if (!bLabelCell)
- {
- aLabel = *pPos;
- if (bOrientCol)
- aLabel.IncRow( -1 );
- else
- aLabel.IncCol( -1 );
- bLabelCell = sal_True;
- }
- }
- }
- if (bLabelCell && bLabel)
- {
- ScRangeList* pLabelRanges = new ScRangeList;
- pLabelRanges->Join(ScRange(aLabel));
- uno::Reference < chart2::data::XDataSequence > xLabelSeq(new ScChart2DataSequence(m_pDocument, this, pLabelRanges));
- uno::Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
- if (xLabelProps.is())
- xLabelProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));
- pHeader->setLabel(xLabelSeq);
+ ScSingleRefData& r = pLabelToken->GetSingleRef();
+ if (bOrientCol)
+ r.nRow -= 1;
+ else
+ r.nCol -= 1;
+ }
}
- else if (bLabelCell)
- {
- pRanges->Join(ScRange(aLabel));
-/* uno::Reference < chart2::data::XDataSequence > xLabelSeq(new ScChart2EmptyDataSequence(m_pDocument, this, new ScRangeList(*pRanges), bOrientCol));
- uno::Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
- if (xLabelProps.is())
- xLabelProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));
- pHeader->setLabel(xLabelSeq);*/
- }
- uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( m_pDocument, this, pRanges ) );
-/* if (bCat)
- {
- uno::Reference< beans::XPropertySet > xProps(xSeq, uno::UNO_QUERY);
- if (xProps.is())
- xProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
- }*/
- pHeader->setValues(xSeq);
}
- if (pHeader)
- aSeqs.push_back(pHeader);
+ }
+ if (pLabelToken)
+ {
+ if (bLabel)
+ {
+ auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>);
+ pTokens->push_back(pLabelToken);
+ Reference < chart2::data::XDataSequence > xLabelSeq(new ScChart2DataSequence(m_pDocument, this, pTokens.release()));
+ Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
+ if (xLabelProps.is())
+ xLabelProps->setPropertyValue(
+ OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)),
+ uno::makeAny(OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));
+ pHeader->setLabel(xLabelSeq);
+ }
+ else
+ ScRefTokenHelper::join(aRefTokens2, pLabelToken);
+ }
+ auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>);
+ pTokens->swap(aRefTokens2);
+ uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( m_pDocument, this, pTokens.release()) );
+ pHeader->setValues(xSeq);
+ }
+ if (pHeader)
+ aSeqs.push_back(pHeader);
- ScRangeListRef xCatRanges = new ScRangeList();
+ // Fill Serieses with Labels
- // Fill Serieses with Labels
+ sal_Int32 nCount = bOrientCol ? pChartMap->getColCount() : pChartMap->getRowCount();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ ScChart2LabeledDataSequence* pLabeled = new ScChart2LabeledDataSequence(m_pDocument);
+ uno::Reference < chart2::data::XDataSequence > xLabelSeq;
+ auto_ptr< vector<ScSharedTokenRef> > pRanges(NULL);
+ if (bOrientCol)
+ pRanges.reset(pChartMap->getColRanges(static_cast<SCCOL>(i)));
+ else
+ pRanges.reset(pChartMap->getRowRanges(static_cast<SCROW>(i)));
+
+ ScSharedTokenRef pHeaderCell;
+ if (bOrientCol)
+ {
+ const FormulaToken* p = pChartMap->getColHeaderPosition(static_cast<SCCOL>(i));
+ if (p)
+ pHeaderCell.reset(static_cast<ScToken*>(p->Clone()));
+ }
+ else
+ {
+ const FormulaToken* p = pChartMap->getRowHeaderPosition(static_cast<SCROW>(i));
+ if (p)
+ pHeaderCell.reset(static_cast<ScToken*>(p->Clone()));
+ }
- sal_Int32 nCount = bOrientCol ? pChartMap->GetColCount() : pChartMap->GetRowCount();
- for (sal_Int32 i = 0; i < nCount; ++i)
+ if (bLabel)
+ {
+ if (!pHeaderCell && pRanges.get() && !pRanges->empty())
{
- ScChart2LabeledDataSequence* pLabeled = new ScChart2LabeledDataSequence(m_pDocument);
- uno::Reference < chart2::data::XDataSequence > xLabelSeq;
- ScRangeListRef xRanges( bOrientCol ?
- pChartMap->GetColRanges( static_cast< SCCOL >( i ) ) :
- pChartMap->GetRowRanges( static_cast< SCROW >( i ) ) );
- const ScAddress* pPos = bOrientCol ?
- pChartMap->GetColHeaderPosition( static_cast< SCCOL >( i ) ) :
- pChartMap->GetRowHeaderPosition( static_cast< SCROW >( i ) );
-
- if (bLabel/* && (bOrientCol ? aChartPositioner.HasColHeaders() : aChartPositioner.HasRowHeaders())*/)
+ const ScSharedTokenRef& p = pRanges->front();
+ if (p && ScRefTokenHelper::isRef(p))
{
- if (!pPos)
- {
- ScRangePtr pR = xRanges->First();
- if (pR)
- {
- pR->Justify();
- pPos = &(pR->aStart);
- }
+ // Take the first cell in the range as the header position.
+ ScSingleRefData aData = p->GetSingleRef();
+ bool bExternal = ScRefTokenHelper::isExternalRef(p);
+ if (bExternal)
+ {
+ sal_uInt16 nFileId = p->GetIndex();
+ const String& rTabName = p->GetString();
+ pHeaderCell.reset(new ScExternalSingleRefToken(nFileId, rTabName, aData));
}
- if (pPos)
- {
- ScRangeList* pRanges = new ScRangeList;
- ScRange aPosRange(*pPos);
- pRanges->Join(aPosRange);
- xLabelSeq.set(new ScChart2DataSequence(m_pDocument, this, pRanges));
- uno::Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
- if (xLabelProps.is())
- xLabelProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));
-
- // remove Header from Ranges
- ScRangePtr pR;
- ScRangeListRef xRangeList = new ScRangeList;
- for ( pR = xRanges->First(); pR; pR = xRanges->Next() )
- {
- if (pR->In(*pPos))
- {
- pR->Justify();
- if (pR->aStart != pR->aEnd)
- {
- DBG_ASSERT(pR->aStart.Tab() == pR->aEnd.Tab(), "a 3D range should not happen in this case");
- if(bOrientCol)
- {
- if (pR->aStart.Col() == pR->aEnd.Col())
- {
- lcl_SeperateOneColumnRange(*pR, *pPos, xRangeList);
- }
- else
- {
- if (pR->aStart.Col() == pPos->Col())
- {
- lcl_SeperateOneColumnRange(ScRange(pR->aStart, ScAddress(pR->aStart.Col(), pR->aEnd.Row(), pR->aStart.Tab())), *pPos, xRangeList);
- xRangeList->Join(ScRange(ScAddress(pR->aStart.Col() + 1, pR->aStart.Row(), pR->aStart.Tab()), pR->aEnd));
- }
- else if (pR->aEnd.Col() == pPos->Col())
- {
- lcl_SeperateOneColumnRange(ScRange(ScAddress(pR->aEnd.Col(), pR->aStart.Row(), pR->aStart.Tab()), pR->aEnd), *pPos, xRangeList);
- xRangeList->Join(ScRange(pR->aStart, ScAddress(pR->aEnd.Col() - 1, pR->aEnd.Row(), pR->aEnd.Tab())));
- }
- else
- {
- xRangeList->Join(ScRange(pR->aStart, ScAddress(pPos->Col() - 1, pR->aEnd.Row(), pPos->Tab())));
- lcl_SeperateOneColumnRange(ScRange(ScAddress(pPos->Col(), pR->aStart.Row(), pR->aStart.Tab()), ScAddress(pPos->Col(), pR->aEnd.Row(), pR->aEnd.Tab())), *pPos, xRangeList);
- xRangeList->Join(ScRange(ScAddress(pPos->Col() + 1, pR->aStart.Row(), pPos->Tab()), pR->aEnd));
- }
- }
- }
- else
- {
- if (pR->aStart.Row() == pR->aEnd.Row())
- {
- lcl_SeperateOneRowRange(*pR, *pPos, xRangeList);
- }
- else
- {
- if (pR->aStart.Row() == pPos->Row())
- {
- lcl_SeperateOneRowRange(ScRange(pR->aStart, ScAddress(pR->aEnd.Col(), pR->aStart.Row(), pR->aStart.Tab())), *pPos, xRangeList);
- xRangeList->Join(ScRange(ScAddress(pR->aStart.Col(), pR->aStart.Row() + 1, pR->aStart.Tab()), pR->aEnd));
- }
- else if (pR->aEnd.Row() == pPos->Row())
- {
- lcl_SeperateOneRowRange(ScRange(ScAddress(pR->aStart.Col(), pR->aEnd.Row(), pR->aStart.Tab()), pR->aEnd), *pPos, xRangeList);
- xRangeList->Join(ScRange(pR->aStart, ScAddress(pR->aEnd.Col(), pR->aEnd.Row() - 1, pR->aEnd.Tab())));
- }
- else
- {
- xRangeList->Join(ScRange(pR->aStart, ScAddress(pR->aEnd.Col(), pPos->Row() - 1, pPos->Tab())));
- lcl_SeperateOneRowRange(ScRange(ScAddress(pR->aStart.Col(), pPos->Row(), pR->aStart.Tab()), ScAddress(pR->aEnd.Col(), pPos->Row(), pR->aEnd.Tab())), *pPos, xRangeList);
- xRangeList->Join(ScRange(ScAddress(pR->aStart.Col(), pPos->Row() + 1, pPos->Tab()), pR->aEnd));
- }
- }
- }
- }
- }
- else
- xRangeList->Join(*pR);
- }
- xRanges = xRangeList;
- }
- }
- else
- {
- if (pPos)
- xRanges->Join(ScRange(*pPos));
-/* xLabelSeq.set(new ScChart2EmptyDataSequence(m_pDocument, this, xRanges, bOrientCol));
- uno::Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
- if (xLabelProps.is())
- xLabelProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));*/
+ else
+ pHeaderCell.reset(new ScSingleRefToken(aData));
}
-
- // FIXME: if there are no labels the column or row name should be taken
-/* else if (bLabel)
- {
- if (bOrientCol)
- {
- String aString = ScGlobal::GetRscString(STR_COLUMN);
- aString += ' ';
- // aString += String::CreateFromInt32( pCols[nCol]+1 );
- ScAddress aPos( nCol, 0, 0 );
- String aColStr;
- aPos.Format( aColStr, SCA_VALID_COL, NULL );
- aString += aColStr;
- }
- else
- {
- String aString = ScGlobal::GetRscString(STR_ROW);
- aString += ' ';
- aString += String::CreateFromInt32( nRow+1 );
- }
- }*/
-
-/* ScRangePtr pR;
- for ( pR = xRanges->First(); pR; pR = xRanges->Next() )
- xCatRanges->Join(*pR);*/
-
- uno::Reference < chart2::data::XDataSequence > xSeq(new ScChart2DataSequence(m_pDocument, this, new ScRangeList(*xRanges)));
-/* if (bCat && !pHeader && (i == 0))
- {
- uno::Reference< beans::XPropertySet > xProps(xSeq, uno::UNO_QUERY);
- if (xProps.is())
- xProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
- }*/
- pLabeled->setValues(xSeq);
- pLabeled->setLabel(xLabelSeq);
-
- aSeqs.push_back(pLabeled);
}
+ if (pHeaderCell)
+ {
+ auto_ptr< vector<ScSharedTokenRef> > pTokens(new vector<ScSharedTokenRef>);
+ pTokens->reserve(1);
+ pTokens->push_back(pHeaderCell);
+ xLabelSeq.set(new ScChart2DataSequence(m_pDocument, this, pTokens.release()));
+ uno::Reference< beans::XPropertySet > xLabelProps(xLabelSeq, uno::UNO_QUERY);
+ if (xLabelProps.is())
+ xLabelProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("label"))));
+
+ // remove Header from Ranges
+ lcl_removeHeaderFromRanges(*pRanges, pHeaderCell, bOrientCol);
+ }
+ }
+ else
+ {
+ if (pHeaderCell)
+ ScRefTokenHelper::join(*pRanges, pHeaderCell);
+ }
-/* if (!bCat)
- {
- ScChart2LabeledDataSequence* pCat = new ScChart2LabeledDataSequence(m_pDocument);
-
- uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2EmptyDataSequence( m_pDocument, this, new ScRangeList(*xCatRanges), !bOrientCol ) );
- uno::Reference< beans::XPropertySet > xProps(xSeq, uno::UNO_QUERY);
- if (xProps.is())
- xProps->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_ROLE)), uno::makeAny(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("categories"))));
- pCat->setValues(xSeq);
+ // FIXME: if there are no labels the column or row name should be taken
- aSeqs.push_front(pCat);
- }*/
+ uno::Reference < chart2::data::XDataSequence > xSeq(new ScChart2DataSequence(m_pDocument, this, pRanges.release()));
- pDS = new ScChart2DataSource(m_pDocument);
- std::list < ScChart2LabeledDataSequence* >::iterator aItr(aSeqs.begin());
- std::list < ScChart2LabeledDataSequence* >::iterator aEndItr(aSeqs.end());
+ pLabeled->setValues(xSeq);
+ pLabeled->setLabel(xLabelSeq);
- //reorder labeled sequences according to aSequenceMapping
- std::vector< ScChart2LabeledDataSequence* > aSeqVector;
- while(aItr != aEndItr)
- {
- aSeqVector.push_back(*aItr);
- ++aItr;
- }
+ aSeqs.push_back(pLabeled);
+ }
- std::map< sal_Int32, ScChart2LabeledDataSequence* > aSequenceMap;
- for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
- {
- // note: assuming that the values in the sequence mapping are always non-negative
- std::vector< ScChart2LabeledDataSequence* >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ));
- if( nOldIndex < aSeqVector.size() )
- {
- pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
- aSeqVector[nOldIndex] = 0;
- }
+ pDS = new ScChart2DataSource(m_pDocument);
+ std::list < ScChart2LabeledDataSequence* >::iterator aItr(aSeqs.begin());
+ std::list < ScChart2LabeledDataSequence* >::iterator aEndItr(aSeqs.end());
- }
+ //reorder labeled sequences according to aSequenceMapping
+ std::vector< ScChart2LabeledDataSequence* > aSeqVector;
+ while(aItr != aEndItr)
+ {
+ aSeqVector.push_back(*aItr);
+ ++aItr;
+ }
- std::vector< ScChart2LabeledDataSequence* >::iterator aVectorItr(aSeqVector.begin());
- std::vector< ScChart2LabeledDataSequence* >::iterator aVectorEndItr(aSeqVector.end());
- while(aVectorItr != aVectorEndItr)
- {
- if(*aVectorItr)
- pDS->AddLabeledSequence(*aVectorItr);
- ++aVectorItr;
- }
+ std::map< sal_Int32, ScChart2LabeledDataSequence* > aSequenceMap;
+ for( sal_Int32 nNewIndex = 0; nNewIndex < aSequenceMapping.getLength(); nNewIndex++ )
+ {
+ // note: assuming that the values in the sequence mapping are always non-negative
+ std::vector< ScChart2LabeledDataSequence* >::size_type nOldIndex( static_cast< sal_uInt32 >( aSequenceMapping[nNewIndex] ));
+ if( nOldIndex < aSeqVector.size() )
+ {
+ pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
+ aSeqVector[nOldIndex] = 0;
}
- xResult.set( pDS );
}
- else
+
+ std::vector< ScChart2LabeledDataSequence* >::iterator aVectorItr(aSeqVector.begin());
+ std::vector< ScChart2LabeledDataSequence* >::iterator aVectorEndItr(aSeqVector.end());
+ while(aVectorItr != aVectorEndItr)
{
- throw lang::IllegalArgumentException();
+ if(*aVectorItr)
+ pDS->AddLabeledSequence(*aVectorItr);
+ ++aVectorItr;
}
+ xResult.set( pDS );
return xResult;
}
namespace
{
-void lcl_detectRanges(
- ScRangeListRef & rOutRanges,
- chart::ChartDataRowSource & rOutRowSource,
- bool & rOutRowSourceDetected,
- const uno::Reference< chart2::data::XDataSource >& xDataSource,
- ScDocument * pDoc )
-{
- if(!pDoc)
- return;
-
- ScUnoGuard aGuard;
-
- sal_Int32 nDataInRows = 0;
- sal_Int32 nDataInColumns = 0;
- bool bRowSourceAmbiguous = false;
-
- ::std::vector< ::rtl::OUString > aRangeRepresentations(
- lcl_getRangeRepresentationsFromDataSource( xDataSource ));
- for (::std::vector< ::rtl::OUString >::const_iterator aIt( aRangeRepresentations.begin());
- aIt != aRangeRepresentations.end(); ++aIt)
- {
- ScRangePtr pR;
- ScRangeListRef aRangeList = new ScRangeList;
- aRangeList->Parse( (*aIt), pDoc);
- for ( pR = aRangeList->First(); pR; pR = aRangeList->Next() )
- {
- bRowSourceAmbiguous = bRowSourceAmbiguous || (pR->aStart.Tab() != pR->aEnd.Tab());
- if( ! bRowSourceAmbiguous )
- {
- bool bColDiff( ( pR->aEnd.Col() - pR->aStart.Col() ) != 0 );
- bool bRowDiff( ( pR->aEnd.Row() - pR->aStart.Row() ) != 0 );
-
- if( bColDiff && ! bRowDiff )
- ++nDataInRows;
- else if( bRowDiff && ! bColDiff )
- ++nDataInColumns;
- else if( bRowDiff && bColDiff )
- bRowSourceAmbiguous = true;
-
- if( nDataInRows > 0 && nDataInColumns > 0 )
- bRowSourceAmbiguous = true;
- }
- rOutRanges->Join(*pR);
- }
- }
-
- if( ! bRowSourceAmbiguous )
- {
- rOutRowSourceDetected = true;
- rOutRowSource = ( nDataInRows > 0
- ? chart::ChartDataRowSource_ROWS
- : chart::ChartDataRowSource_COLUMNS );
- }
- else
- {
- // set DataRowSource to the better of the two ambiguities
- rOutRowSource = ( nDataInRows > nDataInColumns
- ? chart::ChartDataRowSource_ROWS
- : chart::ChartDataRowSource_COLUMNS );
- }
-}
bool lcl_HasCategories(
const uno::Reference< chart2::data::XDataSource >& xDataSource,
@@ -732,80 +1675,335 @@ bool lcl_HasFirstCellAsLabel(
} // anonymous namespace
-bool ScChart2DataProvider::addUpperLeftCornerIfMissing( ScRangeListRef& xRanges )
+bool ScChart2DataProvider::addUpperLeftCornerIfMissing(vector<ScSharedTokenRef>& rRefTokens)
{
- bool bChanged=false;
+ using ::std::max;
+ using ::std::min;
+
+ if (rRefTokens.empty())
+ return false;
- //returns true if the corner was added
- ScRangePtr pR = xRanges->First();
- if( !pR )
- return bChanged;
-
- SCCOL nMinColumn = MAXCOLCOUNT;
+ SCCOL nMinCol = MAXCOLCOUNT;
SCROW nMinRow = MAXROWCOUNT;
- SCCOL nMaxColumn = ::std::max( pR->aStart.Col(), pR->aEnd.Col());
- SCROW nMaxRow = ::std::max( pR->aStart.Row(), pR->aEnd.Row());
- SCTAB nTable = pR->aStart.Tab();
- bool bUniqueTable = true;
- for(; pR; pR=xRanges->Next() )
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ SCTAB nTab = 0;
+
+ USHORT nFileId = 0;
+ String aExtTabName;
+ bool bExternal = false;
+
+ vector<ScSharedTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
+
+ // Get the first ref token.
+ ScSharedTokenRef pToken = *itr;
+ switch (pToken->GetType())
{
- if( bUniqueTable && pR->aStart.Tab() != nTable )
+ case svSingleRef:
{
- bUniqueTable = false;
- break;
+ const ScSingleRefData& rData = pToken->GetSingleRef();
+ nMinCol = rData.nCol;
+ nMinRow = rData.nRow;
+ nMaxCol = rData.nCol;
+ nMaxRow = rData.nRow;
+ nTab = rData.nTab;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.nCol, rData.Ref2.nCol);
+ nMinRow = min(rData.Ref1.nRow, rData.Ref2.nRow);
+ nMaxCol = max(rData.Ref1.nCol, rData.Ref2.nCol);
+ nMaxRow = max(rData.Ref1.nRow, rData.Ref2.nRow);
+ nTab = rData.Ref1.nTab;
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rData = pToken->GetSingleRef();
+ nMinCol = rData.nCol;
+ nMinRow = rData.nRow;
+ nMaxCol = rData.nCol;
+ nMaxRow = rData.nRow;
+ nTab = rData.nTab;
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
}
+ break;
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rData = pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.nCol, rData.Ref2.nCol);
+ nMinRow = min(rData.Ref1.nRow, rData.Ref2.nRow);
+ nMaxCol = max(rData.Ref1.nCol, rData.Ref2.nCol);
+ nMaxRow = max(rData.Ref1.nRow, rData.Ref2.nRow);
+ nTab = rData.Ref1.nTab;
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
+ }
+ break;
+ default:
+ ;
+ }
+
+ // Determine the minimum range enclosing all data ranges. Also make sure
+ // that they are all on the same table.
+
+ for (++itr; itr != itrEnd; ++itr)
+ {
+ pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rData = pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.nCol);
+ nMinRow = min(nMinRow, rData.nRow);
+ nMaxCol = max(nMaxCol, rData.nCol);
+ nMaxRow = max(nMaxRow, rData.nRow);
+ if (nTab != rData.nTab || bExternal)
+ return false;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.nCol);
+ nMinCol = min(nMinCol, rData.Ref2.nCol);
+ nMinRow = min(nMinRow, rData.Ref1.nRow);
+ nMinRow = min(nMinRow, rData.Ref2.nRow);
- nMinColumn = ::std::min( nMinColumn, pR->aStart.Col());
- nMinColumn = ::std::min( nMinColumn, pR->aEnd.Col());
- nMinRow = ::std::min( nMinRow, pR->aStart.Row());
- nMinRow = ::std::min( nMinRow, pR->aEnd.Row());
+ nMaxCol = max(nMaxCol, rData.Ref1.nCol);
+ nMaxCol = max(nMaxCol, rData.Ref2.nCol);
+ nMaxRow = max(nMaxRow, rData.Ref1.nRow);
+ nMaxRow = max(nMaxRow, rData.Ref2.nRow);
+
+ if (nTab != rData.Ref1.nTab || bExternal)
+ return false;
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScSingleRefData& rData = pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.nCol);
+ nMinRow = min(nMinRow, rData.nRow);
+ nMaxCol = max(nMaxCol, rData.nCol);
+ nMaxRow = max(nMaxRow, rData.nRow);
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScComplexRefData& rData = pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.nCol);
+ nMinCol = min(nMinCol, rData.Ref2.nCol);
+ nMinRow = min(nMinRow, rData.Ref1.nRow);
+ nMinRow = min(nMinRow, rData.Ref2.nRow);
+
+ nMaxCol = max(nMaxCol, rData.Ref1.nCol);
+ nMaxCol = max(nMaxCol, rData.Ref2.nCol);
+ nMaxRow = max(nMaxRow, rData.Ref1.nRow);
+ nMaxRow = max(nMaxRow, rData.Ref2.nRow);
+ }
+ break;
+ default:
+ ;
+ }
+ }
- nMaxColumn = ::std::max( nMaxColumn, pR->aStart.Col());
- nMaxColumn = ::std::max( nMaxColumn, pR->aEnd.Col());
- nMaxRow = ::std::max( nMaxRow, pR->aStart.Row());
- nMaxRow = ::std::max( nMaxRow, pR->aEnd.Row());
+ if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
+ nMinRow >= MAXROWCOUNT || nMinCol >= MAXCOLCOUNT ||
+ nMaxRow >= MAXROWCOUNT || nMaxCol >= MAXCOLCOUNT)
+ {
+ // Invalid range. Bail out.
+ return false;
}
-
- if( bUniqueTable
- && nMinRow < nMaxRow && nMinColumn < nMaxColumn
- && nMinRow < MAXROWCOUNT && nMinColumn < MAXCOLCOUNT
- && nMaxRow < MAXROWCOUNT && nMaxColumn < MAXCOLCOUNT )
- {
- ScRange aCorner( nMinColumn, nMinRow, nTable );
-
- //check whether the corner is contained
- bool bCornerMissing = !xRanges->In( aCorner );
-
- //and check whether the cells around the corner are contained thus the corner would be a natural part of the range
- bCornerMissing = bCornerMissing && xRanges->In( ScRange( nMinColumn, nMinRow+1, nTable ) );
- bCornerMissing = bCornerMissing && xRanges->In( ScRange( nMinColumn+1, nMinRow, nTable ) );
- bCornerMissing = bCornerMissing && xRanges->In( ScRange( nMinColumn+1, nMinRow+1, nTable ) );
-
- if( bCornerMissing )
- {
- //make a simple rectangular range if possible
- bool bSimpleRange = false;
- if( xRanges->Count()==2 )
+
+ // Check if the following conditions are met:
+ //
+ // 1) The upper-left corner cell is not included.
+ // 2) The three adjacent cells of that corner cell are included.
+
+ bool bRight = false, bBottom = false, bDiagonal = false;
+ for (itr = rRefTokens.begin(); itr != itrEnd; ++itr)
+ {
+ pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
{
- ScRange aRightPart( ScAddress( nMinColumn+1, nMinRow, nTable), ScAddress( nMaxColumn, nMaxRow, nTable) );
- ScRange aBottomPart( ScAddress( nMinColumn, nMinRow+1, nTable), ScAddress( nMaxColumn, nMaxRow, nTable) );
- if( xRanges->In(aRightPart) && xRanges->In(aBottomPart) )
- {
- xRanges->RemoveAll();
- xRanges->Append( ScRange( ScAddress( nMinColumn, nMinRow, nTable), ScAddress( nMaxColumn, nMaxRow, nTable) ) );
- bChanged=true;
- bSimpleRange = true;
- }
+ const ScSingleRefData& rData = pToken->GetSingleRef();
+ if (rData.nCol == nMinCol && rData.nRow == nMinRow)
+ // The corner cell is contained.
+ return false;
+
+ if (rData.nCol == nMinCol+1 && rData.nRow == nMinRow)
+ bRight = true;
+
+ if (rData.nCol == nMinCol && rData.nRow == nMinRow+1)
+ bBottom = true;
+
+ if (rData.nCol == nMinCol+1 && rData.nRow == nMinRow+1)
+ bDiagonal = true;
}
-
- if( !bSimpleRange )
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
{
- xRanges->Join( aCorner );
- bChanged=true;
+ const ScComplexRefData& rData = pToken->GetDoubleRef();
+ const ScSingleRefData& r1 = rData.Ref1;
+ const ScSingleRefData& r2 = rData.Ref2;
+ if (r1.nCol <= nMinCol && nMinCol <= r2.nCol &&
+ r1.nRow <= nMinRow && nMinRow <= r2.nRow)
+ // The corner cell is contained.
+ return false;
+
+ if (r1.nCol <= nMinCol+1 && nMinCol+1 <= r2.nCol &&
+ r1.nRow <= nMinRow && nMinRow <= r2.nRow)
+ bRight = true;
+
+ if (r1.nCol <= nMinCol && nMinCol <= r2.nCol &&
+ r1.nRow <= nMinRow+1 && nMinRow+1 <= r2.nRow)
+ bBottom = true;
+
+ if (r1.nCol <= nMinCol+1 && nMinCol+1 <= r2.nCol &&
+ r1.nRow <= nMinRow+1 && nMinRow+1 <= r2.nRow)
+ bDiagonal = true;
}
+ break;
}
}
- return bChanged;
+
+ if (!bRight || !bBottom || !bDiagonal)
+ // Not all the adjacent cells are included. Bail out.
+ return false;
+
+#if 0 // Do we really need to do this ???
+ if (rRefTokens.size() == 2)
+ {
+ // Make a simple rectangular range if possible.
+ ScRange aRightPart(ScAddress(nMinCol+1, nMinRow, nTab), ScAddress(nMaxCol, nMaxRow, nTab));
+ ScRange aBottomPart(ScAddress(nMinCol, nMinRow+1, nTab), ScAddress(nMaxCol, nMaxRow, nTab));
+ vector<ScRange> aRanges;
+ aRanges.reserve(2);
+ aRanges.push_back(aRightPart);
+ aRanges.push_back(aBottomPart);
+ if (lcl_isRangeContained(rRefTokens, aRanges))
+ {
+ // Consolidate them into a single rectangle.
+ ScComplexRefData aData;
+ aData.InitFlags();
+ aData.Ref1.SetFlag3D(true);
+ aData.Ref1.SetColRel(false);
+ aData.Ref1.SetRowRel(false);
+ aData.Ref1.SetTabRel(false);
+ aData.Ref2.SetColRel(false);
+ aData.Ref2.SetRowRel(false);
+ aData.Ref2.SetTabRel(false);
+ aData.Ref1.nCol = nMinCol;
+ aData.Ref1.nRow = nMinRow;
+ aData.Ref1.nTab = nTab;
+ aData.Ref2.nCol = nMaxCol;
+ aData.Ref2.nRow = nMaxRow;
+ aData.Ref2.nTab = nTab;
+ vector<ScSharedTokenRef> aNewTokens;
+ aNewTokens.reserve(1);
+ if (bExternal)
+ {
+ ScSharedTokenRef p(
+ new ScExternalDoubleRefToken(nFileId, aExtTabName, aData));
+ aNewTokens.push_back(p);
+ }
+ else
+ {
+ ScSharedTokenRef p(new ScDoubleRefToken(aData));
+ aNewTokens.push_back(p);
+ }
+ rRefTokens.swap(aNewTokens);
+ return true;
+ }
+ }
+#endif
+
+ ScSingleRefData aData;
+ aData.InitFlags();
+ aData.SetFlag3D(true);
+ aData.SetColRel(false);
+ aData.SetRowRel(false);
+ aData.SetTabRel(false);
+ aData.nCol = nMinCol;
+ aData.nRow = nMinRow;
+ aData.nTab = nTab;
+
+ if (bExternal)
+ {
+ ScSharedTokenRef pCorner(
+ new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
+ ScRefTokenHelper::join(rRefTokens, pCorner);
+ }
+ else
+ {
+ ScSharedTokenRef pCorner(new ScSingleRefToken(aData));
+ ScRefTokenHelper::join(rRefTokens, pCorner);
+ }
+
+ return true;
+}
+
+namespace {
+
+/**
+ * Function object to create a list of table numbers from a token list.
+ */
+class InsertTabNumber : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ InsertTabNumber() :
+ mpTabNumList(new list<SCTAB>())
+ {
+ }
+
+ InsertTabNumber(const InsertTabNumber& r) :
+ mpTabNumList(r.mpTabNumList)
+ {
+ }
+
+ void operator() (const ScSharedTokenRef& pToken) const
+ {
+ if (!ScRefTokenHelper::isRef(pToken))
+ return;
+
+ const ScSingleRefData& r = pToken->GetSingleRef();
+ mpTabNumList->push_back(r.nTab);
+ }
+
+ void getList(list<SCTAB>& rList)
+ {
+ mpTabNumList->swap(rList);
+ }
+private:
+ shared_ptr< list<SCTAB> > mpTabNumList;
+};
+
}
uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
@@ -820,7 +2018,7 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
- ScRangeListRef xRanges = new ScRangeList;
+ vector<ScSharedTokenRef> aTokens;
// CellRangeRepresentation
{
@@ -829,23 +2027,15 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
if(!m_pDocument)
return lcl_VectorToSequence( aResult );
- lcl_detectRanges( xRanges, eRowSource, bRowSourceDetected, xDataSource, m_pDocument );
-
- //get range string
- String sRet;
- xRanges->Format(sRet, SCR_ABS_3D, m_pDocument);
- sRangeRep = ::rtl::OUString( sRet );
+ detectRangesFromDataSource(aTokens, eRowSource, bRowSourceDetected, xDataSource);
}
// TableNumberList
{
- ::std::list< SCTAB > aTableNumList;
- ScRangePtr pR=xRanges->First();
- if( pR )
- {
- for (; pR; pR=xRanges->Next())
- aTableNumList.push_back( pR->aStart.Tab());
- }
+ list<SCTAB> aTableNumList;
+ InsertTabNumber func;
+ func = for_each(aTokens.begin(), aTokens.end(), func);
+ func.getList(aTableNumList);
aResult.push_back(
beans::PropertyValue( ::rtl::OUString::createFromAscii("TableNumberList"), -1,
uno::makeAny( lcl_createTableNumberList( aTableNumList ) ),
@@ -880,16 +2070,12 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ));
}
- //add the left upper corner to the range when it is missing
- if( bRowSourceDetected && bFirstCellAsLabel && bHasCategories )
- {
- if( addUpperLeftCornerIfMissing( xRanges ) )
- {
- String sRange;
- xRanges->Format( sRange, SCR_ABS_3D, m_pDocument );
- sRangeRep = ::rtl::OUString( sRange );
- }
- }
+ // Add the left upper corner to the range if it is missing.
+ if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories)
+ addUpperLeftCornerIfMissing(aTokens);
+
+ // Get range string.
+ lcl_convertTokensToString(sRangeRep, aTokens, m_pDocument);
// add cell range property
aResult.push_back(
@@ -979,14 +2165,9 @@ uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArgum
if( ! m_pDocument )
return false;
- ScRangeList aRangeList;
- USHORT nResult = aRangeList.Parse( aRangeRepresentation, m_pDocument );
- //! if anything is missing, SCA_VALID shouldn't be set
- const USHORT nNeeded = SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
- SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2;
- bool bValid = ( (nResult & nNeeded ) == nNeeded );
-
- return bValid;
+ vector<ScSharedTokenRef> aTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aTokens, aRangeRepresentation, m_pDocument);
+ return !aTokens.empty();
}
uno::Reference< chart2::data::XDataSequence > SAL_CALL
@@ -1002,9 +2183,15 @@ uno::Reference< chart2::data::XDataSequence > SAL_CALL
if(!m_pDocument || (aRangeRepresentation.getLength() == 0))
return xResult;
- ScRangeListRef aRangeList = new ScRangeList();
- if (ScRangeStringConverter::GetRangeListFromString( *aRangeList, aRangeRepresentation, m_pDocument, ';' ))
- xResult.set(new ScChart2DataSequence(m_pDocument, this, aRangeList));
+ vector<ScSharedTokenRef> aRefTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aRefTokens, aRangeRepresentation, m_pDocument);
+ if (aRefTokens.empty())
+ return xResult;
+
+ // ScChart2DataSequence manages the life cycle of pRefTokens.
+ vector<ScSharedTokenRef>* pRefTokens = new vector<ScSharedTokenRef>();
+ pRefTokens->swap(aRefTokens);
+ xResult.set(new ScChart2DataSequence(m_pDocument, this, pRefTokens));
return xResult;
}
@@ -1032,55 +2219,201 @@ uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRange
rtl::OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const rtl::OUString& sRangeRepresentation )
throw ( uno::RuntimeException, lang::IllegalArgumentException )
{
- rtl::OUString sRet;
+ OUString aRet;
+ if (!m_pDocument)
+ return aRet;
- if( m_pDocument )
- {
- ScRangeList aList;
- if( !ScRangeStringConverter::GetRangeListFromString(aList, sRangeRepresentation, m_pDocument, ';'))
- throw lang::IllegalArgumentException();
- ScRangeStringConverter::GetStringFromRangeList(sRet, &aList, m_pDocument);
- }
+ if (!sRangeRepresentation.getLength())
+ // Empty data range is allowed.
+ return aRet;
+
+ vector<ScSharedTokenRef> aRefTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aRefTokens, sRangeRepresentation, m_pDocument);
+ if (aRefTokens.empty())
+ throw lang::IllegalArgumentException();
- return sRet;
+ Tokens2RangeStringXML converter(m_pDocument);
+ converter = for_each(aRefTokens.begin(), aRefTokens.end(), converter);
+ converter.getString(aRet);
+
+ return aRet;
}
rtl::OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const rtl::OUString& sXMLRange )
throw ( uno::RuntimeException, lang::IllegalArgumentException )
{
- // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
- // so the conversion has to take place directly with the strings, without looking up the sheets.
-
const sal_Unicode cSep = ' ';
const sal_Unicode cQuote = '\'';
- rtl::OUStringBuffer sRet;
- sal_Int32 nOffset = 0;
- while( nOffset >= 0 )
+ if (!m_pDocument)
+ {
+ // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
+ // so the conversion has to take place directly with the strings, without looking up the sheets.
+
+ rtl::OUStringBuffer sRet;
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ rtl::OUString sToken;
+ ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote );
+ if( nOffset >= 0 )
+ {
+ // convert one address (remove dots)
+
+ String aUIString(sToken);
+
+ sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote );
+ if ( nIndex >= 0 && nIndex < aUIString.Len() - 1 &&
+ aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
+ aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
+
+ if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
+ aUIString.Erase( 0, 1 );
+
+ if( sRet.getLength() )
+ sRet.append( (sal_Unicode) ';' );
+ sRet.append( aUIString );
+ }
+ }
+
+ return sRet.makeStringAndClear();
+ }
+
+ OUString aRet;
+ ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, m_pDocument);
+ return aRet;
+}
+
+namespace {
+
+class CollectRefTokens : public ::std::unary_function<ScSharedTokenRef, void>
+{
+public:
+ CollectRefTokens() :
+ mpRefTokens(new vector<ScSharedTokenRef>()),
+ mnDataInRows(0),
+ mnDataInCols(0),
+ mbRowSourceAmbiguous(false)
+ {
+ }
+
+ CollectRefTokens(const CollectRefTokens& r) :
+ mpRefTokens(r.mpRefTokens),
+ mnDataInRows(r.mnDataInRows),
+ mnDataInCols(r.mnDataInCols),
+ mbRowSourceAmbiguous(r.mbRowSourceAmbiguous)
{
- rtl::OUString sToken;
- ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset, cSep, cQuote );
- if( nOffset >= 0 )
+ }
+
+ void operator() (const ScSharedTokenRef& rRefToken)
+ {
+ if (!mbRowSourceAmbiguous)
{
- // convert one address (remove dots)
+ StackVar eVar = rRefToken->GetType();
+ if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
+ {
+ const ScComplexRefData& r = rRefToken->GetDoubleRef();
+ mbRowSourceAmbiguous = r.Ref1.nTab != r.Ref2.nTab;
+ if (!mbRowSourceAmbiguous)
+ {
+ bool bColDiff = (r.Ref2.nCol - r.Ref1.nCol) != 0;
+ bool bRowDiff = (r.Ref2.nRow - r.Ref1.nRow) != 0;
+
+ if (bColDiff && !bRowDiff)
+ ++mnDataInRows;
+ else if (bRowDiff && !bColDiff)
+ ++mnDataInCols;
+ else if (bRowDiff && bColDiff)
+ mbRowSourceAmbiguous = true;
+
+ if (mnDataInRows > 0 && mnDataInCols > 0)
+ mbRowSourceAmbiguous = true;
+ }
+ }
+ }
+
+ mpRefTokens->push_back(rRefToken);
+ }
- String aUIString(sToken);
+ void appendTokens(vector<ScSharedTokenRef>& rTokens)
+ {
+ vector<ScSharedTokenRef> aNewTokens = rTokens;
+ vector<ScSharedTokenRef>::const_iterator itr = mpRefTokens->begin(), itrEnd = mpRefTokens->end();
+ for (; itr != itrEnd; ++itr)
+ ScRefTokenHelper::join(aNewTokens, *itr);
- sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0, cQuote );
- if ( nIndex >= 0 && nIndex < aUIString.Len() - 1 &&
- aUIString.GetChar((xub_StrLen)nIndex + 1) == (sal_Unicode) '.' )
- aUIString.Erase( (xub_StrLen)nIndex + 1, 1 );
+ rTokens.swap(aNewTokens);
+ }
- if ( aUIString.GetChar(0) == (sal_Unicode) '.' )
- aUIString.Erase( 0, 1 );
+ bool isRowSourceAmbiguous() const
+ {
+ return mbRowSourceAmbiguous;
+ }
- if( sRet.getLength() )
- sRet.append( (sal_Unicode) ';' );
- sRet.append( aUIString );
+ sal_uInt32 getDataInRows() const
+ {
+ return mnDataInRows;
+ }
+
+ sal_uInt32 getDataInCols() const
+ {
+ return mnDataInCols;
+ }
+
+private:
+ shared_ptr< vector<ScSharedTokenRef> > mpRefTokens;
+ sal_uInt32 mnDataInRows;
+ sal_uInt32 mnDataInCols;
+ bool mbRowSourceAmbiguous;
+};
+
+}
+
+void ScChart2DataProvider::detectRangesFromDataSource(vector<ScSharedTokenRef>& rRefTokens,
+ chart::ChartDataRowSource& rRowSource,
+ bool& rRowSourceDetected,
+ const Reference<chart2::data::XDataSource>& xDataSource)
+{
+ if (!m_pDocument)
+ return;
+
+ sal_Int32 nDataInRows = 0;
+ sal_Int32 nDataInCols = 0;
+ bool bRowSourceAmbiguous = false;
+
+ vector<OUString> aRangeReps = lcl_getRangeRepresentationsFromDataSource(xDataSource);
+ for (vector<OUString>::const_iterator itr = aRangeReps.begin(), itrEnd = aRangeReps.end();
+ itr != itrEnd; ++itr)
+ {
+ const OUString& rRangeRep = *itr;
+ vector<ScSharedTokenRef> aTokens;
+ ScRefTokenHelper::compileRangeRepresentation(aTokens, rRangeRep, m_pDocument);
+
+ CollectRefTokens func;
+ func = for_each(aTokens.begin(), aTokens.end(), func);
+ func.appendTokens(rRefTokens);
+ bRowSourceAmbiguous = bRowSourceAmbiguous || func.isRowSourceAmbiguous();
+ if (!bRowSourceAmbiguous)
+ {
+ nDataInRows += func.getDataInRows();
+ nDataInCols += func.getDataInCols();
}
}
- return sRet.makeStringAndClear();
+ if (!bRowSourceAmbiguous)
+ {
+ rRowSourceDetected = true;
+ rRowSource = ( nDataInRows > 0
+ ? chart::ChartDataRowSource_ROWS
+ : chart::ChartDataRowSource_COLUMNS );
+ }
+ else
+ {
+ // set DataRowSource to the better of the two ambiguities
+ rRowSource = ( nDataInRows > nDataInCols
+ ? chart::ChartDataRowSource_ROWS
+ : chart::ChartDataRowSource_COLUMNS );
+ }
}
// DataSource ================================================================
@@ -1315,18 +2648,29 @@ void SAL_CALL ScChart2LabeledDataSequence::removeModifyListener( const uno::Refe
// DataSequence ==============================================================
+ScChart2DataSequence::Item::Item() :
+ mfValue(0.0), mbIsValue(false)
+{
+ ::rtl::math::setNan(&mfValue);
+}
+
ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
- const uno::Reference < chart2::data::XDataProvider >& xDP,
- const ScRangeListRef& rRangeList)
+ const uno::Reference < chart2::data::XDataProvider >& xDP,
+ vector<ScSharedTokenRef>* pTokens)
: m_bHidden( sal_False)
- , m_xRanges( rRangeList)
, m_nObjectId( 0 )
, m_pDocument( pDoc)
+ , m_pTokens(pTokens)
+ , m_pRangeIndices(NULL)
+ , m_pExtRefListener(NULL)
, m_xDataProvider( xDP)
, m_aPropSet(lcl_GetDataSequencePropertyMap())
, m_pValueListener( NULL )
- , m_bGotDataChangedHint( FALSE )
+ , m_bGotDataChangedHint(false)
+ , m_bExtDataRebuildQueued(false)
{
+ DBG_ASSERT(pTokens, "reference token list is null");
+
if ( m_pDocument )
{
m_pDocument->AddUnoObject( *this);
@@ -1345,16 +2689,17 @@ ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
// m_aIdentifier += ::rtl::OUString::valueOf( ++nID);
}
-
ScChart2DataSequence::~ScChart2DataSequence()
{
if ( m_pDocument )
+ {
m_pDocument->RemoveUnoObject( *this);
+ StopListeningToAllExternalRefs();
+ }
delete m_pValueListener;
}
-
void ScChart2DataSequence::RefChanged()
{
if( m_pValueListener && m_aValueListeners.Count() != 0 )
@@ -1363,13 +2708,298 @@ void ScChart2DataSequence::RefChanged()
if( m_pDocument )
{
- ULONG nCount = m_xRanges->Count();
- for (ULONG i=0; i<nCount; i++)
- m_pDocument->StartListeningArea( *m_xRanges->GetObject(i), m_pValueListener );
+ vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
+ for (; itr != itrEnd; ++itr)
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr))
+ continue;
+
+ m_pDocument->StartListeningArea(aRange, m_pValueListener);
+ }
+ }
+ }
+}
+
+void ScChart2DataSequence::BuildDataCache()
+{
+ m_bExtDataRebuildQueued = false;
+
+ if (!m_aDataArray.empty())
+ return;
+
+ if (!m_pTokens.get())
+ {
+ DBG_ERROR("m_pTokens == NULL! Something is wrong.");
+ return;
+ }
+
+ StopListeningToAllExternalRefs();
+
+ ::std::list<sal_Int32> aHiddenValues;
+ sal_Int32 nDataCount = 0;
+ sal_Int32 nHiddenValueCount = 0;
+
+ for (vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
+ itr != itrEnd; ++itr)
+ {
+ if (ScRefTokenHelper::isExternalRef(*itr))
+ {
+ nDataCount += FillCacheFromExternalRef(*itr);
}
+ else
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(aRange, *itr))
+ continue;
+
+ for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
+ {
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ {
+ m_aDataArray.push_back(Item());
+ Item& rItem = m_aDataArray.back();
+ ++nDataCount;
+ USHORT nWidth = m_pDocument->GetColWidth(nCol, nTab);
+ USHORT nHeight = m_pDocument->GetRowHeight(nRow, nTab);
+ if (!nWidth || !nHeight)
+ {
+ // hidden cell
+ ++nHiddenValueCount;
+ aHiddenValues.push_back(nDataCount-1);
+ }
+
+ ScAddress aAdr(nCol, nRow, nTab);
+ ScBaseCell* pCell = m_pDocument->GetCell(aAdr);
+ if (!pCell)
+ continue;
+
+ if (pCell->HasStringData())
+ rItem.maString = pCell->GetStringData();
+ else
+ {
+ String aStr;
+ m_pDocument->GetString(nCol, nRow, nTab, aStr);
+ rItem.maString = aStr;
+ }
+
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ rItem.mfValue = static_cast< ScValueCell*>(pCell)->GetValue();
+ rItem.mbIsValue = true;
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
+ USHORT nErr = pFCell->GetErrCode();
+ if (nErr)
+ break;
+
+ if (pFCell->HasValueData())
+ rItem.mfValue = pFCell->GetValue();
+ rItem.mbIsValue = true;
+ }
+ break;
+ case CELLTYPE_DESTROYED:
+ case CELLTYPE_EDIT:
+ case CELLTYPE_NONE:
+ case CELLTYPE_NOTE:
+ case CELLTYPE_STRING:
+ case CELLTYPE_SYMBOLS:
+ default:
+ ; // do nothing
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // convert the hidden cell list to sequence.
+ m_aHiddenValues.realloc(nHiddenValueCount);
+ sal_Int32* pArr = m_aHiddenValues.getArray();
+ ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end();
+ for (;itr != itrEnd; ++itr, ++pArr)
+ *pArr = *itr;
+}
+
+void ScChart2DataSequence::RebuildDataCache()
+{
+ if (!m_bExtDataRebuildQueued)
+ {
+ m_aDataArray.clear();
+ m_pDocument->BroadcastUno(ScHint(SC_HINT_DATACHANGED, ScAddress(), NULL));
+ m_bExtDataRebuildQueued = true;
+ m_bGotDataChangedHint = true;
+ }
+}
+
+sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScSharedTokenRef& pToken)
+{
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken, true))
+ return 0;
+
+ sal_uInt16 nFileId = pToken->GetIndex();
+ const String& rTabName = pToken->GetString();
+ ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, rTabName, aRange, NULL);
+ if (!pArray)
+ // no external data exists for this range.
+ return 0;
+
+ // Start listening for this external document.
+ ExternalRefListener* pExtRefListener = GetExtRefListener();
+ pRefMgr->addLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->addFileId(nFileId);
+
+ ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, rTabName, false, NULL);
+ sal_Int32 nDataCount = 0;
+ for (FormulaToken* p = pArray->First(); p; p = pArray->Next())
+ {
+ // Cached external range is always represented as a single
+ // matrix token, although that might change in the future when
+ // we introduce a new token type to store multi-table range
+ // data.
+
+ if (p->GetType() != svMatrix)
+ {
+ DBG_ERROR("Cached array is not a matrix token.");
+ continue;
+ }
+
+ const ScMatrix* pMat = static_cast<ScToken*>(p)->GetMatrix();
+ SCSIZE nCSize, nRSize;
+ pMat->GetDimensions(nCSize, nRSize);
+ for (SCSIZE nC = 0; nC < nCSize; ++nC)
+ {
+ for (SCSIZE nR = 0; nR < nRSize; ++nR)
+ {
+ if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
+ {
+ m_aDataArray.push_back(Item());
+ Item& rItem = m_aDataArray.back();
+ ++nDataCount;
+
+ rItem.mbIsValue = true;
+ rItem.mfValue = pMat->GetDouble(nC, nR);
+
+ SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
+ if (pFormatter)
+ {
+ String aStr;
+ const double fVal = rItem.mfValue;
+ Color* pColor = NULL;
+ sal_uInt32 nFmt = 0;
+ if (pTable)
+ {
+ // Get the correct format index from the cache.
+ SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
+ SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
+ pTable->getCell(nCol, nRow, &nFmt);
+ }
+ pFormatter->GetOutputString(fVal, nFmt, aStr, &pColor);
+ rItem.maString = aStr;
+ }
+ }
+ else if (pMat->IsString(nC, nR))
+ {
+ m_aDataArray.push_back(Item());
+ Item& rItem = m_aDataArray.back();
+ ++nDataCount;
+
+ rItem.mbIsValue = false;
+ rItem.maString = pMat->GetString(nC, nR);
+ }
+ }
+ }
+ }
+ return nDataCount;
+}
+
+void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
+{
+ if (!m_pRangeIndices.get())
+ return;
+
+ sal_uInt32 nCount = rRanges.Count();
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ ScSharedTokenRef pToken;
+ ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i));
+ DBG_ASSERT(pRange, "range object is NULL.");
+
+ ScRefTokenHelper::getTokenFromRange(pToken, *pRange);
+ sal_uInt32 nOrigPos = (*m_pRangeIndices)[i];
+ (*m_pTokens)[nOrigPos] = pToken;
}
+
+ RefChanged();
+
+ // any change of the range address is broadcast to value (modify) listeners
+ if ( m_aValueListeners.Count() )
+ m_bGotDataChangedHint = true;
}
+ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
+{
+ if (!m_pExtRefListener.get())
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+
+ return m_pExtRefListener.get();
+}
+
+void ScChart2DataSequence::StopListeningToAllExternalRefs()
+{
+ if (!m_pExtRefListener.get())
+ return;
+
+ const hash_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ for (; itr != itrEnd; ++itr)
+ pRefMgr->removeLinkListener(*itr, m_pExtRefListener.get());
+
+ m_pExtRefListener.reset(NULL);
+}
+
+void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
+{
+ if (!m_pDocument)
+ {
+ DBG_ERROR("document instance is NULL!?");
+ return;
+ }
+
+ list<Item> aDataArray(r.m_aDataArray);
+ m_aDataArray.swap(aDataArray);
+
+ m_aHiddenValues = r.m_aHiddenValues;
+ m_aRole = r.m_aRole;
+ m_bHidden = r.m_bHidden;
+
+ if (r.m_pRangeIndices.get())
+ m_pRangeIndices.reset(new vector<sal_uInt32>(*r.m_pRangeIndices));
+
+ if (r.m_pExtRefListener.get())
+ {
+ // Re-register all external files that the old instance was
+ // listening to.
+
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+ const hash_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
+ hash_set<sal_uInt16>::const_iterator itr = rFileIds.begin(), itrEnd = rFileIds.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ pRefMgr->addLinkListener(*itr, m_pExtRefListener.get());
+ m_pExtRefListener->addFileId(*itr);
+ }
+ }
+}
void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
@@ -1386,6 +3016,7 @@ void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint
if ( m_bGotDataChangedHint && m_pDocument )
{
+ m_aDataArray.clear();
lang::EventObject aEvent;
aEvent.Source.set((cppu::OWeakObject*)this);
@@ -1395,46 +3026,83 @@ void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint
m_pDocument->AddUnoListenerCall( *m_aValueListeners[n], aEvent );
}
- m_bGotDataChangedHint = FALSE;
+ m_bGotDataChangedHint = false;
}
}
}
else if ( rHint.ISA( ScUpdateRefHint ) )
{
- const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;
+ // Create a range list from the token list, have the range list
+ // updated, and bring the change back to the token list.
+
+ ScRangeList aRanges;
+ m_pRangeIndices.reset(new vector<sal_uInt32>());
+ vector<ScSharedTokenRef>::const_iterator itrBeg = m_pTokens->begin(), itrEnd = m_pTokens->end();
+ for (vector<ScSharedTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
+ {
+ if (!ScRefTokenHelper::isExternalRef(*itr))
+ {
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(aRange, *itr);
+ aRanges.Append(aRange);
+ sal_uInt32 nPos = distance(itrBeg, itr);
+ m_pRangeIndices->push_back(nPos);
+ }
+ }
- ScRangeList* pUndoRanges = NULL;
+ DBG_ASSERT(m_pRangeIndices->size() == static_cast<size_t>(aRanges.Count()),
+ "range list and range index list have different sizes.");
+
+ auto_ptr<ScRangeList> pUndoRanges;
if ( m_pDocument->HasUnoRefUndo() )
- pUndoRanges = new ScRangeList( *m_xRanges );
+ pUndoRanges.reset(new ScRangeList(aRanges));
- if ( m_xRanges->UpdateReference( rRef.GetMode(), m_pDocument, rRef.GetRange(),
- rRef.GetDx(), rRef.GetDy(), rRef.GetDz() ) )
+ const ScUpdateRefHint& rRef = (const ScUpdateRefHint&)rHint;
+ bool bChanged = aRanges.UpdateReference(
+ rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
+
+ if (bChanged)
{
- RefChanged();
+ DBG_ASSERT(m_pRangeIndices->size() == static_cast<size_t>(aRanges.Count()),
+ "range list and range index list have different sizes after the reference update.");
- // any change of the range address is broadcast to value (modify) listeners
- if ( m_aValueListeners.Count() )
- m_bGotDataChangedHint = TRUE;
+ // Bring the change back from the range list to the token list.
+ UpdateTokensFromRanges(aRanges);
- if ( pUndoRanges )
- m_pDocument->AddUnoRefChange( m_nObjectId, *pUndoRanges );
+ if (pUndoRanges.get())
+ m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
}
-
- delete pUndoRanges;
}
else if ( rHint.ISA( ScUnoRefUndoHint ) )
{
const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint);
- if ( rUndoHint.GetObjectId() == m_nObjectId )
+
+ do
{
- // restore ranges from hint
+ if (rUndoHint.GetObjectId() != m_nObjectId)
+ break;
- m_xRanges = new ScRangeList( rUndoHint.GetRanges() );
+ // The hint object provides the old ranges. Restore the old state
+ // from these ranges.
- RefChanged();
- if ( m_aValueListeners.Count() )
- m_bGotDataChangedHint = TRUE; // need to broadcast the undo, too
+ if (!m_pRangeIndices.get() || m_pRangeIndices->empty())
+ {
+ DBG_ERROR(" faulty range indices");
+ break;
+ }
+
+ const ScRangeList& rRanges = rUndoHint.GetRanges();
+
+ sal_uInt32 nCount = rRanges.Count();
+ if (nCount != m_pRangeIndices->size())
+ {
+ DBG_ERROR("range count and range index count differ.");
+ break;
+ }
+
+ UpdateTokensFromRanges(rRanges);
}
+ while (false);
}
}
@@ -1448,11 +3116,64 @@ IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, SfxHint*, pHint )
// in the range are notified. So only a flag is set that is checked when
// SFX_HINT_DATACHANGED is received.
- m_bGotDataChangedHint = TRUE;
+ m_bGotDataChangedHint = true;
}
return 0;
}
+// ----------------------------------------------------------------------------
+
+ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
+ ScChart2DataSequence& rParent, ScDocument* pDoc) :
+ ScExternalRefManager::LinkListener(),
+ mrParent(rParent),
+ mpDoc(pDoc)
+{
+}
+
+ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
+{
+ if (!mpDoc || mpDoc->IsInDtorClear())
+ // The document is being destroyed. Do nothing.
+ return;
+
+ // Make sure to remove all pointers to this object.
+ mpDoc->GetExternalRefManager()->removeLinkListener(this);
+}
+
+void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
+{
+ switch (eType)
+ {
+ case ScExternalRefManager::LINK_MODIFIED:
+ {
+ if (maFileIds.count(nFileId))
+ // We are listening to this external document.
+ mrParent.RebuildDataCache();
+ }
+ break;
+ case ScExternalRefManager::LINK_BROKEN:
+ removeFileId(nFileId);
+ break;
+ }
+}
+
+void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
+{
+ maFileIds.insert(nFileId);
+}
+
+void ScChart2DataSequence::ExternalRefListener::removeFileId(sal_uInt16 nFileId)
+{
+ maFileIds.erase(nFileId);
+}
+
+const hash_set<sal_uInt16>& ScChart2DataSequence::ExternalRefListener::getAllFileIds()
+{
+ return maFileIds;
+}
+
+// ----------------------------------------------------------------------------
uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
throw ( uno::RuntimeException)
@@ -1461,72 +3182,19 @@ uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
if ( !m_pDocument)
throw uno::RuntimeException();
- const ScDocument* pDoc = m_pDocument;
- sal_Int32 nCount = 0;
- ScRangePtr p;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
+ BuildDataCache();
+ sal_Int32 nCount = m_aDataArray.size();
+ uno::Sequence<uno::Any> aSeq(nCount);
+ uno::Any* pArr = aSeq.getArray();
+ ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
+ for (; itr != itrEnd; ++itr, ++pArr)
{
- nCount += sal_Int32(p->aEnd.Col() - p->aStart.Col() + 1) *
- (p->aEnd.Row() - p->aStart.Row() + 1) * (p->aEnd.Tab() -
- p->aStart.Tab() + 1);
+ if (itr->mbIsValue)
+ *pArr <<= itr->mfValue;
+ else
+ *pArr <<= itr->maString;
}
- uno::Sequence< uno::Any> aSeq( nCount);
- uno::Any * pArr = aSeq.getArray();
- nCount = 0;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- // TODO: use DocIter?
- ScAddress aAdr( p->aStart);
- for ( SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
- {
- aAdr.SetTab( nTab);
- for ( SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
- {
- aAdr.SetCol( nCol);
- for ( SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row();
- ++nRow)
- {
- aAdr.SetRow( nRow);
- ScBaseCell* pCell = pDoc->GetCell( aAdr);
- if ( pCell)
- {
- switch ( pCell->GetCellType())
- {
- case CELLTYPE_VALUE:
- pArr[nCount] <<= static_cast< ScValueCell*>(
- pCell)->GetValue();
- break;
- case CELLTYPE_FORMULA:
- {
- ScFormulaCell* pFCell = static_cast<
- ScFormulaCell*>( pCell);
- USHORT nErr = pFCell->GetErrCode();
- if ( !nErr)
- {
- if ( pFCell->HasValueData())
- pArr[nCount] <<= pFCell->GetValue();
- else
- {
- String aStr;
- pFCell->GetString( aStr);
- pArr[nCount] <<= ::rtl::OUString(
- aStr);
- }
- }
- }
- default:
- {
- if ( pCell->HasStringData())
- pArr[nCount] <<= ::rtl::OUString(pCell->GetStringData());
- }
- }
- }
- ++nCount;
- }
- }
- }
- }
return aSeq;
}
@@ -1539,67 +3207,18 @@ uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
if ( !m_pDocument)
throw uno::RuntimeException();
+ BuildDataCache();
+
double fNAN;
- ::rtl::math::setNan( & fNAN );
+ ::rtl::math::setNan(&fNAN);
- const ScDocument* pDoc = m_pDocument;
- sal_Int32 nCount = 0;
- ScRangePtr p;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- nCount += sal_Int32(p->aEnd.Col() - p->aStart.Col() + 1) *
- (p->aEnd.Row() - p->aStart.Row() + 1) * (p->aEnd.Tab() -
- p->aStart.Tab() + 1);
- }
- uno::Sequence< double > aSeq( nCount);
+ sal_Int32 nCount = m_aDataArray.size();
+ uno::Sequence<double> aSeq(nCount);
double* pArr = aSeq.getArray();
- nCount = 0;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- // TODO: use DocIter?
- ScAddress aAdr( p->aStart);
- for ( SCTAB nTab = p->aStart.Tab(); nTab <= p->aEnd.Tab(); ++nTab)
- {
- aAdr.SetTab( nTab);
- for ( SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
- {
- aAdr.SetCol( nCol);
- for ( SCROW nRow = p->aStart.Row(); nRow <= p->aEnd.Row();
- ++nRow)
- {
- pArr[nCount] = fNAN;
+ ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
+ for (; itr != itrEnd; ++itr, ++pArr)
+ *pArr = itr->mbIsValue ? itr->mfValue : fNAN;
- aAdr.SetRow( nRow);
- ScBaseCell* pCell = pDoc->GetCell( aAdr);
- if ( pCell)
- {
- switch ( pCell->GetCellType())
- {
- case CELLTYPE_VALUE:
- pArr[nCount] = static_cast< ScValueCell*>(
- pCell)->GetValue();
- break;
- case CELLTYPE_FORMULA:
- {
- ScFormulaCell* pFCell = static_cast<
- ScFormulaCell*>( pCell);
- USHORT nErr = pFCell->GetErrCode();
- if ( !nErr)
- {
- if ( pFCell->HasValueData())
- pArr[nCount] = pFCell->GetValue();
- }
- }
- default:
- // nothing
- break;
- }
- }
- ++nCount;
- }
- }
- }
- }
return aSeq;
}
@@ -1611,49 +3230,15 @@ uno::Sequence< rtl::OUString > SAL_CALL ScChart2DataSequence::getTextualData( )
if ( !m_pDocument)
throw uno::RuntimeException();
- sal_Int32 nCount = 0;
- ScRangePtr p;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- nCount += sal_Int32(p->aEnd.Col() - p->aStart.Col() + 1) *
- (p->aEnd.Row() - p->aStart.Row() + 1) * (p->aEnd.Tab() -
- p->aStart.Tab() + 1);
- }
- uno::Sequence< rtl::OUString > aSeq( nCount);
+ BuildDataCache();
+
+ sal_Int32 nCount = m_aDataArray.size();
+ uno::Sequence<rtl::OUString> aSeq(nCount);
rtl::OUString* pArr = aSeq.getArray();
- nCount = 0;
- uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( lcl_GetSpreadSheetDocument( m_pDocument ));
- if ( xSpreadDoc.is() )
- {
- uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
- if ( xIndex.is() )
- {
- uno::Reference< table::XCellRange > xSheet;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- // TODO: use DocIter?
- table::CellAddress aStart, aEnd;
- ScUnoConversion::FillApiAddress( aStart, p->aStart );
- ScUnoConversion::FillApiAddress( aEnd, p->aEnd );
- for ( sal_Int16 nSheet = aStart.Sheet; nSheet <= aEnd.Sheet; ++nSheet)
- {
- xSheet.set(xIndex->getByIndex(nSheet), uno::UNO_QUERY);
- for ( sal_Int32 nCol = aStart.Column; nCol <= aEnd.Column; ++nCol)
- {
- for ( sal_Int32 nRow = aStart.Row; nRow <= aEnd.Row; ++nRow)
- {
- uno::Reference< text::XText > xText(xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
- if (xText.is())
- {
- pArr[nCount] = xText->getString();
- ++nCount;
- }
- }
- }
- }
- }
- }
- }
+ ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end();
+ for (; itr != itrEnd; ++itr, ++pArr)
+ *pArr = itr->maString;
+
return aSeq;
}
@@ -1661,70 +3246,76 @@ uno::Sequence< rtl::OUString > SAL_CALL ScChart2DataSequence::getTextualData( )
throw ( uno::RuntimeException)
{
ScUnoGuard aGuard;
- String aStr;
+ OUString aStr;
DBG_ASSERT( m_pDocument, "No Document -> no SourceRangeRepresentation" );
- if( m_pDocument )
- m_xRanges->Format( aStr, SCR_ABS_3D, m_pDocument );
+ if (m_pDocument && m_pTokens.get())
+ lcl_convertTokensToString(aStr, *m_pTokens, m_pDocument);
+
return aStr;
}
-uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
- throw (uno::RuntimeException)
-{
- ScUnoGuard aGuard;
- if ( !m_pDocument)
- throw uno::RuntimeException();
-
- sal_Int32 nCount = 0;
- sal_Bool bColumn = sal_True;
+namespace {
- ScRangePtr p;
+/**
+ * This function object is used to accumulatively count the numbers of
+ * columns and rows in all reference tokens.
+ */
+class AccumulateRangeSize : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ AccumulateRangeSize() :
+ mnCols(0), mnRows(0) {}
-// DR: no idea about this assertion
-// DBG_ASSERT(m_xRanges->Count() == 1, "not handled count of ranges");
+ AccumulateRangeSize(const AccumulateRangeSize& r) :
+ mnCols(r.mnCols), mnRows(r.mnRows) {}
- SCCOL nCols = 0;
- SCROW nRows = 0;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
+ void operator() (const ScSharedTokenRef& pToken)
{
- p->Justify();
- nCols += p->aEnd.Col() - p->aStart.Col() + 1;
- nRows += p->aEnd.Row() - p->aStart.Row() + 1;
+ ScRange r;
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRefTokenHelper::getRangeFromToken(r, pToken, bExternal);
+ r.Justify();
+ mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
+ mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
}
- if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
- (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
- {
- if (nRows > nCols)
- {
- if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
- bColumn = sal_True;
- else
- bColumn = sal_False;
- }
- else if (nCols > nRows)
- {
- if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
- bColumn = sal_False;
- else
- bColumn = sal_True;
- }
- else
- return uno::Sequence< rtl::OUString >();
- }
-
- nCount = bColumn ? nCols : nRows;
+ SCCOL getCols() const { return mnCols; }
+ SCROW getRows() const { return mnRows; }
+private:
+ SCCOL mnCols;
+ SCROW mnRows;
+};
- uno::Sequence< rtl::OUString > aSeq( nCount);
- rtl::OUString* pArr = aSeq.getArray();
- nCount = 0;
- for ( p = m_xRanges->First(); p; p = m_xRanges->Next())
- {
- if (bColumn)
+/**
+ * This function object is used to generate label strings from a list of
+ * reference tokens.
+ */
+class GenerateLabelStrings : public unary_function<ScSharedTokenRef, void>
+{
+public:
+ GenerateLabelStrings(sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
+ mpLabels(new Sequence<OUString>(nSize)),
+ meOrigin(eOrigin),
+ mnCount(0),
+ mbColumn(bColumn) {}
+
+ GenerateLabelStrings(const GenerateLabelStrings& r) :
+ mpLabels(r.mpLabels),
+ meOrigin(r.meOrigin),
+ mnCount(r.mnCount),
+ mbColumn(r.mbColumn) {}
+
+ void operator() (const ScSharedTokenRef& pToken)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(aRange, pToken, bExternal);
+ OUString* pArr = mpLabels->getArray();
+ if (mbColumn)
{
- for (SCCOL nCol = p->aStart.Col(); nCol <= p->aEnd.Col(); ++nCol)
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
{
- if( eOrigin != chart2::data::LabelOrigin_LONG_SIDE )
+ if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
{
String aString = ScGlobal::GetRscString(STR_COLUMN);
aString += ' ';
@@ -1732,30 +3323,89 @@ uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(ch
String aColStr;
aPos.Format( aColStr, SCA_VALID_COL, NULL );
aString += aColStr;
- pArr[nCount] = aString;
+ pArr[mnCount] = aString;
}
else //only indices for categories
- pArr[nCount] = String::CreateFromInt32( nCount+1 );
- ++nCount;
+ pArr[mnCount] = String::CreateFromInt32( mnCount+1 );
+ ++mnCount;
}
}
else
{
- for (sal_Int32 nRow = p->aStart.Row(); nRow <= p->aEnd.Row(); ++nRow)
+ for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
{
- if( eOrigin != chart2::data::LabelOrigin_LONG_SIDE )
+ if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
{
String aString = ScGlobal::GetRscString(STR_ROW);
aString += ' ';
aString += String::CreateFromInt32( nRow+1 );
- pArr[nCount] = aString;
+ pArr[mnCount] = aString;
}
else //only indices for categories
- pArr[nCount] = String::CreateFromInt32( nCount+1 );
- ++nCount;
+ pArr[mnCount] = String::CreateFromInt32( mnCount+1 );
+ ++mnCount;
}
}
}
+
+ Sequence<OUString> getLabels() const { return *mpLabels; }
+
+private:
+ GenerateLabelStrings(); // disabled
+
+ shared_ptr< Sequence<OUString> > mpLabels;
+ chart2::data::LabelOrigin meOrigin;
+ sal_Int32 mnCount;
+ bool mbColumn;
+};
+
+}
+
+uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
+ throw (uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ if (!m_pTokens.get())
+ return Sequence<OUString>();
+
+ // Determine the total size of all ranges.
+ AccumulateRangeSize func;
+ func = for_each(m_pTokens->begin(), m_pTokens->end(), func);
+ SCCOL nCols = func.getCols();
+ SCROW nRows = func.getRows();
+
+ // Detemine whether this is column-major or row-major.
+ bool bColumn = true;
+ if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
+ (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
+ {
+ if (nRows > nCols)
+ {
+ if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
+ bColumn = true;
+ else
+ bColumn = false;
+ }
+ else if (nCols > nRows)
+ {
+ if (eOrigin == chart2::data::LabelOrigin_SHORT_SIDE)
+ bColumn = false;
+ else
+ bColumn = true;
+ }
+ else
+ return Sequence<OUString>();
+ }
+
+ // Generate label strings based on the info so far.
+ sal_Int32 nCount = bColumn ? nCols : nRows;
+ GenerateLabelStrings genLabels(nCount, eOrigin, bColumn);
+ genLabels = for_each(m_pTokens->begin(), m_pTokens->end(), genLabels);
+ Sequence<OUString> aSeq = genLabels.getLabels();
+
return aSeq;
}
@@ -1768,7 +3418,7 @@ uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(ch
sal_Int32 nResult = 0;
ScUnoGuard aGuard;
- if ( !m_pDocument)
+ if ( !m_pDocument || !m_pTokens.get())
return nResult;
sal_Int32 nCount = 0;
@@ -1776,54 +3426,56 @@ uno::Sequence< ::rtl::OUString > SAL_CALL ScChart2DataSequence::generateLabel(ch
ScRangePtr p;
uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( lcl_GetSpreadSheetDocument( m_pDocument ));
- if ( xSpreadDoc.is() )
+ if (!xSpreadDoc.is())
+ return nResult;
+
+ uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
+ if (!xIndex.is())
+ return nResult;
+
+ ScRangeList aRanges;
+ ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens);
+ uno::Reference< table::XCellRange > xSheet;
+ for ( p = aRanges.First(); p && !bFound; p = aRanges.Next())
{
- uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
- if ( xIndex.is() )
+ // TODO: use DocIter?
+ table::CellAddress aStart, aEnd;
+ ScUnoConversion::FillApiAddress( aStart, p->aStart );
+ ScUnoConversion::FillApiAddress( aEnd, p->aEnd );
+ for ( sal_Int16 nSheet = aStart.Sheet; nSheet <= aEnd.Sheet && !bFound; ++nSheet)
{
- uno::Reference< table::XCellRange > xSheet;
- for ( p = m_xRanges->First(); p && !bFound; p = m_xRanges->Next())
+ xSheet.set(xIndex->getByIndex(nSheet), uno::UNO_QUERY);
+ for ( sal_Int32 nCol = aStart.Column; nCol <= aEnd.Column && !bFound; ++nCol)
{
- // TODO: use DocIter?
- table::CellAddress aStart, aEnd;
- ScUnoConversion::FillApiAddress( aStart, p->aStart );
- ScUnoConversion::FillApiAddress( aEnd, p->aEnd );
- for ( sal_Int16 nSheet = aStart.Sheet; nSheet <= aEnd.Sheet && !bFound; ++nSheet)
+ for ( sal_Int32 nRow = aStart.Row; nRow <= aEnd.Row && !bFound; ++nRow)
{
- xSheet.set(xIndex->getByIndex(nSheet), uno::UNO_QUERY);
- for ( sal_Int32 nCol = aStart.Column; nCol <= aEnd.Column && !bFound; ++nCol)
+ if( bGetSeriesFormat )
{
- for ( sal_Int32 nRow = aStart.Row; nRow <= aEnd.Row && !bFound; ++nRow)
+ // TODO: use nicer heuristic
+ // return format of first non-empty cell
+ uno::Reference< text::XText > xText(
+ xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
+ if (xText.is() && xText->getString().getLength())
{
- if( bGetSeriesFormat )
- {
- // TODO: use nicer heuristic
- // return format of first non-empty cell
- uno::Reference< text::XText > xText(
- xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
- if (xText.is() && xText->getString().getLength())
- {
- uno::Reference< beans::XPropertySet > xProp(xText, uno::UNO_QUERY);
- if( xProp.is())
- xProp->getPropertyValue(
- ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult;
- bFound = true;
- break;
- }
- }
- else if( nCount == nIndex )
- {
- uno::Reference< beans::XPropertySet > xProp(
- xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
- if( xProp.is())
- xProp->getPropertyValue(
- ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult;
- bFound = true;
- break;
- }
- ++nCount;
+ uno::Reference< beans::XPropertySet > xProp(xText, uno::UNO_QUERY);
+ if( xProp.is())
+ xProp->getPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult;
+ bFound = true;
+ break;
}
}
+ else if( nCount == nIndex )
+ {
+ uno::Reference< beans::XPropertySet > xProp(
+ xSheet->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
+ if( xProp.is())
+ xProp->getPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberFormat"))) >>= nResult;
+ bFound = true;
+ break;
+ }
+ ++nCount;
}
}
}
@@ -1838,22 +3490,25 @@ uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
throw (uno::RuntimeException)
{
ScUnoGuard aGuard;
- uno::Reference < util::XCloneable > xClone;
- if (m_xDataProvider.is())
- {
- xClone.set(m_xDataProvider->createDataSequenceByRangeRepresentation(getSourceRangeRepresentation()), uno::UNO_QUERY);
- // copy properties
- uno::Reference< beans::XPropertySet > xProp( xClone, uno::UNO_QUERY );
- if( xProp.is())
+ auto_ptr< vector<ScSharedTokenRef> > pTokensNew;
+ if (m_pTokens.get())
+ {
+ // Clone tokens.
+ pTokensNew.reset(new vector<ScSharedTokenRef>);
+ pTokensNew->reserve(m_pTokens->size());
+ vector<ScSharedTokenRef>::const_iterator itr = m_pTokens->begin(), itrEnd = m_pTokens->end();
+ for (; itr != itrEnd; ++itr)
{
- xProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_ROLE )),
- uno::makeAny( m_aRole ));
- xProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_ISHIDDEN )),
- uno::makeAny( m_bHidden ));
+ ScSharedTokenRef p(static_cast<ScToken*>((*itr)->Clone()));
+ pTokensNew->push_back(p);
}
}
+ auto_ptr<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, m_xDataProvider, pTokensNew.release()));
+ p->CopyData(*this);
+ Reference< util::XCloneable > xClone(p.release());
+
return xClone;
}
@@ -1863,12 +3518,12 @@ void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< uti
throw (uno::RuntimeException)
{
// like ScCellRangesBase::addModifyListener
-
ScUnoGuard aGuard;
- if ( m_xRanges->Count() == 0 )
+ if (!m_pTokens.get() || m_pTokens->empty())
return;
-// throw uno::RuntimeException();
+ ScRangeList aRanges;
+ ScRefTokenHelper::getRangeListFromTokens(aRanges, *m_pTokens);
uno::Reference<util::XModifyListener> *pObj =
new uno::Reference<util::XModifyListener>( aListener );
m_aValueListeners.Insert( pObj, m_aValueListeners.Count() );
@@ -1880,9 +3535,9 @@ void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< uti
if( m_pDocument )
{
- ULONG nCount = m_xRanges->Count();
+ ULONG nCount = aRanges.Count();
for (ULONG i=0; i<nCount; i++)
- m_pDocument->StartListeningArea( *m_xRanges->GetObject(i), m_pValueListener );
+ m_pDocument->StartListeningArea( *aRanges.GetObject(i), m_pValueListener );
}
acquire(); // don't lose this object (one ref for all listeners)
@@ -1895,9 +3550,8 @@ void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference<
// like ScCellRangesBase::removeModifyListener
ScUnoGuard aGuard;
- if ( m_xRanges->Count() == 0 )
+ if (!m_pTokens.get() || m_pTokens->empty())
return;
-// throw uno::RuntimeException();
acquire(); // in case the listeners have the last ref - released below
@@ -1969,6 +3623,13 @@ uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(
aRet <<= m_aRole;
else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( SC_UNONAME_ISHIDDEN)))
aRet <<= m_bHidden;
+ else if ( rPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(SC_UNONAME_HIDDENVALUES)))
+ {
+ // This property is read-only thus cannot be set externally via
+ // setPropertyValue(...).
+ BuildDataCache();
+ aRet <<= m_aHiddenValues;
+ }
else
throw beans::UnknownPropertyException();
// TODO: support optional properties
@@ -2064,6 +3725,7 @@ void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
// return pRet;
// }
+#if USE_CHART2_EMPTYDATASEQUENCE
// DataSequence ==============================================================
ScChart2EmptyDataSequence::ScChart2EmptyDataSequence( ScDocument* pDoc,
@@ -2179,7 +3841,7 @@ uno::Sequence< rtl::OUString > SAL_CALL ScChart2EmptyDataSequence::getTextualDat
String aStr;
DBG_ASSERT( m_pDocument, "No Document -> no SourceRangeRepresentation" );
if( m_pDocument )
- m_xRanges->Format( aStr, SCR_ABS_3D, m_pDocument );
+ m_xRanges->Format( aStr, SCR_ABS_3D, m_pDocument, m_pDocument->GetAddressConvention() );
return aStr;
}
@@ -2380,4 +4042,4 @@ void SAL_CALL ScChart2EmptyDataSequence::removeVetoableChangeListener(
// pRet = (ScChart2EmptyDataSequence*) xUT->getSomething( getUnoTunnelId() );
// return pRet;
// }
-
+#endif
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index e2b2d6990..607364070 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -2254,7 +2254,8 @@ uno::Sequence < uno::Reference< table::XCellRange > > SAL_CALL ScTableSheetsObj:
uno::Sequence < uno::Reference < table::XCellRange > > xRet;
ScRangeList aRangeList;
- if (ScRangeStringConverter::GetRangeListFromString( aRangeList, aRange, pDocShell->GetDocument(), ';' ))
+ ScDocument* pDoc = pDocShell->GetDocument();
+ if (ScRangeStringConverter::GetRangeListFromString( aRangeList, aRange, pDoc, ::formula::FormulaGrammar::CONV_OOO, ';' ))
{
sal_Int32 nCount = aRangeList.Count();
if (nCount)
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 14a807eb4..1e737ed2e 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -2171,8 +2171,9 @@ void ScTabView::DoChartSelection(
{
Color aSelColor( rHilightRanges[i].PreferredColor );
ScRangeList aRangeList;
+ ScDocument* pDoc = aViewData.GetDocShell()->GetDocument();
if( ScRangeStringConverter::GetRangeListFromString(
- aRangeList, rHilightRanges[i].RangeRepresentation, aViewData.GetDocShell()->GetDocument(), ';' ))
+ aRangeList, rHilightRanges[i].RangeRepresentation, pDoc, pDoc->GetAddressConvention(), ';' ))
{
for ( ScRangePtr p = aRangeList.First(); p; p = aRangeList.Next())
{