1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28
29 #include "scitems.hxx"
30 #include <svl/intitem.hxx>
31 #include <svl/zforlist.hxx>
32 #include <rtl/uuid.h>
33
34 #include "cursuno.hxx"
35 #include "cellsuno.hxx"
36 #include "docsh.hxx"
37 #include "hints.hxx"
38 #include "markdata.hxx"
39 #include "dociter.hxx"
40 #include "unoguard.hxx"
41 #include "miscuno.hxx"
42
43 using namespace com::sun::star;
44
45 //------------------------------------------------------------------------
46
47 #define SCSHEETCELLCURSOR_SERVICE "com.sun.star.sheet.SheetCellCursor"
48 #define SCCELLCURSOR_SERVICE "com.sun.star.table.CellCursor"
49
50 //------------------------------------------------------------------------
51
ScCellCursorObj(ScDocShell * pDocSh,const ScRange & rR)52 ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) :
53 ScCellRangeObj( pDocSh, rR )
54 {
55 }
56
~ScCellCursorObj()57 ScCellCursorObj::~ScCellCursorObj()
58 {
59 }
60
queryInterface(const uno::Type & rType)61 uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType )
62 {
63 SC_QUERYINTERFACE( sheet::XSheetCellCursor )
64 SC_QUERYINTERFACE( sheet::XUsedAreaCursor )
65 SC_QUERYINTERFACE( table::XCellCursor )
66
67 return ScCellRangeObj::queryInterface( rType );
68 }
69
acquire()70 void SAL_CALL ScCellCursorObj::acquire() throw()
71 {
72 ScCellRangeObj::acquire();
73 }
74
release()75 void SAL_CALL ScCellCursorObj::release() throw()
76 {
77 ScCellRangeObj::release();
78 }
79
getTypes()80 uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes()
81 {
82 static uno::Sequence<uno::Type> aTypes;
83 if ( aTypes.getLength() == 0 )
84 {
85 uno::Sequence<uno::Type> aParentTypes(ScCellRangeObj::getTypes());
86 long nParentLen = aParentTypes.getLength();
87 const uno::Type* pParentPtr = aParentTypes.getConstArray();
88
89 aTypes.realloc( nParentLen + 3 );
90 uno::Type* pPtr = aTypes.getArray();
91 pPtr[nParentLen + 0] = getCppuType((const uno::Reference<sheet::XSheetCellCursor>*)0);
92 pPtr[nParentLen + 1] = getCppuType((const uno::Reference<sheet::XUsedAreaCursor>*)0);
93 pPtr[nParentLen + 2] = getCppuType((const uno::Reference<table::XCellCursor>*)0);
94
95 for (long i=0; i<nParentLen; i++)
96 pPtr[i] = pParentPtr[i]; // parent types first
97 }
98 return aTypes;
99 }
100
getImplementationId()101 uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId()
102 {
103 static uno::Sequence< sal_Int8 > aId;
104 if( aId.getLength() == 0 )
105 {
106 aId.realloc( 16 );
107 rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True );
108 }
109 return aId;
110 }
111
112 // XSheetCellCursor
113
collapseToCurrentRegion()114 void SAL_CALL ScCellCursorObj::collapseToCurrentRegion()
115 {
116 ScUnoGuard aGuard;
117 const ScRangeList& rRanges = GetRangeList();
118 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
119 ScRange aOneRange(*rRanges.GetObject(0));
120
121 aOneRange.Justify();
122 ScDocShell* pDocSh = GetDocShell();
123 if ( pDocSh )
124 {
125 SCCOL nStartCol = aOneRange.aStart.Col();
126 SCROW nStartRow = aOneRange.aStart.Row();
127 SCCOL nEndCol = aOneRange.aEnd.Col();
128 SCROW nEndRow = aOneRange.aEnd.Row();
129 SCTAB nTab = aOneRange.aStart.Tab();
130
131 pDocSh->GetDocument()->GetDataArea(
132 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_True, false );
133
134 ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
135 SetNewRange( aNew );
136 }
137 }
138
collapseToCurrentArray()139 void SAL_CALL ScCellCursorObj::collapseToCurrentArray()
140 {
141 ScUnoGuard aGuard;
142 const ScRangeList& rRanges = GetRangeList();
143 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
144 ScRange aOneRange(*rRanges.GetObject(0));
145
146 aOneRange.Justify();
147 ScAddress aCursor(aOneRange.aStart); // use the start address of the range
148
149 ScDocShell* pDocSh = GetDocShell();
150 if ( pDocSh )
151 {
152 ScDocument* pDoc = pDocSh->GetDocument();
153 ScRange aMatrix;
154
155 // finding the matrix range is now in GetMatrixFormulaRange in the document
156 if ( pDoc->GetMatrixFormulaRange( aCursor, aMatrix ) )
157 {
158 SetNewRange( aMatrix );
159 }
160 }
161 // that's a Bug, that this assertion comes; the API Reference says, that
162 // if there is no Matrix, the Range is left unchanged; they says nothing
163 // about a exception
164 /*if (!bFound)
165 {
166 DBG_ERROR("keine Matrix");
167 //! Exception, oder was?
168 }*/
169 }
170
collapseToMergedArea()171 void SAL_CALL ScCellCursorObj::collapseToMergedArea()
172 {
173 ScUnoGuard aGuard;
174 ScDocShell* pDocSh = GetDocShell();
175 if ( pDocSh )
176 {
177 const ScRangeList& rRanges = GetRangeList();
178 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
179 ScRange aNewRange(*rRanges.GetObject(0));
180
181 ScDocument* pDoc = pDocSh->GetDocument();
182 pDoc->ExtendOverlapped( aNewRange );
183 pDoc->ExtendMerge( aNewRange ); // after ExtendOverlapped!
184
185 SetNewRange( aNewRange );
186 }
187 }
188
expandToEntireColumns()189 void SAL_CALL ScCellCursorObj::expandToEntireColumns()
190 {
191 ScUnoGuard aGuard;
192 const ScRangeList& rRanges = GetRangeList();
193 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
194 ScRange aNewRange(*rRanges.GetObject(0));
195
196 aNewRange.aStart.SetRow( 0 );
197 aNewRange.aEnd.SetRow( MAXROW );
198
199 SetNewRange( aNewRange );
200 }
201
expandToEntireRows()202 void SAL_CALL ScCellCursorObj::expandToEntireRows()
203 {
204 ScUnoGuard aGuard;
205 const ScRangeList& rRanges = GetRangeList();
206 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
207 ScRange aNewRange(*rRanges.GetObject(0));
208
209 aNewRange.aStart.SetCol( 0 );
210 aNewRange.aEnd.SetCol( MAXCOL );
211
212 SetNewRange( aNewRange );
213 }
214
collapseToSize(sal_Int32 nColumns,sal_Int32 nRows)215 void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows )
216 {
217 ScUnoGuard aGuard;
218 if ( nColumns <= 0 || nRows <= 0 )
219 {
220 DBG_ERROR("leerer Range geht nicht");
221 //! und dann?
222 }
223 else
224 {
225 const ScRangeList& rRanges = GetRangeList();
226 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
227 ScRange aNewRange(*rRanges.GetObject(0));
228
229 aNewRange.Justify(); //! wirklich?
230
231 long nEndX = aNewRange.aStart.Col() + nColumns - 1;
232 long nEndY = aNewRange.aStart.Row() + nRows - 1;
233 if ( nEndX < 0 ) nEndX = 0;
234 if ( nEndX > MAXCOL ) nEndX = MAXCOL;
235 if ( nEndY < 0 ) nEndY = 0;
236 if ( nEndY > MAXROW ) nEndY = MAXROW;
237 //! Fehler/Exception oder so, wenn zu gross/zu klein?
238
239 aNewRange.aEnd.SetCol((SCCOL)nEndX);
240 aNewRange.aEnd.SetRow((SCROW)nEndY);
241
242 aNewRange.Justify(); //! wirklich?
243
244 SetNewRange( aNewRange );
245 }
246 }
247
248 // XUsedAreaCursor
249
gotoStartOfUsedArea(sal_Bool bExpand)250 void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea( sal_Bool bExpand )
251 {
252 ScUnoGuard aGuard;
253 ScDocShell* pDocSh = GetDocShell();
254 if ( pDocSh )
255 {
256 const ScRangeList& rRanges = GetRangeList();
257 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
258 ScRange aNewRange(*rRanges.GetObject(0));
259 SCTAB nTab = aNewRange.aStart.Tab();
260
261 SCCOL nUsedX = 0; // Anfang holen
262 SCROW nUsedY = 0;
263 if (!pDocSh->GetDocument()->GetDataStart( nTab, nUsedX, nUsedY ))
264 {
265 nUsedX = 0;
266 nUsedY = 0;
267 }
268
269 aNewRange.aStart.SetCol( nUsedX );
270 aNewRange.aStart.SetRow( nUsedY );
271 if (!bExpand)
272 aNewRange.aEnd = aNewRange.aStart;
273 SetNewRange( aNewRange );
274 }
275 }
276
gotoEndOfUsedArea(sal_Bool bExpand)277 void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand )
278 {
279 ScUnoGuard aGuard;
280 ScDocShell* pDocSh = GetDocShell();
281 if ( pDocSh )
282 {
283 const ScRangeList& rRanges = GetRangeList();
284 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
285 ScRange aNewRange(*rRanges.GetObject(0));
286 SCTAB nTab = aNewRange.aStart.Tab();
287
288 SCCOL nUsedX = 0; // Ende holen
289 SCROW nUsedY = 0;
290 if (!pDocSh->GetDocument()->GetTableArea( nTab, nUsedX, nUsedY ))
291 {
292 nUsedX = 0;
293 nUsedY = 0;
294 }
295
296 aNewRange.aEnd.SetCol( nUsedX );
297 aNewRange.aEnd.SetRow( nUsedY );
298 if (!bExpand)
299 aNewRange.aStart = aNewRange.aEnd;
300 SetNewRange( aNewRange );
301 }
302 }
303
304 // XCellCursor
305
gotoStart()306 void SAL_CALL ScCellCursorObj::gotoStart()
307 {
308 // this is similar to collapseToCurrentRegion
309 //! something like gotoEdge with 4 possible directions is needed
310
311 ScUnoGuard aGuard;
312 const ScRangeList& rRanges = GetRangeList();
313 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
314 ScRange aOneRange(*rRanges.GetObject(0));
315
316 aOneRange.Justify();
317 ScDocShell* pDocSh = GetDocShell();
318 if ( pDocSh )
319 {
320 SCCOL nStartCol = aOneRange.aStart.Col();
321 SCROW nStartRow = aOneRange.aStart.Row();
322 SCCOL nEndCol = aOneRange.aEnd.Col();
323 SCROW nEndRow = aOneRange.aEnd.Row();
324 SCTAB nTab = aOneRange.aStart.Tab();
325
326 pDocSh->GetDocument()->GetDataArea(
327 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false );
328
329 ScRange aNew( nStartCol, nStartRow, nTab );
330 SetNewRange( aNew );
331 }
332 }
333
gotoEnd()334 void SAL_CALL ScCellCursorObj::gotoEnd()
335 {
336 // this is similar to collapseToCurrentRegion
337 //! something like gotoEdge with 4 possible directions is needed
338
339 ScUnoGuard aGuard;
340 const ScRangeList& rRanges = GetRangeList();
341 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
342 ScRange aOneRange(*rRanges.GetObject(0));
343
344 aOneRange.Justify();
345 ScDocShell* pDocSh = GetDocShell();
346 if ( pDocSh )
347 {
348 SCCOL nStartCol = aOneRange.aStart.Col();
349 SCROW nStartRow = aOneRange.aStart.Row();
350 SCCOL nEndCol = aOneRange.aEnd.Col();
351 SCROW nEndRow = aOneRange.aEnd.Row();
352 SCTAB nTab = aOneRange.aStart.Tab();
353
354 pDocSh->GetDocument()->GetDataArea(
355 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false );
356
357 ScRange aNew( nEndCol, nEndRow, nTab );
358 SetNewRange( aNew );
359 }
360 }
361
gotoNext()362 void SAL_CALL ScCellCursorObj::gotoNext()
363 {
364 ScUnoGuard aGuard;
365 const ScRangeList& rRanges = GetRangeList();
366 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
367 ScRange aOneRange(*rRanges.GetObject(0));
368
369 aOneRange.Justify();
370 ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen
371
372 ScMarkData aMark; // not used with bMarked=FALSE
373 SCCOL nNewX = aCursor.Col();
374 SCROW nNewY = aCursor.Row();
375 SCTAB nTab = aCursor.Tab();
376 ScDocShell* pDocSh = GetDocShell();
377 if ( pDocSh )
378 pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, 1,0, sal_False,sal_True, aMark );
379 //! sonst Exception oder so
380
381 SetNewRange( ScRange( nNewX, nNewY, nTab ) );
382 }
383
gotoPrevious()384 void SAL_CALL ScCellCursorObj::gotoPrevious()
385 {
386 ScUnoGuard aGuard;
387 const ScRangeList& rRanges = GetRangeList();
388 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
389 ScRange aOneRange(*rRanges.GetObject(0));
390
391 aOneRange.Justify();
392 ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen
393
394 ScMarkData aMark; // not used with bMarked=FALSE
395 SCCOL nNewX = aCursor.Col();
396 SCROW nNewY = aCursor.Row();
397 SCTAB nTab = aCursor.Tab();
398 ScDocShell* pDocSh = GetDocShell();
399 if ( pDocSh )
400 pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, -1,0, sal_False,sal_True, aMark );
401 //! sonst Exception oder so
402
403 SetNewRange( ScRange( nNewX, nNewY, nTab ) );
404 }
405
gotoOffset(sal_Int32 nColumnOffset,sal_Int32 nRowOffset)406 void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset )
407 {
408 ScUnoGuard aGuard;
409 const ScRangeList& rRanges = GetRangeList();
410 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" );
411 ScRange aOneRange(*rRanges.GetObject(0));
412 aOneRange.Justify();
413
414 if ( aOneRange.aStart.Col() + nColumnOffset >= 0 &&
415 aOneRange.aEnd.Col() + nColumnOffset <= MAXCOL &&
416 aOneRange.aStart.Row() + nRowOffset >= 0 &&
417 aOneRange.aEnd.Row() + nRowOffset <= MAXROW )
418 {
419 ScRange aNew( (SCCOL)(aOneRange.aStart.Col() + nColumnOffset),
420 (SCROW)(aOneRange.aStart.Row() + nRowOffset),
421 aOneRange.aStart.Tab(),
422 (SCCOL)(aOneRange.aEnd.Col() + nColumnOffset),
423 (SCROW)(aOneRange.aEnd.Row() + nRowOffset),
424 aOneRange.aEnd.Tab() );
425 SetNewRange( aNew );
426 }
427 }
428
429 // XSheetCellRange
430
getSpreadsheet()431 uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet()
432 {
433 ScUnoGuard aGuard;
434 return ScCellRangeObj::getSpreadsheet();
435 }
436
437 // XCellRange
438
getCellByPosition(sal_Int32 nColumn,sal_Int32 nRow)439 uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition(
440 sal_Int32 nColumn, sal_Int32 nRow )
441 {
442 ScUnoGuard aGuard;
443 return ScCellRangeObj::getCellByPosition(nColumn,nRow);
444 }
445
getCellRangeByPosition(sal_Int32 nLeft,sal_Int32 nTop,sal_Int32 nRight,sal_Int32 nBottom)446 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition(
447 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
448 {
449 ScUnoGuard aGuard;
450 return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
451 }
452
getCellRangeByName(const rtl::OUString & rRange)453 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName(
454 const rtl::OUString& rRange )
455 {
456 ScUnoGuard aGuard;
457 return ScCellRangeObj::getCellRangeByName(rRange);
458 }
459
460 // XServiceInfo
461
getImplementationName()462 rtl::OUString SAL_CALL ScCellCursorObj::getImplementationName()
463 {
464 return rtl::OUString::createFromAscii( "ScCellCursorObj" );
465 }
466
supportsService(const rtl::OUString & rServiceName)467 sal_Bool SAL_CALL ScCellCursorObj::supportsService( const rtl::OUString& rServiceName )
468 {
469 String aServiceStr( rServiceName );
470 return aServiceStr.EqualsAscii( SCSHEETCELLCURSOR_SERVICE ) ||
471 aServiceStr.EqualsAscii( SCCELLCURSOR_SERVICE ) ||
472 ScCellRangeObj::supportsService(rServiceName);
473 }
474
getSupportedServiceNames()475 uno::Sequence<rtl::OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames()
476 {
477 // get all service names from cell range
478 uno::Sequence<rtl::OUString> aParentSeq(ScCellRangeObj::getSupportedServiceNames());
479 sal_Int32 nParentLen = aParentSeq.getLength();
480 const rtl::OUString* pParentArr = aParentSeq.getConstArray();
481
482 // SheetCellCursor should be first (?)
483 uno::Sequence<rtl::OUString> aTotalSeq( nParentLen + 2 );
484 rtl::OUString* pTotalArr = aTotalSeq.getArray();
485 pTotalArr[0] = rtl::OUString::createFromAscii( SCSHEETCELLCURSOR_SERVICE );
486 pTotalArr[1] = rtl::OUString::createFromAscii( SCCELLCURSOR_SERVICE );
487
488 // append cell range services
489 for (long i=0; i<nParentLen; i++)
490 pTotalArr[i+2] = pParentArr[i];
491
492 return aTotalSeq;
493 }
494