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