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