diff options
Diffstat (limited to 'sc/source/ui/docshell')
28 files changed, 24202 insertions, 0 deletions
diff --git a/sc/source/ui/docshell/arealink.cxx b/sc/source/ui/docshell/arealink.cxx new file mode 100644 index 000000000000..d819785c843b --- /dev/null +++ b/sc/source/ui/docshell/arealink.cxx @@ -0,0 +1,530 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------- + +#include <sfx2/app.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/linkmgr.hxx> +#include <svl/stritem.hxx> +#include <vcl/msgbox.hxx> + +#include "arealink.hxx" + +#include "tablink.hxx" +#include "document.hxx" +#include "docsh.hxx" +#include "rangenam.hxx" +#include "dbcolect.hxx" +#include "undoblk.hxx" +#include "globstr.hrc" +#include "markdata.hxx" +#include "hints.hxx" +#include "filter.hxx" +//CHINA001 #include "linkarea.hxx" // dialog + +#include "attrib.hxx" // raus, wenn ResetAttrib am Dokument +#include "patattr.hxx" // raus, wenn ResetAttrib am Dokument +#include "docpool.hxx" // raus, wenn ResetAttrib am Dokument + +#include "sc.hrc" //CHINA001 +#include "scabstdlg.hxx" //CHINA001 +#include "clipparam.hxx" + +struct AreaLink_Impl +{ + ScDocShell* m_pDocSh; + AbstractScLinkedAreaDlg* m_pDialog; + + AreaLink_Impl() : m_pDocSh( NULL ), m_pDialog( NULL ) {} +}; + +TYPEINIT1(ScAreaLink,::sfx2::SvBaseLink); + +//------------------------------------------------------------------------ + +ScAreaLink::ScAreaLink( SfxObjectShell* pShell, const String& rFile, + const String& rFilter, const String& rOpt, + const String& rArea, const ScRange& rDest, + ULONG nRefresh ) : + ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ONCALL,FORMAT_FILE), + ScRefreshTimer ( nRefresh ), + pImpl ( new AreaLink_Impl() ), + aFileName (rFile), + aFilterName (rFilter), + aOptions (rOpt), + aSourceArea (rArea), + aDestArea (rDest), + bAddUndo (TRUE), + bInCreate (FALSE), + bDoInsert (TRUE) +{ + DBG_ASSERT(pShell->ISA(ScDocShell), "ScAreaLink mit falscher ObjectShell"); + pImpl->m_pDocSh = static_cast< ScDocShell* >( pShell ); + SetRefreshHandler( LINK( this, ScAreaLink, RefreshHdl ) ); + SetRefreshControl( pImpl->m_pDocSh->GetDocument()->GetRefreshTimerControlAddress() ); +} + +__EXPORT ScAreaLink::~ScAreaLink() +{ + StopRefreshTimer(); + delete pImpl; +} + +void __EXPORT ScAreaLink::Edit(Window* pParent, const Link& /* rEndEditHdl */ ) +{ + // use own dialog instead of SvBaseLink::Edit... + // DefModalDialogParent setzen, weil evtl. aus der DocShell beim ConvertFrom + // ein Optionen-Dialog kommt... + + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + + AbstractScLinkedAreaDlg* pDlg = pFact->CreateScLinkedAreaDlg( pParent, RID_SCDLG_LINKAREA); + DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 + pDlg->InitFromOldLink( aFileName, aFilterName, aOptions, aSourceArea, GetRefreshDelay() ); + pImpl->m_pDialog = pDlg; + pDlg->StartExecuteModal( LINK( this, ScAreaLink, AreaEndEditHdl ) ); +} + +void __EXPORT ScAreaLink::DataChanged( const String&, + const ::com::sun::star::uno::Any& ) +{ + // bei bInCreate nichts tun, damit Update gerufen werden kann, um den Status im + // LinkManager zu setzen, ohne die Daten im Dokument zu aendern + + if (bInCreate) + return; + + sfx2::LinkManager* pLinkManager=pImpl->m_pDocSh->GetDocument()->GetLinkManager(); + if (pLinkManager!=NULL) + { + String aFile; + String aFilter; + String aArea; + pLinkManager->GetDisplayNames( this,0,&aFile,&aArea,&aFilter); + + // the file dialog returns the filter name with the application prefix + // -> remove prefix + ScDocumentLoader::RemoveAppPrefix( aFilter ); + + // #81155# dialog doesn't set area, so keep old one + if ( !aArea.Len() ) + { + aArea = aSourceArea; + + // adjust in dialog: + String aNewLinkName; + sfx2::MakeLnkName( aNewLinkName, NULL, aFile, aArea, &aFilter ); + SetName( aNewLinkName ); + } + + Refresh( aFile, aFilter, aArea, GetRefreshDelay() ); + } +} + +void __EXPORT ScAreaLink::Closed() +{ + // Verknuepfung loeschen: Undo + + ScDocument* pDoc = pImpl->m_pDocSh->GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + if (bAddUndo && bUndo) + { + pImpl->m_pDocSh->GetUndoManager()->AddUndoAction( new ScUndoRemoveAreaLink( pImpl->m_pDocSh, + aFileName, aFilterName, aOptions, + aSourceArea, aDestArea, GetRefreshDelay() ) ); + + bAddUndo = FALSE; // nur einmal + } + + SCTAB nDestTab = aDestArea.aStart.Tab(); + if (pDoc->IsStreamValid(nDestTab)) + pDoc->SetStreamValid(nDestTab, FALSE); + + SvBaseLink::Closed(); +} + +void ScAreaLink::SetDestArea(const ScRange& rNew) +{ + aDestArea = rNew; // fuer Undo +} + +void ScAreaLink::SetSource(const String& rDoc, const String& rFlt, const String& rOpt, + const String& rArea) +{ + aFileName = rDoc; + aFilterName = rFlt; + aOptions = rOpt; + aSourceArea = rArea; + + // also update link name for dialog + String aNewLinkName; + sfx2::MakeLnkName( aNewLinkName, NULL, aFileName, aSourceArea, &aFilterName ); + SetName( aNewLinkName ); +} + +BOOL ScAreaLink::IsEqual( const String& rFile, const String& rFilter, const String& rOpt, + const String& rSource, const ScRange& rDest ) const +{ + return aFileName == rFile && aFilterName == rFilter && aOptions == rOpt && + aSourceArea == rSource && aDestArea.aStart == rDest.aStart; +} + +// find a range with name >rAreaName< in >pSrcDoc<, return it in >rRange< +BOOL ScAreaLink::FindExtRange( ScRange& rRange, ScDocument* pSrcDoc, const String& rAreaName ) +{ + BOOL bFound = FALSE; + ScRangeName* pNames = pSrcDoc->GetRangeName(); + USHORT nPos; + if (pNames) // benannte Bereiche + { + if (pNames->SearchName( rAreaName, nPos )) + if ( (*pNames)[nPos]->IsValidReference( rRange ) ) + bFound = TRUE; + } + if (!bFound) // Datenbankbereiche + { + ScDBCollection* pDBColl = pSrcDoc->GetDBCollection(); + if (pDBColl) + if (pDBColl->SearchName( rAreaName, nPos )) + { + SCTAB nTab; + SCCOL nCol1, nCol2; + SCROW nRow1, nRow2; + (*pDBColl)[nPos]->GetArea(nTab,nCol1,nRow1,nCol2,nRow2); + rRange = ScRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab ); + bFound = TRUE; + } + } + if (!bFound) // direct reference (range or cell) + { + ScAddress::Details aDetails(pSrcDoc->GetAddressConvention(), 0, 0); + if ( rRange.ParseAny( rAreaName, pSrcDoc, aDetails ) & SCA_VALID ) + bFound = TRUE; + } + return bFound; +} + +// ausfuehren: + +BOOL ScAreaLink::Refresh( const String& rNewFile, const String& rNewFilter, + const String& rNewArea, ULONG nNewRefresh ) +{ + // Dokument laden - wie TabLink + + if (!rNewFile.Len() || !rNewFilter.Len()) + return FALSE; + + String aNewUrl( ScGlobal::GetAbsDocName( rNewFile, pImpl->m_pDocSh ) ); + BOOL bNewUrlName = (aNewUrl != aFileName); + + const SfxFilter* pFilter = pImpl->m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter); + if (!pFilter) + return FALSE; + + ScDocument* pDoc = pImpl->m_pDocSh->GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + pDoc->SetInLinkUpdate( TRUE ); + + // wenn neuer Filter ausgewaehlt wurde, Optionen vergessen + if ( rNewFilter != aFilterName ) + aOptions.Erase(); + + // ItemSet immer anlegen, damit die DocShell die Optionen setzen kann + SfxItemSet* pSet = new SfxAllItemSet( SFX_APP()->GetPool() ); + if ( aOptions.Len() ) + pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) ); + + SfxMedium* pMed = new SfxMedium(aNewUrl, STREAM_STD_READ, FALSE, pFilter); + + ScDocShell* pSrcShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL); +//REMOVE SvEmbeddedObjectRef aRef = pSrcShell; + SfxObjectShellRef aRef = pSrcShell; + pSrcShell->DoLoad(pMed); + + ScDocument* pSrcDoc = pSrcShell->GetDocument(); + + // Optionen koennten gesetzt worden sein + String aNewOpt = ScDocumentLoader::GetOptions(*pMed); + if (!aNewOpt.Len()) + aNewOpt = aOptions; + + // correct source range name list for web query import + String aTempArea; + + if( rNewFilter == ScDocShell::GetWebQueryFilterName() ) + aTempArea = ScFormatFilter::Get().GetHTMLRangeNameList( pSrcDoc, rNewArea ); + else + aTempArea = rNewArea; + + // find total size of source area + SCCOL nWidth = 0; + SCROW nHeight = 0; + xub_StrLen nTokenCnt = aTempArea.GetTokenCount( ';' ); + xub_StrLen nStringIx = 0; + xub_StrLen nToken; + + for( nToken = 0; nToken < nTokenCnt; nToken++ ) + { + String aToken( aTempArea.GetToken( 0, ';', nStringIx ) ); + ScRange aTokenRange; + if( FindExtRange( aTokenRange, pSrcDoc, aToken ) ) + { + // columns: find maximum + nWidth = Max( nWidth, (SCCOL)(aTokenRange.aEnd.Col() - aTokenRange.aStart.Col() + 1) ); + // rows: add row range + 1 empty row + nHeight += aTokenRange.aEnd.Row() - aTokenRange.aStart.Row() + 2; + } + } + // remove the last empty row + if( nHeight > 0 ) + nHeight--; + + // alte Daten loeschen / neue kopieren + + ScAddress aDestPos = aDestArea.aStart; + SCTAB nDestTab = aDestPos.Tab(); + ScRange aOldRange = aDestArea; + ScRange aNewRange = aDestArea; // alter Bereich, wenn Datei nicht gefunden o.ae. + if (nWidth > 0 && nHeight > 0) + { + aNewRange.aEnd.SetCol( aNewRange.aStart.Col() + nWidth - 1 ); + aNewRange.aEnd.SetRow( aNewRange.aStart.Row() + nHeight - 1 ); + } + + //! check CanFitBlock only if bDoInsert is set? + BOOL bCanDo = ValidColRow( aNewRange.aEnd.Col(), aNewRange.aEnd.Row() ) && + pDoc->CanFitBlock( aOldRange, aNewRange ); + if (bCanDo) + { + ScDocShellModificator aModificator( *pImpl->m_pDocSh ); + + SCCOL nOldEndX = aOldRange.aEnd.Col(); + SCROW nOldEndY = aOldRange.aEnd.Row(); + SCCOL nNewEndX = aNewRange.aEnd.Col(); + SCROW nNewEndY = aNewRange.aEnd.Row(); + ScRange aMaxRange( aDestPos, + ScAddress(Max(nOldEndX,nNewEndX), Max(nOldEndY,nNewEndY), nDestTab) ); + + // Undo initialisieren + + ScDocument* pUndoDoc = NULL; + ScDocument* pRedoDoc = NULL; + if ( bAddUndo && bUndo ) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if ( bDoInsert ) + { + if ( nNewEndX != nOldEndX || nNewEndY != nOldEndY ) // Bereich veraendert? + { + pUndoDoc->InitUndo( pDoc, 0, pDoc->GetTableCount()-1 ); + pDoc->CopyToDocument( 0,0,0,MAXCOL,MAXROW,MAXTAB, + IDF_FORMULA, FALSE, pUndoDoc ); // alle Formeln + } + else + pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab ); // nur Zieltabelle + pDoc->CopyToDocument( aOldRange, IDF_ALL & ~IDF_NOTE, FALSE, pUndoDoc ); + } + else // ohne Einfuegen + { + pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab ); // nur Zieltabelle + pDoc->CopyToDocument( aMaxRange, IDF_ALL & ~IDF_NOTE, FALSE, pUndoDoc ); + } + } + + // Zellen einfuegen / loeschen + // DeleteAreaTab loescht auch MERGE_FLAG Attribute + + if (bDoInsert) + pDoc->FitBlock( aOldRange, aNewRange ); // incl. loeschen + else + pDoc->DeleteAreaTab( aMaxRange, IDF_ALL & ~IDF_NOTE ); + + // Daten kopieren + + if (nWidth > 0 && nHeight > 0) + { + ScDocument aClipDoc( SCDOCMODE_CLIP ); + ScRange aNewTokenRange( aNewRange.aStart ); + nStringIx = 0; + for( nToken = 0; nToken < nTokenCnt; nToken++ ) + { + String aToken( aTempArea.GetToken( 0, ';', nStringIx ) ); + ScRange aTokenRange; + if( FindExtRange( aTokenRange, pSrcDoc, aToken ) ) + { + SCTAB nSrcTab = aTokenRange.aStart.Tab(); + ScMarkData aSourceMark; + aSourceMark.SelectOneTable( nSrcTab ); // selektieren fuer CopyToClip + aSourceMark.SetMarkArea( aTokenRange ); + + ScClipParam aClipParam(aTokenRange, false); + pSrcDoc->CopyToClip(aClipParam, &aClipDoc, &aSourceMark); + + if ( aClipDoc.HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab, + HASATTR_MERGED | HASATTR_OVERLAPPED ) ) + { + //! ResetAttrib am Dokument !!! + + ScPatternAttr aPattern( pSrcDoc->GetPool() ); + aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults + aPattern.GetItemSet().Put( ScMergeFlagAttr() ); + aClipDoc.ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern ); + } + + aNewTokenRange.aEnd.SetCol( aNewTokenRange.aStart.Col() + (aTokenRange.aEnd.Col() - aTokenRange.aStart.Col()) ); + aNewTokenRange.aEnd.SetRow( aNewTokenRange.aStart.Row() + (aTokenRange.aEnd.Row() - aTokenRange.aStart.Row()) ); + ScMarkData aDestMark; + aDestMark.SelectOneTable( nDestTab ); + aDestMark.SetMarkArea( aNewTokenRange ); + pDoc->CopyFromClip( aNewTokenRange, aDestMark, IDF_ALL, NULL, &aClipDoc, FALSE ); + aNewTokenRange.aStart.SetRow( aNewTokenRange.aEnd.Row() + 2 ); + } + } + } + else + { + String aErr = ScGlobal::GetRscString(STR_LINKERROR); + pDoc->SetString( aDestPos.Col(), aDestPos.Row(), aDestPos.Tab(), aErr ); + } + + // Undo eintragen + + if ( bAddUndo && bUndo) + { + pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRedoDoc->InitUndo( pDoc, nDestTab, nDestTab ); + pDoc->CopyToDocument( aNewRange, IDF_ALL & ~IDF_NOTE, FALSE, pRedoDoc ); + + pImpl->m_pDocSh->GetUndoManager()->AddUndoAction( + new ScUndoUpdateAreaLink( pImpl->m_pDocSh, + aFileName, aFilterName, aOptions, + aSourceArea, aOldRange, GetRefreshDelay(), + aNewUrl, rNewFilter, aNewOpt, + rNewArea, aNewRange, nNewRefresh, + pUndoDoc, pRedoDoc, bDoInsert ) ); + } + + // neue Einstellungen merken + + if ( bNewUrlName ) + aFileName = aNewUrl; + if ( rNewFilter != aFilterName ) + aFilterName = rNewFilter; + if ( rNewArea != aSourceArea ) + aSourceArea = rNewArea; + if ( aNewOpt != aOptions ) + aOptions = aNewOpt; + + if ( aNewRange != aDestArea ) + aDestArea = aNewRange; + + if ( nNewRefresh != GetRefreshDelay() ) + SetRefreshDelay( nNewRefresh ); + + SCCOL nPaintEndX = Max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() ); + SCROW nPaintEndY = Max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() ); + + if ( aOldRange.aEnd.Col() != aNewRange.aEnd.Col() ) + nPaintEndX = MAXCOL; + if ( aOldRange.aEnd.Row() != aNewRange.aEnd.Row() ) + nPaintEndY = MAXROW; + + if ( !pImpl->m_pDocSh->AdjustRowHeight( aDestPos.Row(), nPaintEndY, nDestTab ) ) + pImpl->m_pDocSh->PostPaint( aDestPos.Col(),aDestPos.Row(),nDestTab, + nPaintEndX,nPaintEndY,nDestTab, PAINT_GRID ); + aModificator.SetDocumentModified(); + } + else + { + // CanFitBlock FALSE -> Probleme mit zusammengefassten Zellen + // oder Tabellengrenze erreicht! + //! Zellschutz ??? + + //! Link-Dialog muss Default-Parent setzen + // "kann keine Zeilen einfuegen" + InfoBox aBox( Application::GetDefDialogParent(), + ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_2 ) ); + aBox.Execute(); + } + + // aufraeumen + + aRef->DoClose(); + + pDoc->SetInLinkUpdate( FALSE ); + + if (bCanDo) + { + // notify Uno objects (for XRefreshListener) + //! also notify Uno objects if file name was changed! + ScLinkRefreshedHint aHint; + aHint.SetAreaLink( aDestPos ); + pDoc->BroadcastUno( aHint ); + } + + return bCanDo; +} + + +IMPL_LINK( ScAreaLink, RefreshHdl, ScAreaLink*, EMPTYARG ) +{ + long nRes = Refresh( aFileName, aFilterName, aSourceArea, + GetRefreshDelay() ) != 0; + return nRes; +} + +IMPL_LINK( ScAreaLink, AreaEndEditHdl, void*, EMPTYARG ) +{ + // #i76514# can't use link argument to access the dialog, + // because it's the ScLinkedAreaDlg, not AbstractScLinkedAreaDlg + + if ( pImpl->m_pDialog && pImpl->m_pDialog->GetResult() == RET_OK ) + { + aOptions = pImpl->m_pDialog->GetOptions(); + Refresh( pImpl->m_pDialog->GetURL(), pImpl->m_pDialog->GetFilter(), + pImpl->m_pDialog->GetSource(), pImpl->m_pDialog->GetRefresh() ); + + // copy source data from members (set in Refresh) into link name for dialog + String aNewLinkName; + sfx2::MakeLnkName( aNewLinkName, NULL, aFileName, aSourceArea, &aFilterName ); + SetName( aNewLinkName ); + } + pImpl->m_pDialog = NULL; // dialog is deleted with parent + + return 0; +} + diff --git a/sc/source/ui/docshell/autostyl.cxx b/sc/source/ui/docshell/autostyl.cxx new file mode 100644 index 000000000000..61683e169f02 --- /dev/null +++ b/sc/source/ui/docshell/autostyl.cxx @@ -0,0 +1,244 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <time.h> +#include "autostyl.hxx" + +#include "docsh.hxx" +#include "attrib.hxx" +#include "sc.hrc" + +//================================================================== + +struct ScAutoStyleInitData +{ + ScRange aRange; + String aStyle1; + ULONG nTimeout; + String aStyle2; + + ScAutoStyleInitData( const ScRange& rR, const String& rSt1, ULONG nT, const String& rSt2 ) : + aRange(rR), aStyle1(rSt1), nTimeout(nT), aStyle2(rSt2) {} +}; + +struct ScAutoStyleData +{ + ULONG nTimeout; + ScRange aRange; + String aStyle; + + ScAutoStyleData( ULONG nT, const ScRange& rR, const String& rT ) : + nTimeout(nT), aRange(rR), aStyle(rT) {} +}; + +//================================================================== + +inline ULONG TimeNow() // Sekunden +{ + return (ULONG) time(0); +} + +//================================================================== + +ScAutoStyleList::ScAutoStyleList(ScDocShell* pShell) : + pDocSh( pShell ) +{ + aTimer.SetTimeoutHdl( LINK( this, ScAutoStyleList, TimerHdl ) ); + aInitTimer.SetTimeoutHdl( LINK( this, ScAutoStyleList, InitHdl ) ); + aInitTimer.SetTimeout( 0 ); +} + +ScAutoStyleList::~ScAutoStyleList() +{ + ULONG i; + ULONG nCount = aEntries.Count(); + for (i=0; i<nCount; i++) + delete (ScAutoStyleData*) aEntries.GetObject(i); + nCount = aInitials.Count(); + for (i=0; i<nCount; i++) + delete (ScAutoStyleInitData*) aInitials.GetObject(i); +} + +//================================================================== + +// initial short delay (asynchronous call) + +void ScAutoStyleList::AddInitial( const ScRange& rRange, const String& rStyle1, + ULONG nTimeout, const String& rStyle2 ) +{ + ScAutoStyleInitData* pNew = + new ScAutoStyleInitData( rRange, rStyle1, nTimeout, rStyle2 ); + aInitials.Insert( pNew, aInitials.Count() ); + aInitTimer.Start(); +} + +IMPL_LINK( ScAutoStyleList, InitHdl, Timer*, EMPTYARG ) +{ + ULONG nCount = aInitials.Count(); + for (ULONG i=0; i<nCount; i++) + { + ScAutoStyleInitData* pData = (ScAutoStyleInitData*) aInitials.GetObject(i); + + // apply first style immediately + pDocSh->DoAutoStyle( pData->aRange, pData->aStyle1 ); + + // add second style to list + if ( pData->nTimeout ) + AddEntry( pData->nTimeout, pData->aRange, pData->aStyle2 ); + + delete pData; + } + aInitials.Clear(); + + return 0; +} + +//================================================================== + +void ScAutoStyleList::AddEntry( ULONG nTimeout, const ScRange& rRange, const String& rStyle ) +{ + aTimer.Stop(); + ULONG nNow = TimeNow(); + + // alten Eintrag loeschen + + ULONG nCount = aEntries.Count(); + ULONG i; + for (i=0; i<nCount; i++) + { + ScAutoStyleData* pData = (ScAutoStyleData*) aEntries.GetObject(i); + if (pData->aRange == rRange) + { + delete pData; + aEntries.Remove(i); + --nCount; + break; // nicht weitersuchen - es kann nur einen geben + } + } + + // Timeouts von allen Eintraegen anpassen + + if (nCount && nNow != nTimerStart) + { + DBG_ASSERT(nNow>nTimerStart, "Zeit laeuft rueckwaerts?"); + AdjustEntries((nNow-nTimerStart)*1000); + } + + // Einfuege-Position suchen + + ULONG nPos = LIST_APPEND; + for (i=0; i<nCount && nPos == LIST_APPEND; i++) + if (nTimeout <= ((ScAutoStyleData*) aEntries.GetObject(i))->nTimeout) + nPos = i; + + ScAutoStyleData* pNew = new ScAutoStyleData( nTimeout, rRange, rStyle ); + aEntries.Insert( pNew, nPos ); + + // abgelaufene ausfuehren, Timer neu starten + + ExecuteEntries(); + StartTimer(nNow); +} + +void ScAutoStyleList::AdjustEntries( ULONG nDiff ) // Millisekunden +{ + ULONG nCount = aEntries.Count(); + for (ULONG i=0; i<nCount; i++) + { + ScAutoStyleData* pData = (ScAutoStyleData*) aEntries.GetObject(i); + if ( pData->nTimeout <= nDiff ) + pData->nTimeout = 0; // abgelaufen + else + pData->nTimeout -= nDiff; // weiterzaehlen + } +} + +void ScAutoStyleList::ExecuteEntries() +{ + ScAutoStyleData* pData; + while ((pData = (ScAutoStyleData*) aEntries.GetObject(0)) != NULL && pData->nTimeout == 0) + { + pDocSh->DoAutoStyle( pData->aRange, pData->aStyle ); //! oder Request ??? + + delete pData; + aEntries.Remove((ULONG)0); + } +} + +void ScAutoStyleList::ExecuteAllNow() +{ + aTimer.Stop(); + + ULONG nCount = aEntries.Count(); + for (ULONG i=0; i<nCount; i++) + { + ScAutoStyleData* pData = (ScAutoStyleData*) aEntries.GetObject(i); + + pDocSh->DoAutoStyle( pData->aRange, pData->aStyle ); //! oder Request ??? + + delete pData; + } + aEntries.Clear(); +} + +void ScAutoStyleList::StartTimer( ULONG nNow ) // Sekunden +{ + // ersten Eintrag mit Timeout != 0 suchen + + ULONG nPos = 0; + ScAutoStyleData* pData; + while ( (pData = (ScAutoStyleData*) aEntries.GetObject(nPos)) != NULL && pData->nTimeout == 0 ) + ++nPos; + + if (pData) + { + aTimer.SetTimeout( pData->nTimeout ); + aTimer.Start(); + } + nTimerStart = nNow; +} + +IMPL_LINK( ScAutoStyleList, TimerHdl, Timer*, EMPTYARG ) +{ + ULONG nNow = TimeNow(); + AdjustEntries(aTimer.GetTimeout()); // eingestellte Wartezeit + ExecuteEntries(); + StartTimer(nNow); + + return 0; +} + + + + diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx new file mode 100644 index 000000000000..1633af000b51 --- /dev/null +++ b/sc/source/ui/docshell/dbdocfun.cxx @@ -0,0 +1,1487 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <sfx2/app.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/waitobj.hxx> + +#include <com/sun/star/sdbc/XResultSet.hpp> + +#include "dbdocfun.hxx" +#include "sc.hrc" +#include "dbcolect.hxx" +#include "undodat.hxx" +#include "docsh.hxx" +#include "docfunc.hxx" +#include "globstr.hrc" +#include "tabvwsh.hxx" +#include "patattr.hxx" +#include "rangenam.hxx" +#include "olinetab.hxx" +#include "dpobject.hxx" +#include "dociter.hxx" // for lcl_EmptyExcept +#include "cell.hxx" // for lcl_EmptyExcept +#include "editable.hxx" +#include "attrib.hxx" +#include "drwlayer.hxx" +#include "dpshttab.hxx" + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::AddDBRange( const String& rName, const ScRange& rRange, BOOL /* bApi */ ) +{ + + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + ScDBCollection* pDocColl = pDoc->GetDBCollection(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + ScDBCollection* pUndoColl = NULL; + if (bUndo) + pUndoColl = new ScDBCollection( *pDocColl ); + + ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(), + rRange.aStart.Col(), rRange.aStart.Row(), + rRange.aEnd.Col(), rRange.aEnd.Row() ); + + // #i55926# While loading XML, formula cells only have a single string token, + // so CompileDBFormula would never find any name (index) tokens, and would + // unnecessarily loop through all cells. + BOOL bCompile = !pDoc->IsImportingXML(); + + if ( bCompile ) + pDoc->CompileDBFormula( TRUE ); // CreateFormulaString + BOOL bOk = pDocColl->Insert( pNew ); + if ( bCompile ) + pDoc->CompileDBFormula( FALSE ); // CompileFormulaString + + if (!bOk) + { + delete pNew; + delete pUndoColl; + return FALSE; + } + + if (bUndo) + { + ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) ); + } + + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); + return TRUE; +} + +BOOL ScDBDocFunc::DeleteDBRange( const String& rName, BOOL /* bApi */ ) +{ + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + ScDBCollection* pDocColl = pDoc->GetDBCollection(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + USHORT nPos = 0; + if (pDocColl->SearchName( rName, nPos )) + { + ScDocShellModificator aModificator( rDocShell ); + + ScDBCollection* pUndoColl = NULL; + if (bUndo) + pUndoColl = new ScDBCollection( *pDocColl ); + + pDoc->CompileDBFormula( TRUE ); // CreateFormulaString + pDocColl->AtFree( nPos ); + pDoc->CompileDBFormula( FALSE ); // CompileFormulaString + + if (bUndo) + { + ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) ); + } + + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); + bDone = TRUE; + } + + return bDone; +} + +BOOL ScDBDocFunc::RenameDBRange( const String& rOld, const String& rNew, BOOL /* bApi */ ) +{ + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + ScDBCollection* pDocColl = pDoc->GetDBCollection(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + USHORT nPos = 0; + USHORT nDummy = 0; + if ( pDocColl->SearchName( rOld, nPos ) && + !pDocColl->SearchName( rNew, nDummy ) ) + { + ScDocShellModificator aModificator( rDocShell ); + + ScDBData* pData = (*pDocColl)[nPos]; + ScDBData* pNewData = new ScDBData(*pData); + pNewData->SetName(rNew); + + ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl ); + + pDoc->CompileDBFormula( TRUE ); // CreateFormulaString + pDocColl->AtFree( nPos ); + BOOL bInserted = pDocColl->Insert( pNewData ); + if (!bInserted) // Fehler -> alten Zustand wiederherstellen + { + delete pNewData; + pDoc->SetDBCollection( pUndoColl ); // gehoert dann dem Dokument + } + pDoc->CompileDBFormula( FALSE ); // CompileFormulaString + + if (bInserted) // Einfuegen hat geklappt + { + if (bUndo) + { + ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) ); + } + else + delete pUndoColl; + + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); + bDone = TRUE; + } + } + + return bDone; +} + +BOOL ScDBDocFunc::ModifyDBData( const ScDBData& rNewData, BOOL /* bApi */ ) +{ + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + ScDBCollection* pDocColl = pDoc->GetDBCollection(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + USHORT nPos = 0; + if (pDocColl->SearchName( rNewData.GetName(), nPos )) + { + ScDocShellModificator aModificator( rDocShell ); + + ScDBData* pData = (*pDocColl)[nPos]; + + ScRange aOldRange, aNewRange; + pData->GetArea(aOldRange); + rNewData.GetArea(aNewRange); + BOOL bAreaChanged = ( aOldRange != aNewRange ); // dann muss neu compiliert werden + + ScDBCollection* pUndoColl = NULL; + if (bUndo) + pUndoColl = new ScDBCollection( *pDocColl ); + + *pData = rNewData; + if (bAreaChanged) + pDoc->CompileDBFormula(); + + if (bUndo) + { + ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) ); + } + + aModificator.SetDocumentModified(); + bDone = TRUE; + } + + return bDone; +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::RepeatDB( const String& rDBName, BOOL bRecord, BOOL bApi ) +{ + //! auch fuer ScDBFunc::RepeatDB benutzen! + + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScDBCollection* pColl = pDoc->GetDBCollection(); + USHORT nIndex; + if ( pColl && pColl->SearchName( rDBName, nIndex ) ) + { + ScDBData* pDBData = (*pColl)[nIndex]; + + ScQueryParam aQueryParam; + pDBData->GetQueryParam( aQueryParam ); + BOOL bQuery = aQueryParam.GetEntry(0).bDoQuery; + + ScSortParam aSortParam; + pDBData->GetSortParam( aSortParam ); + BOOL bSort = aSortParam.bDoSort[0]; + + ScSubTotalParam aSubTotalParam; + pDBData->GetSubTotalParam( aSubTotalParam ); + BOOL bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly; + + if ( bQuery || bSort || bSubTotal ) + { + BOOL bQuerySize = FALSE; + ScRange aOldQuery; + ScRange aNewQuery; + if (bQuery && !aQueryParam.bInplace) + { + ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow, + aQueryParam.nDestTab, TRUE ); + if (pDest && pDest->IsDoSize()) + { + pDest->GetArea( aOldQuery ); + bQuerySize = TRUE; + } + } + + SCTAB nTab; + SCCOL nStartCol; + SCROW nStartRow; + SCCOL nEndCol; + SCROW nEndRow; + pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ); + + //! Undo nur benoetigte Daten ? + + ScDocument* pUndoDoc = NULL; + ScOutlineTable* pUndoTab = NULL; + ScRangeName* pUndoRange = NULL; + ScDBCollection* pUndoDB = NULL; + + if (bRecord) + { + SCTAB nTabCount = pDoc->GetTableCount(); + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + if (pTable) + { + pUndoTab = new ScOutlineTable( *pTable ); + + // column/row state + SCCOLROW nOutStartCol, nOutEndCol; + SCCOLROW nOutStartRow, nOutEndRow; + pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol ); + pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow ); + + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, + nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, + IDF_NONE, FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, static_cast<SCROW>(nOutStartRow), + nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab, + IDF_NONE, FALSE, pUndoDoc ); + } + else + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + + // Datenbereich sichern - incl. Filter-Ergebnis + pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, FALSE, pUndoDoc ); + + // alle Formeln wegen Referenzen + pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, FALSE, pUndoDoc ); + + // DB- und andere Bereiche + ScRangeName* pDocRange = pDoc->GetRangeName(); + if (pDocRange->GetCount()) + pUndoRange = new ScRangeName( *pDocRange ); + ScDBCollection* pDocDB = pDoc->GetDBCollection(); + if (pDocDB->GetCount()) + pUndoDB = new ScDBCollection( *pDocDB ); + } + + if (bSort && bSubTotal) + { + // Sortieren ohne SubTotals + + aSubTotalParam.bRemoveOnly = TRUE; // wird unten wieder zurueckgesetzt + DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi ); + } + + if (bSort) + { + pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben + Sort( nTab, aSortParam, FALSE, FALSE, bApi ); + } + if (bQuery) + { + pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben + ScRange aAdvSource; + if (pDBData->GetAdvancedQuerySource(aAdvSource)) + Query( nTab, aQueryParam, &aAdvSource, FALSE, bApi ); + else + Query( nTab, aQueryParam, NULL, FALSE, bApi ); + + // bei nicht-inplace kann die Tabelle umgestellt worden sein +// if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab ) +// SetTabNo( nTab ); + } + if (bSubTotal) + { + pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben + aSubTotalParam.bRemoveOnly = FALSE; + DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi ); + } + + if (bRecord) + { + SCTAB nDummyTab; + SCCOL nDummyCol; + SCROW nDummyRow; + SCROW nNewEndRow; + pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow ); + + const ScRange* pOld = NULL; + const ScRange* pNew = NULL; + if (bQuerySize) + { + ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow, + aQueryParam.nDestTab, TRUE ); + if (pDest) + { + pDest->GetArea( aNewQuery ); + pOld = &aOldQuery; + pNew = &aNewQuery; + } + } + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRepeatDB( &rDocShell, nTab, + nStartCol, nStartRow, nEndCol, nEndRow, + nNewEndRow, + //nCurX, nCurY, + nStartCol, nStartRow, + pUndoDoc, pUndoTab, + pUndoRange, pUndoDB, + pOld, pNew ) ); + } + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, + PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); + bDone = TRUE; + } + else if (!bApi) // "Keine Operationen auszufuehren" + rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0); + } + + return bDone; +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam, + BOOL bRecord, BOOL bPaint, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + SCTAB nSrcTab = nTab; + ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); + + ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1, + rSortParam.nCol2, rSortParam.nRow2 ); + if (!pDBData) + { + DBG_ERROR( "Sort: keine DBData" ); + return FALSE; + } + + ScDBData* pDestData = NULL; + ScRange aOldDest; + BOOL bCopy = !rSortParam.bInplace; + if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 && + rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab ) + bCopy = FALSE; + ScSortParam aLocalParam( rSortParam ); + if ( bCopy ) + { + aLocalParam.MoveToDest(); + if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PASTE_FULL); + return FALSE; + } + + nTab = rSortParam.nDestTab; + pDestData = pDoc->GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow, + rSortParam.nDestTab, TRUE ); + if (pDestData) + pDestData->GetArea(aOldDest); + } + + ScEditableTester aTester( pDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1, + aLocalParam.nCol2,aLocalParam.nRow2 ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + if ( aLocalParam.bIncludePattern && pDoc->HasAttrib( + aLocalParam.nCol1, aLocalParam.nRow1, nTab, + aLocalParam.nCol2, aLocalParam.nRow2, nTab, + HASATTR_MERGED | HASATTR_OVERLAPPED ) ) + { + // Merge-Attribute wuerden beim Sortieren durcheinanderkommen + if (!bApi) + rDocShell.ErrorMessage(STR_SORT_ERR_MERGED); + return FALSE; + } + + + // ausfuehren + + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + BOOL bRepeatQuery = FALSE; // bestehenden Filter wiederholen? + ScQueryParam aQueryParam; + pDBData->GetQueryParam( aQueryParam ); + if ( aQueryParam.GetEntry(0).bDoQuery ) + bRepeatQuery = TRUE; + + if (bRepeatQuery && bCopy) + { + if ( aQueryParam.bInplace || + aQueryParam.nDestCol != rSortParam.nDestCol || + aQueryParam.nDestRow != rSortParam.nDestRow || + aQueryParam.nDestTab != rSortParam.nDestTab ) // Query auf selben Zielbereich? + bRepeatQuery = FALSE; + } + + ScUndoSort* pUndoAction = 0; + if ( bRecord ) + { + // Referenzen ausserhalb des Bereichs werden nicht veraendert ! + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + // Zeilenhoehen immer (wegen automatischer Anpassung) + //! auf ScBlockUndo umstellen + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + + /* #i59745# Do not copy note captions to undo document. All existing + caption objects will be repositioned while sorting which is tracked + in drawing undo. When undo is executed, the old positions will be + restored, and the cells with the old notes (which still refer to the + existing captions) will be copied back into the source document. */ + pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nTab, + aLocalParam.nCol2, aLocalParam.nRow2, nTab, + IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc ); + + const ScRange* pR = 0; + if (pDestData) + { + /* #i59745# Do not copy note captions from destination range to + undo document. All existing caption objects will be removed + which is tracked in drawing undo. When undo is executed, the + caption objects are reinserted with drawing undo, and the cells + with the old notes (which still refer to the existing captions) + will be copied back into the source document. */ + pDoc->CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc ); + pR = &aOldDest; + } + + // Zeilenhoehen immer (wegen automatischer Anpassung) + //! auf ScBlockUndo umstellen +// if (bRepeatQuery) + pDoc->CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab, + IDF_NONE, FALSE, pUndoDoc ); + + ScDBCollection* pUndoDB = NULL; + ScDBCollection* pDocDB = pDoc->GetDBCollection(); + if (pDocDB->GetCount()) + pUndoDB = new ScDBCollection( *pDocDB ); + + pUndoAction = new ScUndoSort( &rDocShell, nTab, rSortParam, bRepeatQuery, pUndoDoc, pUndoDB, pR ); + rDocShell.GetUndoManager()->AddUndoAction( pUndoAction ); + + // #i59745# collect all drawing undo actions affecting cell note captions + if( pDrawLayer ) + pDrawLayer->BeginCalcUndo(); + } + + if ( bCopy ) + { + if (pDestData) + pDoc->DeleteAreaTab(aOldDest, IDF_CONTENTS); // Zielbereich vorher loeschen + + ScRange aSource( rSortParam.nCol1,rSortParam.nRow1,nSrcTab, + rSortParam.nCol2,rSortParam.nRow2,nSrcTab ); + ScAddress aDest( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab ); + + rDocShell.GetDocFunc().MoveBlock( aSource, aDest, FALSE, FALSE, FALSE, TRUE ); + } + + // #105780# don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set) + if ( aLocalParam.bDoSort[0] ) + pDoc->Sort( nTab, aLocalParam, bRepeatQuery ); + + BOOL bSave = TRUE; + if (bCopy) + { + ScSortParam aOldSortParam; + pDBData->GetSortParam( aOldSortParam ); + if ( aOldSortParam.bDoSort[0] && aOldSortParam.bInplace ) // Inplace-Sortierung gemerkt? + { + bSave = FALSE; + aOldSortParam.nDestCol = rSortParam.nDestCol; + aOldSortParam.nDestRow = rSortParam.nDestRow; + aOldSortParam.nDestTab = rSortParam.nDestTab; + pDBData->SetSortParam( aOldSortParam ); // dann nur DestPos merken + } + } + if (bSave) // Parameter merken + { + pDBData->SetSortParam( rSortParam ); + pDBData->SetHeader( rSortParam.bHasHeader ); //! ??? + pDBData->SetByRow( rSortParam.bByRow ); //! ??? + } + + if (bCopy) // neuen DB-Bereich merken + { + // Tabelle umschalten von aussen (View) + //! SetCursor ??!?! + + ScRange aDestPos( aLocalParam.nCol1, aLocalParam.nRow1, nTab, + aLocalParam.nCol2, aLocalParam.nRow2, nTab ); + ScDBData* pNewData; + if (pDestData) + pNewData = pDestData; // Bereich vorhanden -> anpassen + else // Bereich ab Cursor/Markierung wird angelegt + pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, TRUE ); + if (pNewData) + { + pNewData->SetArea( nTab, + aLocalParam.nCol1,aLocalParam.nRow1, + aLocalParam.nCol2,aLocalParam.nRow2 ); + pNewData->SetSortParam( aLocalParam ); + pNewData->SetHeader( aLocalParam.bHasHeader ); //! ??? + pNewData->SetByRow( aLocalParam.bByRow ); + } + else + { + DBG_ERROR("Zielbereich nicht da"); + } + } + + ScRange aDirtyRange( aLocalParam.nCol1, aLocalParam.nRow1, nTab, + aLocalParam.nCol2, aLocalParam.nRow2, nTab ); + pDoc->SetDirty( aDirtyRange ); + + if (bPaint) + { + USHORT nPaint = PAINT_GRID; + SCCOL nStartX = aLocalParam.nCol1; + SCROW nStartY = aLocalParam.nRow1; + SCCOL nEndX = aLocalParam.nCol2; + SCROW nEndY = aLocalParam.nRow2; + if ( bRepeatQuery ) + { + nPaint |= PAINT_LEFT; + nStartX = 0; + nEndX = MAXCOL; + } + if (pDestData) + { + if ( nEndX < aOldDest.aEnd.Col() ) + nEndX = aOldDest.aEnd.Col(); + if ( nEndY < aOldDest.aEnd.Row() ) + nEndY = aOldDest.aEnd.Row(); + } + rDocShell.PostPaint( nStartX, nStartY, nTab, nEndX, nEndY, nTab, nPaint ); + } + + // AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, bPaint ); + rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab ); + + // #i59745# set collected drawing undo actions at sorting undo action + if( pUndoAction && pDrawLayer ) + pUndoAction->SetDrawUndoAction( pDrawLayer->GetCalcUndo() ); + + aModificator.SetDocumentModified(); + + return TRUE; +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam, + const ScRange* pAdvSource, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1, + rQueryParam.nCol2, rQueryParam.nRow2 ); + if (!pDBData) + { + DBG_ERROR( "Query: keine DBData" ); + return FALSE; + } + + // Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben: + // (nur, wenn im Dialog "Persistent" ausgewaehlt ist) + + if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers ) + { + ScQueryParam aOldQuery; + pDBData->GetQueryParam(aOldQuery); + if (aOldQuery.bInplace) + { + // alte Filterung aufheben + + SCSIZE nEC = aOldQuery.GetEntryCount(); + for (SCSIZE i=0; i<nEC; i++) + aOldQuery.GetEntry(i).bDoQuery = FALSE; + aOldQuery.bDuplicate = TRUE; + Query( nTab, aOldQuery, NULL, bRecord, bApi ); + } + } + + ScQueryParam aLocalParam( rQueryParam ); // fuer Paint / Zielbereich + BOOL bCopy = !rQueryParam.bInplace; // kopiert wird in Table::Query + ScDBData* pDestData = NULL; // Bereich, in den kopiert wird + BOOL bDoSize = FALSE; // Zielgroesse anpassen (einf./loeschen) + SCCOL nFormulaCols = 0; // nur bei bDoSize + BOOL bKeepFmt = FALSE; + ScRange aOldDest; + ScRange aDestTotal; + if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 && + rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab ) + bCopy = FALSE; + SCTAB nDestTab = nTab; + if ( bCopy ) + { + aLocalParam.MoveToDest(); + nDestTab = rQueryParam.nDestTab; + if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PASTE_FULL); + return FALSE; + } + + ScEditableTester aTester( pDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1, + aLocalParam.nCol2,aLocalParam.nRow2); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + pDestData = pDoc->GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow, + rQueryParam.nDestTab, TRUE ); + if (pDestData) + { + pDestData->GetArea( aOldDest ); + aDestTotal=ScRange( rQueryParam.nDestCol, + rQueryParam.nDestRow, + nDestTab, + rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1, + rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1, + nDestTab ); + + bDoSize = pDestData->IsDoSize(); + // Test, ob Formeln aufgefuellt werden muessen (nFormulaCols): + if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() ) + { + SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // neben dem Bereich + SCROW nTestRow = rQueryParam.nDestRow + + ( aLocalParam.bHasHeader ? 1 : 0 ); + while ( nTestCol <= MAXCOL && + pDoc->GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA ) + ++nTestCol, ++nFormulaCols; + } + + bKeepFmt = pDestData->IsKeepFmt(); + if ( bDoSize && !pDoc->CanFitBlock( aOldDest, aDestTotal ) ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // kann keine Zeilen einfuegen + return FALSE; + } + } + } + + // ausfuehren + + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + BOOL bKeepSub = FALSE; // bestehende Teilergebnisse wiederholen? + ScSubTotalParam aSubTotalParam; + if (rQueryParam.GetEntry(0).bDoQuery) // nicht beim Aufheben + { + pDBData->GetSubTotalParam( aSubTotalParam ); // Teilergebnisse vorhanden? + + if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly ) + bKeepSub = TRUE; + } + + ScDocument* pUndoDoc = NULL; + ScDBCollection* pUndoDB = NULL; + const ScRange* pOld = NULL; + + if ( bRecord ) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if (bCopy) + { + pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE ); + pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, + aLocalParam.nCol2, aLocalParam.nRow2, nDestTab, + IDF_ALL, FALSE, pUndoDoc ); + // Attribute sichern, falls beim Filtern mitkopiert + + if (pDestData) + { + pDoc->CopyToDocument( aOldDest, IDF_ALL, FALSE, pUndoDoc ); + pOld = &aOldDest; + } + } + else + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + pDoc->CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab, + IDF_NONE, FALSE, pUndoDoc ); + } + + ScDBCollection* pDocDB = pDoc->GetDBCollection(); + if (pDocDB->GetCount()) + pUndoDB = new ScDBCollection( *pDocDB ); + + pDoc->BeginDrawUndo(); + } + + ScDocument* pAttribDoc = NULL; + ScRange aAttribRange; + if (pDestData) // Zielbereich loeschen + { + if ( bKeepFmt ) + { + // kleinere der End-Spalten, Header+1 Zeile + aAttribRange = aOldDest; + if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() ) + aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() ); + aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() + + ( aLocalParam.bHasHeader ? 1 : 0 ) ); + + // auch fuer aufgefuellte Formeln + aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols ); + + pAttribDoc = new ScDocument( SCDOCMODE_UNDO ); + pAttribDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE ); + pDoc->CopyToDocument( aAttribRange, IDF_ATTRIB, FALSE, pAttribDoc ); + } + + if ( bDoSize ) + pDoc->FitBlock( aOldDest, aDestTotal ); + else + pDoc->DeleteAreaTab(aOldDest, IDF_ALL); // einfach loeschen + } + + // Filtern am Dokument ausfuehren + SCSIZE nCount = pDoc->Query( nTab, rQueryParam, bKeepSub ); + if (bCopy) + { + aLocalParam.nRow2 = aLocalParam.nRow1 + nCount; + if (!aLocalParam.bHasHeader && nCount > 0) + --aLocalParam.nRow2; + + if ( bDoSize ) + { + // auf wirklichen Ergebnis-Bereich anpassen + // (das hier ist immer eine Verkleinerung) + + ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, + aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ); + pDoc->FitBlock( aDestTotal, aNewDest, FALSE ); // FALSE - nicht loeschen + + if ( nFormulaCols > 0 ) + { + // Formeln ausfuellen + //! Undo (Query und Repeat) !!! + + ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab, + aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab ); + ScRange aOldForm = aNewForm; + aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() ); + pDoc->FitBlock( aOldForm, aNewForm, FALSE ); + + ScMarkData aMark; + aMark.SelectOneTable(nDestTab); + SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 ); + pDoc->Fill( aLocalParam.nCol2+1, nFStartY, + aLocalParam.nCol2+nFormulaCols, nFStartY, aMark, + aLocalParam.nRow2 - nFStartY, + FILL_TO_BOTTOM, FILL_SIMPLE ); + } + } + + if ( pAttribDoc ) // gemerkte Attribute zurueckkopieren + { + // Header + if (aLocalParam.bHasHeader) + { + ScRange aHdrRange = aAttribRange; + aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() ); + pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, FALSE, pDoc ); + } + + // Daten + SCCOL nAttrEndCol = aAttribRange.aEnd.Col(); + SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 ); + for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++) + { + const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern( + nCol, nAttrRow, nDestTab ); + DBG_ASSERT(pSrcPattern,"Pattern ist 0"); + if (pSrcPattern) + pDoc->ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2, + nDestTab, *pSrcPattern ); + const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet(); + if (pStyle) + pDoc->ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2, + nDestTab, *pStyle ); + } + + delete pAttribDoc; + } + } + + // speichern: Inplace immer, sonst je nach Einstellung + // alter Inplace-Filter ist ggf. schon aufgehoben + + BOOL bSave = rQueryParam.bInplace || rQueryParam.bDestPers; + if (bSave) // merken + { + pDBData->SetQueryParam( rQueryParam ); + pDBData->SetHeader( rQueryParam.bHasHeader ); //! ??? + pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam + } + + if (bCopy) // neuen DB-Bereich merken + { + // selektieren wird hinterher von aussen (dbfunc) + // momentan ueber DB-Bereich an der Zielposition, darum muss dort + // auf jeden Fall ein Bereich angelegt werden. + + ScDBData* pNewData; + if (pDestData) + pNewData = pDestData; // Bereich vorhanden -> anpassen (immer!) + else // Bereich anlegen + pNewData = rDocShell.GetDBData( + ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, + aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ), + SC_DB_MAKE, TRUE ); + + if (pNewData) + { + pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1, + aLocalParam.nCol2, aLocalParam.nRow2 ); + + // Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung + // und Verwechslung mit dem Query-Param am Quellbereich (#37187#) + } + else + { + DBG_ERROR("Zielbereich nicht da"); + } + } + + if (!bCopy) + pDoc->UpdatePageBreaks( nTab ); + + // #i23299# because of Subtotal functions, the whole rows must be set dirty + ScRange aDirtyRange( 0 , aLocalParam.nRow1, nDestTab, + MAXCOL, aLocalParam.nRow2, nDestTab ); + pDoc->SetDirty( aDirtyRange ); + + if ( bRecord ) + { + // create undo action after executing, because of drawing layer undo + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB, + pOld, bDoSize, pAdvSource ) ); + } + + + if (bCopy) + { + SCCOL nEndX = aLocalParam.nCol2; + SCROW nEndY = aLocalParam.nRow2; + if (pDestData) + { + if ( aOldDest.aEnd.Col() > nEndX ) + nEndX = aOldDest.aEnd.Col(); + if ( aOldDest.aEnd.Row() > nEndY ) + nEndY = aOldDest.aEnd.Row(); + } + if (bDoSize) + nEndY = MAXROW; + rDocShell.PostPaint( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, + nEndX, nEndY, nDestTab, PAINT_GRID ); + } + else + rDocShell.PostPaint( 0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab, + PAINT_GRID | PAINT_LEFT ); + aModificator.SetDocumentModified(); + + return TRUE; +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam, + const ScSortParam* pForceNewSort, BOOL bRecord, BOOL bApi ) +{ + //! auch fuer ScDBFunc::DoSubTotals benutzen! + // dann bleibt aussen: + // - neuen Bereich (aus DBData) markieren + // - SelectionChanged (?) + + BOOL bDo = !rParam.bRemoveOnly; // FALSE = nur loeschen + BOOL bRet = FALSE; + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1, + rParam.nCol2, rParam.nRow2 ); + if (!pDBData) + { + DBG_ERROR( "SubTotals: keine DBData" ); + return FALSE; + } + + ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab, + rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED )) + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen + return FALSE; + } + + BOOL bOk = TRUE; + BOOL bDelete = FALSE; + if (rParam.bReplace) + if (pDoc->TestRemoveSubTotals( nTab, rParam )) + { + bDelete = TRUE; + bOk = ( MessBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES), + // "StarCalc" "Daten loeschen?" + ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ), + ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute() + == RET_YES ); + } + + if (bOk) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + ScDocShellModificator aModificator( rDocShell ); + + ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert + ScDocument* pUndoDoc = NULL; + ScOutlineTable* pUndoTab = NULL; + ScRangeName* pUndoRange = NULL; + ScDBCollection* pUndoDB = NULL; + SCTAB nTabCount = 0; // fuer Referenz-Undo + + if (bRecord) // alte Daten sichern + { + BOOL bOldFilter = bDo && rParam.bDoSort; + + nTabCount = pDoc->GetTableCount(); + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + if (pTable) + { + pUndoTab = new ScOutlineTable( *pTable ); + + // column/row state + SCCOLROW nOutStartCol, nOutEndCol; + SCCOLROW nOutStartRow, nOutEndRow; + pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol ); + pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow ); + + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + else + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, bOldFilter ); + + // Datenbereich sichern - incl. Filter-Ergebnis + pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab, + IDF_ALL, FALSE, pUndoDoc ); + + // alle Formeln wegen Referenzen + pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, + IDF_FORMULA, FALSE, pUndoDoc ); + + // DB- und andere Bereiche + ScRangeName* pDocRange = pDoc->GetRangeName(); + if (pDocRange->GetCount()) + pUndoRange = new ScRangeName( *pDocRange ); + ScDBCollection* pDocDB = pDoc->GetDBCollection(); + if (pDocDB->GetCount()) + pUndoDB = new ScDBCollection( *pDocDB ); + } + +// pDoc->SetOutlineTable( nTab, NULL ); + ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab ); + if (pOut) + pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen + + if (rParam.bReplace) + pDoc->RemoveSubTotals( nTab, aNewParam ); + BOOL bSuccess = TRUE; + if (bDo) + { + // Sortieren + if ( rParam.bDoSort || pForceNewSort ) + { + pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 ); + + // Teilergebnis-Felder vor die Sortierung setzen + // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden) + + ScSortParam aOldSort; + pDBData->GetSortParam( aOldSort ); + ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort ); + Sort( nTab, aSortParam, FALSE, FALSE, bApi ); + } + + bSuccess = pDoc->DoSubTotals( nTab, aNewParam ); + } + ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab, + aNewParam.nCol2, aNewParam.nRow2, nTab ); + pDoc->SetDirty( aDirtyRange ); + + if (bRecord) + { +// ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL; + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoSubTotals( &rDocShell, nTab, + rParam, aNewParam.nRow2, + pUndoDoc, pUndoTab, // pUndoDBData, + pUndoRange, pUndoDB ) ); + } + + if (!bSuccess) + { + // "Kann keine Zeilen einfuegen" + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); + } + + // merken + pDBData->SetSubTotalParam( aNewParam ); + pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 ); + pDoc->CompileDBFormula(); + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, + PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); + aModificator.SetDocumentModified(); + + bRet = bSuccess; + } + return bRet; +} + +//================================================================== + +BOOL lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept ) +{ + ScCellIterator aIter( pDoc, rRange ); + ScBaseCell* pCell = aIter.GetFirst(); + while (pCell) + { + if ( !pCell->IsBlank() ) // real content? + { + if ( !rExcept.In( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) ) ) + return FALSE; // cell found + } + pCell = aIter.GetNext(); + } + + return TRUE; // nothing found - empty +} + +BOOL ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj, + BOOL bRecord, BOOL bApi, BOOL bAllowMove ) +{ + ScDocShellModificator aModificator( rDocShell ); + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + BOOL bDone = FALSE; + BOOL bUndoSelf = FALSE; + USHORT nErrId = 0; + + ScDocument* pOldUndoDoc = NULL; + ScDocument* pNewUndoDoc = NULL; + ScDPObject* pUndoDPObj = NULL; + if ( bRecord && pOldObj ) + pUndoDPObj = new ScDPObject( *pOldObj ); // copy old settings for undo + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + if ( !rDocShell.IsEditable() || pDoc->GetChangeTrack() ) + { + // not recorded -> disallow + //! different error messages? + + nErrId = STR_PROTECTIONERR; + } + if ( pOldObj && !nErrId ) + { + ScRange aOldOut = pOldObj->GetOutRange(); + ScEditableTester aTester( pDoc, aOldOut ); + if ( !aTester.IsEditable() ) + nErrId = aTester.GetMessageId(); + } + if ( pNewObj && !nErrId ) + { + // at least one cell at the output position must be editable + // -> check in advance + // (start of output range in pNewObj is valid) + + ScRange aNewStart( pNewObj->GetOutRange().aStart ); + ScEditableTester aTester( pDoc, aNewStart ); + if ( !aTester.IsEditable() ) + nErrId = aTester.GetMessageId(); + } + + ScDPObject* pDestObj = NULL; + if ( !nErrId ) + { + if ( pOldObj && !pNewObj ) + { + // delete table + + ScRange aRange = pOldObj->GetOutRange(); + SCTAB nTab = aRange.aStart.Tab(); + + if ( bRecord ) + { + pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pOldUndoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc ); + } + + pDoc->DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aEnd.Row(), + nTab, IDF_ALL ); + pDoc->RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aEnd.Row(), + nTab, SC_MF_AUTO ); + + pDoc->GetDPCollection()->FreeTable( pOldObj ); // object is deleted here + + rDocShell.PostPaintGridAll(); //! only necessary parts + rDocShell.PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), nTab, + aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, + PAINT_GRID ); + bDone = TRUE; + } + else if ( pNewObj ) + { + if ( pOldObj ) + { + if ( bRecord ) + { + ScRange aRange = pOldObj->GetOutRange(); + SCTAB nTab = aRange.aStart.Tab(); + pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pOldUndoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc ); + } + + if ( pNewObj == pOldObj ) + { + // refresh only - no settings modified + } + else + { + pNewObj->WriteSourceDataTo( *pOldObj ); // copy source data + + ScDPSaveData* pData = pNewObj->GetSaveData(); + DBG_ASSERT( pData, "no SaveData from living DPObject" ); + if ( pData ) + pOldObj->SetSaveData( *pData ); // copy SaveData + } + + pDestObj = pOldObj; + pDestObj->SetAllowMove( bAllowMove ); + } + else + { + // output range must be set at pNewObj + + pDestObj = new ScDPObject( *pNewObj ); + pDestObj->SetAlive(TRUE); + if ( !pDoc->GetDPCollection()->InsertNewTable(pDestObj) ) + { + DBG_ERROR("cannot insert DPObject"); + DELETEZ( pDestObj ); + } + } + if ( pDestObj ) + { + // #78541# create new database connection for "refresh" + // (and re-read column entry collections) + // so all changes take effect + if ( pNewObj == pOldObj && pDestObj->IsImportData() ) + pDestObj->InvalidateSource(); + + pDestObj->InvalidateData(); // before getting the new output area + + // make sure the table has a name (not set by dialog) + if ( !pDestObj->GetName().Len() ) + pDestObj->SetName( pDoc->GetDPCollection()->CreateNewName() ); + + BOOL bOverflow = FALSE; + ScRange aNewOut = pDestObj->GetNewOutputRange( bOverflow ); + + //! test for overlap with other data pilot tables + if( pOldObj ) + { + const ScSheetSourceDesc* pSheetDesc = pOldObj->GetSheetDesc(); + if( pSheetDesc && pSheetDesc->aSourceRange.Intersects( aNewOut ) ) + { + ScRange aOldRange = pOldObj->GetOutRange(); + SCsROW nDiff = aOldRange.aStart.Row()-aNewOut.aStart.Row(); + aNewOut.aStart.SetRow( aOldRange.aStart.Row() ); + aNewOut.aEnd.SetRow( aNewOut.aEnd.Row()+nDiff ); + if( !ValidRow( aNewOut.aStart.Row() ) || !ValidRow( aNewOut.aEnd.Row() ) ) + bOverflow = TRUE; + } + } + + if ( bOverflow ) + { + // like with STR_PROTECTIONERR, use undo to reverse everything + DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" ); + bUndoSelf = TRUE; + nErrId = STR_PIVOT_ERROR; + } + else + { + ScEditableTester aTester( pDoc, aNewOut ); + if ( !aTester.IsEditable() ) + { + // destination area isn't editable + //! reverse everything done so far, don't proceed + + // quick solution: proceed to end, use undo action + // to reverse everything: + DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" ); + bUndoSelf = TRUE; + nErrId = aTester.GetMessageId(); + } + } + + // test if new output area is empty except for old area + if ( !bApi ) + { + BOOL bEmpty; + if ( pOldObj ) // OutRange of pOldObj (pDestObj) is still old area + bEmpty = lcl_EmptyExcept( pDoc, aNewOut, pOldObj->GetOutRange() ); + else + bEmpty = pDoc->IsBlockEmpty( aNewOut.aStart.Tab(), + aNewOut.aStart.Col(), aNewOut.aStart.Row(), + aNewOut.aEnd.Col(), aNewOut.aEnd.Row() ); + + if ( !bEmpty ) + { + QueryBox aBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES), + ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) ); + if (aBox.Execute() == RET_NO) + { + //! like above (not editable), use undo to reverse everything + DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" ); + bUndoSelf = TRUE; + } + } + } + + if ( bRecord ) + { + SCTAB nTab = aNewOut.aStart.Tab(); + pNewUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pNewUndoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( aNewOut, IDF_ALL, FALSE, pNewUndoDoc ); + } + + pDestObj->Output( aNewOut.aStart ); + + rDocShell.PostPaintGridAll(); //! only necessary parts + bDone = TRUE; + } + } + // else nothing (no old, no new) + } + + if ( bRecord && bDone ) + { + SfxUndoAction* pAction = new ScUndoDataPilot( &rDocShell, + pOldUndoDoc, pNewUndoDoc, pUndoDPObj, pDestObj, bAllowMove ); + pOldUndoDoc = NULL; + pNewUndoDoc = NULL; // pointers are used in undo action + // pUndoDPObj is copied + + if (bUndoSelf) + { + // use undo action to restore original state + //! prevent setting the document modified? (ScDocShellModificator) + + pAction->Undo(); + delete pAction; + bDone = FALSE; + } + else + rDocShell.GetUndoManager()->AddUndoAction( pAction ); + } + + delete pOldUndoDoc; // if not used for undo + delete pNewUndoDoc; + delete pUndoDPObj; + + if (bDone) + aModificator.SetDocumentModified(); + + if ( nErrId && !bApi ) + rDocShell.ErrorMessage( nErrId ); + + return bDone; +} + +//================================================================== +// +// Datenbank-Import... + +void ScDBDocFunc::UpdateImport( const String& rTarget, const String& rDBName, + const String& rTableName, const String& rStatement, BOOL bNative, + BYTE nType, const ::com::sun::star::uno::Reference< + ::com::sun::star::sdbc::XResultSet >& xResultSet, + const SbaSelectionList* pSelection ) +{ + // Target ist jetzt einfach der Bereichsname + + ScDocument* pDoc = rDocShell.GetDocument(); + ScDBCollection& rDBColl = *pDoc->GetDBCollection(); + ScDBData* pData = NULL; + ScImportParam aImportParam; + BOOL bFound = FALSE; + USHORT nCount = rDBColl.GetCount(); + for (USHORT i=0; i<nCount && !bFound; i++) + { + pData = rDBColl[i]; + if (pData->GetName() == rTarget) + bFound = TRUE; + } + if (!bFound) + { + InfoBox aInfoBox(rDocShell.GetActiveDialogParent(), + ScGlobal::GetRscString( STR_TARGETNOTFOUND ) ); + aInfoBox.Execute(); + return; + } + + SCTAB nTab; + SCCOL nDummyCol; + SCROW nDummyRow; + pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow ); + pData->GetImportParam( aImportParam ); + + BOOL bSql = ( rStatement.Len() != 0 ); + + aImportParam.aDBName = rDBName; + aImportParam.bSql = bSql; + aImportParam.aStatement = bSql ? rStatement : rTableName; + aImportParam.bNative = bNative; + aImportParam.nType = nType; + aImportParam.bImport = TRUE; + BOOL bContinue = DoImport( nTab, aImportParam, xResultSet, pSelection, TRUE ); + + // DB-Operationen wiederholen + + ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); + if (pViewSh) + { + ScRange aRange; + pData->GetArea(aRange); + pViewSh->MarkRange(aRange); // selektieren + + if ( bContinue ) // #41905# Fehler beim Import -> Abbruch + { + // interne Operationen, wenn welche gespeichert + + if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() ) + pViewSh->RepeatDB(); + + // Pivottabellen die den Bereich als Quelldaten haben + + rDocShell.RefreshPivotTables(aRange); + } + } +} + + + + diff --git a/sc/source/ui/docshell/dbdocimp.cxx b/sc/source/ui/docshell/dbdocimp.cxx new file mode 100644 index 000000000000..17b07099a491 --- /dev/null +++ b/sc/source/ui/docshell/dbdocimp.cxx @@ -0,0 +1,720 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------- + +#include <comphelper/processfactory.hxx> +#include <comphelper/types.hxx> +#include <vcl/msgbox.hxx> +#include <tools/debug.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <sfx2/viewfrm.hxx> + +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdb/XCompletedExecution.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + + +#include "dbdocfun.hxx" +#include "docsh.hxx" +#include "globstr.hrc" +#include "scerrors.hxx" +#include "dbcolect.hxx" +#include "markdata.hxx" +#include "undodat.hxx" +#include "progress.hxx" +#include "patattr.hxx" +#include "docpool.hxx" +#include "attrib.hxx" +#include "dbdocutl.hxx" +#include "editable.hxx" +#include "hints.hxx" + +using namespace com::sun::star; + +#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet" +#define SC_SERVICE_INTHANDLER "com.sun.star.sdb.InteractionHandler" + +//! move to a header file? +#define SC_DBPROP_DATASOURCENAME "DataSourceName" +#define SC_DBPROP_COMMAND "Command" +#define SC_DBPROP_COMMANDTYPE "CommandType" +#define SC_DBPROP_SELECTION "Selection" +#define SC_DBPROP_CURSOR "Cursor" + +// static +void ScDBDocFunc::ShowInBeamer( const ScImportParam& rParam, SfxViewFrame* pFrame ) +{ + // called after opening the database beamer + + if ( !pFrame || !rParam.bImport ) + return; + + uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame()->GetFrameInterface(); + uno::Reference<frame::XDispatchProvider> xDP(xFrame, uno::UNO_QUERY); + + uno::Reference<frame::XFrame> xBeamerFrame = xFrame->findFrame( + rtl::OUString::createFromAscii("_beamer"), + frame::FrameSearchFlag::CHILDREN); + if (xBeamerFrame.is()) + { + uno::Reference<frame::XController> xController = xBeamerFrame->getController(); + uno::Reference<view::XSelectionSupplier> xControllerSelection(xController, uno::UNO_QUERY); + if (xControllerSelection.is()) + { + sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND : + ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY : + sdb::CommandType::TABLE ); + + ::svx::ODataAccessDescriptor aSelection; + aSelection.setDataSource(rtl::OUString( rParam.aDBName )); + aSelection[svx::daCommand] <<= rtl::OUString( rParam.aStatement ); + aSelection[svx::daCommandType] <<= nType; + + xControllerSelection->select(uno::makeAny(aSelection.createPropertyValueSequence())); + } + else + { + DBG_ERROR("no selection supplier in the beamer!"); + } + } +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::DoImportUno( const ScAddress& rPos, + const uno::Sequence<beans::PropertyValue>& aArgs ) +{ + BOOL bDone = FALSE; + + ScImportParam aImParam; + aImParam.nCol1 = aImParam.nCol2 = rPos.Col(); + aImParam.nRow1 = aImParam.nRow2 = rPos.Row(); + aImParam.bImport = TRUE; + + uno::Reference<sdbc::XResultSet> xResSet; + uno::Sequence<uno::Any> aSelection; + + rtl::OUString aStrVal; + const beans::PropertyValue* pPropArray = aArgs.getConstArray(); + long nPropCount = aArgs.getLength(); + long i; + for (i = 0; i < nPropCount; i++) + { + const beans::PropertyValue& rProp = pPropArray[i]; + String aPropName = rProp.Name; + + if ( aPropName.EqualsAscii( SC_DBPROP_DATASOURCENAME )) + { + if ( rProp.Value >>= aStrVal ) + aImParam.aDBName = aStrVal; + } + else if ( aPropName.EqualsAscii( SC_DBPROP_COMMAND )) + { + if ( rProp.Value >>= aStrVal ) + aImParam.aStatement = aStrVal; + } + else if ( aPropName.EqualsAscii( SC_DBPROP_COMMANDTYPE )) + { + sal_Int32 nType = 0; + if ( rProp.Value >>= nType ) + { + aImParam.bSql = ( nType == sdb::CommandType::COMMAND ); + aImParam.nType = sal::static_int_cast<BYTE>( ( nType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable ); + // nType is ignored if bSql is set + } + } + else if ( aPropName.EqualsAscii( SC_DBPROP_SELECTION )) + { + rProp.Value >>= aSelection; + } + else if ( aPropName.EqualsAscii( SC_DBPROP_CURSOR )) + { + rProp.Value >>= xResSet; + } + } + + SbaSelectionList aList; + long nSelLen = aSelection.getLength(); + for (i = 0; i < nSelLen; i++) + { + sal_Int32 nEntry = 0; + if ( aSelection[i] >>= nEntry ) + aList.Insert( (void*)nEntry, LIST_APPEND ); + } + + BOOL bAddrInsert = FALSE; //!??? + if ( bAddrInsert ) + { + bDone = DoImport( rPos.Tab(), aImParam, xResSet, &aList, TRUE, bAddrInsert ); + } + else + { + // create database range + //! merge this with SID_SBA_IMPORT execute in docsh4.cxx + + ScDBData* pDBData = rDocShell.GetDBData( ScRange(rPos), SC_DB_IMPORT, FALSE ); + DBG_ASSERT(pDBData, "can't create DB data"); + String sTarget = pDBData->GetName(); + + //! change UpdateImport to use only one of rTableName, rStatement + + String aTableName, aStatement; + if ( aImParam.bSql ) + aStatement = aImParam.aStatement; + else + aTableName = aImParam.aStatement; + + UpdateImport( sTarget, aImParam.aDBName, aTableName, aStatement, + aImParam.bNative, aImParam.nType, xResSet, &aList ); + bDone = TRUE; + } + + return bDone; +} + +// ----------------------------------------------------------------- + +BOOL ScDBDocFunc::DoImport( SCTAB nTab, const ScImportParam& rParam, + const uno::Reference< sdbc::XResultSet >& xResultSet, + const SbaSelectionList* pSelection, BOOL bRecord, BOOL bAddrInsert ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScDBData* pDBData = 0; + if ( !bAddrInsert ) + { + pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1, + rParam.nCol2, rParam.nRow2 ); + if (!pDBData) + { + DBG_ERROR( "DoImport: no DBData" ); + return FALSE; + } + } + + Window* pWaitWin = rDocShell.GetActiveDialogParent(); + if (pWaitWin) + pWaitWin->EnterWait(); + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + BOOL bApi = FALSE; //! pass as argument + BOOL bTruncated = FALSE; // for warning + USHORT nErrStringId = 0; + String aErrorMessage; + + SCCOL nCol = rParam.nCol1; + SCROW nRow = rParam.nRow1; + SCCOL nEndCol = nCol; // end of resulting database area + SCROW nEndRow = nRow; + long i; + + BOOL bDoSelection = FALSE; + BOOL bRealSelection = FALSE; // TRUE if not everything is selected + ULONG nListPos = 0; + ULONG nRowsRead = 0; + ULONG nListCount = 0; + + // -1 is special + if ( pSelection && pSelection->Count() && (long)pSelection->GetObject(0) != -1L ) + { + bDoSelection = TRUE; + nListCount = pSelection->Count(); + } + + // ImportDoc - also used for Redo + ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO ); + pImportDoc->InitUndo( pDoc, nTab, nTab ); + ScColumn::bDoubleAlloc = TRUE; + + // + // get data from database into import document + // + + try + { + // progress bar + // only text (title is still needed, for the cancel button) + ScProgress aProgress( &rDocShell, ScGlobal::GetRscString(STR_UNDO_IMPORTDATA), 0 ); + USHORT nInserted = 0; + + uno::Reference<sdbc::XRowSet> xRowSet = uno::Reference<sdbc::XRowSet>( + xResultSet, uno::UNO_QUERY ); + sal_Bool bDispose = sal_False; + if ( !xRowSet.is() ) + { + bDispose = sal_True; + xRowSet = uno::Reference<sdbc::XRowSet>( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRowProp.is(), "can't get RowSet" ); + if ( xRowProp.is() ) + { + // + // set source parameters + // + + sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND : + ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY : + sdb::CommandType::TABLE ); + uno::Any aAny; + + aAny <<= rtl::OUString( rParam.aDBName ); + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_DATASOURCENAME), aAny ); + + aAny <<= rtl::OUString( rParam.aStatement ); + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMAND), aAny ); + + aAny <<= nType; + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMANDTYPE), aAny ); + + uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY ); + if ( xExecute.is() ) + { + uno::Reference<task::XInteractionHandler> xHandler( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii( SC_SERVICE_INTHANDLER ) ), + uno::UNO_QUERY); + xExecute->executeWithCompletion( xHandler ); + } + else + xRowSet->execute(); + } + } + if ( xRowSet.is() ) + { + // + // get column descriptions + // + + long nColCount = 0; + uno::Reference<sdbc::XResultSetMetaData> xMeta; + uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY ); + if ( xMetaSupp.is() ) + xMeta = xMetaSupp->getMetaData(); + if ( xMeta.is() ) + nColCount = xMeta->getColumnCount(); // this is the number of real columns + + if ( rParam.nCol1 + nColCount - 1 > MAXCOL ) + { + nColCount = 0; + //! error message + } + + uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY ); + if ( nColCount > 0 && xRow.is() ) + { + nEndCol = (SCCOL)( rParam.nCol1 + nColCount - 1 ); + + uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types + uno::Sequence<sal_Bool> aColCurr( nColCount ); // currency flag is not in types + sal_Int32* pTypeArr = aColTypes.getArray(); + sal_Bool* pCurrArr = aColCurr.getArray(); + for (i=0; i<nColCount; i++) + { + pTypeArr[i] = xMeta->getColumnType( i+1 ); + pCurrArr[i] = xMeta->isCurrency( i+1 ); + } + + if ( !bAddrInsert ) // read column names + { + nCol = rParam.nCol1; + for (i=0; i<nColCount; i++) + { + pImportDoc->SetString( nCol, nRow, nTab, + xMeta->getColumnLabel( i+1 ) ); + ++nCol; + } + ++nRow; + } + + BOOL bEnd = FALSE; + if ( !bDoSelection ) + xRowSet->beforeFirst(); + while ( !bEnd ) + { + // skip rows that are not selected + if ( !bDoSelection ) + { + if ( (bEnd = !xRowSet->next()) == FALSE ) + ++nRowsRead; + } + else + { + if (nListPos < nListCount) + { + ULONG nNextRow = (ULONG) pSelection->GetObject(nListPos); + if ( nRowsRead+1 < nNextRow ) + bRealSelection = TRUE; + bEnd = !xRowSet->absolute(nRowsRead = nNextRow); + ++nListPos; + } + else + { + bRealSelection = xRowSet->next(); + bEnd = TRUE; // more data available but not used + } + } + + if ( !bEnd ) + { + if ( ValidRow(nRow) ) + { + nCol = rParam.nCol1; + for (i=0; i<nColCount; i++) + { + ScDatabaseDocUtil::PutData( pImportDoc, nCol, nRow, nTab, + xRow, i+1, pTypeArr[i], pCurrArr[i] ); + ++nCol; + } + nEndRow = nRow; + ++nRow; + + // progress bar + + ++nInserted; + if (!(nInserted & 15)) + { + String aPict = ScGlobal::GetRscString( STR_PROGRESS_IMPORT ); + String aText = aPict.GetToken(0,'#'); + aText += String::CreateFromInt32( nInserted ); + aText += aPict.GetToken(1,'#'); + + if (!aProgress.SetStateText( 0, aText )) // stopped by user? + { + bEnd = TRUE; + bSuccess = FALSE; + nErrStringId = STR_DATABASE_ABORTED; + } + } + } + else // past the end of the spreadsheet + { + bEnd = TRUE; // don't continue + bTruncated = TRUE; // warning flag + } + } + } + + bSuccess = TRUE; + } + + if ( bDispose ) + ::comphelper::disposeComponent( xRowSet ); + } + } + catch ( sdbc::SQLException& rError ) + { + aErrorMessage = rError.Message; + } + catch ( uno::Exception& ) + { + DBG_ERROR("Unexpected exception in database"); + } + + ScColumn::bDoubleAlloc = FALSE; + pImportDoc->DoColResize( nTab, rParam.nCol1,nEndCol, 0 ); + + // + // test for cell protection + // + + BOOL bKeepFormat = !bAddrInsert && pDBData->IsKeepFmt(); + BOOL bMoveCells = !bAddrInsert && pDBData->IsDoSize(); + SCCOL nFormulaCols = 0; // columns to be filled with formulas + if (bMoveCells && nEndCol == rParam.nCol2) + { + // if column count changes, formulas would become invalid anyway + // -> only set nFormulaCols for unchanged column count + + SCCOL nTestCol = rParam.nCol2 + 1; // right of the data + SCROW nTestRow = rParam.nRow1 + 1; // below the title row + while ( nTestCol <= MAXCOL && + pDoc->GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA ) + ++nTestCol, ++nFormulaCols; + } + + if (bSuccess) + { + // old and new range editable? + ScEditableTester aTester; + aTester.TestBlock( pDoc, nTab, rParam.nCol1,rParam.nRow1,rParam.nCol2,rParam.nRow2 ); + aTester.TestBlock( pDoc, nTab, rParam.nCol1,rParam.nRow1,nEndCol,nEndRow ); + if ( !aTester.IsEditable() ) + { + nErrStringId = aTester.GetMessageId(); + bSuccess = FALSE; + } + else if ( pDoc->GetChangeTrack() != NULL ) + { + nErrStringId = STR_PROTECTIONERR; + bSuccess = FALSE; + } + } + + if ( bSuccess && bMoveCells ) + { + ScRange aOld( rParam.nCol1, rParam.nRow1, nTab, + rParam.nCol2+nFormulaCols, rParam.nRow2, nTab ); + ScRange aNew( rParam.nCol1, rParam.nRow1, nTab, + nEndCol+nFormulaCols, nEndRow, nTab ); + if (!pDoc->CanFitBlock( aOld, aNew )) + { + nErrStringId = STR_MSSG_DOSUBTOTALS_2; // can't insert cells + bSuccess = FALSE; + } + } + + // + // copy data from import doc into real document + // + + if ( bSuccess ) + { + if (bKeepFormat) + { + // keep formatting of title and first data row from the document + // CopyToDocument also copies styles, Apply... needs separate calls + + SCCOL nMinEndCol = Min( rParam.nCol2, nEndCol ); // not too much + nMinEndCol = sal::static_int_cast<SCCOL>( nMinEndCol + nFormulaCols ); // only if column count unchanged + pImportDoc->DeleteAreaTab( 0,0, MAXCOL,MAXROW, nTab, IDF_ATTRIB ); + pDoc->CopyToDocument( rParam.nCol1, rParam.nRow1, nTab, + nMinEndCol, rParam.nRow1, nTab, + IDF_ATTRIB, FALSE, pImportDoc ); + + SCROW nDataStartRow = rParam.nRow1+1; + for (SCCOL nCopyCol=rParam.nCol1; nCopyCol<=nMinEndCol; nCopyCol++) + { + const ScPatternAttr* pSrcPattern = pDoc->GetPattern( + nCopyCol, nDataStartRow, nTab ); + pImportDoc->ApplyPatternAreaTab( nCopyCol, nDataStartRow, nCopyCol, nEndRow, + nTab, *pSrcPattern ); + const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet(); + if (pStyle) + pImportDoc->ApplyStyleAreaTab( nCopyCol, nDataStartRow, nCopyCol, nEndRow, + nTab, *pStyle ); + } + } + + // don't set cell protection attribute if table is protected + if (pDoc->IsTabProtected(nTab)) + { + ScPatternAttr aPattern(pImportDoc->GetPool()); + aPattern.GetItemSet().Put( ScProtectionAttr( FALSE,FALSE,FALSE,FALSE ) ); + pImportDoc->ApplyPatternAreaTab( 0,0,MAXCOL,MAXROW, nTab, aPattern ); + } + + // + // copy old data for undo + // + + SCCOL nUndoEndCol = Max( nEndCol, rParam.nCol2 ); // rParam = old end + SCROW nUndoEndRow = Max( nEndRow, rParam.nRow2 ); + + ScDocument* pUndoDoc = NULL; + ScDBData* pUndoDBData = NULL; + if ( bRecord ) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab ); + + if ( !bAddrInsert ) + pUndoDBData = new ScDBData( *pDBData ); + } + + ScMarkData aNewMark; + aNewMark.SelectOneTable( nTab ); + + if (bRecord) + { + // do not touch notes (ScUndoImportData does not support drawing undo) + sal_uInt16 nCopyFlags = IDF_ALL & ~IDF_NOTE; + + // nFormulaCols is set only if column count is unchanged + pDoc->CopyToDocument( rParam.nCol1, rParam.nRow1, nTab, + nEndCol+nFormulaCols, nEndRow, nTab, + nCopyFlags, FALSE, pUndoDoc ); + if ( rParam.nCol2 > nEndCol ) + pDoc->CopyToDocument( nEndCol+1, rParam.nRow1, nTab, + nUndoEndCol, nUndoEndRow, nTab, + nCopyFlags, FALSE, pUndoDoc ); + if ( rParam.nRow2 > nEndRow ) + pDoc->CopyToDocument( rParam.nCol1, nEndRow+1, nTab, + nUndoEndCol+nFormulaCols, nUndoEndRow, nTab, + nCopyFlags, FALSE, pUndoDoc ); + } + + // + // move new data + // + + if (bMoveCells) + { + // clear only the range without the formulas, + // so the formula title and first row are preserved + + ScRange aDelRange( rParam.nCol1, rParam.nRow1, nTab, + rParam.nCol2, rParam.nRow2, nTab ); + pDoc->DeleteAreaTab( aDelRange, IDF_ALL & ~IDF_NOTE ); // ohne die Formeln + + ScRange aOld( rParam.nCol1, rParam.nRow1, nTab, + rParam.nCol2+nFormulaCols, rParam.nRow2, nTab ); + ScRange aNew( rParam.nCol1, rParam.nRow1, nTab, + nEndCol+nFormulaCols, nEndRow, nTab ); + pDoc->FitBlock( aOld, aNew, FALSE ); // Formeln nicht loeschen + } + else if ( nEndCol < rParam.nCol2 ) // DeleteArea calls PutInOrder + pDoc->DeleteArea( nEndCol+1, rParam.nRow1, rParam.nCol2, rParam.nRow2, + aNewMark, IDF_CONTENTS & ~IDF_NOTE ); + + // CopyToDocument doesn't remove contents + pDoc->DeleteAreaTab( rParam.nCol1, rParam.nRow1, nEndCol, nEndRow, nTab, IDF_CONTENTS & ~IDF_NOTE ); + + // #41216# remove each column from ImportDoc after copying to reduce memory usage + BOOL bOldAutoCalc = pDoc->GetAutoCalc(); + pDoc->SetAutoCalc( FALSE ); // outside of the loop + for (SCCOL nCopyCol = rParam.nCol1; nCopyCol <= nEndCol; nCopyCol++) + { + pImportDoc->CopyToDocument( nCopyCol, rParam.nRow1, nTab, nCopyCol, nEndRow, nTab, + IDF_ALL, FALSE, pDoc ); + pImportDoc->DeleteAreaTab( nCopyCol, rParam.nRow1, nCopyCol, nEndRow, nTab, IDF_CONTENTS ); + pImportDoc->DoColResize( nTab, nCopyCol, nCopyCol, 0 ); + } + pDoc->SetAutoCalc( bOldAutoCalc ); + + if (nFormulaCols > 0) // copy formulas + { + if (bKeepFormat) // formats for formulas + pImportDoc->CopyToDocument( nEndCol+1, rParam.nRow1, nTab, + nEndCol+nFormulaCols, nEndRow, nTab, + IDF_ATTRIB, FALSE, pDoc ); + // fill formulas + ScMarkData aMark; + aMark.SelectOneTable(nTab); + pDoc->Fill( nEndCol+1, rParam.nRow1+1, nEndCol+nFormulaCols, rParam.nRow1+1, + aMark, nEndRow-rParam.nRow1-1, FILL_TO_BOTTOM, FILL_SIMPLE ); + } + + // if new range is smaller, clear old contents + + if (!bMoveCells) // move has happened above + { + if ( rParam.nCol2 > nEndCol ) + pDoc->DeleteArea( nEndCol+1, rParam.nRow1, rParam.nCol2, rParam.nRow2, + aNewMark, IDF_CONTENTS ); + if ( rParam.nRow2 > nEndRow ) + pDoc->DeleteArea( rParam.nCol1, nEndRow+1, rParam.nCol2, rParam.nRow2, + aNewMark, IDF_CONTENTS ); + } + + if( !bAddrInsert ) // update database range + { + pDBData->SetImportParam( rParam ); + pDBData->SetHeader( TRUE ); + pDBData->SetByRow( TRUE ); + pDBData->SetArea( nTab, rParam.nCol1,rParam.nRow1, nEndCol,nEndRow ); + pDBData->SetImportSelection( bRealSelection ); + pDoc->CompileDBFormula(); + } + + if (bRecord) + { + ScDocument* pRedoDoc = pImportDoc; + pImportDoc = NULL; + + if (nFormulaCols > 0) // include filled formulas for redo + pDoc->CopyToDocument( rParam.nCol1, rParam.nRow1, nTab, + nEndCol+nFormulaCols, nEndRow, nTab, + IDF_ALL & ~IDF_NOTE, FALSE, pRedoDoc ); + + ScDBData* pRedoDBData = pDBData ? new ScDBData( *pDBData ) : NULL; + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoImportData( &rDocShell, nTab, + rParam, nUndoEndCol, nUndoEndRow, + nFormulaCols, + pUndoDoc, pRedoDoc, pUndoDBData, pRedoDBData ) ); + } + + pDoc->SetDirty(); + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID ); + aModificator.SetDocumentModified(); + + ScDBRangeRefreshedHint aHint( rParam ); + pDoc->BroadcastUno( aHint ); + + if (pWaitWin) + pWaitWin->LeaveWait(); + + if ( bTruncated && !bApi ) // show warning + ErrorHandler::HandleError(SCWARN_IMPORT_RANGE_OVERFLOW); + } + else if ( !bApi ) + { + if (pWaitWin) + pWaitWin->LeaveWait(); + + if (!aErrorMessage.Len()) + { + if (!nErrStringId) + nErrStringId = STR_MSSG_IMPORTDATA_0; + aErrorMessage = ScGlobal::GetRscString( nErrStringId ); + } + InfoBox aInfoBox( rDocShell.GetActiveDialogParent(), aErrorMessage ); + aInfoBox.Execute(); + } + + delete pImportDoc; + + return bSuccess; +} + + + + diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx new file mode 100644 index 000000000000..cd28daa99401 --- /dev/null +++ b/sc/source/ui/docshell/docfunc.cxx @@ -0,0 +1,4630 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> + +#include <sfx2/app.hxx> +#include <editeng/editobj.hxx> +#include <sfx2/linkmgr.hxx> +#include <svx/svdundo.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/printer.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/sound.hxx> +#include <vcl/virdev.hxx> +#include <vcl/waitobj.hxx> +#include <svl/zforlist.hxx> +#include <svl/PasswordHelper.hxx> + +#include <list> + +#include "docfunc.hxx" + +#include "sc.hrc" + +#include "arealink.hxx" +#include "attrib.hxx" +#include "dociter.hxx" +#include "autoform.hxx" +#include "cell.hxx" +#include "detdata.hxx" +#include "detfunc.hxx" +#include "docpool.hxx" +#include "docsh.hxx" +#include "drwlayer.hxx" +#include "editutil.hxx" +#include "globstr.hrc" +//CHINA001 #include "namecrea.hxx" // NAME_TOP etc. +#include "olinetab.hxx" +#include "patattr.hxx" +#include "rangenam.hxx" +#include "rangeutl.hxx" +#include "refundo.hxx" +#include "scresid.hxx" +#include "stlpool.hxx" +#include "stlsheet.hxx" +#include "tablink.hxx" +#include "tabvwsh.hxx" +#include "uiitems.hxx" +#include "undoblk.hxx" +#include "undocell.hxx" +#include "undodraw.hxx" +#include "undotab.hxx" +#include "waitoff.hxx" +#include "sizedev.hxx" +#include "scmod.hxx" +#include "inputhdl.hxx" +#include "inputwin.hxx" +#include "editable.hxx" +#include "compiler.hxx" +#include "scui_def.hxx" //CHINA001 +#include "tabprotection.hxx" +#include "clipparam.hxx" + +#include <memory> + +using namespace com::sun::star; +using ::com::sun::star::uno::Sequence; + +// STATIC DATA ----------------------------------------------------------- + +//======================================================================== + +IMPL_LINK( ScDocFunc, NotifyDrawUndo, SdrUndoAction*, pUndoAction ) +{ + // #i101118# if drawing layer collects the undo actions, add it there + ScDrawLayer* pDrawLayer = rDocShell.GetDocument()->GetDrawLayer(); + if( pDrawLayer && pDrawLayer->IsRecording() ) + pDrawLayer->AddCalcUndo( pUndoAction ); + else + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDraw( pUndoAction, &rDocShell ) ); + rDocShell.SetDrawModified(); + + // the affected sheet isn't known, so all stream positions are invalidated + ScDocument* pDoc = rDocShell.GetDocument(); + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + return 0; +} + +//------------------------------------------------------------------------ + +// Zeile ueber dem Range painten (fuer Linien nach AdjustRowHeight) + +void lcl_PaintAbove( ScDocShell& rDocShell, const ScRange& rRange ) +{ + SCROW nRow = rRange.aStart.Row(); + if ( nRow > 0 ) + { + SCTAB nTab = rRange.aStart.Tab(); //! alle? + --nRow; + rDocShell.PostPaint( ScRange(0,nRow,nTab, MAXCOL,nRow,nTab), PAINT_GRID ); + } +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::AdjustRowHeight( const ScRange& rRange, BOOL bPaint ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if ( pDoc->IsImportingXML() ) + { + // for XML import, all row heights are updated together after importing + return FALSE; + } + if ( !pDoc->IsAdjustHeightEnabled() ) + { + return FALSE; + } + + SCTAB nTab = rRange.aStart.Tab(); + SCROW nStartRow = rRange.aStart.Row(); + SCROW nEndRow = rRange.aEnd.Row(); + + ScSizeDeviceProvider aProv( &rDocShell ); + Fraction aOne(1,1); + + BOOL bChanged = pDoc->SetOptimalHeight( nStartRow, nEndRow, nTab, 0, aProv.GetDevice(), + aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, FALSE ); + + if ( bPaint && bChanged ) + rDocShell.PostPaint( 0, nStartRow, nTab, MAXCOL, MAXROW, nTab, + PAINT_GRID | PAINT_LEFT ); + + return bChanged; +} + + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::DetectiveAddPred(const ScAddress& rPos) +{ + ScDocShellModificator aModificator( rDocShell ); + + rDocShell.MakeDrawLayer(); + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + SCCOL nCol = rPos.Col(); + SCROW nRow = rPos.Row(); + SCTAB nTab = rPos.Tab(); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).ShowPred( nCol, nRow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED ); + pDoc->AddDetectiveOperation( aOperation ); + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveDelPred(const ScAddress& rPos) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo(pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + if (!pModel) + return FALSE; + + ScDocShellModificator aModificator( rDocShell ); + + SCCOL nCol = rPos.Col(); + SCROW nRow = rPos.Row(); + SCTAB nTab = rPos.Tab(); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).DeletePred( nCol, nRow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED ); + pDoc->AddDetectiveOperation( aOperation ); + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveAddSucc(const ScAddress& rPos) +{ + ScDocShellModificator aModificator( rDocShell ); + + rDocShell.MakeDrawLayer(); + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo(pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + SCCOL nCol = rPos.Col(); + SCROW nRow = rPos.Row(); + SCTAB nTab = rPos.Tab(); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).ShowSucc( nCol, nRow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC ); + pDoc->AddDetectiveOperation( aOperation ); + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveDelSucc(const ScAddress& rPos) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + if (!pModel) + return FALSE; + + ScDocShellModificator aModificator( rDocShell ); + + SCCOL nCol = rPos.Col(); + SCROW nRow = rPos.Row(); + SCTAB nTab = rPos.Tab(); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).DeleteSucc( nCol, nRow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC ); + pDoc->AddDetectiveOperation( aOperation ); + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveAddError(const ScAddress& rPos) +{ + ScDocShellModificator aModificator( rDocShell ); + + rDocShell.MakeDrawLayer(); + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + SCCOL nCol = rPos.Col(); + SCROW nRow = rPos.Row(); + SCTAB nTab = rPos.Tab(); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).ShowError( nCol, nRow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR ); + pDoc->AddDetectiveOperation( aOperation ); + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, &aOperation ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveMarkInvalid(SCTAB nTab) +{ + ScDocShellModificator aModificator( rDocShell ); + + rDocShell.MakeDrawLayer(); + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + + Window* pWaitWin = rDocShell.GetActiveDialogParent(); + if (pWaitWin) + pWaitWin->EnterWait(); + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bOverflow; + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).MarkInvalid( bOverflow ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (pWaitWin) + pWaitWin->LeaveWait(); + if (bDone) + { + if (pUndo && bUndo) + { + pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETINVALID ) ); + rDocShell.GetUndoManager()->AddUndoAction( pUndo ); + } + aModificator.SetDocumentModified(); + if ( bOverflow ) + { + InfoBox( NULL, + ScGlobal::GetRscString( STR_DETINVALID_OVERFLOW ) ).Execute(); + } + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveDelAll(SCTAB nTab) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + if (!pModel) + return FALSE; + + ScDocShellModificator aModificator( rDocShell ); + + if (bUndo) + pModel->BeginCalcUndo(); + BOOL bDone = ScDetectiveFunc( pDoc,nTab ).DeleteAll( SC_DET_DETECTIVE ); + SdrUndoGroup* pUndo = NULL; + if (bUndo) + pUndo = pModel->GetCalcUndo(); + if (bDone) + { + ScDetOpList* pOldList = pDoc->GetDetOpList(); + ScDetOpList* pUndoList = NULL; + if (bUndo) + pUndoList = pOldList ? new ScDetOpList(*pOldList) : NULL; + + pDoc->ClearDetectiveOperations(); + + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDetective( &rDocShell, pUndo, NULL, pUndoList ) ); + } + aModificator.SetDocumentModified(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_DETECTIVE_REFRESH ); + } + else + delete pUndo; + + return bDone; +} + +BOOL ScDocFunc::DetectiveRefresh( BOOL bAutomatic ) +{ + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo (pDoc->IsUndoEnabled()); + ScDetOpList* pList = pDoc->GetDetOpList(); + if ( pList && pList->Count() ) + { + rDocShell.MakeDrawLayer(); + ScDrawLayer* pModel = pDoc->GetDrawLayer(); + if (bUndo) + pModel->BeginCalcUndo(); + + // Loeschen auf allen Tabellen + + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + ScDetectiveFunc( pDoc,nTab ).DeleteAll( SC_DET_ARROWS ); // don't remove circles + + // Wiederholen + + USHORT nCount = pList->Count(); + for (USHORT i=0; i<nCount; i++) + { + ScDetOpData* pData = (*pList)[i]; + if (pData) + { + ScAddress aPos = pData->GetPos(); + ScDetectiveFunc aFunc( pDoc, aPos.Tab() ); + SCCOL nCol = aPos.Col(); + SCROW nRow = aPos.Row(); + switch (pData->GetOperation()) + { + case SCDETOP_ADDSUCC: + aFunc.ShowSucc( nCol, nRow ); + break; + case SCDETOP_DELSUCC: + aFunc.DeleteSucc( nCol, nRow ); + break; + case SCDETOP_ADDPRED: + aFunc.ShowPred( nCol, nRow ); + break; + case SCDETOP_DELPRED: + aFunc.DeletePred( nCol, nRow ); + break; + case SCDETOP_ADDERROR: + aFunc.ShowError( nCol, nRow ); + break; + default: + DBG_ERROR("falsche Op bei DetectiveRefresh"); + } + } + } + + if (bUndo) + { + SdrUndoGroup* pUndo = pModel->GetCalcUndo(); + if (pUndo) + { + pUndo->SetComment( ScGlobal::GetRscString( STR_UNDO_DETREFRESH ) ); + // wenn automatisch, an letzte Aktion anhaengen + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDraw( pUndo, &rDocShell ), + bAutomatic ); + } + } + rDocShell.SetDrawModified(); + bDone = TRUE; + } + return bDone; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::DeleteContents( const ScMarkData& rMark, USHORT nFlags, + BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) + { + DBG_ERROR("ScDocFunc::DeleteContents ohne Markierung"); + return FALSE; + } + + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScEditableTester aTester( pDoc, rMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + ScRange aMarkRange; + BOOL bSimple = FALSE; + + ScMarkData aMultiMark = rMark; + aMultiMark.SetMarking(FALSE); // fuer MarkToMulti + + ScDocument* pUndoDoc = NULL; + BOOL bMulti = !bSimple && aMultiMark.IsMultiMarked(); + if (!bSimple) + { + aMultiMark.MarkToMulti(); + aMultiMark.GetMultiMarkArea( aMarkRange ); + } + ScRange aExtendedRange(aMarkRange); + if (!bSimple) + { + if ( pDoc->ExtendMerge( aExtendedRange, TRUE ) ) + bMulti = FALSE; + } + + // keine Objekte auf geschuetzten Tabellen + BOOL bObjects = FALSE; + if ( nFlags & IDF_OBJECTS ) + { + bObjects = TRUE; + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (aMultiMark.GetTableSelect(nTab) && pDoc->IsTabProtected(nTab)) + bObjects = FALSE; + } + + USHORT nExtFlags = 0; // extra flags are needed only if attributes are deleted + if ( nFlags & IDF_ATTRIB ) + rDocShell.UpdatePaintExt( nExtFlags, aMarkRange ); + + // Reihenfolge: + // 1) BeginDrawUndo + // 2) Objekte loeschen (DrawUndo wird gefuellt) + // 3) Inhalte fuer Undo kopieren und Undo-Aktion anlegen + // 4) Inhalte loeschen + + bool bDrawUndo = bObjects || (nFlags & IDF_NOTE); + if (bRecord && bDrawUndo) + pDoc->BeginDrawUndo(); + + if (bObjects) + { + if (bMulti) + pDoc->DeleteObjectsInSelection( aMultiMark ); + else + pDoc->DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), + aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), + aMultiMark ); + } + + if ( bRecord ) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, aMarkRange.aStart.Tab(), aMarkRange.aEnd.Tab() ); + + // bei "Format/Standard" alle Attribute kopieren, weil CopyToDocument + // nur mit IDF_HARDATTR zu langsam ist: + USHORT nUndoDocFlags = nFlags; + if (nFlags & IDF_ATTRIB) + nUndoDocFlags |= IDF_ATTRIB; + if (nFlags & IDF_EDITATTR) // Edit-Engine-Attribute + nUndoDocFlags |= IDF_STRING; // -> Zellen werden geaendert + if (nFlags & IDF_NOTE) + nUndoDocFlags |= IDF_CONTENTS; // #68795# copy all cells with their notes + // note captions are handled in drawing undo + nUndoDocFlags |= IDF_NOCAPTIONS; + pDoc->CopyToDocument( aExtendedRange, nUndoDocFlags, bMulti, pUndoDoc, &aMultiMark ); + } + +//! HideAllCursors(); // falls Zusammenfassung aufgehoben wird + if (bSimple) + pDoc->DeleteArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), + aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), + aMultiMark, nFlags ); + else + { + pDoc->DeleteSelection( nFlags, aMultiMark ); +// aMultiMark.MarkToSimple(); + } + + // add undo action after drawing undo is complete (objects and note captions) + if( bRecord ) + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDeleteContents( &rDocShell, aMultiMark, aExtendedRange, + pUndoDoc, bMulti, nFlags, bDrawUndo ) ); + + if (!AdjustRowHeight( aExtendedRange )) + rDocShell.PostPaint( aExtendedRange, PAINT_GRID, nExtFlags ); + else if (nExtFlags & SC_PF_LINES) + lcl_PaintAbove( rDocShell, aExtendedRange ); // fuer Linien ueber dem Bereich + +// rDocShell.UpdateOle(GetViewData()); //! an der View? + aModificator.SetDocumentModified(); +//! CellContentChanged(); +//! ShowAllCursors(); + +#if 0 + //! muss an der View bleiben !!!! + if ( nFlags & IDF_ATTRIB ) + { + if ( nFlags & IDF_CONTENTS ) + ForgetFormatArea(); + else + StartFormatArea(); // Attribute loeschen ist auch Attributierung + } +#endif + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::TransliterateText( const ScMarkData& rMark, sal_Int32 nType, + BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScEditableTester aTester( pDoc, rMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + ScRange aMarkRange; + ScMarkData aMultiMark = rMark; + aMultiMark.SetMarking(FALSE); // for MarkToMulti + aMultiMark.MarkToMulti(); + aMultiMark.GetMultiMarkArea( aMarkRange ); + + if (bRecord) + { + SCTAB nStartTab = aMarkRange.aStart.Tab(); + SCTAB nTabCount = pDoc->GetTableCount(); + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nStartTab && rMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + ScRange aCopyRange = aMarkRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_CONTENTS, TRUE, pUndoDoc, &aMultiMark ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoTransliterate( &rDocShell, aMultiMark, pUndoDoc, nType ) ); + } + + pDoc->TransliterateText( aMultiMark, nType ); + + if (!AdjustRowHeight( aMarkRange )) + rDocShell.PostPaint( aMarkRange, PAINT_GRID ); + + aModificator.SetDocumentModified(); + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::SetNormalString( const ScAddress& rPos, const String& rText, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + ScDocument* pDoc = rDocShell.GetDocument(); + + BOOL bUndo(pDoc->IsUndoEnabled()); + ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + SCTAB* pTabs = NULL; + ScBaseCell** ppOldCells = NULL; + BOOL* pHasFormat = NULL; + ULONG* pOldFormats = NULL; + ScBaseCell* pDocCell = pDoc->GetCell( rPos ); + BOOL bEditDeleted = (pDocCell && pDocCell->GetCellType() == CELLTYPE_EDIT); + if (bUndo) + { + pTabs = new SCTAB[1]; + pTabs[0] = rPos.Tab(); + ppOldCells = new ScBaseCell*[1]; + ppOldCells[0] = pDocCell ? pDocCell->CloneWithoutNote( *pDoc ) : 0; + + pHasFormat = new BOOL[1]; + pOldFormats = new ULONG[1]; + const SfxPoolItem* pItem; + const ScPatternAttr* pPattern = pDoc->GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() ); + if ( SFX_ITEM_SET == pPattern->GetItemSet().GetItemState( + ATTR_VALUE_FORMAT,FALSE,&pItem) ) + { + pHasFormat[0] = TRUE; + pOldFormats[0] = ((const SfxUInt32Item*)pItem)->GetValue(); + } + else + pHasFormat[0] = FALSE; + } + + pDoc->SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText ); + + if (bUndo) + { + // wegen ChangeTracking darf UndoAction erst nach SetString angelegt werden + rDocShell.GetUndoManager()->AddUndoAction(new ScUndoEnterData( &rDocShell, rPos.Col(),rPos.Row(),rPos.Tab(), 1,pTabs, + ppOldCells, pHasFormat, pOldFormats, rText, NULL ) ); + } + + if ( bEditDeleted || pDoc->HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) ) + AdjustRowHeight( ScRange(rPos) ); + + rDocShell.PostPaintCell( rPos ); + aModificator.SetDocumentModified(); + + // #107160# notify input handler here the same way as in PutCell + if (bApi) + NotifyInputHandler( rPos ); + + return TRUE; +} + +BOOL ScDocFunc::PutCell( const ScAddress& rPos, ScBaseCell* pNewCell, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + BOOL bXMLLoading(pDoc->IsImportingXML()); + + // #i925#; it is not neccessary to test whether the cell is editable on loading a XML document + if (!bXMLLoading) + { + ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + pNewCell->Delete(); + return FALSE; + } + } + + BOOL bEditCell = ( pNewCell->GetCellType() == CELLTYPE_EDIT ); + ScBaseCell* pDocCell = pDoc->GetCell( rPos ); + BOOL bEditDeleted = (pDocCell && pDocCell->GetCellType() == CELLTYPE_EDIT); + BOOL bHeight = ( bEditDeleted || bEditCell || + pDoc->HasAttrib( ScRange(rPos), HASATTR_NEEDHEIGHT ) ); + + ScBaseCell* pUndoCell = (bUndo && pDocCell) ? pDocCell->CloneWithoutNote( *pDoc, rPos ) : 0; + ScBaseCell* pRedoCell = (bUndo && pNewCell) ? pNewCell->CloneWithoutNote( *pDoc, rPos ) : 0; + + pDoc->PutCell( rPos, pNewCell ); + + // wegen ChangeTracking darf UndoAction erst nach PutCell angelegt werden + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoPutCell( &rDocShell, rPos, pUndoCell, pRedoCell, bHeight ) ); + } + + if (bHeight) + AdjustRowHeight( ScRange(rPos) ); + + if (!bXMLLoading) + rDocShell.PostPaintCell( rPos ); + + aModificator.SetDocumentModified(); + + // #i925#; it is not neccessary to notify on loading a XML document + // #103934#; notify editline and cell in edit mode + if (bApi && !bXMLLoading) + NotifyInputHandler( rPos ); + + return TRUE; +} + +void ScDocFunc::NotifyInputHandler( const ScAddress& /* rPos */ ) +{ + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if ( pViewSh && pViewSh->GetViewData()->GetDocShell() == &rDocShell ) + { + ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(); + if ( pInputHdl ) + { + sal_Bool bIsEditMode(pInputHdl->IsEditMode()); + + // set modified if in editmode, because so the string is not set in the InputWindow like in the cell + // (the cell shows the same like the InputWindow) + if (bIsEditMode) + pInputHdl->SetModified(); + pViewSh->UpdateInputHandler(FALSE, !bIsEditMode); + } + } +} + + struct ScMyRememberItem + { + USHORT nIndex; + SfxItemSet aItemSet; + + ScMyRememberItem(const SfxItemSet& rItemSet, USHORT nTempIndex) : + nIndex(nTempIndex), aItemSet(rItemSet) {} + }; + + typedef ::std::list<ScMyRememberItem*> ScMyRememberItemList; + +BOOL ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, BOOL bInterpret, BOOL bApi ) +{ + // PutData ruft PutCell oder SetNormalString + + BOOL bRet = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + ScEditAttrTester aTester( &rEngine ); + BOOL bEditCell = aTester.NeedsObject(); + if ( bEditCell ) + { + // #i61702# With bLoseContent set, the content of rEngine isn't restored + // (used in loading XML, where after the removeActionLock call the API obejct's + // EditEngine isn't accessed again. + sal_Bool bLoseContent = pDoc->IsImportingXML(); + + sal_Bool bUpdateMode(rEngine.GetUpdateMode()); + if (bUpdateMode) + rEngine.SetUpdateMode(sal_False); + + ScMyRememberItemList aRememberItems; + ScMyRememberItem* pRememberItem = NULL; + + // All paragraph attributes must be removed before calling CreateTextObject, + // not only alignment, so the object doesn't contain the cell attributes as + // paragraph attributes. Before remove the attributes store they in a list to + // set they back to the EditEngine. + USHORT nCount = rEngine.GetParagraphCount(); + for (USHORT i=0; i<nCount; i++) + { + const SfxItemSet& rOld = rEngine.GetParaAttribs( i ); + if ( rOld.Count() ) + { + if ( !bLoseContent ) + { + pRememberItem = new ScMyRememberItem(rEngine.GetParaAttribs(i), i); + aRememberItems.push_back(pRememberItem); + } + rEngine.SetParaAttribs( i, SfxItemSet( *rOld.GetPool(), rOld.GetRanges() ) ); + } + } + + EditTextObject* pNewData = rEngine.CreateTextObject(); + bRet = PutCell( rPos, + new ScEditCell( pNewData, pDoc, rEngine.GetEditTextObjectPool() ), + bApi ); + delete pNewData; + + // Set the paragraph attributes back to the EditEngine. + if (!aRememberItems.empty()) + { +// ScMyRememberItem* pRememberItem = NULL; + ScMyRememberItemList::iterator aItr = aRememberItems.begin(); + while (aItr != aRememberItems.end()) + { + pRememberItem = *aItr; + rEngine.SetParaAttribs(pRememberItem->nIndex, pRememberItem->aItemSet); + delete pRememberItem; + aItr = aRememberItems.erase(aItr); + } + } + + // #i61702# if the content isn't accessed, there's no need to set the UpdateMode again + if ( bUpdateMode && !bLoseContent ) + rEngine.SetUpdateMode(sal_True); + } + else + { + String aText = rEngine.GetText(); + if ( bInterpret || !aText.Len() ) + bRet = SetNormalString( rPos, aText, bApi ); + else + bRet = PutCell( rPos, new ScStringCell( aText ), bApi ); + } + + if ( bRet && aTester.NeedsCellAttr() ) + { + const SfxItemSet& rEditAttr = aTester.GetAttribs(); + ScPatternAttr aPattern( pDoc->GetPool() ); + aPattern.GetFromEditItemSet( &rEditAttr ); + aPattern.DeleteUnchanged( pDoc->GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() ) ); + aPattern.GetItemSet().ClearItem( ATTR_HOR_JUSTIFY ); // wasn't removed above if no edit object + if ( aPattern.GetItemSet().Count() > 0 ) + { + ScMarkData aMark; + aMark.SelectTable( rPos.Tab(), TRUE ); + aMark.SetMarkArea( ScRange( rPos ) ); + ApplyAttributes( aMark, aPattern, TRUE, bApi ); + } + } + + return bRet; +} + + +ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) +{ + ScTokenArray* pCode = new ScTokenArray; + pCode->AddString( rText ); + if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && (rFormulaNmsp.Len() > 0) ) + pCode->AddString( rFormulaNmsp ); + return pCode; +} + + +ScBaseCell* ScDocFunc::InterpretEnglishString( const ScAddress& rPos, + const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + ScBaseCell* pNewCell = NULL; + + if ( rText.Len() > 1 && rText.GetChar(0) == '=' ) + { + ScTokenArray* pCode; + if ( pDoc->IsImportingXML() ) + { // temporary formula string as string tokens + pCode = lcl_ScDocFunc_CreateTokenArrayXML( rText, rFormulaNmsp, eGrammar ); + pDoc->IncXMLImportedFormulaCount( rText.Len() ); + } + else + { + ScCompiler aComp( pDoc, rPos ); + aComp.SetGrammar(eGrammar); + pCode = aComp.CompileString( rText ); + } + pNewCell = new ScFormulaCell( pDoc, rPos, pCode, eGrammar, MM_NONE ); + delete pCode; // Zell-ctor hat das TokenArray kopiert + } + else if ( rText.Len() > 1 && rText.GetChar(0) == '\'' ) + { + // for bEnglish, "'" at the beginning is always interpreted as text + // marker and stripped + pNewCell = ScBaseCell::CreateTextCell( rText.Copy( 1 ), pDoc ); + } + else // (nur) auf englisches Zahlformat testen + { + SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); + sal_uInt32 nEnglish = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US); + double fVal; + if ( pFormatter->IsNumberFormat( rText, nEnglish, fVal ) ) + pNewCell = new ScValueCell( fVal ); + else if ( rText.Len() ) + pNewCell = ScBaseCell::CreateTextCell( rText, pDoc ); + + // das (englische) Zahlformat wird nicht gesetzt + //! passendes lokales Format suchen und setzen??? + } + + return pNewCell; +} + + +BOOL ScDocFunc::SetCellText( const ScAddress& rPos, const String& rText, + BOOL bInterpret, BOOL bEnglish, BOOL bApi, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) +{ + // SetCellText ruft PutCell oder SetNormalString + + ScDocument* pDoc = rDocShell.GetDocument(); + ScBaseCell* pNewCell = NULL; + if ( bInterpret ) + { + if ( bEnglish ) + { + // code moved to own method InterpretEnglishString because it is also used in + // ScCellRangeObj::setFormulaArray + + pNewCell = InterpretEnglishString( rPos, rText, rFormulaNmsp, eGrammar ); + } + // sonst Null behalten -> SetString mit lokalen Formeln/Zahlformat + } + else if ( rText.Len() ) + { + OSL_ENSURE( rFormulaNmsp.Len() == 0, "ScDocFunc::SetCellText - formula namespace, but do not interpret?" ); + pNewCell = ScBaseCell::CreateTextCell( rText, pDoc ); // immer Text + } + + if (pNewCell) + return PutCell( rPos, pNewCell, bApi ); + else + return SetNormalString( rPos, rText, bApi ); +} + +//------------------------------------------------------------------------ + +bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow ) +{ + ScDocument& rDoc = *rDocShell.GetDocument(); + ScPostIt* pNote = rDoc.GetNote( rPos ); + if( !pNote || (bShow == pNote->IsCaptionShown()) ) return false; + + // move the caption to internal or hidden layer and create undo action + pNote->ShowCaption( rPos, bShow ); + if( rDoc.IsUndoEnabled() ) + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideNote( rDocShell, rPos, bShow ) ); + + if (rDoc.IsStreamValid(rPos.Tab())) + rDoc.SetStreamValid(rPos.Tab(), FALSE); + + rDocShell.SetDocumentModified(); + + return true; +} + +//------------------------------------------------------------------------ + +bool ScDocFunc::SetNoteText( const ScAddress& rPos, const String& rText, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + ScEditableTester aTester( pDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return false; + } + + String aNewText = rText; + aNewText.ConvertLineEnd(); //! ist das noetig ??? + + if( ScPostIt* pNote = (aNewText.Len() > 0) ? pDoc->GetOrCreateNote( rPos ) : pDoc->GetNote( rPos ) ) + pNote->SetText( rPos, aNewText ); + + //! Undo !!! + + if (pDoc->IsStreamValid(rPos.Tab())) + pDoc->SetStreamValid(rPos.Tab(), FALSE); + + rDocShell.PostPaintCell( rPos ); + aModificator.SetDocumentModified(); + + return true; +} + +//------------------------------------------------------------------------ + +bool ScDocFunc::ReplaceNote( const ScAddress& rPos, const String& rNoteText, const String* pAuthor, const String* pDate, BOOL bApi ) +{ + bool bDone = false; + + ScDocShellModificator aModificator( rDocShell ); + ScDocument& rDoc = *rDocShell.GetDocument(); + ScEditableTester aTester( &rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() ); + if (aTester.IsEditable()) + { + ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer(); + SfxUndoManager* pUndoMgr = (pDrawLayer && rDoc.IsUndoEnabled()) ? rDocShell.GetUndoManager() : 0; + + ScNoteData aOldData; + ScPostIt* pOldNote = rDoc.ReleaseNote( rPos ); + if( pOldNote ) + { + // ensure existing caption object before draw undo tracking starts + pOldNote->GetOrCreateCaption( rPos ); + // rescue note data for undo + aOldData = pOldNote->GetNoteData(); + } + + // collect drawing undo actions for deleting/inserting caption obejcts + if( pUndoMgr ) + pDrawLayer->BeginCalcUndo(); + + // delete the note (creates drawing undo action for the caption object) + delete pOldNote; + + // create new note (creates drawing undo action for the new caption object) + ScNoteData aNewData; + if( ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true ) ) + { + if( pAuthor ) pNewNote->SetAuthor( *pAuthor ); + if( pDate ) pNewNote->SetDate( *pDate ); + // rescue note data for undo + aNewData = pNewNote->GetNoteData(); + } + + // create the undo action + if( pUndoMgr && (aOldData.mpCaption || aNewData.mpCaption) ) + pUndoMgr->AddUndoAction( new ScUndoReplaceNote( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo() ) ); + + // repaint cell (to make note marker visible) + rDocShell.PostPaintCell( rPos ); + + if (rDoc.IsStreamValid(rPos.Tab())) + rDoc.SetStreamValid(rPos.Tab(), FALSE); + + aModificator.SetDocumentModified(); + bDone = true; + } + else if (!bApi) + { + rDocShell.ErrorMessage(aTester.GetMessageId()); + } + + return bDone; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern, + BOOL bRecord, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if ( bRecord && !pDoc->IsUndoEnabled() ) + bRecord = FALSE; + + BOOL bImportingXML = pDoc->IsImportingXML(); + // Cell formats can still be set if the range isn't editable only because of matrix formulas. + // #i62483# When loading XML, the check can be skipped altogether. + BOOL bOnlyNotBecauseOfMatrix; + if ( !bImportingXML && !pDoc->IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) + && !bOnlyNotBecauseOfMatrix ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); + return FALSE; + } + + ScDocShellModificator aModificator( rDocShell ); + + //! Umrandung + + ScRange aMultiRange; + BOOL bMulti = rMark.IsMultiMarked(); + if ( bMulti ) + rMark.GetMultiMarkArea( aMultiRange ); + else + rMark.GetMarkArea( aMultiRange ); + + if ( bRecord ) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() ); + pDoc->CopyToDocument( aMultiRange, IDF_ATTRIB, bMulti, pUndoDoc, &rMark ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoSelectionAttr( + &rDocShell, rMark, + aMultiRange.aStart.Col(), aMultiRange.aStart.Row(), aMultiRange.aStart.Tab(), + aMultiRange.aEnd.Col(), aMultiRange.aEnd.Row(), aMultiRange.aEnd.Tab(), + pUndoDoc, bMulti, &rPattern ) ); + } + + // While loading XML it is not neccessary to ask HasAttrib. It needs too much time. + USHORT nExtFlags = 0; + if ( !bImportingXML ) + rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change + pDoc->ApplySelectionPattern( rPattern, rMark ); + if ( !bImportingXML ) + rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content after the change + + if (!AdjustRowHeight( aMultiRange )) + rDocShell.PostPaint( aMultiRange, PAINT_GRID, nExtFlags ); + else if (nExtFlags & SC_PF_LINES) + lcl_PaintAbove( rDocShell, aMultiRange ); // fuer Linien ueber dem Bereich + + aModificator.SetDocumentModified(); + + return TRUE; +} + + +BOOL ScDocFunc::ApplyStyle( const ScMarkData& rMark, const String& rStyleName, + BOOL bRecord, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if ( bRecord && !pDoc->IsUndoEnabled() ) + bRecord = FALSE; + + BOOL bImportingXML = pDoc->IsImportingXML(); + // Cell formats can still be set if the range isn't editable only because of matrix formulas. + // #i62483# When loading XML, the check can be skipped altogether. + BOOL bOnlyNotBecauseOfMatrix; + if ( !bImportingXML && !pDoc->IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix ) + && !bOnlyNotBecauseOfMatrix ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); + return FALSE; + } + + ScStyleSheet* pStyleSheet = (ScStyleSheet*) pDoc->GetStyleSheetPool()->Find( + rStyleName, SFX_STYLE_FAMILY_PARA ); + if (!pStyleSheet) + return FALSE; + + ScDocShellModificator aModificator( rDocShell ); + + ScRange aMultiRange; + BOOL bMulti = rMark.IsMultiMarked(); + if ( bMulti ) + rMark.GetMultiMarkArea( aMultiRange ); + else + rMark.GetMarkArea( aMultiRange ); + + if ( bRecord ) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + SCTAB nStartTab = aMultiRange.aStart.Tab(); + SCTAB nTabCount = pDoc->GetTableCount(); + pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nStartTab && rMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + ScRange aCopyRange = aMultiRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &rMark ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoSelectionStyle( + &rDocShell, rMark, aMultiRange, rStyleName, pUndoDoc ) ); + + } + +// BOOL bPaintExt = pDoc->HasAttrib( aMultiRange, HASATTR_PAINTEXT ); +// pDoc->ApplySelectionPattern( rPattern, rMark ); + + pDoc->ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, rMark ); + +// if (!bPaintExt) +// bPaintExt = pDoc->HasAttrib( aMultiRange, HASATTR_PAINTEXT ); +// USHORT nExtFlags = bPaintExt ? SC_PF_LINES : 0; + USHORT nExtFlags = 0; + if (!AdjustRowHeight( aMultiRange )) + rDocShell.PostPaint( aMultiRange, PAINT_GRID, nExtFlags ); + else if (nExtFlags & SC_PF_LINES) + lcl_PaintAbove( rDocShell, aMultiRange ); // fuer Linien ueber dem Bereich + + aModificator.SetDocumentModified(); + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd, + BOOL bRecord, BOOL bApi, BOOL bPartOfPaste ) +{ + ScDocShellModificator aModificator( rDocShell ); + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) ) + { + DBG_ERROR("invalid row in InsertCells"); + return FALSE; + } + + ScDocument* pDoc = rDocShell.GetDocument(); + SCTAB nTabCount = pDoc->GetTableCount(); + SCCOL nPaintStartX = nStartCol; + SCROW nPaintStartY = nStartRow; + SCCOL nPaintEndX = nEndCol; + SCROW nPaintEndY = nEndRow; + USHORT nPaintFlags = PAINT_GRID; + BOOL bSuccess; + SCTAB i; + + ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); //preserve current cursor position + SCCOL nCursorCol = 0; + SCROW nCursorRow = 0; + if( pViewSh ) + { + nCursorCol = pViewSh->GetViewData()->GetCurX(); + nCursorRow = pViewSh->GetViewData()->GetCurY(); + } + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + SCTAB nCount = 0; + for( i=0; i<nTabCount; i++ ) + { + if( !pDoc->IsScenario(i) ) + { + nCount++; + if( nCount == nEndTab+1 ) + { + aMark.SelectTable( i, TRUE ); + break; + } + } + } + } + + ScMarkData aFullMark( aMark ); // including scenario sheets + for( i=0; i<nTabCount; i++ ) + if( aMark.GetTableSelect( i ) ) + { + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + aFullMark.SelectTable( j, TRUE ); + } + + SCTAB nSelCount = aMark.GetSelectCount(); + + // zugehoerige Szenarien auch anpassen + // Test zusammengefasste + + SCCOL nMergeTestStartX = nStartCol; + SCROW nMergeTestStartY = nStartRow; + SCCOL nMergeTestEndX = nEndCol; + SCROW nMergeTestEndY = nEndRow; + + ScRange aExtendMergeRange( rRange ); + + if( rRange.aStart == rRange.aEnd && pDoc->HasAttrib(rRange, HASATTR_MERGED) ) + { + pDoc->ExtendMerge( aExtendMergeRange ); + pDoc->ExtendOverlapped( aExtendMergeRange ); + nMergeTestEndX = aExtendMergeRange.aEnd.Col(); + nMergeTestEndY = aExtendMergeRange.aEnd.Row(); + nPaintEndX = nMergeTestEndX; + nPaintEndY = nMergeTestEndY; + } + + if ( eCmd == INS_INSROWS ) + { + nMergeTestStartX = 0; + nMergeTestEndX = MAXCOL; + } + if ( eCmd == INS_INSCOLS ) + { + nMergeTestStartY = 0; + nMergeTestEndY = MAXROW; + } + if ( eCmd == INS_CELLSDOWN ) + nMergeTestEndY = MAXROW; + if ( eCmd == INS_CELLSRIGHT ) + nMergeTestEndX = MAXCOL; + + BOOL bNeedRefresh = FALSE; + + SCCOL nEditTestEndX = (eCmd==INS_INSCOLS) ? MAXCOL : nMergeTestEndX; + SCROW nEditTestEndY = (eCmd==INS_INSROWS) ? MAXROW : nMergeTestEndY; + ScEditableTester aTester( pDoc, nMergeTestStartX, nMergeTestStartY, nEditTestEndX, nEditTestEndY, aMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + WaitObject aWait( rDocShell.GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference + + ScDocument* pRefUndoDoc = NULL; + ScRefUndoData* pUndoData = NULL; + if ( bRecord ) + { + pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, FALSE, FALSE ); + + // pRefUndoDoc is filled in InsertCol / InsertRow + + pUndoData = new ScRefUndoData( pDoc ); + + pDoc->BeginDrawUndo(); + } + + // #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction + // the patch comes from mloiseleur and maoyg + BOOL bInsertMerge = FALSE; + std::vector<ScRange> qIncreaseRange; + String aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTCELLS ); + if (bRecord) + rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect(i) ) + { + if( pDoc->HasAttrib( nMergeTestStartX, nMergeTestStartY, i, nMergeTestEndX, nMergeTestEndY, i, HASATTR_MERGED | HASATTR_OVERLAPPED ) ) + { + if (eCmd==INS_CELLSRIGHT) + bNeedRefresh = TRUE; + + SCCOL nMergeStartX = nMergeTestStartX; + SCROW nMergeStartY = nMergeTestStartY; + SCCOL nMergeEndX = nMergeTestEndX; + SCROW nMergeEndY = nMergeTestEndY; + + pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); + pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); + + if(( eCmd == INS_CELLSDOWN && ( nMergeStartX != nMergeTestStartX || nMergeEndX != nMergeTestEndX )) || + (eCmd == INS_CELLSRIGHT && ( nMergeStartY != nMergeTestStartY || nMergeEndY != nMergeTestEndY )) ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); + rDocShell.GetUndoManager()->LeaveListAction(); + return FALSE; + } + + SCCOL nTestCol = -1; + SCROW nTestRow1 = -1; + SCROW nTestRow2 = -1; + + ScDocAttrIterator aTestIter( pDoc, i, nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY ); + ScRange aExtendRange( nMergeTestStartX, nMergeTestStartY, i, nMergeTestEndX, nMergeTestEndY, i ); + const ScPatternAttr* pPattern = NULL; + const ScMergeAttr* pMergeFlag = NULL; + const ScMergeFlagAttr* pMergeFlagAttr = NULL; + while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL ) + { + pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem(ATTR_MERGE); + pMergeFlagAttr = (const ScMergeFlagAttr*) &pPattern->GetItem(ATTR_MERGE_FLAG); + INT16 nNewFlags = pMergeFlagAttr->GetValue() & ( SC_MF_HOR | SC_MF_VER ); + if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == SC_MF_HOR || nNewFlags == SC_MF_VER ) + { + ScRange aRange( nTestCol, nTestRow1, i ); + pDoc->ExtendOverlapped(aRange); + pDoc->ExtendMerge(aRange, TRUE, TRUE); + + if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR ) + { + for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) + { + ScRange aTestRange( nTestCol, nTestRow, i ); + pDoc->ExtendOverlapped( aTestRange ); + pDoc->ExtendMerge( aTestRange, TRUE, TRUE); + ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); + if( !aExtendRange.In( aMergeRange ) ) + { + qIncreaseRange.push_back( aTestRange ); + bInsertMerge = TRUE; + } + } + } + else + { + ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); + if( !aExtendRange.In( aMergeRange ) ) + { + qIncreaseRange.push_back( aRange ); + } + bInsertMerge = TRUE; + } + } + } + + if( bInsertMerge ) + { + if( eCmd == INS_INSROWS || eCmd == INS_CELLSDOWN ) + { + nStartRow = aExtendMergeRange.aStart.Row(); + nEndRow = aExtendMergeRange.aEnd.Row(); + + if( eCmd == INS_CELLSDOWN ) + nEndCol = nMergeTestEndX; + else + { + nStartCol = 0; + nEndCol = MAXCOL; + } + } + else if( eCmd == INS_CELLSRIGHT || eCmd == INS_INSCOLS ) + { + + nStartCol = aExtendMergeRange.aStart.Col(); + nEndCol = aExtendMergeRange.aEnd.Col(); + if( eCmd == INS_CELLSRIGHT ) + { + nEndRow = nMergeTestEndY; + } + else + { + nStartRow = 0; + nEndRow = MAXROW; + } + } + + if( !qIncreaseRange.empty() ) + { + for( ::std::vector<ScRange>::const_iterator iIter( qIncreaseRange.begin()); iIter != qIncreaseRange.end(); iIter++ ) + { + ScRange aRange( *iIter ); + if( pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) + { + UnmergeCells( aRange, TRUE, TRUE ); + } + } + } + } + else + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); + rDocShell.GetUndoManager()->LeaveListAction(); + return FALSE; + } + } + } + } + + switch (eCmd) + { + case INS_CELLSDOWN: + bSuccess = pDoc->InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark ); + nPaintEndY = MAXROW; + break; + case INS_INSROWS: + bSuccess = pDoc->InsertRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &aFullMark ); + nPaintStartX = 0; + nPaintEndX = MAXCOL; + nPaintEndY = MAXROW; + nPaintFlags |= PAINT_LEFT; + break; + case INS_CELLSRIGHT: + bSuccess = pDoc->InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark ); + nPaintEndX = MAXCOL; + break; + case INS_INSCOLS: + bSuccess = pDoc->InsertCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &aFullMark ); + nPaintStartY = 0; + nPaintEndY = MAXROW; + nPaintEndX = MAXCOL; + nPaintFlags |= PAINT_TOP; + break; + default: + DBG_ERROR("Falscher Code beim Einfuegen"); + bSuccess = FALSE; + break; + } + + if ( bSuccess ) + { + SCTAB* pTabs = NULL; + SCTAB* pScenarios = NULL; + SCTAB nUndoPos = 0; + + if ( bRecord ) + { + pTabs = new SCTAB[nSelCount]; + pScenarios = new SCTAB[nSelCount]; + nUndoPos = 0; + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + SCTAB nCount = 0; + for( SCTAB j=i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nCount ++; + + pScenarios[nUndoPos] = nCount; + pTabs[nUndoPos] = i; + nUndoPos ++; + } + } + + if( !bInsertMerge ) + { + rDocShell.GetUndoManager()->LeaveListAction(); + } + + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertCells( + &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ), + nUndoPos, pTabs, pScenarios, eCmd, pRefUndoDoc, pUndoData, bPartOfPaste ) ); + } + + // #i8302 : we remerge growing ranges, with the new part inserted + + while( !qIncreaseRange.empty() ) + { + ScRange aRange = qIncreaseRange.back(); + if( !pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) + { + switch (eCmd) + { + case INS_CELLSDOWN: + case INS_INSROWS: + aRange.aEnd.IncRow(static_cast<SCsCOL>(nEndRow-nStartRow+1)); + break; + case INS_CELLSRIGHT: + case INS_INSCOLS: + aRange.aEnd.IncCol(static_cast<SCsCOL>(nEndCol-nStartCol+1)); + break; + default: + break; + } + MergeCells(aRange, FALSE, TRUE, TRUE); + } + qIncreaseRange.pop_back(); + } + + if( bInsertMerge ) + rDocShell.GetUndoManager()->LeaveListAction(); + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + if (bNeedRefresh) + pDoc->ExtendMerge( nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY, i, TRUE ); + else + pDoc->RefreshAutoFilter( nMergeTestStartX, nMergeTestStartY, nMergeTestEndX, nMergeTestEndY, i ); + + if ( eCmd == INS_INSROWS || eCmd == INS_INSCOLS ) + pDoc->UpdatePageBreaks( i ); + + USHORT nExtFlags = 0; + rDocShell.UpdatePaintExt( nExtFlags, nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i ); + + SCTAB nScenarioCount = 0; + + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nScenarioCount ++; + + BOOL bAdjusted = ( eCmd == INS_INSROWS ) ? AdjustRowHeight(ScRange(0, nStartRow, i, MAXCOL, nEndRow, i+nScenarioCount )) : + AdjustRowHeight(ScRange(0, nPaintStartY, i, MAXCOL, nPaintEndY, i+nScenarioCount )); + if (bAdjusted) + { + // paint only what is not done by AdjustRowHeight + if (nPaintFlags & PAINT_TOP) + rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, PAINT_TOP ); + } + else + rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, nPaintFlags, nExtFlags ); + } + } + //aModificator.SetDocumentModified(); + } + else + { + if( bInsertMerge ) + { + while( !qIncreaseRange.empty() ) + { + ScRange aRange = qIncreaseRange.back(); + MergeCells(aRange, FALSE, TRUE, TRUE); + qIncreaseRange.pop_back(); + } + + if( pViewSh ) + { + pViewSh->MarkRange( rRange, FALSE ); + pViewSh->SetCursor( nCursorCol, nCursorRow ); + } + } + + rDocShell.GetUndoManager()->LeaveListAction(); + SfxUndoManager* pMgr = rDocShell.GetUndoManager(); + pMgr->RemoveLastUndoAction(); + + delete pRefUndoDoc; + delete pUndoData; + if (!bApi) + rDocShell.ErrorMessage(STR_INSERT_FULL); // Spalte/Zeile voll + } + + aModificator.SetDocumentModified(); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); + return bSuccess; +} + +BOOL ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd, + BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) ) + { + DBG_ERROR("invalid row in DeleteCells"); + return FALSE; + } + + ScDocument* pDoc = rDocShell.GetDocument(); + SCTAB nTabCount = pDoc->GetTableCount(); + SCCOL nPaintStartX = nStartCol; + SCROW nPaintStartY = nStartRow; + SCCOL nPaintEndX = nEndCol; + SCROW nPaintEndY = nEndRow; + USHORT nPaintFlags = PAINT_GRID; + SCTAB i; + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + SCTAB nCount = 0; + for( i=0; i<nTabCount; i++ ) + { + if( !pDoc->IsScenario(i) ) + { + nCount++; + if( nCount == nEndTab+1 ) + { + aMark.SelectTable( i, TRUE ); + break; + } + } + } + } + + ScMarkData aFullMark( aMark ); // including scenario sheets + for( i=0; i<nTabCount; i++ ) + if( aMark.GetTableSelect( i ) ) + { + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + aFullMark.SelectTable( j, TRUE ); + } + + SCTAB nSelCount = aMark.GetSelectCount(); + + SCCOL nUndoStartX = nStartCol; + SCROW nUndoStartY = nStartRow; + SCCOL nUndoEndX = nEndCol; + SCROW nUndoEndY = nEndRow; + + ScRange aExtendMergeRange( rRange ); + + if( rRange.aStart == rRange.aEnd && pDoc->HasAttrib(rRange, HASATTR_MERGED) ) + { + pDoc->ExtendMerge( aExtendMergeRange ); + pDoc->ExtendOverlapped( aExtendMergeRange ); + nUndoEndX = aExtendMergeRange.aEnd.Col(); + nUndoEndY = aExtendMergeRange.aEnd.Row(); + nPaintEndX = nUndoEndX; + nPaintEndY = nUndoEndY; + } + + if (eCmd==DEL_DELROWS) + { + nUndoStartX = 0; + nUndoEndX = MAXCOL; + } + if (eCmd==DEL_DELCOLS) + { + nUndoStartY = 0; + nUndoEndY = MAXROW; + } + // Test Zellschutz + + SCCOL nEditTestEndX = nUndoEndX; + if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT ) + nEditTestEndX = MAXCOL; + SCROW nEditTestEndY = nUndoEndY; + if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP ) + nEditTestEndY = MAXROW; + ScEditableTester aTester( pDoc, nUndoStartX, nUndoStartY, nEditTestEndX, nEditTestEndY, aMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + // Test zusammengefasste + + SCCOL nMergeTestEndX = (eCmd==DEL_CELLSLEFT) ? MAXCOL : nUndoEndX; + SCROW nMergeTestEndY = (eCmd==DEL_CELLSUP) ? MAXROW : nUndoEndY; + SCCOL nExtendStartCol = nUndoStartX; + SCROW nExtendStartRow = nUndoStartY; + BOOL bNeedRefresh = FALSE; + + //Issue 8302 want to be able to insert into the middle of merged cells + //the patch comes from maoyg + ::std::vector<ScRange> qDecreaseRange; + BOOL bDeletingMerge = FALSE; + String aUndo = ScGlobal::GetRscString( STR_UNDO_DELETECELLS ); + if (bRecord) + rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect(i) ) + { + if ( pDoc->HasAttrib( nUndoStartX, nUndoStartY, i, nMergeTestEndX, nMergeTestEndY, i, HASATTR_MERGED | HASATTR_OVERLAPPED )) + { + SCCOL nMergeStartX = nUndoStartX; + SCROW nMergeStartY = nUndoStartY; + SCCOL nMergeEndX = nMergeTestEndX; + SCROW nMergeEndY = nMergeTestEndY; + + pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); + pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); + if( ( eCmd == DEL_CELLSUP && ( nMergeStartX != nUndoStartX || nMergeEndX != nMergeTestEndX))|| + ( eCmd == DEL_CELLSLEFT && ( nMergeStartY != nUndoStartY || nMergeEndY != nMergeTestEndY))) + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); + rDocShell.GetUndoManager()->LeaveListAction(); + return FALSE; + } + + nExtendStartCol = nMergeStartX; + nExtendStartRow = nMergeStartY; + SCCOL nTestCol = -1; + SCROW nTestRow1 = -1; + SCROW nTestRow2 = -1; + + ScDocAttrIterator aTestIter( pDoc, i, nUndoStartX, nUndoStartY, nMergeTestEndX, nMergeTestEndY ); + ScRange aExtendRange( nUndoStartX, nUndoStartY, i, nMergeTestEndX, nMergeTestEndY, i ); + const ScPatternAttr* pPattern = NULL; + const ScMergeAttr* pMergeFlag = NULL; + const ScMergeFlagAttr* pMergeFlagAttr = NULL; + while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != NULL ) + { + pMergeFlag = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); + pMergeFlagAttr = (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG ); + INT16 nNewFlags = pMergeFlagAttr->GetValue() & ( SC_MF_HOR | SC_MF_VER ); + if( ( pMergeFlag && pMergeFlag->IsMerged() ) || nNewFlags == SC_MF_HOR || nNewFlags == SC_MF_VER ) + { + ScRange aRange( nTestCol, nTestRow1, i ); + pDoc->ExtendOverlapped( aRange ); + pDoc->ExtendMerge( aRange, TRUE, TRUE ); + + if( nTestRow1 < nTestRow2 && nNewFlags == SC_MF_HOR ) + { + for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ ) + { + ScRange aTestRange( nTestCol, nTestRow, i ); + pDoc->ExtendOverlapped( aTestRange ); + pDoc->ExtendMerge( aTestRange, TRUE, TRUE); + ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i ); + if( !aExtendRange.In( aMergeRange ) ) + { + qDecreaseRange.push_back( aTestRange ); + bDeletingMerge = TRUE; + } + } + } + else + { + ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i ); + if( !aExtendRange.In( aMergeRange ) ) + { + qDecreaseRange.push_back( aRange ); + } + bDeletingMerge = TRUE; + } + } + } + + if( bDeletingMerge ) + { + + if( eCmd == DEL_DELROWS || eCmd == DEL_CELLSUP ) + { + nStartRow = aExtendMergeRange.aStart.Row(); + nEndRow = aExtendMergeRange.aEnd.Row(); + bNeedRefresh = TRUE; + + if( eCmd == DEL_CELLSUP ) + { + nEndCol = aExtendMergeRange.aEnd.Col(); + } + else + { + nStartCol = 0; + nEndCol = MAXCOL; + } + } + else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS ) + { + + nStartCol = aExtendMergeRange.aStart.Col(); + nEndCol = aExtendMergeRange.aEnd.Col(); + if( eCmd == DEL_CELLSLEFT ) + { + nEndRow = aExtendMergeRange.aEnd.Row(); + bNeedRefresh = TRUE; + } + else + { + nStartRow = 0; + nEndRow = MAXROW; + } + } + + if( !qDecreaseRange.empty() ) + { + for( ::std::vector<ScRange>::const_iterator iIter( qDecreaseRange.begin()); iIter != qDecreaseRange.end(); iIter++ ) + { + ScRange aRange( *iIter ); + if( pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) + { + UnmergeCells( aRange, TRUE, TRUE ); + } + } + } + } + else + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0); + rDocShell.GetUndoManager()->LeaveListAction(); + return FALSE; + } + } + } + } + + // + // ausfuehren + // + + WaitObject aWait( rDocShell.GetActiveDialogParent() ); // wichtig wegen TrackFormulas bei UpdateReference + + ScDocument* pUndoDoc = NULL; + ScDocument* pRefUndoDoc = NULL; + ScRefUndoData* pUndoData = NULL; + if ( bRecord ) + { + // With the fix for #101329#, UpdateRef always puts cells into pRefUndoDoc at their old position, + // so it's no longer necessary to copy more than the deleted range into pUndoDoc. + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, 0, nTabCount-1, (eCmd==DEL_DELCOLS), (eCmd==DEL_DELROWS) ); + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + SCTAB nScenarioCount = 0; + + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nScenarioCount ++; + + pDoc->CopyToDocument( nUndoStartX, nUndoStartY, i, nUndoEndX, nUndoEndY, i+nScenarioCount, + IDF_ALL | IDF_NOCAPTIONS, FALSE, pUndoDoc ); + } + } + + pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, FALSE, FALSE ); + + pUndoData = new ScRefUndoData( pDoc ); + + pDoc->BeginDrawUndo(); + } + + USHORT nExtFlags = 0; + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, i, nEndCol, nEndRow, i ); + } + + BOOL bUndoOutline = FALSE; + switch (eCmd) + { + case DEL_CELLSUP: + pDoc->DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, NULL, &aFullMark ); + nPaintEndY = MAXROW; + break; + case DEL_DELROWS: + pDoc->DeleteRow( 0, 0, MAXCOL, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc, &bUndoOutline, &aFullMark ); + nPaintStartX = 0; + nPaintEndX = MAXCOL; + nPaintEndY = MAXROW; + nPaintFlags |= PAINT_LEFT; + break; + case DEL_CELLSLEFT: + pDoc->DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, NULL, &aFullMark ); + nPaintEndX = MAXCOL; + break; + case DEL_DELCOLS: + pDoc->DeleteCol( 0, 0, MAXROW, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc, &bUndoOutline, &aFullMark ); + nPaintStartY = 0; + nPaintEndY = MAXROW; + nPaintEndX = MAXCOL; + nPaintFlags |= PAINT_TOP; + break; + default: + DBG_ERROR("Falscher Code beim Loeschen"); + break; + } + + //! Test, ob Outline in Groesse geaendert + + if ( bRecord ) + { + for( i=0; i<nTabCount; i++ ) + if( aFullMark.GetTableSelect( i ) ) + pRefUndoDoc->DeleteAreaTab(nUndoStartX,nUndoStartY,nUndoEndX,nUndoEndY, i, IDF_ALL); + + // alle Tabellen anlegen, damit Formeln kopiert werden koennen: + pUndoDoc->AddUndoTab( 0, nTabCount-1, FALSE, FALSE ); + + // kopieren mit bColRowFlags=FALSE (#54194#) + pRefUndoDoc->CopyToDocument(0,0,0,MAXCOL,MAXROW,MAXTAB,IDF_FORMULA,FALSE,pUndoDoc,NULL,FALSE); + delete pRefUndoDoc; + + SCTAB* pTabs = new SCTAB[nSelCount]; + SCTAB* pScenarios = new SCTAB[nSelCount]; + SCTAB nUndoPos = 0; + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + SCTAB nCount = 0; + for( SCTAB j=i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nCount ++; + + pScenarios[nUndoPos] = nCount; + pTabs[nUndoPos] = i; + nUndoPos ++; + } + } + + if( !bDeletingMerge ) + { + rDocShell.GetUndoManager()->LeaveListAction(); + } + + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDeleteCells( + &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),nUndoPos, pTabs, pScenarios, + eCmd, pUndoDoc, pUndoData ) ); + } + + // #i8302 want to be able to insert into the middle of merged cells + // the patch comes from maoyg + + while( !qDecreaseRange.empty() ) + { + ScRange aRange = qDecreaseRange.back(); + + long nDecreaseRowCount = 0; + long nDecreaseColCount = 0; + if( eCmd == DEL_CELLSUP || eCmd == DEL_DELROWS ) + { + if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) + nDecreaseRowCount = nEndRow-nStartRow+1; + else if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow >= aRange.aStart.Row() && nEndRow >= aRange.aEnd.Row() ) + nDecreaseRowCount = aRange.aEnd.Row()-nStartRow+1; + else if( nStartRow >= aRange.aStart.Row() && nStartRow >= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() ) + nDecreaseRowCount = aRange.aEnd.Row()-nEndRow+1; + } + else if( eCmd == DEL_CELLSLEFT || eCmd == DEL_DELCOLS ) + { + if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) + nDecreaseColCount = nEndCol-nStartCol+1; + else if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol >= aRange.aStart.Col() && nEndCol >= aRange.aEnd.Col() ) + nDecreaseColCount = aRange.aEnd.Col()-nStartCol+1; + else if( nStartCol >= aRange.aStart.Col() && nStartCol >= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() ) + nDecreaseColCount = aRange.aEnd.Col()-nEndCol+1; + } + + switch (eCmd) + { + case DEL_CELLSUP: + case DEL_DELROWS: + aRange.aEnd.SetRow(static_cast<SCsCOL>( aRange.aEnd.Row()-nDecreaseRowCount)); + break; + case DEL_CELLSLEFT: + case DEL_DELCOLS: + aRange.aEnd.SetCol(static_cast<SCsCOL>( aRange.aEnd.Col()-nDecreaseColCount)); + break; + default: + break; + } + + if( !pDoc->HasAttrib( aRange, HASATTR_OVERLAPPED | HASATTR_MERGED ) ) + { + MergeCells( aRange, FALSE, TRUE, TRUE ); + } + qDecreaseRange.pop_back(); + } + + if( bDeletingMerge ) + rDocShell.GetUndoManager()->LeaveListAction(); + + if ( bNeedRefresh ) + { + // #i51445# old merge flag attributes must be deleted also for single cells, + // not only for whole columns/rows + + if ( eCmd==DEL_DELCOLS || eCmd==DEL_CELLSLEFT ) + nMergeTestEndX = MAXCOL; + if ( eCmd==DEL_DELROWS || eCmd==DEL_CELLSUP ) + nMergeTestEndY = MAXROW; + ScPatternAttr aPattern( pDoc->GetPool() ); + aPattern.GetItemSet().Put( ScMergeFlagAttr() ); + + pDoc->ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndX, nMergeTestEndY, aMark, aPattern ); + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + SCTAB nScenarioCount = 0; + + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nScenarioCount ++; + + ScRange aMergedRange( nExtendStartCol, nExtendStartRow, i, nMergeTestEndX, nMergeTestEndY, i+nScenarioCount ); + pDoc->ExtendMerge( aMergedRange, TRUE ); + } + } + } + + for( i=0; i<nTabCount; i++ ) + { + if( aMark.GetTableSelect( i ) ) + { + if ( eCmd == DEL_DELCOLS || eCmd == DEL_DELROWS ) + pDoc->UpdatePageBreaks( i ); + + rDocShell.UpdatePaintExt( nExtFlags, nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i ); + + SCTAB nScenarioCount = 0; + + for( SCTAB j = i+1; j<nTabCount && pDoc->IsScenario(j); j++ ) + nScenarioCount ++; + + // ganze Zeilen loeschen: nichts anpassen + if ( eCmd == DEL_DELROWS || !AdjustRowHeight(ScRange( 0, nPaintStartY, i, MAXCOL, nPaintEndY, i+nScenarioCount )) ) + rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, nPaintFlags, nExtFlags ); + else + { + // paint only what is not done by AdjustRowHeight + if (nExtFlags & SC_PF_LINES) + lcl_PaintAbove( rDocShell, ScRange( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount) ); + if (nPaintFlags & PAINT_TOP) + rDocShell.PostPaint( nPaintStartX, nPaintStartY, i, nPaintEndX, nPaintEndY, i+nScenarioCount, PAINT_TOP ); + } + } + } + aModificator.SetDocumentModified(); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); + + return TRUE; +} + +BOOL ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos, + BOOL bCut, BOOL bRecord, BOOL bPaint, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + SCCOL nStartCol = rSource.aStart.Col(); + SCROW nStartRow = rSource.aStart.Row(); + SCTAB nStartTab = rSource.aStart.Tab(); + SCCOL nEndCol = rSource.aEnd.Col(); + SCROW nEndRow = rSource.aEnd.Row(); + SCTAB nEndTab = rSource.aEnd.Tab(); + SCCOL nDestCol = rDestPos.Col(); + SCROW nDestRow = rDestPos.Row(); + SCTAB nDestTab = rDestPos.Tab(); + + if ( !ValidRow(nStartRow) || !ValidRow(nEndRow) || !ValidRow(nDestRow) ) + { + DBG_ERROR("invalid row in MoveBlock"); + return FALSE; + } + + // zugehoerige Szenarien auch anpassen - nur wenn innerhalb einer Tabelle verschoben wird! + BOOL bScenariosAdded = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + SCTAB nTabCount = pDoc->GetTableCount(); + if ( nDestTab == nStartTab && !pDoc->IsScenario(nEndTab) ) + while ( nEndTab+1 < nTabCount && pDoc->IsScenario(nEndTab+1) ) + { + ++nEndTab; + bScenariosAdded = TRUE; + } + + SCTAB nSrcTabCount = nEndTab-nStartTab+1; + SCTAB nDestEndTab = nDestTab+nSrcTabCount-1; + SCTAB nTab; + + ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP ); + + ScMarkData aSourceMark; + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + aSourceMark.SelectTable( nTab, TRUE ); // Source selektieren + aSourceMark.SetMarkArea( rSource ); + + ScDocShellRef aDragShellRef; + if ( pDoc->HasOLEObjectsInArea( rSource ) ) + { + aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately + aDragShellRef->DoInitNew(NULL); + } + ScDrawLayer::SetGlobalDrawPersist(aDragShellRef); + + ScClipParam aClipParam(ScRange(nStartCol, nStartRow, 0, nEndCol, nEndRow, 0), bCut); + pDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false, bScenariosAdded, true); + + ScDrawLayer::SetGlobalDrawPersist(NULL); + + SCCOL nOldEndCol = nEndCol; + SCROW nOldEndRow = nEndRow; + BOOL bClipOver = FALSE; + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + { + SCCOL nTmpEndCol = nOldEndCol; + SCROW nTmpEndRow = nOldEndRow; + if (pDoc->ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab )) + bClipOver = TRUE; + if ( nTmpEndCol > nEndCol ) nEndCol = nTmpEndCol; + if ( nTmpEndRow > nEndRow ) nEndRow = nTmpEndRow; + } + + SCCOL nDestEndCol = nDestCol + ( nOldEndCol-nStartCol ); + SCROW nDestEndRow = nDestRow + ( nOldEndRow-nStartRow ); + + SCCOL nUndoEndCol = nDestCol + ( nEndCol-nStartCol ); // erweitert im Zielblock + SCROW nUndoEndRow = nDestRow + ( nEndRow-nStartRow ); + + BOOL bIncludeFiltered = bCut; + if ( !bIncludeFiltered ) + { + // adjust sizes to include only non-filtered rows + + SCCOL nClipX; + SCROW nClipY; + pClipDoc->GetClipArea( nClipX, nClipY, FALSE ); + SCROW nUndoAdd = nUndoEndRow - nDestEndRow; + nDestEndRow = nDestRow + nClipY; + nUndoEndRow = nDestEndRow + nUndoAdd; + } + + if (!ValidCol(nUndoEndCol) || !ValidRow(nUndoEndRow)) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PASTE_FULL); + delete pClipDoc; + return FALSE; + } + + // Test auf Zellschutz + + ScEditableTester aTester; + for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) + aTester.TestBlock( pDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow ); + if (bCut) + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + aTester.TestBlock( pDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); + + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + delete pClipDoc; + return FALSE; + } + + // Test auf zusammengefasste - beim Verschieben erst nach dem Loeschen + + if (bClipOver && !bCut) + if (pDoc->HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab, + HASATTR_MERGED | HASATTR_OVERLAPPED )) + { // "Zusammenfassen nicht verschachteln !" + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); + delete pClipDoc; + return FALSE; + } + + // Are there borders in the cells? (for painting) + + USHORT nSourceExt = 0; + rDocShell.UpdatePaintExt( nSourceExt, nStartCol,nStartRow,nStartTab, nEndCol,nEndRow,nEndTab ); + USHORT nDestExt = 0; + rDocShell.UpdatePaintExt( nDestExt, nDestCol,nDestRow,nDestTab, nDestEndCol,nDestEndRow,nDestEndTab ); + + // + // ausfuehren + // + + ScDocument* pUndoDoc = NULL; + ScDocument* pRefUndoDoc = NULL; + ScRefUndoData* pUndoData = NULL; + if (bRecord) + { + BOOL bWholeCols = ( nStartRow == 0 && nEndRow == MAXROW ); + BOOL bWholeRows = ( nStartCol == 0 && nEndCol == MAXCOL ); + USHORT nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS; + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab, bWholeCols, bWholeRows ); + + if (bCut) + { + pDoc->CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab, + nUndoFlags, FALSE, pUndoDoc ); + pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRefUndoDoc->InitUndo( pDoc, 0, nTabCount-1, FALSE, FALSE ); + } + + if ( nDestTab != nStartTab ) + pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows ); + pDoc->CopyToDocument( nDestCol, nDestRow, nDestTab, + nDestEndCol, nDestEndRow, nDestEndTab, + nUndoFlags, FALSE, pUndoDoc ); + + pUndoData = new ScRefUndoData( pDoc ); + + pDoc->BeginDrawUndo(); + } + + BOOL bSourceHeight = FALSE; // Hoehen angepasst? + if (bCut) + { + ScMarkData aDelMark; // only for tables + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + { + pDoc->DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, IDF_ALL ); + aDelMark.SelectTable( nTab, TRUE ); + } + pDoc->DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark ); + + // Test auf zusammengefasste + + if (bClipOver) + if (pDoc->HasAttrib( nDestCol,nDestRow,nDestTab, + nUndoEndCol,nUndoEndRow,nDestEndTab, + HASATTR_MERGED | HASATTR_OVERLAPPED )) + { + pDoc->CopyFromClip( rSource, aSourceMark, IDF_ALL, pRefUndoDoc, pClipDoc ); + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + { + SCCOL nTmpEndCol = nEndCol; + SCROW nTmpEndRow = nEndRow; + pDoc->ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, TRUE ); + } + + // Fehlermeldung erst nach dem Wiederherstellen des Inhalts + if (!bApi) // "Zusammenfassen nicht verschachteln !" + rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0); + + delete pUndoDoc; + delete pRefUndoDoc; + delete pUndoData; + delete pClipDoc; + return FALSE; + } + + bSourceHeight = AdjustRowHeight( rSource, FALSE ); + } + + ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab ); + + ScMarkData aDestMark; + for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) + aDestMark.SelectTable( nTab, TRUE ); // Destination selektieren + aDestMark.SetMarkArea( aPasteDest ); + + /* Do not copy cell notes and drawing objects here. While pasting, the + function ScDocument::UpdateReference() is called which calls + ScDrawLayer::MoveCells() which may move away inserted objects to wrong + positions (e.g. if source and destination range overlaps). Cell notes + and drawing objects are pasted below after doing all adjusting. */ + pDoc->CopyFromClip( aPasteDest, aDestMark, IDF_ALL & ~(IDF_NOTE | IDF_OBJECTS), + pRefUndoDoc, pClipDoc, TRUE, FALSE, bIncludeFiltered ); + + // skipped rows and merged cells don't mix + if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() ) + UnmergeCells( aPasteDest, FALSE, TRUE ); + + VirtualDevice aVirtDev; + BOOL bDestHeight = AdjustRowHeight( + ScRange( 0,nDestRow,nDestTab, MAXCOL,nDestEndRow,nDestEndTab ), + FALSE ); + + /* Paste cell notes and drawing objects after adjusting formula references + and row heights. There are no cell notes or drawing objects, if the + clipdoc does not contain a drawing layer. + #i102056# Passing IDF_NOTE only would overwrite cell contents with + empty note cells, therefore the special modifier IDF_ADDNOTES is passed + here too which changes the behaviour of ScColumn::CopyFromClip() to not + touch existing cells. */ + if ( pClipDoc->GetDrawLayer() ) + pDoc->CopyFromClip( aPasteDest, aDestMark, IDF_NOTE | IDF_ADDNOTES | IDF_OBJECTS, + pRefUndoDoc, pClipDoc, TRUE, FALSE, bIncludeFiltered ); + + if (bRecord) + { + if (pRefUndoDoc) + { + // alle Tabellen anlegen, damit Formeln kopiert werden koennen: + pUndoDoc->AddUndoTab( 0, nTabCount-1, FALSE, FALSE ); + + pRefUndoDoc->DeleteArea( nDestCol, nDestRow, nDestEndCol, nDestEndRow, aSourceMark, IDF_ALL ); + // kopieren mit bColRowFlags=FALSE (#54194#) + pRefUndoDoc->CopyToDocument( 0, 0, 0, MAXCOL, MAXROW, MAXTAB, + IDF_FORMULA, FALSE, pUndoDoc, NULL, FALSE ); + delete pRefUndoDoc; + } + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDragDrop( &rDocShell, ScRange( + nStartCol, nStartRow, nStartTab, + nOldEndCol, nOldEndRow, nEndTab ), + ScAddress( nDestCol, nDestRow, nDestTab ), + bCut, pUndoDoc, pUndoData, bScenariosAdded ) ); + } + + SCCOL nDestPaintEndCol = nDestEndCol; + SCROW nDestPaintEndRow = nDestEndRow; + for (nTab=nDestTab; nTab<=nDestEndTab; nTab++) + { + SCCOL nTmpEndCol = nDestEndCol; + SCROW nTmpEndRow = nDestEndRow; + pDoc->ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, TRUE ); + if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol; + if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow; + } + + if (bCut) + for (nTab=nStartTab; nTab<=nEndTab; nTab++) + pDoc->RefreshAutoFilter( nStartCol, nStartRow, nEndCol, nEndRow, nTab ); + + if (bPaint) + { + // Zielbereich: + + SCCOL nPaintStartX = nDestCol; + SCROW nPaintStartY = nDestRow; + SCCOL nPaintEndX = nDestPaintEndCol; + SCROW nPaintEndY = nDestPaintEndRow; + USHORT nFlags = PAINT_GRID; + + if ( nStartRow==0 && nEndRow==MAXROW ) // Breiten mitkopiert? + { + nPaintEndX = MAXCOL; + nPaintStartY = 0; + nPaintEndY = MAXROW; + nFlags |= PAINT_TOP; + } + if ( bDestHeight || ( nStartCol == 0 && nEndCol == MAXCOL ) ) + { + nPaintEndY = MAXROW; + nPaintStartX = 0; + nPaintEndX = MAXCOL; + nFlags |= PAINT_LEFT; + } + if ( bScenariosAdded ) + { + nPaintStartX = 0; + nPaintStartY = 0; + nPaintEndX = MAXCOL; + nPaintEndY = MAXROW; + } + + rDocShell.PostPaint( nPaintStartX,nPaintStartY,nDestTab, + nPaintEndX,nPaintEndY,nDestEndTab, nFlags, nSourceExt | nDestExt ); + + if ( bCut ) + { + // Quellbereich: + + nPaintStartX = nStartCol; + nPaintStartY = nStartRow; + nPaintEndX = nEndCol; + nPaintEndY = nEndRow; + nFlags = PAINT_GRID; + + if ( bSourceHeight ) + { + nPaintEndY = MAXROW; + nPaintStartX = 0; + nPaintEndX = MAXCOL; + nFlags |= PAINT_LEFT; + } + if ( bScenariosAdded ) + { + nPaintStartX = 0; + nPaintStartY = 0; + nPaintEndX = MAXCOL; + nPaintEndY = MAXROW; + } + + rDocShell.PostPaint( nPaintStartX,nPaintStartY,nStartTab, + nPaintEndX,nPaintEndY,nEndTab, nFlags, nSourceExt ); + } + } + + aModificator.SetDocumentModified(); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); + + delete pClipDoc; + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::InsertTable( SCTAB nTab, const String& rName, BOOL bRecord, BOOL bApi ) +{ + BOOL bSuccess = FALSE; + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + if (bRecord) + pDoc->BeginDrawUndo(); // InsertTab erzeugt ein SdrUndoNewPage + + SCTAB nTabCount = pDoc->GetTableCount(); + BOOL bAppend = ( nTab >= nTabCount ); + if ( bAppend ) + nTab = nTabCount; // wichtig fuer Undo + + if (pDoc->InsertTab( nTab, rName )) + { + if (bRecord) + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoInsertTab( &rDocShell, nTab, bAppend, rName)); + // Views updaten: + rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) ); + + rDocShell.PostPaintExtras(); + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + bSuccess = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(STR_TABINSERT_ERROR); + + return bSuccess; +} + +BOOL ScDocFunc::DeleteTable( SCTAB nTab, BOOL bRecord, BOOL /* bApi */ ) +{ + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + BOOL bWasLinked = pDoc->IsLinked(nTab); + ScDocument* pUndoDoc = NULL; + ScRefUndoData* pUndoData = NULL; + if (bRecord) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + SCTAB nCount = pDoc->GetTableCount(); + + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); // nur nTab mit Flags + pUndoDoc->AddUndoTab( 0, nCount-1 ); // alle Tabs fuer Referenzen + + pDoc->CopyToDocument(0,0,nTab, MAXCOL,MAXROW,nTab, IDF_ALL,FALSE, pUndoDoc ); + String aOldName; + pDoc->GetName( nTab, aOldName ); + pUndoDoc->RenameTab( nTab, aOldName, FALSE ); + if (bWasLinked) + pUndoDoc->SetLink( nTab, pDoc->GetLinkMode(nTab), pDoc->GetLinkDoc(nTab), + pDoc->GetLinkFlt(nTab), pDoc->GetLinkOpt(nTab), + pDoc->GetLinkTab(nTab), + pDoc->GetLinkRefreshDelay(nTab) ); + + if ( pDoc->IsScenario(nTab) ) + { + pUndoDoc->SetScenario( nTab, TRUE ); + String aComment; + Color aColor; + USHORT nScenFlags; + pDoc->GetScenarioData( nTab, aComment, aColor, nScenFlags ); + pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags ); + BOOL bActive = pDoc->IsActiveScenario( nTab ); + pUndoDoc->SetActiveScenario( nTab, bActive ); + } + pUndoDoc->SetVisible( nTab, pDoc->IsVisible( nTab ) ); + + // Drawing-Layer muss sein Undo selbst in der Hand behalten !!! + pDoc->BeginDrawUndo(); // DeleteTab erzeugt ein SdrUndoDelPage + + pUndoData = new ScRefUndoData( pDoc ); + } + + if (pDoc->DeleteTab( nTab, pUndoDoc )) + { + if (bRecord) + { + SvShorts theTabs; + theTabs.Insert(nTab,theTabs.Count()); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDeleteTab( &rDocShell, theTabs, pUndoDoc, pUndoData )); + } + // Views updaten: + rDocShell.Broadcast( ScTablesHint( SC_TAB_DELETED, nTab ) ); + + if (bWasLinked) + { + rDocShell.UpdateLinks(); // Link-Manager updaten + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate(SID_LINKS); + } + + rDocShell.PostPaintExtras(); + aModificator.SetDocumentModified(); + + SfxApplication* pSfxApp = SFX_APP(); // Navigator + pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); + pSfxApp->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); + + bSuccess = TRUE; + } + else + { + delete pUndoDoc; + delete pUndoData; + } + return bSuccess; +} + +BOOL ScDocFunc::SetTableVisible( SCTAB nTab, BOOL bVisible, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo(pDoc->IsUndoEnabled()); + if ( pDoc->IsVisible( nTab ) == bVisible ) + return TRUE; // nichts zu tun - ok + + if ( !pDoc->IsDocEditable() ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); + return FALSE; + } + + ScDocShellModificator aModificator( rDocShell ); + + if ( !bVisible && !pDoc->IsImportingXML() ) // #i57869# allow hiding in any order for loading + { + // nicht alle Tabellen ausblenden + + USHORT nVisCount = 0; + SCTAB nCount = pDoc->GetTableCount(); + for (SCTAB i=0; i<nCount; i++) + if (pDoc->IsVisible(i)) + ++nVisCount; + + if (nVisCount <= 1) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung? + return FALSE; + } + } + + pDoc->SetVisible( nTab, bVisible ); + if (bUndo) + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoShowHideTab( &rDocShell, nTab, bVisible ) ); + + // Views updaten: + if (!bVisible) + rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) ); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + rDocShell.PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS); + aModificator.SetDocumentModified(); + + return TRUE; +} + +BOOL ScDocFunc::SetLayoutRTL( SCTAB nTab, BOOL bRTL, BOOL /* bApi */ ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo(pDoc->IsUndoEnabled()); + if ( pDoc->IsLayoutRTL( nTab ) == bRTL ) + return TRUE; // nothing to do - ok + + //! protection (sheet or document?) + + ScDocShellModificator aModificator( rDocShell ); + + pDoc->SetLayoutRTL( nTab, bRTL ); + + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoLayoutRTL( &rDocShell, nTab, bRTL ) ); + } + + rDocShell.PostPaint( 0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_ALL ); + aModificator.SetDocumentModified(); + + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( FID_TAB_RTL ); + pBindings->Invalidate( SID_ATTR_SIZE ); + } + + return TRUE; +} + +//UNUSED2009-05 BOOL ScDocFunc::SetGrammar( formula::FormulaGrammar::Grammar eGrammar ) +//UNUSED2009-05 { +//UNUSED2009-05 ScDocument* pDoc = rDocShell.GetDocument(); +//UNUSED2009-05 +//UNUSED2009-05 if ( pDoc->GetGrammar() == eGrammar ) +//UNUSED2009-05 return TRUE; +//UNUSED2009-05 +//UNUSED2009-05 BOOL bUndo(pDoc->IsUndoEnabled()); +//UNUSED2009-05 ScDocShellModificator aModificator( rDocShell ); +//UNUSED2009-05 +//UNUSED2009-05 pDoc->SetGrammar( eGrammar ); +//UNUSED2009-05 +//UNUSED2009-05 if (bUndo) +//UNUSED2009-05 { +//UNUSED2009-05 rDocShell.GetUndoManager()->AddUndoAction( new ScUndoSetGrammar( &rDocShell, eGrammar ) ); +//UNUSED2009-05 } +//UNUSED2009-05 +//UNUSED2009-05 rDocShell.PostPaint( 0,0,0,MAXCOL,MAXROW,MAXTAB, PAINT_ALL ); +//UNUSED2009-05 +//UNUSED2009-05 ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); +//UNUSED2009-05 if (NULL != pViewSh) +//UNUSED2009-05 { +//UNUSED2009-05 pViewSh->UpdateInputHandler( FALSE, FALSE ); +//UNUSED2009-05 } +//UNUSED2009-05 +//UNUSED2009-05 aModificator.SetDocumentModified(); +//UNUSED2009-05 +//UNUSED2009-05 SfxBindings* pBindings = rDocShell.GetViewBindings(); +//UNUSED2009-05 if (pBindings) +//UNUSED2009-05 { +//UNUSED2009-05 // erAck: 2006-09-07T22:19+0200 commented out in CWS scr1c1 +//UNUSED2009-05 //pBindings->Invalidate( FID_TAB_USE_R1C1 ); +//UNUSED2009-05 } +//UNUSED2009-05 +//UNUSED2009-05 return TRUE; +//UNUSED2009-05 } + +BOOL ScDocFunc::RenameTable( SCTAB nTab, const String& rName, BOOL bRecord, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + if ( !pDoc->IsDocEditable() ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); + return FALSE; + } + + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + String sOldName; + pDoc->GetName(nTab, sOldName); + if (pDoc->RenameTab( nTab, rName )) + { + if (bRecord) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRenameTab( &rDocShell, nTab, sOldName, rName)); + } + rDocShell.PostPaintExtras(); + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + + bSuccess = TRUE; + } + return bSuccess; +} + +//------------------------------------------------------------------------ + +//! SetWidthOrHeight - noch doppelt zu ViewFunc !!!!!! +//! Probleme: +//! - Optimale Hoehe fuer Edit-Zellen ist unterschiedlich zwischen Drucker und Bildschirm +//! - Optimale Breite braucht Selektion, um evtl. nur selektierte Zellen zu beruecksichtigen + +USHORT lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab, BOOL bFormula ) +{ + USHORT nTwips = 0; + + ScSizeDeviceProvider aProv(&rDocShell); + OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode + double nPPTX = aProv.GetPPTX(); + double nPPTY = aProv.GetPPTY(); + + ScDocument* pDoc = rDocShell.GetDocument(); + Fraction aOne(1,1); + nTwips = pDoc->GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne, + bFormula, NULL ); + + return nTwips; +} + +BOOL ScDocFunc::SetWidthOrHeight( BOOL bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges, SCTAB nTab, + ScSizeMode eMode, USHORT nSizeTwips, + BOOL bRecord, BOOL bApi ) +{ + if (!nRangeCnt) + return TRUE; + + ScDocument* pDoc = rDocShell.GetDocument(); + if ( bRecord && !pDoc->IsUndoEnabled() ) + bRecord = FALSE; + + // import into read-only document is possible + if ( !pDoc->IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_PROTECTIONERR); //! eigene Meldung? + return FALSE; + } + + BOOL bSuccess = FALSE; + SCCOLROW nStart = pRanges[0]; + SCCOLROW nEnd = pRanges[2*nRangeCnt-1]; + + BOOL bFormula = FALSE; + if ( eMode == SC_SIZE_OPTIMAL ) + { + //! Option "Formeln anzeigen" - woher nehmen? + } + + ScDocument* pUndoDoc = NULL; + ScOutlineTable* pUndoTab = NULL; + SCCOLROW* pUndoRanges = NULL; + + if ( bRecord ) + { + pDoc->BeginDrawUndo(); // Drawing Updates + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if (bWidth) + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, FALSE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + else + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + pDoc->CopyToDocument( 0, static_cast<SCROW>(nStart), nTab, MAXCOL, static_cast<SCROW>(nEnd), nTab, IDF_NONE, FALSE, pUndoDoc ); + } + + pUndoRanges = new SCCOLROW[ 2*nRangeCnt ]; + memmove( pUndoRanges, pRanges, 2*nRangeCnt*sizeof(SCCOLROW) ); + + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + if (pTable) + pUndoTab = new ScOutlineTable( *pTable ); + } + + BOOL bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT; + BOOL bOutline = FALSE; + + pDoc->IncSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln + for (SCCOLROW nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++) + { + SCCOLROW nStartNo = *(pRanges++); + SCCOLROW nEndNo = *(pRanges++); + + if ( !bWidth ) // Hoehen immer blockweise + { + if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) + { + BOOL bAll = ( eMode==SC_SIZE_OPTIMAL ); + if (!bAll) + { + // fuer alle eingeblendeten CR_MANUALSIZE loeschen, + // dann SetOptimalHeight mit bShrink = FALSE + for (SCROW nRow=nStartNo; nRow<=nEndNo; nRow++) + { + BYTE nOld = pDoc->GetRowFlags(nRow,nTab); + if ( (nOld & CR_HIDDEN) == 0 && ( nOld & CR_MANUALSIZE ) ) + pDoc->SetRowFlags( nRow, nTab, nOld & ~CR_MANUALSIZE ); + } + } + + ScSizeDeviceProvider aProv( &rDocShell ); + Fraction aOne(1,1); + pDoc->SetOptimalHeight( nStartNo, nEndNo, nTab, 0, aProv.GetDevice(), + aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, bAll ); + + if (bAll) + pDoc->ShowRows( nStartNo, nEndNo, nTab, TRUE ); + + // Manual-Flag wird bei bAll=TRUE schon in SetOptimalHeight gesetzt + // (an bei Extra-Height, sonst aus). + } + else if ( eMode==SC_SIZE_DIRECT || eMode==SC_SIZE_ORIGINAL ) + { + if (nSizeTwips) + { + pDoc->SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips ); + pDoc->SetManualHeight( nStartNo, nEndNo, nTab, TRUE ); // height was set manually + } + if ( eMode != SC_SIZE_ORIGINAL ) + pDoc->ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 ); + } + else if ( eMode==SC_SIZE_SHOW ) + { + pDoc->ShowRows( nStartNo, nEndNo, nTab, TRUE ); + } + } + else // Spaltenbreiten + { + for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++) + { + if ( eMode != SC_SIZE_VISOPT || + (pDoc->GetColFlags( nCol, nTab ) & CR_HIDDEN) == 0 ) + { + USHORT nThisSize = nSizeTwips; + + if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT ) + nThisSize = nSizeTwips + + lcl_GetOptimalColWidth( rDocShell, nCol, nTab, bFormula ); + if ( nThisSize ) + pDoc->SetColWidth( nCol, nTab, nThisSize ); + + if ( eMode != SC_SIZE_ORIGINAL ) + pDoc->ShowCol( nCol, nTab, bShow ); + } + } + } + + // adjust outlines + + if ( eMode != SC_SIZE_ORIGINAL ) + { + if (bWidth) + bOutline = bOutline || pDoc->UpdateOutlineCol( + static_cast<SCCOL>(nStartNo), + static_cast<SCCOL>(nEndNo), nTab, bShow ); + else + bOutline = bOutline || pDoc->UpdateOutlineRow( + static_cast<SCROW>(nStartNo), + static_cast<SCROW>(nEndNo), nTab, bShow ); + } + } + pDoc->DecSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln + + if (!bOutline) + DELETEZ(pUndoTab); + + if (bRecord) + { + ScMarkData aMark; + aMark.SelectOneTable( nTab ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoWidthOrHeight( &rDocShell, aMark, + nStart, nTab, nEnd, nTab, + pUndoDoc, nRangeCnt, pUndoRanges, + pUndoTab, eMode, nSizeTwips, bWidth ) ); + } + + pDoc->UpdatePageBreaks( nTab ); + + rDocShell.PostPaint(0,0,nTab,MAXCOL,MAXROW,nTab,PAINT_ALL); + + return bSuccess; +} + + +BOOL ScDocFunc::InsertPageBreak( BOOL bColumn, const ScAddress& rPos, + BOOL bRecord, BOOL bSetModified, BOOL /* bApi */ ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + SCTAB nTab = rPos.Tab(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + + SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) : + static_cast<SCCOLROW>(rPos.Row()); + if (nPos == 0) + return FALSE; // erste Spalte / Zeile + + BYTE nFlags = bColumn ? pDoc->GetColFlags( static_cast<SCCOL>(nPos), nTab ) + : pDoc->GetRowFlags( static_cast<SCROW>(nPos), nTab ); + if (nFlags & CR_MANUALBREAK) + return TRUE; // Umbruch schon gesetzt + + if (bRecord) + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, TRUE ) ); + + nFlags |= CR_MANUALBREAK; + if (bColumn) + pDoc->SetColFlags( static_cast<SCCOL>(nPos), nTab, nFlags ); + else + pDoc->SetRowFlags( static_cast<SCROW>(nPos), nTab, nFlags ); + pDoc->UpdatePageBreaks( nTab ); + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + if (bColumn) + { + rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); + if (pBindings) + { + pBindings->Invalidate( FID_INS_COLBRK ); + pBindings->Invalidate( FID_DEL_COLBRK ); + } + } + else + { + rDocShell.PostPaint( 0, static_cast<SCROW>(nPos)-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); + if (pBindings) + { + pBindings->Invalidate( FID_INS_ROWBRK ); + pBindings->Invalidate( FID_DEL_ROWBRK ); + } + } + if (pBindings) + pBindings->Invalidate( FID_DEL_MANUALBREAKS ); + + if (bSetModified) + aModificator.SetDocumentModified(); + + return TRUE; +} + +BOOL ScDocFunc::RemovePageBreak( BOOL bColumn, const ScAddress& rPos, + BOOL bRecord, BOOL bSetModified, BOOL /* bApi */ ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + SCTAB nTab = rPos.Tab(); + SfxBindings* pBindings = rDocShell.GetViewBindings(); + + SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) : + static_cast<SCCOLROW>(rPos.Row()); + BYTE nFlags = bColumn ? pDoc->GetColFlags( static_cast<SCCOL>(nPos), nTab ) + : pDoc->GetRowFlags( static_cast<SCROW>(nPos), nTab ); + if ((nFlags & CR_MANUALBREAK)==0) + return FALSE; // kein Umbruch gesetzt + + if (bRecord) + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoPageBreak( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, FALSE ) ); + + nFlags &= ~CR_MANUALBREAK; + if (bColumn) + pDoc->SetColFlags( static_cast<SCCOL>(nPos), nTab, nFlags ); + else + pDoc->SetRowFlags( static_cast<SCROW>(nPos), nTab, nFlags ); + pDoc->UpdatePageBreaks( nTab ); + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + if (bColumn) + { + rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); + if (pBindings) + { + pBindings->Invalidate( FID_INS_COLBRK ); + pBindings->Invalidate( FID_DEL_COLBRK ); + } + } + else + { + rDocShell.PostPaint( 0, nPos-1, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID ); + if (pBindings) + { + pBindings->Invalidate( FID_INS_ROWBRK ); + pBindings->Invalidate( FID_DEL_ROWBRK ); + } + } + if (pBindings) + pBindings->Invalidate( FID_DEL_MANUALBREAKS ); + + if (bSetModified) + aModificator.SetDocumentModified(); + + return TRUE; +} + +//------------------------------------------------------------------------ + +void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + pDoc->SetTabProtection(nTab, &rProtect); + if (pDoc->IsUndoEnabled()) + { + ScTableProtection* pProtect = pDoc->GetTabProtection(nTab); + DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!"); + if (pProtect) + { + ::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect)); + p->setProtected(true); // just in case ... + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoTabProtect(&rDocShell, nTab, p) ); + + // ownership of auto_ptr now transferred to ScUndoTabProtect. + } + } + + rDocShell.PostPaintGridAll(); + ScDocShellModificator aModificator(rDocShell); + aModificator.SetDocumentModified(); +} + +BOOL ScDocFunc::Protect( SCTAB nTab, const String& rPassword, BOOL /*bApi*/ ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if (nTab == TABLEID_DOC) + { + // document protection + ScDocProtection aProtection; + aProtection.setProtected(true); + aProtection.setPassword(rPassword); + pDoc->SetDocProtection(&aProtection); + if (pDoc->IsUndoEnabled()) + { + ScDocProtection* pProtect = pDoc->GetDocProtection(); + DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScDocProtection pointer is NULL!"); + if (pProtect) + { + ::std::auto_ptr<ScDocProtection> p(new ScDocProtection(*pProtect)); + p->setProtected(true); // just in case ... + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDocProtect(&rDocShell, p) ); + // ownership of auto_ptr is transferred to ScUndoDocProtect. + } + } + } + else + { + // sheet protection + + ScTableProtection aProtection; + aProtection.setProtected(true); + aProtection.setPassword(rPassword); + pDoc->SetTabProtection(nTab, &aProtection); + if (pDoc->IsUndoEnabled()) + { + ScTableProtection* pProtect = pDoc->GetTabProtection(nTab); + DBG_ASSERT(pProtect, "ScDocFunc::Unprotect: ScTableProtection pointer is NULL!"); + if (pProtect) + { + ::std::auto_ptr<ScTableProtection> p(new ScTableProtection(*pProtect)); + p->setProtected(true); // just in case ... + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoTabProtect(&rDocShell, nTab, p) ); + // ownership of auto_ptr now transferred to ScUndoTabProtect. + } + } + } + + rDocShell.PostPaintGridAll(); + ScDocShellModificator aModificator( rDocShell ); + aModificator.SetDocumentModified(); + + return true; +} + +BOOL ScDocFunc::Unprotect( SCTAB nTab, const String& rPassword, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + if (nTab == TABLEID_DOC) + { + // document protection + + ScDocProtection* pDocProtect = pDoc->GetDocProtection(); + if (!pDocProtect || !pDocProtect->isProtected()) + // already unprotected (should not happen)! + return true; + + // save the protection state before unprotect (for undo). + ::std::auto_ptr<ScDocProtection> pProtectCopy(new ScDocProtection(*pDocProtect)); + + if (!pDocProtect->verifyPassword(rPassword)) + { + if (!bApi) + { + InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) ); + aBox.Execute(); + } + return false; + } + + pDoc->SetDocProtection(NULL); + if (pDoc->IsUndoEnabled()) + { + pProtectCopy->setProtected(false); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDocProtect(&rDocShell, pProtectCopy) ); + // ownership of auto_ptr now transferred to ScUndoDocProtect. + } + } + else + { + // sheet protection + + ScTableProtection* pTabProtect = pDoc->GetTabProtection(nTab); + if (!pTabProtect || !pTabProtect->isProtected()) + // already unprotected (should not happen)! + return true; + + // save the protection state before unprotect (for undo). + ::std::auto_ptr<ScTableProtection> pProtectCopy(new ScTableProtection(*pTabProtect)); + if (!pTabProtect->verifyPassword(rPassword)) + { + if (!bApi) + { + InfoBox aBox( rDocShell.GetActiveDialogParent(), String( ScResId( SCSTR_WRONGPASSWORD ) ) ); + aBox.Execute(); + } + return false; + } + + pDoc->SetTabProtection(nTab, NULL); + if (pDoc->IsUndoEnabled()) + { + pProtectCopy->setProtected(false); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoTabProtect(&rDocShell, nTab, pProtectCopy) ); + // ownership of auto_ptr now transferred to ScUndoTabProtect. + } + } + + rDocShell.PostPaintGridAll(); + ScDocShellModificator aModificator( rDocShell ); + aModificator.SetDocumentModified(); + + return true; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::ClearItems( const ScMarkData& rMark, const USHORT* pWhich, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + ScEditableTester aTester( pDoc, rMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + // #i12940# ClearItems is called (from setPropertyToDefault) directly with uno object's cached + // MarkData (GetMarkData), so rMark must be changed to multi selection for ClearSelectionItems + // here. + + ScRange aMarkRange; + ScMarkData aMultiMark = rMark; + aMultiMark.SetMarking(FALSE); // for MarkToMulti + aMultiMark.MarkToMulti(); + aMultiMark.GetMultiMarkArea( aMarkRange ); + +// if (bRecord) + if (bUndo) + { + SCTAB nStartTab = aMarkRange.aStart.Tab(); + SCTAB nEndTab = aMarkRange.aEnd.Tab(); + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab ); + pDoc->CopyToDocument( aMarkRange, IDF_ATTRIB, TRUE, pUndoDoc, (ScMarkData*)&aMultiMark ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoClearItems( &rDocShell, aMultiMark, pUndoDoc, pWhich ) ); + } + + pDoc->ClearSelectionItems( pWhich, aMultiMark ); + + rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE ); + aModificator.SetDocumentModified(); + + //! Bindings-Invalidate etc.? + + return TRUE; +} + +BOOL ScDocFunc::ChangeIndent( const ScMarkData& rMark, BOOL bIncrement, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo(pDoc->IsUndoEnabled()); + ScEditableTester aTester( pDoc, rMark ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + ScRange aMarkRange; + rMark.GetMultiMarkArea( aMarkRange ); + +// if (bRecord) + if (bUndo) + { + SCTAB nStartTab = aMarkRange.aStart.Tab(); + SCTAB nTabCount = pDoc->GetTableCount(); + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nStartTab && rMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + ScRange aCopyRange = aMarkRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, TRUE, pUndoDoc, (ScMarkData*)&rMark ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoIndent( &rDocShell, rMark, pUndoDoc, bIncrement ) ); + } + + pDoc->ChangeSelectionIndent( bIncrement, rMark ); + + rDocShell.PostPaint( aMarkRange, PAINT_GRID, SC_PF_LINES | SC_PF_TESTMERGE ); + aModificator.SetDocumentModified(); + + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( SID_ALIGNLEFT ); // ChangeIndent setzt auf links + pBindings->Invalidate( SID_ALIGNRIGHT ); + pBindings->Invalidate( SID_ALIGNBLOCK ); + pBindings->Invalidate( SID_ALIGNCENTERHOR ); + // pseudo slots for Format menu + pBindings->Invalidate( SID_ALIGN_ANY_HDEFAULT ); + pBindings->Invalidate( SID_ALIGN_ANY_LEFT ); + pBindings->Invalidate( SID_ALIGN_ANY_HCENTER ); + pBindings->Invalidate( SID_ALIGN_ANY_RIGHT ); + pBindings->Invalidate( SID_ALIGN_ANY_JUSTIFIED ); + } + + return TRUE; +} + +BOOL ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark, + USHORT nFormatNo, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat(); + ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); + if ( pAutoFormat && nFormatNo < pAutoFormat->GetCount() && aTester.IsEditable() ) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + BOOL bSize = (*pAutoFormat)[nFormatNo]->GetIncludeWidthHeight(); + + SCTAB nTabCount = pDoc->GetTableCount(); + ScDocument* pUndoDoc = NULL; + if ( bRecord ) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab, bSize, bSize ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nStartTab && aMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i, bSize, bSize ); + + ScRange aCopyRange = rRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aStart.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, FALSE, pUndoDoc, &aMark ); + if (bSize) + { + pDoc->CopyToDocument( nStartCol,0,0, nEndCol,MAXROW,nTabCount-1, + IDF_NONE, FALSE, pUndoDoc, &aMark ); + pDoc->CopyToDocument( 0,nStartRow,0, MAXCOL,nEndRow,nTabCount-1, + IDF_NONE, FALSE, pUndoDoc, &aMark ); + } + pDoc->BeginDrawUndo(); + } + + pDoc->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark ); + + if (bSize) + { +/* SCCOL nCols[2]; + nCols[0] = nStartCol; + nCols[1] = nEndCol; + SCROW nRows[2]; + nRows[0] = nStartRow; + nRows[1] = nEndRow; +*/ + SCCOLROW nCols[2] = { nStartCol, nEndCol }; + SCCOLROW nRows[2] = { nStartRow, nEndRow }; + + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (aMark.GetTableSelect(nTab)) + { + SetWidthOrHeight( TRUE, 1,nCols, nTab, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, FALSE, TRUE); + SetWidthOrHeight( FALSE,1,nRows, nTab, SC_SIZE_VISOPT, 0, FALSE, FALSE); + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, + PAINT_GRID | PAINT_LEFT | PAINT_TOP ); + } + } + else + { + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (aMark.GetTableSelect(nTab)) + { + BOOL bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab), FALSE ); + if (bAdj) + rDocShell.PostPaint( 0,nStartRow,nTab, MAXCOL,MAXROW,nTab, + PAINT_GRID | PAINT_LEFT ); + else + rDocShell.PostPaint( nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab, PAINT_GRID ); + } + } + + if ( bRecord ) // Draw-Undo erst jetzt verfuegbar + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoFormat( &rDocShell, rRange, pUndoDoc, aMark, bSize, nFormatNo ) ); + } + + aModificator.SetDocumentModified(); + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + + return bSuccess; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, + const ScTokenArray* pTokenArray, const String& rString, BOOL bApi, BOOL bEnglish, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) +{ + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + BOOL bUndo(pDoc->IsUndoEnabled()); + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); + if ( aTester.IsEditable() ) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScDocument* pUndoDoc = NULL; +// if (bRecord) // immer + if (bUndo) + { + //! auch bei Undo selektierte Tabellen beruecksichtigen + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab ); + pDoc->CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, FALSE, pUndoDoc ); + } + + // use TokenArray if given, string (and flags) otherwise + if ( pTokenArray ) + { + pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, + aMark, EMPTY_STRING, pTokenArray, eGrammar); + } + else if ( pDoc->IsImportingXML() ) + { + ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString, rFormulaNmsp, eGrammar ); + pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, + aMark, EMPTY_STRING, pCode, eGrammar); + delete pCode; + pDoc->IncXMLImportedFormulaCount( rString.Len() ); + } + else if (bEnglish) + { + ScCompiler aComp( pDoc, rRange.aStart); + aComp.SetGrammar(eGrammar); + ScTokenArray* pCode = aComp.CompileString( rString ); + pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, + aMark, EMPTY_STRING, pCode, eGrammar); + delete pCode; + } + else + pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, + aMark, rString, NULL, eGrammar); + +// if (bRecord) // immer + if (bUndo) + { + //! auch bei Undo selektierte Tabellen beruecksichtigen + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoEnterMatrix( &rDocShell, rRange, pUndoDoc, rString ) ); + } + + // Err522 beim Paint von DDE-Formeln werden jetzt beim Interpretieren abgefangen + rDocShell.PostPaint( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab, PAINT_GRID ); + aModificator.SetDocumentModified(); + + bSuccess = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + + return bSuccess; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark, + const ScTabOpParam& rParam, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); + if ( aTester.IsEditable() ) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + pDoc->SetDirty( rRange ); + if ( bRecord ) + { + //! auch bei Undo selektierte Tabellen beruecksichtigen + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nStartTab, nEndTab ); + pDoc->CopyToDocument( rRange, IDF_ALL & ~IDF_NOTE, FALSE, pUndoDoc ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoTabOp( &rDocShell, + nStartCol, nStartRow, nStartTab, + nEndCol, nEndRow, nEndTab, pUndoDoc, + rParam.aRefFormulaCell, + rParam.aRefFormulaEnd, + rParam.aRefRowCell, + rParam.aRefColCell, + rParam.nMode) ); + } + pDoc->InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark); + rDocShell.PostPaintGridAll(); + aModificator.SetDocumentModified(); + bSuccess = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + + return bSuccess; +} + +//------------------------------------------------------------------------ + +inline ScDirection DirFromFillDir( FillDir eDir ) +{ + if (eDir==FILL_TO_BOTTOM) + return DIR_BOTTOM; + else if (eDir==FILL_TO_RIGHT) + return DIR_RIGHT; + else if (eDir==FILL_TO_TOP) + return DIR_TOP; + else // if (eDir==FILL_TO_LEFT) + return DIR_LEFT; +} + +BOOL ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark, + FillDir eDir, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); + if ( aTester.IsEditable() ) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScRange aSourceArea = rRange; + ScRange aDestArea = rRange; + + SCCOLROW nCount = 0; + switch (eDir) + { + case FILL_TO_BOTTOM: + nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); + aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() ); + break; + case FILL_TO_RIGHT: + nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); + aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() ); + break; + case FILL_TO_TOP: + nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row(); + aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() ); + break; + case FILL_TO_LEFT: + nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col(); + aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() ); + break; + } + + ScDocument* pUndoDoc = NULL; + if ( bRecord ) + { + SCTAB nTabCount = pDoc->GetTableCount(); + SCTAB nDestStartTab = aDestArea.aStart.Tab(); + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nDestStartTab && aMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + ScRange aCopyRange = aDestArea; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_AUTOFILL, FALSE, pUndoDoc, &aMark ); + } + + pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), + aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, + nCount, eDir, FILL_SIMPLE ); + AdjustRowHeight(rRange); + + if ( bRecord ) // Draw-Undo erst jetzt verfuegbar + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, + eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307, + pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + } + + rDocShell.PostPaintGridAll(); +// rDocShell.PostPaintDataChanged(); + aModificator.SetDocumentModified(); + + bSuccess = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + + return bSuccess; +} + +BOOL ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark, + FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, + double fStart, double fStep, double fMax, + BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScEditableTester aTester( pDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark ); + if ( aTester.IsEditable() ) + { + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScRange aSourceArea = rRange; + ScRange aDestArea = rRange; + + SCSIZE nCount = pDoc->GetEmptyLinesInBlock( + aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(), + aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(), + DirFromFillDir(eDir) ); + + // #27665# mindestens eine Zeile/Spalte als Quellbereich behalten: + SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ? + static_cast<SCSIZE>( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) : + static_cast<SCSIZE>( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 ); + if ( nCount >= nTotLines ) + nCount = nTotLines - 1; + + switch (eDir) + { + case FILL_TO_BOTTOM: + aSourceArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() - nCount ) ); + break; + case FILL_TO_RIGHT: + aSourceArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() - nCount ) ); + break; + case FILL_TO_TOP: + aSourceArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() + nCount ) ); + break; + case FILL_TO_LEFT: + aSourceArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() + nCount ) ); + break; + } + + ScDocument* pUndoDoc = NULL; + if ( bRecord ) + { + SCTAB nTabCount = pDoc->GetTableCount(); + SCTAB nDestStartTab = aDestArea.aStart.Tab(); + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nDestStartTab && aMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + pDoc->CopyToDocument( + aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, + aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, + IDF_AUTOFILL, FALSE, pUndoDoc, &aMark ); + } + + if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() && + aDestArea.aStart.Row() <= aDestArea.aEnd.Row()) + { + if ( fStart != MAXDOUBLE ) + { + SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col(); + SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row(); + SCTAB nTab = aDestArea.aStart.Tab(); + pDoc->SetValue( nValX, nValY, nTab, fStart ); + } + pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), + aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, + nCount, eDir, eCmd, eDateCmd, fStep, fMax ); + AdjustRowHeight(rRange); + + rDocShell.PostPaintGridAll(); +// rDocShell.PostPaintDataChanged(); + aModificator.SetDocumentModified(); + } + + if ( bRecord ) // Draw-Undo erst jetzt verfuegbar + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, + eDir, eCmd, eDateCmd, fStart, fStep, fMax, + pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + } + + bSuccess = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + + return bSuccess; +} + +BOOL ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, + FillDir eDir, ULONG nCount, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScMarkData aMark; + if (pTabMark) + aMark = *pTabMark; + else + { + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + aMark.SelectTable( nTab, TRUE ); + } + + ScRange aSourceArea = rRange; + ScRange aDestArea = rRange; + + FillCmd eCmd = FILL_AUTO; + FillDateCmd eDateCmd = FILL_DAY; + double fStep = 1.0; + double fMax = MAXDOUBLE; + + switch (eDir) + { + case FILL_TO_BOTTOM: + aDestArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() + nCount ) ); + break; + case FILL_TO_TOP: + if (nCount > sal::static_int_cast<ULONG>( aSourceArea.aStart.Row() )) + { + DBG_ERROR("FillAuto: Row < 0"); + nCount = aSourceArea.aStart.Row(); + } + aDestArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() - nCount ) ); + break; + case FILL_TO_RIGHT: + aDestArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() + nCount ) ); + break; + case FILL_TO_LEFT: + if (nCount > sal::static_int_cast<ULONG>( aSourceArea.aStart.Col() )) + { + DBG_ERROR("FillAuto: Col < 0"); + nCount = aSourceArea.aStart.Col(); + } + aDestArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() - nCount ) ); + break; + default: + DBG_ERROR("Falsche Richtung bei FillAuto"); + break; + } + + // Zellschutz testen + //! Quellbereich darf geschuetzt sein !!! + //! aber kein Matrixfragment enthalten !!! + + ScEditableTester aTester( pDoc, aDestArea ); + if ( !aTester.IsEditable() ) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + if ( pDoc->HasSelectedBlockMatrixFragment( nStartCol, nStartRow, + nEndCol, nEndRow, aMark ) ) + { + if (!bApi) + rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR); + return FALSE; + } + + WaitObject aWait( rDocShell.GetActiveDialogParent() ); + + ScDocument* pUndoDoc = NULL; + if ( bRecord ) + { + SCTAB nTabCount = pDoc->GetTableCount(); + SCTAB nDestStartTab = aDestArea.aStart.Tab(); + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nDestStartTab, nDestStartTab ); + for (SCTAB i=0; i<nTabCount; i++) + if (i != nDestStartTab && aMark.GetTableSelect(i)) + pUndoDoc->AddUndoTab( i, i ); + + // do not clone note captions in undo document + pDoc->CopyToDocument( + aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0, + aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1, + IDF_AUTOFILL, FALSE, pUndoDoc, &aMark ); + } + + pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), + aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, + nCount, eDir, eCmd, eDateCmd, fStep, fMax ); + + AdjustRowHeight(aDestArea); + + if ( bRecord ) // Draw-Undo erst jetzt verfuegbar + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, + eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax, + pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + } + + rDocShell.PostPaintGridAll(); +// rDocShell.PostPaintDataChanged(); + aModificator.SetDocumentModified(); + + rRange = aDestArea; // Zielbereich zurueckgeben (zum Markieren) + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::MergeCells( const ScRange& rRange, BOOL bContents, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow ); + if (!aTester.IsEditable()) + { + if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + return FALSE; + } + + if ( nStartCol == nEndCol && nStartRow == nEndRow ) + { + // nichts zu tun + return TRUE; + } + + if ( pDoc->HasAttrib( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, + HASATTR_MERGED | HASATTR_OVERLAPPED ) ) + { + // "Zusammenfassen nicht verschachteln !" + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0); + return FALSE; + } + + BOOL bNeedContents = bContents && + ( !pDoc->IsBlockEmpty( nTab, nStartCol,nStartRow+1, nStartCol,nEndRow, true ) || + !pDoc->IsBlockEmpty( nTab, nStartCol+1,nStartRow, nEndCol,nEndRow, true ) ); + + ScDocument* pUndoDoc = 0; + if (bRecord) + { + // test if the range contains other notes which also implies that we need an undo document + bool bHasNotes = false; + for( ScAddress aPos( nStartCol, nStartRow, nTab ); !bHasNotes && (aPos.Col() <= nEndCol); aPos.IncCol() ) + for( aPos.SetRow( nStartRow ); !bHasNotes && (aPos.Row() <= nEndRow); aPos.IncRow() ) + bHasNotes = ((aPos.Col() != nStartCol) || (aPos.Row() != nStartRow)) && (pDoc->GetNote( aPos ) != 0); + + if (bNeedContents || bHasNotes) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab ); + // note captions are collected by drawing undo + pDoc->CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, + IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc ); + } + if( bHasNotes ) + pDoc->BeginDrawUndo(); + } + + if (bNeedContents) + pDoc->DoMergeContents( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); + pDoc->DoMerge( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); + + if( bRecord ) + { + SdrUndoGroup* pDrawUndo = pDoc->GetDrawLayer() ? pDoc->GetDrawLayer()->GetCalcUndo() : 0; + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoMerge( &rDocShell, + nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab, bNeedContents, pUndoDoc, pDrawUndo ) ); + } + + if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab ) ) ) + rDocShell.PostPaint( nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab, PAINT_GRID ); + if (bNeedContents) + pDoc->SetDirty( rRange ); + aModificator.SetDocumentModified(); + + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( FID_MERGE_ON ); + pBindings->Invalidate( FID_MERGE_OFF ); + pBindings->Invalidate( FID_MERGE_TOGGLE ); + } + + return TRUE; +} + +BOOL ScDocFunc::UnmergeCells( const ScRange& rRange, BOOL bRecord, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + ScDocument* pDoc = rDocShell.GetDocument(); + SCTAB nTab = rRange.aStart.Tab(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + if ( pDoc->HasAttrib( rRange, HASATTR_MERGED ) ) + { + ScRange aExtended = rRange; + pDoc->ExtendMerge( aExtended ); + ScRange aRefresh = aExtended; + pDoc->ExtendOverlapped( aRefresh ); + + if (bRecord) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( aExtended, IDF_ATTRIB, FALSE, pUndoDoc ); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRemoveMerge( &rDocShell, rRange, pUndoDoc ) ); + } + + const SfxPoolItem& rDefAttr = pDoc->GetPool()->GetDefaultItem( ATTR_MERGE ); + ScPatternAttr aPattern( pDoc->GetPool() ); + aPattern.GetItemSet().Put( rDefAttr ); + pDoc->ApplyPatternAreaTab( rRange.aStart.Col(), rRange.aStart.Row(), + rRange.aEnd.Col(), rRange.aEnd.Row(), nTab, + aPattern ); + + pDoc->RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(), + aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab, + SC_MF_HOR | SC_MF_VER ); + + pDoc->ExtendMerge( aRefresh, TRUE, FALSE ); + + if ( !AdjustRowHeight( aExtended ) ) + rDocShell.PostPaint( aExtended, PAINT_GRID ); + aModificator.SetDocumentModified(); + } + else if (!bApi) + Sound::Beep(); //! FALSE zurueck??? + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, BOOL bApi ) +{ + return SetNewRangeNames( new ScRangeName( rNewRanges ), bApi ); +} + +BOOL ScDocFunc::SetNewRangeNames( ScRangeName* pNewRanges, BOOL /* bApi */ ) // takes ownership of pNewRanges +{ + ScDocShellModificator aModificator( rDocShell ); + + DBG_ASSERT( pNewRanges, "pNewRanges is 0" ); + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo(pDoc->IsUndoEnabled()); + + if (bUndo) + { + ScRangeName* pOld = pDoc->GetRangeName(); + ScRangeName* pUndoRanges = new ScRangeName(*pOld); + ScRangeName* pRedoRanges = new ScRangeName(*pNewRanges); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRangeNames( &rDocShell, pUndoRanges, pRedoRanges ) ); + } + + // #i55926# While loading XML, formula cells only have a single string token, + // so CompileNameFormula would never find any name (index) tokens, and would + // unnecessarily loop through all cells. + BOOL bCompile = ( !pDoc->IsImportingXML() && pDoc->GetNamedRangesLockCount() == 0 ); + + if ( bCompile ) + pDoc->CompileNameFormula( TRUE ); // CreateFormulaString + pDoc->SetRangeName( pNewRanges ); // takes ownership + if ( bCompile ) + pDoc->CompileNameFormula( FALSE ); // CompileFormulaString + + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) ); + + return TRUE; +} + +//------------------------------------------------------------------------ + +void ScDocFunc::CreateOneName( ScRangeName& rList, + SCCOL nPosX, SCROW nPosY, SCTAB nTab, + SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, + BOOL& rCancel, BOOL bApi ) +{ + if (rCancel) + return; + + ScDocument* pDoc = rDocShell.GetDocument(); + if (!pDoc->HasValueData( nPosX, nPosY, nTab )) + { + String aName; + pDoc->GetString( nPosX, nPosY, nTab, aName ); + ScRangeData::MakeValidName(aName); + if (aName.Len()) + { + String aContent; + ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format( aContent, SCR_ABS_3D, pDoc ); + + BOOL bInsert = FALSE; + USHORT nOldPos; + if (rList.SearchName( aName, nOldPos )) // vorhanden ? + { + ScRangeData* pOld = rList[nOldPos]; + String aOldStr; + pOld->GetSymbol( aOldStr ); + if (aOldStr != aContent) + { + if (bApi) + bInsert = TRUE; // per API nicht nachfragen + else + { + String aTemplate = ScGlobal::GetRscString( STR_CREATENAME_REPLACE ); + + String aMessage = aTemplate.GetToken( 0, '#' ); + aMessage += aName; + aMessage += aTemplate.GetToken( 1, '#' ); + + short nResult = QueryBox( rDocShell.GetActiveDialogParent(), + WinBits(WB_YES_NO_CANCEL | WB_DEF_YES), + aMessage ).Execute(); + if ( nResult == RET_YES ) + { + rList.AtFree(nOldPos); + bInsert = TRUE; + } + else if ( nResult == RET_CANCEL ) + rCancel = TRUE; + } + } + } + else + bInsert = TRUE; + + if (bInsert) + { + ScRangeData* pData = new ScRangeData( pDoc, aName, aContent, + ScAddress( nPosX, nPosY, nTab)); + if (!rList.Insert(pData)) + { + DBG_ERROR("nanu?"); + delete pData; + } + } + } + } +} + +BOOL ScDocFunc::CreateNames( const ScRange& rRange, USHORT nFlags, BOOL bApi ) +{ + if (!nFlags) + return FALSE; // war nix + + ScDocShellModificator aModificator( rDocShell ); + + BOOL bDone = FALSE; + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + DBG_ASSERT(rRange.aEnd.Tab() == nTab, "CreateNames: mehrere Tabellen geht nicht"); + + BOOL bValid = TRUE; + if ( nFlags & ( NAME_TOP | NAME_BOTTOM ) ) + if ( nStartRow == nEndRow ) + bValid = FALSE; + if ( nFlags & ( NAME_LEFT | NAME_RIGHT ) ) + if ( nStartCol == nEndCol ) + bValid = FALSE; + + if (bValid) + { + ScDocument* pDoc = rDocShell.GetDocument(); + ScRangeName* pNames = pDoc->GetRangeName(); + if (!pNames) + return FALSE; // soll nicht sein + ScRangeName aNewRanges( *pNames ); + + BOOL bTop = ( ( nFlags & NAME_TOP ) != 0 ); + BOOL bLeft = ( ( nFlags & NAME_LEFT ) != 0 ); + BOOL bBottom = ( ( nFlags & NAME_BOTTOM ) != 0 ); + BOOL bRight = ( ( nFlags & NAME_RIGHT ) != 0 ); + + SCCOL nContX1 = nStartCol; + SCROW nContY1 = nStartRow; + SCCOL nContX2 = nEndCol; + SCROW nContY2 = nEndRow; + + if ( bTop ) + ++nContY1; + if ( bLeft ) + ++nContX1; + if ( bBottom ) + --nContY2; + if ( bRight ) + --nContX2; + + BOOL bCancel = FALSE; + SCCOL i; + SCROW j; + + if ( bTop ) + for (i=nContX1; i<=nContX2; i++) + CreateOneName( aNewRanges, i,nStartRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); + if ( bLeft ) + for (j=nContY1; j<=nContY2; j++) + CreateOneName( aNewRanges, nStartCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); + if ( bBottom ) + for (i=nContX1; i<=nContX2; i++) + CreateOneName( aNewRanges, i,nEndRow,nTab, i,nContY1,i,nContY2, bCancel, bApi ); + if ( bRight ) + for (j=nContY1; j<=nContY2; j++) + CreateOneName( aNewRanges, nEndCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi ); + + if ( bTop && bLeft ) + CreateOneName( aNewRanges, nStartCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); + if ( bTop && bRight ) + CreateOneName( aNewRanges, nEndCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); + if ( bBottom && bLeft ) + CreateOneName( aNewRanges, nStartCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); + if ( bBottom && bRight ) + CreateOneName( aNewRanges, nEndCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi ); + + bDone = ModifyRangeNames( aNewRanges, bApi ); + + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) ); + } + + return bDone; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::InsertNameList( const ScAddress& rStartPos, BOOL bApi ) +{ + ScDocShellModificator aModificator( rDocShell ); + + + BOOL bDone = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + const BOOL bRecord = pDoc->IsUndoEnabled(); + SCTAB nTab = rStartPos.Tab(); + ScDocument* pUndoDoc = NULL; + + ScRangeName* pList = pDoc->GetRangeName(); + USHORT nCount = pList->GetCount(); + USHORT nValidCount = 0; + USHORT i; + for (i=0; i<nCount; i++) + { + ScRangeData* pData = (*pList)[i]; + if ( !pData->HasType( RT_DATABASE ) && !pData->HasType( RT_SHARED ) ) + ++nValidCount; + } + + if (nValidCount) + { + SCCOL nStartCol = rStartPos.Col(); + SCROW nStartRow = rStartPos.Row(); + SCCOL nEndCol = nStartCol + 1; + SCROW nEndRow = nStartRow + static_cast<SCROW>(nValidCount) - 1; + + ScEditableTester aTester( pDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow ); + if (aTester.IsEditable()) + { + if (bRecord) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, + IDF_ALL, FALSE, pUndoDoc ); + + pDoc->BeginDrawUndo(); // wegen Hoehenanpassung + } + + ScRangeData** ppSortArray = new ScRangeData* [ nValidCount ]; + USHORT j = 0; + for (i=0; i<nCount; i++) + { + ScRangeData* pData = (*pList)[i]; + if ( !pData->HasType( RT_DATABASE ) && !pData->HasType( RT_SHARED ) ) + ppSortArray[j++] = pData; + } +#ifndef ICC + qsort( (void*)ppSortArray, nValidCount, sizeof(ScRangeData*), + &ScRangeData_QsortNameCompare ); +#else + qsort( (void*)ppSortArray, nValidCount, sizeof(ScRangeData*), + ICCQsortNameCompare ); +#endif + String aName; + rtl::OUStringBuffer aContent; + String aFormula; + SCROW nOutRow = nStartRow; + for (j=0; j<nValidCount; j++) + { + ScRangeData* pData = ppSortArray[j]; + pData->GetName(aName); + // relative Referenzen Excel-konform auf die linke Spalte anpassen: + pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab )); + aFormula = '='; + aFormula += aContent; + pDoc->PutCell( nStartCol,nOutRow,nTab, new ScStringCell( aName ) ); + pDoc->PutCell( nEndCol ,nOutRow,nTab, new ScStringCell( aFormula ) ); + ++nOutRow; + } + + delete [] ppSortArray; + + if (bRecord) + { + ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRedoDoc->InitUndo( pDoc, nTab, nTab ); + pDoc->CopyToDocument( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, + IDF_ALL, FALSE, pRedoDoc ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoListNames( &rDocShell, + ScRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ), + pUndoDoc, pRedoDoc ) ); + } + + if (!AdjustRowHeight(ScRange(0,nStartRow,nTab,MAXCOL,nEndRow,nTab))) + rDocShell.PostPaint( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, PAINT_GRID ); +//! rDocShell.UpdateOle(GetViewData()); + aModificator.SetDocumentModified(); + bDone = TRUE; + } + else if (!bApi) + rDocShell.ErrorMessage(aTester.GetMessageId()); + } + return bDone; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd, BOOL bApi ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + SCCOL nStartCol = rOldRange.aStart.Col(); + SCROW nStartRow = rOldRange.aStart.Row(); + SCTAB nTab = rOldRange.aStart.Tab(); + + BOOL bUndo(pDoc->IsUndoEnabled()); + + BOOL bRet = FALSE; + + String aFormula; + pDoc->GetFormula( nStartCol, nStartRow, nTab, aFormula ); + if ( aFormula.GetChar(0) == '{' && aFormula.GetChar(aFormula.Len()-1) == '}' ) + { + String aUndo = ScGlobal::GetRscString( STR_UNDO_RESIZEMATRIX ); + if (bUndo) + rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); + + aFormula.Erase(0,1); + aFormula.Erase(aFormula.Len()-1,1); + + ScMarkData aMark; + aMark.SetMarkArea( rOldRange ); + aMark.SelectTable( nTab, TRUE ); + ScRange aNewRange( rOldRange.aStart, rNewEnd ); + + if ( DeleteContents( aMark, IDF_CONTENTS, TRUE, bApi ) ) + { + // GRAM_PODF_A1 for API compatibility. + bRet = EnterMatrix( aNewRange, &aMark, NULL, aFormula, bApi, FALSE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); + if (!bRet) + { + // versuchen, alten Zustand wiederherzustellen + EnterMatrix( rOldRange, &aMark, NULL, aFormula, bApi, FALSE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); + } + } + + if (bUndo) + rDocShell.GetUndoManager()->LeaveListAction(); + } + + return bRet; +} + +//------------------------------------------------------------------------ + +BOOL ScDocFunc::InsertAreaLink( const String& rFile, const String& rFilter, + const String& rOptions, const String& rSource, + const ScRange& rDestRange, ULONG nRefresh, + BOOL bFitBlock, BOOL bApi ) +{ + //! auch fuer ScViewFunc::InsertAreaLink benutzen! + + ScDocument* pDoc = rDocShell.GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager(); + + // #i52120# if other area links exist at the same start position, + // remove them first (file format specifies only one link definition + // for a cell) + + USHORT nLinkCount = pLinkManager->GetLinks().Count(); + USHORT nRemoved = 0; + USHORT nLinkPos = 0; + while (nLinkPos<nLinkCount) + { + ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[nLinkPos]; + if ( pBase->ISA(ScAreaLink) && + static_cast<ScAreaLink*>(pBase)->GetDestArea().aStart == rDestRange.aStart ) + { + if ( bUndo ) + { + if ( !nRemoved ) + { + // group all remove and the insert action + String aUndo = ScGlobal::GetRscString( STR_UNDO_INSERTAREALINK ); + rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo ); + } + + ScAreaLink* pOldArea = static_cast<ScAreaLink*>(pBase); + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRemoveAreaLink( &rDocShell, + pOldArea->GetFile(), pOldArea->GetFilter(), pOldArea->GetOptions(), + pOldArea->GetSource(), pOldArea->GetDestArea(), pOldArea->GetRefreshDelay() ) ); + } + pLinkManager->Remove( pBase ); + nLinkCount = pLinkManager->GetLinks().Count(); + ++nRemoved; + } + else + ++nLinkPos; + } + + String aFilterName = rFilter; + String aNewOptions = rOptions; + if (!aFilterName.Len()) + ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, TRUE, !bApi ); + + // remove application prefix from filter name here, so the filter options + // aren't reset when the filter name is changed in ScAreaLink::DataChanged + ScDocumentLoader::RemoveAppPrefix( aFilterName ); + + ScAreaLink* pLink = new ScAreaLink( &rDocShell, rFile, aFilterName, + aNewOptions, rSource, rDestRange, nRefresh ); + pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, rFile, &aFilterName, &rSource ); + + // Undo fuer den leeren Link + + if (bUndo) + { + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoInsertAreaLink( &rDocShell, + rFile, aFilterName, aNewOptions, + rSource, rDestRange, nRefresh ) ); + if ( nRemoved ) + rDocShell.GetUndoManager()->LeaveListAction(); // undo for link update is still separate + } + + // Update hat sein eigenes Undo + + pLink->SetDoInsert(bFitBlock); // beim ersten Update ggf. nichts einfuegen + pLink->Update(); // kein SetInCreate -> Update ausfuehren + pLink->SetDoInsert(TRUE); // Default = TRUE + + SfxBindings* pBindings = rDocShell.GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_LINKS ); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) ); // Navigator + + return TRUE; +} + + + + diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx new file mode 100644 index 000000000000..1b4f9b677f81 --- /dev/null +++ b/sc/source/ui/docshell/docsh.cxx @@ -0,0 +1,2591 @@ +/************************************************************************* + * + * 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" +// System - Includes ----------------------------------------------------- + + + +#include "scitems.hxx" +#include <editeng/eeitem.hxx> +#include <editeng/svxenum.hxx> +#include <svx/algitem.hxx> + + + +#include <sot/clsids.hxx> +#include <unotools/securityoptions.hxx> +#include <tools/stream.hxx> +#include <tools/string.hxx> +#include <tools/urlobj.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/virdev.hxx> +#include <vcl/waitobj.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/sfxecode.hxx> +#include <svl/zforlist.hxx> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dinfdlg.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/evntconf.hxx> +#include <sfx2/sfx.hrc> +#include <sfx2/topfrm.hxx> +#include <sfx2/objface.hxx> +#include <svl/srchitem.hxx> +#include <unotools/fltrcfg.hxx> +#include <svl/documentlockfile.hxx> +#include <svl/sharecontrolfile.hxx> +#include <unotools/charclass.hxx> +#include <vcl/virdev.hxx> +#include "chgtrack.hxx" +#include "chgviset.hxx" +#include <sfx2/request.hxx> +#include <com/sun/star/document/UpdateDocMode.hpp> + + +#include "scabstdlg.hxx" //CHINA001 +#include <sot/formats.hxx> +#define SOT_FORMATSTR_ID_STARCALC_30 SOT_FORMATSTR_ID_STARCALC + +// INCLUDE --------------------------------------------------------------- + +#include "cell.hxx" +#include "global.hxx" +#include "filter.hxx" +#include "scmod.hxx" +#include "tabvwsh.hxx" +#include "docfunc.hxx" +#include "imoptdlg.hxx" +#include "impex.hxx" +#include "scresid.hxx" +#include "sc.hrc" +#include "globstr.hrc" +#include "scerrors.hxx" +#include "brdcst.hxx" +#include "stlpool.hxx" +#include "autostyl.hxx" +#include "attrib.hxx" +#include "asciiopt.hxx" +#include "waitoff.hxx" +#include "docpool.hxx" // LoadCompleted +#include "progress.hxx" +#include "pntlock.hxx" +#include "collect.hxx" +#include "docuno.hxx" +#include "appoptio.hxx" +#include "detdata.hxx" +#include "printfun.hxx" +#include "dociter.hxx" +#include "cellform.hxx" +#include "chartlis.hxx" +#include "hints.hxx" +#include "xmlwrap.hxx" +#include "drwlayer.hxx" +#include "refreshtimer.hxx" +#include "dbcolect.hxx" +#include "scextopt.hxx" +#include "compiler.hxx" +#include "cfgids.hxx" +#include "warnpassword.hxx" +#include "optsolver.hxx" +#include "sheetdata.hxx" +#include "tabprotection.hxx" + +#include "docsh.hxx" +#include "docshimp.hxx" +#include <rtl/logfile.hxx> + +#include <comphelper/processfactory.hxx> +#include <basic/sbstar.hxx> +#include <basic/basmgr.hxx> +using namespace com::sun::star; + +// STATIC DATA ----------------------------------------------------------- + +// Stream-Namen im Storage + +const sal_Char __FAR_DATA ScDocShell::pStarCalcDoc[] = STRING_SCSTREAM; // "StarCalcDocument" +const sal_Char __FAR_DATA ScDocShell::pStyleName[] = "SfxStyleSheets"; + +// Filter-Namen (wie in sclib.cxx) + +static const sal_Char __FAR_DATA pFilterSc50[] = "StarCalc 5.0"; +//static const sal_Char __FAR_DATA pFilterSc50Temp[] = "StarCalc 5.0 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterSc40[] = "StarCalc 4.0"; +//static const sal_Char __FAR_DATA pFilterSc40Temp[] = "StarCalc 4.0 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterSc30[] = "StarCalc 3.0"; +//static const sal_Char __FAR_DATA pFilterSc30Temp[] = "StarCalc 3.0 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterSc10[] = "StarCalc 1.0"; +static const sal_Char __FAR_DATA pFilterXML[] = "StarOffice XML (Calc)"; +static const sal_Char __FAR_DATA pFilterAscii[] = "Text - txt - csv (StarCalc)"; +static const sal_Char __FAR_DATA pFilterLotus[] = "Lotus"; +static const sal_Char __FAR_DATA pFilterQPro6[] = "Quattro Pro 6.0"; +static const sal_Char __FAR_DATA pFilterExcel4[] = "MS Excel 4.0"; +static const sal_Char __FAR_DATA pFilterEx4Temp[] = "MS Excel 4.0 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterExcel5[] = "MS Excel 5.0/95"; +static const sal_Char __FAR_DATA pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterExcel95[] = "MS Excel 95"; +static const sal_Char __FAR_DATA pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterExcel97[] = "MS Excel 97"; +static const sal_Char __FAR_DATA pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template"; +static const sal_Char __FAR_DATA pFilterEx07Xml[] = "MS Excel 2007 XML"; +static const sal_Char __FAR_DATA pFilterDBase[] = "dBase"; +static const sal_Char __FAR_DATA pFilterDif[] = "DIF"; +static const sal_Char __FAR_DATA pFilterSylk[] = "SYLK"; +static const sal_Char __FAR_DATA pFilterHtml[] = "HTML (StarCalc)"; +static const sal_Char __FAR_DATA pFilterHtmlWebQ[] = "calc_HTML_WebQuery"; +static const sal_Char __FAR_DATA pFilterRtf[] = "Rich Text Format (StarCalc)"; + +//---------------------------------------------------------------------- + +#define ScDocShell +#include "scslots.hxx" + + +SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell, ScResId(SCSTR_DOCSHELL)) +{ + SFX_CHILDWINDOW_REGISTRATION( SID_HYPERLINK_INSERT ); +} + +// GlobalName der aktuellen Version: +SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), SFXOBJECTSHELL_STD_NORMAL, "scalc" ) + +TYPEINIT1( ScDocShell, SfxObjectShell ); // SfxInPlaceObject: kein Type-Info ? + +//------------------------------------------------------------------ + +void __EXPORT ScDocShell::FillClass( SvGlobalName* pClassName, + sal_uInt32* pFormat, + String* /* pAppName */, + String* pFullTypeName, + String* pShortTypeName, + sal_Int32 nFileFormat, + sal_Bool bTemplate /* = sal_False */) const +{ + if ( nFileFormat == SOFFICE_FILEFORMAT_60 ) + { + *pClassName = SvGlobalName( SO3_SC_CLASSID_60 ); + *pFormat = SOT_FORMATSTR_ID_STARCALC_60; + *pFullTypeName = String( ScResId( SCSTR_LONG_SCDOC_NAME ) ); + *pShortTypeName = String( ScResId( SCSTR_SHORT_SCDOC_NAME ) ); + } + else if ( nFileFormat == SOFFICE_FILEFORMAT_8 ) + { + *pClassName = SvGlobalName( SO3_SC_CLASSID_60 ); + *pFormat = bTemplate ? SOT_FORMATSTR_ID_STARCALC_8_TEMPLATE : SOT_FORMATSTR_ID_STARCALC_8; + *pFullTypeName = String( RTL_CONSTASCII_USTRINGPARAM("calc8") ); + *pShortTypeName = String( ScResId( SCSTR_SHORT_SCDOC_NAME ) ); + } + else + { + DBG_ERROR("wat fuer ne Version?"); + } +} + +//------------------------------------------------------------------ + +void ScDocShell::DoEnterHandler() +{ + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if (pViewSh) + if (pViewSh->GetViewData()->GetDocShell() == this) + SC_MOD()->InputEnterHandler(); +} + +//------------------------------------------------------------------ + +SCTAB ScDocShell::GetSaveTab() +{ + SCTAB nTab = 0; + ScTabViewShell* pSh = GetBestViewShell(); + if (pSh) + { + const ScMarkData& rMark = pSh->GetViewData()->GetMarkData(); + for ( nTab = 0; nTab <= MAXTAB; nTab++ ) // erste markierte Tabelle + if ( rMark.GetTableSelect( nTab ) ) + break; + } + return nTab; +} + +sal_uInt16 ScDocShell::GetHiddenInformationState( sal_uInt16 nStates ) +{ + // get global state like HIDDENINFORMATION_DOCUMENTVERSIONS + sal_uInt16 nState = SfxObjectShell::GetHiddenInformationState( nStates ); + + if ( nStates & HIDDENINFORMATION_RECORDEDCHANGES ) + { + if ( aDocument.GetChangeTrack() && aDocument.GetChangeTrack()->GetFirst() ) + nState |= HIDDENINFORMATION_RECORDEDCHANGES; + } + if ( nStates & HIDDENINFORMATION_NOTES ) + { + SCTAB nTableCount = aDocument.GetTableCount(); + SCTAB nTable = 0; + sal_Bool bFound(sal_False); + while ( nTable < nTableCount && !bFound ) + { + ScCellIterator aCellIter( &aDocument, 0,0, nTable, MAXCOL,MAXROW, nTable ); + for( ScBaseCell* pCell = aCellIter.GetFirst(); pCell && !bFound; pCell = aCellIter.GetNext() ) + if (pCell->HasNote()) + bFound = sal_True; + nTable++; + } + + if (bFound) + nState |= HIDDENINFORMATION_NOTES; + } + + return nState; +} + +void ScDocShell::BeforeXMLLoading() +{ + aDocument.DisableIdle( TRUE ); + + // prevent unnecessary broadcasts and updates + DBG_ASSERT(pModificator == NULL, "The Modificator should not exist"); + pModificator = new ScDocShellModificator( *this ); + + aDocument.SetImportingXML( TRUE ); + aDocument.EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references + aDocument.EnableUndo( FALSE ); + // prevent unnecessary broadcasts and "half way listeners" + aDocument.SetInsertingFromOtherDoc( TRUE ); + + if (GetCreateMode() != SFX_CREATE_MODE_ORGANIZER) + ScColumn::bDoubleAlloc = sal_True; +} + +void ScDocShell::AfterXMLLoading(sal_Bool bRet) +{ + if (GetCreateMode() != SFX_CREATE_MODE_ORGANIZER) + { + UpdateLinks(); + // don't prevent establishing of listeners anymore + aDocument.SetInsertingFromOtherDoc( FALSE ); + if ( bRet ) + { + ScChartListenerCollection* pChartListener = aDocument.GetChartListenerCollection(); + if (pChartListener) + pChartListener->UpdateDirtyCharts(); + + // #95582#; set the table names of linked tables to the new path + SCTAB nTabCount = aDocument.GetTableCount(); + for (SCTAB i = 0; i < nTabCount; ++i) + { + if (aDocument.IsLinked( i )) + { + String aName; + aDocument.GetName(i, aName); + String aLinkTabName = aDocument.GetLinkTab(i); + xub_StrLen nLinkTabNameLength = aLinkTabName.Len(); + xub_StrLen nNameLength = aName.Len(); + if (nLinkTabNameLength < nNameLength) + { + + // remove the quottes on begin and end of the docname and restore the escaped quotes + const sal_Unicode* pNameBuffer = aName.GetBuffer(); + if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos + ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) ) + { + rtl::OUStringBuffer aDocURLBuffer; + BOOL bQuote = TRUE; // Dokumentenname ist immer quoted + ++pNameBuffer; + while ( bQuote && *pNameBuffer ) + { + if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' ) + bQuote = FALSE; + else if( !(*pNameBuffer == '\\' && *(pNameBuffer+1) == '\'') ) + aDocURLBuffer.append(*pNameBuffer); // falls escaped Quote: nur Quote in den Namen + ++pNameBuffer; + } + + + if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char + { + xub_StrLen nIndex = nNameLength - nLinkTabNameLength; + INetURLObject aINetURLObject(aDocURLBuffer.makeStringAndClear()); + if( aName.Equals(aLinkTabName, nIndex, nLinkTabNameLength) && + (aName.GetChar(nIndex - 1) == '#') && // before the table name should be the # char + !aINetURLObject.HasError()) // the docname should be a valid URL + { + aName = ScGlobal::GetDocTabName( aDocument.GetLinkDoc( i ), aDocument.GetLinkTab( i ) ); + aDocument.RenameTab(i, aName, TRUE, TRUE); + } + // else; nothing has to happen, because it is a user given name + } + // else; nothing has to happen, because it is a user given name + } + // else; nothing has to happen, because it is a user given name + } + // else; nothing has to happen, because it is a user given name + } + } + } + ScColumn::bDoubleAlloc = sal_False; + } + else + aDocument.SetInsertingFromOtherDoc( FALSE ); + // add vba globals ( if they are availabl ) + uno::Any aGlobs; + uno::Sequence< uno::Any > aArgs(1); + aArgs[ 0 ] <<= GetModel(); + aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.excel.Globals" ) ), aArgs ); + GetBasicManager()->SetGlobalUNOConstant( "VBAGlobals", aGlobs ); + // Fake ThisComponent being setup by Activate ( which is a view + // related thing ), + // a) if another document is opened then in theory ThisComponent + // will be reset as before, + // b) when this document is 'really' Activated then ThisComponent + // again will be set as before + // The only wrinkle seems if this document is loaded 'InVisible' + // but.. I don't see that this is possible from the vba API + // I could be wrong though + // There may be implications setting the current component + // too early :-/ so I will just manually set the Basic Variables + BasicManager* pAppMgr = SFX_APP()->GetBasicManager(); + if ( pAppMgr ) + pAppMgr->SetGlobalUNOConstant( "ThisExcelDoc", aArgs[ 0 ] ); + + aDocument.SetImportingXML( FALSE ); + aDocument.EnableExecuteLink( true ); + aDocument.EnableUndo( TRUE ); + bIsEmpty = FALSE; + + if (pModificator) + { + delete pModificator; + pModificator = NULL; + } + else + { + DBG_ERROR("The Modificator should exist"); + } + + aDocument.DisableIdle( FALSE ); +} + +BOOL ScDocShell::LoadXML( SfxMedium* pLoadMedium, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStor ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "sb99857", "ScDocShell::LoadXML" ); + + // MacroCallMode is no longer needed, state is kept in SfxObjectShell now + + // no Seek(0) here - always loading from storage, GetInStream must not be called + + BeforeXMLLoading(); + + // #i62677# BeforeXMLLoading is also called from ScXMLImport::startDocument when invoked + // from an external component. The XMLFromWrapper flag is only set here, when called + // through ScDocShell. + aDocument.SetXMLFromWrapper( TRUE ); + + ScXMLImportWrapper aImport( aDocument, pLoadMedium, xStor ); + + sal_Bool bRet(sal_False); + ErrCode nError = ERRCODE_NONE; + if (GetCreateMode() != SFX_CREATE_MODE_ORGANIZER) + bRet = aImport.Import(sal_False, nError); + else + bRet = aImport.Import(sal_True, nError); + + if ( nError ) + pLoadMedium->SetError( nError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + aDocument.SetXMLFromWrapper( FALSE ); + AfterXMLLoading(bRet); + + //! row heights... + + return bRet; +} + +BOOL ScDocShell::SaveXML( SfxMedium* pSaveMedium, const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStor ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "sb99857", "ScDocShell::SaveXML" ); + + aDocument.DisableIdle( TRUE ); + + ScXMLImportWrapper aImport( aDocument, pSaveMedium, xStor ); + sal_Bool bRet(sal_False); + if (GetCreateMode() != SFX_CREATE_MODE_ORGANIZER) + bRet = aImport.Export(sal_False); + else + bRet = aImport.Export(sal_True); + + aDocument.DisableIdle( FALSE ); + + return bRet; +} + +BOOL __EXPORT ScDocShell::Load( SfxMedium& rMedium ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::Load" ); + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + // only the latin script language is loaded + // -> initialize the others from options (before loading) + InitOptions(); + + GetUndoManager()->Clear(); + + BOOL bRet = SfxObjectShell::Load( rMedium ); + if( bRet ) + { + if (GetMedium()) + { + SFX_ITEMSET_ARG( rMedium.GetItemSet(), pUpdateDocItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False); + nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : com::sun::star::document::UpdateDocMode::NO_UPDATE; + } + + { + // prepare a valid document for XML filter + // (for ConvertFrom, InitNew is called before) + aDocument.MakeTable(0); + aDocument.GetStyleSheetPool()->CreateStandardStyles(); + aDocument.UpdStlShtPtrsFrmNms(); + + bRet = LoadXML( &rMedium, NULL ); + } + } + + if (!bRet && !rMedium.GetError()) + rMedium.SetError( SVSTREAM_FILEFORMAT_ERROR, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + if (rMedium.GetError()) + SetError( rMedium.GetError(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + InitItems(); + CalcOutputFactor(); + + // #73762# invalidate eventually temporary table areas + if ( bRet ) + aDocument.InvalidateTableArea(); + + bIsEmpty = FALSE; + FinishedLoading( SFX_LOADED_MAINDOCUMENT | SFX_LOADED_IMAGES ); + return bRet; +} + + +void __EXPORT ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if (rHint.ISA(SfxSimpleHint)) // ohne Parameter + { + ULONG nSlot = ((const SfxSimpleHint&)rHint).GetId(); + switch ( nSlot ) + { + case SFX_HINT_TITLECHANGED: + aDocument.SetName( SfxShell::GetName() ); + // RegisterNewTargetNames gibts nicht mehr + SFX_APP()->Broadcast(SfxSimpleHint( SC_HINT_DOCNAME_CHANGED )); // Navigator + break; + } + } + else if (rHint.ISA(SfxStyleSheetHint)) // Vorlagen geaendert + NotifyStyle((const SfxStyleSheetHint&) rHint); + else if (rHint.ISA(ScAutoStyleHint)) + { + //! direct call for AutoStyles + + // this is called synchronously from ScInterpreter::ScStyle, + // modifying the document must be asynchronous + // (handled by AddInitial) + + ScAutoStyleHint& rStlHint = (ScAutoStyleHint&)rHint; + ScRange aRange = rStlHint.GetRange(); + String aName1 = rStlHint.GetStyle1(); + String aName2 = rStlHint.GetStyle2(); + UINT32 nTimeout = rStlHint.GetTimeout(); + + if (!pAutoStyleList) + pAutoStyleList = new ScAutoStyleList(this); + pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 ); + } + else if ( rHint.ISA( SfxEventHint ) ) + { + ULONG nEventId = ((SfxEventHint&)rHint).GetEventId(); + switch ( nEventId ) + { + case SFX_EVENT_LOADFINISHED: + { + // the readonly documents should not be opened in shared mode + if ( HasSharedXMLFlagSet() && !SC_MOD()->IsInSharedDocLoading() && !IsReadOnly() ) + { + if ( SwitchToShared( sal_True, sal_False ) ) + { + ScViewData* pViewData = GetViewData(); + ScTabView* pTabView = ( pViewData ? dynamic_cast< ScTabView* >( pViewData->GetView() ) : NULL ); + if ( pTabView ) + { + pTabView->UpdateLayerLocks(); + } + } + else + { + // switching to shared mode has failed, the document should be opened readonly + // TODO/LATER: And error message should be shown here probably + SetReadOnlyUI( sal_True ); + } + } + } + break; + case SFX_EVENT_VIEWCREATED: + { + if ( IsDocShared() && !SC_MOD()->IsInSharedDocLoading() ) + { + ScAppOptions aAppOptions = SC_MOD()->GetAppOptions(); + if ( aAppOptions.GetShowSharedDocumentWarning() ) + { + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_OK ), + ScGlobal::GetRscString( STR_SHARED_DOC_WARNING ) ); + aBox.SetDefaultCheckBoxText(); + aBox.Execute(); + BOOL bChecked = aBox.GetCheckBoxState(); + if ( bChecked ) + { + aAppOptions.SetShowSharedDocumentWarning( !bChecked ); + SC_MOD()->SetAppOptions( aAppOptions ); + } + } + } + } + break; + case SFX_EVENT_SAVEDOC: + { + if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() ) + { + bool bSuccess = false; + bool bRetry = true; + while ( bRetry ) + { + bRetry = false; + uno::Reference< frame::XModel > xModel; + try + { + // load shared file + xModel.set( LoadSharedDocument(), uno::UNO_QUERY_THROW ); + uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW ); + + // check if shared flag is set in shared file + bool bShared = false; + ScModelObj* pDocObj = ScModelObj::getImplementation( xModel ); + ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : NULL ); + if ( pSharedDocShell ) + { + bShared = pSharedDocShell->HasSharedXMLFlagSet(); + } + + // #i87870# check if shared status was disabled and enabled again + bool bOwnEntry = false; + bool bEntriesNotAccessible = false; + try + { + ::svt::ShareControlFile aControlFile( GetSharedFileURL() ); + bOwnEntry = aControlFile.HasOwnEntry(); + } + catch ( uno::Exception& ) + { + bEntriesNotAccessible = true; + } + + if ( bShared && bOwnEntry ) + { + uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW ); + + if ( xStorable->isReadonly() ) + { + xCloseable->close( sal_True ); + + String aUserName( ScGlobal::GetRscString( STR_UNKNOWN_USER ) ); + bool bNoLockAccess = false; + try + { + ::svt::DocumentLockFile aLockFile( GetSharedFileURL() ); + uno::Sequence< ::rtl::OUString > aData = aLockFile.GetLockData(); + if ( aData.getLength() > LOCKFILE_SYSUSERNAME_ID ) + { + if ( aData[LOCKFILE_OOOUSERNAME_ID].getLength() > 0 ) + { + aUserName = aData[LOCKFILE_OOOUSERNAME_ID]; + } + else if ( aData[LOCKFILE_SYSUSERNAME_ID].getLength() > 0 ) + { + aUserName = aData[LOCKFILE_SYSUSERNAME_ID]; + } + } + } + catch ( uno::Exception& ) + { + bNoLockAccess = true; + } + + if ( bNoLockAccess ) + { + // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown + ErrorHandler::HandleError( ERRCODE_IO_GENERAL ); + } + else + { + String aMessage( ScGlobal::GetRscString( STR_FILE_LOCKED_SAVE_LATER ) ); + aMessage.SearchAndReplaceAscii( "%1", aUserName ); + + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_RETRY_CANCEL | WB_DEF_RETRY ), aMessage ); + if ( aBox.Execute() == RET_RETRY ) + { + bRetry = true; + } + } + } + else + { + // merge changes from shared file into temp file + bool bSaveToShared = false; + if ( pSharedDocShell ) + { + bSaveToShared = MergeSharedDocument( pSharedDocShell ); + } + + // close shared file + xCloseable->close( sal_True ); + + // TODO: keep file lock on shared file + + // store to shared file + if ( bSaveToShared ) + { + bool bChangedViewSettings = false; + ScChangeViewSettings* pChangeViewSet = aDocument.GetChangeViewSettings(); + if ( pChangeViewSet && pChangeViewSet->ShowChanges() ) + { + pChangeViewSet->SetShowChanges( FALSE ); + pChangeViewSet->SetShowAccepted( FALSE ); + aDocument.SetChangeViewSettings( *pChangeViewSet ); + bChangedViewSettings = true; + } + + uno::Reference< frame::XStorable > xStor( GetModel(), uno::UNO_QUERY_THROW ); + // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge + uno::Sequence< beans::PropertyValue > aValues(1); + aValues[0].Name = ::rtl::OUString::createFromAscii( "FilterName" ); + aValues[0].Value <<= ::rtl::OUString( GetMedium()->GetFilter()->GetFilterName() ); + + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False); + if ( pPasswordItem && pPasswordItem->GetValue().Len() ) + { + aValues.realloc( 2 ); + aValues[1].Name = ::rtl::OUString::createFromAscii( "Password" ); + aValues[1].Value <<= ::rtl::OUString( pPasswordItem->GetValue() ); + } + + SC_MOD()->SetInSharedDocSaving( true ); + xStor->storeToURL( GetSharedFileURL(), aValues ); + SC_MOD()->SetInSharedDocSaving( false ); + + if ( bChangedViewSettings ) + { + pChangeViewSet->SetShowChanges( TRUE ); + pChangeViewSet->SetShowAccepted( TRUE ); + aDocument.SetChangeViewSettings( *pChangeViewSet ); + } + } + + bSuccess = true; + GetUndoManager()->Clear(); + } + } + else + { + xCloseable->close( sal_True ); + + if ( bEntriesNotAccessible ) + { + // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown + ErrorHandler::HandleError( ERRCODE_IO_GENERAL ); + } + else + { + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_OK ), + ScGlobal::GetRscString( STR_DOC_NOLONGERSHARED ) ); + aBox.Execute(); + + SfxBindings* pBindings = GetViewBindings(); + if ( pBindings ) + { + pBindings->ExecuteSynchron( SID_SAVEASDOC ); + } + } + } + } + catch ( uno::Exception& ) + { + DBG_ERROR( "SFX_EVENT_SAVEDOC: caught exception\n" ); + SC_MOD()->SetInSharedDocSaving( false ); + + try + { + uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW ); + xClose->close( sal_True ); + } + catch ( uno::Exception& ) + { + } + } + } + + if ( !bSuccess ) + SetError( ERRCODE_IO_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); // this error code will produce no error message, but will break the further saving process + } + } + break; + case SFX_EVENT_SAVEDOCDONE: + { + if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() ) + { + } + UseSheetSaveEntries(); // use positions from saved file for next saving + } + break; + case SFX_EVENT_SAVEASDOCDONE: + // new positions are used after "save" and "save as", but not "save to" + UseSheetSaveEntries(); // use positions from saved file for next saving + break; + default: + { + } + break; + } + } +} + + // Inhalte fuer Organizer laden + + +BOOL __EXPORT ScDocShell::LoadFrom( SfxMedium& rMedium ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::LoadFrom" ); + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + WaitObject aWait( GetActiveDialogParent() ); + + BOOL bRet = FALSE; + + if (GetMedium()) + { + SFX_ITEMSET_ARG( rMedium.GetItemSet(), pUpdateDocItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False); + nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : com::sun::star::document::UpdateDocMode::NO_UPDATE; + } + + // until loading/saving only the styles in XML is implemented, + // load the whole file + bRet = LoadXML( &rMedium, NULL ); + InitItems(); + + SfxObjectShell::LoadFrom( rMedium ); + + return bRet; +} + + +BOOL __EXPORT ScDocShell::ConvertFrom( SfxMedium& rMedium ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ConvertFrom" ); + + BOOL bRet = FALSE; // FALSE heisst Benutzerabbruch !! + // bei Fehler: Fehler am Stream setzen!! + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + GetUndoManager()->Clear(); + + // ob nach dem Import optimale Spaltenbreiten gesetzt werden sollen + BOOL bSetColWidths = FALSE; + BOOL bSetSimpleTextColWidths = FALSE; + BOOL bSimpleColWidth[MAXCOLCOUNT]; + memset( bSimpleColWidth, 1, (MAXCOLCOUNT) * sizeof(BOOL) ); + ScRange aColWidthRange; + // ob nach dem Import optimale Zeilenhoehen gesetzt werden sollen + BOOL bSetRowHeights = FALSE; + + aConvFilterName.Erase(); //@ #BugId 54198 + + // Alle Filter brauchen die komplette Datei am Stueck (nicht asynchron), + // darum vorher per CreateFileStream dafuer sorgen, dass die komplette + // Datei uebertragen wird. + rMedium.GetPhysicalName(); //! CreateFileStream direkt rufen, wenn verfuegbar + + SFX_ITEMSET_ARG( rMedium.GetItemSet(), pUpdateDocItem, SfxUInt16Item, SID_UPDATEDOCMODE, sal_False); + nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : com::sun::star::document::UpdateDocMode::NO_UPDATE; + + const SfxFilter* pFilter = rMedium.GetFilter(); + if (pFilter) + { + String aFltName = pFilter->GetFilterName(); + + aConvFilterName=aFltName; //@ #BugId 54198 + + BOOL bCalc3 = ( aFltName.EqualsAscii(pFilterSc30) ); + BOOL bCalc4 = ( aFltName.EqualsAscii(pFilterSc40) ); + if (!bCalc3 && !bCalc4) + aDocument.SetInsertingFromOtherDoc( TRUE ); + + if (aFltName.EqualsAscii(pFilterXML)) + bRet = LoadXML( &rMedium, NULL ); + else if (aFltName.EqualsAscii(pFilterSc10)) + { + SvStream* pStream = rMedium.GetInStream(); + if (pStream) + { + FltError eError = ScFormatFilter::Get().ScImportStarCalc10( *pStream, &aDocument ); + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + else + bRet = TRUE; + } + } + else if (aFltName.EqualsAscii(pFilterLotus)) + { + String sItStr; + SfxItemSet* pSet = rMedium.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sItStr = ((const SfxStringItem*)pItem)->GetValue(); + } + + if (sItStr.Len() == 0) + { + // default for lotus import (from API without options): + // IBM_437 encoding + sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 ); + } + + ScColumn::bDoubleAlloc = TRUE; + FltError eError = ScFormatFilter::Get().ScImportLotus123( rMedium, &aDocument, + ScGlobal::GetCharsetValue(sItStr)); + ScColumn::bDoubleAlloc = FALSE; + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + + if( ( eError & ERRCODE_WARNING_MASK ) == ERRCODE_WARNING_MASK ) + bRet = TRUE; + } + else + bRet = TRUE; + bSetColWidths = TRUE; + bSetRowHeights = TRUE; + } + else if ( aFltName.EqualsAscii(pFilterExcel4) || aFltName.EqualsAscii(pFilterExcel5) || + aFltName.EqualsAscii(pFilterExcel95) || aFltName.EqualsAscii(pFilterExcel97) || + aFltName.EqualsAscii(pFilterEx4Temp) || aFltName.EqualsAscii(pFilterEx5Temp) || + aFltName.EqualsAscii(pFilterEx95Temp) || aFltName.EqualsAscii(pFilterEx97Temp) ) + { + EXCIMPFORMAT eFormat = EIF_AUTO; + if ( aFltName.EqualsAscii(pFilterExcel4) || aFltName.EqualsAscii(pFilterEx4Temp) ) + eFormat = EIF_BIFF_LE4; + else if ( aFltName.EqualsAscii(pFilterExcel5) || aFltName.EqualsAscii(pFilterExcel95) || + aFltName.EqualsAscii(pFilterEx5Temp) || aFltName.EqualsAscii(pFilterEx95Temp) ) + eFormat = EIF_BIFF5; + else if ( aFltName.EqualsAscii(pFilterExcel97) || aFltName.EqualsAscii(pFilterEx97Temp) ) + eFormat = EIF_BIFF8; + + MakeDrawLayer(); //! im Filter + CalcOutputFactor(); // #93255# prepare update of row height + ScColumn::bDoubleAlloc = TRUE; + FltError eError = ScFormatFilter::Get().ScImportExcel( rMedium, &aDocument, eFormat ); + ScColumn::bDoubleAlloc = FALSE; + aDocument.UpdateFontCharSet(); + if ( aDocument.IsChartListenerCollectionNeedsUpdate() ) + aDocument.UpdateChartListenerCollection(); //! fuer alle Importe? + + // #75299# all graphics objects must have names + aDocument.EnsureGraphicNames(); + + if (eError == SCWARN_IMPORT_RANGE_OVERFLOW) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + bRet = TRUE; + } + else if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + else + bRet = TRUE; + + // #93255# update of row height done inside of Excel filter to speed up chart import +// bSetRowHeights = TRUE; // #75357# optimal row heights must be updated + } + else if (aFltName.EqualsAscii(pFilterAscii)) + { + SfxItemSet* pSet = rMedium.GetItemSet(); + const SfxPoolItem* pItem; + ScAsciiOptions aOptions; + BOOL bOptInit = FALSE; + + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + aOptions.ReadFromString( ((const SfxStringItem*)pItem)->GetValue() ); + bOptInit = TRUE; + } + + if ( !bOptInit ) + { + // default for ascii import (from API without options): + // ISO8859-1/MS_1252 encoding, comma, double quotes + + aOptions.SetCharSet( RTL_TEXTENCODING_MS_1252 ); + aOptions.SetFieldSeps( (sal_Unicode) ',' ); + aOptions.SetTextSep( (sal_Unicode) '"' ); + } + + FltError eError = eERR_OK; + BOOL bOverflow = FALSE; + + if( ! rMedium.IsStorage() ) + { + ScImportExport aImpEx( &aDocument ); + aImpEx.SetExtOptions( aOptions ); + + SvStream* pInStream = rMedium.GetInStream(); + if (pInStream) + { + pInStream->SetStreamCharSet( aOptions.GetCharSet() ); + pInStream->Seek( 0 ); + bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL() ); + eError = bRet ? eERR_OK : SCERR_IMPORT_CONNECT; + aDocument.StartAllListeners(); + aDocument.SetDirty(); + bOverflow = aImpEx.IsOverflow(); + } + else + { + DBG_ERROR( "No Stream" ); + } + } + + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + else if ( bOverflow ) + { + if (!GetError()) + SetError(SCWARN_IMPORT_RANGE_OVERFLOW, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + bSetColWidths = TRUE; + bSetSimpleTextColWidths = TRUE; + } + else if (aFltName.EqualsAscii(pFilterDBase)) + { + String sItStr; + SfxItemSet* pSet = rMedium.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sItStr = ((const SfxStringItem*)pItem)->GetValue(); + } + + if (sItStr.Len() == 0) + { + // default for dBase import (from API without options): + // IBM_850 encoding + + sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 ); + } + + ULONG eError = DBaseImport( rMedium.GetPhysicalName(), + ScGlobal::GetCharsetValue(sItStr), bSimpleColWidth ); + + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + bRet = ( eError == SCWARN_IMPORT_RANGE_OVERFLOW ); + } + else + bRet = TRUE; + + aColWidthRange.aStart.SetRow( 1 ); // Spaltenheader nicht + bSetColWidths = TRUE; + bSetSimpleTextColWidths = TRUE; + // Memo-Felder fuehren zu einem bSimpleColWidth[nCol]==FALSE + for ( SCCOL nCol=0; nCol <= MAXCOL && !bSetRowHeights; nCol++ ) + { + if ( !bSimpleColWidth[nCol] ) + bSetRowHeights = TRUE; + } + } + else if (aFltName.EqualsAscii(pFilterDif)) + { + SvStream* pStream = rMedium.GetInStream(); + if (pStream) + { + FltError eError; + String sItStr; + SfxItemSet* pSet = rMedium.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sItStr = ((const SfxStringItem*)pItem)->GetValue(); + } + + if (sItStr.Len() == 0) + { + // default for DIF import (from API without options): + // ISO8859-1/MS_1252 encoding + + sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 ); + } + + eError = ScFormatFilter::Get().ScImportDif( *pStream, &aDocument, ScAddress(0,0,0), + ScGlobal::GetCharsetValue(sItStr)); + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + + if( ( eError & ERRCODE_WARNING_MASK ) == ERRCODE_WARNING_MASK ) + bRet = TRUE; + } + else + bRet = TRUE; + } + bSetColWidths = TRUE; + bSetSimpleTextColWidths = TRUE; + bSetRowHeights = TRUE; + } + else if (aFltName.EqualsAscii(pFilterSylk)) + { + FltError eError = SCERR_IMPORT_UNKNOWN; + if( !rMedium.IsStorage() ) + { + ScImportExport aImpEx( &aDocument ); + + SvStream* pInStream = rMedium.GetInStream(); + if (pInStream) + { + pInStream->Seek( 0 ); + bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SOT_FORMATSTR_ID_SYLK ); + eError = bRet ? eERR_OK : SCERR_IMPORT_UNKNOWN; + aDocument.StartAllListeners(); + aDocument.SetDirty(); + } + else + { + DBG_ERROR( "No Stream" ); + } + } + + if ( eError != eERR_OK && !GetError() ) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + bSetColWidths = TRUE; + bSetSimpleTextColWidths = TRUE; + bSetRowHeights = TRUE; + } + else if (aFltName.EqualsAscii(pFilterQPro6)) + { + ScColumn::bDoubleAlloc = TRUE; + FltError eError = ScFormatFilter::Get().ScImportQuattroPro( rMedium, &aDocument); + ScColumn::bDoubleAlloc = FALSE; + if (eError != eERR_OK) + { + if (!GetError()) + SetError( eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + if( ( eError & ERRCODE_WARNING_MASK ) == ERRCODE_WARNING_MASK ) + bRet = TRUE; + } + else + bRet = TRUE; + // TODO: Filter should set column widths. Not doing it here, it may + // result in very narrow or wide columns, depending on content. + // Setting row heights makes cells with font size attribution or + // wrapping enabled look nicer.. + bSetRowHeights = TRUE; + } + else if (aFltName.EqualsAscii(pFilterRtf)) + { + FltError eError = SCERR_IMPORT_UNKNOWN; + if( !rMedium.IsStorage() ) + { + SvStream* pInStream = rMedium.GetInStream(); + if (pInStream) + { + pInStream->Seek( 0 ); + ScRange aRange; + eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), &aDocument, aRange ); + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + + if( ( eError & ERRCODE_WARNING_MASK ) == ERRCODE_WARNING_MASK ) + bRet = TRUE; + } + else + bRet = TRUE; + aDocument.StartAllListeners(); + aDocument.SetDirty(); + bSetColWidths = TRUE; + bSetRowHeights = TRUE; + } + else + { + DBG_ERROR( "No Stream" ); + } + } + + if ( eError != eERR_OK && !GetError() ) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + else if (aFltName.EqualsAscii(pFilterHtml) || aFltName.EqualsAscii(pFilterHtmlWebQ)) + { + FltError eError = SCERR_IMPORT_UNKNOWN; + BOOL bWebQuery = aFltName.EqualsAscii(pFilterHtmlWebQ); + if( !rMedium.IsStorage() ) + { + SvStream* pInStream = rMedium.GetInStream(); + if (pInStream) + { + pInStream->Seek( 0 ); + ScRange aRange; + // HTML macht eigenes ColWidth/RowHeight + CalcOutputFactor(); + eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), &aDocument, aRange, + GetOutputFactor(), !bWebQuery ); + if (eError != eERR_OK) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + + if( ( eError & ERRCODE_WARNING_MASK ) == ERRCODE_WARNING_MASK ) + bRet = TRUE; + } + else + bRet = TRUE; + aDocument.StartAllListeners(); + aDocument.SetDirty(); + } + else + { + DBG_ERROR( "No Stream" ); + } + } + + if ( eError != eERR_OK && !GetError() ) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + else + { + if (!GetError()) + SetError(SCERR_IMPORT_NI, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + + if (!bCalc3) + aDocument.SetInsertingFromOtherDoc( FALSE ); + } + else + { + DBG_ERROR("Kein Filter bei ConvertFrom"); + } + + InitItems(); + CalcOutputFactor(); + if ( bRet && (bSetColWidths || bSetRowHeights) ) + { // Spaltenbreiten/Zeilenhoehen anpassen, Basis 100% Zoom + Fraction aZoom( 1, 1 ); + double nPPTX = ScGlobal::nScreenPPTX * (double) aZoom + / GetOutputFactor(); // Faktor ist Drucker zu Bildschirm + double nPPTY = ScGlobal::nScreenPPTY * (double) aZoom; + VirtualDevice aVirtDev; + // all sheets (for Excel import) + SCTAB nTabCount = aDocument.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + { + SCCOL nEndCol; + SCROW nEndRow; + aDocument.GetCellArea( nTab, nEndCol, nEndRow ); + aColWidthRange.aEnd.SetCol( nEndCol ); + aColWidthRange.aEnd.SetRow( nEndRow ); + ScMarkData aMark; + aMark.SetMarkArea( aColWidthRange ); + aMark.MarkToMulti(); + // Reihenfolge erst Breite dann Hoehe ist wichtig (vergl. hund.rtf) + if ( bSetColWidths ) + { + for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ ) + { + USHORT nWidth = aDocument.GetOptimalColWidth( + nCol, nTab, &aVirtDev, nPPTX, nPPTY, aZoom, aZoom, FALSE, &aMark, + (bSetSimpleTextColWidths && bSimpleColWidth[nCol]) ); + aDocument.SetColWidth( nCol, nTab, + nWidth + (USHORT)ScGlobal::nLastColWidthExtra ); + } + } +// if ( bSetRowHeights ) +// { +// // nExtra must be 0 +// aDocument.SetOptimalHeight( 0, nEndRow, nTab, 0, &aVirtDev, +// nPPTX, nPPTY, aZoom, aZoom, FALSE ); +// } + } + if ( bSetRowHeights ) + UpdateAllRowHeights(); // with vdev or printer, depending on configuration + } + FinishedLoading( SFX_LOADED_MAINDOCUMENT | SFX_LOADED_IMAGES ); + + // #73762# invalidate eventually temporary table areas + if ( bRet ) + aDocument.InvalidateTableArea(); + + bIsEmpty = FALSE; + + return bRet; +} + + +ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell ) + : mrDocShell( rDocShell) +{ + // DoEnterHandler not here (because of AutoSave), is in ExecuteSave. + + ScChartListenerCollection* pCharts = mrDocShell.aDocument.GetChartListenerCollection(); + if (pCharts) + pCharts->UpdateDirtyCharts(); // Charts to be updated. + mrDocShell.aDocument.StopTemporaryChartLock(); + if (mrDocShell.pAutoStyleList) + mrDocShell.pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now. + if (mrDocShell.aDocument.HasExternalRefManager()) + { + ScExternalRefManager* pRefMgr = mrDocShell.aDocument.GetExternalRefManager(); + if (pRefMgr && pRefMgr->hasExternalData()) + { + pRefMgr->setAllCacheTableReferencedStati( false); + mrDocShell.aDocument.MarkUsedExternalReferences(); // Mark tables of external references to be written. + } + } + if (mrDocShell.GetCreateMode()== SFX_CREATE_MODE_STANDARD) + mrDocShell.SfxObjectShell::SetVisArea( Rectangle() ); // "Normally" worked on => no VisArea. +} + +ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() +{ + if (mrDocShell.aDocument.HasExternalRefManager()) + { + ScExternalRefManager* pRefMgr = mrDocShell.aDocument.GetExternalRefManager(); + if (pRefMgr && pRefMgr->hasExternalData()) + { + // Prevent accidental data loss due to lack of knowledge. + pRefMgr->setAllCacheTableReferencedStati( true); + } + } +} + + +BOOL __EXPORT ScDocShell::Save() +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::Save" ); + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + PrepareSaveGuard aPrepareGuard( *this); + + // wait cursor is handled with progress bar + BOOL bRet = SfxObjectShell::Save(); + if( bRet ) + bRet = SaveXML( GetMedium(), NULL ); + return bRet; +} + + +BOOL __EXPORT ScDocShell::SaveAs( SfxMedium& rMedium ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::SaveAs" ); + +#if ENABLE_SHEET_PROTECTION + ScTabViewShell* pViewShell = GetBestViewShell(); + if (pViewShell && ScPassHashHelper::needsPassHashRegen(aDocument, PASSHASH_OOO)) + { + if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_OOO)) + // password re-type cancelled. Don't save the document. + return false; + } +#endif + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + PrepareSaveGuard aPrepareGuard( *this); + + // wait cursor is handled with progress bar + BOOL bRet = SfxObjectShell::SaveAs( rMedium ); + if( bRet ) + bRet = SaveXML( &rMedium, NULL ); + + return bRet; +} + + +BOOL __EXPORT ScDocShell::IsInformationLost() +{ +/* + const SfxFilter *pFilt = GetMedium()->GetFilter(); + BOOL bRet = pFilt && pFilt->IsAlienFormat() && bNoInformLost; + if (bNoInformLost) // nur einmal!! + bNoInformLost = FALSE; + return bRet; +*/ + //!!! bei Gelegenheit ein korrekte eigene Behandlung einbauen + + return SfxObjectShell::IsInformationLost(); +} + + +// Xcl-like column width measured in characters of standard font. +xub_StrLen lcl_ScDocShell_GetColWidthInChars( USHORT nWidth ) +{ + // double fColScale = 1.0; + double f = nWidth; + f *= 1328.0 / 25.0; + f += 90.0; + f *= 1.0 / 23.0; + // f /= fColScale * 256.0; + f /= 256.0; + + return xub_StrLen( f ); +} + + +void lcl_ScDocShell_GetFixedWidthString( String& rStr, const ScDocument& rDoc, + SCTAB nTab, SCCOL nCol, BOOL bValue, SvxCellHorJustify eHorJust ) +{ + xub_StrLen nLen = lcl_ScDocShell_GetColWidthInChars( + rDoc.GetColWidth( nCol, nTab ) ); + if ( nLen < rStr.Len() ) + { + if ( bValue ) + rStr.AssignAscii( "###" ); + rStr.Erase( nLen ); + } + if ( nLen > rStr.Len() ) + { + if ( bValue && eHorJust == SVX_HOR_JUSTIFY_STANDARD ) + eHorJust = SVX_HOR_JUSTIFY_RIGHT; + switch ( eHorJust ) + { + case SVX_HOR_JUSTIFY_RIGHT: + { + String aTmp; + aTmp.Fill( nLen - rStr.Len() ); + rStr.Insert( aTmp, 0 ); + } + break; + case SVX_HOR_JUSTIFY_CENTER: + { + xub_StrLen nLen2 = (nLen - rStr.Len()) / 2; + String aTmp; + aTmp.Fill( nLen2 ); + rStr.Insert( aTmp, 0 ); + rStr.Expand( nLen ); + } + break; + default: + rStr.Expand( nLen ); + } + } +} + + +void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream, + const ScDocument& rDoc, SCTAB nTab, SCCOL nCol ) +{ + String aString; + lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, FALSE, + SVX_HOR_JUSTIFY_STANDARD ); + rStream.WriteUnicodeOrByteText( aString ); +} + + +void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt ) +{ + sal_Unicode cDelim = rAsciiOpt.nFieldSepCode; + sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode; + CharSet eCharSet = rAsciiOpt.eCharSet; + BOOL bFixedWidth = rAsciiOpt.bFixedWidth; + BOOL bSaveAsShown = rAsciiOpt.bSaveAsShown; + + CharSet eOldCharSet = rStream.GetStreamCharSet(); + rStream.SetStreamCharSet( eCharSet ); + USHORT nOldNumberFormatInt = rStream.GetNumberFormatInt(); + ByteString aStrDelimEncoded; // only used if not Unicode + UniString aStrDelimDecoded; // only used if context encoding + BOOL bContextOrNotAsciiEncoding; + if ( eCharSet == RTL_TEXTENCODING_UNICODE ) + { + rStream.StartWritingUnicodeText(); + bContextOrNotAsciiEncoding = FALSE; + } + else + { + aStrDelimEncoded = ByteString( cStrDelim, eCharSet ); + rtl_TextEncodingInfo aInfo; + aInfo.StructSize = sizeof(aInfo); + if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) ) + { + bContextOrNotAsciiEncoding = + (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) || + ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0)); + if ( bContextOrNotAsciiEncoding ) + aStrDelimDecoded = String( aStrDelimEncoded, eCharSet ); + } + else + bContextOrNotAsciiEncoding = FALSE; + } + + SCCOL nStartCol = 0; + SCROW nStartRow = 0; + SCTAB nTab = GetSaveTab(); + SCCOL nEndCol; + SCROW nEndRow; + aDocument.GetCellArea( nTab, nEndCol, nEndRow ); + + ScProgress aProgress( this, ScGlobal::GetRscString( STR_SAVE_DOC ), nEndRow ); + + String aString; + + ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell, SfxViewShell::Current()); + const ScViewOptions& rOpt = (pViewSh) + ? pViewSh->GetViewData()->GetOptions() + : aDocument.GetViewOptions(); + BOOL bShowFormulas = rOpt.GetOption( VOPT_FORMULAS ); + BOOL bTabProtect = aDocument.IsTabProtected( nTab ); + + SCCOL nCol; + SCROW nRow; + SCCOL nNextCol = nStartCol; + SCROW nNextRow = nStartRow; + SCCOL nEmptyCol; + SCROW nEmptyRow; + SvNumberFormatter& rFormatter = *aDocument.GetFormatTable(); + + ScHorizontalCellIterator aIter( &aDocument, nTab, nStartCol, nStartRow, + nEndCol, nEndRow ); + ScBaseCell* pCell; + while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != NULL ) + { + BOOL bProgress = FALSE; // only upon line change + if ( nNextRow < nRow ) + { // empty rows or/and empty columns up to end of row + bProgress = TRUE; + for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ ) + { // remaining columns of last row + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + endlub( rStream ); + nNextRow++; + for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ ) + { // completely empty rows + for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ ) + { + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + endlub( rStream ); + } + for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ ) + { // empty columns at beginning of row + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + nNextRow = nRow; + } + else if ( nNextCol < nCol ) + { // empty columns in same row + for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ ) + { // columns in between + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + } + if ( nCol == nEndCol ) + { + bProgress = TRUE; + nNextCol = nStartCol; + nNextRow = nRow + 1; + } + else + nNextCol = nCol + 1; + + CellType eType = pCell->GetCellType(); + if ( bTabProtect ) + { + const ScProtectionAttr* pProtAttr = + (const ScProtectionAttr*) aDocument.GetAttr( + nCol, nRow, nTab, ATTR_PROTECTION ); + if ( pProtAttr->GetHideCell() || + ( eType == CELLTYPE_FORMULA && bShowFormulas && + pProtAttr->GetHideFormula() ) ) + eType = CELLTYPE_NONE; // hide + } + BOOL bString; + switch ( eType ) + { + case CELLTYPE_NOTE: + case CELLTYPE_NONE: + aString.Erase(); + bString = FALSE; + break; + case CELLTYPE_FORMULA : + { + USHORT nErrCode; + if ( bShowFormulas ) + { + ((ScFormulaCell*)pCell)->GetFormula( aString ); + bString = TRUE; + } + else if ( ( nErrCode = ((ScFormulaCell*)pCell)->GetErrCode() ) != 0 ) + { + aString = ScGlobal::GetErrorString( nErrCode ); + bString = TRUE; + } + else if ( ((ScFormulaCell*)pCell)->IsValue() ) + { + sal_uInt32 nFormat; + aDocument.GetNumberFormat( nCol, nRow, nTab, nFormat ); + if ( bFixedWidth || bSaveAsShown ) + { + Color* pDummy; + ScCellFormat::GetString( pCell, nFormat, aString, &pDummy, rFormatter ); + bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat); + } + else + { + ScCellFormat::GetInputString( pCell, nFormat, aString, rFormatter ); + bString = FALSE; + } + } + else + { + if ( bSaveAsShown ) + { + sal_uInt32 nFormat; + aDocument.GetNumberFormat( nCol, nRow, nTab, nFormat ); + Color* pDummy; + ScCellFormat::GetString( pCell, nFormat, aString, &pDummy, rFormatter ); + } + else + ((ScFormulaCell*)pCell)->GetString( aString ); + bString = TRUE; + } + } + break; + case CELLTYPE_STRING : + if ( bSaveAsShown ) + { + sal_uInt32 nFormat; + aDocument.GetNumberFormat( nCol, nRow, nTab, nFormat ); + Color* pDummy; + ScCellFormat::GetString( pCell, nFormat, aString, &pDummy, rFormatter ); + } + else + ((ScStringCell*)pCell)->GetString( aString ); + bString = TRUE; + break; + case CELLTYPE_EDIT : + { + const EditTextObject* pObj; + static_cast<const ScEditCell*>(pCell)->GetData( pObj); + EditEngine& rEngine = aDocument.GetEditEngine(); + rEngine.SetText( *pObj); + aString = rEngine.GetText(); // including LF + bString = TRUE; + } + break; + case CELLTYPE_VALUE : + { + sal_uInt32 nFormat; + aDocument.GetNumberFormat( nCol, nRow, nTab, nFormat ); + if ( bFixedWidth || bSaveAsShown ) + { + Color* pDummy; + ScCellFormat::GetString( pCell, nFormat, aString, &pDummy, rFormatter ); + bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat); + } + else + { + ScCellFormat::GetInputString( pCell, nFormat, aString, rFormatter ); + bString = FALSE; + } + } + break; + default: + DBG_ERROR( "ScDocShell::AsciiSave: unknown CellType" ); + aString.Erase(); + bString = FALSE; + } + + if ( bFixedWidth ) + { + SvxCellHorJustify eHorJust = (SvxCellHorJustify) + ((const SvxHorJustifyItem*) aDocument.GetAttr( nCol, nRow, + nTab, ATTR_HOR_JUSTIFY ))->GetValue(); + lcl_ScDocShell_GetFixedWidthString( aString, aDocument, nTab, nCol, + !bString, eHorJust ); + rStream.WriteUnicodeOrByteText( aString ); + } + else + { + if (!bString && cStrDelim != 0 && aString.Len() > 0) + { + sal_Unicode c = aString.GetChar(0); + bString = (c == cStrDelim || c == ' ' || + aString.GetChar( aString.Len()-1) == ' ' || + aString.Search( cStrDelim) != STRING_NOTFOUND); + if (!bString && cDelim != 0) + bString = (aString.Search( cDelim) != STRING_NOTFOUND); + } + if ( bString ) + { + if ( cStrDelim != 0 ) //@ BugId 55355 + { + if ( eCharSet == RTL_TEXTENCODING_UNICODE ) + { + xub_StrLen nPos = aString.Search( cStrDelim ); + while ( nPos != STRING_NOTFOUND ) + { + aString.Insert( cStrDelim, nPos ); + nPos = aString.Search( cStrDelim, nPos+2 ); + } + rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); + rStream.WriteUnicodeText( aString ); + rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); + } + else + { + // #105549# This is nasty. The Unicode to byte encoding + // may convert typographical quotation marks to ASCII + // quotation marks, which may interfer with the delimiter, + // so we have to escape delimiters after the string has + // been encoded. Since this may happen also with UTF-8 + // encoded typographical quotation marks if such was + // specified as a delimiter we have to check for the full + // encoded delimiter string, not just one character. + // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain + // dead encodings where one code point (and especially a + // low ASCII value) may represent different characters, we + // have to convert forth and back and forth again. Same for + // UTF-7 since it is a context sensitive encoding too. + + if ( bContextOrNotAsciiEncoding ) + { + // to byte encoding + ByteString aStrEnc( aString, eCharSet ); + // back to Unicode + UniString aStrDec( aStrEnc, eCharSet ); + // search on re-decoded string + xub_StrLen nPos = aStrDec.Search( aStrDelimDecoded ); + while ( nPos != STRING_NOTFOUND ) + { + aStrDec.Insert( aStrDelimDecoded, nPos ); + nPos = aStrDec.Search( aStrDelimDecoded, + nPos+1+aStrDelimDecoded.Len() ); + } + // write byte re-encoded + rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); + rStream.WriteUnicodeOrByteText( aStrDec, eCharSet ); + rStream.WriteUniOrByteChar( cStrDelim, eCharSet ); + } + else + { + ByteString aStrEnc( aString, eCharSet ); + // search on encoded string + xub_StrLen nPos = aStrEnc.Search( aStrDelimEncoded ); + while ( nPos != STRING_NOTFOUND ) + { + aStrEnc.Insert( aStrDelimEncoded, nPos ); + nPos = aStrEnc.Search( aStrDelimEncoded, + nPos+1+aStrDelimEncoded.Len() ); + } + // write byte encoded + rStream.Write( aStrDelimEncoded.GetBuffer(), + aStrDelimEncoded.Len() ); + rStream.Write( aStrEnc.GetBuffer(), aStrEnc.Len() ); + rStream.Write( aStrDelimEncoded.GetBuffer(), + aStrDelimEncoded.Len() ); + } + } + } + else + rStream.WriteUnicodeOrByteText( aString ); + } + else + rStream.WriteUnicodeOrByteText( aString ); + } + + if( nCol < nEndCol ) + { + if(cDelim!=0) //@ BugId 55355 + rStream.WriteUniOrByteChar( cDelim ); + } + else + endlub( rStream ); + + if ( bProgress ) + aProgress.SetStateOnPercent( nRow ); + } + + // write out empty if requested + if ( nNextRow <= nEndRow ) + { + for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ ) + { // remaining empty columns of last row + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + endlub( rStream ); + nNextRow++; + } + for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ ) + { // entire empty rows + for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ ) + { + if ( bFixedWidth ) + lcl_ScDocShell_WriteEmptyFixedWidthString( rStream, + aDocument, nTab, nEmptyCol ); + else if ( cDelim != 0 ) + rStream.WriteUniOrByteChar( cDelim ); + } + endlub( rStream ); + } + + rStream.SetStreamCharSet( eOldCharSet ); + rStream.SetNumberFormatInt( nOldNumberFormatInt ); +} + +BOOL __EXPORT ScDocShell::ConvertTo( SfxMedium &rMed ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ConvertTo" ); + + ScRefreshTimerProtector( aDocument.GetRefreshTimerControlAddress() ); + + // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave), + // it's already in ExecuteSave (as for Save and SaveAs) + + if (pAutoStyleList) + pAutoStyleList->ExecuteAllNow(); // Vorlagen-Timeouts jetzt ausfuehren + if (GetCreateMode()== SFX_CREATE_MODE_STANDARD) + SfxObjectShell::SetVisArea( Rectangle() ); // normal bearbeitet -> keine VisArea + + DBG_ASSERT( rMed.GetFilter(), "Filter == 0" ); + + BOOL bRet = FALSE; + String aFltName = rMed.GetFilter()->GetFilterName(); + +/* + if (aFltName.EqualsAscii(pFilterLotus)) + { + SvStream* pStream = rMed.GetOutStream(); + if (pStream) + { + FltError eError = ScFormatFilter::Get().ScExportLotus123( *pStream, &aDocument, ExpWK1, + CHARSET_IBMPC_437 ); + bRet = eError == eERR_OK; + } + } + else +*/ + if (aFltName.EqualsAscii(pFilterXML)) + { + //TODO/LATER: this shouldn't happen! + DBG_ERROR("XML filter in ConvertFrom?!"); + bRet = SaveXML( &rMed, NULL ); + } + else if (aFltName.EqualsAscii(pFilterExcel5) || aFltName.EqualsAscii(pFilterExcel95) || + aFltName.EqualsAscii(pFilterExcel97) || aFltName.EqualsAscii(pFilterEx5Temp) || + aFltName.EqualsAscii(pFilterEx95Temp) || aFltName.EqualsAscii(pFilterEx97Temp) || + aFltName.EqualsAscii(pFilterEx07Xml)) + { + WaitObject aWait( GetActiveDialogParent() ); + + bool bDoSave = true; + if( ScTabViewShell* pViewShell = GetBestViewShell() ) + { + ScExtDocOptions* pExtDocOpt = aDocument.GetExtDocOptions(); + if( !pExtDocOpt ) + aDocument.SetExtDocOptions( pExtDocOpt = new ScExtDocOptions ); + pViewShell->GetViewData()->WriteExtOptions( *pExtDocOpt ); + + /* #115980# #i104990# If the imported document contains a medium + password, determine if we can save it, otherwise ask the users + whether they want to save without it. */ + if( !::sfx2::CheckMSPasswordCapabilityForExport( aFltName ) ) + { + SfxItemSet* pItemSet = rMed.GetItemSet(); + const SfxPoolItem* pItem = 0; + if( pItemSet && pItemSet->GetItemState( SID_PASSWORD, sal_True, &pItem ) == SFX_ITEM_SET ) + { + bDoSave = ScWarnPassword::WarningOnPassword( rMed ); + // #i42858# remove password from medium (warn only one time) + if( bDoSave ) + pItemSet->ClearItem( SID_PASSWORD ); + } + } + +#if ENABLE_SHEET_PROTECTION + if( bDoSave ) + { + bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( aDocument, PASSHASH_XL ); + bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL ); + } +#endif + } + + if( bDoSave ) + { + ExportFormatExcel eFormat = ExpBiff5; + if( aFltName.EqualsAscii( pFilterExcel97 ) || aFltName.EqualsAscii( pFilterEx97Temp ) ) + eFormat = ExpBiff8; + if( aFltName.EqualsAscii( pFilterEx07Xml ) ) + eFormat = Exp2007Xml; + FltError eError = ScFormatFilter::Get().ScExportExcel5( rMed, &aDocument, eFormat, RTL_TEXTENCODING_MS_1252 ); + + if( eError && !GetError() ) + SetError( eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + // don't return false for warnings + bRet = ((eError & ERRCODE_WARNING_MASK) == ERRCODE_WARNING_MASK) || (eError == eERR_OK); + } + else + { + // export aborted, i.e. "Save without password" warning + SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + else if (aFltName.EqualsAscii(pFilterAscii)) + { + SvStream* pStream = rMed.GetOutStream(); + if (pStream) + { + String sItStr; + SfxItemSet* pSet = rMed.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sItStr = ((const SfxStringItem*)pItem)->GetValue(); + } + + if ( sItStr.Len() == 0 ) + { + // default for ascii export (from API without options): + // ISO8859-1/MS_1252 encoding, comma, double quotes + + ScImportOptions aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252 ); + sItStr = aDefOptions.BuildString(); + } + + WaitObject aWait( GetActiveDialogParent() ); + ScImportOptions aOptions( sItStr ); + AsciiSave( *pStream, aOptions ); + bRet = TRUE; + + if (aDocument.GetTableCount() > 1) + if (!rMed.GetError()) + rMed.SetError(SCWARN_EXPORT_ASCII, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + } + else if (aFltName.EqualsAscii(pFilterDBase)) + { + String sCharSet; + SfxItemSet* pSet = rMed.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sCharSet = ((const SfxStringItem*)pItem)->GetValue(); + } + + if (sCharSet.Len() == 0) + { + // default for dBase export (from API without options): + // IBM_850 encoding + + sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 ); + } + + WaitObject aWait( GetActiveDialogParent() ); +// HACK damit Sba geoffnetes TempFile ueberschreiben kann + rMed.CloseOutStream(); + BOOL bHasMemo = FALSE; + + ULONG eError = DBaseExport( rMed.GetPhysicalName(), + ScGlobal::GetCharsetValue(sCharSet), bHasMemo ); + + if ( eError != eERR_OK && (eError & ERRCODE_WARNING_MASK) ) + { +//! if ( !rMed.GetError() ) +//! rMed.SetError( eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + eError = eERR_OK; + } +//! else if ( aDocument.GetTableCount() > 1 && !rMed.GetError() ) +//! rMed.SetError( SCWARN_EXPORT_ASCII, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + + INetURLObject aTmpFile( rMed.GetPhysicalName(), INET_PROT_FILE ); + if ( bHasMemo ) + aTmpFile.setExtension( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("dbt")) ); + if ( eError != eERR_OK ) + { + if (!GetError()) + SetError(eError, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + if ( bHasMemo && IsDocument( aTmpFile ) ) + KillFile( aTmpFile ); + } + else + { + bRet = TRUE; + if ( bHasMemo ) + { + SfxStringItem* pNameItem = + (SfxStringItem*) rMed.GetItemSet()->GetItem( SID_FILE_NAME ); + INetURLObject aDbtFile( pNameItem->GetValue(), INET_PROT_FILE ); + aDbtFile.setExtension( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("dbt")) ); + if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) ) + bRet = FALSE; + if ( bRet && !MoveFile( aTmpFile, aDbtFile ) ) + bRet = FALSE; + if ( !bRet ) + { + KillFile( aTmpFile ); + if ( !GetError() ) + SetError( SCERR_EXPORT_DATA, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + } + } + else if (aFltName.EqualsAscii(pFilterDif)) + { + SvStream* pStream = rMed.GetOutStream(); + if (pStream) + { + String sItStr; + SfxItemSet* pSet = rMed.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == + pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + { + sItStr = ((const SfxStringItem*)pItem)->GetValue(); + } + + if (sItStr.Len() == 0) + { + // default for DIF export (from API without options): + // ISO8859-1/MS_1252 encoding + + sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 ); + } + + WaitObject aWait( GetActiveDialogParent() ); + ScFormatFilter::Get().ScExportDif( *pStream, &aDocument, ScAddress(0,0,0), + ScGlobal::GetCharsetValue(sItStr) ); + bRet = TRUE; + + if (aDocument.GetTableCount() > 1) + if (!rMed.GetError()) + rMed.SetError(SCWARN_EXPORT_ASCII, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) )); + } + } + else if (aFltName.EqualsAscii(pFilterSylk)) + { + SvStream* pStream = rMed.GetOutStream(); + if ( pStream ) + { + WaitObject aWait( GetActiveDialogParent() ); + + SCCOL nEndCol; + SCROW nEndRow; + aDocument.GetCellArea( 0, nEndCol, nEndRow ); + ScRange aRange( 0,0,0, nEndCol,nEndRow,0 ); + + ScImportExport aImExport( &aDocument, aRange ); + aImExport.SetFormulas( TRUE ); + bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SOT_FORMATSTR_ID_SYLK ); + } + } + else if (aFltName.EqualsAscii(pFilterHtml)) + { + SvStream* pStream = rMed.GetOutStream(); + if ( pStream ) + { + WaitObject aWait( GetActiveDialogParent() ); + ScImportExport aImExport( &aDocument ); + aImExport.SetStreamPath( rMed.GetName() ); + bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SOT_FORMATSTR_ID_HTML ); + if ( bRet && aImExport.GetNonConvertibleChars().Len() ) + SetError( *new StringErrorInfo( + SCWARN_EXPORT_NONCONVERTIBLE_CHARS, + aImExport.GetNonConvertibleChars(), + ERRCODE_BUTTON_OK | ERRCODE_MSG_INFO ), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + } + else + { + if (GetError()) + SetError(SCERR_IMPORT_NI, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); + } + return bRet; +} + + +BOOL __EXPORT ScDocShell::SaveCompleted( const uno::Reference < embed::XStorage >& xStor ) +{ + return SfxObjectShell::SaveCompleted( xStor ); +} + + +BOOL __EXPORT ScDocShell::DoSaveCompleted( SfxMedium * pNewStor ) +{ + BOOL bRet = SfxObjectShell::DoSaveCompleted( pNewStor ); + + // SC_HINT_DOC_SAVED fuer Wechsel ReadOnly -> Read/Write + Broadcast( SfxSimpleHint( SC_HINT_DOC_SAVED ) ); + return bRet; +} + + +USHORT __EXPORT ScDocShell::PrepareClose( BOOL bUI, BOOL bForBrowsing ) +{ + if(SC_MOD()->GetCurRefDlgId()>0) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this, TYPE(SfxTopViewFrame) ); + if( pFrame ) + { + SfxViewShell* p = pFrame->GetViewShell(); + ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell,p); + if(pViewSh!=NULL) + { + Window *pWin=pViewSh->GetWindow(); + if(pWin!=NULL) pWin->GrabFocus(); + } + } + + return FALSE; + } + if ( aDocument.IsInLinkUpdate() || aDocument.IsInInterpreter() ) + { + ErrorMessage(STR_CLOSE_ERROR_LINK); + return FALSE; + } + + DoEnterHandler(); + + USHORT nRet = SfxObjectShell::PrepareClose( bUI, bForBrowsing ); + if (nRet == TRUE) // TRUE = schliessen + aDocument.DisableIdle(TRUE); // nicht mehr drin rumpfuschen !!! + + return nRet; +} + +void ScDocShell::PrepareReload() +{ + SfxObjectShell::PrepareReload(); // tut nichts? + + // Das Disconnect von DDE-Links kann Reschedule ausloesen. + // Wenn die DDE-Links erst im Dokument-dtor geloescht werden, kann beim Reload + // aus diesem Reschedule das DDE-Link-Update fuer das neue Dokument ausgeloest + // werden. Dabei verklemmt sicht dann irgendwas. + // -> Beim Reload die DDE-Links des alten Dokuments vorher disconnecten + + aDocument.DisconnectDdeLinks(); +} + + +String ScDocShell::GetOwnFilterName() // static +{ + return String::CreateFromAscii(pFilterSc50); +} + +String ScDocShell::GetWebQueryFilterName() // static +{ + return String::CreateFromAscii(pFilterHtmlWebQ); +} + +String ScDocShell::GetAsciiFilterName() // static +{ + return String::CreateFromAscii(pFilterAscii); +} + +String ScDocShell::GetLotusFilterName() // static +{ + return String::CreateFromAscii(pFilterLotus); +} + +String ScDocShell::GetDBaseFilterName() // static +{ + return String::CreateFromAscii(pFilterDBase); +} + +String ScDocShell::GetDifFilterName() // static +{ + return String::CreateFromAscii(pFilterDif); +} + +BOOL ScDocShell::HasAutomaticTableName( const String& rFilter ) // static +{ + // TRUE for those filters that keep the default table name + // (which is language specific) + + return rFilter.EqualsAscii( pFilterAscii ) + || rFilter.EqualsAscii( pFilterLotus ) + || rFilter.EqualsAscii( pFilterExcel4 ) + || rFilter.EqualsAscii( pFilterEx4Temp ) + || rFilter.EqualsAscii( pFilterDBase ) + || rFilter.EqualsAscii( pFilterDif ) + || rFilter.EqualsAscii( pFilterSylk ) + || rFilter.EqualsAscii( pFilterHtml ) + || rFilter.EqualsAscii( pFilterRtf ); +} + +//================================================================== + +#define __SCDOCSHELL_INIT \ + aDocument ( SCDOCMODE_DOCUMENT, this ), \ + aDdeTextFmt(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("TEXT"))), \ + nPrtToScreenFactor( 1.0 ), \ + pImpl ( new DocShell_Impl ), \ + bHeaderOn ( TRUE ), \ + bFooterOn ( TRUE ), \ + bNoInformLost ( TRUE ), \ + bIsEmpty ( TRUE ), \ + bIsInUndo ( FALSE ), \ + bDocumentModifiedPending( FALSE ), \ + nDocumentLock ( 0 ), \ + nCanUpdate (com::sun::star::document::UpdateDocMode::ACCORDING_TO_CONFIG), \ + bUpdateEnabled ( TRUE ), \ + pOldAutoDBRange ( NULL ), \ + pDocHelper ( NULL ), \ + pAutoStyleList ( NULL ), \ + pPaintLockData ( NULL ), \ + pOldJobSetup ( NULL ), \ + pSolverSaveData ( NULL ), \ + pSheetSaveData ( NULL ), \ + pModificator ( NULL ) + +//------------------------------------------------------------------ + +ScDocShell::ScDocShell( const ScDocShell& rShell ) + : SvRefBase(), + SotObject(), + SfxObjectShell( rShell.GetCreateMode() ), + SfxListener(), + __SCDOCSHELL_INIT +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ScDocShell" ); + + SetPool( &SC_MOD()->GetPool() ); + + bIsInplace = rShell.bIsInplace; + + pDocFunc = new ScDocFunc(*this); + + // SetBaseModel needs exception handling + ScModelObj::CreateAndSet( this ); + + StartListening(*this); + SfxStyleSheetPool* pStlPool = aDocument.GetStyleSheetPool(); + if (pStlPool) + StartListening(*pStlPool); + + GetPageOnFromPageStyleSet( NULL, 0, bHeaderOn, bFooterOn ); + SetHelpId( HID_SCSHELL_DOCSH ); + + // InitItems und CalcOutputFactor werden jetzt nach bei Load/ConvertFrom/InitNew gerufen +} + +//------------------------------------------------------------------ + +ScDocShell::ScDocShell( SfxObjectCreateMode eMode, const bool _bScriptSupport ) + : SfxObjectShell( eMode ), + __SCDOCSHELL_INIT +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::ScDocShell" ); + + SetPool( &SC_MOD()->GetPool() ); + + bIsInplace = (eMode == SFX_CREATE_MODE_EMBEDDED); + // wird zurueckgesetzt, wenn nicht inplace + + pDocFunc = new ScDocFunc(*this); + + if ( !_bScriptSupport ) + SetHasNoBasic(); + + // SetBaseModel needs exception handling + ScModelObj::CreateAndSet( this ); + + StartListening(*this); + SfxStyleSheetPool* pStlPool = aDocument.GetStyleSheetPool(); + if (pStlPool) + StartListening(*pStlPool); + SetHelpId( HID_SCSHELL_DOCSH ); + + aDocument.GetDBCollection()->SetRefreshHandler( + LINK( this, ScDocShell, RefreshDBDataHdl ) ); + + // InitItems und CalcOutputFactor werden jetzt nach bei Load/ConvertFrom/InitNew gerufen +} + +//------------------------------------------------------------------ + +__EXPORT ScDocShell::~ScDocShell() +{ + ResetDrawObjectShell(); // #55570# falls der Drawing-Layer noch versucht, darauf zuzugreifen + + SfxStyleSheetPool* pStlPool = aDocument.GetStyleSheetPool(); + if (pStlPool) + EndListening(*pStlPool); + EndListening(*this); + + delete pAutoStyleList; + + SfxApplication *pSfxApp = SFX_APP(); + if ( pSfxApp->GetDdeService() ) // DDE vor Dokument loeschen + pSfxApp->RemoveDdeTopic( this ); + + delete pDocFunc; + delete aDocument.mpUndoManager; + aDocument.mpUndoManager = 0; + delete pImpl; + + delete pPaintLockData; + + delete pOldJobSetup; // gesetzt nur bei Fehler in StartJob() + + delete pSolverSaveData; + delete pSheetSaveData; + delete pOldAutoDBRange; + + if (pModificator) + { + DBG_ERROR("The Modificator should not exist"); + delete pModificator; + } +} + +//------------------------------------------------------------------ + +SfxUndoManager* __EXPORT ScDocShell::GetUndoManager() +{ + return aDocument.GetUndoManager(); +} + +void ScDocShell::SetModified( BOOL bModified ) +{ + if ( SfxObjectShell::IsEnableSetModified() ) + { + SfxObjectShell::SetModified( bModified ); + Broadcast( SfxSimpleHint( SFX_HINT_DOCCHANGED ) ); + } +} + + +void ScDocShell::SetDocumentModified( BOOL bIsModified /* = TRUE */ ) +{ + // BroadcastUno muss auch mit pPaintLockData sofort passieren + //! auch bei SetDrawModified, wenn Drawing angebunden ist + //! dann eigener Hint??? + + if ( pPaintLockData && bIsModified ) + { + //! BCA_BRDCST_ALWAYS etc. also needed here? + aDocument.BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + + pPaintLockData->SetModified(); // spaeter... + return; + } + + SetDrawModified( bIsModified ); + + if ( bIsModified ) + { + if ( aDocument.IsAutoCalcShellDisabled() ) + SetDocumentModifiedPending( TRUE ); + else + { + SetDocumentModifiedPending( FALSE ); + aDocument.InvalidateStyleSheetUsage(); + aDocument.InvalidateTableArea(); + aDocument.InvalidateLastTableOpParams(); + aDocument.Broadcast( SC_HINT_DATACHANGED, BCA_BRDCST_ALWAYS, NULL ); + if ( aDocument.IsForcedFormulaPending() && aDocument.GetAutoCalc() ) + aDocument.CalcFormulaTree( TRUE ); + PostDataChanged(); + + // Detective AutoUpdate: + // Update if formulas were modified (DetectiveDirty) or the list contains + // "Trace Error" entries (#75362# - Trace Error can look completely different + // after changes to non-formula cells). + + ScDetOpList* pList = aDocument.GetDetOpList(); + if ( pList && ( aDocument.IsDetectiveDirty() || pList->HasAddError() ) && + pList->Count() && !IsInUndo() && SC_MOD()->GetAppOptions().GetDetectiveAuto() ) + { + GetDocFunc().DetectiveRefresh(TRUE); // TRUE = caused by automatic update + } + aDocument.SetDetectiveDirty(FALSE); // always reset, also if not refreshed + } + + // #b6697848# notify UNO objects after BCA_BRDCST_ALWAYS etc. + aDocument.BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + } +} + +// SetDrawModified - ohne Formel-Update +// (Drawing muss auch beim normalen SetDocumentModified upgedated werden, +// z.B. bei Tabelle loeschen etc.) + +void ScDocShell::SetDrawModified( BOOL bIsModified /* = TRUE */ ) +{ + BOOL bUpdate = ( bIsModified != IsModified() ); + + SetModified( bIsModified ); + + SfxBindings* pBindings = GetViewBindings(); + if (bUpdate) + { + if (pBindings) + { + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + } + + if (bIsModified) + { + if (pBindings) + { + // #i105960# Undo etc used to be volatile. + // They always have to be invalidated, including drawing layer or row height changes + // (but not while pPaintLockData is set). + pBindings->Invalidate( SID_UNDO ); + pBindings->Invalidate( SID_REDO ); + pBindings->Invalidate( SID_REPEAT ); + } + + if ( aDocument.IsChartListenerCollectionNeedsUpdate() ) + { + aDocument.UpdateChartListenerCollection(); + SFX_APP()->Broadcast(SfxSimpleHint( SC_HINT_DRAW_CHANGED )); // Navigator + } + SC_MOD()->AnythingChanged(); + } +} + +void ScDocShell::SetInUndo(BOOL bSet) +{ + bIsInUndo = bSet; +} + + +void ScDocShell::GetDocStat( ScDocStat& rDocStat ) +{ + SfxPrinter* pPrinter = GetPrinter(); + + aDocument.GetDocStat( rDocStat ); + rDocStat.nPageCount = 0; + + if ( pPrinter ) + for ( SCTAB i=0; i<rDocStat.nTableCount; i++ ) + rDocStat.nPageCount = sal::static_int_cast<USHORT>( rDocStat.nPageCount + + (USHORT) ScPrintFunc( this, pPrinter, i ).GetTotalPages() ); +} + + +SfxDocumentInfoDialog* __EXPORT ScDocShell::CreateDocumentInfoDialog( + Window *pParent, const SfxItemSet &rSet ) +{ + SfxDocumentInfoDialog* pDlg = new SfxDocumentInfoDialog( pParent, rSet ); + ScDocShell* pDocSh = PTR_CAST(ScDocShell,SfxObjectShell::Current()); + + //nur mit Statistik, wenn dieses Doc auch angezeigt wird, nicht + //aus dem Doc-Manager + + if( pDocSh == this ) + { + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc( RID_SCPAGE_STAT ); + DBG_ASSERT(ScDocStatPageCreate, "Tabpage create fail!");//CHINA001 + pDlg->AddTabPage( 42, + ScGlobal::GetRscString( STR_DOC_STAT ), + ScDocStatPageCreate, + NULL); +//CHINA001 pDlg->AddTabPage( 42, +//CHINA001 ScGlobal::GetRscString( STR_DOC_STAT ), +//CHINA001 ScDocStatPage::Create, +//CHINA001 NULL ); + } + return pDlg; +} + +Window* ScDocShell::GetActiveDialogParent() +{ + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if ( pViewSh ) + return pViewSh->GetDialogParent(); + else + return Application::GetDefDialogParent(); +} + +void ScDocShell::SetSolverSaveData( const ScOptSolverSave& rData ) +{ + delete pSolverSaveData; + pSolverSaveData = new ScOptSolverSave( rData ); +} + +ScSheetSaveData* ScDocShell::GetSheetSaveData() +{ + if (!pSheetSaveData) + pSheetSaveData = new ScSheetSaveData; + + return pSheetSaveData; +} + +void ScDocShell::UseSheetSaveEntries() +{ + if (pSheetSaveData) + { + pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving + + bool bHasEntries = false; + SCTAB nTabCount = aDocument.GetTableCount(); + SCTAB nTab; + for (nTab = 0; nTab < nTabCount; ++nTab) + if (pSheetSaveData->HasStreamPos(nTab)) + bHasEntries = true; + + if (!bHasEntries) + { + // if no positions were set (for example, export to other format), + // reset all "valid" flags + + for (nTab = 0; nTab < nTabCount; ++nTab) + if (aDocument.IsStreamValid(nTab)) + aDocument.SetStreamValid(nTab, FALSE); + } + } +} + +// --- ScDocShellModificator ------------------------------------------ + +ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS ) + : + rDocShell( rDS ), + aProtector( rDS.GetDocument()->GetRefreshTimerControlAddress() ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + bAutoCalcShellDisabled = pDoc->IsAutoCalcShellDisabled(); + bIdleDisabled = pDoc->IsIdleDisabled(); + pDoc->SetAutoCalcShellDisabled( TRUE ); + pDoc->DisableIdle( TRUE ); +} + + +ScDocShellModificator::~ScDocShellModificator() +{ + ScDocument* pDoc = rDocShell.GetDocument(); + pDoc->SetAutoCalcShellDisabled( bAutoCalcShellDisabled ); + if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() ) + rDocShell.SetDocumentModified(); // last one shuts off the lights + pDoc->DisableIdle( bIdleDisabled ); +} + + +void ScDocShellModificator::SetDocumentModified() +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if ( !pDoc->IsImportingXML() ) + { + // AutoCalcShellDisabled temporaer restaurieren + BOOL bDisabled = pDoc->IsAutoCalcShellDisabled(); + pDoc->SetAutoCalcShellDisabled( bAutoCalcShellDisabled ); + rDocShell.SetDocumentModified(); + pDoc->SetAutoCalcShellDisabled( bDisabled ); + } + else + { + // uno broadcast is necessary for api to work + // -> must also be done during xml import + pDoc->BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + } +} + +//<!--Added by PengYunQuan for Validity Cell Range Picker +sal_Bool ScDocShell::AcceptStateUpdate() const +{ + if( SfxObjectShell::AcceptStateUpdate() ) + return sal_True; + + if( SC_MOD()->Find1RefWindow( SFX_APP()->GetTopWindow() ) ) + return sal_True; + + return sal_False; +} +//-->Added by PengYunQuan for Validity Cell Range Picker diff --git a/sc/source/ui/docshell/docsh2.cxx b/sc/source/ui/docshell/docsh2.cxx new file mode 100644 index 000000000000..4b76c18edbe6 --- /dev/null +++ b/sc/source/ui/docshell/docsh2.cxx @@ -0,0 +1,261 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include <svx/svdpage.hxx> + + +#include <svx/xtable.hxx> + +#include "scitems.hxx" +#include <tools/gen.hxx> +#include <svtools/ctrltool.hxx> +#include <editeng/flstitem.hxx> +#include <svx/drawitem.hxx> +#include <sfx2/printer.hxx> +#include <svl/smplhint.hxx> +#include <svx/svditer.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdoole2.hxx> +#include <vcl/svapp.hxx> +#include <svl/asiancfg.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <editeng/unolingu.hxx> +#include <rtl/logfile.hxx> + +#include <comphelper/processfactory.hxx> +#include <basic/sbstar.hxx> +#include <basic/basmgr.hxx> +#include <sfx2/app.hxx> + +// INCLUDE --------------------------------------------------------------- +/* +#include <svdrwetc.hxx> +#include <svdrwobx.hxx> +#include <sostor.hxx> +*/ +#include "drwlayer.hxx" +#include "stlpool.hxx" +#include "docsh.hxx" +#include "docshimp.hxx" +#include "docfunc.hxx" +#include "sc.hrc" + +using namespace com::sun::star; + +//------------------------------------------------------------------ + +BOOL __EXPORT ScDocShell::InitNew( const uno::Reference < embed::XStorage >& xStor ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::InitNew" ); + + BOOL bRet = SfxObjectShell::InitNew( xStor ); + + aDocument.MakeTable(0); + // zusaetzliche Tabellen werden von der ersten View angelegt, + // wenn bIsEmpty dann noch TRUE ist + + if( bRet ) + { + Size aSize( (long) ( STD_COL_WIDTH * HMM_PER_TWIPS * OLE_STD_CELLS_X ), + (long) ( ScGlobal::nStdRowHeight * HMM_PER_TWIPS * OLE_STD_CELLS_Y ) ); + // hier muss auch der Start angepasst werden + SetVisAreaOrSize( Rectangle( Point(), aSize ), TRUE ); + } + + aDocument.SetDrawDefaults(); // drawing layer defaults that are set only in InitNew + + // InitOptions sets the document languages, must be called before CreateStandardStyles + InitOptions(); + + aDocument.GetStyleSheetPool()->CreateStandardStyles(); + aDocument.UpdStlShtPtrsFrmNms(); + + // SetDocumentModified ist in Load/InitNew nicht mehr erlaubt! + + InitItems(); + CalcOutputFactor(); + uno::Any aGlobs; + uno::Sequence< uno::Any > aArgs(1); + aArgs[ 0 ] <<= GetModel(); + aGlobs <<= ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.excel.Globals" ) ), aArgs ); + GetBasicManager()->SetGlobalUNOConstant( "VBAGlobals", aGlobs ); + // Fake ThisComponent being setup by Activate ( which is a view + // related thing ), + // a) if another document is opened then in theory ThisComponent + // will be reset as before, + // b) when this document is 'really' Activated then ThisComponent + // again will be set as before + // The only wrinkle seems if this document is loaded 'InVisible' + // but.. I don't see that this is possible from the vba API + // I could be wrong though + // There may be implications setting the current component + // too early :-/ so I will just manually set the Basic Variables + BasicManager* pAppMgr = SFX_APP()->GetBasicManager(); + if ( pAppMgr ) + pAppMgr->SetGlobalUNOConstant( "ThisExcelDoc", aArgs[ 0 ] ); + + return bRet; +} + +//------------------------------------------------------------------ + +BOOL ScDocShell::IsEmpty() const +{ + return bIsEmpty; +} + + +void ScDocShell::SetEmpty(BOOL bSet) +{ + bIsEmpty = bSet; +} + +//------------------------------------------------------------------ + +void ScDocShell::InitItems() +{ + // AllItemSet fuer Controller mit benoetigten Items fuellen: + + // if ( pImpl->pFontList ) + // delete pImpl->pFontList; + + // Druck-Optionen werden beim Drucken und evtl. in GetPrinter gesetzt + + // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() ); + //PutItem( SvxFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ) ); + UpdateFontList(); + + ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); + if (pDrawLayer) + { + PutItem( SvxColorTableItem ( pDrawLayer->GetColorTable(), SID_COLOR_TABLE ) ); + PutItem( SvxGradientListItem( pDrawLayer->GetGradientList(), SID_GRADIENT_LIST ) ); + PutItem( SvxHatchListItem ( pDrawLayer->GetHatchList(), SID_HATCH_LIST ) ); + PutItem( SvxBitmapListItem ( pDrawLayer->GetBitmapList(), SID_BITMAP_LIST ) ); + PutItem( SvxDashListItem ( pDrawLayer->GetDashList(), SID_DASH_LIST ) ); + PutItem( SvxLineEndListItem ( pDrawLayer->GetLineEndList(), SID_LINEEND_LIST ) ); + + // andere Anpassungen nach dem Anlegen des DrawLayers + + pDrawLayer->SetNotifyUndoActionHdl( LINK( pDocFunc, ScDocFunc, NotifyDrawUndo ) ); + + //if (SfxObjectShell::HasSbxObject()) + pDrawLayer->UpdateBasic(); // DocShell-Basic in DrawPages setzen + } + else + { + // always use global color table instead of local copy + PutItem( SvxColorTableItem( XColorTable::GetStdColorTable(), SID_COLOR_TABLE ) ); + } + + if ( !aDocument.GetForbiddenCharacters().isValid() || + !aDocument.IsValidAsianCompression() || !aDocument.IsValidAsianKerning() ) + { + // get settings from SvxAsianConfig + SvxAsianConfig aAsian( sal_False ); + + if ( !aDocument.GetForbiddenCharacters().isValid() ) + { + // set forbidden characters if necessary + uno::Sequence<lang::Locale> aLocales = aAsian.GetStartEndCharLocales(); + if (aLocales.getLength()) + { + vos::ORef<SvxForbiddenCharactersTable> xForbiddenTable = + new SvxForbiddenCharactersTable( aDocument.GetServiceManager() ); + + const lang::Locale* pLocales = aLocales.getConstArray(); + for (sal_Int32 i = 0; i < aLocales.getLength(); i++) + { + i18n::ForbiddenCharacters aForbidden; + aAsian.GetStartEndChars( pLocales[i], aForbidden.beginLine, aForbidden.endLine ); + LanguageType eLang = SvxLocaleToLanguage(pLocales[i]); + //pDoc->SetForbiddenCharacters( eLang, aForbidden ); + + xForbiddenTable->SetForbiddenCharacters( eLang, aForbidden ); + } + + aDocument.SetForbiddenCharacters( xForbiddenTable ); + } + } + + if ( !aDocument.IsValidAsianCompression() ) + { + // set compression mode from configuration if not already set (e.g. XML import) + aDocument.SetAsianCompression( sal::static_int_cast<BYTE>( aAsian.GetCharDistanceCompression() ) ); + } + + if ( !aDocument.IsValidAsianKerning() ) + { + // set asian punctuation kerning from configuration if not already set (e.g. XML import) + aDocument.SetAsianKerning( !aAsian.IsKerningWesternTextOnly() ); // reversed + } + } +} + +//------------------------------------------------------------------ + +void ScDocShell::ResetDrawObjectShell() +{ + ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); + if (pDrawLayer) + pDrawLayer->SetObjectShell( NULL ); +} + +//------------------------------------------------------------------ + +void __EXPORT ScDocShell::Activate() +{ +} + + +void __EXPORT ScDocShell::Deactivate() +{ +} + +//------------------------------------------------------------------ + + +ScDrawLayer* ScDocShell::MakeDrawLayer() +{ + ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); + if (!pDrawLayer) + { + RTL_LOGFILE_CONTEXT_AUTHOR ( aLog, "sc", "nn93723", "ScDocShell::MakeDrawLayer" ); + + aDocument.InitDrawLayer(this); + pDrawLayer = aDocument.GetDrawLayer(); + InitItems(); // incl. Undo und Basic + Broadcast( SfxSimpleHint( SC_HINT_DRWLAYER_NEW ) ); + if (nDocumentLock) + pDrawLayer->setLock(TRUE); + } + return pDrawLayer; +} diff --git a/sc/source/ui/docshell/docsh3.cxx b/sc/source/ui/docshell/docsh3.cxx new file mode 100644 index 000000000000..7ff714c2cbdd --- /dev/null +++ b/sc/source/ui/docshell/docsh3.cxx @@ -0,0 +1,1391 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include "scitems.hxx" +#include "rangelst.hxx" +#include <editeng/flstitem.hxx> +#include <svx/pageitem.hxx> +#include <editeng/paperinf.hxx> +#include <svx/postattr.hxx> +#include <editeng/sizeitem.hxx> +#include <unotools/misccfg.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/app.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/printer.hxx> +#include <svtools/ctrltool.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <vcl/msgbox.hxx> +#include <unotools/localedatawrapper.hxx> + +#include "docsh.hxx" +#include "docshimp.hxx" +#include "scmod.hxx" +#include "tabvwsh.hxx" +#include "viewdata.hxx" +#include "docpool.hxx" +#include "stlpool.hxx" +#include "patattr.hxx" +#include "uiitems.hxx" +#include "hints.hxx" +#include "docoptio.hxx" +#include "viewopti.hxx" +#include "pntlock.hxx" +#include "chgtrack.hxx" +#include "docfunc.hxx" +#include "cell.hxx" +#include "chgviset.hxx" +#include "progress.hxx" +#include "redcom.hxx" +#include "sc.hrc" +#include "inputopt.hxx" +#include "drwlayer.hxx" +#include "inputhdl.hxx" +#include "conflictsdlg.hxx" +#include "globstr.hrc" + +#if DEBUG_CHANGETRACK +#include <stdio.h> +#endif // DEBUG_CHANGETRACK + + +//------------------------------------------------------------------ + +// +// Redraw - Benachrichtigungen +// + + +void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos ) +{ +// Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) ); + + // Test: nur aktive ViewShell + + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if (pViewSh && pViewSh->GetViewData()->GetDocShell() == this) + { + ScEditViewHint aHint( pEditEngine, rCursorPos ); + pViewSh->Notify( *this, aHint ); + } +} + +void ScDocShell::PostDataChanged() +{ + Broadcast( SfxSimpleHint( FID_DATACHANGED ) ); + aDocument.ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) ); + + SFX_APP()->Broadcast(SfxSimpleHint( FID_ANYDATACHANGED )); // Navigator + //! Navigator direkt benachrichtigen! +} + +void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, + SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, USHORT nPart, + USHORT nExtFlags ) +{ + if (!ValidCol(nStartCol)) nStartCol = MAXCOL; + if (!ValidRow(nStartRow)) nStartRow = MAXROW; + if (!ValidCol(nEndCol)) nEndCol = MAXCOL; + if (!ValidRow(nEndRow)) nEndRow = MAXROW; + + if ( pPaintLockData ) + { + // #i54081# PAINT_EXTRAS still has to be brodcast because it changes the + // current sheet if it's invalid. All other flags added to pPaintLockData. + USHORT nLockPart = nPart & ~PAINT_EXTRAS; + if ( nLockPart ) + { + //! nExtFlags ??? + pPaintLockData->AddRange( ScRange( nStartCol, nStartRow, nStartTab, + nEndCol, nEndRow, nEndTab ), nLockPart ); + } + + nPart &= PAINT_EXTRAS; // for broadcasting + if ( !nPart ) + return; + } + + + if (nExtFlags & SC_PF_LINES) // Platz fuer Linien beruecksichtigen + { + //! Abfrage auf versteckte Spalten/Zeilen! + if (nStartCol>0) --nStartCol; + if (nEndCol<MAXCOL) ++nEndCol; + if (nStartRow>0) --nStartRow; + if (nEndRow<MAXROW) ++nEndRow; + } + + // um zusammengefasste erweitern + if (nExtFlags & SC_PF_TESTMERGE) + aDocument.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nStartTab ); + + if ( nStartCol != 0 || nEndCol != MAXCOL ) + { + // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left + // aligned cells are contained (see UpdatePaintExt). + // Special handling for RTL text (#i9731#) is unnecessary now with full + // support of right-aligned text. + + if ( ( nExtFlags & SC_PF_WHOLEROWS ) || + aDocument.HasAttrib( nStartCol,nStartRow,nStartTab, + MAXCOL,nEndRow,nEndTab, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) + { + nStartCol = 0; + nEndCol = MAXCOL; + } + } + + Broadcast( ScPaintHint( ScRange( nStartCol, nStartRow, nStartTab, + nEndCol, nEndRow, nEndTab ), nPart ) ); + + if ( nPart & PAINT_GRID ) + aDocument.ResetChanged( ScRange(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) ); +} + +void ScDocShell::PostPaint( const ScRange& rRange, USHORT nPart, USHORT nExtFlags ) +{ + PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(), + rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), + nPart, nExtFlags ); +} + +void ScDocShell::PostPaintGridAll() +{ + PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID ); +} + +void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab ) +{ + PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, SC_PF_TESTMERGE ); +} + +void ScDocShell::PostPaintCell( const ScAddress& rPos ) +{ + PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() ); +} + +void ScDocShell::PostPaintExtras() +{ + PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_EXTRAS ); +} + +void ScDocShell::UpdatePaintExt( USHORT& rExtFlags, const ScRange& rRange ) +{ + if ( ( rExtFlags & SC_PF_LINES ) == 0 && aDocument.HasAttrib( rRange, HASATTR_PAINTEXT ) ) + { + // If the range contains lines, shadow or conditional formats, + // set SC_PF_LINES to include one extra cell in all directions. + + rExtFlags |= SC_PF_LINES; + } + + if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 && + ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != MAXCOL ) && + aDocument.HasAttrib( rRange, HASATTR_ROTATE | HASATTR_RIGHTORCENTER ) ) + { + // If the range contains (logically) right- or center-aligned cells, + // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows. + // This test isn't needed after the cell changes, because it's also + // tested in PostPaint. UpdatePaintExt may later be changed to do this + // only if called before the changes. + + rExtFlags |= SC_PF_WHOLEROWS; + } +} + +void ScDocShell::UpdatePaintExt( USHORT& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, + SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab ) +{ + UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) ); +} + +//------------------------------------------------------------------ + +void ScDocShell::LockPaint_Impl(BOOL bDoc) +{ + if ( !pPaintLockData ) + pPaintLockData = new ScPaintLockData(0); //! Modus... + pPaintLockData->IncLevel(bDoc); +} + +void ScDocShell::UnlockPaint_Impl(BOOL bDoc) +{ + if ( pPaintLockData ) + { + if ( pPaintLockData->GetLevel(bDoc) ) + pPaintLockData->DecLevel(bDoc); + if (!pPaintLockData->GetLevel(!bDoc) && !pPaintLockData->GetLevel(bDoc)) + { + // Paint jetzt ausfuehren + + ScPaintLockData* pPaint = pPaintLockData; + pPaintLockData = NULL; // nicht weitersammeln + + ScRangeListRef xRangeList = pPaint->GetRangeList(); + if (xRangeList) + { + USHORT nParts = pPaint->GetParts(); + ULONG nCount = xRangeList->Count(); + for ( ULONG i=0; i<nCount; i++ ) + { + //! nExtFlags ??? + ScRange aRange = *xRangeList->GetObject(i); + PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), + aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), + nParts ); + } + } + + if ( pPaint->GetModified() ) + SetDocumentModified(); + + delete pPaint; + } + } + else + { + DBG_ERROR("UnlockPaint ohne LockPaint"); + } +} + +void ScDocShell::LockDocument_Impl(USHORT nNew) +{ + if (!nDocumentLock) + { + ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); + if (pDrawLayer) + pDrawLayer->setLock(TRUE); + } + nDocumentLock = nNew; +} + +void ScDocShell::UnlockDocument_Impl(USHORT nNew) +{ + nDocumentLock = nNew; + if (!nDocumentLock) + { + ScDrawLayer* pDrawLayer = aDocument.GetDrawLayer(); + if (pDrawLayer) + pDrawLayer->setLock(FALSE); + } +} + +USHORT ScDocShell::GetLockCount() const +{ + return nDocumentLock; +} + +void ScDocShell::SetLockCount(USHORT nNew) +{ + if (nNew) // setzen + { + if ( !pPaintLockData ) + pPaintLockData = new ScPaintLockData(0); //! Modus... + pPaintLockData->SetLevel(nNew-1, TRUE); + LockDocument_Impl(nNew); + } + else if (pPaintLockData) // loeschen + { + pPaintLockData->SetLevel(0, TRUE); // bei Unlock sofort ausfuehren + UnlockPaint_Impl(TRUE); // jetzt + UnlockDocument_Impl(0); + } +} + +void ScDocShell::LockPaint() +{ + LockPaint_Impl(FALSE); +} + +void ScDocShell::UnlockPaint() +{ + UnlockPaint_Impl(FALSE); +} + +void ScDocShell::LockDocument() +{ + LockPaint_Impl(TRUE); + LockDocument_Impl(nDocumentLock + 1); +} + +void ScDocShell::UnlockDocument() +{ + if (nDocumentLock) + { + UnlockPaint_Impl(TRUE); + UnlockDocument_Impl(nDocumentLock - 1); + } + else + { + DBG_ERROR("UnlockDocument without LockDocument"); + } +} + +//------------------------------------------------------------------ + +void ScDocShell::SetInplace( BOOL bInplace ) +{ + if (bIsInplace != bInplace) + { + bIsInplace = bInplace; + CalcOutputFactor(); + } +} + +void ScDocShell::CalcOutputFactor() +{ + if (bIsInplace) + { + nPrtToScreenFactor = 1.0; // passt sonst nicht zur inaktiven Darstellung + return; + } + + BOOL bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg(); + if (bTextWysiwyg) + { + nPrtToScreenFactor = 1.0; + return; + } + + String aTestString = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789" )); + long nPrinterWidth = 0; + long nWindowWidth = 0; + const ScPatternAttr* pPattern = (const ScPatternAttr*)&aDocument.GetPool()-> + GetDefaultItem(ATTR_PATTERN); + + Font aDefFont; + OutputDevice* pRefDev = GetRefDevice(); + MapMode aOldMode = pRefDev->GetMapMode(); + Font aOldFont = pRefDev->GetFont(); + + pRefDev->SetMapMode(MAP_PIXEL); + pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pRefDev); // font color doesn't matter here + pRefDev->SetFont(aDefFont); + nPrinterWidth = pRefDev->PixelToLogic( Size( pRefDev->GetTextWidth(aTestString), 0 ), MAP_100TH_MM ).Width(); + pRefDev->SetFont(aOldFont); + pRefDev->SetMapMode(aOldMode); + + VirtualDevice aVirtWindow( *Application::GetDefaultDevice() ); + aVirtWindow.SetMapMode(MAP_PIXEL); + pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, &aVirtWindow); // font color doesn't matter here + aVirtWindow.SetFont(aDefFont); + nWindowWidth = aVirtWindow.GetTextWidth(aTestString); + nWindowWidth = (long) ( nWindowWidth / ScGlobal::nScreenPPTX * HMM_PER_TWIPS ); + + if (nPrinterWidth && nWindowWidth) + nPrtToScreenFactor = nPrinterWidth / (double) nWindowWidth; + else + { + DBG_ERROR("GetTextSize gibt 0 ??"); + nPrtToScreenFactor = 1.0; + } +} + +double ScDocShell::GetOutputFactor() const +{ + return nPrtToScreenFactor; +} + +//--------------------------------------------------------------------- + +void ScDocShell::InitOptions() // Fortsetzung von InitNew (CLOOKs) +{ + // Einstellungen aus dem SpellCheckCfg kommen in Doc- und ViewOptions + + USHORT nDefLang, nCjkLang, nCtlLang; + BOOL bAutoSpell; + ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell ); + ScModule* pScMod = SC_MOD(); + + ScDocOptions aDocOpt = pScMod->GetDocOptions(); + ScViewOptions aViewOpt = pScMod->GetViewOptions(); + aDocOpt.SetAutoSpell( bAutoSpell ); + + // zweistellige Jahreszahleneingabe aus Extras->Optionen->Allgemein->Sonstiges + aDocOpt.SetYear2000( sal::static_int_cast<USHORT>( ::utl::MiscCfg().GetYear2000() ) ); + + aDocument.SetDocOptions( aDocOpt ); + aDocument.SetViewOptions( aViewOpt ); + + // Druck-Optionen werden jetzt direkt vor dem Drucken gesetzt + + aDocument.SetLanguage( (LanguageType) nDefLang, (LanguageType) nCjkLang, (LanguageType) nCtlLang ); +} + +//--------------------------------------------------------------------- + +Printer* ScDocShell::GetDocumentPrinter() // fuer OLE +{ + return aDocument.GetPrinter(); +} + +SfxPrinter* ScDocShell::GetPrinter(BOOL bCreateIfNotExist) +{ + return aDocument.GetPrinter(bCreateIfNotExist); +} + +void ScDocShell::UpdateFontList() +{ + delete pImpl->pFontList; + // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() ); + pImpl->pFontList = new FontList( GetRefDevice(), NULL, FALSE ); // FALSE or TRUE??? + SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); + PutItem( aFontListItem ); + + CalcOutputFactor(); +} + +OutputDevice* ScDocShell::GetRefDevice() +{ + return aDocument.GetRefDevice(); +} + +USHORT ScDocShell::SetPrinter( SfxPrinter* pNewPrinter, USHORT nDiffFlags ) +{ + SfxPrinter *pOld = aDocument.GetPrinter( FALSE ); + if ( pOld && pOld->IsPrinting() ) + return SFX_PRINTERROR_BUSY; + + if (nDiffFlags & SFX_PRINTER_PRINTER) + { + if ( aDocument.GetPrinter() != pNewPrinter ) + { + aDocument.SetPrinter( pNewPrinter ); + aDocument.SetPrintOptions(); + + // MT: Use UpdateFontList: Will use Printer fonts only if needed! + /* + delete pImpl->pFontList; + pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() ); + SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST ); + PutItem( aFontListItem ); + + CalcOutputFactor(); + */ + if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() ) + UpdateFontList(); + + ScModule* pScMod = SC_MOD(); + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this ); + while (pFrame) + { + SfxViewShell* pSh = pFrame->GetViewShell(); + if (pSh && pSh->ISA(ScTabViewShell)) + { + ScTabViewShell* pViewSh = (ScTabViewShell*)pSh; + ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh); + if (pInputHdl) + pInputHdl->UpdateRefDevice(); + } + pFrame = SfxViewFrame::GetNext( *pFrame, this ); + } + } + } + else if (nDiffFlags & SFX_PRINTER_JOBSETUP) + { + SfxPrinter* pOldPrinter = aDocument.GetPrinter(); + if (pOldPrinter) + { + pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() ); + + // #i6706# Call SetPrinter with the old printer again, so the drawing layer + // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts), + // because the JobSetup (printer device settings) may affect text layout. + aDocument.SetPrinter( pOldPrinter ); + CalcOutputFactor(); // also with the new settings + } + } + + if (nDiffFlags & SFX_PRINTER_OPTIONS) + { + aDocument.SetPrintOptions(); //! aus neuem Printer ??? + } + + if (nDiffFlags & (SFX_PRINTER_CHG_ORIENTATION | SFX_PRINTER_CHG_SIZE)) + { + String aStyle = aDocument.GetPageStyle( GetCurTab() ); + ScStyleSheetPool* pStPl = aDocument.GetStyleSheetPool(); + SfxStyleSheet* pStyleSheet = (SfxStyleSheet*)pStPl->Find(aStyle, SFX_STYLE_FAMILY_PAGE); + if (pStyleSheet) + { + SfxItemSet& rSet = pStyleSheet->GetItemSet(); + + if (nDiffFlags & SFX_PRINTER_CHG_ORIENTATION) + { + const SvxPageItem& rOldItem = (const SvxPageItem&)rSet.Get(ATTR_PAGE); + BOOL bWasLand = rOldItem.IsLandscape(); + BOOL bNewLand = ( pNewPrinter->GetOrientation() == ORIENTATION_LANDSCAPE ); + if (bNewLand != bWasLand) + { + SvxPageItem aNewItem( rOldItem ); + aNewItem.SetLandscape( bNewLand ); + rSet.Put( aNewItem ); + + // Groesse umdrehen + Size aOldSize = ((const SvxSizeItem&)rSet.Get(ATTR_PAGE_SIZE)).GetSize(); + Size aNewSize(aOldSize.Height(),aOldSize.Width()); + SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize); + rSet.Put( aNewSItem ); + } + } + if (nDiffFlags & SFX_PRINTER_CHG_SIZE) + { + SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) ); + rSet.Put( aPaperSizeItem ); + } + } + } + + PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB,PAINT_ALL); + + return 0; +} + +//--------------------------------------------------------------------- + +ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos ) +{ + ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); + if (!pTrack) + return NULL; + + SCTAB nTab = rPos.Tab(); + + const ScChangeAction* pFound = NULL; + const ScChangeAction* pFoundContent = NULL; + const ScChangeAction* pFoundMove = NULL; + long nModified = 0; + const ScChangeAction* pAction = pTrack->GetFirst(); + while (pAction) + { + ScChangeActionType eType = pAction->GetType(); + //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )... + if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS ) + { + const ScBigRange& rBig = pAction->GetBigRange(); + if ( rBig.aStart.Tab() == nTab ) + { + ScRange aRange = rBig.MakeRange(); + + if ( eType == SC_CAT_DELETE_ROWS ) + aRange.aEnd.SetRow( aRange.aStart.Row() ); + else if ( eType == SC_CAT_DELETE_COLS ) + aRange.aEnd.SetCol( aRange.aStart.Col() ); + + if ( aRange.In( rPos ) ) + { + pFound = pAction; // der letzte gewinnt + switch ( pAction->GetType() ) + { + case SC_CAT_CONTENT : + pFoundContent = pAction; + break; + case SC_CAT_MOVE : + pFoundMove = pAction; + break; + default: + { + // added to avoid warnings + } + } + ++nModified; + } + } + if ( pAction->GetType() == SC_CAT_MOVE ) + { + ScRange aRange = + ((const ScChangeActionMove*)pAction)-> + GetFromRange().MakeRange(); + if ( aRange.In( rPos ) ) + { + pFound = pAction; + ++nModified; + } + } + } + pAction = pAction->GetNext(); + } + + return (ScChangeAction*)pFound; +} + +void ScDocShell::SetChangeComment( ScChangeAction* pAction, const String& rComment ) +{ + if (pAction) + { + pAction->SetComment( rComment ); + //! Undo ??? + SetDocumentModified(); + + // Dialog-Notify + ScChangeTrack* pTrack = GetDocument()->GetChangeTrack(); + if (pTrack) + { + ULONG nNumber = pAction->GetActionNumber(); + pTrack->NotifyModified( SC_CTM_CHANGE, nNumber, nNumber ); + } + } +} + +void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, Window* pParent,BOOL bPrevNext) +{ + if (!pAction) return; // ohne Aktion ist nichts.. + + String aComment = pAction->GetComment(); + String aAuthor = pAction->GetUser(); + + DateTime aDT = pAction->GetDateTime(); + String aDate = ScGlobal::pLocaleData->getDate( aDT ); + aDate += ' '; + aDate += ScGlobal::pLocaleData->getTime( aDT, FALSE, FALSE ); + + SfxItemSet aSet( GetPool(), + SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_AUTHOR, + SID_ATTR_POSTIT_DATE, SID_ATTR_POSTIT_DATE, + SID_ATTR_POSTIT_TEXT, SID_ATTR_POSTIT_TEXT, + 0 ); + + aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) ); + aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) ); + aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) ); + + ScRedComDialog* pDlg = new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext); + + pDlg->Execute(); + + delete pDlg; +} + +//--------------------------------------------------------------------- + +void ScDocShell::CompareDocument( ScDocument& rOtherDoc ) +{ + ScChangeTrack* pTrack = aDocument.GetChangeTrack(); + if ( pTrack && pTrack->GetFirst() ) + { + //! Changes vorhanden -> Nachfrage ob geloescht werden soll + } + + aDocument.EndChangeTracking(); + aDocument.StartChangeTracking(); + + String aOldUser; + pTrack = aDocument.GetChangeTrack(); + if ( pTrack ) + { + aOldUser = pTrack->GetUser(); + + // check if comparing to same document + + String aThisFile; + const SfxMedium* pThisMed = GetMedium(); + if (pThisMed) + aThisFile = pThisMed->GetName(); + String aOtherFile; + SfxObjectShell* pOtherSh = rOtherDoc.GetDocumentShell(); + if (pOtherSh) + { + const SfxMedium* pOtherMed = pOtherSh->GetMedium(); + if (pOtherMed) + aOtherFile = pOtherMed->GetName(); + } + BOOL bSameDoc = ( aThisFile == aOtherFile && aThisFile.Len() ); + if ( !bSameDoc ) + { + // create change actions from comparing with the name of the user + // who last saved the document + // (only if comparing different documents) + + using namespace ::com::sun::star; + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "no DocumentProperties"); + String aDocUser = xDocProps->getModifiedBy(); + + if ( aDocUser.Len() ) + pTrack->SetUser( aDocUser ); + } + } + + aDocument.CompareDocument( rOtherDoc ); + + pTrack = aDocument.GetChangeTrack(); + if ( pTrack ) + pTrack->SetUser( aOldUser ); + + PostPaintGridAll(); + SetDocumentModified(); +} + +//--------------------------------------------------------------------- +// +// Merge (Aenderungen zusammenfuehren) +// +//--------------------------------------------------------------------- + +inline BOOL lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, BOOL bIgnore100Sec ) +{ + return pA && pB && + pA->GetActionNumber() == pB->GetActionNumber() && + pA->GetType() == pB->GetType() && + pA->GetUser() == pB->GetUser() && + (bIgnore100Sec ? + pA->GetDateTimeUTC().IsEqualIgnore100Sec( pB->GetDateTimeUTC() ) : + pA->GetDateTimeUTC() == pB->GetDateTimeUTC()); + // State nicht vergleichen, falls eine alte Aenderung akzeptiert wurde +} + +bool lcl_FindAction( ScDocument* pDoc, const ScChangeAction* pAction, ScDocument* pSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, BOOL bIgnore100Sec ) +{ + if ( !pDoc || !pAction || !pSearchDoc || !pFirstSearchAction || !pLastSearchAction ) + { + return false; + } + + ULONG nLastSearchAction = pLastSearchAction->GetActionNumber(); + const ScChangeAction* pA = pFirstSearchAction; + while ( pA && pA->GetActionNumber() <= nLastSearchAction ) + { + if ( pAction->GetType() == pA->GetType() && + pAction->GetUser() == pA->GetUser() && + (bIgnore100Sec ? + pAction->GetDateTimeUTC().IsEqualIgnore100Sec( pA->GetDateTimeUTC() ) : + pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) && + pAction->GetBigRange() == pA->GetBigRange() ) + { + String aActionDesc; + pAction->GetDescription( aActionDesc, pDoc, TRUE ); + String aADesc; + pA->GetDescription( aADesc, pSearchDoc, TRUE ); + if ( aActionDesc.Equals( aADesc ) ) + { + DBG_ERROR( "lcl_FindAction(): found equal action!" ); + return true; + } + } + pA = pA->GetNext(); + } + + return false; +} + +void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, ULONG nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap ) +{ + ScTabViewShell* pViewSh = GetBestViewShell( FALSE ); //! Funktionen an die DocShell + if (!pViewSh) + return; + + ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack(); + if (!pSourceTrack) + return; //! nichts zu tun - Fehlermeldung? + + ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); + if ( !pThisTrack ) + { // anschalten + aDocument.StartChangeTracking(); + pThisTrack = aDocument.GetChangeTrack(); + DBG_ASSERT(pThisTrack,"ChangeTracking nicht angeschaltet?"); + if ( !bShared ) + { + // #51138# visuelles RedLining einschalten + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges(TRUE); + aDocument.SetChangeViewSettings(aChangeViewSet); + } + } + + // #97286# include 100th seconds in compare? + BOOL bIgnore100Sec = !pSourceTrack->IsTime100thSeconds() || + !pThisTrack->IsTime100thSeconds(); + + // gemeinsame Ausgangsposition suchen + ULONG nFirstNewNumber = 0; + const ScChangeAction* pSourceAction = pSourceTrack->GetFirst(); + const ScChangeAction* pThisAction = pThisTrack->GetFirst(); + // skip identical actions + while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) ) + { + nFirstNewNumber = pSourceAction->GetActionNumber() + 1; + pSourceAction = pSourceAction->GetNext(); + pThisAction = pThisAction->GetNext(); + } + // pSourceAction und pThisAction zeigen jetzt auf die ersten "eigenen" Aktionen + // Die gemeinsamen Aktionen davor interessieren ueberhaupt nicht + + //! Abfrage, ob die Dokumente vor dem Change-Tracking gleich waren !!! + + + const ScChangeAction* pFirstMergeAction = pSourceAction; + const ScChangeAction* pFirstSearchAction = pThisAction; + + // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong + const ScChangeAction* pLastSearchAction = pThisTrack->GetLast(); + + // MergeChangeData aus den folgenden Aktionen erzeugen + ULONG nNewActionCount = 0; + const ScChangeAction* pCount = pSourceAction; + while ( pCount ) + { + if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) ) + ++nNewActionCount; + pCount = pCount->GetNext(); + } + if (!nNewActionCount) + return; //! nichts zu tun - Fehlermeldung? + // ab hier kein return mehr + + ScProgress aProgress( this, + String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("...")), + nNewActionCount ); + + ULONG nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber(); + // UpdateReference-Undo, gueltige Referenzen fuer den letzten gemeinsamen Zustand + pSourceTrack->MergePrepare( (ScChangeAction*) pFirstMergeAction, bShared ); + + // MergeChangeData an alle noch folgenden Aktionen in diesem Dokument anpassen + // -> Referenzen gueltig fuer dieses Dokument + while ( pThisAction ) + { + // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly + if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) ) + { + ScChangeActionType eType = pThisAction->GetType(); + switch ( eType ) + { + case SC_CAT_INSERT_COLS : + case SC_CAT_INSERT_ROWS : + case SC_CAT_INSERT_TABS : + pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange() ); + break; + case SC_CAT_DELETE_COLS : + case SC_CAT_DELETE_ROWS : + case SC_CAT_DELETE_TABS : + { + const ScChangeActionDel* pDel = (const ScChangeActionDel*) pThisAction; + if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) + { // deleted Table enthaelt deleted Cols, die nicht + ULONG nStart, nEnd; + pSourceTrack->AppendDeleteRange( + pDel->GetOverAllRange().MakeRange(), NULL, nStart, nEnd ); + } + } + break; + case SC_CAT_MOVE : + { + const ScChangeActionMove* pMove = (const ScChangeActionMove*) pThisAction; + pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange(), + pMove->GetBigRange().MakeRange(), NULL ); + } + break; + default: + { + // added to avoid warnings + } + } + } + pThisAction = pThisAction->GetNext(); + } + + LockPaint(); // #i73877# no repainting after each action + + // MergeChangeData in das aktuelle Dokument uebernehmen + BOOL bHasRejected = FALSE; + String aOldUser = pThisTrack->GetUser(); + pThisTrack->SetUseFixDateTime( TRUE ); + ScMarkData& rMarkData = pViewSh->GetViewData()->GetMarkData(); + ScMarkData aOldMarkData( rMarkData ); + pSourceAction = pFirstMergeAction; + while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction ) + { + bool bMergeAction = false; + if ( bShared ) + { + if ( !bCheckDuplicates || !lcl_FindAction( &rOtherDoc, pSourceAction, &aDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) ) + { + bMergeAction = true; + } + } + else + { + if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) ) + { + bMergeAction = true; + } + } + + if ( bMergeAction ) + { + ScChangeActionType eSourceType = pSourceAction->GetType(); + if ( !bShared && pSourceAction->IsDeletedIn() ) + { + //! muss hier noch festgestellt werden, ob wirklich in + //! _diesem_ Dokument geloescht? + + // liegt in einem Bereich, der in diesem Dokument geloescht wurde + // -> wird weggelassen + //! ??? Loesch-Aktion rueckgaengig machen ??? + //! ??? Aktion irgendwo anders speichern ??? +#ifdef DBG_UTIL + String aValue; + if ( eSourceType == SC_CAT_CONTENT ) + ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); + ByteString aError( aValue, gsl_getSystemTextEncoding() ); + aError += " weggelassen"; + DBG_ERROR( aError.GetBuffer() ); +#endif + } + else + { + //! Datum/Autor/Kommentar der Source-Aktion uebernehmen! + + pThisTrack->SetUser( pSourceAction->GetUser() ); + pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() ); + ULONG nOldActionMax = pThisTrack->GetActionMax(); + + bool bExecute = true; + ULONG nReject = pSourceAction->GetRejectAction(); + if ( nReject ) + { + if ( bShared ) + { + if ( nReject >= nFirstNewNumber ) + { + nReject += nOffset; + } + ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); + if ( pOldAction && pOldAction->IsVirgin() ) + { + pThisTrack->Reject( pOldAction ); + bHasRejected = TRUE; + bExecute = false; + } + } + else + { + // alte Aktion (aus den gemeinsamen) ablehnen + ScChangeAction* pOldAction = pThisTrack->GetAction( nReject ); + if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN) + { + //! was passiert bei Aktionen, die in diesem Dokument accepted worden sind??? + //! Fehlermeldung oder was??? + //! oder Reject-Aenderung normal ausfuehren + + pThisTrack->Reject(pOldAction); + bHasRejected = TRUE; // fuer Paint + } + bExecute = false; + } + } + + if ( bExecute ) + { + // normal ausfuehren + ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange(); + rMarkData.SelectOneTable( aSourceRange.aStart.Tab() ); + switch ( eSourceType ) + { + case SC_CAT_CONTENT: + { + //! Test, ob es ganz unten im Dokument war, dann automatisches + //! Zeilen-Einfuegen ??? + + DBG_ASSERT( aSourceRange.aStart == aSourceRange.aEnd, "huch?" ); + ScAddress aPos = aSourceRange.aStart; + String aValue; + ((const ScChangeActionContent*)pSourceAction)->GetNewString( aValue ); + BYTE eMatrix = MM_NONE; + const ScBaseCell* pCell = ((const ScChangeActionContent*)pSourceAction)->GetNewCell(); + if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) + eMatrix = ((const ScFormulaCell*)pCell)->GetMatrixFlag(); + switch ( eMatrix ) + { + case MM_NONE : + pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); + break; + case MM_FORMULA : + { + SCCOL nCols; + SCROW nRows; + ((const ScFormulaCell*)pCell)->GetMatColsRows( nCols, nRows ); + aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 ); + aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 ); + aValue.Erase( 0, 1 ); + aValue.Erase( aValue.Len()-1, 1 ); + GetDocFunc().EnterMatrix( aSourceRange, + NULL, NULL, aValue, FALSE, FALSE, + EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT ); + } + break; + case MM_REFERENCE : // do nothing + break; + case MM_FAKE : + DBG_WARNING( "MergeDocument: MatrixFlag MM_FAKE" ); + pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue ); + break; + default: + DBG_ERROR( "MergeDocument: unknown MatrixFlag" ); + } + } + break; + case SC_CAT_INSERT_TABS : + { + String aName; + aDocument.CreateValidTabName( aName ); + GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, TRUE, FALSE ); + } + break; + case SC_CAT_INSERT_ROWS: + GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSROWS, TRUE, FALSE ); + break; + case SC_CAT_INSERT_COLS: + GetDocFunc().InsertCells( aSourceRange, NULL, INS_INSCOLS, TRUE, FALSE ); + break; + case SC_CAT_DELETE_TABS : + GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), TRUE, FALSE ); + break; + case SC_CAT_DELETE_ROWS: + { + const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; + if ( pDel->IsTopDelete() ) + { + aSourceRange = pDel->GetOverAllRange().MakeRange(); + GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELROWS, TRUE, FALSE ); + } + } + break; + case SC_CAT_DELETE_COLS: + { + const ScChangeActionDel* pDel = (const ScChangeActionDel*) pSourceAction; + if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() ) + { // deleted Table enthaelt deleted Cols, die nicht + aSourceRange = pDel->GetOverAllRange().MakeRange(); + GetDocFunc().DeleteCells( aSourceRange, NULL, DEL_DELCOLS, TRUE, FALSE ); + } + } + break; + case SC_CAT_MOVE : + { + const ScChangeActionMove* pMove = (const ScChangeActionMove*) pSourceAction; + ScRange aFromRange( pMove->GetFromRange().MakeRange() ); + GetDocFunc().MoveBlock( aFromRange, + aSourceRange.aStart, TRUE, TRUE, FALSE, FALSE ); + } + break; + default: + { + // added to avoid warnings + } + } + } + const String& rComment = pSourceAction->GetComment(); + if ( rComment.Len() ) + { + ScChangeAction* pAct = pThisTrack->GetLast(); + if ( pAct && pAct->GetActionNumber() > nOldActionMax ) + pAct->SetComment( rComment ); +#ifdef DBG_UTIL + else + DBG_ERROR( "MergeDocument: wohin mit dem Kommentar?!?" ); +#endif + } + + // Referenzen anpassen + pSourceTrack->MergeOwn( (ScChangeAction*) pSourceAction, nFirstNewNumber, bShared ); + + // merge action state + if ( bShared && !pSourceAction->IsRejected() ) + { + ScChangeAction* pAct = pThisTrack->GetLast(); + if ( pAct && pAct->GetActionNumber() > nOldActionMax ) + { + pThisTrack->MergeActionState( pAct, pSourceAction ); + } + } + + // fill merge map + if ( bShared && pMergeMap ) + { + ScChangeAction* pAct = pThisTrack->GetLast(); + if ( pAct && pAct->GetActionNumber() > nOldActionMax ) + { + ULONG nActionMax = pAct->GetActionNumber(); + ULONG nActionCount = nActionMax - nOldActionMax; + ULONG nAction = nActionMax - nActionCount + 1; + ULONG nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1; + while ( nAction <= nActionMax ) + { + if ( bInverseMap ) + { + (*pMergeMap)[ nAction++ ] = nSourceAction++; + } + else + { + (*pMergeMap)[ nSourceAction++ ] = nAction++; + } + } + } + } + } + aProgress.SetStateCountDown( --nNewActionCount ); + } + pSourceAction = pSourceAction->GetNext(); + } + + rMarkData = aOldMarkData; + pThisTrack->SetUser(aOldUser); + pThisTrack->SetUseFixDateTime( FALSE ); + + pSourceTrack->Clear(); //! der ist jetzt verhunzt + + if (bHasRejected) + PostPaintGridAll(); // Reject() paintet nicht selber + + UnlockPaint(); +} + +bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell ) +{ + if ( !pSharedDocShell ) + { + return false; + } + + ScChangeTrack* pThisTrack = aDocument.GetChangeTrack(); + if ( !pThisTrack ) + { + return false; + } + + ScDocument& rSharedDoc = *( pSharedDocShell->GetDocument() ); + ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack(); + if ( !pSharedTrack ) + { + return false; + } + +#if DEBUG_CHANGETRACK + ::rtl::OUString aMessage = ::rtl::OUString::createFromAscii( "\nbefore merge:\n" ); + aMessage += pThisTrack->ToString(); + ::rtl::OString aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); + OSL_ENSURE( false, aMsg.getStr() ); + //fprintf( stdout, "%s ", aMsg.getStr() ); + //fflush( stdout ); +#endif // DEBUG_CHANGETRACK + + // reset show changes + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges( FALSE ); + aDocument.SetChangeViewSettings( aChangeViewSet ); + + // find first merge action in this document + BOOL bIgnore100Sec = !pThisTrack->IsTime100thSeconds() || !pSharedTrack->IsTime100thSeconds(); + ScChangeAction* pThisAction = pThisTrack->GetFirst(); + ScChangeAction* pSharedAction = pSharedTrack->GetFirst(); + while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) ) + { + pThisAction = pThisAction->GetNext(); + pSharedAction = pSharedAction->GetNext(); + } + + if ( pSharedAction ) + { + if ( pThisAction ) + { + // merge own changes into shared document + ULONG nActStartShared = pSharedAction->GetActionNumber(); + ULONG nActEndShared = pSharedTrack->GetActionMax(); + ScDocument* pTmpDoc = new ScDocument; + for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) + { + String sTabName; + pTmpDoc->CreateValidTabName( sTabName ); + pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); + } + aDocument.GetChangeTrack()->Clone( pTmpDoc ); + ScChangeActionMergeMap aOwnInverseMergeMap; + pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true ); + delete pTmpDoc; + ULONG nActStartOwn = nActEndShared + 1; + ULONG nActEndOwn = pSharedTrack->GetActionMax(); + + // find conflicts + ScConflictsList aConflictsList; + ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList ); + if ( aFinder.Find() ) + { + ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnInverseMergeMap ); + bool bLoop = true; + while ( bLoop ) + { + bLoop = false; + ScConflictsDlg aDlg( GetActiveDialogParent(), GetViewData(), &rSharedDoc, aConflictsList ); + if ( aDlg.Execute() == RET_CANCEL ) + { + QueryBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO | WB_DEF_YES ), + ScGlobal::GetRscString( STR_DOC_WILLNOTBESAVED ) ); + if ( aBox.Execute() == RET_YES ) + { + return false; + } + else + { + bLoop = true; + } + } + } + } + + // undo own changes in shared document + pSharedTrack->Undo( nActStartOwn, nActEndOwn ); + + // clone change track for merging into own document + pTmpDoc = new ScDocument; + for ( sal_Int32 nIndex = 0; nIndex < aDocument.GetTableCount(); ++nIndex ) + { + String sTabName; + pTmpDoc->CreateValidTabName( sTabName ); + pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName ); + } + pThisTrack->Clone( pTmpDoc ); + + // undo own changes since last save in own document + ULONG nStartShared = pThisAction->GetActionNumber(); + ScChangeAction* pAction = pThisTrack->GetLast(); + while ( pAction && pAction->GetActionNumber() >= nStartShared ) + { + pThisTrack->Reject( pAction, true ); + pAction = pAction->GetPrev(); + } + + // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong + pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true ); + + // merge shared changes into own document + ScChangeActionMergeMap aSharedMergeMap; + MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap ); + ULONG nEndShared = pThisTrack->GetActionMax(); + + // resolve conflicts for shared non-content actions + if ( !aConflictsList.empty() ) + { + ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, NULL ); + ScConflictsResolver aResolver( pThisTrack, aConflictsList ); + pAction = pThisTrack->GetAction( nEndShared ); + while ( pAction && pAction->GetActionNumber() >= nStartShared ) + { + aResolver.HandleAction( pAction, true /*bIsSharedAction*/, + false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); + pAction = pAction->GetPrev(); + } + } + nEndShared = pThisTrack->GetActionMax(); + + // only show changes from shared document + aChangeViewSet.SetShowChanges( TRUE ); + aChangeViewSet.SetShowAccepted( TRUE ); + aChangeViewSet.SetHasActionRange( true ); + aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); + aDocument.SetChangeViewSettings( aChangeViewSet ); + + // merge own changes back into own document + ULONG nStartOwn = nEndShared + 1; + ScChangeActionMergeMap aOwnMergeMap; + MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap ); + delete pTmpDoc; + ULONG nEndOwn = pThisTrack->GetActionMax(); + + // resolve conflicts for shared content actions and own actions + if ( !aConflictsList.empty() ) + { + ScConflictsListHelper::TransformConflictsList( aConflictsList, NULL, &aOwnMergeMap ); + ScConflictsResolver aResolver( pThisTrack, aConflictsList ); + pAction = pThisTrack->GetAction( nEndShared ); + while ( pAction && pAction->GetActionNumber() >= nStartShared ) + { + aResolver.HandleAction( pAction, true /*bIsSharedAction*/, + true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ ); + pAction = pAction->GetPrev(); + } + + pAction = pThisTrack->GetAction( nEndOwn ); + while ( pAction && pAction->GetActionNumber() >= nStartOwn ) + { + aResolver.HandleAction( pAction, false /*bIsSharedAction*/, + true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ ); + pAction = pAction->GetPrev(); + } + } + nEndOwn = pThisTrack->GetActionMax(); + } + else + { + // merge shared changes into own document + ULONG nStartShared = pThisTrack->GetActionMax() + 1; + MergeDocument( rSharedDoc, true, true ); + ULONG nEndShared = pThisTrack->GetActionMax(); + + // only show changes from shared document + aChangeViewSet.SetShowChanges( TRUE ); + aChangeViewSet.SetShowAccepted( TRUE ); + aChangeViewSet.SetHasActionRange( true ); + aChangeViewSet.SetTheActionRange( nStartShared, nEndShared ); + aDocument.SetChangeViewSettings( aChangeViewSet ); + } + + // update view + PostPaintExtras(); + PostPaintGridAll(); + + InfoBox aInfoBox( GetActiveDialogParent(), ScGlobal::GetRscString( STR_DOC_UPDATED ) ); + aInfoBox.Execute(); + } + +#if DEBUG_CHANGETRACK + aMessage = ::rtl::OUString::createFromAscii( "\nafter merge:\n" ); + aMessage += pThisTrack->ToString(); + aMsg = ::rtl::OUStringToOString( aMessage, RTL_TEXTENCODING_UTF8 ); + OSL_ENSURE( false, aMsg.getStr() ); + //fprintf( stdout, "%s ", aMsg.getStr() ); + //fflush( stdout ); +#endif // DEBUG_CHANGETRACK + + return ( pThisAction != NULL ); +} diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx new file mode 100644 index 000000000000..97403008915d --- /dev/null +++ b/sc/source/ui/docshell/docsh4.cxx @@ -0,0 +1,2730 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> + + +using namespace ::com::sun::star; + +// INCLUDE --------------------------------------------------------------- +#if STLPORT_VERSION>=321 +#include <math.h> // prevent conflict between exception and std::exception +#endif + +#include "scitems.hxx" +#include <sfx2/fcontnr.hxx> +#include <editeng/eeitem.hxx> + +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <svtools/ehdl.hxx> +#include <basic/sbxcore.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/request.hxx> +#include <svtools/sfxecode.hxx> +#include <sfx2/topfrm.hxx> +#include <svx/ofaitem.hxx> +#include <sot/formats.hxx> +#include <svtools/printdlg.hxx> +#include <svl/whiter.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/waitobj.hxx> +#include <tools/multisel.hxx> +#include <svx/drawitem.hxx> +#include <svx/fmview.hxx> +#include <svx/pageitem.hxx> +#include <svx/svditer.hxx> +#include <svx/svdpage.hxx> +#include <svx/fmshell.hxx> +#include <sfx2/passwd.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/docinsert.hxx> +#include <svl/PasswordHelper.hxx> +#include <svl/documentlockfile.hxx> +#include <svl/sharecontrolfile.hxx> + +#include <comphelper/processfactory.hxx> +#include "docuno.hxx" + +#include <com/sun/star/sdbc/XResultSet.hpp> +#include "docsh.hxx" +#include "docshimp.hxx" +#include "docfunc.hxx" +#include "sc.hrc" +#include "stlsheet.hxx" +#include "stlpool.hxx" +#include "appoptio.hxx" +#include "globstr.hrc" +#include "global.hxx" +//CHINA001 #include "styledlg.hxx" +//CHINA001 #include "hfedtdlg.hxx" +#include "dbdocfun.hxx" +#include "printfun.hxx" // DrawToDev +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "impex.hxx" +#include "attrib.hxx" +//CHINA001 #include "corodlg.hxx" +#include "undodat.hxx" +#include "autostyl.hxx" +#include "undocell.hxx" +#include "undotab.hxx" +#include "inputhdl.hxx" +#include "dbcolect.hxx" +#include "servobj.hxx" +#include "rangenam.hxx" +#include "scmod.hxx" +//CHINA001 #include "scendlg.hxx" +#include "chgviset.hxx" +#include "reffact.hxx" +#include "chartlis.hxx" +#include "waitoff.hxx" +#include "tablink.hxx" // ScDocumentLoader statics +#include "drwlayer.hxx" +#include "docoptio.hxx" +#include "undostyl.hxx" +#include "rangeseq.hxx" +#include "chgtrack.hxx" +#include "printopt.hxx" +#include <com/sun/star/document/UpdateDocMode.hpp> +#include "scresid.hxx" //add by CHINA001 +#include "scabstdlg.hxx" //CHINA001 +#include "externalrefmgr.hxx" + +#include "sharedocdlg.hxx" +#include "conditio.hxx" + +//------------------------------------------------------------------ + +#define IS_SHARE_HEADER(set) \ + ((SfxBoolItem&) \ + ((SvxSetItem&)(set).Get(ATTR_PAGE_HEADERSET)).GetItemSet(). \ + Get(ATTR_PAGE_SHARED)).GetValue() + +#define IS_SHARE_FOOTER(set) \ + ((SfxBoolItem&) \ + ((SvxSetItem&)(set).Get(ATTR_PAGE_FOOTERSET)).GetItemSet(). \ + Get(ATTR_PAGE_SHARED)).GetValue() + +#define IS_AVAILABLE(WhichId,ppItem) \ + (pReqArgs->GetItemState((WhichId), TRUE, ppItem ) == SFX_ITEM_SET) + +#define SC_PREVIEW_SIZE_X 10000 +#define SC_PREVIEW_SIZE_Y 12400 + + +//------------------------------------------------------------------ + +void ScDocShell::Execute( SfxRequest& rReq ) +{ + // SID_SC_RANGE (Range), + // SID_SC_CELLTEXT (CellText), + // SID_SC_CELLS (Cells) - removed (old Basic) + + const SfxItemSet* pReqArgs = rReq.GetArgs(); + SfxBindings* pBindings = GetViewBindings(); + BOOL bUndo (aDocument.IsUndoEnabled()); + + USHORT nSlot = rReq.GetSlot(); + switch ( nSlot ) + { + case SID_SC_SETTEXT: + { + const SfxPoolItem* pColItem; + const SfxPoolItem* pRowItem; + const SfxPoolItem* pTabItem; + const SfxPoolItem* pTextItem; + if( pReqArgs && IS_AVAILABLE( FN_PARAM_1, &pColItem ) && + IS_AVAILABLE( FN_PARAM_2, &pRowItem ) && + IS_AVAILABLE( FN_PARAM_3, &pTabItem ) && + IS_AVAILABLE( SID_SC_SETTEXT, &pTextItem ) ) + { + // Parameter sind 1-based !!! + SCCOL nCol = ((SfxInt16Item*)pColItem)->GetValue() - 1; + SCROW nRow = ((SfxInt32Item*)pRowItem)->GetValue() - 1; + SCTAB nTab = ((SfxInt16Item*)pTabItem)->GetValue() - 1; + + SCTAB nTabCount = aDocument.GetTableCount(); + if ( ValidCol(nCol) && ValidRow(nRow) && ValidTab(nTab,nTabCount) ) + { + if ( aDocument.IsBlockEditable( nTab, nCol,nRow, nCol, nRow ) ) + { + String aVal = ((const SfxStringItem*)pTextItem)->GetValue(); + aDocument.SetString( nCol, nRow, nTab, aVal ); + + PostPaintCell( nCol, nRow, nTab ); + SetDocumentModified(); + + rReq.Done(); + break; + } + else // geschuetzte Zelle + { + SbxBase::SetError( SbxERR_BAD_PARAMETER ); //! welchen Fehler ? + break; + } + } + } + SbxBase::SetError( SbxERR_NO_OBJECT ); + } + break; + + + // SID_SBA_QRY_CHANGETARGET gibts nicht mehr - auch in idl raus + + case SID_SBA_IMPORT: + { + if (pReqArgs) + { + const sal_Unicode cSbaSep = 11; // Trennzeichen + + const SfxPoolItem* pItem; + String sSbaData, sTarget; + if ( pReqArgs->GetItemState( nSlot, TRUE, &pItem ) == SFX_ITEM_SET ) + sSbaData = ((const SfxStringItem*)pItem)->GetValue(); + if ( pReqArgs->GetItemState( FN_PARAM_1, TRUE, &pItem ) == SFX_ITEM_SET ) + sTarget = ((const SfxStringItem*)pItem)->GetValue(); + + BOOL bIsNewArea = TRUE; // Default TRUE (keine Nachfrage) + if ( pReqArgs->GetItemState( FN_PARAM_2, TRUE, &pItem ) == SFX_ITEM_SET ) + bIsNewArea = ((const SfxBoolItem*)pItem)->GetValue(); + + ::com::sun::star::uno::Reference< + ::com::sun::star::sdbc::XResultSet > xResultSet; + if ( pReqArgs->GetItemState( FN_PARAM_3, FALSE, &pItem ) == SFX_ITEM_SET && pItem ) + xResultSet.set(((const SfxUsrAnyItem*)pItem)->GetValue(),::com::sun::star::uno::UNO_QUERY); + + String sDBName = sSbaData.GetToken(0,cSbaSep); // Datenbankname + String sDBTable = sSbaData.GetToken(1,cSbaSep); // Tabellen- oder Query-Name + String sTabFlag = sSbaData.GetToken(2,cSbaSep); + String sDBSql = sSbaData.GetToken(3,cSbaSep); // SQL im Klartext + + BYTE nType = ScDbTable; // "0" oder "1" + if ( sTabFlag.EqualsAscii("0") ) // "0" = Query, "1" = Table (Default) + nType = ScDbQuery; + + SbaSelectionListRef pSelectionList = new SbaSelectionList; + xub_StrLen nCount = sSbaData.GetTokenCount(cSbaSep); + + for (xub_StrLen i = 4; i < nCount; i++) + { + String aSelItem = sSbaData.GetToken(i,cSbaSep); + if (aSelItem.Len()) + { + void *pPtr = (void*)aSelItem.ToInt32(); + pSelectionList->Insert( pPtr, LIST_APPEND ); + } + } + + // bei Bedarf neuen Datenbankbereich anlegen + BOOL bMakeArea = FALSE; + if (bIsNewArea) + { + ScDBCollection* pDBColl = aDocument.GetDBCollection(); + USHORT nDummy; + if ( !pDBColl || !pDBColl->SearchName( sTarget, nDummy ) ) + { + ScAddress aPos; + if ( aPos.Parse( sTarget, &aDocument, aDocument.GetAddressConvention() ) & SCA_VALID ) + { + bMakeArea = TRUE; + if (bUndo) + { + String aStrImport = ScGlobal::GetRscString( STR_UNDO_IMPORTDATA ); + GetUndoManager()->EnterListAction( aStrImport, aStrImport ); + } + + ScDBData* pDBData = GetDBData( ScRange(aPos), SC_DB_IMPORT, FALSE ); + DBG_ASSERT(pDBData, "kann DB-Daten nicht anlegen"); + sTarget = pDBData->GetName(); + } + } + } + + // nachfragen, bevor alter DB-Bereich ueberschrieben wird + BOOL bDo = TRUE; + if (!bIsNewArea) + { + String aTemplate = ScGlobal::GetRscString( STR_IMPORT_REPLACE ); + String aMessage = aTemplate.GetToken( 0, '#' ); + aMessage += sTarget; + aMessage += aTemplate.GetToken( 1, '#' ); + + QueryBox aBox( 0, WinBits(WB_YES_NO | WB_DEF_YES), aMessage ); + bDo = ( aBox.Execute() == RET_YES ); + } + + if (bDo) + { + ScDBDocFunc(*this).UpdateImport( sTarget, sDBName, + sDBTable, sDBSql, TRUE, nType, xResultSet, + pSelectionList ); + rReq.Done(); + + // UpdateImport aktualisiert auch die internen Operationen + } + else + rReq.Ignore(); + + if ( bMakeArea && bUndo) + GetUndoManager()->LeaveListAction(); + } + else + { + DBG_ERROR( "arguments expected" ); + } + } + break; + + case SID_CHART_SOURCE: + case SID_CHART_ADDSOURCE: + if (pReqArgs) + { + ScDocument* pDoc = GetDocument(); +// BOOL bUndo (pDoc->IsUndoEnabled()); + const SfxPoolItem* pItem; + String aChartName, aRangeName; + + ScRange aSingleRange; + ScRangeListRef aRangeListRef; + BOOL bMultiRange = FALSE; + + BOOL bColHeaders = TRUE; + BOOL bRowHeaders = TRUE; + BOOL bColInit = FALSE; + BOOL bRowInit = FALSE; + BOOL bAddRange = (nSlot == SID_CHART_ADDSOURCE); + + if( IS_AVAILABLE( SID_CHART_NAME, &pItem ) ) + aChartName = ((const SfxStringItem*)pItem)->GetValue(); + + if( IS_AVAILABLE( SID_CHART_SOURCE, &pItem ) ) + aRangeName = ((const SfxStringItem*)pItem)->GetValue(); + + if( IS_AVAILABLE( FN_PARAM_1, &pItem ) ) + { + bColHeaders = ((const SfxBoolItem*)pItem)->GetValue(); + bColInit = TRUE; + } + if( IS_AVAILABLE( FN_PARAM_2, &pItem ) ) + { + bRowHeaders = ((const SfxBoolItem*)pItem)->GetValue(); + bRowInit = TRUE; + } + + ScAddress::Details aDetails(pDoc->GetAddressConvention(), 0, 0); + BOOL bValid = ( aSingleRange.ParseAny( aRangeName, pDoc, aDetails ) & SCA_VALID ) != 0; + if (!bValid) + { + aRangeListRef = new ScRangeList; + aRangeListRef->Parse( aRangeName, pDoc ); + if ( aRangeListRef->Count() ) + { + bMultiRange = TRUE; + aSingleRange = *aRangeListRef->GetObject(0); // fuer Header + bValid = TRUE; + } + else + aRangeListRef.Clear(); + } + + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if (pViewSh && bValid && aChartName.Len() != 0 ) + { + Window* pParent = pViewSh->GetDialogParent(); + + SCCOL nCol1 = aSingleRange.aStart.Col(); + SCROW nRow1 = aSingleRange.aStart.Row(); + SCCOL nCol2 = aSingleRange.aEnd.Col(); + SCROW nRow2 = aSingleRange.aEnd.Row(); + SCTAB nTab = aSingleRange.aStart.Tab(); + + //! immer oder gar nicht begrenzen ??? + if (!bMultiRange) + aDocument.LimitChartArea( nTab, nCol1,nRow1, nCol2,nRow2 ); + + // Dialog fuer Spalten/Zeilenkoepfe + BOOL bOk = TRUE; + if ( !bAddRange && ( !bColInit || !bRowInit ) ) + { + // Spalten/Zeilenkoepfe testen wie in chartarr + if (!bColInit) + { + for (SCCOL i=nCol1; i<=nCol2 && bColHeaders; i++) + if (aDocument.HasValueData( i, nRow1, nTab )) + bColHeaders = FALSE; + } + if (!bRowInit) + { + for (SCROW i=nRow1; i<=nRow2 && bRowHeaders; i++) + if (aDocument.HasValueData( nCol1, i, nTab )) + bRowHeaders = FALSE; + } + + //CHINA001 ScColRowLabelDlg aDlg( pParent, bRowHeaders, bColHeaders ); + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + + AbstractScColRowLabelDlg* pDlg = pFact->CreateScColRowLabelDlg( pParent, RID_SCDLG_CHARTCOLROW, bRowHeaders, bColHeaders); + DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 + if ( pDlg->Execute() == RET_OK ) //CHINA001 if ( aDlg.Execute() == RET_OK ) + { + bColHeaders = pDlg->IsRow(); //CHINA001 bColHeaders = aDlg.IsRow(); // Spaltenkoepfe = 1. Zeile + bRowHeaders = pDlg->IsCol(); //CHINA001 bRowHeaders = aDlg.IsCol(); + + rReq.AppendItem(SfxBoolItem(FN_PARAM_1, bColHeaders)); + rReq.AppendItem(SfxBoolItem(FN_PARAM_2, bRowHeaders)); + } + else + bOk = FALSE; + delete pDlg; //CHINA001 + } + + if (bOk) // ausfuehren + { + if (bMultiRange) + { + if (bUndo) + { + GetUndoManager()->AddUndoAction( + new ScUndoChartData( this, aChartName, aRangeListRef, + bColHeaders, bRowHeaders, bAddRange ) ); + } + aDocument.UpdateChartArea( aChartName, aRangeListRef, + bColHeaders, bRowHeaders, bAddRange ); + } + else + { + ScRange aNewRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab ); + if (bUndo) + { + GetUndoManager()->AddUndoAction( + new ScUndoChartData( this, aChartName, aNewRange, + bColHeaders, bRowHeaders, bAddRange ) ); + } + aDocument.UpdateChartArea( aChartName, aNewRange, + bColHeaders, bRowHeaders, bAddRange ); + } + } + } + else + { + DBG_ERROR("UpdateChartArea: keine ViewShell oder falsche Daten"); + } + rReq.Done(); + } + else + { + DBG_ERROR("SID_CHART_SOURCE ohne Argumente"); + } + break; + + case FID_AUTO_CALC: + { + BOOL bNewVal; + const SfxPoolItem* pItem; + if ( pReqArgs && SFX_ITEM_SET == pReqArgs->GetItemState( nSlot, TRUE, &pItem ) ) + bNewVal = ((const SfxBoolItem*)pItem)->GetValue(); + else + bNewVal = !aDocument.GetAutoCalc(); // Toggle fuer Menue + aDocument.SetAutoCalc( bNewVal ); + SetDocumentModified(); + if (pBindings) + { + pBindings->Invalidate( FID_AUTO_CALC ); +// pBindings->Invalidate( FID_RECALC ); // jetzt immer enabled + } + rReq.AppendItem( SfxBoolItem( FID_AUTO_CALC, bNewVal ) ); + rReq.Done(); + } + break; + case FID_RECALC: + DoRecalc( rReq.IsAPI() ); + rReq.Done(); + break; + case FID_HARD_RECALC: + DoHardRecalc( rReq.IsAPI() ); + rReq.Done(); + break; + case SID_UPDATETABLINKS: + { + ScDocument* pDoc = GetDocument(); + + ScLkUpdMode nSet=pDoc->GetLinkMode(); + + USHORT nDlgRet=RET_NO; + if(nSet==LM_UNKNOWN) + { + ScAppOptions aAppOptions=SC_MOD()->GetAppOptions(); + nSet=aAppOptions.GetLinkMode(); + } + + if (nCanUpdate == com::sun::star::document::UpdateDocMode::NO_UPDATE) + nSet = LM_NEVER; + else if (nCanUpdate == com::sun::star::document::UpdateDocMode::QUIET_UPDATE && + nSet == LM_ON_DEMAND) + nSet = LM_NEVER; + else if (nCanUpdate == com::sun::star::document::UpdateDocMode::FULL_UPDATE) + nSet = LM_ALWAYS; + + if(nSet==LM_ON_DEMAND) + { + QueryBox aBox( GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES), + ScGlobal::GetRscString(STR_RELOAD_TABLES) ); + + nDlgRet=aBox.Execute(); + } + + if (nDlgRet == RET_YES || nSet==LM_ALWAYS) + { + ReloadTabLinks(); + aDocument.UpdateExternalRefLinks(); + aDocument.UpdateDdeLinks(); + aDocument.UpdateAreaLinks(); + + //! Test, ob Fehler + rReq.Done(); + } + else + rReq.Ignore(); + } + break; + + case SID_REIMPORT_AFTER_LOAD: + { + // wird nach dem Laden aufgerufen, wenn DB-Bereiche mit + // weggelassenen Daten enthalten sind + + BOOL bDone = FALSE; + ScDBCollection* pDBColl = aDocument.GetDBCollection(); + + if ((nCanUpdate != com::sun::star::document::UpdateDocMode::NO_UPDATE) && + (nCanUpdate != com::sun::star::document::UpdateDocMode::QUIET_UPDATE)) + { + ScRange aRange; + ScTabViewShell* pViewSh = GetBestViewShell(); + DBG_ASSERT(pViewSh,"SID_REIMPORT_AFTER_LOAD: keine View"); + if (pViewSh && pDBColl) + { + QueryBox aBox( GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES), + ScGlobal::GetRscString(STR_REIMPORT_AFTER_LOAD) ); + if (aBox.Execute() == RET_YES) + { + for (USHORT i=0; i<pDBColl->GetCount(); i++) + { + ScDBData* pDBData = (*pDBColl)[i]; + if ( pDBData->IsStripData() && + pDBData->HasImportParam() && !pDBData->HasImportSelection() ) + { + pDBData->GetArea(aRange); + pViewSh->MarkRange(aRange); + + // Import und interne Operationen wie SID_REFRESH_DBAREA + // (Abfrage auf Import hier nicht noetig) + + ScImportParam aImportParam; + pDBData->GetImportParam( aImportParam ); + BOOL bContinue = pViewSh->ImportData( aImportParam ); + pDBData->SetImportParam( aImportParam ); + + // markieren (Groesse kann sich geaendert haben) + pDBData->GetArea(aRange); + pViewSh->MarkRange(aRange); + + if ( bContinue ) // #41905# Fehler beim Import -> Abbruch + { + // interne Operationen, wenn welche gespeichert + + if ( pDBData->HasQueryParam() || pDBData->HasSortParam() || + pDBData->HasSubTotalParam() ) + pViewSh->RepeatDB(); + + // Pivottabellen die den Bereich als Quelldaten haben + + RefreshPivotTables(aRange); + } + } + } + bDone = TRUE; + } + } + } + + if ( !bDone && pDBColl ) + { + // wenn nicht, dann aber die abhaengigen Formeln updaten + //! auch fuer einzelne Bereiche, die nicht aktualisiert werden koennen + + aDocument.CalcAll(); //! nur die abhaengigen + PostDataChanged(); + } + + if (bDone) + rReq.Done(); + else + rReq.Ignore(); + } + break; + + + case SID_AUTO_STYLE: + DBG_ERROR("use ScAutoStyleHint instead of SID_AUTO_STYLE"); + break; + + case SID_GET_COLORTABLE: + { + // passende ColorTable ist per PutItem gesetzt worden + SvxColorTableItem* pColItem = (SvxColorTableItem*)GetItem(SID_COLOR_TABLE); + XColorTable* pTable = pColItem->GetColorTable(); + rReq.SetReturnValue(OfaPtrItem(SID_GET_COLORTABLE, pTable)); + } + break; + + case FID_CHG_RECORD: + { + ScDocument* pDoc = GetDocument(); + if(pDoc!=NULL) + { + // get argument (recorded macro) + SFX_REQUEST_ARG( rReq, pItem, SfxBoolItem, FID_CHG_RECORD, sal_False ); + BOOL bDo = TRUE; + + // xmlsec05/06: + // getting real parent window when called from Security-Options TP + Window* pParent = NULL; + const SfxPoolItem* pParentItem; + if( pReqArgs && SFX_ITEM_SET == pReqArgs->GetItemState( SID_ATTR_PARENTWINDOW, FALSE, &pParentItem ) ) + pParent = ( Window* ) ( ( const OfaPtrItem* ) pParentItem )->GetValue(); + + // desired state + ScChangeTrack* pChangeTrack = pDoc->GetChangeTrack(); + BOOL bActivateTracking = (pChangeTrack == 0); // toggle + if ( pItem ) + bActivateTracking = pItem->GetValue(); // from argument + + if ( !bActivateTracking ) + { + if ( !pItem ) + { + // no dialog on playing the macro + WarningBox aBox( pParent ? pParent : GetActiveDialogParent(), + WinBits(WB_YES_NO | WB_DEF_NO), + ScGlobal::GetRscString( STR_END_REDLINING ) ); + bDo = ( aBox.Execute() == RET_YES ); + } + + if ( bDo ) + { + if ( pChangeTrack->IsProtected() ) + bDo = ExecuteChangeProtectionDialog( NULL ); + if ( bDo ) + { + pDoc->EndChangeTracking(); + PostPaintGridAll(); + } + } + } + else + { + pDoc->StartChangeTracking(); + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges(TRUE); + pDoc->SetChangeViewSettings(aChangeViewSet); + } + + if ( bDo ) + { + // update "accept changes" dialog + //! notify all views + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if ( pViewFrm && pViewFrm->HasChildWindow(FID_CHG_ACCEPT) ) + { + SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_CHG_ACCEPT); + if (pChild) + { + ((ScAcceptChgDlgWrapper*)pChild)->ReInitDlg(); + } + } + + // Slots invalidieren + if (pBindings) + pBindings->InvalidateAll(FALSE); + if ( !pItem ) + rReq.AppendItem( SfxBoolItem( FID_CHG_RECORD, bActivateTracking ) ); + rReq.Done(); + } + else + rReq.Ignore(); + } + } + break; + + case SID_CHG_PROTECT : + { + Window* pParent = NULL; + const SfxPoolItem* pParentItem; + if( pReqArgs && SFX_ITEM_SET == pReqArgs->GetItemState( SID_ATTR_PARENTWINDOW, FALSE, &pParentItem ) ) + pParent = ( Window* ) ( ( const OfaPtrItem* ) pParentItem )->GetValue(); + if ( ExecuteChangeProtectionDialog( pParent ) ) + { + rReq.Done(); + SetDocumentModified(); + } + else + rReq.Ignore(); + } + break; + + case SID_DOCUMENT_MERGE: + case SID_DOCUMENT_COMPARE: + { + BOOL bDo = TRUE; + ScChangeTrack* pChangeTrack = aDocument.GetChangeTrack(); + if ( pChangeTrack && !pImpl->bIgnoreLostRedliningWarning ) + { + if ( nSlot == SID_DOCUMENT_COMPARE ) + { //! old changes trace will be lost + WarningBox aBox( GetActiveDialogParent(), + WinBits(WB_YES_NO | WB_DEF_NO), + ScGlobal::GetRscString( STR_END_REDLINING ) ); + if( aBox.Execute() == RET_YES ) + bDo = ExecuteChangeProtectionDialog( NULL, TRUE ); + else + bDo = FALSE; + } + else // merge might reject some actions + bDo = ExecuteChangeProtectionDialog( NULL, TRUE ); + } + if ( !bDo ) + { + rReq.Ignore(); + break; + } + SfxApplication* pApp = SFX_APP(); + const SfxPoolItem* pItem; + SfxMedium* pMed = NULL; + if ( pReqArgs && + pReqArgs->GetItemState( SID_FILE_NAME, TRUE, &pItem ) == SFX_ITEM_SET && + pItem->ISA(SfxStringItem) ) + { + String aFileName = ((const SfxStringItem*)pItem)->GetValue(); + + String aFilterName; + if ( pReqArgs->GetItemState( SID_FILTER_NAME, TRUE, &pItem ) == SFX_ITEM_SET && + pItem->ISA(SfxStringItem) ) + { + aFilterName = ((const SfxStringItem*)pItem)->GetValue(); + } + String aOptions; + if ( pReqArgs->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) == SFX_ITEM_SET && + pItem->ISA(SfxStringItem) ) + { + aOptions = ((const SfxStringItem*)pItem)->GetValue(); + } + short nVersion = 0; + if ( pReqArgs->GetItemState( SID_VERSION, TRUE, &pItem ) == SFX_ITEM_SET && + pItem->ISA(SfxInt16Item) ) + { + nVersion = ((const SfxInt16Item*)pItem)->GetValue(); + } + + // kein Filter angegeben -> Detection + if ( !aFilterName.Len() ) + ScDocumentLoader::GetFilterName( aFileName, aFilterName, aOptions, TRUE, FALSE ); + + // filter name from dialog contains application prefix, + // GetFilter needs name without the prefix. + ScDocumentLoader::RemoveAppPrefix( aFilterName ); + + const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( aFilterName ); + SfxItemSet* pSet = new SfxAllItemSet( pApp->GetPool() ); + if ( aOptions.Len() ) + pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) ); + if ( nVersion != 0 ) + pSet->Put( SfxInt16Item( SID_VERSION, nVersion ) ); + pMed = new SfxMedium( aFileName, STREAM_STD_READ, FALSE, pFilter, pSet ); + } + else + { + // start file dialog asynchronous + pImpl->bIgnoreLostRedliningWarning = true; + delete pImpl->pRequest; + pImpl->pRequest = new SfxRequest( rReq ); + delete pImpl->pDocInserter; + pImpl->pDocInserter = new ::sfx2::DocumentInserter( + 0, String::CreateFromAscii( ScDocShell::Factory().GetShortName() ), 0 ); + pImpl->pDocInserter->StartExecuteModal( LINK( this, ScDocShell, DialogClosedHdl ) ); + return ; + } + + if ( pMed ) // nun wirklich ausfuehren... + { + SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() ); + + ScDocShell* pOtherDocSh = new ScDocShell; + SfxObjectShellRef aDocShTablesRef = pOtherDocSh; + pOtherDocSh->DoLoad( pMed ); + ULONG nErr = pOtherDocSh->GetErrorCode(); + if (nErr) + ErrorHandler::HandleError( nErr ); // auch Warnings + + if ( !pOtherDocSh->GetError() ) // nur Errors + { + BOOL bHadTrack = ( aDocument.GetChangeTrack() != NULL ); + ULONG nStart = 0; + if ( nSlot == SID_DOCUMENT_MERGE && pChangeTrack ) + { + nStart = pChangeTrack->GetActionMax() + 1; + } + + if ( nSlot == SID_DOCUMENT_COMPARE ) + CompareDocument( *pOtherDocSh->GetDocument() ); + else + MergeDocument( *pOtherDocSh->GetDocument() ); + + // show "accept changes" dialog + //! get view for this document! + if ( !IsDocShared() ) + { + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if ( pViewFrm ) + { + pViewFrm->ShowChildWindow( ScAcceptChgDlgWrapper::GetChildWindowId(), TRUE ); //@51669 + } + if ( pBindings ) + { + pBindings->Invalidate( FID_CHG_ACCEPT ); + } + } + + rReq.SetReturnValue( SfxInt32Item( nSlot, 0 ) ); //! ??????? + rReq.Done(); + + if (!bHadTrack) // neu eingeschaltet -> auch anzeigen + { + ScChangeViewSettings* pOldSet = aDocument.GetChangeViewSettings(); + if ( !pOldSet || !pOldSet->ShowChanges() ) + { + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges(TRUE); + aDocument.SetChangeViewSettings(aChangeViewSet); + } + } + else if ( nSlot == SID_DOCUMENT_MERGE && IsDocShared() && pChangeTrack ) + { + ULONG nEnd = pChangeTrack->GetActionMax(); + if ( nEnd >= nStart ) + { + // only show changes from merged document + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges( TRUE ); + aChangeViewSet.SetShowAccepted( TRUE ); + aChangeViewSet.SetHasActionRange( true ); + aChangeViewSet.SetTheActionRange( nStart, nEnd ); + aDocument.SetChangeViewSettings( aChangeViewSet ); + + // update view + PostPaintExtras(); + PostPaintGridAll(); + } + } + } + pOtherDocSh->DoClose(); // delete passiert mit der Ref + } + } + break; + + case SID_DELETE_SCENARIO: + if (pReqArgs) + { + const SfxPoolItem* pItem; + if ( pReqArgs->GetItemState( nSlot, TRUE, &pItem ) == SFX_ITEM_SET ) + { + if ( pItem->ISA(SfxStringItem) ) + { + String aName = ((const SfxStringItem*)pItem)->GetValue(); + SCTAB nTab; + if (aDocument.GetTable( aName, nTab )) + { + // DeleteTable von viewfunc nach docfunc verschieben! + + ScTabViewShell* pSh = GetBestViewShell(); + if ( pSh ) + { + //! SetTabNo in DeleteTable weglassen? + SCTAB nDispTab = pSh->GetViewData()->GetTabNo(); + pSh->DeleteTable( nTab ); + pSh->SetTabNo(nDispTab); + rReq.Done(); + } + } + } + } + } + break; + + case SID_EDIT_SCENARIO: + { + const SfxPoolItem* pItem; + if ( pReqArgs->GetItemState( nSlot, TRUE, &pItem ) == SFX_ITEM_SET ) + { + if ( pItem->ISA(SfxStringItem) ) + { + String aName = ((const SfxStringItem*)pItem)->GetValue(); + SCTAB nTab; + if (aDocument.GetTable( aName, nTab )) + { + if (aDocument.IsScenario(nTab)) + { + String aComment; + Color aColor; + USHORT nFlags; + aDocument.GetScenarioData( nTab, aComment, aColor, nFlags ); + + // Determine if the Sheet that the Scenario was created on + // is protected. But first we need to find that Sheet. + // Rewind back to the actual sheet. + SCTAB nActualTab = nTab; + do + { + nActualTab--; + } + while(aDocument.IsScenario(nActualTab)); + BOOL bSheetProtected = aDocument.IsTabProtected(nActualTab); + + //! anderen Titel am Dialog setzen +//CHINA001 ScNewScenarioDlg* pNewDlg = +//CHINA001 new ScNewScenarioDlg( GetActiveDialogParent(), aName, TRUE, bSheetProtected); + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + + AbstractScNewScenarioDlg* pNewDlg = pFact->CreateScNewScenarioDlg( GetActiveDialogParent(), aName, RID_SCDLG_NEWSCENARIO, TRUE,bSheetProtected); + DBG_ASSERT(pNewDlg, "Dialog create fail!");//CHINA001 + pNewDlg->SetScenarioData( aName, aComment, aColor, nFlags ); + if ( pNewDlg->Execute() == RET_OK ) + { + pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags ); + ModifyScenario( nTab, aName, aComment, aColor, nFlags ); + rReq.Done(); + } + delete pNewDlg; + } + } + } + } + } + break; + + case SID_ATTR_YEAR2000 : + { + const SfxPoolItem* pItem; + if ( pReqArgs->GetItemState( nSlot, TRUE, &pItem ) == SFX_ITEM_SET ) + { + if ( pItem->ISA(SfxUInt16Item) ) + { + UINT16 nY2k = ((SfxUInt16Item*)pItem)->GetValue(); + // immer an den DocOptions setzen, damit das auch fuer SO50 + // gespeichert wird (und alle Abfragen bisher auch darauf laufen). + // SetDocOptions propagiert das an den NumberFormatter + ScDocOptions aDocOpt( aDocument.GetDocOptions() ); + aDocOpt.SetYear2000( nY2k ); + aDocument.SetDocOptions( aDocOpt ); + // die FormShell soll es mitbekommen + ScTabViewShell* pSh = GetBestViewShell(); + if ( pSh ) + { + FmFormShell* pFSh = pSh->GetFormShell(); + if ( pFSh ) + pFSh->SetY2KState( nY2k ); + } + } + } + } + break; + + case SID_SHARE_DOC: + { + ScViewData* pViewData = GetViewData(); + if ( !pViewData ) + { + rReq.Ignore(); + break; + } + + ScShareDocumentDlg aDlg( GetActiveDialogParent(), pViewData ); + if ( aDlg.Execute() == RET_OK ) + { + bool bSetShared = aDlg.IsShareDocumentChecked(); + if ( bSetShared != static_cast< bool >( IsDocShared() ) ) + { + if ( bSetShared ) + { + bool bContinue = true; + if ( HasName() ) + { + QueryBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO | WB_DEF_YES ), + ScGlobal::GetRscString( STR_DOC_WILLBESAVED ) ); + if ( aBox.Execute() == RET_NO ) + { + bContinue = false; + } + } + if ( bContinue ) + { + EnableSharedSettings( true ); + + SC_MOD()->SetInSharedDocSaving( true ); + if ( !SwitchToShared( sal_True, sal_True ) ) + { + // TODO/LATER: what should be done in case the switch has failed? + // for example in case the user has cancelled the saveAs operation + } + + SC_MOD()->SetInSharedDocSaving( false ); + + InvalidateName(); + GetUndoManager()->Clear(); + + ScTabView* pTabView = dynamic_cast< ScTabView* >( pViewData->GetView() ); + if ( pTabView ) + { + pTabView->UpdateLayerLocks(); + } + } + } + else + { + uno::Reference< frame::XModel > xModel; + try + { + // load shared file + xModel.set( LoadSharedDocument(), uno::UNO_QUERY_THROW ); + uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW ); + + // check if shared flag is set in shared file + bool bShared = false; + ScModelObj* pDocObj = ScModelObj::getImplementation( xModel ); + if ( pDocObj ) + { + ScDocShell* pDocShell = dynamic_cast< ScDocShell* >( pDocObj->GetEmbeddedObject() ); + if ( pDocShell ) + { + bShared = pDocShell->HasSharedXMLFlagSet(); + } + } + + // #i87870# check if shared status was disabled and enabled again + bool bOwnEntry = false; + try + { + ::svt::ShareControlFile aControlFile( GetSharedFileURL() ); + bOwnEntry = aControlFile.HasOwnEntry(); + } + catch ( uno::Exception& ) + { + } + + if ( bShared && bOwnEntry ) + { + uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW ); + if ( xStorable->isReadonly() ) + { + xCloseable->close( sal_True ); + + String aUserName( ScGlobal::GetRscString( STR_UNKNOWN_USER ) ); + try + { + ::svt::DocumentLockFile aLockFile( GetSharedFileURL() ); + uno::Sequence< ::rtl::OUString > aData = aLockFile.GetLockData(); + if ( aData.getLength() > LOCKFILE_SYSUSERNAME_ID ) + { + if ( aData[LOCKFILE_OOOUSERNAME_ID].getLength() > 0 ) + { + aUserName = aData[LOCKFILE_OOOUSERNAME_ID]; + } + else if ( aData[LOCKFILE_SYSUSERNAME_ID].getLength() > 0 ) + { + aUserName = aData[LOCKFILE_SYSUSERNAME_ID]; + } + } + } + catch ( uno::Exception& ) + { + } + String aMessage( ScGlobal::GetRscString( STR_FILE_LOCKED_TRY_LATER ) ); + aMessage.SearchAndReplaceAscii( "%1", aUserName ); + + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_OK ), aMessage ); + aBox.Execute(); + } + else + { + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_YES_NO | WB_DEF_YES ), + ScGlobal::GetRscString( STR_DOC_DISABLESHARED ) ); + if ( aBox.Execute() == RET_YES ) + { + xCloseable->close( sal_True ); + + if ( !SwitchToShared( sal_False, sal_True ) ) + { + // TODO/LATER: what should be done in case the switch has failed? + // for example in case the user has cancelled the saveAs operation + } + + EnableSharedSettings( false ); + + if ( pBindings ) + { + pBindings->ExecuteSynchron( SID_SAVEDOC ); + } + + ScTabView* pTabView = dynamic_cast< ScTabView* >( pViewData->GetView() ); + if ( pTabView ) + { + pTabView->UpdateLayerLocks(); + } + } + else + { + xCloseable->close( sal_True ); + } + } + } + else + { + xCloseable->close( sal_True ); + WarningBox aBox( GetActiveDialogParent(), WinBits( WB_OK ), + ScGlobal::GetRscString( STR_DOC_NOLONGERSHARED ) ); + aBox.Execute(); + } + } + catch ( uno::Exception& ) + { + DBG_ERROR( "SID_SHARE_DOC: caught exception\n" ); + SC_MOD()->SetInSharedDocSaving( false ); + + try + { + uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW ); + xClose->close( sal_True ); + } + catch ( uno::Exception& ) + { + } + } + } + } + } + rReq.Done(); + } + break; + + default: + { + // kleiner (?) Hack -> forward der Slots an TabViewShell + ScTabViewShell* pSh = GetBestViewShell(); + if ( pSh ) + pSh->Execute( rReq ); + else + SbxBase::SetError( SbxERR_NO_ACTIVE_OBJECT ); + } + } +} + + +//------------------------------------------------------------------ + +BOOL ScDocShell::ExecuteChangeProtectionDialog( Window* _pParent, BOOL bJustQueryIfProtected ) +{ + BOOL bDone = FALSE; + ScChangeTrack* pChangeTrack = aDocument.GetChangeTrack(); + if ( pChangeTrack ) + { + BOOL bProtected = pChangeTrack->IsProtected(); + if ( bJustQueryIfProtected && !bProtected ) + return TRUE; + + String aTitle( ScResId( bProtected ? SCSTR_CHG_UNPROTECT : SCSTR_CHG_PROTECT ) ); + String aText( ScResId( SCSTR_PASSWORD ) ); + String aPassword; + + SfxPasswordDialog* pDlg = new SfxPasswordDialog( + _pParent ? _pParent : GetActiveDialogParent(), &aText ); + pDlg->SetText( aTitle ); + pDlg->SetMinLen( 1 ); + pDlg->SetHelpId( SID_CHG_PROTECT ); + pDlg->SetEditHelpId( HID_CHG_PROTECT ); + if ( !bProtected ) + pDlg->ShowExtras( SHOWEXTRAS_CONFIRM ); + if ( pDlg->Execute() == RET_OK ) + aPassword = pDlg->GetPassword(); + delete pDlg; + + if ( aPassword.Len() ) + { + if ( bProtected ) + { + if ( SvPasswordHelper::CompareHashPassword(pChangeTrack->GetProtection(), aPassword) ) + { + if ( bJustQueryIfProtected ) + bDone = TRUE; + else + pChangeTrack->SetProtection( + com::sun::star::uno::Sequence< sal_Int8 > (0) ); + } + else + { + InfoBox aBox( GetActiveDialogParent(), + String( ScResId( SCSTR_WRONGPASSWORD ) ) ); + aBox.Execute(); + } + } + else + { + com::sun::star::uno::Sequence< sal_Int8 > aPass; + SvPasswordHelper::GetHashPassword( aPass, aPassword ); + pChangeTrack->SetProtection( aPass ); + } + if ( bProtected != pChangeTrack->IsProtected() ) + { + // update "accept changes" dialog + //! notify all views + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if ( pViewFrm && pViewFrm->HasChildWindow( FID_CHG_ACCEPT ) ) + { + SfxChildWindow* pChild = pViewFrm->GetChildWindow( FID_CHG_ACCEPT ); + if ( pChild ) + ((ScAcceptChgDlgWrapper*)pChild)->ReInitDlg(); + } + bDone = TRUE; + } + } + } + else if ( bJustQueryIfProtected ) + bDone = TRUE; + return bDone; +} + + +//------------------------------------------------------------------ + +void ScDocShell::DoRecalc( BOOL bApi ) +{ + BOOL bDone = FALSE; + ScTabViewShell* pSh = GetBestViewShell(); + if ( pSh ) + { + ScInputHandler* pHdl = SC_MOD()->GetInputHdl(pSh); + if ( pHdl && pHdl->IsInputMode() && pHdl->IsFormulaMode() && !bApi ) + { + pHdl->FormulaPreview(); // Teilergebnis als QuickHelp + bDone = TRUE; + } + else + { + pSh->UpdateInputLine(); // InputEnterHandler + pSh->UpdateInputHandler(); + } + } + if (!bDone) // sonst Dokument neu berechnen + { + WaitObject aWaitObj( GetActiveDialogParent() ); + aDocument.CalcFormulaTree(); + if ( pSh ) + pSh->UpdateCharts(TRUE); + + aDocument.BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + + // #47939# Wenn es Charts gibt, dann alles painten, damit nicht + // PostDataChanged und die Charts nacheinander kommen und Teile + // doppelt gepainted werden. + + ScChartListenerCollection* pCharts = aDocument.GetChartListenerCollection(); + if ( pCharts && pCharts->GetCount() ) + PostPaintGridAll(); + else + PostDataChanged(); + } +} + +void ScDocShell::DoHardRecalc( BOOL /* bApi */ ) +{ + WaitObject aWaitObj( GetActiveDialogParent() ); + ScTabViewShell* pSh = GetBestViewShell(); + if ( pSh ) + { + pSh->UpdateInputLine(); // InputEnterHandler + pSh->UpdateInputHandler(); + } + aDocument.CalcAll(); + GetDocFunc().DetectiveRefresh(); // erzeugt eigenes Undo + if ( pSh ) + pSh->UpdateCharts(TRUE); + + // CalcAll doesn't broadcast value changes, so SC_HINT_CALCALL is broadcasted globally + // in addition to SFX_HINT_DATACHANGED. + aDocument.BroadcastUno( SfxSimpleHint( SC_HINT_CALCALL ) ); + aDocument.BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); + + // use hard recalc also to disable stream-copying of all sheets + // (somewhat consistent with charts) + SCTAB nTabCount = aDocument.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (aDocument.IsStreamValid(nTab)) + aDocument.SetStreamValid(nTab, FALSE); + + PostPaintGridAll(); +} + +//------------------------------------------------------------------ + +void ScDocShell::DoAutoStyle( const ScRange& rRange, const String& rStyle ) +{ + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + ScStyleSheet* pStyleSheet = + pStylePool->FindCaseIns( rStyle, SFX_STYLE_FAMILY_PARA ); + if (!pStyleSheet) + pStyleSheet = (ScStyleSheet*) + pStylePool->Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD), SFX_STYLE_FAMILY_PARA ); + if (pStyleSheet) + { + DBG_ASSERT(rRange.aStart.Tab() == rRange.aEnd.Tab(), + "DoAutoStyle mit mehreren Tabellen"); + SCTAB nTab = rRange.aStart.Tab(); + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + aDocument.ApplyStyleAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, *pStyleSheet ); + aDocument.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab ); + PostPaint( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, PAINT_GRID ); + } +} + +//------------------------------------------------------------------ + +void ScDocShell::NotifyStyle( const SfxStyleSheetHint& rHint ) +{ + USHORT nId = rHint.GetHint(); + const SfxStyleSheetBase* pStyle = rHint.GetStyleSheet(); + if (!pStyle) + return; + + if ( pStyle->GetFamily() == SFX_STYLE_FAMILY_PAGE ) + { + if ( nId == SFX_STYLESHEET_MODIFIED ) + { + ScDocShellModificator aModificator( *this ); + + String aNewName = pStyle->GetName(); + String aOldName = aNewName; + BOOL bExtended = rHint.ISA(SfxStyleSheetHintExtended); // Name geaendert? + if (bExtended) + aOldName = ((SfxStyleSheetHintExtended&)rHint).GetOldName(); + + if ( aNewName != aOldName ) + aDocument.RenamePageStyleInUse( aOldName, aNewName ); + + SCTAB nTabCount = aDocument.GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (aDocument.GetPageStyle(nTab) == aNewName) // schon auf neu angepasst + { + aDocument.PageStyleModified( nTab, aNewName ); + ScPrintFunc aPrintFunc( this, GetPrinter(), nTab ); + aPrintFunc.UpdatePages(); + } + + aModificator.SetDocumentModified(); + + if (bExtended) + { + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( SID_STATUS_PAGESTYLE ); + pBindings->Invalidate( SID_STYLE_FAMILY4 ); + pBindings->Invalidate( FID_RESET_PRINTZOOM ); + pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT ); + pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT ); + } + } + } + } + else if ( pStyle->GetFamily() == SFX_STYLE_FAMILY_PARA ) + { + if ( nId == SFX_STYLESHEET_MODIFIED) + { + String aNewName = pStyle->GetName(); + String aOldName = aNewName; + BOOL bExtended = rHint.ISA(SfxStyleSheetHintExtended); + if (bExtended) + aOldName = ((SfxStyleSheetHintExtended&)rHint).GetOldName(); + if ( aNewName != aOldName ) + { + ScConditionalFormatList* pList = aDocument.GetCondFormList(); + if (pList) + pList->RenameCellStyle( aOldName,aNewName ); + } + } + } + + // alles andere geht ueber Slots... +} + +// wie in printfun.cxx +#define ZOOM_MIN 10 + +void ScDocShell::SetPrintZoom( SCTAB nTab, USHORT nScale, USHORT nPages ) +{ + BOOL bUndo(aDocument.IsUndoEnabled()); + String aStyleName = aDocument.GetPageStyle( nTab ); + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SFX_STYLE_FAMILY_PAGE ); + DBG_ASSERT( pStyleSheet, "PageStyle not found" ); + if ( pStyleSheet ) + { + ScDocShellModificator aModificator( *this ); + + SfxItemSet& rSet = pStyleSheet->GetItemSet(); + if (bUndo) + { + USHORT nOldScale = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_SCALE)).GetValue(); + USHORT nOldPages = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_SCALETOPAGES)).GetValue(); + GetUndoManager()->AddUndoAction( new ScUndoPrintZoom( + this, nTab, nOldScale, nOldPages, nScale, nPages ) ); + } + + rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) ); + rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) ); + + ScPrintFunc aPrintFunc( this, GetPrinter(), nTab ); + aPrintFunc.UpdatePages(); + aModificator.SetDocumentModified(); + + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + pBindings->Invalidate( FID_RESET_PRINTZOOM ); + } +} + +BOOL ScDocShell::AdjustPrintZoom( const ScRange& rRange ) +{ + BOOL bChange = FALSE; + SCTAB nTab = rRange.aStart.Tab(); + + String aStyleName = aDocument.GetPageStyle( nTab ); + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SFX_STYLE_FAMILY_PAGE ); + DBG_ASSERT( pStyleSheet, "PageStyle not found" ); + if ( pStyleSheet ) + { + SfxItemSet& rSet = pStyleSheet->GetItemSet(); + BOOL bHeaders = ((const SfxBoolItem&)rSet.Get(ATTR_PAGE_HEADERS)).GetValue(); + USHORT nOldScale = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_SCALE)).GetValue(); + USHORT nOldPages = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_SCALETOPAGES)).GetValue(); + const ScRange* pRepeatCol = aDocument.GetRepeatColRange( nTab ); + const ScRange* pRepeatRow = aDocument.GetRepeatRowRange( nTab ); + + // benoetigte Skalierung fuer Selektion ausrechnen + + USHORT nNewScale = nOldScale; + + long nBlkTwipsX = 0; + if (bHeaders) + nBlkTwipsX += (long) PRINT_HEADER_WIDTH; + SCCOL nStartCol = rRange.aStart.Col(); + SCCOL nEndCol = rRange.aEnd.Col(); + if ( pRepeatCol && nStartCol >= pRepeatCol->aStart.Col() ) + { + for (SCCOL i=pRepeatCol->aStart.Col(); i<=pRepeatCol->aEnd.Col(); i++ ) + nBlkTwipsX += aDocument.GetColWidth( i, nTab ); + if ( nStartCol <= pRepeatCol->aEnd.Col() ) + nStartCol = pRepeatCol->aEnd.Col() + 1; + } + // legacy compilers' own scope for i + { + for ( SCCOL i=nStartCol; i<=nEndCol; i++ ) + nBlkTwipsX += aDocument.GetColWidth( i, nTab ); + } + + long nBlkTwipsY = 0; + if (bHeaders) + nBlkTwipsY += (long) PRINT_HEADER_HEIGHT; + SCROW nStartRow = rRange.aStart.Row(); + SCROW nEndRow = rRange.aEnd.Row(); + if ( pRepeatRow && nStartRow >= pRepeatRow->aStart.Row() ) + { + nBlkTwipsY += aDocument.FastGetRowHeight( pRepeatRow->aStart.Row(), + pRepeatRow->aEnd.Row(), nTab ); + if ( nStartRow <= pRepeatRow->aEnd.Row() ) + nStartRow = pRepeatRow->aEnd.Row() + 1; + } + nBlkTwipsY += aDocument.FastGetRowHeight( nStartRow, nEndRow, nTab ); + + Size aPhysPage; + long nHdr, nFtr; + ScPrintFunc aOldPrFunc( this, GetPrinter(), nTab ); + aOldPrFunc.GetScaleData( aPhysPage, nHdr, nFtr ); + nBlkTwipsY += nHdr + nFtr; + + if ( nBlkTwipsX == 0 ) // #100639# hidden columns/rows may lead to 0 + nBlkTwipsX = 1; + if ( nBlkTwipsY == 0 ) + nBlkTwipsY = 1; + + long nNeeded = Min( aPhysPage.Width() * 100 / nBlkTwipsX, + aPhysPage.Height() * 100 / nBlkTwipsY ); + if ( nNeeded < ZOOM_MIN ) + nNeeded = ZOOM_MIN; // Begrenzung + if ( nNeeded < (long) nNewScale ) + nNewScale = (USHORT) nNeeded; + + bChange = ( nNewScale != nOldScale || nOldPages != 0 ); + if ( bChange ) + SetPrintZoom( nTab, nNewScale, 0 ); + } + return bChange; +} + +void ScDocShell::PageStyleModified( const String& rStyleName, BOOL bApi ) +{ + ScDocShellModificator aModificator( *this ); + + BOOL bWarn = FALSE; + + SCTAB nTabCount = aDocument.GetTableCount(); + SCTAB nUseTab = MAXTAB+1; + for (SCTAB nTab=0; nTab<nTabCount && nUseTab>MAXTAB; nTab++) + if ( aDocument.GetPageStyle(nTab) == rStyleName && + ( !bApi || aDocument.GetPageSize(nTab).Width() ) ) + nUseTab = nTab; + // bei bApi nur, wenn Umbrueche schon angezeigt + + if (ValidTab(nUseTab)) // nicht verwendet -> nichts zu tun + { + ScPrintFunc aPrintFunc( this, GetPrinter(), nUseTab ); //! ohne CountPages auskommen + if (!aPrintFunc.UpdatePages()) // setzt Umbrueche auf allen Tabs + bWarn = TRUE; + + if (bWarn && !bApi) + { + ScWaitCursorOff aWaitOff( GetActiveDialogParent() ); + InfoBox aInfoBox(GetActiveDialogParent(), + ScGlobal::GetRscString(STR_PRINT_INVALID_AREA)); + aInfoBox.Execute(); + } + } + + aModificator.SetDocumentModified(); + + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( FID_RESET_PRINTZOOM ); + pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT ); + pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT ); + } +} + +void ScDocShell::ExecutePageStyle( SfxViewShell& rCaller, + SfxRequest& rReq, + SCTAB nCurTab ) +{ + const SfxItemSet* pReqArgs = rReq.GetArgs(); + + switch ( rReq.GetSlot() ) + { + case SID_STATUS_PAGESTYLE: // Click auf StatusBar-Control + case SID_FORMATPAGE: + { + if ( pReqArgs != NULL ) + { + } + else if ( pReqArgs == NULL ) + { + BOOL bUndo(aDocument.IsUndoEnabled()); + String aOldName = aDocument.GetPageStyle( nCurTab ); + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet + = pStylePool->Find( aOldName, SFX_STYLE_FAMILY_PAGE ); + + DBG_ASSERT( pStyleSheet, "PageStyle not found! :-/" ); + + if ( pStyleSheet ) + { + ScStyleSaveData aOldData; + if (bUndo) + aOldData.InitFromStyle( pStyleSheet ); + + SfxItemSet& rStyleSet = pStyleSheet->GetItemSet(); + +//CHINA001 ScStyleDlg* pDlg = new ScStyleDlg( GetActiveDialogParent(), +//CHINA001 *pStyleSheet, +//CHINA001 RID_SCDLG_STYLES_PAGE ); +//CHINA001 + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + + SfxAbstractTabDialog* pDlg = pFact->CreateScStyleDlg( GetActiveDialogParent(), *pStyleSheet, RID_SCDLG_STYLES_PAGE, RID_SCDLG_STYLES_PAGE ); + DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 + + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutSet = pDlg->GetOutputItemSet(); + + WaitObject aWait( GetActiveDialogParent() ); + + String aNewName = pStyleSheet->GetName(); + if ( aNewName != aOldName && + aDocument.RenamePageStyleInUse( aOldName, aNewName ) ) + { + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + { + pBindings->Invalidate( SID_STATUS_PAGESTYLE ); + pBindings->Invalidate( FID_RESET_PRINTZOOM ); + } + } + + if ( pOutSet ) + aDocument.ModifyStyleSheet( *pStyleSheet, *pOutSet ); + + // merken fuer GetState(): + GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, bHeaderOn, bFooterOn ); + rCaller.GetViewFrame()->GetBindings().Invalidate( SID_HFEDIT ); + + ScStyleSaveData aNewData; + aNewData.InitFromStyle( pStyleSheet ); + if (bUndo) + { + GetUndoManager()->AddUndoAction( + new ScUndoModifyStyle( this, SFX_STYLE_FAMILY_PAGE, + aOldData, aNewData ) ); + } + + PageStyleModified( aNewName, FALSE ); + rReq.Done(); + } + delete pDlg; + + rStyleSet.ClearItem( ATTR_PAGE_PAPERTRAY ); + } + } + } + break; + + case SID_HFEDIT: + { + if ( pReqArgs != NULL ) + { + } + else if ( pReqArgs == NULL ) + { + String aStr( aDocument.GetPageStyle( nCurTab ) ); + + ScStyleSheetPool* pStylePool + = aDocument.GetStyleSheetPool(); + + SfxStyleSheetBase* pStyleSheet + = pStylePool->Find( aStr, SFX_STYLE_FAMILY_PAGE ); + + DBG_ASSERT( pStyleSheet, "PageStyle not found! :-/" ); + + if ( pStyleSheet ) + { + SfxItemSet& rStyleSet = pStyleSheet->GetItemSet(); + + SvxPageUsage eUsage = + SvxPageUsage( ((const SvxPageItem&) + rStyleSet.Get( ATTR_PAGE )). + GetPageUsage() ); + BOOL bShareHeader = IS_SHARE_HEADER(rStyleSet); + BOOL bShareFooter = IS_SHARE_FOOTER(rStyleSet); + USHORT nResId = 0; + + switch ( eUsage ) + { + case SVX_PAGE_LEFT: + case SVX_PAGE_RIGHT: + { + if ( bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT; + else if ( SVX_PAGE_RIGHT == eUsage ) + { + if ( !bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTHEADER; + } + else + { + // #69193a# respect "shared" setting + if ( !bHeaderOn && bFooterOn ) + nResId = bShareFooter ? + RID_SCDLG_HFEDIT_RIGHTFOOTER : + RID_SCDLG_HFEDIT_LEFTFOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = bShareHeader ? + RID_SCDLG_HFEDIT_RIGHTHEADER : + RID_SCDLG_HFEDIT_LEFTHEADER; + } + } + break; + + case SVX_PAGE_MIRROR: + case SVX_PAGE_ALL: + default: + { + if ( !bShareHeader && !bShareFooter ) + { + if ( bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_ALL; + else if ( !bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_FOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = RID_SCDLG_HFEDIT_HEADER; + } + else if ( bShareHeader && bShareFooter ) + { + if ( bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT; + else + { + if ( !bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTHEADER; + } + } + else if ( !bShareHeader && bShareFooter ) + { + if ( bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_SFTR; + else if ( !bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = RID_SCDLG_HFEDIT_HEADER; + } + else if ( bShareHeader && !bShareFooter ) + { + if ( bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_SHDR; + else if ( !bHeaderOn && bFooterOn ) + nResId = RID_SCDLG_HFEDIT_FOOTER; + else if ( bHeaderOn && !bFooterOn ) + nResId = RID_SCDLG_HFEDIT_RIGHTHEADER; + } + } + } + +//CHINA001 ScHFEditDlg* pDlg +//CHINA001 = new ScHFEditDlg( SFX_APP()->GetViewFrame(), +//CHINA001 GetActiveDialogParent(), +//CHINA001 rStyleSet, +//CHINA001 aStr, +//CHINA001 nResId ); +//CHINA001 + ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 + + SfxAbstractTabDialog* pDlg = pFact->CreateScHFEditDlg( SfxViewFrame::Current(), + GetActiveDialogParent(), + rStyleSet, + aStr, + RID_SCDLG_HFEDIT, nResId); + DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 + if ( pDlg->Execute() == RET_OK ) + { + const SfxItemSet* pOutSet = pDlg->GetOutputItemSet(); + + if ( pOutSet ) + aDocument.ModifyStyleSheet( *pStyleSheet, *pOutSet ); + + SetDocumentModified(); + rReq.Done(); + } + delete pDlg; + } + } + } + break; + + default: + break; + } +} + +void ScDocShell::GetStatePageStyle( SfxViewShell& /* rCaller */, + SfxItemSet& rSet, + SCTAB nCurTab ) +{ + SfxWhichIter aIter(rSet); + USHORT nWhich = aIter.FirstWhich(); + while ( nWhich ) + { + switch (nWhich) + { + case SID_STATUS_PAGESTYLE: + rSet.Put( SfxStringItem( nWhich, aDocument.GetPageStyle( nCurTab ) ) ); + break; + + case SID_HFEDIT: + { + String aStr = aDocument.GetPageStyle( nCurTab ); + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStr, SFX_STYLE_FAMILY_PAGE ); + + DBG_ASSERT( pStyleSheet, "PageStyle not found! :-/" ); + + if ( pStyleSheet ) + { + SfxItemSet& rStyleSet = pStyleSheet->GetItemSet(); + + GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, bHeaderOn, bFooterOn ); + + if ( !bHeaderOn && !bFooterOn ) + rSet.DisableItem( nWhich ); + } + } + break; + } + + nWhich = aIter.NextWhich(); + } +} + +void lcl_GetPrintData( ScDocShell* pDocShell /*in*/, + ScDocument* pDocument /*in*/, SfxPrinter* pPrinter /*in*/, + PrintDialog* pPrintDialog /*in*/, bool bForceSelected /*in*/, + ScMarkData* pMarkData /*inout*/, bool& rbHasOptions /*out*/, + ScPrintOptions& rOptions /*out*/, bool& rbAllTabs /*out*/, + long& rnTotalPages /*out*/, long aPageArr[] /*out*/, + MultiSelection& rPageRanges /*out*/, ScRange** ppMarkedRange /*out*/ ) +{ + // get settings from print options sub-dialog + const SfxItemSet& rOptionSet = pPrinter->GetOptions(); + const SfxPoolItem* pItem; + rbHasOptions = ( rOptionSet.GetItemState( SID_SCPRINTOPTIONS, FALSE, &pItem ) == SFX_ITEM_SET ); + if ( rbHasOptions ) + { + rOptions = ((const ScTpPrintItem*)pItem)->GetPrintOptions(); + } + else + { + // use configuration + rOptions = SC_MOD()->GetPrintOptions(); + } + + // update all pending row heights with a single progress bar, + // instead of a separate progress for each sheet from ScPrintFunc + pDocShell->UpdatePendingRowHeights( MAXTAB, true ); + + // get number of total pages + rnTotalPages = 0; + SCTAB nTabCount = pDocument->GetTableCount(); + for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab ) + { + ScPrintFunc aPrintFunc( pDocShell, pPrinter, nTab, 0, 0, NULL, &rOptions ); + long nThisTab = aPrintFunc.GetTotalPages(); + aPageArr[nTab] = nThisTab; + rnTotalPages += nThisTab; + } + + rPageRanges.SetTotalRange( Range( 0, RANGE_MAX ) ); + rPageRanges.Select( Range( 1, rnTotalPages ) ); + + rbAllTabs = ( pPrintDialog ? ( pPrintDialog->GetCheckedSheetRange() == PRINTSHEETS_ALL ) : SC_MOD()->GetPrintOptions().GetAllSheets() ); + if ( bForceSelected ) + { + rbAllTabs = false; + } + + if ( ( pPrintDialog && pPrintDialog->GetCheckedSheetRange() == PRINTSHEETS_SELECTED_CELLS ) || bForceSelected ) + { + if ( pMarkData && ( pMarkData->IsMarked() || pMarkData->IsMultiMarked() ) ) + { + pMarkData->MarkToMulti(); + *ppMarkedRange = new ScRange; + pMarkData->GetMultiMarkArea( **ppMarkedRange ); + pMarkData->MarkToSimple(); + } + } + + PrintDialogRange eDlgOption = pPrintDialog ? pPrintDialog->GetCheckedRange() : PRINTDIALOG_ALL; + if ( eDlgOption == PRINTDIALOG_RANGE ) + { + rPageRanges = MultiSelection( pPrintDialog->GetRangeText() ); + } + + // get number of total pages if selection + if ( !rbAllTabs ) + { + rnTotalPages = 0; + for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab ) + { + if ( *ppMarkedRange ) // selected range is used instead of print ranges -> page count is different + { + ScPrintFunc aPrintFunc( pDocShell, pPrinter, nTab, 0, 0, *ppMarkedRange, &rOptions ); + aPageArr[nTab] = aPrintFunc.GetTotalPages(); + } + if ( !pMarkData || pMarkData->GetTableSelect( nTab ) ) + { + rnTotalPages += aPageArr[nTab]; + } + } + if ( eDlgOption == PRINTDIALOG_ALL || bForceSelected ) + { + rPageRanges.Select( Range( 1, rnTotalPages ) ); + } + } +} + +bool ScDocShell::CheckPrint( PrintDialog* pPrintDialog, ScMarkData* pMarkData, bool bForceSelected, bool bIsAPI ) +{ + SfxPrinter* pPrinter = GetPrinter(); + if ( !pPrinter ) + { + return false; + } + + bool bHasOptions = false; + ScPrintOptions aOptions; + bool bAllTabs = true; + long nTotalPages = 0; + long aPageArr[MAXTABCOUNT]; // pages per sheet + MultiSelection aPageRanges; // pages to print + ScRange* pMarkedRange = NULL; + + lcl_GetPrintData( this, &aDocument, pPrinter, pPrintDialog, bForceSelected, + pMarkData, bHasOptions, aOptions, bAllTabs, nTotalPages, + aPageArr, aPageRanges, &pMarkedRange ); + + delete pMarkedRange; + + if ( nTotalPages == 0 ) + { + if ( !bIsAPI ) + { + WarningBox aWarningBox( GetActiveDialogParent(), WinBits( WB_OK ), + String( ScResId( STR_PRINT_NOTHING ) ) ); + aWarningBox.Execute(); + } + return false; + } + + return true; +} + +void ScDocShell::PreparePrint( PrintDialog* pPrintDialog, ScMarkData* pMarkData ) +{ + SfxPrinter* pPrinter = GetPrinter(); + if ( !pPrinter ) + { + return; + } + + delete pOldJobSetup; // gesetzt nur bei Fehler in StartJob() + pOldJobSetup = new ScJobSetup( pPrinter ); // Einstellungen merken + + // Einstellungen fuer die erste gedruckte Seite muessen hier (vor StartJob) gesetzt werden + //! Selection etc. mit Print() zusammenfassen !!! + //! Seiten nur einmal zaehlen + + bool bHasOptions = false; + ScPrintOptions aOptions; + bool bAllTabs = true; + long nTotalPages = 0; + long aPageArr[MAXTABCOUNT]; // pages per sheet + MultiSelection aPageRanges; // pages to print + ScRange* pMarkedRange = NULL; + + lcl_GetPrintData( this, &aDocument, pPrinter, pPrintDialog, false, + pMarkData, bHasOptions, aOptions, bAllTabs, nTotalPages, + aPageArr, aPageRanges, &pMarkedRange ); + + BOOL bFound = FALSE; // erste Seite gefunden + long nTabStart = 0; + SCTAB nTabCount = aDocument.GetTableCount(); + for ( SCTAB nTab=0; nTab<nTabCount && !bFound; nTab++ ) + { + if ( bAllTabs || !pMarkData || pMarkData->GetTableSelect( nTab ) ) + { + long nNext = nTabStart + aPageArr[nTab]; + BOOL bSelected = FALSE; + for (long nP=nTabStart+1; nP<=nNext; nP++) // 1-basiert + if (aPageRanges.IsSelected( nP )) // eine Seite von dieser Tabelle selektiert? + bSelected = TRUE; + + if (bSelected) + { + ScPrintFunc aPrintFunc( this, pPrinter, nTab ); + + aPrintFunc.ApplyPrintSettings(); // dann Settings fuer diese Tabelle + bFound = TRUE; + } + nTabStart = nNext; + } + } + + delete pMarkedRange; +} + +BOOL lcl_HasTransparent( ScDocument* pDoc, SCTAB nTab, const ScRange* pRange ) +{ + BOOL bFound = FALSE; + ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer(); + if (pDrawLayer) + { + SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab)); + DBG_ASSERT(pPage,"Page ?"); + if (pPage) + { + Rectangle aMMRect; + if ( pRange ) + aMMRect = pDoc->GetMMRect( pRange->aStart.Col(), pRange->aStart.Row(), + pRange->aEnd.Col(), pRange->aEnd.Row(), nTab ); + + SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS ); + SdrObject* pObject = aIter.Next(); + while (pObject && !bFound) + { + if (pObject->IsTransparent()) + { + if ( pRange ) + { + Rectangle aObjRect = pObject->GetLogicRect(); + if ( aObjRect.IsOver( aMMRect ) ) + bFound = TRUE; + } + else + bFound = TRUE; + } + + pObject = aIter.Next(); + } + } + } + + return bFound; +} + +void ScDocShell::Print( SfxProgress& rProgress, PrintDialog* pPrintDialog, + ScMarkData* pMarkData, Window* pDialogParent, BOOL bForceSelected, BOOL bIsAPI ) +{ + SfxPrinter* pPrinter = GetPrinter(); + if ( !pPrinter ) + { + return; + } + + bool bHasOptions = false; + ScPrintOptions aOptions; + bool bAllTabs = true; + long nTotalPages = 0; + long aPageArr[MAXTABCOUNT]; // pages per sheet + MultiSelection aPageRanges; // pages to print + ScRange* pMarkedRange = NULL; + + lcl_GetPrintData( this, &aDocument, pPrinter, pPrintDialog, bForceSelected, + pMarkData, bHasOptions, aOptions, bAllTabs, nTotalPages, + aPageArr, aPageRanges, &pMarkedRange ); + + USHORT nCollateCopies = 1; + if ( pPrintDialog && pPrintDialog->IsCollateEnabled() && pPrintDialog->IsCollateChecked() ) + nCollateCopies = pPrintDialog->GetCopyCount(); + + // test if printed range contains transparent objects + + BOOL bHasTransp = FALSE; + BOOL bAnyPrintRanges = aDocument.HasPrintRange(); + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SCTAB nTabCount = aDocument.GetTableCount(); + for ( SCTAB nTab=0; nTab<nTabCount && !bHasTransp; nTab++ ) + { + if ( bAllTabs || !pMarkData || pMarkData->GetTableSelect( nTab ) ) + { + SfxStyleSheetBase* pStyleSheet = pStylePool->Find( + aDocument.GetPageStyle( nTab ), SFX_STYLE_FAMILY_PAGE ); + if ( pStyleSheet ) + { + const SfxItemSet& rSet = pStyleSheet->GetItemSet(); + if ( ((const ScViewObjectModeItem&)rSet.Get(ATTR_PAGE_CHARTS)).GetValue() == VOBJ_MODE_SHOW || + ((const ScViewObjectModeItem&)rSet.Get(ATTR_PAGE_OBJECTS)).GetValue() == VOBJ_MODE_SHOW || + ((const ScViewObjectModeItem&)rSet.Get(ATTR_PAGE_DRAWINGS)).GetValue() == VOBJ_MODE_SHOW ) + { + if ( pMarkedRange ) + bHasTransp = bHasTransp || lcl_HasTransparent( &aDocument, nTab, pMarkedRange ); + else if ( aDocument.GetPrintRangeCount(nTab) ) + { + USHORT nRangeCount = aDocument.GetPrintRangeCount(nTab); + for (USHORT i=0; i<nRangeCount; i++) + bHasTransp = bHasTransp || + lcl_HasTransparent( &aDocument, nTab, aDocument.GetPrintRange( nTab, i ) ); + } + else if (!bAnyPrintRanges || aDocument.IsPrintEntireSheet(nTab)) + bHasTransp = bHasTransp || lcl_HasTransparent( &aDocument, nTab, NULL ); + } + } + } + } + + BOOL bContinue = pPrinter->InitJob( pDialogParent, !bIsAPI && bHasTransp ); + + if ( bContinue ) + { + for ( USHORT n=0; n<nCollateCopies; n++ ) + { + long nTabStart = 0; + long nDisplayStart = 0; + long nAttrPage = 1; + long nPrinted = 0; + + for ( SCTAB nTab=0; nTab<nTabCount; nTab++ ) + { + if ( bAllTabs || !pMarkData || pMarkData->GetTableSelect( nTab ) ) + { + FmFormView* pDrawView = NULL; + Rectangle aFull( 0, 0, LONG_MAX, LONG_MAX ); + + // #114135# + ScDrawLayer* pModel = aDocument.GetDrawLayer(); // ist nicht NULL + + if(pModel) + { + pDrawView = new FmFormView( pModel, pPrinter ); + pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab)); + pDrawView->SetPrintPreview( TRUE ); + } + + ScPrintFunc aPrintFunc( this, pPrinter, nTab, nAttrPage, nTotalPages, pMarkedRange, &aOptions ); + aPrintFunc.SetDrawView( pDrawView ); + nPrinted += aPrintFunc.DoPrint( aPageRanges, nTabStart, nDisplayStart, TRUE, &rProgress, NULL ); + + nTabStart += aPageArr[nTab]; + if ( aDocument.NeedPageResetAfterTab(nTab) ) + nDisplayStart = 0; + else + nDisplayStart += aPageArr[nTab]; + nAttrPage = aPrintFunc.GetFirstPageNo(); // behalten oder aus Vorlage + + delete pDrawView; + } + } + + if ( n+1 < nCollateCopies && + (pPrinter->GetDuplexMode() == DUPLEX_SHORTEDGE || pPrinter->GetDuplexMode() == DUPLEX_LONGEDGE) && + ( nPrinted % 2 ) == 1 ) + { + // #105584# when several collated copies are printed in duplex mode, and there is + // an odd number of pages, print an empty page between copies, so the first page of + // the second copy isn't printed on the back of the last page of the first copy. + // (same as in Writer ViewShell::Prt) + + // FIXME: needs to be adapted to XRenderable interface + #if 0 + pPrinter->StartPage(); + pPrinter->EndPage(); + #endif + } + } + } + + delete pMarkedRange; + + if (pOldJobSetup) + { + pPrinter->SetOrientation( pOldJobSetup->eOrientation ); + pPrinter->SetPaperBin ( pOldJobSetup->nPaperBin ); + pPrinter->SetPaper ( pOldJobSetup->ePaper ); + + if ( PAPER_USER == pOldJobSetup->ePaper ) + { + pPrinter->SetMapMode( pOldJobSetup->aUserMapMode ); + pPrinter->SetPaperSizeUser( pOldJobSetup->aUserSize ); + } + + delete pOldJobSetup; + pOldJobSetup = NULL; + } + + if ( bHasOptions ) + { + // remove PrintOptions from printer ItemSet, + // so next time the options from the configuration are used + + SfxItemSet aSet( pPrinter->GetOptions() ); + aSet.ClearItem( SID_SCPRINTOPTIONS ); + pPrinter->SetOptions( aSet ); + } + + PostPaintGridAll(); //! nur wenn geaendert +} + +void ScDocShell::GetState( SfxItemSet &rSet ) +{ + SfxWhichIter aIter(rSet); + USHORT nWhich = aIter.FirstWhich(); + while ( nWhich ) + { + switch (nWhich) + { + case FID_AUTO_CALC: + if ( (BOOL) aDocument.GetHardRecalcState() ) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem( nWhich, aDocument.GetAutoCalc() ) ); + break; + + case FID_CHG_RECORD: + if ( IsDocShared() ) + rSet.DisableItem( nWhich ); + else + rSet.Put( SfxBoolItem( nWhich, + aDocument.GetChangeTrack() != NULL ) ); + break; + + case SID_CHG_PROTECT: + { + ScChangeTrack* pChangeTrack = aDocument.GetChangeTrack(); + if ( pChangeTrack && !IsDocShared() ) + rSet.Put( SfxBoolItem( nWhich, + pChangeTrack->IsProtected() ) ); + else + rSet.DisableItem( nWhich ); + } + break; + + case SID_DOCUMENT_COMPARE: + { + if ( IsDocShared() ) + { + rSet.DisableItem( nWhich ); + } + } + break; + + // Wenn eine Formel editiert wird, muss FID_RECALC auf jeden Fall enabled sein. + // Recalc fuer das Doc war mal wegen #29898# disabled, wenn AutoCalc an war, + // ist jetzt wegen #41540# aber auch immer enabled. +// case FID_RECALC: +// if ( aDocument.GetAutoCalc() ) +// rSet.DisableItem( nWhich ); +// break; + + case SID_TABLES_COUNT: + rSet.Put( SfxInt16Item( nWhich, aDocument.GetTableCount() ) ); + break; + + case SID_ATTR_YEAR2000 : + rSet.Put( SfxUInt16Item( nWhich, + aDocument.GetDocOptions().GetYear2000() ) ); + break; + + case SID_SHARE_DOC: + { + if ( IsReadOnly() ) + { + rSet.DisableItem( nWhich ); + } + } + break; + + default: + { + } + break; + } + + nWhich = aIter.NextWhich(); + } +} + +void ScDocShell::GetSbxState( SfxItemSet &rSet ) +{ + // SID_SC_SELECTION (Selection), + // SID_SC_ACTIVECELL (ActiveCell), + // SID_SC_ACTIVETAB (ActiveTable), + // SID_TABLES_GET (Tables), + // SID_PIVOT_GET (DataPilotTables) - removed (old Basic) + + // + // Wenn hier Slots von der View-Shell executed werden, muss auch der + // GetState weitergeleitet werden! + // + + ScTabViewShell* pVisibleSh = GetBestViewShell(); // sichtbare View + if ( pVisibleSh ) + pVisibleSh->GetState( rSet ); +} + +void __EXPORT ScDocShell::Draw( OutputDevice* pDev, const JobSetup & /* rSetup */, USHORT nAspect ) +{ +// bIsOle = TRUE; // jetzt ueber den CreateMode + + SCTAB nVisTab = aDocument.GetVisibleTab(); + if (!aDocument.HasTable(nVisTab)) + return; + + ULONG nOldLayoutMode = pDev->GetLayoutMode(); + pDev->SetLayoutMode( TEXT_LAYOUT_DEFAULT ); // even if it's the same, to get the metafile action + + if ( nAspect == ASPECT_THUMBNAIL ) + { + Rectangle aBoundRect = GetVisArea( ASPECT_THUMBNAIL ); + ScViewData aTmpData( this, NULL ); + aTmpData.SetTabNo(nVisTab); + aDocument.SnapVisArea( aBoundRect ); + aTmpData.SetScreen( aBoundRect ); + ScPrintFunc::DrawToDev( &aDocument, pDev, 1.0, aBoundRect, &aTmpData, TRUE ); + } + else + { + Rectangle aBoundRect = SfxObjectShell::GetVisArea(); + ScViewData aTmpData( this, NULL ); + aTmpData.SetTabNo(nVisTab); + aDocument.SnapVisArea( aBoundRect ); + aTmpData.SetScreen( aBoundRect ); + ScPrintFunc::DrawToDev( &aDocument, pDev, 1.0, aBoundRect, &aTmpData, TRUE ); + } + + pDev->SetLayoutMode( nOldLayoutMode ); +} + +Rectangle __EXPORT ScDocShell::GetVisArea( USHORT nAspect ) const +{ + SfxObjectCreateMode eShellMode = GetCreateMode(); + if ( eShellMode == SFX_CREATE_MODE_ORGANIZER ) + { + // ohne Inhalte wissen wir auch nicht, wie gross die Inhalte sind + // leeres Rechteck zurueckgeben, das wird dann nach dem Laden berechnet + return Rectangle(); + } + + if( nAspect == ASPECT_THUMBNAIL ) + { +// Rectangle aArea( 0,0, 3175,3175 ); // 120x120 Pixel in 1:1 + Rectangle aArea( 0,0, SC_PREVIEW_SIZE_X,SC_PREVIEW_SIZE_Y ); + BOOL bNegativePage = aDocument.IsNegativePage( aDocument.GetVisibleTab() ); + if ( bNegativePage ) + ScDrawLayer::MirrorRectRTL( aArea ); + aDocument.SnapVisArea( aArea ); + return aArea; + } + else if( nAspect == ASPECT_CONTENT && eShellMode != SFX_CREATE_MODE_EMBEDDED ) + { + // Visarea holen wie nach Load + + SCTAB nVisTab = aDocument.GetVisibleTab(); + if (!aDocument.HasTable(nVisTab)) + { + nVisTab = 0; + ((ScDocShell*)this)->aDocument.SetVisibleTab(nVisTab); + } + SCCOL nStartCol; + SCROW nStartRow; + aDocument.GetDataStart( nVisTab, nStartCol, nStartRow ); + SCCOL nEndCol; + SCROW nEndRow; + aDocument.GetPrintArea( nVisTab, nEndCol, nEndRow ); + if (nStartCol>nEndCol) + nStartCol = nEndCol; + if (nStartRow>nEndRow) + nStartRow = nEndRow; + Rectangle aNewArea = ((ScDocument&)aDocument) + .GetMMRect( nStartCol,nStartRow, nEndCol,nEndRow, nVisTab ); + //TODO/LATER: different methods for setting VisArea?! + ((ScDocShell*)this)->SfxObjectShell::SetVisArea( aNewArea ); + return aNewArea; + } + else + return SfxObjectShell::GetVisArea( nAspect ); +} + +void ScDocShell::GetPageOnFromPageStyleSet( const SfxItemSet* pStyleSet, + SCTAB nCurTab, + BOOL& rbHeader, + BOOL& rbFooter ) +{ + if ( !pStyleSet ) + { + ScStyleSheetPool* pStylePool = aDocument.GetStyleSheetPool(); + SfxStyleSheetBase* pStyleSheet = pStylePool-> + Find( aDocument.GetPageStyle( nCurTab ), + SFX_STYLE_FAMILY_PAGE ); + + DBG_ASSERT( pStyleSheet, "PageStyle not found! :-/" ); + + if ( pStyleSheet ) + pStyleSet = &pStyleSheet->GetItemSet(); + else + rbHeader = rbFooter = FALSE; + } + + DBG_ASSERT( pStyleSet, "PageStyle-Set not found! :-(" ); + + //-------------------------------------------------------------------- + + const SvxSetItem* pSetItem = NULL; + const SfxItemSet* pSet = NULL; + + pSetItem = (const SvxSetItem*) &pStyleSet->Get( ATTR_PAGE_HEADERSET ); + pSet = &pSetItem->GetItemSet(); + rbHeader = ((const SfxBoolItem&)pSet->Get(ATTR_PAGE_ON)).GetValue(); + + pSetItem = (const SvxSetItem*) &pStyleSet->Get( ATTR_PAGE_FOOTERSET ); + pSet = &pSetItem->GetItemSet(); + rbFooter = ((const SfxBoolItem&)pSet->Get(ATTR_PAGE_ON)).GetValue(); +} + +long __EXPORT ScDocShell::DdeGetData( const String& rItem, + const String& rMimeType, + ::com::sun::star::uno::Any & rValue ) +{ + if( FORMAT_STRING == SotExchange::GetFormatIdFromMimeType( rMimeType ) ) + { + if( rItem.EqualsIgnoreCaseAscii( "Format" ) ) + { + ByteString aFmtByte( aDdeTextFmt, gsl_getSystemTextEncoding() ); + rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >( + (sal_Int8*)aFmtByte.GetBuffer(), + aFmtByte.Len() + 1 ); + return 1; + } + ScImportExport aObj( &aDocument, rItem ); + if ( !aObj.IsRef() ) + return 0; // ungueltiger Bereich + + if( aDdeTextFmt.GetChar(0) == 'F' ) + aObj.SetFormulas( TRUE ); + if( aDdeTextFmt.EqualsAscii( "SYLK" ) || + aDdeTextFmt.EqualsAscii( "FSYLK" ) ) + { + ByteString aData; + if( aObj.ExportByteString( aData, gsl_getSystemTextEncoding(), + SOT_FORMATSTR_ID_SYLK ) ) + { + rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >( + (sal_Int8*)aData.GetBuffer(), + aData.Len() + 1 ); + return 1; + } + else + return 0; + } + if( aDdeTextFmt.EqualsAscii( "CSV" ) || + aDdeTextFmt.EqualsAscii( "FCSV" ) ) + aObj.SetSeparator( ',' ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) ); + return aObj.ExportData( rMimeType, rValue ) ? 1 : 0; + } + + ScImportExport aObj( &aDocument, rItem ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) ); + if( aObj.IsRef() ) + return aObj.ExportData( rMimeType, rValue ) ? 1 : 0; + return 0; +} + +long __EXPORT ScDocShell::DdeSetData( const String& rItem, + const String& rMimeType, + const ::com::sun::star::uno::Any & rValue ) +{ + if( FORMAT_STRING == SotExchange::GetFormatIdFromMimeType( rMimeType )) + { + if( rItem.EqualsIgnoreCaseAscii( "Format" ) ) + { + if ( ScByteSequenceToString::GetString( aDdeTextFmt, rValue, gsl_getSystemTextEncoding() ) ) + { + aDdeTextFmt.ToUpperAscii(); + return 1; + } + return 0; + } + ScImportExport aObj( &aDocument, rItem ); + if( aDdeTextFmt.GetChar(0) == 'F' ) + aObj.SetFormulas( TRUE ); + if( aDdeTextFmt.EqualsAscii( "SYLK" ) || + aDdeTextFmt.EqualsAscii( "FSYLK" ) ) + { + String aData; + if ( ScByteSequenceToString::GetString( aData, rValue, gsl_getSystemTextEncoding() ) ) + { + return aObj.ImportString( aData, SOT_FORMATSTR_ID_SYLK ) ? 1 : 0; + } + return 0; + } + if( aDdeTextFmt.EqualsAscii( "CSV" ) || + aDdeTextFmt.EqualsAscii( "FCSV" ) ) + aObj.SetSeparator( ',' ); + return aObj.ImportData( rMimeType, rValue ) ? 1 : 0; + } + ScImportExport aObj( &aDocument, rItem ); + if( aObj.IsRef() ) + return aObj.ImportData( rMimeType, rValue ) ? 1 : 0; + return 0; +} + +::sfx2::SvLinkSource* __EXPORT ScDocShell::DdeCreateLinkSource( const String& rItem ) +{ + // only check for valid item string - range is parsed again in ScServerObject ctor + + // named range? + String aPos = rItem; + ScRangeName* pRange = aDocument.GetRangeName(); + if( pRange ) + { + USHORT nPos; + if( pRange->SearchName( aPos, nPos ) ) + { + ScRangeData* pData = (*pRange)[ nPos ]; + if( pData->HasType( RT_REFAREA ) + || pData->HasType( RT_ABSAREA ) + || pData->HasType( RT_ABSPOS ) ) + pData->GetSymbol( aPos ); // continue with the name's contents + } + } + + // Address in DDE function must be always parsed as CONV_OOO so that it + // would always work regardless of current address convension. We do this + // because the address item in a DDE entry is *not* normalized when saved + // into ODF. + ScRange aRange; + bool bValid = ( (aRange.Parse(aPos, &aDocument, formula::FormulaGrammar::CONV_OOO ) & SCA_VALID) || + (aRange.aStart.Parse(aPos, &aDocument, formula::FormulaGrammar::CONV_OOO) & SCA_VALID) ); + + ScServerObject* pObj = NULL; // NULL = error + if ( bValid ) + pObj = new ScServerObject( this, rItem ); + + // GetLinkManager()->InsertServer() is in the ScServerObject ctor + + return pObj; +} + +//------------------------------------------------------------------ + +ScViewData* ScDocShell::GetViewData() +{ + SfxViewShell* pCur = SfxViewShell::Current(); + ScTabViewShell* pViewSh = PTR_CAST(ScTabViewShell,pCur); + return pViewSh ? pViewSh->GetViewData() : NULL; +} + +//------------------------------------------------------------------ + +SCTAB ScDocShell::GetCurTab() +{ + //! this must be made non-static and use a ViewShell from this document! + + ScViewData* pViewData = GetViewData(); + + return pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0); +} + +ScTabViewShell* ScDocShell::GetBestViewShell( BOOL bOnlyVisible ) +{ + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + // falsches Doc? + if( pViewSh && pViewSh->GetViewData()->GetDocShell() != this ) + pViewSh = NULL; + if( !pViewSh ) + { + // 1. ViewShell suchen + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this, TYPE(SfxTopViewFrame), bOnlyVisible ); + if( pFrame ) + { + SfxViewShell* p = pFrame->GetViewShell(); + pViewSh = PTR_CAST(ScTabViewShell,p); + } + } + return pViewSh; +} + +SfxBindings* ScDocShell::GetViewBindings() +{ + // used to invalidate slots after changes to this document + + SfxViewShell* pViewSh = GetBestViewShell(); + if (pViewSh) + return &pViewSh->GetViewFrame()->GetBindings(); + else + return NULL; +} + +//------------------------------------------------------------------ + +ScDocShell* ScDocShell::GetShellByNum( USHORT nDocNo ) // static +{ + ScDocShell* pFound = NULL; + SfxObjectShell* pShell = SfxObjectShell::GetFirst(); + USHORT nShellCnt = 0; + + while ( pShell && !pFound ) + { + if ( pShell->Type() == TYPE(ScDocShell) ) + { + if ( nShellCnt == nDocNo ) + pFound = (ScDocShell*) pShell; + else + ++nShellCnt; + } + pShell = SfxObjectShell::GetNext( *pShell ); + } + + return pFound; +} + +//------------------------------------------------------------------ + +IMPL_LINK( ScDocShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg ) +{ + DBG_ASSERT( _pFileDlg, "ScDocShell::DialogClosedHdl(): no file dialog" ); + DBG_ASSERT( pImpl->pDocInserter, "ScDocShell::DialogClosedHdl(): no document inserter" ); + + if ( ERRCODE_NONE == _pFileDlg->GetError() ) + { + USHORT nSlot = pImpl->pRequest->GetSlot(); + SfxMedium* pMed = pImpl->pDocInserter->CreateMedium(); + // #i87094# If a .odt was selected pMed is NULL. + if (pMed) + { + pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_NAME, pMed->GetName() ) ); + if ( SID_DOCUMENT_COMPARE == nSlot ) + { + if ( pMed->GetFilter() ) + pImpl->pRequest->AppendItem( + SfxStringItem( SID_FILTER_NAME, pMed->GetFilter()->GetFilterName() ) ); + String sOptions = ScDocumentLoader::GetOptions( *pMed ); + if ( sOptions.Len() > 0 ) + pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_FILTEROPTIONS, sOptions ) ); + } + const SfxPoolItem* pItem = NULL; + SfxItemSet* pSet = pMed->GetItemSet(); + if ( pSet && + pSet->GetItemState( SID_VERSION, TRUE, &pItem ) == SFX_ITEM_SET && + pItem->ISA( SfxInt16Item ) ) + { + pImpl->pRequest->AppendItem( *pItem ); + } + + Execute( *(pImpl->pRequest) ); + } + } + + pImpl->bIgnoreLostRedliningWarning = false; + return 0; +} + +//------------------------------------------------------------------ + +void ScDocShell::EnableSharedSettings( bool bEnable ) +{ + SetDocumentModified(); + + if ( bEnable ) + { + aDocument.EndChangeTracking(); + aDocument.StartChangeTracking(); + + // hide accept or reject changes dialog + USHORT nId = ScAcceptChgDlgWrapper::GetChildWindowId(); + SfxViewFrame* pViewFrame = SfxViewFrame::Current(); + if ( pViewFrame && pViewFrame->HasChildWindow( nId ) ) + { + pViewFrame->ToggleChildWindow( nId ); + SfxBindings* pBindings = GetViewBindings(); + if ( pBindings ) + { + pBindings->Invalidate( FID_CHG_ACCEPT ); + } + } + } + else + { + aDocument.EndChangeTracking(); + } + + ScChangeViewSettings aChangeViewSet; + aChangeViewSet.SetShowChanges( FALSE ); + aDocument.SetChangeViewSettings( aChangeViewSet ); +} + +uno::Reference< frame::XModel > ScDocShell::LoadSharedDocument() +{ + uno::Reference< frame::XModel > xModel; + try + { + SC_MOD()->SetInSharedDocLoading( true ); + uno::Reference< lang::XMultiServiceFactory > xFactory( + ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); + uno::Reference< frame::XComponentLoader > xLoader( + xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.frame.Desktop" ) ) ), + uno::UNO_QUERY_THROW ); + uno::Sequence < beans::PropertyValue > aArgs( 1 ); + aArgs[0].Name = ::rtl::OUString::createFromAscii( "Hidden" ); + aArgs[0].Value <<= sal_True; + + if ( GetMedium() ) + { + SFX_ITEMSET_ARG( GetMedium()->GetItemSet(), pPasswordItem, SfxStringItem, SID_PASSWORD, sal_False); + if ( pPasswordItem && pPasswordItem->GetValue().Len() ) + { + aArgs.realloc( 2 ); + aArgs[1].Name = ::rtl::OUString::createFromAscii( "Password" ); + aArgs[1].Value <<= ::rtl::OUString( pPasswordItem->GetValue() ); + } + } + + xModel.set( + xLoader->loadComponentFromURL( GetSharedFileURL(), ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "_blank" ) ), 0, aArgs ), + uno::UNO_QUERY_THROW ); + SC_MOD()->SetInSharedDocLoading( false ); + } + catch ( uno::Exception& ) + { + DBG_ERROR( "ScDocShell::LoadSharedDocument(): caught exception\n" ); + SC_MOD()->SetInSharedDocLoading( false ); + try + { + uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW ); + xClose->close( sal_True ); + return uno::Reference< frame::XModel >(); + } + catch ( uno::Exception& ) + { + return uno::Reference< frame::XModel >(); + } + } + return xModel; +} diff --git a/sc/source/ui/docshell/docsh5.cxx b/sc/source/ui/docshell/docsh5.cxx new file mode 100644 index 000000000000..6fa6a5ac7863 --- /dev/null +++ b/sc/source/ui/docshell/docsh5.cxx @@ -0,0 +1,938 @@ +/************************************************************************* + * + * 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" + +// System - Includes ----------------------------------------------------- + + + + +#include "scitems.hxx" +#include <vcl/svapp.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/waitobj.hxx> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <svl/smplhint.hxx> + +#include <com/sun/star/sdbc/XResultSet.hpp> + +// INCLUDE --------------------------------------------------------------- + +#include "docsh.hxx" +#include "global.hxx" +#include "globstr.hrc" +#include "undodat.hxx" +#include "undotab.hxx" +#include "undoblk.hxx" +//#include "pivot.hxx" +#include "dpobject.hxx" +#include "dpshttab.hxx" +#include "dbdocfun.hxx" +#include "consoli.hxx" +#include "dbcolect.hxx" +#include "olinetab.hxx" +#include "patattr.hxx" +#include "attrib.hxx" +#include "docpool.hxx" +#include "uiitems.hxx" +#include "sc.hrc" +#include "waitoff.hxx" +#include "sizedev.hxx" + +// --------------------------------------------------------------------------- + +// +// ehemalige viewfunc/dbfunc Methoden +// + +void ScDocShell::ErrorMessage( USHORT nGlobStrId ) +{ + //! StopMarking an der (aktiven) View? + + Window* pParent = GetActiveDialogParent(); + ScWaitCursorOff aWaitOff( pParent ); + BOOL bFocus = pParent && pParent->HasFocus(); + + if(nGlobStrId==STR_PROTECTIONERR) + { + if(IsReadOnly()) + { + nGlobStrId=STR_READONLYERR; + } + } + + InfoBox aBox( pParent, ScGlobal::GetRscString( nGlobStrId ) ); + aBox.Execute(); + if (bFocus) + pParent->GrabFocus(); +} + +BOOL ScDocShell::IsEditable() const +{ + // import into read-only document is possible - must be extended if other filters use api + + return !IsReadOnly() || aDocument.IsImportingXML(); +} + +void ScDocShell::DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW /* nY2 */ ) +{ + ScDocShellModificator aModificator( *this ); + aDocument.RemoveFlagsTab( nX1, nY1, nX2, nY1, nTab, SC_MF_AUTO ); + PostPaint( nX1, nY1, nTab, nX2, nY1, nTab, PAINT_GRID ); + // No SetDocumentModified, as the unnamed database range might have to be restored later. + // The UNO hint is broadcast directly instead, to keep UNO objects in valid state. + aDocument.BroadcastUno( SfxSimpleHint( SFX_HINT_DATACHANGED ) ); +} + +ScDBData* lcl_GetDBNearCursor( ScDBCollection* pColl, SCCOL nCol, SCROW nRow, SCTAB nTab ) +{ + //! nach document/dbcolect verschieben + + if (!pColl) + return NULL; + + ScDBData* pNoNameData = NULL; + ScDBData* pNearData = NULL; + USHORT nCount = pColl->GetCount(); + String aNoName = ScGlobal::GetRscString( STR_DB_NONAME ); + SCTAB nAreaTab; + SCCOL nStartCol, nEndCol; + SCROW nStartRow, nEndRow; + for (USHORT i = 0; i < nCount; i++) + { + ScDBData* pDB = (*pColl)[i]; + pDB->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow ); + if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 && + nRow+1 >= nStartRow && nRow <= nEndRow+1 ) + { + if ( pDB->GetName() == aNoName ) + pNoNameData = pDB; + else if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow ) + { + if (!pNearData) + pNearData = pDB; // ersten angrenzenden Bereich merken + } + else + return pDB; // nicht "unbenannt" und Cursor steht wirklich drin + } + } + if (pNearData) + return pNearData; // angrenzender, wenn nichts direkt getroffen + return pNoNameData; // "unbenannt" nur zurueck, wenn sonst nichts gefunden +} + +ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, BOOL bForceMark ) +{ + SCCOL nCol = rMarked.aStart.Col(); + SCROW nRow = rMarked.aStart.Row(); + SCTAB nTab = rMarked.aStart.Tab(); + + SCCOL nStartCol = nCol; + SCROW nStartRow = nRow; + SCTAB nStartTab = nTab; + SCCOL nEndCol = rMarked.aEnd.Col(); + SCROW nEndRow = rMarked.aEnd.Row(); + SCTAB nEndTab = rMarked.aEnd.Tab(); + + // Wegen #49655# nicht einfach GetDBAtCursor: Der zusammenhaengende Datenbereich + // fuer "unbenannt" (GetDataArea) kann neben dem Cursor legen, also muss auch ein + // benannter DB-Bereich dort gesucht werden. + + ScDBData* pData = aDocument.GetDBAtArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow ); + if (!pData) + pData = lcl_GetDBNearCursor( aDocument.GetDBCollection(), nCol, nRow, nTab ); + + BOOL bSelected = ( bForceMark || rMarked.aStart != rMarked.aEnd ); + + BOOL bUseThis = FALSE; + if (pData) + { + // Bereich nehmen, wenn nichts anderes markiert + + SCTAB nDummy; + SCCOL nOldCol1; + SCROW nOldRow1; + SCCOL nOldCol2; + SCROW nOldRow2; + pData->GetArea( nDummy, nOldCol1,nOldRow1, nOldCol2,nOldRow2 ); + BOOL bIsNoName = ( pData->GetName() == ScGlobal::GetRscString( STR_DB_NONAME ) ); + + if (!bSelected) + { + bUseThis = TRUE; + if ( bIsNoName && eMode == SC_DB_MAKE ) + { + // wenn nichts markiert, "unbenannt" auf zusammenhaengenden Bereich anpassen + nStartCol = nCol; + nStartRow = nRow; + nEndCol = nStartCol; + nEndRow = nStartRow; + aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE ); + if ( nOldCol1 != nStartCol || nOldCol2 != nEndCol || nOldRow1 != nStartRow ) + bUseThis = FALSE; // passt gar nicht + else if ( nOldRow2 != nEndRow ) + { + // Bereich auf neue End-Zeile erweitern + pData->SetArea( nTab, nOldCol1,nOldRow1, nOldCol2,nEndRow ); + } + } + } + else + { + if ( nOldCol1 == nStartCol && nOldRow1 == nStartRow && + nOldCol2 == nEndCol && nOldRow2 == nEndRow ) // genau markiert? + bUseThis = TRUE; + else + bUseThis = FALSE; // immer Markierung nehmen (Bug 11964) + } + + // fuer Import nie "unbenannt" nehmen + + if ( bUseThis && eMode == SC_DB_IMPORT && bIsNoName ) + bUseThis = FALSE; + } + + if ( bUseThis ) + { + pData->GetArea( nStartTab, nStartCol,nStartRow, nEndCol,nEndRow ); + nEndTab = nStartTab; + } + else if ( eMode == SC_DB_OLD ) + { + pData = NULL; // nichts gefunden + nStartCol = nEndCol = nCol; + nStartRow = nEndRow = nRow; + nStartTab = nEndTab = nTab; +// bMark = FALSE; // nichts zu markieren + } + else + { + if ( bSelected ) + { +// bMark = FALSE; + } + else + { // zusammenhaengender Bereich + nStartCol = nCol; + nStartRow = nRow; + nEndCol = nStartCol; + nEndRow = nStartRow; + aDocument.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, FALSE ); + } + + BOOL bHasHeader = aDocument.HasColHeader( nStartCol,nStartRow, nEndCol,nEndRow, nTab ); + + ScDBData* pNoNameData; + USHORT nNoNameIndex; + ScDBCollection* pColl = aDocument.GetDBCollection(); + if ( eMode != SC_DB_IMPORT && + pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) ) + { + pNoNameData = (*pColl)[nNoNameIndex]; + + if ( !pOldAutoDBRange ) + { + // store the old unnamed database range with its settings for undo + // (store at the first change, get the state before all changes) + pOldAutoDBRange = new ScDBData( *pNoNameData ); + } + + SCCOL nOldX1; // alten Bereich sauber wegnehmen + SCROW nOldY1; //! (UNDO ???) + SCCOL nOldX2; + SCROW nOldY2; + SCTAB nOldTab; + pNoNameData->GetArea( nOldTab, nOldX1, nOldY1, nOldX2, nOldY2 ); + DBAreaDeleted( nOldTab, nOldX1, nOldY1, nOldX2, nOldY2 ); + + pNoNameData->SetSortParam( ScSortParam() ); // Parameter zuruecksetzen + pNoNameData->SetQueryParam( ScQueryParam() ); + pNoNameData->SetSubTotalParam( ScSubTotalParam() ); + + pNoNameData->SetArea( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); // neu setzen + pNoNameData->SetByRow( TRUE ); + pNoNameData->SetHeader( bHasHeader ); + pNoNameData->SetAutoFilter( FALSE ); + } + else + { + ScDBCollection* pUndoColl = NULL; + + String aNewName; + if (eMode==SC_DB_IMPORT) + { + aDocument.CompileDBFormula( TRUE ); // CreateFormulaString + pUndoColl = new ScDBCollection( *pColl ); // Undo fuer Import1-Bereich + + String aImport = ScGlobal::GetRscString( STR_DBNAME_IMPORT ); + long nCount = 0; + USHORT nDummy; + do + { + ++nCount; + aNewName = aImport; + aNewName += String::CreateFromInt32( nCount ); + } + while (pColl->SearchName( aNewName, nDummy )); + } + else + aNewName = ScGlobal::GetRscString( STR_DB_NONAME ); + pNoNameData = new ScDBData( aNewName, nTab, + nStartCol,nStartRow, nEndCol,nEndRow, + TRUE, bHasHeader ); + pColl->Insert( pNoNameData ); + + if ( pUndoColl ) + { + aDocument.CompileDBFormula( FALSE ); // CompileFormulaString + + ScDBCollection* pRedoColl = new ScDBCollection( *pColl ); + GetUndoManager()->AddUndoAction( new ScUndoDBData( this, pUndoColl, pRedoColl ) ); + } + + // neuen Bereich am Sba anmelden nicht mehr noetig + + // "Import1" etc am Navigator bekanntmachen + if (eMode==SC_DB_IMPORT) + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) ); + } + pData = pNoNameData; + } + +// if (bMark) +// MarkRange( ScRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ), FALSE ); + + return pData; +} + +ScDBData* ScDocShell::GetOldAutoDBRange() +{ + ScDBData* pRet = pOldAutoDBRange; + pOldAutoDBRange = NULL; + return pRet; // has to be deleted by caller! +} + +void ScDocShell::CancelAutoDBRange() +{ + // called when dialog is cancelled + if ( pOldAutoDBRange ) + { + USHORT nNoNameIndex; + ScDBCollection* pColl = aDocument.GetDBCollection(); + if ( pColl->SearchName( ScGlobal::GetRscString( STR_DB_NONAME ), nNoNameIndex ) ) + { + ScDBData* pNoNameData = (*pColl)[nNoNameIndex]; + + SCCOL nRangeX1; + SCROW nRangeY1; + SCCOL nRangeX2; + SCROW nRangeY2; + SCTAB nRangeTab; + pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); + DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); + + *pNoNameData = *pOldAutoDBRange; // restore old settings + + if ( pOldAutoDBRange->HasAutoFilter() ) + { + // restore AutoFilter buttons + pOldAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 ); + aDocument.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, SC_MF_AUTO ); + PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PAINT_GRID ); + } + } + + delete pOldAutoDBRange; + pOldAutoDBRange = NULL; + } +} + + + // Hoehen anpassen + //! mit docfunc zusammenfassen + +BOOL ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) +{ + ScSizeDeviceProvider aProv(this); + Fraction aZoom(1,1); + BOOL bChange = aDocument.SetOptimalHeight( nStartRow,nEndRow, nTab, 0, aProv.GetDevice(), + aProv.GetPPTX(),aProv.GetPPTY(), aZoom,aZoom, FALSE ); + if (bChange) + PostPaint( 0,nStartRow,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID|PAINT_LEFT ); + + return bChange; +} + +void ScDocShell::UpdateAllRowHeights( const ScMarkData* pTabMark ) +{ + // update automatic row heights + + ScSizeDeviceProvider aProv(this); + Fraction aZoom(1,1); + aDocument.UpdateAllRowHeights( aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), aZoom, aZoom, pTabMark ); +} + +void ScDocShell::UpdatePendingRowHeights( SCTAB nUpdateTab, bool bBefore ) +{ + BOOL bIsUndoEnabled = aDocument.IsUndoEnabled(); + aDocument.EnableUndo( FALSE ); + aDocument.LockStreamValid( true ); // ignore draw page size (but not formula results) + if ( bBefore ) // check all sheets up to nUpdateTab + { + SCTAB nTabCount = aDocument.GetTableCount(); + if ( nUpdateTab >= nTabCount ) + nUpdateTab = nTabCount-1; // nUpdateTab is inclusive + + ScMarkData aUpdateSheets; + SCTAB nTab; + for (nTab=0; nTab<=nUpdateTab; ++nTab) + if ( aDocument.IsPendingRowHeights( nTab ) ) + aUpdateSheets.SelectTable( nTab, TRUE ); + + if (aUpdateSheets.GetSelectCount()) + UpdateAllRowHeights(&aUpdateSheets); // update with a single progress bar + + for (nTab=0; nTab<=nUpdateTab; ++nTab) + if ( aUpdateSheets.GetTableSelect( nTab ) ) + { + aDocument.UpdatePageBreaks( nTab ); + aDocument.SetPendingRowHeights( nTab, FALSE ); + } + } + else // only nUpdateTab + { + if ( aDocument.IsPendingRowHeights( nUpdateTab ) ) + { + AdjustRowHeight( 0, MAXROW, nUpdateTab ); + aDocument.UpdatePageBreaks( nUpdateTab ); + aDocument.SetPendingRowHeights( nUpdateTab, FALSE ); + } + } + aDocument.LockStreamValid( false ); + aDocument.EnableUndo( bIsUndoEnabled ); +} + +void ScDocShell::RefreshPivotTables( const ScRange& rSource ) +{ + //! rename to RefreshDataPilotTables? + + ScDPCollection* pColl = aDocument.GetDPCollection(); + if ( pColl ) + { + // DataPilotUpdate doesn't modify the collection order like PivotUpdate did, + // so a simple loop can be used. + + USHORT nCount = pColl->GetCount(); + for ( USHORT i=0; i<nCount; i++ ) + { + ScDPObject* pOld = (*pColl)[i]; + if ( pOld ) + { + const ScSheetSourceDesc* pSheetDesc = pOld->GetSheetDesc(); + if ( pSheetDesc && pSheetDesc->aSourceRange.Intersects( rSource ) ) + { + ScDPObject* pNew = new ScDPObject( *pOld ); + ScDBDocFunc aFunc( *this ); + aFunc.DataPilotUpdate( pOld, pNew, TRUE, FALSE ); + delete pNew; // DataPilotUpdate copies settings from "new" object + } + } + } + } +} + +String lcl_GetAreaName( ScDocument* pDoc, ScArea* pArea ) +{ + String aName; + BOOL bOk = FALSE; + ScDBData* pData = pDoc->GetDBAtArea( pArea->nTab, pArea->nColStart, pArea->nRowStart, + pArea->nColEnd, pArea->nRowEnd ); + if (pData) + { + pData->GetName( aName ); + if ( aName != ScGlobal::GetRscString( STR_DB_NONAME ) ) + bOk = TRUE; + } + + if (!bOk) + pDoc->GetName( pArea->nTab, aName ); + + return aName; +} + +void ScDocShell::DoConsolidate( const ScConsolidateParam& rParam, BOOL bRecord ) +{ + ScConsData aData; + + USHORT nPos; + SCCOL nColSize = 0; + SCROW nRowSize = 0; + BOOL bErr = FALSE; + for (nPos=0; nPos<rParam.nDataAreaCount; nPos++) + { + ScArea* pArea = rParam.ppDataAreas[nPos]; + nColSize = Max( nColSize, SCCOL( pArea->nColEnd - pArea->nColStart + 1 ) ); + nRowSize = Max( nRowSize, SCROW( pArea->nRowEnd - pArea->nRowStart + 1 ) ); + + // Test, ob Quelldaten verschoben wuerden + if (rParam.bReferenceData) + if (pArea->nTab == rParam.nTab && pArea->nRowEnd >= rParam.nRow) + bErr = TRUE; + } + + if (bErr) + { + InfoBox aBox( GetActiveDialogParent(), + ScGlobal::GetRscString( STR_CONSOLIDATE_ERR1 ) ); + aBox.Execute(); + return; + } + + // ausfuehren + + WaitObject aWait( GetActiveDialogParent() ); + ScDocShellModificator aModificator( *this ); + + ScRange aOldDest; + ScDBData* pDestData = aDocument.GetDBAtCursor( rParam.nCol, rParam.nRow, rParam.nTab, TRUE ); + if (pDestData) + pDestData->GetArea(aOldDest); + + aData.SetSize( nColSize, nRowSize ); + aData.SetFlags( rParam.eFunction, rParam.bByCol, rParam.bByRow, rParam.bReferenceData ); + if ( rParam.bByCol || rParam.bByRow ) + for (nPos=0; nPos<rParam.nDataAreaCount; nPos++) + { + ScArea* pArea = rParam.ppDataAreas[nPos]; + aData.AddFields( &aDocument, pArea->nTab, pArea->nColStart, pArea->nRowStart, + pArea->nColEnd, pArea->nRowEnd ); + } + aData.DoneFields(); + for (nPos=0; nPos<rParam.nDataAreaCount; nPos++) + { + ScArea* pArea = rParam.ppDataAreas[nPos]; + aData.AddData( &aDocument, pArea->nTab, pArea->nColStart, pArea->nRowStart, + pArea->nColEnd, pArea->nRowEnd ); + aData.AddName( lcl_GetAreaName(&aDocument,pArea) ); + } + + aData.GetSize( nColSize, nRowSize ); + if (bRecord && nColSize > 0 && nRowSize > 0) + { + ScDBData* pUndoData = pDestData ? new ScDBData(*pDestData) : NULL; + + SCTAB nDestTab = rParam.nTab; + ScArea aDestArea( rParam.nTab, rParam.nCol, rParam.nRow, + rParam.nCol+nColSize-1, rParam.nRow+nRowSize-1 ); + if (rParam.bByCol) ++aDestArea.nColEnd; + if (rParam.bByRow) ++aDestArea.nRowEnd; + + if (rParam.bReferenceData) + { + SCTAB nTabCount = aDocument.GetTableCount(); + SCROW nInsertCount = aData.GetInsertCount(); + + // alte Outlines + ScOutlineTable* pTable = aDocument.GetOutlineTable( nDestTab ); + ScOutlineTable* pUndoTab = pTable ? new ScOutlineTable( *pTable ) : NULL; + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( &aDocument, 0, nTabCount-1, FALSE, TRUE ); + + // Zeilenstatus + aDocument.CopyToDocument( 0,0,nDestTab, MAXCOL,MAXROW,nDestTab, + IDF_NONE, FALSE, pUndoDoc ); + + // alle Formeln + aDocument.CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, + IDF_FORMULA, FALSE, pUndoDoc ); + + // komplette Ausgangszeilen + aDocument.CopyToDocument( 0,aDestArea.nRowStart,nDestTab, + MAXCOL,aDestArea.nRowEnd,nDestTab, + IDF_ALL, FALSE, pUndoDoc ); + + // alten Ausgabebereich + if (pDestData) + aDocument.CopyToDocument( aOldDest, IDF_ALL, FALSE, pUndoDoc ); + + GetUndoManager()->AddUndoAction( + new ScUndoConsolidate( this, aDestArea, rParam, pUndoDoc, + TRUE, nInsertCount, pUndoTab, pUndoData ) ); + } + else + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( &aDocument, aDestArea.nTab, aDestArea.nTab ); + + aDocument.CopyToDocument( aDestArea.nColStart, aDestArea.nRowStart, aDestArea.nTab, + aDestArea.nColEnd, aDestArea.nRowEnd, aDestArea.nTab, + IDF_ALL, FALSE, pUndoDoc ); + + // alten Ausgabebereich + if (pDestData) + aDocument.CopyToDocument( aOldDest, IDF_ALL, FALSE, pUndoDoc ); + + GetUndoManager()->AddUndoAction( + new ScUndoConsolidate( this, aDestArea, rParam, pUndoDoc, + FALSE, 0, NULL, pUndoData ) ); + } + } + + if (pDestData) // Zielbereich loeschen / anpassen + { + aDocument.DeleteAreaTab(aOldDest, IDF_CONTENTS); + pDestData->SetArea( rParam.nTab, rParam.nCol, rParam.nRow, + rParam.nCol + nColSize - 1, rParam.nRow + nRowSize - 1 ); + pDestData->SetHeader( rParam.bByRow ); + } + + aData.OutputToDocument( &aDocument, rParam.nCol, rParam.nRow, rParam.nTab ); + + SCCOL nPaintStartCol = rParam.nCol; + SCROW nPaintStartRow = rParam.nRow; + SCCOL nPaintEndCol = nPaintStartCol + nColSize - 1; + SCROW nPaintEndRow = nPaintStartRow + nRowSize - 1; + USHORT nPaintFlags = PAINT_GRID; + if (rParam.bByCol) + ++nPaintEndRow; + if (rParam.bByRow) + ++nPaintEndCol; + if (rParam.bReferenceData) + { + nPaintStartCol = 0; + nPaintEndCol = MAXCOL; + nPaintEndRow = MAXROW; + nPaintFlags |= PAINT_LEFT | PAINT_SIZE; + } + if (pDestData) + { + if ( aOldDest.aEnd.Col() > nPaintEndCol ) + nPaintEndCol = aOldDest.aEnd.Col(); + if ( aOldDest.aEnd.Row() > nPaintEndRow ) + nPaintEndRow = aOldDest.aEnd.Row(); + } + PostPaint( nPaintStartCol, nPaintStartRow, rParam.nTab, + nPaintEndCol, nPaintEndRow, rParam.nTab, nPaintFlags ); + aModificator.SetDocumentModified(); +} + +void ScDocShell::UseScenario( SCTAB nTab, const String& rName, BOOL bRecord ) +{ + if (!aDocument.IsScenario(nTab)) + { + SCTAB nTabCount = aDocument.GetTableCount(); + SCTAB nSrcTab = SCTAB_MAX; + SCTAB nEndTab = nTab; + String aCompare; + while ( nEndTab+1 < nTabCount && aDocument.IsScenario(nEndTab+1) ) + { + ++nEndTab; + if (nSrcTab > MAXTAB) // noch auf der Suche nach dem Szenario? + { + aDocument.GetName( nEndTab, aCompare ); + if (aCompare == rName) + nSrcTab = nEndTab; // gefunden + } + } + if (ValidTab(nSrcTab)) + { + if ( aDocument.TestCopyScenario( nSrcTab, nTab ) ) // Zellschutz testen + { + ScDocShellModificator aModificator( *this ); + ScMarkData aScenMark; + aDocument.MarkScenario( nSrcTab, nTab, aScenMark ); + ScRange aMultiRange; + aScenMark.GetMultiMarkArea( aMultiRange ); + SCCOL nStartCol = aMultiRange.aStart.Col(); + SCROW nStartRow = aMultiRange.aStart.Row(); + SCCOL nEndCol = aMultiRange.aEnd.Col(); + SCROW nEndRow = aMultiRange.aEnd.Row(); + + if (bRecord) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( &aDocument, nTab,nEndTab ); // auch alle Szenarien + // angezeigte Tabelle: + aDocument.CopyToDocument( nStartCol,nStartRow,nTab, + nEndCol,nEndRow,nTab, IDF_ALL,TRUE, pUndoDoc, &aScenMark ); + // Szenarien + for (SCTAB i=nTab+1; i<=nEndTab; i++) + { + pUndoDoc->SetScenario( i, TRUE ); + String aComment; + Color aColor; + USHORT nScenFlags; + aDocument.GetScenarioData( i, aComment, aColor, nScenFlags ); + pUndoDoc->SetScenarioData( i, aComment, aColor, nScenFlags ); + BOOL bActive = aDocument.IsActiveScenario( i ); + pUndoDoc->SetActiveScenario( i, bActive ); + // Bei Zurueckkopier-Szenarios auch Inhalte + if ( nScenFlags & SC_SCENARIO_TWOWAY ) + aDocument.CopyToDocument( 0,0,i, MAXCOL,MAXROW,i, + IDF_ALL,FALSE, pUndoDoc ); + } + + GetUndoManager()->AddUndoAction( + new ScUndoUseScenario( this, aScenMark, + ScArea( nTab,nStartCol,nStartRow,nEndCol,nEndRow ), + pUndoDoc, rName ) ); + } + + aDocument.CopyScenario( nSrcTab, nTab ); + aDocument.SetDirty(); + + // alles painten, weil in anderen Bereichen das aktive Szenario + // geaendert sein kann + //! nur, wenn sichtbare Rahmen vorhanden? + PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID ); + aModificator.SetDocumentModified(); + } + else + { + InfoBox aBox(GetActiveDialogParent(), + ScGlobal::GetRscString( STR_PROTECTIONERR ) ); + aBox.Execute(); + } + } + else + { + InfoBox aBox(GetActiveDialogParent(), + ScGlobal::GetRscString( STR_SCENARIO_NOTFOUND ) ); + aBox.Execute(); + } + } + else + { + DBG_ERROR( "UseScenario auf Szenario-Blatt" ); + } +} + +void ScDocShell::ModifyScenario( SCTAB nTab, const String& rName, const String& rComment, + const Color& rColor, USHORT nFlags ) +{ + // Undo + String aOldName; + aDocument.GetName( nTab, aOldName ); + String aOldComment; + Color aOldColor; + USHORT nOldFlags; + aDocument.GetScenarioData( nTab, aOldComment, aOldColor, nOldFlags ); + GetUndoManager()->AddUndoAction( + new ScUndoScenarioFlags( this, nTab, + aOldName, rName, aOldComment, rComment, + aOldColor, rColor, nOldFlags, nFlags ) ); + + // ausfuehren + ScDocShellModificator aModificator( *this ); + aDocument.RenameTab( nTab, rName ); + aDocument.SetScenarioData( nTab, rComment, rColor, nFlags ); + PostPaintGridAll(); + aModificator.SetDocumentModified(); + + if ( rName != aOldName ) + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + + SfxBindings* pBindings = GetViewBindings(); + if (pBindings) + pBindings->Invalidate( SID_SELECT_SCENARIO ); +} + +SCTAB ScDocShell::MakeScenario( SCTAB nTab, const String& rName, const String& rComment, + const Color& rColor, USHORT nFlags, + ScMarkData& rMark, BOOL bRecord ) +{ + rMark.MarkToMulti(); + if (rMark.IsMultiMarked()) + { + SCTAB nNewTab = nTab + 1; + while (aDocument.IsScenario(nNewTab)) + ++nNewTab; + + BOOL bCopyAll = ( (nFlags & SC_SCENARIO_COPYALL) != 0 ); + const ScMarkData* pCopyMark = NULL; + if (!bCopyAll) + pCopyMark = &rMark; + + ScDocShellModificator aModificator( *this ); + + if (bRecord) + aDocument.BeginDrawUndo(); // drawing layer must do its own undo actions + + if (aDocument.CopyTab( nTab, nNewTab, pCopyMark )) + { + if (bRecord) + { + GetUndoManager()->AddUndoAction( + new ScUndoMakeScenario( this, nTab, nNewTab, + rName, rComment, rColor, nFlags, rMark )); + } + + aDocument.RenameTab( nNewTab, rName, FALSE ); // ohne Formel-Update + aDocument.SetScenario( nNewTab, TRUE ); + aDocument.SetScenarioData( nNewTab, rComment, rColor, nFlags ); + + ScMarkData aDestMark = rMark; + aDestMark.SelectOneTable( nNewTab ); + + //! auf Filter / Buttons / Merging testen ! + + ScPatternAttr aProtPattern( aDocument.GetPool() ); + aProtPattern.GetItemSet().Put( ScProtectionAttr( TRUE ) ); + aDocument.ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nNewTab, aProtPattern ); + + ScPatternAttr aPattern( aDocument.GetPool() ); + aPattern.GetItemSet().Put( ScMergeFlagAttr( SC_MF_SCENARIO ) ); + aPattern.GetItemSet().Put( ScProtectionAttr( TRUE ) ); + aDocument.ApplySelectionPattern( aPattern, aDestMark ); + + if (!bCopyAll) + aDocument.SetVisible( nNewTab, FALSE ); + + // dies ist dann das aktive Szenario + aDocument.CopyScenario( nNewTab, nTab, TRUE ); // TRUE - nicht aus Szenario kopieren + + if (nFlags & SC_SCENARIO_SHOWFRAME) + PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID ); // Rahmen painten + PostPaintExtras(); // Tabellenreiter + aModificator.SetDocumentModified(); + + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + + return nNewTab; + } + } + return nTab; +} + +BOOL ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, BOOL bCopy, BOOL bRecord ) +{ + ScDocShellModificator aModificator( *this ); + + // #i92477# be consistent with ScDocFunc::InsertTable: any index past the last sheet means "append" + // #i101139# nDestTab must be the target position, not APPEND (for CopyTabProtection etc.) + if ( nDestTab >= aDocument.GetTableCount() ) + nDestTab = aDocument.GetTableCount(); + + if (bCopy) + { + if (bRecord) + aDocument.BeginDrawUndo(); // drawing layer must do its own undo actions + + if (!aDocument.CopyTab( nSrcTab, nDestTab )) + { + //! EndDrawUndo? + return FALSE; + } + else + { + SCTAB nAdjSource = nSrcTab; + if ( nDestTab <= nSrcTab ) + ++nAdjSource; // new position of source table after CopyTab + + if ( aDocument.IsTabProtected( nAdjSource ) ) + aDocument.CopyTabProtection(nAdjSource, nDestTab); + + if (bRecord) + { + SvShorts aSrcList; + SvShorts aDestList; + aSrcList.Insert(nSrcTab,0); + aDestList.Insert(nDestTab,0); + GetUndoManager()->AddUndoAction( + new ScUndoCopyTab( this, aSrcList, aDestList ) ); + } + } + + Broadcast( ScTablesHint( SC_TAB_COPIED, nSrcTab, nDestTab ) ); + } + else + { + if ( aDocument.GetChangeTrack() ) + return FALSE; + + if ( nSrcTab<nDestTab && nDestTab!=SC_TAB_APPEND ) + nDestTab--; + + if ( nSrcTab == nDestTab ) + { + //! allow only for api calls? + return TRUE; // nothing to do, but valid + } + + if (!aDocument.MoveTab( nSrcTab, nDestTab )) + return FALSE; + else if (bRecord) + { + SvShorts aSrcList; + SvShorts aDestList; + aSrcList.Insert(nSrcTab,0); + aDestList.Insert(nDestTab,0); + GetUndoManager()->AddUndoAction( + new ScUndoMoveTab( this, aSrcList, aDestList ) ); + } + + Broadcast( ScTablesHint( SC_TAB_MOVED, nSrcTab, nDestTab ) ); + } + + PostPaintGridAll(); + PostPaintExtras(); + aModificator.SetDocumentModified(); + SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) ); + + return TRUE; +} + + +IMPL_LINK( ScDocShell, RefreshDBDataHdl, ScRefreshTimer*, pRefreshTimer ) +{ + ScDBDocFunc aFunc(*this); + + BOOL bContinue = TRUE; + ScDBData* pDBData = static_cast<ScDBData*>(pRefreshTimer); + ScImportParam aImportParam; + pDBData->GetImportParam( aImportParam ); + if (aImportParam.bImport && !pDBData->HasImportSelection()) + { + ScRange aRange; + pDBData->GetArea( aRange ); + ::com::sun::star::uno::Reference< ::com::sun::star::sdbc::XResultSet> xResultSet; + bContinue = aFunc.DoImport( aRange.aStart.Tab(), aImportParam, xResultSet, NULL, TRUE, FALSE ); //! Api-Flag as parameter + // internal operations (sort, query, subtotal) only if no error + if (bContinue) + { + aFunc.RepeatDB( pDBData->GetName(), TRUE, TRUE ); + RefreshPivotTables(aRange); + } + } + + return bContinue != 0; +} + diff --git a/sc/source/ui/docshell/docsh6.cxx b/sc/source/ui/docshell/docsh6.cxx new file mode 100644 index 000000000000..fbb6dc8ead35 --- /dev/null +++ b/sc/source/ui/docshell/docsh6.cxx @@ -0,0 +1,469 @@ +/************************************************************************* + * + * 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" + +// System - Includes ----------------------------------------------------- + + + +#ifndef PCH +#include "scitems.hxx" + +#include <svx/pageitem.hxx> +#include <vcl/virdev.hxx> +#include <sfx2/linkmgr.hxx> +#endif + +// INCLUDE --------------------------------------------------------------- + +//#include <svxlink.hxx> + +#include "docsh.hxx" + +#include "stlsheet.hxx" +#include "stlpool.hxx" +#include "global.hxx" +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "tablink.hxx" +#include "collect.hxx" + +struct ScStylePair +{ + SfxStyleSheetBase *pSource; + SfxStyleSheetBase *pDest; +}; + + +// STATIC DATA ----------------------------------------------------------- + +//---------------------------------------------------------------------- + +// +// Ole +// + +void __EXPORT ScDocShell::SetVisArea( const Rectangle & rVisArea ) +{ + // with the SnapVisArea call in SetVisAreaOrSize, it's safe to always + // use both the size and position of the VisArea + SetVisAreaOrSize( rVisArea, TRUE ); +} + +void lcl_SetTopRight( Rectangle& rRect, const Point& rPos ) +{ + Size aSize = rRect.GetSize(); + rRect.Right() = rPos.X(); + rRect.Left() = rPos.X() - aSize.Width() + 1; + rRect.Top() = rPos.Y(); + rRect.Bottom() = rPos.Y() + aSize.Height() - 1; +} + +void ScDocShell::SetVisAreaOrSize( const Rectangle& rVisArea, BOOL bModifyStart ) +{ + BOOL bNegativePage = aDocument.IsNegativePage( aDocument.GetVisibleTab() ); + + Rectangle aArea = rVisArea; + if (bModifyStart) + { + // when loading, don't check for negative values, because the sheet orientation + // might be set later + if ( !aDocument.IsImportingXML() ) + { + if ( ( bNegativePage ? (aArea.Right() > 0) : (aArea.Left() < 0) ) || aArea.Top() < 0 ) + { + // VisArea start position can't be negative. + // Move the VisArea, otherwise only the upper left position would + // be changed in SnapVisArea, and the size would be wrong. + + Point aNewPos( 0, Max( aArea.Top(), (long) 0 ) ); + if ( bNegativePage ) + { + aNewPos.X() = Min( aArea.Right(), (long) 0 ); + lcl_SetTopRight( aArea, aNewPos ); + } + else + { + aNewPos.X() = Max( aArea.Left(), (long) 0 ); + aArea.SetPos( aNewPos ); + } + } + } + } + else + { + Rectangle aOldVisArea = SfxObjectShell::GetVisArea(); + if ( bNegativePage ) + lcl_SetTopRight( aArea, aOldVisArea.TopRight() ); + else + aArea.SetPos( aOldVisArea.TopLeft() ); + } + + // hier Position anpassen! + + // #92248# when loading an ole object, the VisArea is set from the document's + // view settings and must be used as-is (document content may not be complete yet). + if ( !aDocument.IsImportingXML() ) + aDocument.SnapVisArea( aArea ); + + //TODO/LATER: it's unclear which IPEnv is used here + /* + SvInPlaceEnvironment* pEnv = GetIPEnv(); + if (pEnv) + { + Window* pWin = pEnv->GetEditWin(); + pEnv->MakeScale( aArea.GetSize(), MAP_100TH_MM, + pWin->LogicToPixel( aArea.GetSize() ) ); + } */ + + //TODO/LATER: formerly in SvInplaceObject + SfxObjectShell::SetVisArea( aArea ); + + if (bIsInplace) // Zoom in der InPlace View einstellen + { + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if (pViewSh) + { + if (pViewSh->GetViewData()->GetDocShell() == this) + pViewSh->UpdateOleZoom(); + } + //else + // DataChanged( SvDataType() ); // fuer Zuppeln wenn nicht IP-aktiv + } + + if (aDocument.IsEmbedded()) + { + ScRange aOld; + aDocument.GetEmbedded( aOld); + aDocument.SetEmbedded( aArea ); + ScRange aNew; + aDocument.GetEmbedded( aNew); + if (aOld != aNew) + PostPaint(0,0,0,MAXCOL,MAXROW,MAXTAB,PAINT_GRID); + + //TODO/LATER: currently not implemented + //ViewChanged( ASPECT_CONTENT ); // auch im Container anzeigen + } +} + +BOOL ScDocShell::IsOle() +{ + return (GetCreateMode() == SFX_CREATE_MODE_EMBEDDED); +} + +void ScDocShell::UpdateOle( const ScViewData* pViewData, BOOL bSnapSize ) +{ + // wenn's gar nicht Ole ist, kann man sich die Berechnungen sparen + // (VisArea wird dann beim Save wieder zurueckgesetzt) + + if (GetCreateMode() == SFX_CREATE_MODE_STANDARD) + return; + + DBG_ASSERT(pViewData,"pViewData==0 bei ScDocShell::UpdateOle"); + + Rectangle aOldArea = SfxObjectShell::GetVisArea(); + Rectangle aNewArea = aOldArea; + + BOOL bChange = FALSE; + BOOL bEmbedded = aDocument.IsEmbedded(); + if (bEmbedded) + aNewArea = aDocument.GetEmbeddedRect(); + else + { + SCTAB nTab = pViewData->GetTabNo(); + if ( nTab != aDocument.GetVisibleTab() ) + { + aDocument.SetVisibleTab( nTab ); + bChange = TRUE; + } + + BOOL bNegativePage = aDocument.IsNegativePage( nTab ); + SCCOL nX = pViewData->GetPosX(SC_SPLIT_LEFT); + SCROW nY = pViewData->GetPosY(SC_SPLIT_BOTTOM); + Rectangle aMMRect = aDocument.GetMMRect( nX,nY, nX,nY, nTab ); + if (bNegativePage) + lcl_SetTopRight( aNewArea, aMMRect.TopRight() ); + else + aNewArea.SetPos( aMMRect.TopLeft() ); + if (bSnapSize) + aDocument.SnapVisArea(aNewArea); // uses the new VisibleTab + } + + if (aNewArea != aOldArea) + { + SetVisAreaOrSize( aNewArea, TRUE ); // hier muss auch der Start angepasst werden + bChange = TRUE; + } + +// if (bChange) +// DataChanged( SvDataType() ); //! passiert auch bei SetModified +} + +// +// Style-Krempel fuer Organizer etc. +// + +SfxStyleSheetBasePool* __EXPORT ScDocShell::GetStyleSheetPool() +{ + return (SfxStyleSheetBasePool*)aDocument.GetStyleSheetPool(); +} + + +// nach dem Laden von Vorlagen aus einem anderen Dokment (LoadStyles, Insert) +// muessen die SetItems (ATTR_PAGE_HEADERSET, ATTR_PAGE_FOOTERSET) auf den richtigen +// Pool umgesetzt werden, bevor der Quell-Pool geloescht wird. + +void lcl_AdjustPool( SfxStyleSheetBasePool* pStylePool ) +{ + pStylePool->SetSearchMask(SFX_STYLE_FAMILY_PAGE, 0xffff); + SfxStyleSheetBase *pStyle = pStylePool->First(); + while ( pStyle ) + { + SfxItemSet& rStyleSet = pStyle->GetItemSet(); + + const SfxPoolItem* pItem; + if (rStyleSet.GetItemState(ATTR_PAGE_HEADERSET,FALSE,&pItem) == SFX_ITEM_SET) + { + SfxItemSet& rSrcSet = ((SvxSetItem*)pItem)->GetItemSet(); + SfxItemSet* pDestSet = new SfxItemSet(*rStyleSet.GetPool(),rSrcSet.GetRanges()); + pDestSet->Put(rSrcSet); + rStyleSet.Put(SvxSetItem(ATTR_PAGE_HEADERSET,pDestSet)); + } + if (rStyleSet.GetItemState(ATTR_PAGE_FOOTERSET,FALSE,&pItem) == SFX_ITEM_SET) + { + SfxItemSet& rSrcSet = ((SvxSetItem*)pItem)->GetItemSet(); + SfxItemSet* pDestSet = new SfxItemSet(*rStyleSet.GetPool(),rSrcSet.GetRanges()); + pDestSet->Put(rSrcSet); + rStyleSet.Put(SvxSetItem(ATTR_PAGE_FOOTERSET,pDestSet)); + } + + pStyle = pStylePool->Next(); + } +} + +void __EXPORT ScDocShell::LoadStyles( SfxObjectShell &rSource ) +{ + aDocument.StylesToNames(); + + SfxObjectShell::LoadStyles(rSource); + lcl_AdjustPool( GetStyleSheetPool() ); // SetItems anpassen + + aDocument.UpdStlShtPtrsFrmNms(); + + UpdateAllRowHeights(); + + // Paint + + PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID | PAINT_LEFT ); +} + +void ScDocShell::LoadStylesArgs( ScDocShell& rSource, BOOL bReplace, BOOL bCellStyles, BOOL bPageStyles ) +{ + // similar to LoadStyles, but with selectable behavior for XStyleLoader::loadStylesFromURL call + + if ( !bCellStyles && !bPageStyles ) // nothing to do + return; + + ScStyleSheetPool* pSourcePool = rSource.GetDocument()->GetStyleSheetPool(); + ScStyleSheetPool* pDestPool = aDocument.GetStyleSheetPool(); + + SfxStyleFamily eFamily = bCellStyles ? + ( bPageStyles ? SFX_STYLE_FAMILY_ALL : SFX_STYLE_FAMILY_PARA ) : + SFX_STYLE_FAMILY_PAGE; + SfxStyleSheetIterator aIter( pSourcePool, eFamily ); + USHORT nSourceCount = aIter.Count(); + if ( nSourceCount == 0 ) + return; // no source styles + + ScStylePair* pStyles = new ScStylePair[ nSourceCount ]; + USHORT nFound = 0; + + // first create all new styles + + SfxStyleSheetBase* pSourceStyle = aIter.First(); + while (pSourceStyle) + { + String aName = pSourceStyle->GetName(); + SfxStyleSheetBase* pDestStyle = pDestPool->Find( pSourceStyle->GetName(), pSourceStyle->GetFamily() ); + if ( pDestStyle ) + { + // touch existing styles only if replace flag is set + if ( bReplace ) + { + pStyles[nFound].pSource = pSourceStyle; + pStyles[nFound].pDest = pDestStyle; + ++nFound; + } + } + else + { + pStyles[nFound].pSource = pSourceStyle; + pStyles[nFound].pDest = &pDestPool->Make( aName, pSourceStyle->GetFamily(), pSourceStyle->GetMask() ); + ++nFound; + } + + pSourceStyle = aIter.Next(); + } + + // then copy contents (after inserting all styles, for parent etc.) + + for ( USHORT i = 0; i < nFound; ++i ) + { + pStyles[i].pDest->GetItemSet().PutExtended( + pStyles[i].pSource->GetItemSet(), SFX_ITEM_DONTCARE, SFX_ITEM_DEFAULT); + if(pStyles[i].pSource->HasParentSupport()) + pStyles[i].pDest->SetParent(pStyles[i].pSource->GetParent()); + // follow is never used + } + + lcl_AdjustPool( GetStyleSheetPool() ); // adjust SetItems + UpdateAllRowHeights(); + PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID | PAINT_LEFT ); // Paint + + delete[] pStyles; +} + + +BOOL __EXPORT ScDocShell::Insert( SfxObjectShell &rSource, + USHORT nSourceIdx1, USHORT nSourceIdx2, USHORT nSourceIdx3, + USHORT &nIdx1, USHORT &nIdx2, USHORT &nIdx3, USHORT &rIdxDeleted ) +{ + BOOL bRet = SfxObjectShell::Insert( rSource, nSourceIdx1, nSourceIdx2, nSourceIdx3, + nIdx1, nIdx2, nIdx3, rIdxDeleted ); + if (bRet) + lcl_AdjustPool( GetStyleSheetPool() ); // SetItems anpassen + + return bRet; +} + +void ScDocShell::UpdateLinks() +{ + sfx2::LinkManager* pLinkManager = aDocument.GetLinkManager(); + ScStrCollection aNames; + + // nicht mehr benutzte Links raus + + USHORT nCount = pLinkManager->GetLinks().Count(); + for (USHORT k=nCount; k>0; ) + { + --k; + ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[k]; + if (pBase->ISA(ScTableLink)) + { + ScTableLink* pTabLink = (ScTableLink*)pBase; + if (pTabLink->IsUsed()) + { + StrData* pData = new StrData(pTabLink->GetFileName()); + if (!aNames.Insert(pData)) + delete pData; + } + else // nicht mehr benutzt -> loeschen + { + pTabLink->SetAddUndo(TRUE); + pLinkManager->Remove(k); + } + } + } + + + // neue Links eintragen + + SCTAB nTabCount = aDocument.GetTableCount(); + for (SCTAB i=0; i<nTabCount; i++) + if (aDocument.IsLinked(i)) + { + String aDocName = aDocument.GetLinkDoc(i); + String aFltName = aDocument.GetLinkFlt(i); + String aOptions = aDocument.GetLinkOpt(i); + ULONG nRefresh = aDocument.GetLinkRefreshDelay(i); + BOOL bThere = FALSE; + for (SCTAB j=0; j<i && !bThere; j++) // im Dokument mehrfach? + if (aDocument.IsLinked(j) + && aDocument.GetLinkDoc(j) == aDocName + && aDocument.GetLinkFlt(j) == aFltName + && aDocument.GetLinkOpt(j) == aOptions) + // Ignore refresh delay in compare, it should be the + // same for identical links and we don't want dupes + // if it ain't. + bThere = TRUE; + + if (!bThere) // schon als Filter eingetragen? + { + StrData* pData = new StrData(aDocName); + if (!aNames.Insert(pData)) + { + delete pData; + bThere = TRUE; + } + } + if (!bThere) + { + ScTableLink* pLink = new ScTableLink( this, aDocName, aFltName, aOptions, nRefresh ); + pLink->SetInCreate( TRUE ); + pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, aDocName, &aFltName ); + pLink->Update(); + pLink->SetInCreate( FALSE ); + } + } +} + +BOOL ScDocShell::ReloadTabLinks() +{ + sfx2::LinkManager* pLinkManager = aDocument.GetLinkManager(); + + BOOL bAny = FALSE; + USHORT nCount = pLinkManager->GetLinks().Count(); + for (USHORT i=0; i<nCount; i++ ) + { + ::sfx2::SvBaseLink* pBase = *pLinkManager->GetLinks()[i]; + if (pBase->ISA(ScTableLink)) + { + ScTableLink* pTabLink = (ScTableLink*)pBase; +// pTabLink->SetAddUndo(FALSE); //! Undo's zusammenfassen + pTabLink->SetPaint(FALSE); // Paint nur einmal am Ende + pTabLink->Update(); + pTabLink->SetPaint(TRUE); +// pTabLink->SetAddUndo(TRUE); + bAny = TRUE; + } + } + + if ( bAny ) + { + // Paint nur einmal + PostPaint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), + PAINT_GRID | PAINT_TOP | PAINT_LEFT ); + + SetDocumentModified(); + } + + return TRUE; //! Fehler erkennen +} + + diff --git a/sc/source/ui/docshell/docsh7.cxx b/sc/source/ui/docshell/docsh7.cxx new file mode 100644 index 000000000000..89f082672b29 --- /dev/null +++ b/sc/source/ui/docshell/docsh7.cxx @@ -0,0 +1,45 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------- + +#include "docsh.hxx" + +//------------------------------------------------------------------ + +void ScDocShell::GetDrawObjState( SfxItemSet & /* rSet */ ) +{ + // SID_SC_ACTIVEOBJECT (SelectedObject) - removed (old Basic) +} + + + diff --git a/sc/source/ui/docshell/docsh8.cxx b/sc/source/ui/docshell/docsh8.cxx new file mode 100644 index 000000000000..b761dd75d9df --- /dev/null +++ b/sc/source/ui/docshell/docsh8.cxx @@ -0,0 +1,1098 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <stdio.h> +#include <tools/urlobj.hxx> +#include <svl/converter.hxx> +#include <svl/zforlist.hxx> +#include <comphelper/types.hxx> +#include <ucbhelper/content.hxx> +#include <unotools/sharedunocomponent.hxx> +#include <comphelper/processfactory.hxx> +#include <svx/txenctab.hxx> +#include <svx/dbcharsethelper.hxx> + +#include <com/sun/star/sdb/CommandType.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XConnection.hpp> +#include <com/sun/star/sdbc/XDriver.hpp> +#include <com/sun/star/sdbc/XDriverAccess.hpp> +#include <com/sun/star/sdbc/XDriverManager.hpp> +#include <com/sun/star/sdbc/XResultSetUpdate.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/sdbc/XRowSet.hpp> +#include <com/sun/star/sdbc/XRowUpdate.hpp> +#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp> +#include <com/sun/star/sdbcx/XAppend.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp> +#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp> +#include <com/sun/star/sdbcx/XTablesSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> + +#include "scerrors.hxx" +#include "docsh.hxx" +#include "filter.hxx" +#include "progress.hxx" +#include "collect.hxx" +#include "cell.hxx" +#include "editutil.hxx" +#include "cellform.hxx" +#include "dbdocutl.hxx" +#include "dociter.hxx" +#include "globstr.hrc" + +using namespace com::sun::star; + +// ----------------------------------------------------------------------- + +#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet" +#define SC_SERVICE_DRVMAN "com.sun.star.sdbc.DriverManager" + +//! move to a header file? +//#define SC_DBPROP_DATASOURCENAME "DataSourceName" +#define SC_DBPROP_ACTIVECONNECTION "ActiveConnection" +#define SC_DBPROP_COMMAND "Command" +#define SC_DBPROP_COMMANDTYPE "CommandType" + +#define SC_DBPROP_NAME "Name" +#define SC_DBPROP_TYPE "Type" +#define SC_DBPROP_PRECISION "Precision" +#define SC_DBPROP_SCALE "Scale" + +#define SC_DBPROP_EXTENSION "Extension" +#define SC_DBPROP_CHARSET "CharSet" + +#define SC_ROWCOUNT_ERROR (-1) + +namespace +{ + ULONG lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager>& _rDrvMgr,uno::Reference<sdbc::XConnection>& _rConnection,String& _rTabName,const String& rFullFileName,rtl_TextEncoding eCharSet) + { + INetURLObject aURL; + aURL.SetSmartProtocol( INET_PROT_FILE ); + aURL.SetSmartURL( rFullFileName ); + _rTabName = aURL.getBase( INetURLObject::LAST_SEGMENT, true, + INetURLObject::DECODE_UNAMBIGUOUS ); + String aExtension = aURL.getExtension(); + aURL.removeSegment(); + aURL.removeFinalSlash(); + String aPath = aURL.GetMainURL(INetURLObject::NO_DECODE); + uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory(); + if (!xFactory.is()) return SCERR_EXPORT_CONNECT; + + _rDrvMgr.set( xFactory->createInstance( + rtl::OUString::createFromAscii( SC_SERVICE_DRVMAN ) ), + uno::UNO_QUERY); + DBG_ASSERT( _rDrvMgr.is(), "can't get DriverManager" ); + if (!_rDrvMgr.is()) return SCERR_EXPORT_CONNECT; + + // get connection + + String aConnUrl = String::CreateFromAscii("sdbc:dbase:"); + aConnUrl += aPath; + + svxform::ODataAccessCharsetHelper aHelper; + ::std::vector< rtl_TextEncoding > aEncodings; + aHelper.getSupportedTextEncodings( aEncodings ); + ::std::vector< rtl_TextEncoding >::iterator aIter = ::std::find(aEncodings.begin(),aEncodings.end(),(rtl_TextEncoding) eCharSet); + if ( aIter == aEncodings.end() ) + { + DBG_ERRORFILE( "DBaseImport: dbtools::OCharsetMap doesn't know text encoding" ); + return SCERR_IMPORT_CONNECT; + } // if ( aIter == aMap.end() ) + rtl::OUString aCharSetStr; + if ( RTL_TEXTENCODING_DONTKNOW != *aIter ) + { // it's not the virtual "system charset" + const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( *aIter ); + OSL_ENSURE( pIanaName, "invalid mime name!" ); + if ( pIanaName ) + aCharSetStr = ::rtl::OUString::createFromAscii( pIanaName ); + } + + uno::Sequence<beans::PropertyValue> aProps(2); + aProps[0].Name = rtl::OUString::createFromAscii(SC_DBPROP_EXTENSION); + aProps[0].Value <<= rtl::OUString( aExtension ); + aProps[1].Name = rtl::OUString::createFromAscii(SC_DBPROP_CHARSET); + aProps[1].Value <<= aCharSetStr; + + _rConnection = _rDrvMgr->getConnectionWithInfo( aConnUrl, aProps ); + return 0L; + } +} +// ----------------------------------------------------------------------- +// MoveFile/KillFile/IsDocument: similar to SfxContentHelper + +// static +BOOL ScDocShell::MoveFile( const INetURLObject& rSourceObj, const INetURLObject& rDestObj ) +{ + sal_Bool bMoveData = sal_True; + sal_Bool bRet = sal_True, bKillSource = sal_False; + if ( rSourceObj.GetProtocol() != rDestObj.GetProtocol() ) + { + bMoveData = sal_False; + bKillSource = sal_True; + } + String aName = rDestObj.getName(); + INetURLObject aDestPathObj = rDestObj; + aDestPathObj.removeSegment(); + aDestPathObj.setFinalSlash(); + + try + { + ::ucbhelper::Content aDestPath( aDestPathObj.GetMainURL(INetURLObject::NO_DECODE), + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + uno::Reference< ::com::sun::star::ucb::XCommandInfo > xInfo = aDestPath.getCommands(); + rtl::OUString aTransferName = rtl::OUString::createFromAscii( "transfer" ); + if ( xInfo->hasCommandByName( aTransferName ) ) + { + aDestPath.executeCommand( aTransferName, uno::makeAny( + ::com::sun::star::ucb::TransferInfo( bMoveData, rSourceObj.GetMainURL(INetURLObject::NO_DECODE), aName, + ::com::sun::star::ucb::NameClash::ERROR ) ) ); + } + else + { + DBG_ERRORFILE( "transfer command not available" ); + } + } + catch( uno::Exception& ) + { + // ucb may throw different exceptions on failure now + bRet = sal_False; + } + + if ( bKillSource ) + KillFile( rSourceObj ); + + return bRet; +} + + +// static +BOOL ScDocShell::KillFile( const INetURLObject& rURL ) +{ + sal_Bool bRet = sal_True; + try + { + ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE), + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + aCnt.executeCommand( rtl::OUString::createFromAscii( "delete" ), + comphelper::makeBoolAny( sal_True ) ); + } + catch( uno::Exception& ) + { + // ucb may throw different exceptions on failure now + bRet = sal_False; + } + + return bRet; +} + +// static +BOOL ScDocShell::IsDocument( const INetURLObject& rURL ) +{ + sal_Bool bRet = sal_False; + try + { + ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE), + uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () ); + bRet = aCnt.isDocument(); + } + catch( uno::Exception& ) + { + // ucb may throw different exceptions on failure now - warning only + DBG_WARNING( "Any other exception" ); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +ULONG ScDocShell::DBaseImport( const String& rFullFileName, CharSet eCharSet, + BOOL bSimpleColWidth[MAXCOLCOUNT] ) +{ + ULONG nErr = eERR_OK; + long i; + + try + { + String aTabName; + uno::Reference<sdbc::XDriverManager> xDrvMan; + uno::Reference<sdbc::XConnection> xConnection; + ULONG nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet); + if ( !xConnection.is() || !xDrvMan.is() ) + return nRet; + ::utl::DisposableComponent aConnectionHelper(xConnection); + + long nRowCount = 0; + if ( nRowCount < 0 ) + { + DBG_ERROR("can't get row count"); + nRowCount = 0; + } + + ScProgress aProgress( this, ScGlobal::GetRscString( STR_LOAD_DOC ), nRowCount ); + uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory(); + uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance( + rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ), + uno::UNO_QUERY); + ::utl::DisposableComponent aRowSetHelper(xRowSet); + uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRowProp.is(), "can't get RowSet" ); + if (!xRowProp.is()) return SCERR_IMPORT_CONNECT; + + sal_Int32 nType = sdb::CommandType::TABLE; + uno::Any aAny; + + aAny <<= xConnection; + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_ACTIVECONNECTION), aAny ); + + aAny <<= nType; + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMANDTYPE), aAny ); + + aAny <<= rtl::OUString( aTabName ); + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMAND), aAny ); + + xRowSet->execute(); + + long nColCount = 0; + uno::Reference<sdbc::XResultSetMetaData> xMeta; + uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY ); + if ( xMetaSupp.is() ) + xMeta = xMetaSupp->getMetaData(); + if ( xMeta.is() ) + nColCount = xMeta->getColumnCount(); // this is the number of real columns + + if ( nColCount > MAXCOL+1 ) + { + nColCount = MAXCOL+1; + nErr = SCWARN_IMPORT_RANGE_OVERFLOW; // warning + } + + if ( nColCount > 0 ) + aDocument.DoColResize( 0, 0, static_cast<SCCOL>(nColCount) - 1, + static_cast<SCSIZE>(nRowCount) + 1 ); + + uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRow.is(), "can't get Row" ); + if (!xRow.is()) return SCERR_IMPORT_CONNECT; + + // currency flag is not needed for dBase + uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types + sal_Int32* pTypeArr = aColTypes.getArray(); + for (i=0; i<nColCount; i++) + pTypeArr[i] = xMeta->getColumnType( i+1 ); + + // read column names + //! add type descriptions + + for (i=0; i<nColCount; i++) + { + String aHeader = xMeta->getColumnLabel( i+1 ); + + switch ( pTypeArr[i] ) + { + case sdbc::DataType::BIT: + aHeader.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",L" )); + break; + case sdbc::DataType::DATE: + aHeader.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",D" )); + break; + case sdbc::DataType::LONGVARCHAR: + aHeader.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",M" )); + break; + case sdbc::DataType::VARCHAR: + aHeader.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",C," )); + aHeader += String::CreateFromInt32( xMeta->getColumnDisplaySize( i+1 ) ); + break; + case sdbc::DataType::DECIMAL: + { + long nPrec = xMeta->getPrecision( i+1 ); + long nScale = xMeta->getScale( i+1 ); + aHeader.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",N," )); + aHeader += String::CreateFromInt32( + SvDbaseConverter::ConvertPrecisionToDbase( + nPrec, nScale ) ); + aHeader += ','; + aHeader += String::CreateFromInt32( nScale ); + } + break; + } + + aDocument.SetString( static_cast<SCCOL>(i), 0, 0, aHeader ); + } + + SCROW nRow = 1; // 0 is column titles + BOOL bEnd = FALSE; + while ( !bEnd && xRowSet->next() ) + { + if ( nRow <= MAXROW ) + { + SCCOL nCol = 0; + for (i=0; i<nColCount; i++) + { + ScDatabaseDocUtil::PutData( &aDocument, nCol, nRow, 0, + xRow, i+1, pTypeArr[i], FALSE, + &bSimpleColWidth[nCol] ); + ++nCol; + } + ++nRow; + } + else // past the end of the spreadsheet + { + bEnd = TRUE; // don't continue + nErr = SCWARN_IMPORT_RANGE_OVERFLOW; // warning message + } + + if ( nRowCount ) + aProgress.SetStateOnPercent( nRow ); + } + } + catch ( sdbc::SQLException& ) + { + nErr = SCERR_IMPORT_CONNECT; + } + catch ( uno::Exception& ) + { + DBG_ERROR("Unexpected exception in database"); + nErr = ERRCODE_IO_GENERAL; + } + + return nErr; +} + +// ----------------------------------------------------------------------- + +inline sal_Bool IsAsciiDigit( sal_Unicode c ) +{ + return 0x30 <= c && c <= 0x39; +} + +inline sal_Bool IsAsciiAlpha( sal_Unicode c ) +{ + return (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a); +} + +void lcl_GetColumnTypes( ScDocShell& rDocShell, + const ScRange& rDataRange, BOOL bHasFieldNames, + rtl::OUString* pColNames, sal_Int32* pColTypes, + sal_Int32* pColLengths, sal_Int32* pColScales, + BOOL& bHasMemo, CharSet eCharSet ) +{ + // updating of column titles didn't work in 5.2 and isn't always wanted + // (saving normally shouldn't modify the document) + //! read flag from configuration + BOOL bUpdateTitles = FALSE; + + ScDocument* pDoc = rDocShell.GetDocument(); + SvNumberFormatter* pNumFmt = pDoc->GetFormatTable(); + + SCTAB nTab = rDataRange.aStart.Tab(); + SCCOL nFirstCol = rDataRange.aStart.Col(); + SCROW nFirstRow = rDataRange.aStart.Row(); + SCCOL nLastCol = rDataRange.aEnd.Col(); + SCROW nLastRow = rDataRange.aEnd.Row(); + + ScStrCollection aFieldNamesCollection; + + long nField = 0; + SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow ); + for ( SCCOL nCol = nFirstCol; nCol <= nLastCol; nCol++ ) + { + BOOL bTypeDefined = FALSE; + BOOL bPrecDefined = FALSE; + sal_Int32 nFieldLen = 0; + sal_Int32 nPrecision = 0; + sal_Int32 nDbType = sdbc::DataType::SQLNULL; + String aFieldName, aString; + + // Feldname[,Type[,Width[,Prec]]] + // Typ etc.: L; D; C[,W]; N[,W[,P]] + if ( bHasFieldNames ) + { + pDoc->GetString( nCol, nFirstRow, nTab, aString ); + aString.ToUpperAscii(); + xub_StrLen nToken = aString.GetTokenCount( ',' ); + if ( nToken > 1 ) + { + aFieldName = aString.GetToken( 0, ',' ); + aString.EraseAllChars( ' ' ); + switch ( aString.GetToken( 1, ',' ).GetChar(0) ) + { + case 'L' : + nDbType = sdbc::DataType::BIT; + nFieldLen = 1; + bTypeDefined = TRUE; + bPrecDefined = TRUE; + break; + case 'D' : + nDbType = sdbc::DataType::DATE; + nFieldLen = 8; + bTypeDefined = TRUE; + bPrecDefined = TRUE; + break; + case 'M' : + nDbType = sdbc::DataType::LONGVARCHAR; + nFieldLen = 10; + bTypeDefined = TRUE; + bPrecDefined = TRUE; + bHasMemo = TRUE; + break; + case 'C' : + nDbType = sdbc::DataType::VARCHAR; + bTypeDefined = TRUE; + bPrecDefined = TRUE; + break; + case 'N' : + nDbType = sdbc::DataType::DECIMAL; + bTypeDefined = TRUE; + break; + } + if ( bTypeDefined && !nFieldLen && nToken > 2 ) + { + nFieldLen = aString.GetToken( 2, ',' ).ToInt32(); + if ( !bPrecDefined && nToken > 3 ) + { + String aTmp( aString.GetToken( 3, ',' ) ); + if ( CharClass::isAsciiNumeric(aTmp) ) + { + nPrecision = aTmp.ToInt32(); + bPrecDefined = TRUE; + } + } + } + } + else + aFieldName = aString; + + // Feldnamen pruefen und ggbf. gueltigen Feldnamen erzeugen. + // Erstes Zeichen muss Buchstabe sein, + // weitere nur alphanumerisch und Unterstrich erlaubt, + // "_DBASELOCK" ist reserviert (obsolet weil erstes Zeichen kein Buchstabe), + // keine doppelten Namen. + if ( !IsAsciiAlpha( aFieldName.GetChar(0) ) ) + aFieldName.Insert( 'N', 0 ); + String aTmpStr; + sal_Unicode c; + for ( const sal_Unicode* p = aFieldName.GetBuffer(); ( c = *p ) != 0; p++ ) + { + if ( IsAsciiAlpha( c ) || IsAsciiDigit( c ) || c == '_' ) + aTmpStr += c; + else + aTmpStr += '_'; + } + aFieldName = aTmpStr; + if ( aFieldName.Len() > 10 ) + aFieldName.Erase( 10 ); + StrData* pStrData = new StrData( aFieldName ); + if ( !aFieldNamesCollection.Insert( pStrData ) ) + { // doppelter Feldname, numerisch erweitern + USHORT nSub = 1; + String aFixPart( aFieldName ); + do + { + ++nSub; + String aVarPart = String::CreateFromInt32( nSub ); + if ( aFixPart.Len() + aVarPart.Len() > 10 ) + aFixPart.Erase( 10 - aVarPart.Len() ); + aFieldName = aFixPart; + aFieldName += aVarPart; + pStrData->SetString( aFieldName ); + } while ( !aFieldNamesCollection.Insert( pStrData ) ); + } + } + else + { + aFieldName = 'N'; + aFieldName += String::CreateFromInt32(nCol+1); + } + + if ( !bTypeDefined ) + { // Feldtyp + ScBaseCell* pCell; + pDoc->GetCell( nCol, nFirstDataRow, nTab, pCell ); + if ( !pCell || pCell->HasStringData() ) + nDbType = sdbc::DataType::VARCHAR; + else + { + sal_uInt32 nFormat; + pDoc->GetNumberFormat( nCol, nFirstDataRow, nTab, nFormat ); + if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA + && ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) ) + { + nFormat = ScGlobal::GetStandardFormat( + ((ScFormulaCell*)pCell)->GetValue(), *pNumFmt, nFormat, + ((ScFormulaCell*)pCell)->GetFormatType() ); + } + switch ( pNumFmt->GetType( nFormat ) ) + { + case NUMBERFORMAT_LOGICAL : + nDbType = sdbc::DataType::BIT; + nFieldLen = 1; + break; + case NUMBERFORMAT_DATE : + nDbType = sdbc::DataType::DATE; + nFieldLen = 8; + break; + case NUMBERFORMAT_TIME : + case NUMBERFORMAT_DATETIME : + nDbType = sdbc::DataType::VARCHAR; + break; + default: + nDbType = sdbc::DataType::DECIMAL; + } + } + } + BOOL bSdbLenAdjusted = FALSE; + BOOL bSdbLenBad = FALSE; + // Feldlaenge + if ( nDbType == sdbc::DataType::VARCHAR && !nFieldLen ) + { // maximale Feldbreite bestimmen + nFieldLen = pDoc->GetMaxStringLen( nTab, nCol, nFirstDataRow, + nLastRow, eCharSet ); + if ( nFieldLen == 0 ) + nFieldLen = 1; + } + else if ( nDbType == sdbc::DataType::DECIMAL ) + { // maximale Feldbreite und Nachkommastellen bestimmen + xub_StrLen nLen; + USHORT nPrec; + nLen = pDoc->GetMaxNumberStringLen( nPrec, nTab, nCol, + nFirstDataRow, nLastRow ); + // dBaseIII Limit Nachkommastellen: 15 + if ( nPrecision > 15 ) + nPrecision = 15; + if ( nPrec > 15 ) + nPrec = 15; + if ( bPrecDefined && nPrecision != nPrec ) + { // Laenge auf vorgegebene Nachkommastellen anpassen + if ( nPrecision ) + nLen = sal::static_int_cast<xub_StrLen>( nLen + ( nPrecision - nPrec ) ); + else + nLen -= nPrec+1; // auch den . mit raus + } + if ( nLen > nFieldLen && !bTypeDefined ) + nFieldLen = nLen; + if ( !bPrecDefined ) + nPrecision = nPrec; + if ( nFieldLen == 0 ) + nFieldLen = 1; + else if ( nFieldLen > 19 ) + nFieldLen = 19; // dBaseIII Limit Feldlaenge numerisch: 19 + if ( nPrecision && nFieldLen < nPrecision + 2 ) + nFieldLen = nPrecision + 2; // 0. muss mit reinpassen + // 538 MUST: Sdb internal representation adds 2 to the field length! + // To give the user what he wants we must substract it here. + //! CAVEAT! There is no way to define a numeric field with a length + //! of 1 and no decimals! + if ( nFieldLen == 1 && nPrecision == 0 ) + bSdbLenBad = TRUE; + nFieldLen = SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen, nPrecision ); + bSdbLenAdjusted = TRUE; + } + if ( nFieldLen > 254 ) + { + if ( nDbType == sdbc::DataType::VARCHAR ) + { // zu lang fuer normales Textfeld => Memofeld + nDbType = sdbc::DataType::LONGVARCHAR; + nFieldLen = 10; + bHasMemo = TRUE; + } + else + nFieldLen = 254; // dumm gelaufen.. + } + + pColNames[nField] = aFieldName; + pColTypes[nField] = nDbType; + pColLengths[nField] = nFieldLen; + pColScales[nField] = nPrecision; + + // undo change to field length, reflect reality + if ( bSdbLenAdjusted ) + { + nFieldLen = SvDbaseConverter::ConvertPrecisionToDbase( nFieldLen, nPrecision ); + if ( bSdbLenBad && nFieldLen == 1 ) + nFieldLen = 2; // THIS is reality + } + if ( bUpdateTitles ) + { // Angabe anpassen und ausgeben + String aOutString = aFieldName; + switch ( nDbType ) + { + case sdbc::DataType::BIT : + aOutString.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",L" )); + break; + case sdbc::DataType::DATE : + aOutString.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",D" )); + break; + case sdbc::DataType::LONGVARCHAR : + aOutString.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",M" )); + break; + case sdbc::DataType::VARCHAR : + aOutString.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",C," )); + aOutString += String::CreateFromInt32( nFieldLen ); + break; + case sdbc::DataType::DECIMAL : + aOutString.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ",N," )); + aOutString += String::CreateFromInt32( nFieldLen ); + aOutString += ','; + aOutString += String::CreateFromInt32( nPrecision ); + break; + } + if ( !aOutString.EqualsIgnoreCaseAscii( aString ) ) + { + pDoc->SetString( nCol, nFirstRow, nTab, aOutString ); + rDocShell.PostPaint( nCol, nFirstRow, nTab, nCol, nFirstRow, nTab, PAINT_GRID ); + } + } + ++nField; + } +} + + +inline void lcl_getLongVarCharEditString( String& rString, + const ScBaseCell* pCell, ScFieldEditEngine& rEditEngine ) +{ + rEditEngine.SetText( *((const ScEditCell*)pCell)->GetData() ); + rString = rEditEngine.GetText( LINEEND_CRLF ); +} + +inline void lcl_getLongVarCharString( String& rString, ScBaseCell* pCell, + ScDocument& rDocument, SCCOL nCol, SCROW nRow, SCTAB nTab, + SvNumberFormatter& rNumFmt ) +{ + sal_uInt32 nFormat; + Color* pColor; + rDocument.GetNumberFormat( nCol, nRow, nTab, nFormat ); + ScCellFormat::GetString( pCell, nFormat, rString, &pColor, rNumFmt ); +} + + +ULONG ScDocShell::DBaseExport( const String& rFullFileName, CharSet eCharSet, BOOL& bHasMemo ) +{ + // remove the file so the dBase driver doesn't find an invalid file + INetURLObject aDeleteObj( rFullFileName, INET_PROT_FILE ); + KillFile( aDeleteObj ); + + ULONG nErr = eERR_OK; + uno::Any aAny; + + SCCOL nFirstCol, nLastCol; + SCROW nFirstRow, nLastRow; + SCTAB nTab = GetSaveTab(); + aDocument.GetDataStart( nTab, nFirstCol, nFirstRow ); + aDocument.GetCellArea( nTab, nLastCol, nLastRow ); + if ( nFirstCol > nLastCol ) + nFirstCol = nLastCol; + if ( nFirstRow > nLastRow ) + nFirstRow = nLastRow; + ScProgress aProgress( this, ScGlobal::GetRscString( STR_SAVE_DOC ), + nLastRow - nFirstRow ); + SvNumberFormatter* pNumFmt = aDocument.GetFormatTable(); + + BOOL bHasFieldNames = TRUE; + for ( SCCOL nDocCol = nFirstCol; nDocCol <= nLastCol && bHasFieldNames; nDocCol++ ) + { // nur Strings in erster Zeile => sind Feldnamen + if ( !aDocument.HasStringData( nDocCol, nFirstRow, nTab ) ) + bHasFieldNames = FALSE; + } + + long nColCount = nLastCol - nFirstCol + 1; + uno::Sequence<rtl::OUString> aColNames( nColCount ); + uno::Sequence<sal_Int32> aColTypes( nColCount ); + uno::Sequence<sal_Int32> aColLengths( nColCount ); + uno::Sequence<sal_Int32> aColScales( nColCount ); + + ScRange aDataRange( nFirstCol, nFirstRow, nTab, nLastCol, nLastRow, nTab ); + lcl_GetColumnTypes( *this, aDataRange, bHasFieldNames, + aColNames.getArray(), aColTypes.getArray(), + aColLengths.getArray(), aColScales.getArray(), + bHasMemo, eCharSet ); + // also needed for exception catch + SCROW nDocRow = 0; + ScFieldEditEngine aEditEngine( aDocument.GetEditPool() ); + String aString; + String aTabName; + + try + { + uno::Reference<sdbc::XDriverManager> xDrvMan; + uno::Reference<sdbc::XConnection> xConnection; + ULONG nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet); + if ( !xConnection.is() || !xDrvMan.is() ) + return nRet; + ::utl::DisposableComponent aConnectionHelper(xConnection); + + // get dBase driver + uno::Reference< sdbc::XDriverAccess> xAccess(xDrvMan,uno::UNO_QUERY); + uno::Reference< sdbcx::XDataDefinitionSupplier > xDDSup( xAccess->getDriverByURL( xConnection->getMetaData()->getURL() ), uno::UNO_QUERY ); + if ( !xDDSup.is() ) + return SCERR_EXPORT_CONNECT; + + // create table + uno::Reference<sdbcx::XTablesSupplier> xTablesSupp =xDDSup->getDataDefinitionByConnection( xConnection ); + DBG_ASSERT( xTablesSupp.is(), "can't get Data Definition" ); + if (!xTablesSupp.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<container::XNameAccess> xTables = xTablesSupp->getTables(); + DBG_ASSERT( xTables.is(), "can't get Tables" ); + if (!xTables.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<sdbcx::XDataDescriptorFactory> xTablesFact( xTables, uno::UNO_QUERY ); + DBG_ASSERT( xTablesFact.is(), "can't get tables factory" ); + if (!xTablesFact.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<sdbcx::XAppend> xTablesAppend( xTables, uno::UNO_QUERY ); + DBG_ASSERT( xTablesAppend.is(), "can't get tables XAppend" ); + if (!xTablesAppend.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<beans::XPropertySet> xTableDesc = xTablesFact->createDataDescriptor(); + DBG_ASSERT( xTableDesc.is(), "can't get table descriptor" ); + if (!xTableDesc.is()) return SCERR_EXPORT_CONNECT; + + aAny <<= rtl::OUString( aTabName ); + xTableDesc->setPropertyValue( rtl::OUString::createFromAscii(SC_DBPROP_NAME), aAny ); + + // create columns + + uno::Reference<sdbcx::XColumnsSupplier> xColumnsSupp( xTableDesc, uno::UNO_QUERY ); + DBG_ASSERT( xColumnsSupp.is(), "can't get columns supplier" ); + if (!xColumnsSupp.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<container::XNameAccess> xColumns = xColumnsSupp->getColumns(); + DBG_ASSERT( xColumns.is(), "can't get columns" ); + if (!xColumns.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<sdbcx::XDataDescriptorFactory> xColumnsFact( xColumns, uno::UNO_QUERY ); + DBG_ASSERT( xColumnsFact.is(), "can't get columns factory" ); + if (!xColumnsFact.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<sdbcx::XAppend> xColumnsAppend( xColumns, uno::UNO_QUERY ); + DBG_ASSERT( xColumnsAppend.is(), "can't get columns XAppend" ); + if (!xColumnsAppend.is()) return SCERR_EXPORT_CONNECT; + + const rtl::OUString* pColNames = aColNames.getConstArray(); + const sal_Int32* pColTypes = aColTypes.getConstArray(); + const sal_Int32* pColLengths = aColLengths.getConstArray(); + const sal_Int32* pColScales = aColScales.getConstArray(); + long nCol; + + for (nCol=0; nCol<nColCount; nCol++) + { + uno::Reference<beans::XPropertySet> xColumnDesc = xColumnsFact->createDataDescriptor(); + DBG_ASSERT( xColumnDesc.is(), "can't get column descriptor" ); + if (!xColumnDesc.is()) return SCERR_EXPORT_CONNECT; + + aAny <<= pColNames[nCol]; + xColumnDesc->setPropertyValue( rtl::OUString::createFromAscii(SC_DBPROP_NAME), aAny ); + + aAny <<= pColTypes[nCol]; + xColumnDesc->setPropertyValue( rtl::OUString::createFromAscii(SC_DBPROP_TYPE), aAny ); + + aAny <<= pColLengths[nCol]; + xColumnDesc->setPropertyValue( rtl::OUString::createFromAscii(SC_DBPROP_PRECISION), aAny ); + + aAny <<= pColScales[nCol]; + xColumnDesc->setPropertyValue( rtl::OUString::createFromAscii(SC_DBPROP_SCALE), aAny ); + + xColumnsAppend->appendByDescriptor( xColumnDesc ); + } + + xTablesAppend->appendByDescriptor( xTableDesc ); + + // re-open connection +// xConnection = xDrvMan->getConnectionWithInfo( aConnUrl, aProps ); +// DBG_ASSERT( xConnection.is(), "can't get Connection" ); +// if (!xConnection.is()) return SCERR_EXPORT_CONNECT; + + // get row set for writing + uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory(); + uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance( + rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ), + uno::UNO_QUERY); + ::utl::DisposableComponent aRowSetHelper(xRowSet); + uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRowProp.is(), "can't get RowSet" ); + if (!xRowProp.is()) return SCERR_EXPORT_CONNECT; + + aAny <<= xConnection; + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_ACTIVECONNECTION), aAny ); + + aAny <<= (sal_Int32) sdb::CommandType::TABLE; + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMANDTYPE), aAny ); + + aAny <<= rtl::OUString( aTabName ); + xRowProp->setPropertyValue( + rtl::OUString::createFromAscii(SC_DBPROP_COMMAND), aAny ); + + xRowSet->execute(); + + // write data rows + + uno::Reference<sdbc::XResultSetUpdate> xResultUpdate( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xResultUpdate.is(), "can't get XResultSetUpdate" ); + if (!xResultUpdate.is()) return SCERR_EXPORT_CONNECT; + + uno::Reference<sdbc::XRowUpdate> xRowUpdate( xRowSet, uno::UNO_QUERY ); + DBG_ASSERT( xRowUpdate.is(), "can't get XRowUpdate" ); + if (!xRowUpdate.is()) return SCERR_EXPORT_CONNECT; + + SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow ); + double fVal; + + for ( nDocRow = nFirstDataRow; nDocRow <= nLastRow; nDocRow++ ) + { + xResultUpdate->moveToInsertRow(); + + for (nCol=0; nCol<nColCount; nCol++) + { + SCCOL nDocCol = sal::static_int_cast<SCCOL>( nFirstCol + nCol ); + + switch (pColTypes[nCol]) + { + case sdbc::DataType::LONGVARCHAR: + { + ScBaseCell* pCell; + aDocument.GetCell( nDocCol, nDocRow, nTab, pCell ); + if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) + { + if ( pCell->GetCellType() == CELLTYPE_EDIT ) + { // #60761# Paragraphs erhalten + lcl_getLongVarCharEditString( aString, + pCell, aEditEngine); + } + else + { + lcl_getLongVarCharString( aString, pCell, + aDocument, nDocCol, nDocRow, nTab, + *pNumFmt); + } + xRowUpdate->updateString( nCol+1, aString ); + } + else + xRowUpdate->updateNull( nCol+1 ); + } + break; + + case sdbc::DataType::VARCHAR: + aDocument.GetString( nDocCol, nDocRow, nTab, aString ); + xRowUpdate->updateString( nCol+1, aString ); + if ( nErr == eERR_OK && pColLengths[nCol] < aString.Len() ) + nErr = SCWARN_EXPORT_DATALOST; + break; + + case sdbc::DataType::DATE: + { + aDocument.GetValue( nDocCol, nDocRow, nTab, fVal ); + // #39274# zwischen 0 Wert und 0 kein Wert unterscheiden + BOOL bIsNull = (fVal == 0.0); + if ( bIsNull ) + bIsNull = !aDocument.HasValueData( nDocCol, nDocRow, nTab ); + if ( bIsNull ) + { + xRowUpdate->updateNull( nCol+1 ); + if ( nErr == eERR_OK && + aDocument.HasStringData( nDocCol, nDocRow, nTab ) ) + nErr = SCWARN_EXPORT_DATALOST; + } + else + { + Date aDate = *(pNumFmt->GetNullDate()); // tools date + aDate += (long)fVal; //! approxfloor? + util::Date aUnoDate( aDate.GetDay(), aDate.GetMonth(), aDate.GetYear() ); + xRowUpdate->updateDate( nCol+1, aUnoDate ); + } + } + break; + + case sdbc::DataType::DECIMAL: + case sdbc::DataType::BIT: + aDocument.GetValue( nDocCol, nDocRow, nTab, fVal ); + if ( fVal == 0.0 && nErr == eERR_OK && + aDocument.HasStringData( nDocCol, nDocRow, nTab ) ) + nErr = SCWARN_EXPORT_DATALOST; + if ( pColTypes[nCol] == sdbc::DataType::BIT ) + xRowUpdate->updateBoolean( nCol+1, ( fVal != 0.0 ) ); + else + xRowUpdate->updateDouble( nCol+1, fVal ); + break; + + default: + DBG_ERROR( "ScDocShell::DBaseExport: unknown FieldType" ); + if ( nErr == eERR_OK ) + nErr = SCWARN_EXPORT_DATALOST; + aDocument.GetValue( nDocCol, nDocRow, nTab, fVal ); + xRowUpdate->updateDouble( nCol+1, fVal ); + } + } + + xResultUpdate->insertRow(); + + //! error handling and recovery of old + //! ScDocShell::SbaSdbExport is still missing! + + if ( !aProgress.SetStateOnPercent( nDocRow - nFirstRow ) ) + { // UserBreak + nErr = SCERR_EXPORT_DATA; + break; + } + } + + comphelper::disposeComponent( xRowSet ); + comphelper::disposeComponent( xConnection ); + } + catch ( sdbc::SQLException& aException ) + { + sal_Int32 nError = aException.ErrorCode; +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "ScDocShell::DBaseExport: SQLException ErrorCode: %d, SQLState: %s, Message: %s\n", + (int)nError, OUStringToOString( aException.SQLState, + RTL_TEXTENCODING_UTF8).getStr(), OUStringToOString( + aException.Message, RTL_TEXTENCODING_UTF8).getStr()); +#endif + if (nError == 22018 || nError == 22001) + { + // SQL error 22018: Character not in target encoding. + // SQL error 22001: String length exceeds field width (after encoding). + bool bEncErr = (nError == 22018); + bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet); + DBG_ASSERT( !bEncErr || bIsOctetTextEncoding, "ScDocShell::DBaseExport: encoding error and not an octect textencoding"); + SCCOL nDocCol = nFirstCol; + const sal_Int32* pColTypes = aColTypes.getConstArray(); + const sal_Int32* pColLengths = aColLengths.getConstArray(); + ScHorizontalCellIterator aIter( &aDocument, nTab, nFirstCol, + nDocRow, nLastCol, nDocRow); + ScBaseCell* pCell = NULL; + bool bTest = true; + while (bTest && ((pCell = aIter.GetNext( nDocCol, nDocRow)) != NULL)) + { + SCCOL nCol = nDocCol - nFirstCol; + switch (pColTypes[nCol]) + { + case sdbc::DataType::LONGVARCHAR: + { + if ( pCell->GetCellType() != CELLTYPE_NOTE ) + { + if ( pCell->GetCellType() == CELLTYPE_EDIT ) + lcl_getLongVarCharEditString( aString, + pCell, aEditEngine); + else + lcl_getLongVarCharString( aString, + pCell, aDocument, nDocCol, + nDocRow, nTab, *pNumFmt); + } + } + break; + + case sdbc::DataType::VARCHAR: + aDocument.GetString( nDocCol, nDocRow, nTab, aString); + break; + + // NOTE: length of DECIMAL fields doesn't need to be + // checked here, the database driver adjusts the field + // width accordingly. + + default: + bTest = false; + } + if (bTest) + { + sal_Int32 nLen; + if (bIsOctetTextEncoding) + { + rtl::OUString aOUString( aString); + rtl::OString aOString; + if (!aOUString.convertToString( &aOString, eCharSet, + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | + RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)) + { + bTest = false; + bEncErr = true; + } + nLen = aOString.getLength(); +#if OSL_DEBUG_LEVEL > 1 + if (!bTest) + fprintf( stderr, "ScDocShell::DBaseExport encoding error, string with default replacements: ``%s''\n", + OUStringToOString( aOUString, eCharSet).getStr()); +#endif + } + else + nLen = aString.Len() * sizeof(sal_Unicode); + if (!bEncErr && + pColTypes[nCol] != sdbc::DataType::LONGVARCHAR && + pColLengths[nCol] < nLen) + { + bTest = false; +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "ScDocShell::DBaseExport: field width: %d, encoded length: %d\n", + (int)pColLengths[nCol], (int)nLen); +#endif + } + } + else + bTest = true; + } + String sPosition( ScAddress( nDocCol, nDocRow, nTab).GetColRowString()); + String sEncoding( SvxTextEncodingTable().GetTextString( eCharSet)); + nErr = *new TwoStringErrorInfo( (bEncErr ? SCERR_EXPORT_ENCODING : + SCERR_EXPORT_FIELDWIDTH), sPosition, sEncoding, + ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR); + } + else if ( aException.Message.getLength() ) + nErr = *new StringErrorInfo( (SCERR_EXPORT_SQLEXCEPTION), aException.Message, ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR); + else + nErr = SCERR_EXPORT_DATA; + } + catch ( uno::Exception& ) + { + DBG_ERROR("Unexpected exception in database"); + nErr = ERRCODE_IO_GENERAL; + } + + return nErr; +} + + diff --git a/sc/source/ui/docshell/docshimp.hxx b/sc/source/ui/docshell/docshimp.hxx new file mode 100644 index 000000000000..6532c46d0835 --- /dev/null +++ b/sc/source/ui/docshell/docshimp.hxx @@ -0,0 +1,57 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ +#ifndef SC_DOCSHELLIMP_HXX +#define SC_DOCSHELLIMP_HXX + +#include <svtools/ctrltool.hxx> +#include <sfx2/docinsert.hxx> +#include <sfx2/request.hxx> + +struct DocShell_Impl +{ + bool bIgnoreLostRedliningWarning; + FontList* pFontList; + sfx2::DocumentInserter* pDocInserter; + SfxRequest* pRequest; + + DocShell_Impl() : + bIgnoreLostRedliningWarning( false ) + , pFontList( NULL ) + , pDocInserter( NULL ) + , pRequest( NULL ) + {} + + ~DocShell_Impl() + { + delete pFontList; + delete pDocInserter; + delete pRequest; + } +}; + +#endif + diff --git a/sc/source/ui/docshell/editable.cxx b/sc/source/ui/docshell/editable.cxx new file mode 100644 index 000000000000..d381ff067a99 --- /dev/null +++ b/sc/source/ui/docshell/editable.cxx @@ -0,0 +1,162 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include "editable.hxx" +#include "document.hxx" +#include "viewfunc.hxx" +#include "globstr.hrc" + +//------------------------------------------------------------------ + +ScEditableTester::ScEditableTester() : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ +} + +ScEditableTester::ScEditableTester( ScDocument* pDoc, SCTAB nTab, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ + TestBlock( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow ); +} + +ScEditableTester::ScEditableTester( ScDocument* pDoc, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, + const ScMarkData& rMark ) : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ + TestSelectedBlock( pDoc, nStartCol, nStartRow, nEndCol, nEndRow, rMark ); +} + +ScEditableTester::ScEditableTester( ScDocument* pDoc, const ScRange& rRange ) : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ + TestRange( pDoc, rRange ); +} + +ScEditableTester::ScEditableTester( ScDocument* pDoc, const ScMarkData& rMark ) : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ + TestSelection( pDoc, rMark ); +} + +ScEditableTester::ScEditableTester( ScViewFunc* pView ) : + bIsEditable( TRUE ), + bOnlyMatrix( TRUE ) +{ + TestView( pView ); +} + +//------------------------------------------------------------------ + +void ScEditableTester::TestBlock( ScDocument* pDoc, SCTAB nTab, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) +{ + if ( bIsEditable || bOnlyMatrix ) + { + BOOL bThisMatrix; + if ( !pDoc->IsBlockEditable( nTab, nStartCol, nStartRow, nEndCol, nEndRow, &bThisMatrix ) ) + { + bIsEditable = FALSE; + if ( !bThisMatrix ) + bOnlyMatrix = FALSE; + } + } +} + +void ScEditableTester::TestSelectedBlock( ScDocument* pDoc, + SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, + const ScMarkData& rMark ) +{ + SCTAB nTabCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nTabCount; nTab++) + if (rMark.GetTableSelect(nTab)) + TestBlock( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow ); +} + +void ScEditableTester::TestRange( ScDocument* pDoc, const ScRange& rRange ) +{ + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCTAB nStartTab = rRange.aStart.Tab(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nEndTab = rRange.aEnd.Tab(); + for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++) + TestBlock( pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow ); +} + +void ScEditableTester::TestSelection( ScDocument* pDoc, const ScMarkData& rMark ) +{ + if ( bIsEditable || bOnlyMatrix ) + { + BOOL bThisMatrix; + if ( !pDoc->IsSelectionEditable( rMark, &bThisMatrix ) ) + { + bIsEditable = FALSE; + if ( !bThisMatrix ) + bOnlyMatrix = FALSE; + } + } +} + +void ScEditableTester::TestView( ScViewFunc* pView ) +{ + if ( bIsEditable || bOnlyMatrix ) + { + BOOL bThisMatrix; + if ( !pView->SelectionEditable( &bThisMatrix ) ) + { + bIsEditable = FALSE; + if ( !bThisMatrix ) + bOnlyMatrix = FALSE; + } + } +} + +//------------------------------------------------------------------ + +USHORT ScEditableTester::GetMessageId() const +{ + if (bIsEditable) + return 0; + else if (bOnlyMatrix) + return STR_MATRIXFRAGMENTERR; + else + return STR_PROTECTIONERR; +} + diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx new file mode 100644 index 000000000000..836d6cdf98e6 --- /dev/null +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -0,0 +1,2378 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include "externalrefmgr.hxx" +#include "document.hxx" +#include "token.hxx" +#include "tokenarray.hxx" +#include "address.hxx" +#include "tablink.hxx" +#include "docsh.hxx" +#include "scextopt.hxx" +#include "rangenam.hxx" +#include "cell.hxx" +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "sc.hrc" + +#include "sfx2/app.hxx" +#include "sfx2/docfilt.hxx" +#include "sfx2/docfile.hxx" +#include "sfx2/fcontnr.hxx" +#include "sfx2/sfxsids.hrc" +#include "sfx2/objsh.hxx" +#include "svl/broadcast.hxx" +#include "svl/smplhint.hxx" +#include "svl/itemset.hxx" +#include "svl/stritem.hxx" +#include "svl/urihelper.hxx" +#include "svl/zformat.hxx" +#include "sfx2/linkmgr.hxx" +#include "tools/urlobj.hxx" +#include "unotools/ucbhelper.hxx" + +#include <memory> +#include <algorithm> + +using ::std::auto_ptr; +using ::com::sun::star::uno::Any; +using ::rtl::OUString; +using ::std::vector; +using ::std::find; +using ::std::find_if; +using ::std::distance; +using ::std::pair; +using ::std::list; +using ::std::unary_function; +using namespace formula; + +#define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec) +#define SRCDOC_SCAN_INTERVAL 1000*5 // every 5 seconds (in msec) + +namespace { + +class TabNameSearchPredicate : public unary_function<bool, ScExternalRefCache::TableName> +{ +public: + explicit TabNameSearchPredicate(const String& rSearchName) : + maSearchName(ScGlobal::pCharClass->upper(rSearchName)) + { + } + + bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const + { + // Ok, I'm doing case insensitive search here. + return rTabNameSet.maUpperName.Equals(maSearchName); + } + +private: + String maSearchName; +}; + +class FindSrcFileByName : public unary_function<ScExternalRefManager::SrcFileData, bool> +{ +public: + FindSrcFileByName(const String& rMatchName) : + mrMatchName(rMatchName) + { + } + + bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const + { + return rSrcData.maFileName.Equals(mrMatchName); + } + +private: + const String& mrMatchName; +}; + +class NotifyLinkListener : public unary_function<ScExternalRefManager::LinkListener*, void> +{ +public: + NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) : + mnFileId(nFileId), meType(eType) {} + + NotifyLinkListener(const NotifyLinkListener& r) : + mnFileId(r.mnFileId), meType(r.meType) {} + + void operator() (ScExternalRefManager::LinkListener* p) const + { + p->notify(mnFileId, meType); + } +private: + sal_uInt16 mnFileId; + ScExternalRefManager::LinkUpdateType meType; +}; + +} + +// ============================================================================ + +ScExternalRefCache::Table::Table() + : meReferenced( REFERENCED_MARKED ) + // Prevent accidental data loss due to lack of knowledge. +{ +} + +ScExternalRefCache::Table::~Table() +{ +} + +void ScExternalRefCache::Table::setReferencedFlag( ScExternalRefCache::Table::ReferencedFlag eFlag ) +{ + meReferenced = eFlag; +} + +void ScExternalRefCache::Table::setReferenced( bool bReferenced ) +{ + if (meReferenced != REFERENCED_PERMANENT) + meReferenced = (bReferenced ? REFERENCED_MARKED : UNREFERENCED); +} + +ScExternalRefCache::Table::ReferencedFlag ScExternalRefCache::Table::getReferencedFlag() const +{ + return meReferenced; +} + +bool ScExternalRefCache::Table::isReferenced() const +{ + return meReferenced != UNREFERENCED; +} + +void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex) +{ + using ::std::pair; + RowsDataType::iterator itrRow = maRows.find(nRow); + if (itrRow == maRows.end()) + { + // This row does not exist yet. + pair<RowsDataType::iterator, bool> res = maRows.insert( + RowsDataType::value_type(nRow, RowDataType())); + + if (!res.second) + return; + + itrRow = res.first; + } + + // Insert this token into the specified column location. I don't need to + // check for existing data. Just overwrite it. + RowDataType& rRow = itrRow->second; + ScExternalRefCache::Cell aCell; + aCell.mxToken = pToken; + aCell.mnFmtIndex = nFmtIndex; + rRow.insert(RowDataType::value_type(nCol, aCell)); +} + +ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const +{ + RowsDataType::const_iterator itrTable = maRows.find(nRow); + if (itrTable == maRows.end()) + { + // this table doesn't have the specified row. + return TokenRef(); + } + + const RowDataType& rRowData = itrTable->second; + RowDataType::const_iterator itrRow = rRowData.find(nCol); + if (itrRow == rRowData.end()) + { + // this row doesn't have the specified column. + return TokenRef(); + } + + const Cell& rCell = itrRow->second; + if (pnFmtIndex) + *pnFmtIndex = rCell.mnFmtIndex; + + return rCell.mxToken; +} + +bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const +{ + RowsDataType::const_iterator itrRow = maRows.find(nRow); + return itrRow != maRows.end(); +} + +void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const +{ + vector<SCROW> aRows; + aRows.reserve(maRows.size()); + RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end(); + for (; itr != itrEnd; ++itr) + aRows.push_back(itr->first); + + // hash map is not ordered, so we need to explicitly sort it. + ::std::sort(aRows.begin(), aRows.end()); + rRows.swap(aRows); +} + +void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const +{ + RowsDataType::const_iterator itrRow = maRows.find(nRow); + if (itrRow == maRows.end()) + // this table doesn't have the specified row. + return; + + const RowDataType& rRowData = itrRow->second; + vector<SCCOL> aCols; + aCols.reserve(rRowData.size()); + RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end(); + for (; itrCol != itrColEnd; ++itrCol) + aCols.push_back(itrCol->first); + + // hash map is not ordered, so we need to explicitly sort it. + ::std::sort(aCols.begin(), aCols.end()); + rCols.swap(aCols); +} + +void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end(); + for (; itrRow != itrRowEnd; ++itrRow) + { + const RowDataType& rRowData = itrRow->second; + RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end(); + for (; itrCol != itrColEnd; ++itrCol) + { + const Cell& rCell = itrCol->second; + rNumFmts.push_back(rCell.mnFmtIndex); + } + } +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) : + maUpperName(rUpper), maRealName(rReal) +{ +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::CellFormat::CellFormat() : + mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0) +{ +} + +// ---------------------------------------------------------------------------- + +ScExternalRefCache::ScExternalRefCache() +{ +} +ScExternalRefCache::~ScExternalRefCache() +{ +} + +const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return NULL; + } + + const DocItem& rDoc = itrDoc->second; + TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + { + // the specified table is not in cache. + return NULL; + } + + return &rDoc.maTableNames[itrTabId->second].maRealName; +} + +const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return NULL; + } + + const DocItem& rDoc = itrDoc->second; + NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find( + ScGlobal::pCharClass->upper(rRangeName)); + if (itr == rDoc.maRealRangeNameMap.end()) + // range name not found. + return NULL; + + return &itr->second; +} + +ScExternalRefCache::TokenRef ScExternalRefCache::getCellData( + sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow, + bool bEmptyCellOnNull, bool bWriteEmpty, sal_uInt32* pnFmtIndex) +{ + DocDataType::const_iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + return TokenRef(); + } + + const DocItem& rDoc = itrDoc->second; + TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + { + // the specified table is not in cache. + return TokenRef(); + } + + const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second]; + if (!pTableData.get()) + { + // the table data is not instantiated yet. + return TokenRef(); + } + + TokenRef pToken = pTableData->getCell(nCol, nRow, pnFmtIndex); + if (!pToken && bEmptyCellOnNull) + { + pToken.reset(new ScEmptyCellToken(false, false)); + if (bWriteEmpty) + pTableData->setCell(nCol, nRow, pToken); + } + return pToken; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData( + sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, bool bEmptyCellOnNull, bool bWriteEmpty) +{ + DocDataType::iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + // specified document is not cached. + return TokenArrayRef(); + + DocItem& rDoc = itrDoc->second; + + TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabId == rDoc.maTableNameIndex.end()) + // the specified table is not in cache. + return TokenArrayRef(); + + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + + SCTAB nTab1 = s.Tab(), nTab2 = e.Tab(); + SCCOL nCol1 = s.Col(), nCol2 = e.Col(); + SCROW nRow1 = s.Row(), nRow2 = e.Row(); + + // Make sure I have all the tables cached. + size_t nTabFirstId = itrTabId->second; + size_t nTabLastId = nTabFirstId + nTab2 - nTab1; + if (nTabLastId >= rDoc.maTables.size()) + // not all tables are cached. + return TokenArrayRef(); + + ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId)); + RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find( aCacheRange); + if (itrRange != rDoc.maRangeArrays.end()) + { + return itrRange->second; + } + + TokenArrayRef pArray(new ScTokenArray); + bool bFirstTab = true; + for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab) + { + TableTypeRef pTab = rDoc.maTables[nTab]; + if (!pTab.get()) + return TokenArrayRef(); + + ScMatrixRef xMat = new ScMatrix( + static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1)); + + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + TokenRef pToken = pTab->getCell(nCol, nRow); + if (!pToken) + { + if (bEmptyCellOnNull) + { + pToken.reset(new ScEmptyCellToken(false, false)); + if (bWriteEmpty) + pTab->setCell(nCol, nRow, pToken); + } + else + return TokenArrayRef(); + } + + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + switch (pToken->GetType()) + { + case svDouble: + xMat->PutDouble(pToken->GetDouble(), nC, nR); + break; + case svString: + xMat->PutString(pToken->GetString(), nC, nR); + break; + default: + xMat->PutEmpty(nC, nR); + } + } + } + + if (!bFirstTab) + pArray->AddOpCode(ocSep); + + ScMatrix* pMat2 = xMat; + ScMatrixToken aToken(pMat2); + pArray->AddToken(aToken); + + bFirstTab = false; + } + rDoc.maRangeArrays.insert( RangeArrayMap::value_type( aCacheRange, pArray)); + return pArray; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return TokenArrayRef(); + + RangeNameMap& rMap = pDoc->maRangeNames; + RangeNameMap::const_iterator itr = rMap.find( + ScGlobal::pCharClass->upper(rName)); + if (itr == rMap.end()) + return TokenArrayRef(); + + return itr->second; +} + +void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + String aUpperName = ScGlobal::pCharClass->upper(rName); + RangeNameMap& rMap = pDoc->maRangeNames; + rMap.insert(RangeNameMap::value_type(aUpperName, pArray)); + pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName)); +} + +void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol, + TokenRef pToken, sal_uInt32 nFmtIndex) +{ + if (!isDocInitialized(nFileId)) + return; + + using ::std::pair; + DocItem* pDocItem = getDocItem(nFileId); + if (!pDocItem) + return; + + DocItem& rDoc = *pDocItem; + + // See if the table by this name already exists. + TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rTabName)); + if (itrTabName == rDoc.maTableNameIndex.end()) + // Table not found. Maybe the table name or the file id is wrong ??? + return; + + TableTypeRef& pTableData = rDoc.maTables[itrTabName->second]; + if (!pTableData.get()) + pTableData.reset(new Table); + + pTableData->setCell(nCol, nRow, pToken, nFmtIndex); +} + +void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData, + TokenArrayRef pArray) +{ + using ::std::pair; + if (rData.empty() || !isDocInitialized(nFileId)) + // nothing to cache + return; + + // First, get the document item for the given file ID. + DocItem* pDocItem = getDocItem(nFileId); + if (!pDocItem) + return; + + DocItem& rDoc = *pDocItem; + + // Now, find the table position of the first table to cache. + const String& rFirstTabName = rData.front().maTableName; + TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find( + ScGlobal::pCharClass->upper(rFirstTabName)); + if (itrTabName == rDoc.maTableNameIndex.end()) + { + // table index not found. + return; + } + + size_t nTabFirstId = itrTabName->second; + SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row(); + SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col(); + vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end(); + for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData) + { + size_t i = nTabFirstId + ::std::distance(itrDataBeg, itrData); + TableTypeRef& pTabData = rDoc.maTables[i]; + if (!pTabData.get()) + pTabData.reset(new Table); + + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + TokenRef pToken; + const ScMatrixRef& pMat = itrData->mpRangeData; + if (pMat->IsValue(nC, nR)) + pToken.reset(new formula::FormulaDoubleToken(pMat->GetDouble(nC, nR))); + else if (pMat->IsString(nC, nR)) + pToken.reset(new formula::FormulaStringToken(pMat->GetString(nC, nR))); + else + pToken.reset(new ScEmptyCellToken(false, false)); + + pTabData->setCell(nCol, nRow, pToken); + } + } + } + + size_t nTabLastId = nTabFirstId + rRange.aEnd.Tab() - rRange.aStart.Tab(); + ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId)); + rDoc.maRangeArrays.insert( RangeArrayMap::value_type( aCacheRange, pArray)); +} + +bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return false; + + return pDoc->mbInitFromSource; +} + +static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex) +{ + ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName); + if (itr == rMap.end()) + return false; + + rIndex = itr->second; + return true; +} + +void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames) +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + size_t n = rTabNames.size(); + + // table name list - the list must include all table names in the source + // document and only to be populated when loading the source document, not + // when loading cached data from, say, Excel XCT/CRN records. + vector<TableName> aNewTabNames; + aNewTabNames.reserve(n); + for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end(); + itr != itrEnd; ++itr) + { + TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr); + aNewTabNames.push_back(aNameItem); + } + pDoc->maTableNames.swap(aNewTabNames); + + // data tables - preserve any existing data that may have been set during + // file import. + vector<TableTypeRef> aNewTables(n); + for (size_t i = 0; i < n; ++i) + { + size_t nIndex; + if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex)) + { + aNewTables[i] = pDoc->maTables[nIndex]; + } + } + pDoc->maTables.swap(aNewTables); + + // name index map + TableNameIndexMap aNewNameIndex; + for (size_t i = 0; i < n; ++i) + aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i)); + pDoc->maTableNameIndex.swap(aNewNameIndex); + + pDoc->mbInitFromSource = true; +} + +String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const +{ + if( DocItem* pDoc = getDocItem( nFileId ) ) + if( nCacheId < pDoc->maTableNames.size() ) + return pDoc->maTableNames[ nCacheId ].maRealName; + return EMPTY_STRING; +} + +void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const +{ + rTabNames.clear(); + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return; + + size_t n = pDoc->maTableNames.size(); + rTabNames.reserve(n); + for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end(); + itr != itrEnd; ++itr) + rTabNames.push_back(itr->maRealName); +} + +SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return -1; + + vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(); + vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end(); + + vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd, + TabNameSearchPredicate( rStartTabName)); + if (itrStartTab == itrEnd) + return -1; + + vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd, + TabNameSearchPredicate( rEndTabName)); + if (itrEndTab == itrEnd) + return 0; + + size_t nStartDist = ::std::distance( itrBeg, itrStartTab); + size_t nEndDist = ::std::distance( itrBeg, itrEndTab); + return nStartDist <= nEndDist ? static_cast<SCsTAB>(nEndDist - nStartDist + 1) : -static_cast<SCsTAB>(nStartDist - nEndDist + 1); +} + +void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + using ::std::sort; + using ::std::unique; + + vector<sal_uInt32> aNumFmts; + for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end(); + itrDoc != itrDocEnd; ++itrDoc) + { + const vector<TableTypeRef>& rTables = itrDoc->second.maTables; + for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end(); + itrTab != itrTabEnd; ++itrTab) + { + TableTypeRef pTab = *itrTab; + if (!pTab) + continue; + + pTab->getAllNumberFormats(aNumFmts); + } + } + + // remove duplicates. + sort(aNumFmts.begin(), aNumFmts.end()); + aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end()); + rNumFmts.swap(aNumFmts); +} + +bool ScExternalRefCache::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + return false; + + String aUpperName = ScGlobal::pCharClass->upper(rTabName); + vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end(); + vector<TableName>::const_iterator itr = ::std::find_if( + itrBeg, itrEnd, TabNameSearchPredicate(aUpperName)); + + return itr != itrEnd; +} + +size_t ScExternalRefCache::getCacheTableCount(sal_uInt16 nFileId) const +{ + DocItem* pDoc = getDocItem(nFileId); + return pDoc ? pDoc->maTables.size() : 0; +} + +bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId ) +{ + DocItem* pDocItem = getDocItem(nFileId); + if (!pDocItem) + return areAllCacheTablesReferenced(); + + for (::std::vector<TableTypeRef>::iterator itrTab = pDocItem->maTables.begin(); + itrTab != pDocItem->maTables.end(); ++itrTab) + { + if ((*itrTab).get()) + (*itrTab)->setReferenced( true); + } + addCacheDocToReferenced( nFileId); + return areAllCacheTablesReferenced(); +} + +bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets, bool bPermanent ) +{ + DocItem* pDoc = getDocItem(nFileId); + if (pDoc) + { + size_t nIndex = 0; + String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName); + if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex)) + { + size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size()); + for (size_t i = nIndex; i < nStop; ++i) + { + TableTypeRef pTab = pDoc->maTables[i]; + if (pTab.get()) + { + Table::ReferencedFlag eNewFlag = (bPermanent ? + Table::REFERENCED_PERMANENT : + Table::REFERENCED_MARKED); + Table::ReferencedFlag eOldFlag = pTab->getReferencedFlag(); + if (eOldFlag != Table::REFERENCED_PERMANENT && eNewFlag != eOldFlag) + { + pTab->setReferencedFlag( eNewFlag); + addCacheTableToReferenced( nFileId, i); + } + } + } + } + } + return areAllCacheTablesReferenced(); +} + +void ScExternalRefCache::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) +{ + DocItem* pDoc = getDocItem(nFileId); + if (pDoc) + { + size_t nIndex = 0; + String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName); + if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex)) + { + size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size()); + for (size_t i = nIndex; i < nStop; ++i) + { + TableTypeRef pTab = pDoc->maTables[i]; + if (pTab.get()) + pTab->setReferencedFlag( Table::REFERENCED_PERMANENT); + } + } + } +} + +void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced ) +{ + if (bReferenced) + { + maReferenced.reset(0); + for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc) + { + ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second; + for (::std::vector<TableTypeRef>::iterator itrTab = rDocItem.maTables.begin(); + itrTab != rDocItem.maTables.end(); ++itrTab) + { + if ((*itrTab).get()) + (*itrTab)->setReferenced( true); + } + } + } + else + { + size_t nDocs = 0; + for (DocDataType::const_iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc) + { + if (nDocs <= (*itrDoc).first) + nDocs = (*itrDoc).first + 1; + } + maReferenced.reset( nDocs); + + for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc) + { + ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second; + sal_uInt16 nFileId = (*itrDoc).first; + size_t nTables = rDocItem.maTables.size(); + ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId]; + // All referenced => non-existing tables evaluate as completed. + rDocReferenced.maTables.resize( nTables, true); + for (size_t i=0; i < nTables; ++i) + { + TableTypeRef & xTab = rDocItem.maTables[i]; + if (xTab.get()) + { + if (xTab->getReferencedFlag() == Table::REFERENCED_PERMANENT) + addCacheTableToReferenced( nFileId, i); + else + { + xTab->setReferencedFlag( Table::UNREFERENCED); + rDocReferenced.maTables[i] = false; + rDocReferenced.mbAllTablesReferenced = false; + // An addCacheTableToReferenced() actually may have + // resulted in mbAllReferenced been set. Clear it. + maReferenced.mbAllReferenced = false; + } + } + } + } + } +} + +void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex ) +{ + if (nFileId >= maReferenced.maDocs.size()) + return; + + ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables; + size_t nTables = rTables.size(); + if (nIndex >= nTables) + return; + + if (!rTables[nIndex]) + { + rTables[nIndex] = true; + size_t i = 0; + while (i < nTables && rTables[i]) + ++i; + if (i == nTables) + { + maReferenced.maDocs[nFileId].mbAllTablesReferenced = true; + maReferenced.checkAllDocs(); + } + } +} + +void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId ) +{ + if (nFileId >= maReferenced.maDocs.size()) + return; + + if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced) + { + ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables; + size_t nSize = rTables.size(); + for (size_t i=0; i < nSize; ++i) + rTables[i] = true; + maReferenced.maDocs[nFileId].mbAllTablesReferenced = true; + maReferenced.checkAllDocs(); + } +} + +bool ScExternalRefCache::areAllCacheTablesReferenced() const +{ + return maReferenced.mbAllReferenced; +} + +ScExternalRefCache::ReferencedStatus::ReferencedStatus() : + mbAllReferenced(false) +{ + reset(0); +} + +ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs ) : + mbAllReferenced(false) +{ + reset( nDocs); +} + +void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs ) +{ + if (nDocs) + { + mbAllReferenced = false; + DocReferencedVec aRefs( nDocs); + maDocs.swap( aRefs); + } + else + { + mbAllReferenced = true; + DocReferencedVec aRefs; + maDocs.swap( aRefs); + } +} + +void ScExternalRefCache::ReferencedStatus::checkAllDocs() +{ + for (DocReferencedVec::const_iterator itr = maDocs.begin(); itr != maDocs.end(); ++itr) + { + if (!(*itr).mbAllTablesReferenced) + return; + } + mbAllReferenced = true; +} + +ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const +{ + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc || nTabIndex >= pDoc->maTables.size()) + return TableTypeRef(); + + return pDoc->maTables[nTabIndex]; +} + +ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex) +{ + // In API, the index is transported as cached sheet ID of type sal_Int32 in + // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet + // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively + // being 0xffffffff + const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1)); + + DocItem* pDoc = getDocItem(nFileId); + if (!pDoc) + { + if (pnIndex) *pnIndex = nNotAvailable; + return TableTypeRef(); + } + + DocItem& rDoc = *pDoc; + + size_t nIndex; + String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName); + if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex)) + { + // specified table found. + if( pnIndex ) *pnIndex = nIndex; + return rDoc.maTables[nIndex]; + } + + if (!bCreateNew) + { + if (pnIndex) *pnIndex = nNotAvailable; + return TableTypeRef(); + } + + // Specified table doesn't exist yet. Create one. + nIndex = rDoc.maTables.size(); + if( pnIndex ) *pnIndex = nIndex; + TableTypeRef pTab(new Table); + rDoc.maTables.push_back(pTab); + rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName)); + rDoc.maTableNameIndex.insert( + TableNameIndexMap::value_type(aTabNameUpper, nIndex)); + return pTab; +} + +void ScExternalRefCache::clearCache(sal_uInt16 nFileId) +{ + maDocs.erase(nFileId); +} + +ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const +{ + using ::std::pair; + DocDataType::iterator itrDoc = maDocs.find(nFileId); + if (itrDoc == maDocs.end()) + { + // specified document is not cached. + pair<DocDataType::iterator, bool> res = maDocs.insert( + DocDataType::value_type(nFileId, DocItem())); + + if (!res.second) + // insertion failed. + return NULL; + + itrDoc = res.first; + } + + return &itrDoc->second; +} + +// ============================================================================ + +ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) : + ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE), + mnFileId(nFileId), + maFilterName(rFilter), + mpDoc(pDoc), + mbDoRefresh(true) +{ +} + +ScExternalRefLink::~ScExternalRefLink() +{ +} + +void ScExternalRefLink::Closed() +{ + ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager(); + pMgr->breakLink(mnFileId); +} + +void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/) +{ + if (!mbDoRefresh) + return; + + String aFile, aFilter; + mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter); + ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager(); + const String* pCurFile = pMgr->getExternalFileName(mnFileId); + if (!pCurFile) + return; + + if (pCurFile->Equals(aFile)) + { + // Refresh the current source document. + pMgr->refreshNames(mnFileId); + } + else + { + // The source document has changed. + ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell(); + ScDocShellModificator aMod(*pDocShell); + pMgr->switchSrcFile(mnFileId, aFile, aFilter); + maFilterName = aFilter; + aMod.SetDocumentModified(); + } +} + +void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/) +{ + SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl)); +} + +void ScExternalRefLink::SetDoReferesh(bool b) +{ + mbDoRefresh = b; +} + +IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG ) +{ + return 0; +} + +// ============================================================================ + +static FormulaToken* lcl_convertToToken(ScBaseCell* pCell) +{ + if (!pCell || pCell->HasEmptyData()) + { + bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA); + return new ScEmptyCellToken( bInherited, false); + } + + switch (pCell->GetCellType()) + { + case CELLTYPE_EDIT: + { + String aStr; + static_cast<ScEditCell*>(pCell)->GetString(aStr); + return new formula::FormulaStringToken(aStr); + } + //break; + case CELLTYPE_STRING: + { + String aStr; + static_cast<ScStringCell*>(pCell)->GetString(aStr); + return new formula::FormulaStringToken(aStr); + } + //break; + case CELLTYPE_VALUE: + { + double fVal = static_cast<ScValueCell*>(pCell)->GetValue(); + return new formula::FormulaDoubleToken(fVal); + } + //break; + case CELLTYPE_FORMULA: + { + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + USHORT nError = pFCell->GetErrCode(); + if (nError) + return new FormulaErrorToken( nError); + else if (pFCell->IsValue()) + { + double fVal = pFCell->GetValue(); + return new formula::FormulaDoubleToken(fVal); + } + else + { + String aStr; + pFCell->GetString(aStr); + return new formula::FormulaStringToken(aStr); + } + } + //break; + default: + DBG_ERROR("attempted to convert an unknown cell type."); + } + + return NULL; +} + +static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange, + vector<ScExternalRefCache::SingleRangeData>& rCacheData) +{ + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + + SCTAB nTab1 = s.Tab(), nTab2 = e.Tab(); + SCCOL nCol1 = s.Col(), nCol2 = e.Col(); + SCROW nRow1 = s.Row(), nRow2 = e.Row(); + + if (nTab2 != nTab1) + // For now, we don't support multi-sheet ranges intentionally because + // we don't have a way to express them in a single token. In the + // future we can introduce a new stack variable type svMatrixList with + // a new token type that can store a 3D matrix value and convert a 3D + // range to it. + return NULL; + + auto_ptr<ScTokenArray> pArray(new ScTokenArray); + bool bFirstTab = true; + vector<ScExternalRefCache::SingleRangeData>::iterator + itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end(); + for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache) + { + ScMatrixRef xMat = new ScMatrix( + static_cast<SCSIZE>(nCol2-nCol1+1), + static_cast<SCSIZE>(nRow2-nRow1+1)); + + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + SCSIZE nC = nCol - nCol1, nR = nRow - nRow1; + ScBaseCell* pCell; + pSrcDoc->GetCell(nCol, nRow, nTab, pCell); + if (!pCell || pCell->HasEmptyData()) + xMat->PutEmpty(nC, nR); + else + { + switch (pCell->GetCellType()) + { + case CELLTYPE_EDIT: + { + String aStr; + static_cast<ScEditCell*>(pCell)->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + break; + case CELLTYPE_STRING: + { + String aStr; + static_cast<ScStringCell*>(pCell)->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + break; + case CELLTYPE_VALUE: + { + double fVal = static_cast<ScValueCell*>(pCell)->GetValue(); + xMat->PutDouble(fVal, nC, nR); + } + break; + case CELLTYPE_FORMULA: + { + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + USHORT nError = pFCell->GetErrCode(); + if (nError) + xMat->PutDouble( CreateDoubleError( nError), nC, nR); + else if (pFCell->IsValue()) + { + double fVal = pFCell->GetValue(); + xMat->PutDouble(fVal, nC, nR); + } + else + { + String aStr; + pFCell->GetString(aStr); + xMat->PutString(aStr, nC, nR); + } + } + break; + default: + DBG_ERROR("attempted to convert an unknown cell type."); + } + } + } + } + if (!bFirstTab) + pArray->AddOpCode(ocSep); + + ScMatrix* pMat2 = xMat; + ScMatrixToken aToken(pMat2); + pArray->AddToken(aToken); + + itrCache->mpRangeData = xMat; + + bFirstTab = false; + } + return pArray.release(); +} + +ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) : + mpDoc(pDoc), + bInReferenceMarking(false) +{ + maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) ); + maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL); +} + +ScExternalRefManager::~ScExternalRefManager() +{ + clear(); +} + +String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const +{ + return maRefCache.getTableName(nFileId, nTabIndex); +} + +ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const +{ + return maRefCache.getCacheTable(nFileId, nTabIndex); +} + +ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex) +{ + return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex); +} + +// ============================================================================ + +ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex) : + mnIndex(nIndex) +{ +} + +ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem& r) : + mnIndex(r.mnIndex), + maCols(r.maCols) +{ +} + +ScExternalRefManager::RefCells::RefCells() +{ +} + +ScExternalRefManager::RefCells::~RefCells() +{ +} + +list<ScExternalRefManager::RefCells::TabItemRef>::iterator ScExternalRefManager::RefCells::getTabPos(SCTAB nTab) +{ + list<TabItemRef>::iterator itr = maTables.begin(), itrEnd = maTables.end(); + for (; itr != itrEnd; ++itr) + if ((*itr)->mnIndex >= nTab) + return itr; + // Not found. return the end position. + return itrEnd; +} + +void ScExternalRefManager::RefCells::insertCell(const ScAddress& rAddr) +{ + SCTAB nTab = rAddr.Tab(); + SCCOL nCol = rAddr.Col(); + SCROW nRow = rAddr.Row(); + + // Search by table index. + list<TabItemRef>::iterator itrTab = getTabPos(nTab); + TabItemRef xTabRef; + if (itrTab == maTables.end()) + { + // All previous tables come before the specificed table. + xTabRef.reset(new TabItem(nTab)); + maTables.push_back(xTabRef); + } + else if ((*itrTab)->mnIndex > nTab) + { + // Insert at the current iterator position. + xTabRef.reset(new TabItem(nTab)); + maTables.insert(itrTab, xTabRef); + } + else if ((*itrTab)->mnIndex == nTab) + { + // The table found. + xTabRef = *itrTab; + } + ColSet& rCols = xTabRef->maCols; + + // Then by column index. + ColSet::iterator itrCol = rCols.find(nCol); + if (itrCol == rCols.end()) + { + RowSet aRows; + pair<ColSet::iterator, bool> r = rCols.insert(ColSet::value_type(nCol, aRows)); + if (!r.second) + // column insertion failed. + return; + itrCol = r.first; + } + RowSet& rRows = itrCol->second; + + // Finally, insert the row index. + rRows.insert(nRow); +} + +void ScExternalRefManager::RefCells::removeCell(const ScAddress& rAddr) +{ + SCTAB nTab = rAddr.Tab(); + SCCOL nCol = rAddr.Col(); + SCROW nRow = rAddr.Row(); + + // Search by table index. + list<TabItemRef>::iterator itrTab = getTabPos(nTab); + if (itrTab == maTables.end() || (*itrTab)->mnIndex != nTab) + // No such table. + return; + + ColSet& rCols = (*itrTab)->maCols; + + // Then by column index. + ColSet::iterator itrCol = rCols.find(nCol); + if (itrCol == rCols.end()) + // No such column + return; + + RowSet& rRows = itrCol->second; + rRows.erase(nRow); +} + +void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy) +{ + if (nOldTab == nNewTab) + // Nothing to do here. + return; + + list<TabItemRef>::iterator itrOld = getTabPos(nOldTab); + if (itrOld == maTables.end() || (*itrOld)->mnIndex != nOldTab) + // No table to move or copy. + return; + + list<TabItemRef>::iterator itrNew = getTabPos(nNewTab); + if (bCopy) + { + // Simply make a duplicate of the original table, insert it at the + // new tab position, and increment the table index for all tables + // that come after that inserted table. + + TabItemRef xNewTab(new TabItem(*(*itrOld))); + xNewTab->mnIndex = nNewTab; + maTables.insert(itrNew, xNewTab); + list<TabItemRef>::iterator itr = itrNew, itrEnd = maTables.end(); + if (itr != itrEnd) // #i99807# check that itr is not at end already + for (++itr; itr != itrEnd; ++itr) + (*itr)->mnIndex += 1; + } + else + { + if (itrOld == itrNew) + { + // No need to move the table. Just update the table index. + (*itrOld)->mnIndex = nNewTab; + return; + } + + if (nOldTab < nNewTab) + { + // Iterate from the old tab position to the new tab position (not + // inclusive of the old tab itself), and decrement their tab + // index by one. + list<TabItemRef>::iterator itr = itrOld; + for (++itr; itr != itrNew; ++itr) + (*itr)->mnIndex -= 1; + + // Insert a duplicate of the original table. This does not + // invalidate the iterators. + (*itrOld)->mnIndex = nNewTab - 1; + if (itrNew == maTables.end()) + maTables.push_back(*itrOld); + else + maTables.insert(itrNew, *itrOld); + + // Remove the original table. + maTables.erase(itrOld); + } + else + { + // nNewTab < nOldTab + + // Iterate from the new tab position to the one before the old tab + // position, and increment their tab index by one. + list<TabItemRef>::iterator itr = itrNew; + for (++itr; itr != itrOld; ++itr) + (*itr)->mnIndex += 1; + + (*itrOld)->mnIndex = nNewTab; + maTables.insert(itrNew, *itrOld); + + // Remove the original table. + maTables.erase(itrOld); + } + } +} + +void ScExternalRefManager::RefCells::insertTable(SCTAB nPos) +{ + TabItemRef xNewTab(new TabItem(nPos)); + list<TabItemRef>::iterator itr = getTabPos(nPos); + if (itr == maTables.end()) + maTables.push_back(xNewTab); + else + maTables.insert(itr, xNewTab); +} + +void ScExternalRefManager::RefCells::removeTable(SCTAB nPos) +{ + list<TabItemRef>::iterator itr = getTabPos(nPos); + if (itr == maTables.end()) + // nothing to remove. + return; + + maTables.erase(itr); +} + +void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefMgr) +{ + // Get ALL the cell positions for re-compilation. + for (list<TabItemRef>::iterator itrTab = maTables.begin(), itrTabEnd = maTables.end(); + itrTab != itrTabEnd; ++itrTab) + { + SCTAB nTab = (*itrTab)->mnIndex; + ColSet& rCols = (*itrTab)->maCols; + for (ColSet::iterator itrCol = rCols.begin(), itrColEnd = rCols.end(); + itrCol != itrColEnd; ++itrCol) + { + SCCOL nCol = itrCol->first; + RowSet& rRows = itrCol->second; + RowSet aNewRows; + for (RowSet::iterator itrRow = rRows.begin(), itrRowEnd = rRows.end(); + itrRow != itrRowEnd; ++itrRow) + { + SCROW nRow = *itrRow; + ScAddress aCell(nCol, nRow, nTab); + if (rRefMgr.compileTokensByCell(aCell)) + // This cell still contains an external refernce. + aNewRows.insert(nRow); + } + // Update the rows so that cells with no external references are + // no longer tracked. + rRows.swap(aNewRows); + } + } +} + +// ---------------------------------------------------------------------------- + +ScExternalRefManager::LinkListener::LinkListener() +{ +} + +ScExternalRefManager::LinkListener::~LinkListener() +{ +} + +// ---------------------------------------------------------------------------- + +void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const +{ + maRefCache.getAllTableNames(nFileId, rTabNames); +} + +SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const +{ + return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName); +} + +void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const +{ + maRefCache.getAllNumberFormats(rNumFmts); +} + +bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const +{ + return maRefCache.hasCacheTable(nFileId, rTabName); +} + +size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId) const +{ + return maRefCache.getCacheTableCount(nFileId); +} + +sal_uInt16 ScExternalRefManager::getExternalFileCount() const +{ + return static_cast< sal_uInt16 >( maSrcFiles.size() ); +} + +bool ScExternalRefManager::markUsedByLinkListeners() +{ + bool bAllMarked = false; + for (LinkListenerMap::const_iterator itr = maLinkListeners.begin(); + itr != maLinkListeners.end() && !bAllMarked; ++itr) + { + if (!(*itr).second.empty()) + bAllMarked = maRefCache.setCacheDocReferenced( (*itr).first); + /* TODO: LinkListeners should remember the table they're listening to. + * As is, listening to one table will mark all tables of the document + * being referenced. */ + } + return bAllMarked; +} + +bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId ) +{ + return maRefCache.setCacheDocReferenced( nFileId); +} + +bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) +{ + return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, false); +} + +void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) +{ + if (isInReferenceMarking()) + // Do all maintenance work. + maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, true); + else + // Set only the permanent flag. + maRefCache.setCacheTableReferencedPermanently( nFileId, rTabName, nSheets); +} + +void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced ) +{ + bInReferenceMarking = !bReferenced; + maRefCache.setAllCacheTableReferencedStati( bReferenced ); +} + +void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray) +{ + ScExternalRefCache::TokenArrayRef pArray(rArray.Clone()); + maRefCache.setRangeNameTokens(nFileId, rName, pArray); +} + +ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken( + sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell, + const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + if (pTab) + *pTab = -1; + + if (pFmt) + pFmt->mbIsSet = false; + + bool bLoading = mpDoc->IsImportingXML(); + + // Check if the given table name and the cell position is cached. + // #i101304# When loading a file, the saved cache (hidden sheet) + // is assumed to contain all data for the loaded formulas. + // No cache entries are created from empty cells in the saved sheet, + // so they have to be created here (bWriteEmpty parameter). + // Otherwise, later interpretation of the loaded formulas would + // load the source document even if the user didn't want to update. + sal_uInt32 nFmtIndex = 0; + ScExternalRefCache::TokenRef pToken = maRefCache.getCellData( + nFileId, rTabName, rCell.Col(), rCell.Row(), bLoading, bLoading, &nFmtIndex); + if (pToken) + { + if (pFmt) + { + short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex); + if (nFmtType != NUMBERFORMAT_UNDEFINED) + { + pFmt->mbIsSet = true; + pFmt->mnIndex = nFmtIndex; + pFmt->mnType = nFmtType; + } + } + return pToken; + } + + // reference not cached. read from the source document. + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + { + // Source document is not reachable. Try to get data from the cache + // once again, but this time treat a non-cached cell as an empty cell + // as long as the table itself is cached. + pToken = maRefCache.getCellData( + nFileId, rTabName, rCell.Col(), rCell.Row(), true, false, &nFmtIndex); + return pToken; + } + + ScBaseCell* pCell = NULL; + SCTAB nTab; + if (!pSrcDoc->GetTable(rTabName, nTab)) + { + // specified table name doesn't exist in the source document. + return ScExternalRefCache::TokenRef(); + } + + if (pTab) + *pTab = nTab; + + pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell); + ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell)); + + pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex); + nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc); + if (pFmt) + { + short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex); + if (nFmtType != NUMBERFORMAT_UNDEFINED) + { + pFmt->mbIsSet = true; + pFmt->mnIndex = nFmtIndex; + pFmt->mnType = nFmtType; + } + } + + if (!pTok.get()) + { + // Generate an error for unresolvable cells. + pTok.reset( new FormulaErrorToken( errNoValue)); + } + + // Now, insert the token into cache table. + maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok, nFmtIndex); + return pTok; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + bool bLoading = mpDoc->IsImportingXML(); + + // Check if the given table name and the cell position is cached. + // #i101304# When loading, put empty cells into cache, see getSingleRefToken. + ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange, bLoading, bLoading); + if (p.get()) + return p; + + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + { + // Source document is not reachable. Try to get data from the cache + // once again, but this time treat non-cached cells as empty cells as + // long as the table itself is cached. + return maRefCache.getCellRangeData(nFileId, rTabName, rRange, true, false); + } + + SCTAB nTab1; + if (!pSrcDoc->GetTable(rTabName, nTab1)) + // specified table name doesn't exist in the source document. + return ScExternalRefCache::TokenArrayRef(); + + ScRange aRange(rRange); + SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab(); + + vector<ScExternalRefCache::SingleRangeData> aCacheData; + aCacheData.reserve(nTabSpan+1); + aCacheData.push_back(ScExternalRefCache::SingleRangeData()); + aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName); + + for (SCTAB i = 1; i < nTabSpan + 1; ++i) + { + String aTabName; + if (!pSrcDoc->GetName(nTab1 + 1, aTabName)) + // source document doesn't have any table by the specified name. + break; + + aCacheData.push_back(ScExternalRefCache::SingleRangeData()); + aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName); + } + + aRange.aStart.SetTab(nTab1); + aRange.aEnd.SetTab(nTab1 + nTabSpan); + + ScExternalRefCache::TokenArrayRef pArray; + pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData)); + + if (pArray) + // Cache these values. + maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray); + + return pArray; +} + +ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos) +{ + if (pCurPos) + insertRefCell(nFileId, *pCurPos); + + maybeLinkExternalFile(nFileId); + + ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName); + if (pArray.get()) + return pArray; + + ScDocument* pSrcDoc = getSrcDocument(nFileId); + if (!pSrcDoc) + return ScExternalRefCache::TokenArrayRef(); + + ScRangeName* pExtNames = pSrcDoc->GetRangeName(); + String aUpperName = ScGlobal::pCharClass->upper(rName); + USHORT n; + bool bRes = pExtNames->SearchNameUpper(aUpperName, n); + if (!bRes) + return ScExternalRefCache::TokenArrayRef(); + + ScRangeData* pRangeData = (*pExtNames)[n]; + if (!pRangeData) + return ScExternalRefCache::TokenArrayRef(); + + // Parse all tokens in this external range data, and replace each absolute + // reference token with an external reference token, and cache them. Also + // register the source document with the link manager if it's a new + // source. + + ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray); + + ScTokenArray* pCode = pRangeData->GetCode(); + for (FormulaToken* pToken = pCode->First(); pToken; pToken = pCode->Next()) + { + bool bTokenAdded = false; + switch (pToken->GetType()) + { + case svSingleRef: + { + const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef(); + String aTabName; + pSrcDoc->GetName(rRef.nTab, aTabName); + ScExternalSingleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetSingleRef()); + pNew->AddToken(aNewToken); + bTokenAdded = true; + } + break; + case svDoubleRef: + { + const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef(); + String aTabName; + pSrcDoc->GetName(rRef.nTab, aTabName); + ScExternalDoubleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetDoubleRef()); + pNew->AddToken(aNewToken); + bTokenAdded = true; + } + break; + default: + ; // nothing + } + + if (!bTokenAdded) + pNew->AddToken(*pToken); + } + + // Make sure to pass the correctly-cased range name here. + maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew); + return pNew; +} + +void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId) +{ + RefCellMap::iterator itrFile = maRefCells.find(nFileId); + if (itrFile == maRefCells.end()) + return; + + RefCells& rRefCells = itrFile->second; + rRefCells.refreshAllCells(*this); + + ScViewData* pViewData = ScDocShell::GetViewData(); + if (!pViewData) + return; + + ScTabViewShell* pVShell = pViewData->GetViewShell(); + if (!pVShell) + return; + + // Repainting the grid also repaints the texts, but is there a better way + // to refresh texts? + pVShell->Invalidate(FID_REPAINT); + pVShell->PaintGrid(); +} + +void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell) +{ + RefCellMap::iterator itr = maRefCells.find(nFileId); + if (itr == maRefCells.end()) + { + RefCells aRefCells; + pair<RefCellMap::iterator, bool> r = maRefCells.insert( + RefCellMap::value_type(nFileId, aRefCells)); + if (!r.second) + // insertion failed. + return; + + itr = r.first; + } + itr->second.insertCell(rCell); +} + +ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId) +{ + if (!mpDoc->IsExecuteLinkEnabled()) + return NULL; + + DocShellMap::iterator itrEnd = maDocShells.end(); + DocShellMap::iterator itr = maDocShells.find(nFileId); + + if (itr != itrEnd) + { + SfxObjectShell* p = itr->second.maShell; + itr->second.maLastAccess = Time(); + return static_cast<ScDocShell*>(p)->GetDocument(); + } + + const String* pFile = getExternalFileName(nFileId); + if (!pFile) + // no file name associated with this ID. + return NULL; + + String aFilter; + SrcShell aSrcDoc; + aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter); + if (!aSrcDoc.maShell.Is()) + { + // source document could not be loaded. + return NULL; + } + + if (maDocShells.empty()) + { + // If this is the first source document insertion, start up the timer. + maSrcDocTimer.Start(); + } + + maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc)); + SfxObjectShell* p = aSrcDoc.maShell; + ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument(); + + SCTAB nTabCount = pSrcDoc->GetTableCount(); + if (!maRefCache.isDocInitialized(nFileId) && nTabCount) + { + // Populate the cache with all table names in the source document. + vector<String> aTabNames; + aTabNames.reserve(nTabCount); + for (SCTAB i = 0; i < nTabCount; ++i) + { + String aName; + pSrcDoc->GetName(i, aName); + aTabNames.push_back(aName); + } + maRefCache.initializeDoc(nFileId, aTabNames); + } + return pSrcDoc; +} + +SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter) +{ + const SrcFileData* pFileData = getExternalFileData(nFileId); + if (!pFileData) + return NULL; + + // Always load the document by using the path created from the relative + // path. If the referenced document is not there, simply exit. The + // original file name should be used only when the relative path is not + // given. + String aFile = pFileData->maFileName; + maybeCreateRealFileName(nFileId); + if (pFileData->maRealFileName.Len()) + aFile = pFileData->maRealFileName; + + if (!isFileLoadable(aFile)) + return NULL; + + String aOptions; + ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false); + const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter); + + if (!pFileData->maRelativeName.Len()) + { + // Generate a relative file path. + INetURLObject aBaseURL(getOwnDocumentName()); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + + String aStr = URIHelper::simpleNormalizedMakeRelative( + aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile); + + setRelativeFileName(nFileId, aStr); + } + + // Update the filter data now that we are loading it again. + setFilterData(nFileId, rFilter, aOptions); + + SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool()); + if (aOptions.Len()) + pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions)); + + auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet)); + if (pMedium->GetError() != ERRCODE_NONE) + return NULL; + + pMedium->UseInteractionHandler(false); + + ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL); + SfxObjectShellRef aRef = pNewShell; + + // increment the recursive link count of the source document. + ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions(); + sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0; + ScDocument* pSrcDoc = pNewShell->GetDocument(); + ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions(); + if (!pExtOptNew) + { + pExtOptNew = new ScExtDocOptions; + pSrcDoc->SetExtDocOptions(pExtOptNew); + } + pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1; + + pNewShell->DoLoad(pMedium.release()); + return aRef; +} + +bool ScExternalRefManager::isFileLoadable(const String& rFile) const +{ + if (!rFile.Len()) + return false; + + if (isOwnDocument(rFile)) + return false; + + if (utl::UCBContentHelper::IsFolder(rFile)) + return false; + + return utl::UCBContentHelper::Exists(rFile); +} + +void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId) +{ + if (maLinkedDocs.count(nFileId)) + // file alerady linked, or the link has been broken. + return; + + // Source document not linked yet. Link it now. + const String* pFileName = getExternalFileName(nFileId); + if (!pFileName) + return; + + String aFilter, aOptions; + ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false); + sfx2::LinkManager* pLinkMgr = mpDoc->GetLinkManager(); + ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter); + DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL"); + pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter); + + pLink->SetDoReferesh(false); + pLink->Update(); + pLink->SetDoReferesh(true); + + maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true)); +} + +void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName) +{ + if (!maRelativeName.Len()) + // No relative path given. Nothing to do. + return; + + if (maRealFileName.Len()) + // Real file name already created. Nothing to do. + return; + + // Formulate the absolute file path from the relative path. + const String& rRelPath = maRelativeName; + INetURLObject aBaseURL(rOwnDocName); + aBaseURL.insertName(OUString::createFromAscii("content.xml")); + bool bWasAbs = false; + maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE); +} + +void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId) +{ + if (nFileId >= maSrcFiles.size()) + return; + + maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName()); +} + +bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell) +{ + ScBaseCell* pCell; + mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell); + + if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA) + return false; + + ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell); + + // Check to make sure the cell really contains ocExternalRef. + // External names, external cell and range references all have a + // ocExternalRef token. + const ScTokenArray* pCode = pFC->GetCode(); + if (!pCode->HasOpCode( ocExternalRef)) + return false; + + ScTokenArray* pArray = pFC->GetCode(); + if (pArray) + // Clear the error code, or a cell with error won't get re-compiled. + pArray->SetCodeError(0); + + pFC->SetCompile(true); + pFC->CompileTokenArray(); + pFC->SetDirty(); + + return true; +} + +const String& ScExternalRefManager::getOwnDocumentName() const +{ + SfxObjectShell* pShell = mpDoc->GetDocumentShell(); + if (!pShell) + // This should not happen! + return EMPTY_STRING; + + SfxMedium* pMed = pShell->GetMedium(); + if (!pMed) + return EMPTY_STRING; + + return pMed->GetName(); +} + +bool ScExternalRefManager::isOwnDocument(const String& rFile) const +{ + return getOwnDocumentName().Equals(rFile); +} + +void ScExternalRefManager::convertToAbsName(String& rFile) const +{ + SfxObjectShell* pDocShell = mpDoc->GetDocumentShell(); + rFile = ScGlobal::GetAbsDocName(rFile, pDocShell); +} + +sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile) +{ + vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile)); + if (itr != itrEnd) + { + size_t nId = distance(itrBeg, itr); + return static_cast<sal_uInt16>(nId); + } + + SrcFileData aData; + aData.maFileName = rFile; + maSrcFiles.push_back(aData); + return static_cast<sal_uInt16>(maSrcFiles.size() - 1); +} + +const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal) +{ + if (nFileId >= maSrcFiles.size()) + return NULL; + + if (bForceOriginal) + return &maSrcFiles[nFileId].maFileName; + + maybeCreateRealFileName(nFileId); + + if (maSrcFiles[nFileId].maRealFileName.Len()) + return &maSrcFiles[nFileId].maRealFileName; + else + return &maSrcFiles[nFileId].maFileName; +} + +bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const +{ + return nFileId < maSrcFiles.size(); +} + +bool ScExternalRefManager::hasExternalFile(const String& rFile) const +{ + vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile)); + return itr != itrEnd; +} + +const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const +{ + if (nFileId >= maSrcFiles.size()) + return NULL; + + return &maSrcFiles[nFileId]; +} + +const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const +{ + return maRefCache.getRealTableName(nFileId, rTabName); +} + +const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const +{ + return maRefCache.getRealRangeName(nFileId, rRangeName); +} + +template<typename MapContainer> +void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap) +{ + typename MapContainer::iterator itr = rMap.find(nFileId); + if (itr != rMap.end()) + rMap.erase(itr); +} + +void ScExternalRefManager::refreshNames(sal_uInt16 nFileId) +{ + maRefCache.clearCache(nFileId); + lcl_removeByFileId(nFileId, maDocShells); + + if (maDocShells.empty()) + maSrcDocTimer.Stop(); + + // Update all cells containing names from this source document. + refreshAllRefCells(nFileId); + + notifyAllLinkListeners(nFileId, LINK_MODIFIED); +} + +void ScExternalRefManager::breakLink(sal_uInt16 nFileId) +{ + lcl_removeByFileId(nFileId, maDocShells); + + if (maDocShells.empty()) + maSrcDocTimer.Stop(); + + LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId); + if (itr != maLinkedDocs.end()) + itr->second = false; + + notifyAllLinkListeners(nFileId, LINK_BROKEN); +} + +void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter) +{ + maSrcFiles[nFileId].maFileName = rNewFile; + maSrcFiles[nFileId].maRelativeName.Erase(); + maSrcFiles[nFileId].maRealFileName.Erase(); + if (!maSrcFiles[nFileId].maFilterName.Equals(rNewFilter)) + { + // Filter type has changed. + maSrcFiles[nFileId].maFilterName = rNewFilter; + maSrcFiles[nFileId].maFilterOptions.Erase(); + } + refreshNames(nFileId); +} + +void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl) +{ + if (nFileId >= maSrcFiles.size()) + return; + maSrcFiles[nFileId].maRelativeName = rRelUrl; +} + +void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions) +{ + if (nFileId >= maSrcFiles.size()) + return; + maSrcFiles[nFileId].maFilterName = rFilterName; + maSrcFiles[nFileId].maFilterOptions = rOptions; +} + +void ScExternalRefManager::clear() +{ + DocShellMap::iterator itrEnd = maDocShells.end(); + for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr) + itr->second.maShell->DoClose(); + + maDocShells.clear(); + maSrcDocTimer.Stop(); +} + +bool ScExternalRefManager::hasExternalData() const +{ + return !maSrcFiles.empty(); +} + +void ScExternalRefManager::resetSrcFileData(const String& rBaseFileUrl) +{ + for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end(); + itr != itrEnd; ++itr) + { + // Re-generate relative file name from the absolute file name. + String aAbsName = itr->maRealFileName; + if (!aAbsName.Len()) + aAbsName = itr->maFileName; + + itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative( + rBaseFileUrl, aAbsName); + } +} + +void ScExternalRefManager::updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + { + if (!bCopy) + itr->second.removeCell(rOldPos); + itr->second.insertCell(rNewPos); + } +} + +void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.moveTable(nOldTab, nNewTab, bCopy); +} + +void ScExternalRefManager::updateRefInsertTable(SCTAB nPos) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.insertTable(nPos); +} + +void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos) +{ + for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr) + itr->second.removeTable(nPos); +} + +void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener) +{ + LinkListenerMap::iterator itr = maLinkListeners.find(nFileId); + if (itr == maLinkListeners.end()) + { + pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert( + LinkListenerMap::value_type(nFileId, LinkListeners())); + if (!r.second) + { + DBG_ERROR("insertion of new link listener list failed"); + return; + } + + itr = r.first; + } + + LinkListeners& rList = itr->second; + rList.insert(pListener); +} + +void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener) +{ + LinkListenerMap::iterator itr = maLinkListeners.find(nFileId); + if (itr == maLinkListeners.end()) + // no listeners for a specified file. + return; + + LinkListeners& rList = itr->second; + rList.erase(pListener); + + if (rList.empty()) + // No more listeners for this file. Remove its entry. + maLinkListeners.erase(itr); +} + +void ScExternalRefManager::removeLinkListener(LinkListener* pListener) +{ + LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end(); + for (; itr != itrEnd; ++itr) + itr->second.erase(pListener); +} + +void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType) +{ + LinkListenerMap::iterator itr = maLinkListeners.find(nFileId); + if (itr == maLinkListeners.end()) + // no listeners for a specified file. + return; + + LinkListeners& rList = itr->second; + for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType)); +} + +void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut) +{ + DocShellMap aNewDocShells; + DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end(); + for (; itr != itrEnd; ++itr) + { + // in 100th of a second. + sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime(); + if (nSinceLastAccess < nTimeOut) + aNewDocShells.insert(*itr); + } + maDocShells.swap(aNewDocShells); + + if (maDocShells.empty()) + maSrcDocTimer.Stop(); +} + +sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc) +{ + NumFmtMap::iterator itr = maNumFormatMap.find(nFileId); + if (itr == maNumFormatMap.end()) + { + // Number formatter map is not initialized for this external document. + pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert( + NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap())); + + if (!r.second) + // insertion failed. + return nNumFmt; + + itr = r.first; + mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable()); + SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap(); + itr->second.swap(aMap); + } + const SvNumberFormatterMergeMap& rMap = itr->second; + SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt); + if (itrNumFmt != rMap.end()) + // mapped value found. + return itrNumFmt->second; + + return nNumFmt; +} + +IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer) +{ + if (pTimer == &maSrcDocTimer) + purgeStaleSrcDocument(SRCDOC_LIFE_SPAN); + + return 0; +} + diff --git a/sc/source/ui/docshell/hiranges.cxx b/sc/source/ui/docshell/hiranges.cxx new file mode 100644 index 000000000000..af1226216a06 --- /dev/null +++ b/sc/source/ui/docshell/hiranges.cxx @@ -0,0 +1,53 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include "hiranges.hxx" + +//================================================================== + +ScHighlightRanges::ScHighlightRanges() +{ +} + +ScHighlightRanges::~ScHighlightRanges() +{ + void* pEntry = aEntries.First(); + while ( pEntry ) + { + delete (ScHighlightEntry*) aEntries.Remove( pEntry ); + pEntry = aEntries.Next(); + } +} + + + + diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx new file mode 100644 index 000000000000..8fc49696ba59 --- /dev/null +++ b/sc/source/ui/docshell/impex.cxx @@ -0,0 +1,2076 @@ +/************************************************************************* + * + * 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" + +// System - Includes ----------------------------------------------------- + +class StarBASIC; + + + +#ifndef PCH +#include "sc.hrc" +#define GLOBALOVERFLOW +#endif + +// INCLUDE --------------------------------------------------------------- + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <osl/endian.h> +#include <i18npool/mslangid.hxx> +#include <tools/list.hxx> +#include <tools/string.hxx> +#include <rtl/math.hxx> +#include <svtools/htmlout.hxx> +#include <svl/zforlist.hxx> +#define _SVSTDARR_ULONGS +#include <svl/svstdarr.hxx> +#include <sot/formats.hxx> +#include <sfx2/mieclip.hxx> +#include <unotools/charclass.hxx> +#include <unotools/collatorwrapper.hxx> +#include <unotools/calendarwrapper.hxx> +#include <com/sun/star/i18n/CalendarFieldIndex.hpp> +#include <unotools/transliterationwrapper.hxx> + +#include "global.hxx" +#include "scerrors.hxx" +#include "docsh.hxx" +#include "undoblk.hxx" +#include "rangenam.hxx" +#include "viewdata.hxx" +#include "tabvwsh.hxx" +#include "filter.hxx" +#include "asciiopt.hxx" +#include "cell.hxx" +#include "docoptio.hxx" +#include "progress.hxx" +#include "scitems.hxx" +#include "editable.hxx" +#include "compiler.hxx" +#include "warnbox.hxx" + +#include "impex.hxx" + +// ause +#include "editutil.hxx" + +#include "globstr.hrc" +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <osl/module.hxx> + +//======================================================================== + +namespace +{ + const String SYLK_LF = String::CreateFromAscii("\x1b :"); + const String DOUBLE_SEMICOLON = String::CreateFromAscii(";;"); + const String DOUBLE_DOUBLEQUOTE = String::CreateFromAscii("\"\""); +} + +enum SylkVersion +{ + SYLK_SCALC3, // Wrote wrongly quoted strings and unescaped semicolons. + SYLK_OOO32, // Correct strings, plus multiline content. + SYLK_OWN, // Place our new versions, if any, before this value. + SYLK_OTHER // Assume that aliens wrote correct strings. +}; + + +// Gesamtdokument ohne Undo + + +ScImportExport::ScImportExport( ScDocument* p ) + : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), + nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), + bFormulas( FALSE ), bIncludeFiltered( TRUE ), + bAll( TRUE ), bSingle( TRUE ), bUndo( FALSE ), + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() +{ + pUndoDoc = NULL; + pExtOptions = NULL; +} + +// Insert am Punkt ohne Bereichschecks + + +ScImportExport::ScImportExport( ScDocument* p, const ScAddress& rPt ) + : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), + aRange( rPt ), + nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), + bFormulas( FALSE ), bIncludeFiltered( TRUE ), + bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ), + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() +{ + pUndoDoc = NULL; + pExtOptions = NULL; +} + + +// ctor with a range is only used for export +//! ctor with a string (and bSingle=TRUE) is also used for DdeSetData + +ScImportExport::ScImportExport( ScDocument* p, const ScRange& r ) + : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), + aRange( r ), + nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), + bFormulas( FALSE ), bIncludeFiltered( TRUE ), + bAll( FALSE ), bSingle( FALSE ), bUndo( BOOL( pDocSh != NULL ) ), + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() +{ + pUndoDoc = NULL; + pExtOptions = NULL; + // Zur Zeit nur in einer Tabelle! + aRange.aEnd.SetTab( aRange.aStart.Tab() ); +} + +// String auswerten: Entweder Bereich, Punkt oder Gesamtdoc (bei Fehler) +// Falls eine View existiert, wird die TabNo der View entnommen! + + +ScImportExport::ScImportExport( ScDocument* p, const String& rPos ) + : pDocSh( PTR_CAST(ScDocShell,p->GetDocumentShell()) ), pDoc( p ), + nSizeLimit( 0 ), cSep( '\t' ), cStr( '"' ), + bFormulas( FALSE ), bIncludeFiltered( TRUE ), + bAll( FALSE ), bSingle( TRUE ), bUndo( BOOL( pDocSh != NULL ) ), + bOverflow( FALSE ), mbApi( true ), mExportTextOptions() +{ + pUndoDoc = NULL; + pExtOptions = NULL; + + SCTAB nTab = ScDocShell::GetCurTab(); + aRange.aStart.SetTab( nTab ); + String aPos( rPos ); + // Benannter Bereich? + ScRangeName* pRange = pDoc->GetRangeName(); + if( pRange ) + { + USHORT nPos; + if( pRange->SearchName( aPos, nPos ) ) + { + ScRangeData* pData = (*pRange)[ nPos ]; + if( pData->HasType( RT_REFAREA ) + || pData->HasType( RT_ABSAREA ) + || pData->HasType( RT_ABSPOS ) ) + pData->GetSymbol( aPos ); // mit dem Inhalt weitertesten + } + } + formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); + // Bereich? + if( aRange.Parse( aPos, pDoc, eConv ) & SCA_VALID ) + bSingle = FALSE; + // Zelle? + else if( aRange.aStart.Parse( aPos, pDoc, eConv ) & SCA_VALID ) + aRange.aEnd = aRange.aStart; + else + bAll = TRUE; +} + + +ScImportExport::~ScImportExport() +{ + delete pUndoDoc; + delete pExtOptions; +} + + +void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt ) +{ + if ( pExtOptions ) + *pExtOptions = rOpt; + else + pExtOptions = new ScAsciiOptions( rOpt ); + + // "normale" Optionen uebernehmen + + cSep = rOpt.GetFieldSeps().GetChar(0); + cStr = rOpt.GetTextSep(); +} + + +BOOL ScImportExport::IsFormatSupported( ULONG nFormat ) +{ + return BOOL( nFormat == FORMAT_STRING + || nFormat == SOT_FORMATSTR_ID_SYLK + || nFormat == SOT_FORMATSTR_ID_LINK + || nFormat == SOT_FORMATSTR_ID_HTML + || nFormat == SOT_FORMATSTR_ID_HTML_SIMPLE + || nFormat == SOT_FORMATSTR_ID_DIF ); +} + + +////////////////////////////////////////////////////////////////////////////// + +// Vorbereitung fuer Undo: Undo-Dokument erzeugen + + +BOOL ScImportExport::StartPaste() +{ + if ( !bAll ) + { + ScEditableTester aTester( pDoc, aRange ); + if ( !aTester.IsEditable() ) + { + InfoBox aInfoBox(Application::GetDefDialogParent(), + ScGlobal::GetRscString( aTester.GetMessageId() ) ); + aInfoBox.Execute(); + return FALSE; + } + } + if( bUndo && pDocSh && pDoc->IsUndoEnabled()) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() ); + pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, FALSE, pUndoDoc ); + } + return TRUE; +} + +// Nachbereitung Insert: Undo/Redo-Aktionen erzeugen, Invalidate/Repaint + + +void ScImportExport::EndPaste() +{ + BOOL bHeight = pDocSh && pDocSh->AdjustRowHeight( + aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() ); + + if( pUndoDoc && pDoc->IsUndoEnabled() ) + { + ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); + pRedoDoc->InitUndo( pDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() ); + pDoc->CopyToDocument( aRange, IDF_ALL | IDF_NOCAPTIONS, FALSE, pRedoDoc ); + ScMarkData aDestMark; + aDestMark.SelectOneTable( aRange.aStart.Tab() ); + pDocSh->GetUndoManager()->AddUndoAction( + new ScUndoPaste( pDocSh, + aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab(), + aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aEnd.Tab(), aDestMark, + pUndoDoc, pRedoDoc, IDF_ALL, NULL,NULL,NULL,NULL ) ); + } + pUndoDoc = NULL; + if( pDocSh ) + { + if (!bHeight) + pDocSh->PostPaint( aRange, PAINT_GRID ); // AdjustRowHeight paintet evtl. selber + pDocSh->SetDocumentModified(); + } + ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell(); + if ( pViewSh ) + pViewSh->UpdateInputHandler(); + +} + +///////////////////////////////////////////////////////////////////////////// + + +#if 0 +BOOL ScImportExport::ImportData( SvData& rData ) +{ + ULONG nFmt = rData.GetFormat(); + if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE ) + { + MSE40HTMLClipFormatObj aMSE40ClpObj; + if ( aMSE40ClpObj.GetData( rData ) ) + { + SvStream* pStream = aMSE40ClpObj.GetStream(); + return ImportStream( *pStream, nFmt ); + } + return FALSE; + } + else + { + void* pMem; + ULONG nSize = rData.GetMinMemorySize(); + rData.GetData( &pMem, TRANSFER_REFERENCE ); + if( nFmt == FORMAT_STRING + || nFmt == FORMAT_RTF + || nFmt == SOT_FORMATSTR_ID_SYLK + || nFmt == SOT_FORMATSTR_ID_HTML + || nFmt == SOT_FORMATSTR_ID_DIF ) + { + //! String? Unicode?? + + // Stringende ermitteln! + sal_Char* pBegin = (sal_Char*) pMem; + sal_Char* pEnd = (sal_Char*) pMem + nSize; + + nSize = 0; + while( pBegin != pEnd && *pBegin != '\0' ) + pBegin++, nSize++; + // #72909# MT says only STRING has to be zero-terminated + DBG_ASSERT( pBegin != pEnd || nFmt != FORMAT_STRING, "non zero-terminated String" ) + } + SvMemoryStream aStrm( pMem, nSize, STREAM_READ ); + return ImportStream( aStrm, nFmt ); + } +} + +#endif + +BOOL ScImportExport::ImportData( const String& /* rMimeType */, + const ::com::sun::star::uno::Any & /* rValue */ ) +{ + DBG_ASSERT( !this, "Implementation is missing" ); + return FALSE; +} + +BOOL ScImportExport::ExportData( const String& rMimeType, + ::com::sun::star::uno::Any & rValue ) +{ + SvMemoryStream aStrm; + // mba: no BaseURL for data exchange + if( ExportStream( aStrm, String(), + SotExchange::GetFormatIdFromMimeType( rMimeType ) )) + { + aStrm << (BYTE) 0; + rValue <<= ::com::sun::star::uno::Sequence< sal_Int8 >( + (sal_Int8*)aStrm.GetData(), + aStrm.Seek( STREAM_SEEK_TO_END ) ); + return TRUE; + } + return FALSE; +} + + +BOOL ScImportExport::ImportString( const ::rtl::OUString& rText, ULONG nFmt ) +{ + switch ( nFmt ) + { + // formats supporting unicode + case FORMAT_STRING : + { + ScImportStringStream aStrm( rText); + return ImportStream( aStrm, String(), nFmt ); + // ImportStream must handle RTL_TEXTENCODING_UNICODE + } + //break; + default: + { + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + ::rtl::OString aTmp( rText.getStr(), rText.getLength(), eEnc ); + SvMemoryStream aStrm( (void*)aTmp.getStr(), aTmp.getLength() * sizeof(sal_Char), STREAM_READ ); + aStrm.SetStreamCharSet( eEnc ); + SetNoEndianSwap( aStrm ); //! no swapping in memory + return ImportStream( aStrm, String(), nFmt ); + } + } +} + + +BOOL ScImportExport::ExportString( ::rtl::OUString& rText, ULONG nFmt ) +{ + DBG_ASSERT( nFmt == FORMAT_STRING, "ScImportExport::ExportString: Unicode not supported for other formats than FORMAT_STRING" ); + if ( nFmt != FORMAT_STRING ) + { + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + ByteString aTmp; + BOOL bOk = ExportByteString( aTmp, eEnc, nFmt ); + rText = UniString( aTmp, eEnc ); + return bOk; + } + // nSizeLimit not needed for OUString + + SvMemoryStream aStrm; + aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE ); + SetNoEndianSwap( aStrm ); //! no swapping in memory + // mba: no BaseURL for data exc + if( ExportStream( aStrm, String(), nFmt ) ) + { + aStrm << (sal_Unicode) 0; + aStrm.Seek( STREAM_SEEK_TO_END ); + + rText = rtl::OUString( (const sal_Unicode*) aStrm.GetData() ); + return TRUE; + } + rText = rtl::OUString(); + return FALSE; + + // ExportStream must handle RTL_TEXTENCODING_UNICODE +} + + +BOOL ScImportExport::ExportByteString( ByteString& rText, rtl_TextEncoding eEnc, ULONG nFmt ) +{ + DBG_ASSERT( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" ); + if ( eEnc == RTL_TEXTENCODING_UNICODE ) + eEnc = gsl_getSystemTextEncoding(); + + if (!nSizeLimit) + nSizeLimit = STRING_MAXLEN; + + SvMemoryStream aStrm; + aStrm.SetStreamCharSet( eEnc ); + SetNoEndianSwap( aStrm ); //! no swapping in memory + // mba: no BaseURL for data exchange + if( ExportStream( aStrm, String(), nFmt ) ) + { + aStrm << (sal_Char) 0; + aStrm.Seek( STREAM_SEEK_TO_END ); + // Sicherheits-Check: + if( aStrm.Tell() <= (ULONG) STRING_MAXLEN ) + { + rText = (const sal_Char*) aStrm.GetData(); + return TRUE; + } + } + rText.Erase(); + return FALSE; +} + + +BOOL ScImportExport::ImportStream( SvStream& rStrm, const String& rBaseURL, ULONG nFmt ) +{ + if( nFmt == FORMAT_STRING ) + { + if( ExtText2Doc( rStrm ) ) // pExtOptions auswerten + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_SYLK ) + { + if( Sylk2Doc( rStrm ) ) + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_DIF ) + { + if( Dif2Doc( rStrm ) ) + return TRUE; + } + if( nFmt == FORMAT_RTF ) + { + if( RTF2Doc( rStrm, rBaseURL ) ) + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_LINK ) + return TRUE; // Link-Import? + if ( nFmt == SOT_FORMATSTR_ID_HTML ) + { + if( HTML2Doc( rStrm, rBaseURL ) ) + return TRUE; + } + if ( nFmt == SOT_FORMATSTR_ID_HTML_SIMPLE ) + { + MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data + SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm ); + if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) ) + return TRUE; + } + + return FALSE; +} + + +BOOL ScImportExport::ExportStream( SvStream& rStrm, const String& rBaseURL, ULONG nFmt ) +{ + if( nFmt == FORMAT_STRING ) + { + if( Doc2Text( rStrm ) ) + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_SYLK ) + { + if( Doc2Sylk( rStrm ) ) + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_DIF ) + { + if( Doc2Dif( rStrm ) ) + return TRUE; + } + if( nFmt == SOT_FORMATSTR_ID_LINK && !bAll ) + { + String aDocName; + if ( pDoc->IsClipboard() ) + aDocName = ScGlobal::GetClipDocName(); + else + { + SfxObjectShell* pShell = pDoc->GetDocumentShell(); + if (pShell) + aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME ); + } + + DBG_ASSERT( aDocName.Len(), "ClipBoard document has no name! :-/" ); + if( aDocName.Len() ) + { + String aRefName; + USHORT nFlags = SCA_VALID | SCA_TAB_3D; + if( bSingle ) + aRange.aStart.Format( aRefName, nFlags, pDoc, pDoc->GetAddressConvention() ); + else + { + if( aRange.aStart.Tab() != aRange.aEnd.Tab() ) + nFlags |= SCA_TAB2_3D; + aRange.Format( aRefName, nFlags, pDoc ); + } + String aAppName = Application::GetAppName(); + + WriteUnicodeOrByteString( rStrm, aAppName, TRUE ); + WriteUnicodeOrByteString( rStrm, aDocName, TRUE ); + WriteUnicodeOrByteString( rStrm, aRefName, TRUE ); + if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) + rStrm << sal_Unicode(0); + else + rStrm << sal_Char(0); + return BOOL( rStrm.GetError() == SVSTREAM_OK ); + } + } + if( nFmt == SOT_FORMATSTR_ID_HTML ) + { + if( Doc2HTML( rStrm, rBaseURL ) ) + return TRUE; + } + if( nFmt == FORMAT_RTF ) + { + if( Doc2RTF( rStrm ) ) + return TRUE; + } + + return FALSE; +} + + +//static +void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const String& rString, BOOL bZero ) +{ + rtl_TextEncoding eEnc = rStrm.GetStreamCharSet(); + if ( eEnc == RTL_TEXTENCODING_UNICODE ) + { + if ( !IsEndianSwap( rStrm ) ) + rStrm.Write( rString.GetBuffer(), rString.Len() * sizeof(sal_Unicode) ); + else + { + const sal_Unicode* p = rString.GetBuffer(); + const sal_Unicode* const pStop = p + rString.Len(); + while ( p < pStop ) + { + rStrm << *p; + } + } + if ( bZero ) + rStrm << sal_Unicode(0); + } + else + { + ByteString aByteStr( rString, eEnc ); + rStrm << aByteStr.GetBuffer(); + if ( bZero ) + rStrm << sal_Char(0); + } +} + + +// This function could be replaced by endlub() +// static +void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm ) +{ + if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) + { // same as endl() but unicode + switch ( rStrm.GetLineDelimiter() ) + { + case LINEEND_CR : + rStrm << sal_Unicode(_CR); + break; + case LINEEND_LF : + rStrm << sal_Unicode(_LF); + break; + default: + rStrm << sal_Unicode(_CR) << sal_Unicode(_LF); + } + } + else + endl( rStrm ); +} + + +enum DoubledQuoteMode +{ + DQM_KEEP, // both are taken + DQM_ESCAPE, // escaped quote, one is taken, one ignored + DQM_CONCAT, // first is end, next is start, both ignored => strings combined + DQM_SEPARATE // end one string and begin next +}; + +static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, String& rString, + sal_Unicode cStr, DoubledQuoteMode eMode ) +{ + p++; //! jump over opening quote + BOOL bCont; + do + { + bCont = FALSE; + const sal_Unicode* p0 = p; + for( ;; ) + { + if( !*p ) + break; + if( *p == cStr ) + { + if ( *++p != cStr ) + break; + // doubled quote char + switch ( eMode ) + { + case DQM_KEEP : + p++; // both for us (not breaking for-loop) + break; + case DQM_ESCAPE : + p++; // one for us (breaking for-loop) + bCont = TRUE; // and more + break; + case DQM_CONCAT : + if ( p0+1 < p ) + rString.Append( p0, sal::static_int_cast<xub_StrLen>( (p-1) - p0 ) ); // first part + p0 = ++p; // text of next part starts here + break; + case DQM_SEPARATE : + // positioned on next opening quote + break; + } + if ( eMode == DQM_ESCAPE || eMode == DQM_SEPARATE ) + break; + } + else + p++; + } + if ( p0 < p ) + rString.Append( p0, sal::static_int_cast<xub_StrLen>( ((*p || *(p-1) == cStr) ? p-1 : p) - p0 ) ); + } while ( bCont ); + return p; +} + +void lcl_UnescapeSylk( String & rString, SylkVersion eVersion ) +{ + // Older versions didn't escape the semicolon. + // Older versions quoted the string and doubled embedded quotes, but not + // the semicolons, which was plain wrong. + if (eVersion >= SYLK_OOO32) + rString.SearchAndReplaceAll( DOUBLE_SEMICOLON, ';' ); + else + rString.SearchAndReplaceAll( DOUBLE_DOUBLEQUOTE, '"' ); + + rString.SearchAndReplaceAll( SYLK_LF, _LF ); +} + +static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p, + String& rString, SylkVersion eVersion ) +{ + const sal_Unicode* pStartQuote = p; + const sal_Unicode* pEndQuote = 0; + while( *(++p) ) + { + if( *p == '"' ) + { + pEndQuote = p; + if (eVersion >= SYLK_OOO32) + { + if (*(p+1) == ';') + { + if (*(p+2) == ';') + { + p += 2; // escaped ';' + pEndQuote = 0; + } + else + break; // end field + } + } + else + { + if (*(p+1) == '"') + { + ++p; // escaped '"' + pEndQuote = 0; + } + else if (*(p+1) == ';') + break; // end field + } + } + } + if (!pEndQuote) + pEndQuote = p; // Take all data as string. + rString.Append( pStartQuote + 1, sal::static_int_cast<xub_StrLen>( pEndQuote - pStartQuote - 1 ) ); + lcl_UnescapeSylk( rString, eVersion); + return p; +} + +static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p, + String& rString, SylkVersion eVersion ) +{ + const sal_Unicode* pStart = p; + if (eVersion >= SYLK_OOO32) + { + while (*p) + { + if (*p == ';') + { + if (*(p+1) == ';') + ++p; // escaped ';' + else + break; // end field + } + ++p; + } + rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); + lcl_UnescapeSylk( rString, eVersion); + } + else + { + // Nasty. If in old versions the formula contained a semicolon, it was + // quoted and embedded quotes were doubled, but semicolons were not. If + // there was no semicolon, it could still contain quotes and doubled + // embedded quotes if it was something like ="a""b", which was saved as + // E"a""b" as is and has to be preserved, even if older versions + // couldn't even load it correctly. However, theoretically another + // field might follow and thus the line contain a semicolon again, such + // as ...;E"a""b";... + bool bQuoted = false; + if (*p == '"') + { + // May be a quoted expression or just a string constant expression + // with quotes. + while (*(++p)) + { + if (*p == '"') + { + if (*(p+1) == '"') + ++p; // escaped '"' + else + break; // closing '"', had no ';' yet + } + else if (*p == ';') + { + bQuoted = true; // ';' within quoted expression + break; + } + } + p = pStart; + } + if (bQuoted) + p = lcl_ScanSylkString( p, rString, eVersion); + else + { + while (*p && *p != ';') + ++p; + rString.Append( pStart, sal::static_int_cast<xub_StrLen>( p - pStart)); + } + } + return p; +} + +static void lcl_DoubleEscapeChar( String& rString, sal_Unicode cStr ) +{ + xub_StrLen n = 0; + while( ( n = rString.Search( cStr, n ) ) != STRING_NOTFOUND ) + { + rString.Insert( cStr, n ); + n += 2; + } +} + +static void lcl_WriteString( SvStream& rStrm, String& rString, sal_Unicode cQuote, sal_Unicode cEsc ) +{ + if (cEsc) + lcl_DoubleEscapeChar( rString, cEsc ); + + if (cQuote) + { + rString.Insert( cQuote, 0 ); + rString.Append( cQuote ); + } + + ScImportExport::WriteUnicodeOrByteString( rStrm, rString ); +} + +inline void lcl_WriteSimpleString( SvStream& rStrm, const String& rString ) +{ + ScImportExport::WriteUnicodeOrByteString( rStrm, rString ); +} + +////////////////////////////////////////////////////////////////////////////// + + +BOOL ScImportExport::Text2Doc( SvStream& rStrm ) +{ + BOOL bOk = TRUE; + + SCCOL nStartCol = aRange.aStart.Col(); + SCROW nStartRow = aRange.aStart.Row(); + SCCOL nEndCol = aRange.aEnd.Col(); + SCROW nEndRow = aRange.aEnd.Row(); + ULONG nOldPos = rStrm.Tell(); + if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) + rStrm.StartReadingUnicodeText(); + BOOL bData = BOOL( !bSingle ); + if( !bSingle) + bOk = StartPaste(); + + while( bOk ) + { + ByteString aByteLine; + String aLine, aCell; + SCROW nRow = nStartRow; + rStrm.Seek( nOldPos ); + for( ;; ) + { + rStrm.ReadUniOrByteStringLine( aLine ); + if( rStrm.IsEof() ) + break; + SCCOL nCol = nStartCol; + const sal_Unicode* p = aLine.GetBuffer(); + while( *p ) + { + aCell.Erase(); + if( *p == cStr ) + { + p = lcl_ScanString( p, aCell, cStr, DQM_KEEP ); + while( *p && *p != cSep ) + p++; + if( *p ) + p++; + } + else + { + const sal_Unicode* q = p; + while( *p && *p != cSep ) + p++; + aCell.Assign( q, sal::static_int_cast<xub_StrLen>( p - q ) ); + if( *p ) + p++; + } + if (ValidCol(nCol) && ValidRow(nRow) ) + { + if( bSingle ) + { + if (nCol>nEndCol) nEndCol = nCol; + if (nRow>nEndRow) nEndRow = nRow; + } + if( bData && nCol <= nEndCol && nRow <= nEndRow ) + pDoc->SetString( nCol, nRow, aRange.aStart.Tab(), aCell ); + } + else // zuviele Spalten/Zeilen + bOverflow = TRUE; // beim Import Warnung ausgeben + ++nCol; + } + ++nRow; + } + + if( !bData ) + { + aRange.aEnd.SetCol( nEndCol ); + aRange.aEnd.SetRow( nEndRow ); + bOk = StartPaste(); + bData = TRUE; + } + else + break; + } + + EndPaste(); + return bOk; +} + + // + // erweiterter Ascii-Import + // + + +bool lcl_PutString( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, + const String& rStr, BYTE nColFormat, + ::utl::TransliterationWrapper& rTransliteration, + CalendarWrapper& rCalendar, + ::utl::TransliterationWrapper* pSecondTransliteration, + CalendarWrapper* pSecondCalendar ) +{ + bool bMultiLine = false; + if ( nColFormat == SC_COL_SKIP || !rStr.Len() || !ValidCol(nCol) || !ValidRow(nRow) ) + return bMultiLine; + + if ( nColFormat == SC_COL_TEXT ) + { + pDoc->PutCell( nCol, nRow, nTab, ScBaseCell::CreateTextCell( rStr, pDoc ) ); + return bMultiLine; + } + + if ( nColFormat == SC_COL_ENGLISH ) + { + //! SetString mit Extra-Flag ??? + + SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); + sal_uInt32 nEnglish = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US); + double fVal; + if ( pFormatter->IsNumberFormat( rStr, nEnglish, fVal ) ) + { + // Zahlformat wird nicht auf englisch gesetzt + pDoc->SetValue( nCol, nRow, nTab, fVal ); + return bMultiLine; + } + // sonst weiter mit SetString + } + else if ( nColFormat != SC_COL_STANDARD ) // Datumsformate + { + const USHORT nMaxNumberParts = 7; // Y-M-D h:m:s.t + xub_StrLen nLen = rStr.Len(); + xub_StrLen nStart[nMaxNumberParts]; + xub_StrLen nEnd[nMaxNumberParts]; + + USHORT nDP, nMP, nYP; + switch ( nColFormat ) + { + case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; break; + case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; break; + case SC_COL_DMY: + default: nDP = 0; nMP = 1; nYP = 2; break; + } + + USHORT nFound = 0; + BOOL bInNum = FALSE; + for ( xub_StrLen nPos=0; nPos<nLen && (bInNum || + nFound<nMaxNumberParts); nPos++ ) + { + if (bInNum && nFound == 3 && nColFormat == SC_COL_YMD && + nPos <= nStart[nFound]+2 && rStr.GetChar(nPos) == 'T') + bInNum = FALSE; // ISO-8601: YYYY-MM-DDThh:mm... + else if ((((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1)) + && ScGlobal::pCharClass->isLetterNumeric( rStr, nPos)) + || ScGlobal::pCharClass->isDigit( rStr, nPos)) + { + if (!bInNum) + { + bInNum = TRUE; + nStart[nFound] = nPos; + ++nFound; + } + nEnd[nFound-1] = nPos; + } + else + bInNum = FALSE; + } + + if ( nFound == 1 ) + { + // try to break one number (without separators) into date fields + + xub_StrLen nDateStart = nStart[0]; + xub_StrLen nDateLen = nEnd[0] + 1 - nDateStart; + + if ( nDateLen >= 5 && nDateLen <= 8 && + ScGlobal::pCharClass->isNumeric( rStr.Copy( nDateStart, nDateLen ) ) ) + { + // 6 digits: 2 each for day, month, year + // 8 digits: 4 for year, 2 each for day and month + // 5 or 7 digits: first field is shortened by 1 + + BOOL bLongYear = ( nDateLen >= 7 ); + BOOL bShortFirst = ( nDateLen == 5 || nDateLen == 7 ); + + USHORT nFieldStart = nDateStart; + for (USHORT nPos=0; nPos<3; nPos++) + { + USHORT nFieldEnd = nFieldStart + 1; // default: 2 digits + if ( bLongYear && nPos == nYP ) + nFieldEnd += 2; // 2 extra digits for long year + if ( bShortFirst && nPos == 0 ) + --nFieldEnd; // first field shortened? + + nStart[nPos] = nFieldStart; + nEnd[nPos] = nFieldEnd; + nFieldStart = nFieldEnd + 1; + } + nFound = 3; + } + } + + if ( nFound >= 3 ) + { + using namespace ::com::sun::star; + BOOL bSecondCal = FALSE; + USHORT nDay = (USHORT) rStr.Copy( nStart[nDP], nEnd[nDP]+1-nStart[nDP] ).ToInt32(); + USHORT nYear = (USHORT) rStr.Copy( nStart[nYP], nEnd[nYP]+1-nStart[nYP] ).ToInt32(); + String aMStr = rStr.Copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] ); + sal_Int16 nMonth = (sal_Int16) aMStr.ToInt32(); + if (!nMonth) + { + static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) ); + static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) ); + uno::Sequence< i18n::CalendarItem > xMonths; + sal_Int32 i, nMonthCount; + // first test all month names from local international + xMonths = rCalendar.getMonths(); + nMonthCount = xMonths.getLength(); + for (i=0; i<nMonthCount && !nMonth; i++) + { + if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) || + rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) ) + nMonth = sal::static_int_cast<sal_Int16>( i+1 ); + else if ( i == 8 && rTransliteration.isEqual( aSeptCorrect, + xMonths[i].AbbrevName ) && + rTransliteration.isEqual( aMStr, aSepShortened ) ) + { // #102136# correct English abbreviation is SEPT, + // but data mostly contains SEP only + nMonth = sal::static_int_cast<sal_Int16>( i+1 ); + } + } + // if none found, then test english month names + if ( !nMonth && pSecondCalendar && pSecondTransliteration ) + { + xMonths = pSecondCalendar->getMonths(); + nMonthCount = xMonths.getLength(); + for (i=0; i<nMonthCount && !nMonth; i++) + { + if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) || + pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) ) + { + nMonth = sal::static_int_cast<sal_Int16>( i+1 ); + bSecondCal = TRUE; + } + else if ( i == 8 && pSecondTransliteration->isEqual( + aMStr, aSepShortened ) ) + { // #102136# correct English abbreviation is SEPT, + // but data mostly contains SEP only + nMonth = sal::static_int_cast<sal_Int16>( i+1 ); + bSecondCal = TRUE; + } + } + } + } + + SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); + if ( nYear < 100 ) + nYear = pFormatter->ExpandTwoDigitYear( nYear ); + + CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar); + sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear(); + if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths ) + { + --nMonth; + pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay ); + pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth ); + pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear ); + sal_Int16 nHour, nMinute, nSecond, nMilli; + // #i14974# The imported value should have no fractional value, so set the + // time fields to zero (ICU calendar instance defaults to current date/time) + nHour = nMinute = nSecond = nMilli = 0; + if (nFound > 3) + nHour = (sal_Int16) rStr.Copy( nStart[3], nEnd[3]+1-nStart[3]).ToInt32(); + if (nFound > 4) + nMinute = (sal_Int16) rStr.Copy( nStart[4], nEnd[4]+1-nStart[4]).ToInt32(); + if (nFound > 5) + nSecond = (sal_Int16) rStr.Copy( nStart[5], nEnd[5]+1-nStart[5]).ToInt32(); + if (nFound > 6) + { + sal_Unicode cDec = '.'; + rtl::OUString aT( &cDec, 1); + aT += rStr.Copy( nStart[6], nEnd[6]+1-nStart[6]); + rtl_math_ConversionStatus eStatus; + double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus, 0); + if (eStatus == rtl_math_ConversionStatus_Ok) + nMilli = (sal_Int16) (1000.0 * fV + 0.5); + } + pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour ); + pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute ); + pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond ); + pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, nMilli ); + if ( pCalendar->isValid() ) + { + double fDiff = DateTime(*pFormatter->GetNullDate()) - + pCalendar->getEpochStart(); + // #i14974# must use getLocalDateTime to get the same + // date values as set above + double fDays = pCalendar->getLocalDateTime(); + fDays -= fDiff; + + LanguageType eLatin, eCjk, eCtl; + pDoc->GetLanguage( eLatin, eCjk, eCtl ); + LanguageType eDocLang = eLatin; //! which language for date formats? + + short nType = (nFound > 3 ? NUMBERFORMAT_DATETIME : NUMBERFORMAT_DATE); + ULONG nFormat = pFormatter->GetStandardFormat( nType, eDocLang ); + // maybe there is a special format including seconds or milliseconds + if (nFound > 5) + nFormat = pFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang); + + pDoc->PutCell( nCol, nRow, nTab, new ScValueCell(fDays), nFormat, FALSE ); + + return bMultiLine; // success + } + } + } + } + + // Standard or date not determined -> SetString / EditCell + if( rStr.Search( _LF ) == STRING_NOTFOUND ) + pDoc->SetString( nCol, nRow, nTab, rStr ); + else + { + bMultiLine = true; + pDoc->PutCell( nCol, nRow, nTab, new ScEditCell( rStr, pDoc ) ); + } + return bMultiLine; +} + + +String lcl_GetFixed( const String& rLine, xub_StrLen nStart, xub_StrLen nNext ) +{ + xub_StrLen nLen = rLine.Len(); + if (nNext > nLen) + nNext = nLen; + if ( nNext <= nStart ) + return EMPTY_STRING; + + const sal_Unicode* pStr = rLine.GetBuffer(); + + xub_StrLen nSpace = nNext; + while ( nSpace > nStart && pStr[nSpace-1] == ' ' ) + --nSpace; + + return rLine.Copy( nStart, nSpace-nStart ); +} + +BOOL ScImportExport::ExtText2Doc( SvStream& rStrm ) +{ + if (!pExtOptions) + return Text2Doc( rStrm ); + + ULONG nOldPos = rStrm.Tell(); + rStrm.Seek( STREAM_SEEK_TO_END ); + ::std::auto_ptr<ScProgress> xProgress( new ScProgress( pDocSh, + ScGlobal::GetRscString( STR_LOAD_DOC ), rStrm.Tell() - nOldPos )); + rStrm.Seek( nOldPos ); + if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE ) + rStrm.StartReadingUnicodeText(); + + BOOL bOld = ScColumn::bDoubleAlloc; + ScColumn::bDoubleAlloc = TRUE; + + SCCOL nStartCol = aRange.aStart.Col(); + SCCOL nEndCol = aRange.aEnd.Col(); + SCROW nStartRow = aRange.aStart.Row(); + SCTAB nTab = aRange.aStart.Tab(); + + BOOL bFixed = pExtOptions->IsFixedLen(); + const String& rSeps = pExtOptions->GetFieldSeps(); + const sal_Unicode* pSeps = rSeps.GetBuffer(); + BOOL bMerge = pExtOptions->IsMergeSeps(); + USHORT nInfoCount = pExtOptions->GetInfoCount(); + const xub_StrLen* pColStart = pExtOptions->GetColStart(); + const BYTE* pColFormat = pExtOptions->GetColFormat(); + long nSkipLines = pExtOptions->GetStartRow(); + + LanguageType eLatin, eCjk, eCtl; + pDoc->GetLanguage( eLatin, eCjk, eCtl ); + LanguageType eDocLang = eLatin; //! which language for date formats? + + // For date recognition + ::utl::TransliterationWrapper aTransliteration( + pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); + aTransliteration.loadModuleIfNeeded( eDocLang ); + CalendarWrapper aCalendar( pDoc->GetServiceManager() ); + aCalendar.loadDefaultCalendar( + MsLangId::convertLanguageToLocale( eDocLang ) ); + ::utl::TransliterationWrapper* pEnglishTransliteration = NULL; + CalendarWrapper* pEnglishCalendar = NULL; + if ( eDocLang != LANGUAGE_ENGLISH_US ) + { + pEnglishTransliteration = new ::utl::TransliterationWrapper ( + pDoc->GetServiceManager(), SC_TRANSLITERATION_IGNORECASE ); + aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US ); + pEnglishCalendar = new CalendarWrapper ( pDoc->GetServiceManager() ); + pEnglishCalendar->loadDefaultCalendar( + MsLangId::convertLanguageToLocale( LANGUAGE_ENGLISH_US ) ); + } + + String aLine, aCell; + USHORT i; + SCROW nRow = nStartRow; + + while(--nSkipLines>0) + { + rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); // content is ignored + if ( rStrm.IsEof() ) + break; + } + + // Determine range for Undo. + // TODO: we don't need this during import of a file to a new sheet or + // document, could set bDetermineRange=false then. + bool bDetermineRange = true; + + // Row heights don't need to be adjusted on the fly if EndPaste() is called + // afterwards, which happens only if bDetermineRange. This variable also + // survives the toggle of bDetermineRange down at the end of the do{} loop. + bool bRangeIsDetermined = bDetermineRange; + + ULONG nOriginalStreamPos = rStrm.Tell(); + + do + { + for( ;; ) + { + rStrm.ReadCsvLine( aLine, !bFixed, rSeps, cStr); + if ( rStrm.IsEof() ) + break; + + xub_StrLen nLineLen = aLine.Len(); + SCCOL nCol = nStartCol; + bool bMultiLine = false; + if ( bFixed ) // Feste Satzlaenge + { + // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an + // overflow if there is really data following to be put behind + // the last column, which doesn't happen if info is + // SC_COL_SKIP. + for ( i=0; i<nInfoCount && nCol <= MAXCOL+1; i++ ) + { + if ( pColFormat[i] != SC_COL_SKIP ) // sonst auch nCol nicht hochzaehlen + { + if (nCol > MAXCOL) + bOverflow = TRUE; // display warning on import + else if (!bDetermineRange) + { + xub_StrLen nStart = pColStart[i]; + xub_StrLen nNext = ( i+1 < nInfoCount ) ? pColStart[i+1] : nLineLen; + aCell = lcl_GetFixed( aLine, nStart, nNext ); + bMultiLine |= lcl_PutString( pDoc, nCol, nRow, + nTab, aCell, pColFormat[i], + aTransliteration, aCalendar, + pEnglishTransliteration, pEnglishCalendar); + } + ++nCol; + } + } + } + else // Nach Trennzeichen suchen + { + SCCOL nSourceCol = 0; + USHORT nInfoStart = 0; + const sal_Unicode* p = aLine.GetBuffer(); + // Yes, the check is nCol<=MAXCOL+1, +1 because it is only an + // overflow if there is really data following to be put behind + // the last column, which doesn't happen if info is + // SC_COL_SKIP. + while (*p && nCol <= MAXCOL+1) + { + p = ScImportExport::ScanNextFieldFromString( p, aCell, cStr, pSeps, bMerge ); + + BYTE nFmt = SC_COL_STANDARD; + for ( i=nInfoStart; i<nInfoCount; i++ ) + { + if ( pColStart[i] == nSourceCol + 1 ) // pColStart ist 1-basiert + { + nFmt = pColFormat[i]; + nInfoStart = i + 1; // ColInfos sind in Reihenfolge + break; // for + } + } + if ( nFmt != SC_COL_SKIP ) + { + if (nCol > MAXCOL) + bOverflow = TRUE; // display warning on import + else if (!bDetermineRange) + bMultiLine |= lcl_PutString( pDoc, nCol, nRow, + nTab, aCell, nFmt, aTransliteration, + aCalendar, pEnglishTransliteration, + pEnglishCalendar); + ++nCol; + } + + ++nSourceCol; + } + } + if (nEndCol < nCol) + nEndCol = nCol; //! points to the next free or even MAXCOL+2 + + if (!bDetermineRange) + { + if (bMultiLine && !bRangeIsDetermined && pDocSh) + pDocSh->AdjustRowHeight( nRow, nRow, nTab); + xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos ); + } + ++nRow; + if ( nRow > MAXROW ) + { + bOverflow = TRUE; // display warning on import + break; // for + } + } + // so far nRow/nEndCol pointed to the next free + if (nRow > nStartRow) + --nRow; + if (nEndCol > nStartCol) + nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), MAXCOL); + + if (bDetermineRange) + { + aRange.aEnd.SetCol( nEndCol ); + aRange.aEnd.SetRow( nRow ); + + if ( !mbApi && nStartCol != nEndCol && + !pDoc->IsBlockEmpty( nTab, nStartCol + 1, nStartRow, nEndCol, nRow ) ) + { + ScReplaceWarnBox aBox( pDocSh->GetActiveDialogParent() ); + if ( aBox.Execute() != RET_YES ) + { + delete pEnglishTransliteration; + delete pEnglishCalendar; + return FALSE; + } + } + + rStrm.Seek( nOriginalStreamPos ); + nRow = nStartRow; + if (!StartPaste()) + { + EndPaste(); + return FALSE; + } + } + + bDetermineRange = !bDetermineRange; // toggle + } while (!bDetermineRange); + + ScColumn::bDoubleAlloc = bOld; + pDoc->DoColResize( nTab, nStartCol, nEndCol, 0 ); + + delete pEnglishTransliteration; + delete pEnglishCalendar; + + xProgress.reset(); // make room for AdjustRowHeight progress + if (bRangeIsDetermined) + EndPaste(); + + return TRUE; +} + + +// static +const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p, + String& rField, sal_Unicode cStr, const sal_Unicode* pSeps, BOOL bMergeSeps ) +{ + rField.Erase(); + if ( *p == cStr ) // String in Anfuehrungszeichen + { + const sal_Unicode* p1; + p1 = p = lcl_ScanString( p, rField, cStr, DQM_ESCAPE ); + while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) + p++; + // Append remaining unquoted and undelimited data (dirty, dirty) to + // this field. + if (p > p1) + rField.Append( p1, sal::static_int_cast<xub_StrLen>( p - p1 ) ); + if( *p ) + p++; + } + else // bis zum Trennzeichen + { + const sal_Unicode* p0 = p; + while ( *p && !ScGlobal::UnicodeStrChr( pSeps, *p ) ) + p++; + rField.Append( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); + if( *p ) + p++; + } + if ( bMergeSeps ) // folgende Trennzeichen ueberspringen + { + while ( *p && ScGlobal::UnicodeStrChr( pSeps, *p ) ) + p++; + } + return p; +} + + // + // + // + + +BOOL ScImportExport::Doc2Text( SvStream& rStrm ) +{ + SCCOL nCol; + SCROW nRow; + SCCOL nStartCol = aRange.aStart.Col(); + SCROW nStartRow = aRange.aStart.Row(); + SCCOL nEndCol = aRange.aEnd.Col(); + SCROW nEndRow = aRange.aEnd.Row(); + String aCell; + bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF); + + for (nRow = nStartRow; nRow <= nEndRow; nRow++) + { + if (bIncludeFiltered || !pDoc->IsFiltered( nRow, aRange.aStart.Tab() )) + { + for (nCol = nStartCol; nCol <= nEndCol; nCol++) + { + CellType eType; + pDoc->GetCellType( nCol, nRow, aRange.aStart.Tab(), eType ); + switch (eType) + { + case CELLTYPE_FORMULA: + { + if (bFormulas) + { + pDoc->GetFormula( nCol, nRow, aRange.aStart.Tab(), aCell, TRUE ); + if( aCell.Search( cSep ) != STRING_NOTFOUND ) + lcl_WriteString( rStrm, aCell, cStr, cStr ); + else + lcl_WriteSimpleString( rStrm, aCell ); + } + else + { + pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); + + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); + if( bMultiLineText ) + { + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) + aCell.SearchAndReplaceAll( _LF, ' ' ); + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) + aCell.ConvertLineEnd(); + } + + if( mExportTextOptions.mcSeparatorConvertTo && cSep ) + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); + + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) + lcl_WriteString( rStrm, aCell, cStr, cStr ); + else + lcl_WriteSimpleString( rStrm, aCell ); + } + } + break; + case CELLTYPE_VALUE: + { + pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); + lcl_WriteSimpleString( rStrm, aCell ); + } + break; + case CELLTYPE_NOTE: + case CELLTYPE_NONE: + break; + default: + { + pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCell ); + + bool bMultiLineText = ( aCell.Search( _LF ) != STRING_NOTFOUND ); + if( bMultiLineText ) + { + if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace ) + aCell.SearchAndReplaceAll( _LF, ' ' ); + else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF ) + aCell.ConvertLineEnd(); + } + + if( mExportTextOptions.mcSeparatorConvertTo && cSep ) + aCell.SearchAndReplaceAll( cSep, mExportTextOptions.mcSeparatorConvertTo ); + + if( mExportTextOptions.mbAddQuotes && ( aCell.Search( cSep ) != STRING_NOTFOUND ) ) + lcl_WriteString( rStrm, aCell, cStr, cStr ); + else + lcl_WriteSimpleString( rStrm, aCell ); + } + } + if( nCol < nEndCol ) + lcl_WriteSimpleString( rStrm, String(cSep) ); + } +// if( nRow < nEndRow ) + WriteUnicodeOrByteEndl( rStrm ); + if( rStrm.GetError() != SVSTREAM_OK ) + break; + if( nSizeLimit && rStrm.Tell() > nSizeLimit ) + break; + } + } + + return BOOL( rStrm.GetError() == SVSTREAM_OK ); +} + + +BOOL ScImportExport::Sylk2Doc( SvStream& rStrm ) +{ + BOOL bOk = TRUE; + BOOL bMyDoc = FALSE; + SylkVersion eVersion = SYLK_OTHER; + + // US-English separators for StringToDouble + sal_Unicode cDecSep = '.'; + sal_Unicode cGrpSep = ','; + + SCCOL nStartCol = aRange.aStart.Col(); + SCROW nStartRow = aRange.aStart.Row(); + SCCOL nEndCol = aRange.aEnd.Col(); + SCROW nEndRow = aRange.aEnd.Row(); + ULONG nOldPos = rStrm.Tell(); + BOOL bData = BOOL( !bSingle ); + SvULongs aFormats; + + if( !bSingle) + bOk = StartPaste(); + + while( bOk ) + { + String aLine; + String aText; + ByteString aByteLine; + SCCOL nCol = nStartCol; + SCROW nRow = nStartRow; + SCCOL nRefCol = 1; + SCROW nRefRow = 1; + rStrm.Seek( nOldPos ); + for( ;; ) + { + //! allow unicode + rStrm.ReadLine( aByteLine ); + aLine = String( aByteLine, rStrm.GetStreamCharSet() ); + if( rStrm.IsEof() ) + break; + const sal_Unicode* p = aLine.GetBuffer(); + sal_Unicode cTag = *p++; + if( cTag == 'C' ) // Content + { + if( *p++ != ';' ) + return FALSE; + while( *p ) + { + sal_Unicode ch = *p++; + ch = ScGlobal::ToUpperAlpha( ch ); + switch( ch ) + { + case 'X': + nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; + break; + case 'Y': + nRow = String( p ).ToInt32() + nStartRow - 1; + break; + case 'C': + nRefCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; + break; + case 'R': + nRefRow = String( p ).ToInt32() + nStartRow - 1; + break; + case 'K': + { + if( !bSingle && + ( nCol < nStartCol || nCol > nEndCol + || nRow < nStartRow || nRow > nEndRow + || nCol > MAXCOL || nRow > MAXROW ) ) + break; + if( !bData ) + { + if( nRow > nEndRow ) + nEndRow = nRow; + if( nCol > nEndCol ) + nEndCol = nCol; + break; + } + BOOL bText; + if( *p == '"' ) + { + bText = TRUE; + aText.Erase(); + p = lcl_ScanSylkString( p, aText, eVersion); + } + else + bText = FALSE; + const sal_Unicode* q = p; + while( *q && *q != ';' ) + q++; + if ( !(*q == ';' && *(q+1) == 'I') ) + { // don't ignore value + if( bText ) + { + pDoc->PutCell( nCol, nRow, aRange.aStart.Tab(), + ScBaseCell::CreateTextCell( aText, pDoc), + (BOOL) TRUE); + } + else + { + double fVal = rtl_math_uStringToDouble( p, + aLine.GetBuffer() + aLine.Len(), + cDecSep, cGrpSep, NULL, NULL ); + pDoc->SetValue( nCol, nRow, aRange.aStart.Tab(), fVal ); + } + } + } + break; + case 'E': + case 'M': + { + if ( ch == 'M' ) + { + if ( nRefCol < nCol ) + nRefCol = nCol; + if ( nRefRow < nRow ) + nRefRow = nRow; + if ( !bData ) + { + if( nRefRow > nEndRow ) + nEndRow = nRefRow; + if( nRefCol > nEndCol ) + nEndCol = nRefCol; + } + } + if( !bMyDoc || !bData ) + break; + aText = '='; + p = lcl_ScanSylkFormula( p, aText, eVersion); + ScAddress aPos( nCol, nRow, aRange.aStart.Tab() ); + /* FIXME: do we want GRAM_ODFF_A1 instead? At the + * end it probably should be GRAM_ODFF_R1C1, since + * R1C1 is what Excel writes in SYLK. */ + const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1; + ScCompiler aComp( pDoc, aPos); + aComp.SetGrammar(eGrammar); + ScTokenArray* pCode = aComp.CompileString( aText ); + if ( ch == 'M' ) + { + ScMarkData aMark; + aMark.SelectTable( aPos.Tab(), TRUE ); + pDoc->InsertMatrixFormula( nCol, nRow, nRefCol, + nRefRow, aMark, EMPTY_STRING, pCode ); + } + else + { + ScFormulaCell* pFCell = new ScFormulaCell( + pDoc, aPos, pCode, eGrammar, MM_NONE); + pDoc->PutCell( aPos, pFCell ); + } + delete pCode; // ctor/InsertMatrixFormula did copy TokenArray + } + break; + } + while( *p && *p != ';' ) + p++; + if( *p ) + p++; + } + } + else if( cTag == 'F' ) // Format + { + if( *p++ != ';' ) + return FALSE; + sal_Int32 nFormat = -1; + while( *p ) + { + sal_Unicode ch = *p++; + ch = ScGlobal::ToUpperAlpha( ch ); + switch( ch ) + { + case 'X': + nCol = static_cast<SCCOL>(String( p ).ToInt32()) + nStartCol - 1; + break; + case 'Y': + nRow = String( p ).ToInt32() + nStartRow - 1; + break; + case 'P' : + if ( bData ) + { + // F;P<n> sets format code of P;P<code> at + // current position, or at ;X;Y if specified. + // Note that ;X;Y may appear after ;P + const sal_Unicode* p0 = p; + while( *p && *p != ';' ) + p++; + String aNumber( p0, sal::static_int_cast<xub_StrLen>( p - p0 ) ); + nFormat = aNumber.ToInt32(); + } + break; + } + while( *p && *p != ';' ) + p++; + if( *p ) + p++; + } + if ( !bData ) + { + if( nRow > nEndRow ) + nEndRow = nRow; + if( nCol > nEndCol ) + nEndCol = nCol; + } + if ( 0 <= nFormat && nFormat < aFormats.Count() ) + { + ULONG nKey = aFormats[(USHORT)nFormat]; + pDoc->ApplyAttr( nCol, nRow, aRange.aStart.Tab(), + SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) ); + } + } + else if( cTag == 'P' ) + { + if ( bData && *p == ';' && *(p+1) == 'P' ) + { + String aCode( p+2 ); + // unescape doubled semicolons + xub_StrLen nPos = 0; + String aSemicolon( RTL_CONSTASCII_USTRINGPARAM(";;")); + while ( (nPos = aCode.Search( aSemicolon, nPos )) != STRING_NOTFOUND ) + aCode.Erase( nPos++, 1 ); + // get rid of Xcl escape characters + nPos = 0; + while ( (nPos = aCode.Search( sal_Unicode(0x1b), nPos )) != STRING_NOTFOUND ) + aCode.Erase( nPos, 1 ); + xub_StrLen nCheckPos; + short nType; + sal_uInt32 nKey; + pDoc->GetFormatTable()->PutandConvertEntry( + aCode, nCheckPos, nType, nKey, LANGUAGE_ENGLISH_US, + ScGlobal::eLnge ); + if ( nCheckPos ) + nKey = 0; + aFormats.Insert( nKey, aFormats.Count() ); + } + } + else if( cTag == 'I' && *p == 'D' ) + { + aLine.Erase( 0, 4 ); + if (aLine.EqualsAscii( "CALCOOO32" )) + eVersion = SYLK_OOO32; + else if (aLine.EqualsAscii( "SCALC3" )) + eVersion = SYLK_SCALC3; + bMyDoc = (eVersion <= SYLK_OWN); + } + else if( cTag == 'E' ) // Ende + break; + } + if( !bData ) + { + aRange.aEnd.SetCol( nEndCol ); + aRange.aEnd.SetRow( nEndRow ); + bOk = StartPaste(); + bData = TRUE; + } + else + break; + } + + EndPaste(); + return bOk; +} + + +BOOL ScImportExport::Doc2Sylk( SvStream& rStrm ) +{ + SCCOL nCol; + SCROW nRow; + SCCOL nStartCol = aRange.aStart.Col(); + SCROW nStartRow = aRange.aStart.Row(); + SCCOL nEndCol = aRange.aEnd.Col(); + SCROW nEndRow = aRange.aEnd.Row(); + String aCellStr; + String aValStr; + lcl_WriteSimpleString( rStrm, + String( RTL_CONSTASCII_USTRINGPARAM( "ID;PCALCOOO32"))); + WriteUnicodeOrByteEndl( rStrm ); + + for (nRow = nStartRow; nRow <= nEndRow; nRow++) + { + for (nCol = nStartCol; nCol <= nEndCol; nCol++) + { + String aBufStr; + double nVal; + BOOL bForm = FALSE; + SCROW r = nRow - nStartRow + 1; + SCCOL c = nCol - nStartCol + 1; + ScBaseCell* pCell; + pDoc->GetCell( nCol, nRow, aRange.aStart.Tab(), pCell ); + CellType eType = (pCell ? pCell->GetCellType() : CELLTYPE_NONE); + switch( eType ) + { + case CELLTYPE_FORMULA: + bForm = bFormulas; + if( pDoc->HasValueData( nCol, nRow, aRange.aStart.Tab()) ) + goto hasvalue; + else + goto hasstring; + + case CELLTYPE_VALUE: + hasvalue: + pDoc->GetValue( nCol, nRow, aRange.aStart.Tab(), nVal ); + + aValStr = ::rtl::math::doubleToUString( nVal, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', TRUE ); + + aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); + aBufStr += String::CreateFromInt32( c ); + aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); + aBufStr += String::CreateFromInt32( r ); + aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); + aBufStr += aValStr; + lcl_WriteSimpleString( rStrm, aBufStr ); + goto checkformula; + + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + hasstring: + pDoc->GetString( nCol, nRow, aRange.aStart.Tab(), aCellStr ); + aCellStr.SearchAndReplaceAll( _LF, SYLK_LF ); + + aBufStr.AssignAscii(RTL_CONSTASCII_STRINGPARAM( "C;X" )); + aBufStr += String::CreateFromInt32( c ); + aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";Y" )); + aBufStr += String::CreateFromInt32( r ); + aBufStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ";K" )); + lcl_WriteSimpleString( rStrm, aBufStr ); + lcl_WriteString( rStrm, aCellStr, '"', ';' ); + + checkformula: + if( bForm ) + { + const ScFormulaCell* pFCell = + static_cast<const ScFormulaCell*>(pCell); + switch ( pFCell->GetMatrixFlag() ) + { + case MM_REFERENCE : + aCellStr.Erase(); + break; + default: + pFCell->GetFormula( aCellStr,formula::FormulaGrammar::GRAM_PODF_A1); + /* FIXME: do we want GRAM_ODFF_A1 instead? At + * the end it probably should be + * GRAM_ODFF_R1C1, since R1C1 is what Excel + * writes in SYLK. */ + } + if ( pFCell->GetMatrixFlag() != MM_NONE && + aCellStr.Len() > 2 && + aCellStr.GetChar(0) == '{' && + aCellStr.GetChar(aCellStr.Len()-1) == '}' ) + { // cut off matrix {} characters + aCellStr.Erase(aCellStr.Len()-1,1); + aCellStr.Erase(0,1); + } + if ( aCellStr.GetChar(0) == '=' ) + aCellStr.Erase(0,1); + String aPrefix; + switch ( pFCell->GetMatrixFlag() ) + { + case MM_FORMULA : + { // diff expression with 'M' M$-extension + SCCOL nC; + SCROW nR; + pFCell->GetMatColsRows( nC, nR ); + nC += c - 1; + nR += r - 1; + aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";R" ) ); + aPrefix += String::CreateFromInt32( nR ); + aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); + aPrefix += String::CreateFromInt32( nC ); + aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";M" ) ); + } + break; + case MM_REFERENCE : + { // diff expression with 'I' M$-extension + ScAddress aPos; + pFCell->GetMatrixOrigin( aPos ); + aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";I;R" ) ); + aPrefix += String::CreateFromInt32( aPos.Row() - nStartRow + 1 ); + aPrefix.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ";C" ) ); + aPrefix += String::CreateFromInt32( aPos.Col() - nStartCol + 1 ); + } + break; + default: + // formula Expression + aPrefix.AssignAscii( RTL_CONSTASCII_STRINGPARAM( ";E" ) ); + } + lcl_WriteSimpleString( rStrm, aPrefix ); + if ( aCellStr.Len() ) + lcl_WriteString( rStrm, aCellStr, 0, ';' ); + } + WriteUnicodeOrByteEndl( rStrm ); + break; + + default: + { + // added to avoid warnings + } + } + } + } + lcl_WriteSimpleString( rStrm, String( 'E' ) ); + WriteUnicodeOrByteEndl( rStrm ); + return BOOL( rStrm.GetError() == SVSTREAM_OK ); +} + + +BOOL ScImportExport::Doc2HTML( SvStream& rStrm, const String& rBaseURL ) +{ + // CharSet is ignored in ScExportHTML, read from Load/Save HTML options + ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll, + aStreamPath, aNonConvertibleChars ); + return BOOL( rStrm.GetError() == SVSTREAM_OK ); +} + +BOOL ScImportExport::Doc2RTF( SvStream& rStrm ) +{ + // CharSet is ignored in ScExportRTF + ScFormatFilter::Get().ScExportRTF( rStrm, pDoc, aRange, RTL_TEXTENCODING_DONTKNOW ); + return BOOL( rStrm.GetError() == SVSTREAM_OK ); +} + + +BOOL ScImportExport::Doc2Dif( SvStream& rStrm ) +{ + // for DIF in the clipboard, IBM_850 is always used + ScFormatFilter::Get().ScExportDif( rStrm, pDoc, aRange, RTL_TEXTENCODING_IBM_850 ); + return TRUE; +} + + +BOOL ScImportExport::Dif2Doc( SvStream& rStrm ) +{ + SCTAB nTab = aRange.aStart.Tab(); + ScDocument* pImportDoc = new ScDocument( SCDOCMODE_UNDO ); + pImportDoc->InitUndo( pDoc, nTab, nTab ); + + // for DIF in the clipboard, IBM_850 is always used + ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc, aRange.aStart, RTL_TEXTENCODING_IBM_850 ); + + SCCOL nEndCol; + SCROW nEndRow; + pImportDoc->GetCellArea( nTab, nEndCol, nEndRow ); + // #131247# if there are no cells in the imported content, nEndCol/nEndRow may be before the start + if ( nEndCol < aRange.aStart.Col() ) + nEndCol = aRange.aStart.Col(); + if ( nEndRow < aRange.aStart.Row() ) + nEndRow = aRange.aStart.Row(); + aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab ); + + BOOL bOk = StartPaste(); + if (bOk) + { + USHORT nFlags = IDF_ALL & ~IDF_STYLES; + pDoc->DeleteAreaTab( aRange, nFlags ); + pImportDoc->CopyToDocument( aRange, nFlags, FALSE, pDoc ); + EndPaste(); + } + + delete pImportDoc; + + return bOk; +} + + +BOOL ScImportExport::RTF2Doc( SvStream& rStrm, const String& rBaseURL ) +{ + ScEEAbsImport *pImp = ScFormatFilter::Get().CreateRTFImport( pDoc, aRange ); + if (!pImp) + return false; + pImp->Read( rStrm, rBaseURL ); + aRange = pImp->GetRange(); + + BOOL bOk = StartPaste(); + if (bOk) + { + USHORT nFlags = IDF_ALL & ~IDF_STYLES; + pDoc->DeleteAreaTab( aRange, nFlags ); + pImp->WriteToDocument(); + EndPaste(); + } + delete pImp; + return bOk; +} + + +BOOL ScImportExport::HTML2Doc( SvStream& rStrm, const String& rBaseURL ) +{ + ScEEAbsImport *pImp = ScFormatFilter::Get().CreateHTMLImport( pDoc, rBaseURL, aRange, TRUE); + if (!pImp) + return false; + pImp->Read( rStrm, rBaseURL ); + aRange = pImp->GetRange(); + + BOOL bOk = StartPaste(); + if (bOk) + { + // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in + // a Draw Layer but no Draw View -> create Draw Layer and View here + if (pDocSh) + pDocSh->MakeDrawLayer(); + + USHORT nFlags = IDF_ALL & ~IDF_STYLES; + pDoc->DeleteAreaTab( aRange, nFlags ); + pImp->WriteToDocument(); + EndPaste(); + } + delete pImp; + return bOk; +} + +#define RETURN_ERROR { return eERR_INTERN; } +class ScFormatFilterMissing : public ScFormatFilterPlugin { + public: + ScFormatFilterMissing() + { + OSL_ASSERT ("Missing file filters"); + } + virtual FltError ScImportLotus123( SfxMedium&, ScDocument*, CharSet ) RETURN_ERROR + virtual FltError ScImportQuattroPro( SfxMedium &, ScDocument * ) RETURN_ERROR + virtual FltError ScImportExcel( SfxMedium&, ScDocument*, const EXCIMPFORMAT ) RETURN_ERROR + virtual FltError ScImportStarCalc10( SvStream&, ScDocument* ) RETURN_ERROR + virtual FltError ScImportDif( SvStream&, ScDocument*, const ScAddress&, + const CharSet, UINT32 ) RETURN_ERROR + virtual FltError ScImportRTF( SvStream&, const String&, ScDocument*, ScRange& ) RETURN_ERROR + virtual FltError ScImportHTML( SvStream&, const String&, ScDocument*, ScRange&, double, BOOL ) RETURN_ERROR + + virtual ScEEAbsImport *CreateRTFImport( ScDocument*, const ScRange& ) { return NULL; } + virtual ScEEAbsImport *CreateHTMLImport( ScDocument*, const String&, const ScRange&, BOOL ) { return NULL; } + virtual String GetHTMLRangeNameList( ScDocument*, const String& ) { return String(); } + +#if ENABLE_LOTUS123_EXPORT + virtual FltError ScExportLotus123( SvStream&, ScDocument*, ExportFormatLotus, CharSet ) RETURN_ERROR +#endif + virtual FltError ScExportExcel5( SfxMedium&, ScDocument*, ExportFormatExcel, CharSet ) RETURN_ERROR + virtual FltError ScExportDif( SvStream&, ScDocument*, const ScAddress&, const CharSet, UINT32 ) RETURN_ERROR + virtual FltError ScExportDif( SvStream&, ScDocument*, const ScRange&, const CharSet, UINT32 ) RETURN_ERROR + virtual FltError ScExportHTML( SvStream&, const String&, ScDocument*, const ScRange&, const CharSet, BOOL, + const String&, String& ) RETURN_ERROR + virtual FltError ScExportRTF( SvStream&, ScDocument*, const ScRange&, const CharSet ) RETURN_ERROR +}; + +extern "C" { static void SAL_CALL thisModule() {} } +typedef ScFormatFilterPlugin * (*FilterFn)(void); +ScFormatFilterPlugin &ScFormatFilter::Get() +{ + static ScFormatFilterPlugin *plugin; + + if (plugin != NULL) + return *plugin; + + static ::osl::Module aModule; + if ( aModule.loadRelative( &thisModule, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SVLIBRARY( "scfilt" ) ) ) ) ) + { + oslGenericFunction fn = aModule.getFunctionSymbol( ::rtl::OUString::createFromAscii( "ScFilterCreate" ) ); + if (fn != NULL) + plugin = reinterpret_cast<FilterFn>(fn)(); + } + if (plugin == NULL) + plugin = new ScFormatFilterMissing(); + + return *plugin; +} diff --git a/sc/source/ui/docshell/makefile.mk b/sc/source/ui/docshell/makefile.mk new file mode 100644 index 000000000000..99a7495b6b49 --- /dev/null +++ b/sc/source/ui/docshell/makefile.mk @@ -0,0 +1,139 @@ +#************************************************************************* +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=sc +TARGET=docshell +LIBTARGET=no + +# --- Settings ----------------------------------------------------- + +.INCLUDE : scpre.mk +.INCLUDE : settings.mk +.INCLUDE : sc.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +CXXFILES = \ + docsh.cxx \ + docsh2.cxx \ + docsh3.cxx \ + docsh4.cxx \ + docsh5.cxx \ + docsh6.cxx \ + docsh7.cxx \ + docsh8.cxx \ + externalrefmgr.cxx \ + tablink.cxx \ + arealink.cxx \ + dbdocfun.cxx \ + dbdocimp.cxx \ + impex.cxx \ + docfunc.cxx \ + olinefun.cxx \ + servobj.cxx \ + tpstat.cxx \ + autostyl.cxx \ + pagedata.cxx \ + hiranges.cxx \ + pntlock.cxx \ + sizedev.cxx \ + editable.cxx + + +SLOFILES = \ + $(SLO)$/docsh.obj \ + $(SLO)$/docsh2.obj \ + $(SLO)$/docsh3.obj \ + $(SLO)$/docsh4.obj \ + $(SLO)$/docsh5.obj \ + $(SLO)$/docsh6.obj \ + $(SLO)$/docsh7.obj \ + $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ + $(SLO)$/tablink.obj \ + $(SLO)$/arealink.obj \ + $(SLO)$/dbdocfun.obj \ + $(SLO)$/dbdocimp.obj \ + $(SLO)$/impex.obj \ + $(SLO)$/docfunc.obj \ + $(SLO)$/olinefun.obj \ + $(SLO)$/servobj.obj \ + $(SLO)$/tpstat.obj \ + $(SLO)$/autostyl.obj \ + $(SLO)$/pagedata.obj \ + $(SLO)$/hiranges.obj \ + $(SLO)$/pntlock.obj \ + $(SLO)$/sizedev.obj \ + $(SLO)$/editable.obj + + +EXCEPTIONSFILES= \ + $(SLO)$/docsh.obj \ + $(SLO)$/docsh3.obj \ + $(SLO)$/docsh4.obj \ + $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ + $(SLO)$/dbdocimp.obj \ + $(SLO)$/docfunc.obj + +SRS1NAME=$(TARGET) +SRC1FILES = tpstat.src + +LIB1TARGET = $(SLB)$/$(TARGET).lib + +LIB1OBJFILES = \ + $(SLO)$/docsh.obj \ + $(SLO)$/docsh2.obj \ + $(SLO)$/docsh3.obj \ + $(SLO)$/docsh4.obj \ + $(SLO)$/docsh5.obj \ + $(SLO)$/docsh6.obj \ + $(SLO)$/docsh7.obj \ + $(SLO)$/docsh8.obj \ + $(SLO)$/externalrefmgr.obj \ + $(SLO)$/tablink.obj \ + $(SLO)$/arealink.obj \ + $(SLO)$/dbdocfun.obj \ + $(SLO)$/dbdocimp.obj \ + $(SLO)$/impex.obj \ + $(SLO)$/docfunc.obj \ + $(SLO)$/olinefun.obj \ + $(SLO)$/servobj.obj \ + $(SLO)$/autostyl.obj \ + $(SLO)$/pagedata.obj \ + $(SLO)$/hiranges.obj \ + $(SLO)$/pntlock.obj \ + $(SLO)$/sizedev.obj \ + $(SLO)$/editable.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sc/source/ui/docshell/olinefun.cxx b/sc/source/ui/docshell/olinefun.cxx new file mode 100644 index 000000000000..2f42c77ed5f4 --- /dev/null +++ b/sc/source/ui/docshell/olinefun.cxx @@ -0,0 +1,788 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +// INCLUDE --------------------------------------------------------------- + +#include <vcl/sound.hxx> +#include <sfx2/bindings.hxx> + +#include "olinefun.hxx" + +#include "docsh.hxx" +#include "olinetab.hxx" +#include "undodat.hxx" +#include "globstr.hrc" +#include "sc.hrc" + + +//======================================================================== + +void lcl_InvalidateOutliner( SfxBindings* pBindings ) +{ + if ( pBindings ) + { + pBindings->Invalidate( SID_OUTLINE_SHOW ); + pBindings->Invalidate( SID_OUTLINE_HIDE ); + pBindings->Invalidate( SID_OUTLINE_REMOVE ); + + pBindings->Invalidate( SID_STATUS_SUM ); // wegen ein-/ausblenden + pBindings->Invalidate( SID_ATTR_SIZE ); + } +} + +//------------------------------------------------------------------------ + +//! PaintWidthHeight zur DocShell verschieben? + +void lcl_PaintWidthHeight( ScDocShell& rDocShell, SCTAB nTab, + BOOL bColumns, SCCOLROW nStart, SCCOLROW nEnd ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + USHORT nParts = PAINT_GRID; + SCCOL nStartCol = 0; + SCROW nStartRow = 0; + SCCOL nEndCol = MAXCOL; // fuer Test auf Merge + SCROW nEndRow = MAXROW; + if ( bColumns ) + { + nParts |= PAINT_TOP; + nStartCol = static_cast<SCCOL>(nStart); + nEndCol = static_cast<SCCOL>(nEnd); + } + else + { + nParts |= PAINT_LEFT; + nStartRow = nStart; + nEndRow = nEnd; + } + if (pDoc->HasAttrib( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, + HASATTR_MERGED | HASATTR_OVERLAPPED )) + { + nStartCol = 0; + nStartRow = 0; + } + rDocShell.PostPaint( nStartCol,nStartRow,nTab, MAXCOL,MAXROW,nTab, nParts ); +} + +//------------------------------------------------------------------------ + +BOOL ScOutlineDocFunc::MakeOutline( const ScRange& rRange, BOOL bColumns, BOOL bRecord, BOOL bApi ) +{ + BOOL bSuccess = FALSE; + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + ScDocument* pDoc = rDocShell.GetDocument(); + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab, TRUE ); + ScOutlineTable* pUndoTab = NULL; + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + if (bRecord) + pUndoTab = new ScOutlineTable( *pTable ); + + ScOutlineArray* pArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray(); + + BOOL bRes; + BOOL bSize = FALSE; + if ( bColumns ) + bRes = pArray->Insert( nStartCol, nEndCol, bSize ); + else + bRes = pArray->Insert( nStartRow, nEndRow, bSize ); + + if ( bRes ) + { + if (bRecord) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoMakeOutline( &rDocShell, + nStartCol,nStartRow,nTab,nEndCol,nEndRow,nTab, + pUndoTab, bColumns, TRUE ) ); + } + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + USHORT nParts = 0; // Datenbereich nicht geaendert + if ( bColumns ) + nParts |= PAINT_TOP; + else + nParts |= PAINT_LEFT; + if ( bSize ) + nParts |= PAINT_SIZE; + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, nParts ); + rDocShell.SetDocumentModified(); + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + bSuccess = TRUE; + } + else + { + if (!bApi) + rDocShell.ErrorMessage(STR_MSSG_MAKEOUTLINE_0); // "Gruppierung nicht moeglich" + delete pUndoTab; + } + + return bSuccess; +} + +BOOL ScOutlineDocFunc::RemoveOutline( const ScRange& rRange, BOOL bColumns, BOOL bRecord, BOOL bApi ) +{ + BOOL bDone = FALSE; + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + if (pTable) + { + ScOutlineTable* pUndoTab = NULL; + if (bRecord) + pUndoTab = new ScOutlineTable( *pTable ); + + ScOutlineArray* pArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray(); + + BOOL bRes; + BOOL bSize = FALSE; + if ( bColumns ) + bRes = pArray->Remove( nStartCol, nEndCol, bSize ); + else + bRes = pArray->Remove( nStartRow, nEndRow, bSize ); + + if ( bRes ) + { + if (bRecord) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoMakeOutline( &rDocShell, + nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, + pUndoTab, bColumns, FALSE ) ); + } + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + USHORT nParts = 0; // Datenbereich nicht geaendert + if ( bColumns ) + nParts |= PAINT_TOP; + else + nParts |= PAINT_LEFT; + if ( bSize ) + nParts |= PAINT_SIZE; + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, nParts ); + rDocShell.SetDocumentModified(); + bDone = TRUE; + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + + // es wird nicht wieder eingeblendet -> kein UpdatePageBreaks + } + else + delete pUndoTab; + } + + if (!bDone && !bApi) + rDocShell.ErrorMessage(STR_MSSG_REMOVEOUTLINE_0); // "Aufheben nicht moeglich" + + return bDone; +} + +BOOL ScOutlineDocFunc::RemoveAllOutlines( SCTAB nTab, BOOL bRecord, BOOL bApi ) +{ + BOOL bSuccess = FALSE; + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + if (pTable) + { + if (bRecord) + { + SCCOLROW nCol1, nCol2, nRow1, nRow2; + pTable->GetColArray()->GetRange( nCol1, nCol2 ); + pTable->GetRowArray()->GetRange( nRow1, nRow2 ); + SCCOL nStartCol = static_cast<SCCOL>(nCol1); + SCROW nStartRow = nRow1; + SCCOL nEndCol = static_cast<SCCOL>(nCol2); + SCROW nEndRow = nRow2; + + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( nStartCol, 0, nTab, nEndCol, MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab, IDF_NONE, FALSE, pUndoDoc ); + + ScOutlineTable* pUndoTab = new ScOutlineTable( *pTable ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoRemoveAllOutlines( &rDocShell, + nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab, + pUndoDoc, pUndoTab ) ); + } + + SelectLevel( nTab, TRUE, pTable->GetColArray()->GetDepth(), FALSE, FALSE, bApi ); + SelectLevel( nTab, FALSE, pTable->GetRowArray()->GetDepth(), FALSE, FALSE, bApi ); + pDoc->SetOutlineTable( nTab, NULL ); + + pDoc->UpdatePageBreaks( nTab ); + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, + PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); + rDocShell.SetDocumentModified(); + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + bSuccess = TRUE; + } + else if (!bApi) + Sound::Beep(); + + return bSuccess; +} + +//------------------------------------------------------------------------ + +BOOL ScOutlineDocFunc::AutoOutline( const ScRange& rRange, BOOL bRecord, BOOL bApi ) +{ + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + + ScDocument* pUndoDoc = NULL; + ScOutlineTable* pUndoTab = NULL; + + if ( pTable ) + { + if ( bRecord ) + { + pUndoTab = new ScOutlineTable( *pTable ); + + SCCOLROW nCol1, nCol2, nRow1, nRow2; + pTable->GetColArray()->GetRange( nCol1, nCol2 ); + pTable->GetRowArray()->GetRange( nRow1, nRow2 ); + SCCOL nOutStartCol = static_cast<SCCOL>(nCol1);; + SCROW nOutStartRow = nRow1; + SCCOL nOutEndCol = static_cast<SCCOL>(nCol2);; + SCROW nOutEndRow = nRow2; + + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( nOutStartCol, 0, nTab, nOutEndCol, MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + + // einblenden + SelectLevel( nTab, TRUE, pTable->GetColArray()->GetDepth(), FALSE, FALSE, bApi ); + SelectLevel( nTab, FALSE, pTable->GetRowArray()->GetDepth(), FALSE, FALSE, bApi ); + pDoc->SetOutlineTable( nTab, NULL ); + } + + pDoc->DoAutoOutline( nStartCol,nStartRow, nEndCol,nEndRow, nTab ); + + if (bRecord) + { + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoOutline( &rDocShell, + nStartCol, nStartRow, nTab, + nEndCol, nEndRow, nTab, + pUndoDoc, pUndoTab ) ); + } + + if (pDoc->IsStreamValid(nTab)) + pDoc->SetStreamValid(nTab, FALSE); + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_LEFT | PAINT_TOP | PAINT_SIZE ); + rDocShell.SetDocumentModified(); + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScOutlineDocFunc::SelectLevel( SCTAB nTab, BOOL bColumns, USHORT nLevel, + BOOL bRecord, BOOL bPaint, BOOL /* bApi */ ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); // ist schon da + if (!pTable) + return FALSE; + ScOutlineArray* pArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray(); + if (!pArray) + return FALSE; + + SCCOLROW nStart, nEnd; + pArray->GetRange( nStart, nEnd ); + + if ( bRecord ) + { + ScOutlineTable* pUndoTab = new ScOutlineTable( *pTable ); + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if (bColumns) + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, FALSE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, + static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE, FALSE, + pUndoDoc ); + } + else + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + pDoc->CopyToDocument( 0, nStart, nTab, MAXCOL, nEnd, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoOutlineLevel( &rDocShell, + nStart, nEnd, nTab, //! start und end berechnen + pUndoDoc, pUndoTab, + bColumns, nLevel ) ); + } + + ScSubOutlineIterator aIter( pArray ); // alle Eintraege + ScOutlineEntry* pEntry; + while ((pEntry=aIter.GetNext()) != NULL) + { + USHORT nThisLevel = aIter.LastLevel(); + BOOL bShow = (nThisLevel < nLevel); + if (bShow) // einblenden + { + pEntry->SetHidden( FALSE ); + pEntry->SetVisible( TRUE ); + } + else if ( nThisLevel == nLevel ) // ausblenden + { + pEntry->SetHidden( TRUE ); + pEntry->SetVisible( TRUE ); + } + else // verdeckt + { + pEntry->SetVisible( FALSE ); + } + + SCCOLROW nThisStart = pEntry->GetStart(); + SCCOLROW nThisEnd = pEntry->GetEnd(); + for (SCCOLROW i=nThisStart; i<=nThisEnd; i++) + { + if ( bColumns ) + pDoc->ShowCol( static_cast<SCCOL>(i), nTab, bShow ); + else + if ( !bShow || !pDoc->IsFiltered( i,nTab ) ) + pDoc->ShowRow( i, nTab, bShow ); + } + } + + pDoc->UpdatePageBreaks( nTab ); + + if (bPaint) + lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd ); + + rDocShell.SetDocumentModified(); + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + + return TRUE; +} + +//------------------------------------------------------------------------ + +BOOL ScOutlineDocFunc::ShowMarkedOutlines( const ScRange& rRange, BOOL bRecord, BOOL bApi ) +{ + BOOL bDone = FALSE; + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + + if (pTable) + { + ScOutlineArray* pArray; + ScOutlineEntry* pEntry; + SCCOLROW nStart; + SCCOLROW nEnd; + SCCOLROW nMin; + SCCOLROW nMax; + SCCOLROW i; + + if ( bRecord ) + { + ScOutlineTable* pUndoTab = new ScOutlineTable( *pTable ); + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( nStartCol, 0, nTab, nEndCol, MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab, IDF_NONE, FALSE, pUndoDoc ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoOutlineBlock( &rDocShell, + nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, + pUndoDoc, pUndoTab, TRUE ) ); + } + + // Spalten + + nMin=MAXCOL; + nMax=0; + pArray = pTable->GetColArray(); + ScSubOutlineIterator aColIter( pArray ); + while ((pEntry=aColIter.GetNext()) != NULL) + { + nStart = pEntry->GetStart(); + nEnd = pEntry->GetEnd(); + if ( nStart>=nStartCol && nEnd<=nEndCol ) + { + pEntry->SetHidden( FALSE ); + pEntry->SetVisible( TRUE ); + if (nStart<nMin) nMin=nStart; + if (nEnd>nMax) nMax=nEnd; + } + } + for ( i=nMin; i<=nMax; i++ ) + pDoc->ShowCol( static_cast<SCCOL>(i), nTab, TRUE ); + + // Zeilen + + nMin=MAXROW; + nMax=0; + pArray = pTable->GetRowArray(); + ScSubOutlineIterator aRowIter( pArray ); + while ((pEntry=aRowIter.GetNext()) != NULL) + { + nStart = pEntry->GetStart(); + nEnd = pEntry->GetEnd(); + if ( nStart>=nStartRow && nEnd<=nEndRow ) + { + pEntry->SetHidden( FALSE ); + pEntry->SetVisible( TRUE ); + if (nStart<nMin) nMin=nStart; + if (nEnd>nMax) nMax=nEnd; + } + } + for ( i=nMin; i<=nMax; i++ ) + if ( !pDoc->IsFiltered( i,nTab ) ) // weggefilterte nicht einblenden + pDoc->ShowRow( i, nTab, TRUE ); + + pDoc->UpdatePageBreaks( nTab ); + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_LEFT | PAINT_TOP ); + + rDocShell.SetDocumentModified(); + bDone = TRUE; + + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + } + + if (!bDone && !bApi) + Sound::Beep(); + + return bDone; +} + +BOOL ScOutlineDocFunc::HideMarkedOutlines( const ScRange& rRange, BOOL bRecord, BOOL bApi ) +{ + BOOL bDone = FALSE; + + SCCOL nStartCol = rRange.aStart.Col(); + SCROW nStartRow = rRange.aStart.Row(); + SCCOL nEndCol = rRange.aEnd.Col(); + SCROW nEndRow = rRange.aEnd.Row(); + SCTAB nTab = rRange.aStart.Tab(); + + ScDocument* pDoc = rDocShell.GetDocument(); + + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + + if (pTable) + { + ScOutlineEntry* pEntry; + USHORT nColLevel; + USHORT nRowLevel; + USHORT nCount; + SCCOLROW nStart; + SCCOLROW nEnd; + USHORT i; + + SCCOLROW nEffStartCol = nStartCol; + SCCOLROW nEffEndCol = nEndCol; + ScOutlineArray* pColArray = pTable->GetColArray(); + pColArray->FindTouchedLevel( nStartCol, nEndCol, nColLevel ); + pColArray->ExtendBlock( nColLevel, nEffStartCol, nEffEndCol ); + SCCOLROW nEffStartRow = nStartRow; + SCCOLROW nEffEndRow = nEndRow; + ScOutlineArray* pRowArray = pTable->GetRowArray(); + pRowArray->FindTouchedLevel( nStartRow, nEndRow, nRowLevel ); + pRowArray->ExtendBlock( nRowLevel, nEffStartRow, nEffEndRow ); + + if ( bRecord ) + { + ScOutlineTable* pUndoTab = new ScOutlineTable( *pTable ); + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nEffStartCol), 0, nTab, + static_cast<SCCOL>(nEffEndCol), MAXROW, nTab, IDF_NONE, + FALSE, pUndoDoc ); + pDoc->CopyToDocument( 0, nEffStartRow, nTab, MAXCOL, nEffEndRow, nTab, IDF_NONE, FALSE, pUndoDoc ); + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoOutlineBlock( &rDocShell, + nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, + pUndoDoc, pUndoTab, FALSE ) ); + } + + // Spalten + + nCount = pColArray->GetCount(nColLevel); + for ( i=0; i<nCount; i++ ) + { + pEntry = pColArray->GetEntry(nColLevel,i); + nStart = pEntry->GetStart(); + nEnd = pEntry->GetEnd(); + + if ( static_cast<SCCOLROW>(nStartCol)<=nEnd && static_cast<SCCOLROW>(nEndCol)>=nStart ) + HideOutline( nTab, TRUE, nColLevel, i, FALSE, FALSE, bApi ); + } + + // Zeilen + + nCount = pRowArray->GetCount(nRowLevel); + for ( i=0; i<nCount; i++ ) + { + pEntry = pRowArray->GetEntry(nRowLevel,i); + nStart = pEntry->GetStart(); + nEnd = pEntry->GetEnd(); + + if ( nStartRow<=nEnd && nEndRow>=nStart ) + HideOutline( nTab, FALSE, nRowLevel, i, FALSE, FALSE, bApi ); + } + + pDoc->UpdatePageBreaks( nTab ); + + rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_LEFT | PAINT_TOP ); + + rDocShell.SetDocumentModified(); + bDone = TRUE; + + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + } + + if (!bDone && !bApi) + Sound::Beep(); + + return bDone; +} + +//------------------------------------------------------------------------ + +BOOL ScOutlineDocFunc::ShowOutline( SCTAB nTab, BOOL bColumns, USHORT nLevel, USHORT nEntry, + BOOL bRecord, BOOL bPaint, BOOL /* bApi */ ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + ScOutlineArray* pArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray(); + ScOutlineEntry* pEntry = pArray->GetEntry( nLevel, nEntry ); + SCCOLROW nStart = pEntry->GetStart(); + SCCOLROW nEnd = pEntry->GetEnd(); + + if ( bRecord ) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if (bColumns) + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, FALSE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, + static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE, FALSE, + pUndoDoc ); + } + else + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + pDoc->CopyToDocument( 0, nStart, nTab, MAXCOL, nEnd, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDoOutline( &rDocShell, + nStart, nEnd, nTab, pUndoDoc, //! start und end berechnen + bColumns, nLevel, nEntry, TRUE ) ); + } + +//! HideCursor(); + + pEntry->SetHidden(FALSE); + SCCOLROW i; + for ( i = nStart; i <= nEnd; i++ ) + { + if ( bColumns ) + pDoc->ShowCol( static_cast<SCCOL>(i), nTab, TRUE ); + else + if ( !pDoc->IsFiltered( i,nTab ) ) // weggefilterte nicht einblenden + pDoc->ShowRow( i, nTab, TRUE ); + } + + ScSubOutlineIterator aIter( pArray, nLevel, nEntry ); + while ((pEntry=aIter.GetNext()) != NULL) + { + if ( pEntry->IsHidden() ) + { + SCCOLROW nSubStart = pEntry->GetStart(); + SCCOLROW nSubEnd = pEntry->GetEnd(); + for ( i = nSubStart; i <= nSubEnd; i++ ) + { + if ( bColumns ) + pDoc->ShowCol( static_cast<SCCOL>(i), nTab, FALSE ); + else + pDoc->ShowRow( i, nTab, FALSE ); + } + } + } + + pArray->SetVisibleBelow( nLevel, nEntry, TRUE, TRUE ); + + pDoc->UpdatePageBreaks( nTab ); + + if (bPaint) + lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd ); + +//! ShowCursor(); + rDocShell.SetDocumentModified(); + +//! if (bPaint) +//! UpdateScrollBars(); + + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + + return TRUE; //! immer ??? +} + +BOOL ScOutlineDocFunc::HideOutline( SCTAB nTab, BOOL bColumns, USHORT nLevel, USHORT nEntry, + BOOL bRecord, BOOL bPaint, BOOL /* bApi */ ) +{ + ScDocument* pDoc = rDocShell.GetDocument(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + + ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab ); + ScOutlineArray* pArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray(); + ScOutlineEntry* pEntry = pArray->GetEntry( nLevel, nEntry ); + SCCOLROW nStart = pEntry->GetStart(); + SCCOLROW nEnd = pEntry->GetEnd(); + + if ( bRecord ) + { + ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + if (bColumns) + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, FALSE ); + pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, + static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE, FALSE, + pUndoDoc ); + } + else + { + pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE ); + pDoc->CopyToDocument( 0, nStart, nTab, MAXCOL, nEnd, nTab, IDF_NONE, FALSE, pUndoDoc ); + } + + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoDoOutline( &rDocShell, + nStart, nEnd, nTab, pUndoDoc, + bColumns, nLevel, nEntry, FALSE ) ); + } + +//! HideCursor(); + + pEntry->SetHidden(TRUE); + SCCOLROW i; + for ( i = nStart; i <= nEnd; i++ ) + { + if ( bColumns ) + pDoc->ShowCol( static_cast<SCCOL>(i), nTab, FALSE ); + else + pDoc->ShowRow( i, nTab, FALSE ); + } + + pArray->SetVisibleBelow( nLevel, nEntry, FALSE ); + + pDoc->UpdatePageBreaks( nTab ); + + if (bPaint) + lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd ); + +//! ShowCursor(); + rDocShell.SetDocumentModified(); + +//! if (bPaint) +//! UpdateScrollBars(); + + lcl_InvalidateOutliner( rDocShell.GetViewBindings() ); + + return TRUE; //! immer ??? +} + + + + + diff --git a/sc/source/ui/docshell/pagedata.cxx b/sc/source/ui/docshell/pagedata.cxx new file mode 100644 index 000000000000..db55c2364305 --- /dev/null +++ b/sc/source/ui/docshell/pagedata.cxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + +#include <string.h> +#include <tools/debug.hxx> + + +#include "pagedata.hxx" + +//============================================================================ + +ScPrintRangeData::ScPrintRangeData() +{ + nPagesX = nPagesY = 0; + pPageEndX = NULL; + pPageEndY = NULL; + bTopDown = bAutomatic = TRUE; + nFirstPage = 1; +} + +ScPrintRangeData::~ScPrintRangeData() +{ + delete[] pPageEndX; + delete[] pPageEndY; +} + +void ScPrintRangeData::SetPagesX( size_t nCount, const SCCOL* pData ) +{ + delete[] pPageEndX; + if ( nCount ) + { + pPageEndX = new SCCOL[nCount]; + memcpy( pPageEndX, pData, nCount * sizeof(SCCOL) ); + } + else + pPageEndX = NULL; + nPagesX = nCount; +} + +void ScPrintRangeData::SetPagesY( size_t nCount, const SCROW* pData ) +{ + delete[] pPageEndY; + if ( nCount ) + { + pPageEndY = new SCROW[nCount]; + memcpy( pPageEndY, pData, nCount * sizeof(SCROW) ); + } + else + pPageEndY = NULL; + nPagesY = nCount; +} + +//============================================================================ + +ScPageBreakData::ScPageBreakData(size_t nMax) +{ + nUsed = 0; + if (nMax) + pData = new ScPrintRangeData[nMax]; + else + pData = NULL; + nAlloc = nMax; +} + +ScPageBreakData::~ScPageBreakData() +{ + delete[] pData; +} + +ScPrintRangeData& ScPageBreakData::GetData(size_t nPos) +{ + DBG_ASSERT(nPos < nAlloc, "ScPageBreakData::GetData bumm"); + + if ( nPos >= nUsed ) + { + DBG_ASSERT(nPos == nUsed, "ScPageBreakData::GetData falsche Reihenfolge"); + nUsed = nPos+1; + } + + return pData[nPos]; +} + +BOOL ScPageBreakData::IsEqual( const ScPageBreakData& rOther ) const +{ + if ( nUsed != rOther.nUsed ) + return FALSE; + + for (USHORT i=0; i<nUsed; i++) + if ( pData[i].GetPrintRange() != rOther.pData[i].GetPrintRange() ) + return FALSE; + + //! ScPrintRangeData komplett vergleichen ?? + + return TRUE; +} + +void ScPageBreakData::AddPages() +{ + if ( nUsed > 1 ) + { + long nPage = pData[0].GetFirstPage(); + for (USHORT i=0; sal::static_int_cast<size_t>(i+1)<nUsed; i++) + { + nPage += ((long)pData[i].GetPagesX())*pData[i].GetPagesY(); + pData[i+1].SetFirstPage( nPage ); + } + } +} + + + diff --git a/sc/source/ui/docshell/pntlock.cxx b/sc/source/ui/docshell/pntlock.cxx new file mode 100644 index 000000000000..764d431f3af0 --- /dev/null +++ b/sc/source/ui/docshell/pntlock.cxx @@ -0,0 +1,61 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include "pntlock.hxx" + +//------------------------------------------------------------------------ + +ScPaintLockData::ScPaintLockData(USHORT nNewMode) : + nMode( nNewMode ), + nLevel( 0 ), + nDocLevel( 0 ), + nParts( 0 ), + bModified( FALSE ) +{ +} + +ScPaintLockData::~ScPaintLockData() +{ +} + +void ScPaintLockData::AddRange( const ScRange& rRange, USHORT nP ) +{ + if (!xRangeList.Is()) + xRangeList = new ScRangeList; + + xRangeList->Join( rRange ); + nParts |= nP; +} + + + + diff --git a/sc/source/ui/docshell/servobj.cxx b/sc/source/ui/docshell/servobj.cxx new file mode 100644 index 000000000000..dabe38fb8c1d --- /dev/null +++ b/sc/source/ui/docshell/servobj.cxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * 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" +// System - Includes ----------------------------------------------------- + + + +#include <sot/formats.hxx> +#include <sfx2/app.hxx> +#include <sfx2/linkmgr.hxx> +#include "servobj.hxx" +#include "docsh.hxx" +#include "impex.hxx" +#include "brdcst.hxx" +#include "rangenam.hxx" +#include "sc.hrc" // SC_HINT_AREAS_CHANGED + +// ----------------------------------------------------------------------- + +BOOL lcl_FillRangeFromName( ScRange& rRange, ScDocShell* pDocSh, const String& rName ) +{ + if (pDocSh) + { + ScDocument* pDoc = pDocSh->GetDocument(); + ScRangeName* pNames = pDoc->GetRangeName(); + if (pNames) + { + USHORT nPos; + if( pNames->SearchName( rName, nPos ) ) + { + ScRangeData* pData = (*pNames)[ nPos ]; + if ( pData->IsValidReference( rRange ) ) + return TRUE; + } + } + } + return FALSE; +} + +ScServerObjectSvtListenerForwarder::ScServerObjectSvtListenerForwarder( + ScServerObject* pObjP) + : pObj(pObjP) +{ +} + +ScServerObjectSvtListenerForwarder::~ScServerObjectSvtListenerForwarder() +{ + //! do NOT access pObj +} + +void ScServerObjectSvtListenerForwarder::Notify( SvtBroadcaster& /* rBC */, const SfxHint& rHint) +{ + pObj->Notify( aBroadcaster, rHint); +} + +ScServerObject::ScServerObject( ScDocShell* pShell, const String& rItem ) : + aForwarder( this ), + pDocSh( pShell ), + bRefreshListener( FALSE ) +{ + // parse item string + + if ( lcl_FillRangeFromName( aRange, pDocSh, rItem ) ) + { + aItemStr = rItem; // must be parsed again on ref update + } + else + { + // parse ref + ScDocument* pDoc = pDocSh->GetDocument(); + SCTAB nTab = pDocSh->GetCurTab(); + aRange.aStart.SetTab( nTab ); + + if ( aRange.Parse( rItem, pDoc ) & SCA_VALID ) + { + // area reference + } + else if ( aRange.aStart.Parse( rItem, pDoc, pDoc->GetAddressConvention() ) & SCA_VALID ) + { + // cell reference + aRange.aEnd = aRange.aStart; + } + else + { + DBG_ERROR("ScServerObject: invalid item"); + } + } + + pDocSh->GetDocument()->GetLinkManager()->InsertServer( this ); + pDocSh->GetDocument()->StartListeningArea( aRange, &aForwarder ); + + StartListening(*pDocSh); // um mitzubekommen, wenn die DocShell geloescht wird + StartListening(*SFX_APP()); // for SC_HINT_AREAS_CHANGED +} + +__EXPORT ScServerObject::~ScServerObject() +{ + Clear(); +} + +void ScServerObject::Clear() +{ + if (pDocSh) + { + ScDocShell* pTemp = pDocSh; + pDocSh = NULL; + + pTemp->GetDocument()->EndListeningArea( aRange, &aForwarder ); + pTemp->GetDocument()->GetLinkManager()->RemoveServer( this ); + EndListening(*pTemp); + EndListening(*SFX_APP()); + } +} + +void ScServerObject::EndListeningAll() +{ + aForwarder.EndListeningAll(); + SfxListener::EndListeningAll(); +} + +BOOL __EXPORT ScServerObject::GetData( + ::com::sun::star::uno::Any & rData /*out param*/, + const String & rMimeType, BOOL /* bSynchron */ ) +{ + if (!pDocSh) + return FALSE; + + // named ranges may have changed -> update aRange + if ( aItemStr.Len() ) + { + ScRange aNew; + if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange ) + { + aRange = aNew; + bRefreshListener = TRUE; + } + } + + if ( bRefreshListener ) + { + // refresh the listeners now (this is called from a timer) + + EndListeningAll(); + pDocSh->GetDocument()->StartListeningArea( aRange, &aForwarder ); + StartListening(*pDocSh); + StartListening(*SFX_APP()); + bRefreshListener = FALSE; + } + + String aDdeTextFmt = pDocSh->GetDdeTextFmt(); + ScDocument* pDoc = pDocSh->GetDocument(); + + if( FORMAT_STRING == SotExchange::GetFormatIdFromMimeType( rMimeType )) + { + ScImportExport aObj( pDoc, aRange ); + if( aDdeTextFmt.GetChar(0) == 'F' ) + aObj.SetFormulas( TRUE ); + if( aDdeTextFmt.EqualsAscii( "SYLK" ) || + aDdeTextFmt.EqualsAscii( "FSYLK" ) ) + { + ByteString aByteData; + if( aObj.ExportByteString( aByteData, gsl_getSystemTextEncoding(), SOT_FORMATSTR_ID_SYLK ) ) + { + rData <<= ::com::sun::star::uno::Sequence< sal_Int8 >( + (sal_Int8*)aByteData.GetBuffer(), + aByteData.Len() + 1 ); + return 1; + } + return 0; + } + if( aDdeTextFmt.EqualsAscii( "CSV" ) || + aDdeTextFmt.EqualsAscii( "FCSV" ) ) + aObj.SetSeparator( ',' ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); + return aObj.ExportData( rMimeType, rData ) ? 1 : 0; + } + + ScImportExport aObj( pDoc, aRange ); + aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); + if( aObj.IsRef() ) + return aObj.ExportData( rMimeType, rData ) ? 1 : 0; + return 0; +} + +void __EXPORT ScServerObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + BOOL bDataChanged = FALSE; + + // DocShell can't be tested via type info, because SFX_HINT_DYING comes from the dtor + if ( &rBC == pDocSh ) + { + // from DocShell, only SFX_HINT_DYING is interesting + if ( rHint.ISA(SfxSimpleHint) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) + { + pDocSh = NULL; + EndListening(*SFX_APP()); + // don't access DocShell anymore for EndListening etc. + } + } + else if (rBC.ISA(SfxApplication)) + { + if ( aItemStr.Len() && rHint.ISA(SfxSimpleHint) && + ((const SfxSimpleHint&)rHint).GetId() == SC_HINT_AREAS_CHANGED ) + { + // check if named range was modified + ScRange aNew; + if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange ) + bDataChanged = TRUE; + } + } + else + { + // must be from Area broadcasters + + const ScHint* pScHint = PTR_CAST( ScHint, &rHint ); + if( pScHint && (pScHint->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)) ) + bDataChanged = TRUE; + else if (rHint.ISA(ScAreaChangedHint)) // position of broadcaster changed + { + ScRange aNewRange = ((const ScAreaChangedHint&)rHint).GetRange(); + if ( aRange != aNewRange ) + { + bRefreshListener = TRUE; + bDataChanged = TRUE; + } + } + else if (rHint.ISA(SfxSimpleHint)) + { + ULONG nId = ((const SfxSimpleHint&)rHint).GetId(); + if (nId == SFX_HINT_DYING) + { + // If the range is being deleted, listening must be restarted + // after the deletion is complete (done in GetData) + bRefreshListener = TRUE; + bDataChanged = TRUE; + } + } + } + + if ( bDataChanged && HasDataLinks() ) + SvLinkSource::NotifyDataChanged(); +} + + + + + diff --git a/sc/source/ui/docshell/sizedev.cxx b/sc/source/ui/docshell/sizedev.cxx new file mode 100644 index 000000000000..d89009540156 --- /dev/null +++ b/sc/source/ui/docshell/sizedev.cxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + +#include <sfx2/printer.hxx> +#include <vcl/virdev.hxx> + +#include "sizedev.hxx" +#include "docsh.hxx" +#include "scmod.hxx" +#include "inputopt.hxx" + +//------------------------------------------------------------------ + +ScSizeDeviceProvider::ScSizeDeviceProvider( ScDocShell* pDocSh ) +{ + BOOL bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg(); + if ( bTextWysiwyg ) + { + pDevice = pDocSh->GetPrinter(); + bOwner = FALSE; + + aOldMapMode = pDevice->GetMapMode(); + pDevice->SetMapMode( MAP_PIXEL ); // GetNeededSize needs pixel MapMode + // printer has right DigitLanguage already + } + else + { + pDevice = new VirtualDevice; + pDevice->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); + bOwner = TRUE; + } + + Point aLogic = pDevice->LogicToPixel( Point(1000,1000), MAP_TWIP ); + nPPTX = aLogic.X() / 1000.0; + nPPTY = aLogic.Y() / 1000.0; + + if ( !bTextWysiwyg ) + nPPTX /= pDocSh->GetOutputFactor(); +} + +ScSizeDeviceProvider::~ScSizeDeviceProvider() +{ + if (bOwner) + delete pDevice; + else + pDevice->SetMapMode( aOldMapMode ); +} + diff --git a/sc/source/ui/docshell/tablink.cxx b/sc/source/ui/docshell/tablink.cxx new file mode 100644 index 000000000000..4d18f9f18c37 --- /dev/null +++ b/sc/source/ui/docshell/tablink.cxx @@ -0,0 +1,616 @@ +/************************************************************************* + * + * 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" +#ifdef _MSC_VER +#pragma optimize("",off) +#endif + +//------------------------------------------------------------------ + + + +// INCLUDE --------------------------------------------------------- + +#include <sfx2/sfxsids.hrc> +#include <sfx2/app.hxx> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/linkmgr.hxx> +#include <tools/urlobj.hxx> +#include <unotools/transliterationwrapper.hxx> + +#include "tablink.hxx" + +#include "scextopt.hxx" +#include "table.hxx" +#include "document.hxx" +#include "docsh.hxx" +#include "globstr.hrc" +#include "undoblk.hxx" +#include "undotab.hxx" +#include "global.hxx" +#include "hints.hxx" +#include "cell.hxx" +#include "dociter.hxx" +#include "formula/opcode.hxx" + +struct TableLink_Impl +{ + ScDocShell* m_pDocSh; + Window* m_pOldParent; + Link m_aEndEditLink; + + TableLink_Impl() : m_pDocSh( NULL ), m_pOldParent( NULL ) {} +}; + +TYPEINIT1(ScTableLink, ::sfx2::SvBaseLink); + +//------------------------------------------------------------------------ + +ScTableLink::ScTableLink(ScDocShell* pDocSh, const String& rFile, + const String& rFilter, const String& rOpt, + ULONG nRefresh ): + ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ONCALL,FORMAT_FILE), + ScRefreshTimer( nRefresh ), + pImpl( new TableLink_Impl ), + aFileName(rFile), + aFilterName(rFilter), + aOptions(rOpt), + bInCreate( FALSE ), + bInEdit( FALSE ), + bAddUndo( TRUE ), + bDoPaint( TRUE ) +{ + pImpl->m_pDocSh = pDocSh; +} + +ScTableLink::ScTableLink(SfxObjectShell* pShell, const String& rFile, + const String& rFilter, const String& rOpt, + ULONG nRefresh ): + ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ONCALL,FORMAT_FILE), + ScRefreshTimer( nRefresh ), + pImpl( new TableLink_Impl ), + aFileName(rFile), + aFilterName(rFilter), + aOptions(rOpt), + bInCreate( FALSE ), + bInEdit( FALSE ), + bAddUndo( TRUE ), + bDoPaint( TRUE ) +{ + pImpl->m_pDocSh = static_cast< ScDocShell* >( pShell ); + SetRefreshHandler( LINK( this, ScTableLink, RefreshHdl ) ); + SetRefreshControl( pImpl->m_pDocSh->GetDocument()->GetRefreshTimerControlAddress() ); +} + +__EXPORT ScTableLink::~ScTableLink() +{ + // Verbindung aufheben + + StopRefreshTimer(); + String aEmpty; + ScDocument* pDoc = pImpl->m_pDocSh->GetDocument(); + SCTAB nCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nCount; nTab++) + if (pDoc->IsLinked(nTab) && pDoc->GetLinkDoc(nTab)==aFileName) + pDoc->SetLink( nTab, SC_LINK_NONE, aEmpty, aEmpty, aEmpty, aEmpty, 0 ); + delete pImpl; +} + +void __EXPORT ScTableLink::Edit( Window* pParent, const Link& rEndEditHdl ) +{ + // DefModalDialogParent setzen, weil evtl. aus der DocShell beim ConvertFrom + // ein Optionen-Dialog kommt... + + pImpl->m_aEndEditLink = rEndEditHdl; + pImpl->m_pOldParent = Application::GetDefDialogParent(); + if (pParent) + Application::SetDefDialogParent(pParent); + + bInEdit = TRUE; + SvBaseLink::Edit( pParent, LINK( this, ScTableLink, TableEndEditHdl ) ); +} + +void __EXPORT ScTableLink::DataChanged( const String&, + const ::com::sun::star::uno::Any& ) +{ + sfx2::LinkManager* pLinkManager=pImpl->m_pDocSh->GetDocument()->GetLinkManager(); + if (pLinkManager!=NULL) + { + String aFile; + String aFilter; + pLinkManager->GetDisplayNames( this,0,&aFile,NULL,&aFilter); + + // the file dialog returns the filter name with the application prefix + // -> remove prefix + ScDocumentLoader::RemoveAppPrefix( aFilter ); + + if (!bInCreate) + Refresh( aFile, aFilter, NULL, GetRefreshDelay() ); // don't load twice + } +} + +void __EXPORT ScTableLink::Closed() +{ + // Verknuepfung loeschen: Undo + ScDocument* pDoc = pImpl->m_pDocSh->GetDocument(); + BOOL bUndo (pDoc->IsUndoEnabled()); + + if (bAddUndo && bUndo) + { + pImpl->m_pDocSh->GetUndoManager()->AddUndoAction( + new ScUndoRemoveLink( pImpl->m_pDocSh, aFileName ) ); + + bAddUndo = FALSE; // nur einmal + } + + // Verbindung wird im dtor aufgehoben + + SvBaseLink::Closed(); +} + +BOOL ScTableLink::IsUsed() const +{ + return pImpl->m_pDocSh->GetDocument()->HasLink( aFileName, aFilterName, aOptions ); +} + +BOOL ScTableLink::Refresh(const String& rNewFile, const String& rNewFilter, + const String* pNewOptions, ULONG nNewRefresh ) +{ + // Dokument laden + + if (!rNewFile.Len() || !rNewFilter.Len()) + return FALSE; + + String aNewUrl( ScGlobal::GetAbsDocName( rNewFile, pImpl->m_pDocSh ) ); + BOOL bNewUrlName = (aNewUrl != aFileName); + + const SfxFilter* pFilter = pImpl->m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter); + if (!pFilter) + return FALSE; + + ScDocument* pDoc = pImpl->m_pDocSh->GetDocument(); + pDoc->SetInLinkUpdate( TRUE ); + + BOOL bUndo(pDoc->IsUndoEnabled()); + + // wenn neuer Filter ausgewaehlt wurde, Optionen vergessen + if ( rNewFilter != aFilterName ) + aOptions.Erase(); + if ( pNewOptions ) // Optionen hart angegeben? + aOptions = *pNewOptions; + + // ItemSet immer anlegen, damit die DocShell die Optionen setzen kann + SfxItemSet* pSet = new SfxAllItemSet( SFX_APP()->GetPool() ); + if ( aOptions.Len() ) + pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) ); + + SfxMedium* pMed = new SfxMedium(aNewUrl, STREAM_STD_READ, FALSE, pFilter, pSet); + + if ( bInEdit ) // only if using the edit dialog, + pMed->UseInteractionHandler( TRUE ); // enable the filter options dialog + + ScDocShell* pSrcShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL); + SfxObjectShellRef aRef = pSrcShell; + pSrcShell->DoLoad(pMed); + + // Optionen koennten gesetzt worden sein + String aNewOpt = ScDocumentLoader::GetOptions(*pMed); + if (!aNewOpt.Len()) + aNewOpt = aOptions; + + // Undo... + + ScDocument* pUndoDoc = NULL; + BOOL bFirst = TRUE; + if (bAddUndo && bUndo) + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + + // Tabellen kopieren + + ScDocShellModificator aModificator( *pImpl->m_pDocSh ); + + BOOL bNotFound = FALSE; + ScDocument* pSrcDoc = pSrcShell->GetDocument(); + + // #74835# from text filters that don't set the table name, + // use the one table regardless of link table name + BOOL bAutoTab = (pSrcDoc->GetTableCount() == 1) && + ScDocShell::HasAutomaticTableName( rNewFilter ); + + SCTAB nCount = pDoc->GetTableCount(); + for (SCTAB nTab=0; nTab<nCount; nTab++) + { + BYTE nMode = pDoc->GetLinkMode(nTab); + if (nMode && pDoc->GetLinkDoc(nTab)==aFileName) + { + String aTabName = pDoc->GetLinkTab(nTab); + + // Undo + + if (bAddUndo && bUndo) + { + if (bFirst) + pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE ); + else + pUndoDoc->AddUndoTab( nTab, nTab, TRUE, TRUE ); + bFirst = FALSE; + ScRange aRange(0,0,nTab,MAXCOL,MAXROW,nTab); + pDoc->CopyToDocument(aRange, IDF_ALL, FALSE, pUndoDoc); + pUndoDoc->TransferDrawPage( pDoc, nTab, nTab ); + pUndoDoc->SetLink( nTab, nMode, aFileName, aFilterName, + aOptions, aTabName, GetRefreshDelay() ); + } + + // Tabellenname einer ExtDocRef anpassen + + if ( bNewUrlName && nMode == SC_LINK_VALUE ) + { + String aName; + pDoc->GetName( nTab, aName ); + if ( ScGlobal::GetpTransliteration()->isEqual( + ScGlobal::GetDocTabName( aFileName, aTabName ), aName ) ) + { + pDoc->RenameTab( nTab, + ScGlobal::GetDocTabName( aNewUrl, aTabName ), + FALSE, TRUE ); // kein RefUpdate, kein ValidTabName + } + } + + // kopieren + + SCTAB nSrcTab = 0; + bool bFound = false; + /* #i71497# check if external document is loaded successfully, + otherwise we may find the empty default sheet "Sheet1" in + pSrcDoc, even if the document does not exist. */ + if( pMed->GetError() == 0 ) + { + // no sheet name -> use first sheet + if ( aTabName.Len() && !bAutoTab ) + bFound = pSrcDoc->GetTable( aTabName, nSrcTab ); + else + bFound = true; + } + + if (bFound) + pDoc->TransferTab( pSrcDoc, nSrcTab, nTab, FALSE, // nicht neu einfuegen + (nMode == SC_LINK_VALUE) ); // nur Werte? + else + { + pDoc->DeleteAreaTab( 0,0,MAXCOL,MAXROW, nTab, IDF_ALL ); + + bool bShowError = true; + if ( nMode == SC_LINK_VALUE ) + { + // #139464# Value link (used with external references in formulas): + // Look for formulas that reference the sheet, and put errors in the referenced cells. + + ScRangeList aErrorCells; // cells on the linked sheets that need error values + + ScCellIterator aCellIter( pDoc, 0,0,0, MAXCOL,MAXROW,MAXTAB ); // all sheets + ScBaseCell* pCell = aCellIter.GetFirst(); + while (pCell) + { + if (pCell->GetCellType() == CELLTYPE_FORMULA) + { + ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell); + + ScDetectiveRefIter aRefIter( pFCell ); + ScRange aRefRange; + while ( aRefIter.GetNextRef( aRefRange ) ) + { + if ( aRefRange.aStart.Tab() <= nTab && aRefRange.aEnd.Tab() >= nTab ) + { + // use first cell of range references (don't fill potentially large ranges) + + aErrorCells.Join( ScRange( aRefRange.aStart ) ); + } + } + } + pCell = aCellIter.GetNext(); + } + + ULONG nRanges = aErrorCells.Count(); + if ( nRanges ) // found any? + { + ScTokenArray aTokenArr; + aTokenArr.AddOpCode( ocNotAvail ); + aTokenArr.AddOpCode( ocOpen ); + aTokenArr.AddOpCode( ocClose ); + aTokenArr.AddOpCode( ocStop ); + + for (ULONG nPos=0; nPos<nRanges; nPos++) + { + const ScRange* pRange = aErrorCells.GetObject(nPos); + SCCOL nStartCol = pRange->aStart.Col(); + SCROW nStartRow = pRange->aStart.Row(); + SCCOL nEndCol = pRange->aEnd.Col(); + SCROW nEndRow = pRange->aEnd.Row(); + for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++) + for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) + { + ScAddress aDestPos( nCol, nRow, nTab ); + ScFormulaCell* pNewCell = new ScFormulaCell( pDoc, aDestPos, &aTokenArr ); + pDoc->PutCell( aDestPos, pNewCell ); + } + } + + bShowError = false; + } + // if no references were found, insert error message (don't leave the sheet empty) + } + + if ( bShowError ) + { + // Normal link or no references: put error message on sheet. + + pDoc->SetString( 0,0,nTab, ScGlobal::GetRscString(STR_LINKERROR) ); + pDoc->SetString( 0,1,nTab, ScGlobal::GetRscString(STR_LINKERRORFILE) ); + pDoc->SetString( 1,1,nTab, aNewUrl ); + pDoc->SetString( 0,2,nTab, ScGlobal::GetRscString(STR_LINKERRORTAB) ); + pDoc->SetString( 1,2,nTab, aTabName ); + } + + bNotFound = TRUE; + } + + if ( bNewUrlName || rNewFilter != aFilterName || + aNewOpt != aOptions || pNewOptions || + nNewRefresh != GetRefreshDelay() ) + pDoc->SetLink( nTab, nMode, aNewUrl, rNewFilter, aNewOpt, + aTabName, nNewRefresh ); + } + } + + // neue Einstellungen merken + + if ( bNewUrlName ) + aFileName = aNewUrl; + if ( rNewFilter != aFilterName ) + aFilterName = rNewFilter; + if ( aNewOpt != aOptions ) + aOptions = aNewOpt; + + // aufraeumen + +// pSrcShell->DoClose(); + aRef->DoClose(); + + // Undo + + if (bAddUndo && bUndo) + pImpl->m_pDocSh->GetUndoManager()->AddUndoAction( + new ScUndoRefreshLink( pImpl->m_pDocSh, pUndoDoc ) ); + + // Paint (koennen mehrere Tabellen sein) + + if (bDoPaint) + { + pImpl->m_pDocSh->PostPaint( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB), + PAINT_GRID | PAINT_TOP | PAINT_LEFT ); + aModificator.SetDocumentModified(); + } + + if (bNotFound) + { + //! Fehler ausgeben ? + } + + pDoc->SetInLinkUpdate( FALSE ); + + // notify Uno objects (for XRefreshListener) + //! also notify Uno objects if file name was changed! + ScLinkRefreshedHint aHint; + aHint.SetSheetLink( aFileName ); + pDoc->BroadcastUno( aHint ); + + return TRUE; +} + +IMPL_LINK( ScTableLink, RefreshHdl, ScTableLink*, EMPTYARG ) +{ + long nRes = Refresh( aFileName, aFilterName, NULL, GetRefreshDelay() ) != 0; + return nRes; +} + +IMPL_LINK( ScTableLink, TableEndEditHdl, ::sfx2::SvBaseLink*, pLink ) +{ + if ( pImpl->m_aEndEditLink.IsSet() ) + pImpl->m_aEndEditLink.Call( pLink ); + bInEdit = FALSE; + Application::SetDefDialogParent( pImpl->m_pOldParent ); + return 0; +} + +// === ScDocumentLoader ================================================== + +String ScDocumentLoader::GetOptions( SfxMedium& rMedium ) // static +{ + SfxItemSet* pSet = rMedium.GetItemSet(); + const SfxPoolItem* pItem; + if ( pSet && SFX_ITEM_SET == pSet->GetItemState( SID_FILE_FILTEROPTIONS, TRUE, &pItem ) ) + return ((const SfxStringItem*)pItem)->GetValue(); + + return EMPTY_STRING; +} + +BOOL ScDocumentLoader::GetFilterName( const String& rFileName, + String& rFilter, String& rOptions, + BOOL bWithContent, BOOL bWithInteraction ) // static +{ + TypeId aScType = TYPE(ScDocShell); + SfxObjectShell* pDocSh = SfxObjectShell::GetFirst( &aScType ); + while ( pDocSh ) + { + if ( pDocSh->HasName() ) + { + SfxMedium* pMed = pDocSh->GetMedium(); + if ( rFileName == pMed->GetName() ) + { + rFilter = pMed->GetFilter()->GetFilterName(); + rOptions = GetOptions(*pMed); + return TRUE; + } + } + pDocSh = SfxObjectShell::GetNext( *pDocSh, &aScType ); + } + + // Filter-Detection + + const SfxFilter* pSfxFilter = NULL; + SfxMedium* pMedium = new SfxMedium( rFileName, STREAM_STD_READ, FALSE ); + if ( pMedium->GetError() == ERRCODE_NONE ) + { + if ( bWithInteraction ) + pMedium->UseInteractionHandler(TRUE); // #i73992# no longer called from GuessFilter + + SfxFilterMatcher aMatcher( String::CreateFromAscii("scalc") ); + if( bWithContent ) + aMatcher.GuessFilter( *pMedium, &pSfxFilter ); + else + aMatcher.GuessFilterIgnoringContent( *pMedium, &pSfxFilter ); + } + + BOOL bOK = FALSE; + if ( pMedium->GetError() == ERRCODE_NONE ) + { + if ( pSfxFilter ) + rFilter = pSfxFilter->GetFilterName(); + else + rFilter = ScDocShell::GetOwnFilterName(); // sonst Calc-Datei + bOK = (rFilter.Len()>0); + } + + delete pMedium; + return bOK; +} + +void ScDocumentLoader::RemoveAppPrefix( String& rFilterName ) // static +{ + String aAppPrefix = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( STRING_SCAPP )); + aAppPrefix.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ": " )); + xub_StrLen nPreLen = aAppPrefix.Len(); + if ( rFilterName.Copy(0,nPreLen) == aAppPrefix ) + rFilterName.Erase(0,nPreLen); +} + +ScDocumentLoader::ScDocumentLoader( const String& rFileName, + String& rFilterName, String& rOptions, + UINT32 nRekCnt, BOOL bWithInteraction ) : + pDocShell(0), + pMedium(0) +{ + if ( !rFilterName.Len() ) + GetFilterName( rFileName, rFilterName, rOptions, TRUE, bWithInteraction ); + + const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( rFilterName ); + + // ItemSet immer anlegen, damit die DocShell die Optionen setzen kann + SfxItemSet* pSet = new SfxAllItemSet( SFX_APP()->GetPool() ); + if ( rOptions.Len() ) + pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, rOptions ) ); + + pMedium = new SfxMedium( rFileName, STREAM_STD_READ, FALSE, pFilter, pSet ); + if ( pMedium->GetError() != ERRCODE_NONE ) + return ; + + if ( bWithInteraction ) + pMedium->UseInteractionHandler( TRUE ); // to enable the filter options dialog + + pDocShell = new ScDocShell( SFX_CREATE_MODE_INTERNAL ); + aRef = pDocShell; + + ScDocument* pDoc = pDocShell->GetDocument(); + if( pDoc ) + { + ScExtDocOptions* pExtDocOpt = pDoc->GetExtDocOptions(); + if( !pExtDocOpt ) + { + pExtDocOpt = new ScExtDocOptions; + pDoc->SetExtDocOptions( pExtDocOpt ); + } + pExtDocOpt->GetDocSettings().mnLinkCnt = nRekCnt; + } + + pDocShell->DoLoad( pMedium ); + + String aNew = GetOptions(*pMedium); // Optionen werden beim Laden per Dialog gesetzt + if (aNew.Len() && aNew != rOptions) + rOptions = aNew; +} + +ScDocumentLoader::~ScDocumentLoader() +{ +/* if ( pDocShell ) + pDocShell->DoClose(); +*/ + if ( aRef.Is() ) + aRef->DoClose(); + else if ( pMedium ) + delete pMedium; +} + +void ScDocumentLoader::ReleaseDocRef() +{ + if ( aRef.Is() ) + { + // release reference without calling DoClose - caller must + // have another reference to the doc and call DoClose later + + pDocShell = NULL; + pMedium = NULL; + aRef.Clear(); + } +} + +ScDocument* ScDocumentLoader::GetDocument() +{ + return pDocShell ? pDocShell->GetDocument() : 0; +} + +BOOL ScDocumentLoader::IsError() const +{ + if ( pDocShell && pMedium ) + return pMedium->GetError() != ERRCODE_NONE; + else + return TRUE; +} + +String ScDocumentLoader::GetTitle() const +{ + if ( pDocShell ) + return pDocShell->GetTitle(); + else + return EMPTY_STRING; +} + diff --git a/sc/source/ui/docshell/tpstat.cxx b/sc/source/ui/docshell/tpstat.cxx new file mode 100644 index 000000000000..1072af30c7a1 --- /dev/null +++ b/sc/source/ui/docshell/tpstat.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * 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" + +#undef SC_DLLIMPLEMENTATION + + + +#include "document.hxx" +#include "docsh.hxx" +#include "scresid.hxx" +#include "tpstat.hrc" + +#include "tpstat.hxx" + + +//======================================================================== +// Dokumentinfo-Tabpage: +//======================================================================== + +SfxTabPage* __EXPORT ScDocStatPage::Create( Window *pParent, const SfxItemSet& rSet ) +{ + return new ScDocStatPage( pParent, rSet ); +} + +//------------------------------------------------------------------------ + +ScDocStatPage::ScDocStatPage( Window *pParent, const SfxItemSet& rSet ) + : SfxTabPage( pParent, ScResId(RID_SCPAGE_STAT), rSet ), + aFlInfo ( this, ScResId( FL_INFO ) ), + aFtTablesLbl ( this, ScResId( FT_TABLES_LBL ) ), + aFtTables ( this, ScResId( FT_TABLES ) ), + aFtCellsLbl ( this, ScResId( FT_CELLS_LBL ) ), + aFtCells ( this, ScResId( FT_CELLS ) ), + aFtPagesLbl ( this, ScResId( FT_PAGES_LBL ) ), + aFtPages ( this, ScResId( FT_PAGES ) ) +{ + ScDocShell* pDocSh = PTR_CAST( ScDocShell, SfxObjectShell::Current() ); + ScDocStat aDocStat; + + if ( pDocSh ) + pDocSh->GetDocStat( aDocStat ); + + String aInfo = aFlInfo.GetText(); + aInfo += aDocStat.aDocName; + aFlInfo .SetText( aInfo ); + aFtTables .SetText( String::CreateFromInt32( aDocStat.nTableCount ) ); + aFtCells .SetText( String::CreateFromInt32( aDocStat.nCellCount ) ); + aFtPages .SetText( String::CreateFromInt32( aDocStat.nPageCount ) ); + + FreeResource(); +} + +//------------------------------------------------------------------------ + +__EXPORT ScDocStatPage::~ScDocStatPage() +{ +} + +//------------------------------------------------------------------------ + +BOOL __EXPORT ScDocStatPage::FillItemSet( SfxItemSet& /* rSet */ ) +{ + return FALSE; +} + +//------------------------------------------------------------------------ + +void __EXPORT ScDocStatPage::Reset( const SfxItemSet& /* rSet */ ) +{ +} + + + + diff --git a/sc/source/ui/docshell/tpstat.hrc b/sc/source/ui/docshell/tpstat.hrc new file mode 100644 index 000000000000..2b57d20f1a26 --- /dev/null +++ b/sc/source/ui/docshell/tpstat.hrc @@ -0,0 +1,36 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ +#include "sc.hrc" + +#define FT_TABLES 1 +#define FT_TABLES_LBL 2 +#define FT_CELLS 3 +#define FT_CELLS_LBL 4 +#define FT_PAGES 5 +#define FT_PAGES_LBL 6 + +#define FL_INFO 1 diff --git a/sc/source/ui/docshell/tpstat.src b/sc/source/ui/docshell/tpstat.src new file mode 100644 index 000000000000..7226da4642c3 --- /dev/null +++ b/sc/source/ui/docshell/tpstat.src @@ -0,0 +1,112 @@ +/************************************************************************* + * + * 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. + * + ************************************************************************/ + +#include "tpstat.hrc" +TabPage RID_SCPAGE_STAT +{ + // HelpID = HID_DOC_STAT; + Hide = TRUE ; + Size = MAP_APPFONT ( 260 , 185 ) ; + FixedText FT_TABLES_LBL + { + Pos = MAP_APPFONT ( 12 , 17 ) ; + Size = MAP_APPFONT ( 90 , 8 ) ; + Text [ en-US ] = "Number of sheets:" ; + Left = TRUE ; + }; + FixedText FT_TABLES + { + Pos = MAP_APPFONT ( 108 , 17 ) ; + Size = MAP_APPFONT ( 27 , 8 ) ; + Left = TRUE ; + }; + FixedText FT_CELLS_LBL + { + Pos = MAP_APPFONT ( 12 , 29 ) ; + Size = MAP_APPFONT ( 90 , 8 ) ; + Text [ en-US ] = "Number of cells:" ; + Left = TRUE ; + }; + FixedText FT_CELLS + { + Pos = MAP_APPFONT ( 108 , 29 ) ; + Size = MAP_APPFONT ( 27 , 8 ) ; + Left = TRUE ; + }; + FixedText FT_PAGES_LBL + { + Pos = MAP_APPFONT ( 12 , 41 ) ; + Size = MAP_APPFONT ( 90 , 8 ) ; + Text [ en-US ] = "Number of pages:" ; + Left = TRUE ; + }; + FixedText FT_PAGES + { + Pos = MAP_APPFONT ( 108 , 41 ) ; + Size = MAP_APPFONT ( 27 , 8 ) ; + Left = TRUE ; + }; + FixedLine FL_INFO + { + Pos = MAP_APPFONT ( 6 , 3 ) ; + Size = MAP_APPFONT ( 248 , 8 ) ; + Text [ en-US ] = "Document: " ; + }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |