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 .
20 #include <formula/token.hxx>
21 #include <svx/svdocapt.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/dispatch.hxx>
24 #include <sfx2/lokhelper.hxx>
25 #include <svl/stritem.hxx>
26 #include <svl/numformat.hxx>
27 #include <svl/zforlist.hxx>
28 #include <svl/zformat.hxx>
29 #include <vcl/uitest/logger.hxx>
30 #include <vcl/uitest/eventdescription.hxx>
31 #include <vcl/keycod.hxx>
32 #include <vcl/keycodes.hxx>
33 #include <editeng/editview.hxx>
34 #include <rtl/math.hxx>
35 #include <sal/log.hxx>
37 #include <viewfunc.hxx>
38 #include <viewdata.hxx>
39 #include <drwlayer.hxx>
42 #include <docfunc.hxx>
44 #include <reftokenhelper.hxx>
45 #include <externalrefmgr.hxx>
46 #include <markdata.hxx>
47 #include <drawview.hxx>
48 #include <inputhdl.hxx>
49 #include <tabvwsh.hxx>
52 #include <comphelper/scopeguard.hxx>
59 void collectUIInformation( const OUString
& aevent
)
61 EventDescription aDescription
;
62 aDescription
.aID
= "grid_window";
63 aDescription
.aParameters
= {{ aevent
, ""}};
64 aDescription
.aAction
= "COMMENT";
65 aDescription
.aParent
= "MainWindow";
66 aDescription
.aKeyWord
= "ScGridWinUIObject";
67 UITestLogger::getInstance().logEvent(aDescription
);
74 void ScViewFunc::DetectiveAddPred()
76 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
77 pDocSh
->GetDocFunc().DetectiveAddPred( GetViewData().GetCurPos() );
78 RecalcPPT(); //! use broadcast in DocFunc instead?
81 void ScViewFunc::DetectiveDelPred()
83 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
84 pDocSh
->GetDocFunc().DetectiveDelPred( GetViewData().GetCurPos() );
88 void ScViewFunc::DetectiveAddSucc()
90 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
91 pDocSh
->GetDocFunc().DetectiveAddSucc( GetViewData().GetCurPos() );
95 void ScViewFunc::DetectiveDelSucc()
97 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
98 pDocSh
->GetDocFunc().DetectiveDelSucc( GetViewData().GetCurPos() );
102 void ScViewFunc::DetectiveAddError()
104 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
105 pDocSh
->GetDocFunc().DetectiveAddError( GetViewData().GetCurPos() );
109 void ScViewFunc::DetectiveDelAll()
111 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
112 pDocSh
->GetDocFunc().DetectiveDelAll( GetViewData().GetTabNo() );
116 void ScViewFunc::DetectiveMarkInvalid()
118 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
119 pDocSh
->GetDocFunc().DetectiveMarkInvalid( GetViewData().GetTabNo() );
123 void ScViewFunc::DetectiveRefresh()
125 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
126 pDocSh
->GetDocFunc().DetectiveRefresh();
130 static void lcl_jumpToRange(const ScRange
& rRange
, ScViewData
* pView
, const ScDocument
& rDoc
)
132 OUString
aAddrText(rRange
.Format(rDoc
, ScRefFlags::RANGE_ABS_3D
));
133 SfxStringItem
aPosItem(SID_CURRENTCELL
, aAddrText
);
134 SfxBoolItem
aUnmarkItem(FN_PARAM_1
, true); // remove existing selection
135 pView
->GetDispatcher().ExecuteList(
136 SID_CURRENTCELL
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
,
137 { &aPosItem
, &aUnmarkItem
});
140 void ScViewFunc::MarkAndJumpToRanges(const ScRangeList
& rRanges
)
142 ScViewData
& rView
= GetViewData();
143 ScDocShell
* pDocSh
= rView
.GetDocShell();
145 ScRangeList aRangesToMark
;
146 ScAddress aCurPos
= rView
.GetCurPos();
147 size_t ListSize
= rRanges
.size();
148 for ( size_t i
= 0; i
< ListSize
; ++i
)
150 const ScRange
& r
= rRanges
[i
];
151 // Collect only those ranges that are on the same sheet as the current
153 if (r
.aStart
.Tab() == aCurPos
.Tab())
154 aRangesToMark
.push_back(r
);
157 if (aRangesToMark
.empty())
160 // Jump to the first range of all precedent ranges.
161 const ScRange
& r
= aRangesToMark
.front();
162 lcl_jumpToRange(r
, &rView
, pDocSh
->GetDocument());
164 ListSize
= aRangesToMark
.size();
165 for ( size_t i
= 0; i
< ListSize
; ++i
)
167 MarkRange(aRangesToMark
[i
], false, true);
171 void ScViewFunc::DetectiveMarkPred()
173 ScViewData
& rView
= GetViewData();
174 ScDocShell
* pDocSh
= rView
.GetDocShell();
175 ScDocument
& rDoc
= pDocSh
->GetDocument();
176 ScMarkData
& rMarkData
= rView
.GetMarkData();
177 ScAddress aCurPos
= rView
.GetCurPos();
179 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
180 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
182 aRanges
.push_back(ScRange(aCurPos
));
184 vector
<ScTokenRef
> aRefTokens
;
185 pDocSh
->GetDocFunc().DetectiveCollectAllPreds(aRanges
, aRefTokens
);
187 if (aRefTokens
.empty())
188 // No precedents found. Nothing to do.
191 ScTokenRef p
= aRefTokens
.front();
192 if (ScRefTokenHelper::isExternalRef(p
))
194 // This is external. Open the external document if available, and
195 // jump to the destination.
197 sal_uInt16 nFileId
= p
->GetIndex();
198 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
199 const OUString
* pPath
= pRefMgr
->getExternalFileName(nFileId
);
202 if (pPath
&& ScRefTokenHelper::getRangeFromToken(&rDoc
, aRange
, p
, aCurPos
, true))
204 OUString aTabName
= p
->GetString().getString();
205 OUString
aRangeStr(aRange
.Format(rDoc
, ScRefFlags::VALID
));
213 ScGlobal::OpenURL(sUrl
, OUString());
220 ScRefTokenHelper::getRangeFromToken(&rDoc
, aRange
, p
, aCurPos
);
221 if (aRange
.aStart
.Tab() != aCurPos
.Tab())
223 // The first precedent range is on a different sheet. Jump to it
224 // immediately and forget the rest.
225 lcl_jumpToRange(aRange
, &rView
, rDoc
);
230 ScRangeList aDestRanges
;
231 ScRefTokenHelper::getRangeListFromTokens(&rDoc
, aDestRanges
, aRefTokens
, aCurPos
);
232 MarkAndJumpToRanges(aDestRanges
);
235 void ScViewFunc::DetectiveMarkSucc()
237 ScViewData
& rView
= GetViewData();
238 ScDocShell
* pDocSh
= rView
.GetDocShell();
239 ScMarkData
& rMarkData
= rView
.GetMarkData();
240 ScAddress aCurPos
= rView
.GetCurPos();
242 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
243 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
245 aRanges
.push_back(ScRange(aCurPos
));
247 vector
<ScTokenRef
> aRefTokens
;
248 pDocSh
->GetDocFunc().DetectiveCollectAllSuccs(aRanges
, aRefTokens
);
250 if (aRefTokens
.empty())
251 // No dependents found. Nothing to do.
254 ScRangeList aDestRanges
;
255 ScRefTokenHelper::getRangeListFromTokens(&rView
.GetDocument(), aDestRanges
, aRefTokens
, aCurPos
);
256 MarkAndJumpToRanges(aDestRanges
);
259 /** Insert date or time into current cell.
261 If cell is in input or edit mode, insert date/time at cursor position, else
262 create a date or time or date+time cell as follows:
264 - key date on time cell => current date + time of cell => date+time formatted cell
265 - unless time cell was empty or 00:00 time => current date => date formatted cell
266 - key date on date+time cell => current date + 00:00 time => date+time formatted cell
267 - unless date was current date => current date => date formatted cell
268 - key date on other cell => current date => date formatted cell
269 - key time on date cell => date of cell + current time => date+time formatted cell
270 - unless date cell was empty => current time => time formatted cell
271 - key time on date+time cell => current time => time formatted cell
272 - unless cell was empty => current date+time => date+time formatted cell
273 - key time on other cell => current time => time formatted cell
275 void ScViewFunc::InsertCurrentTime(SvNumFormatType nReqFmt
, const OUString
& rUndoStr
)
277 ScViewData
& rViewData
= GetViewData();
279 ScInputHandler
* pInputHdl
= ScModule::get()->GetInputHdl(rViewData
.GetViewShell());
280 bool bInputMode
= (pInputHdl
&& pInputHdl
->IsInputMode());
282 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
283 ScDocument
& rDoc
= pDocSh
->GetDocument();
284 ScAddress aCurPos
= rViewData
.GetCurPos();
285 const sal_uInt32 nCurNumFormat
= rDoc
.GetNumberFormat(ScRange(aCurPos
));
286 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
287 const SvNumberformat
* pCurNumFormatEntry
= pFormatter
->GetEntry(nCurNumFormat
);
288 const SvNumFormatType nCurNumFormatType
= (pCurNumFormatEntry
?
289 pCurNumFormatEntry
->GetMaskedType() : SvNumFormatType::UNDEFINED
);
291 const int nView(comphelper::LibreOfficeKit::isActive() ? SfxLokHelper::getView() : -1);
294 const auto [isTimezoneSet
, aTimezone
] = SfxLokHelper::getViewTimezone(nView
);
295 comphelper::LibreOfficeKit::setTimezone(isTimezoneSet
, aTimezone
);
298 comphelper::ScopeGuard
aAutoUserTimezone(
303 const auto [isTimezoneSet
, aTimezone
] = SfxLokHelper::getDefaultTimezone();
304 comphelper::LibreOfficeKit::setTimezone(isTimezoneSet
, aTimezone
);
311 sal_uInt32 nFormat
= 0;
314 case SvNumFormatType::DATE
:
316 Date
aActDate( Date::SYSTEM
);
317 fVal
= aActDate
- pFormatter
->GetNullDate();
318 if (nCurNumFormatType
== SvNumFormatType::DATE
)
319 nFormat
= nCurNumFormat
;
322 case SvNumFormatType::TIME
:
324 tools::Time
aActTime( tools::Time::SYSTEM
);
325 fVal
= aActTime
.GetTimeInDays();
326 if (nCurNumFormatType
== SvNumFormatType::TIME
)
327 nFormat
= nCurNumFormat
;
331 SAL_WARN("sc.ui","unhandled current date/time request");
332 nReqFmt
= SvNumFormatType::DATETIME
;
334 case SvNumFormatType::DATETIME
:
336 DateTime
aActDateTime( DateTime::SYSTEM
);
337 fVal
= DateTime::Sub( aActDateTime
, DateTime( pFormatter
->GetNullDate()));
338 if (nCurNumFormatType
== SvNumFormatType::DATETIME
)
339 nFormat
= nCurNumFormat
;
346 const LanguageType nLang
= (pCurNumFormatEntry
? pCurNumFormatEntry
->GetLanguage() : ScGlobal::eLnge
);
347 nFormat
= pFormatter
->GetStandardFormat( nReqFmt
, nLang
);
348 // This would return a more precise format with seconds and 100th
349 // seconds for a time request.
350 //nFormat = pFormatter->GetStandardFormat( fVal, nFormat, nReqFmt, nLang);
354 pFormatter
->GetOutputString( fVal
, nFormat
, aString
, &pColor
);
356 pInputHdl
->DataChanging();
357 EditView
* pTopView
= pInputHdl
->GetTopView();
359 pTopView
->InsertText( aString
);
360 EditView
* pTableView
= pInputHdl
->GetTableView();
362 pTableView
->InsertText( aString
);
363 pInputHdl
->DataChanged();
367 // Clear "Enter pastes" mode.
368 rViewData
.SetPasteMode( ScPasteFlags::NONE
);
369 // Clear CopySourceOverlay in each window of a split/frozen tabview.
370 rViewData
.GetViewShell()->UpdateCopySourceOverlay();
372 bool bForceReqFmt
= false;
373 const double fCell
= rDoc
.GetValue( aCurPos
);
374 // Combine requested date/time stamp with existing cell time/date, if any.
377 case SvNumFormatType::DATE
:
378 switch (nCurNumFormatType
)
380 case SvNumFormatType::TIME
:
381 // An empty cell formatted as time (or 00:00 time) shall
382 // not result in the current date with 00:00 time, but only
385 nReqFmt
= SvNumFormatType::DATETIME
;
387 case SvNumFormatType::DATETIME
:
389 // Force to only date if the existing date+time is the
390 // current date. This way inserting current date twice
391 // on an existing date+time cell can be used to force
392 // date, which otherwise would only be possible by
393 // applying a date format.
394 double fDate
= rtl::math::approxFloor( fCell
);
395 if (fDate
== (Date( Date::SYSTEM
) - pFormatter
->GetNullDate()))
402 case SvNumFormatType::TIME
:
403 switch (nCurNumFormatType
)
405 case SvNumFormatType::DATE
:
406 // An empty cell formatted as date shall not result in the
407 // null date and current time, but only in current time.
409 nReqFmt
= SvNumFormatType::DATETIME
;
411 case SvNumFormatType::DATETIME
:
412 // Requesting current time on an empty date+time cell
413 // inserts both current date+time.
415 nReqFmt
= SvNumFormatType::DATETIME
;
418 // Add current time to an existing date+time where time is
419 // zero and date is current date, else force time only.
420 double fDate
= rtl::math::approxFloor( fCell
);
421 double fTime
= fCell
- fDate
;
422 if (fTime
== 0.0 && fDate
== (Date( Date::SYSTEM
) - pFormatter
->GetNullDate()))
423 nReqFmt
= SvNumFormatType::DATETIME
;
432 SAL_WARN("sc.ui","unhandled current date/time request");
433 nReqFmt
= SvNumFormatType::DATETIME
;
435 case SvNumFormatType::DATETIME
:
441 case SvNumFormatType::DATE
:
443 Date
aActDate( Date::SYSTEM
);
444 fVal
= aActDate
- pFormatter
->GetNullDate();
447 case SvNumFormatType::TIME
:
449 tools::Time
aActTime( tools::Time::SYSTEM
);
450 fVal
= aActTime
.GetTimeInDays();
453 case SvNumFormatType::DATETIME
:
454 switch (nCurNumFormatType
)
456 case SvNumFormatType::DATE
:
458 double fDate
= rtl::math::approxFloor( fCell
);
459 tools::Time
aActTime( tools::Time::SYSTEM
);
460 fVal
= fDate
+ aActTime
.GetTimeInDays();
463 case SvNumFormatType::TIME
:
465 double fTime
= fCell
- rtl::math::approxFloor( fCell
);
466 Date
aActDate( Date::SYSTEM
);
467 fVal
= (aActDate
- pFormatter
->GetNullDate()) + fTime
;
472 DateTime
aActDateTime( DateTime::SYSTEM
);
473 fVal
= DateTime::Sub( aActDateTime
, DateTime( pFormatter
->GetNullDate()));
481 SfxUndoManager
* pUndoMgr
= pDocSh
->GetUndoManager();
482 pUndoMgr
->EnterListAction(rUndoStr
, rUndoStr
, 0, rViewData
.GetViewShell()->GetViewShellId());
484 pDocSh
->GetDocFunc().SetValueCell(aCurPos
, fVal
, true);
486 // Set the new cell format only when it differs from the current cell
487 // format type. Preserve a date+time format unless we force a format
489 if (bForceReqFmt
|| (nReqFmt
!= nCurNumFormatType
&& nCurNumFormatType
!= SvNumFormatType::DATETIME
))
490 SetNumberFormat(nReqFmt
);
492 rViewData
.UpdateInputHandler(); // update input bar with new value
494 pUndoMgr
->LeaveListAction();
498 void ScViewFunc::ShowNote( bool bShow
)
502 const ScViewData
& rViewData
= GetViewData();
503 ScAddress
aPos( rViewData
.GetCurX(), rViewData
.GetCurY(), rViewData
.GetTabNo() );
504 // show note moved to ScDocFunc, to be able to use it in notesuno.cxx
505 rViewData
.GetDocShell()->GetDocFunc().ShowNote( aPos
, bShow
);
508 void ScViewFunc::EditNote()
510 // HACK: If another text object is selected, make sure it gets unselected
511 if (FuText
* pOldFuText
= dynamic_cast<FuText
*>(GetDrawFuncPtr()))
512 pOldFuText
->KeyInput(KeyEvent(0, vcl::KeyCode(KEY_ESCAPE
)));
514 // for editing display and activate
516 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
517 ScDocument
& rDoc
= pDocSh
->GetDocument();
518 SCCOL nCol
= GetViewData().GetCurX();
519 SCROW nRow
= GetViewData().GetCurY();
520 SCTAB nTab
= GetViewData().GetTabNo();
521 ScAddress
aPos( nCol
, nRow
, nTab
);
523 // start drawing undo to catch undo action for insertion of the caption object
524 pDocSh
->MakeDrawLayer();
525 ScDrawLayer
* pDrawLayer
= rDoc
.GetDrawLayer();
526 pDrawLayer
->BeginCalcUndo(true);
527 // generated undo action is processed in FuText::StopEditMode
529 // get existing note or create a new note (including caption drawing object)
530 ScPostIt
* pNote
= rDoc
.GetOrCreateNote( aPos
);
534 // hide temporary note caption
536 // show caption object without changing internal visibility state
537 pNote
->ShowCaptionTemp( aPos
);
539 /* Drawing object has been created in ScDocument::GetOrCreateNote() or
540 in ScPostIt::ShowCaptionTemp(), so ScPostIt::GetCaption() should
541 return a caption object. */
542 SdrCaptionObj
* pCaption
= pNote
->GetCaption();
546 if ( ScDrawView
* pScDrawView
= GetScDrawView() )
547 pScDrawView
->SyncForGrid( pCaption
);
549 // activate object (as in FuSelection::TestComment)
550 GetViewData().GetDispatcher().Execute( SID_DRAW_NOTEEDIT
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
551 // now get the created FuText and set into EditMode
552 FuText
* pFuText
= dynamic_cast<FuText
*>(GetDrawFuncPtr());
555 ScrollToObject( pCaption
); // make object fully visible
556 pFuText
->SetInEditMode( pCaption
);
558 ScTabView::OnLOKNoteStateChanged( pNote
);
560 collectUIInformation(u
"OPEN"_ustr
);
563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */