fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / app / inputhdl.cxx
blobfe9ef00e709f79486a4153991d5bb5682e203206
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "inputhdl.hxx"
21 #include "scitems.hxx"
22 #include <editeng/eeitem.hxx>
24 #include <sfx2/app.hxx>
25 #include <editeng/acorrcfg.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/adjustitem.hxx>
28 #include <editeng/brushitem.hxx>
29 #include <svtools/colorcfg.hxx>
30 #include <editeng/colritem.hxx>
31 #include <editeng/editobj.hxx>
32 #include <editeng/editstat.hxx>
33 #include <editeng/editview.hxx>
34 #include <editeng/escapementitem.hxx>
35 #include <editeng/forbiddencharacterstable.hxx>
36 #include <editeng/langitem.hxx>
37 #include <editeng/svxacorr.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <editeng/wghtitem.hxx>
40 #include <editeng/justifyitem.hxx>
41 #include <editeng/misspellrange.hxx>
42 #include <sfx2/bindings.hxx>
43 #include <sfx2/viewfrm.hxx>
44 #include <sfx2/dispatch.hxx>
45 #include <sfx2/docfile.hxx>
46 #include <sfx2/printer.hxx>
47 #include <svl/zforlist.hxx>
48 #include <unotools/localedatawrapper.hxx>
49 #include <vcl/help.hxx>
50 #include <vcl/cursor.hxx>
51 #include <vcl/settings.hxx>
52 #include <tools/urlobj.hxx>
53 #include <comphelper/string.hxx>
54 #include <formula/formulahelper.hxx>
56 #include "inputwin.hxx"
57 #include "tabvwsh.hxx"
58 #include "docsh.hxx"
59 #include "scmod.hxx"
60 #include "uiitems.hxx"
61 #include "global.hxx"
62 #include "sc.hrc"
63 #include "globstr.hrc"
64 #include "patattr.hxx"
65 #include "viewdata.hxx"
66 #include "document.hxx"
67 #include "docpool.hxx"
68 #include "editutil.hxx"
69 #include "appoptio.hxx"
70 #include "docoptio.hxx"
71 #include "validat.hxx"
72 #include "userlist.hxx"
73 #include "rfindlst.hxx"
74 #include "inputopt.hxx"
75 #include "simpleformulacalc.hxx"
76 #include "compiler.hxx"
77 #include "editable.hxx"
78 #include "funcdesc.hxx"
79 #include "markdata.hxx"
80 #include "tokenarray.hxx"
81 #include <gridwin.hxx>
83 // Maximum Ranges in RangeFinder
84 #define RANGEFIND_MAX 32
86 using namespace formula;
88 // STATIC DATA -----------------------------------------------------------
90 bool ScInputHandler::bOptLoaded = false; // Evaluate App options
91 bool ScInputHandler::bAutoComplete = false; // Is set in KeyInput
93 extern sal_uInt16 nEditAdjust; //! Member of ViewData
95 namespace {
97 // Formula data replacement character for a pair of parentheses at end of
98 // function name, to force sorting parentheses before all other characters.
99 // Collation may treat parentheses differently.
100 const sal_Unicode cParenthesesReplacement = 0x0001;
102 sal_Unicode lcl_getSheetSeparator(ScDocument* pDoc)
104 ScCompiler aComp(pDoc, ScAddress());
105 aComp.SetGrammar(pDoc->GetGrammar());
106 return aComp.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
109 ScTypedCaseStrSet::const_iterator findText(
110 const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
111 const OUString& rStart, OUString& rResult, bool bBack)
113 if (bBack) // Backwards
115 ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
116 if (itPos != rDataSet.end())
118 size_t nPos = std::distance(rDataSet.begin(), itPos);
119 size_t nRPos = rDataSet.size() - 1 - nPos;
120 std::advance(it, nRPos);
121 ++it;
124 for (; it != itEnd; ++it)
126 const ScTypedStrData& rData = *it;
127 if (rData.GetStringType() == ScTypedStrData::Value)
128 // skip values
129 continue;
131 if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
132 // not a match
133 continue;
135 rResult = rData.GetString();
136 return (++it).base(); // convert the reverse iterator back to iterator.
139 else // Forwards
141 ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
142 if (itPos != rDataSet.end())
144 it = itPos;
145 ++it;
148 for (; it != itEnd; ++it)
150 const ScTypedStrData& rData = *it;
151 if (rData.GetStringType() == ScTypedStrData::Value)
152 // skip values
153 continue;
155 if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
156 // not a match
157 continue;
159 rResult = rData.GetString();
160 return it;
164 return rDataSet.end(); // no matching text found
167 OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
169 ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
170 for (; it != itEnd; ++it)
172 const ScTypedStrData& rData = *it;
173 if (rData.GetStringType() == ScTypedStrData::Value)
174 continue;
176 if (!ScGlobal::GetpTransliteration()->isEqual(rData.GetString(), rString))
177 continue;
179 return rData.GetString();
181 return rString;
184 void removeChars(OUString& rStr, sal_Unicode c)
186 OUStringBuffer aBuf(rStr);
187 for (sal_Int32 i = 0, n = aBuf.getLength(); i < n; ++i)
189 if (aBuf[i] == c)
190 aBuf[i] = ' ';
192 rStr = aBuf.makeStringAndClear();
197 void ScInputHandler::InitRangeFinder( const OUString& rFormula )
199 DeleteRangeFinder();
200 if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
201 return;
202 ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
203 ScDocument& rDoc = pDocSh->GetDocument();
204 const sal_Unicode cSheetSep = lcl_getSheetSeparator(&rDoc);
206 OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !\"");
207 // delimiters (in addition to ScEditUtil): only characters that are
208 // allowed in formulas next to references and the quotation mark (so
209 // string constants can be skipped)
211 sal_Int32 nColon = aDelimiters.indexOf( ':' );
212 if ( nColon != -1 )
213 aDelimiters = aDelimiters.replaceAt( nColon, 1, ""); // Delimiter without colon
214 sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
215 if ( nDot != -1 )
216 aDelimiters = aDelimiters.replaceAt( nDot, 1 , ""); // Delimiter without dot
218 const sal_Unicode* pChar = rFormula.getStr();
219 sal_Int32 nLen = rFormula.getLength();
220 sal_Int32 nPos = 0;
221 sal_Int32 nStart = 0;
222 sal_uInt16 nCount = 0;
223 ScRange aRange;
224 while ( nPos < nLen && nCount < RANGEFIND_MAX )
226 // Skip separator
227 while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
229 if ( pChar[nPos] == '"' ) // String
231 ++nPos;
232 while (nPos<nLen && pChar[nPos] != '"') // Skip until end
233 ++nPos;
235 ++nPos; // Separator or closing quote
238 // Text zwischen Trennern
239 nStart = nPos;
240 handle_r1c1:
241 while ( nPos<nLen && !ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
242 ++nPos;
244 // for R1C1 '-' in R[-]... or C[-]... are not delimiters
245 // Nothing heroic here to ensure that there are '[]' around a negative
246 // integer. we need to clean up this code.
247 if( nPos < nLen && nPos > 0 &&
248 '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
249 formula::FormulaGrammar::CONV_XL_R1C1 == rDoc.GetAddressConvention() )
251 nPos++;
252 goto handle_r1c1;
255 if ( nPos > nStart )
257 OUString aTest = rFormula.copy( nStart, nPos-nStart );
258 const ScAddress::Details aAddrDetails( &rDoc, aCursorPos );
259 sal_uInt16 nFlags = aRange.ParseAny( aTest, &rDoc, aAddrDetails );
260 if ( nFlags & SCA_VALID )
262 // Set tables if not specified
263 if ( (nFlags & SCA_TAB_3D) == 0 )
264 aRange.aStart.SetTab( pActiveViewSh->GetViewData().GetTabNo() );
265 if ( (nFlags & SCA_TAB2_3D) == 0 )
266 aRange.aEnd.SetTab( aRange.aStart.Tab() );
268 if ( ( nFlags & ( SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2 ) ) == 0 )
270 // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
271 // so Format doesn't output a double ref because of different flags.
272 sal_uInt16 nAbsFlags = nFlags & ( SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
273 nFlags |= nAbsFlags << 4;
276 if (!nCount)
278 pEngine->SetUpdateMode( false );
279 pRangeFindList = new ScRangeFindList( pDocSh->GetTitle() );
282 ColorData nColorData = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
284 ESelection aSel( 0, nStart, 0, nPos );
285 SfxItemSet aSet( pEngine->GetEmptyItemSet() );
286 aSet.Put( SvxColorItem( Color( nColorData ),
287 EE_CHAR_COLOR ) );
288 pEngine->QuickSetAttribs( aSet, aSel );
289 ++nCount;
293 // Do not skip last separator; could be a quote (?)
296 if (nCount)
298 pEngine->SetUpdateMode( true );
300 pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );
304 void ScInputHandler::SetDocumentDisposing( bool b )
306 mbDocumentDisposing = b;
309 static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
311 if ( pView )
313 ESelection aOldSel = pView->GetSelection();
314 if (aOldSel.HasRange())
315 pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
316 aOldSel.nEndPara, aOldSel.nEndPos ) );
318 EditEngine* pEngine = pView->GetEditEngine();
319 pEngine->QuickInsertText( rNewStr, rOldSel );
321 // Dummy InsertText for Update and Paint
322 // To do that we need to cancel the selection from above (before QuickInsertText)
323 pView->InsertText( EMPTY_OUSTRING, false );
325 sal_Int32 nLen = pEngine->GetTextLen(0);
326 ESelection aSel( 0, nLen, 0, nLen );
327 pView->SetSelection( aSel ); // Set cursor to the end
331 void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
333 ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
334 if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
336 ScRangeFindData* pData = pRangeFindList->GetObject( nIndex );
337 sal_Int32 nOldStart = pData->nSelStart;
338 sal_Int32 nOldEnd = pData->nSelEnd;
339 ColorData nNewColor = pRangeFindList->FindColor( rNew, nIndex );
341 ScRange aJustified = rNew;
342 aJustified.Justify(); // Always display Ref in the Formula the right way
343 ScDocument* pDoc = pDocView->GetViewData().GetDocument();
344 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
345 OUString aNewStr(aJustified.Format(pData->nFlags, pDoc, aAddrDetails));
346 ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
347 SfxItemSet aSet( pEngine->GetEmptyItemSet() );
349 DataChanging();
351 lcl_Replace( pTopView, aNewStr, aOldSel );
352 lcl_Replace( pTableView, aNewStr, aOldSel );
353 aSet.Put( SvxColorItem( Color( nNewColor ), EE_CHAR_COLOR ) );
354 pEngine->QuickSetAttribs( aSet, aOldSel );
356 bInRangeUpdate = true;
357 DataChanged();
358 bInRangeUpdate = false;
360 long nDiff = aNewStr.getLength() - (long)(nOldEnd-nOldStart);
362 pData->aRef = rNew;
363 pData->nSelEnd = pData->nSelEnd + nDiff;
364 pData->nColorData = nNewColor;
366 sal_uInt16 nCount = (sal_uInt16) pRangeFindList->Count();
367 for (sal_uInt16 i=nIndex+1; i<nCount; i++)
369 ScRangeFindData* pNext = pRangeFindList->GetObject( i );
370 pNext->nSelStart = pNext->nSelStart + nDiff;
371 pNext->nSelEnd = pNext->nSelEnd + nDiff;
374 EditView* pActiveView = pTopView ? pTopView : pTableView;
375 pActiveView->ShowCursor( false, true );
377 else
379 OSL_FAIL("UpdateRange: we're missing something");
383 void ScInputHandler::DeleteRangeFinder()
385 ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
386 if ( pRangeFindList && pPaintView )
388 ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
389 pRangeFindList->SetHidden(true);
390 pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) ); // Steal
391 DELETEZ(pRangeFindList);
395 inline OUString GetEditText(EditEngine* pEng)
397 return ScEditUtil::GetSpaceDelimitedString(*pEng);
400 static void lcl_RemoveTabs(OUString& rStr)
402 removeChars(rStr, '\t');
405 static void lcl_RemoveLineEnd(OUString& rStr)
407 rStr = convertLineEnd(rStr, LINEEND_LF);
408 removeChars(rStr, '\n');
411 static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
413 int nDir;
414 sal_Unicode c1, c2 = 0;
415 c1 = rStr[nPos];
416 switch ( c1 )
418 case '(' :
419 c2 = ')';
420 nDir = 1;
421 break;
422 case ')' :
423 c2 = '(';
424 nDir = -1;
425 break;
426 case '<' :
427 c2 = '>';
428 nDir = 1;
429 break;
430 case '>' :
431 c2 = '<';
432 nDir = -1;
433 break;
434 case '{' :
435 c2 = '}';
436 nDir = 1;
437 break;
438 case '}' :
439 c2 = '{';
440 nDir = -1;
441 break;
442 case '[' :
443 c2 = ']';
444 nDir = 1;
445 break;
446 case ']' :
447 c2 = '[';
448 nDir = -1;
449 break;
450 default:
451 nDir = 0;
453 if ( !nDir )
454 return -1;
455 sal_Int32 nLen = rStr.getLength();
456 const sal_Unicode* p0 = rStr.getStr();
457 const sal_Unicode* p;
458 const sal_Unicode* p1;
459 sal_uInt16 nQuotes = 0;
460 if ( nPos < nLen / 2 )
462 p = p0;
463 p1 = p0 + nPos;
465 else
467 p = p0 + nPos;
468 p1 = p0 + nLen;
470 while ( p < p1 )
472 if ( *p++ == '\"' )
473 nQuotes++;
475 // Odd number of quotes that we find ourselves in a string
476 bool bLookInString = ((nQuotes % 2) != 0);
477 bool bInString = bLookInString;
478 p = p0 + nPos;
479 p1 = (nDir < 0 ? p0 : p0 + nLen) ;
480 sal_uInt16 nLevel = 1;
481 while ( p != p1 && nLevel )
483 p += nDir;
484 if ( *p == '\"' )
486 bInString = !bInString;
487 if ( bLookInString && !bInString )
488 p = p1; // That's it then
490 else if ( bInString == bLookInString )
492 if ( *p == c1 )
493 nLevel++;
494 else if ( *p == c2 )
495 nLevel--;
498 if ( nLevel )
499 return -1;
500 return (sal_Int32) (p - p0);
503 ScInputHandler::ScInputHandler()
504 : pInputWin( NULL ),
505 pEngine( NULL ),
506 pTableView( NULL ),
507 pTopView( NULL ),
508 pColumnData( NULL ),
509 pFormulaData( NULL ),
510 pFormulaDataPara( NULL ),
511 pTipVisibleParent( NULL ),
512 nTipVisible( 0 ),
513 pTipVisibleSecParent( NULL ),
514 nTipVisibleSec( 0 ),
515 nFormSelStart( 0 ),
516 nFormSelEnd( 0 ),
517 nAutoPar( 0 ),
518 eMode( SC_INPUT_NONE ),
519 bUseTab( false ),
520 bTextValid( true ),
521 bModified( false ),
522 bSelIsRef( false ),
523 bFormulaMode( false ),
524 bInRangeUpdate( false ),
525 bParenthesisShown( false ),
526 bCreatingFuncView( false ),
527 bInEnterHandler( false ),
528 bCommandErrorShown( false ),
529 bInOwnChange( false ),
530 bProtected( false ),
531 bCellHasPercentFormat( false ),
532 bLastIsSymbol( false ),
533 mbDocumentDisposing(false),
534 nValidation( 0 ),
535 eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ),
536 aScaleX( 1,1 ),
537 aScaleY( 1,1 ),
538 pRefViewSh( NULL ),
539 pLastPattern( NULL ),
540 pEditDefaults( NULL ),
541 pLastState( NULL ),
542 pDelayTimer( NULL ),
543 pRangeFindList( NULL ),
544 maFormulaChar()
546 // The InputHandler is constructed with the view, so SfxViewShell::Current
547 // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
548 pActiveViewSh = NULL;
550 // Bindings (only still used for Invalidate) are retrieved if needed on demand
553 ScInputHandler::~ScInputHandler()
555 // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
556 // thus we can't rely on any Sfx functions
557 if (!mbDocumentDisposing) // inplace
558 EnterHandler(); // Finish input
560 if (SC_MOD()->GetRefInputHdl() == this)
561 SC_MOD()->SetRefInputHdl(NULL);
563 if ( pInputWin && pInputWin->GetInputHandler() == this )
564 pInputWin->SetInputHandler( NULL );
566 delete pRangeFindList;
567 delete pEditDefaults;
568 delete pEngine;
569 delete pLastState;
570 delete pDelayTimer;
571 delete pColumnData;
572 delete pFormulaData;
573 delete pFormulaDataPara;
576 void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
578 if ( rX != aScaleX || rY != aScaleY )
580 aScaleX = rX;
581 aScaleY = rY;
582 if (pEngine)
584 MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
585 pEngine->SetRefMapMode( aMode );
590 void ScInputHandler::UpdateRefDevice()
592 if (!pEngine)
593 return;
595 bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
596 bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
597 EEControlBits nCtrl = pEngine->GetControlWord();
598 if ( bTextWysiwyg || bInPlace )
599 nCtrl |= EEControlBits::FORMAT100; // EditEngine default: always format for 100%
600 else
601 nCtrl &= ~EEControlBits::FORMAT100; // when formatting for screen, use the actual MapMode
602 pEngine->SetControlWord( nCtrl );
603 if ( bTextWysiwyg && pActiveViewSh )
604 pEngine->SetRefDevice( pActiveViewSh->GetViewData().GetDocument()->GetPrinter() );
605 else
606 pEngine->SetRefDevice( NULL );
608 MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
609 pEngine->SetRefMapMode( aMode );
611 // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
612 // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
613 if ( !( bTextWysiwyg && pActiveViewSh ) )
615 pEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
619 void ScInputHandler::ImplCreateEditEngine()
621 if ( !pEngine )
623 if ( pActiveViewSh )
625 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
626 pEngine = new ScFieldEditEngine(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
628 else
629 pEngine = new ScFieldEditEngine(NULL, EditEngine::CreatePool(), NULL, true);
630 pEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
631 UpdateRefDevice(); // also sets MapMode
632 pEngine->SetPaperSize( Size( 1000000, 1000000 ) );
633 pEditDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
635 pEngine->SetControlWord( pEngine->GetControlWord() | EEControlBits::AUTOCORRECT );
636 pEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
639 // set the EditEngine so that it invalidates the view instead of direct
640 // paint
641 if (pActiveViewSh)
643 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
644 if (EditView* pEditView = pEngine->GetActiveView())
645 pEditView->setTiledRendering(rDoc.GetDrawLayer()->isTiledRendering());
649 void ScInputHandler::UpdateAutoCorrFlag()
651 EEControlBits nCntrl = pEngine->GetControlWord();
652 EEControlBits nOld = nCntrl;
654 // Don't use pLastPattern here (may be invalid because of AutoStyle)
655 bool bDisable = bLastIsSymbol || bFormulaMode;
656 if ( bDisable )
657 nCntrl &= ~EEControlBits::AUTOCORRECT;
658 else
659 nCntrl |= EEControlBits::AUTOCORRECT;
661 if ( nCntrl != nOld )
662 pEngine->SetControlWord(nCntrl);
665 void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
667 if ( pActiveViewSh )
669 ScViewData& rViewData = pActiveViewSh->GetViewData();
670 bool bOnlineSpell = rViewData.GetDocument()->GetDocOptions().IsAutoSpell();
672 // SetDefaultLanguage is independent of the language attributes,
673 // ScGlobal::GetEditDefaultLanguage is always used.
674 // It must be set every time in case the office language was changed.
676 pEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
678 // if called for changed options, update flags only if already editing
679 // if called from StartTable, always update flags
681 if ( bFromStartTab || eMode != SC_INPUT_NONE )
683 EEControlBits nCntrl = pEngine->GetControlWord();
684 EEControlBits nOld = nCntrl;
685 if( bOnlineSpell )
686 nCntrl |= EEControlBits::ONLINESPELLING;
687 else
688 nCntrl &= ~EEControlBits::ONLINESPELLING;
689 // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
690 if ( pLastPattern && pLastPattern->IsSymbolFont() )
691 nCntrl &= ~EEControlBits::AUTOCORRECT;
692 else
693 nCntrl |= EEControlBits::AUTOCORRECT;
694 if ( nCntrl != nOld )
695 pEngine->SetControlWord(nCntrl);
697 ScDocument* pDoc = rViewData.GetDocument();
698 pDoc->ApplyAsianEditSettings( *pEngine );
699 pEngine->SetDefaultHorizontalTextDirection(
700 (EEHorizontalTextDirection)pDoc->GetEditTextDirection( rViewData.GetTabNo() ) );
701 pEngine->SetFirstWordCapitalization( false );
704 // Language is set separately, so the speller is needed only if online spelling is active
705 if ( bOnlineSpell ) {
706 com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
707 pEngine->SetSpeller( xXSpellChecker1 );
710 bool bHyphen = pLastPattern && static_cast<const SfxBoolItem&>(pLastPattern->GetItem(ATTR_HYPHENATE)).GetValue();
711 if ( bHyphen ) {
712 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
713 pEngine->SetHyphenator( xXHyphenator );
718 // Function/Range names etc. as Tip help
720 // The other types are defined in ScDocument::GetFormulaEntries
721 void ScInputHandler::GetFormulaData()
723 if ( pActiveViewSh )
725 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
727 if ( pFormulaData )
728 pFormulaData->clear();
729 else
731 pFormulaData = new ScTypedCaseStrSet;
734 if( pFormulaDataPara )
735 pFormulaDataPara->clear();
736 else
737 pFormulaDataPara = new ScTypedCaseStrSet;
739 const OUString aParenthesesReplacement( cParenthesesReplacement);
740 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
741 sal_uLong nListCount = pFuncList->GetCount();
742 for(sal_uLong i=0;i<nListCount;i++)
744 const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
745 if ( pDesc->pFuncName )
747 const sal_Unicode* pName = pDesc->pFuncName->getStr();
748 const sal_Int32 nLen = pDesc->pFuncName->getLength();
749 // fdo#75264 fill maFormulaChar with all characters used in formula names
750 for ( sal_Int32 j = 0; j < nLen; j++ )
752 sal_Unicode c = pName[ j ];
753 maFormulaChar.insert( c );
755 OUString aFuncName = *pDesc->pFuncName + aParenthesesReplacement;
756 pFormulaData->insert(ScTypedStrData(aFuncName, 0.0, ScTypedStrData::Standard));
757 pDesc->initArgumentInfo();
758 OUString aEntry = pDesc->getSignature();
759 pFormulaDataPara->insert(ScTypedStrData(aEntry, 0.0, ScTypedStrData::Standard));
762 miAutoPosFormula = pFormulaData->end();
763 rDoc.GetFormulaEntries( *pFormulaData );
764 rDoc.GetFormulaEntries( *pFormulaDataPara );
768 IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent*, pEvent )
770 if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
771 HideTip();
772 return 0;
775 IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent*, pEvent )
777 if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
778 HideTipBelow();
779 return 0;
782 void ScInputHandler::HideTip()
784 if ( nTipVisible )
786 if (pTipVisibleParent)
787 pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
788 Help::HideTip( nTipVisible );
789 nTipVisible = 0;
790 pTipVisibleParent = NULL;
792 aManualTip.clear();
794 void ScInputHandler::HideTipBelow()
796 if ( nTipVisibleSec )
798 if (pTipVisibleSecParent)
799 pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
800 Help::HideTip( nTipVisibleSec );
801 nTipVisibleSec = 0;
802 pTipVisibleSecParent = NULL;
804 aManualTip.clear();
807 void ScInputHandler::ShowArgumentsTip( OUString& rSelText )
809 ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
810 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
811 const sal_Unicode cSheetSep = lcl_getSheetSeparator(&pDocSh->GetDocument());
812 FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
813 bool bFound = false;
814 while( !bFound )
816 rSelText += ")";
817 sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
818 if( nLeftParentPos != -1 )
820 sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
821 const IFunctionDescription* ppFDesc;
822 ::std::vector< OUString> aArgs;
823 if( aHelper.GetNextFunc( rSelText, false, nNextFStart, NULL, &ppFDesc, &aArgs ) )
825 if( !ppFDesc->getFunctionName().isEmpty() )
827 sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
828 sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
829 OUString aFuncName( ppFDesc->getFunctionName() + "(");
830 OUString aNew;
831 ScTypedCaseStrSet::const_iterator it =
832 findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
833 if (it != pFormulaDataPara->end())
835 bool bFlag = false;
836 sal_uInt16 nActive = 0;
837 for( sal_uInt16 i=0; i < nArgs; i++ )
839 sal_Int32 nLength = aArgs[i].getLength();
840 if( nArgPos <= rSelText.getLength()-1 )
842 nActive = i+1;
843 bFlag = true;
845 nArgPos+=nLength+1;
847 if( bFlag )
849 sal_Int32 nCountSemicolon = comphelper::string::getTokenCount(aNew, cSep) - 1;
850 sal_Int32 nCountDot = comphelper::string::getTokenCount(aNew, cSheetSep) - 1;
851 sal_Int32 nStartPosition = 0;
852 sal_Int32 nEndPosition = 0;
854 if( !nCountSemicolon )
856 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
858 sal_Unicode cNext = aNew[i];
859 if( cNext == '(' )
861 nStartPosition = i+1;
865 else if( !nCountDot )
867 sal_uInt16 nCount = 0;
868 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
870 sal_Unicode cNext = aNew[i];
871 if( cNext == '(' )
873 nStartPosition = i+1;
875 else if( cNext == cSep )
877 nCount ++;
878 nEndPosition = i;
879 if( nCount == nActive )
881 break;
883 nStartPosition = nEndPosition+1;
887 else
889 sal_uInt16 nCount = 0;
890 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
892 sal_Unicode cNext = aNew[i];
893 if( cNext == '(' )
895 nStartPosition = i+1;
897 else if( cNext == cSep )
899 nCount ++;
900 nEndPosition = i;
901 if( nCount == nActive )
903 break;
905 nStartPosition = nEndPosition+1;
907 else if( cNext == cSheetSep )
909 continue;
914 if (nStartPosition > 0)
916 OUStringBuffer aBuf;
917 aBuf.append(aNew.copy(0, nStartPosition));
918 aBuf.append(static_cast<sal_Unicode>(0x25BA));
919 aBuf.append(aNew.copy(nStartPosition));
920 aNew = aBuf.makeStringAndClear();
921 ShowTipBelow( aNew );
922 bFound = true;
925 else
927 ShowTipBelow( aNew );
928 bFound = true;
934 else
936 break;
941 void ScInputHandler::ShowTipCursor()
943 HideTip();
944 HideTipBelow();
945 EditView* pActiveView = pTopView ? pTopView : pTableView;
947 if ( bFormulaMode && pActiveView && pFormulaDataPara && pEngine->GetParagraphCount() == 1 )
949 OUString aParagraph = pEngine->GetText( 0 );
950 ESelection aSel = pActiveView->GetSelection();
951 aSel.Adjust();
953 if ( aParagraph.getLength() < aSel.nEndPos )
954 return;
956 if ( aSel.nEndPos > 0 )
958 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
960 ShowArgumentsTip( aSelText );
965 void ScInputHandler::ShowTip( const OUString& rText )
967 // aManualTip needs to be set afterwards from outside
968 HideTip();
969 EditView* pActiveView = pTopView ? pTopView : pTableView;
970 if (pActiveView)
972 Point aPos;
973 pTipVisibleParent = pActiveView->GetWindow();
974 vcl::Cursor* pCur = pActiveView->GetCursor();
975 if (pCur)
976 aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
977 aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
978 Rectangle aRect( aPos, aPos );
980 QuickHelpFlags nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
981 nTipVisible = Help::ShowTip(pTipVisibleParent, aRect, rText, nAlign);
982 pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
986 void ScInputHandler::ShowTipBelow( const OUString& rText )
988 HideTipBelow();
990 EditView* pActiveView = pTopView ? pTopView : pTableView;
991 if ( pActiveView )
993 Point aPos;
994 pTipVisibleSecParent = pActiveView->GetWindow();
995 vcl::Cursor* pCur = pActiveView->GetCursor();
996 if ( pCur )
998 Point aLogicPos = pCur->GetPos();
999 aLogicPos.Y() += pCur->GetHeight();
1000 aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
1002 aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
1003 Rectangle aRect( aPos, aPos );
1004 QuickHelpFlags nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
1005 nTipVisibleSec = Help::ShowTip(pTipVisibleSecParent, aRect, rText, nAlign);
1006 pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1010 bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
1012 if ( aStart.isEmpty() )
1013 return false;
1015 aStart = ScGlobal::pCharClass->uppercase( aStart );
1016 sal_Int32 nPos = aStart.getLength() - 1;
1017 sal_Unicode c = aStart[ nPos ];
1018 // fdo#75264 use maFormulaChar to check if characters are used in function names
1019 ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
1020 if ( p == maFormulaChar.end() )
1021 return false; // last character is not part of any function name, quit
1023 ::std::vector<sal_Unicode> aTemp;
1024 aTemp.push_back( c );
1025 for(sal_Int32 i = nPos - 1; i >= 0; --i)
1027 c = aStart[ i ];
1028 p = maFormulaChar.find( c );
1030 if (p == maFormulaChar.end())
1031 break;
1033 aTemp.push_back( c );
1036 ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
1037 aResult = OUString( *rIt++ );
1038 while ( rIt != aTemp.rend() )
1039 aResult += OUString( *rIt++ );
1041 return true;
1044 void ScInputHandler::UseFormulaData()
1046 EditView* pActiveView = pTopView ? pTopView : pTableView;
1048 // Formulas may only have 1 paragraph
1049 if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
1051 OUString aParagraph = pEngine->GetText( 0 );
1052 ESelection aSel = pActiveView->GetSelection();
1053 aSel.Adjust();
1055 // Due to differences between table and input cell (e.g clipboard with line breaks),
1056 // the selection may not be in line with the EditEngine anymore.
1057 // Just return without any indication as to why.
1058 if ( aSel.nEndPos > aParagraph.getLength() )
1059 return;
1061 if ( aParagraph.getLength() > aSel.nEndPos &&
1062 ( ScGlobal::pCharClass->isLetterNumeric( aParagraph, aSel.nEndPos ) ||
1063 aParagraph[ aSel.nEndPos ] == '_' ||
1064 aParagraph[ aSel.nEndPos ] == '.' ) )
1065 return;
1067 // Is the cursor at the end of a word?
1068 if ( aSel.nEndPos > 0 )
1070 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1072 OUString aText;
1073 if ( GetFuncName( aSelText, aText ) )
1075 // function name is incomplete:
1076 // show first matching function name as tip above cell
1077 OUString aNew;
1078 miAutoPosFormula = pFormulaData->end();
1079 miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
1080 if (miAutoPosFormula != pFormulaData->end())
1082 // check if partial function name is not Between quotes
1083 bool bBetweenQuotes = false;
1084 for ( int n = 0; n < aSelText.getLength(); n++ )
1086 if ( aSelText[ n ] == '"' )
1087 bBetweenQuotes = !bBetweenQuotes;
1089 if ( bBetweenQuotes )
1090 return; // we're between quotes
1092 if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1093 aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1094 ShowTip( aNew );
1095 aAutoSearch = aText;
1097 return;
1100 // function name is complete:
1101 // show tip below the cell with function name and arguments of function
1102 ShowArgumentsTip( aSelText );
1107 void ScInputHandler::NextFormulaEntry( bool bBack )
1109 EditView* pActiveView = pTopView ? pTopView : pTableView;
1110 if ( pActiveView && pFormulaData )
1112 OUString aNew;
1113 ScTypedCaseStrSet::const_iterator itNew = findText(*pFormulaData, miAutoPosFormula, aAutoSearch, aNew, bBack);
1114 if (itNew != pFormulaData->end())
1116 miAutoPosFormula = itNew;
1117 if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1118 aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1119 ShowTip(aNew); // Display a quick help
1123 // For Tab we always call HideCursor first
1124 if (pActiveView)
1125 pActiveView->ShowCursor();
1128 namespace {
1130 bool needToExtendSelection(const OUString& rSelectedText, const OUString& rInsertText)
1132 return !rInsertText.startsWithIgnoreAsciiCase(rSelectedText);
1135 void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
1137 if (pView)
1139 ESelection aSel = pView->GetSelection();
1140 --aSel.nStartPos;
1141 --aSel.nEndPos;
1142 pView->SetSelection(aSel);
1143 pView->SelectCurrentWord();
1145 // a dot and underscore are word separators so we need special
1146 // treatment for any formula containing a dot or underscore
1147 if(rInsert.indexOf(".") != -1 || rInsert.indexOf("_") != -1)
1149 // need to make sure that we replace also the part before the dot
1150 // go through the word to find the match with the insert string
1151 aSel = pView->GetSelection();
1152 ESelection aOldSelection = aSel;
1153 OUString aSelectedText = pView->GetSelected();
1154 if ( needToExtendSelection( aSelectedText, rInsert ) )
1156 while(needToExtendSelection(aSelectedText, rInsert))
1158 assert(aSel.nStartPos > 0);
1159 --aSel.nStartPos;
1160 aSel.nEndPos = aSel.nStartPos;
1161 pView->SetSelection(aSel);
1162 pView->SelectCurrentWord();
1163 aSelectedText = pView->GetSelected();
1165 aSel.nStartPos = aSel.nEndPos - ( aSelectedText.getLength() - 1 );
1167 else
1169 aSel.nStartPos = aSel.nEndPos - aSelectedText.getLength();
1171 aSel.nEndPos = aOldSelection.nEndPos;
1172 pView->SetSelection(aSel);
1175 OUString aInsStr = rInsert;
1176 sal_Int32 nInsLen = aInsStr.getLength();
1177 bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
1178 && aInsStr[nInsLen-1] == ')' );
1179 if ( bDoParen )
1181 // Do not insert parentheses after function names if there already are some
1182 // (e.g. if the function name was edited).
1183 ESelection aWordSel = pView->GetSelection();
1184 OUString aOld = pView->GetEditEngine()->GetText(0);
1186 // aWordSel.EndPos points one behind string if word at end
1187 if (aWordSel.nEndPos < aOld.getLength())
1189 sal_Unicode cNext = aOld[aWordSel.nEndPos];
1190 if ( cNext == '(' )
1192 bDoParen = false;
1193 aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
1198 pView->InsertText( aInsStr, false );
1200 if ( bDoParen ) // Put cursor between parentheses
1202 aSel = pView->GetSelection();
1203 --aSel.nStartPos;
1204 --aSel.nEndPos;
1205 pView->SetSelection(aSel);
1207 rParInserted = true;
1214 void ScInputHandler::PasteFunctionData()
1216 if (pFormulaData && miAutoPosFormula != pFormulaData->end())
1218 const ScTypedStrData& rData = *miAutoPosFormula;
1219 OUString aInsert = rData.GetString();
1220 if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
1221 aInsert = aInsert.copy( 0, aInsert.getLength()-1) + "()";
1222 bool bParInserted = false;
1224 DataChanging(); // Cannot be new
1225 completeFunction( pTopView, aInsert, bParInserted );
1226 completeFunction( pTableView, aInsert, bParInserted );
1227 DataChanged();
1228 ShowTipCursor();
1230 if (bParInserted)
1231 AutoParAdded();
1234 HideTip();
1236 EditView* pActiveView = pTopView ? pTopView : pTableView;
1237 if (pActiveView)
1238 pActiveView->ShowCursor();
1241 // Calculate selection and display as tip help
1242 static OUString lcl_Calculate( const OUString& rFormula, ScDocument* pDoc, const ScAddress &rPos )
1244 //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1245 // Quotation marks for Strings are only inserted here.
1247 if(rFormula.isEmpty())
1248 return OUString();
1250 boost::scoped_ptr<ScSimpleFormulaCalculator> pCalc( new ScSimpleFormulaCalculator( pDoc, rPos, rFormula ) );
1252 // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1253 // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1254 bool bColRowName = pCalc->HasColRowName();
1255 if ( bColRowName )
1257 // ColRowName in RPN code?
1258 if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1259 { // ==1: Single one is as a Parameter always a Range
1260 // ==0: It might be one, if ...
1261 OUStringBuffer aBraced;
1262 aBraced.append('(');
1263 aBraced.append(rFormula);
1264 aBraced.append(')');
1265 pCalc.reset( new ScSimpleFormulaCalculator( pDoc, rPos, aBraced.makeStringAndClear() ) );
1267 else
1268 bColRowName = false;
1271 sal_uInt16 nErrCode = pCalc->GetErrCode();
1272 if ( nErrCode != 0 )
1273 return ScGlobal::GetErrorString(nErrCode);
1275 SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
1276 OUString aValue;
1277 if ( pCalc->IsValue() )
1279 double n = pCalc->GetValue();
1280 sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
1281 pCalc->GetFormatType(), ScGlobal::eLnge );
1282 aFormatter.GetInputLineString( n, nFormat, aValue );
1283 //! display OutputString but insert InputLineString
1285 else
1287 OUString aStr = pCalc->GetString().getString();
1288 sal_uLong nFormat = aFormatter.GetStandardFormat(
1289 pCalc->GetFormatType(), ScGlobal::eLnge);
1291 Color* pColor;
1292 aFormatter.GetOutputString( aStr, nFormat,
1293 aValue, &pColor );
1296 aValue = "\"" + aValue + "\"";
1297 //! Escape quotation marks in String??
1300 ScRange aTestRange;
1301 if ( bColRowName || (aTestRange.Parse(rFormula) & SCA_VALID) )
1302 aValue = aValue + " ...";
1304 return aValue;
1307 void ScInputHandler::FormulaPreview()
1309 OUString aValue;
1310 EditView* pActiveView = pTopView ? pTopView : pTableView;
1311 if ( pActiveView && pActiveViewSh )
1313 OUString aPart = pActiveView->GetSelected();
1314 if (aPart.isEmpty())
1315 aPart = pEngine->GetText(0);
1316 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1317 aValue = lcl_Calculate( aPart, &rDoc, aCursorPos );
1320 if (!aValue.isEmpty())
1322 ShowTip( aValue ); // Display as QuickHelp
1323 aManualTip = aValue; // Set after ShowTip
1324 if (pFormulaData)
1325 miAutoPosFormula = pFormulaData->end();
1326 if (pColumnData)
1327 miAutoPosColumn = pColumnData->end();
1331 void ScInputHandler::PasteManualTip()
1333 // Three dots at the end -> Range reference -> do not insert
1334 // FIXME: Once we have matrix constants, we can change this
1335 sal_Int32 nTipLen = aManualTip.getLength();
1336 sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1337 if ( nTipLen && ( nTipLen < 3 || aManualTip.copy( nTipLen2-3 ) != "..." ) )
1339 DataChanging(); // Cannot be new
1341 OUString aInsert = aManualTip;
1342 EditView* pActiveView = pTopView ? pTopView : pTableView;
1343 if (!pActiveView->HasSelection())
1345 // Nothing selected -> select everything
1346 sal_Int32 nOldLen = pEngine->GetTextLen(0);
1347 ESelection aAllSel( 0, 0, 0, nOldLen );
1348 if ( pTopView )
1349 pTopView->SetSelection( aAllSel );
1350 if ( pTableView )
1351 pTableView->SetSelection( aAllSel );
1354 ESelection aSel = pActiveView->GetSelection();
1355 aSel.Adjust();
1356 OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1357 if ( !aSel.nStartPos ) // Selection from the start?
1359 if ( aSel.nEndPos == pEngine->GetTextLen(0) )
1361 // Everything selected -> skip quotation marks
1362 if ( aInsert[0] == '"' )
1363 aInsert = aInsert.copy(1);
1364 sal_Int32 nInsLen = aInsert.getLength();
1365 if ( aInsert.endsWith("\"") )
1366 aInsert = aInsert.copy( 0, nInsLen-1 );
1368 else if ( aSel.nEndPos )
1370 // Not everything selected -> do not overwrite equality sign
1371 //FIXME: Even double equality signs??
1372 aSel.nStartPos = 1;
1373 if ( pTopView )
1374 pTopView->SetSelection( aSel );
1375 if ( pTableView )
1376 pTableView->SetSelection( aSel );
1379 if ( pTopView )
1380 pTopView->InsertText( aInsert, true );
1381 if ( pTableView )
1382 pTableView->InsertText( aInsert, true );
1384 DataChanged();
1387 HideTip();
1390 void ScInputHandler::ResetAutoPar()
1392 nAutoPar = 0;
1395 void ScInputHandler::AutoParAdded()
1397 ++nAutoPar; // Closing parenthesis can be overwritten
1400 bool ScInputHandler::CursorAtClosingPar()
1402 // Test if the cursor is before a closing parenthesis
1403 // Selection from SetReference has been removed before
1404 EditView* pActiveView = pTopView ? pTopView : pTableView;
1405 if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1407 ESelection aSel = pActiveView->GetSelection();
1408 sal_Int32 nPos = aSel.nStartPos;
1409 OUString aFormula = pEngine->GetText(0);
1410 if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1411 return true;
1413 return false;
1416 void ScInputHandler::SkipClosingPar()
1418 // this is called when a ')' is typed and the cursor is before a ')'
1419 // that can be overwritten -> just set the cursor behind the ')'
1421 EditView* pActiveView = pTopView ? pTopView : pTableView;
1422 if (pActiveView)
1424 ESelection aSel = pActiveView->GetSelection();
1425 ++aSel.nStartPos;
1426 ++aSel.nEndPos;
1428 // this is in a formula (only one paragraph), so the selection
1429 // can be used directly for the TopView
1431 if ( pTopView )
1432 pTopView->SetSelection( aSel );
1433 if ( pTableView )
1434 pTableView->SetSelection( aSel );
1437 OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
1438 --nAutoPar;
1441 // Auto input
1443 void ScInputHandler::GetColData()
1445 if ( pActiveViewSh )
1447 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1449 if ( pColumnData )
1450 pColumnData->clear();
1451 else
1452 pColumnData = new ScTypedCaseStrSet;
1454 std::vector<ScTypedStrData> aEntries;
1455 rDoc.GetDataEntries(
1456 aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), true, aEntries, true);
1457 if (!aEntries.empty())
1458 pColumnData->insert(aEntries.begin(), aEntries.end());
1460 miAutoPosColumn = pColumnData->end();
1464 void ScInputHandler::UseColData() // When typing
1466 EditView* pActiveView = pTopView ? pTopView : pTableView;
1467 if ( pActiveView && pColumnData )
1469 // Only change when cursor is at the end
1470 ESelection aSel = pActiveView->GetSelection();
1471 aSel.Adjust();
1473 sal_Int32 nParCnt = pEngine->GetParagraphCount();
1474 if ( aSel.nEndPara+1 == nParCnt )
1476 sal_Int32 nParLen = pEngine->GetTextLen( aSel.nEndPara );
1477 if ( aSel.nEndPos == nParLen )
1479 OUString aText = GetEditText(pEngine);
1480 if (!aText.isEmpty())
1482 OUString aNew;
1483 miAutoPosColumn = pColumnData->end();
1484 miAutoPosColumn = findText(*pColumnData, miAutoPosColumn, aText, aNew, false);
1485 if (miAutoPosColumn != pColumnData->end())
1487 // Strings can contain line endings (e.g. due to dBase import),
1488 // which would result in multiple paragraphs here, which is not desirable.
1489 //! Then GetExactMatch doesn't work either
1490 lcl_RemoveLineEnd( aNew );
1492 // Keep paragraph, just append the rest
1493 //! Exact replacement in EnterHandler !!!
1494 // One Space between paragraphs:
1495 sal_Int32 nEdLen = pEngine->GetTextLen() + nParCnt - 1;
1496 OUString aIns = aNew.copy(nEdLen);
1498 // Selection must be "backwards", so the cursor stays behind the last
1499 // typed character
1500 ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
1501 aSel.nEndPara, aSel.nEndPos );
1503 // When editing in input line, apply to both edit views
1504 if ( pTableView )
1506 pTableView->InsertText( aIns, false );
1507 pTableView->SetSelection( aSelection );
1509 if ( pTopView )
1511 pTopView->InsertText( aIns, false );
1512 pTopView->SetSelection( aSelection );
1515 aAutoSearch = aText; // To keep searching - nAutoPos is set
1517 if (aText.getLength() == aNew.getLength())
1519 // If the inserted text is found, consume TAB only if there's more coming
1520 OUString aDummy;
1521 ScTypedCaseStrSet::const_iterator itNextPos =
1522 findText(*pColumnData, miAutoPosColumn, aText, aDummy, false);
1523 bUseTab = itNextPos != pColumnData->end();
1525 else
1526 bUseTab = true;
1534 void ScInputHandler::NextAutoEntry( bool bBack )
1536 EditView* pActiveView = pTopView ? pTopView : pTableView;
1537 if ( pActiveView && pColumnData )
1539 if (miAutoPosColumn != pColumnData->end() && !aAutoSearch.isEmpty())
1541 // Is the selection still valid (could be changed via the mouse)?
1542 ESelection aSel = pActiveView->GetSelection();
1543 aSel.Adjust();
1544 sal_Int32 nParCnt = pEngine->GetParagraphCount();
1545 if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
1547 OUString aText = GetEditText(pEngine);
1548 sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
1549 sal_Int32 nParLen = pEngine->GetTextLen( aSel.nEndPara );
1550 if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
1552 OUString aNew;
1553 ScTypedCaseStrSet::const_iterator itNew =
1554 findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
1556 if (itNew != pColumnData->end())
1558 // match found!
1559 miAutoPosColumn = itNew;
1560 bInOwnChange = true; // disable ModifyHdl (reset below)
1562 lcl_RemoveLineEnd( aNew );
1563 OUString aIns = aNew.copy(aAutoSearch.getLength());
1565 // when editing in input line, apply to both edit views
1566 if ( pTableView )
1568 pTableView->DeleteSelected();
1569 pTableView->InsertText( aIns, false );
1570 pTableView->SetSelection( ESelection(
1571 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
1572 aSel.nEndPara, aSel.nStartPos ) );
1574 if ( pTopView )
1576 pTopView->DeleteSelected();
1577 pTopView->InsertText( aIns, false );
1578 pTopView->SetSelection( ESelection(
1579 aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
1580 aSel.nEndPara, aSel.nStartPos ) );
1583 bInOwnChange = false;
1590 // For Tab, HideCursor was always called first
1591 if (pActiveView)
1592 pActiveView->ShowCursor();
1595 // Highlight parentheses
1596 void ScInputHandler::UpdateParenthesis()
1598 // Find parentheses
1599 //TODO: Can we disable parentheses highlighting per parentheses?
1600 bool bFound = false;
1601 if ( bFormulaMode && eMode != SC_INPUT_TOP )
1603 if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
1605 ESelection aSel = pTableView->GetSelection();
1606 if (aSel.nStartPos)
1608 // Examine character left to the cursor
1609 sal_Int32 nPos = aSel.nStartPos - 1;
1610 OUString aFormula = pEngine->GetText(0);
1611 sal_Unicode c = aFormula[nPos];
1612 if ( c == '(' || c == ')' )
1614 sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
1615 if ( nOther != -1 )
1617 SfxItemSet aSet( pEngine->GetEmptyItemSet() );
1618 aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
1620 //! Distinguish if cell is already highlighted!!!!
1621 if (bParenthesisShown)
1623 // Remove old highlighting
1624 sal_Int32 nCount = pEngine->GetParagraphCount();
1625 for (sal_Int32 i=0; i<nCount; i++)
1626 pEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
1629 ESelection aSelThis( 0,nPos, 0,nPos+1 );
1630 pEngine->QuickSetAttribs( aSet, aSelThis );
1631 ESelection aSelOther( 0,nOther, 0,nOther+1 );
1632 pEngine->QuickSetAttribs( aSet, aSelOther );
1634 // Dummy InsertText for Update and Paint (selection is empty)
1635 pTableView->InsertText( EMPTY_OUSTRING, false );
1637 bFound = true;
1642 // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
1643 // with different color (COL_LIGHTBLUE) ??
1647 // Remove old highlighting, if no new one is set
1648 if ( bParenthesisShown && !bFound && pTableView )
1650 sal_Int32 nCount = pEngine->GetParagraphCount();
1651 for (sal_Int32 i=0; i<nCount; i++)
1652 pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
1655 bParenthesisShown = bFound;
1658 void ScInputHandler::ViewShellGone(ScTabViewShell* pViewSh) // Executed synchronously!
1660 if ( pViewSh == pActiveViewSh )
1662 delete pLastState;
1663 pLastState = NULL;
1664 pLastPattern = NULL;
1667 if ( pViewSh == pRefViewSh )
1669 //! The input from the EnterHandler does not arrive anymore
1670 // We end the EditMode anyways
1671 EnterHandler();
1672 bFormulaMode = false;
1673 pRefViewSh = NULL;
1674 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
1675 SC_MOD()->SetRefInputHdl(NULL);
1676 if (pInputWin)
1677 pInputWin->SetFormulaMode(false);
1678 UpdateAutoCorrFlag();
1681 pActiveViewSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
1683 if ( pActiveViewSh && pActiveViewSh == pViewSh )
1685 OSL_FAIL("pActiveViewSh is gone");
1686 pActiveViewSh = NULL;
1689 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
1690 UpdateRefDevice(); // Don't keep old document's printer as RefDevice
1693 void ScInputHandler::UpdateActiveView()
1695 ImplCreateEditEngine();
1697 // #i20588# Don't rely on focus to find the active edit view. Instead, the
1698 // active pane at the start of editing is now stored (GetEditActivePart).
1699 // GetActiveWin (the currently active pane) fails for ref input across the
1700 // panes of a split view.
1702 vcl::Window* pShellWin = pActiveViewSh ?
1703 pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData().GetEditActivePart() ) :
1704 NULL;
1706 sal_uInt16 nCount = pEngine->GetViewCount();
1707 if (nCount > 0)
1709 pTableView = pEngine->GetView(0);
1710 for (sal_uInt16 i=1; i<nCount; i++)
1712 EditView* pThis = pEngine->GetView(i);
1713 vcl::Window* pWin = pThis->GetWindow();
1714 if ( pWin==pShellWin )
1715 pTableView = pThis;
1718 else
1719 pTableView = NULL;
1721 // setup the pTableView editeng for tiled rendering to get cursor and selections
1722 if (pActiveViewSh && pTableView)
1724 ScDocShell* pDocShell = pActiveViewSh->GetViewData().GetDocShell();
1725 ScDocument& rDoc = pDocShell->GetDocument();
1726 if (rDoc.GetDrawLayer()->isTiledRendering())
1728 ScDrawLayer *pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
1729 pTableView->registerLibreOfficeKitCallback(pDrawLayer->getLibreOfficeKitCallback(), pDrawLayer->getLibreOfficeKitData());
1730 pTableView->setTiledRendering(true);
1734 if (pInputWin && eMode == SC_INPUT_TOP )
1735 pTopView = pInputWin->GetEditView();
1736 else
1737 pTopView = NULL;
1740 void ScInputHandler::SetInputWindow( ScInputWindow* pNew )
1742 pInputWin = pNew;
1745 void ScInputHandler::StopInputWinEngine( bool bAll )
1747 if (pInputWin)
1748 pInputWin->StopEditEngine( bAll );
1750 pTopView = NULL; // invalid now
1753 EditView* ScInputHandler::GetActiveView()
1755 UpdateActiveView();
1756 return pTopView ? pTopView : pTableView;
1759 void ScInputHandler::ForgetLastPattern()
1761 pLastPattern = NULL;
1762 if ( !pLastState && pActiveViewSh )
1763 pActiveViewSh->UpdateInputHandler( true ); // Get status again
1764 else
1765 NotifyChange( pLastState, true );
1768 void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
1770 SvxAdjust eSvxAdjust;
1771 switch (eAttrAdjust)
1773 case SVX_HOR_JUSTIFY_STANDARD:
1775 bool bNumber = false;
1776 if (cTyped) // Restarted
1777 bNumber = (cTyped>='0' && cTyped<='9'); // Ony ciphers are numbers
1778 else if ( pActiveViewSh )
1780 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1781 bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
1783 eSvxAdjust = bNumber ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
1785 break;
1786 case SVX_HOR_JUSTIFY_BLOCK:
1787 eSvxAdjust = SVX_ADJUST_BLOCK;
1788 break;
1789 case SVX_HOR_JUSTIFY_CENTER:
1790 eSvxAdjust = SVX_ADJUST_CENTER;
1791 break;
1792 case SVX_HOR_JUSTIFY_RIGHT:
1793 eSvxAdjust = SVX_ADJUST_RIGHT;
1794 break;
1795 default: // SVX_HOR_JUSTIFY_LEFT
1796 eSvxAdjust = SVX_ADJUST_LEFT;
1797 break;
1800 bool bAsianVertical = pLastPattern &&
1801 static_cast<const SfxBoolItem&>(pLastPattern->GetItem( ATTR_STACKED )).GetValue() &&
1802 static_cast<const SfxBoolItem&>(pLastPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
1803 if ( bAsianVertical )
1805 // Always edit at top of cell -> LEFT when editing vertically
1806 eSvxAdjust = SVX_ADJUST_LEFT;
1809 pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
1810 pEngine->SetDefaults( *pEditDefaults );
1812 nEditAdjust = sal::static_int_cast<sal_uInt16>(eSvxAdjust); //! set at ViewData or with PostEditView
1814 pEngine->SetVertical( bAsianVertical );
1817 void ScInputHandler::RemoveAdjust()
1819 // Delete hard alignement attributes
1820 bool bUndo = pEngine->IsUndoEnabled();
1821 if ( bUndo )
1822 pEngine->EnableUndo( false );
1824 // Non-default paragraph attributes (e.g. from clipboard)
1825 // must be turned into character attributes
1826 pEngine->RemoveParaAttribs();
1828 if ( bUndo )
1829 pEngine->EnableUndo( true );
1833 void ScInputHandler::RemoveRangeFinder()
1835 // Delete pRangeFindList and colors
1836 pEngine->SetUpdateMode(false);
1837 sal_Int32 nCount = pEngine->GetParagraphCount(); // Could just have been inserted
1838 for (sal_Int32 i=0; i<nCount; i++)
1839 pEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
1840 pEngine->SetUpdateMode(true);
1842 EditView* pActiveView = pTopView ? pTopView : pTableView;
1843 pActiveView->ShowCursor( false, true );
1845 DeleteRangeFinder(); // Deletes the list and the labels on the table
1848 bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated )
1850 bool bNewTable = false;
1852 if (bModified || !ValidCol(aCursorPos.Col()))
1853 return false;
1855 if (pActiveViewSh)
1857 ImplCreateEditEngine();
1858 UpdateActiveView();
1859 SyncViews();
1861 ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
1863 const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
1864 ScEditableTester aTester;
1865 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1866 aTester.TestSelection( &rDoc, rMark );
1867 else
1868 aTester.TestSelectedBlock(
1869 &rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
1871 bool bStartInputMode = true;
1873 if (!aTester.IsEditable())
1875 bProtected = true;
1876 // We allow read-only input mode activation regardless
1877 // whether it's part of an array or not or whether explicit cell
1878 // activation is requested (double-click or F2) or a click in input
1879 // line.
1880 bool bShowError = (!bInputActivated || aTester.GetMessageId() != STR_PROTECTIONERR) &&
1881 !pActiveViewSh->GetViewData().GetDocShell()->IsReadOnly();
1882 if (bShowError)
1884 eMode = SC_INPUT_NONE;
1885 StopInputWinEngine( true );
1886 UpdateFormulaMode();
1887 if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
1889 // Prevent repeated error messages for the same cell from command events
1890 // (for keyboard events, multiple messages are wanted).
1891 // Set the flag before showing the error message because the command handler
1892 // for the next IME command may be called when showing the dialog.
1893 if ( bFromCommand )
1894 bCommandErrorShown = true;
1896 pActiveViewSh->GetActiveWin()->GrabFocus();
1897 pActiveViewSh->ErrorMessage(aTester.GetMessageId());
1899 bStartInputMode = false;
1903 if (bStartInputMode)
1905 // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
1906 pEngine->SetUpdateMode( false );
1908 // Take over attributes in EditEngine
1909 const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
1910 aCursorPos.Row(),
1911 aCursorPos.Tab() );
1912 if (pPattern != pLastPattern)
1914 // Percent format?
1915 const SfxItemSet& rAttrSet = pPattern->GetItemSet();
1916 const SfxPoolItem* pItem;
1918 if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, true, &pItem ) )
1920 sal_uLong nFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
1921 bCellHasPercentFormat = ( css::util::NumberFormat::PERCENT ==
1922 rDoc.GetFormatTable()->GetType( nFormat ) );
1924 else
1925 bCellHasPercentFormat = false; // Default: no percent
1927 // Validity specified?
1928 if ( SfxItemState::SET == rAttrSet.GetItemState( ATTR_VALIDDATA, true, &pItem ) )
1929 nValidation = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
1930 else
1931 nValidation = 0;
1933 // EditEngine Defaults
1934 // In no case SetParaAttribs, because the EditEngine might already
1935 // be filled (for Edit cells).
1936 // SetParaAttribs would change the content.
1938 //! The SetDefaults is now (since MUST/src602
1939 //! EditEngine changes) implemented as a SetParaAttribs.
1940 //! Any problems?
1942 pPattern->FillEditItemSet( pEditDefaults );
1943 pEngine->SetDefaults( *pEditDefaults );
1944 pLastPattern = pPattern;
1945 bLastIsSymbol = pPattern->IsSymbolFont();
1947 // Background color must be known for automatic font color.
1948 // For transparent cell background, the document background color must be used.
1950 Color aBackCol = static_cast<const SvxBrushItem&>(
1951 pPattern->GetItem( ATTR_BACKGROUND )).GetColor();
1952 ScModule* pScMod = SC_MOD();
1953 if ( aBackCol.GetTransparency() > 0 ||
1954 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1955 aBackCol.SetColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1956 pEngine->SetBackgroundColor( aBackCol );
1958 // Adjustment
1959 eAttrAdjust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
1960 GetItem(ATTR_HOR_JUSTIFY)).GetValue();
1961 if ( eAttrAdjust == SVX_HOR_JUSTIFY_REPEAT &&
1962 static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() )
1964 // #i31843# "repeat" with "line breaks" is treated as default alignement
1965 eAttrAdjust = SVX_HOR_JUSTIFY_STANDARD;
1969 // UpdateSpellSettings enables online spelling if needed
1970 // -> also call if attributes are unchanged
1971 UpdateSpellSettings( true ); // uses pLastPattern
1973 // Fill EditEngine
1974 OUString aStr;
1975 if (bTextValid)
1977 pEngine->SetText(aCurrentText);
1978 aStr = aCurrentText;
1979 bTextValid = false;
1980 aCurrentText.clear();
1982 else
1983 aStr = GetEditText(pEngine);
1985 if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
1987 aStr = aStr.copy(1, aStr.getLength() -2);
1988 pEngine->SetText(aStr);
1989 if ( pInputWin )
1990 pInputWin->SetTextString(aStr);
1993 UpdateAdjust( cTyped );
1995 if ( bAutoComplete )
1996 GetColData();
1998 if ( !aStr.isEmpty() && ( aStr[0] == '=' || aStr[0] == '+' || aStr[0] == '-' ) &&
1999 !cTyped && !bCreatingFuncView )
2000 InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
2002 bNewTable = true; // -> PostEditView Call
2006 if (!bProtected && pInputWin)
2007 pInputWin->SetOkCancelMode();
2009 return bNewTable;
2012 static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
2014 OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
2016 EditEngine* pEngine = pEditView->GetEditEngine();
2017 sal_Int32 nCount = pEngine->GetParagraphCount();
2018 if (nCount > 1)
2020 sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2021 while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2023 rSel.nStartPos -= nParLen + 1; // Including space from line break
2024 nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2027 nParLen = pEngine->GetTextLen(rSel.nEndPara);
2028 while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2030 rSel.nEndPos -= nParLen + 1; // Including space from line break
2031 nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2035 ESelection aSel = pEditView->GetSelection();
2037 if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2038 || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2039 pEditView->SetSelection( rSel );
2042 void ScInputHandler::SyncViews( EditView* pSourceView )
2044 if (pSourceView)
2046 bool bSelectionForTopView = false;
2047 if (pTopView && pTopView != pSourceView)
2048 bSelectionForTopView = true;
2049 bool bSelectionForTableView = false;
2050 if (pTableView && pTableView != pSourceView)
2051 bSelectionForTableView = true;
2052 if (bSelectionForTopView || bSelectionForTableView)
2054 ESelection aSel(pSourceView->GetSelection());
2055 if (bSelectionForTopView)
2056 pTopView->SetSelection(aSel);
2057 if (bSelectionForTableView)
2058 lcl_SetTopSelection(pTableView, aSel);
2061 // Only sync selection from topView if we are actually editiing there
2062 else if (pTopView && pTableView)
2064 ESelection aSel(pTopView->GetSelection());
2065 lcl_SetTopSelection( pTableView, aSel );
2069 IMPL_LINK_NOARG(ScInputHandler, ModifyHdl)
2071 if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2072 pEngine && pEngine->GetUpdateMode() && pInputWin )
2074 // Update input line from ModifyHdl for changes that are not
2075 // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2076 OUString aText;
2077 if ( pInputWin->IsMultiLineInput() )
2078 aText = ScEditUtil::GetMultilineString(*pEngine);
2079 else
2080 aText = GetEditText(pEngine);
2081 lcl_RemoveTabs(aText);
2082 pInputWin->SetTextString(aText);
2084 return 0;
2088 * @return true means new view created
2090 bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2092 if (pActiveViewSh)
2093 pActiveViewSh->GetViewData().SetPasteMode( SC_PASTE_NONE );
2094 bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2096 if ( eMode == SC_INPUT_NONE )
2097 return StartTable( cTyped, bFromCommand, false );
2098 else
2099 return false;
2102 void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2104 ImplCreateEditEngine();
2106 if (eMode==SC_INPUT_NONE)
2107 eMode = SC_INPUT_TYPE;
2109 if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2111 // table EditEngine is formatted below, input line needs formatting after paste
2112 // #i20282# not when called from the input line's modify handler
2113 pTopView->GetEditEngine()->QuickFormatDoc( true );
2115 // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2116 // can't safely access the EditEngine's current view, so the cursor has to be
2117 // shown again here.
2118 pTopView->ShowCursor();
2121 if (bSetModified)
2122 bModified = true;
2123 bSelIsRef = false;
2125 if ( pRangeFindList && !bInRangeUpdate )
2126 RemoveRangeFinder(); // Delete attributes and labels
2128 UpdateParenthesis(); // Highlight parentheses anew
2130 if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
2132 OUString aText;
2133 if ( pInputWin && pInputWin->IsMultiLineInput() )
2134 aText = ScEditUtil::GetMultilineString(*pEngine);
2135 else
2136 aText = GetEditText(pEngine);
2137 lcl_RemoveTabs(aText);
2139 if ( pInputWin )
2140 pInputWin->SetTextString( aText );
2143 // If the cursor is before the end of a paragraph, parts are being pushed to
2144 // the right (independently from the eMode) -> Adapt View!
2145 // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2147 // First make sure the status handler is called now if the cursor
2148 // is outside the visible area
2149 pEngine->QuickFormatDoc();
2151 EditView* pActiveView = pTopView ? pTopView : pTableView;
2152 if (pActiveView && pActiveViewSh)
2154 ScViewData& rViewData = pActiveViewSh->GetViewData();
2156 bool bNeedGrow = ( nEditAdjust != SVX_ADJUST_LEFT ); // Always right-aligned
2157 if (!bNeedGrow)
2159 // Cursor before the end?
2160 ESelection aSel = pActiveView->GetSelection();
2161 aSel.Adjust();
2162 bNeedGrow = ( aSel.nEndPos != pEngine->GetTextLen(aSel.nEndPara) );
2164 if (!bNeedGrow)
2166 bNeedGrow = rViewData.GetDocument()->IsLayoutRTL( rViewData.GetTabNo() );
2168 if (bNeedGrow)
2170 // Adjust inplace view
2171 rViewData.EditGrowY();
2172 rViewData.EditGrowX();
2176 UpdateFormulaMode();
2177 bTextValid = false; // Changes only in the EditEngine
2178 bInOwnChange = false;
2181 void ScInputHandler::UpdateFormulaMode()
2183 SfxApplication* pSfxApp = SfxGetpApp();
2185 bool bIsFormula = !bProtected && pEngine->GetParagraphCount() == 1;
2186 if (bIsFormula)
2188 const OUString& rText = pEngine->GetText(0);
2189 bIsFormula = !rText.isEmpty() &&
2190 (rText[0] == '=' || rText[0] == '+' || rText[0] == '-');
2193 if ( bIsFormula )
2195 if (!bFormulaMode)
2197 bFormulaMode = true;
2198 pRefViewSh = pActiveViewSh;
2199 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2200 SC_MOD()->SetRefInputHdl(this);
2201 if (pInputWin)
2202 pInputWin->SetFormulaMode(true);
2204 if ( bAutoComplete )
2205 GetFormulaData();
2207 UpdateParenthesis();
2208 UpdateAutoCorrFlag();
2211 else // Deactivate
2213 if (bFormulaMode)
2215 ShowRefFrame();
2216 bFormulaMode = false;
2217 pRefViewSh = NULL;
2218 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2219 SC_MOD()->SetRefInputHdl(NULL);
2220 if (pInputWin)
2221 pInputWin->SetFormulaMode(false);
2222 UpdateAutoCorrFlag();
2227 void ScInputHandler::ShowRefFrame()
2229 // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2230 // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2231 // A local variable is used instead.
2232 ScTabViewShell* pVisibleSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
2233 if ( pRefViewSh && pRefViewSh != pVisibleSh )
2235 bool bFound = false;
2236 SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
2237 SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2238 while ( pOneFrame && !bFound )
2240 if ( pOneFrame == pRefFrame )
2241 bFound = true;
2242 pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2245 if (bFound)
2247 // We count on Activate working synchronously here
2248 // (pActiveViewSh is set while doing so)
2249 pRefViewSh->SetActive(); // Appear and SetViewFrame
2251 // pLastState is set correctly in the NotifyChange from the Activate
2253 else
2255 OSL_FAIL("ViewFrame for reference input is not here anymore");
2260 void ScInputHandler::RemoveSelection()
2262 EditView* pActiveView = pTopView ? pTopView : pTableView;
2263 if (!pActiveView)
2264 return;
2266 ESelection aSel = pActiveView->GetSelection();
2267 aSel.nStartPara = aSel.nEndPara;
2268 aSel.nStartPos = aSel.nEndPos;
2269 if (pTableView)
2270 pTableView->SetSelection( aSel );
2271 if (pTopView)
2272 pTopView->SetSelection( aSel );
2275 void ScInputHandler::InvalidateAttribs()
2277 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2278 if (pViewFrm)
2280 SfxBindings& rBindings = pViewFrm->GetBindings();
2282 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2283 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2284 rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2286 rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2287 rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2288 rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2289 rBindings.Invalidate( SID_ULINE_VAL_NONE );
2290 rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2291 rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2292 rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2294 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2296 rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2297 rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2298 rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2299 rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2300 rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2304 // --------------- public methods --------------------------------------------
2306 void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText )
2308 if ( eMode == eNewMode )
2309 return;
2311 ImplCreateEditEngine();
2313 if (bProtected)
2315 eMode = SC_INPUT_NONE;
2316 StopInputWinEngine( true );
2317 if (pActiveViewSh)
2318 pActiveViewSh->GetActiveWin()->GrabFocus();
2319 return;
2322 if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2323 // Disable paste mode when edit mode starts.
2324 pActiveViewSh->GetViewData().SetPasteMode( SC_PASTE_NONE );
2326 bInOwnChange = true; // disable ModifyHdl (reset below)
2328 ScInputMode eOldMode = eMode;
2329 eMode = eNewMode;
2330 if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2331 StopInputWinEngine( false );
2333 if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
2335 if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2337 if (StartTable(0, false, eMode == SC_INPUT_TABLE))
2339 if (pActiveViewSh)
2340 pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
2344 if (pInitText)
2346 pEngine->SetText(*pInitText);
2347 bModified = true;
2350 sal_Int32 nPara = pEngine->GetParagraphCount()-1;
2351 sal_Int32 nLen = pEngine->GetText(nPara).getLength();
2352 sal_uInt16 nCount = pEngine->GetViewCount();
2354 for (sal_uInt16 i=0; i<nCount; i++)
2356 if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2358 // Keep Selection
2360 else
2362 pEngine->GetView(i)->
2363 SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2365 pEngine->GetView(i)->ShowCursor(false);
2369 UpdateActiveView();
2370 if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
2372 if (pTableView)
2373 pTableView->SetEditEngineUpdateMode(true);
2375 else
2377 if (pTopView)
2378 pTopView->SetEditEngineUpdateMode(true);
2381 if (eNewMode != eOldMode)
2382 UpdateFormulaMode();
2384 bInOwnChange = false;
2388 * @return true if rString only contains digits (no autocorrect then)
2390 static bool lcl_IsNumber(const OUString& rString)
2392 sal_Int32 nLen = rString.getLength();
2393 for (sal_Int32 i=0; i<nLen; i++)
2395 sal_Unicode c = rString[i];
2396 if ( c < '0' || c > '9' )
2397 return false;
2399 return true;
2402 static void lcl_SelectionToEnd( EditView* pView )
2404 if ( pView )
2406 EditEngine* pEngine = pView->GetEditEngine();
2407 sal_Int32 nParCnt = pEngine->GetParagraphCount();
2408 if ( nParCnt == 0 )
2409 nParCnt = 1;
2410 ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
2411 pView->SetSelection( aSel );
2415 void ScInputHandler::EnterHandler( sal_uInt8 nBlockMode )
2417 // Macro calls for validity can cause a lot of problems, so inhibit
2418 // nested calls of EnterHandler().
2419 if (bInEnterHandler) return;
2420 bInEnterHandler = true;
2421 bInOwnChange = true; // disable ModifyHdl (reset below)
2423 ImplCreateEditEngine();
2425 bool bMatrix = ( nBlockMode == SC_ENTER_MATRIX );
2427 SfxApplication* pSfxApp = SfxGetpApp();
2428 EditTextObject* pObject = NULL;
2429 ScPatternAttr* pCellAttrs = NULL;
2430 bool bForget = false; // Remove due to validity?
2432 OUString aString = GetEditText(pEngine);
2433 EditView* pActiveView = pTopView ? pTopView : pTableView;
2434 if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
2436 if (pColumnData && miAutoPosColumn != pColumnData->end())
2438 // #i47125# If AutoInput appended something, do the final AutoCorrect
2439 // with the cursor at the end of the input.
2440 lcl_SelectionToEnd(pTopView);
2441 lcl_SelectionToEnd(pTableView);
2444 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
2446 if (pTopView)
2447 pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
2448 if (pTableView)
2449 pTableView->CompleteAutoCorrect(pFrameWin);
2450 aString = GetEditText(pEngine);
2452 lcl_RemoveTabs(aString);
2454 // Test if valid (always with simple string)
2455 if ( bModified && nValidation && pActiveViewSh )
2457 ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2458 const ScValidationData* pData = pDoc->GetValidationEntry( nValidation );
2459 if (pData && pData->HasErrMsg())
2461 // #i67990# don't use pLastPattern in EnterHandler
2462 const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2463 bool bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
2465 if (!bOk)
2467 if ( pActiveViewSh ) // If it came from MouseButtonDown
2468 pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
2470 //FIXME: We still run into problems if the input is triggered by activating another View
2471 vcl::Window* pParent = Application::GetDefDialogParent();
2472 if ( pData->DoError( pParent, aString, aCursorPos ) )
2473 bForget = true; // Do not take over input
2478 // Check for input into DataPilot table
2479 if ( bModified && pActiveViewSh && !bForget )
2481 ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2482 ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2483 if ( pDPObj )
2485 // Any input within the DataPilot table is either a valid renaming
2486 // or an invalid action - normal cell input is always aborted
2487 pActiveViewSh->DataPilotInput( aCursorPos, aString );
2488 bForget = true;
2492 std::vector<editeng::MisspellRanges> aMisspellRanges;
2493 pEngine->CompleteOnlineSpelling();
2494 bool bSpellErrors = !bFormulaMode && pEngine->HasOnlineSpellErrors();
2495 if ( bSpellErrors )
2497 // #i3820# If the spell checker flags numerical input as error,
2498 // it still has to be treated as number, not EditEngine object.
2499 if ( pActiveViewSh )
2501 ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2502 // #i67990# don't use pLastPattern in EnterHandler
2503 const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2504 if (pPattern)
2506 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2507 // without conditional format, as in ScColumn::SetString
2508 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
2509 double nVal;
2510 if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
2512 bSpellErrors = false; // ignore the spelling errors
2518 // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
2519 // SetUpdateMode must come after CompleteOnlineSpelling.
2520 // The view is hidden in any case below (Broadcast).
2521 pEngine->SetUpdateMode( false );
2523 if ( bModified && !bForget ) // What is being entered (text/object)?
2525 sal_Int32 nParCnt = pEngine->GetParagraphCount();
2526 if ( nParCnt == 0 )
2527 nParCnt = 1;
2529 bool bUniformAttribs = true;
2530 SfxItemSet aPara1Attribs = pEngine->GetAttribs(0, 0, pEngine->GetTextLen(0));
2531 for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
2533 SfxItemSet aPara2Attribs = pEngine->GetAttribs(nPara, 0, pEngine->GetTextLen(nPara));
2534 if (!(aPara1Attribs == aPara2Attribs))
2536 // Paragraph format different from that of the 1st paragraph.
2537 bUniformAttribs = false;
2538 break;
2542 ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
2543 SfxItemSet aOldAttribs = pEngine->GetAttribs( aSel );
2544 const SfxPoolItem* pItem = NULL;
2546 // Find common (cell) attributes before RemoveAdjust
2547 if ( pActiveViewSh && bUniformAttribs )
2549 SfxItemSet* pCommonAttrs = NULL;
2550 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
2552 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2553 if ( eState == SfxItemState::SET &&
2554 nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
2555 nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
2556 *pItem != pEditDefaults->Get(nId) )
2558 if ( !pCommonAttrs )
2559 pCommonAttrs = new SfxItemSet( pEngine->GetEmptyItemSet() );
2560 pCommonAttrs->Put( *pItem );
2564 if ( pCommonAttrs )
2566 ScDocument* pDoc = pActiveViewSh->GetViewData().GetDocument();
2567 pCellAttrs = new ScPatternAttr( pDoc->GetPool() );
2568 pCellAttrs->GetFromEditItemSet( pCommonAttrs );
2569 delete pCommonAttrs;
2573 // Clear ParaAttribs (including adjustment)
2574 RemoveAdjust();
2576 bool bAttrib = false; // Formatting present?
2578 // check if EditObject is needed
2579 if (nParCnt > 1)
2580 bAttrib = true;
2581 else
2583 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
2585 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2586 if (eState == SfxItemState::DONTCARE)
2587 bAttrib = true;
2588 else if (eState == SfxItemState::SET)
2590 // Keep same items in EditEngine as in ScEditAttrTester
2591 if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
2592 nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
2594 if ( *pItem != pEditDefaults->Get(nId) )
2595 bAttrib = true;
2600 // Contains fields?
2601 SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
2602 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
2603 bAttrib = true;
2605 // Not converted characters?
2606 SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
2607 if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
2608 bAttrib = true;
2610 // Always recognize formulas as formulas
2611 // We still need the preceding test due to cell attributes
2614 if (bSpellErrors)
2615 pEngine->GetAllMisspellRanges(aMisspellRanges);
2617 if (bMatrix)
2618 bAttrib = false;
2620 if (bAttrib)
2622 pEngine->ClearSpellErrors();
2623 pObject = pEngine->CreateTextObject();
2625 else if (bAutoComplete) // Adjust Upper/Lower case
2627 // Perform case-matching only when the typed text is partial.
2628 if (pColumnData && aAutoSearch.getLength() < aString.getLength())
2629 aString = getExactMatch(*pColumnData, aString);
2633 // Don't rely on ShowRefFrame switching the active view synchronously
2634 // execute the function directly on the correct view's bindings instead
2635 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2636 ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2638 if (bFormulaMode)
2640 ShowRefFrame();
2642 if (pExecuteSh)
2644 pExecuteSh->SetTabNo(aCursorPos.Tab());
2645 pExecuteSh->ActiveGrabFocus();
2648 bFormulaMode = false;
2649 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2650 SC_MOD()->SetRefInputHdl(NULL);
2651 if (pInputWin)
2652 pInputWin->SetFormulaMode(false);
2653 UpdateAutoCorrFlag();
2655 pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2656 DeleteRangeFinder();
2657 ResetAutoPar();
2659 bool bOldMod = bModified;
2661 bModified = false;
2662 bSelIsRef = false;
2663 eMode = SC_INPUT_NONE;
2664 StopInputWinEngine(true);
2666 // Text input (through number formats) or ApplySelectionPattern modify
2667 // the cell's attributes, so pLastPattern is no longer valid
2668 pLastPattern = NULL;
2670 if (bOldMod && !bProtected && !bForget)
2672 // No typographic quotes in formulas
2673 if (aString.startsWith("="))
2675 SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get().GetAutoCorrect();
2676 if ( pAuto )
2678 OUString aReplace(pAuto->GetStartDoubleQuote());
2679 if( aReplace.isEmpty() )
2680 aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkStart();
2681 if( aReplace != "\"" )
2682 aString = aString.replaceAll( aReplace, "\"" );
2684 aReplace = OUString(pAuto->GetEndDoubleQuote());
2685 if( aReplace.isEmpty() )
2686 aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkEnd();
2687 if( aReplace != "\"" )
2688 aString = aString.replaceAll( aReplace, "\"" );
2690 aReplace = OUString(pAuto->GetStartSingleQuote());
2691 if( aReplace.isEmpty() )
2692 aReplace = ScGlobal::pLocaleData->getQuotationMarkStart();
2693 if( aReplace != "'" )
2694 aString = aString.replaceAll( aReplace, "'" );
2696 aReplace = OUString(pAuto->GetEndSingleQuote());
2697 if( aReplace.isEmpty() )
2698 aReplace = ScGlobal::pLocaleData->getQuotationMarkEnd();
2699 if( aReplace != "'" )
2700 aString = aString.replaceAll( aReplace, "'");
2704 pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT ) );
2706 if ( pExecuteSh )
2708 SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
2710 sal_uInt16 nId = FID_INPUTLINE_ENTER;
2711 if ( nBlockMode == SC_ENTER_BLOCK )
2712 nId = FID_INPUTLINE_BLOCK;
2713 else if ( nBlockMode == SC_ENTER_MATRIX )
2714 nId = FID_INPUTLINE_MATRIX;
2716 ScInputStatusItem aItem( FID_INPUTLINE_STATUS,
2717 aCursorPos, aCursorPos, aCursorPos,
2718 aString, pObject );
2720 if (!aMisspellRanges.empty())
2721 aItem.SetMisspellRanges(&aMisspellRanges);
2723 const SfxPoolItem* aArgs[2];
2724 aArgs[0] = &aItem;
2725 aArgs[1] = NULL;
2726 rBindings.Execute( nId, aArgs );
2729 delete pLastState; // pLastState still contains the old text
2730 pLastState = NULL;
2732 else
2733 pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
2735 if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
2737 // Combine with input?
2738 pExecuteSh->ApplySelectionPattern( *pCellAttrs, true, true );
2739 pExecuteSh->AdjustBlockHeight();
2742 delete pCellAttrs;
2743 delete pObject;
2745 HideTip();
2746 HideTipBelow();
2748 nFormSelStart = nFormSelEnd = 0;
2749 aFormText.clear();
2751 bInOwnChange = false;
2752 bInEnterHandler = false;
2755 void ScInputHandler::CancelHandler()
2757 bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
2759 ImplCreateEditEngine();
2761 bModified = false;
2763 // Don't rely on ShowRefFrame switching the active view synchronously
2764 // execute the function directly on the correct view's bindings instead
2765 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2766 ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2768 if (bFormulaMode)
2770 ShowRefFrame();
2771 if (pExecuteSh)
2773 pExecuteSh->SetTabNo(aCursorPos.Tab());
2774 pExecuteSh->ActiveGrabFocus();
2776 bFormulaMode = false;
2777 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2778 SC_MOD()->SetRefInputHdl(NULL);
2779 if (pInputWin)
2780 pInputWin->SetFormulaMode(false);
2781 UpdateAutoCorrFlag();
2783 pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2784 DeleteRangeFinder();
2785 ResetAutoPar();
2787 eMode = SC_INPUT_NONE;
2788 StopInputWinEngine( true );
2789 if (pExecuteSh)
2790 pExecuteSh->StopEditShell();
2792 aCursorPos.Set(MAXCOL+1,0,0); // Invalid flag
2793 pEngine->SetText(OUString());
2795 if ( !pLastState && pExecuteSh )
2796 pExecuteSh->UpdateInputHandler( true ); // Update status again
2797 else
2798 NotifyChange( pLastState, true );
2800 nFormSelStart = nFormSelEnd = 0;
2801 aFormText.clear();
2803 bInOwnChange = false;
2806 bool ScInputHandler::IsModalMode( SfxObjectShell* pDocSh )
2808 // References to unnamed document; that doesn't work
2809 return bFormulaMode && pRefViewSh
2810 && pRefViewSh->GetViewData().GetDocument()->GetDocumentShell() != pDocSh
2811 && !pDocSh->HasName();
2814 void ScInputHandler::AddRefEntry()
2816 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2817 UpdateActiveView();
2818 if (!pTableView && !pTopView)
2819 return; // E.g. FillMode
2821 DataChanging(); // Cannot be new
2823 RemoveSelection();
2824 if (pTableView)
2825 pTableView->InsertText( OUString(cSep), false );
2826 if (pTopView)
2827 pTopView->InsertText( OUString(cSep), false );
2829 DataChanged();
2832 void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc )
2834 HideTip();
2836 bool bOtherDoc = ( pRefViewSh &&
2837 pRefViewSh->GetViewData().GetDocument() != pDoc );
2838 if (bOtherDoc)
2839 if (!pDoc->GetDocumentShell()->HasName())
2841 // References to unnamed document; that doesn't work
2842 // SetReference should not be called, then
2843 return;
2846 UpdateActiveView();
2847 if (!pTableView && !pTopView)
2848 return; // E.g. FillMode
2850 // Never overwrite the "="!
2851 EditView* pActiveView = pTopView ? pTopView : pTableView;
2852 ESelection aSel = pActiveView->GetSelection();
2853 aSel.Adjust();
2854 if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
2855 return;
2857 DataChanging(); // Cannot be new
2859 // Turn around selection if backwards (TODO: Do we really need to do that?)
2860 if (pTableView)
2862 ESelection aTabSel = pTableView->GetSelection();
2863 if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
2865 aTabSel.Adjust();
2866 pTableView->SetSelection(aTabSel);
2869 if (pTopView)
2871 ESelection aTopSel = pTopView->GetSelection();
2872 if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
2874 aTopSel.Adjust();
2875 pTopView->SetSelection(aTopSel);
2879 // Create string from reference
2880 OUString aRefStr;
2881 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
2882 if (bOtherDoc)
2884 // Reference to other document
2885 OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
2887 OUString aTmp(rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails)); // Always 3D
2889 SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
2890 // #i75893# convert escaped URL of the document to something user friendly
2891 OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );
2893 switch(aAddrDetails.eConv)
2895 case formula::FormulaGrammar::CONV_XL_A1 :
2896 case formula::FormulaGrammar::CONV_XL_OOX :
2897 case formula::FormulaGrammar::CONV_XL_R1C1 :
2898 aRefStr = "[\'";
2899 aRefStr += aFileName;
2900 aRefStr += "']";
2901 break;
2902 case formula::FormulaGrammar::CONV_OOO :
2903 default:
2904 aRefStr = "\'";
2905 aRefStr += aFileName;
2906 aRefStr += "'#";
2907 break;
2909 aRefStr += aTmp;
2911 else
2913 if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
2914 rRef.aStart.Tab() != rRef.aEnd.Tab() )
2915 aRefStr = rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails);
2916 else
2917 aRefStr = rRef.Format(SCA_VALID, pDoc, aAddrDetails);
2920 if (pTableView || pTopView)
2922 if (pTableView)
2923 pTableView->InsertText( aRefStr, true );
2924 if (pTopView)
2925 pTopView->InsertText( aRefStr, true );
2927 DataChanged();
2930 bSelIsRef = true;
2933 void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
2935 if ( eMode == SC_INPUT_NONE )
2937 OSL_FAIL("InsertFunction, nicht im Eingabemodus");
2938 return;
2941 UpdateActiveView();
2942 if (!pTableView && !pTopView)
2943 return; // E.g. FillMode
2945 DataChanging(); // Cannot be new
2947 OUString aText = rFuncName;
2948 if (bAddPar)
2949 aText += "()";
2951 if (pTableView)
2953 pTableView->InsertText( aText, false );
2954 if (bAddPar)
2956 ESelection aSel = pTableView->GetSelection();
2957 --aSel.nStartPos;
2958 --aSel.nEndPos;
2959 pTableView->SetSelection(aSel);
2962 if (pTopView)
2964 pTopView->InsertText( aText, false );
2965 if (bAddPar)
2967 ESelection aSel = pTopView->GetSelection();
2968 --aSel.nStartPos;
2969 --aSel.nEndPos;
2970 pTopView->SetSelection(aSel);
2974 DataChanged();
2976 if (bAddPar)
2977 AutoParAdded();
2980 void ScInputHandler::ClearText()
2982 if ( eMode == SC_INPUT_NONE )
2984 OSL_FAIL("ClearText, nicht im Eingabemodus");
2985 return;
2988 UpdateActiveView();
2989 if (!pTableView && !pTopView)
2990 return; // E.g. FillMode
2992 DataChanging(); // Cannot be new
2994 OUString aEmpty;
2995 if (pTableView)
2997 pTableView->GetEditEngine()->SetText( aEmpty );
2998 pTableView->SetSelection( ESelection(0,0, 0,0) );
3000 if (pTopView)
3002 pTopView->GetEditEngine()->SetText( aEmpty );
3003 pTopView->SetSelection( ESelection(0,0, 0,0) );
3006 DataChanged();
3009 bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
3011 if (!bOptLoaded)
3013 bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3014 bOptLoaded = true;
3017 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3018 sal_uInt16 nModi = aCode.GetModifier();
3019 bool bShift = aCode.IsShift();
3020 bool bControl = aCode.IsMod1();
3021 bool bAlt = aCode.IsMod2();
3022 sal_uInt16 nCode = aCode.GetCode();
3023 sal_Unicode nChar = rKEvt.GetCharCode();
3025 if (bAlt && !bControl && nCode != KEY_RETURN)
3026 // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3027 return false;
3029 if (!bControl && nCode == KEY_TAB)
3031 // Normal TAB moves the cursor right.
3032 EnterHandler();
3034 if (pActiveViewSh)
3035 pActiveViewSh->FindNextUnprot( bShift );
3036 return true;
3039 bool bInputLine = ( eMode==SC_INPUT_TOP );
3041 bool bUsed = false;
3042 bool bSkip = false;
3043 bool bDoEnter = false;
3045 switch ( nCode )
3047 case KEY_RETURN:
3048 if (bControl && !bShift && ( !bInputLine || ( pInputWin && pInputWin->IsMultiLineInput() ) ) )
3049 bDoEnter = true;
3050 else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3052 PasteFunctionData();
3053 bUsed = true;
3055 else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3057 PasteManualTip();
3058 bUsed = true;
3060 else
3062 sal_uInt8 nMode = SC_ENTER_NORMAL;
3063 if ( bShift && bControl )
3064 nMode = SC_ENTER_MATRIX;
3065 else if ( bAlt )
3066 nMode = SC_ENTER_BLOCK;
3067 EnterHandler( nMode );
3069 if (pActiveViewSh)
3070 pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3072 bUsed = true;
3074 break;
3075 case KEY_TAB:
3076 if (bControl && !bAlt)
3078 if (pFormulaData && nTipVisible && miAutoPosFormula != pFormulaData->end())
3080 // Iterate
3081 NextFormulaEntry( bShift );
3082 bUsed = true;
3084 else if (pColumnData && bUseTab && miAutoPosColumn != pColumnData->end())
3086 // Iterate through AutoInput entries
3087 NextAutoEntry( bShift );
3088 bUsed = true;
3091 break;
3092 case KEY_ESCAPE:
3093 if ( nTipVisible )
3095 HideTip();
3096 bUsed = true;
3098 else if( nTipVisibleSec )
3100 HideTipBelow();
3101 bUsed = true;
3103 else if (eMode != SC_INPUT_NONE)
3105 CancelHandler();
3106 bUsed = true;
3108 else
3109 bSkip = true;
3110 break;
3111 case KEY_F2:
3112 if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3114 eMode = SC_INPUT_TYPE;
3115 bUsed = true;
3117 break;
3120 // Only execute cursor keys if already in EditMode
3121 // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3122 bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3123 bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3124 if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3125 ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3127 HideTip();
3128 HideTipBelow();
3130 if (bSelIsRef)
3132 RemoveSelection();
3133 bSelIsRef = false;
3136 UpdateActiveView();
3137 bool bNewView = DataChanging( nChar );
3139 if (bProtected) // Protected cell?
3140 bUsed = true; // Don't forward KeyEvent
3141 else // Changes allowed
3143 if (bNewView ) // Create anew
3145 if (pActiveViewSh)
3146 pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
3147 UpdateActiveView();
3148 if (eMode==SC_INPUT_NONE)
3149 if (pTableView || pTopView)
3151 OUString aStrLoP;
3153 if ( bStartEdit && bCellHasPercentFormat && ((nChar >= '0' && nChar <= '9') || nChar == '-') )
3154 aStrLoP = "%";
3156 if (pTableView)
3158 pTableView->GetEditEngine()->SetText( aStrLoP );
3159 if ( !aStrLoP.isEmpty() )
3160 pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3162 // Don't call SetSelection if the string is empty anyway,
3163 // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3165 if (pTopView)
3167 pTopView->GetEditEngine()->SetText( aStrLoP );
3168 if ( !aStrLoP.isEmpty() )
3169 pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3172 SyncViews();
3175 if (pTableView || pTopView)
3177 if (bDoEnter)
3179 if (pTableView)
3180 if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, vcl::KeyCode(KEY_RETURN) ) ) )
3181 bUsed = true;
3182 if (pTopView)
3183 if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, vcl::KeyCode(KEY_RETURN) ) ) )
3184 bUsed = true;
3186 else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3188 SkipClosingPar();
3189 bUsed = true;
3191 else
3193 if (pTableView)
3195 vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
3196 if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3197 bUsed = true;
3199 if (pTopView)
3200 if ( pTopView->PostKeyEvent( rKEvt ) )
3201 bUsed = true;
3204 // AutoInput:
3205 if ( bUsed && bAutoComplete )
3207 bUseTab = false;
3208 if (pFormulaData)
3209 miAutoPosFormula = pFormulaData->end(); // do not search further
3210 if (pColumnData)
3211 miAutoPosColumn = pColumnData->end();
3213 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3214 if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3215 KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
3217 if (bFormulaMode)
3218 UseFormulaData();
3219 else
3220 UseColData();
3224 // When the selection is changed manually or an opening parenthesis
3225 // is typed, stop overwriting parentheses
3226 if ( bUsed && nChar == '(' )
3227 ResetAutoPar();
3229 if ( KEY_INSERT == nCode )
3231 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3232 if (pViewFrm)
3233 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3235 if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3237 ShowTipCursor();
3241 // #i114511# don't count cursor keys as modification
3242 bool bSetModified = !bCursorKey;
3243 DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3244 InvalidateAttribs(); //! in DataChanged?
3248 if (pTopView && eMode != SC_INPUT_NONE)
3249 SyncViews();
3251 return bUsed;
3254 bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, bool bForce )
3256 bool bUsed = false;
3258 if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
3260 // For CommandEventId::CursorPos, do as little as possible, because
3261 // with remote VCL, even a ShowCursor will generate another event.
3262 if ( eMode != SC_INPUT_NONE )
3264 UpdateActiveView();
3265 if (pTableView || pTopView)
3267 if (pTableView)
3268 pTableView->Command( rCEvt );
3269 else if (pTopView) // call only once
3270 pTopView->Command( rCEvt );
3271 bUsed = true;
3275 else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
3277 if ( eMode != SC_INPUT_NONE )
3279 UpdateActiveView();
3280 if (pTableView || pTopView)
3282 if (pTableView)
3283 pTableView->Command( rCEvt );
3284 else if (pTopView) // call only once
3285 pTopView->Command( rCEvt );
3286 bUsed = true;
3290 else
3292 if ( bForce || eMode != SC_INPUT_NONE )
3294 if (!bOptLoaded)
3296 bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3297 bOptLoaded = true;
3300 HideTip();
3301 HideTipBelow();
3303 if ( bSelIsRef )
3305 RemoveSelection();
3306 bSelIsRef = false;
3309 UpdateActiveView();
3310 bool bNewView = DataChanging( 0, true );
3312 if (bProtected) // cell protected
3313 bUsed = true; // event is used
3314 else // changes allowed
3316 if (bNewView) // create new edit view
3318 if (pActiveViewSh)
3319 pActiveViewSh->GetViewData().GetDocShell()->PostEditView( pEngine, aCursorPos );
3320 UpdateActiveView();
3321 if (eMode==SC_INPUT_NONE)
3322 if (pTableView || pTopView)
3324 OUString aStrLoP;
3325 if (pTableView)
3327 pTableView->GetEditEngine()->SetText( aStrLoP );
3328 pTableView->SetSelection( ESelection(0,0, 0,0) );
3330 if (pTopView)
3332 pTopView->GetEditEngine()->SetText( aStrLoP );
3333 pTopView->SetSelection( ESelection(0,0, 0,0) );
3336 SyncViews();
3339 if (pTableView || pTopView)
3341 if (pTableView)
3342 pTableView->Command( rCEvt );
3343 if (pTopView)
3344 pTopView->Command( rCEvt );
3346 bUsed = true;
3348 if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
3350 // AutoInput after ext text input
3352 if (pFormulaData)
3353 miAutoPosFormula = pFormulaData->end();
3354 if (pColumnData)
3355 miAutoPosColumn = pColumnData->end();
3357 if (bFormulaMode)
3358 UseFormulaData();
3359 else
3360 UseColData();
3364 DataChanged(); // calls UpdateParenthesis()
3365 InvalidateAttribs(); //! in DataChanged ?
3369 if (pTopView && eMode != SC_INPUT_NONE)
3370 SyncViews();
3373 return bUsed;
3376 void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
3377 bool bForce, ScTabViewShell* pSourceSh,
3378 bool bStopEditing)
3380 // If the call originates from a macro call in the EnterHandler,
3381 // return immediately and don't mess up the status
3382 if (bInEnterHandler)
3383 return;
3385 bool bRepeat = (pState == pLastState);
3386 if (!bRepeat && pState && pLastState)
3387 bRepeat = (*pState == *pLastState);
3388 if (bRepeat && !bForce)
3389 return;
3391 bInOwnChange = true; // disable ModifyHdl (reset below)
3393 if ( pState && !pLastState ) // Enable again
3394 bForce = true;
3396 bool bHadObject = pLastState && pLastState->GetEditData();
3398 //! Before EditEngine gets eventually created (so it gets the right pools)
3399 if ( pSourceSh )
3400 pActiveViewSh = pSourceSh;
3401 else
3402 pActiveViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current());
3404 ImplCreateEditEngine();
3406 if ( pState != pLastState )
3408 delete pLastState;
3409 pLastState = pState ? new ScInputHdlState( *pState ) : NULL;
3412 if ( pState && pActiveViewSh )
3414 ScModule* pScMod = SC_MOD();
3416 if ( pState )
3419 // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
3420 // FormEditData, if we're switching from Help to Calc:
3421 if ( !bFormulaMode && !pScMod->IsFormulaMode() && !pScMod->GetFormEditData() )
3423 bool bIgnore = false;
3424 if ( bModified )
3426 if (pState->GetPos() != aCursorPos)
3428 if (!bProtected)
3429 EnterHandler();
3431 else
3432 bIgnore = true;
3435 if ( !bIgnore )
3437 const ScAddress& rSPos = pState->GetStartPos();
3438 const ScAddress& rEPos = pState->GetEndPos();
3439 const EditTextObject* pData = pState->GetEditData();
3440 OUString aString = pState->GetString();
3441 bool bTxtMod = false;
3442 ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
3443 ScDocument& rDoc = pDocSh->GetDocument();
3445 aCursorPos = pState->GetPos();
3447 if ( pData )
3448 bTxtMod = true;
3449 else if ( bHadObject )
3450 bTxtMod = true;
3451 else if ( bTextValid )
3452 bTxtMod = ( !aString.equals(aCurrentText) );
3453 else
3454 bTxtMod = ( !aString.equals(GetEditText(pEngine)) );
3456 if ( bTxtMod || bForce )
3458 if (pData)
3460 pEngine->SetText( *pData );
3461 if ( pInputWin && pInputWin->IsMultiLineInput() )
3462 aString = ScEditUtil::GetMultilineString(*pEngine);
3463 else
3464 aString = GetEditText(pEngine);
3465 lcl_RemoveTabs(aString);
3466 bTextValid = false;
3467 aCurrentText.clear();
3469 else
3471 aCurrentText = aString;
3472 bTextValid = true; //! To begin with remember as a string
3475 if ( pInputWin )
3476 pInputWin->SetTextString(aString);
3479 if ( pInputWin ) // Named range input
3481 OUString aPosStr;
3482 const ScAddress::Details aAddrDetails( &rDoc, aCursorPos );
3484 // Is the range a name?
3485 //! Find by Timer?
3486 if ( pActiveViewSh )
3487 pActiveViewSh->GetViewData().GetDocument()->
3488 GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );
3490 if ( aPosStr.isEmpty() ) // Not a name -> format
3492 sal_uInt16 nFlags = 0;
3493 if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
3494 nFlags |= SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;
3495 if ( rSPos != rEPos )
3497 ScRange r(rSPos, rEPos);
3498 nFlags |= (nFlags << 4);
3499 aPosStr = r.Format(SCA_VALID | nFlags, &rDoc, aAddrDetails);
3501 else
3502 aPosStr = aCursorPos.Format(SCA_VALID | nFlags, &rDoc, aAddrDetails);
3505 // Disable the accessible VALUE_CHANGE event
3506 bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
3507 pInputWin->SetAccessibilityEventsSuppressed(true);
3508 pInputWin->SetPosString(aPosStr);
3509 pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
3510 pInputWin->SetSumAssignMode();
3513 if (bStopEditing)
3514 SfxGetpApp()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
3516 // As long as the content is not edited, turn off online spelling.
3517 // Online spelling is turned back on in StartTable, after setting
3518 // the right language from cell attributes.
3520 EEControlBits nCntrl = pEngine->GetControlWord();
3521 if ( nCntrl & EEControlBits::ONLINESPELLING )
3522 pEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
3524 bModified = false;
3525 bSelIsRef = false;
3526 bProtected = false;
3527 bCommandErrorShown = false;
3532 if ( pInputWin)
3534 // Do not enable if RefDialog is open
3535 if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
3537 if ( !pInputWin->IsEnabled())
3539 pInputWin->Enable();
3540 if(pDelayTimer )
3542 DELETEZ( pDelayTimer );
3546 else if(pScMod->IsRefDialogOpen())
3547 { // Because every document has its own InputWin,
3548 // we should start Timer again, because the input line may
3549 // still be active
3550 if ( !pDelayTimer )
3552 pDelayTimer = new Timer;
3553 pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3554 pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3555 pDelayTimer->Start();
3560 else // !pState || !pActiveViewSh
3562 if ( !pDelayTimer )
3564 pDelayTimer = new Timer;
3565 pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3566 pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3567 pDelayTimer->Start();
3571 HideTip();
3572 HideTipBelow();
3573 bInOwnChange = false;
3576 void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
3578 eAttrAdjust = eJust;
3579 UpdateAdjust( 0 );
3582 void ScInputHandler::ResetDelayTimer()
3584 if(pDelayTimer!=NULL)
3586 DELETEZ( pDelayTimer );
3588 if ( pInputWin)
3590 pInputWin->Enable();
3595 IMPL_LINK_TYPED( ScInputHandler, DelayTimer, Timer*, pTimer, void )
3597 if ( pTimer == pDelayTimer )
3599 DELETEZ( pDelayTimer );
3601 if ( NULL == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
3603 //! New method at ScModule to query if function autopilot is open
3604 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3605 if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
3607 if ( pInputWin)
3609 pInputWin->EnableButtons( false );
3610 pInputWin->Disable();
3613 else if ( !bFormulaMode ) // Keep formula e.g. for help
3615 bInOwnChange = true; // disable ModifyHdl (reset below)
3617 pActiveViewSh = NULL;
3618 pEngine->SetText( EMPTY_OUSTRING );
3619 if ( pInputWin )
3621 pInputWin->SetPosString( EMPTY_OUSTRING );
3622 pInputWin->SetTextString( EMPTY_OUSTRING );
3623 pInputWin->Disable();
3626 bInOwnChange = false;
3632 void ScInputHandler::InputSelection( EditView* pView )
3634 SyncViews( pView );
3635 ShowTipCursor();
3636 UpdateParenthesis(); // Selection changed -> update parentheses highlighting
3638 // When the selection is changed manually, stop overwriting parentheses
3639 ResetAutoPar();
3642 void ScInputHandler::InputChanged( EditView* pView, bool bFromNotify )
3644 UpdateActiveView();
3646 // #i20282# DataChanged needs to know if this is from the input line's modify handler
3647 bool bFromTopNotify = ( bFromNotify && pView == pTopView );
3649 bool bNewView = DataChanging(); //FIXME: Is this at all possible?
3650 aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
3651 pEngine->SetText( aCurrentText );
3652 DataChanged( bFromTopNotify );
3653 bTextValid = true; // Is set to false in DataChanged
3655 if ( pActiveViewSh )
3657 ScViewData& rViewData = pActiveViewSh->GetViewData();
3658 if ( bNewView )
3659 rViewData.GetDocShell()->PostEditView( pEngine, aCursorPos );
3661 rViewData.EditGrowY();
3662 rViewData.EditGrowX();
3665 SyncViews( pView );
3668 const OUString& ScInputHandler::GetEditString()
3670 if (pEngine)
3672 aCurrentText = pEngine->GetText(); // Always new from Engine
3673 bTextValid = true;
3676 return aCurrentText;
3679 Size ScInputHandler::GetTextSize()
3681 Size aSize;
3682 if ( pEngine )
3683 aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
3685 return aSize;
3688 bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
3690 bool bRet = false;
3691 if (pEngine)
3693 // Contains field?
3694 sal_Int32 nParCnt = pEngine->GetParagraphCount();
3695 SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
3696 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
3697 if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
3699 // Copy content
3700 EditTextObject* pObj = pEngine->CreateTextObject();
3701 rDestEngine.SetText(*pObj);
3702 delete pObj;
3704 // Delete attributes
3705 for (sal_Int32 i=0; i<nParCnt; i++)
3706 rDestEngine.RemoveCharAttribs( i );
3708 // Combine paragraphs
3709 while ( nParCnt > 1 )
3711 sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
3712 ESelection aSel( 0,nLen, 1,0 );
3713 rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
3714 --nParCnt;
3717 bRet = true;
3720 return bRet;
3724 * Methods for FunctionAutoPilot:
3725 * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
3727 void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
3729 rStart = nFormSelStart;
3730 rEnd = nFormSelEnd;
3733 EditView* ScInputHandler::GetFuncEditView()
3735 UpdateActiveView(); // Due to pTableView
3737 EditView* pView = NULL;
3738 if ( pInputWin )
3740 pInputWin->MakeDialogEditView();
3741 pView = pInputWin->GetEditView();
3743 else
3745 if ( eMode != SC_INPUT_TABLE )
3747 bCreatingFuncView = true; // Don't display RangeFinder
3748 SetMode( SC_INPUT_TABLE );
3749 bCreatingFuncView = false;
3750 if ( pTableView )
3751 pTableView->GetEditEngine()->SetText( EMPTY_OUSTRING );
3753 pView = pTableView;
3756 return pView;
3759 void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
3761 if ( nStart <= nEnd )
3763 nFormSelStart = nStart;
3764 nFormSelEnd = nEnd;
3766 else
3768 nFormSelEnd = nStart;
3769 nFormSelStart = nEnd;
3772 EditView* pView = GetFuncEditView();
3773 if (pView)
3774 pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
3776 bModified = true;
3779 void ScInputHandler::InputReplaceSelection( const OUString& rStr )
3781 if (!pRefViewSh)
3782 pRefViewSh = pActiveViewSh;
3784 OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
3786 sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
3787 sal_Int32 nNewLen = rStr.getLength();
3789 OUStringBuffer aBuf(aFormText);
3790 if (nOldLen)
3791 aBuf.remove(nFormSelStart, nOldLen);
3792 if (nNewLen)
3793 aBuf.insert(nFormSelStart, rStr);
3795 aFormText = aBuf.makeStringAndClear();
3797 nFormSelEnd = nFormSelStart + nNewLen;
3799 EditView* pView = GetFuncEditView();
3800 if (pView)
3802 pView->SetEditEngineUpdateMode( false );
3803 pView->GetEditEngine()->SetText( aFormText );
3804 pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
3805 pView->SetEditEngineUpdateMode( true );
3807 bModified = true;
3810 void ScInputHandler::InputTurnOffWinEngine()
3812 bInOwnChange = true; // disable ModifyHdl (reset below)
3814 eMode = SC_INPUT_NONE;
3815 /* TODO: it would be better if there was some way to reset the input bar
3816 * engine instead of deleting and having it recreate through
3817 * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
3818 * fdo#72278 without reintroducing fdo#69971. */
3819 StopInputWinEngine(true);
3821 bInOwnChange = false;
3825 * ScInputHdlState
3827 ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
3828 const ScAddress& rStartPos,
3829 const ScAddress& rEndPos,
3830 const OUString& rString,
3831 const EditTextObject* pData )
3832 : aCursorPos ( rCurPos ),
3833 aStartPos ( rStartPos ),
3834 aEndPos ( rEndPos ),
3835 aString ( rString ),
3836 pEditData ( pData ? pData->Clone() : NULL )
3840 ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
3841 : pEditData ( NULL )
3843 *this = rCpy;
3846 ScInputHdlState::~ScInputHdlState()
3848 delete pEditData;
3851 bool ScInputHdlState::operator==( const ScInputHdlState& r ) const
3853 return ( (aStartPos == r.aStartPos)
3854 && (aEndPos == r.aEndPos)
3855 && (aCursorPos == r.aCursorPos)
3856 && (aString == r.aString)
3857 && ScGlobal::EETextObjEqual( pEditData, r.pEditData ) );
3860 ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
3862 delete pEditData;
3864 aCursorPos = r.aCursorPos;
3865 aStartPos = r.aStartPos;
3866 aEndPos = r.aEndPos;
3867 aString = r.aString;
3868 pEditData = r.pEditData ? r.pEditData->Clone() : NULL;
3870 return *this;
3873 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */