/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

//------------------------------------------------------------------

#include "scitems.hxx"
#include <editeng/eeitem.hxx>

#include <sfx2/app.hxx>
#include <editeng/acorrcfg.hxx>
#include <svx/algitem.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/brshitem.hxx>
#include <svtools/colorcfg.hxx>
#include <editeng/colritem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/editstat.hxx>
#include <editeng/editview.hxx>
#include <editeng/escpitem.hxx>
#include <editeng/forbiddencharacterstable.hxx>
#include <editeng/langitem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/wghtitem.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/printer.hxx>
#include <svl/zforlist.hxx>
#include <vcl/sound.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/help.hxx>
#include <vcl/cursor.hxx>
#include <tools/urlobj.hxx>
#include <formula/formulahelper.hxx>

#include "inputwin.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "scmod.hxx"
#include "uiitems.hxx"
#include "global.hxx"
#include "sc.hrc"
#include "globstr.hrc"
#include "patattr.hxx"
#include "viewdata.hxx"
#include "document.hxx"
#include "docpool.hxx"
#include "editutil.hxx"
#include "collect.hxx"
#include "appoptio.hxx"
#include "docoptio.hxx"
#include "validat.hxx"
#include "userlist.hxx"
#include "rfindlst.hxx"
#include "inputopt.hxx"
#include "cell.hxx"				// fuer Formel-Preview
#include "compiler.hxx"			// fuer Formel-Preview
#include "editable.hxx"
#include "funcdesc.hxx"

#define _INPUTHDL_CXX
#include "inputhdl.hxx"

//	max. Ranges im RangeFinder
#define RANGEFIND_MAX	32

using namespace formula;

// STATIC DATA -----------------------------------------------------------

sal_Bool ScInputHandler::bOptLoaded = sal_False;			// App-Optionen ausgewertet
sal_Bool ScInputHandler::bAutoComplete = sal_False;			// wird in KeyInput gesetzt

//	delimiters (in addition to ScEditUtil) needed for range finder:
//	only characters that are allowed in formulas next to references
//	and the quotation mark (so string constants can be skipped)

static const sal_Char __FAR_DATA pMinDelimiters[] = " !\"";

extern sal_uInt16 nEditAdjust;		//! Member an ViewData

//==================================================================

static sal_Unicode lcl_getSheetSeparator(ScDocument* pDoc)
{
    ScCompiler aComp(pDoc, ScAddress());
    aComp.SetGrammar(pDoc->GetGrammar());
    return aComp.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
}

void ScInputHandler::InitRangeFinder( const String& rFormula )
{
	DeleteRangeFinder();
    ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
    ScDocument* pDoc = pDocSh->GetDocument();
    const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDoc);

	if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
		return;

//	String aDelimiters = pEngine->GetWordDelimiters();
	String aDelimiters = ScEditUtil::ModifyDelimiters(
							String::CreateFromAscii( pMinDelimiters ) );

	xub_StrLen nColon = aDelimiters.Search(':');
	if ( nColon != STRING_NOTFOUND )
		aDelimiters.Erase( nColon, 1 );				// Delimiter ohne Doppelpunkt
	xub_StrLen nDot = aDelimiters.Search(cSheetSep);
	if ( nDot != STRING_NOTFOUND )
		aDelimiters.Erase( nDot, 1 );				// Delimiter ohne Punkt

	const sal_Unicode* pChar = rFormula.GetBuffer();
	xub_StrLen nLen = rFormula.Len();
	xub_StrLen nPos = 0;
	xub_StrLen nStart = 0;
	sal_uInt16 nCount = 0;
	ScRange aRange;
	while ( nPos < nLen && nCount < RANGEFIND_MAX )
	{
		//	Trenner ueberlesen
		while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.GetBuffer(), pChar[nPos] ) )
		{
			if ( pChar[nPos] == '"' )						// String
			{
				++nPos;
				while (nPos<nLen && pChar[nPos] != '"')		// bis zum Ende ueberlesen
					++nPos;
			}
			++nPos;						// Trennzeichen oder schliessender Quote
		}

		//	Text zwischen Trennern
		nStart = nPos;
handle_r1c1:
		while ( nPos<nLen && !ScGlobal::UnicodeStrChr( aDelimiters.GetBuffer(), pChar[nPos] ) )
			++nPos;

		// for R1C1 '-' in R[-]... or C[-]... are not delimiters
		// Nothing heroic here to ensure that there are '[]' around a negative
		// integer.  we need to clean up this code.
		if( nPos < nLen && nPos > 0 &&
			'-' == pChar[nPos] && '[' == pChar[nPos-1] &&
			NULL != pDoc &&
			formula::FormulaGrammar::CONV_XL_R1C1 == pDoc->GetAddressConvention() )
		{
			nPos++;
			goto handle_r1c1;
		}

		if ( nPos > nStart )
		{
			String aTest = rFormula.Copy( nStart, nPos-nStart );
			const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
			sal_uInt16 nFlags = aRange.ParseAny( aTest, pDoc, aAddrDetails );
			if ( nFlags & SCA_VALID )
			{
				//	Tabelle setzen, wenn nicht angegeben
				if ( (nFlags & SCA_TAB_3D) == 0 )
					aRange.aStart.SetTab( pActiveViewSh->GetViewData()->GetTabNo() );
				if ( (nFlags & SCA_TAB2_3D) == 0 )
					aRange.aEnd.SetTab( aRange.aStart.Tab() );

                if ( ( nFlags & ( SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2 ) ) == 0 )
                {
                    // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
                    // so Format doesn't output a double ref because of different flags.
                    sal_uInt16 nAbsFlags = nFlags & ( SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
                    nFlags |= nAbsFlags << 4;
                }

				if (!nCount)
				{
					pEngine->SetUpdateMode( sal_False );
					pRangeFindList = new ScRangeFindList( pDocSh->GetTitle() );
				}

				ScRangeFindData* pNew = new ScRangeFindData( aRange, nFlags, nStart, nPos );
				pRangeFindList->Insert( pNew );

				ESelection aSel( 0, nStart, 0, nPos );
				SfxItemSet aSet( pEngine->GetEmptyItemSet() );
				aSet.Put( SvxColorItem( Color( ScRangeFindList::GetColorName( nCount ) ),
							EE_CHAR_COLOR ) );
				pEngine->QuickSetAttribs( aSet, aSel );
				++nCount;
			}
		}

		//	letzten Trenner nicht ueberlesen, koennte ja ein Quote sein (?)
	}

	if (nCount)
	{
		pEngine->SetUpdateMode( sal_True );

		pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );
	}
}

void lcl_Replace( EditView* pView, const String& rNewStr, const ESelection& rOldSel )
{
	if ( pView )
	{
		ESelection aOldSel = pView->GetSelection();
		if (aOldSel.HasRange())
			pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
											 aOldSel.nEndPara, aOldSel.nEndPos ) );

		EditEngine* pEngine = pView->GetEditEngine();
		pEngine->QuickInsertText( rNewStr, rOldSel );

		//	Dummy-InsertText fuer Update und Paint
		//	dafuer muss oben die Selektion aufgehoben werden (vor QuickInsertText)
		pView->InsertText( EMPTY_STRING, sal_False );

		xub_StrLen nLen = pEngine->GetTextLen(0);
		ESelection aSel( 0, nLen, 0, nLen );
		pView->SetSelection( aSel );				// Cursor ans Ende
	}
}

void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
{
	ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
	if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
	{
		ScRangeFindData* pData = pRangeFindList->GetObject( nIndex );
		xub_StrLen nOldStart = pData->nSelStart;
		xub_StrLen nOldEnd = pData->nSelEnd;

		ScRange aJustified = rNew;
		aJustified.Justify();			// Ref in der Formel immer richtigherum anzeigen
		String aNewStr;
		ScDocument* pDoc = pDocView->GetViewData()->GetDocument();
		const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
		aJustified.Format( aNewStr, pData->nFlags, pDoc, aAddrDetails );
		ESelection aOldSel( 0, nOldStart, 0, nOldEnd );

		DataChanging();

		lcl_Replace( pTopView, aNewStr, aOldSel );
		lcl_Replace( pTableView, aNewStr, aOldSel );

		bInRangeUpdate = sal_True;
		DataChanged();
		bInRangeUpdate = sal_False;

		long nDiff = aNewStr.Len() - (long)(nOldEnd-nOldStart);

		pData->aRef = rNew;
		pData->nSelEnd = (xub_StrLen)(pData->nSelEnd + nDiff);

		sal_uInt16 nCount = (sal_uInt16) pRangeFindList->Count();
		for (sal_uInt16 i=nIndex+1; i<nCount; i++)
		{
			ScRangeFindData* pNext = pRangeFindList->GetObject( i );
			pNext->nSelStart = (xub_StrLen)(pNext->nSelStart + nDiff);
			pNext->nSelEnd   = (xub_StrLen)(pNext->nSelEnd   + nDiff);
		}
	}
	else
	{
		DBG_ERROR("UpdateRange: da fehlt was");
	}
}

void ScInputHandler::DeleteRangeFinder()
{
	ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
	if ( pRangeFindList && pPaintView )
	{
		ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
		pRangeFindList->SetHidden(sal_True);
		pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );	// wegnehmen
		DELETEZ(pRangeFindList);
	}
}

//==================================================================

inline String GetEditText(EditEngine* pEng)
{
	return ScEditUtil::GetSpaceDelimitedString(*pEng);
}

void lcl_RemoveTabs(String& rStr)
{
	xub_StrLen nPos;
	while ( (nPos=rStr.Search('\t')) != STRING_NOTFOUND )
		rStr.SetChar( nPos, ' ' );
}

void lcl_RemoveLineEnd(String& rStr)
{
	rStr.ConvertLineEnd(LINEEND_LF);
	xub_StrLen nPos;
	while ( (nPos=rStr.Search('\n')) != STRING_NOTFOUND )
		rStr.SetChar( nPos, ' ' );
}

xub_StrLen lcl_MatchParenthesis( const String& rStr, xub_StrLen nPos )
{
    int nDir;
    sal_Unicode c1, c2 = 0;
    c1 = rStr.GetChar( nPos );
    switch ( c1 )
    {
    case '(' :
        c2 = ')';
        nDir = 1;
        break;
    case ')' :
        c2 = '(';
        nDir = -1;
        break;
    case '<' :
        c2 = '>';
        nDir = 1;
        break;
    case '>' :
        c2 = '<';
        nDir = -1;
        break;
    case '{' :
        c2 = '}';
        nDir = 1;
        break;
    case '}' :
        c2 = '{';
        nDir = -1;
        break;
    case '[' :
        c2 = ']';
        nDir = 1;
        break;
    case ']' :
        c2 = '[';
        nDir = -1;
        break;
    default:
        nDir = 0;
    }
    if ( !nDir )
        return STRING_NOTFOUND;
    xub_StrLen nLen = rStr.Len();
    const sal_Unicode* p0 = rStr.GetBuffer();
    register const sal_Unicode* p;
    const sal_Unicode* p1;
    sal_uInt16 nQuotes = 0;
    if ( nPos < nLen / 2 )
    {
        p = p0;
        p1 = p0 + nPos;
    }
    else
    {
        p = p0 + nPos;
        p1 = p0 + nLen;
    }
    while ( p < p1 )
    {
        if ( *p++ == '\"' )
            nQuotes++;
    }
    // Odd number of quotes that we find ourselves in a string
    sal_Bool bLookInString = ((nQuotes % 2) != 0);
    sal_Bool bInString = bLookInString;
    p = p0 + nPos;
    p1 = (nDir < 0 ? p0 : p0 + nLen) ;
    sal_uInt16 nLevel = 1;
    while ( p != p1 && nLevel )
    {
        p += nDir;
        if ( *p == '\"' )
        {
            bInString = !bInString;
            if ( bLookInString && !bInString )
                p = p1;		//That's it then
        }
        else if ( bInString == bLookInString )
        {
            if ( *p == c1 )
                nLevel++;
            else if ( *p == c2 )
                nLevel--;
        }
    }
    if ( nLevel )
        return STRING_NOTFOUND;
    return (xub_StrLen) (p - p0);
}

//==================================================================

ScInputHandler::ScInputHandler()
    :   pInputWin( NULL ),
		pEngine( NULL ),
		pTableView( NULL ),
		pTopView( NULL ),
		pColumnData( NULL ),
		pFormulaData( NULL ),
        pFormulaDataPara( NULL ),
        pTipVisibleParent( NULL ),
		nTipVisible( 0 ),
        pTipVisibleSecParent( NULL ),
        nTipVisibleSec( 0 ),
		nAutoPos( SCPOS_INVALID ),
		bUseTab( sal_False ),
		bTextValid( sal_True ),
		nFormSelStart( 0 ),
		nFormSelEnd( 0 ),
		nAutoPar( 0 ),
        eMode( SC_INPUT_NONE ),
		bModified( sal_False ),
		bSelIsRef( sal_False ),
		bFormulaMode( sal_False ),
		bInRangeUpdate( sal_False ),
		bParenthesisShown( sal_False ),
		bCreatingFuncView( sal_False ),
		bInEnterHandler( sal_False ),
		bCommandErrorShown( sal_False ),
		bInOwnChange( sal_False ),
		bProtected( sal_False ),
		bCellHasPercentFormat( sal_False ),
		nValidation( 0 ),
        eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ),
		aScaleX( 1,1 ),
		aScaleY( 1,1 ),
		pRefViewSh( NULL ),
		pLastPattern( NULL ),
		pEditDefaults( NULL ),
		bLastIsSymbol( sal_False ),
		pLastState( NULL ),
		pDelayTimer( NULL ),
		pRangeFindList( NULL )
{
	//	The InputHandler is constructed with the view, so SfxViewShell::Current
	//	doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
	pActiveViewSh = NULL;

	//	Bindings (nur noch fuer Invalidate benutzt) werden bei Bedarf aktuell geholt
}

__EXPORT ScInputHandler::~ScInputHandler()
{
	//	Wenn dies der Applikations-InputHandler ist, wird der dtor erst nach SfxApplication::Main
	//	gerufen, darf sich also auf keine Sfx-Funktionen mehr verlassen

	if ( !SFX_APP()->IsDowning() )			// inplace
		EnterHandler();						// Eingabe noch abschliessen

	if (SC_MOD()->GetRefInputHdl()==this)
		SC_MOD()->SetRefInputHdl(NULL);

	if ( pInputWin && pInputWin->GetInputHandler() == this )
		pInputWin->SetInputHandler( NULL );

	delete pRangeFindList;
	delete pEditDefaults;
	delete pEngine;
	delete pLastState;
	delete pDelayTimer;
	delete pColumnData;
	delete pFormulaData;
    delete pFormulaDataPara;
}

void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
{
	if ( rX != aScaleX || rY != aScaleY )
	{
		aScaleX = rX;
		aScaleY = rY;
		if (pEngine)
		{
			MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
			pEngine->SetRefMapMode( aMode );
		}
	}
}

void ScInputHandler::UpdateRefDevice()
{
	if (!pEngine)
		return;

	sal_Bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
    bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
    sal_uInt32 nCtrl = pEngine->GetControlWord();
    if ( bTextWysiwyg || bInPlace )
        nCtrl |= EE_CNTRL_FORMAT100;    // EditEngine default: always format for 100%
    else
        nCtrl &= ~EE_CNTRL_FORMAT100;   // when formatting for screen, use the actual MapMode
    pEngine->SetControlWord( nCtrl );
	if ( bTextWysiwyg && pActiveViewSh )
		pEngine->SetRefDevice( pActiveViewSh->GetViewData()->GetDocument()->GetPrinter() );
	else
		pEngine->SetRefDevice( NULL );

	MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
	pEngine->SetRefMapMode( aMode );

	//	SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
	//	so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
	if ( !( bTextWysiwyg && pActiveViewSh ) )
	{
		pEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
	}
}

void ScInputHandler::ImplCreateEditEngine()
{
	if ( !pEngine )
	{
		if ( pActiveViewSh )
		{
			const ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
			pEngine = new ScFieldEditEngine( pDoc->GetEnginePool(), pDoc->GetEditPool() );
		}
		else
			pEngine = new ScFieldEditEngine( EditEngine::CreatePool(), NULL, sal_True );
		pEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
		UpdateRefDevice();		// also sets MapMode
		pEngine->SetPaperSize( Size( 1000000, 1000000 ) );
		pEditDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );

		pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_AUTOCORRECT );
        pEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
	}
}

void ScInputHandler::UpdateAutoCorrFlag()
{
	sal_uLong nCntrl = pEngine->GetControlWord();
	sal_uLong nOld = nCntrl;

	//	don't use pLastPattern here (may be invalid because of AutoStyle)

	sal_Bool bDisable = bLastIsSymbol || bFormulaMode;
	if ( bDisable )
		nCntrl &= ~EE_CNTRL_AUTOCORRECT;
	else
		nCntrl |= EE_CNTRL_AUTOCORRECT;

	if ( nCntrl != nOld )
		pEngine->SetControlWord(nCntrl);
}

void ScInputHandler::UpdateSpellSettings( sal_Bool bFromStartTab )
{
	if ( pActiveViewSh )
	{
		ScViewData* pViewData = pActiveViewSh->GetViewData();
		sal_Bool bOnlineSpell = pViewData->GetDocument()->GetDocOptions().IsAutoSpell();

		//	SetDefaultLanguage is independent of the language attributes,
		//	ScGlobal::GetEditDefaultLanguage is always used.
		//	It must be set every time in case the office language was changed.

		pEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );

		//	if called for changed options, update flags only if already editing
		//	if called from StartTable, always update flags

		if ( bFromStartTab || eMode != SC_INPUT_NONE )
		{
			sal_uLong nCntrl = pEngine->GetControlWord();
			sal_uLong nOld = nCntrl;
			if( bOnlineSpell )
				nCntrl |= EE_CNTRL_ONLINESPELLING;
			else
				nCntrl &= ~EE_CNTRL_ONLINESPELLING;
			// kein AutoCorrect auf Symbol-Font (EditEngine wertet Default nicht aus)
			if ( pLastPattern && pLastPattern->IsSymbolFont() )
				nCntrl &= ~EE_CNTRL_AUTOCORRECT;
			else
				nCntrl |= EE_CNTRL_AUTOCORRECT;
			if ( nCntrl != nOld )
				pEngine->SetControlWord(nCntrl);

			ScDocument* pDoc = pViewData->GetDocument();
            pDoc->ApplyAsianEditSettings( *pEngine );
			pEngine->SetDefaultHorizontalTextDirection(
				(EEHorizontalTextDirection)pDoc->GetEditTextDirection( pViewData->GetTabNo() ) );
			pEngine->SetFirstWordCapitalization( sal_False );
		}

		//	language is set separately, so the speller is needed only if online
		//	spelling is active

		if ( bOnlineSpell ) {
            com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
			pEngine->SetSpeller( xXSpellChecker1 );
        }

		sal_Bool bHyphen = pLastPattern && ((const SfxBoolItem&)pLastPattern->GetItem(ATTR_HYPHENATE)).GetValue();
		if ( bHyphen ) {
            com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
			pEngine->SetHyphenator( xXHyphenator );
        }
	}
}

//
//		Funktionen/Bereichsnamen etc. als Tip-Hilfe
//

#define SC_STRTYPE_FUNCTIONS	1
//	die anderen Typen sind in ScDocument::GetFormulaEntries festgelegt

void ScInputHandler::GetFormulaData()
{
	if ( pActiveViewSh )
	{
		ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();

		if ( pFormulaData )
			pFormulaData->FreeAll();
        else
            pFormulaData = new TypedScStrCollection;

        if( pFormulaDataPara )
            pFormulaDataPara->FreeAll();
        else
            pFormulaDataPara = new TypedScStrCollection;

		//		MRU-Funktionen aus dem Funktions-Autopiloten
		//		wie in ScPosWnd::FillFunctions (inputwin.cxx)
	    
        const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
        sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
        const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
        const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
        sal_uLong nListCount = pFuncList->GetCount();
        if (pMRUList)
        {
            for (sal_uInt16 i=0; i<nMRUCount; i++)
            {
                sal_uInt16 nId = pMRUList[i];
                for (sal_uLong j=0; j<nListCount; j++)
                {
                    const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
                    if ( pDesc->nFIndex == nId && pDesc->pFuncName )
                    {
                        String aEntry = *pDesc->pFuncName;
                        aEntry.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "()" ));
                        TypedStrData* pData = new TypedStrData( aEntry, 0.0, SC_STRTYPE_FUNCTIONS );
                        if (!pFormulaData->Insert(pData))
                            delete pData;
                        break;                  // nicht weitersuchen
                    }
                }
            }
        }
        for(sal_uLong i=0;i<nListCount;i++)
        {
            const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
            if ( pDesc->pFuncName )
            {
                pDesc->initArgumentInfo();
                String aEntry = pDesc->GetSignature();
                TypedStrData* pData = new TypedStrData( aEntry, 0.0, SC_STRTYPE_FUNCTIONS );
                if (!pFormulaDataPara->Insert(pData))
                    delete pData;
            }
        }
		pDoc->GetFormulaEntries( *pFormulaData );
        pDoc->GetFormulaEntries( *pFormulaDataPara );
	}
}

IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent*, pEvent )
{
    if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
        HideTip();
    return 0;
}

IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent*, pEvent )
{
    if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
        HideTipBelow();
    return 0;
}

void ScInputHandler::HideTip()
{
	if ( nTipVisible )
	{
        if (pTipVisibleParent)
            pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
		Help::HideTip( nTipVisible );
		nTipVisible = 0;
        pTipVisibleParent = NULL;
	}
	aManualTip.Erase();
}
void ScInputHandler::HideTipBelow()
{
    if ( nTipVisibleSec )
    {
        if (pTipVisibleSecParent)
            pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
        Help::HideTip( nTipVisibleSec );
        nTipVisibleSec = 0;
        pTipVisibleSecParent = NULL;
    }
    aManualTip.Erase();
}

void ScInputHandler::ShowTipCursor()
{
    HideTip();
    HideTipBelow();
    EditView* pActiveView = pTopView ? pTopView : pTableView;
    ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
    const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
    const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDocSh->GetDocument());

    if ( bFormulaMode && pActiveView && pFormulaDataPara && pEngine->GetParagraphCount() == 1 )
    {
        String aFormula = pEngine->GetText( (sal_uInt16) 0 );
        ESelection aSel = pActiveView->GetSelection();
        aSel.Adjust();
        xub_StrLen  nLeftParentPos = 0;
        if( aSel.nEndPos )
        {
            if ( aFormula.Len() < aSel.nEndPos )
                return;
            xub_StrLen nPos = aSel.nEndPos;
            String  aSelText = aFormula.Copy( 0, nPos );
            xub_StrLen  nNextFStart = 0;
            xub_StrLen  nNextFEnd = 0;
            xub_StrLen  nArgPos = 0;
            const IFunctionDescription* ppFDesc;
            ::std::vector< ::rtl::OUString> aArgs;
            sal_uInt16	    nArgs;
            sal_Bool  bFound = sal_False;
            FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());

            while( !bFound )
            {
                aSelText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
                nLeftParentPos = lcl_MatchParenthesis( aSelText, aSelText.Len()-1 );
                if( nLeftParentPos != STRING_NOTFOUND )
                {
                    sal_Unicode c = ( nLeftParentPos > 0 ) ? aSelText.GetChar( nLeftParentPos-1 ) : 0;
                    if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z' )) )
                        continue;
                    nNextFStart = aHelper.GetFunctionStart( aSelText, nLeftParentPos, sal_True);
                    if( aHelper.GetNextFunc( aSelText, sal_False, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) )
                    {
                        if( ppFDesc->getFunctionName().getLength() )
                        {
                            nArgPos = aHelper.GetArgStart( aSelText, nNextFStart, 0 );
                            nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());

                            sal_uInt16 nActive = 0;
                            sal_uInt16 nCount = 0;
                            sal_uInt16 nCountSemicolon = 0;
                            sal_uInt16 nCountDot = 0;
                            sal_uInt16 nStartPosition = 0;
                            sal_uInt16 nEndPosition = 0;
                            sal_Bool   bFlag = sal_False;
                            String aNew;
                            sal_uInt16 nParAutoPos = SCPOS_INVALID;
                            if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, sal_False ) )
                            {
                                for( sal_uInt16 i=0; i < nArgs; i++ )
                                {
                                    xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength());
                                    if( nArgPos <= aSelText.Len()-1 )
                                    {
                                        nActive = i+1;
                                        bFlag = sal_True;
                                    }
                                    nArgPos+=nLength+1;
                                }
                                if( bFlag )
                                {
                                    nCountSemicolon = aNew.GetTokenCount(cSep)-1;
                                    nCountDot = aNew.GetTokenCount(cSheetSep)-1;

                                    if( !nCountSemicolon )
                                    {
                                        for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                        {
                                            sal_Unicode cNext = aNew.GetChar( i );
                                            if( cNext == '(' )
                                            {
                                                nStartPosition = i+1;
                                            }
                                        }
                                    }
                                    else if( !nCountDot )
                                    {
                                        for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                        {
                                            sal_Unicode cNext = aNew.GetChar( i );
                                            if( cNext == '(' )
                                            {
                                                nStartPosition = i+1;
                                            }
                                            else if( cNext == cSep )
                                            {
                                                nCount ++;
                                                nEndPosition = i;
                                                if( nCount == nActive )
                                                {
                                                    break;
                                                }
                                                nStartPosition = nEndPosition+1;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                        {
                                            sal_Unicode cNext = aNew.GetChar( i );
                                            if( cNext == '(' )
                                            {
                                                nStartPosition = i+1;
                                            }
                                            else if( cNext == cSep )
                                            {
                                                nCount ++;
                                                nEndPosition = i;
                                                if( nCount == nActive )
                                                {
                                                    break;
                                                }
                                                nStartPosition = nEndPosition+1;
                                            }
                                            else if( cNext == cSheetSep )
                                            {
                                                continue;
                                            }
                                        }
                                    }

                                    if( nStartPosition )
                                    {
                                        aNew.Insert( 0x25BA, nStartPosition );
                                        ShowTipBelow( aNew );
                                        bFound = sal_True;
                                    }
                                }
                                else
                                {
                                    ShowTipBelow( aNew );
                                    bFound = sal_True;
                                }
                            }
                        }
                    }
                }
                else
                {
                    sal_uInt16 nPosition = 0;
                    String aText = pEngine->GetWord( 0, aSel.nEndPos-1 );
                    if( aText.GetChar( aSel.nEndPos-1 ) == '=' )
                    {
                        break;
                    }
                    String aNew;
                    sal_uInt16 nParAutoPos = SCPOS_INVALID;
                    nPosition = aText.Len()+1;
                    if( pFormulaDataPara->FindText( aText, aNew, nParAutoPos, sal_False ) )
                    {
                        if( aFormula.GetChar( nPosition ) =='(' )
                        {
                            ShowTipBelow( aNew );
                            bFound = sal_True;
                        }
                        else 
                            break;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }
}

void ScInputHandler::ShowTip( const String& rText )
{
	//	aManualTip muss hinterher von aussen gesetzt werden
	HideTip();

	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (pActiveView)
	{
		Point aPos;
		pTipVisibleParent = pActiveView->GetWindow();
		Cursor* pCur = pActiveView->GetCursor();
		if (pCur)
			aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
		aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
		Rectangle aRect( aPos, aPos );

		sal_uInt16 nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM;
		nTipVisible = Help::ShowTip(pTipVisibleParent, aRect, rText, nAlign);
		pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
	}
}

void ScInputHandler::ShowTipBelow( const String& rText )
{
    HideTipBelow();

    EditView* pActiveView = pTopView ? pTopView : pTableView;
    if ( pActiveView )
    {
        Point aPos;
        pTipVisibleSecParent = pActiveView->GetWindow();
        Cursor* pCur = pActiveView->GetCursor();
        if ( pCur )
        {
            Point aLogicPos = pCur->GetPos();
            aLogicPos.Y() += pCur->GetHeight();
            aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
        }
        aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
        Rectangle aRect( aPos, aPos );
        sal_uInt16 nAlign = QUICKHELP_LEFT | QUICKHELP_TOP | QUICKHELP_NOEVADEPOINTER;
        nTipVisibleSec = Help::ShowTip(pTipVisibleSecParent, aRect, rText, nAlign);
        pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
    }
}

void ScInputHandler::UseFormulaData()
{
	EditView* pActiveView = pTopView ? pTopView : pTableView;
    ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
    const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
    const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDocSh->GetDocument());

	//	Formeln duerfen nur 1 Absatz haben
	if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
	{
		String aTotal = pEngine->GetText( (sal_uInt16) 0 );
		ESelection aSel = pActiveView->GetSelection();
		aSel.Adjust();

		//	#59348# Durch Differenzen zwischen Tabelle und Eingabezeile
		//	(z.B. Clipboard mit Zeilenumbruechen) kann es sein, dass die Selektion
		//	nicht mehr zur EditEngine passt. Dann halt kommentarlos abbrechen:

		if ( aSel.nEndPos > aTotal.Len() )
			return;

		//	steht der Cursor am Ende eines Wortes?

		if ( aSel.nEndPos > 0 )
		{
            xub_StrLen nPos = aSel.nEndPos;
            String  aFormula = aTotal.Copy( 0, nPos );;
            xub_StrLen  nLeftParentPos = 0;
            xub_StrLen  nNextFStart = 0;
            xub_StrLen  nNextFEnd = 0;
            xub_StrLen  nArgPos = 0;
            const IFunctionDescription* ppFDesc;
            ::std::vector< ::rtl::OUString> aArgs;
            sal_uInt16	    nArgs;
            sal_Bool  bFound = sal_False;

            String aText = pEngine->GetWord( 0, aSel.nEndPos-1 );
            if ( aText.Len() )
            {
                String aNew;
                nAutoPos = SCPOS_INVALID;
                if ( pFormulaData->FindText( aText, aNew, nAutoPos, sal_False ) )
                {
                    ShowTip( aNew );
                    aAutoSearch = aText;
                }
            }
            FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());

            while( !bFound )
            {
                aFormula.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
                nLeftParentPos = lcl_MatchParenthesis( aFormula, aFormula.Len()-1 );
                if( nLeftParentPos == STRING_NOTFOUND )
                    break;

                // #160063# nLeftParentPos can be 0 if a parenthesis is inserted before the formula
                sal_Unicode c = ( nLeftParentPos > 0 ) ? aFormula.GetChar( nLeftParentPos-1 ) : 0;
                if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z') ) )
                    continue;
                nNextFStart = aHelper.GetFunctionStart( aFormula, nLeftParentPos, sal_True);
                if( aHelper.GetNextFunc( aFormula, sal_False, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) )
                {
                    if( ppFDesc->getFunctionName().getLength() )
                    {
                        nArgPos = aHelper.GetArgStart( aFormula, nNextFStart, 0 );
                        nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());

                        sal_uInt16 nActive = 0;
                        sal_uInt16 nCount = 0;
                        sal_uInt16 nCountSemicolon = 0;
                        sal_uInt16 nCountDot = 0;
                        sal_uInt16 nStartPosition = 0;
                        sal_uInt16 nEndPosition = 0;
                        sal_Bool   bFlag = sal_False;
                        String aNew;
                        sal_uInt16 nParAutoPos = SCPOS_INVALID;
                        if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, sal_False ) )
                        {
                            for( sal_uInt16 i=0; i < nArgs; i++ )
                            {
                                xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength());
                                if( nArgPos <= aFormula.Len()-1 )
                                {
                                    nActive = i+1;
                                    bFlag = sal_True;
                                }
                                nArgPos+=nLength+1;
                            }
                            if( bFlag )
                            {
                                nCountSemicolon = aNew.GetTokenCount(cSep)-1;
                                nCountDot = aNew.GetTokenCount(cSheetSep)-1;
                                
                               if( !nCountSemicolon )
                               {
                                    for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                    {
                                        sal_Unicode cNext = aNew.GetChar( i );
                                        if( cNext == '(' )
                                        {
                                            nStartPosition = i+1;
                                        }
                                    }
                                }
                                else if( !nCountDot )
                                {
                                    for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                    {
                                        sal_Unicode cNext = aNew.GetChar( i );
                                        if( cNext == '(' )
                                        {
                                            nStartPosition = i+1;
                                        }
                                        else if( cNext == cSep )
                                        {
                                            nCount ++;
                                            nEndPosition = i;
                                            if( nCount == nActive )
                                            {
                                                break;
                                            }
                                            nStartPosition = nEndPosition+1;
                                        }
                                    }
                                }
                                else
                                {
                                    for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
                                    {
                                        sal_Unicode cNext = aNew.GetChar( i );
                                        if( cNext == '(' )
                                        {
                                            nStartPosition = i+1;
                                        }
                                        else if( cNext == cSep )
                                        {
                                            nCount ++;
                                            nEndPosition = i;
                                            if( nCount == nActive )
                                            {
                                                break;
                                            }
                                            nStartPosition = nEndPosition+1;
                                        }
                                        else if( cNext == cSheetSep )
                                        {
                                            continue;
                                        }
                                    }
                                }

                                if( nStartPosition )
                                {
                                    aNew.Insert( 0x25BA, nStartPosition );
                                    ShowTipBelow( aNew );
                                    bFound = sal_True;
                                }
                            }
                            else
                            {
                                ShowTipBelow( aNew );
                                bFound = sal_True;
                            }
                        }
                    }
                }
            }
        }
    }
}

void ScInputHandler::NextFormulaEntry( sal_Bool bBack )
{
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if ( pActiveView && pFormulaData )
	{
		String aNew;
		if ( pFormulaData->FindText( aAutoSearch, aNew, nAutoPos, bBack ) )
			ShowTip( aNew );		//	als QuickHelp anzeigen
	}

	//	bei Tab wird vorher immer HideCursor gerufen

	if (pActiveView)
		pActiveView->ShowCursor();
}

void lcl_CompleteFunction( EditView* pView, const String& rInsert, sal_Bool& rParInserted )
{
	if (pView)
	{
		ESelection aSel = pView->GetSelection();
		--aSel.nStartPos;
		--aSel.nEndPos;
		pView->SetSelection(aSel);
		pView->SelectCurrentWord();

		String aInsStr = rInsert;
		xub_StrLen nInsLen = aInsStr.Len();
		sal_Bool bDoParen = ( nInsLen > 1 && aInsStr.GetChar(nInsLen-2) == '('
									  && aInsStr.GetChar(nInsLen-1) == ')' );
		if ( bDoParen )
		{
			//	Klammern hinter Funktionsnamen nicht einfuegen, wenn direkt dahinter
			//	schon eine Klammer steht (z.B. wenn der Funktionsname geaendert wurde,
			//	#39393#).

			ESelection aWordSel = pView->GetSelection();
			String aOld = pView->GetEditEngine()->GetText((sal_uInt16)0);
			sal_Unicode cNext = aOld.GetChar(aWordSel.nEndPos);
			if ( cNext == '(' )
			{
				bDoParen = sal_False;
				aInsStr.Erase( nInsLen - 2 );	// Klammern weglassen
			}
		}

		pView->InsertText( aInsStr, sal_False );

		if ( bDoParen )							// Cursor zwischen die Klammern setzen
		{
			aSel = pView->GetSelection();
			--aSel.nStartPos;
			--aSel.nEndPos;
			pView->SetSelection(aSel);

			rParInserted = sal_True;
		}
	}
}

void ScInputHandler::PasteFunctionData()
{
	if ( pFormulaData && nAutoPos != SCPOS_INVALID )
	{
		TypedStrData* pData = (*pFormulaData)[nAutoPos];
		if (pData)
		{
			String aInsert = pData->GetString();
			sal_Bool bParInserted = sal_False;

			DataChanging(); 						// kann nicht neu sein
			lcl_CompleteFunction( pTopView, aInsert, bParInserted );
			lcl_CompleteFunction( pTableView, aInsert, bParInserted );
			DataChanged();
            ShowTipCursor();

			if (bParInserted)
				AutoParAdded();
		}
	}

	HideTip();

	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (pActiveView)
		pActiveView->ShowCursor();
}

//
//		Selektion berechnen und als Tip-Hilfe anzeigen
//

String lcl_Calculate( const String& rFormula, ScDocument* pDoc, const ScAddress &rPos )
{
	//!		mit ScFormulaDlg::CalcValue zusammenfassen und ans Dokument verschieben !!!!
	//!		(Anfuehrungszeichen bei Strings werden nur hier eingefuegt)

	String aValue;

	if (rFormula.Len())
	{
		ScFormulaCell* pCell = new ScFormulaCell( pDoc, rPos, rFormula );

		// #35521# HACK! um bei ColRowNames kein #REF! zu bekommen,
		// wenn ein Name eigentlich als Bereich in die Gesamt-Formel
		// eingefuegt wird, bei der Einzeldarstellung aber als
		// single-Zellbezug interpretiert wird
		sal_Bool bColRowName = pCell->HasColRowName();
		if ( bColRowName )
		{
			// ColRowName im RPN-Code?
			if ( pCell->GetCode()->GetCodeLen() <= 1 )
			{	// ==1: einzelner ist als Parameter immer Bereich
				// ==0: es waere vielleicht einer, wenn..
				String aBraced( '(' );
				aBraced += rFormula;
				aBraced += ')';
				delete pCell;
				pCell = new ScFormulaCell( pDoc, rPos, aBraced );
			}
			else
				bColRowName = sal_False;
		}

		sal_uInt16 nErrCode = pCell->GetErrCode();
		if ( nErrCode == 0 )
		{
			SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
			Color* pColor;
			if ( pCell->IsValue() )
			{
				double n = pCell->GetValue();
				sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
								pCell->GetFormatType(), ScGlobal::eLnge );
				aFormatter.GetInputLineString( n, nFormat, aValue );
				//!	display OutputString but insert InputLineString
			}
			else
			{
				String aStr;

				pCell->GetString( aStr );
				sal_uLong nFormat = aFormatter.GetStandardFormat(
								pCell->GetFormatType(), ScGlobal::eLnge);
				aFormatter.GetOutputString( aStr, nFormat,
											aValue, &pColor );

				aValue.Insert('"',0);	// in Anfuehrungszeichen
				aValue+='"';
				//!	Anfuehrungszeichen im String escapen ????
			}

			ScRange aTestRange;
			if ( bColRowName || (aTestRange.Parse(rFormula) & SCA_VALID) )
				aValue.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ..." ));		// Bereich
		}
		else
			aValue = ScGlobal::GetErrorString(nErrCode);
		delete pCell;
	}

	return aValue;
}

void ScInputHandler::FormulaPreview()
{
	String aValue;
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if ( pActiveView && pActiveViewSh )
	{
		String aPart = pActiveView->GetSelected();
		if (!aPart.Len())
			aPart = pEngine->GetText((sal_uInt16)0);
		ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
		aValue = lcl_Calculate( aPart, pDoc, aCursorPos );
	}

	if (aValue.Len())
	{
		ShowTip( aValue );			//	als QuickHelp anzeigen
		aManualTip = aValue;		//	nach ShowTip setzen
		nAutoPos = SCPOS_INVALID;	//	Formel-Autocomplete aufheben
	}
}

void ScInputHandler::PasteManualTip()
{
	//	drei Punkte am Ende -> Bereichsreferenz -> nicht einfuegen
	//	(wenn wir mal Matrix-Konstanten haben, kann das geaendert werden)

	xub_StrLen nTipLen = aManualTip.Len();
	if ( nTipLen && ( nTipLen < 3 || !aManualTip.Copy( nTipLen-3 ).EqualsAscii("...") ) )
	{
		DataChanging(); 									// kann nicht neu sein

		String aInsert = aManualTip;
		EditView* pActiveView = pTopView ? pTopView : pTableView;
		if (!pActiveView->HasSelection())
		{
			//	nichts selektiert -> alles selektieren
			xub_StrLen nOldLen = pEngine->GetTextLen(0);
			ESelection aAllSel( 0, 0, 0, nOldLen );
			if ( pTopView )
				pTopView->SetSelection( aAllSel );
			if ( pTableView )
				pTableView->SetSelection( aAllSel );
		}

		ESelection aSel = pActiveView->GetSelection();
		aSel.Adjust();
		DBG_ASSERT( !aSel.nStartPara && !aSel.nEndPara, "Zuviele Absaetze in Formel" );
		if ( !aSel.nStartPos )	// Selektion ab Anfang?
		{
			if ( aSel.nEndPos == pEngine->GetTextLen(0) )
			{
				//	alles selektiert -> Anfuehrungszeichen weglassen
				if ( aInsert.GetChar(0) == '"' )
					aInsert.Erase(0,1);
				xub_StrLen nInsLen = aInsert.Len();
				if ( nInsLen && aInsert.GetChar(nInsLen-1) == '"' )
					aInsert.Erase( nInsLen-1 );
			}
			else if ( aSel.nEndPos )
			{
				//	nicht alles selektiert -> Gleichheitszeichen nicht ueberschreiben
				//!	doppelte Gleichheitszeichen auch ???

				aSel.nStartPos = 1;
				if ( pTopView )
					pTopView->SetSelection( aSel );
				if ( pTableView )
					pTableView->SetSelection( aSel );
			}
		}
		if ( pTopView )
			pTopView->InsertText( aInsert, sal_True );
		if ( pTableView )
			pTableView->InsertText( aInsert, sal_True );

		DataChanged();
	}

	HideTip();
}

void ScInputHandler::ResetAutoPar()
{
	nAutoPar = 0;
}

void ScInputHandler::AutoParAdded()
{
	++nAutoPar;		//	closing parenthesis can be overwritten
}

sal_Bool ScInputHandler::CursorAtClosingPar()
{
	//	test if the cursor is before a closing parenthesis

	//	selection from SetReference has been removed before
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
	{
		ESelection aSel = pActiveView->GetSelection();
		xub_StrLen nPos = aSel.nStartPos;
		String aFormula = pEngine->GetText((sal_uInt16)0);
		if ( nPos < aFormula.Len() && aFormula.GetChar(nPos) == ')' )
			return sal_True;
	}
	return sal_False;
}

void ScInputHandler::SkipClosingPar()
{
	//	this is called when a ')' is typed and the cursor is before a ')'
	//	that can be overwritten -> just set the cursor behind the ')'

	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (pActiveView)
	{
		ESelection aSel = pActiveView->GetSelection();
		++aSel.nStartPos;
		++aSel.nEndPos;

		//	this is in a formula (only one paragraph), so the selection
		//	can be used directly for the TopView

		if ( pTopView )
			pTopView->SetSelection( aSel );
		if ( pTableView )
			pTableView->SetSelection( aSel );
	}

	DBG_ASSERT(nAutoPar, "SkipClosingPar: count is wrong");
	--nAutoPar;
}

//
//		Auto-Eingabe
//

void ScInputHandler::GetColData()
{
	if ( pActiveViewSh )
	{
		ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();

		if ( pColumnData )
			pColumnData->FreeAll();
		else
		{
			pColumnData = new TypedScStrCollection;
			pColumnData->SetCaseSensitive( sal_True );		// equal strings are handled in FindText
		}

		pDoc->GetDataEntries( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
								*pColumnData, sal_True );
	}
}

void ScInputHandler::UseColData()			// beim Tippen
{
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if ( pActiveView && pColumnData )
	{
		//	nur anpassen, wenn Cursor am Ende steht

		ESelection aSel = pActiveView->GetSelection();
		aSel.Adjust();

		sal_uInt16 nParCnt = pEngine->GetParagraphCount();
		if ( aSel.nEndPara+1 == nParCnt )
		{
			xub_StrLen nParLen = pEngine->GetTextLen( aSel.nEndPara );
			if ( aSel.nEndPos == nParLen )
			{
				String aText = GetEditText(pEngine);
				if (aText.Len())
				{
					String aNew;
					nAutoPos = SCPOS_INVALID;	// nix
					if ( pColumnData->FindText( aText, aNew, nAutoPos, sal_False ) )
					{
						//	#45434# durch dBase Import etc. koennen Umbrueche im String sein,
						//	das wuerde hier mehrere Absaetze ergeben -> nicht gut
						//!	GetExactMatch funktioniert dann auch nicht
						lcl_RemoveLineEnd( aNew );

                        //  Absaetze beibehalten, nur den Rest anfuegen
						//!	genaue Ersetzung im EnterHandler !!!

						// ein Space zwischen Absaetzen:
						sal_uLong nEdLen = pEngine->GetTextLen() + nParCnt - 1;
						String aIns = aNew.Copy( (xub_StrLen)nEdLen );

						//	selection must be "backwards", so the cursor stays behind the last
						//	typed character
						ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.Len(),
											   aSel.nEndPara, aSel.nEndPos );

						//	when editing in input line, apply to both edit views
						if ( pTableView )
						{
							pTableView->InsertText( aIns, sal_False );
							pTableView->SetSelection( aSelection );
						}
						if ( pTopView )
						{
							pTopView->InsertText( aIns, sal_False );
							pTopView->SetSelection( aSelection );
						}

						aAutoSearch = aText;	// zum Weitersuchen - nAutoPos ist gesetzt

						if ( aText.Len() == aNew.Len() )
						{
							//	Wenn der eingegebene Text gefunden wurde, TAB nur dann
							//	verschlucken, wenn noch etwas kommt

							String aDummy;
							sal_uInt16 nNextPos = nAutoPos;
							bUseTab = pColumnData->FindText( aText, aDummy, nNextPos, sal_False );
						}
						else
							bUseTab = sal_True;
					}
				}
			}
		}
	}
}

void ScInputHandler::NextAutoEntry( sal_Bool bBack )
{
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if ( pActiveView && pColumnData )
	{
		if ( nAutoPos != SCPOS_INVALID && aAutoSearch.Len() )
		{
			//	stimmt die Selektion noch? (kann per Maus geaendert sein)

			ESelection aSel = pActiveView->GetSelection();
			aSel.Adjust();
			sal_uInt16 nParCnt = pEngine->GetParagraphCount();
			if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
			{
				String aText = GetEditText(pEngine);
				xub_StrLen nSelLen = aSel.nEndPos - aSel.nStartPos;
				xub_StrLen nParLen = pEngine->GetTextLen( aSel.nEndPara );
				if ( aSel.nEndPos == nParLen && aText.Len() == aAutoSearch.Len() + nSelLen )
				{
					String aNew;
					if ( pColumnData->FindText( aAutoSearch, aNew, nAutoPos, bBack ) )
					{
						bInOwnChange = sal_True;		// disable ModifyHdl (reset below)

						lcl_RemoveLineEnd( aNew );
						String aIns = aNew.Copy( aAutoSearch.Len() );

						//	when editing in input line, apply to both edit views
						if ( pTableView )
						{
							pTableView->DeleteSelected();
							pTableView->InsertText( aIns, sal_False );
							pTableView->SetSelection( ESelection(
														aSel.nEndPara, aSel.nStartPos + aIns.Len(),
														aSel.nEndPara, aSel.nStartPos ) );
						}
						if ( pTopView )
						{
							pTopView->DeleteSelected();
							pTopView->InsertText( aIns, sal_False );
							pTopView->SetSelection( ESelection(
														aSel.nEndPara, aSel.nStartPos + aIns.Len(),
														aSel.nEndPara, aSel.nStartPos ) );
						}

						bInOwnChange = sal_False;
					}
					else
					{
						// mehr gibts nicht

						Sound::Beep();
					}
				}
			}
		}
	}

	//	bei Tab wird vorher immer HideCursor gerufen

	if (pActiveView)
		pActiveView->ShowCursor();
}

//
//		Klammern hervorheben
//

void ScInputHandler::UpdateParenthesis()
{
	//	Klammern suchen

	//!	Klammer-Hervorhebung einzeln abschaltbar ????

	sal_Bool bFound = sal_False;
	if ( bFormulaMode && eMode != SC_INPUT_TOP )
	{
		if ( pTableView && !pTableView->HasSelection() )		// Selektion ist immer unten
		{
			ESelection aSel = pTableView->GetSelection();
			if (aSel.nStartPos)
			{
				//	Das Zeichen links vom Cursor wird angeschaut

				xub_StrLen nPos = aSel.nStartPos - 1;
				String aFormula = pEngine->GetText((sal_uInt16)0);
				sal_Unicode c = aFormula.GetChar(nPos);
				if ( c == '(' || c == ')' )
				{
					xub_StrLen nOther = lcl_MatchParenthesis( aFormula, nPos );
					if ( nOther != STRING_NOTFOUND )
					{
						SfxItemSet aSet( pEngine->GetEmptyItemSet() );
						aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
						//!	Unterscheidung, wenn die Zelle schon fett ist !!!!

						if (bParenthesisShown)
						{
							//	alte Hervorhebung wegnehmen
							sal_uInt16 nCount = pEngine->GetParagraphCount();
							for (sal_uInt16 i=0; i<nCount; i++)
								pEngine->QuickRemoveCharAttribs( i, EE_CHAR_WEIGHT );
						}

						ESelection aSelThis( 0,nPos, 0,nPos+1 );
						pEngine->QuickSetAttribs( aSet, aSelThis );
						ESelection aSelOther( 0,nOther, 0,nOther+1 );
						pEngine->QuickSetAttribs( aSet, aSelOther );

						//	Dummy-InsertText fuer Update und Paint (Selektion ist leer)
						pTableView->InsertText( EMPTY_STRING, sal_False );

						bFound = sal_True;
					}
				}
			}

			//	mark parenthesis right of cursor if it will be overwritten (nAutoPar)
			//	with different color (COL_LIGHTBLUE) ??
		}
	}

	//	alte Hervorhebung wegnehmen, wenn keine neue gesetzt

	if ( bParenthesisShown && !bFound && pTableView )
	{
		sal_uInt16 nCount = pEngine->GetParagraphCount();
		for (sal_uInt16 i=0; i<nCount; i++)
			pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
	}

	bParenthesisShown = bFound;
}

void ScInputHandler::ViewShellGone(ScTabViewShell* pViewSh) 	// wird synchron aufgerufen!
{
	if ( pViewSh == pActiveViewSh )
	{
		delete pLastState;
		pLastState = NULL;
		pLastPattern = NULL;
	}

	if ( pViewSh == pRefViewSh )
	{
		//! Die Eingabe kommt aus dem EnterHandler nicht mehr an
		//	Trotzdem wird immerhin der Editmodus beendet

		EnterHandler();
		bFormulaMode = sal_False;
		pRefViewSh = NULL;
		SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
		SC_MOD()->SetRefInputHdl(NULL);
		if (pInputWin)
			pInputWin->SetFormulaMode(sal_False);
		UpdateAutoCorrFlag();
	}

	pActiveViewSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );

	if ( pActiveViewSh && pActiveViewSh == pViewSh )
	{
		DBG_ERROR("pActiveViewSh weg");
		pActiveViewSh = NULL;
	}

	if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
		UpdateRefDevice();		// don't keep old document's printer as RefDevice
}

void ScInputHandler::UpdateActiveView()
{
	ImplCreateEditEngine();

    // #i20588# Don't rely on focus to find the active edit view. Instead, the
    // active pane at the start of editing is now stored (GetEditActivePart).
    // GetActiveWin (the currently active pane) fails for ref input across the
    // panes of a split view.

    Window* pShellWin = pActiveViewSh ?
                pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData()->GetEditActivePart() ) :
                NULL;

	sal_uInt16 nCount = pEngine->GetViewCount();
	if (nCount > 0)
	{
		pTableView = pEngine->GetView(0);
		for (sal_uInt16 i=1; i<nCount; i++)
		{
			EditView* pThis = pEngine->GetView(i);
			Window* pWin = pThis->GetWindow();
			if ( pWin==pShellWin )
				pTableView = pThis;
		}
	}
	else
		pTableView = NULL;

	if (pInputWin)
		pTopView = pInputWin->GetEditView();
	else
		pTopView = NULL;
}

void ScInputHandler::StopInputWinEngine( sal_Bool bAll )
{
	if (pInputWin)
		pInputWin->StopEditEngine( bAll );

	pTopView = NULL;		// invalid now
}

EditView* ScInputHandler::GetActiveView()
{
	UpdateActiveView();
	return pTopView ? pTopView : pTableView;
}

void ScInputHandler::ForgetLastPattern()
{
	pLastPattern = NULL;
	if ( !pLastState && pActiveViewSh )
		pActiveViewSh->UpdateInputHandler( sal_True );		// Status neu holen
	else
		NotifyChange( pLastState, sal_True );
}

void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
{
	SvxAdjust eSvxAdjust;
    switch (eAttrAdjust)
	{
		case SVX_HOR_JUSTIFY_STANDARD:
			{
				sal_Bool bNumber = sal_False;
				if (cTyped)										// neu angefangen
					bNumber = (cTyped>='0' && cTyped<='9');		// nur Ziffern sind Zahlen
				else if ( pActiveViewSh )
				{
					ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
					bNumber = ( pDoc->GetCellType( aCursorPos ) == CELLTYPE_VALUE );
				}
				eSvxAdjust = bNumber ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
			}
			break;
		case SVX_HOR_JUSTIFY_BLOCK:
			eSvxAdjust = SVX_ADJUST_BLOCK;
			break;
		case SVX_HOR_JUSTIFY_CENTER:
			eSvxAdjust = SVX_ADJUST_CENTER;
			break;
		case SVX_HOR_JUSTIFY_RIGHT:
			eSvxAdjust = SVX_ADJUST_RIGHT;
			break;
		default:	// SVX_HOR_JUSTIFY_LEFT
			eSvxAdjust = SVX_ADJUST_LEFT;
			break;
	}

	sal_Bool bAsianVertical = pLastPattern &&
        ((const SfxBoolItem&)pLastPattern->GetItem( ATTR_STACKED )).GetValue() &&
		((const SfxBoolItem&)pLastPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
	if ( bAsianVertical )
	{
		//	always edit at top of cell -> LEFT when editing vertically
		eSvxAdjust = SVX_ADJUST_LEFT;
	}

	pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
	pEngine->SetDefaults( *pEditDefaults );

    nEditAdjust = sal::static_int_cast<sal_uInt16>(eSvxAdjust);     //! set at ViewData or with PostEditView

	pEngine->SetVertical( bAsianVertical );
}

void ScInputHandler::RemoveAdjust()
{
	//	harte Ausrichtungs-Attribute loeschen

	sal_Bool bUndo = pEngine->IsUndoEnabled();
	if ( bUndo )
		pEngine->EnableUndo( sal_False );

	//	RemoveParaAttribs removes all paragraph attributes, including EE_PARA_JUST
#if 0
	sal_Bool bChange = sal_False;
	sal_uInt16 nCount = pEngine->GetParagraphCount();
	for (sal_uInt16 i=0; i<nCount; i++)
	{
		const SfxItemSet& rOld = pEngine->GetParaAttribs( i );
		if ( rOld.GetItemState( EE_PARA_JUST ) == SFX_ITEM_SET )
		{
			SfxItemSet aNew( rOld );
			aNew.ClearItem( EE_PARA_JUST );
			pEngine->SetParaAttribs( i, aNew );
			bChange = sal_True;
		}
	}
#endif

	//	#89403# non-default paragraph attributes (e.g. from clipboard)
	//	must be turned into character attributes
	pEngine->RemoveParaAttribs();

	if ( bUndo )
		pEngine->EnableUndo( sal_True );

	// ER 31.08.00  Only called in EnterHandler, don't change view anymore.
#if 0
	if (bChange)
	{
		EditView* pActiveView = pTopView ? pTopView : pTableView;
		pActiveView->ShowCursor( sal_False, sal_True );
	}
#endif
}

void ScInputHandler::RemoveRangeFinder()
{
	//	pRangeFindList und Farben loeschen

	pEngine->SetUpdateMode(sal_False);
	sal_uInt16 nCount = pEngine->GetParagraphCount();	// koennte gerade neu eingefuegt worden sein
	for (sal_uInt16 i=0; i<nCount; i++)
		pEngine->QuickRemoveCharAttribs( i, EE_CHAR_COLOR );
	pEngine->SetUpdateMode(sal_True);

	EditView* pActiveView = pTopView ? pTopView : pTableView;
	pActiveView->ShowCursor( sal_False, sal_True );

	DeleteRangeFinder();		// loescht die Liste und die Markierungen auf der Tabelle
}

sal_Bool ScInputHandler::StartTable( sal_Unicode cTyped, sal_Bool bFromCommand )
{
	// returns sal_True if a new edit mode was started

	sal_Bool bNewTable = sal_False;

	if (!bModified && ValidCol(aCursorPos.Col()))
	{
		if (pActiveViewSh)
		{
			ImplCreateEditEngine();
			UpdateActiveView();
			SyncViews();

			ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();

			const ScMarkData& rMark = pActiveViewSh->GetViewData()->GetMarkData();
			ScEditableTester aTester;
			if ( rMark.IsMarked() || rMark.IsMultiMarked() )
				aTester.TestSelection( pDoc, rMark );
			else
				aTester.TestSelectedBlock( pDoc, aCursorPos.Col(),aCursorPos.Row(),
												 aCursorPos.Col(),aCursorPos.Row(), rMark );
			if ( aTester.IsEditable() )
			{
				// UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
				pEngine->SetUpdateMode( sal_False );

				//	Attribute in EditEngine uebernehmen

				const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(),
																  aCursorPos.Row(),
																  aCursorPos.Tab() );
				if (pPattern != pLastPattern)
				{
					//	Prozent-Format?

					const SfxItemSet& rAttrSet = pPattern->GetItemSet();
					const SfxPoolItem* pItem;

					if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, sal_True, &pItem ) )
					{
						sal_uLong nFormat = ((const SfxUInt32Item*)pItem)->GetValue();
						bCellHasPercentFormat = ( NUMBERFORMAT_PERCENT ==
												  pDoc->GetFormatTable()->GetType( nFormat ) );
					}
					else
						bCellHasPercentFormat = sal_False; // Default: kein Prozent

					//	Gueltigkeit angegeben?

					if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALIDDATA, sal_True, &pItem ) )
						nValidation = ((const SfxUInt32Item*)pItem)->GetValue();
					else
						nValidation = 0;

					// 	EditEngine Defaults

					//	Hier auf keinen Fall SetParaAttribs, weil die EditEngine evtl.
					//	schon gefuellt ist (bei Edit-Zellen).
					//	SetParaAttribs wuerde dann den Inhalt aendern

					//! ER 30.08.00  The SetDefaults is now (since MUST/src602
					//! EditEngine changes) implemented as a SetParaAttribs.
					//! Any problems?

					pPattern->FillEditItemSet( pEditDefaults );
					pEngine->SetDefaults( *pEditDefaults );
					pLastPattern = pPattern;
					bLastIsSymbol = pPattern->IsSymbolFont();

					//	Background color must be known for automatic font color.
					//	For transparent cell background, the document background color must be used.

					Color aBackCol = ((const SvxBrushItem&)
									pPattern->GetItem( ATTR_BACKGROUND )).GetColor();
					ScModule* pScMod = SC_MOD();
					//	#105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
					if ( aBackCol.GetTransparency() > 0 ||
							Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
                        aBackCol.SetColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
					pEngine->SetBackgroundColor( aBackCol );

					//	Ausrichtung

                    eAttrAdjust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
									GetItem(ATTR_HOR_JUSTIFY)).GetValue();
                    if ( eAttrAdjust == SVX_HOR_JUSTIFY_REPEAT &&
                         static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() )
                    {
                        // #i31843# "repeat" with "line breaks" is treated as default alignment
                        eAttrAdjust = SVX_HOR_JUSTIFY_STANDARD;
                    }
				}

				//	UpdateSpellSettings enables online spelling if needed
				//	-> also call if attributes are unchanged

				UpdateSpellSettings( sal_True );	// uses pLastPattern

				//	Edit-Engine fuellen

				String aStr;
				if (bTextValid)
				{
					pEngine->SetText(aCurrentText);
					aStr = aCurrentText;
					bTextValid = sal_False;
					aCurrentText.Erase();
				}
				else
					aStr = GetEditText(pEngine);

				if (aStr.Len() > 3 && 					// Matrix-Formel ?
					aStr.GetChar(0) == '{' &&
					aStr.GetChar(1) == '=' &&
					aStr.GetChar(aStr.Len()-1) == '}')
				{
					aStr.Erase(0,1);
					aStr.Erase(aStr.Len()-1,1);
					pEngine->SetText(aStr);
					if ( pInputWin )
						pInputWin->SetTextString(aStr);
				}

				UpdateAdjust( cTyped );

				if ( bAutoComplete )
					GetColData();

                if ( ( aStr.GetChar(0) == '=' || aStr.GetChar(0) == '+' || aStr.GetChar(0) == '-' ) &&
                     !cTyped && !bCreatingFuncView )
					InitRangeFinder(aStr);				// Formel wird editiert -> RangeFinder

				bNewTable = sal_True;		//	-> PostEditView-Aufruf
			}
			else
			{
				bProtected = sal_True;
				eMode = SC_INPUT_NONE;
				StopInputWinEngine( sal_True );
				UpdateFormulaMode();
				if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
				{
					//	#97673# Prevent repeated error messages for the same cell from command events
					//	(for keyboard events, multiple messages are wanted).
					//	Set the flag before showing the error message because the command handler
					//	for the next IME command may be called when showing the dialog.
					if ( bFromCommand )
						bCommandErrorShown = sal_True;

					pActiveViewSh->GetActiveWin()->GrabFocus();
					pActiveViewSh->ErrorMessage(aTester.GetMessageId());
				}
			}
		}

		if (!bProtected && pInputWin)
			pInputWin->SetOkCancelMode();
	}

	return bNewTable;
}

void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
{
	DBG_ASSERT( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );

	EditEngine* pEngine = pEditView->GetEditEngine();
	sal_uInt16 nCount = pEngine->GetParagraphCount();
	if (nCount > 1)
	{
		xub_StrLen nParLen = pEngine->GetTextLen(rSel.nStartPara);
		while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
		{
			rSel.nStartPos -= nParLen + 1;			// incl. Leerzeichen vom Umbruch
			nParLen = pEngine->GetTextLen(++rSel.nStartPara);
		}

		nParLen = pEngine->GetTextLen(rSel.nEndPara);
		while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
		{
			rSel.nEndPos -= nParLen + 1;			// incl. Leerzeichen vom Umbruch
			nParLen = pEngine->GetTextLen(++rSel.nEndPara);
		}
	}

	ESelection aSel = pEditView->GetSelection();

	if (   rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
		|| rSel.nStartPos  != aSel.nStartPos  || rSel.nEndPos  != aSel.nEndPos )
		pEditView->SetSelection( rSel );
}

void ScInputHandler::SyncViews( EditView* pSourceView )
{
	ESelection aSel;

	if (pSourceView)
	{
		aSel = pSourceView->GetSelection();
		if (pTopView && pTopView != pSourceView)
			pTopView->SetSelection( aSel );
		if (pTableView && pTableView != pSourceView)
			lcl_SetTopSelection( pTableView, aSel );
	}
	else if (pTopView && pTableView)
	{
		aSel = pTopView->GetSelection();
		lcl_SetTopSelection( pTableView, aSel );
	}
}

IMPL_LINK( ScInputHandler, ModifyHdl, void *, EMPTYARG )
{
	if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
		 pEngine && pEngine->GetUpdateMode() && pInputWin )
	{
		//	#102745# update input line from ModifyHdl for changes that are not
		//	wrapped by DataChanging/DataChanged calls (like Drag&Drop)

		String aText = GetEditText(pEngine);
		lcl_RemoveTabs(aText);
		pInputWin->SetTextString(aText);
	}
	return 0;
}

sal_Bool ScInputHandler::DataChanging( sal_Unicode cTyped, sal_Bool bFromCommand )		// return sal_True = new view created
{
	bInOwnChange = sal_True;				// disable ModifyHdl (reset in DataChanged)

	if ( eMode == SC_INPUT_NONE )
		return StartTable( cTyped, bFromCommand );
	else
		return sal_False;
}

void ScInputHandler::DataChanged( sal_Bool bFromTopNotify, sal_Bool bSetModified )
{
	ImplCreateEditEngine();

	if (eMode==SC_INPUT_NONE)
		eMode = SC_INPUT_TYPE;

	if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
	{
		//	table EditEngine is formatted below, input line needs formatting after paste
		//	#i20282# not when called from the input line's modify handler
		pTopView->GetEditEngine()->QuickFormatDoc( sal_True );

		//	#i23720# QuickFormatDoc hides the cursor, but can't show it again because it
		//	can't safely access the EditEngine's current view, so the cursor has to be
		//	shown again here.
		pTopView->ShowCursor();
	}

    if (bSetModified)
        bModified = sal_True;
	bSelIsRef = sal_False;

	if ( pRangeFindList && !bInRangeUpdate )
		RemoveRangeFinder();					// Attribute und Markierung loeschen

	UpdateParenthesis();	//	Hervorhebung der Klammern neu

	// ER 31.08.00  New SetDefaults sets ParaAttribs, don't clear them away ...
//	RemoveAdjust();		//	#40255# harte Ausrichtungs-Attribute loeschen

	if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
	{
		String aText = GetEditText(pEngine);
		lcl_RemoveTabs(aText);

		if ( pInputWin )
			pInputWin->SetTextString(aText);
	}

		//	wenn der Cursor vor dem Absatzende steht, werden Teile rechts rausgeschoben
		//	(unabhaengig von eMode)		-> View anpassen!
		//	wenn der Cursor am Ende steht, reicht der Status-Handler an der ViewData

	//	#93767# first make sure the status handler is called now if the cursor
	//	is outside the visible area
	pEngine->QuickFormatDoc();

	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (pActiveView && pActiveViewSh)
	{
		ScViewData* pViewData = pActiveViewSh->GetViewData();

		sal_Bool bNeedGrow = ( nEditAdjust != SVX_ADJUST_LEFT );		// rechtsbuendig immer
		if (!bNeedGrow)
		{
				//	Cursor vor dem Ende?
			ESelection aSel = pActiveView->GetSelection();
			aSel.Adjust();
			bNeedGrow = ( aSel.nEndPos != pEngine->GetTextLen(aSel.nEndPara) );
		}
		if (!bNeedGrow)
		{
			bNeedGrow = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
		}
		if (bNeedGrow)
		{
			// adjust inplace view
			pViewData->EditGrowY();
			pViewData->EditGrowX();
		}
	}

	UpdateFormulaMode();
	bTextValid = sal_False;			// Aenderungen sind nur in der Edit-Engine
	bInOwnChange = sal_False;
}

void ScInputHandler::UpdateFormulaMode()
{
	SfxApplication* pSfxApp = SFX_APP();

    if ( pEngine->GetParagraphCount() == 1 &&
         ( pEngine->GetText((sal_uInt16)0).GetChar(0) == '=' ||
           pEngine->GetText((sal_uInt16)0).GetChar(0) == '+' ||
           pEngine->GetText((sal_uInt16)0).GetChar(0) == '-' ) &&
         !bProtected )
	{
		if (!bFormulaMode)
		{
			bFormulaMode = sal_True;
			pRefViewSh = pActiveViewSh;
			pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
			SC_MOD()->SetRefInputHdl(this);
			if (pInputWin)
				pInputWin->SetFormulaMode(sal_True);

			if ( bAutoComplete )
				GetFormulaData();

			UpdateParenthesis();
			UpdateAutoCorrFlag();
		}
	}
	else		// ausschalten
	{
		if (bFormulaMode)
		{
			ShowRefFrame();
			bFormulaMode = sal_False;
			pRefViewSh = NULL;
			pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
			SC_MOD()->SetRefInputHdl(NULL);
			if (pInputWin)
				pInputWin->SetFormulaMode(sal_False);
			UpdateAutoCorrFlag();
		}
	}
}

void ScInputHandler::ShowRefFrame()
{
    // #123169# Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
    // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
    // A local variable is used instead.
    ScTabViewShell* pVisibleSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
    if ( pRefViewSh && pRefViewSh != pVisibleSh )
	{
		sal_Bool bFound = sal_False;
		SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
		SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
		while ( pOneFrame && !bFound )
		{
			if ( pOneFrame == pRefFrame )
				bFound = sal_True;
			pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
		}

		if (bFound)
		{
			//	Hier wird sich darauf verlassen, dass Activate synchron funktioniert
			//	(dabei wird pActiveViewSh umgesetzt)

			pRefViewSh->SetActive();	// Appear und SetViewFrame

			//	pLastState wird im NotifyChange aus dem Activate richtig gesetzt
		}
		else
		{
			DBG_ERROR("ViewFrame fuer Referenzeingabe ist nicht mehr da");
		}
	}
}

void ScInputHandler::RemoveSelection()
{
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (!pActiveView)
		return;

	ESelection aSel = pActiveView->GetSelection();
	aSel.nStartPara = aSel.nEndPara;
	aSel.nStartPos  = aSel.nEndPos;
	if (pTableView)
		pTableView->SetSelection( aSel );
	if (pTopView)
		pTopView->SetSelection( aSel );
}

void ScInputHandler::InvalidateAttribs()
{
	SfxViewFrame* pViewFrm = SfxViewFrame::Current();
	if (pViewFrm)
	{
		SfxBindings& rBindings = pViewFrm->GetBindings();

		rBindings.Invalidate( SID_ATTR_CHAR_FONT );
		rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
		rBindings.Invalidate( SID_ATTR_CHAR_COLOR );

		rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
		rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
		rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
		rBindings.Invalidate( SID_ULINE_VAL_NONE );
		rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
		rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
		rBindings.Invalidate( SID_ULINE_VAL_DOTTED );

		rBindings.Invalidate( SID_HYPERLINK_GETLINK );
	}
}


//
//		--------------- public Methoden --------------------------------------------
//

void ScInputHandler::SetMode( ScInputMode eNewMode )
{
	if ( eMode == eNewMode )
		return;

	ImplCreateEditEngine();

	if (bProtected)
	{
		eMode = SC_INPUT_NONE;
		StopInputWinEngine( sal_True );
		if (pActiveViewSh)
			pActiveViewSh->GetActiveWin()->GrabFocus();
		return;
	}

	bInOwnChange = sal_True;				// disable ModifyHdl (reset below)

	ScInputMode eOldMode = eMode;
	eMode = eNewMode;
	if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
		StopInputWinEngine( sal_False );

	if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
	{
		if (eOldMode == SC_INPUT_NONE)		// not when switching between modes
		{
			if (StartTable(0, sal_False))		// 0 = look at existing document content for text or number
			{
				if (pActiveViewSh)
					pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
			}
		}

		sal_uInt16 nPara    = pEngine->GetParagraphCount()-1;
		xub_StrLen nLen = pEngine->GetText(nPara).Len();
		sal_uInt16 nCount   = pEngine->GetViewCount();

		for (sal_uInt16 i=0; i<nCount; i++)
		{
			if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
			{
				//	Selektion bleibt
			}
			else
			{
				pEngine->GetView(i)->
					SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
			}
			pEngine->GetView(i)->ShowCursor(sal_False);
		}
	}

	UpdateActiveView();
	if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
	{
		if (pTableView)
			pTableView->SetEditEngineUpdateMode(sal_True);
	}
	else
	{
		if (pTopView)
			pTopView->SetEditEngineUpdateMode(sal_True);
	}

	if (eNewMode != eOldMode)
		UpdateFormulaMode();

	bInOwnChange = sal_False;
}

//----------------------------------------------------------------------------------------

//	lcl_IsNumber - sal_True, wenn nur Ziffern (dann keine Autokorrektur)

sal_Bool lcl_IsNumber(const String& rString)
{
	xub_StrLen nLen = rString.Len();
	for (xub_StrLen i=0; i<nLen; i++)
	{
		sal_Unicode c = rString.GetChar(i);
		if ( c < '0' || c > '9' )
			return sal_False;
	}
	return sal_True;
}

void lcl_SelectionToEnd( EditView* pView )
{
    if ( pView )
    {
        EditEngine* pEngine = pView->GetEditEngine();
        sal_uInt16 nParCnt = pEngine->GetParagraphCount();
        if ( nParCnt == 0 )
            nParCnt = 1;
        ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) );   // empty selection, cursor at the end
        pView->SetSelection( aSel );
    }
}

void ScInputHandler::EnterHandler( sal_uInt8 nBlockMode )
{
	//	#62806# Bei Makro-Aufrufen fuer Gueltigkeit kann Tod und Teufel passieren,
	//	darum dafuer sorgen, dass EnterHandler nicht verschachtelt gerufen wird:

	if (bInEnterHandler) return;
	bInEnterHandler = sal_True;
	bInOwnChange = sal_True;				// disable ModifyHdl (reset below)

	ImplCreateEditEngine();

	sal_Bool bMatrix = ( nBlockMode == SC_ENTER_MATRIX );

	SfxApplication*	pSfxApp		= SFX_APP();
	EditTextObject* pObject		= NULL;
	ScPatternAttr*	pCellAttrs	= NULL;
	sal_Bool			bAttrib		= sal_False;	// Formatierung vorhanden ?
	sal_Bool			bForget		= sal_False;	// wegen Gueltigkeit streichen ?

	String aString = GetEditText(pEngine);
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	if (bModified && pActiveView && aString.Len() && !lcl_IsNumber(aString))
	{
        if ( pColumnData && nAutoPos != SCPOS_INVALID )
        {
            // #i47125# If AutoInput appended something, do the final AutoCorrect
            // with the cursor at the end of the input.

            lcl_SelectionToEnd(pTopView);
            lcl_SelectionToEnd(pTableView);
        }

		if (pTopView)
			pTopView->CompleteAutoCorrect();	// #59759# CompleteAutoCorrect fuer beide Views
		if (pTableView)
			pTableView->CompleteAutoCorrect();
		aString = GetEditText(pEngine);
	}
	lcl_RemoveTabs(aString);

	//	Test, ob zulaessig (immer mit einfachem String)

	if ( bModified && nValidation && pActiveViewSh )
	{
		ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
		const ScValidationData*	pData = pDoc->GetValidationEntry( nValidation );
		if (pData && pData->HasErrMsg())
		{
            // #i67990# don't use pLastPattern in EnterHandler
            const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
			sal_Bool bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );

			if (!bOk)
			{
				if ( pActiveViewSh )				// falls aus MouseButtonDown gekommen
					pActiveViewSh->StopMarking();	// (die InfoBox verschluckt das MouseButtonUp)

					//!	es gibt noch Probleme, wenn die Eingabe durch Aktivieren einer
					//!	anderen View ausgeloest wurde

				Window* pParent = Application::GetDefDialogParent();
				if ( pData->DoError( pParent, aString, aCursorPos ) )
					bForget = sal_True;					// Eingabe nicht uebernehmen
			}
		}
	}

    // check for input into DataPilot table

	if ( bModified && pActiveViewSh && !bForget )
	{
		ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
        ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
        if ( pDPObj )
        {
            // any input within the DataPilot table is either a valid renaming
            // or an invalid action - normal cell input is always aborted

            pActiveViewSh->DataPilotInput( aCursorPos, aString );
            bForget = sal_True;
        }
	}

	pEngine->CompleteOnlineSpelling();
	sal_Bool bSpellErrors = !bFormulaMode && pEngine->HasOnlineSpellErrors();
	if ( bSpellErrors )
	{
		//	#i3820# If the spell checker flags numerical input as error,
		//	it still has to be treated as number, not EditEngine object.

        if ( pActiveViewSh )
		{
			ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
            // #i67990# don't use pLastPattern in EnterHandler
            const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
			SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
			// without conditional format, as in ScColumn::SetString
            sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
			double nVal;
			if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
			{
				bSpellErrors = sal_False;		// ignore the spelling errors
			}
		}
	}

	//	After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
	//	SetUpdateMode must come after CompleteOnlineSpelling.
	//	The view is hidden in any case below (Broadcast).
	pEngine->SetUpdateMode( sal_False );

	if ( bModified && !bForget )			// was wird eingeben (Text/Objekt) ?
	{
		sal_uInt16 nParCnt = pEngine->GetParagraphCount();
		if ( nParCnt == 0 )
			nParCnt = 1;
		ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
		SfxItemSet aOldAttribs = pEngine->GetAttribs( aSel );
		const SfxPoolItem* pItem = NULL;

		//	find common (cell) attributes before RemoveAdjust

		if ( pActiveViewSh )
		{
			SfxItemSet* pCommonAttrs = NULL;
			for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
			{
				SfxItemState eState = aOldAttribs.GetItemState( nId, sal_False, &pItem );
				if ( eState == SFX_ITEM_SET &&
						nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
						nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
							*pItem != pEditDefaults->Get(nId) )
				{
					if ( !pCommonAttrs )
						pCommonAttrs = new SfxItemSet( pEngine->GetEmptyItemSet() );
					pCommonAttrs->Put( *pItem );
				}
			}

			if ( pCommonAttrs )
			{
				ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
				pCellAttrs = new ScPatternAttr( pDoc->GetPool() );
				pCellAttrs->GetFromEditItemSet( pCommonAttrs );
				delete pCommonAttrs;
			}
		}

		//	clear ParaAttribs (including adjustment)

		RemoveAdjust();

		//	check if EditObject is needed

		if ( bSpellErrors || nParCnt > 1 )
			bAttrib = sal_True;
		else
		{
			for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
			{
				SfxItemState eState = aOldAttribs.GetItemState( nId, sal_False, &pItem );
				if (eState == SFX_ITEM_DONTCARE)
					bAttrib = sal_True;
				else if (eState == SFX_ITEM_SET)
				{
					//	keep same items in EditEngine as in ScEditAttrTester
					if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
						 nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
					{
						if ( *pItem != pEditDefaults->Get(nId) )
							bAttrib = sal_True;
					}
				}
			}

			//	Feldbefehle enthalten?

			SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, sal_False );
			if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
				bAttrib = sal_True;

			//	not converted characters?

			SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, sal_False );
			if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET )
				bAttrib = sal_True;

			//	Formeln immer als Formeln erkennen (#38309#)
			//	(der Test vorher ist trotzdem noetig wegen Zell-Attributen)
		}

		if (bMatrix)
			bAttrib = sal_False;

		if (bAttrib)
		{
			sal_uLong nCtrl = pEngine->GetControlWord();
			sal_uLong nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
			if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
				pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
			pObject = pEngine->CreateTextObject();
		}
		else if (bAutoComplete)			// Gross-/Kleinschreibung anpassen
		{
			if (pColumnData)
				pColumnData->GetExactMatch( aString );

			//!	effizienter in der Liste suchen (ScUserList, nur einmal ToUpper)

			sal_uInt16 nIndex;
			ScUserListData* pData = ScGlobal::GetUserList()->GetData(aString);
			if ( pData && pData->GetSubIndex( aString, nIndex ) )
				aString = pData->GetSubStr( nIndex );
		}
	}

	//	don't rely on ShowRefFrame switching the active view synchronously
	//	execute the function directly on the correct view's bindings instead
	//	pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
	ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;

	if (bFormulaMode)
	{
		ShowRefFrame();

		if (pExecuteSh)
        {
			pExecuteSh->SetTabNo(aCursorPos.Tab());
            pExecuteSh->ActiveGrabFocus();
        }

		bFormulaMode = sal_False;
		pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
		SC_MOD()->SetRefInputHdl(NULL);
		if (pInputWin)
			pInputWin->SetFormulaMode(sal_False);
		UpdateAutoCorrFlag();
	}
	pRefViewSh = NULL;			// auch ohne FormulaMode wegen Funktions-AP
	DeleteRangeFinder();
	ResetAutoPar();

	sal_Bool bOldMod = bModified;

	bModified = sal_False;
	bSelIsRef = sal_False;
	eMode 	  = SC_INPUT_NONE;
	StopInputWinEngine( sal_True );

    // #123344# Text input (through number formats) or ApplySelectionPattern modify
    // the cell's attributes, so pLastPattern is no longer valid
    pLastPattern = NULL;

	if (bOldMod && !bProtected && !bForget)
	{
		//	keine typographische Anfuehrungszeichen in Formeln

		if ( aString.GetChar(0) == '=' )
		{
			SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get()->GetAutoCorrect();
			if ( pAuto )
			{
				sal_Unicode cReplace = pAuto->GetStartDoubleQuote();
				if( !cReplace )
                    cReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkStart().GetChar(0);
				if ( cReplace != '"' )
					aString.SearchAndReplaceAll( cReplace, '"' );

				cReplace = pAuto->GetEndDoubleQuote();
				if( !cReplace )
                    cReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkEnd().GetChar(0);
				if ( cReplace != '"' )
					aString.SearchAndReplaceAll( cReplace, '"' );

				cReplace = pAuto->GetStartSingleQuote();
				if( !cReplace )
                    cReplace = ScGlobal::pLocaleData->getQuotationMarkStart().GetChar(0);
				if ( cReplace != '\'' )
					aString.SearchAndReplaceAll( cReplace, '\'' );

				cReplace = pAuto->GetEndSingleQuote();
				if( !cReplace )
                    cReplace = ScGlobal::pLocaleData->getQuotationMarkEnd().GetChar(0);
				if ( cReplace != '\'' )
					aString.SearchAndReplaceAll( cReplace, '\'' );
			}
		}

		pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT ) );

		if ( pExecuteSh )
		{
			SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();

			sal_uInt16 nId = FID_INPUTLINE_ENTER;
			if ( nBlockMode == SC_ENTER_BLOCK )
				nId = FID_INPUTLINE_BLOCK;
			else if ( nBlockMode == SC_ENTER_MATRIX )
				nId = FID_INPUTLINE_MATRIX;

			ScInputStatusItem aItem( FID_INPUTLINE_STATUS,
									 aCursorPos, aCursorPos, aCursorPos,
									 aString, pObject );
			const SfxPoolItem* aArgs[2];
			aArgs[0] = &aItem;
			aArgs[1] = NULL;
			rBindings.Execute( nId, aArgs );
		}

		delete pLastState;		// pLastState enthaelt noch den alten Text
		pLastState = NULL;
	}
	else
		pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );

	if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
	{
		//	mit Eingabe zusammenfassen ?
		pExecuteSh->ApplySelectionPattern( *pCellAttrs, sal_True, sal_True );
		pExecuteSh->AdjustBlockHeight();
	}

	delete pCellAttrs;
	delete pObject;

	HideTip();
    HideTipBelow();

	nFormSelStart = nFormSelEnd = 0;
	aFormText.Erase();

	bInOwnChange = sal_False;
	bInEnterHandler = sal_False;
}

void ScInputHandler::CancelHandler()
{
	bInOwnChange = sal_True;				// disable ModifyHdl (reset below)

	ImplCreateEditEngine();

	bModified = sal_False;

	//	don't rely on ShowRefFrame switching the active view synchronously
	//	execute the function directly on the correct view's bindings instead
	//	pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
	ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;

	if (bFormulaMode)
	{
		ShowRefFrame();
		if (pExecuteSh)
        {
			pExecuteSh->SetTabNo(aCursorPos.Tab());
            pExecuteSh->ActiveGrabFocus();
        }
		bFormulaMode = sal_False;
		SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
		SC_MOD()->SetRefInputHdl(NULL);
		if (pInputWin)
			pInputWin->SetFormulaMode(sal_False);
		UpdateAutoCorrFlag();
	}
	pRefViewSh = NULL;			// auch ohne FormulaMode wegen Funktions-AP
	DeleteRangeFinder();
	ResetAutoPar();

	eMode = SC_INPUT_NONE;
	StopInputWinEngine( sal_True );
	if (pExecuteSh)
		pExecuteSh->StopEditShell();

	aCursorPos.Set(MAXCOL+1,0,0);		// Flag, dass ungueltig
	pEngine->SetText(String());

	if ( !pLastState && pExecuteSh )
		pExecuteSh->UpdateInputHandler( sal_True );		// Status neu holen
	else
		NotifyChange( pLastState, sal_True );

	nFormSelStart = nFormSelEnd = 0;
	aFormText.Erase();

	bInOwnChange = sal_False;
}

sal_Bool ScInputHandler::IsModalMode( SfxObjectShell* pDocSh )
{
	//	Referenzen auf unbenanntes Dokument gehen nicht

	return bFormulaMode && pRefViewSh
			&& pRefViewSh->GetViewData()->GetDocument()->GetDocumentShell() != pDocSh
			&& !pDocSh->HasName();
}

void ScInputHandler::AddRefEntry()
{
    const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
	UpdateActiveView();
	if (!pTableView && !pTopView)
		return; 							// z.B. FillMode

	DataChanging(); 						// kann nicht neu sein

	RemoveSelection();
	if (pTableView)
        pTableView->InsertText( cSep, sal_False );
	if (pTopView)
        pTopView->InsertText( cSep, sal_False );

	DataChanged();
}

void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc )
{
	HideTip();

	sal_Bool bOtherDoc = ( pRefViewSh &&
						pRefViewSh->GetViewData()->GetDocument() != pDoc );
	if (bOtherDoc)
		if (!pDoc->GetDocumentShell()->HasName())
		{
			//	Referenzen auf unbenanntes Dokument gehen nicht
			//	(SetReference sollte dann auch nicht gerufen werden)

			return;
		}

	UpdateActiveView();
	if (!pTableView && !pTopView)
		return; 							// z.B. FillMode

	//	nie das "=" ueberschreiben!
	EditView* pActiveView = pTopView ? pTopView : pTableView;
	ESelection aSel = pActiveView->GetSelection();
	aSel.Adjust();
	if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
		return;

	DataChanging(); 						// kann nicht neu sein

			//	Selektion umdrehen, falls rueckwaerts (noetig ???)

	if (pTableView)
	{
        ESelection aTabSel = pTableView->GetSelection();
        if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
		{
            aTabSel.Adjust();
            pTableView->SetSelection(aTabSel);
		}
	}
	if (pTopView)
	{
        ESelection aTopSel = pTopView->GetSelection();
        if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
		{
            aTopSel.Adjust();
            pTopView->SetSelection(aTopSel);
		}
	}

	//	String aus Referenz erzeugen

	String aRefStr;
	const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
	if (bOtherDoc)
	{
		//	Referenz auf anderes Dokument

		DBG_ASSERT(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");

		String aTmp;
		rRef.Format( aTmp, SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails );		// immer 3d

		SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
        // #i75893# convert escaped URL of the document to something user friendly
//       String aFileName = pObjSh->GetMedium()->GetName();
        String aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );

		aRefStr = '\'';
		aRefStr += aFileName;
		aRefStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "'#" ));
		aRefStr += aTmp;
	}
	else
	{
		if ( ( rRef.aStart.Tab() != aCursorPos.Tab() ||
				rRef.aStart.Tab() != rRef.aEnd.Tab() ) && pDoc )
			rRef.Format( aRefStr, SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails );
		else
			rRef.Format( aRefStr, SCA_VALID, pDoc, aAddrDetails );
	}

	if (pTableView || pTopView)
	{
		if (pTableView)
			pTableView->InsertText( aRefStr, sal_True );
		if (pTopView)
			pTopView->InsertText( aRefStr, sal_True );

		DataChanged();
	}

	bSelIsRef = sal_True;
}

void ScInputHandler::InsertFunction( const String& rFuncName, sal_Bool bAddPar )
{
	if ( eMode == SC_INPUT_NONE )
	{
		DBG_ERROR("InsertFunction, nicht im Eingabemodus");
		return;
	}

	UpdateActiveView();
	if (!pTableView && !pTopView)
		return; 							// z.B. FillMode

	DataChanging(); 						// kann nicht neu sein

	String aText = rFuncName;
	if (bAddPar)
		aText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "()" ));

	if (pTableView)
	{
		pTableView->InsertText( aText, sal_False );
		if (bAddPar)
		{
			ESelection aSel = pTableView->GetSelection();
			--aSel.nStartPos;
			--aSel.nEndPos;
			pTableView->SetSelection(aSel);
		}
	}
	if (pTopView)
	{
		pTopView->InsertText( aText, sal_False );
		if (bAddPar)
		{
			ESelection aSel = pTopView->GetSelection();
			--aSel.nStartPos;
			--aSel.nEndPos;
			pTopView->SetSelection(aSel);
		}
	}

	DataChanged();

	if (bAddPar)
		AutoParAdded();
}

void ScInputHandler::ClearText()
{
	if ( eMode == SC_INPUT_NONE )
	{
		DBG_ERROR("ClearText, nicht im Eingabemodus");
		return;
	}

	UpdateActiveView();
	if (!pTableView && !pTopView)
		return; 							// z.B. FillMode

	DataChanging(); 						// darf nicht neu sein

	String aEmpty;
	if (pTableView)
	{
		pTableView->GetEditEngine()->SetText( aEmpty );
		pTableView->SetSelection( ESelection(0,0, 0,0) );
	}
	if (pTopView)
	{
		pTopView->GetEditEngine()->SetText( aEmpty );
		pTopView->SetSelection( ESelection(0,0, 0,0) );
	}

	DataChanged();
}

sal_Bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, sal_Bool bStartEdit /* = sal_False */ )
{
	if (!bOptLoaded)
	{
		bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
		bOptLoaded = sal_True;
	}

	KeyCode aCode = rKEvt.GetKeyCode();
	sal_uInt16 nModi  = aCode.GetModifier();
	sal_Bool bShift   = aCode.IsShift();
	sal_Bool bControl = aCode.IsMod1();
	sal_Bool bAlt	  = aCode.IsMod2();
	sal_uInt16 nCode  = aCode.GetCode();
	sal_Unicode nChar = rKEvt.GetCharCode();

	//	Alt-Return is accepted, everything else with ALT, or CTRL-TAB are not:
	if (( bAlt && !bControl && nCode != KEY_RETURN ) ||
			( bControl && aCode.GetCode() == KEY_TAB ))
		return sal_False;

	sal_Bool bInputLine = ( eMode==SC_INPUT_TOP );

	sal_Bool bUsed = sal_False;
	sal_Bool bSkip = sal_False;
	sal_Bool bDoEnter = sal_False;

	switch ( nCode )
	{
		case KEY_RETURN:
			if (bControl && !bShift && !bInputLine)
				bDoEnter = sal_True;
			else if ( nModi == 0 && nTipVisible && pFormulaData && nAutoPos != SCPOS_INVALID )
			{
				PasteFunctionData();
				bUsed = sal_True;
			}
			else if ( nModi == 0 && nTipVisible && aManualTip.Len() )
			{
				PasteManualTip();
				bUsed = sal_True;
			}
			else
			{
				sal_uInt8 nMode = SC_ENTER_NORMAL;
				if ( bShift && bControl )
					nMode = SC_ENTER_MATRIX;
				else if ( bAlt )
					nMode = SC_ENTER_BLOCK;
				EnterHandler( nMode );

				if (pActiveViewSh)
					pActiveViewSh->MoveCursorEnter( bShift && !bControl );

				bUsed = sal_True;
			}
			break;
		case KEY_TAB:
			if (!bControl && !bAlt)
			{
				if ( pFormulaData && nTipVisible && nAutoPos != SCPOS_INVALID )
				{
					//	blaettern

					NextFormulaEntry( bShift );
				}
				else if ( pColumnData && bUseTab && nAutoPos != SCPOS_INVALID )
				{
					//	in den Eintraegen der AutoEingabe blaettern

					NextAutoEntry( bShift );
				}
				else
				{
					EnterHandler();

					//	TabKeyInput gibt auf manchen Rechnern unter W95 Stackueberlaeufe,
					//	darum direkter Aufruf:
					if (pActiveViewSh)
						pActiveViewSh->FindNextUnprot( bShift );
				}
				bUsed = sal_True;
			}
			break;
		case KEY_ESCAPE:
			if ( nTipVisible )
			{
				HideTip();
				bUsed = sal_True;
			}
            else if( nTipVisibleSec )
            {
                HideTipBelow();
                bUsed = sal_True;
            }
			else if (eMode != SC_INPUT_NONE)
			{
				CancelHandler();
				bUsed = sal_True;
			}
			else
				bSkip = sal_True;
			break;
		case KEY_F2:
			if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
			{
				eMode = SC_INPUT_TYPE;
				bUsed = sal_True;
			}
			break;
	}

	//	Cursortasten nur ausfuehren, wenn schon im Edit-Modus
	//	z.B. wegen Shift-Ctrl-PageDn (ist nicht als Accelerator definiert)

	sal_Bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
	sal_Bool bInsKey = ( nCode == KEY_INSERT && !nModi );	// Insert wie Cursortasten behandeln
	if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
					( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
	{
		HideTip();
        HideTipBelow();

		if (bSelIsRef)
		{
			RemoveSelection();
			bSelIsRef = sal_False;
		}

		UpdateActiveView();
		sal_Bool bNewView = DataChanging( nChar );

		if (bProtected)								// Zelle geschuetzt?
			bUsed = sal_True;							// Key-Event nicht weiterleiten
		else										// Aenderungen erlaubt
		{
			if (bNewView )							// neu anlegen
			{
				if (pActiveViewSh)
					pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
				UpdateActiveView();
				if (eMode==SC_INPUT_NONE)
					if (pTableView || pTopView)
					{
						String aStrLoP;

						if ( bStartEdit && bCellHasPercentFormat && ((nChar >= '0' && nChar <= '9') || nChar == '-') )
							aStrLoP = '%';

						if (pTableView)
						{
							pTableView->GetEditEngine()->SetText( aStrLoP );
							if ( aStrLoP.Len() )
								pTableView->SetSelection( ESelection(0,0, 0,0) );	// before the '%'

							// don't call SetSelection if the string is empty anyway,
							// to avoid breaking the bInitial handling in ScViewData::EditGrowY
						}
						if (pTopView)
						{
							pTopView->GetEditEngine()->SetText( aStrLoP );
							if ( aStrLoP.Len() )
								pTopView->SetSelection( ESelection(0,0, 0,0) );		// before the '%'
						}
					}
				SyncViews();
			}

			if (pTableView || pTopView)
			{
//				pActiveView->SetEditEngineUpdateMode(sal_True); 		//! gibt Muell !!!!

				if (bDoEnter)
				{
					if (pTableView)
						if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
							bUsed = sal_True;
					if (pTopView)
						if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
							bUsed = sal_True;
				}
				else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
				{
					SkipClosingPar();
					bUsed = sal_True;
				}
				else
				{
					if (pTableView)
						if ( pTableView->PostKeyEvent( rKEvt ) )
							bUsed = sal_True;
					if (pTopView)
						if ( pTopView->PostKeyEvent( rKEvt ) )
							bUsed = sal_True;
				}

				//	Auto-Eingabe:

				if ( bUsed && bAutoComplete )
				{
					bUseTab = sal_False;
					nAutoPos = SCPOS_INVALID;						// do not search further

					KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
					if ( nChar && nChar != 8 && nChar != 127 &&		// no 'backspace', no 'delete'
						 KEYFUNC_CUT != eFunc)						// and no 'CTRL-X'
					{
						if (bFormulaMode)
							UseFormulaData();
						else
							UseColData();
					}
				}

				//	when the selection is changed manually or an opening parenthesis
				//	is typed, stop overwriting parentheses
				if ( bUsed && nChar == '(' )
					ResetAutoPar();

				if ( KEY_INSERT == nCode )
				{
					SfxViewFrame* pViewFrm = SfxViewFrame::Current();
					if (pViewFrm)
						pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
				}
                if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
                {
                    ShowTipCursor();
                }
			}

            // #i114511# don't count cursor keys as modification
            sal_Bool bSetModified = !bCursorKey;
            DataChanged(sal_False, bSetModified);  // also calls UpdateParenthesis()
			InvalidateAttribs();		//! in DataChanged ?
		}
	}

	if (pTopView && eMode != SC_INPUT_NONE)
		SyncViews();

	return bUsed;
}

sal_Bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, sal_Bool bForce )
{
	sal_Bool bUsed = sal_False;

	if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
	{
		//	#90346# for COMMAND_CURSORPOS, do as little as possible, because
		//	with remote VCL, even a ShowCursor will generate another event.
		if ( eMode != SC_INPUT_NONE )
		{
			UpdateActiveView();
			if (pTableView || pTopView)
			{
				if (pTableView)
					pTableView->Command( rCEvt );
				else if (pTopView)						// call only once
					pTopView->Command( rCEvt );
				bUsed = sal_True;
			}
		}
	}
	else
	{
		if ( bForce || eMode != SC_INPUT_NONE )
		{
			if (!bOptLoaded)
			{
				bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
				bOptLoaded = sal_True;
			}

			HideTip();
            HideTipBelow();

			if ( bSelIsRef )
			{
				RemoveSelection();
				bSelIsRef = sal_False;
			}

			UpdateActiveView();
			sal_Bool bNewView = DataChanging( 0, sal_True );

			if (bProtected)								// cell protected
				bUsed = sal_True;							// event is used
			else										// changes allowed
			{
				if (bNewView)							// create new edit view
				{
					if (pActiveViewSh)
						pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
					UpdateActiveView();
					if (eMode==SC_INPUT_NONE)
						if (pTableView || pTopView)
						{
							String aStrLoP;
							if (pTableView)
							{
								pTableView->GetEditEngine()->SetText( aStrLoP );
								pTableView->SetSelection( ESelection(0,0, 0,0) );
							}
							if (pTopView)
							{
								pTopView->GetEditEngine()->SetText( aStrLoP );
								pTopView->SetSelection( ESelection(0,0, 0,0) );
							}
						}
					SyncViews();
				}

				if (pTableView || pTopView)
				{
					if (pTableView)
						pTableView->Command( rCEvt );
					if (pTopView)
						pTopView->Command( rCEvt );

					bUsed = sal_True;

					if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
					{
						//	AutoInput after ext text input

						nAutoPos = SCPOS_INVALID;
						if (bFormulaMode)
							UseFormulaData();
						else
							UseColData();
					}
				}

				DataChanged();				//	calls UpdateParenthesis()
				InvalidateAttribs();		//! in DataChanged ?
			}
		}

		if (pTopView && eMode != SC_INPUT_NONE)
			SyncViews();
	}

	return bUsed;
}

void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
								   sal_Bool bForce, ScTabViewShell* pSourceSh,
                                   sal_Bool bStopEditing)
{
	//	#62806# Wenn der Aufruf aus einem Makro-Aufruf im EnterHandler kommt,
	//	gleich abbrechen und nicht den Status durcheinander bringen
	if (bInEnterHandler)
		return;

	sal_Bool bRepeat = (pState == pLastState);
	if (!bRepeat && pState && pLastState)
        bRepeat = sal::static_int_cast<sal_Bool>(*pState == *pLastState);
	if (bRepeat && !bForce)
		return;

	bInOwnChange = sal_True;				// disable ModifyHdl (reset below)

	if ( pState && !pLastState )		// wieder enablen
		bForce = sal_True;

	sal_Bool bHadObject = pLastState && pLastState->GetEditData();

	//! Before EditEngine gets eventually created (so it gets the right pools)
	if ( pSourceSh )
		pActiveViewSh = pSourceSh;
	else
		pActiveViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current());

	ImplCreateEditEngine();

	if ( pState != pLastState )
	{
		delete pLastState;
		pLastState = pState ? new ScInputHdlState( *pState ) : NULL;
	}

	if ( pState && pActiveViewSh )
	{
		ScModule* pScMod = SC_MOD();

		if ( pState )
		{
			sal_Bool bIgnore = sal_False;

			//	hier auch fremde Referenzeingabe beruecksichtigen (z.B. Funktions-AP),
			//	FormEditData falls gerade von der Hilfe auf Calc umgeschaltet wird:

			if ( !bFormulaMode && !pScMod->IsFormulaMode() && !pScMod->GetFormEditData() )
			{
				if ( bModified )
				{
					if (pState->GetPos() != aCursorPos)
					{
						if (!bProtected)
							EnterHandler();
					}
					else
						bIgnore = sal_True;
				}

				if ( !bIgnore /* || bRepeat */ )
				{
					const ScAddress& 		rSPos	= pState->GetStartPos();
					const ScAddress& 		rEPos	= pState->GetEndPos();
					const EditTextObject*	pData	= pState->GetEditData();
					String					aString = pState->GetString();
					sal_Bool					bTxtMod = sal_False;
					ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
					ScDocument* pDoc = pDocSh->GetDocument();

					aCursorPos	= pState->GetPos();

					if ( pData /* || bRepeat */ )
						bTxtMod = sal_True;
					else if ( bHadObject )
						bTxtMod = sal_True;
					else if ( bTextValid )
						bTxtMod = ( aString != aCurrentText );
					else
						bTxtMod = ( aString != GetEditText(pEngine) );

					if ( bTxtMod || bForce )
					{
						if (pData)
						{
							pEngine->SetText( *pData );
							aString = GetEditText(pEngine);
							lcl_RemoveTabs(aString);
							bTextValid = sal_False;
							aCurrentText.Erase();
						}
						else
						{
							aCurrentText = aString;
							bTextValid = sal_True;				//! erst nur als String merken
						}

						if ( pInputWin )
							pInputWin->SetTextString(aString);
					}

					if ( pInputWin )						// Bereichsanzeige
					{
						String aPosStr;
						const ScAddress::Details aAddrDetails( pDoc, aCursorPos );

						//	Ist der Bereich ein Name?
						//!	per Timer suchen ???

						if ( pActiveViewSh )
							pActiveViewSh->GetViewData()->GetDocument()->
								GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );

						if ( !aPosStr.Len() )			// kein Name -> formatieren
						{
							sal_uInt16 nFlags = 0;
							if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
								nFlags |= SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;
							if ( rSPos != rEPos )
							{
								ScRange r(rSPos, rEPos);
								nFlags |= (nFlags << 4);
								r.Format( aPosStr, SCA_VALID | nFlags, pDoc, aAddrDetails );
							}
							else
								aCursorPos.Format( aPosStr, SCA_VALID | nFlags, pDoc, aAddrDetails );
						}
						//IAccessibility2 Implementation 2009-----
						// Disable the accessible VALUE_CHANGE event
						sal_Bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(sal_False);
						pInputWin->SetAccessibilityEventsSuppressed(sal_True);
						pInputWin->SetPosString(aPosStr);
						pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
						//-----IAccessibility2 Implementation 2009
						pInputWin->SetSumAssignMode();
					}

                    if (bStopEditing)
					    SFX_APP()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );

					//	As long as the content is not edited, turn off online spelling.
					//	Online spelling is turned back on in StartTable, after setting
					//	the right language from cell attributes.

					sal_uLong nCntrl = pEngine->GetControlWord();
					if ( nCntrl & EE_CNTRL_ONLINESPELLING )
						pEngine->SetControlWord( nCntrl & ~EE_CNTRL_ONLINESPELLING );

					bModified = sal_False;
					bSelIsRef = sal_False;
					bProtected = sal_False;
					bCommandErrorShown = sal_False;
				}
			}
		}

//		bProtected = sal_False;

		if ( pInputWin)
		{
			if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())	//BugID 54702
			{															//Wenn RefDialog offen, dann nicht enablen
				if ( !pInputWin->IsEnabled())
				{
					pInputWin->Enable();
					if(pDelayTimer )
					{
						DELETEZ( pDelayTimer );
					}
				}
			}
			else if(pScMod->IsRefDialogOpen())
			{									// Da jedes Dokument eigenes InputWin hat, sollte
				if ( !pDelayTimer )				// nochmals Timer gestartet werden, da sonst Ein-
				{								// gabezeile evt. noch aktiv ist.
					pDelayTimer = new Timer;
					pDelayTimer->SetTimeout( 500 ); // 100ms Verzoegerung
					pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
					pDelayTimer->Start();
				}
			}
		}
	}
	else // !pState || !pActiveViewSh
	{
		if ( !pDelayTimer )
		{
			pDelayTimer = new Timer;
			pDelayTimer->SetTimeout( 500 ); // 100ms Verzoegerung
			pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
			pDelayTimer->Start();
		}
	}

	HideTip();
    HideTipBelow();
	bInOwnChange = sal_False;
}

void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
{
    eAttrAdjust = eJust;
    UpdateAdjust( 0 );
}

void ScInputHandler::ResetDelayTimer()
{
	if(pDelayTimer!=NULL)
	{
		DELETEZ( pDelayTimer );

		if ( pInputWin)
		{
			pInputWin->Enable();
		}
	}
}

IMPL_LINK( ScInputHandler, DelayTimer, Timer*, pTimer )
{
	if ( pTimer == pDelayTimer )
	{
		DELETEZ( pDelayTimer );

		if ( NULL == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
		{
			//!	new method at ScModule to query if function autopilot is open

			SfxViewFrame* pViewFrm = SfxViewFrame::Current();
			if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
			{
				if ( pInputWin)
				{
					pInputWin->EnableButtons( sal_False );
					pInputWin->Disable();
				}
			}
			else if ( !bFormulaMode )	// #39210# Formel auch z.B. bei Hilfe behalten
			{
				bInOwnChange = sal_True;	// disable ModifyHdl (reset below)

				pActiveViewSh = NULL;
				pEngine->SetText( EMPTY_STRING );
				if ( pInputWin )
				{
					pInputWin->SetPosString( EMPTY_STRING );
					pInputWin->SetTextString( EMPTY_STRING );
					pInputWin->Disable();
				}

				bInOwnChange = sal_False;
			}
		}
	}
	return 0;
}

void ScInputHandler::InputSelection( EditView* pView )
{
	SyncViews( pView );
    ShowTipCursor();
	UpdateParenthesis();	//	Selektion geaendert -> Klammer-Hervorhebung neu

	//	when the selection is changed manually, stop overwriting parentheses
	ResetAutoPar();
}

void ScInputHandler::InputChanged( EditView* pView, sal_Bool bFromNotify )
{
	ESelection aSelection = pView->GetSelection();

	UpdateActiveView();

	// #i20282# DataChanged needs to know if this is from the input line's modify handler
	sal_Bool bFromTopNotify = ( bFromNotify && pView == pTopView );

	sal_Bool bNewView = DataChanging();						//!	kann das hier ueberhaupt sein?
	aCurrentText = pView->GetEditEngine()->GetText();	// auch den String merken
	pEngine->SetText( aCurrentText );
	DataChanged( bFromTopNotify );
	bTextValid = sal_True;		// wird in DataChanged auf sal_False gesetzt

	if ( pActiveViewSh )
	{
		ScViewData* pViewData = pActiveViewSh->GetViewData();
		if ( bNewView )
			pViewData->GetDocShell()->PostEditView( pEngine, aCursorPos );

		pViewData->EditGrowY();
		pViewData->EditGrowX();
	}

	SyncViews( pView );
}

const String& ScInputHandler::GetEditString()
{
	if (pEngine)
	{
		aCurrentText = pEngine->GetText();		// immer neu aus Engine
		bTextValid = sal_True;
	}

	return aCurrentText;
}

Size ScInputHandler::GetTextSize()
{
	Size aSize;
	if ( pEngine )
		aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );

	return aSize;
}

sal_Bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
{
	sal_Bool bRet = sal_False;
	if (pEngine)
	{
		//	Feldbefehle enthalten?

		sal_uInt16 nParCnt = pEngine->GetParagraphCount();
		SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
		SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, sal_False );
		if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
		{
			//	Inhalt kopieren

			EditTextObject* pObj = pEngine->CreateTextObject();
			rDestEngine.SetText(*pObj);
			delete pObj;

			//	Attribute loeschen

			for (sal_uInt16 i=0; i<nParCnt; i++)
				rDestEngine.QuickRemoveCharAttribs( i );

			//	Absaetze zusammenfassen

			while ( nParCnt > 1 )
			{
				xub_StrLen nLen = rDestEngine.GetTextLen( (sal_uInt16)0 );
				ESelection aSel( 0,nLen, 1,0 );
				rDestEngine.QuickInsertText( ' ', aSel );		// Umbruch durch Space ersetzen
				--nParCnt;
			}

			bRet = sal_True;
		}
	}
	return bRet;
}


//------------------------------------------------------------------------
// Methoden fuer FunktionsAutopiloten:
// InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
//------------------------------------------------------------------------

void ScInputHandler::InputGetSelection( xub_StrLen& rStart, xub_StrLen& rEnd )
{
	rStart = nFormSelStart;
	rEnd = nFormSelEnd;
}

//------------------------------------------------------------------------

EditView* ScInputHandler::GetFuncEditView()
{
	UpdateActiveView();		// wegen pTableView

	EditView* pView = NULL;
	if ( pInputWin )
	{
		pInputWin->MakeDialogEditView();
		pView = pInputWin->GetEditView();
	}
	else
	{
		if ( eMode != SC_INPUT_TABLE )
		{
			bCreatingFuncView = sal_True;		// RangeFinder nicht anzeigen
			SetMode( SC_INPUT_TABLE );
			bCreatingFuncView = sal_False;
			if ( pTableView )
				pTableView->GetEditEngine()->SetText( EMPTY_STRING );
		}
		pView = pTableView;
	}

	return pView;
}

//------------------------------------------------------------------------

void ScInputHandler::InputSetSelection( xub_StrLen nStart, xub_StrLen nEnd )
{
	if ( nStart <= nEnd )
	{
		nFormSelStart = nStart;
		nFormSelEnd = nEnd;
	}
	else
	{
		nFormSelEnd = nStart;
		nFormSelStart = nEnd;
	}

	EditView* pView = GetFuncEditView();
	if (pView)
		pView->SetSelection( ESelection(0,nStart, 0,nEnd) );

	bModified = sal_True;
}

//------------------------------------------------------------------------

void ScInputHandler::InputReplaceSelection( const String& rStr )
{
	if (!pRefViewSh)
		pRefViewSh = pActiveViewSh;

	DBG_ASSERT(nFormSelEnd>=nFormSelStart,"Selektion kaputt...");

	xub_StrLen nOldLen = nFormSelEnd-nFormSelStart;
	xub_StrLen nNewLen = rStr.Len();
	if (nOldLen)
		aFormText.Erase( nFormSelStart, nOldLen );
	if (nNewLen)
		aFormText.Insert( rStr, nFormSelStart );
	nFormSelEnd = nFormSelStart + nNewLen;

	EditView* pView = GetFuncEditView();
	if (pView)
	{
		pView->SetEditEngineUpdateMode( sal_False );
//		pView->InsertText( rStr, sal_True );
		pView->GetEditEngine()->SetText( aFormText );
		pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
		pView->SetEditEngineUpdateMode( sal_True );
	}
	bModified = sal_True;
}

//------------------------------------------------------------------------

String ScInputHandler::InputGetFormulaStr()
{
	return aFormText;	//!	eigene Membervariable?
}

//========================================================================
//	ScInputHdlState
//========================================================================

ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
								  const ScAddress& rStartPos,
								  const ScAddress& rEndPos,
								  const String& rString,
								  const EditTextObject* pData )
	:   aCursorPos	( rCurPos ),
		aStartPos	( rStartPos ),
		aEndPos		( rEndPos ),
		aString		( rString ),
		pEditData	( pData ? pData->Clone() : NULL )
{
}

//------------------------------------------------------------------------

ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
	:	pEditData	( NULL )
{
	*this = rCpy;
}

//------------------------------------------------------------------------

ScInputHdlState::~ScInputHdlState()
{
	delete pEditData;
}

//------------------------------------------------------------------------

int ScInputHdlState::operator==( const ScInputHdlState& r ) const
{
	return (    (aStartPos 	== r.aStartPos)
			 &&	(aEndPos   	== r.aEndPos)
			 &&	(aCursorPos == r.aCursorPos)
			 && (aString   	== r.aString)
			 && ScGlobal::EETextObjEqual( pEditData, r.pEditData ) );
}

//------------------------------------------------------------------------

ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
{
	delete pEditData;

	aCursorPos	= r.aCursorPos;
	aStartPos	= r.aStartPos;
	aEndPos		= r.aEndPos;
	aString		= r.aString;
	pEditData	= r.pEditData ? r.pEditData->Clone() : NULL;

	return *this;
}




