summaryrefslogtreecommitdiff
path: root/sw/source/core/docnode
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/docnode')
-rw-r--r--sw/source/core/docnode/cancellablejob.cxx43
-rw-r--r--sw/source/core/docnode/cancellablejob.hxx56
-rw-r--r--sw/source/core/docnode/finalthreadmanager.cxx505
-rw-r--r--sw/source/core/docnode/ndcopy.cxx1620
-rw-r--r--sw/source/core/docnode/ndindex.cxx166
-rw-r--r--sw/source/core/docnode/ndnotxt.cxx308
-rw-r--r--sw/source/core/docnode/ndnum.cxx148
-rw-r--r--sw/source/core/docnode/ndsect.cxx1479
-rw-r--r--sw/source/core/docnode/ndtbl.cxx4563
-rw-r--r--sw/source/core/docnode/ndtbl1.cxx1598
-rw-r--r--sw/source/core/docnode/node.cxx2028
-rw-r--r--sw/source/core/docnode/node2lay.cxx474
-rw-r--r--sw/source/core/docnode/nodes.cxx2508
-rw-r--r--sw/source/core/docnode/observablethread.cxx100
-rw-r--r--sw/source/core/docnode/pausethreadstarting.cxx58
-rw-r--r--sw/source/core/docnode/retrievedinputstreamdata.cxx169
-rw-r--r--sw/source/core/docnode/retrieveinputstream.cxx87
-rw-r--r--sw/source/core/docnode/retrieveinputstreamconsumer.cxx74
-rw-r--r--sw/source/core/docnode/section.cxx1777
-rw-r--r--sw/source/core/docnode/swbaslnk.cxx502
-rw-r--r--sw/source/core/docnode/swthreadjoiner.cxx64
-rw-r--r--sw/source/core/docnode/swthreadmanager.cxx90
-rw-r--r--sw/source/core/docnode/threadlistener.cxx59
-rw-r--r--sw/source/core/docnode/threadmanager.cxx260
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: */