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