Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / ui / app / inputwin.cxx
blob5896653ad0e1173b39f4659c5031aabe3a39f361
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 <algorithm>
22 #include "scitems.hxx"
23 #include <editeng/eeitem.hxx>
25 #include <sfx2/app.hxx>
26 #include <editeng/adjustitem.hxx>
27 #include <editeng/editview.hxx>
28 #include <editeng/editstat.hxx>
29 #include <editeng/frmdiritem.hxx>
30 #include <editeng/lspcitem.hxx>
31 #include <sfx2/bindings.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <sfx2/event.hxx>
35 #include <sfx2/imgmgr.hxx>
36 #include <stdlib.h>
37 #include <editeng/scriptspaceitem.hxx>
38 #include <editeng/scripttypeitem.hxx>
39 #include <vcl/cursor.hxx>
40 #include <vcl/help.hxx>
41 #include <vcl/settings.hxx>
42 #include <svl/stritem.hxx>
44 #include "inputwin.hxx"
45 #include "scmod.hxx"
46 #include "uiitems.hxx"
47 #include "global.hxx"
48 #include "scresid.hxx"
49 #include "sc.hrc"
50 #include "globstr.hrc"
51 #include "reffact.hxx"
52 #include "editutil.hxx"
53 #include "inputhdl.hxx"
54 #include "tabvwsh.hxx"
55 #include "document.hxx"
56 #include "docsh.hxx"
57 #include "appoptio.hxx"
58 #include "rangenam.hxx"
59 #include <formula/compiler.hrc>
60 #include "dbdata.hxx"
61 #include "rangeutl.hxx"
62 #include "docfunc.hxx"
63 #include "funcdesc.hxx"
64 #include "markdata.hxx"
65 #include <editeng/fontitem.hxx>
66 #include <com/sun/star/accessibility/XAccessible.hpp>
67 #include "AccessibleEditObject.hxx"
68 #include "AccessibleText.hxx"
69 #include <svtools/miscopt.hxx>
70 #include <comphelper/string.hxx>
71 #include <com/sun/star/frame/XLayoutManager.hpp>
73 #define THESIZE 1000000 // Should be more than enough!
74 #define TBX_WINDOW_HEIGHT 22 // in pixel - TODO: The same on all systems?
75 #define MULTILINE_BUTTON_WIDTH 20 // Width of the button which opens the multiline dropdown
76 #define LEFT_OFFSET 5
77 #define INPUTWIN_MULTILINES 6
78 const long BUTTON_OFFSET = 2; ///< space between input line and the button to expand / collapse
79 const long ADDITIONAL_BORDER = 1; ///< height of the line at the bottom
80 const long ADDITIONAL_SPACE = 4; ///< additional vertical space when the multiline edit has more lines
82 using com::sun::star::uno::Reference;
83 using com::sun::star::uno::UNO_QUERY;
85 using com::sun::star::frame::XLayoutManager;
86 using com::sun::star::beans::XPropertySet;
88 enum ScNameInputType
90 SC_NAME_INPUT_CELL,
91 SC_NAME_INPUT_RANGE,
92 SC_NAME_INPUT_NAMEDRANGE,
93 SC_NAME_INPUT_DATABASE,
94 SC_NAME_INPUT_ROW,
95 SC_NAME_INPUT_SHEET,
96 SC_NAME_INPUT_DEFINE,
97 SC_NAME_INPUT_BAD_NAME,
98 SC_NAME_INPUT_BAD_SELECTION,
99 SC_MANAGE_NAMES
102 ScTextWndBase::ScTextWndBase( vcl::Window* pParent, WinBits nStyle )
103 : Window ( pParent, nStyle )
105 if ( IsNativeControlSupported( ControlType::Editbox, ControlPart::Entire ) )
107 SetType( WINDOW_CALCINPUTLINE );
108 SetBorderStyle( WindowBorderStyle::NWF );
112 // class ScInputWindowWrapper
114 SFX_IMPL_CHILDWINDOW_WITHID(ScInputWindowWrapper,FID_INPUTLINE_STATUS)
116 ScInputWindowWrapper::ScInputWindowWrapper( vcl::Window* pParentP,
117 sal_uInt16 nId,
118 SfxBindings* pBindings,
119 SfxChildWinInfo* /* pInfo */ )
120 : SfxChildWindow( pParentP, nId )
122 VclPtr<ScInputWindow> pWin = VclPtr<ScInputWindow>::Create( pParentP, pBindings );
123 SetWindow( pWin );
125 pWin->Show();
127 pWin->SetSizePixel( pWin->CalcWindowSizePixel() );
129 SetAlignment(SfxChildAlignment::LOWESTTOP);
130 pBindings->Invalidate( FID_TOGGLEINPUTLINE );
134 * GetInfo is disposed of if there's a SFX_IMPL_TOOLBOX!
136 SfxChildWinInfo ScInputWindowWrapper::GetInfo() const
138 SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
139 return aInfo;
142 #define IMAGE(id) pImgMgr->SeekImage(id)
144 // class ScInputWindow
146 static VclPtr<ScTextWndBase> lcl_chooseRuntimeImpl( vcl::Window* pParent, SfxBindings* pBind )
148 ScTabViewShell* pViewSh = nullptr;
149 SfxDispatcher* pDisp = pBind->GetDispatcher();
150 if ( pDisp )
152 SfxViewFrame* pViewFrm = pDisp->GetFrame();
153 if ( pViewFrm )
154 pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
157 return VclPtr<ScInputBarGroup>::Create( pParent, pViewSh );
160 ScInputWindow::ScInputWindow( vcl::Window* pParent, SfxBindings* pBind ) :
161 // With WB_CLIPCHILDREN otherwise we get flickering
162 ToolBox ( pParent, WinBits(WB_CLIPCHILDREN) ),
163 aWndPos ( VclPtr<ScPosWnd>::Create(this) ),
164 pRuntimeWindow ( lcl_chooseRuntimeImpl( this, pBind ) ),
165 aTextWindow ( *pRuntimeWindow ),
166 pInputHdl ( nullptr ),
167 aTextOk ( ScResId( SCSTR_QHELP_BTNOK ) ), // Not always new as a Resource
168 aTextCancel ( ScResId( SCSTR_QHELP_BTNCANCEL ) ),
169 aTextSum ( ScResId( SCSTR_QHELP_BTNSUM ) ),
170 aTextEqual ( ScResId( SCSTR_QHELP_BTNEQUAL ) ),
171 mnMaxY (0),
172 bIsOkCancelMode ( false ),
173 bInResize ( false )
175 ScModule* pScMod = SC_MOD();
176 SfxImageManager* pImgMgr = SfxImageManager::GetImageManager(*pScMod);
178 // #i73615# don't rely on SfxViewShell::Current while constructing the input line
179 // (also for GetInputHdl below)
180 ScTabViewShell* pViewSh = nullptr;
181 SfxDispatcher* pDisp = pBind->GetDispatcher();
182 if ( pDisp )
184 SfxViewFrame* pViewFrm = pDisp->GetFrame();
185 if ( pViewFrm )
186 pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
188 OSL_ENSURE( pViewSh, "no view shell for input window" );
190 // Position window, 3 buttons, input window
191 InsertWindow (1, aWndPos.get(), ToolBoxItemBits::NONE, 0);
192 InsertSeparator (1);
193 InsertItem (SID_INPUT_FUNCTION, IMAGE(SID_INPUT_FUNCTION), ToolBoxItemBits::NONE, 2);
194 InsertItem (SID_INPUT_SUM, IMAGE(SID_INPUT_SUM), ToolBoxItemBits::NONE, 3);
195 InsertItem (SID_INPUT_EQUAL, IMAGE(SID_INPUT_EQUAL), ToolBoxItemBits::NONE, 4);
196 InsertSeparator (5);
197 InsertWindow (7, &aTextWindow, ToolBoxItemBits::NONE, 6);
199 aWndPos ->SetQuickHelpText(ScResId(SCSTR_QHELP_POSWND));
200 aWndPos ->SetHelpId (HID_INSWIN_POS);
201 aTextWindow.SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
202 aTextWindow.SetHelpId (HID_INSWIN_INPUT);
204 // No SetHelpText: the helptexts come from the Help
205 SetItemText (SID_INPUT_FUNCTION, ScResId(SCSTR_QHELP_BTNCALC));
206 SetHelpId (SID_INPUT_FUNCTION, HID_INSWIN_CALC);
208 SetItemText (SID_INPUT_SUM, aTextSum);
209 SetHelpId (SID_INPUT_SUM, HID_INSWIN_SUMME);
211 SetItemText (SID_INPUT_EQUAL, aTextEqual);
212 SetHelpId (SID_INPUT_EQUAL, HID_INSWIN_FUNC);
214 SetHelpId( HID_SC_INPUTWIN ); // For the whole input row
216 aWndPos ->Show();
217 aTextWindow.Show();
219 pInputHdl = SC_MOD()->GetInputHdl( pViewSh, false ); // use own handler even if ref-handler is set
220 if (pInputHdl)
221 pInputHdl->SetInputWindow( this );
223 if (pInputHdl && !pInputHdl->GetFormString().isEmpty())
225 // Switch over while the Function AutoPilot is active
226 // -> show content of the Function AutoPilot again
227 // Also show selection (remember at the InputHdl)
228 aTextWindow.SetTextString( pInputHdl->GetFormString() );
230 else if (pInputHdl && pInputHdl->IsInputMode())
232 // If the input row was hidden while editing (e.g. when editing a formula
233 // and then switching to another document or the help), display the text
234 // we just edited from the InputHandler
235 aTextWindow.SetTextString( pInputHdl->GetEditString() ); // Display text
236 if ( pInputHdl->IsTopMode() )
237 pInputHdl->SetMode( SC_INPUT_TABLE ); // Focus ends up at the bottom anyways
239 else if (pViewSh)
240 pViewSh->UpdateInputHandler(true); // Absolutely necessary update
242 pImgMgr->RegisterToolBox(this);
243 SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
246 ScInputWindow::~ScInputWindow()
248 disposeOnce();
251 void ScInputWindow::dispose()
253 bool bDown = ( ScGlobal::pSysLocale == nullptr ); // after Clear?
255 // if any view's input handler has a pointer to this input window, reset it
256 // (may be several ones, #74522#)
257 // member pInputHdl is not used here
259 if ( !bDown )
261 SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
262 while ( pSh )
264 ScInputHandler* pHdl = static_cast<ScTabViewShell*>(pSh)->GetInputHandler();
265 if ( pHdl && pHdl->GetInputWindow() == this )
267 pHdl->SetInputWindow( nullptr );
268 pHdl->StopInputWinEngine( false ); // reset pTopView pointer
270 pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
274 SfxImageManager::GetImageManager( *SC_MOD() )->ReleaseToolBox( this );
276 pRuntimeWindow.disposeAndClear();
277 aWndPos.disposeAndClear();
279 ToolBox::dispose();
282 void ScInputWindow::SetInputHandler( ScInputHandler* pNew )
284 // Is called in the Activate of the View ...
285 if ( pNew != pInputHdl )
287 // On Reload (last version) the pInputHdl is the InputHandler of the old, deleted
288 // ViewShell: so don't touch it here!
289 pInputHdl = pNew;
290 if (pInputHdl)
291 pInputHdl->SetInputWindow( this );
295 bool ScInputWindow::UseSubTotal(ScRangeList* pRangeList)
297 bool bSubTotal = false;
298 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
299 if ( pViewSh )
301 ScDocument* pDoc = pViewSh->GetViewData().GetDocument();
302 size_t nRangeCount (pRangeList->size());
303 size_t nRangeIndex (0);
304 while (!bSubTotal && nRangeIndex < nRangeCount)
306 const ScRange* pRange = (*pRangeList)[nRangeIndex];
307 if( pRange )
309 SCTAB nTabEnd(pRange->aEnd.Tab());
310 SCTAB nTab(pRange->aStart.Tab());
311 while (!bSubTotal && nTab <= nTabEnd)
313 SCROW nRowEnd(pRange->aEnd.Row());
314 SCROW nRow(pRange->aStart.Row());
315 while (!bSubTotal && nRow <= nRowEnd)
317 if (pDoc->RowFiltered(nRow, nTab))
318 bSubTotal = true;
319 else
320 ++nRow;
322 ++nTab;
325 ++nRangeIndex;
328 const ScDBCollection::NamedDBs& rDBs = pDoc->GetDBCollection()->getNamedDBs();
329 ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(), itrEnd = rDBs.end();
330 for (; !bSubTotal && itr != itrEnd; ++itr)
332 const ScDBData& rDB = **itr;
333 if (!rDB.HasAutoFilter())
334 continue;
336 nRangeIndex = 0;
337 while (!bSubTotal && nRangeIndex < nRangeCount)
339 const ScRange* pRange = (*pRangeList)[nRangeIndex];
340 if( pRange )
342 ScRange aDBArea;
343 rDB.GetArea(aDBArea);
344 if (aDBArea.Intersects(*pRange))
345 bSubTotal = true;
347 ++nRangeIndex;
351 return bSubTotal;
354 void ScInputWindow::Select()
356 ScModule* pScMod = SC_MOD();
357 ToolBox::Select();
359 switch ( GetCurItemId() )
361 case SID_INPUT_FUNCTION:
363 //! new method at ScModule to query if function autopilot is open
364 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
365 if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
367 pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
368 SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
370 // The Toolbox will be disabled anyways, so we don't need to switch here,
371 // regardless whether it succeeded or not!
372 // SetOkCancelMode();
375 break;
377 case SID_INPUT_CANCEL:
378 pScMod->InputCancelHandler();
379 SetSumAssignMode();
380 break;
382 case SID_INPUT_OK:
383 pScMod->InputEnterHandler();
384 SetSumAssignMode();
385 aTextWindow.Invalidate(); // Or else the Selection remains
386 break;
388 case SID_INPUT_SUM:
390 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
391 if ( pViewSh )
393 const ScMarkData& rMark = pViewSh->GetViewData().GetMarkData();
394 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
396 ScRangeList aMarkRangeList;
397 rMark.FillRangeListWithMarks( &aMarkRangeList, false );
398 ScDocument* pDoc = pViewSh->GetViewData().GetDocument();
400 // check if one of the marked ranges is empty
401 bool bEmpty = false;
402 const size_t nCount = aMarkRangeList.size();
403 for ( size_t i = 0; i < nCount; ++i )
405 const ScRange aRange( *aMarkRangeList[i] );
406 if ( pDoc->IsBlockEmpty( aRange.aStart.Tab(),
407 aRange.aStart.Col(), aRange.aStart.Row(),
408 aRange.aEnd.Col(), aRange.aEnd.Row() ) )
410 bEmpty = true;
411 break;
415 if ( bEmpty )
417 ScRangeList aRangeList;
418 const bool bDataFound = pViewSh->GetAutoSumArea( aRangeList );
419 if ( bDataFound )
421 ScAddress aAddr = aRangeList.back()->aEnd;
422 aAddr.IncRow();
423 const bool bSubTotal( UseSubTotal( &aRangeList ) );
424 pViewSh->EnterAutoSum( aRangeList, bSubTotal, aAddr );
427 else
429 const bool bSubTotal( UseSubTotal( &aMarkRangeList ) );
430 for ( size_t i = 0; i < nCount; ++i )
432 const ScRange aRange( *aMarkRangeList[i] );
433 const bool bSetCursor = ( i == nCount - 1 );
434 const bool bContinue = ( i != 0 );
435 if ( !pViewSh->AutoSum( aRange, bSubTotal, bSetCursor, bContinue ) )
437 pViewSh->MarkRange( aRange, false );
438 pViewSh->SetCursor( aRange.aEnd.Col(), aRange.aEnd.Row() );
439 const ScRangeList aRangeList;
440 ScAddress aAddr = aRange.aEnd;
441 aAddr.IncRow();
442 const OUString aFormula = pViewSh->GetAutoSumFormula(
443 aRangeList, bSubTotal, aAddr );
444 SetFuncString( aFormula );
445 break;
450 else // Only insert into input row
452 ScRangeList aRangeList;
453 const bool bDataFound = pViewSh->GetAutoSumArea( aRangeList );
454 const bool bSubTotal( UseSubTotal( &aRangeList ) );
455 ScAddress aAddr = pViewSh->GetViewData().GetCurPos();
456 const OUString aFormula = pViewSh->GetAutoSumFormula( aRangeList, bSubTotal, aAddr );
457 SetFuncString( aFormula );
459 if ( bDataFound && pScMod->IsEditMode() )
461 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
462 if ( pHdl )
464 pHdl->InitRangeFinder( aFormula );
466 //! SetSelection at the InputHandler?
467 //! Set bSelIsRef?
468 const sal_Int32 nOpen = aFormula.indexOf('(');
469 const sal_Int32 nLen = aFormula.getLength();
470 if ( nOpen != -1 && nLen > nOpen )
472 sal_uInt8 nAdd(1);
473 if (bSubTotal)
474 nAdd = 3;
475 ESelection aSel(0,nOpen+nAdd,0,nLen-1);
476 EditView* pTableView = pHdl->GetTableView();
477 if (pTableView)
478 pTableView->SetSelection(aSel);
479 EditView* pTopView = pHdl->GetTopView();
480 if (pTopView)
481 pTopView->SetSelection(aSel);
488 break;
490 case SID_INPUT_EQUAL:
492 aTextWindow.StartEditEngine();
493 if ( pScMod->IsEditMode() ) // Isn't if e.g. protected
495 aTextWindow.StartEditEngine();
497 sal_Int32 nStartPos = 1;
498 sal_Int32 nEndPos = 1;
500 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
501 if ( pViewSh )
503 const OUString& rString = aTextWindow.GetTextString();
504 const sal_Int32 nLen = rString.getLength();
506 ScDocument* pDoc = pViewSh->GetViewData().GetDocument();
507 CellType eCellType = pDoc->GetCellType( pViewSh->GetViewData().GetCurPos() );
508 switch ( eCellType )
510 case CELLTYPE_VALUE:
512 nEndPos = nLen + 1;
513 aTextWindow.SetTextString("=" + rString);
514 break;
516 case CELLTYPE_STRING:
517 case CELLTYPE_EDIT:
518 nStartPos = 0;
519 nEndPos = nLen;
520 break;
521 case CELLTYPE_FORMULA:
522 nEndPos = nLen;
523 break;
524 default:
525 aTextWindow.SetTextString("=");
526 break;
530 EditView* pView = aTextWindow.GetEditView();
531 if (pView)
533 pView->SetSelection( ESelection(0, nStartPos, 0, nEndPos) );
534 pScMod->InputChanged(pView);
535 SetOkCancelMode();
536 pView->SetEditEngineUpdateMode(true);
539 break;
544 void ScInputWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
546 ToolBox::Paint(rRenderContext, rRect);
548 // draw a line at the bottom to distinguish that from the grid
549 // (we have space for that thanks to ADDITIONAL_BORDER)
550 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
551 rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
553 Size aSize = GetSizePixel();
554 rRenderContext.DrawLine(Point(0, aSize.Height() - 1),
555 Point(aSize.Width() - 1, aSize.Height() - 1));
558 void ScInputWindow::Resize()
560 ToolBox::Resize();
562 aTextWindow.Resize();
563 Size aSize = GetSizePixel();
564 aSize.Height() = CalcWindowSizePixel().Height() + ADDITIONAL_BORDER;
565 ScInputBarGroup* pGroupBar = dynamic_cast<ScInputBarGroup*>(pRuntimeWindow.get());
566 if (pGroupBar)
568 // To ensure smooth display and prevent the items in the toolbar being
569 // repositioned ( vertically ) we lock the vertical positioning of the toolbox
570 // items when we are displaying > 1 line.
571 // So, we need to adjust the height of the toolbox accordingly. If we don't
572 // then the largest item ( e.g. the GroupBar window ) will actually be
573 // positioned such that the toolbar will cut off the bottom of that item
574 if (pGroupBar->GetNumLines() > 1)
575 aSize.Height() += pGroupBar->GetVertOffset() + ADDITIONAL_SPACE;
577 SetSizePixel(aSize);
578 Invalidate();
581 void ScInputWindow::SetFuncString( const OUString& rString, bool bDoEdit )
583 //! new method at ScModule to query if function autopilot is open
584 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
585 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
586 aTextWindow.StartEditEngine();
588 ScModule* pScMod = SC_MOD();
589 if ( pScMod->IsEditMode() )
591 if ( bDoEdit )
592 aTextWindow.GrabFocus();
593 aTextWindow.SetTextString( rString );
594 EditView* pView = aTextWindow.GetEditView();
595 if (pView)
597 sal_Int32 nLen = rString.getLength();
599 if ( nLen > 0 )
601 nLen--;
602 pView->SetSelection( ESelection( 0, nLen, 0, nLen ) );
605 pScMod->InputChanged(pView);
606 if ( bDoEdit )
607 SetOkCancelMode(); // Not the case if immediately followed by Enter/Cancel
609 pView->SetEditEngineUpdateMode(true);
614 void ScInputWindow::SetPosString( const OUString& rStr )
616 aWndPos->SetPos( rStr );
619 void ScInputWindow::SetTextString( const OUString& rString )
621 if (rString.getLength() <= 32767)
622 aTextWindow.SetTextString(rString);
623 else
624 aTextWindow.SetTextString(rString.copy(0, 32767));
627 void ScInputWindow::SetOkCancelMode()
629 //! new method at ScModule to query if function autopilot is open
630 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
631 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
633 ScModule* pScMod = SC_MOD();
634 SfxImageManager* pImgMgr = SfxImageManager::GetImageManager(*pScMod);
635 if (!bIsOkCancelMode)
637 RemoveItem( 3 ); // Remove SID_INPUT_SUM and SID_INPUT_EQUAL
638 RemoveItem( 3 );
639 InsertItem( SID_INPUT_CANCEL, IMAGE( SID_INPUT_CANCEL ), ToolBoxItemBits::NONE, 3 );
640 InsertItem( SID_INPUT_OK, IMAGE( SID_INPUT_OK ), ToolBoxItemBits::NONE, 4 );
641 SetItemText ( SID_INPUT_CANCEL, aTextCancel );
642 SetHelpId ( SID_INPUT_CANCEL, HID_INSWIN_CANCEL );
643 SetItemText ( SID_INPUT_OK, aTextOk );
644 SetHelpId ( SID_INPUT_OK, HID_INSWIN_OK );
645 bIsOkCancelMode = true;
649 void ScInputWindow::SetSumAssignMode()
651 //! new method at ScModule to query if function autopilot is open
652 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
653 EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
655 ScModule* pScMod = SC_MOD();
656 SfxImageManager* pImgMgr = SfxImageManager::GetImageManager(*pScMod);
657 if (bIsOkCancelMode)
659 // Remove SID_INPUT_CANCEL, and SID_INPUT_OK
660 RemoveItem( 3 );
661 RemoveItem( 3 );
662 InsertItem( SID_INPUT_SUM, IMAGE( SID_INPUT_SUM ), ToolBoxItemBits::NONE, 3 );
663 InsertItem( SID_INPUT_EQUAL, IMAGE( SID_INPUT_EQUAL ), ToolBoxItemBits::NONE, 4 );
664 SetItemText ( SID_INPUT_SUM, aTextSum );
665 SetHelpId ( SID_INPUT_SUM, HID_INSWIN_SUMME );
666 SetItemText ( SID_INPUT_EQUAL, aTextEqual );
667 SetHelpId ( SID_INPUT_EQUAL, HID_INSWIN_FUNC );
668 bIsOkCancelMode = false;
670 SetFormulaMode(false); // No editing -> no formula
674 void ScInputWindow::SetFormulaMode( bool bSet )
676 aWndPos->SetFormulaMode(bSet);
677 aTextWindow.SetFormulaMode(bSet);
680 void ScInputWindow::SetText( const OUString& rString )
682 ToolBox::SetText(rString);
685 OUString ScInputWindow::GetText() const
687 return ToolBox::GetText();
690 bool ScInputWindow::IsInputActive()
692 return aTextWindow.IsInputActive();
695 EditView* ScInputWindow::GetEditView()
697 return aTextWindow.GetEditView();
700 void ScInputWindow::MakeDialogEditView()
702 aTextWindow.MakeDialogEditView();
705 void ScInputWindow::StopEditEngine( bool bAll )
707 aTextWindow.StopEditEngine( bAll );
710 void ScInputWindow::TextGrabFocus()
712 aTextWindow.TextGrabFocus();
715 void ScInputWindow::TextInvalidate()
717 aTextWindow.Invalidate();
720 void ScInputWindow::SwitchToTextWin()
722 // used for shift-ctrl-F2
724 aTextWindow.StartEditEngine();
725 if ( SC_MOD()->IsEditMode() )
727 aTextWindow.TextGrabFocus();
728 EditView* pView = aTextWindow.GetEditView();
729 if (pView)
731 sal_Int32 nPara = pView->GetEditEngine()->GetParagraphCount() ? ( pView->GetEditEngine()->GetParagraphCount() - 1 ) : 0;
732 sal_Int32 nLen = pView->GetEditEngine()->GetTextLen( nPara );
733 ESelection aSel( nPara, nLen, nPara, nLen );
734 pView->SetSelection( aSel ); // set cursor to end of text
739 void ScInputWindow::PosGrabFocus()
741 aWndPos->GrabFocus();
744 void ScInputWindow::EnableButtons( bool bEnable )
746 // when enabling buttons, always also enable the input window itself
747 if ( bEnable && !IsEnabled() )
748 Enable();
750 EnableItem( SID_INPUT_FUNCTION, bEnable );
751 EnableItem( bIsOkCancelMode ? SID_INPUT_CANCEL : SID_INPUT_SUM, bEnable );
752 EnableItem( bIsOkCancelMode ? SID_INPUT_OK : SID_INPUT_EQUAL, bEnable );
753 // Invalidate();
756 void ScInputWindow::StateChanged( StateChangedType nType )
758 ToolBox::StateChanged( nType );
760 if ( nType == StateChangedType::InitShow ) Resize();
763 void ScInputWindow::DataChanged( const DataChangedEvent& rDCEvt )
765 if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
767 // update item images
768 ScModule* pScMod = SC_MOD();
769 SfxImageManager* pImgMgr = SfxImageManager::GetImageManager(*pScMod);
771 // IMAGE macro uses pScMod, pImgMg
772 SetItemImage( SID_INPUT_FUNCTION, IMAGE( SID_INPUT_FUNCTION ) );
773 if ( bIsOkCancelMode )
775 SetItemImage( SID_INPUT_CANCEL, IMAGE( SID_INPUT_CANCEL ) );
776 SetItemImage( SID_INPUT_OK, IMAGE( SID_INPUT_OK ) );
778 else
780 SetItemImage( SID_INPUT_SUM, IMAGE( SID_INPUT_SUM ) );
781 SetItemImage( SID_INPUT_EQUAL, IMAGE( SID_INPUT_EQUAL ) );
785 ToolBox::DataChanged( rDCEvt );
788 bool ScInputWindow::IsPointerAtResizePos()
790 if ( GetOutputSizePixel().Height() - GetPointerPosPixel().Y() <= 4 )
791 return true;
792 else
793 return false;
796 void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
798 Point aPosPixel = GetPointerPosPixel();
800 ScInputBarGroup* pGroupBar = dynamic_cast<ScInputBarGroup*>(pRuntimeWindow.get());
802 if (bInResize || IsPointerAtResizePos())
803 SetPointer(Pointer(PointerStyle::WindowSSize));
804 else
805 SetPointer(Pointer(PointerStyle::Arrow));
807 if (bInResize)
809 // detect direction
810 long nResizeThreshold = ((long)TBX_WINDOW_HEIGHT * 0.7);
811 bool bResetPointerPos = false;
813 // Detect attempt to expand toolbar too much
814 if (aPosPixel.Y() >= mnMaxY)
816 bResetPointerPos = true;
817 aPosPixel.Y() = mnMaxY;
818 } // or expanding down
819 else if (GetOutputSizePixel().Height() - aPosPixel.Y() < -nResizeThreshold)
821 pGroupBar->IncrementVerticalSize();
822 bResetPointerPos = true;
823 } // or shrinking up
824 else if ((GetOutputSizePixel().Height() - aPosPixel.Y()) > nResizeThreshold)
826 bResetPointerPos = true;
827 pGroupBar->DecrementVerticalSize();
830 if (bResetPointerPos)
832 aPosPixel.Y() = GetOutputSizePixel().Height();
833 SetPointerPosPixel(aPosPixel);
837 ToolBox::MouseMove(rMEvt);
840 void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
842 if (rMEvt.IsLeft())
844 if (IsPointerAtResizePos())
846 // Don't leave the mouse pointer leave *this* window
847 CaptureMouse();
848 bInResize = true;
850 // find the height of the gridwin, we don't wan't to be
851 // able to expand the toolbar too far so we need to
852 // calculate an upper limit
853 // I'd prefer to leave at least a single column header and a
854 // row but I don't know how to get that value in pixels.
855 // Use TBX_WINDOW_HEIGHT for the moment
856 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
857 mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP) + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TBX_WINDOW_HEIGHT;
861 ToolBox::MouseButtonDown( rMEvt );
863 void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )
865 ReleaseMouse();
866 if ( rMEvt.IsLeft() )
868 bInResize = false;
869 mnMaxY = 0;
872 ToolBox::MouseButtonUp( rMEvt );
875 ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
876 : ScTextWndBase(pParent, WinBits(WB_HIDE | WB_TABSTOP)),
877 maTextWnd(VclPtr<ScTextWnd>::Create(this, pViewSh)),
878 maButton(VclPtr<ImageButton>::Create(this, WB_TABSTOP | WB_RECTSTYLE | WB_SMALLSTYLE)),
879 maScrollbar(VclPtr<ScrollBar>::Create(this, WB_TABSTOP | WB_VERT | WB_DRAG)),
880 mnVertOffset(0)
882 maTextWnd->Show();
883 maTextWnd->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
884 maTextWnd->SetHelpId(HID_INSWIN_INPUT);
886 Size aSize(MULTILINE_BUTTON_WIDTH, maTextWnd->GetPixelHeightForLines(1));
888 maButton->SetClickHdl(LINK(this, ScInputBarGroup, ClickHdl));
889 maButton->SetSizePixel(aSize);
890 maButton->Enable();
891 maButton->SetSymbol(SymbolType::SPIN_DOWN);
892 maButton->SetQuickHelpText(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
893 maButton->Show();
895 maScrollbar->SetSizePixel(aSize);
896 maScrollbar->SetScrollHdl(LINK(this, ScInputBarGroup, Impl_ScrollHdl));
899 ScInputBarGroup::~ScInputBarGroup()
901 disposeOnce();
904 void ScInputBarGroup::dispose()
906 maTextWnd.disposeAndClear();
907 maButton.disposeAndClear();
908 maScrollbar.disposeAndClear();
909 ScTextWndBase::dispose();
912 void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
914 maTextWnd->InsertAccessibleTextData( rTextData );
917 void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
919 maTextWnd->RemoveAccessibleTextData( rTextData );
922 const OUString& ScInputBarGroup::GetTextString() const
924 return maTextWnd->GetTextString();
927 void ScInputBarGroup::SetTextString( const OUString& rString )
929 maTextWnd->SetTextString(rString);
932 void ScInputBarGroup::Resize()
934 vcl::Window*w = GetParent();
935 ScInputWindow *pParent;
936 pParent = dynamic_cast<ScInputWindow*>(w);
938 if (pParent == nullptr)
940 OSL_FAIL("The parent window pointer pParent is null");
941 return;
944 long nWidth = pParent->GetSizePixel().Width();
945 long nLeft = GetPosPixel().X();
947 Size aSize = GetSizePixel();
948 aSize.Width() = std::max(long(nWidth - nLeft - LEFT_OFFSET), long(0));
950 maScrollbar->SetPosPixel(Point( aSize.Width() - maButton->GetSizePixel().Width(), maButton->GetSizePixel().Height() ) );
952 Size aTmpSize( aSize );
953 aTmpSize.Width() = aTmpSize.Width() - maButton->GetSizePixel().Width() - BUTTON_OFFSET;
954 maTextWnd->SetSizePixel(aTmpSize);
956 maTextWnd->Resize();
958 aSize.Height() = maTextWnd->GetSizePixel().Height();
960 SetSizePixel(aSize);
962 if (maTextWnd->GetNumLines() > 1)
964 maButton->SetSymbol( SymbolType::SPIN_UP );
965 maButton->SetQuickHelpText( ScResId( SCSTR_QHELP_COLLAPSE_FORMULA ) );
966 Size scrollSize = maButton->GetSizePixel();
967 scrollSize.Height() = maTextWnd->GetSizePixel().Height() - maButton->GetSizePixel().Height();
968 maScrollbar->SetSizePixel( scrollSize );
970 Size aOutSz = maTextWnd->GetOutputSize();
972 maScrollbar->SetVisibleSize( aOutSz.Height() );
973 maScrollbar->SetPageSize( aOutSz.Height() );
974 maScrollbar->SetLineSize( maTextWnd->GetTextHeight() );
975 maScrollbar->SetRange( Range( 0, maTextWnd->GetEditEngTxtHeight() ) );
977 maScrollbar->Resize();
978 maScrollbar->Show();
980 else
982 maButton->SetSymbol( SymbolType::SPIN_DOWN );
983 maButton->SetQuickHelpText( ScResId( SCSTR_QHELP_EXPAND_FORMULA ) );
984 maScrollbar->Hide();
987 maButton->SetPosPixel(Point(aSize.Width() - maButton->GetSizePixel().Width(), 0));
989 Invalidate();
992 void ScInputBarGroup::StopEditEngine( bool bAll )
994 maTextWnd->StopEditEngine( bAll );
997 void ScInputBarGroup::StartEditEngine()
999 maTextWnd->StartEditEngine();
1002 void ScInputBarGroup::MakeDialogEditView()
1004 maTextWnd->MakeDialogEditView();
1007 EditView* ScInputBarGroup::GetEditView()
1009 return maTextWnd->GetEditView();
1012 bool ScInputBarGroup::IsInputActive()
1014 return maTextWnd->IsInputActive();
1017 void ScInputBarGroup::SetFormulaMode(bool bSet)
1019 maTextWnd->SetFormulaMode(bSet);
1022 void ScInputBarGroup::IncrementVerticalSize()
1024 maTextWnd->SetNumLines( maTextWnd->GetNumLines() + 1 );
1025 TriggerToolboxLayout();
1028 void ScInputBarGroup::DecrementVerticalSize()
1030 if ( maTextWnd->GetNumLines() > 1 )
1032 maTextWnd->SetNumLines( maTextWnd->GetNumLines() - 1 );
1033 TriggerToolboxLayout();
1037 IMPL_LINK_NOARG_TYPED(ScInputBarGroup, ClickHdl, Button*, void)
1039 vcl::Window* w = GetParent();
1040 ScInputWindow* pParent;
1041 pParent = dynamic_cast<ScInputWindow*>(w);
1043 if (pParent == nullptr)
1045 OSL_FAIL("The parent window pointer pParent is null");
1046 return;
1048 if (maTextWnd->GetNumLines() > 1)
1050 maTextWnd->SetNumLines(1);
1052 else
1054 maTextWnd->SetNumLines(maTextWnd->GetLastNumExpandedLines());
1056 TriggerToolboxLayout();
1058 // Restore focus to input line(s) if necessary
1059 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1060 if ( pHdl && pHdl->IsTopMode() )
1061 maTextWnd->GrabFocus();
1064 void ScInputBarGroup::TriggerToolboxLayout()
1066 vcl::Window *w=GetParent();
1067 ScInputWindow &rParent = dynamic_cast<ScInputWindow&>(*w);
1068 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1070 // Capture the vertical position of this window in the toolbar, when we increase
1071 // the size of the toolbar to accommodate expanded line input we need to take this
1072 // into account
1073 if ( !mnVertOffset )
1074 mnVertOffset = rParent.GetItemPosRect( rParent.GetItemCount() - 1 ).Top();
1076 if ( pViewFrm )
1078 Reference< css::beans::XPropertySet > xPropSet( pViewFrm->GetFrame().GetFrameInterface(), UNO_QUERY );
1079 Reference< css::frame::XLayoutManager > xLayoutManager;
1081 if ( xPropSet.is() )
1083 css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
1084 aValue >>= xLayoutManager;
1087 if ( xLayoutManager.is() )
1089 if ( maTextWnd->GetNumLines() > 1)
1090 rParent.SetToolbarLayoutMode( TBX_LAYOUT_LOCKVERT );
1091 else
1092 rParent.SetToolbarLayoutMode( TBX_LAYOUT_NORMAL );
1093 xLayoutManager->lock();
1094 DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr, AllSettingsFlags::STYLE );
1096 // this basically will trigger the reposititioning of the
1097 // items in the toolbar from ImplFormat ( which is controlled by
1098 // mnWinHeight ) which in turn is updated in ImplCalcItem which is
1099 // controlled by mbCalc. Additionally the ImplFormat above is
1100 // controlled via mbFormat. It seems the easiest way to get these
1101 // booleans set is to send in the fake event below.
1102 rParent.DataChanged( aFakeUpdate);
1104 // highest item in toolbar will have been calculated via the
1105 // event above. Call resize on InputBar to pick up the height
1106 // change
1107 rParent.Resize();
1109 // unlock relayouts the toolbars in the 4 quadrants
1110 xLayoutManager->unlock();
1115 IMPL_LINK_NOARG_TYPED(ScInputBarGroup, Impl_ScrollHdl, ScrollBar*, void)
1117 maTextWnd->DoScroll();
1120 void ScInputBarGroup::TextGrabFocus()
1122 maTextWnd->TextGrabFocus();
1125 void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const Rectangle& rRect )
1127 EditView* pView = GetEditView();
1128 if (pView)
1130 if (mbInvalidate)
1132 pView->Invalidate();
1133 mbInvalidate = false;
1135 pEditView->Paint(rRect, &rRenderContext);
1139 EditView* ScTextWnd::GetEditView()
1141 if ( !pEditView )
1142 InitEditEngine();
1143 return pEditView;
1146 long ScTextWnd::GetPixelHeightForLines(long nLines)
1148 // add padding ( for the borders of the window )
1149 return ( nLines * LogicToPixel( Size( 0, GetTextHeight() ) ).Height() ) + mnBorderHeight;
1152 void ScTextWnd::SetNumLines(long nLines)
1154 mnLines = nLines;
1155 if ( nLines > 1 )
1157 mnLastExpandedLines = nLines;
1158 Resize();
1162 void ScTextWnd::Resize()
1164 // Only Height is recalculated here, Width is applied from
1165 // parent/container window
1166 Size aTextBoxSize = GetSizePixel();
1168 aTextBoxSize.Height() = GetPixelHeightForLines( mnLines );
1169 SetSizePixel( aTextBoxSize );
1171 if (pEditView)
1173 Size aOutputSize = GetOutputSizePixel();
1174 Rectangle aOutputArea = PixelToLogic( Rectangle( Point(), aOutputSize ));
1175 pEditView->SetOutputArea( aOutputArea );
1177 // Don't leave an empty area at the bottom if we can move the text down.
1178 long nMaxVisAreaTop = pEditEngine->GetTextHeight() - aOutputArea.GetHeight();
1179 if (pEditView->GetVisArea().Top() > nMaxVisAreaTop)
1181 pEditView->Scroll(0, pEditView->GetVisArea().Top() - nMaxVisAreaTop);
1184 pEditEngine->SetPaperSize( PixelToLogic( Size( aOutputSize.Width(), 10000 ) ) );
1187 SetScrollBarRange();
1190 long ScTextWnd::GetEditEngTxtHeight()
1192 return pEditView ? pEditView->GetEditEngine()->GetTextHeight() : 0;
1195 void ScTextWnd::SetScrollBarRange()
1197 if ( pEditView )
1199 ScrollBar& rVBar = mrGroupBar.GetScrollBar();
1200 rVBar.SetRange( Range( 0, GetEditEngTxtHeight() ) );
1201 long currentDocPos = pEditView->GetVisArea().TopLeft().Y();
1202 rVBar.SetThumbPos( currentDocPos );
1206 void ScTextWnd::DoScroll()
1208 if ( pEditView )
1210 ScrollBar& rVBar = mrGroupBar.GetScrollBar();
1211 long currentDocPos = pEditView->GetVisArea().TopLeft().Y();
1212 long nDiff = currentDocPos - rVBar.GetThumbPos();
1213 pEditView->Scroll( 0, nDiff );
1214 currentDocPos = pEditView->GetVisArea().TopLeft().Y();
1215 rVBar.SetThumbPos( currentDocPos );
1219 void ScTextWnd::StartEditEngine()
1221 // Don't activate if we're a modal dialog ourselves (Doc-modal dialog)
1222 SfxObjectShell* pObjSh = SfxObjectShell::Current();
1223 if ( pObjSh && pObjSh->IsInModalMode() )
1224 return;
1226 if ( !pEditView || !pEditEngine )
1228 InitEditEngine();
1231 SC_MOD()->SetInputMode( SC_INPUT_TOP );
1233 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1234 if (pViewFrm)
1235 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1238 static void lcl_ExtendEditFontAttribs( SfxItemSet& rSet )
1240 const SfxPoolItem& rFontItem = rSet.Get( EE_CHAR_FONTINFO );
1241 rSet.Put( rFontItem, EE_CHAR_FONTINFO_CJK );
1242 rSet.Put( rFontItem, EE_CHAR_FONTINFO_CTL );
1243 const SfxPoolItem& rHeightItem = rSet.Get( EE_CHAR_FONTHEIGHT );
1244 rSet.Put( rHeightItem, EE_CHAR_FONTHEIGHT_CJK );
1245 rSet.Put( rHeightItem, EE_CHAR_FONTHEIGHT_CTL );
1246 const SfxPoolItem& rWeightItem = rSet.Get( EE_CHAR_WEIGHT );
1247 rSet.Put( rWeightItem, EE_CHAR_WEIGHT_CJK );
1248 rSet.Put( rWeightItem, EE_CHAR_WEIGHT_CTL );
1249 const SfxPoolItem& rItalicItem = rSet.Get( EE_CHAR_ITALIC );
1250 rSet.Put( rItalicItem, EE_CHAR_ITALIC_CJK );
1251 rSet.Put( rItalicItem, EE_CHAR_ITALIC_CTL );
1252 const SfxPoolItem& rLangItem = rSet.Get( EE_CHAR_LANGUAGE );
1253 rSet.Put( rLangItem, EE_CHAR_LANGUAGE_CJK );
1254 rSet.Put( rLangItem, EE_CHAR_LANGUAGE_CTL );
1257 static void lcl_ModifyRTLDefaults( SfxItemSet& rSet )
1259 rSet.Put( SvxAdjustItem( SVX_ADJUST_RIGHT, EE_PARA_JUST ) );
1261 // always using rtl writing direction would break formulas
1262 //rSet.Put( SvxFrameDirectionItem( FRMDIR_HORI_RIGHT_TOP, EE_PARA_WRITINGDIR ) );
1264 // PaperSize width is limited to USHRT_MAX in RTL mode (because of EditEngine's
1265 // sal_uInt16 values in EditLine), so the text may be wrapped and line spacing must be
1266 // increased to not see the beginning of the next line.
1267 SvxLineSpacingItem aItem( SVX_LINESPACE_TWO_LINES, EE_PARA_SBL );
1268 aItem.SetPropLineSpace( 200 );
1269 rSet.Put( aItem );
1272 static void lcl_ModifyRTLVisArea( EditView* pEditView )
1274 Rectangle aVisArea = pEditView->GetVisArea();
1275 Size aPaper = pEditView->GetEditEngine()->GetPaperSize();
1276 long nDiff = aPaper.Width() - aVisArea.Right();
1277 aVisArea.Left() += nDiff;
1278 aVisArea.Right() += nDiff;
1279 pEditView->SetVisArea(aVisArea);
1282 void ScTextWnd::InitEditEngine()
1284 ScFieldEditEngine* pNew;
1285 ScTabViewShell* pViewSh = GetViewShell();
1286 ScDocShell* pDocSh = nullptr;
1287 if ( pViewSh )
1289 pDocSh = pViewSh->GetViewData().GetDocShell();
1290 ScDocument* pDoc = pViewSh->GetViewData().GetDocument();
1291 pNew = new ScFieldEditEngine(pDoc, pDoc->GetEnginePool(), pDoc->GetEditPool());
1293 else
1294 pNew = new ScFieldEditEngine(nullptr, EditEngine::CreatePool(), nullptr, true);
1295 pNew->SetExecuteURL( false );
1296 pEditEngine = pNew;
1298 Size barSize=GetSizePixel();
1299 pEditEngine->SetUpdateMode( false );
1300 pEditEngine->SetPaperSize( PixelToLogic(Size(barSize.Width(),10000)) );
1301 pEditEngine->SetWordDelimiters(
1302 ScEditUtil::ModifyDelimiters( pEditEngine->GetWordDelimiters() ) );
1303 pEditEngine->SetReplaceLeadingSingleQuotationMark( false );
1305 UpdateAutoCorrFlag();
1308 SfxItemSet* pSet = new SfxItemSet( pEditEngine->GetEmptyItemSet() );
1309 EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
1310 lcl_ExtendEditFontAttribs( *pSet );
1311 // turn off script spacing to match DrawText output
1312 pSet->Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
1313 if ( bIsRTL )
1314 lcl_ModifyRTLDefaults( *pSet );
1315 pEditEngine->SetDefaults( pSet );
1318 // If the Cell contains URLFields, they need to be taken over into the entry row,
1319 // or else the position is not correct anymore
1320 bool bFilled = false;
1321 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1322 if ( pHdl ) //! Test if it's the right InputHdl?
1323 bFilled = pHdl->GetTextAndFields( *pEditEngine );
1325 pEditEngine->SetUpdateMode( true );
1327 // aString is the truth ...
1328 if (bFilled && pEditEngine->GetText() == aString)
1329 Invalidate(); // Repaint for (filled) Field
1330 else
1331 pEditEngine->SetText(aString); // At least the right text then
1333 pEditView = new EditView( pEditEngine, this );
1334 pEditView->SetInsertMode(bIsInsertMode);
1336 // Text from Clipboard is taken over as ASCII in a single row
1337 EVControlBits n = pEditView->GetControlWord();
1338 pEditView->SetControlWord( n | EVControlBits::SINGLELINEPASTE );
1340 pEditEngine->InsertView( pEditView, EE_APPEND );
1342 Resize();
1344 if ( bIsRTL )
1345 lcl_ModifyRTLVisArea( pEditView );
1347 pEditEngine->SetModifyHdl(LINK(this, ScTextWnd, ModifyHdl));
1348 pEditEngine->SetNotifyHdl(LINK(this, ScTextWnd, NotifyHdl));
1350 if (!maAccTextDatas.empty())
1351 maAccTextDatas.back()->StartEdit();
1353 // as long as EditEngine and DrawText sometimes differ for CTL text,
1354 // repaint now to have the EditEngine's version visible
1355 if (pDocSh)
1357 ScDocument& rDoc = pDocSh->GetDocument(); // any document
1358 SvtScriptType nScript = rDoc.GetStringScriptType( aString );
1359 if ( nScript & SvtScriptType::COMPLEX )
1360 Invalidate();
1364 ScTextWnd::ScTextWnd(ScInputBarGroup* pParent, ScTabViewShell* pViewSh)
1365 : ScTextWndBase(pParent, WinBits(WB_HIDE | WB_BORDER)),
1366 DragSourceHelper(this),
1367 pEditEngine (nullptr),
1368 pEditView (nullptr),
1369 bIsInsertMode(true),
1370 bFormulaMode (false),
1371 bInputMode (false),
1372 mpViewShell(pViewSh),
1373 mrGroupBar(*pParent),
1374 mnLines(1),
1375 mnLastExpandedLines(INPUTWIN_MULTILINES),
1376 mbInvalidate(false)
1378 EnableRTL(false); // EditEngine can't be used with VCL EnableRTL
1380 bIsRTL = AllSettings::GetLayoutRTL();
1382 // always use application font, so a font with cjk chars can be installed
1383 vcl::Font aAppFont = GetFont();
1384 aTextFont = aAppFont;
1385 aTextFont.SetFontSize(PixelToLogic(aAppFont.GetFontSize(), MAP_TWIP)); // AppFont is in pixels
1387 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1389 Color aBgColor = rStyleSettings.GetWindowColor();
1390 Color aTxtColor = rStyleSettings.GetWindowTextColor();
1392 aTextFont.SetTransparent(true);
1393 aTextFont.SetFillColor(aBgColor);
1394 aTextFont.SetColor(aTxtColor);
1395 aTextFont.SetWeight(WEIGHT_NORMAL);
1397 Size aSize(1,TBX_WINDOW_HEIGHT);
1398 Size aMinEditSize( Edit::GetMinimumEditSize() );
1399 if( aMinEditSize.Height() > aSize.Height() )
1400 aSize.Height() = aMinEditSize.Height();
1402 SetSizePixel(aSize);
1403 SetBackground(aBgColor);
1404 SetLineColor(COL_BLACK);
1405 SetMapMode(MAP_TWIP);
1406 SetPointer(PointerStyle::Text);
1407 SetFont(aTextFont);
1409 Size aBorder;
1410 aBorder = CalcWindowSize(aBorder);
1411 mnBorderHeight = aBorder.Height();
1414 ScTextWnd::~ScTextWnd()
1416 disposeOnce();
1419 void ScTextWnd::dispose()
1421 while (!maAccTextDatas.empty()) {
1422 maAccTextDatas.back()->Dispose();
1424 delete pEditView;
1425 pEditView = nullptr;
1426 delete pEditEngine;
1427 pEditEngine = nullptr;
1429 ScTextWndBase::dispose();
1432 void ScTextWnd::MouseMove( const MouseEvent& rMEvt )
1434 if (pEditView)
1435 pEditView->MouseMove( rMEvt );
1438 void ScTextWnd::MouseButtonDown( const MouseEvent& rMEvt )
1440 if (!HasFocus())
1442 StartEditEngine();
1443 if ( SC_MOD()->IsEditMode() )
1444 GrabFocus();
1447 if (pEditView)
1449 pEditView->SetEditEngineUpdateMode( true );
1450 pEditView->MouseButtonDown( rMEvt );
1454 void ScTextWnd::MouseButtonUp( const MouseEvent& rMEvt )
1456 if (pEditView)
1457 if (pEditView->MouseButtonUp( rMEvt ))
1459 if ( rMEvt.IsMiddle() &&
1460 GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
1462 // EditView may have pasted from selection
1463 SC_MOD()->InputChanged( pEditView );
1465 else
1466 SC_MOD()->InputSelection( pEditView );
1470 void ScTextWnd::Command( const CommandEvent& rCEvt )
1472 bInputMode = true;
1473 CommandEventId nCommand = rCEvt.GetCommand();
1474 if ( pEditView /* && nCommand == CommandEventId::StartDrag */ )
1476 ScModule* pScMod = SC_MOD();
1477 ScTabViewShell* pStartViewSh = ScTabViewShell::GetActiveViewShell();
1479 // don't modify the font defaults here - the right defaults are
1480 // already set in StartEditEngine when the EditEngine is created
1482 // Prevent that the EditView is lost when switching between Views
1483 pScMod->SetInEditCommand( true );
1484 pEditView->Command( rCEvt );
1485 pScMod->SetInEditCommand( false );
1487 // CommandEventId::StartDrag does not mean by far that the content was actually changed,
1488 // so don't trigger an InputChanged.
1489 //! Detect if dragged with Move or forbid Drag&Move somehow
1491 if ( nCommand == CommandEventId::StartDrag )
1493 // Is dragged onto another View?
1494 ScTabViewShell* pEndViewSh = ScTabViewShell::GetActiveViewShell();
1495 if ( pEndViewSh != pStartViewSh && pStartViewSh != nullptr )
1497 ScViewData& rViewData = pStartViewSh->GetViewData();
1498 ScInputHandler* pHdl = pScMod->GetInputHdl( pStartViewSh );
1499 if ( pHdl && rViewData.HasEditView( rViewData.GetActivePart() ) )
1501 pHdl->CancelHandler();
1502 rViewData.GetView()->ShowCursor(); // Missing for KillEditView, due to being inactive
1506 else if ( nCommand == CommandEventId::CursorPos )
1508 // don't call InputChanged for CommandEventId::CursorPos
1510 else if ( nCommand == CommandEventId::InputLanguageChange )
1512 // #i55929# Font and font size state depends on input language if nothing is selected,
1513 // so the slots have to be invalidated when the input language is changed.
1515 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1516 if (pViewFrm)
1518 SfxBindings& rBindings = pViewFrm->GetBindings();
1519 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
1520 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
1523 else if ( nCommand == CommandEventId::Wheel )
1525 //don't call InputChanged for CommandEventId::Wheel
1527 else if ( nCommand == CommandEventId::Swipe )
1529 //don't call InputChanged for CommandEventId::Swipe
1531 else
1532 SC_MOD()->InputChanged( pEditView );
1534 else
1535 Window::Command(rCEvt); // Or else let the base class handle it...
1537 bInputMode = false;
1540 void ScTextWnd::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
1542 if ( pEditView )
1544 CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true );
1545 pEditView->Command( aDragEvent );
1547 // handling of d&d to different view (CancelHandler) can't be done here,
1548 // because the call returns before d&d is complete.
1552 void ScTextWnd::KeyInput(const KeyEvent& rKEvt)
1554 bInputMode = true;
1555 if (!SC_MOD()->InputKeyEvent( rKEvt ))
1557 bool bUsed = false;
1558 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1559 if ( pViewSh )
1560 bUsed = pViewSh->SfxKeyInput(rKEvt); // Only accelerators, no input
1561 if (!bUsed)
1562 Window::KeyInput( rKEvt );
1564 bInputMode = false;
1567 void ScTextWnd::GetFocus()
1569 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1570 if ( pViewSh )
1571 pViewSh->SetFormShellAtTop( false ); // focus in input line -> FormShell no longer on top
1574 void ScTextWnd::LoseFocus()
1578 OUString ScTextWnd::GetText() const
1580 // Override to get the text via the testtool
1581 if ( pEditEngine )
1582 return pEditEngine->GetText();
1583 else
1584 return GetTextString();
1587 void ScTextWnd::SetFormulaMode( bool bSet )
1589 if ( bSet != bFormulaMode )
1591 bFormulaMode = bSet;
1592 UpdateAutoCorrFlag();
1596 void ScTextWnd::UpdateAutoCorrFlag()
1598 if ( pEditEngine )
1600 EEControlBits nControl = pEditEngine->GetControlWord();
1601 EEControlBits nOld = nControl;
1602 if ( bFormulaMode )
1603 nControl &= ~EEControlBits::AUTOCORRECT; // No AutoCorrect in Formulas
1604 else
1605 nControl |= EEControlBits::AUTOCORRECT; // Else do enable it
1607 if ( nControl != nOld )
1608 pEditEngine->SetControlWord( nControl );
1612 IMPL_LINK_TYPED(ScTextWnd, NotifyHdl, EENotify&, rNotify, void)
1614 // need to process EE_NOTIFY_TEXTVIEWSCROLLED here
1615 // sometimes we don't seem to get EE_NOTIFY_TEXTVIEWSCROLLED e.g. when
1616 // we insert text at the beginning of the text so the cursor never moves
1617 // down to generate a scroll event
1619 if ( rNotify.eNotificationType == EE_NOTIFY_TEXTVIEWSCROLLED
1620 || rNotify.eNotificationType == EE_NOTIFY_TEXTHEIGHTCHANGED )
1621 SetScrollBarRange();
1624 IMPL_LINK_NOARG_TYPED(ScTextWnd, ModifyHdl, LinkParamNone*, void)
1626 if (pEditView && !bInputMode)
1628 ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
1630 // Use the InputHandler's InOwnChange flag to prevent calling InputChanged
1631 // while an InputHandler method is modifying the EditEngine content
1633 if ( pHdl && !pHdl->IsInOwnChange() )
1634 pHdl->InputChanged( pEditView, true ); // #i20282# InputChanged must know if called from modify handler
1638 void ScTextWnd::StopEditEngine( bool bAll )
1640 if (!pEditEngine)
1641 return;
1643 pEditEngine->SetNotifyHdl(Link<EENotify&, void>());
1645 if (pEditView)
1647 if (!maAccTextDatas.empty())
1648 maAccTextDatas.back()->EndEdit();
1650 ScModule* pScMod = SC_MOD();
1652 if (!bAll)
1653 pScMod->InputSelection( pEditView );
1654 aString = pEditEngine->GetText();
1655 bIsInsertMode = pEditView->IsInsertMode();
1656 bool bSelection = pEditView->HasSelection();
1657 pEditEngine->SetModifyHdl(Link<LinkParamNone*,void>());
1658 DELETEZ(pEditView);
1659 DELETEZ(pEditEngine);
1661 if ( pScMod->IsEditMode() && !bAll )
1662 pScMod->SetInputMode(SC_INPUT_TABLE);
1664 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
1665 if (pViewFrm)
1666 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
1668 if (bSelection)
1669 Invalidate(); // So that the Selection is not left there
1673 static sal_Int32 findFirstNonMatchingChar(const OUString& rStr1, const OUString& rStr2)
1675 // Search the string for unmatching chars
1676 const sal_Unicode* pStr1 = rStr1.getStr();
1677 const sal_Unicode* pStr2 = rStr2.getStr();
1678 sal_Int32 i = 0;
1679 while ( i < rStr1.getLength() )
1681 // Abort on the first unmatching char
1682 if ( *pStr1 != *pStr2 )
1683 return i;
1684 ++pStr1;
1685 ++pStr2;
1686 ++i;
1689 return i;
1692 void ScTextWnd::SetTextString( const OUString& rNewString )
1694 // Ideally it would be best to create on demand the EditEngine/EditView here, but... for
1695 // the initialisation scenario where a cell is first clicked on we end up with the text in the
1696 // inputbar window scrolled to the bottom if we do that here ( because the tableview and topview
1697 // are synced I guess ).
1698 // should fix that I suppose :-/ need to look a bit further into that
1699 mbInvalidate = true; // ensure next Paint ( that uses editengine ) call will call Invalidate first
1701 if ( rNewString != aString )
1703 bInputMode = true;
1705 // Find position of the change, only paint the rest
1706 if (!pEditEngine)
1708 bool bPaintAll;
1709 if ( bIsRTL )
1710 bPaintAll = true;
1711 else
1713 // test if CTL script type is involved
1714 SvtScriptType nOldScript = SvtScriptType::NONE;
1715 SvtScriptType nNewScript = SvtScriptType::NONE;
1716 SfxObjectShell* pObjSh = SfxObjectShell::Current();
1717 if ( pObjSh && dynamic_cast<const ScDocShell*>( pObjSh) != nullptr )
1719 // any document can be used (used only for its break iterator)
1720 ScDocument& rDoc = static_cast<ScDocShell*>(pObjSh)->GetDocument();
1721 nOldScript = rDoc.GetStringScriptType( aString );
1722 nNewScript = rDoc.GetStringScriptType( rNewString );
1724 bPaintAll = ( nOldScript & SvtScriptType::COMPLEX ) || ( nNewScript & SvtScriptType::COMPLEX );
1727 if ( bPaintAll )
1729 // if CTL is involved, the whole text has to be redrawn
1730 Invalidate();
1732 else
1734 long nTextSize = 0;
1735 sal_Int32 nDifPos;
1736 if (rNewString.getLength() > aString.getLength())
1737 nDifPos = findFirstNonMatchingChar(rNewString, aString);
1738 else
1739 nDifPos = findFirstNonMatchingChar(aString, rNewString);
1741 long nSize1 = GetTextWidth(aString);
1742 long nSize2 = GetTextWidth(rNewString);
1743 if ( nSize1>0 && nSize2>0 )
1744 nTextSize = std::max( nSize1, nSize2 );
1745 else
1746 nTextSize = GetOutputSize().Width(); // Overflow
1748 Point aLogicStart = PixelToLogic(Point(0,0));
1749 long nStartPos = aLogicStart.X();
1750 long nInvPos = nStartPos;
1751 if (nDifPos)
1752 nInvPos += GetTextWidth(aString,0,nDifPos);
1754 InvalidateFlags nFlags = InvalidateFlags::NONE;
1755 if ( nDifPos == aString.getLength() ) // only new characters appended
1756 nFlags = InvalidateFlags::NoErase; // then background is already clear
1758 Invalidate( Rectangle( nInvPos, 0, nStartPos+nTextSize, GetOutputSize().Height()-1 ), nFlags );
1761 else
1763 pEditEngine->SetText(rNewString);
1766 aString = rNewString;
1768 if (!maAccTextDatas.empty())
1769 maAccTextDatas.back()->TextChanged();
1771 bInputMode = false;
1774 SetScrollBarRange();
1775 DoScroll();
1778 const OUString& ScTextWnd::GetTextString() const
1780 return aString;
1783 bool ScTextWnd::IsInputActive()
1785 return HasFocus();
1788 void ScTextWnd::MakeDialogEditView()
1790 if ( pEditView ) return;
1792 ScFieldEditEngine* pNew;
1793 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
1794 if ( pViewSh )
1796 ScDocument* pDoc = pViewSh->GetViewData().GetDocument();
1797 pNew = new ScFieldEditEngine(pDoc, pDoc->GetEnginePool(), pDoc->GetEditPool());
1799 else
1800 pNew = new ScFieldEditEngine(nullptr, EditEngine::CreatePool(), nullptr, true);
1801 pNew->SetExecuteURL( false );
1802 pEditEngine = pNew;
1804 pEditEngine->SetUpdateMode( false );
1805 pEditEngine->SetWordDelimiters( pEditEngine->GetWordDelimiters() + "=" );
1806 pEditEngine->SetPaperSize( Size( bIsRTL ? USHRT_MAX : THESIZE, 300 ) );
1808 SfxItemSet* pSet = new SfxItemSet( pEditEngine->GetEmptyItemSet() );
1809 EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
1810 lcl_ExtendEditFontAttribs( *pSet );
1811 if ( bIsRTL )
1812 lcl_ModifyRTLDefaults( *pSet );
1813 pEditEngine->SetDefaults( pSet );
1814 pEditEngine->SetUpdateMode( true );
1816 pEditView = new EditView( pEditEngine, this );
1817 pEditEngine->InsertView( pEditView, EE_APPEND );
1819 Resize();
1821 if ( bIsRTL )
1822 lcl_ModifyRTLVisArea( pEditView );
1824 if (!maAccTextDatas.empty())
1825 maAccTextDatas.back()->StartEdit();
1828 void ScTextWnd::ImplInitSettings()
1830 bIsRTL = AllSettings::GetLayoutRTL();
1832 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1834 Color aBgColor= rStyleSettings.GetWindowColor();
1835 Color aTxtColor= rStyleSettings.GetWindowTextColor();
1837 aTextFont.SetFillColor ( aBgColor );
1838 aTextFont.SetColor (aTxtColor);
1839 SetBackground ( aBgColor );
1840 Invalidate();
1843 css::uno::Reference< css::accessibility::XAccessible > ScTextWnd::CreateAccessible()
1845 return new ScAccessibleEditObject(GetAccessibleParentWindow()->GetAccessible(), nullptr, this,
1846 OUString(ScResId(STR_ACC_EDITLINE_NAME)),
1847 OUString(ScResId(STR_ACC_EDITLINE_DESCR)), ScAccessibleEditObject::EditLine);
1850 void ScTextWnd::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
1852 OSL_ENSURE( ::std::find( maAccTextDatas.begin(), maAccTextDatas.end(), &rTextData ) == maAccTextDatas.end(),
1853 "ScTextWnd::InsertAccessibleTextData - passed object already registered" );
1854 maAccTextDatas.push_back( &rTextData );
1857 void ScTextWnd::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
1859 AccTextDataVector::iterator aEnd = maAccTextDatas.end();
1860 AccTextDataVector::iterator aIt = ::std::find( maAccTextDatas.begin(), aEnd, &rTextData );
1861 OSL_ENSURE( aIt != aEnd, "ScTextWnd::RemoveAccessibleTextData - passed object not registered" );
1862 if( aIt != aEnd )
1863 maAccTextDatas.erase( aIt );
1866 void ScTextWnd::DataChanged( const DataChangedEvent& rDCEvt )
1868 if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1869 (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1871 ImplInitSettings();
1872 Invalidate();
1874 else
1875 Window::DataChanged( rDCEvt );
1878 void ScTextWnd::TextGrabFocus()
1880 GrabFocus();
1883 // Position window
1885 ScPosWnd::ScPosWnd( vcl::Window* pParent ) :
1886 ComboBox ( pParent, WinBits(WB_HIDE | WB_DROPDOWN) ),
1887 nTipVisible ( 0 ),
1888 bFormulaMode( false )
1890 Size aSize( GetTextWidth( "GW99999:GW99999" ),
1891 GetTextHeight() );
1892 aSize.Width() += 25; // FIXME: ??
1893 aSize.Height() = CalcWindowSizePixel(11); // Functions: 10 MRU + "others..."
1894 SetSizePixel( aSize );
1896 FillRangeNames();
1898 StartListening( *SfxGetpApp() ); // For Navigator rangename updates
1901 ScPosWnd::~ScPosWnd()
1903 disposeOnce();
1906 void ScPosWnd::dispose()
1908 EndListening( *SfxGetpApp() );
1910 HideTip();
1912 ComboBox::dispose();
1915 void ScPosWnd::SetFormulaMode( bool bSet )
1917 if ( bSet != bFormulaMode )
1919 bFormulaMode = bSet;
1921 if ( bSet )
1922 FillFunctions();
1923 else
1924 FillRangeNames();
1926 HideTip();
1930 void ScPosWnd::SetPos( const OUString& rPosStr )
1932 if ( aPosStr != rPosStr )
1934 aPosStr = rPosStr;
1935 SetText(aPosStr);
1939 namespace {
1941 OUString createLocalRangeName(const OUString& rName, const OUString& rTableName)
1943 OUStringBuffer aString (rName);
1944 aString.append(" (");
1945 aString.append(rTableName);
1946 aString.append(")");
1947 return aString.makeStringAndClear();
1952 void ScPosWnd::FillRangeNames()
1954 Clear();
1956 SfxObjectShell* pObjSh = SfxObjectShell::Current();
1957 if ( pObjSh && dynamic_cast<const ScDocShell*>( pObjSh) != nullptr )
1959 ScDocument& rDoc = static_cast<ScDocShell*>(pObjSh)->GetDocument();
1961 InsertEntry(ScGlobal::GetRscString( STR_MANAGE_NAMES ));
1962 SetSeparatorPos(0);
1964 ScRange aDummy;
1965 std::set<OUString> aSet;
1966 ScRangeName* pRangeNames = rDoc.GetRangeName();
1967 if (!pRangeNames->empty())
1969 ScRangeName::const_iterator itrBeg = pRangeNames->begin(), itrEnd = pRangeNames->end();
1970 for (ScRangeName::const_iterator itr = itrBeg; itr != itrEnd; ++itr)
1972 if (itr->second->IsValidReference(aDummy))
1973 aSet.insert(itr->second->GetName());
1976 for (SCTAB i = 0; i < rDoc.GetTableCount(); ++i)
1978 ScRangeName* pLocalRangeName = rDoc.GetRangeName(i);
1979 if (pLocalRangeName && !pLocalRangeName->empty())
1981 OUString aTableName;
1982 rDoc.GetName(i, aTableName);
1983 for (ScRangeName::const_iterator itr = pLocalRangeName->begin(); itr != pLocalRangeName->end(); ++itr)
1985 if (itr->second->IsValidReference(aDummy))
1986 aSet.insert(createLocalRangeName(itr->second->GetName(), aTableName));
1991 if (!aSet.empty())
1993 for (std::set<OUString>::iterator itr = aSet.begin();
1994 itr != aSet.end(); ++itr)
1996 InsertEntry(*itr);
2000 SetText(aPosStr);
2003 void ScPosWnd::FillFunctions()
2005 Clear();
2007 OUString aFirstName;
2008 const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
2009 sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
2010 const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
2011 if (pMRUList)
2013 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
2014 sal_uLong nListCount = pFuncList->GetCount();
2015 for (sal_uInt16 i=0; i<nMRUCount; i++)
2017 sal_uInt16 nId = pMRUList[i];
2018 for (sal_uLong j=0; j<nListCount; j++)
2020 const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
2021 if ( pDesc->nFIndex == nId && pDesc->pFuncName )
2023 InsertEntry( *pDesc->pFuncName );
2024 if (aFirstName.isEmpty())
2025 aFirstName = *pDesc->pFuncName;
2026 break; // Stop searching
2032 //! Re-add entry "Other..." for Function AutoPilot if it can work with text that
2033 // has been entered so far
2035 // InsertEntry( ScGlobal::GetRscString(STR_FUNCTIONLIST_MORE) );
2037 SetText(aFirstName);
2040 void ScPosWnd::Notify( SfxBroadcaster&, const SfxHint& rHint )
2042 if ( !bFormulaMode )
2044 // Does the list of range names need updating?
2045 const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
2046 if ( pSimpleHint )
2048 const sal_uInt32 nHintId = pSimpleHint->GetId();
2049 if ( nHintId == SC_HINT_AREAS_CHANGED || nHintId == SC_HINT_NAVIGATOR_UPDATEALL)
2050 FillRangeNames();
2052 else if ( dynamic_cast<const SfxEventHint*>(&rHint) )
2054 sal_uLong nEventId = static_cast<const SfxEventHint*>(&rHint)->GetEventId();
2055 if ( nEventId == SFX_EVENT_ACTIVATEDOC )
2056 FillRangeNames();
2061 void ScPosWnd::HideTip()
2063 if ( nTipVisible )
2065 vcl::Window* pWin = GetSubEdit();
2066 if (!pWin)
2067 pWin = this;
2068 Help::HidePopover(pWin, nTipVisible);
2069 nTipVisible = 0;
2073 static ScNameInputType lcl_GetInputType( const OUString& rText )
2075 ScNameInputType eRet = SC_NAME_INPUT_BAD_NAME; // the more general error
2077 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2078 if ( pViewSh )
2080 ScViewData& rViewData = pViewSh->GetViewData();
2081 ScDocument* pDoc = rViewData.GetDocument();
2082 SCTAB nTab = rViewData.GetTabNo();
2083 formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
2085 // test in same order as in SID_CURRENTCELL execute
2087 ScRange aRange;
2088 ScAddress aAddress;
2089 ScRangeUtil aRangeUtil;
2090 SCTAB nNameTab;
2091 sal_Int32 nNumeric;
2093 if (rText == ScGlobal::GetRscString(STR_MANAGE_NAMES))
2094 eRet = SC_MANAGE_NAMES;
2095 else if ( aRange.Parse( rText, pDoc, eConv ) & ScRefFlags::VALID )
2096 eRet = SC_NAME_INPUT_RANGE;
2097 else if ( aAddress.Parse( rText, pDoc, eConv ) & ScRefFlags::VALID )
2098 eRet = SC_NAME_INPUT_CELL;
2099 else if ( ScRangeUtil::MakeRangeFromName( rText, pDoc, nTab, aRange, RUTL_NAMES, eConv ) )
2100 eRet = SC_NAME_INPUT_NAMEDRANGE;
2101 else if ( ScRangeUtil::MakeRangeFromName( rText, pDoc, nTab, aRange, RUTL_DBASE, eConv ) )
2102 eRet = SC_NAME_INPUT_DATABASE;
2103 else if ( comphelper::string::isdigitAsciiString( rText ) &&
2104 ( nNumeric = rText.toInt32() ) > 0 && nNumeric <= MAXROW+1 )
2105 eRet = SC_NAME_INPUT_ROW;
2106 else if ( pDoc->GetTable( rText, nNameTab ) )
2107 eRet = SC_NAME_INPUT_SHEET;
2108 else if ( ScRangeData::IsNameValid( rText, pDoc ) ) // nothing found, create new range?
2110 if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
2111 eRet = SC_NAME_INPUT_DEFINE;
2112 else
2113 eRet = SC_NAME_INPUT_BAD_SELECTION;
2115 else
2116 eRet = SC_NAME_INPUT_BAD_NAME;
2119 return eRet;
2122 void ScPosWnd::Modify()
2124 ComboBox::Modify();
2126 HideTip();
2128 if ( !IsTravelSelect() && !bFormulaMode )
2130 // determine the action that would be taken for the current input
2132 ScNameInputType eType = lcl_GetInputType( GetText() ); // uses current view
2133 sal_uInt16 nStrId = 0;
2134 switch ( eType )
2136 case SC_NAME_INPUT_CELL:
2137 nStrId = STR_NAME_INPUT_CELL;
2138 break;
2139 case SC_NAME_INPUT_RANGE:
2140 case SC_NAME_INPUT_NAMEDRANGE:
2141 nStrId = STR_NAME_INPUT_RANGE; // named range or range reference
2142 break;
2143 case SC_NAME_INPUT_DATABASE:
2144 nStrId = STR_NAME_INPUT_DBRANGE;
2145 break;
2146 case SC_NAME_INPUT_ROW:
2147 nStrId = STR_NAME_INPUT_ROW;
2148 break;
2149 case SC_NAME_INPUT_SHEET:
2150 nStrId = STR_NAME_INPUT_SHEET;
2151 break;
2152 case SC_NAME_INPUT_DEFINE:
2153 nStrId = STR_NAME_INPUT_DEFINE;
2154 break;
2155 default:
2156 // other cases (error): no tip help
2157 break;
2160 if ( nStrId )
2162 // show the help tip at the text cursor position
2164 vcl::Window* pWin = GetSubEdit();
2165 if (!pWin)
2166 pWin = this;
2167 Point aPos;
2168 vcl::Cursor* pCur = pWin->GetCursor();
2169 if (pCur)
2170 aPos = pWin->LogicToPixel( pCur->GetPos() );
2171 aPos = pWin->OutputToScreenPixel( aPos );
2172 Rectangle aRect( aPos, aPos );
2174 OUString aText = ScGlobal::GetRscString( nStrId );
2175 QuickHelpFlags nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
2176 nTipVisible = Help::ShowPopover(pWin, aRect, aText, nAlign);
2181 void ScPosWnd::Select()
2183 ComboBox::Select(); // In VCL GetText() only return the selected entry afterwards
2185 HideTip();
2187 if (!IsTravelSelect())
2188 DoEnter();
2191 void ScPosWnd::DoEnter()
2193 OUString aText = GetText();
2194 if ( !aText.isEmpty() )
2196 if ( bFormulaMode )
2198 ScModule* pScMod = SC_MOD();
2199 if ( aText == ScGlobal::GetRscString(STR_FUNCTIONLIST_MORE) )
2201 // Function AutoPilot
2202 //! Continue working with the text entered so far
2204 //! new method at ScModule to query if function autopilot is open
2205 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2206 if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
2207 pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
2208 SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
2210 else
2212 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2213 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
2214 if (pHdl)
2215 pHdl->InsertFunction( aText );
2218 else
2220 // depending on the input, select something or create a new named range
2222 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
2223 if ( pViewSh )
2225 ScViewData& rViewData = pViewSh->GetViewData();
2226 ScDocShell* pDocShell = rViewData.GetDocShell();
2227 ScDocument& rDoc = pDocShell->GetDocument();
2229 ScNameInputType eType = lcl_GetInputType( aText );
2230 if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION )
2232 sal_uInt16 nId = ( eType == SC_NAME_INPUT_BAD_NAME ) ? STR_NAME_ERROR_NAME : STR_NAME_ERROR_SELECTION;
2233 pViewSh->ErrorMessage( nId );
2235 else if ( eType == SC_NAME_INPUT_DEFINE )
2237 ScRangeName* pNames = rDoc.GetRangeName();
2238 ScRange aSelection;
2239 if ( pNames && !pNames->findByUpperName(ScGlobal::pCharClass->uppercase(aText)) &&
2240 (rViewData.GetSimpleArea( aSelection ) == SC_MARK_SIMPLE) )
2242 ScRangeName aNewRanges( *pNames );
2243 ScAddress aCursor( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
2244 OUString aContent(aSelection.Format(ScRefFlags::RANGE_ABS_3D, &rDoc, rDoc.GetAddressConvention()));
2245 ScRangeData* pNew = new ScRangeData( &rDoc, aText, aContent, aCursor );
2246 if ( aNewRanges.insert(pNew) )
2248 pDocShell->GetDocFunc().ModifyRangeNames( aNewRanges );
2249 pViewSh->UpdateInputHandler(true);
2253 else if (eType == SC_MANAGE_NAMES)
2255 sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
2256 SfxViewFrame* pViewFrm = pViewSh->GetViewFrame();
2257 SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
2259 SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
2261 else
2263 // for all selection types, execute the SID_CURRENTCELL slot.
2264 if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE)
2266 // Note that SID_CURRENTCELL always expects address to
2267 // be in Calc A1 format. Convert the text.
2268 ScRange aRange(0,0, rViewData.GetTabNo());
2269 aRange.ParseAny(aText, &rDoc, rDoc.GetAddressConvention());
2270 aText = aRange.Format(ScRefFlags::RANGE_ABS_3D, &rDoc, ::formula::FormulaGrammar::CONV_OOO);
2273 SfxStringItem aPosItem( SID_CURRENTCELL, aText );
2274 SfxBoolItem aUnmarkItem( FN_PARAM_1, true ); // remove existing selection
2276 pViewSh->GetViewData().GetDispatcher().ExecuteList( SID_CURRENTCELL,
2277 SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
2278 { &aPosItem, &aUnmarkItem });
2283 else
2284 SetText( aPosStr );
2286 ReleaseFocus_Impl();
2289 bool ScPosWnd::Notify( NotifyEvent& rNEvt )
2291 bool bHandled = true;
2293 switch (rNEvt.GetType())
2295 case MouseNotifyEvent::KEYINPUT:
2297 const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
2299 switch ( pKEvt->GetKeyCode().GetCode() )
2301 case KEY_RETURN:
2302 DoEnter();
2303 break;
2305 case KEY_ESCAPE:
2306 if (nTipVisible)
2308 // escape when the tip help is shown: only hide the tip
2309 HideTip();
2311 else
2313 if (!bFormulaMode)
2314 SetText( aPosStr );
2315 ReleaseFocus_Impl();
2317 break;
2319 default:
2320 bHandled = false;
2321 break;
2324 break;
2325 case MouseNotifyEvent::GETFOCUS:
2327 // Select the whole text upon focus.
2328 OUString aStr = GetText();
2329 SetSelection(Selection(0, aStr.getLength()));
2331 break;
2332 case MouseNotifyEvent::LOSEFOCUS:
2333 HideTip();
2334 bHandled = false;
2335 break;
2336 default:
2337 bHandled = false;
2340 if (!bHandled)
2341 bHandled = ComboBox::Notify(rNEvt);
2343 return bHandled;
2346 void ScPosWnd::ReleaseFocus_Impl()
2348 HideTip();
2350 SfxViewShell* pCurSh = SfxViewShell::Current();
2351 ScInputHandler* pHdl = SC_MOD()->GetInputHdl( dynamic_cast<ScTabViewShell*>( pCurSh ) );
2352 if ( pHdl && pHdl->IsTopMode() )
2354 // Focus back in input row?
2355 ScInputWindow* pInputWin = pHdl->GetInputWindow();
2356 if (pInputWin)
2358 pInputWin->TextGrabFocus();
2359 return;
2363 // Set focus to active View
2364 if ( pCurSh )
2366 vcl::Window* pShellWnd = pCurSh->GetWindow();
2368 if ( pShellWnd )
2369 pShellWnd->GrabFocus();
2373 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */