xref: /core/sc/source/ui/view/cellsh3.cxx (revision e932e2ab)
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 <scitems.hxx>
21 #include <editeng/editview.hxx>
22 #include <editeng/editeng.hxx>
23 #include <formula/formulahelper.hxx>
24 #include <sfx2/viewfrm.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/request.hxx>
28 #include <svl/stritem.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/weld.hxx>
31 #include <globstr.hrc>
32 #include <scresid.hxx>
33 #include <scmod.hxx>
34 #include <appoptio.hxx>
35 #include <tabvwsh.hxx>
36 #include <document.hxx>
37 #include <sc.hrc>
38 #include <reffact.hxx>
39 #include <uiitems.hxx>
40 #include <autoform.hxx>
41 #include <cellsh.hxx>
42 #include <inputhdl.hxx>
43 #include <inputopt.hxx>
44 #include <editable.hxx>
45 #include <funcdesc.hxx>
46 #include <markdata.hxx>
47 #include <scabstdlg.hxx>
48 #include <columnspanset.hxx>
49 #include <comphelper/lok.hxx>
50 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
51 #include <inputwin.hxx>
52 #include <officecfg/Office/Calc.hxx>
53 
54 #include <memory>
55 
56 using sc::TwipsToEvenHMM;
57 
58 namespace
59 {
60 /// Rid ourselves of unwanted " quoted json characters.
escapeJSON(const OUString & aStr)61 OString escapeJSON(const OUString &aStr)
62 {
63     OUString aEscaped = aStr;
64     aEscaped = aEscaped.replaceAll("\n", " ");
65     aEscaped = aEscaped.replaceAll("\"", "'");
66     return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
67 }
68 
lcl_lokGetWholeFunctionList()69 void lcl_lokGetWholeFunctionList()
70 {
71     const SfxViewShell* pViewShell = SfxViewShell::Current();
72     if (!(comphelper::LibreOfficeKit::isActive()
73         && pViewShell && pViewShell->isLOKMobilePhone()))
74         return;
75 
76     const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
77     sal_uInt32 nListCount = pFuncList->GetCount();
78     std::set<OUString> aFuncNameOrderedSet;
79     for(sal_uInt32 i = 0; i < nListCount; ++i)
80     {
81         const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
82         if ( pDesc->mxFuncName )
83         {
84             aFuncNameOrderedSet.insert(*pDesc->mxFuncName);
85         }
86     }
87     ScFunctionMgr* pFuncManager = ScGlobal::GetStarCalcFunctionMgr();
88     if (!(pFuncManager && aFuncNameOrderedSet.size()))
89         return;
90 
91     OStringBuffer aPayload(
92         "{ \"wholeList\": true, "
93         "\"categories\": [ ");
94 
95     formula::FormulaHelper aHelper(pFuncManager);
96     sal_uInt32 nCategoryCount = pFuncManager->getCount();
97     for (sal_uInt32 i = 0; i < nCategoryCount; ++i)
98     {
99         OUString sCategoryName = ScFunctionMgr::GetCategoryName(i);
100         aPayload.append("{"
101             "\"name\": \""
102             + escapeJSON(sCategoryName)
103             + "\"}, ");
104     }
105     sal_Int32 nLen = aPayload.getLength();
106     aPayload[nLen - 2] = ' ';
107     aPayload[nLen - 1] = ']';
108     aPayload.append(", ");
109 
110     OUString aDescFuncNameStr;
111     aPayload.append("\"functions\": [ ");
112     sal_uInt32 nCurIndex = 0;
113     for (const OUString& aFuncNameStr : aFuncNameOrderedSet)
114     {
115         aDescFuncNameStr = aFuncNameStr + "()";
116         sal_Int32 nNextFStart = 0;
117         const formula::IFunctionDescription* ppFDesc;
118         ::std::vector< OUString > aArgs;
119         OUString eqPlusFuncName = "=" + aDescFuncNameStr;
120         if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
121         {
122             if ( ppFDesc && !ppFDesc->getFunctionName().isEmpty() )
123             {
124                 if (ppFDesc->getCategory())
125                 {
126                     aPayload.append("{"
127                         "\"index\": "
128                         + OString::number(static_cast<sal_Int64>(nCurIndex))
129                         + ", "
130                         "\"category\": "
131                         + OString::number(static_cast<sal_Int64>(ppFDesc->getCategory()->getNumber()))
132                         + ", "
133                         "\"signature\": \""
134                         + escapeJSON(ppFDesc->getSignature())
135                         + "\", "
136                         "\"description\": \""
137                         + escapeJSON(ppFDesc->getDescription())
138                         + "\"}, ");
139                 }
140             }
141         }
142         ++nCurIndex;
143     }
144     nLen = aPayload.getLength();
145     aPayload[nLen - 2] = ' ';
146     aPayload[nLen - 1] = ']';
147     aPayload.append(" }");
148 
149     OString s = aPayload.makeStringAndClear();
150     pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s);
151 }
152 
153 } // end namespace
154 
Execute(SfxRequest & rReq)155 void ScCellShell::Execute( SfxRequest& rReq )
156 {
157     ScTabViewShell* pTabViewShell   = GetViewData().GetViewShell();
158     SfxBindings&        rBindings   = pTabViewShell->GetViewFrame().GetBindings();
159     ScModule*           pScMod      = SC_MOD();
160     const SfxItemSet*   pReqArgs    = rReq.GetArgs();
161     sal_uInt16              nSlot       = rReq.GetSlot();
162 
163     if (nSlot != SID_CURRENTCELL)       // this comes with MouseButtonUp
164         pTabViewShell->HideListBox();   // Autofilter-DropDown-Listbox
165 
166     if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
167     {
168         switch ( nSlot )
169         {
170             //  when opening a reference-dialog the subshell may not be switched
171             //  (on closing the dialog StopEditShell is called)
172             case SID_OPENDLG_FUNCTION:
173                     //  inplace leads to trouble with EditShell ...
174                     //! cannot always be switched ????
175                     if (!pTabViewShell->GetViewFrame().GetFrame().IsInPlace())
176                         pTabViewShell->SetDontSwitch(true);         // do not switch off EditShell
177                     [[fallthrough]];
178 
179             case FID_CELL_FORMAT:
180             case SID_ENABLE_HYPHENATION:
181             case SID_DATA_SELECT:
182             case SID_OPENDLG_CONSOLIDATE:
183             case SID_OPENDLG_SOLVE:
184             case SID_OPENDLG_OPTSOLVER:
185 
186                     pScMod->InputEnterHandler();
187                     pTabViewShell->UpdateInputHandler();
188 
189                     pTabViewShell->SetDontSwitch(false);
190 
191                     break;
192 
193             default:
194                     break;
195         }
196     }
197 
198     switch ( nSlot )
199     {
200         case SID_STATUS_SELMODE:
201             if ( pReqArgs )
202             {
203                 /* 0: STD   Click cancels selection
204                  * 1: ER    Click extends selection
205                  * 2: ERG   Click defines further selection
206                  */
207                 sal_uInt16 nMode = static_cast<const SfxUInt16Item&>(pReqArgs->Get( nSlot )).GetValue();
208 
209                 switch ( nMode )
210                 {
211                     case 1: nMode = KEY_SHIFT;  break;
212                     case 2: nMode = KEY_MOD1;   break; // control-key
213                     case 0:
214                     default:
215                         nMode = 0;
216                 }
217 
218                 pTabViewShell->LockModifiers( nMode );
219             }
220             else
221             {
222                 //  no arguments (also executed by double click on the status bar controller):
223                 //  advance to next selection mode
224 
225                 sal_uInt16 nModifiers = pTabViewShell->GetLockedModifiers();
226                 switch ( nModifiers )
227                 {
228                     case KEY_SHIFT: nModifiers = KEY_MOD1;  break;      // EXT -> ADD
229                     case KEY_MOD1:  nModifiers = 0;         break;      // ADD -> STD
230                     default:        nModifiers = KEY_SHIFT; break;      // STD -> EXT
231                 }
232                 pTabViewShell->LockModifiers( nModifiers );
233             }
234 
235             rBindings.Invalidate( SID_STATUS_SELMODE );
236             rReq.Done();
237             break;
238 
239         //  SID_STATUS_SELMODE_NORM is not used ???
240 
241         case SID_STATUS_SELMODE_NORM:
242             pTabViewShell->LockModifiers( 0 );
243             rBindings.Invalidate( SID_STATUS_SELMODE );
244             break;
245 
246         //  SID_STATUS_SELMODE_ERG / SID_STATUS_SELMODE_ERW as toggles:
247 
248         case SID_STATUS_SELMODE_ERG:
249             if ( pTabViewShell->GetLockedModifiers() & KEY_MOD1 )
250                 pTabViewShell->LockModifiers( 0 );
251             else
252                 pTabViewShell->LockModifiers( KEY_MOD1 );
253             rBindings.Invalidate( SID_STATUS_SELMODE );
254             break;
255 
256         case SID_STATUS_SELMODE_ERW:
257             if ( pTabViewShell->GetLockedModifiers() & KEY_SHIFT )
258                 pTabViewShell->LockModifiers( 0 );
259             else
260                 pTabViewShell->LockModifiers( KEY_SHIFT );
261             rBindings.Invalidate( SID_STATUS_SELMODE );
262             break;
263 
264         case SID_ENTER_STRING:
265             {
266                 if ( pReqArgs )
267                 {
268                     // In the LOK case, we want to set the document modified state
269                     // right away at the start of the edit, so that the content is
270                     // saved even when the user leaves the document before hitting
271                     // Enter
272                     // NOTE: This also means we want to set the modified state
273                     // regardless of the DontCommit parameter's value.
274                     if (comphelper::LibreOfficeKit::isActive() && !GetViewData().GetDocShell()->IsModified())
275                     {
276                         GetViewData().GetDocShell()->SetModified();
277                         rBindings.Invalidate(SID_SAVEDOC);
278                         rBindings.Invalidate(SID_DOC_MODIFIED);
279                     }
280 
281                     OUString aStr( pReqArgs->Get( SID_ENTER_STRING ).GetValue() );
282                     const SfxPoolItem* pDontCommitItem;
283                     bool bCommit = true;
284                     if (pReqArgs->HasItem(FN_PARAM_1, &pDontCommitItem))
285                         bCommit = !(static_cast<const SfxBoolItem*>(pDontCommitItem)->GetValue());
286 
287                     ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pTabViewShell );
288                     if (bCommit)
289                     {
290                         pTabViewShell->EnterData( GetViewData().GetCurX(),
291                                                   GetViewData().GetCurY(),
292                                                   GetViewData().GetTabNo(),
293                                                   aStr, nullptr,
294                                                   true /*bMatrixExpand*/);
295                     }
296                     else if (pHdl)
297                     {
298                         SC_MOD()->SetInputMode(SC_INPUT_TABLE);
299 
300                         EditView* pTableView = pHdl->GetActiveView();
301                         pHdl->DataChanging();
302                         if (pTableView)
303                             pTableView->getEditEngine().SetText(aStr);
304                         pHdl->DataChanged();
305 
306                         SC_MOD()->SetInputMode(SC_INPUT_NONE);
307                     }
308 
309                     if ( !pHdl || !pHdl->IsInEnterHandler() )
310                     {
311                         //  UpdateInputHandler is needed after the cell content
312                         //  has changed, but if called from EnterHandler, UpdateInputHandler
313                         //  will be called later when moving the cursor.
314                         pTabViewShell->UpdateInputHandler();
315                     }
316 
317                     rReq.Done();
318 
319                     //  no GrabFocus here, as otherwise on a Mac the tab jumps before the
320                     //  sideview, when the input was not finished
321                     //  (GrabFocus is called in KillEditView)
322                 }
323             }
324             break;
325 
326         case SID_INSERT_MATRIX:
327             {
328                 if ( pReqArgs )
329                 {
330                     OUString aStr = static_cast<const SfxStringItem&>(pReqArgs->
331                                     Get( SID_INSERT_MATRIX )).GetValue();
332                     ScDocument& rDoc = GetViewData().GetDocument();
333                     pTabViewShell->EnterMatrix( aStr, rDoc.GetGrammar() );
334                     rReq.Done();
335                 }
336             }
337             break;
338 
339         case FID_INPUTLINE_ENTER:
340         case FID_INPUTLINE_BLOCK:
341         case FID_INPUTLINE_MATRIX:
342             {
343                 if( pReqArgs == nullptr ) //XXX temporary HACK to avoid GPF
344                     break;
345 
346                 const ScInputStatusItem* pStatusItem
347                     = static_cast<const ScInputStatusItem*>(&pReqArgs->
348                             Get( FID_INPUTLINE_STATUS ));
349 
350                 const ScAddress& aCursorPos = pStatusItem->GetPos();
351                 const OUString& aString = pStatusItem->GetString();
352                 const EditTextObject* pData = pStatusItem->GetEditData();
353 
354                 if (pData)
355                 {
356                     if (nSlot == FID_INPUTLINE_BLOCK)
357                     {
358                         pTabViewShell->EnterBlock( aString, pData );
359                     }
360                     else if ( !aString.isEmpty() && ( aString[0] == '=' || aString[0] == '+' || aString[0] == '-' ) )
361                     {
362                         pTabViewShell->EnterData( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
363                                 aString, pData, true /*bMatrixExpand*/);
364                     }
365                     else
366                     {
367                         pTabViewShell->EnterData(aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), *pData);
368                     }
369                 }
370                 else
371                 {
372                     if (nSlot == FID_INPUTLINE_ENTER)
373                     {
374                         if (
375                             aCursorPos.Col() == GetViewData().GetCurX() &&
376                             aCursorPos.Row() == GetViewData().GetCurY() &&
377                             aCursorPos.Tab() == GetViewData().GetTabNo()
378                             )
379                         {
380                             SfxStringItem   aItem( SID_ENTER_STRING, aString );
381 
382                             const SfxPoolItem* aArgs[2];
383                             aArgs[0] = &aItem;
384                             aArgs[1] = nullptr;
385                             rBindings.Execute( SID_ENTER_STRING, aArgs );
386                         }
387                         else
388                         {
389                             pTabViewShell->EnterData( aCursorPos.Col(),
390                                                     aCursorPos.Row(),
391                                                     aCursorPos.Tab(),
392                                                     aString, nullptr,
393                                                     true /*bMatrixExpand*/);
394                             rReq.Done();
395                         }
396                     }
397                     else if (nSlot == FID_INPUTLINE_BLOCK)
398                     {
399                         pTabViewShell->EnterBlock( aString, nullptr );
400                         rReq.Done();
401                     }
402                     else
403                     {
404                         ScDocument& rDoc = GetViewData().GetDocument();
405                         pTabViewShell->EnterMatrix( aString, rDoc.GetGrammar() );
406                         rReq.Done();
407                     }
408                 }
409 
410                 pTabViewShell->SetAutoSpellData(
411                     aCursorPos.Col(), aCursorPos.Row(), pStatusItem->GetMisspellRanges());
412 
413                 //  no GrabFocus here, as otherwise on a Mac the tab jumps before the
414                 //  sideview, when the input was not finished
415                 //  (GrabFocus is called in KillEditView)
416             }
417             break;
418 
419         case SID_OPENDLG_FUNCTION:
420             {
421                 const SfxViewShell* pViewShell = SfxViewShell::Current();
422                 if (comphelper::LibreOfficeKit::isActive()
423                     && pViewShell && pViewShell->isLOKMobilePhone())
424                 {
425                     // not set the dialog id in the mobile case or we would
426                     // not be able to get cell address pasted in the edit view
427                     // by just tapping on them
428                     lcl_lokGetWholeFunctionList();
429                 }
430                 else
431                 {
432                     sal_uInt16 nId = SID_OPENDLG_FUNCTION;
433                     SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
434                     SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
435                     bool bVis = comphelper::LibreOfficeKit::isActive() || pWnd == nullptr;
436                     pScMod->SetRefDialog( nId, bVis );
437                 }
438                 rReq.Ignore();
439             }
440             break;
441 
442         case SID_OPENDLG_CONSOLIDATE:
443             {
444                 sal_uInt16          nId  = ScConsolidateDlgWrapper::GetChildWindowId();
445                 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
446                 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
447 
448                 pScMod->SetRefDialog( nId, pWnd == nullptr );
449             }
450             break;
451 
452         case SID_EASY_CONDITIONAL_FORMAT_DIALOG:
453             {
454                 if (pReqArgs != nullptr)
455                 {
456                     const SfxPoolItem* pFormat;
457                     if (pReqArgs->HasItem( FN_PARAM_1, &pFormat))
458                     {
459                         sal_Int16 nFormat = static_cast<const SfxInt16Item*>(pFormat)->GetValue();
460                         sal_uInt16 nId = sc::ConditionalFormatEasyDialogWrapper::GetChildWindowId();
461                         SfxViewFrame& rViewFrame = pTabViewShell->GetViewFrame();
462                         SfxChildWindow* pWindow = rViewFrame.GetChildWindow( nId );
463                         GetViewData().GetDocument().SetEasyConditionalFormatDialogData(std::make_unique<ScConditionMode>(static_cast<ScConditionMode>(nFormat)));
464 
465                         pScMod->SetRefDialog( nId, pWindow == nullptr );
466                     }
467                 }
468             }
469             break;
470 
471         case FID_CELL_FORMAT:
472             {
473                 if ( pReqArgs != nullptr )
474                 {
475                     // set cell attribute without dialog:
476                     SfxItemSet aEmptySet(SfxItemSet::makeFixedSfxItemSet<ATTR_PATTERN_START, ATTR_PATTERN_END>(*pReqArgs->GetPool()));
477                     // SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END>  aEmptySet( *pReqArgs->GetPool() );
478 
479                     SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END>  aNewSet( *pReqArgs->GetPool() );
480 
481                     const SfxPoolItem*  pAttr = nullptr;
482                     sal_uInt16              nWhich = 0;
483 
484                     for ( nWhich=ATTR_PATTERN_START; nWhich<=ATTR_PATTERN_END; nWhich++ )
485                         if ( pReqArgs->GetItemState( nWhich, true, &pAttr ) == SfxItemState::SET )
486                             aNewSet.Put( *pAttr );
487 
488                     pTabViewShell->ApplyAttributes( aNewSet, aEmptySet );
489 
490                     rReq.Done();
491                 }
492                 else
493                 {
494                     pTabViewShell->ExecuteCellFormatDlg( rReq, u""_ustr );
495                 }
496             }
497             break;
498 
499         case SID_ENABLE_HYPHENATION:
500             pTabViewShell->ExecuteCellFormatDlg(rReq, u"alignment"_ustr);
501             break;
502 
503         case SID_PROPERTY_PANEL_CELLTEXT_DLG:
504             pTabViewShell->ExecuteCellFormatDlg( rReq, u"font"_ustr );
505             break;
506 
507         case SID_CELL_FORMAT_BORDER:
508             pTabViewShell->ExecuteCellFormatDlg( rReq, u"borders"_ustr );
509             break;
510 
511         case SID_CHAR_DLG_EFFECT:
512             pTabViewShell->ExecuteCellFormatDlg( rReq, u"fonteffects"_ustr );
513             break;
514 
515         case SID_OPENDLG_SOLVE:
516             {
517                 sal_uInt16          nId  = ScSolverDlgWrapper::GetChildWindowId();
518                 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
519                 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
520 
521                 pScMod->SetRefDialog( nId, pWnd == nullptr );
522             }
523             break;
524 
525         case SID_OPENDLG_OPTSOLVER:
526             {
527                 sal_uInt16 nId = ScOptSolverDlgWrapper::GetChildWindowId();
528                 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
529                 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
530 
531                 pScMod->SetRefDialog( nId, pWnd == nullptr );
532             }
533             break;
534 
535         case SID_OPENDLG_TABOP:
536             {
537                 sal_uInt16          nId  = ScTabOpDlgWrapper::GetChildWindowId();
538                 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
539                 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
540 
541                 pScMod->SetRefDialog( nId, pWnd == nullptr );
542             }
543             break;
544 
545         case SID_SCENARIOS:
546             {
547                 ScDocument& rDoc = GetViewData().GetDocument();
548                 ScMarkData& rMark = GetViewData().GetMarkData();
549                 SCTAB nTab = GetViewData().GetTabNo();
550 
551                 if ( rDoc.IsScenario(nTab) )
552                 {
553                     rMark.MarkToMulti();
554                     if ( rMark.IsMultiMarked() )
555                     {
556 
557                         bool bExtend = rReq.IsAPI();
558                         if (!bExtend)
559                         {
560                             std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
561                                                                            VclMessageType::Question, VclButtonsType::YesNo,
562                                                                            ScResId(STR_UPDATE_SCENARIO)));
563                             xQueryBox->set_default_response(RET_YES);
564                             bExtend = xQueryBox->run() == RET_YES;
565                         }
566 
567                         if (bExtend)
568                         {
569                             pTabViewShell->ExtendScenario();
570                             rReq.Done();
571                         }
572                     }
573                     else if( ! rReq.IsAPI() )
574                     {
575                         std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
576                                                                        VclMessageType::Warning, VclButtonsType::Ok,
577                                                                        ScResId(STR_NOAREASELECTED)));
578                         xErrorBox->run();
579                     }
580                 }
581                 else
582                 {
583                     rMark.MarkToMulti();
584                     if ( rMark.IsMultiMarked() )
585                     {
586                         SCTAB i=1;
587                         OUString aBaseName;
588                         OUString aName;
589                         Color  aColor;
590                         ScScenarioFlags nFlags;
591 
592                         OUString aTmp;
593                         rDoc.GetName(nTab, aTmp);
594                         aBaseName = aTmp + "_" + ScResId(STR_SCENARIO) + "_";
595 
596                         //  first test, if the prefix is recognised as valid,
597                         //  else avoid only doubles
598                         bool bPrefix = ScDocument::ValidTabName( aBaseName );
599                         OSL_ENSURE(bPrefix, "invalid sheet name");
600 
601                         while ( rDoc.IsScenario(nTab+i) )
602                             i++;
603 
604                         bool bValid;
605                         SCTAB nDummy;
606                         do
607                         {
608                             aName = aBaseName + OUString::number( i );
609                             if (bPrefix)
610                                 bValid = rDoc.ValidNewTabName( aName );
611                             else
612                                 bValid = !rDoc.GetTable( aName, nDummy );
613                             ++i;
614                         }
615                         while ( !bValid && i <= MAXTAB + 2 );
616 
617                         if ( pReqArgs != nullptr )
618                         {
619                             OUString aArgName;
620                             OUString aArgComment;
621                             if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_SCENARIOS ) )
622                                 aArgName = pItem->GetValue();
623                             if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_NEW_TABLENAME ) )
624                                 aArgComment = pItem->GetValue();
625 
626                             aColor = COL_LIGHTGRAY;        // Default
627                             nFlags = ScScenarioFlags::NONE;         // not TwoWay
628 
629                             pTabViewShell->MakeScenario( aArgName, aArgComment, aColor, nFlags );
630                             if( ! rReq.IsAPI() )
631                                 rReq.Done();
632                         }
633                         else
634                         {
635                             bool bSheetProtected = rDoc.IsTabProtected(nTab);
636                             ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
637 
638                             ScopedVclPtr<AbstractScNewScenarioDlg> pNewDlg(pFact->CreateScNewScenarioDlg(pTabViewShell->GetFrameWeld(), aName, false, bSheetProtected));
639                             if ( pNewDlg->Execute() == RET_OK )
640                             {
641                                 OUString aComment;
642                                 pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags );
643                                 pTabViewShell->MakeScenario( aName, aComment, aColor, nFlags );
644 
645                                 rReq.AppendItem( SfxStringItem( SID_SCENARIOS, aName ) );
646                                 rReq.AppendItem( SfxStringItem( SID_NEW_TABLENAME, aComment ) );
647                                 rReq.Done();
648                             }
649                         }
650                     }
651                     else if( ! rReq.IsAPI() )
652                     {
653                         pTabViewShell->ErrorMessage(STR_ERR_NEWSCENARIO);
654                     }
655                 }
656             }
657             break;
658 
659         case SID_SELECTALL:
660             {
661                 SCTAB nTab = GetViewData().GetTabNo();
662                 SCCOL nStartCol = GetViewData().GetCurX();
663                 SCROW nStartRow = GetViewData().GetCurY();
664                 SCCOL nEndCol = nStartCol;
665                 SCROW nEndRow = nStartRow;
666                 bool bCanMark = false;
667 
668                 ScMarkData& rMarkdata = GetViewData().GetMarkData();
669                 const bool bSelectFirst(officecfg::Office::Calc::Input::SelectRangeBeforeAll::get());
670 
671                 if (bSelectFirst && !rMarkdata.IsMarked())
672                 {
673                     const ScDocument& rDoc = GetViewData().GetDocument();
674                     rDoc.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, false );
675                     bCanMark = nStartCol != nEndCol || nStartRow != nEndRow;
676                 }
677 
678                 if (bCanMark)
679                 {
680                     const ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab);
681                     pTabViewShell->MarkRange(aRange, false);
682                 }
683                 else
684                     pTabViewShell->SelectAll();
685 
686                 rReq.Done();
687             }
688             break;
689 
690         case FID_ROW_HEIGHT:
691             {
692                 const SfxPoolItem* pRow;
693                 const SfxUInt16Item* pHeight;
694                 sal_uInt16 nHeight;
695 
696                 if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) &&
697                                  pReqArgs->HasItem( FN_PARAM_1, &pRow ) )
698                 {
699                     std::vector<sc::ColRowSpan> aRanges;
700                     SCCOLROW nRow = static_cast<const SfxInt32Item*>(pRow)->GetValue() - 1;
701                     nHeight = pHeight->GetValue();
702                     ScMarkData& rMark = GetViewData().GetMarkData();
703 
704                     if ( rMark.IsRowMarked( static_cast<SCROW>(nRow) ) )
705                     {
706                         aRanges = rMark.GetMarkedRowSpans();
707                     }
708                     else
709                     {
710                         aRanges.emplace_back(nRow, nRow);
711                     }
712 
713                     pTabViewShell->SetWidthOrHeight(false, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nHeight, o3tl::Length::mm100));
714                 }
715                 else if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) )
716                 {
717                     nHeight = pHeight->GetValue();
718 
719                     // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
720                     pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT,
721                         o3tl::toTwips(nHeight, o3tl::Length::mm100));
722                     if( ! rReq.IsAPI() )
723                         rReq.Done();
724                 }
725                 else
726                 {
727                     ScViewData& rData      = GetViewData();
728                     FieldUnit   eMetric    = SC_MOD()->GetAppOptions().GetAppMetric();
729                     sal_uInt16      nCurHeight = rData.GetDocument().
730                                                 GetRowHeight( rData.GetCurY(),
731                                                               rData.GetTabNo() );
732                     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
733                     VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
734                         pTabViewShell->GetFrameWeld(), u"RowHeightDialog"_ustr, nCurHeight,
735                         rData.GetDocument().GetSheetOptimalMinRowHeight(rData.GetTabNo()),
736                         eMetric, 2, MAX_ROW_HEIGHT));
737 
738                     pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
739                         if (nResult == RET_OK)
740                         {
741                             SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_ROW_HEIGHT);
742                             tools::Long nVal = pDlg->GetInputValue();
743                             pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
744 
745                             // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
746                             pRequest.AppendItem( SfxUInt16Item( FID_ROW_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
747                             pRequest.Done();
748                         }
749                         pDlg->disposeOnce();
750                     });
751                 }
752             }
753             break;
754 
755         case FID_ROW_OPT_HEIGHT:
756             {
757                 if ( pReqArgs )
758                 {
759                     const SfxUInt16Item&  rUInt16Item = pReqArgs->Get( FID_ROW_OPT_HEIGHT );
760 
761                     // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
762                     pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL,
763                                     o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
764                     ScGlobal::nLastRowHeightExtra = rUInt16Item.GetValue();
765 
766                     if( ! rReq.IsAPI() )
767                         rReq.Done();
768                 }
769                 else
770                 {
771                     FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
772 
773                     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
774                     VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
775                         pTabViewShell->GetFrameWeld(), u"OptimalRowHeightDialog"_ustr,
776                         ScGlobal::nLastRowHeightExtra, 0, eMetric, 2, MAX_EXTRA_HEIGHT));
777 
778                     pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
779                         if ( nResult == RET_OK )
780                         {
781                             SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_ROW_OPT_HEIGHT);
782                             tools::Long nVal = pDlg->GetInputValue();
783                             pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
784                             ScGlobal::nLastRowHeightExtra = nVal;
785 
786                             // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
787                             pRequest.AppendItem( SfxUInt16Item( FID_ROW_OPT_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
788                             pRequest.Done();
789                         }
790                         pDlg->disposeOnce();
791                     });
792                 }
793             }
794             break;
795 
796         case FID_COL_WIDTH:
797             {
798                 const SfxPoolItem* pColumn;
799                 const SfxUInt16Item* pWidth;
800                 sal_uInt16 nWidth;
801 
802                 if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) &&
803                                  pReqArgs->HasItem( FN_PARAM_1, &pColumn ) )
804                 {
805                     std::vector<sc::ColRowSpan> aRanges;
806                     SCCOLROW nColumn = static_cast<const SfxUInt16Item*>(pColumn)->GetValue() - 1;
807                     nWidth = pWidth->GetValue();
808                     ScMarkData& rMark = GetViewData().GetMarkData();
809 
810                     if ( rMark.IsColumnMarked( static_cast<SCCOL>(nColumn) ) )
811                     {
812                         aRanges = rMark.GetMarkedColSpans();
813                     }
814                     else
815                     {
816                         aRanges.emplace_back(nColumn, nColumn);
817                     }
818 
819                     pTabViewShell->SetWidthOrHeight(true, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nWidth, o3tl::Length::mm100));
820                 }
821                 else if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) )
822                 {
823                     nWidth = pWidth->GetValue();
824 
825                     // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
826                     pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT,
827                         o3tl::toTwips(nWidth, o3tl::Length::mm100));
828                     if( ! rReq.IsAPI() )
829                         rReq.Done();
830                 }
831                 else
832                 {
833                     FieldUnit   eMetric    = SC_MOD()->GetAppOptions().GetAppMetric();
834                     ScViewData& rData      = GetViewData();
835                     sal_uInt16      nCurHeight = rData.GetDocument().
836                                                 GetColWidth( rData.GetCurX(),
837                                                              rData.GetTabNo() );
838                     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
839                     VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
840                         pTabViewShell->GetFrameWeld(), u"ColWidthDialog"_ustr, nCurHeight,
841                         STD_COL_WIDTH, eMetric, 2, MAX_COL_WIDTH));
842 
843                     pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
844                         if ( nResult == RET_OK )
845                         {
846                             SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_COL_WIDTH);
847                             tools::Long nVal = pDlg->GetInputValue();
848                             pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
849 
850                             // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
851                             pRequest.AppendItem( SfxUInt16Item( FID_COL_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal))) );
852                             pRequest.Done();
853                         }
854                         pDlg->disposeOnce();
855                     });
856                 }
857             }
858             break;
859 
860         case FID_COL_OPT_WIDTH:
861             {
862                 if ( pReqArgs )
863                 {
864                     const SfxUInt16Item&  rUInt16Item = pReqArgs->Get( FID_COL_OPT_WIDTH );
865 
866                     // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
867                     pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL,
868                                     o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
869                     ScGlobal::nLastColWidthExtra = rUInt16Item.GetValue();
870 
871                     if( ! rReq.IsAPI() )
872                         rReq.Done();
873                 }
874                 else
875                 {
876                     FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
877 
878                     ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
879                     VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
880                         pTabViewShell->GetFrameWeld(), u"OptimalColWidthDialog"_ustr,
881                         ScGlobal::nLastColWidthExtra, STD_EXTRA_WIDTH, eMetric, 2, MAX_EXTRA_WIDTH));
882 
883                     pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
884                         SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_COL_OPT_WIDTH);
885                         if ( nResult == RET_OK )
886                         {
887                             tools::Long nVal = pDlg->GetInputValue();
888                             pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
889                             ScGlobal::nLastColWidthExtra = nVal;
890 
891                             // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
892                             pRequest.AppendItem( SfxUInt16Item( FID_COL_OPT_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
893                             pRequest.Done();
894                         }
895                         pDlg->disposeOnce();
896                     });
897                 }
898             }
899             break;
900 
901         case FID_COL_OPT_DIRECT:
902             pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH );
903             rReq.Done();
904             break;
905 
906         case FID_ROW_HIDE:
907             pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, 0 );
908             rReq.Done();
909             break;
910         case FID_ROW_SHOW:
911             pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_SHOW, 0 );
912             rReq.Done();
913             break;
914         case FID_COL_HIDE:
915             pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, 0 );
916             rReq.Done();
917             break;
918         case FID_COL_SHOW:
919             pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_SHOW, 0 );
920             rReq.Done();
921             break;
922 
923         case SID_CELL_FORMAT_RESET:
924             {
925                 pTabViewShell->DeleteContents( InsertDeleteFlags::HARDATTR | InsertDeleteFlags::EDITATTR );
926                 rReq.Done();
927             }
928             break;
929 
930         case FID_MERGE_ON:
931         case FID_MERGE_OFF:
932         case FID_MERGE_TOGGLE:
933         {
934             if ( !GetViewData().GetDocument().GetChangeTrack() )
935             {
936                 // test whether to merge or to split
937                 bool bMerge = false;
938                 bool bCenter = false;
939                 switch( nSlot )
940                 {
941                     case FID_MERGE_ON:
942                         bMerge = true;
943                     break;
944                     case FID_MERGE_OFF:
945                         bMerge = false;
946                     break;
947                     case FID_MERGE_TOGGLE:
948                     {
949                         bCenter = true;
950                         std::unique_ptr<SfxPoolItem> pItem;
951                         if( rBindings.QueryState( nSlot, pItem ) >= SfxItemState::DEFAULT )
952                             bMerge = !static_cast< SfxBoolItem* >( pItem.get() )->GetValue();
953                     }
954                     break;
955                 }
956 
957                 if( bMerge )
958                 {
959                     // merge - check if to move contents of covered cells
960                     bool bMoveContents = false;
961                     bool bApi = rReq.IsAPI();
962                     const SfxPoolItem* pItem;
963                     if ( pReqArgs &&
964                         pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
965                     {
966                         assert(dynamic_cast<const SfxBoolItem*>( pItem) && "wrong item");
967                         bMoveContents = static_cast<const SfxBoolItem*>(pItem)->GetValue();
968                     }
969 
970                     pTabViewShell->MergeCells( bApi, bMoveContents, bCenter, nSlot );
971                 }
972                 else
973                 {
974                     // split cells
975                     if (pTabViewShell->RemoveMerge())
976                     {
977                         rBindings.Invalidate( nSlot );
978                         rReq.Done();
979                     }
980                 }
981                 break;
982             }
983         }
984         break;
985 
986         case SID_AUTOFORMAT:
987             {
988                 weld::Window* pDlgParent = pTabViewShell->GetFrameWeld();
989                 SCCOL nStartCol;
990                 SCROW nStartRow;
991                 SCTAB nStartTab;
992                 SCCOL nEndCol;
993                 SCROW nEndRow;
994                 SCTAB nEndTab;
995 
996                 const ScMarkData& rMark = GetViewData().GetMarkData();
997                 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
998                     pTabViewShell->MarkDataArea();
999 
1000                 GetViewData().GetSimpleArea( nStartCol,nStartRow,nStartTab,
1001                                               nEndCol,nEndRow,nEndTab );
1002 
1003                 if (   ( std::abs(nEndCol-nStartCol) > 1 )
1004                     && ( std::abs(nEndRow-nStartRow) > 1 ) )
1005                 {
1006                     if ( pReqArgs )
1007                     {
1008                         const SfxStringItem& rNameItem = pReqArgs->Get( SID_AUTOFORMAT );
1009                         ScAutoFormat* pFormat = ScGlobal::GetOrCreateAutoFormat();
1010                         ScAutoFormat::const_iterator it = pFormat->find(rNameItem.GetValue());
1011                         ScAutoFormat::const_iterator itBeg = pFormat->begin();
1012                         size_t nIndex = std::distance(itBeg, it);
1013 
1014                         pTabViewShell->AutoFormat( nIndex );
1015 
1016                         if( ! rReq.IsAPI() )
1017                             rReq.Done();
1018                     }
1019                     else
1020                     {
1021                         ScGlobal::ClearAutoFormat();
1022                         std::unique_ptr<ScAutoFormatData> pNewEntry(pTabViewShell->CreateAutoFormatData());
1023                         ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
1024 
1025                         ScopedVclPtr<AbstractScAutoFormatDlg> pDlg(pFact->CreateScAutoFormatDlg(pDlgParent, ScGlobal::GetOrCreateAutoFormat(), pNewEntry.get(), GetViewData()));
1026 
1027                         if ( pDlg->Execute() == RET_OK )
1028                         {
1029                             ScEditableTester aTester( pTabViewShell );
1030                             if ( !aTester.IsEditable() )
1031                             {
1032                                 pTabViewShell->ErrorMessage(aTester.GetMessageId());
1033                             }
1034                             else
1035                             {
1036                                 pTabViewShell->AutoFormat( pDlg->GetIndex() );
1037 
1038                                 rReq.AppendItem( SfxStringItem( SID_AUTOFORMAT, pDlg->GetCurrFormatName() ) );
1039                                 rReq.Done();
1040                             }
1041                         }
1042                     }
1043                 }
1044                 else
1045                 {
1046                     std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDlgParent,
1047                                                                    VclMessageType::Warning, VclButtonsType::Ok,
1048                                                                    ScResId(STR_INVALID_AFAREA)));
1049                     xErrorBox->run();
1050                 }
1051             }
1052             break;
1053 
1054         case SID_CANCEL:
1055             {
1056                 if (GetViewData().HasEditView(GetViewData().GetActivePart()))
1057                     pScMod->InputCancelHandler();
1058                 else if (pTabViewShell->HasPaintBrush())
1059                     pTabViewShell->ResetBrushDocument();            // abort format paint brush
1060                 else if (pTabViewShell->HasHintWindow())
1061                     pTabViewShell->RemoveHintWindow();
1062                 else if( ScViewUtil::IsFullScreen( *pTabViewShell ) )
1063                     ScViewUtil::SetFullScreen( *pTabViewShell, false );
1064                 else
1065                 {
1066                     // TODO/LATER: when is this code executed?
1067                     pTabViewShell->Escape();
1068                 }
1069             }
1070             break;
1071 
1072         case SID_ACCEPT_FORMULA:
1073             {
1074                 if (GetViewData().HasEditView(GetViewData().GetActivePart()))
1075                     pScMod->InputEnterHandler();
1076             }
1077             break;
1078 
1079         case SID_START_FORMULA:
1080             {
1081                 ScInputHandler* pInputHandler = pScMod->GetInputHdl();
1082                 if (pInputHandler && pInputHandler->GetInputWindow())
1083                     pInputHandler->GetInputWindow()->StartFormula();
1084             }
1085             break;
1086 
1087         case SID_DATA_SELECT:
1088             pTabViewShell->StartDataSelect();
1089             break;
1090 
1091         case SID_DETECTIVE_FILLMODE:
1092             {
1093                 bool bOldMode = pTabViewShell->IsAuditShell();
1094                 pTabViewShell->SetAuditShell( !bOldMode );
1095                 pTabViewShell->Invalidate( nSlot );
1096             }
1097             break;
1098 
1099         case FID_INPUTLINE_STATUS:
1100             OSL_FAIL("Execute from InputLine status");
1101             break;
1102 
1103         case SID_STATUS_DOCPOS:
1104             // Launch navigator.
1105             GetViewData().GetDispatcher().Execute(
1106                 SID_NAVIGATOR, SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
1107             break;
1108 
1109         case SID_MARKAREA:
1110             // called from Basic at the hidden view to select a range in the visible view
1111             OSL_FAIL("old slot SID_MARKAREA");
1112             break;
1113 
1114         case FID_MOVE_KEEP_INSERT_MODE:
1115         {
1116             const SfxBoolItem* pEnabledArg = rReq.GetArg<SfxBoolItem>(FID_MOVE_KEEP_INSERT_MODE);
1117             if (!pEnabledArg) {
1118                 SAL_WARN("sfx.appl", "FID_MOVE_KEEP_INSERT_MODE: must specify if you would like this to be enabled");
1119                 break;
1120             }
1121 
1122             ScInputOptions aInputOptions = pScMod->GetInputOptions();
1123 
1124             aInputOptions.SetMoveKeepEdit(pEnabledArg->GetValue());
1125             pScMod->SetInputOptions(aInputOptions);
1126 
1127             if (comphelper::LibreOfficeKit::isActive())
1128                 pTabViewShell->SetMoveKeepEdit(pEnabledArg->GetValue());
1129 
1130             break;
1131         }
1132 
1133         default:
1134             OSL_FAIL("ScCellShell::Execute: unknown slot");
1135             break;
1136     }
1137 }
1138 
1139 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1140