summaryrefslogtreecommitdiff
path: root/sw/source/core/ole/ndole.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/ole/ndole.cxx')
-rw-r--r--sw/source/core/ole/ndole.cxx644
1 files changed, 644 insertions, 0 deletions
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
new file mode 100644
index 000000000000..5d168aaf724d
--- /dev/null
+++ b/sw/source/core/ole/ndole.cxx
@@ -0,0 +1,644 @@
+/*************************************************************************
+ *
+ * $RCSfile: ndole.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-19 00:08:23 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#ifdef PRECOMPILED
+#include "core_pch.hxx"
+#endif
+
+#pragma hdrstop
+
+#ifndef _HINTIDS_HXX
+#include <hintids.hxx>
+#endif
+
+#ifndef _URLOBJ_HXX //autogen
+#include <tools/urlobj.hxx>
+#endif
+#ifndef _SFXDOCFILE_HXX //autogen
+#include <sfx2/docfile.hxx>
+#endif
+#ifndef _SFXAPP_HXX //autogen
+#include <sfx2/app.hxx>
+#endif
+#ifndef _SFXINIMGR_HXX //autogen
+#include <svtools/iniman.hxx>
+#endif
+#ifndef _SVXLINKMGR_HXX
+#include <svx/linkmgr.hxx>
+#endif
+#ifndef _FMTANCHR_HXX
+#include <fmtanchr.hxx>
+#endif
+#ifndef _FRMFMT_HXX //autogen
+#include <frmfmt.hxx>
+#endif
+
+#ifndef _DOC_HXX
+#include <doc.hxx>
+#endif
+#ifndef _PAM_HXX
+#include <pam.hxx>
+#endif
+#ifndef _SECTION_HXX
+#include <section.hxx>
+#endif
+#ifndef _CNTFRM_HXX
+#include <cntfrm.hxx>
+#endif
+#ifndef _FRMATR_HXX
+#include <frmatr.hxx>
+#endif
+#ifndef _DOCSH_HXX
+#include <docsh.hxx>
+#endif
+#ifndef _NDOLE_HXX
+#include <ndole.hxx>
+#endif
+#ifndef _SW3IO_HXX
+#include <sw3io.hxx>
+#endif
+
+
+class SwOLELRUCache : private SvPtrarr
+{
+public:
+ SwOLELRUCache( USHORT nInitSize )
+ : SvPtrarr( nInitSize, 1 )
+ {
+ }
+
+ SvPtrarr::Count;
+
+ void Insert( SwOLEObj& rObj );
+ void Remove( SwOLEObj& rObj );
+
+ void RemovePtr( SwOLEObj* pObj )
+ {
+ USHORT nPos = SvPtrarr::GetPos( pObj );
+ if( USHRT_MAX != nPos )
+ SvPtrarr::Remove( nPos );
+ }
+};
+
+SwOLELRUCache* SwOLEObj::pOLELRU_Cache = 0;
+static USHORT nLRU_InitSize = 0;
+
+// --------------------
+// SwOLENode
+// --------------------
+
+SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
+ SvInPlaceObject *pObj,
+ SwGrfFmtColl *pGrfColl,
+ SwAttrSet* pAutoAttr ) :
+ SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ),
+ aOLEObj( pObj ),
+ bOLESizeInvalid( FALSE )
+{
+ aOLEObj.SetNode( this );
+}
+
+SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
+ const String &rString,
+ SwGrfFmtColl *pGrfColl,
+ SwAttrSet* pAutoAttr ) :
+ SwNoTxtNode( rWhere, ND_OLENODE, pGrfColl, pAutoAttr ),
+ aOLEObj( rString ),
+ bOLESizeInvalid( FALSE )
+{
+ aOLEObj.SetNode( this );
+}
+
+SwCntntNode *SwOLENode::SplitNode( const SwPosition & )
+{
+ // OLE-Objecte vervielfaeltigen ??
+ ASSERT( FALSE, "OleNode: can't split." );
+ return this;
+}
+
+// Laden eines in den Undo-Bereich verschobenen OLE-Objekts
+
+BOOL SwOLENode::RestorePersistentData()
+{
+ if( aOLEObj.IsOLELink() )
+ {
+ aOLEObj.GetLink()->SetVisible( GetDoc()->IsVisibleLinks() );
+ GetDoc()->GetLinkManager().InsertSoLink( *aOLEObj.GetLink() );
+ }
+ else if( aOLEObj.pOLERef && aOLEObj.pOLERef->Is() )
+ {
+ SvPersist* p = GetDoc()->GetPersist();
+ if( p ) // muss da sein
+ {
+ SvInfoObjectRef aRef( p->Find( aOLEObj.aName ) );
+ if( aRef.Is() )
+ aRef->SetDeleted( FALSE );
+ }
+ }
+
+// muss das sein????
+// if( pOLELRU_Cache )
+// pOLELRU_Cache->RemovePtr( &aOLEObj );
+ return TRUE;
+}
+
+// Sichern eines in den Undo-Bereich zu verschiebenden OLE-Objekts
+
+BOOL SwOLENode::SavePersistentData()
+{
+ if( aOLEObj.IsOLELink() )
+ {
+ GetDoc()->GetLinkManager().Remove( *aOLEObj.GetLink() );
+ }
+ else if( aOLEObj.pOLERef && aOLEObj.pOLERef->Is() )
+ {
+ SvPersist* p = GetDoc()->GetPersist();
+ if( p ) // muss da sein
+ {
+ SvInfoObjectRef aRef( p->Find( aOLEObj.aName ) );
+ if( aRef.Is() )
+ aRef->SetDeleted( TRUE );
+ }
+ (*aOLEObj.pOLERef)->DoClose();
+ }
+
+ if( SwOLEObj::pOLELRU_Cache )
+ SwOLEObj::pOLELRU_Cache->RemovePtr( &aOLEObj );
+
+ return TRUE;
+}
+
+
+SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere,
+ SvInPlaceObject *pObj,
+ SwGrfFmtColl* pGrfColl,
+ SwAttrSet* pAutoAttr )
+{
+ ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." );
+
+ SwOLENode *pNode =
+ new SwOLENode( rWhere, pObj, pGrfColl, pAutoAttr );
+
+#if 0
+JP 02.10.97 - OLE Objecte stehen immer alleine im Rahmen, also hat es
+ keinen Sinn, nach einem vorherigen/nachfolgenden
+ ContentNode zu suchen!
+
+ SwCntntNode *pCntntNd;
+ SwIndex aIdx( rWhere, -1 );
+ if ( (pCntntNd=(*this)[ rWhere ]->GetCntntNode()) != 0 )
+ pCntntNd->MakeFrms( rWhere, aIdx );
+ else
+ {
+ aIdx--;
+ if ( (pCntntNd=(*this)[aIdx]->GetCntntNode()) != 0 )
+ {
+ SwIndex aTmp( aIdx );
+ aIdx++;
+ pCntntNd->MakeFrms( aTmp, aIdx );
+ }
+ }
+#endif
+ return pNode;
+}
+
+
+SwOLENode * SwNodes::MakeOLENode( const SwNodeIndex & rWhere,
+ String &rName,
+ SwGrfFmtColl* pGrfColl,
+ SwAttrSet* pAutoAttr )
+{
+ ASSERT( pGrfColl,"SwNodes::MakeOLENode: Formatpointer ist 0." );
+
+ SwOLENode *pNode =
+ new SwOLENode( rWhere, rName, pGrfColl, pAutoAttr );
+
+#if 0
+JP 02.10.97 - OLE Objecte stehen immer alleine im Rahmen, also hat es
+ keinen Sinn, nach einem vorherigen/nachfolgenden
+ ContentNode zu suchen!
+ SwCntntNode *pCntntNd;
+ SwIndex aIdx( rWhere, -1 );
+ if ( (pCntntNd=(*this)[ rWhere ]->GetCntntNode()) != 0 )
+ pCntntNd->MakeFrms( rWhere, aIdx );
+ else
+ {
+ aIdx--;
+ if ( (pCntntNd=(*this)[aIdx]->GetCntntNode()) != 0 )
+ {
+ SwIndex aTmp( aIdx );
+ aIdx++;
+ pCntntNd->MakeFrms( aTmp, aIdx );
+ }
+ }
+#endif
+ return pNode;
+}
+
+
+Size SwOLENode::GetTwipSize() const
+{
+ SvInPlaceObjectRef xRef( ((SwOLENode*)this)->aOLEObj.GetOleRef() );
+ Size aSz( xRef->GetVisArea().GetSize() );
+ const MapMode aDest( MAP_TWIP );
+ const MapMode aSrc ( xRef->GetMapUnit() );
+ return OutputDevice::LogicToLogic( aSz, aSrc, aDest );
+}
+
+
+SwCntntNode* SwOLENode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
+{
+ // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese
+ SvPersist* p = pDoc->GetPersist();
+ if( !p )
+ {
+ ASSERT( pDoc->GetRefForDocShell(),
+ "wo ist die Ref-Klasse fuer die DocShell?")
+ p = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL );
+ *pDoc->GetRefForDocShell() = p;
+ p->DoInitNew( NULL );
+ }
+
+ // Wir hauen das Ding auf SvPersist-Ebene rein
+ String aNewName( Sw3Io::UniqueName( p->GetStorage(), "Obj" ) );
+ SvPersist* pSrc = GetDoc()->GetPersist();
+ SvInfoObjectRef refObj = pSrc->Find( aOLEObj.aName );
+ if( refObj.Is() )
+ p->Copy( aNewName, aNewName, refObj, pSrc );
+ SwOLENode* pOLENd = pDoc->GetNodes().MakeOLENode( rIdx, aNewName,
+ (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl(),
+ (SwAttrSet*)GetpSwAttrSet() );
+
+ if( aOLEObj.refLink.Is() ) // sollte es ein OLE-Link sein?
+ {
+ pOLENd->aOLEObj.refLink = new SwOLELink( *pOLENd,
+ pOLENd->aOLEObj.GetOleRef() );
+ // bei UNDO nie in den LinkManager uebernehmen
+ if( pOLENd->GetNodes().IsDocNodes() )
+ {
+ pOLENd->aOLEObj.GetLink()->SetVisible( pDoc->IsVisibleLinks() );
+ pDoc->GetLinkManager().InsertSoLink( *pOLENd->aOLEObj.refLink );
+// JP 19.01.96: warum Updaten??
+// pOLENd->aOLEObj.refLink->Update();
+ }
+ }
+ pOLENd->SetChartTblName( GetChartTblName() );
+ pOLENd->SetAlternateText( GetAlternateText() );
+ pOLENd->SetContour( HasContour() );
+
+ pOLENd->SetOLESizeInvalid( TRUE );
+ pDoc->SetOLEPrtNotifyPending();
+
+ return pOLENd;
+}
+
+
+BOOL SwOLENode::IsInGlobalDocSection() const
+{
+ // suche den "Body Anchor"
+ ULONG nEndExtraIdx = GetNodes().GetEndOfExtras().GetIndex();
+ const SwNode* pAnchorNd = this;
+ do {
+ SwFrmFmt* pFlyFmt = pAnchorNd->GetFlyFmt();
+ if( !pFlyFmt )
+ return FALSE;
+
+ const SwFmtAnchor& rAnchor = pFlyFmt->GetAnchor();
+ if( !rAnchor.GetCntntAnchor() )
+ return FALSE;
+
+ pAnchorNd = &rAnchor.GetCntntAnchor()->nNode.GetNode();
+ } while( pAnchorNd->GetIndex() < nEndExtraIdx );
+
+ const SwSectionNode* pSectNd = pAnchorNd->FindSectionNode();
+ if( !pSectNd )
+ return FALSE;
+
+ while( pSectNd )
+ {
+ pAnchorNd = pSectNd;
+ pSectNd = pAnchorNd->FindStartNode()->FindSectionNode();
+ }
+
+ // in pAnchorNd steht der zuletzt gefundene Section Node. Der muss
+ // jetzt die Bedingung fuers GlobalDoc erfuellen.
+ pSectNd = (SwSectionNode*)pAnchorNd;
+ return FILE_LINK_SECTION == pSectNd->GetSection().GetType() &&
+ pSectNd->GetIndex() > nEndExtraIdx;
+}
+
+
+BOOL SwOLENode::IsOLEObjectDeleted() const
+{
+ BOOL bRet = FALSE;
+ if( !aOLEObj.IsOLELink() && aOLEObj.pOLERef && aOLEObj.pOLERef->Is() )
+ {
+ SvPersist* p = GetDoc()->GetPersist();
+ if( p ) // muss da sein
+ {
+ SvInfoObjectRef aRef( p->Find( aOLEObj.aName ) );
+ if( aRef.Is() )
+ bRet = aRef->IsDeleted();
+ }
+ }
+ return bRet;
+}
+
+
+SwOLEObj::SwOLEObj( SvInPlaceObject *pObj ) :
+ pOLERef( new SvInPlaceObjectRef( pObj ) ),
+ pOLENd( 0 )
+{
+}
+
+
+SwOLEObj::SwOLEObj( const String &rString ) :
+ pOLERef( 0 ),
+ pOLENd( 0 ),
+ aName( rString )
+{
+}
+
+
+SwOLEObj::~SwOLEObj()
+{
+ if( pOLERef && pOLERef->Is() )
+ //#41499# Kein DoClose(). Beim Beenden ruft der Sfx ein DoClose auf
+ //die offenen Objekte. Dadurch wird ggf. eine temp. OLE-Grafik wieder
+ //in eine Grafik gewandelt. Der OLE-Node wird zerstoert. Das DoClose
+ //wueder in das leere laufen, weil das Objekt bereits im DoClose steht.
+ //Durch das remove unten waere das DoClose aber nicht vollstaendig.
+ (*pOLERef)->GetProtocol().Reset();
+ delete pOLERef;
+ // Object aus dem Storage removen!!
+ if( pOLENd && !pOLENd->GetDoc()->IsInDtor() ) //NIcht notwendig im DTor (MM)
+ {
+ SvPersist* p = pOLENd->GetDoc()->GetPersist();
+ if( p ) // muss er existieren ?
+ p->Remove( aName );
+ }
+
+ if( pOLELRU_Cache )
+ {
+ pOLELRU_Cache->RemovePtr( this );
+ if( !pOLELRU_Cache->Count() )
+ // der letzte macht die Tuer zu
+ delete pOLELRU_Cache, pOLELRU_Cache = 0;
+ }
+}
+
+
+void SwOLEObj::SetNode( SwOLENode* pNode )
+{
+ pOLENd = pNode;
+ if ( pOLERef && !aName.Len() )
+ {
+ SwDoc* pDoc = pNode->GetDoc();
+
+ // Falls bereits eine SvPersist-Instanz existiert, nehmen wir diese
+ SvPersist* p = pDoc->GetPersist();
+ if( !p )
+ {
+ ASSERT( !this, "warum wird hier eine DocShell angelegt?" );
+ p = new SwDocShell( pDoc, SFX_CREATE_MODE_INTERNAL );
+ p->DoInitNew( NULL );
+ }
+ // Wir hauen das Ding auf SvPersist-Ebene rein
+ aName = Sw3Io::UniqueName( p->GetStorage(), "Obj" );
+ SvInfoObjectRef refObj = new SvEmbeddedInfoObject( *pOLERef, aName );
+
+//JP 05.02.96: solange das Move nicht richtig funktioniert muss der
+// (Object-)Name gesetzt werden. Sonst wird Object nicht
+// wiedergefunden
+//(*pOLERef)->SetName( new SvLinkName( aName ));
+
+ if ( !p->Move( refObj, aName ) ) // Eigentuemer Uebergang!
+ refObj.Clear();
+ else if( (*pOLERef)->IsLink() )
+ {
+ refLink = new SwOLELink( *pNode, &(*pOLERef) );
+ if( pNode->GetNodes().IsDocNodes() )
+ {
+ refLink->SetVisible( pDoc->IsVisibleLinks() );
+ pDoc->GetLinkManager().InsertSoLink( *refLink );
+ refLink->Update();
+ }
+ }
+ ASSERT( refObj.Is(), "InsertObject failed" );
+ }
+}
+
+BOOL SwOLEObj::IsOleRef() const
+{
+ return pOLERef && pOLERef->Is();
+}
+
+SvInPlaceObjectRef SwOLEObj::GetOleRef()
+{
+ if( !pOLERef || !pOLERef->Is() )
+ {
+ SvPersist* p = pOLENd->GetDoc()->GetPersist();
+ ASSERT( p, "kein SvPersist vorhanden" );
+
+ // MIB 18.5.97: DIe Base-URL wird jetzt gesetzt, damit Plugins
+ // nach dem Laden und vor dem Aktivieren des Frames korrekt
+ // geladen werden koennen
+ String sBaseURL( INetURLObject::GetBaseURL() );
+ const SwDocShell *pDocSh = pOLENd->GetDoc()->GetDocShell();
+ const SfxMedium *pMedium;
+ if( pDocSh && 0 != (pMedium = pDocSh->GetMedium()) &&
+ pMedium->GetName() != sBaseURL )
+ INetURLObject::SetBaseURL( pMedium->GetName() );
+
+ SvPersistRef xObj = p->GetObject( aName );
+ ASSERT( !pOLERef || !pOLERef->Is(),
+ "rekursiver Aufruf von GetOleRef() ist nicht erlaubt" )
+
+ INetURLObject::SetBaseURL( sBaseURL );
+
+ if ( !xObj.Is() )
+ {
+ //Das Teil konnte nicht geladen werden (wahrsch. Kaputt).
+ Rectangle aArea;
+ SwFrm *pFrm = pOLENd->GetFrm();
+ if ( pFrm )
+ {
+ Size aSz( pFrm->Frm().SSize() );
+ const MapMode aSrc ( MAP_TWIP );
+ const MapMode aDest( MAP_100TH_MM );
+ aSz = OutputDevice::LogicToLogic( aSz, aSrc, aDest );
+ aArea.SetSize( aSz );
+ }
+ else
+ aArea.SetSize( Size( 5000, 5000 ) );
+ xObj = new SvDeathObject( aArea );
+ }
+
+ if( pOLERef )
+ *pOLERef = &xObj;
+ else
+ pOLERef = new SvInPlaceObjectRef( xObj );
+ }
+
+ if( !pOLELRU_Cache )
+ {
+ // Init Size besorgen
+ if( !nLRU_InitSize )
+ {
+ nLRU_InitSize = SFX_APP()->GetIniManager()->Get(
+ SFX_GROUP_WORKINGSET_IMPL, String::CreateFromAscii(
+ RTL_CONSTASCII_STRINGPARAM( "MaxOLEObjectsInSWMemory" )))
+ .ToInt32();
+
+ if( 20 > nLRU_InitSize )
+ nLRU_InitSize = 20;
+ }
+ pOLELRU_Cache = new SwOLELRUCache( nLRU_InitSize );
+ }
+ pOLELRU_Cache->Insert( *this );
+
+ return *pOLERef;
+}
+
+
+void SwOLEObj::ReleaseLink()
+{
+ if( refLink.Is() )
+ {
+ ((SwOLENode*)pOLENd)->GetDoc()->GetLinkManager().Remove( *refLink );
+ refLink.Clear();
+ }
+}
+
+void SwOLEObj::Unload()
+{
+ if( pOLERef && pOLELRU_Cache )
+ pOLELRU_Cache->Remove( *this );
+}
+
+BOOL SwOLEObj::RemovedFromLRU()
+{
+ BOOL bRet = TRUE;
+ //Nicht notwendig im Doc DTor (MM)
+ ASSERT( pOLERef && pOLERef->Is() && 1 < (*pOLERef)->GetRefCount(),
+ "Falscher RefCount fuers Unload" );
+ const SwDoc* pDoc;
+ if( pOLERef && pOLERef->Is() && pOLENd &&
+ !( pDoc = pOLENd->GetDoc())->IsInDtor() &&
+ SVOBJ_MISCSTATUS_ALWAYSACTIVATE != (*pOLERef)->GetMiscStatus() &&
+ 1 < (*pOLERef)->GetRefCount() &&
+ !(*pOLERef)->GetProtocol().IsInPlaceActive() )
+ {
+ SvPersist* p = pDoc->GetPersist();
+ if( p )
+ {
+ if( pDoc->IsPurgeOLE() )
+ {
+ SvPersist* pO = *pOLERef;
+
+ if( pO->IsModified() && !pO->IsHandsOff() )
+ {
+ pO->DoSave();
+ pO->DoSaveCompleted();
+ }
+
+ pOLERef->Clear();
+ if( !p->Unload( pO ) )
+ *pOLERef = pO;
+ }
+ else
+ bRet = FALSE;
+ }
+ }
+ return bRet;
+}
+
+
+void SwOLELRUCache::Insert( SwOLEObj& rObj )
+{
+ SwOLEObj* pObj = &rObj;
+ USHORT nPos = SvPtrarr::GetPos( pObj );
+ if( nPos ) // der auf der 0. Pos muss nicht verschoben werden!
+ {
+ if( USHRT_MAX != nPos )
+ SvPtrarr::Remove( nPos );
+
+ SvPtrarr::Insert( pObj, 0 );
+
+ nPos = SvPtrarr::Count();
+ while( nPos > nLRU_InitSize )
+ {
+ pObj = (SwOLEObj*) SvPtrarr::GetObject( --nPos );
+ if( pObj->RemovedFromLRU() )
+ SvPtrarr::Remove( nPos );
+ }
+ }
+}
+
+void SwOLELRUCache::Remove( SwOLEObj& rObj )
+{
+ USHORT nPos = SvPtrarr::GetPos( &rObj );
+ if( USHRT_MAX != nPos && rObj.RemovedFromLRU() )
+ SvPtrarr::Remove( nPos );
+}
+
+
+