1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "inputhdl.hxx"
21 #include "scitems.hxx"
22 #include <editeng/eeitem.hxx>
24 #include <sfx2/app.hxx>
25 #include <editeng/acorrcfg.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/adjustitem.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <svtools/colorcfg.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/editobj.hxx>
32 #include <editeng/editstat.hxx>
33 #include <editeng/editview.hxx>
34 #include <editeng/escapementitem.hxx>
35 #include <editeng/forbiddencharacterstable.hxx>
36 #include <editeng/langitem.hxx>
37 #include <editeng/svxacorr.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <editeng/wghtitem.hxx>
40 #include <editeng/justifyitem.hxx>
41 #include <editeng/misspellrange.hxx>
42 #include <sfx2/bindings.hxx>
43 #include <sfx2/viewfrm.hxx>
44 #include <sfx2/dispatch.hxx>
45 #include <sfx2/docfile.hxx>
46 #include <sfx2/printer.hxx>
47 #include <svl/zforlist.hxx>
48 #include <unotools/localedatawrapper.hxx>
49 #include <vcl/help.hxx>
50 #include <vcl/cursor.hxx>
51 #include <vcl/settings.hxx>
52 #include <tools/urlobj.hxx>
53 #include <comphelper/string.hxx>
54 #include <formula/formulahelper.hxx>
55 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
56 #include <comphelper/lok.hxx>
58 #include "inputwin.hxx"
59 #include "tabvwsh.hxx"
62 #include "uiitems.hxx"
65 #include "globstr.hrc"
66 #include "patattr.hxx"
67 #include "viewdata.hxx"
68 #include "document.hxx"
69 #include "docpool.hxx"
70 #include "editutil.hxx"
71 #include "appoptio.hxx"
72 #include "docoptio.hxx"
73 #include "validat.hxx"
74 #include "userlist.hxx"
75 #include "rfindlst.hxx"
76 #include "inputopt.hxx"
77 #include "simpleformulacalc.hxx"
78 #include "compiler.hxx"
79 #include "editable.hxx"
80 #include "funcdesc.hxx"
81 #include "markdata.hxx"
82 #include "tokenarray.hxx"
83 #include <gridwin.hxx>
85 // Maximum Ranges in RangeFinder
86 #define RANGEFIND_MAX 64
88 using namespace formula
;
90 bool ScInputHandler::bOptLoaded
= false; // Evaluate App options
91 bool ScInputHandler::bAutoComplete
= false; // Is set in KeyInput
93 extern sal_uInt16 nEditAdjust
; //! Member of ViewData
97 // Formula data replacement character for a pair of parentheses at end of
98 // function name, to force sorting parentheses before all other characters.
99 // Collation may treat parentheses differently.
100 const sal_Unicode cParenthesesReplacement
= 0x0001;
102 sal_Unicode
lcl_getSheetSeparator(ScDocument
* pDoc
)
104 ScCompiler
aComp(pDoc
, ScAddress());
105 aComp
.SetGrammar(pDoc
->GetGrammar());
106 return aComp
.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR
);
109 ScTypedCaseStrSet::const_iterator
findText(
110 const ScTypedCaseStrSet
& rDataSet
, ScTypedCaseStrSet::const_iterator itPos
,
111 const OUString
& rStart
, OUString
& rResult
, bool bBack
)
113 if (bBack
) // Backwards
115 ScTypedCaseStrSet::const_reverse_iterator it
= rDataSet
.rbegin(), itEnd
= rDataSet
.rend();
116 if (itPos
!= rDataSet
.end())
118 size_t nPos
= std::distance(rDataSet
.begin(), itPos
);
119 size_t nRPos
= rDataSet
.size() - 1 - nPos
;
120 std::advance(it
, nRPos
);
124 for (; it
!= itEnd
; ++it
)
126 const ScTypedStrData
& rData
= *it
;
127 if (rData
.GetStringType() == ScTypedStrData::Value
)
131 if (!ScGlobal::GetpTransliteration()->isMatch(rStart
, rData
.GetString()))
135 rResult
= rData
.GetString();
136 return (++it
).base(); // convert the reverse iterator back to iterator.
141 ScTypedCaseStrSet::const_iterator it
= rDataSet
.begin(), itEnd
= rDataSet
.end();
142 if (itPos
!= rDataSet
.end())
148 for (; it
!= itEnd
; ++it
)
150 const ScTypedStrData
& rData
= *it
;
151 if (rData
.GetStringType() == ScTypedStrData::Value
)
155 if (!ScGlobal::GetpTransliteration()->isMatch(rStart
, rData
.GetString()))
159 rResult
= rData
.GetString();
164 return rDataSet
.end(); // no matching text found
167 OUString
getExactMatch(const ScTypedCaseStrSet
& rDataSet
, const OUString
& rString
)
169 ScTypedCaseStrSet::const_iterator it
= rDataSet
.begin(), itEnd
= rDataSet
.end();
170 for (; it
!= itEnd
; ++it
)
172 const ScTypedStrData
& rData
= *it
;
173 if (rData
.GetStringType() == ScTypedStrData::Value
)
176 if (!ScGlobal::GetpTransliteration()->isEqual(rData
.GetString(), rString
))
179 return rData
.GetString();
184 ScTypedCaseStrSet::const_iterator
findTextAll(
185 const ScTypedCaseStrSet
& rDataSet
, ScTypedCaseStrSet::const_iterator itPos
,
186 const OUString
& rStart
, ::std::vector
< OUString
> &rResultVec
, bool bBack
)
188 rResultVec
.clear(); // clear contents
191 ScTypedCaseStrSet::const_iterator retit
;
192 if ( bBack
) // Backwards
194 ScTypedCaseStrSet::const_reverse_iterator it
, itEnd
;
195 if ( itPos
== rDataSet
.end() )
197 it
= rDataSet
.rend();
203 it
= rDataSet
.rbegin();
204 size_t nPos
= std::distance(rDataSet
.begin(), itPos
);
205 size_t nRPos
= rDataSet
.size() - 1 - nPos
; // if itPos == rDataSet.end(), then nRPos = -1
206 std::advance(it
, nRPos
);
207 if ( it
== rDataSet
.rend() )
208 it
= rDataSet
.rbegin();
211 bool bFirstTime
= true;
213 while ( it
!= itEnd
|| bFirstTime
)
216 if ( it
== rDataSet
.rend() ) // go to the first if reach the end
217 it
= rDataSet
.rbegin();
221 const ScTypedStrData
& rData
= *it
;
222 if ( rData
.GetStringType() == ScTypedStrData::Value
)
226 if ( !ScGlobal::GetpTransliteration()->isMatch(rStart
, rData
.GetString()) )
230 rResultVec
.push_back(rData
.GetString()); // set the match data
231 if ( nCount
== 0 ) // convert the reverse iterator back to iterator.
233 // actually we want to do "retit = it;".
234 retit
= rDataSet
.begin();
235 size_t nRPos
= std::distance(rDataSet
.rbegin(), it
);
236 size_t nPos
= rDataSet
.size() - 1 - nRPos
;
237 std::advance(retit
, nPos
);
244 ScTypedCaseStrSet::const_iterator it
, itEnd
;
246 if ( it
== rDataSet
.end() )
247 it
= rDataSet
.begin();
249 bool bFirstTime
= true;
251 while ( it
!= itEnd
|| bFirstTime
)
254 if ( it
== rDataSet
.end() ) // go to the first if reach the end
255 it
= rDataSet
.begin();
259 const ScTypedStrData
& rData
= *it
;
260 if ( rData
.GetStringType() == ScTypedStrData::Value
)
264 if ( !ScGlobal::GetpTransliteration()->isMatch(rStart
, rData
.GetString()) )
268 rResultVec
.push_back(rData
.GetString()); // set the match data
270 retit
= it
; // remember first match iterator
275 if ( nCount
> 0 ) // at least one function has matched
277 return rDataSet
.end(); // no matching text found
280 void removeChars(OUString
& rStr
, sal_Unicode c
)
282 OUStringBuffer
aBuf(rStr
);
283 for (sal_Int32 i
= 0, n
= aBuf
.getLength(); i
< n
; ++i
)
288 rStr
= aBuf
.makeStringAndClear();
293 void ScInputHandler::InitRangeFinder( const OUString
& rFormula
)
296 if ( !pActiveViewSh
|| !SC_MOD()->GetInputOptions().GetRangeFinder() )
298 ScDocShell
* pDocSh
= pActiveViewSh
->GetViewData().GetDocShell();
299 ScDocument
& rDoc
= pDocSh
->GetDocument();
300 const sal_Unicode cSheetSep
= lcl_getSheetSeparator(&rDoc
);
302 OUString aDelimiters
= ScEditUtil::ModifyDelimiters(" !\"");
303 // delimiters (in addition to ScEditUtil): only characters that are
304 // allowed in formulas next to references and the quotation mark (so
305 // string constants can be skipped)
307 sal_Int32 nColon
= aDelimiters
.indexOf( ':' );
309 aDelimiters
= aDelimiters
.replaceAt( nColon
, 1, ""); // Delimiter without colon
310 sal_Int32 nDot
= aDelimiters
.indexOf(cSheetSep
);
312 aDelimiters
= aDelimiters
.replaceAt( nDot
, 1 , ""); // Delimiter without dot
314 const sal_Unicode
* pChar
= rFormula
.getStr();
315 sal_Int32 nLen
= rFormula
.getLength();
317 sal_Int32 nStart
= 0;
318 sal_uInt16 nCount
= 0;
320 while ( nPos
< nLen
&& nCount
< RANGEFIND_MAX
)
323 while ( nPos
<nLen
&& ScGlobal::UnicodeStrChr( aDelimiters
.getStr(), pChar
[nPos
] ) )
325 if ( pChar
[nPos
] == '"' ) // String
328 while (nPos
<nLen
&& pChar
[nPos
] != '"') // Skip until end
331 ++nPos
; // Separator or closing quote
334 // Text zwischen Trennern
337 while ( nPos
<nLen
&& !ScGlobal::UnicodeStrChr( aDelimiters
.getStr(), pChar
[nPos
] ) )
340 // for R1C1 '-' in R[-]... or C[-]... are not delimiters
341 // Nothing heroic here to ensure that there are '[]' around a negative
342 // integer. we need to clean up this code.
343 if( nPos
< nLen
&& nPos
> 0 &&
344 '-' == pChar
[nPos
] && '[' == pChar
[nPos
-1] &&
345 formula::FormulaGrammar::CONV_XL_R1C1
== rDoc
.GetAddressConvention() )
353 OUString aTest
= rFormula
.copy( nStart
, nPos
-nStart
);
354 const ScAddress::Details
aAddrDetails( &rDoc
, aCursorPos
);
355 ScRefFlags nFlags
= aRange
.ParseAny( aTest
, &rDoc
, aAddrDetails
);
356 if ( nFlags
& ScRefFlags::VALID
)
358 // Set tables if not specified
359 if ( (nFlags
& ScRefFlags::TAB_3D
) == ScRefFlags::ZERO
)
360 aRange
.aStart
.SetTab( pActiveViewSh
->GetViewData().GetTabNo() );
361 if ( (nFlags
& ScRefFlags::TAB2_3D
) == ScRefFlags::ZERO
)
362 aRange
.aEnd
.SetTab( aRange
.aStart
.Tab() );
364 if ( ( nFlags
& (ScRefFlags::COL2_VALID
|ScRefFlags::ROW2_VALID
|ScRefFlags::TAB2_VALID
) ) ==
367 // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
368 // so Format doesn't output a double ref because of different flags.
369 ScRefFlags nAbsFlags
= nFlags
& (ScRefFlags::COL_ABS
|ScRefFlags::ROW_ABS
|ScRefFlags::TAB_ABS
);
370 applyStartToEndFlags(nFlags
, nAbsFlags
);
375 pEngine
->SetUpdateMode( false );
376 pRangeFindList
= new ScRangeFindList( pDocSh
->GetTitle() );
379 ColorData nColorData
= pRangeFindList
->Insert( ScRangeFindData( aRange
, nFlags
, nStart
, nPos
) );
381 ESelection
aSel( 0, nStart
, 0, nPos
);
382 SfxItemSet
aSet( pEngine
->GetEmptyItemSet() );
383 aSet
.Put( SvxColorItem( Color( nColorData
),
385 pEngine
->QuickSetAttribs( aSet
, aSel
);
390 // Do not skip last separator; could be a quote (?)
395 pEngine
->SetUpdateMode( true );
397 pDocSh
->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER
) );
401 void ScInputHandler::SetDocumentDisposing( bool b
)
403 mbDocumentDisposing
= b
;
406 static void lcl_Replace( EditView
* pView
, const OUString
& rNewStr
, const ESelection
& rOldSel
)
410 ESelection aOldSel
= pView
->GetSelection();
411 if (aOldSel
.HasRange())
412 pView
->SetSelection( ESelection( aOldSel
.nEndPara
, aOldSel
.nEndPos
,
413 aOldSel
.nEndPara
, aOldSel
.nEndPos
) );
415 EditEngine
* pEngine
= pView
->GetEditEngine();
416 pEngine
->QuickInsertText( rNewStr
, rOldSel
);
418 // Dummy InsertText for Update and Paint
419 // To do that we need to cancel the selection from above (before QuickInsertText)
420 pView
->InsertText( EMPTY_OUSTRING
);
422 sal_Int32 nLen
= pEngine
->GetTextLen(0);
423 ESelection
aSel( 0, nLen
, 0, nLen
);
424 pView
->SetSelection( aSel
); // Set cursor to the end
428 void ScInputHandler::UpdateRange( sal_uInt16 nIndex
, const ScRange
& rNew
)
430 ScTabViewShell
* pDocView
= pRefViewSh
? pRefViewSh
: pActiveViewSh
;
431 if ( pDocView
&& pRangeFindList
&& nIndex
< pRangeFindList
->Count() )
433 ScRangeFindData
& rData
= pRangeFindList
->GetObject( nIndex
);
434 sal_Int32 nOldStart
= rData
.nSelStart
;
435 sal_Int32 nOldEnd
= rData
.nSelEnd
;
436 ColorData nNewColor
= pRangeFindList
->FindColor( rNew
, nIndex
);
438 ScRange aJustified
= rNew
;
439 aJustified
.PutInOrder(); // Always display Ref in the Formula the right way
440 ScDocument
* pDoc
= pDocView
->GetViewData().GetDocument();
441 const ScAddress::Details
aAddrDetails( pDoc
, aCursorPos
);
442 OUString
aNewStr(aJustified
.Format(rData
.nFlags
, pDoc
, aAddrDetails
));
443 ESelection
aOldSel( 0, nOldStart
, 0, nOldEnd
);
444 SfxItemSet
aSet( pEngine
->GetEmptyItemSet() );
448 lcl_Replace( pTopView
, aNewStr
, aOldSel
);
449 lcl_Replace( pTableView
, aNewStr
, aOldSel
);
450 aSet
.Put( SvxColorItem( Color( nNewColor
), EE_CHAR_COLOR
) );
451 pEngine
->QuickSetAttribs( aSet
, aOldSel
);
453 bInRangeUpdate
= true;
455 bInRangeUpdate
= false;
457 long nDiff
= aNewStr
.getLength() - (long)(nOldEnd
-nOldStart
);
460 rData
.nSelEnd
= rData
.nSelEnd
+ nDiff
;
461 rData
.nColorData
= nNewColor
;
463 sal_uInt16 nCount
= (sal_uInt16
) pRangeFindList
->Count();
464 for (sal_uInt16 i
=nIndex
+1; i
<nCount
; i
++)
466 ScRangeFindData
& rNext
= pRangeFindList
->GetObject( i
);
467 rNext
.nSelStart
= rNext
.nSelStart
+ nDiff
;
468 rNext
.nSelEnd
= rNext
.nSelEnd
+ nDiff
;
471 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
472 pActiveView
->ShowCursor( false );
476 OSL_FAIL("UpdateRange: we're missing something");
480 void ScInputHandler::DeleteRangeFinder()
482 ScTabViewShell
* pPaintView
= pRefViewSh
? pRefViewSh
: pActiveViewSh
;
483 if ( pRangeFindList
&& pPaintView
)
485 ScDocShell
* pDocSh
= pActiveViewSh
->GetViewData().GetDocShell();
486 pRangeFindList
->SetHidden(true);
487 pDocSh
->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER
) ); // Steal
488 DELETEZ(pRangeFindList
);
492 inline OUString
GetEditText(EditEngine
* pEng
)
494 return ScEditUtil::GetSpaceDelimitedString(*pEng
);
497 static void lcl_RemoveTabs(OUString
& rStr
)
499 removeChars(rStr
, '\t');
502 static void lcl_RemoveLineEnd(OUString
& rStr
)
504 rStr
= convertLineEnd(rStr
, LINEEND_LF
);
505 removeChars(rStr
, '\n');
508 static sal_Int32
lcl_MatchParenthesis( const OUString
& rStr
, sal_Int32 nPos
)
511 sal_Unicode c1
, c2
= 0;
552 sal_Int32 nLen
= rStr
.getLength();
553 const sal_Unicode
* p0
= rStr
.getStr();
554 const sal_Unicode
* p
;
555 const sal_Unicode
* p1
;
556 sal_uInt16 nQuotes
= 0;
557 if ( nPos
< nLen
/ 2 )
572 // Odd number of quotes that we find ourselves in a string
573 bool bLookInString
= ((nQuotes
% 2) != 0);
574 bool bInString
= bLookInString
;
576 p1
= (nDir
< 0 ? p0
: p0
+ nLen
) ;
577 sal_uInt16 nLevel
= 1;
578 while ( p
!= p1
&& nLevel
)
583 bInString
= !bInString
;
584 if ( bLookInString
&& !bInString
)
585 p
= p1
; // That's it then
587 else if ( bInString
== bLookInString
)
597 return (sal_Int32
) (p
- p0
);
600 ScInputHandler::ScInputHandler()
601 : pInputWin( nullptr ),
603 pTableView( nullptr ),
605 pColumnData( nullptr ),
606 pFormulaData( nullptr ),
607 pFormulaDataPara( nullptr ),
608 pTipVisibleParent( nullptr ),
610 pTipVisibleSecParent( nullptr ),
615 eMode( SC_INPUT_NONE
),
620 bFormulaMode( false ),
621 bInRangeUpdate( false ),
622 bParenthesisShown( false ),
623 bCreatingFuncView( false ),
624 bInEnterHandler( false ),
625 bCommandErrorShown( false ),
626 bInOwnChange( false ),
628 bCellHasPercentFormat( false ),
629 bLastIsSymbol( false ),
630 mbDocumentDisposing(false),
632 eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD
),
635 pRefViewSh( nullptr ),
636 pLastPattern( nullptr ),
637 pEditDefaults( nullptr ),
638 pLastState( nullptr ),
639 pDelayTimer( nullptr ),
640 pRangeFindList( nullptr ),
643 // The InputHandler is constructed with the view, so SfxViewShell::Current
644 // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
645 pActiveViewSh
= nullptr;
647 // Bindings (only still used for Invalidate) are retrieved if needed on demand
650 ScInputHandler::~ScInputHandler()
652 // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
653 // thus we can't rely on any Sfx functions
654 if (!mbDocumentDisposing
) // inplace
655 EnterHandler(); // Finish input
657 if (SC_MOD()->GetRefInputHdl() == this)
658 SC_MOD()->SetRefInputHdl(nullptr);
660 if ( pInputWin
&& pInputWin
->GetInputHandler() == this )
661 pInputWin
->SetInputHandler( nullptr );
663 delete pRangeFindList
;
664 delete pEditDefaults
;
670 delete pFormulaDataPara
;
673 void ScInputHandler::SetRefScale( const Fraction
& rX
, const Fraction
& rY
)
675 if ( rX
!= aScaleX
|| rY
!= aScaleY
)
681 MapMode
aMode( MAP_100TH_MM
, Point(), aScaleX
, aScaleY
);
682 pEngine
->SetRefMapMode( aMode
);
687 void ScInputHandler::UpdateRefDevice()
692 bool bTextWysiwyg
= SC_MOD()->GetInputOptions().GetTextWysiwyg();
693 bool bInPlace
= pActiveViewSh
&& pActiveViewSh
->GetViewFrame()->GetFrame().IsInPlace();
694 EEControlBits nCtrl
= pEngine
->GetControlWord();
695 if ( bTextWysiwyg
|| bInPlace
)
696 nCtrl
|= EEControlBits::FORMAT100
; // EditEngine default: always format for 100%
698 nCtrl
&= ~EEControlBits::FORMAT100
; // when formatting for screen, use the actual MapMode
699 pEngine
->SetControlWord( nCtrl
);
700 if ( bTextWysiwyg
&& pActiveViewSh
)
701 pEngine
->SetRefDevice( pActiveViewSh
->GetViewData().GetDocument()->GetPrinter() );
703 pEngine
->SetRefDevice( nullptr );
705 MapMode
aMode( MAP_100TH_MM
, Point(), aScaleX
, aScaleY
);
706 pEngine
->SetRefMapMode( aMode
);
708 // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
709 // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
710 if ( !( bTextWysiwyg
&& pActiveViewSh
) )
712 pEngine
->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
716 void ScInputHandler::ImplCreateEditEngine()
722 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
723 pEngine
= new ScFieldEditEngine(&rDoc
, rDoc
.GetEnginePool(), rDoc
.GetEditPool());
726 pEngine
= new ScFieldEditEngine(nullptr, EditEngine::CreatePool(), nullptr, true);
727 pEngine
->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine
->GetWordDelimiters() ) );
728 UpdateRefDevice(); // also sets MapMode
729 pEngine
->SetPaperSize( Size( 1000000, 1000000 ) );
730 pEditDefaults
= new SfxItemSet( pEngine
->GetEmptyItemSet() );
732 pEngine
->SetControlWord( pEngine
->GetControlWord() | EEControlBits::AUTOCORRECT
);
733 pEngine
->SetReplaceLeadingSingleQuotationMark( false );
734 pEngine
->SetModifyHdl( LINK( this, ScInputHandler
, ModifyHdl
) );
738 void ScInputHandler::UpdateAutoCorrFlag()
740 EEControlBits nCntrl
= pEngine
->GetControlWord();
741 EEControlBits nOld
= nCntrl
;
743 // Don't use pLastPattern here (may be invalid because of AutoStyle)
744 bool bDisable
= bLastIsSymbol
|| bFormulaMode
;
746 nCntrl
&= ~EEControlBits::AUTOCORRECT
;
748 nCntrl
|= EEControlBits::AUTOCORRECT
;
750 if ( nCntrl
!= nOld
)
751 pEngine
->SetControlWord(nCntrl
);
754 void ScInputHandler::UpdateSpellSettings( bool bFromStartTab
)
758 ScViewData
& rViewData
= pActiveViewSh
->GetViewData();
759 bool bOnlineSpell
= rViewData
.GetDocument()->GetDocOptions().IsAutoSpell();
761 // SetDefaultLanguage is independent of the language attributes,
762 // ScGlobal::GetEditDefaultLanguage is always used.
763 // It must be set every time in case the office language was changed.
765 pEngine
->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
767 // if called for changed options, update flags only if already editing
768 // if called from StartTable, always update flags
770 if ( bFromStartTab
|| eMode
!= SC_INPUT_NONE
)
772 EEControlBits nCntrl
= pEngine
->GetControlWord();
773 EEControlBits nOld
= nCntrl
;
775 nCntrl
|= EEControlBits::ONLINESPELLING
;
777 nCntrl
&= ~EEControlBits::ONLINESPELLING
;
778 // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
779 if ( pLastPattern
&& pLastPattern
->IsSymbolFont() )
780 nCntrl
&= ~EEControlBits::AUTOCORRECT
;
782 nCntrl
|= EEControlBits::AUTOCORRECT
;
783 if ( nCntrl
!= nOld
)
784 pEngine
->SetControlWord(nCntrl
);
786 ScDocument
* pDoc
= rViewData
.GetDocument();
787 pDoc
->ApplyAsianEditSettings( *pEngine
);
788 pEngine
->SetDefaultHorizontalTextDirection(
789 (EEHorizontalTextDirection
)pDoc
->GetEditTextDirection( rViewData
.GetTabNo() ) );
790 pEngine
->SetFirstWordCapitalization( false );
793 // Language is set separately, so the speller is needed only if online spelling is active
794 if ( bOnlineSpell
) {
795 css::uno::Reference
<css::linguistic2::XSpellChecker1
> xXSpellChecker1( LinguMgr::GetSpellChecker() );
796 pEngine
->SetSpeller( xXSpellChecker1
);
799 bool bHyphen
= pLastPattern
&& static_cast<const SfxBoolItem
&>(pLastPattern
->GetItem(ATTR_HYPHENATE
)).GetValue();
801 css::uno::Reference
<css::linguistic2::XHyphenator
> xXHyphenator( LinguMgr::GetHyphenator() );
802 pEngine
->SetHyphenator( xXHyphenator
);
807 // Function/Range names etc. as Tip help
809 // The other types are defined in ScDocument::GetFormulaEntries
810 void ScInputHandler::GetFormulaData()
814 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
817 pFormulaData
->clear();
820 pFormulaData
= new ScTypedCaseStrSet
;
823 if( pFormulaDataPara
)
824 pFormulaDataPara
->clear();
826 pFormulaDataPara
= new ScTypedCaseStrSet
;
828 const OUString
aParenthesesReplacement( cParenthesesReplacement
);
829 const ScFunctionList
* pFuncList
= ScGlobal::GetStarCalcFunctionList();
830 sal_uLong nListCount
= pFuncList
->GetCount();
831 for(sal_uLong i
=0;i
<nListCount
;i
++)
833 const ScFuncDesc
* pDesc
= pFuncList
->GetFunction( i
);
834 if ( pDesc
->pFuncName
)
836 const sal_Unicode
* pName
= pDesc
->pFuncName
->getStr();
837 const sal_Int32 nLen
= pDesc
->pFuncName
->getLength();
838 // fdo#75264 fill maFormulaChar with all characters used in formula names
839 for ( sal_Int32 j
= 0; j
< nLen
; j
++ )
841 sal_Unicode c
= pName
[ j
];
842 maFormulaChar
.insert( c
);
844 OUString aFuncName
= *pDesc
->pFuncName
+ aParenthesesReplacement
;
845 pFormulaData
->insert(ScTypedStrData(aFuncName
, 0.0, ScTypedStrData::Standard
));
846 pDesc
->initArgumentInfo();
847 OUString aEntry
= pDesc
->getSignature();
848 pFormulaDataPara
->insert(ScTypedStrData(aEntry
, 0.0, ScTypedStrData::Standard
));
851 miAutoPosFormula
= pFormulaData
->end();
852 rDoc
.GetFormulaEntries( *pFormulaData
);
853 rDoc
.GetFormulaEntries( *pFormulaDataPara
);
857 IMPL_LINK_TYPED( ScInputHandler
, ShowHideTipVisibleParentListener
, VclWindowEvent
&, rEvent
, void )
859 if( rEvent
.GetId() == VCLEVENT_OBJECT_DYING
|| rEvent
.GetId() == VCLEVENT_WINDOW_HIDE
)
863 IMPL_LINK_TYPED( ScInputHandler
, ShowHideTipVisibleSecParentListener
, VclWindowEvent
&, rEvent
, void )
865 if( rEvent
.GetId() == VCLEVENT_OBJECT_DYING
|| rEvent
.GetId() == VCLEVENT_WINDOW_HIDE
)
869 void ScInputHandler::HideTip()
873 pTipVisibleParent
->RemoveEventListener( LINK( this, ScInputHandler
, ShowHideTipVisibleParentListener
) );
874 Help::HidePopover(pTipVisibleParent
, nTipVisible
);
876 pTipVisibleParent
= nullptr;
880 void ScInputHandler::HideTipBelow()
882 if ( nTipVisibleSec
)
884 pTipVisibleSecParent
->RemoveEventListener( LINK( this, ScInputHandler
, ShowHideTipVisibleSecParentListener
) );
885 Help::HidePopover(pTipVisibleSecParent
, nTipVisibleSec
);
887 pTipVisibleSecParent
= nullptr;
892 void ScInputHandler::ShowArgumentsTip( OUString
& rSelText
)
894 ScDocShell
* pDocSh
= pActiveViewSh
->GetViewData().GetDocShell();
895 const sal_Unicode cSep
= ScCompiler::GetNativeSymbolChar(ocSep
);
896 const sal_Unicode cSheetSep
= lcl_getSheetSeparator(&pDocSh
->GetDocument());
897 FormulaHelper
aHelper(ScGlobal::GetStarCalcFunctionMgr());
902 sal_Int32 nLeftParentPos
= lcl_MatchParenthesis( rSelText
, rSelText
.getLength()-1 );
903 if( nLeftParentPos
!= -1 )
905 sal_Int32 nNextFStart
= aHelper
.GetFunctionStart( rSelText
, nLeftParentPos
, true);
906 const IFunctionDescription
* ppFDesc
;
907 ::std::vector
< OUString
> aArgs
;
908 if( aHelper
.GetNextFunc( rSelText
, false, nNextFStart
, nullptr, &ppFDesc
, &aArgs
) )
910 if( !ppFDesc
->getFunctionName().isEmpty() )
912 sal_Int32 nArgPos
= aHelper
.GetArgStart( rSelText
, nNextFStart
, 0 );
913 sal_uInt16 nArgs
= static_cast<sal_uInt16
>(ppFDesc
->getParameterCount());
914 OUString
aFuncName( ppFDesc
->getFunctionName() + "(");
916 ScTypedCaseStrSet::const_iterator it
=
917 findText(*pFormulaDataPara
, pFormulaDataPara
->end(), aFuncName
, aNew
, false);
918 if (it
!= pFormulaDataPara
->end())
921 sal_uInt16 nActive
= 0;
922 for( sal_uInt16 i
=0; i
< nArgs
; i
++ )
924 sal_Int32 nLength
= aArgs
[i
].getLength();
925 if( nArgPos
<= rSelText
.getLength()-1 )
934 sal_Int32 nCountSemicolon
= comphelper::string::getTokenCount(aNew
, cSep
) - 1;
935 sal_Int32 nCountDot
= comphelper::string::getTokenCount(aNew
, cSheetSep
) - 1;
936 sal_Int32 nStartPosition
= 0;
937 sal_Int32 nEndPosition
= 0;
939 if( !nCountSemicolon
)
941 for (sal_Int32 i
= 0; i
< aNew
.getLength(); ++i
)
943 sal_Unicode cNext
= aNew
[i
];
946 nStartPosition
= i
+1;
950 else if( !nCountDot
)
952 sal_uInt16 nCount
= 0;
953 for (sal_Int32 i
= 0; i
< aNew
.getLength(); ++i
)
955 sal_Unicode cNext
= aNew
[i
];
958 nStartPosition
= i
+1;
960 else if( cNext
== cSep
)
964 if( nCount
== nActive
)
968 nStartPosition
= nEndPosition
+1;
974 sal_uInt16 nCount
= 0;
975 for (sal_Int32 i
= 0; i
< aNew
.getLength(); ++i
)
977 sal_Unicode cNext
= aNew
[i
];
980 nStartPosition
= i
+1;
982 else if( cNext
== cSep
)
986 if( nCount
== nActive
)
990 nStartPosition
= nEndPosition
+1;
992 else if( cNext
== cSheetSep
)
999 if (nStartPosition
> 0)
1001 OUStringBuffer aBuf
;
1002 aBuf
.append(aNew
.copy(0, nStartPosition
));
1003 aBuf
.append(static_cast<sal_Unicode
>(0x25BA));
1004 aBuf
.append(aNew
.copy(nStartPosition
));
1005 nArgs
= ppFDesc
->getParameterCount();
1006 sal_Int16 nVarArgsSet
= 0;
1007 if ( nArgs
>= PAIRED_VAR_ARGS
)
1010 nArgs
-= PAIRED_VAR_ARGS
- nVarArgsSet
;
1012 else if ( nArgs
>= VAR_ARGS
)
1015 nArgs
-= VAR_ARGS
- nVarArgsSet
;
1017 if ( nVarArgsSet
> 0 && nActive
> nArgs
)
1018 nActive
= nArgs
- (nActive
- nArgs
) % nVarArgsSet
;
1019 aBuf
.append( " : " );
1020 aBuf
.append( ppFDesc
->getParameterDescription(nActive
-1) );
1021 aNew
= aBuf
.makeStringAndClear();
1022 ShowTipBelow( aNew
);
1028 ShowTipBelow( aNew
);
1042 void ScInputHandler::ShowTipCursor()
1046 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1048 if ( bFormulaMode
&& pActiveView
&& pFormulaDataPara
&& pEngine
->GetParagraphCount() == 1 )
1050 OUString aParagraph
= pEngine
->GetText( 0 );
1051 ESelection aSel
= pActiveView
->GetSelection();
1054 if ( aParagraph
.getLength() < aSel
.nEndPos
)
1057 if ( aSel
.nEndPos
> 0 )
1059 OUString
aSelText( aParagraph
.copy( 0, aSel
.nEndPos
));
1061 ShowArgumentsTip( aSelText
);
1066 void ScInputHandler::ShowTip( const OUString
& rText
)
1068 // aManualTip needs to be set afterwards from outside
1073 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1077 pTipVisibleParent
= pActiveView
->GetWindow();
1078 vcl::Cursor
* pCur
= pActiveView
->GetCursor();
1080 aPos
= pTipVisibleParent
->LogicToPixel( pCur
->GetPos() );
1081 aPos
= pTipVisibleParent
->OutputToScreenPixel( aPos
);
1082 Rectangle
aRect( aPos
, aPos
);
1084 QuickHelpFlags nAlign
= QuickHelpFlags::Left
|QuickHelpFlags::Bottom
;
1085 nTipVisible
= Help::ShowPopover(pTipVisibleParent
, aRect
, rText
, nAlign
);
1086 pTipVisibleParent
->AddEventListener( LINK( this, ScInputHandler
, ShowHideTipVisibleParentListener
) );
1090 void ScInputHandler::ShowTipBelow( const OUString
& rText
)
1094 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1098 pTipVisibleSecParent
= pActiveView
->GetWindow();
1099 vcl::Cursor
* pCur
= pActiveView
->GetCursor();
1102 Point aLogicPos
= pCur
->GetPos();
1103 aLogicPos
.Y() += pCur
->GetHeight();
1104 aPos
= pTipVisibleSecParent
->LogicToPixel( aLogicPos
);
1106 aPos
= pTipVisibleSecParent
->OutputToScreenPixel( aPos
);
1107 Rectangle
aRect( aPos
, aPos
);
1108 QuickHelpFlags nAlign
= QuickHelpFlags::Left
| QuickHelpFlags::Top
| QuickHelpFlags::NoEvadePointer
;
1109 nTipVisibleSec
= Help::ShowPopover(pTipVisibleSecParent
, aRect
, rText
, nAlign
);
1110 pTipVisibleSecParent
->AddEventListener( LINK( this, ScInputHandler
, ShowHideTipVisibleSecParentListener
) );
1114 bool ScInputHandler::GetFuncName( OUString
& aStart
, OUString
& aResult
)
1116 if ( aStart
.isEmpty() )
1119 aStart
= ScGlobal::pCharClass
->uppercase( aStart
);
1120 sal_Int32 nPos
= aStart
.getLength() - 1;
1121 sal_Unicode c
= aStart
[ nPos
];
1122 // fdo#75264 use maFormulaChar to check if characters are used in function names
1123 ::std::set
< sal_Unicode
>::const_iterator p
= maFormulaChar
.find( c
);
1124 if ( p
== maFormulaChar
.end() )
1125 return false; // last character is not part of any function name, quit
1127 ::std::vector
<sal_Unicode
> aTemp
;
1128 aTemp
.push_back( c
);
1129 for(sal_Int32 i
= nPos
- 1; i
>= 0; --i
)
1132 p
= maFormulaChar
.find( c
);
1134 if (p
== maFormulaChar
.end())
1137 aTemp
.push_back( c
);
1140 ::std::vector
<sal_Unicode
>::reverse_iterator rIt
= aTemp
.rbegin();
1141 aResult
= OUString( *rIt
++ );
1142 while ( rIt
!= aTemp
.rend() )
1143 aResult
+= OUString( *rIt
++ );
1148 void ScInputHandler::ShowFuncList( const ::std::vector
< OUString
> & rFuncStrVec
)
1151 OUString aFuncNameStr
;
1152 OUString aDescFuncNameStr
;
1153 ::std::vector
<OUString
>::const_iterator itStr
= rFuncStrVec
.begin();
1154 sal_Int32 nMaxFindNumber
= 3;
1155 sal_Int32 nRemainFindNumber
= nMaxFindNumber
;
1156 for ( ; itStr
!= rFuncStrVec
.end(); ++itStr
)
1158 const OUString
& rFunc
= *itStr
;
1159 if ( rFunc
[rFunc
.getLength()-1] == cParenthesesReplacement
)
1161 aFuncNameStr
= rFunc
.copy(0, rFunc
.getLength()-1);
1165 aFuncNameStr
= rFunc
;
1167 if ( itStr
== rFuncStrVec
.begin() )
1170 aDescFuncNameStr
= aFuncNameStr
+ "()";
1174 aTipStr
= aTipStr
+ ", ";
1176 aTipStr
= aTipStr
+ aFuncNameStr
;
1177 if ( itStr
== rFuncStrVec
.begin() )
1179 if ( --nRemainFindNumber
<= 0 )
1182 sal_Int32 nRemainNumber
= rFuncStrVec
.size() - nMaxFindNumber
;
1183 if ( nRemainFindNumber
== 0 && nRemainNumber
> 0 )
1185 OUString
aBufStr( aTipStr
);
1186 OUString
aMessage( ScGlobal::GetRscString( STR_FUNCTIONS_FOUND
) );
1187 aMessage
= aMessage
.replaceFirst("%2", OUString::number(nRemainNumber
));
1188 aMessage
= aMessage
.replaceFirst("%1", aBufStr
);
1191 FormulaHelper
aHelper(ScGlobal::GetStarCalcFunctionMgr());
1192 sal_Int32 nNextFStart
= 0;
1193 const IFunctionDescription
* ppFDesc
;
1194 ::std::vector
< OUString
> aArgs
;
1195 OUString eqPlusFuncName
= "=" + aDescFuncNameStr
;
1196 if ( aHelper
.GetNextFunc( eqPlusFuncName
, false, nNextFStart
, nullptr, &ppFDesc
, &aArgs
) )
1198 if ( !ppFDesc
->getFunctionName().isEmpty() )
1200 aTipStr
+= " : " + ppFDesc
->getDescription();
1206 void ScInputHandler::UseFormulaData()
1208 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1210 // Formulas may only have 1 paragraph
1211 if ( pActiveView
&& pFormulaData
&& pEngine
->GetParagraphCount() == 1 )
1213 OUString aParagraph
= pEngine
->GetText( 0 );
1214 ESelection aSel
= pActiveView
->GetSelection();
1217 // Due to differences between table and input cell (e.g clipboard with line breaks),
1218 // the selection may not be in line with the EditEngine anymore.
1219 // Just return without any indication as to why.
1220 if ( aSel
.nEndPos
> aParagraph
.getLength() )
1223 if ( aParagraph
.getLength() > aSel
.nEndPos
&&
1224 ( ScGlobal::pCharClass
->isLetterNumeric( aParagraph
, aSel
.nEndPos
) ||
1225 aParagraph
[ aSel
.nEndPos
] == '_' ||
1226 aParagraph
[ aSel
.nEndPos
] == '.' ||
1227 aParagraph
[ aSel
.nEndPos
] == '$' ) )
1230 // Is the cursor at the end of a word?
1231 if ( aSel
.nEndPos
> 0 )
1233 OUString
aSelText( aParagraph
.copy( 0, aSel
.nEndPos
));
1236 if ( GetFuncName( aSelText
, aText
) )
1238 // function name is incomplete:
1239 // show matching functions name as tip above cell
1240 ::std::vector
<OUString
> aNewVec
;
1241 miAutoPosFormula
= pFormulaData
->end();
1242 miAutoPosFormula
= findTextAll(*pFormulaData
, miAutoPosFormula
, aText
, aNewVec
, false);
1243 if (miAutoPosFormula
!= pFormulaData
->end())
1245 // check if partial function name is not between quotes
1246 sal_Unicode cBetweenQuotes
= 0;
1247 for ( int n
= 0; n
< aSelText
.getLength(); n
++ )
1251 if (aSelText
[n
] == cBetweenQuotes
)
1254 else if ( aSelText
[ n
] == '"' )
1255 cBetweenQuotes
= '"';
1256 else if ( aSelText
[ n
] == '\'' )
1257 cBetweenQuotes
= '\'';
1259 if ( cBetweenQuotes
)
1260 return; // we're between quotes
1262 ShowFuncList(aNewVec
);
1263 aAutoSearch
= aText
;
1268 // function name is complete:
1269 // show tip below the cell with function name and arguments of function
1270 ShowArgumentsTip( aSelText
);
1275 void ScInputHandler::NextFormulaEntry( bool bBack
)
1277 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1278 if ( pActiveView
&& pFormulaData
)
1280 ::std::vector
<OUString
> aNewVec
;
1281 ScTypedCaseStrSet::const_iterator itNew
= findTextAll(*pFormulaData
, miAutoPosFormula
, aAutoSearch
, aNewVec
, bBack
);
1282 if (itNew
!= pFormulaData
->end())
1284 miAutoPosFormula
= itNew
;
1285 ShowFuncList( aNewVec
);
1289 // For Tab we always call HideCursor first
1291 pActiveView
->ShowCursor();
1296 bool needToExtendSelection(const OUString
& rSelectedText
, const OUString
& rInsertText
)
1298 return !rInsertText
.startsWithIgnoreAsciiCase(rSelectedText
);
1301 void completeFunction( EditView
* pView
, const OUString
& rInsert
, bool& rParInserted
)
1305 ESelection aSel
= pView
->GetSelection();
1308 pView
->SetSelection(aSel
);
1309 pView
->SelectCurrentWord();
1311 // a dot and underscore are word separators so we need special
1312 // treatment for any formula containing a dot or underscore
1313 if(rInsert
.indexOf(".") != -1 || rInsert
.indexOf("_") != -1)
1315 // need to make sure that we replace also the part before the dot
1316 // go through the word to find the match with the insert string
1317 aSel
= pView
->GetSelection();
1318 ESelection aOldSelection
= aSel
;
1319 OUString aSelectedText
= pView
->GetSelected();
1320 if ( needToExtendSelection( aSelectedText
, rInsert
) )
1322 while(needToExtendSelection(aSelectedText
, rInsert
))
1324 assert(aSel
.nStartPos
> 0);
1326 aSel
.nEndPos
= aSel
.nStartPos
;
1327 pView
->SetSelection(aSel
);
1328 pView
->SelectCurrentWord();
1329 aSelectedText
= pView
->GetSelected();
1331 aSel
.nStartPos
= aSel
.nEndPos
- ( aSelectedText
.getLength() - 1 );
1335 aSel
.nStartPos
= aSel
.nEndPos
- aSelectedText
.getLength();
1337 aSel
.nEndPos
= aOldSelection
.nEndPos
;
1338 pView
->SetSelection(aSel
);
1341 OUString aInsStr
= rInsert
;
1342 sal_Int32 nInsLen
= aInsStr
.getLength();
1343 bool bDoParen
= ( nInsLen
> 1 && aInsStr
[nInsLen
-2] == '('
1344 && aInsStr
[nInsLen
-1] == ')' );
1347 // Do not insert parentheses after function names if there already are some
1348 // (e.g. if the function name was edited).
1349 ESelection aWordSel
= pView
->GetSelection();
1350 OUString aOld
= pView
->GetEditEngine()->GetText(0);
1352 // aWordSel.EndPos points one behind string if word at end
1353 if (aWordSel
.nEndPos
< aOld
.getLength())
1355 sal_Unicode cNext
= aOld
[aWordSel
.nEndPos
];
1359 aInsStr
= aInsStr
.copy( 0, nInsLen
- 2 ); // Skip parentheses
1364 pView
->InsertText( aInsStr
);
1366 if ( bDoParen
) // Put cursor between parentheses
1368 aSel
= pView
->GetSelection();
1371 pView
->SetSelection(aSel
);
1373 rParInserted
= true;
1380 void ScInputHandler::PasteFunctionData()
1382 if (pFormulaData
&& miAutoPosFormula
!= pFormulaData
->end())
1384 const ScTypedStrData
& rData
= *miAutoPosFormula
;
1385 OUString aInsert
= rData
.GetString();
1386 if (aInsert
[aInsert
.getLength()-1] == cParenthesesReplacement
)
1387 aInsert
= aInsert
.copy( 0, aInsert
.getLength()-1) + "()";
1388 bool bParInserted
= false;
1390 DataChanging(); // Cannot be new
1391 completeFunction( pTopView
, aInsert
, bParInserted
);
1392 completeFunction( pTableView
, aInsert
, bParInserted
);
1402 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1404 pActiveView
->ShowCursor();
1407 // Calculate selection and display as tip help
1408 static OUString
lcl_Calculate( const OUString
& rFormula
, ScDocument
* pDoc
, const ScAddress
&rPos
)
1410 //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1411 // Quotation marks for Strings are only inserted here.
1413 if(rFormula
.isEmpty())
1416 std::unique_ptr
<ScSimpleFormulaCalculator
> pCalc( new ScSimpleFormulaCalculator( pDoc
, rPos
, rFormula
, false ) );
1418 // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1419 // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1420 bool bColRowName
= pCalc
->HasColRowName();
1423 // ColRowName in RPN code?
1424 if ( pCalc
->GetCode()->GetCodeLen() <= 1 )
1425 { // ==1: Single one is as a Parameter always a Range
1426 // ==0: It might be one, if ...
1427 OUStringBuffer aBraced
;
1428 aBraced
.append('(');
1429 aBraced
.append(rFormula
);
1430 aBraced
.append(')');
1431 pCalc
.reset( new ScSimpleFormulaCalculator( pDoc
, rPos
, aBraced
.makeStringAndClear(), false ) );
1434 bColRowName
= false;
1437 sal_uInt16 nErrCode
= pCalc
->GetErrCode();
1438 if ( nErrCode
!= 0 )
1439 return ScGlobal::GetErrorString(nErrCode
);
1441 SvNumberFormatter
& aFormatter
= *(pDoc
->GetFormatTable());
1443 if ( pCalc
->IsValue() )
1445 double n
= pCalc
->GetValue();
1446 sal_uLong nFormat
= aFormatter
.GetStandardFormat( n
, 0,
1447 pCalc
->GetFormatType(), ScGlobal::eLnge
);
1448 aFormatter
.GetInputLineString( n
, nFormat
, aValue
);
1449 //! display OutputString but insert InputLineString
1453 OUString aStr
= pCalc
->GetString().getString();
1454 sal_uLong nFormat
= aFormatter
.GetStandardFormat(
1455 pCalc
->GetFormatType(), ScGlobal::eLnge
);
1458 aFormatter
.GetOutputString( aStr
, nFormat
,
1462 aValue
= "\"" + aValue
+ "\"";
1463 //! Escape quotation marks in String??
1467 if ( bColRowName
|| (aTestRange
.Parse(rFormula
) & ScRefFlags::VALID
) )
1468 aValue
= aValue
+ " ...";
1473 void ScInputHandler::FormulaPreview()
1476 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1477 if ( pActiveView
&& pActiveViewSh
)
1479 OUString aPart
= pActiveView
->GetSelected();
1480 if (aPart
.isEmpty())
1481 aPart
= pEngine
->GetText(0);
1482 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
1483 aValue
= lcl_Calculate( aPart
, &rDoc
, aCursorPos
);
1486 if (!aValue
.isEmpty())
1488 ShowTip( aValue
); // Display as QuickHelp
1489 aManualTip
= aValue
; // Set after ShowTip
1491 miAutoPosFormula
= pFormulaData
->end();
1493 miAutoPosColumn
= pColumnData
->end();
1497 void ScInputHandler::PasteManualTip()
1499 // Three dots at the end -> Range reference -> do not insert
1500 // FIXME: Once we have matrix constants, we can change this
1501 sal_Int32 nTipLen
= aManualTip
.getLength();
1502 sal_uInt32
const nTipLen2(sal::static_int_cast
<sal_uInt32
>(nTipLen
));
1503 if ( nTipLen
&& ( nTipLen
< 3 || aManualTip
.copy( nTipLen2
-3 ) != "..." ) )
1505 DataChanging(); // Cannot be new
1507 OUString aInsert
= aManualTip
;
1508 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1509 if (!pActiveView
->HasSelection())
1511 // Nothing selected -> select everything
1512 sal_Int32 nOldLen
= pEngine
->GetTextLen(0);
1513 ESelection
aAllSel( 0, 0, 0, nOldLen
);
1515 pTopView
->SetSelection( aAllSel
);
1517 pTableView
->SetSelection( aAllSel
);
1520 ESelection aSel
= pActiveView
->GetSelection();
1522 OSL_ENSURE( !aSel
.nStartPara
&& !aSel
.nEndPara
, "Too many paragraphs in Formula" );
1523 if ( !aSel
.nStartPos
) // Selection from the start?
1525 if ( aSel
.nEndPos
== pEngine
->GetTextLen(0) )
1527 // Everything selected -> skip quotation marks
1528 if ( aInsert
[0] == '"' )
1529 aInsert
= aInsert
.copy(1);
1530 sal_Int32 nInsLen
= aInsert
.getLength();
1531 if ( aInsert
.endsWith("\"") )
1532 aInsert
= aInsert
.copy( 0, nInsLen
-1 );
1534 else if ( aSel
.nEndPos
)
1536 // Not everything selected -> do not overwrite equality sign
1537 //FIXME: Even double equality signs??
1540 pTopView
->SetSelection( aSel
);
1542 pTableView
->SetSelection( aSel
);
1546 pTopView
->InsertText( aInsert
, true );
1548 pTableView
->InsertText( aInsert
, true );
1556 void ScInputHandler::ResetAutoPar()
1561 void ScInputHandler::AutoParAdded()
1563 ++nAutoPar
; // Closing parenthesis can be overwritten
1566 bool ScInputHandler::CursorAtClosingPar()
1568 // Test if the cursor is before a closing parenthesis
1569 // Selection from SetReference has been removed before
1570 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1571 if ( pActiveView
&& !pActiveView
->HasSelection() && bFormulaMode
)
1573 ESelection aSel
= pActiveView
->GetSelection();
1574 sal_Int32 nPos
= aSel
.nStartPos
;
1575 OUString aFormula
= pEngine
->GetText(0);
1576 if ( nPos
< aFormula
.getLength() && aFormula
[nPos
] == ')' )
1582 void ScInputHandler::SkipClosingPar()
1584 // this is called when a ')' is typed and the cursor is before a ')'
1585 // that can be overwritten -> just set the cursor behind the ')'
1587 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1590 ESelection aSel
= pActiveView
->GetSelection();
1594 // this is in a formula (only one paragraph), so the selection
1595 // can be used directly for the TopView
1598 pTopView
->SetSelection( aSel
);
1600 pTableView
->SetSelection( aSel
);
1603 OSL_ENSURE(nAutoPar
, "SkipClosingPar: count is wrong");
1609 void ScInputHandler::GetColData()
1611 if ( pActiveViewSh
)
1613 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
1616 pColumnData
->clear();
1618 pColumnData
= new ScTypedCaseStrSet
;
1620 std::vector
<ScTypedStrData
> aEntries
;
1621 rDoc
.GetDataEntries(
1622 aCursorPos
.Col(), aCursorPos
.Row(), aCursorPos
.Tab(), aEntries
, true);
1623 if (!aEntries
.empty())
1624 pColumnData
->insert(aEntries
.begin(), aEntries
.end());
1626 miAutoPosColumn
= pColumnData
->end();
1630 void ScInputHandler::UseColData() // When typing
1632 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1633 if ( pActiveView
&& pColumnData
)
1635 // Only change when cursor is at the end
1636 ESelection aSel
= pActiveView
->GetSelection();
1639 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
1640 if ( aSel
.nEndPara
+1 == nParCnt
)
1642 sal_Int32 nParLen
= pEngine
->GetTextLen( aSel
.nEndPara
);
1643 if ( aSel
.nEndPos
== nParLen
)
1645 OUString aText
= GetEditText(pEngine
);
1646 if (!aText
.isEmpty())
1649 miAutoPosColumn
= pColumnData
->end();
1650 miAutoPosColumn
= findText(*pColumnData
, miAutoPosColumn
, aText
, aNew
, false);
1651 if (miAutoPosColumn
!= pColumnData
->end())
1653 // Strings can contain line endings (e.g. due to dBase import),
1654 // which would result in multiple paragraphs here, which is not desirable.
1655 //! Then GetExactMatch doesn't work either
1656 lcl_RemoveLineEnd( aNew
);
1658 // Keep paragraph, just append the rest
1659 //! Exact replacement in EnterHandler !!!
1660 // One Space between paragraphs:
1661 sal_Int32 nEdLen
= pEngine
->GetTextLen() + nParCnt
- 1;
1662 OUString aIns
= aNew
.copy(nEdLen
);
1664 // Selection must be "backwards", so the cursor stays behind the last
1666 ESelection
aSelection( aSel
.nEndPara
, aSel
.nEndPos
+ aIns
.getLength(),
1667 aSel
.nEndPara
, aSel
.nEndPos
);
1669 // When editing in input line, apply to both edit views
1672 pTableView
->InsertText( aIns
);
1673 pTableView
->SetSelection( aSelection
);
1677 pTopView
->InsertText( aIns
);
1678 pTopView
->SetSelection( aSelection
);
1681 aAutoSearch
= aText
; // To keep searching - nAutoPos is set
1683 if (aText
.getLength() == aNew
.getLength())
1685 // If the inserted text is found, consume TAB only if there's more coming
1687 ScTypedCaseStrSet::const_iterator itNextPos
=
1688 findText(*pColumnData
, miAutoPosColumn
, aText
, aDummy
, false);
1689 bUseTab
= itNextPos
!= pColumnData
->end();
1700 void ScInputHandler::NextAutoEntry( bool bBack
)
1702 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
1703 if ( pActiveView
&& pColumnData
)
1705 if (miAutoPosColumn
!= pColumnData
->end() && !aAutoSearch
.isEmpty())
1707 // Is the selection still valid (could be changed via the mouse)?
1708 ESelection aSel
= pActiveView
->GetSelection();
1710 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
1711 if ( aSel
.nEndPara
+1 == nParCnt
&& aSel
.nStartPara
== aSel
.nEndPara
)
1713 OUString aText
= GetEditText(pEngine
);
1714 sal_Int32 nSelLen
= aSel
.nEndPos
- aSel
.nStartPos
;
1715 sal_Int32 nParLen
= pEngine
->GetTextLen( aSel
.nEndPara
);
1716 if ( aSel
.nEndPos
== nParLen
&& aText
.getLength() == aAutoSearch
.getLength() + nSelLen
)
1719 ScTypedCaseStrSet::const_iterator itNew
=
1720 findText(*pColumnData
, miAutoPosColumn
, aAutoSearch
, aNew
, bBack
);
1722 if (itNew
!= pColumnData
->end())
1725 miAutoPosColumn
= itNew
;
1726 bInOwnChange
= true; // disable ModifyHdl (reset below)
1728 lcl_RemoveLineEnd( aNew
);
1729 OUString aIns
= aNew
.copy(aAutoSearch
.getLength());
1731 // when editing in input line, apply to both edit views
1734 pTableView
->DeleteSelected();
1735 pTableView
->InsertText( aIns
);
1736 pTableView
->SetSelection( ESelection(
1737 aSel
.nEndPara
, aSel
.nStartPos
+ aIns
.getLength(),
1738 aSel
.nEndPara
, aSel
.nStartPos
) );
1742 pTopView
->DeleteSelected();
1743 pTopView
->InsertText( aIns
);
1744 pTopView
->SetSelection( ESelection(
1745 aSel
.nEndPara
, aSel
.nStartPos
+ aIns
.getLength(),
1746 aSel
.nEndPara
, aSel
.nStartPos
) );
1749 bInOwnChange
= false;
1756 // For Tab, HideCursor was always called first
1758 pActiveView
->ShowCursor();
1761 // Highlight parentheses
1762 void ScInputHandler::UpdateParenthesis()
1765 //TODO: Can we disable parentheses highlighting per parentheses?
1766 bool bFound
= false;
1767 if ( bFormulaMode
&& eMode
!= SC_INPUT_TOP
)
1769 if ( pTableView
&& !pTableView
->HasSelection() ) // Selection is always at the bottom
1771 ESelection aSel
= pTableView
->GetSelection();
1774 // Examine character left to the cursor
1775 sal_Int32 nPos
= aSel
.nStartPos
- 1;
1776 OUString aFormula
= pEngine
->GetText(0);
1777 sal_Unicode c
= aFormula
[nPos
];
1778 if ( c
== '(' || c
== ')' )
1780 sal_Int32 nOther
= lcl_MatchParenthesis( aFormula
, nPos
);
1783 SfxItemSet
aSet( pEngine
->GetEmptyItemSet() );
1784 aSet
.Put( SvxWeightItem( WEIGHT_BOLD
, EE_CHAR_WEIGHT
) );
1786 //! Distinguish if cell is already highlighted!!!!
1787 if (bParenthesisShown
)
1789 // Remove old highlighting
1790 sal_Int32 nCount
= pEngine
->GetParagraphCount();
1791 for (sal_Int32 i
=0; i
<nCount
; i
++)
1792 pEngine
->RemoveCharAttribs( i
, EE_CHAR_WEIGHT
);
1795 ESelection
aSelThis( 0,nPos
, 0,nPos
+1 );
1796 pEngine
->QuickSetAttribs( aSet
, aSelThis
);
1797 ESelection
aSelOther( 0,nOther
, 0,nOther
+1 );
1798 pEngine
->QuickSetAttribs( aSet
, aSelOther
);
1800 // Dummy InsertText for Update and Paint (selection is empty)
1801 pTableView
->InsertText( EMPTY_OUSTRING
);
1808 // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
1809 // with different color (COL_LIGHTBLUE) ??
1813 // Remove old highlighting, if no new one is set
1814 if ( bParenthesisShown
&& !bFound
&& pTableView
)
1816 sal_Int32 nCount
= pEngine
->GetParagraphCount();
1817 for (sal_Int32 i
=0; i
<nCount
; i
++)
1818 pTableView
->RemoveCharAttribs( i
, EE_CHAR_WEIGHT
);
1821 bParenthesisShown
= bFound
;
1824 void ScInputHandler::ViewShellGone(ScTabViewShell
* pViewSh
) // Executed synchronously!
1826 if ( pViewSh
== pActiveViewSh
)
1829 pLastState
= nullptr;
1830 pLastPattern
= nullptr;
1833 if ( pViewSh
== pRefViewSh
)
1835 //! The input from the EnterHandler does not arrive anymore
1836 // We end the EditMode anyways
1838 bFormulaMode
= false;
1839 pRefViewSh
= nullptr;
1840 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED
) );
1841 SC_MOD()->SetRefInputHdl(nullptr);
1843 pInputWin
->SetFormulaMode(false);
1844 UpdateAutoCorrFlag();
1847 pActiveViewSh
= dynamic_cast<ScTabViewShell
*>( SfxViewShell::Current() );
1849 if ( pActiveViewSh
&& pActiveViewSh
== pViewSh
)
1851 OSL_FAIL("pActiveViewSh is gone");
1852 pActiveViewSh
= nullptr;
1855 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
1856 UpdateRefDevice(); // Don't keep old document's printer as RefDevice
1859 void ScInputHandler::UpdateActiveView()
1861 ImplCreateEditEngine();
1863 // #i20588# Don't rely on focus to find the active edit view. Instead, the
1864 // active pane at the start of editing is now stored (GetEditActivePart).
1865 // GetActiveWin (the currently active pane) fails for ref input across the
1866 // panes of a split view.
1868 vcl::Window
* pShellWin
= pActiveViewSh
?
1869 pActiveViewSh
->GetWindowByPos( pActiveViewSh
->GetViewData().GetEditActivePart() ) :
1872 sal_uInt16 nCount
= pEngine
->GetViewCount();
1875 pTableView
= pEngine
->GetView();
1876 for (sal_uInt16 i
=1; i
<nCount
; i
++)
1878 EditView
* pThis
= pEngine
->GetView(i
);
1879 vcl::Window
* pWin
= pThis
->GetWindow();
1880 if ( pWin
==pShellWin
)
1885 pTableView
= nullptr;
1887 // setup the pTableView editeng for tiled rendering to get cursor and selections
1888 if (pActiveViewSh
&& pTableView
)
1890 ScDocShell
* pDocShell
= pActiveViewSh
->GetViewData().GetDocShell();
1891 if (comphelper::LibreOfficeKit::isActive())
1893 ScDrawLayer
*pDrawLayer
= pDocShell
->GetDocument().GetDrawLayer();
1894 pTableView
->registerLibreOfficeKitCallback(pDrawLayer
);
1898 if (pInputWin
&& eMode
== SC_INPUT_TOP
)
1899 pTopView
= pInputWin
->GetEditView();
1904 void ScInputHandler::SetInputWindow( ScInputWindow
* pNew
)
1909 void ScInputHandler::StopInputWinEngine( bool bAll
)
1912 pInputWin
->StopEditEngine( bAll
);
1914 pTopView
= nullptr; // invalid now
1917 EditView
* ScInputHandler::GetActiveView()
1920 return pTopView
? pTopView
: pTableView
;
1923 void ScInputHandler::ForgetLastPattern()
1925 pLastPattern
= nullptr;
1926 if ( !pLastState
&& pActiveViewSh
)
1927 pActiveViewSh
->UpdateInputHandler( true ); // Get status again
1929 NotifyChange( pLastState
, true );
1932 void ScInputHandler::UpdateAdjust( sal_Unicode cTyped
)
1934 SvxAdjust eSvxAdjust
;
1935 switch (eAttrAdjust
)
1937 case SVX_HOR_JUSTIFY_STANDARD
:
1939 bool bNumber
= false;
1940 if (cTyped
) // Restarted
1941 bNumber
= (cTyped
>='0' && cTyped
<='9'); // Ony ciphers are numbers
1942 else if ( pActiveViewSh
)
1944 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
1945 bNumber
= ( rDoc
.GetCellType( aCursorPos
) == CELLTYPE_VALUE
);
1947 eSvxAdjust
= bNumber
? SVX_ADJUST_RIGHT
: SVX_ADJUST_LEFT
;
1950 case SVX_HOR_JUSTIFY_BLOCK
:
1951 eSvxAdjust
= SVX_ADJUST_BLOCK
;
1953 case SVX_HOR_JUSTIFY_CENTER
:
1954 eSvxAdjust
= SVX_ADJUST_CENTER
;
1956 case SVX_HOR_JUSTIFY_RIGHT
:
1957 eSvxAdjust
= SVX_ADJUST_RIGHT
;
1959 default: // SVX_HOR_JUSTIFY_LEFT
1960 eSvxAdjust
= SVX_ADJUST_LEFT
;
1964 bool bAsianVertical
= pLastPattern
&&
1965 static_cast<const SfxBoolItem
&>(pLastPattern
->GetItem( ATTR_STACKED
)).GetValue() &&
1966 static_cast<const SfxBoolItem
&>(pLastPattern
->GetItem( ATTR_VERTICAL_ASIAN
)).GetValue();
1967 if ( bAsianVertical
)
1969 // Always edit at top of cell -> LEFT when editing vertically
1970 eSvxAdjust
= SVX_ADJUST_LEFT
;
1973 pEditDefaults
->Put( SvxAdjustItem( eSvxAdjust
, EE_PARA_JUST
) );
1974 pEngine
->SetDefaults( *pEditDefaults
);
1976 nEditAdjust
= sal::static_int_cast
<sal_uInt16
>(eSvxAdjust
); //! set at ViewData or with PostEditView
1978 pEngine
->SetVertical( bAsianVertical
);
1981 void ScInputHandler::RemoveAdjust()
1983 // Delete hard alignement attributes
1984 bool bUndo
= pEngine
->IsUndoEnabled();
1986 pEngine
->EnableUndo( false );
1988 // Non-default paragraph attributes (e.g. from clipboard)
1989 // must be turned into character attributes
1990 pEngine
->RemoveParaAttribs();
1993 pEngine
->EnableUndo( true );
1997 void ScInputHandler::RemoveRangeFinder()
1999 // Delete pRangeFindList and colors
2000 pEngine
->SetUpdateMode(false);
2001 sal_Int32 nCount
= pEngine
->GetParagraphCount(); // Could just have been inserted
2002 for (sal_Int32 i
=0; i
<nCount
; i
++)
2003 pEngine
->RemoveCharAttribs( i
, EE_CHAR_COLOR
);
2004 pEngine
->SetUpdateMode(true);
2006 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
2007 pActiveView
->ShowCursor( false );
2009 DeleteRangeFinder(); // Deletes the list and the labels on the table
2012 bool ScInputHandler::StartTable( sal_Unicode cTyped
, bool bFromCommand
, bool bInputActivated
)
2014 bool bNewTable
= false;
2016 if (bModified
|| !ValidCol(aCursorPos
.Col()))
2021 ImplCreateEditEngine();
2025 ScDocument
& rDoc
= pActiveViewSh
->GetViewData().GetDocShell()->GetDocument();
2027 const ScMarkData
& rMark
= pActiveViewSh
->GetViewData().GetMarkData();
2028 ScEditableTester aTester
;
2029 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
2030 aTester
.TestSelection( &rDoc
, rMark
);
2032 aTester
.TestSelectedBlock(
2033 &rDoc
, aCursorPos
.Col(), aCursorPos
.Row(), aCursorPos
.Col(), aCursorPos
.Row(), rMark
);
2035 bool bStartInputMode
= true;
2037 if (!aTester
.IsEditable())
2040 // We allow read-only input mode activation regardless
2041 // whether it's part of an array or not or whether explicit cell
2042 // activation is requested (double-click or F2) or a click in input
2044 bool bShowError
= (!bInputActivated
|| aTester
.GetMessageId() != STR_PROTECTIONERR
) &&
2045 !pActiveViewSh
->GetViewData().GetDocShell()->IsReadOnly();
2048 eMode
= SC_INPUT_NONE
;
2049 StopInputWinEngine( true );
2050 UpdateFormulaMode();
2051 if ( pActiveViewSh
&& ( !bFromCommand
|| !bCommandErrorShown
) )
2053 // Prevent repeated error messages for the same cell from command events
2054 // (for keyboard events, multiple messages are wanted).
2055 // Set the flag before showing the error message because the command handler
2056 // for the next IME command may be called when showing the dialog.
2058 bCommandErrorShown
= true;
2060 pActiveViewSh
->GetActiveWin()->GrabFocus();
2061 pActiveViewSh
->ErrorMessage(aTester
.GetMessageId());
2063 bStartInputMode
= false;
2067 if (bStartInputMode
)
2069 // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
2070 pEngine
->SetUpdateMode( false );
2072 // Take over attributes in EditEngine
2073 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( aCursorPos
.Col(),
2076 if (pPattern
!= pLastPattern
)
2079 const SfxItemSet
& rAttrSet
= pPattern
->GetItemSet();
2080 const SfxPoolItem
* pItem
;
2082 if ( SfxItemState::SET
== rAttrSet
.GetItemState( ATTR_VALUE_FORMAT
, true, &pItem
) )
2084 sal_uLong nFormat
= static_cast<const SfxUInt32Item
*>(pItem
)->GetValue();
2085 bCellHasPercentFormat
= ( css::util::NumberFormat::PERCENT
==
2086 rDoc
.GetFormatTable()->GetType( nFormat
) );
2089 bCellHasPercentFormat
= false; // Default: no percent
2091 // Validity specified?
2092 if ( SfxItemState::SET
== rAttrSet
.GetItemState( ATTR_VALIDDATA
, true, &pItem
) )
2093 nValidation
= static_cast<const SfxUInt32Item
*>(pItem
)->GetValue();
2097 // EditEngine Defaults
2098 // In no case SetParaAttribs, because the EditEngine might already
2099 // be filled (for Edit cells).
2100 // SetParaAttribs would change the content.
2102 //! The SetDefaults is now (since MUST/src602
2103 //! EditEngine changes) implemented as a SetParaAttribs.
2106 pPattern
->FillEditItemSet( pEditDefaults
);
2107 pEngine
->SetDefaults( *pEditDefaults
);
2108 pLastPattern
= pPattern
;
2109 bLastIsSymbol
= pPattern
->IsSymbolFont();
2111 // Background color must be known for automatic font color.
2112 // For transparent cell background, the document background color must be used.
2114 Color aBackCol
= static_cast<const SvxBrushItem
&>(
2115 pPattern
->GetItem( ATTR_BACKGROUND
)).GetColor();
2116 ScModule
* pScMod
= SC_MOD();
2117 if ( aBackCol
.GetTransparency() > 0 ||
2118 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
2119 aBackCol
.SetColor( pScMod
->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
);
2120 pEngine
->SetBackgroundColor( aBackCol
);
2123 eAttrAdjust
= (SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
&>(pPattern
->
2124 GetItem(ATTR_HOR_JUSTIFY
)).GetValue();
2125 if ( eAttrAdjust
== SVX_HOR_JUSTIFY_REPEAT
&&
2126 static_cast<const SfxBoolItem
&>(pPattern
->GetItem(ATTR_LINEBREAK
)).GetValue() )
2128 // #i31843# "repeat" with "line breaks" is treated as default alignement
2129 eAttrAdjust
= SVX_HOR_JUSTIFY_STANDARD
;
2133 // UpdateSpellSettings enables online spelling if needed
2134 // -> also call if attributes are unchanged
2135 UpdateSpellSettings( true ); // uses pLastPattern
2141 pEngine
->SetText(aCurrentText
);
2142 aStr
= aCurrentText
;
2144 aCurrentText
.clear();
2147 aStr
= GetEditText(pEngine
);
2149 if (aStr
.startsWith("{=") && aStr
.endsWith("}") ) // Matrix formula?
2151 aStr
= aStr
.copy(1, aStr
.getLength() -2);
2152 pEngine
->SetText(aStr
);
2154 pInputWin
->SetTextString(aStr
);
2157 UpdateAdjust( cTyped
);
2159 if ( bAutoComplete
)
2162 if ( !aStr
.isEmpty() && ( aStr
[0] == '=' || aStr
[0] == '+' || aStr
[0] == '-' ) &&
2163 !cTyped
&& !bCreatingFuncView
)
2164 InitRangeFinder(aStr
); // Formula is being edited -> RangeFinder
2166 bNewTable
= true; // -> PostEditView Call
2170 if (!bProtected
&& pInputWin
)
2171 pInputWin
->SetOkCancelMode();
2176 static void lcl_SetTopSelection( EditView
* pEditView
, ESelection
& rSel
)
2178 OSL_ENSURE( rSel
.nStartPara
==0 && rSel
.nEndPara
==0, "SetTopSelection: Para != 0" );
2180 EditEngine
* pEngine
= pEditView
->GetEditEngine();
2181 sal_Int32 nCount
= pEngine
->GetParagraphCount();
2184 sal_Int32 nParLen
= pEngine
->GetTextLen(rSel
.nStartPara
);
2185 while (rSel
.nStartPos
> nParLen
&& rSel
.nStartPara
+1 < nCount
)
2187 rSel
.nStartPos
-= nParLen
+ 1; // Including space from line break
2188 nParLen
= pEngine
->GetTextLen(++rSel
.nStartPara
);
2191 nParLen
= pEngine
->GetTextLen(rSel
.nEndPara
);
2192 while (rSel
.nEndPos
> nParLen
&& rSel
.nEndPara
+1 < nCount
)
2194 rSel
.nEndPos
-= nParLen
+ 1; // Including space from line break
2195 nParLen
= pEngine
->GetTextLen(++rSel
.nEndPara
);
2199 ESelection aSel
= pEditView
->GetSelection();
2201 if ( rSel
.nStartPara
!= aSel
.nStartPara
|| rSel
.nEndPara
!= aSel
.nEndPara
2202 || rSel
.nStartPos
!= aSel
.nStartPos
|| rSel
.nEndPos
!= aSel
.nEndPos
)
2203 pEditView
->SetSelection( rSel
);
2206 void ScInputHandler::SyncViews( EditView
* pSourceView
)
2210 bool bSelectionForTopView
= false;
2211 if (pTopView
&& pTopView
!= pSourceView
)
2212 bSelectionForTopView
= true;
2213 bool bSelectionForTableView
= false;
2214 if (pTableView
&& pTableView
!= pSourceView
)
2215 bSelectionForTableView
= true;
2216 if (bSelectionForTopView
|| bSelectionForTableView
)
2218 ESelection
aSel(pSourceView
->GetSelection());
2219 if (bSelectionForTopView
)
2220 pTopView
->SetSelection(aSel
);
2221 if (bSelectionForTableView
)
2222 lcl_SetTopSelection(pTableView
, aSel
);
2225 // Only sync selection from topView if we are actually editing there
2226 else if (pTopView
&& pTableView
)
2228 ESelection
aSel(pTopView
->GetSelection());
2229 lcl_SetTopSelection( pTableView
, aSel
);
2233 IMPL_LINK_NOARG_TYPED(ScInputHandler
, ModifyHdl
, LinkParamNone
*, void)
2235 if ( !bInOwnChange
&& ( eMode
==SC_INPUT_TYPE
|| eMode
==SC_INPUT_TABLE
) &&
2236 pEngine
&& pEngine
->GetUpdateMode() && pInputWin
)
2238 // Update input line from ModifyHdl for changes that are not
2239 // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2240 OUString
aText(ScEditUtil::GetMultilineString(*pEngine
));
2241 lcl_RemoveTabs(aText
);
2242 pInputWin
->SetTextString(aText
);
2247 * @return true means new view created
2249 bool ScInputHandler::DataChanging( sal_Unicode cTyped
, bool bFromCommand
)
2252 pActiveViewSh
->GetViewData().SetPasteMode( SC_PASTE_NONE
);
2253 bInOwnChange
= true; // disable ModifyHdl (reset in DataChanged)
2255 if ( eMode
== SC_INPUT_NONE
)
2256 return StartTable( cTyped
, bFromCommand
, false );
2261 void ScInputHandler::DataChanged( bool bFromTopNotify
, bool bSetModified
)
2263 ImplCreateEditEngine();
2265 if (eMode
==SC_INPUT_NONE
)
2266 eMode
= SC_INPUT_TYPE
;
2268 if ( eMode
== SC_INPUT_TOP
&& pTopView
&& !bFromTopNotify
)
2270 // table EditEngine is formatted below, input line needs formatting after paste
2271 // #i20282# not when called from the input line's modify handler
2272 pTopView
->GetEditEngine()->QuickFormatDoc( true );
2274 // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2275 // can't safely access the EditEngine's current view, so the cursor has to be
2276 // shown again here.
2277 pTopView
->ShowCursor();
2284 if ( pRangeFindList
&& !bInRangeUpdate
)
2285 RemoveRangeFinder(); // Delete attributes and labels
2287 UpdateParenthesis(); // Highlight parentheses anew
2289 if (eMode
==SC_INPUT_TYPE
|| eMode
==SC_INPUT_TABLE
)
2293 aText
= ScEditUtil::GetMultilineString(*pEngine
);
2295 aText
= GetEditText(pEngine
);
2296 lcl_RemoveTabs(aText
);
2299 pInputWin
->SetTextString( aText
);
2301 ScDocShell
* pDocSh
= pActiveViewSh
->GetViewData().GetDocShell();
2302 ScDocument
& rDoc
= pDocSh
->GetDocument();
2303 if ( comphelper::LibreOfficeKit::isActive() )
2304 rDoc
.GetDrawLayer()->libreOfficeKitCallback(LOK_CALLBACK_CELL_FORMULA
, aText
.toUtf8().getStr());
2307 // If the cursor is before the end of a paragraph, parts are being pushed to
2308 // the right (independently from the eMode) -> Adapt View!
2309 // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2311 // First make sure the status handler is called now if the cursor
2312 // is outside the visible area
2313 pEngine
->QuickFormatDoc();
2315 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
2316 if (pActiveView
&& pActiveViewSh
)
2318 ScViewData
& rViewData
= pActiveViewSh
->GetViewData();
2320 bool bNeedGrow
= ( nEditAdjust
!= SVX_ADJUST_LEFT
); // Always right-aligned
2323 // Cursor before the end?
2324 ESelection aSel
= pActiveView
->GetSelection();
2326 bNeedGrow
= ( aSel
.nEndPos
!= pEngine
->GetTextLen(aSel
.nEndPara
) );
2330 bNeedGrow
= rViewData
.GetDocument()->IsLayoutRTL( rViewData
.GetTabNo() );
2334 // Adjust inplace view
2335 rViewData
.EditGrowY();
2336 rViewData
.EditGrowX();
2340 UpdateFormulaMode();
2341 bTextValid
= false; // Changes only in the EditEngine
2342 bInOwnChange
= false;
2345 void ScInputHandler::UpdateFormulaMode()
2347 SfxApplication
* pSfxApp
= SfxGetpApp();
2349 bool bIsFormula
= !bProtected
&& pEngine
->GetParagraphCount() == 1;
2352 const OUString
& rText
= pEngine
->GetText(0);
2353 bIsFormula
= !rText
.isEmpty() &&
2354 (rText
[0] == '=' || rText
[0] == '+' || rText
[0] == '-');
2361 bFormulaMode
= true;
2362 pRefViewSh
= pActiveViewSh
;
2363 pSfxApp
->Broadcast( SfxSimpleHint( FID_REFMODECHANGED
) );
2364 SC_MOD()->SetRefInputHdl(this);
2366 pInputWin
->SetFormulaMode(true);
2368 if ( bAutoComplete
)
2371 UpdateParenthesis();
2372 UpdateAutoCorrFlag();
2380 bFormulaMode
= false;
2381 pRefViewSh
= nullptr;
2382 pSfxApp
->Broadcast( SfxSimpleHint( FID_REFMODECHANGED
) );
2383 SC_MOD()->SetRefInputHdl(nullptr);
2385 pInputWin
->SetFormulaMode(false);
2386 UpdateAutoCorrFlag();
2391 void ScInputHandler::ShowRefFrame()
2393 // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2394 // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2395 // A local variable is used instead.
2396 ScTabViewShell
* pVisibleSh
= dynamic_cast<ScTabViewShell
*>( SfxViewShell::Current() );
2397 if ( pRefViewSh
&& pRefViewSh
!= pVisibleSh
)
2399 bool bFound
= false;
2400 SfxViewFrame
* pRefFrame
= pRefViewSh
->GetViewFrame();
2401 SfxViewFrame
* pOneFrame
= SfxViewFrame::GetFirst();
2402 while ( pOneFrame
&& !bFound
)
2404 if ( pOneFrame
== pRefFrame
)
2406 pOneFrame
= SfxViewFrame::GetNext( *pOneFrame
);
2411 // We count on Activate working synchronously here
2412 // (pActiveViewSh is set while doing so)
2413 pRefViewSh
->SetActive(); // Appear and SetViewFrame
2415 // pLastState is set correctly in the NotifyChange from the Activate
2419 OSL_FAIL("ViewFrame for reference input is not here anymore");
2424 void ScInputHandler::RemoveSelection()
2426 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
2430 ESelection aSel
= pActiveView
->GetSelection();
2431 aSel
.nStartPara
= aSel
.nEndPara
;
2432 aSel
.nStartPos
= aSel
.nEndPos
;
2434 pTableView
->SetSelection( aSel
);
2436 pTopView
->SetSelection( aSel
);
2439 void ScInputHandler::InvalidateAttribs()
2441 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
2444 SfxBindings
& rBindings
= pViewFrm
->GetBindings();
2446 rBindings
.Invalidate( SID_ATTR_CHAR_FONT
);
2447 rBindings
.Invalidate( SID_ATTR_CHAR_FONTHEIGHT
);
2448 rBindings
.Invalidate( SID_ATTR_CHAR_COLOR
);
2450 rBindings
.Invalidate( SID_ATTR_CHAR_WEIGHT
);
2451 rBindings
.Invalidate( SID_ATTR_CHAR_POSTURE
);
2452 rBindings
.Invalidate( SID_ATTR_CHAR_UNDERLINE
);
2453 rBindings
.Invalidate( SID_ATTR_CHAR_OVERLINE
);
2454 rBindings
.Invalidate( SID_ULINE_VAL_NONE
);
2455 rBindings
.Invalidate( SID_ULINE_VAL_SINGLE
);
2456 rBindings
.Invalidate( SID_ULINE_VAL_DOUBLE
);
2457 rBindings
.Invalidate( SID_ULINE_VAL_DOTTED
);
2459 rBindings
.Invalidate( SID_HYPERLINK_GETLINK
);
2461 rBindings
.Invalidate( SID_ATTR_CHAR_KERNING
);
2462 rBindings
.Invalidate( SID_SET_SUPER_SCRIPT
);
2463 rBindings
.Invalidate( SID_SET_SUB_SCRIPT
);
2464 rBindings
.Invalidate( SID_ATTR_CHAR_STRIKEOUT
);
2465 rBindings
.Invalidate( SID_ATTR_CHAR_SHADOWED
);
2469 // --------------- public methods --------------------------------------------
2471 void ScInputHandler::SetMode( ScInputMode eNewMode
, const OUString
* pInitText
)
2473 if ( eMode
== eNewMode
)
2476 ImplCreateEditEngine();
2480 eMode
= SC_INPUT_NONE
;
2481 StopInputWinEngine( true );
2483 pActiveViewSh
->GetActiveWin()->GrabFocus();
2487 if (eNewMode
!= SC_INPUT_NONE
&& pActiveViewSh
)
2488 // Disable paste mode when edit mode starts.
2489 pActiveViewSh
->GetViewData().SetPasteMode( SC_PASTE_NONE
);
2491 bInOwnChange
= true; // disable ModifyHdl (reset below)
2493 ScInputMode eOldMode
= eMode
;
2495 if (eOldMode
== SC_INPUT_TOP
&& eNewMode
!= eOldMode
)
2496 StopInputWinEngine( false );
2498 if (eMode
==SC_INPUT_TOP
|| eMode
==SC_INPUT_TABLE
)
2500 if (eOldMode
== SC_INPUT_NONE
) // not if switching between modes
2502 if (StartTable(0, false, eMode
== SC_INPUT_TABLE
))
2505 pActiveViewSh
->GetViewData().GetDocShell()->PostEditView( pEngine
, aCursorPos
);
2511 pEngine
->SetText(*pInitText
);
2515 sal_Int32 nPara
= pEngine
->GetParagraphCount()-1;
2516 sal_Int32 nLen
= pEngine
->GetText(nPara
).getLength();
2517 sal_uInt16 nCount
= pEngine
->GetViewCount();
2519 for (sal_uInt16 i
=0; i
<nCount
; i
++)
2521 if ( eMode
== SC_INPUT_TABLE
&& eOldMode
== SC_INPUT_TOP
)
2527 pEngine
->GetView(i
)->
2528 SetSelection( ESelection( nPara
, nLen
, nPara
, nLen
) );
2530 pEngine
->GetView(i
)->ShowCursor(false);
2535 if (eMode
==SC_INPUT_TABLE
|| eMode
==SC_INPUT_TYPE
)
2538 pTableView
->SetEditEngineUpdateMode(true);
2543 pTopView
->SetEditEngineUpdateMode(true);
2546 if (eNewMode
!= eOldMode
)
2547 UpdateFormulaMode();
2549 bInOwnChange
= false;
2553 * @return true if rString only contains digits (no autocorrect then)
2555 static bool lcl_IsNumber(const OUString
& rString
)
2557 sal_Int32 nLen
= rString
.getLength();
2558 for (sal_Int32 i
=0; i
<nLen
; i
++)
2560 sal_Unicode c
= rString
[i
];
2561 if ( c
< '0' || c
> '9' )
2567 static void lcl_SelectionToEnd( EditView
* pView
)
2571 EditEngine
* pEngine
= pView
->GetEditEngine();
2572 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
2575 ESelection
aSel( nParCnt
-1, pEngine
->GetTextLen(nParCnt
-1) ); // empty selection, cursor at the end
2576 pView
->SetSelection( aSel
);
2580 void ScInputHandler::EnterHandler( ScEnterMode nBlockMode
)
2582 // Macro calls for validity can cause a lot of problems, so inhibit
2583 // nested calls of EnterHandler().
2584 if (bInEnterHandler
) return;
2585 bInEnterHandler
= true;
2586 bInOwnChange
= true; // disable ModifyHdl (reset below)
2588 ImplCreateEditEngine();
2590 bool bMatrix
= ( nBlockMode
== ScEnterMode::MATRIX
);
2592 SfxApplication
* pSfxApp
= SfxGetpApp();
2593 EditTextObject
* pObject
= nullptr;
2594 ScPatternAttr
* pCellAttrs
= nullptr;
2595 bool bForget
= false; // Remove due to validity?
2597 OUString aString
= GetEditText(pEngine
);
2598 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
2599 if (bModified
&& pActiveView
&& !aString
.isEmpty() && !lcl_IsNumber(aString
))
2601 if (pColumnData
&& miAutoPosColumn
!= pColumnData
->end())
2603 // #i47125# If AutoInput appended something, do the final AutoCorrect
2604 // with the cursor at the end of the input.
2605 lcl_SelectionToEnd(pTopView
);
2606 lcl_SelectionToEnd(pTableView
);
2609 vcl::Window
* pFrameWin
= pActiveViewSh
? pActiveViewSh
->GetFrameWin() : nullptr;
2612 pTopView
->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
2614 pTableView
->CompleteAutoCorrect(pFrameWin
);
2615 aString
= GetEditText(pEngine
);
2617 lcl_RemoveTabs(aString
);
2619 // Test if valid (always with simple string)
2620 if ( bModified
&& nValidation
&& pActiveViewSh
)
2622 ScDocument
* pDoc
= pActiveViewSh
->GetViewData().GetDocument();
2623 const ScValidationData
* pData
= pDoc
->GetValidationEntry( nValidation
);
2624 if (pData
&& pData
->HasErrMsg())
2626 // #i67990# don't use pLastPattern in EnterHandler
2627 const ScPatternAttr
* pPattern
= pDoc
->GetPattern( aCursorPos
.Col(), aCursorPos
.Row(), aCursorPos
.Tab() );
2628 bool bOk
= pData
->IsDataValid( aString
, *pPattern
, aCursorPos
);
2632 if ( pActiveViewSh
) // If it came from MouseButtonDown
2633 pActiveViewSh
->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
2635 //FIXME: We still run into problems if the input is triggered by activating another View
2636 vcl::Window
* pParent
= Application::GetDefDialogParent();
2637 if ( pData
->DoError( pParent
, aString
, aCursorPos
) )
2638 bForget
= true; // Do not take over input
2643 // Check for input into DataPilot table
2644 if ( bModified
&& pActiveViewSh
&& !bForget
)
2646 ScDocument
* pDoc
= pActiveViewSh
->GetViewData().GetDocument();
2647 ScDPObject
* pDPObj
= pDoc
->GetDPAtCursor( aCursorPos
.Col(), aCursorPos
.Row(), aCursorPos
.Tab() );
2650 // Any input within the DataPilot table is either a valid renaming
2651 // or an invalid action - normal cell input is always aborted
2652 pActiveViewSh
->DataPilotInput( aCursorPos
, aString
);
2657 std::vector
<editeng::MisspellRanges
> aMisspellRanges
;
2658 pEngine
->CompleteOnlineSpelling();
2659 bool bSpellErrors
= !bFormulaMode
&& pEngine
->HasOnlineSpellErrors();
2662 // #i3820# If the spell checker flags numerical input as error,
2663 // it still has to be treated as number, not EditEngine object.
2664 if ( pActiveViewSh
)
2666 ScDocument
* pDoc
= pActiveViewSh
->GetViewData().GetDocument();
2667 // #i67990# don't use pLastPattern in EnterHandler
2668 const ScPatternAttr
* pPattern
= pDoc
->GetPattern( aCursorPos
.Col(), aCursorPos
.Row(), aCursorPos
.Tab() );
2671 SvNumberFormatter
* pFormatter
= pDoc
->GetFormatTable();
2672 // without conditional format, as in ScColumn::SetString
2673 sal_uInt32 nFormat
= pPattern
->GetNumberFormat( pFormatter
);
2675 if ( pFormatter
->IsNumberFormat( aString
, nFormat
, nVal
) )
2677 bSpellErrors
= false; // ignore the spelling errors
2683 // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
2684 // SetUpdateMode must come after CompleteOnlineSpelling.
2685 // The view is hidden in any case below (Broadcast).
2686 pEngine
->SetUpdateMode( false );
2688 if ( bModified
&& !bForget
) // What is being entered (text/object)?
2690 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
2694 bool bUniformAttribs
= true;
2695 SfxItemSet aPara1Attribs
= pEngine
->GetAttribs(0, 0, pEngine
->GetTextLen(0));
2696 for (sal_Int32 nPara
= 1; nPara
< nParCnt
; ++nPara
)
2698 SfxItemSet aPara2Attribs
= pEngine
->GetAttribs(nPara
, 0, pEngine
->GetTextLen(nPara
));
2699 if (!(aPara1Attribs
== aPara2Attribs
))
2701 // Paragraph format different from that of the 1st paragraph.
2702 bUniformAttribs
= false;
2707 ESelection
aSel( 0, 0, nParCnt
-1, pEngine
->GetTextLen(nParCnt
-1) );
2708 SfxItemSet aOldAttribs
= pEngine
->GetAttribs( aSel
);
2709 const SfxPoolItem
* pItem
= nullptr;
2711 // Find common (cell) attributes before RemoveAdjust
2712 if ( pActiveViewSh
&& bUniformAttribs
)
2714 SfxItemSet
* pCommonAttrs
= nullptr;
2715 for (sal_uInt16 nId
= EE_CHAR_START
; nId
<= EE_CHAR_END
; nId
++)
2717 SfxItemState eState
= aOldAttribs
.GetItemState( nId
, false, &pItem
);
2718 if ( eState
== SfxItemState::SET
&&
2719 nId
!= EE_CHAR_ESCAPEMENT
&& nId
!= EE_CHAR_PAIRKERNING
&&
2720 nId
!= EE_CHAR_KERNING
&& nId
!= EE_CHAR_XMLATTRIBS
&&
2721 *pItem
!= pEditDefaults
->Get(nId
) )
2723 if ( !pCommonAttrs
)
2724 pCommonAttrs
= new SfxItemSet( pEngine
->GetEmptyItemSet() );
2725 pCommonAttrs
->Put( *pItem
);
2731 ScDocument
* pDoc
= pActiveViewSh
->GetViewData().GetDocument();
2732 pCellAttrs
= new ScPatternAttr( pDoc
->GetPool() );
2733 pCellAttrs
->GetFromEditItemSet( pCommonAttrs
);
2734 delete pCommonAttrs
;
2738 // Clear ParaAttribs (including adjustment)
2741 bool bAttrib
= false; // Formatting present?
2743 // check if EditObject is needed
2748 for (sal_uInt16 nId
= EE_CHAR_START
; nId
<= EE_CHAR_END
&& !bAttrib
; nId
++)
2750 SfxItemState eState
= aOldAttribs
.GetItemState( nId
, false, &pItem
);
2751 if (eState
== SfxItemState::DONTCARE
)
2753 else if (eState
== SfxItemState::SET
)
2755 // Keep same items in EditEngine as in ScEditAttrTester
2756 if ( nId
== EE_CHAR_ESCAPEMENT
|| nId
== EE_CHAR_PAIRKERNING
||
2757 nId
== EE_CHAR_KERNING
|| nId
== EE_CHAR_XMLATTRIBS
)
2759 if ( *pItem
!= pEditDefaults
->Get(nId
) )
2766 SfxItemState eFieldState
= aOldAttribs
.GetItemState( EE_FEATURE_FIELD
, false );
2767 if ( eFieldState
== SfxItemState::DONTCARE
|| eFieldState
== SfxItemState::SET
)
2770 // Not converted characters?
2771 SfxItemState eConvState
= aOldAttribs
.GetItemState( EE_FEATURE_NOTCONV
, false );
2772 if ( eConvState
== SfxItemState::DONTCARE
|| eConvState
== SfxItemState::SET
)
2775 // Always recognize formulas as formulas
2776 // We still need the preceding test due to cell attributes
2780 pEngine
->GetAllMisspellRanges(aMisspellRanges
);
2787 pEngine
->ClearSpellErrors();
2788 pObject
= pEngine
->CreateTextObject();
2790 else if (bAutoComplete
) // Adjust Upper/Lower case
2792 // Perform case-matching only when the typed text is partial.
2793 if (pColumnData
&& aAutoSearch
.getLength() < aString
.getLength())
2794 aString
= getExactMatch(*pColumnData
, aString
);
2798 // Don't rely on ShowRefFrame switching the active view synchronously
2799 // execute the function directly on the correct view's bindings instead
2800 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2801 ScTabViewShell
* pExecuteSh
= pRefViewSh
? pRefViewSh
: pActiveViewSh
;
2809 pExecuteSh
->SetTabNo(aCursorPos
.Tab());
2810 pExecuteSh
->ActiveGrabFocus();
2813 bFormulaMode
= false;
2814 pSfxApp
->Broadcast( SfxSimpleHint( FID_REFMODECHANGED
) );
2815 SC_MOD()->SetRefInputHdl(nullptr);
2817 pInputWin
->SetFormulaMode(false);
2818 UpdateAutoCorrFlag();
2820 pRefViewSh
= nullptr; // Also without FormulaMode due to FunctionsAutoPilot
2821 DeleteRangeFinder();
2824 bool bOldMod
= bModified
;
2828 eMode
= SC_INPUT_NONE
;
2829 StopInputWinEngine(true);
2831 // Text input (through number formats) or ApplySelectionPattern modify
2832 // the cell's attributes, so pLastPattern is no longer valid
2833 pLastPattern
= nullptr;
2835 if (bOldMod
&& !bProtected
&& !bForget
)
2837 // No typographic quotes in formulas
2838 if (aString
.startsWith("="))
2840 SvxAutoCorrect
* pAuto
= SvxAutoCorrCfg::Get().GetAutoCorrect();
2843 OUString
aReplace(pAuto
->GetStartDoubleQuote());
2844 if( aReplace
.isEmpty() )
2845 aReplace
= ScGlobal::pLocaleData
->getDoubleQuotationMarkStart();
2846 if( aReplace
!= "\"" )
2847 aString
= aString
.replaceAll( aReplace
, "\"" );
2849 aReplace
= OUString(pAuto
->GetEndDoubleQuote());
2850 if( aReplace
.isEmpty() )
2851 aReplace
= ScGlobal::pLocaleData
->getDoubleQuotationMarkEnd();
2852 if( aReplace
!= "\"" )
2853 aString
= aString
.replaceAll( aReplace
, "\"" );
2855 aReplace
= OUString(pAuto
->GetStartSingleQuote());
2856 if( aReplace
.isEmpty() )
2857 aReplace
= ScGlobal::pLocaleData
->getQuotationMarkStart();
2858 if( aReplace
!= "'" )
2859 aString
= aString
.replaceAll( aReplace
, "'" );
2861 aReplace
= OUString(pAuto
->GetEndSingleQuote());
2862 if( aReplace
.isEmpty() )
2863 aReplace
= ScGlobal::pLocaleData
->getQuotationMarkEnd();
2864 if( aReplace
!= "'" )
2865 aString
= aString
.replaceAll( aReplace
, "'");
2869 pSfxApp
->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT
) );
2873 SfxBindings
& rBindings
= pExecuteSh
->GetViewFrame()->GetBindings();
2875 sal_uInt16 nId
= FID_INPUTLINE_ENTER
;
2876 if ( nBlockMode
== ScEnterMode::BLOCK
)
2877 nId
= FID_INPUTLINE_BLOCK
;
2878 else if ( nBlockMode
== ScEnterMode::MATRIX
)
2879 nId
= FID_INPUTLINE_MATRIX
;
2881 ScInputStatusItem
aItem( FID_INPUTLINE_STATUS
,
2882 aCursorPos
, aCursorPos
, aCursorPos
,
2885 if (!aMisspellRanges
.empty())
2886 aItem
.SetMisspellRanges(&aMisspellRanges
);
2888 const SfxPoolItem
* aArgs
[2];
2891 rBindings
.Execute( nId
, aArgs
);
2894 delete pLastState
; // pLastState still contains the old text
2895 pLastState
= nullptr;
2898 pSfxApp
->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW
) );
2900 if ( bOldMod
&& pExecuteSh
&& pCellAttrs
&& !bForget
)
2902 // Combine with input?
2903 pExecuteSh
->ApplySelectionPattern( *pCellAttrs
, true );
2904 pExecuteSh
->AdjustBlockHeight();
2913 nFormSelStart
= nFormSelEnd
= 0;
2916 bInOwnChange
= false;
2917 bInEnterHandler
= false;
2920 void ScInputHandler::CancelHandler()
2922 bInOwnChange
= true; // Also without FormulaMode due to FunctionsAutoPilot
2924 ImplCreateEditEngine();
2928 // Don't rely on ShowRefFrame switching the active view synchronously
2929 // execute the function directly on the correct view's bindings instead
2930 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2931 ScTabViewShell
* pExecuteSh
= pRefViewSh
? pRefViewSh
: pActiveViewSh
;
2938 pExecuteSh
->SetTabNo(aCursorPos
.Tab());
2939 pExecuteSh
->ActiveGrabFocus();
2941 bFormulaMode
= false;
2942 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED
) );
2943 SC_MOD()->SetRefInputHdl(nullptr);
2945 pInputWin
->SetFormulaMode(false);
2946 UpdateAutoCorrFlag();
2948 pRefViewSh
= nullptr; // Also without FormulaMode due to FunctionsAutoPilot
2949 DeleteRangeFinder();
2952 eMode
= SC_INPUT_NONE
;
2953 StopInputWinEngine( true );
2955 pExecuteSh
->StopEditShell();
2957 aCursorPos
.Set(MAXCOL
+1,0,0); // Invalid flag
2958 pEngine
->SetText(OUString());
2960 if ( !pLastState
&& pExecuteSh
)
2961 pExecuteSh
->UpdateInputHandler( true ); // Update status again
2963 NotifyChange( pLastState
, true );
2965 nFormSelStart
= nFormSelEnd
= 0;
2968 bInOwnChange
= false;
2971 bool ScInputHandler::IsModalMode( SfxObjectShell
* pDocSh
)
2973 // References to unnamed document; that doesn't work
2974 return bFormulaMode
&& pRefViewSh
2975 && pRefViewSh
->GetViewData().GetDocument()->GetDocumentShell() != pDocSh
2976 && !pDocSh
->HasName();
2979 void ScInputHandler::AddRefEntry()
2981 const sal_Unicode cSep
= ScCompiler::GetNativeSymbolChar(ocSep
);
2983 if (!pTableView
&& !pTopView
)
2984 return; // E.g. FillMode
2986 DataChanging(); // Cannot be new
2989 OUString aText
= GetEditText(pEngine
);
2990 sal_Unicode cLastChar
= 0;
2991 sal_Int32 nPos
= aText
.getLength() - 1;
2992 while (nPos
>= 0 && ((cLastChar
= aText
[nPos
]) == ' ')) //checking space
2995 bool bAppendSeparator
= (cLastChar
!= '(' && cLastChar
!= cSep
&& cLastChar
!= '=');
2996 if (bAppendSeparator
)
2999 pTableView
->InsertText( OUString(cSep
) );
3001 pTopView
->InsertText( OUString(cSep
) );
3007 void ScInputHandler::SetReference( const ScRange
& rRef
, ScDocument
* pDoc
)
3011 bool bOtherDoc
= ( pRefViewSh
&&
3012 pRefViewSh
->GetViewData().GetDocument() != pDoc
);
3014 if (!pDoc
->GetDocumentShell()->HasName())
3016 // References to unnamed document; that doesn't work
3017 // SetReference should not be called, then
3022 if (!pTableView
&& !pTopView
)
3023 return; // E.g. FillMode
3025 // Never overwrite the "="!
3026 EditView
* pActiveView
= pTopView
? pTopView
: pTableView
;
3027 ESelection aSel
= pActiveView
->GetSelection();
3029 if ( aSel
.nStartPara
== 0 && aSel
.nStartPos
== 0 )
3032 DataChanging(); // Cannot be new
3034 // Turn around selection if backwards (TODO: Do we really need to do that?)
3037 ESelection aTabSel
= pTableView
->GetSelection();
3038 if (aTabSel
.nStartPos
> aTabSel
.nEndPos
&& aTabSel
.nStartPara
== aTabSel
.nEndPara
)
3041 pTableView
->SetSelection(aTabSel
);
3046 ESelection aTopSel
= pTopView
->GetSelection();
3047 if (aTopSel
.nStartPos
> aTopSel
.nEndPos
&& aTopSel
.nStartPara
== aTopSel
.nEndPara
)
3050 pTopView
->SetSelection(aTopSel
);
3054 // Create string from reference
3056 const ScAddress::Details
aAddrDetails( pDoc
, aCursorPos
);
3059 // Reference to other document
3060 OSL_ENSURE(rRef
.aStart
.Tab()==rRef
.aEnd
.Tab(), "nStartTab!=nEndTab");
3062 OUString
aTmp(rRef
.Format(ScRefFlags::VALID
|ScRefFlags::TAB_3D
, pDoc
, aAddrDetails
)); // Always 3D
3064 SfxObjectShell
* pObjSh
= pDoc
->GetDocumentShell();
3065 // #i75893# convert escaped URL of the document to something user friendly
3066 OUString aFileName
= pObjSh
->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS
);
3068 switch(aAddrDetails
.eConv
)
3070 case formula::FormulaGrammar::CONV_XL_A1
:
3071 case formula::FormulaGrammar::CONV_XL_OOX
:
3072 case formula::FormulaGrammar::CONV_XL_R1C1
:
3074 aRefStr
+= aFileName
;
3077 case formula::FormulaGrammar::CONV_OOO
:
3080 aRefStr
+= aFileName
;
3088 if ( rRef
.aStart
.Tab() != aCursorPos
.Tab() ||
3089 rRef
.aStart
.Tab() != rRef
.aEnd
.Tab() )
3090 aRefStr
= rRef
.Format(ScRefFlags::VALID
|ScRefFlags::TAB_3D
, pDoc
, aAddrDetails
);
3092 aRefStr
= rRef
.Format(ScRefFlags::VALID
, pDoc
, aAddrDetails
);
3095 if (pTableView
|| pTopView
)
3098 pTableView
->InsertText( aRefStr
, true );
3100 pTopView
->InsertText( aRefStr
, true );
3108 void ScInputHandler::InsertFunction( const OUString
& rFuncName
, bool bAddPar
)
3110 if ( eMode
== SC_INPUT_NONE
)
3112 OSL_FAIL("InsertFunction, nicht im Eingabemodus");
3117 if (!pTableView
&& !pTopView
)
3118 return; // E.g. FillMode
3120 DataChanging(); // Cannot be new
3122 OUString aText
= rFuncName
;
3128 pTableView
->InsertText( aText
);
3131 ESelection aSel
= pTableView
->GetSelection();
3134 pTableView
->SetSelection(aSel
);
3139 pTopView
->InsertText( aText
);
3142 ESelection aSel
= pTopView
->GetSelection();
3145 pTopView
->SetSelection(aSel
);
3155 void ScInputHandler::ClearText()
3157 if ( eMode
== SC_INPUT_NONE
)
3159 OSL_FAIL("ClearText, nicht im Eingabemodus");
3164 if (!pTableView
&& !pTopView
)
3165 return; // E.g. FillMode
3167 DataChanging(); // Cannot be new
3171 pTableView
->GetEditEngine()->SetText( "" );
3172 pTableView
->SetSelection( ESelection(0,0, 0,0) );
3176 pTopView
->GetEditEngine()->SetText( "" );
3177 pTopView
->SetSelection( ESelection(0,0, 0,0) );
3183 bool ScInputHandler::KeyInput( const KeyEvent
& rKEvt
, bool bStartEdit
/* = false */ )
3187 bAutoComplete
= SC_MOD()->GetAppOptions().GetAutoComplete();
3191 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
3192 sal_uInt16 nModi
= aCode
.GetModifier();
3193 bool bShift
= aCode
.IsShift();
3194 bool bControl
= aCode
.IsMod1();
3195 bool bAlt
= aCode
.IsMod2();
3196 sal_uInt16 nCode
= aCode
.GetCode();
3197 sal_Unicode nChar
= rKEvt
.GetCharCode();
3199 if (bAlt
&& !bControl
&& nCode
!= KEY_RETURN
)
3200 // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3203 if (!bControl
&& nCode
== KEY_TAB
)
3205 // Normal TAB moves the cursor right.
3209 pActiveViewSh
->FindNextUnprot( bShift
);
3213 bool bInputLine
= ( eMode
==SC_INPUT_TOP
);
3217 bool bDoEnter
= false;
3222 // New line when in the input line and Shift/Ctrl-Enter is pressed,
3223 // or when in a cell and Ctrl-Enter is pressed.
3224 if ((pInputWin
&& bInputLine
&& bControl
!= bShift
) || (!bInputLine
&& bControl
&& !bShift
))
3228 else if (nModi
== 0 && nTipVisible
&& pFormulaData
&& miAutoPosFormula
!= pFormulaData
->end())
3230 PasteFunctionData();
3233 else if ( nModi
== 0 && nTipVisible
&& !aManualTip
.isEmpty() )
3240 ScEnterMode nMode
= ScEnterMode::NORMAL
;
3241 if ( bShift
&& bControl
)
3242 nMode
= ScEnterMode::MATRIX
;
3244 nMode
= ScEnterMode::BLOCK
;
3245 EnterHandler( nMode
);
3248 pActiveViewSh
->MoveCursorEnter( bShift
&& !bControl
);
3254 if (bControl
&& !bAlt
)
3256 if (pFormulaData
&& nTipVisible
&& miAutoPosFormula
!= pFormulaData
->end())
3259 NextFormulaEntry( bShift
);
3262 else if (pColumnData
&& bUseTab
&& miAutoPosColumn
!= pColumnData
->end())
3264 // Iterate through AutoInput entries
3265 NextAutoEntry( bShift
);
3276 else if( nTipVisibleSec
)
3281 else if (eMode
!= SC_INPUT_NONE
)
3290 if ( !bShift
&& !bControl
&& !bAlt
&& eMode
== SC_INPUT_TABLE
)
3292 eMode
= SC_INPUT_TYPE
;
3298 // Only execute cursor keys if already in EditMode
3299 // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3300 bool bCursorKey
= EditEngine::DoesKeyMoveCursor(rKEvt
);
3301 bool bInsKey
= ( nCode
== KEY_INSERT
&& !nModi
); // Treat Insert like Cursorkeys
3302 if ( !bUsed
&& !bSkip
&& ( bDoEnter
|| EditEngine::DoesKeyChangeText(rKEvt
) ||
3303 ( eMode
!= SC_INPUT_NONE
&& ( bCursorKey
|| bInsKey
) ) ) )
3315 bool bNewView
= DataChanging( nChar
);
3317 if (bProtected
) // Protected cell?
3318 bUsed
= true; // Don't forward KeyEvent
3319 else // Changes allowed
3321 if (bNewView
) // Create anew
3324 pActiveViewSh
->GetViewData().GetDocShell()->PostEditView( pEngine
, aCursorPos
);
3326 if (eMode
==SC_INPUT_NONE
)
3327 if (pTableView
|| pTopView
)
3331 if ( bStartEdit
&& bCellHasPercentFormat
&& ((nChar
>= '0' && nChar
<= '9') || nChar
== '-') )
3336 pTableView
->GetEditEngine()->SetText( aStrLoP
);
3337 if ( !aStrLoP
.isEmpty() )
3338 pTableView
->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3340 // Don't call SetSelection if the string is empty anyway,
3341 // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3345 pTopView
->GetEditEngine()->SetText( aStrLoP
);
3346 if ( !aStrLoP
.isEmpty() )
3347 pTopView
->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3353 if (pTableView
|| pTopView
)
3358 if( pTableView
->PostKeyEvent( KeyEvent( CHAR_CR
, vcl::KeyCode(KEY_RETURN
) ) ) )
3361 if( pTopView
->PostKeyEvent( KeyEvent( CHAR_CR
, vcl::KeyCode(KEY_RETURN
) ) ) )
3364 else if ( nAutoPar
&& nChar
== ')' && CursorAtClosingPar() )
3373 vcl::Window
* pFrameWin
= pActiveViewSh
? pActiveViewSh
->GetFrameWin() : nullptr;
3374 if ( pTableView
->PostKeyEvent( rKEvt
, pFrameWin
) )
3378 if ( pTopView
->PostKeyEvent( rKEvt
) )
3383 if ( bUsed
&& bAutoComplete
)
3387 miAutoPosFormula
= pFormulaData
->end(); // do not search further
3389 miAutoPosColumn
= pColumnData
->end();
3391 KeyFuncType eFunc
= rKEvt
.GetKeyCode().GetFunction();
3392 if ( nChar
&& nChar
!= 8 && nChar
!= 127 && // no 'backspace', no 'delete'
3393 KeyFuncType::CUT
!= eFunc
) // and no 'CTRL-X'
3402 // When the selection is changed manually or an opening parenthesis
3403 // is typed, stop overwriting parentheses
3404 if ( bUsed
&& nChar
== '(' )
3407 if ( KEY_INSERT
== nCode
)
3409 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
3411 pViewFrm
->GetBindings().Invalidate( SID_ATTR_INSERT
);
3413 if( bUsed
&& bFormulaMode
&& ( bCursorKey
|| bInsKey
|| nCode
== KEY_DELETE
|| nCode
== KEY_BACKSPACE
) )
3417 if( bUsed
&& bFormulaMode
&& nCode
== KEY_BACKSPACE
)
3427 // #i114511# don't count cursor keys as modification
3428 bool bSetModified
= !bCursorKey
;
3429 DataChanged(false, bSetModified
); // also calls UpdateParenthesis()
3430 InvalidateAttribs(); //! in DataChanged?
3434 if (pTopView
&& eMode
!= SC_INPUT_NONE
)
3440 void ScInputHandler::InputCommand( const CommandEvent
& rCEvt
)
3442 if ( rCEvt
.GetCommand() == CommandEventId::CursorPos
)
3444 // For CommandEventId::CursorPos, do as little as possible, because
3445 // with remote VCL, even a ShowCursor will generate another event.
3446 if ( eMode
!= SC_INPUT_NONE
)
3449 if (pTableView
|| pTopView
)
3452 pTableView
->Command( rCEvt
);
3453 else if (pTopView
) // call only once
3454 pTopView
->Command( rCEvt
);
3458 else if ( rCEvt
.GetCommand() == CommandEventId::QueryCharPosition
)
3460 if ( eMode
!= SC_INPUT_NONE
)
3463 if (pTableView
|| pTopView
)
3466 pTableView
->Command( rCEvt
);
3467 else if (pTopView
) // call only once
3468 pTopView
->Command( rCEvt
);
3476 bAutoComplete
= SC_MOD()->GetAppOptions().GetAutoComplete();
3490 bool bNewView
= DataChanging( 0, true );
3492 if (!bProtected
) // changes allowed
3494 if (bNewView
) // create new edit view
3497 pActiveViewSh
->GetViewData().GetDocShell()->PostEditView( pEngine
, aCursorPos
);
3499 if (eMode
==SC_INPUT_NONE
)
3500 if (pTableView
|| pTopView
)
3505 pTableView
->GetEditEngine()->SetText( aStrLoP
);
3506 pTableView
->SetSelection( ESelection(0,0, 0,0) );
3510 pTopView
->GetEditEngine()->SetText( aStrLoP
);
3511 pTopView
->SetSelection( ESelection(0,0, 0,0) );
3517 if (pTableView
|| pTopView
)
3520 pTableView
->Command( rCEvt
);
3522 pTopView
->Command( rCEvt
);
3524 if ( rCEvt
.GetCommand() == CommandEventId::EndExtTextInput
)
3526 // AutoInput after ext text input
3529 miAutoPosFormula
= pFormulaData
->end();
3531 miAutoPosColumn
= pColumnData
->end();
3540 DataChanged(); // calls UpdateParenthesis()
3541 InvalidateAttribs(); //! in DataChanged ?
3544 if (pTopView
&& eMode
!= SC_INPUT_NONE
)
3549 void ScInputHandler::NotifyChange( const ScInputHdlState
* pState
,
3550 bool bForce
, ScTabViewShell
* pSourceSh
,
3553 // If the call originates from a macro call in the EnterHandler,
3554 // return immediately and don't mess up the status
3555 if (bInEnterHandler
)
3558 bool bRepeat
= (pState
== pLastState
);
3559 if (!bRepeat
&& pState
&& pLastState
)
3560 bRepeat
= (*pState
== *pLastState
);
3561 if (bRepeat
&& !bForce
)
3564 bInOwnChange
= true; // disable ModifyHdl (reset below)
3566 if ( pState
&& !pLastState
) // Enable again
3569 bool bHadObject
= pLastState
&& pLastState
->GetEditData();
3571 //! Before EditEngine gets eventually created (so it gets the right pools)
3573 pActiveViewSh
= pSourceSh
;
3575 pActiveViewSh
= dynamic_cast<ScTabViewShell
*>( SfxViewShell::Current() );
3577 ImplCreateEditEngine();
3579 if ( pState
!= pLastState
)
3582 pLastState
= pState
? new ScInputHdlState( *pState
) : nullptr;
3585 if ( pState
&& pActiveViewSh
)
3587 ScModule
* pScMod
= SC_MOD();
3592 // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
3593 // FormEditData, if we're switching from Help to Calc:
3594 if ( !bFormulaMode
&& !pScMod
->IsFormulaMode() && !pScMod
->GetFormEditData() )
3596 bool bIgnore
= false;
3599 if (pState
->GetPos() != aCursorPos
)
3610 const ScAddress
& rSPos
= pState
->GetStartPos();
3611 const ScAddress
& rEPos
= pState
->GetEndPos();
3612 const EditTextObject
* pData
= pState
->GetEditData();
3613 OUString aString
= pState
->GetString();
3614 bool bTxtMod
= false;
3615 ScDocShell
* pDocSh
= pActiveViewSh
->GetViewData().GetDocShell();
3616 ScDocument
& rDoc
= pDocSh
->GetDocument();
3618 aCursorPos
= pState
->GetPos();
3622 else if ( bHadObject
)
3624 else if ( bTextValid
)
3625 bTxtMod
= ( !aString
.equals(aCurrentText
) );
3627 bTxtMod
= ( !aString
.equals(GetEditText(pEngine
)) );
3629 if ( bTxtMod
|| bForce
)
3633 pEngine
->SetText( *pData
);
3635 aString
= ScEditUtil::GetMultilineString(*pEngine
);
3637 aString
= GetEditText(pEngine
);
3638 lcl_RemoveTabs(aString
);
3640 aCurrentText
.clear();
3644 aCurrentText
= aString
;
3645 bTextValid
= true; //! To begin with remember as a string
3649 pInputWin
->SetTextString(aString
);
3650 else if ( comphelper::LibreOfficeKit::isActive() )
3651 rDoc
.GetDrawLayer()->libreOfficeKitCallback(LOK_CALLBACK_CELL_FORMULA
, aString
.toUtf8().getStr());
3654 if ( pInputWin
) // Named range input
3657 const ScAddress::Details
aAddrDetails( &rDoc
, aCursorPos
);
3659 // Is the range a name?
3661 if ( pActiveViewSh
)
3662 pActiveViewSh
->GetViewData().GetDocument()->
3663 GetRangeAtBlock( ScRange( rSPos
, rEPos
), &aPosStr
);
3665 if ( aPosStr
.isEmpty() ) // Not a name -> format
3667 ScRefFlags nFlags
= ScRefFlags::ZERO
;
3668 if( aAddrDetails
.eConv
== formula::FormulaGrammar::CONV_XL_R1C1
)
3669 nFlags
|= ScRefFlags::COL_ABS
| ScRefFlags::ROW_ABS
;
3670 if ( rSPos
!= rEPos
)
3672 ScRange
r(rSPos
, rEPos
);
3673 applyStartToEndFlags(nFlags
);
3674 aPosStr
= r
.Format(ScRefFlags::VALID
| nFlags
, &rDoc
, aAddrDetails
);
3677 aPosStr
= aCursorPos
.Format(ScRefFlags::VALID
| nFlags
, &rDoc
, aAddrDetails
);
3680 // Disable the accessible VALUE_CHANGE event
3681 bool bIsSuppressed
= pInputWin
->IsAccessibilityEventsSuppressed(false);
3682 pInputWin
->SetAccessibilityEventsSuppressed(true);
3683 pInputWin
->SetPosString(aPosStr
);
3684 pInputWin
->SetAccessibilityEventsSuppressed(bIsSuppressed
);
3685 pInputWin
->SetSumAssignMode();
3689 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW
) );
3691 // As long as the content is not edited, turn off online spelling.
3692 // Online spelling is turned back on in StartTable, after setting
3693 // the right language from cell attributes.
3695 EEControlBits nCntrl
= pEngine
->GetControlWord();
3696 if ( nCntrl
& EEControlBits::ONLINESPELLING
)
3697 pEngine
->SetControlWord( nCntrl
& ~EEControlBits::ONLINESPELLING
);
3702 bCommandErrorShown
= false;
3709 // Do not enable if RefDialog is open
3710 if(!pScMod
->IsFormulaMode()&& !pScMod
->IsRefDialogOpen())
3712 if ( !pInputWin
->IsEnabled())
3714 pInputWin
->Enable();
3717 DELETEZ( pDelayTimer
);
3721 else if(pScMod
->IsRefDialogOpen())
3722 { // Because every document has its own InputWin,
3723 // we should start Timer again, because the input line may
3727 pDelayTimer
= new Timer
;
3728 pDelayTimer
->SetTimeout( 500 ); // 500 ms delay
3729 pDelayTimer
->SetTimeoutHdl( LINK( this, ScInputHandler
, DelayTimer
) );
3730 pDelayTimer
->Start();
3735 else // !pState || !pActiveViewSh
3739 pDelayTimer
= new Timer
;
3740 pDelayTimer
->SetTimeout( 500 ); // 500 ms delay
3741 pDelayTimer
->SetTimeoutHdl( LINK( this, ScInputHandler
, DelayTimer
) );
3742 pDelayTimer
->Start();
3748 bInOwnChange
= false;
3751 void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust
)
3753 eAttrAdjust
= eJust
;
3757 void ScInputHandler::ResetDelayTimer()
3759 if(pDelayTimer
!=nullptr)
3761 DELETEZ( pDelayTimer
);
3765 pInputWin
->Enable();
3770 IMPL_LINK_TYPED( ScInputHandler
, DelayTimer
, Timer
*, pTimer
, void )
3772 if ( pTimer
== pDelayTimer
)
3774 DELETEZ( pDelayTimer
);
3776 if ( nullptr == pLastState
|| SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
3778 //! New method at ScModule to query if function autopilot is open
3779 SfxViewFrame
* pViewFrm
= SfxViewFrame::Current();
3780 if ( pViewFrm
&& pViewFrm
->GetChildWindow( SID_OPENDLG_FUNCTION
) )
3784 pInputWin
->EnableButtons( false );
3785 pInputWin
->Disable();
3788 else if ( !bFormulaMode
) // Keep formula e.g. for help
3790 bInOwnChange
= true; // disable ModifyHdl (reset below)
3792 pActiveViewSh
= nullptr;
3793 pEngine
->SetText( EMPTY_OUSTRING
);
3796 pInputWin
->SetPosString( EMPTY_OUSTRING
);
3797 pInputWin
->SetTextString( EMPTY_OUSTRING
);
3798 pInputWin
->Disable();
3801 bInOwnChange
= false;
3807 void ScInputHandler::InputSelection( EditView
* pView
)
3811 UpdateParenthesis(); // Selection changed -> update parentheses highlighting
3813 // When the selection is changed manually, stop overwriting parentheses
3817 void ScInputHandler::InputChanged( EditView
* pView
, bool bFromNotify
)
3821 // #i20282# DataChanged needs to know if this is from the input line's modify handler
3822 bool bFromTopNotify
= ( bFromNotify
&& pView
== pTopView
);
3824 bool bNewView
= DataChanging(); //FIXME: Is this at all possible?
3825 aCurrentText
= pView
->GetEditEngine()->GetText(); // Also remember the string
3826 pEngine
->SetText( aCurrentText
);
3827 DataChanged( bFromTopNotify
);
3828 bTextValid
= true; // Is set to false in DataChanged
3830 if ( pActiveViewSh
)
3832 ScViewData
& rViewData
= pActiveViewSh
->GetViewData();
3834 rViewData
.GetDocShell()->PostEditView( pEngine
, aCursorPos
);
3836 rViewData
.EditGrowY();
3837 rViewData
.EditGrowX();
3843 const OUString
& ScInputHandler::GetEditString()
3847 aCurrentText
= pEngine
->GetText(); // Always new from Engine
3851 return aCurrentText
;
3854 Size
ScInputHandler::GetTextSize()
3858 aSize
= Size( pEngine
->CalcTextWidth(), pEngine
->GetTextHeight() );
3863 bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter
& rDestEngine
)
3869 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
3870 SfxItemSet aSet
= pEngine
->GetAttribs( ESelection(0,0,nParCnt
,0) );
3871 SfxItemState eFieldState
= aSet
.GetItemState( EE_FEATURE_FIELD
, false );
3872 if ( eFieldState
== SfxItemState::DONTCARE
|| eFieldState
== SfxItemState::SET
)
3875 EditTextObject
* pObj
= pEngine
->CreateTextObject();
3876 rDestEngine
.SetText(*pObj
);
3879 // Delete attributes
3880 for (sal_Int32 i
=0; i
<nParCnt
; i
++)
3881 rDestEngine
.RemoveCharAttribs( i
);
3883 // Combine paragraphs
3884 while ( nParCnt
> 1 )
3886 sal_Int32 nLen
= rDestEngine
.GetTextLen( 0 );
3887 ESelection
aSel( 0,nLen
, 1,0 );
3888 rDestEngine
.QuickInsertText( OUString(' '), aSel
); // Replace line break with space
3899 * Methods for FunctionAutoPilot:
3900 * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
3902 void ScInputHandler::InputGetSelection( sal_Int32
& rStart
, sal_Int32
& rEnd
)
3904 rStart
= nFormSelStart
;
3908 EditView
* ScInputHandler::GetFuncEditView()
3910 UpdateActiveView(); // Due to pTableView
3912 EditView
* pView
= nullptr;
3915 pInputWin
->MakeDialogEditView();
3916 pView
= pInputWin
->GetEditView();
3920 if ( eMode
!= SC_INPUT_TABLE
)
3922 bCreatingFuncView
= true; // Don't display RangeFinder
3923 SetMode( SC_INPUT_TABLE
);
3924 bCreatingFuncView
= false;
3926 pTableView
->GetEditEngine()->SetText( EMPTY_OUSTRING
);
3934 void ScInputHandler::InputSetSelection( sal_Int32 nStart
, sal_Int32 nEnd
)
3936 if ( nStart
<= nEnd
)
3938 nFormSelStart
= nStart
;
3943 nFormSelEnd
= nStart
;
3944 nFormSelStart
= nEnd
;
3947 EditView
* pView
= GetFuncEditView();
3949 pView
->SetSelection( ESelection(0,nStart
, 0,nEnd
) );
3954 void ScInputHandler::InputReplaceSelection( const OUString
& rStr
)
3957 pRefViewSh
= pActiveViewSh
;
3959 OSL_ENSURE(nFormSelEnd
>=nFormSelStart
,"Selection broken...");
3961 sal_Int32 nOldLen
= nFormSelEnd
- nFormSelStart
;
3962 sal_Int32 nNewLen
= rStr
.getLength();
3964 OUStringBuffer
aBuf(aFormText
);
3966 aBuf
.remove(nFormSelStart
, nOldLen
);
3968 aBuf
.insert(nFormSelStart
, rStr
);
3970 aFormText
= aBuf
.makeStringAndClear();
3972 nFormSelEnd
= nFormSelStart
+ nNewLen
;
3974 EditView
* pView
= GetFuncEditView();
3977 pView
->SetEditEngineUpdateMode( false );
3978 pView
->GetEditEngine()->SetText( aFormText
);
3979 pView
->SetSelection( ESelection(0,nFormSelStart
, 0,nFormSelEnd
) );
3980 pView
->SetEditEngineUpdateMode( true );
3985 void ScInputHandler::InputTurnOffWinEngine()
3987 bInOwnChange
= true; // disable ModifyHdl (reset below)
3989 eMode
= SC_INPUT_NONE
;
3990 /* TODO: it would be better if there was some way to reset the input bar
3991 * engine instead of deleting and having it recreate through
3992 * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
3993 * fdo#72278 without reintroducing fdo#69971. */
3994 StopInputWinEngine(true);
3996 bInOwnChange
= false;
4002 ScInputHdlState::ScInputHdlState( const ScAddress
& rCurPos
,
4003 const ScAddress
& rStartPos
,
4004 const ScAddress
& rEndPos
,
4005 const OUString
& rString
,
4006 const EditTextObject
* pData
)
4007 : aCursorPos ( rCurPos
),
4008 aStartPos ( rStartPos
),
4009 aEndPos ( rEndPos
),
4010 aString ( rString
),
4011 pEditData ( pData
? pData
->Clone() : nullptr )
4015 ScInputHdlState::ScInputHdlState( const ScInputHdlState
& rCpy
)
4016 : pEditData ( nullptr )
4021 ScInputHdlState::~ScInputHdlState()
4026 bool ScInputHdlState::operator==( const ScInputHdlState
& r
) const
4028 return ( (aStartPos
== r
.aStartPos
)
4029 && (aEndPos
== r
.aEndPos
)
4030 && (aCursorPos
== r
.aCursorPos
)
4031 && (aString
== r
.aString
)
4032 && ScGlobal::EETextObjEqual( pEditData
, r
.pEditData
) );
4035 ScInputHdlState
& ScInputHdlState::operator=( const ScInputHdlState
& r
)
4039 aCursorPos
= r
.aCursorPos
;
4040 aStartPos
= r
.aStartPos
;
4041 aEndPos
= r
.aEndPos
;
4042 aString
= r
.aString
;
4043 pEditData
= r
.pEditData
? r
.pEditData
->Clone() : nullptr;
4048 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */