LibreOffice Module sc (master) 1
inputhdl.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <iterator>
21#include <memory>
22#include <string_view>
23
24#include <inputhdl.hxx>
25#include <scitems.hxx>
26#include <editeng/eeitem.hxx>
27
28#include <sfx2/app.hxx>
29#include <editeng/acorrcfg.hxx>
32#include <editeng/brushitem.hxx>
33#include <svtools/colorcfg.hxx>
34#include <editeng/colritem.hxx>
35#include <editeng/editobj.hxx>
36#include <editeng/editstat.hxx>
37#include <editeng/editview.hxx>
38#include <editeng/langitem.hxx>
39#include <editeng/svxacorr.hxx>
40#include <editeng/unolingu.hxx>
41#include <editeng/wghtitem.hxx>
44#include <sfx2/bindings.hxx>
45#include <sfx2/viewfrm.hxx>
46#include <sfx2/docfile.hxx>
47#include <sfx2/printer.hxx>
48#include <svl/numformat.hxx>
49#include <svl/zforlist.hxx>
52#include <utility>
53#include <vcl/help.hxx>
55#include <vcl/commandevent.hxx>
56#include <vcl/cursor.hxx>
57#include <vcl/settings.hxx>
58#include <vcl/svapp.hxx>
59#include <tools/urlobj.hxx>
61#include <formula/funcvarargs.h>
62#include <LibreOfficeKit/LibreOfficeKitEnums.h>
63#include <comphelper/lok.hxx>
64#include <osl/diagnose.h>
65
66#include <attrib.hxx>
67#include <inputwin.hxx>
68#include <tabvwsh.hxx>
69#include <docsh.hxx>
70#include <scmod.hxx>
71#include <formulaopt.hxx>
72#include <uiitems.hxx>
73#include <global.hxx>
74#include <sc.hrc>
75#include <globstr.hrc>
76#include <scresid.hxx>
77#include <patattr.hxx>
78#include <viewdata.hxx>
79#include <document.hxx>
80#include <docpool.hxx>
81#include <editutil.hxx>
82#include <appoptio.hxx>
83#include <docoptio.hxx>
84#include <validat.hxx>
85#include <rfindlst.hxx>
86#include <inputopt.hxx>
87#include <simpleformulacalc.hxx>
88#include <compiler.hxx>
89#include <editable.hxx>
90#include <funcdesc.hxx>
91#include <markdata.hxx>
92#include <tokenarray.hxx>
93#include <gridwin.hxx>
94#include <output.hxx>
95#include <fillinfo.hxx>
96
97// Maximum Ranges in RangeFinder
98#define RANGEFIND_MAX 128
99
100using namespace formula;
101
102namespace {
103
104ScTypedCaseStrSet::const_iterator findText(
105 const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
106 const OUString& rStart, OUString& rResult, bool bBack)
107{
108 auto lIsMatch = [&rStart](const ScTypedStrData& rData) {
109 return (rData.GetStringType() != ScTypedStrData::Value) && ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()); };
110
111 if (bBack) // Backwards
112 {
113 ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
114 if (itPos != rDataSet.end())
115 {
116 size_t nPos = std::distance(rDataSet.begin(), itPos);
117 size_t nRPos = rDataSet.size() - 1 - nPos;
118 std::advance(it, nRPos);
119 ++it;
120 }
121
122 it = std::find_if(it, itEnd, lIsMatch);
123 if (it != itEnd)
124 {
125 rResult = it->GetString();
126 return (++it).base(); // convert the reverse iterator back to iterator.
127 }
128 }
129 else // Forwards
130 {
131 ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
132 if (itPos != itEnd)
133 {
134 it = std::next(itPos);
135 }
136
137 it = std::find_if(it, itEnd, lIsMatch);
138 if (it != itEnd)
139 {
140 rResult = it->GetString();
141 return it;
142 }
143 }
144
145 return rDataSet.end(); // no matching text found
146}
147
148OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
149{
150 auto it = std::find_if(rDataSet.begin(), rDataSet.end(),
151 [&rString](const ScTypedStrData& rData) {
152 return (rData.GetStringType() != ScTypedStrData::Value)
153 && ScGlobal::GetTransliteration().isEqual(rData.GetString(), rString);
154 });
155 if (it != rDataSet.end())
156 return it->GetString();
157 return rString;
158}
159
160// This assumes that rResults is a sorted ring w.r.t ScTypedStrData::LessCaseInsensitive() or
161// in the reverse direction, whose origin is specified by nRingOrigin.
162sal_Int32 getLongestCommonPrefixLength(const std::vector<OUString>& rResults, std::u16string_view aUserEntry, sal_Int32 nRingOrigin)
163{
164 sal_Int32 nResults = rResults.size();
165 if (!nResults)
166 return 0;
167
168 if (nResults == 1)
169 return rResults[0].getLength();
170
171 sal_Int32 nMinLen = aUserEntry.size();
172 sal_Int32 nLastIdx = nRingOrigin ? nRingOrigin - 1 : nResults - 1;
173 const OUString& rFirst = rResults[nRingOrigin];
174 const OUString& rLast = rResults[nLastIdx];
175 const sal_Int32 nMaxLen = std::min(rFirst.getLength(), rLast.getLength());
176
177 for (sal_Int32 nLen = nMaxLen; nLen > nMinLen; --nLen)
178 {
179 if (ScGlobal::GetTransliteration().isMatch(rFirst.copy(0, nLen), rLast))
180 return nLen;
181 }
182
183 return nMinLen;
184}
185
186ScTypedCaseStrSet::const_iterator findTextAll(
187 const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
188 const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, sal_Int32* pLongestPrefixLen = nullptr)
189{
190 rResultVec.clear(); // clear contents
191
192 if (!rDataSet.size())
193 return rDataSet.end();
194
195 sal_Int32 nRingOrigin = 0;
196 size_t nCount = 0;
197 ScTypedCaseStrSet::const_iterator retit;
198 if ( bBack ) // Backwards
199 {
200 ScTypedCaseStrSet::const_reverse_iterator it, itEnd;
201 if ( itPos == rDataSet.end() )
202 {
203 it = rDataSet.rend();
204 --it;
205 itEnd = it;
206 }
207 else
208 {
209 it = rDataSet.rbegin();
210 size_t nPos = std::distance(rDataSet.begin(), itPos);
211 size_t nRPos = rDataSet.size() - 1 - nPos; // if itPos == rDataSet.end(), then nRPos = -1
212 std::advance(it, nRPos);
213 if ( it == rDataSet.rend() )
214 it = rDataSet.rbegin();
215 itEnd = it;
216 }
217 bool bFirstTime = true;
218
219 while ( it != itEnd || bFirstTime )
220 {
221 ++it;
222 if ( it == rDataSet.rend() ) // go to the first if reach the end
223 {
224 it = rDataSet.rbegin();
225 nRingOrigin = nCount;
226 }
227
228 if ( bFirstTime )
229 bFirstTime = false;
230 const ScTypedStrData& rData = *it;
231 if ( rData.GetStringType() == ScTypedStrData::Value )
232 // skip values
233 continue;
234
235 if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
236 // not a match
237 continue;
238
239 rResultVec.push_back(rData.GetString()); // set the match data
240 if ( nCount == 0 ) // convert the reverse iterator back to iterator.
241 {
242 // actually we want to do "retit = it;".
243 retit = rDataSet.begin();
244 size_t nRPos = std::distance(rDataSet.rbegin(), it);
245 size_t nPos = rDataSet.size() - 1 - nRPos;
246 std::advance(retit, nPos);
247 }
248 ++nCount;
249 }
250 }
251 else // Forwards
252 {
253 ScTypedCaseStrSet::const_iterator it, itEnd;
254 it = itPos;
255 if ( it == rDataSet.end() )
256 it = --rDataSet.end();
257 itEnd = it;
258 bool bFirstTime = true;
259
260 while ( it != itEnd || bFirstTime )
261 {
262 ++it;
263 if ( it == rDataSet.end() ) // go to the first if reach the end
264 {
265 it = rDataSet.begin();
266 nRingOrigin = nCount;
267 }
268
269 if ( bFirstTime )
270 bFirstTime = false;
271 const ScTypedStrData& rData = *it;
272 if ( rData.GetStringType() == ScTypedStrData::Value )
273 // skip values
274 continue;
275
276 if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
277 // not a match
278 continue;
279
280 rResultVec.push_back(rData.GetString()); // set the match data
281 if ( nCount == 0 )
282 retit = it; // remember first match iterator
283 ++nCount;
284 }
285 }
286
287 if (pLongestPrefixLen)
288 {
289 if (nRingOrigin >= static_cast<sal_Int32>(nCount))
290 {
291 // All matches were picked when rDataSet was read in one direction.
292 nRingOrigin = 0;
293 }
294 // rResultsVec is a sorted ring with nRingOrigin "origin".
295 // The direction of sorting is not important for getLongestCommonPrefixLength.
296 *pLongestPrefixLen = getLongestCommonPrefixLength(rResultVec, rStart, nRingOrigin);
297 }
298
299 if ( nCount > 0 ) // at least one function has matched
300 return retit;
301 return rDataSet.end(); // no matching text found
302}
303
304}
305
307 const std::vector<ReferenceMark>& rReferenceMarks )
308{
309 if ( !pViewShell )
310 return;
311
312 bool bSend = false;
313
315
316 ss << "{ \"marks\": [ ";
317
318 for ( size_t i = 0; i < rReferenceMarks.size(); i++ )
319 {
320 if ( rReferenceMarks[i].Is() )
321 {
322 if ( bSend )
323 ss << ", ";
324
325 ss << "{ \"rectangle\": \""
326 << rReferenceMarks[i].nX << ", "
327 << rReferenceMarks[i].nY << ", "
328 << rReferenceMarks[i].nWidth << ", "
329 << rReferenceMarks[i].nHeight << "\", "
330 "\"color\": \"" << rReferenceMarks[i].aColor.AsRGBHexString() << "\", "
331 "\"part\": \"" << rReferenceMarks[i].nTab << "\" } ";
332
333 bSend = true;
334 }
335 }
336
337 ss << " ] }";
338
339 OString aPayload = ss.str().c_str();
340 pViewShell->libreOfficeKitViewCallback(
341 LOK_CALLBACK_REFERENCE_MARKS, aPayload.getStr() );
342}
343
344void ScInputHandler::InitRangeFinder( const OUString& rFormula )
345{
347 if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
348 return;
350 ScDocument& rDoc = pDocSh->GetDocument();
351 const sal_Unicode cSheetSep = rDoc.GetSheetSeparator();
352
353 OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !~\"");
354 // delimiters (in addition to ScEditUtil): only characters that are
355 // allowed in formulas next to references and the quotation mark (so
356 // string constants can be skipped)
357
358 sal_Int32 nColon = aDelimiters.indexOf( ':' );
359 if ( nColon != -1 )
360 aDelimiters = aDelimiters.replaceAt( nColon, 1, u""); // Delimiter without colon
361 sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
362 if ( nDot != -1 )
363 aDelimiters = aDelimiters.replaceAt( nDot, 1 , u""); // Delimiter without dot
364
365 const sal_Unicode* pChar = rFormula.getStr();
366 sal_Int32 nLen = rFormula.getLength();
367 sal_Int32 nPos = 0;
368 sal_Int32 nStart = 0;
369 sal_uInt16 nCount = 0;
370 ScRange aRange;
371 while ( nPos < nLen && nCount < RANGEFIND_MAX )
372 {
373 // Skip separator
374 while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
375 {
376 if ( pChar[nPos] == '"' ) // String
377 {
378 ++nPos;
379 while (nPos<nLen && pChar[nPos] != '"') // Skip until end
380 ++nPos;
381 }
382 ++nPos; // Separator or closing quote
383 }
384
385 // text between separators
386 nStart = nPos;
387handle_r1c1:
388 {
389 bool bSingleQuoted = false;
390 while (nPos < nLen)
391 {
392 // tdf#114113: handle addresses with quoted sheet names like "'Sheet 1'.A1"
393 // Literal single quotes in sheet names are masked by another single quote
394 if (pChar[nPos] == '\'')
395 {
396 bSingleQuoted = !bSingleQuoted;
397 }
398 else if (!bSingleQuoted) // Get everything in single quotes, including separators
399 {
400 if (ScGlobal::UnicodeStrChr(aDelimiters.getStr(), pChar[nPos]))
401 break;
402 }
403 ++nPos;
404 }
405 }
406
407 // for R1C1 '-' in R[-]... or C[-]... are not delimiters
408 // Nothing heroic here to ensure that there are '[]' around a negative
409 // integer. we need to clean up this code.
410 if( nPos < nLen && nPos > 0 &&
411 '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
413 {
414 nPos++;
415 goto handle_r1c1;
416 }
417
418 if ( nPos > nStart )
419 {
420 OUString aTest = rFormula.copy( nStart, nPos-nStart );
421 const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
422 ScRefFlags nFlags = aRange.ParseAny( aTest, rDoc, aAddrDetails );
423 if ( nFlags & ScRefFlags::VALID )
424 {
425 // Set tables if not specified
426 if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO)
428 if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO)
429 aRange.aEnd.SetTab( aRange.aStart.Tab() );
430
433 {
434 // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
435 // so Format doesn't output a double ref because of different flags.
437 applyStartToEndFlags(nFlags, nAbsFlags);
438 }
439
440 if (!nCount)
441 {
442 mpEditEngine->SetUpdateLayout( false );
443 pRangeFindList.reset(new ScRangeFindList( pDocSh->GetTitle() ));
444 }
445
446 Color nColor = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
447
448 ESelection aSel( 0, nStart, 0, nPos );
449 SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
450 aSet.Put( SvxColorItem( nColor, EE_CHAR_COLOR ) );
451 mpEditEngine->QuickSetAttribs( aSet, aSel );
452 ++nCount;
453 }
454 }
455
456 // Do not skip last separator; could be a quote (?)
457 }
458
460
461 if (nCount)
462 {
463 mpEditEngine->SetUpdateLayout( true );
464
465 pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) );
466 }
467}
468
471 tools::Long nTab, const Color& rColor )
472{
473 ScSplitPos eWhich = rViewData.GetActivePart();
474
475 // This method is LOK specific.
477 comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
478 {
479 SCCOL nCol1 = nX1, nCol2 = nX2;
480 SCROW nRow1 = nY1, nRow2 = nY2;
481 PutInOrder(nCol1, nCol2);
482 PutInOrder(nRow1, nRow2);
483 if (nCol1 == nCol2 && nRow1 == nRow2)
484 pDocSh->GetDocument().ExtendMerge(nCol1, nRow1, nCol2, nRow2, nTab);
485
486 Point aTopLeft = rViewData.GetPrintTwipsPos(nCol1, nRow1);
487 Point aBottomRight = rViewData.GetPrintTwipsPos(nCol2 + 1, nRow2 + 1);
488 tools::Long nSizeX = aBottomRight.X() - aTopLeft.X() - 1;
489 tools::Long nSizeY = aBottomRight.Y() - aTopLeft.Y() - 1;
490
491 return ReferenceMark(aTopLeft.X(), aTopLeft.Y(), nSizeX, nSizeY, nTab, rColor);
492 }
493
494 Point aScrPos = rViewData.GetScrPos( nX1, nY1, eWhich );
495 tools::Long nScrX = aScrPos.X();
496 tools::Long nScrY = aScrPos.Y();
497
498 double nPPTX = rViewData.GetPPTX();
499 double nPPTY = rViewData.GetPPTY();
500
501 Fraction aZoomX = rViewData.GetZoomX();
502 Fraction aZoomY = rViewData.GetZoomY();
503
504 ScTableInfo aTabInfo;
505 pDocSh->GetDocument().FillInfo( aTabInfo, nX1, nY1, nX2, nY2,
506 nTab, nPPTX, nPPTY, false, false );
507
508 ScOutputData aOutputData( nullptr, OUTTYPE_WINDOW, aTabInfo,
509 &( pDocSh->GetDocument() ), nTab,
510 nScrX, nScrY,
511 nX1, nY1, nX2, nY2,
512 nPPTX, nPPTY,
513 &aZoomX, &aZoomY );
514
515 return aOutputData.FillReferenceMark( nX1, nY1, nX2, nY2,
516 rColor );
517}
518
520{
522 return;
523
525 : dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
526
527 if (!pShell)
528 return;
529
530 ScViewData& rViewData = pShell->GetViewData();
531 ScDocShell* pDocSh = rViewData.GetDocShell();
532 ScRangeFindList* pRangeFinder = GetRangeFindList();
533
534 if ( !pRangeFinder && !rViewData.IsRefMode() )
535 return;
536
537 sal_uInt16 nAdditionalMarks = 0;
538 std::vector<ReferenceMark> aReferenceMarks( 1 );
539
540 if ( rViewData.IsRefMode() )
541 {
542 nAdditionalMarks = 1;
543
544 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
545 Color aRefColor( rColorCfg.GetColorValue( svtools::CALCREFERENCE ).nColor );
546 tools::Long nX1 = rViewData.GetRefStartX();
547 tools::Long nX2 = rViewData.GetRefEndX();
548 tools::Long nY1 = rViewData.GetRefStartY();
549 tools::Long nY2 = rViewData.GetRefEndY();
550 tools::Long nTab = rViewData.GetRefStartZ();
551
552 if (rViewData.GetRefEndZ() == rViewData.GetTabNo())
553 nTab = rViewData.GetRefEndZ();
554
555 PutInOrder(nX1, nX2);
556 PutInOrder(nY1, nY2);
557
558 aReferenceMarks[0] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
559 nX1, nX2, nY1, nY2,
560 nTab, aRefColor );
561 }
562
563 sal_uInt16 nCount = pRangeFinder ?
564 ( static_cast<sal_uInt16>( pRangeFinder->Count() ) + nAdditionalMarks ) : nAdditionalMarks;
565 aReferenceMarks.resize( nCount );
566
567 if ( nCount && pRangeFinder && !pRangeFinder->IsHidden() &&
568 pRangeFinder->GetDocName() == pDocSh->GetTitle() )
569 {
570 for (sal_uInt16 i = 0; i < nCount - nAdditionalMarks; i++)
571 {
572 ScRangeFindData& rData = pRangeFinder->GetObject( i );
573 ScRange aRef = rData.aRef;
574 aRef.PutInOrder();
575
576 tools::Long nX1 = aRef.aStart.Col();
577 tools::Long nX2 = aRef.aEnd.Col();
578 tools::Long nY1 = aRef.aStart.Row();
579 tools::Long nY2 = aRef.aEnd.Row();
580 tools::Long nTab = aRef.aStart.Tab();
581
582 aReferenceMarks[i + nAdditionalMarks] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
583 nX1, nX2, nY1, nY2,
584 nTab, rData.nColor );
585
586 ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
587 }
588 }
589 else if ( nCount )
590 {
591 ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
592 }
593 else
594 {
595 // Clear
596 aReferenceMarks.clear();
597 ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
598 }
599}
600
602{
604}
605
606static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
607{
608 if ( !pView )
609 return;
610
611 ESelection aOldSel = pView->GetSelection();
612 if (aOldSel.HasRange())
613 pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
614 aOldSel.nEndPara, aOldSel.nEndPos ) );
615
616 EditEngine* pEngine = pView->GetEditEngine();
617 pEngine->QuickInsertText( rNewStr, rOldSel );
618
619 // Dummy InsertText for Update and Paint
620 // To do that we need to cancel the selection from above (before QuickInsertText)
621 pView->InsertText( OUString() );
622
623 sal_Int32 nLen = pEngine->GetTextLen(0);
624 ESelection aSel( 0, nLen, 0, nLen );
625 pView->SetSelection( aSel ); // Set cursor to the end
626}
627
628void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
629{
631 if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
632 {
633 ScRangeFindData& rData = pRangeFindList->GetObject( nIndex );
634 sal_Int32 nOldStart = rData.nSelStart;
635 sal_Int32 nOldEnd = rData.nSelEnd;
636 Color nNewColor = pRangeFindList->FindColor( rNew, nIndex );
637
638 ScRange aJustified = rNew;
639 aJustified.PutInOrder(); // Always display Ref in the Formula the right way
640 ScDocument& rDoc = pDocView->GetViewData().GetDocument();
641 const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
642 OUString aNewStr(aJustified.Format(rDoc, rData.nFlags, aAddrDetails));
643 ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
644 SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
645
646 DataChanging();
647
648 lcl_Replace( pTopView, aNewStr, aOldSel );
649 lcl_Replace( pTableView, aNewStr, aOldSel );
650 aSet.Put( SvxColorItem( nNewColor, EE_CHAR_COLOR ) );
651 mpEditEngine->QuickSetAttribs( aSet, aOldSel );
652
653 bInRangeUpdate = true;
654 DataChanged();
655 bInRangeUpdate = false;
656
657 tools::Long nDiff = aNewStr.getLength() - static_cast<tools::Long>(nOldEnd-nOldStart);
658
659 rData.aRef = rNew;
660 rData.nSelEnd = rData.nSelEnd + nDiff;
661 rData.nColor = nNewColor;
662
663 sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFindList->Count());
664 for (sal_uInt16 i=nIndex+1; i<nCount; i++)
665 {
666 ScRangeFindData& rNext = pRangeFindList->GetObject( i );
667 rNext.nSelStart = rNext.nSelStart + nDiff;
668 rNext.nSelEnd = rNext.nSelEnd + nDiff;
669 }
670
671 EditView* pActiveView = pTopView ? pTopView : pTableView;
672 pActiveView->ShowCursor( false );
673 }
674 else
675 {
676 OSL_FAIL("UpdateRange: we're missing something");
677 }
678}
679
681{
683 if ( pRangeFindList && pPaintView )
684 {
686 pRangeFindList->SetHidden(true);
687 pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) ); // Steal
688 pRangeFindList.reset();
689 }
690}
691
692static OUString GetEditText(const EditEngine* pEng)
693{
694 return ScEditUtil::GetMultilineString(*pEng);
695}
696
697static void lcl_RemoveTabs(OUString& rStr)
698{
699 rStr = rStr.replace('\t', ' ');
700}
701
702static void lcl_RemoveLineEnd(OUString& rStr)
703{
704 rStr = convertLineEnd(rStr, LINEEND_LF);
705 rStr = rStr.replace('\n', ' ');
706}
707
708static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
709{
710 int nDir;
711 sal_Unicode c1, c2 = 0;
712 c1 = rStr[nPos];
713 switch ( c1 )
714 {
715 case '(' :
716 c2 = ')';
717 nDir = 1;
718 break;
719 case ')' :
720 c2 = '(';
721 nDir = -1;
722 break;
723 case '<' :
724 c2 = '>';
725 nDir = 1;
726 break;
727 case '>' :
728 c2 = '<';
729 nDir = -1;
730 break;
731 case '{' :
732 c2 = '}';
733 nDir = 1;
734 break;
735 case '}' :
736 c2 = '{';
737 nDir = -1;
738 break;
739 case '[' :
740 c2 = ']';
741 nDir = 1;
742 break;
743 case ']' :
744 c2 = '[';
745 nDir = -1;
746 break;
747 default:
748 nDir = 0;
749 }
750 if ( !nDir )
751 return -1;
752 sal_Int32 nLen = rStr.getLength();
753 const sal_Unicode* p0 = rStr.getStr();
754 const sal_Unicode* p;
755 const sal_Unicode* p1;
756 sal_uInt16 nQuotes = 0;
757 if ( nPos < nLen / 2 )
758 {
759 p = p0;
760 p1 = p0 + nPos;
761 }
762 else
763 {
764 p = p0 + nPos;
765 p1 = p0 + nLen;
766 }
767 while ( p < p1 )
768 {
769 if ( *p++ == '\"' )
770 nQuotes++;
771 }
772 // Odd number of quotes that we find ourselves in a string
773 bool bLookInString = ((nQuotes % 2) != 0);
774 bool bInString = bLookInString;
775 p = p0 + nPos;
776 p1 = (nDir < 0 ? p0 : p0 + nLen) ;
777 sal_uInt16 nLevel = 1;
778 while ( p != p1 && nLevel )
779 {
780 p += nDir;
781 if ( *p == '\"' )
782 {
783 bInString = !bInString;
784 if ( bLookInString && !bInString )
785 p = p1; // That's it then
786 }
787 else if ( bInString == bLookInString )
788 {
789 if ( *p == c1 )
790 nLevel++;
791 else if ( *p == c2 )
792 nLevel--;
793 }
794 }
795 if ( nLevel )
796 return -1;
797 return static_cast<sal_Int32>(p - p0);
798}
799
801 : pInputWin( nullptr ),
802 pTableView( nullptr ),
803 pTopView( nullptr ),
804 pTipVisibleParent( nullptr ),
805 nTipVisible( nullptr ),
806 pTipVisibleSecParent( nullptr ),
807 nTipVisibleSec( nullptr ),
808 nFormSelStart( 0 ),
809 nFormSelEnd( 0 ),
810 nCellPercentFormatDecSep( 0 ),
811 nAutoPar( 0 ),
813 bUseTab( false ),
814 bTextValid( true ),
815 bModified( false ),
816 bSelIsRef( false ),
817 bFormulaMode( false ),
818 bInRangeUpdate( false ),
819 bParenthesisShown( false ),
820 bCreatingFuncView( false ),
821 bInEnterHandler( false ),
822 bCommandErrorShown( false ),
823 bInOwnChange( false ),
824 bProtected( false ),
825 bLastIsSymbol( false ),
826 mbDocumentDisposing(false),
827 mbPartialPrefix(false),
828 mbEditingExistingContent(false),
829 nValidation( 0 ),
830 eAttrAdjust( SvxCellHorJustify::Standard ),
831 aScaleX( 1,1 ),
832 aScaleY( 1,1 ),
833 pRefViewSh( nullptr ),
834 pLastPattern( nullptr )
835{
836 // The InputHandler is constructed with the view, so SfxViewShell::Current
837 // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
838 pActiveViewSh = nullptr;
839
840 // Bindings (only still used for Invalidate) are retrieved if needed on demand
841
842 pDelayTimer.reset( new Timer( "ScInputHandlerDelay timer" ) );
843 pDelayTimer->SetTimeout( 500 ); // 500 ms delay
844 pDelayTimer->SetInvokeHandler( LINK( this, ScInputHandler, DelayTimer ) );
845}
846
848{
849 // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
850 // thus we can't rely on any Sfx functions
851 if (!mbDocumentDisposing) // inplace
852 EnterHandler(); // Finish input
853
854 if (SC_MOD()->GetRefInputHdl() == this)
855 SC_MOD()->SetRefInputHdl(nullptr);
856
857 if ( pInputWin && pInputWin->GetInputHandler() == this )
858 pInputWin->SetInputHandler( nullptr );
859}
860
862{
863 if ( rX != aScaleX || rY != aScaleY )
864 {
865 aScaleX = rX;
866 aScaleY = rY;
867 if (mpEditEngine)
868 {
869 MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
870 mpEditEngine->SetRefMapMode( aMode );
871 }
872 }
873}
874
876{
877 if (!mpEditEngine)
878 return;
879
880 bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
882 EEControlBits nCtrl = mpEditEngine->GetControlWord();
883 if ( bTextWysiwyg || bInPlace )
884 nCtrl |= EEControlBits::FORMAT100; // EditEngine default: always format for 100%
885 else
886 nCtrl &= ~EEControlBits::FORMAT100; // when formatting for screen, use the actual MapMode
887 mpEditEngine->SetControlWord( nCtrl );
888 if ( bTextWysiwyg && pActiveViewSh )
890 else
891 mpEditEngine->SetRefDevice( nullptr );
892
893 MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
894 mpEditEngine->SetRefMapMode( aMode );
895
896 // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
897 // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
898 if ( !( bTextWysiwyg && pActiveViewSh ) )
899 {
900 mpEditEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
901 }
902}
903
905{
906 if ( mpEditEngine )
907 return;
908
909 if ( pActiveViewSh )
910 {
912 mpEditEngine = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
913 }
914 else
915 mpEditEngine = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
916
917 mpEditEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( mpEditEngine->GetWordDelimiters() ) );
918 UpdateRefDevice(); // also sets MapMode
919 mpEditEngine->SetPaperSize( Size( 1000000, 1000000 ) );
920 pEditDefaults.reset( new SfxItemSet( mpEditEngine->GetEmptyItemSet() ) );
921
922 mpEditEngine->SetControlWord( mpEditEngine->GetControlWord() | EEControlBits::AUTOCORRECT );
923 mpEditEngine->SetReplaceLeadingSingleQuotationMark( false );
924 mpEditEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
925}
926
928{
929 EEControlBits nCntrl = mpEditEngine->GetControlWord();
930 EEControlBits nOld = nCntrl;
931
932 // Don't use pLastPattern here (may be invalid because of AutoStyle)
933 bool bDisable = bLastIsSymbol || bFormulaMode;
934 if ( bDisable )
935 nCntrl &= ~EEControlBits::AUTOCORRECT;
936 else
937 nCntrl |= EEControlBits::AUTOCORRECT;
938
939 if ( nCntrl != nOld )
940 mpEditEngine->SetControlWord(nCntrl);
941}
942
943void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
944{
945 if ( !pActiveViewSh )
946 return;
947
948 ScViewData& rViewData = pActiveViewSh->GetViewData();
949 bool bOnlineSpell = rViewData.GetDocument().GetDocOptions().IsAutoSpell();
950
951 // SetDefaultLanguage is independent of the language attributes,
952 // ScGlobal::GetEditDefaultLanguage is always used.
953 // It must be set every time in case the office language was changed.
954
955 mpEditEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
956
957 // if called for changed options, update flags only if already editing
958 // if called from StartTable, always update flags
959
960 if ( bFromStartTab || eMode != SC_INPUT_NONE )
961 {
962 EEControlBits nCntrl = mpEditEngine->GetControlWord();
963 EEControlBits nOld = nCntrl;
964 if( bOnlineSpell )
965 nCntrl |= EEControlBits::ONLINESPELLING;
966 else
967 nCntrl &= ~EEControlBits::ONLINESPELLING;
968 // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
970 nCntrl &= ~EEControlBits::AUTOCORRECT;
971 else
972 nCntrl |= EEControlBits::AUTOCORRECT;
973 if ( nCntrl != nOld )
974 mpEditEngine->SetControlWord(nCntrl);
975
976 ScDocument& rDoc = rViewData.GetDocument();
978 mpEditEngine->SetDefaultHorizontalTextDirection(
979 rDoc.GetEditTextDirection( rViewData.GetTabNo() ) );
980 mpEditEngine->SetFirstWordCapitalization( false );
981 }
982
983 // Language is set separately, so the speller is needed only if online spelling is active
984 if ( bOnlineSpell ) {
985 css::uno::Reference<css::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
986 mpEditEngine->SetSpeller( xXSpellChecker1 );
987 }
988
989 bool bHyphen = pLastPattern && pLastPattern->GetItem(ATTR_HYPHENATE).GetValue();
990 if ( bHyphen ) {
991 css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
992 mpEditEngine->SetHyphenator( xXHyphenator );
993 }
994}
995
996// Function/Range names etc. as Tip help
997
998// The other types are defined in ScDocument::GetFormulaEntries
1000{
1001 if ( !pActiveViewSh )
1002 return;
1003
1005
1006 if ( pFormulaData )
1007 pFormulaData->clear();
1008 else
1009 {
1010 pFormulaData.reset( new ScTypedCaseStrSet );
1011 }
1012
1013 if( pFormulaDataPara )
1014 pFormulaDataPara->clear();
1015 else
1017
1018 const OUString aParenthesesReplacement( cParenthesesReplacement);
1020 const sal_uInt32 nListCount = pFuncList->GetCount();
1022 *pFormulaData = rFunctionNames.maFunctionData;
1023 *pFormulaDataPara = rFunctionNames.maFunctionDataPara;
1024 maFormulaChar = rFunctionNames.maFunctionChar;
1025
1026 // Increase suggestion priority of MRU formulas
1027 const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
1028 const sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
1029 const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
1030 for (sal_uInt16 i = 0; i < nMRUCount; i++)
1031 {
1032 const sal_uInt16 nId = pMRUList[i];
1033 for (sal_uInt32 j = 0; j < nListCount; j++)
1034 {
1035 const ScFuncDesc* pDesc = pFuncList->GetFunction(j);
1036 if (pDesc->nFIndex == nId && pDesc->mxFuncName)
1037 {
1038 const OUString aEntry = *pDesc->mxFuncName + aParenthesesReplacement;;
1039 const ScTypedStrData aData(aEntry, 0.0, 0.0, ScTypedStrData::Standard);
1040 auto it = pFormulaData->find(aData);
1041 if (it != pFormulaData->end())
1042 pFormulaData->erase(it);
1043 pFormulaData->insert(ScTypedStrData(aEntry, 0.0, 0.0, ScTypedStrData::MRU));
1044 break; // Stop searching
1045 }
1046 }
1047 }
1049
1050 // tdf#142031 - collect all the characters for the formula suggestion auto input
1051 ScTypedCaseStrSet aStrSet;
1052 rDoc.GetFormulaEntries( aStrSet );
1053 for (auto iter = aStrSet.begin(); iter != aStrSet.end(); ++iter)
1054 {
1055 const OUString aFuncName = ScGlobal::getCharClass().uppercase((*iter).GetString());
1056 // fdo#75264 fill maFormulaChar with all characters used in formula names
1057 for (sal_Int32 j = 0; j < aFuncName.getLength(); j++)
1058 maFormulaChar.insert(aFuncName[j]);
1059 }
1060 pFormulaData->insert(aStrSet.begin(), aStrSet.end());
1061 pFormulaDataPara->insert(aStrSet.begin(), aStrSet.end());
1062}
1063
1064IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent&, rEvent, void )
1065{
1066 if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
1067 || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
1068 HideTip();
1069}
1070
1071IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent&, rEvent, void )
1072{
1073 if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
1074 || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
1075 HideTipBelow();
1076}
1077
1079{
1080 if ( nTipVisible )
1081 {
1082 pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
1084 nTipVisible = nullptr;
1085 pTipVisibleParent = nullptr;
1086 }
1087 aManualTip.clear();
1088}
1090{
1091 if ( nTipVisibleSec )
1092 {
1093 pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1095 nTipVisibleSec = nullptr;
1096 pTipVisibleSecParent = nullptr;
1097 }
1098 aManualTip.clear();
1099}
1100
1101namespace
1102{
1103
1104bool lcl_hasSingleToken(std::u16string_view s, sal_Unicode c)
1105{
1106 return !s.empty() && s.find(c) == std::u16string_view::npos;
1107}
1108
1109}
1110
1111void ScInputHandler::ShowArgumentsTip( OUString& rSelText )
1112{
1114 {
1115 return;
1116 }
1117
1120 const sal_Unicode cSheetSep = pDocSh->GetDocument().GetSheetSeparator();
1122 bool bFound = false;
1123 while( !bFound )
1124 {
1125 rSelText += ")";
1126 sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
1127 if( nLeftParentPos != -1 )
1128 {
1129 sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
1130 const IFunctionDescription* ppFDesc;
1131 ::std::vector< OUString> aArgs;
1132 if( aHelper.GetNextFunc( rSelText, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
1133 {
1134 if( !ppFDesc->getFunctionName().isEmpty() )
1135 {
1136 sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
1137 sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
1138 OUString aFuncName( ppFDesc->getFunctionName() + "(");
1139 OUString aNew;
1140 ScTypedCaseStrSet::const_iterator it =
1141 findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
1142 if (it != pFormulaDataPara->end())
1143 {
1144 bool bFlag = false;
1145 sal_uInt16 nActive = 0;
1146 for( sal_uInt16 i=0; i < nArgs; i++ )
1147 {
1148 sal_Int32 nLength = aArgs[i].getLength();
1149 if( nArgPos <= rSelText.getLength()-1 )
1150 {
1151 nActive = i+1;
1152 bFlag = true;
1153 }
1154 nArgPos+=nLength+1;
1155 }
1156 if( bFlag )
1157 {
1158 sal_Int32 nStartPosition = 0;
1159 sal_Int32 nEndPosition = 0;
1160
1161 if( lcl_hasSingleToken(aNew, cSep) )
1162 {
1163 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
1164 {
1165 sal_Unicode cNext = aNew[i];
1166 if( cNext == '(' )
1167 {
1168 nStartPosition = i+1;
1169 }
1170 }
1171 }
1172 else if( lcl_hasSingleToken(aNew, cSheetSep) )
1173 {
1174 sal_uInt16 nCount = 0;
1175 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
1176 {
1177 sal_Unicode cNext = aNew[i];
1178 if( cNext == '(' )
1179 {
1180 nStartPosition = i+1;
1181 }
1182 else if( cNext == cSep )
1183 {
1184 nCount ++;
1185 nEndPosition = i;
1186 if( nCount == nActive )
1187 {
1188 break;
1189 }
1190 nStartPosition = nEndPosition+1;
1191 }
1192 }
1193 }
1194 else
1195 {
1196 sal_uInt16 nCount = 0;
1197 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
1198 {
1199 sal_Unicode cNext = aNew[i];
1200 if( cNext == '(' )
1201 {
1202 nStartPosition = i+1;
1203 }
1204 else if( cNext == cSep )
1205 {
1206 nCount ++;
1207 nEndPosition = i;
1208 if( nCount == nActive )
1209 {
1210 break;
1211 }
1212 nStartPosition = nEndPosition+1;
1213 }
1214 else if( cNext == cSheetSep )
1215 {
1216 continue;
1217 }
1218 }
1219 }
1220
1221 if (nStartPosition > 0)
1222 {
1223 nArgs = ppFDesc->getParameterCount();
1224 sal_Int16 nVarArgsSet = 0;
1225 if ( nArgs >= PAIRED_VAR_ARGS )
1226 {
1227 nVarArgsSet = 2;
1228 nArgs -= PAIRED_VAR_ARGS - nVarArgsSet;
1229 }
1230 else if ( nArgs >= VAR_ARGS )
1231 {
1232 nVarArgsSet = 1;
1233 nArgs -= VAR_ARGS - nVarArgsSet;
1234 }
1235 if ( nVarArgsSet > 0 && nActive > nArgs )
1236 nActive = nArgs - (nActive - nArgs) % nVarArgsSet;
1237 aNew = OUString::Concat(aNew.subView(0, nStartPosition)) +
1238 u"\x25BA" +
1239 aNew.subView(nStartPosition) +
1240 " : " +
1241 ppFDesc->getParameterDescription(nActive-1);
1242 if (eMode != SC_INPUT_TOP)
1243 {
1244 ShowTipBelow( aNew );
1245 }
1246 else
1247 {
1248 ShowTip(aNew);
1249 }
1250 bFound = true;
1251 }
1252 }
1253 else
1254 {
1255 ShowTipBelow( aNew );
1256 bFound = true;
1257 }
1258 }
1259 }
1260 }
1261 }
1262 else
1263 {
1264 break;
1265 }
1266 }
1267}
1268
1270{
1271 HideTip();
1272 HideTipBelow();
1273 EditView* pActiveView = pTopView ? pTopView : pTableView;
1274
1275 /* TODO: MLFORMULA: this should work also with multi-line formulas. */
1276 if ( !(bFormulaMode && pActiveView && pFormulaDataPara && mpEditEngine->GetParagraphCount() == 1) )
1277 return;
1278
1279 OUString aParagraph = mpEditEngine->GetText( 0 );
1280 ESelection aSel = pActiveView->GetSelection();
1281 aSel.Adjust();
1282
1283 if ( aParagraph.getLength() < aSel.nEndPos )
1284 return;
1285
1286 if ( aSel.nEndPos > 0 )
1287 {
1288 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1289
1290 ShowArgumentsTip( aSelText );
1291 }
1292}
1293
1294void ScInputHandler::ShowTip( const OUString& rText )
1295{
1296 // aManualTip needs to be set afterwards from outside
1297
1298 HideTip();
1299 HideTipBelow();
1300
1301 EditView* pActiveView = pTopView ? pTopView : pTableView;
1302 if (!pActiveView)
1303 return;
1304
1305 Point aPos;
1306 if (pInputWin && pInputWin->GetEditView() == pActiveView)
1307 {
1308 pTipVisibleParent = pInputWin->GetEditWindow();
1309 aPos = pInputWin->GetCursorScreenPixelPos();
1310 }
1311 else
1312 {
1313 pTipVisibleParent = pActiveView->GetWindow();
1314 if (vcl::Cursor* pCur = pActiveView->GetCursor())
1315 aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
1316 aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
1317 }
1318
1319 tools::Rectangle aRect( aPos, aPos );
1320 QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
1321 nTipVisible = Help::ShowPopover(pTipVisibleParent, aRect, rText, nAlign);
1322 pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
1323}
1324
1325void ScInputHandler::ShowTipBelow( const OUString& rText )
1326{
1327 HideTipBelow();
1328
1329 EditView* pActiveView = pTopView ? pTopView : pTableView;
1330 if ( !pActiveView )
1331 return;
1332
1333 Point aPos;
1334 if (pInputWin && pInputWin->GetEditView() == pActiveView)
1335 {
1336 pTipVisibleSecParent = pInputWin->GetEditWindow();
1337 aPos = pInputWin->GetCursorScreenPixelPos(true);
1338 }
1339 else
1340 {
1341 pTipVisibleSecParent = pActiveView->GetWindow();
1342 if (vcl::Cursor* pCur = pActiveView->GetCursor())
1343 {
1344 Point aLogicPos = pCur->GetPos();
1345 aLogicPos.AdjustY(pCur->GetHeight() );
1346 aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
1347 }
1348 aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
1349 }
1350
1351 tools::Rectangle aRect( aPos, aPos );
1352 QuickHelpFlags const nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
1353 nTipVisibleSec = Help::ShowPopover(pTipVisibleSecParent, aRect, rText, nAlign);
1354 pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1355}
1356
1357bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
1358{
1359 if ( aStart.isEmpty() )
1360 return false;
1361
1362 aStart = ScGlobal::getCharClass().uppercase( aStart );
1363 sal_Int32 nPos = aStart.getLength() - 1;
1364 sal_Unicode c = aStart[ nPos ];
1365 // fdo#75264 use maFormulaChar to check if characters are used in function names
1366 ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
1367 if ( p == maFormulaChar.end() )
1368 return false; // last character is not part of any function name, quit
1369
1370 ::std::vector<sal_Unicode> aTemp { c };
1371 for(sal_Int32 i = nPos - 1; i >= 0; --i)
1372 {
1373 c = aStart[ i ];
1374 p = maFormulaChar.find( c );
1375
1376 if (p == maFormulaChar.end())
1377 break;
1378
1379 aTemp.push_back( c );
1380 }
1381
1382 ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
1383 aResult = OUString( *rIt++ );
1384 while ( rIt != aTemp.rend() )
1385 aResult += OUStringChar( *rIt++ );
1386
1387 return true;
1388}
1389
1390namespace {
1392 OString escapeJSON(const OUString &aStr)
1393 {
1394 OUString aEscaped = aStr;
1395 aEscaped = aEscaped.replaceAll("\n", " ");
1396 aEscaped = aEscaped.replaceAll("\"", "'");
1397 return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
1398 }
1399}
1400
1401void ScInputHandler::ShowFuncList( const ::std::vector< OUString > & rFuncStrVec )
1402{
1403 const SfxViewShell* pViewShell = SfxViewShell::Current();
1405 {
1406 if (rFuncStrVec.size() && pViewShell && pViewShell->isLOKMobilePhone())
1407 {
1408 auto aPos = pFormulaData->begin();
1409 sal_uInt32 nCurIndex = std::distance(aPos, miAutoPosFormula);
1410 const sal_uInt32 nSize = pFormulaData->size();
1411
1412 OUString aFuncNameStr;
1413 OUString aDescFuncNameStr;
1414 OStringBuffer aPayload;
1415 aPayload.append("[ ");
1416 for (const OUString& rFunc : rFuncStrVec)
1417 {
1418 if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
1419 {
1420 aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
1421 }
1422 else
1423 {
1424 aFuncNameStr = rFunc;
1425 }
1426
1428 aDescFuncNameStr = aFuncNameStr + "()";
1429 sal_Int32 nNextFStart = 0;
1430 const IFunctionDescription* ppFDesc;
1431 ::std::vector< OUString > aArgs;
1432 OUString eqPlusFuncName = "=" + aDescFuncNameStr;
1433 if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
1434 {
1435 if ( !ppFDesc->getFunctionName().isEmpty() )
1436 {
1437 aPayload.append("{");
1438 aPayload.append("\"index\": ");
1439 aPayload.append(static_cast<sal_Int64>(nCurIndex));
1440 aPayload.append(", ");
1441 aPayload.append("\"signature\": \"");
1442 aPayload.append(escapeJSON(ppFDesc->getSignature()));
1443 aPayload.append("\", ");
1444 aPayload.append("\"description\": \"");
1445 aPayload.append(escapeJSON(ppFDesc->getDescription()));
1446 aPayload.append("\"}, ");
1447 }
1448 }
1449 ++nCurIndex;
1450 if (nCurIndex == nSize)
1451 nCurIndex = 0;
1452 }
1453 sal_Int32 nLen = aPayload.getLength();
1454 aPayload[nLen - 2] = ' ';
1455 aPayload[nLen - 1] = ']';
1456
1457 OString s = aPayload.makeStringAndClear();
1458 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s.getStr());
1459 }
1460 // not tunnel tooltips in the lok case
1461 return;
1462 }
1463
1464 OUStringBuffer aTipStr;
1465 OUString aFuncNameStr;
1466 OUString aDescFuncNameStr;
1467 ::std::vector<OUString>::const_iterator itStr = rFuncStrVec.begin();
1468 sal_Int32 nMaxFindNumber = 3;
1469 sal_Int32 nRemainFindNumber = nMaxFindNumber;
1470 for ( ; itStr != rFuncStrVec.end(); ++itStr )
1471 {
1472 const OUString& rFunc = *itStr;
1473 if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
1474 {
1475 aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
1476 }
1477 else
1478 {
1479 aFuncNameStr = rFunc;
1480 }
1481 if ( itStr == rFuncStrVec.begin() )
1482 {
1483 aTipStr = "[";
1484 aDescFuncNameStr = aFuncNameStr + "()";
1485 }
1486 else
1487 {
1488 aTipStr.append(", ");
1489 }
1490 aTipStr.append(aFuncNameStr);
1491 if ( itStr == rFuncStrVec.begin() )
1492 aTipStr.append("]");
1493 if ( --nRemainFindNumber <= 0 )
1494 break;
1495 }
1496 sal_Int32 nRemainNumber = rFuncStrVec.size() - nMaxFindNumber;
1497 if ( nRemainFindNumber == 0 && nRemainNumber > 0 )
1498 {
1499 OUString aMessage( ScResId( STR_FUNCTIONS_FOUND ) );
1500 aMessage = aMessage.replaceFirst("%2", OUString::number(nRemainNumber));
1501 aMessage = aMessage.replaceFirst("%1", aTipStr);
1502 aTipStr = aMessage;
1503 }
1505 sal_Int32 nNextFStart = 0;
1506 const IFunctionDescription* ppFDesc;
1507 ::std::vector< OUString > aArgs;
1508 OUString eqPlusFuncName = "=" + aDescFuncNameStr;
1509 if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
1510 {
1511 if ( !ppFDesc->getFunctionName().isEmpty() )
1512 {
1513 aTipStr.append(" : " + ppFDesc->getDescription());
1514 }
1515 }
1516 ShowTip( aTipStr.makeStringAndClear() );
1517}
1518
1520{
1521 EditView* pActiveView = pTopView ? pTopView : pTableView;
1522
1523 /* TODO: MLFORMULA: this should work also with multi-line formulas. */
1524 if ( !(pActiveView && pFormulaData && mpEditEngine->GetParagraphCount() == 1) )
1525 return;
1526
1527 OUString aParagraph = mpEditEngine->GetText( 0 );
1528 ESelection aSel = pActiveView->GetSelection();
1529 aSel.Adjust();
1530
1531 // Due to differences between table and input cell (e.g clipboard with line breaks),
1532 // the selection may not be in line with the EditEngine anymore.
1533 // Just return without any indication as to why.
1534 if ( aSel.nEndPos > aParagraph.getLength() )
1535 return;
1536
1537 if ( aParagraph.getLength() > aSel.nEndPos &&
1538 ( ScGlobal::getCharClass().isLetterNumeric( aParagraph, aSel.nEndPos ) ||
1539 aParagraph[ aSel.nEndPos ] == '_' ||
1540 aParagraph[ aSel.nEndPos ] == '.' ||
1541 aParagraph[ aSel.nEndPos ] == '$' ) )
1542 return;
1543
1544 // Is the cursor at the end of a word?
1545 if ( aSel.nEndPos <= 0 )
1546 return;
1547
1548 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1549
1550 OUString aText;
1551 if ( GetFuncName( aSelText, aText ) )
1552 {
1553 // function name is incomplete:
1554 // show matching functions name as tip above cell
1555 ::std::vector<OUString> aNewVec;
1557 miAutoPosFormula = findTextAll(*pFormulaData, miAutoPosFormula, aText, aNewVec, false);
1558 if (miAutoPosFormula != pFormulaData->end())
1559 {
1560 // check if partial function name is not between quotes
1561 sal_Unicode cBetweenQuotes = 0;
1562 for ( int n = 0; n < aSelText.getLength(); n++ )
1563 {
1564 if (cBetweenQuotes)
1565 {
1566 if (aSelText[n] == cBetweenQuotes)
1567 cBetweenQuotes = 0;
1568 }
1569 else if ( aSelText[ n ] == '"' )
1570 cBetweenQuotes = '"';
1571 else if ( aSelText[ n ] == '\'' )
1572 cBetweenQuotes = '\'';
1573 }
1574 if ( cBetweenQuotes )
1575 return; // we're between quotes
1576
1577 ShowFuncList(aNewVec);
1578 aAutoSearch = aText;
1579 }
1580 return;
1581 }
1582
1583 // function name is complete:
1584 // show tip below the cell with function name and arguments of function
1585 ShowArgumentsTip( aSelText );
1586}
1587
1589{
1590 EditView* pActiveView = pTopView ? pTopView : pTableView;
1591 if ( pActiveView && pFormulaData )
1592 {
1593 ::std::vector<OUString> aNewVec;
1594 ScTypedCaseStrSet::const_iterator itNew = findTextAll(*pFormulaData, miAutoPosFormula, aAutoSearch, aNewVec, bBack);
1595 if (itNew != pFormulaData->end())
1596 {
1597 miAutoPosFormula = itNew;
1598 ShowFuncList( aNewVec );
1599 }
1600 }
1601
1602 // For Tab we always call HideCursor first
1603 if (pActiveView)
1604 pActiveView->ShowCursor();
1605}
1606
1607namespace {
1608
1609void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
1610{
1611 if (!pView)
1612 return;
1613
1614 ESelection aSel = pView->GetSelection();
1615
1616 bool bNoInitialLetter = false;
1617 OUString aOld = pView->GetEditEngine()->GetText(0);
1618 // in case we want just insert a function and not completing
1620 {
1621 ESelection aSelRange = aSel;
1622 --aSelRange.nStartPos;
1623 --aSelRange.nEndPos;
1624 pView->SetSelection(aSelRange);
1625 pView->SelectCurrentWord();
1626
1627 if ( aOld == "=" )
1628 {
1629 bNoInitialLetter = true;
1630 aSelRange.nStartPos = 1;
1631 aSelRange.nEndPos = 1;
1632 pView->SetSelection(aSelRange);
1633 }
1634 else if ( pView->GetSelected().startsWith("()") )
1635 {
1636 bNoInitialLetter = true;
1637 ++aSelRange.nStartPos;
1638 ++aSelRange.nEndPos;
1639 pView->SetSelection(aSelRange);
1640 }
1641 }
1642
1643 if(!bNoInitialLetter)
1644 {
1645 const sal_Int32 nMinLen = std::max(aSel.nEndPos - aSel.nStartPos, sal_Int32(1));
1646 // Since transliteration service is used to test for match, the replaced string could be
1647 // longer than rInsert, so in order to find longest match before the cursor, test whole
1648 // string from start to current cursor position (don't limit to length of rInsert)
1649 // Disclaimer: I really don't know if a match longer than rInsert is actually possible,
1650 // so the above is based on assumptions how "transliteration" might possibly work. If
1651 // it's in fact impossible, an optimization would be useful to limit aSel.nStartPos to
1652 // std::max(sal_Int32(0), aSel.nEndPos - rInsert.getLength()).
1653 aSel.nStartPos = 0;
1654 pView->SetSelection(aSel);
1655 const OUString aAll = pView->GetSelected();
1656 OUString aMatch;
1657 for (sal_Int32 n = aAll.getLength(); n >= nMinLen && aMatch.isEmpty(); --n)
1658 {
1659 const OUString aTest = aAll.copy(aAll.getLength() - n); // n trailing chars
1660 if (ScGlobal::GetTransliteration().isMatch(aTest, rInsert))
1661 aMatch = aTest; // Found => break the loop
1662 }
1663
1664 aSel.nStartPos = aSel.nEndPos - aMatch.getLength();
1665 pView->SetSelection(aSel);
1666 }
1667
1668 OUString aInsStr = rInsert;
1669 sal_Int32 nInsLen = aInsStr.getLength();
1670 bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
1671 && aInsStr[nInsLen-1] == ')' );
1672 if ( bDoParen )
1673 {
1674 // Do not insert parentheses after function names if there already are some
1675 // (e.g. if the function name was edited).
1676 ESelection aWordSel = pView->GetSelection();
1677
1678 // aWordSel.EndPos points one behind string if word at end
1679 if (aWordSel.nEndPos < aOld.getLength())
1680 {
1681 sal_Unicode cNext = aOld[aWordSel.nEndPos];
1682 if ( cNext == '(' )
1683 {
1684 bDoParen = false;
1685 aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
1686 }
1687 }
1688 }
1689
1690 pView->InsertText( aInsStr );
1691
1692 if ( bDoParen ) // Put cursor between parentheses
1693 {
1694 aSel = pView->GetSelection();
1695 --aSel.nStartPos;
1696 --aSel.nEndPos;
1697 pView->SetSelection(aSel);
1698
1699 rParInserted = true;
1700 }
1701}
1702
1703}
1704
1706{
1708 {
1709 const ScTypedStrData& rData = *miAutoPosFormula;
1710 OUString aInsert = rData.GetString();
1711 if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
1712 aInsert = OUString::Concat(aInsert.subView( 0, aInsert.getLength()-1)) + "()";
1713 bool bParInserted = false;
1714
1715 DataChanging(); // Cannot be new
1716 completeFunction( pTopView, aInsert, bParInserted );
1717 completeFunction( pTableView, aInsert, bParInserted );
1718 DataChanged();
1719 ShowTipCursor();
1720
1721 if (bParInserted)
1722 AutoParAdded();
1723 }
1724
1725 HideTip();
1726
1727 EditView* pActiveView = pTopView ? pTopView : pTableView;
1729 pInputWin->TextGrabFocus();
1730 if (pActiveView)
1731 pActiveView->ShowCursor();
1732}
1733
1734void ScInputHandler::LOKPasteFunctionData(const OUString& rFunctionName)
1735{
1736 // in case we have no top view try to create it
1737 if (!pTopView && pInputWin)
1738 {
1739 ScInputMode eCurMode = eMode;
1741 if (!pTopView)
1742 SetMode(eCurMode);
1743 }
1744
1745 EditView* pEditView = pTopView ? pTopView : pTableView;
1746
1747 if (!pActiveViewSh || !pEditView)
1748 return;
1749
1750 bool bEdit = false;
1751 OUString aFormula;
1752 const EditEngine* pEditEngine = pEditView->GetEditEngine();
1753 if (pEditEngine)
1754 {
1755 aFormula = pEditEngine->GetText(0);
1756 /* TODO: LOK: are you sure you want '+' and '-' let start formulas with
1757 * function names? That was meant for "data typist" numeric keyboard
1758 * input. */
1759 bEdit = aFormula.getLength() > 1 && (aFormula[0] == '=' || aFormula[0] == '+' || aFormula[0] == '-');
1760 }
1761
1762 if ( !bEdit )
1763 {
1764 OUString aNewFormula('=');
1765 if ( aFormula.startsWith("=") )
1766 aNewFormula = aFormula;
1767
1768 InputReplaceSelection( aNewFormula );
1769 }
1770
1771 if (pFormulaData)
1772 {
1773 OUString aNew;
1774 ScTypedCaseStrSet::const_iterator aPos = findText(*pFormulaData, pFormulaData->begin(), rFunctionName, aNew, /* backward = */false);
1775
1776 if (aPos != pFormulaData->end())
1777 {
1778 miAutoPosFormula = aPos;
1780 }
1781 }
1782}
1783
1785 const SfxViewShell* pActiveViewSh,
1786 const OUString& rText,
1787 const ESelection& rSelection)
1788{
1789 OUString aSelection;
1790 if (pActiveView)
1791 {
1792 aSelection = OUString::number(pActiveView->GetPosWithField(0, rSelection.nStartPos)) + ";" +
1793 OUString::number(pActiveView->GetPosWithField(0, rSelection.nEndPos)) + ";" +
1794 OUString::number(rSelection.nStartPara) + ";" + OUString::number(rSelection.nEndPara);
1795 }
1796 else
1797 {
1798 aSelection = OUString::number(rSelection.nStartPos) + ";" + OUString::number(rSelection.nEndPos) + ";" +
1799 OUString::number(rSelection.nStartPara) + ";" + OUString::number(rSelection.nEndPara);
1800 }
1801
1802 std::unique_ptr<jsdialog::ActionDataMap> pData = std::make_unique<jsdialog::ActionDataMap>();
1803 (*pData)["action_type"] = "setText";
1804 (*pData)["text"] = rText;
1805 (*pData)["selection"] = aSelection;
1806
1807 sal_uInt64 nCurrentShellId = reinterpret_cast<sal_uInt64>(pActiveViewSh);
1808 std::string sWindowId = std::to_string(nCurrentShellId) + "formulabar";
1809 jsdialog::SendAction(sWindowId, "sc_input_window", std::move(pData));
1810}
1811
1812// Calculate selection and display as tip help
1813static OUString lcl_Calculate( const OUString& rFormula, ScDocument& rDoc, const ScAddress &rPos )
1814{
1815 //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1816 // Quotation marks for Strings are only inserted here.
1817
1818 if(rFormula.isEmpty())
1819 return OUString();
1820
1821 std::optional<ScSimpleFormulaCalculator> pCalc( std::in_place, rDoc, rPos, rFormula, false );
1822
1823 // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1824 // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1825 bool bColRowName = pCalc->HasColRowName();
1826 if ( bColRowName )
1827 {
1828 // ColRowName in RPN code?
1829 if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1830 { // ==1: Single one is as a Parameter always a Range
1831 // ==0: It might be one, if ...
1832 OUString aBraced = "(" + rFormula + ")";
1833 pCalc.emplace( rDoc, rPos, aBraced, false );
1834 }
1835 else
1836 bColRowName = false;
1837 }
1838
1839 FormulaError nErrCode = pCalc->GetErrCode();
1840 if ( nErrCode != FormulaError::NONE )
1841 return ScGlobal::GetErrorString(nErrCode);
1842
1843 SvNumberFormatter& aFormatter = *rDoc.GetFormatTable();
1844 OUString aValue;
1845 if ( pCalc->IsValue() )
1846 {
1847 double n = pCalc->GetValue();
1848 sal_uInt32 nFormat = aFormatter.GetStandardFormat( n, 0,
1849 pCalc->GetFormatType(), ScGlobal::eLnge );
1850 aFormatter.GetInputLineString( n, nFormat, aValue );
1852 }
1853 else
1854 {
1855 OUString aStr = pCalc->GetString().getString();
1856 sal_uInt32 nFormat = aFormatter.GetStandardFormat(
1857 pCalc->GetFormatType(), ScGlobal::eLnge);
1858 {
1859 const Color* pColor;
1860 aFormatter.GetOutputString( aStr, nFormat,
1861 aValue, &pColor );
1862 }
1863
1864 aValue = "\"" + aValue + "\"";
1866 }
1867
1868 ScRange aTestRange;
1869 if ( bColRowName || (aTestRange.Parse(rFormula, rDoc) & ScRefFlags::VALID) )
1870 aValue += " ...";
1871
1872 return aValue;
1873}
1874
1876{
1877 OUString aValue;
1878 EditView* pActiveView = pTopView ? pTopView : pTableView;
1879 if ( pActiveView && pActiveViewSh )
1880 {
1881 OUString aPart = pActiveView->GetSelected();
1882 if (aPart.isEmpty())
1883 aPart = mpEditEngine->GetText(0);
1885 aValue = lcl_Calculate( aPart, rDoc, aCursorPos );
1886 }
1887
1888 if (!aValue.isEmpty())
1889 {
1890 ShowTip( aValue ); // Display as QuickHelp
1891 aManualTip = aValue; // Set after ShowTip
1892 if (pFormulaData)
1894 if (pColumnData)
1896 }
1897}
1898
1900{
1901 // Three dots at the end -> Range reference -> do not insert
1902 // FIXME: Once we have matrix constants, we can change this
1903 sal_Int32 nTipLen = aManualTip.getLength();
1904 sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1905 if ( nTipLen && ( nTipLen < 3 || aManualTip.subView( nTipLen2-3 ) != u"..." ) )
1906 {
1907 DataChanging(); // Cannot be new
1908
1909 OUString aInsert = aManualTip;
1910 EditView* pActiveView = pTopView ? pTopView : pTableView;
1911 if (!pActiveView->HasSelection())
1912 {
1913 // Nothing selected -> select everything
1914 sal_Int32 nOldLen = mpEditEngine->GetTextLen(0);
1915 ESelection aAllSel( 0, 0, 0, nOldLen );
1916 if ( pTopView )
1917 pTopView->SetSelection( aAllSel );
1918 if ( pTableView )
1919 pTableView->SetSelection( aAllSel );
1920 }
1921
1922 ESelection aSel = pActiveView->GetSelection();
1923 aSel.Adjust();
1924 OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1925 if ( !aSel.nStartPos ) // Selection from the start?
1926 {
1927 if ( aSel.nEndPos == mpEditEngine->GetTextLen(0) )
1928 {
1929 // Everything selected -> skip quotation marks
1930 if ( aInsert[0] == '"' )
1931 aInsert = aInsert.copy(1);
1932 sal_Int32 nInsLen = aInsert.getLength();
1933 if ( aInsert.endsWith("\"") )
1934 aInsert = aInsert.copy( 0, nInsLen-1 );
1935 }
1936 else if ( aSel.nEndPos )
1937 {
1938 // Not everything selected -> do not overwrite equality sign
1939 //FIXME: Even double equality signs??
1940 aSel.nStartPos = 1;
1941 if ( pTopView )
1942 pTopView->SetSelection( aSel );
1943 if ( pTableView )
1944 pTableView->SetSelection( aSel );
1945 }
1946 }
1947 if ( pTopView )
1948 pTopView->InsertText( aInsert, true );
1949 if ( pTableView )
1950 pTableView->InsertText( aInsert, true );
1951
1952 DataChanged();
1953 }
1954
1955 HideTip();
1956}
1957
1959{
1960 nAutoPar = 0;
1961}
1962
1964{
1965 ++nAutoPar; // Closing parenthesis can be overwritten
1966}
1967
1969{
1970 // Test if the cursor is before a closing parenthesis
1971 // Selection from SetReference has been removed before
1972 EditView* pActiveView = pTopView ? pTopView : pTableView;
1973 if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1974 {
1975 ESelection aSel = pActiveView->GetSelection();
1976 sal_Int32 nPos = aSel.nStartPos;
1977 OUString aFormula = mpEditEngine->GetText(0);
1978 if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1979 return true;
1980 }
1981 return false;
1982}
1983
1985{
1986 // this is called when a ')' is typed and the cursor is before a ')'
1987 // that can be overwritten -> just set the cursor behind the ')'
1988
1989 EditView* pActiveView = pTopView ? pTopView : pTableView;
1990 if (pActiveView)
1991 {
1992 ESelection aSel = pActiveView->GetSelection();
1993 ++aSel.nStartPos;
1994 ++aSel.nEndPos;
1995
1996 // this is in a formula (only one paragraph), so the selection
1997 // can be used directly for the TopView
1998
1999 if ( pTopView )
2000 pTopView->SetSelection( aSel );
2001 if ( pTableView )
2002 pTableView->SetSelection( aSel );
2003 }
2004
2005 OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
2006 --nAutoPar;
2007}
2008
2009// Auto input
2010
2012{
2013 if ( !pActiveViewSh )
2014 return;
2015
2017
2018 if ( pColumnData )
2019 pColumnData->clear();
2020 else
2021 pColumnData.reset( new ScTypedCaseStrSet );
2022
2023 std::vector<ScTypedStrData> aEntries;
2024 rDoc.GetDataEntries(
2026 if (!aEntries.empty())
2027 pColumnData->insert(aEntries.begin(), aEntries.end());
2028
2030}
2031
2032void ScInputHandler::UseColData() // When typing
2033{
2034 EditView* pActiveView = pTopView ? pTopView : pTableView;
2035 if ( !(pActiveView && pColumnData) )
2036 return;
2037
2038 // Only change when cursor is at the end
2039 ESelection aSel = pActiveView->GetSelection();
2040 aSel.Adjust();
2041
2042 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
2043 if ( aSel.nEndPara+1 != nParCnt )
2044 return;
2045
2046 sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
2047 if ( aSel.nEndPos != nParLen )
2048 return;
2049
2050 OUString aText = GetEditText(mpEditEngine.get());
2051 if (aText.isEmpty())
2052 return;
2053
2054 std::vector< OUString > aResultVec;
2055 OUString aNew;
2056 sal_Int32 nLongestPrefixLen = 0;
2058 mbPartialPrefix = false;
2059 miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, &nLongestPrefixLen);
2060
2061 if (nLongestPrefixLen <= 0 || aResultVec.empty())
2062 return;
2063
2064 if (aResultVec.size() > 1)
2065 {
2066 mbPartialPrefix = true;
2067 bUseTab = true; // Allow Ctrl (+ Shift + ) + TAB cycling.
2069
2070 // Display the rest of longest common prefix as suggestion.
2071 aNew = aResultVec[0].copy(0, nLongestPrefixLen);
2072 }
2073 else
2074 {
2075 aNew = aResultVec[0];
2076 }
2077
2078 // Strings can contain line endings (e.g. due to dBase import),
2079 // which would result in multiple paragraphs here, which is not desirable.
2081 lcl_RemoveLineEnd( aNew );
2082
2083 // Keep paragraph, just append the rest
2085 // One Space between paragraphs:
2086 sal_Int32 nEdLen = mpEditEngine->GetTextLen() + nParCnt - 1;
2087 OUString aIns = aNew.copy(nEdLen);
2088
2089 // Selection must be "backwards", so the cursor stays behind the last
2090 // typed character
2091 ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
2092 aSel.nEndPara, aSel.nEndPos );
2093
2094 // When editing in input line, apply to both edit views
2095 if ( pTableView )
2096 {
2097 pTableView->InsertText( aIns );
2098 pTableView->SetSelection( aSelection );
2099 }
2100 if ( pTopView )
2101 {
2102 pTopView->InsertText( aIns );
2103 pTopView->SetSelection( aSelection );
2104 }
2105
2106 aAutoSearch = aText; // To keep searching - nAutoPos is set
2107}
2108
2110{
2111 EditView* pActiveView = pTopView ? pTopView : pTableView;
2112 if ( pActiveView && pColumnData )
2113 {
2114 if (!aAutoSearch.isEmpty())
2115 {
2116 // Is the selection still valid (could be changed via the mouse)?
2117 ESelection aSel = pActiveView->GetSelection();
2118 aSel.Adjust();
2119 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
2120 if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
2121 {
2122 OUString aText = GetEditText(mpEditEngine.get());
2123 sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
2124 sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
2125 if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
2126 {
2127 OUString aNew;
2128 ScTypedCaseStrSet::const_iterator itNew =
2129 findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
2130
2131 if (itNew != pColumnData->end())
2132 {
2133 // match found!
2134 miAutoPosColumn = itNew;
2135 bInOwnChange = true; // disable ModifyHdl (reset below)
2136 mbPartialPrefix = false;
2137
2138 lcl_RemoveLineEnd( aNew );
2139 OUString aIns = aNew.copy(aAutoSearch.getLength());
2140
2141 // when editing in input line, apply to both edit views
2142 if ( pTableView )
2143 {
2145 pTableView->InsertText( aIns );
2147 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2148 aSel.nEndPara, aSel.nStartPos ) );
2149 }
2150 if ( pTopView )
2151 {
2153 pTopView->InsertText( aIns );
2155 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2156 aSel.nEndPara, aSel.nStartPos ) );
2157 }
2158
2159 bInOwnChange = false;
2160 }
2161 }
2162 }
2163 }
2164 }
2165
2166 // For Tab, HideCursor was always called first
2167 if (pActiveView)
2168 pActiveView->ShowCursor();
2169}
2170
2171// Highlight parentheses
2173{
2174 // Find parentheses
2175 //TODO: Can we disable parentheses highlighting per parentheses?
2176 bool bFound = false;
2177 if ( bFormulaMode && eMode != SC_INPUT_TOP )
2178 {
2179 if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
2180 {
2182 if (aSel.nStartPos)
2183 {
2184 // Examine character left to the cursor
2185 sal_Int32 nPos = aSel.nStartPos - 1;
2186 OUString aFormula = mpEditEngine->GetText(aSel.nStartPara);
2187 sal_Unicode c = aFormula[nPos];
2188 if ( c == '(' || c == ')' )
2189 {
2190 // Note this matches only within one paragraph.
2191 sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
2192 if ( nOther != -1 )
2193 {
2194 SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
2196
2199 {
2200 // Remove old highlighting
2201 sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2202 for (sal_Int32 i=0; i<nCount; i++)
2203 mpEditEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
2204 }
2205
2206 ESelection aSelThis( aSel.nStartPara, nPos, aSel.nStartPara, nPos+1);
2207 mpEditEngine->QuickSetAttribs( aSet, aSelThis );
2208 ESelection aSelOther( aSel.nStartPara, nOther, aSel.nStartPara, nOther+1);
2209 mpEditEngine->QuickSetAttribs( aSet, aSelOther );
2210
2211 // Dummy InsertText for Update and Paint (selection is empty)
2212 pTableView->InsertText( OUString() );
2213
2214 bFound = true;
2215 }
2216 }
2217 }
2218
2219 // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
2220 // with different color (COL_LIGHTBLUE) ??
2221 }
2222 }
2223
2224 // Remove old highlighting, if no new one is set
2225 if ( bParenthesisShown && !bFound && pTableView )
2226 {
2227 sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2228 for (sal_Int32 i=0; i<nCount; i++)
2230 }
2231
2232 bParenthesisShown = bFound;
2233}
2234
2235void ScInputHandler::ViewShellGone(const ScTabViewShell* pViewSh) // Executed synchronously!
2236{
2237 if ( pViewSh == pActiveViewSh )
2238 {
2239 pLastState.reset();
2240 pLastPattern = nullptr;
2241 }
2242
2243 if ( pViewSh == pRefViewSh )
2244 {
2246 // We end the EditMode anyways
2247 EnterHandler();
2248 bFormulaMode = false;
2249 pRefViewSh = nullptr;
2250 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2251 SC_MOD()->SetRefInputHdl(nullptr);
2252 if (pInputWin)
2253 pInputWin->SetFormulaMode(false);
2255 }
2256
2258
2259 if ( pActiveViewSh && pActiveViewSh == pViewSh )
2260 {
2261 OSL_FAIL("pActiveViewSh is gone");
2262 pActiveViewSh = nullptr;
2263 }
2264
2265 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
2266 UpdateRefDevice(); // Don't keep old document's printer as RefDevice
2267}
2268
2270{
2272
2273 // #i20588# Don't rely on focus to find the active edit view. Instead, the
2274 // active pane at the start of editing is now stored (GetEditActivePart).
2275 // GetActiveWin (the currently active pane) fails for ref input across the
2276 // panes of a split view.
2277
2278 vcl::Window* pShellWin = pActiveViewSh ?
2280 nullptr;
2281
2282 sal_uInt16 nCount = mpEditEngine->GetViewCount();
2283 if (nCount > 0)
2284 {
2285 pTableView = mpEditEngine->GetView();
2286 for (sal_uInt16 i=1; i<nCount; i++)
2287 {
2288 EditView* pThis = mpEditEngine->GetView(i);
2289 vcl::Window* pWin = pThis->GetWindow();
2290 if ( pWin==pShellWin )
2291 pTableView = pThis;
2292 }
2293 }
2294 else
2295 pTableView = nullptr;
2296
2297 // setup the pTableView editeng for tiled rendering to get cursor and selections
2299 {
2301 {
2303 }
2304 }
2305
2307 {
2308 // tdf#71409: Always create the edit engine instance for the input
2309 // window, in order to properly manage accessibility events.
2310 pTopView = pInputWin->GetEditView();
2311 if (eMode != SC_INPUT_TOP)
2312 pTopView = nullptr;
2313 }
2314 else
2315 pTopView = nullptr;
2316}
2317
2319{
2320 pInputWin = pNew;
2321}
2322
2324{
2325 if (pInputWin && !pInputWin->isDisposed())
2326 pInputWin->StopEditEngine( bAll );
2327
2328 pTopView = nullptr; // invalid now
2329}
2330
2332{
2334 return pTopView ? pTopView : pTableView;
2335}
2336
2338{
2339 pLastPattern = nullptr;
2340 if ( !pLastState && pActiveViewSh )
2341 pActiveViewSh->UpdateInputHandler( true ); // Get status again
2342 else
2343 NotifyChange( pLastState.get(), true );
2344}
2345
2347{
2348 SvxAdjust eSvxAdjust;
2349 switch (eAttrAdjust)
2350 {
2351 case SvxCellHorJustify::Standard:
2352 {
2353 bool bNumber = false;
2354 if (cTyped) // Restarted
2355 bNumber = (cTyped>='0' && cTyped<='9'); // Only ciphers are numbers
2356 else if ( pActiveViewSh )
2357 {
2359 bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
2360 }
2361 eSvxAdjust = bNumber ? SvxAdjust::Right : SvxAdjust::Left;
2362 }
2363 break;
2364 case SvxCellHorJustify::Block:
2365 eSvxAdjust = SvxAdjust::Block;
2366 break;
2367 case SvxCellHorJustify::Center:
2368 eSvxAdjust = SvxAdjust::Center;
2369 break;
2370 case SvxCellHorJustify::Right:
2371 eSvxAdjust = SvxAdjust::Right;
2372 break;
2373 default: // SvxCellHorJustify::Left
2374 eSvxAdjust = SvxAdjust::Left;
2375 break;
2376 }
2377
2378 bool bAsianVertical = pLastPattern &&
2379 pLastPattern->GetItem( ATTR_STACKED ).GetValue() &&
2381 if ( bAsianVertical )
2382 {
2383 // Always edit at top of cell -> LEFT when editing vertically
2384 eSvxAdjust = SvxAdjust::Left;
2385 }
2386
2387 pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
2388 mpEditEngine->SetDefaults( *pEditDefaults );
2389
2390 if ( pActiveViewSh )
2391 {
2392 pActiveViewSh->GetViewData().SetEditAdjust( eSvxAdjust );
2393 }
2394 mpEditEngine->SetVertical( bAsianVertical );
2395}
2396
2398{
2399 // Delete hard alignment attributes
2400 bool bUndo = mpEditEngine->IsUndoEnabled();
2401 if ( bUndo )
2402 mpEditEngine->EnableUndo( false );
2403
2404 // Non-default paragraph attributes (e.g. from clipboard)
2405 // must be turned into character attributes
2406 mpEditEngine->RemoveParaAttribs();
2407
2408 if ( bUndo )
2409 mpEditEngine->EnableUndo( true );
2410
2411}
2412
2414{
2415 // Delete pRangeFindList and colors
2416 mpEditEngine->SetUpdateLayout(false);
2417 sal_Int32 nCount = mpEditEngine->GetParagraphCount(); // Could just have been inserted
2418 for (sal_Int32 i=0; i<nCount; i++)
2419 mpEditEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
2420 mpEditEngine->SetUpdateLayout(true);
2421
2422 EditView* pActiveView = pTopView ? pTopView : pTableView;
2423 pActiveView->ShowCursor( false );
2424
2425 DeleteRangeFinder(); // Deletes the list and the labels on the table
2426}
2427
2428bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
2429 ScEditEngineDefaulter* pTopEngine )
2430{
2431 bool bNewTable = false;
2432
2433 if (bModified)
2434 return false;
2435
2436 if (pActiveViewSh)
2437 {
2439
2440 if (!rDoc.ValidCol(aCursorPos.Col()))
2441 return false;
2442
2445 SyncViews();
2446
2447
2448 const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
2449 ScEditableTester aTester;
2450 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
2451 aTester.TestSelection( rDoc, rMark );
2452 else
2453 aTester.TestSelectedBlock(
2454 rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
2455
2456 bool bStartInputMode = true;
2457
2458 if (!aTester.IsEditable())
2459 {
2460 bProtected = true;
2461 // We allow read-only input mode activation regardless
2462 // whether it's part of an array or not or whether explicit cell
2463 // activation is requested (double-click or F2) or a click in input
2464 // line.
2465 bool bShowError = (!bInputActivated || !aTester.GetMessageId() || aTester.GetMessageId() != STR_PROTECTIONERR) &&
2467 if (bShowError)
2468 {
2470 StopInputWinEngine( true );
2472 if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
2473 {
2474 // Prevent repeated error messages for the same cell from command events
2475 // (for keyboard events, multiple messages are wanted).
2476 // Set the flag before showing the error message because the command handler
2477 // for the next IME command may be called when showing the dialog.
2478 if ( bFromCommand )
2479 bCommandErrorShown = true;
2480
2483 }
2484 bStartInputMode = false;
2485 }
2486 }
2487
2488 if (bStartInputMode)
2489 {
2490 // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
2491 mpEditEngine->SetUpdateLayout( false );
2492
2493 // Take over attributes in EditEngine
2494 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
2495 aCursorPos.Row(),
2496 aCursorPos.Tab() );
2497 if (pPattern != pLastPattern)
2498 {
2499 // Percent format?
2500 const SfxItemSet& rAttrSet = pPattern->GetItemSet();
2501
2502 if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALUE_FORMAT ) )
2503 {
2504 sal_uInt32 nFormat = pItem->GetValue();
2505 if (SvNumFormatType::PERCENT == rDoc.GetFormatTable()->GetType( nFormat ))
2506 nCellPercentFormatDecSep = rDoc.GetFormatTable()->GetFormatDecimalSep( nFormat).toChar();
2507 else
2509 }
2510 else
2511 nCellPercentFormatDecSep = 0; // Default: no percent
2512
2513 // Validity specified?
2514 if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALIDDATA ) )
2515 nValidation = pItem->GetValue();
2516 else
2517 nValidation = 0;
2518
2519 // EditEngine Defaults
2520 // In no case SetParaAttribs, because the EditEngine might already
2521 // be filled (for Edit cells).
2522 // SetParaAttribs would change the content.
2523
2527
2528 pPattern->FillEditItemSet( pEditDefaults.get() );
2529 mpEditEngine->SetDefaults( *pEditDefaults );
2530 pLastPattern = pPattern;
2531 bLastIsSymbol = pPattern->IsSymbolFont();
2532
2533 // Background color must be known for automatic font color.
2534 // For transparent cell background, the document background color must be used.
2535
2536 Color aBackCol = pPattern->GetItem( ATTR_BACKGROUND ).GetColor();
2537 ScModule* pScMod = SC_MOD();
2538 if ( aBackCol.IsTransparent() ||
2541 mpEditEngine->SetBackgroundColor( aBackCol );
2542
2543 // Adjustment
2544 eAttrAdjust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
2545 if ( eAttrAdjust == SvxCellHorJustify::Repeat &&
2546 pPattern->GetItem(ATTR_LINEBREAK).GetValue() )
2547 {
2548 // #i31843# "repeat" with "line breaks" is treated as default alignment
2549 eAttrAdjust = SvxCellHorJustify::Standard;
2550 }
2551 }
2552
2553 if (pTopEngine)
2554 {
2555 // Necessary to sync SvxAutoCorrect behavior. This has to be
2556 // done before InitRangeFinder() below.
2557 MergeLanguageAttributes( *pTopEngine);
2558 }
2559
2560 // UpdateSpellSettings enables online spelling if needed
2561 // -> also call if attributes are unchanged
2562 UpdateSpellSettings( true ); // uses pLastPattern
2563
2564 // Fill EditEngine
2565 OUString aStr;
2566 if (bTextValid)
2567 {
2568 mpEditEngine->SetTextCurrentDefaults(aCurrentText);
2570 bTextValid = false;
2571 aCurrentText.clear();
2572 }
2573 else
2574 aStr = GetEditText(mpEditEngine.get());
2575
2576 // cTyped!=0 is overtyping, not editing.
2577 mbEditingExistingContent = !cTyped && !aStr.isEmpty();
2578
2579 if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
2580 {
2581 aStr = aStr.copy(1, aStr.getLength() -2);
2582 mpEditEngine->SetTextCurrentDefaults(aStr);
2583 if ( pInputWin )
2584 pInputWin->SetTextString(aStr);
2585 }
2586
2587 UpdateAdjust( cTyped );
2588
2589 if ( SC_MOD()->GetAppOptions().GetAutoComplete() )
2590 GetColData();
2591
2592 if (!cTyped && !bCreatingFuncView && StartsLikeFormula(aStr))
2593 InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
2594
2595 bNewTable = true; // -> PostEditView Call
2596 }
2597 }
2598
2599 if (!bProtected && pInputWin)
2600 pInputWin->SetOkCancelMode();
2601
2602 return bNewTable;
2603}
2604
2606{
2607 const SfxItemSet& rSrcSet = mpEditEngine->GetDefaults();
2608 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE ));
2609 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CJK ));
2610 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CTL ));
2611}
2612
2613static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
2614{
2615 OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
2616
2617 EditEngine* pEngine = pEditView->GetEditEngine();
2618 sal_Int32 nCount = pEngine->GetParagraphCount();
2619 if (nCount > 1)
2620 {
2621 sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2622 while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2623 {
2624 rSel.nStartPos -= nParLen + 1; // Including space from line break
2625 nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2626 }
2627
2628 nParLen = pEngine->GetTextLen(rSel.nEndPara);
2629 while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2630 {
2631 rSel.nEndPos -= nParLen + 1; // Including space from line break
2632 nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2633 }
2634 }
2635
2636 ESelection aSel = pEditView->GetSelection();
2637
2638 if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2639 || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2640 pEditView->SetSelection( rSel );
2641}
2642
2643void ScInputHandler::SyncViews( const EditView* pSourceView )
2644{
2645 if (pSourceView)
2646 {
2647 bool bSelectionForTopView = false;
2648 if (pTopView && pTopView != pSourceView)
2649 bSelectionForTopView = true;
2650 bool bSelectionForTableView = false;
2651 if (pTableView && pTableView != pSourceView)
2652 bSelectionForTableView = true;
2653 if (bSelectionForTopView || bSelectionForTableView)
2654 {
2655 ESelection aSel(pSourceView->GetSelection());
2656 if (bSelectionForTopView)
2657 pTopView->SetSelection(aSel);
2658 if (bSelectionForTableView)
2660 }
2661 }
2662 // Only sync selection from topView if we are actually editing there
2663 else if (pTopView && pTableView)
2664 {
2667 }
2668}
2669
2671{
2672 if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2673 mpEditEngine && mpEditEngine->IsUpdateLayout() && pInputWin )
2674 {
2675 // Update input line from ModifyHdl for changes that are not
2676 // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2677 OUString aText(ScEditUtil::GetMultilineString(*mpEditEngine));
2678 lcl_RemoveTabs(aText);
2679 pInputWin->SetTextString(aText);
2680 }
2681}
2682
2686bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2687{
2688 if (pActiveViewSh)
2690 bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2691
2692 if ( eMode == SC_INPUT_NONE )
2693 return StartTable( cTyped, bFromCommand, false, nullptr );
2694 else
2695 return false;
2696}
2697
2698void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2699{
2701
2702 if (eMode==SC_INPUT_NONE)
2704
2705 if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2706 {
2707 // table EditEngine is formatted below, input line needs formatting after paste
2708 // #i20282# not when called from the input line's modify handler
2710
2711 // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2712 // can't safely access the EditEngine's current view, so the cursor has to be
2713 // shown again here.
2715 }
2716
2717 if (bSetModified)
2718 bModified = true;
2719 bSelIsRef = false;
2720
2722 RemoveRangeFinder(); // Delete attributes and labels
2723
2724 UpdateParenthesis(); // Highlight parentheses anew
2725
2727 {
2728 OUString aText;
2729 if (pInputWin)
2731 else
2732 aText = GetEditText(mpEditEngine.get());
2733 lcl_RemoveTabs(aText);
2734
2735 if ( pInputWin )
2736 pInputWin->SetTextString( aText );
2737
2739 {
2740 if (pActiveViewSh)
2741 {
2742 // TODO: deprecated?
2743 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aText.toUtf8().getStr());
2744 }
2745 }
2746 }
2747
2748 // If the cursor is before the end of a paragraph, parts are being pushed to
2749 // the right (independently from the eMode) -> Adapt View!
2750 // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2751 //
2752 // First make sure the status handler is called now if the cursor
2753 // is outside the visible area
2754 mpEditEngine->QuickFormatDoc();
2755
2756 EditView* pActiveView = pTopView ? pTopView : pTableView;
2757 ESelection aSel;
2758 if (pActiveView && pActiveViewSh)
2759 {
2760 ScViewData& rViewData = pActiveViewSh->GetViewData();
2761
2762 bool bNeedGrow = ( rViewData.GetEditAdjust() != SvxAdjust::Left ); // Always right-aligned
2763 if (!bNeedGrow)
2764 {
2765 // Cursor before the end?
2766 aSel = pActiveView->GetSelection();
2767 aSel.Adjust();
2768 bNeedGrow = ( aSel.nEndPos != mpEditEngine->GetTextLen(aSel.nEndPara) );
2769 }
2770 if (!bNeedGrow)
2771 {
2772 bNeedGrow = rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
2773 }
2774 if (bNeedGrow)
2775 {
2776 // Adjust inplace view
2777 rViewData.EditGrowY();
2778 rViewData.EditGrowX();
2779 }
2780 }
2781
2783 {
2785 if (pActiveView)
2786 aSel = pActiveView->GetSelection();
2787
2790 aSel);
2791 }
2792
2794 bTextValid = false; // Changes only in the EditEngine
2795 bInOwnChange = false;
2796}
2797
2798bool ScInputHandler::StartsLikeFormula( std::u16string_view rStr ) const
2799{
2800 // For new input '+' and '-' may start the dreaded "lazy data typist"
2801 // formula input, editing existing formula content can only start with '='.
2802 return !rStr.empty() && (rStr[0] == '=' || (!mbEditingExistingContent && (rStr[0] == '+' || rStr[0] == '-')));
2803}
2804
2806{
2807 SfxApplication* pSfxApp = SfxGetpApp();
2808
2809 bool bIsFormula = !bProtected;
2810 if (bIsFormula)
2811 {
2812 const OUString& rText = mpEditEngine->GetText(0);
2813 bIsFormula = StartsLikeFormula(rText);
2814 }
2815
2816 if ( bIsFormula )
2817 {
2818 if (!bFormulaMode)
2819 {
2820 bFormulaMode = true;
2822 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2823 ScModule* pMod = SC_MOD();
2824 pMod->SetRefInputHdl(this);
2825 if (pInputWin)
2826 pInputWin->SetFormulaMode(true);
2827
2828 // in LOK, we always need to perform the GetFormulaData() call so
2829 // that the formula insertion works
2832
2835 }
2836 }
2837 else // Deactivate
2838 {
2839 if (bFormulaMode)
2840 {
2841 ShowRefFrame();
2842 bFormulaMode = false;
2843 pRefViewSh = nullptr;
2844 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2845 SC_MOD()->SetRefInputHdl(nullptr);
2846 if (pInputWin)
2847 pInputWin->SetFormulaMode(false);
2849 }
2850 }
2851}
2852
2854{
2855 // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2856 // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2857 // A local variable is used instead.
2858 ScTabViewShell* pVisibleSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2859 if ( !(pRefViewSh && pRefViewSh != pVisibleSh) )
2860 return;
2861
2862 bool bFound = false;
2863 SfxViewFrame& rRefFrame = pRefViewSh->GetViewFrame();
2864 SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2865 while ( pOneFrame && !bFound )
2866 {
2867 if ( pOneFrame == &rRefFrame )
2868 bFound = true;
2869 pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2870 }
2871
2872 if (bFound)
2873 {
2874 // We count on Activate working synchronously here
2875 // (pActiveViewSh is set while doing so)
2876 pRefViewSh->SetActive(); // Appear and SetViewFrame
2877
2878 // pLastState is set correctly in the NotifyChange from the Activate
2879 }
2880 else
2881 {
2882 OSL_FAIL("ViewFrame for reference input is not here anymore");
2883 }
2884}
2885
2887{
2888 EditView* pActiveView = pTopView ? pTopView : pTableView;
2889 if (!pActiveView)
2890 return;
2891
2892 ESelection aSel = pActiveView->GetSelection();
2893 aSel.nStartPara = aSel.nEndPara;
2894 aSel.nStartPos = aSel.nEndPos;
2895 if (pTableView)
2896 pTableView->SetSelection( aSel );
2897 if (pTopView)
2898 pTopView->SetSelection( aSel );
2899}
2900
2902{
2903 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2904 if (!pViewFrm)
2905 return;
2906
2907 SfxBindings& rBindings = pViewFrm->GetBindings();
2908
2909 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2910 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2911 rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2912
2913 rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2914 rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2915 rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2916 rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
2917 rBindings.Invalidate( SID_ULINE_VAL_NONE );
2918 rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2919 rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2920 rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2921
2922 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2923
2924 rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2925 rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2926 rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2927 rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2928 rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2929
2930 rBindings.Invalidate( SID_SAVEDOC );
2931 rBindings.Invalidate( SID_DOC_MODIFIED );
2932}
2933
2934// --------------- public methods --------------------------------------------
2935
2936void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText, ScEditEngineDefaulter* pTopEngine )
2937{
2938 if ( eMode == eNewMode )
2939 return;
2940
2942
2943 if (bProtected)
2944 {
2946 StopInputWinEngine( true );
2947 if (pActiveViewSh)
2949 return;
2950 }
2951
2952 if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2953 // Disable paste mode when edit mode starts.
2955
2956 bInOwnChange = true; // disable ModifyHdl (reset below)
2957
2958 ScInputMode eOldMode = eMode;
2959 eMode = eNewMode;
2960 if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2961 StopInputWinEngine( false );
2962
2964 {
2965 if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2966 {
2967 if (StartTable(0, false, eMode == SC_INPUT_TABLE, pTopEngine))
2968 {
2969 if (pActiveViewSh)
2971 }
2972 }
2973
2974 if (pInitText)
2975 {
2976 mpEditEngine->SetTextCurrentDefaults(*pInitText);
2977 bModified = true;
2978 }
2979
2980 sal_Int32 nPara = mpEditEngine->GetParagraphCount()-1;
2981 sal_Int32 nLen = mpEditEngine->GetText(nPara).getLength();
2982 sal_uInt16 nCount = mpEditEngine->GetViewCount();
2983
2984 for (sal_uInt16 i=0; i<nCount; i++)
2985 {
2986 if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2987 {
2988 // Keep Selection
2989 }
2990 else
2991 {
2992 mpEditEngine->GetView(i)->
2993 SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2994 }
2995 mpEditEngine->GetView(i)->ShowCursor(false);
2996 }
2997 }
2998
3001 {
3002 if (pTableView)
3004 }
3005 else
3006 {
3007 if (pTopView)
3009 }
3010
3011 if (eNewMode != eOldMode)
3013
3014 bInOwnChange = false;
3015}
3016
3020static bool lcl_IsNumber(std::u16string_view aString)
3021{
3022 size_t nLen = aString.size();
3023 for (size_t i=0; i<nLen; i++)
3024 {
3025 sal_Unicode c = aString[i];
3026 if ( c < '0' || c > '9' )
3027 return false;
3028 }
3029 return true;
3030}
3031
3032static void lcl_SelectionToEnd( EditView* pView )
3033{
3034 if ( pView )
3035 {
3036 EditEngine* pEngine = pView->GetEditEngine();
3037 sal_Int32 nParCnt = pEngine->GetParagraphCount();
3038 if ( nParCnt == 0 )
3039 nParCnt = 1;
3040 ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
3041 pView->SetSelection( aSel );
3042 }
3043}
3044
3045void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
3046{
3049 return;
3050
3051 // Macro calls for validity can cause a lot of problems, so inhibit
3052 // nested calls of EnterHandler().
3053 if (bInEnterHandler) return;
3054 bInEnterHandler = true;
3055 bInOwnChange = true; // disable ModifyHdl (reset below)
3056 mbPartialPrefix = false;
3057
3059
3060 bool bMatrix = ( nBlockMode == ScEnterMode::MATRIX );
3061
3062 SfxApplication* pSfxApp = SfxGetpApp();
3063 std::unique_ptr<EditTextObject> pObject;
3064 std::unique_ptr<ScPatternAttr> pCellAttrs;
3065 bool bForget = false; // Remove due to validity?
3066
3067 OUString aString = GetEditText(mpEditEngine.get());
3068 OUString aPreAutoCorrectString(aString);
3069 EditView* pActiveView = pTopView ? pTopView : pTableView;
3070 if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
3071 {
3072 if (pColumnData && miAutoPosColumn != pColumnData->end())
3073 {
3074 // #i47125# If AutoInput appended something, do the final AutoCorrect
3075 // with the cursor at the end of the input.
3078 }
3079
3080 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
3081
3082 if (pTopView)
3083 pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
3084 if (pTableView)
3085 pTableView->CompleteAutoCorrect(pFrameWin);
3086 aString = GetEditText(mpEditEngine.get());
3087 }
3088 lcl_RemoveTabs(aString);
3089 lcl_RemoveTabs(aPreAutoCorrectString);
3090
3091 // Test if valid (always with simple string)
3093 {
3096 if (pData && pData->HasErrMsg())
3097 {
3098 // #i67990# don't use pLastPattern in EnterHandler
3099 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3100
3101 bool bOk;
3102
3103 if (pData->GetDataMode() == SC_VALID_CUSTOM)
3104 {
3105 bOk = pData->IsDataValidCustom( aString, *pPattern, aCursorPos, ScValidationData::CustomValidationPrivateAccess() );
3106 }
3107 else
3108 {
3109 bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
3110 }
3111
3112 if (!bOk)
3113 {
3114 pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
3115
3116 // tdf#125917 Release the grab that a current mouse-down event being handled
3117 // by ScTabView has put on the mouse via its SelectionEngine.
3118 // Otherwise the warning box cannot interact with the mouse
3119 if (ScTabView* pView = pActiveViewSh->GetViewData().GetView())
3120 {
3121 if (ScViewSelectionEngine* pSelEngine = pView->GetSelEngine())
3122 pSelEngine->ReleaseMouse();
3123 }
3124
3125 if (bBeforeSavingInLOK)
3126 {
3127 // Invalid entry but not applied to the document model.
3128 // Exit to complete the "save", leaving the edit view as it is
3129 // for the user to continue after save.
3130 bInOwnChange = false;
3131 bInEnterHandler = false;
3132 return;
3133 }
3134
3135 if (pData->DoError(pActiveViewSh->GetFrameWeld(), aString, aCursorPos))
3136 bForget = true; // Do not take over input
3137 }
3138 }
3139 }
3140
3141 // Check for input into DataPilot table
3142 if ( bModified && pActiveViewSh && !bForget )
3143 {
3146 if ( pDPObj )
3147 {
3148 // Any input within the DataPilot table is either a valid renaming
3149 // or an invalid action - normal cell input is always aborted
3151 bForget = true;
3152 }
3153 }
3154
3155 std::vector<editeng::MisspellRanges> aMisspellRanges;
3156 // UpdateLayout must be true during CompleteOnlineSpelling
3157 const bool bUpdateLayout = mpEditEngine->SetUpdateLayout( true );
3158 mpEditEngine->CompleteOnlineSpelling();
3159 bool bSpellErrors = !bFormulaMode && mpEditEngine->HasOnlineSpellErrors();
3160 if ( bSpellErrors )
3161 {
3162 // #i3820# If the spell checker flags numerical input as error,
3163 // it still has to be treated as number, not EditEngine object.
3164 if ( pActiveViewSh )
3165 {
3167 // #i67990# don't use pLastPattern in EnterHandler
3168 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3169 if (pPattern)
3170 {
3171 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
3172 // without conditional format, as in ScColumn::SetString
3173 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
3174 double nVal;
3175 if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
3176 {
3177 bSpellErrors = false; // ignore the spelling errors
3178 }
3179 }
3180 }
3181 }
3182
3183 // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
3184 // SetUpdateLayout must come after CompleteOnlineSpelling.
3185 // The view is hidden in any case below (Broadcast).
3186 mpEditEngine->SetUpdateLayout( false );
3187
3188 if ( bModified && !bForget ) // What is being entered (text/object)?
3189 {
3190 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
3191 if ( nParCnt == 0 )
3192 nParCnt = 1;
3193
3194 bool bUniformAttribs = true;
3195 SfxItemSet aPara1Attribs = mpEditEngine->GetAttribs(0, 0, mpEditEngine->GetTextLen(0));
3196 for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
3197 {
3198 SfxItemSet aPara2Attribs = mpEditEngine->GetAttribs(nPara, 0, mpEditEngine->GetTextLen(nPara));
3199 if (!(aPara1Attribs == aPara2Attribs))
3200 {
3201 // Paragraph format different from that of the 1st paragraph.
3202 bUniformAttribs = false;
3203 break;
3204 }
3205 }
3206
3207 ESelection aSel( 0, 0, nParCnt-1, mpEditEngine->GetTextLen(nParCnt-1) );
3208 SfxItemSet aOldAttribs = mpEditEngine->GetAttribs( aSel );
3209 const SfxPoolItem* pItem = nullptr;
3210
3211 // Find common (cell) attributes before RemoveAdjust
3212 if ( pActiveViewSh && bUniformAttribs )
3213 {
3214 std::optional<SfxItemSet> pCommonAttrs;
3215 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
3216 {
3217 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3218 if ( eState == SfxItemState::SET &&
3221 *pItem != pEditDefaults->Get(nId) )
3222 {
3223 if ( !pCommonAttrs )
3224 pCommonAttrs.emplace( mpEditEngine->GetEmptyItemSet() );
3225 pCommonAttrs->Put( *pItem );
3226 }
3227 }
3228
3229 if ( pCommonAttrs )
3230 {
3232 pCellAttrs = std::make_unique<ScPatternAttr>(rDoc.GetPool());
3233 pCellAttrs->GetFromEditItemSet( &*pCommonAttrs );
3234 }
3235 }
3236
3237 // Clear ParaAttribs (including adjustment)
3238 RemoveAdjust();
3239
3240 bool bAttrib = false; // Formatting present?
3241
3242 // check if EditObject is needed
3243 if (nParCnt > 1)
3244 bAttrib = true;
3245 else
3246 {
3247 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
3248 {
3249 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3250 if (eState == SfxItemState::DONTCARE)
3251 bAttrib = true;
3252 else if (eState == SfxItemState::SET)
3253 {
3254 // Keep same items in EditEngine as in ScEditAttrTester
3257 {
3258 if ( *pItem != pEditDefaults->Get(nId) )
3259 bAttrib = true;
3260 }
3261 }
3262 }
3263
3264 // Contains fields?
3265 SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
3266 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
3267 bAttrib = true;
3268
3269 // Not converted characters?
3270 SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
3271 if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
3272 bAttrib = true;
3273
3274 // Always recognize formulas as formulas
3275 // We still need the preceding test due to cell attributes
3276 }
3277
3278 if (bSpellErrors)
3279 mpEditEngine->GetAllMisspellRanges(aMisspellRanges);
3280
3281 if (bMatrix)
3282 bAttrib = false;
3283
3284 if (bAttrib)
3285 {
3286 mpEditEngine->ClearSpellErrors();
3287 pObject = mpEditEngine->CreateTextObject();
3288 }
3289 else if (SC_MOD()->GetAppOptions().GetAutoComplete()) // Adjust Upper/Lower case
3290 {
3291 // Perform case-matching only when the typed text is partial.
3292 if (pColumnData && aAutoSearch.getLength() < aString.getLength())
3293 aString = getExactMatch(*pColumnData, aString);
3294 }
3295 }
3296
3297 // Don't rely on ShowRefFrame switching the active view synchronously
3298 // execute the function directly on the correct view's bindings instead
3299 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3301
3302 if (bFormulaMode)
3303 {
3304 ShowRefFrame();
3305
3306 if (pExecuteSh)
3307 {
3308 pExecuteSh->SetTabNo(aCursorPos.Tab());
3309 pExecuteSh->ActiveGrabFocus();
3310 }
3311
3312 bFormulaMode = false;
3313 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3314 SC_MOD()->SetRefInputHdl(nullptr);
3315 if (pInputWin)
3316 pInputWin->SetFormulaMode(false);
3318 }
3319 pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3321 ResetAutoPar();
3322
3323 bool bOldMod = bModified;
3324
3325 bModified = false;
3326 bSelIsRef = false;
3328 StopInputWinEngine(true);
3329
3330 // Text input (through number formats) or ApplySelectionPattern modify
3331 // the cell's attributes, so pLastPattern is no longer valid
3332 pLastPattern = nullptr;
3333
3334 if (bOldMod && !bProtected && !bForget)
3335 {
3336 bool bInsertPreCorrectedString = true;
3337 // No typographic quotes in formulas
3338 if (aString.startsWith("="))
3339 {
3341 if ( pAuto )
3342 {
3343 bInsertPreCorrectedString = false;
3344 OUString aReplace(pAuto->GetStartDoubleQuote());
3345 if( aReplace.isEmpty() )
3347 if( aReplace != "\"" )
3348 aString = aString.replaceAll( aReplace, "\"" );
3349
3350 aReplace = OUString(pAuto->GetEndDoubleQuote());
3351 if( aReplace.isEmpty() )
3353 if( aReplace != "\"" )
3354 aString = aString.replaceAll( aReplace, "\"" );
3355
3356 aReplace = OUString(pAuto->GetStartSingleQuote());
3357 if( aReplace.isEmpty() )
3359 if( aReplace != "'" )
3360 aString = aString.replaceAll( aReplace, "'" );
3361
3362 aReplace = OUString(pAuto->GetEndSingleQuote());
3363 if( aReplace.isEmpty() )
3365 if( aReplace != "'" )
3366 aString = aString.replaceAll( aReplace, "'");
3367 }
3368 }
3369
3370 pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditViewNoPaint ) );
3371
3372 if ( pExecuteSh )
3373 {
3374 SfxBindings& rBindings = pExecuteSh->GetViewFrame().GetBindings();
3375
3376 sal_uInt16 nId = FID_INPUTLINE_ENTER;
3377 if ( nBlockMode == ScEnterMode::BLOCK )
3378 nId = FID_INPUTLINE_BLOCK;
3379 else if ( nBlockMode == ScEnterMode::MATRIX )
3380 nId = FID_INPUTLINE_MATRIX;
3381
3382 const SfxPoolItem* aArgs[2];
3383 aArgs[1] = nullptr;
3384
3385 if ( bInsertPreCorrectedString && aString != aPreAutoCorrectString )
3386 {
3387 ScInputStatusItem aItem(FID_INPUTLINE_STATUS,
3389 aPreAutoCorrectString, pObject.get());
3390 aArgs[0] = &aItem;
3391 rBindings.Execute(nId, aArgs);
3392 }
3393
3394 ScInputStatusItem aItemCorrected(FID_INPUTLINE_STATUS,
3396 aString, pObject.get());
3397 if ( !aMisspellRanges.empty() )
3398 aItemCorrected.SetMisspellRanges(&aMisspellRanges);
3399
3400 aArgs[0] = &aItemCorrected;
3401 rBindings.Execute(nId, aArgs);
3402 }
3403
3404 pLastState.reset(); // pLastState still contains the old text
3405 }
3406 else
3407 pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
3408
3409 if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
3410 {
3411 // Combine with input?
3412 pExecuteSh->ApplySelectionPattern( *pCellAttrs, true );
3413 pExecuteSh->AdjustBlockHeight();
3414 }
3415
3416 HideTip();
3417 HideTipBelow();
3418
3420 aFormText.clear();
3421
3423 bInOwnChange = false;
3424 bInEnterHandler = false;
3425 if (bUpdateLayout)
3426 mpEditEngine->SetUpdateLayout( true );
3427}
3428
3430{
3431 bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
3432
3434
3435 bModified = false;
3436 mbPartialPrefix = false;
3438
3439 // Don't rely on ShowRefFrame switching the active view synchronously
3440 // execute the function directly on the correct view's bindings instead
3441 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3443
3444 if (bFormulaMode)
3445 {
3446 ShowRefFrame();
3447 if (pExecuteSh)
3448 {
3449 pExecuteSh->SetTabNo(aCursorPos.Tab());
3450 pExecuteSh->ActiveGrabFocus();
3451 }
3452 bFormulaMode = false;
3453 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3454 SC_MOD()->SetRefInputHdl(nullptr);
3455 if (pInputWin)
3456 pInputWin->SetFormulaMode(false);
3458 }
3459 pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3461 ResetAutoPar();
3462
3464 StopInputWinEngine( true );
3465 SCCOL nMaxCol(MAXCOL);
3466 if (pExecuteSh)
3467 {
3468 pExecuteSh->StopEditShell();
3469 nMaxCol = pExecuteSh->GetViewData().GetDocument().MaxCol();
3470 }
3471
3472 aCursorPos.Set(nMaxCol+1,0,0); // Invalid flag
3473 mpEditEngine->SetTextCurrentDefaults(OUString());
3474
3475 if ( !pLastState && pExecuteSh )
3476 pExecuteSh->UpdateInputHandler( true ); // Update status again
3477 else
3478 NotifyChange( pLastState.get(), true );
3479
3481 aFormText.clear();
3482
3483 bInOwnChange = false;
3484
3485 if ( comphelper::LibreOfficeKit::isActive() && pExecuteSh )
3486 {
3487 // Clear
3488 std::vector<ReferenceMark> aReferenceMarks;
3490 }
3491}
3492
3494{
3495 // References to unnamed document; that doesn't work
3496 return bFormulaMode && pRefViewSh
3498 && !pDocSh->HasName();
3499}
3500
3502{
3505 if (!pTableView && !pTopView)
3506 return; // E.g. FillMode
3507
3508 DataChanging(); // Cannot be new
3509
3511 OUString aText = GetEditText(mpEditEngine.get());
3512 sal_Unicode cLastChar = 0;
3513 sal_Int32 nPos = aText.getLength() - 1;
3514 while (nPos >= 0) //checking space
3515 {
3516 cLastChar = aText[nPos];
3517 if (cLastChar != ' ')
3518 break;
3519 --nPos;
3520 }
3521
3522 bool bAppendSeparator = (cLastChar != '(' && cLastChar != cSep && cLastChar != '=');
3523 if (bAppendSeparator)
3524 {
3525 if (pTableView)
3526 pTableView->InsertText( OUString(cSep) );
3527 if (pTopView)
3528 pTopView->InsertText( OUString(cSep) );
3529 }
3530
3531 DataChanged();
3532}
3533
3534void ScInputHandler::SetReference( const ScRange& rRef, const ScDocument& rDoc )
3535{
3536 HideTip();
3537
3538 const ScDocument* pThisDoc = nullptr;
3539 if (pRefViewSh)
3540 pThisDoc = &pRefViewSh->GetViewData().GetDocument();
3541 bool bOtherDoc = (pThisDoc != &rDoc);
3542 if (bOtherDoc && !rDoc.GetDocumentShell()->HasName())
3543 {
3544 // References to unnamed document; that doesn't work
3545 // SetReference should not be called, then
3546 return;
3547 }
3548 if (!pThisDoc)
3549 pThisDoc = &rDoc;
3550
3552 if (!pTableView && !pTopView)
3553 return; // E.g. FillMode
3554
3555 // Never overwrite the "="!
3556 EditView* pActiveView = pTopView ? pTopView : pTableView;
3557 ESelection aSel = pActiveView->GetSelection();
3558 aSel.Adjust();
3559 if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
3560 return;
3561
3562 DataChanging(); // Cannot be new
3563
3564 // Turn around selection if backwards.
3565 if (pTableView)
3566 {
3567 ESelection aTabSel = pTableView->GetSelection();
3568 if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
3569 {
3570 aTabSel.Adjust();
3571 pTableView->SetSelection(aTabSel);
3572 }
3573 }
3574 if (pTopView)
3575 {
3576 ESelection aTopSel = pTopView->GetSelection();
3577 if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
3578 {
3579 aTopSel.Adjust();
3580 pTopView->SetSelection(aTopSel);
3581 }
3582 }
3583
3584 // Create string from reference, in the syntax of the document being edited.
3585 OUString aRefStr;
3586 const ScAddress::Details aAddrDetails( *pThisDoc, aCursorPos );
3587 if (bOtherDoc)
3588 {
3589 // Reference to other document
3590 OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
3591
3592 // Always 3D and absolute.
3593 OUString aTmp(rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails));
3594
3595 SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
3596 // #i75893# convert escaped URL of the document to something user friendly
3598
3599 switch(aAddrDetails.eConv)
3600 {
3604 aRefStr = "[\'" + aFileName + "']";
3605 break;
3607 default:
3608 aRefStr = "\'" + aFileName + "'#";
3609 break;
3610 }
3611 aRefStr += aTmp;
3612 }
3613 else
3614 {
3615 if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
3616 rRef.aStart.Tab() != rRef.aEnd.Tab() )
3617 // pointer-selected => absolute sheet reference
3618 aRefStr = rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails);
3619 else
3620 aRefStr = rRef.Format(rDoc, ScRefFlags::VALID, aAddrDetails);
3621 }
3622 bool bLOKShowSelect = true;
3624 bLOKShowSelect = false;
3625
3626 if (pTableView || pTopView)
3627 {
3628 if (pTableView)
3629 pTableView->InsertText( aRefStr, true, bLOKShowSelect );
3630 if (pTopView)
3631 pTopView->InsertText( aRefStr, true, bLOKShowSelect );
3632
3633 DataChanged();
3634 }
3635
3636 bSelIsRef = true;
3637}
3638
3639void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
3640{
3641 if ( eMode == SC_INPUT_NONE )
3642 {
3643 OSL_FAIL("InsertFunction, not during input mode");
3644 return;
3645 }
3646
3648 if (!pTableView && !pTopView)
3649 return; // E.g. FillMode
3650
3651 DataChanging(); // Cannot be new
3652
3653 OUString aText = rFuncName;
3654 if (bAddPar)
3655 aText += "()";
3656
3657 if (pTableView)
3658 {
3659 pTableView->InsertText( aText );
3660 if (bAddPar)
3661 {
3663 --aSel.nStartPos;
3664 --aSel.nEndPos;
3665 pTableView->SetSelection(aSel);
3666 }
3667 }
3668 if (pTopView)
3669 {
3670 pTopView->InsertText( aText );
3671 if (bAddPar)
3672 {
3674 --aSel.nStartPos;
3675 --aSel.nEndPos;
3676 pTopView->SetSelection(aSel);
3677 }
3678 }
3679
3680 DataChanged();
3681
3682 if (bAddPar)
3683 AutoParAdded();
3684}
3685
3687{
3688 if ( eMode == SC_INPUT_NONE )
3689 {
3690 OSL_FAIL("ClearText, not during input mode");
3691 return;
3692 }
3693
3695 if (!pTableView && !pTopView)
3696 return; // E.g. FillMode
3697
3698 DataChanging(); // Cannot be new
3699
3700 if (pTableView)
3701 {
3703 pTableView->SetSelection( ESelection(0,0, 0,0) );
3704 }
3705 if (pTopView)
3706 {
3707 pTopView->GetEditEngine()->SetText( "" );
3708 pTopView->SetSelection( ESelection(0,0, 0,0) );
3709 }
3710
3711 DataChanged();
3712}
3713
3714bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
3715{
3716 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3717 sal_uInt16 nModi = aCode.GetModifier();
3718 bool bShift = aCode.IsShift();
3719 bool bControl = aCode.IsMod1();
3720 bool bAlt = aCode.IsMod2();
3721 sal_uInt16 nCode = aCode.GetCode();
3722 sal_Unicode nChar = rKEvt.GetCharCode();
3723
3724 if (bAlt && !bControl && nCode != KEY_RETURN)
3725 // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3726 return false;
3727
3728 // There is a partial autocomplete suggestion.
3729 // Allow its completion with right arrow key (without modifiers).
3730 if (mbPartialPrefix && nCode == KEY_RIGHT && !bControl && !bShift && !bAlt &&
3731 (pTopView || pTableView))
3732 {
3733 if (pTopView)
3734 pTopView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
3735 if (pTableView)
3736 pTableView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
3737
3738 mbPartialPrefix = false;
3739
3740 // Indicate that this event has been consumed and ScTabViewShell should not act on this.
3741 return true;
3742 }
3743
3744 if (!bControl && nCode == KEY_TAB)
3745 {
3746 // Normal TAB moves the cursor right.
3747 EnterHandler();
3748
3749 if (pActiveViewSh)
3750 pActiveViewSh->FindNextUnprot( bShift, true );
3751 return true;
3752 }
3753
3754 bool bInputLine = ( eMode==SC_INPUT_TOP );
3755
3756 bool bUsed = false;
3757 bool bSkip = false;
3758 bool bDoEnter = false;
3759
3760 switch ( nCode )
3761 {
3762 case KEY_RETURN:
3763 // New line when in the input line and Shift/Ctrl-Enter is pressed,
3764 // or when in a cell and Ctrl-Enter is pressed.
3765 if ((pInputWin && bInputLine && bControl != bShift) || (!bInputLine && bControl && !bShift))
3766 {
3767 bDoEnter = true;
3768 }
3769 else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3770 {
3772 bUsed = true;
3773 }
3774 else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3775 {
3777 bUsed = true;
3778 }
3779 else
3780 {
3782 if ( bShift && bControl )
3783 nMode = ScEnterMode::MATRIX;
3784 else if ( bAlt )
3785 nMode = ScEnterMode::BLOCK;
3786 EnterHandler( nMode );
3787
3788 if (pActiveViewSh)
3789 pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3790
3791 bUsed = true;
3792 }
3793 break;
3794 case KEY_TAB:
3795 if (bControl && !bAlt)
3796 {
3798 {
3799 // Iterate
3800 NextFormulaEntry( bShift );
3801 bUsed = true;
3802 }
3803 else if (pColumnData && bUseTab)
3804 {
3805 // Iterate through AutoInput entries
3806 NextAutoEntry( bShift );
3807 bUsed = true;
3808 }
3809 }
3810 break;
3811 case KEY_ESCAPE:
3812 if ( nTipVisible )
3813 {
3814 HideTip();
3815 bUsed = true;
3816 }
3817 else if( nTipVisibleSec )
3818 {
3819 HideTipBelow();
3820 bUsed = true;
3821 }
3822 else if (eMode != SC_INPUT_NONE)
3823 {
3824 CancelHandler();
3825 bUsed = true;
3826 }
3827 else
3828 bSkip = true;
3829 break;
3830 case KEY_F2:
3831 if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3832 {
3834 bUsed = true;
3835 }
3836 break;
3837 }
3838
3839 // Only execute cursor keys if already in EditMode
3840 // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3841 bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3842 bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3843 if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3844 ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3845 {
3846 HideTip();
3847 HideTipBelow();
3848
3849 if (bSelIsRef)
3850 {
3852 bSelIsRef = false;
3853 }
3854
3856 bool bNewView = DataChanging( nChar );
3857
3858 if (bProtected) // Protected cell?
3859 bUsed = true; // Don't forward KeyEvent
3860 else // Changes allowed
3861 {
3862 if (bNewView ) // Create anew
3863 {
3864 if (pActiveViewSh)
3867 if (eMode==SC_INPUT_NONE)
3868 if (pTableView || pTopView)
3869 {
3870 OUString aStrLoP;
3871
3872 if (bStartEdit && nCellPercentFormatDecSep != 0 &&
3873 ((nChar >= '0' && nChar <= '9') || nChar == '-' || nChar == nCellPercentFormatDecSep))
3874 {
3875 aStrLoP = "%";
3876 }
3877
3878 if (pTableView)
3879 {
3880 pTableView->GetEditEngine()->SetText( aStrLoP );
3881 if ( !aStrLoP.isEmpty() )
3882 pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3883
3884 // Don't call SetSelection if the string is empty anyway,
3885 // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3886 }
3887 if (pTopView)
3888 {
3889 pTopView->GetEditEngine()->SetText( aStrLoP );
3890 if ( !aStrLoP.isEmpty() )
3891 pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3892 }
3893 }
3894 SyncViews();
3895 }
3896
3897 if (pTableView || pTopView)
3898 {
3899 if (bDoEnter)
3900 {
3901 if (pTableView)
3903 bUsed = true;
3904 if (pTopView)
3906 bUsed = true;
3907 }
3908 else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3909 {
3911 bUsed = true;
3912 }
3913 else
3914 {
3915 if (pTableView)
3916 {
3917 if (pTopView)
3918 pTableView->SetControlWord(pTableView->GetControlWord() | EVControlBits::SINGLELINEPASTE);
3919
3920 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
3921 if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3922 bUsed = true;
3923
3924 pTableView->SetControlWord(pTableView->GetControlWord() & ~EVControlBits::SINGLELINEPASTE);
3925 }
3926 if (pTopView)
3927 {
3928 if ( bUsed && rKEvt.GetKeyCode().GetFunction() == KeyFuncType::CUT )
3930 else if ( pTopView->PostKeyEvent( rKEvt ) )
3931 bUsed = true;
3932 }
3933 }
3934
3935 // AutoInput:
3936 if ( bUsed && SC_MOD()->GetAppOptions().GetAutoComplete() )
3937 {
3938 bUseTab = false;
3939 if (pFormulaData)
3940 miAutoPosFormula = pFormulaData->end(); // do not search further
3941 if (pColumnData)
3943
3944 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3945 if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3946 KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
3947 {
3948 if (bFormulaMode)
3950 else
3951 UseColData();
3952 }
3953 }
3954
3955 // When the selection is changed manually or an opening parenthesis
3956 // is typed, stop overwriting parentheses
3957 if ( bUsed && nChar == '(' )
3958 ResetAutoPar();
3959
3960 if ( KEY_INSERT == nCode )
3961 {
3962 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3963 if (pViewFrm)
3964 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3965 }
3966 if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3967 {
3968 ShowTipCursor();
3969 }
3970 if( bUsed && bFormulaMode && nCode == KEY_BACKSPACE )
3971 {
3973 }
3974
3975 }
3976
3977 // #i114511# don't count cursor keys as modification
3978 bool bSetModified = !bCursorKey;
3979 DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3980
3981 // In the LOK case, we want to set the document modified state
3982 // right away at the start of the edit, so that the content is
3983 // saved even when the user leaves the document before hitting
3984 // Enter
3987
3989 }
3990 }
3991
3992 if (pTopView && eMode != SC_INPUT_NONE)
3993 SyncViews();
3994
3995 return bUsed;
3996}
3997
3999{
4000 if (eMode != SC_INPUT_NONE)
4001 {
4003 if (pTableView || pTopView)
4004 {
4005 if (pTableView)
4007 else if (pTopView) // call only once
4008 return pTopView->GetSurroundingText();
4009 }
4010 }
4011 return OUString();
4012}
4013
4015{
4016 if (eMode != SC_INPUT_NONE)
4017 {
4019 if (pTableView || pTopView)
4020 {
4021 if (pTableView)
4023 else if (pTopView) // call only once
4025 }
4026 }
4027 return Selection(0, 0);
4028}
4029
4031{
4032 if (eMode != SC_INPUT_NONE)
4033 {
4035 if (pTableView || pTopView)
4036 {
4037 if (pTableView)
4038 return pTableView->DeleteSurroundingText(rSelection);
4039 else if (pTopView) // call only once
4040 return pTopView->DeleteSurroundingText(rSelection);
4041 }
4042 }
4043 return false;
4044}
4045
4047{
4048 if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
4049 {
4050 // For CommandEventId::CursorPos, do as little as possible, because
4051 // with remote VCL, even a ShowCursor will generate another event.
4052 if ( eMode != SC_INPUT_NONE )
4053 {
4055 if (pTableView || pTopView)
4056 {
4057 if (pTableView)
4058 pTableView->Command( rCEvt );
4059 else if (pTopView) // call only once
4060 pTopView->Command( rCEvt );
4061 }
4062 }
4063 }
4064 else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
4065 {
4066 if ( eMode != SC_INPUT_NONE )
4067 {
4069 if (pTableView || pTopView)
4070 {
4071 if (pTableView)
4072 pTableView->Command( rCEvt );
4073 else if (pTopView) // call only once
4074 pTopView->Command( rCEvt );
4075 }
4076 }
4077 }
4078 else
4079 {
4080 HideTip();
4081 HideTipBelow();
4082
4083 if ( bSelIsRef )
4084 {
4086 bSelIsRef = false;
4087 }
4088
4090 bool bNewView = DataChanging( 0, true );
4091
4092 if (!bProtected) // changes allowed
4093 {
4094 if (bNewView) // create new edit view
4095 {
4096 if (pActiveViewSh)
4099 if (eMode==SC_INPUT_NONE)
4100 if (pTableView || pTopView)
4101 {
4102 if (pTableView)
4103 {
4105 pTableView->SetSelection( ESelection(0,0, 0,0) );
4106 }
4107 if (pTopView)
4108 {
4109 pTopView->GetEditEngine()->SetText( "" );
4110 pTopView->SetSelection( ESelection(0,0, 0,0) );
4111 }
4112 }
4113 SyncViews();
4114 }
4115
4116 if (pTableView || pTopView)
4117 {
4118 if (pTableView)
4119 pTableView->Command( rCEvt );
4120 if (pTopView)
4121 pTopView->Command( rCEvt );
4122
4123 if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
4124 {
4125 // AutoInput after ext text input
4126
4127 if (pFormulaData)
4129 if (pColumnData)
4131
4132 if (bFormulaMode)
4134 else
4135 UseColData();
4136 }
4137 }
4138
4139 DataChanged(); // calls UpdateParenthesis()
4141 }
4142
4143 if (pTopView && eMode != SC_INPUT_NONE)
4144 SyncViews();
4145 }
4146}
4147
4149 bool bForce, ScTabViewShell* pSourceSh,
4150 bool bStopEditing)
4151{
4152 // If the call originates from a macro call in the EnterHandler,
4153 // return immediately and don't mess up the status
4154 if (bInEnterHandler)
4155 return;
4156
4157 bool bRepeat = (pState == pLastState.get());
4158 if (!bRepeat && pState && pLastState)
4159 bRepeat = (*pState == *pLastState);
4160 if (bRepeat && !bForce)
4161 return;
4162
4163 bInOwnChange = true; // disable ModifyHdl (reset below)
4164
4165 if ( pState && !pLastState ) // Enable again
4166 bForce = true;
4167
4168 bool bHadObject = pLastState && pLastState->GetEditData();
4169
4171 if ( pSourceSh )
4172 pActiveViewSh = pSourceSh;
4173 else
4175
4177
4178 if ( pState != pLastState.get() )
4179 {
4180 pLastState.reset( pState ? new ScInputHdlState( *pState ) : nullptr);
4181 }
4182
4183 if ( pState && pActiveViewSh )
4184 {
4185 ScModule* pScMod = SC_MOD();
4186
4187 ScTabViewShell* pScTabViewShell = dynamic_cast<ScTabViewShell*>(pScMod->GetViewShell());
4188
4189 // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
4190 // FormEditData, if we're switching from Help to Calc:
4191 if ( !bFormulaMode && !pScMod->IsFormulaMode() &&
4192 ( !pScTabViewShell || !pScTabViewShell->GetFormEditData() ) )
4193 {
4194 bool bIgnore = false;
4195 if ( bModified )
4196 {
4197 if (pState->GetPos() != aCursorPos)
4198 {
4199 if (!bProtected)
4200 EnterHandler();
4201 }
4202 else
4203 bIgnore = true;
4204 }
4205
4206 if ( !bIgnore )
4207 {
4208 const ScAddress& rSPos = pState->GetStartPos();
4209 const ScAddress& rEPos = pState->GetEndPos();
4210 const EditTextObject* pData = pState->GetEditData();
4211 OUString aString = pState->GetString();
4212 bool bTxtMod = false;
4214 ScDocument& rDoc = pDocSh->GetDocument();
4215
4216 aCursorPos = pState->GetPos();
4217
4218 if ( pData )
4219 bTxtMod = true;
4220 else if ( bHadObject )
4221 bTxtMod = true;
4222 else if ( bTextValid )
4223 bTxtMod = ( aString != aCurrentText );
4224 else
4225 bTxtMod = ( aString != GetEditText(mpEditEngine.get()) );
4226
4227 if ( bTxtMod || bForce )
4228 {
4229 if (pData)
4230 {
4231 mpEditEngine->SetTextCurrentDefaults( *pData );
4232 if (pInputWin)
4234 else
4235 aString = GetEditText(mpEditEngine.get());
4236 lcl_RemoveTabs(aString);
4237 bTextValid = false;
4238 aCurrentText.clear();
4239 }
4240 else
4241 {
4242 aCurrentText = aString;
4243 bTextValid = true;
4244 }
4245
4246 if ( pInputWin )
4247 pInputWin->SetTextString(aString);
4248
4250 {
4251 EditView* pActiveView = pTopView ? pTopView : pTableView;
4252 ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
4253
4254 // if we switched content completely - don't send huge numbers
4255 if (aSel.nStartPara == EE_PARA_NOT_FOUND)
4256 aSel.nStartPara = 0;
4257
4258 if (aSel.nEndPara == EE_PARA_NOT_FOUND)
4259 aSel.nEndPara = 0;
4260
4261 ScInputHandler::LOKSendFormulabarUpdate(pActiveView, pActiveViewSh, aString, aSel);
4262 // TODO: deprecated?
4263 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aString.toUtf8().getStr());
4264 }
4265 }
4266
4267 if ( pInputWin || comphelper::LibreOfficeKit::isActive()) // Named range input
4268 {
4269 OUString aPosStr;
4270 bool bSheetLocal = false;
4271 const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
4272
4273 // Is the range a name?
4275 if ( pActiveViewSh )
4277 GetRangeAtBlock( ScRange( rSPos, rEPos ), aPosStr, &bSheetLocal);
4278
4279 if ( aPosStr.isEmpty() ) // Not a name -> format
4280 {
4282 if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
4284 if ( rSPos != rEPos )
4285 {
4286 ScRange r(rSPos, rEPos);
4287 applyStartToEndFlags(nFlags);
4288 aPosStr = r.Format(rDoc, ScRefFlags::VALID | nFlags, aAddrDetails);
4289 }
4290 else
4291 aPosStr = aCursorPos.Format(ScRefFlags::VALID | nFlags, &rDoc, aAddrDetails);
4292 }
4293 else if (bSheetLocal)
4294 {
4295 OUString aName;
4296 if (rDoc.GetName( rSPos.Tab(), aName))
4297 aPosStr = ScPosWnd::createLocalRangeName( aPosStr, aName);
4298 }
4299
4300 if (pInputWin)
4301 {
4302 // Disable the accessible VALUE_CHANGE event
4303 bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
4304 pInputWin->SetAccessibilityEventsSuppressed(true);
4305 pInputWin->SetPosString(aPosStr);
4306 pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
4307 pInputWin->SetSumAssignMode();
4308 }
4309
4311 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_ADDRESS, aPosStr.toUtf8().getStr());
4312 }
4313
4314 if (bStopEditing) {
4315 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
4316
4317 // As long as the content is not edited, turn off online spelling.
4318 // Online spelling is turned back on in StartTable, after setting
4319 // the right language from cell attributes.
4320
4321 EEControlBits nCntrl = mpEditEngine->GetControlWord();
4322 if ( nCntrl & EEControlBits::ONLINESPELLING )
4323 mpEditEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
4324 }
4325
4326 bModified = false;
4327 bSelIsRef = false;
4328 bProtected = false;
4329 bCommandErrorShown = false;
4330 }
4331 }
4332
4333 if ( pInputWin)
4334 {
4335 // Do not enable if RefDialog is open
4336 if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
4337 {
4338 if ( !pInputWin->IsEnabled())
4339 {
4340 pDelayTimer->Stop();
4341 pInputWin->Enable();
4342 }
4343 }
4344 else if(pScMod->IsRefDialogOpen())
4345 { // Because every document has its own InputWin,
4346 // we should start Timer again, because the input line may
4347 // still be active
4348 if ( !pDelayTimer->IsActive() )
4349 pDelayTimer->Start();
4350 }
4351 }
4352 }
4353 else // !pState || !pActiveViewSh
4354 {
4355 if ( !pDelayTimer->IsActive() )
4356 pDelayTimer->Start();
4357 }
4358
4359 HideTip();
4360 HideTipBelow();
4361 bInOwnChange = false;
4362}
4363
4365{
4366 eAttrAdjust = eJust;
4367 UpdateAdjust( 0 );
4368}
4369
4371{
4372 if( pDelayTimer->IsActive() )
4373 {
4374 pDelayTimer->Stop();
4375 if ( pInputWin )
4376 pInputWin->Enable();
4377 }
4378}
4379
4381{
4382 if ( !(nullptr == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen()))
4383 return;
4384
4386 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
4387 if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
4388 {
4389 if ( pInputWin)
4390 {
4391 pInputWin->EnableButtons( false );
4392 pInputWin->Disable();
4393 }
4394 }
4395 else if ( !bFormulaMode ) // Keep formula e.g. for help
4396 {
4397 bInOwnChange = true; // disable ModifyHdl (reset below)
4398
4399 pActiveViewSh = nullptr;
4400 mpEditEngine->SetTextCurrentDefaults( OUString() );
4401 if ( pInputWin )
4402 {
4403 pInputWin->SetPosString( OUString() );
4404 pInputWin->SetTextString( OUString() );
4405 pInputWin->Disable();
4406 }
4407
4408 bInOwnChange = false;
4409 }
4410}
4411
4413{
4414 SyncViews( pView );
4415 ShowTipCursor();
4416 UpdateParenthesis(); // Selection changed -> update parentheses highlighting
4417
4418 // When the selection is changed manually, stop overwriting parentheses
4419 ResetAutoPar();
4420
4422 {
4423 EditView* pActiveView = pTopView ? pTopView : pTableView;
4424 ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
4426 }
4427}
4428
4429void ScInputHandler::InputChanged( const EditView* pView, bool bFromNotify )
4430{
4431 if ( !pView )
4432 return;
4433
4435
4436 // #i20282# DataChanged needs to know if this is from the input line's modify handler
4437 bool bFromTopNotify = ( bFromNotify && pView == pTopView );
4438
4439 bool bNewView = DataChanging(); //FIXME: Is this at all possible?
4440 aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
4441 mpEditEngine->SetTextCurrentDefaults( aCurrentText );
4442 DataChanged( bFromTopNotify );
4443 bTextValid = true; // Is set to false in DataChanged
4444
4445 if ( pActiveViewSh )
4446 {
4447 ScViewData& rViewData = pActiveViewSh->GetViewData();
4448 if ( bNewView )
4449 rViewData.GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
4450
4451 rViewData.EditGrowY();
4452 rViewData.EditGrowX();
4453 }
4454
4455 SyncViews( pView );
4456}
4457
4459{
4460 if (mpEditEngine)
4461 {
4462 aCurrentText = mpEditEngine->GetText(); // Always new from Engine
4463 bTextValid = true;
4464 }
4465
4466 return aCurrentText;
4467}
4468
4470{
4471 Size aSize;
4472 if ( mpEditEngine )
4473 aSize = Size( mpEditEngine->CalcTextWidth(), mpEditEngine->GetTextHeight() );
4474
4475 return aSize;
4476}
4477
4479{
4480 bool bRet = false;
4481 if (mpEditEngine)
4482 {
4483 // Contains field?
4484 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
4485 SfxItemSet aSet = mpEditEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
4486 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
4487 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
4488 {
4489 // Copy content
4490 std::unique_ptr<EditTextObject> pObj = mpEditEngine->CreateTextObject();
4491 rDestEngine.SetTextCurrentDefaults(*pObj);
4492 pObj.reset();
4493
4494 // Delete attributes
4495 for (sal_Int32 i=0; i<nParCnt; i++)
4496 rDestEngine.RemoveCharAttribs( i );
4497
4498 // Combine paragraphs
4499 while ( nParCnt > 1 )
4500 {
4501 sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
4502 ESelection aSel( 0,nLen, 1,0 );
4503 rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
4504 --nParCnt;
4505 }
4506
4507 bRet = true;
4508 }
4509 }
4510 return bRet;
4511}
4512
4517void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
4518{
4519 rStart = nFormSelStart;
4520 rEnd = nFormSelEnd;
4521}
4522
4524{
4525 UpdateActiveView(); // Due to pTableView
4526
4527 EditView* pView = nullptr;
4528 if ( pInputWin )
4529 {
4530 pInputWin->MakeDialogEditView();
4531 pView = pInputWin->GetEditView();
4532 }
4533 else
4534 {
4535 if ( eMode != SC_INPUT_TABLE )
4536 {
4537 bCreatingFuncView = true; // Don't display RangeFinder
4539 bCreatingFuncView = false;
4540 if ( pTableView )
4541 pTableView->GetEditEngine()->SetText( OUString() );
4542 }
4543 pView = pTableView;
4544 }
4545
4546 return pView;
4547}
4548
4549void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
4550{
4551 if ( nStart <= nEnd )
4552 {
4553 nFormSelStart = nStart;
4554 nFormSelEnd = nEnd;
4555 }
4556 else
4557 {
4558 nFormSelEnd = nStart;
4559 nFormSelStart = nEnd;
4560 }
4561
4562 EditView* pView = GetFuncEditView();
4563 if (pView)
4564 pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
4565
4566 bModified = true;
4567}
4568
4569void ScInputHandler::InputReplaceSelection( std::u16string_view aStr )
4570{
4571 if (!pRefViewSh)
4573
4574 OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
4575
4576 sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
4577 sal_Int32 nNewLen = aStr.size();
4578
4579 OUStringBuffer aBuf(aFormText);
4580 if (nOldLen)
4581 aBuf.remove(nFormSelStart, nOldLen);
4582 if (nNewLen)
4583 aBuf.insert(nFormSelStart, aStr);
4584
4585 aFormText = aBuf.makeStringAndClear();
4586
4587 nFormSelEnd = nFormSelStart + nNewLen;
4588
4589 EditView* pView = GetFuncEditView();
4590 if (pView)
4591 {
4592 pView->SetEditEngineUpdateLayout( false );
4593 pView->GetEditEngine()->SetText( aFormText );
4595 pView->SetEditEngineUpdateLayout( true );
4596 }
4597 bModified = true;
4598}
4599
4601{
4602 bInOwnChange = true; // disable ModifyHdl (reset below)
4603
4605 /* TODO: it would be better if there was some way to reset the input bar
4606 * engine instead of deleting and having it recreate through
4607 * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
4608 * fdo#72278 without reintroducing fdo#69971. */
4609 StopInputWinEngine(true);
4610
4611 bInOwnChange = false;
4612}
4613
4618 const ScAddress& rStartPos,
4619 const ScAddress& rEndPos,
4620 OUString _aString,
4621 const EditTextObject* pData )
4622 : aCursorPos ( rCurPos ),
4623 aStartPos ( rStartPos ),
4624 aEndPos ( rEndPos ),
4625 aString (std::move( _aString )),
4626 pEditData ( pData ? pData->Clone() : nullptr )
4627{
4628}
4629
4631{
4632 *this = rCpy;
4633}
4634
4636{
4637}
4638
4640{
4641 return ( (aStartPos == r.aStartPos)
4642 && (aEndPos == r.aEndPos)
4643 && (aCursorPos == r.aCursorPos)
4644 && (aString == r.aString)
4645 && ScGlobal::EETextObjEqual( pEditData.get(), r.pEditData.get() ) );
4646}
4647
4649{
4650 if (this != &r)
4651 {
4653 aStartPos = r.aStartPos;
4654 aEndPos = r.aEndPos;
4655 aString = r.aString;
4656 pEditData.reset();
4657 if (r.pEditData)
4658 pEditData = r.pEditData->Clone();
4659 }
4660 return *this;
4661}
4662
4663/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScRefFlags
Definition: address.hxx:158
void applyStartToEndFlags(ScRefFlags &target, const ScRefFlags source)
Definition: address.hxx:196
const SCCOL MAXCOL
Definition: address.hxx:69
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:150
SfxApplication * SfxGetpApp()
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
bool isLetterNumeric(const OUString &rStr, sal_Int32 nPos) const
bool IsTransparent() const
CommandEventId GetCommand() const
void QuickFormatDoc(bool bFull=false)
OUString GetText(LineEnd eEnd=LINEEND_LF) const
void SetText(const OUString &rStr)
void RemoveCharAttribs(sal_Int32 nPara, sal_uInt16 nWhich=0, bool bRemoveFeatures=false)
sal_Int32 GetParagraphCount() const
sal_Int32 GetTextLen() const
static rtl::Reference< SfxItemPool > CreatePool()
static bool DoesKeyMoveCursor(const KeyEvent &rKeyEvent)
void QuickInsertText(const OUString &rText, const ESelection &rSel)
static bool DoesKeyChangeText(const KeyEvent &rKeyEvent)
bool DeleteSurroundingText(const Selection &rRange)
void SetControlWord(EVControlBits nWord)
OUString GetSurroundingText() const
void RemoveCharAttribs(sal_Int32 nPara, sal_uInt16 nWhich)
ESelection GetSelection() const
void SelectCurrentWord(sal_Int16 nWordType=css::i18n::WordType::ANYWORD_IGNOREWHITESPACES)
void RegisterViewShell(OutlinerViewShell *pViewShell)
Selection GetSurroundingTextSelection() const
bool HasSelection() const
void SetSelection(const ESelection &rNewSel)
void InsertText(const OUString &rNew, bool bSelect=false, bool bLOKShowSelect=true)
bool PostKeyEvent(const KeyEvent &rKeyEvent, vcl::Window const *pFrameWin=nullptr)
sal_Int32 GetPosWithField(sal_Int32 nPara, sal_Int32 nPos) const
void ShowCursor(bool bGotoCursor=true, bool bForceVisCursor=true, bool bActivate=false)
vcl::Cursor * GetCursor() const
vcl::Window * GetWindow() const
void DeleteSelected()
EVControlBits GetControlWord() const
void CompleteAutoCorrect(vcl::Window const *pFrameWin=nullptr)
bool Command(const CommandEvent &rCEvt)
EditEngine * GetEditEngine() const
OUString GetSelected() const
bool SetEditEngineUpdateLayout(bool bUpdate)
static void * ShowPopover(vcl::Window *pParent, const tools::Rectangle &rScreenRect, const OUString &rText, QuickHelpFlags nStyle)
static void HidePopover(vcl::Window const *pParent, void *nId)
OUString GetMainURL(DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8) const
sal_Unicode GetCharCode() const
const vcl::KeyCode & GetKeyCode() const
static css::uno::Reference< css::linguistic2::XSpellChecker1 > GetSpellChecker()
static css::uno::Reference< css::linguistic2::XHyphenator > GetHyphenator()
const OUString & getDoubleQuotationMarkStart() const
const OUString & getQuotationMarkStart() const
const OUString & getDoubleQuotationMarkEnd() const
const OUString & getQuotationMarkEnd() const
SCTAB Tab() const
Definition: address.hxx:283
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2074
SCROW Row() const
Definition: address.hxx:274
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
sal_uInt16 GetLRUFuncListCount() const
Definition: appoptio.hxx:47
sal_uInt16 * GetLRUFuncList() const
Definition: appoptio.hxx:48
bool GetAutoComplete() const
Definition: appoptio.hxx:54
void DataPilotInput(const ScAddress &rPos, const OUString &rString)
Definition: dbfunc3.cxx:1382
bool IsAutoSpell() const
Definition: docoptio.hxx:53
virtual void SetModified(bool=true) override
Definition: docsh.cxx:2968
const ScDocument & GetDocument() const
Definition: docsh.hxx:220
void PostEditView(ScEditEngineDefaulter *pEditEngine, const ScAddress &rCursorPos)
Definition: docsh3.cxx:79
SC_DLLPUBLIC SfxItemPool * GetEnginePool() const
Definition: documen2.cxx:478
SC_DLLPUBLIC bool ExtendMerge(SCCOL nStartCol, SCROW nStartRow, SCCOL &rEndCol, SCROW &rEndRow, SCTAB nTab, bool bRefresh=false)
Definition: document.cxx:5687
EEHorizontalTextDirection GetEditTextDirection(SCTAB nTab) const
Definition: documen8.cxx:355
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uInt32 nIndex) const
Definition: documen4.cxx:881
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6181
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:500
void FillInfo(ScTableInfo &rTabInfo, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, double fColScale, double fRowScale, bool bPageMode, bool bFormulaMode, const ScMarkData *pMarkData=nullptr)
Definition: fillinfo.cxx:354
SC_DLLPUBLIC SfxItemPool * GetEditPool() const
Definition: documen2.cxx:473
void GetDataEntries(SCCOL nCol, SCROW nRow, SCTAB nTab, std::vector< ScTypedStrData > &rStrings, bool bValidation=false)
Entries for selection list listbox (no numbers/formulas)
Definition: documen3.cxx:1633
SC_DLLPUBLIC ScDPObject * GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen3.cxx:383
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1082
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:899
void ApplyAsianEditSettings(ScEditEngineDefaulter &rEngine)
Definition: documen9.cxx:656
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC CellType GetCellType(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3793
SC_DLLPUBLIC bool IsLayoutRTL(SCTAB nTab) const
Definition: document.cxx:998
SfxPrinter * GetPrinter(bool bCreateIfNotExist=true)
Definition: documen8.cxx:114
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:217
SC_DLLPUBLIC sal_Unicode GetSheetSeparator() const
Obtain the sheet separator corresponding to the document's grammar.
Definition: documen4.cxx:1359
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4824
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1952
void GetFormulaEntries(ScTypedCaseStrSet &rStrings)
Entries for Formula auto input.
Definition: documen3.cxx:1673
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:616
void SetDefaultItem(const SfxPoolItem &rItem)
Set the item in the default ItemSet which is created if it doesn't exist yet.
Definition: editutil.cxx:595
static OUString ModifyDelimiters(const OUString &rOld)
Definition: editutil.cxx:65
static OUString GetMultilineString(const EditEngine &rEngine)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:109
void TestSelection(const ScDocument &rDoc, const ScMarkData &rMark)
Definition: editable.cxx:123
bool IsEditable() const
Definition: editable.hxx:84
TranslateId GetMessageId() const
Definition: editable.cxx:152
void TestSelectedBlock(const ScDocument &rDoc, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScMarkData &rMark)
Definition: editable.cxx:97
Stores and generates human readable descriptions for spreadsheet-functions, e.g. functions used in fo...
Definition: funcdesc.hxx:41
sal_uInt16 nFIndex
Unique function index.
Definition: funcdesc.hxx:221
std::optional< OUString > mxFuncName
Function name.
Definition: funcdesc.hxx:216
List of spreadsheet functions.
Definition: funcdesc.hxx:242
const ScFuncDesc * GetFunction(sal_uInt32 nIndex) const
Definition: funcdesc.cxx:1010
sal_uInt32 GetCount() const
Definition: funcdesc.hxx:247
static const sal_Unicode * UnicodeStrChr(const sal_Unicode *pStr, sal_Unicode c)
strchr() functionality on unicode, as long as we need it for FormulaToken etc.
Definition: global.cxx:689
static LanguageType GetEditDefaultLanguage()
Definition: global.cxx:907
static SC_DLLPUBLIC ::utl::TransliterationWrapper & GetTransliteration()
Definition: global.cxx:1024
static const InputHandlerFunctionNames & GetInputHandlerFunctionNames()
Definition: global.cxx:651
static SC_DLLPUBLIC LanguageType eLnge
Definition: global.hxx:559
static bool EETextObjEqual(const EditTextObject *pObj1, const EditTextObject *pObj2)
Definition: global.cxx:796
static ScFunctionList * GetStarCalcFunctionList()
Definition: global.cxx:624
static SC_DLLPUBLIC const LocaleDataWrapper & getLocaleData()
Definition: global.cxx:1053
static OUString GetErrorString(FormulaError nErrNumber)
Definition: global.cxx:315
static ScFunctionMgr * GetStarCalcFunctionMgr()
Definition: global.cxx:633
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1062
std::set< sal_Unicode > maFormulaChar
Definition: inputhdl.hxx:71
OUString aCurrentText
Definition: inputhdl.hxx:80
SvxCellHorJustify eAttrAdjust
Definition: inputhdl.hxx:112
void CancelHandler()
Definition: inputhdl.cxx:3429
void ForgetLastPattern()
Definition: inputhdl.cxx:2337
void SetReference(const ScRange &rRef, const ScDocument &rDoc)
Definition: inputhdl.cxx:3534
bool mbEditingExistingContent
Definition: inputhdl.hxx:109
bool KeyInput(const KeyEvent &rKEvt, bool bStartEdit)
Definition: inputhdl.cxx:3714
void * nTipVisibleSec
Definition: inputhdl.hxx:76
void SetDocumentDisposing(bool b)
Definition: inputhdl.cxx:601
EditView * GetFuncEditView()
Definition: inputhdl.cxx:4523
void InputCommand(const CommandEvent &rCEvt)
Definition: inputhdl.cxx:4046
void AddRefEntry()
Definition: inputhdl.cxx:3501
void ShowArgumentsTip(OUString &rSelText)
Definition: inputhdl.cxx:1111
std::unique_ptr< ScInputHdlState > pLastState
Definition: inputhdl.hxx:125
void ViewShellGone(const ScTabViewShell *pViewSh)
Definition: inputhdl.cxx:2235
void UpdateSpellSettings(bool bFromStartTab=false)
Definition: inputhdl.cxx:943
void InputTurnOffWinEngine()
Definition: inputhdl.cxx:4600
ScInputMode eMode
Definition: inputhdl.hxx:91
static void LOKSendFormulabarUpdate(EditView *pEditView, const SfxViewShell *pActiveViewSh, const OUString &rText, const ESelection &rSelection)
Definition: inputhdl.cxx:1784
OUString aAutoSearch
Definition: inputhdl.hxx:78
void ShowTip(const OUString &rText)
Definition: inputhdl.cxx:1294
void FormulaPreview()
Definition: inputhdl.cxx:1875
Fraction aScaleX
Definition: inputhdl.hxx:114
ScTabViewShell * pActiveViewSh
Definition: inputhdl.hxx:118
void UpdateAdjust(sal_Unicode cTyped)
Definition: inputhdl.cxx:2346
Size GetTextSize()
Definition: inputhdl.cxx:4469
bool bFormulaMode
Definition: inputhdl.hxx:96
bool GetFuncName(OUString &aStart, OUString &aResult)
Definition: inputhdl.cxx:1357
void ResetDelayTimer()
Definition: inputhdl.cxx:4370
void PasteManualTip()
Definition: inputhdl.cxx:1899
static void SendReferenceMarks(const SfxViewShell *pViewShell, const std::vector< ReferenceMark > &rReferenceMarks)
Definition: inputhdl.cxx:306
bool GetTextAndFields(ScEditEngineDefaulter &rDestEngine)
Definition: inputhdl.cxx:4478
sal_uLong nValidation
Definition: inputhdl.hxx:111
void NotifyChange(const ScInputHdlState *pState, bool bForce=false, ScTabViewShell *pSourceSh=nullptr, bool bStopEditing=true)
Definition: inputhdl.cxx:4148
bool bLastIsSymbol
Definition: inputhdl.hxx:105
void ShowFuncList(const ::std::vector< OUString > &rFuncStrVec)
Definition: inputhdl.cxx:1401
bool StartTable(sal_Unicode cTyped, bool bFromCommand, bool bInputActivated, ScEditEngineDefaulter *pTopEngine)
Definition: inputhdl.cxx:2428
bool bCreatingFuncView
Definition: inputhdl.hxx:99
void ShowTipCursor()
Definition: inputhdl.cxx:1269
void UpdateRange(sal_uInt16 nIndex, const ScRange &rNew)
Definition: inputhdl.cxx:628
void UseFormulaData()
Definition: inputhdl.cxx:1519
static void InvalidateAttribs()
Definition: inputhdl.cxx:2901
void UpdateCellAdjust(SvxCellHorJustify eJust)
Definition: inputhdl.cxx:4364
std::unique_ptr< ScEditEngineDefaulter > mpEditEngine
Edited data in the sheet (when the user clicks into the sheet, and starts writing there).
Definition: inputhdl.hxx:62
sal_uInt16 nAutoPar
Definition: inputhdl.hxx:88
void HideTipBelow()
Definition: inputhdl.cxx:1089
void DeleteRangeFinder()
Definition: inputhdl.cxx:680
void ResetAutoPar()
Definition: inputhdl.cxx:1958
OUString aFormText
Definition: inputhdl.hxx:82
ScAddress aCursorPos
Definition: inputhdl.hxx:90