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 : #include "helper/sorthelper.hxx"
12 :
13 : #include <postit.hxx>
14 : #include <sortparam.hxx>
15 : #include <dbdata.hxx>
16 : #include <patattr.hxx>
17 : #include <formulacell.hxx>
18 : #include <scopetools.hxx>
19 : #include <globalnames.hxx>
20 : #include <dbdocfun.hxx>
21 : #include <docfunc.hxx>
22 : #include <scitems.hxx>
23 : #include <editutil.hxx>
24 :
25 : #include <sal/config.h>
26 : #include <editeng/wghtitem.hxx>
27 : #include <editeng/postitem.hxx>
28 : #include <test/bootstrapfixture.hxx>
29 :
30 1 : void Test::testSort()
31 : {
32 1 : m_pDoc->InsertTab(0, "test1");
33 :
34 1 : ScRange aDataRange;
35 1 : ScAddress aPos(0,0,0);
36 : {
37 : const char* aData[][2] = {
38 : { "2", "4" },
39 : { "4", "1" },
40 : { "1", "2" },
41 : { "1", "23" },
42 1 : };
43 :
44 1 : clearRange(m_pDoc, ScRange(0, 0, 0, 1, SAL_N_ELEMENTS(aData), 0));
45 1 : aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
46 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
47 : }
48 :
49 : // Insert note in cell B2.
50 1 : ScAddress rAddr(1, 1, 0);
51 1 : ScPostIt* pNote = m_pDoc->GetOrCreateNote(rAddr);
52 1 : pNote->SetText(rAddr, "Hello");
53 1 : pNote->SetAuthor("Jim Bob");
54 :
55 1 : ScSortParam aSortData;
56 1 : aSortData.nCol1 = 1;
57 1 : aSortData.nCol2 = 1;
58 1 : aSortData.nRow1 = 0;
59 1 : aSortData.nRow2 = 2;
60 1 : aSortData.maKeyState[0].bDoSort = true;
61 1 : aSortData.maKeyState[0].nField = 1;
62 1 : aSortData.maKeyState[0].bAscending = true;
63 :
64 1 : m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
65 :
66 1 : double nVal = m_pDoc->GetValue(1,0,0);
67 1 : ASSERT_DOUBLES_EQUAL(nVal, 1.0);
68 :
69 : // check that note is also moved after sorting
70 1 : pNote = m_pDoc->GetNote(1, 0, 0);
71 1 : CPPUNIT_ASSERT(pNote);
72 :
73 1 : clearRange(m_pDoc, ScRange(0, 0, 0, 1, 9, 0)); // Clear A1:B10.
74 : {
75 : // 0 = empty cell
76 : const char* aData[][1] = {
77 : { "Title" },
78 : { 0 },
79 : { 0 },
80 : { "12" },
81 : { "b" },
82 : { "1" },
83 : { "9" },
84 : { "123" }
85 1 : };
86 :
87 1 : aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
88 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aDataRange.aStart == aPos);
89 : }
90 :
91 1 : aSortData.nCol1 = aDataRange.aStart.Col();
92 1 : aSortData.nCol2 = aDataRange.aEnd.Col();
93 1 : aSortData.nRow1 = aDataRange.aStart.Row();
94 1 : aSortData.nRow2 = aDataRange.aEnd.Row();
95 1 : aSortData.bHasHeader = true;
96 1 : aSortData.maKeyState[0].nField = 0;
97 1 : m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
98 :
99 : // Title should stay at the top, numbers should be sorted numerically,
100 : // numbers always come before strings, and empty cells always occur at the
101 : // end.
102 1 : CPPUNIT_ASSERT_EQUAL(OUString("Title"), m_pDoc->GetString(aPos));
103 1 : aPos.IncRow();
104 1 : CPPUNIT_ASSERT_EQUAL(OUString("1"), m_pDoc->GetString(aPos));
105 1 : aPos.IncRow();
106 1 : CPPUNIT_ASSERT_EQUAL(OUString("9"), m_pDoc->GetString(aPos));
107 1 : aPos.IncRow();
108 1 : CPPUNIT_ASSERT_EQUAL(OUString("12"), m_pDoc->GetString(aPos));
109 1 : aPos.IncRow();
110 1 : CPPUNIT_ASSERT_EQUAL(OUString("123"), m_pDoc->GetString(aPos));
111 1 : aPos.IncRow();
112 1 : CPPUNIT_ASSERT_EQUAL(OUString("b"), m_pDoc->GetString(aPos));
113 1 : aPos.IncRow();
114 1 : CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE, m_pDoc->GetCellType(aPos));
115 :
116 1 : m_pDoc->DeleteTab(0);
117 1 : }
118 :
119 1 : void Test::testSortHorizontal()
120 : {
121 1 : SortRefUpdateSetter aUpdateSet;
122 :
123 2 : ScFormulaOptions aOptions;
124 1 : aOptions.SetFormulaSepArg(";");
125 1 : aOptions.SetFormulaSepArrayCol(";");
126 1 : aOptions.SetFormulaSepArrayRow("|");
127 1 : getDocShell().SetFormulaOptions(aOptions);
128 :
129 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
130 1 : m_pDoc->InsertTab(0, "Sort");
131 :
132 : // Test case from fdo#78079.
133 :
134 : // 0 = empty cell
135 : const char* aData[][4] = {
136 : { "table", "has UNIQUE", "Publish to EC2", "flag" },
137 : { "w2gi.mobilehit", "Yes", "No", "=CONCATENATE(B2;\"-\";C2)" },
138 : { "w2gi.visitors", "No", "No", "=CONCATENATE(B3;\"-\";C3)" },
139 : { "w2gi.pagedimension", "Yes", "Yes", "=CONCATENATE(B4;\"-\";C4)" },
140 1 : };
141 :
142 : // Insert raw data into A1:D4.
143 1 : ScRange aDataRange = insertRangeData(m_pDoc, ScAddress(0,0,0), aData, SAL_N_ELEMENTS(aData));
144 1 : CPPUNIT_ASSERT_EQUAL(OUString("A1:D4"), aDataRange.Format(SCA_VALID));
145 :
146 : // Check the formula values.
147 1 : CPPUNIT_ASSERT_EQUAL(OUString("Yes-No"), m_pDoc->GetString(ScAddress(3,1,0)));
148 1 : CPPUNIT_ASSERT_EQUAL(OUString("No-No"), m_pDoc->GetString(ScAddress(3,2,0)));
149 1 : CPPUNIT_ASSERT_EQUAL(OUString("Yes-Yes"), m_pDoc->GetString(ScAddress(3,3,0)));
150 :
151 : // Define A1:D4 as sheet-local anonymous database range.
152 : m_pDoc->SetAnonymousDBData(
153 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 3, 3));
154 :
155 : // Sort A1:D4 horizontally, ascending by row 1.
156 2 : ScDBDocFunc aFunc(getDocShell());
157 :
158 2 : ScSortParam aSortData;
159 1 : aSortData.nCol1 = 0;
160 1 : aSortData.nCol2 = 3;
161 1 : aSortData.nRow1 = 0;
162 1 : aSortData.nRow2 = 3;
163 1 : aSortData.bHasHeader = true;
164 1 : aSortData.bByRow = false; // Sort by column (in horizontal direction).
165 1 : aSortData.bIncludePattern = true;
166 1 : aSortData.maKeyState[0].bDoSort = true;
167 1 : aSortData.maKeyState[0].nField = 0;
168 1 : aSortData.maKeyState[0].bAscending = true;
169 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
170 1 : CPPUNIT_ASSERT(bSorted);
171 :
172 : {
173 : // Expected output table content. 0 = empty cell
174 : const char* aOutputCheck[][4] = {
175 : { "table", "flag", "has UNIQUE", "Publish to EC2" },
176 : { "w2gi.mobilehit", "Yes-No", "Yes", "No" },
177 : { "w2gi.visitors", "No-No", "No", "No" },
178 : { "w2gi.pagedimension", "Yes-Yes", "Yes", "Yes" },
179 1 : };
180 :
181 1 : bool bSuccess = checkOutput<4>(m_pDoc, aDataRange, aOutputCheck, "Sorted by column with formula");
182 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
183 : }
184 :
185 1 : if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "CONCATENATE(C2;\"-\";D2)"))
186 0 : CPPUNIT_FAIL("Wrong formula!");
187 1 : if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "CONCATENATE(C3;\"-\";D3)"))
188 0 : CPPUNIT_FAIL("Wrong formula!");
189 1 : if (!checkFormula(*m_pDoc, ScAddress(1,3,0), "CONCATENATE(C4;\"-\";D4)"))
190 0 : CPPUNIT_FAIL("Wrong formula!");
191 :
192 2 : m_pDoc->DeleteTab(0);
193 1 : }
194 :
195 1 : void Test::testSortHorizontalWholeColumn()
196 : {
197 1 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true);
198 1 : m_pDoc->InsertTab(0, "Sort");
199 :
200 : // 0 = empty cell
201 : const char* aData[][5] = {
202 : { "4", "2", "47", "a", "9" }
203 1 : };
204 :
205 : // Insert row data to C1:G1.
206 1 : ScRange aSortRange = insertRangeData(m_pDoc, ScAddress(2,0,0), aData, SAL_N_ELEMENTS(aData));
207 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(2,0,0)));
208 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,0,0)));
209 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(4,0,0)));
210 1 : CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(5,0,0)));
211 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(6,0,0)));
212 :
213 : // Extend the sort range to whole column.
214 1 : aSortRange.aEnd.SetRow(MAXROW);
215 :
216 1 : SCCOL nCol1 = aSortRange.aStart.Col();
217 1 : SCCOL nCol2 = aSortRange.aEnd.Col();
218 1 : SCROW nRow1 = aSortRange.aStart.Row();
219 1 : SCROW nRow2 = aSortRange.aEnd.Row();
220 :
221 : // Define C:G as sheet-local anonymous database range.
222 : m_pDoc->SetAnonymousDBData(
223 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, nCol1, nRow1, nCol2, nRow2, false, false));
224 :
225 : // Sort C:G horizontally ascending by row 1.
226 2 : ScDBDocFunc aFunc(getDocShell());
227 :
228 2 : ScSortParam aSortData;
229 1 : aSortData.nCol1 = nCol1;
230 1 : aSortData.nCol2 = nCol2;
231 1 : aSortData.nRow1 = nRow1;
232 1 : aSortData.nRow2 = nRow2;
233 1 : aSortData.bHasHeader = false;
234 1 : aSortData.bByRow = false; // Sort by column (in horizontal direction).
235 1 : aSortData.bIncludePattern = true;
236 1 : aSortData.maKeyState[0].bDoSort = true;
237 1 : aSortData.maKeyState[0].nField = 0;
238 1 : aSortData.maKeyState[0].bAscending = true;
239 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
240 1 : CPPUNIT_ASSERT(bSorted);
241 :
242 : // Check the sort result.
243 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
244 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(3,0,0)));
245 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
246 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(5,0,0)));
247 1 : CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(6,0,0)));
248 :
249 : // Undo and check.
250 :
251 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
252 1 : CPPUNIT_ASSERT(pUndoMgr);
253 :
254 1 : pUndoMgr->Undo();
255 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(2,0,0)));
256 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,0,0)));
257 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(4,0,0)));
258 1 : CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(5,0,0)));
259 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(6,0,0)));
260 :
261 : // Redo and check.
262 1 : pUndoMgr->Redo();
263 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
264 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(3,0,0)));
265 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
266 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(5,0,0)));
267 1 : CPPUNIT_ASSERT_EQUAL(OUString("a"), m_pDoc->GetString(ScAddress(6,0,0)));
268 :
269 2 : m_pDoc->DeleteTab(0);
270 1 : }
271 :
272 1 : void Test::testSortSingleRow()
273 : {
274 : // This test case is from fdo#80462.
275 :
276 1 : m_pDoc->InsertTab(0, "Test");
277 :
278 : // Sort range consists of only one row.
279 1 : m_pDoc->SetString(ScAddress(0,0,0), "X");
280 1 : m_pDoc->SetString(ScAddress(1,0,0), "Y");
281 :
282 : // Define A1:B1 as sheet-local anonymous database range.
283 : m_pDoc->SetAnonymousDBData(
284 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 1, 0));
285 :
286 : // Sort A1:B1 horizontally, ascending by row 1.
287 1 : ScDBDocFunc aFunc(getDocShell());
288 :
289 2 : ScSortParam aSortData;
290 1 : aSortData.nCol1 = 0;
291 1 : aSortData.nCol2 = 1;
292 1 : aSortData.nRow1 = 0;
293 1 : aSortData.nRow2 = 0;
294 1 : aSortData.bHasHeader = true;
295 1 : aSortData.bByRow = true;
296 1 : aSortData.bIncludePattern = true;
297 1 : aSortData.maKeyState[0].bDoSort = true;
298 1 : aSortData.maKeyState[0].nField = 0;
299 1 : aSortData.maKeyState[0].bAscending = true;
300 :
301 : // Do the sorting. This should not crash.
302 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
303 1 : CPPUNIT_ASSERT(bSorted);
304 :
305 : // Another test case - single row horizontal sort with header column.
306 1 : clearSheet(m_pDoc, 0);
307 :
308 : // A1:G1
309 1 : m_pDoc->SetString(ScAddress(0,0,0), "Header");
310 1 : m_pDoc->SetValue(ScAddress(1,0,0), 1.0);
311 1 : m_pDoc->SetValue(ScAddress(2,0,0), 10.0);
312 1 : m_pDoc->SetValue(ScAddress(3,0,0), 3.0);
313 1 : m_pDoc->SetValue(ScAddress(4,0,0), 9.0);
314 1 : m_pDoc->SetValue(ScAddress(5,0,0), 12.0);
315 1 : m_pDoc->SetValue(ScAddress(6,0,0), 2.0);
316 :
317 : // Define A1:G1 as sheet-local anonymous database range.
318 : m_pDoc->SetAnonymousDBData(
319 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 6, 0, false, true));
320 :
321 : // Update the sort data.
322 1 : aSortData.nCol1 = 0;
323 1 : aSortData.nCol2 = 6;
324 1 : aSortData.bByRow = false;
325 1 : bSorted = aFunc.Sort(0, aSortData, true, true, true);
326 1 : CPPUNIT_ASSERT(bSorted);
327 :
328 : // Check the result.
329 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
330 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
331 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
332 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
333 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
334 1 : CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(5,0,0)));
335 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(6,0,0)));
336 :
337 : // Undo and check.
338 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
339 1 : CPPUNIT_ASSERT(pUndoMgr);
340 1 : pUndoMgr->Undo();
341 :
342 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
343 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
344 1 : CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(2,0,0)));
345 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
346 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
347 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(5,0,0)));
348 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(6,0,0)));
349 :
350 : // Redo and check.
351 1 : pUndoMgr->Redo();
352 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
353 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(1,0,0)));
354 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
355 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,0,0)));
356 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(4,0,0)));
357 1 : CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(5,0,0)));
358 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(6,0,0)));
359 :
360 2 : m_pDoc->DeleteTab(0);
361 1 : }
362 :
363 : // regression test fo fdo#53814, sorting doesn't work as expected
364 : // if cells in the sort are referenced by formulas
365 1 : void Test::testSortWithFormulaRefs()
366 : {
367 1 : SortRefUpdateSetter aUpdateSet;
368 :
369 1 : m_pDoc->InsertTab(0, "List1");
370 1 : m_pDoc->InsertTab(1, "List2");
371 :
372 : const char* aFormulaData[6] = {
373 : "=IF($List1.A2<>\"\";$List1.A2;\"\")",
374 : "=IF($List1.A3<>\"\";$List1.A3;\"\")",
375 : "=IF($List1.A4<>\"\";$List1.A4;\"\")",
376 : "=IF($List1.A5<>\"\";$List1.A5;\"\")",
377 : "=IF($List1.A6<>\"\";$List1.A6;\"\")",
378 : "=IF($List1.A7<>\"\";$List1.A7;\"\")",
379 1 : };
380 :
381 : const char* aTextData[4] = {
382 : "bob",
383 : "tim",
384 : "brian",
385 : "larry",
386 1 : };
387 :
388 : const char* aResults[6] = {
389 : "bob",
390 : "brian",
391 : "larry",
392 : "tim",
393 : "",
394 : "",
395 1 : };
396 :
397 : // Insert data to sort in A2:A5 on the 1st sheet.
398 5 : for (SCROW i = 1; i <= 4; ++i)
399 4 : m_pDoc->SetString( 0, i, 0, OUString::createFromAscii(aTextData[i-1]) );
400 :
401 : // Insert forumulas in A1:A6 on the 2nd sheet.
402 7 : for (size_t i = 0; i < SAL_N_ELEMENTS(aFormulaData); ++i)
403 6 : m_pDoc->SetString( 0, i, 1, OUString::createFromAscii(aFormulaData[i]) );
404 :
405 : // Sort data in A2:A8 on the 1st sheet. No column header.
406 2 : ScSortParam aSortData;
407 1 : aSortData.nCol1 = 0;
408 1 : aSortData.nCol2 = 0;
409 1 : aSortData.nRow1 = 1;
410 1 : aSortData.nRow2 = 7;
411 1 : aSortData.maKeyState[0].bDoSort = true;
412 1 : aSortData.maKeyState[0].nField = 0;
413 :
414 1 : m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
415 :
416 7 : for (size_t i = 0; i < SAL_N_ELEMENTS(aResults); ++i)
417 : {
418 6 : OUString sResult = m_pDoc->GetString(0, i + 1, 0);
419 6 : CPPUNIT_ASSERT_EQUAL( OUString::createFromAscii( aResults[i] ), sResult );
420 6 : }
421 1 : m_pDoc->DeleteTab(1);
422 2 : m_pDoc->DeleteTab(0);
423 1 : }
424 :
425 1 : void Test::testSortWithStrings()
426 : {
427 1 : m_pDoc->InsertTab(0, "Test");
428 :
429 1 : ScFieldEditEngine& rEE = m_pDoc->GetEditEngine();
430 1 : rEE.SetText("Val1");
431 1 : m_pDoc->SetString(ScAddress(1,1,0), "Header");
432 1 : m_pDoc->SetString(ScAddress(1,2,0), "Val2");
433 1 : m_pDoc->SetEditText(ScAddress(1,3,0), rEE.CreateTextObject());
434 :
435 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
436 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
437 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
438 :
439 1 : ScSortParam aParam;
440 1 : aParam.nCol1 = 1;
441 1 : aParam.nCol2 = 1;
442 1 : aParam.nRow1 = 1;
443 1 : aParam.nRow2 = 3;
444 1 : aParam.bHasHeader = true;
445 1 : aParam.maKeyState[0].bDoSort = true;
446 1 : aParam.maKeyState[0].bAscending = true;
447 1 : aParam.maKeyState[0].nField = 1;
448 :
449 1 : m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
450 :
451 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
452 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,2,0)));
453 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,3,0)));
454 :
455 1 : aParam.maKeyState[0].bAscending = false;
456 :
457 1 : m_pDoc->Sort(0, aParam, false, true, NULL, NULL);
458 :
459 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(1,1,0)));
460 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val2"), m_pDoc->GetString(ScAddress(1,2,0)));
461 1 : CPPUNIT_ASSERT_EQUAL(OUString("Val1"), m_pDoc->GetString(ScAddress(1,3,0)));
462 :
463 1 : m_pDoc->DeleteTab(0);
464 1 : }
465 :
466 1 : void Test::testSortInFormulaGroup()
467 : {
468 1 : SortRefUpdateSetter aUpdateSet;
469 :
470 : static struct {
471 : SCCOL nCol;
472 : SCROW nRow;
473 : const char *pData;
474 : } aEntries[] = {
475 : { 0, 0, "3" }, { 1, 0, "=A1" },
476 : { 0, 1, "1" }, { 1, 1, "=A2" },
477 : { 0, 2, "20" }, { 1, 2, "=A3" },
478 : { 0, 3, "10" }, { 1, 3, "=A4+1" }, // swap across groups
479 : { 0, 4, "2" }, { 1, 4, "=A5+1" },
480 : { 0, 5, "101" }, { 1, 5, "=A6" }, // swap inside contiguious group
481 : { 0, 6, "100" }, { 1, 6, "=A7" },
482 : { 0, 7, "102" }, { 1, 7, "=A8" },
483 : { 0, 8, "104" }, { 1, 8, "=A9" },
484 : { 0, 9, "103" }, { 1, 9, "=A10" },
485 : };
486 :
487 1 : m_pDoc->InsertTab(0, "sorttest");
488 :
489 21 : for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
490 : m_pDoc->SetString( aEntries[i].nCol, aEntries[i].nRow, 0,
491 20 : OUString::createFromAscii( aEntries[i].pData) );
492 :
493 2 : ScSortParam aSortData;
494 1 : aSortData.nCol1 = 0;
495 1 : aSortData.nCol2 = 1;
496 1 : aSortData.nRow1 = 0;
497 1 : aSortData.nRow2 = 9;
498 1 : aSortData.maKeyState[0].bDoSort = true;
499 1 : aSortData.maKeyState[0].nField = 0;
500 1 : aSortData.maKeyState[0].bAscending = true;
501 :
502 1 : m_pDoc->Sort(0, aSortData, false, true, NULL, NULL);
503 :
504 : static struct {
505 : SCCOL nCol;
506 : SCROW nRow;
507 : double fValue;
508 : } aResults[] = {
509 : { 0, 0, 1.0 }, { 1, 0, 1.0 },
510 : { 0, 1, 2.0 }, { 1, 1, 3.0 },
511 : { 0, 2, 3.0 }, { 1, 2, 3.0 },
512 : { 0, 3, 10.0 }, { 1, 3, 11.0 },
513 : { 0, 4, 20.0 }, { 1, 4, 20.0 },
514 : { 0, 5, 100.0 }, { 1, 5, 100.0 },
515 : { 0, 6, 101.0 }, { 1, 6, 101.0 },
516 : { 0, 7, 102.0 }, { 1, 7, 102.0 },
517 : { 0, 8, 103.0 }, { 1, 8, 103.0 },
518 : { 0, 9, 104.0 }, { 1, 9, 104.0 },
519 : };
520 :
521 21 : for ( SCROW i = 0; i < (SCROW) SAL_N_ELEMENTS( aEntries ); ++i )
522 : {
523 20 : double val = m_pDoc->GetValue( aEntries[i].nCol, aEntries[i].nRow, 0 );
524 : // fprintf(stderr, "value at %d %d is %g = %g\n",
525 : // (int)aResults[i].nRow, (int)aResults[i].nCol,
526 : // val, aResults[i].fValue);
527 40 : CPPUNIT_ASSERT_MESSAGE("Mis-matching value after sort.",
528 20 : rtl::math::approxEqual(val, aResults[i].fValue));
529 : }
530 :
531 2 : m_pDoc->DeleteTab( 0 );
532 1 : }
533 :
534 1 : void Test::testSortWithCellFormats()
535 : {
536 : struct
537 : {
538 2 : bool isBold( const ScPatternAttr* pPat ) const
539 : {
540 2 : if (!pPat)
541 : {
542 0 : cerr << "Pattern is NULL!" << endl;
543 0 : return false;
544 : }
545 :
546 2 : const SfxPoolItem* pItem = NULL;
547 2 : if (!pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
548 : {
549 0 : cerr << "Pattern does not have a font weight item, but it should." << endl;
550 0 : return false;
551 : }
552 :
553 2 : CPPUNIT_ASSERT(pItem);
554 :
555 2 : if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() != WEIGHT_BOLD)
556 : {
557 0 : cerr << "Font weight should be bold." << endl;
558 0 : return false;
559 : }
560 :
561 2 : return true;
562 : }
563 :
564 2 : bool isItalic( const ScPatternAttr* pPat ) const
565 : {
566 2 : if (!pPat)
567 : {
568 0 : cerr << "Pattern is NULL!" << endl;
569 0 : return false;
570 : }
571 :
572 2 : const SfxPoolItem* pItem = NULL;
573 2 : if (!pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
574 : {
575 0 : cerr << "Pattern does not have a font posture item, but it should." << endl;
576 0 : return false;
577 : }
578 :
579 2 : CPPUNIT_ASSERT(pItem);
580 :
581 2 : if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() != ITALIC_NORMAL)
582 : {
583 0 : cerr << "Italic should be applied.." << endl;
584 0 : return false;
585 : }
586 :
587 2 : return true;
588 : }
589 :
590 1 : bool isNormal( const ScPatternAttr* pPat ) const
591 : {
592 1 : if (!pPat)
593 : {
594 0 : cerr << "Pattern is NULL!" << endl;
595 0 : return false;
596 : }
597 :
598 1 : const SfxPoolItem* pItem = NULL;
599 1 : if (pPat->GetItemSet().HasItem(ATTR_FONT_WEIGHT, &pItem))
600 : {
601 : // Check if the font weight is applied.
602 0 : if (static_cast<const SvxWeightItem*>(pItem)->GetEnumValue() == WEIGHT_BOLD)
603 : {
604 0 : cerr << "This cell is bold, but shouldn't." << endl;
605 0 : return false;
606 : }
607 : }
608 :
609 1 : if (pPat->GetItemSet().HasItem(ATTR_FONT_POSTURE, &pItem))
610 : {
611 : // Check if the italics is applied.
612 0 : if (static_cast<const SvxPostureItem*>(pItem)->GetEnumValue() == ITALIC_NORMAL)
613 : {
614 0 : cerr << "This cell is bold, but shouldn't." << endl;
615 0 : return false;
616 : }
617 : }
618 :
619 1 : return true;
620 : }
621 :
622 : } aCheck;
623 :
624 1 : m_pDoc->InsertTab(0, "Test");
625 :
626 : // Insert some values into A1:A4.
627 1 : m_pDoc->SetString(ScAddress(0,0,0), "Header");
628 1 : m_pDoc->SetString(ScAddress(0,1,0), "Normal");
629 1 : m_pDoc->SetString(ScAddress(0,2,0), "Bold");
630 1 : m_pDoc->SetString(ScAddress(0,3,0), "Italic");
631 :
632 : // Set A3 bold and A4 italic.
633 1 : const ScPatternAttr* pPat = m_pDoc->GetPattern(ScAddress(0,2,0));
634 1 : CPPUNIT_ASSERT(pPat);
635 : {
636 1 : ScPatternAttr aNewPat(*pPat);
637 1 : SfxItemSet& rSet = aNewPat.GetItemSet();
638 1 : rSet.Put(SvxWeightItem(WEIGHT_BOLD, ATTR_FONT_WEIGHT));
639 1 : m_pDoc->ApplyPattern(0, 2, 0, aNewPat);
640 :
641 : // Make sure it's really in.
642 1 : bool bGood = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,2,0)));
643 1 : CPPUNIT_ASSERT_MESSAGE("A3 is not bold but it should.", bGood);
644 : }
645 :
646 1 : pPat = m_pDoc->GetPattern(ScAddress(0,3,0));
647 1 : CPPUNIT_ASSERT(pPat);
648 : {
649 1 : ScPatternAttr aNewPat(*pPat);
650 1 : SfxItemSet& rSet = aNewPat.GetItemSet();
651 1 : rSet.Put(SvxPostureItem(ITALIC_NORMAL, ATTR_FONT_POSTURE));
652 1 : m_pDoc->ApplyPattern(0, 3, 0, aNewPat);
653 :
654 1 : bool bGood = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,3,0)));
655 1 : CPPUNIT_ASSERT_MESSAGE("A4 is not italic but it should.", bGood);
656 : }
657 :
658 : // Define A1:A4 as sheet-local anonymous database range, else sort wouldn't run.
659 : m_pDoc->SetAnonymousDBData(
660 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 3));
661 :
662 : // Sort A1:A4 ascending with cell formats.
663 1 : ScDBDocFunc aFunc(getDocShell());
664 :
665 2 : ScSortParam aSortData;
666 1 : aSortData.nCol1 = 0;
667 1 : aSortData.nCol2 = 0;
668 1 : aSortData.nRow1 = 0;
669 1 : aSortData.nRow2 = 3;
670 1 : aSortData.bHasHeader = true;
671 1 : aSortData.bIncludePattern = true;
672 1 : aSortData.maKeyState[0].bDoSort = true;
673 1 : aSortData.maKeyState[0].nField = 0;
674 1 : aSortData.maKeyState[0].bAscending = true;
675 1 : bool bSorted = aFunc.Sort(0, aSortData, true, false, true);
676 1 : CPPUNIT_ASSERT(bSorted);
677 :
678 : // Check the sort result.
679 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
680 1 : CPPUNIT_ASSERT_EQUAL(OUString("Bold"), m_pDoc->GetString(ScAddress(0,1,0)));
681 1 : CPPUNIT_ASSERT_EQUAL(OUString("Italic"), m_pDoc->GetString(ScAddress(0,2,0)));
682 1 : CPPUNIT_ASSERT_EQUAL(OUString("Normal"), m_pDoc->GetString(ScAddress(0,3,0)));
683 :
684 : // A2 should be bold now.
685 1 : bool bBold = aCheck.isBold(m_pDoc->GetPattern(ScAddress(0,1,0)));
686 1 : CPPUNIT_ASSERT_MESSAGE("A2 should be bold after the sort.", bBold);
687 :
688 : // and A3 should be italic.
689 1 : bool bItalic = aCheck.isItalic(m_pDoc->GetPattern(ScAddress(0,2,0)));
690 1 : CPPUNIT_ASSERT_MESSAGE("A3 should be italic.", bItalic);
691 :
692 : // A4 should have neither bold nor italic.
693 1 : bool bNormal = aCheck.isNormal(m_pDoc->GetPattern(ScAddress(0,3,0)));
694 1 : CPPUNIT_ASSERT_MESSAGE("A4 should be neither bold nor italic.", bNormal);
695 :
696 2 : m_pDoc->DeleteTab(0);
697 1 : }
698 :
699 1 : void Test::testSortRefUpdate()
700 : {
701 1 : SortTypeSetter aSortTypeSet(true);
702 :
703 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
704 2 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
705 :
706 1 : m_pDoc->InsertTab(0, "Sort");
707 :
708 : // Set values to sort in column A.
709 1 : m_pDoc->SetString(ScAddress(0,0,0), "Header");
710 :
711 1 : double aValues[] = { 4.0, 36.0, 14.0, 29.0, 98.0, 78.0, 0.0, 99.0, 1.0 };
712 1 : size_t nCount = SAL_N_ELEMENTS(aValues);
713 10 : for (size_t i = 0; i < nCount; ++i)
714 9 : m_pDoc->SetValue(ScAddress(0,i+1,0), aValues[i]);
715 :
716 : // Set formulas to reference these values in column C.
717 1 : m_pDoc->SetString(ScAddress(2,0,0), "Formula");
718 10 : for (size_t i = 0; i < nCount; ++i)
719 9 : m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
720 :
721 : // Check the values in column C.
722 10 : for (size_t i = 0; i < nCount; ++i)
723 : {
724 9 : double fCheck = aValues[i];
725 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
726 : }
727 :
728 2 : ScDBDocFunc aFunc(getDocShell());
729 :
730 : // Define A1:A10 as sheet-local anonymous database range, else sort wouldn't run.
731 : m_pDoc->SetAnonymousDBData(
732 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 9));
733 :
734 : // Sort A1:A10 (with a header row).
735 2 : ScSortParam aSortData;
736 1 : aSortData.nCol1 = 0;
737 1 : aSortData.nCol2 = 0;
738 1 : aSortData.nRow1 = 0;
739 1 : aSortData.nRow2 = 9;
740 1 : aSortData.bHasHeader = true;
741 1 : aSortData.maKeyState[0].bDoSort = true;
742 1 : aSortData.maKeyState[0].nField = 0;
743 1 : aSortData.maKeyState[0].bAscending = true;
744 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
745 1 : CPPUNIT_ASSERT(bSorted);
746 :
747 1 : double aSorted[] = { 0.0, 1.0, 4.0, 14.0, 29.0, 36.0, 78.0, 98.0, 99.0 };
748 :
749 : // Check the sort result.
750 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
751 10 : for (size_t i = 0; i < nCount; ++i)
752 : {
753 9 : double fCheck = aSorted[i];
754 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
755 : }
756 :
757 : // Sorting should not alter the values in column C.
758 1 : m_pDoc->CalcAll(); // just in case...
759 10 : for (size_t i = 0; i < nCount; ++i)
760 : {
761 9 : double fCheck = aValues[i];
762 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
763 : }
764 :
765 : // C2 should now point to A4.
766 1 : if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "R[2]C[-2]"))
767 0 : CPPUNIT_FAIL("Wrong formula in C2!");
768 :
769 : // Undo the sort.
770 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
771 1 : pUndoMgr->Undo();
772 :
773 : // Check the undo result.
774 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
775 10 : for (size_t i = 0; i < nCount; ++i)
776 : {
777 9 : double fCheck = aValues[i];
778 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
779 : }
780 :
781 : // Values in column C should still be unaltered.
782 1 : m_pDoc->CalcAll(); // just in case...
783 10 : for (size_t i = 0; i < nCount; ++i)
784 : {
785 9 : double fCheck = aValues[i];
786 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
787 : }
788 :
789 : // C2 should now point to A2.
790 1 : if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "RC[-2]"))
791 0 : CPPUNIT_FAIL("Wrong formula in C2!");
792 :
793 : // Redo.
794 1 : pUndoMgr->Redo();
795 :
796 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
797 10 : for (size_t i = 0; i < nCount; ++i)
798 : {
799 9 : double fCheck = aSorted[i];
800 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
801 : }
802 :
803 : // Sorting should not alter the values in column C.
804 1 : m_pDoc->CalcAll(); // just in case...
805 10 : for (size_t i = 0; i < nCount; ++i)
806 : {
807 9 : double fCheck = aValues[i];
808 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0)));
809 : }
810 :
811 : // C2 should now point to A4.
812 1 : if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "R[2]C[-2]"))
813 0 : CPPUNIT_FAIL("Wrong formula in C2!");
814 :
815 : // Undo again.
816 1 : pUndoMgr->Undo();
817 :
818 : // Formulas in column C should all be "RC[-2]" again.
819 10 : for (size_t i = 0; i < nCount; ++i)
820 9 : m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
821 :
822 : // Turn off reference update on sort.
823 1 : SortTypeSetter::changeTo(false);
824 :
825 1 : bSorted = aFunc.Sort(0, aSortData, true, true, true);
826 1 : CPPUNIT_ASSERT(bSorted);
827 :
828 : // Check the sort result again.
829 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
830 10 : for (size_t i = 0; i < nCount; ++i)
831 : {
832 9 : double fCheck = aSorted[i];
833 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(0,i+1,0)));
834 : }
835 :
836 : // Formulas in column C should all remain "RC[-2]".
837 10 : for (size_t i = 0; i < nCount; ++i)
838 9 : m_pDoc->SetString(ScAddress(2,1+i,0), "=RC[-2]");
839 :
840 : // The values in column C should now be the same as sorted values in column A.
841 1 : m_pDoc->CalcAll(); // just in case...
842 10 : for (size_t i = 0; i < nCount; ++i)
843 : {
844 9 : double fCheck = aSorted[i];
845 9 : CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i+1,0))); // column C
846 : }
847 :
848 2 : m_pDoc->DeleteTab(0);
849 1 : }
850 :
851 1 : void Test::testSortRefUpdate2()
852 : {
853 1 : SortRefUpdateSetter aUpdateSet;
854 :
855 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
856 2 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
857 :
858 1 : m_pDoc->InsertTab(0, "Sort");
859 :
860 : // Set up the sheet.
861 : const char* aData[][2] = {
862 : { "F1", "F2" },
863 : { "9", "=RC[-1]" },
864 : { "2", "=RC[-1]" },
865 : { "6", "=RC[-1]" },
866 : { "4", "=RC[-1]" },
867 : { 0, 0 } // terminator
868 1 : };
869 :
870 6 : for (SCROW i = 0; aData[i][0]; ++i)
871 : {
872 5 : m_pDoc->SetString(0, i, 0, OUString::createFromAscii(aData[i][0]));
873 5 : m_pDoc->SetString(1, i, 0, OUString::createFromAscii(aData[i][1]));
874 : }
875 :
876 : // Check the values in B2:B5.
877 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,1,0)));
878 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
879 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
880 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,4,0)));
881 :
882 2 : ScDBDocFunc aFunc(getDocShell());
883 :
884 : // Define A1:B5 as sheet-local anonymous database range, else sort wouldn't run.
885 : m_pDoc->SetAnonymousDBData(
886 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 1, 4));
887 :
888 : // Sort A1:B5 by column A (with a row header).
889 2 : ScSortParam aSortData;
890 1 : aSortData.nCol1 = 0;
891 1 : aSortData.nCol2 = 1;
892 1 : aSortData.nRow1 = 0;
893 1 : aSortData.nRow2 = 4;
894 1 : aSortData.bHasHeader = true;
895 1 : aSortData.maKeyState[0].bDoSort = true;
896 1 : aSortData.maKeyState[0].nField = 0;
897 1 : aSortData.maKeyState[0].bAscending = true;
898 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
899 1 : CPPUNIT_ASSERT(bSorted);
900 :
901 : // Check the sort result in column A.
902 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(0,1,0)));
903 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(0,2,0)));
904 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(0,3,0)));
905 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
906 :
907 : // and column B.
908 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
909 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,2,0)));
910 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
911 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,4,0)));
912 :
913 : // Formulas in column B should still point to their respective left neighbor cell.
914 5 : for (SCROW i = 1; i <= 4; ++i)
915 : {
916 4 : if (!checkFormula(*m_pDoc, ScAddress(1,i,0), "RC[-1]"))
917 0 : CPPUNIT_FAIL("Wrong formula!");
918 : }
919 :
920 : // Undo and check the result in column B.
921 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
922 1 : pUndoMgr->Undo();
923 :
924 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,1,0)));
925 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
926 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
927 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,4,0)));
928 :
929 : // and redo.
930 1 : pUndoMgr->Redo();
931 :
932 1 : CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,1,0)));
933 1 : CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(ScAddress(1,2,0)));
934 1 : CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,3,0)));
935 1 : CPPUNIT_ASSERT_EQUAL(9.0, m_pDoc->GetValue(ScAddress(1,4,0)));
936 :
937 2 : m_pDoc->DeleteTab(0);
938 1 : }
939 :
940 1 : void Test::testSortRefUpdate3()
941 : {
942 1 : SortRefUpdateSetter aUpdateSet;
943 :
944 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
945 1 : m_pDoc->InsertTab(0, "Sort");
946 :
947 : const char* pData[] = {
948 : "Header",
949 : "1",
950 : "=A2+10",
951 : "2",
952 : "=A4+10",
953 : "=A2+A4",
954 : 0 // terminator
955 1 : };
956 :
957 7 : for (SCROW i = 0; pData[i]; ++i)
958 6 : m_pDoc->SetString(ScAddress(0,i,0), OUString::createFromAscii(pData[i]));
959 :
960 : // Check the initial values.
961 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
962 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
963 1 : CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,2,0)));
964 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
965 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,4,0)));
966 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,5,0)));
967 :
968 2 : ScDBDocFunc aFunc(getDocShell());
969 :
970 : // Sort A1:A6.
971 : m_pDoc->SetAnonymousDBData(
972 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 5));
973 :
974 : // Sort A1:A6 by column A (with a row header).
975 2 : ScSortParam aSortData;
976 1 : aSortData.nCol1 = 0;
977 1 : aSortData.nCol2 = 0;
978 1 : aSortData.nRow1 = 0;
979 1 : aSortData.nRow2 = 5;
980 1 : aSortData.bHasHeader = true;
981 1 : aSortData.maKeyState[0].bDoSort = true;
982 1 : aSortData.maKeyState[0].nField = 0;
983 1 : aSortData.maKeyState[0].bAscending = true;
984 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
985 1 : CPPUNIT_ASSERT(bSorted);
986 :
987 : // Check the sorted values.
988 1 : m_pDoc->CalcAll();
989 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
990 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
991 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
992 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
993 1 : CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,4,0)));
994 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,5,0)));
995 :
996 : // Make sure the formula cells have been adjusted correctly.
997 1 : if (!checkFormula(*m_pDoc, ScAddress(0,3,0), "A2+A3"))
998 0 : CPPUNIT_FAIL("Wrong formula in A4.");
999 1 : if (!checkFormula(*m_pDoc, ScAddress(0,4,0), "A2+10"))
1000 0 : CPPUNIT_FAIL("Wrong formula in A5.");
1001 1 : if (!checkFormula(*m_pDoc, ScAddress(0,5,0), "A3+10"))
1002 0 : CPPUNIT_FAIL("Wrong formula in A6.");
1003 :
1004 : // Undo and check the result.
1005 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
1006 1 : pUndoMgr->Undo();
1007 1 : m_pDoc->CalcAll();
1008 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
1009 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
1010 1 : CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,2,0)));
1011 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
1012 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,4,0)));
1013 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,5,0)));
1014 :
1015 : // Redo and check the result.
1016 1 : pUndoMgr->Redo();
1017 1 : m_pDoc->CalcAll();
1018 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
1019 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
1020 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,2,0)));
1021 1 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(0,3,0)));
1022 1 : CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(0,4,0)));
1023 1 : CPPUNIT_ASSERT_EQUAL(12.0, m_pDoc->GetValue(ScAddress(0,5,0)));
1024 :
1025 2 : m_pDoc->DeleteTab(0);
1026 1 : }
1027 :
1028 : // Derived from fdo#79441 https://bugs.freedesktop.org/attachment.cgi?id=100144
1029 : // testRefInterne.ods
1030 1 : void Test::testSortRefUpdate4()
1031 : {
1032 : // This test has to work in both update reference modes.
1033 : {
1034 1 : SortRefNoUpdateSetter aUpdateSet;
1035 1 : testSortRefUpdate4_Impl();
1036 : }
1037 : {
1038 1 : SortRefUpdateSetter aUpdateSet;
1039 1 : testSortRefUpdate4_Impl();
1040 : }
1041 1 : }
1042 :
1043 2 : void Test::testSortRefUpdate4_Impl()
1044 : {
1045 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
1046 2 : m_pDoc->InsertTab(0, "Sort");
1047 2 : m_pDoc->InsertTab(1, "Lesson1");
1048 2 : m_pDoc->InsertTab(2, "Lesson2");
1049 :
1050 2 : ScRange aLesson1Range;
1051 : {
1052 : const char* aData[][2] = {
1053 : { "Name", "Note" },
1054 : { "Student1", "1" },
1055 : { "Student2", "2" },
1056 : { "Student3", "3" },
1057 : { "Student4", "4" },
1058 : { "Student5", "5" },
1059 2 : };
1060 :
1061 2 : SCTAB nTab = 1;
1062 2 : ScAddress aPos(0,0,nTab);
1063 2 : clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
1064 2 : aLesson1Range = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1065 2 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aLesson1Range.aStart == aPos);
1066 : }
1067 :
1068 2 : ScRange aLesson2Range;
1069 : {
1070 : const char* aData[][2] = {
1071 : { "Name", "Note" },
1072 : { "=Lesson1.A2", "3" },
1073 : { "=Lesson1.A3", "4" },
1074 : { "=Lesson1.A4", "9" },
1075 : { "=Lesson1.A5", "6" },
1076 : { "=Lesson1.A6", "3" },
1077 2 : };
1078 :
1079 2 : SCTAB nTab = 2;
1080 2 : ScAddress aPos(0,0,nTab);
1081 2 : clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
1082 2 : aLesson2Range = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1083 2 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aLesson2Range.aStart == aPos);
1084 : }
1085 :
1086 2 : ScRange aSortRange;
1087 : {
1088 : const char* aData[][4] = {
1089 : { "Name", "Lesson1", "Lesson2", "Average" },
1090 : { "=Lesson1.A2", "=Lesson1.B2", "=Lesson2.B2", "=AVERAGE(B2:C2)" },
1091 : { "=Lesson1.A3", "=Lesson1.B3", "=Lesson2.B3", "=AVERAGE(B3:C3)" },
1092 : { "=Lesson1.A4", "=Lesson1.B4", "=Lesson2.B4", "=AVERAGE(B4:C4)" },
1093 : { "=Lesson1.A5", "=Lesson1.B5", "=Lesson2.B5", "=AVERAGE(B5:C5)" },
1094 : { "=Lesson1.A6", "=Lesson1.B6", "=Lesson2.B6", "=AVERAGE(B6:C6)" },
1095 2 : };
1096 :
1097 2 : SCTAB nTab = 0;
1098 2 : ScAddress aPos(0,0,nTab);
1099 2 : clearRange(m_pDoc, ScRange(0, 0, nTab, 1, SAL_N_ELEMENTS(aData), nTab));
1100 2 : aSortRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1101 2 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aSortRange.aStart == aPos);
1102 : }
1103 :
1104 4 : ScDBDocFunc aFunc(getDocShell());
1105 :
1106 : // Sort A1:D6 by column D (Average, with a row header).
1107 : {
1108 2 : ScSortParam aSortData;
1109 2 : aSortData.nCol1 = aSortRange.aStart.Col();
1110 2 : aSortData.nCol2 = aSortRange.aEnd.Col();
1111 2 : aSortData.nRow1 = aSortRange.aStart.Row();
1112 2 : aSortData.nRow2 = aSortRange.aEnd.Row();
1113 2 : aSortData.bHasHeader = true;
1114 2 : aSortData.maKeyState[0].bDoSort = true; // sort on
1115 2 : aSortData.maKeyState[0].nField = 3; // Average
1116 2 : aSortData.maKeyState[0].bAscending = false; // descending
1117 :
1118 2 : m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
1119 4 : aSortData.nCol1, aSortData.nRow1, aSortData.nCol2, aSortData.nRow2));
1120 :
1121 2 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1122 2 : CPPUNIT_ASSERT(bSorted);
1123 :
1124 : // Check the sorted values.
1125 2 : m_pDoc->CalcAll();
1126 2 : CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
1127 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student3"), m_pDoc->GetString(ScAddress(0,1,0)));
1128 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student4"), m_pDoc->GetString(ScAddress(0,2,0)));
1129 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student5"), m_pDoc->GetString(ScAddress(0,3,0)));
1130 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student2"), m_pDoc->GetString(ScAddress(0,4,0)));
1131 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student1"), m_pDoc->GetString(ScAddress(0,5,0)));
1132 2 : CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,1,0)));
1133 2 : CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
1134 2 : CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,3,0)));
1135 2 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
1136 2 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
1137 :
1138 : // Make sure the formula cells have been adjusted correctly.
1139 : const char* aCheck[][4] = {
1140 : // Name Lesson1 Lesson2 Average
1141 : { "Lesson1.A4", "Lesson1.B4", "Lesson2.B4", "AVERAGE(B2:C2)" },
1142 : { "Lesson1.A5", "Lesson1.B5", "Lesson2.B5", "AVERAGE(B3:C3)" },
1143 : { "Lesson1.A6", "Lesson1.B6", "Lesson2.B6", "AVERAGE(B4:C4)" },
1144 : { "Lesson1.A3", "Lesson1.B3", "Lesson2.B3", "AVERAGE(B5:C5)" },
1145 : { "Lesson1.A2", "Lesson1.B2", "Lesson2.B2", "AVERAGE(B6:C6)" },
1146 2 : };
1147 12 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aCheck)); ++nRow)
1148 : {
1149 50 : for (SCCOL nCol=0; nCol < 4; ++nCol)
1150 : {
1151 40 : if (!checkFormula(*m_pDoc, ScAddress(nCol,nRow+1,0), aCheck[nRow][nCol]))
1152 0 : CPPUNIT_FAIL(OString("Wrong formula in " + OString('A'+nCol) + OString::number(nRow+2) + ".").getStr());
1153 : }
1154 : }
1155 :
1156 : // Undo and check the result.
1157 2 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
1158 2 : pUndoMgr->Undo();
1159 2 : m_pDoc->CalcAll();
1160 2 : CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
1161 2 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,1,0)));
1162 2 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,2,0)));
1163 2 : CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,3,0)));
1164 2 : CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,4,0)));
1165 2 : CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,5,0)));
1166 :
1167 : // Redo and check the result.
1168 2 : pUndoMgr->Redo();
1169 2 : m_pDoc->CalcAll();
1170 2 : CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
1171 2 : CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,1,0)));
1172 2 : CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
1173 2 : CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,3,0)));
1174 2 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
1175 2 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
1176 : }
1177 :
1178 : // Sort A2:AMJ6 by column A (Name, without header).
1179 : {
1180 2 : ScSortParam aSortData;
1181 2 : aSortData.nCol1 = 0;
1182 2 : aSortData.nCol2 = MAXCOL;
1183 2 : aSortData.nRow1 = aSortRange.aStart.Row()+1;
1184 2 : aSortData.nRow2 = aSortRange.aEnd.Row();
1185 2 : aSortData.bHasHeader = false;
1186 2 : aSortData.maKeyState[0].bDoSort = true; // sort on
1187 2 : aSortData.maKeyState[0].nField = 0; // Name
1188 2 : aSortData.maKeyState[0].bAscending = false; // descending
1189 :
1190 2 : m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
1191 4 : aSortData.nCol1, aSortData.nRow1, aSortData.nCol2, aSortData.nRow2));
1192 :
1193 2 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1194 2 : CPPUNIT_ASSERT(bSorted);
1195 :
1196 : // Check the sorted values.
1197 2 : m_pDoc->CalcAll();
1198 2 : CPPUNIT_ASSERT_EQUAL(OUString("Name"), m_pDoc->GetString(ScAddress(0,0,0)));
1199 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student5"), m_pDoc->GetString(ScAddress(0,1,0)));
1200 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student4"), m_pDoc->GetString(ScAddress(0,2,0)));
1201 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student3"), m_pDoc->GetString(ScAddress(0,3,0)));
1202 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student2"), m_pDoc->GetString(ScAddress(0,4,0)));
1203 2 : CPPUNIT_ASSERT_EQUAL(OUString("Student1"), m_pDoc->GetString(ScAddress(0,5,0)));
1204 2 : CPPUNIT_ASSERT_EQUAL( 4.0, m_pDoc->GetValue(ScAddress(3,1,0)));
1205 2 : CPPUNIT_ASSERT_EQUAL( 5.0, m_pDoc->GetValue(ScAddress(3,2,0)));
1206 2 : CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue(ScAddress(3,3,0)));
1207 2 : CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue(ScAddress(3,4,0)));
1208 2 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(3,5,0)));
1209 :
1210 : // Make sure the formula cells have been adjusted correctly.
1211 : const char* aCheck[][4] = {
1212 : // Name Lesson1 Lesson2 Average
1213 : { "Lesson1.A6", "Lesson1.B6", "Lesson2.B6", "AVERAGE(B2:C2)" },
1214 : { "Lesson1.A5", "Lesson1.B5", "Lesson2.B5", "AVERAGE(B3:C3)" },
1215 : { "Lesson1.A4", "Lesson1.B4", "Lesson2.B4", "AVERAGE(B4:C4)" },
1216 : { "Lesson1.A3", "Lesson1.B3", "Lesson2.B3", "AVERAGE(B5:C5)" },
1217 : { "Lesson1.A2", "Lesson1.B2", "Lesson2.B2", "AVERAGE(B6:C6)" },
1218 2 : };
1219 12 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aCheck)); ++nRow)
1220 : {
1221 50 : for (SCCOL nCol=0; nCol < 4; ++nCol)
1222 : {
1223 40 : if (!checkFormula(*m_pDoc, ScAddress(nCol,nRow+1,0), aCheck[nRow][nCol]))
1224 0 : CPPUNIT_FAIL(OString("Wrong formula in " + OString('A'+nCol) + OString::number(nRow+2) + ".").getStr());
1225 : }
1226 2 : }
1227 : }
1228 :
1229 2 : m_pDoc->DeleteTab(2);
1230 2 : m_pDoc->DeleteTab(1);
1231 4 : m_pDoc->DeleteTab(0);
1232 2 : }
1233 :
1234 : // Make sure the refupdate works also with volatile cells, see fdo#83067
1235 : /* FIXME: this test is not roll-over-midnight safe and will fail then! We may
1236 : * want to have something different, but due to the nature of volatile
1237 : * functions it's not that easy to come up with something reproducible staying
1238 : * stable over sorts.. ;-) Check for time and don't run test a few seconds
1239 : * before midnight, ermm.. */
1240 1 : void Test::testSortRefUpdate5()
1241 : {
1242 1 : SortRefUpdateSetter aUpdateSet;
1243 :
1244 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
1245 1 : m_pDoc->InsertTab(0, "Sort");
1246 :
1247 : double aValCheck[][3] = {
1248 : // Result, Unsorted order, Sorted result.
1249 : { 0, 4, 0 },
1250 : { 0, 1, 0 },
1251 : { 0, 3, 0 },
1252 : { 0, 2, 0 },
1253 1 : };
1254 1 : ScRange aSortRange;
1255 : {
1256 : const char* aData[][3] = {
1257 : { "Date", "Volatile", "Order" },
1258 : { "1999-05-05", "=TODAY()-$A2", "4" },
1259 : { "1994-10-18", "=TODAY()-$A3", "1" },
1260 : { "1996-06-30", "=TODAY()-$A4", "3" },
1261 : { "1995-11-21", "=TODAY()-$A5", "2" },
1262 1 : };
1263 :
1264 1 : SCTAB nTab = 0;
1265 1 : ScAddress aPos(0,0,nTab);
1266 1 : clearRange(m_pDoc, ScRange(0, 0, nTab, 2, SAL_N_ELEMENTS(aData), nTab));
1267 1 : aSortRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1268 1 : CPPUNIT_ASSERT_MESSAGE("failed to insert range data at correct position", aSortRange.aStart == aPos);
1269 :
1270 : // Actual results and expected sorted results.
1271 5 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
1272 : {
1273 4 : double fVal = m_pDoc->GetValue(ScAddress(1,nRow+1,0));
1274 4 : aValCheck[nRow][0] = fVal;
1275 4 : aValCheck[static_cast<size_t>(aValCheck[nRow][1])-1][2] = fVal;
1276 : }
1277 : }
1278 :
1279 2 : ScDBDocFunc aFunc(getDocShell());
1280 :
1281 : // Sort A1:B5.
1282 1 : m_pDoc->SetAnonymousDBData( 0, new ScDBData( STR_DB_LOCAL_NONAME, aSortRange.aStart.Tab(),
1283 2 : aSortRange.aStart.Col(), aSortRange.aStart.Row(), aSortRange.aEnd.Col(), aSortRange.aEnd.Row()));
1284 :
1285 : // Sort by column A.
1286 2 : ScSortParam aSortData;
1287 1 : aSortData.nCol1 = aSortRange.aStart.Col();
1288 1 : aSortData.nCol2 = aSortRange.aEnd.Col();
1289 1 : aSortData.nRow1 = aSortRange.aStart.Row();
1290 1 : aSortData.nRow2 = aSortRange.aEnd.Row();
1291 1 : aSortData.bHasHeader = true;
1292 1 : aSortData.maKeyState[0].bDoSort = true; // sort on
1293 1 : aSortData.maKeyState[0].nField = 0; // Date
1294 1 : aSortData.maKeyState[0].bAscending = true; // ascending
1295 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1296 1 : CPPUNIT_ASSERT(bSorted);
1297 :
1298 : // Check the sorted values.
1299 1 : m_pDoc->CalcAll();
1300 5 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
1301 : {
1302 4 : size_t i = static_cast<size_t>(m_pDoc->GetValue(ScAddress(2,nRow+1,0))); // order 1..4
1303 4 : CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(nRow+1), i);
1304 4 : CPPUNIT_ASSERT_EQUAL( aValCheck[i-1][2], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
1305 : }
1306 :
1307 : // Make sure the formula cells have been adjusted correctly.
1308 : const char* aFormulaCheck[] = {
1309 : // Volatile
1310 : "TODAY()-$A2",
1311 : "TODAY()-$A3",
1312 : "TODAY()-$A4",
1313 : "TODAY()-$A5",
1314 1 : };
1315 5 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aFormulaCheck)); ++nRow)
1316 : {
1317 4 : if (!checkFormula(*m_pDoc, ScAddress(1,nRow+1,0), aFormulaCheck[nRow]))
1318 0 : CPPUNIT_FAIL(OString("Wrong formula in B" + OString::number(nRow+2) + ".").getStr());
1319 : }
1320 :
1321 : // Undo and check the result.
1322 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
1323 1 : pUndoMgr->Undo();
1324 1 : m_pDoc->CalcAll();
1325 5 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
1326 : {
1327 4 : CPPUNIT_ASSERT_EQUAL( aValCheck[nRow][0], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
1328 4 : CPPUNIT_ASSERT_EQUAL( aValCheck[nRow][1], m_pDoc->GetValue(ScAddress(2,nRow+1,0)));
1329 : }
1330 :
1331 : // Redo and check the result.
1332 1 : pUndoMgr->Redo();
1333 1 : m_pDoc->CalcAll();
1334 5 : for (SCROW nRow=0; nRow < static_cast<SCROW>(SAL_N_ELEMENTS(aValCheck)); ++nRow)
1335 : {
1336 4 : size_t i = static_cast<size_t>(m_pDoc->GetValue(ScAddress(2,nRow+1,0))); // order 1..4
1337 4 : CPPUNIT_ASSERT_EQUAL( static_cast<size_t>(nRow+1), i);
1338 4 : CPPUNIT_ASSERT_EQUAL( aValCheck[i-1][2], m_pDoc->GetValue(ScAddress(1,nRow+1,0)));
1339 : }
1340 :
1341 2 : m_pDoc->DeleteTab(0);
1342 1 : }
1343 :
1344 1 : void Test::testSortRefUpdate6()
1345 : {
1346 1 : SortRefNoUpdateSetter aUpdateSet;
1347 :
1348 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
1349 1 : m_pDoc->InsertTab(0, "Sort");
1350 :
1351 : const char* aData[][3] = {
1352 : { "Order", "Value", "1" },
1353 : { "9", "1", "=C1+B2" },
1354 : { "1", "2", "=C2+B3" },
1355 : { "8", "3", "=C3+B4" },
1356 1 : };
1357 :
1358 1 : ScAddress aPos(0,0,0);
1359 1 : ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1360 1 : CPPUNIT_ASSERT(aDataRange.aStart == aPos);
1361 :
1362 : {
1363 : // Expected output table content. 0 = empty cell
1364 : const char* aOutputCheck[][3] = {
1365 : { "Order", "Value", "1" },
1366 : { "9", "1", "2" },
1367 : { "1", "2", "4" },
1368 : { "8", "3", "7" },
1369 1 : };
1370 :
1371 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
1372 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1373 : }
1374 :
1375 2 : ScDBDocFunc aFunc(getDocShell());
1376 :
1377 : // Sort A1:C4.
1378 : m_pDoc->SetAnonymousDBData(
1379 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 2, 3));
1380 :
1381 : // Sort A1:A6 by column A (with a row header).
1382 2 : ScSortParam aSortData;
1383 1 : aSortData.nCol1 = 0;
1384 1 : aSortData.nCol2 = 2;
1385 1 : aSortData.nRow1 = 0;
1386 1 : aSortData.nRow2 = 3;
1387 1 : aSortData.bHasHeader = true;
1388 1 : aSortData.maKeyState[0].bDoSort = true;
1389 1 : aSortData.maKeyState[0].nField = 0;
1390 1 : aSortData.maKeyState[0].bAscending = true;
1391 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1392 1 : CPPUNIT_ASSERT(bSorted);
1393 :
1394 : {
1395 : // Expected output table content. 0 = empty cell
1396 : const char* aOutputCheck[][3] = {
1397 : { "Order", "Value", "1" },
1398 : { "1", "2", "3" },
1399 : { "8", "3", "6" },
1400 : { "9", "1", "7" },
1401 1 : };
1402 :
1403 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Sorted without reference update");
1404 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1405 : }
1406 :
1407 : // Make sure that the formulas in C2:C4 are not adjusted.
1408 1 : if (!checkFormula(*m_pDoc, ScAddress(2,1,0), "C1+B2"))
1409 0 : CPPUNIT_FAIL("Wrong formula!");
1410 1 : if (!checkFormula(*m_pDoc, ScAddress(2,2,0), "C2+B3"))
1411 0 : CPPUNIT_FAIL("Wrong formula!");
1412 1 : if (!checkFormula(*m_pDoc, ScAddress(2,3,0), "C3+B4"))
1413 0 : CPPUNIT_FAIL("Wrong formula!");
1414 :
1415 : // Undo and check.
1416 1 : SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
1417 1 : CPPUNIT_ASSERT(pUndoMgr);
1418 :
1419 1 : pUndoMgr->Undo();
1420 :
1421 : {
1422 : // Expected output table content. 0 = empty cell
1423 : const char* aOutputCheck[][3] = {
1424 : { "Order", "Value", "1" },
1425 : { "9", "1", "2" },
1426 : { "1", "2", "4" },
1427 : { "8", "3", "7" },
1428 1 : };
1429 :
1430 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "After undo");
1431 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1432 : }
1433 :
1434 : // Redo and check.
1435 1 : pUndoMgr->Redo();
1436 : {
1437 : // Expected output table content. 0 = empty cell
1438 : const char* aOutputCheck[][3] = {
1439 : { "Order", "Value", "1" },
1440 : { "1", "2", "3" },
1441 : { "8", "3", "6" },
1442 : { "9", "1", "7" },
1443 1 : };
1444 :
1445 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "After redo");
1446 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1447 : }
1448 :
1449 : // Change the value of C1 and make sure the formula broadcasting chain still works.
1450 1 : ScDocFunc& rFunc = getDocShell().GetDocFunc();
1451 1 : rFunc.SetValueCell(ScAddress(2,0,0), 11.0, false);
1452 : {
1453 : // Expected output table content. 0 = empty cell
1454 : const char* aOutputCheck[][3] = {
1455 : { "Order", "Value", "11" },
1456 : { "1", "2", "13" },
1457 : { "8", "3", "16" },
1458 : { "9", "1", "17" },
1459 1 : };
1460 :
1461 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "Change the header value");
1462 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1463 : }
1464 :
1465 : // Undo and check.
1466 1 : pUndoMgr->Undo();
1467 : {
1468 : // Expected output table content. 0 = empty cell
1469 : const char* aOutputCheck[][3] = {
1470 : { "Order", "Value", "1" },
1471 : { "1", "2", "3" },
1472 : { "8", "3", "6" },
1473 : { "9", "1", "7" },
1474 1 : };
1475 :
1476 1 : bool bSuccess = checkOutput<3>(m_pDoc, aDataRange, aOutputCheck, "After undo of header value change");
1477 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1478 : }
1479 :
1480 2 : m_pDoc->DeleteTab(0);
1481 1 : }
1482 :
1483 : // fdo#86762 check that broadcasters are sorted correctly and empty cell is
1484 : // broadcasted.
1485 1 : void Test::testSortBroadcaster()
1486 : {
1487 1 : SortRefNoUpdateSetter aUpdateSet;
1488 :
1489 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
1490 1 : m_pDoc->InsertTab(0, "Sort");
1491 :
1492 : {
1493 : const char* aData[][7] = {
1494 : { "1", 0, 0, "=B1", "=$B$1", "=SUM(A1:B1)", "=SUM($A$1:$B$1)" },
1495 : { "2", "8", 0, "=B2", "=$B$2", "=SUM(A2:B2)", "=SUM($A$2:$B$2)" },
1496 1 : };
1497 :
1498 1 : ScAddress aPos(0,0,0);
1499 1 : ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1500 1 : CPPUNIT_ASSERT(aDataRange.aStart == aPos);
1501 :
1502 : {
1503 : // Expected output table content. 0 = empty cell
1504 : const char* aOutputCheck[][7] = {
1505 : { "1", 0, 0, "0", "0", "1", "1" },
1506 : { "2", "8", 0, "8", "8", "10", "10" },
1507 1 : };
1508 :
1509 1 : bool bSuccess = checkOutput<7>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
1510 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1511 : }
1512 :
1513 : // Sort A1:B2.
1514 : m_pDoc->SetAnonymousDBData(
1515 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 1, 1));
1516 :
1517 1 : ScDBDocFunc aFunc(getDocShell());
1518 :
1519 : // Sort A1:B2 by column A descending.
1520 2 : ScSortParam aSortData;
1521 1 : aSortData.nCol1 = 0;
1522 1 : aSortData.nCol2 = 1;
1523 1 : aSortData.nRow1 = 0;
1524 1 : aSortData.nRow2 = 1;
1525 1 : aSortData.bHasHeader = false;
1526 1 : aSortData.bByRow = true;
1527 1 : aSortData.maKeyState[0].bDoSort = true;
1528 1 : aSortData.maKeyState[0].nField = 0;
1529 1 : aSortData.maKeyState[0].bAscending = false;
1530 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1531 1 : CPPUNIT_ASSERT(bSorted);
1532 :
1533 : {
1534 : // Expected output table content. 0 = empty cell
1535 : const char* aOutputCheck[][7] = {
1536 : { "2", "8", 0, "8", "8", "10", "10" },
1537 : { "1", 0, 0, "0", "0", "1", "1" },
1538 1 : };
1539 :
1540 1 : bool bSuccess = checkOutput<7>(m_pDoc, aDataRange, aOutputCheck, "Sorted without reference update");
1541 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1542 : }
1543 :
1544 : // Make sure that the formulas in D1:G2 are not adjusted.
1545 1 : if (!checkFormula(*m_pDoc, ScAddress(3,0,0), "B1"))
1546 0 : CPPUNIT_FAIL("Wrong formula!");
1547 1 : if (!checkFormula(*m_pDoc, ScAddress(3,1,0), "B2"))
1548 0 : CPPUNIT_FAIL("Wrong formula!");
1549 1 : if (!checkFormula(*m_pDoc, ScAddress(4,0,0), "$B$1"))
1550 0 : CPPUNIT_FAIL("Wrong formula!");
1551 1 : if (!checkFormula(*m_pDoc, ScAddress(4,1,0), "$B$2"))
1552 0 : CPPUNIT_FAIL("Wrong formula!");
1553 1 : if (!checkFormula(*m_pDoc, ScAddress(5,0,0), "SUM(A1:B1)"))
1554 0 : CPPUNIT_FAIL("Wrong formula!");
1555 1 : if (!checkFormula(*m_pDoc, ScAddress(5,1,0), "SUM(A2:B2)"))
1556 0 : CPPUNIT_FAIL("Wrong formula!");
1557 1 : if (!checkFormula(*m_pDoc, ScAddress(6,0,0), "SUM($A$1:$B$1)"))
1558 0 : CPPUNIT_FAIL("Wrong formula!");
1559 1 : if (!checkFormula(*m_pDoc, ScAddress(6,1,0), "SUM($A$2:$B$2)"))
1560 0 : CPPUNIT_FAIL("Wrong formula!");
1561 :
1562 : // Enter new value and check that it is broadcasted. First in empty cell.
1563 1 : m_pDoc->SetString(1,1,0, "16");
1564 1 : double nVal = m_pDoc->GetValue(3,1,0);
1565 1 : ASSERT_DOUBLES_EQUAL( 16.0, nVal);
1566 1 : nVal = m_pDoc->GetValue(4,1,0);
1567 1 : ASSERT_DOUBLES_EQUAL( 16.0, nVal);
1568 1 : nVal = m_pDoc->GetValue(5,1,0);
1569 1 : ASSERT_DOUBLES_EQUAL( 17.0, nVal);
1570 1 : nVal = m_pDoc->GetValue(6,1,0);
1571 1 : ASSERT_DOUBLES_EQUAL( 17.0, nVal);
1572 :
1573 : // Enter new value and check that it is broadcasted. Now overwriting data.
1574 1 : m_pDoc->SetString(1,0,0, "32");
1575 1 : nVal = m_pDoc->GetValue(3,0,0);
1576 1 : ASSERT_DOUBLES_EQUAL( 32.0, nVal);
1577 1 : nVal = m_pDoc->GetValue(4,0,0);
1578 1 : ASSERT_DOUBLES_EQUAL( 32.0, nVal);
1579 1 : nVal = m_pDoc->GetValue(5,0,0);
1580 1 : ASSERT_DOUBLES_EQUAL( 34.0, nVal);
1581 1 : nVal = m_pDoc->GetValue(6,0,0);
1582 2 : ASSERT_DOUBLES_EQUAL( 34.0, nVal);
1583 : }
1584 :
1585 : // The same for sort by column. Start data at A5.
1586 :
1587 : {
1588 : const char* aData[][2] = {
1589 : { "1", "2" },
1590 : { 0, "8" },
1591 : { 0, 0 },
1592 : { "=A6", "=B6" },
1593 : { "=$A$6", "=$B$6" },
1594 : { "=SUM(A5:A6)", "=SUM(B5:B6)" },
1595 : { "=SUM($A$5:$A$6)", "=SUM($B$5:$B$6)" },
1596 1 : };
1597 :
1598 1 : ScAddress aPos(0,4,0);
1599 1 : ScRange aDataRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
1600 1 : CPPUNIT_ASSERT(aDataRange.aStart == aPos);
1601 :
1602 : {
1603 : // Expected output table content. 0 = empty cell
1604 : const char* aOutputCheck[][2] = {
1605 : { "1", "2" },
1606 : { 0, "8" },
1607 : { 0, 0 },
1608 : { "0", "8" },
1609 : { "0", "8" },
1610 : { "1", "10" },
1611 : { "1", "10" },
1612 1 : };
1613 :
1614 1 : bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Initial value");
1615 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1616 : }
1617 :
1618 : // Sort A5:B6.
1619 : m_pDoc->SetAnonymousDBData(
1620 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 4, 1, 5));
1621 :
1622 1 : ScDBDocFunc aFunc(getDocShell());
1623 :
1624 : // Sort A5:B6 by row 5 descending.
1625 2 : ScSortParam aSortData;
1626 1 : aSortData.nCol1 = 0;
1627 1 : aSortData.nCol2 = 1;
1628 1 : aSortData.nRow1 = 4;
1629 1 : aSortData.nRow2 = 5;
1630 1 : aSortData.bHasHeader = false;
1631 1 : aSortData.bByRow = false;
1632 1 : aSortData.maKeyState[0].bDoSort = true;
1633 1 : aSortData.maKeyState[0].nField = 0;
1634 1 : aSortData.maKeyState[0].bAscending = false;
1635 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1636 1 : CPPUNIT_ASSERT(bSorted);
1637 :
1638 : {
1639 : // Expected output table content. 0 = empty cell
1640 : const char* aOutputCheck[][2] = {
1641 : { "2", "1" },
1642 : { "8", 0 },
1643 : { 0, 0 },
1644 : { "8", "0" },
1645 : { "8", "0" },
1646 : { "10", "1" },
1647 : { "10", "1" },
1648 1 : };
1649 :
1650 1 : bool bSuccess = checkOutput<2>(m_pDoc, aDataRange, aOutputCheck, "Sorted without reference update");
1651 1 : CPPUNIT_ASSERT_MESSAGE("Table output check failed", bSuccess);
1652 : }
1653 :
1654 : // Make sure that the formulas in A8:B11 are not adjusted.
1655 1 : if (!checkFormula(*m_pDoc, ScAddress(0,7,0), "A6"))
1656 0 : CPPUNIT_FAIL("Wrong formula!");
1657 1 : if (!checkFormula(*m_pDoc, ScAddress(1,7,0), "B6"))
1658 0 : CPPUNIT_FAIL("Wrong formula!");
1659 1 : if (!checkFormula(*m_pDoc, ScAddress(0,8,0), "$A$6"))
1660 0 : CPPUNIT_FAIL("Wrong formula!");
1661 1 : if (!checkFormula(*m_pDoc, ScAddress(1,8,0), "$B$6"))
1662 0 : CPPUNIT_FAIL("Wrong formula!");
1663 1 : if (!checkFormula(*m_pDoc, ScAddress(0,9,0), "SUM(A5:A6)"))
1664 0 : CPPUNIT_FAIL("Wrong formula!");
1665 1 : if (!checkFormula(*m_pDoc, ScAddress(1,9,0), "SUM(B5:B6)"))
1666 0 : CPPUNIT_FAIL("Wrong formula!");
1667 1 : if (!checkFormula(*m_pDoc, ScAddress(0,10,0), "SUM($A$5:$A$6)"))
1668 0 : CPPUNIT_FAIL("Wrong formula!");
1669 1 : if (!checkFormula(*m_pDoc, ScAddress(1,10,0), "SUM($B$5:$B$6)"))
1670 0 : CPPUNIT_FAIL("Wrong formula!");
1671 :
1672 : // Enter new value and check that it is broadcasted. First in empty cell.
1673 1 : m_pDoc->SetString(1,5,0, "16");
1674 1 : double nVal = m_pDoc->GetValue(1,7,0);
1675 1 : ASSERT_DOUBLES_EQUAL(nVal, 16.0);
1676 1 : nVal = m_pDoc->GetValue(1,8,0);
1677 1 : ASSERT_DOUBLES_EQUAL(nVal, 16.0);
1678 1 : nVal = m_pDoc->GetValue(1,9,0);
1679 1 : ASSERT_DOUBLES_EQUAL(nVal, 17.0);
1680 1 : nVal = m_pDoc->GetValue(1,10,0);
1681 1 : ASSERT_DOUBLES_EQUAL(nVal, 17.0);
1682 :
1683 : // Enter new value and check that it is broadcasted. Now overwriting data.
1684 1 : m_pDoc->SetString(0,5,0, "32");
1685 1 : nVal = m_pDoc->GetValue(0,7,0);
1686 1 : ASSERT_DOUBLES_EQUAL(nVal, 32.0);
1687 1 : nVal = m_pDoc->GetValue(0,8,0);
1688 1 : ASSERT_DOUBLES_EQUAL(nVal, 32.0);
1689 1 : nVal = m_pDoc->GetValue(0,9,0);
1690 1 : ASSERT_DOUBLES_EQUAL(nVal, 34.0);
1691 1 : nVal = m_pDoc->GetValue(0,10,0);
1692 2 : ASSERT_DOUBLES_EQUAL(nVal, 34.0);
1693 : }
1694 :
1695 2 : m_pDoc->DeleteTab(0);
1696 1 : }
1697 :
1698 1 : void Test::testSortOutOfPlaceResult()
1699 : {
1700 1 : m_pDoc->InsertTab(0, "Sort");
1701 1 : m_pDoc->InsertTab(1, "Result");
1702 :
1703 : const char* pData[] = {
1704 : "Header",
1705 : "1",
1706 : "23",
1707 : "2",
1708 : "9",
1709 : "-2",
1710 : 0 // terminator
1711 1 : };
1712 :
1713 : // source data in A1:A6.
1714 7 : for (SCROW i = 0; pData[i]; ++i)
1715 6 : m_pDoc->SetString(ScAddress(0,i,0), OUString::createFromAscii(pData[i]));
1716 :
1717 : // Check the initial values.
1718 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
1719 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
1720 1 : CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(0,2,0)));
1721 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
1722 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
1723 1 : CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(0,5,0)));
1724 :
1725 1 : ScDBDocFunc aFunc(getDocShell());
1726 :
1727 : // Sort A1:A6, and set the result to C2:C7
1728 : m_pDoc->SetAnonymousDBData(
1729 1 : 0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 0, 0, 0, 5));
1730 :
1731 2 : ScSortParam aSortData;
1732 1 : aSortData.nCol1 = 0;
1733 1 : aSortData.nCol2 = 0;
1734 1 : aSortData.nRow1 = 0;
1735 1 : aSortData.nRow2 = 5;
1736 1 : aSortData.bHasHeader = true;
1737 1 : aSortData.bInplace = false;
1738 1 : aSortData.nDestTab = 1;
1739 1 : aSortData.nDestCol = 2;
1740 1 : aSortData.nDestRow = 1;
1741 1 : aSortData.maKeyState[0].bDoSort = true;
1742 1 : aSortData.maKeyState[0].nField = 0;
1743 1 : aSortData.maKeyState[0].bAscending = true;
1744 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1745 1 : CPPUNIT_ASSERT(bSorted);
1746 :
1747 : // Source data still intact.
1748 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(0,0,0)));
1749 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(0,1,0)));
1750 1 : CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(0,2,0)));
1751 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(0,3,0)));
1752 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(0,4,0)));
1753 1 : CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(0,5,0)));
1754 :
1755 : // Sort result in C2:C7 on sheet "Result".
1756 1 : CPPUNIT_ASSERT_EQUAL(OUString("Header"), m_pDoc->GetString(ScAddress(2,1,1)));
1757 1 : CPPUNIT_ASSERT_EQUAL(-2.0, m_pDoc->GetValue(ScAddress(2,2,1)));
1758 1 : CPPUNIT_ASSERT_EQUAL( 1.0, m_pDoc->GetValue(ScAddress(2,3,1)));
1759 1 : CPPUNIT_ASSERT_EQUAL( 2.0, m_pDoc->GetValue(ScAddress(2,4,1)));
1760 1 : CPPUNIT_ASSERT_EQUAL( 9.0, m_pDoc->GetValue(ScAddress(2,5,1)));
1761 1 : CPPUNIT_ASSERT_EQUAL(23.0, m_pDoc->GetValue(ScAddress(2,6,1)));
1762 :
1763 1 : m_pDoc->DeleteTab(1);
1764 2 : m_pDoc->DeleteTab(0);
1765 1 : }
1766 :
1767 1 : void Test::testSortPartialFormulaGroup()
1768 : {
1769 1 : SortRefUpdateSetter aUpdateSet;
1770 :
1771 2 : sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
1772 2 : FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
1773 :
1774 1 : m_pDoc->InsertTab(0, "Sort");
1775 :
1776 : // Set up the sheet.
1777 : const char* aData[][2] = {
1778 : { "F1", "F2" },
1779 : { "43", "=RC[-1]" },
1780 : { "50", "=RC[-1]" },
1781 : { "8", "=RC[-1]" },
1782 : { "47", "=RC[-1]" },
1783 : { "28", "=RC[-1]" },
1784 : { 0, 0 } // terminator
1785 1 : };
1786 :
1787 : // A1:B6.
1788 7 : for (SCROW i = 0; aData[i][0]; ++i)
1789 : {
1790 6 : m_pDoc->SetString(0, i, 0, OUString::createFromAscii(aData[i][0]));
1791 6 : m_pDoc->SetString(1, i, 0, OUString::createFromAscii(aData[i][1]));
1792 : }
1793 :
1794 : // Check the initial condition.
1795 6 : for (SCROW i = 1; i <= 5; ++i)
1796 : // A2:A6 should equal B2:B6.
1797 5 : CPPUNIT_ASSERT_EQUAL(m_pDoc->GetValue(ScAddress(0,i,0)), m_pDoc->GetValue(ScAddress(1,i,0)));
1798 :
1799 1 : const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
1800 1 : CPPUNIT_ASSERT(pFC);
1801 1 : CPPUNIT_ASSERT_MESSAGE("This formula cell should be the first in a group.", pFC->IsSharedTop());
1802 1 : CPPUNIT_ASSERT_MESSAGE("Incorrect formula group length.", pFC->GetSharedLength() == 5);
1803 :
1804 2 : ScDBDocFunc aFunc(getDocShell());
1805 :
1806 : // Sort only B2:B4. This caused crash at one point (c.f. fdo#81617).
1807 :
1808 1 : m_pDoc->SetAnonymousDBData(0, new ScDBData(STR_DB_LOCAL_NONAME, 0, 1, 1, 1, 3));
1809 :
1810 2 : ScSortParam aSortData;
1811 1 : aSortData.nCol1 = 1;
1812 1 : aSortData.nCol2 = 1;
1813 1 : aSortData.nRow1 = 1;
1814 1 : aSortData.nRow2 = 3;
1815 1 : aSortData.bHasHeader = false;
1816 1 : aSortData.bInplace = true;
1817 1 : aSortData.maKeyState[0].bDoSort = true;
1818 1 : aSortData.maKeyState[0].nField = 0;
1819 1 : aSortData.maKeyState[0].bAscending = true;
1820 1 : bool bSorted = aFunc.Sort(0, aSortData, true, true, true);
1821 1 : CPPUNIT_ASSERT(bSorted);
1822 :
1823 1 : m_pDoc->CalcAll(); // just in case...
1824 :
1825 : // Check the cell values after the partial sort.
1826 :
1827 : // Column A
1828 1 : CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc->GetValue(ScAddress(0,1,0)));
1829 1 : CPPUNIT_ASSERT_EQUAL(50.0, m_pDoc->GetValue(ScAddress(0,2,0)));
1830 1 : CPPUNIT_ASSERT_EQUAL( 8.0, m_pDoc->GetValue(ScAddress(0,3,0)));
1831 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(0,4,0)));
1832 1 : CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc->GetValue(ScAddress(0,5,0)));
1833 :
1834 : // Column B
1835 1 : CPPUNIT_ASSERT_EQUAL( 8.0, m_pDoc->GetValue(ScAddress(1,1,0)));
1836 1 : CPPUNIT_ASSERT_EQUAL(43.0, m_pDoc->GetValue(ScAddress(1,2,0)));
1837 1 : CPPUNIT_ASSERT_EQUAL(50.0, m_pDoc->GetValue(ScAddress(1,3,0)));
1838 1 : CPPUNIT_ASSERT_EQUAL(47.0, m_pDoc->GetValue(ScAddress(1,4,0)));
1839 1 : CPPUNIT_ASSERT_EQUAL(28.0, m_pDoc->GetValue(ScAddress(1,5,0)));
1840 :
1841 2 : m_pDoc->DeleteTab(0);
1842 4 : }
1843 :
1844 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|