summaryrefslogtreecommitdiff
path: root/sc/source/ui/app/inputhdl.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/app/inputhdl.cxx')
-rw-r--r--sc/source/ui/app/inputhdl.cxx3793
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;
+}
+
+
+
+