/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
for (sal_Int32 nStyle = 0; nStyle < aCharStyles.getLength(); nStyle++)
{
uno::Any aStyle;
rPam.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
aStyle <<= aCharStyles.getConstArray()[nStyle]; // create a local set and apply each format directly
SfxItemSetFixed<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT> aSet(rPam.GetDoc().GetAttrPool());
SwUnoCursorHelper::SetCharStyle(rPam.GetDoc(), aStyle, aSet); // the first style should replace the current attributes, // all other have to be added
SwUnoCursorHelper::SetCursorAttr(rPam, aSet, nStyle
? SetAttrMode::DONTREPLACE
: SetAttrMode::DEFAULT);
rPam.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START, nullptr);
} returntrue;
}
staticvoid
lcl_setDropcapCharStyle(SwPaM const & rPam, SfxItemSet & rItemSet,
uno::Any const& rValue)
{
OUString uStyle; if (!(rValue >>= uStyle))
{ throw lang::IllegalArgumentException();
}
UIName sStyle;
SwStyleNameMapper::FillUIName(ProgName(uStyle), sStyle,
SwGetPoolIdFromName::ChrFmt);
SwDoc& rDoc = rPam.GetDoc(); //default character style must not be set as default format
SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
rDoc.GetDocShell()
->GetStyleSheetPool()->Find(sStyle.toString(), SfxStyleFamily::Char)); if (!pStyle || pStyle->GetCharFormat() == rDoc.GetDfltCharFormat())
{ throw lang::IllegalArgumentException();
}
std::unique_ptr<SwFormatDrop> pDrop; if (const SwFormatDrop* pItem = rItemSet.GetItemIfSet(RES_PARATR_DROP))
{
pDrop.reset(new SwFormatDrop(*pItem));
} if (!pDrop)
{
pDrop.reset(new SwFormatDrop);
} const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*pStyle));
pDrop->SetCharFormat(xStyle->GetCharFormat());
rItemSet.Put(std::move(pDrop));
}
IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); // Add it to the autostyle pool, needed by the ODT export.
pAutoStyle = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR);
} elseif (OUString styleName; rValue >>= styleName)
{
IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess();
pAutoStyle = rStyleAccess.getByName(styleName, IStyleAccess::AUTO_STYLE_CHAR);
} if (pAutoStyle)
{
SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT); // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add()
item.SetStyleHandle(pAutoStyle);
pTextNd->SetAttr(item);
}
} //PROPERTY_MAYBEVOID!
} break; case FN_NUMBER_NEWSTART:
{ bool bVal = false; if (!(rValue >>= bVal))
{ throw lang::IllegalArgumentException();
}
rPam.GetDoc().SetNumRuleStart(*rPam.GetPoint(), bVal);
} break; case FN_UNO_NUM_RULES:
SwUnoCursorHelper::setNumberingProperty(rValue, rPam); break; case RES_PARATR_DROP:
{ if (MID_DROPCAP_CHAR_STYLE_NAME == rEntry.nMemberId)
{
lcl_setDropcapCharStyle(rPam, rItemSet, rValue);
} else
{
bRet = false;
}
} break; case RES_TXTATR_CJK_RUBY:
{ if (MID_RUBY_CHARSTYLE == rEntry.nMemberId)
{
lcl_setRubyCharstyle(rItemSet, rValue);
} else
{
bRet = false;
}
} break; case RES_PAGEDESC:
{ if (MID_PAGEDESC_PAGEDESCNAME == rEntry.nMemberId)
{
SwUnoCursorHelper::SetPageDesc(
rValue, rPam.GetDoc(), rItemSet);
} else
{
bRet = false;
}
} break; default:
bRet = false;
} return bRet;
}
SwXTextCursor::~SwXTextCursor()
{
SolarMutexGuard g; // #i105557#: call dtor with locked solar mutex
m_pUnoCursor.reset(nullptr); // need to delete this with SolarMutex held
}
void SwXTextCursor::DeleteAndInsert(std::u16string_view aText,
::sw::DeleteAndInsertMode const eMode)
{ auto pUnoCursor = static_cast<SwCursor*>(m_pUnoCursor.get()); if (!pUnoCursor) return;
// Start/EndAction
SwDoc& rDoc = pUnoCursor->GetDoc();
UnoActionContext aAction(&rDoc); const sal_Int32 nTextLen = aText.size();
rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr); auto pCurrent = pUnoCursor; do
{ if (pCurrent->HasMark())
{
rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent, // is it "delete" or "replace"?
(nTextLen != 0 || eMode & ::sw::DeleteAndInsertMode::ForceReplace) ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default);
} if(nTextLen)
{ // Store node and content indexes prior to insertion: to select the inserted text, // we need to account for possible surrogate pairs, combining characters, etc.; it // is easier to just restore the correct position from the indexes. constauto start = pCurrent->Start(); constauto nodeIndex = start->GetNodeIndex(); constauto contentIndex = start->GetContentIndex(); constbool bSuccess(
SwUnoCursorHelper::DocInsertStringSplitCR(
rDoc, SwPaM(*start, pCurrent), aText, bool(eMode & ::sw::DeleteAndInsertMode::ForceExpandHints)));
OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." );
// Force the cursor back into the content control if it has moved outside.
SwPosition aStart(*pTextNode, nStart);
SwPosition aEnd(*pTextNode, nEnd); switch (eMode)
{ case CONTENT_CONTROL_INIT_START:
*rCursor.GetPoint() = aStart; break;
case CONTENT_CONTROL_INIT_END:
*rCursor.GetPoint() = aEnd; break;
case CONTENT_CONTROL_CHECK_BOTH: if (*rCursor.Start() < aStart)
{
*rCursor.Start() = std::move(aStart);
bRet = false;
}
if (CursorType::Meta == m_eType)
{
SwPaM CopyPam(*pPam->GetMark(), *pPam->GetPoint()); constbool bNotForced( lcl_ForceIntoMeta(
CopyPam, m_xParentText, META_CHECK_BOTH) ); if (!bNotForced)
{ throw uno::RuntimeException(
u"gotoRange: parameter range not contained in nesting" " text content for which this cursor was created"_ustr, static_cast<text::XWordCursor*>(this));
}
} elseif (m_eType == CursorType::ContentControl)
{
SwPaM aPaM(*pPam->GetMark(), *pPam->GetPoint()); if (!lcl_ForceIntoContentControl(aPaM, m_xParentText, CONTENT_CONTROL_CHECK_BOTH))
{ throw uno::RuntimeException(u"gotoRange: xRange is out of bounds of the content control"_ustr, static_cast<text::XWordCursor*>(this));
}
}
// selection has to be expanded here if(bExpand)
{ // cursor should include its previous range plus the given range const SwPosition aOwnLeft(*rOwnCursor.Start()); const SwPosition aOwnRight(*rOwnCursor.End());
SwPosition const& rParamLeft = *pPam->Start();
SwPosition const& rParamRight = *pPam->End();
// now there are four SwPositions, // two of them are going to be used, but which ones? if (aOwnRight > rParamRight)
*rOwnCursor.GetPoint() = aOwnRight; else
*rOwnCursor.GetPoint() = rParamRight;
rOwnCursor.SetMark(); if (aOwnLeft < rParamLeft)
*rOwnCursor.GetMark() = aOwnLeft; else
*rOwnCursor.GetMark() = rParamLeft;
} else
{ // cursor should be the given range
*rOwnCursor.GetPoint() = *pPam->GetPoint(); if (pPam->HasMark())
{
rOwnCursor.SetMark();
*rOwnCursor.GetMark() = *pPam->GetMark();
} else
{
rOwnCursor.DeleteMark();
}
}
}
// problems arise when a paragraph starts with something other than a word bool bRet = false; // remember old position to check if cursor has moved // since the called functions are sometimes a bit unreliable // in specific cases...
SwPosition *const pPoint = rUnoCursor.GetPoint();
SwNode *const pOldNode = &pPoint->GetNode();
sal_Int32 const nOldIndex = pPoint->GetContentIndex();
SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); // end of paragraph if (rUnoCursor.GetPointContentNode() &&
(pPoint->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len()))
{
rUnoCursor.Right(1);
} else
{ constbool bTmp =
rUnoCursor.GoNextWordWT( i18n::WordType::DICTIONARY_WORD ); // if there is no next word within the current paragraph // try to go to the start of the next paragraph if (!bTmp)
{
rUnoCursor.MovePara(GoNextPara, fnParaStart);
}
}
// restore old cursor if we are not at the end of a word by now // otherwise use current one
bRet = rUnoCursor.IsEndWordWT( nWordType ); if (!bRet)
{
pPoint->Assign(rOldNode, nOldIndex);
} elseif (CursorType::Meta == m_eType)
{
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
} elseif (m_eType == CursorType::ContentControl)
{
bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
}
// restore old cursor if we are not at the start of a word by now // otherwise use current one
bRet = rUnoCursor.IsStartWordWT( nWordType ); if (!bRet)
{
pPoint->Assign(rOldNode, nOldIndex);
} elseif (CursorType::Meta == m_eType)
{
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
} elseif (m_eType == CursorType::ContentControl)
{
bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
}
// start of paragraph? bool bRet = rUnoCursor.GetPoint()->GetContentIndex() == 0; // with mark ->no sentence start // (check if cursor is no selection, i.e. it does not have // a mark or else point and mark are identical) if (!bRet && (!rUnoCursor.HasMark() ||
*rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
{
SwCursor aCursor(*rUnoCursor.GetPoint(),nullptr);
SwPosition aOrigPos = *aCursor.GetPoint();
aCursor.GoSentence(SwCursor::START_SENT );
bRet = aOrigPos == *aCursor.GetPoint();
} return bRet;
}
// end of paragraph? bool bRet = rUnoCursor.GetPointContentNode() &&
(rUnoCursor.GetPoint()->GetContentIndex() == rUnoCursor.GetPointContentNode()->Len()); // with mark->no sentence end // (check if cursor is no selection, i.e. it does not have // a mark or else point and mark are identical) if (!bRet && (!rUnoCursor.HasMark() ||
*rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
{
SwCursor aCursor(*rUnoCursor.GetPoint(), nullptr);
SwPosition aOrigPos = *aCursor.GetPoint();
aCursor.GoSentence(SwCursor::END_SENT);
bRet = aOrigPos == *aCursor.GetPoint();
} return bRet;
}
// if at the end of the sentence (i.e. at the space after the '.') // advance to next word in order for GoSentence to work properly // next time and have isStartOfSentence return true after this call if (!rUnoCursor.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES))
{ constbool bNextWord = rUnoCursor.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES); if (bWasEOS && !bNextWord)
{
bRet = false;
}
} if (CursorType::Meta == m_eType)
{
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH)
&& bRet;
} elseif (m_eType == CursorType::ContentControl)
{
bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
&& bRet;
} return bRet;
}
SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); // if we're at the para start then we won't move // but bRet is also true if GoSentence failed but // the start of the sentence is reached bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor)
|| rUnoCursor.GoSentence(SwCursor::START_SENT)
|| SwUnoCursorHelper::IsStartOfPara(rUnoCursor); if (CursorType::Meta == m_eType)
{
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH)
&& bRet;
} elseif (m_eType == CursorType::ContentControl)
{
bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
&& bRet;
} return bRet;
}
SwUnoCursorHelper::SelectPam(rUnoCursor, Expand); // bRet is true if GoSentence() succeeded or if the // MovePara() succeeded while the end of the para is // not reached already bool bAlreadyParaEnd = SwUnoCursorHelper::IsEndOfPara(rUnoCursor); bool bRet = !bAlreadyParaEnd
&& (rUnoCursor.GoSentence(SwCursor::END_SENT)
|| rUnoCursor.MovePara(GoCurrPara, fnParaEnd)); if (CursorType::Meta == m_eType)
{
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH)
&& bRet;
} elseif (m_eType == CursorType::ContentControl)
{
bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
&& bRet;
} return bRet;
}
// since MovePara(GoCurrPara, fnParaStart) only returns false // if we were already at the start of the paragraph this function // should always complete successfully.
OSL_ENSURE( bRet, "gotoStartOfParagraph failed" ); return bRet;
}
// since MovePara(GoCurrPara, fnParaEnd) only returns false // if we were already at the end of the paragraph this function // should always complete successfully.
OSL_ENSURE( bRet, "gotoEndOfParagraph failed" ); return bRet;
}
// FN_UNO_PARA_STYLE is known to set attributes for nodes, inside // SwUnoCursorHelper::SetTextFormatColl, instead of extending item set. // We need to get them from nodes in next call to GetCursorAttr. // The rest could cause similar problems in theory, so we just list them here. staticbool propertyCausesSideEffectsInNodes(sal_uInt16 nWID)
{ return nWID == FN_UNO_PARA_STYLE ||
nWID == FN_UNO_CHARFMT_SEQUENCE ||
nWID == FN_UNO_NUM_START_VALUE ||
nWID == FN_UNO_NUM_RULES;
}
// Queue up any exceptions until the end ... if (!pEntry)
{
aUnknownExMsg += "Unknown property: '" + rPropertyName + "' "; continue;
} elseif (pEntry->nFlags & beans::PropertyAttribute::READONLY)
{
aPropertyVetoExMsg += "Property is read-only: '" + rPropertyName + "' "; continue;
} if (propertyCausesSideEffectsInNodes(pEntry->nWID))
{
aSideEffectsEntries.emplace_back(pEntry, rPropVal.Value);
} else
{
aRanges = aRanges.MergeRange(pEntry->nWID, pEntry->nWID);
aEntries.emplace_back(pEntry, rPropVal.Value);
}
}
// Entries with side effects first, using dedicated one-element SfxItemSet for each for (constauto& [pEntry, rValue] : aSideEffectsEntries)
{
SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID); // we need to get up-to-date item set from nodes
SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet); // this can set some attributes in nodes' mpAttrSet if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet))
SfxItemPropertySet::setPropertyValue(*pEntry, rValue, aItemSet);
SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false/*bTableMode*/);
}
if (!aEntries.empty())
{ // Fetch, overwrite, and re-set the attributes from the core
SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aRanges)); // we need to get up-to-date item set from nodes
SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
for (constauto& [pEntry, rValue] : aEntries)
{ // this can set some attributes in nodes' mpAttrSet if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet))
SfxItemPropertySet::setPropertyValue(*pEntry, rValue, aItemSet);
}
if (!aUnknownExMsg.isEmpty()) throw beans::UnknownPropertyException(aUnknownExMsg); if (!aPropertyVetoExMsg.isEmpty()) throw beans::PropertyVetoException(aPropertyVetoExMsg);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.