Line data Source code
1 : /*
2 : * This file is part of the LibreOffice project.
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : */
8 :
9 : #include "ucalc.hxx"
10 :
11 : #include <sal/config.h>
12 : #include <test/bootstrapfixture.hxx>
13 :
14 : #include <rtl/strbuf.hxx>
15 : #include <osl/file.hxx>
16 : #include <osl/time.h>
17 :
18 : #include "scdll.hxx"
19 : #include "formulacell.hxx"
20 : #include "stringutil.hxx"
21 : #include "scmatrix.hxx"
22 : #include "drwlayer.hxx"
23 : #include "scitems.hxx"
24 : #include "reffind.hxx"
25 : #include "markdata.hxx"
26 : #include "clipparam.hxx"
27 : #include "refundo.hxx"
28 : #include "undoblk.hxx"
29 : #include "undotab.hxx"
30 : #include "queryentry.hxx"
31 : #include "postit.hxx"
32 : #include "attrib.hxx"
33 : #include "dbdata.hxx"
34 : #include "reftokenhelper.hxx"
35 : #include "userdat.hxx"
36 :
37 : #include "docsh.hxx"
38 : #include "docfunc.hxx"
39 : #include "dbdocfun.hxx"
40 : #include "funcdesc.hxx"
41 : #include "externalrefmgr.hxx"
42 :
43 : #include "calcconfig.hxx"
44 : #include "interpre.hxx"
45 : #include "columniterator.hxx"
46 : #include "types.hxx"
47 : #include "conditio.hxx"
48 : #include "colorscale.hxx"
49 : #include "fillinfo.hxx"
50 : #include "globstr.hrc"
51 : #include "tokenarray.hxx"
52 : #include "scopetools.hxx"
53 : #include "dociter.hxx"
54 : #include "queryparam.hxx"
55 : #include "edittextiterator.hxx"
56 : #include "editutil.hxx"
57 : #include <asciiopt.hxx>
58 : #include <impex.hxx>
59 : #include <columnspanset.hxx>
60 : #include <docoptio.hxx>
61 : #include <patattr.hxx>
62 : #include <docpool.hxx>
63 : #include <globalnames.hxx>
64 : #include <inputopt.hxx>
65 :
66 : #include <editable.hxx>
67 : #include <bcaslot.hxx>
68 : #include <sharedformula.hxx>
69 :
70 : #include <formula/IFunctionDescription.hxx>
71 :
72 : #include <basegfx/polygon/b2dpolygon.hxx>
73 : #include <editeng/boxitem.hxx>
74 : #include <editeng/brushitem.hxx>
75 : #include <editeng/wghtitem.hxx>
76 : #include <editeng/postitem.hxx>
77 :
78 : #include <svx/svdograf.hxx>
79 : #include <svx/svdpage.hxx>
80 : #include <svx/svdocirc.hxx>
81 : #include <svx/svdopath.hxx>
82 : #include <svx/svdocapt.hxx>
83 : #include <svl/srchitem.hxx>
84 : #include <svl/sharedstringpool.hxx>
85 :
86 : #include <sfx2/docfile.hxx>
87 :
88 : #include <iostream>
89 : #include <sstream>
90 : #include <vector>
91 :
92 : #include <com/sun/star/i18n/TransliterationModules.hpp>
93 :
94 408 : struct TestImpl
95 : {
96 : ScDocShellRef m_xDocShell;
97 : };
98 :
99 15 : FormulaGrammarSwitch::FormulaGrammarSwitch(ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar) :
100 15 : mpDoc(pDoc), meOldGrammar(pDoc->GetGrammar())
101 : {
102 15 : mpDoc->SetGrammar(eGrammar);
103 15 : }
104 :
105 15 : FormulaGrammarSwitch::~FormulaGrammarSwitch()
106 : {
107 15 : mpDoc->SetGrammar(meOldGrammar);
108 15 : }
109 :
110 : class MeasureTimeSwitch
111 : {
112 : double& mrDiff;
113 : TimeValue maTimeBefore;
114 : public:
115 0 : MeasureTimeSwitch(double& rDiff) : mrDiff(rDiff)
116 : {
117 0 : mrDiff = 9999.0;
118 0 : osl_getSystemTime(&maTimeBefore);
119 0 : }
120 :
121 0 : ~MeasureTimeSwitch()
122 : {
123 : TimeValue aTimeAfter;
124 0 : osl_getSystemTime(&aTimeAfter);
125 0 : mrDiff = getTimeDiff(aTimeAfter, maTimeBefore);
126 0 : }
127 :
128 0 : static double getTimeDiff(const TimeValue& t1, const TimeValue& t2)
129 : {
130 0 : double tv1 = t1.Seconds;
131 0 : double tv2 = t2.Seconds;
132 0 : tv1 += t1.Nanosec / 1000000000.0;
133 0 : tv2 += t2.Nanosec / 1000000000.0;
134 :
135 0 : return tv1 - tv2;
136 : }
137 : };
138 :
139 204 : Test::Test() :
140 204 : m_pImpl(new TestImpl),
141 408 : m_pDoc(0)
142 : {
143 204 : }
144 :
145 612 : Test::~Test()
146 : {
147 204 : delete m_pImpl;
148 408 : }
149 :
150 78 : ScDocShell& Test::getDocShell()
151 : {
152 78 : return *m_pImpl->m_xDocShell;
153 : }
154 :
155 204 : void Test::setUp()
156 : {
157 204 : BootstrapFixture::setUp();
158 :
159 204 : ScDLL::Init();
160 612 : m_pImpl->m_xDocShell = new ScDocShell(
161 : SfxModelFlags::EMBEDDED_OBJECT |
162 408 : SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
163 612 : SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
164 :
165 204 : m_pImpl->m_xDocShell->DoInitUnitTest();
166 204 : m_pDoc = &m_pImpl->m_xDocShell->GetDocument();
167 204 : }
168 :
169 204 : void Test::tearDown()
170 : {
171 204 : m_pImpl->m_xDocShell->DoClose();
172 204 : m_pImpl->m_xDocShell.Clear();
173 204 : BootstrapFixture::tearDown();
174 204 : }
175 :
176 : #define PERF_ASSERT(df,scale,time,message) \
177 : do { \
178 : double dfscaled = df / scale; \
179 : if ((dfscaled) >= (time)) \
180 : { \
181 : std::ostringstream os; \
182 : os << message " took " << dfscaled << " pseudo-cycles (" << df << " real-time seconds), expected: " << time << " pseudo-cycles."; \
183 : CPPUNIT_FAIL(os.str().c_str()); \
184 : } \
185 : } while (false)
186 :
187 0 : void Test::testPerf()
188 : {
189 0 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
190 :
191 : // First do a set of simple operations to try to work out
192 : // how fast (or not) this particular machine is:
193 : double scale;
194 : {
195 0 : MeasureTimeSwitch aTime(scale);
196 0 : for (int i = 0; i < 10000000; ++i)
197 : {
198 : // Bang on the allocator
199 0 : volatile ScRange *pRange = new ScRange (ScAddress (0,0,0));
200 : // Calc does quite a bit of string conversion
201 0 : volatile double it = OUString::number ((double)i/253.0).toDouble();
202 : // Do we have floating point math ?
203 0 : volatile double another = rtl::math::sin (it);
204 0 : (void)another;
205 0 : delete pRange;
206 0 : }
207 : }
208 0 : printf("CPU scale factor %g\n", scale);
209 :
210 : // FIXME: we should check if this already took too long
211 : // and if so not run the perf. tests to have pity on some
212 : // slow ARM machines - I think.
213 :
214 : // to make the numbers more round and helpful,
215 : // but the calculation of scale reasonably precise.
216 0 : scale /= 100000.0;
217 :
218 : double diff;
219 :
220 : // Clearing an already empty sheet should finish in a fraction of a
221 : // second. Flag failure if it takes more than one second. Clearing 100
222 : // columns should be large enough to flag if something goes wrong.
223 : {
224 0 : MeasureTimeSwitch aTime(diff);
225 0 : clearRange(m_pDoc, ScRange(0,0,0,99,MAXROW,0));
226 : }
227 0 : PERF_ASSERT(diff, scale, 1.0, "Clearing an empty sheet");
228 :
229 : {
230 : // Switch to R1C1 to make it easier to input relative references in multiple cells.
231 0 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
232 :
233 : // Insert formulas in B1:B100000. This shouldn't take long, but may take
234 : // close to a second on a slower machine. We don't measure this yet, for
235 : // now.
236 0 : for (SCROW i = 0; i < 100000; ++i)
237 0 : m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
238 :
239 : // Now, Delete B2:B100000. This should complete in a fraction of a second
240 : // (0.06 sec on my machine).
241 : {
242 0 : MeasureTimeSwitch aTime(diff);
243 0 : clearRange(m_pDoc, ScRange(1,1,0,1,99999,0));
244 : }
245 0 : PERF_ASSERT(diff, scale, 2000, "Removal of a large array of formula cells");
246 : }
247 :
248 0 : clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
249 0 : CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
250 0 : CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
251 :
252 : {
253 : // Measure the performance of repeat-pasting a single cell to a large
254 : // cell range, undoing it, and redoing it.
255 :
256 0 : ScAddress aPos(0,0,0);
257 0 : m_pDoc->SetString(aPos, "test");
258 0 : ScMarkData aMark;
259 0 : aMark.SelectOneTable(0);
260 :
261 : // Copy cell A1 to clipboard.
262 0 : ScDocument aClipDoc(SCDOCMODE_CLIP);
263 0 : ScClipParam aParam(aPos, false);
264 0 : m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
265 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
266 :
267 0 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
268 0 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
269 0 : m_pDoc->CopyToDocument(ScRange(aPos), IDF_CONTENTS, false, pUndoDoc, &aMark);
270 :
271 : // Paste it to A2:A100000, and measure its duration.
272 0 : ScRange aPasteRange(0,1,0,0,99999,0);
273 0 : aMark.SetMarkArea(aPasteRange);
274 :
275 : {
276 0 : MeasureTimeSwitch aTime(diff);
277 0 : m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
278 : }
279 0 : PERF_ASSERT(diff, scale, 1500.0, "Pasting a single cell to A2:A100000");
280 :
281 0 : ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
282 0 : pRedoDoc->InitUndo(m_pDoc, 0, 0);
283 0 : m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
284 :
285 : // Create an undo object for this.
286 0 : ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
287 0 : ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
288 :
289 : // Make sure it did what it's supposed to do.
290 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
291 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
292 :
293 : {
294 0 : MeasureTimeSwitch aTime(diff);
295 0 : aUndo.Undo();
296 : }
297 0 : PERF_ASSERT(diff, scale, 500.0, "Undoing a pasting of a cell to A2:A100000");
298 :
299 : // Make sure it's really undone.
300 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, m_pDoc->GetCellType(aPos));
301 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
302 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
303 :
304 : // Now redo.
305 : {
306 0 : MeasureTimeSwitch aTime(diff);
307 0 : aUndo.Redo();
308 : }
309 0 : PERF_ASSERT(diff, scale, 1000.0, "Redoing a pasting of a cell to A2:A100000");
310 :
311 : // Make sure it's really redone.
312 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
313 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
314 : }
315 :
316 0 : clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
317 0 : CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
318 0 : CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
319 :
320 : {
321 : // Measure the performance of repeat-pasting 2 adjacent cells to a
322 : // large cell range, undoing it, and redoing it. The bottom one of
323 : // the two source cells is empty.
324 :
325 0 : ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
326 :
327 0 : ScAddress aPos(0,0,0);
328 0 : m_pDoc->SetValue(aPos, 12);
329 0 : ScMarkData aMark;
330 0 : aMark.SetMarkArea(aSrcRange);
331 :
332 : // Copy to clipboard.
333 0 : ScDocument aClipDoc(SCDOCMODE_CLIP);
334 0 : ScClipParam aParam(aSrcRange, false);
335 0 : m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
336 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
337 :
338 0 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
339 0 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
340 0 : m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
341 :
342 : // Paste it to A3:A100001, and measure its duration.
343 0 : ScRange aPasteRange(0,2,0,0,100000,0);
344 0 : aMark.SetMarkArea(aPasteRange);
345 :
346 : {
347 0 : MeasureTimeSwitch aTime(diff);
348 0 : m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
349 : }
350 0 : PERF_ASSERT(diff, scale, 1000.0, "Pasting A1:A2 to A3:A100001");
351 :
352 0 : ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
353 0 : pRedoDoc->InitUndo(m_pDoc, 0, 0);
354 0 : m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
355 :
356 : // Create an undo object for this.
357 0 : ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
358 0 : ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
359 :
360 : // Make sure it did what it's supposed to do.
361 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
362 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
363 0 : ScAddress aTmp = aPasteRange.aStart;
364 0 : aTmp.IncRow();
365 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
366 :
367 : {
368 0 : MeasureTimeSwitch aTime(diff);
369 0 : aUndo.Undo();
370 : }
371 0 : PERF_ASSERT(diff, scale, 500.0, "Undoing");
372 :
373 : // Make sure it's really undone.
374 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_VALUE, m_pDoc->GetCellType(aPos));
375 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
376 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
377 :
378 : // Now redo.
379 : {
380 0 : MeasureTimeSwitch aTime(diff);
381 0 : aUndo.Redo();
382 : }
383 0 : PERF_ASSERT(diff, scale, 800.0, "Redoing");
384 :
385 : // Make sure it's really redone.
386 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aStart));
387 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), m_pDoc->GetString(aPasteRange.aEnd));
388 : }
389 :
390 0 : clearRange(m_pDoc, ScRange(0,0,0,1,MAXROW,0)); // Clear columns A:B.
391 0 : CPPUNIT_ASSERT_MESSAGE("Column A shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,0));
392 0 : CPPUNIT_ASSERT_MESSAGE("Column B shouldn't have any broadcasters.", !m_pDoc->HasBroadcaster(0,1));
393 :
394 : {
395 : // Measure the performance of repeat-pasting 2 adjacent cells to a
396 : // large cell range, undoing it, and redoing it. The bottom one of
397 : // the two source cells is empty. In this scenario, the non-empty
398 : // cell is a formula cell referencing a cell to the right, which
399 : // inserts a broadcaster to cell it references. So it has a higher
400 : // overhead than the previous scenario.
401 :
402 0 : ScRange aSrcRange(0,0,0,0,1,0); // A1:A2
403 :
404 0 : ScAddress aPos(0,0,0);
405 0 : m_pDoc->SetString(aPos, "=B1");
406 0 : ScMarkData aMark;
407 0 : aMark.SetMarkArea(aSrcRange);
408 :
409 : // Copy to clipboard.
410 0 : ScDocument aClipDoc(SCDOCMODE_CLIP);
411 0 : ScClipParam aParam(aSrcRange, false);
412 0 : m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
413 0 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
414 :
415 0 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
416 0 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
417 0 : m_pDoc->CopyToDocument(aSrcRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
418 :
419 : // Paste it to A3:A50001, and measure its duration.
420 0 : ScRange aPasteRange(0,2,0,0,50000,0);
421 0 : aMark.SetMarkArea(aPasteRange);
422 :
423 : {
424 0 : MeasureTimeSwitch aTime(diff);
425 0 : m_pDoc->CopyFromClip(aPasteRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc);
426 : }
427 0 : PERF_ASSERT(diff, scale, 2000.0, "Pasting");
428 :
429 0 : ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
430 0 : pRedoDoc->InitUndo(m_pDoc, 0, 0);
431 0 : m_pDoc->CopyToDocument(aPasteRange, IDF_CONTENTS, false, pRedoDoc, &aMark);
432 :
433 : // Create an undo object for this.
434 0 : ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
435 0 : ScUndoPaste aUndo(&getDocShell(), aPasteRange, aMark, pUndoDoc, pRedoDoc, IDF_CONTENTS, pRefUndoData);
436 :
437 : // Make sure it did what it's supposed to do.
438 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
439 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
440 0 : ScAddress aTmp = aPasteRange.aStart;
441 0 : aTmp.IncRow();
442 0 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aTmp));
443 :
444 : #if 0 // TODO: Undo and redo of this scenario is currently not fast enough to be tested reliably.
445 : {
446 : MeasureTimeSwitch aTime(diff);
447 : aUndo.Undo();
448 : }
449 : PERF_ASSERT(diff, scale, 1.0, "Undoing");
450 :
451 : // Make sure it's really undone.
452 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPos));
453 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aStart));
454 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPasteRange.aEnd));
455 :
456 : // Now redo.
457 : {
458 : MeasureTimeSwitch aTime(diff);
459 : aUndo.Redo();
460 : }
461 : PERF_ASSERT(diff, scale, 1.0, "Redoing");
462 :
463 : // Make sure it's really redone.
464 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aStart));
465 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_FORMULA, m_pDoc->GetCellType(aPasteRange.aEnd));
466 : #endif
467 : }
468 :
469 0 : m_pDoc->DeleteTab(0);
470 0 : }
471 :
472 1 : void Test::testCollator()
473 : {
474 1 : CollatorWrapper* p = ScGlobal::GetCollator();
475 1 : sal_Int32 nRes = p->compareString("A", "B");
476 1 : CPPUNIT_ASSERT_MESSAGE("these strings are supposed to be different!", nRes != 0);
477 1 : }
478 :
479 1 : void Test::testSharedStringPool()
480 : {
481 1 : m_pDoc->InsertTab(0, "foo");
482 :
483 : // Strings that are identical.
484 1 : m_pDoc->SetString(ScAddress(0,0,0), "Andy"); // A1
485 1 : m_pDoc->SetString(ScAddress(0,1,0), "Andy"); // A2
486 1 : m_pDoc->SetString(ScAddress(0,2,0), "Bruce"); // A3
487 1 : m_pDoc->SetString(ScAddress(0,3,0), "andy"); // A4
488 1 : m_pDoc->SetString(ScAddress(0,4,0), "BRUCE"); // A5
489 :
490 : {
491 : // These two shared string objects must go out of scope before the purge test.
492 1 : svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
493 2 : svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(0,1,0));
494 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS1.isValid());
495 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid shared string.", aSS2.isValid());
496 1 : CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
497 :
498 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(0,2,0));
499 1 : CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
500 :
501 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
502 1 : CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
503 :
504 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
505 1 : CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
506 :
507 : // A3 and A5 should differ but should be equal case-insensitively.
508 1 : aSS1 = m_pDoc->GetSharedString(ScAddress(0,2,0));
509 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(0,4,0));
510 1 : CPPUNIT_ASSERT_MESSAGE("They must differ", aSS1.getData() != aSS2.getData());
511 1 : CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
512 :
513 : // A2 and A4 should be equal when ignoring cases.
514 1 : aSS1 = m_pDoc->GetSharedString(ScAddress(0,1,0));
515 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(0,3,0));
516 2 : CPPUNIT_ASSERT_MESSAGE("They must be equal when cases are ignored.", aSS1.getDataIgnoreCase() == aSS2.getDataIgnoreCase());
517 : }
518 :
519 : // Check the string counts after purging. Purging shouldn't remove any strings in this case.
520 1 : svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
521 1 : rPool.purge();
522 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
523 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
524 :
525 : // Clear A1 and purge again.
526 1 : clearRange(m_pDoc, ScAddress(0,0,0));
527 1 : rPool.purge();
528 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rPool.getCount());
529 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
530 :
531 : // Clear A2 and purge again.
532 1 : clearRange(m_pDoc, ScAddress(0,1,0));
533 1 : rPool.purge();
534 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rPool.getCount());
535 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
536 :
537 : // Clear A3 and purge again.
538 1 : clearRange(m_pDoc, ScAddress(0,2,0));
539 1 : rPool.purge();
540 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCount());
541 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPool.getCountIgnoreCase());
542 :
543 : // Clear A4 and purge again.
544 1 : clearRange(m_pDoc, ScAddress(0,3,0));
545 1 : rPool.purge();
546 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCount());
547 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPool.getCountIgnoreCase());
548 :
549 : // Clear A5 and the pool should be completely empty.
550 1 : clearRange(m_pDoc, ScAddress(0,4,0));
551 1 : rPool.purge();
552 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCount());
553 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rPool.getCountIgnoreCase());
554 :
555 : // Now, compare string and edit text cells.
556 1 : m_pDoc->SetString(ScAddress(0,0,0), "Andy and Bruce"); // A1
557 1 : ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
558 1 : rEE.SetText("Andy and Bruce");
559 :
560 1 : ESelection aSel;
561 1 : aSel.nStartPara = aSel.nEndPara = 0;
562 :
563 : {
564 : // Set 'Andy' bold.
565 1 : SfxItemSet aItemSet = rEE.GetEmptyItemSet();
566 1 : aSel.nStartPos = 0;
567 1 : aSel.nEndPos = 4;
568 2 : SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
569 1 : aItemSet.Put(aWeight);
570 2 : rEE.QuickSetAttribs(aItemSet, aSel);
571 : }
572 :
573 : {
574 : // Set 'Bruce' italic.
575 1 : SfxItemSet aItemSet = rEE.GetEmptyItemSet();
576 2 : SvxPostureItem aItalic(ITALIC_NORMAL, EE_CHAR_ITALIC);
577 1 : aItemSet.Put(aItalic);
578 1 : aSel.nStartPos = 9;
579 1 : aSel.nEndPos = 14;
580 2 : rEE.QuickSetAttribs(aItemSet, aSel);
581 : }
582 :
583 1 : m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject()); // B1
584 :
585 : // These two should be equal.
586 1 : svl::SharedString aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
587 2 : svl::SharedString aSS2 = m_pDoc->GetSharedString(ScAddress(1,0,0));
588 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
589 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
590 1 : CPPUNIT_ASSERT_EQUAL(aSS1.getData(), aSS2.getData());
591 :
592 1 : rEE.SetText("ANDY and BRUCE");
593 1 : m_pDoc->SetEditText(ScAddress(2,0,0), rEE.CreateTextObject()); // C1
594 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
595 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
596 1 : CPPUNIT_ASSERT_MESSAGE("These two should be different when cases are considered.", aSS1.getData() != aSS2.getData());
597 :
598 : // But they should be considered equal when cases are ignored.
599 1 : aSS1 = m_pDoc->GetSharedString(ScAddress(0,0,0));
600 1 : aSS2 = m_pDoc->GetSharedString(ScAddress(2,0,0));
601 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS1.isValid());
602 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get a valid string ID.", aSS2.isValid());
603 1 : CPPUNIT_ASSERT_EQUAL(aSS1.getDataIgnoreCase(), aSS2.getDataIgnoreCase());
604 :
605 2 : m_pDoc->DeleteTab(0);
606 1 : }
607 :
608 1 : void Test::testSharedStringPoolUndoDoc()
609 : {
610 : struct
611 : {
612 2 : bool check( ScDocument& rSrcDoc, ScDocument& rCopyDoc )
613 : {
614 : // Copy A1:A4 to the undo document.
615 12 : for (SCROW i = 0; i <= 4; ++i)
616 : {
617 10 : ScAddress aPos(0,i,0);
618 10 : rCopyDoc.SetString(aPos, rSrcDoc.GetString(aPos));
619 : }
620 :
621 : // String values in A1:A4 should have identical hash.
622 12 : for (SCROW i = 0; i <= 4; ++i)
623 : {
624 10 : ScAddress aPos(0,i,0);
625 10 : svl::SharedString aSS1 = rSrcDoc.GetSharedString(aPos);
626 20 : svl::SharedString aSS2 = rCopyDoc.GetSharedString(aPos);
627 10 : if (aSS1.getDataIgnoreCase() != aSS2.getDataIgnoreCase())
628 : {
629 0 : cerr << "String hash values are not equal at row " << (i+1)
630 0 : << " for string '" << aSS1.getString() << "'" << endl;
631 0 : return false;
632 : }
633 10 : }
634 :
635 2 : return true;
636 : }
637 :
638 : } aTest;
639 :
640 1 : m_pDoc->InsertTab(0, "Test");
641 :
642 1 : m_pDoc->SetString(ScAddress(0,0,0), "Header");
643 1 : m_pDoc->SetString(ScAddress(0,1,0), "A1");
644 1 : m_pDoc->SetString(ScAddress(0,2,0), "A2");
645 1 : m_pDoc->SetString(ScAddress(0,3,0), "A3");
646 :
647 1 : ScDocument aUndoDoc(SCDOCMODE_UNDO);
648 1 : aUndoDoc.InitUndo(m_pDoc, 0, 0);
649 :
650 1 : bool bSuccess = aTest.check(*m_pDoc, aUndoDoc);
651 1 : CPPUNIT_ASSERT_MESSAGE("Check failed with undo document.", bSuccess);
652 :
653 : // Test the clip document as well.
654 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
655 1 : aClipDoc.ResetClip(m_pDoc, static_cast<SCTAB>(0));
656 :
657 1 : bSuccess = aTest.check(*m_pDoc, aClipDoc);
658 1 : CPPUNIT_ASSERT_MESSAGE("Check failed with clip document.", bSuccess);
659 :
660 2 : m_pDoc->DeleteTab(0);
661 1 : }
662 :
663 1 : void Test::testRangeList()
664 : {
665 1 : m_pDoc->InsertTab(0, "foo");
666 :
667 1 : ScRangeList aRL;
668 1 : aRL.Append(ScRange(1,1,0,3,10,0));
669 1 : CPPUNIT_ASSERT_MESSAGE("List should have one range.", aRL.size() == 1);
670 1 : const ScRange* p = aRL[0];
671 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get the range object.", p);
672 1 : CPPUNIT_ASSERT_MESSAGE("Wrong range.", p->aStart == ScAddress(1,1,0) && p->aEnd == ScAddress(3,10,0));
673 :
674 : // TODO: Add more tests here.
675 :
676 1 : m_pDoc->DeleteTab(0);
677 1 : }
678 :
679 1 : void Test::testMarkData()
680 : {
681 1 : ScMarkData aMarkData;
682 :
683 : // Empty mark. Nothing is selected.
684 2 : std::vector<sc::ColRowSpan> aSpans = aMarkData.GetMarkedRowSpans();
685 1 : CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
686 1 : aSpans = aMarkData.GetMarkedColSpans();
687 1 : CPPUNIT_ASSERT_MESSAGE("Span should be empty.", aSpans.empty());
688 :
689 : // Select B3:F7.
690 1 : aMarkData.SetMarkArea(ScRange(1,2,0,5,6,0));
691 1 : aSpans = aMarkData.GetMarkedRowSpans();
692 1 : CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
693 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
694 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
695 :
696 1 : aSpans = aMarkData.GetMarkedColSpans();
697 1 : CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
698 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(1), aSpans[0].mnStart);
699 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
700 :
701 : // Select A11:B13.
702 1 : aMarkData.SetMultiMarkArea(ScRange(0,10,0,1,12,0));
703 1 : aSpans = aMarkData.GetMarkedRowSpans();
704 1 : CPPUNIT_ASSERT_MESSAGE("There should be 2 selected row spans.", aSpans.size() == 2);
705 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
706 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(6), aSpans[0].mnEnd);
707 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(10), aSpans[1].mnStart);
708 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[1].mnEnd);
709 :
710 1 : aSpans = aMarkData.GetMarkedColSpans();
711 1 : CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
712 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
713 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
714 :
715 : // Select C8:C10.
716 1 : aMarkData.SetMultiMarkArea(ScRange(2,7,0,2,9,0));
717 1 : aSpans = aMarkData.GetMarkedRowSpans();
718 1 : CPPUNIT_ASSERT_MESSAGE("There should be one selected row span.", aSpans.size() == 1);
719 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(2), aSpans[0].mnStart);
720 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(12), aSpans[0].mnEnd);
721 :
722 1 : aSpans = aMarkData.GetMarkedColSpans();
723 1 : CPPUNIT_ASSERT_MESSAGE("There should be one selected column span.", aSpans.size() == 1);
724 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(0), aSpans[0].mnStart);
725 2 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOLROW>(5), aSpans[0].mnEnd);
726 1 : }
727 :
728 1 : void Test::testInput()
729 : {
730 :
731 2 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
732 1 : m_pDoc->InsertTab (0, "foo"));
733 1 : OUString test;
734 :
735 1 : m_pDoc->SetString(0, 0, 0, "'10.5");
736 1 : test = m_pDoc->GetString(0, 0, 0);
737 1 : bool bTest = test == "10.5";
738 1 : CPPUNIT_ASSERT_MESSAGE("String number should have the first apostrophe stripped.", bTest);
739 1 : m_pDoc->SetString(0, 0, 0, "'apple'");
740 1 : test = m_pDoc->GetString(0, 0, 0);
741 1 : bTest = test == "'apple'";
742 1 : CPPUNIT_ASSERT_MESSAGE("Text content should have retained the first apostrophe.", bTest);
743 :
744 : // Customized string handling policy.
745 1 : ScSetStringParam aParam;
746 1 : aParam.setTextInput();
747 1 : m_pDoc->SetString(0, 0, 0, "000123", &aParam);
748 1 : test = m_pDoc->GetString(0, 0, 0);
749 1 : CPPUNIT_ASSERT_MESSAGE("Text content should have been treated as string, not number.", test == "000123");
750 :
751 1 : m_pDoc->DeleteTab(0);
752 1 : }
753 :
754 1 : void Test::testDocStatistics()
755 : {
756 1 : SCTAB nStartTabs = m_pDoc->GetTableCount();
757 1 : m_pDoc->InsertTab(0, "Sheet1");
758 1 : CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
759 1 : m_pDoc->InsertTab(1, "Sheet2");
760 1 : CPPUNIT_ASSERT_MESSAGE("Failed to increment sheet count.", m_pDoc->GetTableCount() == nStartTabs+2);
761 :
762 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), m_pDoc->GetCellCount());
763 1 : m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
764 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), m_pDoc->GetCellCount());
765 1 : m_pDoc->SetValue(ScAddress(2,2,0), 2.5);
766 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), m_pDoc->GetCellCount());
767 1 : m_pDoc->SetString(ScAddress(1,1,1), "Test");
768 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(3), m_pDoc->GetCellCount());
769 :
770 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(0), m_pDoc->GetFormulaGroupCount());
771 1 : m_pDoc->SetString(ScAddress(3,0,1), "=A1");
772 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), m_pDoc->GetFormulaGroupCount());
773 1 : m_pDoc->SetString(ScAddress(3,1,1), "=A2");
774 1 : m_pDoc->SetString(ScAddress(3,2,1), "=A3");
775 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(1), m_pDoc->GetFormulaGroupCount());
776 1 : m_pDoc->SetString(ScAddress(3,3,1), "=A5");
777 1 : m_pDoc->SetString(ScAddress(3,4,1), "=A6");
778 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), m_pDoc->GetFormulaGroupCount());
779 1 : m_pDoc->SetString(ScAddress(3,1,1), "=A3");
780 1 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(4), m_pDoc->GetFormulaGroupCount());
781 :
782 1 : m_pDoc->DeleteTab(1);
783 1 : CPPUNIT_ASSERT_MESSAGE("Failed to decrement sheet count.", m_pDoc->GetTableCount() == nStartTabs+1);
784 1 : m_pDoc->DeleteTab(0); // This may fail in case there is only one sheet in the document.
785 1 : }
786 :
787 1 : void Test::testDataEntries()
788 : {
789 1 : m_pDoc->InsertTab(0, "Test");
790 :
791 1 : m_pDoc->SetString(ScAddress(0,5,0), "Andy");
792 1 : m_pDoc->SetString(ScAddress(0,6,0), "Bruce");
793 1 : m_pDoc->SetString(ScAddress(0,7,0), "Charlie");
794 1 : m_pDoc->SetString(ScAddress(0,10,0), "Andy");
795 :
796 1 : std::vector<ScTypedStrData> aEntries;
797 1 : m_pDoc->GetDataEntries(0, 0, 0, true, aEntries); // Try at the very top.
798 :
799 : // Entries are supposed to be sorted in ascending order, and are all unique.
800 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
801 1 : std::vector<ScTypedStrData>::const_iterator it = aEntries.begin();
802 1 : CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
803 1 : ++it;
804 1 : CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
805 1 : ++it;
806 1 : CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
807 1 : ++it;
808 1 : CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
809 :
810 1 : aEntries.clear();
811 1 : m_pDoc->GetDataEntries(0, MAXROW, 0, true, aEntries); // Try at the very bottom.
812 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aEntries.size());
813 :
814 : // Make sure we get the same set of suggestions.
815 1 : it = aEntries.begin();
816 1 : CPPUNIT_ASSERT_EQUAL(OUString("Andy"), it->GetString());
817 1 : ++it;
818 1 : CPPUNIT_ASSERT_EQUAL(OUString("Bruce"), it->GetString());
819 1 : ++it;
820 1 : CPPUNIT_ASSERT_EQUAL(OUString("Charlie"), it->GetString());
821 1 : ++it;
822 1 : CPPUNIT_ASSERT_MESSAGE("The entries should have ended here.", it == aEntries.end());
823 :
824 1 : m_pDoc->DeleteTab(0);
825 1 : }
826 :
827 1 : void Test::testSelectionFunction()
828 : {
829 1 : m_pDoc->InsertTab(0, "Test");
830 :
831 : // Insert values into B2:B4.
832 1 : m_pDoc->SetString(ScAddress(1,1,0), "=1"); // formula
833 1 : m_pDoc->SetValue(ScAddress(1,2,0), 2.0);
834 1 : m_pDoc->SetValue(ScAddress(1,3,0), 3.0);
835 :
836 : // Insert strings into B5:B8.
837 1 : m_pDoc->SetString(ScAddress(1,4,0), "A");
838 1 : m_pDoc->SetString(ScAddress(1,5,0), "B");
839 1 : m_pDoc->SetString(ScAddress(1,6,0), "=\"C\""); // formula
840 1 : m_pDoc->SetString(ScAddress(1,7,0), "D");
841 :
842 : // Insert values into D2:D4.
843 1 : m_pDoc->SetValue(ScAddress(3,1,0), 4.0);
844 1 : m_pDoc->SetValue(ScAddress(3,2,0), 5.0);
845 1 : m_pDoc->SetValue(ScAddress(3,3,0), 6.0);
846 :
847 : // Insert edit text into D5.
848 1 : ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
849 1 : rEE.SetText("Rich Text");
850 1 : m_pDoc->SetEditText(ScAddress(3,4,0), rEE.CreateTextObject());
851 :
852 : // Insert Another string into D6.
853 1 : m_pDoc->SetString(ScAddress(3,5,0), "E");
854 :
855 : // Select B2:B8 & D2:D8 disjoint region.
856 1 : ScRangeList aRanges;
857 1 : aRanges.Append(ScRange(1,1,0,1,7,0)); // B2:B8
858 1 : aRanges.Append(ScRange(3,1,0,3,7,0)); // D2:D8
859 2 : ScMarkData aMark;
860 1 : aMark.MarkFromRangeList(aRanges, true);
861 :
862 : struct Check
863 : {
864 : ScSubTotalFunc meFunc;
865 : double mfExpected;
866 : };
867 :
868 : {
869 : Check aChecks[] =
870 : {
871 : { SUBTOTAL_FUNC_AVE, 3.5 },
872 : { SUBTOTAL_FUNC_CNT2, 12.0 },
873 : { SUBTOTAL_FUNC_CNT, 6.0 },
874 : { SUBTOTAL_FUNC_MAX, 6.0 },
875 : { SUBTOTAL_FUNC_MIN, 1.0 },
876 : { SUBTOTAL_FUNC_SUM, 21.0 },
877 : { SUBTOTAL_FUNC_SELECTION_COUNT, 14.0 }
878 1 : };
879 :
880 8 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
881 : {
882 7 : double fRes = 0.0;
883 7 : bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
884 7 : CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
885 7 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
886 : }
887 : }
888 :
889 : // Hide rows 4 and 6 and check the results again.
890 :
891 1 : m_pDoc->SetRowHidden(3, 3, 0, true);
892 1 : m_pDoc->SetRowHidden(5, 5, 0, true);
893 1 : CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(3, 0));
894 1 : CPPUNIT_ASSERT_MESSAGE("This row should be hidden.", m_pDoc->RowHidden(5, 0));
895 :
896 : {
897 : Check aChecks[] =
898 : {
899 : { SUBTOTAL_FUNC_AVE, 3.0 },
900 : { SUBTOTAL_FUNC_CNT2, 8.0 },
901 : { SUBTOTAL_FUNC_CNT, 4.0 },
902 : { SUBTOTAL_FUNC_MAX, 5.0 },
903 : { SUBTOTAL_FUNC_MIN, 1.0 },
904 : { SUBTOTAL_FUNC_SUM, 12.0 },
905 : { SUBTOTAL_FUNC_SELECTION_COUNT, 10.0 }
906 1 : };
907 :
908 8 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
909 : {
910 7 : double fRes = 0.0;
911 7 : bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, ScAddress(), aMark, fRes);
912 7 : CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
913 7 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
914 : }
915 : }
916 :
917 : // Make sure that when no selection is present, use the current cursor position.
918 2 : ScMarkData aEmpty;
919 :
920 : {
921 : // D3 (numeric cell containing 5.)
922 1 : ScAddress aPos(3, 2, 0);
923 :
924 : Check aChecks[] =
925 : {
926 : { SUBTOTAL_FUNC_AVE, 5.0 },
927 : { SUBTOTAL_FUNC_CNT2, 1.0 },
928 : { SUBTOTAL_FUNC_CNT, 1.0 },
929 : { SUBTOTAL_FUNC_MAX, 5.0 },
930 : { SUBTOTAL_FUNC_MIN, 5.0 },
931 : { SUBTOTAL_FUNC_SUM, 5.0 },
932 : { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
933 1 : };
934 :
935 8 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
936 : {
937 7 : double fRes = 0.0;
938 7 : bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
939 7 : CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
940 7 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
941 : }
942 : }
943 :
944 : {
945 : // B7 (string formula cell containing ="C".)
946 1 : ScAddress aPos(1, 6, 0);
947 :
948 : Check aChecks[] =
949 : {
950 : { SUBTOTAL_FUNC_CNT2, 1.0 },
951 : { SUBTOTAL_FUNC_SELECTION_COUNT, 1.0 }
952 1 : };
953 :
954 3 : for (size_t i = 0; i < SAL_N_ELEMENTS(aChecks); ++i)
955 : {
956 2 : double fRes = 0.0;
957 2 : bool bRes = m_pDoc->GetSelectionFunction(aChecks[i].meFunc, aPos, aEmpty, fRes);
958 2 : CPPUNIT_ASSERT_MESSAGE("Failed to fetch selection function result.", bRes);
959 2 : CPPUNIT_ASSERT_EQUAL(aChecks[i].mfExpected, fRes);
960 : }
961 : }
962 :
963 2 : m_pDoc->DeleteTab(0);
964 1 : }
965 :
966 1 : void Test::testCopyToDocument()
967 : {
968 1 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "src"));
969 :
970 1 : m_pDoc->SetString(0, 0, 0, "Header");
971 1 : m_pDoc->SetString(0, 1, 0, "1");
972 1 : m_pDoc->SetString(0, 2, 0, "2");
973 1 : m_pDoc->SetString(0, 3, 0, "3");
974 1 : m_pDoc->SetString(0, 4, 0, "=4/2");
975 1 : m_pDoc->CalcAll();
976 :
977 : //note on A1
978 1 : ScAddress aAdrA1 (0, 0, 0); // numerical cell content
979 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(aAdrA1);
980 1 : pNote->SetText(aAdrA1, "Hello world in A1");
981 :
982 : // Copy statically to another document.
983 :
984 1 : ScDocument aDestDoc(SCDOCMODE_DOCUMENT);
985 1 : aDestDoc.InsertTab(0, "src");
986 1 : m_pDoc->CopyStaticToDocument(ScRange(0,1,0,0,3,0), 0, &aDestDoc); // Copy A2:A4
987 1 : m_pDoc->CopyStaticToDocument(ScAddress(0,0,0), 0, &aDestDoc); // Copy A1
988 1 : m_pDoc->CopyStaticToDocument(ScRange(0,4,0,0,7,0), 0, &aDestDoc); // Copy A5:A8
989 :
990 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), aDestDoc.GetString(0,0,0));
991 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,1,0), aDestDoc.GetString(0,1,0));
992 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,2,0), aDestDoc.GetString(0,2,0));
993 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,3,0), aDestDoc.GetString(0,3,0));
994 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,4,0), aDestDoc.GetString(0,4,0));
995 :
996 : // verify note
997 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note in A1 destDocument", aDestDoc.HasNote(ScAddress(0, 0, 0)));
998 2 : CPPUNIT_ASSERT_MESSAGE("The notes content should be the same on both documents",
999 1 : aDestDoc.GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
1000 :
1001 1 : m_pDoc->DeleteTab(0);
1002 1 : }
1003 :
1004 : namespace {
1005 :
1006 : struct HoriIterCheck
1007 : {
1008 : SCCOL nCol;
1009 : SCROW nRow;
1010 : const char* pVal;
1011 : };
1012 :
1013 : template<size_t _Size>
1014 6 : bool checkHorizontalIterator(ScDocument* pDoc, const char* pData[][_Size], size_t nDataCount, const HoriIterCheck* pChecks, size_t nCheckCount)
1015 : {
1016 6 : ScAddress aPos(0,0,0);
1017 6 : Test::insertRangeData(pDoc, aPos, pData, nDataCount);
1018 6 : ScHorizontalCellIterator aIter(pDoc, 0, 0, 0, 1, nDataCount-1);
1019 :
1020 : SCCOL nCol;
1021 : SCROW nRow;
1022 6 : size_t i = 0;
1023 31 : for (ScRefCellValue* pCell = aIter.GetNext(nCol, nRow); pCell; pCell = aIter.GetNext(nCol, nRow), ++i)
1024 : {
1025 25 : if (i >= nCheckCount)
1026 : {
1027 0 : cerr << "hit invalid check " << i << " of " << nCheckCount << endl;
1028 0 : CPPUNIT_FAIL("Iterator claims there is more data than there should be.");
1029 0 : return false;
1030 : }
1031 :
1032 25 : if (pChecks[i].nCol != nCol)
1033 : {
1034 0 : cerr << "Column mismatch " << pChecks[i].nCol << " vs. " << nCol << endl;
1035 0 : return false;
1036 : }
1037 :
1038 25 : if (pChecks[i].nRow != nRow)
1039 : {
1040 0 : cerr << "Row mismatch " << pChecks[i].nRow << " vs. " << nRow << endl;
1041 0 : return false;
1042 : }
1043 :
1044 25 : if (OUString::createFromAscii(pChecks[i].pVal) != pCell->getString(pDoc))
1045 : {
1046 0 : cerr << "String mismatch " << pChecks[i].pVal << " vs. " <<
1047 : OUStringToOString(pCell->getString(pDoc), RTL_TEXTENCODING_UTF8).getStr() << endl;
1048 0 : return false;
1049 : }
1050 : }
1051 :
1052 6 : return true;
1053 : }
1054 :
1055 : }
1056 :
1057 1 : void Test::testHorizontalIterator()
1058 : {
1059 1 : m_pDoc->InsertTab(0, "test");
1060 :
1061 : {
1062 : // Raw data - mixed types
1063 : const char* aData[][2] = {
1064 : { "A", "B" },
1065 : { "C", "1" },
1066 : { "D", "2" },
1067 : { "E", "3" }
1068 1 : };
1069 :
1070 : HoriIterCheck aChecks[] = {
1071 : { 0, 0, "A" },
1072 : { 1, 0, "B" },
1073 : { 0, 1, "C" },
1074 : { 1, 1, "1" },
1075 : { 0, 2, "D" },
1076 : { 1, 2, "2" },
1077 : { 0, 3, "E" },
1078 : { 1, 3, "3" },
1079 1 : };
1080 :
1081 : bool bRes = checkHorizontalIterator(
1082 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1083 :
1084 1 : if (!bRes)
1085 0 : CPPUNIT_FAIL("Failed on test mixed.");
1086 : }
1087 :
1088 : {
1089 : // Raw data - 'hole' data
1090 : const char* aData[][2] = {
1091 : { "A", "B" },
1092 : { "C", 0 },
1093 : { "D", "E" },
1094 1 : };
1095 :
1096 : HoriIterCheck aChecks[] = {
1097 : { 0, 0, "A" },
1098 : { 1, 0, "B" },
1099 : { 0, 1, "C" },
1100 : { 0, 2, "D" },
1101 : { 1, 2, "E" },
1102 1 : };
1103 :
1104 : bool bRes = checkHorizontalIterator(
1105 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1106 :
1107 1 : if (!bRes)
1108 0 : CPPUNIT_FAIL("Failed on test hole.");
1109 : }
1110 :
1111 : {
1112 : // Very holy data
1113 : const char* aData[][2] = {
1114 : { 0, "A" },
1115 : { 0, 0 },
1116 : { 0, "1" },
1117 : { "B", 0 },
1118 : { "C", "2" },
1119 : { "D", "3" },
1120 : { "E", 0 },
1121 : { 0, "G" },
1122 : { 0, 0 },
1123 1 : };
1124 :
1125 : HoriIterCheck aChecks[] = {
1126 : { 1, 0, "A" },
1127 : { 1, 2, "1" },
1128 : { 0, 3, "B" },
1129 : { 0, 4, "C" },
1130 : { 1, 4, "2" },
1131 : { 0, 5, "D" },
1132 : { 1, 5, "3" },
1133 : { 0, 6, "E" },
1134 : { 1, 7, "G" },
1135 1 : };
1136 :
1137 : bool bRes = checkHorizontalIterator(
1138 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1139 :
1140 1 : if (!bRes)
1141 0 : CPPUNIT_FAIL("Failed on test holy.");
1142 : }
1143 :
1144 : {
1145 : // Degenerate case
1146 : const char* aData[][2] = {
1147 : { 0, 0 },
1148 : { 0, 0 },
1149 : { 0, 0 },
1150 1 : };
1151 :
1152 : bool bRes = checkHorizontalIterator(
1153 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), NULL, 0);
1154 :
1155 1 : if (!bRes)
1156 0 : CPPUNIT_FAIL("Failed on test degenerate.");
1157 : }
1158 :
1159 : {
1160 : // Data at end
1161 : const char* aData[][2] = {
1162 : { 0, 0 },
1163 : { 0, 0 },
1164 : { 0, "A" },
1165 1 : };
1166 :
1167 : HoriIterCheck aChecks[] = {
1168 : { 1, 2, "A" },
1169 1 : };
1170 :
1171 : bool bRes = checkHorizontalIterator(
1172 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1173 :
1174 1 : if (!bRes)
1175 0 : CPPUNIT_FAIL("Failed on test at end.");
1176 : }
1177 :
1178 : {
1179 : // Data in middle
1180 : const char* aData[][2] = {
1181 : { 0, 0 },
1182 : { 0, 0 },
1183 : { 0, "A" },
1184 : { 0, "1" },
1185 : { 0, 0 },
1186 1 : };
1187 :
1188 : HoriIterCheck aChecks[] = {
1189 : { 1, 2, "A" },
1190 : { 1, 3, "1" },
1191 1 : };
1192 :
1193 : bool bRes = checkHorizontalIterator(
1194 1 : m_pDoc, aData, SAL_N_ELEMENTS(aData), aChecks, SAL_N_ELEMENTS(aChecks));
1195 :
1196 1 : if (!bRes)
1197 0 : CPPUNIT_FAIL("Failed on test in middle.");
1198 : }
1199 :
1200 1 : m_pDoc->DeleteTab(0);
1201 1 : }
1202 :
1203 1 : void Test::testValueIterator()
1204 : {
1205 1 : m_pDoc->InsertTab(0, "Test");
1206 :
1207 : // Turn on "precision as shown" option.
1208 1 : ScDocOptions aOpt = m_pDoc->GetDocOptions();
1209 1 : aOpt.SetCalcAsShown(true);
1210 1 : m_pDoc->SetDocOptions(aOpt);
1211 :
1212 : // Purely horizontal data layout with numeric data.
1213 4 : for (SCCOL i = 1; i <= 3; ++i)
1214 3 : m_pDoc->SetValue(ScAddress(i,2,0), i);
1215 :
1216 : double fVal;
1217 : sal_uInt16 nErr;
1218 :
1219 : {
1220 1 : const double aChecks[] = { 1.0, 2.0, 3.0 };
1221 1 : size_t nCheckLen = SAL_N_ELEMENTS(aChecks);
1222 :
1223 1 : ScValueIterator aIter(m_pDoc, ScRange(1,2,0,3,2,0));
1224 1 : bool bHas = false;
1225 :
1226 1 : size_t nCheckPos = 0;
1227 4 : for (bHas = aIter.GetFirst(fVal, nErr); bHas; bHas = aIter.GetNext(fVal, nErr), ++nCheckPos)
1228 : {
1229 3 : CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
1230 3 : CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos], fVal);
1231 3 : CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), nErr);
1232 : }
1233 : }
1234 :
1235 1 : m_pDoc->DeleteTab(0);
1236 1 : }
1237 :
1238 1 : void Test::testHorizontalAttrIterator()
1239 : {
1240 1 : m_pDoc->InsertTab(0, "Test");
1241 :
1242 : // Set the background color of B2:C3,D2,E3,C4:D4,B5:D5 to blue
1243 1 : ScPatternAttr aCellBackColor(m_pDoc->GetPool());
1244 1 : aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_BLUE, ATTR_BACKGROUND));
1245 1 : m_pDoc->ApplyPatternAreaTab(1, 1, 2, 2, 0, aCellBackColor);
1246 1 : m_pDoc->ApplyPatternAreaTab(3, 1, 3, 1, 0, aCellBackColor);
1247 1 : m_pDoc->ApplyPatternAreaTab(4, 2, 4, 2, 0, aCellBackColor);
1248 1 : m_pDoc->ApplyPatternAreaTab(2, 3, 3, 3, 0, aCellBackColor);
1249 1 : m_pDoc->ApplyPatternAreaTab(1, 4, 4, 4, 0, aCellBackColor);
1250 :
1251 : // some numeric data
1252 5 : for (SCCOL i = 1; i <= 4; ++i)
1253 20 : for (SCROW j = 1; j <= 4; ++j)
1254 16 : m_pDoc->SetValue(ScAddress(i,j,0), i*10+j);
1255 :
1256 : {
1257 1 : const int aChecks[][3] = { {1, 3, 1}, {1, 2, 2}, {4, 4, 2}, {2, 3, 3}, {1, 4, 4} };
1258 1 : size_t nCheckLen = SAL_N_ELEMENTS(aChecks);
1259 :
1260 1 : ScHorizontalAttrIterator aIter(m_pDoc, 0, 0, 0, 5, 5);
1261 : SCCOL nCol1, nCol2;
1262 : SCROW nRow;
1263 1 : size_t nCheckPos = 0;
1264 6 : for (const ScPatternAttr* pAttr = aIter.GetNext(nCol1, nCol2, nRow); pAttr; pAttr = aIter.GetNext(nCol1, nCol2, nRow), ++nCheckPos)
1265 : {
1266 5 : CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
1267 5 : CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][0], static_cast<int>(nCol1));
1268 5 : CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][1], static_cast<int>(nCol2));
1269 5 : CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][2], static_cast<int>(nRow));
1270 1 : }
1271 : }
1272 :
1273 1 : m_pDoc->DeleteTab(0);
1274 1 : }
1275 :
1276 : namespace {
1277 :
1278 7 : bool broadcasterShifted(const ScDocument& rDoc, const ScAddress& rFrom, const ScAddress& rTo)
1279 : {
1280 7 : const SvtBroadcaster* pBC = rDoc.GetBroadcaster(rFrom);
1281 7 : if (pBC)
1282 : {
1283 0 : cerr << "Broadcaster shouldn't be here." << endl;
1284 0 : return false;
1285 : }
1286 :
1287 7 : pBC = rDoc.GetBroadcaster(rTo);
1288 7 : if (!pBC)
1289 : {
1290 0 : cerr << "Broadcaster should be here." << endl;
1291 0 : return false;
1292 : }
1293 7 : return true;
1294 : }
1295 :
1296 11 : formula::FormulaToken* getSingleRefToken(ScDocument& rDoc, const ScAddress& rPos)
1297 : {
1298 11 : ScFormulaCell* pFC = rDoc.GetFormulaCell(rPos);
1299 11 : if (!pFC)
1300 : {
1301 0 : cerr << "Formula cell expected, but not found." << endl;
1302 0 : return NULL;
1303 : }
1304 :
1305 11 : ScTokenArray* pTokens = pFC->GetCode();
1306 11 : if (!pTokens)
1307 : {
1308 0 : cerr << "Token array is not present." << endl;
1309 0 : return NULL;
1310 : }
1311 :
1312 11 : formula::FormulaToken* pToken = pTokens->First();
1313 11 : if (!pToken || pToken->GetType() != formula::svSingleRef)
1314 : {
1315 0 : cerr << "Not a single reference token." << endl;
1316 0 : return NULL;
1317 : }
1318 :
1319 11 : return pToken;
1320 : }
1321 :
1322 9 : bool checkRelativeRefToken(ScDocument& rDoc, const ScAddress& rPos, SCsCOL nRelCol, SCsROW nRelRow)
1323 : {
1324 9 : formula::FormulaToken* pToken = getSingleRefToken(rDoc, rPos);
1325 9 : if (!pToken)
1326 0 : return false;
1327 :
1328 9 : ScSingleRefData& rRef = *pToken->GetSingleRef();
1329 9 : if (!rRef.IsColRel() || rRef.Col() != nRelCol)
1330 : {
1331 0 : cerr << "Unexpected relative column address." << endl;
1332 0 : return false;
1333 : }
1334 :
1335 9 : if (!rRef.IsRowRel() || rRef.Row() != nRelRow)
1336 : {
1337 0 : cerr << "Unexpected relative row address." << endl;
1338 0 : return false;
1339 : }
1340 :
1341 9 : return true;
1342 : }
1343 :
1344 2 : bool checkDeletedRefToken(ScDocument& rDoc, const ScAddress& rPos)
1345 : {
1346 2 : formula::FormulaToken* pToken = getSingleRefToken(rDoc, rPos);
1347 2 : if (!pToken)
1348 0 : return false;
1349 :
1350 2 : ScSingleRefData& rRef = *pToken->GetSingleRef();
1351 2 : if (!rRef.IsDeleted())
1352 : {
1353 0 : cerr << "Deleted reference is expected, but it's still a valid reference." << endl;
1354 0 : return false;
1355 : }
1356 :
1357 2 : return true;
1358 : }
1359 :
1360 : }
1361 :
1362 1 : void Test::testCellBroadcaster()
1363 : {
1364 1 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "foo"));
1365 :
1366 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calculation.
1367 1 : m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1368 1 : double val = m_pDoc->GetValue(ScAddress(1,0,0)); // A1 is empty, so the result should be 0.
1369 1 : CPPUNIT_ASSERT_EQUAL(0.0, val);
1370 :
1371 1 : const SvtBroadcaster* pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1372 1 : CPPUNIT_ASSERT_MESSAGE("Cell A1 should have a broadcaster.", pBC);
1373 :
1374 : // Change the value of A1 and make sure that B1 follows.
1375 1 : m_pDoc->SetValue(ScAddress(0,0,0), 1.23);
1376 1 : val = m_pDoc->GetValue(ScAddress(1,0,0));
1377 1 : CPPUNIT_ASSERT_EQUAL(1.23, val);
1378 :
1379 : // Move column A down 5 cells. Make sure B1 now references A6, not A1.
1380 1 : m_pDoc->InsertRow(0, 0, 0, 0, 0, 5);
1381 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1382 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 5));
1383 :
1384 : // Make sure the broadcaster has also moved.
1385 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1386 1 : broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,5,0)));
1387 :
1388 : // Set new value to A6 and make sure B1 gets updated.
1389 1 : m_pDoc->SetValue(ScAddress(0,5,0), 45.6);
1390 1 : val = m_pDoc->GetValue(ScAddress(1,0,0));
1391 1 : CPPUNIT_ASSERT_EQUAL(45.6, val);
1392 :
1393 : // Move column A up 3 cells, and make sure B1 now references A3, not A6.
1394 1 : m_pDoc->DeleteRow(0, 0, 0, 0, 0, 3);
1395 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1396 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 2));
1397 :
1398 : // The broadcaster should also have been relocated from A6 to A3.
1399 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1400 1 : broadcasterShifted(*m_pDoc, ScAddress(0,5,0), ScAddress(0,2,0)));
1401 :
1402 : // Insert cells over A1:A10 and shift cells to right.
1403 1 : m_pDoc->InsertCol(ScRange(0, 0, 0, 0, 10, 0));
1404 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check failed.",
1405 1 : checkRelativeRefToken(*m_pDoc, ScAddress(2,0,0), -1, 2));
1406 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1407 1 : broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(1,2,0)));
1408 :
1409 : // Delete formula in C2, which should remove the broadcaster in B3.
1410 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
1411 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should still exist.", pBC);
1412 1 : clearRange(m_pDoc, ScAddress(2,0,0));
1413 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(ScAddress(2,0,0))); // C2 should be empty.
1414 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(1,2,0));
1415 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster in B3 should have been removed.", !pBC);
1416 :
1417 : // Clear everything and start over.
1418 1 : clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1419 :
1420 1 : m_pDoc->SetString(ScAddress(1,0,0), "=A1"); // B1 depends on A1.
1421 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1422 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", pBC);
1423 :
1424 : // While column A is still empty, move column A down 2 cells. This should
1425 : // move the broadcaster from A1 to A3.
1426 1 : m_pDoc->InsertRow(0, 0, 0, 0, 0, 2);
1427 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1428 1 : broadcasterShifted(*m_pDoc, ScAddress(0,0,0), ScAddress(0,2,0)));
1429 :
1430 : // Move it back while column A is still empty.
1431 1 : m_pDoc->DeleteRow(0, 0, 0, 0, 0, 2);
1432 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1433 1 : broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,0,0)));
1434 :
1435 : // Clear everything again
1436 1 : clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1437 :
1438 : // B1:B3 depends on A1:A3
1439 1 : m_pDoc->SetString(ScAddress(1,0,0), "=A1");
1440 1 : m_pDoc->SetString(ScAddress(1,1,0), "=A2");
1441 1 : m_pDoc->SetString(ScAddress(1,2,0), "=A3");
1442 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1443 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
1444 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1445 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 0));
1446 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B3 failed.",
1447 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 0));
1448 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1449 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A2.", m_pDoc->GetBroadcaster(ScAddress(0,1,0)));
1450 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A3.", m_pDoc->GetBroadcaster(ScAddress(0,2,0)));
1451 :
1452 : // Insert Rows at row 2, down 5 rows.
1453 1 : m_pDoc->InsertRow(0, 0, 0, 0, 1, 5);
1454 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist in A1.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1455 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B1 failed.",
1456 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,0,0), -1, 0));
1457 :
1458 : // Broadcasters in A2 and A3 should shift down by 5 rows.
1459 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1460 1 : broadcasterShifted(*m_pDoc, ScAddress(0,1,0), ScAddress(0,6,0)));
1461 2 : CPPUNIT_ASSERT_MESSAGE("Broadcaster relocation failed.",
1462 1 : broadcasterShifted(*m_pDoc, ScAddress(0,2,0), ScAddress(0,7,0)));
1463 :
1464 : // B2 and B3 should reference shifted cells.
1465 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1466 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,1,0), -1, 5));
1467 2 : CPPUNIT_ASSERT_MESSAGE("Relative reference check in B2 failed.",
1468 1 : checkRelativeRefToken(*m_pDoc, ScAddress(1,2,0), -1, 5));
1469 :
1470 : // Delete cells with broadcasters.
1471 1 : m_pDoc->DeleteRow(0, 0, 0, 0, 4, 6);
1472 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A7.", !m_pDoc->GetBroadcaster(ScAddress(0,6,0)));
1473 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should NOT exist in A8.", !m_pDoc->GetBroadcaster(ScAddress(0,7,0)));
1474 :
1475 : // References in B2 and B3 should be invalid.
1476 2 : CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B2 failed.",
1477 1 : checkDeletedRefToken(*m_pDoc, ScAddress(1,1,0)));
1478 2 : CPPUNIT_ASSERT_MESSAGE("Deleted reference check in B3 failed.",
1479 1 : checkDeletedRefToken(*m_pDoc, ScAddress(1,2,0)));
1480 :
1481 : // Clear everything again
1482 1 : clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1483 :
1484 : {
1485 : // Switch to R1C1 to make it easier to input relative references in multiple cells.
1486 1 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
1487 :
1488 : // Have B1:B20 reference A1:A20.
1489 1 : val = 0.0;
1490 21 : for (SCROW i = 0; i < 20; ++i)
1491 : {
1492 20 : m_pDoc->SetValue(ScAddress(0,i,0), val++);
1493 20 : m_pDoc->SetString(ScAddress(1,i,0), "=RC[-1]");
1494 1 : }
1495 : }
1496 :
1497 : // Ensure that the formula cells show correct values, and the referenced
1498 : // cells have broadcasters.
1499 1 : val = 0.0;
1500 21 : for (SCROW i = 0; i < 20; ++i, ++val)
1501 : {
1502 20 : CPPUNIT_ASSERT_EQUAL(val, m_pDoc->GetValue(ScAddress(1,i,0)));
1503 20 : pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
1504 20 : CPPUNIT_ASSERT_MESSAGE("Broadcast should exist here.", pBC);
1505 : }
1506 :
1507 : // Delete formula cells in B2:B19.
1508 1 : clearRange(m_pDoc, ScRange(1,1,0,1,18,0));
1509 : // Ensure that A2:A19 no longer have broadcasters, but A1 and A20 still do.
1510 1 : CPPUNIT_ASSERT_MESSAGE("A1 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,0,0)));
1511 1 : CPPUNIT_ASSERT_MESSAGE("A20 should still have broadcaster.", m_pDoc->GetBroadcaster(ScAddress(0,19,0)));
1512 19 : for (SCROW i = 1; i <= 18; ++i)
1513 : {
1514 18 : pBC = m_pDoc->GetBroadcaster(ScAddress(0,i,0));
1515 18 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should have been deleted.", !pBC);
1516 : }
1517 :
1518 : // Clear everything again
1519 1 : clearRange(m_pDoc, ScRange(0,0,0,10,100,0));
1520 :
1521 1 : m_pDoc->SetValue(ScAddress(0,0,0), 2.0);
1522 1 : m_pDoc->SetString(ScAddress(1,0,0), "=A1");
1523 1 : m_pDoc->SetString(ScAddress(2,0,0), "=B1");
1524 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(0,0,0));
1525 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,0,0));
1526 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(2,0,0));
1527 :
1528 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1529 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1530 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(1,0,0));
1531 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1532 :
1533 : // Change the value of A1 and make sure everyone follows suit.
1534 1 : m_pDoc->SetValue(ScAddress(0,0,0), 3.5);
1535 1 : CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(0,0,0));
1536 1 : CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(1,0,0));
1537 1 : CPPUNIT_ASSERT_EQUAL(3.5, m_pDoc->GetValue(2,0,0));
1538 :
1539 : // Insert a column at column B.
1540 1 : m_pDoc->InsertCol(ScRange(1,0,0,1,MAXROW,0));
1541 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(0,0,0));
1542 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1543 1 : pBC = m_pDoc->GetBroadcaster(ScAddress(2,0,0));
1544 1 : CPPUNIT_ASSERT_MESSAGE("Broadcaster should exist here.", pBC);
1545 :
1546 : // Change the value of A1 again.
1547 1 : m_pDoc->SetValue(ScAddress(0,0,0), 5.5);
1548 1 : CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(0,0,0));
1549 1 : CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(2,0,0));
1550 1 : CPPUNIT_ASSERT_EQUAL(5.5, m_pDoc->GetValue(3,0,0));
1551 :
1552 1 : m_pDoc->DeleteTab(0);
1553 1 : }
1554 :
1555 1 : void Test::testFuncParam()
1556 : {
1557 :
1558 2 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet",
1559 1 : m_pDoc->InsertTab (0, "foo"));
1560 :
1561 : // First, the normal case, with no missing parameters.
1562 1 : m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;2;3)");
1563 1 : m_pDoc->CalcFormulaTree(false, false);
1564 : double val;
1565 1 : m_pDoc->GetValue(0, 0, 0, val);
1566 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 2);
1567 :
1568 : // Now function with missing parameters. Missing values should be treated
1569 : // as zeros.
1570 1 : m_pDoc->SetString(0, 0, 0, "=AVERAGE(1;;;)");
1571 1 : m_pDoc->CalcFormulaTree(false, false);
1572 1 : m_pDoc->GetValue(0, 0, 0, val);
1573 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 0.25);
1574 :
1575 : // Conversion of string to numeric argument.
1576 1 : m_pDoc->SetString(0, 0, 0, "=\"\"+3"); // empty string
1577 1 : m_pDoc->SetString(0, 1, 0, "=\" \"+3"); // only blank
1578 1 : m_pDoc->SetString(0, 2, 0, "=\" 4 \"+3"); // number in blanks
1579 1 : m_pDoc->SetString(0, 3, 0, "=\" x \"+3"); // non-numeric
1580 1 : m_pDoc->SetString(0, 4, 0, "=\"4.4\"+3"); // locale dependent
1581 :
1582 1 : OUString aVal;
1583 2 : ScCalcConfig aConfig;
1584 :
1585 : // With "Convert also locale dependent" and "Empty string as zero"=True option.
1586 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::LOCALE;
1587 1 : aConfig.mbEmptyStringAsZero = true;
1588 1 : m_pDoc->SetCalcConfig(aConfig);
1589 1 : m_pDoc->CalcAll();
1590 1 : m_pDoc->GetValue(0, 0, 0, val);
1591 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1592 1 : m_pDoc->GetValue(0, 1, 0, val);
1593 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1594 1 : m_pDoc->GetValue(0, 2, 0, val);
1595 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1596 1 : aVal = m_pDoc->GetString( 0, 3, 0);
1597 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1598 1 : m_pDoc->GetValue(0, 4, 0, val);
1599 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
1600 :
1601 : // With "Convert also locale dependent" and "Empty string as zero"=False option.
1602 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::LOCALE;
1603 1 : aConfig.mbEmptyStringAsZero = false;
1604 1 : m_pDoc->SetCalcConfig(aConfig);
1605 1 : m_pDoc->CalcAll();
1606 1 : aVal = m_pDoc->GetString( 0, 0, 0);
1607 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1608 1 : aVal = m_pDoc->GetString( 0, 1, 0);
1609 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1610 1 : m_pDoc->GetValue(0, 2, 0, val);
1611 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1612 1 : aVal = m_pDoc->GetString( 0, 3, 0);
1613 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1614 1 : m_pDoc->GetValue(0, 4, 0, val);
1615 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7.4);
1616 :
1617 : // With "Convert only unambiguous" and "Empty string as zero"=True option.
1618 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::UNAMBIGUOUS;
1619 1 : aConfig.mbEmptyStringAsZero = true;
1620 1 : m_pDoc->SetCalcConfig(aConfig);
1621 1 : m_pDoc->CalcAll();
1622 1 : m_pDoc->GetValue(0, 0, 0, val);
1623 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1624 1 : m_pDoc->GetValue(0, 1, 0, val);
1625 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1626 1 : m_pDoc->GetValue(0, 2, 0, val);
1627 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1628 1 : aVal = m_pDoc->GetString( 0, 3, 0);
1629 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1630 1 : aVal = m_pDoc->GetString( 0, 4, 0);
1631 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1632 :
1633 : // With "Convert only unambiguous" and "Empty string as zero"=False option.
1634 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::UNAMBIGUOUS;
1635 1 : aConfig.mbEmptyStringAsZero = false;
1636 1 : m_pDoc->SetCalcConfig(aConfig);
1637 1 : m_pDoc->CalcAll();
1638 1 : aVal = m_pDoc->GetString( 0, 0, 0);
1639 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1640 1 : aVal = m_pDoc->GetString( 0, 1, 0);
1641 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1642 1 : m_pDoc->GetValue(0, 2, 0, val);
1643 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 7);
1644 1 : aVal = m_pDoc->GetString( 0, 3, 0);
1645 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1646 1 : aVal = m_pDoc->GetString( 0, 4, 0);
1647 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1648 :
1649 : // With "Treat as zero" ("Empty string as zero" is ignored).
1650 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::ZERO;
1651 1 : aConfig.mbEmptyStringAsZero = true;
1652 1 : m_pDoc->SetCalcConfig(aConfig);
1653 1 : m_pDoc->CalcAll();
1654 1 : m_pDoc->GetValue(0, 0, 0, val);
1655 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1656 1 : m_pDoc->GetValue(0, 1, 0, val);
1657 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1658 1 : m_pDoc->GetValue(0, 2, 0, val);
1659 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1660 1 : m_pDoc->GetValue(0, 3, 0, val);
1661 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1662 1 : m_pDoc->GetValue(0, 4, 0, val);
1663 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", val == 3);
1664 :
1665 : // With "Generate #VALUE! error" ("Empty string as zero" is ignored).
1666 1 : aConfig.meStringConversion = ScCalcConfig::StringConversion::ILLEGAL;
1667 1 : aConfig.mbEmptyStringAsZero = false;
1668 1 : m_pDoc->SetCalcConfig(aConfig);
1669 1 : m_pDoc->CalcAll();
1670 1 : aVal = m_pDoc->GetString( 0, 0, 0);
1671 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1672 1 : aVal = m_pDoc->GetString( 0, 1, 0);
1673 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1674 1 : aVal = m_pDoc->GetString( 0, 2, 0);
1675 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1676 1 : aVal = m_pDoc->GetString( 0, 3, 0);
1677 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1678 1 : aVal = m_pDoc->GetString( 0, 4, 0);
1679 1 : CPPUNIT_ASSERT_MESSAGE("incorrect result", aVal == "#VALUE!");
1680 :
1681 2 : m_pDoc->DeleteTab(0);
1682 1 : }
1683 :
1684 1 : void Test::testNamedRange()
1685 : {
1686 : RangeNameDef aNames[] = {
1687 : { "Divisor", "$Sheet1.$A$1:$A$1048576", 1 },
1688 : { "MyRange1", "$Sheet1.$A$1:$A$100", 2 },
1689 : { "MyRange2", "$Sheet1.$B$1:$B$100", 3 },
1690 : { "MyRange3", "$Sheet1.$C$1:$C$100", 4 }
1691 1 : };
1692 :
1693 1 : CPPUNIT_ASSERT_MESSAGE ("failed to insert sheet", m_pDoc->InsertTab (0, "Sheet1"));
1694 :
1695 1 : m_pDoc->SetValue (0, 0, 0, 101);
1696 :
1697 1 : ScRangeName* pNames = new ScRangeName;
1698 1 : bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
1699 1 : CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
1700 1 : m_pDoc->SetRangeName(pNames);
1701 :
1702 1 : ScRangeName* pNewRanges = m_pDoc->GetRangeName();
1703 1 : CPPUNIT_ASSERT(pNewRanges);
1704 :
1705 : // Make sure the index lookup does the right thing.
1706 5 : for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
1707 : {
1708 4 : const ScRangeData* p = pNewRanges->findByIndex(aNames[i].mnIndex);
1709 4 : CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed.", p);
1710 4 : OUString aName = p->GetName();
1711 4 : CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved.", aName.equalsAscii(aNames[i].mpName));
1712 4 : }
1713 :
1714 : // Test usage in formula expression.
1715 1 : m_pDoc->SetString (1, 0, 0, "=A1/Divisor");
1716 1 : m_pDoc->CalcAll();
1717 :
1718 : double result;
1719 1 : m_pDoc->GetValue (1, 0, 0, result);
1720 1 : CPPUNIT_ASSERT_MESSAGE ("calculation failed", result == 1.0);
1721 :
1722 : // Test copy-ability of range names.
1723 1 : ScRangeName* pCopiedRanges = new ScRangeName(*pNewRanges);
1724 1 : m_pDoc->SetRangeName(pCopiedRanges);
1725 : // Make sure the index lookup still works.
1726 5 : for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i)
1727 : {
1728 4 : const ScRangeData* p = pCopiedRanges->findByIndex(aNames[i].mnIndex);
1729 4 : CPPUNIT_ASSERT_MESSAGE("lookup of range name by index failed with the copied instance.", p);
1730 4 : OUString aName = p->GetName();
1731 4 : CPPUNIT_ASSERT_MESSAGE("wrong range name is retrieved with the copied instance.", aName.equalsAscii(aNames[i].mpName));
1732 4 : }
1733 :
1734 1 : m_pDoc->SetRangeName(NULL); // Delete the names.
1735 1 : m_pDoc->DeleteTab(0);
1736 1 : }
1737 :
1738 1 : void Test::testInsertNameList()
1739 : {
1740 1 : m_pDoc->InsertTab(0, "Test");
1741 :
1742 : RangeNameDef aNames[] = {
1743 : { "MyRange1", "$Test.$A$1:$A$100", 1 },
1744 : { "MyRange2", "$Test.$B$1:$B$100", 2 },
1745 : { "MyRange3", "$Test.$C$1:$C$100", 3 }
1746 1 : };
1747 :
1748 1 : ScRangeName* pNames = new ScRangeName;
1749 1 : bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
1750 1 : CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
1751 1 : m_pDoc->SetRangeName(pNames);
1752 :
1753 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
1754 1 : ScAddress aPos(1,1,0);
1755 1 : rDocFunc.InsertNameList(aPos, true);
1756 :
1757 4 : for (size_t i = 0; i < SAL_N_ELEMENTS(aNames); ++i, aPos.IncRow())
1758 : {
1759 3 : OUString aName = m_pDoc->GetString(aPos);
1760 3 : CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(aNames[i].mpName), aName);
1761 3 : ScAddress aExprPos = aPos;
1762 3 : aExprPos.IncCol();
1763 6 : OUString aExpr = m_pDoc->GetString(aExprPos);
1764 6 : OUString aExpected = "=";
1765 3 : aExpected += OUString::createFromAscii(aNames[i].mpExpr);
1766 3 : CPPUNIT_ASSERT_EQUAL(aExpected, aExpr);
1767 3 : }
1768 :
1769 1 : m_pDoc->DeleteTab(0);
1770 1 : }
1771 :
1772 1 : void Test::testCSV()
1773 : {
1774 1 : const int English = 0, European = 1;
1775 : struct {
1776 : const char *pStr; int eSep; bool bResult; double nValue;
1777 : } aTests[] = {
1778 : { "foo", English, false, 0.0 },
1779 : { "1.0", English, true, 1.0 },
1780 : { "1,0", English, false, 0.0 },
1781 : { "1.0", European, false, 0.0 },
1782 : { "1.000", European, true, 1000.0 },
1783 : { "1,000", European, true, 1.0 },
1784 : { "1.000", English, true, 1.0 },
1785 : { "1,000", English, true, 1000.0 },
1786 : { " 1.0", English, true, 1.0 },
1787 : { " 1.0 ", English, true, 1.0 },
1788 : { "1.0 ", European, false, 0.0 },
1789 : { "1.000", European, true, 1000.0 },
1790 : { "1137.999", English, true, 1137.999 },
1791 : { "1.000.00", European, false, 0.0 }
1792 1 : };
1793 15 : for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(aTests); i++) {
1794 14 : OUString aStr(aTests[i].pStr, strlen (aTests[i].pStr), RTL_TEXTENCODING_UTF8);
1795 14 : double nValue = 0.0;
1796 : bool bResult = ScStringUtil::parseSimpleNumber
1797 14 : (aStr, aTests[i].eSep == English ? '.' : ',',
1798 14 : aTests[i].eSep == English ? ',' : '.',
1799 28 : nValue);
1800 14 : CPPUNIT_ASSERT_MESSAGE ("CSV numeric detection failure", bResult == aTests[i].bResult);
1801 14 : CPPUNIT_ASSERT_MESSAGE ("CSV numeric value failure", nValue == aTests[i].nValue);
1802 14 : }
1803 1 : }
1804 :
1805 : template<typename Evaluator>
1806 4 : void checkMatrixElements(const ScMatrix& rMat)
1807 : {
1808 : SCSIZE nC, nR;
1809 4 : rMat.GetDimensions(nC, nR);
1810 : Evaluator aEval;
1811 32 : for (SCSIZE i = 0; i < nC; ++i)
1812 : {
1813 508 : for (SCSIZE j = 0; j < nR; ++j)
1814 : {
1815 480 : aEval(i, j, rMat.Get(i, j));
1816 : }
1817 : }
1818 4 : }
1819 :
1820 : struct AllZeroMatrix
1821 : {
1822 40 : void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
1823 : {
1824 40 : CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
1825 40 : CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
1826 40 : }
1827 : };
1828 :
1829 : struct PartiallyFilledZeroMatrix
1830 : {
1831 40 : void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
1832 : {
1833 40 : CPPUNIT_ASSERT_MESSAGE("element is not of numeric type", rVal.nType == SC_MATVAL_VALUE);
1834 40 : if (1 <= nCol && nCol <= 2 && 2 <= nRow && nRow <= 8)
1835 : {
1836 14 : CPPUNIT_ASSERT_MESSAGE("element value must be 3.0", rVal.fVal == 3.0);
1837 : }
1838 : else
1839 : {
1840 26 : CPPUNIT_ASSERT_MESSAGE("element value must be zero", rVal.fVal == 0.0);
1841 : }
1842 40 : }
1843 : };
1844 :
1845 : struct AllEmptyMatrix
1846 : {
1847 200 : void operator() (SCSIZE /*nCol*/, SCSIZE /*nRow*/, const ScMatrixValue& rVal) const
1848 : {
1849 200 : CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
1850 200 : CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1851 200 : }
1852 : };
1853 :
1854 : struct PartiallyFilledEmptyMatrix
1855 : {
1856 200 : void operator() (SCSIZE nCol, SCSIZE nRow, const ScMatrixValue& rVal) const
1857 : {
1858 200 : if (nCol == 1 && nRow == 1)
1859 : {
1860 1 : CPPUNIT_ASSERT_MESSAGE("element is not of boolean type", rVal.nType == SC_MATVAL_BOOLEAN);
1861 1 : CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == 1.0);
1862 : }
1863 199 : else if (nCol == 4 && nRow == 5)
1864 : {
1865 1 : CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_VALUE);
1866 1 : CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.fVal == -12.5);
1867 : }
1868 198 : else if (nCol == 8 && nRow == 2)
1869 : {
1870 1 : CPPUNIT_ASSERT_MESSAGE("element is not of value type", rVal.nType == SC_MATVAL_STRING);
1871 1 : CPPUNIT_ASSERT_MESSAGE("element value is not what is expected", rVal.aStr.getString() == "Test");
1872 : }
1873 197 : else if (nCol == 8 && nRow == 11)
1874 : {
1875 1 : CPPUNIT_ASSERT_MESSAGE("element is not of empty path type", rVal.nType == SC_MATVAL_EMPTYPATH);
1876 1 : CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1877 : }
1878 : else
1879 : {
1880 196 : CPPUNIT_ASSERT_MESSAGE("element is not of empty type", rVal.nType == SC_MATVAL_EMPTY);
1881 196 : CPPUNIT_ASSERT_MESSAGE("value of \"empty\" element is expected to be zero", rVal.fVal == 0.0);
1882 : }
1883 200 : }
1884 : };
1885 :
1886 1 : void Test::testMatrix()
1887 : {
1888 1 : svl::SharedStringPool& rPool = m_pDoc->GetSharedStringPool();
1889 2 : ScMatrixRef pMat, pMat2;
1890 :
1891 : // First, test the zero matrix type.
1892 1 : pMat = new ScMatrix(0, 0, 0.0);
1893 : SCSIZE nC, nR;
1894 1 : pMat->GetDimensions(nC, nR);
1895 1 : CPPUNIT_ASSERT_MESSAGE("matrix is not empty", nC == 0 && nR == 0);
1896 1 : pMat->Resize(4, 10, 0.0);
1897 1 : pMat->GetDimensions(nC, nR);
1898 1 : CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 4 && nR == 10);
1899 2 : CPPUNIT_ASSERT_MESSAGE("both 'and' and 'or' should evaluate to false",
1900 1 : !pMat->And() && !pMat->Or());
1901 :
1902 : // Resizing into a larger matrix should fill the void space with zeros.
1903 1 : checkMatrixElements<AllZeroMatrix>(*pMat);
1904 :
1905 1 : pMat->FillDouble(3.0, 1, 2, 2, 8);
1906 1 : checkMatrixElements<PartiallyFilledZeroMatrix>(*pMat);
1907 1 : CPPUNIT_ASSERT_MESSAGE("matrix is expected to be numeric", pMat->IsNumeric());
1908 2 : CPPUNIT_ASSERT_MESSAGE("partially non-zero matrix should evaluate false on 'and' and true on 'or",
1909 1 : !pMat->And() && pMat->Or());
1910 1 : pMat->FillDouble(5.0, 0, 0, nC-1, nR-1);
1911 2 : CPPUNIT_ASSERT_MESSAGE("fully non-zero matrix should evaluate true both on 'and' and 'or",
1912 1 : pMat->And() && pMat->Or());
1913 :
1914 : // Test the AND and OR evaluations.
1915 1 : pMat = new ScMatrix(2, 2, 0.0);
1916 :
1917 : // Only some of the elements are non-zero.
1918 1 : pMat->PutBoolean(true, 0, 0);
1919 1 : pMat->PutDouble(1.0, 1, 1);
1920 1 : CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
1921 1 : CPPUNIT_ASSERT_MESSAGE("incorrect AND result", !pMat->And());
1922 :
1923 : // All of the elements are non-zero.
1924 1 : pMat->PutBoolean(true, 0, 1);
1925 1 : pMat->PutDouble(2.3, 1, 0);
1926 1 : CPPUNIT_ASSERT_MESSAGE("incorrect OR result", pMat->Or());
1927 1 : CPPUNIT_ASSERT_MESSAGE("incorrect AND result", pMat->And());
1928 :
1929 : // Now test the emtpy matrix type.
1930 1 : pMat = new ScMatrix(10, 20);
1931 1 : pMat->GetDimensions(nC, nR);
1932 1 : CPPUNIT_ASSERT_MESSAGE("matrix size is not as expected", nC == 10 && nR == 20);
1933 1 : checkMatrixElements<AllEmptyMatrix>(*pMat);
1934 :
1935 1 : pMat->PutBoolean(true, 1, 1);
1936 1 : pMat->PutDouble(-12.5, 4, 5);
1937 1 : pMat->PutString(rPool.intern("Test"), 8, 2);
1938 1 : pMat->PutEmptyPath(8, 11);
1939 1 : checkMatrixElements<PartiallyFilledEmptyMatrix>(*pMat);
1940 :
1941 : // Test resizing.
1942 1 : pMat = new ScMatrix(0, 0);
1943 1 : pMat->Resize(2, 2, 1.5);
1944 1 : pMat->PutEmpty(1, 1);
1945 :
1946 1 : CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 0));
1947 1 : CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(0, 1));
1948 1 : CPPUNIT_ASSERT_EQUAL(1.5, pMat->GetDouble(1, 0));
1949 1 : CPPUNIT_ASSERT_MESSAGE("PutEmpty() call failed.", pMat->IsEmpty(1, 1));
1950 :
1951 : // Max and min values.
1952 1 : pMat = new ScMatrix(2, 2, 0.0);
1953 1 : pMat->PutDouble(-10, 0, 0);
1954 1 : pMat->PutDouble(-12, 0, 1);
1955 1 : pMat->PutDouble(-8, 1, 0);
1956 1 : pMat->PutDouble(-25, 1, 1);
1957 1 : CPPUNIT_ASSERT_EQUAL(-25.0, pMat->GetMinValue(false));
1958 1 : CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false));
1959 1 : pMat->PutString(rPool.intern("Test"), 0, 0);
1960 1 : CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMaxValue(true)); // text as zero.
1961 1 : CPPUNIT_ASSERT_EQUAL(-8.0, pMat->GetMaxValue(false)); // ignore text.
1962 1 : pMat->PutBoolean(true, 0, 0);
1963 1 : CPPUNIT_ASSERT_EQUAL(1.0, pMat->GetMaxValue(false));
1964 1 : pMat = new ScMatrix(2, 2, 10.0);
1965 1 : pMat->PutBoolean(false, 0, 0);
1966 1 : pMat->PutDouble(12.5, 1, 1);
1967 1 : CPPUNIT_ASSERT_EQUAL(0.0, pMat->GetMinValue(false));
1968 1 : CPPUNIT_ASSERT_EQUAL(12.5, pMat->GetMaxValue(false));
1969 :
1970 : // Convert matrix into a linear double array. String elements become NaN
1971 : // and empty elements become 0.
1972 1 : pMat = new ScMatrix(3, 3);
1973 1 : pMat->PutDouble(2.5, 0, 0);
1974 1 : pMat->PutDouble(1.2, 0, 1);
1975 1 : pMat->PutString(rPool.intern("A"), 1, 1);
1976 1 : pMat->PutDouble(2.3, 2, 1);
1977 1 : pMat->PutDouble(-20, 2, 2);
1978 :
1979 : double fNaN;
1980 1 : rtl::math::setNan(&fNaN);
1981 :
1982 2 : std::vector<double> aDoubles;
1983 1 : pMat->GetDoubleArray(aDoubles);
1984 :
1985 : {
1986 1 : const double pChecks[] = { 2.5, 1.2, 0, 0, fNaN, 0, 0, 2.3, -20 };
1987 1 : CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
1988 10 : for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
1989 : {
1990 9 : if (rtl::math::isNan(pChecks[i]))
1991 1 : CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
1992 : else
1993 8 : CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
1994 : }
1995 : }
1996 :
1997 1 : pMat2 = new ScMatrix(3, 3, 10.0);
1998 1 : pMat2->PutString(rPool.intern("B"), 1, 0);
1999 1 : pMat2->MergeDoubleArray(aDoubles, ScMatrix::Mul);
2000 :
2001 : {
2002 1 : const double pChecks[] = { 25, 12, 0, fNaN, fNaN, 0, 0, 23, -200 };
2003 1 : CPPUNIT_ASSERT_EQUAL(SAL_N_ELEMENTS(pChecks), aDoubles.size());
2004 10 : for (size_t i = 0, n = aDoubles.size(); i < n; ++i)
2005 : {
2006 9 : if (rtl::math::isNan(pChecks[i]))
2007 2 : CPPUNIT_ASSERT_MESSAGE("NaN is expected, but it's not.", rtl::math::isNan(aDoubles[i]));
2008 : else
2009 7 : CPPUNIT_ASSERT_EQUAL(pChecks[i], aDoubles[i]);
2010 : }
2011 1 : }
2012 1 : }
2013 :
2014 1 : void Test::testMatrixComparisonWithErrors()
2015 : {
2016 1 : m_pDoc->InsertTab(0, "foo");
2017 :
2018 : // Insert the source values in A1:A2.
2019 1 : m_pDoc->SetString(0, 0, 0, "=1/0");
2020 1 : m_pDoc->SetValue( 0, 1, 0, 1.0);
2021 :
2022 : // Create a matrix formula in B3:B4 referencing A1:A2 and doing a greater
2023 : // than comparison on it's values. Error value must be propagated.
2024 1 : ScMarkData aMark;
2025 1 : aMark.SelectOneTable(0);
2026 1 : m_pDoc->InsertMatrixFormula(1, 2, 1, 3, aMark, "=A1:A2>0");
2027 :
2028 1 : CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc->GetString(0,0,0));
2029 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue( 0,1,0));
2030 1 : CPPUNIT_ASSERT_EQUAL(OUString("#DIV/0!"), m_pDoc->GetString(1,2,0));
2031 1 : CPPUNIT_ASSERT_EQUAL(OUString("TRUE"), m_pDoc->GetString(1,3,0));
2032 :
2033 1 : m_pDoc->DeleteTab(0);
2034 1 : }
2035 :
2036 1 : void Test::testEnterMixedMatrix()
2037 : {
2038 1 : m_pDoc->InsertTab(0, "foo");
2039 :
2040 : // Insert the source values in A1:B2.
2041 1 : m_pDoc->SetString(0, 0, 0, "A");
2042 1 : m_pDoc->SetString(1, 0, 0, "B");
2043 1 : double val = 1.0;
2044 1 : m_pDoc->SetValue(0, 1, 0, val);
2045 1 : val = 2.0;
2046 1 : m_pDoc->SetValue(1, 1, 0, val);
2047 :
2048 : // Create a matrix range in A4:B5 referencing A1:B2.
2049 1 : ScMarkData aMark;
2050 1 : aMark.SelectOneTable(0);
2051 1 : m_pDoc->InsertMatrixFormula(0, 3, 1, 4, aMark, "=A1:B2", NULL);
2052 :
2053 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(0,0,0), m_pDoc->GetString(0,3,0));
2054 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(1,0,0), m_pDoc->GetString(1,3,0));
2055 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(0,1,0), m_pDoc->GetValue(0,4,0));
2056 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(1,1,0), m_pDoc->GetValue(1,4,0));
2057 :
2058 1 : m_pDoc->DeleteTab(0);
2059 1 : }
2060 :
2061 1 : void Test::testMatrixEditable()
2062 : {
2063 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
2064 :
2065 1 : m_pDoc->InsertTab(0, "Test");
2066 :
2067 : // Values in A1:B1.
2068 1 : m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
2069 1 : m_pDoc->SetValue(ScAddress(1,0,0), 2.0);
2070 :
2071 : // A2 is a normal formula.
2072 1 : m_pDoc->SetString(ScAddress(0,1,0), "=5");
2073 :
2074 : // A3:A4 is a matrix.
2075 1 : ScRange aMatRange(0,2,0,0,3,0);
2076 2 : ScMarkData aMark;
2077 1 : aMark.SetMarkArea(aMatRange);
2078 1 : m_pDoc->InsertMatrixFormula(0, 2, 0, 3, aMark, "=TRANSPOSE(A1:B1)", NULL);
2079 :
2080 : // Check their values.
2081 1 : CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,1,0)));
2082 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,2,0)));
2083 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
2084 :
2085 : // Make sure A3:A4 is a matrix.
2086 1 : ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,2,0));
2087 1 : CPPUNIT_ASSERT(pFC);
2088 1 : CPPUNIT_ASSERT_MESSAGE("A3 should be matrix origin.", pFC->GetMatrixFlag() == MM_FORMULA);
2089 :
2090 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(0,3,0));
2091 1 : CPPUNIT_ASSERT(pFC);
2092 1 : CPPUNIT_ASSERT_MESSAGE("A4 should be matrix reference.", pFC->GetMatrixFlag() == MM_REFERENCE);
2093 :
2094 : // Check to make sure A3:A4 combined is editable.
2095 1 : ScEditableTester aTester;
2096 1 : aTester.TestSelection(m_pDoc, aMark);
2097 1 : CPPUNIT_ASSERT(aTester.IsEditable());
2098 :
2099 2 : m_pDoc->DeleteTab(0);
2100 1 : }
2101 :
2102 1 : void Test::testCellCopy()
2103 : {
2104 1 : m_pDoc->InsertTab(0, "TestTab");
2105 1 : ScAddress aSrc(0,0,0);
2106 1 : ScAddress aDest(0,1,0);
2107 1 : OUString aStr("please copy me");
2108 1 : m_pDoc->SetString(aSrc, "please copy me");
2109 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aSrc), aStr);
2110 : // copy to self - why not ?
2111 1 : m_pDoc->CopyCellToDocument(aSrc,aDest,*m_pDoc);
2112 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aDest), aStr);
2113 1 : }
2114 :
2115 1 : void Test::testSheetCopy()
2116 : {
2117 1 : m_pDoc->InsertTab(0, "TestTab");
2118 1 : CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
2119 :
2120 : // Insert text in A1.
2121 1 : m_pDoc->SetString(ScAddress(0,0,0), "copy me");
2122 :
2123 : // Insert edit cells in B1:B3.
2124 1 : ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
2125 1 : rEE.SetText("Edit 1");
2126 1 : m_pDoc->SetEditText(ScAddress(1,0,0), rEE.CreateTextObject());
2127 1 : rEE.SetText("Edit 2");
2128 1 : m_pDoc->SetEditText(ScAddress(1,1,0), rEE.CreateTextObject());
2129 1 : rEE.SetText("Edit 3");
2130 1 : m_pDoc->SetEditText(ScAddress(1,2,0), rEE.CreateTextObject());
2131 :
2132 : SCROW nRow1, nRow2;
2133 1 : bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2134 1 : CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2135 :
2136 : // insert a note
2137 1 : ScAddress aAdrA1 (0,2,0); // empty cell content.
2138 1 : ScPostIt *pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
2139 1 : pNoteA1->SetText(aAdrA1, "Hello world in A3");
2140 :
2141 : // Copy and test the result.
2142 1 : m_pDoc->CopyTab(0, 1);
2143 1 : CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
2144 1 : bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2145 1 : CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2146 1 : CPPUNIT_ASSERT_MESSAGE("There should be note on A3 in new sheet", m_pDoc->HasNote(ScAddress(0,2,1)));
2147 1 : CPPUNIT_ASSERT_EQUAL(OUString("copy me"), m_pDoc->GetString(ScAddress(0,0,1)));
2148 :
2149 : // Check the copied edit cells.
2150 1 : const EditTextObject* pEditObj = m_pDoc->GetEditText(ScAddress(1,0,1));
2151 1 : CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B1.", pEditObj);
2152 1 : CPPUNIT_ASSERT_EQUAL(OUString("Edit 1"), pEditObj->GetText(0));
2153 1 : pEditObj = m_pDoc->GetEditText(ScAddress(1,1,1));
2154 1 : CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B2.", pEditObj);
2155 1 : CPPUNIT_ASSERT_EQUAL(OUString("Edit 2"), pEditObj->GetText(0));
2156 1 : pEditObj = m_pDoc->GetEditText(ScAddress(1,2,1));
2157 1 : CPPUNIT_ASSERT_MESSAGE("There should be an edit cell in B3.", pEditObj);
2158 1 : CPPUNIT_ASSERT_EQUAL(OUString("Edit 3"), pEditObj->GetText(0));
2159 :
2160 1 : m_pDoc->DeleteTab(1);
2161 :
2162 1 : m_pDoc->SetRowHidden(5, 10, 0, true);
2163 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2164 1 : CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2165 1 : bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
2166 1 : CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2167 1 : bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
2168 1 : CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2169 :
2170 : // Copy the sheet once again.
2171 1 : m_pDoc->CopyTab(0, 1);
2172 1 : CPPUNIT_ASSERT_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount() == 2);
2173 1 : bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2174 1 : CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2175 1 : bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
2176 1 : CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2177 1 : bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
2178 1 : CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2179 1 : m_pDoc->DeleteTab(1);
2180 1 : m_pDoc->DeleteTab(0);
2181 1 : }
2182 :
2183 1 : void Test::testSheetMove()
2184 : {
2185 1 : m_pDoc->InsertTab(0, "TestTab1");
2186 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount(), static_cast<SCTAB>(1));
2187 : SCROW nRow1, nRow2;
2188 1 : bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2189 1 : CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2190 :
2191 : //test if inserting before another sheet works
2192 1 : m_pDoc->InsertTab(0, "TestTab2");
2193 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("document should have two sheets", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2194 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2195 1 : CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2196 :
2197 : // Move and test the result.
2198 1 : m_pDoc->MoveTab(0, 1);
2199 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2200 1 : bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2201 1 : CPPUNIT_ASSERT_MESSAGE("copied sheet should also have all rows visible as the original.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2202 1 : OUString aName;
2203 1 : m_pDoc->GetName(0, aName);
2204 1 : CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab1" );
2205 :
2206 1 : m_pDoc->SetRowHidden(5, 10, 0, true);
2207 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2208 1 : CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2209 1 : bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
2210 1 : CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2211 1 : bHidden = m_pDoc->RowHidden(11, 0, &nRow1, &nRow2);
2212 1 : CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2213 :
2214 : // Move the sheet once again.
2215 1 : m_pDoc->MoveTab(1, 0);
2216 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("document now should have two sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(2));
2217 1 : bHidden = m_pDoc->RowHidden(0, 1, &nRow1, &nRow2);
2218 1 : CPPUNIT_ASSERT_MESSAGE("rows 0 - 4 should be visible", !bHidden && nRow1 == 0 && nRow2 == 4);
2219 1 : bHidden = m_pDoc->RowHidden(5, 1, &nRow1, &nRow2);
2220 1 : CPPUNIT_ASSERT_MESSAGE("rows 5 - 10 should be hidden", bHidden && nRow1 == 5 && nRow2 == 10);
2221 1 : bHidden = m_pDoc->RowHidden(11, 1, &nRow1, &nRow2);
2222 1 : CPPUNIT_ASSERT_MESSAGE("rows 11 - maxrow should be visible", !bHidden && nRow1 == 11 && nRow2 == MAXROW);
2223 1 : m_pDoc->GetName(0, aName);
2224 1 : CPPUNIT_ASSERT_MESSAGE( "sheets should have changed places", aName == "TestTab2" );
2225 1 : m_pDoc->DeleteTab(1);
2226 1 : m_pDoc->DeleteTab(0);
2227 1 : }
2228 :
2229 1 : void Test::testDataArea()
2230 : {
2231 1 : m_pDoc->InsertTab(0, "Data");
2232 :
2233 : // Totally empty sheet should be rightfully considered empty in all accounts.
2234 1 : CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
2235 1 : CPPUNIT_ASSERT_MESSAGE("Sheet is expected to be empty.", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2236 :
2237 : // Now, set borders in some cells....
2238 1 : ::editeng::SvxBorderLine aLine(NULL, 50, table::BorderLineStyle::SOLID);
2239 1 : SvxBoxItem aBorderItem(ATTR_BORDER);
2240 1 : aBorderItem.SetLine(&aLine, SvxBoxItemLine::LEFT);
2241 1 : aBorderItem.SetLine(&aLine, SvxBoxItemLine::RIGHT);
2242 101 : for (SCROW i = 0; i < 100; ++i)
2243 : // Set borders from row 1 to 100.
2244 100 : m_pDoc->ApplyAttr(0, i, 0, aBorderItem);
2245 :
2246 : // Now the sheet is considered non-empty for printing purposes, but still
2247 : // be empty in all the other cases.
2248 2 : CPPUNIT_ASSERT_MESSAGE("Empty sheet with borders should be printable.",
2249 1 : !m_pDoc->IsPrintEmpty(0, 0, 0, 100, 100));
2250 2 : CPPUNIT_ASSERT_MESSAGE("But it should still be considered empty in all the other cases.",
2251 1 : m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2252 :
2253 : // Adding a real cell content should turn the block non-empty.
2254 1 : m_pDoc->SetString(0, 0, 0, "Some text");
2255 2 : CPPUNIT_ASSERT_MESSAGE("Now the block should not be empty with a real cell content.",
2256 1 : !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100));
2257 :
2258 : // TODO: Add more tests for normal data area calculation.
2259 :
2260 1 : m_pDoc->DeleteTab(0);
2261 1 : }
2262 :
2263 1 : void Test::testStreamValid()
2264 : {
2265 1 : m_pDoc->InsertTab(0, "Sheet1");
2266 1 : m_pDoc->InsertTab(1, "Sheet2");
2267 1 : m_pDoc->InsertTab(2, "Sheet3");
2268 1 : m_pDoc->InsertTab(3, "Sheet4");
2269 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("We should have 4 sheet instances.", m_pDoc->GetTableCount(), static_cast<SCTAB>(4));
2270 :
2271 1 : OUString a1("A1");
2272 2 : OUString a2("A2");
2273 2 : OUString test;
2274 :
2275 : // Put values into Sheet1.
2276 1 : m_pDoc->SetString(0, 0, 0, a1);
2277 1 : m_pDoc->SetString(0, 1, 0, a2);
2278 1 : test = m_pDoc->GetString(0, 0, 0);
2279 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A1", test.equals(a1));
2280 1 : test = m_pDoc->GetString(0, 1, 0);
2281 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet1.A2", test.equals(a2));
2282 :
2283 : // Put formulas into Sheet2 to Sheet4 to reference values from Sheet1.
2284 1 : m_pDoc->SetString(0, 0, 1, "=Sheet1.A1");
2285 1 : m_pDoc->SetString(0, 1, 1, "=Sheet1.A2");
2286 1 : m_pDoc->SetString(0, 0, 2, "=Sheet1.A1");
2287 1 : m_pDoc->SetString(0, 0, 3, "=Sheet1.A2");
2288 :
2289 1 : test = m_pDoc->GetString(0, 0, 1);
2290 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A1", test.equals(a1));
2291 1 : test = m_pDoc->GetString(0, 1, 1);
2292 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet2.A2", test.equals(a2));
2293 1 : test = m_pDoc->GetString(0, 0, 2);
2294 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a1));
2295 1 : test = m_pDoc->GetString(0, 0, 3);
2296 1 : CPPUNIT_ASSERT_MESSAGE("Unexpected value in Sheet3.A1", test.equals(a2));
2297 :
2298 : // Set all sheet streams valid after all the initial cell values are in
2299 : // place. In reality we need to have real XML streams stored in order to
2300 : // claim they are valid, but we are just testing the flag values here.
2301 1 : m_pDoc->SetStreamValid(0, true);
2302 1 : m_pDoc->SetStreamValid(1, true);
2303 1 : m_pDoc->SetStreamValid(2, true);
2304 1 : m_pDoc->SetStreamValid(3, true);
2305 1 : CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(0));
2306 1 : CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(1));
2307 1 : CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(2));
2308 1 : CPPUNIT_ASSERT_MESSAGE("Stream is expected to be valid.", m_pDoc->IsStreamValid(3));
2309 :
2310 : // Now, insert a new row at row 2 position on Sheet1. This will move cell
2311 : // A2 downward but cell A1 remains unmoved.
2312 1 : m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 2);
2313 1 : test = m_pDoc->GetString(0, 0, 0);
2314 1 : CPPUNIT_ASSERT_MESSAGE("Cell A1 should not have moved.", test.equals(a1));
2315 1 : test = m_pDoc->GetString(0, 3, 0);
2316 1 : CPPUNIT_ASSERT_MESSAGE("the old cell A2 should now be at A4.", test.equals(a2));
2317 2 : ScRefCellValue aCell;
2318 1 : aCell.assign(*m_pDoc, ScAddress(0,1,0));
2319 1 : CPPUNIT_ASSERT_MESSAGE("Cell A2 should be empty.", aCell.isEmpty());
2320 1 : aCell.assign(*m_pDoc, ScAddress(0,2,0));
2321 1 : CPPUNIT_ASSERT_MESSAGE("Cell A3 should be empty.", aCell.isEmpty());
2322 :
2323 : // After the move, Sheet1, Sheet2, and Sheet4 should have their stream
2324 : // invalidated, whereas Sheet3's stream should still be valid.
2325 1 : CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(0));
2326 1 : CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(1));
2327 1 : CPPUNIT_ASSERT_MESSAGE("Stream should have been invalidated.", !m_pDoc->IsStreamValid(3));
2328 1 : CPPUNIT_ASSERT_MESSAGE("Stream should still be valid.", m_pDoc->IsStreamValid(2));
2329 :
2330 1 : m_pDoc->DeleteTab(3);
2331 1 : m_pDoc->DeleteTab(2);
2332 1 : m_pDoc->DeleteTab(1);
2333 2 : m_pDoc->DeleteTab(0);
2334 1 : }
2335 :
2336 1 : void Test::testFunctionLists()
2337 : {
2338 : const char* aDataBase[] = {
2339 : "DAVERAGE",
2340 : "DCOUNT",
2341 : "DCOUNTA",
2342 : "DGET",
2343 : "DMAX",
2344 : "DMIN",
2345 : "DPRODUCT",
2346 : "DSTDEV",
2347 : "DSTDEVP",
2348 : "DSUM",
2349 : "DVAR",
2350 : "DVARP",
2351 : 0
2352 1 : };
2353 :
2354 : const char* aDateTime[] = {
2355 : "DATE",
2356 : "DATEDIF",
2357 : "DATEVALUE",
2358 : "DAY",
2359 : "DAYS",
2360 : "DAYS360",
2361 : "DAYSINMONTH",
2362 : "DAYSINYEAR",
2363 : "EASTERSUNDAY",
2364 : "HOUR",
2365 : "ISLEAPYEAR",
2366 : "MINUTE",
2367 : "MONTH",
2368 : "MONTHS",
2369 : "NETWORKDAYS",
2370 : "NETWORKDAYS.INTL",
2371 : "NOW",
2372 : "SECOND",
2373 : "TIME",
2374 : "TIMEVALUE",
2375 : "TODAY",
2376 : "WEEKDAY",
2377 : "WEEKNUM",
2378 : "WEEKS",
2379 : "WEEKSINYEAR",
2380 : "WORKDAY.INTL",
2381 : "YEAR",
2382 : "YEARS",
2383 : 0
2384 1 : };
2385 :
2386 : const char* aFinancial[] = {
2387 : "CUMIPMT",
2388 : "CUMPRINC",
2389 : "DB",
2390 : "DDB",
2391 : "DURATION",
2392 : "EFFECTIVE",
2393 : "FV",
2394 : "IPMT",
2395 : "IRR",
2396 : "ISPMT",
2397 : "MIRR",
2398 : "NOMINAL",
2399 : "NPER",
2400 : "NPV",
2401 : "OPT_BARRIER",
2402 : "OPT_PROB_HIT",
2403 : "OPT_PROB_INMONEY",
2404 : "OPT_TOUCH",
2405 : "PMT",
2406 : "PPMT",
2407 : "PV",
2408 : "RATE",
2409 : "RRI",
2410 : "SLN",
2411 : "SYD",
2412 : "VDB",
2413 : 0
2414 1 : };
2415 :
2416 : const char* aInformation[] = {
2417 : "CELL",
2418 : "CURRENT",
2419 : "FORMULA",
2420 : "INFO",
2421 : "ISBLANK",
2422 : "ISERR",
2423 : "ISERROR",
2424 : "ISEVEN",
2425 : "ISFORMULA",
2426 : "ISLOGICAL",
2427 : "ISNA",
2428 : "ISNONTEXT",
2429 : "ISNUMBER",
2430 : "ISODD",
2431 : "ISREF",
2432 : "ISTEXT",
2433 : "N",
2434 : "NA",
2435 : "TYPE",
2436 : 0
2437 1 : };
2438 :
2439 : const char* aLogical[] = {
2440 : "AND",
2441 : "FALSE",
2442 : "IF",
2443 : "IFERROR",
2444 : "IFNA",
2445 : "NOT",
2446 : "OR",
2447 : "TRUE",
2448 : "XOR",
2449 : 0
2450 1 : };
2451 :
2452 : const char* aMathematical[] = {
2453 : "ABS",
2454 : "ACOS",
2455 : "ACOSH",
2456 : "ACOT",
2457 : "ACOTH",
2458 : "AGGREGATE",
2459 : "ASIN",
2460 : "ASINH",
2461 : "ATAN",
2462 : "ATAN2",
2463 : "ATANH",
2464 : "BITAND",
2465 : "BITLSHIFT",
2466 : "BITOR",
2467 : "BITRSHIFT",
2468 : "BITXOR",
2469 : "CEILING",
2470 : "CEILING.MATH",
2471 : "CEILING.PRECISE",
2472 : "CEILING.XCL",
2473 : "COLOR",
2474 : "COMBIN",
2475 : "COMBINA",
2476 : "CONVERT",
2477 : "COS",
2478 : "COSH",
2479 : "COT",
2480 : "COTH",
2481 : "CSC",
2482 : "CSCH",
2483 : "DEGREES",
2484 : "EUROCONVERT",
2485 : "EVEN",
2486 : "EXP",
2487 : "FACT",
2488 : "FLOOR",
2489 : "FLOOR.PRECISE",
2490 : "GCD",
2491 : "INT",
2492 : "ISO.CEILING",
2493 : "LCM",
2494 : "LN",
2495 : "LOG",
2496 : "LOG10",
2497 : "MOD",
2498 : "ODD",
2499 : "PI",
2500 : "POWER",
2501 : "PRODUCT",
2502 : "RADIANS",
2503 : "RAND",
2504 : "ROUND",
2505 : "ROUNDDOWN",
2506 : "ROUNDUP",
2507 : "SEC",
2508 : "SECH",
2509 : "SIGN",
2510 : "SIN",
2511 : "SINH",
2512 : "SQRT",
2513 : "SUBTOTAL",
2514 : "SUM",
2515 : "SUMIF",
2516 : "SUMIFS",
2517 : "SUMSQ",
2518 : "TAN",
2519 : "TANH",
2520 : "TRUNC",
2521 : 0
2522 1 : };
2523 :
2524 : const char* aArray[] = {
2525 : "FREQUENCY",
2526 : "GROWTH",
2527 : "LINEST",
2528 : "LOGEST",
2529 : "MDETERM",
2530 : "MINVERSE",
2531 : "MMULT",
2532 : "MUNIT",
2533 : "SUMPRODUCT",
2534 : "SUMX2MY2",
2535 : "SUMX2PY2",
2536 : "SUMXMY2",
2537 : "TRANSPOSE",
2538 : "TREND",
2539 : 0
2540 1 : };
2541 :
2542 : const char* aStatistical[] = {
2543 : "AVEDEV",
2544 : "AVERAGE",
2545 : "AVERAGEA",
2546 : "AVERAGEIF",
2547 : "AVERAGEIFS",
2548 : "B",
2549 : "BETA.DIST",
2550 : "BETA.INV",
2551 : "BETADIST",
2552 : "BETAINV",
2553 : "BINOM.DIST",
2554 : "BINOM.INV",
2555 : "BINOMDIST",
2556 : "CHIDIST",
2557 : "CHIINV",
2558 : "CHISQ.DIST",
2559 : "CHISQ.DIST.RT",
2560 : "CHISQ.INV",
2561 : "CHISQ.INV.RT",
2562 : "CHISQ.TEST",
2563 : "CHISQDIST",
2564 : "CHISQINV",
2565 : "CHITEST",
2566 : "CONFIDENCE",
2567 : "CONFIDENCE.NORM",
2568 : "CONFIDENCE.T",
2569 : "CORREL",
2570 : "COUNT",
2571 : "COUNTA",
2572 : "COUNTBLANK",
2573 : "COUNTIF",
2574 : "COUNTIFS",
2575 : "COVAR",
2576 : "COVARIANCE.P",
2577 : "COVARIANCE.S",
2578 : "CRITBINOM",
2579 : "DEVSQ",
2580 : "ERF.PRECISE",
2581 : "ERFC.PRECISE",
2582 : "EXPON.DIST",
2583 : "EXPONDIST",
2584 : "F.DIST",
2585 : "F.DIST.RT",
2586 : "F.INV",
2587 : "F.INV.RT",
2588 : "F.TEST",
2589 : "FDIST",
2590 : "FINV",
2591 : "FISHER",
2592 : "FISHERINV",
2593 : "FORECAST",
2594 : "FTEST",
2595 : "GAMMA",
2596 : "GAMMA.DIST",
2597 : "GAMMA.INV",
2598 : "GAMMADIST",
2599 : "GAMMAINV",
2600 : "GAMMALN",
2601 : "GAMMALN.PRECISE",
2602 : "GAUSS",
2603 : "GEOMEAN",
2604 : "HARMEAN",
2605 : "HYPGEOM.DIST",
2606 : "HYPGEOMDIST",
2607 : "INTERCEPT",
2608 : "KURT",
2609 : "LARGE",
2610 : "LOGINV",
2611 : "LOGNORM.DIST",
2612 : "LOGNORM.INV",
2613 : "LOGNORMDIST",
2614 : "MAX",
2615 : "MAXA",
2616 : "MEDIAN",
2617 : "MIN",
2618 : "MINA",
2619 : "MODE",
2620 : "MODE.MULT",
2621 : "MODE.SNGL",
2622 : "NEGBINOM.DIST",
2623 : "NEGBINOMDIST",
2624 : "NORM.DIST",
2625 : "NORM.INV",
2626 : "NORM.S.DIST",
2627 : "NORM.S.INV",
2628 : "NORMDIST",
2629 : "NORMINV",
2630 : "NORMSDIST",
2631 : "NORMSINV",
2632 : "PEARSON",
2633 : "PERCENTILE",
2634 : "PERCENTILE.EXC",
2635 : "PERCENTILE.INC",
2636 : "PERCENTRANK",
2637 : "PERCENTRANK.EXC",
2638 : "PERCENTRANK.INC",
2639 : "PERMUT",
2640 : "PERMUTATIONA",
2641 : "PHI",
2642 : "POISSON",
2643 : "POISSON.DIST",
2644 : "PROB",
2645 : "QUARTILE",
2646 : "QUARTILE.EXC",
2647 : "QUARTILE.INC",
2648 : "RANK",
2649 : "RANK.AVG",
2650 : "RANK.EQ",
2651 : "RSQ",
2652 : "SKEW",
2653 : "SKEWP",
2654 : "SLOPE",
2655 : "SMALL",
2656 : "STANDARDIZE",
2657 : "STDEV",
2658 : "STDEV.P",
2659 : "STDEV.S",
2660 : "STDEVA",
2661 : "STDEVP",
2662 : "STDEVPA",
2663 : "STEYX",
2664 : "T.DIST",
2665 : "T.DIST.2T",
2666 : "T.DIST.RT",
2667 : "T.INV",
2668 : "T.INV.2T",
2669 : "T.TEST",
2670 : "TDIST",
2671 : "TINV",
2672 : "TRIMMEAN",
2673 : "TTEST",
2674 : "VAR",
2675 : "VAR.P",
2676 : "VAR.S",
2677 : "VARA",
2678 : "VARP",
2679 : "VARPA",
2680 : "WEIBULL",
2681 : "WEIBULL.DIST",
2682 : "Z.TEST",
2683 : "ZTEST",
2684 : 0
2685 1 : };
2686 :
2687 : const char* aSpreadsheet[] = {
2688 : "ADDRESS",
2689 : "AREAS",
2690 : "CHOOSE",
2691 : "COLUMN",
2692 : "COLUMNS",
2693 : "DDE",
2694 : "ERROR.TYPE",
2695 : "ERRORTYPE",
2696 : "GETPIVOTDATA",
2697 : "HLOOKUP",
2698 : "HYPERLINK",
2699 : "INDEX",
2700 : "INDIRECT",
2701 : "LOOKUP",
2702 : "MATCH",
2703 : "OFFSET",
2704 : "ROW",
2705 : "ROWS",
2706 : "SHEET",
2707 : "SHEETS",
2708 : "STYLE",
2709 : "VLOOKUP",
2710 : 0
2711 1 : };
2712 :
2713 : const char* aText[] = {
2714 : "ARABIC",
2715 : "ASC",
2716 : "BAHTTEXT",
2717 : "BASE",
2718 : "CHAR",
2719 : "CLEAN",
2720 : "CODE",
2721 : "CONCATENATE",
2722 : "DECIMAL",
2723 : "DOLLAR",
2724 : "ENCODEURL",
2725 : "EXACT",
2726 : "FILTERXML",
2727 : "FIND",
2728 : "FIXED",
2729 : "JIS",
2730 : "LEFT",
2731 : "LEFTB",
2732 : "LEN",
2733 : "LENB",
2734 : "LOWER",
2735 : "MID",
2736 : "MIDB",
2737 : "NUMBERVALUE",
2738 : "PROPER",
2739 : "REPLACE",
2740 : "REPT",
2741 : "RIGHT",
2742 : "RIGHTB",
2743 : "ROMAN",
2744 : "ROT13",
2745 : "SEARCH",
2746 : "SUBSTITUTE",
2747 : "T",
2748 : "TEXT",
2749 : "TRIM",
2750 : "UNICHAR",
2751 : "UNICODE",
2752 : "UPPER",
2753 : "VALUE",
2754 : "WEBSERVICE",
2755 : 0
2756 1 : };
2757 :
2758 : struct {
2759 : const char* Category; const char** Functions;
2760 : } aTests[] = {
2761 : { "Database", aDataBase },
2762 : { "Date&Time", aDateTime },
2763 : { "Financial", aFinancial },
2764 : { "Information", aInformation },
2765 : { "Logical", aLogical },
2766 : { "Mathematical", aMathematical },
2767 : { "Array", aArray },
2768 : { "Statistical", aStatistical },
2769 : { "Spreadsheet", aSpreadsheet },
2770 : { "Text", aText },
2771 : { "Add-in", 0 },
2772 : { 0, 0 }
2773 1 : };
2774 :
2775 1 : ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
2776 1 : sal_uInt32 n = pFuncMgr->getCount();
2777 12 : for (sal_uInt32 i = 0; i < n; ++i)
2778 : {
2779 11 : const formula::IFunctionCategory* pCat = pFuncMgr->getCategory(i);
2780 11 : CPPUNIT_ASSERT_MESSAGE("Unexpected category name", pCat->getName().equalsAscii(aTests[i].Category));
2781 11 : sal_uInt32 nFuncCount = pCat->getCount();
2782 391 : for (sal_uInt32 j = 0; j < nFuncCount; ++j)
2783 : {
2784 380 : const formula::IFunctionDescription* pFunc = pCat->getFunction(j);
2785 380 : CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected function name", OUString::createFromAscii(aTests[i].Functions[j]), pFunc->getFunctionName());
2786 : }
2787 : }
2788 1 : }
2789 :
2790 1 : void Test::testGraphicsInGroup()
2791 : {
2792 1 : m_pDoc->InsertTab(0, "TestTab");
2793 1 : CPPUNIT_ASSERT_MESSAGE("document should have one sheet to begin with.", m_pDoc->GetTableCount() == 1);
2794 : SCROW nRow1, nRow2;
2795 1 : bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
2796 1 : CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
2797 :
2798 1 : m_pDoc->InitDrawLayer();
2799 1 : ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
2800 1 : CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
2801 1 : SdrPage* pPage = pDrawLayer->GetPage(0);
2802 1 : CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
2803 :
2804 : {
2805 : //Add a square
2806 1 : Rectangle aOrigRect(2,2,100,100);
2807 1 : SdrRectObj *pObj = new SdrRectObj(aOrigRect);
2808 1 : pPage->InsertObject(pObj);
2809 1 : const Rectangle &rNewRect = pObj->GetLogicRect();
2810 1 : CPPUNIT_ASSERT_MESSAGE("must have equal position and size", aOrigRect == rNewRect);
2811 :
2812 1 : ScDrawLayer::SetPageAnchored(*pObj);
2813 :
2814 : //Use a range of rows guaranteed to include all of the square
2815 1 : m_pDoc->ShowRows(0, 100, 0, false);
2816 1 : m_pDoc->SetDrawPageSize(0);
2817 1 : CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2818 1 : m_pDoc->ShowRows(0, 100, 0, true);
2819 1 : m_pDoc->SetDrawPageSize(0);
2820 1 : CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2821 :
2822 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2823 1 : CPPUNIT_ASSERT_MESSAGE("That shouldn't change size or positioning", aOrigRect == rNewRect);
2824 :
2825 1 : m_pDoc->ShowRows(0, 100, 0, false);
2826 1 : m_pDoc->SetDrawPageSize(0);
2827 2 : CPPUNIT_ASSERT_MESSAGE("Left and Right should be unchanged",
2828 1 : aOrigRect.Left() == rNewRect.Left() && aOrigRect.Right() == rNewRect.Right());
2829 2 : CPPUNIT_ASSERT_MESSAGE("Height should be minimum allowed height",
2830 1 : (rNewRect.Bottom() - rNewRect.Top()) <= 1);
2831 1 : m_pDoc->ShowRows(0, 100, 0, true);
2832 1 : m_pDoc->SetDrawPageSize(0);
2833 1 : CPPUNIT_ASSERT_MESSAGE("Should not change when page anchored", aOrigRect == rNewRect);
2834 : }
2835 :
2836 : {
2837 : // Add a circle.
2838 1 : Rectangle aOrigRect = Rectangle(10,10,210,210); // 200 x 200
2839 1 : SdrCircObj* pObj = new SdrCircObj(OBJ_CIRC, aOrigRect);
2840 1 : pPage->InsertObject(pObj);
2841 1 : const Rectangle& rNewRect = pObj->GetLogicRect();
2842 2 : CPPUNIT_ASSERT_MESSAGE("Position and size of the circle shouldn't change when inserted into the page.",
2843 1 : aOrigRect == rNewRect);
2844 :
2845 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2846 2 : CPPUNIT_ASSERT_MESSAGE("Size changed when cell anchored. Not good.",
2847 1 : aOrigRect == rNewRect);
2848 :
2849 : // Insert 2 rows at the top. This should push the circle object down.
2850 1 : m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
2851 1 : m_pDoc->SetDrawPageSize(0);
2852 :
2853 : // Make sure the size of the circle is still identical.
2854 2 : CPPUNIT_ASSERT_MESSAGE("Size of the circle has changed, but shouldn't!",
2855 1 : aOrigRect.GetSize() == rNewRect.GetSize());
2856 :
2857 : // Delete 2 rows at the top. This should bring the circle object to its original position.
2858 1 : m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
2859 1 : m_pDoc->SetDrawPageSize(0);
2860 1 : CPPUNIT_ASSERT_MESSAGE("Failed to move back to its original position.", aOrigRect == rNewRect);
2861 : }
2862 :
2863 : {
2864 : // Add a line.
2865 1 : basegfx::B2DPolygon aTempPoly;
2866 1 : Point aStartPos(10,300), aEndPos(110,200); // bottom-left to top-right.
2867 1 : Rectangle aOrigRect(10,200,110,300); // 100 x 100
2868 1 : aTempPoly.append(basegfx::B2DPoint(aStartPos.X(), aStartPos.Y()));
2869 1 : aTempPoly.append(basegfx::B2DPoint(aEndPos.X(), aEndPos.Y()));
2870 1 : SdrPathObj* pObj = new SdrPathObj(OBJ_LINE, basegfx::B2DPolyPolygon(aTempPoly));
2871 1 : pObj->NbcSetLogicRect(aOrigRect);
2872 1 : pPage->InsertObject(pObj);
2873 1 : const Rectangle& rNewRect = pObj->GetLogicRect();
2874 1 : CPPUNIT_ASSERT_MESSAGE("Size differ.", aOrigRect == rNewRect);
2875 :
2876 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2877 2 : CPPUNIT_ASSERT_MESSAGE("Size changed when cell-anchored. Not good.",
2878 1 : aOrigRect == rNewRect);
2879 :
2880 : // Insert 2 rows at the top and delete them immediately.
2881 1 : m_pDoc->InsertRow(0, 0, MAXCOL, 0, 0, 2);
2882 1 : m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 2);
2883 1 : m_pDoc->SetDrawPageSize(0);
2884 2 : CPPUNIT_ASSERT_MESSAGE("Size of a line object changed after row insertion and removal.",
2885 1 : aOrigRect == rNewRect);
2886 :
2887 1 : sal_Int32 n = pObj->GetPointCount();
2888 1 : CPPUNIT_ASSERT_MESSAGE("There should be exactly 2 points in a line object.", n == 2);
2889 2 : CPPUNIT_ASSERT_MESSAGE("Line shape has changed.",
2890 2 : aStartPos == pObj->GetPoint(0) && aEndPos == pObj->GetPoint(1));
2891 : }
2892 :
2893 1 : m_pDoc->DeleteTab(0);
2894 1 : }
2895 :
2896 1 : void Test::testGraphicsOnSheetMove()
2897 : {
2898 1 : m_pDoc->InsertTab(0, "Tab1");
2899 1 : m_pDoc->InsertTab(1, "Tab2");
2900 1 : CPPUNIT_ASSERT_MESSAGE("There should be only 2 sheets to begin with", m_pDoc->GetTableCount() == 2);
2901 :
2902 1 : m_pDoc->InitDrawLayer();
2903 1 : ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer();
2904 1 : CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
2905 1 : SdrPage* pPage = pDrawLayer->GetPage(0);
2906 1 : CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
2907 :
2908 : // Insert an object.
2909 1 : Rectangle aObjRect(2,2,100,100);
2910 1 : SdrObject* pObj = new SdrRectObj(aObjRect);
2911 1 : pPage->InsertObject(pObj);
2912 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
2913 :
2914 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be one object on the 1st sheet.", pPage->GetObjCount(), static_cast<size_t>(1));
2915 :
2916 1 : const ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj);
2917 1 : CPPUNIT_ASSERT_MESSAGE("Object meta-data doesn't exist.", pData);
2918 1 : CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
2919 :
2920 1 : pPage = pDrawLayer->GetPage(1);
2921 1 : CPPUNIT_ASSERT_MESSAGE("No page instance for the 2nd sheet.", pPage);
2922 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("2nd sheet shouldn't have any object.", pPage->GetObjCount(), static_cast<size_t>(0));
2923 :
2924 : // Insert a new sheet at left-end, and make sure the object has moved to
2925 : // the 2nd page.
2926 1 : m_pDoc->InsertTab(0, "NewTab");
2927 1 : CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 3 sheets.", m_pDoc->GetTableCount(), static_cast<SCTAB>(3));
2928 1 : pPage = pDrawLayer->GetPage(0);
2929 1 : CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2930 1 : pPage = pDrawLayer->GetPage(1);
2931 1 : CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2932 1 : pPage = pDrawLayer->GetPage(2);
2933 1 : CPPUNIT_ASSERT_MESSAGE("3rd sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2934 :
2935 1 : CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
2936 :
2937 : // Now, delete the sheet that just got inserted. The object should be back
2938 : // on the 1st sheet.
2939 1 : m_pDoc->DeleteTab(0);
2940 1 : pPage = pDrawLayer->GetPage(0);
2941 1 : CPPUNIT_ASSERT_MESSAGE("1st sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2942 2 : CPPUNIT_ASSERT_MESSAGE("Size and position of the object shouldn't change.",
2943 1 : pObj->GetLogicRect() == aObjRect);
2944 :
2945 1 : CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 0 && pData->maEnd.Tab() == 0);
2946 :
2947 : // Move the 1st sheet to the last position.
2948 1 : m_pDoc->MoveTab(0, 1);
2949 1 : pPage = pDrawLayer->GetPage(0);
2950 1 : CPPUNIT_ASSERT_MESSAGE("1st sheet should have no object.", pPage && pPage->GetObjCount() == 0);
2951 1 : pPage = pDrawLayer->GetPage(1);
2952 1 : CPPUNIT_ASSERT_MESSAGE("2nd sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2953 1 : CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 1 && pData->maEnd.Tab() == 1);
2954 :
2955 : // Copy the 2nd sheet, which has one drawing object to the last position.
2956 1 : m_pDoc->CopyTab(1, 2);
2957 1 : pPage = pDrawLayer->GetPage(2);
2958 1 : CPPUNIT_ASSERT_MESSAGE("Copied sheet should have one object.", pPage && pPage->GetObjCount() == 1);
2959 1 : pObj = pPage->GetObj(0);
2960 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj);
2961 1 : pData = ScDrawLayer::GetObjData(pObj);
2962 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
2963 1 : CPPUNIT_ASSERT_MESSAGE("Wrong sheet ID in cell anchor data!", pData->maStart.Tab() == 2 && pData->maEnd.Tab() == 2);
2964 :
2965 1 : m_pDoc->DeleteTab(2);
2966 1 : m_pDoc->DeleteTab(1);
2967 1 : m_pDoc->DeleteTab(0);
2968 1 : }
2969 :
2970 1 : void Test::testToggleRefFlag()
2971 : {
2972 : // In this test, there is no need to insert formula string into a cell in
2973 : // the document, as ScRefFinder does not depend on the content of the
2974 : // document except for the sheet names.
2975 :
2976 1 : m_pDoc->InsertTab(0, "Test");
2977 :
2978 : {
2979 : // Calc A1: basic 2D reference
2980 :
2981 1 : OUString aFormula("=B100");
2982 1 : ScAddress aPos(1, 5, 0);
2983 2 : ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
2984 :
2985 : // Original
2986 1 : CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
2987 :
2988 : // column relative / row relative -> column absolute / row absolute
2989 1 : aFinder.ToggleRel(0, aFormula.getLength());
2990 1 : aFormula = aFinder.GetText();
2991 1 : CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B$100" );
2992 :
2993 : // column absolute / row absolute -> column relative / row absolute
2994 1 : aFinder.ToggleRel(0, aFormula.getLength());
2995 1 : aFormula = aFinder.GetText();
2996 1 : CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B$100" );
2997 :
2998 : // column relative / row absolute -> column absolute / row relative
2999 1 : aFinder.ToggleRel(0, aFormula.getLength());
3000 1 : aFormula = aFinder.GetText();
3001 1 : CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=$B100" );
3002 :
3003 : // column absolute / row relative -> column relative / row relative
3004 1 : aFinder.ToggleRel(0, aFormula.getLength());
3005 1 : aFormula = aFinder.GetText();
3006 2 : CPPUNIT_ASSERT_MESSAGE( "Wrong conversion.", aFormula == "=B100" );
3007 : }
3008 :
3009 : {
3010 : // Excel R1C1: basic 2D reference
3011 :
3012 1 : OUString aFormula("=R2C1");
3013 1 : ScAddress aPos(3, 5, 0);
3014 2 : ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
3015 :
3016 : // Original
3017 1 : CPPUNIT_ASSERT_MESSAGE("Does not equal the original text.", aFormula.equals(aFinder.GetText()));
3018 :
3019 : // column absolute / row absolute -> column relative / row absolute
3020 1 : aFinder.ToggleRel(0, aFormula.getLength());
3021 1 : aFormula = aFinder.GetText();
3022 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R2C[-3]"), aFormula);
3023 :
3024 : // column relative / row absolute - > column absolute / row relative
3025 1 : aFinder.ToggleRel(0, aFormula.getLength());
3026 1 : aFormula = aFinder.GetText();
3027 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C1"), aFormula);
3028 :
3029 : // column absolute / row relative -> column relative / row relative
3030 1 : aFinder.ToggleRel(0, aFormula.getLength());
3031 1 : aFormula = aFinder.GetText();
3032 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R[-4]C[-3]"), aFormula);
3033 :
3034 : // column relative / row relative -> column absolute / row absolute
3035 1 : aFinder.ToggleRel(0, aFormula.getLength());
3036 1 : aFormula = aFinder.GetText();
3037 2 : CPPUNIT_ASSERT_EQUAL(OUString("=R2C1"), aFormula);
3038 : }
3039 :
3040 : {
3041 : // Excel R1C1: Selection at the end of the formula string and does not
3042 : // overlap the formula string at all (inspired by fdo#39135).
3043 1 : OUString aFormula("=R1C1");
3044 1 : ScAddress aPos(1, 1, 0);
3045 2 : ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_XL_R1C1);
3046 :
3047 : // Original
3048 1 : CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
3049 :
3050 : // Make the column relative.
3051 1 : sal_Int32 n = aFormula.getLength();
3052 1 : aFinder.ToggleRel(n, n);
3053 1 : aFormula = aFinder.GetText();
3054 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R1C[-1]"), aFormula);
3055 :
3056 : // Make the row relative.
3057 1 : n = aFormula.getLength();
3058 1 : aFinder.ToggleRel(n, n);
3059 1 : aFormula = aFinder.GetText();
3060 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C1"), aFormula);
3061 :
3062 : // Make both relative.
3063 1 : n = aFormula.getLength();
3064 1 : aFinder.ToggleRel(n, n);
3065 1 : aFormula = aFinder.GetText();
3066 1 : CPPUNIT_ASSERT_EQUAL(OUString("=R[-1]C[-1]"), aFormula);
3067 :
3068 : // Back to the original.
3069 1 : n = aFormula.getLength();
3070 1 : aFinder.ToggleRel(n, n);
3071 1 : aFormula = aFinder.GetText();
3072 2 : CPPUNIT_ASSERT_EQUAL(OUString("=R1C1"), aFormula);
3073 : }
3074 :
3075 : {
3076 : // Calc A1:
3077 1 : OUString aFormula("=A1+4");
3078 1 : ScAddress aPos(1, 1, 0);
3079 2 : ScRefFinder aFinder(aFormula, aPos, m_pDoc, formula::FormulaGrammar::CONV_OOO);
3080 :
3081 : // Original
3082 1 : CPPUNIT_ASSERT_EQUAL(aFormula, aFinder.GetText());
3083 :
3084 : // Set the cursor over the 'A1' part and toggle.
3085 1 : aFinder.ToggleRel(2, 2);
3086 1 : aFormula = aFinder.GetText();
3087 1 : CPPUNIT_ASSERT_EQUAL(OUString("=$A$1+4"), aFormula);
3088 :
3089 1 : aFinder.ToggleRel(2, 2);
3090 1 : aFormula = aFinder.GetText();
3091 1 : CPPUNIT_ASSERT_EQUAL(OUString("=A$1+4"), aFormula);
3092 :
3093 1 : aFinder.ToggleRel(2, 2);
3094 1 : aFormula = aFinder.GetText();
3095 1 : CPPUNIT_ASSERT_EQUAL(OUString("=$A1+4"), aFormula);
3096 :
3097 1 : aFinder.ToggleRel(2, 2);
3098 1 : aFormula = aFinder.GetText();
3099 2 : CPPUNIT_ASSERT_EQUAL(OUString("=A1+4"), aFormula);
3100 : }
3101 :
3102 : // TODO: Add more test cases esp. for 3D references, Excel A1 syntax, and
3103 : // partial selection within formula string.
3104 :
3105 1 : m_pDoc->DeleteTab(0);
3106 1 : }
3107 :
3108 1 : void Test::testAutofilter()
3109 : {
3110 1 : OUString aDBName("NONAME");
3111 :
3112 1 : m_pDoc->InsertTab( 0, "Test" );
3113 :
3114 : // cell contents (0 = empty cell)
3115 : const char* aData[][3] = {
3116 : { "C1", "C2", "C3" },
3117 : { "0", "1", "A" },
3118 : { "1", "2", 0 },
3119 : { "1", "2", "B" },
3120 : { "0", "2", "B" }
3121 1 : };
3122 :
3123 1 : SCCOL nCols = SAL_N_ELEMENTS(aData[0]);
3124 1 : SCROW nRows = SAL_N_ELEMENTS(aData);
3125 :
3126 : // Populate cells.
3127 6 : for (SCROW i = 0; i < nRows; ++i)
3128 20 : for (SCCOL j = 0; j < nCols; ++j)
3129 15 : if (aData[i][j])
3130 14 : m_pDoc->SetString(j, i, 0, OUString::createFromAscii(aData[i][j]));
3131 :
3132 1 : ScDBData* pDBData = new ScDBData(aDBName, 0, 0, 0, nCols-1, nRows-1);
3133 1 : m_pDoc->SetAnonymousDBData(0,pDBData);
3134 :
3135 1 : pDBData->SetAutoFilter(true);
3136 1 : ScRange aRange;
3137 1 : pDBData->GetArea(aRange);
3138 1 : m_pDoc->ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
3139 1 : aRange.aEnd.Col(), aRange.aStart.Row(),
3140 3 : aRange.aStart.Tab(), SC_MF_AUTO);
3141 :
3142 : //create the query param
3143 2 : ScQueryParam aParam;
3144 1 : pDBData->GetQueryParam(aParam);
3145 1 : ScQueryEntry& rEntry = aParam.GetEntry(0);
3146 1 : rEntry.bDoQuery = true;
3147 1 : rEntry.nField = 0;
3148 1 : rEntry.eOp = SC_EQUAL;
3149 1 : rEntry.GetQueryItem().mfVal = 0;
3150 : // add queryParam to database range.
3151 1 : pDBData->SetQueryParam(aParam);
3152 :
3153 : // perform the query.
3154 1 : m_pDoc->Query(0, aParam, true);
3155 :
3156 : //control output
3157 : SCROW nRow1, nRow2;
3158 1 : bool bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3159 1 : CPPUNIT_ASSERT_MESSAGE("rows 2 & 3 should be hidden", bHidden && nRow1 == 2 && nRow2 == 3);
3160 :
3161 : // Remove filtering.
3162 1 : rEntry.Clear();
3163 1 : m_pDoc->Query(0, aParam, true);
3164 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3165 1 : CPPUNIT_ASSERT_MESSAGE("All rows should be shown.", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
3166 :
3167 : // Filter for non-empty cells by column C.
3168 1 : rEntry.bDoQuery = true;
3169 1 : rEntry.nField = 2;
3170 1 : rEntry.SetQueryByNonEmpty();
3171 1 : m_pDoc->Query(0, aParam, true);
3172 :
3173 : // only row 3 should be hidden. The rest should be visible.
3174 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3175 1 : CPPUNIT_ASSERT_MESSAGE("rows 1 & 2 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 1);
3176 1 : bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3177 1 : CPPUNIT_ASSERT_MESSAGE("row 3 should be hidden.", bHidden && nRow1 == 2 && nRow2 == 2);
3178 1 : bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
3179 1 : CPPUNIT_ASSERT_MESSAGE("row 4 and down should be visible.", !bHidden && nRow1 == 3 && nRow2 == MAXROW);
3180 :
3181 : // Now, filter for empty cells by column C.
3182 1 : rEntry.SetQueryByEmpty();
3183 1 : m_pDoc->Query(0, aParam, true);
3184 :
3185 : // Now, only row 1 and 3, and 6 and down should be visible.
3186 1 : bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
3187 1 : CPPUNIT_ASSERT_MESSAGE("row 1 should be visible.", !bHidden && nRow1 == 0 && nRow2 == 0);
3188 1 : bHidden = m_pDoc->RowHidden(1, 0, &nRow1, &nRow2);
3189 1 : CPPUNIT_ASSERT_MESSAGE("row 2 should be hidden.", bHidden && nRow1 == 1 && nRow2 == 1);
3190 1 : bHidden = m_pDoc->RowHidden(2, 0, &nRow1, &nRow2);
3191 1 : CPPUNIT_ASSERT_MESSAGE("row 3 should be visible.", !bHidden && nRow1 == 2 && nRow2 == 2);
3192 1 : bHidden = m_pDoc->RowHidden(3, 0, &nRow1, &nRow2);
3193 1 : CPPUNIT_ASSERT_MESSAGE("rows 4 & 5 should be hidden.", bHidden && nRow1 == 3 && nRow2 == 4);
3194 1 : bHidden = m_pDoc->RowHidden(5, 0, &nRow1, &nRow2);
3195 1 : CPPUNIT_ASSERT_MESSAGE("rows 6 and down should be all visible.", !bHidden && nRow1 == 5 && nRow2 == MAXROW);
3196 :
3197 2 : m_pDoc->DeleteTab(0);
3198 1 : }
3199 :
3200 1 : void Test::testCopyPaste()
3201 : {
3202 1 : m_pDoc->InsertTab(0, "Sheet1");
3203 1 : m_pDoc->InsertTab(1, "Sheet2");
3204 : //test copy&paste + ScUndoPaste
3205 : //copy local and global range names in formulas
3206 : //string cells and value cells
3207 1 : m_pDoc->SetValue(0, 0, 0, 1);
3208 1 : m_pDoc->SetValue(3, 0, 0, 0);
3209 1 : m_pDoc->SetValue(3, 1, 0, 1);
3210 1 : m_pDoc->SetValue(3, 2, 0, 2);
3211 1 : m_pDoc->SetValue(3, 3, 0, 3);
3212 1 : m_pDoc->SetString(2, 0, 0, "test");
3213 1 : ScAddress aAdr (0, 0, 0);
3214 :
3215 : //create some range names, local and global
3216 1 : ScRangeData* pLocal1 = new ScRangeData(m_pDoc, OUString("local1"), aAdr);
3217 1 : ScRangeData* pLocal2 = new ScRangeData(m_pDoc, OUString("local2"), aAdr);
3218 1 : ScRangeData* pGlobal = new ScRangeData(m_pDoc, OUString("global"), aAdr);
3219 1 : ScRangeName* pGlobalRangeName = new ScRangeName();
3220 1 : pGlobalRangeName->insert(pGlobal);
3221 1 : ScRangeName* pLocalRangeName1 = new ScRangeName();
3222 1 : pLocalRangeName1->insert(pLocal1);
3223 1 : pLocalRangeName1->insert(pLocal2);
3224 1 : m_pDoc->SetRangeName(pGlobalRangeName);
3225 1 : m_pDoc->SetRangeName(0, pLocalRangeName1);
3226 :
3227 : // Add formula to B1.
3228 1 : OUString aFormulaString("=local1+global+SUM($C$1:$D$4)");
3229 1 : m_pDoc->SetString(1, 0, 0, aFormulaString);
3230 :
3231 1 : double fValue = m_pDoc->GetValue(ScAddress(1,0,0));
3232 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 8", fValue, 8);
3233 :
3234 : // add notes to A1:C1
3235 1 : ScAddress aAdrA1 (0, 0, 0); // empty cell content
3236 2 : OUString aHelloA1("Hello world in A1");
3237 1 : ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
3238 1 : pNoteA1->SetText(aAdrA1, aHelloA1);
3239 1 : ScAddress aAdrB1 (1, 0, 0); // formula cell content
3240 2 : OUString aHelloB1("Hello world in B1");
3241 1 : ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
3242 1 : pNoteB1->SetText(aAdrB1, aHelloB1);
3243 1 : ScAddress aAdrC1 (2, 0, 0); // string cell content
3244 2 : OUString aHelloC1("Hello world in C1");
3245 1 : ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
3246 1 : pNoteC1->SetText(aAdrC1, aHelloC1);
3247 :
3248 : //copy Sheet1.A1:C1 to Sheet2.A2:C2
3249 1 : ScRange aRange(0,0,0,2,0,0);
3250 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3251 1 : copyToClip(m_pDoc, aRange, &aClipDoc);
3252 :
3253 1 : aRange = ScRange(0,1,1,2,1,1);//target: Sheet2.A2:C2
3254 1 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3255 1 : pUndoDoc->InitUndo(m_pDoc, 1, 1, true, true);
3256 2 : boost::scoped_ptr<ScUndoPaste> pUndo(createUndoPaste(getDocShell(), aRange, pUndoDoc));
3257 2 : ScMarkData aMark;
3258 1 : aMark.SetMarkArea(aRange);
3259 1 : m_pDoc->CopyFromClip(aRange, aMark, IDF_ALL, NULL, &aClipDoc);
3260 :
3261 : //check values after copying
3262 2 : OUString aString;
3263 1 : fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3264 1 : m_pDoc->GetFormula(1,1,1, aString);
3265 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("copied formula should return 2", fValue, 2);
3266 1 : CPPUNIT_ASSERT_MESSAGE("formula string was not copied correctly", aString == aFormulaString);
3267 1 : fValue = m_pDoc->GetValue(ScAddress(0,1,1));
3268 1 : CPPUNIT_ASSERT_MESSAGE("copied value should be 1", fValue == 1);
3269 :
3270 : //check local range name after copying
3271 1 : pLocal1 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL1"));
3272 1 : CPPUNIT_ASSERT_MESSAGE("local range name 1 should be copied", pLocal1);
3273 1 : ScRange aRangeLocal1;
3274 1 : bool bIsValidRef = pLocal1->IsValidReference(aRangeLocal1);
3275 1 : CPPUNIT_ASSERT_MESSAGE("local range name 1 should be valid", bIsValidRef);
3276 1 : CPPUNIT_ASSERT_MESSAGE("local range 1 should still point to Sheet1.A1",aRangeLocal1 == ScRange(0,0,0,0,0,0));
3277 1 : pLocal2 = m_pDoc->GetRangeName(1)->findByUpperName(OUString("LOCAL2"));
3278 1 : CPPUNIT_ASSERT_MESSAGE("local2 should not be copied", pLocal2 == NULL);
3279 :
3280 : // check notes after copying
3281 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
3282 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
3283 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
3284 2 : CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.A1 not copied to Sheet2.A2, empty cell content",
3285 1 : m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
3286 2 : CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.B1 not copied to Sheet2.B2, formula cell content",
3287 1 : m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
3288 2 : CPPUNIT_ASSERT_MESSAGE("Note content on Sheet1.C1 not copied to Sheet2.C2, string cell content",
3289 1 : m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
3290 :
3291 : //check undo and redo
3292 1 : pUndo->Undo();
3293 1 : fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3294 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after undo formula should return nothing", fValue, 0);
3295 1 : aString = m_pDoc->GetString(2, 1, 1);
3296 1 : CPPUNIT_ASSERT_MESSAGE("after undo, string should be removed", aString.isEmpty());
3297 1 : CPPUNIT_ASSERT_MESSAGE("after undo, note on A2 should be removed", !m_pDoc->HasNote(ScAddress(0, 1, 1)));
3298 1 : CPPUNIT_ASSERT_MESSAGE("after undo, note on B2 should be removed", !m_pDoc->HasNote(ScAddress(1, 1, 1)));
3299 1 : CPPUNIT_ASSERT_MESSAGE("after undo, note on C2 should be removed", !m_pDoc->HasNote(ScAddress(2, 1, 1)));
3300 :
3301 1 : pUndo->Redo();
3302 1 : fValue = m_pDoc->GetValue(ScAddress(1,1,1));
3303 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("formula should return 2 after redo", fValue, 2);
3304 1 : aString = m_pDoc->GetString(2, 1, 1);
3305 1 : CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.C2 should contain: test", aString == "test");
3306 1 : m_pDoc->GetFormula(1,1,1, aString);
3307 1 : CPPUNIT_ASSERT_MESSAGE("Formula should be correct again", aString == aFormulaString);
3308 :
3309 1 : CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.A2", m_pDoc->HasNote(ScAddress(0, 1, 1)));
3310 1 : CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.B2", m_pDoc->HasNote(ScAddress(1, 1, 1)));
3311 1 : CPPUNIT_ASSERT_MESSAGE("After Redo, there should be a note on Sheet2.C2", m_pDoc->HasNote(ScAddress(2, 1, 1)));
3312 2 : CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.A2, empty cell content",
3313 1 : m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(0, 1, 1))->GetText());
3314 2 : CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.B2, formula cell content",
3315 1 : m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(1, 1, 1))->GetText());
3316 2 : CPPUNIT_ASSERT_MESSAGE("After Redo, note again on Sheet2.C2, string cell content",
3317 1 : m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText() == m_pDoc->GetNote(ScAddress(2, 1, 1))->GetText());
3318 :
3319 1 : m_pDoc->DeleteTab(1);
3320 2 : m_pDoc->DeleteTab(0);
3321 1 : }
3322 :
3323 1 : void Test::testCopyPasteAsLink()
3324 : {
3325 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // Turn on auto calc.
3326 :
3327 1 : m_pDoc->InsertTab(0, "Sheet1");
3328 1 : m_pDoc->InsertTab(1, "Sheet2");
3329 :
3330 1 : m_pDoc->SetValue(ScAddress(0,0,0), 1); // A1
3331 1 : m_pDoc->SetValue(ScAddress(0,1,0), 2); // A2
3332 1 : m_pDoc->SetValue(ScAddress(0,2,0), 3); // A3
3333 :
3334 1 : ScRange aRange(0,0,0,0,2,0); // Copy A1:A3 to clip.
3335 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3336 1 : copyToClip(m_pDoc, aRange, &aClipDoc);
3337 :
3338 1 : aRange = ScRange(1,1,1,1,3,1); // Paste to B2:B4 on Sheet2.
3339 2 : ScMarkData aMark;
3340 1 : aMark.SetMarkArea(aRange);
3341 : // Paste range as link.
3342 1 : m_pDoc->CopyFromClip(aRange, aMark, IDF_CONTENTS, NULL, &aClipDoc, true, true);
3343 :
3344 : // Check pasted content to make sure they reference the correct cells.
3345 1 : ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,1));
3346 1 : CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3347 1 : CPPUNIT_ASSERT_EQUAL(1.0, pFC->GetValue());
3348 :
3349 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,1));
3350 1 : CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3351 1 : CPPUNIT_ASSERT_EQUAL(2.0, pFC->GetValue());
3352 :
3353 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(1,3,1));
3354 1 : CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
3355 1 : CPPUNIT_ASSERT_EQUAL(3.0, pFC->GetValue());
3356 :
3357 1 : m_pDoc->DeleteTab(1);
3358 2 : m_pDoc->DeleteTab(0);
3359 1 : }
3360 :
3361 1 : void Test::testCopyPasteTranspose()
3362 : {
3363 1 : m_pDoc->InsertTab(0, "Sheet1");
3364 1 : m_pDoc->InsertTab(1, "Sheet2");
3365 :
3366 1 : m_pDoc->SetValue(0, 0, 0, 1);
3367 1 : m_pDoc->SetString(1, 0, 0, "=A1+1");
3368 1 : m_pDoc->SetString(2, 0, 0, "test");
3369 :
3370 : // add notes to A1:C1
3371 1 : ScAddress aAdrA1 (0, 0, 0); // numerical cell content
3372 1 : OUString aHelloA1("Hello world in A1");
3373 1 : ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAdrA1);
3374 1 : pNoteA1->SetText(aAdrA1, aHelloA1);
3375 1 : ScAddress aAdrB1 (1, 0, 0); // formula cell content
3376 2 : OUString aHelloB1("Hello world in B1");
3377 1 : ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAdrB1);
3378 1 : pNoteB1->SetText(aAdrB1, aHelloB1);
3379 1 : ScAddress aAdrC1 (2, 0, 0); // string cell content
3380 2 : OUString aHelloC1("Hello world in C1");
3381 1 : ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAdrC1);
3382 1 : pNoteC1->SetText(aAdrC1, aHelloC1);
3383 :
3384 : // transpose clipboard, paste and check on Sheet2
3385 1 : m_pDoc->InsertTab(1, "Sheet2");
3386 :
3387 1 : ScRange aSrcRange = ScRange(0,0,0,2,0,0);
3388 2 : ScDocument aNewClipDoc(SCDOCMODE_CLIP);
3389 1 : copyToClip(m_pDoc, aSrcRange, &aNewClipDoc);
3390 :
3391 2 : ::std::unique_ptr<ScDocument> pTransClip;
3392 1 : pTransClip.reset(new ScDocument(SCDOCMODE_CLIP));
3393 1 : aNewClipDoc.TransposeClip(pTransClip.get(), IDF_ALL, false);
3394 1 : ScDocument* pTransposedClip = pTransClip.release();
3395 :
3396 1 : ScRange aDestRange = ScRange(3,1,1,3,3,1);//target: Sheet2.D2:D4
3397 2 : ScMarkData aMark;
3398 1 : aMark.SetMarkArea(aDestRange);
3399 1 : m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, NULL, pTransposedClip);
3400 :
3401 : //check cell content after transposed copy/paste
3402 2 : OUString aString = m_pDoc->GetString(3, 3, 1);
3403 1 : CPPUNIT_ASSERT_MESSAGE("Cell Sheet2.D4 should contain: test", aString == "test");
3404 1 : double fValue = m_pDoc->GetValue(ScAddress(3,1,1));
3405 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied cell should return 1", fValue, 1);
3406 1 : fValue = m_pDoc->GetValue(ScAddress(3,2,1));
3407 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("transposed copied formula should return 2", fValue, 2);
3408 1 : m_pDoc->GetFormula(3, 2, 1, aString);
3409 1 : CPPUNIT_ASSERT_MESSAGE("transposed formula should point on Sheet2.D2", aString == "=D2+1");
3410 :
3411 : // check notes after transposed copy/paste
3412 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D2", m_pDoc->HasNote(ScAddress(3, 1, 1)));
3413 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D3", m_pDoc->HasNote(ScAddress(3, 2, 1)));
3414 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on Sheet2.D4", m_pDoc->HasNote(ScAddress(3, 3, 1)));
3415 2 : CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D2",
3416 1 : m_pDoc->GetNote(ScAddress(3, 1, 1))->GetText() == m_pDoc->GetNote(ScAddress(0, 0, 0))->GetText());
3417 2 : CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D3",
3418 1 : m_pDoc->GetNote(ScAddress(3, 2, 1))->GetText() == m_pDoc->GetNote(ScAddress(1, 0, 0))->GetText());
3419 2 : CPPUNIT_ASSERT_MESSAGE("Content of cell note on Sheet2.D4",
3420 1 : m_pDoc->GetNote(ScAddress(3, 3, 1))->GetText() == m_pDoc->GetNote(ScAddress(2, 0, 0))->GetText());
3421 :
3422 1 : m_pDoc->DeleteTab(1);
3423 2 : m_pDoc->DeleteTab(0);
3424 :
3425 1 : }
3426 :
3427 1 : void Test::testCopyPasteMultiRange()
3428 : {
3429 1 : m_pDoc->InsertTab(0, "Test");
3430 :
3431 : // Fill A2:B6 with numbers.
3432 6 : for (SCROW nRow = 1; nRow <= 5; ++nRow)
3433 : {
3434 15 : for (SCCOL nCol = 0; nCol <= 1; ++nCol)
3435 : {
3436 10 : ScAddress aPos(nCol,nRow,0);
3437 10 : m_pDoc->SetValue(aPos, nRow+nCol);
3438 : }
3439 : }
3440 :
3441 : // Fill D9:E11 with numbers.
3442 4 : for (SCROW nRow = 8; nRow <= 10; ++nRow)
3443 : {
3444 9 : for (SCCOL nCol = 3; nCol <= 4; ++nCol)
3445 : {
3446 6 : ScAddress aPos(nCol,nRow,0);
3447 6 : m_pDoc->SetValue(aPos, 10.0);
3448 : }
3449 : }
3450 :
3451 1 : ScMarkData aMark;
3452 1 : aMark.SelectOneTable(0);
3453 :
3454 : // Copy A2:B2, A4:B4, and A6:B6 to clipboard.
3455 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3456 2 : ScClipParam aClipParam;
3457 1 : aClipParam.maRanges.Append(ScRange(0,1,0,1,1,0)); // A2:B2
3458 1 : aClipParam.maRanges.Append(ScRange(0,3,0,1,3,0)); // A4:B4
3459 1 : aClipParam.maRanges.Append(ScRange(0,5,0,1,5,0)); // A6:B6
3460 1 : aClipParam.meDirection = ScClipParam::Row;
3461 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
3462 :
3463 : // Paste to D9:E11, and make sure it won't crash (rhbz#1080196).
3464 1 : m_pDoc->CopyMultiRangeFromClip(ScAddress(3,8,0), aMark, IDF_CONTENTS, &aClipDoc);
3465 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,8,0)));
3466 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,8,0)));
3467 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,9,0)));
3468 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(4,9,0)));
3469 1 : CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(3,10,0)));
3470 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(4,10,0)));
3471 :
3472 2 : m_pDoc->DeleteTab(0);
3473 1 : }
3474 :
3475 1 : void Test::testCopyPasteSkipEmpty()
3476 : {
3477 : struct Check
3478 : {
3479 : const char* mpStr;
3480 : Color maColor;
3481 : bool mbHasNote;
3482 : };
3483 :
3484 : struct TestRange
3485 : {
3486 : ScDocument* mpDoc;
3487 :
3488 1 : TestRange( ScDocument* pDoc ) : mpDoc(pDoc) {}
3489 :
3490 4 : bool checkRange( const ScAddress& rPos, const Check* p, const Check* pEnd )
3491 : {
3492 4 : ScAddress aPos(rPos);
3493 4 : OUString aPosStr = aPos.Format(SCA_VALID);
3494 24 : for (; p != pEnd; ++p, aPos.IncRow())
3495 : {
3496 20 : if (!mpDoc->GetString(aPos).equalsAscii(p->mpStr))
3497 : {
3498 0 : cerr << aPosStr << ": incorrect string value: expected='" << p->mpStr << "' actual='" << mpDoc->GetString(aPos) << endl;
3499 0 : return false;
3500 : }
3501 :
3502 : const SvxBrushItem* pBrush =
3503 20 : dynamic_cast<const SvxBrushItem*>(mpDoc->GetAttr(aPos, ATTR_BACKGROUND));
3504 :
3505 20 : if (!pBrush)
3506 : {
3507 0 : cerr << aPosStr << ": failed to get brush item from the cell." << endl;
3508 0 : return false;
3509 : }
3510 :
3511 20 : if (pBrush->GetColor() != p->maColor)
3512 : {
3513 0 : Color aExpected = p->maColor;
3514 0 : Color aActual = pBrush->GetColor();
3515 0 : cerr << aPosStr << ": incorrect cell background color: expected=("
3516 0 : << static_cast<int>(aExpected.GetRed()) << ","
3517 0 : << static_cast<int>(aExpected.GetGreen()) << ","
3518 0 : << static_cast<int>(aExpected.GetBlue()) << "), actual=("
3519 0 : << static_cast<int>(aActual.GetRed()) << ","
3520 0 : << static_cast<int>(aActual.GetGreen()) << ","
3521 0 : << static_cast<int>(aActual.GetBlue()) << ")" << endl;
3522 :
3523 0 : return false;
3524 : }
3525 :
3526 20 : bool bHasNote = mpDoc->HasNote(aPos);
3527 20 : if (bHasNote != p->mbHasNote)
3528 : {
3529 0 : cerr << aPosStr << ": ";
3530 0 : if (p->mbHasNote)
3531 0 : cerr << "this cell should have a cell note, but doesn't." << endl;
3532 : else
3533 0 : cerr << "this cell should NOT have a cell note, but one is found." << endl;
3534 :
3535 0 : return false;
3536 : }
3537 : }
3538 :
3539 4 : return true;
3540 : }
3541 :
3542 1 : } aTest(m_pDoc);
3543 :
3544 1 : m_pDoc->InsertTab(0, "Test");
3545 1 : m_pDoc->InitDrawLayer(&getDocShell()); // for cell note objects.
3546 :
3547 1 : ScRange aSrcRange(0,0,0,0,4,0);
3548 1 : ScRange aDestRange(1,0,0,1,4,0);
3549 :
3550 1 : ScMarkData aMark;
3551 1 : aMark.SetMarkArea(aDestRange);
3552 :
3553 : // Put some texts in B1:B5.
3554 1 : m_pDoc->SetString(ScAddress(1,0,0), "A");
3555 1 : m_pDoc->SetString(ScAddress(1,1,0), "B");
3556 1 : m_pDoc->SetString(ScAddress(1,2,0), "C");
3557 1 : m_pDoc->SetString(ScAddress(1,3,0), "D");
3558 1 : m_pDoc->SetString(ScAddress(1,4,0), "E");
3559 :
3560 : // Set the background color of B1:B5 to blue.
3561 2 : ScPatternAttr aCellBackColor(m_pDoc->GetPool());
3562 1 : aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_BLUE, ATTR_BACKGROUND));
3563 1 : m_pDoc->ApplyPatternAreaTab(1, 0, 1, 4, 0, aCellBackColor);
3564 :
3565 : // Insert notes to B1:B5.
3566 1 : m_pDoc->GetOrCreateNote(ScAddress(1,0,0));
3567 1 : m_pDoc->GetOrCreateNote(ScAddress(1,1,0));
3568 1 : m_pDoc->GetOrCreateNote(ScAddress(1,2,0));
3569 1 : m_pDoc->GetOrCreateNote(ScAddress(1,3,0));
3570 1 : m_pDoc->GetOrCreateNote(ScAddress(1,4,0));
3571 :
3572 : // Prepare a clipboard content interleaved with empty cells.
3573 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3574 1 : aClipDoc.ResetClip(m_pDoc, &aMark);
3575 2 : ScClipParam aParam(aSrcRange, false);
3576 1 : aClipDoc.SetClipParam(aParam);
3577 1 : aClipDoc.SetString(ScAddress(0,0,0), "Clip1");
3578 1 : aClipDoc.SetString(ScAddress(0,2,0), "Clip2");
3579 1 : aClipDoc.SetString(ScAddress(0,4,0), "Clip3");
3580 :
3581 : // Set the background color of A1:A5 to yellow.
3582 1 : aCellBackColor.GetItemSet().Put(SvxBrushItem(COL_YELLOW, ATTR_BACKGROUND));
3583 1 : aClipDoc.ApplyPatternAreaTab(0, 0, 0, 4, 0, aCellBackColor);
3584 :
3585 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,0,0)));
3586 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aClipDoc.GetCellType(ScAddress(0,1,0)));
3587 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,2,0)));
3588 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, aClipDoc.GetCellType(ScAddress(0,3,0)));
3589 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING, aClipDoc.GetCellType(ScAddress(0,4,0)));
3590 :
3591 : // Check the initial condition.
3592 : {
3593 : Check aChecks[] = {
3594 : { "A", COL_BLUE, true },
3595 : { "B", COL_BLUE, true },
3596 : { "C", COL_BLUE, true },
3597 : { "D", COL_BLUE, true },
3598 : { "E", COL_BLUE, true },
3599 1 : };
3600 :
3601 1 : bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3602 1 : CPPUNIT_ASSERT_MESSAGE("Initial check failed.", bRes);
3603 : }
3604 :
3605 : // Create undo document.
3606 1 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3607 1 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
3608 1 : m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pUndoDoc, &aMark);
3609 :
3610 : // Paste clipboard content onto A1:A5 but skip empty cells.
3611 1 : bool bSkipEmpty = true;
3612 1 : m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
3613 :
3614 : // Create redo document.
3615 1 : ScDocument* pRedoDoc = new ScDocument(SCDOCMODE_UNDO);
3616 1 : pRedoDoc->InitUndo(m_pDoc, 0, 0);
3617 1 : m_pDoc->CopyToDocument(aDestRange, IDF_ALL, false, pRedoDoc, &aMark);
3618 :
3619 : // Create an undo object for this.
3620 1 : ScRefUndoData* pRefUndoData = new ScRefUndoData(m_pDoc);
3621 2 : ScUndoPaste aUndo(&getDocShell(), aDestRange, aMark, pUndoDoc, pRedoDoc, IDF_ALL, pRefUndoData);
3622 :
3623 : // Check the content after the paste.
3624 : {
3625 : Check aChecks[] = {
3626 : { "Clip1", COL_YELLOW, false },
3627 : { "B", COL_BLUE, true },
3628 : { "Clip2", COL_YELLOW, false },
3629 : { "D", COL_BLUE, true },
3630 : { "Clip3", COL_YELLOW, false },
3631 1 : };
3632 :
3633 1 : bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3634 1 : CPPUNIT_ASSERT_MESSAGE("Check after paste failed.", bRes);
3635 : }
3636 :
3637 : // Undo, and check the content.
3638 1 : aUndo.Undo();
3639 : {
3640 : Check aChecks[] = {
3641 : { "A", COL_BLUE, true },
3642 : { "B", COL_BLUE, true },
3643 : { "C", COL_BLUE, true },
3644 : { "D", COL_BLUE, true },
3645 : { "E", COL_BLUE, true },
3646 1 : };
3647 :
3648 1 : bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3649 1 : CPPUNIT_ASSERT_MESSAGE("Check after undo failed.", bRes);
3650 : }
3651 :
3652 : // Redo, and check the content again.
3653 1 : aUndo.Redo();
3654 : {
3655 : Check aChecks[] = {
3656 : { "Clip1", COL_YELLOW, false },
3657 : { "B", COL_BLUE, true },
3658 : { "Clip2", COL_YELLOW, false },
3659 : { "D", COL_BLUE, true },
3660 : { "Clip3", COL_YELLOW, false },
3661 1 : };
3662 :
3663 1 : bool bRes = aTest.checkRange(ScAddress(1,0,0), aChecks, aChecks + SAL_N_ELEMENTS(aChecks));
3664 1 : CPPUNIT_ASSERT_MESSAGE("Check after redo failed.", bRes);
3665 : }
3666 :
3667 2 : m_pDoc->DeleteTab(0);
3668 1 : }
3669 :
3670 1 : void Test::testCopyPasteSkipEmpty2()
3671 : {
3672 1 : m_pDoc->InsertTab(0, "Test");
3673 :
3674 1 : m_pDoc->SetString(ScAddress(0,0,0), "A");
3675 1 : m_pDoc->SetString(ScAddress(2,0,0), "C");
3676 :
3677 : // Copy A1:C1 to clipboard.
3678 1 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3679 1 : aClipDoc.ResetClip(m_pDoc, static_cast<SCTAB>(0));
3680 1 : copyToClip(m_pDoc, ScRange(0,0,0,2,0,0), &aClipDoc);
3681 :
3682 : // Paste to A3 with the skip empty option set. This used to freeze. (fdo#77735)
3683 1 : ScRange aDestRange(0,2,0,2,2,0);
3684 2 : ScMarkData aMark;
3685 1 : aMark.SetMarkArea(aDestRange);
3686 1 : m_pDoc->CopyFromClip(aDestRange, aMark, IDF_ALL, NULL, &aClipDoc, false, false, true, true);
3687 :
3688 1 : CPPUNIT_ASSERT_EQUAL(OUString("A"), m_pDoc->GetString(ScAddress(0,2,0)));
3689 1 : CPPUNIT_ASSERT_MESSAGE("B3 should be empty.", m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_NONE);
3690 1 : CPPUNIT_ASSERT_EQUAL(OUString("C"), m_pDoc->GetString(ScAddress(2,2,0)));
3691 :
3692 2 : m_pDoc->DeleteTab(0);
3693 1 : }
3694 :
3695 0 : void Test::testCopyPasteSkipEmptyConditionalFormatting()
3696 : {
3697 0 : m_pDoc->InsertTab(0, "Test");
3698 :
3699 0 : ScRange aDestRange(0,0,0,1,2,0);
3700 0 : ScRange aSrcRange(3,3,0,5,4,0);
3701 :
3702 0 : ScMarkData aMark;
3703 0 : aMark.SetMarkArea(aDestRange);
3704 :
3705 0 : m_pDoc->SetValue(0,0,0,1);
3706 0 : m_pDoc->SetValue(1,0,0,1);
3707 0 : m_pDoc->SetValue(0,1,0,1);
3708 0 : m_pDoc->SetValue(0,2,0,1);
3709 0 : m_pDoc->SetValue(1,2,0,1);
3710 :
3711 : //create conditional formatting for A1:B3
3712 0 : ScConditionalFormatList* pCondFormatList = new ScConditionalFormatList();
3713 0 : m_pDoc->SetCondFormList(pCondFormatList, 0);
3714 :
3715 0 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
3716 0 : pFormat->SetRange(aDestRange);
3717 0 : sal_uLong nCondFormatKey = m_pDoc->AddCondFormat(pFormat, 0);
3718 :
3719 : // Prepare a clipboard content interleaved with empty cells.
3720 0 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3721 0 : aClipDoc.ResetClip(m_pDoc, &aMark);
3722 0 : ScClipParam aParam(aSrcRange, false);
3723 0 : aClipDoc.SetClipParam(aParam);
3724 0 : aClipDoc.SetValue(3,3,0,2);
3725 0 : aClipDoc.SetValue(4,3,0,2);
3726 0 : aClipDoc.SetValue(4,4,0,2);
3727 0 : aClipDoc.SetValue(3,5,0,2);
3728 0 : aClipDoc.SetValue(4,5,0,2);
3729 :
3730 0 : ScConditionalFormat* pClipFormat = new ScConditionalFormat(2, &aClipDoc);
3731 0 : pClipFormat->SetRange(aSrcRange);
3732 0 : aClipDoc.AddCondFormat(pClipFormat, 0);
3733 :
3734 : // Create undo document.
3735 0 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3736 0 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
3737 0 : m_pDoc->CopyToDocument(aDestRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
3738 :
3739 : // Paste clipboard content onto A1:A5 but skip empty cells.
3740 0 : bool bSkipEmpty = true;
3741 0 : m_pDoc->CopyFromClip(aDestRange, aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc, true, false, false, bSkipEmpty);
3742 :
3743 0 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
3744 0 : CPPUNIT_ASSERT_EQUAL(size_t(2), pList->size());
3745 0 : CPPUNIT_ASSERT(m_pDoc->GetCondFormat(1,1,0));
3746 : // empty cell in copy area does not overwrite conditional formatting
3747 0 : CPPUNIT_ASSERT_EQUAL(sal_uInt32(nCondFormatKey), m_pDoc->GetCondFormat(1,1,0)->GetKey());
3748 0 : for(SCCOL nCol = 0; nCol <= 1; ++nCol)
3749 : {
3750 0 : for(SCROW nRow = 0; nRow <= 2; ++nRow)
3751 : {
3752 0 : if(nRow == 1 && nCol == 1)
3753 0 : continue;
3754 :
3755 0 : CPPUNIT_ASSERT(m_pDoc->GetCondFormat(nCol, nRow, 0));
3756 0 : CPPUNIT_ASSERT(nCondFormatKey != m_pDoc->GetCondFormat(nCol, nRow, 0)->GetKey());
3757 : }
3758 : }
3759 0 : m_pDoc->DeleteTab(0);
3760 0 : }
3761 :
3762 1 : void Test::testCutPasteRefUndo()
3763 : {
3764 : // Testing scenario: A2 references B2, and B2 gets cut and pasted onto C2,
3765 : // which updates A2's formula to reference C2. Then the paste action gets
3766 : // undone, which should also undo A2's formula to reference back to B2.
3767 :
3768 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3769 :
3770 1 : m_pDoc->InsertTab(0, "Test");
3771 :
3772 : // A2 references B2.
3773 1 : m_pDoc->SetString(ScAddress(0,1,0), "=B2");
3774 :
3775 2 : ScMarkData aMark;
3776 1 : aMark.SelectOneTable(0);
3777 :
3778 : // Set up clip document for cutting of B2.
3779 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3780 1 : aClipDoc.ResetClip(m_pDoc, &aMark);
3781 2 : ScClipParam aParam(ScAddress(1,1,0), true);
3782 1 : aClipDoc.SetClipParam(aParam);
3783 1 : aClipDoc.SetValue(ScAddress(1,1,0), 12.0);
3784 :
3785 : // Set up undo document for reference update.
3786 1 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3787 1 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
3788 :
3789 : // Do the pasting of 12 into C2. This should update A2 to reference C2.
3790 1 : m_pDoc->CopyFromClip(ScAddress(2,1,0), aMark, IDF_CONTENTS, pUndoDoc, &aClipDoc, true, false);
3791 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(0,1,0));
3792 :
3793 1 : if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "C2"))
3794 0 : CPPUNIT_FAIL("A2 should be referencing C2.");
3795 :
3796 : // At this point, the ref undo document should contain a formula cell at A2 that references B2.
3797 1 : if (!checkFormula(*pUndoDoc, ScAddress(0,1,0), "B2"))
3798 0 : CPPUNIT_FAIL("A2 in the undo document should be referencing B2.");
3799 :
3800 2 : ScUndoPaste aUndo(&getDocShell(), ScRange(ScAddress(2,1,0)), aMark, pUndoDoc, NULL, IDF_CONTENTS, NULL, false, NULL);
3801 1 : aUndo.Undo();
3802 :
3803 : // Now A2 should be referencing B2 once again.
3804 1 : if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "B2"))
3805 0 : CPPUNIT_FAIL("A2 should be referencing B2 after undo.");
3806 :
3807 2 : m_pDoc->DeleteTab(0);
3808 1 : }
3809 :
3810 1 : void Test::testMoveRefBetweenSheets()
3811 : {
3812 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3813 :
3814 1 : m_pDoc->InsertTab(0, "Test1");
3815 1 : m_pDoc->InsertTab(1, "Test2");
3816 :
3817 1 : m_pDoc->SetValue(ScAddress(0,0,0), 12.0);
3818 1 : m_pDoc->SetValue(ScAddress(1,0,0), 10.0);
3819 1 : m_pDoc->SetValue(ScAddress(2,0,0), 8.0);
3820 1 : m_pDoc->SetString(ScAddress(0,1,0), "=A1");
3821 1 : m_pDoc->SetString(ScAddress(0,2,0), "=SUM(A1:C1)");
3822 :
3823 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,0,0)));
3824 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,1,0)));
3825 1 : CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc->GetValue(ScAddress(0,2,0)));
3826 :
3827 : // These formulas should not display the sheet name.
3828 1 : if (!checkFormula(*m_pDoc, ScAddress(0,1,0), "A1"))
3829 0 : CPPUNIT_FAIL("Wrong formula!");
3830 1 : if (!checkFormula(*m_pDoc, ScAddress(0,2,0), "SUM(A1:C1)"))
3831 0 : CPPUNIT_FAIL("Wrong formula!");
3832 :
3833 : // Move Test1.A2:A3 to Test2.A2:A3.
3834 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
3835 1 : bool bMoved = rFunc.MoveBlock(ScRange(0,1,0,0,2,0), ScAddress(0,1,1), true, true, false, true);
3836 1 : CPPUNIT_ASSERT(bMoved);
3837 :
3838 1 : CPPUNIT_ASSERT_MESSAGE("This cell should be empty after the move.", m_pDoc->GetCellType(ScAddress(0,1,0)) == CELLTYPE_NONE);
3839 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,1,1)));
3840 1 : CPPUNIT_ASSERT_EQUAL(30.0, m_pDoc->GetValue(ScAddress(0,2,1)));
3841 :
3842 : // The reference in the pasted formula should display sheet name after the move.
3843 1 : if (!checkFormula(*m_pDoc, ScAddress(0,1,1), "Test1.A1"))
3844 0 : CPPUNIT_FAIL("Wrong formula!");
3845 1 : if (!checkFormula(*m_pDoc, ScAddress(0,2,1), "SUM(Test1.A1:C1)"))
3846 0 : CPPUNIT_FAIL("Wrong formula!");
3847 :
3848 1 : m_pDoc->DeleteTab(1);
3849 1 : m_pDoc->DeleteTab(0);
3850 1 : }
3851 :
3852 1 : void Test::testUndoCut()
3853 : {
3854 1 : m_pDoc->InsertTab(0, "Test");
3855 :
3856 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
3857 :
3858 : // Insert values into A1:A3.
3859 1 : m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
3860 1 : m_pDoc->SetValue(ScAddress(0,1,0), 10.0);
3861 1 : m_pDoc->SetValue(ScAddress(0,2,0), 100.0);
3862 :
3863 : // SUM in A4.
3864 1 : m_pDoc->SetString(ScAddress(0,3,0), "=SUM(A1:A3)");
3865 1 : CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
3866 :
3867 : // Select A1:A3.
3868 2 : ScMarkData aMark;
3869 1 : ScRange aRange(0,0,0,0,2,0);
3870 1 : aMark.SetMarkArea(aRange);
3871 1 : aMark.MarkToMulti();
3872 :
3873 : // Set up an undo object for cutting A1:A3.
3874 1 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
3875 1 : pUndoDoc->InitUndo(m_pDoc, 0 ,0);
3876 1 : m_pDoc->CopyToDocument(aRange, IDF_ALL, false, pUndoDoc);
3877 1 : CPPUNIT_ASSERT_EQUAL( 1.0, pUndoDoc->GetValue(ScAddress(0,0,0)));
3878 1 : CPPUNIT_ASSERT_EQUAL( 10.0, pUndoDoc->GetValue(ScAddress(0,1,0)));
3879 1 : CPPUNIT_ASSERT_EQUAL(100.0, pUndoDoc->GetValue(ScAddress(0,2,0)));
3880 2 : ScUndoCut aUndo(&getDocShell(), aRange, aRange.aEnd, aMark, pUndoDoc);
3881 :
3882 : // "Cut" the selection.
3883 1 : m_pDoc->DeleteSelection(IDF_ALL, aMark);
3884 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0)); // The SUM should be zero after the "cut".
3885 :
3886 : // Undo it, and check the result.
3887 1 : aUndo.Undo();
3888 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
3889 1 : CPPUNIT_ASSERT_EQUAL( 10.0, m_pDoc->GetValue(ScAddress(0,1,0)));
3890 1 : CPPUNIT_ASSERT_EQUAL(100.0, m_pDoc->GetValue(ScAddress(0,2,0)));
3891 1 : CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0)); // The SUM value should be back to the original.
3892 :
3893 : // Redo it and check.
3894 1 : aUndo.Redo();
3895 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(0,3,0));
3896 :
3897 : // Undo again.
3898 1 : aUndo.Undo();
3899 1 : CPPUNIT_ASSERT_EQUAL(111.0, m_pDoc->GetValue(0,3,0));
3900 :
3901 2 : m_pDoc->DeleteTab(0);
3902 1 : }
3903 :
3904 1 : void Test::testMoveBlock()
3905 : {
3906 1 : m_pDoc->InsertTab(0, "SheetNotes");
3907 :
3908 1 : m_pDoc->SetValue(0, 0, 0, 1);
3909 1 : m_pDoc->SetString(1, 0, 0, "=A1+1");
3910 1 : m_pDoc->SetString(2, 0, 0, "test");
3911 :
3912 : // add notes to A1:C1
3913 1 : ScAddress aAddrA1 (0, 0, 0);
3914 1 : OUString aHelloA1("Hello world in A1");
3915 1 : ScPostIt* pNoteA1 = m_pDoc->GetOrCreateNote(aAddrA1);
3916 1 : pNoteA1->SetText(aAddrA1, aHelloA1);
3917 1 : ScAddress aAddrB1 (1, 0, 0);
3918 2 : OUString aHelloB1("Hello world in B1");
3919 1 : ScPostIt* pNoteB1 = m_pDoc->GetOrCreateNote(aAddrB1);
3920 1 : pNoteB1->SetText(aAddrB1, aHelloB1);
3921 1 : ScAddress aAddrC1 (2, 0, 0);
3922 2 : OUString aHelloC1("Hello world in C1");
3923 1 : ScPostIt* pNoteC1 = m_pDoc->GetOrCreateNote(aAddrC1);
3924 1 : pNoteC1->SetText(aAddrC1, aHelloC1);
3925 1 : ScAddress aAddrD1 (3, 0, 0);
3926 :
3927 : // previous tests on cell note content are ok. this one fails !!! :(
3928 : //CPPUNIT_ASSERT_MESSAGE("Note content in B1 before move block", m_pDoc->GetNote(aAddrB1)->GetText() == aHelloB1);
3929 :
3930 : // move notes to B1:D1
3931 1 : bool bCut = true;
3932 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
3933 1 : bool bMoveDone = rDocFunc.MoveBlock(ScRange(0, 0 ,0 ,2 ,0 ,0), ScAddress(1, 0, 0), bCut, false, false, false);
3934 :
3935 1 : CPPUNIT_ASSERT_MESSAGE("Cells not moved", bMoveDone);
3936 :
3937 : //check cell content
3938 2 : OUString aString = m_pDoc->GetString(3, 0, 0);
3939 1 : CPPUNIT_ASSERT_MESSAGE("Cell D1 should contain: test", aString == "test");
3940 1 : m_pDoc->GetFormula(2, 0, 0, aString);
3941 1 : CPPUNIT_ASSERT_MESSAGE("Cell C1 should contain an updated formula", aString == "=B1+1");
3942 1 : double fValue = m_pDoc->GetValue(aAddrB1);
3943 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("Cell B1 should contain 1", fValue, 1);
3944 :
3945 : // cell notes has been moved 1 cell right (event when overlapping)
3946 1 : CPPUNIT_ASSERT_MESSAGE("There should be NO note on A1", !m_pDoc->HasNote(aAddrA1));
3947 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on B1", m_pDoc->HasNote(aAddrB1));
3948 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on C1", m_pDoc->HasNote(aAddrC1));
3949 1 : CPPUNIT_ASSERT_MESSAGE("There should be a note on D1", m_pDoc->HasNote(aAddrD1));
3950 : /* still failing, wrong content ???
3951 : OUString sNoteText;
3952 : sNoteText = m_pDoc->GetNote(aAddrB1)->GetText();
3953 : CPPUNIT_ASSERT_MESSAGE("Note content in B1", sNoteText == aHelloA1);
3954 : sNoteText = m_pDoc->GetNote(aAddrC1)->GetText();
3955 : CPPUNIT_ASSERT_MESSAGE("Note content in C1", sNoteText == aHelloB1);
3956 : sNoteText = m_pDoc->GetNote(aAddrD1)->GetText();
3957 : CPPUNIT_ASSERT_MESSAGE("Note content in D1", sNoteText == aHelloC1);
3958 : */
3959 :
3960 2 : m_pDoc->DeleteTab(0);
3961 1 : }
3962 :
3963 1 : void Test::testCopyPasteRelativeFormula()
3964 : {
3965 1 : m_pDoc->InsertTab(0, "Formula");
3966 :
3967 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
3968 :
3969 : // Insert values to A2 and A4.
3970 1 : m_pDoc->SetValue(ScAddress(0,1,0), 1);
3971 1 : m_pDoc->SetValue(ScAddress(0,3,0), 2);
3972 :
3973 : // Insert formula to B4.
3974 1 : m_pDoc->SetString(ScAddress(1,3,0), "=A4");
3975 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,3,0)));
3976 :
3977 : // Select and copy B3:B4 to the clipboard.
3978 1 : ScRange aRange(1,2,0,1,3,0);
3979 2 : ScClipParam aClipParam(aRange, false);
3980 2 : ScMarkData aMark;
3981 1 : aMark.SetMarkArea(aRange);
3982 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
3983 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
3984 :
3985 : // Paste it to B1:B2.
3986 1 : InsertDeleteFlags nFlags = IDF_ALL;
3987 1 : ScRange aDestRange(1,0,0,1,1,0);
3988 1 : aMark.SetMarkArea(aDestRange);
3989 1 : m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
3990 :
3991 : // B2 references A2, so the value should be 1.
3992 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
3993 :
3994 : // Clear content and start over.
3995 1 : clearSheet(m_pDoc, 0);
3996 1 : clearSheet(&aClipDoc, 0);
3997 :
3998 : // Insert a single formula cell in A1.
3999 1 : m_pDoc->SetString(ScAddress(0,0,0), "=ROW()");
4000 1 : const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(0,0,0));
4001 1 : CPPUNIT_ASSERT(pFC);
4002 1 : CPPUNIT_ASSERT(!pFC->IsShared()); // single formula cell is never shared.
4003 :
4004 : // Copy A1 to clipboard.
4005 1 : aClipParam = ScClipParam(ScAddress(0,0,0), false);
4006 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
4007 :
4008 1 : pFC = aClipDoc.GetFormulaCell(ScAddress(0,0,0));
4009 1 : CPPUNIT_ASSERT(pFC);
4010 1 : CPPUNIT_ASSERT(!pFC->IsShared());
4011 :
4012 : // Paste to A3.
4013 1 : aDestRange = ScRange(0,2,0,0,2,0);
4014 1 : aMark.SetMarkArea(aDestRange);
4015 1 : m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
4016 :
4017 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(0,2,0));
4018 1 : CPPUNIT_ASSERT(pFC);
4019 1 : CPPUNIT_ASSERT(!pFC->IsShared());
4020 :
4021 : // Delete A3 and make sure it doesn't crash (see fdo#76132).
4022 1 : clearRange(m_pDoc, ScAddress(0,2,0));
4023 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,2,0)) == CELLTYPE_NONE);
4024 :
4025 2 : m_pDoc->DeleteTab(0);
4026 1 : }
4027 :
4028 1 : void Test::testCopyPasteRepeatOneFormula()
4029 : {
4030 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
4031 :
4032 1 : m_pDoc->InsertTab(0, "Test");
4033 :
4034 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
4035 2 : ScMarkData aMark;
4036 :
4037 : // Insert values in A1:B10.
4038 11 : for (SCROW i = 0; i < 10; ++i)
4039 : {
4040 10 : m_pDoc->SetValue(ScAddress(0,i,0), i+1.0); // column A
4041 10 : m_pDoc->SetValue(ScAddress(1,i,0), (i+1.0)*10.0); // column B
4042 : }
4043 :
4044 : // Insert a formula in C1.
4045 1 : ScAddress aPos(2,0,0); // C1
4046 1 : m_pDoc->SetString(aPos, "=SUM(A1:B1)");
4047 1 : CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(aPos));
4048 :
4049 : // This check makes only sense if group listeners are activated.
4050 : #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4051 : // At this point, there should be only one normal area listener listening
4052 : // on A1:B1.
4053 1 : ScRange aWholeSheet(0,0,0,MAXCOL,MAXROW,0);
4054 1 : ScBroadcastAreaSlotMachine* pBASM = m_pDoc->GetBASM();
4055 1 : CPPUNIT_ASSERT(pBASM);
4056 2 : std::vector<sc::AreaListener> aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4057 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4058 1 : const sc::AreaListener* pListener = &aListeners[0];
4059 1 : CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,0,0), pListener->maArea);
4060 1 : CPPUNIT_ASSERT_MESSAGE("This listener shouldn't be a group listener.", !pListener->mbGroupListening);
4061 : #endif
4062 :
4063 : // Copy C1 to clipboard.
4064 2 : ScClipParam aClipParam(aPos, false);
4065 1 : aMark.SetMarkArea(aPos);
4066 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark);
4067 :
4068 : // Paste it to C2:C10.
4069 1 : InsertDeleteFlags nFlags = IDF_CONTENTS;
4070 1 : ScRange aDestRange(2,1,0,2,9,0);
4071 1 : aMark.SetMarkArea(aDestRange);
4072 1 : m_pDoc->CopyFromClip(aDestRange, aMark, nFlags, NULL, &aClipDoc);
4073 :
4074 : // Make sure C1:C10 are grouped.
4075 1 : const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
4076 1 : CPPUNIT_ASSERT(pFC);
4077 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(10), pFC->GetSharedLength());
4078 :
4079 : // Check the formula results.
4080 11 : for (SCROW i = 0; i < 10; ++i)
4081 : {
4082 10 : double fExpected = (i+1.0)*11.0;
4083 10 : CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i,0)));
4084 : }
4085 :
4086 : // This check makes only sense if group listeners are activated.
4087 : #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4088 : // At this point, there should only be one area listener and it should be
4089 : // a group listener listening on A1:B10.
4090 1 : aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4091 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4092 1 : pListener = &aListeners[0];
4093 1 : CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,9,0), pListener->maArea);
4094 1 : CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4095 : #endif
4096 :
4097 : // Insert a new row at row 1.
4098 1 : ScRange aRowOne(0,0,0,MAXCOL,0,0);
4099 1 : aMark.SetMarkArea(aRowOne);
4100 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
4101 1 : rFunc.InsertCells(aRowOne, &aMark, INS_INSROWS_BEFORE, true, true, false);
4102 :
4103 1 : CPPUNIT_ASSERT_MESSAGE("C1 should be empty.", m_pDoc->GetCellType(ScAddress(2,0,0)) == CELLTYPE_NONE);
4104 :
4105 : // This check makes only sense if group listeners are activated.
4106 : #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4107 : // Make there we only have one group area listener listening on A2:B11.
4108 1 : aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4109 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4110 1 : pListener = &aListeners[0];
4111 1 : CPPUNIT_ASSERT_EQUAL(ScRange(0,1,0,1,10,0), pListener->maArea);
4112 1 : CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4113 : #endif
4114 :
4115 : // Check the formula results.
4116 11 : for (SCROW i = 0; i < 10; ++i)
4117 : {
4118 10 : double fExpected = (i+1.0)*11.0;
4119 10 : CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i+1,0)));
4120 : }
4121 :
4122 : // Delete row at row 1 to shift the cells up.
4123 1 : rFunc.DeleteCells(aRowOne, &aMark, DEL_DELROWS, true, true);
4124 :
4125 : // Check the formula results again.
4126 11 : for (SCROW i = 0; i < 10; ++i)
4127 : {
4128 10 : double fExpected = (i+1.0)*11.0;
4129 10 : CPPUNIT_ASSERT_EQUAL(fExpected, m_pDoc->GetValue(ScAddress(2,i,0)));
4130 : }
4131 :
4132 : // This check makes only sense if group listeners are activated.
4133 : #if !defined(USE_FORMULA_GROUP_LISTENER) || USE_FORMULA_GROUP_LISTENER
4134 : // Check the group area listener again to make sure it's listening on A1:B10 once again.
4135 1 : aListeners = pBASM->GetAllListeners(aWholeSheet, sc::AreaInside);
4136 1 : CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aListeners.size());
4137 1 : pListener = &aListeners[0];
4138 1 : CPPUNIT_ASSERT_EQUAL(ScRange(0,0,0,1,9,0), pListener->maArea);
4139 1 : CPPUNIT_ASSERT_MESSAGE("This listener should be a group listener.", pListener->mbGroupListening);
4140 : #endif
4141 :
4142 2 : m_pDoc->DeleteTab(0);
4143 1 : }
4144 :
4145 1 : void Test::testMergedCells()
4146 : {
4147 : //test merge and unmerge
4148 : //TODO: an undo/redo test for this would be a good idea
4149 1 : m_pDoc->InsertTab(0, "Sheet1");
4150 1 : m_pDoc->DoMerge(0, 1, 1, 3, 3, false);
4151 1 : SCCOL nEndCol = 1;
4152 1 : SCROW nEndRow = 1;
4153 1 : m_pDoc->ExtendMerge( 1, 1, nEndCol, nEndRow, 0, false);
4154 1 : CPPUNIT_ASSERT_MESSAGE("did not merge cells", nEndCol == 3 && nEndRow == 3);
4155 1 : ScRange aRange(0,2,0,MAXCOL,2,0);
4156 1 : ScMarkData aMark;
4157 1 : aMark.SetMarkArea(aRange);
4158 1 : getDocShell().GetDocFunc().InsertCells(aRange, &aMark, INS_INSROWS_BEFORE, true, true);
4159 1 : m_pDoc->ExtendMerge(1, 1, nEndCol, nEndRow, 0, false);
4160 1 : CPPUNIT_ASSERT_MESSAGE("did not increase merge area", nEndCol == 3 && nEndRow == 4);
4161 1 : m_pDoc->DeleteTab(0);
4162 1 : }
4163 :
4164 1 : void Test::testRenameTable()
4165 : {
4166 : //test set rename table
4167 : //TODO: set name1 and name2 and do an undo to check if name 1 is set now
4168 : //TODO: also check if new name for table is same as another table
4169 :
4170 1 : m_pDoc->InsertTab(0, "Sheet1");
4171 1 : m_pDoc->InsertTab(1, "Sheet2");
4172 :
4173 : //test case 1 , rename table2 to sheet 1, it should return error
4174 1 : OUString nameToSet = "Sheet1";
4175 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4176 1 : CPPUNIT_ASSERT_MESSAGE("name same as another table is being set", !rDocFunc.RenameTable(1,nameToSet,false,true) );
4177 :
4178 : //test case 2 , simple rename to check name
4179 1 : nameToSet = "test1";
4180 1 : getDocShell().GetDocFunc().RenameTable(0,nameToSet,false,true);
4181 2 : OUString nameJustSet;
4182 1 : m_pDoc->GetName(0,nameJustSet);
4183 1 : CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
4184 :
4185 : //test case 3 , rename again
4186 2 : OUString anOldName;
4187 1 : m_pDoc->GetName(0,anOldName);
4188 :
4189 1 : nameToSet = "test2";
4190 1 : rDocFunc.RenameTable(0,nameToSet,false,true);
4191 1 : m_pDoc->GetName(0,nameJustSet);
4192 1 : CPPUNIT_ASSERT_MESSAGE("table not renamed", nameToSet == nameJustSet);
4193 :
4194 : //test case 4 , check if undo works
4195 1 : SfxUndoAction* pUndo = new ScUndoRenameTab(&getDocShell(),0,anOldName,nameToSet);
4196 1 : pUndo->Undo();
4197 1 : m_pDoc->GetName(0,nameJustSet);
4198 1 : CPPUNIT_ASSERT_MESSAGE("the correct name is not set after undo", nameJustSet == anOldName);
4199 :
4200 1 : pUndo->Redo();
4201 1 : m_pDoc->GetName(0,nameJustSet);
4202 1 : CPPUNIT_ASSERT_MESSAGE("the correct color is not set after redo", nameJustSet == nameToSet);
4203 :
4204 1 : m_pDoc->DeleteTab(0);
4205 2 : m_pDoc->DeleteTab(1);
4206 1 : }
4207 :
4208 1 : void Test::testSetBackgroundColor()
4209 : {
4210 : //test set background color
4211 : //TODO: set color1 and set color2 and do an undo to check if color1 is set now.
4212 :
4213 1 : m_pDoc->InsertTab(0, "Sheet1");
4214 1 : Color aColor;
4215 :
4216 : //test yellow
4217 1 : aColor=Color(COL_YELLOW);
4218 1 : getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
4219 2 : CPPUNIT_ASSERT_MESSAGE("the correct color is not set",
4220 1 : m_pDoc->GetTabBgColor(0) == aColor);
4221 :
4222 1 : Color aOldTabBgColor=m_pDoc->GetTabBgColor(0);
4223 1 : aColor.SetColor(COL_BLUE);//set BLUE
4224 1 : getDocShell().GetDocFunc().SetTabBgColor(0,aColor,false, true);
4225 2 : CPPUNIT_ASSERT_MESSAGE("the correct color is not set the second time",
4226 1 : m_pDoc->GetTabBgColor(0) == aColor);
4227 :
4228 : //now check for undo
4229 1 : SfxUndoAction* pUndo = new ScUndoTabColor(&getDocShell(), 0, aOldTabBgColor, aColor);
4230 1 : pUndo->Undo();
4231 1 : CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aOldTabBgColor);
4232 1 : pUndo->Redo();
4233 1 : CPPUNIT_ASSERT_MESSAGE("the correct color is not set after undo", m_pDoc->GetTabBgColor(0)== aColor);
4234 1 : m_pDoc->DeleteTab(0);
4235 1 : }
4236 :
4237 1 : void Test::testUpdateReference()
4238 : {
4239 : //test that formulas are correctly updated during sheet delete
4240 : //TODO: add tests for relative references, updating of named ranges, ...
4241 1 : m_pDoc->InsertTab(0, "Sheet1");
4242 1 : m_pDoc->InsertTab(1, "Sheet2");
4243 1 : m_pDoc->InsertTab(2, "Sheet3");
4244 1 : m_pDoc->InsertTab(3, "Sheet4");
4245 :
4246 1 : m_pDoc->SetValue(0,0,2, 1);
4247 1 : m_pDoc->SetValue(1,0,2, 2);
4248 1 : m_pDoc->SetValue(1,1,3, 4);
4249 1 : m_pDoc->SetString(2,0,2, "=A1+B1");
4250 1 : m_pDoc->SetString(2,1,2, "=Sheet4.B2+A1");
4251 :
4252 : double aValue;
4253 1 : m_pDoc->GetValue(2,0,2, aValue);
4254 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 3);
4255 1 : m_pDoc->GetValue(2,1,2, aValue);
4256 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("formula does not return correct result", aValue, 5);
4257 :
4258 : //test deleting both sheets: one is not directly before the sheet, the other one is
4259 1 : m_pDoc->DeleteTab(0);
4260 1 : m_pDoc->GetValue(2,0,1, aValue);
4261 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 3);
4262 1 : m_pDoc->GetValue(2,1,1, aValue);
4263 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting first sheet formula does not return correct result", aValue, 5);
4264 :
4265 1 : m_pDoc->DeleteTab(0);
4266 1 : m_pDoc->GetValue(2,0,0, aValue);
4267 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 3);
4268 1 : m_pDoc->GetValue(2,1,0, aValue);
4269 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting second sheet formula does not return correct result", aValue, 5);
4270 :
4271 : //test adding two sheets
4272 1 : m_pDoc->InsertTab(0, "Sheet2");
4273 1 : m_pDoc->GetValue(2,0,1, aValue);
4274 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 3);
4275 1 : m_pDoc->GetValue(2,1,1, aValue);
4276 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting first sheet formula does not return correct result", aValue, 5);
4277 :
4278 1 : m_pDoc->InsertTab(0, "Sheet1");
4279 1 : m_pDoc->GetValue(2,0,2, aValue);
4280 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 3);
4281 1 : m_pDoc->GetValue(2,1,2, aValue);
4282 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting second sheet formula does not return correct result", aValue, 5);
4283 :
4284 : //test new DeleteTabs/InsertTabs methods
4285 1 : m_pDoc->DeleteTabs(0, 2);
4286 1 : m_pDoc->GetValue(2, 0, 0, aValue);
4287 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 3);
4288 1 : m_pDoc->GetValue(2, 1, 0, aValue);
4289 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after deleting sheets formula does not return correct result", aValue, 5);
4290 :
4291 1 : std::vector<OUString> aSheets;
4292 1 : aSheets.push_back("Sheet1");
4293 1 : aSheets.push_back("Sheet2");
4294 1 : m_pDoc->InsertTabs(0, aSheets, false, true);
4295 1 : m_pDoc->GetValue(2, 0, 2, aValue);
4296 2 : OUString aFormula;
4297 1 : m_pDoc->GetFormula(2,0,2, aFormula);
4298 :
4299 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 3);
4300 1 : m_pDoc->GetValue(2, 1, 2, aValue);
4301 1 : ASSERT_DOUBLES_EQUAL_MESSAGE("after inserting sheets formula does not return correct result", aValue, 5);
4302 :
4303 1 : m_pDoc->DeleteTab(3);
4304 1 : m_pDoc->DeleteTab(2);
4305 1 : m_pDoc->DeleteTab(1);
4306 2 : m_pDoc->DeleteTab(0);
4307 1 : }
4308 :
4309 1 : void Test::testSearchCells()
4310 : {
4311 1 : m_pDoc->InsertTab(0, "Test");
4312 :
4313 1 : m_pDoc->SetString(ScAddress(0,0,0), "A");
4314 1 : m_pDoc->SetString(ScAddress(0,1,0), "B");
4315 1 : m_pDoc->SetString(ScAddress(0,2,0), "A");
4316 : // Leave A4 blank.
4317 1 : m_pDoc->SetString(ScAddress(0,4,0), "A");
4318 1 : m_pDoc->SetString(ScAddress(0,5,0), "B");
4319 1 : m_pDoc->SetString(ScAddress(0,6,0), "C");
4320 :
4321 1 : SvxSearchItem aItem(SID_SEARCH_ITEM);
4322 1 : aItem.SetSearchString(OUString("A"));
4323 1 : aItem.SetCommand(SvxSearchCmd::FIND_ALL);
4324 2 : ScMarkData aMarkData;
4325 1 : aMarkData.SelectOneTable(0);
4326 1 : SCCOL nCol = 0;
4327 1 : SCROW nRow = 0;
4328 1 : SCTAB nTab = 0;
4329 2 : ScRangeList aMatchedRanges;
4330 2 : OUString aUndoStr;
4331 1 : bool bSuccess = m_pDoc->SearchAndReplace(aItem, nCol, nRow, nTab, aMarkData, aMatchedRanges, aUndoStr);
4332 :
4333 1 : CPPUNIT_ASSERT_MESSAGE("Search And Replace should succeed", bSuccess);
4334 1 : CPPUNIT_ASSERT_MESSAGE("There should be exactly 3 matching cells.", aMatchedRanges.size() == 3);
4335 1 : ScAddress aHit(0,0,0);
4336 1 : CPPUNIT_ASSERT_MESSAGE("A1 should be inside the matched range.", aMatchedRanges.In(aHit));
4337 1 : aHit.SetRow(2);
4338 1 : CPPUNIT_ASSERT_MESSAGE("A3 should be inside the matched range.", aMatchedRanges.In(aHit));
4339 1 : aHit.SetRow(4);
4340 1 : CPPUNIT_ASSERT_MESSAGE("A5 should be inside the matched range.", aMatchedRanges.In(aHit));
4341 :
4342 2 : m_pDoc->DeleteTab(0);
4343 1 : }
4344 :
4345 1 : void Test::testFormulaPosition()
4346 : {
4347 1 : m_pDoc->InsertTab(0, "Test");
4348 :
4349 1 : ScAddress aPos(0,0,0); // A1
4350 1 : m_pDoc->SetString(aPos, "=ROW()");
4351 1 : aPos.IncRow(); // A2
4352 1 : m_pDoc->SetString(aPos, "=ROW()");
4353 1 : aPos.SetRow(3); // A4;
4354 1 : m_pDoc->SetString(aPos, "=ROW()");
4355 :
4356 : {
4357 1 : SCROW aRows[] = { 0, 1, 3 };
4358 1 : bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
4359 1 : CPPUNIT_ASSERT(bRes);
4360 : }
4361 :
4362 1 : m_pDoc->InsertRow(0,0,0,0,1,5); // Insert 5 rows at A2.
4363 : {
4364 1 : SCROW aRows[] = { 0, 6, 8 };
4365 1 : bool bRes = checkFormulaPositions(*m_pDoc, aPos.Tab(), aPos.Col(), aRows, SAL_N_ELEMENTS(aRows));
4366 1 : CPPUNIT_ASSERT(bRes);
4367 : }
4368 :
4369 1 : m_pDoc->DeleteTab(0);
4370 1 : }
4371 :
4372 : namespace {
4373 :
4374 4 : bool hasRange(const std::vector<ScTokenRef>& rRefTokens, const ScRange& rRange, const ScAddress& rPos)
4375 : {
4376 4 : std::vector<ScTokenRef>::const_iterator it = rRefTokens.begin(), itEnd = rRefTokens.end();
4377 5 : for (; it != itEnd; ++it)
4378 : {
4379 5 : const ScTokenRef& p = *it;
4380 5 : if (!ScRefTokenHelper::isRef(p) || ScRefTokenHelper::isExternalRef(p))
4381 0 : continue;
4382 :
4383 5 : switch (p->GetType())
4384 : {
4385 : case formula::svSingleRef:
4386 : {
4387 2 : ScSingleRefData aData = *p->GetSingleRef();
4388 2 : if (rRange.aStart != rRange.aEnd)
4389 0 : break;
4390 :
4391 2 : ScAddress aThis = aData.toAbs(rPos);
4392 2 : if (aThis == rRange.aStart)
4393 2 : return true;
4394 : }
4395 0 : break;
4396 : case formula::svDoubleRef:
4397 : {
4398 3 : ScComplexRefData aData = *p->GetDoubleRef();
4399 3 : ScRange aThis = aData.toAbs(rPos);
4400 3 : if (aThis == rRange)
4401 2 : return true;
4402 : }
4403 1 : break;
4404 : default:
4405 : ;
4406 : }
4407 : }
4408 0 : return false;
4409 : }
4410 :
4411 : }
4412 :
4413 1 : void Test::testJumpToPrecedentsDependents()
4414 : {
4415 : // Precedent is another cell that the cell references, while dependent is
4416 : // another cell that references it.
4417 1 : m_pDoc->InsertTab(0, "Test");
4418 :
4419 1 : m_pDoc->SetString(2, 0, 0, "=A1+A2+B3"); // C1
4420 1 : m_pDoc->SetString(2, 1, 0, "=A1"); // C2
4421 1 : m_pDoc->CalcAll();
4422 :
4423 1 : std::vector<ScTokenRef> aRefTokens;
4424 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4425 :
4426 : {
4427 : // C1's precedent should be A1:A2,B3.
4428 1 : ScAddress aC1(2, 0, 0);
4429 1 : ScRangeList aRange(aC1);
4430 1 : rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
4431 2 : CPPUNIT_ASSERT_MESSAGE("A1:A2 should be a precedent of C1.",
4432 1 : hasRange(aRefTokens, ScRange(0, 0, 0, 0, 1, 0), aC1));
4433 2 : CPPUNIT_ASSERT_MESSAGE("B3 should be a precedent of C1.",
4434 2 : hasRange(aRefTokens, ScRange(1, 2, 0), aC1));
4435 : }
4436 :
4437 : {
4438 : // C2's precedent should be A1 only.
4439 1 : ScAddress aC2(2, 1, 0);
4440 1 : ScRangeList aRange(aC2);
4441 1 : rDocFunc.DetectiveCollectAllPreds(aRange, aRefTokens);
4442 2 : CPPUNIT_ASSERT_EQUAL_MESSAGE("there should only be one reference token.",
4443 1 : aRefTokens.size(), static_cast<size_t>(1));
4444 2 : CPPUNIT_ASSERT_MESSAGE("A1 should be a precedent of C1.",
4445 2 : hasRange(aRefTokens, ScRange(0, 0, 0), aC2));
4446 : }
4447 :
4448 : {
4449 : // A1's dependent should be C1:C2.
4450 1 : ScAddress aA1(0, 0, 0);
4451 1 : ScRangeList aRange(aA1);
4452 1 : rDocFunc.DetectiveCollectAllSuccs(aRange, aRefTokens);
4453 2 : CPPUNIT_ASSERT_MESSAGE("C1:C2 should be the only dependent of A1.",
4454 2 : aRefTokens.size() == 1 && hasRange(aRefTokens, ScRange(2, 0, 0, 2, 1, 0), aA1));
4455 : }
4456 :
4457 1 : m_pDoc->DeleteTab(0);
4458 1 : }
4459 :
4460 1 : void Test::testAutoFill()
4461 : {
4462 1 : m_pDoc->InsertTab(0, "test");
4463 :
4464 1 : m_pDoc->SetValue(0,0,0,1);
4465 :
4466 1 : ScMarkData aMarkData;
4467 1 : aMarkData.SelectTable(0, true);
4468 :
4469 1 : m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 5);
4470 7 : for (SCROW i = 0; i< 6; ++i)
4471 6 : ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1.0), m_pDoc->GetValue(0, i, 0));
4472 :
4473 : // check that hidden rows are not affected by autofill
4474 : // set values for hidden rows
4475 1 : m_pDoc->SetValue(0,1,0,10);
4476 1 : m_pDoc->SetValue(0,2,0,10);
4477 :
4478 1 : m_pDoc->SetRowHidden(1, 2, 0, true);
4479 1 : m_pDoc->Fill( 0, 0, 0, 0, NULL, aMarkData, 8);
4480 :
4481 1 : ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,1,0));
4482 1 : ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,2,0));
4483 6 : for (SCROW i = 3; i< 8; ++i)
4484 5 : ASSERT_DOUBLES_EQUAL(static_cast<double>(i-1.0), m_pDoc->GetValue(0, i, 0));
4485 :
4486 1 : m_pDoc->Fill( 0, 0, 0, 8, NULL, aMarkData, 5, FILL_TO_RIGHT );
4487 6 : for (SCCOL i = 0; i < 5; ++i)
4488 : {
4489 45 : for(SCROW j = 0; j < 8; ++j)
4490 : {
4491 40 : if (j > 2)
4492 : {
4493 25 : ASSERT_DOUBLES_EQUAL(static_cast<double>(j-1+i), m_pDoc->GetValue(i, j, 0));
4494 : }
4495 15 : else if (j == 0)
4496 : {
4497 5 : ASSERT_DOUBLES_EQUAL(static_cast<double>(i+1), m_pDoc->GetValue(i, 0, 0));
4498 : }
4499 10 : else if (j == 1 || j== 2)
4500 : {
4501 10 : if(i == 0)
4502 2 : ASSERT_DOUBLES_EQUAL(10.0, m_pDoc->GetValue(0,j,0));
4503 : else
4504 8 : ASSERT_DOUBLES_EQUAL(0.0, m_pDoc->GetValue(i,j,0));
4505 : }
4506 : }
4507 : }
4508 :
4509 : // test auto fill user data lists
4510 1 : m_pDoc->SetString( 0, 100, 0, "January" );
4511 1 : m_pDoc->Fill( 0, 100, 0, 100, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
4512 2 : OUString aTestValue = m_pDoc->GetString( 0, 101, 0 );
4513 1 : CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("February") );
4514 1 : aTestValue = m_pDoc->GetString( 0, 102, 0 );
4515 1 : CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("March") );
4516 :
4517 : // test that two same user data list entries will not result in incremental fill
4518 1 : m_pDoc->SetString( 0, 101, 0, "January" );
4519 1 : m_pDoc->Fill( 0, 100, 0, 101, NULL, aMarkData, 2, FILL_TO_BOTTOM, FILL_AUTO );
4520 3 : for ( SCROW i = 102; i <= 103; ++i )
4521 : {
4522 2 : aTestValue = m_pDoc->GetString( 0, i, 0 );
4523 2 : CPPUNIT_ASSERT_EQUAL( aTestValue, OUString("January") );
4524 : }
4525 :
4526 : // Clear column A for a new test.
4527 1 : clearRange(m_pDoc, ScRange(0,0,0,0,MAXROW,0));
4528 1 : m_pDoc->SetRowHidden(0, MAXROW, 0, false); // Show all rows.
4529 :
4530 : // Fill A1:A6 with 1,2,3,4,5,6.
4531 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
4532 1 : m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
4533 1 : ScRange aRange(0,0,0,0,5,0);
4534 1 : aMarkData.SetMarkArea(aRange);
4535 1 : rFunc.FillSeries(aRange, &aMarkData, FILL_TO_BOTTOM, FILL_AUTO, FILL_DAY, MAXDOUBLE, 1.0, MAXDOUBLE, true, true);
4536 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4537 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
4538 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
4539 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
4540 1 : CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
4541 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
4542 :
4543 : // Undo should clear the area except for the top cell.
4544 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
4545 1 : CPPUNIT_ASSERT(pUndoMgr);
4546 1 : pUndoMgr->Undo();
4547 :
4548 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4549 6 : for (SCROW i = 1; i <= 5; ++i)
4550 5 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(0,i,0)) == CELLTYPE_NONE);
4551 :
4552 : // Redo should put the serial values back in.
4553 1 : pUndoMgr->Redo();
4554 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
4555 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
4556 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(0,2,0)));
4557 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,3,0)));
4558 1 : CPPUNIT_ASSERT_EQUAL(5.0, m_pDoc->GetValue(ScAddress(0,4,0)));
4559 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,5,0)));
4560 :
4561 : // test that filling formulas vertically up does the right thing
4562 11 : for(SCROW nRow = 0; nRow < 10; ++nRow)
4563 10 : m_pDoc->SetValue(100, 100 + nRow, 0, 1);
4564 :
4565 1 : m_pDoc->SetString(100, 110, 0, "=A111");
4566 :
4567 1 : m_pDoc->Fill(100, 110, 100, 110, NULL, aMarkData, 10, FILL_TO_TOP, FILL_AUTO);
4568 12 : for(SCROW nRow = 110; nRow >= 100; --nRow)
4569 : {
4570 11 : OUString aExpected = "=A" + OUString::number(nRow +1);
4571 22 : OUString aFormula;
4572 11 : m_pDoc->GetFormula(100, nRow, 0, aFormula);
4573 11 : CPPUNIT_ASSERT_EQUAL(aExpected, aFormula);
4574 11 : }
4575 :
4576 2 : m_pDoc->DeleteTab(0);
4577 1 : }
4578 :
4579 1 : void Test::testAutoFillSimple()
4580 : {
4581 1 : m_pDoc->InsertTab(0, "test");
4582 :
4583 1 : m_pDoc->SetValue(0, 0, 0, 1);
4584 1 : m_pDoc->SetString(0, 1, 0, "=10");
4585 :
4586 1 : ScMarkData aMarkData;
4587 1 : aMarkData.SelectTable(0, true);
4588 :
4589 1 : m_pDoc->Fill( 0, 0, 0, 1, NULL, aMarkData, 6, FILL_TO_BOTTOM, FILL_AUTO);
4590 :
4591 9 : for(SCROW nRow = 0; nRow < 8; ++nRow)
4592 : {
4593 8 : if (nRow % 2 == 0)
4594 : {
4595 4 : double nVal = m_pDoc->GetValue(0, nRow, 0);
4596 4 : CPPUNIT_ASSERT_EQUAL((nRow+2)/2.0, nVal);
4597 : }
4598 : else
4599 : {
4600 4 : OString aMsg = OString("wrong value in row: ") + OString::number(nRow);
4601 4 : double nVal = m_pDoc->GetValue(0, nRow, 0);
4602 4 : CPPUNIT_ASSERT_EQUAL_MESSAGE(aMsg.getStr(), 10.0, nVal);
4603 : }
4604 : }
4605 :
4606 1 : m_pDoc->DeleteTab(0);
4607 1 : }
4608 :
4609 1 : void Test::testCopyPasteFormulas()
4610 : {
4611 1 : m_pDoc->InsertTab(0, "Sheet1");
4612 1 : m_pDoc->InsertTab(1, "Sheet2");
4613 :
4614 1 : m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
4615 1 : m_pDoc->SetString(0,1,0, "=$A$1+B2" );
4616 1 : m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
4617 1 : m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
4618 1 : m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
4619 :
4620 : // to prevent ScEditableTester in ScDocFunc::MoveBlock
4621 1 : ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,0,0), 1.0);
4622 1 : ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(0,1,0), 1.0);
4623 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4624 1 : bool bMoveDone = rDocFunc.MoveBlock(ScRange(0,0,0,0,4,0), ScAddress( 10, 10, 0), false, false, false, true);
4625 :
4626 : // check that moving was successful, mainly for editable tester
4627 1 : CPPUNIT_ASSERT(bMoveDone);
4628 1 : ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,10,0), 1.0);
4629 1 : ASSERT_DOUBLES_EQUAL(m_pDoc->GetValue(10,11,0), 1.0);
4630 1 : OUString aFormula;
4631 1 : m_pDoc->GetFormula(10,10,0, aFormula);
4632 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($A$1)"));
4633 1 : m_pDoc->GetFormula(10,11,0, aFormula);
4634 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$A$1+L12"));
4635 1 : m_pDoc->GetFormula(10,12,0, aFormula);
4636 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K11"));
4637 1 : m_pDoc->GetFormula(10,13,0, aFormula);
4638 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.$A$1"));
4639 1 : m_pDoc->GetFormula(10,14,0, aFormula);
4640 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$Sheet2.K$1"));
4641 1 : }
4642 :
4643 1 : void Test::testCopyPasteFormulasExternalDoc()
4644 : {
4645 1 : OUString aDocName("file:///source.fake");
4646 1 : SfxMedium* pMedium = new SfxMedium(aDocName, STREAM_STD_READWRITE);
4647 1 : getDocShell().DoInitNew(pMedium);
4648 1 : m_pDoc = &getDocShell().GetDocument();
4649 :
4650 2 : ScDocShellRef xExtDocSh = new ScDocShell;
4651 2 : OUString aExtDocName("file:///extdata.fake");
4652 2 : OUString aExtSh1Name("ExtSheet1");
4653 2 : OUString aExtSh2Name("ExtSheet2");
4654 1 : SfxMedium* pMed = new SfxMedium(aExtDocName, STREAM_STD_READWRITE);
4655 1 : xExtDocSh->DoInitNew(pMed);
4656 2 : CPPUNIT_ASSERT_MESSAGE("external document instance not loaded.",
4657 1 : findLoadedDocShellByName(aExtDocName) != NULL);
4658 :
4659 1 : ScDocument& rExtDoc = xExtDocSh->GetDocument();
4660 1 : rExtDoc.InsertTab(0, aExtSh1Name);
4661 1 : rExtDoc.InsertTab(1, aExtSh2Name);
4662 :
4663 1 : m_pDoc->InsertTab(0, "Sheet1");
4664 1 : m_pDoc->InsertTab(1, "Sheet2");
4665 :
4666 1 : m_pDoc->SetString(0,0,0, "=COLUMN($A$1)");
4667 1 : m_pDoc->SetString(0,1,0, "=$A$1+B2" );
4668 1 : m_pDoc->SetString(0,2,0, "=$Sheet2.A1");
4669 1 : m_pDoc->SetString(0,3,0, "=$Sheet2.$A$1");
4670 1 : m_pDoc->SetString(0,4,0, "=$Sheet2.A$1");
4671 1 : m_pDoc->SetString(0,5,0, "=$Sheet1.$A$1");
4672 :
4673 1 : ScRange aRange(0,0,0,0,5,0);
4674 2 : ScClipParam aClipParam(aRange, false);
4675 2 : ScMarkData aMark;
4676 1 : aMark.SetMarkArea(aRange);
4677 1 : ScDocument* pClipDoc = new ScDocument(SCDOCMODE_CLIP);
4678 1 : m_pDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
4679 :
4680 1 : InsertDeleteFlags nFlags = IDF_ALL;
4681 1 : aRange = ScRange(1,1,1,1,6,1);
4682 2 : ScMarkData aMarkData2;
4683 1 : aMarkData2.SetMarkArea(aRange);
4684 1 : rExtDoc.CopyFromClip(aRange, aMarkData2, nFlags, NULL, pClipDoc);
4685 :
4686 2 : OUString aFormula;
4687 1 : rExtDoc.GetFormula(1,1,1, aFormula);
4688 : //adjust absolute refs pointing to the copy area
4689 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=COLUMN($B$2)"));
4690 1 : rExtDoc.GetFormula(1,2,1, aFormula);
4691 : //adjust absolute refs and keep relative refs
4692 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$B$2+C3"));
4693 1 : rExtDoc.GetFormula(1,3,1, aFormula);
4694 : // make absolute sheet refs external refs
4695 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B2"));
4696 1 : rExtDoc.GetFormula(1,4,1, aFormula);
4697 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.$A$1"));
4698 1 : rExtDoc.GetFormula(1,5,1, aFormula);
4699 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("='file:///source.fake'#$Sheet2.B$1"));
4700 1 : rExtDoc.GetFormula(1,6,1, aFormula);
4701 1 : CPPUNIT_ASSERT_EQUAL(aFormula, OUString("=$ExtSheet2.$B$2"));
4702 :
4703 2 : xExtDocSh->DoClose();
4704 1 : }
4705 :
4706 1 : void Test::testFindAreaPosVertical()
4707 : {
4708 : const char* aData[][3] = {
4709 : { 0, "1", "1" },
4710 : { "1", 0, "1" },
4711 : { "1", "1", "1" },
4712 : { 0, "1", "1" },
4713 : { "1", "1", "1" },
4714 : { "1", 0, "1" },
4715 : { "1", "1", "1" },
4716 1 : };
4717 :
4718 1 : m_pDoc->InsertTab(0, "Test1");
4719 1 : clearRange( m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
4720 1 : ScAddress aPos(0,0,0);
4721 1 : ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
4722 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
4723 :
4724 1 : m_pDoc->SetRowHidden(4,4,0,true);
4725 1 : bool bHidden = m_pDoc->RowHidden(4,0);
4726 1 : CPPUNIT_ASSERT(bHidden);
4727 :
4728 1 : SCCOL nCol = 0;
4729 1 : SCROW nRow = 0;
4730 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4731 :
4732 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4733 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4734 :
4735 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4736 :
4737 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), nRow);
4738 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4739 :
4740 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4741 :
4742 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(5), nRow);
4743 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4744 :
4745 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4746 :
4747 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
4748 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4749 :
4750 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4751 :
4752 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(MAXROW), nRow);
4753 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(0), nCol);
4754 :
4755 1 : nCol = 1;
4756 1 : nRow = 2;
4757 :
4758 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4759 :
4760 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), nRow);
4761 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4762 :
4763 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_DOWN);
4764 :
4765 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(6), nRow);
4766 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4767 :
4768 1 : nCol = 2;
4769 1 : nRow = 6;
4770 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_UP);
4771 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4772 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
4773 :
4774 1 : m_pDoc->DeleteTab(0);
4775 1 : }
4776 :
4777 1 : void Test::testFindAreaPosColRight()
4778 : {
4779 : const char* aData[][7] = {
4780 : { "", "1", "1", "", "1", "1", "1" },
4781 1 : { "", "", "1", "1", "1", "", "1" }, };
4782 :
4783 1 : m_pDoc->InsertTab(0, "test1");
4784 1 : clearRange( m_pDoc, ScRange(0, 0, 0, 7, SAL_N_ELEMENTS(aData), 0));
4785 1 : ScAddress aPos(0,0,0);
4786 1 : ScRange aDataRange = insertRangeData( m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
4787 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
4788 :
4789 1 : m_pDoc->SetColHidden(4,4,0,true);
4790 1 : bool bHidden = m_pDoc->ColHidden(4,0);
4791 1 : CPPUNIT_ASSERT(bHidden);
4792 :
4793 1 : SCCOL nCol = 0;
4794 1 : SCROW nRow = 0;
4795 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4796 :
4797 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4798 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(1), nCol);
4799 :
4800 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4801 :
4802 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4803 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(2), nCol);
4804 :
4805 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4806 :
4807 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4808 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(5), nCol);
4809 :
4810 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4811 :
4812 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4813 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
4814 :
4815 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4816 :
4817 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), nRow);
4818 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(MAXCOL), nCol);
4819 :
4820 1 : nCol = 2;
4821 1 : nRow = 1;
4822 :
4823 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4824 :
4825 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4826 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(3), nCol);
4827 :
4828 1 : m_pDoc->FindAreaPos(nCol, nRow, 0, SC_MOVE_RIGHT);
4829 :
4830 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), nRow);
4831 1 : CPPUNIT_ASSERT_EQUAL(static_cast<SCCOL>(6), nCol);
4832 :
4833 1 : m_pDoc->DeleteTab(0);
4834 1 : }
4835 :
4836 1 : void Test::testShiftCells()
4837 : {
4838 1 : m_pDoc->InsertTab(0, "foo");
4839 :
4840 1 : OUString aTestVal("Some Text");
4841 :
4842 : // Text into cell E5.
4843 1 : m_pDoc->SetString(4, 3, 0, aTestVal);
4844 :
4845 : // put a Note in cell E5
4846 1 : ScAddress rAddr(4, 3, 0);
4847 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
4848 1 : pNote->SetText(rAddr, "Hello");
4849 :
4850 1 : CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
4851 :
4852 : // Insert cell at D5. This should shift the string cell to right.
4853 1 : m_pDoc->InsertCol(3, 0, 3, 0, 3, 1);
4854 2 : OUString aStr = m_pDoc->GetString(5, 3, 0);
4855 1 : CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
4856 1 : CPPUNIT_ASSERT_MESSAGE("D5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 3, 4, 3, 4));
4857 :
4858 1 : CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(4, 3, 0));
4859 1 : CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(5, 3, 0));
4860 :
4861 : // Delete cell D5, to shift the text cell back into D5.
4862 1 : m_pDoc->DeleteCol(3, 0, 3, 0, 3, 1);
4863 1 : aStr = m_pDoc->GetString(4, 3, 0);
4864 1 : CPPUNIT_ASSERT_MESSAGE("We should have a string cell here.", aStr == aTestVal);
4865 1 : CPPUNIT_ASSERT_MESSAGE("E5 is supposed to be blank.", m_pDoc->IsBlockEmpty(0, 4, 4, 4, 4));
4866 :
4867 1 : CPPUNIT_ASSERT_MESSAGE("there should be NO note", !m_pDoc->HasNote(5, 3, 0));
4868 1 : CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(4, 3, 0));
4869 :
4870 2 : m_pDoc->DeleteTab(0);
4871 1 : }
4872 :
4873 1 : void Test::testNoteBasic()
4874 : {
4875 1 : m_pDoc->InsertTab(0, "PostIts");
4876 :
4877 1 : CPPUNIT_ASSERT(!m_pDoc->HasNotes());
4878 :
4879 : // Check for note's presence in all tables before inserting any notes.
4880 10001 : for (SCTAB i = 0; i <= MAXTAB; ++i)
4881 : {
4882 10000 : bool bHasNotes = m_pDoc->HasTabNotes(i);
4883 10000 : CPPUNIT_ASSERT(!bHasNotes);
4884 : }
4885 :
4886 1 : ScAddress aAddr(2, 2, 0); // cell C3
4887 1 : ScPostIt *pNote = m_pDoc->GetOrCreateNote(aAddr);
4888 :
4889 1 : pNote->SetText(aAddr, "Hello world");
4890 1 : pNote->SetAuthor("Jim Bob");
4891 :
4892 1 : ScPostIt *pGetNote = m_pDoc->GetNote(aAddr);
4893 1 : CPPUNIT_ASSERT_MESSAGE("note should be itself", pGetNote == pNote);
4894 :
4895 : // Insert one row at row 1.
4896 1 : bool bInsertRow = m_pDoc->InsertRow(0, 0, MAXCOL, 0, 1, 1);
4897 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert row", bInsertRow );
4898 :
4899 1 : CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4900 1 : aAddr.IncRow(); // cell C4
4901 1 : CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4902 :
4903 : // Insert column at column A.
4904 1 : bool bInsertCol = m_pDoc->InsertCol(0, 0, MAXROW, 0, 1, 1);
4905 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert column", bInsertCol );
4906 :
4907 1 : CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4908 1 : aAddr.IncCol(); // cell D4
4909 1 : CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4910 :
4911 : // Insert a new sheet to shift the current sheet to the right.
4912 1 : m_pDoc->InsertTab(0, "Table2");
4913 1 : CPPUNIT_ASSERT_MESSAGE("note hasn't moved", m_pDoc->GetNote(aAddr) == NULL);
4914 1 : aAddr.IncTab(); // Move to the next sheet.
4915 1 : CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4916 :
4917 1 : m_pDoc->DeleteTab(0);
4918 1 : aAddr.IncTab(-1);
4919 1 : CPPUNIT_ASSERT_MESSAGE("note not there", m_pDoc->GetNote(aAddr) == pNote);
4920 :
4921 : // Insert cell at C4. This should NOT shift the note position.
4922 1 : bInsertRow = m_pDoc->InsertRow(2, 0, 2, 0, 3, 1);
4923 1 : CPPUNIT_ASSERT_MESSAGE("Failed to insert cell at C4.", bInsertRow);
4924 1 : CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
4925 :
4926 : // Delete cell at C4. Again, this should NOT shift the note position.
4927 1 : m_pDoc->DeleteRow(2, 0, 2, 0, 3, 1);
4928 1 : CPPUNIT_ASSERT_MESSAGE("Note shouldn't have moved but it has.", m_pDoc->GetNote(aAddr) == pNote);
4929 :
4930 : // Now, with the note at D4, delete cell D3. This should shift the note one cell up.
4931 1 : m_pDoc->DeleteRow(3, 0, 3, 0, 2, 1);
4932 1 : aAddr.IncRow(-1); // cell D3
4933 1 : CPPUNIT_ASSERT_MESSAGE("Note at D4 should have shifted up to D3.", m_pDoc->GetNote(aAddr) == pNote);
4934 :
4935 : // Delete column C. This should shift the note one cell left.
4936 1 : m_pDoc->DeleteCol(0, 0, MAXROW, 0, 2, 1);
4937 1 : aAddr.IncCol(-1); // cell C3
4938 1 : CPPUNIT_ASSERT_MESSAGE("Note at D3 should have shifted left to C3.", m_pDoc->GetNote(aAddr) == pNote);
4939 :
4940 : // Insert a text where the note is.
4941 1 : m_pDoc->SetString(aAddr, "Note is here.");
4942 :
4943 : // Delete row 1. This should shift the note from C3 to C2.
4944 1 : m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 0, 1);
4945 1 : aAddr.IncRow(-1); // C2
4946 1 : CPPUNIT_ASSERT_MESSAGE("Note at C3 should have shifted up to C2.", m_pDoc->GetNote(aAddr) == pNote);
4947 :
4948 1 : m_pDoc->DeleteTab(0);
4949 1 : }
4950 :
4951 1 : void Test::testNoteDeleteRow()
4952 : {
4953 1 : m_pDoc->InsertTab(0, "Sheet1");
4954 :
4955 : // We need a drawing layer in order to create caption objects.
4956 1 : m_pDoc->InitDrawLayer(&getDocShell());
4957 :
4958 1 : OUString aHello("Hello");
4959 2 : OUString aJimBob("Jim Bob");
4960 1 : ScAddress aPos(1, 1, 0);
4961 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
4962 1 : pNote->SetText(aPos, aHello);
4963 1 : pNote->SetAuthor(aJimBob);
4964 :
4965 1 : CPPUNIT_ASSERT_MESSAGE("there should be a note", m_pDoc->HasNote(1, 1, 0));
4966 :
4967 : // test with IsBlockEmpty
4968 1 : bool bIgnoreNotes = true;
4969 1 : CPPUNIT_ASSERT_MESSAGE("The Block should be detected as empty (no Notes)", m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
4970 1 : bIgnoreNotes = false;
4971 1 : CPPUNIT_ASSERT_MESSAGE("The Block should NOT be detected as empty", !m_pDoc->IsBlockEmpty(0, 0, 0, 100, 100, bIgnoreNotes));
4972 :
4973 1 : m_pDoc->DeleteRow(0, 0, MAXCOL, 0, 1, 1);
4974 :
4975 1 : CPPUNIT_ASSERT_MESSAGE("there should be no more note", !m_pDoc->HasNote(1, 1, 0));
4976 :
4977 : // Set values and notes into B3:B4.
4978 1 : aPos = ScAddress(1,2,0); // B3
4979 1 : m_pDoc->SetString(aPos, "First");
4980 1 : ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "First Note", false, false);
4981 :
4982 1 : aPos = ScAddress(1,3,0); // B4
4983 1 : m_pDoc->SetString(aPos, "Second");
4984 1 : ScNoteUtil::CreateNoteFromString(*m_pDoc, aPos, "Second Note", false, false);
4985 :
4986 : // Delete row 2.
4987 1 : ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
4988 2 : ScMarkData aMark;
4989 1 : aMark.SelectOneTable(0);
4990 1 : rDocFunc.DeleteCells(ScRange(0,1,0,MAXCOL,1,0), &aMark, DEL_CELLSUP, true, true);
4991 :
4992 : // Check to make sure the notes have shifted upward.
4993 1 : pNote = m_pDoc->GetNote(ScAddress(1,1,0));
4994 1 : CPPUNIT_ASSERT_MESSAGE("B2 should have a note.", pNote);
4995 1 : CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
4996 1 : pNote = m_pDoc->GetNote(ScAddress(1,2,0));
4997 1 : CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
4998 1 : CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
4999 1 : pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5000 1 : CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
5001 :
5002 : // Undo.
5003 :
5004 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
5005 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
5006 1 : m_pDoc->CreateAllNoteCaptions(); // to make sure that all notes have their corresponding caption objects...
5007 :
5008 1 : pUndoMgr->Undo();
5009 1 : pNote = m_pDoc->GetNote(ScAddress(1,1,0));
5010 1 : CPPUNIT_ASSERT_MESSAGE("B2 should NOT have a note.", !pNote);
5011 1 : pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5012 1 : CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5013 1 : CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
5014 1 : pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5015 1 : CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
5016 1 : CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5017 :
5018 : // Delete row 3.
5019 1 : rDocFunc.DeleteCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, DEL_CELLSUP, true, true);
5020 :
5021 1 : pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5022 1 : CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5023 1 : CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5024 1 : pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5025 1 : CPPUNIT_ASSERT_MESSAGE("B4 should NOT have a note.", !pNote);
5026 :
5027 : // Undo and check the result.
5028 1 : pUndoMgr->Undo();
5029 1 : pNote = m_pDoc->GetNote(ScAddress(1,2,0));
5030 1 : CPPUNIT_ASSERT_MESSAGE("B3 should have a note.", pNote);
5031 1 : CPPUNIT_ASSERT_EQUAL(OUString("First Note"), pNote->GetText());
5032 1 : pNote = m_pDoc->GetNote(ScAddress(1,3,0));
5033 1 : CPPUNIT_ASSERT_MESSAGE("B4 should have a note.", pNote);
5034 1 : CPPUNIT_ASSERT_EQUAL(OUString("Second Note"), pNote->GetText());
5035 :
5036 2 : m_pDoc->DeleteTab(0);
5037 1 : }
5038 :
5039 1 : void Test::testNoteDeleteCol()
5040 : {
5041 1 : ScDocument& rDoc = getDocShell().GetDocument();
5042 1 : rDoc.InsertTab(0, "Sheet1");
5043 :
5044 1 : ScAddress rAddr(1, 1, 0);
5045 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
5046 1 : pNote->SetText(rAddr, "Hello");
5047 1 : pNote->SetAuthor("Jim Bob");
5048 :
5049 1 : CPPUNIT_ASSERT_MESSAGE("there should be a note", rDoc.HasNote(1, 1, 0));
5050 :
5051 1 : rDoc.DeleteCol(0, 0, MAXROW, 0, 1, 1);
5052 :
5053 1 : CPPUNIT_ASSERT_MESSAGE("there should be no more note", !rDoc.HasNote(1, 1, 0));
5054 :
5055 1 : rDoc.DeleteTab(0);
5056 1 : }
5057 :
5058 1 : void Test::testNoteLifeCycle()
5059 : {
5060 1 : m_pDoc->InsertTab(0, "Test");
5061 :
5062 : // We need a drawing layer in order to create caption objects.
5063 1 : m_pDoc->InitDrawLayer(&getDocShell());
5064 :
5065 1 : ScAddress aPos(1,1,0);
5066 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
5067 1 : CPPUNIT_ASSERT_MESSAGE("Failed to insert a new cell comment.", pNote);
5068 :
5069 1 : pNote->SetText(aPos, "New note");
5070 1 : ScPostIt* pNote2 = m_pDoc->ReleaseNote(aPos);
5071 1 : CPPUNIT_ASSERT_MESSAGE("This note instance is expected to be identical to the original.", pNote == pNote2);
5072 1 : CPPUNIT_ASSERT_MESSAGE("The note shouldn't be here after it's been released.", !m_pDoc->HasNote(aPos));
5073 :
5074 : // Modify the internal state of the note instance to make sure it's really
5075 : // been released.
5076 1 : pNote->SetText(aPos, "New content");
5077 :
5078 : // Re-insert the note back to the same place.
5079 1 : m_pDoc->SetNote(aPos, pNote);
5080 1 : const SdrCaptionObj* pCaption = pNote->GetOrCreateCaption(aPos);
5081 1 : CPPUNIT_ASSERT_MESSAGE("Failed to create a caption object.", pCaption);
5082 2 : CPPUNIT_ASSERT_MESSAGE("This caption should belong to the drawing layer of the document.",
5083 1 : pCaption->GetModel() == m_pDoc->GetDrawLayer());
5084 :
5085 : // Copy B2 with note to a clipboard.
5086 :
5087 1 : ScClipParam aClipParam(aPos, false);
5088 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
5089 2 : ScMarkData aMarkData;
5090 1 : aMarkData.SelectOneTable(0);
5091 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMarkData, false, false, true, true, false);
5092 :
5093 1 : ScPostIt* pClipNote = aClipDoc.GetNote(aPos);
5094 1 : CPPUNIT_ASSERT_MESSAGE("Failed to copy note to the clipboard.", pClipNote);
5095 2 : CPPUNIT_ASSERT_MESSAGE("Note on the clipboard should share the same caption object from the original.",
5096 1 : pClipNote->GetCaption() == pCaption);
5097 :
5098 2 : m_pDoc->DeleteTab(0);
5099 1 : }
5100 :
5101 1 : void Test::testNoteCopyPaste()
5102 : {
5103 1 : m_pDoc->InsertTab(0, "Test");
5104 :
5105 : // We need a drawing layer in order to create caption objects.
5106 1 : m_pDoc->InitDrawLayer(&getDocShell());
5107 :
5108 : // Insert in B2 a text and cell comment.
5109 1 : ScAddress aPos(1,1,0);
5110 1 : m_pDoc->SetString(aPos, "Text");
5111 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(aPos);
5112 1 : CPPUNIT_ASSERT(pNote);
5113 1 : pNote->SetText(aPos, "Note1");
5114 :
5115 : // Insert in B4 a number and cell comment.
5116 1 : aPos.SetRow(3);
5117 1 : m_pDoc->SetValue(aPos, 1.1);
5118 1 : pNote = m_pDoc->GetOrCreateNote(aPos);
5119 1 : CPPUNIT_ASSERT(pNote);
5120 1 : pNote->SetText(aPos, "Note2");
5121 :
5122 : // Copy B2:B4 to clipboard.
5123 1 : ScMarkData aMark;
5124 1 : aMark.SelectOneTable(0);
5125 1 : ScRange aCopyRange(1,1,0,1,3,0);
5126 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
5127 1 : aClipDoc.ResetClip(m_pDoc, &aMark);
5128 2 : ScClipParam aClipParam(aCopyRange, false);
5129 1 : m_pDoc->CopyToClip(aClipParam, &aClipDoc, &aMark, false, false, false, true, false);
5130 :
5131 : // Make sure the notes are in the clipboard.
5132 1 : pNote = aClipDoc.GetNote(ScAddress(1,1,0));
5133 1 : CPPUNIT_ASSERT(pNote);
5134 1 : CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote->GetText());
5135 :
5136 1 : pNote = aClipDoc.GetNote(ScAddress(1,3,0));
5137 1 : CPPUNIT_ASSERT(pNote);
5138 1 : CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote->GetText());
5139 :
5140 : // Paste to B6:B8 but only cell notes.
5141 1 : ScRange aDestRange(1,5,0,1,7,0);
5142 1 : m_pDoc->CopyFromClip(aDestRange, aMark, IDF_NOTE, NULL, &aClipDoc);
5143 :
5144 : // Make sure the notes are there.
5145 1 : pNote = m_pDoc->GetNote(ScAddress(1,5,0));
5146 1 : CPPUNIT_ASSERT(pNote);
5147 1 : CPPUNIT_ASSERT_EQUAL(OUString("Note1"), pNote->GetText());
5148 :
5149 1 : pNote = m_pDoc->GetNote(ScAddress(1,7,0));
5150 1 : CPPUNIT_ASSERT(pNote);
5151 1 : CPPUNIT_ASSERT_EQUAL(OUString("Note2"), pNote->GetText());
5152 :
5153 2 : m_pDoc->DeleteTab(0);
5154 1 : }
5155 :
5156 1 : void Test::testAreasWithNotes()
5157 : {
5158 1 : ScDocument& rDoc = getDocShell().GetDocument();
5159 1 : rDoc.InsertTab(0, "Sheet1");
5160 :
5161 1 : ScAddress rAddr(1, 5, 0);
5162 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
5163 1 : pNote->SetText(rAddr, "Hello");
5164 1 : pNote->SetAuthor("Jim Bob");
5165 1 : ScAddress rAddrMin(2, 2, 0);
5166 1 : ScPostIt* pNoteMin = m_pDoc->GetOrCreateNote(rAddrMin);
5167 1 : pNoteMin->SetText(rAddrMin, "Hello");
5168 :
5169 : SCCOL col;
5170 : SCROW row;
5171 1 : bool dataFound = false;
5172 :
5173 : // only cell notes (empty content)
5174 :
5175 1 : dataFound = rDoc.GetDataStart(0,col,row);
5176 :
5177 1 : CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
5178 1 : CPPUNIT_ASSERT_MESSAGE("DataStart wrong col for notes", col == 1);
5179 1 : CPPUNIT_ASSERT_MESSAGE("DataStart wrong row for notes", row == 2);
5180 :
5181 1 : dataFound = rDoc.GetCellArea(0,col,row);
5182 :
5183 1 : CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
5184 1 : CPPUNIT_ASSERT_MESSAGE("CellArea wrong col for notes", col == 2);
5185 1 : CPPUNIT_ASSERT_MESSAGE("CellArea wrong row for notes", row == 5);
5186 :
5187 1 : bool bNotes = true;
5188 1 : dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5189 :
5190 1 : CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5191 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col for notes", col == 2);
5192 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row for notes", row == 5);
5193 :
5194 1 : bNotes = false;
5195 1 : dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5196 1 : CPPUNIT_ASSERT_MESSAGE("No PrintArea should be found", !dataFound);
5197 :
5198 1 : bNotes = true;
5199 1 : dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5200 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5201 1 : CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 5);
5202 :
5203 1 : dataFound = rDoc.GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
5204 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5205 1 : CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row for notes", row == 2);
5206 :
5207 1 : bNotes = false;
5208 1 : dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // col 0 & 1
5209 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer should be found", !dataFound);
5210 :
5211 : // now add cells with value, check that notes are taken into accompt in good cases
5212 :
5213 1 : m_pDoc->SetString(0, 3, 0, "Some Text");
5214 1 : m_pDoc->SetString(3, 3, 0, "Some Text");
5215 :
5216 1 : dataFound = rDoc.GetDataStart(0,col,row);
5217 :
5218 1 : CPPUNIT_ASSERT_MESSAGE("No DataStart found", dataFound);
5219 1 : CPPUNIT_ASSERT_MESSAGE("DataStart wrong col", col == 0);
5220 1 : CPPUNIT_ASSERT_MESSAGE("DataStart wrong row", row == 2);
5221 :
5222 1 : dataFound = rDoc.GetCellArea(0,col,row);
5223 :
5224 1 : CPPUNIT_ASSERT_MESSAGE("No CellArea found", dataFound);
5225 1 : CPPUNIT_ASSERT_MESSAGE("CellArea wrong col", col == 3);
5226 1 : CPPUNIT_ASSERT_MESSAGE("CellArea wrong row", row == 5);
5227 :
5228 1 : bNotes = true;
5229 1 : dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5230 :
5231 1 : CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5232 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
5233 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 5);
5234 :
5235 1 : bNotes = false;
5236 1 : dataFound = rDoc.GetPrintArea(0,col,row, bNotes);
5237 1 : CPPUNIT_ASSERT_MESSAGE("No PrintArea found", dataFound);
5238 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong col", col == 3);
5239 1 : CPPUNIT_ASSERT_MESSAGE("PrintArea wrong row", row == 3);
5240 :
5241 1 : bNotes = true;
5242 1 : dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5243 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5244 1 : CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 5);
5245 :
5246 1 : dataFound = rDoc.GetPrintAreaVer(0,2,3,row, bNotes); // cols 2 & 3
5247 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5248 1 : CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
5249 :
5250 1 : bNotes = false;
5251 1 : dataFound = rDoc.GetPrintAreaVer(0,0,1,row, bNotes); // cols 0 & 1
5252 1 : CPPUNIT_ASSERT_MESSAGE("No PrintAreaVer found", dataFound);
5253 1 : CPPUNIT_ASSERT_MESSAGE("PrintAreaVer wrong row", row == 3);
5254 :
5255 1 : rDoc.DeleteTab(0);
5256 1 : }
5257 :
5258 1 : void Test::testAnchoredRotatedShape()
5259 : {
5260 1 : m_pDoc->InsertTab(0, "TestTab");
5261 : SCROW nRow1, nRow2;
5262 1 : bool bHidden = m_pDoc->RowHidden(0, 0, &nRow1, &nRow2);
5263 1 : CPPUNIT_ASSERT_MESSAGE("new sheet should have all rows visible", !bHidden && nRow1 == 0 && nRow2 == MAXROW);
5264 :
5265 1 : m_pDoc->InitDrawLayer();
5266 1 : ScDrawLayer *pDrawLayer = m_pDoc->GetDrawLayer();
5267 1 : CPPUNIT_ASSERT_MESSAGE("must have a draw layer", pDrawLayer != NULL);
5268 1 : SdrPage* pPage = pDrawLayer->GetPage(0);
5269 1 : CPPUNIT_ASSERT_MESSAGE("must have a draw page", pPage != NULL);
5270 1 : m_pDoc->SetRowHeightRange( 0, MAXROW, 0, sc::HMMToTwips( 1000 ) );
5271 1 : const long TOLERANCE = 30; //30 hmm
5272 1024 : for ( SCCOL nCol = 0; nCol < MAXCOL; ++nCol )
5273 1023 : m_pDoc->SetColWidth( nCol, 0, sc::HMMToTwips( 1000 ) );
5274 : {
5275 : //Add a rect
5276 1 : Rectangle aRect( 4000, 5000, 10000, 7000 );
5277 :
5278 1 : Rectangle aRotRect( 6000, 3000, 8000, 9000 );
5279 1 : SdrRectObj *pObj = new SdrRectObj(aRect);
5280 1 : pPage->InsertObject(pObj);
5281 1 : Point aRef1(pObj->GetSnapRect().Center());
5282 1 : int nAngle = 9000; //90 deg.
5283 1 : double nSin=sin(nAngle*nPi180);
5284 1 : double nCos=cos(nAngle*nPi180);
5285 1 : pObj->Rotate(aRef1,nAngle,nSin,nCos);
5286 :
5287 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
5288 :
5289 1 : Rectangle aSnap = pObj->GetSnapRect();
5290 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
5291 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
5292 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Left(), aSnap.Left(), TOLERANCE ) );
5293 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.Top(), aSnap.Top(), TOLERANCE ) );
5294 :
5295 1 : ScDrawObjData aAnchor;
5296 1 : ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
5297 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object meta-data.", pData);
5298 :
5299 1 : aAnchor.maStart = pData->maStart;
5300 1 : aAnchor.maEnd = pData->maEnd;
5301 :
5302 1 : m_pDoc->SetDrawPageSize(0);
5303 :
5304 : // increase row 5 by 2000 hmm
5305 1 : m_pDoc->SetRowHeight( 5, 0, sc::HMMToTwips( 3000 ) );
5306 : // increase col 6 by 1000 hmm
5307 1 : m_pDoc->SetColWidth( 6, 0, sc::HMMToTwips( 2000 ) );
5308 :
5309 1 : aRotRect.setWidth( aRotRect.GetWidth() + 1000 );
5310 1 : aRotRect.setHeight( aRotRect.GetHeight() + 2000 );
5311 :
5312 1 : m_pDoc->SetDrawPageSize(0);
5313 :
5314 1 : aSnap = pObj->GetSnapRect();
5315 :
5316 : // ensure that width and height have been adjusted accordingly
5317 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetHeight(), aSnap.GetHeight(), TOLERANCE ) );
5318 1 : CPPUNIT_ASSERT_EQUAL( true, testEqualsWithTolerance( aRotRect.GetWidth(), aSnap.GetWidth(), TOLERANCE ) );
5319 :
5320 : // ensure that anchor start and end addresses haven't changed
5321 1 : CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Row(), pData->maStart.Row() ); // start row 0
5322 1 : CPPUNIT_ASSERT_EQUAL( aAnchor.maStart.Col(), pData->maStart.Col() ); // start column 5
5323 1 : CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Row(), pData->maEnd.Row() ); // end row 3
5324 1 : CPPUNIT_ASSERT_EQUAL( aAnchor.maEnd.Col(), pData->maEnd.Col() ); // end col 7
5325 : }
5326 1 : m_pDoc->DeleteTab(0);
5327 1 : }
5328 :
5329 1 : void Test::testCellTextWidth()
5330 : {
5331 1 : m_pDoc->InsertTab(0, "Test");
5332 :
5333 1 : ScAddress aTopCell(0, 0, 0);
5334 :
5335 : // Sheet is empty.
5336 1 : boost::scoped_ptr<ScColumnTextWidthIterator> pIter(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5337 1 : CPPUNIT_ASSERT_MESSAGE("Column should have no text widths stored.", !pIter->hasCell());
5338 :
5339 : // Sheet only has one cell.
5340 1 : m_pDoc->SetString(0, 0, 0, "Only one cell");
5341 1 : pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5342 1 : CPPUNIT_ASSERT_MESSAGE("Column should have a cell.", pIter->hasCell());
5343 1 : SCROW nTestRow = 0;
5344 1 : CPPUNIT_ASSERT_EQUAL(nTestRow, pIter->getPos());
5345 :
5346 : // Setting a text width here should commit it to the column.
5347 1 : sal_uInt16 nTestVal = 432;
5348 1 : pIter->setValue(nTestVal);
5349 1 : CPPUNIT_ASSERT_EQUAL(nTestVal, m_pDoc->GetTextWidth(aTopCell));
5350 :
5351 : // Set values to row 2 through 6.
5352 6 : for (SCROW i = 2; i <= 6; ++i)
5353 5 : m_pDoc->SetString(0, i, 0, "foo");
5354 :
5355 : // Set values to row 10 through 18.
5356 10 : for (SCROW i = 10; i <= 18; ++i)
5357 9 : m_pDoc->SetString(0, i, 0, "foo");
5358 :
5359 : {
5360 : // Full range.
5361 1 : pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5362 1 : SCROW aRows[] = { 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
5363 1 : size_t n = SAL_N_ELEMENTS(aRows);
5364 16 : for (size_t i = 0; i < n; ++i, pIter->next())
5365 : {
5366 15 : CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5367 15 : CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5368 : }
5369 1 : CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5370 : }
5371 :
5372 : {
5373 : // Specify start and end rows (6 - 16)
5374 1 : ScAddress aStart = aTopCell;
5375 1 : aStart.SetRow(6);
5376 1 : pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aStart, 16));
5377 1 : SCROW aRows[] = { 6, 10, 11, 12, 13, 14, 15, 16 };
5378 1 : size_t n = SAL_N_ELEMENTS(aRows);
5379 9 : for (size_t i = 0; i < n; ++i, pIter->next())
5380 : {
5381 8 : CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5382 8 : CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5383 : }
5384 1 : CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5385 : }
5386 :
5387 : // Clear from row 3 to row 17. After this, we should only have cells at rows 0, 2 and 18.
5388 1 : clearRange(m_pDoc, ScRange(0, 3, 0, 0, 17, 0));
5389 :
5390 : {
5391 : // Full range again.
5392 1 : pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5393 1 : SCROW aRows[] = { 0, 2, 18 };
5394 1 : size_t n = SAL_N_ELEMENTS(aRows);
5395 4 : for (size_t i = 0; i < n; ++i, pIter->next())
5396 : {
5397 3 : CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5398 3 : CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5399 : }
5400 1 : CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5401 : }
5402 :
5403 : // Delete row 2 which shifts all cells below row 2 upward. After this, we
5404 : // should only have cells at rows 0 and 17.
5405 1 : m_pDoc->DeleteRow(0, 0, MAXCOL, MAXTAB, 2, 1);
5406 : {
5407 : // Full range again.
5408 1 : pIter.reset(new ScColumnTextWidthIterator(*m_pDoc, aTopCell, MAXROW));
5409 1 : SCROW aRows[] = { 0, 17 };
5410 1 : size_t n = SAL_N_ELEMENTS(aRows);
5411 3 : for (size_t i = 0; i < n; ++i, pIter->next())
5412 : {
5413 2 : CPPUNIT_ASSERT_MESSAGE("Cell expected, but not there.", pIter->hasCell());
5414 2 : CPPUNIT_ASSERT_EQUAL(aRows[i], pIter->getPos());
5415 : }
5416 1 : CPPUNIT_ASSERT_MESSAGE("Iterator should have ended.", !pIter->hasCell());
5417 : }
5418 :
5419 1 : m_pDoc->DeleteTab(0);
5420 1 : }
5421 :
5422 5 : bool checkEditTextIterator(sc::EditTextIterator& rIter, const char** pChecks)
5423 : {
5424 5 : const EditTextObject* pText = rIter.first();
5425 5 : const char* p = *pChecks;
5426 :
5427 24 : for (int i = 0; i < 100; ++i) // cap it to 100 loops.
5428 : {
5429 24 : if (!pText)
5430 : // No more edit cells. The check string array should end too.
5431 5 : return p == NULL;
5432 :
5433 19 : if (!p)
5434 : // More edit cell, but no more check string. Bad.
5435 0 : return false;
5436 :
5437 19 : if (pText->GetParagraphCount() != 1)
5438 : // For this test, we don't handle multi-paragraph text.
5439 0 : return false;
5440 :
5441 19 : if (pText->GetText(0) != OUString::createFromAscii(p))
5442 : // Text differs from what's expected.
5443 0 : return false;
5444 :
5445 19 : pText = rIter.next();
5446 19 : ++pChecks;
5447 19 : p = *pChecks;
5448 : }
5449 :
5450 0 : return false;
5451 : }
5452 :
5453 1 : void Test::testEditTextIterator()
5454 : {
5455 1 : m_pDoc->InsertTab(0, "Test");
5456 :
5457 : {
5458 : // First, try with an empty sheet.
5459 1 : sc::EditTextIterator aIter(*m_pDoc,0);
5460 1 : const char* pChecks[] = { NULL };
5461 1 : CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5462 : }
5463 :
5464 1 : ScFieldEditEngine& rEditEngine = m_pDoc->GetEditEngine();
5465 :
5466 : {
5467 : // Only set one edit cell.
5468 1 : rEditEngine.SetText("A2");
5469 1 : m_pDoc->SetEditText(ScAddress(0,1,0), rEditEngine.CreateTextObject());
5470 1 : sc::EditTextIterator aIter(*m_pDoc,0);
5471 1 : const char* pChecks[] = { "A2", NULL };
5472 1 : CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5473 : }
5474 :
5475 : {
5476 : // Add a series of edit cells.
5477 1 : rEditEngine.SetText("A5");
5478 1 : m_pDoc->SetEditText(ScAddress(0,4,0), rEditEngine.CreateTextObject());
5479 1 : rEditEngine.SetText("A6");
5480 1 : m_pDoc->SetEditText(ScAddress(0,5,0), rEditEngine.CreateTextObject());
5481 1 : rEditEngine.SetText("A7");
5482 1 : m_pDoc->SetEditText(ScAddress(0,6,0), rEditEngine.CreateTextObject());
5483 1 : sc::EditTextIterator aIter(*m_pDoc,0);
5484 1 : const char* pChecks[] = { "A2", "A5", "A6", "A7", NULL };
5485 1 : CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5486 : }
5487 :
5488 : {
5489 : // Add more edit cells to column C. Skip column B.
5490 1 : rEditEngine.SetText("C1");
5491 1 : m_pDoc->SetEditText(ScAddress(2,0,0), rEditEngine.CreateTextObject());
5492 1 : rEditEngine.SetText("C3");
5493 1 : m_pDoc->SetEditText(ScAddress(2,2,0), rEditEngine.CreateTextObject());
5494 1 : rEditEngine.SetText("C4");
5495 1 : m_pDoc->SetEditText(ScAddress(2,3,0), rEditEngine.CreateTextObject());
5496 1 : sc::EditTextIterator aIter(*m_pDoc,0);
5497 1 : const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
5498 1 : CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5499 : }
5500 :
5501 : {
5502 : // Add some numeric, string and formula cells. This shouldn't affect the outcome.
5503 1 : m_pDoc->SetString(ScAddress(0,99,0), "=ROW()");
5504 1 : m_pDoc->SetValue(ScAddress(1,3,0), 1.2);
5505 1 : m_pDoc->SetString(ScAddress(2,4,0), "Simple string");
5506 1 : sc::EditTextIterator aIter(*m_pDoc,0);
5507 1 : const char* pChecks[] = { "A2", "A5", "A6", "A7", "C1", "C3", "C4", NULL };
5508 1 : CPPUNIT_ASSERT_MESSAGE("Wrong iterator behavior.", checkEditTextIterator(aIter, pChecks));
5509 : }
5510 :
5511 1 : m_pDoc->DeleteTab(0);
5512 1 : }
5513 :
5514 1 : void Test::testCondFormatINSDEL()
5515 : {
5516 : // fdo#62206
5517 1 : m_pDoc->InsertTab(0, "Test");
5518 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5519 :
5520 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5521 1 : ScRangeList aRangeList(ScRange(0,0,0,0,3,0));
5522 1 : pFormat->SetRange(aRangeList);
5523 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5524 1 : pFormat->AddEntry(pEntry);
5525 :
5526 1 : m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5527 1 : pList->InsertNew(pFormat);
5528 :
5529 1 : m_pDoc->InsertCol(0,0,MAXROW,0,0,2);
5530 1 : const ScRangeList& rRange = pFormat->GetRange();
5531 1 : CPPUNIT_ASSERT(rRange == ScRange(2,0,0,2,3,0));
5532 :
5533 2 : OUString aExpr = pEntry->GetExpression(ScAddress(2,0,0), 0);
5534 1 : CPPUNIT_ASSERT_EQUAL(aExpr, OUString("D2"));
5535 :
5536 2 : m_pDoc->DeleteTab(0);
5537 1 : }
5538 :
5539 1 : void Test::testCondFormatInsertCol()
5540 : {
5541 1 : m_pDoc->InsertTab(0, "Test");
5542 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5543 :
5544 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5545 1 : ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
5546 1 : pFormat->SetRange(aRangeList);
5547 :
5548 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5549 1 : pFormat->AddEntry(pEntry);
5550 :
5551 1 : m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5552 1 : pList->InsertNew(pFormat);
5553 :
5554 1 : m_pDoc->InsertCol(0,0,MAXROW,0,4,2);
5555 1 : const ScRangeList& rRange = pFormat->GetRange();
5556 1 : CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,5,3,0)), rRange);
5557 :
5558 1 : m_pDoc->DeleteTab(0);
5559 1 : }
5560 :
5561 1 : void Test::testCondFormatInsertRow()
5562 : {
5563 1 : m_pDoc->InsertTab(0, "Test");
5564 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5565 :
5566 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5567 1 : ScRangeList aRangeList(ScRange(0,0,0,3,3,0));
5568 1 : pFormat->SetRange(aRangeList);
5569 :
5570 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5571 1 : pFormat->AddEntry(pEntry);
5572 :
5573 1 : m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5574 1 : pList->InsertNew(pFormat);
5575 :
5576 1 : m_pDoc->InsertRow(0,0,MAXCOL,0,4,2);
5577 1 : const ScRangeList& rRange = pFormat->GetRange();
5578 1 : CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,0,3,5,0)), rRange);
5579 :
5580 1 : m_pDoc->DeleteTab(0);
5581 1 : }
5582 :
5583 1 : void Test::testCondFormatInsertDeleteSheets()
5584 : {
5585 1 : m_pDoc->InsertTab(0, "Test");
5586 :
5587 : // Add a conditional format to B2:B4.
5588 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5589 1 : pFormat->SetRange(ScRange(1,1,0,1,3,0));
5590 :
5591 1 : sal_uLong nKey = m_pDoc->AddCondFormat(pFormat, 0);
5592 :
5593 : // Add condition in which if the value equals 2, set the "Result" style.
5594 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(
5595 1 : SC_COND_EQUAL, "=2", "" , m_pDoc, ScAddress(0,0,0), ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5596 1 : pFormat->AddEntry(pEntry);
5597 :
5598 : // Apply the format to the range.
5599 1 : m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, nKey);
5600 :
5601 : // Make sure this conditional format entry is really there.
5602 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5603 1 : CPPUNIT_ASSERT(pList);
5604 1 : const ScConditionalFormat* pCheck = pList->GetFormat(nKey);
5605 1 : CPPUNIT_ASSERT_MESSAGE("Wrong condntional format instance.", pCheck == pFormat);
5606 :
5607 : // ... and its range is B2:B4.
5608 1 : ScRangeList aCheckRange = pCheck->GetRange();
5609 1 : CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5610 1 : const ScRange* pRange = aCheckRange[0];
5611 1 : CPPUNIT_ASSERT(pRange);
5612 1 : CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4.", *pRange == ScRange(1,1,0,1,3,0));
5613 :
5614 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
5615 :
5616 : // Insert a new sheet at the left.
5617 1 : bool bInserted = rFunc.InsertTable(0, "Inserted", true, true);
5618 1 : CPPUNIT_ASSERT(bInserted);
5619 :
5620 1 : pList = m_pDoc->GetCondFormList(1);
5621 1 : CPPUNIT_ASSERT(pList);
5622 1 : pCheck = pList->GetFormat(nKey);
5623 1 : CPPUNIT_ASSERT(pCheck);
5624 :
5625 : // Make sure the range also got shifted.
5626 1 : aCheckRange = pCheck->GetRange();
5627 1 : CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5628 1 : pRange = aCheckRange[0];
5629 1 : CPPUNIT_ASSERT(pRange);
5630 1 : CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the sheet insertion.", *pRange == ScRange(1,1,1,1,3,1));
5631 :
5632 : // Delete the sheet to the left.
5633 1 : bool bDeleted = rFunc.DeleteTable(0, true, true);
5634 1 : CPPUNIT_ASSERT(bDeleted);
5635 :
5636 1 : pList = m_pDoc->GetCondFormList(0);
5637 1 : CPPUNIT_ASSERT(pList);
5638 1 : pCheck = pList->GetFormat(nKey);
5639 1 : CPPUNIT_ASSERT(pCheck);
5640 :
5641 : // Make sure the range got shifted back.
5642 1 : aCheckRange = pCheck->GetRange();
5643 1 : CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5644 1 : pRange = aCheckRange[0];
5645 1 : CPPUNIT_ASSERT(pRange);
5646 1 : CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the sheet removal.", *pRange == ScRange(1,1,0,1,3,0));
5647 :
5648 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
5649 1 : CPPUNIT_ASSERT(pUndoMgr);
5650 :
5651 : // Undo and re-check.
5652 1 : pUndoMgr->Undo();
5653 :
5654 1 : pList = m_pDoc->GetCondFormList(1);
5655 1 : CPPUNIT_ASSERT(pList);
5656 1 : pCheck = pList->GetFormat(nKey);
5657 1 : CPPUNIT_ASSERT(pCheck);
5658 :
5659 1 : aCheckRange = pCheck->GetRange();
5660 1 : CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5661 1 : pRange = aCheckRange[0];
5662 1 : CPPUNIT_ASSERT(pRange);
5663 1 : CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 2nd sheet after the undo of the sheet removal.", *pRange == ScRange(1,1,1,1,3,1));
5664 :
5665 : #if 0 // TODO : Undo of sheet insertion currently depends on the presence of
5666 : // view shell, and crashes when executed during cppunit run.
5667 :
5668 : // Undo again and re-check.
5669 : pUndoMgr->Undo();
5670 :
5671 : pList = m_pDoc->GetCondFormList(0);
5672 : CPPUNIT_ASSERT(pList);
5673 : pCheck = pList->GetFormat(nKey);
5674 : CPPUNIT_ASSERT(pCheck);
5675 :
5676 : // Make sure the range got shifted back.
5677 : aCheckRange = pCheck->GetRange();
5678 : CPPUNIT_ASSERT_MESSAGE("This should be a single range.", aCheckRange.size() == 1);
5679 : pRange = aCheckRange[0];
5680 : CPPUNIT_ASSERT(pRange);
5681 : CPPUNIT_ASSERT_MESSAGE("Format should be applied to B2:B4 on the 1st sheet after the undo of sheet insertion.", *pRange == ScRange(1,1,0,1,3,0));
5682 : #else
5683 1 : m_pDoc->DeleteTab(1);
5684 : #endif
5685 :
5686 1 : m_pDoc->DeleteTab(0);
5687 1 : }
5688 :
5689 1 : void Test::testCondCopyPaste()
5690 : {
5691 1 : m_pDoc->InsertTab(0, "Test");
5692 :
5693 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5694 1 : ScRange aCondFormatRange(0,0,0,3,3,0);
5695 1 : ScRangeList aRangeList(aCondFormatRange);
5696 1 : pFormat->SetRange(aRangeList);
5697 :
5698 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5699 1 : pFormat->AddEntry(pEntry);
5700 1 : sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5701 :
5702 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
5703 1 : copyToClip(m_pDoc, aCondFormatRange, &aClipDoc);
5704 :
5705 1 : ScRange aTargetRange(4,4,0,7,7,0);
5706 1 : pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5707 :
5708 1 : ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(7,7,0);
5709 1 : CPPUNIT_ASSERT(pPastedFormat);
5710 :
5711 1 : CPPUNIT_ASSERT_EQUAL(ScRangeList(aTargetRange), pPastedFormat->GetRange());
5712 1 : CPPUNIT_ASSERT( nIndex != pPastedFormat->GetKey());
5713 1 : const SfxPoolItem* pItem = m_pDoc->GetAttr( 7, 7, 0, ATTR_CONDITIONAL );
5714 1 : const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5715 :
5716 1 : CPPUNIT_ASSERT(pCondFormatItem);
5717 1 : CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5718 1 : CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5719 :
5720 2 : m_pDoc->DeleteTab(0);
5721 1 : }
5722 :
5723 1 : void Test::testCondCopyPasteSingleCell()
5724 : {
5725 1 : m_pDoc->InsertTab(0, "Test");
5726 :
5727 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5728 1 : ScRange aCondFormatRange(0,0,0,3,3,0);
5729 1 : ScRangeList aRangeList(aCondFormatRange);
5730 1 : pFormat->SetRange(aRangeList);
5731 :
5732 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5733 1 : pFormat->AddEntry(pEntry);
5734 1 : sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5735 :
5736 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
5737 1 : copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
5738 :
5739 1 : ScRange aTargetRange(4,4,0,4,4,0);
5740 1 : pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5741 :
5742 1 : ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4,4,0);
5743 1 : CPPUNIT_ASSERT(pPastedFormat);
5744 :
5745 1 : CPPUNIT_ASSERT_EQUAL(ScRangeList(aTargetRange), pPastedFormat->GetRange());
5746 1 : CPPUNIT_ASSERT( nIndex != pPastedFormat->GetKey());
5747 1 : const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, 4, 0, ATTR_CONDITIONAL );
5748 1 : const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5749 :
5750 1 : CPPUNIT_ASSERT(pCondFormatItem);
5751 1 : CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5752 1 : CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5753 :
5754 2 : m_pDoc->DeleteTab(0);
5755 1 : }
5756 :
5757 1 : void Test::testCondCopyPasteSingleCellToRange()
5758 : {
5759 1 : m_pDoc->InsertTab(0, "Test");
5760 :
5761 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5762 1 : ScRange aCondFormatRange(0,0,0,3,3,0);
5763 1 : ScRangeList aRangeList(aCondFormatRange);
5764 1 : pFormat->SetRange(aRangeList);
5765 :
5766 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5767 1 : pFormat->AddEntry(pEntry);
5768 1 : sal_uLong nIndex = m_pDoc->AddCondFormat(pFormat, 0);
5769 :
5770 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
5771 1 : copyToClip(m_pDoc, ScRange(0,0,0,0,0,0), &aClipDoc);
5772 :
5773 1 : ScRange aTargetRange(4,4,0,4,8,0);
5774 1 : pasteFromClip(m_pDoc, aTargetRange, &aClipDoc);
5775 :
5776 2 : std::set<sal_uLong> aCondFormatIndices;
5777 6 : for(SCROW nRow = 4; nRow <= 8; ++nRow)
5778 : {
5779 5 : ScConditionalFormat* pPastedFormat = m_pDoc->GetCondFormat(4, nRow, 0);
5780 5 : CPPUNIT_ASSERT(pPastedFormat);
5781 :
5782 5 : CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(4, nRow, 0)), pPastedFormat->GetRange());
5783 5 : sal_uLong nPastedKey = pPastedFormat->GetKey();
5784 5 : CPPUNIT_ASSERT( nIndex != nPastedKey);
5785 5 : const SfxPoolItem* pItem = m_pDoc->GetAttr( 4, nRow, 0, ATTR_CONDITIONAL );
5786 5 : const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5787 :
5788 5 : CPPUNIT_ASSERT(pCondFormatItem);
5789 5 : CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5790 5 : CPPUNIT_ASSERT( nIndex != pCondFormatItem->GetCondFormatData().at(0) );
5791 5 : auto itr = aCondFormatIndices.find(nPastedKey);
5792 5 : CPPUNIT_ASSERT(itr == aCondFormatIndices.end());
5793 5 : aCondFormatIndices.insert(nPastedKey);
5794 : }
5795 :
5796 2 : m_pDoc->DeleteTab(0);
5797 1 : }
5798 :
5799 1 : void Test::testCondCopyPasteSheetBetweenDoc()
5800 : {
5801 1 : m_pDoc->InsertTab(0, "Test");
5802 :
5803 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5804 1 : ScRange aCondFormatRange(0,0,0,3,3,0);
5805 1 : ScRangeList aRangeList(aCondFormatRange);
5806 1 : pFormat->SetRange(aRangeList);
5807 :
5808 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5809 1 : pFormat->AddEntry(pEntry);
5810 1 : m_pDoc->AddCondFormat(pFormat, 0);
5811 :
5812 2 : ScDocument aDoc;
5813 1 : aDoc.TransferTab(m_pDoc, 0, 0, true);
5814 :
5815 1 : ScConditionalFormatList* pList = aDoc.GetCondFormList(0);
5816 1 : CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
5817 :
5818 2 : m_pDoc->DeleteTab(0);
5819 1 : }
5820 :
5821 1 : void Test::testCondCopyPasteSheet()
5822 : {
5823 1 : m_pDoc->InsertTab(0, "Test");
5824 :
5825 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5826 1 : ScRange aCondFormatRange(0,0,0,3,3,0);
5827 1 : ScRangeList aRangeList(aCondFormatRange);
5828 1 : pFormat->SetRange(aRangeList);
5829 :
5830 1 : ScCondFormatEntry* pEntry = new ScCondFormatEntry(SC_COND_DIRECT,"=B2","",m_pDoc,ScAddress(0,0,0),ScGlobal::GetRscString(STR_STYLENAME_RESULT));
5831 1 : pFormat->AddEntry(pEntry);
5832 1 : m_pDoc->AddCondFormat(pFormat, 0);
5833 :
5834 1 : m_pDoc->CopyTab(0, SC_TAB_APPEND);
5835 :
5836 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(1);
5837 1 : CPPUNIT_ASSERT_EQUAL(size_t(1), pList->size());
5838 :
5839 1 : ScConditionalFormat& rFormat = *pList->begin();
5840 1 : const ScRangeList& rRange = rFormat.GetRange();
5841 1 : CPPUNIT_ASSERT_EQUAL(ScRangeList(ScRange(0,0,1,3,3,1)), rRange);
5842 1 : sal_uInt32 nKey = rFormat.GetKey();
5843 1 : const SfxPoolItem* pItem = m_pDoc->GetAttr( 2, 2, 1, ATTR_CONDITIONAL );
5844 1 : const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
5845 :
5846 1 : CPPUNIT_ASSERT(pCondFormatItem);
5847 1 : CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormatItem->GetCondFormatData().size());
5848 1 : CPPUNIT_ASSERT( nKey == pCondFormatItem->GetCondFormatData().at(0) );
5849 :
5850 1 : m_pDoc->DeleteTab(1);
5851 1 : m_pDoc->DeleteTab(0);
5852 1 : }
5853 :
5854 1 : void Test::testIconSet()
5855 : {
5856 1 : m_pDoc->InsertTab(0, "Test");
5857 1 : ScConditionalFormatList* pList = m_pDoc->GetCondFormList(0);
5858 :
5859 1 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, m_pDoc);
5860 1 : ScRangeList aRangeList(ScRange(0,0,0,0,0,0));
5861 1 : pFormat->SetRange(aRangeList);
5862 :
5863 1 : ScIconSetFormat* pEntry = new ScIconSetFormat(m_pDoc);
5864 1 : ScIconSetFormatData* pData = new ScIconSetFormatData;
5865 1 : pData->maEntries.push_back(new ScColorScaleEntry(0, COL_BLUE));
5866 1 : pData->maEntries.push_back(new ScColorScaleEntry(1, COL_GREEN));
5867 1 : pData->maEntries.push_back(new ScColorScaleEntry(2, COL_RED));
5868 1 : pEntry->SetIconSetData(pData);
5869 :
5870 1 : m_pDoc->AddCondFormatData(pFormat->GetRange(), 0, 1);
5871 1 : pList->InsertNew(pFormat);
5872 :
5873 : struct {
5874 : double nVal; sal_Int32 nIndex;
5875 : } aTests[] = {
5876 : { -1.0, 0 },
5877 : { 0.0, 0 },
5878 : { 1.0, 1 },
5879 : { 2.0, 2 },
5880 : { 3.0, 2 }
5881 1 : };
5882 6 : for(size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i)
5883 : {
5884 5 : m_pDoc->SetValue(0,0,0,aTests[i].nVal);
5885 5 : ScIconSetInfo* pInfo = pEntry->GetIconSetInfo(ScAddress(0,0,0));
5886 5 : CPPUNIT_ASSERT_EQUAL(aTests[i].nIndex, pInfo->nIconIndex);
5887 5 : delete pInfo;
5888 : }
5889 :
5890 1 : delete pEntry;
5891 1 : m_pDoc->DeleteTab(0);
5892 1 : }
5893 :
5894 : namespace {
5895 :
5896 : struct ScDataBarLengthData
5897 : {
5898 : double nVal;
5899 : double nLength;
5900 : };
5901 :
5902 6 : void testDataBarLengthImpl(ScDocument* pDoc, ScDataBarLengthData* pData, const ScRange& rRange,
5903 : double nMinVal, ScColorScaleEntryType eMinType,
5904 : double nMaxVal, ScColorScaleEntryType eMaxType,
5905 : double nZeroPos, databar::ScAxisPosition eAxisPos)
5906 : {
5907 6 : ScConditionalFormat* pFormat = new ScConditionalFormat(1, pDoc);
5908 6 : ScRangeList aRangeList(rRange);
5909 6 : pFormat->SetRange(aRangeList);
5910 :
5911 6 : SCCOL nCol = rRange.aStart.Col();
5912 :
5913 6 : ScDataBarFormat* pDatabar = new ScDataBarFormat(pDoc);
5914 6 : pFormat->AddEntry(pDatabar);
5915 :
5916 6 : ScDataBarFormatData* pFormatData = new ScDataBarFormatData();
5917 6 : pFormatData->meAxisPosition = eAxisPos;
5918 :
5919 6 : pFormatData->mpLowerLimit.reset(new ScColorScaleEntry());
5920 6 : pFormatData->mpLowerLimit->SetValue(nMinVal);
5921 6 : pFormatData->mpLowerLimit->SetType(eMinType);
5922 6 : pFormatData->mpUpperLimit.reset(new ScColorScaleEntry());
5923 6 : pFormatData->mpUpperLimit->SetValue(nMaxVal);
5924 6 : pFormatData->mpUpperLimit->SetType(eMaxType);
5925 6 : pDatabar->SetDataBarData(pFormatData);
5926 :
5927 63 : for (size_t i = 0; pData[i].nLength != -200; ++i)
5928 : {
5929 57 : pDoc->SetValue(nCol, i, 0, pData[i].nVal);
5930 : }
5931 :
5932 63 : for (size_t i = 0; pData[i].nLength != -200; ++i)
5933 : {
5934 57 : std::unique_ptr<ScDataBarInfo> xInfo(pDatabar->GetDataBarInfo(ScAddress(nCol, i, 0)));
5935 57 : CPPUNIT_ASSERT(xInfo.get());
5936 57 : ASSERT_DOUBLES_EQUAL(pData[i].nLength, xInfo->mnLength);
5937 57 : ASSERT_DOUBLES_EQUAL(nZeroPos, xInfo->mnZero);
5938 57 : }
5939 6 : delete pFormat;
5940 6 : }
5941 :
5942 : }
5943 :
5944 1 : void Test::testDataBarLengthAutomaticAxis()
5945 : {
5946 1 : m_pDoc->InsertTab(0, "Test");
5947 :
5948 : ScDataBarLengthData aValues[] = {
5949 : { 2, 0 },
5950 : { 3, 0 },
5951 : { 4, 25.0 },
5952 : { 5, 50.0 },
5953 : { 6, 75.0 },
5954 : { 7, 100.0 },
5955 : { 8, 100.0 },
5956 : { 9, 100.0 },
5957 : { 0, -200 }
5958 1 : };
5959 :
5960 : testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,7,0),
5961 1 : 3, COLORSCALE_VALUE, 7, COLORSCALE_VALUE, 0.0, databar::AUTOMATIC);
5962 :
5963 : ScDataBarLengthData aValues2[] = {
5964 : { -6, -100 },
5965 : { -5, -100 },
5966 : { -4, -100 },
5967 : { -3, -75.0 },
5968 : { -2, -50.0 },
5969 : { -1, -25.0 },
5970 : { 0, 0.0 },
5971 : { 1, 12.5 },
5972 : { 2, 25.0 },
5973 : { 3, 37.5 },
5974 : { 4, 50.0 },
5975 : { 5, 62.5 },
5976 : { 6, 75.0 },
5977 : { 7, 87.5 },
5978 : { 8, 100.0 },
5979 : { 9, 100.0 },
5980 : { 0, -200 }
5981 1 : };
5982 : testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
5983 1 : -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 1.0/3.0 * 100, databar::AUTOMATIC);
5984 :
5985 : ScDataBarLengthData aValues3[] = {
5986 : { 2, 0.0 },
5987 : { 3, 25.0 },
5988 : { 4, 50.0 },
5989 : { 6, 100.0 },
5990 : { 0, -200 }
5991 1 : };
5992 : testDataBarLengthImpl(m_pDoc, aValues3, ScRange(2,0,0,2,3,0),
5993 1 : 0, COLORSCALE_MIN, 0, COLORSCALE_MAX, 0, databar::AUTOMATIC);
5994 :
5995 : ScDataBarLengthData aValues4[] = {
5996 : { 2, 40.0 },
5997 : { 3, 60.0 },
5998 : { 4, 80.0 },
5999 : { 5, 100.0 },
6000 : { 0, -200 }
6001 1 : };
6002 : testDataBarLengthImpl(m_pDoc, aValues4, ScRange(3,0,0,3,3,0),
6003 1 : 0, COLORSCALE_AUTO, 0, COLORSCALE_AUTO, 0, databar::AUTOMATIC);
6004 :
6005 1 : m_pDoc->DeleteTab(0);
6006 1 : }
6007 :
6008 1 : void Test::testDataBarLengthMiddleAxis()
6009 : {
6010 1 : m_pDoc->InsertTab(0, "Test");
6011 :
6012 : ScDataBarLengthData aValues[] = {
6013 : { 1, 25.0 },
6014 : { 2, 25.0 },
6015 : { 3, 37.5 },
6016 : { 4, 50.0 },
6017 : { 5, 62.5 },
6018 : { 6, 75.0 },
6019 : { 7, 87.5 },
6020 : { 8, 100.0 },
6021 : { 9, 100.0 },
6022 : { 0, -200 }
6023 1 : };
6024 :
6025 : testDataBarLengthImpl(m_pDoc, aValues, ScRange(0,0,0,0,8,0),
6026 1 : 2, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
6027 :
6028 : ScDataBarLengthData aValues2[] = {
6029 : { -6, -50 },
6030 : { -5, -50 },
6031 : { -4, -50 },
6032 : { -3, -37.5 },
6033 : { -2, -25.0 },
6034 : { -1, -12.5 },
6035 : { 0, 0.0 },
6036 : { 1, 12.5 },
6037 : { 2, 25.0 },
6038 : { 3, 37.5 },
6039 : { 4, 50.0 },
6040 : { 5, 62.5 },
6041 : { 6, 75.0 },
6042 : { 7, 87.5 },
6043 : { 8, 100.0 },
6044 : { 9, 100.0 },
6045 : { 0, -200 }
6046 1 : };
6047 : testDataBarLengthImpl(m_pDoc, aValues2, ScRange(1,0,0,1,15,0),
6048 1 : -4, COLORSCALE_VALUE, 8, COLORSCALE_VALUE, 50.0, databar::MIDDLE);
6049 :
6050 1 : m_pDoc->DeleteTab(0);
6051 1 : }
6052 :
6053 1 : void Test::testImportStream()
6054 : {
6055 1 : sc::AutoCalcSwitch aAC(*m_pDoc, true); // turn on auto calc.
6056 2 : sc::UndoSwitch aUndo(*m_pDoc, true); // enable undo.
6057 :
6058 1 : m_pDoc->InsertTab(0, "Test");
6059 :
6060 1 : m_pDoc->SetString(ScAddress(0,1,0), "=SUM(A1:C1)"); // A2
6061 :
6062 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6063 :
6064 : // CSV import options.
6065 2 : ScAsciiOptions aOpt;
6066 1 : aOpt.SetFieldSeps(",");
6067 :
6068 : // Import values to A1:C1.
6069 2 : ScImportExport aObj(m_pDoc, ScAddress(0,0,0));
6070 1 : aObj.SetImportBroadcast(true);
6071 1 : aObj.SetExtOptions(aOpt);
6072 1 : aObj.ImportString("1,2,3", SotClipboardFormatId::STRING);
6073 :
6074 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6075 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6076 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6077 :
6078 : // Formula value should have been updated.
6079 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6080 :
6081 : // Undo, and check the result.
6082 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6083 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get the undo manager.", pUndoMgr);
6084 1 : pUndoMgr->Undo();
6085 :
6086 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6087 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6088 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6089 :
6090 1 : CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
6091 :
6092 : // Redo, and check the result.
6093 1 : pUndoMgr->Redo();
6094 :
6095 1 : CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(0,0,0)));
6096 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,0,0)));
6097 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(2,0,0)));
6098 :
6099 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,1,0))); // formula
6100 :
6101 1 : pUndoMgr->Clear();
6102 :
6103 2 : m_pDoc->DeleteTab(0);
6104 1 : }
6105 :
6106 1 : void Test::testDeleteContents()
6107 : {
6108 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
6109 2 : sc::UndoSwitch aUndoSwitch(*m_pDoc, true); // enable undo.
6110 :
6111 1 : m_pDoc->InsertTab(0, "Test");
6112 :
6113 1 : m_pDoc->SetValue(ScAddress(3,1,0), 1.0);
6114 1 : m_pDoc->SetValue(ScAddress(3,2,0), 1.0);
6115 1 : m_pDoc->SetValue(ScAddress(3,3,0), 1.0);
6116 1 : m_pDoc->SetValue(ScAddress(3,4,0), 1.0);
6117 1 : m_pDoc->SetValue(ScAddress(3,5,0), 1.0);
6118 1 : m_pDoc->SetValue(ScAddress(3,6,0), 1.0);
6119 1 : m_pDoc->SetValue(ScAddress(3,7,0), 1.0);
6120 1 : m_pDoc->SetValue(ScAddress(3,8,0), 1.0);
6121 1 : m_pDoc->SetString(ScAddress(3,15,0), "=SUM(D2:D15)");
6122 :
6123 1 : CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6124 :
6125 : // Delete D2:D6.
6126 1 : ScRange aRange(3,1,0,3,5,0);
6127 2 : ScMarkData aMark;
6128 1 : aMark.SelectOneTable(0);
6129 1 : aMark.SetMarkArea(aRange);
6130 :
6131 1 : ScDocument* pUndoDoc = new ScDocument(SCDOCMODE_UNDO);
6132 1 : pUndoDoc->InitUndo(m_pDoc, 0, 0);
6133 1 : m_pDoc->CopyToDocument(aRange, IDF_CONTENTS, false, pUndoDoc, &aMark);
6134 2 : ScUndoDeleteContents aUndo(&getDocShell(), aMark, aRange, pUndoDoc, false, IDF_CONTENTS, true);
6135 :
6136 1 : clearRange(m_pDoc, aRange);
6137 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6138 :
6139 1 : aUndo.Undo();
6140 1 : CPPUNIT_ASSERT_EQUAL(8.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6141 :
6142 1 : aUndo.Redo();
6143 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(ScAddress(3,15,0))); // formula
6144 :
6145 2 : m_pDoc->DeleteTab(0);
6146 1 : }
6147 :
6148 1 : void Test::testTransliterateText()
6149 : {
6150 1 : m_pDoc->InsertTab(0, "Test");
6151 :
6152 : // Set texts to A1:A3.
6153 1 : m_pDoc->SetString(ScAddress(0,0,0), "Mike");
6154 1 : m_pDoc->SetString(ScAddress(0,1,0), "Noah");
6155 1 : m_pDoc->SetString(ScAddress(0,2,0), "Oscar");
6156 :
6157 : // Change them to uppercase.
6158 1 : ScMarkData aMark;
6159 1 : aMark.SetMarkArea(ScRange(0,0,0,0,2,0));
6160 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
6161 : rFunc.TransliterateText(
6162 1 : aMark, i18n::TransliterationModules_LOWERCASE_UPPERCASE, true, true);
6163 :
6164 1 : CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
6165 1 : CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
6166 1 : CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
6167 :
6168 : // Test the undo and redo.
6169 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6170 1 : CPPUNIT_ASSERT_MESSAGE("Failed to get undo manager.", pUndoMgr);
6171 :
6172 1 : pUndoMgr->Undo();
6173 1 : CPPUNIT_ASSERT_EQUAL(OUString("Mike"), m_pDoc->GetString(ScAddress(0,0,0)));
6174 1 : CPPUNIT_ASSERT_EQUAL(OUString("Noah"), m_pDoc->GetString(ScAddress(0,1,0)));
6175 1 : CPPUNIT_ASSERT_EQUAL(OUString("Oscar"), m_pDoc->GetString(ScAddress(0,2,0)));
6176 :
6177 1 : pUndoMgr->Redo();
6178 1 : CPPUNIT_ASSERT_EQUAL(OUString("MIKE"), m_pDoc->GetString(ScAddress(0,0,0)));
6179 1 : CPPUNIT_ASSERT_EQUAL(OUString("NOAH"), m_pDoc->GetString(ScAddress(0,1,0)));
6180 1 : CPPUNIT_ASSERT_EQUAL(OUString("OSCAR"), m_pDoc->GetString(ScAddress(0,2,0)));
6181 :
6182 1 : m_pDoc->DeleteTab(0);
6183 1 : }
6184 :
6185 1 : void Test::testFormulaToValue()
6186 : {
6187 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
6188 2 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
6189 :
6190 1 : m_pDoc->InsertTab(0, "Test");
6191 :
6192 : const char* aData[][3] = {
6193 : { "=1", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6194 : { "=2", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6195 : { "=3", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6196 : { "=4", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6197 : { "=5", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6198 : { "=6", "=RC[-1]*2", "=ISFORMULA(RC[-1])" },
6199 1 : };
6200 :
6201 1 : ScAddress aPos(1,2,0); // B3
6202 1 : ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
6203 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
6204 :
6205 : {
6206 : // Expected output table content. 0 = empty cell
6207 : const char* aOutputCheck[][3] = {
6208 : { "1", "2", "TRUE" },
6209 : { "2", "4", "TRUE" },
6210 : { "3", "6", "TRUE" },
6211 : { "4", "8", "TRUE" },
6212 : { "5", "10", "TRUE" },
6213 : { "6", "12", "TRUE" },
6214 1 : };
6215 :
6216 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6217 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6218 : }
6219 :
6220 : // Convert B5:C6 to static values, and check the result.
6221 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
6222 1 : ScRange aConvRange(1,4,0,2,5,0); // B5:C6
6223 1 : rFunc.ConvertFormulaToValue(aConvRange, true, false);
6224 :
6225 : {
6226 : // Expected output table content. 0 = empty cell
6227 : const char* aOutputCheck[][3] = {
6228 : { "1", "2", "TRUE" },
6229 : { "2", "4", "TRUE" },
6230 : { "3", "6", "FALSE" },
6231 : { "4", "8", "FALSE" },
6232 : { "5", "10", "TRUE" },
6233 : { "6", "12", "TRUE" },
6234 1 : };
6235 :
6236 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Converted");
6237 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6238 : }
6239 :
6240 : // Make sure that B3:B4 and B7:B8 are formula cells.
6241 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_FORMULA);
6242 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,3,0)) == CELLTYPE_FORMULA);
6243 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,6,0)) == CELLTYPE_FORMULA);
6244 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,7,0)) == CELLTYPE_FORMULA);
6245 :
6246 : // Make sure that B5:C6 are numeric cells.
6247 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,4,0)) == CELLTYPE_VALUE);
6248 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,5,0)) == CELLTYPE_VALUE);
6249 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,4,0)) == CELLTYPE_VALUE);
6250 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,5,0)) == CELLTYPE_VALUE);
6251 :
6252 : // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
6253 1 : const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6254 1 : CPPUNIT_ASSERT(pFC);
6255 1 : CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6256 1 : CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6257 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(2,6,0));
6258 1 : CPPUNIT_ASSERT(pFC);
6259 1 : CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 6);
6260 1 : CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6261 :
6262 : // Undo and check.
6263 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6264 1 : CPPUNIT_ASSERT(pUndoMgr);
6265 1 : pUndoMgr->Undo();
6266 :
6267 : {
6268 : // Expected output table content. 0 = empty cell
6269 : const char* aOutputCheck[][3] = {
6270 : { "1", "2", "TRUE" },
6271 : { "2", "4", "TRUE" },
6272 : { "3", "6", "TRUE" },
6273 : { "4", "8", "TRUE" },
6274 : { "5", "10", "TRUE" },
6275 : { "6", "12", "TRUE" },
6276 1 : };
6277 :
6278 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "After undo");
6279 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6280 : }
6281 :
6282 : // B3:B8 should all be (ungrouped) formula cells.
6283 7 : for (SCROW i = 2; i <= 7; ++i)
6284 : {
6285 6 : pFC = m_pDoc->GetFormulaCell(ScAddress(1,i,0));
6286 6 : CPPUNIT_ASSERT(pFC);
6287 6 : CPPUNIT_ASSERT(!pFC->IsShared());
6288 : }
6289 :
6290 : // C3:C8 should be shared formula cells.
6291 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6292 1 : CPPUNIT_ASSERT(pFC);
6293 1 : CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6294 1 : CPPUNIT_ASSERT(pFC->GetSharedLength() == 6);
6295 :
6296 : // Redo and check.
6297 1 : pUndoMgr->Redo();
6298 : {
6299 : // Expected output table content. 0 = empty cell
6300 : const char* aOutputCheck[][3] = {
6301 : { "1", "2", "TRUE" },
6302 : { "2", "4", "TRUE" },
6303 : { "3", "6", "FALSE" },
6304 : { "4", "8", "FALSE" },
6305 : { "5", "10", "TRUE" },
6306 : { "6", "12", "TRUE" },
6307 1 : };
6308 :
6309 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Converted");
6310 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6311 : }
6312 :
6313 : // Make sure that B3:B4 and B7:B8 are formula cells.
6314 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,2,0)) == CELLTYPE_FORMULA);
6315 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,3,0)) == CELLTYPE_FORMULA);
6316 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,6,0)) == CELLTYPE_FORMULA);
6317 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,7,0)) == CELLTYPE_FORMULA);
6318 :
6319 : // Make sure that B5:C6 are numeric cells.
6320 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,4,0)) == CELLTYPE_VALUE);
6321 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(1,5,0)) == CELLTYPE_VALUE);
6322 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,4,0)) == CELLTYPE_VALUE);
6323 1 : CPPUNIT_ASSERT(m_pDoc->GetCellType(ScAddress(2,5,0)) == CELLTYPE_VALUE);
6324 :
6325 : // Make sure that formula cells in C3:C4 and C7:C8 are grouped.
6326 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(2,2,0));
6327 1 : CPPUNIT_ASSERT(pFC);
6328 1 : CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 2);
6329 1 : CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6330 1 : pFC = m_pDoc->GetFormulaCell(ScAddress(2,6,0));
6331 1 : CPPUNIT_ASSERT(pFC);
6332 1 : CPPUNIT_ASSERT(pFC->GetSharedTopRow() == 6);
6333 1 : CPPUNIT_ASSERT(pFC->GetSharedLength() == 2);
6334 :
6335 : // Undo again and make sure the recovered formulas in C5:C6 still track B5:B6.
6336 1 : pUndoMgr->Undo();
6337 1 : m_pDoc->SetValue(ScAddress(1,4,0), 10);
6338 1 : m_pDoc->SetValue(ScAddress(1,5,0), 11);
6339 1 : CPPUNIT_ASSERT_EQUAL(20.0, m_pDoc->GetValue(ScAddress(2,4,0)));
6340 1 : CPPUNIT_ASSERT_EQUAL(22.0, m_pDoc->GetValue(ScAddress(2,5,0)));
6341 :
6342 2 : m_pDoc->DeleteTab(0);
6343 1 : }
6344 :
6345 1 : void Test::testFormulaToValue2()
6346 : {
6347 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
6348 2 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
6349 :
6350 1 : m_pDoc->InsertTab(0, "Test");
6351 :
6352 : const char* aData[][2] = {
6353 : { "=1", "=ISFORMULA(RC[-1])" },
6354 : { "=2", "=ISFORMULA(RC[-1])" },
6355 : { "3", "=ISFORMULA(RC[-1])" },
6356 : { "=4", "=ISFORMULA(RC[-1])" },
6357 : { "=5", "=ISFORMULA(RC[-1])" },
6358 1 : };
6359 :
6360 : // Insert data into B2:C6.
6361 1 : ScAddress aPos(1,1,0); // B2
6362 1 : ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
6363 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
6364 :
6365 : {
6366 : // Expected output table content. 0 = empty cell
6367 : const char* aOutputCheck[][2] = {
6368 : { "1", "TRUE" },
6369 : { "2", "TRUE" },
6370 : { "3", "FALSE" },
6371 : { "4", "TRUE" },
6372 : { "5", "TRUE" },
6373 1 : };
6374 :
6375 1 : bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6376 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6377 : }
6378 :
6379 : // Convert B3:B5 to a value.
6380 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
6381 1 : ScRange aConvRange(1,2,0,1,4,0); // B3:B5
6382 1 : rFunc.ConvertFormulaToValue(aConvRange, true, false);
6383 :
6384 : {
6385 : // Expected output table content. 0 = empty cell
6386 : const char* aOutputCheck[][2] = {
6387 : { "1", "TRUE" },
6388 : { "2", "FALSE" },
6389 : { "3", "FALSE" },
6390 : { "4", "FALSE" },
6391 : { "5", "TRUE" },
6392 1 : };
6393 :
6394 1 : bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6395 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6396 : }
6397 :
6398 : // Undo and check.
6399 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6400 1 : CPPUNIT_ASSERT(pUndoMgr);
6401 1 : pUndoMgr->Undo();
6402 :
6403 : {
6404 : // Expected output table content. 0 = empty cell
6405 : const char* aOutputCheck[][2] = {
6406 : { "1", "TRUE" },
6407 : { "2", "TRUE" },
6408 : { "3", "FALSE" },
6409 : { "4", "TRUE" },
6410 : { "5", "TRUE" },
6411 1 : };
6412 :
6413 1 : bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
6414 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
6415 : }
6416 :
6417 2 : m_pDoc->DeleteTab(0);
6418 1 : }
6419 :
6420 1 : void Test::testMixData()
6421 : {
6422 1 : m_pDoc->InsertTab(0, "Test");
6423 :
6424 1 : m_pDoc->SetValue(ScAddress(1,0,0), 2.0); // B1
6425 1 : m_pDoc->SetValue(ScAddress(0,1,0), 3.0); // A2
6426 :
6427 : // Copy A1:B1 to the clip document.
6428 1 : ScDocument aClipDoc(SCDOCMODE_CLIP);
6429 1 : copyToClip(m_pDoc, ScRange(0,0,0,1,0,0), &aClipDoc); // A1:B1
6430 :
6431 : // Copy A2:B2 to the mix document (for arithemetic paste).
6432 2 : ScDocument aMixDoc(SCDOCMODE_CLIP);
6433 1 : copyToClip(m_pDoc, ScRange(0,1,0,1,1,0), &aMixDoc); // A2:B2
6434 :
6435 : // Paste A1:B1 to A2:B2 and perform addition.
6436 1 : pasteFromClip(m_pDoc, ScRange(0,1,0,1,1,0), &aClipDoc);
6437 1 : m_pDoc->MixDocument(ScRange(0,1,0,1,1,0), PASTE_ADD, false, &aMixDoc);
6438 :
6439 1 : CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(0,1,0)); // A2
6440 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(1,1,0)); // B2
6441 :
6442 : // Clear everything and start over.
6443 1 : clearSheet(m_pDoc, 0);
6444 1 : clearSheet(&aClipDoc, 0);
6445 1 : clearSheet(&aMixDoc, 0);
6446 :
6447 : // Set values to A1, A2, and B1. B2 will remain empty.
6448 1 : m_pDoc->SetValue(ScAddress(0,0,0), 15.0);
6449 1 : m_pDoc->SetValue(ScAddress(0,1,0), 16.0);
6450 1 : m_pDoc->SetValue(ScAddress(1,0,0), 12.0);
6451 1 : CPPUNIT_ASSERT_MESSAGE("B2 should be empty.", m_pDoc->GetCellType(ScAddress(1,1,0)) == CELLTYPE_NONE);
6452 :
6453 : // Copy A1:A2 and paste it onto B1:B2 with subtraction operation.
6454 1 : copyToClip(m_pDoc, ScRange(0,0,0,0,1,0), &aClipDoc);
6455 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,0,0)), aClipDoc.GetValue(ScAddress(0,0,0)));
6456 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,1,0)), aClipDoc.GetValue(ScAddress(0,1,0)));
6457 :
6458 1 : copyToClip(m_pDoc, ScRange(1,0,0,1,1,0), &aMixDoc);
6459 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(1,0,0)), aMixDoc.GetValue(ScAddress(1,0,0)));
6460 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(1,1,0)), aMixDoc.GetValue(ScAddress(1,1,0)));
6461 :
6462 1 : pasteFromClip(m_pDoc, ScRange(1,0,0,1,1,0), &aClipDoc);
6463 1 : m_pDoc->MixDocument(ScRange(1,0,0,1,1,0), PASTE_SUB, false, &aMixDoc);
6464 :
6465 1 : CPPUNIT_ASSERT_EQUAL( -3.0, m_pDoc->GetValue(ScAddress(1,0,0))); // 12 - 15
6466 1 : CPPUNIT_ASSERT_EQUAL(-16.0, m_pDoc->GetValue(ScAddress(1,1,0))); // 0 - 16
6467 :
6468 2 : m_pDoc->DeleteTab(0);
6469 1 : }
6470 :
6471 1 : void Test::testSetStringAndNote()
6472 : {
6473 1 : m_pDoc->InsertTab(0, "Test");
6474 :
6475 : //note on A1
6476 1 : ScAddress aAdrA1 (0, 0, 0);
6477 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(aAdrA1);
6478 1 : pNote->SetText(aAdrA1, "Hello world in A1");
6479 :
6480 1 : m_pDoc->SetString(0, 0, 0, "");
6481 :
6482 1 : pNote = m_pDoc->GetNote(aAdrA1);
6483 1 : CPPUNIT_ASSERT(pNote);
6484 :
6485 1 : m_pDoc->DeleteTab(0);
6486 1 : }
6487 :
6488 1 : void Test::testCopyPasteMatrixFormula()
6489 : {
6490 1 : m_pDoc->InsertTab(0, "hcv");
6491 :
6492 : // Set Values to B1, C1, D1
6493 1 : m_pDoc->SetValue(ScAddress(1,0,0), 2.0); // B1
6494 1 : m_pDoc->SetValue(ScAddress(2,0,0), 5.0); // C1
6495 1 : m_pDoc->SetValue(ScAddress(3,0,0), 3.0); // D1
6496 :
6497 : // Set Values to B2, C2
6498 1 : m_pDoc->SetString(ScAddress(1,1,0), "B2"); // B2
6499 : //m_pDoc->SetString(ScAddress(2,1,0), "C2"); // C2
6500 1 : m_pDoc->SetString(ScAddress(3,1,0), "D2"); // D2
6501 :
6502 : // Set Vallues to D3
6503 : //m_pDoc->SetValue(ScAddress(1,2,0), 9.0); // B3
6504 : //m_pDoc->SetString(ScAddress(2,2,0), "C3"); // C3
6505 1 : m_pDoc->SetValue(ScAddress(3,2,0), 11.0); // D3
6506 :
6507 : // Insert matrix formula to A1
6508 1 : ScMarkData aMark;
6509 1 : aMark.SelectOneTable(0);
6510 1 : m_pDoc->InsertMatrixFormula(0, 0, 0, 0, aMark, "=COUNTIF(ISBLANK(B1:D1);TRUE())");
6511 1 : m_pDoc->CalcAll();
6512 : // A1 should containg 0
6513 1 : CPPUNIT_ASSERT_EQUAL( 0.0, m_pDoc->GetValue(ScAddress(0,0,0)) ); // A1
6514 :
6515 : // Copy cell A1 to clipboard.
6516 1 : ScAddress aPos(0,0,0); // A1
6517 2 : ScDocument aClipDoc(SCDOCMODE_CLIP);
6518 2 : ScClipParam aParam(aPos, false);
6519 1 : m_pDoc->CopyToClip(aParam, &aClipDoc, &aMark);
6520 : // Formula string should be equal.
6521 1 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetString(aPos), aClipDoc.GetString(aPos));
6522 :
6523 : // First try single range.
6524 : // Paste matrix formula to A2
6525 1 : pasteFromClip(m_pDoc, ScRange(0,1,0,0,1,0), &aClipDoc); // A2
6526 : // A2 Cell value should contain 1.0
6527 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6528 :
6529 : // Paste matrix formula to A3
6530 1 : pasteFromClip(m_pDoc, ScRange(0,2,0,0,2,0), &aClipDoc); // A3
6531 : // A3 Cell value should contain 2.0
6532 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
6533 :
6534 : // Paste matrix formula to A4
6535 1 : pasteFromClip(m_pDoc, ScRange(0,3,0,0,3,0), &aClipDoc); // A4
6536 : // A4 Cell value should contain 3.0
6537 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
6538 :
6539 : // Clear cell A2:A4
6540 1 : clearRange(m_pDoc, ScRange(0,1,0,0,3,0));
6541 :
6542 : // Paste matrix formula to range A2:A4
6543 1 : pasteFromClip(m_pDoc, ScRange(0,1,0,0,3,0), &aClipDoc); // A2:A4
6544 :
6545 : // A2 Cell value should contain 1.0
6546 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
6547 : // A3 Cell value should contain 2.0
6548 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
6549 : // A4 Cell value should contain 3.0
6550 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
6551 :
6552 2 : m_pDoc->DeleteTab(0);
6553 1 : }
6554 :
6555 1 : void Test::testUndoDataAnchor()
6556 : {
6557 1 : m_pDoc->InsertTab(0, "Tab1");
6558 1 : CPPUNIT_ASSERT_MESSAGE("There should be only 1 sheets to begin with", m_pDoc->GetTableCount() == 1);
6559 :
6560 1 : m_pDoc->InitDrawLayer();
6561 1 : ScDrawLayer* pDrawLayer = m_pDoc->GetDrawLayer();
6562 1 : CPPUNIT_ASSERT_MESSAGE("No drawing layer.", pDrawLayer);
6563 1 : SdrPage* pPage = pDrawLayer->GetPage(0);
6564 1 : CPPUNIT_ASSERT_MESSAGE("No page instance for the 1st sheet.", pPage);
6565 :
6566 : // Insert an object.
6567 1 : Rectangle aObjRect(2,1000,100,1100);
6568 1 : SdrObject* pObj = new SdrRectObj(aObjRect);
6569 1 : pPage->InsertObject(pObj);
6570 1 : ScDrawLayer::SetCellAnchoredFromPosition(*pObj, *m_pDoc, 0);
6571 :
6572 : // Get anchor data
6573 1 : ScDrawObjData* pData = ScDrawLayer::GetObjData(pObj, false);
6574 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6575 :
6576 1 : ScAddress aOldStart = pData->maStart;
6577 1 : ScAddress aOldEnd = pData->maEnd;
6578 :
6579 : // Get non rotated anchor data
6580 1 : ScDrawObjData* pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6581 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6582 :
6583 1 : ScAddress aNOldStart = pNData->maStart;
6584 1 : ScAddress aNOldEnd = pNData->maEnd;
6585 1 : CPPUNIT_ASSERT_EQUAL(aOldStart, aNOldStart);
6586 1 : CPPUNIT_ASSERT_EQUAL(aOldEnd, aNOldEnd);
6587 :
6588 : //pDrawLayer->BeginCalcUndo(false);
6589 : // Insert a new row at row 3.
6590 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
6591 1 : ScMarkData aMark;
6592 1 : aMark.SelectOneTable(0);
6593 1 : rFunc.InsertCells(ScRange( 0, aOldStart.Row() - 1, 0, MAXCOL, aOldStart.Row(), 0 ), &aMark, INS_INSROWS_BEFORE, true, true, false);
6594 :
6595 1 : pData = ScDrawLayer::GetObjData(pObj, false);
6596 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6597 :
6598 1 : ScAddress aNewStart = pData->maStart;
6599 1 : ScAddress aNewEnd = pData->maEnd;
6600 :
6601 : // Get non rotated anchor data
6602 1 : pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6603 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6604 :
6605 1 : ScAddress aNNewStart = pNData->maStart;
6606 1 : ScAddress aNNewEnd = pNData->maEnd;
6607 1 : CPPUNIT_ASSERT_EQUAL(aNewStart, aNNewStart);
6608 1 : CPPUNIT_ASSERT_EQUAL(aNewEnd, aNNewEnd);
6609 2 : CPPUNIT_ASSERT_MESSAGE("Failed to compare Address.", aNewStart != aOldStart && aNewEnd != aOldEnd &&
6610 1 : aNNewStart != aNOldStart && aNNewEnd != aNOldEnd );
6611 :
6612 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
6613 1 : CPPUNIT_ASSERT(pUndoMgr);
6614 1 : pUndoMgr->Undo();
6615 :
6616 : // Check state
6617 1 : ScAnchorType oldType = ScDrawLayer::GetAnchorType(*pObj);
6618 1 : CPPUNIT_ASSERT_MESSAGE( "Failed to check state SCA_CELL.", oldType == SCA_CELL );
6619 :
6620 : // Get anchor data
6621 1 : pData = ScDrawLayer::GetObjData(pObj, false);
6622 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6623 :
6624 : // Get non rotated anchor data
6625 1 : pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6626 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6627 :
6628 : // Check if data has moved to new rows
6629 1 : CPPUNIT_ASSERT_EQUAL(pData->maStart, aOldStart);
6630 1 : CPPUNIT_ASSERT_EQUAL(pData->maEnd, aOldEnd);
6631 :
6632 1 : CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNOldStart);
6633 1 : CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNOldEnd);
6634 :
6635 1 : pUndoMgr->Redo();
6636 :
6637 : // Get anchor data
6638 1 : pData = ScDrawLayer::GetObjData(pObj, false);
6639 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData);
6640 :
6641 : // Get non rotated anchor data
6642 1 : pNData = ScDrawLayer::GetNonRotatedObjData( pObj );
6643 1 : CPPUNIT_ASSERT_MESSAGE("Failed to retrieve non rotated user data for this object.", pNData);
6644 :
6645 : // Check if data has moved to new rows
6646 1 : CPPUNIT_ASSERT_EQUAL(pData->maStart, aNewStart);
6647 1 : CPPUNIT_ASSERT_EQUAL(pData->maEnd, aNewEnd);
6648 :
6649 1 : CPPUNIT_ASSERT_EQUAL(pNData->maStart, aNNewStart);
6650 1 : CPPUNIT_ASSERT_EQUAL(pNData->maEnd, aNNewEnd);
6651 :
6652 1 : m_pDoc->DeleteTab(0);
6653 1 : }
6654 :
6655 5 : ScDocShell* Test::findLoadedDocShellByName(const OUString& rName)
6656 : {
6657 5 : TypeId aType(TYPE(ScDocShell));
6658 5 : ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
6659 15 : while (pShell)
6660 : {
6661 8 : SfxMedium* pMedium = pShell->GetMedium();
6662 8 : if (pMedium)
6663 : {
6664 8 : OUString aName = pMedium->GetName();
6665 8 : if (aName.equals(rName))
6666 3 : return pShell;
6667 : }
6668 5 : pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
6669 : }
6670 2 : return NULL;
6671 : }
6672 :
6673 4 : bool Test::insertRangeNames(
6674 : ScDocument* pDoc, ScRangeName* pNames, const RangeNameDef* p, const RangeNameDef* pEnd)
6675 : {
6676 4 : ScAddress aA1(0, 0, 0);
6677 13 : for (; p != pEnd; ++p)
6678 : {
6679 : ScRangeData* pNew = new ScRangeData(
6680 : pDoc,
6681 : OUString::createFromAscii(p->mpName),
6682 : OUString::createFromAscii(p->mpExpr),
6683 9 : aA1, 0, formula::FormulaGrammar::GRAM_ENGLISH);
6684 9 : pNew->SetIndex(p->mnIndex);
6685 9 : bool bSuccess = pNames->insert(pNew);
6686 9 : if (!bSuccess)
6687 : {
6688 0 : cerr << "Insertion failed." << endl;
6689 0 : return false;
6690 : }
6691 : }
6692 :
6693 4 : return true;
6694 : }
6695 :
6696 69 : void Test::printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption)
6697 : {
6698 69 : SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
6699 69 : SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
6700 69 : svl::GridPrinter printer(nRow2 - nRow1 + 1, nCol2 - nCol1 + 1, CALC_DEBUG_OUTPUT != 0);
6701 529 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
6702 : {
6703 1716 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
6704 : {
6705 1256 : OUString aVal = pDoc->GetString(nCol, nRow, rRange.aStart.Tab());
6706 1256 : printer.set(nRow-nRow1, nCol-nCol1, aVal);
6707 1256 : }
6708 : }
6709 69 : printer.print(pCaption);
6710 69 : }
6711 :
6712 132 : void Test::clearRange(ScDocument* pDoc, const ScRange& rRange)
6713 : {
6714 132 : ScMarkData aMarkData;
6715 132 : aMarkData.SetMarkArea(rRange);
6716 : pDoc->DeleteArea(
6717 132 : rRange.aStart.Col(), rRange.aStart.Row(),
6718 264 : rRange.aEnd.Col(), rRange.aEnd.Row(), aMarkData, IDF_CONTENTS);
6719 132 : }
6720 :
6721 17 : void Test::clearSheet(ScDocument* pDoc, SCTAB nTab)
6722 : {
6723 17 : ScRange aRange(0,0,nTab,MAXCOL,MAXROW,nTab);
6724 17 : clearRange(pDoc, aRange);
6725 17 : }
6726 :
6727 12 : void Test::copyToClip(ScDocument* pSrcDoc, const ScRange& rRange, ScDocument* pClipDoc)
6728 : {
6729 12 : ScClipParam aClipParam(rRange, false);
6730 24 : ScMarkData aMark;
6731 12 : aMark.SetMarkArea(rRange);
6732 24 : pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aMark);
6733 12 : }
6734 :
6735 10 : void Test::pasteFromClip(ScDocument* pDestDoc, const ScRange& rDestRange, ScDocument* pClipDoc)
6736 : {
6737 10 : ScMarkData aMark;
6738 10 : aMark.SetMarkArea(rDestRange);
6739 10 : pDestDoc->CopyFromClip(rDestRange, aMark, IDF_ALL, NULL, pClipDoc);
6740 10 : }
6741 :
6742 2 : ScUndoPaste* Test::createUndoPaste(ScDocShell& rDocSh, const ScRange& rRange, ScDocument* pUndoDoc)
6743 : {
6744 2 : ScDocument& rDoc = rDocSh.GetDocument();
6745 2 : ScMarkData aMarkData;
6746 2 : aMarkData.SetMarkArea(rRange);
6747 2 : ScRefUndoData* pRefUndoData = new ScRefUndoData(&rDoc);
6748 :
6749 : return new ScUndoPaste(
6750 2 : &rDocSh, rRange, aMarkData, pUndoDoc, NULL, IDF_ALL, pRefUndoData, false);
6751 : }
6752 :
6753 7 : void Test::setExpandRefs(bool bExpand)
6754 : {
6755 7 : ScModule* pMod = SC_MOD();
6756 7 : ScInputOptions aOpt = pMod->GetInputOptions();
6757 7 : aOpt.SetExpandRefs(bExpand);
6758 7 : pMod->SetInputOptions(aOpt);
6759 7 : }
6760 :
6761 1 : void Test::setCalcAsShown(ScDocument* pDoc, bool bCalcAsShown)
6762 : {
6763 1 : ScDocOptions aOpt = pDoc->GetDocOptions();
6764 1 : aOpt.SetCalcAsShown(bCalcAsShown);
6765 1 : pDoc->SetDocOptions(aOpt);
6766 1 : }
6767 :
6768 1 : CPPUNIT_TEST_SUITE_REGISTRATION(Test);
6769 :
6770 4 : CPPUNIT_PLUGIN_IMPLEMENT();
6771 :
6772 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|