blob: 552e6319772defbd051d4f5b68dfe20ab7bb8b97 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
//------------------------------------------------------------------
#include "scitems.hxx"
#include <editeng/eeitem.hxx>
#include <sfx2/app.hxx>
#include <editeng/acorrcfg.hxx>
#include <svx/algitem.hxx>
#include <editeng/adjitem.hxx>
#include <editeng/brshitem.hxx>
#include <svtools/colorcfg.hxx>
#include <editeng/colritem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/editstat.hxx>
#include <editeng/editview.hxx>
#include <editeng/escpitem.hxx>
#include <editeng/forbiddencharacterstable.hxx>
#include <editeng/langitem.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/unolingu.hxx>
#include <editeng/wghtitem.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/printer.hxx>
#include <svl/zforlist.hxx>
#include <vcl/sound.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/help.hxx>
#include <vcl/cursor.hxx>
#include <tools/urlobj.hxx>
#include <formula/formulahelper.hxx>
#include "inputwin.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "scmod.hxx"
#include "uiitems.hxx"
#include "global.hxx"
#include "sc.hrc"
#include "globstr.hrc"
#include "patattr.hxx"
#include "viewdata.hxx"
#include "document.hxx"
#include "docpool.hxx"
#include "editutil.hxx"
#include "collect.hxx"
#include "appoptio.hxx"
#include "docoptio.hxx"
#include "validat.hxx"
#include "userlist.hxx"
#include "rfindlst.hxx"
#include "inputopt.hxx"
#include "cell.hxx" // fuer Formel-Preview
#include "compiler.hxx" // fuer Formel-Preview
#include "editable.hxx"
#include "funcdesc.hxx"
#define _INPUTHDL_CXX
#include "inputhdl.hxx"
// max. Ranges im RangeFinder
#define RANGEFIND_MAX 32
using namespace formula;
// STATIC DATA -----------------------------------------------------------
sal_Bool ScInputHandler::bOptLoaded = sal_False; // App-Optionen ausgewertet
sal_Bool ScInputHandler::bAutoComplete = sal_False; // wird in KeyInput gesetzt
// delimiters (in addition to ScEditUtil) needed for range finder:
// only characters that are allowed in formulas next to references
// and the quotation mark (so string constants can be skipped)
static const sal_Char __FAR_DATA pMinDelimiters[] = " !\"";
extern sal_uInt16 nEditAdjust; //! Member an ViewData
//==================================================================
static sal_Unicode lcl_getSheetSeparator(ScDocument* pDoc)
{
ScCompiler aComp(pDoc, ScAddress());
aComp.SetGrammar(pDoc->GetGrammar());
return aComp.GetNativeAddressSymbol(ScCompiler::Convention::SHEET_SEPARATOR);
}
void ScInputHandler::InitRangeFinder( const String& rFormula )
{
DeleteRangeFinder();
ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDoc);
if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
return;
// String aDelimiters = pEngine->GetWordDelimiters();
String aDelimiters = ScEditUtil::ModifyDelimiters(
String::CreateFromAscii( pMinDelimiters ) );
xub_StrLen nColon = aDelimiters.Search(':');
if ( nColon != STRING_NOTFOUND )
aDelimiters.Erase( nColon, 1 ); // Delimiter ohne Doppelpunkt
xub_StrLen nDot = aDelimiters.Search(cSheetSep);
if ( nDot != STRING_NOTFOUND )
aDelimiters.Erase( nDot, 1 ); // Delimiter ohne Punkt
const sal_Unicode* pChar = rFormula.GetBuffer();
xub_StrLen nLen = rFormula.Len();
xub_StrLen nPos = 0;
xub_StrLen nStart = 0;
sal_uInt16 nCount = 0;
ScRange aRange;
while ( nPos < nLen && nCount < RANGEFIND_MAX )
{
// Trenner ueberlesen
while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.GetBuffer(), pChar[nPos] ) )
{
if ( pChar[nPos] == '"' ) // String
{
++nPos;
while (nPos<nLen && pChar[nPos] != '"') // bis zum Ende ueberlesen
++nPos;
}
++nPos; // Trennzeichen oder schliessender Quote
}
// Text zwischen Trennern
nStart = nPos;
handle_r1c1:
while ( nPos<nLen && !ScGlobal::UnicodeStrChr( aDelimiters.GetBuffer(), pChar[nPos] ) )
++nPos;
// for R1C1 '-' in R[-]... or C[-]... are not delimiters
// Nothing heroic here to ensure that there are '[]' around a negative
// integer. we need to clean up this code.
if( nPos < nLen && nPos > 0 &&
'-' == pChar[nPos] && '[' == pChar[nPos-1] &&
NULL != pDoc &&
formula::FormulaGrammar::CONV_XL_R1C1 == pDoc->GetAddressConvention() )
{
nPos++;
goto handle_r1c1;
}
if ( nPos > nStart )
{
String aTest = rFormula.Copy( nStart, nPos-nStart );
const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
sal_uInt16 nFlags = aRange.ParseAny( aTest, pDoc, aAddrDetails );
if ( nFlags & SCA_VALID )
{
// Tabelle setzen, wenn nicht angegeben
if ( (nFlags & SCA_TAB_3D) == 0 )
aRange.aStart.SetTab( pActiveViewSh->GetViewData()->GetTabNo() );
if ( (nFlags & SCA_TAB2_3D) == 0 )
aRange.aEnd.SetTab( aRange.aStart.Tab() );
if ( ( nFlags & ( SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2 ) ) == 0 )
{
// #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
// so Format doesn't output a double ref because of different flags.
sal_uInt16 nAbsFlags = nFlags & ( SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE | SCA_TAB_ABSOLUTE );
nFlags |= nAbsFlags << 4;
}
if (!nCount)
{
pEngine->SetUpdateMode( sal_False );
pRangeFindList = new ScRangeFindList( pDocSh->GetTitle() );
}
ScRangeFindData* pNew = new ScRangeFindData( aRange, nFlags, nStart, nPos );
pRangeFindList->Insert( pNew );
ESelection aSel( 0, nStart, 0, nPos );
SfxItemSet aSet( pEngine->GetEmptyItemSet() );
aSet.Put( SvxColorItem( Color( ScRangeFindList::GetColorName( nCount ) ),
EE_CHAR_COLOR ) );
pEngine->QuickSetAttribs( aSet, aSel );
++nCount;
}
}
// letzten Trenner nicht ueberlesen, koennte ja ein Quote sein (?)
}
if (nCount)
{
pEngine->SetUpdateMode( sal_True );
pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) );
}
}
void lcl_Replace( EditView* pView, const String& rNewStr, const ESelection& rOldSel )
{
if ( pView )
{
ESelection aOldSel = pView->GetSelection();
if (aOldSel.HasRange())
pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
aOldSel.nEndPara, aOldSel.nEndPos ) );
EditEngine* pEngine = pView->GetEditEngine();
pEngine->QuickInsertText( rNewStr, rOldSel );
// Dummy-InsertText fuer Update und Paint
// dafuer muss oben die Selektion aufgehoben werden (vor QuickInsertText)
pView->InsertText( EMPTY_STRING, sal_False );
xub_StrLen nLen = pEngine->GetTextLen(0);
ESelection aSel( 0, nLen, 0, nLen );
pView->SetSelection( aSel ); // Cursor ans Ende
}
}
void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
{
ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
{
ScRangeFindData* pData = pRangeFindList->GetObject( nIndex );
xub_StrLen nOldStart = pData->nSelStart;
xub_StrLen nOldEnd = pData->nSelEnd;
ScRange aJustified = rNew;
aJustified.Justify(); // Ref in der Formel immer richtigherum anzeigen
String aNewStr;
ScDocument* pDoc = pDocView->GetViewData()->GetDocument();
const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
aJustified.Format( aNewStr, pData->nFlags, pDoc, aAddrDetails );
ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
DataChanging();
lcl_Replace( pTopView, aNewStr, aOldSel );
lcl_Replace( pTableView, aNewStr, aOldSel );
bInRangeUpdate = sal_True;
DataChanged();
bInRangeUpdate = sal_False;
long nDiff = aNewStr.Len() - (long)(nOldEnd-nOldStart);
pData->aRef = rNew;
pData->nSelEnd = (xub_StrLen)(pData->nSelEnd + nDiff);
sal_uInt16 nCount = (sal_uInt16) pRangeFindList->Count();
for (sal_uInt16 i=nIndex+1; i<nCount; i++)
{
ScRangeFindData* pNext = pRangeFindList->GetObject( i );
pNext->nSelStart = (xub_StrLen)(pNext->nSelStart + nDiff);
pNext->nSelEnd = (xub_StrLen)(pNext->nSelEnd + nDiff);
}
}
else
{
DBG_ERROR("UpdateRange: da fehlt was");
}
}
void ScInputHandler::DeleteRangeFinder()
{
ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
if ( pRangeFindList && pPaintView )
{
ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
pRangeFindList->SetHidden(sal_True);
pDocSh->Broadcast( SfxSimpleHint( SC_HINT_SHOWRANGEFINDER ) ); // wegnehmen
DELETEZ(pRangeFindList);
}
}
//==================================================================
inline String GetEditText(EditEngine* pEng)
{
return ScEditUtil::GetSpaceDelimitedString(*pEng);
}
void lcl_RemoveTabs(String& rStr)
{
xub_StrLen nPos;
while ( (nPos=rStr.Search('\t')) != STRING_NOTFOUND )
rStr.SetChar( nPos, ' ' );
}
void lcl_RemoveLineEnd(String& rStr)
{
rStr.ConvertLineEnd(LINEEND_LF);
xub_StrLen nPos;
while ( (nPos=rStr.Search('\n')) != STRING_NOTFOUND )
rStr.SetChar( nPos, ' ' );
}
xub_StrLen lcl_MatchParenthesis( const String& rStr, xub_StrLen nPos )
{
int nDir;
sal_Unicode c1, c2 = 0;
c1 = rStr.GetChar( nPos );
switch ( c1 )
{
case '(' :
c2 = ')';
nDir = 1;
break;
case ')' :
c2 = '(';
nDir = -1;
break;
case '<' :
c2 = '>';
nDir = 1;
break;
case '>' :
c2 = '<';
nDir = -1;
break;
case '{' :
c2 = '}';
nDir = 1;
break;
case '}' :
c2 = '{';
nDir = -1;
break;
case '[' :
c2 = ']';
nDir = 1;
break;
case ']' :
c2 = '[';
nDir = -1;
break;
default:
nDir = 0;
}
if ( !nDir )
return STRING_NOTFOUND;
xub_StrLen nLen = rStr.Len();
const sal_Unicode* p0 = rStr.GetBuffer();
register const sal_Unicode* p;
const sal_Unicode* p1;
sal_uInt16 nQuotes = 0;
if ( nPos < nLen / 2 )
{
p = p0;
p1 = p0 + nPos;
}
else
{
p = p0 + nPos;
p1 = p0 + nLen;
}
while ( p < p1 )
{
if ( *p++ == '\"' )
nQuotes++;
}
// Odd number of quotes that we find ourselves in a string
sal_Bool bLookInString = ((nQuotes % 2) != 0);
sal_Bool bInString = bLookInString;
p = p0 + nPos;
p1 = (nDir < 0 ? p0 : p0 + nLen) ;
sal_uInt16 nLevel = 1;
while ( p != p1 && nLevel )
{
p += nDir;
if ( *p == '\"' )
{
bInString = !bInString;
if ( bLookInString && !bInString )
p = p1; //That's it then
}
else if ( bInString == bLookInString )
{
if ( *p == c1 )
nLevel++;
else if ( *p == c2 )
nLevel--;
}
}
if ( nLevel )
return STRING_NOTFOUND;
return (xub_StrLen) (p - p0);
}
//==================================================================
ScInputHandler::ScInputHandler()
: pInputWin( NULL ),
pEngine( NULL ),
pTableView( NULL ),
pTopView( NULL ),
pColumnData( NULL ),
pFormulaData( NULL ),
pFormulaDataPara( NULL ),
pTipVisibleParent( NULL ),
nTipVisible( 0 ),
pTipVisibleSecParent( NULL ),
nTipVisibleSec( 0 ),
nAutoPos( SCPOS_INVALID ),
bUseTab( sal_False ),
bTextValid( sal_True ),
nFormSelStart( 0 ),
nFormSelEnd( 0 ),
nAutoPar( 0 ),
eMode( SC_INPUT_NONE ),
bModified( sal_False ),
bSelIsRef( sal_False ),
bFormulaMode( sal_False ),
bInRangeUpdate( sal_False ),
bParenthesisShown( sal_False ),
bCreatingFuncView( sal_False ),
bInEnterHandler( sal_False ),
bCommandErrorShown( sal_False ),
bInOwnChange( sal_False ),
bProtected( sal_False ),
bCellHasPercentFormat( sal_False ),
nValidation( 0 ),
eAttrAdjust( SVX_HOR_JUSTIFY_STANDARD ),
aScaleX( 1,1 ),
aScaleY( 1,1 ),
pRefViewSh( NULL ),
pLastPattern( NULL ),
pEditDefaults( NULL ),
bLastIsSymbol( sal_False ),
pLastState( NULL ),
pDelayTimer( NULL ),
pRangeFindList( NULL )
{
// The InputHandler is constructed with the view, so SfxViewShell::Current
// doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
pActiveViewSh = NULL;
// Bindings (nur noch fuer Invalidate benutzt) werden bei Bedarf aktuell geholt
}
__EXPORT ScInputHandler::~ScInputHandler()
{
// Wenn dies der Applikations-InputHandler ist, wird der dtor erst nach SfxApplication::Main
// gerufen, darf sich also auf keine Sfx-Funktionen mehr verlassen
if ( !SFX_APP()->IsDowning() ) // inplace
EnterHandler(); // Eingabe noch abschliessen
if (SC_MOD()->GetRefInputHdl()==this)
SC_MOD()->SetRefInputHdl(NULL);
if ( pInputWin && pInputWin->GetInputHandler() == this )
pInputWin->SetInputHandler( NULL );
delete pRangeFindList;
delete pEditDefaults;
delete pEngine;
delete pLastState;
delete pDelayTimer;
delete pColumnData;
delete pFormulaData;
delete pFormulaDataPara;
}
void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
{
if ( rX != aScaleX || rY != aScaleY )
{
aScaleX = rX;
aScaleY = rY;
if (pEngine)
{
MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
pEngine->SetRefMapMode( aMode );
}
}
}
void ScInputHandler::UpdateRefDevice()
{
if (!pEngine)
return;
sal_Bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
sal_uInt32 nCtrl = pEngine->GetControlWord();
if ( bTextWysiwyg || bInPlace )
nCtrl |= EE_CNTRL_FORMAT100; // EditEngine default: always format for 100%
else
nCtrl &= ~EE_CNTRL_FORMAT100; // when formatting for screen, use the actual MapMode
pEngine->SetControlWord( nCtrl );
if ( bTextWysiwyg && pActiveViewSh )
pEngine->SetRefDevice( pActiveViewSh->GetViewData()->GetDocument()->GetPrinter() );
else
pEngine->SetRefDevice( NULL );
MapMode aMode( MAP_100TH_MM, Point(), aScaleX, aScaleY );
pEngine->SetRefMapMode( aMode );
// SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
// so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
if ( !( bTextWysiwyg && pActiveViewSh ) )
{
pEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
}
}
void ScInputHandler::ImplCreateEditEngine()
{
if ( !pEngine )
{
if ( pActiveViewSh )
{
const ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
pEngine = new ScFieldEditEngine( pDoc->GetEnginePool(), pDoc->GetEditPool() );
}
else
pEngine = new ScFieldEditEngine( EditEngine::CreatePool(), NULL, sal_True );
pEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
UpdateRefDevice(); // also sets MapMode
pEngine->SetPaperSize( Size( 1000000, 1000000 ) );
pEditDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_AUTOCORRECT );
pEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
}
}
void ScInputHandler::UpdateAutoCorrFlag()
{
sal_uLong nCntrl = pEngine->GetControlWord();
sal_uLong nOld = nCntrl;
// don't use pLastPattern here (may be invalid because of AutoStyle)
sal_Bool bDisable = bLastIsSymbol || bFormulaMode;
if ( bDisable )
nCntrl &= ~EE_CNTRL_AUTOCORRECT;
else
nCntrl |= EE_CNTRL_AUTOCORRECT;
if ( nCntrl != nOld )
pEngine->SetControlWord(nCntrl);
}
void ScInputHandler::UpdateSpellSettings( sal_Bool bFromStartTab )
{
if ( pActiveViewSh )
{
ScViewData* pViewData = pActiveViewSh->GetViewData();
sal_Bool bOnlineSpell = pViewData->GetDocument()->GetDocOptions().IsAutoSpell();
// SetDefaultLanguage is independent of the language attributes,
// ScGlobal::GetEditDefaultLanguage is always used.
// It must be set every time in case the office language was changed.
pEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
// if called for changed options, update flags only if already editing
// if called from StartTable, always update flags
if ( bFromStartTab || eMode != SC_INPUT_NONE )
{
sal_uLong nCntrl = pEngine->GetControlWord();
sal_uLong nOld = nCntrl;
if( bOnlineSpell )
nCntrl |= EE_CNTRL_ONLINESPELLING;
else
nCntrl &= ~EE_CNTRL_ONLINESPELLING;
// kein AutoCorrect auf Symbol-Font (EditEngine wertet Default nicht aus)
if ( pLastPattern && pLastPattern->IsSymbolFont() )
nCntrl &= ~EE_CNTRL_AUTOCORRECT;
else
nCntrl |= EE_CNTRL_AUTOCORRECT;
if ( nCntrl != nOld )
pEngine->SetControlWord(nCntrl);
ScDocument* pDoc = pViewData->GetDocument();
pDoc->ApplyAsianEditSettings( *pEngine );
pEngine->SetDefaultHorizontalTextDirection(
(EEHorizontalTextDirection)pDoc->GetEditTextDirection( pViewData->GetTabNo() ) );
pEngine->SetFirstWordCapitalization( sal_False );
}
// language is set separately, so the speller is needed only if online
// spelling is active
if ( bOnlineSpell ) {
com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
pEngine->SetSpeller( xXSpellChecker1 );
}
sal_Bool bHyphen = pLastPattern && ((const SfxBoolItem&)pLastPattern->GetItem(ATTR_HYPHENATE)).GetValue();
if ( bHyphen ) {
com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
pEngine->SetHyphenator( xXHyphenator );
}
}
}
//
// Funktionen/Bereichsnamen etc. als Tip-Hilfe
//
#define SC_STRTYPE_FUNCTIONS 1
// die anderen Typen sind in ScDocument::GetFormulaEntries festgelegt
void ScInputHandler::GetFormulaData()
{
if ( pActiveViewSh )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
if ( pFormulaData )
pFormulaData->FreeAll();
else
pFormulaData = new TypedScStrCollection;
if( pFormulaDataPara )
pFormulaDataPara->FreeAll();
else
pFormulaDataPara = new TypedScStrCollection;
// MRU-Funktionen aus dem Funktions-Autopiloten
// wie in ScPosWnd::FillFunctions (inputwin.cxx)
const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
sal_uLong nListCount = pFuncList->GetCount();
if (pMRUList)
{
for (sal_uInt16 i=0; i<nMRUCount; i++)
{
sal_uInt16 nId = pMRUList[i];
for (sal_uLong j=0; j<nListCount; j++)
{
const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
if ( pDesc->nFIndex == nId && pDesc->pFuncName )
{
String aEntry = *pDesc->pFuncName;
aEntry.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "()" ));
TypedStrData* pData = new TypedStrData( aEntry, 0.0, SC_STRTYPE_FUNCTIONS );
if (!pFormulaData->Insert(pData))
delete pData;
break; // nicht weitersuchen
}
}
}
}
for(sal_uLong i=0;i<nListCount;i++)
{
const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
if ( pDesc->pFuncName )
{
pDesc->initArgumentInfo();
String aEntry = pDesc->GetSignature();
TypedStrData* pData = new TypedStrData( aEntry, 0.0, SC_STRTYPE_FUNCTIONS );
if (!pFormulaDataPara->Insert(pData))
delete pData;
}
}
pDoc->GetFormulaEntries( *pFormulaData );
pDoc->GetFormulaEntries( *pFormulaDataPara );
}
}
IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent*, pEvent )
{
if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
HideTip();
return 0;
}
IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent*, pEvent )
{
if( pEvent->GetId() == VCLEVENT_OBJECT_DYING || pEvent->GetId() == VCLEVENT_WINDOW_HIDE )
HideTipBelow();
return 0;
}
void ScInputHandler::HideTip()
{
if ( nTipVisible )
{
if (pTipVisibleParent)
pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
Help::HideTip( nTipVisible );
nTipVisible = 0;
pTipVisibleParent = NULL;
}
aManualTip.Erase();
}
void ScInputHandler::HideTipBelow()
{
if ( nTipVisibleSec )
{
if (pTipVisibleSecParent)
pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
Help::HideTip( nTipVisibleSec );
nTipVisibleSec = 0;
pTipVisibleSecParent = NULL;
}
aManualTip.Erase();
}
void ScInputHandler::ShowTipCursor()
{
HideTip();
HideTipBelow();
EditView* pActiveView = pTopView ? pTopView : pTableView;
ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDocSh->GetDocument());
if ( bFormulaMode && pActiveView && pFormulaDataPara && pEngine->GetParagraphCount() == 1 )
{
String aFormula = pEngine->GetText( (sal_uInt16) 0 );
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
xub_StrLen nLeftParentPos = 0;
if( aSel.nEndPos )
{
if ( aFormula.Len() < aSel.nEndPos )
return;
xub_StrLen nPos = aSel.nEndPos;
String aSelText = aFormula.Copy( 0, nPos );
xub_StrLen nNextFStart = 0;
xub_StrLen nNextFEnd = 0;
xub_StrLen nArgPos = 0;
const IFunctionDescription* ppFDesc;
::std::vector< ::rtl::OUString> aArgs;
sal_uInt16 nArgs;
sal_Bool bFound = sal_False;
FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
while( !bFound )
{
aSelText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
nLeftParentPos = lcl_MatchParenthesis( aSelText, aSelText.Len()-1 );
if( nLeftParentPos != STRING_NOTFOUND )
{
sal_Unicode c = ( nLeftParentPos > 0 ) ? aSelText.GetChar( nLeftParentPos-1 ) : 0;
if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z' )) )
continue;
nNextFStart = aHelper.GetFunctionStart( aSelText, nLeftParentPos, sal_True);
if( aHelper.GetNextFunc( aSelText, sal_False, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) )
{
if( ppFDesc->getFunctionName().getLength() )
{
nArgPos = aHelper.GetArgStart( aSelText, nNextFStart, 0 );
nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
sal_uInt16 nActive = 0;
sal_uInt16 nCount = 0;
sal_uInt16 nCountSemicolon = 0;
sal_uInt16 nCountDot = 0;
sal_uInt16 nStartPosition = 0;
sal_uInt16 nEndPosition = 0;
sal_Bool bFlag = sal_False;
String aNew;
sal_uInt16 nParAutoPos = SCPOS_INVALID;
if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, sal_False ) )
{
for( sal_uInt16 i=0; i < nArgs; i++ )
{
xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength());
if( nArgPos <= aSelText.Len()-1 )
{
nActive = i+1;
bFlag = sal_True;
}
nArgPos+=nLength+1;
}
if( bFlag )
{
nCountSemicolon = aNew.GetTokenCount(cSep)-1;
nCountDot = aNew.GetTokenCount(cSheetSep)-1;
if( !nCountSemicolon )
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
}
}
else if( !nCountDot )
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
else if( cNext == cSep )
{
nCount ++;
nEndPosition = i;
if( nCount == nActive )
{
break;
}
nStartPosition = nEndPosition+1;
}
}
}
else
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
else if( cNext == cSep )
{
nCount ++;
nEndPosition = i;
if( nCount == nActive )
{
break;
}
nStartPosition = nEndPosition+1;
}
else if( cNext == cSheetSep )
{
continue;
}
}
}
if( nStartPosition )
{
aNew.Insert( 0x25BA, nStartPosition );
ShowTipBelow( aNew );
bFound = sal_True;
}
}
else
{
ShowTipBelow( aNew );
bFound = sal_True;
}
}
}
}
}
else
{
sal_uInt16 nPosition = 0;
String aText = pEngine->GetWord( 0, aSel.nEndPos-1 );
if( aText.GetChar( aSel.nEndPos-1 ) == '=' )
{
break;
}
String aNew;
sal_uInt16 nParAutoPos = SCPOS_INVALID;
nPosition = aText.Len()+1;
if( pFormulaDataPara->FindText( aText, aNew, nParAutoPos, sal_False ) )
{
if( aFormula.GetChar( nPosition ) =='(' )
{
ShowTipBelow( aNew );
bFound = sal_True;
}
else
break;
}
else
{
break;
}
}
}
}
}
}
void ScInputHandler::ShowTip( const String& rText )
{
// aManualTip muss hinterher von aussen gesetzt werden
HideTip();
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (pActiveView)
{
Point aPos;
pTipVisibleParent = pActiveView->GetWindow();
Cursor* pCur = pActiveView->GetCursor();
if (pCur)
aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
Rectangle aRect( aPos, aPos );
sal_uInt16 nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM;
nTipVisible = Help::ShowTip(pTipVisibleParent, aRect, rText, nAlign);
pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
}
}
void ScInputHandler::ShowTipBelow( const String& rText )
{
HideTipBelow();
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView )
{
Point aPos;
pTipVisibleSecParent = pActiveView->GetWindow();
Cursor* pCur = pActiveView->GetCursor();
if ( pCur )
{
Point aLogicPos = pCur->GetPos();
aLogicPos.Y() += pCur->GetHeight();
aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
}
aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
Rectangle aRect( aPos, aPos );
sal_uInt16 nAlign = QUICKHELP_LEFT | QUICKHELP_TOP | QUICKHELP_NOEVADEPOINTER;
nTipVisibleSec = Help::ShowTip(pTipVisibleSecParent, aRect, rText, nAlign);
pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
}
}
void ScInputHandler::UseFormulaData()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
const sal_Unicode cSheetSep = lcl_getSheetSeparator(pDocSh->GetDocument());
// Formeln duerfen nur 1 Absatz haben
if ( pActiveView && pFormulaData && pEngine->GetParagraphCount() == 1 )
{
String aTotal = pEngine->GetText( (sal_uInt16) 0 );
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
// #59348# Durch Differenzen zwischen Tabelle und Eingabezeile
// (z.B. Clipboard mit Zeilenumbruechen) kann es sein, dass die Selektion
// nicht mehr zur EditEngine passt. Dann halt kommentarlos abbrechen:
if ( aSel.nEndPos > aTotal.Len() )
return;
// steht der Cursor am Ende eines Wortes?
if ( aSel.nEndPos > 0 )
{
xub_StrLen nPos = aSel.nEndPos;
String aFormula = aTotal.Copy( 0, nPos );;
xub_StrLen nLeftParentPos = 0;
xub_StrLen nNextFStart = 0;
xub_StrLen nNextFEnd = 0;
xub_StrLen nArgPos = 0;
const IFunctionDescription* ppFDesc;
::std::vector< ::rtl::OUString> aArgs;
sal_uInt16 nArgs;
sal_Bool bFound = sal_False;
String aText = pEngine->GetWord( 0, aSel.nEndPos-1 );
if ( aText.Len() )
{
String aNew;
nAutoPos = SCPOS_INVALID;
if ( pFormulaData->FindText( aText, aNew, nAutoPos, sal_False ) )
{
ShowTip( aNew );
aAutoSearch = aText;
}
}
FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
while( !bFound )
{
aFormula.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) );
nLeftParentPos = lcl_MatchParenthesis( aFormula, aFormula.Len()-1 );
if( nLeftParentPos == STRING_NOTFOUND )
break;
// #160063# nLeftParentPos can be 0 if a parenthesis is inserted before the formula
sal_Unicode c = ( nLeftParentPos > 0 ) ? aFormula.GetChar( nLeftParentPos-1 ) : 0;
if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z') ) )
continue;
nNextFStart = aHelper.GetFunctionStart( aFormula, nLeftParentPos, sal_True);
if( aHelper.GetNextFunc( aFormula, sal_False, nNextFStart, &nNextFEnd, &ppFDesc, &aArgs ) )
{
if( ppFDesc->getFunctionName().getLength() )
{
nArgPos = aHelper.GetArgStart( aFormula, nNextFStart, 0 );
nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
sal_uInt16 nActive = 0;
sal_uInt16 nCount = 0;
sal_uInt16 nCountSemicolon = 0;
sal_uInt16 nCountDot = 0;
sal_uInt16 nStartPosition = 0;
sal_uInt16 nEndPosition = 0;
sal_Bool bFlag = sal_False;
String aNew;
sal_uInt16 nParAutoPos = SCPOS_INVALID;
if( pFormulaDataPara->FindText( ppFDesc->getFunctionName(), aNew, nParAutoPos, sal_False ) )
{
for( sal_uInt16 i=0; i < nArgs; i++ )
{
xub_StrLen nLength = static_cast<xub_StrLen>(aArgs[i].getLength());
if( nArgPos <= aFormula.Len()-1 )
{
nActive = i+1;
bFlag = sal_True;
}
nArgPos+=nLength+1;
}
if( bFlag )
{
nCountSemicolon = aNew.GetTokenCount(cSep)-1;
nCountDot = aNew.GetTokenCount(cSheetSep)-1;
if( !nCountSemicolon )
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
}
}
else if( !nCountDot )
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
else if( cNext == cSep )
{
nCount ++;
nEndPosition = i;
if( nCount == nActive )
{
break;
}
nStartPosition = nEndPosition+1;
}
}
}
else
{
for( sal_uInt16 i = 0; i < aNew.Len(); i++ )
{
sal_Unicode cNext = aNew.GetChar( i );
if( cNext == '(' )
{
nStartPosition = i+1;
}
else if( cNext == cSep )
{
nCount ++;
nEndPosition = i;
if( nCount == nActive )
{
break;
}
nStartPosition = nEndPosition+1;
}
else if( cNext == cSheetSep )
{
continue;
}
}
}
if( nStartPosition )
{
aNew.Insert( 0x25BA, nStartPosition );
ShowTipBelow( aNew );
bFound = sal_True;
}
}
else
{
ShowTipBelow( aNew );
bFound = sal_True;
}
}
}
}
}
}
}
}
void ScInputHandler::NextFormulaEntry( sal_Bool bBack )
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView && pFormulaData )
{
String aNew;
if ( pFormulaData->FindText( aAutoSearch, aNew, nAutoPos, bBack ) )
ShowTip( aNew ); // als QuickHelp anzeigen
}
// bei Tab wird vorher immer HideCursor gerufen
if (pActiveView)
pActiveView->ShowCursor();
}
void lcl_CompleteFunction( EditView* pView, const String& rInsert, sal_Bool& rParInserted )
{
if (pView)
{
ESelection aSel = pView->GetSelection();
--aSel.nStartPos;
--aSel.nEndPos;
pView->SetSelection(aSel);
pView->SelectCurrentWord();
String aInsStr = rInsert;
xub_StrLen nInsLen = aInsStr.Len();
sal_Bool bDoParen = ( nInsLen > 1 && aInsStr.GetChar(nInsLen-2) == '('
&& aInsStr.GetChar(nInsLen-1) == ')' );
if ( bDoParen )
{
// Klammern hinter Funktionsnamen nicht einfuegen, wenn direkt dahinter
// schon eine Klammer steht (z.B. wenn der Funktionsname geaendert wurde,
// #39393#).
ESelection aWordSel = pView->GetSelection();
String aOld = pView->GetEditEngine()->GetText((sal_uInt16)0);
sal_Unicode cNext = aOld.GetChar(aWordSel.nEndPos);
if ( cNext == '(' )
{
bDoParen = sal_False;
aInsStr.Erase( nInsLen - 2 ); // Klammern weglassen
}
}
pView->InsertText( aInsStr, sal_False );
if ( bDoParen ) // Cursor zwischen die Klammern setzen
{
aSel = pView->GetSelection();
--aSel.nStartPos;
--aSel.nEndPos;
pView->SetSelection(aSel);
rParInserted = sal_True;
}
}
}
void ScInputHandler::PasteFunctionData()
{
if ( pFormulaData && nAutoPos != SCPOS_INVALID )
{
TypedStrData* pData = (*pFormulaData)[nAutoPos];
if (pData)
{
String aInsert = pData->GetString();
sal_Bool bParInserted = sal_False;
DataChanging(); // kann nicht neu sein
lcl_CompleteFunction( pTopView, aInsert, bParInserted );
lcl_CompleteFunction( pTableView, aInsert, bParInserted );
DataChanged();
ShowTipCursor();
if (bParInserted)
AutoParAdded();
}
}
HideTip();
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (pActiveView)
pActiveView->ShowCursor();
}
//
// Selektion berechnen und als Tip-Hilfe anzeigen
//
String lcl_Calculate( const String& rFormula, ScDocument* pDoc, const ScAddress &rPos )
{
//! mit ScFormulaDlg::CalcValue zusammenfassen und ans Dokument verschieben !!!!
//! (Anfuehrungszeichen bei Strings werden nur hier eingefuegt)
String aValue;
if (rFormula.Len())
{
ScFormulaCell* pCell = new ScFormulaCell( pDoc, rPos, rFormula );
// #35521# HACK! um bei ColRowNames kein #REF! zu bekommen,
// wenn ein Name eigentlich als Bereich in die Gesamt-Formel
// eingefuegt wird, bei der Einzeldarstellung aber als
// single-Zellbezug interpretiert wird
sal_Bool bColRowName = pCell->HasColRowName();
if ( bColRowName )
{
// ColRowName im RPN-Code?
if ( pCell->GetCode()->GetCodeLen() <= 1 )
{ // ==1: einzelner ist als Parameter immer Bereich
// ==0: es waere vielleicht einer, wenn..
String aBraced( '(' );
aBraced += rFormula;
aBraced += ')';
delete pCell;
pCell = new ScFormulaCell( pDoc, rPos, aBraced );
}
else
bColRowName = sal_False;
}
sal_uInt16 nErrCode = pCell->GetErrCode();
if ( nErrCode == 0 )
{
SvNumberFormatter& aFormatter = *(pDoc->GetFormatTable());
Color* pColor;
if ( pCell->IsValue() )
{
double n = pCell->GetValue();
sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
pCell->GetFormatType(), ScGlobal::eLnge );
aFormatter.GetInputLineString( n, nFormat, aValue );
//! display OutputString but insert InputLineString
}
else
{
String aStr;
pCell->GetString( aStr );
sal_uLong nFormat = aFormatter.GetStandardFormat(
pCell->GetFormatType(), ScGlobal::eLnge);
aFormatter.GetOutputString( aStr, nFormat,
aValue, &pColor );
aValue.Insert('"',0); // in Anfuehrungszeichen
aValue+='"';
//! Anfuehrungszeichen im String escapen ????
}
ScRange aTestRange;
if ( bColRowName || (aTestRange.Parse(rFormula) & SCA_VALID) )
aValue.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ..." )); // Bereich
}
else
aValue = ScGlobal::GetErrorString(nErrCode);
delete pCell;
}
return aValue;
}
void ScInputHandler::FormulaPreview()
{
String aValue;
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView && pActiveViewSh )
{
String aPart = pActiveView->GetSelected();
if (!aPart.Len())
aPart = pEngine->GetText((sal_uInt16)0);
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
aValue = lcl_Calculate( aPart, pDoc, aCursorPos );
}
if (aValue.Len())
{
ShowTip( aValue ); // als QuickHelp anzeigen
aManualTip = aValue; // nach ShowTip setzen
nAutoPos = SCPOS_INVALID; // Formel-Autocomplete aufheben
}
}
void ScInputHandler::PasteManualTip()
{
// drei Punkte am Ende -> Bereichsreferenz -> nicht einfuegen
// (wenn wir mal Matrix-Konstanten haben, kann das geaendert werden)
xub_StrLen nTipLen = aManualTip.Len();
if ( nTipLen && ( nTipLen < 3 || !aManualTip.Copy( nTipLen-3 ).EqualsAscii("...") ) )
{
DataChanging(); // kann nicht neu sein
String aInsert = aManualTip;
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (!pActiveView->HasSelection())
{
// nichts selektiert -> alles selektieren
xub_StrLen nOldLen = pEngine->GetTextLen(0);
ESelection aAllSel( 0, 0, 0, nOldLen );
if ( pTopView )
pTopView->SetSelection( aAllSel );
if ( pTableView )
pTableView->SetSelection( aAllSel );
}
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
DBG_ASSERT( !aSel.nStartPara && !aSel.nEndPara, "Zuviele Absaetze in Formel" );
if ( !aSel.nStartPos ) // Selektion ab Anfang?
{
if ( aSel.nEndPos == pEngine->GetTextLen(0) )
{
// alles selektiert -> Anfuehrungszeichen weglassen
if ( aInsert.GetChar(0) == '"' )
aInsert.Erase(0,1);
xub_StrLen nInsLen = aInsert.Len();
if ( nInsLen && aInsert.GetChar(nInsLen-1) == '"' )
aInsert.Erase( nInsLen-1 );
}
else if ( aSel.nEndPos )
{
// nicht alles selektiert -> Gleichheitszeichen nicht ueberschreiben
//! doppelte Gleichheitszeichen auch ???
aSel.nStartPos = 1;
if ( pTopView )
pTopView->SetSelection( aSel );
if ( pTableView )
pTableView->SetSelection( aSel );
}
}
if ( pTopView )
pTopView->InsertText( aInsert, sal_True );
if ( pTableView )
pTableView->InsertText( aInsert, sal_True );
DataChanged();
}
HideTip();
}
void ScInputHandler::ResetAutoPar()
{
nAutoPar = 0;
}
void ScInputHandler::AutoParAdded()
{
++nAutoPar; // closing parenthesis can be overwritten
}
sal_Bool ScInputHandler::CursorAtClosingPar()
{
// test if the cursor is before a closing parenthesis
// selection from SetReference has been removed before
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
{
ESelection aSel = pActiveView->GetSelection();
xub_StrLen nPos = aSel.nStartPos;
String aFormula = pEngine->GetText((sal_uInt16)0);
if ( nPos < aFormula.Len() && aFormula.GetChar(nPos) == ')' )
return sal_True;
}
return sal_False;
}
void ScInputHandler::SkipClosingPar()
{
// this is called when a ')' is typed and the cursor is before a ')'
// that can be overwritten -> just set the cursor behind the ')'
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (pActiveView)
{
ESelection aSel = pActiveView->GetSelection();
++aSel.nStartPos;
++aSel.nEndPos;
// this is in a formula (only one paragraph), so the selection
// can be used directly for the TopView
if ( pTopView )
pTopView->SetSelection( aSel );
if ( pTableView )
pTableView->SetSelection( aSel );
}
DBG_ASSERT(nAutoPar, "SkipClosingPar: count is wrong");
--nAutoPar;
}
//
// Auto-Eingabe
//
void ScInputHandler::GetColData()
{
if ( pActiveViewSh )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
if ( pColumnData )
pColumnData->FreeAll();
else
{
pColumnData = new TypedScStrCollection;
pColumnData->SetCaseSensitive( sal_True ); // equal strings are handled in FindText
}
pDoc->GetDataEntries( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
*pColumnData, sal_True );
}
}
void ScInputHandler::UseColData() // beim Tippen
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView && pColumnData )
{
// nur anpassen, wenn Cursor am Ende steht
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
sal_uInt16 nParCnt = pEngine->GetParagraphCount();
if ( aSel.nEndPara+1 == nParCnt )
{
xub_StrLen nParLen = pEngine->GetTextLen( aSel.nEndPara );
if ( aSel.nEndPos == nParLen )
{
String aText = GetEditText(pEngine);
if (aText.Len())
{
String aNew;
nAutoPos = SCPOS_INVALID; // nix
if ( pColumnData->FindText( aText, aNew, nAutoPos, sal_False ) )
{
// #45434# durch dBase Import etc. koennen Umbrueche im String sein,
// das wuerde hier mehrere Absaetze ergeben -> nicht gut
//! GetExactMatch funktioniert dann auch nicht
lcl_RemoveLineEnd( aNew );
// Absaetze beibehalten, nur den Rest anfuegen
//! genaue Ersetzung im EnterHandler !!!
// ein Space zwischen Absaetzen:
sal_uLong nEdLen = pEngine->GetTextLen() + nParCnt - 1;
String aIns = aNew.Copy( (xub_StrLen)nEdLen );
// selection must be "backwards", so the cursor stays behind the last
// typed character
ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.Len(),
aSel.nEndPara, aSel.nEndPos );
// when editing in input line, apply to both edit views
if ( pTableView )
{
pTableView->InsertText( aIns, sal_False );
pTableView->SetSelection( aSelection );
}
if ( pTopView )
{
pTopView->InsertText( aIns, sal_False );
pTopView->SetSelection( aSelection );
}
aAutoSearch = aText; // zum Weitersuchen - nAutoPos ist gesetzt
if ( aText.Len() == aNew.Len() )
{
// Wenn der eingegebene Text gefunden wurde, TAB nur dann
// verschlucken, wenn noch etwas kommt
String aDummy;
sal_uInt16 nNextPos = nAutoPos;
bUseTab = pColumnData->FindText( aText, aDummy, nNextPos, sal_False );
}
else
bUseTab = sal_True;
}
}
}
}
}
}
void ScInputHandler::NextAutoEntry( sal_Bool bBack )
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
if ( pActiveView && pColumnData )
{
if ( nAutoPos != SCPOS_INVALID && aAutoSearch.Len() )
{
// stimmt die Selektion noch? (kann per Maus geaendert sein)
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
sal_uInt16 nParCnt = pEngine->GetParagraphCount();
if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
{
String aText = GetEditText(pEngine);
xub_StrLen nSelLen = aSel.nEndPos - aSel.nStartPos;
xub_StrLen nParLen = pEngine->GetTextLen( aSel.nEndPara );
if ( aSel.nEndPos == nParLen && aText.Len() == aAutoSearch.Len() + nSelLen )
{
String aNew;
if ( pColumnData->FindText( aAutoSearch, aNew, nAutoPos, bBack ) )
{
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
lcl_RemoveLineEnd( aNew );
String aIns = aNew.Copy( aAutoSearch.Len() );
// when editing in input line, apply to both edit views
if ( pTableView )
{
pTableView->DeleteSelected();
pTableView->InsertText( aIns, sal_False );
pTableView->SetSelection( ESelection(
aSel.nEndPara, aSel.nStartPos + aIns.Len(),
aSel.nEndPara, aSel.nStartPos ) );
}
if ( pTopView )
{
pTopView->DeleteSelected();
pTopView->InsertText( aIns, sal_False );
pTopView->SetSelection( ESelection(
aSel.nEndPara, aSel.nStartPos + aIns.Len(),
aSel.nEndPara, aSel.nStartPos ) );
}
bInOwnChange = sal_False;
}
else
{
// mehr gibts nicht
Sound::Beep();
}
}
}
}
}
// bei Tab wird vorher immer HideCursor gerufen
if (pActiveView)
pActiveView->ShowCursor();
}
//
// Klammern hervorheben
//
void ScInputHandler::UpdateParenthesis()
{
// Klammern suchen
//! Klammer-Hervorhebung einzeln abschaltbar ????
sal_Bool bFound = sal_False;
if ( bFormulaMode && eMode != SC_INPUT_TOP )
{
if ( pTableView && !pTableView->HasSelection() ) // Selektion ist immer unten
{
ESelection aSel = pTableView->GetSelection();
if (aSel.nStartPos)
{
// Das Zeichen links vom Cursor wird angeschaut
xub_StrLen nPos = aSel.nStartPos - 1;
String aFormula = pEngine->GetText((sal_uInt16)0);
sal_Unicode c = aFormula.GetChar(nPos);
if ( c == '(' || c == ')' )
{
xub_StrLen nOther = lcl_MatchParenthesis( aFormula, nPos );
if ( nOther != STRING_NOTFOUND )
{
SfxItemSet aSet( pEngine->GetEmptyItemSet() );
aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
//! Unterscheidung, wenn die Zelle schon fett ist !!!!
if (bParenthesisShown)
{
// alte Hervorhebung wegnehmen
sal_uInt16 nCount = pEngine->GetParagraphCount();
for (sal_uInt16 i=0; i<nCount; i++)
pEngine->QuickRemoveCharAttribs( i, EE_CHAR_WEIGHT );
}
ESelection aSelThis( 0,nPos, 0,nPos+1 );
pEngine->QuickSetAttribs( aSet, aSelThis );
ESelection aSelOther( 0,nOther, 0,nOther+1 );
pEngine->QuickSetAttribs( aSet, aSelOther );
// Dummy-InsertText fuer Update und Paint (Selektion ist leer)
pTableView->InsertText( EMPTY_STRING, sal_False );
bFound = sal_True;
}
}
}
// mark parenthesis right of cursor if it will be overwritten (nAutoPar)
// with different color (COL_LIGHTBLUE) ??
}
}
// alte Hervorhebung wegnehmen, wenn keine neue gesetzt
if ( bParenthesisShown && !bFound && pTableView )
{
sal_uInt16 nCount = pEngine->GetParagraphCount();
for (sal_uInt16 i=0; i<nCount; i++)
pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
}
bParenthesisShown = bFound;
}
void ScInputHandler::ViewShellGone(ScTabViewShell* pViewSh) // wird synchron aufgerufen!
{
if ( pViewSh == pActiveViewSh )
{
delete pLastState;
pLastState = NULL;
pLastPattern = NULL;
}
if ( pViewSh == pRefViewSh )
{
//! Die Eingabe kommt aus dem EnterHandler nicht mehr an
// Trotzdem wird immerhin der Editmodus beendet
EnterHandler();
bFormulaMode = sal_False;
pRefViewSh = NULL;
SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
SC_MOD()->SetRefInputHdl(NULL);
if (pInputWin)
pInputWin->SetFormulaMode(sal_False);
UpdateAutoCorrFlag();
}
pActiveViewSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
if ( pActiveViewSh && pActiveViewSh == pViewSh )
{
DBG_ERROR("pActiveViewSh weg");
pActiveViewSh = NULL;
}
if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
UpdateRefDevice(); // don't keep old document's printer as RefDevice
}
void ScInputHandler::UpdateActiveView()
{
ImplCreateEditEngine();
// #i20588# Don't rely on focus to find the active edit view. Instead, the
// active pane at the start of editing is now stored (GetEditActivePart).
// GetActiveWin (the currently active pane) fails for ref input across the
// panes of a split view.
Window* pShellWin = pActiveViewSh ?
pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData()->GetEditActivePart() ) :
NULL;
sal_uInt16 nCount = pEngine->GetViewCount();
if (nCount > 0)
{
pTableView = pEngine->GetView(0);
for (sal_uInt16 i=1; i<nCount; i++)
{
EditView* pThis = pEngine->GetView(i);
Window* pWin = pThis->GetWindow();
if ( pWin==pShellWin )
pTableView = pThis;
}
}
else
pTableView = NULL;
if (pInputWin)
pTopView = pInputWin->GetEditView();
else
pTopView = NULL;
}
void ScInputHandler::StopInputWinEngine( sal_Bool bAll )
{
if (pInputWin)
pInputWin->StopEditEngine( bAll );
pTopView = NULL; // invalid now
}
EditView* ScInputHandler::GetActiveView()
{
UpdateActiveView();
return pTopView ? pTopView : pTableView;
}
void ScInputHandler::ForgetLastPattern()
{
pLastPattern = NULL;
if ( !pLastState && pActiveViewSh )
pActiveViewSh->UpdateInputHandler( sal_True ); // Status neu holen
else
NotifyChange( pLastState, sal_True );
}
void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
{
SvxAdjust eSvxAdjust;
switch (eAttrAdjust)
{
case SVX_HOR_JUSTIFY_STANDARD:
{
sal_Bool bNumber = sal_False;
if (cTyped) // neu angefangen
bNumber = (cTyped>='0' && cTyped<='9'); // nur Ziffern sind Zahlen
else if ( pActiveViewSh )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
bNumber = ( pDoc->GetCellType( aCursorPos ) == CELLTYPE_VALUE );
}
eSvxAdjust = bNumber ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
}
break;
case SVX_HOR_JUSTIFY_BLOCK:
eSvxAdjust = SVX_ADJUST_BLOCK;
break;
case SVX_HOR_JUSTIFY_CENTER:
eSvxAdjust = SVX_ADJUST_CENTER;
break;
case SVX_HOR_JUSTIFY_RIGHT:
eSvxAdjust = SVX_ADJUST_RIGHT;
break;
default: // SVX_HOR_JUSTIFY_LEFT
eSvxAdjust = SVX_ADJUST_LEFT;
break;
}
sal_Bool bAsianVertical = pLastPattern &&
((const SfxBoolItem&)pLastPattern->GetItem( ATTR_STACKED )).GetValue() &&
((const SfxBoolItem&)pLastPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue();
if ( bAsianVertical )
{
// always edit at top of cell -> LEFT when editing vertically
eSvxAdjust = SVX_ADJUST_LEFT;
}
pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
pEngine->SetDefaults( *pEditDefaults );
nEditAdjust = sal::static_int_cast<sal_uInt16>(eSvxAdjust); //! set at ViewData or with PostEditView
pEngine->SetVertical( bAsianVertical );
}
void ScInputHandler::RemoveAdjust()
{
// harte Ausrichtungs-Attribute loeschen
sal_Bool bUndo = pEngine->IsUndoEnabled();
if ( bUndo )
pEngine->EnableUndo( sal_False );
// RemoveParaAttribs removes all paragraph attributes, including EE_PARA_JUST
#if 0
sal_Bool bChange = sal_False;
sal_uInt16 nCount = pEngine->GetParagraphCount();
for (sal_uInt16 i=0; i<nCount; i++)
{
const SfxItemSet& rOld = pEngine->GetParaAttribs( i );
if ( rOld.GetItemState( EE_PARA_JUST ) == SFX_ITEM_SET )
{
SfxItemSet aNew( rOld );
aNew.ClearItem( EE_PARA_JUST );
pEngine->SetParaAttribs( i, aNew );
bChange = sal_True;
}
}
#endif
// #89403# non-default paragraph attributes (e.g. from clipboard)
// must be turned into character attributes
pEngine->RemoveParaAttribs();
if ( bUndo )
pEngine->EnableUndo( sal_True );
// ER 31.08.00 Only called in EnterHandler, don't change view anymore.
#if 0
if (bChange)
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
pActiveView->ShowCursor( sal_False, sal_True );
}
#endif
}
void ScInputHandler::RemoveRangeFinder()
{
// pRangeFindList und Farben loeschen
pEngine->SetUpdateMode(sal_False);
sal_uInt16 nCount = pEngine->GetParagraphCount(); // koennte gerade neu eingefuegt worden sein
for (sal_uInt16 i=0; i<nCount; i++)
pEngine->QuickRemoveCharAttribs( i, EE_CHAR_COLOR );
pEngine->SetUpdateMode(sal_True);
EditView* pActiveView = pTopView ? pTopView : pTableView;
pActiveView->ShowCursor( sal_False, sal_True );
DeleteRangeFinder(); // loescht die Liste und die Markierungen auf der Tabelle
}
sal_Bool ScInputHandler::StartTable( sal_Unicode cTyped, sal_Bool bFromCommand )
{
// returns sal_True if a new edit mode was started
sal_Bool bNewTable = sal_False;
if (!bModified && ValidCol(aCursorPos.Col()))
{
if (pActiveViewSh)
{
ImplCreateEditEngine();
UpdateActiveView();
SyncViews();
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocShell()->GetDocument();
const ScMarkData& rMark = pActiveViewSh->GetViewData()->GetMarkData();
ScEditableTester aTester;
if ( rMark.IsMarked() || rMark.IsMultiMarked() )
aTester.TestSelection( pDoc, rMark );
else
aTester.TestSelectedBlock( pDoc, aCursorPos.Col(),aCursorPos.Row(),
aCursorPos.Col(),aCursorPos.Row(), rMark );
if ( aTester.IsEditable() )
{
// UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
pEngine->SetUpdateMode( sal_False );
// Attribute in EditEngine uebernehmen
const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(),
aCursorPos.Row(),
aCursorPos.Tab() );
if (pPattern != pLastPattern)
{
// Prozent-Format?
const SfxItemSet& rAttrSet = pPattern->GetItemSet();
const SfxPoolItem* pItem;
if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALUE_FORMAT, sal_True, &pItem ) )
{
sal_uLong nFormat = ((const SfxUInt32Item*)pItem)->GetValue();
bCellHasPercentFormat = ( NUMBERFORMAT_PERCENT ==
pDoc->GetFormatTable()->GetType( nFormat ) );
}
else
bCellHasPercentFormat = sal_False; // Default: kein Prozent
// Gueltigkeit angegeben?
if ( SFX_ITEM_SET == rAttrSet.GetItemState( ATTR_VALIDDATA, sal_True, &pItem ) )
nValidation = ((const SfxUInt32Item*)pItem)->GetValue();
else
nValidation = 0;
// EditEngine Defaults
// Hier auf keinen Fall SetParaAttribs, weil die EditEngine evtl.
// schon gefuellt ist (bei Edit-Zellen).
// SetParaAttribs wuerde dann den Inhalt aendern
//! ER 30.08.00 The SetDefaults is now (since MUST/src602
//! EditEngine changes) implemented as a SetParaAttribs.
//! Any problems?
pPattern->FillEditItemSet( pEditDefaults );
pEngine->SetDefaults( *pEditDefaults );
pLastPattern = pPattern;
bLastIsSymbol = pPattern->IsSymbolFont();
// Background color must be known for automatic font color.
// For transparent cell background, the document background color must be used.
Color aBackCol = ((const SvxBrushItem&)
pPattern->GetItem( ATTR_BACKGROUND )).GetColor();
ScModule* pScMod = SC_MOD();
// #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
if ( aBackCol.GetTransparency() > 0 ||
Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
aBackCol.SetColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
pEngine->SetBackgroundColor( aBackCol );
// Ausrichtung
eAttrAdjust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
GetItem(ATTR_HOR_JUSTIFY)).GetValue();
if ( eAttrAdjust == SVX_HOR_JUSTIFY_REPEAT &&
static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() )
{
// #i31843# "repeat" with "line breaks" is treated as default alignment
eAttrAdjust = SVX_HOR_JUSTIFY_STANDARD;
}
}
// UpdateSpellSettings enables online spelling if needed
// -> also call if attributes are unchanged
UpdateSpellSettings( sal_True ); // uses pLastPattern
// Edit-Engine fuellen
String aStr;
if (bTextValid)
{
pEngine->SetText(aCurrentText);
aStr = aCurrentText;
bTextValid = sal_False;
aCurrentText.Erase();
}
else
aStr = GetEditText(pEngine);
if (aStr.Len() > 3 && // Matrix-Formel ?
aStr.GetChar(0) == '{' &&
aStr.GetChar(1) == '=' &&
aStr.GetChar(aStr.Len()-1) == '}')
{
aStr.Erase(0,1);
aStr.Erase(aStr.Len()-1,1);
pEngine->SetText(aStr);
if ( pInputWin )
pInputWin->SetTextString(aStr);
}
UpdateAdjust( cTyped );
if ( bAutoComplete )
GetColData();
if ( ( aStr.GetChar(0) == '=' || aStr.GetChar(0) == '+' || aStr.GetChar(0) == '-' ) &&
!cTyped && !bCreatingFuncView )
InitRangeFinder(aStr); // Formel wird editiert -> RangeFinder
bNewTable = sal_True; // -> PostEditView-Aufruf
}
else
{
bProtected = sal_True;
eMode = SC_INPUT_NONE;
StopInputWinEngine( sal_True );
UpdateFormulaMode();
if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
{
// #97673# Prevent repeated error messages for the same cell from command events
// (for keyboard events, multiple messages are wanted).
// Set the flag before showing the error message because the command handler
// for the next IME command may be called when showing the dialog.
if ( bFromCommand )
bCommandErrorShown = sal_True;
pActiveViewSh->GetActiveWin()->GrabFocus();
pActiveViewSh->ErrorMessage(aTester.GetMessageId());
}
}
}
if (!bProtected && pInputWin)
pInputWin->SetOkCancelMode();
}
return bNewTable;
}
void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
{
DBG_ASSERT( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
EditEngine* pEngine = pEditView->GetEditEngine();
sal_uInt16 nCount = pEngine->GetParagraphCount();
if (nCount > 1)
{
xub_StrLen nParLen = pEngine->GetTextLen(rSel.nStartPara);
while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
{
rSel.nStartPos -= nParLen + 1; // incl. Leerzeichen vom Umbruch
nParLen = pEngine->GetTextLen(++rSel.nStartPara);
}
nParLen = pEngine->GetTextLen(rSel.nEndPara);
while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
{
rSel.nEndPos -= nParLen + 1; // incl. Leerzeichen vom Umbruch
nParLen = pEngine->GetTextLen(++rSel.nEndPara);
}
}
ESelection aSel = pEditView->GetSelection();
if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
|| rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
pEditView->SetSelection( rSel );
}
void ScInputHandler::SyncViews( EditView* pSourceView )
{
ESelection aSel;
if (pSourceView)
{
aSel = pSourceView->GetSelection();
if (pTopView && pTopView != pSourceView)
pTopView->SetSelection( aSel );
if (pTableView && pTableView != pSourceView)
lcl_SetTopSelection( pTableView, aSel );
}
else if (pTopView && pTableView)
{
aSel = pTopView->GetSelection();
lcl_SetTopSelection( pTableView, aSel );
}
}
IMPL_LINK( ScInputHandler, ModifyHdl, void *, EMPTYARG )
{
if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
pEngine && pEngine->GetUpdateMode() && pInputWin )
{
// #102745# update input line from ModifyHdl for changes that are not
// wrapped by DataChanging/DataChanged calls (like Drag&Drop)
String aText = GetEditText(pEngine);
lcl_RemoveTabs(aText);
pInputWin->SetTextString(aText);
}
return 0;
}
sal_Bool ScInputHandler::DataChanging( sal_Unicode cTyped, sal_Bool bFromCommand ) // return sal_True = new view created
{
bInOwnChange = sal_True; // disable ModifyHdl (reset in DataChanged)
if ( eMode == SC_INPUT_NONE )
return StartTable( cTyped, bFromCommand );
else
return sal_False;
}
void ScInputHandler::DataChanged( sal_Bool bFromTopNotify, sal_Bool bSetModified )
{
ImplCreateEditEngine();
if (eMode==SC_INPUT_NONE)
eMode = SC_INPUT_TYPE;
if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
{
// table EditEngine is formatted below, input line needs formatting after paste
// #i20282# not when called from the input line's modify handler
pTopView->GetEditEngine()->QuickFormatDoc( sal_True );
// #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
// can't safely access the EditEngine's current view, so the cursor has to be
// shown again here.
pTopView->ShowCursor();
}
if (bSetModified)
bModified = sal_True;
bSelIsRef = sal_False;
if ( pRangeFindList && !bInRangeUpdate )
RemoveRangeFinder(); // Attribute und Markierung loeschen
UpdateParenthesis(); // Hervorhebung der Klammern neu
// ER 31.08.00 New SetDefaults sets ParaAttribs, don't clear them away ...
// RemoveAdjust(); // #40255# harte Ausrichtungs-Attribute loeschen
if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
{
String aText = GetEditText(pEngine);
lcl_RemoveTabs(aText);
if ( pInputWin )
pInputWin->SetTextString(aText);
}
// wenn der Cursor vor dem Absatzende steht, werden Teile rechts rausgeschoben
// (unabhaengig von eMode) -> View anpassen!
// wenn der Cursor am Ende steht, reicht der Status-Handler an der ViewData
// #93767# first make sure the status handler is called now if the cursor
// is outside the visible area
pEngine->QuickFormatDoc();
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (pActiveView && pActiveViewSh)
{
ScViewData* pViewData = pActiveViewSh->GetViewData();
sal_Bool bNeedGrow = ( nEditAdjust != SVX_ADJUST_LEFT ); // rechtsbuendig immer
if (!bNeedGrow)
{
// Cursor vor dem Ende?
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
bNeedGrow = ( aSel.nEndPos != pEngine->GetTextLen(aSel.nEndPara) );
}
if (!bNeedGrow)
{
bNeedGrow = pViewData->GetDocument()->IsLayoutRTL( pViewData->GetTabNo() );
}
if (bNeedGrow)
{
// adjust inplace view
pViewData->EditGrowY();
pViewData->EditGrowX();
}
}
UpdateFormulaMode();
bTextValid = sal_False; // Aenderungen sind nur in der Edit-Engine
bInOwnChange = sal_False;
}
void ScInputHandler::UpdateFormulaMode()
{
SfxApplication* pSfxApp = SFX_APP();
if ( pEngine->GetParagraphCount() == 1 &&
( pEngine->GetText((sal_uInt16)0).GetChar(0) == '=' ||
pEngine->GetText((sal_uInt16)0).GetChar(0) == '+' ||
pEngine->GetText((sal_uInt16)0).GetChar(0) == '-' ) &&
!bProtected )
{
if (!bFormulaMode)
{
bFormulaMode = sal_True;
pRefViewSh = pActiveViewSh;
pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
SC_MOD()->SetRefInputHdl(this);
if (pInputWin)
pInputWin->SetFormulaMode(sal_True);
if ( bAutoComplete )
GetFormulaData();
UpdateParenthesis();
UpdateAutoCorrFlag();
}
}
else // ausschalten
{
if (bFormulaMode)
{
ShowRefFrame();
bFormulaMode = sal_False;
pRefViewSh = NULL;
pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
SC_MOD()->SetRefInputHdl(NULL);
if (pInputWin)
pInputWin->SetFormulaMode(sal_False);
UpdateAutoCorrFlag();
}
}
}
void ScInputHandler::ShowRefFrame()
{
// #123169# Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
// checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
// A local variable is used instead.
ScTabViewShell* pVisibleSh = PTR_CAST( ScTabViewShell, SfxViewShell::Current() );
if ( pRefViewSh && pRefViewSh != pVisibleSh )
{
sal_Bool bFound = sal_False;
SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
while ( pOneFrame && !bFound )
{
if ( pOneFrame == pRefFrame )
bFound = sal_True;
pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
}
if (bFound)
{
// Hier wird sich darauf verlassen, dass Activate synchron funktioniert
// (dabei wird pActiveViewSh umgesetzt)
pRefViewSh->SetActive(); // Appear und SetViewFrame
// pLastState wird im NotifyChange aus dem Activate richtig gesetzt
}
else
{
DBG_ERROR("ViewFrame fuer Referenzeingabe ist nicht mehr da");
}
}
}
void ScInputHandler::RemoveSelection()
{
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (!pActiveView)
return;
ESelection aSel = pActiveView->GetSelection();
aSel.nStartPara = aSel.nEndPara;
aSel.nStartPos = aSel.nEndPos;
if (pTableView)
pTableView->SetSelection( aSel );
if (pTopView)
pTopView->SetSelection( aSel );
}
void ScInputHandler::InvalidateAttribs()
{
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if (pViewFrm)
{
SfxBindings& rBindings = pViewFrm->GetBindings();
rBindings.Invalidate( SID_ATTR_CHAR_FONT );
rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
rBindings.Invalidate( SID_ULINE_VAL_NONE );
rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
rBindings.Invalidate( SID_HYPERLINK_GETLINK );
rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
rBindings.Invalidate( SID_SET_SUB_SCRIPT );
rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
}
}
//
// --------------- public Methoden --------------------------------------------
//
void ScInputHandler::SetMode( ScInputMode eNewMode )
{
if ( eMode == eNewMode )
return;
ImplCreateEditEngine();
if (bProtected)
{
eMode = SC_INPUT_NONE;
StopInputWinEngine( sal_True );
if (pActiveViewSh)
pActiveViewSh->GetActiveWin()->GrabFocus();
return;
}
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
ScInputMode eOldMode = eMode;
eMode = eNewMode;
if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
StopInputWinEngine( sal_False );
if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
{
if (eOldMode == SC_INPUT_NONE) // not when switching between modes
{
if (StartTable(0, sal_False)) // 0 = look at existing document content for text or number
{
if (pActiveViewSh)
pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
}
}
sal_uInt16 nPara = pEngine->GetParagraphCount()-1;
xub_StrLen nLen = pEngine->GetText(nPara).Len();
sal_uInt16 nCount = pEngine->GetViewCount();
for (sal_uInt16 i=0; i<nCount; i++)
{
if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
{
// Selektion bleibt
}
else
{
pEngine->GetView(i)->
SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
}
pEngine->GetView(i)->ShowCursor(sal_False);
}
}
UpdateActiveView();
if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
{
if (pTableView)
pTableView->SetEditEngineUpdateMode(sal_True);
}
else
{
if (pTopView)
pTopView->SetEditEngineUpdateMode(sal_True);
}
if (eNewMode != eOldMode)
UpdateFormulaMode();
bInOwnChange = sal_False;
}
//----------------------------------------------------------------------------------------
// lcl_IsNumber - sal_True, wenn nur Ziffern (dann keine Autokorrektur)
sal_Bool lcl_IsNumber(const String& rString)
{
xub_StrLen nLen = rString.Len();
for (xub_StrLen i=0; i<nLen; i++)
{
sal_Unicode c = rString.GetChar(i);
if ( c < '0' || c > '9' )
return sal_False;
}
return sal_True;
}
void lcl_SelectionToEnd( EditView* pView )
{
if ( pView )
{
EditEngine* pEngine = pView->GetEditEngine();
sal_uInt16 nParCnt = pEngine->GetParagraphCount();
if ( nParCnt == 0 )
nParCnt = 1;
ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
pView->SetSelection( aSel );
}
}
void ScInputHandler::EnterHandler( sal_uInt8 nBlockMode )
{
// #62806# Bei Makro-Aufrufen fuer Gueltigkeit kann Tod und Teufel passieren,
// darum dafuer sorgen, dass EnterHandler nicht verschachtelt gerufen wird:
if (bInEnterHandler) return;
bInEnterHandler = sal_True;
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
ImplCreateEditEngine();
sal_Bool bMatrix = ( nBlockMode == SC_ENTER_MATRIX );
SfxApplication* pSfxApp = SFX_APP();
EditTextObject* pObject = NULL;
ScPatternAttr* pCellAttrs = NULL;
sal_Bool bAttrib = sal_False; // Formatierung vorhanden ?
sal_Bool bForget = sal_False; // wegen Gueltigkeit streichen ?
String aString = GetEditText(pEngine);
EditView* pActiveView = pTopView ? pTopView : pTableView;
if (bModified && pActiveView && aString.Len() && !lcl_IsNumber(aString))
{
if ( pColumnData && nAutoPos != SCPOS_INVALID )
{
// #i47125# If AutoInput appended something, do the final AutoCorrect
// with the cursor at the end of the input.
lcl_SelectionToEnd(pTopView);
lcl_SelectionToEnd(pTableView);
}
if (pTopView)
pTopView->CompleteAutoCorrect(); // #59759# CompleteAutoCorrect fuer beide Views
if (pTableView)
pTableView->CompleteAutoCorrect();
aString = GetEditText(pEngine);
}
lcl_RemoveTabs(aString);
// Test, ob zulaessig (immer mit einfachem String)
if ( bModified && nValidation && pActiveViewSh )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
const ScValidationData* pData = pDoc->GetValidationEntry( nValidation );
if (pData && pData->HasErrMsg())
{
// #i67990# don't use pLastPattern in EnterHandler
const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
sal_Bool bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
if (!bOk)
{
if ( pActiveViewSh ) // falls aus MouseButtonDown gekommen
pActiveViewSh->StopMarking(); // (die InfoBox verschluckt das MouseButtonUp)
//! es gibt noch Probleme, wenn die Eingabe durch Aktivieren einer
//! anderen View ausgeloest wurde
Window* pParent = Application::GetDefDialogParent();
if ( pData->DoError( pParent, aString, aCursorPos ) )
bForget = sal_True; // Eingabe nicht uebernehmen
}
}
}
// check for input into DataPilot table
if ( bModified && pActiveViewSh && !bForget )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
ScDPObject* pDPObj = pDoc->GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
if ( pDPObj )
{
// any input within the DataPilot table is either a valid renaming
// or an invalid action - normal cell input is always aborted
pActiveViewSh->DataPilotInput( aCursorPos, aString );
bForget = sal_True;
}
}
pEngine->CompleteOnlineSpelling();
sal_Bool bSpellErrors = !bFormulaMode && pEngine->HasOnlineSpellErrors();
if ( bSpellErrors )
{
// #i3820# If the spell checker flags numerical input as error,
// it still has to be treated as number, not EditEngine object.
if ( pActiveViewSh )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
// #i67990# don't use pLastPattern in EnterHandler
const ScPatternAttr* pPattern = pDoc->GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
// without conditional format, as in ScColumn::SetString
sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
double nVal;
if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
{
bSpellErrors = sal_False; // ignore the spelling errors
}
}
}
// After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
// SetUpdateMode must come after CompleteOnlineSpelling.
// The view is hidden in any case below (Broadcast).
pEngine->SetUpdateMode( sal_False );
if ( bModified && !bForget ) // was wird eingeben (Text/Objekt) ?
{
sal_uInt16 nParCnt = pEngine->GetParagraphCount();
if ( nParCnt == 0 )
nParCnt = 1;
ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
SfxItemSet aOldAttribs = pEngine->GetAttribs( aSel );
const SfxPoolItem* pItem = NULL;
// find common (cell) attributes before RemoveAdjust
if ( pActiveViewSh )
{
SfxItemSet* pCommonAttrs = NULL;
for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
{
SfxItemState eState = aOldAttribs.GetItemState( nId, sal_False, &pItem );
if ( eState == SFX_ITEM_SET &&
nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
*pItem != pEditDefaults->Get(nId) )
{
if ( !pCommonAttrs )
pCommonAttrs = new SfxItemSet( pEngine->GetEmptyItemSet() );
pCommonAttrs->Put( *pItem );
}
}
if ( pCommonAttrs )
{
ScDocument* pDoc = pActiveViewSh->GetViewData()->GetDocument();
pCellAttrs = new ScPatternAttr( pDoc->GetPool() );
pCellAttrs->GetFromEditItemSet( pCommonAttrs );
delete pCommonAttrs;
}
}
// clear ParaAttribs (including adjustment)
RemoveAdjust();
// check if EditObject is needed
if ( bSpellErrors || nParCnt > 1 )
bAttrib = sal_True;
else
{
for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
{
SfxItemState eState = aOldAttribs.GetItemState( nId, sal_False, &pItem );
if (eState == SFX_ITEM_DONTCARE)
bAttrib = sal_True;
else if (eState == SFX_ITEM_SET)
{
// keep same items in EditEngine as in ScEditAttrTester
if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
{
if ( *pItem != pEditDefaults->Get(nId) )
bAttrib = sal_True;
}
}
}
// Feldbefehle enthalten?
SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, sal_False );
if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
bAttrib = sal_True;
// not converted characters?
SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, sal_False );
if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET )
bAttrib = sal_True;
// Formeln immer als Formeln erkennen (#38309#)
// (der Test vorher ist trotzdem noetig wegen Zell-Attributen)
}
if (bMatrix)
bAttrib = sal_False;
if (bAttrib)
{
sal_uLong nCtrl = pEngine->GetControlWord();
sal_uLong nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
pObject = pEngine->CreateTextObject();
}
else if (bAutoComplete) // Gross-/Kleinschreibung anpassen
{
if (pColumnData)
pColumnData->GetExactMatch( aString );
//! effizienter in der Liste suchen (ScUserList, nur einmal ToUpper)
sal_uInt16 nIndex;
ScUserListData* pData = ScGlobal::GetUserList()->GetData(aString);
if ( pData && pData->GetSubIndex( aString, nIndex ) )
aString = pData->GetSubStr( nIndex );
}
}
// don't rely on ShowRefFrame switching the active view synchronously
// execute the function directly on the correct view's bindings instead
// pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
if (bFormulaMode)
{
ShowRefFrame();
if (pExecuteSh)
{
pExecuteSh->SetTabNo(aCursorPos.Tab());
pExecuteSh->ActiveGrabFocus();
}
bFormulaMode = sal_False;
pSfxApp->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
SC_MOD()->SetRefInputHdl(NULL);
if (pInputWin)
pInputWin->SetFormulaMode(sal_False);
UpdateAutoCorrFlag();
}
pRefViewSh = NULL; // auch ohne FormulaMode wegen Funktions-AP
DeleteRangeFinder();
ResetAutoPar();
sal_Bool bOldMod = bModified;
bModified = sal_False;
bSelIsRef = sal_False;
eMode = SC_INPUT_NONE;
StopInputWinEngine( sal_True );
// #123344# Text input (through number formats) or ApplySelectionPattern modify
// the cell's attributes, so pLastPattern is no longer valid
pLastPattern = NULL;
if (bOldMod && !bProtected && !bForget)
{
// keine typographische Anfuehrungszeichen in Formeln
if ( aString.GetChar(0) == '=' )
{
SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get()->GetAutoCorrect();
if ( pAuto )
{
sal_Unicode cReplace = pAuto->GetStartDoubleQuote();
if( !cReplace )
cReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkStart().GetChar(0);
if ( cReplace != '"' )
aString.SearchAndReplaceAll( cReplace, '"' );
cReplace = pAuto->GetEndDoubleQuote();
if( !cReplace )
cReplace = ScGlobal::pLocaleData->getDoubleQuotationMarkEnd().GetChar(0);
if ( cReplace != '"' )
aString.SearchAndReplaceAll( cReplace, '"' );
cReplace = pAuto->GetStartSingleQuote();
if( !cReplace )
cReplace = ScGlobal::pLocaleData->getQuotationMarkStart().GetChar(0);
if ( cReplace != '\'' )
aString.SearchAndReplaceAll( cReplace, '\'' );
cReplace = pAuto->GetEndSingleQuote();
if( !cReplace )
cReplace = ScGlobal::pLocaleData->getQuotationMarkEnd().GetChar(0);
if ( cReplace != '\'' )
aString.SearchAndReplaceAll( cReplace, '\'' );
}
}
pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW_NOPAINT ) );
if ( pExecuteSh )
{
SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
sal_uInt16 nId = FID_INPUTLINE_ENTER;
if ( nBlockMode == SC_ENTER_BLOCK )
nId = FID_INPUTLINE_BLOCK;
else if ( nBlockMode == SC_ENTER_MATRIX )
nId = FID_INPUTLINE_MATRIX;
ScInputStatusItem aItem( FID_INPUTLINE_STATUS,
aCursorPos, aCursorPos, aCursorPos,
aString, pObject );
const SfxPoolItem* aArgs[2];
aArgs[0] = &aItem;
aArgs[1] = NULL;
rBindings.Execute( nId, aArgs );
}
delete pLastState; // pLastState enthaelt noch den alten Text
pLastState = NULL;
}
else
pSfxApp->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
{
// mit Eingabe zusammenfassen ?
pExecuteSh->ApplySelectionPattern( *pCellAttrs, sal_True, sal_True );
pExecuteSh->AdjustBlockHeight();
}
delete pCellAttrs;
delete pObject;
HideTip();
HideTipBelow();
nFormSelStart = nFormSelEnd = 0;
aFormText.Erase();
bInOwnChange = sal_False;
bInEnterHandler = sal_False;
}
void ScInputHandler::CancelHandler()
{
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
ImplCreateEditEngine();
bModified = sal_False;
// don't rely on ShowRefFrame switching the active view synchronously
// execute the function directly on the correct view's bindings instead
// pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
if (bFormulaMode)
{
ShowRefFrame();
if (pExecuteSh)
{
pExecuteSh->SetTabNo(aCursorPos.Tab());
pExecuteSh->ActiveGrabFocus();
}
bFormulaMode = sal_False;
SFX_APP()->Broadcast( SfxSimpleHint( FID_REFMODECHANGED ) );
SC_MOD()->SetRefInputHdl(NULL);
if (pInputWin)
pInputWin->SetFormulaMode(sal_False);
UpdateAutoCorrFlag();
}
pRefViewSh = NULL; // auch ohne FormulaMode wegen Funktions-AP
DeleteRangeFinder();
ResetAutoPar();
eMode = SC_INPUT_NONE;
StopInputWinEngine( sal_True );
if (pExecuteSh)
pExecuteSh->StopEditShell();
aCursorPos.Set(MAXCOL+1,0,0); // Flag, dass ungueltig
pEngine->SetText(String());
if ( !pLastState && pExecuteSh )
pExecuteSh->UpdateInputHandler( sal_True ); // Status neu holen
else
NotifyChange( pLastState, sal_True );
nFormSelStart = nFormSelEnd = 0;
aFormText.Erase();
bInOwnChange = sal_False;
}
sal_Bool ScInputHandler::IsModalMode( SfxObjectShell* pDocSh )
{
// Referenzen auf unbenanntes Dokument gehen nicht
return bFormulaMode && pRefViewSh
&& pRefViewSh->GetViewData()->GetDocument()->GetDocumentShell() != pDocSh
&& !pDocSh->HasName();
}
void ScInputHandler::AddRefEntry()
{
const sal_Unicode cSep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
UpdateActiveView();
if (!pTableView && !pTopView)
return; // z.B. FillMode
DataChanging(); // kann nicht neu sein
RemoveSelection();
if (pTableView)
pTableView->InsertText( cSep, sal_False );
if (pTopView)
pTopView->InsertText( cSep, sal_False );
DataChanged();
}
void ScInputHandler::SetReference( const ScRange& rRef, ScDocument* pDoc )
{
HideTip();
sal_Bool bOtherDoc = ( pRefViewSh &&
pRefViewSh->GetViewData()->GetDocument() != pDoc );
if (bOtherDoc)
if (!pDoc->GetDocumentShell()->HasName())
{
// Referenzen auf unbenanntes Dokument gehen nicht
// (SetReference sollte dann auch nicht gerufen werden)
return;
}
UpdateActiveView();
if (!pTableView && !pTopView)
return; // z.B. FillMode
// nie das "=" ueberschreiben!
EditView* pActiveView = pTopView ? pTopView : pTableView;
ESelection aSel = pActiveView->GetSelection();
aSel.Adjust();
if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
return;
DataChanging(); // kann nicht neu sein
// Selektion umdrehen, falls rueckwaerts (noetig ???)
if (pTableView)
{
ESelection aTabSel = pTableView->GetSelection();
if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
{
aTabSel.Adjust();
pTableView->SetSelection(aTabSel);
}
}
if (pTopView)
{
ESelection aTopSel = pTopView->GetSelection();
if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
{
aTopSel.Adjust();
pTopView->SetSelection(aTopSel);
}
}
// String aus Referenz erzeugen
String aRefStr;
const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
if (bOtherDoc)
{
// Referenz auf anderes Dokument
DBG_ASSERT(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
String aTmp;
rRef.Format( aTmp, SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails ); // immer 3d
SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
// #i75893# convert escaped URL of the document to something user friendly
// String aFileName = pObjSh->GetMedium()->GetName();
String aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS );
aRefStr = '\'';
aRefStr += aFileName;
aRefStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "'#" ));
aRefStr += aTmp;
}
else
{
if ( ( rRef.aStart.Tab() != aCursorPos.Tab() ||
rRef.aStart.Tab() != rRef.aEnd.Tab() ) && pDoc )
rRef.Format( aRefStr, SCA_VALID|SCA_TAB_3D, pDoc, aAddrDetails );
else
rRef.Format( aRefStr, SCA_VALID, pDoc, aAddrDetails );
}
if (pTableView || pTopView)
{
if (pTableView)
pTableView->InsertText( aRefStr, sal_True );
if (pTopView)
pTopView->InsertText( aRefStr, sal_True );
DataChanged();
}
bSelIsRef = sal_True;
}
void ScInputHandler::InsertFunction( const String& rFuncName, sal_Bool bAddPar )
{
if ( eMode == SC_INPUT_NONE )
{
DBG_ERROR("InsertFunction, nicht im Eingabemodus");
return;
}
UpdateActiveView();
if (!pTableView && !pTopView)
return; // z.B. FillMode
DataChanging(); // kann nicht neu sein
String aText = rFuncName;
if (bAddPar)
aText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "()" ));
if (pTableView)
{
pTableView->InsertText( aText, sal_False );
if (bAddPar)
{
ESelection aSel = pTableView->GetSelection();
--aSel.nStartPos;
--aSel.nEndPos;
pTableView->SetSelection(aSel);
}
}
if (pTopView)
{
pTopView->InsertText( aText, sal_False );
if (bAddPar)
{
ESelection aSel = pTopView->GetSelection();
--aSel.nStartPos;
--aSel.nEndPos;
pTopView->SetSelection(aSel);
}
}
DataChanged();
if (bAddPar)
AutoParAdded();
}
void ScInputHandler::ClearText()
{
if ( eMode == SC_INPUT_NONE )
{
DBG_ERROR("ClearText, nicht im Eingabemodus");
return;
}
UpdateActiveView();
if (!pTableView && !pTopView)
return; // z.B. FillMode
DataChanging(); // darf nicht neu sein
String aEmpty;
if (pTableView)
{
pTableView->GetEditEngine()->SetText( aEmpty );
pTableView->SetSelection( ESelection(0,0, 0,0) );
}
if (pTopView)
{
pTopView->GetEditEngine()->SetText( aEmpty );
pTopView->SetSelection( ESelection(0,0, 0,0) );
}
DataChanged();
}
sal_Bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, sal_Bool bStartEdit /* = sal_False */ )
{
if (!bOptLoaded)
{
bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
bOptLoaded = sal_True;
}
KeyCode aCode = rKEvt.GetKeyCode();
sal_uInt16 nModi = aCode.GetModifier();
sal_Bool bShift = aCode.IsShift();
sal_Bool bControl = aCode.IsMod1();
sal_Bool bAlt = aCode.IsMod2();
sal_uInt16 nCode = aCode.GetCode();
sal_Unicode nChar = rKEvt.GetCharCode();
// Alt-Return is accepted, everything else with ALT, or CTRL-TAB are not:
if (( bAlt && !bControl && nCode != KEY_RETURN ) ||
( bControl && aCode.GetCode() == KEY_TAB ))
return sal_False;
sal_Bool bInputLine = ( eMode==SC_INPUT_TOP );
sal_Bool bUsed = sal_False;
sal_Bool bSkip = sal_False;
sal_Bool bDoEnter = sal_False;
switch ( nCode )
{
case KEY_RETURN:
if (bControl && !bShift && !bInputLine)
bDoEnter = sal_True;
else if ( nModi == 0 && nTipVisible && pFormulaData && nAutoPos != SCPOS_INVALID )
{
PasteFunctionData();
bUsed = sal_True;
}
else if ( nModi == 0 && nTipVisible && aManualTip.Len() )
{
PasteManualTip();
bUsed = sal_True;
}
else
{
sal_uInt8 nMode = SC_ENTER_NORMAL;
if ( bShift && bControl )
nMode = SC_ENTER_MATRIX;
else if ( bAlt )
nMode = SC_ENTER_BLOCK;
EnterHandler( nMode );
if (pActiveViewSh)
pActiveViewSh->MoveCursorEnter( bShift && !bControl );
bUsed = sal_True;
}
break;
case KEY_TAB:
if (!bControl && !bAlt)
{
if ( pFormulaData && nTipVisible && nAutoPos != SCPOS_INVALID )
{
// blaettern
NextFormulaEntry( bShift );
}
else if ( pColumnData && bUseTab && nAutoPos != SCPOS_INVALID )
{
// in den Eintraegen der AutoEingabe blaettern
NextAutoEntry( bShift );
}
else
{
EnterHandler();
// TabKeyInput gibt auf manchen Rechnern unter W95 Stackueberlaeufe,
// darum direkter Aufruf:
if (pActiveViewSh)
pActiveViewSh->FindNextUnprot( bShift );
}
bUsed = sal_True;
}
break;
case KEY_ESCAPE:
if ( nTipVisible )
{
HideTip();
bUsed = sal_True;
}
else if( nTipVisibleSec )
{
HideTipBelow();
bUsed = sal_True;
}
else if (eMode != SC_INPUT_NONE)
{
CancelHandler();
bUsed = sal_True;
}
else
bSkip = sal_True;
break;
case KEY_F2:
if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
{
eMode = SC_INPUT_TYPE;
bUsed = sal_True;
}
break;
}
// Cursortasten nur ausfuehren, wenn schon im Edit-Modus
// z.B. wegen Shift-Ctrl-PageDn (ist nicht als Accelerator definiert)
sal_Bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
sal_Bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Insert wie Cursortasten behandeln
if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
{
HideTip();
HideTipBelow();
if (bSelIsRef)
{
RemoveSelection();
bSelIsRef = sal_False;
}
UpdateActiveView();
sal_Bool bNewView = DataChanging( nChar );
if (bProtected) // Zelle geschuetzt?
bUsed = sal_True; // Key-Event nicht weiterleiten
else // Aenderungen erlaubt
{
if (bNewView ) // neu anlegen
{
if (pActiveViewSh)
pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
UpdateActiveView();
if (eMode==SC_INPUT_NONE)
if (pTableView || pTopView)
{
String aStrLoP;
if ( bStartEdit && bCellHasPercentFormat && ((nChar >= '0' && nChar <= '9') || nChar == '-') )
aStrLoP = '%';
if (pTableView)
{
pTableView->GetEditEngine()->SetText( aStrLoP );
if ( aStrLoP.Len() )
pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
// don't call SetSelection if the string is empty anyway,
// to avoid breaking the bInitial handling in ScViewData::EditGrowY
}
if (pTopView)
{
pTopView->GetEditEngine()->SetText( aStrLoP );
if ( aStrLoP.Len() )
pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
}
}
SyncViews();
}
if (pTableView || pTopView)
{
// pActiveView->SetEditEngineUpdateMode(sal_True); //! gibt Muell !!!!
if (bDoEnter)
{
if (pTableView)
if( pTableView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
bUsed = sal_True;
if (pTopView)
if( pTopView->PostKeyEvent( KeyEvent( CHAR_CR, KeyCode(KEY_RETURN) ) ) )
bUsed = sal_True;
}
else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
{
SkipClosingPar();
bUsed = sal_True;
}
else
{
if (pTableView)
if ( pTableView->PostKeyEvent( rKEvt ) )
bUsed = sal_True;
if (pTopView)
if ( pTopView->PostKeyEvent( rKEvt ) )
bUsed = sal_True;
}
// Auto-Eingabe:
if ( bUsed && bAutoComplete )
{
bUseTab = sal_False;
nAutoPos = SCPOS_INVALID; // do not search further
KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
KEYFUNC_CUT != eFunc) // and no 'CTRL-X'
{
if (bFormulaMode)
UseFormulaData();
else
UseColData();
}
}
// when the selection is changed manually or an opening parenthesis
// is typed, stop overwriting parentheses
if ( bUsed && nChar == '(' )
ResetAutoPar();
if ( KEY_INSERT == nCode )
{
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if (pViewFrm)
pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
}
if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
{
ShowTipCursor();
}
}
// #i114511# don't count cursor keys as modification
sal_Bool bSetModified = !bCursorKey;
DataChanged(sal_False, bSetModified); // also calls UpdateParenthesis()
InvalidateAttribs(); //! in DataChanged ?
}
}
if (pTopView && eMode != SC_INPUT_NONE)
SyncViews();
return bUsed;
}
sal_Bool ScInputHandler::InputCommand( const CommandEvent& rCEvt, sal_Bool bForce )
{
sal_Bool bUsed = sal_False;
if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
{
// #90346# for COMMAND_CURSORPOS, do as little as possible, because
// with remote VCL, even a ShowCursor will generate another event.
if ( eMode != SC_INPUT_NONE )
{
UpdateActiveView();
if (pTableView || pTopView)
{
if (pTableView)
pTableView->Command( rCEvt );
else if (pTopView) // call only once
pTopView->Command( rCEvt );
bUsed = sal_True;
}
}
}
else
{
if ( bForce || eMode != SC_INPUT_NONE )
{
if (!bOptLoaded)
{
bAutoComplete = SC_MOD()->GetAppOptions().GetAutoComplete();
bOptLoaded = sal_True;
}
HideTip();
HideTipBelow();
if ( bSelIsRef )
{
RemoveSelection();
bSelIsRef = sal_False;
}
UpdateActiveView();
sal_Bool bNewView = DataChanging( 0, sal_True );
if (bProtected) // cell protected
bUsed = sal_True; // event is used
else // changes allowed
{
if (bNewView) // create new edit view
{
if (pActiveViewSh)
pActiveViewSh->GetViewData()->GetDocShell()->PostEditView( pEngine, aCursorPos );
UpdateActiveView();
if (eMode==SC_INPUT_NONE)
if (pTableView || pTopView)
{
String aStrLoP;
if (pTableView)
{
pTableView->GetEditEngine()->SetText( aStrLoP );
pTableView->SetSelection( ESelection(0,0, 0,0) );
}
if (pTopView)
{
pTopView->GetEditEngine()->SetText( aStrLoP );
pTopView->SetSelection( ESelection(0,0, 0,0) );
}
}
SyncViews();
}
if (pTableView || pTopView)
{
if (pTableView)
pTableView->Command( rCEvt );
if (pTopView)
pTopView->Command( rCEvt );
bUsed = sal_True;
if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
{
// AutoInput after ext text input
nAutoPos = SCPOS_INVALID;
if (bFormulaMode)
UseFormulaData();
else
UseColData();
}
}
DataChanged(); // calls UpdateParenthesis()
InvalidateAttribs(); //! in DataChanged ?
}
}
if (pTopView && eMode != SC_INPUT_NONE)
SyncViews();
}
return bUsed;
}
void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
sal_Bool bForce, ScTabViewShell* pSourceSh,
sal_Bool bStopEditing)
{
// #62806# Wenn der Aufruf aus einem Makro-Aufruf im EnterHandler kommt,
// gleich abbrechen und nicht den Status durcheinander bringen
if (bInEnterHandler)
return;
sal_Bool bRepeat = (pState == pLastState);
if (!bRepeat && pState && pLastState)
bRepeat = sal::static_int_cast<sal_Bool>(*pState == *pLastState);
if (bRepeat && !bForce)
return;
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
if ( pState && !pLastState ) // wieder enablen
bForce = sal_True;
sal_Bool bHadObject = pLastState && pLastState->GetEditData();
//! Before EditEngine gets eventually created (so it gets the right pools)
if ( pSourceSh )
pActiveViewSh = pSourceSh;
else
pActiveViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current());
ImplCreateEditEngine();
if ( pState != pLastState )
{
delete pLastState;
pLastState = pState ? new ScInputHdlState( *pState ) : NULL;
}
if ( pState && pActiveViewSh )
{
ScModule* pScMod = SC_MOD();
if ( pState )
{
sal_Bool bIgnore = sal_False;
// hier auch fremde Referenzeingabe beruecksichtigen (z.B. Funktions-AP),
// FormEditData falls gerade von der Hilfe auf Calc umgeschaltet wird:
if ( !bFormulaMode && !pScMod->IsFormulaMode() && !pScMod->GetFormEditData() )
{
if ( bModified )
{
if (pState->GetPos() != aCursorPos)
{
if (!bProtected)
EnterHandler();
}
else
bIgnore = sal_True;
}
if ( !bIgnore /* || bRepeat */ )
{
const ScAddress& rSPos = pState->GetStartPos();
const ScAddress& rEPos = pState->GetEndPos();
const EditTextObject* pData = pState->GetEditData();
String aString = pState->GetString();
sal_Bool bTxtMod = sal_False;
ScDocShell* pDocSh = pActiveViewSh->GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
aCursorPos = pState->GetPos();
if ( pData /* || bRepeat */ )
bTxtMod = sal_True;
else if ( bHadObject )
bTxtMod = sal_True;
else if ( bTextValid )
bTxtMod = ( aString != aCurrentText );
else
bTxtMod = ( aString != GetEditText(pEngine) );
if ( bTxtMod || bForce )
{
if (pData)
{
pEngine->SetText( *pData );
aString = GetEditText(pEngine);
lcl_RemoveTabs(aString);
bTextValid = sal_False;
aCurrentText.Erase();
}
else
{
aCurrentText = aString;
bTextValid = sal_True; //! erst nur als String merken
}
if ( pInputWin )
pInputWin->SetTextString(aString);
}
if ( pInputWin ) // Bereichsanzeige
{
String aPosStr;
const ScAddress::Details aAddrDetails( pDoc, aCursorPos );
// Ist der Bereich ein Name?
//! per Timer suchen ???
if ( pActiveViewSh )
pActiveViewSh->GetViewData()->GetDocument()->
GetRangeAtBlock( ScRange( rSPos, rEPos ), &aPosStr );
if ( !aPosStr.Len() ) // kein Name -> formatieren
{
sal_uInt16 nFlags = 0;
if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
nFlags |= SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;
if ( rSPos != rEPos )
{
ScRange r(rSPos, rEPos);
nFlags |= (nFlags << 4);
r.Format( aPosStr, SCA_VALID | nFlags, pDoc, aAddrDetails );
}
else
aCursorPos.Format( aPosStr, SCA_VALID | nFlags, pDoc, aAddrDetails );
}
// Disable the accessible VALUE_CHANGE event
sal_Bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(sal_False);
pInputWin->SetAccessibilityEventsSuppressed(sal_True);
pInputWin->SetPosString(aPosStr);
pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
pInputWin->SetSumAssignMode();
}
if (bStopEditing)
SFX_APP()->Broadcast( SfxSimpleHint( FID_KILLEDITVIEW ) );
// As long as the content is not edited, turn off online spelling.
// Online spelling is turned back on in StartTable, after setting
// the right language from cell attributes.
sal_uLong nCntrl = pEngine->GetControlWord();
if ( nCntrl & EE_CNTRL_ONLINESPELLING )
pEngine->SetControlWord( nCntrl & ~EE_CNTRL_ONLINESPELLING );
bModified = sal_False;
bSelIsRef = sal_False;
bProtected = sal_False;
bCommandErrorShown = sal_False;
}
}
}
// bProtected = sal_False;
if ( pInputWin)
{
if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen()) //BugID 54702
{ //Wenn RefDialog offen, dann nicht enablen
if ( !pInputWin->IsEnabled())
{
pInputWin->Enable();
if(pDelayTimer )
{
DELETEZ( pDelayTimer );
}
}
}
else if(pScMod->IsRefDialogOpen())
{ // Da jedes Dokument eigenes InputWin hat, sollte
if ( !pDelayTimer ) // nochmals Timer gestartet werden, da sonst Ein-
{ // gabezeile evt. noch aktiv ist.
pDelayTimer = new Timer;
pDelayTimer->SetTimeout( 500 ); // 100ms Verzoegerung
pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
pDelayTimer->Start();
}
}
}
}
else // !pState || !pActiveViewSh
{
if ( !pDelayTimer )
{
pDelayTimer = new Timer;
pDelayTimer->SetTimeout( 500 ); // 100ms Verzoegerung
pDelayTimer->SetTimeoutHdl( LINK( this, ScInputHandler, DelayTimer ) );
pDelayTimer->Start();
}
}
HideTip();
HideTipBelow();
bInOwnChange = sal_False;
}
void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
{
eAttrAdjust = eJust;
UpdateAdjust( 0 );
}
void ScInputHandler::ResetDelayTimer()
{
if(pDelayTimer!=NULL)
{
DELETEZ( pDelayTimer );
if ( pInputWin)
{
pInputWin->Enable();
}
}
}
IMPL_LINK( ScInputHandler, DelayTimer, Timer*, pTimer )
{
if ( pTimer == pDelayTimer )
{
DELETEZ( pDelayTimer );
if ( NULL == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen())
{
//! new method at ScModule to query if function autopilot is open
SfxViewFrame* pViewFrm = SfxViewFrame::Current();
if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
{
if ( pInputWin)
{
pInputWin->EnableButtons( sal_False );
pInputWin->Disable();
}
}
else if ( !bFormulaMode ) // #39210# Formel auch z.B. bei Hilfe behalten
{
bInOwnChange = sal_True; // disable ModifyHdl (reset below)
pActiveViewSh = NULL;
pEngine->SetText( EMPTY_STRING );
if ( pInputWin )
{
pInputWin->SetPosString( EMPTY_STRING );
pInputWin->SetTextString( EMPTY_STRING );
pInputWin->Disable();
}
bInOwnChange = sal_False;
}
}
}
return 0;
}
void ScInputHandler::InputSelection( EditView* pView )
{
SyncViews( pView );
ShowTipCursor();
UpdateParenthesis(); // Selektion geaendert -> Klammer-Hervorhebung neu
// when the selection is changed manually, stop overwriting parentheses
ResetAutoPar();
}
void ScInputHandler::InputChanged( EditView* pView, sal_Bool bFromNotify )
{
ESelection aSelection = pView->GetSelection();
UpdateActiveView();
// #i20282# DataChanged needs to know if this is from the input line's modify handler
sal_Bool bFromTopNotify = ( bFromNotify && pView == pTopView );
sal_Bool bNewView = DataChanging(); //! kann das hier ueberhaupt sein?
aCurrentText = pView->GetEditEngine()->GetText(); // auch den String merken
pEngine->SetText( aCurrentText );
DataChanged( bFromTopNotify );
bTextValid = sal_True; // wird in DataChanged auf sal_False gesetzt
if ( pActiveViewSh )
{
ScViewData* pViewData = pActiveViewSh->GetViewData();
if ( bNewView )
pViewData->GetDocShell()->PostEditView( pEngine, aCursorPos );
pViewData->EditGrowY();
pViewData->EditGrowX();
}
SyncViews( pView );
}
const String& ScInputHandler::GetEditString()
{
if (pEngine)
{
aCurrentText = pEngine->GetText(); // immer neu aus Engine
bTextValid = sal_True;
}
return aCurrentText;
}
Size ScInputHandler::GetTextSize()
{
Size aSize;
if ( pEngine )
aSize = Size( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
return aSize;
}
sal_Bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
{
sal_Bool bRet = sal_False;
if (pEngine)
{
// Feldbefehle enthalten?
sal_uInt16 nParCnt = pEngine->GetParagraphCount();
SfxItemSet aSet = pEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, sal_False );
if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET )
{
// Inhalt kopieren
EditTextObject* pObj = pEngine->CreateTextObject();
rDestEngine.SetText(*pObj);
delete pObj;
// Attribute loeschen
for (sal_uInt16 i=0; i<nParCnt; i++)
rDestEngine.QuickRemoveCharAttribs( i );
// Absaetze zusammenfassen
while ( nParCnt > 1 )
{
xub_StrLen nLen = rDestEngine.GetTextLen( (sal_uInt16)0 );
ESelection aSel( 0,nLen, 1,0 );
rDestEngine.QuickInsertText( ' ', aSel ); // Umbruch durch Space ersetzen
--nParCnt;
}
bRet = sal_True;
}
}
return bRet;
}
//------------------------------------------------------------------------
// Methoden fuer FunktionsAutopiloten:
// InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
//------------------------------------------------------------------------
void ScInputHandler::InputGetSelection( xub_StrLen& rStart, xub_StrLen& rEnd )
{
rStart = nFormSelStart;
rEnd = nFormSelEnd;
}
//------------------------------------------------------------------------
EditView* ScInputHandler::GetFuncEditView()
{
UpdateActiveView(); // wegen pTableView
EditView* pView = NULL;
if ( pInputWin )
{
pInputWin->MakeDialogEditView();
pView = pInputWin->GetEditView();
}
else
{
if ( eMode != SC_INPUT_TABLE )
{
bCreatingFuncView = sal_True; // RangeFinder nicht anzeigen
SetMode( SC_INPUT_TABLE );
bCreatingFuncView = sal_False;
if ( pTableView )
pTableView->GetEditEngine()->SetText( EMPTY_STRING );
}
pView = pTableView;
}
return pView;
}
//------------------------------------------------------------------------
void ScInputHandler::InputSetSelection( xub_StrLen nStart, xub_StrLen nEnd )
{
if ( nStart <= nEnd )
{
nFormSelStart = nStart;
nFormSelEnd = nEnd;
}
else
{
nFormSelEnd = nStart;
nFormSelStart = nEnd;
}
EditView* pView = GetFuncEditView();
if (pView)
pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
bModified = sal_True;
}
//------------------------------------------------------------------------
void ScInputHandler::InputReplaceSelection( const String& rStr )
{
if (!pRefViewSh)
pRefViewSh = pActiveViewSh;
DBG_ASSERT(nFormSelEnd>=nFormSelStart,"Selektion kaputt...");
xub_StrLen nOldLen = nFormSelEnd-nFormSelStart;
xub_StrLen nNewLen = rStr.Len();
if (nOldLen)
aFormText.Erase( nFormSelStart, nOldLen );
if (nNewLen)
aFormText.Insert( rStr, nFormSelStart );
nFormSelEnd = nFormSelStart + nNewLen;
EditView* pView = GetFuncEditView();
if (pView)
{
pView->SetEditEngineUpdateMode( sal_False );
// pView->InsertText( rStr, sal_True );
pView->GetEditEngine()->SetText( aFormText );
pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
pView->SetEditEngineUpdateMode( sal_True );
}
bModified = sal_True;
}
//------------------------------------------------------------------------
String ScInputHandler::InputGetFormulaStr()
{
return aFormText; //! eigene Membervariable?
}
//========================================================================
// ScInputHdlState
//========================================================================
ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
const ScAddress& rStartPos,
const ScAddress& rEndPos,
const String& rString,
const EditTextObject* pData )
: aCursorPos ( rCurPos ),
aStartPos ( rStartPos ),
aEndPos ( rEndPos ),
aString ( rString ),
pEditData ( pData ? pData->Clone() : NULL )
{
}
//------------------------------------------------------------------------
ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
: pEditData ( NULL )
{
*this = rCpy;
}
//------------------------------------------------------------------------
ScInputHdlState::~ScInputHdlState()
{
delete pEditData;
}
//------------------------------------------------------------------------
int ScInputHdlState::operator==( const ScInputHdlState& r ) const
{
return ( (aStartPos == r.aStartPos)
&& (aEndPos == r.aEndPos)
&& (aCursorPos == r.aCursorPos)
&& (aString == r.aString)
&& ScGlobal::EETextObjEqual( pEditData, r.pEditData ) );
}
//------------------------------------------------------------------------
ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
{
delete pEditData;
aCursorPos = r.aCursorPos;
aStartPos = r.aStartPos;
aEndPos = r.aEndPos;
aString = r.aString;
pEditData = r.pEditData ? r.pEditData->Clone() : NULL;
return *this;
}