diff options
Diffstat (limited to 'sw/source/core/docnode')
24 files changed, 18736 insertions, 0 deletions
diff --git a/sw/source/core/docnode/cancellablejob.cxx b/sw/source/core/docnode/cancellablejob.cxx new file mode 100644 index 000000000000..ec32c602137f --- /dev/null +++ b/sw/source/core/docnode/cancellablejob.cxx @@ -0,0 +1,43 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <cancellablejob.hxx> +#include <observablethread.hxx> + +CancellableJob::CancellableJob( const rtl::Reference< ObservableThread >& rThread ) : + mrThread( rThread ) +{ +} + +// ::com::sun::star::util::XCancellable: +void SAL_CALL CancellableJob::cancel() throw (com::sun::star::uno::RuntimeException) +{ + mrThread->join(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/cancellablejob.hxx b/sw/source/core/docnode/cancellablejob.hxx new file mode 100644 index 000000000000..d675159f757b --- /dev/null +++ b/sw/source/core/docnode/cancellablejob.hxx @@ -0,0 +1,56 @@ +/* -*- 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. + * + ************************************************************************/ +#ifndef _CANCELLABLEJOB_HXX +#define _CANCELLABLEJOB_HXX + +#include "sal/config.h" +#include "cppuhelper/implbase1.hxx" +#include "com/sun/star/util/XCancellable.hpp" + +#include <rtl/ref.hxx> + +class ObservableThread; + +class CancellableJob : public ::cppu::WeakImplHelper1<com::sun::star::util::XCancellable> +{ +public: + explicit CancellableJob( const ::rtl::Reference< ObservableThread >& rThread ); + ~CancellableJob() {} + + // ::com::sun::star::util::XCancellable: + virtual void SAL_CALL cancel() throw (com::sun::star::uno::RuntimeException); + +private: + CancellableJob( CancellableJob& ); // not defined + void operator =( CancellableJob& ); // not defined + + ::rtl::Reference< ObservableThread > mrThread; +}; +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/finalthreadmanager.cxx b/sw/source/core/docnode/finalthreadmanager.cxx new file mode 100644 index 000000000000..f1ab71a0f1eb --- /dev/null +++ b/sw/source/core/docnode/finalthreadmanager.cxx @@ -0,0 +1,505 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <finalthreadmanager.hxx> + +#include <osl/thread.hxx> +#include <pausethreadstarting.hxx> +#include <swthreadjoiner.hxx> + +#include <com/sun/star/frame/XDesktop.hpp> +#include <rtl/ustring.hxx> +#include <com/sun/star/frame/XFramesSupplier.hpp> + +namespace css = ::com::sun::star; + +/** thread to cancel a give list of cancellable jobs + + helper class for FinalThreadManager + + @author OD +*/ +class CancelJobsThread : public osl::Thread +{ + public: + CancelJobsThread( std::list< css::uno::Reference< css::util::XCancellable > > aJobs ) + : osl::Thread(), + maMutex(), + maJobs( aJobs ), + mbAllJobsCancelled( false ), + mbStopped( false ) + { + } + + virtual ~CancelJobsThread() {} + + void addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs ); + bool allJobsCancelled() const; + void stopWhenAllJobsCancelled(); + + private: + bool existJobs() const; + + css::uno::Reference< css::util::XCancellable > getNextJob(); + + bool stopped() const; + virtual void SAL_CALL run(); + mutable osl::Mutex maMutex; + + std::list< css::uno::Reference< css::util::XCancellable > > maJobs; + + bool mbAllJobsCancelled; + bool mbStopped; +}; + +void CancelJobsThread::addJobs( std::list< css::uno::Reference< css::util::XCancellable > >& rJobs ) +{ + osl::MutexGuard aGuard(maMutex); + + maJobs.insert( maJobs.end(), rJobs.begin(), rJobs.end() ); + mbAllJobsCancelled = !maJobs.empty(); +} + +bool CancelJobsThread::existJobs() const +{ + osl::MutexGuard aGuard(maMutex); + + return !maJobs.empty(); +} + +bool CancelJobsThread::allJobsCancelled() const +{ + osl::MutexGuard aGuard(maMutex); + + return maJobs.empty() && mbAllJobsCancelled; +} +void CancelJobsThread::stopWhenAllJobsCancelled() +{ + osl::MutexGuard aGuard(maMutex); + + mbStopped = true; +} + +css::uno::Reference< css::util::XCancellable > CancelJobsThread::getNextJob() +{ + css::uno::Reference< css::util::XCancellable > xRet; + + { + osl::MutexGuard aGuard(maMutex); + + if ( !maJobs.empty() ) + { + xRet = maJobs.front(); + maJobs.pop_front(); + } + } + + return xRet; +} + +bool CancelJobsThread::stopped() const +{ + osl::MutexGuard aGuard(maMutex); + + return mbStopped; +} + +void SAL_CALL CancelJobsThread::run() +{ + while ( !stopped() ) + { + while ( existJobs() ) + { + css::uno::Reference< css::util::XCancellable > aJob( getNextJob() ); + if ( aJob.is() ) + aJob->cancel(); + } + + mbAllJobsCancelled = true; + + { + TimeValue aSleepTime; + aSleepTime.Seconds = 1; + aSleepTime.Nanosec = 0; + osl_waitThread( &aSleepTime ); + } + } +} + +/** thread to terminate office, when all jobs are cancelled. + + helper class for FinalThreadManager + + @author OD +*/ +class TerminateOfficeThread : public osl::Thread +{ + public: + TerminateOfficeThread( CancelJobsThread& rCancelJobsThread, + css::uno::Reference< css::uno::XComponentContext > const & xContext ) + : osl::Thread(), + maMutex(), + mrCancelJobsThread( rCancelJobsThread ), + mbStopOfficeTermination( false ), + mxContext( xContext ) + { + } + + virtual ~TerminateOfficeThread() {} + void StopOfficeTermination(); + + private: + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); + bool OfficeTerminationStopped(); + void PerformOfficeTermination(); + + osl::Mutex maMutex; + + const CancelJobsThread& mrCancelJobsThread; + bool mbStopOfficeTermination; + + css::uno::Reference< css::uno::XComponentContext > mxContext; +}; + +void TerminateOfficeThread::StopOfficeTermination() +{ + osl::MutexGuard aGuard(maMutex); + + mbStopOfficeTermination = true; +} + +bool TerminateOfficeThread::OfficeTerminationStopped() +{ + osl::MutexGuard aGuard(maMutex); + + return mbStopOfficeTermination; +} + +void SAL_CALL TerminateOfficeThread::run() +{ + while ( !OfficeTerminationStopped() ) + { + osl::MutexGuard aGuard(maMutex); + + if ( mrCancelJobsThread.allJobsCancelled() ) + break; + } + + if ( !OfficeTerminationStopped() ) + PerformOfficeTermination(); +} + +void TerminateOfficeThread::PerformOfficeTermination() +{ + css::uno::Reference< css::frame::XFramesSupplier > xTasksSupplier( + mxContext->getServiceManager()->createInstanceWithContext( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ), + mxContext ), + css::uno::UNO_QUERY ); + if ( !xTasksSupplier.is() ) + { + OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XFramesSupplier!" ); + return; + } + + css::uno::Reference< css::container::XElementAccess > xList( xTasksSupplier->getFrames(), css::uno::UNO_QUERY ); + if ( !xList.is() ) + { + OSL_FAIL( "<TerminateOfficeThread::PerformOfficeTermination()> - no XElementAccess!" ); + return; + } + + if ( !xList->hasElements() ) + { + css::uno::Reference< css::frame::XDesktop > xDesktop( xTasksSupplier, css::uno::UNO_QUERY ); + if ( xDesktop.is() && !OfficeTerminationStopped() ) + xDesktop->terminate(); + } +} + +void SAL_CALL TerminateOfficeThread::onTerminated() +{ + if ( OfficeTerminationStopped() ) + delete this; +} + + +/** class FinalThreadManager + + @author OD +*/ +FinalThreadManager::FinalThreadManager(css::uno::Reference< css::uno::XComponentContext > const & context) + : m_xContext(context), + maMutex(), + maThreads(), + mpCancelJobsThread( 0 ), + mpTerminateOfficeThread( 0 ), + mpPauseThreadStarting( 0 ), + mbRegisteredAtDesktop( false ) +{ + +} + +void FinalThreadManager::registerAsListenerAtDesktop() +{ + css::uno::Reference< css::frame::XDesktop > xDesktop( + m_xContext->getServiceManager()->createInstanceWithContext( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ), + m_xContext ), + css::uno::UNO_QUERY ); + + if ( xDesktop.is() ) + xDesktop->addTerminateListener( css::uno::Reference< css::frame::XTerminateListener >( static_cast< cppu::OWeakObject* >( this ), css::uno::UNO_QUERY ) ); +} + +FinalThreadManager::~FinalThreadManager() +{ + if ( mpPauseThreadStarting != 0 ) + { + delete mpPauseThreadStarting; + mpPauseThreadStarting = 0; + } + + if ( mpTerminateOfficeThread != 0 ) + { + mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself. + mpTerminateOfficeThread = 0; + } + + if ( !maThreads.empty() ) + { + OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - still registered jobs are existing -> perform cancellation" ); + cancelAllJobs(); + } + + if ( mpCancelJobsThread != 0 ) + { + if ( !mpCancelJobsThread->allJobsCancelled() ) + OSL_FAIL( "<FinalThreadManager::~FinalThreadManager()> - cancellation of registered jobs not yet finished -> wait for its finish" ); + + mpCancelJobsThread->stopWhenAllJobsCancelled(); + mpCancelJobsThread->join(); + delete mpCancelJobsThread; + mpCancelJobsThread = 0; + } +} + +// com.sun.star.uno.XServiceInfo: +::rtl::OUString SAL_CALL FinalThreadManager::getImplementationName() throw (css::uno::RuntimeException) +{ + return comp_FinalThreadManager::_getImplementationName(); +} + +::sal_Bool SAL_CALL FinalThreadManager::supportsService(::rtl::OUString const & serviceName) throw (css::uno::RuntimeException) +{ + css::uno::Sequence< ::rtl::OUString > serviceNames = comp_FinalThreadManager::_getSupportedServiceNames(); + for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) { + if (serviceNames[i] == serviceName) + return sal_True; + } + return sal_False; +} + +css::uno::Sequence< ::rtl::OUString > SAL_CALL FinalThreadManager::getSupportedServiceNames() throw (css::uno::RuntimeException) +{ + return comp_FinalThreadManager::_getSupportedServiceNames(); +} + +// ::com::sun::star::util::XJobManager: +void SAL_CALL FinalThreadManager::registerJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException) +{ + osl::MutexGuard aGuard(maMutex); + + maThreads.push_back( Job ); + + if ( !mbRegisteredAtDesktop ) + { + registerAsListenerAtDesktop(); + mbRegisteredAtDesktop = true; + } +} + +void SAL_CALL FinalThreadManager::releaseJob(const css::uno::Reference< css::util::XCancellable > & Job) throw (css::uno::RuntimeException) +{ + osl::MutexGuard aGuard(maMutex); + + maThreads.remove( Job ); +} + +void SAL_CALL FinalThreadManager::cancelAllJobs() throw (css::uno::RuntimeException) +{ + std::list< css::uno::Reference< css::util::XCancellable > > aThreads; + { + osl::MutexGuard aGuard(maMutex); + + aThreads.insert( aThreads.end(), maThreads.begin(), maThreads.end() ); + maThreads.clear(); + } + + if ( !aThreads.empty() ) + { + osl::MutexGuard aGuard(maMutex); + + if ( mpCancelJobsThread == 0 ) + { + mpCancelJobsThread = new CancelJobsThread( aThreads );; + if ( !mpCancelJobsThread->create() ) + { + delete mpCancelJobsThread; + mpCancelJobsThread = 0; + while ( !aThreads.empty() ) + { + aThreads.front()->cancel(); + aThreads.pop_front(); + } + } + } + else + mpCancelJobsThread->addJobs( aThreads ); + } +} + +// ::com::sun::star::frame::XTerminateListener +void SAL_CALL FinalThreadManager::queryTermination( const css::lang::EventObject& ) throw (css::frame::TerminationVetoException, css::uno::RuntimeException) +{ + osl::MutexGuard aGuard(maMutex); + + cancelAllJobs(); + // Sleep 1 second to give the thread for job cancellation some time. + // Probably, all started threads have already finished its work. + if ( mpCancelJobsThread != 0 && + !mpCancelJobsThread->allJobsCancelled() ) + { + TimeValue aSleepTime; + aSleepTime.Seconds = 1; + aSleepTime.Nanosec = 0; + osl_waitThread( &aSleepTime ); + } + + if ( mpCancelJobsThread != 0 && + !mpCancelJobsThread->allJobsCancelled() ) + { + if ( mpTerminateOfficeThread != 0 ) + { + if ( mpTerminateOfficeThread->isRunning() ) + mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself. + else + delete mpTerminateOfficeThread; + + mpTerminateOfficeThread = 0; + } + mpTerminateOfficeThread = new TerminateOfficeThread( *mpCancelJobsThread, + m_xContext ); + if ( !mpTerminateOfficeThread->create() ) + { + delete mpTerminateOfficeThread; + mpTerminateOfficeThread = 0; + } + + throw css::frame::TerminationVetoException(); + } + + mpPauseThreadStarting = new SwPauseThreadStarting(); + + return; +} + +void SAL_CALL FinalThreadManager::cancelTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException) +{ + if ( mpPauseThreadStarting != 0 ) + { + delete mpPauseThreadStarting; + mpPauseThreadStarting = 0; + } + + return; +} + +void SAL_CALL FinalThreadManager::notifyTermination( const css::lang::EventObject& ) throw (css::uno::RuntimeException) +{ + if ( mpTerminateOfficeThread != 0 ) + { + if ( mpTerminateOfficeThread->isRunning() ) + mpTerminateOfficeThread->StopOfficeTermination(); // thread kills itself. + else + delete mpTerminateOfficeThread; + + mpTerminateOfficeThread = 0; + } + + if ( !maThreads.empty() ) + cancelAllJobs(); + + if ( mpCancelJobsThread != 0 ) + { + mpCancelJobsThread->stopWhenAllJobsCancelled(); + mpCancelJobsThread->join(); + delete mpCancelJobsThread; + mpCancelJobsThread = 0; + } + + // get reference of this + css::uno::Reference< css::uno::XInterface > aOwnRef( static_cast< cppu::OWeakObject* >( this )); + // notify <SwThreadJoiner> to release its reference + SwThreadJoiner::ReleaseThreadJoiner(); +} + +// ::com::sun:star::lang::XEventListener (inherited via com::sun::star::frame::XTerminateListener) +void SAL_CALL FinalThreadManager::disposing( const css::lang::EventObject& ) throw (css::uno::RuntimeException) +{ + // nothing to do, because instance doesn't hold any references of observed objects +} + +// component helper namespace +namespace comp_FinalThreadManager { + + ::rtl::OUString SAL_CALL _getImplementationName() + { + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.util.comp.FinalThreadManager")); + } + + css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames() + { + css::uno::Sequence< ::rtl::OUString > s(1); + s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.util.JobManager")); + return s; + } + + css::uno::Reference< css::uno::XInterface > SAL_CALL _create( + const css::uno::Reference< css::uno::XComponentContext > & context) + SAL_THROW((css::uno::Exception)) + { + return static_cast< ::cppu::OWeakObject * >(new FinalThreadManager(context)); + } + +} // closing component helper namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndcopy.cxx b/sw/source/core/docnode/ndcopy.cxx new file mode 100644 index 000000000000..090c9654b501 --- /dev/null +++ b/sw/source/core/docnode/ndcopy.cxx @@ -0,0 +1,1620 @@ +/* -*- 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_sw.hxx" + +#include <editeng/brkitem.hxx> + +#define _ZFORLIST_DECLARE_TABLE +#include <hintids.hxx> +#include <fmtpdsc.hxx> +#include <fmtanchr.hxx> +#include <fmtcntnt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <fldbas.hxx> +#include <swtable.hxx> +#include <ddefld.hxx> +#include <undobj.hxx> +#include <IMark.hxx> +#include <mvsave.hxx> +#include <cellatr.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <docary.hxx> +#include <fmtcnct.hxx> +#include <redline.hxx> +#include <paratr.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <SwNodeNum.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif + +namespace +{ + /* + The lcl_CopyBookmarks function has to copy bookmarks from the source to the destination nodes + array. It is called after a call of the _CopyNodes(..) function. But this function does not copy + every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied if the corresponding end/start node is outside the copied pam. + The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node + index inside the pam. + rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number + of "non-copy" nodes between rPam.Start() and rLastIdx. + nNewIdx is the new position of interest. + */ + + static void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const sal_uLong nNewIdx, sal_uLong& rDelCount ) + { + sal_uLong nStart = rPam.Start()->nNode.GetIndex(); + sal_uLong nEnd = rPam.End()->nNode.GetIndex(); + if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward? + { + do // count "non-copy" nodes + { + SwNode& rNode = rLastIdx.GetNode(); + if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd ) + || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) ) + ++rDelCount; + rLastIdx++; + } + while( rLastIdx.GetIndex() < nNewIdx ); + } + else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now, + // no move backward needed + { + while( rLastIdx.GetIndex() > nNewIdx ) + { + SwNode& rNode = rLastIdx.GetNode(); + if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd ) + || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) ) + --rDelCount; + rLastIdx--; + } + } + } + + static void lcl_SetCpyPos( const SwPosition& rOrigPos, + const SwPosition& rOrigStt, + const SwPosition& rCpyStt, + SwPosition& rChgPos, + sal_uLong nDelCount ) + { + sal_uLong nNdOff = rOrigPos.nNode.GetIndex(); + nNdOff -= rOrigStt.nNode.GetIndex(); + nNdOff -= nDelCount; + xub_StrLen nCntntPos = rOrigPos.nContent.GetIndex(); + + // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos> + rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex(); + if( !nNdOff ) + { + // dann nur den Content anpassen + if( nCntntPos > rOrigStt.nContent.GetIndex() ) + nCntntPos = nCntntPos - rOrigStt.nContent.GetIndex(); + else + nCntntPos = 0; + nCntntPos = nCntntPos + rCpyStt.nContent.GetIndex(); + } + rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetCntntNode(), nCntntPos ); + } + + // TODO: use SaveBookmark (from _DelBookmarks) + static void lcl_CopyBookmarks(const SwPaM& rPam, SwPaM& rCpyPam) + { + const SwDoc* pSrcDoc = rPam.GetDoc(); + SwDoc* pDestDoc = rCpyPam.GetDoc(); + const IDocumentMarkAccess* const pSrcMarkAccess = pSrcDoc->getIDocumentMarkAccess(); + ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo()); + + const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); + SwPosition* pCpyStt = rCpyPam.Start(); + + typedef ::std::vector< const ::sw::mark::IMark* > mark_vector_t; + mark_vector_t vMarksToCopy; + for(IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getMarksBegin(); + ppMark != pSrcMarkAccess->getMarksEnd(); + ppMark++) + { + const ::sw::mark::IMark* const pMark = ppMark->get(); + const SwPosition& rMarkStart = pMark->GetMarkStart(); + const SwPosition& rMarkEnd = pMark->GetMarkEnd(); + // only include marks that are in the range and not touching + // both start and end + bool bIsNotOnBoundary = pMark->IsExpanded() + ? (rMarkStart != rStt || rMarkEnd != rEnd) // rMarkStart != rMarkEnd + : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd + if(rMarkStart >= rStt && rMarkEnd <= rEnd && bIsNotOnBoundary) + { + vMarksToCopy.push_back(pMark); + } + } + // We have to count the "non-copied" nodes.. + SwNodeIndex aCorrIdx(rStt.nNode); + sal_uLong nDelCount = 0; + for(mark_vector_t::const_iterator ppMark = vMarksToCopy.begin(); + ppMark != vMarksToCopy.end(); + ++ppMark) + { + const ::sw::mark::IMark* const pMark = *ppMark; + SwPaM aTmpPam(*pCpyStt); + lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount); + lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount); + if(pMark->IsExpanded()) + { + aTmpPam.SetMark(); + lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount); + lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount); + } + + ::sw::mark::IMark* const pNewMark = pDestDoc->getIDocumentMarkAccess()->makeMark( + aTmpPam, + pMark->GetName(), + IDocumentMarkAccess::GetType(*pMark)); + // Explicitly try to get exactly the same name as in the source + // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name + pDestDoc->getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName()); + ::sw::mark::IBookmark* const pNewBookmark = + dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark); + if(pNewBookmark) /* copying additional attributes for bookmarks */ + { + const ::sw::mark::IBookmark* const pOldBookmark = dynamic_cast< const ::sw::mark::IBookmark* >(pMark); + pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode()); + pNewBookmark->SetShortName(pOldBookmark->GetShortName()); + } + ::sfx2::Metadatable const*const pMetadatable( + dynamic_cast< ::sfx2::Metadatable const* >(pMark)); + ::sfx2::Metadatable *const pNewMetadatable( + dynamic_cast< ::sfx2::Metadatable * >(pNewMark)); + if (pMetadatable && pNewMetadatable) + { + pNewMetadatable->RegisterAsCopyOf(*pMetadatable); + } + } + } +} + +// Struktur fuer das Mappen von alten und neuen Frame-Formaten an den +// Boxen und Lines einer Tabelle + +struct _MapTblFrmFmt +{ + const SwFrmFmt *pOld, *pNew; + _MapTblFrmFmt( const SwFrmFmt *pOldFmt, const SwFrmFmt*pNewFmt ) + : pOld( pOldFmt ), pNew( pNewFmt ) + {} +}; + +SV_DECL_VARARR( _MapTblFrmFmts, _MapTblFrmFmt, 0, 10 ) +SV_IMPL_VARARR( _MapTblFrmFmts, _MapTblFrmFmt ); + +SwCntntNode* SwTxtNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const +{ + // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the + // node with the collection and hard attributes. Normally ist the same + // node, but if insert a glossary without formatting, then the Attrnode + // is the prev node of the destionation position in dest. document. + SwTxtNode* pCpyTxtNd = (SwTxtNode*)this; + SwTxtNode* pCpyAttrNd = pCpyTxtNd; + + // kopiere die Formate in das andere Dokument: + SwTxtFmtColl* pColl = 0; + if( pDoc->IsInsOnlyTextGlossary() ) + { + SwNodeIndex aIdx( rIdx, -1 ); + if( aIdx.GetNode().IsTxtNode() ) + { + pCpyAttrNd = aIdx.GetNode().GetTxtNode(); + pColl = &pCpyAttrNd->GetTxtColl()->GetNextTxtFmtColl(); + } + } + if( !pColl ) + pColl = pDoc->CopyTxtColl( *GetTxtColl() ); + + SwTxtNode* pTxtNd = pDoc->GetNodes().MakeTxtNode( rIdx, pColl ); + + // METADATA: register copy + pTxtNd->RegisterAsCopyOf(*pCpyTxtNd); + + // kopiere Attribute/Text + if( !pCpyAttrNd->HasSwAttrSet() ) + // wurde ein AttrSet fuer die Numerierung angelegt, so loesche diesen! + pCpyAttrNd->ResetAllAttr(); + + // if Copy-Textnode unequal to Copy-Attrnode, then copy first + // the attributes into the new Node. + if( pCpyAttrNd != pCpyTxtNd ) + { + pCpyAttrNd->CopyAttr( pTxtNd, 0, 0 ); + if( pCpyAttrNd->HasSwAttrSet() ) + { + SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() ); + aSet.ClearItem( RES_PAGEDESC ); + aSet.ClearItem( RES_BREAK ); + aSet.CopyToModify( *pTxtNd ); + } + } + + // ??? reicht das ??? was ist mit PostIts/Feldern/FeldTypen ??? + // #i96213# - force copy of all attributes + pCpyTxtNd->CopyText( pTxtNd, SwIndex( pCpyTxtNd ), + pCpyTxtNd->GetTxt().Len(), true ); + // <-- + +//FEATURE::CONDCOLL + if( RES_CONDTXTFMTCOLL == pColl->Which() ) + pTxtNd->ChkCondColl(); +//FEATURE::CONDCOLL + + return pTxtNd; +} + + +sal_Bool lcl_SrchNew( const _MapTblFrmFmt& rMap, void * pPara ) +{ + if( rMap.pOld != *(const SwFrmFmt**)pPara ) + return sal_True; + *((const SwFrmFmt**)pPara) = rMap.pNew; + return sal_False; // abbrechen, Pointer gefunden +} + + +struct _CopyTable +{ + SwDoc* pDoc; + sal_uLong nOldTblSttIdx; + _MapTblFrmFmts& rMapArr; + SwTableLine* pInsLine; + SwTableBox* pInsBox; + SwTableNode *pTblNd; + const SwTable *pOldTable; + + _CopyTable( SwDoc* pDc, _MapTblFrmFmts& rArr, sal_uLong nOldStt, + SwTableNode& rTblNd, const SwTable* pOldTbl ) + : pDoc(pDc), nOldTblSttIdx(nOldStt), rMapArr(rArr), + pInsLine(0), pInsBox(0), pTblNd(&rTblNd), pOldTable( pOldTbl ) + {} +}; + +sal_Bool lcl_CopyTblBox( const SwTableBox*& rpBox, void* pPara ); + +sal_Bool lcl_CopyTblLine( const SwTableLine*& rpLine, void* pPara ); + +sal_Bool lcl_CopyTblBox( const SwTableBox*& rpBox, void* pPara ) +{ + _CopyTable* pCT = (_CopyTable*)pPara; + + SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rpBox->GetFrmFmt(); + pCT->rMapArr.ForEach( lcl_SrchNew, &pBoxFmt ); + if( pBoxFmt == rpBox->GetFrmFmt() ) // ein neues anlegen ?? + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMULA, sal_False, + &pItem ) && ((SwTblBoxFormula*)pItem)->IsIntrnlName() ) + { + ((SwTblBoxFormula*)pItem)->PtrToBoxNm( pCT->pOldTable ); + } + + pBoxFmt = pCT->pDoc->MakeTableBoxFmt(); + pBoxFmt->CopyAttrs( *rpBox->GetFrmFmt() ); + + if( rpBox->GetSttIdx() ) + { + SvNumberFormatter* pN = pCT->pDoc->GetNumberFormatter( sal_False ); + if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == pBoxFmt-> + GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) ) + { + sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx ); + if( nNewIdx != nOldIdx ) + pBoxFmt->SetFmtAttr( SwTblBoxNumFormat( nNewIdx )); + + } + } + + pCT->rMapArr.Insert( _MapTblFrmFmt( rpBox->GetFrmFmt(), pBoxFmt ), + pCT->rMapArr.Count() ); + } + + sal_uInt16 nLines = rpBox->GetTabLines().Count(); + SwTableBox* pNewBox; + if( nLines ) + pNewBox = new SwTableBox( pBoxFmt, nLines, pCT->pInsLine ); + else + { + SwNodeIndex aNewIdx( *pCT->pTblNd, + rpBox->GetSttIdx() - pCT->nOldTblSttIdx ); + OSL_ENSURE( aNewIdx.GetNode().IsStartNode(), "Index nicht auf einem StartNode" ); + pNewBox = new SwTableBox( pBoxFmt, aNewIdx, pCT->pInsLine ); + pNewBox->setRowSpan( rpBox->getRowSpan() ); + } + + pCT->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pNewBox, + pCT->pInsLine->GetTabBoxes().Count() ); + + if( nLines ) + { + _CopyTable aPara( *pCT ); + aPara.pInsBox = pNewBox; + ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_CopyTblLine, &aPara ); + } + else if( pNewBox->IsInHeadline( &pCT->pTblNd->GetTable() )) + // in der HeadLine sind die Absaetze mit BedingtenVorlage anzupassen + pNewBox->GetSttNd()->CheckSectionCondColl(); + return sal_True; +} + +sal_Bool lcl_CopyTblLine( const SwTableLine*& rpLine, void* pPara ) +{ + _CopyTable* pCT = (_CopyTable*)pPara; + SwTableLineFmt* pLineFmt = (SwTableLineFmt*)rpLine->GetFrmFmt(); + pCT->rMapArr.ForEach( lcl_SrchNew, &pLineFmt ); + if( pLineFmt == rpLine->GetFrmFmt() ) // ein neues anlegen ?? + { + pLineFmt = pCT->pDoc->MakeTableLineFmt(); + pLineFmt->CopyAttrs( *rpLine->GetFrmFmt() ); + pCT->rMapArr.Insert( _MapTblFrmFmt( rpLine->GetFrmFmt(), pLineFmt ), + pCT->rMapArr.Count()); + } + SwTableLine* pNewLine = new SwTableLine( pLineFmt, + rpLine->GetTabBoxes().Count(), pCT->pInsBox ); + // die neue Zeile in die Tabelle eintragen + if( pCT->pInsBox ) + { + pCT->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCT->pInsBox->GetTabLines().Count() ); + } + else + { + pCT->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCT->pTblNd->GetTable().GetTabLines().Count() ); + } + pCT->pInsLine = pNewLine; + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_CopyTblBox, pCT ); + return sal_True; +} + +SwTableNode* SwTableNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const +{ + // in welchen Array steht ich denn Nodes, UndoNodes ?? + SwNodes& rNds = (SwNodes&)GetNodes(); + + { + if( rIdx < pDoc->GetNodes().GetEndOfInserts().GetIndex() && + rIdx >= pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex() ) + return 0; + } + + // das TableFrmFmt kopieren + String sTblName( GetTable().GetFrmFmt()->GetName() ); + if( !pDoc->IsCopyIsMove() ) + { + const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts(); + for( sal_uInt16 n = rTblFmts.Count(); n; ) + if( rTblFmts[ --n ]->GetName() == sTblName ) + { + sTblName = pDoc->GetUniqueTblName(); + break; + } + } + + SwFrmFmt* pTblFmt = pDoc->MakeTblFrmFmt( sTblName, pDoc->GetDfltFrmFmt() ); + pTblFmt->CopyAttrs( *GetTable().GetFrmFmt() ); + SwTableNode* pTblNd = new SwTableNode( rIdx ); + SwEndNode* pEndNd = new SwEndNode( rIdx, *pTblNd ); + SwNodeIndex aInsPos( *pEndNd ); + + SwTable& rTbl = (SwTable&)pTblNd->GetTable(); + rTbl.RegisterToFormat( *pTblFmt ); + + rTbl.SetRowsToRepeat( GetTable().GetRowsToRepeat() ); + rTbl.SetTblChgMode( GetTable().GetTblChgMode() ); + rTbl.SetTableModel( GetTable().IsNewModel() ); + + SwDDEFieldType* pDDEType = 0; + if( IS_TYPE( SwDDETable, &GetTable() )) + { + // es wird eine DDE-Tabelle kopiert + // ist im neuen Dokument ueberhaupt der FeldTyp vorhanden ? + pDDEType = ((SwDDETable&)GetTable()).GetDDEFldType(); + if( pDDEType->IsDeleted() ) + pDoc->InsDeletedFldType( *pDDEType ); + else + pDDEType = (SwDDEFieldType*)pDoc->InsertFldType( *pDDEType ); + OSL_ENSURE( pDDEType, "unbekannter FieldType" ); + + // tauschen am Node den Tabellen-Pointer aus + SwDDETable* pNewTable = new SwDDETable( pTblNd->GetTable(), pDDEType ); + pTblNd->SetNewTable( pNewTable, sal_False ); + } + // dann kopiere erstmal den Inhalt der Tabelle, die Zuordnung der + // Boxen/Lines und das anlegen der Frames erfolgt spaeter + SwNodeRange aRg( *this, +1, *EndOfSectionNode() ); // (wo stehe in denn nun ??) + + // If there is a table in this table, the table format for the outer table + // does not seem to be used, because the table does not have any contents yet + // (see IsUsed). Therefore the inner table gets the same name as the outer table. + // We have to make sure that the table node of the SwTable is accessible, even + // without any content in aSortCntBoxes. #i26629# + pTblNd->GetTable().SetTableNode( pTblNd ); + rNds._Copy( aRg, aInsPos, sal_False ); + pTblNd->GetTable().SetTableNode( 0 ); + + // Sonderbehandlung fuer eine einzelne Box + if( 1 == GetTable().GetTabSortBoxes().Count() ) + { + aRg.aStart.Assign( *pTblNd, 1 ); + aRg.aEnd.Assign( *pTblNd->EndOfSectionNode() ); + pDoc->GetNodes().SectionDown( &aRg, SwTableBoxStartNode ); + } + + // loesche alle Frames vom kopierten Bereich, diese werden beim + // erzeugen des TableFrames angelegt ! + pTblNd->DelFrms(); + + _MapTblFrmFmts aMapArr; + _CopyTable aPara( pDoc, aMapArr, GetIndex(), *pTblNd, &GetTable() ); + + ((SwTable&)GetTable()).GetTabLines().ForEach( &lcl_CopyTblLine, &aPara ); + + if( pDDEType ) + pDDEType->IncRefCnt(); + + CHECK_TABLE( GetTable() ); + return pTblNd; +} + +void SwTxtNode::CopyCollFmt( SwTxtNode& rDestNd ) +{ + // kopiere die Formate in das andere Dokument: + + // Sonderbehandlung fuer PageBreak/PageDesc/ColBrk + SwDoc* pDestDoc = rDestNd.GetDoc(); + SwAttrSet aPgBrkSet( pDestDoc->GetAttrPool(), aBreakSetRange ); + const SwAttrSet* pSet; + + if( 0 != ( pSet = rDestNd.GetpSwAttrSet() ) ) + { + // Sonderbehandlung fuer unsere Break-Attribute + const SfxPoolItem* pAttr; + if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pAttr ) ) + aPgBrkSet.Put( *pAttr ); + + if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, sal_False, &pAttr ) ) + aPgBrkSet.Put( *pAttr ); + } + + rDestNd.ChgFmtColl( pDestDoc->CopyTxtColl( *GetTxtColl() )); + if( 0 != ( pSet = GetpSwAttrSet() ) ) + pSet->CopyToModify( rDestNd ); + + if( aPgBrkSet.Count() ) + rDestNd.SetAttr( aPgBrkSet ); +} + + +// ----- Copy-Methode vom SwDoc ------ + + // verhinder das Kopieren in Fly's, die im Bereich verankert sind. +sal_Bool lcl_ChkFlyFly( SwDoc* pDoc, sal_uLong nSttNd, sal_uLong nEndNd, + sal_uLong nInsNd ) +{ + const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts(); + + for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n ) + { + SwFrmFmt const*const pFmt = rFrmFmtTbl[n]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AS_CHAR == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId()) || + (FLY_AT_FLY == pAnchor->GetAnchorId()) || + (FLY_AT_PARA == pAnchor->GetAnchorId())) && + nSttNd <= pAPos->nNode.GetIndex() && + pAPos->nNode.GetIndex() < nEndNd ) + { + const SwFmtCntnt& rCntnt = pFmt->GetCntnt(); + SwStartNode* pSNd; + if( !rCntnt.GetCntntIdx() || + 0 == ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() )) + continue; + + if( pSNd->GetIndex() < nInsNd && + nInsNd < pSNd->EndOfSectionIndex() ) + return sal_True; // nicht kopieren !! + + if( lcl_ChkFlyFly( pDoc, pSNd->GetIndex(), + pSNd->EndOfSectionIndex(), nInsNd ) ) + return sal_True; // nicht kopieren !! + } + } + + return sal_False; +} + +void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam ) +{ + const SwDoc* pSrcDoc = rPam.GetDoc(); + const SwRedlineTbl& rTbl = pSrcDoc->GetRedlineTbl(); + if( rTbl.Count() ) + { + SwDoc* pDestDoc = rCpyPam.GetDoc(); + SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End(); + SwPaM* pDelPam = 0; + const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); + // We have to count the "non-copied" nodes + sal_uLong nDelCount = 0; + SwNodeIndex aCorrIdx( pStt->nNode ); + + sal_uInt16 n = 0; + pSrcDoc->GetRedline( *pStt, &n ); + for( ; n < rTbl.Count(); ++n ) + { + const SwRedline* pRedl = rTbl[ n ]; + if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() && pRedl->IsVisible() ) + { + const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End(); + + SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); + switch( eCmpPos ) + { + case POS_COLLIDE_END: + case POS_BEFORE: // Pos1 liegt vor Pos2 + break; + + case POS_COLLIDE_START: + case POS_BEHIND: // Pos1 liegt hinter Pos2 + n = rTbl.Count(); + break; + + default: + { + pDelPam = new SwPaM( *pCpyStt, pDelPam ); + if( *pStt < *pRStt ) + { + lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount ); + lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt, + *pDelPam->GetPoint(), nDelCount ); + } + pDelPam->SetMark(); + + if( *pEnd < *pREnd ) + *pDelPam->GetPoint() = *pCpyEnd; + else + { + lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount ); + lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt, + *pDelPam->GetPoint(), nDelCount ); + } + } + } + } + } + + if( pDelPam ) + { + RedlineMode_t eOld = pDestDoc->GetRedlineMode(); + pDestDoc->SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + + ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo()); + + do { + pDestDoc->DeleteAndJoin( *(SwPaM*)pDelPam->GetNext() ); + if( pDelPam->GetNext() == pDelPam ) + break; + delete pDelPam->GetNext(); + } while( sal_True ); + delete pDelPam; + + pDestDoc->SetRedlineMode_intern( eOld ); + } + } +} + +void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange& rCpyRg ) +{ + SwDoc* pSrcDoc = rRg.aStart.GetNode().GetDoc(); + if( pSrcDoc->GetRedlineTbl().Count() ) + { + SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); + SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd ); + lcl_DeleteRedlines( aRgTmp, aCpyTmp ); + } +} + +// Kopieren eines Bereiches im oder in ein anderes Dokument ! + +bool +SwDoc::CopyRange( SwPaM& rPam, SwPosition& rPos, const bool bCopyAll ) const +{ + const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); + + SwDoc* pDoc = rPos.nNode.GetNode().GetDoc(); + bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection(); + + // kein Copy abfangen. + if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) ) + return false; + + // verhinder das Kopieren in Fly's, die im Bereich verankert sind. + if( pDoc == this ) + { + // Start-/EndNode noch korrigieren + sal_uLong nStt = pStt->nNode.GetIndex(), + nEnd = pEnd->nNode.GetIndex(), + nDiff = nEnd - nStt +1; + SwNode* pNd = GetNodes()[ nStt ]; + if( pNd->IsCntntNode() && pStt->nContent.GetIndex() ) + ++nStt, --nDiff; + if( (pNd = GetNodes()[ nEnd ])->IsCntntNode() && + ((SwCntntNode*)pNd)->Len() != pEnd->nContent.GetIndex() ) + --nEnd, --nDiff; + if( nDiff && + lcl_ChkFlyFly( pDoc, nStt, nEnd, rPos.nNode.GetIndex() ) ) + { + return false; + } + } + + SwPaM* pRedlineRange = 0; + if( pDoc->IsRedlineOn() || + (!pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) ) + pRedlineRange = new SwPaM( rPos ); + + RedlineMode_t eOld = pDoc->GetRedlineMode(); + + bool bRet = false; + + if( pDoc != this ) + { // ordinary copy + bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange ); + } + // Copy in sich selbst (ueber mehrere Nodes wird hier gesondert + // behandelt; in einem TextNode wird normal behandelt) + else if( ! ( *pStt <= rPos && rPos < *pEnd && + ( pStt->nNode != pEnd->nNode || + !pStt->nNode.GetNode().IsTxtNode() )) ) + { // ordinary copy + bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange ); + } + else + { + OSL_ENSURE( this == pDoc, " falscher Copy-Zweig!" ); + OSL_FAIL("mst: i thought this could be dead code;" + "please tell me what you did to get here!"); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + + // dann kopiere den Bereich im unteren DokumentBereich, + // (mit Start/End-Nodes geklammert) und verschiebe diese + // dann an die gewuenschte Stelle. + + SwUndoCpyDoc* pUndo = 0; + SwPaM aPam( rPos ); // UndoBereich sichern + if (pDoc->GetIDocumentUndoRedo().DoesUndo()) + { + pDoc->GetIDocumentUndoRedo().ClearRedo(); + pUndo = new SwUndoCpyDoc( aPam ); + } + + { + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection( + SwNodeIndex( GetNodes().GetEndOfAutotext() )); + aPam.GetPoint()->nNode = *pSttNd->EndOfSectionNode(); + // copy without Frames + pDoc->CopyImpl( rPam, *aPam.GetPoint(), false, bCopyAll, 0 ); + + aPam.GetPoint()->nNode = pDoc->GetNodes().GetEndOfAutotext(); + aPam.SetMark(); + SwCntntNode* pNode = + pDoc->GetNodes().GoPrevious( &aPam.GetMark()->nNode ); + pNode->MakeEndIndex( &aPam.GetMark()->nContent ); + + aPam.GetPoint()->nNode = *aPam.GetNode()->StartOfSectionNode(); + pNode = pDoc->GetNodes().GoNext( &aPam.GetPoint()->nNode ); + pNode->MakeStartIndex( &aPam.GetPoint()->nContent ); + // move to desired position + pDoc->MoveRange( aPam, rPos, DOC_MOVEDEFAULT ); + + pNode = aPam.GetCntntNode(); + *aPam.GetPoint() = rPos; // Cursor umsetzen fuers Undo ! + aPam.SetMark(); // auch den Mark umsetzen !! + aPam.DeleteMark(); // aber keinen Bereich makieren !! + pDoc->DeleteSection( pNode ); // Bereich wieder loeschen + } + + // if Undo is enabled, store the insertion range + if (pDoc->GetIDocumentUndoRedo().DoesUndo()) + { + pUndo->SetInsertRange( aPam ); + pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if( pRedlineRange ) + { + pRedlineRange->SetMark(); + *pRedlineRange->GetPoint() = *aPam.GetPoint(); + *pRedlineRange->GetMark() = *aPam.GetMark(); + } + + pDoc->SetModified(); + bRet = true; + } + + pDoc->SetRedlineMode_intern( eOld ); + if( pRedlineRange ) + { + if( pDoc->IsRedlineOn() ) + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlineRange ), true); + else + pDoc->SplitRedline( *pRedlineRange ); + delete pRedlineRange; + } + + return bRet; +} + +// Kopieren eines Bereiches im oder in ein anderes Dokument ! +// Die Position darf nicht im Bereich liegen !! + +bool lcl_MarksWholeNode(const SwPaM & rPam) +{ + bool bResult = false; + const SwPosition* pStt = rPam.Start(); + const SwPosition* pEnd = rPam.End(); + + if (NULL != pStt && NULL != pEnd) + { + const SwTxtNode* pSttNd = pStt->nNode.GetNode().GetTxtNode(); + const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode(); + + if (NULL != pSttNd && NULL != pEndNd && + pStt->nContent.GetIndex() == 0 && + pEnd->nContent.GetIndex() == pEndNd->Len()) + { + bResult = true; + } + } + + return bResult; +} + +// #i86492# +bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam ) +{ + bool bRet = false; + + const SwTxtNode* pTxtNd = rPam.Start()->nNode.GetNode().GetTxtNode(); + const SwTxtNode* pEndTxtNd = rPam.End()->nNode.GetNode().GetTxtNode(); + if ( pTxtNd && pTxtNd->IsInList() && + pEndTxtNd && pEndTxtNd->IsInList() ) + { + bRet = true; + SwNodeIndex aIdx(rPam.Start()->nNode); + + do + { + aIdx++; + pTxtNd = aIdx.GetNode().GetTxtNode(); + + if ( !pTxtNd || !pTxtNd->IsInList() ) + { + bRet = false; + break; + } + } while ( pTxtNd && pTxtNd != pEndTxtNd ); + } + + + return bRet; +} +// <-- + +bool SwDoc::CopyImpl( SwPaM& rPam, SwPosition& rPos, + const bool bMakeNewFrms, const bool bCopyAll, + SwPaM *const pCpyRange ) const +{ + SwDoc* pDoc = rPos.nNode.GetNode().GetDoc(); + const bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection(); + + SwPosition* pStt = rPam.Start(); + SwPosition* pEnd = rPam.End(); + + // kein Copy abfangen. + if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) || + //JP 29.6.2001: 88963 - dont copy if inspos is in region of start to end + //JP 15.11.2001: don't test inclusive the end, ever exclusive + ( pDoc == this && *pStt <= rPos && rPos < *pEnd )) + { + return false; + } + + const bool bEndEqualIns = pDoc == this && rPos == *pEnd; + + // falls Undo eingeschaltet, erzeuge das UndoCopy-Objekt + SwUndoCpyDoc* pUndo = 0; + SwPaM aCpyPam( rPos ); + + SwTblNumFmtMerge aTNFM( *this, *pDoc ); + + if (pDoc->GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoCpyDoc( aCpyPam ); + pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + + + // bewege den Pam von der Insert-Position ein zurueck, dadurch wird + // die Position nicht "verschoben" + aCpyPam.SetMark(); + sal_Bool bCanMoveBack = aCpyPam.Move( fnMoveBackward, fnGoCntnt ); + // If the position was shifted from more than one node, an end node has been skipped + bool bAfterTable = false; + if ( ( rPos.nNode.GetIndex() - aCpyPam.GetPoint()->nNode.GetIndex() ) > 1 ) + { + // First go back to the original place + aCpyPam.GetPoint()->nNode = rPos.nNode; + aCpyPam.GetPoint()->nContent = rPos.nContent; + + bCanMoveBack = false; + bAfterTable = true; + } + if( !bCanMoveBack ) + aCpyPam.GetPoint()->nNode--; + + SwNodeRange aRg( pStt->nNode, pEnd->nNode ); + SwNodeIndex aInsPos( rPos.nNode ); + const bool bOneNode = pStt->nNode == pEnd->nNode; + SwTxtNode* pSttTxtNd = pStt->nNode.GetNode().GetTxtNode(); + SwTxtNode* pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode(); + SwTxtNode* pDestTxtNd = aInsPos.GetNode().GetTxtNode(); + bool bCopyCollFmt = !pDoc->IsInsOnlyTextGlossary() && + ( ( pDestTxtNd && !pDestTxtNd->GetTxt().Len() ) || + ( !bOneNode && !rPos.nContent.GetIndex() ) ); + bool bCopyBookmarks = true; + sal_Bool bStartIsTxtNode = 0 != pSttTxtNd; + + // #i104585# copy outline num rule to clipboard (for ASCII filter) + if (pDoc->IsClipBoard() && GetOutlineNumRule()) + { + pDoc->SetOutlineNumRule(*GetOutlineNumRule()); + } + + // #i86492# + // Correct the search for a previous list: + // First search for non-outline numbering list. Then search for non-outline + // bullet list. + // Keep also the <ListId> value for possible propagation. + String aListIdToPropagate; + const SwNumRule* pNumRuleToPropagate = + pDoc->SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, true ); + if ( !pNumRuleToPropagate ) + { + pNumRuleToPropagate = + pDoc->SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, true ); + } + // <-- + // #i86492# + // Do not propagate previous found list, if + // - destination is an empty paragraph which is not in a list and + // - source contains at least one paragraph which is not in a list + if ( pNumRuleToPropagate && + pDestTxtNd && !pDestTxtNd->GetTxt().Len() && !pDestTxtNd->IsInList() && + !lcl_ContainsOnlyParagraphsInList( rPam ) ) + { + pNumRuleToPropagate = 0; + } + // <-- + + // Block, damit aus diesem gesprungen werden kann !! + do { + if( pSttTxtNd ) + { + // den Anfang nicht komplett kopieren ? + if( !bCopyCollFmt || bColumnSel || pStt->nContent.GetIndex() ) + { + SwIndex aDestIdx( rPos.nContent ); + sal_Bool bCopyOk = sal_False; + if( !pDestTxtNd ) + { + if( pStt->nContent.GetIndex() || bOneNode ) + pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos, + pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD)); + else + { + pDestTxtNd = static_cast<SwTxtNode*>(pSttTxtNd->MakeCopy( pDoc, aInsPos )); + bCopyOk = sal_True; + } + aDestIdx.Assign( pDestTxtNd, 0 ); + bCopyCollFmt = true; + } + else if( !bOneNode || bColumnSel ) + { + xub_StrLen nCntntEnd = pEnd->nContent.GetIndex(); + { + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + pDoc->SplitNode( rPos, false ); + } + + if( bCanMoveBack && rPos == *aCpyPam.GetPoint() ) + { + // nach dem SplitNode, den CpyPam wieder richtig aufspannen + aCpyPam.Move( fnMoveBackward, fnGoCntnt ); + aCpyPam.Move( fnMoveBackward, fnGoCntnt ); + } + + pDestTxtNd = pDoc->GetNodes()[ aInsPos.GetIndex()-1 ]->GetTxtNode(); + aDestIdx.Assign( pDestTxtNd, pDestTxtNd->GetTxt().Len() ); + + // korrigiere den Bereich wieder !! + if( bEndEqualIns ) + { + sal_Bool bChg = pEnd != rPam.GetPoint(); + if( bChg ) + rPam.Exchange(); + rPam.Move( fnMoveBackward, fnGoCntnt ); + if( bChg ) + rPam.Exchange(); + + aRg.aEnd = pEnd->nNode; + pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode(); + } + else if( rPos == *pEnd ) // Wurde das Ende auch verschoben + { + pEnd->nNode--; + pEnd->nContent.Assign( pDestTxtNd, nCntntEnd ); + aRg.aEnd = pEnd->nNode; + pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode(); + } + } + + // Safe numrule item at destination. + // #i86492# - Safe also <ListId> item of destination. + int aNumRuleState = SFX_ITEM_UNKNOWN; + SwNumRuleItem aNumRuleItem; + int aListIdState = SFX_ITEM_UNKNOWN; + SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() ); + { + const SfxItemSet * pAttrSet = pDestTxtNd->GetpSwAttrSet(); + if (pAttrSet != NULL) + { + const SfxPoolItem * pItem = NULL; + aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, sal_False, &pItem); + if (SFX_ITEM_SET == aNumRuleState) + aNumRuleItem = *((SwNumRuleItem *) pItem); + + aListIdState = + pAttrSet->GetItemState(RES_PARATR_LIST_ID, sal_False, &pItem); + if (SFX_ITEM_SET == aListIdState) + { + aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() ); + } + } + } + // <-- + + if( !bCopyOk ) + { + const xub_StrLen nCpyLen = ( (bOneNode) + ? pEnd->nContent.GetIndex() + : pSttTxtNd->GetTxt().Len() ) + - pStt->nContent.GetIndex(); + pSttTxtNd->CopyText( pDestTxtNd, aDestIdx, + pStt->nContent, nCpyLen ); + if( bEndEqualIns ) + pEnd->nContent -= nCpyLen; + } + + if( bOneNode ) + { + if( bCopyCollFmt ) + { + pSttTxtNd->CopyCollFmt( *pDestTxtNd ); + + /* If only a part of one paragraph is copied + restore the numrule at the destination. */ + // #i86492# - restore also <ListId> item + if ( !lcl_MarksWholeNode(rPam) ) + { + if (SFX_ITEM_SET == aNumRuleState) + { + pDestTxtNd->SetAttr(aNumRuleItem); + } + else + { + pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE); + } + if (SFX_ITEM_SET == aListIdState) + { + pDestTxtNd->SetAttr(aListIdItem); + } + else + { + pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID); + } + } + } + + break; + } + + aRg.aStart++; + } + } + else if( pDestTxtNd ) + { + // Problems with insertion of table selections into "normal" text solved. + // We have to set the correct PaM for Undo, if this PaM starts in a textnode, + // the undo operation will try to merge this node after removing the table. + // If we didn't split a textnode, the PaM should start at the inserted table node + if( rPos.nContent.GetIndex() == pDestTxtNd->Len() ) + { // Insertion at the last position of a textnode (empty or not) + aInsPos++; // The table will be inserted behind the text node + } + else if( rPos.nContent.GetIndex() ) + { // Insertion in the middle of a text node, it has to be split + // (and joined from undo) + bStartIsTxtNode = sal_True; + // splitte den TextNode, bei dem Eingefuegt wird. + + xub_StrLen nCntntEnd = pEnd->nContent.GetIndex(); + { + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + pDoc->SplitNode( rPos, false ); + } + + if( bCanMoveBack && rPos == *aCpyPam.GetPoint() ) + { + // nach dem SplitNode, den CpyPam wieder richtig aufspannen + aCpyPam.Move( fnMoveBackward, fnGoCntnt ); + aCpyPam.Move( fnMoveBackward, fnGoCntnt ); + } + + // korrigiere den Bereich wieder !! + if( bEndEqualIns ) + aRg.aEnd--; + else if( rPos == *pEnd ) // Wurde das Ende auch verschoben + { + rPos.nNode-=2; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), + nCntntEnd ); + rPos.nNode++; + aRg.aEnd--; + } + } + else if( bCanMoveBack ) + { //Insertion at the first position of a text node. It will not be splitted, the table + // will be inserted before the text node. + // See below, before the SetInsertRange funciton of the undo object will be called, + // the CpyPam would be moved to the next content position. This has to be avoided + // We want to be moved to the table node itself thus we have to set bCanMoveBack + // and to manipulate aCpyPam. + bCanMoveBack = false; + aCpyPam.GetPoint()->nNode--; + } + } + + pDestTxtNd = aInsPos.GetNode().GetTxtNode(); + if( pEndTxtNd ) + { + SwIndex aDestIdx( rPos.nContent ); + if( !pDestTxtNd ) + { + pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos, + pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD)); + aDestIdx.Assign( pDestTxtNd, 0 ); + aInsPos--; + + // if we have to insert an extra text node + // at the destination, this node will be our new destination + // (text) node, and thus we set bStartisTxtNode to true. This + // will ensure that this node will be deleted during Undo + // using JoinNext. + DBG_ASSERT( !bStartIsTxtNode, "Oops, undo may be instable now." ); + bStartIsTxtNode = sal_True; + } + + // Save numrule at destination + // #i86492# - Safe also <ListId> item of destination. + int aNumRuleState = SFX_ITEM_UNKNOWN; + SwNumRuleItem aNumRuleItem; + int aListIdState = SFX_ITEM_UNKNOWN; + SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() ); + { + const SfxItemSet* pAttrSet = pDestTxtNd->GetpSwAttrSet(); + if (pAttrSet != NULL) + { + const SfxPoolItem * pItem = NULL; + + aNumRuleState = + pAttrSet->GetItemState(RES_PARATR_NUMRULE, sal_False, &pItem); + if (SFX_ITEM_SET == aNumRuleState) + aNumRuleItem = *((SwNumRuleItem *) pItem); + + aListIdState = + pAttrSet->GetItemState(RES_PARATR_LIST_ID, sal_False, &pItem); + if (SFX_ITEM_SET == aListIdState) + aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() ); + } + } + // <-- + + const bool bEmptyDestNd = 0 == pDestTxtNd->GetTxt().Len(); + pEndTxtNd->CopyText( pDestTxtNd, aDestIdx, SwIndex( pEndTxtNd ), + pEnd->nContent.GetIndex() ); + + // auch alle FormatVorlagen kopieren + if( bCopyCollFmt && ( bOneNode || bEmptyDestNd )) + { + pEndTxtNd->CopyCollFmt( *pDestTxtNd ); + + if ( bOneNode ) + { + /* If only a part of one paragraph is copied + restore the numrule at the destination. */ + // #i86492# - restore also <ListId> item + if ( !lcl_MarksWholeNode(rPam) ) + { + if (SFX_ITEM_SET == aNumRuleState) + { + pDestTxtNd->SetAttr(aNumRuleItem); + } + else + { + pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE); + } + if (SFX_ITEM_SET == aListIdState) + { + pDestTxtNd->SetAttr(aListIdItem); + } + else + { + pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID); + } + } + } + } + } + + if( bCopyAll || aRg.aStart != aRg.aEnd ) + { + SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange ); + if( pSttTxtNd && bCopyCollFmt && pDestTxtNd->HasSwAttrSet() ) + { + aBrkSet.Put( *pDestTxtNd->GetpSwAttrSet() ); + if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_BREAK, sal_False ) ) + pDestTxtNd->ResetAttr( RES_BREAK ); + if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_PAGEDESC, sal_False ) ) + pDestTxtNd->ResetAttr( RES_PAGEDESC ); + } + + if( aInsPos == pEnd->nNode ) + { + SwNodeIndex aSaveIdx( aInsPos, -1 ); + CopyWithFlyInFly( aRg, 0,aInsPos, bMakeNewFrms, sal_False ); + aSaveIdx++; + pEnd->nNode = aSaveIdx; + pEnd->nContent.Assign( aSaveIdx.GetNode().GetTxtNode(), 0 ); + } + else + CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, bMakeNewFrms, sal_False ); + + bCopyBookmarks = false; + + // harte Umbrueche wieder in den ersten Node setzen + if( aBrkSet.Count() && 0 != ( pDestTxtNd = pDoc->GetNodes()[ + aCpyPam.GetPoint()->nNode.GetIndex()+1 ]->GetTxtNode() ) ) + { + pDestTxtNd->SetAttr( aBrkSet ); + } + } + } while( sal_False ); + + // Position ummelden ( falls verschoben / im anderen Node ) + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), + rPos.nContent.GetIndex() ); + + if( rPos.nNode != aInsPos ) + { + aCpyPam.GetMark()->nNode = aInsPos; + aCpyPam.GetMark()->nContent.Assign( aCpyPam.GetCntntNode(sal_False), 0 ); + rPos = *aCpyPam.GetMark(); + } + else + *aCpyPam.GetMark() = rPos; + + if ( !bAfterTable ) + aCpyPam.Move( fnMoveForward, bCanMoveBack ? fnGoCntnt : fnGoNode ); + else + { + // Reset the offset to 0 as it was before the insertion + aCpyPam.GetPoint( )->nContent -= aCpyPam.GetPoint( )->nContent; + + aCpyPam.GetPoint( )->nNode++; + // If the next node is a start node, then step back: the start node + // has been copied and needs to be in the selection for the undo + if ( aCpyPam.GetPoint()->nNode.GetNode().IsStartNode() ) + aCpyPam.GetPoint( )->nNode--; + + } + aCpyPam.Exchange(); + + // dann kopiere noch alle Bookmarks + if( bCopyBookmarks && getIDocumentMarkAccess()->getMarksCount() ) + lcl_CopyBookmarks( rPam, aCpyPam ); + + if( nsRedlineMode_t::REDLINE_DELETE_REDLINES & eOld ) + lcl_DeleteRedlines( rPam, aCpyPam ); + + // falls Undo eingeschaltet ist, so speicher den eingefuegten Bereich + if (pDoc->GetIDocumentUndoRedo().DoesUndo()) + { + pUndo->SetInsertRange( aCpyPam, sal_True, bStartIsTxtNode ); + } + + if( pCpyRange ) + { + pCpyRange->SetMark(); + *pCpyRange->GetPoint() = *aCpyPam.GetPoint(); + *pCpyRange->GetMark() = *aCpyPam.GetMark(); + } + + if ( pNumRuleToPropagate ) + { + // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId> + pDoc->SetNumRule( aCpyPam, *pNumRuleToPropagate, false, + aListIdToPropagate, sal_True, true ); + } + + pDoc->SetRedlineMode_intern( eOld ); + pDoc->SetModified(); + + return true; +} + + +// ----- Copy-Methode vom SwDoc - "kopiere Fly's in Fly's" ------ + +void SwDoc::CopyWithFlyInFly( const SwNodeRange& rRg, const xub_StrLen nEndContentIndex, + const SwNodeIndex& rInsPos, sal_Bool bMakeNewFrms, + sal_Bool bDelRedlines, sal_Bool bCopyFlyAtFly ) const +{ + SwDoc* pDest = rInsPos.GetNode().GetDoc(); + + _SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 ); + + SwNodeIndex aSavePos( rInsPos, -1 ); + sal_Bool bEndIsEqualEndPos = rInsPos == rRg.aEnd; + GetNodes()._CopyNodes( rRg, rInsPos, bMakeNewFrms, sal_True ); + aSavePos++; + if( bEndIsEqualEndPos ) + ((SwNodeIndex&)rRg.aEnd) = aSavePos; + + aRedlRest.Restore(); + +#if OSL_DEBUG_LEVEL > 1 + { + //JP 17.06.99: Bug 66973 - check count only if the selection is in + // the same (or no) section. Becaus not full selected + // section are not copied. + const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode(); + SwNodeIndex aTmpI( rRg.aEnd, -1 ); + const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode(); + if( pSSectNd == pESectNd && + !rRg.aStart.GetNode().IsSectionNode() && + !aTmpI.GetNode().IsEndNode() ) + { + OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() == + rRg.aEnd.GetIndex() - rRg.aStart.GetIndex(), + "Es wurden zu wenig Nodes kopiert!" ); + } + } +#endif + + { + ::sw::UndoGuard const undoGuard(pDest->GetIDocumentUndoRedo()); + CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly ); + } + + SwNodeRange aCpyRange( aSavePos, rInsPos ); + + // dann kopiere noch alle Bookmarks + if( getIDocumentMarkAccess()->getMarksCount() ) + { + SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); + SwPaM aCpyTmp( aCpyRange.aStart, aCpyRange.aEnd ); + + lcl_CopyBookmarks( aRgTmp, aCpyTmp ); + } + + if( bDelRedlines && ( nsRedlineMode_t::REDLINE_DELETE_REDLINES & pDest->GetRedlineMode() )) + lcl_DeleteRedlines( rRg, aCpyRange ); + + pDest->GetNodes()._DelDummyNodes( aCpyRange ); +} + +void lcl_ChainFmts( SwFlyFrmFmt *pSrc, SwFlyFrmFmt *pDest ) +{ + SwFmtChain aSrc( pSrc->GetChain() ); + if ( !aSrc.GetNext() ) + { + aSrc.SetNext( pDest ); + pSrc->SetFmtAttr( aSrc ); + } + SwFmtChain aDest( pDest->GetChain() ); + if ( !aDest.GetPrev() ) + { + aDest.SetPrev( pSrc ); + pDest->SetFmtAttr( aDest ); + } +} + +void SwDoc::CopyFlyInFlyImpl( const SwNodeRange& rRg, + const xub_StrLen nEndContentIndex, const SwNodeIndex& rStartIdx, + const bool bCopyFlyAtFly ) const +{ + // Bug 22727: suche erst mal alle Flys zusammen, sortiere sie entsprechend + // ihrer Ordnungsnummer und kopiere sie erst dann. Damit wird + // die Ordnungsnummer (wird nur im DrawModel verwaltet) + // beibehalten. + SwDoc *const pDest = rStartIdx.GetNode().GetDoc(); + _ZSortFlys aArr; + sal_uInt16 nArrLen = GetSpzFrmFmts()->Count(); + + for ( sal_uInt16 n = 0; n < nArrLen; ++n ) + { + SwFrmFmt const*const pFmt = (*GetSpzFrmFmts())[n]; + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + bool bAtCntnt = (pAnchor->GetAnchorId() == FLY_AT_PARA); + if ( pAPos && + ( bAtCntnt || + (pAnchor->GetAnchorId() == FLY_AT_FLY) || + (pAnchor->GetAnchorId() == FLY_AT_CHAR)) && + (( bCopyFlyAtFly && FLY_AT_FLY == pAnchor->GetAnchorId() ) + ? rRg.aStart <= pAPos->nNode.GetIndex() + 1 + : ( IsRedlineMove() + ? rRg.aStart < pAPos->nNode + : rRg.aStart <= pAPos->nNode )) && + pAPos->nNode <= rRg.aEnd ) + { + //frames at the last source node are not always copied: + //- if the node is empty and is the last node of the document or a table cell + // or a text frame then tey have to be copied + //- if the content index in this node is > 0 then paragph and frame bound objects are copied + //- to-character bound objects are copied if their index is <= nEndContentIndex + bool bAdd = false; + if( pAPos->nNode < rRg.aEnd ) + bAdd = true; + if( !bAdd ) + { + bool bEmptyNode = false; + bool bLastNode = false; + // is the node empty? + const SwNodes& rNodes = pAPos->nNode.GetNodes(); + SwTxtNode* pTxtNode; + if( 0 != ( pTxtNode = pAPos->nNode.GetNode().GetTxtNode() )) + { + bEmptyNode = !pTxtNode->GetTxt().Len(); + if( bEmptyNode ) + { + //last node information is only necessary to know for the last TextNode + SwNodeIndex aTmp( pAPos->nNode ); + ++aTmp;//goto next node + while (aTmp.GetNode().IsEndNode()) + { + if( aTmp == rNodes.GetEndOfContent().GetIndex() ) + { + bLastNode = true; + break; + } + ++aTmp; + } + } + } + bAdd = bLastNode && bEmptyNode; + if( !bAdd ) + { + if( bAtCntnt ) + bAdd = nEndContentIndex > 0; + else + bAdd = pAPos->nContent <= nEndContentIndex; + } + } + if( bAdd ) + aArr.Insert( _ZSortFly( pFmt, pAnchor, nArrLen + aArr.Count() )); + } + } + + //Alle kopierten (also die neu erzeugten) Rahmen in ein weiteres Array + //stopfen. Dort sizten sie passend zu den Originalen, damit hinterher + //die Chains entsprechend aufgebaut werden koennen. + SvPtrarr aNewArr( 10, 10 ); + + for ( sal_uInt16 n = 0; n < aArr.Count(); ++n ) + { + const _ZSortFly& rZSortFly = aArr[ n ]; + + // #i59964# + // correct determination of new anchor position + SwFmtAnchor aAnchor( *rZSortFly.GetAnchor() ); + SwPosition* pNewPos = (SwPosition*)aAnchor.GetCntntAnchor(); + // for at-paragraph and at-character anchored objects the new anchor + // position can *not* be determined by the difference of the current + // anchor position to the start of the copied range, because not + // complete selected sections in the copied range aren't copied - see + // method <SwNodes::_CopyNodes(..)>. + // Thus, the new anchor position in the destination document is found + // by counting the text nodes. + if ((aAnchor.GetAnchorId() == FLY_AT_PARA) || + (aAnchor.GetAnchorId() == FLY_AT_CHAR) ) + { + // First, determine number of anchor text node in the copied range. + // Note: The anchor text node *have* to be inside the copied range. + sal_uLong nAnchorTxtNdNumInRange( 0L ); + bool bAnchorTxtNdFound( false ); + SwNodeIndex aIdx( rRg.aStart ); + while ( !bAnchorTxtNdFound && aIdx <= rRg.aEnd ) + { + if ( aIdx.GetNode().IsTxtNode() ) + { + ++nAnchorTxtNdNumInRange; + bAnchorTxtNdFound = aAnchor.GetCntntAnchor()->nNode == aIdx; + } + + ++aIdx; + } + if ( !bAnchorTxtNdFound ) + { + // This case can *not* happen, but to be robust take the first + // text node in the destination document. + OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" ); + nAnchorTxtNdNumInRange = 1; + } + // Second, search corresponding text node in destination document + // by counting forward from start insert position <rStartIdx> the + // determined number of text nodes. + aIdx = rStartIdx; + SwNodeIndex aAnchorNdIdx( rStartIdx ); + const SwNode& aEndOfContentNd = + aIdx.GetNode().GetNodes().GetEndOfContent(); + while ( nAnchorTxtNdNumInRange > 0 && + &(aIdx.GetNode()) != &aEndOfContentNd ) + { + if ( aIdx.GetNode().IsTxtNode() ) + { + --nAnchorTxtNdNumInRange; + aAnchorNdIdx = aIdx; + } + + ++aIdx; + } + if ( !aAnchorNdIdx.GetNode().IsTxtNode() ) + { + // This case can *not* happen, but to be robust take the first + // text node in the destination document. + OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" ); + aAnchorNdIdx = rStartIdx; + while ( !aAnchorNdIdx.GetNode().IsTxtNode() ) + { + ++aAnchorNdIdx; + } + } + // apply found anchor text node as new anchor position + pNewPos->nNode = aAnchorNdIdx; + } + else + { + long nOffset = pNewPos->nNode.GetIndex() - rRg.aStart.GetIndex(); + SwNodeIndex aIdx( rStartIdx, nOffset ); + pNewPos->nNode = aIdx; + } + // <-- + // die am Zeichen Flys wieder ans das vorgegebene Zeichen setzen + if ((FLY_AT_CHAR == aAnchor.GetAnchorId()) && + pNewPos->nNode.GetNode().IsTxtNode() ) + { + pNewPos->nContent.Assign( (SwTxtNode*)&pNewPos->nNode.GetNode(), + pNewPos->nContent.GetIndex() ); + } + else + { + pNewPos->nContent.Assign( 0, 0 ); + } + + // ueberpruefe Rekursion: Inhalt in "seinen eigenen" Frame + // kopieren. Dann nicht kopieren + sal_Bool bMakeCpy = sal_True; + if( pDest == this ) + { + const SwFmtCntnt& rCntnt = rZSortFly.GetFmt()->GetCntnt(); + const SwStartNode* pSNd; + if( rCntnt.GetCntntIdx() && + 0 != ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ) && + pSNd->GetIndex() < rStartIdx.GetIndex() && + rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() ) + { + bMakeCpy = sal_False; + aArr.Remove( n, 1 ); + --n; + } + } + + // Format kopieren und den neuen Anker setzen + if( bMakeCpy ) + aNewArr.Insert( pDest->CopyLayoutFmt( *rZSortFly.GetFmt(), + aAnchor, false, true ), aNewArr.Count() ); + } + + //Alle chains, die im Original vorhanden sind, soweit wie moeglich wieder + //aufbauen. + OSL_ENSURE( aArr.Count() == aNewArr.Count(), "Missing new Flys" ); + if ( aArr.Count() == aNewArr.Count() ) + { + for ( sal_uInt16 n = 0; n < aArr.Count(); ++n ) + { + const SwFrmFmt *pFmt = aArr[n].GetFmt(); + const SwFmtChain &rChain = pFmt->GetChain(); + int nCnt = 0 != rChain.GetPrev(); + nCnt += rChain.GetNext() ? 1: 0; + for ( sal_uInt16 k = 0; nCnt && k < aArr.Count(); ++k ) + { + const _ZSortFly &rTmp = aArr[k]; + const SwFrmFmt *pTmp = rTmp.GetFmt(); + if ( rChain.GetPrev() == pTmp ) + { + ::lcl_ChainFmts( (SwFlyFrmFmt*)aNewArr[k], + (SwFlyFrmFmt*)aNewArr[n] ); + --nCnt; + } + else if ( rChain.GetNext() == pTmp ) + { + ::lcl_ChainFmts( (SwFlyFrmFmt*)aNewArr[n], + (SwFlyFrmFmt*)aNewArr[k] ); + --nCnt; + } + } + } + } +} + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndindex.cxx b/sw/source/core/docnode/ndindex.cxx new file mode 100644 index 000000000000..3b064674d7bd --- /dev/null +++ b/sw/source/core/docnode/ndindex.cxx @@ -0,0 +1,166 @@ +/* -*- 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_sw.hxx" + +#include "ndindex.hxx" + +#if OSL_DEBUG_LEVEL > 1 +int SwNodeIndex::nSerial = 0; +#endif + + +SwNodeRange::SwNodeRange( const SwNodeIndex &rS, const SwNodeIndex &rE ) + : aStart( rS ), aEnd( rE ) +{} + +SwNodeRange::SwNodeRange( const SwNodeRange &rRange ) + : aStart( rRange.aStart ), aEnd( rRange.aEnd ) +{} + +SwNodeRange::SwNodeRange( SwNodes& rNds, sal_uLong nSttIdx, sal_uLong nEndIdx ) + : aStart( rNds, nSttIdx ), aEnd( rNds, nEndIdx ) +{} + + +SwNodeRange::SwNodeRange( const SwNodeIndex& rS, long nSttDiff, + const SwNodeIndex& rE, long nEndDiff ) + : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) +{} + +SwNodeRange::SwNodeRange( const SwNode& rS, long nSttDiff, + const SwNode& rE, long nEndDiff ) + : aStart( rS, nSttDiff ), aEnd( rE, nEndDiff ) +{} + + +SwNodeIndex::SwNodeIndex( SwNodes& rNds, sal_uLong nIdx ) + : pNd( rNds[ nIdx ] ), pNext( 0 ), pPrev( 0 ) +{ + rNds.RegisterIndex( *this ); + +#if OSL_DEBUG_LEVEL > 1 + MySerial = ++nSerial; // nur in der nicht PRODUCT-Version +#endif +} + + +SwNodeIndex::SwNodeIndex( const SwNodeIndex& rIdx, long nDiff ) + : pNext( 0 ), pPrev( 0 ) +{ + if( nDiff ) + pNd = rIdx.GetNodes()[ rIdx.GetIndex() + nDiff ]; + else + pNd = rIdx.pNd; + + pNd->GetNodes().RegisterIndex( *this ); +#if OSL_DEBUG_LEVEL > 1 + MySerial = ++nSerial; // nur in der nicht PRODUCT-Version +#endif +} + + +SwNodeIndex::SwNodeIndex( const SwNode& rNd, long nDiff ) + : pNext( 0 ), pPrev( 0 ) +{ + if( nDiff ) + pNd = rNd.GetNodes()[ rNd.GetIndex() + nDiff ]; + else + pNd = (SwNode*)&rNd; + + pNd->GetNodes().RegisterIndex( *this ); +#if OSL_DEBUG_LEVEL > 1 + MySerial = ++nSerial; // nur in der nicht PRODUCT-Version +#endif +} + + +void SwNodeIndex::Remove() +{ + pNd->GetNodes().DeRegisterIndex( *this ); +} + +SwNodeIndex& SwNodeIndex::operator=( const SwNodeIndex& rIdx ) +{ + if( &pNd->GetNodes() != &rIdx.pNd->GetNodes() ) + { + pNd->GetNodes().DeRegisterIndex( *this ); + pNd = rIdx.pNd; + pNd->GetNodes().RegisterIndex( *this ); + } + else + pNd = rIdx.pNd; + return *this; +} + +SwNodeIndex& SwNodeIndex::operator=( const SwNode& rNd ) +{ + if( &pNd->GetNodes() != &rNd.GetNodes() ) + { + pNd->GetNodes().DeRegisterIndex( *this ); + pNd = (SwNode*)&rNd; + pNd->GetNodes().RegisterIndex( *this ); + } + else + pNd = (SwNode*)&rNd; + return *this; +} + +SwNodeIndex& SwNodeIndex::Assign( SwNodes& rNds, sal_uLong nIdx ) +{ + if( &pNd->GetNodes() != &rNds ) + { + pNd->GetNodes().DeRegisterIndex( *this ); + pNd = rNds[ nIdx ]; + pNd->GetNodes().RegisterIndex( *this ); + } + else + pNd = rNds[ nIdx ]; + return *this; +} + +SwNodeIndex& SwNodeIndex::Assign( const SwNode& rNd, long nOffset ) +{ + if( &pNd->GetNodes() != &rNd.GetNodes() ) + { + pNd->GetNodes().DeRegisterIndex( *this ); + pNd = (SwNode*)&rNd; + pNd->GetNodes().RegisterIndex( *this ); + } + else + pNd = (SwNode*)&rNd; + + if( nOffset ) + pNd = pNd->GetNodes()[ pNd->GetIndex() + nOffset ]; + + return *this; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndnotxt.cxx b/sw/source/core/docnode/ndnotxt.cxx new file mode 100644 index 000000000000..c244e14267c4 --- /dev/null +++ b/sw/source/core/docnode/ndnotxt.cxx @@ -0,0 +1,308 @@ +/* -*- 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_sw.hxx" + + +#include <hintids.hxx> +#include <tools/poly.hxx> +#include <svl/stritem.hxx> +#include <svx/contdlg.hxx> +#include <vcl/svapp.hxx> +#include <docary.hxx> +#include <doc.hxx> +#include <fmtcol.hxx> +#include <ndnotxt.hxx> +#include <ndgrf.hxx> +#include <ndole.hxx> +#include <ndindex.hxx> +#include <hints.hxx> // fuer SwFmtChg +#include <istyleaccess.hxx> +#include <SwStyleNameMapper.hxx> + +#include <frmfmt.hxx> // #i73249# + +SwNoTxtNode::SwNoTxtNode( const SwNodeIndex & rWhere, + const sal_uInt8 nNdType, + SwGrfFmtColl *pGrfColl, + SwAttrSet* pAutoAttr ) : + SwCntntNode( rWhere, nNdType, pGrfColl ), + pContour( 0 ), + bAutomaticContour( sal_False ), + bContourMapModeValid( sal_True ), + bPixelContour( sal_False ) +{ + // soll eine Harte-Attributierung gesetzt werden? + if( pAutoAttr ) + SetAttr( *pAutoAttr ); +} + + +SwNoTxtNode::~SwNoTxtNode() +{ + delete pContour; +} + + +// erzeugt fuer alle Ableitungen einen AttrSet mit Bereichen +// fuer Frame- und Grafik-Attributen +void SwNoTxtNode::NewAttrSet( SwAttrPool& rPool ) +{ + OSL_ENSURE( !mpAttrSet.get(), "AttrSet ist doch gesetzt" ); + SwAttrSet aNewAttrSet( rPool, aNoTxtNodeSetRange ); + + // put names of parent style and conditional style: + const SwFmtColl* pFmtColl = GetFmtColl(); + String sVal; + SwStyleNameMapper::FillProgName( pFmtColl->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); + SfxStringItem aFmtColl( RES_FRMATR_STYLE_NAME, sVal ); + aNewAttrSet.Put( aFmtColl ); + + aNewAttrSet.SetParent( &GetFmtColl()->GetAttrSet() ); + mpAttrSet = GetDoc()->GetIStyleAccess().getAutomaticStyle( aNewAttrSet, IStyleAccess::AUTO_STYLE_NOTXT ); +} + +// Dummies fuer das Laden/Speichern von persistenten Daten +// bei Grafiken und OLE-Objekten + + +sal_Bool SwNoTxtNode::RestorePersistentData() +{ + return sal_True; +} + + +sal_Bool SwNoTxtNode::SavePersistentData() +{ + return sal_True; +} + + +void SwNoTxtNode::SetContour( const PolyPolygon *pPoly, sal_Bool bAutomatic ) +{ + delete pContour; + if ( pPoly ) + pContour = new PolyPolygon( *pPoly ); + else + pContour = 0; + bAutomaticContour = bAutomatic; + bContourMapModeValid = sal_True; + bPixelContour = sal_False; +} + + +void SwNoTxtNode::CreateContour() +{ + OSL_ENSURE( !pContour, "Contour available." ); + pContour = new PolyPolygon(SvxContourDlg::CreateAutoContour(GetGraphic())); + bAutomaticContour = sal_True; + bContourMapModeValid = sal_True; + bPixelContour = sal_False; +} + +const PolyPolygon *SwNoTxtNode::HasContour() const +{ + if( !bContourMapModeValid ) + { + const MapMode aGrfMap( GetGraphic().GetPrefMapMode() ); + sal_Bool bPixelGrf = aGrfMap.GetMapUnit() == MAP_PIXEL; + const MapMode aContourMap( bPixelGrf ? MAP_PIXEL : MAP_100TH_MM ); + if( bPixelGrf ? !bPixelContour : aGrfMap != aContourMap ) + { + OSL_ENSURE( !bPixelGrf || aGrfMap == aContourMap, + "scale factor for pixel unsupported" ); + OutputDevice* pOutDev = + (bPixelGrf || bPixelContour) ? Application::GetDefaultDevice() + : 0; + sal_uInt16 nPolyCount = pContour->Count(); + for( sal_uInt16 j=0; j<nPolyCount; j++ ) + { + Polygon& rPoly = (*pContour)[j]; + + sal_uInt16 nCount = rPoly.GetSize(); + for( sal_uInt16 i=0 ; i<nCount; i++ ) + { + if( bPixelGrf ) + rPoly[i] = pOutDev->LogicToPixel( rPoly[i], + aContourMap ); + else if( bPixelContour ) + rPoly[i] = pOutDev->PixelToLogic( rPoly[i], aGrfMap ); + else + rPoly[i] = OutputDevice::LogicToLogic( rPoly[i], + aContourMap, + aGrfMap ); + } + } + } + ((SwNoTxtNode *)this)->bContourMapModeValid = sal_True; + ((SwNoTxtNode *)this)->bPixelContour = sal_False; + } + + return pContour; +} + +void SwNoTxtNode::GetContour( PolyPolygon &rPoly ) const +{ + OSL_ENSURE( pContour, "Contour not available." ); + rPoly = *HasContour(); +} + +void SwNoTxtNode::SetContourAPI( const PolyPolygon *pPoly ) +{ + delete pContour; + if ( pPoly ) + pContour = new PolyPolygon( *pPoly ); + else + pContour = 0; + bContourMapModeValid = sal_False; +} + +sal_Bool SwNoTxtNode::GetContourAPI( PolyPolygon &rContour ) const +{ + if( !pContour ) + return sal_False; + + rContour = *pContour; + if( bContourMapModeValid ) + { + const MapMode aGrfMap( GetGraphic().GetPrefMapMode() ); + const MapMode aContourMap( MAP_100TH_MM ); + OSL_ENSURE( aGrfMap.GetMapUnit() != MAP_PIXEL || + aGrfMap == MapMode( MAP_PIXEL ), + "scale factor for pixel unsupported" ); + if( aGrfMap.GetMapUnit() != MAP_PIXEL && + aGrfMap != aContourMap ) + { + sal_uInt16 nPolyCount = rContour.Count(); + for( sal_uInt16 j=0; j<nPolyCount; j++ ) + { + Polygon& rPoly = (*pContour)[j]; + + sal_uInt16 nCount = rPoly.GetSize(); + for( sal_uInt16 i=0 ; i<nCount; i++ ) + { + rPoly[i] = OutputDevice::LogicToLogic( rPoly[i], aGrfMap, + aContourMap ); + } + } + } + } + + return sal_True; +} + +sal_Bool SwNoTxtNode::IsPixelContour() const +{ + sal_Bool bRet; + if( bContourMapModeValid ) + { + const MapMode aGrfMap( GetGraphic().GetPrefMapMode() ); + bRet = aGrfMap.GetMapUnit() == MAP_PIXEL; + } + else + { + bRet = bPixelContour; + } + + return bRet; +} + + +Graphic SwNoTxtNode::GetGraphic() const +{ + Graphic aRet; + if ( GetGrfNode() ) + { + ((SwGrfNode*)this)->SwapIn( sal_True ); + aRet = ((SwGrfNode*)this)->GetGrf(); + } + else + { + OSL_ENSURE( GetOLENode(), "new type of Node?" ); + aRet = *((SwOLENode*)this)->SwOLENode::GetGraphic(); + } + return aRet; +} + +// #i73249# +void SwNoTxtNode::SetTitle( const String& rTitle, bool bBroadcast ) +{ + // Title attribute of <SdrObject> replaces own AlternateText attribute + SwFlyFrmFmt* pFlyFmt = dynamic_cast<SwFlyFrmFmt*>(GetFlyFmt()); + OSL_ENSURE( pFlyFmt, + "<SwNoTxtNode::SetTitle(..)> - missing <SwFlyFrmFmt> instance" ); + if ( !pFlyFmt ) + { + return; + } + + pFlyFmt->SetObjTitle( rTitle, bBroadcast ); +} + +const String SwNoTxtNode::GetTitle() const +{ + const SwFlyFrmFmt* pFlyFmt = dynamic_cast<const SwFlyFrmFmt*>(GetFlyFmt()); + OSL_ENSURE( pFlyFmt, + "<SwNoTxtNode::GetTitle(..)> - missing <SwFlyFrmFmt> instance" ); + if ( !pFlyFmt ) + { + return aEmptyStr; + } + + return pFlyFmt->GetObjTitle(); +} + +void SwNoTxtNode::SetDescription( const String& rDescription, bool bBroadcast ) +{ + SwFlyFrmFmt* pFlyFmt = dynamic_cast<SwFlyFrmFmt*>(GetFlyFmt()); + OSL_ENSURE( pFlyFmt, + "<SwNoTxtNode::SetDescription(..)> - missing <SwFlyFrmFmt> instance" ); + if ( !pFlyFmt ) + { + return; + } + + pFlyFmt->SetObjDescription( rDescription, bBroadcast ); +} + +const String SwNoTxtNode::GetDescription() const +{ + const SwFlyFrmFmt* pFlyFmt = dynamic_cast<const SwFlyFrmFmt*>(GetFlyFmt()); + OSL_ENSURE( pFlyFmt, + "<SwNoTxtNode::GetDescription(..)> - missing <SwFlyFrmFmt> instance" ); + if ( !pFlyFmt ) + { + return aEmptyStr; + } + + return pFlyFmt->GetObjDescription(); +} +// <-- + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndnum.cxx b/sw/source/core/docnode/ndnum.cxx new file mode 100644 index 000000000000..5cbce94d072c --- /dev/null +++ b/sw/source/core/docnode/ndnum.cxx @@ -0,0 +1,148 @@ +/* -*- 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_sw.hxx" + + +#include <node.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <fldbas.hxx> // UpdateFlds der KapitelNummerierung +#include <docary.hxx> + +_SV_IMPL_SORTAR_ALG( SwOutlineNodes, SwNodePtr ) +sal_Bool SwOutlineNodes::Seek_Entry( const SwNodePtr rSrch, sal_uInt16* pFndPos ) const +{ + sal_uLong nIdx = rSrch->GetIndex(); + + sal_uInt16 nO = Count(), nM, nU = 0; + if( nO > 0 ) + { +//JP 17.03.98: aufgrund des Bug 48592 - wo unter anderem nach Undo/Redo +// Nodes aus dem falschen NodesArray im OutlineArray standen, +// jetzt mal einen Check eingebaut. +#if OSL_DEBUG_LEVEL > 1 + { + for( sal_uInt16 n = 1; n < nO; ++n ) + if( &(*this)[ n-1 ]->GetNodes() != + &(*this)[ n ]->GetNodes() ) + { + OSL_ENSURE( !this, "Node im falschen Outline-Array" ); + } + } +#endif + + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + if( (*this)[ nM ] == rSrch ) + { + if( pFndPos ) + *pFndPos = nM; + return sal_True; + } + else if( (*this)[ nM ]->GetIndex() < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pFndPos ) + *pFndPos = nU; + return sal_False; + } + else + nO = nM - 1; + } + } + if( pFndPos ) + *pFndPos = nU; + return sal_False; +} + +void SwNodes::UpdateOutlineNode(SwNode & rNd) +{ + SwTxtNode * pTxtNd = rNd.GetTxtNode(); + + if (pTxtNd && pTxtNd->IsOutlineStateChanged()) + { + sal_Bool bFound = pOutlineNds->Seek_Entry(pTxtNd); + + if (pTxtNd->IsOutline()) + { + if (! bFound) + { + // assure that text is in the correct nodes array + if ( &(pTxtNd->GetNodes()) == this ) + { + pOutlineNds->Insert(pTxtNd); + } + else + { + OSL_FAIL( "<SwNodes::UpdateOutlineNode(..)> - given text node isn't in the correct nodes array. This is a serious defect -> inform OD" ); + } + } + } + else + { + if (bFound) + pOutlineNds->Remove(pTxtNd); + } + + pTxtNd->UpdateOutlineState(); + + // die Gliederungs-Felder Updaten + GetDoc()->GetSysFldType( RES_CHAPTERFLD )->UpdateFlds(); + } +} + +void SwNodes::UpdtOutlineIdx( const SwNode& rNd ) +{ + if( !pOutlineNds->Count() ) // keine OutlineNodes vorhanden ? + return; + + const SwNodePtr pSrch = (SwNodePtr)&rNd; + sal_uInt16 nPos; + pOutlineNds->Seek_Entry( pSrch, &nPos ); + if( nPos == pOutlineNds->Count() ) // keine zum Updaten vorhanden ? + return; + + if( nPos ) + --nPos; + + if( !GetDoc()->IsInDtor() && IsDocNodes() ) + UpdateOutlineNode( *(*pOutlineNds)[ nPos ]); +} + +const SwOutlineNodes & SwNodes::GetOutLineNds() const +{ + return *pOutlineNds; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx new file mode 100644 index 000000000000..00cee7bacd14 --- /dev/null +++ b/sw/source/core/docnode/ndsect.cxx @@ -0,0 +1,1479 @@ +/* -*- 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_sw.hxx" + +#include <svl/smplhint.hxx> +#include <hintids.hxx> +#include <sfx2/linkmgr.hxx> +#include <svl/itemiter.hxx> +#include <tools/resid.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <txtftn.hxx> +#include <fmtclds.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <rootfrm.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <section.hxx> +#include <UndoSection.hxx> +#include <UndoDelete.hxx> +#include <swundo.hxx> +#include <calc.hxx> +#include <swtable.hxx> +#include <swserv.hxx> +#include <frmfmt.hxx> +#include <frmtool.hxx> +#include <ftnidx.hxx> +#include <docary.hxx> +#include <redline.hxx> +#include <sectfrm.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <node2lay.hxx> +#include <doctxm.hxx> +#include <fmtftntx.hxx> +#include <comcore.hrc> +// #i27138# +#include <viewsh.hxx> +#include <txtfrm.hxx> +// <-- + + +// #i21457# - new implementation of local method <lcl_IsInSameTblBox(..)>. +// Method now determines the previous/next on its own. Thus, it can be controlled, +// for which previous/next is checked, if it's visible. +bool lcl_IsInSameTblBox( SwNodes& _rNds, + const SwNode& _rNd, + const bool _bPrev ) +{ + const SwTableNode* pTblNd = _rNd.FindTableNode(); + if ( !pTblNd ) + { + return true; + } + + // determine index to be checked. Its assumed that a previous/next exist. + SwNodeIndex aChkIdx( _rNd ); + { + // determine index of previous/next - skip hidden ones, which are + // inside the table. + // If found one is before/after table, this one isn't in the same + // table box as <_rNd>. + bool bFound = false; + do + { + if ( _bPrev + ? !_rNds.GoPrevSection( &aChkIdx, sal_False, sal_False ) + : !_rNds.GoNextSection( &aChkIdx, sal_False, sal_False ) ) + { + OSL_FAIL( "<lcl_IsInSameTblBox(..)> - no previous/next!" ); + return false; + } + else + { + if ( aChkIdx < pTblNd->GetIndex() || + aChkIdx > pTblNd->EndOfSectionNode()->GetIndex() ) + { + return false; + } + else + { + // check, if found one isn't inside a hidden section, which + // is also inside the table. + SwSectionNode* pSectNd = aChkIdx.GetNode().FindSectionNode(); + if ( !pSectNd || + pSectNd->GetIndex() < pTblNd->GetIndex() || + !pSectNd->GetSection().IsHiddenFlag() ) + { + bFound = true; + } + } + } + } while ( !bFound ); + } + + // dann suche den StartNode der Box + const SwTableSortBoxes& rSortBoxes = pTblNd->GetTable().GetTabSortBoxes(); + sal_uLong nIdx = _rNd.GetIndex(); + for( sal_uInt16 n = 0; n < rSortBoxes.Count(); ++n ) + { + const SwStartNode* pNd = rSortBoxes[ n ]->GetSttNd(); + if ( pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex() ) + { + // dann muss der andere Index in derselben Section liegen + nIdx = aChkIdx.GetIndex(); + return pNd->GetIndex() < nIdx && nIdx < pNd->EndOfSectionIndex(); + } + } + + return true; +} + +void lcl_CheckEmptyLayFrm( SwNodes& rNds, SwSectionData& rSectionData, + const SwNode& rStt, const SwNode& rEnd ) +{ + SwNodeIndex aIdx( rStt ); + if( !rNds.GoPrevSection( &aIdx, sal_True, sal_False ) || + !CheckNodesRange( rStt, aIdx, sal_True ) || + // #i21457# + !lcl_IsInSameTblBox( rNds, rStt, true )) + { + aIdx = rEnd; + if( !rNds.GoNextSection( &aIdx, sal_True, sal_False ) || + !CheckNodesRange( rEnd, aIdx, sal_True ) || + // #i21457# + !lcl_IsInSameTblBox( rNds, rEnd, false )) + { + rSectionData.SetHidden( false ); + } + } +} + +SwSection * +SwDoc::InsertSwSection(SwPaM const& rRange, SwSectionData & rNewData, + SwTOXBase const*const pTOXBase, + SfxItemSet const*const pAttr, bool const bUpdate) +{ + const SwNode* pPrvNd = 0; + sal_uInt16 nRegionRet = 0; + if( rRange.HasMark() && + 0 == ( nRegionRet = IsInsRegionAvailable( rRange, &pPrvNd ) )) + { + OSL_ENSURE( !this, "Selection ueber verschiedene Sections" ); + return 0; + } + + // Teste ob das gesamte Dokument versteckt werden soll, + // koennen wir zur Zeit nicht !!!! + if (rNewData.IsHidden() && rRange.HasMark()) + { + const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); + if( !pStt->nContent.GetIndex() && + pEnd->nNode.GetNode().GetCntntNode()->Len() == + pEnd->nContent.GetIndex() ) + { + ::lcl_CheckEmptyLayFrm( GetNodes(), + rNewData, + pStt->nNode.GetNode(), + pEnd->nNode.GetNode() ); + } + } + + SwUndoInsSection* pUndoInsSect = 0; + bool const bUndo(GetIDocumentUndoRedo().DoesUndo()); + if (bUndo) + { + pUndoInsSect = new SwUndoInsSection(rRange, rNewData, pAttr, pTOXBase); + GetIDocumentUndoRedo().AppendUndo( pUndoInsSect ); + GetIDocumentUndoRedo().DoUndo(false); + } + + SwSectionFmt* const pFmt = MakeSectionFmt( 0 ); + if ( pAttr ) + { + pFmt->SetFmtAttr( *pAttr ); + } + + SwSectionNode* pNewSectNode = 0; + + RedlineMode_t eOld = GetRedlineMode(); + SetRedlineMode_intern( (RedlineMode_t)((eOld & ~nsRedlineMode_t::REDLINE_SHOW_MASK) | nsRedlineMode_t::REDLINE_IGNORE)); + + if( rRange.HasMark() ) + { + SwPosition *pSttPos = (SwPosition*)rRange.Start(), + *pEndPos = (SwPosition*)rRange.End(); + if( pPrvNd && 3 == nRegionRet ) + { + OSL_ENSURE( pPrvNd, "der SectionNode fehlt" ); + SwNodeIndex aStt( pSttPos->nNode ), aEnd( pEndPos->nNode, +1 ); + while( pPrvNd != aStt.GetNode().StartOfSectionNode() ) + aStt--; + while( pPrvNd != aEnd.GetNode().StartOfSectionNode() ) + aEnd++; + + --aEnd; // im InsertSection ist Ende inclusive + pNewSectNode = GetNodes().InsertTextSection( + aStt, *pFmt, rNewData, pTOXBase, & aEnd); + } + else + { + if( pUndoInsSect ) + { + if( !( pPrvNd && 1 == nRegionRet ) && + pSttPos->nContent.GetIndex() ) + { + SwTxtNode* const pTNd = + pSttPos->nNode.GetNode().GetTxtNode(); + if (pTNd) + { + pUndoInsSect->SaveSplitNode( pTNd, sal_True ); + } + } + + if ( !( pPrvNd && 2 == nRegionRet ) ) + { + SwTxtNode *const pTNd = + pEndPos->nNode.GetNode().GetTxtNode(); + if (pTNd && + (pTNd->GetTxt().Len() != pEndPos->nContent.GetIndex())) + { + pUndoInsSect->SaveSplitNode( pTNd, sal_False ); + } + } + } + + const SwCntntNode* pCNd; + if( pPrvNd && 1 == nRegionRet ) + { + pSttPos->nNode.Assign( *pPrvNd ); + pSttPos->nContent.Assign( pSttPos->nNode.GetNode().GetCntntNode(), 0 ); + } + else if( pSttPos->nContent.GetIndex() ) + { + SplitNode( *pSttPos, false ); + } + + if( pPrvNd && 2 == nRegionRet ) + { + pEndPos->nNode.Assign( *pPrvNd ); + pEndPos->nContent.Assign( pEndPos->nNode.GetNode().GetCntntNode(), 0 ); + } + else + { + pCNd = pEndPos->nNode.GetNode().GetCntntNode(); + if( pCNd && pCNd->Len() != pEndPos->nContent.GetIndex() ) + { + xub_StrLen nCntnt = pSttPos->nContent.GetIndex(); + SplitNode( *pEndPos, false ); + + SwTxtNode* pTNd; + if( pEndPos->nNode.GetIndex() == pSttPos->nNode.GetIndex() ) + { + pSttPos->nNode--; + pEndPos->nNode--; + pTNd = pSttPos->nNode.GetNode().GetTxtNode(); + pSttPos->nContent.Assign( pTNd, nCntnt ); + } + else + { + // wieder ans Ende vom vorherigen setzen + pEndPos->nNode--; + pTNd = pEndPos->nNode.GetNode().GetTxtNode(); + } + if( pTNd ) nCntnt = pTNd->GetTxt().Len(); else nCntnt = 0; + pEndPos->nContent.Assign( pTNd, nCntnt ); + } + } + pNewSectNode = GetNodes().InsertTextSection( + pSttPos->nNode, *pFmt, rNewData, pTOXBase, &pEndPos->nNode); + } + } + else + { + const SwPosition* pPos = rRange.GetPoint(); + const SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode(); + if( !pPos->nContent.GetIndex() ) + { + pNewSectNode = GetNodes().InsertTextSection( + pPos->nNode, *pFmt, rNewData, pTOXBase, 0, true); + } + else if( pPos->nContent.GetIndex() == pCNd->Len() ) + { + pNewSectNode = GetNodes().InsertTextSection( + pPos->nNode, *pFmt, rNewData, pTOXBase, 0, false); + } + else + { + if( pUndoInsSect && pCNd->IsTxtNode() ) + { + pUndoInsSect->SaveSplitNode( (SwTxtNode*)pCNd, sal_True ); + } + SplitNode( *pPos, false ); + pNewSectNode = GetNodes().InsertTextSection( + pPos->nNode, *pFmt, rNewData, pTOXBase, 0, true); + } + } + +//FEATURE::CONDCOLL + pNewSectNode->CheckSectionCondColl(); +//FEATURE::CONDCOLL + + SetRedlineMode_intern( eOld ); + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + SwPaM aPam( *pNewSectNode->EndOfSectionNode(), *pNewSectNode, 1 ); + if( IsRedlineOn() ) + { + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + } + else + { + SplitRedline( aPam ); + } + } + + // ist eine Condition gesetzt + if (rNewData.IsHidden() && rNewData.GetCondition().Len()) + { + // dann berechne bis zu dieser Position + SwCalc aCalc( *this ); + if( ! IsInReading() ) + { + FldsToCalc( aCalc, pNewSectNode->GetIndex(), USHRT_MAX ); + } + SwSection& rNewSect = pNewSectNode->GetSection(); + rNewSect.SetCondHidden( aCalc.Calculate( rNewSect.GetCondition() ).GetBool() ); + } + + sal_Bool bUpdateFtn = sal_False; + if( GetFtnIdxs().Count() && pAttr ) + { + sal_uInt16 nVal = ((SwFmtFtnAtTxtEnd&)pAttr->Get( + RES_FTN_AT_TXTEND )).GetValue(); + if( ( FTNEND_ATTXTEND_OWNNUMSEQ == nVal || + FTNEND_ATTXTEND_OWNNUMANDFMT == nVal ) || + ( FTNEND_ATTXTEND_OWNNUMSEQ == ( nVal = ((SwFmtEndAtTxtEnd&) + pAttr->Get( RES_END_AT_TXTEND )).GetValue() ) || + FTNEND_ATTXTEND_OWNNUMANDFMT == nVal )) + { + bUpdateFtn = sal_True; + } + } + + if( pUndoInsSect ) + { + pUndoInsSect->SetSectNdPos( pNewSectNode->GetIndex() ); + pUndoInsSect->SetUpdtFtnFlag( bUpdateFtn ); + GetIDocumentUndoRedo().DoUndo(bUndo); + } + + if (rNewData.IsLinkType()) + { + pNewSectNode->GetSection().CreateLink( bUpdate ? CREATE_UPDATE : CREATE_CONNECT ); + } + + if( bUpdateFtn ) + { + GetFtnIdxs().UpdateFtn( SwNodeIndex( *pNewSectNode )); + } + + SetModified(); + return &pNewSectNode->GetSection(); +} + +sal_uInt16 SwDoc::IsInsRegionAvailable( const SwPaM& rRange, + const SwNode** ppSttNd ) const +{ + sal_uInt16 nRet = 1; + if( rRange.HasMark() ) + { + // teste ob es sich um eine gueltige Selektion handelt + const SwPosition* pStt = rRange.Start(), + * pEnd = rRange.End(); + + const SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode(); + const SwNode* pNd = &pStt->nNode.GetNode(); + const SwSectionNode* pSectNd = pNd->FindSectionNode(); + const SwSectionNode* pEndSectNd = pCNd ? pCNd->FindSectionNode() : 0; + if( pSectNd && pEndSectNd && pSectNd != pEndSectNd ) + { + // versuche eine umschliessende Section zu erzeugen + // Aber, nur wenn der Start am Sectionanfang und das Ende am + // Section Ende liegt! + nRet = 0; + if( !pStt->nContent.GetIndex() && pSectNd->GetIndex() + == pStt->nNode.GetIndex() - 1 && pEnd->nContent.GetIndex() == + pCNd->Len() ) + { + SwNodeIndex aIdx( pStt->nNode, -1 ); + sal_uLong nCmp = pEnd->nNode.GetIndex(); + const SwStartNode* pPrvNd; + const SwEndNode* pNxtNd; + while( 0 != ( pPrvNd = (pNd = &aIdx.GetNode())->GetSectionNode() ) && + !( aIdx.GetIndex() < nCmp && + nCmp < pPrvNd->EndOfSectionIndex() ) ) + { + aIdx--; + } + if( !pPrvNd ) + pPrvNd = pNd->IsStartNode() ? (SwStartNode*)pNd + : pNd->StartOfSectionNode(); + + aIdx = pEnd->nNode.GetIndex() + 1; + nCmp = pStt->nNode.GetIndex(); + while( 0 != ( pNxtNd = (pNd = &aIdx.GetNode())->GetEndNode() ) && + pNxtNd->StartOfSectionNode()->IsSectionNode() && + !( pNxtNd->StartOfSectionIndex() < nCmp && + nCmp < aIdx.GetIndex() ) ) + { + aIdx++; + } + if( !pNxtNd ) + pNxtNd = pNd->EndOfSectionNode(); + + if( pPrvNd && pNxtNd && pPrvNd == pNxtNd->StartOfSectionNode() ) + { + nRet = 3; + + if( ppSttNd ) + *ppSttNd = pPrvNd; + } + } + } + else if( !pSectNd && pEndSectNd ) + { + // versuche eine umschliessende Section zu erzeugen + // Aber, nur wenn das Ende am Section Ende liegt! + nRet = 0; + if( pEnd->nContent.GetIndex() == pCNd->Len() ) + { + SwNodeIndex aIdx( pEnd->nNode, 1 ); + if( aIdx.GetNode().IsEndNode() && + 0 != aIdx.GetNode().FindSectionNode() ) + { + do { + aIdx++; + } while( aIdx.GetNode().IsEndNode() && + 0 != aIdx.GetNode().FindSectionNode() ); + { + nRet = 2; + if( ppSttNd ) + { + aIdx--; + *ppSttNd = &aIdx.GetNode(); + } + } + } + } + } + else if( pSectNd && !pEndSectNd ) + { + // versuche eine umschliessende Section zu erzeugen + // Aber, nur wenn der Start am Section Anfang liegt! + nRet = 0; + if( !pStt->nContent.GetIndex() ) + { + SwNodeIndex aIdx( pStt->nNode, -1 ); + if( aIdx.GetNode().IsSectionNode() ) + { + do { + aIdx--; + } while( aIdx.GetNode().IsSectionNode() ); + if( !aIdx.GetNode().IsSectionNode() ) + { + nRet = 1; + if( ppSttNd ) + { + aIdx++; + *ppSttNd = &aIdx.GetNode(); + } + } + } + } + } + } + return nRet; +} + +SwSection* SwDoc::GetCurrSection( const SwPosition& rPos ) const +{ + const SwSectionNode* pSectNd = rPos.nNode.GetNode().FindSectionNode(); + if( pSectNd ) + return (SwSection*)&pSectNd->GetSection(); + return 0; +} + +SwSectionFmt* SwDoc::MakeSectionFmt( SwSectionFmt *pDerivedFrom ) +{ + if( !pDerivedFrom ) + pDerivedFrom = (SwSectionFmt*)pDfltFrmFmt; + SwSectionFmt* pNew = new SwSectionFmt( pDerivedFrom, this ); + pSectionFmtTbl->Insert( pNew, pSectionFmtTbl->Count() ); + return pNew; +} + +void SwDoc::DelSectionFmt( SwSectionFmt *pFmt, sal_Bool bDelNodes ) +{ + sal_uInt16 nPos = pSectionFmtTbl->GetPos( pFmt ); + + GetIDocumentUndoRedo().StartUndo(UNDO_DELSECTION, NULL); + + if( USHRT_MAX != nPos ) + { + const SwNodeIndex* pIdx = pFmt->GetCntnt( sal_False ).GetCntntIdx(); + const SfxPoolItem* pFtnEndAtTxtEnd; + if( SFX_ITEM_SET != pFmt->GetItemState( + RES_FTN_AT_TXTEND, sal_True, &pFtnEndAtTxtEnd ) || + SFX_ITEM_SET != pFmt->GetItemState( + RES_END_AT_TXTEND, sal_True, &pFtnEndAtTxtEnd )) + pFtnEndAtTxtEnd = 0; + + const SwSectionNode* pSectNd; + + if( GetIDocumentUndoRedo().DoesUndo() ) + { + if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + SwNodeIndex aUpdIdx( *pIdx ); + SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd ); + GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( aPaM )); + if( pFtnEndAtTxtEnd ) + GetFtnIdxs().UpdateFtn( aUpdIdx ); + SetModified(); + //#126178# start/end undo have to be pairs! + GetIDocumentUndoRedo().EndUndo(UNDO_DELSECTION, NULL); + return ; + } + GetIDocumentUndoRedo().AppendUndo( MakeUndoDelSection( *pFmt ) ); + } + else if( bDelNodes && pIdx && &GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + SwNodeIndex aUpdIdx( *pIdx ); + DeleteSection( (SwNode*)pSectNd ); + if( pFtnEndAtTxtEnd ) + GetFtnIdxs().UpdateFtn( aUpdIdx ); + SetModified(); + //#126178# start/end undo have to be pairs! + GetIDocumentUndoRedo().EndUndo(UNDO_DELSECTION, NULL); + return ; + } + + { + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFmt ); + pFmt->ModifyNotification( &aMsgHint, &aMsgHint ); + } + + // A ClearRedo could result in a rekursive call of this function and delete some section + // formats => the position iside the SectionFmtTbl could have changed + nPos = pSectionFmtTbl->GetPos( pFmt ); + + // ACHTUNG: erst aus dem Array entfernen und dann loeschen. + // Der Section-DTOR versucht selbst noch sein Format + // zu loeschen! + pSectionFmtTbl->Remove( nPos ); +//FEATURE::CONDCOLL + sal_uLong nCnt = 0, nSttNd = 0; + if( pIdx && &GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + nSttNd = pSectNd->GetIndex(); + nCnt = pSectNd->EndOfSectionIndex() - nSttNd - 1; + } +//FEATURE::CONDCOLL + + delete pFmt; + + if( nSttNd && pFtnEndAtTxtEnd ) + { + SwNodeIndex aUpdIdx( GetNodes(), nSttNd ); + GetFtnIdxs().UpdateFtn( aUpdIdx ); + } + +//FEATURE::CONDCOLL + SwCntntNode* pCNd; + for( ; nCnt--; ++nSttNd ) + if( 0 != (pCNd = GetNodes()[ nSttNd ]->GetCntntNode() ) && + RES_CONDTXTFMTCOLL == pCNd->GetFmtColl()->Which() ) + pCNd->ChkCondColl(); +//FEATURE::CONDCOLL + } + + GetIDocumentUndoRedo().EndUndo(UNDO_DELSECTION, NULL); + + SetModified(); +} + +void SwDoc::UpdateSection(sal_uInt16 const nPos, SwSectionData & rNewData, + SfxItemSet const*const pAttr, bool const bPreventLinkUpdate) +{ + SwSectionFmt* pFmt = (*pSectionFmtTbl)[ nPos ]; + SwSection* pSection = pFmt->GetSection(); + + /// remember hidden condition flag of SwSection before changes + bool bOldCondHidden = pSection->IsCondHidden() ? true : false; + + if (pSection->DataEquals(rNewData)) + { + // die Attribute ueberpruefen + sal_Bool bOnlyAttrChg = sal_False; + if( pAttr && pAttr->Count() ) + { + SfxItemIter aIter( *pAttr ); + sal_uInt16 nWhich = aIter.GetCurItem()->Which(); + while( sal_True ) + { + if( pFmt->GetFmtAttr( nWhich ) != *aIter.GetCurItem() ) + { + bOnlyAttrChg = sal_True; + break; + } + + if( aIter.IsAtEnd() ) + break; + nWhich = aIter.NextItem()->Which(); + } + } + + if( bOnlyAttrChg ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + MakeUndoUpdateSection( *pFmt, true ) ); + } + // #i32968# Inserting columns in the section causes MakeFrmFmt + // to put two objects of type SwUndoFrmFmt on the undo stack. + // We don't want them. + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + pFmt->SetFmtAttr( *pAttr ); + SetModified(); + } + return; + } + + // Teste ob eine gesamte Content-Section (Dokument/TabellenBox/Fly) + // versteckt werden soll, koennen wir zur Zeit nicht !!!! + const SwNodeIndex* pIdx = 0; + { + if (rNewData.IsHidden()) + { + pIdx = pFmt->GetCntnt().GetCntntIdx(); + if (pIdx) + { + const SwSectionNode* pSectNd = + pIdx->GetNode().GetSectionNode(); + if (pSectNd) + { + ::lcl_CheckEmptyLayFrm( GetNodes(), rNewData, + *pSectNd, *pSectNd->EndOfSectionNode() ); + } + } + } + } + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(MakeUndoUpdateSection(*pFmt, false)); + } + // #i32968# Inserting columns in the section causes MakeFrmFmt to put two + // objects of type SwUndoFrmFmt on the undo stack. We don't want them. + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + // Der LinkFileName koennte auch nur aus Separatoren bestehen + String sCompareString = sfx2::cTokenSeperator; + sCompareString += sfx2::cTokenSeperator; + const bool bUpdate = + (!pSection->IsLinkType() && rNewData.IsLinkType()) + || ( rNewData.GetLinkFileName().Len() + && (rNewData.GetLinkFileName() != sCompareString) + && (rNewData.GetLinkFileName() != pSection->GetLinkFileName())); + + String sSectName( rNewData.GetSectionName() ); + if (sSectName != pSection->GetSectionName()) + GetUniqueSectionName( &sSectName ); + else + sSectName.Erase(); + + /// In SwSection::operator=(..) class member bCondHiddenFlag is always set to sal_True. + /// IMHO this have to be changed, but I can't estimate the consequences: + /// Either it is set to sal_True using corresponding method <SwSection.SetCondHidden(..)>, + /// or it is set to the value of SwSection which is assigned to it. + /// Discussion with AMA results that the adjustment to the assignment operator + /// could be very risky. + pSection->SetSectionData(rNewData); + + if( pAttr ) + pSection->GetFmt()->SetFmtAttr( *pAttr ); + + if( sSectName.Len() ) + { + pSection->SetSectionName( sSectName ); + } + + // ist eine Condition gesetzt + if( pSection->IsHidden() && pSection->GetCondition().Len() ) + { + // dann berechne bis zu dieser Position + SwCalc aCalc( *this ); + if( !pIdx ) + pIdx = pFmt->GetCntnt().GetCntntIdx(); + FldsToCalc( aCalc, pIdx->GetIndex(), USHRT_MAX ); + + /// Because on using SwSection::operator=() to set up <pSection> + /// with <rNewData> and the above given note, the hidden condition flag + /// has to be set to sal_False, if hidden condition flag of <pFmt->GetSection()> + /// (SwSection before the changes) is sal_False (already saved in <bOldCondHidden>) + /// and new calculated condition is sal_True. + /// This is necessary, because otherwise the <SetCondHidden> would have + /// no effect. + bool bCalculatedCondHidden = + aCalc.Calculate( pSection->GetCondition() ).GetBool() ? true : false; + if ( bCalculatedCondHidden && !bOldCondHidden ) + { + pSection->SetCondHidden( false ); + } + pSection->SetCondHidden( bCalculatedCondHidden ); + } + + if( bUpdate ) + pSection->CreateLink( bPreventLinkUpdate ? CREATE_CONNECT : CREATE_UPDATE ); + else if( !pSection->IsLinkType() && pSection->IsConnected() ) + { + pSection->Disconnect(); + GetLinkManager().Remove( &pSection->GetBaseLink() ); + } + + SetModified(); +} + +/* -------------------------------------------------- + * LockFrms wurde im InsertSection genutzt, um zu verhindern, dass + * SectionFrms durch das DelFrms zerstoert werden. Dies ist durch + * den Destroy-Listen-Mechanismus ueberfluessig geworden. + * Falls diese Methode doch noch einmal reanimiert wird, bietet es + * sich vielleicht an, beim Entlocken die SectionFrms auf Inhalt zu + * pruefen und dann ggf. zur Zerstoerung anzumelden. + * --------------------------------------------------*/ + +// und dann waren da noch die Fussnoten: +void lcl_DeleteFtn( SwSectionNode *pNd, sal_uLong nStt, sal_uLong nEnd ) +{ + SwFtnIdxs& rFtnArr = pNd->GetDoc()->GetFtnIdxs(); + if( rFtnArr.Count() ) + { + sal_uInt16 nPos; + rFtnArr.SeekEntry( SwNodeIndex( *pNd ), &nPos ); + SwTxtFtn* pSrch; + + // loesche erstmal alle, die dahinter stehen + while( nPos < rFtnArr.Count() && + _SwTxtFtn_GetIndex( (pSrch = rFtnArr[ nPos ]) ) <= nEnd ) + { + // Werden die Nodes nicht geloescht mussen sie bei den Seiten + // abmeldet (Frms loeschen) werden, denn sonst bleiben sie + // stehen (Undo loescht sie nicht!) + pSrch->DelFrms(0); + ++nPos; + } + + while( nPos-- && + _SwTxtFtn_GetIndex( (pSrch = rFtnArr[ nPos ]) ) >= nStt ) + { + // Werden die Nodes nicht geloescht mussen sie bei den Seiten + // abmeldet (Frms loeschen) werden, denn sonst bleiben sie + // stehen (Undo loescht sie nicht!) + pSrch->DelFrms(0); + } + } +} + +static inline bool lcl_IsTOXSection(SwSectionData const& rSectionData) +{ + return (TOX_CONTENT_SECTION == rSectionData.GetType()) + || (TOX_HEADER_SECTION == rSectionData.GetType()); +} + +SwSectionNode* SwNodes::InsertTextSection(SwNodeIndex const& rNdIdx, + SwSectionFmt& rSectionFmt, + SwSectionData const& rSectionData, + SwTOXBase const*const pTOXBase, + SwNodeIndex const*const pEnde, + bool const bInsAtStart, bool const bCreateFrms) +{ + SwNodeIndex aInsPos( rNdIdx ); + if( !pEnde ) // kein Bereich also neue Section davor/hinter anlegen + { + // #i26762# + OSL_ENSURE(!pEnde || rNdIdx <= *pEnde, + "Section start and end in wrong order!"); + + if( bInsAtStart ) + { + if (!lcl_IsTOXSection(rSectionData)) + { + do { + aInsPos--; + } while( aInsPos.GetNode().IsSectionNode() ); + aInsPos++; + } + } + else + { + SwNode* pNd; + aInsPos++; + if (!lcl_IsTOXSection(rSectionData)) + { + while( aInsPos.GetIndex() < Count() - 1 && + ( pNd = &aInsPos.GetNode())->IsEndNode() && + pNd->StartOfSectionNode()->IsSectionNode()) + { + aInsPos++; + } + } + } + } + + SwSectionNode *const pSectNd = + new SwSectionNode(aInsPos, rSectionFmt, pTOXBase); + if( pEnde ) + { + // Sonderfall fuer die Reader/Writer + if( &pEnde->GetNode() != &GetEndOfContent() ) + aInsPos = pEnde->GetIndex()+1; + // #i58710: We created a RTF document with a section break inside a table cell + // We are not able to handle a section start inside a table and the section end outside. + const SwNode* pLastNode = pSectNd->StartOfSectionNode()->EndOfSectionNode(); + if( aInsPos > pLastNode->GetIndex() ) + aInsPos = pLastNode->GetIndex(); + // Another way round: if the section starts outside a table but the end is inside... + // aInsPos is at the moment the Position where my EndNode will be inserted + const SwStartNode* pStartNode = aInsPos.GetNode().StartOfSectionNode(); + // This StartNode should be in front of me, but if not, I wanna survive + sal_uLong nMyIndex = pSectNd->GetIndex(); + if( pStartNode->GetIndex() > nMyIndex ) // Suspicious! + { + const SwNode* pTemp; + do + { + pTemp = pStartNode; // pTemp is a suspicious one + pStartNode = pStartNode->StartOfSectionNode(); + } + while( pStartNode->GetIndex() > nMyIndex ); + pTemp = pTemp->EndOfSectionNode(); + // If it starts behind me but ends behind my end... + if( pTemp->GetIndex() >= aInsPos.GetIndex() ) + aInsPos = pTemp->GetIndex()+1; // ...I have to correct my end position + } + + } + else + { + SwTxtNode* pCpyTNd = rNdIdx.GetNode().GetTxtNode(); + if( pCpyTNd ) + { + SwTxtNode* pTNd = new SwTxtNode( aInsPos, pCpyTNd->GetTxtColl() ); + if( pCpyTNd->HasSwAttrSet() ) + { + // Task 70955 - move PageDesc/Break to the first Node of the + // section + const SfxItemSet& rSet = *pCpyTNd->GetpSwAttrSet(); + if( SFX_ITEM_SET == rSet.GetItemState( RES_BREAK ) || + SFX_ITEM_SET == rSet.GetItemState( RES_PAGEDESC )) + { + SfxItemSet aSet( rSet ); + if( bInsAtStart ) + pCpyTNd->ResetAttr( RES_PAGEDESC, RES_BREAK ); + else + { + aSet.ClearItem( RES_PAGEDESC ); + aSet.ClearItem( RES_BREAK ); + } + pTNd->SetAttr( aSet ); + } + else + pTNd->SetAttr( rSet ); + } + // den Frame anlegen nicht vergessen !! + pCpyTNd->MakeFrms( *pTNd ); + } + else + new SwTxtNode( aInsPos, (SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl() ); + } + new SwEndNode( aInsPos, *pSectNd ); + + pSectNd->GetSection().SetSectionData(rSectionData); + SwSectionFmt* pSectFmt = pSectNd->GetSection().GetFmt(); + + // Hier bietet sich als Optimierung an, vorhandene Frames nicht zu + // zerstoeren und wieder neu anzulegen, sondern nur umzuhaengen. + sal_Bool bInsFrm = bCreateFrms && !pSectNd->GetSection().IsHidden() && + GetDoc()->GetCurrentViewShell(); //swmod 071108//swmod 071225 + SwNode2Layout *pNode2Layout = NULL; + if( bInsFrm ) + { + SwNodeIndex aTmp( *pSectNd ); + if( !pSectNd->GetNodes().FindPrvNxtFrmNode( aTmp, pSectNd->EndOfSectionNode() ) ) + // dann sammel mal alle Uppers ein + pNode2Layout = new SwNode2Layout( *pSectNd ); + } + + // jetzt noch bei allen im Bereich den richtigen StartNode setzen + sal_uLong nEnde = pSectNd->EndOfSectionIndex(); + sal_uLong nStart = pSectNd->GetIndex()+1; + sal_uLong nSkipIdx = ULONG_MAX; + for( sal_uLong n = nStart; n < nEnde; ++n ) + { + SwNode* pNd = (*this)[n]; + + //JP 30.04.99: Bug 65644 - alle in der NodeSection liegenden + // Sections unter die neue haengen + if( ULONG_MAX == nSkipIdx ) + pNd->pStartOfSection = pSectNd; + else if( n >= nSkipIdx ) + nSkipIdx = ULONG_MAX; + + if( pNd->IsStartNode() ) + { + // die Verschachtelung der Formate herstellen! + if( pNd->IsSectionNode() ) + { + ((SwSectionNode*)pNd)->GetSection().GetFmt()-> + SetDerivedFrom( pSectFmt ); + ((SwSectionNode*)pNd)->DelFrms(); + n = pNd->EndOfSectionIndex(); + } + else + { + if( pNd->IsTableNode() ) + ((SwTableNode*)pNd)->DelFrms(); + + if( ULONG_MAX == nSkipIdx ) + nSkipIdx = pNd->EndOfSectionIndex(); + } + } + else if( pNd->IsCntntNode() ) + ((SwCntntNode*)pNd)->DelFrms(); + } + + lcl_DeleteFtn( pSectNd, nStart, nEnde ); + + if( bInsFrm ) + { + if( pNode2Layout ) + { + sal_uLong nIdx = pSectNd->GetIndex(); + pNode2Layout->RestoreUpperFrms( pSectNd->GetNodes(), nIdx, nIdx + 1 ); + delete pNode2Layout; + } + else + pSectNd->MakeFrms( &aInsPos ); + } + + return pSectNd; +} + +SwSectionNode* SwNode::FindSectionNode() +{ + if( IsSectionNode() ) + return GetSectionNode(); + SwStartNode* pTmp = pStartOfSection; + while( !pTmp->IsSectionNode() && pTmp->GetIndex() ) +#if defined( ALPHA ) && defined( UNX ) + pTmp = ((SwNode*)pTmp)->pStartOfSection; +#else + pTmp = pTmp->pStartOfSection; +#endif + return pTmp->GetSectionNode(); +} + + +//--------- +// SwSectionNode +//--------- + +// ugly hack to make m_pSection const +static SwSectionFmt & +lcl_initParent(SwSectionNode & rThis, SwSectionFmt & rFmt) +{ + SwSectionNode *const pParent = + rThis.StartOfSectionNode()->FindSectionNode(); + if( pParent ) + { + // das Format beim richtigen Parent anmelden. + rFmt.SetDerivedFrom( pParent->GetSection().GetFmt() ); + } + return rFmt; +} + +SwSectionNode::SwSectionNode(SwNodeIndex const& rIdx, + SwSectionFmt & rFmt, SwTOXBase const*const pTOXBase) + : SwStartNode( rIdx, ND_SECTIONNODE ) + , m_pSection( (pTOXBase) + ? new SwTOXBaseSection(*pTOXBase, lcl_initParent(*this, rFmt)) + : new SwSection( CONTENT_SECTION, rFmt.GetName(), + lcl_initParent(*this, rFmt) ) ) +{ + // jetzt noch die Verbindung von Format zum Node setzen + // Modify unterdruecken, interresiert keinen + rFmt.LockModify(); + rFmt.SetFmtAttr( SwFmtCntnt( this ) ); + rFmt.UnlockModify(); +} + +#if OSL_DEBUG_LEVEL > 1 +//Hier werden ueberfluessige SectionFrms entfernt +SwFrm* SwClearDummies( SwFrm* pFrm ) +{ + SwFrm* pTmp = pFrm; + while( pTmp ) + { + OSL_ENSURE( !pTmp->GetUpper(), "SwClearDummies: No Upper allowed!" ); + if( pTmp->IsSctFrm() ) + { + SwSectionFrm* pSectFrm = (SwSectionFrm*)pFrm; + pTmp = pTmp->GetNext(); + if( !pSectFrm->GetLower() ) + { + if( pSectFrm->GetPrev() ) + pSectFrm->GetPrev()->pNext = pTmp; + else + pFrm = pTmp; + if( pTmp ) + pTmp->pPrev = pSectFrm->GetPrev(); + delete pSectFrm; + } + } + else + pTmp = pTmp->GetNext(); + } + return pFrm; +} +#endif + +SwSectionNode::~SwSectionNode() +{ + // mba: test if iteration works as clients will be removed in callback + m_pSection->GetFmt()->CallSwClientNotify( SfxSimpleHint( SFX_HINT_DYING ) ); + SwSectionFmt* pFmt = m_pSection->GetFmt(); + if( pFmt ) + { + // das Attribut entfernen, weil die Section ihr Format loescht + // und falls das Cntnt-Attribut vorhanden ist, die Section aufhebt. + pFmt->LockModify(); + pFmt->ResetFmtAttr( RES_CNTNT ); + pFmt->UnlockModify(); + } +} + + +SwFrm *SwSectionNode::MakeFrm( SwFrm *pSib ) +{ + m_pSection->m_Data.SetHiddenFlag(false); + return new SwSectionFrm( *m_pSection, pSib ); +} + +//Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom +//Dokument. Die erzeugten Contentframes werden in das entsprechende +//Layout gehaengt. +void SwSectionNode::MakeFrms(const SwNodeIndex & rIdx ) +{ + // also nehme meinen nachfolgenden oder vorhergehenden ContentFrame: + SwNodes& rNds = GetNodes(); + if( rNds.IsDocNodes() && rNds.GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225 + { + if( GetSection().IsHidden() || IsCntntHidden() ) + { + SwNodeIndex aIdx( *EndOfSectionNode() ); + SwCntntNode* pCNd = rNds.GoNextSection( &aIdx, sal_True, sal_False ); + if( !pCNd ) + { + aIdx = *this; + if( 0 == ( pCNd = rNds.GoPrevSection( &aIdx, sal_True, sal_False )) ) + return ; + } + pCNd = aIdx.GetNode().GetCntntNode(); + pCNd->MakeFrms( (SwCntntNode&)rIdx.GetNode() ); + } + else + { + SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() ); + SwFrm *pFrm, *pNew; + while( 0 != (pFrm = aNode2Layout.NextFrm()) ) + { + OSL_ENSURE( pFrm->IsSctFrm(), "Depend von Section keine Section." ); + pNew = rIdx.GetNode().GetCntntNode()->MakeFrm( pFrm ); + + SwSectionNode* pS = rIdx.GetNode().FindSectionNode(); + + // Assure that node is not inside a table, which is inside the + // found section. + if ( pS ) + { + SwTableNode* pTableNode = rIdx.GetNode().FindTableNode(); + if ( pTableNode && + pTableNode->GetIndex() > pS->GetIndex() ) + { + pS = 0; + } + } + + // if the node is in a section, the sectionframe now + // has to be created.. + // boolean to control <Init()> of a new section frame. + bool bInitNewSect = false; + if( pS ) + { + SwSectionFrm *pSct = new SwSectionFrm( pS->GetSection(), pFrm ); + // prepare <Init()> of new section frame. + bInitNewSect = true; + SwLayoutFrm* pUp = pSct; + while( pUp->Lower() ) // for columned sections + { + OSL_ENSURE( pUp->Lower()->IsLayoutFrm(),"Who's in there?" ); + pUp = (SwLayoutFrm*)pUp->Lower(); + } + pNew->Paste( pUp, NULL ); + // #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for next paragraph will change + // and relation CONTENT_FLOWS_TO for previous paragraph will change. + if ( pNew->IsTxtFrm() ) + { + ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) ); + } + } + // <-- + pNew = pSct; + } + + // wird ein Node vorher oder nachher mit Frames versehen + if ( rIdx < GetIndex() ) + // der neue liegt vor mir + pNew->Paste( pFrm->GetUpper(), pFrm ); + else + // der neue liegt hinter mir + pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() ); + // #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for next paragraph will change + // and relation CONTENT_FLOWS_TO for previous paragraph will change. + if ( pNew->IsTxtFrm() ) + { + ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) ); + } + } + // <-- + if ( bInitNewSect ) + static_cast<SwSectionFrm*>(pNew)->Init(); + } + } + } +} + +//Fuer jedes vorkommen im Layout einen SectionFrm anlegen und vor den +//entsprechenden CntntFrm pasten. + +void SwSectionNode::MakeFrms( SwNodeIndex* pIdxBehind, SwNodeIndex* pEndIdx ) +{ + OSL_ENSURE( pIdxBehind, "kein Index" ); + SwNodes& rNds = GetNodes(); + SwDoc* pDoc = rNds.GetDoc(); + + *pIdxBehind = *this; + + m_pSection->m_Data.SetHiddenFlag(true); + + if( rNds.IsDocNodes() ) + { + SwNodeIndex *pEnd = pEndIdx ? pEndIdx : + new SwNodeIndex( *EndOfSectionNode(), 1 ); + ::MakeFrms( pDoc, *pIdxBehind, *pEnd ); + if( !pEndIdx ) + delete pEnd; + } + +} + +void SwSectionNode::DelFrms() +{ + sal_uLong nStt = GetIndex()+1, nEnd = EndOfSectionIndex(); + if( nStt >= nEnd ) + { + return ; + } + + SwNodes& rNds = GetNodes(); + m_pSection->GetFmt()->DelFrms(); + + // unser Flag muessen wir noch aktualisieren + m_pSection->m_Data.SetHiddenFlag(true); + + // Bug 30582: falls der Bereich in Fly oder TabellenBox ist, dann + // kann er nur "gehiddet" werden, wenn weiterer Content + // vorhanden ist, der "Frames" haelt. Sonst hat der + // Fly/TblBox-Frame keinen Lower !!! + { + SwNodeIndex aIdx( *this ); + if( !rNds.GoPrevSection( &aIdx, sal_True, sal_False ) || + !CheckNodesRange( *this, aIdx, sal_True ) || + // #i21457# + !lcl_IsInSameTblBox( rNds, *this, true )) + { + aIdx = *EndOfSectionNode(); + if( !rNds.GoNextSection( &aIdx, sal_True, sal_False ) || + !CheckNodesRange( *EndOfSectionNode(), aIdx, sal_True ) || + // #i21457# + !lcl_IsInSameTblBox( rNds, *EndOfSectionNode(), false )) + { + m_pSection->m_Data.SetHiddenFlag(false); + } + } + } +} + +SwSectionNode* SwSectionNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const +{ + // in welchen Array steht ich denn: Nodes, UndoNodes ?? + const SwNodes& rNds = GetNodes(); + + // das SectionFrmFmt kopieren + SwSectionFmt* pSectFmt = pDoc->MakeSectionFmt( 0 ); + pSectFmt->CopyAttrs( *GetSection().GetFmt() ); + + ::std::auto_ptr<SwTOXBase> pTOXBase; + if (TOX_CONTENT_SECTION == GetSection().GetType()) + { + OSL_ENSURE( GetSection().ISA( SwTOXBaseSection ), "no TOXBaseSection!" ); + SwTOXBaseSection const& rTBS( + dynamic_cast<SwTOXBaseSection const&>(GetSection())); + pTOXBase.reset( new SwTOXBase(rTBS, pDoc) ); + } + + SwSectionNode *const pSectNd = + new SwSectionNode(rIdx, *pSectFmt, pTOXBase.get()); + SwEndNode* pEndNd = new SwEndNode( rIdx, *pSectNd ); + SwNodeIndex aInsPos( *pEndNd ); + + // Werte uebertragen + SwSection *const pNewSect = pSectNd->m_pSection.get(); + + if (TOX_CONTENT_SECTION != GetSection().GetType()) + { + // beim Move den Namen beibehalten + if( rNds.GetDoc() == pDoc && pDoc->IsCopyIsMove() ) + { + pNewSect->SetSectionName( GetSection().GetSectionName() ); + } + else + { + pNewSect->SetSectionName( + pDoc->GetUniqueSectionName( &GetSection().GetSectionName() )); + } + } + + + pNewSect->SetType( GetSection().GetType() ); + pNewSect->SetCondition( GetSection().GetCondition() ); + pNewSect->SetLinkFileName( GetSection().GetLinkFileName() ); + if( !pNewSect->IsHiddenFlag() && GetSection().IsHidden() ) + pNewSect->SetHidden( sal_True ); + if( !pNewSect->IsProtectFlag() && GetSection().IsProtect() ) + pNewSect->SetProtect( sal_True ); + // edit in readonly sections + if( !pNewSect->IsEditInReadonlyFlag() && GetSection().IsEditInReadonly() ) + pNewSect->SetEditInReadonly( sal_True ); + + SwNodeRange aRg( *this, +1, *EndOfSectionNode() ); // (wo stehe in denn nun ??) + rNds._Copy( aRg, aInsPos, sal_False ); + + // loesche alle Frames vom kopierten Bereich, diese werden beim + // erzeugen des SectionFrames angelegt ! + pSectNd->DelFrms(); + + // dann kopiere auch noch die Links/Server + if( pNewSect->IsLinkType() ) // den Link eintragen + pNewSect->CreateLink( pDoc->GetCurrentViewShell() ? CREATE_CONNECT //swmod 071108//swmod 071225 + : CREATE_NONE ); + + // falls als Server aus dem Undo kopiert wird, wieder eintragen + if (m_pSection->IsServer() + && pDoc->GetIDocumentUndoRedo().IsUndoNodes(rNds)) + { + pNewSect->SetRefObject( m_pSection->GetObject() ); + pDoc->GetLinkManager().InsertServer( pNewSect->GetObject() ); + } + + // METADATA: copy xml:id; must be done after insertion of node + pSectFmt->RegisterAsCopyOf(*GetSection().GetFmt()); + + return pSectNd; +} + +sal_Bool SwSectionNode::IsCntntHidden() const +{ + OSL_ENSURE( !m_pSection->IsHidden(), + "That's simple: Hidden Section => Hidden Content" ); + SwNodeIndex aTmp( *this, 1 ); + sal_uLong nEnd = EndOfSectionIndex(); + while( aTmp < nEnd ) + { + if( aTmp.GetNode().IsSectionNode() ) + { + const SwSection& rSect = ((SwSectionNode&)aTmp.GetNode()).GetSection(); + if( rSect.IsHiddenFlag() ) + // dann diese Section ueberspringen + aTmp = *aTmp.GetNode().EndOfSectionNode(); + } + else + { + if( aTmp.GetNode().IsCntntNode() || aTmp.GetNode().IsTableNode() ) + return sal_False; // Nicht versteckter Inhalt wurde gefunden + OSL_ENSURE( aTmp.GetNode().IsEndNode(), "EndNode expected" ); + } + aTmp++; + } + return sal_True; // Alles versteckt +} + + +void SwSectionNode::NodesArrChgd() +{ + SwSectionFmt *const pFmt = m_pSection->GetFmt(); + if( pFmt ) + { + SwNodes& rNds = GetNodes(); + SwDoc* pDoc = pFmt->GetDoc(); + + if( !rNds.IsDocNodes() ) + { + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFmt ); + pFmt->ModifyNotification( &aMsgHint, &aMsgHint ); + } + + pFmt->LockModify(); + pFmt->SetFmtAttr( SwFmtCntnt( this )); + pFmt->UnlockModify(); + + SwSectionNode* pSectNd = StartOfSectionNode()->FindSectionNode(); + // set the correct parent from the new section + pFmt->SetDerivedFrom( pSectNd ? pSectNd->GetSection().GetFmt() + : pDoc->GetDfltFrmFmt() ); + + // jetzt noch bei allen im Bereich den richtigen StartNode setzen + sal_uLong nStart = GetIndex()+1, nEnde = EndOfSectionIndex(); + for( sal_uLong n = nStart; n < nEnde; ++n ) + // die Verschachtelung der Formate herstellen! + if( 0 != ( pSectNd = rNds[ n ]->GetSectionNode() ) ) + { + pSectNd->GetSection().GetFmt()->SetDerivedFrom( pFmt ); + n = pSectNd->EndOfSectionIndex(); + } + + // verschieben vom Nodes- ins UndoNodes-Array? + if( rNds.IsDocNodes() ) + { + OSL_ENSURE( pDoc == GetDoc(), + "verschieben in unterschiedliche Documente?" ); + if( m_pSection->IsLinkType() ) // den Link austragen + m_pSection->CreateLink( pDoc->GetCurrentViewShell() ? CREATE_CONNECT //swmod 071108 + : CREATE_NONE );//swmod 071225 + if (m_pSection->IsServer()) + { + pDoc->GetLinkManager().InsertServer( m_pSection->GetObject() ); + } + } + else + { + if (CONTENT_SECTION != m_pSection->GetType()) + { + pDoc->GetLinkManager().Remove( &m_pSection->GetBaseLink() ); + } + + if (m_pSection->IsServer()) + { + pDoc->GetLinkManager().RemoveServer( m_pSection->GetObject() ); + } + } + } +} + + +String SwDoc::GetUniqueSectionName( const String* pChkStr ) const +{ + ResId aId( STR_REGION_DEFNAME, *pSwResMgr ); + String aName( aId ); + xub_StrLen nNmLen = aName.Len(); + + sal_uInt16 nNum = 0; + sal_uInt16 nTmp, nFlagSize = ( pSectionFmtTbl->Count() / 8 ) +2; + sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; + memset( pSetFlags, 0, nFlagSize ); + + const SwSectionNode* pSectNd; + sal_uInt16 n; + + for( n = 0; n < pSectionFmtTbl->Count(); ++n ) + if( 0 != ( pSectNd = (*pSectionFmtTbl)[ n ]->GetSectionNode( sal_False ) )) + { + const String& rNm = pSectNd->GetSection().GetSectionName(); + if( rNm.Match( aName ) == nNmLen ) + { + // Nummer bestimmen und das Flag setzen + nNum = static_cast<sal_uInt16>(rNm.Copy( nNmLen ).ToInt32()); + if( nNum-- && nNum < pSectionFmtTbl->Count() ) + pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); + } + if( pChkStr && pChkStr->Equals( rNm ) ) + pChkStr = 0; + } + + if( !pChkStr ) + { + // alle Nummern entsprechend geflag, also bestimme die richtige Nummer + nNum = pSectionFmtTbl->Count(); + for( n = 0; n < nFlagSize; ++n ) + if( 0xff != ( nTmp = pSetFlags[ n ] )) + { + // also die Nummer bestimmen + nNum = n * 8; + while( nTmp & 1 ) + ++nNum, nTmp >>= 1; + break; + } + + } + delete [] pSetFlags; + if( pChkStr ) + return *pChkStr; + return aName += String::CreateFromInt32( ++nNum ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx new file mode 100644 index 000000000000..a17567e7d04f --- /dev/null +++ b/sw/source/core/docnode/ndtbl.cxx @@ -0,0 +1,4563 @@ +/* -*- 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_sw.hxx" + +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <hintids.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/boxitem.hxx> +#include <svl/stritem.hxx> +// #i17174# +#include <editeng/shaditem.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtfordr.hxx> +#include <fmtpdsc.hxx> +#include <fmtanchr.hxx> +#include <fmtlsplt.hxx> +#include <frmatr.hxx> +#include <charatr.hxx> +#include <cellfrm.hxx> +#include <pagefrm.hxx> +#include <tabcol.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <UndoManager.hxx> +#include <cntfrm.hxx> +#include <pam.hxx> +#include <swcrsr.hxx> +#include <viscrs.hxx> +#include <swtable.hxx> +#include <swundo.hxx> +#include <tblsel.hxx> +#include <fldbas.hxx> +#include <poolfmt.hxx> +#include <tabfrm.hxx> +#include <UndoCore.hxx> +#include <UndoRedline.hxx> +#include <UndoDelete.hxx> +#include <UndoNumbering.hxx> +#include <UndoTable.hxx> +#include <hints.hxx> +#include <tblafmt.hxx> +#include <swcache.hxx> +#include <ddefld.hxx> +#include <frminf.hxx> +#include <cellatr.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <mvsave.hxx> +#include <docary.hxx> +#include <redline.hxx> +#include <rolbck.hxx> +#include <tblrwcl.hxx> +#include <editsh.hxx> +#include <txtfrm.hxx> +#include <ftnfrm.hxx> +#include <section.hxx> +#include <frmtool.hxx> +#include <node2lay.hxx> +#include <comcore.hrc> +#include "docsh.hxx" +#include <unochart.hxx> +#include <node.hxx> +#include <ndtxt.hxx> +#include <map> +#include <algorithm> +#include <rootfrm.hxx> +#include <fldupde.hxx> +#include <switerator.hxx> +#if OSL_DEBUG_LEVEL > 1 +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif + +using ::editeng::SvxBorderLine; +using namespace ::com::sun::star; + +const sal_Unicode T2T_PARA = 0x0a; + +extern void ClearFEShellTabCols(); + +// steht im gctable.cxx +extern sal_Bool lcl_GC_Line_Border( const SwTableLine*& , void* pPara ); + +void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, sal_uInt8 nId ) +{ + sal_Bool bTop = sal_False, bBottom = sal_False, bLeft = sal_False, bRight = sal_False; + switch ( nId ) + { + case 0: bTop = bBottom = bLeft = sal_True; break; + case 1: bTop = bBottom = bLeft = bRight = sal_True; break; + case 2: bBottom = bLeft = sal_True; break; + case 3: bBottom = bLeft = bRight = sal_True; break; + } + + const sal_Bool bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE); + Color aCol( bHTML ? COL_GRAY : COL_BLACK ); + SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 ); + if ( bHTML ) + { + aLine.SetStyle( editeng::DOUBLE ); + aLine.SetWidth( DEF_LINE_WIDTH_0 ); + } + SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 ); + if ( bTop ) + aBox.SetLine( &aLine, BOX_LINE_TOP ); + if ( bBottom ) + aBox.SetLine( &aLine, BOX_LINE_BOTTOM ); + if ( bLeft ) + aBox.SetLine( &aLine, BOX_LINE_LEFT ); + if ( bRight ) + aBox.SetLine( &aLine, BOX_LINE_RIGHT ); + rFmt.SetFmtAttr( aBox ); +} + +void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, sal_uInt8 nId, + const SwTableAutoFmt* pAutoFmt = 0 ) +{ + SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ]; + if( !pArr ) + { + pArr = new SvPtrarr; + rBoxFmtArr.Replace( pArr, nId ); + } + + SwTableBoxFmt* pNewBoxFmt = 0; + SwFrmFmt* pBoxFmt = rBox.GetFrmFmt(); + for( sal_uInt16 n = 0; n < pArr->Count(); n += 2 ) + if( pArr->GetObject( n ) == pBoxFmt ) + { + pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 ); + break; + } + + if( !pNewBoxFmt ) + { + SwDoc* pDoc = pBoxFmt->GetDoc(); + // das Format ist also nicht vorhanden, also neu erzeugen + pNewBoxFmt = pDoc->MakeTableBoxFmt(); + pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) ); + + if( pAutoFmt ) + pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(), + SwTableAutoFmt::UPDATE_BOX, + pDoc->GetNumberFormatter( sal_True ) ); + else + ::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId ); + + void* p = pBoxFmt; + pArr->Insert( p, pArr->Count() ); + p = pNewBoxFmt; + pArr->Insert( p, pArr->Count() ); + } + rBox.ChgFrmFmt( pNewBoxFmt ); +} + +SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr, + sal_uInt16 nCols, sal_uInt8 nId ) +{ + if ( !rBoxFmtArr[nId] ) + { + SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt(); + if( USHRT_MAX != nCols ) + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + USHRT_MAX / nCols, 0 )); + ::lcl_SetDfltBoxAttr( *pBoxFmt, nId ); + rBoxFmtArr.Replace( pBoxFmt, nId ); + } + return (SwTableBoxFmt*)rBoxFmtArr[nId]; +} + +SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr, + const SwTableAutoFmt& rAutoFmt, + sal_uInt16 nCols, sal_uInt8 nId ) +{ + if( !rBoxFmtArr[nId] ) + { + SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt(); + rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(), + SwTableAutoFmt::UPDATE_BOX, + rDoc.GetNumberFormatter( sal_True ) ); + if( USHRT_MAX != nCols ) + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + USHRT_MAX / nCols, 0 )); + rBoxFmtArr.Replace( pBoxFmt, nId ); + } + return (SwTableBoxFmt*)rBoxFmtArr[nId]; +} + +SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx) +{ + SwTableNode* pTableNd = 0; + sal_uLong nIndex = rIdx.GetIndex(); + do { + SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode(); + if( 0 != ( pTableNd = pNd->GetTableNode() ) ) + break; + + nIndex = pNd->GetIndex(); + } while ( nIndex ); + return pTableNd; +} + + +// --------------- einfuegen einer neuen Box -------------- + + // fuege in der Line, vor der InsPos eine neue Box ein. + +sal_Bool SwNodes::InsBoxen( SwTableNode* pTblNd, + SwTableLine* pLine, + SwTableBoxFmt* pBoxFmt, + SwTxtFmtColl* pTxtColl, + const SfxItemSet* pAutoAttr, + sal_uInt16 nInsPos, + sal_uInt16 nCnt ) +{ + if( !nCnt ) + return sal_False; + OSL_ENSURE( pLine, "keine gueltige Zeile" ); + + // Index hinter die letzte Box der Line + sal_uLong nIdxPos = 0; + SwTableBox *pPrvBox = 0, *pNxtBox = 0; + if( pLine->GetTabBoxes().Count() ) + { + if( nInsPos < pLine->GetTabBoxes().Count() ) + { + if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(), + pLine->GetTabBoxes()[ nInsPos ] ))) + pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() ); + } + else + { + if( 0 == (pNxtBox = pLine->FindNextBox( pTblNd->GetTable(), + pLine->GetTabBoxes()[ pLine->GetTabBoxes().Count()-1 ] ))) + pNxtBox = pLine->FindNextBox( pTblNd->GetTable() ); + } + } + else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() ))) + pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() ); + + if( !pPrvBox && !pNxtBox ) + { + sal_Bool bSetIdxPos = sal_True; + if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos ) + { + const SwTableLine* pTblLn = pLine; + while( pTblLn->GetUpper() ) + pTblLn = pTblLn->GetUpper()->GetUpper(); + + if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn ) + { + // also vor die erste Box der Tabelle + while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() ) + pLine = pNxtBox->GetTabLines()[0]; + nIdxPos = pNxtBox->GetSttIdx(); + bSetIdxPos = sal_False; + } + } + if( bSetIdxPos ) + // Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende + nIdxPos = pTblNd->EndOfSectionIndex(); + } + else if( pNxtBox ) // es gibt einen Nachfolger + nIdxPos = pNxtBox->GetSttIdx(); + else // es gibt einen Vorgaenger + nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1; + + SwNodeIndex aEndIdx( *this, nIdxPos ); + for( sal_uInt16 n = 0; n < nCnt; ++n ) + { + SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE, + SwTableBoxStartNode ); + pSttNd->pStartOfSection = pTblNd; + new SwEndNode( aEndIdx, *pSttNd ); + + pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + + SwTableBoxes & rTabBoxes = pLine->GetTabBoxes(); + sal_uInt16 nRealInsPos = nInsPos + n; + if (nRealInsPos > rTabBoxes.Count()) + nRealInsPos = rTabBoxes.Count(); + + rTabBoxes.C40_INSERT( SwTableBox, pPrvBox, nRealInsPos ); + + if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei +//FEATURE::CONDCOLL + && RES_CONDTXTFMTCOLL != pTxtColl->Which() +//FEATURE::CONDCOLL + ) + new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ), + pTxtColl, pAutoAttr ); + else + { + // Outline-Numerierung richtig behandeln !!! + SwTxtNode* pTNd = new SwTxtNode( + SwNodeIndex( *pSttNd->EndOfSectionNode() ), + (SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(), + pAutoAttr ); + pTNd->ChgFmtColl( pTxtColl ); + } + } + return sal_True; +} + +// --------------- einfuegen einer neuen Tabelle -------------- + +const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts, + const SwPosition& rPos, sal_uInt16 nRows, + sal_uInt16 nCols, sal_Int16 eAdjust, + const SwTableAutoFmt* pTAFmt, + const SvUShorts* pColArr, + sal_Bool bCalledFromShell, + sal_Bool bNewModel ) +{ + OSL_ENSURE( nRows, "Tabelle ohne Zeile?" ); + OSL_ENSURE( nCols, "Tabelle ohne Spalten?" ); + + { + // nicht in Fussnoten kopieren !! + if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() && + rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() ) + return 0; + + // sollte das ColumnArray die falsche Anzahl haben wird es ignoriert! + if( pColArr && + (nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() ) + pColArr = 0; + } + + String aTblName = GetUniqueTblName(); + + if( GetIDocumentUndoRedo().DoesUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( + new SwUndoInsTbl( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust), + rInsTblOpts, pTAFmt, pColArr, + aTblName)); + } + + // fuege erstmal die Nodes ein + // hole das Auto-Format fuer die Tabelle + SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ), + *pHeadColl = pBodyColl; + + sal_Bool bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER ); + + if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) ) + pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ); + + const sal_uInt16 nRowsToRepeat = + tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ? + rInsTblOpts.mnRowsToRepeat : + 0; + + /* Save content node to extract FRAMEDIR from. */ + const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode(); + + /* If we are called from a shell pass the attrset from + pCntntNd (aka the node the table is inserted at) thus causing + SwNodes::InsertTable to propagate an adjust item if + necessary. */ + SwTableNode *pTblNd = GetNodes().InsertTable( + rPos.nNode, + nCols, + pBodyColl, + nRows, + nRowsToRepeat, + pHeadColl, + bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 ); + + // dann erstelle die Box/Line/Table-Struktur + SwTableLineFmt* pLineFmt = MakeTableLineFmt(); + SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() ); + + /* If the node to insert the table at is a context node and has a + non-default FRAMEDIR propagate it to the table. */ + if (pCntntNd) + { + const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet(); + const SfxPoolItem *pItem = NULL; + + if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem ) + && pItem != NULL) + { + pTableFmt->SetFmtAttr( *pItem ); + } + } + + //Orientation am Fmt der Table setzen + pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) ); + // alle Zeilen haben die Fill-Order von links nach rechts ! + pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT )); + + // die Tabelle bekommt USHRT_MAX als default SSize + SwTwips nWidth = USHRT_MAX; + if( pColArr ) + { + sal_uInt16 nSttPos = (*pColArr)[ 0 ]; + sal_uInt16 nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-1)]; + if( text::HoriOrientation::NONE == eAdjust ) + { + sal_uInt16 nFrmWidth = nLastPos; + nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-2)]; + pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) ); + } + nWidth = nLastPos - nSttPos; + } + else if( nCols ) + { + nWidth /= nCols; + nWidth *= nCols; // to avoid rounding problems + } + pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth )); + if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) ) + pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False )); + + // verschiebe ggfs. die harten PageDesc/PageBreak Attribute: + SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ] + ->GetCntntNode(); + if( pNextNd && pNextNd->HasSwAttrSet() ) + { + const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, sal_False, + &pItem ) ) + { + pTableFmt->SetFmtAttr( *pItem ); + pNextNd->ResetAttr( RES_PAGEDESC ); + pNdSet = pNextNd->GetpSwAttrSet(); + } + if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_False, + &pItem ) ) + { + pTableFmt->SetFmtAttr( *pItem ); + pNextNd->ResetAttr( RES_BREAK ); + } + } + + SwTable * pNdTbl = &pTblNd->GetTable(); + pNdTbl->RegisterToFormat( *pTableFmt ); + + pNdTbl->SetRowsToRepeat( nRowsToRepeat ); + pNdTbl->SetTableModel( bNewModel ); + + SvPtrarr aBoxFmtArr( 0, 16 ); + SwTableBoxFmt* pBoxFmt = 0; + if( !bDfltBorders && !pTAFmt ) + { + pBoxFmt = MakeTableBoxFmt(); + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 )); + } + else + { + const sal_uInt16 nBoxArrLen = pTAFmt ? 16 : 4; + for( sal_uInt16 i = 0; i < nBoxArrLen; ++i ) + aBoxFmtArr.Insert( (void*)0, i ); + } + SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 ); + + SwNodeIndex aNdIdx( *pTblNd, 1 ); // auf den ersten Box-StartNode + SwTableLines& rLines = pNdTbl->GetTabLines(); + for( sal_uInt16 n = 0; n < nRows; ++n ) + { + SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 ); + rLines.C40_INSERT( SwTableLine, pLine, n ); + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 i = 0; i < nCols; ++i ) + { + SwTableBoxFmt *pBoxF; + if( pTAFmt ) + { + sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows ) + ? 12 : (4 * (1 + ((n-1) & 1 ))))); + nId = nId + static_cast<sal_uInt8>( !i ? 0 : + ( i+1 == nCols ? 3 : (1 + ((i-1) & 1)))); + pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt, + nCols, nId ); + + // ggfs. noch die Absatz/ZeichenAttribute setzen + if( pTAFmt->IsFont() || pTAFmt->IsJustify() ) + { + aCharSet.ClearItem(); + pTAFmt->UpdateToSet( nId, aCharSet, + SwTableAutoFmt::UPDATE_CHAR, 0 ); + if( aCharSet.Count() ) + GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()-> + SetAttr( aCharSet ); + } + } + else if( bDfltBorders ) + { + sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 ); + pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId); + } + else + pBoxF = pBoxFmt; + + // fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle + // werden gleich die Spalten gesetzt. Im Array stehen die + // Positionen der Spalten!! (nicht deren Breite!) + if( pColArr ) + { + nWidth = (*pColArr)[ sal_uInt16(i + 1) ] - (*pColArr)[ i ]; + if( pBoxF->GetFrmSize().GetWidth() != nWidth ) + { + if( pBoxF->GetDepends() ) // neues Format erzeugen! + { + SwTableBoxFmt *pNewFmt = MakeTableBoxFmt(); + *pNewFmt = *pBoxF; + pBoxF = pNewFmt; + } + pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth )); + } + } + + SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine); + rBoxes.C40_INSERT( SwTableBox, pBox, i ); + aNdIdx += 3; // StartNode, TextNode, EndNode == 3 Nodes + } + } + // und Frms einfuegen. + GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode + pTblNd->MakeFrms( &aNdIdx ); + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 ); + if( IsRedlineOn() ) + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + else + SplitRedline( aPam ); + } + + SetModified(); + CHECK_TABLE( *pNdTbl ); + return pNdTbl; +} + +SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx, + sal_uInt16 nBoxes, + SwTxtFmtColl* pCntntTxtColl, + sal_uInt16 nLines, + sal_uInt16 nRepeat, + SwTxtFmtColl* pHeadlineTxtColl, + const SwAttrSet * pAttrSet) +{ + if( !nBoxes ) + return 0; + + // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen + if( !pHeadlineTxtColl || !nLines ) + pHeadlineTxtColl = pCntntTxtColl; + + SwTableNode * pTblNd = new SwTableNode( rNdIdx ); + SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd ); + + if( !nLines ) // fuer die FOR-Schleife + ++nLines; + + SwNodeIndex aIdx( *pEndNd ); + SwTxtFmtColl* pTxtColl = pHeadlineTxtColl; + for( sal_uInt16 nL = 0; nL < nLines; ++nL ) + { + for( sal_uInt16 nB = 0; nB < nBoxes; ++nB ) + { + SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE, + SwTableBoxStartNode ); + pSttNd->pStartOfSection = pTblNd; + + SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl ); + + // --> FME 2006-04-13 #i60422# Propagate some more attributes. + const SfxPoolItem* pItem = NULL; + if ( NULL != pAttrSet ) + { + static const sal_uInt16 aPropagateItems[] = { + RES_PARATR_ADJUST, + RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, + RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE, + RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 }; + + const sal_uInt16* pIdx = aPropagateItems; + while ( *pIdx != 0 ) + { + if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) && + SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, sal_True, &pItem ) ) + static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem); + ++pIdx; + } + } + // <-- + + new SwEndNode( aIdx, *pSttNd ); + } + if ( nL + 1 >= nRepeat ) + pTxtColl = pCntntTxtColl; + } + return pTblNd; +} + + +//---------------- Text -> Tabelle ----------------------- + +const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts, + const SwPaM& rRange, sal_Unicode cCh, + sal_Int16 eAdjust, + const SwTableAutoFmt* pTAFmt ) +{ + // pruefe ob in der Selection eine Tabelle liegt + const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End(); + { + sal_uLong nCnt = pStt->nNode.GetIndex(); + for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt ) + if( !GetNodes()[ nCnt ]->IsTxtNode() ) + return 0; + } + + /* Save first node in the selection if it is a context node. */ + SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode(); + + SwPaM aOriginal( *pStt, *pEnd ); + pStt = aOriginal.GetMark(); + pEnd = aOriginal.GetPoint(); + + SwUndoTxtToTbl* pUndo = 0; + if( GetIDocumentUndoRedo().DoesUndo() ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_TEXTTOTABLE, NULL ); + pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh, + static_cast<sal_uInt16>(eAdjust), pTAFmt ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + + // das Splitten vom TextNode nicht in die Undohistory aufnehmen + GetIDocumentUndoRedo().DoUndo( false ); + } + + ::PaMCorrAbs( aOriginal, *pEnd ); + + // sorge dafuer, das der Bereich auf Node-Grenzen liegt + SwNodeRange aRg( pStt->nNode, pEnd->nNode ); + if( pStt->nContent.GetIndex() ) + SplitNode( *pStt, false ); + + sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex(); + // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!) + if( bEndCntnt ) + { + if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex() + || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 ) + { + SplitNode( *pEnd, false ); + ((SwNodeIndex&)pEnd->nNode)--; + ((SwIndex&)pEnd->nContent).Assign( + pEnd->nNode.GetNode().GetCntntNode(), 0 ); + // ein Node und am Ende ?? + if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() ) + aRg.aStart--; + } + else + aRg.aEnd++; + } + + + if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() ) + { + OSL_FAIL( "Kein Bereich" ); + aRg.aEnd++; + } + + // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen: + SwNode2Layout aNode2Layout( aRg.aStart.GetNode() ); + + GetIDocumentUndoRedo().DoUndo( 0 != pUndo ); + + // dann erstelle die Box/Line/Table-Struktur + SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt(); + SwTableLineFmt* pLineFmt = MakeTableLineFmt(); + SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() ); + + // alle Zeilen haben die Fill-Order von links nach rechts ! + pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT )); + // die Tabelle bekommt USHRT_MAX als default SSize + pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX )); + if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) ) + pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False )); + + /* If the first node in the selection is a context node and if it + has an item FRAMEDIR set (no default) propagate the item to the + replacing table. */ + if (pSttCntntNd) + { + const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet(); + const SfxPoolItem *pItem = NULL; + + if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem ) + && pItem != NULL) + { + pTableFmt->SetFmtAttr( *pItem ); + } + } + + SwTableNode* pTblNd = GetNodes().TextToTable( + aRg, cCh, pTableFmt, pLineFmt, pBoxFmt, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo ); + + SwTable * pNdTbl = &pTblNd->GetTable(); + OSL_ENSURE( pNdTbl, "kein Tabellen-Node angelegt." ); + + const sal_uInt16 nRowsToRepeat = + tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ? + rInsTblOpts.mnRowsToRepeat : + 0; + pNdTbl->SetRowsToRepeat( nRowsToRepeat ); + + sal_Bool bUseBoxFmt = sal_False; + if( !pBoxFmt->GetDepends() ) + { + // die Formate an den Boxen haben schon die richtige Size, es darf + // also nur noch die richtige Umrandung/AutoFmt gesetzt werden. + bUseBoxFmt = sal_True; + pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() ); + delete pBoxFmt; + eAdjust = text::HoriOrientation::NONE; + } + + //Orientation am Fmt der Table setzen + pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) ); + pNdTbl->RegisterToFormat( *pTableFmt ); + + if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) ) + { + sal_uInt8 nBoxArrLen = pTAFmt ? 16 : 4; + SvPtrarr aBoxFmtArr( nBoxArrLen, 0 ); + { + for( sal_uInt8 i = 0; i < nBoxArrLen; ++i ) + aBoxFmtArr.Insert( (void*)0, i ); + } + + SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 ); + + SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0; + + SwTableBoxFmt *pBoxF = 0; + SwTableLines& rLines = pNdTbl->GetTabLines(); + sal_uInt16 nRows = rLines.Count(); + for( sal_uInt16 n = 0; n < nRows; ++n ) + { + SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes(); + sal_uInt16 nCols = rBoxes.Count(); + for( sal_uInt16 i = 0; i < nCols; ++i ) + { + SwTableBox* pBox = rBoxes[ i ]; + sal_Bool bChgSz = sal_False; + + if( pTAFmt ) + { + sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows ) + ? 12 : (4 * (1 + ((n-1) & 1 ))))); + nId = nId + static_cast<sal_uInt8>(!i ? 0 : + ( i+1 == nCols ? 3 : (1 + ((i-1) & 1)))); + if( bUseBoxFmt ) + ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt ); + else + { + bChgSz = 0 == aBoxFmtArr[ nId ]; + pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, + *pTAFmt, USHRT_MAX, nId ); + } + + // ggfs. noch die Absatz/ZeichenAttribute setzen + if( pTAFmt->IsFont() || pTAFmt->IsJustify() ) + { + aCharSet.ClearItem(); + pTAFmt->UpdateToSet( nId, aCharSet, + SwTableAutoFmt::UPDATE_CHAR, 0 ); + if( aCharSet.Count() ) + { + sal_uLong nSttNd = pBox->GetSttIdx()+1; + sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex(); + for( ; nSttNd < nEndNd; ++nSttNd ) + { + SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode(); + if( pNd ) + { + if( pHistory ) + { + SwRegHistory aReg( pNd, *pNd, pHistory ); + pNd->SetAttr( aCharSet ); + } + else + pNd->SetAttr( aCharSet ); + } + } + } + } + } + else + { + sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 ); + if( bUseBoxFmt ) + ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId ); + else + { + bChgSz = 0 == aBoxFmtArr[ nId ]; + pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, + USHRT_MAX, nId ); + } + } + + if( !bUseBoxFmt ) + { + if( bChgSz ) + pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() ); + pBox->ChgFrmFmt( pBoxF ); + } + } + } + + if( bUseBoxFmt ) + { + for( sal_uInt8 i = 0; i < nBoxArrLen; ++i ) + { + SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ]; + delete pArr; + } + } + } + + // JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen + if( IsInsTblFormatNum() ) + { + for( sal_uInt16 nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; ) + ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], sal_False ); + } + + sal_uLong nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 ); + + { + SwPaM& rTmp = (SwPaM&)rRange; // Point immer an den Anfang + rTmp.DeleteMark(); + rTmp.GetPoint()->nNode = *pTblNd; + SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode ); + rTmp.GetPoint()->nContent.Assign( pCNd, 0 ); + } + + if( pUndo ) + { + GetIDocumentUndoRedo().EndUndo( UNDO_TEXTTOTABLE, NULL ); + } + + SetModified(); + SetFieldsDirty(true, NULL, 0); + return pNdTbl; +} + +SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh, + SwTableFmt* pTblFmt, + SwTableLineFmt* pLineFmt, + SwTableBoxFmt* pBoxFmt, + SwTxtFmtColl* pTxtColl, + SwUndoTxtToTbl* pUndo ) +{ + if( rRange.aStart >= rRange.aEnd ) + return 0; + + SwTableNode * pTblNd = new SwTableNode( rRange.aStart ); + new SwEndNode( rRange.aEnd, *pTblNd ); + + SwDoc* pDoc = GetDoc(); + SvUShorts aPosArr( 0, 16 ); + SwTable * pTable = &pTblNd->GetTable(); + SwTableLine* pLine; + SwTableBox* pBox; + sal_uInt16 nBoxes, nLines, nMaxBoxes = 0; + + SwNodeIndex aSttIdx( *pTblNd, 1 ); + SwNodeIndex aEndIdx( rRange.aEnd, -1 ); + for( nLines = 0, nBoxes = 0; + aSttIdx.GetIndex() < aEndIdx.GetIndex(); + aSttIdx += 2, nLines++, nBoxes = 0 ) + { + SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode(); + OSL_ENSURE( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" ); + + if( !nLines && 0x0b == cCh ) + { + cCh = 0x09; + + // JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen, + // damit die Boxen entsprechend eingestellt werden + SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->getLayoutFrm( pTxtNd->GetDoc()->GetCurrentLayout() ) ); + if( aFInfo.IsOneLine() ) // nur dann sinnvoll! + { + const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer(); + for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt ) + { + if( *pTxt == cCh ) + { + aPosArr.Insert( static_cast<sal_uInt16>( + aFInfo.GetCharPos( nChPos+1, sal_False )), + aPosArr.Count() ); + } + } + + aPosArr.Insert( + static_cast<sal_uInt16>(aFInfo.GetFrm()->IsVertical() ? + aFInfo.GetFrm()->Prt().Bottom() : + aFInfo.GetFrm()->Prt().Right()), + aPosArr.Count() ); + } + } + + // die alten Frames loeschen, es werden neue erzeugt + pTxtNd->DelFrms(); + + // PageBreaks/PageDesc/ColBreak rausschmeissen. + const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet(); + if( pSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + pTxtNd->ResetAttr( RES_BREAK ); + pSet = pTxtNd->GetpSwAttrSet(); + } + + if( pSet && SFX_ITEM_SET == pSet->GetItemState( + RES_PAGEDESC, sal_False, &pItem ) && + ((SwFmtPageDesc*)pItem)->GetPageDesc() ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + pTxtNd->ResetAttr( RES_PAGEDESC ); + } + } + + // setze den bei allen TextNode in der Tabelle den TableNode + // als StartNode + pTxtNd->pStartOfSection = pTblNd; + + pLine = new SwTableLine( pLineFmt, 1, 0 ); + pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines ); + + SwStartNode* pSttNd; + SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd )); + + SvULongs aBkmkArr( 15, 15 ); + _SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr ); + + const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer(); + + if( T2T_PARA != cCh ) + for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt ) + if( *pTxt == cCh ) + { + aCntPos.nContent = nChPos; + SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos ); + + if( aBkmkArr.Count() ) + _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos, + nChPos + 1 ); + + // Trennzeichen loeschen und SuchString korrigieren + pTxtNd->EraseText( aCntPos.nContent, 1 ); + pTxt = pTxtNd->GetTxt().GetBuffer(); + nChPos = 0; + --nChPos, --pTxt; // for the ++ in the for loop !!! + + // setze bei allen TextNodes in der Tabelle den TableNode + // als StartNode + const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 ); + pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE, + SwTableBoxStartNode ); + new SwEndNode( aCntPos.nNode, *pSttNd ); + pNewNd->pStartOfSection = pSttNd; + + // Section der Box zuweisen + pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ ); + } + + // und jetzt den letzten Teil-String + if( aBkmkArr.Count() ) + _RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(), + pTxtNd->GetTxt().Len()+1 ); + + pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode ); + const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 ); + new SwEndNode( aTmpIdx, *pSttNd ); + pTxtNd->pStartOfSection = pSttNd; + + pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ ); + if( nMaxBoxes < nBoxes ) + nMaxBoxes = nBoxes; + } + + // die Tabelle ausgleichen, leere Sections einfuegen + sal_uInt16 n; + + for( n = 0; n < pTable->GetTabLines().Count(); ++n ) + { + SwTableLine* pCurrLine = pTable->GetTabLines()[ n ]; + if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() )) + { + InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0, + nBoxes, nMaxBoxes - nBoxes ); + + if( pUndo ) + for( sal_uInt16 i = nBoxes; i < nMaxBoxes; ++i ) + pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] ); + + // fehlen der 1. Line Boxen, dann kann man das Breiten Array + // vergessen! + if( !n ) + aPosArr.Remove( 0, aPosArr.Count() ); + } + } + + if( aPosArr.Count() ) + { + SwTableLines& rLns = pTable->GetTabLines(); + sal_uInt16 nLastPos = 0; + for( n = 0; n < aPosArr.Count(); ++n ) + { + SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + aPosArr[ n ] - nLastPos )); + for( sal_uInt16 nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine ) + //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat + // von der rufenden Methode noch gebraucht wird! + pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] ); + + nLastPos = aPosArr[ n ]; + } + + // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die + // Groesse nach "oben" transportieren. + OSL_ENSURE( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" ); + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos )); + } + else + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes )); + + // das wars doch wohl ?? + return pTblNd; +} + +const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes ) +{ + /* Save first node in the selection if it is a content node. */ + SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode(); + + /**debug**/ +#if OSL_DEBUG_LEVEL > 1 + const SwNodeRange& rStartRange = *rTableNodes.begin()->begin(); + const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin(); + (void) rStartRange; + (void) rEndRange; +#endif + /**debug**/ + + //!!! not necessarily TextNodes !!! + SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd ); + const SwPosition *pStt = aOriginal.GetMark(); + const SwPosition *pEnd = aOriginal.GetPoint(); + +// SwUndoTxtToTbl* pUndo = 0; + bool const bUndo(GetIDocumentUndoRedo().DoesUndo()); + if (bUndo) + { + // das Splitten vom TextNode nicht in die Undohistory aufnehmen + GetIDocumentUndoRedo().DoUndo(false); + } + + ::PaMCorrAbs( aOriginal, *pEnd ); + + // sorge dafuer, das der Bereich auf Node-Grenzen liegt + SwNodeRange aRg( pStt->nNode, pEnd->nNode ); + if( pStt->nContent.GetIndex() ) + SplitNode( *pStt, false ); + + sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex(); + // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!) + if( bEndCntnt ) + { + if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex() + || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 ) + { + SplitNode( *pEnd, false ); + ((SwNodeIndex&)pEnd->nNode)--; + ((SwIndex&)pEnd->nContent).Assign( + pEnd->nNode.GetNode().GetCntntNode(), 0 ); + // ein Node und am Ende ?? + if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() ) + aRg.aStart--; + } + else + aRg.aEnd++; + } + + + if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() ) + { + OSL_FAIL( "Kein Bereich" ); + aRg.aEnd++; + } + + // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen: + SwNode2Layout aNode2Layout( aRg.aStart.GetNode() ); + + GetIDocumentUndoRedo().DoUndo(bUndo); + + // dann erstelle die Box/Line/Table-Struktur + SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt(); + SwTableLineFmt* pLineFmt = MakeTableLineFmt(); + SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() ); + + // alle Zeilen haben die Fill-Order von links nach rechts ! + pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT )); + // die Tabelle bekommt USHRT_MAX als default SSize + pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX )); + + /* If the first node in the selection is a context node and if it + has an item FRAMEDIR set (no default) propagate the item to the + replacing table. */ + if (pSttCntntNd) + { + const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet(); + const SfxPoolItem *pItem = NULL; + + if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem ) + && pItem != NULL) + { + pTableFmt->SetFmtAttr( *pItem ); + } + } + + SwTableNode* pTblNd = GetNodes().TextToTable( + rTableNodes, pTableFmt, pLineFmt, pBoxFmt, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ ); + + SwTable * pNdTbl = &pTblNd->GetTable(); + OSL_ENSURE( pNdTbl, "kein Tabellen-Node angelegt." ); + pNdTbl->RegisterToFormat( *pTableFmt ); + + if( !pBoxFmt->GetDepends() ) + { + // die Formate an den Boxen haben schon die richtige Size, es darf + // also nur noch die richtige Umrandung/AutoFmt gesetzt werden. + pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() ); + delete pBoxFmt; + } + + sal_uLong nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 ); + + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + return pNdTbl; +} + +SwNodeRange * SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange) +{ + SwNodeRange * pResult = NULL; + bool bChanged = false; + + SwNodeIndex aNewStart = rRange.aStart; + SwNodeIndex aNewEnd = rRange.aEnd; + + SwNodeIndex aEndIndex = rRange.aEnd; + SwNodeIndex aIndex = rRange.aStart; + + while (aIndex < aEndIndex) + { + SwNode& rNode = aIndex.GetNode(); + + if (rNode.IsStartNode()) + { + // advance aIndex to the end node of this start node + SwNode * pEndNode = rNode.EndOfSectionNode(); + aIndex = *pEndNode; + + if (aIndex > aNewEnd) + { + aNewEnd = aIndex; + bChanged = true; + } + } + else if (rNode.IsEndNode()) + { + SwNode * pStartNode = rNode.StartOfSectionNode(); + SwNodeIndex aStartIndex = *pStartNode; + + if (aStartIndex < aNewStart) + { + aNewStart = aStartIndex; + bChanged = true; + } + } + + if (aIndex < aEndIndex) + ++aIndex; + } + + SwNode * pNode = &aIndex.GetNode(); + while (pNode->IsEndNode()) + { + SwNode * pStartNode = pNode->StartOfSectionNode(); + SwNodeIndex aStartIndex(*pStartNode); + aNewStart = aStartIndex; + aNewEnd = aIndex; + bChanged = true; + + ++aIndex; + pNode = &aIndex.GetNode(); + } + + if (bChanged) + pResult = new SwNodeRange(aNewStart, aNewEnd); + + return pResult; +} + +SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes, + SwTableFmt* pTblFmt, + SwTableLineFmt* pLineFmt, + SwTableBoxFmt* pBoxFmt, + SwTxtFmtColl* /*pTxtColl*/ /*, SwUndo... pUndo*/ ) +{ + if( !rTableNodes.size() ) + return 0; + + SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart ); + //insert the end node after the last text node + SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd ); + ++aInsertIndex; + + //!! owner ship will be transferred in c-tor to SwNodes array. + //!! Thus no real problem here... + new SwEndNode( aInsertIndex, *pTblNd ); + +#if OSL_DEBUG_LEVEL > 1 + /**debug**/ + const SwNodeRange& rStartRange = *rTableNodes.begin()->begin(); + const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin(); + (void) rStartRange; + (void) rEndRange; + /**debug**/ +#endif + + SwDoc* pDoc = GetDoc(); + SvUShorts aPosArr( 0, 16 ); + SwTable * pTable = &pTblNd->GetTable(); + SwTableLine* pLine; + SwTableBox* pBox; + sal_uInt16 nBoxes, nLines, nMaxBoxes = 0; + + SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart; + // delete frames of all contained content nodes + for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines ) + { + SwNode& rNode = aNodeIndex.GetNode(); + if( rNode.IsCntntNode() ) + { + static_cast<SwCntntNode&>(rNode).DelFrms(); + if(rNode.IsTxtNode()) + { + SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode); + // setze den bei allen TextNode in der Tabelle den TableNode + // als StartNode + + // remove PageBreaks/PageDesc/ColBreak + const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet(); + if( pSet ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + rTxtNode.ResetAttr( RES_BREAK ); + pSet = rTxtNode.GetpSwAttrSet(); + } + + if( pSet && SFX_ITEM_SET == pSet->GetItemState( + RES_PAGEDESC, sal_False, &pItem ) && + ((SwFmtPageDesc*)pItem)->GetPageDesc() ) + { + if( !nLines ) + pTblFmt->SetFmtAttr( *pItem ); + rTxtNode.ResetAttr( RES_PAGEDESC ); + } + } + } + } + } + + std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin(); + for( nLines = 0, nBoxes = 0; + aRowIter != rTableNodes.end(); + ++aRowIter, nLines++, nBoxes = 0 ) + { + pLine = new SwTableLine( pLineFmt, 1, 0 ); + pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines ); + + std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin(); + + for( ; aCellIter != aRowIter->end(); ++aCellIter ) + { + const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 ); + + SwNodeIndex aCellEndIdx(aCellIter->aEnd); + ++aCellEndIdx; + SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE, + SwTableBoxStartNode ); + new SwEndNode( aCellEndIdx, *pSttNd ); + //set the start node on all node of the current cell + SwNodeIndex aCellNodeIdx = aCellIter->aStart; + for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx ) + { + aCellNodeIdx.GetNode().pStartOfSection = pSttNd; + //skip start/end node pairs + if( aCellNodeIdx.GetNode().IsStartNode() ) + aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() ); + } + + // Section der Box zuweisen + pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine ); + pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ ); + } + if( nMaxBoxes < nBoxes ) + nMaxBoxes = nBoxes; + } + + // die Tabelle ausgleichen, leere Sections einfuegen + sal_uInt16 n; + + if( aPosArr.Count() ) + { + SwTableLines& rLns = pTable->GetTabLines(); + sal_uInt16 nLastPos = 0; + for( n = 0; n < aPosArr.Count(); ++n ) + { + SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + aPosArr[ n ] - nLastPos )); + for( sal_uInt16 nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 ) + //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat + // von der rufenden Methode noch gebraucht wird! + pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] ); + + nLastPos = aPosArr[ n ]; + } + + // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die + // Groesse nach "oben" transportieren. + OSL_ENSURE( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" ); + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos )); + } + else + pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes )); + + // das wars doch wohl ?? + return pTblNd; +} + + +//---------------- Tabelle -> Text ----------------------- + + +sal_Bool SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh ) +{ + if( !pTblNd ) + return sal_False; + + // --> FME 2004-09-28 #i34471# + // If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted + // the table cursor. + SwEditShell* pESh = GetEditShell(); + if( pESh && pESh->IsTableMode() ) + pESh->ClearMark(); + // <-- + + SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() ); + SwUndoTblToTxt* pUndo = 0; + SwNodeRange* pUndoRg = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 ); + pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh ); + } + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXNAME; + UpdateTblFlds( &aMsgHnt ); + + sal_Bool bRet = GetNodes().TableToText( aRg, cCh, pUndo ); + if( pUndoRg ) + { + pUndoRg->aStart++; + pUndoRg->aEnd--; + pUndo->SetRange( *pUndoRg ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + delete pUndoRg; + } + + if( bRet ) + SetModified(); + + return bRet; +} + +// -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder +// Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!) +struct _DelTabPara +{ + SwTxtNode* pLastNd; + SwNodes& rNds; + SwUndoTblToTxt* pUndo; + sal_Unicode cCh; + + _DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) : + pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {} + _DelTabPara( const _DelTabPara& rPara ) : + pLastNd(rPara.pLastNd), rNds( rPara.rNds ), + pUndo( rPara.pUndo ), cCh( rPara.cCh ) {} +}; + +// forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen +// koennen. +sal_Bool lcl_DelBox( const SwTableBox*&, void *pPara ); + +sal_Bool lcl_DelLine( const SwTableLine*& rpLine, void* pPara ) +{ + OSL_ENSURE( pPara, "die Parameter fehlen" ); + _DelTabPara aPara( *(_DelTabPara*)pPara ); + ((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara ); + if( rpLine->GetUpper() ) // gibt es noch eine uebergeordnete Box ?? + // dann gebe den letzten TextNode zurueck + ((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd; + return sal_True; +} + + +sal_Bool lcl_DelBox( const SwTableBox*& rpBox, void* pPara ) +{ + OSL_ENSURE( pPara, "die Parameter fehlen" ); + + // loesche erstmal die Lines der Box + _DelTabPara* pDelPara = (_DelTabPara*)pPara; + if( rpBox->GetTabLines().Count() ) + ((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara ); + else + { + SwDoc* pDoc = pDelPara->rNds.GetDoc(); + SwNodeRange aDelRg( *rpBox->GetSttNd(), 0, + *rpBox->GetSttNd()->EndOfSectionNode() ); + // loesche die Section + pDelPara->rNds.SectionUp( &aDelRg ); + const SwTxtNode* pCurTxtNd; + if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd && + 0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() )) + { + // Join the current text node with the last from the previous box if possible + sal_uLong nNdIdx = aDelRg.aStart.GetIndex(); + aDelRg.aStart--; + if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() ) + { + // Inserting the seperator + SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len()); + pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx, + IDocumentContentOperations::INS_EMPTYEXPAND ); + if( pDelPara->pUndo ) + pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(), + aCntIdx.GetIndex() ); + + SvULongs aBkmkArr( 4, 4 ); + xub_StrLen nOldTxtLen = aCntIdx.GetIndex(); + _SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(), + aBkmkArr ); + + pDelPara->pLastNd->JoinNext(); + + if( aBkmkArr.Count() ) + _RestoreCntntIdx( pDoc, aBkmkArr, + pDelPara->pLastNd->GetIndex(), + nOldTxtLen ); + } + else if( pDelPara->pUndo ) + { + aDelRg.aStart++; + pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() ); + } + } + else if( pDelPara->pUndo ) + pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() ); + aDelRg.aEnd--; + pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode(); + + //JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf + // keinen Fall uebernehmen + if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() ) + pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST ); + } + return sal_True; +} + + +sal_Bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh, + SwUndoTblToTxt* pUndo ) +{ + // ist eine Tabelle selektiert ? + SwTableNode* pTblNd; + if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() || + 0 == ( pTblNd = rRange.aStart.GetNode().GetTableNode()) || + &rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() ) + return sal_False; + + // stand die Tabelle ganz alleine in einer Section ? + // dann ueber den Upper der Tabelle die Frames anlegen + SwNode2Layout* pNode2Layout = 0; + SwNodeIndex aFrmIdx( rRange.aStart ); + SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() ); + if( !pFrmNd ) + // dann sammel mal alle Uppers ein + pNode2Layout = new SwNode2Layout( *pTblNd ); + + // loesche schon mal die Frames + pTblNd->DelFrms(); + + // dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen + _DelTabPara aDelPara( *this, cCh, pUndo ); + pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara ); + + // jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden + // Trenner erzeugt worden. Es braucht nur noch die Table-Section + // geloescht und fuer die neuen TextNode die Frames erzeugt werden. + SwNodeRange aDelRg( rRange.aStart, rRange.aEnd ); + + // JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den + // ersten TextNode uebernehmen + { +// was ist mit UNDO??? + const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet(); + const SfxPoolItem *pBreak, *pDesc; + if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, sal_False, &pDesc )) + pDesc = 0; + if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, sal_False, &pBreak )) + pBreak = 0; + + if( pBreak || pDesc ) + { + SwNodeIndex aIdx( *pTblNd ); + SwCntntNode* pCNd = GoNext( &aIdx ); + if( pBreak ) + pCNd->SetAttr( *pBreak ); + if( pDesc ) + pCNd->SetAttr( *pDesc ); + } + } + + SectionUp( &aDelRg ); // loesche die Section und damit die Tabelle + // #i28006# + sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex(); + if( !pFrmNd ) + { + pNode2Layout->RestoreUpperFrms( *this, + aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() ); + delete pNode2Layout; + } + else + { + SwCntntNode *pCNd; + SwSectionNode *pSNd; + while( aDelRg.aStart.GetIndex() < nEnd ) + { + if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode())) + { + if( pFrmNd->IsCntntNode() ) + ((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd ); + else if( pFrmNd->IsTableNode() ) + ((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart ); + else if( pFrmNd->IsSectionNode() ) + ((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart ); + pFrmNd = pCNd; + } + else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode())) + { + if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() ) + { + pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd ); + pFrmNd = pSNd; + break; + } + aDelRg.aStart = *pSNd->EndOfSectionNode(); + } + aDelRg.aStart++; + } + } + + // #i28006# Fly frames have to be restored even if the table was + // #alone in the section + const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < rFlyArr.Count(); ++n ) + { + SwFrmFmt *const pFmt = (SwFrmFmt*)rFlyArr[n]; + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId())) && + nStt <= pAPos->nNode.GetIndex() && + pAPos->nNode.GetIndex() < nEnd ) + { + pFmt->MakeFrms(); + } + } + + return sal_True; +} + + +// ----- einfuegen von Spalten/Zeilen ------------------------ + +sal_Bool SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind ) +{ + if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) ) + return sal_False; + + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + ::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL ); + + sal_Bool bRet = sal_False; + if( aBoxes.Count() ) + bRet = InsertCol( aBoxes, nCnt, bBehind ); + return bRet; +} + +sal_Bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind ) +{ + // uebers SwDoc fuer Undo !! + OSL_ENSURE( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return sal_False; + + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd, + 0, 0, nCnt, bBehind, sal_False ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + bool bRet(false); + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind ); + if (bRet) + { + SetModified(); + ::ClearFEShellTabCols(); + SetFieldsDirty( true, NULL, 0 ); + } + } + + if( pUndo ) + { + if( bRet ) + { + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bRet; +} + +sal_Bool SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind ) +{ + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW ); + + sal_Bool bRet = sal_False; + if( aBoxes.Count() ) + bRet = InsertRow( aBoxes, nCnt, bBehind ); + return bRet; +} + +sal_Bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind ) +{ + // uebers SwDoc fuer Undo !! + OSL_ENSURE( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return sal_False; + + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd, + 0, 0, nCnt, bBehind, sal_False ); + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + bool bRet(false); + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind ); + if (bRet) + { + SetModified(); + ::ClearFEShellTabCols(); + SetFieldsDirty( true, NULL, 0 ); + } + } + + if( pUndo ) + { + if( bRet ) + { + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bRet; + +} + +// ----- loeschen von Spalten/Zeilen ------------------------ + +sal_Bool SwDoc::DeleteRow( const SwCursor& rCursor ) +{ + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW ); + if( ::HasProtectedCells( aBoxes )) + return sal_False; + + // die Crsr aus dem Loeschbereich entfernen. + // Der Cursor steht danach: + // - es folgt noch eine Zeile, in dieser + // - vorher steht noch eine Zeile, in dieser + // - sonst immer dahinter + { + SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode(); + + if( pTblNd->GetTable().ISA( SwDDETable )) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( aBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + + if( !aFndBox.GetLines().Count() ) + return sal_False; + + SwEditShell* pESh = GetEditShell(); + if( pESh ) + { + pESh->KillPams(); + // JP: eigentlich sollte man ueber alle Shells iterieren!! + } + + _FndBox* pFndBox = &aFndBox; + while( 1 == pFndBox->GetLines().Count() && + 1 == pFndBox->GetLines()[0]->GetBoxes().Count() ) + { + _FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0]; + if( pTmp->GetBox()->GetSttNd() ) + break; // das ist sonst zu weit + pFndBox = pTmp; + } + + SwTableLine* pDelLine = pFndBox->GetLines()[ + pFndBox->GetLines().Count()-1 ]->GetLine(); + SwTableBox* pDelBox = pDelLine->GetTabBoxes()[ + pDelLine->GetTabBoxes().Count() - 1 ]; + while( !pDelBox->GetSttNd() ) + { + SwTableLine* pLn = pDelBox->GetTabLines()[ + pDelBox->GetTabLines().Count()-1 ]; + pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ]; + } + SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(), + pDelBox, sal_True ); + while( pNextBox && + pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox ); + + if( !pNextBox ) // keine nachfolgende? dann die vorhergehende + { + pDelLine = pFndBox->GetLines()[ 0 ]->GetLine(); + pDelBox = pDelLine->GetTabBoxes()[ 0 ]; + while( !pDelBox->GetSttNd() ) + pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0]; + pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(), + pDelBox, sal_True ); + while( pNextBox && + pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox ); + } + + sal_uLong nIdx; + if( pNextBox ) // dann den Cursor hier hinein + nIdx = pNextBox->GetSttIdx() + 1; + else // ansonsten hinter die Tabelle + nIdx = pTblNd->EndOfSectionIndex() + 1; + + SwNodeIndex aIdx( GetNodes(), nIdx ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetNodes().GoNext( &aIdx ); + + if( pCNd ) + { + // die Cursor von der Shell oder den uebergebenen Cursor aendern? + SwPaM* pPam = (SwPaM*)&rCursor; + pPam->GetPoint()->nNode = aIdx; + pPam->GetPoint()->nContent.Assign( pCNd, 0 ); + pPam->SetMark(); // beide wollen etwas davon haben + pPam->DeleteMark(); + } + } + + // dann loesche doch die Zeilen + + GetIDocumentUndoRedo().StartUndo(UNDO_ROW_DELETE, NULL); + sal_Bool bResult = DeleteRowCol( aBoxes ); + GetIDocumentUndoRedo().EndUndo(UNDO_ROW_DELETE, NULL); + + return bResult; +} + +sal_Bool SwDoc::DeleteCol( const SwCursor& rCursor ) +{ + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL ); + if( ::HasProtectedCells( aBoxes )) + return sal_False; + + // die Crsr muessen noch aus dem Loesch Bereich entfernt + // werden. Setze sie immer hinter/auf die Tabelle; ueber die + // Dokument-Position werden sie dann immer an die alte Position gesetzt. + SwEditShell* pESh = GetEditShell(); + if( pESh ) + { + const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode(); + pESh->ParkCrsr( SwNodeIndex( *pNd ) ); + } + + // dann loesche doch die Spalten + GetIDocumentUndoRedo().StartUndo(UNDO_COL_DELETE, NULL); + sal_Bool bResult = DeleteRowCol( aBoxes, true ); + GetIDocumentUndoRedo().EndUndo(UNDO_COL_DELETE, NULL); + + return bResult; +} + +sal_Bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn ) +{ + if( ::HasProtectedCells( rBoxes )) + return sal_False; + + // uebers SwDoc fuer Undo !! + OSL_ENSURE( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + if( pTblNd->GetTable().ISA( SwDDETable )) + return sal_False; + + ::ClearFEShellTabCols(); + SwSelBoxes aSelBoxes; + aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count()); + SwTable &rTable = pTblNd->GetTable(); + long nMin = 0; + long nMax = 0; + if( rTable.IsNewModel() ) + { + if( bColumn ) + rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax ); + else + rTable.FindSuperfluousRows( aSelBoxes ); + } + + // soll die gesamte Tabelle geloescht werden ?? + const sal_uLong nTmpIdx1 = pTblNd->GetIndex(); + const sal_uLong nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()-> + EndOfSectionIndex()+1; + if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() && + aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 && + nTmpIdx2 == pTblNd->EndOfSectionIndex() ) + { + sal_Bool bNewTxtNd = sal_False; + // steht diese auch noch alleine in einem FlyFrame ? + SwNodeIndex aIdx( *pTblNd, -1 ); + const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode(); + if( pSttNd ) + { + const sal_uLong nTblEnd = pTblNd->EndOfSectionIndex() + 1; + const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex(); + if( nTblEnd == nSectEnd ) + { + if( SwFlyStartNode == pSttNd->GetStartNodeType() ) + { + SwFrmFmt* pFmt = pSttNd->GetFlyFmt(); + if( pFmt ) + { + // Ok, das ist das gesuchte FlyFormat + DelLayoutFmt( pFmt ); + return sal_True; + } + } + // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen + // TextNode ueberig lassen. + // Undo koennen wir dann vergessen !! + bNewTxtNd = sal_True; + } + } + + // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen + // TextNode ueberig lassen. + aIdx++; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() ); + + if( bNewTxtNd ) + { + const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 ); + GetNodes().MakeTxtNode( aTmpIdx, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) ); + } + + // save the cursors (UNO and otherwise) + SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) ); + if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) ) + { + *aSavePaM.GetMark() = SwPosition( *pTblNd ); + aSavePaM.Move( fnMoveBackward, fnGoNode ); + } + { + SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode()); + ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark()); + } + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False; + sal_uLong nNextNd = pTblNd->EndOfSectionIndex()+1; + SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode(); + if( pNextNd ) + { + { + SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageDesc = sal_True; + } + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageBreak = sal_True; + } + } + } + SwUndoDelete* pUndo = new SwUndoDelete( aPaM ); + if( bNewTxtNd ) + pUndo->SetTblDelLastNd(); + pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); + pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName()); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + { + if( bNewTxtNd ) + { + const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 ); + GetNodes().MakeTxtNode( aTmpIdx, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) ); + } + + // save the cursors (UNO and otherwise) + SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) ); + if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) ) + { + *aSavePaM.GetMark() = SwPosition( *pTblNd ); + aSavePaM.Move( fnMoveBackward, fnGoNode ); + } + { + SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode()); + ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark()); + } + + // harte SeitenUmbrueche am nachfolgenden Node verschieben + SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode(); + if( pNextNd ) + { + SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + pTblNd->DelFrms(); + DeleteSection( pTblNd ); + } + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + return sal_True; + } + + SwUndoTblNdsChg* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd, + nMin, nMax, 0, sal_False, sal_False ); + } + + bool bRet(false); + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + if (rTable.IsNewModel()) + { + if (bColumn) + rTable.PrepareDeleteCol( nMin, nMax ); + rTable.FindSuperfluousRows( aSelBoxes ); + if (pUndo) + pUndo->ReNewBoxes( aSelBoxes ); + } + bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, sal_True, sal_True ); + if (bRet) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + } + + if( pUndo ) + { + if( bRet ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + + return bRet; +} + + +// ---------- teilen / zusammenfassen von Boxen in der Tabelle -------- + +sal_Bool SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, sal_uInt16 nCnt, + sal_Bool bSameHeight ) +{ + // uebers SwDoc fuer Undo !! + OSL_ENSURE( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + SwTable& rTbl = pTblNd->GetTable(); + if( rTbl.ISA( SwDDETable )) + return sal_False; + + SvULongs aNdsCnts; + SwTableSortBoxes aTmpLst( 0, 5 ); + SwUndoTblNdsChg* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0, + nCnt, bVert, bSameHeight ); + + aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + if( !bVert ) + { + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd(); + aNdsCnts.Insert( pSttNd->EndOfSectionIndex() - + pSttNd->GetIndex(), n ); + } + } + } + + bool bRet(false); + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + SwTableFmlUpdate aMsgHnt( &rTbl ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + if (bVert) + bRet = rTbl.SplitCol( this, rBoxes, nCnt ); + else + bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight ); + + if (bRet) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + } + + if( pUndo ) + { + if( bRet ) + { + if( bVert ) + pUndo->SaveNewBoxes( *pTblNd, aTmpLst ); + else + pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + + return bRet; +} + + +sal_uInt16 SwDoc::MergeTbl( SwPaM& rPam ) +{ + // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen + SwTableNode* pTblNd = rPam.GetNode()->FindTableNode(); + if( !pTblNd ) + return TBLMERGE_NOSELECTION; + SwTable& rTable = pTblNd->GetTable(); + if( rTable.ISA(SwDDETable) ) + return TBLMERGE_NOSELECTION; + sal_uInt16 nRet = TBLMERGE_NOSELECTION; + if( !rTable.IsNewModel() ) + { + nRet =::CheckMergeSel( rPam ); + if( TBLMERGE_OK != nRet ) + return nRet; + nRet = TBLMERGE_NOSELECTION; + } + + // --> FME 2004-10-08 #i33394# + GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_MERGE, NULL ); + // <-- + + RedlineMode_t eOld = GetRedlineMode(); + SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + + SwUndoTblMerge *const pUndo( (GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoTblMerge( rPam ) + : 0 ); + + // lasse ueber das Layout die Boxen suchen + SwSelBoxes aBoxes; + SwSelBoxes aMerged; + SwTableBox* pMergeBox; + + if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) ) + { // no cells found to merge + SetRedlineMode_intern( eOld ); + if( pUndo ) + { + delete pUndo; + SwUndoId nLastUndoId(UNDO_EMPTY); + if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId) + && (UNDO_REDLINE == nLastUndoId)) + { + // FIXME: why is this horrible cleanup necessary? + SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>( + GetUndoManager().RemoveLastUndo()); + if( pU->GetRedlSaveCount() ) + { + SwEditShell *const pEditShell(GetEditShell(0)); + OSL_ASSERT(pEditShell); + ::sw::UndoRedoContext context(*this, *pEditShell); + static_cast<SfxUndoAction *>(pU)->UndoWithContext(context); + } + delete pU; + } + } + } + else + { + // die PaMs muessen noch aus dem Loesch Bereich entfernt + // werden. Setze sie immer hinter/auf die Tabelle; ueber die + // Dokument-Position werden sie dann immer an die alte Position gesetzt. + // Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel + // komme ich nicht mehr dran. + { + rPam.DeleteMark(); + rPam.GetPoint()->nNode = *pMergeBox->GetSttNd(); + rPam.GetPoint()->nContent.Assign( 0, 0 ); + rPam.SetMark(); + rPam.DeleteMark(); + + SwPaM* pTmp = &rPam; + while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() )) + for( int i = 0; i < 2; ++i ) + pTmp->GetBound( (sal_Bool)i ) = *rPam.GetPoint(); + } + + // dann fuege sie zusammen + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo )) + { + nRet = TBLMERGE_OK; + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + if( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + else if( pUndo ) + delete pUndo; + + rPam.GetPoint()->nNode = *pMergeBox->GetSttNd(); + rPam.Move(); + + ::ClearFEShellTabCols(); + SetRedlineMode_intern( eOld ); + } + GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_MERGE, NULL ); + return nRet; +} + + + +// ------------------------------------------------------- + +//--------- +// SwTableNode +//--------- + +SwTableNode::SwTableNode( const SwNodeIndex& rIdx ) + : SwStartNode( rIdx, ND_TABLENODE ) +{ + pTable = new SwTable( 0 ); +} + +SwTableNode::~SwTableNode() +{ + //don't forget to notify uno wrappers + SwFrmFmt* pTblFmt = GetTable().GetFrmFmt(); + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, + pTblFmt ); + pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint ); + DelFrms(); + delete pTable; +} + +SwTabFrm *SwTableNode::MakeFrm( SwFrm* pSib ) +{ + return new SwTabFrm( *pTable, pSib ); +} + +//Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom +//Dokument. Die erzeugten Contentframes werden in das entsprechende +//Layout gehaengt. +void SwTableNode::MakeFrms(const SwNodeIndex & rIdx ) +{ + if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ?? + return; + + SwFrm *pFrm, *pNew; + SwCntntNode * pNode = rIdx.GetNode().GetCntntNode(); + + OSL_ENSURE( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch."); + + sal_Bool bBefore = rIdx < GetIndex(); + + SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() ); + + while( 0 != (pFrm = aNode2Layout.NextFrm()) ) + { + pNew = pNode->MakeFrm( pFrm ); + // wird ein Node vorher oder nachher mit Frames versehen + if ( bBefore ) + // der neue liegt vor mir + pNew->Paste( pFrm->GetUpper(), pFrm ); + else + // der neue liegt hinter mir + pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() ); + } +} + +//Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden +//CntntFrm pasten. + +void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind ) +{ + OSL_ENSURE( pIdxBehind, "kein Index" ); + *pIdxBehind = *this; + SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() ); + if( !pNd ) + return ; + + SwFrm *pFrm( 0L ); + SwLayoutFrm *pUpper( 0L ); + SwNode2Layout aNode2Layout( *pNd, GetIndex() ); + while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) ) + { + SwTabFrm* pNew = MakeFrm( pUpper ); + pNew->Paste( pUpper, pFrm ); + // #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for next paragraph will change + // and relation CONTENT_FLOWS_TO for previous paragraph will change. + { + ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) ); + } + } + // <-- + ((SwTabFrm*)pNew)->RegistFlys(); + } +} + +void SwTableNode::DelFrms() +{ + //Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows + //nehmen sie mit in's Grab. + //Die TabFrms haengen am FrmFmt des SwTable. + //Sie muessen etwas umstaendlich zerstort werden, damit die Master + //die Follows mit in's Grab nehmen. + + SwIterator<SwTabFrm,SwFmt> aIter( *(pTable->GetFrmFmt()) ); + SwTabFrm *pFrm = aIter.First(); + while ( pFrm ) + { + sal_Bool bAgain = sal_False; + { + if ( !pFrm->IsFollow() ) + { + while ( pFrm->HasFollow() ) + pFrm->JoinAndDelFollows(); + // #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for current next paragraph will change + // and relation CONTENT_FLOWS_TO for current previous paragraph will change. + { + ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) ); + } + } + // <-- + pFrm->Cut(); + delete pFrm; + bAgain = sal_True; + } + } + pFrm = bAgain ? aIter.First() : aIter.Next(); + } +} + + +void SwTableNode::SetNewTable( SwTable* pNewTable, sal_Bool bNewFrames ) +{ + DelFrms(); + delete pTable; + pTable = pNewTable; + if( bNewFrames ) + { + SwNodeIndex aIdx( *EndOfSectionNode()); + GetNodes().GoNext( &aIdx ); + MakeFrms( &aIdx ); + } +} + +void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr, + const SwCellFrm* pBoxFrm ) const +{ + const SwTableBox* pBox = 0; + SwTabFrm *pTab = 0; + + if( pBoxFrm ) + { + pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm(); + pBox = pBoxFrm->GetTabBox(); + } + else if( pCrsr ) + { + const SwCntntNode* pCNd = pCrsr->GetCntntNode(); + if( !pCNd ) + return ; + + Point aPt; + const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr); + if( pShCrsr ) + aPt = pShCrsr->GetPtPos(); + + const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False ); + do { + pTmpFrm = pTmpFrm->GetUpper(); + } while ( !pTmpFrm->IsCellFrm() ); + + pBoxFrm = (SwCellFrm*)pTmpFrm; + pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm(); + pBox = pBoxFrm->GetTabBox(); + } + else if( !pCrsr && !pBoxFrm ) + { + OSL_ENSURE( !this, "einer von beiden muss angegeben werden!" ); + return ; + } + + //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ. + SWRECTFN( pTab ) + const SwPageFrm* pPage = pTab->FindPageFrm(); + const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + + rFill.SetLeftMin ( nLeftMin ); + rFill.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() ); + rFill.SetRight ( (pTab->Prt().*fnRect->fnGetRight)()); + rFill.SetRightMax( nRightMax - nLeftMin ); + + pTab->GetTable()->GetTabCols( rFill, pBox ); +} + +// +// Here are some little helpers used in SwDoc::GetTabRows +// + +#define ROWFUZZY 25 + +struct FuzzyCompare +{ + bool operator() ( long s1, long s2 ) const; +}; + +bool FuzzyCompare::operator() ( long s1, long s2 ) const +{ + return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY ); +} + +bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes ) +{ + for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + { + if ( rFrm.GetTabBox() == rBoxes[ i ] ) + return true; + } + + return false; +} + +// +// SwDoc::GetTabRows() +// + +void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* , + const SwCellFrm* pBoxFrm ) const +{ + OSL_ENSURE( pBoxFrm, "GetTabRows called without pBoxFrm" ); + + // Make code robust: + if ( !pBoxFrm ) + return; + + // --> FME 2005-01-06 #i39552# Collection of the boxes of the current + // column has to be done at the beginning of this function, because + // the table may be formatted in ::GetTblSel. + SwDeletionChecker aDelCheck( pBoxFrm ); + + SwSelBoxes aBoxes; + const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm ); + if ( pCntnt && pCntnt->IsTxtFrm() ) + { + const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() ); + const SwCursor aTmpCrsr( aPos, 0, false ); + ::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL ); + } + // <-- + + // Make code robust: + if ( aDelCheck.HasBeenDeleted() ) + { + OSL_FAIL( "Current box has been deleted during GetTabRows()" ); + return; + } + + // Make code robust: + const SwTabFrm* pTab = pBoxFrm->FindTabFrm(); + OSL_ENSURE( pTab, "GetTabRows called without a table" ); + if ( !pTab ) + return; + + const SwFrm* pFrm = pTab->GetNextLayoutLeaf(); + + //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ. + SWRECTFN( pTab ) + const SwPageFrm* pPage = pTab->FindPageFrm(); + const long nLeftMin = ( bVert ? + pTab->GetPrtLeft() - pPage->Frm().Left() : + pTab->GetPrtTop() - pPage->Frm().Top() ); + const long nLeft = bVert ? LONG_MAX : 0; + const long nRight = (pTab->Prt().*fnRect->fnGetHeight)(); + const long nRightMax = bVert ? nRight : LONG_MAX; + + rFill.SetLeftMin( nLeftMin ); + rFill.SetLeft( nLeft ); + rFill.SetRight( nRight ); + rFill.SetRightMax( nRightMax ); + + typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap; + BoundaryMap aBoundaries; + BoundaryMap::iterator aIter; + std::pair< long, long > aPair; + + typedef std::map< long, bool > HiddenMap; + HiddenMap aHidden; + HiddenMap::iterator aHiddenIter; + + while ( pFrm && pTab->IsAnLower( pFrm ) ) + { + if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab ) + { + // upper and lower borders of current cell frame: + long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)(); + long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)(); + + // get boundaries for nUpperBorder: + aIter = aBoundaries.find( nUpperBorder ); + if ( aIter == aBoundaries.end() ) + { + aPair.first = nUpperBorder; aPair.second = LONG_MAX; + aBoundaries[ nUpperBorder ] = aPair; + } + + // get boundaries for nLowerBorder: + aIter = aBoundaries.find( nLowerBorder ); + if ( aIter == aBoundaries.end() ) + { + aPair.first = nUpperBorder; aPair.second = LONG_MAX; + } + else + { + nLowerBorder = (*aIter).first; + long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder ); + aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX; + } + aBoundaries[ nLowerBorder ] = aPair; + + // calculate hidden flags for entry nUpperBorder/nLowerBorder: + long nTmpVal = nUpperBorder; + for ( sal_uInt8 i = 0; i < 2; ++i ) + { + aHiddenIter = aHidden.find( nTmpVal ); + if ( aHiddenIter == aHidden.end() ) + aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ); + else + { + if ( aHidden[ nTmpVal ] && + lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) ) + aHidden[ nTmpVal ] = false; + } + nTmpVal = nLowerBorder; + } + } + + pFrm = pFrm->GetNextLayoutLeaf(); + } + + // transfer calculated values from BoundaryMap and HiddenMap into rFill: + sal_uInt16 nIdx = 0; + for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter ) + { + const long nTabTop = (pTab->*fnRect->fnGetPrtTop)(); + const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop ); + const std::pair< long, long > aTmpPair = (*aIter).second; + const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop ); + const long nSecond = aTmpPair.second; + + aHiddenIter = aHidden.find( (*aIter).first ); + const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second; + rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ ); + } + + // delete first and last entry + OSL_ENSURE( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" ); + // --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make + // code robust by checking count of rFill. + if ( rFill.Count() ) rFill.Remove( 0, 1 ); + if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 ); + // <-- + rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() ); +} + +void SwDoc::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly, + const SwCursor* pCrsr, const SwCellFrm* pBoxFrm ) +{ + const SwTableBox* pBox = 0; + SwTabFrm *pTab = 0; + + if( pBoxFrm ) + { + pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm(); + pBox = pBoxFrm->GetTabBox(); + } + else if( pCrsr ) + { + const SwCntntNode* pCNd = pCrsr->GetCntntNode(); + if( !pCNd ) + return ; + + Point aPt; + const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr); + if( pShCrsr ) + aPt = pShCrsr->GetPtPos(); + + const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False ); + do { + pTmpFrm = pTmpFrm->GetUpper(); + } while ( !pTmpFrm->IsCellFrm() ); + + pBoxFrm = (SwCellFrm*)pTmpFrm; + pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm(); + pBox = pBoxFrm->GetTabBox(); + } + else if( !pCrsr && !pBoxFrm ) + { + OSL_ENSURE( !this, "einer von beiden muss angegeben werden!" ); + return ; + } + + // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen + // dann muss es jetzt auf absolute umgerechnet werden. + SwTable& rTab = *pTab->GetTable(); + const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize(); + SWRECTFN( pTab ) + // #i17174# - With fix for #i9040# the shadow size is taken + // from the table width. Thus, add its left and right size to current table + // printing area width in order to get the correct table size attribute. + SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); + { + SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() ); + nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) + + aShadow.CalcShadowSpace( SHADOW_RIGHT ); + } + if( nPrtWidth != rTblFrmSz.GetWidth() ) + { + SwFmtFrmSize aSz( rTblFrmSz ); + aSz.SetWidth( nPrtWidth ); + rTab.GetFrmFmt()->SetFmtAttr( aSz ); + } + + SwTabCols aOld( rNew.Count() ); + + const SwPageFrm* pPage = pTab->FindPageFrm(); + const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() - + (pPage->Frm().*fnRect->fnGetLeft)(); + + //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ. + aOld.SetLeftMin ( nLeftMin ); + aOld.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() ); + aOld.SetRight ( (pTab->Prt().*fnRect->fnGetRight)()); + aOld.SetRightMax( nRightMax - nLeftMin ); + + rTab.GetTabCols( aOld, pBox ); + SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly ); +} + +void SwDoc::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const SwCursor*, + const SwCellFrm* pBoxFrm ) +{ + const SwTableBox* pBox; + SwTabFrm *pTab; + + OSL_ENSURE( pBoxFrm, "SetTabRows called without pBoxFrm" ); + + pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm(); + pBox = pBoxFrm->GetTabBox(); + + // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen + // dann muss es jetzt auf absolute umgerechnet werden. + SWRECTFN( pTab ) + SwTabCols aOld( rNew.Count() ); + + //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ. + const SwPageFrm* pPage = pTab->FindPageFrm(); + + aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() ); + long nLeftMin; + if ( bVert ) + { + nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left(); + aOld.SetLeft ( LONG_MAX ); + aOld.SetRightMax( aOld.GetRight() ); + + } + else + { + nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top(); + aOld.SetLeft ( 0 ); + aOld.SetRightMax( LONG_MAX ); + } + aOld.SetLeftMin ( nLeftMin ); + + GetTabRows( aOld, 0, pBoxFrm ); + + GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_ATTR, NULL ); + + // check for differences between aOld and rNew: + const sal_uInt16 nCount = rNew.Count(); + const SwTable* pTable = pTab->GetTable(); + OSL_ENSURE( pTable, "My colleague told me, this couldn't happen" ); + + for ( sal_uInt16 i = 0; i <= nCount; ++i ) + { + const sal_uInt16 nIdxStt = bVert ? nCount - i : i - 1; + const sal_uInt16 nIdxEnd = bVert ? nCount - i - 1 : i; + + const long nOldRowStart = i == 0 ? 0 : aOld[ nIdxStt ]; + const long nOldRowEnd = i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ]; + const long nOldRowHeight = nOldRowEnd - nOldRowStart; + + const long nNewRowStart = i == 0 ? 0 : rNew[ nIdxStt ]; + const long nNewRowEnd = i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ]; + const long nNewRowHeight = nNewRowEnd - nNewRowStart; + + const long nDiff = nNewRowHeight - nOldRowHeight; + if ( abs( nDiff ) >= ROWFUZZY ) + { + // For the old table model pTxtFrm and pLine will be set for every box. + // For the new table model pTxtFrm will be set if the box is not covered, + // but the pLine will be set if the box is not an overlapping box + // In the new table model the row height can be adjusted, + // when both variables are set. + SwTxtFrm* pTxtFrm = 0; + const SwTableLine* pLine = 0; + + // Iterate over all SwCellFrms with Bottom = nOldPos + const SwFrm* pFrm = pTab->GetNextLayoutLeaf(); + while ( pFrm && pTab->IsAnLower( pFrm ) ) + { + if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab ) + { + const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)(); + const sal_uLong nTabTop = (pTab->*fnRect->fnGetPrtTop)(); + if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY ) + { + if ( !bCurColOnly || pFrm == pBoxFrm ) + { + const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) ); + + if ( pCntnt && pCntnt->IsTxtFrm() ) + { + pBox = ((SwCellFrm*)pFrm)->GetTabBox(); + const long nRowSpan = pBox->getRowSpan(); + if( nRowSpan > 0 ) // Not overlapped + pTxtFrm = (SwTxtFrm*)pCntnt; + if( nRowSpan < 2 ) // Not overlapping for row height + pLine = pBox->GetUpper(); + if( pLine && pTxtFrm ) // always for old table model + { + // The new row height must not to be calculated from a overlapping box + SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() ); + const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff; + if( nNewSize != aNew.GetHeight() ) + { + aNew.SetHeight( nNewSize ); + if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() ) + aNew.SetHeightSizeType( ATT_MIN_SIZE ); + // This position must not be in an overlapped box + const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() ); + const SwCursor aTmpCrsr( aPos, 0, false ); + SetRowHeight( aTmpCrsr, aNew ); + // For the new table model we're done, for the old one + // there might be another (sub)row to adjust... + if( pTable->IsNewModel() ) + break; + } + pLine = 0; + } + } + } + } + } + pFrm = pFrm->GetNextLayoutLeaf(); + } + } + } + + GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_ATTR, NULL ); + + ::ClearFEShellTabCols(); +} + +/* -------------------------------------------------- + * Direktzugriff fuer UNO + * --------------------------------------------------*/ +void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld, + const SwTableBox *pStart, sal_Bool bCurRowOnly ) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + new SwUndoAttrTbl( *rTab.GetTableNode(), sal_True )); + } + rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly ); + ::ClearFEShellTabCols(); + SetModified(); +} + +void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet ) +{ + if( nSet == rTable.GetRowsToRepeat() ) + return; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + new SwUndoTblHeadline(rTable, rTable.GetRowsToRepeat(), nSet) ); + } + + SwMsgPoolItem aChg( RES_TBLHEADLINECHG ); + rTable.SetRowsToRepeat( nSet ); + rTable.GetFrmFmt()->ModifyNotification( &aChg, &aChg ); + SetModified(); +} + + + + +// Splittet eine Tabelle in der Grund-Zeile, in der der Index steht. +// Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node. +// Ist das Flag bCalcNewSize auf sal_True, wird fuer beide neuen Tabellen +// die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt, +// die Size ist "absolut" gesetzt (USHRT_MAX) + +void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd ) +{ + if( pHst ) + pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE ); +} + +void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox ) +{ + aPosArr.Insert( nWidth, aPosArr.Count() ); + SwTableBox* p = (SwTableBox*)&rBox; + aBoxes.Insert( p, aBoxes.Count() ); + nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth(); +} + +const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox ) +{ + const SwTableBox* pRet = 0; + sal_uInt16 n; + + if( aPosArr.Count() ) + { + for( n = 0; n < aPosArr.Count(); ++n ) + if( aPosArr[ n ] == nWidth ) + break; + else if( aPosArr[ n ] > nWidth ) + { + if( n ) + --n; + break; + } + + if( n >= aPosArr.Count() ) + --n; + + nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth(); + pRet = aBoxes[ n ]; + } + return pRet; +} + +sal_Bool SwCollectTblLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth ) +{ + sal_uInt16 n; + + if( aPosArr.Count() ) + { + for( n = 0; n < aPosArr.Count(); ++n ) + if( aPosArr[ n ] == nOffset ) + break; + else if( aPosArr[ n ] > nOffset ) + { + if( n ) + --n; + break; + } + + aPosArr.Remove( 0, n ); + aBoxes.Remove( 0, n ); + + // dann die Positionen der neuen Size anpassen + for( n = 0; n < aPosArr.Count(); ++n ) + { + sal_uLong nSize = nWidth; + nSize *= ( aPosArr[ n ] - nOffset ); + nSize /= nOldWidth; + aPosArr[ n ] = sal_uInt16( nSize ); + } + } + return 0 != aPosArr.Count(); +} + +sal_Bool lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara ) +{ + SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara; + if( pSplPara->IsGetValues() ) + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara ); + else + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara ); + return sal_True; +} + +sal_Bool lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara ) +{ + SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara; + sal_uInt16 nLen = rpBox->GetTabLines().Count(); + if( nLen ) + { + // dann mit der richtigen Line weitermachen + if( pSplPara->IsGetFromTop() ) + nLen = 0; + else + --nLen; + + const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ]; + lcl_Line_CollectBox( pLn, pPara ); + } + else + pSplPara->AddBox( *rpBox ); + return sal_True; +} + +sal_Bool lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara ) +{ + SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara; + sal_uInt16 nLen = rpBox->GetTabLines().Count(); + if( nLen ) + { + // dann mit der richtigen Line weitermachen + if( pSplPara->IsGetFromTop() ) + nLen = 0; + else + --nLen; + + const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ]; + lcl_Line_CollectBox( pLn, pPara ); + } + else + { + const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox ); + SwFrmFmt* pFmt = pSrcBox->GetFrmFmt(); + SwTableBox* pBox = (SwTableBox*)rpBox; + + if( HEADLINE_BORDERCOPY == pSplPara->GetMode() ) + { + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + if( !rBoxItem.GetTop() ) + { + SvxBoxItem aNew( rBoxItem ); + aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP ); + if( aNew != rBoxItem ) + pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); + } + } + else + { +sal_uInt16 aTableSplitBoxSetRange[] = { + RES_LR_SPACE, RES_UL_SPACE, + RES_BACKGROUND, RES_SHADOW, + RES_PROTECT, RES_PROTECT, + RES_VERT_ORIENT, RES_VERT_ORIENT, + 0 }; + SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(), + aTableSplitBoxSetRange ); + aTmpSet.Put( pFmt->GetAttrSet() ); + if( aTmpSet.Count() ) + pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet ); + + if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() ) + { + SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = aIdx.GetNodes().GoNext( &aIdx ); + aIdx = *pBox->GetSttNd(); + SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx ); + + // nur wenn der Node alleine in der Section steht + if( 2 == pDNd->EndOfSectionIndex() - + pDNd->StartOfSectionIndex() ) + { + pSplPara->AddToUndoHistory( *pDNd ); + pDNd->ChgFmtColl( pCNd->GetFmtColl() ); + } + } + + // bedingte Vorlage beachten + pBox->GetSttNd()->CheckSectionCondColl(); + } + } + return sal_True; +} + + +sal_Bool SwDoc::SplitTable( const SwPosition& rPos, sal_uInt16 eHdlnMode, + sal_Bool bCalcNewSize ) +{ + SwNode* pNd = &rPos.nNode.GetNode(); + SwTableNode* pTNd = pNd->FindTableNode(); + if( !pTNd || pNd->IsTableNode() ) + return 0; + + if( pTNd->GetTable().ISA( SwDDETable )) + return sal_False; + + SwTable& rTbl = pTNd->GetTable(); + rTbl.SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + SwTableFmlUpdate aMsgHnt( &rTbl ); + + SwHistory aHistory; + if (GetIDocumentUndoRedo().DoesUndo()) + { + aMsgHnt.pHistory = &aHistory; + } + + { + sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex(); + + // Suche die Grund-Line dieser Box: + SwTableBox* pBox = rTbl.GetTblBox( nSttIdx ); + if( pBox ) + { + SwTableLine* pLine = pBox->GetUpper(); + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + // in pLine steht jetzt die GrundLine. + aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + } + + String sNewTblNm( GetUniqueTblName() ); + aMsgHnt.DATA.pNewTblNm = &sNewTblNm; + aMsgHnt.eFlags = TBL_SPLITTBL; + UpdateTblFlds( &aMsgHnt ); + } + + //Lines fuer das Layout-Update heraussuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( rTbl ); + aFndBox.DelFrms( rTbl ); + + SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, sal_False, bCalcNewSize ); + + if( pNew ) + { + SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() ); + SwUndoSplitTbl* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoSplitTbl( + *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize); + GetIDocumentUndoRedo().AppendUndo(pUndo); + if( aHistory.Count() ) + pUndo->SaveFormula( aHistory ); + } + + switch( eHdlnMode ) + { + // setze die untere Border der vorherige Line, + // an der aktuellen als obere + case HEADLINE_BORDERCOPY: + { + SwCollectTblLineBoxes aPara( sal_False, eHdlnMode ); + SwTableLine* pLn = rTbl.GetTabLines()[ + rTbl.GetTabLines().Count() - 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara ); + + aPara.SetValues( sal_True ); + pLn = pNew->GetTable().GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara ); + + // Kopfzeile wiederholen abschalten + pNew->GetTable().SetRowsToRepeat( 0 ); + } + break; + + // setze die Attributierung der ersten Line an der neuen ersten + case HEADLINE_BOXATTRCOPY: + case HEADLINE_BOXATRCOLLCOPY: + { + SwHistory* pHst = 0; + if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo ) + pHst = pUndo->GetHistory(); + + SwCollectTblLineBoxes aPara( sal_True, eHdlnMode, pHst ); + SwTableLine* pLn = rTbl.GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara ); + + aPara.SetValues( sal_True ); + pLn = pNew->GetTable().GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara ); + } + break; + + case HEADLINE_CNTNTCOPY: + rTbl.CopyHeadlineIntoTable( *pNew ); + if( pUndo ) + pUndo->SetTblNodeOffset( pNew->GetIndex() ); + break; + + case HEADLINE_NONE: + // Kopfzeile wiederholen abschalten + pNew->GetTable().SetRowsToRepeat( 0 ); + break; + } + + // und Frms einfuegen. + SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() ); + GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode + pNew->MakeFrms( &aNdIdx ); + + //Zwischen die Tabellen wird ein Absatz geschoben + GetNodes().MakeTxtNode( SwNodeIndex( *pNew ), + GetTxtCollFromPool( RES_POOLCOLL_TEXT ) ); + } + + //Layout updaten + aFndBox.MakeFrms( rTbl ); + + // TL_CHART2: need to inform chart of probably changed cell names + UpdateCharts( rTbl.GetFrmFmt()->GetName() ); + + SetFieldsDirty( true, NULL, 0 ); + + return 0 != pNew; +} + +sal_Bool lcl_ChgTblSize( SwTable& rTbl ) +{ + // das Attribut darf nicht ueber das Modify an der + // Tabelle gesetzt werden, denn sonst werden alle + // Boxen wieder auf 0 zurueck gesetzt. Also locke das Format + SwFrmFmt* pFmt = rTbl.GetFrmFmt(); + SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() ); + + if( USHRT_MAX == aTblMaxSz.GetWidth() ) + return sal_False; + + sal_Bool bLocked = pFmt->IsModifyLocked(); + pFmt->LockModify(); + + aTblMaxSz.SetWidth( 0 ); + + SwTableLines& rLns = rTbl.GetTabLines(); + for( sal_uInt16 nLns = 0; nLns < rLns.Count(); ++nLns ) + { + SwTwips nMaxLnWidth = 0; + SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes(); + for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox ) + nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth(); + + if( nMaxLnWidth > aTblMaxSz.GetWidth() ) + aTblMaxSz.SetWidth( nMaxLnWidth ); + } + pFmt->SetFmtAttr( aTblMaxSz ); + if( !bLocked ) // und gegebenenfalls Lock wieder freigeben + pFmt->UnlockModify(); + + return sal_True; +} + +class _SplitTable_Para +{ + SvPtrarr aSrc, aDest; + SwTableNode* pNewTblNd; + SwTable& rOldTbl; + +public: + _SplitTable_Para( SwTableNode* pNew, SwTable& rOld ) + : aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld ) + {} + sal_uInt16 SrcFmt_GetPos( void* pFmt ) const + { return aSrc.GetPos( pFmt ); } + + void DestFmt_Insert( void* pFmt ) + { aDest.Insert( pFmt, aDest.Count() ); } + + void SrcFmt_Insert( void* pFmt ) + { aSrc.Insert( pFmt, aSrc.Count() ); } + + SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const + { return (SwFrmFmt*)aDest[ nPos ]; } + + void ChgBox( SwTableBox* pBox ) + { + rOldTbl.GetTabSortBoxes().Remove( pBox ); + pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox ); + } +}; + + +sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara ); + +sal_Bool lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara ) +{ + SwTableLine* pLn = (SwTableLine*)rpLine; + _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara; + + SwFrmFmt *pSrcFmt = pLn->GetFrmFmt(); + sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt ); + if( USHRT_MAX == nPos ) + { + rPara.DestFmt_Insert( pLn->ClaimFrmFmt() ); + rPara.SrcFmt_Insert( pSrcFmt ); + } + else + pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) ); + + pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara ); + return sal_True; +} + +sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara ) +{ + SwTableBox* pBox = (SwTableBox*)rpBox; + _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara; + + SwFrmFmt *pSrcFmt = pBox->GetFrmFmt(); + sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt ); + if( USHRT_MAX == nPos ) + { + rPara.DestFmt_Insert( pBox->ClaimFrmFmt() ); + rPara.SrcFmt_Insert( pSrcFmt ); + } + else + pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) ); + + if( pBox->GetSttNd() ) + rPara.ChgBox( pBox ); + else + pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara ); + return sal_True; +} + +SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, sal_Bool bAfter, + sal_Bool bCalcNewSize ) +{ + SwNode* pNd = &rPos.GetNode(); + SwTableNode* pTNd = pNd->FindTableNode(); + if( !pTNd || pNd->IsTableNode() ) + return 0; + + sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex(); + + // Suche die Grund-Line dieser Box: + SwTable& rTbl = pTNd->GetTable(); + SwTableBox* pBox = rTbl.GetTblBox( nSttIdx ); + if( !pBox ) + return 0; + + SwTableLine* pLine = pBox->GetUpper(); + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + // in pLine steht jetzt die GrundLine. + sal_uInt16 nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + if( USHRT_MAX == nLinePos || + ( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos )) + return 0; // nicht gefunden oder letze Line !! + + // Suche jetzt die 1. Box der nachfolgenden Line + SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ]; + pBox = pNextLine->GetTabBoxes()[0]; + while( !pBox->GetSttNd() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + + // dann fuege mal einen End- und TabelleNode ins Nodes-Array ein. + SwTableNode * pNewTblNd; + { + SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode(); + OSL_ENSURE( pOldTblEndNd, "wo ist der EndNode?" ); + + SwNodeIndex aIdx( *pBox->GetSttNd() ); + new SwEndNode( aIdx, *pTNd ); + pNewTblNd = new SwTableNode( aIdx ); + pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() ); + + pOldTblEndNd->pStartOfSection = pNewTblNd; + pNewTblNd->pEndOfSection = pOldTblEndNd; + + SwNode* pBoxNd = aIdx.GetNode().GetStartNode(); + do { + OSL_ENSURE( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" ); + pBoxNd->pStartOfSection = pNewTblNd; + pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ]; + } while( pBoxNd != pOldTblEndNd ); + } + + { + // die Lines ruebermoven... + SwTable& rNewTbl = pNewTblNd->GetTable(); + rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos ); + // + // von hinten (unten-rechts) nach vorn (oben-links) alle Boxen + // beim chart data provider austragen (das modified event wird dann + // in der aufrufenden Funktion getriggert. + // TL_CHART2: + SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider(); + if( pPCD ) + { + for (sal_uInt16 k = nLinePos; k < rTbl.GetTabLines().Count(); ++k) + { + sal_uInt16 nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos; + sal_uInt16 nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count(); + for (sal_uInt16 j = 0; j < nBoxCnt; ++j) + { + sal_uInt16 nIdx = nBoxCnt - 1 - j; + pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] ); + } + } + } + // + // ...und loeschen + sal_uInt16 nDeleted = rTbl.GetTabLines().Count() - nLinePos; + rTbl.GetTabLines().Remove( nLinePos, nDeleted ); + + // und die betr. Boxen verschieben. Dabei die Formate eindeutig + // machen und die StartNodes korrigieren + _SplitTable_Para aPara( pNewTblNd, rTbl ); + rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara ); + rTbl.CleanUpBottomRowSpan( nDeleted ); + } + + { + // Das Tabellen-FrmFormat kopieren + SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt(); + SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt( + pOldTblFmt->GetDoc()->GetUniqueTblName(), + pOldTblFmt->GetDoc()->GetDfltFrmFmt() ); + + *pNewTblFmt = *pOldTblFmt; + pNewTblNd->GetTable().RegisterToFormat( *pNewTblFmt ); + + // neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es + // beim 1. schon geklappt hat; also absolute Groesse hat) + if( bCalcNewSize && lcl_ChgTblSize( rTbl ) ) + lcl_ChgTblSize( pNewTblNd->GetTable() ); + } + + // TL_CHART2: need to inform chart of probably changed cell names + rTbl.UpdateCharts(); + + return pNewTblNd; // das wars +} + +// und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen +// bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter +// stehenden vereint wird. +sal_Bool SwDoc::MergeTable( const SwPosition& rPos, sal_Bool bWithPrev, sal_uInt16 nMode ) +{ + SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd; + if( !pTblNd ) + return sal_False; + + SwNodes& rNds = GetNodes(); + if( bWithPrev ) + pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode(); + else + pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode(); + if( !pDelTblNd ) + return sal_False; + + if( pTblNd->GetTable().ISA( SwDDETable ) || + pDelTblNd->GetTable().ISA( SwDDETable )) + return sal_False; + + // MIB 9.7.97: HTML-Layout loeschen + pTblNd->GetTable().SetHTMLTableLayout( 0 ); + pDelTblNd->GetTable().SetHTMLTableLayout( 0 ); + + // beide Tabellen vorhanden, also kanns losgehen + SwUndoMergeTbl* pUndo = 0; + SwHistory* pHistory = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, bWithPrev, nMode ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + pHistory = new SwHistory; + } + + // alle "Tabellenformeln" anpassen + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable(); + aMsgHnt.eFlags = TBL_MERGETBL; + aMsgHnt.pHistory = pHistory; + UpdateTblFlds( &aMsgHnt ); + + // das eigentliche Mergen + SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd ); + sal_Bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory ); + + if( pHistory ) + { + if( pHistory->Count() ) + pUndo->SaveFormula( *pHistory ); + delete pHistory; + } + if( bRet ) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + return bRet; +} + +sal_Bool SwNodes::MergeTable( const SwNodeIndex& rPos, sal_Bool bWithPrev, + sal_uInt16 nMode, SwHistory* ) +{ + SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode(); + OSL_ENSURE( pDelTblNd, "wo ist der TableNode geblieben?" ); + + SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode(); + OSL_ENSURE( pTblNd, "wo ist der TableNode geblieben?" ); + + if( !pDelTblNd || !pTblNd ) + return sal_False; + + pDelTblNd->DelFrms(); + + SwTable& rDelTbl = pDelTblNd->GetTable(); + SwTable& rTbl = pTblNd->GetTable(); + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( rTbl ); + aFndBox.DelFrms( rTbl ); + + // TL_CHART2: since chart currently does not want to get informed about + // additional rows/cols there is no need for a modified event in the + // remaining first table. Also, if it is required it should be done + // after the merging and not here... + // pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() ); + + + // TL_CHART2: + // tell the charts about the table to be deleted and have them use their own data + GetDoc()->CreateChartInternalDataProviders( &rDelTbl ); + + // die Breite der TabellenFormate abgleichen: + { + const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize(); + const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize(); + if( rTblSz != rDelTblSz ) + { + // dann sollten die mal schleunigst korrigiert werden + if( bWithPrev ) + rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz ); + else + rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz ); + } + } + + if( !bWithPrev ) + { + // dann mussen alle Attruibute der hinteren Tabelle auf die + // vordere uebertragen werden, weil die hintere ueber das loeschen + // des Node geloescht wird. + rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() ); + rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() ); + + rTbl.GetFrmFmt()->LockModify(); + *rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt(); + // auch den Namen umsetzen! + rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() ); + rTbl.GetFrmFmt()->UnlockModify(); + } + + // die Lines und Boxen ruebermoven + sal_uInt16 nOldSize = rTbl.GetTabLines().Count(); + rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize ); + rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() ); + + rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() ); + rDelTbl.GetTabSortBoxes().Remove( (sal_uInt16)0, rDelTbl.GetTabSortBoxes().Count() ); + + // die vordere Tabelle bleibt immer stehen, die hintere wird geloescht + SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode(); + pTblNd->pEndOfSection = pTblEndNd; + + SwNodeIndex aIdx( *pDelTblNd, 1 ); + + SwNode* pBoxNd = aIdx.GetNode().GetStartNode(); + do { + OSL_ENSURE( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" ); + pBoxNd->pStartOfSection = pTblNd; + pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ]; + } while( pBoxNd != pTblEndNd ); + pBoxNd->pStartOfSection = pTblNd; + + aIdx -= 2; + DelNodes( aIdx, 2 ); + + // jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen + const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ]; + if( 1 == nMode ) // + { + // Header-Vorlagen in der Zeile setzen + // und ggfs. in der History speichern fuers Undo!!! + } + lcl_LineSetHeadCondColl( pFirstLn, 0 ); + + // und die Borders "aufrauemen" + if( nOldSize ) + { + _SwGCLineBorder aPara( rTbl ); + aPara.nLinePos = --nOldSize; + pFirstLn = rTbl.GetTabLines()[ nOldSize ]; + lcl_GC_Line_Border( pFirstLn, &aPara ); + } + + //Layout updaten + aFndBox.MakeFrms( rTbl ); + + return sal_True; +} + +// ------------------------------------------------------------------- + + +// -- benutze die ForEach Methode vom PtrArray +struct _SetAFmtTabPara +{ + SwTableAutoFmt& rTblFmt; + SwUndoTblAutoFmt* pUndo; + sal_uInt16 nEndBox, nCurBox; + sal_uInt8 nAFmtLine, nAFmtBox; + + _SetAFmtTabPara( const SwTableAutoFmt& rNew ) + : rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ), + nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 ) + {} +}; + +// forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen +// koennen. +sal_Bool lcl_SetAFmtBox( const _FndBox*&, void *pPara ); +sal_Bool lcl_SetAFmtLine( const _FndLine*&, void *pPara ); + +sal_Bool lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara ) +{ + ((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara ); + return sal_True; +} + +sal_Bool lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara ) +{ + _SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara; + + if( !rpBox->GetUpper()->GetUpper() ) // Box auf 1. Ebene ? + { + if( !pSetPara->nCurBox ) + pSetPara->nAFmtBox = 0; + else if( pSetPara->nCurBox == pSetPara->nEndBox ) + pSetPara->nAFmtBox = 3; + else + pSetPara->nAFmtBox = (sal_uInt8)(1 + ((pSetPara->nCurBox-1) & 1)); + } + + if( rpBox->GetBox()->GetSttNd() ) + { + SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox(); + SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc(); + SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 ); + SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange ); + sal_uInt8 nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox; + pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet, + SwTableAutoFmt::UPDATE_CHAR, 0 ); + pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet, + SwTableAutoFmt::UPDATE_BOX, + pDoc->GetNumberFormatter( sal_True ) ); + if( aCharSet.Count() ) + { + sal_uLong nSttNd = pSetBox->GetSttIdx()+1; + sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex(); + for( ; nSttNd < nEndNd; ++nSttNd ) + { + SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode(); + if( pNd ) + pNd->SetAttr( aCharSet ); + } + } + + if( aBoxSet.Count() ) + { + if( pSetPara->pUndo && + SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT )) + pSetPara->pUndo->SaveBoxCntnt( *pSetBox ); + + pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet ); + } + } + else + ((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara ); + + if( !rpBox->GetUpper()->GetUpper() ) // eine BaseLine + ++pSetPara->nCurBox; + return sal_True; +} + + + // AutoFormat fuer die Tabelle/TabellenSelection +sal_Bool SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew ) +{ + OSL_ENSURE( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + pTblNd->GetTable().SetHTMLTableLayout( 0 ); + + _FndBox* pFndBox = &aFndBox; + while( 1 == pFndBox->GetLines().Count() && + 1 == pFndBox->GetLines()[0]->GetBoxes().Count() ) + pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0]; + + if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box) + pFndBox = pFndBox->GetUpper()->GetUpper(); + + + // Undo abschalten, Attribute werden sich vorher gemerkt + SwUndoTblAutoFmt* pUndo = 0; + bool const bUndo(GetIDocumentUndoRedo().DoesUndo()); + if (bUndo) + { + pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + GetIDocumentUndoRedo().DoUndo(false); + } + + _SetAFmtTabPara aPara( rNew ); + _FndLines& rFLns = pFndBox->GetLines(); + _FndLine* pLine; + + for( sal_uInt16 n = 0; n < rFLns.Count(); ++n ) + { + pLine = rFLns[n]; + + // Upper auf 0 setzen (Base-Line simulieren!) + _FndBox* pSaveBox = pLine->GetUpper(); + pLine->SetUpper( 0 ); + + if( !n ) + aPara.nAFmtLine = 0; + else if( n+1 == rFLns.Count() ) + aPara.nAFmtLine = 3; + else + aPara.nAFmtLine = (sal_uInt8)(1 + ((n-1) & 1 )); + + aPara.nAFmtBox = 0; + aPara.nCurBox = 0; + aPara.nEndBox = pLine->GetBoxes().Count()-1; + aPara.pUndo = pUndo; + pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara ); + + pLine->SetUpper( pSaveBox ); + } + + if( pUndo ) + { + GetIDocumentUndoRedo().DoUndo(bUndo); + } + + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + + return sal_True; +} + + + // Erfrage wie attributiert ist +sal_Bool SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet ) +{ + OSL_ENSURE( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + _FndBox* pFndBox = &aFndBox; + while( 1 == pFndBox->GetLines().Count() && + 1 == pFndBox->GetLines()[0]->GetBoxes().Count() ) + pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0]; + + if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box) + pFndBox = pFndBox->GetUpper()->GetUpper(); + + _FndLines& rFLns = pFndBox->GetLines(); + + sal_uInt16 aLnArr[4]; + aLnArr[0] = 0; + aLnArr[1] = 1 < rFLns.Count() ? 1 : 0; + aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1]; + aLnArr[3] = rFLns.Count() - 1; + + for( sal_uInt8 nLine = 0; nLine < 4; ++nLine ) + { + _FndLine& rLine = *rFLns[ aLnArr[ nLine ] ]; + + sal_uInt16 aBoxArr[4]; + aBoxArr[0] = 0; + aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0; + aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1]; + aBoxArr[3] = rLine.GetBoxes().Count() - 1; + + for( sal_uInt8 nBox = 0; nBox < 4; ++nBox ) + { + SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox(); + // immer auf die 1. runterfallen + while( !pFBox->GetSttNd() ) + pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0]; + + sal_uInt8 nPos = nLine * 4 + nBox; + SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 ); + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetNodes().GoNext( &aIdx ); + + if( pCNd ) + rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(), + SwTableAutoFmt::UPDATE_CHAR, 0 ); + rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(), + SwTableAutoFmt::UPDATE_BOX, + GetNumberFormatter( sal_True ) ); + } + } + + return sal_True; +} + +String SwDoc::GetUniqueTblName() const +{ + ResId aId( STR_TABLE_DEFNAME, *pSwResMgr ); + String aName( aId ); + xub_StrLen nNmLen = aName.Len(); + + sal_uInt16 nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2; + sal_uInt16 n; + + sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; + memset( pSetFlags, 0, nFlagSize ); + + for( n = 0; n < pTblFrmFmtTbl->Count(); ++n ) + { + const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ]; + if( !pFmt->IsDefault() && IsUsed( *pFmt ) && + pFmt->GetName().Match( aName ) == nNmLen ) + { + // Nummer bestimmen und das Flag setzen + nNum = static_cast<sal_uInt16>(pFmt->GetName().Copy( nNmLen ).ToInt32()); + if( nNum-- && nNum < pTblFrmFmtTbl->Count() ) + pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); + } + } + + // alle Nummern entsprechend geflag, also bestimme die richtige Nummer + nNum = pTblFrmFmtTbl->Count(); + for( n = 0; n < nFlagSize; ++n ) + if( 0xff != ( nTmp = pSetFlags[ n ] )) + { + // also die Nummer bestimmen + nNum = n * 8; + while( nTmp & 1 ) + ++nNum, nTmp >>= 1; + break; + } + + delete [] pSetFlags; + return aName += String::CreateFromInt32( ++nNum ); +} + +SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, sal_Bool bAll ) const +{ + const SwFmt* pRet = 0; + if( bAll ) + pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName ); + else + { + // dann nur die, die im Doc gesetzt sind + for( sal_uInt16 n = 0; n < pTblFrmFmtTbl->Count(); ++n ) + { + const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ]; + if( !pFmt->IsDefault() && IsUsed( *pFmt ) && + pFmt->GetName() == rName ) + { + pRet = pFmt; + break; + } + } + } + return (SwTableFmt*)pRet; +} + +sal_Bool SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, sal_uInt16 eType, + SwTwips nAbsDiff, SwTwips nRelDiff ) +{ + SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode(); + SwUndo* pUndo = 0; + + if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable )) + return sal_False; + + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_BOXPTR; + UpdateTblFlds( &aMsgHnt ); + + bool const bUndo(GetIDocumentUndoRedo().DoesUndo()); + sal_Bool bRet = sal_False; + switch( eType & 0xff ) + { + case nsTblChgWidthHeightType::WH_COL_LEFT: + case nsTblChgWidthHeightType::WH_COL_RIGHT: + case nsTblChgWidthHeightType::WH_CELL_LEFT: + case nsTblChgWidthHeightType::WH_CELL_RIGHT: + { + bRet = pTblNd->GetTable().SetColWidth( rAktBox, + eType, nAbsDiff, nRelDiff, + (bUndo) ? &pUndo : 0 ); + } + break; + case nsTblChgWidthHeightType::WH_ROW_TOP: + case nsTblChgWidthHeightType::WH_ROW_BOTTOM: + case nsTblChgWidthHeightType::WH_CELL_TOP: + case nsTblChgWidthHeightType::WH_CELL_BOTTOM: + bRet = pTblNd->GetTable().SetRowHeight( rAktBox, + eType, nAbsDiff, nRelDiff, + (bUndo) ? &pUndo : 0 ); + break; + } + + GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off + if( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + + if( bRet ) + { + SetModified(); + if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType ) + SetFieldsDirty( true, NULL, 0 ); + } + return bRet; +} + + +void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, sal_Bool bCallUpdate ) +{ + //JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text + // sein soll, dann bleibt das auch Text! + const SfxPoolItem* pNumFmtItem = 0; + if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, + sal_False, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat( + ((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() )) + return ; + + SwUndoTblNumFmt* pUndo = 0; + + sal_Bool bIsEmptyTxtNd, bChgd = sal_True; + sal_uInt32 nFmtIdx; + double fNumber; + if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) ) + { + if( !rBox.IsNumberChanged() ) + bChgd = sal_False; + else + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL ); + pUndo = new SwUndoTblNumFmt( rBox ); + pUndo->SetNumFmt( nFmtIdx, fNumber ); + } + + SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt(); + SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + + sal_Bool bSetNumFmt = IsInsTblFormatNum(), bLockModify = sal_True; + if( bSetNumFmt ) + { + if( !IsInsTblChangeNumFormat() ) + { + if( !pNumFmtItem ) + bSetNumFmt = sal_False; + else + { + sal_uLong nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)-> + GetValue(); + SvNumberFormatter* pNumFmtr = GetNumberFormatter(); + + short nFmtType = pNumFmtr->GetType( nFmtIdx ); + if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) || + NUMBERFORMAT_NUMBER == nFmtType ) + // eingstelltes und vorgegebenes NumFormat + // stimmen ueberein -> altes Format beibehalten + nFmtIdx = nOldNumFmt; + else + // eingstelltes und vorgegebenes NumFormat + // stimmen nicht ueberein -> als Text einfuegen + bLockModify = bSetNumFmt = sal_False; + } + } + + if( bSetNumFmt ) + { + pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt(); + + aBoxSet.Put( SwTblBoxValue( fNumber )); + aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx )); + } + } + + // JP 28.04.98: Nur Formel zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + + if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem ) + { + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT )); + } + + if( bLockModify ) pBoxFmt->LockModify(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + if( bLockModify ) pBoxFmt->UnlockModify(); + + if( bSetNumFmt ) + pBoxFmt->SetFmtAttr( aBoxSet ); + } + } + else + { + // es ist keine Zahl + const SfxPoolItem* pValueItem = 0, *pFmtItem = 0; + SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt(); + if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT, + sal_False, &pFmtItem ) || + SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE, + sal_False, &pValueItem )) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL ); + pUndo = new SwUndoTblNumFmt( rBox ); + } + + pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt(); + + // alle Zahlenformate entfernen + sal_uInt16 nWhich1 = RES_BOXATR_FORMULA; + if( !bIsEmptyTxtNd ) + { + nWhich1 = RES_BOXATR_FORMAT; + + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 )); + } + pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE ); + } + else + bChgd = sal_False; + } + + if( bChgd ) + { + if( pUndo ) + { + pUndo->SetBox( rBox ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + } + + const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode(); + if( bCallUpdate ) + { + SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() ); + UpdateTblFlds( &aTblUpdate ); + + // TL_CHART2: update charts (when cursor leaves cell and + // automatic update is enabled) + if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true)) + pTblNd->GetTable().UpdateCharts(); + } + SetModified(); + } +} + +void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet ) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoTblNumFmt(rBox, &rSet) ); + } + + SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt(); + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA )) + { + pBoxFmt->LockModify(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE ); + pBoxFmt->UnlockModify(); + } + else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE )) + { + pBoxFmt->LockModify(); + pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA ); + pBoxFmt->UnlockModify(); + } + pBoxFmt->SetFmtAttr( rSet ); + SetModified(); +} + +void SwDoc::ClearLineNumAttrs( SwPosition & rPos ) +{ + SwPaM aPam(rPos); + aPam.Move(fnMoveBackward); + SwCntntNode *pNode = aPam.GetCntntNode(); + if ( 0 == pNode ) + return ; + if( pNode->IsTxtNode() ) + { + SwTxtNode * pTxtNode = pNode->GetTxtNode(); + if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->GetTxt().Len()==0 ) + { + const SfxPoolItem* pFmtItem = 0; + SfxItemSet rSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()), + RES_PARATR_BEGIN, RES_PARATR_END - 1, + 0); + pTxtNode->SwCntntNode::GetAttr( rSet ); + if ( SFX_ITEM_SET == rSet.GetItemState( RES_PARATR_NUMRULE , sal_False , &pFmtItem ) ) + { + SwUndoDelNum * pUndo; + if( GetIDocumentUndoRedo().DoesUndo() ) + { + GetIDocumentUndoRedo().ClearRedo(); + GetIDocumentUndoRedo().AppendUndo( pUndo = new SwUndoDelNum( aPam ) ); + } + else + pUndo = 0; + SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 ); + aRegH.RegisterInModify( pTxtNode , *pTxtNode ); + if ( pUndo ) + pUndo->AddNode( *pTxtNode , sal_False ); + String aStyle = String::CreateFromAscii(""); + SfxStringItem * pNewItem = (SfxStringItem*)pFmtItem->Clone(); + pNewItem->SetValue( aStyle ); + rSet.Put( *pNewItem ); + pTxtNode->SetAttr( rSet ); + delete pNewItem; + } + } + } +} + +void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode ) +{ + SwStartNode* pSttNd; + if( 0 != ( pSttNd = rNode.GetNode(). + FindSttNodeByType( SwTableBoxStartNode )) && + 2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() ) + { + SwTableBox* pBox = pSttNd->FindTableNode()->GetTable(). + GetTblBox( pSttNd->GetIndex() ); + + const SfxPoolItem* pFmtItem = 0; + const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet(); + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pFmtItem ) || + SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, sal_False ) || + SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, sal_False )) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoTblNumFmt(*pBox)); + } + + SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt(); + + //JP 01.09.97: TextFormate bleiben erhalten! + sal_uInt16 nWhich1 = RES_BOXATR_FORMAT; + if( pFmtItem && GetNumberFormatter()->IsTextFormat( + ((SwTblBoxNumFormat*)pFmtItem)->GetValue() )) + nWhich1 = RES_BOXATR_FORMULA; + else + // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht. + // Sorge dafuer, das der Text auch entsprechend + // formatiert wird! + pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT )); + + pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE ); + SetModified(); + } + } +} + +// kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich +// selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende +// mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder +// in eine bestehende TblSelektion gefuellt wird. +// Gerufen wird es von: edglss.cxx/fecopy.cxx + +sal_Bool SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes, + const SwTable* pCpyTbl, sal_Bool bCpyName, sal_Bool bCorrPos ) +{ + sal_Bool bRet; + + const SwTableNode* pSrcTblNd = pCpyTbl + ? pCpyTbl->GetTableNode() + : rBoxes[ 0 ]->GetSttNd()->FindTableNode(); + + SwTableNode * pInsTblNd = rInsPos.nNode.GetNode().FindTableNode(); + + bool const bUndo( GetIDocumentUndoRedo().DoesUndo() ); + if( !pCpyTbl && !pInsTblNd ) + { + SwUndoCpyTbl* pUndo = 0; + if (bUndo) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndo = new SwUndoCpyTbl; + } + + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes, + sal_True, bCpyName ); + } + + if( pUndo ) + { + if( !bRet ) + { + delete pUndo; + pUndo = 0; + } + else + { + pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode(); + + pUndo->SetTableSttIdx( pInsTblNd->GetIndex() ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + } + else + { + RedlineMode_t eOld = GetRedlineMode(); + if( IsRedlineOn() ) + SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | + nsRedlineMode_t::REDLINE_SHOW_INSERT | + nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + SwUndoTblCpyTbl* pUndo = 0; + if (bUndo) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndo = new SwUndoTblCpyTbl; + GetIDocumentUndoRedo().DoUndo(false); + } + + SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc(); + sal_Bool bDelCpyDoc = pCpyDoc == this; + + if( bDelCpyDoc ) + { + // kopiere die Tabelle erstmal in ein temp. Doc + pCpyDoc = new SwDoc; + pCpyDoc->acquire(); + + SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() )); + if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, sal_True, sal_True )) + { + if( pCpyDoc->release() == 0 ) + delete pCpyDoc; + + if( pUndo ) + { + GetIDocumentUndoRedo().DoUndo(bUndo); + delete pUndo; + pUndo = 0; + } + return sal_False; + } + aPos.nNode -= 1; // auf den EndNode der Tabelle + pSrcTblNd = aPos.nNode.GetNode().FindTableNode(); + } + + const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode(); + + rInsPos.nContent.Assign( 0, 0 ); + + // no complex into complex, but copy into or from new model is welcome + if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() ) + && ( bDelCpyDoc || rBoxes.Count() ) ) + { + // dann die Tabelle "relativ" kopieren + const SwSelBoxes* pBoxes; + SwSelBoxes aBoxes; + + if( bDelCpyDoc ) + { + SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox( + pSttNd->GetIndex() ); + OSL_ENSURE( pBox, "Box steht nicht in dieser Tabelle" ); + aBoxes.Insert( pBox ); + pBoxes = &aBoxes; + } + else + pBoxes = &rBoxes; + + // kopiere die Tabelle in die selktierten Zellen. + bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(), + *pBoxes, pUndo ); + } + else + { + SwNodeIndex aNdIdx( *pSttNd, 1 ); + bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(), + aNdIdx, pUndo ); + } + + if( bDelCpyDoc ) + { + if( pCpyDoc->release() == 0 ) + delete pCpyDoc; + } + + if( pUndo ) + { + // falls die Tabelle nicht kopiert werden konnte, das Undo-Object + // wieder loeschen + GetIDocumentUndoRedo().DoUndo(bUndo); + if( !bRet && pUndo->IsEmpty() ) + delete pUndo; + else + { + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + + if( bCorrPos ) + { + rInsPos.nNode = *pSttNd; + rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 ); + } + SetRedlineMode( eOld ); + } + + if( bRet ) + { + SetModified(); + SetFieldsDirty( true, NULL, 0 ); + } + return bRet; +} + + + +sal_Bool SwDoc::_UnProtectTblCells( SwTable& rTbl ) +{ + sal_Bool bChgd = sal_False; + SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoAttrTbl( *rTbl.GetTableNode() ) + : 0; + + SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes(); + for( sal_uInt16 i = rSrtBox.Count(); i; ) + { + SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + pBoxFmt->ResetFmtAttr( RES_PROTECT ); + bChgd = sal_True; + } + } + + if( pUndo ) + { + if( bChgd ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + return bChgd; +} + + +sal_Bool SwDoc::UnProtectCells( const String& rName ) +{ + sal_Bool bChgd = sal_False; + SwTableFmt* pFmt = FindTblFmtByName( rName ); + if( pFmt ) + { + bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) ); + if( bChgd ) + SetModified(); + } + + return bChgd; +} + +sal_Bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes ) +{ + sal_Bool bChgd = sal_False; + if( rBoxes.Count() ) + { + SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() ) + : 0; + + SvPtrarr aFmts( 16 ), aNewFmts( 16 ); + for( sal_uInt16 i = rBoxes.Count(); i; ) + { + SwTableBox* pBox = rBoxes[ --i ]; + SwFrmFmt* pBoxFmt = pBox->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + sal_uInt16 nFnd = aFmts.GetPos( pBoxFmt ); + if( USHRT_MAX != nFnd ) + pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] ); + else + { + aFmts.Insert( pBoxFmt, aFmts.Count() ); + pBoxFmt = pBox->ClaimFrmFmt(); + pBoxFmt->ResetFmtAttr( RES_PROTECT ); + aNewFmts.Insert( pBoxFmt, aNewFmts.Count() ); + } + bChgd = sal_True; + } + } + + if( pUndo ) + { + if( bChgd ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + delete pUndo; + } + } + return bChgd; +} + +sal_Bool SwDoc::UnProtectTbls( const SwPaM& rPam ) +{ + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); + + sal_Bool bChgd = sal_False, bHasSel = rPam.HasMark() || + rPam.GetNext() != (SwPaM*)&rPam; + SwFrmFmts& rFmts = *GetTblFrmFmts(); + SwTable* pTbl; + const SwTableNode* pTblNd; + for( sal_uInt16 n = rFmts.Count(); n ; ) + if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) && + 0 != (pTblNd = pTbl->GetTableNode() ) && + pTblNd->GetNodes().IsDocNodes() ) + { + sal_uLong nTblIdx = pTblNd->GetIndex(); + + // dann ueberpruefe ob Tabelle in der Selection liegt + if( bHasSel ) + { + int bFound = sal_False; + SwPaM* pTmp = (SwPaM*)&rPam; + do { + const SwPosition *pStt = pTmp->Start(), + *pEnd = pTmp->End(); + bFound = pStt->nNode.GetIndex() < nTblIdx && + nTblIdx < pEnd->nNode.GetIndex(); + + } while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) ); + if( !bFound ) + continue; // weitersuchen + } + + // dann mal den Schutz aufheben + bChgd |= _UnProtectTblCells( *pTbl ); + } + + GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); + if( bChgd ) + SetModified(); + + return bChgd; +} + +sal_Bool SwDoc::HasTblAnyProtection( const SwPosition* pPos, + const String* pTblName, + sal_Bool* pFullTblProtection ) +{ + sal_Bool bHasProtection = sal_False; + SwTable* pTbl = 0; + if( pTblName ) + pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) ); + else if( pPos ) + { + SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode(); + if( pTblNd ) + pTbl = &pTblNd->GetTable(); + } + + if( pTbl ) + { + SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes(); + for( sal_uInt16 i = rSrtBox.Count(); i; ) + { + SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt(); + if( pBoxFmt->GetProtect().IsCntntProtected() ) + { + if( !bHasProtection ) + { + bHasProtection = sal_True; + if( !pFullTblProtection ) + break; + *pFullTblProtection = sal_True; + } + } + else if( bHasProtection && pFullTblProtection ) + { + *pFullTblProtection = sal_False; + break; + } + } + } + return bHasProtection; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx new file mode 100644 index 000000000000..5f66a3d17fbd --- /dev/null +++ b/sw/source/core/docnode/ndtbl1.cxx @@ -0,0 +1,1598 @@ +/* -*- 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_sw.hxx" + +#include "hintids.hxx" +#include <editeng/lrspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtlsplt.hxx> +#include <fmtrowsplt.hxx> +#include <tabcol.hxx> +#include <frmatr.hxx> +#include <cellfrm.hxx> +#include <tabfrm.hxx> +#include <cntfrm.hxx> +#include <txtfrm.hxx> +#include <svx/svxids.hrc> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include "pam.hxx" +#include "swcrsr.hxx" +#include "viscrs.hxx" +#include "swtable.hxx" +#include "htmltbl.hxx" +#include "tblsel.hxx" +#include "swtblfmt.hxx" +#include "docary.hxx" +#include "ndindex.hxx" +#include "undobj.hxx" +#include "switerator.hxx" +#include <UndoTable.hxx> + +using ::editeng::SvxBorderLine; +using namespace ::com::sun::star; + + +extern void ClearFEShellTabCols(); + +//siehe auch swtable.cxx +#define COLFUZZY 20L + +inline sal_Bool IsSame( long nA, long nB ) { return Abs(nA-nB) <= COLFUZZY; } + +class SwTblFmtCmp +{ +public: + SwFrmFmt *pOld, + *pNew; + sal_Int16 nType; + + SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, sal_Int16 nType ); + + static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, sal_Int16 nType ); + static void Delete( SvPtrarr &rArr ); +}; + + +SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, sal_Int16 nT ) + : pOld ( pO ), pNew ( pN ), nType( nT ) +{ +} + +SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, sal_Int16 nType ) +{ + for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) + { + SwTblFmtCmp *pCmp = (SwTblFmtCmp*)rArr[i]; + if ( pCmp->pOld == pOld && pCmp->nType == nType ) + return pCmp->pNew; + } + return 0; +} + +void SwTblFmtCmp::Delete( SvPtrarr &rArr ) +{ + for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) + delete (SwTblFmtCmp*)rArr[i]; +} + +void lcl_GetStartEndCell( const SwCursor& rCrsr, + SwLayoutFrm *&prStart, SwLayoutFrm *&prEnd ) +{ + OSL_ENSURE( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ), + "Tabselection nicht auf Cnt." ); + + Point aPtPos, aMkPos; + const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); + if( pShCrsr ) + { + aPtPos = pShCrsr->GetPtPos(); + aMkPos = pShCrsr->GetMkPos(); + } + + // robust: + SwCntntNode* pPointNd = rCrsr.GetCntntNode(); + SwCntntNode* pMarkNd = rCrsr.GetCntntNode(sal_False); + + SwFrm* pPointFrm = pPointNd ? pPointNd->getLayoutFrm( pPointNd->GetDoc()->GetCurrentLayout(), &aPtPos ) : 0; + SwFrm* pMarkFrm = pMarkNd ? pMarkNd->getLayoutFrm( pMarkNd->GetDoc()->GetCurrentLayout(), &aMkPos ) : 0; + + prStart = pPointFrm ? pPointFrm->GetUpper() : 0; + prEnd = pMarkFrm ? pMarkFrm->GetUpper() : 0; +} + +sal_Bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes, + sal_Bool bAllCrsr = sal_False ) +{ + const SwTableCursor* pTblCrsr = + dynamic_cast<const SwTableCursor*>(&rCursor); + if( pTblCrsr ) + ::GetTblSelCrs( *pTblCrsr, rBoxes ); + else + { + const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam; + do { + const SwNode* pNd = pCurPam->GetNode()->FindTableBoxStartNode(); + if( pNd ) + { + SwTableBox* pBox = (SwTableBox*)pNd->FindTableNode()->GetTable(). + GetTblBox( pNd->GetIndex() ); + rBoxes.Insert( pBox ); + } + } while( bAllCrsr && + pSttPam != ( pCurPam = (SwPaM*)pCurPam->GetNext()) ); + } + return 0 != rBoxes.Count(); +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetRowHeight(), GetRowHeight() +#***********************************************************************/ +//Die Zeilenhoehe wird ausgehend von der Selektion ermittelt/gesetzt. +//Ausgehend von jeder Zelle innerhalb der Selektion werden nach oben alle +//Zeilen abgeklappert, die oberste Zeile erhaelt den gewuenschten Wert alle +//tieferliegenden Zeilen einen entsprechenden Wert der sich aus der +//Relation der alten und neuen Groesse der obersten Zeile und ihrer +//eigenen Groesse ergiebt. +//Alle veraenderten Zeilen erhalten ggf. ein eigenes FrmFmt. +//Natuerlich darf jede Zeile nur einmal angefasst werden. + +inline void InsertLine( SvPtrarr& rLineArr, SwTableLine* pLine ) +{ + if( USHRT_MAX == rLineArr.GetPos( pLine ) ) + rLineArr.Insert( pLine, rLineArr.Count() ); +} + +//----------------------------------------------------------------------------- + +sal_Bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed ) +{ + const SwTableLine *pTmp = pAssumed->GetUpper() ? + pAssumed->GetUpper()->GetUpper() : 0; + while ( pTmp ) + { + if ( pTmp == pLine ) + return sal_True; + pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0; + } + return sal_False; +} +//----------------------------------------------------------------------------- + +struct LinesAndTable +{ + SvPtrarr &rLines; + const SwTable &rTable; + sal_Bool bInsertLines; + + LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) : + rLines( rL ), rTable( rTbl ), bInsertLines( sal_True ) {} +}; + + +sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ); + +sal_Bool _FindBox( const _FndBox*& rpBox, void* pPara ) +{ + if ( rpBox->GetLines().Count() ) + { + ((LinesAndTable*)pPara)->bInsertLines = sal_True; + ((_FndBox*)rpBox)->GetLines().ForEach( _FindLine, pPara ); + if ( ((LinesAndTable*)pPara)->bInsertLines ) + { + const SwTableLines &rLines = rpBox->GetBox() + ? rpBox->GetBox()->GetTabLines() + : ((LinesAndTable*)pPara)->rTable.GetTabLines(); + if ( rpBox->GetLines().Count() == rLines.Count() ) + { + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + ::InsertLine( ((LinesAndTable*)pPara)->rLines, + (SwTableLine*)rLines[i] ); + } + else + ((LinesAndTable*)pPara)->bInsertLines = sal_False; + } + } + else if ( rpBox->GetBox() ) + ::InsertLine( ((LinesAndTable*)pPara)->rLines, + (SwTableLine*)rpBox->GetBox()->GetUpper() ); + return sal_True; +} + +sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara ) +{ + ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara ); + return sal_True; +} + +void lcl_CollectLines( SvPtrarr &rArr, const SwCursor& rCursor, bool bRemoveLines ) +{ + //Zuerst die selektierten Boxen einsammeln. + SwSelBoxes aBoxes; + if( !::lcl_GetBoxSel( rCursor, aBoxes )) + return ; + + //Die selektierte Struktur kopieren. + const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable(); + LinesAndTable aPara( rArr, rTable ); + _FndBox aFndBox( 0, 0 ); + { + _FndPara aTmpPara( aBoxes, &aFndBox ); + ((SwTableLines&)rTable.GetTabLines()).ForEach( &_FndLineCopyCol, &aTmpPara ); + } + + //Diejenigen Lines einsammeln, die nur selektierte Boxen enthalten. + const _FndBox *pTmp = &aFndBox; + ::_FindBox( pTmp, &aPara ); + + // Remove lines, that have a common superordinate row. + // (Not for row split) + if ( bRemoveLines ) + { + for ( sal_uInt16 i = 0; i < rArr.Count(); ++i ) + { + SwTableLine *pUpLine = (SwTableLine*)rArr[i]; + for ( sal_uInt16 k = 0; k < rArr.Count(); ++k ) + { + if ( k != i && ::lcl_IsAnLower( pUpLine, (SwTableLine*)rArr[k] ) ) + { + rArr.Remove( k ); + if ( k <= i ) + --i; + --k; + } + } + } + } +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessRowAttr( SvPtrarr& rFmtCmp, SwTableLine* pLine, const SfxPoolItem& rNew ) +{ + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( rFmtCmp, pLine->GetFrmFmt(), 0 ))) + pLine->ChgFrmFmt( (SwTableLineFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pLine->GetFrmFmt(); + SwFrmFmt *pNew = pLine->ClaimFrmFmt(); + pNew->SetFmtAttr( rNew ); + rFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), rFmtCmp.Count()); + } +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ); + +void lcl_ProcessRowSize( SvPtrarr &rFmtCmp, SwTableLine *pLine, const SwFmtFrmSize &rNew ) +{ + lcl_ProcessRowAttr( rFmtCmp, pLine, rNew ); + SwTableBoxes &rBoxes = pLine->GetTabBoxes(); + for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) + ::lcl_ProcessBoxSize( rFmtCmp, rBoxes[i], rNew ); +} + +//----------------------------------------------------------------------------- + +void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew ) +{ + SwTableLines &rLines = pBox->GetTabLines(); + if ( rLines.Count() ) + { + SwFmtFrmSize aSz( rNew ); + aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.Count() : 0 ); + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + ::lcl_ProcessRowSize( rFmtCmp, rLines[i], aSz ); + } +} + +//----------------------------------------------------------------------------- + +/****************************************************************************** + * void SwDoc::SetRowSplit() + ******************************************************************************/ +void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFmtRowSplit &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, false ); + + if( aRowArr.Count() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); + } + + SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); + + for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } + } +} + + +/****************************************************************************** + * SwTwips SwDoc::GetRowSplit() const + ******************************************************************************/ +void SwDoc::GetRowSplit( const SwCursor& rCursor, SwFmtRowSplit *& rpSz ) const +{ + rpSz = 0; + + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, false ); + + if( aRowArr.Count() ) + { + rpSz = &(SwFmtRowSplit&)((SwTableLine*)aRowArr[0])-> + GetFrmFmt()->GetRowSplit(); + + for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i ) + { + if ( (*rpSz).GetValue() != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetRowSplit().GetValue() ) + rpSz = 0; + } + if ( rpSz ) + rpSz = new SwFmtRowSplit( *rpSz ); + } + } +} + + +/****************************************************************************** + * void SwDoc::SetRowHeight( SwTwips nNew ) + ******************************************************************************/ +void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFmtFrmSize &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); + } + + SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); + for ( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + SwTblFmtCmp::Delete( aFmtCmp ); + + SetModified(); + } + } +} + + +/****************************************************************************** + * SwTwips SwDoc::GetRowHeight() const + ******************************************************************************/ +void SwDoc::GetRowHeight( const SwCursor& rCursor, SwFmtFrmSize *& rpSz ) const +{ + rpSz = 0; + + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + rpSz = &(SwFmtFrmSize&)((SwTableLine*)aRowArr[0])-> + GetFrmFmt()->GetFrmSize(); + + for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i ) + { + if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() ) + rpSz = 0; + } + if ( rpSz ) + rpSz = new SwFmtFrmSize( *rpSz ); + } + } +} + +sal_Bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, sal_Bool bTstOnly ) +{ + sal_Bool bRet = sal_False; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( 1 < aRowArr.Count() ) + { + if( !bTstOnly ) + { + long nHeight = 0; + sal_uInt16 i; + + for ( i = 0; i < aRowArr.Count(); ++i ) + { + SwIterator<SwFrm,SwFmt> aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() ); + SwFrm* pFrm = aIter.First(); + while ( pFrm ) + { + nHeight = Max( nHeight, pFrm->Frm().Height() ); + pFrm = aIter.Next(); + } + } + SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + new SwUndoAttrTbl(*pTblNd)); + } + + SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); + for( i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew ); + SwTblFmtCmp::Delete( aFmtCmp ); + + SetModified(); + } + bRet = sal_True; + } + } + return bRet; +} + +/****************************************************************************** + * void SwDoc::SetRowBackground() + ******************************************************************************/ +void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); + } + + SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 ); + + for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i ) + ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew ); + + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } + } +} + +/****************************************************************************** + * SwTwips SwDoc::GetRowBackground() const + ******************************************************************************/ +sal_Bool SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const +{ + sal_Bool bRet = sal_False; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines. + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.Count() ) + { + rToFill = ((SwTableLine*)aRowArr[0])->GetFrmFmt()->GetBackground(); + + bRet = sal_True; + for ( sal_uInt16 i = 1; i < aRowArr.Count(); ++i ) + if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() ) + { + bRet = sal_False; + break; + } + } + } + return bRet; +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetTabBorders(), GetTabBorders() +#***********************************************************************/ +inline void InsertCell( SvPtrarr& rCellArr, SwCellFrm* pCellFrm ) +{ + if( USHRT_MAX == rCellArr.GetPos( pCellFrm ) ) + rCellArr.Insert( pCellFrm, rCellArr.Count() ); +} + +//----------------------------------------------------------------------------- +void lcl_CollectCells( SvPtrarr &rArr, const SwRect &rUnion, + SwTabFrm *pTab ) +{ + SwLayoutFrm *pCell = pTab->FirstCell(); + do + { + // Wenn in der Zelle ein spaltiger Bereich sitzt, muessen wir + // uns erst wieder zur Zelle hochhangeln + while ( !pCell->IsCellFrm() ) + pCell = pCell->GetUpper(); + OSL_ENSURE( pCell, "Frame ist keine Zelle." ); + if ( rUnion.IsOver( pCell->Frm() ) ) + ::InsertCell( rArr, (SwCellFrm*)pCell ); + //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche) + SwLayoutFrm *pTmp = pCell; + do + { pTmp = pTmp->GetNextLayoutLeaf(); + } while ( pCell->IsAnLower( pTmp ) ); + pCell = pTmp; + } while( pCell && pTab->IsAnLower( pCell ) ); +} + +void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet ) +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SwTable& rTable = pTblNd->GetTable(); + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) ); + } + + SvPtrarr aFmtCmp( 255, 255 ); + const SvxBoxItem* pSetBox; + const SvxBoxInfoItem *pSetBoxInfo; + + const SvxBorderLine* pLeft = 0; + const SvxBorderLine* pRight = 0; + const SvxBorderLine* pTop = 0; + const SvxBorderLine* pBottom = 0; + const SvxBorderLine* pHori = 0; + const SvxBorderLine* pVert = 0; + sal_Bool bHoriValid = sal_True, bVertValid = sal_True, + bTopValid = sal_True, bBottomValid = sal_True, + bLeftValid = sal_True, bRightValid = sal_True; + + // JP 21.07.95: die Flags im BoxInfo-Item entscheiden, wann eine + // BorderLine gueltig ist!! + if( SFX_ITEM_SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, sal_False, + (const SfxPoolItem**)&pSetBoxInfo) ) + { + pHori = pSetBoxInfo->GetHori(); + pVert = pSetBoxInfo->GetVert(); + + bHoriValid = pSetBoxInfo->IsValid(VALID_HORI); + bVertValid = pSetBoxInfo->IsValid(VALID_VERT); + + // wollen wir die auswerten ?? + bTopValid = pSetBoxInfo->IsValid(VALID_TOP); + bBottomValid = pSetBoxInfo->IsValid(VALID_BOTTOM); + bLeftValid = pSetBoxInfo->IsValid(VALID_LEFT); + bRightValid = pSetBoxInfo->IsValid(VALID_RIGHT); + } + + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOX, sal_False, + (const SfxPoolItem**)&pSetBox) ) + { + pLeft = pSetBox->GetLeft(); + pRight = pSetBox->GetRight(); + pTop = pSetBox->GetTop(); + pBottom = pSetBox->GetBottom(); + } + else + { + // nicht gesetzt, also keine gueltigen Werte + bTopValid = bBottomValid = bLeftValid = bRightValid = sal_False; + pSetBox = 0; + } + + sal_Bool bFirst = sal_True; + for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + SwTabFrm *pTab = pUnion->GetTable(); + const SwRect &rUnion = pUnion->GetUnion(); + const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_False; + + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); + + //Alle Zellenkanten, die mit dem UnionRect uebereinstimmen oder + //darueber hinausragen sind Aussenkanten. Alle anderen sind + //Innenkanten. + //neu: Die Aussenkanten koennen abhaengig davon, ob es sich um eine + //Start/Mittlere/Folge -Tabelle (bei Selektionen ueber FollowTabs) + //handelt doch keine Aussenkanten sein. + //Aussenkanten werden links, rechts, oben und unten gesetzt. + //Innenkanten werden nur oben und links gesetzt. + for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) + { + SwCellFrm *pCell = (SwCellFrm*)aCellArr[j]; + const sal_Bool bVert = pTab->IsVertical(); + const sal_Bool bRTL = pTab->IsRightToLeft(); + sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; + if ( bVert ) + { + bTopOver = pCell->Frm().Right() >= rUnion.Right(); + bLeftOver = pCell->Frm().Top() <= rUnion.Top(); + bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + bBottomOver = pCell->Frm().Left() <= rUnion.Left(); + } + else + { + bTopOver = pCell->Frm().Top() <= rUnion.Top(); + bLeftOver = pCell->Frm().Left() <= rUnion.Left(); + bRightOver = pCell->Frm().Right() >= rUnion.Right(); + bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + } + + if ( bRTL ) + { + sal_Bool bTmp = bRightOver; + bRightOver = bLeftOver; + bLeftOver = bTmp; + } + + //Grundsaetzlich nichts setzen in HeadlineRepeats. + if ( pTab->IsFollow() && + ( pTab->IsInHeadline( *pCell ) || + // Same holds for follow flow rows. + pCell->IsInFollowFlowRow() ) ) + continue; + + SvxBoxItem aBox( pCell->GetFmt()->GetBox() ); + + sal_Int16 nType = 0; + + //Obere Kante + if( bTopValid ) + { + if ( bFirst && bTopOver ) + { + aBox.SetLine( pTop, BOX_LINE_TOP ); + nType |= 0x0001; + } + else if ( bHoriValid ) + { + aBox.SetLine( 0, BOX_LINE_TOP ); + nType |= 0x0002; + } + } + + //Linke Kante + if ( bLeftOver ) + { + if( bLeftValid ) + { + aBox.SetLine( pLeft, BOX_LINE_LEFT ); + nType |= 0x0004; + } + } + else if( bVertValid ) + { + aBox.SetLine( pVert, BOX_LINE_LEFT ); + nType |= 0x0008; + } + + //Rechte Kante + if( bRightValid ) + { + if ( bRightOver ) + { + aBox.SetLine( pRight, BOX_LINE_RIGHT ); + nType |= 0x0010; + } + else if ( bVertValid ) + { + aBox.SetLine( 0, BOX_LINE_RIGHT ); + nType |= 0x0020; + } + } + + //Untere Kante + if ( bLast && bBottomOver ) + { + if( bBottomValid ) + { + aBox.SetLine( pBottom, BOX_LINE_BOTTOM ); + nType |= 0x0040; + } + } + else if( bHoriValid ) + { + aBox.SetLine( pHori, BOX_LINE_BOTTOM ); + nType |= 0x0080; + } + + if( pSetBox ) + { + static sal_uInt16 const aBorders[] = { + BOX_LINE_BOTTOM, BOX_LINE_TOP, + BOX_LINE_RIGHT, BOX_LINE_LEFT }; + const sal_uInt16* pBrd = aBorders; + for( int k = 0; k < 4; ++k, ++pBrd ) + aBox.SetDistance( pSetBox->GetDistance( *pBrd ), *pBrd ); + } + + SwTableBox *pBox = (SwTableBox*)pCell->GetTabBox(); + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), nType ))) + pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pBox->GetFrmFmt(); + SwFrmFmt *pNew = pBox->ClaimFrmFmt(); + pNew->SetFmtAttr( aBox ); + aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, nType ), aFmtCmp.Count()); + } + } + + bFirst = sal_False; + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->BordersChanged( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); + } + SwTblFmtCmp::Delete( aFmtCmp ); + ::ClearFEShellTabCols(); + SetModified(); + } +} + +void lcl_SetLineStyle( SvxBorderLine *pToSet, + const Color *pColor, const SvxBorderLine *pBorderLine) +{ + if ( pBorderLine ) + { + if ( !pColor ) + { + Color aTmp( pToSet->GetColor() ); + *pToSet = *pBorderLine; + pToSet->SetColor( aTmp ); + } + else + *pToSet = *pBorderLine; + } + if ( pColor ) + pToSet->SetColor( *pColor ); +} + +void SwDoc::SetTabLineStyle( const SwCursor& rCursor, + const Color* pColor, sal_Bool bSetLine, + const SvxBorderLine* pBorderLine ) +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SwTable& rTable = pTblNd->GetTable(); + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd)); + } + + for( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + SwTabFrm *pTab = pUnion->GetTable(); + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab ); + + for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) + { + SwCellFrm *pCell = ( SwCellFrm* )aCellArr[j]; + + //Grundsaetzlich nichts setzen in HeadlineRepeats. + if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) ) + continue; + + ((SwTableBox*)pCell->GetTabBox())->ClaimFrmFmt(); + SwFrmFmt *pFmt = pCell->GetFmt(); + SvxBoxItem aBox( pFmt->GetBox() ); + + if ( !pBorderLine && bSetLine ) + aBox = *(SvxBoxItem*)::GetDfltAttr( RES_BOX ); + else + { + if ( aBox.GetTop() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetTop(), + pColor, pBorderLine ); + if ( aBox.GetBottom() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetBottom(), + pColor, pBorderLine ); + if ( aBox.GetLeft() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetLeft(), + pColor, pBorderLine ); + if ( aBox.GetRight() ) + ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetRight(), + pColor, pBorderLine ); + } + pFmt->SetFmtAttr( aBox ); + } + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->BordersChanged( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); + } + ::ClearFEShellTabCols(); + SetModified(); + } +} + +void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet ) const +{ + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd ); + + if( aUnions.Count() ) + { + SvxBoxItem aSetBox ((const SvxBoxItem &) rSet.Get(RES_BOX )); + SvxBoxInfoItem aSetBoxInfo((const SvxBoxInfoItem&) rSet.Get(SID_ATTR_BORDER_INNER)); + + sal_Bool bTopSet = sal_False, + bBottomSet = sal_False, + bLeftSet = sal_False, + bRightSet = sal_False, + bHoriSet = sal_False, + bVertSet = sal_False, + bDistanceSet = sal_False; + + aSetBoxInfo.ResetFlags(); + + for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) + { + SwSelUnion *pUnion = aUnions[i]; + const SwTabFrm *pTab = pUnion->GetTable(); + const SwRect &rUnion = pUnion->GetUnion(); + const sal_Bool bFirst = i == 0 ? sal_True : sal_False; + const sal_Bool bLast = i == aUnions.Count() - 1 ? sal_True : sal_False; + + SvPtrarr aCellArr( 255, 255 ); + ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab ); + + for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j ) + { + const SwCellFrm *pCell = (const SwCellFrm*)aCellArr[j]; + const sal_Bool bVert = pTab->IsVertical(); + const sal_Bool bRTL = pTab->IsRightToLeft(); + sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver; + if ( bVert ) + { + bTopOver = pCell->Frm().Right() >= rUnion.Right(); + bLeftOver = pCell->Frm().Top() <= rUnion.Top(); + bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + bBottomOver = pCell->Frm().Left() <= rUnion.Left(); + } + else + { + bTopOver = pCell->Frm().Top() <= rUnion.Top(); + bLeftOver = pCell->Frm().Left() <= rUnion.Left(); + bRightOver = pCell->Frm().Right() >= rUnion.Right(); + bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom(); + } + + if ( bRTL ) + { + sal_Bool bTmp = bRightOver; + bRightOver = bLeftOver; + bLeftOver = bTmp; + } + + const SwFrmFmt *pFmt = pCell->GetFmt(); + const SvxBoxItem &rBox = pFmt->GetBox(); + + //Obere Kante + if ( bFirst && bTopOver ) + { + if (aSetBoxInfo.IsValid(VALID_TOP)) + { + if ( !bTopSet ) + { bTopSet = sal_True; + aSetBox.SetLine( rBox.GetTop(), BOX_LINE_TOP ); + } + else if ((aSetBox.GetTop() && rBox.GetTop() && + !(*aSetBox.GetTop() == *rBox.GetTop())) || + ((!aSetBox.GetTop()) ^ (!rBox.GetTop()))) // XOR-Ausdruck ist sal_True, wenn genau einer der beiden Pointer 0 ist + { + aSetBoxInfo.SetValid(VALID_TOP, sal_False ); + aSetBox.SetLine( 0, BOX_LINE_TOP ); + } + } + } + + //Linke Kante + if ( bLeftOver ) + { + if (aSetBoxInfo.IsValid(VALID_LEFT)) + { + if ( !bLeftSet ) + { bLeftSet = sal_True; + aSetBox.SetLine( rBox.GetLeft(), BOX_LINE_LEFT ); + } + else if ((aSetBox.GetLeft() && rBox.GetLeft() && + !(*aSetBox.GetLeft() == *rBox.GetLeft())) || + ((!aSetBox.GetLeft()) ^ (!rBox.GetLeft()))) + { + aSetBoxInfo.SetValid(VALID_LEFT, sal_False ); + aSetBox.SetLine( 0, BOX_LINE_LEFT ); + } + } + } + else + { + if (aSetBoxInfo.IsValid(VALID_VERT)) + { + if ( !bVertSet ) + { bVertSet = sal_True; + aSetBoxInfo.SetLine( rBox.GetLeft(), BOXINFO_LINE_VERT ); + } + else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() && + !(*aSetBoxInfo.GetVert() == *rBox.GetLeft())) || + ((!aSetBoxInfo.GetVert()) ^ (!rBox.GetLeft()))) + { aSetBoxInfo.SetValid( VALID_VERT, sal_False ); + aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT ); + } + } + } + + //Rechte Kante + if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver ) + { + if ( !bRightSet ) + { bRightSet = sal_True; + aSetBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); + } + else if ((aSetBox.GetRight() && rBox.GetRight() && + !(*aSetBox.GetRight() == *rBox.GetRight())) || + (!aSetBox.GetRight() ^ !rBox.GetRight())) + { aSetBoxInfo.SetValid( VALID_RIGHT, sal_False ); + aSetBox.SetLine( 0, BOX_LINE_RIGHT ); + } + } + + //Untere Kante + if ( bLast && bBottomOver ) + { + if ( aSetBoxInfo.IsValid(VALID_BOTTOM) ) + { + if ( !bBottomSet ) + { bBottomSet = sal_True; + aSetBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); + } + else if ((aSetBox.GetBottom() && rBox.GetBottom() && + !(*aSetBox.GetBottom() == *rBox.GetBottom())) || + (!aSetBox.GetBottom() ^ !rBox.GetBottom())) + { aSetBoxInfo.SetValid( VALID_BOTTOM, sal_False ); + aSetBox.SetLine( 0, BOX_LINE_BOTTOM ); + } + } + } + //in allen Zeilen ausser der letzten werden die + // horiz. Linien aus der Bottom-Linie entnommen + else + { + if (aSetBoxInfo.IsValid(VALID_HORI)) + { + if ( !bHoriSet ) + { bHoriSet = sal_True; + aSetBoxInfo.SetLine( rBox.GetBottom(), BOXINFO_LINE_HORI ); + } + else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() && + !(*aSetBoxInfo.GetHori() == *rBox.GetBottom())) || + ((!aSetBoxInfo.GetHori()) ^ (!rBox.GetBottom()))) + { + aSetBoxInfo.SetValid( VALID_HORI, sal_False ); + aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI ); + } + } + } + + // Abstand zum Text + if (aSetBoxInfo.IsValid(VALID_DISTANCE)) + { + static sal_uInt16 const aBorders[] = { + BOX_LINE_BOTTOM, BOX_LINE_TOP, + BOX_LINE_RIGHT, BOX_LINE_LEFT }; + const sal_uInt16* pBrd = aBorders; + + if( !bDistanceSet ) // bei 1. Durchlauf erstmal setzen + { + bDistanceSet = sal_True; + for( int k = 0; k < 4; ++k, ++pBrd ) + aSetBox.SetDistance( rBox.GetDistance( *pBrd ), + *pBrd ); + } + else + { + for( int k = 0; k < 4; ++k, ++pBrd ) + if( aSetBox.GetDistance( *pBrd ) != + rBox.GetDistance( *pBrd ) ) + { + aSetBoxInfo.SetValid( VALID_DISTANCE, sal_False ); + aSetBox.SetDistance( (sal_uInt16) 0 ); + break; + } + } + } + } + } + rSet.Put( aSetBox ); + rSet.Put( aSetBoxInfo ); + } +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetBoxAttr +#***********************************************************************/ +void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew ) +{ + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes, sal_True ) ) + { + SwTable& rTable = pTblNd->GetTable(); + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) ); + } + + SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aBoxes.Count()) ), 255 ); + for ( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) + { + SwTableBox *pBox = aBoxes[i]; + + SwFrmFmt *pNewFmt; + if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), 0 ))) + pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt ); + else + { + SwFrmFmt *pOld = pBox->GetFrmFmt(); + SwFrmFmt *pNew = pBox->ClaimFrmFmt(); + pNew->SetFmtAttr( rNew ); + aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), aFmtCmp.Count()); + } + } + + SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout(); + if( pTableLayout ) + { + SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() ); + SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm(); + + pTableLayout->Resize( + pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True ); + } + SwTblFmtCmp::Delete( aFmtCmp ); + SetModified(); + } +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : GetBoxAttr() +#***********************************************************************/ + +sal_Bool SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const +{ + sal_Bool bRet = sal_False; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes )) + { + bRet = sal_True; + sal_Bool bOneFound = sal_False; + const sal_uInt16 nWhich = rToFill.Which(); + for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) + { + switch ( nWhich ) + { + case RES_BACKGROUND: + { + const SvxBrushItem &rBack = + aBoxes[i]->GetFrmFmt()->GetBackground(); + if( !bOneFound ) + { + (SvxBrushItem&)rToFill = rBack; + bOneFound = sal_True; + } + else if( rToFill != rBack ) + bRet = sal_False; + } + break; + + case RES_FRAMEDIR: + { + const SvxFrameDirectionItem& rDir = + aBoxes[i]->GetFrmFmt()->GetFrmDir(); + if( !bOneFound ) + { + (SvxFrameDirectionItem&)rToFill = rDir; + bOneFound = sal_True; + } + else if( rToFill != rDir ) + bRet = sal_False; + } + case RES_VERT_ORIENT: + { + const SwFmtVertOrient& rOrient = + aBoxes[i]->GetFrmFmt()->GetVertOrient(); + if( !bOneFound ) + { + (SwFmtVertOrient&)rToFill = rOrient; + bOneFound = sal_True; + } + else if( rToFill != rOrient ) + bRet = sal_False; + } + } + + if ( sal_False == bRet ) + break; + } + } + return bRet; +} + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : SetBoxAlign, SetBoxAlign +#***********************************************************************/ +void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign ) +{ + OSL_ENSURE( nAlign == text::VertOrientation::NONE || + nAlign == text::VertOrientation::CENTER || + nAlign == text::VertOrientation::BOTTOM, "wrong alignment" ); + SwFmtVertOrient aVertOri( 0, nAlign ); + SetBoxAttr( rCursor, aVertOri ); +} + +sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor ) const +{ + sal_uInt16 nAlign = USHRT_MAX; + SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + SwSelBoxes aBoxes; + if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes )) + for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i ) + { + const SwFmtVertOrient &rOri = + aBoxes[i]->GetFrmFmt()->GetVertOrient(); + if( USHRT_MAX == nAlign ) + nAlign = static_cast<sal_uInt16>(rOri.GetVertOrient()); + else if( rOri.GetVertOrient() != nAlign ) + { + nAlign = USHRT_MAX; + break; + } + } + return nAlign; +} + + +/*********************************************************************** +#* Class : SwDoc +#* Methoden : AdjustCellWidth() +#***********************************************************************/ +sal_uInt16 lcl_CalcCellFit( const SwLayoutFrm *pCell ) +{ + SwTwips nRet = 0; + const SwFrm *pFrm = pCell->Lower(); //Die ganze Zelle. + SWRECTFN( pCell ) + while ( pFrm ) + { + const SwTwips nAdd = (pFrm->Frm().*fnRect->fnGetWidth)() - + (pFrm->Prt().*fnRect->fnGetWidth)(); + + // pFrm does not necessarily have to be a SwTxtFrm! + const SwTwips nCalcFitToContent = pFrm->IsTxtFrm() ? + ((SwTxtFrm*)pFrm)->CalcFitToContent() : + (pFrm->Prt().*fnRect->fnGetWidth)(); + + nRet = Max( nRet, nCalcFitToContent + nAdd ); + pFrm = pFrm->GetNext(); + } + //Umrandung und linker/rechter Rand wollen mit kalkuliert werden. + nRet += (pCell->Frm().*fnRect->fnGetWidth)() - + (pCell->Prt().*fnRect->fnGetWidth)(); + + //Um Rechenungenauikeiten, die spaeter bei SwTable::SetTabCols enstehen, + //auszugleichen, addieren wir noch ein bischen. + nRet += COLFUZZY; + return (sal_uInt16)Max( long(MINLAY), nRet ); +} + +/*Die Zelle ist in der Selektion, wird aber nicht von den TabCols beschrieben. + *Das bedeutet, dass die Zelle aufgrund der zweidimensionalen Darstellung von + *anderen Zellen "geteilt" wurde. Wir muessen also den Wunsch- bzw. Minimalwert + *der Zelle auf die Spalten, durch die sie geteilt wurde verteilen. + * + *Dazu sammeln wir zuerst die Spalten - nicht die Spaltentrenner! - ein, die + *sich mit der Zelle ueberschneiden. Den Wunschwert der Zelle verteilen wir + *dann anhand des Betrages der Ueberschneidung auf die Zellen. + *Wenn eine Zelle bereits einen groesseren Wunschwert angemeldet hat, so bleibt + *dieser erhalten, kleinere Wuensche werden ueberschrieben. + */ + +void lcl_CalcSubColValues( SvUShorts &rToFill, const SwTabCols &rCols, + const SwLayoutFrm *pCell, const SwLayoutFrm *pTab, + sal_Bool bWishValues ) +{ + const sal_uInt16 nWish = bWishValues ? + ::lcl_CalcCellFit( pCell ) : + MINLAY + sal_uInt16(pCell->Frm().Width() - pCell->Prt().Width()); + + SWRECTFN( pTab ) + + for ( sal_uInt16 i = 0 ; i <= rCols.Count(); ++i ) + { + long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; + long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; + nColLeft += rCols.GetLeftMin(); + nColRight += rCols.GetLeftMin(); + + //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. + if ( rCols.GetLeftMin() != sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) ) + { + const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); + nColLeft += nDiff; + nColRight += nDiff; + } + const long nCellLeft = (pCell->Frm().*fnRect->fnGetLeft)(); + const long nCellRight = (pCell->Frm().*fnRect->fnGetRight)(); + + //Ueberschneidungsbetrag ermitteln. + long nWidth = 0; + if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) ) + nWidth = nColRight - nCellLeft; + else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight ) + nWidth = nCellRight - nColLeft; + else if ( nColLeft >= nCellLeft && nColRight <= nCellRight ) + nWidth = nColRight - nColLeft; + if ( nWidth && pCell->Frm().Width() ) + { + long nTmp = nWidth * nWish / pCell->Frm().Width(); + if ( sal_uInt16(nTmp) > rToFill[i] ) + rToFill[i] = sal_uInt16(nTmp); + } + } +} + +/*Besorgt neue Werte zu Einstellung der TabCols. + *Es wird nicht ueber die Eintrage in den TabCols itereriert, sondern + *quasi ueber die Zwischenraeume, die ja die Zellen beschreiben. + * + *bWishValues == sal_True: Es werden zur aktuellen Selektion bzw. zur aktuellen + * Zelle die Wunschwerte aller betroffen Zellen ermittelt. + * Sind mehrere Zellen in einer Spalte, so wird der + * groesste Wunschwert als Ergebnis geliefert. + * Fuer die TabCol-Eintraege, zu denen keine Zellen + * ermittelt wurden, werden 0-en eingetragen. + * + *bWishValues == sal_False: Die Selektion wird senkrecht ausgedehnt. Zu jeder + * Spalte in den TabCols, die sich mit der Selektion + * schneidet wird der Minimalwert ermittelt. + */ + +void lcl_CalcColValues( SvUShorts &rToFill, const SwTabCols &rCols, + const SwLayoutFrm *pStart, const SwLayoutFrm *pEnd, + sal_Bool bWishValues ) +{ + SwSelUnions aUnions; + ::MakeSelUnions( aUnions, pStart, pEnd, + bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL ); + + for ( sal_uInt16 i2 = 0; i2 < aUnions.Count(); ++i2 ) + { + SwSelUnion *pSelUnion = aUnions[i2]; + const SwTabFrm *pTab = pSelUnion->GetTable(); + const SwRect &rUnion = pSelUnion->GetUnion(); + + SWRECTFN( pTab ) + sal_Bool bRTL = pTab->IsRightToLeft(); + + const SwLayoutFrm *pCell = pTab->FirstCell(); + do + { + if ( pCell->IsCellFrm() && pCell->FindTabFrm() == pTab && ::IsFrmInTblSel( rUnion, pCell ) ) + { + const long nCLeft = (pCell->Frm().*fnRect->fnGetLeft)(); + const long nCRight = (pCell->Frm().*fnRect->fnGetRight)(); + + sal_Bool bNotInCols = sal_True; + + for ( sal_uInt16 i = 0; i <= rCols.Count(); ++i ) + { + sal_uInt16 nFit = rToFill[i]; + long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1]; + long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i]; + + if ( bRTL ) + { + long nTmpRight = nColRight; + nColRight = rCols.GetRight() - nColLeft; + nColLeft = rCols.GetRight() - nTmpRight; + } + + nColLeft += rCols.GetLeftMin(); + nColRight += rCols.GetLeftMin(); + + //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen. + long nLeftA = nColLeft; + long nRightA = nColRight; + if ( rCols.GetLeftMin() != sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) ) + { + const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin(); + nLeftA += nDiff; + nRightA += nDiff; + } + + //Wir wollen nicht allzu genau hinsehen. + if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA)) + { + bNotInCols = sal_False; + if ( bWishValues ) + { + const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell ); + if ( nWish > nFit ) + nFit = nWish; + } + else + { const sal_uInt16 nMin = MINLAY + sal_uInt16(pCell->Frm().Width() - + pCell->Prt().Width()); + if ( !nFit || nMin < nFit ) + nFit = nMin; + } + if ( rToFill[i] < nFit ) + rToFill[i] = nFit; + } + } + if ( bNotInCols ) + ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues ); + } + do { + pCell = pCell->GetNextLayoutLeaf(); + }while( pCell && pCell->Frm().Width() == 0 ); + } while ( pCell && pTab->IsAnLower( pCell ) ); + } +} + + +void SwDoc::AdjustCellWidth( const SwCursor& rCursor, sal_Bool bBalance ) +{ + // pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen + SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode(); + SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0; + if( !pTblNd ) + return ; + + SwLayoutFrm *pStart, *pEnd; + ::lcl_GetStartEndCell( rCursor, pStart, pEnd ); + + //TabCols besorgen, den ueber diese stellen wir die Tabelle neu ein. + SwFrm* pBoxFrm = pStart; + while( pBoxFrm && !pBoxFrm->IsCellFrm() ) + pBoxFrm = pBoxFrm->GetUpper(); + + if ( !pBoxFrm ) + return; // robust + + SwTabCols aTabCols; + GetTabCols( aTabCols, 0, (SwCellFrm*)pBoxFrm ); + + if ( ! aTabCols.Count() ) + return; + + const sal_uInt8 nTmp = (sal_uInt8)Max( sal_uInt16(255), sal_uInt16(aTabCols.Count() + 1) ); + SvUShorts aWish( nTmp, nTmp ), + aMins( nTmp, nTmp ); + sal_uInt16 i; + + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + aWish.Insert( sal_uInt16(0), aWish.Count() ); + aMins.Insert( sal_uInt16(0), aMins.Count() ); + } + ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, sal_True ); + + //Es ist Robuster wenn wir die Min-Werte fuer die ganze Tabelle berechnen. + const SwTabFrm *pTab = pStart->ImplFindTabFrm(); + pStart = (SwLayoutFrm*)pTab->FirstCell(); + pEnd = (SwLayoutFrm*)pTab->FindLastCntnt()->GetUpper(); + while( !pEnd->IsCellFrm() ) + pEnd = pEnd->GetUpper(); + ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, sal_False ); + + if( bBalance ) + { + //Alle Spalten, die makiert sind haben jetzt einen Wunschwert + //eingtragen. Wir addieren die aktuellen Werte, teilen das Ergebnis + //durch die Anzahl und haben eine Wunschwert fuer den ausgleich. + sal_uInt16 nWish = 0, nCnt = 0; + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + int nDiff = aWish[i]; + if ( nDiff ) + { + if ( i == 0 ) + nWish = static_cast<sal_uInt16>( nWish + aTabCols[i] - aTabCols.GetLeft() ); + else if ( i == aTabCols.Count() ) + nWish = static_cast<sal_uInt16>(nWish + aTabCols.GetRight() - aTabCols[i-1] ); + else + nWish = static_cast<sal_uInt16>(nWish + aTabCols[i] - aTabCols[i-1] ); + ++nCnt; + } + } + nWish = nWish / nCnt; + for ( i = 0; i < aWish.Count(); ++i ) + if ( aWish[i] ) + aWish[i] = nWish; + } + + const sal_uInt16 nOldRight = static_cast<sal_uInt16>(aTabCols.GetRight()); + + //Um die Impl. einfach zu gestalten, aber trotzdem in den meissten Faellen + //den Platz richtig auszunutzen laufen wir zweimal. + //Problem: Erste Spalte wird breiter, die anderen aber erst danach + //schmaler. Die Wunschbreite der ersten Spalte wuerde abgelehnt, weil + //mit ihr die max. Breite der Tabelle ueberschritten wuerde. + for ( sal_uInt16 k= 0; k < 2; ++k ) + { + for ( i = 0; i <= aTabCols.Count(); ++i ) + { + int nDiff = aWish[i]; + if ( nDiff ) + { + int nMin = aMins[i]; + if ( nMin > nDiff ) + nDiff = nMin; + + if ( i == 0 ) + { + if( aTabCols.Count() ) + nDiff -= aTabCols[0] - aTabCols.GetLeft(); + else + nDiff -= aTabCols.GetRight() - aTabCols.GetLeft(); + } + else if ( i == aTabCols.Count() ) + nDiff -= aTabCols.GetRight() - aTabCols[i-1]; + else + nDiff -= aTabCols[i] - aTabCols[i-1]; + + long nTabRight = aTabCols.GetRight() + nDiff; + + //Wenn die Tabelle zu breit wuerde begrenzen wir die Anpassung + //auf das erlaubte Maximum. + if ( !bBalance && nTabRight > aTabCols.GetRightMax() ) + { + const long nTmpD = nTabRight - aTabCols.GetRightMax(); + nDiff -= nTmpD; + nTabRight -= nTmpD; + } + for ( sal_uInt16 i2 = i; i2 < aTabCols.Count(); ++i2 ) + aTabCols[i2] += nDiff; + aTabCols.SetRight( nTabRight ); + } + } + } + + const sal_uInt16 nNewRight = static_cast<sal_uInt16>(aTabCols.GetRight()); + + SwFrmFmt *pFmt = pTblNd->GetTable().GetFrmFmt(); + const sal_Int16 nOriHori = pFmt->GetHoriOrient().GetHoriOrient(); + + //So, die richtige Arbeit koennen wir jetzt der SwTable ueberlassen. + SetTabCols( aTabCols, sal_False, 0, (SwCellFrm*)pBoxFrm ); + + // i54248: lijian/fme + // alignment might have been changed in SetTabCols, restore old value: + const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient(); + SwFmtHoriOrient aHori( rHori ); + if ( aHori.GetHoriOrient() != nOriHori ) + { + aHori.SetHoriOrient( nOriHori ); + pFmt->SetFmtAttr( aHori ); + } + + //Bei Automatischer Breite wird auf Linksbuendig umgeschaltet. + //Bei Randattributen wird der Rechte Rand angepasst. + if( !bBalance && nNewRight < nOldRight ) + { + if( aHori.GetHoriOrient() == text::HoriOrientation::FULL ) + { + aHori.SetHoriOrient( text::HoriOrientation::LEFT ); + pFmt->SetFmtAttr( aHori ); + } + } + + SetModified(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx new file mode 100644 index 000000000000..26521624abb7 --- /dev/null +++ b/sw/source/core/docnode/node.cxx @@ -0,0 +1,2028 @@ +/* -*- 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_sw.hxx" + +#include <hintids.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/protitem.hxx> +#include <com/sun/star/i18n/CharacterIteratorMode.hdl> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <txtftn.hxx> +#include <ftnfrm.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <node.hxx> +#include <ndindex.hxx> +#include <numrule.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <swcache.hxx> +#include <section.hxx> +#include <cntfrm.hxx> +#include <flyfrm.hxx> +#include <txtfrm.hxx> +#include <tabfrm.hxx> // SwTabFrm +#include <viewsh.hxx> +#include <paratr.hxx> +#include <ftnidx.hxx> +#include <fmtftn.hxx> +#include <fmthdft.hxx> +#include <frmatr.hxx> +#include <fmtautofmt.hxx> +#include <frmtool.hxx> +#include <pagefrm.hxx> +#include <node2lay.hxx> +#include <pagedesc.hxx> +#include <fmtpdsc.hxx> +#include <breakit.hxx> +#include <crsskip.hxx> +#include <SwStyleNameMapper.hxx> +#include <scriptinfo.hxx> +#include <rootfrm.hxx> +#include <istyleaccess.hxx> +#include <IDocumentListItems.hxx> +#include <switerator.hxx> +#include "ndole.hxx" + +using namespace ::com::sun::star::i18n; + +TYPEINIT2( SwCntntNode, SwModify, SwIndexReg ) + +/* + * Some local helper functions for the attribute set handle of a content node. + * Since the attribute set of a content node may not be modified directly, + * we always have to create a new SwAttrSet, do the modifications, and get + * a new handle from the style access + */ + +namespace AttrSetHandleHelper +{ + +void GetNewAutoStyle( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, + SwAttrSet& rNewAttrSet ) +{ + const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(mrpAttrSet.get()); + if( rNode.GetModifyAtAttr() ) + const_cast<SwAttrSet*>(pAttrSet)->SetModifyAtAttr( 0 ); + IStyleAccess& rSA = pAttrSet->GetPool()->GetDoc()->GetIStyleAccess(); + mrpAttrSet = rSA.getAutomaticStyle( rNewAttrSet, rNode.IsTxtNode() ? + IStyleAccess::AUTO_STYLE_PARA : + IStyleAccess::AUTO_STYLE_NOTXT ); + const bool bSetModifyAtAttr = ((SwAttrSet*)mrpAttrSet.get())->SetModifyAtAttr( &rNode ); + rNode.SetModifyAtAttr( bSetModifyAtAttr ); +} + + +void SetParent( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, + const SwFmt* pParentFmt, + const SwFmt* pConditionalFmt ) +{ + const SwAttrSet* pAttrSet = static_cast<const SwAttrSet*>(mrpAttrSet.get()); + OSL_ENSURE( pAttrSet, "no SwAttrSet" ); + OSL_ENSURE( pParentFmt || !pConditionalFmt, "ConditionalFmt without ParentFmt?" ); + + const SwAttrSet* pParentSet = pParentFmt ? &pParentFmt->GetAttrSet() : 0; + + if ( pParentSet != pAttrSet->GetParent() ) + { + SwAttrSet aNewSet( *pAttrSet ); + aNewSet.SetParent( pParentSet ); + aNewSet.ClearItem( RES_FRMATR_STYLE_NAME ); + aNewSet.ClearItem( RES_FRMATR_CONDITIONAL_STYLE_NAME ); + String sVal; + + if ( pParentFmt ) + { + SwStyleNameMapper::FillProgName( pParentFmt->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); + const SfxStringItem aAnyFmtColl( RES_FRMATR_STYLE_NAME, sVal ); + aNewSet.Put( aAnyFmtColl ); + + if ( pConditionalFmt != pParentFmt ) + SwStyleNameMapper::FillProgName( pConditionalFmt->GetName(), sVal, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, sal_True ); + + const SfxStringItem aFmtColl( RES_FRMATR_CONDITIONAL_STYLE_NAME, sVal ); + aNewSet.Put( aFmtColl ); + } + + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + } +} + +const SfxPoolItem* Put( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, + const SfxPoolItem& rAttr ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + const SfxPoolItem* pRet = aNewSet.Put( rAttr ); + if ( pRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + return pRet; +} + +int Put( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, const SwCntntNode& rNode, + const SfxItemSet& rSet ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + + // --> FME 2007-4-12 #i76273# Robust: Save the style name items: + SfxItemSet* pStyleNames = 0; + if ( SFX_ITEM_SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, sal_False ) ) + { + pStyleNames = new SfxItemSet( *aNewSet.GetPool(), RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME ); + pStyleNames->Put( aNewSet ); + } + // <-- + + const int nRet = aNewSet.Put( rSet ); + + // --> FME 2007-4-12 #i76273# Robust: Save the style name items: + if ( pStyleNames ) + { + aNewSet.Put( *pStyleNames ); + delete pStyleNames; + } + // <-- + + if ( nRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + + return nRet; +} + +int Put_BC( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, const SfxPoolItem& rAttr, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + + // for a correct broadcast, we need to do a SetModifyAtAttr with the items + // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle + if( rNode.GetModifyAtAttr() ) + aNewSet.SetModifyAtAttr( &rNode ); + + const int nRet = aNewSet.Put_BC( rAttr, pOld, pNew ); + + if ( nRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + + return nRet; +} + +int Put_BC( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, const SfxItemSet& rSet, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + + // --> FME 2007-4-12 #i76273# Robust: Save the style name items: + SfxItemSet* pStyleNames = 0; + if ( SFX_ITEM_SET == rSet.GetItemState( RES_FRMATR_STYLE_NAME, sal_False ) ) + { + pStyleNames = new SfxItemSet( *aNewSet.GetPool(), RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME ); + pStyleNames->Put( aNewSet ); + } + // <-- + + // for a correct broadcast, we need to do a SetModifyAtAttr with the items + // from aNewSet. The 'regular' SetModifyAtAttr is done in GetNewAutoStyle + if( rNode.GetModifyAtAttr() ) + aNewSet.SetModifyAtAttr( &rNode ); + + const int nRet = aNewSet.Put_BC( rSet, pOld, pNew ); + + // --> FME 2007-4-12 #i76273# Robust: Save the style name items: + if ( pStyleNames ) + { + aNewSet.Put( *pStyleNames ); + delete pStyleNames; + } + // <-- + + if ( nRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + + return nRet; +} + +sal_uInt16 ClearItem_BC( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, sal_uInt16 nWhich, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + if( rNode.GetModifyAtAttr() ) + aNewSet.SetModifyAtAttr( &rNode ); + const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich, pOld, pNew ); + if ( nRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + return nRet; +} + +sal_uInt16 ClearItem_BC( boost::shared_ptr<const SfxItemSet>& mrpAttrSet, + const SwCntntNode& rNode, + sal_uInt16 nWhich1, sal_uInt16 nWhich2, + SwAttrSet* pOld, SwAttrSet* pNew ) +{ + SwAttrSet aNewSet( (SwAttrSet&)*mrpAttrSet ); + if( rNode.GetModifyAtAttr() ) + aNewSet.SetModifyAtAttr( &rNode ); + const sal_uInt16 nRet = aNewSet.ClearItem_BC( nWhich1, nWhich2, pOld, pNew ); + if ( nRet ) + GetNewAutoStyle( mrpAttrSet, rNode, aNewSet ); + return nRet; +} + +} + +/******************************************************************* +|* +|* SwNode::GetSectionLevel +|* +|* Beschreibung +|* Die Funktion liefert den Sectionlevel an der durch +|* aIndex bezeichneten Position. +|* +|* Die Logik ist wie folgt: ( S -> Start, E -> End, C -> CntntNode) +|* Level 0 E +|* 1 S E +|* 2 SC +|* +|* alle EndNodes der GrundSection haben den Level 0 +|* alle StartNodes der GrundSection haben den Level 1 +|* +*******************************************************************/ + + +sal_uInt16 SwNode::GetSectionLevel() const +{ + // EndNode einer Grund-Section ?? diese sind immer 0 !! + if( IsEndNode() && 0 == pStartOfSection->StartOfSectionIndex() ) + return 0; + + sal_uInt16 nLevel; + const SwNode* pNode = IsStartNode() ? this : pStartOfSection; + for( nLevel = 1; 0 != pNode->StartOfSectionIndex(); ++nLevel ) + pNode = pNode->pStartOfSection; + return IsEndNode() ? nLevel-1 : nLevel; +} + +/******************************************************************* +|* +|* SwNode::SwNode +|* +|* Beschreibung +|* Konstruktor; dieser fuegt einen Node in das Array rNodes +|* an der Position rWhere ein. Dieser bekommt als +|* theEndOfSection den EndOfSection-Index des Nodes +|* unmittelbar vor ihm. Falls er sich an der Position 0 +|* innerhalb des variablen Arrays befindet, wird +|* theEndOfSection 0 (der neue selbst). +|* +|* Parameter +|* IN +|* rNodes bezeichnet das variable Array, in das der Node +|* eingefuegt werden soll +|* IN +|* rWhere bezeichnet die Position innerhalb dieses Arrays, +|* an der der Node eingefuegt werden soll +|* +*******************************************************************/ + +#if OSL_DEBUG_LEVEL > 1 +long SwNode::nSerial = 0; +#endif + +SwNode::SwNode( const SwNodeIndex &rWhere, const sal_uInt8 nNdType ) + : nNodeType( nNdType ), pStartOfSection( 0 ) +{ + bSetNumLSpace = bIgnoreDontExpand = sal_False; + nAFmtNumLvl = 0; + + SwNodes& rNodes = (SwNodes&)rWhere.GetNodes(); + SwNode* pInsNd = this; // der MAC kann this nicht einfuegen !! + if( rWhere.GetIndex() ) + { + SwNode* pNd = rNodes[ rWhere.GetIndex() -1 ]; + rNodes.InsertNode( pInsNd, rWhere ); + if( 0 == ( pStartOfSection = pNd->GetStartNode()) ) + { + pStartOfSection = pNd->pStartOfSection; + if( pNd->GetEndNode() ) // EndNode ? Section ueberspringen! + { + pNd = pStartOfSection; + pStartOfSection = pNd->pStartOfSection; + } + } + } + else + { + rNodes.InsertNode( pInsNd, rWhere ); + pStartOfSection = (SwStartNode*)this; + } + +#if OSL_DEBUG_LEVEL > 1 + nMySerial = nSerial; + nSerial++; +#endif +} + +SwNode::SwNode( SwNodes& rNodes, sal_uLong nPos, const sal_uInt8 nNdType ) + : nNodeType( nNdType ), pStartOfSection( 0 ) +{ + bSetNumLSpace = bIgnoreDontExpand = sal_False; + nAFmtNumLvl = 0; + + SwNode* pInsNd = this; // der MAC kann this nicht einfuegen !! + if( nPos ) + { + SwNode* pNd = rNodes[ nPos - 1 ]; + rNodes.InsertNode( pInsNd, nPos ); + if( 0 == ( pStartOfSection = pNd->GetStartNode()) ) + { + pStartOfSection = pNd->pStartOfSection; + if( pNd->GetEndNode() ) // EndNode ? Section ueberspringen! + { + pNd = pStartOfSection; + pStartOfSection = pNd->pStartOfSection; + } + } + } + else + { + rNodes.InsertNode( pInsNd, nPos ); + pStartOfSection = (SwStartNode*)this; + } + +#if OSL_DEBUG_LEVEL > 1 + nMySerial = nSerial; + nSerial++; +#endif +} + +SwNode::~SwNode() +{ +} + +// suche den TabellenNode, in dem dieser steht. Wenn in keiner +// Tabelle wird 0 returnt. + + +SwTableNode* SwNode::FindTableNode() +{ + if( IsTableNode() ) + return GetTableNode(); + SwStartNode* pTmp = pStartOfSection; + while( !pTmp->IsTableNode() && pTmp->GetIndex() ) +#if defined( ALPHA ) && defined( UNX ) + pTmp = ((SwNode*)pTmp)->pStartOfSection; +#else + pTmp = pTmp->pStartOfSection; +#endif + return pTmp->GetTableNode(); +} + + +// liegt der Node im Sichtbarenbereich der Shell ? +sal_Bool SwNode::IsInVisibleArea( ViewShell* pSh ) const +{ + sal_Bool bRet = sal_False; + const SwCntntNode* pNd; + + if( ND_STARTNODE & nNodeType ) + { + SwNodeIndex aIdx( *this ); + pNd = GetNodes().GoNext( &aIdx ); + } + else if( ND_ENDNODE & nNodeType ) + { + SwNodeIndex aIdx( *EndOfSectionNode() ); + pNd = GetNodes().GoPrevious( &aIdx ); + } + else + pNd = GetCntntNode(); + + if( !pSh ) + // dann die Shell vom Doc besorgen: + GetDoc()->GetEditShell( &pSh ); + + if( pSh ) + { + const SwFrm* pFrm; + if( pNd && 0 != ( pFrm = pNd->getLayoutFrm( pSh->GetLayout(), 0, 0, sal_False ) ) ) + { + + if ( pFrm->IsInTab() ) + pFrm = pFrm->FindTabFrm(); + + if( !pFrm->IsValid() ) + do + { pFrm = pFrm->FindPrev(); + } while ( pFrm && !pFrm->IsValid() ); + + if( !pFrm || pSh->VisArea().IsOver( pFrm->Frm() ) ) + bRet = sal_True; + } + } + + return bRet; +} + +sal_Bool SwNode::IsInProtectSect() const +{ + const SwNode* pNd = ND_SECTIONNODE == nNodeType ? pStartOfSection : this; + const SwSectionNode* pSectNd = pNd->FindSectionNode(); + return pSectNd && pSectNd->GetSection().IsProtectFlag(); +} + + // befindet sich der Node in irgendetwas geschuetzten ? + // (Bereich/Rahmen/Tabellenzellen/... incl. des Ankers bei + // Rahmen/Fussnoten/..) +sal_Bool SwNode::IsProtect() const +{ + const SwNode* pNd = ND_SECTIONNODE == nNodeType ? pStartOfSection : this; + const SwStartNode* pSttNd = pNd->FindSectionNode(); + if( pSttNd && ((SwSectionNode*)pSttNd)->GetSection().IsProtectFlag() ) + return sal_True; + + if( 0 != ( pSttNd = FindTableBoxStartNode() ) ) + { + SwCntntFrm* pCFrm; + if( IsCntntNode() && 0 != (pCFrm = ((SwCntntNode*)this)->getLayoutFrm( GetDoc()->GetCurrentLayout() ) )) + return pCFrm->IsProtected(); + + const SwTableBox* pBox = pSttNd->FindTableNode()->GetTable(). + GetTblBox( pSttNd->GetIndex() ); + //Robust #149568 + if( pBox && pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + return sal_True; + } + + SwFrmFmt* pFlyFmt = GetFlyFmt(); + if( pFlyFmt ) + { + if( pFlyFmt->GetProtect().IsCntntProtected() ) + return sal_True; + const SwFmtAnchor& rAnchor = pFlyFmt->GetAnchor(); + return rAnchor.GetCntntAnchor() + ? rAnchor.GetCntntAnchor()->nNode.GetNode().IsProtect() + : sal_False; + } + + if( 0 != ( pSttNd = FindFootnoteStartNode() ) ) + { + const SwTxtFtn* pTFtn = GetDoc()->GetFtnIdxs().SeekEntry( + SwNodeIndex( *pSttNd ) ); + if( pTFtn ) + return pTFtn->GetTxtNode().IsProtect(); + } + + return sal_False; +} + + // suche den PageDesc, mit dem dieser Node formatiert ist. Wenn das + // Layout vorhanden ist wird ueber das gesucht, ansonsten gibt es nur + // die harte Tour ueber die Nodes nach vorne suchen!! +const SwPageDesc* SwNode::FindPageDesc( sal_Bool bCalcLay, + sal_uInt32* pPgDescNdIdx ) const +{ + if ( !GetNodes().IsDocNodes() ) + { + return 0; + } + + const SwPageDesc* pPgDesc = 0; + + const SwCntntNode* pNode; + if( ND_STARTNODE & nNodeType ) + { + SwNodeIndex aIdx( *this ); + pNode = GetNodes().GoNext( &aIdx ); + } + else if( ND_ENDNODE & nNodeType ) + { + SwNodeIndex aIdx( *EndOfSectionNode() ); + pNode = GetNodes().GoPrevious( &aIdx ); + } + else + { + pNode = GetCntntNode(); + if( pNode ) + pPgDesc = ((SwFmtPageDesc&)pNode->GetAttr( RES_PAGEDESC )).GetPageDesc(); + } + + // geht es uebers Layout? + if( !pPgDesc ) + { + const SwFrm* pFrm; + const SwPageFrm* pPage; + if( pNode && 0 != ( pFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout(), 0, 0, bCalcLay ) ) && + 0 != ( pPage = pFrm->FindPageFrm() ) ) + { + pPgDesc = pPage->GetPageDesc(); + if ( pPgDescNdIdx ) + { + *pPgDescNdIdx = pNode->GetIndex(); + } + } + } + + if( !pPgDesc ) + { + // dann also uebers Nodes-Array + const SwDoc* pDoc = GetDoc(); + const SwNode* pNd = this; + const SwStartNode* pSttNd; + if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() && + 0 != ( pSttNd = pNd->FindFlyStartNode() ) ) + { + // dann erstmal den richtigen Anker finden + const SwFrmFmt* pFmt = 0; + const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts(); + sal_uInt16 n; + + for( n = 0; n < rFmts.Count(); ++n ) + { + SwFrmFmt* pFrmFmt = rFmts[ n ]; + const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() && + &rCntnt.GetCntntIdx()->GetNode() == (SwNode*)pSttNd ) + { + pFmt = pFrmFmt; + break; + } + } + + if( pFmt ) + { + const SwFmtAnchor* pAnchor = &pFmt->GetAnchor(); + if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && + pAnchor->GetCntntAnchor() ) + { + pNd = &pAnchor->GetCntntAnchor()->nNode.GetNode(); + const SwNode* pFlyNd = pNd->FindFlyStartNode(); + while( pFlyNd ) + { + // dann ueber den Anker nach oben "hangeln" + for( n = 0; n < rFmts.Count(); ++n ) + { + const SwFrmFmt* pFrmFmt = rFmts[ n ]; + const SwNodeIndex* pIdx = pFrmFmt->GetCntnt(). + GetCntntIdx(); + if( pIdx && pFlyNd == &pIdx->GetNode() ) + { + if( pFmt == pFrmFmt ) + { + pNd = pFlyNd; + pFlyNd = 0; + break; + } + pAnchor = &pFrmFmt->GetAnchor(); + if ((FLY_AT_PAGE == pAnchor->GetAnchorId()) || + !pAnchor->GetCntntAnchor() ) + { + pFlyNd = 0; + break; + } + + pFlyNd = pAnchor->GetCntntAnchor()->nNode. + GetNode().FindFlyStartNode(); + break; + } + } + if( n >= rFmts.Count() ) + { + OSL_ENSURE( !this, "Fly-Section aber kein Format gefunden" ); + return sal_False; + } + } + } + } + // in pNd sollte jetzt der richtige Anker Node stehen oder + // immer noch der this + } + + if( pNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) + { + if( pNd->GetIndex() > GetNodes().GetEndOfAutotext().GetIndex() ) + { + pPgDesc = &pDoc->GetPageDesc( 0 ); + pNd = 0; + } + else + { + // suche den Body Textnode + if( 0 != ( pSttNd = pNd->FindHeaderStartNode() ) || + 0 != ( pSttNd = pNd->FindFooterStartNode() )) + { + // dann in den PageDescs diesen StartNode suchen + sal_uInt16 nId; + UseOnPage eAskUse; + if( SwHeaderStartNode == pSttNd->GetStartNodeType()) + { + nId = RES_HEADER; + eAskUse = nsUseOnPage::PD_HEADERSHARE; + } + else + { + nId = RES_FOOTER; + eAskUse = nsUseOnPage::PD_FOOTERSHARE; + } + + for( sal_uInt16 n = pDoc->GetPageDescCnt(); n && !pPgDesc; ) + { + const SwPageDesc& rPgDsc = pDoc->GetPageDesc( --n ); + const SwFrmFmt* pFmt = &rPgDsc.GetMaster(); + int nStt = 0, nLast = 1; + if( !( eAskUse & rPgDsc.ReadUseOn() )) ++nLast; + + for( ; nStt < nLast; ++nStt, pFmt = &rPgDsc.GetLeft() ) + { + const SwFmtHeader& rHdFt = (SwFmtHeader&) + pFmt->GetFmtAttr( nId ); + if( rHdFt.GetHeaderFmt() ) + { + const SwFmtCntnt& rCntnt = + rHdFt.GetHeaderFmt()->GetCntnt(); + if( rCntnt.GetCntntIdx() && + &rCntnt.GetCntntIdx()->GetNode() == + (SwNode*)pSttNd ) + { + pPgDesc = &rPgDsc; + break; + } + } + } + } + + if( !pPgDesc ) + pPgDesc = &pDoc->GetPageDesc( 0 ); + pNd = 0; + } + else if( 0 != ( pSttNd = pNd->FindFootnoteStartNode() )) + { + // der Anker kann nur im Bodytext sein + const SwTxtFtn* pTxtFtn; + const SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs(); + for( sal_uInt16 n = 0; n < rFtnArr.Count(); ++n ) + if( 0 != ( pTxtFtn = rFtnArr[ n ])->GetStartNode() && + (SwNode*)pSttNd == + &pTxtFtn->GetStartNode()->GetNode() ) + { + pNd = &pTxtFtn->GetTxtNode(); + break; + } + } + else + { + // kann jetzt nur noch ein Seitengebundener Fly sein + // oder irgendetwas neueres. + // Hier koennen wir nur noch den Standard returnen + OSL_ENSURE( pNd->FindFlyStartNode(), + "wo befindet sich dieser Node?" ); + + pPgDesc = &pDoc->GetPageDesc( 0 ); + pNd = 0; + } + } + } + + if( pNd ) + { + SwFindNearestNode aInfo( *pNd ); + // dann ueber alle Nodes aller PageDesc + const SfxPoolItem* pItem; + sal_uInt32 i, nMaxItems = pDoc->GetAttrPool().GetItemCount2( RES_PAGEDESC ); + for( i = 0; i < nMaxItems; ++i ) + if( 0 != (pItem = pDoc->GetAttrPool().GetItem2( RES_PAGEDESC, i ) ) && + ((SwFmtPageDesc*)pItem)->GetDefinedIn() ) + { + const SwModify* pMod = ((SwFmtPageDesc*)pItem)->GetDefinedIn(); + if( pMod->ISA( SwCntntNode ) ) + aInfo.CheckNode( *(SwCntntNode*)pMod ); + else if( pMod->ISA( SwFmt )) + ((SwFmt*)pMod)->GetInfo( aInfo ); + } + + if( 0 != ( pNd = aInfo.GetFoundNode() )) + { + if( pNd->IsCntntNode() ) + pPgDesc = ((SwFmtPageDesc&)pNd->GetCntntNode()-> + GetAttr( RES_PAGEDESC )).GetPageDesc(); + else if( pNd->IsTableNode() ) + pPgDesc = pNd->GetTableNode()->GetTable(). + GetFrmFmt()->GetPageDesc().GetPageDesc(); + else if( pNd->IsSectionNode() ) + pPgDesc = pNd->GetSectionNode()->GetSection(). + GetFmt()->GetPageDesc().GetPageDesc(); + if ( pPgDescNdIdx ) + { + *pPgDescNdIdx = pNd->GetIndex(); + } + } + if( !pPgDesc ) + pPgDesc = &pDoc->GetPageDesc( 0 ); + } + } + return pPgDesc; +} + + + // falls der Node in einem Fly steht, dann wird das entsprechende Format + // returnt +SwFrmFmt* SwNode::GetFlyFmt() const +{ + SwFrmFmt* pRet = 0; + const SwNode* pSttNd = FindFlyStartNode(); + if( pSttNd ) + { + if( IsCntntNode() ) + { + SwCntntFrm* pFrm = SwIterator<SwCntntFrm,SwCntntNode>::FirstElement( *(SwCntntNode*)this ); + if( pFrm ) + pRet = pFrm->FindFlyFrm()->GetFmt(); + } + if( !pRet ) + { + // dann gibts noch harten steinigen Weg uebers Dokument: + const SwSpzFrmFmts& rFrmFmtTbl = *GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n ) + { + SwFrmFmt* pFmt = rFrmFmtTbl[n]; + const SwFmtCntnt& rCntnt = pFmt->GetCntnt(); + if( rCntnt.GetCntntIdx() && + &rCntnt.GetCntntIdx()->GetNode() == pSttNd ) + { + pRet = pFmt; + break; + } + } + } + } + return pRet; +} + +SwTableBox* SwNode::GetTblBox() const +{ + SwTableBox* pBox = 0; + const SwNode* pSttNd = FindTableBoxStartNode(); + if( pSttNd ) + pBox = (SwTableBox*)pSttNd->FindTableNode()->GetTable().GetTblBox( + pSttNd->GetIndex() ); + return pBox; +} + +SwStartNode* SwNode::FindSttNodeByType( SwStartNodeType eTyp ) +{ + SwStartNode* pTmp = IsStartNode() ? (SwStartNode*)this : pStartOfSection; + + while( eTyp != pTmp->GetStartNodeType() && pTmp->GetIndex() ) +#if defined( ALPHA ) && defined( UNX ) + pTmp = ((SwNode*)pTmp)->pStartOfSection; +#else + pTmp = pTmp->pStartOfSection; +#endif + return eTyp == pTmp->GetStartNodeType() ? pTmp : 0; +} + +const SwTxtNode* SwNode::FindOutlineNodeOfLevel( sal_uInt8 nLvl ) const +{ + const SwTxtNode* pRet = 0; + const SwOutlineNodes& rONds = GetNodes().GetOutLineNds(); + if( MAXLEVEL > nLvl && rONds.Count() ) + { + sal_uInt16 nPos; + SwNode* pNd = (SwNode*)this; + sal_Bool bCheckFirst = sal_False; + if( !rONds.Seek_Entry( pNd, &nPos )) + { + if( nPos ) + nPos = nPos-1; + else + bCheckFirst = sal_True; + } + + if( bCheckFirst ) + { + // der 1.GliederungsNode liegt hinter dem Fragenden. Dann + // teste mal, ob dieser auf der gleichen Seite steht. Wenn + // nicht, ist das ein ungueltiger. Bug 61865 + pRet = rONds[0]->GetTxtNode(); + + const SwCntntNode* pCNd = GetCntntNode(); + + Point aPt( 0, 0 ); + const SwFrm* pFrm = pRet->getLayoutFrm( pRet->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False ), + * pMyFrm = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False ) : 0; + const SwPageFrm* pPgFrm = pFrm ? pFrm->FindPageFrm() : 0; + if( pPgFrm && pMyFrm && + pPgFrm->Frm().Top() > pMyFrm->Frm().Top() ) + { + // der Fragende liegt vor der Seite, also ist er ungueltig + pRet = 0; + } + } + else + { + // oder ans Feld und von dort holen !! + while( nPos && + nLvl < ( pRet = rONds[nPos]->GetTxtNode() ) + ->GetAttrOutlineLevel() - 1 ) //<-end,zhaojianwei + --nPos; + + if( !nPos ) // bei 0 gesondert holen !! + pRet = rONds[0]->GetTxtNode(); + } + } + return pRet; +} + +inline sal_Bool IsValidNextPrevNd( const SwNode& rNd ) +{ + return ND_TABLENODE == rNd.GetNodeType() || + ( ND_CONTENTNODE & rNd.GetNodeType() ) || + ( ND_ENDNODE == rNd.GetNodeType() && rNd.StartOfSectionNode() && + ND_TABLENODE == rNd.StartOfSectionNode()->GetNodeType() ); +} + +sal_uInt8 SwNode::HasPrevNextLayNode() const +{ + // assumption: <this> node is a node inside the document nodes array section. + + sal_uInt8 nRet = 0; + if( IsValidNextPrevNd( *this )) + { + SwNodeIndex aIdx( *this, -1 ); + // #i77805# - skip section start and end nodes + while ( aIdx.GetNode().IsSectionNode() || + ( aIdx.GetNode().IsEndNode() && + aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) ) + { + --aIdx; + } + // <-- + if( IsValidNextPrevNd( aIdx.GetNode() )) + nRet |= ND_HAS_PREV_LAYNODE; + // #i77805# - skip section start and end nodes + aIdx = SwNodeIndex( *this, +1 ); + while ( aIdx.GetNode().IsSectionNode() || + ( aIdx.GetNode().IsEndNode() && + aIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) ) + { + ++aIdx; + } + if( IsValidNextPrevNd( aIdx.GetNode() )) + nRet |= ND_HAS_NEXT_LAYNODE; + } + return nRet; +} + +/******************************************************************* +|* +|* SwNode::StartOfSection +|* +|* Beschreibung +|* Die Funktion liefert die StartOfSection des Nodes. +|* +|* Parameter +|* IN +|* rNodes bezeichnet das variable Array, in dem sich der Node +|* befindet +|* +*******************************************************************/ + + +SwStartNode::SwStartNode( const SwNodeIndex &rWhere, const sal_uInt8 nNdType, + SwStartNodeType eSttNd ) + : SwNode( rWhere, nNdType ), eSttNdTyp( eSttNd ) +{ + // erstmal temporaer, bis der EndNode eingefuegt wird. + pEndOfSection = (SwEndNode*)this; +} + +SwStartNode::SwStartNode( SwNodes& rNodes, sal_uLong nPos ) + : SwNode( rNodes, nPos, ND_STARTNODE ), eSttNdTyp( SwNormalStartNode ) +{ + // erstmal temporaer, bis der EndNode eingefuegt wird. + pEndOfSection = (SwEndNode*)this; +} + + +void SwStartNode::CheckSectionCondColl() const +{ +//FEATURE::CONDCOLL + SwNodeIndex aIdx( *this ); + sal_uLong nEndIdx = EndOfSectionIndex(); + const SwNodes& rNds = GetNodes(); + SwCntntNode* pCNd; + while( 0 != ( pCNd = rNds.GoNext( &aIdx )) && pCNd->GetIndex() < nEndIdx ) + pCNd->ChkCondColl(); +//FEATURE::CONDCOLL +} + +/******************************************************************* +|* +|* SwEndNode::SwEndNode +|* +|* Beschreibung +|* Konstruktor; dieser fuegt einen Node in das Array rNodes +|* an der Position aWhere ein. Der +|* theStartOfSection-Pointer wird entsprechend gesetzt, +|* und der EndOfSection-Pointer des zugehoerigen +|* Startnodes -- durch rStartOfSection bezeichnet -- +|* wird auf diesen Node gesetzt. +|* +|* Parameter +|* IN +|* rNodes bezeichnet das variable Array, in das der Node +|* eingefuegt werden soll +|* IN +|* aWhere bezeichnet die Position innerhalb dieses Arrays, +|* an der der Node eingefuegt werden soll +|* !!!!!!!!!!!! +|* Es wird eine Kopie uebergeben! +|* +*******************************************************************/ + + +SwEndNode::SwEndNode( const SwNodeIndex &rWhere, SwStartNode& rSttNd ) + : SwNode( rWhere, ND_ENDNODE ) +{ + pStartOfSection = &rSttNd; + pStartOfSection->pEndOfSection = this; +} + +SwEndNode::SwEndNode( SwNodes& rNds, sal_uLong nPos, SwStartNode& rSttNd ) + : SwNode( rNds, nPos, ND_ENDNODE ) +{ + pStartOfSection = &rSttNd; + pStartOfSection->pEndOfSection = this; +} + + + +// -------------------- +// SwCntntNode +// -------------------- + + +SwCntntNode::SwCntntNode( const SwNodeIndex &rWhere, const sal_uInt8 nNdType, + SwFmtColl *pColl ) + : SwModify( pColl ), // CrsrsShell, FrameFmt, + SwNode( rWhere, nNdType ), + pCondColl( 0 ), + mbSetModifyAtAttr( false ) +{ +} + + +SwCntntNode::~SwCntntNode() +{ + // Die Basisklasse SwClient vom SwFrm nimmt sich aus + // der Abhaengikeitsliste raus! + // Daher muessen alle Frames in der Abhaengigkeitsliste geloescht werden. + if( GetDepends() ) + DelFrms(); + + if( pCondColl ) + delete pCondColl; + + if ( mpAttrSet.get() && mbSetModifyAtAttr ) + ((SwAttrSet*)mpAttrSet.get())->SetModifyAtAttr( 0 ); +} + +void SwCntntNode::Modify( const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue ) +{ + sal_uInt16 nWhich = pOldValue ? pOldValue->Which() : + pNewValue ? pNewValue->Which() : 0 ; + + switch( nWhich ) + { + case RES_OBJECTDYING : + { + SwFmt * pFmt = (SwFmt *) ((SwPtrMsgPoolItem *)pNewValue)->pObject; + + // nicht umhaengen wenn dieses das oberste Format ist !! + if( GetRegisteredIn() == pFmt ) + { + if( pFmt->GetRegisteredIn() ) + { + // wenn Parent, dann im neuen Parent wieder anmelden + ((SwModify*)pFmt->GetRegisteredIn())->Add( this ); + if ( GetpSwAttrSet() ) + AttrSetHandleHelper::SetParent( mpAttrSet, *this, GetFmtColl(), GetFmtColl() ); + } + else + { + // sonst auf jeden Fall beim sterbenden abmelden + ((SwModify*)GetRegisteredIn())->Remove( this ); + if ( GetpSwAttrSet() ) + AttrSetHandleHelper::SetParent( mpAttrSet, *this, 0, 0 ); + } + } + } + break; + + + case RES_FMT_CHG: + // falls mein Format Parent umgesetzt wird, dann melde ich + // meinen Attrset beim Neuen an. + + // sein eigenes Modify ueberspringen !! + if( GetpSwAttrSet() && + ((SwFmtChg*)pNewValue)->pChangedFmt == GetRegisteredIn() ) + { + // den Set an den neuen Parent haengen + AttrSetHandleHelper::SetParent( mpAttrSet, *this, GetFmtColl(), GetFmtColl() ); + } + break; +//FEATURE::CONDCOLL + case RES_CONDCOLL_CONDCHG: + if( ((SwCondCollCondChg*)pNewValue)->pChangedFmt == GetRegisteredIn() && + &GetNodes() == &GetDoc()->GetNodes() ) + { + ChkCondColl(); + } + return ; // nicht an die Basisklasse / Frames weitergeben +//FEATURE::CONDCOLL + + case RES_ATTRSET_CHG: + if( GetNodes().IsDocNodes() && IsTxtNode() ) + { + if( SFX_ITEM_SET == ((SwAttrSetChg*)pOldValue)->GetChgSet()->GetItemState( + RES_CHRATR_HIDDEN, sal_False ) ) + { + ((SwTxtNode*)this)->SetCalcHiddenCharFlags(); + } + } + break; + + case RES_UPDATE_ATTR: + if( GetNodes().IsDocNodes() && IsTxtNode() ) + { + const sal_uInt16 nTmp = ((SwUpdateAttr*)pNewValue)->nWhichAttr; + if ( RES_ATTRSET_CHG == nTmp ) + { + // anybody wants to do some optimization here? + ((SwTxtNode*)this)->SetCalcHiddenCharFlags(); + } + } + break; + } + + NotifyClients( pOldValue, pNewValue ); +} + +sal_Bool SwCntntNode::InvalidateNumRule() +{ + SwNumRule* pRule = 0; + const SfxPoolItem* pItem; + if( GetNodes().IsDocNodes() && + 0 != ( pItem = GetNoCondAttr( RES_PARATR_NUMRULE, sal_True )) && + ((SwNumRuleItem*)pItem)->GetValue().Len() && + 0 != (pRule = GetDoc()->FindNumRulePtr( + ((SwNumRuleItem*)pItem)->GetValue() ) ) ) + { + pRule->SetInvalidRule( sal_True ); + } + return 0 != pRule; +} + +SwCntntFrm *SwCntntNode::getLayoutFrm( const SwRootFrm* _pRoot, + const Point* pPoint, const SwPosition *pPos, const sal_Bool bCalcFrm ) const +{ + return (SwCntntFrm*) ::GetFrmOfModify( _pRoot, *(SwModify*)this, FRM_CNTNT, + pPoint, pPos, bCalcFrm ); +} + +SwRect SwCntntNode::FindLayoutRect( const sal_Bool bPrtArea, const Point* pPoint, + const sal_Bool bCalcFrm ) const +{ + SwRect aRet; + SwCntntFrm* pFrm = (SwCntntFrm*)::GetFrmOfModify( 0, *(SwModify*)this, + FRM_CNTNT, pPoint, 0, bCalcFrm ); + if( pFrm ) + aRet = bPrtArea ? pFrm->Prt() : pFrm->Frm(); + return aRet; +} + +SwRect SwCntntNode::FindPageFrmRect( const sal_Bool bPrtArea, const Point* pPoint, + const sal_Bool bCalcFrm ) const +{ + SwRect aRet; + SwFrm* pFrm = ::GetFrmOfModify( 0, *(SwModify*)this, + FRM_CNTNT, pPoint, 0, bCalcFrm ); + if( pFrm && 0 != ( pFrm = pFrm->FindPageFrm() )) + aRet = bPrtArea ? pFrm->Prt() : pFrm->Frm(); + return aRet; +} + +xub_StrLen SwCntntNode::Len() const { return 0; } + + + +SwFmtColl *SwCntntNode::ChgFmtColl( SwFmtColl *pNewColl ) +{ + OSL_ENSURE( pNewColl, "Collectionpointer ist 0." ); + SwFmtColl *pOldColl = GetFmtColl(); + + if( pNewColl != pOldColl ) + { + pNewColl->Add( this ); + + // setze den Parent von unseren Auto-Attributen auf die neue + // Collection: + if( GetpSwAttrSet() ) + AttrSetHandleHelper::SetParent( mpAttrSet, *this, pNewColl, pNewColl ); + +//FEATURE::CONDCOLL + // HACK: hier muss die entsprechend der neuen Vorlage die Bedingungen + // neu ueberprueft werden! + if( sal_True /*pNewColl */ ) + { + SetCondFmtColl( 0 ); + } +//FEATURE::CONDCOLL + + if( !IsModifyLocked() ) + { + SwFmtChg aTmp1( pOldColl ); + SwFmtChg aTmp2( pNewColl ); + SwCntntNode::Modify( &aTmp1, &aTmp2 ); + } + } + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + return pOldColl; +} + + +sal_Bool SwCntntNode::GoNext(SwIndex * pIdx, sal_uInt16 nMode ) const +{ + sal_Bool bRet = sal_True; + if( pIdx->GetIndex() < Len() ) + { + if( !IsTxtNode() ) + (*pIdx)++; + else + { + const SwTxtNode& rTNd = *GetTxtNode(); + xub_StrLen nPos = pIdx->GetIndex(); + if( pBreakIt->GetBreakIter().is() ) + { + sal_Int32 nDone = 0; + sal_uInt16 nItrMode = ( CRSR_SKIP_CELLS & nMode ) ? + CharacterIteratorMode::SKIPCELL : + CharacterIteratorMode::SKIPCONTROLCHARACTER; + nPos = (xub_StrLen)pBreakIt->GetBreakIter()->nextCharacters( rTNd.GetTxt(), nPos, + pBreakIt->GetLocale( rTNd.GetLang( nPos ) ), + nItrMode, 1, nDone ); + + // Check if nPos is inside hidden text range: + if ( CRSR_SKIP_HIDDEN & nMode ) + { + xub_StrLen nHiddenStart; + xub_StrLen nHiddenEnd; + SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd ); + if ( nHiddenStart != STRING_LEN && nHiddenStart != nPos ) + nPos = nHiddenEnd; + } + + if( 1 == nDone ) + *pIdx = nPos; + else + bRet = sal_False; + } + else if( nPos < rTNd.GetTxt().Len() ) + (*pIdx)++; + else + bRet = sal_False; + } + } + else + bRet = sal_False; + return bRet; +} + + +sal_Bool SwCntntNode::GoPrevious(SwIndex * pIdx, sal_uInt16 nMode ) const +{ + sal_Bool bRet = sal_True; + if( pIdx->GetIndex() > 0 ) + { + if( !IsTxtNode() ) + (*pIdx)--; + else + { + const SwTxtNode& rTNd = *GetTxtNode(); + xub_StrLen nPos = pIdx->GetIndex(); + if( pBreakIt->GetBreakIter().is() ) + { + sal_Int32 nDone = 0; + sal_uInt16 nItrMode = ( CRSR_SKIP_CELLS & nMode ) ? + CharacterIteratorMode::SKIPCELL : + CharacterIteratorMode::SKIPCONTROLCHARACTER; + nPos = (xub_StrLen)pBreakIt->GetBreakIter()->previousCharacters( rTNd.GetTxt(), nPos, + pBreakIt->GetLocale( rTNd.GetLang( nPos ) ), + nItrMode, 1, nDone ); + + // Check if nPos is inside hidden text range: + if ( CRSR_SKIP_HIDDEN & nMode ) + { + xub_StrLen nHiddenStart; + xub_StrLen nHiddenEnd; + SwScriptInfo::GetBoundsOfHiddenRange( rTNd, nPos, nHiddenStart, nHiddenEnd ); + if ( nHiddenStart != STRING_LEN ) + nPos = nHiddenStart; + } + + if( 1 == nDone ) + *pIdx = nPos; + else + bRet = sal_False; + } + else if( nPos ) + (*pIdx)--; + else + bRet = sal_False; + } + } + else + bRet = sal_False; + return bRet; +} + + +/* + * Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom + * Dokument. Die erzeugten Contentframes werden in das entsprechende + * Layout gehaengt. + */ + + +void SwCntntNode::MakeFrms( SwCntntNode& rNode ) +{ + OSL_ENSURE( &rNode != this, + "Kein Contentnode oder Copy-Node und neuer Node identisch." ); + + if( !GetDepends() || &rNode == this ) // gibt es ueberhaupt Frames ?? + return; + + SwFrm *pFrm, *pNew; + SwLayoutFrm *pUpper; + // Frames anlegen fuer Nodes, die vor oder hinter der Tabelle stehen ?? + OSL_ENSURE( FindTableNode() == rNode.FindTableNode(), "Table confusion" ); + + SwNode2Layout aNode2Layout( *this, rNode.GetIndex() ); + + while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, rNode )) ) + { + pNew = rNode.MakeFrm( pUpper ); + pNew->Paste( pUpper, pFrm ); + // #i27138# + // notify accessibility paragraphs objects about changed + // CONTENT_FLOWS_FROM/_TO relation. + // Relation CONTENT_FLOWS_FROM for next paragraph will change + // and relation CONTENT_FLOWS_TO for previous paragraph will change. + if ( pNew->IsTxtFrm() ) + { + ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); + if ( pViewShell && pViewShell->GetLayout() && + pViewShell->GetLayout()->IsAnyShellAccessible() ) + { + pViewShell->InvalidateAccessibleParaFlowRelation( + dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), + dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) ); + } + } + // <-- + } +} + +/* + * Methode loescht fuer den Node alle Ansichten vom + * Dokument. Die Contentframes werden aus dem entsprechenden + * Layout ausgehaengt. + */ + + +void SwCntntNode::DelFrms() +{ + if( !GetDepends() ) + return; + + SwCntntFrm::DelFrms(*this); + if( IsTxtNode() ) + { + ((SwTxtNode*)this)->SetWrong( NULL ); + ((SwTxtNode*)this)->SetWrongDirty( true ); + + ((SwTxtNode*)this)->SetGrammarCheck( NULL ); + ((SwTxtNode*)this)->SetGrammarCheckDirty( true ); + // SMARTTAGS + ((SwTxtNode*)this)->SetSmartTags( NULL ); + ((SwTxtNode*)this)->SetSmartTagDirty( true ); + + ((SwTxtNode*)this)->SetWordCountDirty( true ); + ((SwTxtNode*)this)->SetAutoCompleteWordDirty( true ); + } +} + + +SwCntntNode *SwCntntNode::JoinNext() +{ + return this; +} + + +SwCntntNode *SwCntntNode::JoinPrev() +{ + return this; +} + + + + // erfrage vom Modify Informationen +sal_Bool SwCntntNode::GetInfo( SfxPoolItem& rInfo ) const +{ + switch( rInfo.Which() ) + { + case RES_AUTOFMT_DOCNODE: + if( &GetNodes() == ((SwAutoFmtGetDocNode&)rInfo).pNodes ) + { + ((SwAutoFmtGetDocNode&)rInfo).pCntntNode = this; + return sal_False; + } + break; + + case RES_FINDNEARESTNODE: + if( ((SwFmtPageDesc&)GetAttr( RES_PAGEDESC )).GetPageDesc() ) + ((SwFindNearestNode&)rInfo).CheckNode( *this ); + return sal_True; + + case RES_CONTENT_VISIBLE: + { + ((SwPtrMsgPoolItem&)rInfo).pObject = + SwIterator<SwFrm,SwCntntNode>::FirstElement(*this); + } + return sal_False; + } + + return SwModify::GetInfo( rInfo ); +} + + + // setze ein Attribut +sal_Bool SwCntntNode::SetAttr(const SfxPoolItem& rAttr ) +{ + if( !GetpSwAttrSet() ) // lasse von den entsprechenden Nodes die + NewAttrSet( GetDoc()->GetAttrPool() ); // AttrSets anlegen + + OSL_ENSURE( GetpSwAttrSet(), "warum wurde kein AttrSet angelegt?" ); + + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + + sal_Bool bRet = sal_False; + // wenn Modify gelockt ist, werden keine Modifies verschickt + if( IsModifyLocked() || + ( !GetDepends() && RES_PARATR_NUMRULE != rAttr.Which() )) + { + bRet = 0 != AttrSetHandleHelper::Put( mpAttrSet, *this, rAttr ); + } + else + { + SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), + aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); + if( 0 != ( bRet = 0 != AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rAttr, &aOld, &aNew ) )) + { + SwAttrSetChg aChgOld( *GetpSwAttrSet(), aOld ); + SwAttrSetChg aChgNew( *GetpSwAttrSet(), aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + } + } + return bRet; +} +#include <svl/itemiter.hxx> + +sal_Bool SwCntntNode::SetAttr( const SfxItemSet& rSet ) +{ + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + + const SfxPoolItem* pFnd = 0; + if( SFX_ITEM_SET == rSet.GetItemState( RES_AUTO_STYLE, sal_False, &pFnd ) ) + { + OSL_ENSURE( rSet.Count() == 1, "SetAutoStyle mixed with other attributes?!" ); + const SwFmtAutoFmt* pTmp = static_cast<const SwFmtAutoFmt*>(pFnd); + + // If there already is an attribute set (usually containing a numbering + // item), we have to merge the attribute of the new set into the old set: + bool bSetParent = true; + if ( GetpSwAttrSet() ) + { + bSetParent = false; + AttrSetHandleHelper::Put( mpAttrSet, *this, *pTmp->GetStyleHandle() ); + } + else + { + mpAttrSet = pTmp->GetStyleHandle(); + } + + if ( bSetParent ) + { + // If the content node has a conditional style, we have to set the + // string item containing the correct conditional style name (the + // style name property has already been set during the import!) + // In case we do not have a conditional style, we make use of the + // fact that nobody else uses the attribute set behind the handle. + // FME 2007-07-10 #i78124# If autostyle does not have a parent, + // the string is empty. + const SfxPoolItem* pNameItem = 0; + if ( 0 != GetCondFmtColl() || + SFX_ITEM_SET != mpAttrSet->GetItemState( RES_FRMATR_STYLE_NAME, sal_False, &pNameItem ) || + 0 == static_cast<const SfxStringItem*>(pNameItem)->GetValue().Len() ) + AttrSetHandleHelper::SetParent( mpAttrSet, *this, &GetAnyFmtColl(), GetFmtColl() ); + else + const_cast<SfxItemSet*>(mpAttrSet.get())->SetParent( &GetFmtColl()->GetAttrSet() ); + } + + return sal_True; + } + + if( !GetpSwAttrSet() ) // lasse von den entsprechenden Nodes die + NewAttrSet( GetDoc()->GetAttrPool() ); // AttrSets anlegen + + sal_Bool bRet = sal_False; + // wenn Modify gelockt ist, werden keine Modifies verschickt + if ( IsModifyLocked() || + ( !GetDepends() && + SFX_ITEM_SET != rSet.GetItemState( RES_PARATR_NUMRULE, sal_False ) ) ) + { + // einige Sonderbehandlungen fuer Attribute + bRet = 0 != AttrSetHandleHelper::Put( mpAttrSet, *this, rSet ); + } + else + { + SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), + aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); + if( 0 != (bRet = 0 != AttrSetHandleHelper::Put_BC( mpAttrSet, *this, rSet, &aOld, &aNew )) ) + { + // einige Sonderbehandlungen fuer Attribute + SwAttrSetChg aChgOld( *GetpSwAttrSet(), aOld ); + SwAttrSetChg aChgNew( *GetpSwAttrSet(), aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + } + } + return bRet; +} + +// Nimmt den Hint mit nWhich aus dem Delta-Array + + +sal_Bool SwCntntNode::ResetAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 ) +{ + if( !GetpSwAttrSet() ) + return sal_False; + + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + + // wenn Modify gelockt ist, werden keine Modifies verschickt + if( IsModifyLocked() ) + { + sal_uInt16 nDel = 0; + if ( !nWhich2 || nWhich2 < nWhich1 ) + { + std::vector<sal_uInt16> aClearWhichIds; + aClearWhichIds.push_back( nWhich1 ); + nDel = ClearItemsFromAttrSet( aClearWhichIds ); + } + else + nDel = AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, 0, 0 ); + + if( !GetpSwAttrSet()->Count() ) // leer, dann loeschen + mpAttrSet.reset();//DELETEZ( mpAttrSet ); + return 0 != nDel; + } + + // sollte kein gueltiger Bereich definiert sein ? + if( !nWhich2 || nWhich2 < nWhich1 ) + nWhich2 = nWhich1; // dann setze auf 1. Id, nur dieses Item + + SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), + aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); + sal_Bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, nWhich1, nWhich2, &aOld, &aNew ); + + if( bRet ) + { + SwAttrSetChg aChgOld( *GetpSwAttrSet(), aOld ); + SwAttrSetChg aChgNew( *GetpSwAttrSet(), aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + + if( !GetpSwAttrSet()->Count() ) // leer, dann loeschen + mpAttrSet.reset();//DELETEZ( mpAttrSet ); + } + return bRet; +} +sal_Bool SwCntntNode::ResetAttr( const SvUShorts& rWhichArr ) +{ + if( !GetpSwAttrSet() ) + return sal_False; + + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + + // wenn Modify gelockt ist, werden keine Modifies verschickt + sal_uInt16 nDel = 0; + if( IsModifyLocked() ) + { + std::vector<sal_uInt16> aClearWhichIds; + for( sal_uInt16 n = 0, nEnd = rWhichArr.Count(); n < nEnd; ++n ) + aClearWhichIds.push_back( rWhichArr[ n ] ); + + nDel = ClearItemsFromAttrSet( aClearWhichIds ); + } + else + { + SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), + aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); + + for( sal_uInt16 n = 0, nEnd = rWhichArr.Count(); n < nEnd; ++n ) + if( AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, rWhichArr[ n ], &aOld, &aNew )) + ++nDel; + + if( nDel ) + { + SwAttrSetChg aChgOld( *GetpSwAttrSet(), aOld ); + SwAttrSetChg aChgNew( *GetpSwAttrSet(), aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + } + } + if( !GetpSwAttrSet()->Count() ) // leer, dann loeschen + mpAttrSet.reset();//DELETEZ( mpAttrSet ); + return 0 != nDel ; +} + + +sal_uInt16 SwCntntNode::ResetAllAttr() +{ + if( !GetpSwAttrSet() ) + return 0; + + if ( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + + // wenn Modify gelockt ist, werden keine Modifies verschickt + if( IsModifyLocked() ) + { + std::vector<sal_uInt16> aClearWhichIds; + aClearWhichIds.push_back(0); + sal_uInt16 nDel = ClearItemsFromAttrSet( aClearWhichIds ); + if( !GetpSwAttrSet()->Count() ) // leer, dann loeschen + mpAttrSet.reset(); // DELETEZ( mpAttrSet ); + return nDel; + } + + SwAttrSet aOld( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ), + aNew( *GetpSwAttrSet()->GetPool(), GetpSwAttrSet()->GetRanges() ); + sal_Bool bRet = 0 != AttrSetHandleHelper::ClearItem_BC( mpAttrSet, *this, 0, &aOld, &aNew ); + + if( bRet ) + { + SwAttrSetChg aChgOld( *GetpSwAttrSet(), aOld ); + SwAttrSetChg aChgNew( *GetpSwAttrSet(), aNew ); + ModifyNotification( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + + if( !GetpSwAttrSet()->Count() ) // leer, dann loeschen + mpAttrSet.reset();//DELETEZ( mpAttrSet ); + } + return aNew.Count(); +} + + +sal_Bool SwCntntNode::GetAttr( SfxItemSet& rSet, sal_Bool bInParent ) const +{ + if( rSet.Count() ) + rSet.ClearItem(); + + const SwAttrSet& rAttrSet = GetSwAttrSet(); + if( bInParent ) + return rSet.Set( rAttrSet, sal_True ) ? sal_True : sal_False; + + rSet.Put( rAttrSet ); + return rSet.Count() ? sal_True : sal_False; +} + +sal_uInt16 SwCntntNode::ClearItemsFromAttrSet( const std::vector<sal_uInt16>& rWhichIds ) +{ + sal_uInt16 nRet = 0; + if ( 0 == rWhichIds.size() ) + return nRet; + + OSL_ENSURE( GetpSwAttrSet(), "no item set" ); + SwAttrSet aNewAttrSet( *GetpSwAttrSet() ); + for ( std::vector<sal_uInt16>::const_iterator aIter = rWhichIds.begin(); + aIter != rWhichIds.end(); + ++aIter ) + { + nRet = nRet + aNewAttrSet.ClearItem( *aIter ); + } + if ( nRet ) + AttrSetHandleHelper::GetNewAutoStyle( mpAttrSet, *this, aNewAttrSet ); + + return nRet; +} + +const SfxPoolItem* SwCntntNode::GetNoCondAttr( sal_uInt16 nWhich, + sal_Bool bInParents ) const +{ + const SfxPoolItem* pFnd = 0; + if( pCondColl && pCondColl->GetRegisteredIn() ) + { + if( !GetpSwAttrSet() || ( SFX_ITEM_SET != GetpSwAttrSet()->GetItemState( + nWhich, sal_False, &pFnd ) && bInParents )) + ((SwFmt*)GetRegisteredIn())->GetItemState( nWhich, bInParents, &pFnd ); + } + // undo change of issue #i51029# + // Note: <GetSwAttrSet()> returns <mpAttrSet>, if set, otherwise it returns + // the attribute set of the paragraph style, which is valid for the + // content node - see file <node.hxx> + else + // <-- + { + GetSwAttrSet().GetItemState( nWhich, bInParents, &pFnd ); + } + return pFnd; +} + + // koennen 2 Nodes zusammengefasst werden ? + // in pIdx kann die 2. Position returnt werden. +int SwCntntNode::CanJoinNext( SwNodeIndex* pIdx ) const +{ + const SwNodes& rNds = GetNodes(); + sal_uInt8 nNdType = GetNodeType(); + SwNodeIndex aIdx( *this, 1 ); + + const SwNode* pNd = this; + while( aIdx < rNds.Count()-1 && + (( pNd = &aIdx.GetNode())->IsSectionNode() || + ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) + aIdx++; + + if( pNd->GetNodeType() != nNdType || rNds.Count()-1 == aIdx.GetIndex() ) + return sal_False; + if( IsTxtNode() ) + { // Do not merge strings if the result exceeds the allowed string length + const SwTxtNode* pTxtNd = static_cast<const SwTxtNode*>(this); + sal_uInt64 nSum = pTxtNd->GetTxt().Len(); + pTxtNd = static_cast<const SwTxtNode*>(pNd); + nSum += pTxtNd->GetTxt().Len(); + if( nSum > STRING_LEN ) + return sal_False; + } + if( pIdx ) + *pIdx = aIdx; + return sal_True; +} + + + // koennen 2 Nodes zusammengefasst werden ? + // in pIdx kann die 2. Position returnt werden. +int SwCntntNode::CanJoinPrev( SwNodeIndex* pIdx ) const +{ + sal_uInt8 nNdType = GetNodeType(); + SwNodeIndex aIdx( *this, -1 ); + + const SwNode* pNd = this; + while( aIdx.GetIndex() && + (( pNd = &aIdx.GetNode())->IsSectionNode() || + ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() ))) + aIdx--; + + if( pNd->GetNodeType() != nNdType || 0 == aIdx.GetIndex() ) + return sal_False; + if( pIdx ) + *pIdx = aIdx; + return sal_True; +} + + +//FEATURE::CONDCOLL + + +void SwCntntNode::SetCondFmtColl( SwFmtColl* pColl ) +{ + if( (!pColl && pCondColl) || ( pColl && !pCondColl ) || + ( pColl && pColl != pCondColl->GetRegisteredIn() ) ) + { + SwFmtColl* pOldColl = GetCondFmtColl(); + delete pCondColl; + if( pColl ) + pCondColl = new SwDepend( this, pColl ); + else + pCondColl = 0; + + if( GetpSwAttrSet() ) + { + AttrSetHandleHelper::SetParent( mpAttrSet, *this, &GetAnyFmtColl(), GetFmtColl() ); + } + + if( !IsModifyLocked() ) + { + SwFmtChg aTmp1( pOldColl ? pOldColl : GetFmtColl() ); + SwFmtChg aTmp2( pColl ? pColl : GetFmtColl() ); + NotifyClients( &aTmp1, &aTmp2 ); + } + if( IsInCache() ) + { + SwFrm::GetCache().Delete( this ); + SetInCache( sal_False ); + } + } +} + + +sal_Bool SwCntntNode::IsAnyCondition( SwCollCondition& rTmp ) const +{ + const SwNodes& rNds = GetNodes(); + { + int nCond = 0; + const SwStartNode* pSttNd = StartOfSectionNode(); + while( pSttNd ) + { + switch( pSttNd->GetNodeType() ) + { + case ND_TABLENODE: nCond = PARA_IN_TABLEBODY; break; + case ND_SECTIONNODE: nCond = PARA_IN_SECTION; break; + + default: + switch( pSttNd->GetStartNodeType() ) + { + case SwTableBoxStartNode: + { + nCond = PARA_IN_TABLEBODY; + const SwTableNode* pTblNd = pSttNd->FindTableNode(); + const SwTableBox* pBox; + if( pTblNd && 0 != ( pBox = pTblNd->GetTable(). + GetTblBox( pSttNd->GetIndex() ) ) && pBox && + pBox->IsInHeadline( &pTblNd->GetTable() ) ) + nCond = PARA_IN_TABLEHEAD; + } + break; + case SwFlyStartNode: nCond = PARA_IN_FRAME; break; + case SwFootnoteStartNode: + { + nCond = PARA_IN_FOOTENOTE; + const SwFtnIdxs& rFtnArr = rNds.GetDoc()->GetFtnIdxs(); + const SwTxtFtn* pTxtFtn; + const SwNode* pSrchNd = pSttNd; + + for( sal_uInt16 n = 0; n < rFtnArr.Count(); ++n ) + if( 0 != ( pTxtFtn = rFtnArr[ n ])->GetStartNode() && + pSrchNd == &pTxtFtn->GetStartNode()->GetNode() ) + { + if( pTxtFtn->GetFtn().IsEndNote() ) + nCond = PARA_IN_ENDNOTE; + break; + } + } + break; + case SwHeaderStartNode: nCond = PARA_IN_HEADER; break; + case SwFooterStartNode: nCond = PARA_IN_FOOTER; break; + case SwNormalStartNode: break; + } + } + + if( nCond ) + { + rTmp.SetCondition( (Master_CollConditions)nCond, 0 ); + return sal_True; + } + pSttNd = pSttNd->GetIndex() + ? pSttNd->StartOfSectionNode() + : 0; + } + } + + { + sal_uInt16 nPos; + const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); + if( rOutlNds.Count() ) + { + if( !rOutlNds.Seek_Entry( (SwCntntNode*)this, &nPos ) && nPos ) + --nPos; + if( nPos < rOutlNds.Count() && + rOutlNds[ nPos ]->GetIndex() < GetIndex() ) + { + SwTxtNode* pOutlNd = rOutlNds[ nPos ]->GetTxtNode(); + + if( pOutlNd->IsOutline()) + { + rTmp.SetCondition( PARA_IN_OUTLINE, pOutlNd->GetAttrOutlineLevel() - 1 ); + return sal_True; + } + } + } + } + + return sal_False; +} + + +void SwCntntNode::ChkCondColl() +{ + // zur Sicherheit abfragen + if( RES_CONDTXTFMTCOLL == GetFmtColl()->Which() ) + { + SwCollCondition aTmp( 0, 0, 0 ); + const SwCollCondition* pCColl; + + bool bDone = false; + + if( IsAnyCondition( aTmp )) + { + pCColl = static_cast<SwConditionTxtFmtColl*>(GetFmtColl()) + ->HasCondition( aTmp ); + + if (pCColl) + { + SetCondFmtColl( pCColl->GetTxtFmtColl() ); + bDone = true; + } + } + + if (!bDone) + { + if( IsTxtNode() && ((SwTxtNode*)this)->GetNumRule()) + { + // steht in einer Numerierung + // welcher Level? + aTmp.SetCondition( PARA_IN_LIST, + ((SwTxtNode*)this)->GetActualListLevel() ); + pCColl = ((SwConditionTxtFmtColl*)GetFmtColl())-> + HasCondition( aTmp ); + } + else + pCColl = 0; + + if( pCColl ) + SetCondFmtColl( pCColl->GetTxtFmtColl() ); + else if( pCondColl ) + SetCondFmtColl( 0 ); + } + } +} + +// #i42921# +short SwCntntNode::GetTextDirection( const SwPosition& rPos, + const Point* pPt ) const +{ + short nRet = -1; + + Point aPt; + if( pPt ) + aPt = *pPt; + + // #i72024# - No format of the frame, because this can cause recursive layout actions + SwFrm* pFrm = getLayoutFrm( GetDoc()->GetCurrentLayout(), &aPt, &rPos, sal_False ); + + if ( pFrm ) + { + if ( pFrm->IsVertical() ) + { + if ( pFrm->IsRightToLeft() ) + nRet = FRMDIR_VERT_TOP_LEFT; + else + nRet = FRMDIR_VERT_TOP_RIGHT; + } + else + { + if ( pFrm->IsRightToLeft() ) + nRet = FRMDIR_HORI_RIGHT_TOP; + else + nRet = FRMDIR_HORI_LEFT_TOP; + } + } + + + return nRet; +} +// <-- + +SwOLENodes* SwCntntNode::CreateOLENodesArray( const SwFmtColl& rColl, bool bOnlyWithInvalidSize ) +{ + SwOLENodes *pNodes = 0; + SwIterator<SwCntntNode,SwFmtColl> aIter( rColl ); + for( SwCntntNode* pNd = aIter.First(); pNd; pNd = aIter.Next() ) + { + SwOLENode *pONd = pNd->GetOLENode(); + if ( pONd && (!bOnlyWithInvalidSize || pONd->IsOLESizeInvalid()) ) + { + if ( !pNodes ) + pNodes = new SwOLENodes; + pNodes->Insert( pONd, pNodes->Count() ); + } + } + + return pNodes; +} + +//FEATURE::CONDCOLL +// Metoden aus Node.hxx - erst hier ist der TxtNode bekannt !! +// os: nur fuer ICC, da der zum optimieren zu dumm ist +#ifdef ICC +SwTxtNode *SwNode::GetTxtNode() +{ + return ND_TEXTNODE == nNodeType ? (SwTxtNode*)this : 0; +} +const SwTxtNode *SwNode::GetTxtNode() const +{ + return ND_TEXTNODE == nNodeType ? (const SwTxtNode*)this : 0; +} +#endif + +/* + * Document Interface Access + */ +const IDocumentSettingAccess* SwNode::getIDocumentSettingAccess() const { return GetDoc(); } +const IDocumentDeviceAccess* SwNode::getIDocumentDeviceAccess() const { return GetDoc(); } +const IDocumentMarkAccess* SwNode::getIDocumentMarkAccess() const { return GetDoc()->getIDocumentMarkAccess(); } +const IDocumentRedlineAccess* SwNode::getIDocumentRedlineAccess() const { return GetDoc(); } +const IDocumentStylePoolAccess* SwNode::getIDocumentStylePoolAccess() const { return GetDoc(); } +const IDocumentLineNumberAccess* SwNode::getIDocumentLineNumberAccess() const { return GetDoc(); } +const IDocumentDrawModelAccess* SwNode::getIDocumentDrawModelAccess() const { return GetDoc(); } +const IDocumentLayoutAccess* SwNode::getIDocumentLayoutAccess() const { return GetDoc(); } +IDocumentLayoutAccess* SwNode::getIDocumentLayoutAccess() { return GetDoc(); } +const IDocumentLinksAdministration* SwNode::getIDocumentLinksAdministration() const { return GetDoc(); } +IDocumentLinksAdministration* SwNode::getIDocumentLinksAdministration() { return GetDoc(); } +const IDocumentFieldsAccess* SwNode::getIDocumentFieldsAccess() const { return GetDoc(); } +IDocumentFieldsAccess* SwNode::getIDocumentFieldsAccess() { return GetDoc(); } +IDocumentContentOperations* SwNode::getIDocumentContentOperations() { return GetDoc(); } +IStyleAccess& SwNode::getIDocumentStyleAccess() { return GetDoc()->GetIStyleAccess(); } +// #i83479# +IDocumentListItems& SwNode::getIDocumentListItems() +{ + return *GetDoc(); +} + +sal_Bool SwNode::IsInRedlines() const +{ + const SwDoc * pDoc = GetDoc(); + sal_Bool bResult = sal_False; + + if (pDoc != NULL) + bResult = pDoc->IsInRedlines(*this); + + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/node2lay.cxx b/sw/source/core/docnode/node2lay.cxx new file mode 100644 index 000000000000..16bc2fef53ae --- /dev/null +++ b/sw/source/core/docnode/node2lay.cxx @@ -0,0 +1,474 @@ +/* -*- 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_sw.hxx" + +#include <switerator.hxx> +#include <calbck.hxx> +#include <node.hxx> +#include <ndindex.hxx> +#include <swtable.hxx> +#include <ftnfrm.hxx> +#include <sectfrm.hxx> +#include "frmfmt.hxx" +#include "cntfrm.hxx" +#include "tabfrm.hxx" +#include "frmtool.hxx" +#include "section.hxx" +#include "node2lay.hxx" + +/* -------------------------------------------------- + * Die SwNode2LayImpl-Klasse erledigt die eigentliche Arbeit, + * die SwNode2Layout-Klasse ist nur die der Oefffentlichkeit bekannte Schnittstelle + * --------------------------------------------------*/ +class SwNode2LayImpl +{ + SwIterator<SwFrm,SwModify>* pIter; + SwModify* pMod; + SvPtrarr *pUpperFrms;// Zum Einsammeln der Upper + sal_uLong nIndex; // Der Index des einzufuegenden Nodes + sal_Bool bMaster : 1; // sal_True => nur Master , sal_False => nur Frames ohne Follow + sal_Bool bInit : 1; // Ist am SwClient bereits ein First()-Aufruf erfolgt? +public: + SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ); + ~SwNode2LayImpl() { delete pIter; delete pUpperFrms; } + SwFrm* NextFrm(); // liefert den naechsten "sinnvollen" Frame + SwLayoutFrm* UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ); + void SaveUpperFrms(); // Speichert (und lockt ggf.) die pUpper + // Fuegt unter jeden pUpper des Arrays einen Frame ein. + void RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ); + + SwFrm* GetFrm( const Point* pDocPos = 0, + const SwPosition *pPos = 0, + const sal_Bool bCalcFrm = sal_True ) const; +}; + +/* -------------------------------------------------- + * Hauptaufgabe des Ctor: Das richtige SwModify zu ermitteln, + * ueber das iteriert wird. + * Uebergibt man bSearch == sal_True, so wird der naechste Cntnt- oder TableNode + * gesucht, der Frames besitzt ( zum Einsammeln der pUpper ), ansonsten wird + * erwartet, das rNode bereits auf einem solchen Cntnt- oder TableNode sitzt, + * vor oder hinter den eingefuegt werden soll. + * --------------------------------------------------*/ + +SwNode* GoNextWithFrm(const SwNodes& rNodes, SwNodeIndex *pIdx) +{ + if( pIdx->GetIndex() >= rNodes.Count() - 1 ) + return 0; + + SwNodeIndex aTmp(*pIdx, +1); + SwNode* pNd = 0; + while( aTmp < rNodes.Count()-1 ) + { + pNd = &aTmp.GetNode(); + bool bFound = false; + if ( pNd->IsCntntNode() ) + bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); + else if ( pNd->IsTableNode() ) + bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); + else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() ) + { + pNd = 0; + break; + } + if ( bFound ) + break; + aTmp++; + } + + if( aTmp == rNodes.Count()-1 ) + pNd = 0; + else if( pNd ) + (*pIdx) = aTmp; + return pNd; +} + +SwNode* GoPreviousWithFrm(SwNodeIndex *pIdx) +{ + if( !pIdx->GetIndex() ) + return 0; + + SwNodeIndex aTmp( *pIdx, -1 ); + SwNode* pNd(0); + while( aTmp.GetIndex() ) + { + pNd = &aTmp.GetNode(); + bool bFound = false; + if ( pNd->IsCntntNode() ) + bFound = ( SwIterator<SwFrm,SwCntntNode>::FirstElement(*(SwCntntNode*)pNd) != 0); + else if ( pNd->IsTableNode() ) + bFound = ( SwIterator<SwFrm,SwFmt>::FirstElement(*((SwTableNode*)pNd)->GetTable().GetFrmFmt()) != 0 ); + else if( pNd->IsStartNode() && !pNd->IsSectionNode() ) + { + pNd = 0; + break; + } + if ( bFound ) + break; + aTmp--; + } + + if( !aTmp.GetIndex() ) + pNd = 0; + else if( pNd ) + (*pIdx) = aTmp; + return pNd; +} + + +SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, sal_Bool bSearch ) + : pUpperFrms( NULL ), nIndex( nIdx ), bInit( sal_False ) +{ + const SwNode* pNd; + if( bSearch || rNode.IsSectionNode() ) + { + // Suche den naechsten Cntnt/TblNode, der einen Frame besitzt, + // damit wir uns vor/hinter ihn haengen koennen + if( !bSearch && rNode.GetIndex() < nIndex ) + { + SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 ); + pNd = GoPreviousWithFrm( &aTmp ); + if( !bSearch && pNd && rNode.GetIndex() > pNd->GetIndex() ) + pNd = NULL; // Nicht ueber den Bereich hinausschiessen + bMaster = sal_False; + } + else + { + SwNodeIndex aTmp( rNode, -1 ); + pNd = GoNextWithFrm( rNode.GetNodes(), &aTmp ); + bMaster = sal_True; + if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() ) + pNd = NULL; // Nicht ueber den Bereich hinausschiessen + } + } + else + { + pNd = &rNode; + bMaster = nIndex < rNode.GetIndex(); + } + if( pNd ) + { + if( pNd->IsCntntNode() ) + pMod = (SwModify*)pNd->GetCntntNode(); + else + { + OSL_ENSURE( pNd->IsTableNode(), "For Tablenodes only" ); + pMod = pNd->GetTableNode()->GetTable().GetFrmFmt(); + } + pIter = new SwIterator<SwFrm,SwModify>( *pMod ); + } + else + { + pIter = NULL; + pMod = 0; + } +} + +/* -------------------------------------------------- + * SwNode2LayImpl::NextFrm() liefert den naechsten "sinnvollen" Frame, + * beim ersten Aufruf wird am eigentlichen Iterator ein First gerufen, + * danach die Next-Methode. Das Ergebnis wird auf Brauchbarkeit untersucht, + * so werden keine Follows akzeptiert, ein Master wird beim Einsammeln der + * pUpper und beim Einfuegen vor ihm akzeptiert. Beim Einfuegen dahinter + * wird vom Master ausgehend der letzte Follow gesucht und zurueckgegeben. + * Wenn der Frame innerhalb eines SectionFrms liegt, wird noch festgestellt, + * ob statt des Frames der SectionFrm der geeignete Rueckgabewert ist, dies + * ist der Fall, wenn der neu einzufuegende Node ausserhalb des Bereichs liegt. + * --------------------------------------------------*/ +SwFrm* SwNode2LayImpl::NextFrm() +{ + SwFrm* pRet; + if( !pIter ) + return sal_False; + if( !bInit ) + { + pRet = pIter->First(); + bInit = sal_True; + } + else + pRet = pIter->Next(); + while( pRet ) + { + SwFlowFrm* pFlow = SwFlowFrm::CastFlowFrm( pRet ); + OSL_ENSURE( pFlow, "Cntnt or Table expected?!" ); + // Follows sind fluechtige Gestalten, deshalb werden sie ignoriert. + // Auch wenn wir hinter dem Frame eingefuegt werden sollen, nehmen wir + // zunaechst den Master, hangeln uns dann aber zum letzten Follow durch. + if( !pFlow->IsFollow() ) + { + if( !bMaster ) + { + while( pFlow->HasFollow() ) + pFlow = pFlow->GetFollow(); + pRet = pFlow->GetFrm(); + } + if( pRet->IsInSct() ) + { + SwSectionFrm* pSct = pRet->FindSctFrm(); + // Vorsicht: Wenn wir in einer Fussnote sind, so kann diese + // Layoutmaessig in einem spaltigen Bereich liegen, obwohl + // sie nodemaessig ausserhalb liegt. Deshalb muss bei Fussnoten + // ueberprueft werden, ob auch der SectionFrm in der Fussnote + // und nicht ausserhalb liegt. + if( !pRet->IsInFtn() || pSct->IsInFtn() ) + { + OSL_ENSURE( pSct && pSct->GetSection(), "Where's my section?" ); + SwSectionNode* pNd = pSct->GetSection()->GetFmt()->GetSectionNode(); + OSL_ENSURE( pNd, "Lost SectionNode" ); + // Wenn der erhaltene Frame in einem Bereichsframe steht, + // dessen Bereich den Ausgangsnode nicht umfasst, so kehren + // wir mit dem SectionFrm zurueck, sonst mit dem Cntnt/TabFrm + if( bMaster ) + { + if( pNd->GetIndex() >= nIndex ) + pRet = pSct; + } + else if( pNd->EndOfSectionIndex() < nIndex ) + pRet = pSct; + } + } + return pRet; + } + pRet = pIter->Next(); + } + return NULL; +} + +void SwNode2LayImpl::SaveUpperFrms() +{ + pUpperFrms = new SvPtrarr( 0, 20 ); + SwFrm* pFrm; + while( 0 != (pFrm = NextFrm()) ) + { + SwFrm* pPrv = pFrm->GetPrev(); + pFrm = pFrm->GetUpper(); + if( pFrm ) + { + if( pFrm->IsFtnFrm() ) + ((SwFtnFrm*)pFrm)->ColLock(); + else if( pFrm->IsInSct() ) + pFrm->FindSctFrm()->ColLock(); + if( pPrv && pPrv->IsSctFrm() ) + ((SwSectionFrm*)pPrv)->LockJoin(); + pUpperFrms->Insert( (void*)pPrv, pUpperFrms->Count() ); + pUpperFrms->Insert( (void*)pFrm, pUpperFrms->Count() ); + } + } + delete pIter; + pIter = NULL; + pMod = 0; +} + +SwLayoutFrm* SwNode2LayImpl::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) +{ + rpFrm = NextFrm(); + if( !rpFrm ) + return NULL; + SwLayoutFrm* pUpper = rpFrm->GetUpper(); + if( rpFrm->IsSctFrm() ) + { + const SwNode* pNode = rNode.StartOfSectionNode(); + if( pNode->IsSectionNode() ) + { + SwFrm* pFrm = bMaster ? rpFrm->FindPrev() : rpFrm->FindNext(); + if( pFrm && pFrm->IsSctFrm() ) + { + // pFrm could be a "dummy"-section + if( ((SwSectionFrm*)pFrm)->GetSection() && + (&((SwSectionNode*)pNode)->GetSection() == + ((SwSectionFrm*)pFrm)->GetSection()) ) + { + // #i22922# - consider columned sections + // 'Go down' the section frame as long as the layout frame + // is found, which would contain content. + while ( pFrm->IsLayoutFrm() && + static_cast<SwLayoutFrm*>(pFrm)->Lower() && + !static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsFlowFrm() && + static_cast<SwLayoutFrm*>(pFrm)->Lower()->IsLayoutFrm() ) + { + pFrm = static_cast<SwLayoutFrm*>(pFrm)->Lower(); + } + OSL_ENSURE( pFrm->IsLayoutFrm(), + "<SwNode2LayImpl::UpperFrm(..)> - expected upper frame isn't a layout frame." ); + rpFrm = bMaster ? NULL + : static_cast<SwLayoutFrm*>(pFrm)->Lower(); + OSL_ENSURE( !rpFrm || rpFrm->IsFlowFrm(), + "<SwNode2LayImpl::UpperFrm(..)> - expected sibling isn't a flow frame." ); + return static_cast<SwLayoutFrm*>(pFrm); + } + + pUpper = new SwSectionFrm(((SwSectionNode*)pNode)->GetSection(), rpFrm); + pUpper->Paste( rpFrm->GetUpper(), + bMaster ? rpFrm : rpFrm->GetNext() ); + static_cast<SwSectionFrm*>(pUpper)->Init(); + rpFrm = NULL; + // 'Go down' the section frame as long as the layout frame + // is found, which would contain content. + while ( pUpper->Lower() && + !pUpper->Lower()->IsFlowFrm() && + pUpper->Lower()->IsLayoutFrm() ) + { + pUpper = static_cast<SwLayoutFrm*>(pUpper->Lower()); + } + return pUpper; + } + } + }; + if( !bMaster ) + rpFrm = rpFrm->GetNext(); + return pUpper; +} + +void SwNode2LayImpl::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) +{ + OSL_ENSURE( pUpperFrms, "RestoreUpper without SaveUpper?" ); + SwNode* pNd; + SwDoc *pDoc = rNds.GetDoc(); + sal_Bool bFirst = sal_True; + for( ; nStt < nEnd; ++nStt ) + { + SwFrm* pNew = 0; + SwFrm* pNxt; + SwLayoutFrm* pUp; + if( (pNd = rNds[nStt])->IsCntntNode() ) + for( sal_uInt16 n = 0; n < pUpperFrms->Count(); ) + { + pNxt = (SwFrm*)(*pUpperFrms)[n++]; + if( bFirst && pNxt && pNxt->IsSctFrm() ) + ((SwSectionFrm*)pNxt)->UnlockJoin(); + pUp = (SwLayoutFrm*)(*pUpperFrms)[n++]; + if( pNxt ) + pNxt = pNxt->GetNext(); + else + pNxt = pUp->Lower(); + pNew = ((SwCntntNode*)pNd)->MakeFrm( pUp ); + pNew->Paste( pUp, pNxt ); + (*pUpperFrms)[n-2] = pNew; + } + else if( pNd->IsTableNode() ) + for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) + { + pNxt = (SwFrm*)(*pUpperFrms)[x++]; + if( bFirst && pNxt && pNxt->IsSctFrm() ) + ((SwSectionFrm*)pNxt)->UnlockJoin(); + pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; + if( pNxt ) + pNxt = pNxt->GetNext(); + else + pNxt = pUp->Lower(); + pNew = ((SwTableNode*)pNd)->MakeFrm( pUp ); + OSL_ENSURE( pNew->IsTabFrm(), "Table exspected" ); + pNew->Paste( pUp, pNxt ); + ((SwTabFrm*)pNew)->RegistFlys(); + (*pUpperFrms)[x-2] = pNew; + } + else if( pNd->IsSectionNode() ) + { + nStt = pNd->EndOfSectionIndex(); + for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ) + { + pNxt = (SwFrm*)(*pUpperFrms)[x++]; + if( bFirst && pNxt && pNxt->IsSctFrm() ) + ((SwSectionFrm*)pNxt)->UnlockJoin(); + pUp = (SwLayoutFrm*)(*pUpperFrms)[x++]; + OSL_ENSURE( pUp->GetUpper() || pUp->IsFlyFrm(), "Lost Upper" ); + ::_InsertCnt( pUp, pDoc, pNd->GetIndex(), sal_False, nStt+1, pNxt ); + pNxt = pUp->GetLastLower(); + (*pUpperFrms)[x-2] = pNxt; + } + } + bFirst = sal_False; + } + for( sal_uInt16 x = 0; x < pUpperFrms->Count(); ++x ) + { + SwFrm* pTmp = (SwFrm*)(*pUpperFrms)[++x]; + if( pTmp->IsFtnFrm() ) + ((SwFtnFrm*)pTmp)->ColUnlock(); + else if ( pTmp->IsInSct() ) + { + SwSectionFrm* pSctFrm = pTmp->FindSctFrm(); + pSctFrm->ColUnlock(); + // #i18103# - invalidate size of section in order to + // assure, that the section is formatted, unless it was 'Collocked' + // from its 'collection' until its 'restoration'. + pSctFrm->_InvalidateSize(); + } + } +} + +SwFrm* SwNode2LayImpl::GetFrm( const Point* pDocPos, + const SwPosition *pPos, + const sal_Bool bCalcFrm ) const +{ + // mba: test if change of member pIter -> pMod broke anything + return pMod ? ::GetFrmOfModify( 0, *pMod, USHRT_MAX, pDocPos, pPos, bCalcFrm ) : 0; +} + +SwNode2Layout::SwNode2Layout( const SwNode& rNd, sal_uLong nIdx ) +{ + pImpl = new SwNode2LayImpl( rNd, nIdx, sal_False ); +} + +SwNode2Layout::SwNode2Layout( const SwNode& rNd ) +{ + pImpl = new SwNode2LayImpl( rNd, rNd.GetIndex(), sal_True ); + pImpl->SaveUpperFrms(); +} + +void SwNode2Layout::RestoreUpperFrms( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd ) +{ + OSL_ENSURE( pImpl, "RestoreUpperFrms without SaveUpperFrms" ); + pImpl->RestoreUpperFrms( rNds, nStt, nEnd ); +} + +SwFrm* SwNode2Layout::NextFrm() +{ + return pImpl->NextFrm(); +} + +SwLayoutFrm* SwNode2Layout::UpperFrm( SwFrm* &rpFrm, const SwNode &rNode ) +{ + return pImpl->UpperFrm( rpFrm, rNode ); +} + +SwNode2Layout::~SwNode2Layout() +{ + delete pImpl; +} + +SwFrm* SwNode2Layout::GetFrm( const Point* pDocPos, + const SwPosition *pPos, + const sal_Bool bCalcFrm ) const +{ + return pImpl->GetFrm( pDocPos, pPos, bCalcFrm ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx new file mode 100644 index 000000000000..dbd0f4194bf8 --- /dev/null +++ b/sw/source/core/docnode/nodes.cxx @@ -0,0 +1,2508 @@ +/* -*- 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_sw.hxx" + +#include <stdlib.h> + +#include <node.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pam.hxx> +#include <txtfld.hxx> +#include <fmtfld.hxx> +#include <hints.hxx> +#include <numrule.hxx> +#include <ndtxt.hxx> +#include <ndnotxt.hxx> +#include <swtable.hxx> // fuer erzuegen / loeschen der Table-Frames +#include <tblsel.hxx> +#include <section.hxx> +#include <ddefld.hxx> +#include <swddetbl.hxx> +#include <frame.hxx> +#include <txtatr.hxx> +#include <tox.hxx> // InvalidateTOXMark + +#include <docsh.hxx> +#include <svl/smplhint.hxx> + +extern sal_Bool CheckNodesRange( const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, sal_Bool bChkSection ); + +SV_DECL_PTRARR(SwSttNdPtrs,SwStartNode*,2,2) + + +// Funktion zum bestimmen des hoechsten Levels innerhalb des Bereiches + +sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange ); + +//----------------------------------------------------------------------- + +/******************************************************************* +|* SwNodes::SwNodes +|* +|* Beschreibung +|* Konstruktor; legt die vier Grundsektions (PostIts, +|* Inserts, Icons, Inhalt) an +*******************************************************************/ +SwNodes::SwNodes( SwDoc* pDocument ) + : pRoot( 0 ), pMyDoc( pDocument ) +{ + bInNodesDel = bInDelUpdOutl = bInDelUpdNum = sal_False; + + OSL_ENSURE( pMyDoc, "in welchem Doc stehe ich denn?" ); + + sal_uLong nPos = 0; + SwStartNode* pSttNd = new SwStartNode( *this, nPos++ ); + pEndOfPostIts = new SwEndNode( *this, nPos++, *pSttNd ); + + SwStartNode* pTmp = new SwStartNode( *this, nPos++ ); + pEndOfInserts = new SwEndNode( *this, nPos++, *pTmp ); + + pTmp = new SwStartNode( *this, nPos++ ); + pTmp->pStartOfSection = pSttNd; + pEndOfAutotext = new SwEndNode( *this, nPos++, *pTmp ); + + pTmp = new SwStartNode( *this, nPos++ ); + pTmp->pStartOfSection = pSttNd; + pEndOfRedlines = new SwEndNode( *this, nPos++, *pTmp ); + + pTmp = new SwStartNode( *this, nPos++ ); + pTmp->pStartOfSection = pSttNd; + pEndOfContent = new SwEndNode( *this, nPos++, *pTmp ); + + pOutlineNds = new SwOutlineNodes; +} + +/******************************************************************* +|* +|* SwNodes::~SwNodes +|* +|* Beschreibung +|* dtor, loescht alle Nodes, deren Pointer in diesem dynamischen +|* Array sind. Ist kein Problem, da Nodes ausserhalb dieses +|* Arrays nicht erzeugt werden koennen und somit auch nicht +|* in mehreren drin sein koennen +|* +*******************************************************************/ + +SwNodes::~SwNodes() +{ + delete pOutlineNds; + + { + SwNode *pNode; + SwNodeIndex aNdIdx( *this ); + while( sal_True ) + { + pNode = &aNdIdx.GetNode(); + if( pNode == pEndOfContent ) + break; + + aNdIdx++; + delete pNode; + } + } + + // jetzt muessen alle SwNodeIndizies abgemeldet sein!!! + delete pEndOfContent; +} + +void SwNodes::ChgNode( SwNodeIndex& rDelPos, sal_uLong nSz, + SwNodeIndex& rInsPos, sal_Bool bNewFrms ) +{ + // im UndoBereich brauchen wir keine Frames + SwNodes& rNds = rInsPos.GetNodes(); + const SwNode* pPrevInsNd = rNds[ rInsPos.GetIndex() -1 ]; + + //JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im + // Idle-Handler des Docs + if( GetDoc()->SetFieldsDirty( sal_True, &rDelPos.GetNode(), nSz ) && + rNds.GetDoc() != GetDoc() ) + rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 ); + + //JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen + sal_uLong nNd = rInsPos.GetIndex(); + sal_Bool bInsOutlineIdx = !( + rNds.GetEndOfRedlines().StartOfSectionNode()->GetIndex() < nNd && + nNd < rNds.GetEndOfRedlines().GetIndex() ); + + if( &rNds == this ) // im gleichen Nodes-Array -> moven !! + { + // wird von vorne nach hinten gemovt, so wird nach vorne immer + // nachgeschoben, d.H. die Loeschposition ist immer gleich + sal_uInt16 nDiff = rDelPos.GetIndex() < rInsPos.GetIndex() ? 0 : 1; + + for( sal_uLong n = rDelPos.GetIndex(); nSz; n += nDiff, --nSz ) + { + SwNodeIndex aDelIdx( *this, n ); + SwNode& rNd = aDelIdx.GetNode(); + + // #i57920# - correction of refactoring done by cws swnumtree: + // - <SwTxtNode::SetLevel( NO_NUMBERING ) is deprecated and + // set <IsCounted> state of the text node to <false>, which + // isn't correct here. + if ( rNd.IsTxtNode() ) + { + SwTxtNode* pTxtNode = rNd.GetTxtNode(); + + pTxtNode->RemoveFromList(); + + if ( pTxtNode->GetAttrOutlineLevel() != 0 )//<-end,zhaojianwei + { + const SwNodePtr pSrch = (SwNodePtr)&rNd; + pOutlineNds->Remove( pSrch ); + } + } + // <-- + + BigPtrArray::Move( aDelIdx.GetIndex(), rInsPos.GetIndex() ); + + if( rNd.IsTxtNode() ) + { + SwTxtNode& rTxtNd = (SwTxtNode&)rNd; + + rTxtNd.AddToList(); + + if( bInsOutlineIdx && + 0 != rTxtNd.GetAttrOutlineLevel() )//<-end,zhaojianwei + { + const SwNodePtr pSrch = (SwNodePtr)&rNd; + pOutlineNds->Insert( pSrch ); + } + rTxtNd.InvalidateNumRule(); + +//FEATURE::CONDCOLL + if( RES_CONDTXTFMTCOLL == rTxtNd.GetTxtColl()->Which() ) + rTxtNd.ChkCondColl(); +//FEATURE::CONDCOLL + } + else if( rNd.IsCntntNode() ) + ((SwCntntNode&)rNd).InvalidateNumRule(); + } + } + else + { + bool bSavePersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds)); + bool bRestPersData(GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this)); + SwDoc* pDestDoc = rNds.GetDoc() != GetDoc() ? rNds.GetDoc() : 0; + OSL_ENSURE(!pDestDoc, "SwNodes::ChgNode(): " + "the code to handle text fields here looks broken\n" + "if the target is in a different document."); + if( !bRestPersData && !bSavePersData && pDestDoc ) + bSavePersData = bRestPersData = sal_True; + + String sNumRule; + SwNodeIndex aInsPos( rInsPos ); + for( sal_uLong n = 0; n < nSz; n++ ) + { + SwNode* pNd = &rDelPos.GetNode(); + + // NoTextNode muessen ihre Persitenten Daten mitnehmen + if( pNd->IsNoTxtNode() ) + { + if( bSavePersData ) + ((SwNoTxtNode*)pNd)->SavePersistentData(); + } + else if( pNd->IsTxtNode() ) + { + SwTxtNode* pTxtNd = (SwTxtNode*)pNd; + + // loesche die Gliederungs-Indizies aus dem alten Nodes-Array + if( 0 != pTxtNd->GetAttrOutlineLevel() )//<-end,zhaojianwei + pOutlineNds->Remove( pNd ); + + // muss die Rule kopiere werden? + if( pDestDoc ) + { + const SwNumRule* pNumRule = pTxtNd->GetNumRule(); + if( pNumRule && sNumRule != pNumRule->GetName() ) + { + sNumRule = pNumRule->GetName(); + SwNumRule* pDestRule = pDestDoc->FindNumRulePtr( sNumRule ); + if( pDestRule ) + pDestRule->SetInvalidRule( sal_True ); + else + pDestDoc->MakeNumRule( sNumRule, pNumRule ); + } + } + else + // wenns ins UndoNodes-Array gemoved wird, sollten die + // Numerierungen auch aktualisiert werden. + pTxtNd->InvalidateNumRule(); + + pTxtNd->RemoveFromList(); + } + + RemoveNode( rDelPos.GetIndex(), 1, sal_False ); // Indizies verschieben !! + SwCntntNode * pCNd = pNd->GetCntntNode(); + rNds.InsertNode( pNd, aInsPos ); + + if( pCNd ) + { + SwTxtNode* pTxtNd = pCNd->GetTxtNode(); + if( pTxtNd ) + { + SwpHints * const pHts = pTxtNd->GetpSwpHints(); + // OultineNodes set the new nodes in the array + if( bInsOutlineIdx && + 0 != pTxtNd->GetAttrOutlineLevel() ) //#outline level,added by zhaojianwei + { + rNds.pOutlineNds->Insert( pTxtNd ); + } + + pTxtNd->AddToList(); + + // Sonderbehandlung fuer die Felder! + if( pHts && pHts->Count() ) + { + // this looks fishy if pDestDoc != 0 + bool const bToUndo = !pDestDoc && + GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNds); + for( sal_uInt16 i = pHts->Count(); i; ) + { + sal_uInt16 nDelMsg = 0; + SwTxtAttr * const pAttr = pHts->GetTextHint( --i ); + switch ( pAttr->Which() ) + { + case RES_TXTATR_FIELD: + { + SwTxtFld* pTxtFld = + static_cast<SwTxtFld*>(pAttr); + rNds.GetDoc()->InsDelFldInFldLst( !bToUndo, *pTxtFld ); + + const SwFieldType* pTyp = pTxtFld->GetFld().GetFld()->GetTyp(); + if ( RES_POSTITFLD == pTyp->Which() ) + { + rNds.GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( &pTxtFld->GetFld(), pTxtFld->GetFld().IsFldInDoc() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) ); + } + else + if( RES_DDEFLD == pTyp->Which() ) + { + if( bToUndo ) + ((SwDDEFieldType*)pTyp)->DecRefCnt(); + else + ((SwDDEFieldType*)pTyp)->IncRefCnt(); + } + nDelMsg = RES_FIELD_DELETED; + } + break; + case RES_TXTATR_FTN: + nDelMsg = RES_FOOTNOTE_DELETED; + break; + + case RES_TXTATR_TOXMARK: + static_cast<SwTOXMark&>(pAttr->GetAttr()) + .InvalidateTOXMark(); + break; + + case RES_TXTATR_REFMARK: + nDelMsg = RES_REFMARK_DELETED; + break; + + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + { + SwTxtMeta *const pTxtMeta( + static_cast<SwTxtMeta*>(pAttr)); + // force removal of UNO object + pTxtMeta->ChgTxtNode(0); + pTxtMeta->ChgTxtNode(pTxtNd); + } + break; + + default: + break; + } + if( nDelMsg && bToUndo ) + { + SwPtrMsgPoolItem aMsgHint( nDelMsg, + (void*)&pAttr->GetAttr() ); + rNds.GetDoc()->GetUnoCallBack()-> + ModifyNotification( &aMsgHint, &aMsgHint ); + } + } + } +//FEATURE::CONDCOLL + if( RES_CONDTXTFMTCOLL == pTxtNd->GetTxtColl()->Which() ) + pTxtNd->ChkCondColl(); +//FEATURE::CONDCOLL + } + else + { + // in unterschiedliche Docs gemoved ? + // dann die Daten wieder persistent machen + if( pCNd->IsNoTxtNode() && bRestPersData ) + ((SwNoTxtNode*)pCNd)->RestorePersistentData(); + } + } + } + } + + //JP 03.02.99: alle Felder als invalide erklaeren, aktu. erfolgt im + // Idle-Handler des Docs + GetDoc()->SetFieldsDirty( true, NULL, 0 ); + if( rNds.GetDoc() != GetDoc() ) + rNds.GetDoc()->SetFieldsDirty( true, NULL, 0 ); + + + if( bNewFrms ) + bNewFrms = &GetDoc()->GetNodes() == (const SwNodes*)&rNds && + GetDoc()->GetCurrentViewShell(); //swmod 071108//swmod 071225 + if( bNewFrms ) + { + // Frames besorgen: + SwNodeIndex aIdx( *pPrevInsNd, 1 ); + SwNodeIndex aFrmNdIdx( aIdx ); + SwNode* pFrmNd = rNds.FindPrvNxtFrmNode( aFrmNdIdx, + rNds[ rInsPos.GetIndex() - 1 ] ); + + if( !pFrmNd && aFrmNdIdx > rNds.GetEndOfExtras().GetIndex() ) + { + OSL_ENSURE( !this, "ob das so richtig ist ??" ); + aFrmNdIdx = rNds.GetEndOfContent(); + pFrmNd = rNds.GoPrevSection( &aFrmNdIdx, sal_True, sal_False ); + if( pFrmNd && !((SwCntntNode*)pFrmNd)->GetDepends() ) + pFrmNd = 0; + +#if OSL_DEBUG_LEVEL > 1 + if( !pFrmNd ) + OSL_ENSURE( !this, "ChgNode() - kein FrameNode gefunden" ); +#endif + } + if( pFrmNd ) + while( aIdx != rInsPos ) + { + SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); + if( pCNd ) + { + if( pFrmNd->IsTableNode() ) + ((SwTableNode*)pFrmNd)->MakeFrms( aIdx ); + else if( pFrmNd->IsSectionNode() ) + ((SwSectionNode*)pFrmNd)->MakeFrms( aIdx ); + else + ((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd ); + pFrmNd = pCNd; + } + aIdx++; + } + } +} + + +/*********************************************************************** +|* +|* SwNodes::Move +|* +|* Beschreibung +|* Move loescht die Node-Pointer ab und einschliesslich der Startposition +|* bis zu und ausschliesslich der Endposition und fuegt sie an +|* der vor der Zielposition ein. +|* Wenn das Ziel vor dem ersten oder dem letzten zu bewegenden Element oder +|* dazwischen liegt, geschieht nichts. +|* Wenn der zu bewegende Bereich leer ist oder das Ende vor +|* dem Anfang liegt, geschieht nichts. +|* +|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !! +|* ( 1.Node: aStart, letzer Node: aEnd-1 !! ) +|* +***********************************************************************/ + +sal_Bool SwNodes::_MoveNodes( const SwNodeRange& aRange, SwNodes & rNodes, + const SwNodeIndex& aIndex, sal_Bool bNewFrms ) +{ + SwNode * pAktNode; + if( aIndex == 0 || + ( (pAktNode = &aIndex.GetNode())->GetStartNode() && + !pAktNode->StartOfSectionIndex() )) + return sal_False; + + SwNodeRange aRg( aRange ); + + // "einfache" StartNodes oder EndNodes ueberspringen + while( ND_STARTNODE == (pAktNode = &aRg.aStart.GetNode())->GetNodeType() + || ( pAktNode->IsEndNode() && + !pAktNode->pStartOfSection->IsSectionNode() ) ) + aRg.aStart++; + aRg.aStart--; + + // falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen + aRg.aEnd--; + while( ( (( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() && + !pAktNode->IsSectionNode() ) || + ( pAktNode->IsEndNode() && + ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) ) && + aRg.aEnd > aRg.aStart ) + aRg.aEnd--; + + + // wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos. + if( aRg.aStart >= aRg.aEnd ) + return sal_False; + + if( this == &rNodes ) + { + if( ( aIndex.GetIndex()-1 >= aRg.aStart.GetIndex() && + aIndex.GetIndex()-1 < aRg.aEnd.GetIndex()) || + ( aIndex.GetIndex()-1 == aRg.aEnd.GetIndex() ) ) + return sal_False; + } + + sal_uInt16 nLevel = 0; // Level-Counter + sal_uLong nInsPos = 0; // Cnt fuer das TmpArray + + // das Array bildet einen Stack, es werden alle StartOfSelction's gesichert + SwSttNdPtrs aSttNdStack( 1, 5 ); + + // setze den Start-Index + SwNodeIndex aIdx( aIndex ); + + SwStartNode* pStartNode = aIdx.GetNode().pStartOfSection; + aSttNdStack.C40_INSERT( SwStartNode, pStartNode, 0 ); + + SwNodeRange aOrigInsPos( aIdx, -1, aIdx ); // Originale Insert Pos + + //JP 16.01.98: SectionNodes: DelFrms/MakeFrms beim obersten SectionNode! + sal_uInt16 nSectNdCnt = 0; + sal_Bool bSaveNewFrms = bNewFrms; + + // bis alles verschoben ist + while( aRg.aStart < aRg.aEnd ) + switch( (pAktNode = &aRg.aEnd.GetNode())->GetNodeType() ) + { + case ND_ENDNODE: + { + if( nInsPos ) // verschieb schon mal alle bis hier her + { + // loeschen und kopieren. ACHTUNG: die Indizies ab + // "aRg.aEnd+1" werden mit verschoben !! + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + aIdx -= nInsPos; + nInsPos = 0; + } + + SwStartNode* pSttNd = pAktNode->pStartOfSection; + if( pSttNd->IsTableNode() ) + { + SwTableNode* pTblNd = (SwTableNode*)pSttNd; + + // dann bewege die gesamte Tabelle/den Bereich !! + nInsPos = (aRg.aEnd.GetIndex() - + pSttNd->GetIndex() )+1; + aRg.aEnd -= nInsPos; + + //JP 12.03.99: 63293 - Nodes vom RedlineBereich NIE aufnehmen + sal_uLong nNd = aIdx.GetIndex(); + sal_Bool bInsOutlineIdx = !( rNodes.GetEndOfRedlines(). + StartOfSectionNode()->GetIndex() < nNd && + nNd < rNodes.GetEndOfRedlines().GetIndex() ); + + if( bNewFrms ) + // loesche erstmal die Frames + pTblNd->DelFrms(); + if( &rNodes == this ) // in sich selbst moven ?? + { + // dann bewege alle Start/End/ContentNodes. Loesche + // bei den ContentNodes auch die Frames !! + pTblNd->pStartOfSection = aIdx.GetNode().pStartOfSection; + for( sal_uLong n = 0; n < nInsPos; ++n ) + { + SwNodeIndex aMvIdx( aRg.aEnd, 1 ); + SwCntntNode* pCNd = 0; + SwNode* pTmpNd = &aMvIdx.GetNode(); + if( pTmpNd->IsCntntNode() ) + { + pCNd = (SwCntntNode*)pTmpNd; + if( pTmpNd->IsTxtNode() ) + ((SwTxtNode*)pTmpNd)->RemoveFromList(); + + // setze bei Start/EndNodes die richtigen Indizies + // loesche die Gliederungs-Indizies aus + // dem alten Nodes-Array + if( pCNd->IsTxtNode() && 0 != + ((SwTxtNode*)pCNd)->GetAttrOutlineLevel() )//<-end,by zhaojianwei + pOutlineNds->Remove( pCNd ); + else + pCNd = 0; + } + + BigPtrArray::Move( aMvIdx.GetIndex(), aIdx.GetIndex() ); + + if( bInsOutlineIdx && pCNd ) + pOutlineNds->Insert( pCNd ); + if( pTmpNd->IsTxtNode() ) + ((SwTxtNode*)pTmpNd)->AddToList(); + } + } + else + { + // StartNode holen + // Even aIdx points to a startnode, we need the startnode + // of the environment of aIdx (#i80941) + SwStartNode* pSttNode = aIdx.GetNode().pStartOfSection; + + // Hole alle Boxen mit Inhalt. Deren Indizies auf die + // StartNodes muessen umgemeldet werden !! + // (Array kopieren und alle gefunden wieder loeschen; + // erleichtert das suchen!!) + SwNodeIndex aMvIdx( aRg.aEnd, 1 ); + for( sal_uLong n = 0; n < nInsPos; ++n ) + { + SwNode* pNd = &aMvIdx.GetNode(); + + const bool bOutlNd = pNd->IsTxtNode() && + 0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel();//<-end,zhaojianwei + // loesche die Gliederungs-Indizies aus + // dem alten Nodes-Array + if( bOutlNd ) + pOutlineNds->Remove( pNd ); + + RemoveNode( aMvIdx.GetIndex(), 1, sal_False ); + pNd->pStartOfSection = pSttNode; + rNodes.InsertNode( pNd, aIdx ); + + // setze bei Start/EndNodes die richtigen Indizies + if( bInsOutlineIdx && bOutlNd ) + // und setze sie im neuen Nodes-Array + rNodes.pOutlineNds->Insert( pNd ); + else if( pNd->IsStartNode() ) + pSttNode = (SwStartNode*)pNd; + else if( pNd->IsEndNode() ) + { + pSttNode->pEndOfSection = (SwEndNode*)pNd; + if( pSttNode->IsSectionNode() ) + ((SwSectionNode*)pSttNode)->NodesArrChgd(); + pSttNode = pSttNode->pStartOfSection; + } + } + + if( pTblNd->GetTable().IsA( TYPE( SwDDETable ) )) + { + SwDDEFieldType* pTyp = ((SwDDETable&)pTblNd-> + GetTable()).GetDDEFldType(); + if( pTyp ) + { + if( rNodes.IsDocNodes() ) + pTyp->IncRefCnt(); + else + pTyp->DecRefCnt(); + } + } + + if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes( + rNodes)) + { + SwFrmFmt* pTblFmt = pTblNd->GetTable().GetFrmFmt(); + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, + pTblFmt ); + pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint ); + } + } + if( bNewFrms ) + { + SwNodeIndex aTmp( aIdx ); + pTblNd->MakeFrms( &aTmp ); + } + aIdx -= nInsPos; + nInsPos = 0; + } + else if( pSttNd->GetIndex() < aRg.aStart.GetIndex() ) + { + // SectionNode: es wird nicht die gesamte Section + // verschoben, also bewege nur die + // ContentNodes + // StartNode: erzeuge an der Postion eine neue Section + do { // middle check loop + if( !pSttNd->IsSectionNode() ) + { + // Start und EndNode an der InsertPos erzeugen + SwStartNode* pTmp = new SwStartNode( aIdx, + ND_STARTNODE, +/*?? welcher NodeTyp ??*/ + SwNormalStartNode ); + + nLevel++; // den Index auf StartNode auf den Stack + aSttNdStack.C40_INSERT( SwStartNode, pTmp, nLevel ); + + // noch den EndNode erzeugen + new SwEndNode( aIdx, *pTmp ); + } + else if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes( + rNodes)) + { + // im UndoNodes-Array spendieren wir einen + // Platzhalter + new SwNode( aIdx, ND_SECTIONDUMMY ); + } + else + { + // JP 18.5.2001: neue Section anlegen?? Bug 70454 + aRg.aEnd--; + break; + + } + + aRg.aEnd--; + aIdx--; + } while( sal_False ); + } + else + { + // Start und EndNode komplett verschieben +// s. u. SwIndex aOldStt( pSttNd->theIndex ); +//JP 21.05.97: sollte der Start genau der Start des Bereiches sein, so muss +// der Node auf jedenfall noch besucht werden! + if( &aRg.aStart.GetNode() == pSttNd ) + --aRg.aStart; + + SwSectionNode* pSctNd = pSttNd->GetSectionNode(); + if( bNewFrms && pSctNd ) + pSctNd->DelFrms(); + + RemoveNode( aRg.aEnd.GetIndex(), 1, sal_False ); // EndNode loeschen + sal_uLong nSttPos = pSttNd->GetIndex(); + + // dieser StartNode wird spaeter wieder entfernt! + SwStartNode* pTmpSttNd = new SwStartNode( *this, nSttPos+1 ); + pTmpSttNd->pStartOfSection = pSttNd->pStartOfSection; + + RemoveNode( nSttPos, 1, sal_False ); // SttNode loeschen + + pSttNd->pStartOfSection = aIdx.GetNode().pStartOfSection; + rNodes.InsertNode( pSttNd, aIdx ); + rNodes.InsertNode( pAktNode, aIdx ); + aIdx--; + pSttNd->pEndOfSection = (SwEndNode*)pAktNode; + + aRg.aEnd--; + + nLevel++; // den Index auf StartNode auf den Stack + aSttNdStack.C40_INSERT( SwStartNode, pSttNd, nLevel ); + + // SectionNode muss noch ein paar Indizies ummelden + if( pSctNd ) + { + pSctNd->NodesArrChgd(); + ++nSectNdCnt; + bNewFrms = sal_False; + } + } + } + break; + + + + case ND_SECTIONNODE: + if( !nLevel && + GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(rNodes)) + { + // dann muss an der akt. InsPos ein SectionDummyNode + // eingefuegt werden + if( nInsPos ) // verschieb schon mal alle bis hier her + { + // loeschen und kopieren. ACHTUNG: die Indizies ab + // "aRg.aEnd+1" werden mit verschoben !! + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + aIdx -= nInsPos; + nInsPos = 0; + } + new SwNode( aIdx, ND_SECTIONDUMMY ); + aRg.aEnd--; + aIdx--; + break; + } + // kein break !! + case ND_TABLENODE: + case ND_STARTNODE: + { + // empty section -> nothing to do + // and only if it's a top level section + if( !nInsPos && !nLevel ) + { + aRg.aEnd--; + break; + } + + if( !nLevel ) // es wird eine Stufe runter gestuft + { + // erzeuge die Runterstufung + SwNodeIndex aTmpSIdx( aOrigInsPos.aStart, 1 ); + SwStartNode* pTmpStt = new SwStartNode( aTmpSIdx, + ND_STARTNODE, + ((SwStartNode*)pAktNode)->GetStartNodeType() ); + + aTmpSIdx--; + + SwNodeIndex aTmpEIdx( aOrigInsPos.aEnd ); + new SwEndNode( aTmpEIdx, *pTmpStt ); + aTmpEIdx--; + aTmpSIdx++; + + // setze die StartOfSection richtig + aRg.aEnd++; + { + SwNodeIndex aCntIdx( aRg.aEnd ); + for( sal_uLong n = 0; n < nInsPos; n++, aCntIdx++) + aCntIdx.GetNode().pStartOfSection = pTmpStt; + } + + // Setze auch bei allen runtergestuften den richtigen StartNode + while( aTmpSIdx < aTmpEIdx ) + if( 0 != (( pAktNode = &aTmpEIdx.GetNode())->GetEndNode()) ) + aTmpEIdx = pAktNode->StartOfSectionIndex(); + else + { + pAktNode->pStartOfSection = pTmpStt; + aTmpEIdx--; + } + + aIdx--; // hinter den eingefuegten StartNode + aRg.aEnd--; // vor den StartNode + // kopiere jetzt das Array. ACHTUNG: die Indizies ab + // "aRg.aEnd+1" werden mit verschoben !! + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + aIdx -= nInsPos+1; + nInsPos = 0; + } + else // es wurden alle Nodes innerhalb eines + { // Start- und End-Nodes verschoben + OSL_ENSURE( pAktNode == aSttNdStack[nLevel] || + ( pAktNode->IsStartNode() && + aSttNdStack[nLevel]->IsSectionNode()), + "falscher StartNode" ); + + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + aIdx -= nInsPos+1; // vor den eingefuegten StartNode + nInsPos = 0; + + // loesche nur noch den Pointer aus dem Nodes-Array. + RemoveNode( aRg.aEnd.GetIndex(), 1, sal_True ); + aRg.aEnd--; + + SwSectionNode* pSectNd = aSttNdStack[ nLevel ]->GetSectionNode(); + if( pSectNd && !--nSectNdCnt ) + { + SwNodeIndex aTmp( *pSectNd ); + pSectNd->MakeFrms( &aTmp ); + bNewFrms = bSaveNewFrms; + } + aSttNdStack.Remove( nLevel ); // vom Stack loeschen + nLevel--; + } + + // loesche alle entstehenden leeren Start-/End-Node-Paare + SwNode* pTmpNode = (*this)[ aRg.aEnd.GetIndex()+1 ]->GetEndNode(); + if( pTmpNode && ND_STARTNODE == (pAktNode = &aRg.aEnd.GetNode()) + ->GetNodeType() && pAktNode->StartOfSectionIndex() && + pTmpNode->StartOfSectionNode() == pAktNode ) + { + DelNodes( aRg.aEnd, 2 ); + aRg.aEnd--; + } + } + break; + + case ND_TEXTNODE: + case ND_GRFNODE: + case ND_OLENODE: + { + if( bNewFrms && pAktNode->GetCntntNode() ) + ((SwCntntNode*)pAktNode)->DelFrms(); + + pAktNode->pStartOfSection = aSttNdStack[ nLevel ]; + nInsPos++; + aRg.aEnd--; + } + break; + + case ND_SECTIONDUMMY: + if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this)) + { + if( &rNodes == this ) // innerhalb vom UndoNodesArray + { + // mit verschieben + pAktNode->pStartOfSection = aSttNdStack[ nLevel ]; + nInsPos++; + } + else // in ein "normales" Nodes-Array verschieben + { + // dann muss an der akt. InsPos auch ein SectionNode + // (Start/Ende) stehen; dann diesen ueberspringen. + // Andernfalls nicht weiter beachten. + if( nInsPos ) // verschieb schon mal alle bis hier her + { + // loeschen und kopieren. ACHTUNG: die Indizies ab + // "aRg.aEnd+1" werden mit verschoben !! + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + aIdx -= nInsPos; + nInsPos = 0; + } + SwNode* pTmpNd = &aIdx.GetNode(); + if( pTmpNd->IsSectionNode() || + pTmpNd->StartOfSectionNode()->IsSectionNode() ) + aIdx--; // ueberspringen + } + } + else { + OSL_FAIL( "wie kommt diser Node ins Nodes-Array??" ); + } + aRg.aEnd--; + break; + + default: + OSL_FAIL( "was ist das fuer ein Node??" ); + break; + } + + if( nInsPos ) // kopiere den Rest + { + // der Rest muesste so stimmen + SwNodeIndex aSwIndex( aRg.aEnd, 1 ); + ChgNode( aSwIndex, nInsPos, aIdx, bNewFrms ); + } + aRg.aEnd++; // wieder exklusive Ende + + // loesche alle leeren Start-/End-Node-Paare + if( ( pAktNode = &aRg.aStart.GetNode())->GetStartNode() && + pAktNode->StartOfSectionIndex() && + aRg.aEnd.GetNode().GetEndNode() ) + DelNodes( aRg.aStart, 2 ); + + // rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf + aOrigInsPos.aStart++; + // im gleichen Nodes-Array verschoben ??, + // dann von oben nach unten das Update aufrufen !! + if( this == &rNodes && + aRg.aEnd.GetIndex() >= aOrigInsPos.aStart.GetIndex() ) + { + UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() ); + UpdtOutlineIdx( aRg.aEnd.GetNode() ); + } + else + { + UpdtOutlineIdx( aRg.aEnd.GetNode() ); + rNodes.UpdtOutlineIdx( aOrigInsPos.aStart.GetNode() ); + } + + return sal_True; +} + + +/******************************************************************* +|* +|* SwNodes::SectionDown +|* +|* Beschreibung +|* SectionDown() legt ein Paar von Start- und EndSection-Node +|* (andere Nodes koennen dazwischen liegen) an. +|* +|* Zustand des SRange beim Verlassen der Funktion: nStart ist der +|* Index des ersten Node hinter dem Start Section Node, nEnd ist +|* der Index des End Section Nodes. Beispiel: Wird Insert Section +|* mehrmals hintereinander aufgerufen, so werden mehrere +|* unmittelbar geschachtelte Sections (keine Content Nodes +|* zwischen Start- bzw. End Nodes) angelegt. +|* +|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !! +|* ( 1.Node: aStart, letzer Node: aEnd-1 !! ) +|* +|* Parameter +|* SwRange &rRange +|* IO: +|* IN +|* rRange.aStart: Einfuegeposition des StartNodes +|* rRange.aEnd: Einfuegeposition des EndNodes +|* OUT +|* rRange.aStart: steht hinter dem eingefuegten Startnode +|* rRange.aEnd: steht auf dem eingefuegen Endnode +|* +|* Ausnahmen +|* 1. SRange-Anfang und SRange-Ende muessen auf dem gleichen Level sein +|* 2. duerfen nicht auf dem obersten Level sein +|* Ist dies nicht der Fall, wird die +|* Funktion durch Aufruf von ERR_RAISE verlassen. +|* +|* Debug-Funktionen +|* die Debugging Tools geben rRange beim Eintritt und beim +|* Verlassen der Funktion aus +|* +*******************************************************************/ +void SwNodes::SectionDown(SwNodeRange *pRange, SwStartNodeType eSttNdTyp ) +{ + if( pRange->aStart >= pRange->aEnd || + pRange->aEnd >= Count() || + !CheckNodesRange( pRange->aStart, pRange->aEnd )) + return; + + // Ist der Anfang vom Bereich vor oder auf einem EndNode, so loesche + // diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen. + // Bei anderen Nodes wird eine neuer StartNode eingefuegt + SwNode * pAktNode = &pRange->aStart.GetNode(); + SwNodeIndex aTmpIdx( *pAktNode->StartOfSectionNode() ); + + if( pAktNode->GetEndNode() ) + DelNodes( pRange->aStart, 1 ); // verhinder leere Section + else + { + // fuege einen neuen StartNode ein + SwNode* pSttNd = new SwStartNode( pRange->aStart, ND_STARTNODE, eSttNdTyp ); + pRange->aStart = *pSttNd; + aTmpIdx = pRange->aStart; + } + + // Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche + // diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen + // Bei anderen Nodes wird eine neuer EndNode eingefuegt + pRange->aEnd--; + if( pRange->aEnd.GetNode().GetStartNode() ) + DelNodes( pRange->aEnd, 1 ); + else + { + pRange->aEnd++; + // fuege einen neuen EndNode ein + new SwEndNode( pRange->aEnd, *pRange->aStart.GetNode().GetStartNode() ); + } + pRange->aEnd--; + + SectionUpDown( aTmpIdx, pRange->aEnd ); +} + +/******************************************************************* +|* +|* SwNodes::SectionUp +|* +|* Beschreibung +|* Der von rRange umspannte Bereich wird auf die naechst hoehere +|* Ebene gehoben. Das geschieht dadurch, dass bei +|* rRange.aStart ein Endnode und bei rRange.aEnd ein +|* Startnode eingefuegt wird. Die Indices fuer den Bereich +|* innerhalb von rRange werden geupdated. +|* +|* Allg.: aRange beschreibt den Bereich -exklusive- aEnd !! +|* ( 1.Node: aStart, letzer Node: aEnd-1 !! ) +|* +|* Parameter +|* SwRange &rRange +|* IO: +|* IN +|* rRange.aStart: Anfang des hoeher zubewegenden Bereiches +|* rRange.aEnd: der 1.Node hinter dem Bereich +|* OUT +|* rRange.aStart: an der ersten Position innerhalb des +|* hochbewegten Bereiches +|* rRange.aEnd: an der letzten Position innerhalb des +|* hochbewegten Bereiches +|* +|* Debug-Funktionen +|* die Debugging Tools geben rRange beim Eintritt und beim +|* Verlassen der Funktion aus +|* +*******************************************************************/ +void SwNodes::SectionUp(SwNodeRange *pRange) +{ + if( pRange->aStart >= pRange->aEnd || + pRange->aEnd >= Count() || + !CheckNodesRange( pRange->aStart, pRange->aEnd ) || + !( HighestLevel( *this, *pRange ) > 1 )) + return; + + // Ist der Anfang vom Bereich vor oder auf einem StartNode, so loesche + // diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes enstehen. + // Bei anderen Nodes wird eine neuer EndNode eingefuegt + SwNode * pAktNode = &pRange->aStart.GetNode(); + SwNodeIndex aIdx( *pAktNode->StartOfSectionNode() ); + if( pAktNode->IsStartNode() ) // selbst StartNode + { + SwEndNode* pEndNd = pRange->aEnd.GetNode().GetEndNode(); + if( pAktNode == pEndNd->pStartOfSection ) + { + // dann wurde paarig aufgehoben, also nur die im Berich neu anpassen + SwStartNode* pTmpSttNd = pAktNode->pStartOfSection; + RemoveNode( pRange->aStart.GetIndex(), 1, sal_True ); + RemoveNode( pRange->aEnd.GetIndex(), 1, sal_True ); + + SwNodeIndex aTmpIdx( pRange->aStart ); + while( aTmpIdx < pRange->aEnd ) + { + pAktNode = &aTmpIdx.GetNode(); + pAktNode->pStartOfSection = pTmpSttNd; + if( pAktNode->IsStartNode() ) + aTmpIdx = pAktNode->EndOfSectionIndex() + 1; + else + aTmpIdx++; + } + return ; + } + DelNodes( pRange->aStart, 1 ); + } + else if( aIdx == pRange->aStart.GetIndex()-1 ) // vor StartNode + DelNodes( aIdx, 1 ); + else + new SwEndNode( pRange->aStart, *aIdx.GetNode().GetStartNode() ); + + // Ist das Ende vom Bereich vor oder auf einem StartNode, so loesche + // diesen, denn sonst wuerden leere S/E-Nodes oder E/S-Nodes entstehen + // Bei anderen Nodes wird eine neuer EndNode eingefuegt + SwNodeIndex aTmpIdx( pRange->aEnd ); + if( pRange->aEnd.GetNode().IsEndNode() ) + DelNodes( pRange->aEnd, 1 ); + else + { + pAktNode = new SwStartNode( pRange->aEnd ); +/*?? welcher NodeTyp ??*/ + aTmpIdx = *pRange->aEnd.GetNode().EndOfSectionNode(); + pRange->aEnd--; + } + + SectionUpDown( aIdx, aTmpIdx ); +} + + +/************************************************************************* +|* +|* SwNodes::SectionUpDown() +|* +|* Beschreibung +|* Methode setzt die Indizies die bei SectionUp oder SectionDwon +|* veraendert wurden wieder richtig, sodass die Ebenen wieder +|* Konsistent sind. +|* +|* Parameter +|* SwIndex & aStart StartNode !!! +|* SwIndex & aEnd EndPunkt +|* +*************************************************************************/ +void SwNodes::SectionUpDown( const SwNodeIndex & aStart, const SwNodeIndex & aEnd ) +{ + SwNode * pAktNode; + SwNodeIndex aTmpIdx( aStart, +1 ); + // das Array bildet einen Stack, es werden alle StartOfSelction's gesichert + SwSttNdPtrs aSttNdStack( 1, 5 ); + SwStartNode* pTmp = aStart.GetNode().GetStartNode(); + aSttNdStack.C40_INSERT( SwStartNode, pTmp, 0 ); + + // durchlaufe bis der erste zu aendernde Start-Node gefunden wurde + // ( Es wird vom eingefuegten EndNode bis nach vorne die Indexe gesetzt ) + for( ;; aTmpIdx++ ) + { + pAktNode = &aTmpIdx.GetNode(); + pAktNode->pStartOfSection = aSttNdStack[ aSttNdStack.Count()-1 ]; + + if( pAktNode->GetStartNode() ) + { + pTmp = (SwStartNode*)pAktNode; + aSttNdStack.C40_INSERT( SwStartNode, pTmp, aSttNdStack.Count() ); + } + else if( pAktNode->GetEndNode() ) + { + SwStartNode* pSttNd = aSttNdStack[ aSttNdStack.Count() - 1 ]; + pSttNd->pEndOfSection = (SwEndNode*)pAktNode; + aSttNdStack.Remove( aSttNdStack.Count() - 1 ); + if( aSttNdStack.Count() ) + continue; // noch genuegend EndNodes auf dem Stack + + else if( aTmpIdx < aEnd ) // Uebergewicht an StartNodes + // ist das Ende noch nicht erreicht, so hole den Start von + // der uebergeordneten Section + { + aSttNdStack.C40_INSERT( SwStartNode, pSttNd->pStartOfSection, 0 ); + } + else // wenn ueber den Bereich hinaus, dann Ende + break; + } + } +} + + + + +/******************************************************************* +|* +|* SwNodes::Delete +|* +|* Beschreibung +|* Spezielle Implementierung der Delete-Funktion des +|* variablen Array. Diese spezielle Implementierung ist +|* notwendig, da durch das Loeschen von Start- bzw. +|* Endnodes Inkonsistenzen entstehen koennen. Diese werden +|* durch diese Funktion beseitigt. +|* +|* Parameter +|* IN +|* SwIndex &rIndex bezeichnet die Position, an der +|* geloescht wird +|* rIndex ist nach Aufruf der Funktion unveraendert (Kopie?!) +|* sal_uInt16 nNodes bezeichnet die Anzahl der zu loeschenden +|* Nodes; ist auf 1 defaulted +|* +|* Debug-Funktionen +|* geben beim Eintritt in die Funktion Position und Anzahl +|* der zu loeschenden Nodes aus. +|* +*******************************************************************/ +void SwNodes::Delete(const SwNodeIndex &rIndex, sal_uLong nNodes) +{ + sal_uInt16 nLevel = 0; // Level-Counter + SwNode * pAktNode; + + sal_uLong nCnt = Count() - rIndex.GetIndex() - 1; + if( nCnt > nNodes ) nCnt = nNodes; + + if( nCnt == 0 ) // keine Anzahl -> return + return; + + SwNodeRange aRg( rIndex, 0, rIndex, nCnt-1 ); + // ueberprufe ob rIndex..rIndex + nCnt ueber einen Bereich hinausragt !! + if( ( !aRg.aStart.GetNode().StartOfSectionIndex() && + !aRg.aStart.GetIndex() ) || + ! CheckNodesRange( aRg.aStart, aRg.aEnd ) ) + return; + + + // falls aEnd auf keinem ContentNode steht, dann suche den vorherigen + while( ( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() || + ( pAktNode->GetEndNode() && + !pAktNode->pStartOfSection->IsTableNode() )) + aRg.aEnd--; + + nCnt = 0; + // Start erhoehen, damit auf < abgefragt wird. ( bei <= kann es zu + // Problemen fuehren; ist aEnd == aStart und wird aEnd geloscht, + // so ist aEnd <= aStart + aRg.aStart--; + + sal_Bool bSaveInNodesDel = bInNodesDel; + bInNodesDel = sal_True; + sal_Bool bUpdateOutline = sal_False; + + // bis alles geloescht ist + while( aRg.aStart < aRg.aEnd ) + { + pAktNode = &aRg.aEnd.GetNode(); + + if( pAktNode->GetEndNode() ) + { + // die gesamte Section loeschen ? + if( pAktNode->StartOfSectionIndex() > aRg.aStart.GetIndex() ) + { + SwTableNode* pTblNd = pAktNode->pStartOfSection->GetTableNode(); + if( pTblNd ) + pTblNd->DelFrms(); + + SwNode *pNd, *pChkNd = pAktNode->pStartOfSection; + sal_uInt16 nIdxPos; + do { + pNd = &aRg.aEnd.GetNode(); + + if( pNd->IsTxtNode() ) + { + if( 0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() &&//<-end,zhaojianwei + pOutlineNds->Seek_Entry( pNd, &nIdxPos )) + { + // loesche die Gliederungs-Indizies. + pOutlineNds->Remove( nIdxPos ); + bUpdateOutline = sal_True; + } + ((SwTxtNode*)pNd)->InvalidateNumRule(); + } + else if( pNd->IsEndNode() && + pNd->pStartOfSection->IsTableNode() ) + ((SwTableNode*)pNd->pStartOfSection)->DelFrms(); + + aRg.aEnd--; + nCnt++; + + } while( pNd != pChkNd ); + } + else + { + RemoveNode( aRg.aEnd.GetIndex()+1, nCnt, sal_True ); // loesche + nCnt = 0; + aRg.aEnd--; // vor den EndNode + nLevel++; + } + } + else if( pAktNode->GetStartNode() ) // StartNode gefunden + { + if( nLevel == 0 ) // es wird eine Stufe runter gestuft + { + if( nCnt ) + { + // loesche jetzt das Array + aRg.aEnd++; + RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True ); + nCnt = 0; + } + } + else // es werden alle Nodes Innerhalb eines Start- und + { // End-Nodes geloescht, loesche mit Start/EndNode + RemoveNode( aRg.aEnd.GetIndex(), nCnt + 2, sal_True ); // loesche Array + nCnt = 0; + nLevel--; + } + + // nach dem loeschen kann aEnd auf einem EndNode stehen + // loesche alle leeren Start-/End-Node-Paare + SwNode* pTmpNode = aRg.aEnd.GetNode().GetEndNode(); + aRg.aEnd--; + while( pTmpNode && + ( pAktNode = &aRg.aEnd.GetNode())->GetStartNode() && + pAktNode->StartOfSectionIndex() ) + { + // loesche den EndNode und StartNode + DelNodes( aRg.aEnd, 2 ); + pTmpNode = aRg.aEnd.GetNode().GetEndNode(); + aRg.aEnd--; + } + } + else // normaler Node, also ins TmpArray einfuegen + { + SwTxtNode* pTxtNd = pAktNode->GetTxtNode(); + if( pTxtNd ) + { + if( pTxtNd->IsOutline()) + { // loesche die Gliederungs-Indizies. + pOutlineNds->Remove( pTxtNd ); + bUpdateOutline = sal_True; + } + pTxtNd->InvalidateNumRule(); + } + else if( pAktNode->IsCntntNode() ) + ((SwCntntNode*)pAktNode)->InvalidateNumRule(); + + aRg.aEnd--; + nCnt++; + } + } + + aRg.aEnd++; + if( nCnt != 0 ) + RemoveNode( aRg.aEnd.GetIndex(), nCnt, sal_True ); // loesche den Rest + + // loesche alle leeren Start-/End-Node-Paare + while( aRg.aEnd.GetNode().GetEndNode() && + ( pAktNode = &aRg.aStart.GetNode())->GetStartNode() && + pAktNode->StartOfSectionIndex() ) + // aber ja keinen der heiligen 5. + { + DelNodes( aRg.aStart, 2 ); // loesche den Start- und EndNode + aRg.aStart--; + } + + bInNodesDel = bSaveInNodesDel; + + if( !bInNodesDel ) + { + // rufe jetzt noch das Update fuer die Gliederung/Nummerierung auf + if( bUpdateOutline || bInDelUpdOutl ) + { + UpdtOutlineIdx( aRg.aEnd.GetNode() ); + bInDelUpdOutl = sal_False; + } + + } + else + { + if( bUpdateOutline ) + bInDelUpdOutl = sal_True; + } +} + +/******************************************************************* +|* +|* SwNodes::GetSectionLevel +|* +|* Beschreibung +|* Die Funktion liefert den Sectionlevel an der durch +|* aIndex bezeichneten Position. Die Funktion ruft die +|* GetSectionlevel-Funktion des durch aIndex bezeichneten +|* Nodes. Diese ist eine virtuelle Funktion, die fuer +|* Endnodes speziell implementiert werden musste. +|* Die Sectionlevels werden ermittelt, indem rekursiv durch +|* die Nodesstruktur (jeweils zum naechsten theEndOfSection) +|* gegangen wird, bis die oberste Ebene erreicht ist +|* (theEndOfSection == 0) +|* +|* Parameter +|* aIndex bezeichnet die Position des Nodes, dessen +|* Sectionlevel ermittelt werden soll. Hier wird eine Kopie +|* uebergeben, da eine Veraenderung der Variablen in der +|* rufenden Funktion nicht wuenschenswert ist. +|* +|* Ausnahmen +|* Der erste Node im Array sollte immer ein Startnode sein. +|* Dieser erfaehrt in der Funktion SwNodes::GetSectionLevel() +|* eine Sonderbehandlung; es wird davon ausgegangen, dass der +|* erste Node auch ein Startnode ist. +|* +*******************************************************************/ +sal_uInt16 SwNodes::GetSectionLevel(const SwNodeIndex &rIdx) const { + // Sonderbehandlung 1. Node + if(rIdx == 0) return 1; + /* + * Keine Rekursion! - hier wird das SwNode::GetSectionLevel + * aufgerufen + */ + return rIdx.GetNode().GetSectionLevel(); +} + +void SwNodes::GoStartOfSection(SwNodeIndex *pIdx) const +{ + // hinter den naechsten Startnode + SwNodeIndex aTmp( *pIdx->GetNode().StartOfSectionNode(), +1 ); + + // steht der Index auf keinem ContentNode, dann gehe dahin. Ist aber + // kein weiterer vorhanden, dann lasse den Index an alter Pos stehen !!! + while( !aTmp.GetNode().IsCntntNode() ) + { // gehe vom StartNode ( es kann nur ein StartNode sein ! ) an sein + // Ende + if( *pIdx <= aTmp ) + return; // FEHLER: Steht schon hinter der Sektion + aTmp = aTmp.GetNode().EndOfSectionIndex()+1; + if( *pIdx <= aTmp ) + return; // FEHLER: Steht schon hinter der Sektion + } + (*pIdx) = aTmp; // steht auf einem ContentNode +} + +void SwNodes::GoEndOfSection(SwNodeIndex *pIdx) const +{ + // falls er vor einem Endnode steht --> nichts tun + if( !pIdx->GetNode().IsEndNode() ) + (*pIdx) = *pIdx->GetNode().EndOfSectionNode(); +} + +SwCntntNode* SwNodes::GoNext(SwNodeIndex *pIdx) const +{ + if( pIdx->GetIndex() >= Count() - 1 ) + return 0; + + SwNodeIndex aTmp(*pIdx, +1); + SwNode* pNd = 0; + while( aTmp < Count()-1 && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() ) + aTmp++; + + if( aTmp == Count()-1 ) + pNd = 0; + else + (*pIdx) = aTmp; + return (SwCntntNode*)pNd; +} + +SwCntntNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) const +{ + if( !pIdx->GetIndex() ) + return 0; + + SwNodeIndex aTmp( *pIdx, -1 ); + SwNode* pNd = 0; + while( aTmp.GetIndex() && 0 == ( pNd = &aTmp.GetNode())->IsCntntNode() ) + aTmp--; + + if( !aTmp.GetIndex() ) + pNd = 0; + else + (*pIdx) = aTmp; + return (SwCntntNode*)pNd; +} + +/************************************************************************* +|* +|* sal_Bool SwNodes::CheckNodesRange() +|* +|* Beschreibung +|* Teste ob der uebergene SRange nicht ueber die Grenzen der +|* einzelnen Bereiche (PosIts, Autotext, Content, Icons und Inserts ) +|* hinaus reicht. +|* Nach Wahrscheinlichkeit des Ranges sortiert. +|* +|* Alg.: Da festgelegt ist, das aRange.aEnd den 1.Node hinter dem Bereich +|* bezeichnet, wird hier auf aEnd <= End.. getestet !! +|* +|* Parameter SwIndex & Start-Index vom Bereich +|* SwIndex & End-Index vom Bereich +|* sal_Bool sal_True: Start+End in gleicher Section! +|* sal_False: Start+End in verschiedenen Sect. +|* Return-Wert sal_Bool sal_True: gueltiger SRange +|* sal_False: ungueltiger SRange +|* +*************************************************************************/ + +inline int TstIdx( sal_uLong nSttIdx, sal_uLong nEndIdx, sal_uLong nStt, sal_uLong nEnd ) +{ + return nStt < nSttIdx && nEnd >= nSttIdx && + nStt < nEndIdx && nEnd >= nEndIdx; +} + +sal_Bool SwNodes::CheckNodesRange( const SwNodeIndex& rStt, const SwNodeIndex& rEnd ) const +{ + sal_uLong nStt = rStt.GetIndex(), nEnd = rEnd.GetIndex(); + if( TstIdx( nStt, nEnd, pEndOfContent->StartOfSectionIndex(), + pEndOfContent->GetIndex() )) return sal_True; + if( TstIdx( nStt, nEnd, pEndOfAutotext->StartOfSectionIndex(), + pEndOfAutotext->GetIndex() )) return sal_True; + if( TstIdx( nStt, nEnd, pEndOfPostIts->StartOfSectionIndex(), + pEndOfPostIts->GetIndex() )) return sal_True; + if( TstIdx( nStt, nEnd, pEndOfInserts->StartOfSectionIndex(), + pEndOfInserts->GetIndex() )) return sal_True; + if( TstIdx( nStt, nEnd, pEndOfRedlines->StartOfSectionIndex(), + pEndOfRedlines->GetIndex() )) return sal_True; + + return sal_False; // liegt irgendwo dazwischen, FEHLER +} + + +/************************************************************************* +|* +|* void SwNodes::DelNodes() +|* +|* Beschreibung +|* Loesche aus den NodesArray ab einer Position entsprechend Node's. +|* +|* Parameter SwIndex & Der Startpunkt im Nodes-Array +|* sal_uInt16 die Anzahl +|* +*************************************************************************/ +void SwNodes::DelNodes( const SwNodeIndex & rStart, sal_uLong nCnt ) +{ + sal_uLong nSttIdx = rStart.GetIndex(); + + if( !nSttIdx && nCnt == GetEndOfContent().GetIndex()+1 ) + { + // es wird das gesamte Nodes-Array zerstoert, man ist im Doc DTOR! + // Die initialen Start-/End-Nodes duerfen nur im SwNodes-DTOR + // zerstoert werden! + SwNode* aEndNdArr[] = { pEndOfContent, + pEndOfPostIts, pEndOfInserts, + pEndOfAutotext, pEndOfRedlines, + 0 + }; + + SwNode** ppEndNdArr = aEndNdArr; + while( *ppEndNdArr ) + { + nSttIdx = (*ppEndNdArr)->StartOfSectionIndex() + 1; + sal_uLong nEndIdx = (*ppEndNdArr)->GetIndex(); + + if( nSttIdx != nEndIdx ) + RemoveNode( nSttIdx, nEndIdx - nSttIdx, sal_True ); + + ++ppEndNdArr; + } + } + else + { + int bUpdateNum = 0; + for( sal_uLong n = nSttIdx, nEnd = nSttIdx + nCnt; n < nEnd; ++n ) + { + SwNode* pNd = (*this)[ n ]; + + if( pNd->IsTxtNode() && + 0 != ((SwTxtNode*)pNd)->GetAttrOutlineLevel() ) //<-end,zhaojianwei + { // loesche die Gliederungs-Indizies. + sal_uInt16 nIdxPos; + if( pOutlineNds->Seek_Entry( pNd, &nIdxPos )) + { + pOutlineNds->Remove( nIdxPos ); + bUpdateNum = 1; + } + } + if( pNd->IsCntntNode() ) + { + ((SwCntntNode*)pNd)->InvalidateNumRule(); + ((SwCntntNode*)pNd)->DelFrms(); + } + } + RemoveNode( nSttIdx, nCnt, sal_True ); + + // rufe noch das Update fuer die Gliederungsnumerierung auf + if( bUpdateNum ) + UpdtOutlineIdx( rStart.GetNode() ); + } +} + + +/************************************************************************* +|* +|* sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange ) +|* +|* Beschreibung +|* Berechne den hoehsten Level innerhalb des Bereiches +|* +|* Parameter SwNodes & das Node-Array +|* SwNodeRange & der zu ueberpruefende Bereich +|* Return sal_uInt16 der hoechste Level +|* +*************************************************************************/ + +struct HighLevel +{ + sal_uInt16 nLevel, nTop; + HighLevel( sal_uInt16 nLv ) : nLevel( nLv ), nTop( nLv ) {} + +}; + +sal_Bool _HighestLevel( const SwNodePtr& rpNode, void * pPara ) +{ + HighLevel * pHL = (HighLevel*)pPara; + if( rpNode->GetStartNode() ) + pHL->nLevel++; + else if( rpNode->GetEndNode() ) + pHL->nLevel--; + if( pHL->nTop > pHL->nLevel ) + pHL->nTop = pHL->nLevel; + return sal_True; + +} + +sal_uInt16 HighestLevel( SwNodes & rNodes, const SwNodeRange & rRange ) +{ + HighLevel aPara( rNodes.GetSectionLevel( rRange.aStart )); + rNodes.ForEach( rRange.aStart, rRange.aEnd, _HighestLevel, &aPara ); + return aPara.nTop; + +} + +/************************************************************************* +|* +|* SwNodes::Move() +|* +|* Beschreibung +|* Parameter SwPaM& zu kopierender Bereich +|* SwNodes& in dieses Nodes-Array +|* SwPosition& auf diese Position im Nodes-Array +|* +*************************************************************************/ +void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes ) +{ + SwPosition * const pStt = rPam.Start(); + SwPosition * const pEnd = rPam.End(); + + if( !rPam.HasMark() || *pStt >= *pEnd ) + return; + + if( this == &rNodes && *pStt <= rPos && rPos < *pEnd ) + return; + + SwNodeIndex aEndIdx( pEnd->nNode ); + SwNodeIndex aSttIdx( pStt->nNode ); + SwTxtNode *const pSrcNd = aSttIdx.GetNode().GetTxtNode(); + SwTxtNode * pDestNd = rPos.nNode.GetNode().GetTxtNode(); + sal_Bool bSplitDestNd = sal_True; + sal_Bool bCopyCollFmt = pDestNd && !pDestNd->GetTxt().Len(); + + if( pSrcNd ) + { + // ist der 1.Node ein TextNode, dann muss im NodesArray auch + // ein TextNode vorhanden sein, in den der Inhalt geschoben wird + if( !pDestNd ) + { + pDestNd = rNodes.MakeTxtNode( rPos.nNode, pSrcNd->GetTxtColl() ); + rPos.nNode--; + rPos.nContent.Assign( pDestNd, 0 ); + bCopyCollFmt = sal_True; + } + bSplitDestNd = pDestNd->Len() > rPos.nContent.GetIndex() || + pEnd->nNode.GetNode().IsTxtNode(); + + // verschiebe jetzt noch den Inhalt in den neuen Node + sal_Bool bOneNd = pStt->nNode == pEnd->nNode; + const xub_StrLen nLen = + ( (bOneNd) ? pEnd->nContent.GetIndex() : pSrcNd->Len() ) + - pStt->nContent.GetIndex(); + + if( !pEnd->nNode.GetNode().IsCntntNode() ) + { + bOneNd = sal_True; + sal_uLong nSttNdIdx = pStt->nNode.GetIndex() + 1; + const sal_uLong nEndNdIdx = pEnd->nNode.GetIndex(); + for( ; nSttNdIdx < nEndNdIdx; ++nSttNdIdx ) + { + if( (*this)[ nSttNdIdx ]->IsCntntNode() ) + { + bOneNd = sal_False; + break; + } + } + } + + // das kopieren / setzen der Vorlagen darf erst nach + // dem Splitten erfolgen + if( !bOneNd && bSplitDestNd ) + { + if( !rPos.nContent.GetIndex() ) + { + bCopyCollFmt = sal_True; + } + if( rNodes.IsDocNodes() ) + { + SwDoc* const pInsDoc = pDestNd->GetDoc(); + ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo()); + pInsDoc->SplitNode( rPos, false ); + } + else + { + pDestNd->SplitCntntNode( rPos ); + } + + if( rPos.nNode == aEndIdx ) + { + aEndIdx--; + } + bSplitDestNd = sal_True; + + pDestNd = rNodes[ rPos.nNode.GetIndex() - 1 ]->GetTxtNode(); + if( nLen ) + { + pSrcNd->CutText( pDestNd, SwIndex( pDestNd, pDestNd->Len()), + pStt->nContent, nLen ); + } + } + else if ( nLen ) + { + pSrcNd->CutText( pDestNd, rPos.nContent, pStt->nContent, nLen ); + } + + if( bCopyCollFmt ) + { + SwDoc* const pInsDoc = pDestNd->GetDoc(); + ::sw::UndoGuard const undoGuard(pInsDoc->GetIDocumentUndoRedo()); + pSrcNd->CopyCollFmt( *pDestNd ); + bCopyCollFmt = sal_False; + } + + if( bOneNd ) // das wars schon + { + // der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben + // wurde, so stehen sie in unterschieden Nodes. Auch die Selektion + // wird aufgehoben ! + pEnd->nContent = pStt->nContent; + rPam.DeleteMark(); + GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0, + rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) ); + return; + } + + aSttIdx++; + } + else if( pDestNd ) + { + if( rPos.nContent.GetIndex() ) + { + if( rPos.nContent.GetIndex() == pDestNd->Len() ) + { + rPos.nNode++; + } + else if( rPos.nContent.GetIndex() ) + { + // falls im EndNode gesplittet wird, dann muss der EndIdx + // korrigiert werden !! + const bool bCorrEnd = aEndIdx == rPos.nNode; + // es wird kein Text an den TextNode angehaengt, also splitte ihn + + if( rNodes.IsDocNodes() ) + { + SwDoc* const pInsDoc = pDestNd->GetDoc(); + ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo()); + pInsDoc->SplitNode( rPos, false ); + } + else + { + pDestNd->SplitCntntNode( rPos ); + } + + pDestNd = rPos.nNode.GetNode().GetTxtNode(); + + if ( bCorrEnd ) + { + aEndIdx--; + } + } + } + // am Ende steht noch ein leerer Text Node herum. + bSplitDestNd = sal_True; + } + + SwTxtNode* const pEndSrcNd = aEndIdx.GetNode().GetTxtNode(); + if ( pEndSrcNd ) + { + { + // am Bereichsende entsteht ein neuer TextNode + if( !bSplitDestNd ) + { + if( rPos.nNode < rNodes.GetEndOfContent().GetIndex() ) + { + rPos.nNode++; + } + + pDestNd = + rNodes.MakeTxtNode( rPos.nNode, pEndSrcNd->GetTxtColl() ); + rPos.nNode--; + rPos.nContent.Assign( pDestNd, 0 ); + } + else + { + pDestNd = rPos.nNode.GetNode().GetTxtNode(); + } + + if( pDestNd && pEnd->nContent.GetIndex() ) + { + // verschiebe jetzt noch den Inhalt in den neuen Node + SwIndex aIdx( pEndSrcNd, 0 ); + pEndSrcNd->CutText( pDestNd, rPos.nContent, aIdx, + pEnd->nContent.GetIndex()); + } + + if( bCopyCollFmt ) + { + SwDoc* const pInsDoc = pDestNd->GetDoc(); + ::sw::UndoGuard const ug(pInsDoc->GetIDocumentUndoRedo()); + pEndSrcNd->CopyCollFmt( *pDestNd ); + } + } + } + else + { + if ( pSrcNd && aEndIdx.GetNode().IsCntntNode() ) + { + aEndIdx++; + } + if( !bSplitDestNd ) + { + rPos.nNode++; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), 0 ); + } + } + + if( aEndIdx != aSttIdx ) + { + // verschiebe jetzt die Nodes in das NodesArary + const sal_uLong nSttDiff = aSttIdx.GetIndex() - pStt->nNode.GetIndex(); + SwNodeRange aRg( aSttIdx, aEndIdx ); + _MoveNodes( aRg, rNodes, rPos.nNode ); + // falls ins gleiche Nodes-Array verschoben wurde, stehen die + // Indizies jetzt auch an der neuen Position !!!! + // (also alles wieder umsetzen) + if( &rNodes == this ) + { + pStt->nNode = aRg.aEnd.GetIndex() - nSttDiff; + } + } + + // falls der Start-Node verschoben wurde, in dem der Cursor stand, so + // muss der Content im akt. Content angemeldet werden !!! + if ( &pStt->nNode.GetNode() == &GetEndOfContent() ) + { + const bool bSuccess = GoPrevious( &pStt->nNode ); + OSL_ENSURE( bSuccess, "Move() - no ContentNode here" ); + (void) bSuccess; + } + pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(), + pStt->nContent.GetIndex() ); + // der PaM wird korrigiert, denn falls ueber Nodegrenzen verschoben + // wurde, so stehen sie in unterschielichen Nodes. Auch die Selektion + // wird aufgehoben ! + *pEnd = *pStt; + rPam.DeleteMark(); + GetDoc()->GetDocShell()->Broadcast( SwFmtFldHint( 0, + rNodes.IsDocNodes() ? SWFMTFLD_INSERTED : SWFMTFLD_REMOVED ) ); +} + + + +/************************************************************************* +|* +|* SwNodes::_Copy() +|* +|* Beschreibung +|* Parameter SwNodeRange& zu kopierender Bereich +|* SwDoc& in dieses Dokument +|* SwIndex& auf diese Position im Nodes-Array +|* +*************************************************************************/ + +inline sal_uInt8 MaxLvl( sal_uInt8 nMin, sal_uInt8 nMax, short nNew ) +{ + return (sal_uInt8)(nNew < nMin ? nMin : nNew > nMax ? nMax : nNew); +} + +void SwNodes::_CopyNodes( const SwNodeRange& rRange, + const SwNodeIndex& rIndex, sal_Bool bNewFrms, sal_Bool bTblInsDummyNode ) const +{ + SwDoc* pDoc = rIndex.GetNode().GetDoc(); + + SwNode * pAktNode; + if( rIndex == 0 || + ( (pAktNode = &rIndex.GetNode())->GetStartNode() && + !pAktNode->StartOfSectionIndex() )) + return; + + SwNodeRange aRg( rRange ); + + // "einfache" StartNodes oder EndNodes ueberspringen + while( ND_STARTNODE == (pAktNode = & aRg.aStart.GetNode())->GetNodeType() + || ( pAktNode->IsEndNode() && + !pAktNode->pStartOfSection->IsSectionNode() ) ) + aRg.aStart++; + + // falls aEnd-1 auf keinem ContentNode steht, dann suche den vorherigen + aRg.aEnd--; + // #i107142#: if aEnd is start node of a special section, do nothing. + // Otherwise this could lead to crash: going through all previous + // special section nodes and then one before the first. + if (aRg.aEnd.GetNode().StartOfSectionIndex() != 0) + { + while( ((pAktNode = & aRg.aEnd.GetNode())->GetStartNode() && + !pAktNode->IsSectionNode() ) || + ( pAktNode->IsEndNode() && + ND_STARTNODE == pAktNode->pStartOfSection->GetNodeType()) ) + { + aRg.aEnd--; + } + } + aRg.aEnd++; + + // wird im selben Array's verschoben, dann ueberpruefe die Einfuegepos. + if( aRg.aStart >= aRg.aEnd ) + return; + + // when inserting into the source range, nothing need to be done + DBG_ASSERT( &aRg.aStart.GetNodes() == this, + "aRg should use thisnodes array" ); + DBG_ASSERT( &aRg.aStart.GetNodes() == &aRg.aEnd.GetNodes(), + "Range across different nodes arrays? You deserve punishment!"); + if( &rIndex.GetNodes() == &aRg.aStart.GetNodes() && + rIndex.GetIndex() >= aRg.aStart.GetIndex() && + rIndex.GetIndex() < aRg.aEnd.GetIndex() ) + return; + + SwNodeIndex aInsPos( rIndex ); + SwNodeIndex aOrigInsPos( rIndex, -1 ); // Originale Insert Pos + sal_uInt16 nLevel = 0; // Level-Counter + + for( sal_uLong nNodeCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex(); + nNodeCnt > 0; --nNodeCnt ) + { + pAktNode = &aRg.aStart.GetNode(); + switch( pAktNode->GetNodeType() ) + { + case ND_TABLENODE: + // dann kopiere mal den TableNode + // Tabell in Fussnote kopieren ? + if( aInsPos < pDoc->GetNodes().GetEndOfInserts().GetIndex() && + pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex() + < aInsPos.GetIndex() ) + { + sal_uLong nDistance = + ( pAktNode->EndOfSectionIndex() - + aRg.aStart.GetIndex() ); + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + + // dann alle Nodes der Tabelle in die akt. Zelle kopieren + // fuer den TabellenNode einen DummyNode einfuegen? + if( bTblInsDummyNode ) + new SwNode( aInsPos, ND_SECTIONDUMMY ); + + for( aRg.aStart++; aRg.aStart.GetIndex() < + pAktNode->EndOfSectionIndex(); + aRg.aStart++ ) + { + // fuer den Box-StartNode einen DummyNode einfuegen? + if( bTblInsDummyNode ) + new SwNode( aInsPos, ND_SECTIONDUMMY ); + + SwStartNode* pSttNd = aRg.aStart.GetNode().GetStartNode(); + _CopyNodes( SwNodeRange( *pSttNd, + 1, + *pSttNd->EndOfSectionNode() ), + aInsPos, bNewFrms, sal_False ); + + // fuer den Box-EndNode einen DummyNode einfuegen? + if( bTblInsDummyNode ) + new SwNode( aInsPos, ND_SECTIONDUMMY ); + aRg.aStart = *pSttNd->EndOfSectionNode(); + } + // fuer den TabellenEndNode einen DummyNode einfuegen? + if( bTblInsDummyNode ) + new SwNode( aInsPos, ND_SECTIONDUMMY ); + aRg.aStart = *pAktNode->EndOfSectionNode(); + } + else + { + SwNodeIndex nStt( aInsPos, -1 ); + SwTableNode* pTblNd = ((SwTableNode*)pAktNode)-> + MakeCopy( pDoc, aInsPos ); + sal_uLong nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + + aRg.aStart = pAktNode->EndOfSectionIndex(); + + if( bNewFrms && pTblNd ) + { + nStt = aInsPos; + pTblNd->MakeFrms( &nStt ); + } + } + break; + + case ND_SECTIONNODE: // SectionNode + // If the end of the section is outside the copy range, + // the section node will skipped, not copied! + // If someone want to change this behaviour, he has to adjust the function + // lcl_NonCopyCount(..) in ndcopy.cxx which relies on it. + if( pAktNode->EndOfSectionIndex() < aRg.aEnd.GetIndex() ) + { + // also der gesamte, lege einen neuen SectionNode an + SwNodeIndex nStt( aInsPos, -1 ); + SwSectionNode* pSectNd = ((SwSectionNode*)pAktNode)-> + MakeCopy( pDoc, aInsPos ); + + sal_uLong nDistance = aInsPos.GetIndex() - nStt.GetIndex() - 2; + if (nDistance < nNodeCnt) + nNodeCnt -= nDistance; + else + nNodeCnt = 1; + aRg.aStart = pAktNode->EndOfSectionIndex(); + + if( bNewFrms && pSectNd && + !pSectNd->GetSection().IsHidden() ) + pSectNd->MakeFrms( &nStt ); + } + break; + + case ND_STARTNODE: // StartNode gefunden + { + SwStartNode* pTmp = new SwStartNode( aInsPos, ND_STARTNODE, + ((SwStartNode*)pAktNode)->GetStartNodeType() ); + new SwEndNode( aInsPos, *pTmp ); + aInsPos--; + nLevel++; + } + break; + + case ND_ENDNODE: + if( nLevel ) // vollstaendige Section + { + --nLevel; + aInsPos++; // EndNode schon vorhanden + } + else if( !pAktNode->pStartOfSection->IsSectionNode() ) + { + // erzeuge eine Section an der originalen InsertPosition + SwNodeRange aTmpRg( aOrigInsPos, 1, aInsPos ); + pDoc->GetNodes().SectionDown( &aTmpRg, + pAktNode->pStartOfSection->GetStartNodeType() ); + } + break; + + case ND_TEXTNODE: + case ND_GRFNODE: + case ND_OLENODE: + { + SwCntntNode* pNew = ((SwCntntNode*)pAktNode)->MakeCopy( + pDoc, aInsPos ); + if( !bNewFrms ) // dflt. werden die Frames immer angelegt + pNew->DelFrms(); + } + break; + + case ND_SECTIONDUMMY: + if (GetDoc()->GetIDocumentUndoRedo().IsUndoNodes(*this)) + { + // dann muss an der akt. InsPos auch ein SectionNode + // (Start/Ende) stehen; dann diesen ueberspringen. + // Andernfalls nicht weiter beachten. + SwNode *const pTmpNd = & aInsPos.GetNode(); + if( pTmpNd->IsSectionNode() || + pTmpNd->StartOfSectionNode()->IsSectionNode() ) + aInsPos++; // ueberspringen + } + else { + OSL_FAIL( "wie kommt diser Node ins Nodes-Array??" ); + } + break; + + default: + OSL_FAIL( "weder Start-/End-/Content-Node, unbekannter Typ" ); + } + aRg.aStart++; + } +} + +void SwNodes::_DelDummyNodes( const SwNodeRange& rRg ) +{ + SwNodeIndex aIdx( rRg.aStart ); + while( aIdx.GetIndex() < rRg.aEnd.GetIndex() ) + { + if( ND_SECTIONDUMMY == aIdx.GetNode().GetNodeType() ) + RemoveNode( aIdx.GetIndex(), 1, sal_True ); + else + aIdx++; + } +} + +SwStartNode* SwNodes::MakeEmptySection( const SwNodeIndex& rIdx, + SwStartNodeType eSttNdTyp ) +{ + SwStartNode* pSttNd = new SwStartNode( rIdx, ND_STARTNODE, eSttNdTyp ); + new SwEndNode( rIdx, *pSttNd ); + return pSttNd; +} + + +SwStartNode* SwNodes::MakeTextSection( const SwNodeIndex & rWhere, + SwStartNodeType eSttNdTyp, + SwTxtFmtColl *pColl, + SwAttrSet* pAutoAttr ) +{ + SwStartNode* pSttNd = new SwStartNode( rWhere, ND_STARTNODE, eSttNdTyp ); + new SwEndNode( rWhere, *pSttNd ); + MakeTxtNode( SwNodeIndex( rWhere, - 1 ), pColl, pAutoAttr ); + return pSttNd; +} + + // zum naechsten Content-Node, der nicht geschuetzt oder versteckt ist + // (beides auf sal_False ==> GoNext/GoPrevious!!!) +SwCntntNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, + int bSkipHidden, int bSkipProtect ) const +{ + int bFirst = sal_True; + SwNodeIndex aTmp( *pIdx ); + const SwNode* pNd; + while( aTmp < Count() - 1 ) + { + pNd = & aTmp.GetNode(); + if (ND_SECTIONNODE == pNd->GetNodeType()) + { + const SwSection& rSect = ((SwSectionNode*)pNd)->GetSection(); + if( (bSkipHidden && rSect.IsHiddenFlag()) || + (bSkipProtect && rSect.IsProtectFlag()) ) + // dann diese Section ueberspringen + aTmp = *pNd->EndOfSectionNode(); + bFirst = sal_False; + } + else if( bFirst ) + { + bFirst = sal_False; + if( pNd->pStartOfSection->IsSectionNode() ) + { + const SwSection& rSect = ((SwSectionNode*)pNd-> + pStartOfSection)->GetSection(); + if( (bSkipHidden && rSect.IsHiddenFlag()) || + (bSkipProtect && rSect.IsProtectFlag()) ) + // dann diese Section ueberspringen + aTmp = *pNd->EndOfSectionNode(); + } + } + else if( ND_CONTENTNODE & pNd->GetNodeType() ) + { + const SwSectionNode* pSectNd; + if( ( bSkipHidden || bSkipProtect ) && + 0 != (pSectNd = pNd->FindSectionNode() ) && + ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || + ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) + { + aTmp = *pSectNd->EndOfSectionNode(); + } + else + { + (*pIdx) = aTmp; + return (SwCntntNode*)pNd; + } + } + aTmp++; + bFirst = sal_False; + } + return 0; +} + +SwCntntNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx, + int bSkipHidden, int bSkipProtect ) const +{ + int bFirst = sal_True; + SwNodeIndex aTmp( *pIdx ); + const SwNode* pNd; + while( aTmp > 0 ) + { + pNd = & aTmp.GetNode(); + if (ND_ENDNODE == pNd->GetNodeType()) + { + if( pNd->pStartOfSection->IsSectionNode() ) + { + const SwSection& rSect = ((SwSectionNode*)pNd-> + pStartOfSection)->GetSection(); + if( (bSkipHidden && rSect.IsHiddenFlag()) || + (bSkipProtect && rSect.IsProtectFlag()) ) + // dann diese Section ueberspringen + aTmp = *pNd->StartOfSectionNode(); + } + bFirst = sal_False; + } + else if( bFirst ) + { + bFirst = sal_False; + if( pNd->pStartOfSection->IsSectionNode() ) + { + const SwSection& rSect = ((SwSectionNode*)pNd-> + pStartOfSection)->GetSection(); + if( (bSkipHidden && rSect.IsHiddenFlag()) || + (bSkipProtect && rSect.IsProtectFlag()) ) + // dann diese Section ueberspringen + aTmp = *pNd->StartOfSectionNode(); + } + } + else if( ND_CONTENTNODE & pNd->GetNodeType() ) + { + const SwSectionNode* pSectNd; + if( ( bSkipHidden || bSkipProtect ) && + 0 != (pSectNd = pNd->FindSectionNode() ) && + ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || + ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) + { + aTmp = *pSectNd; + } + else + { + (*pIdx) = aTmp; + return (SwCntntNode*)pNd; + } + } + aTmp--; + } + return 0; +} + + + // suche den vorhergehenden [/nachfolgenden ] ContentNode oder + // TabellenNode mit Frames. Wird kein Ende angeben, dann wird mit + // dem FrameIndex begonnen; ansonsten, wird mit dem vor rFrmIdx und + // dem hintern pEnd die Suche gestartet. Sollte kein gueltiger Node + // gefunden werden, wird 0 returnt. rFrmIdx zeigt auf dem Node mit + // Frames +SwNode* SwNodes::FindPrvNxtFrmNode( SwNodeIndex& rFrmIdx, + const SwNode* pEnd ) const +{ + SwNode* pFrmNd = 0; + + // habe wir gar kein Layout, vergiss es + if( GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225 + { + SwNode* pSttNd = &rFrmIdx.GetNode(); + + // wird in eine versteckte Section verschoben ?? + SwSectionNode* pSectNd = pSttNd->IsSectionNode() + ? pSttNd->StartOfSectionNode()->FindSectionNode() + : pSttNd->FindSectionNode(); + if( !( pSectNd && pSectNd->GetSection().CalcHiddenFlag()/*IsHiddenFlag()*/ ) ) + { + // in a table in table situation we have to assure that we don't leave the + // outer table cell when the inner table is looking for a PrvNxt... + SwTableNode* pTableNd = pSttNd->IsTableNode() + ? pSttNd->StartOfSectionNode()->FindTableNode() + : pSttNd->FindTableNode(); + SwNodeIndex aIdx( rFrmIdx ); + SwNode* pNd; + if( pEnd ) + { + aIdx--; + pNd = &aIdx.GetNode(); + } + else + pNd = pSttNd; + + if( ( pFrmNd = pNd )->IsCntntNode() ) + rFrmIdx = aIdx; + + // suche nach vorne/hinten nach einem Content Node + else if( 0 != ( pFrmNd = GoPrevSection( &aIdx, sal_True, sal_False )) && + ::CheckNodesRange( aIdx, rFrmIdx, sal_True ) && + // nach vorne nie aus der Tabelle hinaus! + pFrmNd->FindTableNode() == pTableNd && + // Bug 37652: nach hinten nie aus der Tabellenzelle hinaus! + (!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode() + == pSttNd->FindTableBoxStartNode() ) && + (!pSectNd || pSttNd->IsSectionNode() || + pSectNd->GetIndex() < pFrmNd->GetIndex()) + ) + { + rFrmIdx = aIdx; + } + else + { + if( pEnd ) + aIdx = pEnd->GetIndex() + 1; + else + aIdx = rFrmIdx; + + // JP 19.09.93: aber nie die Section dafuer verlassen !! + if( ( pEnd && ( pFrmNd = &aIdx.GetNode())->IsCntntNode() ) || + ( 0 != ( pFrmNd = GoNextSection( &aIdx, sal_True, sal_False )) && + ::CheckNodesRange( aIdx, rFrmIdx, sal_True ) && + ( pFrmNd->FindTableNode() == pTableNd && + // Bug 37652: nach hinten nie aus der Tabellenzelle hinaus! + (!pFrmNd->FindTableNode() || pFrmNd->FindTableBoxStartNode() + == pSttNd->FindTableBoxStartNode() ) ) && + (!pSectNd || pSttNd->IsSectionNode() || + pSectNd->EndOfSectionIndex() > pFrmNd->GetIndex()) + )) + { + //JP 18.02.99: Undo von Merge einer Tabelle mit der + // der vorherigen, wenn dahinter auch noch eine steht + // falls aber der Node in einer Tabelle steht, muss + // natuerlich dieser returnt werden, wenn der SttNode eine + // Section oder Tabelle ist! + SwTableNode* pTblNd; + if( pSttNd->IsTableNode() && + 0 != ( pTblNd = pFrmNd->FindTableNode() ) && + // TABLE IN TABLE: + pTblNd != pSttNd->StartOfSectionNode()->FindTableNode() ) + { + pFrmNd = pTblNd; + rFrmIdx = *pFrmNd; + } + else + rFrmIdx = aIdx; + } + else if( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() ) + { + pFrmNd = pNd->StartOfSectionNode(); + rFrmIdx = *pFrmNd; + } + else + { + if( pEnd ) + aIdx = pEnd->GetIndex() + 1; + else + aIdx = rFrmIdx.GetIndex() + 1; + + if( (pFrmNd = &aIdx.GetNode())->IsTableNode() ) + rFrmIdx = aIdx; + else + { + pFrmNd = 0; + + // is there some sectionnodes before a tablenode? + while( aIdx.GetNode().IsSectionNode() ) + { + const SwSection& rSect = aIdx.GetNode(). + GetSectionNode()->GetSection(); + if( rSect.IsHiddenFlag() ) + aIdx = aIdx.GetNode().EndOfSectionIndex()+1; + else + aIdx++; + } + if( aIdx.GetNode().IsTableNode() ) + { + rFrmIdx = aIdx; + pFrmNd = &aIdx.GetNode(); + } + } + } + } + } + } + return pFrmNd; +} + +void SwNodes::ForEach( const SwNodeIndex& rStart, const SwNodeIndex& rEnd, + FnForEach_SwNodes fnForEach, void* pArgs ) +{ + BigPtrArray::ForEach( rStart.GetIndex(), rEnd.GetIndex(), + (FnForEach) fnForEach, pArgs ); +} + +struct _TempBigPtrEntry : public BigPtrEntry +{ + _TempBigPtrEntry() {} +}; + + +void SwNodes::RemoveNode( sal_uLong nDelPos, sal_uLong nSz, sal_Bool bDel ) +{ + sal_uLong nEnd = nDelPos + nSz; + SwNode* pNew = (*this)[ nEnd ]; + + if( pRoot ) + { + SwNodeIndex *p = pRoot; + while( p ) + { + sal_uLong nIdx = p->GetIndex(); + SwNodeIndex* pNext = p->pNext; + if( nDelPos <= nIdx && nIdx < nEnd ) + (*p) = *pNew; + + p = pNext; + } + + p = pRoot->pPrev; + while( p ) + { + sal_uLong nIdx = p->GetIndex(); + SwNodeIndex* pPrev = p->pPrev; + if( nDelPos <= nIdx && nIdx < nEnd ) + (*p) = *pNew; + + p = pPrev; + } + } + + { + for (sal_uLong nCnt = 0; nCnt < nSz; nCnt++) + { + SwTxtNode * pTxtNd = ((*this)[ nDelPos + nCnt ])->GetTxtNode(); + + if (pTxtNd) + { + pTxtNd->RemoveFromList(); + } + } + } + + if( bDel ) + { + sal_uLong nCnt = nSz; + SwNode *pDel = (*this)[ nDelPos+nCnt-1 ], *pPrev = (*this)[ nDelPos+nCnt-2 ]; + +// temp. Object setzen + //JP 24.08.98: muessten eigentlich einzeln removed werden, weil + // das Remove auch rekursiv gerufen werden kann, z.B. bei + // zeichengebundenen Rahmen. Da aber dabei viel zu viel + // ablaueft, wird hier ein temp. Objekt eingefuegt, das + // dann mit dem Remove wieder entfernt wird. + // siehe Bug 55406 + _TempBigPtrEntry aTempEntry; + BigPtrEntry* pTempEntry = &aTempEntry; + + while( nCnt-- ) + { + delete pDel; + pDel = pPrev; + sal_uLong nPrevNdIdx = pPrev->GetIndex(); + BigPtrArray::Replace( nPrevNdIdx+1, pTempEntry ); + if( nCnt ) + pPrev = (*this)[ nPrevNdIdx - 1 ]; + } + nDelPos = pDel->GetIndex() + 1; + } + + BigPtrArray::Remove( nDelPos, nSz ); +} + +void SwNodes::RegisterIndex( SwNodeIndex& rIdx ) +{ + if( !pRoot ) // noch keine Root gesetzt? + { + pRoot = &rIdx; + pRoot->pPrev = 0; + pRoot->pNext = 0; + } + else + { + // immer hinter die Root haengen + rIdx.pNext = pRoot->pNext; + pRoot->pNext = &rIdx; + rIdx.pPrev = pRoot; + if( rIdx.pNext ) + rIdx.pNext->pPrev = &rIdx; + } +} + +void SwNodes::DeRegisterIndex( SwNodeIndex& rIdx ) +{ + SwNodeIndex* pN = rIdx.pNext; + SwNodeIndex* pP = rIdx.pPrev; + + if( pRoot == &rIdx ) + pRoot = pP ? pP : pN; + + if( pP ) + pP->pNext = pN; + if( pN ) + pN->pPrev = pP; + + rIdx.pNext = 0; + rIdx.pPrev = 0; +} + +void SwNodes::InsertNode( const SwNodePtr pNode, + const SwNodeIndex& rPos ) +{ + const ElementPtr pIns = pNode; + BigPtrArray::Insert( pIns, rPos.GetIndex() ); +} + +void SwNodes::InsertNode( const SwNodePtr pNode, + sal_uLong nPos ) +{ + const ElementPtr pIns = pNode; + BigPtrArray::Insert( pIns, nPos ); +} + +// ->#112139# +SwNode * SwNodes::DocumentSectionStartNode(SwNode * pNode) const +{ + if (NULL != pNode) + { + SwNodeIndex aIdx(*pNode); + + if (aIdx <= (*this)[0]->EndOfSectionIndex()) + pNode = (*this)[0]; + else + { + while ((*this)[0] != pNode->StartOfSectionNode()) + pNode = pNode->StartOfSectionNode(); + } + } + + return pNode; +} + +SwNode * SwNodes::DocumentSectionEndNode(SwNode * pNode) const +{ + return DocumentSectionStartNode(pNode)->EndOfSectionNode(); +} + +sal_Bool SwNodes::IsDocNodes() const +{ + return this == &pMyDoc->GetNodes(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/observablethread.cxx b/sw/source/core/docnode/observablethread.cxx new file mode 100644 index 000000000000..cafeb9b610b1 --- /dev/null +++ b/sw/source/core/docnode/observablethread.cxx @@ -0,0 +1,100 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <observablethread.hxx> + +#include <boost/shared_ptr.hpp> + +/** class for an observable thread + + #i73788# + + @author OD +*/ +ObservableThread::ObservableThread() + : mnRefCount( 0 ), + mnThreadID( 0 ), + mpThreadListener() +{ +} + +ObservableThread::~ObservableThread() +{ +} + +oslInterlockedCount ObservableThread::acquire() +{ + return osl_incrementInterlockedCount( &mnRefCount ); +} + +oslInterlockedCount ObservableThread::release() +{ + oslInterlockedCount nCount( osl_decrementInterlockedCount( &mnRefCount ) ); + if ( nCount == 0 ) + { + delete this; + return nCount; + } + + return nCount; +} + +void ObservableThread::SetListener( boost::weak_ptr< IFinishedThreadListener > pThreadListener, + const oslInterlockedCount nThreadID ) +{ + mpThreadListener = pThreadListener; + mnThreadID = nThreadID; +} + +void SAL_CALL ObservableThread::run() +{ + acquire(); + + threadFunction(); +} + +void SAL_CALL ObservableThread::onTerminated() +{ + threadFinished(); + + // notify observer + boost::shared_ptr< IFinishedThreadListener > pThreadListener = mpThreadListener.lock(); + if ( pThreadListener ) + { + pThreadListener->NotifyAboutFinishedThread( mnThreadID ); + } + + release(); +} + +void ObservableThread::threadFinished() +{ + // empty default implementation +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/pausethreadstarting.cxx b/sw/source/core/docnode/pausethreadstarting.cxx new file mode 100644 index 000000000000..df4a060dea67 --- /dev/null +++ b/sw/source/core/docnode/pausethreadstarting.cxx @@ -0,0 +1,58 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <pausethreadstarting.hxx> +#include <swthreadmanager.hxx> + +/** Helper class to pause starting of threads during existence of an instance + of this class + + #i73788# + + @author OD +*/ +SwPauseThreadStarting::SwPauseThreadStarting() + : mbPausedThreadStarting( false ) +{ + if ( SwThreadManager::ExistsThreadManager() && + !SwThreadManager::GetThreadManager().StartingOfThreadsSuspended() ) + { + SwThreadManager::GetThreadManager().SuspendStartingOfThreads(); + mbPausedThreadStarting = true; + } +} + +SwPauseThreadStarting::~SwPauseThreadStarting() +{ + if ( mbPausedThreadStarting ) + { + SwThreadManager::GetThreadManager().ResumeStartingOfThreads(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/retrievedinputstreamdata.cxx b/sw/source/core/docnode/retrievedinputstreamdata.cxx new file mode 100644 index 000000000000..78bf5b144e05 --- /dev/null +++ b/sw/source/core/docnode/retrievedinputstreamdata.cxx @@ -0,0 +1,169 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <retrievedinputstreamdata.hxx> +#include <retrieveinputstreamconsumer.hxx> +#include <vcl/svapp.hxx> + +/** implementation of class <SwRetrievedInputStreamDataManager> + + #i73788# +*/ +SwRetrievedInputStreamDataManager* SwRetrievedInputStreamDataManager::mpManager = 0; +SwRetrievedInputStreamDataManager::tDataKey SwRetrievedInputStreamDataManager::mnNextKeyValue = 1; +osl::Mutex SwRetrievedInputStreamDataManager::maGetManagerMutex; + +SwRetrievedInputStreamDataManager& SwRetrievedInputStreamDataManager::GetManager() +{ + osl::MutexGuard aGuard(maGetManagerMutex); + + if ( mpManager == 0 ) + { + mpManager = new SwRetrievedInputStreamDataManager(); + } + + return *mpManager; +} + +SwRetrievedInputStreamDataManager::tDataKey SwRetrievedInputStreamDataManager::ReserveData( + boost::weak_ptr< SwAsyncRetrieveInputStreamThreadConsumer > pThreadConsumer ) +{ + osl::MutexGuard aGuard(maMutex); + + // create empty data container for given thread Consumer + tDataKey nDataKey( mnNextKeyValue ); + tData aNewEntry( pThreadConsumer ); + maInputStreamData[ nDataKey ] = aNewEntry; + + // prepare next data key value + if ( mnNextKeyValue < SAL_MAX_UINT64 ) + { + ++mnNextKeyValue; + } + else + { + mnNextKeyValue = 1; + } + + return nDataKey; +} + +void SwRetrievedInputStreamDataManager::PushData( + const tDataKey nDataKey, + com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xInputStream, + const sal_Bool bIsStreamReadOnly ) +{ + osl::MutexGuard aGuard(maMutex); + + std::map< tDataKey, tData >::iterator aIter = maInputStreamData.find( nDataKey ); + + if ( aIter != maInputStreamData.end() ) + { + // Fill data container. + (*aIter).second.mxInputStream = xInputStream; + (*aIter).second.mbIsStreamReadOnly = bIsStreamReadOnly; + + // post user event to process the retrieved input stream data + if ( GetpApp() ) + { + + tDataKey* pDataKey = new tDataKey; + *pDataKey = nDataKey; + GetpApp()->PostUserEvent( LINK( this, SwRetrievedInputStreamDataManager, LinkedInputStreamReady ), pDataKey ); + } + else + { + // no application available -> discard data + maInputStreamData.erase( aIter ); + } + } +} + +bool SwRetrievedInputStreamDataManager::PopData( const tDataKey nDataKey, + tData& rData ) +{ + osl::MutexGuard aGuard(maMutex); + + bool bDataProvided( false ); + + std::map< tDataKey, tData >::iterator aIter = maInputStreamData.find( nDataKey ); + + if ( aIter != maInputStreamData.end() ) + { + rData.mpThreadConsumer = (*aIter).second.mpThreadConsumer; + rData.mxInputStream = (*aIter).second.mxInputStream; + rData.mbIsStreamReadOnly = (*aIter).second.mbIsStreamReadOnly; + + maInputStreamData.erase( aIter ); + + bDataProvided = true; + } + + return bDataProvided; +} + +/** callback function, which is triggered by input stream data manager on + filling of the data container to provide retrieved input stream to the + thread Consumer using <Application::PostUserEvent(..)> + + #i73788# + Note: This method has to be run in the main thread. + + @author OD +*/ +IMPL_LINK( SwRetrievedInputStreamDataManager, + LinkedInputStreamReady, + SwRetrievedInputStreamDataManager::tDataKey*, + pDataKey ) +{ + if ( !pDataKey ) + { + return 0; + } + + osl::MutexGuard aGuard(maMutex); + + SwRetrievedInputStreamDataManager& rDataManager = + SwRetrievedInputStreamDataManager::GetManager(); + SwRetrievedInputStreamDataManager::tData aInputStreamData; + if ( rDataManager.PopData( *pDataKey, aInputStreamData ) ) + { + boost::shared_ptr< SwAsyncRetrieveInputStreamThreadConsumer > pThreadConsumer = + aInputStreamData.mpThreadConsumer.lock(); + if ( pThreadConsumer ) + { + pThreadConsumer->ApplyInputStream( aInputStreamData.mxInputStream, + aInputStreamData.mbIsStreamReadOnly ); + } + } + delete pDataKey; + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/retrieveinputstream.cxx b/sw/source/core/docnode/retrieveinputstream.cxx new file mode 100644 index 000000000000..848c5769621c --- /dev/null +++ b/sw/source/core/docnode/retrieveinputstream.cxx @@ -0,0 +1,87 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <retrieveinputstream.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <com/sun/star/io/XStream.hpp> + +/** class for a thread to retrieve an input stream given by an URL + + #i73788# + + @author OD +*/ +::rtl::Reference< ObservableThread > SwAsyncRetrieveInputStreamThread::createThread( + const SwRetrievedInputStreamDataManager::tDataKey nDataKey, + const String& rLinkedURL ) +{ + SwAsyncRetrieveInputStreamThread* pNewThread = + new SwAsyncRetrieveInputStreamThread( nDataKey, rLinkedURL ); + return pNewThread; +} + +SwAsyncRetrieveInputStreamThread::SwAsyncRetrieveInputStreamThread( + const SwRetrievedInputStreamDataManager::tDataKey nDataKey, + const String& rLinkedURL ) + : ObservableThread(), + mnDataKey( nDataKey ), + mrLinkedURL( rLinkedURL ) +{ +} + +SwAsyncRetrieveInputStreamThread::~SwAsyncRetrieveInputStreamThread() +{ +} + +void SwAsyncRetrieveInputStreamThread::threadFunction() +{ + com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > xProps( 1 ); + xProps[0].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL")); + xProps[0].Value <<= ::rtl::OUString( mrLinkedURL ); + comphelper::MediaDescriptor aMedium( xProps ); + + aMedium.addInputStream(); + + com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xInputStream; + aMedium[comphelper::MediaDescriptor::PROP_INPUTSTREAM()] >>= xInputStream; + if ( !xInputStream.is() ) + { + com::sun::star::uno::Reference<com::sun::star::io::XStream> xStream; + aMedium[comphelper::MediaDescriptor::PROP_STREAM()] >>= xStream; + if ( xStream.is() ) + { + xInputStream = xStream->getInputStream(); + } + } + + SwRetrievedInputStreamDataManager::GetManager().PushData( mnDataKey, + xInputStream, + aMedium.isStreamReadOnly() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/retrieveinputstreamconsumer.cxx b/sw/source/core/docnode/retrieveinputstreamconsumer.cxx new file mode 100644 index 000000000000..82ae987f43f5 --- /dev/null +++ b/sw/source/core/docnode/retrieveinputstreamconsumer.cxx @@ -0,0 +1,74 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <retrieveinputstreamconsumer.hxx> +#include <ndgrf.hxx> +#include <retrieveinputstream.hxx> +#include <swthreadmanager.hxx> + +/** class to provide creation of a thread to retrieve an input stream given by + an URL and to consume the retrieved input stream. + + #i73788# + + @author OD +*/ +SwAsyncRetrieveInputStreamThreadConsumer::SwAsyncRetrieveInputStreamThreadConsumer( + SwGrfNode& rGrfNode ) + : mrGrfNode( rGrfNode ), + mnThreadID( 0 ) +{ +} + +SwAsyncRetrieveInputStreamThreadConsumer::~SwAsyncRetrieveInputStreamThreadConsumer() +{ + SwThreadManager::GetThreadManager().RemoveThread( mnThreadID ); +} + +void SwAsyncRetrieveInputStreamThreadConsumer::CreateThread( const String& rURL ) +{ + // Get new data container for input stream data + SwRetrievedInputStreamDataManager::tDataKey nDataKey = + SwRetrievedInputStreamDataManager::GetManager().ReserveData( + mrGrfNode.GetThreadConsumer() ); + + rtl::Reference< ObservableThread > pNewThread = + SwAsyncRetrieveInputStreamThread::createThread( nDataKey, rURL ); + + // Add thread to thread manager and pass ownership of thread to thread manager. + mnThreadID = SwThreadManager::GetThreadManager().AddThread( pNewThread ); +} + +void SwAsyncRetrieveInputStreamThreadConsumer::ApplyInputStream( + com::sun::star::uno::Reference<com::sun::star::io::XInputStream> xInputStream, + const sal_Bool bIsStreamReadOnly ) +{ + mrGrfNode.ApplyInputStream( xInputStream, bIsStreamReadOnly ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/section.cxx b/sw/source/core/docnode/section.cxx new file mode 100644 index 000000000000..a5bcf822af03 --- /dev/null +++ b/sw/source/core/docnode/section.cxx @@ -0,0 +1,1777 @@ +/* -*- 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_sw.hxx" + +#include <stdlib.h> +#include <hintids.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <editeng/protitem.hxx> +#include <sfx2/linkmgr.hxx> +#include <tools/urlobj.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/fcontnr.hxx> +#include <docary.hxx> +#include <fmtcntnt.hxx> +#include <fmtpdsc.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <node.hxx> +#include <pam.hxx> +#include <frmtool.hxx> +#include <editsh.hxx> +#include <hints.hxx> +#include <docsh.hxx> +#include <ndtxt.hxx> +#include <section.hxx> +#include <swserv.hxx> +#include <shellio.hxx> +#include <poolfmt.hxx> +#include <expfld.hxx> +#include <swbaslnk.hxx> +#include <mvsave.hxx> +#include <sectfrm.hxx> +#include <fmtftntx.hxx> +#include <ftnidx.hxx> +#include <doctxm.hxx> +#include <fmteiro.hxx> +#include <swerror.h> +#include <unosection.hxx> +#include <switerator.hxx> +#include <svl/smplhint.hxx> + +using namespace ::com::sun::star; + + +SV_IMPL_REF( SwServerObject ) + +#define sSectionFmtNm aEmptyStr + +class SwIntrnlSectRefLink : public SwBaseLink +{ + SwSectionFmt& rSectFmt; +public: + SwIntrnlSectRefLink( SwSectionFmt& rFmt, sal_uInt16 nUpdateType, sal_uInt16 nFmt ) + : SwBaseLink( nUpdateType, nFmt ), + rSectFmt( rFmt ) + {} + + virtual void Closed(); + virtual void DataChanged( const String& rMimeType, + const uno::Any & rValue ); + + virtual const SwNode* GetAnchor() const; + virtual sal_Bool IsInRange( sal_uLong nSttNd, sal_uLong nEndNd, xub_StrLen nStt = 0, + xub_StrLen nEnd = STRING_NOTFOUND ) const; + + inline SwSectionNode* GetSectNode() + { + const SwNode* pSectNd( const_cast<SwIntrnlSectRefLink*>(this)->GetAnchor() ); + return const_cast<SwSectionNode*>( dynamic_cast<const SwSectionNode*>( pSectNd ) ); + } +}; + + +TYPEINIT1(SwSectionFmt,SwFrmFmt ); +TYPEINIT1(SwSection,SwClient ); + +typedef SwSection* SwSectionPtr; + +SV_IMPL_PTRARR( SwSections, SwSection*) +SV_IMPL_PTRARR(SwSectionFmts,SwSectionFmt*) + + +SwSectionData::SwSectionData(SectionType const eType, String const& rName) + : m_eType(eType) + , m_sSectionName(rName) + , m_bHiddenFlag(false) + , m_bProtectFlag(false) + , m_bEditInReadonlyFlag(false) // edit in readonly sections + , m_bHidden(false) + , m_bCondHiddenFlag(true) + , m_bConnectFlag(true) +{ +} + +// this must have the same semantics as operator=() +SwSectionData::SwSectionData(SwSection const& rSection) + : m_eType(rSection.GetType()) + , m_sSectionName(rSection.GetSectionName()) + , m_sCondition(rSection.GetCondition()) + , m_sLinkFileName(rSection.GetLinkFileName()) + , m_sLinkFilePassword(rSection.GetLinkFilePassword()) + , m_Password(rSection.GetPassword()) + , m_bHiddenFlag(rSection.IsHiddenFlag()) + , m_bProtectFlag(rSection.IsProtect()) + // edit in readonly sections + , m_bEditInReadonlyFlag(rSection.IsEditInReadonly()) + , m_bHidden(rSection.IsHidden()) + , m_bCondHiddenFlag(true) + , m_bConnectFlag(rSection.IsConnectFlag()) +{ +} + +// this must have the same semantics as operator=() +SwSectionData::SwSectionData(SwSectionData const& rOther) + : m_eType(rOther.m_eType) + , m_sSectionName(rOther.m_sSectionName) + , m_sCondition(rOther.m_sCondition) + , m_sLinkFileName(rOther.m_sLinkFileName) + , m_sLinkFilePassword(rOther.m_sLinkFilePassword) + , m_Password(rOther.m_Password) + , m_bHiddenFlag(rOther.m_bHiddenFlag) + , m_bProtectFlag(rOther.m_bProtectFlag) + // edit in readonly sections + , m_bEditInReadonlyFlag(rOther.m_bEditInReadonlyFlag) + , m_bHidden(rOther.m_bHidden) + , m_bCondHiddenFlag(true) + , m_bConnectFlag(rOther.m_bConnectFlag) +{ +} + +// the semantics here are weird for reasons of backward compatibility +SwSectionData & SwSectionData::operator= (SwSectionData const& rOther) +{ + m_eType = rOther.m_eType; + m_sSectionName = rOther.m_sSectionName; + m_sCondition = rOther.m_sCondition; + m_sLinkFileName = rOther.m_sLinkFileName; + m_sLinkFilePassword = rOther.m_sLinkFilePassword; + m_bConnectFlag = rOther.m_bConnectFlag; + m_Password = rOther.m_Password; + + m_bEditInReadonlyFlag = rOther.m_bEditInReadonlyFlag; + m_bProtectFlag = rOther.m_bProtectFlag; + + m_bHidden = rOther.m_bHidden; + // FIXME: old code did not assign m_bHiddenFlag ? + // FIXME: why should m_bCondHiddenFlag always default to true? + m_bCondHiddenFlag = true; + + return *this; +} + +// the semantics here are weird for reasons of backward compatibility +bool SwSectionData::operator==(SwSectionData const& rOther) const +{ + return (m_eType == rOther.m_eType) + && (m_sSectionName == rOther.m_sSectionName) + && (m_sCondition == rOther.m_sCondition) + && (m_bHidden == rOther.m_bHidden) + && (m_bProtectFlag == rOther.m_bProtectFlag) + && (m_bEditInReadonlyFlag == rOther.m_bEditInReadonlyFlag) + && (m_sLinkFileName == rOther.m_sLinkFileName) + && (m_sLinkFilePassword == rOther.m_sLinkFilePassword) + && (m_Password == rOther.m_Password); + // FIXME: old code ignored m_bCondHiddenFlag m_bHiddenFlag m_bConnectFlag +} + +// SwSection =========================================================== + +SwSection::SwSection( + SectionType const eType, String const& rName, SwSectionFmt & rFormat) + : SwClient(& rFormat) + , m_Data(eType, rName) +{ + SwSection *const pParentSect = GetParent(); + if( pParentSect ) + { + if( pParentSect->IsHiddenFlag() ) + { + SetHidden( true ); + } + + m_Data.SetProtectFlag( pParentSect->IsProtectFlag() ); + // edit in readonly sections + m_Data.SetEditInReadonlyFlag( pParentSect->IsEditInReadonlyFlag() ); + } + + if (!m_Data.IsProtectFlag()) + { + m_Data.SetProtectFlag( rFormat.GetProtect().IsCntntProtected() ); + } + + if (!m_Data.IsEditInReadonlyFlag()) // edit in readonly sections + { + m_Data.SetEditInReadonlyFlag( rFormat.GetEditInReadonly().GetValue() ); + } +} + + +SwSection::~SwSection() +{ + SwSectionFmt* pFmt = GetFmt(); + if( !pFmt ) + return; + + SwDoc* pDoc = pFmt->GetDoc(); + if( pDoc->IsInDtor() ) + { + // dann melden wir noch schnell unser Format um ans dflt FrameFmt, + // damit es keine Abhaengigkeiten gibt + if( pFmt->DerivedFrom() != pDoc->GetDfltFrmFmt() ) + pFmt->RegisterToFormat( *pDoc->GetDfltFrmFmt() ); + } + else + { + pFmt->Remove( this ); // austragen, + + if (CONTENT_SECTION != m_Data.GetType()) + { + pDoc->GetLinkManager().Remove( m_RefLink ); + } + + if (m_RefObj.Is()) + { + pDoc->GetLinkManager().RemoveServer( &m_RefObj ); + } + + // ist die Section der letzte Client im Format, kann dieses + // geloescht werden + SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT, pFmt ); + pFmt->ModifyNotification( &aMsgHint, &aMsgHint ); + if( !pFmt->GetDepends() ) + { + // Bug: 28191 - nicht ins Undo aufnehmen, sollte schon vorher + // geschehen sein!! + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + pDoc->DelSectionFmt( pFmt ); // und loeschen + } + } + if (m_RefObj.Is()) + { + m_RefObj->Closed(); + } +} + +void SwSection::SetSectionData(SwSectionData const& rData) +{ + bool const bOldHidden( m_Data.IsHidden() ); + m_Data = rData; + // next 2 may actually overwrite m_Data.m_b{Protect,EditInReadonly}Flag + // in Modify, which should result in same flag value as the old code! + SetProtect(m_Data.IsProtectFlag()); + SetEditInReadonly(m_Data.IsEditInReadonlyFlag()); + if (bOldHidden != m_Data.IsHidden()) // check if changed... + { + ImplSetHiddenFlag(m_Data.IsHidden(), m_Data.IsCondHidden()); + } +} + +bool SwSection::DataEquals(SwSectionData const& rCmp) const +{ + // note that the old code compared the flags of the parameter with the + // format attributes of this; the following mess should do the same... + (void) GetLinkFileName(); // updates m_sLinkFileName + bool const bProtect(m_Data.IsProtectFlag()); + bool const bEditInReadonly(m_Data.IsEditInReadonlyFlag()); + const_cast<SwSection*>(this)->m_Data.SetProtectFlag(IsProtect()); + const_cast<SwSection*>(this)->m_Data + .SetEditInReadonlyFlag(IsEditInReadonly()); + bool const bResult( m_Data == rCmp ); + const_cast<SwSection*>(this)->m_Data.SetProtectFlag(bProtect); + const_cast<SwSection*>(this)->m_Data.SetEditInReadonlyFlag(bEditInReadonly); + return bResult; +} + + +void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition) +{ + SwSectionFmt* pFmt = GetFmt(); + OSL_ENSURE(pFmt, "ImplSetHiddenFlag: no format?"); + if( pFmt ) + { + const bool bHide = bTmpHidden && bCondition; + + if (bHide) // should be hidden + { + if (!m_Data.IsHiddenFlag()) // is not hidden + { + // wie sieht es mit dem Parent aus, ist der versteckt ? + // (eigentlich muesste das vom bHiddenFlag angezeigt werden!) + + // erstmal allen Childs sagen, das sie versteckt sind + SwMsgPoolItem aMsgItem( RES_SECTION_HIDDEN ); + pFmt->ModifyNotification( &aMsgItem, &aMsgItem ); + + // alle Frames loeschen + pFmt->DelFrms(); + } + } + else if (m_Data.IsHiddenFlag()) // show Nodes again + { + // alle Frames sichtbar machen ( Childs Sections werden vom + // MakeFrms beruecksichtigt). Aber nur wenn die ParentSection + // nichts dagegen hat ! + SwSection* pParentSect = pFmt->GetParentSection(); + if( !pParentSect || !pParentSect->IsHiddenFlag() ) + { + // erstmal allen Childs sagen, das der Parent nicht mehr + // versteckt ist + SwMsgPoolItem aMsgItem( RES_SECTION_NOT_HIDDEN ); + pFmt->ModifyNotification( &aMsgItem, &aMsgItem ); + + pFmt->MakeFrms(); + } + } + } +} + +sal_Bool SwSection::CalcHiddenFlag() const +{ + const SwSection* pSect = this; + do { + if( pSect->IsHidden() && pSect->IsCondHidden() ) + return sal_True; + } while( 0 != ( pSect = pSect->GetParent()) ); + + return sal_False; +} + +bool SwSection::IsProtect() const +{ + SwSectionFmt *const pFmt( GetFmt() ); + OSL_ENSURE(pFmt, "SwSection::IsProtect: no format?"); + return (pFmt) + ? pFmt->GetProtect().IsCntntProtected() + : IsProtectFlag(); +} + +// edit in readonly sections +bool SwSection::IsEditInReadonly() const +{ + SwSectionFmt *const pFmt( GetFmt() ); + OSL_ENSURE(pFmt, "SwSection::IsEditInReadonly: no format?"); + return (pFmt) + ? pFmt->GetEditInReadonly().GetValue() + : IsEditInReadonlyFlag(); +} + +void SwSection::SetHidden(bool const bFlag) +{ + if (!m_Data.IsHidden() == !bFlag) + return; + + m_Data.SetHidden(bFlag); + ImplSetHiddenFlag(bFlag, m_Data.IsCondHidden()); +} + + +void SwSection::SetProtect(bool const bFlag) +{ + SwSectionFmt *const pFormat( GetFmt() ); + OSL_ENSURE(pFormat, "SwSection::SetProtect: no format?"); + if (pFormat) + { + SvxProtectItem aItem( RES_PROTECT ); + aItem.SetCntntProtect( (sal_Bool)bFlag ); + pFormat->SetFmtAttr( aItem ); + // note: this will call m_Data.SetProtectFlag via Modify! + } + else + { + m_Data.SetProtectFlag(bFlag); + } +} + +// edit in readonly sections +void SwSection::SetEditInReadonly(bool const bFlag) +{ + SwSectionFmt *const pFormat( GetFmt() ); + OSL_ENSURE(pFormat, "SwSection::SetEditInReadonly: no format?"); + if (pFormat) + { + SwFmtEditInReadonly aItem; + aItem.SetValue( (sal_Bool)bFlag ); + pFormat->SetFmtAttr( aItem ); + // note: this will call m_Data.SetEditInReadonlyFlag via Modify! + } + else + { + m_Data.SetEditInReadonlyFlag(bFlag); + } +} + +void SwSection::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + bool bRemake = false; + bool bUpdateFtn = false; + switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ) + { + case RES_ATTRSET_CHG: + { + SfxItemSet* pNewSet = ((SwAttrSetChg*)pNew)->GetChgSet(); + SfxItemSet* pOldSet = ((SwAttrSetChg*)pOld)->GetChgSet(); + const SfxPoolItem* pItem; + + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_PROTECT, sal_False, &pItem ) ) + { + m_Data.SetProtectFlag( static_cast<SvxProtectItem const*>(pItem) + ->IsCntntProtected() ); + pNewSet->ClearItem( RES_PROTECT ); + pOldSet->ClearItem( RES_PROTECT ); + } + + // --> edit in readonly sections + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_EDIT_IN_READONLY, sal_False, &pItem ) ) + { + m_Data.SetEditInReadonlyFlag( + static_cast<SwFmtEditInReadonly const*>(pItem)->GetValue()); + pNewSet->ClearItem( RES_EDIT_IN_READONLY ); + pOldSet->ClearItem( RES_EDIT_IN_READONLY ); + } + // <-- + + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_FTN_AT_TXTEND, sal_False, &pItem ) || + SFX_ITEM_SET == pNewSet->GetItemState( + RES_END_AT_TXTEND, sal_False, &pItem )) + { + bUpdateFtn = true; + } + + if( !pNewSet->Count() ) + return; + } + break; + + case RES_PROTECT: + if( pNew ) + { + bool bNewFlag = + static_cast<const SvxProtectItem*>(pNew)->IsCntntProtected(); + if( !bNewFlag ) + { + // Abschalten: teste ob nicht vielleich ueber die Parents + // doch ein Schutzt besteht! + const SwSection* pSect = this; + do { + if( pSect->IsProtect() ) + { + bNewFlag = true; + break; + } + pSect = pSect->GetParent(); + } while (pSect); + } + + m_Data.SetProtectFlag( bNewFlag ); + } + return; + // edit in readonly sections + case RES_EDIT_IN_READONLY: + if( pNew ) + { + const bool bNewFlag = + static_cast<const SwFmtEditInReadonly*>(pNew)->GetValue(); + m_Data.SetEditInReadonlyFlag( bNewFlag ); + } + return; + + case RES_SECTION_HIDDEN: + m_Data.SetHiddenFlag(true); + return; + + case RES_SECTION_NOT_HIDDEN: + case RES_SECTION_RESETHIDDENFLAG: + m_Data.SetHiddenFlag( m_Data.IsHidden() && m_Data.IsCondHidden() ); + return; + + case RES_COL: + /* wird ggf. vom Layout erledigt */ + break; + + case RES_FTN_AT_TXTEND: + if( pNew && pOld ) + { + bUpdateFtn = true; + } + break; + + case RES_END_AT_TXTEND: + if( pNew && pOld ) + { + bUpdateFtn = true; + } + break; + + default: + CheckRegistration( pOld, pNew ); + break; + } + + if( bRemake ) + { + GetFmt()->DelFrms(); + GetFmt()->MakeFrms(); + } + + if( bUpdateFtn ) + { + SwSectionNode* pSectNd = GetFmt()->GetSectionNode( sal_False ); + if( pSectNd ) + pSectNd->GetDoc()->GetFtnIdxs().UpdateFtn(SwNodeIndex( *pSectNd )); + } +} + +void SwSection::SetRefObject( SwServerObject* pObj ) +{ + m_RefObj = pObj; +} + + +void SwSection::SetCondHidden(bool const bFlag) +{ + if (!m_Data.IsCondHidden() == !bFlag) + return; + + m_Data.SetCondHidden(bFlag); + ImplSetHiddenFlag(m_Data.IsHidden(), bFlag); +} + + +// setze/erfrage den gelinkten FileNamen +const String& SwSection::GetLinkFileName() const +{ + if (m_RefLink.Is()) + { + String sTmp; + switch (m_Data.GetType()) + { + case DDE_LINK_SECTION: + sTmp = m_RefLink->GetLinkSourceName(); + break; + + case FILE_LINK_SECTION: + { + String sRange, sFilter; + if (m_RefLink->GetLinkManager() && + m_RefLink->GetLinkManager()->GetDisplayNames( + m_RefLink, 0, &sTmp, &sRange, &sFilter )) + { + ( sTmp += sfx2::cTokenSeperator ) += sFilter; + ( sTmp += sfx2::cTokenSeperator ) += sRange; + } + else if( GetFmt() && !GetFmt()->GetSectionNode() ) + { + // ist die Section im UndoNodesArray, dann steht + // der Link nicht im LinkManager, kann also auch nicht + // erfragt werden. Dann returne den akt. Namen + return m_Data.GetLinkFileName(); + } + } + break; + default: break; + } + const_cast<SwSection*>(this)->m_Data.SetLinkFileName(sTmp); + } + return m_Data.GetLinkFileName(); +} + + +void SwSection::SetLinkFileName(const String& rNew, String const*const pPassWd) +{ + if (m_RefLink.Is()) + { + m_RefLink->SetLinkSourceName( rNew ); + } + m_Data.SetLinkFileName(rNew); + if( pPassWd ) + { + SetLinkFilePassword( *pPassWd ); + } +} + +// falls es ein gelinkter Bereich war, dann muessen alle +// Child-Verknuepfungen sichtbar bemacht werden. +void SwSection::MakeChildLinksVisible( const SwSectionNode& rSectNd ) +{ + const SwNode* pNd; + const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc()->GetLinkManager().GetLinks(); + for( sal_uInt16 n = rLnks.Count(); n; ) + { + ::sfx2::SvBaseLink* pBLnk = &(*rLnks[ --n ]); + if( pBLnk && !pBLnk->IsVisible() && + pBLnk->ISA( SwBaseLink ) && + 0 != ( pNd = ((SwBaseLink*)pBLnk)->GetAnchor() ) ) + { + pNd = pNd->StartOfSectionNode(); // falls SectionNode ist! + const SwSectionNode* pParent; + while( 0 != ( pParent = pNd->FindSectionNode() ) && + ( CONTENT_SECTION == pParent->GetSection().GetType() + || pNd == &rSectNd )) + pNd = pParent->StartOfSectionNode(); + + // steht nur noch in einer normalen Section, also + // wieder anzeigen + if( !pParent ) + pBLnk->SetVisible( sal_True ); + } + } +} + +const SwTOXBase* SwSection::GetTOXBase() const +{ + const SwTOXBase* pRet = 0; + if( TOX_CONTENT_SECTION == GetType() ) + pRet = PTR_CAST( SwTOXBaseSection, this ); + return pRet; +} + +// SwSectionFmt ======================================================== + +SwSectionFmt::SwSectionFmt( SwSectionFmt* pDrvdFrm, SwDoc *pDoc ) + : SwFrmFmt( pDoc->GetAttrPool(), sSectionFmtNm, pDrvdFrm ) +{ + LockModify(); + SetFmtAttr( *GetDfltAttr( RES_COL ) ); + UnlockModify(); +} + +SwSectionFmt::~SwSectionFmt() +{ + if( !GetDoc()->IsInDtor() ) + { + SwSectionNode* pSectNd; + const SwNodeIndex* pIdx = GetCntnt( sal_False ).GetCntntIdx(); + if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + SwSection& rSect = pSectNd->GetSection(); + // falls es ein gelinkter Bereich war, dann muessen alle + // Child-Verknuepfungen sichtbar bemacht werden. + if( rSect.IsConnected() ) + rSect.MakeChildLinksVisible( *pSectNd ); + + // vorm loeschen der Nodes pruefe, ob wir uns nicht + // noch anzeigen muessen! + if( rSect.IsHiddenFlag() ) + { + SwSectionPtr pParentSect = rSect.GetParent(); + if( !pParentSect || !pParentSect->IsHiddenFlag() ) + { + // Nodes wieder anzeigen + rSect.SetHidden(false); + } + } + // mba: test iteration; objects are removed while iterating + CallSwClientNotify( SfxSimpleHint(SFX_HINT_DYING) ); + + // hebe die Section doch mal auf + SwNodeRange aRg( *pSectNd, 0, *pSectNd->EndOfSectionNode() ); + GetDoc()->GetNodes().SectionUp( &aRg ); + } + LockModify(); + ResetFmtAttr( RES_CNTNT ); + UnlockModify(); + } +} + + +SwSection * SwSectionFmt::GetSection() const +{ + return SwIterator<SwSection,SwSectionFmt>::FirstElement( *this ); +} + +extern void lcl_DeleteFtn( SwSectionNode *pNd, sal_uLong nStt, sal_uLong nEnd ); + +//Vernichtet alle Frms in aDepend (Frms werden per PTR_CAST erkannt). +void SwSectionFmt::DelFrms() +{ + SwSectionNode* pSectNd; + const SwNodeIndex* pIdx = GetCntnt(sal_False).GetCntntIdx(); + if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + // #147431# : First delete the <SwSectionFrm> of the <SwSectionFmt> instance + // mba: test iteration as objects are removed in iteration + CallSwClientNotify( SfxSimpleHint(SFX_HINT_DYING) ); + + // Then delete frames of the nested <SwSectionFmt> instances + SwIterator<SwSectionFmt,SwSectionFmt> aIter( *this ); + SwSectionFmt *pLast = aIter.First(); + while ( pLast ) + { + pLast->DelFrms(); + pLast = aIter.Next(); + } + + sal_uLong nEnde = pSectNd->EndOfSectionIndex(); + sal_uLong nStart = pSectNd->GetIndex()+1; + lcl_DeleteFtn( pSectNd, nStart, nEnde ); + } + if( pIdx ) + { + //Hint fuer Pagedesc versenden. Das mueste eigntlich das Layout im + //Paste der Frames selbst erledigen, aber das fuehrt dann wiederum + //zu weiteren Folgefehlern, die mit Laufzeitkosten geloest werden + //muesten. + SwNodeIndex aNextNd( *pIdx ); + SwCntntNode* pCNd = GetDoc()->GetNodes().GoNextSection( &aNextNd, sal_True, sal_False ); + if( pCNd ) + { + const SfxPoolItem& rItem = pCNd->GetSwAttrSet().Get( RES_PAGEDESC ); + pCNd->ModifyNotification( (SfxPoolItem*)&rItem, (SfxPoolItem*)&rItem ); + } + } +} + + +//Erzeugt die Ansichten +void SwSectionFmt::MakeFrms() +{ + SwSectionNode* pSectNd; + const SwNodeIndex* pIdx = GetCntnt(sal_False).GetCntntIdx(); + + if( pIdx && &GetDoc()->GetNodes() == &pIdx->GetNodes() && + 0 != (pSectNd = pIdx->GetNode().GetSectionNode() )) + { + SwNodeIndex aIdx( *pIdx ); + pSectNd->MakeFrms( &aIdx ); + } +} + +void SwSectionFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew ) +{ + sal_Bool bClients = sal_False; + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + switch( nWhich ) + { + case RES_ATTRSET_CHG: + if( GetDepends() ) + { + SfxItemSet* pNewSet = ((SwAttrSetChg*)pNew)->GetChgSet(); + SfxItemSet* pOldSet = ((SwAttrSetChg*)pOld)->GetChgSet(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_PROTECT, sal_False, &pItem )) + { + ModifyBroadcast( (SfxPoolItem*)pItem, (SfxPoolItem*)pItem ); + pNewSet->ClearItem( RES_PROTECT ); + pOldSet->ClearItem( RES_PROTECT ); + } + + // --> edit in readonly sections + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_EDIT_IN_READONLY, sal_False, &pItem ) ) + { + ModifyBroadcast( (SfxPoolItem*)pItem, (SfxPoolItem*)pItem ); + pNewSet->ClearItem( RES_EDIT_IN_READONLY ); + pOldSet->ClearItem( RES_EDIT_IN_READONLY ); + } + // <-- + + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_FTN_AT_TXTEND, sal_False, &pItem )) + { + ModifyBroadcast( (SfxPoolItem*)&pOldSet->Get( RES_FTN_AT_TXTEND ), (SfxPoolItem*)pItem ); + pNewSet->ClearItem( RES_FTN_AT_TXTEND ); + pOldSet->ClearItem( RES_FTN_AT_TXTEND ); + } + if( SFX_ITEM_SET == pNewSet->GetItemState( + RES_END_AT_TXTEND, sal_False, &pItem )) + { + ModifyBroadcast( (SfxPoolItem*)&pOldSet->Get( RES_END_AT_TXTEND ), (SfxPoolItem*)pItem ); + pNewSet->ClearItem( RES_END_AT_TXTEND ); + pOldSet->ClearItem( RES_END_AT_TXTEND ); + } + if( !((SwAttrSetChg*)pOld)->GetChgSet()->Count() ) + return; + } + break; + + case RES_SECTION_RESETHIDDENFLAG: + case RES_FTN_AT_TXTEND: + case RES_END_AT_TXTEND : bClients = sal_True; + // no break !! + case RES_SECTION_HIDDEN: + case RES_SECTION_NOT_HIDDEN: + { + SwSection* pSect = GetSection(); + if( pSect && ( bClients || ( RES_SECTION_HIDDEN == nWhich ? + !pSect->IsHiddenFlag() : pSect->IsHiddenFlag() ) ) ) + { + ModifyBroadcast( pOld, pNew ); + } + } + return ; + + + case RES_PROTECT: + case RES_EDIT_IN_READONLY: // edit in readonly sections + // diese Messages bis zum Ende des Baums durchreichen ! + if( GetDepends() ) + { + ModifyBroadcast( pOld, pNew ); + } + return; // das wars + + case RES_OBJECTDYING: + if( !GetDoc()->IsInDtor() && + ((SwPtrMsgPoolItem *)pOld)->pObject == (void*)GetRegisteredIn() ) + { + // mein Parent wird vernichtet, dann an den Parent vom Parent + // umhaengen und wieder aktualisieren + SwFrmFmt::Modify( pOld, pNew ); // erst umhaengen !!! + UpdateParent(); + return; + } + break; + + case RES_FMT_CHG: + if( !GetDoc()->IsInDtor() && + ((SwFmtChg*)pNew)->pChangedFmt == (void*)GetRegisteredIn() && + ((SwFmtChg*)pNew)->pChangedFmt->IsA( TYPE( SwSectionFmt )) ) + { + // mein Parent wird veraendert, muss mich aktualisieren + SwFrmFmt::Modify( pOld, pNew ); // erst umhaengen !!! + UpdateParent(); + return; + } + break; + } + SwFrmFmt::Modify( pOld, pNew ); + + if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which())) + { // invalidate cached uno object + SetXTextSection(uno::Reference<text::XTextSection>(0)); + } +} + + // erfrage vom Format Informationen +sal_Bool SwSectionFmt::GetInfo( SfxPoolItem& rInfo ) const +{ + switch( rInfo.Which() ) + { + case RES_FINDNEARESTNODE: + if( ((SwFmtPageDesc&)GetFmtAttr( RES_PAGEDESC )).GetPageDesc() ) + { + const SwSectionNode* pNd = GetSectionNode(); + if( pNd ) + ((SwFindNearestNode&)rInfo).CheckNode( *pNd ); + } + return sal_True; + + case RES_CONTENT_VISIBLE: + { + SwFrm* pFrm = SwIterator<SwFrm,SwFmt>::FirstElement(*this); + // if the current section has no own frame search for the children + if(!pFrm) + { + SwIterator<SwSectionFmt,SwSectionFmt> aFormatIter(*this); + SwSectionFmt* pChild = aFormatIter.First(); + while(pChild && !pFrm) + { + pFrm = SwIterator<SwFrm,SwFmt>::FirstElement(*pChild); + pChild = aFormatIter.Next(); + } + } + ((SwPtrMsgPoolItem&)rInfo).pObject = pFrm; + } + return sal_False; + } + return SwModify::GetInfo( rInfo ); +} + +extern "C" { + + int +#if defined( WNT ) + __cdecl +#endif +#if defined( ICC ) + _Optlink +#endif + lcl_SectionCmpPos( const void *pFirst, const void *pSecond) + { + const SwSectionFmt* pFSectFmt = (*(SwSectionPtr*)pFirst)->GetFmt(); + const SwSectionFmt* pSSectFmt = (*(SwSectionPtr*)pSecond)->GetFmt(); + OSL_ENSURE( pFSectFmt && pSSectFmt && + pFSectFmt->GetCntnt(sal_False).GetCntntIdx() && + pSSectFmt->GetCntnt(sal_False).GetCntntIdx(), + "ungueltige Sections" ); + return (int)((long)pFSectFmt->GetCntnt(sal_False).GetCntntIdx()->GetIndex()) - + pSSectFmt->GetCntnt(sal_False).GetCntntIdx()->GetIndex(); + } + + int +#if defined( WNT ) + __cdecl +#endif +#if defined( ICC ) + _Optlink +#endif + lcl_SectionCmpNm( const void *pFirst, const void *pSecond) + { + const SwSectionPtr pFSect = *(SwSectionPtr*)pFirst; + const SwSectionPtr pSSect = *(SwSectionPtr*)pSecond; + OSL_ENSURE( pFSect && pSSect, "ungueltige Sections" ); + StringCompare const eCmp = + pFSect->GetSectionName().CompareTo( pSSect->GetSectionName() ); + return eCmp == COMPARE_EQUAL ? 0 + : eCmp == COMPARE_LESS ? 1 : -1; + } +} + + // alle Sections, die von dieser abgeleitet sind +sal_uInt16 SwSectionFmt::GetChildSections( SwSections& rArr, + SectionSort eSort, + sal_Bool bAllSections ) const +{ + rArr.Remove( 0, rArr.Count() ); + + if( GetDepends() ) + { + SwIterator<SwSectionFmt,SwSectionFmt> aIter(*this); + const SwNodeIndex* pIdx; + for( SwSectionFmt* pLast = aIter.First(); pLast; pLast = aIter.Next() ) + if( bAllSections || + ( 0 != ( pIdx = pLast->GetCntnt(sal_False). + GetCntntIdx()) && &pIdx->GetNodes() == &GetDoc()->GetNodes() )) + { + const SwSection* Dummy = pLast->GetSection(); + rArr.C40_INSERT( SwSection, + Dummy, + rArr.Count() ); + } + + // noch eine Sortierung erwuenscht ? + if( 1 < rArr.Count() ) + switch( eSort ) + { + case SORTSECT_NAME: + qsort( (void*)rArr.GetData(), + rArr.Count(), + sizeof( SwSectionPtr ), + lcl_SectionCmpNm ); + break; + + case SORTSECT_POS: + qsort( (void*)rArr.GetData(), + rArr.Count(), + sizeof( SwSectionPtr ), + lcl_SectionCmpPos ); + break; + case SORTSECT_NOT: break; + } + } + return rArr.Count(); +} + + // erfrage, ob sich die Section im Nodes-Array oder UndoNodes-Array + // befindet. +sal_Bool SwSectionFmt::IsInNodesArr() const +{ + const SwNodeIndex* pIdx = GetCntnt(sal_False).GetCntntIdx(); + return pIdx && &pIdx->GetNodes() == &GetDoc()->GetNodes(); +} + + +void SwSectionFmt::UpdateParent() // Parent wurde veraendert +{ + if( !GetDepends() ) + return; + + SwSectionPtr pSection = 0; + const SvxProtectItem* pProtect(0); + // edit in readonly sections + const SwFmtEditInReadonly* pEditInReadonly = 0; + bool bIsHidden = false; + + SwClientIter aIter( *this ); // TODO + ::SwClient * pLast = aIter.GoStart(); + if( pLast ) // konnte zum Anfang gesprungen werden ?? + do { + if( pLast->IsA( TYPE(SwSectionFmt) ) ) + { + if( !pSection ) + { + pSection = GetSection(); + if( GetRegisteredIn() ) + { + const SwSectionPtr pPS = GetParentSection(); + pProtect = &pPS->GetFmt()->GetProtect(); + // edit in readonly sections + pEditInReadonly = &pPS->GetFmt()->GetEditInReadonly(); + bIsHidden = pPS->IsHiddenFlag(); + } + else + { + pProtect = &GetProtect(); + // edit in readonly sections + pEditInReadonly = &GetEditInReadonly(); + bIsHidden = pSection->IsHidden(); + } + } + if (!pProtect->IsCntntProtected() != + !pSection->IsProtectFlag()) + { + pLast->ModifyNotification( (SfxPoolItem*)pProtect, + (SfxPoolItem*)pProtect ); + } + + // edit in readonly sections + if (!pEditInReadonly->GetValue() != + !pSection->IsEditInReadonlyFlag()) + { + pLast->ModifyNotification( (SfxPoolItem*)pEditInReadonly, + (SfxPoolItem*)pEditInReadonly ); + } + + if( bIsHidden == pSection->IsHiddenFlag() ) + { + SwMsgPoolItem aMsgItem( static_cast<sal_uInt16>(bIsHidden + ? RES_SECTION_HIDDEN + : RES_SECTION_NOT_HIDDEN ) ); + pLast->ModifyNotification( &aMsgItem, &aMsgItem ); + } + } + else if( !pSection && + pLast->IsA( TYPE(SwSection) ) ) + { + pSection = (SwSectionPtr)pLast; + if( GetRegisteredIn() ) + { + const SwSectionPtr pPS = GetParentSection(); + pProtect = &pPS->GetFmt()->GetProtect(); + // edit in readonly sections + pEditInReadonly = &pPS->GetFmt()->GetEditInReadonly(); + bIsHidden = pPS->IsHiddenFlag(); + } + else + { + pProtect = &GetProtect(); + // edit in readonly sections + pEditInReadonly = &GetEditInReadonly(); + bIsHidden = pSection->IsHidden(); + } + } + } while( 0 != ( pLast = aIter++ )); +} + + +SwSectionNode* SwSectionFmt::GetSectionNode(bool const bAlways) +{ + const SwNodeIndex* pIdx = GetCntnt(sal_False).GetCntntIdx(); + if( pIdx && ( bAlways || &pIdx->GetNodes() == &GetDoc()->GetNodes() )) + return pIdx->GetNode().GetSectionNode(); + return 0; +} + + // ist die Section eine gueltige fuers GlobalDocument? +const SwSection* SwSectionFmt::GetGlobalDocSection() const +{ + const SwSectionNode* pNd = GetSectionNode(); + if( pNd && + ( FILE_LINK_SECTION == pNd->GetSection().GetType() || + TOX_CONTENT_SECTION == pNd->GetSection().GetType() ) && + pNd->GetIndex() > pNd->GetNodes().GetEndOfExtras().GetIndex() && + !pNd->StartOfSectionNode()->IsSectionNode() && + !pNd->StartOfSectionNode()->FindSectionNode() ) + return &pNd->GetSection(); + return 0; +} + +// sw::Metadatable +::sfx2::IXmlIdRegistry& SwSectionFmt::GetRegistry() +{ + return GetDoc()->GetXmlIdRegistry(); +} + +bool SwSectionFmt::IsInClipboard() const +{ + return GetDoc()->IsClipBoard(); +} + +bool SwSectionFmt::IsInUndo() const +{ + return !IsInNodesArr(); +} + +bool SwSectionFmt::IsInContent() const +{ + SwNodeIndex const*const pIdx = GetCntnt(sal_False).GetCntntIdx(); + OSL_ENSURE(pIdx, "SwSectionFmt::IsInContent: no index?"); + return (pIdx) ? !GetDoc()->IsInHeaderFooter(*pIdx) : true; +} + +// n.b.: if the section format represents an index, then there is both a +// SwXDocumentIndex and a SwXTextSection instance for this single core object. +// these two can both implement XMetadatable and forward to the same core +// section format. but here only one UNO object can be returned, +// so always return the text section. +uno::Reference< rdf::XMetadatable > +SwSectionFmt::MakeUnoObject() +{ + uno::Reference<rdf::XMetadatable> xMeta; + SwSection *const pSection( GetSection() ); + if (pSection) + { + xMeta.set( SwXTextSection::CreateXTextSection(this, + TOX_HEADER_SECTION == pSection->GetType()), + uno::UNO_QUERY ); + } + return xMeta; +} + + +// Method to break section links inside a linked section +void lcl_BreakSectionLinksInSect( const SwSectionNode& rSectNd ) +{ + if ( !rSectNd.GetDoc() ) + { + OSL_FAIL( "method <lcl_RemoveSectionLinksInSect(..)> - no Doc at SectionNode" ); + return; + } + + if ( !rSectNd.GetSection().IsConnected() ) + { + OSL_FAIL( "method <lcl_RemoveSectionLinksInSect(..)> - no Link at Section of SectionNode" ); + return; + } + const ::sfx2::SvBaseLink* pOwnLink( &(rSectNd.GetSection().GetBaseLink() ) ); + const ::sfx2::SvBaseLinks& rLnks = rSectNd.GetDoc()->GetLinkManager().GetLinks(); + for ( sal_uInt16 n = rLnks.Count(); n > 0; ) + { + SwIntrnlSectRefLink* pSectLnk = dynamic_cast<SwIntrnlSectRefLink*>(&(*rLnks[ --n ])); + if ( pSectLnk && pSectLnk != pOwnLink && + pSectLnk->IsInRange( rSectNd.GetIndex(), rSectNd.EndOfSectionIndex() ) ) + { + // break the link of the corresponding section. + // the link is also removed from the link manager + pSectLnk->GetSectNode()->GetSection().BreakLink(); + + // for robustness, because link is removed from the link manager + if ( n > rLnks.Count() ) + { + n = rLnks.Count(); + } + } + } +} + +void lcl_UpdateLinksInSect( SwBaseLink& rUpdLnk, SwSectionNode& rSectNd ) +{ + SwDoc* pDoc = rSectNd.GetDoc(); + SwDocShell* pDShell = pDoc->GetDocShell(); + if( !pDShell || !pDShell->GetMedium() ) + return ; + + String sName( pDShell->GetMedium()->GetName() ); + SwBaseLink* pBLink; + String sMimeType( SotExchange::GetFormatMimeType( FORMAT_FILE )); + uno::Any aValue; + aValue <<= ::rtl::OUString( sName ); // beliebiger Name + + const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks(); + for( sal_uInt16 n = rLnks.Count(); n; ) + { + ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); + if( pLnk && pLnk != &rUpdLnk && + OBJECT_CLIENT_FILE == pLnk->GetObjType() && + pLnk->ISA( SwBaseLink ) && + ( pBLink = (SwBaseLink*)pLnk )->IsInRange( rSectNd.GetIndex(), + rSectNd.EndOfSectionIndex() ) ) + { + // liegt in dem Bereich: also updaten. Aber nur wenns nicht + // im gleichen File liegt + String sFName; + pDoc->GetLinkManager().GetDisplayNames( pBLink, 0, &sFName, 0, 0 ); + if( sFName != sName ) + { + pBLink->DataChanged( sMimeType, aValue ); + + // ggfs. neu den Link-Pointer wieder suchen, damit nicht einer + // ausgelassen oder doppelt gerufen wird. + if( n >= rLnks.Count() && 0 != ( n = rLnks.Count() )) + --n; + + if( n && pLnk != &(*rLnks[ n ]) ) + { + // suchen - kann nur davor liegen!! + while( n ) + if( pLnk == &(*rLnks[ --n ] ) ) + break; + } + } + } + } +} + + +// sucht sich die richtige DocShell raus oder erzeugt eine neue: +// Der Return-Wert gibt an, was mit der Shell zu geschehen hat: +// 0 - Fehler, konnte DocShell nicht finden +// 1 - DocShell ist ein existieren Document +// 2 - DocShell wurde neu angelegt, muss also wieder geschlossen werden ( will be assigned to xLockRef additionaly ) + +int lcl_FindDocShell( SfxObjectShellRef& xDocSh, + SfxObjectShellLock& xLockRef, + const String& rFileName, + const String& rPasswd, + String& rFilter, + sal_Int16 nVersion, + SwDocShell* pDestSh ) +{ + if( !rFileName.Len() ) + return 0; + + // 1. existiert die Datei schon in der Liste aller Dokumente? + INetURLObject aTmpObj( rFileName ); + aTmpObj.SetMark( aEmptyStr ); + + // erstmal nur ueber die DocumentShells laufen und die mit dem + // Namen heraussuchen: + TypeId aType( TYPE(SwDocShell) ); + + SfxObjectShell* pShell = pDestSh; + sal_Bool bFirst = 0 != pShell; + + if( !bFirst ) + // keine DocShell uebergeben, also beginne mit der ersten aus der + // DocShell Liste + pShell = SfxObjectShell::GetFirst( &aType ); + + while( pShell ) + { + // die wollen wir haben + SfxMedium* pMed = pShell->GetMedium(); + if( pMed && pMed->GetURLObject() == aTmpObj ) + { + const SfxPoolItem* pItem; + if( ( SFX_ITEM_SET == pMed->GetItemSet()->GetItemState( + SID_VERSION, sal_False, &pItem ) ) + ? (nVersion == ((SfxInt16Item*)pItem)->GetValue()) + : !nVersion ) + { + // gefunden also returnen + xDocSh = pShell; + return 1; + } + } + + if( bFirst ) + { + bFirst = sal_False; + pShell = SfxObjectShell::GetFirst( &aType ); + } + else + pShell = SfxObjectShell::GetNext( *pShell, &aType ); + } + + // 2. selbst die Date oeffnen + SfxMedium* pMed = new SfxMedium( aTmpObj.GetMainURL( + INetURLObject::NO_DECODE ), STREAM_READ, sal_True ); + if( INET_PROT_FILE == aTmpObj.GetProtocol() ) + pMed->DownLoad(); // nur mal das Medium anfassen (DownLoaden) + + const SfxFilter* pSfxFlt = 0; + if( !pMed->GetError() ) + { + String sFactory(String::CreateFromAscii(SwDocShell::Factory().GetShortName())); + SfxFilterMatcher aMatcher( sFactory ); + + // kein Filter, dann suche ihn. Ansonsten teste, ob der angegebene + // ein gueltiger ist + if( rFilter.Len() ) + { + pSfxFlt = aMatcher.GetFilter4FilterName( rFilter ); + } + + if( nVersion ) + pMed->GetItemSet()->Put( SfxInt16Item( SID_VERSION, nVersion )); + + if( rPasswd.Len() ) + pMed->GetItemSet()->Put( SfxStringItem( SID_PASSWORD, rPasswd )); + + if( !pSfxFlt ) + aMatcher.DetectFilter( *pMed, &pSfxFlt, sal_False, sal_False ); + + if( pSfxFlt ) + { + // ohne Filter geht gar nichts + pMed->SetFilter( pSfxFlt ); + + // if the new shell is created, SfxObjectShellLock should be used to let it be closed later for sure + xLockRef = new SwDocShell( SFX_CREATE_MODE_INTERNAL ); + xDocSh = (SfxObjectShell*)xLockRef; + if( xDocSh->DoLoad( pMed ) ) + return 2; + } + } + + if( !xDocSh.Is() ) // Medium muss noch geloescht werden + delete pMed; + + return 0; // das war wohl nichts +} + + +void SwIntrnlSectRefLink::DataChanged( const String& rMimeType, + const uno::Any & rValue ) +{ + SwSectionNode* pSectNd = rSectFmt.GetSectionNode( sal_False ); + SwDoc* pDoc = rSectFmt.GetDoc(); + + sal_uLong nDataFormat = SotExchange::GetFormatIdFromMimeType( rMimeType ); + + if( !pSectNd || !pDoc || pDoc->IsInDtor() || ChkNoDataFlag() || + sfx2::LinkManager::RegisterStatusInfoId() == nDataFormat ) + { + // sollten wir schon wieder im Undo stehen? + return ; + } + + // #i38810# - Due to possible existing signatures, the + // document has to be modified after updating a link. + pDoc->SetModified(); + // set additional flag that links have been updated, in order to check this + // during load. + pDoc->SetLinksUpdated( sal_True ); + // <-- + + // Undo immer abschalten + bool const bWasUndo = pDoc->GetIDocumentUndoRedo().DoesUndo(); + pDoc->GetIDocumentUndoRedo().DoUndo(false); + sal_Bool bWasVisibleLinks = pDoc->IsVisibleLinks(); + pDoc->SetVisibleLinks( sal_False ); + + SwPaM* pPam; + ViewShell* pVSh = 0; + SwEditShell* pESh = pDoc->GetEditShell( &pVSh ); + pDoc->LockExpFlds(); + { + // am Anfang des Bereichs einen leeren TextNode einfuegen + SwNodeIndex aIdx( *pSectNd, +1 ); + SwNodeIndex aEndIdx( *pSectNd->EndOfSectionNode() ); + SwTxtNode* pNewNd = pDoc->GetNodes().MakeTxtNode( aIdx, + pDoc->GetTxtCollFromPool( RES_POOLCOLL_TEXT ) ); + + if( pESh ) + pESh->StartAllAction(); + else if( pVSh ) + pVSh->StartAction(); + + SwPosition aPos( aIdx, SwIndex( pNewNd, 0 )); + aPos.nNode--; + pDoc->CorrAbs( aIdx, aEndIdx, aPos, sal_True ); + + pPam = new SwPaM( aPos ); + + //und alles dahinter liegende loeschen + aIdx--; + DelFlyInRange( aIdx, aEndIdx ); + _DelBookmarks(aIdx, aEndIdx); + aIdx++; + + pDoc->GetNodes().Delete( aIdx, aEndIdx.GetIndex() - aIdx.GetIndex() ); + } + + SwSection& rSection = pSectNd->GetSection(); + rSection.SetConnectFlag(false); + + ::rtl::OUString sNewFileName; + Reader* pRead = 0; + switch( nDataFormat ) + { + case FORMAT_STRING: + pRead = ReadAscii; + break; + + case FORMAT_RTF: + pRead = SwReaderWriter::GetReader( READER_WRITER_RTF ); + break; + + case FORMAT_FILE: + if( rValue.hasValue() && ( rValue >>= sNewFileName ) ) + { + String sFilter, sRange, sFileName( sNewFileName ); + pDoc->GetLinkManager().GetDisplayNames( this, 0, &sFileName, + &sRange, &sFilter ); + + RedlineMode_t eOldRedlineMode = nsRedlineMode_t::REDLINE_NONE; + SfxObjectShellRef xDocSh; + SfxObjectShellLock xLockRef; + int nRet; + if( !sFileName.Len() ) + { + xDocSh = pDoc->GetDocShell(); + nRet = 1; + } + else + { + nRet = lcl_FindDocShell( xDocSh, xLockRef, sFileName, + rSection.GetLinkFilePassword(), + sFilter, 0, pDoc->GetDocShell() ); + if( nRet ) + { + SwDoc* pSrcDoc = ((SwDocShell*)&xDocSh)->GetDoc(); + eOldRedlineMode = pSrcDoc->GetRedlineMode(); + pSrcDoc->SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT ); + } + } + + if( nRet ) + { + rSection.SetConnectFlag(true); + + SwNodeIndex aSave( pPam->GetPoint()->nNode, -1 ); + SwNodeRange* pCpyRg = 0; + + if( xDocSh->GetMedium() && + !rSection.GetLinkFilePassword().Len() ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == xDocSh->GetMedium()->GetItemSet()-> + GetItemState( SID_PASSWORD, sal_False, &pItem ) ) + rSection.SetLinkFilePassword( + ((SfxStringItem*)pItem)->GetValue() ); + } + + SwDoc* pSrcDoc = ((SwDocShell*)&xDocSh)->GetDoc(); + + if( sRange.Len() ) + { + // Rekursionen abfangen + sal_Bool bRecursion = sal_False; + if( pSrcDoc == pDoc ) + { + SwServerObjectRef refObj( (SwServerObject*) + pDoc->CreateLinkSource( sRange )); + if( refObj.Is() ) + { + bRecursion = refObj->IsLinkInServer( this ) || + ChkNoDataFlag(); + } + } + + SwNodeIndex& rInsPos = pPam->GetPoint()->nNode; + + SwPaM* pCpyPam = 0; + if( !bRecursion && + pSrcDoc->SelectServerObj( sRange, pCpyPam, pCpyRg ) + && pCpyPam ) + { + if( pSrcDoc != pDoc || + pCpyPam->Start()->nNode > rInsPos || + rInsPos >= pCpyPam->End()->nNode ) + { + pSrcDoc->CopyRange( *pCpyPam, *pPam->GetPoint(), + false ); + } + delete pCpyPam; + } + if( pCpyRg && pSrcDoc == pDoc && + pCpyRg->aStart < rInsPos && rInsPos < pCpyRg->aEnd ) + delete pCpyRg, pCpyRg = 0; + } + else if( pSrcDoc != pDoc ) + pCpyRg = new SwNodeRange( pSrcDoc->GetNodes().GetEndOfExtras(), 2, + pSrcDoc->GetNodes().GetEndOfContent() ); + + // #i81653# + // Update links of extern linked document or extern linked + // document section, if section is protected. + if ( pSrcDoc != pDoc && + rSection.IsProtectFlag() ) + { + pSrcDoc->GetLinkManager().UpdateAllLinks( sal_False, sal_True, sal_False, 0 ); + } + // <-- + if( pCpyRg ) + { + SwNodeIndex& rInsPos = pPam->GetPoint()->nNode; + sal_Bool bCreateFrm = rInsPos.GetIndex() <= + pDoc->GetNodes().GetEndOfExtras().GetIndex() || + rInsPos.GetNode().FindTableNode(); + + SwTblNumFmtMerge aTNFM( *pSrcDoc, *pDoc ); + + pSrcDoc->CopyWithFlyInFly( *pCpyRg, 0, rInsPos, bCreateFrm ); + aSave++; + + if( !bCreateFrm ) + ::MakeFrms( pDoc, aSave, rInsPos ); + + // den letzten Node noch loeschen, aber nur wenn + // erfolgreich kopiert werden konnte, also der Bereich + // mehr als 1 Node enthaelt + if( 2 < pSectNd->EndOfSectionIndex() - pSectNd->GetIndex() ) + { + aSave = rInsPos; + pPam->Move( fnMoveBackward, fnGoNode ); + pPam->SetMark(); // beide SwPositions ummelden! + + pDoc->CorrAbs( aSave, *pPam->GetPoint(), 0, sal_True ); + pDoc->GetNodes().Delete( aSave, 1 ); + } + delete pCpyRg; + } + + lcl_BreakSectionLinksInSect( *pSectNd ); + + // update alle Links in diesem Bereich + lcl_UpdateLinksInSect( *this, *pSectNd ); + } + if( xDocSh.Is() ) + { + if( 2 == nRet ) + xDocSh->DoClose(); + else if( ((SwDocShell*)&xDocSh)->GetDoc() ) + ((SwDocShell*)&xDocSh)->GetDoc()->SetRedlineMode( + eOldRedlineMode ); + } + } + break; + } + + // !!!! DDE nur updaten wenn Shell vorhanden ist?? + uno::Sequence< sal_Int8 > aSeq; + if( pRead && rValue.hasValue() && ( rValue >>= aSeq ) ) + { + if( pESh ) + { + pESh->Push(); + SwPaM* pCrsr = pESh->GetCrsr(); + *pCrsr->GetPoint() = *pPam->GetPoint(); + delete pPam; + pPam = pCrsr; + } + + SvMemoryStream aStrm( (void*)aSeq.getConstArray(), aSeq.getLength(), + STREAM_READ ); + aStrm.Seek( 0 ); + +#if OSL_DEBUG_LEVEL > 1 + { + SvFileStream aDeb( String::CreateFromAscii( + "file:///d|/temp/update.txt" ), STREAM_WRITE ); + aDeb << aStrm; + } + aStrm.Seek( 0 ); +#endif + + // TODO/MBA: it's impossible to set a BaseURL here! + SwReader aTmpReader( aStrm, aEmptyStr, pDoc->GetDocShell()->GetMedium()->GetBaseURL(), *pPam ); + + if( !IsError( aTmpReader.Read( *pRead ) )) + { + rSection.SetConnectFlag(true); + } + + if( pESh ) + { + pESh->Pop( sal_False ); + pPam = 0; // pam is deleted before + } + } + + + // remove all undo actions and turn undo on again + pDoc->GetIDocumentUndoRedo().DelAllUndoObj(); + pDoc->GetIDocumentUndoRedo().DoUndo(bWasUndo); + pDoc->SetVisibleLinks( bWasVisibleLinks ); + + pDoc->UnlockExpFlds(); + if( !pDoc->IsExpFldsLocked() ) + pDoc->UpdateExpFlds(NULL, true); + + if( pESh ) + pESh->EndAllAction(); + else if( pVSh ) + pVSh->EndAction(); + delete pPam; // wurde am Anfang angelegt +} + + +void SwIntrnlSectRefLink::Closed() +{ + SwDoc* pDoc = rSectFmt.GetDoc(); + if( pDoc && !pDoc->IsInDtor() ) + { + // Advise verabschiedet sich, den Bereich als nicht geschuetzt + // kennzeichnen und das Flag umsetzen + + const SwSectionFmts& rFmts = pDoc->GetSections(); + for( sal_uInt16 n = rFmts.Count(); n; ) + if( rFmts[ --n ] == &rSectFmt ) + { + ViewShell* pSh; + SwEditShell* pESh = pDoc->GetEditShell( &pSh ); + + if( pESh ) + pESh->StartAllAction(); + else + pSh->StartAction(); + + SwSectionData aSectionData(*rSectFmt.GetSection()); + aSectionData.SetType( CONTENT_SECTION ); + aSectionData.SetLinkFileName( aEmptyStr ); + aSectionData.SetHidden( false ); + aSectionData.SetProtectFlag( false ); + // edit in readonly sections + aSectionData.SetEditInReadonlyFlag( false ); + + aSectionData.SetConnectFlag( false ); + + pDoc->UpdateSection( n, aSectionData ); + + // alle in der Section liegenden Links werden sichtbar + SwSectionNode* pSectNd = rSectFmt.GetSectionNode( sal_False ); + if( pSectNd ) + pSectNd->GetSection().MakeChildLinksVisible( *pSectNd ); + + if( pESh ) + pESh->EndAllAction(); + else + pSh->EndAction(); + break; + } + } + SvBaseLink::Closed(); +} + + +void SwSection::CreateLink( LinkCreateType eCreateType ) +{ + SwSectionFmt* pFmt = GetFmt(); + OSL_ENSURE(pFmt, "SwSection::CreateLink: no format?"); + if (!pFmt || (CONTENT_SECTION == m_Data.GetType())) + return ; + + sal_uInt16 nUpdateType = sfx2::LINKUPDATE_ALWAYS; + + if (!m_RefLink.Is()) + { + // create BaseLink + m_RefLink = new SwIntrnlSectRefLink( *pFmt, nUpdateType, FORMAT_RTF ); + } + else + { + pFmt->GetDoc()->GetLinkManager().Remove( m_RefLink ); + } + + SwIntrnlSectRefLink *const pLnk = + static_cast<SwIntrnlSectRefLink*>(& m_RefLink); + + String sCmd( m_Data.GetLinkFileName() ); + xub_StrLen nPos; + while( STRING_NOTFOUND != (nPos = sCmd.SearchAscii( " " )) ) + sCmd.Erase( nPos, 1 ); + + pLnk->SetUpdateMode( nUpdateType ); + pLnk->SetVisible( pFmt->GetDoc()->IsVisibleLinks() ); + + switch (m_Data.GetType()) + { + case DDE_LINK_SECTION: + pLnk->SetLinkSourceName( sCmd ); + pFmt->GetDoc()->GetLinkManager().InsertDDELink( pLnk ); + break; + case FILE_LINK_SECTION: + { + pLnk->SetContentType( FORMAT_FILE ); + String sFltr( sCmd.GetToken( 1, sfx2::cTokenSeperator ) ); + String sRange( sCmd.GetToken( 2, sfx2::cTokenSeperator ) ); + pFmt->GetDoc()->GetLinkManager().InsertFileLink( *pLnk, + static_cast<sal_uInt16>(m_Data.GetType()), + sCmd.GetToken( 0, sfx2::cTokenSeperator ), + ( sFltr.Len() ? &sFltr : 0 ), + ( sRange.Len() ? &sRange : 0 ) ); + } + break; + default: + OSL_ENSURE( !this, "Was ist das fuer ein Link?" ); + } + + switch( eCreateType ) + { + case CREATE_CONNECT: // Link gleich connecten + pLnk->Connect(); + break; + + case CREATE_UPDATE: // Link connecten und updaten + pLnk->Update(); + break; + case CREATE_NONE: break; + } +} + +void SwSection::BreakLink() +{ + const SectionType eCurrentType( GetType() ); + if ( eCurrentType == CONTENT_SECTION || + eCurrentType == TOX_HEADER_SECTION || + eCurrentType == TOX_CONTENT_SECTION ) + { + // nothing to do + return; + } + + // release link, if it exists + if (m_RefLink.Is()) + { + SwSectionFmt *const pFormat( GetFmt() ); + OSL_ENSURE(pFormat, "SwSection::BreakLink: no format?"); + if (pFormat) + { + pFormat->GetDoc()->GetLinkManager().Remove( m_RefLink ); + } + m_RefLink.Clear(); + } + // change type + SetType( CONTENT_SECTION ); + // reset linked file data + SetLinkFileName( aEmptyStr ); + SetLinkFilePassword( aEmptyStr ); +} + +const SwNode* SwIntrnlSectRefLink::GetAnchor() const +{ + return rSectFmt.GetSectionNode( sal_False ); +} + + +sal_Bool SwIntrnlSectRefLink::IsInRange( sal_uLong nSttNd, sal_uLong nEndNd, + xub_StrLen , xub_StrLen ) const +{ + SwStartNode* pSttNd = rSectFmt.GetSectionNode( sal_False ); + return pSttNd && + nSttNd < pSttNd->GetIndex() && + pSttNd->EndOfSectionIndex() < nEndNd; +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/swbaslnk.cxx b/sw/source/core/docnode/swbaslnk.cxx new file mode 100644 index 000000000000..d04fd3fee03b --- /dev/null +++ b/sw/source/core/docnode/swbaslnk.cxx @@ -0,0 +1,502 @@ +/* -*- 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_sw.hxx" + +#include <hintids.hxx> +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> + +#include <osl/thread.hxx> +#include <salhelper/condition.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/lnkbase.hxx> +#include <sfx2/objsh.hxx> +#include <editeng/boxitem.hxx> +#include <svx/svxids.hrc> // fuer die EventIds +#include <sfx2/linkmgr.hxx> +#include <svtools/soerr.hxx> +#include <fmtfsize.hxx> +#include <fmtanchr.hxx> +#include <frmatr.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <editsh.hxx> +#include <swtable.hxx> +#include <docary.hxx> +#include <swevent.hxx> +#include <swbaslnk.hxx> +#include <swserv.hxx> +#include <ndgrf.hxx> +#include <ndole.hxx> +#include <hints.hxx> +#include <tabfrm.hxx> +#include <cntfrm.hxx> +#include <htmltbl.hxx> + +using namespace com::sun::star; + +sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ); + +TYPEINIT1( SwBaseLink, ::sfx2::SvBaseLink ); + +SV_IMPL_REF( SwServerObject ) + +void lcl_CallModify( SwGrfNode& rGrfNd, SfxPoolItem& rItem ) +{ + //call fist all not SwNoTxtFrames, then the SwNoTxtFrames. + // The reason is, that in the SwNoTxtFrames the Graphic + // after a Paint will be swapped out! So all other "behind" + // them havent't a loaded Graphic. + rGrfNd.LockModify(); + + SwClientIter aIter( rGrfNd ); // TODO + for( int n = 0; n < 2; ++n ) + { + SwClient * pLast = aIter.GoStart(); + if( pLast ) // konnte zum Anfang gesprungen werden ?? + { + do { + if( (0 == n) ^ ( 0 != pLast->ISA( SwCntntFrm )) ) + pLast->ModifyNotification( &rItem, &rItem ); + } while( 0 != ( pLast = aIter++ )); + } + } + rGrfNd.UnlockModify(); +} + + +void SwBaseLink::DataChanged( const String& rMimeType, + const uno::Any & rValue ) +{ + if( !pCntntNode ) + { + OSL_ENSURE(!this, "DataChanged ohne ContentNode" ); + return ; + } + + SwDoc* pDoc = pCntntNode->GetDoc(); + if( pDoc->IsInDtor() || ChkNoDataFlag() || bIgnoreDataChanged ) + { + bIgnoreDataChanged = sal_False; + return ; + } + + sal_uLong nFmt = SotExchange::GetFormatIdFromMimeType( rMimeType ); + + if( pCntntNode->IsNoTxtNode() && + nFmt == sfx2::LinkManager::RegisterStatusInfoId() ) + { + // nur eine Statusaenderung - Events bedienen ? + ::rtl::OUString sState; + if( rValue.hasValue() && ( rValue >>= sState )) + { + sal_uInt16 nEvent = 0; + switch( sState.toInt32() ) + { + case sfx2::LinkManager::STATE_LOAD_OK: nEvent = SVX_EVENT_IMAGE_LOAD; break; + case sfx2::LinkManager::STATE_LOAD_ERROR: nEvent = SVX_EVENT_IMAGE_ERROR; break; + case sfx2::LinkManager::STATE_LOAD_ABORT: nEvent = SVX_EVENT_IMAGE_ABORT; break; + } + + SwFrmFmt* pFmt; + if( nEvent && 0 != ( pFmt = pCntntNode->GetFlyFmt() )) + { + SwCallMouseEvent aCallEvent; + aCallEvent.Set( EVENT_OBJECT_IMAGE, pFmt ); + pDoc->CallEvent( nEvent, aCallEvent ); + } + } + return; // das wars! + } + + sal_Bool bUpdate = sal_False; + sal_Bool bGraphicArrived = sal_False; + sal_Bool bGraphicPieceArrived = sal_False; + sal_Bool bDontNotify = sal_False; + Size aGrfSz, aFrmFmtSz; + + if( pCntntNode->IsGrfNode() ) + { + GraphicObject& rGrfObj = ((SwGrfNode*)pCntntNode)->GetGrfObj(); + + bDontNotify = ((SwGrfNode*)pCntntNode)->IsFrameInPaint(); + + bGraphicArrived = GetObj()->IsDataComplete(); + bGraphicPieceArrived = GetObj()->IsPending(); + ((SwGrfNode*)pCntntNode)->SetGrafikArrived( bGraphicArrived ); + + Graphic aGrf; + if( sfx2::LinkManager::GetGraphicFromAny( rMimeType, rValue, aGrf ) && + ( GRAPHIC_DEFAULT != aGrf.GetType() || + GRAPHIC_DEFAULT != rGrfObj.GetType() ) ) + { + aGrfSz = ::GetGraphicSizeTwip( aGrf, 0 ); + if( static_cast< const SwGrfNode * >( pCntntNode )->IsChgTwipSizeFromPixel() ) + { + const MapMode aMapTwip( MAP_TWIP ); + aFrmFmtSz = + Application::GetDefaultDevice()->PixelToLogic( + aGrf.GetSizePixel(), aMapTwip ); + + } + else + { + aFrmFmtSz = aGrfSz; + } + Size aSz( ((SwGrfNode*)pCntntNode)->GetTwipSize() ); + + if( bGraphicPieceArrived && GRAPHIC_DEFAULT != aGrf.GetType() && + ( !aSz.Width() || !aSz.Height() ) ) + { + // wenn nur ein Teil ankommt, aber die Groesse nicht + // gesetzt ist, dann muss "unten" der Teil von + // bGraphicArrived durchlaufen werden! + // (ansonten wird die Grafik in deft. Size gepaintet) + bGraphicArrived = sal_True; + bGraphicPieceArrived = sal_False; + } + + rGrfObj.SetGraphic( aGrf, rGrfObj.GetLink() ); + bUpdate = sal_True; + + // Bug 33999: damit der Node den Transparent-Status + // richtig gesetzt hat, ohne auf die Grafik + // zugreifen zu muessen (sonst erfolgt ein SwapIn!). + if( bGraphicArrived ) + { + // immer mit der korrekten Grafik-Size arbeiten + if( aGrfSz.Height() && aGrfSz.Width() && + aSz.Height() && aSz.Width() && + aGrfSz != aSz ) + ((SwGrfNode*)pCntntNode)->SetTwipSize( aGrfSz ); + } + } + if ( bUpdate && !bGraphicArrived && !bGraphicPieceArrived ) + ((SwGrfNode*)pCntntNode)->SetTwipSize( Size(0,0) ); + } + else if( pCntntNode->IsOLENode() ) + bUpdate = sal_True; + + ViewShell *pSh = 0; + SwEditShell* pESh = pDoc->GetEditShell( &pSh ); + + if ( bUpdate && bGraphicPieceArrived && !(bSwapIn || bDontNotify) ) + { + //Hint ohne Actions verschicken, loest direktes Paint aus. + if ( (!pSh || !pSh->ActionPend()) && (!pESh || !pESh->ActionPend()) ) + { + SwMsgPoolItem aMsgHint( RES_GRAPHIC_PIECE_ARRIVED ); + pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); + bUpdate = sal_False; + } + } + + static sal_Bool bInNotifyLinks = sal_False; + if( bUpdate && !bDontNotify && (!bSwapIn || bGraphicArrived) && + !bInNotifyLinks) + { + sal_Bool bLockView = sal_False; + if( pSh ) + { + bLockView = pSh->IsViewLocked(); + pSh->LockView( sal_True ); + } + + if( pESh ) + pESh->StartAllAction(); + else if( pSh ) + pSh->StartAction(); + + SwMsgPoolItem aMsgHint( static_cast<sal_uInt16>( + bGraphicArrived ? RES_GRAPHIC_ARRIVED : RES_UPDATE_ATTR ) ); + + if ( bGraphicArrived ) + { + //Alle benachrichtigen, die am gleichen Link horchen. + bInNotifyLinks = sal_True; + + const ::sfx2::SvBaseLinks& rLnks = pDoc->GetLinkManager().GetLinks(); + for( sal_uInt16 n = rLnks.Count(); n; ) + { + ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); + if( pLnk && OBJECT_CLIENT_GRF == pLnk->GetObjType() && + pLnk->ISA( SwBaseLink ) && pLnk->GetObj() == GetObj() ) + { + SwBaseLink* pBLink = (SwBaseLink*)pLnk; + SwGrfNode* pGrfNd = (SwGrfNode*)pBLink->pCntntNode; + + if( pBLink != this && + ( !bSwapIn || + GRAPHIC_DEFAULT == pGrfNd->GetGrfObj().GetType())) + { + pBLink->bIgnoreDataChanged = sal_False; + pBLink->DataChanged( rMimeType, rValue ); + pBLink->bIgnoreDataChanged = sal_True; + + pGrfNd->SetGrafikArrived( ((SwGrfNode*)pCntntNode)-> + IsGrafikArrived() ); + + // Fly der Grafik anpassen ! + if( !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) + ::lcl_CallModify( *pGrfNd, aMsgHint ); + } + else if( pBLink == this && + !::SetGrfFlySize( aGrfSz, aFrmFmtSz, pGrfNd ) ) + // Fly der Grafik anpassen ! + ::lcl_CallModify( *pGrfNd, aMsgHint ); + } + } + + bInNotifyLinks = sal_False; + } + else + { + pCntntNode->ModifyNotification( &aMsgHint, &aMsgHint ); + } + + + if( pESh ) + { + const sal_Bool bEndActionByVirDev = pESh->IsEndActionByVirDev(); + pESh->SetEndActionByVirDev( sal_True ); + pESh->EndAllAction(); + pESh->SetEndActionByVirDev( bEndActionByVirDev ); + } + else if( pSh ) + pSh->EndAction(); + + if( pSh && !bLockView ) + pSh->LockView( sal_False ); + } +} + +sal_Bool SetGrfFlySize( const Size& rGrfSz, const Size& rFrmSz, SwGrfNode* pGrfNd ) +{ + sal_Bool bRet = sal_False; + ViewShell *pSh; + CurrShell *pCurr = 0; + if ( pGrfNd->GetDoc()->GetEditShell( &pSh ) ) + pCurr = new CurrShell( pSh ); + + Size aSz = pGrfNd->GetTwipSize(); + if ( !(aSz.Width() && aSz.Height()) && + rGrfSz.Width() && rGrfSz.Height() ) + { + SwFrmFmt* pFmt; + if( pGrfNd->IsChgTwipSize() && + 0 != (pFmt = pGrfNd->GetFlyFmt()) ) + { + Size aCalcSz( aSz ); + if ( !aSz.Height() && aSz.Width() ) + //passende Hoehe ausrechnen. + aCalcSz.Height() = rFrmSz.Height() * + aSz.Width() / rFrmSz.Width(); + else if ( !aSz.Width() && aSz.Height() ) + //passende Breite ausrechnen + aCalcSz.Width() = rFrmSz.Width() * + aSz.Height() / rFrmSz.Height(); + else + //Hoehe und Breite uebernehmen + aCalcSz = rFrmSz; + + const SvxBoxItem &rBox = pFmt->GetBox(); + aCalcSz.Width() += rBox.CalcLineSpace(BOX_LINE_LEFT) + + rBox.CalcLineSpace(BOX_LINE_RIGHT); + aCalcSz.Height()+= rBox.CalcLineSpace(BOX_LINE_TOP) + + rBox.CalcLineSpace(BOX_LINE_BOTTOM); + const SwFmtFrmSize& rOldAttr = pFmt->GetFrmSize(); + if( rOldAttr.GetSize() != aCalcSz ) + { + SwFmtFrmSize aAttr( rOldAttr ); + aAttr.SetSize( aCalcSz ); + pFmt->SetFmtAttr( aAttr ); + bRet = sal_True; + } + + if( !aSz.Width() ) + { + // Wenn die Grafik in einer Tabelle verankert ist, muess + // die Tabellen-Spalten neu berechnet werden + const SwDoc *pDoc = pGrfNd->GetDoc(); + const SwPosition* pAPos = pFmt->GetAnchor().GetCntntAnchor(); + SwNode *pANd; + SwTableNode *pTblNd; + if( pAPos && + 0 != (pANd = & pAPos->nNode.GetNode()) && + 0 != (pTblNd = pANd->FindTableNode()) ) + { + const sal_Bool bLastGrf = !pTblNd->GetTable().DecGrfsThatResize(); + SwHTMLTableLayout *pLayout = + pTblNd->GetTable().GetHTMLTableLayout(); + if( pLayout ) + { + const sal_uInt16 nBrowseWidth = + pLayout->GetBrowseWidthByTable( *pDoc ); + if ( nBrowseWidth ) + { + pLayout->Resize( nBrowseWidth, sal_True, sal_True, + bLastGrf ? HTMLTABLE_RESIZE_NOW + : 500 ); + } + } + } + } + } + + // SetTwipSize skaliert ggf. eine ImageMap neu und + // braucht dazu das Frame-Format + pGrfNd->SetTwipSize( rGrfSz ); + } + + delete pCurr; + + return bRet; +} + + +sal_Bool SwBaseLink::SwapIn( sal_Bool bWaitForData, sal_Bool bNativFormat ) +{ + bSwapIn = sal_True; + + sal_Bool bRes; + + if( !GetObj() && ( bNativFormat || ( !IsSynchron() && bWaitForData ) )) + { + AddNextRef(); + _GetRealObject(); + ReleaseRef(); + } + +#if OSL_DEBUG_LEVEL > 1 + { + String sGrfNm; + if(GetLinkManager()) + GetLinkManager()->GetDisplayNames( this, 0, &sGrfNm, 0, 0 ); + int x = 0; + ++x; + } +#endif + + if( GetObj() ) + { + String aMimeType( SotExchange::GetFormatMimeType( GetContentType() )); + uno::Any aValue; + GetObj()->GetData( aValue, aMimeType, !IsSynchron() && bWaitForData ); + + if( bWaitForData && !GetObj() ) + { + OSL_ENSURE( !this, "das SvxFileObject wurde in einem GetData geloescht!" ); + bRes = sal_False; + } + else if( 0 != ( bRes = aValue.hasValue() ) ) + { + //JP 14.04.99: Bug 64820 - das Flag muss beim SwapIn natuerlich + // zurueckgesetzt werden. Die Daten sollen ja neu + // uebernommen werden + bIgnoreDataChanged = sal_False; + DataChanged( aMimeType, aValue ); + } + } + else if( !IsSynchron() && bWaitForData ) + { + SetSynchron( sal_True ); + bRes = Update(); + SetSynchron( sal_False ); + } + else + bRes = Update(); + + bSwapIn = sal_False; + return bRes; +} + +void SwBaseLink::Closed() +{ + if( pCntntNode && !pCntntNode->GetDoc()->IsInDtor() ) + { + // wir heben die Verbindung auf + if( pCntntNode->IsGrfNode() ) + ((SwGrfNode*)pCntntNode)->ReleaseLink(); + } + SvBaseLink::Closed(); +} + +const SwNode* SwBaseLink::GetAnchor() const +{ + if (pCntntNode) + { + SwFrmFmt *const pFmt = pCntntNode->GetFlyFmt(); + if (pFmt) + { + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if (pAPos && + ((FLY_AS_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId()) || + (FLY_AT_FLY == rAnchor.GetAnchorId()) || + (FLY_AT_PARA == rAnchor.GetAnchorId()))) + { + return &pAPos->nNode.GetNode(); + } + return 0; + } + } + + OSL_ENSURE( !this, "GetAnchor nicht ueberlagert" ); + return 0; +} + +sal_Bool SwBaseLink::IsRecursion( const SwBaseLink* pChkLnk ) const +{ + SwServerObjectRef aRef( (SwServerObject*)GetObj() ); + if( aRef.Is() ) + { + // es ist ein ServerObject, also frage nach allen darin + // befindlichen Links, ob wir darin enthalten sind. Ansonsten + // handelt es sich um eine Rekursion. + return aRef->IsLinkInServer( pChkLnk ); + } + return sal_False; +} + +sal_Bool SwBaseLink::IsInRange( sal_uLong, sal_uLong, xub_StrLen, xub_StrLen ) const +{ + // Grafik oder OLE-Links nicht, + // Felder oder Sections haben eigene Ableitung! + return sal_False; +} + +SwBaseLink::~SwBaseLink() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/swthreadjoiner.cxx b/sw/source/core/docnode/swthreadjoiner.cxx new file mode 100644 index 000000000000..70997287e0ae --- /dev/null +++ b/sw/source/core/docnode/swthreadjoiner.cxx @@ -0,0 +1,64 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <swthreadjoiner.hxx> +#include <finalthreadmanager.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> + +/** Testing + + @author OD +*/ +using namespace ::com::sun::star; + +uno::Reference< util::XJobManager > SwThreadJoiner::mpThreadJoiner; +osl::Mutex* SwThreadJoiner::mpGetJoinerMutex = new osl::Mutex(); + +uno::Reference< util::XJobManager >& SwThreadJoiner::GetThreadJoiner() +{ + osl::MutexGuard aGuard(*mpGetJoinerMutex); + + if ( !mpThreadJoiner.is() ) + { + mpThreadJoiner = + uno::Reference< util::XJobManager >( + ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.util.JobManager")) ), + uno::UNO_QUERY ); + } + + return mpThreadJoiner; +} + +void SwThreadJoiner::ReleaseThreadJoiner() +{ + mpThreadJoiner.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/swthreadmanager.cxx b/sw/source/core/docnode/swthreadmanager.cxx new file mode 100644 index 000000000000..989ee9348961 --- /dev/null +++ b/sw/source/core/docnode/swthreadmanager.cxx @@ -0,0 +1,90 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <swthreadmanager.hxx> +#include <swthreadjoiner.hxx> +#include <observablethread.hxx> +#include <threadmanager.hxx> + +/** class to manage threads in Writer - it conforms the singleton pattern + + #i73788# + + @author OD +*/ +bool SwThreadManager::mbThreadManagerInstantiated = false; + +SwThreadManager::SwThreadManager() + : mpThreadManagerImpl( new ThreadManager( SwThreadJoiner::GetThreadJoiner() ) ) +{ + mpThreadManagerImpl->Init(); + mbThreadManagerInstantiated = true; +} + +SwThreadManager::~SwThreadManager() +{ +} + +struct InitInstance : public rtl::Static<SwThreadManager, InitInstance> {}; + +SwThreadManager& SwThreadManager::GetThreadManager() +{ + return InitInstance::get(); +} + +bool SwThreadManager::ExistsThreadManager() +{ + return mbThreadManagerInstantiated; +} + +oslInterlockedCount SwThreadManager::AddThread( const rtl::Reference< ObservableThread >& rThread ) +{ + return mpThreadManagerImpl->AddThread( rThread ); +} + +void SwThreadManager::RemoveThread( const oslInterlockedCount nThreadID ) +{ + mpThreadManagerImpl->RemoveThread( nThreadID ); +} + +void SwThreadManager::SuspendStartingOfThreads() +{ + mpThreadManagerImpl->SuspendStartingOfThreads(); +} + +void SwThreadManager::ResumeStartingOfThreads() +{ + mpThreadManagerImpl->ResumeStartingOfThreads(); +} + +bool SwThreadManager::StartingOfThreadsSuspended() +{ + return mpThreadManagerImpl->StartingOfThreadsSuspended(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/threadlistener.cxx b/sw/source/core/docnode/threadlistener.cxx new file mode 100644 index 000000000000..c06fa618d2e8 --- /dev/null +++ b/sw/source/core/docnode/threadlistener.cxx @@ -0,0 +1,59 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <threadlistener.hxx> + +/** helper class to observe threads + + #i73788# + + @author OD +*/ +ThreadListener::ThreadListener( IThreadListenerOwner& rThreadListenerOwner ) + : IFinishedThreadListener(), + mrThreadListenerOwner( rThreadListenerOwner ) +{ +} + +ThreadListener::~ThreadListener() +{ +} + +void ThreadListener::ListenToThread( const oslInterlockedCount nThreadID, + ObservableThread& rThread ) +{ + rThread.SetListener( mrThreadListenerOwner.GetThreadListenerWeakRef(), + nThreadID ); +} + +void ThreadListener::NotifyAboutFinishedThread( const oslInterlockedCount nThreadID ) +{ + mrThreadListenerOwner.NotifyAboutFinishedThread( nThreadID ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/docnode/threadmanager.cxx b/sw/source/core/docnode/threadmanager.cxx new file mode 100644 index 000000000000..b7819527470f --- /dev/null +++ b/sw/source/core/docnode/threadmanager.cxx @@ -0,0 +1,260 @@ +/* -*- 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. + * + ************************************************************************/ +#include "precompiled_sw.hxx" +#include <threadmanager.hxx> + +#include <algorithm> + +using namespace ::com::sun::star; + +/** class to manage threads + + #i73788# + + @author OD +*/ +const std::deque< ThreadManager::tThreadData >::size_type ThreadManager::mnStartedSize = 10; + +ThreadManager::ThreadManager( uno::Reference< util::XJobManager >& rThreadJoiner ) + : maMutex(), + mrThreadJoiner( rThreadJoiner ), + mpThreadListener(), + mnThreadIDCounter( 0 ), + maWaitingForStartThreads(), + maStartedThreads(), + maStartNewThreadTimer(), + mbStartingOfThreadsSuspended( false ) +{ +} + +void ThreadManager::Init() +{ + mpThreadListener.reset( new ThreadListener( *this ) ); + + maStartNewThreadTimer.SetTimeout( 2000 ); + maStartNewThreadTimer.SetTimeoutHdl( LINK( this, ThreadManager, TryToStartNewThread ) ); +} + +ThreadManager::~ThreadManager() +{ + maWaitingForStartThreads.clear(); + maStartedThreads.clear(); +} + +boost::weak_ptr< IFinishedThreadListener > ThreadManager::GetThreadListenerWeakRef() +{ + return mpThreadListener; +} + +void ThreadManager::NotifyAboutFinishedThread( const oslInterlockedCount nThreadID ) +{ + RemoveThread( nThreadID, true ); +} + +oslInterlockedCount ThreadManager::AddThread( + const rtl::Reference< ObservableThread >& rThread ) + +{ + osl::MutexGuard aGuard(maMutex); + + // create new thread + tThreadData aThreadData; + oslInterlockedCount nNewThreadID( RetrieveNewThreadID() ); + { + aThreadData.nThreadID = nNewThreadID; + + aThreadData.pThread = rThread; + aThreadData.aJob = new CancellableJob( aThreadData.pThread ); + + aThreadData.pThread->setPriority( osl_Thread_PriorityBelowNormal ); + mpThreadListener->ListenToThread( aThreadData.nThreadID, + *(aThreadData.pThread) ); + } + + // add thread to manager + if ( maStartedThreads.size() < mnStartedSize && + !StartingOfThreadsSuspended() ) + { + // Try to start thread + if ( !StartThread( aThreadData ) ) + { + // No success on starting thread + // If no more started threads exist, but still threads are waiting, + // setup Timer to start thread from waiting ones + if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) + { + maStartNewThreadTimer.Start(); + } + } + } + else + { + // Thread will be started later + maWaitingForStartThreads.push_back( aThreadData ); + } + + return nNewThreadID; +} + +void ThreadManager::RemoveThread( const oslInterlockedCount nThreadID, + const bool bThreadFinished ) +{ + // --> SAFE ---- + osl::MutexGuard aGuard(maMutex); + + std::deque< tThreadData >::iterator aIter = + std::find_if( maStartedThreads.begin(), maStartedThreads.end(), + ThreadPred( nThreadID ) ); + + if ( aIter != maStartedThreads.end() ) + { + tThreadData aTmpThreadData( (*aIter) ); + + maStartedThreads.erase( aIter ); + + if ( bThreadFinished ) + { + // release thread as job from thread joiner instance + ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); + if ( rThreadJoiner.is() ) + { + rThreadJoiner->releaseJob( aTmpThreadData.aJob ); + } + else + { + OSL_FAIL( "<ThreadManager::RemoveThread(..)> - ThreadJoiner already gone!" ); + } + } + + // Try to start thread from waiting ones + TryToStartNewThread( 0 ); + } + else + { + aIter = std::find_if( maWaitingForStartThreads.begin(), + maWaitingForStartThreads.end(), ThreadPred( nThreadID ) ); + + if ( aIter != maWaitingForStartThreads.end() ) + { + maWaitingForStartThreads.erase( aIter ); + } + } + // <-- SAFE ---- +} + +bool ThreadManager::StartWaitingThread() +{ + if ( !maWaitingForStartThreads.empty() ) + { + tThreadData aThreadData( maWaitingForStartThreads.front() ); + maWaitingForStartThreads.pop_front(); + return StartThread( aThreadData ); + } + else + { + return false; + } +} + +bool ThreadManager::StartThread( const tThreadData& rThreadData ) +{ + bool bThreadStarted( false ); + + if ( rThreadData.pThread->create() ) + { + // start of thread successful. + bThreadStarted = true; + + maStartedThreads.push_back( rThreadData ); + + // register thread as job at thread joiner instance + ::com::sun::star::uno::Reference< ::com::sun::star::util::XJobManager > rThreadJoiner( mrThreadJoiner ); + if ( rThreadJoiner.is() ) + { + rThreadJoiner->registerJob( rThreadData.aJob ); + } + else + { + OSL_FAIL( "<ThreadManager::StartThread(..)> - ThreadJoiner already gone!" ); + } + } + else + { + // thread couldn't be started. + maWaitingForStartThreads.push_front( rThreadData ); + } + + return bThreadStarted; +} + +IMPL_LINK( ThreadManager, TryToStartNewThread, Timer *, EMPTYARG ) +{ + osl::MutexGuard aGuard(maMutex); + + if ( !StartingOfThreadsSuspended() ) + { + // Try to start thread from waiting ones + if ( !StartWaitingThread() ) + { + // No success on starting thread + // If no more started threads exist, but still threads are waiting, + // setup Timer to start thread from waiting ones + if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) + { + maStartNewThreadTimer.Start(); + } + } + } + + return sal_True; +} + +void ThreadManager::ResumeStartingOfThreads() +{ + osl::MutexGuard aGuard(maMutex); + + mbStartingOfThreadsSuspended = false; + + while ( maStartedThreads.size() < mnStartedSize && + !maWaitingForStartThreads.empty() ) + { + if ( !StartWaitingThread() ) + { + // No success on starting thread + // If no more started threads exist, but still threads are waiting, + // setup Timer to start thread from waiting ones + if ( maStartedThreads.empty() && !maWaitingForStartThreads.empty() ) + { + maStartNewThreadTimer.Start(); + break; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |