diff options
Diffstat (limited to 'sc/source/ui/app/inputhdl.cxx')
-rw-r--r-- | sc/source/ui/app/inputhdl.cxx | 3793 |
1 files changed, 3793 insertions, 0 deletions
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx new file mode 100644 index 000000000000..485ea4b88589 --- /dev/null +++ b/sc/source/ui/app/inputhdl.cxx @@ -0,0 +1,3793 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 ----------------------------------------------------------- + +BOOL ScInputHandler::bOptLoaded = FALSE; // App-Optionen ausgewertet +BOOL ScInputHandler::bAutoComplete = 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 USHORT 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; + USHORT 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 ); + USHORT 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 (!nCount) + { + pEngine->SetUpdateMode( 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( 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, FALSE ); + + xub_StrLen nLen = pEngine->GetTextLen(0); + ESelection aSel( 0, nLen, 0, nLen ); + pView->SetSelection( aSel ); // Cursor ans Ende + } +} + +void ScInputHandler::UpdateRange( USHORT 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 = TRUE; + DataChanged(); + bInRangeUpdate = FALSE; + + long nDiff = aNewStr.Len() - (long)(nOldEnd-nOldStart); + + pData->aRef = rNew; + pData->nSelEnd = (xub_StrLen)(pData->nSelEnd + nDiff); + + USHORT nCount = (USHORT) pRangeFindList->Count(); + for (USHORT 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(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; + USHORT 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 + BOOL bLookInString = ((nQuotes % 2) != 0); + BOOL bInString = bLookInString; + p = p0 + nPos; + p1 = (nDir < 0 ? p0 : p0 + nLen) ; + USHORT 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 ), + nTipVisible( 0 ), + nTipVisibleSec( 0 ), + nAutoPos( SCPOS_INVALID ), + bUseTab( FALSE ), + bTextValid( TRUE ), + nFormSelStart( 0 ), + nFormSelEnd( 0 ), + nAutoPar( 0 ), + eMode( SC_INPUT_NONE ), + bModified( FALSE ), + bSelIsRef( FALSE ), + bFormulaMode( FALSE ), + bInRangeUpdate( FALSE ), + bParenthesisShown( FALSE ), + bCreatingFuncView( FALSE ), + bInEnterHandler( FALSE ), + bCommandErrorShown( FALSE ), + bInOwnChange( FALSE ), + bProtected( FALSE ), + bCellHasPercentFormat( FALSE ), + nValidation( 0 ), + eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ), + aScaleX( 1,1 ), + aScaleY( 1,1 ), + pRefViewSh( NULL ), + pLastPattern( NULL ), + pEditDefaults( NULL ), + bLastIsSymbol( 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; + + BOOL bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg(); + 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, 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() +{ + ULONG nCntrl = pEngine->GetControlWord(); + ULONG nOld = nCntrl; + + // don't use pLastPattern here (may be invalid because of AutoStyle) + + BOOL bDisable = bLastIsSymbol || bFormulaMode; + if ( bDisable ) + nCntrl &= ~EE_CNTRL_AUTOCORRECT; + else + nCntrl |= EE_CNTRL_AUTOCORRECT; + + if ( nCntrl != nOld ) + pEngine->SetControlWord(nCntrl); +} + +void ScInputHandler::UpdateSpellSettings( BOOL bFromStartTab ) +{ + if ( pActiveViewSh ) + { + ScViewData* pViewData = pActiveViewSh->GetViewData(); + 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 ) + { + ULONG nCntrl = pEngine->GetControlWord(); + 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(); + pEngine->SetForbiddenCharsTable( pDoc->GetForbiddenCharacters() ); + pEngine->SetAsianCompressionMode( pDoc->GetAsianCompression() ); + pEngine->SetKernAsianPunctuation( pDoc->GetAsianKerning() ); + pEngine->SetDefaultHorizontalTextDirection( + (EEHorizontalTextDirection)pDoc->GetEditTextDirection( pViewData->GetTabNo() ) ); + pEngine->SetFirstWordCapitalization( 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 ); + } + + 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(); + USHORT nMRUCount = rOpt.GetLRUFuncListCount(); + const USHORT* pMRUList = rOpt.GetLRUFuncList(); + const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList(); + ULONG nListCount = pFuncList->GetCount(); + if (pMRUList) + { + for (USHORT i=0; i<nMRUCount; i++) + { + USHORT nId = pMRUList[i]; + for (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(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 ); + } +} + +void ScInputHandler::HideTip() +{ + if ( nTipVisible ) + { + Help::HideTip( nTipVisible ); + nTipVisible = 0; + } + aManualTip.Erase(); +} +void ScInputHandler::HideTipBelow() +{ + if ( nTipVisibleSec ) + { + Help::HideTip( nTipVisibleSec ); + nTipVisibleSec = 0; + } + 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( (USHORT) 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; + USHORT nArgs; + BOOL bFound = 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, TRUE); + if( aHelper.GetNextFunc( aSelText, FALSE, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) ) + { + if( ppFDesc->getFunctionName().getLength() ) + { + nArgPos = aHelper.GetArgStart( aSelText, nNextFStart, 0 ); + nArgs = static_cast<USHORT>(ppFDesc->getParameterCount()); + + USHORT nActive = 0; + USHORT nCount = 0; + USHORT nCountSemicolon = 0; + USHORT nCountDot = 0; + USHORT nStartPosition = 0; + USHORT nEndPosition = 0; + BOOL bFlag = FALSE; + String aNew; + USHORT nParAutoPos = SCPOS_INVALID; + if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, FALSE ) ) + { + for( USHORT i=0; i < nArgs; i++ ) + { + xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength()); + if( nArgPos <= aSelText.Len()-1 ) + { + nActive = i+1; + bFlag = TRUE; + } + nArgPos+=nLength+1; + } + if( bFlag ) + { + nCountSemicolon = aNew.GetTokenCount(cSep)-1; + nCountDot = aNew.GetTokenCount(cSheetSep)-1; + + if( !nCountSemicolon ) + { + for( USHORT i = 0; i < aNew.Len(); i++ ) + { + sal_Unicode cNext = aNew.GetChar( i ); + if( cNext == '(' ) + { + nStartPosition = i+1; + } + } + } + else if( !nCountDot ) + { + for( USHORT 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( USHORT 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 = TRUE; + } + } + else + { + ShowTipBelow( aNew ); + bFound = TRUE; + } + } + } + } + } + else + { + USHORT nPosition = 0; + String aText = pEngine->GetWord( 0, aSel.nEndPos-1 ); + if( aText.GetChar( aSel.nEndPos-1 ) == '=' ) + { + break; + } + String aNew; + USHORT nParAutoPos = SCPOS_INVALID; + nPosition = aText.Len()+1; + if( pFormulaDataPara->FindText( aText, aNew, nParAutoPos, FALSE ) ) + { + if( aFormula.GetChar( nPosition ) =='(' ) + { + ShowTipBelow( aNew ); + bFound = 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; + Window* pWin = pActiveView->GetWindow(); + Cursor* pCur = pActiveView->GetCursor(); + if (pCur) + aPos = pWin->LogicToPixel( pCur->GetPos() ); + aPos = pWin->OutputToScreenPixel( aPos ); + Rectangle aRect( aPos, aPos ); + + USHORT nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM; + nTipVisible = Help::ShowTip(pWin, aRect, rText, nAlign); + } +} + +void ScInputHandler::ShowTipBelow( const String& rText ) +{ + HideTipBelow(); + + EditView* pActiveView = pTopView ? pTopView : pTableView; + if ( pActiveView ) + { + Point aPos; + Window* pWin = pActiveView->GetWindow(); + Cursor* pCur = pActiveView->GetCursor(); + if ( pCur ) + { + Point aLogicPos = pCur->GetPos(); + aLogicPos.Y() += pCur->GetHeight(); + aPos = pWin->LogicToPixel( aLogicPos ); + } + aPos = pWin->OutputToScreenPixel( aPos ); + Rectangle aRect( aPos, aPos ); + USHORT nAlign = QUICKHELP_LEFT | QUICKHELP_TOP; + nTipVisibleSec = Help::ShowTip(pWin, aRect, rText, nAlign); + } +} + +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( (USHORT) 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; + USHORT nArgs; + BOOL bFound = FALSE; + + String aText = pEngine->GetWord( 0, aSel.nEndPos-1 ); + if ( aText.Len() ) + { + String aNew; + nAutoPos = SCPOS_INVALID; + if ( pFormulaData->FindText( aText, aNew, nAutoPos, 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, TRUE); + if( aHelper.GetNextFunc( aFormula, FALSE, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) ) + { + if( ppFDesc->getFunctionName().getLength() ) + { + nArgPos = aHelper.GetArgStart( aFormula, nNextFStart, 0 ); + nArgs = static_cast<USHORT>(ppFDesc->getParameterCount()); + + USHORT nActive = 0; + USHORT nCount = 0; + USHORT nCountSemicolon = 0; + USHORT nCountDot = 0; + USHORT nStartPosition = 0; + USHORT nEndPosition = 0; + BOOL bFlag = FALSE; + String aNew; + USHORT nParAutoPos = SCPOS_INVALID; + if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, FALSE ) ) + { + for( USHORT i=0; i < nArgs; i++ ) + { + xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength()); + if( nArgPos <= aFormula.Len()-1 ) + { + nActive = i+1; + bFlag = TRUE; + } + nArgPos+=nLength+1; + } + if( bFlag ) + { + nCountSemicolon = aNew.GetTokenCount(cSep)-1; + nCountDot = aNew.GetTokenCount(cSheetSep)-1; + + if( !nCountSemicolon ) + { + for( USHORT i = 0; i < aNew.Len(); i++ ) + { + sal_Unicode cNext = aNew.GetChar( i ); + if( cNext == '(' ) + { + nStartPosition = i+1; + } + } + } + else if( !nCountDot ) + { + for( USHORT 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( USHORT 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 = TRUE; + } + } + else + { + ShowTipBelow( aNew ); + bFound = TRUE; + } + } + } + } + } + } + } +} + +void ScInputHandler::NextFormulaEntry( 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, 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(); + 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((USHORT)0); + sal_Unicode cNext = aOld.GetChar(aWordSel.nEndPos); + if ( cNext == '(' ) + { + bDoParen = FALSE; + aInsStr.Erase( nInsLen - 2 ); // Klammern weglassen + } + } + + pView->InsertText( aInsStr, FALSE ); + + if ( bDoParen ) // Cursor zwischen die Klammern setzen + { + aSel = pView->GetSelection(); + --aSel.nStartPos; + --aSel.nEndPos; + pView->SetSelection(aSel); + + rParInserted = TRUE; + } + } +} + +void ScInputHandler::PasteFunctionData() +{ + if ( pFormulaData && nAutoPos != SCPOS_INVALID ) + { + TypedStrData* pData = (*pFormulaData)[nAutoPos]; + if (pData) + { + String aInsert = pData->GetString(); + BOOL bParInserted = 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 + 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 = FALSE; + } + + USHORT nErrCode = pCell->GetErrCode(); + if ( nErrCode == 0 ) + { + SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable()); + Color* pColor; + if ( pCell->IsValue() ) + { + double n = pCell->GetValue(); + 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 ); + 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((USHORT)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, TRUE ); + if ( pTableView ) + pTableView->InsertText( aInsert, TRUE ); + + DataChanged(); + } + + HideTip(); +} + +void ScInputHandler::ResetAutoPar() +{ + nAutoPar = 0; +} + +void ScInputHandler::AutoParAdded() +{ + ++nAutoPar; // closing parenthesis can be overwritten +} + +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((USHORT)0); + if ( nPos < aFormula.Len() && aFormula.GetChar(nPos) == ')' ) + return TRUE; + } + return 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( TRUE ); // equal strings are handled in FindText + } + + pDoc->GetDataEntries( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), + *pColumnData, 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(); + + USHORT 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, 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: + 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, FALSE ); + pTableView->SetSelection( aSelection ); + } + if ( pTopView ) + { + pTopView->InsertText( aIns, 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; + USHORT nNextPos = nAutoPos; + bUseTab = pColumnData->FindText( aText, aDummy, nNextPos, FALSE ); + } + else + bUseTab = TRUE; + } + } + } + } + } +} + +void ScInputHandler::NextAutoEntry( 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(); + USHORT 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 = 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, FALSE ); + pTableView->SetSelection( ESelection( + aSel.nEndPara, aSel.nStartPos + aIns.Len(), + aSel.nEndPara, aSel.nStartPos ) ); + } + if ( pTopView ) + { + pTopView->DeleteSelected(); + pTopView->InsertText( aIns, FALSE ); + pTopView->SetSelection( ESelection( + aSel.nEndPara, aSel.nStartPos + aIns.Len(), + aSel.nEndPara, aSel.nStartPos ) ); + } + + bInOwnChange = 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 ???? + + BOOL bFound = 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((USHORT)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 + USHORT nCount = pEngine->GetParagraphCount(); + for (USHORT 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, FALSE ); + + bFound = 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 ) + { + USHORT nCount = pEngine->GetParagraphCount(); + for (USHORT 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 = FALSE; + pRefViewSh = NULL; + SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) ); + SC_MOD()->SetRefInputHdl(NULL); + if (pInputWin) + pInputWin->SetFormulaMode(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; + + USHORT nCount = pEngine->GetViewCount(); + if (nCount > 0) + { + pTableView = pEngine->GetView(0); + for (USHORT 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( 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( TRUE ); // Status neu holen + else + NotifyChange( pLastState, TRUE ); +} + +void ScInputHandler::UpdateAdjust( sal_Unicode cTyped ) +{ + SvxAdjust eSvxAdjust; + switch (eAttrAdjust) + { + case SVX_HOR_JUSTIFY_STANDARD: + { + BOOL bNumber = 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; + } + + 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<USHORT>(eSvxAdjust); //! set at ViewData or with PostEditView + + pEngine->SetVertical( bAsianVertical ); +} + +void ScInputHandler::RemoveAdjust() +{ + // harte Ausrichtungs-Attribute loeschen + + BOOL bUndo = pEngine->IsUndoEnabled(); + if ( bUndo ) + pEngine->EnableUndo( FALSE ); + + // RemoveParaAttribs removes all paragraph attributes, including EE_PARA_JUST +#if 0 + BOOL bChange = FALSE; + USHORT nCount = pEngine->GetParagraphCount(); + for (USHORT 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 = TRUE; + } + } +#endif + + // #89403# non-default paragraph attributes (e.g. from clipboard) + // must be turned into character attributes + pEngine->RemoveParaAttribs(); + + if ( bUndo ) + pEngine->EnableUndo( 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( FALSE, TRUE ); + } +#endif +} + +void ScInputHandler::RemoveRangeFinder() +{ + // pRangeFindList und Farben loeschen + + pEngine->SetUpdateMode(FALSE); + USHORT nCount = pEngine->GetParagraphCount(); // koennte gerade neu eingefuegt worden sein + for (USHORT i=0; i<nCount; i++) + pEngine->QuickRemoveCharAttribs( i, EE_CHAR_COLOR ); + pEngine->SetUpdateMode(TRUE); + + EditView* pActiveView = pTopView ? pTopView : pTableView; + pActiveView->ShowCursor( FALSE, TRUE ); + + DeleteRangeFinder(); // loescht die Liste und die Markierungen auf der Tabelle +} + +BOOL ScInputHandler::StartTable( sal_Unicode cTyped, BOOL bFromCommand ) +{ + // returns TRUE if a new edit mode was started + + BOOL bNewTable = 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( 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, TRUE, &pItem ) ) + { + ULONG nFormat = ((const SfxUInt32Item*)pItem)->GetValue(); + bCellHasPercentFormat = ( NUMBERFORMAT_PERCENT == + pDoc->GetFormatTable()->GetType( nFormat ) ); + } + else + bCellHasPercentFormat = FALSE; // Default: kein Prozent + + // Gueltigkeit angegeben? + + if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALIDDATA, 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 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( TRUE ); // uses pLastPattern + + // Edit-Engine fuellen + + String aStr; + if (bTextValid) + { + pEngine->SetText(aCurrentText); + aStr = aCurrentText; + bTextValid = 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 = TRUE; // -> PostEditView-Aufruf + } + else + { + bProtected = TRUE; + eMode = SC_INPUT_NONE; + StopInputWinEngine( 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 = 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(); + USHORT 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; +} + +BOOL ScInputHandler::DataChanging( sal_Unicode cTyped, BOOL bFromCommand ) // return TRUE = new view created +{ + bInOwnChange = TRUE; // disable ModifyHdl (reset in DataChanged) + + if ( eMode == SC_INPUT_NONE ) + return StartTable( cTyped, bFromCommand ); + else + return FALSE; +} + +void ScInputHandler::DataChanged( BOOL bFromTopNotify ) +{ + 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( 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(); + } + + bModified = TRUE; + bSelIsRef = 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(); + + 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 = FALSE; // Aenderungen sind nur in der Edit-Engine + bInOwnChange = FALSE; +} + +void ScInputHandler::UpdateFormulaMode() +{ + SfxApplication* pSfxApp = SFX_APP(); + + if ( pEngine->GetParagraphCount() == 1 && + ( pEngine->GetText((USHORT)0).GetChar(0) == '=' || + pEngine->GetText((USHORT)0).GetChar(0) == '+' || + pEngine->GetText((USHORT)0).GetChar(0) == '-' ) && + !bProtected ) + { + if (!bFormulaMode) + { + bFormulaMode = TRUE; + pRefViewSh = pActiveViewSh; + pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) ); + SC_MOD()->SetRefInputHdl(this); + if (pInputWin) + pInputWin->SetFormulaMode(TRUE); + + if ( bAutoComplete ) + GetFormulaData(); + + UpdateParenthesis(); + UpdateAutoCorrFlag(); + } + } + else // ausschalten + { + if (bFormulaMode) + { + ShowRefFrame(); + bFormulaMode = FALSE; + pRefViewSh = NULL; + pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) ); + SC_MOD()->SetRefInputHdl(NULL); + if (pInputWin) + pInputWin->SetFormulaMode(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 ) + { + BOOL bFound = FALSE; + SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame(); + SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst(); + while ( pOneFrame && !bFound ) + { + if ( pOneFrame == pRefFrame ) + bFound = 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( TRUE ); + if (pActiveViewSh) + pActiveViewSh->GetActiveWin()->GrabFocus(); + return; + } + + bInOwnChange = TRUE; // disable ModifyHdl (reset below) + + ScInputMode eOldMode = eMode; + eMode = eNewMode; + if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode) + StopInputWinEngine( FALSE ); + + if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE) + { + if (eOldMode == SC_INPUT_NONE) // not when switching between modes + { + if (StartTable(0, FALSE)) // 0 = look at existing document content for text or number + { + if (pActiveViewSh) + pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos ); + } + } + + USHORT nPara = pEngine->GetParagraphCount()-1; + xub_StrLen nLen = pEngine->GetText(nPara).Len(); + USHORT nCount = pEngine->GetViewCount(); + + for (USHORT 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(FALSE); + } + } + + UpdateActiveView(); + if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE) + { + if (pTableView) + pTableView->SetEditEngineUpdateMode(TRUE); + } + else + { + if (pTopView) + pTopView->SetEditEngineUpdateMode(TRUE); + } + + if (eNewMode != eOldMode) + UpdateFormulaMode(); + + bInOwnChange = FALSE; +} + +//---------------------------------------------------------------------------------------- + +// lcl_IsNumber - TRUE, wenn nur Ziffern (dann keine Autokorrektur) + +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 FALSE; + } + return TRUE; +} + +void lcl_SelectionToEnd( EditView* pView ) +{ + if ( pView ) + { + EditEngine* pEngine = pView->GetEditEngine(); + USHORT 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( BYTE 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 = TRUE; + bInOwnChange = TRUE; // disable ModifyHdl (reset below) + + ImplCreateEditEngine(); + + BOOL bMatrix = ( nBlockMode == SC_ENTER_MATRIX ); + + SfxApplication* pSfxApp = SFX_APP(); + EditTextObject* pObject = NULL; + ScPatternAttr* pCellAttrs = NULL; + BOOL bAttrib = FALSE; // Formatierung vorhanden ? + BOOL bForget = 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() ); + 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 = 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 = TRUE; + } + } + + pEngine->CompleteOnlineSpelling(); + 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 = 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( FALSE ); + + if ( bModified && !bForget ) // was wird eingeben (Text/Objekt) ? + { + USHORT 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 (USHORT nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++) + { + SfxItemState eState = aOldAttribs.GetItemState( nId, 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 = TRUE; + else + { + for (USHORT nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++) + { + SfxItemState eState = aOldAttribs.GetItemState( nId, FALSE, &pItem ); + if (eState == SFX_ITEM_DONTCARE) + bAttrib = 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 = TRUE; + } + } + } + + // Feldbefehle enthalten? + + SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, FALSE ); + if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET ) + bAttrib = TRUE; + + // not converted characters? + + SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, FALSE ); + if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET ) + bAttrib = TRUE; + + // Formeln immer als Formeln erkennen (#38309#) + // (der Test vorher ist trotzdem noetig wegen Zell-Attributen) + } + + if (bMatrix) + bAttrib = FALSE; + + if (bAttrib) + { + ULONG nCtrl = pEngine->GetControlWord(); + 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) + + USHORT 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 = FALSE; + pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) ); + SC_MOD()->SetRefInputHdl(NULL); + if (pInputWin) + pInputWin->SetFormulaMode(FALSE); + UpdateAutoCorrFlag(); + } + pRefViewSh = NULL; // auch ohne FormulaMode wegen Funktions-AP + DeleteRangeFinder(); + ResetAutoPar(); + + BOOL bOldMod = bModified; + + bModified = FALSE; + bSelIsRef = FALSE; + eMode = SC_INPUT_NONE; + StopInputWinEngine( 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(); + + USHORT 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, TRUE, TRUE ); + pExecuteSh->AdjustBlockHeight(); + } + + delete pCellAttrs; + delete pObject; + + HideTip(); + + nFormSelStart = nFormSelEnd = 0; + aFormText.Erase(); + + bInOwnChange = FALSE; + bInEnterHandler = FALSE; +} + +void ScInputHandler::CancelHandler() +{ + bInOwnChange = TRUE; // disable ModifyHdl (reset below) + + ImplCreateEditEngine(); + + bModified = 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 = FALSE; + SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) ); + SC_MOD()->SetRefInputHdl(NULL); + if (pInputWin) + pInputWin->SetFormulaMode(FALSE); + UpdateAutoCorrFlag(); + } + pRefViewSh = NULL; // auch ohne FormulaMode wegen Funktions-AP + DeleteRangeFinder(); + ResetAutoPar(); + + eMode = SC_INPUT_NONE; + StopInputWinEngine( TRUE ); + if (pExecuteSh) + pExecuteSh->StopEditShell(); + + aCursorPos.Set(MAXCOL+1,0,0); // Flag, dass ungueltig + pEngine->SetText(String()); + + if ( !pLastState && pExecuteSh ) + pExecuteSh->UpdateInputHandler( TRUE ); // Status neu holen + else + NotifyChange( pLastState, TRUE ); + + nFormSelStart = nFormSelEnd = 0; + aFormText.Erase(); + + bInOwnChange = FALSE; +} + +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, FALSE ); + if (pTopView) + pTopView->InsertText( cSep, FALSE ); + + DataChanged(); +} + +void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc ) +{ + HideTip(); + + 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, TRUE ); + if (pTopView) + pTopView->InsertText( aRefStr, TRUE ); + + DataChanged(); + } + + bSelIsRef = TRUE; +} + +void ScInputHandler::InsertFunction( const String& rFuncName, 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, FALSE ); + if (bAddPar) + { + ESelection aSel = pTableView->GetSelection(); + --aSel.nStartPos; + --aSel.nEndPos; + pTableView->SetSelection(aSel); + } + } + if (pTopView) + { + pTopView->InsertText( aText, 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(); +} + +BOOL ScInputHandler::KeyInput( const KeyEvent& rKEvt, BOOL bStartEdit /* = FALSE */ ) +{ + if (!bOptLoaded) + { + bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete(); + bOptLoaded = TRUE; + } + + KeyCode aCode = rKEvt.GetKeyCode(); + USHORT nModi = aCode.GetModifier(); + BOOL bShift = aCode.IsShift(); + BOOL bControl = aCode.IsMod1(); + BOOL bAlt = aCode.IsMod2(); + USHORT 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 FALSE; + + BOOL bInputLine = ( eMode==SC_INPUT_TOP ); + + BOOL bUsed = FALSE; + BOOL bSkip = FALSE; + BOOL bDoEnter = FALSE; + + switch ( nCode ) + { + case KEY_RETURN: + if (bControl && !bShift && !bInputLine) + bDoEnter = TRUE; + else if ( nModi == 0 && nTipVisible && pFormulaData && nAutoPos != SCPOS_INVALID ) + { + PasteFunctionData(); + bUsed = TRUE; + } + else if ( nModi == 0 && nTipVisible && aManualTip.Len() ) + { + PasteManualTip(); + bUsed = TRUE; + } + else + { + BYTE 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 = 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 = TRUE; + } + break; + case KEY_ESCAPE: + if ( nTipVisible ) + { + HideTip(); + bUsed = TRUE; + } + else if( nTipVisibleSec ) + { + HideTipBelow(); + bUsed = TRUE; + } + else if (eMode != SC_INPUT_NONE) + { + CancelHandler(); + bUsed = TRUE; + } + else + bSkip = TRUE; + break; + case KEY_F2: + if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE ) + { + eMode = SC_INPUT_TYPE; + bUsed = TRUE; + } + break; + } + + // Cursortasten nur ausfuehren, wenn schon im Edit-Modus + // z.B. wegen Shift-Ctrl-PageDn (ist nicht als Accelerator definiert) + + BOOL bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt); + 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 = FALSE; + } + + UpdateActiveView(); + BOOL bNewView = DataChanging( nChar ); + + if (bProtected) // Zelle geschuetzt? + bUsed = 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(TRUE); //! gibt Muell !!!! + + if (bDoEnter) + { + if (pTableView) + if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) ) + bUsed = TRUE; + if (pTopView) + if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) ) + bUsed = TRUE; + } + else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() ) + { + SkipClosingPar(); + bUsed = TRUE; + } + else + { + if (pTableView) + if ( pTableView->PostKeyEvent( rKEvt ) ) + bUsed = TRUE; + if (pTopView) + if ( pTopView->PostKeyEvent( rKEvt ) ) + bUsed = TRUE; + } + + // Auto-Eingabe: + + if ( bUsed && bAutoComplete ) + { + bUseTab = 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(); + } + } + + DataChanged(); // ruft auch UpdateParenthesis() + InvalidateAttribs(); //! in DataChanged ? + } + } + + if (pTopView && eMode != SC_INPUT_NONE) + SyncViews(); + + return bUsed; +} + +BOOL ScInputHandler::InputCommand( const CommandEvent& rCEvt, BOOL bForce ) +{ + BOOL bUsed = 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 = TRUE; + } + } + } + else + { + if ( bForce || eMode != SC_INPUT_NONE ) + { + if (!bOptLoaded) + { + bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete(); + bOptLoaded = TRUE; + } + + HideTip(); + HideTipBelow(); + + if ( bSelIsRef ) + { + RemoveSelection(); + bSelIsRef = FALSE; + } + + UpdateActiveView(); + BOOL bNewView = DataChanging( 0, TRUE ); + + if (bProtected) // cell protected + bUsed = 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 = 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, + BOOL bForce, ScTabViewShell* pSourceSh, + BOOL bStopEditing) +{ + // #62806# Wenn der Aufruf aus einem Makro-Aufruf im EnterHandler kommt, + // gleich abbrechen und nicht den Status durcheinander bringen + if (bInEnterHandler) + return; + + BOOL bRepeat = (pState == pLastState); + if (!bRepeat && pState && pLastState) + bRepeat = sal::static_int_cast<BOOL>(*pState == *pLastState); + if (bRepeat && !bForce) + return; + + bInOwnChange = TRUE; // disable ModifyHdl (reset below) + + if ( pState && !pLastState ) // wieder enablen + bForce = TRUE; + + 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 ) + { + BOOL bIgnore = 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 = TRUE; + } + + if ( !bIgnore /* || bRepeat */ ) + { + const ScAddress& rSPos = pState->GetStartPos(); + const ScAddress& rEPos = pState->GetEndPos(); + const EditTextObject* pData = pState->GetEditData(); + String aString = pState->GetString(); + BOOL bTxtMod = FALSE; + ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell(); + ScDocument* pDoc = pDocSh->GetDocument(); + + aCursorPos = pState->GetPos(); + + if ( pData /* || bRepeat */ ) + bTxtMod = TRUE; + else if ( bHadObject ) + bTxtMod = 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 = FALSE; + aCurrentText.Erase(); + } + else + { + aCurrentText = aString; + bTextValid = 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 + { + USHORT 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 ); + } + + pInputWin->SetPosString(aPosStr); + 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. + + ULONG nCntrl = pEngine->GetControlWord(); + if ( nCntrl & EE_CNTRL_ONLINESPELLING ) + pEngine->SetControlWord( nCntrl & ~EE_CNTRL_ONLINESPELLING ); + + bModified = FALSE; + bSelIsRef = FALSE; + bProtected = FALSE; + bCommandErrorShown = FALSE; + } + } + } + +// bProtected = 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 = 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( FALSE ); + pInputWin->Disable(); + } + } + else if ( !bFormulaMode ) // #39210# Formel auch z.B. bei Hilfe behalten + { + bInOwnChange = TRUE; // disable ModifyHdl (reset below) + + pActiveViewSh = NULL; + pEngine->SetText( EMPTY_STRING ); + if ( pInputWin ) + { + pInputWin->SetPosString( EMPTY_STRING ); + pInputWin->SetTextString( EMPTY_STRING ); + pInputWin->Disable(); + } + + bInOwnChange = 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, BOOL bFromNotify ) +{ + ESelection aSelection = pView->GetSelection(); + + UpdateActiveView(); + + // #i20282# DataChanged needs to know if this is from the input line's modify handler + BOOL bFromTopNotify = ( bFromNotify && pView == pTopView ); + + BOOL bNewView = DataChanging(); //! kann das hier ueberhaupt sein? + aCurrentText = pView->GetEditEngine()->GetText(); // auch den String merken + pEngine->SetText( aCurrentText ); + DataChanged( bFromTopNotify ); + bTextValid = TRUE; // wird in DataChanged auf 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 = TRUE; + } + + return aCurrentText; +} + +Size ScInputHandler::GetTextSize() +{ + Size aSize; + if ( pEngine ) + aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() ); + + return aSize; +} + +BOOL ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine ) +{ + BOOL bRet = FALSE; + if (pEngine) + { + // Feldbefehle enthalten? + + USHORT nParCnt = pEngine->GetParagraphCount(); + SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) ); + SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, FALSE ); + if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET ) + { + // Inhalt kopieren + + EditTextObject* pObj = pEngine->CreateTextObject(); + rDestEngine.SetText(*pObj); + delete pObj; + + // Attribute loeschen + + for (USHORT i=0; i<nParCnt; i++) + rDestEngine.QuickRemoveCharAttribs( i ); + + // Absaetze zusammenfassen + + while ( nParCnt > 1 ) + { + xub_StrLen nLen = rDestEngine.GetTextLen( (USHORT)0 ); + ESelection aSel( 0,nLen, 1,0 ); + rDestEngine.QuickInsertText( ' ', aSel ); // Umbruch durch Space ersetzen + --nParCnt; + } + + bRet = 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 = TRUE; // RangeFinder nicht anzeigen + SetMode( SC_INPUT_TABLE ); + bCreatingFuncView = 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 = 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( FALSE ); +// pView->InsertText( rStr, TRUE ); + pView->GetEditEngine()->SetText( aFormText ); + pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) ); + pView->SetEditEngineUpdateMode( TRUE ); + } + bModified = 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; +} + + + + |