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