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 = ScModule::get();
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 aInputString = 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* pInputHandler = pScMod->GetInputHdl(pTabViewShell);
288 if (bCommit)
289 {
290 pTabViewShell->EnterDataToCurrentCell(aInputString, nullptr, true /*bMatrixExpand*/);
291 }
292 else if (pInputHandler)
293 {
294 pScMod->SetInputMode(SC_INPUT_TABLE);
295
296 EditView* pTableView = pInputHandler->GetActiveView();
297 pInputHandler->DataChanging();
298 if (pTableView)
299 pTableView->getEditEngine().SetText(aInputString);
300 pInputHandler->DataChanged();
301
302 pScMod->SetInputMode(SC_INPUT_NONE);
303 }
304
305 if (!pInputHandler || !pInputHandler->IsInEnterHandler())
306 {
307 // UpdateInputHandler is needed after the cell content
308 // has changed, but if called from EnterHandler, UpdateInputHandler
309 // will be called later when moving the cursor.
310 pTabViewShell->UpdateInputHandler();
311 }
312
313 rReq.Done();
314
315 // no GrabFocus here, as otherwise on a Mac the tab jumps before the
316 // sideview, when the input was not finished
317 // (GrabFocus is called in KillEditView)
318 }
319 }
320 break;
321
322 case SID_INSERT_MATRIX:
323 {
324 if ( pReqArgs )
325 {
326 OUString aStr = static_cast<const SfxStringItem&>(pReqArgs->
327 Get( SID_INSERT_MATRIX )).GetValue();
328 ScDocument& rDoc = GetViewData().GetDocument();
329 pTabViewShell->EnterMatrix( aStr, rDoc.GetGrammar() );
330 rReq.Done();
331 }
332 }
333 break;
334
335 case FID_INPUTLINE_ENTER:
336 case FID_INPUTLINE_BLOCK:
337 case FID_INPUTLINE_MATRIX:
338 {
339 if( pReqArgs == nullptr ) //XXX temporary HACK to avoid GPF
340 break;
341
342 const ScInputStatusItem* pStatusItem
343 = static_cast<const ScInputStatusItem*>(&pReqArgs->
344 Get( FID_INPUTLINE_STATUS ));
345
346 const ScAddress& aCursorPos = pStatusItem->GetPos();
347 const OUString& aString = pStatusItem->GetString();
348 const EditTextObject* pData = pStatusItem->GetEditData();
349
350 if (pData)
351 {
352 if (nSlot == FID_INPUTLINE_BLOCK)
353 {
354 pTabViewShell->EnterBlock( aString, pData );
355 }
356 else if ( !aString.isEmpty() && ( aString[0] == '=' || aString[0] == '+' || aString[0] == '-' ) )
357 {
358 pTabViewShell->EnterData( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
359 aString, pData, true /*bMatrixExpand*/);
360 }
361 else
362 {
363 pTabViewShell->EnterData(aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), *pData);
364 }
365 }
366 else
367 {
368 if (nSlot == FID_INPUTLINE_ENTER)
369 {
370 if (
371 aCursorPos.Col() == GetViewData().GetCurX() &&
372 aCursorPos.Row() == GetViewData().GetCurY() &&
373 aCursorPos.Tab() == GetViewData().GetTabNo()
374 )
375 {
376 SfxStringItem aItem( SID_ENTER_STRING, aString );
377
378 const SfxPoolItem* aArgs[2];
379 aArgs[0] = &aItem;
380 aArgs[1] = nullptr;
381 rBindings.Execute( SID_ENTER_STRING, aArgs );
382 }
383 else
384 {
385 pTabViewShell->EnterData( aCursorPos.Col(),
386 aCursorPos.Row(),
387 aCursorPos.Tab(),
388 aString, nullptr,
389 true /*bMatrixExpand*/);
390 rReq.Done();
391 }
392 }
393 else if (nSlot == FID_INPUTLINE_BLOCK)
394 {
395 pTabViewShell->EnterBlock( aString, nullptr );
396 rReq.Done();
397 }
398 else
399 {
400 ScDocument& rDoc = GetViewData().GetDocument();
401 pTabViewShell->EnterMatrix( aString, rDoc.GetGrammar() );
402 rReq.Done();
403 }
404 }
405
406 pTabViewShell->SetAutoSpellData(
407 aCursorPos.Col(), aCursorPos.Row(), pStatusItem->GetMisspellRanges());
408
409 // no GrabFocus here, as otherwise on a Mac the tab jumps before the
410 // sideview, when the input was not finished
411 // (GrabFocus is called in KillEditView)
412 }
413 break;
414
415 case SID_OPENDLG_FUNCTION:
416 {
417 const SfxViewShell* pViewShell = SfxViewShell::Current();
418 if (comphelper::LibreOfficeKit::isActive()
419 && pViewShell && pViewShell->isLOKMobilePhone())
420 {
421 // not set the dialog id in the mobile case or we would
422 // not be able to get cell address pasted in the edit view
423 // by just tapping on them
424 lcl_lokGetWholeFunctionList();
425 }
426 else
427 {
428 sal_uInt16 nId = SID_OPENDLG_FUNCTION;
429 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
430 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
431 bool bVis = comphelper::LibreOfficeKit::isActive() || pWnd == nullptr;
432 pScMod->SetRefDialog( nId, bVis );
433 }
434 rReq.Ignore();
435 }
436 break;
437
438 case SID_OPENDLG_CONSOLIDATE:
439 {
440 sal_uInt16 nId = ScConsolidateDlgWrapper::GetChildWindowId();
441 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
442 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
443
444 pScMod->SetRefDialog( nId, pWnd == nullptr );
445 }
446 break;
447
448 case SID_EASY_CONDITIONAL_FORMAT_DIALOG:
449 {
450 if (pReqArgs != nullptr)
451 {
452 const SfxPoolItem* pFormat;
453 if (pReqArgs->HasItem( FN_PARAM_1, &pFormat))
454 {
455 sal_Int16 nFormat = static_cast<const SfxInt16Item*>(pFormat)->GetValue();
456 sal_uInt16 nId = sc::ConditionalFormatEasyDialogWrapper::GetChildWindowId();
457 SfxViewFrame& rViewFrame = pTabViewShell->GetViewFrame();
458 SfxChildWindow* pWindow = rViewFrame.GetChildWindow(nId);
459 GetViewData().GetDocument().SetEasyConditionalFormatDialogData(
460 std::make_unique<ScConditionMode>(
461 static_cast<ScConditionMode>(nFormat)));
462
463 pScMod->SetRefDialog( nId, pWindow == nullptr );
464 }
465 }
466 }
467 break;
468
469 case FID_CELL_FORMAT:
470 {
471 if ( pReqArgs != nullptr )
472 {
473 // set cell attribute without dialog:
474 SfxItemSet aEmptySet(SfxItemSet::makeFixedSfxItemSet<ATTR_PATTERN_START, ATTR_PATTERN_END>(*pReqArgs->GetPool()));
475
476 SfxItemSet aNewSet(SfxItemSet::makeFixedSfxItemSet<ATTR_PATTERN_START, ATTR_PATTERN_END>(*pReqArgs->GetPool()));
477
478 const SfxPoolItem* pAttr = nullptr;
479 sal_uInt16 nWhich = 0;
480
481 for ( nWhich=ATTR_PATTERN_START; nWhich<=ATTR_PATTERN_END; nWhich++ )
482 if ( pReqArgs->GetItemState( nWhich, true, &pAttr ) == SfxItemState::SET )
483 aNewSet.Put( *pAttr );
484
485 pTabViewShell->ApplyAttributes( aNewSet, aEmptySet );
486
487 rReq.Done();
488 }
489 else
490 {
491 pTabViewShell->ExecuteCellFormatDlg( rReq, u""_ustr );
492 }
493 }
494 break;
495
496 case SID_ENABLE_HYPHENATION:
497 pTabViewShell->ExecuteCellFormatDlg(rReq, u"alignment"_ustr);
498 break;
499
500 case SID_PROPERTY_PANEL_CELLTEXT_DLG:
501 pTabViewShell->ExecuteCellFormatDlg( rReq, u"font"_ustr );
502 break;
503
504 case SID_CELL_FORMAT_BORDER:
505 pTabViewShell->ExecuteCellFormatDlg( rReq, u"borders"_ustr );
506 break;
507
508 case SID_CHAR_DLG_EFFECT:
509 pTabViewShell->ExecuteCellFormatDlg( rReq, u"fonteffects"_ustr );
510 break;
511
512 case SID_OPENDLG_SOLVE:
513 {
514 sal_uInt16 nId = ScSolverDlgWrapper::GetChildWindowId();
515 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
516 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
517
518 pScMod->SetRefDialog( nId, pWnd == nullptr );
519 }
520 break;
521
522 case SID_OPENDLG_OPTSOLVER:
523 {
524 sal_uInt16 nId = ScOptSolverDlgWrapper::GetChildWindowId();
525 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
526 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
527
528 pScMod->SetRefDialog( nId, pWnd == nullptr );
529 }
530 break;
531
532 case SID_OPENDLG_TABOP:
533 {
534 sal_uInt16 nId = ScTabOpDlgWrapper::GetChildWindowId();
535 SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
536 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
537
538 pScMod->SetRefDialog( nId, pWnd == nullptr );
539 }
540 break;
541
542 case SID_SCENARIOS:
543 {
544 ScDocument& rDoc = GetViewData().GetDocument();
545 ScMarkData& rMark = GetViewData().GetMarkData();
546 SCTAB nTab = GetViewData().GetTabNo();
547
548 if ( rDoc.IsScenario(nTab) )
549 {
550 rMark.MarkToMulti();
551 if ( rMark.IsMultiMarked() )
552 {
553
554 bool bExtend = rReq.IsAPI();
555 if (!bExtend)
556 {
557 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
558 VclMessageType::Question, VclButtonsType::YesNo,
559 ScResId(STR_UPDATE_SCENARIO)));
560 xQueryBox->set_default_response(RET_YES);
561 bExtend = xQueryBox->run() == RET_YES;
562 }
563
564 if (bExtend)
565 {
566 pTabViewShell->ExtendScenario();
567 rReq.Done();
568 }
569 }
570 else if( ! rReq.IsAPI() )
571 {
572 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
573 VclMessageType::Warning, VclButtonsType::Ok,
574 ScResId(STR_NOAREASELECTED)));
575 xErrorBox->run();
576 }
577 }
578 else
579 {
580 rMark.MarkToMulti();
581 if ( rMark.IsMultiMarked() )
582 {
583 SCTAB i=1;
584 OUString aBaseName;
585 OUString aName;
586 Color aColor;
587 ScScenarioFlags nFlags;
588
589 OUString aTmp;
590 rDoc.GetName(nTab, aTmp);
591 aBaseName = aTmp + "_" + ScResId(STR_SCENARIO) + "_";
592
593 // first test, if the prefix is recognised as valid,
594 // else avoid only doubles
595 bool bPrefix = ScDocument::ValidTabName( aBaseName );
596 OSL_ENSURE(bPrefix, "invalid sheet name");
597
598 while ( rDoc.IsScenario(nTab+i) )
599 i++;
600
601 bool bValid;
602 SCTAB nDummy;
603 do
604 {
605 aName = aBaseName + OUString::number( i );
606 if (bPrefix)
607 bValid = rDoc.ValidNewTabName( aName );
608 else
609 bValid = !rDoc.GetTable( aName, nDummy );
610 ++i;
611 }
612 while ( !bValid && i <= MAXTAB + 2 );
613
614 if ( pReqArgs != nullptr )
615 {
616 OUString aArgName;
617 OUString aArgComment;
618 if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_SCENARIOS ) )
619 aArgName = pItem->GetValue();
620 if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_NEW_TABLENAME ) )
621 aArgComment = pItem->GetValue();
622
623 aColor = COL_LIGHTGRAY; // Default
624 nFlags = ScScenarioFlags::NONE; // not TwoWay
625
626 pTabViewShell->MakeScenario( aArgName, aArgComment, aColor, nFlags );
627 if( ! rReq.IsAPI() )
628 rReq.Done();
629 }
630 else
631 {
632 bool bSheetProtected = rDoc.IsTabProtected(nTab);
633 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
634
635 ScopedVclPtr<AbstractScNewScenarioDlg> pNewDlg(pFact->CreateScNewScenarioDlg(pTabViewShell->GetFrameWeld(), aName, false, bSheetProtected));
636 if ( pNewDlg->Execute() == RET_OK )
637 {
638 OUString aComment;
639 pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags );
640 pTabViewShell->MakeScenario( aName, aComment, aColor, nFlags );
641
642 rReq.AppendItem( SfxStringItem( SID_SCENARIOS, aName ) );
643 rReq.AppendItem( SfxStringItem( SID_NEW_TABLENAME, aComment ) );
644 rReq.Done();
645 }
646 }
647 }
648 else if( ! rReq.IsAPI() )
649 {
650 pTabViewShell->ErrorMessage(STR_ERR_NEWSCENARIO);
651 }
652 }
653 }
654 break;
655
656 case SID_SELECTALL:
657 {
658 SCTAB nTab = GetViewData().GetTabNo();
659 SCCOL nStartCol = GetViewData().GetCurX();
660 SCROW nStartRow = GetViewData().GetCurY();
661 SCCOL nEndCol = nStartCol;
662 SCROW nEndRow = nStartRow;
663 bool bCanMark = false;
664
665 ScMarkData& rMarkdata = GetViewData().GetMarkData();
666 const bool bSelectFirst(officecfg::Office::Calc::Input::SelectRangeBeforeAll::get());
667
668 if (bSelectFirst && !rMarkdata.IsMarked())
669 {
670 const ScDocument& rDoc = GetViewData().GetDocument();
671 rDoc.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, false );
672 bCanMark = nStartCol != nEndCol || nStartRow != nEndRow;
673 }
674
675 if (bCanMark)
676 {
677 const ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab);
678 pTabViewShell->MarkRange(aRange, false);
679 }
680 else
681 pTabViewShell->SelectAll();
682
683 rReq.Done();
684 }
685 break;
686
687 case FID_ROW_HEIGHT:
688 {
689 const SfxPoolItem* pRow;
690 const SfxUInt16Item* pHeight;
691 sal_uInt16 nHeight;
692
693 if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) &&
694 pReqArgs->HasItem( FN_PARAM_1, &pRow ) )
695 {
696 std::vector<sc::ColRowSpan> aRanges;
697 SCCOLROW nRow = static_cast<const SfxInt32Item*>(pRow)->GetValue() - 1;
698 nHeight = pHeight->GetValue();
699 ScMarkData& rMark = GetViewData().GetMarkData();
700
701 if ( rMark.IsRowMarked( static_cast<SCROW>(nRow) ) )
702 {
703 aRanges = rMark.GetMarkedRowSpans();
704 }
705 else
706 {
707 aRanges.emplace_back(nRow, nRow);
708 }
709
710 pTabViewShell->SetWidthOrHeight(false, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nHeight, o3tl::Length::mm100));
711 }
712 else if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) )
713 {
714 nHeight = pHeight->GetValue();
715
716 // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
717 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT,
718 o3tl::toTwips(nHeight, o3tl::Length::mm100));
719 if( ! rReq.IsAPI() )
720 rReq.Done();
721 }
722 else
723 {
724 ScViewData& rData = GetViewData();
725 FieldUnit eMetric = pScMod->GetMetric();
726 sal_uInt16 nCurHeight = rData.GetDocument().
727 GetRowHeight( rData.GetCurY(),
728 rData.GetTabNo() );
729 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
730 VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
731 pTabViewShell->GetFrameWeld(), u"RowHeightDialog"_ustr, nCurHeight,
732 rData.GetDocument().GetSheetOptimalMinRowHeight(rData.GetTabNo()),
733 eMetric, 2, MAX_ROW_HEIGHT));
734
735 pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
736 if (nResult == RET_OK)
737 {
738 SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_ROW_HEIGHT);
739 tools::Long nVal = pDlg->GetInputValue();
740 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
741
742 // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
743 pRequest.AppendItem( SfxUInt16Item( FID_ROW_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
744 pRequest.Done();
745 }
746 pDlg->disposeOnce();
747 });
748 }
749 }
750 break;
751
752 case FID_ROW_OPT_HEIGHT:
753 {
754 if ( pReqArgs )
755 {
756 const SfxUInt16Item& rUInt16Item = pReqArgs->Get( FID_ROW_OPT_HEIGHT );
757
758 // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
759 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL,
760 o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
761 ScGlobal::nLastRowHeightExtra = rUInt16Item.GetValue();
762
763 if( ! rReq.IsAPI() )
764 rReq.Done();
765 }
766 else
767 {
768 FieldUnit eMetric = pScMod->GetMetric();
769
770 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
771 VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
772 pTabViewShell->GetFrameWeld(), u"OptimalRowHeightDialog"_ustr,
773 ScGlobal::nLastRowHeightExtra, 0, eMetric, 2, MAX_EXTRA_HEIGHT));
774
775 pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
776 if ( nResult == RET_OK )
777 {
778 SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_ROW_OPT_HEIGHT);
779 tools::Long nVal = pDlg->GetInputValue();
780 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
781 ScGlobal::nLastRowHeightExtra = nVal;
782
783 // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
784 pRequest.AppendItem( SfxUInt16Item( FID_ROW_OPT_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
785 pRequest.Done();
786 }
787 pDlg->disposeOnce();
788 });
789 }
790 }
791 break;
792
793 case FID_COL_WIDTH:
794 {
795 const SfxPoolItem* pColumn;
796 const SfxUInt16Item* pWidth;
797 sal_uInt16 nWidth;
798
799 if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) &&
800 pReqArgs->HasItem( FN_PARAM_1, &pColumn ) )
801 {
802 std::vector<sc::ColRowSpan> aRanges;
803 SCCOLROW nColumn = static_cast<const SfxUInt16Item*>(pColumn)->GetValue() - 1;
804 nWidth = pWidth->GetValue();
805 ScMarkData& rMark = GetViewData().GetMarkData();
806
807 if ( rMark.IsColumnMarked( static_cast<SCCOL>(nColumn) ) )
808 {
809 aRanges = rMark.GetMarkedColSpans();
810 }
811 else
812 {
813 aRanges.emplace_back(nColumn, nColumn);
814 }
815
816 pTabViewShell->SetWidthOrHeight(true, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nWidth, o3tl::Length::mm100));
817 }
818 else if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) )
819 {
820 nWidth = pWidth->GetValue();
821
822 // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
823 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT,
824 o3tl::toTwips(nWidth, o3tl::Length::mm100));
825 if( ! rReq.IsAPI() )
826 rReq.Done();
827 }
828 else
829 {
830 FieldUnit eMetric = pScMod->GetMetric();
831 ScViewData& rData = GetViewData();
832 sal_uInt16 nCurHeight = rData.GetDocument().
833 GetColWidth( rData.GetCurX(),
834 rData.GetTabNo() );
835 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
836 VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
837 pTabViewShell->GetFrameWeld(), u"ColWidthDialog"_ustr, nCurHeight,
838 STD_COL_WIDTH, eMetric, 2, MAX_COL_WIDTH));
839
840 pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
841 if ( nResult == RET_OK )
842 {
843 SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_COL_WIDTH);
844 tools::Long nVal = pDlg->GetInputValue();
845 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
846
847 // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
848 pRequest.AppendItem( SfxUInt16Item( FID_COL_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal))) );
849 pRequest.Done();
850 }
851 pDlg->disposeOnce();
852 });
853 }
854 }
855 break;
856
857 case FID_COL_OPT_WIDTH:
858 {
859 if ( pReqArgs )
860 {
861 const SfxUInt16Item& rUInt16Item = pReqArgs->Get( FID_COL_OPT_WIDTH );
862
863 // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
864 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL,
865 o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
866 ScGlobal::nLastColWidthExtra = rUInt16Item.GetValue();
867
868 if( ! rReq.IsAPI() )
869 rReq.Done();
870 }
871 else
872 {
873 FieldUnit eMetric = pScMod->GetMetric();
874
875 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
876 VclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
877 pTabViewShell->GetFrameWeld(), u"OptimalColWidthDialog"_ustr,
878 ScGlobal::nLastColWidthExtra, STD_EXTRA_WIDTH, eMetric, 2, MAX_EXTRA_WIDTH));
879
880 pDlg->StartExecuteAsync([pDlg, pTabViewShell](sal_Int32 nResult){
881 SfxRequest pRequest(pTabViewShell->GetViewFrame(), FID_COL_OPT_WIDTH);
882 if ( nResult == RET_OK )
883 {
884 tools::Long nVal = pDlg->GetInputValue();
885 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
886 ScGlobal::nLastColWidthExtra = nVal;
887
888 // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
889 pRequest.AppendItem( SfxUInt16Item( FID_COL_OPT_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
890 pRequest.Done();
891 }
892 pDlg->disposeOnce();
893 });
894 }
895 }
896 break;
897
898 case FID_COL_OPT_DIRECT:
899 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH );
900 rReq.Done();
901 break;
902
903 case FID_ROW_HIDE:
904 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, 0 );
905 rReq.Done();
906 break;
907 case FID_ROW_SHOW:
908 pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_SHOW, 0 );
909 rReq.Done();
910 break;
911 case FID_COL_HIDE:
912 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, 0 );
913 rReq.Done();
914 break;
915 case FID_COL_SHOW:
916 pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_SHOW, 0 );
917 rReq.Done();
918 break;
919
920 case SID_CELL_FORMAT_RESET:
921 {
922 pTabViewShell->DeleteContents( InsertDeleteFlags::HARDATTR | InsertDeleteFlags::EDITATTR );
923 rReq.Done();
924 }
925 break;
926
927 case FID_MERGE_ON:
928 case FID_MERGE_OFF:
929 case FID_MERGE_TOGGLE:
930 {
931 if ( !GetViewData().GetDocument().GetChangeTrack() )
932 {
933 // test whether to merge or to split
934 bool bMerge = false;
935 bool bCenter = false;
936 switch( nSlot )
937 {
938 case FID_MERGE_ON:
939 bMerge = true;
940 break;
941 case FID_MERGE_OFF:
942 bMerge = false;
943 break;
944 case FID_MERGE_TOGGLE:
945 {
946 bCenter = true;
947 std::unique_ptr<SfxPoolItem> pItem;
948 if( rBindings.QueryState( nSlot, pItem ) >= SfxItemState::DEFAULT )
949 bMerge = !static_cast< SfxBoolItem* >( pItem.get() )->GetValue();
950 }
951 break;
952 }
953
954 if( bMerge )
955 {
956 // merge - check if to move contents of covered cells
957 bool bMoveContents = false;
958 bool bApi = rReq.IsAPI();
959 const SfxPoolItem* pItem;
960 if ( pReqArgs &&
961 pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
962 {
963 assert(dynamic_cast<const SfxBoolItem*>( pItem) && "wrong item");
964 bMoveContents = static_cast<const SfxBoolItem*>(pItem)->GetValue();
965 }
966
967 pTabViewShell->MergeCells( bApi, bMoveContents, bCenter, nSlot );
968 }
969 else
970 {
971 // split cells
972 if (pTabViewShell->RemoveMerge())
973 {
974 rBindings.Invalidate( nSlot );
975 rReq.Done();
976 }
977 }
978 break;
979 }
980 }
981 break;
982
983 case SID_AUTOFORMAT:
984 {
985 weld::Window* pDlgParent = pTabViewShell->GetFrameWeld();
986 SCCOL nStartCol;
987 SCROW nStartRow;
988 SCTAB nStartTab;
989 SCCOL nEndCol;
990 SCROW nEndRow;
991 SCTAB nEndTab;
992
993 const ScMarkData& rMark = GetViewData().GetMarkData();
994 if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
995 pTabViewShell->MarkDataArea();
996
997 GetViewData().GetSimpleArea( nStartCol,nStartRow,nStartTab,
998 nEndCol,nEndRow,nEndTab );
999
1000 if ( ( std::abs(nEndCol-nStartCol) > 1 )
1001 && ( std::abs(nEndRow-nStartRow) > 1 ) )
1002 {
1003 if ( pReqArgs )
1004 {
1005 const SfxStringItem& rNameItem = pReqArgs->Get( SID_AUTOFORMAT );
1006 ScAutoFormat* pFormat = ScGlobal::GetOrCreateAutoFormat();
1007 ScAutoFormat::const_iterator it = pFormat->find(rNameItem.GetValue());
1008 ScAutoFormat::const_iterator itBeg = pFormat->begin();
1009 size_t nIndex = std::distance(itBeg, it);
1010
1011 pTabViewShell->AutoFormat( nIndex );
1012
1013 if( ! rReq.IsAPI() )
1014 rReq.Done();
1015 }
1016 else
1017 {
1018 ScGlobal::ClearAutoFormat();
1019 std::unique_ptr<ScAutoFormatData> pNewEntry(pTabViewShell->CreateAutoFormatData());
1020 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
1021
1022 ScopedVclPtr<AbstractScAutoFormatDlg> pDlg(pFact->CreateScAutoFormatDlg(pDlgParent, ScGlobal::GetOrCreateAutoFormat(), pNewEntry.get(), GetViewData()));
1023
1024 if ( pDlg->Execute() == RET_OK )
1025 {
1026 ScEditableTester aTester( pTabViewShell );
1027 if ( !aTester.IsEditable() )
1028 {
1029 pTabViewShell->ErrorMessage(aTester.GetMessageId());
1030 }
1031 else
1032 {
1033 pTabViewShell->AutoFormat( pDlg->GetIndex() );
1034
1035 rReq.AppendItem( SfxStringItem( SID_AUTOFORMAT, pDlg->GetCurrFormatName() ) );
1036 rReq.Done();
1037 }
1038 }
1039 }
1040 }
1041 else
1042 {
1043 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDlgParent,
1044 VclMessageType::Warning, VclButtonsType::Ok,
1045 ScResId(STR_INVALID_AFAREA)));
1046 xErrorBox->run();
1047 }
1048 }
1049 break;
1050
1051 case SID_CANCEL:
1052 {
1053 if (GetViewData().HasEditView(GetViewData().GetActivePart()))
1054 pScMod->InputCancelHandler();
1055 else if (pTabViewShell->HasPaintBrush())
1056 pTabViewShell->ResetBrushDocument(); // abort format paint brush
1057 else if (pTabViewShell->HasHintWindow())
1058 pTabViewShell->RemoveHintWindow();
1059 else if( ScViewUtil::IsFullScreen( *pTabViewShell ) )
1060 ScViewUtil::SetFullScreen( *pTabViewShell, false );
1061 else
1062 {
1063 // TODO/LATER: when is this code executed?
1064 pTabViewShell->Escape();
1065 }
1066 }
1067 break;
1068
1069 case SID_ACCEPT_FORMULA:
1070 {
1071 if (GetViewData().HasEditView(GetViewData().GetActivePart()))
1072 pScMod->InputEnterHandler();
1073 }
1074 break;
1075
1076 case SID_START_FORMULA:
1077 {
1078 ScInputHandler* pInputHandler = pScMod->GetInputHdl();
1079 if (pInputHandler && pInputHandler->GetInputWindow())
1080 pInputHandler->GetInputWindow()->StartFormula();
1081 }
1082 break;
1083
1084 case SID_DATA_SELECT:
1085 pTabViewShell->StartDataSelect();
1086 break;
1087
1088 case SID_DETECTIVE_FILLMODE:
1089 {
1090 bool bOldMode = pTabViewShell->IsAuditShell();
1091 pTabViewShell->SetAuditShell( !bOldMode );
1092 pTabViewShell->Invalidate( nSlot );
1093 }
1094 break;
1095
1096 case FID_INPUTLINE_STATUS:
1097 OSL_FAIL("Execute from InputLine status");
1098 break;
1099
1100 case SID_STATUS_DOCPOS:
1101 // Launch navigator.
1102 GetViewData().GetDispatcher().Execute(
1103 SID_NAVIGATOR, SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
1104 break;
1105
1106 case SID_MARKAREA:
1107 // called from Basic at the hidden view to select a range in the visible view
1108 OSL_FAIL("old slot SID_MARKAREA");
1109 break;
1110
1111 case FID_MOVE_KEEP_INSERT_MODE:
1112 {
1113 const SfxBoolItem* pEnabledArg = rReq.GetArg<SfxBoolItem>(FID_MOVE_KEEP_INSERT_MODE);
1114 if (!pEnabledArg) {
1115 SAL_WARN("sfx.appl", "FID_MOVE_KEEP_INSERT_MODE: must specify if you would like this to be enabled");
1116 break;
1117 }
1118
1119 ScInputOptions aInputOptions = pScMod->GetInputOptions();
1120
1121 aInputOptions.SetMoveKeepEdit(pEnabledArg->GetValue());
1122 pScMod->SetInputOptions(aInputOptions);
1123
1124 if (comphelper::LibreOfficeKit::isActive())
1125 pTabViewShell->SetMoveKeepEdit(pEnabledArg->GetValue());
1126
1127 break;
1128 }
1129
1130 default:
1131 OSL_FAIL("ScCellShell::Execute: unknown slot");
1132 break;
1133 }
1134 }
1135
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1137