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