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