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();
881 bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
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 OUString& rText,
1786 const ESelection& rSelection)
1787{
1788 OUString aSelection =
1789 OUString::number(rSelection.nStartPos) + ";" + OUString::number(rSelection.nEndPos) + ";" +
1790 OUString::number(rSelection.nStartPara) + ";" + OUString::number(rSelection.nEndPara);
1791
1792 std::unique_ptr<jsdialog::ActionDataMap> pData = std::make_unique<jsdialog::ActionDataMap>();
1793 (*pData)["action_type"] = "setText";
1794 (*pData)["text"] = rText;
1795 (*pData)["selection"] = aSelection;
1796
1797 sal_uInt64 nCurrentShellId = reinterpret_cast<sal_uInt64>(pActiveViewSh);
1798 std::string sWindowId = std::to_string(nCurrentShellId) + "formulabar";
1799 jsdialog::SendAction(sWindowId, "sc_input_window", std::move(pData));
1800}
1801
1802// Calculate selection and display as tip help
1803static OUString lcl_Calculate( const OUString& rFormula, ScDocument& rDoc, const ScAddress &rPos )
1804{
1805 //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1806 // Quotation marks for Strings are only inserted here.
1807
1808 if(rFormula.isEmpty())
1809 return OUString();
1810
1811 std::optional<ScSimpleFormulaCalculator> pCalc( std::in_place, rDoc, rPos, rFormula, false );
1812
1813 // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1814 // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1815 bool bColRowName = pCalc->HasColRowName();
1816 if ( bColRowName )
1817 {
1818 // ColRowName in RPN code?
1819 if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1820 { // ==1: Single one is as a Parameter always a Range
1821 // ==0: It might be one, if ...
1822 OUString aBraced = "(" + rFormula + ")";
1823 pCalc.emplace( rDoc, rPos, aBraced, false );
1824 }
1825 else
1826 bColRowName = false;
1827 }
1828
1829 FormulaError nErrCode = pCalc->GetErrCode();
1830 if ( nErrCode != FormulaError::NONE )
1831 return ScGlobal::GetErrorString(nErrCode);
1832
1833 SvNumberFormatter& aFormatter = *rDoc.GetFormatTable();
1834 OUString aValue;
1835 if ( pCalc->IsValue() )
1836 {
1837 double n = pCalc->GetValue();
1838 sal_uInt32 nFormat = aFormatter.GetStandardFormat( n, 0,
1839 pCalc->GetFormatType(), ScGlobal::eLnge );
1840 aFormatter.GetInputLineString( n, nFormat, aValue );
1842 }
1843 else
1844 {
1845 OUString aStr = pCalc->GetString().getString();
1846 sal_uInt32 nFormat = aFormatter.GetStandardFormat(
1847 pCalc->GetFormatType(), ScGlobal::eLnge);
1848 {
1849 const Color* pColor;
1850 aFormatter.GetOutputString( aStr, nFormat,
1851 aValue, &pColor );
1852 }
1853
1854 aValue = "\"" + aValue + "\"";
1856 }
1857
1858 ScRange aTestRange;
1859 if ( bColRowName || (aTestRange.Parse(rFormula, rDoc) & ScRefFlags::VALID) )
1860 aValue += " ...";
1861
1862 return aValue;
1863}
1864
1866{
1867 OUString aValue;
1868 EditView* pActiveView = pTopView ? pTopView : pTableView;
1869 if ( pActiveView && pActiveViewSh )
1870 {
1871 OUString aPart = pActiveView->GetSelected();
1872 if (aPart.isEmpty())
1873 aPart = mpEditEngine->GetText(0);
1875 aValue = lcl_Calculate( aPart, rDoc, aCursorPos );
1876 }
1877
1878 if (!aValue.isEmpty())
1879 {
1880 ShowTip( aValue ); // Display as QuickHelp
1881 aManualTip = aValue; // Set after ShowTip
1882 if (pFormulaData)
1884 if (pColumnData)
1886 }
1887}
1888
1890{
1891 // Three dots at the end -> Range reference -> do not insert
1892 // FIXME: Once we have matrix constants, we can change this
1893 sal_Int32 nTipLen = aManualTip.getLength();
1894 sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1895 if ( nTipLen && ( nTipLen < 3 || aManualTip.subView( nTipLen2-3 ) != u"..." ) )
1896 {
1897 DataChanging(); // Cannot be new
1898
1899 OUString aInsert = aManualTip;
1900 EditView* pActiveView = pTopView ? pTopView : pTableView;
1901 if (!pActiveView->HasSelection())
1902 {
1903 // Nothing selected -> select everything
1904 sal_Int32 nOldLen = mpEditEngine->GetTextLen(0);
1905 ESelection aAllSel( 0, 0, 0, nOldLen );
1906 if ( pTopView )
1907 pTopView->SetSelection( aAllSel );
1908 if ( pTableView )
1909 pTableView->SetSelection( aAllSel );
1910 }
1911
1912 ESelection aSel = pActiveView->GetSelection();
1913 aSel.Adjust();
1914 OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1915 if ( !aSel.nStartPos ) // Selection from the start?
1916 {
1917 if ( aSel.nEndPos == mpEditEngine->GetTextLen(0) )
1918 {
1919 // Everything selected -> skip quotation marks
1920 if ( aInsert[0] == '"' )
1921 aInsert = aInsert.copy(1);
1922 sal_Int32 nInsLen = aInsert.getLength();
1923 if ( aInsert.endsWith("\"") )
1924 aInsert = aInsert.copy( 0, nInsLen-1 );
1925 }
1926 else if ( aSel.nEndPos )
1927 {
1928 // Not everything selected -> do not overwrite equality sign
1929 //FIXME: Even double equality signs??
1930 aSel.nStartPos = 1;
1931 if ( pTopView )
1932 pTopView->SetSelection( aSel );
1933 if ( pTableView )
1934 pTableView->SetSelection( aSel );
1935 }
1936 }
1937 if ( pTopView )
1938 pTopView->InsertText( aInsert, true );
1939 if ( pTableView )
1940 pTableView->InsertText( aInsert, true );
1941
1942 DataChanged();
1943 }
1944
1945 HideTip();
1946}
1947
1949{
1950 nAutoPar = 0;
1951}
1952
1954{
1955 ++nAutoPar; // Closing parenthesis can be overwritten
1956}
1957
1959{
1960 // Test if the cursor is before a closing parenthesis
1961 // Selection from SetReference has been removed before
1962 EditView* pActiveView = pTopView ? pTopView : pTableView;
1963 if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1964 {
1965 ESelection aSel = pActiveView->GetSelection();
1966 sal_Int32 nPos = aSel.nStartPos;
1967 OUString aFormula = mpEditEngine->GetText(0);
1968 if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1969 return true;
1970 }
1971 return false;
1972}
1973
1975{
1976 // this is called when a ')' is typed and the cursor is before a ')'
1977 // that can be overwritten -> just set the cursor behind the ')'
1978
1979 EditView* pActiveView = pTopView ? pTopView : pTableView;
1980 if (pActiveView)
1981 {
1982 ESelection aSel = pActiveView->GetSelection();
1983 ++aSel.nStartPos;
1984 ++aSel.nEndPos;
1985
1986 // this is in a formula (only one paragraph), so the selection
1987 // can be used directly for the TopView
1988
1989 if ( pTopView )
1990 pTopView->SetSelection( aSel );
1991 if ( pTableView )
1992 pTableView->SetSelection( aSel );
1993 }
1994
1995 OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
1996 --nAutoPar;
1997}
1998
1999// Auto input
2000
2002{
2003 if ( !pActiveViewSh )
2004 return;
2005
2007
2008 if ( pColumnData )
2009 pColumnData->clear();
2010 else
2011 pColumnData.reset( new ScTypedCaseStrSet );
2012
2013 std::vector<ScTypedStrData> aEntries;
2014 rDoc.GetDataEntries(
2016 if (!aEntries.empty())
2017 pColumnData->insert(aEntries.begin(), aEntries.end());
2018
2020}
2021
2022void ScInputHandler::UseColData() // When typing
2023{
2024 EditView* pActiveView = pTopView ? pTopView : pTableView;
2025 if ( !(pActiveView && pColumnData) )
2026 return;
2027
2028 // Only change when cursor is at the end
2029 ESelection aSel = pActiveView->GetSelection();
2030 aSel.Adjust();
2031
2032 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
2033 if ( aSel.nEndPara+1 != nParCnt )
2034 return;
2035
2036 sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
2037 if ( aSel.nEndPos != nParLen )
2038 return;
2039
2040 OUString aText = GetEditText(mpEditEngine.get());
2041 if (aText.isEmpty())
2042 return;
2043
2044 std::vector< OUString > aResultVec;
2045 OUString aNew;
2046 sal_Int32 nLongestPrefixLen = 0;
2048 mbPartialPrefix = false;
2049 miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, &nLongestPrefixLen);
2050
2051 if (nLongestPrefixLen <= 0 || aResultVec.empty())
2052 return;
2053
2054 if (aResultVec.size() > 1)
2055 {
2056 mbPartialPrefix = true;
2057 bUseTab = true; // Allow Ctrl (+ Shift + ) + TAB cycling.
2059
2060 // Display the rest of longest common prefix as suggestion.
2061 aNew = aResultVec[0].copy(0, nLongestPrefixLen);
2062 }
2063 else
2064 {
2065 aNew = aResultVec[0];
2066 }
2067
2068 // Strings can contain line endings (e.g. due to dBase import),
2069 // which would result in multiple paragraphs here, which is not desirable.
2071 lcl_RemoveLineEnd( aNew );
2072
2073 // Keep paragraph, just append the rest
2075 // One Space between paragraphs:
2076 sal_Int32 nEdLen = mpEditEngine->GetTextLen() + nParCnt - 1;
2077 OUString aIns = aNew.copy(nEdLen);
2078
2079 // Selection must be "backwards", so the cursor stays behind the last
2080 // typed character
2081 ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
2082 aSel.nEndPara, aSel.nEndPos );
2083
2084 // When editing in input line, apply to both edit views
2085 if ( pTableView )
2086 {
2087 pTableView->InsertText( aIns );
2088 pTableView->SetSelection( aSelection );
2089 }
2090 if ( pTopView )
2091 {
2092 pTopView->InsertText( aIns );
2093 pTopView->SetSelection( aSelection );
2094 }
2095
2096 aAutoSearch = aText; // To keep searching - nAutoPos is set
2097}
2098
2100{
2101 EditView* pActiveView = pTopView ? pTopView : pTableView;
2102 if ( pActiveView && pColumnData )
2103 {
2104 if (!aAutoSearch.isEmpty())
2105 {
2106 // Is the selection still valid (could be changed via the mouse)?
2107 ESelection aSel = pActiveView->GetSelection();
2108 aSel.Adjust();
2109 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
2110 if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
2111 {
2112 OUString aText = GetEditText(mpEditEngine.get());
2113 sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
2114 sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
2115 if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
2116 {
2117 OUString aNew;
2118 ScTypedCaseStrSet::const_iterator itNew =
2119 findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
2120
2121 if (itNew != pColumnData->end())
2122 {
2123 // match found!
2124 miAutoPosColumn = itNew;
2125 bInOwnChange = true; // disable ModifyHdl (reset below)
2126 mbPartialPrefix = false;
2127
2128 lcl_RemoveLineEnd( aNew );
2129 OUString aIns = aNew.copy(aAutoSearch.getLength());
2130
2131 // when editing in input line, apply to both edit views
2132 if ( pTableView )
2133 {
2135 pTableView->InsertText( aIns );
2137 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2138 aSel.nEndPara, aSel.nStartPos ) );
2139 }
2140 if ( pTopView )
2141 {
2143 pTopView->InsertText( aIns );
2145 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2146 aSel.nEndPara, aSel.nStartPos ) );
2147 }
2148
2149 bInOwnChange = false;
2150 }
2151 }
2152 }
2153 }
2154 }
2155
2156 // For Tab, HideCursor was always called first
2157 if (pActiveView)
2158 pActiveView->ShowCursor();
2159}
2160
2161// Highlight parentheses
2163{
2164 // Find parentheses
2165 //TODO: Can we disable parentheses highlighting per parentheses?
2166 bool bFound = false;
2167 if ( bFormulaMode && eMode != SC_INPUT_TOP )
2168 {
2169 if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
2170 {
2172 if (aSel.nStartPos)
2173 {
2174 // Examine character left to the cursor
2175 sal_Int32 nPos = aSel.nStartPos - 1;
2176 OUString aFormula = mpEditEngine->GetText(aSel.nStartPara);
2177 sal_Unicode c = aFormula[nPos];
2178 if ( c == '(' || c == ')' )
2179 {
2180 // Note this matches only within one paragraph.
2181 sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
2182 if ( nOther != -1 )
2183 {
2184 SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
2186
2189 {
2190 // Remove old highlighting
2191 sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2192 for (sal_Int32 i=0; i<nCount; i++)
2193 mpEditEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
2194 }
2195
2196 ESelection aSelThis( aSel.nStartPara, nPos, aSel.nStartPara, nPos+1);
2197 mpEditEngine->QuickSetAttribs( aSet, aSelThis );
2198 ESelection aSelOther( aSel.nStartPara, nOther, aSel.nStartPara, nOther+1);
2199 mpEditEngine->QuickSetAttribs( aSet, aSelOther );
2200
2201 // Dummy InsertText for Update and Paint (selection is empty)
2202 pTableView->InsertText( OUString() );
2203
2204 bFound = true;
2205 }
2206 }
2207 }
2208
2209 // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
2210 // with different color (COL_LIGHTBLUE) ??
2211 }
2212 }
2213
2214 // Remove old highlighting, if no new one is set
2215 if ( bParenthesisShown && !bFound && pTableView )
2216 {
2217 sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2218 for (sal_Int32 i=0; i<nCount; i++)
2220 }
2221
2222 bParenthesisShown = bFound;
2223}
2224
2225void ScInputHandler::ViewShellGone(const ScTabViewShell* pViewSh) // Executed synchronously!
2226{
2227 if ( pViewSh == pActiveViewSh )
2228 {
2229 pLastState.reset();
2230 pLastPattern = nullptr;
2231 }
2232
2233 if ( pViewSh == pRefViewSh )
2234 {
2236 // We end the EditMode anyways
2237 EnterHandler();
2238 bFormulaMode = false;
2239 pRefViewSh = nullptr;
2240 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2241 SC_MOD()->SetRefInputHdl(nullptr);
2242 if (pInputWin)
2243 pInputWin->SetFormulaMode(false);
2245 }
2246
2248
2249 if ( pActiveViewSh && pActiveViewSh == pViewSh )
2250 {
2251 OSL_FAIL("pActiveViewSh is gone");
2252 pActiveViewSh = nullptr;
2253 }
2254
2255 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
2256 UpdateRefDevice(); // Don't keep old document's printer as RefDevice
2257}
2258
2260{
2262
2263 // #i20588# Don't rely on focus to find the active edit view. Instead, the
2264 // active pane at the start of editing is now stored (GetEditActivePart).
2265 // GetActiveWin (the currently active pane) fails for ref input across the
2266 // panes of a split view.
2267
2268 vcl::Window* pShellWin = pActiveViewSh ?
2270 nullptr;
2271
2272 sal_uInt16 nCount = mpEditEngine->GetViewCount();
2273 if (nCount > 0)
2274 {
2275 pTableView = mpEditEngine->GetView();
2276 for (sal_uInt16 i=1; i<nCount; i++)
2277 {
2278 EditView* pThis = mpEditEngine->GetView(i);
2279 vcl::Window* pWin = pThis->GetWindow();
2280 if ( pWin==pShellWin )
2281 pTableView = pThis;
2282 }
2283 }
2284 else
2285 pTableView = nullptr;
2286
2287 // setup the pTableView editeng for tiled rendering to get cursor and selections
2289 {
2291 {
2293 }
2294 }
2295
2297 {
2298 // tdf#71409: Always create the edit engine instance for the input
2299 // window, in order to properly manage accessibility events.
2300 pTopView = pInputWin->GetEditView();
2301 if (eMode != SC_INPUT_TOP)
2302 pTopView = nullptr;
2303 }
2304 else
2305 pTopView = nullptr;
2306}
2307
2309{
2310 pInputWin = pNew;
2311}
2312
2314{
2315 if (pInputWin && !pInputWin->isDisposed())
2316 pInputWin->StopEditEngine( bAll );
2317
2318 pTopView = nullptr; // invalid now
2319}
2320
2322{
2324 return pTopView ? pTopView : pTableView;
2325}
2326
2328{
2329 pLastPattern = nullptr;
2330 if ( !pLastState && pActiveViewSh )
2331 pActiveViewSh->UpdateInputHandler( true ); // Get status again
2332 else
2333 NotifyChange( pLastState.get(), true );
2334}
2335
2337{
2338 SvxAdjust eSvxAdjust;
2339 switch (eAttrAdjust)
2340 {
2341 case SvxCellHorJustify::Standard:
2342 {
2343 bool bNumber = false;
2344 if (cTyped) // Restarted
2345 bNumber = (cTyped>='0' && cTyped<='9'); // Only ciphers are numbers
2346 else if ( pActiveViewSh )
2347 {
2349 bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
2350 }
2351 eSvxAdjust = bNumber ? SvxAdjust::Right : SvxAdjust::Left;
2352 }
2353 break;
2354 case SvxCellHorJustify::Block:
2355 eSvxAdjust = SvxAdjust::Block;
2356 break;
2357 case SvxCellHorJustify::Center:
2358 eSvxAdjust = SvxAdjust::Center;
2359 break;
2360 case SvxCellHorJustify::Right:
2361 eSvxAdjust = SvxAdjust::Right;
2362 break;
2363 default: // SvxCellHorJustify::Left
2364 eSvxAdjust = SvxAdjust::Left;
2365 break;
2366 }
2367
2368 bool bAsianVertical = pLastPattern &&
2369 pLastPattern->GetItem( ATTR_STACKED ).GetValue() &&
2371 if ( bAsianVertical )
2372 {
2373 // Always edit at top of cell -> LEFT when editing vertically
2374 eSvxAdjust = SvxAdjust::Left;
2375 }
2376
2377 pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
2378 mpEditEngine->SetDefaults( *pEditDefaults );
2379
2380 if ( pActiveViewSh )
2381 {
2382 pActiveViewSh->GetViewData().SetEditAdjust( eSvxAdjust );
2383 }
2384 mpEditEngine->SetVertical( bAsianVertical );
2385}
2386
2388{
2389 // Delete hard alignment attributes
2390 bool bUndo = mpEditEngine->IsUndoEnabled();
2391 if ( bUndo )
2392 mpEditEngine->EnableUndo( false );
2393
2394 // Non-default paragraph attributes (e.g. from clipboard)
2395 // must be turned into character attributes
2396 mpEditEngine->RemoveParaAttribs();
2397
2398 if ( bUndo )
2399 mpEditEngine->EnableUndo( true );
2400
2401}
2402
2404{
2405 // Delete pRangeFindList and colors
2406 mpEditEngine->SetUpdateLayout(false);
2407 sal_Int32 nCount = mpEditEngine->GetParagraphCount(); // Could just have been inserted
2408 for (sal_Int32 i=0; i<nCount; i++)
2409 mpEditEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
2410 mpEditEngine->SetUpdateLayout(true);
2411
2412 EditView* pActiveView = pTopView ? pTopView : pTableView;
2413 pActiveView->ShowCursor( false );
2414
2415 DeleteRangeFinder(); // Deletes the list and the labels on the table
2416}
2417
2418bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
2419 ScEditEngineDefaulter* pTopEngine )
2420{
2421 bool bNewTable = false;
2422
2423 if (bModified)
2424 return false;
2425
2426 if (pActiveViewSh)
2427 {
2429
2430 if (!rDoc.ValidCol(aCursorPos.Col()))
2431 return false;
2432
2435 SyncViews();
2436
2437
2438 const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
2439 ScEditableTester aTester;
2440 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
2441 aTester.TestSelection( rDoc, rMark );
2442 else
2443 aTester.TestSelectedBlock(
2444 rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
2445
2446 bool bStartInputMode = true;
2447
2448 if (!aTester.IsEditable())
2449 {
2450 bProtected = true;
2451 // We allow read-only input mode activation regardless
2452 // whether it's part of an array or not or whether explicit cell
2453 // activation is requested (double-click or F2) or a click in input
2454 // line.
2455 bool bShowError = (!bInputActivated || !aTester.GetMessageId() || aTester.GetMessageId() != STR_PROTECTIONERR) &&
2457 if (bShowError)
2458 {
2460 StopInputWinEngine( true );
2462 if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
2463 {
2464 // Prevent repeated error messages for the same cell from command events
2465 // (for keyboard events, multiple messages are wanted).
2466 // Set the flag before showing the error message because the command handler
2467 // for the next IME command may be called when showing the dialog.
2468 if ( bFromCommand )
2469 bCommandErrorShown = true;
2470
2473 }
2474 bStartInputMode = false;
2475 }
2476 }
2477
2478 if (bStartInputMode)
2479 {
2480 // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
2481 mpEditEngine->SetUpdateLayout( false );
2482
2483 // Take over attributes in EditEngine
2484 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
2485 aCursorPos.Row(),
2486 aCursorPos.Tab() );
2487 if (pPattern != pLastPattern)
2488 {
2489 // Percent format?
2490 const SfxItemSet& rAttrSet = pPattern->GetItemSet();
2491
2492 if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALUE_FORMAT ) )
2493 {
2494 sal_uInt32 nFormat = pItem->GetValue();
2495 if (SvNumFormatType::PERCENT == rDoc.GetFormatTable()->GetType( nFormat ))
2496 nCellPercentFormatDecSep = rDoc.GetFormatTable()->GetFormatDecimalSep( nFormat).toChar();
2497 else
2499 }
2500 else
2501 nCellPercentFormatDecSep = 0; // Default: no percent
2502
2503 // Validity specified?
2504 if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALIDDATA ) )
2505 nValidation = pItem->GetValue();
2506 else
2507 nValidation = 0;
2508
2509 // EditEngine Defaults
2510 // In no case SetParaAttribs, because the EditEngine might already
2511 // be filled (for Edit cells).
2512 // SetParaAttribs would change the content.
2513
2517
2518 pPattern->FillEditItemSet( pEditDefaults.get() );
2519 mpEditEngine->SetDefaults( *pEditDefaults );
2520 pLastPattern = pPattern;
2521 bLastIsSymbol = pPattern->IsSymbolFont();
2522
2523 // Background color must be known for automatic font color.
2524 // For transparent cell background, the document background color must be used.
2525
2526 Color aBackCol = pPattern->GetItem( ATTR_BACKGROUND ).GetColor();
2527 ScModule* pScMod = SC_MOD();
2528 if ( aBackCol.IsTransparent() ||
2531 mpEditEngine->SetBackgroundColor( aBackCol );
2532
2533 // Adjustment
2534 eAttrAdjust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
2535 if ( eAttrAdjust == SvxCellHorJustify::Repeat &&
2536 pPattern->GetItem(ATTR_LINEBREAK).GetValue() )
2537 {
2538 // #i31843# "repeat" with "line breaks" is treated as default alignment
2539 eAttrAdjust = SvxCellHorJustify::Standard;
2540 }
2541 }
2542
2543 if (pTopEngine)
2544 {
2545 // Necessary to sync SvxAutoCorrect behavior. This has to be
2546 // done before InitRangeFinder() below.
2547 MergeLanguageAttributes( *pTopEngine);
2548 }
2549
2550 // UpdateSpellSettings enables online spelling if needed
2551 // -> also call if attributes are unchanged
2552 UpdateSpellSettings( true ); // uses pLastPattern
2553
2554 // Fill EditEngine
2555 OUString aStr;
2556 if (bTextValid)
2557 {
2558 mpEditEngine->SetTextCurrentDefaults(aCurrentText);
2560 bTextValid = false;
2561 aCurrentText.clear();
2562 }
2563 else
2564 aStr = GetEditText(mpEditEngine.get());
2565
2566 // cTyped!=0 is overtyping, not editing.
2567 mbEditingExistingContent = !cTyped && !aStr.isEmpty();
2568
2569 if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
2570 {
2571 aStr = aStr.copy(1, aStr.getLength() -2);
2572 mpEditEngine->SetTextCurrentDefaults(aStr);
2573 if ( pInputWin )
2574 pInputWin->SetTextString(aStr);
2575 }
2576
2577 UpdateAdjust( cTyped );
2578
2579 if ( SC_MOD()->GetAppOptions().GetAutoComplete() )
2580 GetColData();
2581
2582 if (!cTyped && !bCreatingFuncView && StartsLikeFormula(aStr))
2583 InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
2584
2585 bNewTable = true; // -> PostEditView Call
2586 }
2587 }
2588
2589 if (!bProtected && pInputWin)
2590 pInputWin->SetOkCancelMode();
2591
2592 return bNewTable;
2593}
2594
2596{
2597 const SfxItemSet& rSrcSet = mpEditEngine->GetDefaults();
2598 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE ));
2599 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CJK ));
2600 rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CTL ));
2601}
2602
2603static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
2604{
2605 OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
2606
2607 EditEngine* pEngine = pEditView->GetEditEngine();
2608 sal_Int32 nCount = pEngine->GetParagraphCount();
2609 if (nCount > 1)
2610 {
2611 sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2612 while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2613 {
2614 rSel.nStartPos -= nParLen + 1; // Including space from line break
2615 nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2616 }
2617
2618 nParLen = pEngine->GetTextLen(rSel.nEndPara);
2619 while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2620 {
2621 rSel.nEndPos -= nParLen + 1; // Including space from line break
2622 nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2623 }
2624 }
2625
2626 ESelection aSel = pEditView->GetSelection();
2627
2628 if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2629 || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2630 pEditView->SetSelection( rSel );
2631}
2632
2633void ScInputHandler::SyncViews( const EditView* pSourceView )
2634{
2635 if (pSourceView)
2636 {
2637 bool bSelectionForTopView = false;
2638 if (pTopView && pTopView != pSourceView)
2639 bSelectionForTopView = true;
2640 bool bSelectionForTableView = false;
2641 if (pTableView && pTableView != pSourceView)
2642 bSelectionForTableView = true;
2643 if (bSelectionForTopView || bSelectionForTableView)
2644 {
2645 ESelection aSel(pSourceView->GetSelection());
2646 if (bSelectionForTopView)
2647 pTopView->SetSelection(aSel);
2648 if (bSelectionForTableView)
2650 }
2651 }
2652 // Only sync selection from topView if we are actually editing there
2653 else if (pTopView && pTableView)
2654 {
2657 }
2658}
2659
2661{
2662 if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2663 mpEditEngine && mpEditEngine->IsUpdateLayout() && pInputWin )
2664 {
2665 // Update input line from ModifyHdl for changes that are not
2666 // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2667 OUString aText(ScEditUtil::GetMultilineString(*mpEditEngine));
2668 lcl_RemoveTabs(aText);
2669 pInputWin->SetTextString(aText);
2670 }
2671}
2672
2676bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2677{
2678 if (pActiveViewSh)
2680 bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2681
2682 if ( eMode == SC_INPUT_NONE )
2683 return StartTable( cTyped, bFromCommand, false, nullptr );
2684 else
2685 return false;
2686}
2687
2688void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2689{
2691
2692 if (eMode==SC_INPUT_NONE)
2694
2695 if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2696 {
2697 // table EditEngine is formatted below, input line needs formatting after paste
2698 // #i20282# not when called from the input line's modify handler
2700
2701 // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2702 // can't safely access the EditEngine's current view, so the cursor has to be
2703 // shown again here.
2705 }
2706
2707 if (bSetModified)
2708 bModified = true;
2709 bSelIsRef = false;
2710
2712 RemoveRangeFinder(); // Delete attributes and labels
2713
2714 UpdateParenthesis(); // Highlight parentheses anew
2715
2717 {
2718 OUString aText;
2719 if (pInputWin)
2721 else
2722 aText = GetEditText(mpEditEngine.get());
2723 lcl_RemoveTabs(aText);
2724
2725 if ( pInputWin )
2726 pInputWin->SetTextString( aText );
2727
2729 {
2730 if (pActiveViewSh)
2731 {
2732 // TODO: deprecated?
2733 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aText.toUtf8().getStr());
2734 }
2735 }
2736 }
2737
2738 // If the cursor is before the end of a paragraph, parts are being pushed to
2739 // the right (independently from the eMode) -> Adapt View!
2740 // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2741 //
2742 // First make sure the status handler is called now if the cursor
2743 // is outside the visible area
2744 mpEditEngine->QuickFormatDoc();
2745
2746 EditView* pActiveView = pTopView ? pTopView : pTableView;
2747 ESelection aSel;
2748 if (pActiveView && pActiveViewSh)
2749 {
2750 ScViewData& rViewData = pActiveViewSh->GetViewData();
2751
2752 bool bNeedGrow = ( rViewData.GetEditAdjust() != SvxAdjust::Left ); // Always right-aligned
2753 if (!bNeedGrow)
2754 {
2755 // Cursor before the end?
2756 aSel = pActiveView->GetSelection();
2757 aSel.Adjust();
2758 bNeedGrow = ( aSel.nEndPos != mpEditEngine->GetTextLen(aSel.nEndPara) );
2759 }
2760 if (!bNeedGrow)
2761 {
2762 bNeedGrow = rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
2763 }
2764 if (bNeedGrow)
2765 {
2766 // Adjust inplace view
2767 rViewData.EditGrowY();
2768 rViewData.EditGrowX();
2769 }
2770 }
2771
2773 {
2775 if (pActiveView)
2776 aSel = pActiveView->GetSelection();
2777
2780 aSel);
2781 }
2782
2784 bTextValid = false; // Changes only in the EditEngine
2785 bInOwnChange = false;
2786}
2787
2788bool ScInputHandler::StartsLikeFormula( std::u16string_view rStr ) const
2789{
2790 // For new input '+' and '-' may start the dreaded "lazy data typist"
2791 // formula input, editing existing formula content can only start with '='.
2792 return !rStr.empty() && (rStr[0] == '=' || (!mbEditingExistingContent && (rStr[0] == '+' || rStr[0] == '-')));
2793}
2794
2796{
2797 SfxApplication* pSfxApp = SfxGetpApp();
2798
2799 bool bIsFormula = !bProtected;
2800 if (bIsFormula)
2801 {
2802 const OUString& rText = mpEditEngine->GetText(0);
2803 bIsFormula = StartsLikeFormula(rText);
2804 }
2805
2806 if ( bIsFormula )
2807 {
2808 if (!bFormulaMode)
2809 {
2810 bFormulaMode = true;
2812 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2813 ScModule* pMod = SC_MOD();
2814 pMod->SetRefInputHdl(this);
2815 if (pInputWin)
2816 pInputWin->SetFormulaMode(true);
2817
2818 // in LOK, we always need to perform the GetFormulaData() call so
2819 // that the formula insertion works
2822
2825 }
2826 }
2827 else // Deactivate
2828 {
2829 if (bFormulaMode)
2830 {
2831 ShowRefFrame();
2832 bFormulaMode = false;
2833 pRefViewSh = nullptr;
2834 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2835 SC_MOD()->SetRefInputHdl(nullptr);
2836 if (pInputWin)
2837 pInputWin->SetFormulaMode(false);
2839 }
2840 }
2841}
2842
2844{
2845 // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2846 // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2847 // A local variable is used instead.
2848 ScTabViewShell* pVisibleSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2849 if ( !(pRefViewSh && pRefViewSh != pVisibleSh) )
2850 return;
2851
2852 bool bFound = false;
2853 SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
2854 SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2855 while ( pOneFrame && !bFound )
2856 {
2857 if ( pOneFrame == pRefFrame )
2858 bFound = true;
2859 pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2860 }
2861
2862 if (bFound)
2863 {
2864 // We count on Activate working synchronously here
2865 // (pActiveViewSh is set while doing so)
2866 pRefViewSh->SetActive(); // Appear and SetViewFrame
2867
2868 // pLastState is set correctly in the NotifyChange from the Activate
2869 }
2870 else
2871 {
2872 OSL_FAIL("ViewFrame for reference input is not here anymore");
2873 }
2874}
2875
2877{
2878 EditView* pActiveView = pTopView ? pTopView : pTableView;
2879 if (!pActiveView)
2880 return;
2881
2882 ESelection aSel = pActiveView->GetSelection();
2883 aSel.nStartPara = aSel.nEndPara;
2884 aSel.nStartPos = aSel.nEndPos;
2885 if (pTableView)
2886 pTableView->SetSelection( aSel );
2887 if (pTopView)
2888 pTopView->SetSelection( aSel );
2889}
2890
2892{
2893 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2894 if (!pViewFrm)
2895 return;
2896
2897 SfxBindings& rBindings = pViewFrm->GetBindings();
2898
2899 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2900 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2901 rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2902
2903 rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2904 rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2905 rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2906 rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
2907 rBindings.Invalidate( SID_ULINE_VAL_NONE );
2908 rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2909 rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2910 rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2911
2912 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2913
2914 rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2915 rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2916 rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2917 rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2918 rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2919
2920 rBindings.Invalidate( SID_SAVEDOC );
2921 rBindings.Invalidate( SID_DOC_MODIFIED );
2922}
2923
2924// --------------- public methods --------------------------------------------
2925
2926void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText, ScEditEngineDefaulter* pTopEngine )
2927{
2928 if ( eMode == eNewMode )
2929 return;
2930
2932
2933 if (bProtected)
2934 {
2936 StopInputWinEngine( true );
2937 if (pActiveViewSh)
2939 return;
2940 }
2941
2942 if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2943 // Disable paste mode when edit mode starts.
2945
2946 bInOwnChange = true; // disable ModifyHdl (reset below)
2947
2948 ScInputMode eOldMode = eMode;
2949 eMode = eNewMode;
2950 if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2951 StopInputWinEngine( false );
2952
2954 {
2955 if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2956 {
2957 if (StartTable(0, false, eMode == SC_INPUT_TABLE, pTopEngine))
2958 {
2959 if (pActiveViewSh)
2961 }
2962 }
2963
2964 if (pInitText)
2965 {
2966 mpEditEngine->SetTextCurrentDefaults(*pInitText);
2967 bModified = true;
2968 }
2969
2970 sal_Int32 nPara = mpEditEngine->GetParagraphCount()-1;
2971 sal_Int32 nLen = mpEditEngine->GetText(nPara).getLength();
2972 sal_uInt16 nCount = mpEditEngine->GetViewCount();
2973
2974 for (sal_uInt16 i=0; i<nCount; i++)
2975 {
2976 if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2977 {
2978 // Keep Selection
2979 }
2980 else
2981 {
2982 mpEditEngine->GetView(i)->
2983 SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2984 }
2985 mpEditEngine->GetView(i)->ShowCursor(false);
2986 }
2987 }
2988
2991 {
2992 if (pTableView)
2994 }
2995 else
2996 {
2997 if (pTopView)
2999 }
3000
3001 if (eNewMode != eOldMode)
3003
3004 bInOwnChange = false;
3005}
3006
3010static bool lcl_IsNumber(std::u16string_view aString)
3011{
3012 size_t nLen = aString.size();
3013 for (size_t i=0; i<nLen; i++)
3014 {
3015 sal_Unicode c = aString[i];
3016 if ( c < '0' || c > '9' )
3017 return false;
3018 }
3019 return true;
3020}
3021
3022static void lcl_SelectionToEnd( EditView* pView )
3023{
3024 if ( pView )
3025 {
3026 EditEngine* pEngine = pView->GetEditEngine();
3027 sal_Int32 nParCnt = pEngine->GetParagraphCount();
3028 if ( nParCnt == 0 )
3029 nParCnt = 1;
3030 ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
3031 pView->SetSelection( aSel );
3032 }
3033}
3034
3035void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
3036{
3039 return;
3040
3041 // Macro calls for validity can cause a lot of problems, so inhibit
3042 // nested calls of EnterHandler().
3043 if (bInEnterHandler) return;
3044 bInEnterHandler = true;
3045 bInOwnChange = true; // disable ModifyHdl (reset below)
3046 mbPartialPrefix = false;
3047
3049
3050 bool bMatrix = ( nBlockMode == ScEnterMode::MATRIX );
3051
3052 SfxApplication* pSfxApp = SfxGetpApp();
3053 std::unique_ptr<EditTextObject> pObject;
3054 std::unique_ptr<ScPatternAttr> pCellAttrs;
3055 bool bForget = false; // Remove due to validity?
3056
3057 OUString aString = GetEditText(mpEditEngine.get());
3058 OUString aPreAutoCorrectString(aString);
3059 EditView* pActiveView = pTopView ? pTopView : pTableView;
3060 if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
3061 {
3062 if (pColumnData && miAutoPosColumn != pColumnData->end())
3063 {
3064 // #i47125# If AutoInput appended something, do the final AutoCorrect
3065 // with the cursor at the end of the input.
3068 }
3069
3070 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
3071
3072 if (pTopView)
3073 pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
3074 if (pTableView)
3075 pTableView->CompleteAutoCorrect(pFrameWin);
3076 aString = GetEditText(mpEditEngine.get());
3077 }
3078 lcl_RemoveTabs(aString);
3079 lcl_RemoveTabs(aPreAutoCorrectString);
3080
3081 // Test if valid (always with simple string)
3083 {
3086 if (pData && pData->HasErrMsg())
3087 {
3088 // #i67990# don't use pLastPattern in EnterHandler
3089 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3090
3091 bool bOk;
3092
3093 if (pData->GetDataMode() == SC_VALID_CUSTOM)
3094 {
3095 bOk = pData->IsDataValidCustom( aString, *pPattern, aCursorPos, ScValidationData::CustomValidationPrivateAccess() );
3096 }
3097 else
3098 {
3099 bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
3100 }
3101
3102 if (!bOk)
3103 {
3104 pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
3105
3106 // tdf#125917 Release the grab that a current mouse-down event being handled
3107 // by ScTabView has put on the mouse via its SelectionEngine.
3108 // Otherwise the warning box cannot interact with the mouse
3109 if (ScTabView* pView = pActiveViewSh->GetViewData().GetView())
3110 {
3111 if (ScViewSelectionEngine* pSelEngine = pView->GetSelEngine())
3112 pSelEngine->ReleaseMouse();
3113 }
3114
3115 if (bBeforeSavingInLOK)
3116 {
3117 // Invalid entry but not applied to the document model.
3118 // Exit to complete the "save", leaving the edit view as it is
3119 // for the user to continue after save.
3120 bInOwnChange = false;
3121 bInEnterHandler = false;
3122 return;
3123 }
3124
3125 if (pData->DoError(pActiveViewSh->GetFrameWeld(), aString, aCursorPos))
3126 bForget = true; // Do not take over input
3127 }
3128 }
3129 }
3130
3131 // Check for input into DataPilot table
3132 if ( bModified && pActiveViewSh && !bForget )
3133 {
3136 if ( pDPObj )
3137 {
3138 // Any input within the DataPilot table is either a valid renaming
3139 // or an invalid action - normal cell input is always aborted
3141 bForget = true;
3142 }
3143 }
3144
3145 std::vector<editeng::MisspellRanges> aMisspellRanges;
3146 // UpdateLayout must be true during CompleteOnlineSpelling
3147 const bool bUpdateLayout = mpEditEngine->SetUpdateLayout( true );
3148 mpEditEngine->CompleteOnlineSpelling();
3149 bool bSpellErrors = !bFormulaMode && mpEditEngine->HasOnlineSpellErrors();
3150 if ( bSpellErrors )
3151 {
3152 // #i3820# If the spell checker flags numerical input as error,
3153 // it still has to be treated as number, not EditEngine object.
3154 if ( pActiveViewSh )
3155 {
3157 // #i67990# don't use pLastPattern in EnterHandler
3158 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3159 if (pPattern)
3160 {
3161 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
3162 // without conditional format, as in ScColumn::SetString
3163 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
3164 double nVal;
3165 if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
3166 {
3167 bSpellErrors = false; // ignore the spelling errors
3168 }
3169 }
3170 }
3171 }
3172
3173 // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
3174 // SetUpdateLayout must come after CompleteOnlineSpelling.
3175 // The view is hidden in any case below (Broadcast).
3176 mpEditEngine->SetUpdateLayout( false );
3177
3178 if ( bModified && !bForget ) // What is being entered (text/object)?
3179 {
3180 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
3181 if ( nParCnt == 0 )
3182 nParCnt = 1;
3183
3184 bool bUniformAttribs = true;
3185 SfxItemSet aPara1Attribs = mpEditEngine->GetAttribs(0, 0, mpEditEngine->GetTextLen(0));
3186 for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
3187 {
3188 SfxItemSet aPara2Attribs = mpEditEngine->GetAttribs(nPara, 0, mpEditEngine->GetTextLen(nPara));
3189 if (!(aPara1Attribs == aPara2Attribs))
3190 {
3191 // Paragraph format different from that of the 1st paragraph.
3192 bUniformAttribs = false;
3193 break;
3194 }
3195 }
3196
3197 ESelection aSel( 0, 0, nParCnt-1, mpEditEngine->GetTextLen(nParCnt-1) );
3198 SfxItemSet aOldAttribs = mpEditEngine->GetAttribs( aSel );
3199 const SfxPoolItem* pItem = nullptr;
3200
3201 // Find common (cell) attributes before RemoveAdjust
3202 if ( pActiveViewSh && bUniformAttribs )
3203 {
3204 std::optional<SfxItemSet> pCommonAttrs;
3205 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
3206 {
3207 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3208 if ( eState == SfxItemState::SET &&
3211 *pItem != pEditDefaults->Get(nId) )
3212 {
3213 if ( !pCommonAttrs )
3214 pCommonAttrs.emplace( mpEditEngine->GetEmptyItemSet() );
3215 pCommonAttrs->Put( *pItem );
3216 }
3217 }
3218
3219 if ( pCommonAttrs )
3220 {
3222 pCellAttrs = std::make_unique<ScPatternAttr>(rDoc.GetPool());
3223 pCellAttrs->GetFromEditItemSet( &*pCommonAttrs );
3224 }
3225 }
3226
3227 // Clear ParaAttribs (including adjustment)
3228 RemoveAdjust();
3229
3230 bool bAttrib = false; // Formatting present?
3231
3232 // check if EditObject is needed
3233 if (nParCnt > 1)
3234 bAttrib = true;
3235 else
3236 {
3237 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
3238 {
3239 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3240 if (eState == SfxItemState::DONTCARE)
3241 bAttrib = true;
3242 else if (eState == SfxItemState::SET)
3243 {
3244 // Keep same items in EditEngine as in ScEditAttrTester
3247 {
3248 if ( *pItem != pEditDefaults->Get(nId) )
3249 bAttrib = true;
3250 }
3251 }
3252 }
3253
3254 // Contains fields?
3255 SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
3256 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
3257 bAttrib = true;
3258
3259 // Not converted characters?
3260 SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
3261 if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
3262 bAttrib = true;
3263
3264 // Always recognize formulas as formulas
3265 // We still need the preceding test due to cell attributes
3266 }
3267
3268 if (bSpellErrors)
3269 mpEditEngine->GetAllMisspellRanges(aMisspellRanges);
3270
3271 if (bMatrix)
3272 bAttrib = false;
3273
3274 if (bAttrib)
3275 {
3276 mpEditEngine->ClearSpellErrors();
3277 pObject = mpEditEngine->CreateTextObject();
3278 }
3279 else if (SC_MOD()->GetAppOptions().GetAutoComplete()) // Adjust Upper/Lower case
3280 {
3281 // Perform case-matching only when the typed text is partial.
3282 if (pColumnData && aAutoSearch.getLength() < aString.getLength())
3283 aString = getExactMatch(*pColumnData, aString);
3284 }
3285 }
3286
3287 // Don't rely on ShowRefFrame switching the active view synchronously
3288 // execute the function directly on the correct view's bindings instead
3289 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3291
3292 if (bFormulaMode)
3293 {
3294 ShowRefFrame();
3295
3296 if (pExecuteSh)
3297 {
3298 pExecuteSh->SetTabNo(aCursorPos.Tab());
3299 pExecuteSh->ActiveGrabFocus();
3300 }
3301
3302 bFormulaMode = false;
3303 pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3304 SC_MOD()->SetRefInputHdl(nullptr);
3305 if (pInputWin)
3306 pInputWin->SetFormulaMode(false);
3308 }
3309 pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3311 ResetAutoPar();
3312
3313 bool bOldMod = bModified;
3314
3315 bModified = false;
3316 bSelIsRef = false;
3318 StopInputWinEngine(true);
3319
3320 // Text input (through number formats) or ApplySelectionPattern modify
3321 // the cell's attributes, so pLastPattern is no longer valid
3322 pLastPattern = nullptr;
3323
3324 if (bOldMod && !bProtected && !bForget)
3325 {
3326 bool bInsertPreCorrectedString = true;
3327 // No typographic quotes in formulas
3328 if (aString.startsWith("="))
3329 {
3331 if ( pAuto )
3332 {
3333 bInsertPreCorrectedString = false;
3334 OUString aReplace(pAuto->GetStartDoubleQuote());
3335 if( aReplace.isEmpty() )
3337 if( aReplace != "\"" )
3338 aString = aString.replaceAll( aReplace, "\"" );
3339
3340 aReplace = OUString(pAuto->GetEndDoubleQuote());
3341 if( aReplace.isEmpty() )
3343 if( aReplace != "\"" )
3344 aString = aString.replaceAll( aReplace, "\"" );
3345
3346 aReplace = OUString(pAuto->GetStartSingleQuote());
3347 if( aReplace.isEmpty() )
3349 if( aReplace != "'" )
3350 aString = aString.replaceAll( aReplace, "'" );
3351
3352 aReplace = OUString(pAuto->GetEndSingleQuote());
3353 if( aReplace.isEmpty() )
3355 if( aReplace != "'" )
3356 aString = aString.replaceAll( aReplace, "'");
3357 }
3358 }
3359
3360 pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditViewNoPaint ) );
3361
3362 if ( pExecuteSh )
3363 {
3364 SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
3365
3366 sal_uInt16 nId = FID_INPUTLINE_ENTER;
3367 if ( nBlockMode == ScEnterMode::BLOCK )
3368 nId = FID_INPUTLINE_BLOCK;
3369 else if ( nBlockMode == ScEnterMode::MATRIX )
3370 nId = FID_INPUTLINE_MATRIX;
3371
3372 const SfxPoolItem* aArgs[2];
3373 aArgs[1] = nullptr;
3374
3375 if ( bInsertPreCorrectedString && aString != aPreAutoCorrectString )
3376 {
3377 ScInputStatusItem aItem(FID_INPUTLINE_STATUS,
3379 aPreAutoCorrectString, pObject.get());
3380 aArgs[0] = &aItem;
3381 rBindings.Execute(nId, aArgs);
3382 }
3383
3384 ScInputStatusItem aItemCorrected(FID_INPUTLINE_STATUS,
3386 aString, pObject.get());
3387 if ( !aMisspellRanges.empty() )
3388 aItemCorrected.SetMisspellRanges(&aMisspellRanges);
3389
3390 aArgs[0] = &aItemCorrected;
3391 rBindings.Execute(nId, aArgs);
3392 }
3393
3394 pLastState.reset(); // pLastState still contains the old text
3395 }
3396 else
3397 pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
3398
3399 if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
3400 {
3401 // Combine with input?
3402 pExecuteSh->ApplySelectionPattern( *pCellAttrs, true );
3403 pExecuteSh->AdjustBlockHeight();
3404 }
3405
3406 HideTip();
3407 HideTipBelow();
3408
3410 aFormText.clear();
3411
3413 bInOwnChange = false;
3414 bInEnterHandler = false;
3415 if (bUpdateLayout)
3416 mpEditEngine->SetUpdateLayout( true );
3417}
3418
3420{
3421 bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
3422
3424
3425 bModified = false;
3426 mbPartialPrefix = false;
3428
3429 // Don't rely on ShowRefFrame switching the active view synchronously
3430 // execute the function directly on the correct view's bindings instead
3431 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3433
3434 if (bFormulaMode)
3435 {
3436 ShowRefFrame();
3437 if (pExecuteSh)
3438 {
3439 pExecuteSh->SetTabNo(aCursorPos.Tab());
3440 pExecuteSh->ActiveGrabFocus();
3441 }
3442 bFormulaMode = false;
3443 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3444 SC_MOD()->SetRefInputHdl(nullptr);
3445 if (pInputWin)
3446 pInputWin->SetFormulaMode(false);
3448 }
3449 pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3451 ResetAutoPar();
3452
3454 StopInputWinEngine( true );
3455 SCCOL nMaxCol(MAXCOL);
3456 if (pExecuteSh)
3457 {
3458 pExecuteSh->StopEditShell();
3459 nMaxCol = pExecuteSh->GetViewData().GetDocument().MaxCol();
3460 }
3461
3462 aCursorPos.Set(nMaxCol+1,0,0); // Invalid flag
3463 mpEditEngine->SetTextCurrentDefaults(OUString());
3464
3465 if ( !pLastState && pExecuteSh )
3466 pExecuteSh->UpdateInputHandler( true ); // Update status again
3467 else
3468 NotifyChange( pLastState.get(), true );
3469
3471 aFormText.clear();
3472
3473 bInOwnChange = false;
3474
3475 if ( comphelper::LibreOfficeKit::isActive() && pExecuteSh )
3476 {
3477 // Clear
3478 std::vector<ReferenceMark> aReferenceMarks;
3480 }
3481}
3482
3484{
3485 // References to unnamed document; that doesn't work
3486 return bFormulaMode && pRefViewSh
3488 && !pDocSh->HasName();
3489}
3490
3492{
3495 if (!pTableView && !pTopView)
3496 return; // E.g. FillMode
3497
3498 DataChanging(); // Cannot be new
3499
3501 OUString aText = GetEditText(mpEditEngine.get());
3502 sal_Unicode cLastChar = 0;
3503 sal_Int32 nPos = aText.getLength() - 1;
3504 while (nPos >= 0) //checking space
3505 {
3506 cLastChar = aText[nPos];
3507 if (cLastChar != ' ')
3508 break;
3509 --nPos;
3510 }
3511
3512 bool bAppendSeparator = (cLastChar != '(' && cLastChar != cSep && cLastChar != '=');
3513 if (bAppendSeparator)
3514 {
3515 if (pTableView)
3516 pTableView->InsertText( OUString(cSep) );
3517 if (pTopView)
3518 pTopView->InsertText( OUString(cSep) );
3519 }
3520
3521 DataChanged();
3522}
3523
3524void ScInputHandler::SetReference( const ScRange& rRef, const ScDocument& rDoc )
3525{
3526 HideTip();
3527
3528 const ScDocument* pThisDoc = nullptr;
3529 if (pRefViewSh)
3530 pThisDoc = &pRefViewSh->GetViewData().GetDocument();
3531 bool bOtherDoc = (pThisDoc != &rDoc);
3532 if (bOtherDoc && !rDoc.GetDocumentShell()->HasName())
3533 {
3534 // References to unnamed document; that doesn't work
3535 // SetReference should not be called, then
3536 return;
3537 }
3538 if (!pThisDoc)
3539 pThisDoc = &rDoc;
3540
3542 if (!pTableView && !pTopView)
3543 return; // E.g. FillMode
3544
3545 // Never overwrite the "="!
3546 EditView* pActiveView = pTopView ? pTopView : pTableView;
3547 ESelection aSel = pActiveView->GetSelection();
3548 aSel.Adjust();
3549 if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
3550 return;
3551
3552 DataChanging(); // Cannot be new
3553
3554 // Turn around selection if backwards.
3555 if (pTableView)
3556 {
3557 ESelection aTabSel = pTableView->GetSelection();
3558 if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
3559 {
3560 aTabSel.Adjust();
3561 pTableView->SetSelection(aTabSel);
3562 }
3563 }
3564 if (pTopView)
3565 {
3566 ESelection aTopSel = pTopView->GetSelection();
3567 if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
3568 {
3569 aTopSel.Adjust();
3570 pTopView->SetSelection(aTopSel);
3571 }
3572 }
3573
3574 // Create string from reference, in the syntax of the document being edited.
3575 OUString aRefStr;
3576 const ScAddress::Details aAddrDetails( *pThisDoc, aCursorPos );
3577 if (bOtherDoc)
3578 {
3579 // Reference to other document
3580 OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
3581
3582 // Always 3D and absolute.
3583 OUString aTmp(rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails));
3584
3585 SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
3586 // #i75893# convert escaped URL of the document to something user friendly
3588
3589 switch(aAddrDetails.eConv)
3590 {
3594 aRefStr = "[\'" + aFileName + "']";
3595 break;
3597 default:
3598 aRefStr = "\'" + aFileName + "'#";
3599 break;
3600 }
3601 aRefStr += aTmp;
3602 }
3603 else
3604 {
3605 if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
3606 rRef.aStart.Tab() != rRef.aEnd.Tab() )
3607 // pointer-selected => absolute sheet reference
3608 aRefStr = rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails);
3609 else
3610 aRefStr = rRef.Format(rDoc, ScRefFlags::VALID, aAddrDetails);
3611 }
3612 bool bLOKShowSelect = true;
3614 bLOKShowSelect = false;
3615
3616 if (pTableView || pTopView)
3617 {
3618 if (pTableView)
3619 pTableView->InsertText( aRefStr, true, bLOKShowSelect );
3620 if (pTopView)
3621 pTopView->InsertText( aRefStr, true, bLOKShowSelect );
3622
3623 DataChanged();
3624 }
3625
3626 bSelIsRef = true;
3627}
3628
3629void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
3630{
3631 if ( eMode == SC_INPUT_NONE )
3632 {
3633 OSL_FAIL("InsertFunction, not during input mode");
3634 return;
3635 }
3636
3638 if (!pTableView && !pTopView)
3639 return; // E.g. FillMode
3640
3641 DataChanging(); // Cannot be new
3642
3643 OUString aText = rFuncName;
3644 if (bAddPar)
3645 aText += "()";
3646
3647 if (pTableView)
3648 {
3649 pTableView->InsertText( aText );
3650 if (bAddPar)
3651 {
3653 --aSel.nStartPos;
3654 --aSel.nEndPos;
3655 pTableView->SetSelection(aSel);
3656 }
3657 }
3658 if (pTopView)
3659 {
3660 pTopView->InsertText( aText );
3661 if (bAddPar)
3662 {
3664 --aSel.nStartPos;
3665 --aSel.nEndPos;
3666 pTopView->SetSelection(aSel);
3667 }
3668 }
3669
3670 DataChanged();
3671
3672 if (bAddPar)
3673 AutoParAdded();
3674}
3675
3677{
3678 if ( eMode == SC_INPUT_NONE )
3679 {
3680 OSL_FAIL("ClearText, not during input mode");
3681 return;
3682 }
3683
3685 if (!pTableView && !pTopView)
3686 return; // E.g. FillMode
3687
3688 DataChanging(); // Cannot be new
3689
3690 if (pTableView)
3691 {
3693 pTableView->SetSelection( ESelection(0,0, 0,0) );
3694 }
3695 if (pTopView)
3696 {
3697 pTopView->GetEditEngine()->SetText( "" );
3698 pTopView->SetSelection( ESelection(0,0, 0,0) );
3699 }
3700
3701 DataChanged();
3702}
3703
3704bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
3705{
3706 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3707 sal_uInt16 nModi = aCode.GetModifier();
3708 bool bShift = aCode.IsShift();
3709 bool bControl = aCode.IsMod1();
3710 bool bAlt = aCode.IsMod2();
3711 sal_uInt16 nCode = aCode.GetCode();
3712 sal_Unicode nChar = rKEvt.GetCharCode();
3713
3714 if (bAlt && !bControl && nCode != KEY_RETURN)
3715 // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3716 return false;
3717
3718 // There is a partial autocomplete suggestion.
3719 // Allow its completion with right arrow key (without modifiers).
3720 if (mbPartialPrefix && nCode == KEY_RIGHT && !bControl && !bShift && !bAlt &&
3721 (pTopView || pTableView))
3722 {
3723 if (pTopView)
3724 pTopView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
3725 if (pTableView)
3726 pTableView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
3727
3728 mbPartialPrefix = false;
3729
3730 // Indicate that this event has been consumed and ScTabViewShell should not act on this.
3731 return true;
3732 }
3733
3734 if (!bControl && nCode == KEY_TAB)
3735 {
3736 // Normal TAB moves the cursor right.
3737 EnterHandler();
3738
3739 if (pActiveViewSh)
3740 pActiveViewSh->FindNextUnprot( bShift, true );
3741 return true;
3742 }
3743
3744 bool bInputLine = ( eMode==SC_INPUT_TOP );
3745
3746 bool bUsed = false;
3747 bool bSkip = false;
3748 bool bDoEnter = false;
3749
3750 switch ( nCode )
3751 {
3752 case KEY_RETURN:
3753 // New line when in the input line and Shift/Ctrl-Enter is pressed,
3754 // or when in a cell and Ctrl-Enter is pressed.
3755 if ((pInputWin && bInputLine && bControl != bShift) || (!bInputLine && bControl && !bShift))
3756 {
3757 bDoEnter = true;
3758 }
3759 else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3760 {
3762 bUsed = true;
3763 }
3764 else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3765 {
3767 bUsed = true;
3768 }
3769 else
3770 {
3772 if ( bShift && bControl )
3773 nMode = ScEnterMode::MATRIX;
3774 else if ( bAlt )
3775 nMode = ScEnterMode::BLOCK;
3776 EnterHandler( nMode );
3777
3778 if (pActiveViewSh)
3779 pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3780
3781 bUsed = true;
3782 }
3783 break;
3784 case KEY_TAB:
3785 if (bControl && !bAlt)
3786 {
3788 {
3789 // Iterate
3790 NextFormulaEntry( bShift );
3791 bUsed = true;
3792 }
3793 else if (pColumnData && bUseTab)
3794 {
3795 // Iterate through AutoInput entries
3796 NextAutoEntry( bShift );
3797 bUsed = true;
3798 }
3799 }
3800 break;
3801 case KEY_ESCAPE:
3802 if ( nTipVisible )
3803 {
3804 HideTip();
3805 bUsed = true;
3806 }
3807 else if( nTipVisibleSec )
3808 {
3809 HideTipBelow();
3810 bUsed = true;
3811 }
3812 else if (eMode != SC_INPUT_NONE)
3813 {
3814 CancelHandler();
3815 bUsed = true;
3816 }
3817 else
3818 bSkip = true;
3819 break;
3820 case KEY_F2:
3821 if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3822 {
3824 bUsed = true;
3825 }
3826 break;
3827 }
3828
3829 // Only execute cursor keys if already in EditMode
3830 // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3831 bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3832 bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3833 if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3834 ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3835 {
3836 HideTip();
3837 HideTipBelow();
3838
3839 if (bSelIsRef)
3840 {
3842 bSelIsRef = false;
3843 }
3844
3846 bool bNewView = DataChanging( nChar );
3847
3848 if (bProtected) // Protected cell?
3849 bUsed = true; // Don't forward KeyEvent
3850 else // Changes allowed
3851 {
3852 if (bNewView ) // Create anew
3853 {
3854 if (pActiveViewSh)
3857 if (eMode==SC_INPUT_NONE)
3858 if (pTableView || pTopView)
3859 {
3860 OUString aStrLoP;
3861
3862 if (bStartEdit && nCellPercentFormatDecSep != 0 &&
3863 ((nChar >= '0' && nChar <= '9') || nChar == '-' || nChar == nCellPercentFormatDecSep))
3864 {
3865 aStrLoP = "%";
3866 }
3867
3868 if (pTableView)
3869 {
3870 pTableView->GetEditEngine()->SetText( aStrLoP );
3871 if ( !aStrLoP.isEmpty() )
3872 pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3873
3874 // Don't call SetSelection if the string is empty anyway,
3875 // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3876 }
3877 if (pTopView)
3878 {
3879 pTopView->GetEditEngine()->SetText( aStrLoP );
3880 if ( !aStrLoP.isEmpty() )
3881 pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3882 }
3883 }
3884 SyncViews();
3885 }
3886
3887 if (pTableView || pTopView)
3888 {
3889 if (bDoEnter)
3890 {
3891 if (pTableView)
3893 bUsed = true;
3894 if (pTopView)
3896 bUsed = true;
3897 }
3898 else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3899 {
3901 bUsed = true;
3902 }
3903 else
3904 {
3905 if (pTableView)
3906 {
3907 if (pTopView)
3908 pTableView->SetControlWord(pTableView->GetControlWord() | EVControlBits::SINGLELINEPASTE);
3909
3910 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
3911 if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3912 bUsed = true;
3913
3914 pTableView->SetControlWord(pTableView->GetControlWord() & ~EVControlBits::SINGLELINEPASTE);
3915 }
3916 if (pTopView)
3917 {
3918 if ( bUsed && rKEvt.GetKeyCode().GetFunction() == KeyFuncType::CUT )
3920 else if ( pTopView->PostKeyEvent( rKEvt ) )
3921 bUsed = true;
3922 }
3923 }
3924
3925 // AutoInput:
3926 if ( bUsed && SC_MOD()->GetAppOptions().GetAutoComplete() )
3927 {
3928 bUseTab = false;
3929 if (pFormulaData)
3930 miAutoPosFormula = pFormulaData->end(); // do not search further
3931 if (pColumnData)
3933
3934 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3935 if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3936 KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
3937 {
3938 if (bFormulaMode)
3940 else
3941 UseColData();
3942 }
3943 }
3944
3945 // When the selection is changed manually or an opening parenthesis
3946 // is typed, stop overwriting parentheses
3947 if ( bUsed && nChar == '(' )
3948 ResetAutoPar();
3949
3950 if ( KEY_INSERT == nCode )
3951 {
3952 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3953 if (pViewFrm)
3954 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3955 }
3956 if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3957 {
3958 ShowTipCursor();
3959 }
3960 if( bUsed && bFormulaMode && nCode == KEY_BACKSPACE )
3961 {
3963 }
3964
3965 }
3966
3967 // #i114511# don't count cursor keys as modification
3968 bool bSetModified = !bCursorKey;
3969 DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3970
3971 // In the LOK case, we want to set the document modified state
3972 // right away at the start of the edit, so that the content is
3973 // saved even when the user leaves the document before hitting
3974 // Enter
3977
3979 }
3980 }
3981
3982 if (pTopView && eMode != SC_INPUT_NONE)
3983 SyncViews();
3984
3985 return bUsed;
3986}
3987
3989{
3990 if (eMode != SC_INPUT_NONE)
3991 {
3993 if (pTableView || pTopView)
3994 {
3995 if (pTableView)
3997 else if (pTopView) // call only once
3998 return pTopView->GetSurroundingText();
3999 }
4000 }
4001 return OUString();
4002}
4003
4005{
4006 if (eMode != SC_INPUT_NONE)
4007 {
4009 if (pTableView || pTopView)
4010 {
4011 if (pTableView)
4013 else if (pTopView) // call only once
4015 }
4016 }
4017 return Selection(0, 0);
4018}
4019
4021{
4022 if (eMode != SC_INPUT_NONE)
4023 {
4025 if (pTableView || pTopView)
4026 {
4027 if (pTableView)
4028 return pTableView->DeleteSurroundingText(rSelection);
4029 else if (pTopView) // call only once
4030 return pTopView->DeleteSurroundingText(rSelection);
4031 }
4032 }
4033 return false;
4034}
4035
4037{
4038 if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
4039 {
4040 // For CommandEventId::CursorPos, do as little as possible, because
4041 // with remote VCL, even a ShowCursor will generate another event.
4042 if ( eMode != SC_INPUT_NONE )
4043 {
4045 if (pTableView || pTopView)
4046 {
4047 if (pTableView)
4048 pTableView->Command( rCEvt );
4049 else if (pTopView) // call only once
4050 pTopView->Command( rCEvt );
4051 }
4052 }
4053 }
4054 else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
4055 {
4056 if ( eMode != SC_INPUT_NONE )
4057 {
4059 if (pTableView || pTopView)
4060 {
4061 if (pTableView)
4062 pTableView->Command( rCEvt );
4063 else if (pTopView) // call only once
4064 pTopView->Command( rCEvt );
4065 }
4066 }
4067 }
4068 else
4069 {
4070 HideTip();
4071 HideTipBelow();
4072
4073 if ( bSelIsRef )
4074 {
4076 bSelIsRef = false;
4077 }
4078
4080 bool bNewView = DataChanging( 0, true );
4081
4082 if (!bProtected) // changes allowed
4083 {
4084 if (bNewView) // create new edit view
4085 {
4086 if (pActiveViewSh)
4089 if (eMode==SC_INPUT_NONE)
4090 if (pTableView || pTopView)
4091 {
4092 if (pTableView)
4093 {
4095 pTableView->SetSelection( ESelection(0,0, 0,0) );
4096 }
4097 if (pTopView)
4098 {
4099 pTopView->GetEditEngine()->SetText( "" );
4100 pTopView->SetSelection( ESelection(0,0, 0,0) );
4101 }
4102 }
4103 SyncViews();
4104 }
4105
4106 if (pTableView || pTopView)
4107 {
4108 if (pTableView)
4109 pTableView->Command( rCEvt );
4110 if (pTopView)
4111 pTopView->Command( rCEvt );
4112
4113 if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
4114 {
4115 // AutoInput after ext text input
4116
4117 if (pFormulaData)
4119 if (pColumnData)
4121
4122 if (bFormulaMode)
4124 else
4125 UseColData();
4126 }
4127 }
4128
4129 DataChanged(); // calls UpdateParenthesis()
4131 }
4132
4133 if (pTopView && eMode != SC_INPUT_NONE)
4134 SyncViews();
4135 }
4136}
4137
4139 bool bForce, ScTabViewShell* pSourceSh,
4140 bool bStopEditing)
4141{
4142 // If the call originates from a macro call in the EnterHandler,
4143 // return immediately and don't mess up the status
4144 if (bInEnterHandler)
4145 return;
4146
4147 bool bRepeat = (pState == pLastState.get());
4148 if (!bRepeat && pState && pLastState)
4149 bRepeat = (*pState == *pLastState);
4150 if (bRepeat && !bForce)
4151 return;
4152
4153 bInOwnChange = true; // disable ModifyHdl (reset below)
4154
4155 if ( pState && !pLastState ) // Enable again
4156 bForce = true;
4157
4158 bool bHadObject = pLastState && pLastState->GetEditData();
4159
4161 if ( pSourceSh )
4162 pActiveViewSh = pSourceSh;
4163 else
4165
4167
4168 if ( pState != pLastState.get() )
4169 {
4170 pLastState.reset( pState ? new ScInputHdlState( *pState ) : nullptr);
4171 }
4172
4173 if ( pState && pActiveViewSh )
4174 {
4175 ScModule* pScMod = SC_MOD();
4176
4177 ScTabViewShell* pScTabViewShell = dynamic_cast<ScTabViewShell*>(pScMod->GetViewShell());
4178
4179 // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
4180 // FormEditData, if we're switching from Help to Calc:
4181 if ( !bFormulaMode && !pScMod->IsFormulaMode() &&
4182 ( !pScTabViewShell || !pScTabViewShell->GetFormEditData() ) )
4183 {
4184 bool bIgnore = false;
4185 if ( bModified )
4186 {
4187 if (pState->GetPos() != aCursorPos)
4188 {
4189 if (!bProtected)
4190 EnterHandler();
4191 }
4192 else
4193 bIgnore = true;
4194 }
4195
4196 if ( !bIgnore )
4197 {
4198 const ScAddress& rSPos = pState->GetStartPos();
4199 const ScAddress& rEPos = pState->GetEndPos();
4200 const EditTextObject* pData = pState->GetEditData();
4201 OUString aString = pState->GetString();
4202 bool bTxtMod = false;
4204 ScDocument& rDoc = pDocSh->GetDocument();
4205
4206 aCursorPos = pState->GetPos();
4207
4208 if ( pData )
4209 bTxtMod = true;
4210 else if ( bHadObject )
4211 bTxtMod = true;
4212 else if ( bTextValid )
4213 bTxtMod = ( aString != aCurrentText );
4214 else
4215 bTxtMod = ( aString != GetEditText(mpEditEngine.get()) );
4216
4217 if ( bTxtMod || bForce )
4218 {
4219 if (pData)
4220 {
4221 mpEditEngine->SetTextCurrentDefaults( *pData );
4222 if (pInputWin)
4224 else
4225 aString = GetEditText(mpEditEngine.get());
4226 lcl_RemoveTabs(aString);
4227 bTextValid = false;
4228 aCurrentText.clear();
4229 }
4230 else
4231 {
4232 aCurrentText = aString;
4233 bTextValid = true;
4234 }
4235
4236 if ( pInputWin )
4237 pInputWin->SetTextString(aString);
4238
4240 {
4241 EditView* pActiveView = pTopView ? pTopView : pTableView;
4242 ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
4243
4244 // if we switched content completely - don't send huge numbers
4245 if (aSel.nStartPara == EE_PARA_NOT_FOUND)
4246 aSel.nStartPara = 0;
4247
4248 if (aSel.nEndPara == EE_PARA_NOT_FOUND)
4249 aSel.nEndPara = 0;
4250
4252 // TODO: deprecated?
4253 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aString.toUtf8().getStr());
4254 }
4255 }
4256
4257 if ( pInputWin || comphelper::LibreOfficeKit::isActive()) // Named range input
4258 {
4259 OUString aPosStr;
4260 bool bSheetLocal = false;
4261 const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
4262
4263 // Is the range a name?
4265 if ( pActiveViewSh )
4267 GetRangeAtBlock( ScRange( rSPos, rEPos ), aPosStr, &bSheetLocal);
4268
4269 if ( aPosStr.isEmpty() ) // Not a name -> format
4270 {
4272 if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
4274 if ( rSPos != rEPos )
4275 {
4276 ScRange r(rSPos, rEPos);
4277 applyStartToEndFlags(nFlags);
4278 aPosStr = r.Format(rDoc, ScRefFlags::VALID | nFlags, aAddrDetails);
4279 }
4280 else
4281 aPosStr = aCursorPos.Format(ScRefFlags::VALID | nFlags, &rDoc, aAddrDetails);
4282 }
4283 else if (bSheetLocal)
4284 {
4285 OUString aName;
4286 if (rDoc.GetName( rSPos.Tab(), aName))
4287 aPosStr = ScPosWnd::createLocalRangeName( aPosStr, aName);
4288 }
4289
4290 if (pInputWin)
4291 {
4292 // Disable the accessible VALUE_CHANGE event
4293 bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
4294 pInputWin->SetAccessibilityEventsSuppressed(true);
4295 pInputWin->SetPosString(aPosStr);
4296 pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
4297 pInputWin->SetSumAssignMode();
4298 }
4299
4301 pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_ADDRESS, aPosStr.toUtf8().getStr());
4302 }
4303
4304 if (bStopEditing) {
4305 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
4306
4307 // As long as the content is not edited, turn off online spelling.
4308 // Online spelling is turned back on in StartTable, after setting
4309 // the right language from cell attributes.
4310
4311 EEControlBits nCntrl = mpEditEngine->GetControlWord();
4312 if ( nCntrl & EEControlBits::ONLINESPELLING )
4313 mpEditEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
4314 }
4315
4316 bModified = false;
4317 bSelIsRef = false;
4318 bProtected = false;
4319 bCommandErrorShown = false;
4320 }
4321 }
4322
4323 if ( pInputWin)
4324 {
4325 // Do not enable if RefDialog is open
4326 if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
4327 {
4328 if ( !pInputWin->IsEnabled())
4329 {
4330 pDelayTimer->Stop();
4331 pInputWin->Enable();
4332 }
4333 }
4334 else if(pScMod->IsRefDialogOpen())
4335 { // Because every document has its own InputWin,
4336 // we should start Timer again, because the input line may
4337 // still be active
4338 if ( !pDelayTimer->IsActive() )
4339 pDelayTimer->Start();
4340 }
4341 }
4342 }
4343 else // !pState || !pActiveViewSh
4344 {
4345 if ( !pDelayTimer->IsActive() )
4346 pDelayTimer->Start();
4347 }
4348
4349 HideTip();
4350 HideTipBelow();
4351 bInOwnChange = false;
4352}
4353
4355{
4356 eAttrAdjust = eJust;
4357 UpdateAdjust( 0 );
4358}
4359
4361{
4362 if( pDelayTimer->IsActive() )
4363 {
4364 pDelayTimer->Stop();
4365 if ( pInputWin )
4366 pInputWin->Enable();
4367 }
4368}
4369
4371{
4372 if ( !(nullptr == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen()))
4373 return;
4374
4376 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
4377 if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
4378 {
4379 if ( pInputWin)
4380 {
4381 pInputWin->EnableButtons( false );
4382 pInputWin->Disable();
4383 }
4384 }
4385 else if ( !bFormulaMode ) // Keep formula e.g. for help
4386 {
4387 bInOwnChange = true; // disable ModifyHdl (reset below)
4388
4389 pActiveViewSh = nullptr;
4390 mpEditEngine->SetTextCurrentDefaults( OUString() );
4391 if ( pInputWin )
4392 {
4393 pInputWin->SetPosString( OUString() );
4394 pInputWin->SetTextString( OUString() );
4395 pInputWin->Disable();
4396 }
4397
4398 bInOwnChange = false;
4399 }
4400}
4401
4403{
4404 SyncViews( pView );
4405 ShowTipCursor();
4406 UpdateParenthesis(); // Selection changed -> update parentheses highlighting
4407
4408 // When the selection is changed manually, stop overwriting parentheses
4409 ResetAutoPar();
4410
4412 {
4413 EditView* pActiveView = pTopView ? pTopView : pTableView;
4414 ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
4416 }
4417}
4418
4419void ScInputHandler::InputChanged( const EditView* pView, bool bFromNotify )
4420{
4422
4423 // #i20282# DataChanged needs to know if this is from the input line's modify handler
4424 bool bFromTopNotify = ( bFromNotify && pView == pTopView );
4425
4426 bool bNewView = DataChanging(); //FIXME: Is this at all possible?
4427 aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
4428 mpEditEngine->SetTextCurrentDefaults( aCurrentText );
4429 DataChanged( bFromTopNotify );
4430 bTextValid = true; // Is set to false in DataChanged
4431
4432 if ( pActiveViewSh )
4433 {
4434 ScViewData& rViewData = pActiveViewSh->GetViewData();
4435 if ( bNewView )
4436 rViewData.GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
4437
4438 rViewData.EditGrowY();
4439 rViewData.EditGrowX();
4440 }
4441
4442 SyncViews( pView );
4443}
4444
4446{
4447 if (mpEditEngine)
4448 {
4449 aCurrentText = mpEditEngine->GetText(); // Always new from Engine
4450 bTextValid = true;
4451 }
4452
4453 return aCurrentText;
4454}
4455
4457{
4458 Size aSize;
4459 if ( mpEditEngine )
4460 aSize = Size( mpEditEngine->CalcTextWidth(), mpEditEngine->GetTextHeight() );
4461
4462 return aSize;
4463}
4464
4466{
4467 bool bRet = false;
4468 if (mpEditEngine)
4469 {
4470 // Contains field?
4471 sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
4472 SfxItemSet aSet = mpEditEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
4473 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
4474 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
4475 {
4476 // Copy content
4477 std::unique_ptr<EditTextObject> pObj = mpEditEngine->CreateTextObject();
4478 rDestEngine.SetTextCurrentDefaults(*pObj);
4479 pObj.reset();
4480
4481 // Delete attributes
4482 for (sal_Int32 i=0; i<nParCnt; i++)
4483 rDestEngine.RemoveCharAttribs( i );
4484
4485 // Combine paragraphs
4486 while ( nParCnt > 1 )
4487 {
4488 sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
4489 ESelection aSel( 0,nLen, 1,0 );
4490 rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
4491 --nParCnt;
4492 }
4493
4494 bRet = true;
4495 }
4496 }
4497 return bRet;
4498}
4499
4504void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
4505{
4506 rStart = nFormSelStart;
4507 rEnd = nFormSelEnd;
4508}
4509
4511{
4512 UpdateActiveView(); // Due to pTableView
4513
4514 EditView* pView = nullptr;
4515 if ( pInputWin )
4516 {
4517 pInputWin->MakeDialogEditView();
4518 pView = pInputWin->GetEditView();
4519 }
4520 else
4521 {
4522 if ( eMode != SC_INPUT_TABLE )
4523 {
4524 bCreatingFuncView = true; // Don't display RangeFinder
4526 bCreatingFuncView = false;
4527 if ( pTableView )
4528 pTableView->GetEditEngine()->SetText( OUString() );
4529 }
4530 pView = pTableView;
4531 }
4532
4533 return pView;
4534}
4535
4536void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
4537{
4538 if ( nStart <= nEnd )
4539 {
4540 nFormSelStart = nStart;
4541 nFormSelEnd = nEnd;
4542 }
4543 else
4544 {
4545 nFormSelEnd = nStart;
4546 nFormSelStart = nEnd;
4547 }
4548
4549 EditView* pView = GetFuncEditView();
4550 if (pView)
4551 pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
4552
4553 bModified = true;
4554}
4555
4556void ScInputHandler::InputReplaceSelection( std::u16string_view aStr )
4557{
4558 if (!pRefViewSh)
4560
4561 OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
4562
4563 sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
4564 sal_Int32 nNewLen = aStr.size();
4565
4566 OUStringBuffer aBuf(aFormText);
4567 if (nOldLen)
4568 aBuf.remove(nFormSelStart, nOldLen);
4569 if (nNewLen)
4570 aBuf.insert(nFormSelStart, aStr);
4571
4572 aFormText = aBuf.makeStringAndClear();
4573
4574 nFormSelEnd = nFormSelStart + nNewLen;
4575
4576 EditView* pView = GetFuncEditView();
4577 if (pView)
4578 {
4579 pView->SetEditEngineUpdateLayout( false );
4580 pView->GetEditEngine()->SetText( aFormText );
4582 pView->SetEditEngineUpdateLayout( true );
4583 }
4584 bModified = true;
4585}
4586
4588{
4589 bInOwnChange = true; // disable ModifyHdl (reset below)
4590
4592 /* TODO: it would be better if there was some way to reset the input bar
4593 * engine instead of deleting and having it recreate through
4594 * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
4595 * fdo#72278 without reintroducing fdo#69971. */
4596 StopInputWinEngine(true);
4597
4598 bInOwnChange = false;
4599}
4600
4605 const ScAddress& rStartPos,
4606 const ScAddress& rEndPos,
4607 OUString _aString,
4608 const EditTextObject* pData )
4609 : aCursorPos ( rCurPos ),
4610 aStartPos ( rStartPos ),
4611 aEndPos ( rEndPos ),
4612 aString (std::move( _aString )),
4613 pEditData ( pData ? pData->Clone() : nullptr )
4614{
4615}
4616
4618{
4619 *this = rCpy;
4620}
4621
4623{
4624}
4625
4627{
4628 return ( (aStartPos == r.aStartPos)
4629 && (aEndPos == r.aEndPos)
4630 && (aCursorPos == r.aCursorPos)
4631 && (aString == r.aString)
4632 && ScGlobal::EETextObjEqual( pEditData.get(), r.pEditData.get() ) );
4633}
4634
4636{
4637 if (this != &r)
4638 {
4640 aStartPos = r.aStartPos;
4641 aEndPos = r.aEndPos;
4642 aString = r.aString;
4643 pEditData.reset();
4644 if (r.pEditData)
4645 pEditData = r.pEditData->Clone();
4646 }
4647 return *this;
4648}
4649
4650/* 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)
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:2950
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:5676
EEHorizontalTextDirection GetEditTextDirection(SCTAB nTab) const
Definition: documen8.cxx:355
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uInt32 nIndex) const
Definition: documen4.cxx:881
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6170
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:1081
bool ValidCol(SCCOL nCol) const
Definition: document.hxx:898
void ApplyAsianEditSettings(ScEditEngineDefaulter &rEngine)
Definition: documen9.cxx:674
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC CellType GetCellType(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3790
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:4813
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:3419
void ForgetLastPattern()
Definition: inputhdl.cxx:2327
void SetReference(const ScRange &rRef, const ScDocument &rDoc)
Definition: inputhdl.cxx:3524
bool mbEditingExistingContent
Definition: inputhdl.hxx:109
bool KeyInput(const KeyEvent &rKEvt, bool bStartEdit)
Definition: inputhdl.cxx:3704
void * nTipVisibleSec
Definition: inputhdl.hxx:76
void SetDocumentDisposing(bool b)
Definition: inputhdl.cxx:601
EditView * GetFuncEditView()
Definition: inputhdl.cxx:4510
void InputCommand(const CommandEvent &rCEvt)
Definition: inputhdl.cxx:4036
void AddRefEntry()
Definition: inputhdl.cxx:3491
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:2225
void UpdateSpellSettings(bool bFromStartTab=false)
Definition: inputhdl.cxx:943
void InputTurnOffWinEngine()
Definition: inputhdl.cxx:4587
ScInputMode eMode
Definition: inputhdl.hxx:91
OUString aAutoSearch
Definition: inputhdl.hxx:78
void ShowTip(const OUString &rText)
Definition: inputhdl.cxx:1294
void FormulaPreview()
Definition: inputhdl.cxx:1865
Fraction aScaleX
Definition: inputhdl.hxx:114
ScTabViewShell * pActiveViewSh
Definition: inputhdl.hxx:118
void UpdateAdjust(sal_Unicode cTyped)
Definition: inputhdl.cxx:2336
Size GetTextSize()
Definition: inputhdl.cxx:4456
bool bFormulaMode
Definition: inputhdl.hxx:96
bool GetFuncName(OUString &aStart, OUString &aResult)
Definition: inputhdl.cxx:1357
void ResetDelayTimer()
Definition: inputhdl.cxx:4360
void PasteManualTip()
Definition: inputhdl.cxx:1889
static void SendReferenceMarks(const SfxViewShell *pViewShell, const std::vector< ReferenceMark > &rReferenceMarks)
Definition: inputhdl.cxx:306
bool GetTextAndFields(ScEditEngineDefaulter &rDestEngine)
Definition: inputhdl.cxx:4465
sal_uLong nValidation
Definition: inputhdl.hxx:111
void NotifyChange(const ScInputHdlState *pState, bool bForce=false, ScTabViewShell *pSourceSh=nullptr, bool bStopEditing=true)
Definition: inputhdl.cxx:4138
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:2418
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:2891
void UpdateCellAdjust(SvxCellHorJustify eJust)
Definition: inputhdl.cxx:4354
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:1948
OUString aFormText
Definition: inputhdl.hxx:82
ScAddress aCursorPos
Definition: inputhdl.hxx:90
void * nTipVisible
Definition: inputhdl.hxx:74
void PasteFunctionData()
Definition: inputhdl.cxx:1705
ScTabViewShell * pRefViewSh
Definition: inputhdl.hxx:117
bool mbDocumentDisposing
Definition: inputhdl.hxx:106
EditView * pTopView
Definition: inputhdl.hxx:64
void DataChanged(bool bFromTopNotify=false, bool bSetModified=true)
Definition: inputhdl.cxx:2688
void UpdateRefDevice()
Definition: inputhdl.cxx:875
bool mbPartialPrefix
To indicate if there is a partial prefix completion.
Definition: inputhdl.hxx:108