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