1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <svx/svdundo.hxx>
22 #include <svx/svdocapt.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <sfx2/dispatch.hxx>
25 #include <vcl/msgbox.hxx>
26 #include <svl/zforlist.hxx>
27 #include <svl/zformat.hxx>
28 #include <editeng/editview.hxx>
30 #include "viewfunc.hxx"
31 #include "detfunc.hxx"
32 #include "detdata.hxx"
33 #include "viewdata.hxx"
34 #include "drwlayer.hxx"
36 #include "undocell.hxx"
38 #include "docfunc.hxx"
39 #include "globstr.hrc"
42 #include "reftokenhelper.hxx"
43 #include "externalrefmgr.hxx"
44 #include "formulacell.hxx"
45 #include "markdata.hxx"
46 #include "drawview.hxx"
47 #include "globalnames.hxx"
48 #include "inputhdl.hxx"
54 void ScViewFunc::DetectiveAddPred()
56 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
57 pDocSh
->GetDocFunc().DetectiveAddPred( GetViewData()->GetCurPos() );
58 RecalcPPT(); //! use broadcast in DocFunc instead?
61 void ScViewFunc::DetectiveDelPred()
63 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
64 pDocSh
->GetDocFunc().DetectiveDelPred( GetViewData()->GetCurPos() );
68 void ScViewFunc::DetectiveAddSucc()
70 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
71 pDocSh
->GetDocFunc().DetectiveAddSucc( GetViewData()->GetCurPos() );
75 void ScViewFunc::DetectiveDelSucc()
77 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
78 pDocSh
->GetDocFunc().DetectiveDelSucc( GetViewData()->GetCurPos() );
82 void ScViewFunc::DetectiveAddError()
84 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
85 pDocSh
->GetDocFunc().DetectiveAddError( GetViewData()->GetCurPos() );
89 void ScViewFunc::DetectiveDelAll()
91 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
92 pDocSh
->GetDocFunc().DetectiveDelAll( GetViewData()->GetTabNo() );
96 void ScViewFunc::DetectiveMarkInvalid()
98 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
99 pDocSh
->GetDocFunc().DetectiveMarkInvalid( GetViewData()->GetTabNo() );
103 void ScViewFunc::DetectiveRefresh()
105 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
106 pDocSh
->GetDocFunc().DetectiveRefresh();
110 static void lcl_jumpToRange(const ScRange
& rRange
, ScViewData
* pView
, ScDocument
* pDoc
)
112 OUString
aAddrText(rRange
.Format(SCR_ABS_3D
, pDoc
));
113 SfxStringItem
aPosItem(SID_CURRENTCELL
, aAddrText
);
114 SfxBoolItem
aUnmarkItem(FN_PARAM_1
, true); // remove existing selection
115 pView
->GetDispatcher().Execute(
116 SID_CURRENTCELL
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
,
117 &aPosItem
, &aUnmarkItem
, 0L);
120 void ScViewFunc::MarkAndJumpToRanges(const ScRangeList
& rRanges
)
122 ScViewData
* pView
= GetViewData();
123 ScDocShell
* pDocSh
= pView
->GetDocShell();
125 ScRangeList
aRanges(rRanges
);
126 ScRangeList aRangesToMark
;
127 ScAddress aCurPos
= pView
->GetCurPos();
128 size_t ListSize
= aRanges
.size();
129 for ( size_t i
= 0; i
< ListSize
; ++i
)
131 const ScRange
* p
= aRanges
[i
];
132 // Collect only those ranges that are on the same sheet as the current
134 if (p
->aStart
.Tab() == aCurPos
.Tab())
135 aRangesToMark
.Append(*p
);
138 if (aRangesToMark
.empty())
141 // Jump to the first range of all precedent ranges.
142 const ScRange
* p
= aRangesToMark
.front();
143 lcl_jumpToRange(*p
, pView
, pDocSh
->GetDocument());
145 ListSize
= aRangesToMark
.size();
146 for ( size_t i
= 0; i
< ListSize
; ++i
)
148 p
= aRangesToMark
[i
];
149 MarkRange(*p
, false, true);
153 void ScViewFunc::DetectiveMarkPred()
155 ScViewData
* pView
= GetViewData();
156 ScDocShell
* pDocSh
= pView
->GetDocShell();
157 ScDocument
* pDoc
= pDocSh
->GetDocument();
158 ScMarkData
& rMarkData
= pView
->GetMarkData();
159 ScAddress aCurPos
= pView
->GetCurPos();
161 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
162 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
164 aRanges
.Append(aCurPos
);
166 vector
<ScTokenRef
> aRefTokens
;
167 pDocSh
->GetDocFunc().DetectiveCollectAllPreds(aRanges
, aRefTokens
);
169 if (aRefTokens
.empty())
170 // No precedents found. Nothing to do.
173 ScTokenRef p
= aRefTokens
.front();
174 if (ScRefTokenHelper::isExternalRef(p
))
176 // This is external. Open the external document if available, and
177 // jump to the destination.
179 sal_uInt16 nFileId
= p
->GetIndex();
180 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
181 const OUString
* pPath
= pRefMgr
->getExternalFileName(nFileId
);
184 if (pPath
&& ScRefTokenHelper::getRangeFromToken(aRange
, p
, aCurPos
, true))
186 OUString aTabName
= p
->GetString().getString();
190 aBuf
.append(aTabName
);
193 OUString
aRangeStr(aRange
.Format(SCA_VALID
));
194 aBuf
.append(aRangeStr
);
196 ScGlobal::OpenURL(aBuf
.makeStringAndClear(), OUString());
203 ScRefTokenHelper::getRangeFromToken(aRange
, p
, aCurPos
, false);
204 if (aRange
.aStart
.Tab() != aCurPos
.Tab())
206 // The first precedent range is on a different sheet. Jump to it
207 // immediately and forget the rest.
208 lcl_jumpToRange(aRange
, pView
, pDoc
);
213 ScRangeList aDestRanges
;
214 ScRefTokenHelper::getRangeListFromTokens(aDestRanges
, aRefTokens
, aCurPos
);
215 MarkAndJumpToRanges(aDestRanges
);
218 void ScViewFunc::DetectiveMarkSucc()
220 ScViewData
* pView
= GetViewData();
221 ScDocShell
* pDocSh
= pView
->GetDocShell();
222 ScMarkData
& rMarkData
= pView
->GetMarkData();
223 ScAddress aCurPos
= pView
->GetCurPos();
225 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
226 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
228 aRanges
.Append(aCurPos
);
230 vector
<ScTokenRef
> aRefTokens
;
231 pDocSh
->GetDocFunc().DetectiveCollectAllSuccs(aRanges
, aRefTokens
);
233 if (aRefTokens
.empty())
234 // No dependents found. Nothing to do.
237 ScRangeList aDestRanges
;
238 ScRefTokenHelper::getRangeListFromTokens(aDestRanges
, aRefTokens
, aCurPos
);
239 MarkAndJumpToRanges(aDestRanges
);
242 /** Insert date or time into current cell.
244 If cell is in input or edit mode, insert date/time at cursor position, else
245 create a date or time or date+time cell as follows:
247 - key date on time cell => current date + time of cell => date+time formatted cell
248 - unless time cell was empty or 00:00 time => current date => date formatted cell
249 - key date on date+time cell => current date + 00:00 time => date+time formatted cell
250 - unless date was current date => current date => date formatted cell
251 - key date on other cell => current date => date formatted cell
252 - key time on date cell => date of cell + current time => date+time formatted cell
253 - unless date cell was empty => current time => time formatted cell
254 - key time on date+time cell => current time => time formatted cell
255 - unless cell was empty => current date+time => date+time formatted cell
256 - key time on other cell => current time => time formatted cell
258 void ScViewFunc::InsertCurrentTime(short nReqFmt
, const OUString
& rUndoStr
)
260 ScViewData
& rViewData
= *GetViewData();
262 ScInputHandler
* pInputHdl
= SC_MOD()->GetInputHdl( rViewData
.GetViewShell());
263 bool bInputMode
= (pInputHdl
&& pInputHdl
->IsInputMode());
265 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
266 ScDocument
& rDoc
= *pDocSh
->GetDocument();
267 ScAddress aCurPos
= rViewData
.GetCurPos();
268 const sal_uInt32 nCurNumFormat
= rDoc
.GetNumberFormat(aCurPos
);
269 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
270 const SvNumberformat
* pCurNumFormatEntry
= pFormatter
->GetEntry(nCurNumFormat
);
271 const short nCurNumFormatType
= (pCurNumFormatEntry
?
272 (pCurNumFormatEntry
->GetType() & ~NUMBERFORMAT_DEFINED
) : NUMBERFORMAT_UNDEFINED
);
277 sal_uInt32 nFormat
= 0;
280 case NUMBERFORMAT_DATE
:
282 Date
aActDate( Date::SYSTEM
);
283 fVal
= aActDate
- *pFormatter
->GetNullDate();
284 if (nCurNumFormatType
== NUMBERFORMAT_DATE
)
285 nFormat
= nCurNumFormat
;
288 case NUMBERFORMAT_TIME
:
290 Time
aActTime( Time::SYSTEM
);
291 fVal
= aActTime
.GetTimeInDays();
292 if (nCurNumFormatType
== NUMBERFORMAT_TIME
)
293 nFormat
= nCurNumFormat
;
297 assert(!"unhandled current date/time request");
298 nReqFmt
= NUMBERFORMAT_DATETIME
;
300 case NUMBERFORMAT_DATETIME
:
302 DateTime
aActDateTime( DateTime::SYSTEM
);
303 fVal
= aActDateTime
- DateTime( *pFormatter
->GetNullDate());
304 if (nCurNumFormatType
== NUMBERFORMAT_DATETIME
)
305 nFormat
= nCurNumFormat
;
312 const LanguageType nLang
= (pCurNumFormatEntry
? pCurNumFormatEntry
->GetLanguage() : ScGlobal::eLnge
);
313 nFormat
= pFormatter
->GetStandardFormat( nReqFmt
, nLang
);
314 // This would return a more precise format with seconds and 100th
315 // seconds for a time request.
316 //nFormat = pFormatter->GetStandardFormat( fVal, nFormat, nReqFmt, nLang);
320 pFormatter
->GetOutputString( fVal
, nFormat
, aString
, &pColor
);
322 pInputHdl
->DataChanging();
323 EditView
* pTopView
= pInputHdl
->GetTopView();
325 pTopView
->InsertText( aString
);
326 EditView
* pTableView
= pInputHdl
->GetTableView();
328 pTableView
->InsertText( aString
);
329 pInputHdl
->DataChanged( false, true);
333 bool bForceReqFmt
= false;
334 const double fCell
= rDoc
.GetValue( aCurPos
);
335 // Combine requested date/time stamp with existing cell time/date, if any.
338 case NUMBERFORMAT_DATE
:
339 switch (nCurNumFormatType
)
341 case NUMBERFORMAT_TIME
:
342 // An empty cell formatted as time (or 00:00 time) shall
343 // not result in the current date with 00:00 time, but only
346 nReqFmt
= NUMBERFORMAT_DATETIME
;
348 case NUMBERFORMAT_DATETIME
:
350 // Force to only date if the existing date+time is the
351 // current date. This way inserting current date twice
352 // on an existing date+time cell can be used to force
353 // date, which otherwise would only be possible by
354 // applying a date format.
355 double fDate
= rtl::math::approxFloor( fCell
);
356 if (fDate
== (Date( Date::SYSTEM
) - *pFormatter
->GetNullDate()))
362 case NUMBERFORMAT_TIME
:
363 switch (nCurNumFormatType
)
365 case NUMBERFORMAT_DATE
:
366 // An empty cell formatted as date shall not result in the
367 // null date and current time, but only in current time.
369 nReqFmt
= NUMBERFORMAT_DATETIME
;
371 case NUMBERFORMAT_DATETIME
:
372 // Requesting current time on an empty date+time cell
373 // inserts both current date+time.
375 nReqFmt
= NUMBERFORMAT_DATETIME
;
378 // Add current time to an existing date+time where time is
379 // zero and date is current date, else force time only.
380 double fDate
= rtl::math::approxFloor( fCell
);
381 double fTime
= fCell
- fDate
;
382 if (fTime
== 0.0 && fDate
== (Date( Date::SYSTEM
) - *pFormatter
->GetNullDate()))
383 nReqFmt
= NUMBERFORMAT_DATETIME
;
391 assert(!"unhandled current date/time request");
392 nReqFmt
= NUMBERFORMAT_DATETIME
;
394 case NUMBERFORMAT_DATETIME
:
400 case NUMBERFORMAT_DATE
:
402 Date
aActDate( Date::SYSTEM
);
403 fVal
= aActDate
- *pFormatter
->GetNullDate();
406 case NUMBERFORMAT_TIME
:
408 Time
aActTime( Time::SYSTEM
);
409 fVal
= aActTime
.GetTimeInDays();
412 case NUMBERFORMAT_DATETIME
:
413 switch (nCurNumFormatType
)
415 case NUMBERFORMAT_DATE
:
417 double fDate
= rtl::math::approxFloor( fCell
);
418 Time
aActTime( Time::SYSTEM
);
419 fVal
= fDate
+ aActTime
.GetTimeInDays();
422 case NUMBERFORMAT_TIME
:
424 double fTime
= fCell
- rtl::math::approxFloor( fCell
);
425 Date
aActDate( Date::SYSTEM
);
426 fVal
= (aActDate
- *pFormatter
->GetNullDate()) + fTime
;
431 DateTime
aActDateTime( DateTime::SYSTEM
);
432 // Converting the null date to DateTime forces the
433 // correct operator-() to be used, resulting in a
434 // fractional date+time instead of only date value.
435 fVal
= aActDateTime
- DateTime( *pFormatter
->GetNullDate());
441 ::svl::IUndoManager
* pUndoMgr
= pDocSh
->GetUndoManager();
442 pUndoMgr
->EnterListAction(rUndoStr
, rUndoStr
);
444 pDocSh
->GetDocFunc().SetValueCell(aCurPos
, fVal
, true);
446 // Set the new cell format only when it differs from the current cell
447 // format type. Preserve a date+time format unless we force a format
449 if (bForceReqFmt
|| (nReqFmt
!= nCurNumFormatType
&& nCurNumFormatType
!= NUMBERFORMAT_DATETIME
))
450 SetNumberFormat(nReqFmt
);
452 rViewData
.UpdateInputHandler(); // update input bar with new value
454 pUndoMgr
->LeaveListAction();
458 void ScViewFunc::ShowNote( bool bShow
)
462 const ScViewData
& rViewData
= *GetViewData();
463 ScAddress
aPos( rViewData
.GetCurX(), rViewData
.GetCurY(), rViewData
.GetTabNo() );
464 // show note moved to ScDocFunc, to be able to use it in notesuno.cxx
465 rViewData
.GetDocShell()->GetDocFunc().ShowNote( aPos
, bShow
);
468 void ScViewFunc::EditNote()
470 // for editing display and activate
472 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
473 ScDocument
* pDoc
= pDocSh
->GetDocument();
474 SCCOL nCol
= GetViewData()->GetCurX();
475 SCROW nRow
= GetViewData()->GetCurY();
476 SCTAB nTab
= GetViewData()->GetTabNo();
477 ScAddress
aPos( nCol
, nRow
, nTab
);
479 // start drawing undo to catch undo action for insertion of the caption object
480 pDocSh
->MakeDrawLayer();
481 ScDrawLayer
* pDrawLayer
= pDoc
->GetDrawLayer();
482 pDrawLayer
->BeginCalcUndo(true);
483 // generated undo action is processed in FuText::StopEditMode
485 // get existing note or create a new note (including caption drawing object)
486 if( ScPostIt
* pNote
= pDoc
->GetOrCreateNote( aPos
) )
488 // hide temporary note caption
490 // show caption object without changing internal visibility state
491 pNote
->ShowCaptionTemp( aPos
);
493 /* Drawing object has been created in ScDocument::GetOrCreateNote() or
494 in ScPostIt::ShowCaptionTemp(), so ScPostIt::GetCaption() should
495 return a caption object. */
496 if( SdrCaptionObj
* pCaption
= pNote
->GetCaption() )
498 if ( ScDrawView
* pScDrawView
= GetScDrawView() )
499 pScDrawView
->SyncForGrid( pCaption
);
500 // #i33764# enable the resize handles before starting edit mode
501 if( FuPoor
* pDraw
= GetDrawFuncPtr() )
502 static_cast< FuSelection
* >( pDraw
)->ActivateNoteHandles( pCaption
);
504 // activate object (as in FuSelection::TestComment)
505 GetViewData()->GetDispatcher().Execute( SID_DRAW_NOTEEDIT
, SFX_CALLMODE_SYNCHRON
| SFX_CALLMODE_RECORD
);
506 // now get the created FuText and set into EditMode
507 FuPoor
* pPoor
= GetDrawFuncPtr();
508 if ( pPoor
&& (pPoor
->GetSlotID() == SID_DRAW_NOTEEDIT
) ) // has no RTTI
510 ScrollToObject( pCaption
); // make object fully visible
511 static_cast< FuText
* >( pPoor
)->SetInEditMode( pCaption
);
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */