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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/svapp.hxx>
21 #include <comphelper/sequence.hxx>
22 #include <cppuhelper/supportsservice.hxx>
23 
24 #include <cursuno.hxx>
25 #include <cellsuno.hxx>
26 #include <docsh.hxx>
27 #include <markdata.hxx>
28 #include <miscuno.hxx>
29 
30 using namespace com::sun::star;
31 
32 #define SCSHEETCELLCURSOR_SERVICE   "com.sun.star.sheet.SheetCellCursor"
33 #define SCCELLCURSOR_SERVICE        "com.sun.star.table.CellCursor"
34 
ScCellCursorObj(ScDocShell * pDocSh,const ScRange & rR)35 ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) :
36     ScCellRangeObj( pDocSh, rR )
37 {
38 }
39 
~ScCellCursorObj()40 ScCellCursorObj::~ScCellCursorObj()
41 {
42 }
43 
queryInterface(const uno::Type & rType)44 uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType )
45 {
46     SC_QUERYINTERFACE( sheet::XSheetCellCursor )
47     SC_QUERYINTERFACE( sheet::XUsedAreaCursor )
48     SC_QUERYINTERFACE( table::XCellCursor )
49 
50     return ScCellRangeObj::queryInterface( rType );
51 }
52 
acquire()53 void SAL_CALL ScCellCursorObj::acquire() noexcept
54 {
55     ScCellRangeObj::acquire();
56 }
57 
release()58 void SAL_CALL ScCellCursorObj::release() noexcept
59 {
60     ScCellRangeObj::release();
61 }
62 
getTypes()63 uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes()
64 {
65     return comphelper::concatSequences(
66         ScCellRangeObj::getTypes(),
67         uno::Sequence<uno::Type>
68         {
69             cppu::UnoType<sheet::XSheetCellCursor>::get(),
70             cppu::UnoType<sheet::XUsedAreaCursor>::get(),
71             cppu::UnoType<table::XCellCursor>::get()
72         } );
73 }
74 
getImplementationId()75 uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId()
76 {
77     return css::uno::Sequence<sal_Int8>();
78 }
79 
80 // XSheetCellCursor
81 
collapseToCurrentRegion()82 void SAL_CALL ScCellCursorObj::collapseToCurrentRegion()
83 {
84     SolarMutexGuard aGuard;
85     const ScRangeList& rRanges = GetRangeList();
86     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
87     ScRange aOneRange( rRanges[ 0 ] );
88 
89     aOneRange.PutInOrder();
90     ScDocShell* pDocSh = GetDocShell();
91     if ( !pDocSh )
92         return;
93 
94     SCCOL nStartCol = aOneRange.aStart.Col();
95     SCROW nStartRow = aOneRange.aStart.Row();
96     SCCOL nEndCol = aOneRange.aEnd.Col();
97     SCROW nEndRow = aOneRange.aEnd.Row();
98     SCTAB nTab = aOneRange.aStart.Tab();
99 
100     pDocSh->GetDocument().GetDataArea(
101                     nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, false );
102 
103     ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
104     SetNewRange( aNew );
105 }
106 
collapseToCurrentArray()107 void SAL_CALL ScCellCursorObj::collapseToCurrentArray()
108 {
109     SolarMutexGuard aGuard;
110     const ScRangeList& rRanges = GetRangeList();
111     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
112     ScRange aOneRange( rRanges[ 0 ] );
113 
114     aOneRange.PutInOrder();
115     ScAddress aCursor(aOneRange.aStart);        //  use the start address of the range
116 
117     ScDocShell* pDocSh = GetDocShell();
118     if ( pDocSh )
119     {
120         ScDocument& rDoc = pDocSh->GetDocument();
121         ScRange aMatrix;
122 
123         // finding the matrix range is now in GetMatrixFormulaRange in the document
124         if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) )
125         {
126             SetNewRange( aMatrix );
127         }
128     }
129     // that's a Bug, that this assertion comes; the API Reference says, that
130     // if there is no Matrix, the Range is left unchanged; they say nothing
131     // about an exception
132     /*if (!bFound)
133     {
134         OSL_FAIL("no matrix");
135         //! Exception, or what?
136     }*/
137 }
138 
collapseToMergedArea()139 void SAL_CALL ScCellCursorObj::collapseToMergedArea()
140 {
141     SolarMutexGuard aGuard;
142     ScDocShell* pDocSh = GetDocShell();
143     if ( pDocSh )
144     {
145         const ScRangeList& rRanges = GetRangeList();
146         OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
147         ScRange aNewRange( rRanges[ 0 ] );
148 
149         ScDocument& rDoc = pDocSh->GetDocument();
150         rDoc.ExtendOverlapped( aNewRange );
151         rDoc.ExtendMerge( aNewRange );                 // after ExtendOverlapped!
152 
153         SetNewRange( aNewRange );
154     }
155 }
156 
expandToEntireColumns()157 void SAL_CALL ScCellCursorObj::expandToEntireColumns()
158 {
159     SolarMutexGuard aGuard;
160     const ScRangeList& rRanges = GetRangeList();
161     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
162     ScRange aNewRange( rRanges[ 0 ] );
163 
164     aNewRange.aStart.SetRow( 0 );
165     aNewRange.aEnd.SetRow( GetDocShell()->GetDocument().MaxRow() );
166 
167     SetNewRange( aNewRange );
168 }
169 
expandToEntireRows()170 void SAL_CALL ScCellCursorObj::expandToEntireRows()
171 {
172     SolarMutexGuard aGuard;
173     const ScRangeList& rRanges = GetRangeList();
174     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
175     ScRange aNewRange( rRanges[ 0 ] );
176 
177     aNewRange.aStart.SetCol( 0 );
178     aNewRange.aEnd.SetCol( GetDocShell()->GetDocument().MaxCol() );
179 
180     SetNewRange( aNewRange );
181 }
182 
collapseToSize(sal_Int32 nColumns,sal_Int32 nRows)183 void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows )
184 {
185     SolarMutexGuard aGuard;
186     if ( nColumns <= 0 || nRows <= 0 )
187     {
188         OSL_FAIL("Empty range not allowed");
189         //! and then?
190     }
191     else
192     {
193         const ScRangeList& rRanges = GetRangeList();
194         OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
195         ScRange aNewRange( rRanges[ 0 ] );
196 
197         aNewRange.PutInOrder();    //! really?
198 
199         const auto & rDoc = GetDocShell()->GetDocument();
200         tools::Long nEndX = aNewRange.aStart.Col() + nColumns - 1;
201         tools::Long nEndY = aNewRange.aStart.Row() + nRows - 1;
202         if ( nEndX < 0 )      nEndX = 0;
203         if ( nEndX > rDoc.MaxCol() ) nEndX = rDoc.MaxCol();
204         if ( nEndY < 0 )      nEndY = 0;
205         if ( nEndY > rDoc.MaxRow() ) nEndY = rDoc.MaxRow();
206         //! error/exception or so, if too big/small
207 
208         aNewRange.aEnd.SetCol(static_cast<SCCOL>(nEndX));
209         aNewRange.aEnd.SetRow(static_cast<SCROW>(nEndY));
210 
211         aNewRange.PutInOrder();    //! really?
212 
213         SetNewRange( aNewRange );
214     }
215 }
216 
217 // XUsedAreaCursor
218 
gotoStartOfUsedArea(sal_Bool bExpand)219 void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea(sal_Bool bExpand)
220 {
221     SolarMutexGuard aGuard;
222     ScDocShell* pDocSh = GetDocShell();
223     if ( !pDocSh )
224         return;
225 
226     const ScRangeList& rRanges = GetRangeList();
227     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
228     ScRange aNewRange( rRanges[0] );
229     SCTAB nTab = aNewRange.aStart.Tab();
230 
231     SCCOL nUsedX = 0;       // fetch the beginning
232     SCROW nUsedY = 0;
233     if (!pDocSh->GetDocument().GetDataStart( nTab, nUsedX, nUsedY ))
234     {
235         nUsedX = 0;
236         nUsedY = 0;
237     }
238 
239     aNewRange.aStart.SetCol( nUsedX );
240     aNewRange.aStart.SetRow( nUsedY );
241     if (!bExpand)
242         aNewRange.aEnd = aNewRange.aStart;
243     SetNewRange( aNewRange );
244 }
245 
gotoEndOfUsedArea(sal_Bool bExpand)246 void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand )
247 {
248     SolarMutexGuard aGuard;
249     ScDocShell* pDocSh = GetDocShell();
250     if ( !pDocSh )
251         return;
252 
253     const ScRangeList& rRanges = GetRangeList();
254     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
255     ScRange aNewRange( rRanges[ 0 ]);
256     SCTAB nTab = aNewRange.aStart.Tab();
257 
258     SCCOL nUsedX = 0;       // fetch the end
259     SCROW nUsedY = 0;
260     if (!pDocSh->GetDocument().GetTableArea( nTab, nUsedX, nUsedY, true ))
261     {
262         nUsedX = 0;
263         nUsedY = 0;
264     }
265 
266     aNewRange.aEnd.SetCol( nUsedX );
267     aNewRange.aEnd.SetRow( nUsedY );
268     if (!bExpand)
269         aNewRange.aStart = aNewRange.aEnd;
270     SetNewRange( aNewRange );
271 }
272 
273 // XCellCursor
274 
gotoStart()275 void SAL_CALL ScCellCursorObj::gotoStart()
276 {
277     //  this is similar to collapseToCurrentRegion
278     //! something like gotoEdge with 4 possible directions is needed
279 
280     SolarMutexGuard aGuard;
281     const ScRangeList& rRanges = GetRangeList();
282     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
283     ScRange aOneRange( rRanges[ 0 ]);
284 
285     aOneRange.PutInOrder();
286     ScDocShell* pDocSh = GetDocShell();
287     if ( !pDocSh )
288         return;
289 
290     SCCOL nStartCol = aOneRange.aStart.Col();
291     SCROW nStartRow = aOneRange.aStart.Row();
292     SCCOL nEndCol = aOneRange.aEnd.Col();
293     SCROW nEndRow = aOneRange.aEnd.Row();
294     SCTAB nTab = aOneRange.aStart.Tab();
295 
296     pDocSh->GetDocument().GetDataArea(
297                     nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
298 
299     ScRange aNew( nStartCol, nStartRow, nTab );
300     SetNewRange( aNew );
301 }
302 
gotoEnd()303 void SAL_CALL ScCellCursorObj::gotoEnd()
304 {
305     //  this is similar to collapseToCurrentRegion
306     //! something like gotoEdge with 4 possible directions is needed
307 
308     SolarMutexGuard aGuard;
309     const ScRangeList& rRanges = GetRangeList();
310     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
311     ScRange aOneRange( rRanges[ 0 ] );
312 
313     aOneRange.PutInOrder();
314     ScDocShell* pDocSh = GetDocShell();
315     if ( !pDocSh )
316         return;
317 
318     SCCOL nStartCol = aOneRange.aStart.Col();
319     SCROW nStartRow = aOneRange.aStart.Row();
320     SCCOL nEndCol = aOneRange.aEnd.Col();
321     SCROW nEndRow = aOneRange.aEnd.Row();
322     SCTAB nTab = aOneRange.aStart.Tab();
323 
324     pDocSh->GetDocument().GetDataArea(
325                     nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
326 
327     ScRange aNew( nEndCol, nEndRow, nTab );
328     SetNewRange( aNew );
329 }
330 
gotoNext()331 void SAL_CALL ScCellCursorObj::gotoNext()
332 {
333     SolarMutexGuard aGuard;
334     const ScRangeList& rRanges = GetRangeList();
335     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
336     ScRange aOneRange( rRanges[ 0 ] );
337 
338     aOneRange.PutInOrder();
339     ScAddress aCursor(aOneRange.aStart);        //  always use start of block
340 
341     ScMarkData aMark(GetDocument()->GetSheetLimits());   // not used with bMarked=FALSE
342     SCCOL nNewX = aCursor.Col();
343     SCROW nNewY = aCursor.Row();
344     SCTAB nTab  = aCursor.Tab();
345     ScDocShell* pDocSh = GetDocShell();
346     if ( pDocSh )
347         pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab,  1,0, false,true, aMark );
348     //! otherwise exception or so
349 
350     SetNewRange( ScRange( nNewX, nNewY, nTab ) );
351 }
352 
gotoPrevious()353 void SAL_CALL ScCellCursorObj::gotoPrevious()
354 {
355     SolarMutexGuard aGuard;
356     const ScRangeList& rRanges = GetRangeList();
357     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
358     ScRange aOneRange( rRanges[ 0 ] );
359 
360     aOneRange.PutInOrder();
361     ScAddress aCursor(aOneRange.aStart);        //  always use start of block
362 
363     ScMarkData aMark(GetDocument()->GetSheetLimits());   // not used with bMarked=FALSE
364     SCCOL nNewX = aCursor.Col();
365     SCROW nNewY = aCursor.Row();
366     SCTAB nTab  = aCursor.Tab();
367     ScDocShell* pDocSh = GetDocShell();
368     if ( pDocSh )
369         pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab, -1,0, false,true, aMark );
370     //! otherwise exception or so
371 
372     SetNewRange( ScRange( nNewX, nNewY, nTab ) );
373 }
374 
gotoOffset(sal_Int32 nColumnOffset,sal_Int32 nRowOffset)375 void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset )
376 {
377     SolarMutexGuard aGuard;
378     const ScRangeList& rRanges = GetRangeList();
379     OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
380     ScRange aOneRange( rRanges[ 0 ] );
381     aOneRange.PutInOrder();
382 
383     const auto & rDoc = GetDocShell()->GetDocument();
384     if ( aOneRange.aStart.Col() + nColumnOffset >= 0 &&
385          aOneRange.aEnd.Col()   + nColumnOffset <= rDoc.MaxCol() &&
386          aOneRange.aStart.Row() + nRowOffset    >= 0 &&
387          aOneRange.aEnd.Row()   + nRowOffset    <= rDoc.MaxRow() )
388     {
389         ScRange aNew( static_cast<SCCOL>(aOneRange.aStart.Col() + nColumnOffset),
390                       static_cast<SCROW>(aOneRange.aStart.Row() + nRowOffset),
391                       aOneRange.aStart.Tab(),
392                       static_cast<SCCOL>(aOneRange.aEnd.Col() + nColumnOffset),
393                       static_cast<SCROW>(aOneRange.aEnd.Row() + nRowOffset),
394                       aOneRange.aEnd.Tab() );
395         SetNewRange( aNew );
396     }
397 }
398 
399 // XSheetCellRange
400 
getSpreadsheet()401 uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet()
402 {
403     SolarMutexGuard aGuard;
404     return ScCellRangeObj::getSpreadsheet();
405 }
406 
407 // XCellRange
408 
getCellByPosition(sal_Int32 nColumn,sal_Int32 nRow)409 uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition(
410                                         sal_Int32 nColumn, sal_Int32 nRow )
411 {
412     SolarMutexGuard aGuard;
413     return ScCellRangeObj::getCellByPosition(nColumn,nRow);
414 }
415 
getCellRangeByPosition(sal_Int32 nLeft,sal_Int32 nTop,sal_Int32 nRight,sal_Int32 nBottom)416 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition(
417                 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
418 {
419     SolarMutexGuard aGuard;
420     return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
421 }
422 
getCellRangeByName(const OUString & rRange)423 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName(
424                         const OUString& rRange )
425 {
426     SolarMutexGuard aGuard;
427     return ScCellRangeObj::getCellRangeByName(rRange);
428 }
429 
430 // XServiceInfo
431 
getImplementationName()432 OUString SAL_CALL ScCellCursorObj::getImplementationName()
433 {
434     return "ScCellCursorObj";
435 }
436 
supportsService(const OUString & rServiceName)437 sal_Bool SAL_CALL ScCellCursorObj::supportsService( const OUString& rServiceName )
438 {
439     return cppu::supportsService(this, rServiceName);
440 }
441 
getSupportedServiceNames()442 uno::Sequence<OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames()
443 {
444     //  SheetCellCursor should be first (?)
445     return comphelper::concatSequences<OUString>(
446         { SCSHEETCELLCURSOR_SERVICE, SCCELLCURSOR_SERVICE },
447         ScCellRangeObj::getSupportedServiceNames());
448 }
449 
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
451