diff options
Diffstat (limited to 'sc/source/core/data/documen8.cxx')
-rw-r--r-- | sc/source/core/data/documen8.cxx | 1625 |
1 files changed, 1625 insertions, 0 deletions
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx new file mode 100644 index 000000000000..e3c9d251fab7 --- /dev/null +++ b/sc/source/core/data/documen8.cxx @@ -0,0 +1,1625 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#define _ZFORLIST_DECLARE_TABLE +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + +#include <tools/string.hxx> +#include <editeng/editobj.hxx> +#include <editeng/editstat.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/langitem.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/unolingu.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <svl/flagitem.hxx> +#include <svl/intitem.hxx> +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <unotools/misccfg.hxx> +#include <sfx2/app.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/securityoptions.hxx> + +#include <vcl/virdev.hxx> +#include <vcl/msgbox.hxx> + +#include "inputopt.hxx" +#include "global.hxx" +#include "table.hxx" +#include "column.hxx" +#include "cell.hxx" +#include "poolhelp.hxx" +#include "docpool.hxx" +#include "stlpool.hxx" +#include "stlsheet.hxx" +#include "docoptio.hxx" +#include "viewopti.hxx" +#include "scextopt.hxx" +#include "rechead.hxx" +#include "ddelink.hxx" +#include "scmatrix.hxx" +#include "arealink.hxx" +#include "dociter.hxx" +#include "patattr.hxx" +#include "hints.hxx" +#include "editutil.hxx" +#include "progress.hxx" +#include "document.hxx" +#include "chartlis.hxx" +#include "chartlock.hxx" +#include "refupdat.hxx" +#include "validat.hxx" // fuer HasMacroCalls +#include "markdata.hxx" +#include "scmod.hxx" +#include "printopt.hxx" +#include "externalrefmgr.hxx" +#include "globstr.hrc" +#include "sc.hrc" +#include "charthelper.hxx" +#include "dpobject.hxx" + +#define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue() + +// states for online spelling in the visible range (0 is set initially) +#define VSPL_START 0 +#define VSPL_DONE 1 + + +// STATIC DATA ----------------------------------------------------------- + +//------------------------------------------------------------------------ + +void ScDocument::ImplCreateOptions() +{ + pDocOptions = new ScDocOptions(); + pViewOptions = new ScViewOptions(); +} + +//------------------------------------------------------------------------ + +void ScDocument::ImplDeleteOptions() +{ + delete pDocOptions; + delete pViewOptions; + delete pExtDocOptions; +} + +//------------------------------------------------------------------------ + +SfxPrinter* ScDocument::GetPrinter(BOOL bCreateIfNotExist) +{ + if ( !pPrinter && bCreateIfNotExist ) + { + SfxItemSet* pSet = + new SfxItemSet( *xPoolHelper->GetDocPool(), + SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC, + SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET, + SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS, + NULL ); + + ::utl::MiscCfg aMisc; + USHORT nFlags = 0; + if ( aMisc.IsPaperOrientationWarning() ) + nFlags |= SFX_PRINTER_CHG_ORIENTATION; + if ( aMisc.IsPaperSizeWarning() ) + nFlags |= SFX_PRINTER_CHG_SIZE; + pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) ); + pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) ); + + pPrinter = new SfxPrinter( pSet ); + pPrinter->SetMapMode( MAP_100TH_MM ); + UpdateDrawPrinter(); + pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); + } + + return pPrinter; +} + +//------------------------------------------------------------------------ + +void ScDocument::SetPrinter( SfxPrinter* pNewPrinter ) +{ + if ( pNewPrinter == pPrinter ) + { + // #i6706# SetPrinter is called with the same printer again if + // the JobSetup has changed. In that case just call UpdateDrawPrinter + // (SetRefDevice for drawing layer) because of changed text sizes. + UpdateDrawPrinter(); + } + else + { + SfxPrinter* pOld = pPrinter; + pPrinter = pNewPrinter; + UpdateDrawPrinter(); + pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); + delete pOld; + } + InvalidateTextWidth(NULL, NULL, FALSE); // in both cases +} + +//------------------------------------------------------------------------ + +void ScDocument::SetPrintOptions() +{ + if ( !pPrinter ) GetPrinter(); // setzt pPrinter + DBG_ASSERT( pPrinter, "Error in printer creation :-/" ); + + if ( pPrinter ) + { + ::utl::MiscCfg aMisc; + SfxItemSet aOptSet( pPrinter->GetOptions() ); + + USHORT nFlags = 0; + if ( aMisc.IsPaperOrientationWarning() ) + nFlags |= SFX_PRINTER_CHG_ORIENTATION; + if ( aMisc.IsPaperSizeWarning() ) + nFlags |= SFX_PRINTER_CHG_SIZE; + aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) ); + aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, aMisc.IsNotFoundWarning() ) ); + + pPrinter->SetOptions( aOptSet ); + } +} + +//------------------------------------------------------------------------ + +VirtualDevice* ScDocument::GetVirtualDevice_100th_mm() +{ + if (!pVirtualDevice_100th_mm) + { +// pVirtualDevice_100th_mm = new VirtualDevice; +// pVirtualDevice_100th_mm->SetMapMode( MAP_100TH_MM ); + + pVirtualDevice_100th_mm = new VirtualDevice( 1 ); + pVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::REFDEV_MODE_MSO1); + MapMode aMapMode( pVirtualDevice_100th_mm->GetMapMode() ); + aMapMode.SetMapUnit( MAP_100TH_MM ); + pVirtualDevice_100th_mm->SetMapMode( aMapMode ); + } + return pVirtualDevice_100th_mm; +} + +OutputDevice* ScDocument::GetRefDevice() +{ + // Create printer like ref device, see Writer... + OutputDevice* pRefDevice = NULL; + if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() ) + pRefDevice = GetPrinter(); + else + pRefDevice = GetVirtualDevice_100th_mm(); + return pRefDevice; +} + +//------------------------------------------------------------------------ + +void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet, + const SfxItemSet& rChanges ) +{ + SfxItemSet& rSet = rStyleSheet.GetItemSet(); + + switch ( rStyleSheet.GetFamily() ) + { + case SFX_STYLE_FAMILY_PAGE: + { + const USHORT nOldScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE); + const USHORT nOldScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES); + rSet.Put( rChanges ); + const USHORT nNewScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE); + const USHORT nNewScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES); + + if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) ) + InvalidateTextWidth( rStyleSheet.GetName() ); + + if( SvtLanguageOptions().IsCTLFontEnabled() ) + { + const SfxPoolItem *pItem = NULL; + if( rChanges.GetItemState(ATTR_WRITINGDIR, TRUE, &pItem ) == SFX_ITEM_SET ) + ScChartHelper::DoUpdateAllCharts( this ); + } + } + break; + + case SFX_STYLE_FAMILY_PARA: + { + BOOL bNumFormatChanged; + if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, + rSet, rChanges ) ) + InvalidateTextWidth( NULL, NULL, bNumFormatChanged ); + + for (SCTAB nTab=0; nTab<=MAXTAB; ++nTab) + if (pTab[nTab] && pTab[nTab]->IsStreamValid()) + pTab[nTab]->SetStreamValid( FALSE ); + + ULONG nOldFormat = + ((const SfxUInt32Item*)&rSet.Get( + ATTR_VALUE_FORMAT ))->GetValue(); + ULONG nNewFormat = + ((const SfxUInt32Item*)&rChanges.Get( + ATTR_VALUE_FORMAT ))->GetValue(); + LanguageType eNewLang, eOldLang; + eNewLang = eOldLang = LANGUAGE_DONTKNOW; + if ( nNewFormat != nOldFormat ) + { + SvNumberFormatter* pFormatter = GetFormatTable(); + eOldLang = pFormatter->GetEntry( nOldFormat )->GetLanguage(); + eNewLang = pFormatter->GetEntry( nNewFormat )->GetLanguage(); + } + + // Bedeutung der Items in rChanges: + // Item gesetzt - Aenderung uebernehmen + // Dontcare - Default setzen + // Default - keine Aenderung + // ("keine Aenderung" geht nicht mit PutExtended, darum Schleife) + for (USHORT nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++) + { + const SfxPoolItem* pItem; + SfxItemState eState = rChanges.GetItemState( nWhich, FALSE, &pItem ); + if ( eState == SFX_ITEM_SET ) + rSet.Put( *pItem ); + else if ( eState == SFX_ITEM_DONTCARE ) + rSet.ClearItem( nWhich ); + // bei Default nichts + } + + if ( eNewLang != eOldLang ) + rSet.Put( + SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) ); + } + break; + default: + { + // added to avoid warnings + } + } +} + +//------------------------------------------------------------------------ + +void ScDocument::CopyStdStylesFrom( ScDocument* pSrcDoc ) +{ + // #b5017505# number format exchange list has to be handled here, too + NumFmtMergeHandler aNumFmtMergeHdl(this, pSrcDoc); + xPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->xPoolHelper->GetStylePool() ); +} + +//------------------------------------------------------------------------ + +void ScDocument::InvalidateTextWidth( const String& rStyleName ) +{ + const SCTAB nCount = GetTableCount(); + for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) + if ( pTab[i]->GetPageStyle() == rStyleName ) + InvalidateTextWidth( i ); +} + +//------------------------------------------------------------------------ + +void ScDocument::InvalidateTextWidth( SCTAB nTab ) +{ + ScAddress aAdrFrom( 0, 0, nTab ); + ScAddress aAdrTo ( MAXCOL, MAXROW, nTab ); + InvalidateTextWidth( &aAdrFrom, &aAdrTo, FALSE ); +} + +//------------------------------------------------------------------------ + +BOOL ScDocument::IsPageStyleInUse( const String& rStrPageStyle, SCTAB* pInTab ) +{ + BOOL bInUse = FALSE; + const SCTAB nCount = GetTableCount(); + SCTAB i; + + for ( i = 0; !bInUse && i < nCount && pTab[i]; i++ ) + bInUse = ( pTab[i]->GetPageStyle() == rStrPageStyle ); + + if ( pInTab ) + *pInTab = i-1; + + return bInUse; +} + +//------------------------------------------------------------------------ + +BOOL ScDocument::RemovePageStyleInUse( const String& rStyle ) +{ + BOOL bWasInUse = FALSE; + const SCTAB nCount = GetTableCount(); + + for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) + if ( pTab[i]->GetPageStyle() == rStyle ) + { + bWasInUse = TRUE; + pTab[i]->SetPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ); + } + + return bWasInUse; +} + +BOOL ScDocument::RenamePageStyleInUse( const String& rOld, const String& rNew ) +{ + BOOL bWasInUse = FALSE; + const SCTAB nCount = GetTableCount(); + + for ( SCTAB i=0; i<nCount && pTab[i]; i++ ) + if ( pTab[i]->GetPageStyle() == rOld ) + { + bWasInUse = TRUE; + pTab[i]->SetPageStyle( rNew ); + } + + return bWasInUse; +} + +//------------------------------------------------------------------------ + +BYTE ScDocument::GetEditTextDirection(SCTAB nTab) const +{ + EEHorizontalTextDirection eRet = EE_HTEXTDIR_DEFAULT; + + String aStyleName = GetPageStyle( nTab ); + SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aStyleName, SFX_STYLE_FAMILY_PAGE ); + if ( pStyle ) + { + SfxItemSet& rStyleSet = pStyle->GetItemSet(); + SvxFrameDirection eDirection = (SvxFrameDirection) + ((const SvxFrameDirectionItem&)rStyleSet.Get( ATTR_WRITINGDIR )).GetValue(); + + if ( eDirection == FRMDIR_HORI_LEFT_TOP ) + eRet = EE_HTEXTDIR_L2R; + else if ( eDirection == FRMDIR_HORI_RIGHT_TOP ) + eRet = EE_HTEXTDIR_R2L; + // else (invalid for EditEngine): keep "default" + } + + return sal::static_int_cast<BYTE>(eRet); +} + +//------------------------------------------------------------------------ + +void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo, + BOOL bNumFormatChanged ) +{ + BOOL bBroadcast = (bNumFormatChanged && GetDocOptions().IsCalcAsShown() && !IsImportingXML() && !IsClipboard()); + if ( pAdrFrom && !pAdrTo ) + { + const SCTAB nTab = pAdrFrom->Tab(); + + if ( pTab[nTab] ) + pTab[nTab]->InvalidateTextWidth( pAdrFrom, NULL, bNumFormatChanged, bBroadcast ); + } + else + { + const SCTAB nTabStart = pAdrFrom ? pAdrFrom->Tab() : 0; + const SCTAB nTabEnd = pAdrTo ? pAdrTo->Tab() : MAXTAB; + + for ( SCTAB nTab=nTabStart; nTab<=nTabEnd; nTab++ ) + if ( pTab[nTab] ) + pTab[nTab]->InvalidateTextWidth( pAdrFrom, pAdrTo, bNumFormatChanged, bBroadcast ); + } +} + +//------------------------------------------------------------------------ + +#define CALCMAX 1000 // Berechnungen +#define ABORT_EVENTS (INPUT_ANY & ~INPUT_TIMER & ~INPUT_OTHER) + +BOOL ScDocument::IdleCalcTextWidth() // TRUE = demnaechst wieder versuchen +{ + // #i75610# if a printer hasn't been set or created yet, don't create one for this + if ( bIdleDisabled || IsInLinkUpdate() || GetPrinter(FALSE) == NULL ) + return FALSE; + bIdleDisabled = TRUE; + +// ULONG nMs = 0; +// USHORT nIter = 0; + + const ULONG nStart = Time::GetSystemTicks(); + double nPPTX = 0.0; + double nPPTY = 0.0; + OutputDevice* pDev = NULL; + MapMode aOldMap; + ScStyleSheet* pStyle = NULL; + ScColumnIterator* pColIter = NULL; + ScTable* pTable = NULL; + ScColumn* pColumn = NULL; + ScBaseCell* pCell = NULL; + SCTAB nTab = aCurTextWidthCalcPos.Tab(); + SCROW nRow = aCurTextWidthCalcPos.Row(); + SCsCOL nCol = aCurTextWidthCalcPos.Col(); + USHORT nRestart = 0; + USHORT nZoom = 0; + BOOL bNeedMore= FALSE; + + if ( !ValidRow(nRow) ) + nRow = 0, nCol--; + if ( nCol < 0 ) + nCol = MAXCOL, nTab++; + if ( !ValidTab(nTab) || !pTab[nTab] ) + nTab = 0; + +// DBG_ERROR( String("Start = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); + + // SearchMask/Family muss gemerkt werden, + // damit z.B. der Organizer nicht durcheinanderkommt, wenn zwischendurch eine + // Query-Box aufgemacht wird !!! + + ScStyleSheetPool* pStylePool = xPoolHelper->GetStylePool(); + USHORT nOldMask = pStylePool->GetSearchMask(); + SfxStyleFamily eOldFam = pStylePool->GetSearchFamily(); + + pTable = pTab[nTab]; + pStylePool->SetSearchMask( SFX_STYLE_FAMILY_PAGE, SFXSTYLEBIT_ALL ); + pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle, + SFX_STYLE_FAMILY_PAGE ); + + DBG_ASSERT( pStyle, "Missing StyleSheet :-/" ); + + BOOL bProgress = FALSE; + if ( pStyle && 0 == GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALETOPAGES) ) + { + USHORT nCount = 0; + + nZoom = GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALE); + Fraction aZoomFract( nZoom, 100 ); + pColumn = &pTable->aCol[nCol]; + pColIter = new ScColumnIterator( pColumn, nRow, MAXROW ); + + while ( (nZoom > 0) && (nCount < CALCMAX) && (nRestart < 2) ) + { + if ( pColIter->Next( nRow, pCell ) ) + { + if ( TEXTWIDTH_DIRTY == pCell->GetTextWidth() ) + { + if ( !pDev ) + { + pDev = GetPrinter(); + aOldMap = pDev->GetMapMode(); + pDev->SetMapMode( MAP_PIXEL ); // wichtig fuer GetNeededSize + + Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP ); + nPPTX = aPix1000.X() / 1000.0; + nPPTY = aPix1000.Y() / 1000.0; + } + if ( !bProgress && pCell->GetCellType() == CELLTYPE_FORMULA + && ((ScFormulaCell*)pCell)->GetDirty() ) + { + ScProgress::CreateInterpretProgress( this, FALSE ); + bProgress = TRUE; + } + +// DBG_ERROR( String("t,c,r = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); +// DBG_ERROR( String("nOldWidth = ") + String(pCell->GetTextWidth()) ); + + USHORT nNewWidth = (USHORT)GetNeededSize( nCol, nRow, nTab, + pDev, nPPTX, nPPTY, + aZoomFract,aZoomFract, TRUE, + TRUE ); // bTotalSize + +// DBG_ERROR( String("nNewWidth = ") + String(nNewWidth) ); + + pCell->SetTextWidth( nNewWidth ); + + bNeedMore = TRUE; + } + } + else + { + BOOL bNewTab = FALSE; + + nRow = 0; + nCol--; + + if ( nCol < 0 ) + { + nCol = MAXCOL; + nTab++; + bNewTab = TRUE; + } + + if ( !ValidTab(nTab) || !pTab[nTab] ) + { + nTab = 0; + nRestart++; + bNewTab = TRUE; + } + + if ( nRestart < 2 ) + { + if ( bNewTab ) + { + pTable = pTab[nTab]; + pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle, + SFX_STYLE_FAMILY_PAGE ); + + if ( pStyle ) + { + SfxItemSet& rSet = pStyle->GetItemSet(); + if ( GET_SCALEVALUE( rSet, ATTR_PAGE_SCALETOPAGES ) == 0 ) + nZoom = GET_SCALEVALUE(rSet, ATTR_PAGE_SCALE ); + else + nZoom = 0; + } + else + { + DBG_ERROR( "Missing StyleSheet :-/" ); + } + } + + if ( nZoom > 0 ) + { + delete pColIter; + + pColumn = &pTable->aCol[nCol]; + pColIter = new ScColumnIterator( pColumn, nRow, MAXROW ); + } + else + nTab++; // Tabelle nicht mit absolutem Zoom -> naechste + } + } + +// nIter = nCount; + + nCount++; + + // Idle Berechnung abbrechen, wenn Berechnungen laenger als + // 50ms dauern, oder nach 32 Berechnungen mal nachschauen, ob + // bestimmte Events anstehen, die Beachtung wuenschen: + +// nMs = SysTicksToMs( GetSysTicks() - nStart ); + + if ( ( 50L < Time::GetSystemTicks() - nStart ) + || ( !(nCount&31) && Application::AnyInput( ABORT_EVENTS ) ) ) + nCount = CALCMAX; + } + } + else + nTab++; // Tabelle nicht mit absolutem Zoom -> naechste + + if ( bProgress ) + ScProgress::DeleteInterpretProgress(); + + delete pColIter; + +// DBG_ERROR( String(nCount) + String(" End = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) ); + + if (pDev) + pDev->SetMapMode(aOldMap); + + aCurTextWidthCalcPos.SetTab( nTab ); + aCurTextWidthCalcPos.SetRow( nRow ); + aCurTextWidthCalcPos.SetCol( (SCCOL)nCol ); + +// DBG_ERROR( String(nMs) + String(" ms (") + String(nIter) + String(')') ); + + pStylePool->SetSearchMask( eOldFam, nOldMask ); + bIdleDisabled = FALSE; + + return bNeedMore; +} + +//------------------------------------------------------------------------ + +class ScSpellStatus +{ +public: + BOOL bModified; + + ScSpellStatus() : bModified(FALSE) {}; + + DECL_LINK (EventHdl, EditStatus*); +}; + +IMPL_LINK( ScSpellStatus, EventHdl, EditStatus *, pStatus ) +{ + ULONG nStatus = pStatus->GetStatusWord(); + if ( nStatus & EE_STAT_WRONGWORDCHANGED ) + bModified = TRUE; + + return 0; +} + +// SPELL_MAXCELLS muss mindestens 256 sein, solange am Iterator keine +// Start-Spalte gesetzt werden kann + +//! SPELL_MAXTEST fuer Timer und Idle unterschiedlich ??? + +// SPELL_MAXTEST now divided between visible and rest of document + +#define SPELL_MAXTEST_VIS 1 +#define SPELL_MAXTEST_ALL 3 +#define SPELL_MAXCELLS 256 + +BOOL ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpellPos, + USHORT nMaxTest ) +{ + ScEditEngineDefaulter* pEngine = NULL; //! am Dokument speichern + SfxItemSet* pDefaults = NULL; + ScSpellStatus aStatus; + + USHORT nCellCount = 0; // Zellen insgesamt + USHORT nTestCount = 0; // Aufrufe Spelling + BOOL bChanged = FALSE; // Aenderungen? + + SCCOL nCol = rSpellRange.aStart.Col(); // iterator always starts on the left edge + SCROW nRow = rSpellPos.Row(); + SCTAB nTab = rSpellPos.Tab(); + if ( !pTab[nTab] ) // sheet deleted? + { + nTab = rSpellRange.aStart.Tab(); + nRow = rSpellRange.aStart.Row(); + if ( !pTab[nTab] ) + { + // may happen for visible range + return FALSE; + } + } + ScHorizontalCellIterator aIter( this, nTab, + rSpellRange.aStart.Col(), nRow, + rSpellRange.aEnd.Col(), rSpellRange.aEnd.Row() ); + ScBaseCell* pCell = aIter.GetNext( nCol, nRow ); + // skip everything left of rSpellPos: + while ( pCell && nRow == rSpellPos.Row() && nCol < rSpellPos.Col() ) + pCell = aIter.GetNext( nCol, nRow ); + + for (; pCell; pCell = aIter.GetNext(nCol, nRow)) + { + if (pDPCollection && pDPCollection->HasDPTable(nCol, nRow, nTab)) + // Don't spell check within datapilot table. + continue; + + CellType eType = pCell->GetCellType(); + if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT ) + { + if (!pEngine) + { + // #71154# ScTabEditEngine is needed + // because MapMode must be set for some old documents + pEngine = new ScTabEditEngine( this ); + pEngine->SetControlWord( pEngine->GetControlWord() | + ( EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS ) ); + pEngine->SetStatusEventHdl( LINK( &aStatus, ScSpellStatus, EventHdl ) ); + // Delimiters hier wie in inputhdl.cxx !!! + pEngine->SetWordDelimiters( + ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) ); + pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() ); + + com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() ); + + pEngine->SetSpeller( xXSpellChecker1 ); + } + + const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab ); + pPattern->FillEditItemSet( pDefaults ); + pEngine->SetDefaults( pDefaults, FALSE ); //! noetig ? + + USHORT nCellLang = ((const SvxLanguageItem&) + pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue(); + if ( nCellLang == LANGUAGE_SYSTEM ) + nCellLang = Application::GetSettings().GetLanguage(); // never use SYSTEM for spelling + pEngine->SetDefaultLanguage( nCellLang ); + + if ( eType == CELLTYPE_STRING ) + { + String aText; + ((ScStringCell*)pCell)->GetString(aText); + pEngine->SetText( aText ); + } + else + pEngine->SetText( *((ScEditCell*)pCell)->GetData() ); + + aStatus.bModified = FALSE; + pEngine->CompleteOnlineSpelling(); + if ( aStatus.bModified ) // Fehler dazu oder weggekommen? + { + BOOL bNeedEdit = TRUE; // Test auf einfachen Text + if ( !pEngine->HasOnlineSpellErrors() ) + { + ScEditAttrTester aTester( pEngine ); + bNeedEdit = aTester.NeedsObject(); + } + + if ( bNeedEdit ) + { + EditTextObject* pNewData = pEngine->CreateTextObject(); + if ( eType == CELLTYPE_EDIT ) + ((ScEditCell*)pCell)->SetData( pNewData, + pEngine->GetEditTextObjectPool() ); + else + PutCell( nCol, nRow, nTab, new ScEditCell( pNewData, + this, pEngine->GetEditTextObjectPool() ) ); + delete pNewData; + } + else // einfacher String + PutCell( nCol, nRow, nTab, new ScStringCell( pEngine->GetText() ) ); + + // Paint + if (pShell) + { + // #47751# Seitenvorschau ist davon nicht betroffen + // (sollte jedenfalls nicht) + ScPaintHint aHint( ScRange( nCol, nRow, nTab ), PAINT_GRID ); + aHint.SetPrintFlag( FALSE ); + pShell->Broadcast( aHint ); + } + + bChanged = TRUE; + } + + if ( ++nTestCount >= nMaxTest ) // checked enough text? + break; + } + + if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells? + break; + } + + if ( pCell ) + { + ++nCol; // continue after last cell + if ( nCol > rSpellRange.aEnd.Col() ) + { + nCol = rSpellRange.aStart.Col(); + ++nRow; + if ( nRow > rSpellRange.aEnd.Row() ) + pCell = NULL; + } + } + + if (!pCell) // end of range reached -> next sheet + { + ++nTab; + if ( nTab > rSpellRange.aEnd.Tab() || !pTab[nTab] ) + nTab = rSpellRange.aStart.Tab(); + nCol = rSpellRange.aStart.Col(); + nRow = rSpellRange.aStart.Row(); + + nVisSpellState = VSPL_DONE; //! only if this is for the visible range + } + rSpellPos.Set( nCol, nRow, nTab ); + + delete pDefaults; + delete pEngine; // bevor aStatus out of scope geht + + return bChanged; +} + + +BOOL ScDocument::ContinueOnlineSpelling() +{ + if ( bIdleDisabled || !pDocOptions->IsAutoSpell() || (pShell && pShell->IsReadOnly()) ) + return FALSE; + + // #i48433# set bInsertingFromOtherDoc flag so there are no broadcasts when PutCell is called + // (same behavior as in RemoveAutoSpellObj: just transfer the broadcaster) + BOOL bOldInserting = IsInsertingFromOtherDoc(); + SetInsertingFromOtherDoc( TRUE ); + + //! use one EditEngine for both calls + + // #41504# first check visible range + BOOL bResult = OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_VIS ); + + // during first pass through visible range, always continue + if ( nVisSpellState == VSPL_START ) + bResult = TRUE; + + if (bResult) + { + // if errors found, continue there + OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_ALL ); + } + else + { + // if nothing found there, continue with rest of document + ScRange aTotalRange( 0,0,0, MAXCOL,MAXROW,MAXTAB ); + bResult = OnlineSpellInRange( aTotalRange, aOnlineSpellPos, SPELL_MAXTEST_ALL ); + } + + SetInsertingFromOtherDoc( bOldInserting ); + + return bResult; +} + + +void ScDocument::SetOnlineSpellPos( const ScAddress& rPos ) +{ + aOnlineSpellPos = rPos; + + // skip visible area for aOnlineSpellPos + if ( aVisSpellRange.In( aOnlineSpellPos ) ) + aOnlineSpellPos = aVisSpellRange.aEnd; +} + +BOOL ScDocument::SetVisibleSpellRange( const ScRange& rNewRange ) +{ + BOOL bChange = ( aVisSpellRange != rNewRange ); + if (bChange) + { + // continue spelling through visible range when scrolling down + BOOL bContDown = ( nVisSpellState == VSPL_START && rNewRange.In( aVisSpellPos ) && + rNewRange.aStart.Row() > aVisSpellRange.aStart.Row() && + rNewRange.aStart.Col() == aVisSpellRange.aStart.Col() && + rNewRange.aEnd.Col() == aVisSpellRange.aEnd.Col() ); + + aVisSpellRange = rNewRange; + + if ( !bContDown ) + { + aVisSpellPos = aVisSpellRange.aStart; + nVisSpellState = VSPL_START; + } + + // skip visible area for aOnlineSpellPos + if ( aVisSpellRange.In( aOnlineSpellPos ) ) + aOnlineSpellPos = aVisSpellRange.aEnd; + } + return bChange; +} + +void ScDocument::RemoveAutoSpellObj() +{ + // alle Spelling-Informationen entfernen + + for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++) + pTab[nTab]->RemoveAutoSpellObj(); +} + +//------------------------------------------------------------------------ + +BOOL ScDocument::IdleCheckLinks() // TRUE = demnaechst wieder versuchen +{ + BOOL bAnyLeft = FALSE; + + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + { + ScDdeLink* pDdeLink = (ScDdeLink*)pBase; + if (pDdeLink->NeedsUpdate()) + { + pDdeLink->TryUpdate(); + if (pDdeLink->NeedsUpdate()) // war nix? + bAnyLeft = TRUE; + } + } + } + } + + return bAnyLeft; +} + +void ScDocument::SaveDdeLinks(SvStream& rStream) const +{ + // bei 4.0-Export alle mit Modus != DEFAULT weglassen + BOOL bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 ); + + const ::sfx2::SvBaseLinks& rLinks = GetLinkManager()->GetLinks(); + USHORT nCount = rLinks.Count(); + + // erstmal zaehlen... + + USHORT nDdeCount = 0; + USHORT i; + for (i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + if ( !bExport40 || ((ScDdeLink*)pBase)->GetMode() == SC_DDE_DEFAULT ) + ++nDdeCount; + } + + // Header + + ScMultipleWriteHeader aHdr( rStream ); + rStream << nDdeCount; + + // Links speichern + + for (i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + { + ScDdeLink* pLink = (ScDdeLink*)pBase; + if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT ) + pLink->Store( rStream, aHdr ); + } + } +} + +void ScDocument::LoadDdeLinks(SvStream& rStream) +{ + ScMultipleReadHeader aHdr( rStream ); + + GetLinkManager(); + USHORT nCount; + rStream >> nCount; + for (USHORT i=0; i<nCount; i++) + { + ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr ); + pLinkManager->InsertDDELink( pLink, + pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem() ); + } +} + +BOOL ScDocument::HasDdeLinks() const +{ + if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + if ((*rLinks[i])->ISA(ScDdeLink)) + return TRUE; + } + + return FALSE; +} + +void ScDocument::SetInLinkUpdate(BOOL bSet) +{ + // called from TableLink and AreaLink + + DBG_ASSERT( bInLinkUpdate != bSet, "SetInLinkUpdate twice" ); + bInLinkUpdate = bSet; +} + +BOOL ScDocument::IsInLinkUpdate() const +{ + return bInLinkUpdate || IsInDdeLinkUpdate(); +} + +void ScDocument::UpdateExternalRefLinks() +{ + if (!GetLinkManager()) + return; + + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + + bool bAny = false; + for (USHORT i = 0; i < nCount; ++i) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase); + if (pRefLink) + { + pRefLink->Update(); + bAny = true; + } + } + if (bAny) + { + TrackFormulas(); + pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) ); + ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) ); + + // #i101960# set document modified, as in TrackTimeHdl for DDE links + if (!pShell->IsModified()) + { + pShell->SetModified( TRUE ); + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + } + } +} + +void ScDocument::UpdateDdeLinks() +{ + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + USHORT i; + + // #49226# falls das Updaten laenger dauert, erstmal alle Werte + // zuruecksetzen, damit nichts altes (falsches) stehen bleibt + BOOL bAny = FALSE; + for (i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + { + ((ScDdeLink*)pBase)->ResetValue(); + bAny = TRUE; + } + } + if (bAny) + { + // Formeln berechnen und painten wie im TrackTimeHdl + TrackFormulas(); + pShell->Broadcast( SfxSimpleHint( FID_DATACHANGED ) ); + ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) ); + + // wenn FID_DATACHANGED irgendwann mal asynchron werden sollte + // (z.B. mit Invalidate am Window), muss hier ein Update erzwungen werden. + } + + // nun wirklich updaten... + for (i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + ((ScDdeLink*)pBase)->TryUpdate(); // bei DDE-Links TryUpdate statt Update + } + } +} + +BOOL ScDocument::UpdateDdeLink( const String& rAppl, const String& rTopic, const String& rItem ) +{ + // fuer refresh() per StarOne Api + // ResetValue() fuer einzelnen Link nicht noetig + //! wenn's mal alles asynchron wird, aber auch hier + + BOOL bFound = FALSE; + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + { + ScDdeLink* pDdeLink = (ScDdeLink*)pBase; + if ( pDdeLink->GetAppl() == rAppl && + pDdeLink->GetTopic() == rTopic && + pDdeLink->GetItem() == rItem ) + { + pDdeLink->TryUpdate(); + bFound = TRUE; // koennen theoretisch mehrere sein (Mode), darum weitersuchen + } + } + } + } + return bFound; +} + +void ScDocument::DisconnectDdeLinks() +{ + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + pBase->Disconnect(); // bleibt im LinkManager eingetragen + } + } +} + +void ScDocument::CopyDdeLinks( ScDocument* pDestDoc ) const +{ + if (bIsClip) // aus Stream erzeugen + { + if (pClipData) + { + pClipData->Seek(0); + pDestDoc->LoadDdeLinks(*pClipData); + } + } + else if (GetLinkManager()) // Links direkt kopieren + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScDdeLink)) + { + ScDdeLink* pNew = new ScDdeLink( pDestDoc, *(ScDdeLink*)pBase ); + + pDestDoc->pLinkManager->InsertDDELink( pNew, + pNew->GetAppl(), pNew->GetTopic(), pNew->GetItem() ); + } + } + } +} + +USHORT ScDocument::GetDdeLinkCount() const +{ + USHORT nDdeCount = 0; + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + if ((*rLinks[i])->ISA(ScDdeLink)) + ++nDdeCount; + } + return nDdeCount; +} + +// ---------------------------------------------------------------------------- + +namespace { + +/** Tries to find the specified DDE link. + @param pnDdePos (out-param) if not 0, the index of the DDE link is returned here + (does not include other links from link manager). + @return The DDE link, if it exists, otherwise 0. */ +ScDdeLink* lclGetDdeLink( + const sfx2::LinkManager* pLinkManager, + const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, + USHORT* pnDdePos = NULL ) +{ + if( pLinkManager ) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + if( pnDdePos ) *pnDdePos = 0; + for( USHORT nIndex = 0; nIndex < nCount; ++nIndex ) + { + ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ]; + if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) ) + { + if( (pDdeLink->GetAppl() == rAppl) && + (pDdeLink->GetTopic() == rTopic) && + (pDdeLink->GetItem() == rItem) && + ((nMode == SC_DDE_IGNOREMODE) || (nMode == pDdeLink->GetMode())) ) + return pDdeLink; + if( pnDdePos ) ++*pnDdePos; + } + } + } + return NULL; +} + +/** Returns a pointer to the specified DDE link. + @param nDdePos Index of the DDE link (does not include other links from link manager). + @return The DDE link, if it exists, otherwise 0. */ +ScDdeLink* lclGetDdeLink( const sfx2::LinkManager* pLinkManager, USHORT nDdePos ) +{ + if( pLinkManager ) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + USHORT nDdeIndex = 0; // counts only the DDE links + for( USHORT nIndex = 0; nIndex < nCount; ++nIndex ) + { + ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ]; + if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) ) + { + if( nDdeIndex == nDdePos ) + return pDdeLink; + ++nDdeIndex; + } + } + } + return NULL; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +bool ScDocument::FindDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, USHORT& rnDdePos ) +{ + return lclGetDdeLink( GetLinkManager(), rAppl, rTopic, rItem, nMode, &rnDdePos ) != NULL; +} + +bool ScDocument::GetDdeLinkData( USHORT nDdePos, String& rAppl, String& rTopic, String& rItem ) const +{ + if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) + { + rAppl = pDdeLink->GetAppl(); + rTopic = pDdeLink->GetTopic(); + rItem = pDdeLink->GetItem(); + return true; + } + return false; +} + +bool ScDocument::GetDdeLinkMode( USHORT nDdePos, BYTE& rnMode ) const +{ + if( const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) + { + rnMode = pDdeLink->GetMode(); + return true; + } + return false; +} + +const ScMatrix* ScDocument::GetDdeLinkResultMatrix( USHORT nDdePos ) const +{ + const ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ); + return pDdeLink ? pDdeLink->GetResult() : NULL; +} + +bool ScDocument::CreateDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, ScMatrix* pResults ) +{ + /* Create a DDE link without updating it (i.e. for Excel import), to prevent + unwanted connections. First try to find existing link. Set result array + on existing and new links. */ + //! store DDE links additionally at document (for efficiency)? + DBG_ASSERT( nMode != SC_DDE_IGNOREMODE, "ScDocument::CreateDdeLink - SC_DDE_IGNOREMODE not allowed here" ); + if( GetLinkManager() && (nMode != SC_DDE_IGNOREMODE) ) + { + ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, rAppl, rTopic, rItem, nMode ); + if( !pDdeLink ) + { + // create a new DDE link, but without TryUpdate + pDdeLink = new ScDdeLink( this, rAppl, rTopic, rItem, nMode ); + pLinkManager->InsertDDELink( pDdeLink, rAppl, rTopic, rItem ); + } + + // insert link results + if( pResults ) + pDdeLink->SetResult( pResults ); + + return true; + } + return false; +} + +bool ScDocument::SetDdeLinkResultMatrix( USHORT nDdePos, ScMatrix* pResults ) +{ + if( ScDdeLink* pDdeLink = lclGetDdeLink( GetLinkManager(), nDdePos ) ) + { + pDdeLink->SetResult( pResults ); + return true; + } + return false; +} + +//------------------------------------------------------------------------ + +BOOL ScDocument::HasAreaLinks() const +{ + if (GetLinkManager()) // Clipboard z.B. hat keinen LinkManager + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + if ((*rLinks[i])->ISA(ScAreaLink)) + return TRUE; + } + + return FALSE; +} + +void ScDocument::UpdateAreaLinks() +{ + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScAreaLink)) + pBase->Update(); + } + } +} + +void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab ) +{ + if (GetLinkManager()) + { + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nPos = 0; + while ( nPos < rLinks.Count() ) + { + const ::sfx2::SvBaseLink* pBase = *rLinks[nPos]; + if ( pBase->ISA(ScAreaLink) && + static_cast<const ScAreaLink*>(pBase)->GetDestArea().aStart.Tab() == nTab ) + pLinkManager->Remove( nPos ); + else + ++nPos; + } + } +} + +void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode, + const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) +{ + if (GetLinkManager()) + { + bool bAnyUpdate = false; + + const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks(); + USHORT nCount = rLinks.Count(); + for (USHORT i=0; i<nCount; i++) + { + ::sfx2::SvBaseLink* pBase = *rLinks[i]; + if (pBase->ISA(ScAreaLink)) + { + ScAreaLink* pLink = (ScAreaLink*) pBase; + ScRange aOutRange = pLink->GetDestArea(); + + SCCOL nCol1 = aOutRange.aStart.Col(); + SCROW nRow1 = aOutRange.aStart.Row(); + SCTAB nTab1 = aOutRange.aStart.Tab(); + SCCOL nCol2 = aOutRange.aEnd.Col(); + SCROW nRow2 = aOutRange.aEnd.Row(); + SCTAB nTab2 = aOutRange.aEnd.Tab(); + + ScRefUpdateRes eRes = + ScRefUpdate::Update( this, eUpdateRefMode, + rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), + rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz, + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + if ( eRes != UR_NOTHING ) + { + pLink->SetDestArea( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) ); + bAnyUpdate = true; + } + } + } + + if ( bAnyUpdate ) + { + // #i52120# Look for duplicates (after updating all positions). + // If several links start at the same cell, the one with the lower index is removed + // (file format specifies only one link definition for a cell). + + USHORT nFirstIndex = 0; + while ( nFirstIndex < nCount ) + { + bool bFound = false; + ::sfx2::SvBaseLink* pFirst = *rLinks[nFirstIndex]; + if ( pFirst->ISA(ScAreaLink) ) + { + ScAddress aFirstPos = static_cast<ScAreaLink*>(pFirst)->GetDestArea().aStart; + for ( USHORT nSecondIndex = nFirstIndex + 1; nSecondIndex < nCount && !bFound; ++nSecondIndex ) + { + ::sfx2::SvBaseLink* pSecond = *rLinks[nSecondIndex]; + if ( pSecond->ISA(ScAreaLink) && + static_cast<ScAreaLink*>(pSecond)->GetDestArea().aStart == aFirstPos ) + { + // remove the first link, exit the inner loop, don't increment nFirstIndex + pLinkManager->Remove( pFirst ); + nCount = rLinks.Count(); + bFound = true; + } + } + } + if (!bFound) + ++nFirstIndex; + } + } + } +} + +//------------------------------------------------------------------------ + +// TimerDelays etc. +void ScDocument::KeyInput( const KeyEvent& ) +{ + if ( pChartListenerCollection->GetCount() ) + pChartListenerCollection->StartTimer(); + if( apTemporaryChartLock.get() ) + apTemporaryChartLock->StartOrContinueLocking(); +} + +// ---------------------------------------------------------------------------- + +BOOL ScDocument::CheckMacroWarn() +{ + // The check for macro configuration, macro warning and disabling is now handled + // in SfxObjectShell::AdjustMacroMode, called by SfxObjectShell::CallBasic. + + return TRUE; +} + +//------------------------------------------------------------------------ + +SfxBindings* ScDocument::GetViewBindings() +{ + // used to invalidate slots after changes to this document + + if ( !pShell ) + return NULL; // no ObjShell -> no view + + // first check current view + SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + if ( pViewFrame && pViewFrame->GetObjectShell() != pShell ) // wrong document? + pViewFrame = NULL; + + // otherwise use first view for this doc + if ( !pViewFrame ) + pViewFrame = SfxViewFrame::GetFirst( pShell ); + + if (pViewFrame) + return &pViewFrame->GetBindings(); + else + return NULL; +} + +//------------------------------------------------------------------------ + +void lcl_TransliterateEditEngine( ScEditEngineDefaulter& rEngine, + utl::TransliterationWrapper& rTranslitarationWrapper, + BOOL bConsiderLanguage, ScDocument* pDoc ) +{ + //! should use TransliterateText method of EditEngine instead, when available! + + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + + USHORT nParCount = rEngine.GetParagraphCount(); + for (USHORT nPar=0; nPar<nParCount; nPar++) + { + SvUShorts aPortions; + rEngine.GetPortions( (USHORT)nPar, aPortions ); + + for ( USHORT nPos = aPortions.Count(); nPos; ) + { + --nPos; + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos ? aPortions.GetObject( nPos - 1 ) : 0; + + ESelection aSel( nPar, nStart, nPar, nEnd ); + String aOldStr = rEngine.GetText( aSel ); + SfxItemSet aAttr = rEngine.GetAttribs( aSel ); + + if ( aAttr.GetItemState( EE_FEATURE_FIELD ) != SFX_ITEM_ON ) // fields are not touched + { + if ( bConsiderLanguage ) + { + BYTE nScript = pDoc->GetStringScriptType( aOldStr ); + USHORT nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? EE_CHAR_LANGUAGE_CJK : + ( ( nScript == SCRIPTTYPE_COMPLEX ) ? EE_CHAR_LANGUAGE_CTL : + EE_CHAR_LANGUAGE ); + nLanguage = ((const SvxLanguageItem&)aAttr.Get(nWhich)).GetValue(); + } + + com::sun::star::uno::Sequence<sal_Int32> aOffsets; + String aNewStr = rTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, aOldStr.Len(), &aOffsets ); + + if ( aNewStr != aOldStr ) + { + // replace string, keep attributes + + rEngine.QuickInsertText( aNewStr, aSel ); + aSel.nEndPos = aSel.nStartPos + aNewStr.Len(); + rEngine.QuickSetAttribs( aAttr, aSel ); + } + } + } + } +} + +void ScDocument::TransliterateText( const ScMarkData& rMultiMark, sal_Int32 nType ) +{ + DBG_ASSERT( rMultiMark.IsMultiMarked(), "TransliterateText: no selection" ); + + utl::TransliterationWrapper aTranslitarationWrapper( xServiceManager, nType ); + BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + + ScEditEngineDefaulter* pEngine = NULL; // not using pEditEngine member because of defaults + + SCTAB nCount = GetTableCount(); + for (SCTAB nTab = 0; nTab < nCount; nTab++) + if ( pTab[nTab] && rMultiMark.GetTableSelect(nTab) ) + { + SCCOL nCol = 0; + SCROW nRow = 0; + + BOOL bFound = rMultiMark.IsCellMarked( nCol, nRow ); + if (!bFound) + bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark ); + + while (bFound) + { + const ScBaseCell* pCell = GetCell( ScAddress( nCol, nRow, nTab ) ); + CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE; + + if ( eType == CELLTYPE_STRING ) + { + String aOldStr; + ((const ScStringCell*)pCell)->GetString(aOldStr); + xub_StrLen nOldLen = aOldStr.Len(); + + if ( bConsiderLanguage ) + { + BYTE nScript = GetStringScriptType( aOldStr ); //! cell script type? + USHORT nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? ATTR_CJK_FONT_LANGUAGE : + ( ( nScript == SCRIPTTYPE_COMPLEX ) ? ATTR_CTL_FONT_LANGUAGE : + ATTR_FONT_LANGUAGE ); + nLanguage = ((const SvxLanguageItem*)GetAttr( nCol, nRow, nTab, nWhich ))->GetValue(); + } + + com::sun::star::uno::Sequence<sal_Int32> aOffsets; + String aNewStr = aTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets ); + + if ( aNewStr != aOldStr ) + PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) ); + } + else if ( eType == CELLTYPE_EDIT ) + { + if (!pEngine) + pEngine = new ScFieldEditEngine( GetEnginePool(), GetEditPool() ); + + // defaults from cell attributes must be set so right language is used + const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab ); + SfxItemSet* pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() ); + pPattern->FillEditItemSet( pDefaults ); + pEngine->SetDefaults( pDefaults, TRUE ); + + const EditTextObject* pData = ((const ScEditCell*)pCell)->GetData(); + pEngine->SetText( *pData ); + + pEngine->ClearModifyFlag(); + + lcl_TransliterateEditEngine( *pEngine, aTranslitarationWrapper, bConsiderLanguage, this ); + + if ( pEngine->IsModified() ) + { + ScEditAttrTester aTester( pEngine ); + if ( aTester.NeedsObject() ) + { + // remove defaults (paragraph attributes) before creating text object + SfxItemSet* pEmpty = new SfxItemSet( pEngine->GetEmptyItemSet() ); + pEngine->SetDefaults( pEmpty, TRUE ); + + EditTextObject* pNewData = pEngine->CreateTextObject(); + PutCell( nCol, nRow, nTab, + new ScEditCell( pNewData, this, pEngine->GetEditTextObjectPool() ) ); + delete pNewData; + } + else + { + String aNewStr = pEngine->GetText(); + PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) ); + } + } + } + + bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark ); + } + } + + delete pEngine; +} + |