Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / app / inputhdl.cxx
blob961cbcdf4d61e67588043a845e191a221f64917a
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 // Delimiters (in addition to ScEditUtil) needed for range finder:
98 // only characters that are allowed in formulas next to references
99 // and the quotation mark (so string constants can be skipped)
100 const sal_Char pMinDelimiters[] = " !\"";
102 // Formula data replacement character for a pair of parentheses at end of
103 // function name, to force sorting parentheses before all other characters.
104 // Collation may treat parentheses differently.
105 const sal_Unicode cParenthesesReplacement = 0x0001;
107 sal_Unicode lcl_getSheetSeparator(ScDocument* pDoc)
109 ScCompiler aComp(pDoc, ScAddress());
110 aComp.SetGrammar(pDoc->GetGrammar());
111 return aComp.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
114 ScTypedCaseStrSet::const_iterator findText(
115 const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator itPos,
116 const OUString& rStart, OUString& rResult, bool bBack)
118 if (bBack) // Backwards
120 ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
121 if (itPos != rDataSet.end())
123 size_t nPos = std::distance(rDataSet.begin(), itPos);
124 size_t nRPos = rDataSet.size() - 1 - nPos;
125 std::advance(it, nRPos);
126 ++it;
129 for (; it != itEnd; ++it)
131 const ScTypedStrData& rData = *it;
132 if (rData.GetStringType() == ScTypedStrData::Value)
133 // skip values
134 continue;
136 if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
137 // not a match
138 continue;
140 rResult = rData.GetString();
141 return (++it).base(); // convert the reverse iterator back to iterator.
144 else // Forwards
146 ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
147 if (itPos != rDataSet.end())
149 it = itPos;
150 ++it;
153 for (; it != itEnd; ++it)
155 const ScTypedStrData& rData = *it;
156 if (rData.GetStringType() == ScTypedStrData::Value)
157 // skip values
158 continue;
160 if (!ScGlobal::GetpTransliteration()->isMatch(rStart, rData.GetString()))
161 // not a match
162 continue;
164 rResult = rData.GetString();
165 return it;
169 return rDataSet.end(); // no matching text found
172 OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
174 ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
175 for (; it != itEnd; ++it)
177 const ScTypedStrData& rData = *it;
178 if (rData.GetStringType() == ScTypedStrData::Value)
179 continue;
181 if (!ScGlobal::GetpTransliteration()->isEqual(rData.GetString(), rString))
182 continue;
184 return rData.GetString();
186 return rString;
189 void removeChars(OUString& rStr, sal_Unicode c)
191 OUStringBuffer aBuf(rStr);
192 for (sal_Int32 i = 0, n = aBuf.getLength(); i < n; ++i)
194 if (aBuf[i] == c)
195 aBuf[i] = ' ';
197 rStr = aBuf.makeStringAndClear();
202 void ScInputHandler::InitRangeFinder( const OUString& rFormula )
204 DeleteRangeFinder();
205 ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
206 ScDocument* pDoc = pDocSh->GetDocument();
207 const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDoc);
209 if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
210 return;
212 OUString aDelimiters = ScEditUtil::ModifyDelimiters(
213 OUString::createFromAscii( pMinDelimiters ) );
215 sal_Int32 nColon = aDelimiters.indexOf( ':' );
216 if ( nColon != -1 )
217 aDelimiters = aDelimiters.replaceAt( nColon, 1, ""); // Delimiter without colon
218 sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
219 if ( nDot != -1 )
220 aDelimiters = aDelimiters.replaceAt( nDot, 1 , ""); // Delimiter without dot
222 const sal_Unicode* pChar = rFormula.getStr();
223 sal_Int32 nLen = rFormula.getLength();
224 sal_Int32 nPos = 0;
225 sal_Int32 nStart = 0;
226 sal_uInt16 nCount = 0;
227 ScRange aRange;
228 while ( nPos < nLen && nCount < RANGEFIND_MAX )
230 // Skip separator
231 while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
233 if ( pChar[nPos] == '"' ) // String
235 ++nPos;
236 while (nPos<nLen && pChar[nPos] != '"') // Skip until end
237 ++nPos;
239 ++nPos; // Separator or closing quote
242 // Text zwischen Trennern
243 nStart = nPos;
244 handle_r1c1:
245 while ( nPos<nLen && !ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
246 ++nPos;
248 // for R1C1 '-' in R[-]... or C[-]... are not delimiters
249 // Nothing heroic here to ensure that there are '[]' around a negative
250 // integer. we need to clean up this code.
251 if( nPos < nLen && nPos > 0 &&
252 '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
253 formula::FormulaGrammar::CONV_XL_R1C1 == pDoc->GetAddressConvention() )
255 nPos++;
256 goto handle_r1c1;
259 if ( nPos > nStart )
261 OUString aTest = rFormula.copy( nStart, nPos-nStart );
262 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
263 sal_uInt16 nFlags = aRange.ParseAny( aTest, pDoc, aAddrDetails );
264 if ( nFlags & SCA_VALID )
266 // Set tables if not specified
267 if ( (nFlags & SCA_TAB_3D) == 0 )
268 aRange.aStart.SetTab( pActiveViewSh->GetViewData()->GetTabNo() );
269 if ( (nFlags & SCA_TAB2_3D) == 0 )
270 aRange.aEnd.SetTab( aRange.aStart.Tab() );
272 if ( ( nFlags & ( SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2 ) ) == 0 )
274 // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
275 // so Format doesn't output a double ref because of different flags.
276 sal_uInt16 nAbsFlags = nFlags & ( SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
277 nFlags |= nAbsFlags << 4;
280 if (!nCount)
282 pEngine->SetUpdateMode( false );
283 pRangeFindList = new ScRangeFindList( pDocSh->GetTitle() );
286 ColorData nColorData = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
288 ESelection aSel( 0, nStart, 0, nPos );
289 SfxItemSet aSet( pEngine->GetEmptyItemSet() );
290 aSet.Put( SvxColorItem( Color( nColorData ),
291 EE_CHAR_COLOR ) );
292 pEngine->QuickSetAttribs( aSet, aSel );
293 ++nCount;
297 // Do not skip last separator; could be a quote (?)
300 if (nCount)
302 pEngine->SetUpdateMode( true );
304 pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );
308 void ScInputHandler::SetDocumentDisposing( bool b )
310 mbDocumentDisposing = b;
313 static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
315 if ( pView )
317 ESelection aOldSel = pView->GetSelection();
318 if (aOldSel.HasRange())
319 pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
320 aOldSel.nEndPara, aOldSel.nEndPos ) );
322 EditEngine* pEngine = pView->GetEditEngine();
323 pEngine->QuickInsertText( rNewStr, rOldSel );
325 // Dummy InsertText for Update and Paint
326 // To do that we need to cancel the selection from above (before QuickInsertText)
327 pView->InsertText( EMPTY_OUSTRING, false );
329 sal_Int32 nLen = pEngine->GetTextLen(0);
330 ESelection aSel( 0, nLen, 0, nLen );
331 pView->SetSelection( aSel ); // Set cursor to the end
335 void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
337 ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
338 if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
340 ScRangeFindData* pData = pRangeFindList->GetObject( nIndex );
341 sal_Int32 nOldStart = pData->nSelStart;
342 sal_Int32 nOldEnd = pData->nSelEnd;
344 ScRange aJustified = rNew;
345 aJustified.Justify(); // Always display Ref in the Formula the right way
346 ScDocument* pDoc = pDocView->GetViewData()->GetDocument();
347 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
348 OUString aNewStr(aJustified.Format(pData->nFlags, pDoc, aAddrDetails));
349 ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
351 DataChanging();
353 lcl_Replace( pTopView, aNewStr, aOldSel );
354 lcl_Replace( pTableView, aNewStr, 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;
365 sal_uInt16 nCount = (sal_uInt16) pRangeFindList->Count();
366 for (sal_uInt16 i=nIndex+1; i<nCount; i++)
368 ScRangeFindData* pNext = pRangeFindList->GetObject( i );
369 pNext->nSelStart = pNext->nSelStart + nDiff;
370 pNext->nSelEnd = pNext->nSelEnd + nDiff;
373 else
375 OSL_FAIL("UpdateRange: we're missing something");
379 void ScInputHandler::DeleteRangeFinder()
381 ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
382 if ( pRangeFindList && pPaintView )
384 ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
385 pRangeFindList->SetHidden(true);
386 pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) ); // Steal
387 DELETEZ(pRangeFindList);
391 inline OUString GetEditText(EditEngine* pEng)
393 return ScEditUtil::GetSpaceDelimitedString(*pEng);
396 static void lcl_RemoveTabs(OUString& rStr)
398 removeChars(rStr, '\t');
401 static void lcl_RemoveLineEnd(OUString& rStr)
403 rStr = convertLineEnd(rStr, LINEEND_LF);
404 removeChars(rStr, '\n');
407 static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
409 int nDir;
410 sal_Unicode c1, c2 = 0;
411 c1 = rStr[nPos];
412 switch ( c1 )
414 case '(' :
415 c2 = ')';
416 nDir = 1;
417 break;
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 default:
447 nDir = 0;
449 if ( !nDir )
450 return -1;
451 sal_Int32 nLen = rStr.getLength();
452 const sal_Unicode* p0 = rStr.getStr();
453 const sal_Unicode* p;
454 const sal_Unicode* p1;
455 sal_uInt16 nQuotes = 0;
456 if ( nPos < nLen / 2 )
458 p = p0;
459 p1 = p0 + nPos;
461 else
463 p = p0 + nPos;
464 p1 = p0 + nLen;
466 while ( p < p1 )
468 if ( *p++ == '\"' )
469 nQuotes++;
471 // Odd number of quotes that we find ourselves in a string
472 bool bLookInString = ((nQuotes % 2) != 0);
473 bool bInString = bLookInString;
474 p = p0 + nPos;
475 p1 = (nDir < 0 ? p0 : p0 + nLen) ;
476 sal_uInt16 nLevel = 1;
477 while ( p != p1 && nLevel )
479 p += nDir;
480 if ( *p == '\"' )
482 bInString = !bInString;
483 if ( bLookInString && !bInString )
484 p = p1; // That's it then
486 else if ( bInString == bLookInString )
488 if ( *p == c1 )
489 nLevel++;
490 else if ( *p == c2 )
491 nLevel--;
494 if ( nLevel )
495 return -1;
496 return (sal_Int32) (p - p0);
499 ScInputHandler::ScInputHandler()
500 : pInputWin( NULL ),
501 pEngine( NULL ),
502 pTableView( NULL ),
503 pTopView( NULL ),
504 pColumnData( NULL ),
505 pFormulaData( NULL ),
506 pFormulaDataPara( NULL ),
507 pTipVisibleParent( NULL ),
508 nTipVisible( 0 ),
509 pTipVisibleSecParent( NULL ),
510 nTipVisibleSec( 0 ),
511 nFormSelStart( 0 ),
512 nFormSelEnd( 0 ),
513 nAutoPar( 0 ),
514 eMode( SC_INPUT_NONE ),
515 bUseTab( false ),
516 bTextValid( true ),
517 bModified( false ),
518 bSelIsRef( false ),
519 bFormulaMode( false ),
520 bInRangeUpdate( false ),
521 bParenthesisShown( false ),
522 bCreatingFuncView( false ),
523 bInEnterHandler( false ),
524 bCommandErrorShown( false ),
525 bInOwnChange( false ),
526 bProtected( false ),
527 bCellHasPercentFormat( false ),
528 bLastIsSymbol( false ),
529 mbDocumentDisposing(false),
530 nValidation( 0 ),
531 eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ),
532 aScaleX( 1,1 ),
533 aScaleY( 1,1 ),
534 pRefViewSh( NULL ),
535 pLastPattern( NULL ),
536 pEditDefaults( NULL ),
537 pLastState( NULL ),
538 pDelayTimer( NULL ),
539 pRangeFindList( NULL ),
540 maFormulaChar()
542 // The InputHandler is constructed with the view, so SfxViewShell::Current
543 // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
544 pActiveViewSh = NULL;
546 // Bindings (only still used for Invalidate) are retrieved if needed on demand
549 ScInputHandler::~ScInputHandler()
551 // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
552 // thus we can't rely on any Sfx functions
553 if (!mbDocumentDisposing) // inplace
554 EnterHandler(); // Finish input
556 if (SC_MOD()->GetRefInputHdl() == this)
557 SC_MOD()->SetRefInputHdl(NULL);
559 if ( pInputWin && pInputWin->GetInputHandler() == this )
560 pInputWin->SetInputHandler( NULL );
562 delete pRangeFindList;
563 delete pEditDefaults;
564 delete pEngine;
565 delete pLastState;
566 delete pDelayTimer;
567 delete pColumnData;
568 delete pFormulaData;
569 delete pFormulaDataPara;
572 void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
574 if ( rX != aScaleX || rY != aScaleY )
576 aScaleX = rX;
577 aScaleY = rY;
578 if (pEngine)
580 MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
581 pEngine->SetRefMapMode( aMode );
586 void ScInputHandler::UpdateRefDevice()
588 if (!pEngine)
589 return;
591 bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
592 bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
593 sal_uLong nCtrl = pEngine->GetControlWord();
594 if ( bTextWysiwyg || bInPlace )
595 nCtrl |= EE_CNTRL_FORMAT100; // EditEngine default: always format for 100%
596 else
597 nCtrl &= ~EE_CNTRL_FORMAT100; // when formatting for screen, use the actual MapMode
598 pEngine->SetControlWord( nCtrl );
599 if ( bTextWysiwyg && pActiveViewSh )
600 pEngine->SetRefDevice( pActiveViewSh->GetViewData()->GetDocument()->GetPrinter() );
601 else
602 pEngine->SetRefDevice( NULL );
604 MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
605 pEngine->SetRefMapMode( aMode );
607 // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
608 // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
609 if ( !( bTextWysiwyg && pActiveViewSh ) )
611 pEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
615 void ScInputHandler::ImplCreateEditEngine()
617 if ( !pEngine )
619 if ( pActiveViewSh )
621 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
622 pEngine = new ScFieldEditEngine(pDoc, pDoc->GetEnginePool(), pDoc->GetEditPool());
624 else
625 pEngine = new ScFieldEditEngine(NULL, EditEngine::CreatePool(), NULL, true);
626 pEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
627 UpdateRefDevice(); // also sets MapMode
628 pEngine->SetPaperSize( Size( 1000000, 1000000 ) );
629 pEditDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
631 pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_AUTOCORRECT );
632 pEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
636 void ScInputHandler::UpdateAutoCorrFlag()
638 sal_uLong nCntrl = pEngine->GetControlWord();
639 sal_uLong nOld = nCntrl;
641 // Don't use pLastPattern here (may be invalid because of AutoStyle)
642 bool bDisable = bLastIsSymbol || bFormulaMode;
643 if ( bDisable )
644 nCntrl &= ~EE_CNTRL_AUTOCORRECT;
645 else
646 nCntrl |= EE_CNTRL_AUTOCORRECT;
648 if ( nCntrl != nOld )
649 pEngine->SetControlWord(nCntrl);
652 void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
654 if ( pActiveViewSh )
656 ScViewData* pViewData = pActiveViewSh->GetViewData();
657 bool bOnlineSpell = pViewData->GetDocument()->GetDocOptions().IsAutoSpell();
659 // SetDefaultLanguage is independent of the language attributes,
660 // ScGlobal::GetEditDefaultLanguage is always used.
661 // It must be set every time in case the office language was changed.
663 pEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
665 // if called for changed options, update flags only if already editing
666 // if called from StartTable, always update flags
668 if ( bFromStartTab || eMode != SC_INPUT_NONE )
670 sal_uLong nCntrl = pEngine->GetControlWord();
671 sal_uLong nOld = nCntrl;
672 if( bOnlineSpell )
673 nCntrl |= EE_CNTRL_ONLINESPELLING;
674 else
675 nCntrl &= ~EE_CNTRL_ONLINESPELLING;
676 // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
677 if ( pLastPattern && pLastPattern->IsSymbolFont() )
678 nCntrl &= ~EE_CNTRL_AUTOCORRECT;
679 else
680 nCntrl |= EE_CNTRL_AUTOCORRECT;
681 if ( nCntrl != nOld )
682 pEngine->SetControlWord(nCntrl);
684 ScDocument* pDoc = pViewData->GetDocument();
685 pDoc->ApplyAsianEditSettings( *pEngine );
686 pEngine->SetDefaultHorizontalTextDirection(
687 (EEHorizontalTextDirection)pDoc->GetEditTextDirection( pViewData->GetTabNo() ) );
688 pEngine->SetFirstWordCapitalization( false );
691 // Language is set separately, so the speller is needed only if online spelling is active
692 if ( bOnlineSpell ) {
693 com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
694 pEngine->SetSpeller( xXSpellChecker1 );
697 bool bHyphen = pLastPattern && ((const SfxBoolItem&)pLastPattern->GetItem(ATTR_HYPHENATE)).GetValue();
698 if ( bHyphen ) {
699 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
700 pEngine->SetHyphenator( xXHyphenator );
706 // Function/Range names etc. as Tip help
709 // The other types are defined in ScDocument::GetFormulaEntries
710 void ScInputHandler::GetFormulaData()
712 if ( pActiveViewSh )
714 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
716 if ( pFormulaData )
717 pFormulaData->clear();
718 else
720 pFormulaData = new ScTypedCaseStrSet;
723 if( pFormulaDataPara )
724 pFormulaDataPara->clear();
725 else
726 pFormulaDataPara = new ScTypedCaseStrSet;
728 const OUString aParenthesesReplacement( cParenthesesReplacement);
729 const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
730 sal_uLong nListCount = pFuncList->GetCount();
731 for(sal_uLong i=0;i<nListCount;i++)
733 const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
734 if ( pDesc->pFuncName )
736 const sal_Unicode* pName = pDesc->pFuncName->getStr();
737 const sal_Int32 nLen = pDesc->pFuncName->getLength();
738 // fdo#75264 fill maFormulaChar with all characters used in formula names
739 for ( sal_Int32 j = 0; j < nLen; j++ )
741 sal_Unicode c = pName[ j ];
742 maFormulaChar.insert( c );
744 OUString aFuncName = *pDesc->pFuncName + aParenthesesReplacement;
745 pFormulaData->insert(ScTypedStrData(aFuncName, 0.0, ScTypedStrData::Standard));
746 pDesc->initArgumentInfo();
747 OUString aEntry = pDesc->getSignature();
748 pFormulaDataPara->insert(ScTypedStrData(aEntry, 0.0, ScTypedStrData::Standard));
751 miAutoPosFormula = pFormulaData->end();
752 pDoc->GetFormulaEntries( *pFormulaData );
753 pDoc->GetFormulaEntries( *pFormulaDataPara );
757 IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent*, pEvent )
759 if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
760 HideTip();
761 return 0;
764 IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent*, pEvent )
766 if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
767 HideTipBelow();
768 return 0;
771 void ScInputHandler::HideTip()
773 if ( nTipVisible )
775 if (pTipVisibleParent)
776 pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
777 Help::HideTip( nTipVisible );
778 nTipVisible = 0;
779 pTipVisibleParent = NULL;
781 aManualTip = OUString();
783 void ScInputHandler::HideTipBelow()
785 if ( nTipVisibleSec )
787 if (pTipVisibleSecParent)
788 pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
789 Help::HideTip( nTipVisibleSec );
790 nTipVisibleSec = 0;
791 pTipVisibleSecParent = NULL;
793 aManualTip = OUString();
796 void ScInputHandler::ShowArgumentsTip( const OUString& rParagraph, OUString& rSelText, const ESelection& rSel,
797 bool bTryFirstSel )
799 ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
800 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
801 const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDocSh->GetDocument());
802 FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
803 bool bFound = false;
804 while( !bFound )
806 rSelText += ")";
807 sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
808 if( nLeftParentPos != -1 )
810 sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
811 const IFunctionDescription* ppFDesc;
812 ::std::vector< OUString> aArgs;
813 if( aHelper.GetNextFunc( rSelText, false, nNextFStart, NULL, &ppFDesc, &aArgs ) )
815 if( !ppFDesc->getFunctionName().isEmpty() )
817 sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
818 sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
819 OUString aFuncName( ppFDesc->getFunctionName() + "(");
820 OUString aNew;
821 ScTypedCaseStrSet::const_iterator it =
822 findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
823 if (it != pFormulaDataPara->end())
825 bool bFlag = false;
826 sal_uInt16 nActive = 0;
827 for( sal_uInt16 i=0; i < nArgs; i++ )
829 sal_Int32 nLength = aArgs[i].getLength();
830 if( nArgPos <= rSelText.getLength()-1 )
832 nActive = i+1;
833 bFlag = true;
835 nArgPos+=nLength+1;
837 if( bFlag )
839 sal_Int32 nCountSemicolon = comphelper::string::getTokenCount(aNew, cSep) - 1;
840 sal_Int32 nCountDot = comphelper::string::getTokenCount(aNew, cSheetSep) - 1;
841 sal_Int32 nStartPosition = 0;
842 sal_Int32 nEndPosition = 0;
844 if( !nCountSemicolon )
846 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
848 sal_Unicode cNext = aNew[i];
849 if( cNext == '(' )
851 nStartPosition = i+1;
855 else if( !nCountDot )
857 sal_uInt16 nCount = 0;
858 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
860 sal_Unicode cNext = aNew[i];
861 if( cNext == '(' )
863 nStartPosition = i+1;
865 else if( cNext == cSep )
867 nCount ++;
868 nEndPosition = i;
869 if( nCount == nActive )
871 break;
873 nStartPosition = nEndPosition+1;
877 else
879 sal_uInt16 nCount = 0;
880 for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
882 sal_Unicode cNext = aNew[i];
883 if( cNext == '(' )
885 nStartPosition = i+1;
887 else if( cNext == cSep )
889 nCount ++;
890 nEndPosition = i;
891 if( nCount == nActive )
893 break;
895 nStartPosition = nEndPosition+1;
897 else if( cNext == cSheetSep )
899 continue;
904 if (nStartPosition > 0)
906 OUStringBuffer aBuf;
907 aBuf.append(aNew.copy(0, nStartPosition));
908 aBuf.append(static_cast<sal_Unicode>(0x25BA));
909 aBuf.append(aNew.copy(nStartPosition));
910 aNew = aBuf.makeStringAndClear();
911 ShowTipBelow( aNew );
912 bFound = true;
915 else
917 ShowTipBelow( aNew );
918 bFound = true;
924 else if (bTryFirstSel)
926 sal_Int32 nPosition = 0;
927 OUString aText = pEngine->GetWord( 0, rSel.nEndPos-1 );
928 /* XXX: dubious, what is this condition supposed to exactly match? */
929 if (rSel.nEndPos <= aText.getLength() && aText[ rSel.nEndPos-1 ] == '=')
931 break;
933 OUString aNew;
934 nPosition = aText.getLength()+1;
935 ScTypedCaseStrSet::const_iterator it =
936 findText(*pFormulaDataPara, pFormulaDataPara->end(), aText, aNew, false);
937 if (it != pFormulaDataPara->end())
939 if( nPosition < rParagraph.getLength() && rParagraph[ nPosition ] =='(' )
941 ShowTipBelow( aNew );
942 bFound = true;
944 else
945 break;
947 else
949 break;
952 else
954 break;
959 void ScInputHandler::ShowTipCursor()
961 HideTip();
962 HideTipBelow();
963 EditView* pActiveView = pTopView ? pTopView : pTableView;
965 if ( bFormulaMode && pActiveView && pFormulaDataPara && pEngine->GetParagraphCount() == 1 )
967 OUString aParagraph = pEngine->GetText( 0 );
968 ESelection aSel = pActiveView->GetSelection();
969 aSel.Adjust();
971 if ( aParagraph.getLength() < aSel.nEndPos )
972 return;
974 if ( aSel.nEndPos > 0 )
976 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
978 ShowArgumentsTip( aParagraph, aSelText, aSel, true);
983 void ScInputHandler::ShowTip( const OUString& rText )
985 // aManualTip needs to be set afterwards from outside
986 HideTip();
987 EditView* pActiveView = pTopView ? pTopView : pTableView;
988 if (pActiveView)
990 Point aPos;
991 pTipVisibleParent = pActiveView->GetWindow();
992 Cursor* pCur = pActiveView->GetCursor();
993 if (pCur)
994 aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
995 aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
996 Rectangle aRect( aPos, aPos );
998 sal_uInt16 nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM;
999 nTipVisible = Help::ShowTip(pTipVisibleParent, aRect, rText, nAlign);
1000 pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
1004 void ScInputHandler::ShowTipBelow( const OUString& rText )
1006 HideTipBelow();
1008 EditView* pActiveView = pTopView ? pTopView : pTableView;
1009 if ( pActiveView )
1011 Point aPos;
1012 pTipVisibleSecParent = pActiveView->GetWindow();
1013 Cursor* pCur = pActiveView->GetCursor();
1014 if ( pCur )
1016 Point aLogicPos = pCur->GetPos();
1017 aLogicPos.Y() += pCur->GetHeight();
1018 aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
1020 aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
1021 Rectangle aRect( aPos, aPos );
1022 sal_uInt16 nAlign = QUICKHELP_LEFT | QUICKHELP_TOP | QUICKHELP_NOEVADEPOINTER;
1023 nTipVisibleSec = Help::ShowTip(pTipVisibleSecParent, aRect, rText, nAlign);
1024 pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
1028 bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
1030 if ( aStart.isEmpty() )
1031 return false;
1033 aStart = ScGlobal::pCharClass->uppercase( aStart );
1034 sal_Int32 nPos = aStart.getLength() - 1;
1035 sal_Unicode c = aStart[ nPos ];
1036 // fdo#75264 use maFormulaChar to check if characters are used in function names
1037 ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
1038 if ( p == maFormulaChar.end() )
1039 return false; // last character is not part of any function name, quit
1041 ::std::vector<sal_Unicode> aTemp;
1042 while ( nPos >= 0 && p != maFormulaChar.end() )
1044 aTemp.push_back( c );
1045 c = aStart[ --nPos ];
1046 p = maFormulaChar.find( c );
1049 ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
1050 aResult = OUString( *rIt++ );
1051 while ( rIt != aTemp.rend() )
1052 aResult += OUString( *rIt++ );
1054 return true;
1057 void ScInputHandler::UseFormulaData()
1059 EditView* pActiveView = pTopView ? pTopView : pTableView;
1061 // Formulas may only have 1 paragraph
1062 if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
1064 OUString aParagraph = pEngine->GetText( 0 );
1065 ESelection aSel = pActiveView->GetSelection();
1066 aSel.Adjust();
1068 // Due to differences between table and input cell (e.g clipboard with line breaks),
1069 // the selection may not be in line with the EditEngine anymore.
1070 // Just return without any indication as to why.
1071 if ( aSel.nEndPos > aParagraph.getLength() )
1072 return;
1074 // Is the cursor at the end of a word?
1075 if ( aSel.nEndPos > 0 )
1077 OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
1079 OUString aText;
1080 if ( GetFuncName( aSelText, aText ) )
1082 // function name is incomplete:
1083 // show first matching function name as tip above cell
1084 OUString aNew;
1085 miAutoPosFormula = pFormulaData->end();
1086 miAutoPosFormula = findText(*pFormulaData, miAutoPosFormula, aText, aNew, false);
1087 if (miAutoPosFormula != pFormulaData->end())
1089 if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1090 aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1091 ShowTip( aNew );
1092 aAutoSearch = aText;
1094 return;
1097 // function name is complete:
1098 // show tip below the cell with function name and arguments of function
1099 ShowArgumentsTip( aParagraph, aSelText, aSel, false);
1104 void ScInputHandler::NextFormulaEntry( bool bBack )
1106 EditView* pActiveView = pTopView ? pTopView : pTableView;
1107 if ( pActiveView && pFormulaData )
1109 OUString aNew;
1110 ScTypedCaseStrSet::const_iterator itNew = findText(*pFormulaData, miAutoPosFormula, aAutoSearch, aNew, bBack);
1111 if (itNew != pFormulaData->end())
1113 miAutoPosFormula = itNew;
1114 if (aNew[aNew.getLength()-1] == cParenthesesReplacement)
1115 aNew = aNew.copy( 0, aNew.getLength()-1) + "()";
1116 ShowTip(aNew); // Display a quick help
1120 // For Tab we always call HideCursor first
1121 if (pActiveView)
1122 pActiveView->ShowCursor();
1125 namespace {
1127 bool needToExtendSelection(const OUString& rSelectedText, const OUString& rInsertText)
1129 SAL_DEBUG(rSelectedText);
1130 return !rInsertText.startsWithIgnoreAsciiCase(rSelectedText);
1133 void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
1135 if (pView)
1137 ESelection aSel = pView->GetSelection();
1138 --aSel.nStartPos;
1139 --aSel.nEndPos;
1140 pView->SetSelection(aSel);
1141 pView->SelectCurrentWord();
1143 // a dot and underscore are word separators so we need special
1144 // treatment for any formula containing a dot or underscore
1145 if(rInsert.indexOf(".") != -1 || rInsert.indexOf("_") != -1)
1147 // need to make sure that we replace also the part before the dot
1148 // go through the word to find the match with the insert string
1149 aSel = pView->GetSelection();
1150 ESelection aOldSelection = aSel;
1151 OUString aSelectedText = pView->GetSelected();
1152 if ( needToExtendSelection( aSelectedText, rInsert ) )
1154 while(needToExtendSelection(aSelectedText, rInsert))
1156 assert(aSel.nStartPos > 0);
1157 --aSel.nStartPos;
1158 aSel.nEndPos = aSel.nStartPos;
1159 pView->SetSelection(aSel);
1160 pView->SelectCurrentWord();
1161 aSelectedText = pView->GetSelected();
1163 aSel.nStartPos = aSel.nEndPos - ( aSelectedText.getLength() - 1 );
1165 else
1167 aSel.nStartPos = aSel.nEndPos - aSelectedText.getLength();
1169 aSel.nEndPos = aOldSelection.nEndPos;
1170 pView->SetSelection(aSel);
1173 OUString aInsStr = rInsert;
1174 sal_Int32 nInsLen = aInsStr.getLength();
1175 bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
1176 && aInsStr[nInsLen-1] == ')' );
1177 if ( bDoParen )
1179 // Do not insert parentheses after function names if there already are some
1180 // (e.g. if the function name was edited).
1181 ESelection aWordSel = pView->GetSelection();
1182 OUString aOld = pView->GetEditEngine()->GetText(0);
1184 // aWordSel.EndPos points one behind string if word at end
1185 if (aWordSel.nEndPos < aOld.getLength())
1187 sal_Unicode cNext = aOld[aWordSel.nEndPos];
1188 if ( cNext == '(' )
1190 bDoParen = false;
1191 aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
1196 pView->InsertText( aInsStr, false );
1198 if ( bDoParen ) // Put cursor between parentheses
1200 aSel = pView->GetSelection();
1201 --aSel.nStartPos;
1202 --aSel.nEndPos;
1203 pView->SetSelection(aSel);
1205 rParInserted = true;
1212 void ScInputHandler::PasteFunctionData()
1214 if (pFormulaData && miAutoPosFormula != pFormulaData->end())
1216 const ScTypedStrData& rData = *miAutoPosFormula;
1217 OUString aInsert = rData.GetString();
1218 if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
1219 aInsert = aInsert.copy( 0, aInsert.getLength()-1) + "()";
1220 bool bParInserted = false;
1222 DataChanging(); // Cannot be new
1223 completeFunction( pTopView, aInsert, bParInserted );
1224 completeFunction( pTableView, aInsert, bParInserted );
1225 DataChanged();
1226 ShowTipCursor();
1228 if (bParInserted)
1229 AutoParAdded();
1232 HideTip();
1234 EditView* pActiveView = pTopView ? pTopView : pTableView;
1235 if (pActiveView)
1236 pActiveView->ShowCursor();
1240 // Calculate selection and display as tip help
1241 static OUString lcl_Calculate( const OUString& rFormula, ScDocument* pDoc, const ScAddress &rPos )
1243 //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
1244 // Quotation marks for Strings are only inserted here.
1246 if(rFormula.isEmpty())
1247 return OUString();
1249 boost::scoped_ptr<ScSimpleFormulaCalculator> pCalc( new ScSimpleFormulaCalculator( pDoc, rPos, rFormula ) );
1251 // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
1252 // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
1253 bool bColRowName = pCalc->HasColRowName();
1254 if ( bColRowName )
1256 // ColRowName in RPN code?
1257 if ( pCalc->GetCode()->GetCodeLen() <= 1 )
1258 { // ==1: Single one is as a Parameter always a Range
1259 // ==0: It might be one, if ...
1260 OUStringBuffer aBraced;
1261 aBraced.append('(');
1262 aBraced.append(rFormula);
1263 aBraced.append(')');
1264 pCalc.reset( new ScSimpleFormulaCalculator( pDoc, rPos, aBraced.makeStringAndClear() ) );
1266 else
1267 bColRowName = false;
1270 sal_uInt16 nErrCode = pCalc->GetErrCode();
1271 if ( nErrCode != 0 )
1272 return ScGlobal::GetErrorString(nErrCode);
1274 SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
1275 OUString aValue;
1276 if ( pCalc->IsValue() )
1278 double n = pCalc->GetValue();
1279 sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
1280 pCalc->GetFormatType(), ScGlobal::eLnge );
1281 aFormatter.GetInputLineString( n, nFormat, aValue );
1282 //! display OutputString but insert InputLineString
1284 else
1286 OUString aStr = pCalc->GetString().getString();
1287 sal_uLong nFormat = aFormatter.GetStandardFormat(
1288 pCalc->GetFormatType(), ScGlobal::eLnge);
1290 Color* pColor;
1291 aFormatter.GetOutputString( aStr, nFormat,
1292 aValue, &pColor );
1295 aValue = "\"" + aValue + "\"";
1296 //! Escape quotation marks in String??
1299 ScRange aTestRange;
1300 if ( bColRowName || (aTestRange.Parse(rFormula) & SCA_VALID) )
1301 aValue = aValue + " ...";
1303 return aValue;
1306 void ScInputHandler::FormulaPreview()
1308 OUString aValue;
1309 EditView* pActiveView = pTopView ? pTopView : pTableView;
1310 if ( pActiveView && pActiveViewSh )
1312 OUString aPart = pActiveView->GetSelected();
1313 if (aPart.isEmpty())
1314 aPart = pEngine->GetText(0);
1315 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
1316 aValue = lcl_Calculate( aPart, pDoc, aCursorPos );
1319 if (!aValue.isEmpty())
1321 ShowTip( aValue ); // Display as QuickHelp
1322 aManualTip = aValue; // Set after ShowTip
1323 if (pFormulaData)
1324 miAutoPosFormula = pFormulaData->end();
1325 if (pColumnData)
1326 miAutoPosColumn = pColumnData->end();
1330 void ScInputHandler::PasteManualTip()
1332 // Three dots at the end -> Range reference -> do not insert
1333 // FIXME: Once we have matrix constants, we can change this
1334 sal_Int32 nTipLen = aManualTip.getLength();
1335 sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
1336 if ( nTipLen && ( nTipLen < 3 || aManualTip.copy( nTipLen2-3 ) != "..." ) )
1338 DataChanging(); // Cannot be new
1340 OUString aInsert = aManualTip;
1341 EditView* pActiveView = pTopView ? pTopView : pTableView;
1342 if (!pActiveView->HasSelection())
1344 // Nothing selected -> select everything
1345 sal_Int32 nOldLen = pEngine->GetTextLen(0);
1346 ESelection aAllSel( 0, 0, 0, nOldLen );
1347 if ( pTopView )
1348 pTopView->SetSelection( aAllSel );
1349 if ( pTableView )
1350 pTableView->SetSelection( aAllSel );
1353 ESelection aSel = pActiveView->GetSelection();
1354 aSel.Adjust();
1355 OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
1356 if ( !aSel.nStartPos ) // Selection from the start?
1358 if ( aSel.nEndPos == pEngine->GetTextLen(0) )
1360 // Everything selected -> skip quotation marks
1361 if ( aInsert[0] == '"' )
1362 aInsert = aInsert.copy(1);
1363 sal_Int32 nInsLen = aInsert.getLength();
1364 if ( aInsert.endsWith("\"") )
1365 aInsert = aInsert.copy( 0, nInsLen-1 );
1367 else if ( aSel.nEndPos )
1369 // Not everything selected -> do not overwrite equality sign
1370 //FIXME: Even double equality signs??
1371 aSel.nStartPos = 1;
1372 if ( pTopView )
1373 pTopView->SetSelection( aSel );
1374 if ( pTableView )
1375 pTableView->SetSelection( aSel );
1378 if ( pTopView )
1379 pTopView->InsertText( aInsert, true );
1380 if ( pTableView )
1381 pTableView->InsertText( aInsert, true );
1383 DataChanged();
1386 HideTip();
1389 void ScInputHandler::ResetAutoPar()
1391 nAutoPar = 0;
1394 void ScInputHandler::AutoParAdded()
1396 ++nAutoPar; // Closing parenthesis can be overwritten
1399 bool ScInputHandler::CursorAtClosingPar()
1401 // Test if the cursor is before a closing parenthesis
1402 // Selection from SetReference has been removed before
1403 EditView* pActiveView = pTopView ? pTopView : pTableView;
1404 if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
1406 ESelection aSel = pActiveView->GetSelection();
1407 sal_Int32 nPos = aSel.nStartPos;
1408 OUString aFormula = pEngine->GetText(0);
1409 if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
1410 return true;
1412 return false;
1415 void ScInputHandler::SkipClosingPar()
1417 // this is called when a ')' is typed and the cursor is before a ')'
1418 // that can be overwritten -> just set the cursor behind the ')'
1420 EditView* pActiveView = pTopView ? pTopView : pTableView;
1421 if (pActiveView)
1423 ESelection aSel = pActiveView->GetSelection();
1424 ++aSel.nStartPos;
1425 ++aSel.nEndPos;
1427 // this is in a formula (only one paragraph), so the selection
1428 // can be used directly for the TopView
1430 if ( pTopView )
1431 pTopView->SetSelection( aSel );
1432 if ( pTableView )
1433 pTableView->SetSelection( aSel );
1436 OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
1437 --nAutoPar;
1441 // Auto input
1443 void ScInputHandler::GetColData()
1445 if ( pActiveViewSh )
1447 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
1449 if ( pColumnData )
1450 pColumnData->clear();
1451 else
1452 pColumnData = new ScTypedCaseStrSet;
1454 std::vector<ScTypedStrData> aEntries;
1455 pDoc->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();
1596 // Highlight parentheses
1597 void ScInputHandler::UpdateParenthesis()
1599 // Find parentheses
1600 //TODO: Can we disable parentheses highlighting per paranthesis?
1601 bool bFound = false;
1602 if ( bFormulaMode && eMode != SC_INPUT_TOP )
1604 if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
1606 ESelection aSel = pTableView->GetSelection();
1607 if (aSel.nStartPos)
1609 // Examine character left to the cursor
1610 sal_Int32 nPos = aSel.nStartPos - 1;
1611 OUString aFormula = pEngine->GetText(0);
1612 sal_Unicode c = aFormula[nPos];
1613 if ( c == '(' || c == ')' )
1615 sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
1616 if ( nOther != -1 )
1618 SfxItemSet aSet( pEngine->GetEmptyItemSet() );
1619 aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
1621 //! Distinguish if cell is already highlighted!!!!
1622 if (bParenthesisShown)
1624 // Remove old highlighting
1625 sal_Int32 nCount = pEngine->GetParagraphCount();
1626 for (sal_Int32 i=0; i<nCount; i++)
1627 pEngine->QuickRemoveCharAttribs( i, EE_CHAR_WEIGHT );
1630 ESelection aSelThis( 0,nPos, 0,nPos+1 );
1631 pEngine->QuickSetAttribs( aSet, aSelThis );
1632 ESelection aSelOther( 0,nOther, 0,nOther+1 );
1633 pEngine->QuickSetAttribs( aSet, aSelOther );
1635 // Dummy InsertText for Update and Paint (selection is empty)
1636 pTableView->InsertText( EMPTY_OUSTRING, false );
1638 bFound = true;
1643 // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
1644 // with different color (COL_LIGHTBLUE) ??
1648 // Remove old highlighting, if no new one is set
1649 if ( bParenthesisShown && !bFound && pTableView )
1651 sal_Int32 nCount = pEngine->GetParagraphCount();
1652 for (sal_Int32 i=0; i<nCount; i++)
1653 pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
1656 bParenthesisShown = bFound;
1659 void ScInputHandler::ViewShellGone(ScTabViewShell* pViewSh) // Executed synchronously!
1661 if ( pViewSh == pActiveViewSh )
1663 delete pLastState;
1664 pLastState = NULL;
1665 pLastPattern = NULL;
1668 if ( pViewSh == pRefViewSh )
1670 //! The input from the EnterHandler does not arrive anymore
1671 // We end the EditMode anyways
1672 EnterHandler();
1673 bFormulaMode = false;
1674 pRefViewSh = NULL;
1675 SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
1676 SC_MOD()->SetRefInputHdl(NULL);
1677 if (pInputWin)
1678 pInputWin->SetFormulaMode(false);
1679 UpdateAutoCorrFlag();
1682 pActiveViewSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
1684 if ( pActiveViewSh && pActiveViewSh == pViewSh )
1686 OSL_FAIL("pActiveViewSh is gone");
1687 pActiveViewSh = NULL;
1690 if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
1691 UpdateRefDevice(); // Don't keep old document's printer as RefDevice
1694 void ScInputHandler::UpdateActiveView()
1696 ImplCreateEditEngine();
1698 // #i20588# Don't rely on focus to find the active edit view. Instead, the
1699 // active pane at the start of editing is now stored (GetEditActivePart).
1700 // GetActiveWin (the currently active pane) fails for ref input across the
1701 // panes of a split view.
1703 Window* pShellWin = pActiveViewSh ?
1704 pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData()->GetEditActivePart() ) :
1705 NULL;
1707 sal_uInt16 nCount = pEngine->GetViewCount();
1708 if (nCount > 0)
1710 pTableView = pEngine->GetView(0);
1711 for (sal_uInt16 i=1; i<nCount; i++)
1713 EditView* pThis = pEngine->GetView(i);
1714 Window* pWin = pThis->GetWindow();
1715 if ( pWin==pShellWin )
1716 pTableView = pThis;
1719 else
1720 pTableView = NULL;
1722 if (pInputWin && eMode == SC_INPUT_TOP )
1723 pTopView = pInputWin->GetEditView();
1724 else
1725 pTopView = NULL;
1728 void ScInputHandler::StopInputWinEngine( bool bAll )
1730 if (pInputWin)
1731 pInputWin->StopEditEngine( bAll );
1733 pTopView = NULL; // invalid now
1736 EditView* ScInputHandler::GetActiveView()
1738 UpdateActiveView();
1739 return pTopView ? pTopView : pTableView;
1742 void ScInputHandler::ForgetLastPattern()
1744 pLastPattern = NULL;
1745 if ( !pLastState && pActiveViewSh )
1746 pActiveViewSh->UpdateInputHandler( true ); // Get status again
1747 else
1748 NotifyChange( pLastState, true );
1751 void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
1753 SvxAdjust eSvxAdjust;
1754 switch (eAttrAdjust)
1756 case SVX_HOR_JUSTIFY_STANDARD:
1758 bool bNumber = false;
1759 if (cTyped) // Restarted
1760 bNumber = (cTyped>='0' && cTyped<='9'); // Ony ciphers are numbers
1761 else if ( pActiveViewSh )
1763 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
1764 bNumber = ( pDoc->GetCellType( aCursorPos ) == CELLTYPE_VALUE );
1766 eSvxAdjust = bNumber ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
1768 break;
1769 case SVX_HOR_JUSTIFY_BLOCK:
1770 eSvxAdjust = SVX_ADJUST_BLOCK;
1771 break;
1772 case SVX_HOR_JUSTIFY_CENTER:
1773 eSvxAdjust = SVX_ADJUST_CENTER;
1774 break;
1775 case SVX_HOR_JUSTIFY_RIGHT:
1776 eSvxAdjust = SVX_ADJUST_RIGHT;
1777 break;
1778 default: // SVX_HOR_JUSTIFY_LEFT
1779 eSvxAdjust = SVX_ADJUST_LEFT;
1780 break;
1783 bool bAsianVertical = pLastPattern &&
1784 ((const SfxBoolItem&)pLastPattern->GetItem( ATTR_STACKED )).GetValue() &&
1785 ((const SfxBoolItem&)pLastPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
1786 if ( bAsianVertical )
1788 // Always edit at top of cell -> LEFT when editing vertically
1789 eSvxAdjust = SVX_ADJUST_LEFT;
1792 pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
1793 pEngine->SetDefaults( *pEditDefaults );
1795 nEditAdjust = sal::static_int_cast<sal_uInt16>(eSvxAdjust); //! set at ViewData or with PostEditView
1797 pEngine->SetVertical( bAsianVertical );
1800 void ScInputHandler::RemoveAdjust()
1802 // Delete hard alignement attributes
1803 bool bUndo = pEngine->IsUndoEnabled();
1804 if ( bUndo )
1805 pEngine->EnableUndo( false );
1807 // Non-default paragraph attributes (e.g. from clipboard)
1808 // must be turned into character attributes
1809 pEngine->RemoveParaAttribs();
1811 if ( bUndo )
1812 pEngine->EnableUndo( true );
1816 void ScInputHandler::RemoveRangeFinder()
1818 // Delete pRangeFindList and colors
1819 pEngine->SetUpdateMode(false);
1820 sal_Int32 nCount = pEngine->GetParagraphCount(); // Could just have been inserted
1821 for (sal_Int32 i=0; i<nCount; i++)
1822 pEngine->QuickRemoveCharAttribs( i, EE_CHAR_COLOR );
1823 pEngine->SetUpdateMode(true);
1825 EditView* pActiveView = pTopView ? pTopView : pTableView;
1826 pActiveView->ShowCursor( false, true );
1828 DeleteRangeFinder(); // Deletes the list and the labels on the table
1831 bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated )
1833 bool bNewTable = false;
1835 if (bModified || !ValidCol(aCursorPos.Col()))
1836 return false;
1838 if (pActiveViewSh)
1840 ImplCreateEditEngine();
1841 UpdateActiveView();
1842 SyncViews();
1844 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
1846 const ScMarkData& rMark = pActiveViewSh->GetViewData()->GetMarkData();
1847 ScEditableTester aTester;
1848 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
1849 aTester.TestSelection( pDoc, rMark );
1850 else
1851 aTester.TestSelectedBlock(
1852 pDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
1854 bool bStartInputMode = true;
1856 if (!aTester.IsEditable())
1858 bProtected = true;
1859 // We allow read-only input mode activation regardless
1860 // whether it's part of an array or not or whether explicit cell
1861 // activation is requested (double-click or F2) or a click in input
1862 // line.
1863 bool bShowError = (!bInputActivated || aTester.GetMessageId() != STR_PROTECTIONERR) &&
1864 !pActiveViewSh->GetViewData()->GetDocShell()->IsReadOnly();
1865 if (bShowError)
1867 eMode = SC_INPUT_NONE;
1868 StopInputWinEngine( true );
1869 UpdateFormulaMode();
1870 if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
1872 // Prevent repeated error messages for the same cell from command events
1873 // (for keyboard events, multiple messages are wanted).
1874 // Set the flag before showing the error message because the command handler
1875 // for the next IME command may be called when showing the dialog.
1876 if ( bFromCommand )
1877 bCommandErrorShown = true;
1879 pActiveViewSh->GetActiveWin()->GrabFocus();
1880 pActiveViewSh->ErrorMessage(aTester.GetMessageId());
1882 bStartInputMode = false;
1886 if (bStartInputMode)
1888 // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
1889 pEngine->SetUpdateMode( false );
1891 // Take over attributes in EditEngine
1892 const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(),
1893 aCursorPos.Row(),
1894 aCursorPos.Tab() );
1895 if (pPattern != pLastPattern)
1897 // Percent format?
1898 const SfxItemSet& rAttrSet = pPattern->GetItemSet();
1899 const SfxPoolItem* pItem;
1901 if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, true, &pItem ) )
1903 sal_uLong nFormat = ((const SfxUInt32Item*)pItem)->GetValue();
1904 bCellHasPercentFormat = ( NUMBERFORMAT_PERCENT ==
1905 pDoc->GetFormatTable()->GetType( nFormat ) );
1907 else
1908 bCellHasPercentFormat = false; // Default: no percent
1910 // Validity specified?
1911 if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALIDDATA, true, &pItem ) )
1912 nValidation = ((const SfxUInt32Item*)pItem)->GetValue();
1913 else
1914 nValidation = 0;
1916 // EditEngine Defaults
1917 // In no case SetParaAttribs, because the EditEngine might already
1918 // be filled (for Edit cells).
1919 // SetParaAttribs would change the content.
1921 //! The SetDefaults is now (since MUST/src602
1922 //! EditEngine changes) implemented as a SetParaAttribs.
1923 //! Any problems?
1925 pPattern->FillEditItemSet( pEditDefaults );
1926 pEngine->SetDefaults( *pEditDefaults );
1927 pLastPattern = pPattern;
1928 bLastIsSymbol = pPattern->IsSymbolFont();
1930 // Background color must be known for automatic font color.
1931 // For transparent cell background, the document background color must be used.
1933 Color aBackCol = ((const SvxBrushItem&)
1934 pPattern->GetItem( ATTR_BACKGROUND )).GetColor();
1935 ScModule* pScMod = SC_MOD();
1936 if ( aBackCol.GetTransparency() > 0 ||
1937 Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
1938 aBackCol.SetColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1939 pEngine->SetBackgroundColor( aBackCol );
1941 // Adjustment
1942 eAttrAdjust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1943 GetItem(ATTR_HOR_JUSTIFY)).GetValue();
1944 if ( eAttrAdjust == SVX_HOR_JUSTIFY_REPEAT &&
1945 static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() )
1947 // #i31843# "repeat" with "line breaks" is treated as default alignement
1948 eAttrAdjust = SVX_HOR_JUSTIFY_STANDARD;
1952 // UpdateSpellSettings enables online spelling if needed
1953 // -> also call if attributes are unchanged
1954 UpdateSpellSettings( true ); // uses pLastPattern
1956 // Fill EditEngine
1957 OUString aStr;
1958 if (bTextValid)
1960 pEngine->SetText(aCurrentText);
1961 aStr = aCurrentText;
1962 bTextValid = false;
1963 aCurrentText = OUString();
1965 else
1966 aStr = GetEditText(pEngine);
1968 if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
1970 aStr = aStr.copy(1, aStr.getLength() -2);
1971 pEngine->SetText(aStr);
1972 if ( pInputWin )
1973 pInputWin->SetTextString(aStr);
1976 UpdateAdjust( cTyped );
1978 if ( bAutoComplete )
1979 GetColData();
1981 if ( !aStr.isEmpty() && ( aStr[0] == '=' || aStr[0] == '+' || aStr[0] == '-' ) &&
1982 !cTyped && !bCreatingFuncView )
1983 InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
1985 bNewTable = true; // -> PostEditView Call
1989 if (!bProtected && pInputWin)
1990 pInputWin->SetOkCancelMode();
1992 return bNewTable;
1995 static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
1997 OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
1999 EditEngine* pEngine = pEditView->GetEditEngine();
2000 sal_Int32 nCount = pEngine->GetParagraphCount();
2001 if (nCount > 1)
2003 sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
2004 while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
2006 rSel.nStartPos -= nParLen + 1; // Including space from line break
2007 nParLen = pEngine->GetTextLen(++rSel.nStartPara);
2010 nParLen = pEngine->GetTextLen(rSel.nEndPara);
2011 while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
2013 rSel.nEndPos -= nParLen + 1; // Including space from line break
2014 nParLen = pEngine->GetTextLen(++rSel.nEndPara);
2018 ESelection aSel = pEditView->GetSelection();
2020 if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
2021 || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
2022 pEditView->SetSelection( rSel );
2025 void ScInputHandler::SyncViews( EditView* pSourceView )
2027 if (pSourceView)
2029 bool bSelectionForTopView = false;
2030 if (pTopView && pTopView != pSourceView)
2031 bSelectionForTopView = true;
2032 bool bSelectionForTableView = false;
2033 if (pTableView && pTableView != pSourceView)
2034 bSelectionForTableView = true;
2035 if (bSelectionForTopView || bSelectionForTableView)
2037 ESelection aSel(pSourceView->GetSelection());
2038 if (bSelectionForTopView)
2039 pTopView->SetSelection(aSel);
2040 if (bSelectionForTableView)
2041 lcl_SetTopSelection(pTableView, aSel);
2044 // Only sync selection from topView if we are actually editiing there
2045 else if (pTopView && pTableView)
2047 ESelection aSel(pTopView->GetSelection());
2048 lcl_SetTopSelection( pTableView, aSel );
2052 IMPL_LINK_NOARG(ScInputHandler, ModifyHdl)
2054 if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
2055 pEngine && pEngine->GetUpdateMode() && pInputWin )
2057 // Update input line from ModifyHdl for changes that are not
2058 // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
2059 OUString aText;
2060 if ( pInputWin->IsMultiLineInput() )
2061 aText = ScEditUtil::GetMultilineString(*pEngine);
2062 else
2063 aText = GetEditText(pEngine);
2064 lcl_RemoveTabs(aText);
2065 pInputWin->SetTextString(aText);
2067 return 0;
2071 * @return true means new view created
2073 bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
2075 if (pActiveViewSh)
2076 pActiveViewSh->GetViewData()->SetPasteMode( SC_PASTE_NONE );
2077 bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
2079 if ( eMode == SC_INPUT_NONE )
2080 return StartTable( cTyped, bFromCommand, false );
2081 else
2082 return false;
2085 void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
2087 ImplCreateEditEngine();
2089 if (eMode==SC_INPUT_NONE)
2090 eMode = SC_INPUT_TYPE;
2092 if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
2094 // table EditEngine is formatted below, input line needs formatting after paste
2095 // #i20282# not when called from the input line's modify handler
2096 pTopView->GetEditEngine()->QuickFormatDoc( true );
2098 // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
2099 // can't safely access the EditEngine's current view, so the cursor has to be
2100 // shown again here.
2101 pTopView->ShowCursor();
2104 if (bSetModified)
2105 bModified = true;
2106 bSelIsRef = false;
2108 if ( pRangeFindList && !bInRangeUpdate )
2109 RemoveRangeFinder(); // Delete attributes and labels
2111 UpdateParenthesis(); // Highlight parentheses anew
2113 if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
2115 OUString aText;
2116 if ( pInputWin && pInputWin->IsMultiLineInput() )
2117 aText = ScEditUtil::GetMultilineString(*pEngine);
2118 else
2119 aText = GetEditText(pEngine);
2120 lcl_RemoveTabs(aText);
2122 if ( pInputWin )
2123 pInputWin->SetTextString( aText );
2126 // If the cursor is before the end of a paragraph, parts are being pushed to
2127 // the right (independently from the eMode) -> Adapt View!
2128 // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
2130 // First make sure the status handler is called now if the cursor
2131 // is outside the visible area
2132 pEngine->QuickFormatDoc();
2134 EditView* pActiveView = pTopView ? pTopView : pTableView;
2135 if (pActiveView && pActiveViewSh)
2137 ScViewData* pViewData = pActiveViewSh->GetViewData();
2139 bool bNeedGrow = ( nEditAdjust != SVX_ADJUST_LEFT ); // Always right-aligned
2140 if (!bNeedGrow)
2142 // Cursor before the end?
2143 ESelection aSel = pActiveView->GetSelection();
2144 aSel.Adjust();
2145 bNeedGrow = ( aSel.nEndPos != pEngine->GetTextLen(aSel.nEndPara) );
2147 if (!bNeedGrow)
2149 bNeedGrow = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
2151 if (bNeedGrow)
2153 // Adjust inplace view
2154 pViewData->EditGrowY();
2155 pViewData->EditGrowX();
2159 UpdateFormulaMode();
2160 bTextValid = false; // Changes only in the EditEngine
2161 bInOwnChange = false;
2164 void ScInputHandler::UpdateFormulaMode()
2166 SfxApplication* pSfxApp = SFX_APP();
2168 bool bIsFormula = !bProtected && pEngine->GetParagraphCount() == 1;
2169 if (bIsFormula)
2171 const OUString& rText = pEngine->GetText(0);
2172 bIsFormula = !rText.isEmpty() &&
2173 (rText[0] == '=' || rText[0] == '+' || rText[0] == '-');
2176 if ( bIsFormula )
2178 if (!bFormulaMode)
2180 bFormulaMode = true;
2181 pRefViewSh = pActiveViewSh;
2182 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2183 SC_MOD()->SetRefInputHdl(this);
2184 if (pInputWin)
2185 pInputWin->SetFormulaMode(true);
2187 if ( bAutoComplete )
2188 GetFormulaData();
2190 UpdateParenthesis();
2191 UpdateAutoCorrFlag();
2194 else // Deactivate
2196 if (bFormulaMode)
2198 ShowRefFrame();
2199 bFormulaMode = false;
2200 pRefViewSh = NULL;
2201 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2202 SC_MOD()->SetRefInputHdl(NULL);
2203 if (pInputWin)
2204 pInputWin->SetFormulaMode(false);
2205 UpdateAutoCorrFlag();
2210 void ScInputHandler::ShowRefFrame()
2212 // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
2213 // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
2214 // A local variable is used instead.
2215 ScTabViewShell* pVisibleSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
2216 if ( pRefViewSh && pRefViewSh != pVisibleSh )
2218 bool bFound = false;
2219 SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
2220 SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
2221 while ( pOneFrame && !bFound )
2223 if ( pOneFrame == pRefFrame )
2224 bFound = true;
2225 pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
2228 if (bFound)
2230 // We count on Activate working synchronously here
2231 // (pActiveViewSh is set while doing so)
2232 pRefViewSh->SetActive(); // Appear and SetViewFrame
2234 // pLastState is set correctly in the NotifyChange from the Activate
2236 else
2238 OSL_FAIL("ViewFrame for reference input is not here anymore");
2243 void ScInputHandler::RemoveSelection()
2245 EditView* pActiveView = pTopView ? pTopView : pTableView;
2246 if (!pActiveView)
2247 return;
2249 ESelection aSel = pActiveView->GetSelection();
2250 aSel.nStartPara = aSel.nEndPara;
2251 aSel.nStartPos = aSel.nEndPos;
2252 if (pTableView)
2253 pTableView->SetSelection( aSel );
2254 if (pTopView)
2255 pTopView->SetSelection( aSel );
2258 void ScInputHandler::InvalidateAttribs()
2260 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
2261 if (pViewFrm)
2263 SfxBindings& rBindings = pViewFrm->GetBindings();
2265 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2266 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2267 rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
2269 rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
2270 rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
2271 rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
2272 rBindings.Invalidate( SID_ULINE_VAL_NONE );
2273 rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
2274 rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
2275 rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
2277 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2279 rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
2280 rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
2281 rBindings.Invalidate( SID_SET_SUB_SCRIPT );
2282 rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
2283 rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
2288 // --------------- public methods --------------------------------------------
2291 void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText )
2293 if ( eMode == eNewMode )
2294 return;
2296 ImplCreateEditEngine();
2298 if (bProtected)
2300 eMode = SC_INPUT_NONE;
2301 StopInputWinEngine( true );
2302 if (pActiveViewSh)
2303 pActiveViewSh->GetActiveWin()->GrabFocus();
2304 return;
2307 if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
2308 // Disable paste mode when edit mode starts.
2309 pActiveViewSh->GetViewData()->SetPasteMode( SC_PASTE_NONE );
2311 bInOwnChange = true; // disable ModifyHdl (reset below)
2313 ScInputMode eOldMode = eMode;
2314 eMode = eNewMode;
2315 if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
2316 StopInputWinEngine( false );
2318 if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
2320 if (eOldMode == SC_INPUT_NONE) // not if switching between modes
2322 if (StartTable(0, false, eMode == SC_INPUT_TABLE))
2324 if (pActiveViewSh)
2325 pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
2329 if (pInitText)
2331 pEngine->SetText(*pInitText);
2332 bModified = true;
2335 sal_Int32 nPara = pEngine->GetParagraphCount()-1;
2336 sal_Int32 nLen = pEngine->GetText(nPara).getLength();
2337 sal_uInt16 nCount = pEngine->GetViewCount();
2339 for (sal_uInt16 i=0; i<nCount; i++)
2341 if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
2343 // Keep Selection
2345 else
2347 pEngine->GetView(i)->
2348 SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
2350 pEngine->GetView(i)->ShowCursor(false);
2354 UpdateActiveView();
2355 if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
2357 if (pTableView)
2358 pTableView->SetEditEngineUpdateMode(true);
2360 else
2362 if (pTopView)
2363 pTopView->SetEditEngineUpdateMode(true);
2366 if (eNewMode != eOldMode)
2367 UpdateFormulaMode();
2369 bInOwnChange = false;
2373 * @return true if rString only contains digits (no autocorrect then)
2375 static bool lcl_IsNumber(const OUString& rString)
2377 sal_Int32 nLen = rString.getLength();
2378 for (sal_Int32 i=0; i<nLen; i++)
2380 sal_Unicode c = rString[i];
2381 if ( c < '0' || c > '9' )
2382 return false;
2384 return true;
2387 static void lcl_SelectionToEnd( EditView* pView )
2389 if ( pView )
2391 EditEngine* pEngine = pView->GetEditEngine();
2392 sal_Int32 nParCnt = pEngine->GetParagraphCount();
2393 if ( nParCnt == 0 )
2394 nParCnt = 1;
2395 ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
2396 pView->SetSelection( aSel );
2400 void ScInputHandler::EnterHandler( sal_uInt8 nBlockMode )
2402 // Macro calls for validity can cause a lot of problems, so inhibit
2403 // nested calls of EnterHandler().
2404 if (bInEnterHandler) return;
2405 bInEnterHandler = true;
2406 bInOwnChange = true; // disable ModifyHdl (reset below)
2408 ImplCreateEditEngine();
2410 bool bMatrix = ( nBlockMode == SC_ENTER_MATRIX );
2412 SfxApplication* pSfxApp = SFX_APP();
2413 EditTextObject* pObject = NULL;
2414 ScPatternAttr* pCellAttrs = NULL;
2415 bool bForget = false; // Remove due to validity?
2417 OUString aString = GetEditText(pEngine);
2418 EditView* pActiveView = pTopView ? pTopView : pTableView;
2419 if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
2421 if (pColumnData && miAutoPosColumn != pColumnData->end())
2423 // #i47125# If AutoInput appended something, do the final AutoCorrect
2424 // with the cursor at the end of the input.
2425 lcl_SelectionToEnd(pTopView);
2426 lcl_SelectionToEnd(pTableView);
2429 Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
2431 if (pTopView)
2432 pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
2433 if (pTableView)
2434 pTableView->CompleteAutoCorrect(pFrameWin);
2435 aString = GetEditText(pEngine);
2437 lcl_RemoveTabs(aString);
2439 // Test if valid (always with simple string)
2440 if ( bModified && nValidation && pActiveViewSh )
2442 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
2443 const ScValidationData* pData = pDoc->GetValidationEntry( nValidation );
2444 if (pData && pData->HasErrMsg())
2446 // #i67990# don't use pLastPattern in EnterHandler
2447 const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2448 bool bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
2450 if (!bOk)
2452 if ( pActiveViewSh ) // If it came from MouseButtonDown
2453 pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
2455 //FIXME: We still run into problems if the input is triggered by activating another View
2456 Window* pParent = Application::GetDefDialogParent();
2457 if ( pData->DoError( pParent, aString, aCursorPos ) )
2458 bForget = true; // Do not take over input
2463 // Check for input into DataPilot table
2464 if ( bModified && pActiveViewSh && !bForget )
2466 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
2467 ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2468 if ( pDPObj )
2470 // Any input within the DataPilot table is either a valid renaming
2471 // or an invalid action - normal cell input is always aborted
2472 pActiveViewSh->DataPilotInput( aCursorPos, aString );
2473 bForget = true;
2477 std::vector<editeng::MisspellRanges> aMisspellRanges;
2478 pEngine->CompleteOnlineSpelling();
2479 bool bSpellErrors = !bFormulaMode && pEngine->HasOnlineSpellErrors();
2480 if ( bSpellErrors )
2482 // #i3820# If the spell checker flags numerical input as error,
2483 // it still has to be treated as number, not EditEngine object.
2484 if ( pActiveViewSh )
2486 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
2487 // #i67990# don't use pLastPattern in EnterHandler
2488 const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
2489 if (pPattern)
2491 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
2492 // without conditional format, as in ScColumn::SetString
2493 sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
2494 double nVal;
2495 if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
2497 bSpellErrors = false; // ignore the spelling errors
2503 // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
2504 // SetUpdateMode must come after CompleteOnlineSpelling.
2505 // The view is hidden in any case below (Broadcast).
2506 pEngine->SetUpdateMode( false );
2508 if ( bModified && !bForget ) // What is being entered (text/object)?
2510 sal_Int32 nParCnt = pEngine->GetParagraphCount();
2511 if ( nParCnt == 0 )
2512 nParCnt = 1;
2514 bool bUniformAttribs = true;
2515 SfxItemSet aPara1Attribs = pEngine->GetAttribs(0, 0, pEngine->GetTextLen(0));
2516 for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
2518 SfxItemSet aPara2Attribs = pEngine->GetAttribs(nPara, 0, pEngine->GetTextLen(nPara));
2519 if (!(aPara1Attribs == aPara2Attribs))
2521 // Paragraph format different from that of the 1st paragraph.
2522 bUniformAttribs = false;
2523 break;
2527 ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
2528 SfxItemSet aOldAttribs = pEngine->GetAttribs( aSel );
2529 const SfxPoolItem* pItem = NULL;
2531 // Find common (cell) attributes before RemoveAdjust
2532 if ( pActiveViewSh && bUniformAttribs )
2534 SfxItemSet* pCommonAttrs = NULL;
2535 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
2537 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2538 if ( eState == SFX_ITEM_SET &&
2539 nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
2540 nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
2541 *pItem != pEditDefaults->Get(nId) )
2543 if ( !pCommonAttrs )
2544 pCommonAttrs = new SfxItemSet( pEngine->GetEmptyItemSet() );
2545 pCommonAttrs->Put( *pItem );
2549 if ( pCommonAttrs )
2551 ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
2552 pCellAttrs = new ScPatternAttr( pDoc->GetPool() );
2553 pCellAttrs->GetFromEditItemSet( pCommonAttrs );
2554 delete pCommonAttrs;
2558 // Clear ParaAttribs (including adjustment)
2559 RemoveAdjust();
2561 bool bAttrib = false; // Formatting present?
2563 // check if EditObject is needed
2564 if (nParCnt > 1)
2565 bAttrib = true;
2566 else
2568 for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
2570 SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
2571 if (eState == SFX_ITEM_DONTCARE)
2572 bAttrib = true;
2573 else if (eState == SFX_ITEM_SET)
2575 // Keep same items in EditEngine as in ScEditAttrTester
2576 if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
2577 nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
2579 if ( *pItem != pEditDefaults->Get(nId) )
2580 bAttrib = true;
2585 // Contains fields?
2586 SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
2587 if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
2588 bAttrib = true;
2590 // Not converted characters?
2591 SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
2592 if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET )
2593 bAttrib = true;
2595 // Always recognize formulas as formulas
2596 // We still need the preceding test due to cell attributes
2599 if (bSpellErrors)
2600 pEngine->GetAllMisspellRanges(aMisspellRanges);
2602 if (bMatrix)
2603 bAttrib = false;
2605 if (bAttrib)
2607 pEngine->ClearSpellErrors();
2608 pObject = pEngine->CreateTextObject();
2610 else if (bAutoComplete) // Adjust Upper/Lower case
2612 // Perform case-matching only when the typed text is partial.
2613 if (pColumnData && aAutoSearch.getLength() < aString.getLength())
2614 aString = getExactMatch(*pColumnData, aString);
2618 // Don't rely on ShowRefFrame switching the active view synchronously
2619 // execute the function directly on the correct view's bindings instead
2620 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2621 ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2623 if (bFormulaMode)
2625 ShowRefFrame();
2627 if (pExecuteSh)
2629 pExecuteSh->SetTabNo(aCursorPos.Tab());
2630 pExecuteSh->ActiveGrabFocus();
2633 bFormulaMode = false;
2634 pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2635 SC_MOD()->SetRefInputHdl(NULL);
2636 if (pInputWin)
2637 pInputWin->SetFormulaMode(false);
2638 UpdateAutoCorrFlag();
2640 pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2641 DeleteRangeFinder();
2642 ResetAutoPar();
2644 bool bOldMod = bModified;
2646 bModified = false;
2647 bSelIsRef = false;
2648 eMode = SC_INPUT_NONE;
2649 StopInputWinEngine(true);
2651 // Text input (through number formats) or ApplySelectionPattern modify
2652 // the cell's attributes, so pLastPattern is no longer valid
2653 pLastPattern = NULL;
2655 if (bOldMod && !bProtected && !bForget)
2657 // No typographic quotes in formulas
2658 if (aString.startsWith("="))
2660 SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get().GetAutoCorrect();
2661 if ( pAuto )
2663 OUString aReplace(pAuto->GetStartDoubleQuote());
2664 if( aReplace.isEmpty() )
2665 aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkStart();
2666 if( aReplace != "\"" )
2667 aString = aString.replaceAll( aReplace, "\"" );
2669 aReplace = OUString(pAuto->GetEndDoubleQuote());
2670 if( aReplace.isEmpty() )
2671 aReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkEnd();
2672 if( aReplace != "\"" )
2673 aString = aString.replaceAll( aReplace, "\"" );
2675 aReplace = OUString(pAuto->GetStartSingleQuote());
2676 if( aReplace.isEmpty() )
2677 aReplace = ScGlobal::pLocaleData->getQuotationMarkStart();
2678 if( aReplace != "'" )
2679 aString = aString.replaceAll( aReplace, "'" );
2681 aReplace = OUString(pAuto->GetEndSingleQuote());
2682 if( aReplace.isEmpty() )
2683 aReplace = ScGlobal::pLocaleData->getQuotationMarkEnd();
2684 if( aReplace != "'" )
2685 aString = aString.replaceAll( aReplace, "'");
2689 pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT ) );
2691 if ( pExecuteSh )
2693 SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
2695 sal_uInt16 nId = FID_INPUTLINE_ENTER;
2696 if ( nBlockMode == SC_ENTER_BLOCK )
2697 nId = FID_INPUTLINE_BLOCK;
2698 else if ( nBlockMode == SC_ENTER_MATRIX )
2699 nId = FID_INPUTLINE_MATRIX;
2701 ScInputStatusItem aItem( FID_INPUTLINE_STATUS,
2702 aCursorPos, aCursorPos, aCursorPos,
2703 aString, pObject );
2705 if (!aMisspellRanges.empty())
2706 aItem.SetMisspellRanges(&aMisspellRanges);
2708 const SfxPoolItem* aArgs[2];
2709 aArgs[0] = &aItem;
2710 aArgs[1] = NULL;
2711 rBindings.Execute( nId, aArgs );
2714 delete pLastState; // pLastState still contains the old text
2715 pLastState = NULL;
2717 else
2718 pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
2720 if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
2722 // Combine with input?
2723 pExecuteSh->ApplySelectionPattern( *pCellAttrs, true, true );
2724 pExecuteSh->AdjustBlockHeight();
2727 delete pCellAttrs;
2728 delete pObject;
2730 HideTip();
2731 HideTipBelow();
2733 nFormSelStart = nFormSelEnd = 0;
2734 aFormText = OUString();
2736 bInOwnChange = false;
2737 bInEnterHandler = false;
2740 void ScInputHandler::CancelHandler()
2742 bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
2744 ImplCreateEditEngine();
2746 bModified = false;
2748 // Don't rely on ShowRefFrame switching the active view synchronously
2749 // execute the function directly on the correct view's bindings instead
2750 // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
2751 ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
2753 if (bFormulaMode)
2755 ShowRefFrame();
2756 if (pExecuteSh)
2758 pExecuteSh->SetTabNo(aCursorPos.Tab());
2759 pExecuteSh->ActiveGrabFocus();
2761 bFormulaMode = false;
2762 SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
2763 SC_MOD()->SetRefInputHdl(NULL);
2764 if (pInputWin)
2765 pInputWin->SetFormulaMode(false);
2766 UpdateAutoCorrFlag();
2768 pRefViewSh = NULL; // Also without FormulaMode due to FunctionsAutoPilot
2769 DeleteRangeFinder();
2770 ResetAutoPar();
2772 eMode = SC_INPUT_NONE;
2773 StopInputWinEngine( true );
2774 if (pExecuteSh)
2775 pExecuteSh->StopEditShell();
2777 aCursorPos.Set(MAXCOL+1,0,0); // Invalid flag
2778 pEngine->SetText(OUString());
2780 if ( !pLastState && pExecuteSh )
2781 pExecuteSh->UpdateInputHandler( true ); // Update status again
2782 else
2783 NotifyChange( pLastState, true );
2785 nFormSelStart = nFormSelEnd = 0;
2786 aFormText = OUString();
2788 bInOwnChange = false;
2791 bool ScInputHandler::IsModalMode( SfxObjectShell* pDocSh )
2793 // References to unnamed document; that doesn't work
2794 return bFormulaMode && pRefViewSh
2795 && pRefViewSh->GetViewData()->GetDocument()->GetDocumentShell() != pDocSh
2796 && !pDocSh->HasName();
2799 void ScInputHandler::AddRefEntry()
2801 const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
2802 UpdateActiveView();
2803 if (!pTableView && !pTopView)
2804 return; // E.g. FillMode
2806 DataChanging(); // Cannot be new
2808 RemoveSelection();
2809 if (pTableView)
2810 pTableView->InsertText( OUString(cSep), false );
2811 if (pTopView)
2812 pTopView->InsertText( OUString(cSep), false );
2814 DataChanged();
2817 void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc )
2819 HideTip();
2821 bool bOtherDoc = ( pRefViewSh &&
2822 pRefViewSh->GetViewData()->GetDocument() != pDoc );
2823 if (bOtherDoc)
2824 if (!pDoc->GetDocumentShell()->HasName())
2826 // References to unnamed document; that doesn't work
2827 // SetReference should not be called, then
2828 return;
2831 UpdateActiveView();
2832 if (!pTableView && !pTopView)
2833 return; // E.g. FillMode
2835 // Never overwrite the "="!
2836 EditView* pActiveView = pTopView ? pTopView : pTableView;
2837 ESelection aSel = pActiveView->GetSelection();
2838 aSel.Adjust();
2839 if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
2840 return;
2842 DataChanging(); // Cannot be new
2844 // Turn around selection if backwards (TODO: Do we really need to do that?)
2845 if (pTableView)
2847 ESelection aTabSel = pTableView->GetSelection();
2848 if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
2850 aTabSel.Adjust();
2851 pTableView->SetSelection(aTabSel);
2854 if (pTopView)
2856 ESelection aTopSel = pTopView->GetSelection();
2857 if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
2859 aTopSel.Adjust();
2860 pTopView->SetSelection(aTopSel);
2864 // Create string from reference
2865 OUString aRefStr;
2866 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
2867 if (bOtherDoc)
2869 // Reference to other document
2870 OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
2872 OUString aTmp(rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails)); // Always 3D
2874 SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
2875 // #i75893# convert escaped URL of the document to something user friendly
2876 OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );
2878 switch(aAddrDetails.eConv)
2880 case formula::FormulaGrammar::CONV_XL_A1 :
2881 case formula::FormulaGrammar::CONV_XL_OOX :
2882 case formula::FormulaGrammar::CONV_XL_R1C1 :
2883 aRefStr = "[\'";
2884 aRefStr += aFileName;
2885 aRefStr += "']";
2886 break;
2887 case formula::FormulaGrammar::CONV_OOO :
2888 default:
2889 aRefStr = "\'";
2890 aRefStr += aFileName;
2891 aRefStr += "'#";
2892 break;
2894 aRefStr += aTmp;
2896 else
2898 if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
2899 rRef.aStart.Tab() != rRef.aEnd.Tab() )
2900 aRefStr = rRef.Format(SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails);
2901 else
2902 aRefStr = rRef.Format(SCA_VALID, pDoc, aAddrDetails);
2905 if (pTableView || pTopView)
2907 if (pTableView)
2908 pTableView->InsertText( aRefStr, true );
2909 if (pTopView)
2910 pTopView->InsertText( aRefStr, true );
2912 DataChanged();
2915 bSelIsRef = true;
2918 void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
2920 if ( eMode == SC_INPUT_NONE )
2922 OSL_FAIL("InsertFunction, nicht im Eingabemodus");
2923 return;
2926 UpdateActiveView();
2927 if (!pTableView && !pTopView)
2928 return; // E.g. FillMode
2930 DataChanging(); // Cannot be new
2932 OUString aText = rFuncName;
2933 if (bAddPar)
2934 aText += "()";
2936 if (pTableView)
2938 pTableView->InsertText( aText, false );
2939 if (bAddPar)
2941 ESelection aSel = pTableView->GetSelection();
2942 --aSel.nStartPos;
2943 --aSel.nEndPos;
2944 pTableView->SetSelection(aSel);
2947 if (pTopView)
2949 pTopView->InsertText( aText, false );
2950 if (bAddPar)
2952 ESelection aSel = pTopView->GetSelection();
2953 --aSel.nStartPos;
2954 --aSel.nEndPos;
2955 pTopView->SetSelection(aSel);
2959 DataChanged();
2961 if (bAddPar)
2962 AutoParAdded();
2965 void ScInputHandler::ClearText()
2967 if ( eMode == SC_INPUT_NONE )
2969 OSL_FAIL("ClearText, nicht im Eingabemodus");
2970 return;
2973 UpdateActiveView();
2974 if (!pTableView && !pTopView)
2975 return; // E.g. FillMode
2977 DataChanging(); // Cannot be new
2979 OUString aEmpty;
2980 if (pTableView)
2982 pTableView->GetEditEngine()->SetText( aEmpty );
2983 pTableView->SetSelection( ESelection(0,0, 0,0) );
2985 if (pTopView)
2987 pTopView->GetEditEngine()->SetText( aEmpty );
2988 pTopView->SetSelection( ESelection(0,0, 0,0) );
2991 DataChanged();
2994 bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
2996 if (!bOptLoaded)
2998 bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
2999 bOptLoaded = true;
3002 KeyCode aCode = rKEvt.GetKeyCode();
3003 sal_uInt16 nModi = aCode.GetModifier();
3004 bool bShift = aCode.IsShift();
3005 bool bControl = aCode.IsMod1();
3006 bool bAlt = aCode.IsMod2();
3007 sal_uInt16 nCode = aCode.GetCode();
3008 sal_Unicode nChar = rKEvt.GetCharCode();
3010 if (bAlt && !bControl && nCode != KEY_RETURN)
3011 // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
3012 return false;
3014 if (!bControl && nCode == KEY_TAB)
3016 // Normal TAB moves the cursor right.
3017 EnterHandler();
3019 if (pActiveViewSh)
3020 pActiveViewSh->FindNextUnprot( bShift );
3021 return true;
3024 bool bInputLine = ( eMode==SC_INPUT_TOP );
3026 bool bUsed = false;
3027 bool bSkip = false;
3028 bool bDoEnter = false;
3030 switch ( nCode )
3032 case KEY_RETURN:
3033 if (bControl && !bShift && ( !bInputLine || ( pInputWin && pInputWin->IsMultiLineInput() ) ) )
3034 bDoEnter = true;
3035 else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
3037 PasteFunctionData();
3038 bUsed = true;
3040 else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
3042 PasteManualTip();
3043 bUsed = true;
3045 else
3047 sal_uInt8 nMode = SC_ENTER_NORMAL;
3048 if ( bShift && bControl )
3049 nMode = SC_ENTER_MATRIX;
3050 else if ( bAlt )
3051 nMode = SC_ENTER_BLOCK;
3052 EnterHandler( nMode );
3054 if (pActiveViewSh)
3055 pActiveViewSh->MoveCursorEnter( bShift && !bControl );
3057 bUsed = true;
3059 break;
3060 case KEY_TAB:
3061 if (bControl && !bAlt)
3063 if (pFormulaData && nTipVisible && miAutoPosFormula != pFormulaData->end())
3065 // Iterate
3066 NextFormulaEntry( bShift );
3067 bUsed = true;
3069 else if (pColumnData && bUseTab && miAutoPosColumn != pColumnData->end())
3071 // Iterate through AutoInput entries
3072 NextAutoEntry( bShift );
3073 bUsed = true;
3076 break;
3077 case KEY_ESCAPE:
3078 if ( nTipVisible )
3080 HideTip();
3081 bUsed = true;
3083 else if( nTipVisibleSec )
3085 HideTipBelow();
3086 bUsed = true;
3088 else if (eMode != SC_INPUT_NONE)
3090 CancelHandler();
3091 bUsed = true;
3093 else
3094 bSkip = true;
3095 break;
3096 case KEY_F2:
3097 if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
3099 eMode = SC_INPUT_TYPE;
3100 bUsed = true;
3102 break;
3105 // Only execute cursor keys if already in EditMode
3106 // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
3107 bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
3108 bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
3109 if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
3110 ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
3112 HideTip();
3113 HideTipBelow();
3115 if (bSelIsRef)
3117 RemoveSelection();
3118 bSelIsRef = false;
3121 UpdateActiveView();
3122 bool bNewView = DataChanging( nChar );
3124 if (bProtected) // Protected cell?
3125 bUsed = true; // Don't forward KeyEvent
3126 else // Changes allowed
3128 if (bNewView ) // Create anew
3130 if (pActiveViewSh)
3131 pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
3132 UpdateActiveView();
3133 if (eMode==SC_INPUT_NONE)
3134 if (pTableView || pTopView)
3136 OUString aStrLoP;
3138 if ( bStartEdit && bCellHasPercentFormat && ((nChar >= '0' && nChar <= '9') || nChar == '-') )
3139 aStrLoP = "%";
3141 if (pTableView)
3143 pTableView->GetEditEngine()->SetText( aStrLoP );
3144 if ( !aStrLoP.isEmpty() )
3145 pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3147 // Don't call SetSelection if the string is empty anyway,
3148 // to avoid breaking the bInitial handling in ScViewData::EditGrowY
3150 if (pTopView)
3152 pTopView->GetEditEngine()->SetText( aStrLoP );
3153 if ( !aStrLoP.isEmpty() )
3154 pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
3157 SyncViews();
3160 if (pTableView || pTopView)
3162 if (bDoEnter)
3164 if (pTableView)
3165 if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
3166 bUsed = true;
3167 if (pTopView)
3168 if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
3169 bUsed = true;
3171 else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
3173 SkipClosingPar();
3174 bUsed = true;
3176 else
3178 if (pTableView)
3180 Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : NULL;
3181 if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
3182 bUsed = true;
3184 if (pTopView)
3185 if ( pTopView->PostKeyEvent( rKEvt ) )
3186 bUsed = true;
3189 // AutoInput:
3190 if ( bUsed && bAutoComplete )
3192 bUseTab = false;
3193 if (pFormulaData)
3194 miAutoPosFormula = pFormulaData->end(); // do not search further
3195 if (pColumnData)
3196 miAutoPosColumn = pColumnData->end();
3198 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
3199 if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
3200 KEYFUNC_CUT != eFunc) // and no 'CTRL-X'
3202 if (bFormulaMode)
3203 UseFormulaData();
3204 else
3205 UseColData();
3209 // When the selection is changed manually or an opening parenthesis
3210 // is typed, stop overwriting parentheses
3211 if ( bUsed && nChar == '(' )
3212 ResetAutoPar();
3214 if ( KEY_INSERT == nCode )
3216 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3217 if (pViewFrm)
3218 pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
3220 if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
3222 ShowTipCursor();
3226 // #i114511# don't count cursor keys as modification
3227 bool bSetModified = !bCursorKey;
3228 DataChanged(false, bSetModified); // also calls UpdateParenthesis()
3229 InvalidateAttribs(); //! in DataChanged?
3233 if (pTopView && eMode != SC_INPUT_NONE)
3234 SyncViews();
3236 return bUsed;
3239 bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, bool bForce )
3241 bool bUsed = false;
3243 if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
3245 // For COMMAND_CURSORPOS, do as little as possible, because
3246 // with remote VCL, even a ShowCursor will generate another event.
3247 if ( eMode != SC_INPUT_NONE )
3249 UpdateActiveView();
3250 if (pTableView || pTopView)
3252 if (pTableView)
3253 pTableView->Command( rCEvt );
3254 else if (pTopView) // call only once
3255 pTopView->Command( rCEvt );
3256 bUsed = true;
3260 else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION )
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
3277 if ( bForce || eMode != SC_INPUT_NONE )
3279 if (!bOptLoaded)
3281 bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
3282 bOptLoaded = true;
3285 HideTip();
3286 HideTipBelow();
3288 if ( bSelIsRef )
3290 RemoveSelection();
3291 bSelIsRef = false;
3294 UpdateActiveView();
3295 bool bNewView = DataChanging( 0, true );
3297 if (bProtected) // cell protected
3298 bUsed = true; // event is used
3299 else // changes allowed
3301 if (bNewView) // create new edit view
3303 if (pActiveViewSh)
3304 pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
3305 UpdateActiveView();
3306 if (eMode==SC_INPUT_NONE)
3307 if (pTableView || pTopView)
3309 OUString aStrLoP;
3310 if (pTableView)
3312 pTableView->GetEditEngine()->SetText( aStrLoP );
3313 pTableView->SetSelection( ESelection(0,0, 0,0) );
3315 if (pTopView)
3317 pTopView->GetEditEngine()->SetText( aStrLoP );
3318 pTopView->SetSelection( ESelection(0,0, 0,0) );
3321 SyncViews();
3324 if (pTableView || pTopView)
3326 if (pTableView)
3327 pTableView->Command( rCEvt );
3328 if (pTopView)
3329 pTopView->Command( rCEvt );
3331 bUsed = true;
3333 if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
3335 // AutoInput after ext text input
3337 if (pFormulaData)
3338 miAutoPosFormula = pFormulaData->end();
3339 if (pColumnData)
3340 miAutoPosColumn = pColumnData->end();
3342 if (bFormulaMode)
3343 UseFormulaData();
3344 else
3345 UseColData();
3349 DataChanged(); // calls UpdateParenthesis()
3350 InvalidateAttribs(); //! in DataChanged ?
3354 if (pTopView && eMode != SC_INPUT_NONE)
3355 SyncViews();
3358 return bUsed;
3361 void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
3362 bool bForce, ScTabViewShell* pSourceSh,
3363 bool bStopEditing)
3365 // If the call originates from a macro call in the EnterHandler,
3366 // return immediately and don't mess up the status
3367 if (bInEnterHandler)
3368 return;
3370 bool bRepeat = (pState == pLastState);
3371 if (!bRepeat && pState && pLastState)
3372 bRepeat = (*pState == *pLastState);
3373 if (bRepeat && !bForce)
3374 return;
3376 bInOwnChange = true; // disable ModifyHdl (reset below)
3378 if ( pState && !pLastState ) // Enable again
3379 bForce = true;
3381 bool bHadObject = pLastState && pLastState->GetEditData();
3383 //! Before EditEngine gets eventually created (so it gets the right pools)
3384 if ( pSourceSh )
3385 pActiveViewSh = pSourceSh;
3386 else
3387 pActiveViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current());
3389 ImplCreateEditEngine();
3391 if ( pState != pLastState )
3393 delete pLastState;
3394 pLastState = pState ? new ScInputHdlState( *pState ) : NULL;
3397 if ( pState && pActiveViewSh )
3399 ScModule* pScMod = SC_MOD();
3401 if ( pState )
3404 // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
3405 // FormEditData, if we're switching from Help to Calc:
3406 if ( !bFormulaMode && !pScMod->IsFormulaMode() && !pScMod->GetFormEditData() )
3408 bool bIgnore = false;
3409 if ( bModified )
3411 if (pState->GetPos() != aCursorPos)
3413 if (!bProtected)
3414 EnterHandler();
3416 else
3417 bIgnore = true;
3420 if ( !bIgnore )
3422 const ScAddress& rSPos = pState->GetStartPos();
3423 const ScAddress& rEPos = pState->GetEndPos();
3424 const EditTextObject* pData = pState->GetEditData();
3425 OUString aString = pState->GetString();
3426 bool bTxtMod = false;
3427 ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
3428 ScDocument* pDoc = pDocSh->GetDocument();
3430 aCursorPos = pState->GetPos();
3432 if ( pData )
3433 bTxtMod = true;
3434 else if ( bHadObject )
3435 bTxtMod = true;
3436 else if ( bTextValid )
3437 bTxtMod = ( !aString.equals(aCurrentText) );
3438 else
3439 bTxtMod = ( !aString.equals(GetEditText(pEngine)) );
3441 if ( bTxtMod || bForce )
3443 if (pData)
3445 pEngine->SetText( *pData );
3446 if ( pInputWin && pInputWin->IsMultiLineInput() )
3447 aString = ScEditUtil::GetMultilineString(*pEngine);
3448 else
3449 aString = GetEditText(pEngine);
3450 lcl_RemoveTabs(aString);
3451 bTextValid = false;
3452 aCurrentText = OUString();
3454 else
3456 aCurrentText = aString;
3457 bTextValid = true; //! To begin with remember as a string
3460 if ( pInputWin )
3461 pInputWin->SetTextString(aString);
3464 if ( pInputWin ) // Named range input
3466 OUString aPosStr;
3467 const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
3469 // Is the range a name?
3470 //! Find by Timer?
3471 if ( pActiveViewSh )
3472 pActiveViewSh->GetViewData()->GetDocument()->
3473 GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );
3475 if ( aPosStr.isEmpty() ) // Not a name -> format
3477 sal_uInt16 nFlags = 0;
3478 if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
3479 nFlags |= SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;
3480 if ( rSPos != rEPos )
3482 ScRange r(rSPos, rEPos);
3483 nFlags |= (nFlags << 4);
3484 aPosStr = r.Format(SCA_VALID | nFlags, pDoc, aAddrDetails);
3486 else
3487 aPosStr = aCursorPos.Format(SCA_VALID | nFlags, pDoc, aAddrDetails);
3490 // Disable the accessible VALUE_CHANGE event
3491 bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
3492 pInputWin->SetAccessibilityEventsSuppressed(true);
3493 pInputWin->SetPosString(aPosStr);
3494 pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
3495 pInputWin->SetSumAssignMode();
3498 if (bStopEditing)
3499 SFX_APP()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
3501 // As long as the content is not edited, turn off online spelling.
3502 // Online spelling is turned back on in StartTable, after setting
3503 // the right language from cell attributes.
3505 sal_uLong nCntrl = pEngine->GetControlWord();
3506 if ( nCntrl & EE_CNTRL_ONLINESPELLING )
3507 pEngine->SetControlWord( nCntrl & ~EE_CNTRL_ONLINESPELLING );
3509 bModified = false;
3510 bSelIsRef = false;
3511 bProtected = false;
3512 bCommandErrorShown = false;
3517 if ( pInputWin)
3519 // Do not enable if RefDialog is open
3520 if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
3522 if ( !pInputWin->IsEnabled())
3524 pInputWin->Enable();
3525 if(pDelayTimer )
3527 DELETEZ( pDelayTimer );
3531 else if(pScMod->IsRefDialogOpen())
3532 { // Because every document has its own InputWin,
3533 // we should start Timer again, because the input line may
3534 // still be active
3535 if ( !pDelayTimer )
3537 pDelayTimer = new Timer;
3538 pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3539 pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3540 pDelayTimer->Start();
3545 else // !pState || !pActiveViewSh
3547 if ( !pDelayTimer )
3549 pDelayTimer = new Timer;
3550 pDelayTimer->SetTimeout( 500 ); // 500 ms delay
3551 pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
3552 pDelayTimer->Start();
3556 HideTip();
3557 HideTipBelow();
3558 bInOwnChange = false;
3561 void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
3563 eAttrAdjust = eJust;
3564 UpdateAdjust( 0 );
3567 void ScInputHandler::ResetDelayTimer()
3569 if(pDelayTimer!=NULL)
3571 DELETEZ( pDelayTimer );
3573 if ( pInputWin)
3575 pInputWin->Enable();
3580 IMPL_LINK( ScInputHandler, DelayTimer, Timer*, pTimer )
3582 if ( pTimer == pDelayTimer )
3584 DELETEZ( pDelayTimer );
3586 if ( NULL == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
3588 //! New method at ScModule to query if function autopilot is open
3589 SfxViewFrame* pViewFrm = SfxViewFrame::Current();
3590 if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
3592 if ( pInputWin)
3594 pInputWin->EnableButtons( false );
3595 pInputWin->Disable();
3598 else if ( !bFormulaMode ) // Keep formula e.g. for help
3600 bInOwnChange = true; // disable ModifyHdl (reset below)
3602 pActiveViewSh = NULL;
3603 pEngine->SetText( EMPTY_OUSTRING );
3604 if ( pInputWin )
3606 pInputWin->SetPosString( EMPTY_OUSTRING );
3607 pInputWin->SetTextString( EMPTY_OUSTRING );
3608 pInputWin->Disable();
3611 bInOwnChange = false;
3615 return 0;
3618 void ScInputHandler::InputSelection( EditView* pView )
3620 SyncViews( pView );
3621 ShowTipCursor();
3622 UpdateParenthesis(); // Selection changed -> update parentheses highlighting
3624 // When the selection is changed manually, stop overwriting parentheses
3625 ResetAutoPar();
3628 void ScInputHandler::InputChanged( EditView* pView, bool bFromNotify )
3630 UpdateActiveView();
3632 // #i20282# DataChanged needs to know if this is from the input line's modify handler
3633 bool bFromTopNotify = ( bFromNotify && pView == pTopView );
3635 bool bNewView = DataChanging(); //FIXME: Is this at all possible?
3636 aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
3637 pEngine->SetText( aCurrentText );
3638 DataChanged( bFromTopNotify );
3639 bTextValid = true; // Is set to false in DataChanged
3641 if ( pActiveViewSh )
3643 ScViewData* pViewData = pActiveViewSh->GetViewData();
3644 if ( bNewView )
3645 pViewData->GetDocShell()->PostEditView( pEngine, aCursorPos );
3647 pViewData->EditGrowY();
3648 pViewData->EditGrowX();
3651 SyncViews( pView );
3654 const OUString& ScInputHandler::GetEditString()
3656 if (pEngine)
3658 aCurrentText = pEngine->GetText(); // Always new from Engine
3659 bTextValid = true;
3662 return aCurrentText;
3665 Size ScInputHandler::GetTextSize()
3667 Size aSize;
3668 if ( pEngine )
3669 aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
3671 return aSize;
3674 bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
3676 bool bRet = false;
3677 if (pEngine)
3679 // Contains field?
3680 sal_Int32 nParCnt = pEngine->GetParagraphCount();
3681 SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
3682 SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
3683 if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
3685 // Copy content
3686 EditTextObject* pObj = pEngine->CreateTextObject();
3687 rDestEngine.SetText(*pObj);
3688 delete pObj;
3690 // Delete attributes
3691 for (sal_Int32 i=0; i<nParCnt; i++)
3692 rDestEngine.QuickRemoveCharAttribs( i );
3694 // Combine paragraphs
3695 while ( nParCnt > 1 )
3697 sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
3698 ESelection aSel( 0,nLen, 1,0 );
3699 rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
3700 --nParCnt;
3703 bRet = true;
3706 return bRet;
3711 * Methods for FunctionAutoPilot:
3712 * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
3714 void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
3716 rStart = nFormSelStart;
3717 rEnd = nFormSelEnd;
3720 EditView* ScInputHandler::GetFuncEditView()
3722 UpdateActiveView(); // Due to pTableView
3724 EditView* pView = NULL;
3725 if ( pInputWin )
3727 pInputWin->MakeDialogEditView();
3728 pView = pInputWin->GetEditView();
3730 else
3732 if ( eMode != SC_INPUT_TABLE )
3734 bCreatingFuncView = true; // Don't display RangeFinder
3735 SetMode( SC_INPUT_TABLE );
3736 bCreatingFuncView = false;
3737 if ( pTableView )
3738 pTableView->GetEditEngine()->SetText( EMPTY_OUSTRING );
3740 pView = pTableView;
3743 return pView;
3746 void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
3748 if ( nStart <= nEnd )
3750 nFormSelStart = nStart;
3751 nFormSelEnd = nEnd;
3753 else
3755 nFormSelEnd = nStart;
3756 nFormSelStart = nEnd;
3759 EditView* pView = GetFuncEditView();
3760 if (pView)
3761 pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
3763 bModified = true;
3766 void ScInputHandler::InputReplaceSelection( const OUString& rStr )
3768 if (!pRefViewSh)
3769 pRefViewSh = pActiveViewSh;
3771 OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
3773 sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
3774 sal_Int32 nNewLen = rStr.getLength();
3776 OUStringBuffer aBuf(aFormText);
3777 if (nOldLen)
3778 aBuf.remove(nFormSelStart, nOldLen);
3779 if (nNewLen)
3780 aBuf.insert(nFormSelStart, rStr);
3782 aFormText = aBuf.makeStringAndClear();
3784 nFormSelEnd = nFormSelStart + nNewLen;
3786 EditView* pView = GetFuncEditView();
3787 if (pView)
3789 pView->SetEditEngineUpdateMode( false );
3790 pView->GetEditEngine()->SetText( aFormText );
3791 pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
3792 pView->SetEditEngineUpdateMode( true );
3794 bModified = true;
3797 void ScInputHandler::InputTurnOffWinEngine()
3799 bInOwnChange = true; // disable ModifyHdl (reset below)
3801 eMode = SC_INPUT_NONE;
3802 /* TODO: it would be better if there was some way to reset the input bar
3803 * engine instead of deleting and having it recreate through
3804 * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
3805 * fdo#72278 without reintroducing fdo#69971. */
3806 StopInputWinEngine(true);
3808 bInOwnChange = false;
3813 * ScInputHdlState
3815 ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
3816 const ScAddress& rStartPos,
3817 const ScAddress& rEndPos,
3818 const OUString& rString,
3819 const EditTextObject* pData )
3820 : aCursorPos ( rCurPos ),
3821 aStartPos ( rStartPos ),
3822 aEndPos ( rEndPos ),
3823 aString ( rString ),
3824 pEditData ( pData ? pData->Clone() : NULL )
3828 ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
3829 : pEditData ( NULL )
3831 *this = rCpy;
3834 ScInputHdlState::~ScInputHdlState()
3836 delete pEditData;
3839 bool ScInputHdlState::operator==( const ScInputHdlState& r ) const
3841 return ( (aStartPos == r.aStartPos)
3842 && (aEndPos == r.aEndPos)
3843 && (aCursorPos == r.aCursorPos)
3844 && (aString == r.aString)
3845 && ScGlobal::EETextObjEqual( pEditData, r.pEditData ) );
3848 ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
3850 delete pEditData;
3852 aCursorPos = r.aCursorPos;
3853 aStartPos = r.aStartPos;
3854 aEndPos = r.aEndPos;
3855 aString = r.aString;
3856 pEditData = r.pEditData ? r.pEditData->Clone() : NULL;
3858 return *this;
3861 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */