summaryrefslogtreecommitdiff
path: root/sc/source/ui/docshell/tablink.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/docshell/tablink.cxx')
-rw-r--r--sc/source/ui/docshell/tablink.cxx620
1 files changed, 620 insertions, 0 deletions
diff --git a/sc/source/ui/docshell/tablink.cxx b/sc/source/ui/docshell/tablink.cxx
new file mode 100644
index 000000000000..b962bcfd37e1
--- /dev/null
+++ b/sc/source/ui/docshell/tablink.cxx
@@ -0,0 +1,620 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * 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,
+ sal_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( sal_True ),
+ bDoPaint( sal_True )
+{
+ pImpl->m_pDocSh = pDocSh;
+}
+
+ScTableLink::ScTableLink(SfxObjectShell* pShell, const String& rFile,
+ const String& rFilter, const String& rOpt,
+ sal_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( sal_True ),
+ bDoPaint( sal_True )
+{
+ pImpl->m_pDocSh = static_cast< ScDocShell* >( pShell );
+ SetRefreshHandler( LINK( this, ScTableLink, RefreshHdl ) );
+ SetRefreshControl( pImpl->m_pDocSh->GetDocument()->GetRefreshTimerControlAddress() );
+}
+
+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 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 = sal_True;
+ SvBaseLink::Edit( pParent, LINK( this, ScTableLink, TableEndEditHdl ) );
+}
+
+void 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 ScTableLink::Closed()
+{
+ // Verknuepfung loeschen: Undo
+ ScDocument* pDoc = pImpl->m_pDocSh->GetDocument();
+ sal_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();
+}
+
+sal_Bool ScTableLink::IsUsed() const
+{
+ return pImpl->m_pDocSh->GetDocument()->HasLink( aFileName, aFilterName, aOptions );
+}
+
+sal_Bool ScTableLink::Refresh(const String& rNewFile, const String& rNewFilter,
+ const String* pNewOptions, sal_uLong nNewRefresh )
+{
+ // Dokument laden
+
+ if (!rNewFile.Len() || !rNewFilter.Len())
+ return false;
+
+ String aNewUrl( ScGlobal::GetAbsDocName( rNewFile, pImpl->m_pDocSh ) );
+ sal_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( sal_True );
+
+ sal_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( sal_True ); // enable the filter options dialog
+
+ // aRef->DoClose() will be called explicitly, but it is still more safe to use SfxObjectShellLock here
+ ScDocShell* pSrcShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
+ SfxObjectShellLock aRef = pSrcShell;
+ pSrcShell->DoLoad(pMed);
+
+ // Optionen koennten gesetzt worden sein
+ String aNewOpt = ScDocumentLoader::GetOptions(*pMed);
+ if (!aNewOpt.Len())
+ aNewOpt = aOptions;
+
+ // Undo...
+
+ ScDocument* pUndoDoc = NULL;
+ sal_Bool bFirst = sal_True;
+ if (bAddUndo && bUndo)
+ pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
+
+ // Tabellen kopieren
+
+ ScDocShellModificator aModificator( *pImpl->m_pDocSh );
+
+ sal_Bool bNotFound = false;
+ ScDocument* pSrcDoc = pSrcShell->GetDocument();
+
+ // from text filters that don't set the table name,
+ // use the one table regardless of link table name
+ sal_Bool bAutoTab = (pSrcDoc->GetTableCount() == 1) &&
+ ScDocShell::HasAutomaticTableName( rNewFilter );
+
+ SCTAB nCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ {
+ sal_uInt8 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, sal_True, sal_True );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab, sal_True, sal_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, sal_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 )
+ {
+ // 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();
+ }
+
+ size_t nRanges = aErrorCells.size();
+ if ( nRanges ) // found any?
+ {
+ ScTokenArray aTokenArr;
+ aTokenArr.AddOpCode( ocNotAvail );
+ aTokenArr.AddOpCode( ocOpen );
+ aTokenArr.AddOpCode( ocClose );
+ aTokenArr.AddOpCode( ocStop );
+
+ for (size_t nPos=0; nPos < nRanges; nPos++)
+ {
+ const ScRange* pRange = aErrorCells[ 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 = sal_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
+
+ 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 sal_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 )
+{
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxPoolItem* pItem;
+ if ( pSet && SFX_ITEM_SET == pSet->GetItemState( SID_FILE_FILTEROPTIONS, sal_True, &pItem ) )
+ return ((const SfxStringItem*)pItem)->GetValue();
+
+ return EMPTY_STRING;
+}
+
+sal_Bool ScDocumentLoader::GetFilterName( const String& rFileName,
+ String& rFilter, String& rOptions,
+ sal_Bool bWithContent, sal_Bool bWithInteraction )
+{
+ 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 sal_True;
+ }
+ }
+ pDocSh = SfxObjectShell::GetNext( *pDocSh, &aScType );
+ }
+
+ INetURLObject aUrl( rFileName );
+ INetProtocol eProt = aUrl.GetProtocol();
+ if ( eProt == INET_PROT_NOT_VALID ) // invalid URL?
+ return false; // abort without creating a medium
+
+ // Filter-Detection
+
+ const SfxFilter* pSfxFilter = NULL;
+ SfxMedium* pMedium = new SfxMedium( rFileName, STREAM_STD_READ, false );
+ if ( pMedium->GetError() == ERRCODE_NONE )
+ {
+ if ( bWithInteraction )
+ pMedium->UseInteractionHandler(sal_True); // #i73992# no longer called from GuessFilter
+
+ SfxFilterMatcher aMatcher( String::CreateFromAscii("scalc") );
+ if( bWithContent )
+ aMatcher.GuessFilter( *pMedium, &pSfxFilter );
+ else
+ aMatcher.GuessFilterIgnoringContent( *pMedium, &pSfxFilter );
+ }
+
+ sal_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 )
+{
+ 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,
+ sal_uInt32 nRekCnt, sal_Bool bWithInteraction ) :
+ pDocShell(0),
+ pMedium(0)
+{
+ if ( !rFilterName.Len() )
+ GetFilterName( rFileName, rFilterName, rOptions, sal_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( sal_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 ( 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;
+}
+
+sal_Bool ScDocumentLoader::IsError() const
+{
+ if ( pDocShell && pMedium )
+ return pMedium->GetError() != ERRCODE_NONE;
+ else
+ return sal_True;
+}
+
+String ScDocumentLoader::GetTitle() const
+{
+ if ( pDocShell )
+ return pDocShell->GetTitle();
+ else
+ return EMPTY_STRING;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */