/************************************************************** * * 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" // System - Includes ----------------------------------------------------- // INCLUDE --------------------------------------------------------------- #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef _SVSTDARR_USHORTS #define _SVSTDARR_USHORTS #include #endif #include "editutil.hxx" #include "global.hxx" #include "attrib.hxx" #include "document.hxx" #include "docpool.hxx" #include "patattr.hxx" #include "scmod.hxx" #include "inputopt.hxx" #include "compiler.hxx" // STATIC DATA ----------------------------------------------------------- // Delimiters zusaetzlich zu EditEngine-Default: const sal_Char __FAR_DATA ScEditUtil::pCalcDelimiters[] = "=()+-*/^&<>"; //------------------------------------------------------------------------ String ScEditUtil::ModifyDelimiters( const String& rOld ) { String aRet = rOld; aRet.EraseAllChars( '_' ); // underscore is used in function argument names aRet.AppendAscii( RTL_CONSTASCII_STRINGPARAM( pCalcDelimiters ) ); aRet.Append(ScCompiler::GetNativeSymbol(ocSep)); // argument separator is localized. return aRet; } static String lcl_GetDelimitedString( const EditEngine& rEngine, const sal_Char c ) { String aRet; sal_uInt32 nParCount = rEngine.GetParagraphCount(); for (sal_uInt32 nPar=0; nPar 0) aRet += c; aRet += rEngine.GetText( nPar ); } return aRet; } String ScEditUtil::GetSpaceDelimitedString( const EditEngine& rEngine ) { return lcl_GetDelimitedString(rEngine, ' '); } String ScEditUtil::GetMultilineString( const EditEngine& rEngine ) { return lcl_GetDelimitedString(rEngine, '\n'); } //------------------------------------------------------------------------ Rectangle ScEditUtil::GetEditArea( const ScPatternAttr* pPattern, sal_Bool bForceToTop ) { // bForceToTop = always align to top, for editing // (sal_False for querying URLs etc.) if (!pPattern) pPattern = pDoc->GetPattern( nCol, nRow, nTab ); Point aStartPos = aScrPos; sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); long nLayoutSign = bLayoutRTL ? -1 : 1; const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE); long nCellX = (long) ( pDoc->GetColWidth(nCol,nTab) * nPPTX ); if ( pMerge->GetColMerge() > 1 ) { SCCOL nCountX = pMerge->GetColMerge(); for (SCCOL i=1; iGetColWidth(nCol+i,nTab) * nPPTX ); } long nCellY = (long) ( pDoc->GetRowHeight(nRow,nTab) * nPPTY ); if ( pMerge->GetRowMerge() > 1 ) { SCROW nCountY = pMerge->GetRowMerge(); nCellY += (long) pDoc->GetScaledRowHeight( nRow+1, nRow+nCountY-1, nTab, nPPTY); } const SvxMarginItem* pMargin = (const SvxMarginItem*)&pPattern->GetItem(ATTR_MARGIN); sal_uInt16 nIndent = 0; if ( ((const SvxHorJustifyItem&)pPattern->GetItem(ATTR_HOR_JUSTIFY)).GetValue() == SVX_HOR_JUSTIFY_LEFT ) nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue(); long nPixDifX = (long) ( ( pMargin->GetLeftMargin() + nIndent ) * nPPTX ); aStartPos.X() += nPixDifX * nLayoutSign; nCellX -= nPixDifX + (long) ( pMargin->GetRightMargin() * nPPTX ); // wegen Umbruch etc. // vertikale Position auf die in der Tabelle anpassen long nPixDifY; long nTopMargin = (long) ( pMargin->GetTopMargin() * nPPTY ); SvxCellVerJustify eJust = (SvxCellVerJustify) ((const SvxVerJustifyItem&)pPattern-> GetItem(ATTR_VER_JUSTIFY)).GetValue(); // asian vertical is always edited top-aligned sal_Bool bAsianVertical = ((const SfxBoolItem&)pPattern->GetItem( ATTR_STACKED )).GetValue() && ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN )).GetValue(); if ( eJust == SVX_VER_JUSTIFY_TOP || ( bForceToTop && ( SC_MOD()->GetInputOptions().GetTextWysiwyg() || bAsianVertical ) ) ) nPixDifY = nTopMargin; else { MapMode aMode = pDev->GetMapMode(); pDev->SetMapMode( MAP_PIXEL ); long nTextHeight = pDoc->GetNeededSize( nCol, nRow, nTab, pDev, nPPTX, nPPTY, aZoomX, aZoomY, sal_False ); if (!nTextHeight) { // leere Zelle Font aFont; // font color doesn't matter here pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aZoomY ); pDev->SetFont(aFont); nTextHeight = pDev->GetTextHeight() + nTopMargin + (long) ( pMargin->GetBottomMargin() * nPPTY ); } pDev->SetMapMode(aMode); if ( nTextHeight > nCellY + nTopMargin || bForceToTop ) nPixDifY = 0; // zu gross -> oben anfangen else { if ( eJust == SVX_VER_JUSTIFY_CENTER ) nPixDifY = nTopMargin + ( nCellY - nTextHeight ) / 2; else nPixDifY = nCellY - nTextHeight + nTopMargin; // JUSTIFY_BOTTOM } } aStartPos.Y() += nPixDifY; nCellY -= nPixDifY; if ( bLayoutRTL ) aStartPos.X() -= nCellX - 2; // excluding grid on both sides // -1 -> Gitter nicht ueberschreiben return Rectangle( aStartPos, Size(nCellX-1,nCellY-1) ); } //------------------------------------------------------------------------ ScEditAttrTester::ScEditAttrTester( ScEditEngineDefaulter* pEng ) : pEngine( pEng ), pEditAttrs( NULL ), bNeedsObject( sal_False ), bNeedsCellAttr( sal_False ) { if ( pEngine->GetParagraphCount() > 1 ) { bNeedsObject = sal_True; //! Zellatribute finden ? } else { const SfxPoolItem* pItem = NULL; pEditAttrs = new SfxItemSet( pEngine->GetAttribs( ESelection(0,0,0,pEngine->GetTextLen(0)), EditEngineAttribs_OnlyHard ) ); const SfxItemSet& rEditDefaults = pEngine->GetDefaults(); for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bNeedsObject; nId++) { SfxItemState eState = pEditAttrs->GetItemState( nId, sal_False, &pItem ); if (eState == SFX_ITEM_DONTCARE) bNeedsObject = sal_True; else if (eState == SFX_ITEM_SET) { if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING || nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS ) { // Escapement and kerning are kept in EditEngine because there are no // corresponding cell format items. User defined attributes are kept in // EditEngine because "user attributes applied to all the text" is different // from "user attributes applied to the cell". if ( *pItem != rEditDefaults.Get(nId) ) bNeedsObject = sal_True; } else if (!bNeedsCellAttr) if ( *pItem != rEditDefaults.Get(nId) ) bNeedsCellAttr = sal_True; // rEditDefaults contains the defaults from the cell format } } // Feldbefehle enthalten? SfxItemState eFieldState = pEditAttrs->GetItemState( EE_FEATURE_FIELD, sal_False ); if ( eFieldState == SFX_ITEM_DONTCARE || eFieldState == SFX_ITEM_SET ) bNeedsObject = sal_True; // not converted characters? SfxItemState eConvState = pEditAttrs->GetItemState( EE_FEATURE_NOTCONV, sal_False ); if ( eConvState == SFX_ITEM_DONTCARE || eConvState == SFX_ITEM_SET ) bNeedsObject = sal_True; } } ScEditAttrTester::~ScEditAttrTester() { delete pEditAttrs; } //------------------------------------------------------------------------ ScEnginePoolHelper::ScEnginePoolHelper( SfxItemPool* pEnginePoolP, sal_Bool bDeleteEnginePoolP ) : pEnginePool( pEnginePoolP ), pDefaults( NULL ), bDeleteEnginePool( bDeleteEnginePoolP ), bDeleteDefaults( sal_False ) { } ScEnginePoolHelper::ScEnginePoolHelper( const ScEnginePoolHelper& rOrg ) : pEnginePool( rOrg.bDeleteEnginePool ? rOrg.pEnginePool->Clone() : rOrg.pEnginePool ), pDefaults( NULL ), bDeleteEnginePool( rOrg.bDeleteEnginePool ), bDeleteDefaults( sal_False ) { } ScEnginePoolHelper::~ScEnginePoolHelper() { if ( bDeleteDefaults ) delete pDefaults; if ( bDeleteEnginePool ) SfxItemPool::Free(pEnginePool); } //------------------------------------------------------------------------ ScEditEngineDefaulter::ScEditEngineDefaulter( SfxItemPool* pEnginePoolP, sal_Bool bDeleteEnginePoolP ) : ScEnginePoolHelper( pEnginePoolP, bDeleteEnginePoolP ), EditEngine( pEnginePoolP ) { // All EditEngines use ScGlobal::GetEditDefaultLanguage as DefaultLanguage. // DefaultLanguage for InputHandler's EditEngine is updated later. SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() ); } ScEditEngineDefaulter::ScEditEngineDefaulter( const ScEditEngineDefaulter& rOrg ) : ScEnginePoolHelper( rOrg ), EditEngine( pEnginePool ) { SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() ); } ScEditEngineDefaulter::~ScEditEngineDefaulter() { } void ScEditEngineDefaulter::SetDefaults( const SfxItemSet& rSet, sal_Bool bRememberCopy ) { if ( bRememberCopy ) { if ( bDeleteDefaults ) delete pDefaults; pDefaults = new SfxItemSet( rSet ); bDeleteDefaults = sal_True; } const SfxItemSet& rNewSet = bRememberCopy ? *pDefaults : rSet; sal_Bool bUndo = IsUndoEnabled(); EnableUndo( sal_False ); sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); sal_uInt32 nPara = GetParagraphCount(); for ( sal_uInt32 j=0; jPut( rItem ); SetDefaults( *pDefaults, sal_False ); } const SfxItemSet& ScEditEngineDefaulter::GetDefaults() { if ( !pDefaults ) { pDefaults = new SfxItemSet( GetEmptyItemSet() ); bDeleteDefaults = sal_True; } return *pDefaults; } void ScEditEngineDefaulter::SetText( const EditTextObject& rTextObject ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rTextObject ); if ( pDefaults ) SetDefaults( *pDefaults, sal_False ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject, const SfxItemSet& rSet, sal_Bool bRememberCopy ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rTextObject ); SetDefaults( rSet, bRememberCopy ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::SetTextNewDefaults( const EditTextObject& rTextObject, SfxItemSet* pSet, sal_Bool bTakeOwnership ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rTextObject ); SetDefaults( pSet, bTakeOwnership ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::SetText( const String& rText ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rText ); if ( pDefaults ) SetDefaults( *pDefaults, sal_False ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText, const SfxItemSet& rSet, sal_Bool bRememberCopy ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rText ); SetDefaults( rSet, bRememberCopy ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::SetTextNewDefaults( const String& rText, SfxItemSet* pSet, sal_Bool bTakeOwnership ) { sal_Bool bUpdateMode = GetUpdateMode(); if ( bUpdateMode ) SetUpdateMode( sal_False ); EditEngine::SetText( rText ); SetDefaults( pSet, bTakeOwnership ); if ( bUpdateMode ) SetUpdateMode( sal_True ); } void ScEditEngineDefaulter::RepeatDefaults() { if ( pDefaults ) { sal_uInt32 nPara = GetParagraphCount(); for ( sal_uInt32 j=0; jGet(nWhich) ) { if (!pCharItems) pCharItems = new SfxItemSet( GetEmptyItemSet() ); pCharItems->Put( *pParaItem ); } } } if ( pCharItems ) { SvUShorts aPortions; GetPortions( nPar, aPortions ); // loop through the portions of the paragraph, and set only those items // that are not overridden by existing character attributes sal_uInt16 nPCount = aPortions.Count(); sal_uInt16 nStart = 0; for ( sal_uInt16 nPos=0; nPosGetEnginePool() ) { SetEditTextObjectPool( pDoc->GetEditPool() ); Init((const ScPatternAttr&)pDoc->GetPool()->GetDefaultItem(ATTR_PATTERN)); } ScTabEditEngine::ScTabEditEngine( const ScPatternAttr& rPattern, SfxItemPool* pEnginePoolP, SfxItemPool* pTextObjectPool ) : ScEditEngineDefaulter( pEnginePoolP ) { if ( pTextObjectPool ) SetEditTextObjectPool( pTextObjectPool ); Init( rPattern ); } void ScTabEditEngine::Init( const ScPatternAttr& rPattern ) { SetRefMapMode(MAP_100TH_MM); SfxItemSet* pEditDefaults = new SfxItemSet( GetEmptyItemSet() ); rPattern.FillEditItemSet( pEditDefaults ); SetDefaults( pEditDefaults ); // wir haben keine StyleSheets fuer Text SetControlWord( GetControlWord() & ~EE_CNTRL_RTFSTYLESHEETS ); } //------------------------------------------------------------------------ // Feldbefehle fuer Kopf- und Fusszeilen //------------------------------------------------------------------------ // // Zahlen aus \sw\source\core\doc\numbers.cxx // String lcl_GetCharStr( sal_Int32 nNo ) { DBG_ASSERT( nNo, "0 ist eine ungueltige Nummer !!" ); String aStr; const sal_Int32 coDiff = 'Z' - 'A' +1; sal_Int32 nCalc; do { nCalc = nNo % coDiff; if( !nCalc ) nCalc = coDiff; aStr.Insert( (sal_Unicode)('a' - 1 + nCalc ), 0 ); nNo = sal::static_int_cast( nNo - nCalc ); if( nNo ) nNo /= coDiff; } while( nNo ); return aStr; } String lcl_GetNumStr( sal_Int32 nNo, SvxNumType eType ) { String aTmpStr( '0' ); if( nNo ) { switch( eType ) { case SVX_CHARS_UPPER_LETTER: case SVX_CHARS_LOWER_LETTER: aTmpStr = lcl_GetCharStr( nNo ); break; case SVX_ROMAN_UPPER: case SVX_ROMAN_LOWER: if( nNo < 4000 ) aTmpStr = SvxNumberFormat::CreateRomanString( nNo, ( eType == SVX_ROMAN_UPPER ) ); else aTmpStr.Erase(); break; case SVX_NUMBER_NONE: aTmpStr.Erase(); break; // CHAR_SPECIAL: // ???? // case ARABIC: ist jetzt default default: aTmpStr = String::CreateFromInt32( nNo ); break; } if( SVX_CHARS_UPPER_LETTER == eType ) aTmpStr.ToUpperAscii(); } return aTmpStr; } ScHeaderFieldData::ScHeaderFieldData() { nPageNo = nTotalPages = 0; eNumType = SVX_ARABIC; } ScHeaderEditEngine::ScHeaderEditEngine( SfxItemPool* pEnginePoolP, sal_Bool bDeleteEnginePoolP ) : ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ) { } String __EXPORT ScHeaderEditEngine::CalcFieldValue( const SvxFieldItem& rField, sal_uInt32 /* nPara */, sal_uInt16 /* nPos */, Color*& /* rTxtColor */, Color*& /* rFldColor */ ) { String aRet; const SvxFieldData* pFieldData = rField.GetField(); if ( pFieldData ) { TypeId aType = pFieldData->Type(); if (aType == TYPE(SvxPageField)) aRet = lcl_GetNumStr( aData.nPageNo,aData.eNumType ); else if (aType == TYPE(SvxPagesField)) aRet = lcl_GetNumStr( aData.nTotalPages,aData.eNumType ); else if (aType == TYPE(SvxTimeField)) aRet = ScGlobal::pLocaleData->getTime(aData.aTime); else if (aType == TYPE(SvxFileField)) aRet = aData.aTitle; else if (aType == TYPE(SvxExtFileField)) { switch ( ((const SvxExtFileField*)pFieldData)->GetFormat() ) { case SVXFILEFORMAT_FULLPATH : aRet = aData.aLongDocName; break; default: aRet = aData.aShortDocName; } } else if (aType == TYPE(SvxTableField)) aRet = aData.aTabName; else if (aType == TYPE(SvxDateField)) aRet = ScGlobal::pLocaleData->getDate(aData.aDate); else { //DBG_ERROR("unbekannter Feldbefehl"); aRet = '?'; } } else { DBG_ERROR("FieldData ist 0"); aRet = '?'; } return aRet; } //------------------------------------------------------------------------ // // Feld-Daten // //------------------------------------------------------------------------ ScFieldEditEngine::ScFieldEditEngine( SfxItemPool* pEnginePoolP, SfxItemPool* pTextObjectPool, sal_Bool bDeleteEnginePoolP ) : ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ), bExecuteURL( sal_True ) { if ( pTextObjectPool ) SetEditTextObjectPool( pTextObjectPool ); // EE_CNTRL_URLSFXEXECUTE nicht, weil die Edit-Engine den ViewFrame nicht kennt // wir haben keine StyleSheets fuer Text SetControlWord( (GetControlWord() | EE_CNTRL_MARKFIELDS) & ~EE_CNTRL_RTFSTYLESHEETS ); } String __EXPORT ScFieldEditEngine::CalcFieldValue( const SvxFieldItem& rField, sal_uInt32 /* nPara */, sal_uInt16 /* nPos */, Color*& rTxtColor, Color*& /* rFldColor */ ) { String aRet; const SvxFieldData* pFieldData = rField.GetField(); if ( pFieldData ) { TypeId aType = pFieldData->Type(); if (aType == TYPE(SvxURLField)) { String aURL = ((const SvxURLField*)pFieldData)->GetURL(); switch ( ((const SvxURLField*)pFieldData)->GetFormat() ) { case SVXURLFORMAT_APPDEFAULT: //!!! einstellbar an App??? case SVXURLFORMAT_REPR: aRet = ((const SvxURLField*)pFieldData)->GetRepresentation(); break; case SVXURLFORMAT_URL: aRet = aURL; break; } svtools::ColorConfigEntry eEntry = INetURLHistory::GetOrCreate()->QueryUrl( aURL ) ? svtools::LINKSVISITED : svtools::LINKS; rTxtColor = new Color( SC_MOD()->GetColorConfig().GetColorValue(eEntry).nColor ); } else { //DBG_ERROR("unbekannter Feldbefehl"); aRet = '?'; } } if (!aRet.Len()) // leer ist baeh aRet = ' '; // Space ist Default der Editengine return aRet; } void __EXPORT ScFieldEditEngine::FieldClicked( const SvxFieldItem& rField, sal_uInt32, sal_uInt16 ) { const SvxFieldData* pFld = rField.GetField(); if ( pFld && pFld->ISA( SvxURLField ) && bExecuteURL ) { const SvxURLField* pURLField = (const SvxURLField*) pFld; ScGlobal::OpenURL( pURLField->GetURL(), pURLField->GetTargetFrame() ); } } //------------------------------------------------------------------------ ScNoteEditEngine::ScNoteEditEngine( SfxItemPool* pEnginePoolP, SfxItemPool* pTextObjectPool, sal_Bool bDeleteEnginePoolP ) : ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ) { if ( pTextObjectPool ) SetEditTextObjectPool( pTextObjectPool ); SetControlWord( (GetControlWord() | EE_CNTRL_MARKFIELDS) & ~EE_CNTRL_RTFSTYLESHEETS ); }