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* pDoc)
109 {
110  ScCompiler aComp(pDoc, ScAddress(), pDoc->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  long nX1, long nX2, long nY1, long nY2,
433  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  long nSizeX = aBottomRight.X() - aTopLeft.X() - 1;
451  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  long nScrX = aScrPos.X();
458  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  long nX1 = rViewData.GetRefStartX();
509  long nX2 = rViewData.GetRefEndX();
510  long nY1 = rViewData.GetRefStartY();
511  long nY2 = rViewData.GetRefEndY();
512  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  long nX1 = aRef.aStart.Col();
536  long nX2 = aRef.aEnd.Col();
537  long nY1 = aRef.aStart.Row();
538  long nY2 = aRef.aEnd.Row();
539  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* pDoc = pDocView->GetViewData().GetDocument();
600  const ScAddress::Details aAddrDetails( *pDoc, aCursorPos );
601  OUString aNewStr(aJustified.Format(*pDoc, 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  long nDiff = aNewStr.getLength() - static_cast<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* pDoc = rViewData.GetDocument();
942  mpEditEngine->SetDefaultHorizontalTextDirection(
943  pDoc->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  pTipVisibleParent = pActiveView->GetWindow();
1254  vcl::Cursor* pCur = pActiveView->GetCursor();
1255  if (pCur)
1256  aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
1257  aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
1258  tools::Rectangle aRect( aPos, aPos );
1259 
1260  QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
1261  nTipVisible = Help::ShowPopover(pTipVisibleParent, aRect, rText, nAlign);
1262  pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
1263 }
1264 
1265 void ScInputHandler::ShowTipBelow( const OUString& rText )
1266 {
1267  HideTipBelow();
1268 
1269  EditView* pActiveView = pTopView ? pTopView : pTableView;
1270  if ( !pActiveView )
1271  return;
1272 
1273  Point aPos;
1274  pTipVisibleSecParent = pActiveView->GetWindow();
1275  vcl::Cursor* pCur = pActiveView->GetCursor();
1276  if ( pCur )
1277  {
1278  Point aLogicPos = pCur->GetPos();
1279  aLogicPos.AdjustY(pCur->GetHeight() );
1280  aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
1281  }
1282  aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
1283  tools::Rectangle aRect( aPos, aPos );
1284  QuickHelpFlags const nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
1285  nTipVisibleSec = Help::ShowPopover(pTipVisibleSecParent, aRect, rText, nAlign);
1286  pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1287 }
1288 
1289 bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
1290 {
1291  if ( aStart.isEmpty() )
1292  return false;
1293 
1294  aStart = ScGlobal::getCharClassPtr()->uppercase( aStart );
1295  sal_Int32 nPos = aStart.getLength() - 1;
1296  sal_Unicode c = aStart[ nPos ];
1297  // fdo#75264 use maFormulaChar to check if characters are used in function names
1298  ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
1299  if ( p == maFormulaChar.end() )
1300  return false; // last character is not part of any function name, quit
1301 
1302  ::std::vector<sal_Unicode> aTemp;
1303  aTemp.push_back( c );
1304  for(sal_Int32 i = nPos - 1; i >= 0; --i)
1305  {
1306  c = aStart[ i ];
1307  p = maFormulaChar.find( c );
1308 
1309  if (p == maFormulaChar.end())
1310  break;
1311 
1312  aTemp.push_back( c );
1313  }
1314 
1315  ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
1316  aResult = OUString( *rIt++ );
1317  while ( rIt != aTemp.rend() )
1318  aResult += OUStringChar( *rIt++ );
1319 
1320  return true;
1321 }
1322 
1323 namespace {
1325  OString escapeJSON(const OUString &aStr)
1326  {
1327  OUString aEscaped = aStr;
1328  aEscaped = aEscaped.replaceAll("\n", " ");
1329  aEscaped = aEscaped.replaceAll("\"", "'");
1330  return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
1331  }
1332 }
1333 
1334 void ScInputHandler::ShowFuncList( const ::std::vector< OUString > & rFuncStrVec )
1335 {
1336  const SfxViewShell* pViewShell = SfxViewShell::Current();
1338  pViewShell && pViewShell->isLOKMobilePhone())
1339  {
1340  if (rFuncStrVec.size())
1341  {
1342  auto aPos = pFormulaData->begin();
1343  sal_uInt32 nCurIndex = std::distance(aPos, miAutoPosFormula);
1344  const sal_uInt32 nSize = pFormulaData->size();
1345 
1346  OUString aFuncNameStr;
1347  OUString aDescFuncNameStr;
1348  OStringBuffer aPayload;
1349  aPayload.append("[ ");
1350  for (const OUString& rFunc : rFuncStrVec)
1351  {
1352  if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
1353  {
1354  aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
1355  }
1356  else
1357  {
1358  aFuncNameStr = rFunc;
1359  }
1360 
1362  aDescFuncNameStr = aFuncNameStr + "()";
1363  sal_Int32 nNextFStart = 0;
1364  const IFunctionDescription* ppFDesc;
1365  ::std::vector< OUString > aArgs;
1366  OUString eqPlusFuncName = "=" + aDescFuncNameStr;
1367  if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
1368  {
1369  if ( !ppFDesc->getFunctionName().isEmpty() )
1370  {
1371  aPayload.append("{");
1372  aPayload.append("\"index\": ");
1373  aPayload.append(OString::number(nCurIndex));
1374  aPayload.append(", ");
1375  aPayload.append("\"signature\": \"");
1376  aPayload.append(escapeJSON(ppFDesc->getSignature()));
1377  aPayload.append("\", ");
1378  aPayload.append("\"description\": \"");
1379  aPayload.append(escapeJSON(ppFDesc->getDescription()));
1380  aPayload.append("\"}, ");
1381  }
1382  }
1383  ++nCurIndex;
1384  if (nCurIndex == nSize)
1385  nCurIndex = 0;
1386  }
1387  sal_Int32 nLen = aPayload.getLength();
1388  aPayload[nLen - 2] = ' ';
1389  aPayload[nLen - 1] = ']';
1390 
1391  OString s = aPayload.makeStringAndClear();
1392  pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s.getStr());
1393  }
1394  return;
1395  }
1396 
1397  OUStringBuffer aTipStr;
1398  OUString aFuncNameStr;
1399  OUString aDescFuncNameStr;
1400  ::std::vector<OUString>::const_iterator itStr = rFuncStrVec.begin();
1401  sal_Int32 nMaxFindNumber = 3;
1402  sal_Int32 nRemainFindNumber = nMaxFindNumber;
1403  for ( ; itStr != rFuncStrVec.end(); ++itStr )
1404  {
1405  const OUString& rFunc = *itStr;
1406  if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
1407  {
1408  aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
1409  }
1410  else
1411  {
1412  aFuncNameStr = rFunc;
1413  }
1414  if ( itStr == rFuncStrVec.begin() )
1415  {
1416  aTipStr = "[";
1417  aDescFuncNameStr = aFuncNameStr + "()";
1418  }
1419  else
1420  {
1421  aTipStr.append(", ");
1422  }
1423  aTipStr.append(aFuncNameStr);
1424  if ( itStr == rFuncStrVec.begin() )
1425  aTipStr.append("]");
1426  if ( --nRemainFindNumber <= 0 )
1427  break;
1428  }
1429  sal_Int32 nRemainNumber = rFuncStrVec.size() - nMaxFindNumber;
1430  if ( nRemainFindNumber == 0 && nRemainNumber > 0 )
1431  {
1432  OUString aMessage( ScResId( STR_FUNCTIONS_FOUND ) );
1433  aMessage = aMessage.replaceFirst("%2", OUString::number(nRemainNumber));
1434  aMessage = aMessage.replaceFirst("%1", aTipStr.makeStringAndClear());
1435  aTipStr = aMessage;
1436  }
1438  sal_Int32 nNextFStart = 0;
1439  const IFunctionDescription* ppFDesc;
1440  ::std::vector< OUString > aArgs;
1441  OUString eqPlusFuncName = "=" + aDescFuncNameStr;
1442  if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
1443  {
1444  if ( !ppFDesc->getFunctionName().isEmpty() )
1445  {
1446  aTipStr.append(" : ").append(ppFDesc->getDescription());
1447  }
1448  }
1449  ShowTip( aTipStr.makeStringAndClear() );
1450 }
1451 
1453 {
1454  EditView* pActiveView = pTopView ? pTopView : pTableView;
1455 
1456  // Formulas may only have 1 paragraph
1457  if ( !(pActiveView && pFormulaData && mpEditEngine->GetParagraphCount() == 1) )
1458  return;
1459 
1460  OUString aParagraph = mpEditEngine->GetText( 0 );
1461  ESelection aSel = pActiveView->GetSelection();
1462  aSel.Adjust();
1463 
1464  // Due to differences between table and input cell (e.g clipboard with line breaks),
1465  // the selection may not be in line with the EditEngine anymore.
1466  // Just return without any indication as to why.
1467  if ( aSel.nEndPos > aParagraph.getLength() )
1468  return;
1469 
1470  if ( aParagraph.getLength() > aSel.nEndPos &&
1471  ( ScGlobal::getCharClassPtr()->isLetterNumeric( aParagraph, aSel.nEndPos ) ||
1472  aParagraph[ aSel.nEndPos ] == '_' ||
1473  aParagraph[ aSel.nEndPos ] == '.' ||
1474  aParagraph[ aSel.nEndPos ] == '$' ) )
1475  return;
1476 
1477  // Is the cursor at the end of a word?
1478  if ( aSel.nEndPos <= 0 )
1479  return;
1480 
1481  OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1482 
1483  OUString aText;
1484  if ( GetFuncName( aSelText, aText ) )
1485  {
1486  // function name is incomplete:
1487  // show matching functions name as tip above cell
1488  ::std::vector<OUString> aNewVec;
1489  miAutoPosFormula = pFormulaData->end();
1490  miAutoPosFormula = findTextAll(*pFormulaData, miAutoPosFormula, aText, aNewVec, false);
1491  if (miAutoPosFormula != pFormulaData->end())
1492  {
1493  // check if partial function name is not between quotes
1494  sal_Unicode cBetweenQuotes = 0;
1495  for ( int n = 0; n < aSelText.getLength(); n++ )
1496  {
1497  if (cBetweenQuotes)
1498  {
1499  if (aSelText[n] == cBetweenQuotes)
1500  cBetweenQuotes = 0;
1501  }
1502  else if ( aSelText[ n ] == '"' )
1503  cBetweenQuotes = '"';
1504  else if ( aSelText[ n ] == '\'' )
1505  cBetweenQuotes = '\'';
1506  }
1507  if ( cBetweenQuotes )
1508  return; // we're between quotes
1509 
1510  ShowFuncList(aNewVec);
1511  aAutoSearch = aText;
1512  }
1513  return;
1514  }
1515 
1516  // function name is complete:
1517  // show tip below the cell with function name and arguments of function
1518  ShowArgumentsTip( aSelText );
1519 }
1520 
1522 {
1523  EditView* pActiveView = pTopView ? pTopView : pTableView;
1524  if ( pActiveView && pFormulaData )
1525  {
1526  ::std::vector<OUString> aNewVec;
1527  ScTypedCaseStrSet::const_iterator itNew = findTextAll(*pFormulaData, miAutoPosFormula, aAutoSearch, aNewVec, bBack);
1528  if (itNew != pFormulaData->end())
1529  {
1530  miAutoPosFormula = itNew;
1531  ShowFuncList( aNewVec );
1532  }
1533  }
1534 
1535  // For Tab we always call HideCursor first
1536  if (pActiveView)
1537  pActiveView->ShowCursor();
1538 }
1539 
1540 namespace {
1541 
1542 void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
1543 {
1544  if (!pView)
1545  return;
1546 
1547  ESelection aSel = pView->GetSelection();
1548 
1549  bool bNoInitialLetter = false;
1550  OUString aOld = pView->GetEditEngine()->GetText(0);
1551  // in case we want just insert a function and not completing
1553  {
1554  ESelection aSelRange = aSel;
1555  --aSelRange.nStartPos;
1556  --aSelRange.nEndPos;
1557  pView->SetSelection(aSelRange);
1558  pView->SelectCurrentWord();
1559 
1560  if ( aOld == "=" )
1561  {
1562  bNoInitialLetter = true;
1563  aSelRange.nStartPos = 1;
1564  aSelRange.nEndPos = 1;
1565  pView->SetSelection(aSelRange);
1566  }
1567  else if ( pView->GetSelected().startsWith("()") )
1568  {
1569  bNoInitialLetter = true;
1570  ++aSelRange.nStartPos;
1571  ++aSelRange.nEndPos;
1572  pView->SetSelection(aSelRange);
1573  }
1574  }
1575 
1576  if(!bNoInitialLetter)
1577  {
1578  const sal_Int32 nMinLen = std::max(aSel.nEndPos - aSel.nStartPos, sal_Int32(1));
1579  // Since transliteration service is used to test for match, the replaced string could be
1580  // longer than rInsert, so in order to find longest match before the cursor, test whole
1581  // string from start to current cursor position (don't limit to length of rInsert)
1582  // Disclaimer: I really don't know if a match longer than rInsert is actually possible,
1583  // so the above is based on assumptions how "transliteration" might possibly work. If
1584  // it's in fact impossible, an optimization would be useful to limit aSel.nStartPos to
1585  // std::max(sal_Int32(0), aSel.nEndPos - rInsert.getLength()).
1586  aSel.nStartPos = 0;
1587  pView->SetSelection(aSel);
1588  const OUString aAll = pView->GetSelected();
1589  OUString aMatch;
1590  for (sal_Int32 n = aAll.getLength(); n >= nMinLen && aMatch.isEmpty(); --n)
1591  {
1592  const OUString aTest = aAll.copy(aAll.getLength() - n); // n trailing chars
1593  if (ScGlobal::GetpTransliteration()->isMatch(aTest, rInsert))
1594  aMatch = aTest; // Found => break the loop
1595  }
1596 
1597  aSel.nStartPos = aSel.nEndPos - aMatch.getLength();
1598  pView->SetSelection(aSel);
1599  }
1600 
1601  OUString aInsStr = rInsert;
1602  sal_Int32 nInsLen = aInsStr.getLength();
1603  bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
1604  && aInsStr[nInsLen-1] == ')' );
1605  if ( bDoParen )
1606  {
1607  // Do not insert parentheses after function names if there already are some
1608  // (e.g. if the function name was edited).
1609  ESelection aWordSel = pView->GetSelection();
1610 
1611  // aWordSel.EndPos points one behind string if word at end
1612  if (aWordSel.nEndPos < aOld.getLength())
1613  {
1614  sal_Unicode cNext = aOld[aWordSel.nEndPos];
1615  if ( cNext == '(' )
1616  {
1617  bDoParen = false;
1618  aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
1619  }
1620  }
1621  }
1622 
1623  pView->InsertText( aInsStr );
1624 
1625  if ( bDoParen ) // Put cursor between parentheses
1626  {
1627  aSel = pView->GetSelection();
1628  --aSel.nStartPos;
1629  --aSel.nEndPos;
1630  pView->SetSelection(aSel);
1631 
1632  rParInserted = true;
1633  }
1634 }
1635 
1636 }
1637 
1639 {
1640  if (pFormulaData && miAutoPosFormula != pFormulaData->end())
1641  {
1643  OUString aInsert = rData.GetString();
1644  if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
1645  aInsert = aInsert.copy( 0, aInsert.getLength()-1) + "()";
1646  bool bParInserted = false;
1647 
1648  DataChanging(); // Cannot be new
1649  completeFunction( pTopView, aInsert, bParInserted );
1650  completeFunction( pTableView, aInsert, bParInserted );
1651  DataChanged();
1652  ShowTipCursor();
1653 
1654  if (bParInserted)
1655  AutoParAdded();
1656  }
1657 
1658  HideTip();
1659 
1660  EditView* pActiveView = pTopView ? pTopView : pTableView;
1661  if (pActiveView)
1662  pActiveView->ShowCursor();
1663 }
1664 
1665 void ScInputHandler::LOKPasteFunctionData(const OUString& rFunctionName)
1666 {
1667  if (!(pActiveViewSh && (pTopView || pTableView)))
1668  return;
1669 
1670  bool bEdit = false;
1671  OUString aFormula;
1672  EditView* pEditView = pTopView ? pTopView : pTableView;
1673  const EditEngine* pEditEngine = pEditView->GetEditEngine();
1674  if (pEditEngine)
1675  {
1676  aFormula = pEditEngine->GetText(0);
1677  bEdit = aFormula.getLength() > 1 && (aFormula[0] == '=' || aFormula[0] == '+' || aFormula[0] == '-');
1678  }
1679 
1680  if ( !bEdit )
1681  {
1682  OUString aNewFormula('=');
1683  if ( aFormula.startsWith("=") )
1684  aNewFormula = aFormula;
1685 
1686  InputReplaceSelection( aNewFormula );
1687  }
1688 
1689  if (pFormulaData)
1690  {
1691  OUString aNew;
1692  ScTypedCaseStrSet::const_iterator aPos = findText(*pFormulaData, pFormulaData->begin(), rFunctionName, aNew, /* backward = */false);
1693 
1694  if (aPos != pFormulaData->end())
1695  {
1696  miAutoPosFormula = aPos;
1698  }
1699  }
1700 }
1701 
1702 // Calculate selection and display as tip help
1703 static OUString lcl_Calculate( const OUString& rFormula, ScDocument* pDoc, const ScAddress &rPos )
1704 {
1705  //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1706  // Quotation marks for Strings are only inserted here.
1707 
1708  if(rFormula.isEmpty())
1709  return OUString();
1710 
1711  std::unique_ptr<ScSimpleFormulaCalculator> pCalc( new ScSimpleFormulaCalculator( pDoc, rPos, rFormula, false ) );
1712 
1713  // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1714  // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1715  bool bColRowName = pCalc->HasColRowName();
1716  if ( bColRowName )
1717  {
1718  // ColRowName in RPN code?
1719  if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1720  { // ==1: Single one is as a Parameter always a Range
1721  // ==0: It might be one, if ...
1722  OUString aBraced = "(" + rFormula + ")";
1723  pCalc.reset( new ScSimpleFormulaCalculator( pDoc, rPos, aBraced, false ) );
1724  }
1725  else
1726  bColRowName = false;
1727  }
1728 
1729  FormulaError nErrCode = pCalc->GetErrCode();
1730  if ( nErrCode != FormulaError::NONE )
1731  return ScGlobal::GetErrorString(nErrCode);
1732 
1733  SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
1734  OUString aValue;
1735  if ( pCalc->IsValue() )
1736  {
1737  double n = pCalc->GetValue();
1738  sal_uInt32 nFormat = aFormatter.GetStandardFormat( n, 0,
1739  pCalc->GetFormatType(), ScGlobal::eLnge );
1740  aFormatter.GetInputLineString( n, nFormat, aValue );
1742  }
1743  else
1744  {
1745  OUString aStr = pCalc->GetString().getString();
1746  sal_uInt32 nFormat = aFormatter.GetStandardFormat(
1747  pCalc->GetFormatType(), ScGlobal::eLnge);
1748  {
1749  Color* pColor;
1750  aFormatter.GetOutputString( aStr, nFormat,
1751  aValue, &pColor );
1752  }
1753 
1754  aValue = "\"" + aValue + "\"";
1756  }
1757 
1758  ScRange aTestRange;
1759  if ( bColRowName || (aTestRange.Parse(rFormula) & ScRefFlags::VALID) )
1760  aValue += " ...";
1761 
1762  return aValue;
1763 }
1764 
1766 {
1767  OUString aValue;
1768  EditView* pActiveView = pTopView ? pTopView : pTableView;
1769  if ( pActiveView && pActiveViewSh )
1770  {
1771  OUString aPart = pActiveView->GetSelected();
1772  if (aPart.isEmpty())
1773  aPart = mpEditEngine->GetText(0);
1775  aValue = lcl_Calculate( aPart, &rDoc, aCursorPos );
1776  }
1777 
1778  if (!aValue.isEmpty())
1779  {
1780  ShowTip( aValue ); // Display as QuickHelp
1781  aManualTip = aValue; // Set after ShowTip
1782  if (pFormulaData)
1783  miAutoPosFormula = pFormulaData->end();
1784  if (pColumnData)
1785  miAutoPosColumn = pColumnData->end();
1786  }
1787 }
1788 
1790 {
1791  // Three dots at the end -> Range reference -> do not insert
1792  // FIXME: Once we have matrix constants, we can change this
1793  sal_Int32 nTipLen = aManualTip.getLength();
1794  sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1795  if ( nTipLen && ( nTipLen < 3 || aManualTip.copy( nTipLen2-3 ) != "..." ) )
1796  {
1797  DataChanging(); // Cannot be new
1798 
1799  OUString aInsert = aManualTip;
1800  EditView* pActiveView = pTopView ? pTopView : pTableView;
1801  if (!pActiveView->HasSelection())
1802  {
1803  // Nothing selected -> select everything
1804  sal_Int32 nOldLen = mpEditEngine->GetTextLen(0);
1805  ESelection aAllSel( 0, 0, 0, nOldLen );
1806  if ( pTopView )
1807  pTopView->SetSelection( aAllSel );
1808  if ( pTableView )
1809  pTableView->SetSelection( aAllSel );
1810  }
1811 
1812  ESelection aSel = pActiveView->GetSelection();
1813  aSel.Adjust();
1814  OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1815  if ( !aSel.nStartPos ) // Selection from the start?
1816  {
1817  if ( aSel.nEndPos == mpEditEngine->GetTextLen(0) )
1818  {
1819  // Everything selected -> skip quotation marks
1820  if ( aInsert[0] == '"' )
1821  aInsert = aInsert.copy(1);
1822  sal_Int32 nInsLen = aInsert.getLength();
1823  if ( aInsert.endsWith("\"") )
1824  aInsert = aInsert.copy( 0, nInsLen-1 );
1825  }
1826  else if ( aSel.nEndPos )
1827  {
1828  // Not everything selected -> do not overwrite equality sign
1829  //FIXME: Even double equality signs??
1830  aSel.nStartPos = 1;
1831  if ( pTopView )
1832  pTopView->SetSelection( aSel );
1833  if ( pTableView )
1834  pTableView->SetSelection( aSel );
1835  }
1836  }
1837  if ( pTopView )
1838  pTopView->InsertText( aInsert, true );
1839  if ( pTableView )
1840  pTableView->InsertText( aInsert, true );
1841 
1842  DataChanged();
1843  }
1844 
1845  HideTip();
1846 }
1847 
1849 {
1850  nAutoPar = 0;
1851 }
1852 
1854 {
1855  ++nAutoPar; // Closing parenthesis can be overwritten
1856 }
1857 
1859 {
1860  // Test if the cursor is before a closing parenthesis
1861  // Selection from SetReference has been removed before
1862  EditView* pActiveView = pTopView ? pTopView : pTableView;
1863  if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1864  {
1865  ESelection aSel = pActiveView->GetSelection();
1866  sal_Int32 nPos = aSel.nStartPos;
1867  OUString aFormula = mpEditEngine->GetText(0);
1868  if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1869  return true;
1870  }
1871  return false;
1872 }
1873 
1875 {
1876  // this is called when a ')' is typed and the cursor is before a ')'
1877  // that can be overwritten -> just set the cursor behind the ')'
1878 
1879  EditView* pActiveView = pTopView ? pTopView : pTableView;
1880  if (pActiveView)
1881  {
1882  ESelection aSel = pActiveView->GetSelection();
1883  ++aSel.nStartPos;
1884  ++aSel.nEndPos;
1885 
1886  // this is in a formula (only one paragraph), so the selection
1887  // can be used directly for the TopView
1888 
1889  if ( pTopView )
1890  pTopView->SetSelection( aSel );
1891  if ( pTableView )
1892  pTableView->SetSelection( aSel );
1893  }
1894 
1895  OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
1896  --nAutoPar;
1897 }
1898 
1899 // Auto input
1900 
1902 {
1903  if ( !pActiveViewSh )
1904  return;
1905 
1907 
1908  if ( pColumnData )
1909  pColumnData->clear();
1910  else
1911  pColumnData.reset( new ScTypedCaseStrSet );
1912 
1913  std::vector<ScTypedStrData> aEntries;
1914  rDoc.GetDataEntries(
1916  if (!aEntries.empty())
1917  pColumnData->insert(aEntries.begin(), aEntries.end());
1918 
1919  miAutoPosColumn = pColumnData->end();
1920 }
1921 
1922 void ScInputHandler::UseColData() // When typing
1923 {
1924  EditView* pActiveView = pTopView ? pTopView : pTableView;
1925  if ( !(pActiveView && pColumnData) )
1926  return;
1927 
1928  // Only change when cursor is at the end
1929  ESelection aSel = pActiveView->GetSelection();
1930  aSel.Adjust();
1931 
1932  sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
1933  if ( aSel.nEndPara+1 != nParCnt )
1934  return;
1935 
1936  sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
1937  if ( aSel.nEndPos != nParLen )
1938  return;
1939 
1940  OUString aText = GetEditText(mpEditEngine.get());
1941  if (aText.isEmpty())
1942  return;
1943 
1944  OUString aNew;
1945  miAutoPosColumn = pColumnData->end();
1946  miAutoPosColumn = findText(*pColumnData, miAutoPosColumn, aText, aNew, false);
1947  if (miAutoPosColumn != pColumnData->end())
1948  {
1949  // Strings can contain line endings (e.g. due to dBase import),
1950  // which would result in multiple paragraphs here, which is not desirable.
1952  lcl_RemoveLineEnd( aNew );
1953 
1954  // Keep paragraph, just append the rest
1956  // One Space between paragraphs:
1957  sal_Int32 nEdLen = mpEditEngine->GetTextLen() + nParCnt - 1;
1958  OUString aIns = aNew.copy(nEdLen);
1959 
1960  // Selection must be "backwards", so the cursor stays behind the last
1961  // typed character
1962  ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
1963  aSel.nEndPara, aSel.nEndPos );
1964 
1965  // When editing in input line, apply to both edit views
1966  if ( pTableView )
1967  {
1968  pTableView->InsertText( aIns );
1969  pTableView->SetSelection( aSelection );
1970  }
1971  if ( pTopView )
1972  {
1973  pTopView->InsertText( aIns );
1974  pTopView->SetSelection( aSelection );
1975  }
1976 
1977  aAutoSearch = aText; // To keep searching - nAutoPos is set
1978 
1979  if (aText.getLength() == aNew.getLength())
1980  {
1981  // If the inserted text is found, consume TAB only if there's more coming
1982  OUString aDummy;
1983  ScTypedCaseStrSet::const_iterator itNextPos =
1984  findText(*pColumnData, miAutoPosColumn, aText, aDummy, false);
1985  bUseTab = itNextPos != pColumnData->end();
1986  }
1987  else
1988  bUseTab = true;
1989  }
1990 }
1991 
1993 {
1994  EditView* pActiveView = pTopView ? pTopView : pTableView;
1995  if ( pActiveView && pColumnData )
1996  {
1997  if (miAutoPosColumn != pColumnData->end() && !aAutoSearch.isEmpty())
1998  {
1999  // Is the selection still valid (could be changed via the mouse)?
2000  ESelection aSel = pActiveView->GetSelection();
2001  aSel.Adjust();
2002  sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
2003  if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
2004  {
2005  OUString aText = GetEditText(mpEditEngine.get());
2006  sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
2007  sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
2008  if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
2009  {
2010  OUString aNew;
2011  ScTypedCaseStrSet::const_iterator itNew =
2012  findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
2013 
2014  if (itNew != pColumnData->end())
2015  {
2016  // match found!
2017  miAutoPosColumn = itNew;
2018  bInOwnChange = true; // disable ModifyHdl (reset below)
2019 
2020  lcl_RemoveLineEnd( aNew );
2021  OUString aIns = aNew.copy(aAutoSearch.getLength());
2022 
2023  // when editing in input line, apply to both edit views
2024  if ( pTableView )
2025  {
2027  pTableView->InsertText( aIns );
2029  aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2030  aSel.nEndPara, aSel.nStartPos ) );
2031  }
2032  if ( pTopView )
2033  {
2035  pTopView->InsertText( aIns );
2037  aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
2038  aSel.nEndPara, aSel.nStartPos ) );
2039  }
2040 
2041  bInOwnChange = false;
2042  }
2043  }
2044  }
2045  }
2046  }
2047 
2048  // For Tab, HideCursor was always called first
2049  if (pActiveView)
2050  pActiveView->ShowCursor();
2051 }
2052 
2053 // Highlight parentheses
2055 {
2056  // Find parentheses
2057  //TODO: Can we disable parentheses highlighting per parentheses?
2058  bool bFound = false;
2059  if ( bFormulaMode && eMode != SC_INPUT_TOP )
2060  {
2061  if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
2062  {
2064  if (aSel.nStartPos)
2065  {
2066  // Examine character left to the cursor
2067  sal_Int32 nPos = aSel.nStartPos - 1;
2068  OUString aFormula = mpEditEngine->GetText(0);
2069  sal_Unicode c = aFormula[nPos];
2070  if ( c == '(' || c == ')' )
2071  {
2072  sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
2073  if ( nOther != -1 )
2074  {
2075  SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
2076  aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
2077 
2079  if (bParenthesisShown)
2080  {
2081  // Remove old highlighting
2082  sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2083  for (sal_Int32 i=0; i<nCount; i++)
2084  mpEditEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
2085  }
2086 
2087  ESelection aSelThis( 0,nPos, 0,nPos+1 );
2088  mpEditEngine->QuickSetAttribs( aSet, aSelThis );
2089  ESelection aSelOther( 0,nOther, 0,nOther+1 );
2090  mpEditEngine->QuickSetAttribs( aSet, aSelOther );
2091 
2092  // Dummy InsertText for Update and Paint (selection is empty)
2094 
2095  bFound = true;
2096  }
2097  }
2098  }
2099 
2100  // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
2101  // with different color (COL_LIGHTBLUE) ??
2102  }
2103  }
2104 
2105  // Remove old highlighting, if no new one is set
2106  if ( bParenthesisShown && !bFound && pTableView )
2107  {
2108  sal_Int32 nCount = mpEditEngine->GetParagraphCount();
2109  for (sal_Int32 i=0; i<nCount; i++)
2111  }
2112 
2113  bParenthesisShown = bFound;
2114 }
2115 
2116 void ScInputHandler::ViewShellGone(const ScTabViewShell* pViewSh) // Executed synchronously!
2117 {
2118  if ( pViewSh == pActiveViewSh )
2119  {
2120  pLastState.reset();
2121  pLastPattern = nullptr;
2122  }
2123 
2124  if ( pViewSh == pRefViewSh )
2125  {
2127  // We end the EditMode anyways
2128  EnterHandler();
2129  bFormulaMode = false;
2130  pRefViewSh = nullptr;
2131  SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2132  SC_MOD()->SetRefInputHdl(nullptr);
2133  if (pInputWin)
2134  pInputWin->SetFormulaMode(false);
2136  }
2137 
2138  pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2139 
2140  if ( pActiveViewSh && pActiveViewSh == pViewSh )
2141  {
2142  OSL_FAIL("pActiveViewSh is gone");
2143  pActiveViewSh = nullptr;
2144  }
2145 
2146  if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
2147  UpdateRefDevice(); // Don't keep old document's printer as RefDevice
2148 }
2149 
2151 {
2153 
2154  // #i20588# Don't rely on focus to find the active edit view. Instead, the
2155  // active pane at the start of editing is now stored (GetEditActivePart).
2156  // GetActiveWin (the currently active pane) fails for ref input across the
2157  // panes of a split view.
2158 
2159  vcl::Window* pShellWin = pActiveViewSh ?
2161  nullptr;
2162 
2163  sal_uInt16 nCount = mpEditEngine->GetViewCount();
2164  if (nCount > 0)
2165  {
2166  pTableView = mpEditEngine->GetView();
2167  for (sal_uInt16 i=1; i<nCount; i++)
2168  {
2169  EditView* pThis = mpEditEngine->GetView(i);
2170  vcl::Window* pWin = pThis->GetWindow();
2171  if ( pWin==pShellWin )
2172  pTableView = pThis;
2173  }
2174  }
2175  else
2176  pTableView = nullptr;
2177 
2178  // setup the pTableView editeng for tiled rendering to get cursor and selections
2179  if (pTableView && pActiveViewSh)
2180  {
2182  {
2184  }
2185  }
2186 
2187  if (pInputWin && (eMode == SC_INPUT_TOP || eMode == SC_INPUT_TABLE))
2188  {
2189  // tdf#71409: Always create the edit engine instance for the input
2190  // window, in order to properly manage accessibility events.
2192  if (eMode != SC_INPUT_TOP)
2193  pTopView = nullptr;
2194  }
2195  else
2196  pTopView = nullptr;
2197 }
2198 
2200 {
2201  pInputWin = pNew;
2202 }
2203 
2205 {
2206  if (pInputWin && !pInputWin->IsDisposed())
2207  pInputWin->StopEditEngine( bAll );
2208 
2209  pTopView = nullptr; // invalid now
2210 }
2211 
2213 {
2214  UpdateActiveView();
2215  return pTopView ? pTopView : pTableView;
2216 }
2217 
2219 {
2220  pLastPattern = nullptr;
2221  if ( !pLastState && pActiveViewSh )
2222  pActiveViewSh->UpdateInputHandler( true ); // Get status again
2223  else
2224  NotifyChange( pLastState.get(), true );
2225 }
2226 
2228 {
2229  SvxAdjust eSvxAdjust;
2230  switch (eAttrAdjust)
2231  {
2232  case SvxCellHorJustify::Standard:
2233  {
2234  bool bNumber = false;
2235  if (cTyped) // Restarted
2236  bNumber = (cTyped>='0' && cTyped<='9'); // Only ciphers are numbers
2237  else if ( pActiveViewSh )
2238  {
2240  bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
2241  }
2242  eSvxAdjust = bNumber ? SvxAdjust::Right : SvxAdjust::Left;
2243  }
2244  break;
2245  case SvxCellHorJustify::Block:
2246  eSvxAdjust = SvxAdjust::Block;
2247  break;
2248  case SvxCellHorJustify::Center:
2249  eSvxAdjust = SvxAdjust::Center;
2250  break;
2251  case SvxCellHorJustify::Right:
2252  eSvxAdjust = SvxAdjust::Right;
2253  break;
2254  default: // SvxCellHorJustify::Left
2255  eSvxAdjust = SvxAdjust::Left;
2256  break;
2257  }
2258 
2259  bool bAsianVertical = pLastPattern &&
2260  pLastPattern->GetItem( ATTR_STACKED ).GetValue() &&
2261  pLastPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue();
2262  if ( bAsianVertical )
2263  {
2264  // Always edit at top of cell -> LEFT when editing vertically
2265  eSvxAdjust = SvxAdjust::Left;
2266  }
2267 
2268  pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
2269  mpEditEngine->SetDefaults( *pEditDefaults );
2270 
2271  if ( pActiveViewSh )
2272  {
2273  pActiveViewSh->GetViewData().SetEditAdjust( eSvxAdjust );
2274  }
2275  mpEditEngine->SetVertical( bAsianVertical );
2276 }
2277 
2279 {
2280  // Delete hard alignment attributes
2281  bool bUndo = mpEditEngine->IsUndoEnabled();
2282  if ( bUndo )
2283  mpEditEngine->EnableUndo( false );
2284 
2285  // Non-default paragraph attributes (e.g. from clipboard)
2286  // must be turned into character attributes
2287  mpEditEngine->RemoveParaAttribs();
2288 
2289  if ( bUndo )
2290  mpEditEngine->EnableUndo( true );
2291 
2292 }
2293 
2295 {
2296  // Delete pRangeFindList and colors
2297  mpEditEngine->SetUpdateMode(false);
2298  sal_Int32 nCount = mpEditEngine->GetParagraphCount(); // Could just have been inserted
2299  for (sal_Int32 i=0; i<nCount; i++)
2300  mpEditEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
2301  mpEditEngine->SetUpdateMode(true);
2302 
2303  EditView* pActiveView = pTopView ? pTopView : pTableView;
2304  pActiveView->ShowCursor( false );
2305 
2306  DeleteRangeFinder(); // Deletes the list and the labels on the table
2307 }
2308 
2309 bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
2310  ScEditEngineDefaulter* pTopEngine )
2311 {
2312  bool bNewTable = false;
2313 
2314  if (bModified)
2315  return false;
2316 
2317  if (pActiveViewSh)
2318  {
2320 
2321  if (!rDoc.ValidCol(aCursorPos.Col()))
2322  return false;
2323 
2325  UpdateActiveView();
2326  SyncViews();
2327 
2328 
2329  const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
2330  ScEditableTester aTester;
2331  if ( rMark.IsMarked() || rMark.IsMultiMarked() )
2332  aTester.TestSelection( &rDoc, rMark );
2333  else
2334  aTester.TestSelectedBlock(
2335  &rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
2336 
2337  bool bStartInputMode = true;
2338 
2339  if (!aTester.IsEditable())
2340  {
2341  bProtected = true;
2342  // We allow read-only input mode activation regardless
2343  // whether it's part of an array or not or whether explicit cell
2344  // activation is requested (double-click or F2) or a click in input
2345  // line.
2346  bool bShowError = (!bInputActivated || !aTester.GetMessageId() || strcmp(aTester.GetMessageId(), STR_PROTECTIONERR) != 0) &&
2348  if (bShowError)
2349  {
2350  eMode = SC_INPUT_NONE;
2351  StopInputWinEngine( true );
2353  if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
2354  {
2355  // Prevent repeated error messages for the same cell from command events
2356  // (for keyboard events, multiple messages are wanted).
2357  // Set the flag before showing the error message because the command handler
2358  // for the next IME command may be called when showing the dialog.
2359  if ( bFromCommand )
2360  bCommandErrorShown = true;
2361 
2364  }
2365  bStartInputMode = false;
2366  }
2367  }
2368 
2369  if (bStartInputMode)
2370  {
2371  // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
2372  mpEditEngine->SetUpdateMode( false );
2373 
2374  // Take over attributes in EditEngine
2375  const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
2376  aCursorPos.Row(),
2377  aCursorPos.Tab() );
2378  if (pPattern != pLastPattern)
2379  {
2380  // Percent format?
2381  const SfxItemSet& rAttrSet = pPattern->GetItemSet();
2382  const SfxPoolItem* pItem;
2383 
2384  if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, true, &pItem ) )
2385  {
2386  sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
2387  if (SvNumFormatType::PERCENT == rDoc.GetFormatTable()->GetType( nFormat ))
2388  nCellPercentFormatDecSep = rDoc.GetFormatTable()->GetFormatDecimalSep( nFormat).toChar();
2389  else
2391  }
2392  else
2393  nCellPercentFormatDecSep = 0; // Default: no percent
2394 
2395  // Validity specified?
2396  if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALIDDATA, true, &pItem ) )
2397  nValidation = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
2398  else
2399  nValidation = 0;
2400 
2401  // EditEngine Defaults
2402  // In no case SetParaAttribs, because the EditEngine might already
2403  // be filled (for Edit cells).
2404  // SetParaAttribs would change the content.
2405 
2409 
2410  pPattern->FillEditItemSet( pEditDefaults.get() );
2411  mpEditEngine->SetDefaults( *pEditDefaults );
2412  pLastPattern = pPattern;
2413  bLastIsSymbol = pPattern->IsSymbolFont();
2414 
2415  // Background color must be known for automatic font color.
2416  // For transparent cell background, the document background color must be used.
2417 
2418  Color aBackCol = pPattern->GetItem( ATTR_BACKGROUND ).GetColor();
2419  ScModule* pScMod = SC_MOD();
2420  if ( aBackCol.GetTransparency() > 0 ||
2422  aBackCol = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2423  mpEditEngine->SetBackgroundColor( aBackCol );
2424 
2425  // Adjustment
2426  eAttrAdjust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
2427  if ( eAttrAdjust == SvxCellHorJustify::Repeat &&
2428  pPattern->GetItem(ATTR_LINEBREAK).GetValue() )
2429  {
2430  // #i31843# "repeat" with "line breaks" is treated as default alignment
2431  eAttrAdjust = SvxCellHorJustify::Standard;
2432  }
2433  }
2434 
2435  if (pTopEngine)
2436  {
2437  // Necessary to sync SvxAutoCorrect behavior. This has to be
2438  // done before InitRangeFinder() below.
2439  MergeLanguageAttributes( *pTopEngine);
2440  }
2441 
2442  // UpdateSpellSettings enables online spelling if needed
2443  // -> also call if attributes are unchanged
2444  UpdateSpellSettings( true ); // uses pLastPattern
2445 
2446  // Fill EditEngine
2447  OUString aStr;
2448  if (bTextValid)
2449  {
2450  mpEditEngine->SetTextCurrentDefaults(aCurrentText);
2451  aStr = aCurrentText;
2452  bTextValid = false;
2453  aCurrentText.clear();
2454  }
2455  else
2456  aStr = GetEditText(mpEditEngine.get());
2457 
2458  if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
2459  {
2460  aStr = aStr.copy(1, aStr.getLength() -2);
2461  mpEditEngine->SetTextCurrentDefaults(aStr);
2462  if ( pInputWin )
2463  pInputWin->SetTextString(aStr);
2464  }
2465 
2466  UpdateAdjust( cTyped );
2467 
2468  if ( bAutoComplete )
2469  GetColData();
2470 
2471  if ( !aStr.isEmpty() && ( aStr[0] == '=' || aStr[0] == '+' || aStr[0] == '-' ) &&
2472  !cTyped && !bCreatingFuncView )
2473  InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
2474 
2475  bNewTable = true; // -> PostEditView Call
2476  }
2477  }
2478 
2479  if (!bProtected && pInputWin)
2481 
2482  return bNewTable;
2483 }
2484 
2486 {
2487  const SfxItemSet& rSrcSet = mpEditEngine->GetDefaults();
2488  rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE ));
2489  rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CJK ));
2490  rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CTL ));
2491 }
2492 
2493 static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
2494 {
2495  OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
2496 
2497  EditEngine* pEngine = pEditView->GetEditEngine();
2498  sal_Int32 nCount = pEngine->GetParagraphCount();
2499  if (nCount > 1)
2500  {
2501  sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2502  while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2503  {
2504  rSel.nStartPos -= nParLen + 1; // Including space from line break
2505  nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2506  }
2507 
2508  nParLen = pEngine->GetTextLen(rSel.nEndPara);
2509  while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2510  {
2511  rSel.nEndPos -= nParLen + 1; // Including space from line break
2512  nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2513  }
2514  }
2515 
2516  ESelection aSel = pEditView->GetSelection();
2517 
2518  if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2519  || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2520  pEditView->SetSelection( rSel );
2521 }
2522 
2523 void ScInputHandler::SyncViews( const EditView* pSourceView )
2524 {
2525  if (pSourceView)
2526  {
2527  bool bSelectionForTopView = false;
2528  if (pTopView && pTopView != pSourceView)
2529  bSelectionForTopView = true;
2530  bool bSelectionForTableView = false;
2531  if (pTableView && pTableView != pSourceView)
2532  bSelectionForTableView = true;
2533  if (bSelectionForTopView || bSelectionForTableView)
2534  {
2535  ESelection aSel(pSourceView->GetSelection());
2536  if (bSelectionForTopView)
2537  pTopView->SetSelection(aSel);
2538  if (bSelectionForTableView)
2540  }
2541  }
2542  // Only sync selection from topView if we are actually editing there
2543  else if (pTopView && pTableView)
2544  {
2545  ESelection aSel(pTopView->GetSelection());
2547  }
2548 }
2549 
2551 {
2552  if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2553  mpEditEngine && mpEditEngine->GetUpdateMode() && pInputWin )
2554  {
2555  // Update input line from ModifyHdl for changes that are not
2556  // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2557  OUString aText(ScEditUtil::GetMultilineString(*mpEditEngine));
2558  lcl_RemoveTabs(aText);
2559  pInputWin->SetTextString(aText);
2560  }
2561 }
2562 
2566 bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2567 {
2568  if (pActiveViewSh)
2570  bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2571 
2572  if ( eMode == SC_INPUT_NONE )
2573  return StartTable( cTyped, bFromCommand, false, nullptr );
2574  else
2575  return false;
2576 }
2577 
2578 void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2579 {
2581 
2582  if (eMode==SC_INPUT_NONE)
2583  eMode = SC_INPUT_TYPE;
2584 
2585  if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2586  {
2587  // table EditEngine is formatted below, input line needs formatting after paste
2588  // #i20282# not when called from the input line's modify handler
2590 
2591  // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2592  // can't safely access the EditEngine's current view, so the cursor has to be
2593  // shown again here.
2594  pTopView->ShowCursor();
2595  }
2596 
2597  if (bSetModified)
2598  bModified = true;
2599  bSelIsRef = false;
2600 
2601  if ( pRangeFindList && !bInRangeUpdate )
2602  RemoveRangeFinder(); // Delete attributes and labels
2603 
2604  UpdateParenthesis(); // Highlight parentheses anew
2605 
2607  {
2608  OUString aText;
2609  if (pInputWin)
2611  else
2612  aText = GetEditText(mpEditEngine.get());
2613  lcl_RemoveTabs(aText);
2614 
2615  if ( pInputWin )
2616  pInputWin->SetTextString( aText );
2617 
2619  {
2620  if (pActiveViewSh)
2621  pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aText.toUtf8().getStr());
2622  }
2623  }
2624 
2625  // If the cursor is before the end of a paragraph, parts are being pushed to
2626  // the right (independently from the eMode) -> Adapt View!
2627  // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2628  //
2629  // First make sure the status handler is called now if the cursor
2630  // is outside the visible area
2631  mpEditEngine->QuickFormatDoc();
2632 
2633  EditView* pActiveView = pTopView ? pTopView : pTableView;
2634  if (pActiveView && pActiveViewSh)
2635  {
2636  ScViewData& rViewData = pActiveViewSh->GetViewData();
2637 
2638  bool bNeedGrow = ( rViewData.GetEditAdjust() != SvxAdjust::Left ); // Always right-aligned
2639  if (!bNeedGrow)
2640  {
2641  // Cursor before the end?
2642  ESelection aSel = pActiveView->GetSelection();
2643  aSel.Adjust();
2644  bNeedGrow = ( aSel.nEndPos != mpEditEngine->GetTextLen(aSel.nEndPara) );
2645  }
2646  if (!bNeedGrow)
2647  {
2648  bNeedGrow = rViewData.GetDocument()->IsLayoutRTL( rViewData.GetTabNo() );
2649  }
2650  if (bNeedGrow)
2651  {
2652  // Adjust inplace view
2653  rViewData.EditGrowY();
2654  rViewData.EditGrowX();
2655  }
2656  }
2657 
2659  bTextValid = false; // Changes only in the EditEngine
2660  bInOwnChange = false;
2661 }
2662 
2664 {
2665  SfxApplication* pSfxApp = SfxGetpApp();
2666 
2667  bool bIsFormula = !bProtected && mpEditEngine->GetParagraphCount() == 1;
2668  if (bIsFormula)
2669  {
2670  const OUString& rText = mpEditEngine->GetText(0);
2671  bIsFormula = !rText.isEmpty() &&
2672  (rText[0] == '=' || rText[0] == '+' || rText[0] == '-');
2673  }
2674 
2675  if ( bIsFormula )
2676  {
2677  if (!bFormulaMode)
2678  {
2679  bFormulaMode = true;
2681  pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2682  SC_MOD()->SetRefInputHdl(this);
2683  if (pInputWin)
2684  pInputWin->SetFormulaMode(true);
2685 
2686  if ( bAutoComplete )
2687  GetFormulaData();
2688 
2691  }
2692  }
2693  else // Deactivate
2694  {
2695  if (bFormulaMode)
2696  {
2697  ShowRefFrame();
2698  bFormulaMode = false;
2699  pRefViewSh = nullptr;
2700  pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
2701  SC_MOD()->SetRefInputHdl(nullptr);
2702  if (pInputWin)
2703  pInputWin->SetFormulaMode(false);
2705  }
2706  }
2707 }
2708 
2710 {
2711  // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2712  // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2713  // A local variable is used instead.
2714  ScTabViewShell* pVisibleSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
2715  if ( !(pRefViewSh && pRefViewSh != pVisibleSh) )
2716  return;
2717 
2718  bool bFound = false;
2719  SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
2720  SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2721  while ( pOneFrame && !bFound )
2722  {
2723  if ( pOneFrame == pRefFrame )
2724  bFound = true;
2725  pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2726  }
2727 
2728  if (bFound)
2729  {
2730  // We count on Activate working synchronously here
2731  // (pActiveViewSh is set while doing so)
2732  pRefViewSh->SetActive(); // Appear and SetViewFrame
2733 
2734  // pLastState is set correctly in the NotifyChange from the Activate
2735  }
2736  else
2737  {
2738  OSL_FAIL("ViewFrame for reference input is not here anymore");
2739  }
2740 }
2741 
2743 {
2744  EditView* pActiveView = pTopView ? pTopView : pTableView;
2745  if (!pActiveView)
2746  return;
2747 
2748  ESelection aSel = pActiveView->GetSelection();
2749  aSel.nStartPara = aSel.nEndPara;
2750  aSel.nStartPos = aSel.nEndPos;
2751  if (pTableView)
2752  pTableView->SetSelection( aSel );
2753  if (pTopView)
2754  pTopView->SetSelection( aSel );
2755 }
2756 
2758 {
2759  SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2760  if (!pViewFrm)
2761  return;
2762 
2763  SfxBindings& rBindings = pViewFrm->GetBindings();
2764 
2765  rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2766  rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2767  rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2768 
2769  rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2770  rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2771  rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2772  rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
2773  rBindings.Invalidate( SID_ULINE_VAL_NONE );
2774  rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2775  rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2776  rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2777 
2778  rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2779 
2780  rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2781  rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2782  rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2783  rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2784  rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2785 
2786  rBindings.Invalidate( SID_SAVEDOC );
2787  rBindings.Invalidate( SID_DOC_MODIFIED );
2788 }
2789 
2790 // --------------- public methods --------------------------------------------
2791 
2792 void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText, ScEditEngineDefaulter* pTopEngine )
2793 {
2794  if ( eMode == eNewMode )
2795  return;
2796 
2798 
2799  if (bProtected)
2800  {
2801  eMode = SC_INPUT_NONE;
2802  StopInputWinEngine( true );
2803  if (pActiveViewSh)
2805  return;
2806  }
2807 
2808  if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2809  // Disable paste mode when edit mode starts.
2811 
2812  bInOwnChange = true; // disable ModifyHdl (reset below)
2813 
2814  ScInputMode eOldMode = eMode;
2815  eMode = eNewMode;
2816  if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2817  StopInputWinEngine( false );
2818 
2820  {
2821  if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2822  {
2823  if (StartTable(0, false, eMode == SC_INPUT_TABLE, pTopEngine))
2824  {
2825  if (pActiveViewSh)
2827  }
2828  }
2829 
2830  if (pInitText)
2831  {
2832  mpEditEngine->SetTextCurrentDefaults(*pInitText);
2833  bModified = true;
2834  }
2835 
2836  sal_Int32 nPara = mpEditEngine->GetParagraphCount()-1;
2837  sal_Int32 nLen = mpEditEngine->GetText(nPara).getLength();
2838  sal_uInt16 nCount = mpEditEngine->GetViewCount();
2839 
2840  for (sal_uInt16 i=0; i<nCount; i++)
2841  {
2842  if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2843  {
2844  // Keep Selection
2845  }
2846  else
2847  {
2848  mpEditEngine->GetView(i)->
2849  SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2850  }
2851  mpEditEngine->GetView(i)->ShowCursor(false);
2852  }
2853  }
2854 
2855  UpdateActiveView();
2857  {
2858  if (pTableView)
2860  }
2861  else
2862  {
2863  if (pTopView)
2865  }
2866 
2867  if (eNewMode != eOldMode)
2869 
2870  bInOwnChange = false;
2871 }
2872 
2876 static bool lcl_IsNumber(const OUString& rString)
2877 {
2878  sal_Int32 nLen = rString.getLength();
2879  for (sal_Int32 i=0; i<nLen; i++)
2880  {
2881  sal_Unicode c = rString[i];
2882  if ( c < '0' || c > '9' )
2883  return false;
2884  }
2885  return true;
2886 }
2887 
2888 static void lcl_SelectionToEnd( EditView* pView )
2889 {
2890  if ( pView )
2891  {
2892  EditEngine* pEngine = pView->GetEditEngine();
2893  sal_Int32 nParCnt = pEngine->GetParagraphCount();
2894  if ( nParCnt == 0 )
2895  nParCnt = 1;
2896  ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
2897  pView->SetSelection( aSel );
2898  }
2899 }
2900 
2902 {
2905  return;
2906 
2907  // Macro calls for validity can cause a lot of problems, so inhibit
2908  // nested calls of EnterHandler().
2909  if (bInEnterHandler) return;
2910  bInEnterHandler = true;
2911  bInOwnChange = true; // disable ModifyHdl (reset below)
2912 
2914 
2915  bool bMatrix = ( nBlockMode == ScEnterMode::MATRIX );
2916 
2917  SfxApplication* pSfxApp = SfxGetpApp();
2918  std::unique_ptr<EditTextObject> pObject;
2919  std::unique_ptr<ScPatternAttr> pCellAttrs;
2920  bool bForget = false; // Remove due to validity?
2921 
2922  OUString aString = GetEditText(mpEditEngine.get());
2923  OUString aPreAutoCorrectString(aString);
2924  EditView* pActiveView = pTopView ? pTopView : pTableView;
2925  if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
2926  {
2927  if (pColumnData && miAutoPosColumn != pColumnData->end())
2928  {
2929  // #i47125# If AutoInput appended something, do the final AutoCorrect
2930  // with the cursor at the end of the input.
2933  }
2934 
2935  vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
2936 
2937  if (pTopView)
2938  pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
2939  if (pTableView)
2940  pTableView->CompleteAutoCorrect(pFrameWin);
2941  aString = GetEditText(mpEditEngine.get());
2942  }
2943  lcl_RemoveTabs(aString);
2944  lcl_RemoveTabs(aPreAutoCorrectString);
2945 
2946  // Test if valid (always with simple string)
2947  if ( bModified && nValidation && pActiveViewSh )
2948  {
2951  if (pData && pData->HasErrMsg())
2952  {
2953  // #i67990# don't use pLastPattern in EnterHandler
2954  const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2955 
2956  bool bOk;
2957 
2958  if (pData->GetDataMode() == SC_VALID_CUSTOM)
2959  {
2960  bOk = pData->IsDataValidCustom( aString, *pPattern, aCursorPos, ScValidationData::CustomValidationPrivateAccess() );
2961  }
2962  else
2963  {
2964  bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
2965  }
2966 
2967  if (!bOk)
2968  {
2969  if ( pActiveViewSh ) // If it came from MouseButtonDown
2970  {
2971  pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
2972 
2973  // tdf#125917 Release the grab that a current mouse-down event being handled
2974  // by ScTabView has put on the mouse via its SelectionEngine.
2975  // Otherwise the warning box cannot interact with the mouse
2976  if (ScTabView* pView = pActiveViewSh->GetViewData().GetView())
2977  {
2978  if (ScViewSelectionEngine* pSelEngine = pView->GetSelEngine())
2979  pSelEngine->ReleaseMouse();
2980  }
2981  }
2982 
2983  vcl::Window* pParent = nullptr;
2984  if (pActiveViewSh)
2985  pParent = &pActiveViewSh->GetViewFrame()->GetWindow();
2986  else
2987  pParent = Application::GetDefDialogParent();
2988 
2989  if (pData->DoError(pParent ? pParent->GetFrameWeld() : nullptr, aString, aCursorPos))
2990  bForget = true; // Do not take over input
2991  }
2992  }
2993  }
2994 
2995  // Check for input into DataPilot table
2996  if ( bModified && pActiveViewSh && !bForget )
2997  {
2999  ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3000  if ( pDPObj )
3001  {
3002  // Any input within the DataPilot table is either a valid renaming
3003  // or an invalid action - normal cell input is always aborted
3005  bForget = true;
3006  }
3007  }
3008 
3009  std::vector<editeng::MisspellRanges> aMisspellRanges;
3010  mpEditEngine->CompleteOnlineSpelling();
3011  bool bSpellErrors = !bFormulaMode && mpEditEngine->HasOnlineSpellErrors();
3012  if ( bSpellErrors )
3013  {
3014  // #i3820# If the spell checker flags numerical input as error,
3015  // it still has to be treated as number, not EditEngine object.
3016  if ( pActiveViewSh )
3017  {
3019  // #i67990# don't use pLastPattern in EnterHandler
3020  const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
3021  if (pPattern)
3022  {
3023  SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
3024  // without conditional format, as in ScColumn::SetString
3025  sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
3026  double nVal;
3027  if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
3028  {
3029  bSpellErrors = false; // ignore the spelling errors
3030  }
3031  }
3032  }
3033  }
3034 
3035  // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
3036  // SetUpdateMode must come after CompleteOnlineSpelling.
3037  // The view is hidden in any case below (Broadcast).
3038  mpEditEngine->SetUpdateMode( false );
3039 
3040  if ( bModified && !bForget ) // What is being entered (text/object)?
3041  {
3042  sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
3043  if ( nParCnt == 0 )
3044  nParCnt = 1;
3045 
3046  bool bUniformAttribs = true;
3047  SfxItemSet aPara1Attribs = mpEditEngine->GetAttribs(0, 0, mpEditEngine->GetTextLen(0));
3048  for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
3049  {
3050  SfxItemSet aPara2Attribs = mpEditEngine->GetAttribs(nPara, 0, mpEditEngine->GetTextLen(nPara));
3051  if (!(aPara1Attribs == aPara2Attribs))
3052  {
3053  // Paragraph format different from that of the 1st paragraph.
3054  bUniformAttribs = false;
3055  break;
3056  }
3057  }
3058 
3059  ESelection aSel( 0, 0, nParCnt-1, mpEditEngine->GetTextLen(nParCnt-1) );
3060  SfxItemSet aOldAttribs = mpEditEngine->GetAttribs( aSel );
3061  const SfxPoolItem* pItem = nullptr;
3062 
3063  // Find common (cell) attributes before RemoveAdjust
3064  if ( pActiveViewSh && bUniformAttribs )
3065  {
3066  std::unique_ptr<SfxItemSet> pCommonAttrs;
3067  for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
3068  {
3069  SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3070  if ( eState == SfxItemState::SET &&
3073  *pItem != pEditDefaults->Get(nId) )
3074  {
3075  if ( !pCommonAttrs )
3076  pCommonAttrs.reset(new SfxItemSet( mpEditEngine->GetEmptyItemSet() ));
3077  pCommonAttrs->Put( *pItem );
3078  }
3079  }
3080 
3081  if ( pCommonAttrs )
3082  {
3084  pCellAttrs = std::make_unique<ScPatternAttr>(pDoc->GetPool());
3085  pCellAttrs->GetFromEditItemSet( pCommonAttrs.get() );
3086  }
3087  }
3088 
3089  // Clear ParaAttribs (including adjustment)
3090  RemoveAdjust();
3091 
3092  bool bAttrib = false; // Formatting present?
3093 
3094  // check if EditObject is needed
3095  if (nParCnt > 1)
3096  bAttrib = true;
3097  else
3098  {
3099  for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
3100  {
3101  SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
3102  if (eState == SfxItemState::DONTCARE)
3103  bAttrib = true;
3104  else if (eState == SfxItemState::SET)
3105  {
3106  // Keep same items in EditEngine as in ScEditAttrTester
3109  {
3110  if ( *pItem != pEditDefaults->Get(nId) )
3111  bAttrib = true;
3112  }
3113  }
3114  }
3115 
3116  // Contains fields?
3117  SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
3118  if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
3119  bAttrib = true;
3120 
3121  // Not converted characters?
3122  SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
3123  if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
3124  bAttrib = true;
3125 
3126  // Always recognize formulas as formulas
3127  // We still need the preceding test due to cell attributes
3128  }
3129 
3130  if (bSpellErrors)
3131  mpEditEngine->GetAllMisspellRanges(aMisspellRanges);
3132 
3133  if (bMatrix)
3134  bAttrib = false;
3135 
3136  if (bAttrib)
3137  {
3138  mpEditEngine->ClearSpellErrors();
3139  pObject = mpEditEngine->CreateTextObject();
3140  }
3141  else if (bAutoComplete) // Adjust Upper/Lower case
3142  {
3143  // Perform case-matching only when the typed text is partial.
3144  if (pColumnData && aAutoSearch.getLength() < aString.getLength())
3145  aString = getExactMatch(*pColumnData, aString);
3146  }
3147  }
3148 
3149  // Don't rely on ShowRefFrame switching the active view synchronously
3150  // execute the function directly on the correct view's bindings instead
3151  // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3153 
3154  if (bFormulaMode)
3155  {
3156  ShowRefFrame();
3157 
3158  if (pExecuteSh)
3159  {
3160  pExecuteSh->SetTabNo(aCursorPos.Tab());
3161  pExecuteSh->ActiveGrabFocus();
3162  }
3163 
3164  bFormulaMode = false;
3165  pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3166  SC_MOD()->SetRefInputHdl(nullptr);
3167  if (pInputWin)
3168  pInputWin->SetFormulaMode(false);
3170  }
3171  pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3173  ResetAutoPar();
3174 
3175  bool bOldMod = bModified;
3176 
3177  bModified = false;
3178  bSelIsRef = false;
3179  eMode = SC_INPUT_NONE;
3180  StopInputWinEngine(true);
3181 
3182  // Text input (through number formats) or ApplySelectionPattern modify
3183  // the cell's attributes, so pLastPattern is no longer valid
3184  pLastPattern = nullptr;
3185 
3186  if (bOldMod && !bProtected && !bForget)
3187  {
3188  bool bInsertPreCorrectedString = true;
3189  // No typographic quotes in formulas
3190  if (aString.startsWith("="))
3191  {
3193  if ( pAuto )
3194  {
3195  bInsertPreCorrectedString = false;
3196  OUString aReplace(pAuto->GetStartDoubleQuote());
3197  if( aReplace.isEmpty() )
3199  if( aReplace != "\"" )
3200  aString = aString.replaceAll( aReplace, "\"" );
3201 
3202  aReplace = OUString(pAuto->GetEndDoubleQuote());
3203  if( aReplace.isEmpty() )
3205  if( aReplace != "\"" )
3206  aString = aString.replaceAll( aReplace, "\"" );
3207 
3208  aReplace = OUString(pAuto->GetStartSingleQuote());
3209  if( aReplace.isEmpty() )
3211  if( aReplace != "'" )
3212  aString = aString.replaceAll( aReplace, "'" );
3213 
3214  aReplace = OUString(pAuto->GetEndSingleQuote());
3215  if( aReplace.isEmpty() )
3217  if( aReplace != "'" )
3218  aString = aString.replaceAll( aReplace, "'");
3219  }
3220  }
3221 
3222  pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditViewNoPaint ) );
3223 
3224  if ( pExecuteSh )
3225  {
3226  SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
3227 
3228  sal_uInt16 nId = FID_INPUTLINE_ENTER;
3229  if ( nBlockMode == ScEnterMode::BLOCK )
3230  nId = FID_INPUTLINE_BLOCK;
3231  else if ( nBlockMode == ScEnterMode::MATRIX )
3232  nId = FID_INPUTLINE_MATRIX;
3233 
3234  const SfxPoolItem* aArgs[2];
3235  aArgs[1] = nullptr;
3236 
3237  if ( bInsertPreCorrectedString && aString != aPreAutoCorrectString )
3238  {
3239  ScInputStatusItem aItem(FID_INPUTLINE_STATUS,
3241  aPreAutoCorrectString, pObject.get());
3242  aArgs[0] = &aItem;
3243  rBindings.Execute(nId, aArgs);
3244  }
3245 
3246  ScInputStatusItem aItemCorrected(FID_INPUTLINE_STATUS,
3248  aString, pObject.get());
3249  if ( !aMisspellRanges.empty() )
3250  aItemCorrected.SetMisspellRanges(&aMisspellRanges);
3251 
3252  aArgs[0] = &aItemCorrected;
3253  rBindings.Execute(nId, aArgs);
3254  }
3255 
3256  pLastState.reset(); // pLastState still contains the old text
3257  }
3258  else
3259  pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
3260 
3261  if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
3262  {
3263  // Combine with input?
3264  pExecuteSh->ApplySelectionPattern( *pCellAttrs, true );
3265  pExecuteSh->AdjustBlockHeight();
3266  }
3267 
3268  HideTip();
3269  HideTipBelow();
3270 
3271  nFormSelStart = nFormSelEnd = 0;
3272  aFormText.clear();
3273 
3274  bInOwnChange = false;
3275  bInEnterHandler = false;
3276 }
3277 
3279 {
3280  bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
3281 
3283 
3284  bModified = false;
3285 
3286  // Don't rely on ShowRefFrame switching the active view synchronously
3287  // execute the function directly on the correct view's bindings instead
3288  // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
3290 
3291  if (bFormulaMode)
3292  {
3293  ShowRefFrame();
3294  if (pExecuteSh)
3295  {
3296  pExecuteSh->SetTabNo(aCursorPos.Tab());
3297  pExecuteSh->ActiveGrabFocus();
3298  }
3299  bFormulaMode = false;
3300  SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
3301  SC_MOD()->SetRefInputHdl(nullptr);
3302  if (pInputWin)
3303  pInputWin->SetFormulaMode(false);
3305  }
3306  pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
3308  ResetAutoPar();
3309 
3310  eMode = SC_INPUT_NONE;
3311  StopInputWinEngine( true );
3312  if (pExecuteSh)
3313  pExecuteSh->StopEditShell();
3314 
3315  aCursorPos.Set(pExecuteSh->GetViewData().GetDocument()->MaxCol()+1,0,0); // Invalid flag
3316  mpEditEngine->SetTextCurrentDefaults(OUString());
3317 
3318  if ( !pLastState && pExecuteSh )
3319  pExecuteSh->UpdateInputHandler( true ); // Update status again
3320  else
3321  NotifyChange( pLastState.get(), true );
3322 
3323  nFormSelStart = nFormSelEnd = 0;
3324  aFormText.clear();
3325 
3326  bInOwnChange = false;
3327 
3328  if ( comphelper::LibreOfficeKit::isActive() && pExecuteSh )
3329  {
3330  // Clear
3331  std::vector<ReferenceMark> aReferenceMarks;
3333  }
3334 }
3335 
3337 {
3338  // References to unnamed document; that doesn't work
3339  return bFormulaMode && pRefViewSh
3340  && pRefViewSh->GetViewData().GetDocument()->GetDocumentShell() != pDocSh
3341  && !pDocSh->HasName();
3342 }
3343 
3345 {
3347  UpdateActiveView();
3348  if (!pTableView && !pTopView)
3349  return; // E.g. FillMode
3350 
3351  DataChanging(); // Cannot be new
3352 
3353  RemoveSelection();
3354  OUString aText = GetEditText(mpEditEngine.get());
3355  sal_Unicode cLastChar = 0;
3356  sal_Int32 nPos = aText.getLength() - 1;
3357  while (nPos >= 0) //checking space
3358  {
3359  cLastChar = aText[nPos];
3360  if (cLastChar != ' ')
3361  break;
3362  --nPos;
3363  }
3364 
3365  bool bAppendSeparator = (cLastChar != '(' && cLastChar != cSep && cLastChar != '=');
3366  if (bAppendSeparator)
3367  {
3368  if (pTableView)
3369  pTableView->InsertText( OUString(cSep) );
3370  if (pTopView)
3371  pTopView->InsertText( OUString(cSep) );
3372  }
3373 
3374  DataChanged();
3375 }
3376 
3377 void ScInputHandler::SetReference( const ScRange& rRef, const ScDocument& rDoc )
3378 {
3379  HideTip();
3380 
3381  const ScDocument* pThisDoc = nullptr;
3382  if (pRefViewSh)
3383  pThisDoc = pRefViewSh->GetViewData().GetDocument();
3384  bool bOtherDoc = (pThisDoc != &rDoc);
3385  if (bOtherDoc && !rDoc.GetDocumentShell()->HasName())
3386  {
3387  // References to unnamed document; that doesn't work
3388  // SetReference should not be called, then
3389  return;
3390  }
3391  if (!pThisDoc)
3392  pThisDoc = &rDoc;
3393 
3394  UpdateActiveView();
3395  if (!pTableView && !pTopView)
3396  return; // E.g. FillMode
3397 
3398  // Never overwrite the "="!
3399  EditView* pActiveView = pTopView ? pTopView : pTableView;
3400  ESelection aSel = pActiveView->GetSelection();
3401  aSel.Adjust();
3402  if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
3403  return;
3404 
3405  DataChanging(); // Cannot be new
3406 
3407  // Turn around selection if backwards.
3408  if (pTableView)
3409  {
3410  ESelection aTabSel = pTableView->GetSelection();
3411  if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
3412  {
3413  aTabSel.Adjust();
3414  pTableView->SetSelection(aTabSel);
3415  }
3416  }
3417  if (pTopView)
3418  {
3419  ESelection aTopSel = pTopView->GetSelection();
3420  if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
3421  {
3422  aTopSel.Adjust();
3423  pTopView->SetSelection(aTopSel);
3424  }
3425  }
3426 
3427  // Create string from reference, in the syntax of the document being edited.
3428  OUString aRefStr;
3429  const ScAddress::Details aAddrDetails( *pThisDoc, aCursorPos );
3430  if (bOtherDoc)
3431  {
3432  // Reference to other document
3433  OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
3434 
3435  // Always 3D and absolute.
3436  OUString aTmp(rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails));
3437 
3438  SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
3439  // #i75893# convert escaped URL of the document to something user friendly
3441 
3442  switch(aAddrDetails.eConv)
3443  {
3447  aRefStr = "[\'" + aFileName + "']";
3448  break;
3450  default:
3451  aRefStr = "\'" + aFileName + "'#";
3452  break;
3453  }
3454  aRefStr += aTmp;
3455  }
3456  else
3457  {
3458  if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
3459  rRef.aStart.Tab() != rRef.aEnd.Tab() )
3460  // pointer-selected => absolute sheet reference
3461  aRefStr = rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails);
3462  else
3463  aRefStr = rRef.Format(rDoc, ScRefFlags::VALID, aAddrDetails);
3464  }
3465 
3466  if (pTableView || pTopView)
3467  {
3468  if (pTableView)
3469  pTableView->InsertText( aRefStr, true );
3470  if (pTopView)
3471  pTopView->InsertText( aRefStr, true );
3472 
3473  DataChanged();
3474  }
3475 
3476  bSelIsRef = true;
3477 }
3478 
3479 void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
3480 {
3481  if ( eMode == SC_INPUT_NONE )
3482  {
3483  OSL_FAIL("InsertFunction, not during input mode");
3484  return;
3485  }
3486 
3487  UpdateActiveView();
3488  if (!pTableView && !pTopView)
3489  return; // E.g. FillMode
3490 
3491  DataChanging(); // Cannot be new
3492 
3493  OUString aText = rFuncName;
3494  if (bAddPar)
3495  aText += "()";
3496 
3497  if (pTableView)
3498  {
3499  pTableView->InsertText( aText );
3500  if (bAddPar)
3501  {
3503  --aSel.nStartPos;
3504  --aSel.nEndPos;
3505  pTableView->SetSelection(aSel);
3506  }
3507  }
3508  if (pTopView)
3509  {
3510  pTopView->InsertText( aText );
3511  if (bAddPar)
3512  {
3513  ESelection aSel = pTopView->GetSelection();
3514  --aSel.nStartPos;
3515  --aSel.nEndPos;
3516  pTopView->SetSelection(aSel);
3517  }
3518  }
3519 
3520  DataChanged();
3521 
3522  if (bAddPar)
3523  AutoParAdded();
3524 }
3525 
3527 {
3528  if ( eMode == SC_INPUT_NONE )
3529  {
3530  OSL_FAIL("ClearText, not during input mode");
3531  return;
3532  }
3533 
3534  UpdateActiveView();
3535  if (!pTableView && !pTopView)
3536  return; // E.g. FillMode
3537 
3538  DataChanging(); // Cannot be new
3539 
3540  if (pTableView)
3541  {
3542  pTableView->GetEditEngine()->SetText( "" );
3543  pTableView->SetSelection( ESelection(0,0, 0,0) );
3544  }
3545  if (pTopView)
3546  {
3547  pTopView->GetEditEngine()->SetText( "" );
3548  pTopView->SetSelection( ESelection(0,0, 0,0) );
3549  }
3550 
3551  DataChanged();
3552 }
3553 
3554 bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
3555 {
3556  if (!bOptLoaded)
3557  {
3558  bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3559  bOptLoaded = true;
3560  }
3561 
3562  vcl::KeyCode aCode = rKEvt.GetKeyCode();
3563  sal_uInt16 nModi = aCode.GetModifier();
3564  bool bShift = aCode.IsShift();
3565  bool bControl = aCode.IsMod1();
3566  bool bAlt = aCode.IsMod2();
3567  sal_uInt16 nCode = aCode.GetCode();
3568  sal_Unicode nChar = rKEvt.GetCharCode();
3569 
3570  if (bAlt && !bControl && nCode != KEY_RETURN)
3571  // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3572  return false;
3573 
3574  if (!bControl && nCode == KEY_TAB)
3575  {
3576  // Normal TAB moves the cursor right.
3577  EnterHandler();
3578 
3579  if (pActiveViewSh)
3580  pActiveViewSh->FindNextUnprot( bShift, true );
3581  return true;
3582  }
3583 
3584  bool bInputLine = ( eMode==SC_INPUT_TOP );
3585 
3586  bool bUsed = false;
3587  bool bSkip = false;
3588  bool bDoEnter = false;
3589 
3590  switch ( nCode )
3591  {
3592  case KEY_RETURN:
3593  // New line when in the input line and Shift/Ctrl-Enter is pressed,
3594  // or when in a cell and Ctrl-Enter is pressed.
3595  if ((pInputWin && bInputLine && bControl != bShift) || (!bInputLine && bControl && !bShift))
3596  {
3597  bDoEnter = true;
3598  }
3599  else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3600  {
3602  bUsed = true;
3603  }
3604  else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3605  {
3606  PasteManualTip();
3607  bUsed = true;
3608  }
3609  else
3610  {
3612  if ( bShift && bControl )
3613  nMode = ScEnterMode::MATRIX;
3614  else if ( bAlt )
3615  nMode = ScEnterMode::BLOCK;
3616  EnterHandler( nMode );
3617 
3618  if (pActiveViewSh)
3619  pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3620 
3621  bUsed = true;
3622  }
3623  break;
3624  case KEY_TAB:
3625  if (bControl && !bAlt)
3626  {
3628  {
3629  // Iterate
3630  NextFormulaEntry( bShift );
3631  bUsed = true;
3632  }
3633  else if (pColumnData && bUseTab && miAutoPosColumn != pColumnData->end())
3634  {
3635  // Iterate through AutoInput entries
3636  NextAutoEntry( bShift );
3637  bUsed = true;
3638  }
3639  }
3640  break;
3641  case KEY_ESCAPE:
3642  if ( nTipVisible )
3643  {
3644  HideTip();
3645  bUsed = true;
3646  }
3647  else if( nTipVisibleSec )
3648  {
3649  HideTipBelow();
3650  bUsed = true;
3651  }
3652  else if (eMode != SC_INPUT_NONE)
3653  {
3654  CancelHandler();
3655  bUsed = true;
3656  }
3657  else
3658  bSkip = true;
3659  break;
3660  case KEY_F2:
3661  if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3662  {
3663  eMode = SC_INPUT_TYPE;
3664  bUsed = true;
3665  }
3666  break;
3667  }
3668 
3669  // Only execute cursor keys if already in EditMode
3670  // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3671  bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3672  bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3673  if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3674  ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3675  {
3676  HideTip();
3677  HideTipBelow();
3678 
3679  if (bSelIsRef)
3680  {
3681  RemoveSelection();
3682  bSelIsRef = false;
3683  }
3684 
3685  UpdateActiveView();
3686  bool bNewView = DataChanging( nChar );
3687 
3688  if (bProtected) // Protected cell?
3689  bUsed = true; // Don't forward KeyEvent
3690  else // Changes allowed
3691  {
3692  if (bNewView ) // Create anew
3693  {
3694  if (pActiveViewSh)
3696  UpdateActiveView();
3697  if (eMode==SC_INPUT_NONE)
3698  if (pTableView || pTopView)
3699  {
3700  OUString aStrLoP;
3701 
3702  if (bStartEdit && nCellPercentFormatDecSep != 0 &&
3703  ((nChar >= '0' && nChar <= '9') || nChar == '-' || nChar == nCellPercentFormatDecSep))
3704  {
3705  aStrLoP = "%";
3706  }
3707 
3708  if (pTableView)
3709  {
3710  pTableView->GetEditEngine()->SetText( aStrLoP );
3711  if ( !aStrLoP.isEmpty() )
3712  pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3713 
3714  // Don't call SetSelection if the string is empty anyway,
3715  // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3716  }
3717  if (pTopView)
3718  {
3719  pTopView->GetEditEngine()->SetText( aStrLoP );
3720  if ( !aStrLoP.isEmpty() )
3721  pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3722  }
3723  }
3724  SyncViews();
3725  }
3726 
3727  if (pTableView || pTopView)
3728  {
3729  if (bDoEnter)
3730  {
3731  if (pTableView)
3733  bUsed = true;
3734  if (pTopView)
3736  bUsed = true;
3737  }
3738  else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3739  {
3740  SkipClosingPar();
3741  bUsed = true;
3742  }
3743  else
3744  {
3745  if (pTableView)
3746  {
3747  if (pTopView)
3748  pTableView->SetControlWord(pTableView->GetControlWord() | EVControlBits::SINGLELINEPASTE);
3749 
3750  vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
3751  if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3752  bUsed = true;
3753 
3755  }
3756  if (pTopView)
3757  {
3758  if ( bUsed && rKEvt.GetKeyCode().GetFunction() == KeyFuncType::CUT )
3760  else if ( pTopView->PostKeyEvent( rKEvt ) )
3761  bUsed = true;
3762  }
3763  }
3764 
3765  // AutoInput:
3766  if ( bUsed && bAutoComplete )
3767  {
3768  bUseTab = false;
3769  if (pFormulaData)
3770  miAutoPosFormula = pFormulaData->end(); // do not search further
3771  if (pColumnData)
3772  miAutoPosColumn = pColumnData->end();
3773 
3774  KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3775  if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3776  KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
3777  {
3778  if (bFormulaMode)
3779  UseFormulaData();
3780  else
3781  UseColData();
3782  }
3783  }
3784 
3785  // When the selection is changed manually or an opening parenthesis
3786  // is typed, stop overwriting parentheses
3787  if ( bUsed && nChar == '(' )
3788  ResetAutoPar();
3789 
3790  if ( KEY_INSERT == nCode )
3791  {
3792  SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3793  if (pViewFrm)
3794  pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3795  }
3796  if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3797  {
3798  ShowTipCursor();
3799  }
3800  if( bUsed && bFormulaMode && nCode == KEY_BACKSPACE )
3801  {
3802  UseFormulaData();
3803  }
3804 
3805  }
3806 
3807  // #i114511# don't count cursor keys as modification
3808  bool bSetModified = !bCursorKey;
3809  DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3810 
3811  // In the LOK case, we want to set the document modified state
3812  // right away at the start of the edit, so that the content is
3813  // saved even when the user leaves the document before hitting
3814  // Enter
3817 
3818  InvalidateAttribs();
3819  }
3820  }
3821 
3822  if (pTopView && eMode != SC_INPUT_NONE)
3823  SyncViews();
3824 
3825  return bUsed;
3826 }
3827 
3829 {
3830  if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
3831  {
3832  // For CommandEventId::CursorPos, do as little as possible, because
3833  // with remote VCL, even a ShowCursor will generate another event.
3834  if ( eMode != SC_INPUT_NONE )
3835  {
3836  UpdateActiveView();
3837  if (pTableView || pTopView)
3838  {
3839  if (pTableView)
3840  pTableView->Command( rCEvt );
3841  else if (pTopView) // call only once
3842  pTopView->Command( rCEvt );
3843  }
3844  }
3845  }
3846  else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
3847  {
3848  if ( eMode != SC_INPUT_NONE )
3849  {
3850  UpdateActiveView();
3851  if (pTableView || pTopView)
3852  {
3853  if (pTableView)
3854  pTableView->Command( rCEvt );
3855  else if (pTopView) // call only once
3856  pTopView->Command( rCEvt );
3857  }
3858  }
3859  }
3860  else
3861  {
3862  if (!bOptLoaded)
3863  {
3864  bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3865  bOptLoaded = true;
3866  }
3867 
3868  HideTip();
3869  HideTipBelow();
3870 
3871  if ( bSelIsRef )
3872  {
3873  RemoveSelection();
3874  bSelIsRef = false;
3875  }
3876 
3877  UpdateActiveView();
3878  bool bNewView = DataChanging( 0, true );
3879 
3880  if (!bProtected) // changes allowed
3881  {
3882  if (bNewView) // create new edit view
3883  {
3884  if (pActiveViewSh)
3886  UpdateActiveView();
3887  if (eMode==SC_INPUT_NONE)
3888  if (pTableView || pTopView)
3889  {
3890  OUString aStrLoP;
3891  if (pTableView)
3892  {
3893  pTableView->GetEditEngine()->SetText( aStrLoP );
3894  pTableView->SetSelection( ESelection(0,0, 0,0) );
3895  }
3896  if (pTopView)
3897  {
3898  pTopView->GetEditEngine()->SetText( aStrLoP );
3899  pTopView->SetSelection( ESelection(0,0, 0,0) );
3900  }
3901  }
3902  SyncViews();
3903  }
3904 
3905  if (pTableView || pTopView)
3906  {
3907  if (pTableView)
3908  pTableView->Command( rCEvt );
3910  pTopView->Command( rCEvt );
3911 
3912  if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
3913  {
3914  // AutoInput after ext text input
3915 
3916  if (pFormulaData)
3917  miAutoPosFormula = pFormulaData->end();
3918  if (pColumnData)
3919  miAutoPosColumn = pColumnData->end();
3920 
3921  if (bFormulaMode)
3922  UseFormulaData();
3923  else
3924  UseColData();
3925  }
3926  }
3927 
3928  DataChanged(); // calls UpdateParenthesis()
3929  InvalidateAttribs();
3930  }
3931 
3932  if (pTopView && eMode != SC_INPUT_NONE)
3933  SyncViews();
3934  }
3935 }
3936 
3938  bool bForce, ScTabViewShell* pSourceSh,
3939  bool bStopEditing)
3940 {
3941  // If the call originates from a macro call in the EnterHandler,
3942  // return immediately and don't mess up the status
3943  if (bInEnterHandler)
3944  return;
3945 
3946  bool bRepeat = (pState == pLastState.get());
3947  if (!bRepeat && pState && pLastState)
3948  bRepeat = (*pState == *pLastState);
3949  if (bRepeat && !bForce)
3950  return;
3951 
3952  bInOwnChange = true; // disable ModifyHdl (reset below)
3953 
3954  if ( pState && !pLastState ) // Enable again
3955  bForce = true;
3956 
3957  bool bHadObject = pLastState && pLastState->GetEditData();
3958 
3960  if ( pSourceSh )
3961  pActiveViewSh = pSourceSh;
3962  else
3963  pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
3964 
3966 
3967  if ( pState != pLastState.get() )
3968  {
3969  pLastState.reset( pState ? new ScInputHdlState( *pState ) : nullptr);
3970  }
3971 
3972  if ( pState && pActiveViewSh )
3973  {
3974  ScModule* pScMod = SC_MOD();
3975 
3976  ScTabViewShell* pScTabViewShell = dynamic_cast<ScTabViewShell*>(pScMod->GetViewShell());
3977 
3978  // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
3979  // FormEditData, if we're switching from Help to Calc:
3980  if ( !bFormulaMode && !pScMod->IsFormulaMode() &&
3981  ( !pScTabViewShell || !pScTabViewShell->GetFormEditData() ) )
3982  {
3983  bool bIgnore = false;
3984  if ( bModified )
3985  {
3986  if (pState->GetPos() != aCursorPos)
3987  {
3988  if (!bProtected)
3989  EnterHandler();
3990  }
3991  else
3992  bIgnore = true;
3993  }
3994 
3995  if ( !bIgnore )
3996  {
3997  const ScAddress& rSPos = pState->GetStartPos();
3998  const ScAddress& rEPos = pState->GetEndPos();
3999  const EditTextObject* pData = pState->GetEditData();
4000  OUString aString = pState->GetString();
4001  bool bTxtMod = false;
4003  ScDocument& rDoc = pDocSh->GetDocument();
4004 
4005  aCursorPos = pState->GetPos();
4006 
4007  if ( pData )
4008  bTxtMod = true;
4009  else if ( bHadObject )
4010  bTxtMod = true;
4011  else if ( bTextValid )
4012  bTxtMod = ( aString != aCurrentText );
4013  else
4014  bTxtMod = ( aString != GetEditText(mpEditEngine.get()) );
4015 
4016  if ( bTxtMod || bForce )
4017  {
4018  if (pData)
4019  {
4020  mpEditEngine->SetTextCurrentDefaults( *pData );
4021  if (pInputWin)
4023  else
4024  aString = GetEditText(mpEditEngine.get());
4025  lcl_RemoveTabs(aString);
4026  bTextValid = false;
4027  aCurrentText.clear();
4028  }
4029  else
4030  {
4031  aCurrentText = aString;
4032  bTextValid = true;
4033  }
4034 
4035  if ( pInputWin )
4036  pInputWin->SetTextString(aString);
4037 
4039  pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aString.toUtf8().getStr());
4040  }
4041 
4042  if ( pInputWin || comphelper::LibreOfficeKit::isActive()) // Named range input
4043  {
4044  OUString aPosStr;
4045  const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
4046 
4047  // Is the range a name?
4049  if ( pActiveViewSh )
4051  GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );
4052 
4053  if ( aPosStr.isEmpty() ) // Not a name -> format
4054  {
4055  ScRefFlags nFlags = ScRefFlags::ZERO;
4056  if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
4058  if ( rSPos != rEPos )
4059  {
4060  ScRange r(rSPos, rEPos);
4061  applyStartToEndFlags(nFlags);
4062  aPosStr = r.Format(rDoc, ScRefFlags::VALID | nFlags, aAddrDetails);
4063  }
4064  else
4065  aPosStr = aCursorPos.Format(ScRefFlags::VALID | nFlags, &rDoc, aAddrDetails);
4066  }
4067 
4068  if (pInputWin)
4069  {
4070  // Disable the accessible VALUE_CHANGE event
4071  bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
4073  pInputWin->SetPosString(aPosStr);
4076  }
4077 
4079  pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_ADDRESS, aPosStr.toUtf8().getStr());
4080  }
4081 
4082  if (bStopEditing)
4083  SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
4084 
4085  // As long as the content is not edited, turn off online spelling.
4086  // Online spelling is turned back on in StartTable, after setting
4087  // the right language from cell attributes.
4088 
4089  EEControlBits nCntrl = mpEditEngine->GetControlWord();
4090  if ( nCntrl & EEControlBits::ONLINESPELLING )
4091  mpEditEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
4092 
4093  bModified = false;
4094  bSelIsRef = false;
4095  bProtected = false;
4096  bCommandErrorShown = false;
4097  }
4098  }
4099 
4100  if ( pInputWin)
4101  {
4102  // Do not enable if RefDialog is open
4103  if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
4104  {
4105  if ( !pInputWin->IsEnabled())
4106  {
4107  pDelayTimer->Stop();
4108  pInputWin->Enable();
4109  }
4110  }
4111  else if(pScMod->IsRefDialogOpen())
4112  { // Because every document has its own InputWin,
4113  // we should start Timer again, because the input line may
4114  // still be active
4115  if ( !pDelayTimer->IsActive() )
4116  pDelayTimer->Start();
4117  }
4118  }
4119  }
4120  else // !pState || !pActiveViewSh
4121  {
4122  if ( !pDelayTimer->IsActive() )
4123  pDelayTimer->Start();
4124  }
4125 
4126  HideTip();
4127  HideTipBelow();
4128  bInOwnChange = false;
4129 }
4130 
4132 {
4133  eAttrAdjust = eJust;
4134  UpdateAdjust( 0 );
4135 }
4136 
4138 {
4139  if( pDelayTimer->IsActive() )
4140  {
4141  pDelayTimer->Stop();
4142  if ( pInputWin )
4143  pInputWin->Enable();
4144  }
4145 }
4146 
4147 IMPL_LINK_NOARG( ScInputHandler, DelayTimer, Timer*, void )
4148 {
4149  if ( !(nullptr == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen()))
4150  return;
4151 
4153  SfxViewFrame* pViewFrm = SfxViewFrame::Current();
4154  if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
4155  {
4156  if ( pInputWin)
4157  {
4158  pInputWin->EnableButtons( false );
4159  pInputWin->Disable();
4160  }
4161  }
4162  else if ( !bFormulaMode ) // Keep formula e.g. for help
4163  {
4164  bInOwnChange = true; // disable ModifyHdl (reset below)
4165 
4166  pActiveViewSh = nullptr;
4167  mpEditEngine->SetTextCurrentDefaults( EMPTY_OUSTRING );
4168  if ( pInputWin )
4169  {
4170  pInputWin->SetPosString( EMPTY_OUSTRING );
4171  pInputWin->SetTextString( EMPTY_OUSTRING );
4172  pInputWin->Disable();
4173  }
4174 
4175  bInOwnChange = false;
4176  }
4177 }
4178 
4180 {
4181  SyncViews( pView );
4182  ShowTipCursor();
4183  UpdateParenthesis(); // Selection changed -> update parentheses highlighting
4184 
4185  // When the selection is changed manually, stop overwriting parentheses
4186  ResetAutoPar();
4187 }
4188 
4189 void ScInputHandler::InputChanged( const EditView* pView, bool bFromNotify )
4190 {
4191  UpdateActiveView();
4192 
4193  // #i20282# DataChanged needs to know if this is from the input line's modify handler
4194  bool bFromTopNotify = ( bFromNotify && pView == pTopView );
4195 
4196  bool bNewView = DataChanging(); //FIXME: Is this at all possible?
4197  aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
4198  mpEditEngine->SetTextCurrentDefaults( aCurrentText );
4199  DataChanged( bFromTopNotify );
4200  bTextValid = true; // Is set to false in DataChanged
4201 
4202  if ( pActiveViewSh )
4203  {
4204  ScViewData& rViewData = pActiveViewSh->GetViewData();
4205  if ( bNewView )
4206  rViewData.GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
4207 
4208  rViewData.EditGrowY();
4209  rViewData.EditGrowX();
4210  }
4211 
4212  SyncViews( pView );
4213 }
4214 
4216 {
4217  if (mpEditEngine)
4218  {
4219  aCurrentText = mpEditEngine->GetText(); // Always new from Engine
4220  bTextValid = true;
4221  }
4222 
4223  return aCurrentText;
4224 }
4225 
4227 {
4228  Size aSize;
4229  if ( mpEditEngine )
4230  aSize = Size( mpEditEngine->CalcTextWidth(), mpEditEngine->GetTextHeight() );
4231 
4232  return aSize;
4233 }
4234 
4236 {
4237  bool bRet = false;
4238  if (mpEditEngine)
4239  {
4240  // Contains field?
4241  sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
4242  SfxItemSet aSet = mpEditEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
4243  SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
4244  if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
4245  {
4246  // Copy content
4247  std::unique_ptr<EditTextObject> pObj = mpEditEngine->CreateTextObject();
4248  rDestEngine.SetTextCurrentDefaults(*pObj);
4249  pObj.reset();
4250 
4251  // Delete attributes
4252  for (sal_Int32 i=0; i<nParCnt; i++)
4253  rDestEngine.RemoveCharAttribs( i );
4254 
4255  // Combine paragraphs
4256  while ( nParCnt > 1 )
4257  {
4258  sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
4259  ESelection aSel( 0,nLen, 1,0 );
4260  rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
4261  --nParCnt;
4262  }
4263 
4264  bRet = true;
4265  }
4266  }
4267  return bRet;
4268 }
4269 
4274 void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
4275 {
4276  rStart = nFormSelStart;
4277  rEnd = nFormSelEnd;
4278 }
4279 
4281 {
4282  UpdateActiveView(); // Due to pTableView
4283 
4284  EditView* pView = nullptr;
4285  if ( pInputWin )
4286  {
4288  pView = pInputWin->GetEditView();
4289  }
4290  else
4291  {
4292  if ( eMode != SC_INPUT_TABLE )
4293  {
4294  bCreatingFuncView = true; // Don't display RangeFinder
4296  bCreatingFuncView = false;
4297  if ( pTableView )
4299  }
4300  pView = pTableView;
4301  }
4302 
4303  return pView;
4304 }
4305 
4306 void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
4307 {
4308  if ( nStart <= nEnd )
4309  {
4310  nFormSelStart = nStart;
4311  nFormSelEnd = nEnd;
4312  }
4313  else
4314  {
4315  nFormSelEnd = nStart;
4316  nFormSelStart = nEnd;
4317  }
4318 
4319  EditView* pView = GetFuncEditView();
4320  if (pView)
4321  pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
4322 
4323  bModified = true;
4324 }
4325 
4326 void ScInputHandler::InputReplaceSelection( const OUString& rStr )
4327 {
4328  if (!pRefViewSh)
4330 
4331  OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
4332 
4333  sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
4334  sal_Int32 nNewLen = rStr.getLength();
4335 
4336  OUStringBuffer aBuf(aFormText);
4337  if (nOldLen)
4338  aBuf.remove(nFormSelStart, nOldLen);
4339  if (nNewLen)
4340  aBuf.insert(nFormSelStart, rStr);
4341 
4342  aFormText = aBuf.makeStringAndClear();
4343 
4344  nFormSelEnd = nFormSelStart + nNewLen;
4345 
4346  EditView* pView = GetFuncEditView();
4347  if (pView)
4348  {
4349  pView->SetEditEngineUpdateMode( false );
4350  pView->GetEditEngine()->SetText( aFormText );
4351  pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
4352  pView->SetEditEngineUpdateMode( true );
4353  }
4354  bModified = true;
4355 }
4356 
4358 {
4359  bInOwnChange = true; // disable ModifyHdl (reset below)
4360 
4361  eMode = SC_INPUT_NONE;
4362  /* TODO: it would be better if there was some way to reset the input bar
4363  * engine instead of deleting and having it recreate through
4364  * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
4365  * fdo#72278 without reintroducing fdo#69971. */
4366  StopInputWinEngine(true);
4367 
4368  bInOwnChange = false;
4369 }
4370 
4375  const ScAddress& rStartPos,
4376  const ScAddress& rEndPos,
4377  const OUString& rString,
4378  const EditTextObject* pData )
4379  : aCursorPos ( rCurPos ),
4380  aStartPos ( rStartPos ),
4381  aEndPos ( rEndPos ),
4382  aString ( rString ),
4383  pEditData ( pData ? pData->Clone() : nullptr )
4384 {
4385 }
4386 
4388 {
4389  *this = rCpy;
4390 }
4391 
4393 {
4394 }
4395 
4397 {
4398  return ( (aStartPos == r.aStartPos)
4399  && (aEndPos == r.aEndPos)
4400  && (aCursorPos == r.aCursorPos)
4401  && (aString == r.aString)
4402  && ScGlobal::EETextObjEqual( pEditData.get(), r.pEditData.get() ) );
4403 }
4404 
4406 {
4407  if (this != &r)
4408  {
4409  aCursorPos = r.aCursorPos;
4410  aStartPos = r.aStartPos;
4411  aEndPos = r.aEndPos;
4412  aString = r.aString;
4413  pEditData.reset();
4414  if (r.pEditData)
4415  pEditData = r.pEditData->Clone();
4416  }
4417  return *this;
4418 }
4419 
4420 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScMarkData & GetMarkData()
Definition: viewdata.cxx:3053
void FindNextUnprot(bool bShift, bool bInSelection)
Definition: tabview3.cxx:1526
SfxViewFrame * GetViewFrame() const
ScDBFunc * GetView() const
Definition: viewdata.hxx:356
void Command(const CommandEvent &rCEvt)
sal_Unicode GetEndDoubleQuote() const
SC_DLLPUBLIC ScDPObject * GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen3.cxx:358
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:479
SC_DLLPUBLIC void Format(OStringBuffer &r, ScRefFlags nFlags, const ScDocument *pDocument=nullptr, const Details &rDetails=detailsOOOa1) const
Definition: address.cxx:2111
sal_uInt16 nAutoPar
Definition: inputhdl.hxx:88
void UpdateRange(sal_uInt16 nIndex, const ScRange &rNew)
Definition: inputhdl.cxx:587
bool CursorAtClosingPar()
Definition: inputhdl.cxx:1858
SC_DLLPUBLIC ScRefFlags ParseAny(const OUString &, const ScDocument *, const ScAddress::Details &rDetails=ScAddress::detailsOOOa1)
Definition: address.cxx:1770
sal_Int32 nStartPara
void CancelHandler()
Definition: inputhdl.cxx:3278
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:317
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:1992
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
#define PAIRED_VAR_ARGS
#define EMPTY_OUSTRING
Definition: global.hxx:214
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:754
void UpdateCellAdjust(SvxCellHorJustify eJust)
Definition: inputhdl.cxx:4131
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:2199
void StopEditEngine(bool bAll)
Definition: inputwin.cxx:659
const OUString & GetEditString()
Definition: inputhdl.cxx:4215
static SC_DLLPUBLIC::utl::TransliterationWrapper * GetpTransliteration()
Definition: global.cxx:982
void NextFormulaEntry(bool bBack)
Definition: inputhdl.cxx:1521
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:1789
void CompleteAutoCorrect(vcl::Window const *pFrameWin=nullptr)
constexpr TypedWhichId< SfxBoolItem > ATTR_VERTICAL_ASIAN(137)
void ShowFuncList(const ::std::vector< OUString > &rFuncStrVec)
Definition: inputhdl.cxx:1334
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:2566
Point GetPrintTwipsPos(SCCOL nCol, SCROW nRow) const
returns the position (top-left corner) of the requested cell in print twips coordinates.
Definition: viewdata.cxx:2471
bool IsDataValidCustom(const OUString &rTest, const ScPatternAttr &rPattern, const ScAddress &rPos, const CustomValidationPrivateAccess &) const
Definition: validat.cxx:434
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, Color **ppColor, bool bUseStarFormat=false)
void UpdateParenthesis()
Definition: inputhdl.cxx:2054
SCROW GetRefStartY() const
Definition: viewdata.hxx:516
const ScAddress & GetPos() const
Definition: inputhdl.hxx:313
sal_uInt8 GetTransparency() const
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:3526
void AutoParAdded()
Definition: inputhdl.cxx:1853
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:322
std::unique_ptr< Timer > pDelayTimer
Definition: inputhdl.hxx:122
ScAddress aEnd
Definition: address.hxx:501
ScSplitPos GetActivePart() const
Definition: viewdata.hxx:398
void ResetAutoPar()
Definition: inputhdl.cxx:1848
void EditGrowY(bool bInitial=false)
Extend the output area for the edit engine view in a vertical direction as needed.
Definition: viewdata.cxx:2080
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:2742
void InputSelection(const EditView *pView)
Definition: inputhdl.cxx:4179
void UpdateActiveView()
Definition: inputhdl.cxx:2150
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:1665
EmbeddedObjectRef * pObject
EEControlBits
void ViewShellGone(const ScTabViewShell *pViewSh)
Definition: inputhdl.cxx:2116
bool bCreatingFuncView
Definition: inputhdl.hxx:99
void SetDocumentDisposing(bool b)
Definition: inputhdl.cxx:560
SC_DLLPUBLIC formula::FormulaGrammar::AddressConvention GetAddressConvention() const
Definition: documen3.cxx:475
void ShowRefFrame()
Definition: inputhdl.cxx:2709
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:614
ScSplitPos
Definition: viewdata.hxx:45
void SetPosString(const OUString &rStr)
Definition: inputwin.cxx:579
SfxApplication * SfxGetpApp()
OUString aCurrentText
Definition: inputhdl.hxx:80
EditView * GetActiveView()
Definition: inputhdl.cxx:2212
OUString aManualTip
Definition: inputhdl.hxx:77
bool operator==(const ScInputHdlState &r) const
Definition: inputhdl.cxx:4396
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:6064
ScInputHdlState & operator=(const ScInputHdlState &r)
Definition: inputhdl.cxx:4405
WEIGHT_BOLD
SC_DLLPUBLIC const ScValidationData * GetValidationEntry(sal_uLong nIndex) const
Definition: documen4.cxx:871
void MakeDialogEditView()
Definition: inputwin.cxx:654
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:649
vcl::Window & GetWindow() const
void SkipClosingPar()
Definition: inputhdl.cxx:1874
OUString aAutoSearch
Definition: inputhdl.hxx:78
void DeleteRangeFinder()
Definition: inputhdl.cxx:639
void InputReplaceSelection(const OUString &rStr)
Definition: inputhdl.cxx:4326
void Enable(bool bEnable=true, bool bChild=true)
void RemoveRangeFinder()
Definition: inputhdl.cxx:2294
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:2485
vcl::Cursor * GetCursor() const
void ImplCreateEditEngine()
Definition: inputhdl.cxx:868
bool HasErrMsg() const
Definition: validat.hxx:112
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:1784
SfxFrame & GetFrame() const
void AddRefEntry()
Definition: inputhdl.cxx:3344
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:5306
Mode eMode
void UpdateInputHandler(bool bForce=false, bool bStopEditing=true)
Definition: tabvwsha.cxx:632
void SyncViews(const EditView *pSourceView=nullptr)
Definition: inputhdl.cxx:2523
SCTAB Tab() const
Definition: address.hxx:271
sal_uInt16 GetModifier() const
Is
ScDocument * GetDocument() const
Definition: viewdata.cxx:859
SvxCellHorJustify eAttrAdjust
Definition: inputhdl.hxx:108
void ShowArgumentsTip(OUString &rSelText)
Definition: inputhdl.cxx:1057
void SetFormulaMode(bool bSet)
Definition: inputwin.cxx:638
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:4306
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:4738
bool bParenthesisShown
Definition: inputhdl.hxx:98
ScViewData & GetViewData()
Definition: tabview.hxx:332
void UpdateFormulaMode()
Definition: inputhdl.cxx:2663
constexpr TypedWhichId< SvxWeightItem > EE_CHAR_WEIGHT(EE_CHAR_START+4)
ScGridWindow * GetActiveWin()
Definition: tabview.cxx:884
void UpdateSpellSettings(bool bFromStartTab=false)
Definition: inputhdl.cxx:907
ScValidationMode GetDataMode() const
Definition: validat.hxx:114
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:70
static OUString lcl_Calculate(const OUString &rFormula, ScDocument *pDoc, const ScAddress &rPos)
Definition: inputhdl.cxx:1703
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)
static ReferenceMark GetReferenceMark(ScViewData &rViewData, ScDocShell *pDocSh, long nX1, long nX2, long nY1, long nY2, long nTab, const Color &rColor)
Definition: inputhdl.cxx:431
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1904
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:324
bool IsModalMode(const SfxObjectShell *pDocSh)
Definition: inputhdl.cxx:3336
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
static css::uno::Reference< css::linguistic2::XSpellChecker1 > GetSpellChecker()
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:559
static void HidePopover(vcl::Window const *pParent, void *nId)
bool IsMarked() const
Definition: markdata.hxx:82
virtual OUString getSignature() const override
Returns the full function signature.
Definition: funcdesc.cxx:224
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
void GetFormulaData()
Definition: inputhdl.cxx:963
void SetDefaultItem(const SfxPoolItem &rItem)
Set the item in the default ItemSet which is created if it doesn't exist yet.
Definition: editutil.cxx:538
SvxAdjust
int i
Reference< XAnimationNode > Clone(const Reference< XAnimationNode > &xSourceNode, const SdPage *pSource, const SdPage *pTarget)