blob: c942e26d0f02f6ab1f1d84412eca7859de4acbc2 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include <bookmrk.hxx>
#include <IDocumentMarkAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <doc.hxx>
#include <errhdl.hxx>
#include <ndtxt.hxx>
#include <pam.hxx>
#include <swserv.hxx>
#include <sfx2/linkmgr.hxx>
#include <swtypes.hxx>
#include <UndoBookmark.hxx>
#include <unobookmark.hxx>
#include <rtl/random.h>
#include <xmloff/odffields.hxx>
SV_IMPL_REF( SwServerObject )
using namespace ::sw::mark;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
namespace
{
static void lcl_FixPosition(SwPosition& rPos)
{
// make sure the position has 1) the proper node, and 2) a proper index
SwTxtNode* pTxtNode = rPos.nNode.GetNode().GetTxtNode();
if(pTxtNode == NULL && rPos.nContent.GetIndex() > 0)
{
OSL_TRACE(
"bookmrk.cxx::lcl_FixPosition"
" - illegal position: %d without proper TxtNode", rPos.nContent.GetIndex());
rPos.nContent.Assign(NULL, 0);
}
else if(pTxtNode != NULL && rPos.nContent.GetIndex() > pTxtNode->Len())
{
OSL_TRACE(
"bookmrk.cxx::lcl_FixPosition"
" - illegal position: %d is beyond %d", rPos.nContent.GetIndex(), pTxtNode->Len());
rPos.nContent.Assign(pTxtNode, pTxtNode->Len());
}
};
static void lcl_AssureFieldMarksSet(Fieldmark* const pField,
SwDoc* const io_pDoc,
const sal_Unicode aStartMark,
const sal_Unicode aEndMark)
{
io_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_UI_REPLACE, NULL);
SwPosition rStart = pField->GetMarkStart();
SwTxtNode const*const pStartTxtNode = rStart.nNode.GetNode().GetTxtNode();
const sal_Unicode ch_start=pStartTxtNode->GetTxt().GetChar(rStart.nContent.GetIndex());
if(ch_start != aStartMark)
{
SwPaM aStartPaM(rStart);
io_pDoc->InsertString(aStartPaM, aStartMark);
rStart.nContent--;
pField->SetMarkStartPos( rStart );
}
const SwPosition& rEnd = pField->GetMarkEnd();
SwTxtNode const*const pEndTxtNode = rEnd.nNode.GetNode().GetTxtNode();
const sal_Unicode ch_end=pEndTxtNode->GetTxt().GetChar(rEnd.nContent.GetIndex()-1);
if ( aEndMark && ( ch_end != aEndMark ) && ( rStart != rEnd ) )
{
SwPaM aEndPaM(rEnd);
io_pDoc->InsertString(aEndPaM, aEndMark);
}
io_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_UI_REPLACE, NULL);
};
static void lcl_RemoveFieldMarks(Fieldmark* const pField,
SwDoc* const io_pDoc,
const sal_Unicode aStartMark,
const sal_Unicode aEndMark)
{
io_pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_UI_REPLACE, NULL);
const SwPosition& rStart = pField->GetMarkStart();
SwTxtNode const*const pStartTxtNode = rStart.nNode.GetNode().GetTxtNode();
const sal_Unicode ch_start=pStartTxtNode->GetTxt().GetChar(rStart.nContent.GetIndex());
if( ch_start == aStartMark )
{
SwPaM aStart(rStart, rStart);
aStart.End()->nContent++;
io_pDoc->DeleteRange(aStart);
}
const SwPosition& rEnd = pField->GetMarkEnd();
SwTxtNode const*const pEndTxtNode = rEnd.nNode.GetNode().GetTxtNode();
const xub_StrLen nEndPos = ( rEnd == rStart || rEnd.nContent.GetIndex() == 0 )
? rEnd.nContent.GetIndex()
: rEnd.nContent.GetIndex() - 1;
const sal_Unicode ch_end=pEndTxtNode->GetTxt().GetChar( nEndPos );
if ( ch_end == aEndMark )
{
SwPaM aEnd(rEnd, rEnd);
aEnd.Start()->nContent--;
io_pDoc->DeleteRange(aEnd);
}
io_pDoc->GetIDocumentUndoRedo().EndUndo(UNDO_UI_REPLACE, NULL);
};
}
namespace sw { namespace mark
{
MarkBase::MarkBase(const SwPaM& aPaM,
const ::rtl::OUString& rName)
: SwModify(0)
, m_pPos1(new SwPosition(*(aPaM.GetPoint())))
, m_aName(rName)
{
lcl_FixPosition(*m_pPos1);
if (aPaM.HasMark() && (*aPaM.GetMark() != *aPaM.GetPoint()))
{
MarkBase::SetOtherMarkPos(*(aPaM.GetMark()));
lcl_FixPosition(*m_pPos2);
}
}
bool MarkBase::IsCoveringPosition(const SwPosition& rPos) const
{
return GetMarkStart() <= rPos && rPos <= GetMarkEnd();
}
void MarkBase::SetMarkPos(const SwPosition& rNewPos)
{
::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos1);
//lcl_FixPosition(*m_pPos1);
}
void MarkBase::SetOtherMarkPos(const SwPosition& rNewPos)
{
::boost::scoped_ptr<SwPosition>(new SwPosition(rNewPos)).swap(m_pPos2);
//lcl_FixPosition(*m_pPos2);
}
rtl::OUString MarkBase::ToString( ) const
{
rtl::OUStringBuffer buf;
buf.appendAscii( "Mark: ( Name, [ Node1, Index1 ] ): ( " );
buf.append( m_aName ).appendAscii( ", [ " );
buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
buf.append( sal_Int32( GetMarkPos().nContent.GetIndex( ) ) ).appendAscii( " ] )" );
return buf.makeStringAndClear( );
}
MarkBase::~MarkBase()
{ }
::rtl::OUString MarkBase::GenerateNewName(const ::rtl::OUString& rPrefix)
{
static rtlRandomPool aPool = rtl_random_createPool();
static ::rtl::OUString sUniquePostfix;
static sal_Int32 nCount = SAL_MAX_INT32;
::rtl::OUStringBuffer aResult(rPrefix);
if(nCount == SAL_MAX_INT32)
{
sal_Int32 nRandom;
rtl_random_getBytes(aPool, &nRandom, sizeof(nRandom));
sUniquePostfix = ::rtl::OUStringBuffer(13).appendAscii("_").append(static_cast<sal_Int32>(abs(nRandom))).makeStringAndClear();
nCount = 0;
}
// putting the counter in front of the random parts will speed up string comparisons
return aResult.append(nCount++).append(sUniquePostfix).makeStringAndClear();
}
void MarkBase::Modify( const SfxPoolItem *pOld, const SfxPoolItem *pNew )
{
NotifyClients(pOld, pNew);
if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
{ // invalidate cached uno object
SetXBookmark(uno::Reference<text::XTextContent>(0));
}
}
NavigatorReminder::NavigatorReminder(const SwPaM& rPaM)
: MarkBase(rPaM, our_sNamePrefix)
{ }
const ::rtl::OUString NavigatorReminder::our_sNamePrefix = ::rtl::OUString::createFromAscii("__NavigatorReminder__");
UnoMark::UnoMark(const SwPaM& aPaM)
: MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix))
{ }
const ::rtl::OUString UnoMark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__UnoMark__");
DdeBookmark::DdeBookmark(const SwPaM& aPaM)
: MarkBase(aPaM, MarkBase::GenerateNewName(our_sNamePrefix))
, m_aRefObj(NULL)
, mbInDestruction( false )
{ }
void DdeBookmark::SetRefObject(SwServerObject* pObj)
{
m_aRefObj = pObj;
}
const ::rtl::OUString DdeBookmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__DdeLink__");
void DdeBookmark::DeregisterFromDoc(SwDoc* const pDoc)
{
if(m_aRefObj.Is())
pDoc->GetLinkManager().RemoveServer(m_aRefObj);
}
DdeBookmark::~DdeBookmark()
{
mbInDestruction = true;
if( m_aRefObj.Is() )
{
if(m_aRefObj->HasDataLinks())
{
::sfx2::SvLinkSource* p = &m_aRefObj;
p->SendDataChanged();
}
m_aRefObj->SetNoServer();
}
}
Bookmark::Bookmark(const SwPaM& aPaM,
const KeyCode& rCode,
const ::rtl::OUString& rName,
const ::rtl::OUString& rShortName)
: DdeBookmark(aPaM)
, ::sfx2::Metadatable()
, m_aCode(rCode)
, m_sShortName(rShortName)
{
m_aName = rName;
}
void Bookmark::InitDoc(SwDoc* const io_pDoc)
{
if (io_pDoc->GetIDocumentUndoRedo().DoesUndo())
{
io_pDoc->GetIDocumentUndoRedo().AppendUndo(
new SwUndoInsBookmark(*this));
}
io_pDoc->SetModified();
}
// ::sfx2::Metadatable
::sfx2::IXmlIdRegistry& Bookmark::GetRegistry()
{
SwDoc *const pDoc( GetMarkPos().GetDoc() );
OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
return pDoc->GetXmlIdRegistry();
}
bool Bookmark::IsInClipboard() const
{
SwDoc *const pDoc( GetMarkPos().GetDoc() );
OSL_ENSURE(pDoc, "Bookmark::IsInClipboard: no doc?");
return pDoc->IsClipBoard();
}
bool Bookmark::IsInUndo() const
{
return false;
}
bool Bookmark::IsInContent() const
{
SwDoc *const pDoc( GetMarkPos().GetDoc() );
OSL_ENSURE(pDoc, "Bookmark::IsInContent: no doc?");
return !pDoc->IsInHeaderFooter( SwNodeIndex(GetMarkPos().nNode) );
}
uno::Reference< rdf::XMetadatable > Bookmark::MakeUnoObject()
{
// create new SwXBookmark
SwDoc *const pDoc( GetMarkPos().GetDoc() );
OSL_ENSURE(pDoc, "Bookmark::MakeUnoObject: no doc?");
const uno::Reference< rdf::XMetadatable> xMeta(
SwXBookmark::CreateXBookmark(*pDoc, *this), uno::UNO_QUERY);
return xMeta;
}
Fieldmark::Fieldmark(const SwPaM& rPaM)
: MarkBase(rPaM, MarkBase::GenerateNewName(our_sNamePrefix))
{
if(!IsExpanded())
SetOtherMarkPos(GetMarkPos());
}
void Fieldmark::SetMarkStartPos( const SwPosition& rNewStartPos )
{
if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
return SetMarkPos( rNewStartPos );
else
return SetOtherMarkPos( rNewStartPos );
}
void Fieldmark::SetMarkEndPos( const SwPosition& rNewEndPos )
{
if ( GetMarkPos( ) <= GetOtherMarkPos( ) )
return SetOtherMarkPos( rNewEndPos );
else
return SetMarkPos( rNewEndPos );
}
rtl::OUString Fieldmark::ToString( ) const
{
rtl::OUStringBuffer buf;
buf.appendAscii( "Fieldmark: ( Name, Type, [ Nd1, Id1 ], [ Nd2, Id2 ] ): ( " );
buf.append( m_aName ).appendAscii( ", " );
buf.append( m_aFieldname ).appendAscii( ", [ " );
buf.append( sal_Int32( GetMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
buf.append( sal_Int32( GetMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ], [" );
buf.append( sal_Int32( GetOtherMarkPos().nNode.GetIndex( ) ) ).appendAscii( ", " );
buf.append( sal_Int32( GetOtherMarkPos( ).nContent.GetIndex( ) ) ).appendAscii( " ] ) " );
return buf.makeStringAndClear( );
}
void Fieldmark::Invalidate( )
{
// @TODO: Does exist a better solution to trigger a format of the
// fieldmark portion? If yes, please use it.
SwPaM aPaM( this->GetMarkPos(), this->GetOtherMarkPos() );
aPaM.InvalidatePaM();
}
const ::rtl::OUString Fieldmark::our_sNamePrefix = ::rtl::OUString::createFromAscii("__Fieldmark__");
TextFieldmark::TextFieldmark(const SwPaM& rPaM)
: Fieldmark(rPaM)
{ }
void TextFieldmark::InitDoc(SwDoc* const io_pDoc)
{
lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
}
void TextFieldmark::ReleaseDoc(SwDoc* const pDoc)
{
lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND);
}
CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM)
: Fieldmark(rPaM)
{ }
void CheckboxFieldmark::InitDoc(SwDoc* const io_pDoc)
{
lcl_AssureFieldMarksSet(this, io_pDoc, CH_TXT_ATR_FORMELEMENT, CH_TXT_ATR_FIELDEND);
// For some reason the end mark is moved from 1 by the Insert: we don't
// want this for checkboxes
SwPosition aNewEndPos = this->GetMarkEnd();
aNewEndPos.nContent--;
SetMarkEndPos( aNewEndPos );
}
void CheckboxFieldmark::SetChecked(bool checked)
{
(*GetParameters())[::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT)] = makeAny(checked);
}
bool CheckboxFieldmark::IsChecked() const
{
bool bResult = false;
parameter_map_t::const_iterator pResult = GetParameters()->find(::rtl::OUString::createFromAscii(ODF_FORMCHECKBOX_RESULT));
if(pResult != GetParameters()->end())
pResult->second >>= bResult;
return bResult;
}
}}