tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / app / inputwin.cxx
blobb70a2d21aa90bd6e9c01e22db98012ddc1d113b2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <algorithm>
22 #include <string_view>
24 #include <editeng/eeitem.hxx>
26 #include <sfx2/app.hxx>
27 #include <editeng/adjustitem.hxx>
28 #include <editeng/editview.hxx>
29 #include <editeng/editstat.hxx>
30 #include <editeng/lspcitem.hxx>
31 #include <editeng/fhgtitem.hxx>
32 #include <editeng/wghtitem.hxx>
33 #include <editeng/postitem.hxx>
34 #include <editeng/langitem.hxx>
35 #include <sfx2/bindings.hxx>
36 #include <sfx2/viewfrm.hxx>
37 #include <sfx2/dispatch.hxx>
38 #include <sfx2/event.hxx>
39 #include <editeng/scriptspaceitem.hxx>
40 #include <vcl/commandevent.hxx>
41 #include <vcl/cursor.hxx>
42 #include <vcl/help.hxx>
43 #include <vcl/settings.hxx>
44 #include <svl/stritem.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/weldutils.hxx>
47 #include <unotools/charclass.hxx>
49 #include <inputwin.hxx>
50 #include <scmod.hxx>
51 #include <global.hxx>
52 #include <scresid.hxx>
53 #include <strings.hrc>
54 #include <globstr.hrc>
55 #include <bitmaps.hlst>
56 #include <reffact.hxx>
57 #include <editutil.hxx>
58 #include <inputhdl.hxx>
59 #include <tabvwsh.hxx>
60 #include <document.hxx>
61 #include <docsh.hxx>
62 #include <appoptio.hxx>
63 #include <rangenam.hxx>
64 #include <rangeutl.hxx>
65 #include <docfunc.hxx>
66 #include <funcdesc.hxx>
67 #include <editeng/fontitem.hxx>
68 #include <AccessibleEditObject.hxx>
69 #include <AccessibleText.hxx>
70 #include <comphelper/lok.hxx>
71 #include <comphelper/string.hxx>
72 #include <com/sun/star/frame/XLayoutManager.hpp>
73 #include <helpids.h>
74 #include <output.hxx>
76 namespace com::sun::star::accessibility { class XAccessible; }
78 const tools::Long THESIZE = 1000000; // Should be more than enough!
79 const tools::Long INPUTLINE_INSET_MARGIN = 2; // Space between border and interior widgets of input line
80 const tools::Long LEFT_OFFSET = 5; // Left offset of input line
81 //TODO const long BUTTON_OFFSET = 2; // Space between input line and button to expand/collapse
82 const tools::Long INPUTWIN_MULTILINES = 6; // Initial number of lines within multiline dropdown
83 const tools::Long TOOLBOX_WINDOW_HEIGHT = 22; // Height of toolbox window in pixels - TODO: The same on all systems?
84 const tools::Long POSITION_COMBOBOX_WIDTH = 18; // Width of position combobox in characters
85 const int RESIZE_HOTSPOT_HEIGHT = 4;
87 using com::sun::star::uno::Reference;
88 using com::sun::star::uno::UNO_QUERY;
90 using com::sun::star::frame::XLayoutManager;
91 using com::sun::star::beans::XPropertySet;
93 namespace {
95 constexpr ToolBoxItemId SID_INPUT_FUNCTION (SC_VIEW_START + 47);
96 constexpr ToolBoxItemId SID_INPUT_SUM (SC_VIEW_START + 48);
97 constexpr ToolBoxItemId SID_INPUT_EQUAL (SC_VIEW_START + 49);
98 constexpr ToolBoxItemId SID_INPUT_CANCEL (SC_VIEW_START + 50);
99 constexpr ToolBoxItemId SID_INPUT_OK (SC_VIEW_START + 51);
101 enum ScNameInputType
103 SC_NAME_INPUT_CELL,
104 SC_NAME_INPUT_RANGE,
105 SC_NAME_INPUT_NAMEDRANGE_LOCAL,
106 SC_NAME_INPUT_NAMEDRANGE_GLOBAL,
107 SC_NAME_INPUT_DATABASE,
108 SC_NAME_INPUT_ROW,
109 SC_NAME_INPUT_SHEET,
110 SC_NAME_INPUT_DEFINE,
111 SC_NAME_INPUT_BAD_NAME,
112 SC_NAME_INPUT_BAD_SELECTION,
113 SC_MANAGE_NAMES
118 SFX_IMPL_CHILDWINDOW_WITHID(ScInputWindowWrapper,FID_INPUTLINE_STATUS)
120 ScInputWindowWrapper::ScInputWindowWrapper( vcl::Window* pParentP,
121 sal_uInt16 nId,
122 SfxBindings* pBindings,
123 SfxChildWinInfo* /* pInfo */ )
124 : SfxChildWindow( pParentP, nId )
126 VclPtr<ScInputWindow> pWin = VclPtr<ScInputWindow>::Create( pParentP, pBindings );
127 SetWindow( pWin );
129 pWin->Show();
131 pWin->SetSizePixel( pWin->CalcWindowSizePixel() );
133 SetAlignment(SfxChildAlignment::LOWESTTOP);
134 pBindings->Invalidate( FID_TOGGLEINPUTLINE );
138 * GetInfo is disposed of if there's a SFX_IMPL_TOOLBOX!
140 SfxChildWinInfo ScInputWindowWrapper::GetInfo() const
142 SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
143 return aInfo;
147 static VclPtr<ScInputBarGroup> lcl_chooseRuntimeImpl( vcl::Window* pParent, const SfxBindings* pBind )
149 ScTabViewShell* pViewSh = nullptr;
150 SfxDispatcher* pDisp = pBind->GetDispatcher();
151 if ( pDisp )
153 SfxViewFrame* pViewFrm = pDisp->GetFrame();
154 if ( pViewFrm )
155 pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
158 return VclPtr<ScInputBarGroup>::Create( pParent, pViewSh );
161 ScInputWindow::ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind ) :
162 // With WB_CLIPCHILDREN otherwise we get flickering
163 ToolBox ( pParent, WinBits(WB_CLIPCHILDREN | WB_BORDER | WB_NOSHADOW) ),
164 aWndPos ( !comphelper::LibreOfficeKit::isActive() ? VclPtr<ScPosWnd>::Create(this) : nullptr ),
165 mxTextWindow ( lcl_chooseRuntimeImpl( this, pBind ) ),
166 pInputHdl ( nullptr ),
167 mpViewShell ( nullptr ),
168 mnMaxY (0),
169 mnStandardItemHeight(0),
170 bIsOkCancelMode ( false ),
171 bInResize ( false )
173 // #i73615# don't rely on SfxViewShell::Current while constructing the input line
174 // (also for GetInputHdl below)
175 ScTabViewShell* pViewSh = nullptr;
176 SfxDispatcher* pDisp = pBind->GetDispatcher();
177 if ( pDisp )
179 SfxViewFrame* pViewFrm = pDisp->GetFrame();
180 if ( pViewFrm )
181 pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
183 OSL_ENSURE( pViewSh, "no view shell for input window" );
185 mpViewShell = pViewSh;
187 // Position window, 3 buttons, input window
188 if (!comphelper::LibreOfficeKit::isActive())
190 InsertWindow (ToolBoxItemId(1), aWndPos.get(), ToolBoxItemBits::NONE, 0);
191 InsertSeparator (1);
192 InsertItem (SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION), ToolBoxItemBits::NONE, 2);
195 const bool bIsLOKMobilePhone = mpViewShell && mpViewShell->isLOKMobilePhone();
197 // sigma and equal buttons
198 if (!bIsLOKMobilePhone)
200 InsertItem (SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM), ToolBoxItemBits::DROPDOWN, 3);
201 InsertItem (SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL), ToolBoxItemBits::NONE, 4);
202 InsertItem (SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL), ToolBoxItemBits::NONE, 5);
203 InsertItem (SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK), ToolBoxItemBits::NONE, 6);
206 InsertWindow (ToolBoxItemId(7), mxTextWindow.get(), ToolBoxItemBits::NONE, 7);
207 SetDropdownClickHdl( LINK( this, ScInputWindow, DropdownClickHdl ));
209 if (!comphelper::LibreOfficeKit::isActive())
211 aWndPos ->SetQuickHelpText(ScResId(SCSTR_QHELP_POSWND));
212 aWndPos ->SetHelpId (HID_INSWIN_POS);
214 mxTextWindow->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
215 mxTextWindow->SetHelpId (HID_INSWIN_INPUT);
217 // No SetHelpText: the helptexts come from the Help
218 SetItemText (SID_INPUT_FUNCTION, ScResId(SCSTR_QHELP_BTNCALC));
219 SetHelpId (SID_INPUT_FUNCTION, HID_INSWIN_CALC);
222 // sigma and equal buttons
223 if (!bIsLOKMobilePhone)
225 SetHelpId (SID_INPUT_SUM, HID_INSWIN_SUMME);
226 SetHelpId (SID_INPUT_EQUAL, HID_INSWIN_FUNC);
227 SetHelpId (SID_INPUT_CANCEL, HID_INSWIN_CANCEL);
228 SetHelpId (SID_INPUT_OK, HID_INSWIN_OK);
230 if (!comphelper::LibreOfficeKit::isActive())
232 SetItemText ( SID_INPUT_SUM, ScResId( SCSTR_QHELP_BTNSUM ) );
233 SetItemText ( SID_INPUT_EQUAL, ScResId( SCSTR_QHELP_BTNEQUAL ) );
234 SetItemText ( SID_INPUT_CANCEL, ScResId( SCSTR_QHELP_BTNCANCEL ) );
235 SetItemText ( SID_INPUT_OK, ScResId( SCSTR_QHELP_BTNOK ) );
238 EnableItem( SID_INPUT_CANCEL, false );
239 EnableItem( SID_INPUT_OK, false );
241 HideItem( SID_INPUT_CANCEL );
242 HideItem( SID_INPUT_OK );
244 mnStandardItemHeight = GetItemRect(SID_INPUT_SUM).GetHeight();
247 SetHelpId( HID_SC_INPUTWIN ); // For the whole input row
249 if (!comphelper::LibreOfficeKit::isActive())
250 aWndPos ->Show();
251 mxTextWindow->Show();
253 pInputHdl = ScModule::get()->GetInputHdl( pViewSh, false ); // use own handler even if ref-handler is set
254 if (pInputHdl)
255 pInputHdl->SetInputWindow( this );
257 if (pInputHdl && !pInputHdl->GetFormString().isEmpty())
259 // Switch over while the Function AutoPilot is active
260 // -> show content of the Function AutoPilot again
261 // Also show selection (remember at the InputHdl)
262 mxTextWindow->SetTextString(pInputHdl->GetFormString(), true);
264 else if (pInputHdl && pInputHdl->IsInputMode())
266 // If the input row was hidden while editing (e.g. when editing a formula
267 // and then switching to another document or the help), display the text
268 // we just edited from the InputHandler
269 mxTextWindow->SetTextString(pInputHdl->GetEditString(), true); // Display text
270 if ( pInputHdl->IsTopMode() )
271 pInputHdl->SetMode( SC_INPUT_TABLE ); // Focus ends up at the bottom anyways
273 else if (pViewSh)
275 // Don't stop editing in LOK a remote user might be editing.
276 const bool bStopEditing = !comphelper::LibreOfficeKit::isActive();
277 pViewSh->UpdateInputHandler(true, bStopEditing); // Absolutely necessary update
280 SetToolbarLayoutMode( ToolBoxLayoutMode::Locked );
282 SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
285 ScInputWindow::~ScInputWindow()
287 disposeOnce();
290 void ScInputWindow::dispose()
292 bool bDown = !ScGlobal::oSysLocale; // after Clear?
294 // if any view's input handler has a pointer to this input window, reset it
295 // (may be several ones, #74522#)
296 // member pInputHdl is not used here
298 if ( !bDown )
300 SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
301 while ( pSh )
303 ScInputHandler* pHdl = static_cast<ScTabViewShell*>(pSh)->GetInputHandler();
304 if ( pHdl && pHdl->GetInputWindow() == this )
306 pHdl->SetInputWindow( nullptr );
307 pHdl->StopInputWinEngine( false ); // reset pTopView pointer
309 pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
313 if (comphelper::LibreOfficeKit::isActive())
315 if (GetLOKNotifier())
316 ReleaseLOKNotifier();
319 mxTextWindow.disposeAndClear();
320 aWndPos.disposeAndClear();
322 ToolBox::dispose();
325 void ScInputWindow::SetInputHandler( ScInputHandler* pNew )
327 // Is called in the Activate of the View ...
328 if ( pNew != pInputHdl )
330 // On Reload (last version) the pInputHdl is the InputHandler of the old, deleted
331 // ViewShell: so don't touch it here!
332 pInputHdl = pNew;
333 if (pInputHdl)
334 pInputHdl->SetInputWindow( this );
338 void ScInputWindow::Select()
340 ScModule* pScMod = ScModule::get();
341 ToolBox::Select();
343 ToolBoxItemId curItemId = GetCurItemId();
344 if (curItemId == SID_INPUT_FUNCTION)
346 //! new method at ScModule to query if function autopilot is open
347 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
348 if ( pViewFrm && ( comphelper::LibreOfficeKit::isActive() || !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) ) )
350 pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
351 SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
353 // The Toolbox will be disabled anyways, so we don't need to switch here,
354 // regardless whether it succeeded or not!
355 // SetOkCancelMode();
358 else if (curItemId == SID_INPUT_CANCEL)
360 pScMod->InputCancelHandler();
361 SetSumAssignMode();
363 else if (curItemId == SID_INPUT_OK)
365 pScMod->InputEnterHandler();
366 SetSumAssignMode();
367 mxTextWindow->Invalidate(); // Or else the Selection remains
369 else if (curItemId == SID_INPUT_SUM)
371 bool bRangeFinder = false;
372 bool bSubTotal = false;
373 AutoSum(bRangeFinder, bSubTotal, ocSum);
375 else if (curItemId == SID_INPUT_EQUAL)
377 StartFormula();
381 void ScInputWindow::StartFormula()
383 ScModule* pScMod = ScModule::get();
384 mxTextWindow->StartEditEngine();
385 if ( pScMod->IsEditMode() ) // Isn't if e.g. protected
387 mxTextWindow->StartEditEngine();
389 sal_Int32 nStartPos = 1;
390 sal_Int32 nEndPos = 1;
392 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
393 if ( pViewSh )
395 const OUString& rString = mxTextWindow->GetTextString();
396 const sal_Int32 nLen = rString.getLength();
398 ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
399 CellType eCellType = rDoc.GetCellType( pViewSh->GetViewData().GetCurPos() );
400 switch ( eCellType )
402 case CELLTYPE_VALUE:
404 nEndPos = nLen + 1;
405 mxTextWindow->SetTextString("=" + rString, true);
406 break;
408 case CELLTYPE_STRING:
409 case CELLTYPE_EDIT:
410 nStartPos = 0;
411 nEndPos = nLen;
412 break;
413 case CELLTYPE_FORMULA:
414 nEndPos = nLen;
415 break;
416 default:
417 mxTextWindow->SetTextString(u"="_ustr, true);
418 break;
422 EditView* pView = mxTextWindow->GetEditView();
423 if (pView)
425 sal_Int32 nStartPara = 0, nEndPara = 0;
426 if (comphelper::LibreOfficeKit::isActive())
428 TextGrabFocus();
429 if (pViewSh && !pViewSh->isLOKDesktop())
431 nStartPara = nEndPara = pView->getEditEngine().GetParagraphCount() ?
432 (pView->getEditEngine().GetParagraphCount() - 1) : 0;
433 nStartPos = nEndPos = pView->getEditEngine().GetTextLen(nStartPara);
436 pView->SetSelection(ESelection(nStartPara, nStartPos, nEndPara, nEndPos));
437 pScMod->InputChanged(pView);
438 SetOkCancelMode();
439 pView->SetEditEngineUpdateLayout(true);
444 void ScInputWindow::PixelInvalidate(const tools::Rectangle* pRectangle)
446 if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
447 return;
449 if (pRectangle)
451 tools::Rectangle aRect(*pRectangle);
452 aRect.Move(-GetOutOffXPixel(), -GetOutOffYPixel());
453 Window::PixelInvalidate(&aRect);
455 else
457 Window::PixelInvalidate(nullptr);
461 void ScInputWindow::SetSizePixel( const Size& rNewSize )
463 const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier();
464 if (pNotifier)
466 if (vcl::Window* pFrameWindowImpl = GetParent())
468 if (vcl::Window* pWorkWindow = pFrameWindowImpl->GetParent())
470 if (vcl::Window* pImplBorderWindow = pWorkWindow->GetParent())
472 Size aSize = pImplBorderWindow->GetSizePixel();
473 aSize.setWidth(rNewSize.getWidth());
474 pImplBorderWindow->SetSizePixel(aSize);
480 ToolBox::SetSizePixel(rNewSize);
483 void ScInputWindow::Resize()
485 ToolBox::Resize();
487 Size aStartSize = GetSizePixel();
488 Size aSize = aStartSize;
490 auto nLines = mxTextWindow->GetNumLines();
491 //(-10) to allow margin between sidebar and formulabar
492 tools::Long margin = (comphelper::LibreOfficeKit::isActive()) ? 10 : 0;
493 Size aTextWindowSize(aSize.Width() - mxTextWindow->GetPosPixel().X() - LEFT_OFFSET - margin,
494 mxTextWindow->GetPixelHeightForLines(nLines));
495 mxTextWindow->SetSizePixel(aTextWindowSize);
497 int nTopOffset = 0;
498 if (nLines > 1)
500 // Initially there is 1 line and the edit is vertically centered in the toolbar
501 // Later, if expanded then the vertical position of the edit will remain at
502 // that initial position, so when calculating the overall size of the expanded
503 // toolbar we have to include that initial offset in order to not make
504 // the edit overlap the RESIZE_HOTSPOT_HEIGHT area so that dragging to resize
505 // is still possible.
506 int nNormalHeight = mxTextWindow->GetPixelHeightForLines(1);
507 int nInitialTopMargin = (mnStandardItemHeight - nNormalHeight) / 2;
508 if (nInitialTopMargin > 0)
509 nTopOffset = nInitialTopMargin;
512 // add empty space of RESIZE_HOTSPOT_HEIGHT so resize is possible when hovering there
513 aSize.setHeight(CalcWindowSizePixel().Height() + RESIZE_HOTSPOT_HEIGHT + nTopOffset);
515 if (aStartSize != aSize)
516 SetSizePixel(aSize);
518 Invalidate();
521 void ScInputWindow::NotifyLOKClient()
523 if (comphelper::LibreOfficeKit::isActive() && !GetLOKNotifier() && mpViewShell)
524 SetLOKNotifier(mpViewShell);
527 void ScInputWindow::SetFuncString( const OUString& rString, bool bDoEdit )
529 //! new method at ScModule to query if function autopilot is open
530 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
531 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
532 mxTextWindow->StartEditEngine();
534 ScModule* pScMod = ScModule::get();
535 if ( !pScMod->IsEditMode() )
536 return;
538 if ( bDoEdit )
539 mxTextWindow->TextGrabFocus();
540 mxTextWindow->SetTextString(rString, true);
541 EditView* pView = mxTextWindow->GetEditView();
542 if (!pView)
543 return;
545 sal_Int32 nLen = rString.getLength();
547 if ( nLen > 0 )
549 nLen--;
550 pView->SetSelection(ESelection(0, nLen));
553 pScMod->InputChanged(pView);
554 if ( bDoEdit )
555 SetOkCancelMode(); // Not the case if immediately followed by Enter/Cancel
557 pView->SetEditEngineUpdateLayout(true);
560 void ScInputWindow::SetPosString( const OUString& rStr )
562 if (!comphelper::LibreOfficeKit::isActive())
563 aWndPos->SetPos( rStr );
566 void ScInputWindow::SetTextString( const OUString& rString, bool bKitUpdate )
568 if (rString.getLength() <= 32767)
569 mxTextWindow->SetTextString(rString, bKitUpdate);
570 else
571 mxTextWindow->SetTextString(rString.copy(0, 32767), bKitUpdate);
574 void ScInputWindow::SetOkCancelMode()
576 //! new method at ScModule to query if function autopilot is open
577 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
578 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
580 if (bIsOkCancelMode)
581 return;
583 EnableItem ( SID_INPUT_SUM, false );
584 EnableItem ( SID_INPUT_EQUAL, false );
585 HideItem ( SID_INPUT_SUM );
586 HideItem ( SID_INPUT_EQUAL );
588 ShowItem ( SID_INPUT_CANCEL, true );
589 ShowItem ( SID_INPUT_OK, true );
590 EnableItem ( SID_INPUT_CANCEL, true );
591 EnableItem ( SID_INPUT_OK, true );
593 bIsOkCancelMode = true;
596 void ScInputWindow::SetSumAssignMode()
598 //! new method at ScModule to query if function autopilot is open
599 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
600 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
602 if (!bIsOkCancelMode)
603 return;
605 EnableItem ( SID_INPUT_CANCEL, false );
606 EnableItem ( SID_INPUT_OK, false );
607 HideItem ( SID_INPUT_CANCEL );
608 HideItem ( SID_INPUT_OK );
610 ShowItem ( SID_INPUT_SUM, true );
611 ShowItem ( SID_INPUT_EQUAL, true );
612 EnableItem ( SID_INPUT_SUM, true );
613 EnableItem ( SID_INPUT_EQUAL, true );
615 bIsOkCancelMode = false;
617 SetFormulaMode(false); // No editing -> no formula
620 void ScInputWindow::SetFormulaMode( bool bSet )
622 if (!comphelper::LibreOfficeKit::isActive())
623 aWndPos->SetFormulaMode(bSet);
624 mxTextWindow->SetFormulaMode(bSet);
627 bool ScInputWindow::IsInputActive()
629 return mxTextWindow->IsInputActive();
632 EditView* ScInputWindow::GetEditView()
634 return mxTextWindow->GetEditView();
637 vcl::Window* ScInputWindow::GetEditWindow()
639 return mxTextWindow;
642 Point ScInputWindow::GetCursorScreenPixelPos(bool bBelow)
644 return mxTextWindow->GetCursorScreenPixelPos(bBelow);
647 void ScInputWindow::MakeDialogEditView()
649 mxTextWindow->MakeDialogEditView();
652 void ScInputWindow::StopEditEngine( bool bAll )
654 mxTextWindow->StopEditEngine( bAll );
657 void ScInputWindow::TextGrabFocus()
659 mxTextWindow->TextGrabFocus();
662 void ScInputWindow::TextInvalidate()
664 mxTextWindow->Invalidate();
667 void ScInputWindow::SwitchToTextWin()
669 // used for shift-ctrl-F2
671 mxTextWindow->StartEditEngine();
672 if (ScModule::get()->IsEditMode())
674 mxTextWindow->TextGrabFocus();
675 EditView* pView = mxTextWindow->GetEditView();
676 if (pView)
678 pView->SetSelection(ESelection::AtEnd()); // set cursor to end of text
683 void ScInputWindow::PosGrabFocus()
685 if (!comphelper::LibreOfficeKit::isActive())
686 aWndPos->GrabFocus();
689 void ScInputWindow::EnableButtons( bool bEnable )
691 // when enabling buttons, always also enable the input window itself
692 if ( bEnable && !IsEnabled() )
693 Enable();
695 EnableItem( SID_INPUT_FUNCTION, bEnable );
696 EnableItem( bIsOkCancelMode ? SID_INPUT_CANCEL : SID_INPUT_SUM, bEnable );
697 EnableItem( bIsOkCancelMode ? SID_INPUT_OK : SID_INPUT_EQUAL, bEnable );
698 // Invalidate();
701 void ScInputWindow::NumLinesChanged()
703 mxTextWindow->NumLinesChanged();
706 void ScInputWindow::StateChanged( StateChangedType nType )
708 ToolBox::StateChanged( nType );
710 if ( nType == StateChangedType::InitShow ) Resize();
713 void ScInputWindow::DataChanged( const DataChangedEvent& rDCEvt )
715 if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
717 // update item images
718 SetItemImage(SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION));
719 if ( bIsOkCancelMode )
721 SetItemImage(SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL));
722 SetItemImage(SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK));
724 else
726 SetItemImage(SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM));
727 SetItemImage(SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL));
731 ToolBox::DataChanged( rDCEvt );
734 bool ScInputWindow::IsPointerAtResizePos()
736 return GetOutputSizePixel().Height() - GetPointerPosPixel().Y() <= RESIZE_HOTSPOT_HEIGHT;
739 void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
741 Point aPosPixel = GetPointerPosPixel();
743 ScInputBarGroup* pGroupBar = mxTextWindow.get();
745 if (bInResize || IsPointerAtResizePos())
746 SetPointer(PointerStyle::WindowSSize);
747 else
748 SetPointer(PointerStyle::Arrow);
750 if (bInResize)
752 // detect direction
753 tools::Long nResizeThreshold = tools::Long(TOOLBOX_WINDOW_HEIGHT * 0.7);
754 bool bResetPointerPos = false;
756 // Detect attempt to expand toolbar too much
757 if (aPosPixel.Y() >= mnMaxY)
759 bResetPointerPos = true;
760 aPosPixel.setY( mnMaxY );
761 } // or expanding down
762 else if (GetOutputSizePixel().Height() - aPosPixel.Y() < -nResizeThreshold)
764 pGroupBar->IncrementVerticalSize();
765 bResetPointerPos = true;
766 } // or shrinking up
767 else if ((GetOutputSizePixel().Height() - aPosPixel.Y()) > nResizeThreshold)
769 bResetPointerPos = true;
770 pGroupBar->DecrementVerticalSize();
773 if (bResetPointerPos)
775 aPosPixel.setY( GetOutputSizePixel().Height() );
776 SetPointerPosPixel(aPosPixel);
780 ToolBox::MouseMove(rMEvt);
783 void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
785 if (rMEvt.IsLeft())
787 if (IsPointerAtResizePos())
789 // Don't leave the mouse pointer leave *this* window
790 CaptureMouse();
791 bInResize = true;
793 // find the height of the gridwin, we don't want to be
794 // able to expand the toolbar too far so we need to
795 // calculate an upper limit
796 // I'd prefer to leave at least a single column header and a
797 // row but I don't know how to get that value in pixels.
798 // Use TOOLBOX_WINDOW_HEIGHT for the moment
799 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
801 mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP)
802 + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TOOLBOX_WINDOW_HEIGHT;
807 ToolBox::MouseButtonDown( rMEvt );
809 void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )
811 ReleaseMouse();
812 if ( rMEvt.IsLeft() )
814 bInResize = false;
815 mnMaxY = 0;
818 ToolBox::MouseButtonUp( rMEvt );
821 void ScInputWindow::AutoSum( bool& bRangeFinder, bool& bSubTotal, OpCode eCode )
823 ScModule* pScMod = ScModule::get();
824 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
825 if ( !pViewSh )
826 return;
828 const OUString aFormula = pViewSh->DoAutoSum(bRangeFinder, bSubTotal, eCode);
829 if ( aFormula.isEmpty() )
830 return;
832 SetFuncString( aFormula );
833 const sal_Int32 aOpen = aFormula.indexOf('(');
834 const sal_Int32 aLen = aFormula.getLength();
835 if (!(bRangeFinder && pScMod->IsEditMode()))
836 return;
838 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
839 if ( !pHdl )
840 return;
842 pHdl->InitRangeFinder( aFormula );
844 //! SetSelection at the InputHandler?
845 //! Set bSelIsRef?
846 if ( aOpen != -1 && aLen > aOpen )
848 ESelection aSel( 0, aOpen + (bSubTotal ? 3 : 1), 0, aLen-1 );
849 EditView* pTableView = pHdl->GetTableView();
850 if ( pTableView )
851 pTableView->SetSelection( aSel );
852 EditView* pTopView = pHdl->GetTopView();
853 if ( pTopView )
854 pTopView->SetSelection( aSel );
858 ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
859 : InterimItemWindow(pParent, u"modules/scalc/ui/inputbar.ui"_ustr, u"InputBar"_ustr, true, reinterpret_cast<sal_uInt64>(pViewSh))
860 , mxBackground(m_xBuilder->weld_container(u"background"_ustr))
861 , mxTextWndGroup(new ScTextWndGroup(*this, pViewSh))
862 , mxButtonUp(m_xBuilder->weld_button(u"up"_ustr))
863 , mxButtonDown(m_xBuilder->weld_button(u"down"_ustr))
865 InitControlBase(m_xContainer.get());
867 SetPaintTransparent(false);
868 SetBackgrounds();
870 mxButtonUp->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
871 mxButtonDown->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
873 if (!comphelper::LibreOfficeKit::isActive())
875 mxButtonUp->set_tooltip_text(ScResId( SCSTR_QHELP_COLLAPSE_FORMULA));
876 mxButtonDown->set_tooltip_text(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
879 int nHeight = mxTextWndGroup->GetPixelHeightForLines(1);
880 mxButtonUp->set_size_request(-1, nHeight);
881 mxButtonDown->set_size_request(-1, nHeight);
883 // disable the multiline toggle on the mobile phones
884 const SfxViewShell* pViewShell = SfxViewShell::Current();
885 if (!comphelper::LibreOfficeKit::isActive() || !(pViewShell && pViewShell->isLOKMobilePhone()))
886 mxButtonDown->show();
888 // tdf#154042 Use an initial height of one row so the Toolbar positions
889 // this in the same place regardless of how many rows it eventually shows
890 Size aSize(GetSizePixel().Width(), nHeight);
891 SetSizePixel(aSize);
894 void ScInputBarGroup::SetBackgrounds()
896 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
897 SetBackground(rStyleSettings.GetFaceColor());
898 // match to bg used in ScTextWnd::SetDrawingArea to the margin area is drawn with the
899 // same desired bg
900 mxBackground->set_background(rStyleSettings.GetFieldColor());
903 void ScInputBarGroup::DataChanged(const DataChangedEvent& rDCEvt)
905 InterimItemWindow::DataChanged(rDCEvt);
906 if ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
908 SetBackgrounds();
909 Invalidate();
913 Point ScInputBarGroup::GetCursorScreenPixelPos(bool bBelow)
915 return mxTextWndGroup->GetCursorScreenPixelPos(bBelow);
918 ScInputBarGroup::~ScInputBarGroup()
920 disposeOnce();
923 void ScInputBarGroup::dispose()
925 mxTextWndGroup.reset();
926 mxButtonUp.reset();
927 mxButtonDown.reset();
928 mxBackground.reset();
929 InterimItemWindow::dispose();
932 void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
934 mxTextWndGroup->InsertAccessibleTextData(rTextData);
937 void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
939 mxTextWndGroup->RemoveAccessibleTextData(rTextData);
942 const OUString& ScInputBarGroup::GetTextString() const
944 return mxTextWndGroup->GetTextString();
947 void ScInputBarGroup::SetTextString(const OUString& rString, bool bKitUpdate)
949 mxTextWndGroup->SetTextString(rString, bKitUpdate);
952 void ScInputBarGroup::Resize()
954 mxTextWndGroup->SetScrollPolicy();
955 InterimItemWindow::Resize();
958 void ScInputBarGroup::StopEditEngine(bool bAll)
960 mxTextWndGroup->StopEditEngine(bAll);
963 void ScInputBarGroup::StartEditEngine()
965 mxTextWndGroup->StartEditEngine();
968 void ScInputBarGroup::MakeDialogEditView()
970 mxTextWndGroup->MakeDialogEditView();
973 EditView* ScInputBarGroup::GetEditView() const
975 return mxTextWndGroup->GetEditView();
978 bool ScInputBarGroup::HasEditView() const
980 return mxTextWndGroup->HasEditView();
983 bool ScInputBarGroup::IsInputActive()
985 return mxTextWndGroup->IsInputActive();
988 void ScInputBarGroup::SetFormulaMode(bool bSet)
990 mxTextWndGroup->SetFormulaMode(bSet);
993 void ScInputBarGroup::IncrementVerticalSize()
995 mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() + 1);
996 TriggerToolboxLayout();
999 void ScInputBarGroup::DecrementVerticalSize()
1001 if (mxTextWndGroup->GetNumLines() > 1)
1003 mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() - 1);
1004 TriggerToolboxLayout();
1008 void ScInputWindow::MenuHdl(std::u16string_view command)
1010 if (command.empty())
1011 return;
1013 bool bSubTotal = false;
1014 bool bRangeFinder = false;
1015 OpCode eCode = ocSum;
1016 if ( command == u"sum" )
1018 eCode = ocSum;
1020 else if ( command == u"average" )
1022 eCode = ocAverage;
1024 else if ( command == u"max" )
1026 eCode = ocMax;
1028 else if ( command == u"min" )
1030 eCode = ocMin;
1032 else if ( command == u"count" )
1034 eCode = ocCount;
1036 else if ( command == u"counta" )
1038 eCode = ocCount2;
1040 else if ( command == u"product" )
1042 eCode = ocProduct;
1044 else if (command == u"stdev")
1046 eCode = ocStDev;
1048 else if (command == u"stdevp")
1050 eCode = ocStDevP;
1052 else if (command == u"var")
1054 eCode = ocVar;
1056 else if (command == u"varp")
1058 eCode = ocVarP;
1061 AutoSum( bRangeFinder, bSubTotal, eCode );
1064 IMPL_LINK_NOARG(ScInputWindow, DropdownClickHdl, ToolBox *, void)
1066 ToolBoxItemId nCurID = GetCurItemId();
1067 EndSelection();
1069 if (nCurID == SID_INPUT_SUM)
1071 tools::Rectangle aRect(GetItemRect(SID_INPUT_SUM));
1072 weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
1073 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, u"modules/scalc/ui/autosum.ui"_ustr));
1074 std::unique_ptr<weld::Menu> xPopMenu(xBuilder->weld_menu(u"menu"_ustr));
1075 MenuHdl(xPopMenu->popup_at_rect(pPopupParent, aRect));
1079 IMPL_LINK_NOARG(ScInputBarGroup, ClickHdl, weld::Button&, void)
1081 if (mxTextWndGroup->GetNumLines() > 1)
1082 mxTextWndGroup->SetNumLines(1);
1083 else
1084 mxTextWndGroup->SetNumLines(mxTextWndGroup->GetLastNumExpandedLines());
1086 NumLinesChanged();
1089 void ScInputBarGroup::NumLinesChanged()
1091 if (mxTextWndGroup->GetNumLines() > 1)
1093 mxButtonDown->hide();
1094 mxButtonUp->show();
1095 mxTextWndGroup->SetLastNumExpandedLines(mxTextWndGroup->GetNumLines());
1097 else
1099 mxButtonUp->hide();
1100 mxButtonDown->show();
1102 TriggerToolboxLayout();
1104 // Restore focus to input line(s) if necessary
1105 ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1106 if ( pHdl && pHdl->IsTopMode() )
1107 mxTextWndGroup->TextGrabFocus();
1110 void ScInputBarGroup::TriggerToolboxLayout()
1112 // layout changes are expensive and un-necessary.
1113 if (comphelper::LibreOfficeKit::isActive())
1114 return;
1116 vcl::Window *w=GetParent();
1117 ScInputWindow &rParent = dynamic_cast<ScInputWindow&>(*w);
1118 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1120 if ( !pViewFrm )
1121 return;
1123 Reference< css::beans::XPropertySet > xPropSet( pViewFrm->GetFrame().GetFrameInterface(), UNO_QUERY );
1124 Reference< css::frame::XLayoutManager > xLayoutManager;
1126 if ( xPropSet.is() )
1128 css::uno::Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
1129 aValue >>= xLayoutManager;
1132 if ( !xLayoutManager.is() )
1133 return;
1135 xLayoutManager->lock();
1136 DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr, AllSettingsFlags::STYLE );
1138 // this basically will trigger the repositioning of the
1139 // items in the toolbar from ImplFormat ( which is controlled by
1140 // mnWinHeight ) which in turn is updated in ImplCalcItem which is
1141 // controlled by mbCalc. Additionally the ImplFormat above is
1142 // controlled via mbFormat. It seems the easiest way to get these
1143 // booleans set is to send in the fake event below.
1144 rParent.DataChanged( aFakeUpdate);
1146 // highest item in toolbar will have been calculated via the
1147 // event above. Call resize on InputBar to pick up the height
1148 // change
1149 rParent.Resize();
1151 // unlock relayouts the toolbars in the 4 quadrants
1152 xLayoutManager->unlock();
1155 void ScInputBarGroup::TextGrabFocus()
1157 mxTextWndGroup->TextGrabFocus();
1160 constexpr tools::Long gnBorderWidth = (INPUTLINE_INSET_MARGIN + 1) * 2;
1161 constexpr tools::Long gnBorderHeight = INPUTLINE_INSET_MARGIN + 1;
1163 ScTextWndGroup::ScTextWndGroup(ScInputBarGroup& rParent, ScTabViewShell* pViewSh)
1164 : mxTextWnd(new ScTextWnd(*this, pViewSh))
1165 , mxScrollWin(rParent.GetBuilder().weld_scrolled_window(u"scrolledwindow"_ustr, true))
1166 , mxTextWndWin(new weld::CustomWeld(rParent.GetBuilder(), u"sc_input_window"_ustr, *mxTextWnd))
1167 , mrParent(rParent)
1169 mxScrollWin->connect_vadjustment_changed(LINK(this, ScTextWndGroup, Impl_ScrollHdl));
1170 if (ScTabViewShell* pActiveViewShell = comphelper::LibreOfficeKit::isActive() ?
1171 dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()) : nullptr)
1173 pActiveViewShell->LOKSendFormulabarUpdate(nullptr, u""_ustr, ESelection());
1177 Point ScTextWndGroup::GetCursorScreenPixelPos(bool bBelow)
1179 Point aPos;
1180 if (!HasEditView())
1181 return aPos;
1182 EditView* pEditView = GetEditView();
1183 vcl::Cursor* pCur = pEditView->GetCursor();
1184 if (!pCur)
1185 return aPos;
1186 Point aLogicPos = pCur->GetPos();
1187 if (bBelow)
1188 aLogicPos.AdjustY(pCur->GetHeight());
1189 aPos = GetEditViewDevice().LogicToPixel(aLogicPos);
1190 bool bRTL = mrParent.IsRTLEnabled();
1191 if (bRTL)
1192 aPos.setX(mxTextWnd->GetOutputSizePixel().Width() - aPos.X() + gnBorderWidth);
1193 else
1194 aPos.AdjustX(gnBorderWidth + 1);
1196 return mrParent.OutputToScreenPixel(aPos);
1199 ScTextWndGroup::~ScTextWndGroup()
1203 void ScTextWndGroup::InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
1205 mxTextWnd->InsertAccessibleTextData(rTextData);
1208 EditView* ScTextWndGroup::GetEditView() const
1210 return mxTextWnd->GetEditView();
1213 const OutputDevice& ScTextWndGroup::GetEditViewDevice() const
1215 return mxTextWnd->GetEditViewDevice();
1218 tools::Long ScTextWndGroup::GetLastNumExpandedLines() const
1220 return mxTextWnd->GetLastNumExpandedLines();
1223 void ScTextWndGroup::SetLastNumExpandedLines(tools::Long nLastExpandedLines)
1225 mxTextWnd->SetLastNumExpandedLines(nLastExpandedLines);
1228 tools::Long ScTextWndGroup::GetNumLines() const
1230 return mxTextWnd->GetNumLines();
1233 int ScTextWndGroup::GetPixelHeightForLines(tools::Long nLines)
1235 return mxTextWnd->GetPixelHeightForLines(nLines) + 2 * gnBorderHeight;
1238 weld::ScrolledWindow& ScTextWndGroup::GetScrollWin()
1240 return *mxScrollWin;
1243 const OUString& ScTextWndGroup::GetTextString() const
1245 return mxTextWnd->GetTextString();
1248 bool ScTextWndGroup::HasEditView() const
1250 return mxTextWnd->HasEditView();
1253 bool ScTextWndGroup::IsInputActive()
1255 return mxTextWnd->IsInputActive();
1258 void ScTextWndGroup::MakeDialogEditView()
1260 mxTextWnd->MakeDialogEditView();
1263 void ScTextWndGroup::RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
1265 mxTextWnd->RemoveAccessibleTextData(rTextData);
1268 void ScTextWndGroup::SetScrollPolicy()
1270 if (mxTextWnd->GetNumLines() > 2)
1271 mxScrollWin->set_vpolicy(VclPolicyType::ALWAYS);
1272 else
1273 mxScrollWin->set_vpolicy(VclPolicyType::NEVER);
1276 void ScTextWndGroup::SetNumLines(tools::Long nLines)
1278 mxTextWnd->SetNumLines(nLines);
1281 void ScTextWndGroup::SetFormulaMode(bool bSet)
1283 mxTextWnd->SetFormulaMode(bSet);
1286 void ScTextWndGroup::SetTextString(const OUString& rString, bool bKitUpdate)
1288 mxTextWnd->SetTextString(rString, bKitUpdate);
1291 void ScTextWndGroup::StartEditEngine()
1293 mxTextWnd->StartEditEngine();
1296 void ScTextWndGroup::StopEditEngine(bool bAll)
1298 mxTextWnd->StopEditEngine( bAll );
1301 void ScTextWndGroup::TextGrabFocus()
1303 mxTextWnd->TextGrabFocus();
1306 IMPL_LINK_NOARG(ScTextWndGroup, Impl_ScrollHdl, weld::ScrolledWindow&, void)
1308 mxTextWnd->DoScroll();
1311 void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
1313 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1314 Color aBgColor = rStyleSettings.GetFieldColor();
1315 rRenderContext.SetBackground(aBgColor);
1317 // tdf#137713 we rely on GetEditView creating it if it doesn't already exist so
1318 // GetEditView() must be called unconditionally
1319 if (EditView* pView = GetEditView())
1321 if (mbInvalidate)
1323 pView->Invalidate();
1324 mbInvalidate = false;
1328 if (comphelper::LibreOfficeKit::isActive() && m_xEditEngine)
1330 // EditEngine/EditView works in twips logical coordinates, so set the device map-mode to twips before painting
1331 // and use twips version of the painting area 'rRect'.
1332 // Document zoom should not be included in this conversion.
1333 tools::Rectangle aLogicRect = OutputDevice::LogicToLogic(rRect, MapMode(MapUnit::MapPixel), MapMode(MapUnit::MapTwip));
1334 MapMode aOriginalMode = rRenderContext.GetMapMode();
1335 rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
1336 WeldEditView::Paint(rRenderContext, aLogicRect);
1337 rRenderContext.SetMapMode(aOriginalMode);
1339 else
1340 WeldEditView::Paint(rRenderContext, rRect);
1343 EditView* ScTextWnd::GetEditView() const
1345 if ( !m_xEditView )
1346 const_cast<ScTextWnd&>(*this).InitEditEngine();
1347 return m_xEditView.get();
1350 bool ScTextWnd::HasEditView() const { return m_xEditView != nullptr; }
1352 const OutputDevice& ScTextWnd::GetEditViewDevice() const
1354 return EditViewOutputDevice();
1357 int ScTextWnd::GetPixelHeightForLines(tools::Long nLines)
1359 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1360 return rDevice.LogicToPixel(Size(0, nLines * rDevice.GetTextHeight())).Height() + 1;
1363 tools::Long ScTextWnd::GetNumLines() const
1365 ScViewData& rViewData = mpViewShell->GetViewData();
1366 return rViewData.GetFormulaBarLines();
1369 void ScTextWnd::SetNumLines(tools::Long nLines)
1371 ScViewData& rViewData = mpViewShell->GetViewData();
1372 rViewData.SetFormulaBarLines(nLines);
1373 if ( nLines > 1 )
1375 // SetFormulaBarLines sanitizes the height, so get the sanitized value
1376 mnLastExpandedLines = rViewData.GetFormulaBarLines();
1377 Resize();
1381 void ScTextWnd::Resize()
1383 if (m_xEditView)
1385 Size aOutputSize = GetOutputSizePixel();
1386 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1387 tools::Rectangle aOutputArea = rDevice.PixelToLogic( tools::Rectangle( Point(), aOutputSize ));
1388 m_xEditView->SetOutputArea( aOutputArea );
1390 // Don't leave an empty area at the bottom if we can move the text down.
1391 tools::Long nMaxVisAreaTop = m_xEditEngine->GetTextHeight() - aOutputArea.GetHeight();
1392 if (m_xEditView->GetVisArea().Top() > nMaxVisAreaTop)
1394 m_xEditView->Scroll(0, m_xEditView->GetVisArea().Top() - nMaxVisAreaTop);
1397 m_xEditEngine->SetPaperSize( rDevice.PixelToLogic( Size( aOutputSize.Width(), 10000 ) ) );
1400 // skip WeldEditView's Resize();
1401 weld::CustomWidgetController::Resize();
1403 SetScrollBarRange();
1406 int ScTextWnd::GetEditEngTxtHeight() const
1408 return m_xEditView ? m_xEditView->getEditEngine().GetTextHeight() : 0;
1411 void ScTextWnd::SetScrollBarRange()
1413 if (!m_xEditView)
1414 return;
1416 OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
1417 Size aOutputSize = rDevice.GetOutputSize();
1419 int nUpper = GetEditEngTxtHeight();
1420 int nCurrentDocPos = m_xEditView->GetVisArea().Top();
1421 int nStepIncrement = GetTextHeight();
1422 int nPageIncrement = aOutputSize.Height();
1423 int nPageSize = aOutputSize.Height();
1425 /* limit the page size to below nUpper because gtk's gtk_scrolled_window_start_deceleration has
1426 effectively...
1428 lower = gtk_adjustment_get_lower
1429 upper = gtk_adjustment_get_upper - gtk_adjustment_get_page_size
1431 and requires that upper > lower or the deceleration animation never ends
1433 nPageSize = std::min(nPageSize, nUpper);
1435 weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
1436 rVBar.vadjustment_configure(nCurrentDocPos, 0, nUpper,
1437 nStepIncrement, nPageIncrement, nPageSize);
1440 void ScTextWnd::DoScroll()
1442 if (m_xEditView)
1444 weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
1445 auto currentDocPos = m_xEditView->GetVisArea().Top();
1446 auto nDiff = currentDocPos - rVBar.vadjustment_get_value();
1447 // we expect SetScrollBarRange callback to be triggered by Scroll
1448 // to set where we ended up
1449 m_xEditView->Scroll(0, nDiff);
1453 void ScTextWnd::StartEditEngine()
1455 // Don't activate if we're a modal dialog ourselves (Doc-modal dialog)
1456 SfxObjectShell* pObjSh = SfxObjectShell::Current();
1457 if ( pObjSh && pObjSh->IsInModalMode() )
1458 return;
1460 if ( !m_xEditView || !m_xEditEngine )
1462 InitEditEngine();
1465 ScInputHandler* pHdl = mpViewShell->GetInputHandler();
1466 if (pHdl)
1467 pHdl->SetMode(SC_INPUT_TOP, nullptr, static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get()));
1469 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1470 if (pViewFrm)
1471 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1474 static void lcl_ExtendEditFontAttribs( SfxItemSet& rSet )
1476 const SfxPoolItem& rFontItem = rSet.Get( EE_CHAR_FONTINFO );
1477 std::unique_ptr<SfxPoolItem> pNewItem(rFontItem.Clone());
1478 pNewItem->SetWhich(EE_CHAR_FONTINFO_CJK);
1479 rSet.Put( *pNewItem );
1480 pNewItem->SetWhich(EE_CHAR_FONTINFO_CTL);
1481 rSet.Put( *pNewItem );
1482 const SfxPoolItem& rHeightItem = rSet.Get( EE_CHAR_FONTHEIGHT );
1483 pNewItem.reset(rHeightItem.Clone());
1484 pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CJK);
1485 rSet.Put( *pNewItem );
1486 pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CTL);
1487 rSet.Put( *pNewItem );
1488 const SfxPoolItem& rWeightItem = rSet.Get( EE_CHAR_WEIGHT );
1489 pNewItem.reset(rWeightItem.Clone());
1490 pNewItem->SetWhich(EE_CHAR_WEIGHT_CJK);
1491 rSet.Put( *pNewItem );
1492 pNewItem->SetWhich(EE_CHAR_WEIGHT_CTL);
1493 rSet.Put( *pNewItem );
1494 const SfxPoolItem& rItalicItem = rSet.Get( EE_CHAR_ITALIC );
1495 pNewItem.reset(rItalicItem.Clone());
1496 pNewItem->SetWhich(EE_CHAR_ITALIC_CJK);
1497 rSet.Put( *pNewItem );
1498 pNewItem->SetWhich(EE_CHAR_ITALIC_CTL);
1499 rSet.Put( *pNewItem );
1500 const SfxPoolItem& rLangItem = rSet.Get( EE_CHAR_LANGUAGE );
1501 pNewItem.reset(rLangItem.Clone());
1502 pNewItem->SetWhich(EE_CHAR_LANGUAGE_CJK);
1503 rSet.Put( *pNewItem );
1504 pNewItem->SetWhich(EE_CHAR_LANGUAGE_CTL);
1505 rSet.Put( *pNewItem );
1508 static void lcl_ModifyRTLDefaults( SfxItemSet& rSet )
1510 rSet.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
1512 // always using rtl writing direction would break formulas
1513 //rSet.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
1515 // PaperSize width is limited to USHRT_MAX in RTL mode (because of EditEngine's
1516 // sal_uInt16 values in EditLine), so the text may be wrapped and line spacing must be
1517 // increased to not see the beginning of the next line.
1518 SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
1519 aItem.SetPropLineSpace( 200 );
1520 rSet.Put( aItem );
1523 static void lcl_ModifyRTLVisArea( EditView* pEditView )
1525 tools::Rectangle aVisArea = pEditView->GetVisArea();
1526 Size aPaper = pEditView->getEditEngine().GetPaperSize();
1527 tools::Long nDiff = aPaper.Width() - aVisArea.Right();
1528 aVisArea.AdjustLeft(nDiff );
1529 aVisArea.AdjustRight(nDiff );
1530 pEditView->SetVisArea(aVisArea);
1533 void ScTextWnd::InitEditEngine()
1535 std::unique_ptr<ScFieldEditEngine> pNew;
1536 ScDocShell* pDocSh = nullptr;
1537 if ( mpViewShell )
1539 pDocSh = mpViewShell->GetViewData().GetDocShell();
1540 ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
1541 pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
1543 else
1544 pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
1545 pNew->SetExecuteURL( false );
1546 m_xEditEngine = std::move(pNew);
1548 Size barSize = GetOutputSizePixel();
1549 m_xEditEngine->SetUpdateLayout( false );
1550 m_xEditEngine->SetPaperSize( GetDrawingArea()->get_ref_device().PixelToLogic(Size(barSize.Width(),10000)) );
1551 m_xEditEngine->SetWordDelimiters(
1552 ScEditUtil::ModifyDelimiters( m_xEditEngine->GetWordDelimiters() ) );
1553 m_xEditEngine->SetReplaceLeadingSingleQuotationMark( false );
1555 UpdateAutoCorrFlag();
1558 auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
1559 EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
1560 lcl_ExtendEditFontAttribs( *pSet );
1561 // turn off script spacing to match DrawText output
1562 pSet->Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
1563 if ( bIsRTL )
1564 lcl_ModifyRTLDefaults( *pSet );
1565 static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
1568 // If the Cell contains URLFields, they need to be taken over into the entry row,
1569 // or else the position is not correct anymore
1570 bool bFilled = false;
1571 ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1572 if ( pHdl ) //! Test if it's the right InputHdl?
1573 bFilled = pHdl->GetTextAndFields(static_cast<ScEditEngineDefaulter&>(*m_xEditEngine));
1575 m_xEditEngine->SetUpdateLayout( true );
1577 // aString is the truth ...
1578 if (bFilled && m_xEditEngine->GetText() == aString)
1579 Invalidate(); // Repaint for (filled) Field
1580 else
1581 static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(aString); // At least the right text then
1583 m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
1585 // we get cursor, selection etc. messages from the VCL/window layer
1586 // otherwise these are injected into the document causing confusion.
1587 m_xEditView->SuppressLOKMessages(true);
1589 m_xEditView->setEditViewCallbacks(this);
1590 m_xEditView->SetInsertMode(bIsInsertMode);
1592 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1593 Color aBgColor = rStyleSettings.GetFieldColor();
1594 m_xEditView->SetBackgroundColor(aBgColor);
1596 if (pAcc)
1598 pAcc->InitAcc(nullptr, m_xEditView.get(),
1599 ScResId(STR_ACC_EDITLINE_NAME),
1600 ScResId(STR_ACC_EDITLINE_DESCR));
1603 if (comphelper::LibreOfficeKit::isActive())
1604 m_xEditView->RegisterViewShell(mpViewShell);
1606 // Text from Clipboard is taken over as ASCII in a single row
1607 EVControlBits n = m_xEditView->GetControlWord();
1608 m_xEditView->SetControlWord( n | EVControlBits::SINGLELINEPASTE );
1610 m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
1612 Resize();
1614 if ( bIsRTL )
1615 lcl_ModifyRTLVisArea( m_xEditView.get() );
1617 m_xEditEngine->SetModifyHdl(LINK(this, ScTextWnd, ModifyHdl));
1618 m_xEditEngine->SetStatusEventHdl(LINK(this, ScTextWnd, EditStatusHdl));
1620 if (!maAccTextDatas.empty())
1621 maAccTextDatas.back()->StartEdit();
1623 // as long as EditEngine and DrawText sometimes differ for CTL text,
1624 // repaint now to have the EditEngine's version visible
1625 if (pDocSh)
1627 ScDocument& rDoc = pDocSh->GetDocument(); // any document
1628 SvtScriptType nScript = rDoc.GetStringScriptType( aString );
1629 if ( nScript & SvtScriptType::COMPLEX )
1630 Invalidate();
1634 ScTextWnd::ScTextWnd(ScTextWndGroup& rParent, ScTabViewShell* pViewSh) :
1635 bIsRTL(AllSettings::GetLayoutRTL()),
1636 bIsInsertMode(true),
1637 bFormulaMode (false),
1638 bInputMode (false),
1639 mpViewShell(pViewSh),
1640 mrGroupBar(rParent),
1641 mnLastExpandedLines(INPUTWIN_MULTILINES),
1642 mbInvalidate(false)
1646 ScTextWnd::~ScTextWnd()
1648 while (!maAccTextDatas.empty()) {
1649 maAccTextDatas.back()->Dispose();
1653 bool ScTextWnd::MouseMove( const MouseEvent& rMEvt )
1655 return m_xEditView && m_xEditView->MouseMove(rMEvt);
1658 bool ScTextWnd::CanFocus() const
1660 return ScModule::get()->IsEditMode();
1663 void ScTextWnd::UpdateFocus()
1665 if (!HasFocus())
1667 StartEditEngine();
1668 if (CanFocus())
1669 TextGrabFocus();
1673 bool ScTextWnd::MouseButtonDown( const MouseEvent& rMEvt )
1675 UpdateFocus();
1677 bool bClickOnSelection = false;
1678 if (m_xEditView)
1680 m_xEditView->SetEditEngineUpdateLayout( true );
1681 bClickOnSelection = m_xEditView->IsSelectionAtPoint(rMEvt.GetPosPixel());
1683 if (!bClickOnSelection)
1685 rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
1686 GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_NONE);
1688 else
1690 rtl::Reference<TransferDataContainer> xTransferable(m_xHelper);
1691 GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_COPY);
1693 return WeldEditView::MouseButtonDown(rMEvt);
1696 bool ScTextWnd::MouseButtonUp( const MouseEvent& rMEvt )
1698 bool bRet = WeldEditView::MouseButtonUp(rMEvt);
1699 if (bRet)
1701 if ( rMEvt.IsMiddle() &&
1702 Application::GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
1704 // EditView may have pasted from selection
1705 ScModule::get()->InputChanged(m_xEditView.get());
1707 else
1708 ScModule::get()->InputSelection(m_xEditView.get());
1710 return bRet;
1713 bool ScTextWnd::Command( const CommandEvent& rCEvt )
1715 bool bConsumed = false;
1717 bInputMode = true;
1718 CommandEventId nCommand = rCEvt.GetCommand();
1719 if (m_xEditView)
1721 ScModule* pScMod = ScModule::get();
1722 ScTabViewShell* pStartViewSh = ScTabViewShell::GetActiveViewShell();
1724 // don't modify the font defaults here - the right defaults are
1725 // already set in StartEditEngine when the EditEngine is created
1727 // Prevent that the EditView is lost when switching between Views
1728 pScMod->SetInEditCommand( true );
1729 m_xEditView->Command( rCEvt );
1730 pScMod->SetInEditCommand( false );
1732 // CommandEventId::StartDrag does not mean by far that the content was actually changed,
1733 // so don't trigger an InputChanged.
1734 //! Detect if dragged with Move or forbid Drag&Move somehow
1736 if ( nCommand == CommandEventId::StartDrag )
1738 // Is dragged onto another View?
1739 ScTabViewShell* pEndViewSh = ScTabViewShell::GetActiveViewShell();
1740 if ( pEndViewSh != pStartViewSh && pStartViewSh != nullptr )
1742 ScViewData& rViewData = pStartViewSh->GetViewData();
1743 ScInputHandler* pHdl = pScMod->GetInputHdl( pStartViewSh );
1744 if ( pHdl && rViewData.HasEditView( rViewData.GetActivePart() ) )
1746 pHdl->CancelHandler();
1747 rViewData.GetView()->ShowCursor(); // Missing for KillEditView, due to being inactive
1751 else if ( nCommand == CommandEventId::EndExtTextInput )
1753 ScModule* mod = ScModule::get();
1754 if (bFormulaMode)
1756 ScInputHandler* pHdl = mod->GetInputHdl();
1757 if (pHdl)
1758 pHdl->InputCommand(rCEvt);
1760 mod->InputChanged(m_xEditView.get());
1762 else if ( nCommand == CommandEventId::CursorPos )
1764 // don't call InputChanged for CommandEventId::CursorPos
1766 else if ( nCommand == CommandEventId::InputLanguageChange )
1768 // #i55929# Font and font size state depends on input language if nothing is selected,
1769 // so the slots have to be invalidated when the input language is changed.
1771 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1772 if (pViewFrm)
1774 SfxBindings& rBindings = pViewFrm->GetBindings();
1775 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
1776 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
1779 else if ( nCommand == CommandEventId::ContextMenu )
1781 bConsumed = true;
1782 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1783 if (pViewFrm)
1785 Point aPos = rCEvt.GetMousePosPixel();
1786 if (!rCEvt.IsMouseEvent())
1788 Size aSize = GetOutputSizePixel();
1789 aPos = Point(aSize.Width() / 2, aSize.Height() / 2);
1791 if (IsMouseCaptured())
1792 ReleaseMouse();
1793 UpdateFocus();
1794 pViewFrm->GetDispatcher()->ExecutePopup(u"formulabar"_ustr, &mrGroupBar.GetVclParent(), &aPos);
1797 else if ( nCommand == CommandEventId::Wheel )
1799 //don't call InputChanged for CommandEventId::Wheel
1801 else if ( nCommand == CommandEventId::GestureSwipe )
1803 //don't call InputChanged for CommandEventId::GestureSwipe
1805 else if ( nCommand == CommandEventId::GestureLongPress )
1807 //don't call InputChanged for CommandEventId::GestureLongPress
1809 else if ( nCommand == CommandEventId::ModKeyChange )
1811 //pass alt press/release to parent impl
1813 else
1814 ScModule::get()->InputChanged(m_xEditView.get());
1817 if ( comphelper::LibreOfficeKit::isActive() && nCommand == CommandEventId::CursorPos )
1819 // LOK uses this to setup caret position because drawingarea is replaced
1820 // with text input field, it sends logical caret position (start, end) not pixels
1822 StartEditEngine();
1823 TextGrabFocus();
1825 if (!m_xEditView)
1826 return true;
1828 ScModule* mod = ScModule::get();
1829 // if we focus input after "Accept Formula" command, we need to notify to get it working
1830 mod->InputChanged(m_xEditView.get());
1832 // information about paragraph is in additional data
1833 // information about position in a paragraph in a Mouse Pos
1834 // see vcl/jsdialog/executor.cxx "textselection" event
1835 const Point* pParaPoint = static_cast<const Point*>(rCEvt.GetEventData());
1836 Point aSelectionStartEnd = rCEvt.GetMousePosPixel();
1838 sal_Int32 nParaStart, nParaEnd, nPosStart, nPosEnd;
1840 nParaStart = pParaPoint ? pParaPoint->X() : 0;
1841 nParaEnd = pParaPoint ? pParaPoint->Y() : 0;
1842 nPosStart = m_xEditView->GetPosNoField(nParaStart, aSelectionStartEnd.X());
1843 nPosEnd = m_xEditView->GetPosNoField(nParaEnd, aSelectionStartEnd.Y());
1845 m_xEditView->SetSelection(ESelection(nParaStart, nPosStart, nParaEnd, nPosEnd));
1846 mod->InputSelection(m_xEditView.get());
1848 bConsumed = true;
1851 bInputMode = false;
1853 return bConsumed;
1856 bool ScTextWnd::StartDrag()
1858 // tdf#145248 don't start a drag if actively selecting
1859 if (m_xEditView && !m_xEditEngine->IsInSelectionMode())
1861 OUString sSelection = m_xEditView->GetSelected();
1862 m_xHelper->SetData(sSelection);
1863 return sSelection.isEmpty();
1865 return true;
1868 bool ScTextWnd::KeyInput(const KeyEvent& rKEvt)
1870 bool bUsed = true;
1871 bInputMode = true;
1872 if (!ScModule::get()->InputKeyEvent(rKEvt))
1874 bUsed = false;
1875 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1876 if ( pViewSh )
1877 bUsed = pViewSh->SfxKeyInput(rKEvt); // Only accelerators, no input
1879 bInputMode = false;
1880 return bUsed;
1883 void ScTextWnd::GetFocus()
1885 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1886 if ( pViewSh )
1887 pViewSh->SetFormShellAtTop( false ); // focus in input line -> FormShell no longer on top
1888 WeldEditView::GetFocus();
1891 void ScTextWnd::SetFormulaMode( bool bSet )
1893 if ( bSet != bFormulaMode )
1895 bFormulaMode = bSet;
1896 UpdateAutoCorrFlag();
1900 void ScTextWnd::UpdateAutoCorrFlag()
1902 if (m_xEditEngine)
1904 EEControlBits nControl = m_xEditEngine->GetControlWord();
1905 EEControlBits nOld = nControl;
1906 if ( bFormulaMode )
1907 nControl &= ~EEControlBits::AUTOCORRECT; // No AutoCorrect in Formulas
1908 else
1909 nControl |= EEControlBits::AUTOCORRECT; // Else do enable it
1911 if ( nControl != nOld )
1912 m_xEditEngine->SetControlWord( nControl );
1916 void ScTextWnd::EditViewScrollStateChange()
1918 // editengine height has changed or editview scroll pos has changed
1919 SetScrollBarRange();
1922 IMPL_LINK_NOARG(ScTextWnd, ModifyHdl, LinkParamNone*, void)
1924 if (m_xEditView && !bInputMode)
1926 ScInputHandler* pHdl = ScModule::get()->GetInputHdl();
1928 // Use the InputHandler's InOwnChange flag to prevent calling InputChanged
1929 // while an InputHandler method is modifying the EditEngine content
1931 if ( pHdl && !pHdl->IsInOwnChange() )
1932 pHdl->InputChanged( m_xEditView.get(), true ); // #i20282# InputChanged must know if called from modify handler
1936 IMPL_LINK_NOARG(ScTextWnd, EditStatusHdl, EditStatus&, void)
1938 SetScrollBarRange();
1939 DoScroll();
1940 Invalidate();
1943 void ScTextWnd::StopEditEngine( bool bAll )
1945 if (!m_xEditEngine)
1946 return;
1948 if (m_xEditView)
1950 if (!maAccTextDatas.empty())
1951 maAccTextDatas.back()->EndEdit();
1953 ScModule* pScMod = ScModule::get();
1955 if (!bAll)
1956 pScMod->InputSelection( m_xEditView.get() );
1957 aString = m_xEditEngine->GetText();
1958 bIsInsertMode = m_xEditView->IsInsertMode();
1959 bool bSelection = m_xEditView->HasSelection();
1960 m_xEditEngine->SetStatusEventHdl(Link<EditStatus&, void>());
1961 m_xEditEngine->SetModifyHdl(Link<LinkParamNone*,void>());
1962 m_xEditView.reset();
1963 m_xEditEngine.reset();
1965 ScInputHandler* pHdl = mpViewShell->GetInputHandler();
1967 if (pHdl && pHdl->IsEditMode() && !bAll)
1968 pHdl->SetMode(SC_INPUT_TABLE);
1970 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1971 if (pViewFrm)
1972 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1974 if (bSelection)
1975 Invalidate(); // So that the Selection is not left there
1978 if (comphelper::LibreOfficeKit::isActive())
1980 // Clear
1981 std::vector<ReferenceMark> aReferenceMarks;
1982 ScInputHandler::SendReferenceMarks( mpViewShell, aReferenceMarks );
1986 static sal_Int32 findFirstNonMatchingChar(const OUString& rStr1, const OUString& rStr2)
1988 // Search the string for unmatching chars
1989 const sal_Unicode* pStr1 = rStr1.getStr();
1990 const sal_Unicode* pStr2 = rStr2.getStr();
1991 sal_Int32 i = 0;
1992 while ( i < rStr1.getLength() )
1994 // Abort on the first unmatching char
1995 if ( *pStr1 != *pStr2 )
1996 return i;
1997 ++pStr1;
1998 ++pStr2;
1999 ++i;
2002 return i;
2005 void ScTextWnd::SetTextString( const OUString& rNewString, bool bKitUpdate )
2007 // Ideally it would be best to create on demand the EditEngine/EditView here, but... for
2008 // the initialisation scenario where a cell is first clicked on we end up with the text in the
2009 // inputbar window scrolled to the bottom if we do that here ( because the tableview and topview
2010 // are synced I guess ).
2011 // should fix that I suppose :-/ need to look a bit further into that
2012 mbInvalidate = true; // ensure next Paint ( that uses editengine ) call will call Invalidate first
2014 if ( rNewString != aString )
2016 bInputMode = true;
2018 // Find position of the change, only paint the rest
2019 if (!m_xEditEngine)
2021 bool bPaintAll = GetNumLines() > 1 || bIsRTL;
2022 if (!bPaintAll)
2024 // test if CTL script type is involved
2025 SvtScriptType nOldScript = SvtScriptType::NONE;
2026 SvtScriptType nNewScript = SvtScriptType::NONE;
2027 SfxObjectShell* pObjSh = SfxObjectShell::Current();
2028 if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
2030 // any document can be used (used only for its break iterator)
2031 ScDocument& rDoc = pDocShell->GetDocument();
2032 nOldScript = rDoc.GetStringScriptType( aString );
2033 nNewScript = rDoc.GetStringScriptType( rNewString );
2035 bPaintAll = ( nOldScript & SvtScriptType::COMPLEX ) || ( nNewScript & SvtScriptType::COMPLEX );
2038 if ( bPaintAll )
2040 // In multiline mode, or if CTL is involved, the whole text has to be redrawn
2041 Invalidate();
2043 else
2045 tools::Long nTextSize = 0;
2046 sal_Int32 nDifPos;
2047 if (rNewString.getLength() > aString.getLength())
2048 nDifPos = findFirstNonMatchingChar(rNewString, aString);
2049 else
2050 nDifPos = findFirstNonMatchingChar(aString, rNewString);
2052 tools::Long nSize1 = GetTextWidth(aString);
2053 tools::Long nSize2 = GetTextWidth(rNewString);
2054 if ( nSize1>0 && nSize2>0 )
2055 nTextSize = std::max( nSize1, nSize2 );
2056 else
2057 nTextSize = GetOutputSizePixel().Width(); // Overflow
2059 Point aLogicStart = GetDrawingArea()->get_ref_device().PixelToLogic(Point(0,0));
2060 tools::Long nStartPos = aLogicStart.X();
2061 tools::Long nInvPos = nStartPos;
2062 if (nDifPos)
2063 nInvPos += GetTextWidth(aString.copy(0,nDifPos));
2065 Invalidate(tools::Rectangle(nInvPos, 0, nStartPos+nTextSize, GetOutputSizePixel().Height() - 1));
2068 else
2070 static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(rNewString);
2073 aString = rNewString;
2075 if (!maAccTextDatas.empty())
2076 maAccTextDatas.back()->TextChanged();
2078 bInputMode = false;
2081 if (ScTabViewShell* pActiveViewShell = bKitUpdate && comphelper::LibreOfficeKit::isActive() ?
2082 dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()) : nullptr)
2084 ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : ESelection();
2085 pActiveViewShell->LOKSendFormulabarUpdate(m_xEditView.get(), rNewString, aSel);
2088 SetScrollBarRange();
2089 DoScroll();
2092 const OUString& ScTextWnd::GetTextString() const
2094 return aString;
2097 bool ScTextWnd::IsInputActive()
2099 return HasFocus();
2102 void ScTextWnd::MakeDialogEditView()
2104 if ( m_xEditView ) return;
2106 std::unique_ptr<ScFieldEditEngine> pNew;
2107 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2108 if ( pViewSh )
2110 ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
2111 pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
2113 else
2114 pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
2115 pNew->SetExecuteURL( false );
2116 m_xEditEngine = std::move(pNew);
2118 const bool bPrevUpdateLayout = m_xEditEngine->SetUpdateLayout( false );
2119 m_xEditEngine->SetWordDelimiters( m_xEditEngine->GetWordDelimiters() + "=" );
2120 m_xEditEngine->SetPaperSize( Size( bIsRTL ? USHRT_MAX : THESIZE, 300 ) );
2122 auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
2123 EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
2124 lcl_ExtendEditFontAttribs( *pSet );
2125 if ( bIsRTL )
2126 lcl_ModifyRTLDefaults( *pSet );
2127 static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
2128 m_xEditEngine->SetUpdateLayout( bPrevUpdateLayout );
2130 m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
2131 m_xEditView->setEditViewCallbacks(this);
2133 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2134 Color aBgColor = rStyleSettings.GetFieldColor();
2135 m_xEditView->SetBackgroundColor(aBgColor);
2137 if (pAcc)
2139 pAcc->InitAcc(nullptr, m_xEditView.get(),
2140 ScResId(STR_ACC_EDITLINE_NAME),
2141 ScResId(STR_ACC_EDITLINE_DESCR));
2144 if (comphelper::LibreOfficeKit::isActive())
2145 m_xEditView->RegisterViewShell(mpViewShell);
2146 m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
2148 Resize();
2150 if ( bIsRTL )
2151 lcl_ModifyRTLVisArea( m_xEditView.get() );
2153 if (!maAccTextDatas.empty())
2154 maAccTextDatas.back()->StartEdit();
2157 void ScTextWnd::ImplInitSettings()
2159 bIsRTL = AllSettings::GetLayoutRTL();
2161 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2163 Color aBgColor= rStyleSettings.GetFieldColor();
2164 Color aTxtColor= rStyleSettings.GetWindowTextColor();
2166 aTextFont.SetFillColor ( aBgColor );
2167 aTextFont.SetColor (aTxtColor);
2168 Invalidate();
2171 void ScTextWnd::SetDrawingArea(weld::DrawingArea* pDrawingArea)
2173 // bypass WeldEditView::SetDrawingArea
2174 weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
2176 // set cursor
2177 pDrawingArea->set_cursor(PointerStyle::Text);
2179 // initialize dnd, deliberately just a simple string so
2180 // we don't transfer the happenstance formatting in
2181 // the input line
2182 m_xHelper.set(new svt::OStringTransferable(OUString()));
2183 rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
2184 SetDragDataTransferable(xHelper, DND_ACTION_COPY);
2186 OutputDevice& rDevice = pDrawingArea->get_ref_device();
2187 pDrawingArea->set_margin_start(gnBorderWidth);
2188 pDrawingArea->set_margin_end(gnBorderWidth);
2189 // leave 1 for the width of the scrolledwindow border
2190 pDrawingArea->set_margin_top(gnBorderHeight - 1);
2191 pDrawingArea->set_margin_bottom(gnBorderHeight - 1);
2193 // always use application font, so a font with cjk chars can be installed
2194 vcl::Font aAppFont = Application::GetSettings().GetStyleSettings().GetAppFont();
2195 weld::SetPointFont(rDevice, aAppFont);
2197 aTextFont = rDevice.GetFont();
2198 Size aFontSize = aTextFont.GetFontSize();
2199 aTextFont.SetFontSize(rDevice.PixelToLogic(aFontSize, MapMode(MapUnit::MapTwip)));
2201 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2203 Color aBgColor = rStyleSettings.GetFieldColor();
2204 Color aTxtColor = rStyleSettings.GetWindowTextColor();
2206 aTextFont.SetTransparent(true);
2207 aTextFont.SetFillColor(aBgColor);
2208 aTextFont.SetColor(aTxtColor);
2209 aTextFont.SetWeight(WEIGHT_NORMAL);
2211 Size aSize(1, GetPixelHeightForLines(1));
2212 pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
2214 rDevice.SetBackground(aBgColor);
2215 rDevice.SetLineColor(COL_BLACK);
2216 rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
2217 rDevice.SetFont(aTextFont);
2219 EnableRTL(false); // EditEngine can't be used with VCL EnableRTL
2222 css::uno::Reference< css::accessibility::XAccessible > ScTextWnd::CreateAccessible()
2224 pAcc = new ScAccessibleEditLineObject(this);
2225 return pAcc;
2228 void ScTextWnd::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
2230 OSL_ENSURE( ::std::find( maAccTextDatas.begin(), maAccTextDatas.end(), &rTextData ) == maAccTextDatas.end(),
2231 "ScTextWnd::InsertAccessibleTextData - passed object already registered" );
2232 maAccTextDatas.push_back( &rTextData );
2235 void ScTextWnd::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
2237 AccTextDataVector::iterator aEnd = maAccTextDatas.end();
2238 AccTextDataVector::iterator aIt = ::std::find( maAccTextDatas.begin(), aEnd, &rTextData );
2239 OSL_ENSURE( aIt != aEnd, "ScTextWnd::RemoveAccessibleTextData - passed object not registered" );
2240 if( aIt != aEnd )
2241 maAccTextDatas.erase( aIt );
2244 void ScTextWnd::StyleUpdated()
2246 ImplInitSettings();
2247 CustomWidgetController::Invalidate();
2250 void ScTextWnd::TextGrabFocus()
2252 GrabFocus();
2255 // Position window
2256 ScPosWnd::ScPosWnd(vcl::Window* pParent)
2257 : InterimItemWindow(pParent, u"modules/scalc/ui/posbox.ui"_ustr, u"PosBox"_ustr)
2258 , m_xWidget(m_xBuilder->weld_combo_box(u"pos_window"_ustr))
2259 , m_nAsyncGetFocusId(nullptr)
2260 , nTipVisible(nullptr)
2261 , bFormulaMode(false)
2263 InitControlBase(m_xWidget.get());
2265 // Use calculation according to tdf#132338 to align combobox width to width of fontname combobox within formatting toolbar;
2266 // formatting toolbar is placed above formulabar when using multiple toolbars typically
2268 m_xWidget->set_entry_width_chars(1);
2269 Size aSize(LogicToPixel(Size(POSITION_COMBOBOX_WIDTH * 4, 0), MapMode(MapUnit::MapAppFont)));
2270 m_xWidget->set_size_request(aSize.Width(), -1);
2271 SetSizePixel(m_xContainer->get_preferred_size());
2273 FillRangeNames();
2275 StartListening( *SfxGetpApp() ); // For Navigator rangename updates
2277 m_xWidget->connect_key_press(LINK(this, ScPosWnd, KeyInputHdl));
2278 m_xWidget->connect_entry_activate(LINK(this, ScPosWnd, ActivateHdl));
2279 m_xWidget->connect_changed(LINK(this, ScPosWnd, ModifyHdl));
2280 m_xWidget->connect_focus_in(LINK(this, ScPosWnd, FocusInHdl));
2281 m_xWidget->connect_focus_out(LINK(this, ScPosWnd, FocusOutHdl));
2284 ScPosWnd::~ScPosWnd()
2286 disposeOnce();
2289 void ScPosWnd::dispose()
2291 EndListening( *SfxGetpApp() );
2293 HideTip();
2295 if (m_nAsyncGetFocusId)
2297 Application::RemoveUserEvent(m_nAsyncGetFocusId);
2298 m_nAsyncGetFocusId = nullptr;
2300 m_xWidget.reset();
2302 InterimItemWindow::dispose();
2305 void ScPosWnd::SetFormulaMode( bool bSet )
2307 if ( bSet != bFormulaMode )
2309 bFormulaMode = bSet;
2311 if ( bSet )
2312 FillFunctions();
2313 else
2314 FillRangeNames();
2316 HideTip();
2320 void ScPosWnd::SetPos( const OUString& rPosStr )
2322 if ( aPosStr != rPosStr )
2324 aPosStr = rPosStr;
2325 m_xWidget->set_entry_text(aPosStr);
2329 // static
2330 OUString ScPosWnd::createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
2332 return OUString::Concat(rName) + " (" + rTableName + ")";
2335 void ScPosWnd::FillRangeNames()
2337 m_xWidget->clear();
2338 m_xWidget->freeze();
2340 SfxObjectShell* pObjSh = SfxObjectShell::Current();
2341 if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
2343 ScDocument& rDoc = pDocShell->GetDocument();
2345 m_xWidget->append_text(ScResId(STR_MANAGE_NAMES));
2346 m_xWidget->append_separator(u"separator"_ustr);
2348 ScRange aDummy;
2349 std::set<OUString> aSet;
2350 ScRangeName* pRangeNames = rDoc.GetRangeName();
2351 for (const auto& rEntry : *pRangeNames)
2353 if (rEntry.second->IsValidReference(aDummy))
2354 aSet.insert(rEntry.second->GetName());
2356 for (SCTAB i = 0; i < rDoc.GetTableCount(); ++i)
2358 ScRangeName* pLocalRangeName = rDoc.GetRangeName(i);
2359 if (pLocalRangeName && !pLocalRangeName->empty())
2361 OUString aTableName;
2362 rDoc.GetName(i, aTableName);
2363 for (const auto& rEntry : *pLocalRangeName)
2365 if (rEntry.second->IsValidReference(aDummy))
2366 aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
2371 for (const auto& rItem : aSet)
2373 m_xWidget->append_text(rItem);
2376 m_xWidget->thaw();
2377 m_xWidget->set_entry_text(aPosStr);
2380 void ScPosWnd::FillFunctions()
2382 m_xWidget->clear();
2383 m_xWidget->freeze();
2385 OUString aFirstName;
2386 const ScAppOptions& rOpt = ScModule::get()->GetAppOptions();
2387 sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
2388 const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
2389 if (pMRUList)
2391 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
2392 sal_uInt32 nListCount = pFuncList->GetCount();
2393 for (sal_uInt16 i=0; i<nMRUCount; i++)
2395 sal_uInt16 nId = pMRUList[i];
2396 for (sal_uInt32 j=0; j<nListCount; j++)
2398 const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
2399 if ( pDesc->nFIndex == nId && pDesc->mxFuncName )
2401 m_xWidget->append_text(*pDesc->mxFuncName);
2402 if (aFirstName.isEmpty())
2403 aFirstName = *pDesc->mxFuncName;
2404 break; // Stop searching
2410 //! Re-add entry "Other..." for Function AutoPilot if it can work with text that
2411 // has been entered so far
2413 // m_xWidget->append_text(ScResId(STR_FUNCTIONLIST_MORE));
2415 m_xWidget->thaw();
2416 m_xWidget->set_entry_text(aFirstName);
2419 void ScPosWnd::Notify( SfxBroadcaster&, const SfxHint& rHint )
2421 if ( bFormulaMode )
2422 return;
2424 const SfxHintId nHintId = rHint.GetId();
2425 // Does the list of range names need updating?
2426 if (nHintId == SfxHintId::ThisIsAnSfxEventHint)
2428 SfxEventHintId nEventId = static_cast<const SfxEventHint&>(rHint).GetEventId();
2429 if ( nEventId == SfxEventHintId::ActivateDoc )
2430 FillRangeNames();
2432 else
2434 if (nHintId == SfxHintId::ScAreasChanged || nHintId == SfxHintId::ScNavigatorUpdateAll)
2435 FillRangeNames();
2439 void ScPosWnd::HideTip()
2441 if (nTipVisible)
2443 Help::HidePopover(this, nTipVisible);
2444 nTipVisible = nullptr;
2448 static ScNameInputType lcl_GetInputType( const OUString& rText )
2450 ScNameInputType eRet = SC_NAME_INPUT_BAD_NAME; // the more general error
2452 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2453 if ( pViewSh )
2455 ScViewData& rViewData = pViewSh->GetViewData();
2456 ScDocument& rDoc = rViewData.GetDocument();
2457 SCTAB nTab = rViewData.GetTabNo();
2458 ScAddress::Details aDetails( rDoc.GetAddressConvention());
2460 // test in same order as in SID_CURRENTCELL execute
2462 ScRange aRange;
2463 ScAddress aAddress;
2464 SCTAB nNameTab;
2465 sal_Int32 nNumeric;
2467 // From the context we know that when testing for a range name
2468 // sheet-local scope names have " (sheetname)" appended and global
2469 // names don't and can't contain ')', so we can force one or the other.
2470 const RutlNameScope eNameScope =
2471 ((!rText.isEmpty() && rText[rText.getLength()-1] == ')') ? RUTL_NAMES_LOCAL : RUTL_NAMES_GLOBAL);
2473 if (rText == ScResId(STR_MANAGE_NAMES))
2474 eRet = SC_MANAGE_NAMES;
2475 else if ( aRange.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
2476 eRet = SC_NAME_INPUT_RANGE;
2477 else if ( aAddress.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
2478 eRet = SC_NAME_INPUT_CELL;
2479 else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, eNameScope, aDetails ) )
2481 eRet = ((eNameScope == RUTL_NAMES_LOCAL) ? SC_NAME_INPUT_NAMEDRANGE_LOCAL :
2482 SC_NAME_INPUT_NAMEDRANGE_GLOBAL);
2484 else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, RUTL_DBASE, aDetails ) )
2485 eRet = SC_NAME_INPUT_DATABASE;
2486 else if ( comphelper::string::isdigitAsciiString( rText ) &&
2487 ( nNumeric = rText.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
2488 eRet = SC_NAME_INPUT_ROW;
2489 else if ( rDoc.GetTable( rText, nNameTab ) )
2490 eRet = SC_NAME_INPUT_SHEET;
2491 else if (ScRangeData::IsNameValid(rText, rDoc)
2492 == ScRangeData::IsNameValidType::NAME_VALID) // nothing found, create new range?
2494 if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
2495 eRet = SC_NAME_INPUT_DEFINE;
2496 else
2497 eRet = SC_NAME_INPUT_BAD_SELECTION;
2499 else
2500 eRet = SC_NAME_INPUT_BAD_NAME;
2503 return eRet;
2506 IMPL_LINK_NOARG(ScPosWnd, ModifyHdl, weld::ComboBox&, void)
2508 HideTip();
2510 if (m_xWidget->changed_by_direct_pick())
2512 DoEnter();
2513 return;
2516 if (bFormulaMode)
2517 return;
2519 // determine the action that would be taken for the current input
2521 ScNameInputType eType = lcl_GetInputType(m_xWidget->get_active_text()); // uses current view
2522 TranslateId pStrId;
2523 switch ( eType )
2525 case SC_NAME_INPUT_CELL:
2526 pStrId = STR_NAME_INPUT_CELL;
2527 break;
2528 case SC_NAME_INPUT_RANGE:
2529 case SC_NAME_INPUT_NAMEDRANGE_LOCAL:
2530 case SC_NAME_INPUT_NAMEDRANGE_GLOBAL:
2531 pStrId = STR_NAME_INPUT_RANGE; // named range or range reference
2532 break;
2533 case SC_NAME_INPUT_DATABASE:
2534 pStrId = STR_NAME_INPUT_DBRANGE;
2535 break;
2536 case SC_NAME_INPUT_ROW:
2537 pStrId = STR_NAME_INPUT_ROW;
2538 break;
2539 case SC_NAME_INPUT_SHEET:
2540 pStrId = STR_NAME_INPUT_SHEET;
2541 break;
2542 case SC_NAME_INPUT_DEFINE:
2543 pStrId = STR_NAME_INPUT_DEFINE;
2544 break;
2545 default:
2546 // other cases (error): no tip help
2547 break;
2550 if (!pStrId)
2551 return;
2553 // show the help tip at the text cursor position
2554 Point aPos;
2555 vcl::Cursor* pCur = GetCursor();
2556 if (pCur)
2557 aPos = LogicToPixel( pCur->GetPos() );
2558 aPos = OutputToScreenPixel( aPos );
2559 tools::Rectangle aRect( aPos, aPos );
2561 OUString aText = ScResId(pStrId);
2562 QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
2563 nTipVisible = Help::ShowPopover(this, aRect, aText, nAlign);
2566 void ScPosWnd::DoEnter()
2568 bool bOpenManageNamesDialog = false;
2569 OUString aText = m_xWidget->get_active_text();
2570 if ( !aText.isEmpty() )
2572 if ( bFormulaMode )
2574 ScModule* pScMod = ScModule::get();
2575 if ( aText == ScResId(STR_FUNCTIONLIST_MORE) )
2577 // Function AutoPilot
2578 //! Continue working with the text entered so far
2580 //! new method at ScModule to query if function autopilot is open
2581 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2582 if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
2583 pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
2584 SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
2586 else
2588 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2589 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
2590 if (pHdl)
2591 pHdl->InsertFunction( aText );
2594 else
2596 // depending on the input, select something or create a new named range
2598 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2599 if ( pViewSh )
2601 ScViewData& rViewData = pViewSh->GetViewData();
2602 ScDocShell* pDocShell = rViewData.GetDocShell();
2603 ScDocument& rDoc = pDocShell->GetDocument();
2605 ScNameInputType eType = lcl_GetInputType( aText );
2606 if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION )
2608 TranslateId pId = (eType == SC_NAME_INPUT_BAD_NAME) ? STR_NAME_ERROR_NAME : STR_NAME_ERROR_SELECTION;
2609 pViewSh->ErrorMessage(pId);
2611 else if ( eType == SC_NAME_INPUT_DEFINE )
2613 ScRangeName* pNames = rDoc.GetRangeName();
2614 ScRange aSelection;
2615 if ( pNames && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aText)) &&
2616 (rViewData.GetSimpleArea( aSelection ) == SC_MARK_SIMPLE) )
2618 ScRangeName aNewRanges( *pNames );
2619 ScAddress aCursor( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
2620 OUString aContent(aSelection.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
2621 ScRangeData* pNew = new ScRangeData( rDoc, aText, aContent, aCursor );
2622 if ( aNewRanges.insert(pNew) )
2624 pDocShell->GetDocFunc().ModifyRangeNames( aNewRanges );
2625 pViewSh->UpdateInputHandler(true);
2629 else if (eType == SC_MANAGE_NAMES)
2631 // dialog is only set below after calling 'ReleaseFocus_Impl' to ensure it gets focus
2632 bOpenManageNamesDialog = true;
2634 else
2636 bool bForceGlobalName = false;
2637 // for all selection types, execute the SID_CURRENTCELL slot.
2638 if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE)
2640 // Note that SID_CURRENTCELL always expects address to
2641 // be in Calc A1 format. Convert the text.
2642 ScRange aRange(0,0, rViewData.GetTabNo());
2643 aRange.ParseAny(aText, rDoc, rDoc.GetAddressConvention());
2644 aText = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, ::formula::FormulaGrammar::CONV_OOO);
2646 else if (eType == SC_NAME_INPUT_NAMEDRANGE_GLOBAL)
2648 bForceGlobalName = true;
2651 SfxStringItem aPosItem( SID_CURRENTCELL, aText );
2652 SfxBoolItem aUnmarkItem( FN_PARAM_1, true ); // remove existing selection
2653 // FN_PARAM_2 reserved for AlignToCursor
2654 SfxBoolItem aForceGlobalName( FN_PARAM_3, bForceGlobalName );
2656 pViewSh->GetViewData().GetDispatcher().ExecuteList( SID_CURRENTCELL,
2657 SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
2658 { &aPosItem, &aUnmarkItem, &aForceGlobalName });
2663 else
2664 m_xWidget->set_entry_text(aPosStr);
2666 ReleaseFocus_Impl();
2668 if (bOpenManageNamesDialog)
2670 const sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
2671 if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
2673 SfxViewFrame& rViewFrm = pViewSh->GetViewFrame();
2674 SfxChildWindow* pWnd = rViewFrm.GetChildWindow( nId );
2675 ScModule::get()->SetRefDialog(nId, pWnd == nullptr);
2680 IMPL_LINK_NOARG(ScPosWnd, ActivateHdl, weld::ComboBox&, bool)
2682 DoEnter();
2683 return true;
2686 IMPL_LINK(ScPosWnd, KeyInputHdl, const KeyEvent&, rKEvt, bool)
2688 bool bHandled = true;
2690 switch (rKEvt.GetKeyCode().GetCode())
2692 case KEY_RETURN:
2693 bHandled = ActivateHdl(*m_xWidget);
2694 break;
2695 case KEY_ESCAPE:
2696 if (nTipVisible)
2698 // escape when the tip help is shown: only hide the tip
2699 HideTip();
2701 else
2703 if (!bFormulaMode)
2704 m_xWidget->set_entry_text(aPosStr);
2705 ReleaseFocus_Impl();
2707 break;
2708 default:
2709 bHandled = false;
2710 break;
2713 return bHandled || ChildKeyInput(rKEvt);
2716 IMPL_LINK_NOARG(ScPosWnd, OnAsyncGetFocus, void*, void)
2718 m_nAsyncGetFocusId = nullptr;
2719 m_xWidget->select_entry_region(0, -1);
2722 IMPL_LINK_NOARG(ScPosWnd, FocusInHdl, weld::Widget&, void)
2724 if (m_nAsyncGetFocusId)
2725 return;
2726 // do it async to defeat entry in combobox having its own ideas about the focus
2727 m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, ScPosWnd, OnAsyncGetFocus));
2730 IMPL_LINK_NOARG(ScPosWnd, FocusOutHdl, weld::Widget&, void)
2732 if (m_nAsyncGetFocusId)
2734 Application::RemoveUserEvent(m_nAsyncGetFocusId);
2735 m_nAsyncGetFocusId = nullptr;
2738 HideTip();
2741 void ScPosWnd::ReleaseFocus_Impl()
2743 HideTip();
2745 SfxViewShell* pCurSh = SfxViewShell::Current();
2746 ScInputHandler* pHdl = ScModule::get()->GetInputHdl(dynamic_cast<ScTabViewShell*>(pCurSh));
2747 if ( pHdl && pHdl->IsTopMode() )
2749 // Focus back in input row?
2750 ScInputWindow* pInputWin = pHdl->GetInputWindow();
2751 if (pInputWin)
2753 pInputWin->TextGrabFocus();
2754 return;
2758 // Set focus to active View
2759 if ( pCurSh )
2761 vcl::Window* pShellWnd = pCurSh->GetWindow();
2763 if ( pShellWnd )
2764 pShellWnd->GrabFocus();
2768 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */