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