tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / view / viewfun6.cxx
blob0c614b80aa8cf9e4f916aeae2caae1cbf1d803a4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
40 #include <docsh.hxx>
41 #include <futext.hxx>
42 #include <docfunc.hxx>
43 #include <sc.hrc>
44 #include <reftokenhelper.hxx>
45 #include <externalrefmgr.hxx>
46 #include <markdata.hxx>
47 #include <drawview.hxx>
48 #include <inputhdl.hxx>
49 #include <tabvwsh.hxx>
50 #include <scmod.hxx>
51 #include <postit.hxx>
52 #include <comphelper/scopeguard.hxx>
54 #include <vector>
56 namespace
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);
72 using ::std::vector;
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() );
85 RecalcPPT();
88 void ScViewFunc::DetectiveAddSucc()
90 ScDocShell* pDocSh = GetViewData().GetDocShell();
91 pDocSh->GetDocFunc().DetectiveAddSucc( GetViewData().GetCurPos() );
92 RecalcPPT();
95 void ScViewFunc::DetectiveDelSucc()
97 ScDocShell* pDocSh = GetViewData().GetDocShell();
98 pDocSh->GetDocFunc().DetectiveDelSucc( GetViewData().GetCurPos() );
99 RecalcPPT();
102 void ScViewFunc::DetectiveAddError()
104 ScDocShell* pDocSh = GetViewData().GetDocShell();
105 pDocSh->GetDocFunc().DetectiveAddError( GetViewData().GetCurPos() );
106 RecalcPPT();
109 void ScViewFunc::DetectiveDelAll()
111 ScDocShell* pDocSh = GetViewData().GetDocShell();
112 pDocSh->GetDocFunc().DetectiveDelAll( GetViewData().GetTabNo() );
113 RecalcPPT();
116 void ScViewFunc::DetectiveMarkInvalid()
118 ScDocShell* pDocSh = GetViewData().GetDocShell();
119 pDocSh->GetDocFunc().DetectiveMarkInvalid( GetViewData().GetTabNo() );
120 RecalcPPT();
123 void ScViewFunc::DetectiveRefresh()
125 ScDocShell* pDocSh = GetViewData().GetDocShell();
126 pDocSh->GetDocFunc().DetectiveRefresh();
127 RecalcPPT();
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
152 // cursor.
153 if (r.aStart.Tab() == aCurPos.Tab())
154 aRangesToMark.push_back(r);
157 if (aRangesToMark.empty())
158 return;
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();
178 ScRangeList aRanges;
179 if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
180 rMarkData.FillRangeListWithMarks(&aRanges, false);
181 else
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.
189 return;
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);
201 ScRange aRange;
202 if (pPath && ScRefTokenHelper::getRangeFromToken(&rDoc, aRange, p, aCurPos, true))
204 OUString aTabName = p->GetString().getString();
205 OUString aRangeStr(aRange.Format(rDoc, ScRefFlags::VALID));
206 OUString sUrl =
207 *pPath +
208 "#" +
209 aTabName +
210 "." +
211 aRangeStr;
213 ScGlobal::OpenURL(sUrl, OUString());
215 return;
217 else
219 ScRange aRange;
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);
226 return;
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();
241 ScRangeList aRanges;
242 if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
243 rMarkData.FillRangeListWithMarks(&aRanges, false);
244 else
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.
252 return;
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);
292 if (nView >= 0)
294 const auto [isTimezoneSet, aTimezone] = SfxLokHelper::getViewTimezone(nView);
295 comphelper::LibreOfficeKit::setTimezone(isTimezoneSet, aTimezone);
298 comphelper::ScopeGuard aAutoUserTimezone(
299 [nView]()
301 if (nView >= 0)
303 const auto [isTimezoneSet, aTimezone] = SfxLokHelper::getDefaultTimezone();
304 comphelper::LibreOfficeKit::setTimezone(isTimezoneSet, aTimezone);
308 if (bInputMode)
310 double fVal = 0.0;
311 sal_uInt32 nFormat = 0;
312 switch (nReqFmt)
314 case SvNumFormatType::DATE:
316 Date aActDate( Date::SYSTEM );
317 fVal = aActDate - pFormatter->GetNullDate();
318 if (nCurNumFormatType == SvNumFormatType::DATE)
319 nFormat = nCurNumFormat;
321 break;
322 case SvNumFormatType::TIME:
324 tools::Time aActTime( tools::Time::SYSTEM );
325 fVal = aActTime.GetTimeInDays();
326 if (nCurNumFormatType == SvNumFormatType::TIME)
327 nFormat = nCurNumFormat;
329 break;
330 default:
331 SAL_WARN("sc.ui","unhandled current date/time request");
332 nReqFmt = SvNumFormatType::DATETIME;
333 [[fallthrough]];
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;
341 break;
344 if (!nFormat)
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);
352 OUString aString;
353 const Color* pColor;
354 pFormatter->GetOutputString( fVal, nFormat, aString, &pColor);
356 pInputHdl->DataChanging();
357 EditView* pTopView = pInputHdl->GetTopView();
358 if (pTopView)
359 pTopView->InsertText( aString);
360 EditView* pTableView = pInputHdl->GetTableView();
361 if (pTableView)
362 pTableView->InsertText( aString);
363 pInputHdl->DataChanged();
365 else
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.
375 switch (nReqFmt)
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
383 // in current date.
384 if (fCell != 0.0)
385 nReqFmt = SvNumFormatType::DATETIME;
386 break;
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()))
396 bForceReqFmt = true;
398 break;
399 default: break;
401 break;
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.
408 if (fCell != 0.0)
409 nReqFmt = SvNumFormatType::DATETIME;
410 break;
411 case SvNumFormatType::DATETIME:
412 // Requesting current time on an empty date+time cell
413 // inserts both current date+time.
414 if (fCell == 0.0)
415 nReqFmt = SvNumFormatType::DATETIME;
416 else
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;
424 else
425 bForceReqFmt = true;
427 break;
428 default: break;
430 break;
431 default:
432 SAL_WARN("sc.ui","unhandled current date/time request");
433 nReqFmt = SvNumFormatType::DATETIME;
434 [[fallthrough]];
435 case SvNumFormatType::DATETIME:
436 break;
438 double fVal = 0.0;
439 switch (nReqFmt)
441 case SvNumFormatType::DATE:
443 Date aActDate( Date::SYSTEM );
444 fVal = aActDate - pFormatter->GetNullDate();
446 break;
447 case SvNumFormatType::TIME:
449 tools::Time aActTime( tools::Time::SYSTEM );
450 fVal = aActTime.GetTimeInDays();
452 break;
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();
462 break;
463 case SvNumFormatType::TIME:
465 double fTime = fCell - rtl::math::approxFloor( fCell);
466 Date aActDate( Date::SYSTEM );
467 fVal = (aActDate - pFormatter->GetNullDate()) + fTime;
469 break;
470 default:
472 DateTime aActDateTime( DateTime::SYSTEM );
473 fVal = DateTime::Sub( aActDateTime, DateTime( pFormatter->GetNullDate()));
476 break;
477 default: break;
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
488 // through.
489 if (bForceReqFmt || (nReqFmt != nCurNumFormatType && nCurNumFormatType != SvNumFormatType::DATETIME))
490 SetNumberFormat(nReqFmt);
491 else
492 rViewData.UpdateInputHandler(); // update input bar with new value
494 pUndoMgr->LeaveListAction();
498 void ScViewFunc::ShowNote( bool bShow )
500 if( bShow )
501 HideNoteMarker();
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 );
531 if(!pNote)
532 return;
534 // hide temporary note caption
535 HideNoteMarker();
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();
543 if( !pCaption )
544 return;
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());
553 if (pFuText)
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: */