/* -*- 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 .
*/
// Used to draw the guide line while resizing the comment sidebar width static tools::Rectangle aLastCommentSidebarPos;
// Usually in MouseButtonUp a selection is revoked when the selection is // not currently being pulled open. Unfortunately in MouseButtonDown there // is being selected at double/triple click. That selection is completely // finished in the Handler and thus can't be distinguished in the Up. // To resolve this g_bHoldSelection is set in Down and evaluated in Up. staticbool g_bHoldSelection = false;
/// Check if the selected shape has a TextBox: if so, go into that instead. staticbool lcl_goIntoTextBox(SwEditWin& rEditWin, SwWrtShell& rSh)
{
SdrMark* pMark = rSh.GetDrawView()->GetMarkedObjectList().GetMark(0); if (!pMark) returnfalse;
SdrObject* pSdrObject = pMark->GetMarkedSdrObj();
SwFrameFormat* pObjectFormat = ::FindFrameFormat(pSdrObject); if (SwFrameFormat* pTextBoxFormat = SwTextBoxHelper::getOtherTextBoxFormat(pObjectFormat, RES_DRAWFRMFMT))
{
SdrObject* pTextBox = pTextBoxFormat->FindRealSdrObject();
SdrView* pSdrView = rSh.GetDrawView(); // Unmark the shape.
pSdrView->UnmarkAllObj(); // Mark the textbox.
rSh.SelectObj(Point(), SW_ALLOW_TEXTBOX, pTextBox); // Clear the DrawFuncPtr.
rEditWin.StopInsFrame(); returntrue;
} returnfalse;
}
/// Assists with auto-completion of AutoComplete words and AutoText names. struct QuickHelpData
{ /// Strings that at least partially match an input word, and match length.
std::vector<std::pair<OUString, sal_uInt16>> m_aHelpStrings; /// Index of the current help string.
sal_uInt16 nCurArrPos; static constexpr sal_uInt16 nNoPos = std::numeric_limits<sal_uInt16>::max();
/// Help data stores AutoText names rather than AutoComplete words. bool m_bIsAutoText; /// Display help string as a tip rather than inline. bool m_bIsTip; /// Tip ID when a help string is displayed as a tip. void* nTipId; /// Append a space character to the displayed help string (if appropriate). bool m_bAppendSpace;
/// Help string is currently displayed. bool m_bIsDisplayed;
/** * For MouseButtonDown - determine whether a DrawObject * a NO SwgFrame was hit! Shift/Ctrl should only result * in selecting, with DrawObjects; at SwgFlys to trigger * hyperlinks if applicable (Download/NewWindow!)
*/ staticbool IsDrawObjSelectable( const SwWrtShell& rSh, const Point& rPt )
{ bool bRet = true;
SdrObject* pObj; switch( rSh.GetObjCntType( rPt, pObj ))
{ case OBJCNT_NONE: case OBJCNT_FLY: case OBJCNT_GRF: case OBJCNT_OLE:
bRet = false; break; default:; //prevent warning
} return bRet;
}
m_aActHitType = SdrHitKind::NONE;
PointerStyle eStyle = PointerStyle::Text; if ( !pSdrView )
bCntAtPos = true; elseif ( (bHitHandle = (pSdrView->PickHandle(rLPt) != nullptr)) )
{
m_aActHitType = SdrHitKind::Object;
bPrefSdrPointer = true;
} else
{ constbool bNotInSelObj = !rSh.IsInsideSelectedObj( rLPt ); if ( m_rView.GetDrawFuncPtr() && !m_bInsDraw && bNotInSelObj )
{
m_aActHitType = SdrHitKind::Object; if (IsObjectSelect())
eStyle = PointerStyle::Arrow; else
bPrefSdrPointer = true;
} else
{
SdrPageView* pPV = nullptr;
pSdrView->SetHitTolerancePixel( HIT_PIX );
SdrObject* pObj = (bNotInSelObj && bExecHyperlinks) ?
pSdrView->PickObj(rLPt, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) :
nullptr; if (pObj)
{
SdrObjMacroHitRec aTmp;
aTmp.aPos = rLPt;
aTmp.pPageView = pPV;
SetPointer( pObj->GetMacroPointer( aTmp ) ); return;
} else
{ // dvo: IsObjSelectable() eventually calls SdrView::PickObj, so // apparently this is used to determine whether this is a // drawling layer object or not. if ( rSh.IsObjSelectable( rLPt ) )
{ if (pSdrView->IsTextEdit())
{
m_aActHitType = SdrHitKind::NONE;
bPrefSdrPointer = true;
} else
{
SdrViewEvent aVEvt;
SdrHitKind eHit = pSdrView->PickAnything(rLPt, aVEvt);
if (eHit == SdrHitKind::UrlField && bExecHyperlinks)
{
m_aActHitType = SdrHitKind::Object;
bPrefSdrPointer = true;
} else
{ // if we're over a selected object, we show an // ARROW by default. We only show a MOVE if 1) the // object is selected, and 2) it may be moved // (i.e., position is not protected). bool bMovable =
(!bNotInSelObj) &&
(rSh.GetSelectedObjCount() || rSh.IsFrameSelected()) &&
(rSh.IsSelObjProtected(FlyProtectFlags::Pos) == FlyProtectFlags::NONE);
SdrObject* pSelectableObj = rSh.GetObjAt(rLPt); // Don't update pointer if this is a background image only. if (pSelectableObj->GetLayer() != rSh.GetDoc()->getIDocumentDrawModelAccess().GetHellId())
eStyle = bMovable ? PointerStyle::Move : PointerStyle::Arrow;
m_aActHitType = SdrHitKind::Object;
}
}
} else
{ if ( rSh.IsFrameSelected() && !bNotInSelObj )
{ // dvo: this branch appears to be dead and should be // removed in a future version. Reason: The condition // !bNotInSelObj means that this branch will only be // executed in the cursor points inside a selected // object. However, if this is the case, the previous // if( rSh.IsObjSelectable(rLPt) ) must always be true: // rLPt is inside a selected object, then obviously // rLPt is over a selectable object. if (rSh.IsSelObjProtected(FlyProtectFlags::Size) != FlyProtectFlags::NONE)
eStyle = PointerStyle::NotAllowed; else
eStyle = PointerStyle::Move;
m_aActHitType = SdrHitKind::Object;
} else
{ if ( m_rView.GetDrawFuncPtr() )
bPrefSdrPointer = true; else
bCntAtPos = true;
}
}
}
}
} if ( bPrefSdrPointer )
{ if (bIsViewReadOnly || (rSh.GetSelectedObjCount() && rSh.IsSelObjProtected(FlyProtectFlags::Content) != FlyProtectFlags::NONE))
SetPointer( PointerStyle::NotAllowed ); else
{ if (m_rView.GetDrawFuncPtr() && m_rView.GetDrawFuncPtr()->IsInsertForm() && !bHitHandle)
SetPointer( PointerStyle::DrawRect ); else
SetPointer( pSdrView->GetPreferredPointer( rLPt, rSh.GetOut() ) );
}
} else
{ if( !rSh.IsPageAtPos( rLPt ) || m_pAnchorMarker )
eStyle = PointerStyle::Arrow; else
{ // Even if we already have something, prefer URLs if possible.
SwContentAtPos aUrlPos(IsAttrAtPos::InetAttr); if (bCntAtPos || rSh.GetContentAtPos(rLPt, aUrlPos))
{
SwContentAtPos aSwContentAtPos(
IsAttrAtPos::Field |
IsAttrAtPos::ClickField |
IsAttrAtPos::InetAttr |
IsAttrAtPos::Footnote |
IsAttrAtPos::SmartTag); if( rSh.GetContentAtPos( rLPt, aSwContentAtPos) )
{ // Is edit inline input field if (IsAttrAtPos::Field == aSwContentAtPos.eContentAtPos
&& aSwContentAtPos.pFndTextAttr != nullptr
&& aSwContentAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD)
{ const SwField *pCursorField = rSh.CursorInsideInputField() ? rSh.GetCurField( true ) : nullptr; if (!(pCursorField && pCursorField == aSwContentAtPos.pFndTextAttr->GetFormatField().GetField()))
eStyle = PointerStyle::RefHand;
} else
{ constbool bClickToFollow = IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos ||
IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos; if( !bClickToFollow ||
(IsAttrAtPos::InetAttr == aSwContentAtPos.eContentAtPos && bExecHyperlinks) ||
(IsAttrAtPos::SmartTag == aSwContentAtPos.eContentAtPos && bExecSmarttags) )
eStyle = PointerStyle::RefHand;
}
} elseif (GetView().GetWrtShell().GetViewOptions()->IsShowOutlineContentVisibilityButton())
{
aSwContentAtPos.eContentAtPos = IsAttrAtPos::Outline; if (rSh.GetContentAtPos(rLPt, aSwContentAtPos))
{ if (IsAttrAtPos::Outline == aSwContentAtPos.eContentAtPos)
{ if (nModifier == KEY_MOD1)
{
eStyle = PointerStyle::RefHand; // set quick help if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
{ const SwNodes& rNds = GetView().GetWrtShell().GetDoc()->GetNodes();
SwOutlineNodes::size_type nPos;
rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos);
SwOutlineNodes::size_type nOutlineNodesCount
= rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos);
OUString sQuickHelp(SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY)); if (!rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent()
&& nPos + 1 < nOutlineNodesCount
&& rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos + 1) > nLevel)
sQuickHelp += " (" + SwResId(STR_CLICK_OUTLINE_CONTENT_TOGGLE_VISIBILITY_EXT) + ")";
SetQuickHelpText(sQuickHelp);
}
}
}
}
}
}
}
// which kind of text pointer have we to show - horz / vert - ? if( PointerStyle::Text == eStyle && rSh.IsInVerticalText( &rLPt ))
eStyle = PointerStyle::TextVertical; elseif (rSh.GetViewOptions()->CanHideWhitespace() &&
rSh.GetLayout()->IsBetweenPages(rLPt))
{ if (rSh.GetViewOptions()->IsHideWhitespaceMode())
eStyle = PointerStyle::ShowWhitespace; else
eStyle = PointerStyle::HideWhitespace;
}
if( m_pShadCursor )
{ if( text::HoriOrientation::LEFT == m_eOrient ) // Arrow to the right
eStyle = PointerStyle::AutoScrollE; else// Arrow to the left
eStyle = PointerStyle::AutoScrollW;
}
// It can be that a "jump" over a table cannot be accomplished like // that. So we jump over the table by Up/Down here. const SwRect& rVisArea = rSh.VisArea(); if( aOldVis == rVisArea && !rSh.IsStartOfDoc() && !rSh.IsEndOfDoc() )
{ // take the center point of VisArea to // decide in which direction the user want. if( aModPt.Y() < ( rVisArea.Top() + rVisArea.Height() / 2 ) )
rSh.Up( true ); else
rSh.Down( true );
}
}
//return INVALID_HINT if language should not be explicitly overridden, the correct //HintId to use for the eBufferLanguage otherwise static sal_uInt16 lcl_isNonDefaultLanguage(LanguageType eBufferLanguage, SwView const & rView, const OUString &rInBuffer)
{
sal_uInt16 nWhich = INVALID_HINT;
//If the option to IgnoreLanguageChange is set, short-circuit this method //which results in the document/paragraph language remaining the same //despite a change to the keyboard/input language
SvtSysLocaleOptions aSysLocaleOptions; if(aSysLocaleOptions.IsIgnoreLanguageChange())
{ return INVALID_HINT;
}
bool bLang = true; if(eBufferLanguage != LANGUAGE_DONTKNOW)
{ switch( SvtLanguageOptions::GetI18NScriptTypeOfLanguage( eBufferLanguage ))
{ case i18n::ScriptType::ASIAN: nWhich = RES_CHRATR_CJK_LANGUAGE; break; case i18n::ScriptType::COMPLEX: nWhich = RES_CHRATR_CTL_LANGUAGE; break; case i18n::ScriptType::LATIN: nWhich = RES_CHRATR_LANGUAGE; break; default: bLang = false;
} if(bLang)
{
SfxItemSet aLangSet(rView.GetPool(), nWhich, nWhich);
SwWrtShell& rSh = rView.GetWrtShell();
rSh.GetCurAttr(aLangSet); if(SfxItemState::DEFAULT <= aLangSet.GetItemState(nWhich))
{
LanguageType eLang = static_cast<const SvxLanguageItem&>(aLangSet.Get(nWhich)).GetLanguage(); if ( eLang == eBufferLanguage )
{ // current language attribute equal to language reported from system
bLang = false;
} elseif ( !g_bInputLanguageSwitched && RES_CHRATR_LANGUAGE == nWhich )
{ // special case: switching between two "LATIN" languages // In case the current keyboard setting might be suitable // for both languages we can't safely assume that the user // wants to use the language reported from the system, // except if we knew that it was explicitly switched (thus // the check for "bInputLangeSwitched").
// The language reported by the system could be just the // system default language that the user is not even aware // of, because no language selection tool is installed at // all. In this case the OOo language should get preference // as it might have been selected by the user explicitly.
// Usually this case happens if the OOo language is // different to the system language but the system keyboard // is still suitable for the OOo language (e.g. writing // English texts with a German keyboard).
// For non-latin keyboards overwriting the attribute is // still valid. We do this for cyrillic and greek ATM. In // future versions of OOo this should be replaced by a // configuration switch that allows to give the preference // to the OOo setting or the system setting explicitly // and/or a better handling of the script type.
i18n::UnicodeScript eType = !rInBuffer.isEmpty() ?
GetAppCharClass().getScript( rInBuffer, 0 ) :
i18n::UnicodeScript_kScriptCount;
bool bSystemIsNonLatin = false; switch ( eType )
{ case i18n::UnicodeScript_kGreek: case i18n::UnicodeScript_kCyrillic: // in case other UnicodeScripts require special // keyboards they can be added here
bSystemIsNonLatin = true; break; default: break;
}
/** * Character buffer is inserted into the document
*/ void SwEditWin::FlushInBuffer()
{ if ( m_aKeyInputFlushTimer.IsActive())
m_aKeyInputFlushTimer.Stop();
// get text from the beginning (i.e left side) of current selection // to the start of the paragraph
rSh.NormalizePam(); // make point be the first (left) one if (!rSh.GetCursor()->HasMark())
rSh.GetCursor()->SetMark();
rSh.GetCursor()->GetMark()->SetContent(0);
// valid sequence or sequence could be corrected: if (nPrevPos != aNewText.getLength())
nTmpPos = nPrevPos + 1;
}
// find position of first character that has changed
sal_Int32 nNewLen = aNewText.getLength(); const sal_Unicode *pOldText = aOldText.getStr(); const sal_Unicode *pNewText = aNewText.getStr();
sal_Int32 nChgPos = 0; while ( nChgPos < nOldLen && nChgPos < nNewLen &&
pOldText[nChgPos] == pNewText[nChgPos] )
++nChgPos;
const sal_Int32 nChgLen = nNewLen - nChgPos; if (nChgLen)
{
m_aInBuffer = aNewText.copy( nChgPos, nChgLen );
nExpandSelection = nOldLen - nChgPos;
} else
m_aInBuffer.clear();
} else
{ for( sal_Int32 k = 0; k < m_aInBuffer.getLength(); ++k )
{ const sal_Unicode cChar = m_aInBuffer[k]; if (xISC->checkInputSequence( aNewText, nTmpPos - 1, cChar, nCheckMode ))
{ // character can be inserted:
aNewText += OUStringChar( cChar );
++nTmpPos;
}
}
m_aInBuffer = aNewText.copy( aOldText.getLength() ); // copy new text to be inserted to buffer
}
}
// at this point now we will insert the buffer text 'normally' some lines below...
rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
if (m_aInBuffer.isEmpty()) return;
// if text prior to the original selection needs to be changed // as well, we now expand the selection accordingly.
SwPaM &rCursor = *rSh.GetCursor(); const sal_Int32 nCursorStartPos = rCursor.Start()->GetContentIndex();
OSL_ENSURE( nCursorStartPos >= nExpandSelection, "cannot expand selection as specified!!"); if (nExpandSelection && nCursorStartPos >= nExpandSelection)
{ if (!rCursor.HasMark())
rCursor.SetMark();
rCursor.Start()->AdjustContent( -nExpandSelection );
}
}
if ( xRecorder.is() )
{ // determine shell
SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView ); // generate request and record if (pSfxShell)
{
SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, m_aInBuffer ) );
aReq.Done();
}
}
void SwEditWin::ChangeDrawing( sal_uInt8 nDir )
{ // start undo action in order to get only one // undo action for this change.
SwWrtShell &rSh = m_rView.GetWrtShell();
rSh.StartUndo();
tools::Long nX = 0;
tools::Long nY = 0; constbool bOnePixel(
MOVE_LEFT_SMALL == nDir ||
MOVE_UP_SMALL == nDir ||
MOVE_RIGHT_SMALL == nDir ||
MOVE_DOWN_SMALL == nDir); constbool bHuge(
MOVE_LEFT_HUGE == nDir ||
MOVE_UP_HUGE == nDir ||
MOVE_RIGHT_HUGE == nDir ||
MOVE_DOWN_HUGE == nDir);
SwMove nAnchorDir = SwMove::UP; switch(nDir)
{ case MOVE_LEFT_SMALL: case MOVE_LEFT_HUGE: case MOVE_LEFT_BIG:
nX = -1;
nAnchorDir = SwMove::LEFT; break; case MOVE_UP_SMALL: case MOVE_UP_HUGE: case MOVE_UP_BIG:
nY = -1; break; case MOVE_RIGHT_SMALL: case MOVE_RIGHT_HUGE: case MOVE_RIGHT_BIG:
nX = +1;
nAnchorDir = SwMove::RIGHT; break; case MOVE_DOWN_SMALL: case MOVE_DOWN_HUGE: case MOVE_DOWN_BIG:
nY = +1;
nAnchorDir = SwMove::DOWN; break;
}
if(bOnePixel)
{
aSnap = PixelToLogic(Size(1,1));
} elseif(bHuge)
{ // #i121236# 567twips == 1cm, but just take three times the normal snap
aSnap = Size(aSnap.Width() * 3, aSnap.Height() * 3);
}
nX *= aSnap.Width();
nY *= aSnap.Height();
SdrView *pSdrView = rSh.GetDrawView(); const SdrHdlList& rHdlList = pSdrView->GetHdlList();
SdrHdl* pHdl = rHdlList.GetFocusHdl();
rSh.StartAllAction(); if(nullptr == pHdl)
{ // now move the selected draw objects // if the object's position is not protected if(!(nProtect&FlyProtectFlags::Pos))
{ // Check if object is anchored as character and move direction bool bDummy1, bDummy2; constbool bVertAnchor = rSh.IsFrameVertical( true, bDummy1, bDummy2 ); bool bHoriMove = !bVertAnchor == !( nDir % 2 ); bool bMoveAllowed =
!bHoriMove || (rSh.GetAnchorId() != RndStdIds::FLY_AS_CHAR); if ( bMoveAllowed )
{
pSdrView->MoveAllMarked(Size(nX, nY));
rSh.SetModified();
}
}
} else
{ // move handle with index nHandleIndex if (nX || nY)
{ if( SdrHdlKind::Anchor == pHdl->GetKind() ||
SdrHdlKind::Anchor_TR == pHdl->GetKind() )
{ // anchor move cannot be allowed when position is protected if(!(nProtect&FlyProtectFlags::Pos))
rSh.MoveAnchor( nAnchorDir );
} //now resize if size is protected elseif(!(nProtect&FlyProtectFlags::Size))
{ // now move the Handle (nX, nY)
Point aStartPoint(pHdl->GetPos());
Point aEndPoint(pHdl->GetPos() + Point(nX, nY)); const SdrDragStat& rDragStat = pSdrView->GetDragStat();
SfxObjectShell *pObjSh = m_rView.GetViewFrame().GetObjectShell(); if ( m_bLockInput || (pObjSh && pObjSh->GetProgress()) ) // When the progress bar is active or a progress is // running on a document, no order is being taken return;
m_pShadCursor.reset(); // Do not reset the timer here, otherwise when flooded with events it would never time out // if every key event stopped and started it again.
comphelper::ScopeGuard keyInputFlushTimerStop([this]() { m_aKeyInputFlushTimer.Stop(); });
bool bIsViewReadOnly = IsViewReadonly();
//if the language changes the buffer must be flushed
LanguageType eNewLanguage = GetInputLanguage(); if(!bIsViewReadOnly && m_eBufferLanguage != eNewLanguage && !m_aInBuffer.isEmpty())
{
FlushInBuffer();
}
m_eBufferLanguage = eNewLanguage;
// OS:the DrawView also needs a readonly-Flag as well if ( !bIsViewReadOnly && rSh.GetDrawView() && rSh.GetDrawView()->KeyInput( rKEvt, this ) )
{
rSh.GetView().GetViewFrame().GetBindings().InvalidateAll( false );
rSh.SetModified(); return; // Event evaluated by SdrView
}
if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
{
StopInsFrame();
rSh.Edit();
}
const vcl::KeyCode& rKeyCode = aKeyEvent.GetKeyCode();
sal_Unicode aCh = aKeyEvent.GetCharCode();
// enable switching to notes anchor with Ctrl - Alt - Page Up/Down // pressing this inside a note will switch to next/previous note if ((rKeyCode.IsMod1() && rKeyCode.IsMod2()) && ((rKeyCode.GetCode() == KEY_PAGEUP) || (rKeyCode.GetCode() == KEY_PAGEDOWN)))
{ constbool bNext = rKeyCode.GetCode()==KEY_PAGEDOWN; const SwFieldType* pFieldType = rSh.GetFieldType( 0, SwFieldIds::Postit );
rSh.MoveFieldType( pFieldType, bNext ); return;
}
if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
{ // Check if this combination of rKeyCode and pTextContentControl should open a popup. const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl(); if (pContentControl->ShouldOpenPopup(rKeyCode))
{
SwShellCursor* pCursor = rSh.GetCursor_(); if (pCursor)
{
VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton(); if (pContentControlButton)
{
pContentControlButton->StartPopup(); return;
}
}
}
}
if (pFlyFormat)
{ // See if the fly frame's anchor is in a content control. If so, // try to interact with it. const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode(); if (pAnchorNode)
{
SwTextNode* pTextNode = pAnchorNode->GetTextNode(); if (pTextNode)
{
sal_Int32 nContentIdx = rFormatAnchor.GetAnchorContentOffset();
SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
nContentIdx, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent); if (pAttr)
{
SwTextContentControl* pTextContentControl
= static_txtattr_cast<SwTextContentControl*>(pAttr); const SwFormatContentControl& rFormatContentControl
= pTextContentControl->GetContentControl();
std::shared_ptr<SwContentControl> pContentControl
= rFormatContentControl.GetContentControl(); if (pContentControl->IsInteractingCharacter(aCh))
{
rSh.GotoContentControl(rFormatContentControl); return;
}
}
}
}
}
// If the cursor is in an empty paragraph, which has // a numbering, but not the outline numbering, and // there is no selection, the numbering has to be // deleted on key <Backspace>. // Otherwise method <SwEditShell::NumOrNoNum(..)> // should only change the <IsCounted()> state of // the current paragraph depending of the key. // On <backspace> it is set to <false>, // on <shift-backspace> it is set to <true>. // Thus, assure that method <SwEditShell::NumOrNum(..)> // is only called for the intended purpose. if ( !bDone && rSh.IsSttPara() )
{ bool bCallNumOrNoNum( false ); if ( bOnlyBackspaceKey && !rSh.IsNoNum() )
{
bCallNumOrNoNum = true;
} elseif ( !bOnlyBackspaceKey && rSh.IsNoNum() )
{
bCallNumOrNoNum = true;
} elseif ( bOnlyBackspaceKey
&& rSh.IsSttPara()
&& rSh.IsEndPara()
&& !rSh.HasSelection() )
{ const SwNumRule* pCurrNumRule( rSh.GetNumRuleAtCurrCursorPos() ); if ( pCurrNumRule != nullptr
&& pCurrNumRule != rSh.GetOutlineNumRule() )
{
bCallNumOrNoNum = true;
}
} if ( bCallNumOrNoNum
&& rSh.NumOrNoNum( !bOnlyBackspaceKey ) )
{
eKeyState = SwKeyState::NumOrNoNum;
}
}
}
} elseif (!rSh.IsCursorInParagraphMetadataField())
{
rSh.InfoReadOnlyDialog(false);
eKeyState = SwKeyState::End;
} break;
case KEY_RIGHT:
{
eFlyState = SwKeyState::Fly_Change;
nDir = MOVE_RIGHT_BIG; goto KEYINPUT_CHECKTABLE_INSDEL;
} case KEY_TAB:
{ // Rich text contentControls accept tabs and fieldmarks and other rich text, // so first act on cases that are not a content control
SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl(); if ((rSh.IsFormProtected() && !pTextContentControl) ||
rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
{
eKeyState = SwKeyState::GotoNextFieldMark;
} elseif ( !rSh.IsMultiSelection() && rSh.CursorInsideInputField() )
{
GetView().GetViewFrame().GetDispatcher()->Execute( FN_GOTO_NEXT_INPUTFLD );
eKeyState = SwKeyState::End;
} elseif( rSh.GetNumRuleAtCurrCursorPos()
&& rSh.IsSttOfPara()
&& !rSh.HasReadonlySel() )
{ if (numfunc::NumDownChangesIndent(rSh))
{
eKeyState = SwKeyState::NumDown;
} else
{
eKeyState = SwKeyState::InsTab;
}
} elseif (rSh.GetSelectionType() &
(SelectionType::Graphic |
SelectionType::Frame |
SelectionType::Ole |
SelectionType::DrawObject |
SelectionType::DbForm))
{
eKeyState = SwKeyState::NextObject;
} elseif ( rSh.GetTableFormat() )
{ if( rSh.HasSelection() || rSh.HasReadonlySel() )
eKeyState = SwKeyState::NextCell; else
{
eKeyState = SwKeyState::CheckAutoCorrect;
eNextKeyState = SwKeyState::NextCell;
}
} elseif (pTextContentControl)
{ auto pCC = pTextContentControl->GetContentControl().GetContentControl(); if (pCC)
{ switch (pCC->GetType())
{ case SwContentControlType::RICH_TEXT:
eKeyState = SwKeyState::InsTab; break; default:
eKeyState = SwKeyState::GotoNextFieldMark;
}
}
} else
{
eKeyState = SwKeyState::InsTab; if( rSh.IsSttOfPara() && !rSh.HasReadonlySel() )
{
SwTextFormatColl* pColl = rSh.GetCurTextFormatColl(); if( pColl &&
if (rSh.HasReadonlySel()
&& ( rKeyCode.GetFunction() == KeyFuncType::PASTE
|| rKeyCode.GetFunction() == KeyFuncType::CUT))
{
rSh.InfoReadOnlyDialog(true);
eKeyState = SwKeyState::End;
} elseif( m_rView.KeyInput( aKeyEvent ) )
{
bFlushBuffer = true;
bNormalChar = false;
} else
{ // Because Sfx accelerators are only called when they were // enabled at the last status update, copy has to called // 'forcefully' by us if necessary. if( rKeyCode.GetFunction() == KeyFuncType::COPY )
GetView().GetViewFrame().GetBindings().Execute(SID_COPY);
bool bTextBox = false; if (bDrawObject && lcl_goIntoTextBox(*this, rSh)) // A draw shape was selected, but it has a TextBox, // start editing that instead when the normal // character is pressed.
bTextBox = true;
const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl(bForward);
eKeyState = SwKeyState::End;
} break; case SwKeyState::InsTab: if( dynamic_cast<const SwWebView*>( &m_rView) != nullptr) // no Tab for WebView
{ // then it should be passed along
Window::KeyInput( aKeyEvent );
eKeyState = SwKeyState::End; break;
}
aCh = '\t';
[[fallthrough]]; case SwKeyState::InsChar:
{ if (rSh.CursorInsideContentControl())
{ const SwPosition* pStart = rSh.GetCursor()->Start();
SwTextNode* pTextNode = pStart->GetNode().GetTextNode(); if (pTextNode)
{
sal_Int32 nIndex = pStart->GetContentIndex();
SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent); if (pAttr)
{ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl(); if (pContentControl->IsInteractingCharacter(aCh))
{
rSh.GotoContentControl(rFormatContentControl);
eKeyState = SwKeyState::End; break;
}
}
}
}
if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
{
::sw::mark::CheckboxFieldmark* pFieldmark = dynamic_cast< ::sw::mark::CheckboxFieldmark* >
(rSh.GetCurrentFieldmark());
OSL_ENSURE(pFieldmark, "Where is my FieldMark??"); if(pFieldmark)
{
pFieldmark->SetChecked(!pFieldmark->IsChecked());
OSL_ENSURE(pFieldmark->IsExpanded(), "where is the otherpos?"); if (pFieldmark->IsExpanded())
{
rSh.CalcLayout();
}
}
eKeyState = SwKeyState::End;
} elseif ( !rSh.HasReadonlySel()
|| rSh.CursorInsideInputField() )
{ constbool bIsNormalChar =
GetAppCharClass().isLetterNumeric( OUString( aCh ), 0 ); if( bAppendSpace && bIsNormalChar &&
(!m_aInBuffer.isEmpty() || !rSh.IsSttPara() || !rSh.IsEndPara() ))
{ // insert a blank ahead of the character. this ends up // between the expanded text and the new "non-word-separator".
m_aInBuffer += " ";
}
case SwKeyState::NumOff: // shell change - so record in advance
rSh.DelNumRules(); break; case SwKeyState::OutlineLvOff: // delete autofmt outlinelevel later break;
case SwKeyState::NumDown:
rSh.NumUpDown();
m_nKS_NUMDOWN_Count = 2; break; case SwKeyState::NumUp:
rSh.NumUpDown( false ); break;
case SwKeyState::NumIndentInc:
rSh.ChangeIndentOfAllListLevels(360);
m_nKS_NUMINDENTINC_Count = 2; break;
case SwKeyState::GotoNextFieldMark:
{
rSh.GotoFormControl(/*bNext=*/true);
} break;
case SwKeyState::GotoPrevFieldMark:
{
rSh.GotoFormControl(/*bNext=*/false);
} break;
case SwKeyState::NumIndentDec:
rSh.ChangeIndentOfAllListLevels(-360); break;
case SwKeyState::OutlineDown:
rSh.OutlineUpDown(); break; case SwKeyState::OutlineUp:
rSh.OutlineUpDown( -1 ); break;
case SwKeyState::NextCell: // always 'flush' in tables
rSh.GoNextCell(!rSh.HasReadonlySel());
nSlotId = FN_GOTO_NEXT_CELL; break; case SwKeyState::PrevCell:
rSh.GoPrevCell();
nSlotId = FN_GOTO_PREV_CELL; break; case SwKeyState::AutoFormatByInput:
rSh.SplitNode( true ); break;
case SwKeyState::NextObject: case SwKeyState::PrevObject: if(rSh.GotoObj( SwKeyState::NextObject == eKeyState, GotoObjFlags::Any))
{ if( rSh.IsFrameSelected() &&
m_rView.GetDrawFuncPtr() )
{
m_rView.GetDrawFuncPtr()->Deactivate();
m_rView.SetDrawFuncPtr(nullptr);
m_rView.LeaveDrawCreate();
m_rView.AttrChangedNotify(nullptr);
}
rSh.HideCursor();
rSh.EnterSelFrameMode();
} break; case SwKeyState::GlossaryExpand:
{ // replace the word or abbreviation with the auto text
rSh.StartUndo( SwUndoId::START );
// in case the buffered characters are inserted if( bFlushBuffer && !m_aInBuffer.isEmpty() )
{
FlushInBuffer();
}
// get the word count dialog to update itself
SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId())); if( pWrdCnt )
pWrdCnt->UpdateCounts();
}
/** * MouseEvents
*/ void SwEditWin::ResetMouseButtonDownFlags()
{ // Not on all systems a MouseButtonUp is used ahead // of the modal dialog (like on WINDOWS). // So reset the statuses here and release the mouse // for the dialog.
m_bMBPressed = false;
g_bNoInterrupt = false;
EnterArea();
ReleaseMouse();
}
/** * Determines if the current position has a clickable url over a background * frame. In that case, ctrl-click should select the url, not the frame.
*/ staticbool lcl_urlOverBackground(SwWrtShell& rSh, const Point& rDocPos)
{
SwContentAtPos aSwContentAtPos(IsAttrAtPos::InetAttr);
SdrObject* pSelectableObj = rSh.GetObjAt(rDocPos);
// We have to check if a context menu is shown and we have an UI // active inplace client. In that case we have to ignore the mouse // button down event. Otherwise we would crash (context menu has been // opened by inplace client and we would deactivate the inplace client, // the context menu is closed by VCL asynchronously which in the end // would work on deleted objects or the context menu has no parent anymore)
SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient(); bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() );
if (bIsOleActive && vcl::IsInPopupMenuExecute()) return;
MouseEvent aMEvt(_rMEvt);
if (m_rView.GetPostItMgr()->IsHit(aMEvt.GetPosPixel())) return;
if (comphelper::LibreOfficeKit::isActive())
{ if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(aMEvt.GetPosPixel()))
{
pWindow->MouseButtonDown(aMEvt); return;
}
}
if (aMEvt.GetButtons() == MOUSE_LEFT && m_rView.GetPostItMgr()->IsHitSidebarDragArea(aMEvt.GetPosPixel()))
{
mbIsDragSidebar = true; // Capture mouse to keep tracking even if the mouse leaves the document window
CaptureMouse(); return;
}
bool bIsViewReadOnly = m_rView.GetDocShell()->IsReadOnly() || (rSh.GetSfxViewShell() && rSh.GetSfxViewShell()->IsLokReadOnlyView()); if (bOverHeaderFooterFly && (!bIsViewReadOnly && rSh.GetCurField())) // We have a field here, that should have priority over header/footer fly.
bOverHeaderFooterFly = false;
// Are we clicking on a blank header/footer area? if ( IsInHeaderFooter( aDocPos, eControl ) || bOverHeaderFooterFly )
{ const SwPageFrame* pPageFrame = rSh.GetLayout()->GetPageAtPos( aDocPos );
if ( pPageFrame )
{ // Is it active? bool bActive = true; const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
if ( pFormat )
{ if ( eControl == FrameControlType::Header )
bActive = pFormat->GetHeader().IsActive(); else
bActive = pFormat->GetFooter().IsActive();
}
if ( !bActive )
{ // HeaderFooter menu implies header/footer controls, so only do this with IsUseHeaderFooterMenu enabled. // But, additionally, when in Hide-Whitespace mode, we don't want those controls. if (rSh.GetViewOptions()->IsUseHeaderFooterMenu() && !rSh.GetViewOptions()->IsHideWhitespaceMode())
{
SwPaM aPam(*rSh.GetCurrentShellCursor().GetPoint()); constbool bWasInHeader = aPam.GetPoint()->GetNode().FindHeaderStartNode() != nullptr; constbool bWasInFooter = aPam.GetPoint()->GetNode().FindFooterStartNode() != nullptr;
// Is the cursor in a part like similar to the one we clicked on? For example, // if the cursor is in a header and we click on an empty header... don't change anything to // keep consistent behaviour due to header edit mode (and the same for the footer as well).
// Otherwise, we hide the header/footer control if a separator is shown, and vice versa. if (!(bWasInHeader && eControl == FrameControlType::Header) &&
!(bWasInFooter && eControl == FrameControlType::Footer))
{ constbool bSeparatorWasVisible = rSh.IsShowHeaderFooterSeparator(eControl);
rSh.SetShowHeaderFooterSeparator(eControl, !bSeparatorWasVisible);
// Repaint everything
Invalidate();
// tdf#84929. If the footer control had not been showing, do not change the cursor position, // because the user may have scrolled to turn on the separator control and // if the cursor cannot be positioned on-screen, then the user would need to scroll back again to use the control. // This should only be done for the footer. The cursor can always be re-positioned near the header. tdf#134023. if ( eControl == FrameControlType::Footer && !bSeparatorWasVisible
&& !Application::IsHeadlessModeEnabled() ) return;
}
}
} else
{ // Make sure we have the proper Header/Footer separators shown // as these may be changed if clicking on an empty Header/Footer
rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, eControl == FrameControlType::Header );
rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, eControl == FrameControlType::Footer );
if ( !rSh.IsHeaderFooterEdit() )
rSh.ToggleHeaderFooterEdit();
}
}
} else
{ if ( rSh.IsHeaderFooterEdit( ) )
rSh.ToggleHeaderFooterEdit( ); else
{ // Make sure that the separators are hidden
rSh.SetShowHeaderFooterSeparator( FrameControlType::Header, false );
rSh.SetShowHeaderFooterSeparator( FrameControlType::Footer, false );
}
// Toggle Hide-Whitespace if between pages. if (rSh.GetViewOptions()->CanHideWhitespace() &&
rSh.GetLayout()->IsBetweenPages(aDocPos))
{ if (_rMEvt.GetClicks() >= 2)
{
SwViewOption aOpt(*rSh.GetViewOptions());
aOpt.SetHideWhitespaceMode(!aOpt.IsHideWhitespaceMode());
rSh.ApplyViewOptions(aOpt);
}
if ( !rSh.IsTableMode() )
{ // comes from table columns out of the document. if(SwTab::COL_VERT == nMouseTabCol || SwTab::COL_HORI == nMouseTabCol)
m_rView.SetTabColFromDoc( true ); else
m_rView.SetTabRowFromDoc( true );
if (RulerMarginDrag(aMEvt, SwFEShell::IsVerticalModeAtNdAndPos(*pNodeAtPos, aDocPos)))
{
m_rView.SetNumRuleNodeFromDoc( nullptr );
m_rView.InvalidateRulerPos();
rBind.Update();
bCallBase = false;
} else
{ // Make sure the pointer is set to 0, otherwise it may point to // nowhere after deleting the corresponding text node.
m_rView.SetNumRuleNodeFromDoc( nullptr ); return;
}
}
if ( rSh.IsInSelect() )
rSh.EndSelect();
// query against LEFT because otherwise for example also a right // click releases the selection. if (MOUSE_LEFT == aMEvt.GetButtons())
{ bool bOnlyText = false;
m_bMBPressed = true;
g_bNoInterrupt = true;
m_nKS_NUMDOWN_Count = 0;
CaptureMouse();
// reset cursor position if applicable
rSh.ResetCursorStack();
switch (aMEvt.GetModifier() + aMEvt.GetButtons())
{ case MOUSE_LEFT: case MOUSE_LEFT + KEY_MOD1: case MOUSE_LEFT + KEY_MOD2:
{
// fdo#79604: first, check if a link has been clicked - do not // select fly in this case! if (1 == nNumberOfClicks)
{
UpdatePointer(aDocPos, aMEvt.GetModifier());
SwEditWin::s_nDDStartPosY = aDocPos.Y();
SwEditWin::s_nDDStartPosX = aDocPos.X();
// hit a URL in DrawText object? if (bExecHyperlinks && pSdrView)
{
SdrViewEvent aVEvt;
pSdrView->PickAnything(aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
bExecDrawTextLink = true;
}
}
if (1 == nNumberOfClicks && !bExecDrawTextLink)
{ // only try to select frame, if pointer already was // switched accordingly if ( m_aActHitType != SdrHitKind::NONE && !rSh.IsSelFrameMode() &&
!GetView().GetViewFrame().GetDispatcher()->IsLocked())
{ // Test if there is a draw object at that position and if it should be selected. bool bSelectFrameInsteadOfCroppedImage = false; bool bShould = rSh.ShouldObjectBeSelected(aDocPos, &bSelectFrameInsteadOfCroppedImage);
if( bSelObj )
{ // if the frame was deselected in the macro // the cursor just has to be displayed again if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
rSh.ShowCursor(); else
{ if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
{
m_rView.GetDrawFuncPtr()->Deactivate();
m_rView.SetDrawFuncPtr(nullptr);
m_rView.LeaveDrawCreate();
m_rView.AttrChangedNotify(nullptr);
}
if( !bSelObj )
{ // move cursor here so that it is not drawn in the // frame first; ShowCursor() happens in LeaveSelFrameMode()
g_bValidCursorPos = !(CRSR_POSCHG & rSh.CallSetCursor(&aDocPos, false));
rSh.LeaveSelFrameMode();
m_rView.AttrChangedNotify(nullptr);
bCallBase = false;
} else
{
rSh.HideCursor();
rSh.EnterSelFrameMode( &aDocPos );
rSh.SelFlyGrabCursor();
rSh.MakeSelVisible();
g_bFrameDrag = true; if( rSh.IsFrameSelected() &&
m_rView.GetDrawFuncPtr() )
{
m_rView.GetDrawFuncPtr()->Deactivate();
m_rView.SetDrawFuncPtr(nullptr);
m_rView.LeaveDrawCreate();
m_rView.AttrChangedNotify(nullptr);
}
UpdatePointer(aDocPos, aMEvt.GetModifier()); return;
}
}
}
}
switch ( nNumberOfClicks )
{ case 1: break; case 2:
{
g_bFrameDrag = false; if (!bIsViewReadOnly && rSh.IsInsideSelectedObj(aDocPos)
&& (FlyProtectFlags::NONE
== rSh.IsSelObjProtected(FlyProtectFlags::Content
| FlyProtectFlags::Parent)
|| rSh.GetSelectionType() == SelectionType::Ole))
{ /* This is no good: on the one hand GetSelectionType is used as flag field * (take a look into the GetSelectionType method) and on the other hand the * return value is used in a switch without proper masking (very nice), this must lead to trouble
*/ switch ( rSh.GetSelectionType() & ~SelectionType( SelectionType::FontWork | SelectionType::ExtrudedCustomShape ) )
{ case SelectionType::Graphic:
ResetMouseButtonDownFlags(); if (!comphelper::LibreOfficeKit::isActive())
{
GetView().GetViewFrame().GetBindings().Execute(
FN_FORMAT_GRAFIC_DLG, nullptr,
SfxCallMode::RECORD|SfxCallMode::SLOT);
} return;
// double click on OLE object --> OLE-InPlace case SelectionType::Ole:
ResetMouseButtonDownFlags();
rSh.LaunchOLEObj(); return;
case SelectionType::Frame:
ResetMouseButtonDownFlags(); if (!comphelper::LibreOfficeKit::isActive())
{
GetView().GetViewFrame().GetBindings().Execute(
FN_FORMAT_FRAME_DLG, nullptr,
SfxCallMode::RECORD|SfxCallMode::SLOT);
} return;
case SelectionType::DrawObject:
ResetMouseButtonDownFlags();
EnterDrawTextMode(aDocPos); if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
pSwDrawTextShell->Init(); return;
default: break;
}
}
// if the cursor position was corrected or if a Fly // was selected in ReadOnlyMode, no word selection, except when tiled rendering. if ((!g_bValidCursorPos || rSh.IsFrameSelected()) && !comphelper::LibreOfficeKit::isActive()) return;
if( nullptr != pField ||
( bFootnote = rSh.GetCurFootnote() ))
{ if (!bIsViewReadOnly)
{
ResetMouseButtonDownFlags(); if( bFootnote )
GetView().GetViewFrame().GetBindings().Execute( FN_EDIT_FOOTNOTE ); else
{
SwFieldTypesEnum nTypeId = pField->GetTypeId();
SfxViewFrame& rVFrame = GetView().GetViewFrame(); switch( nTypeId )
{ case SwFieldTypesEnum::Postit: case SwFieldTypesEnum::Script:
{ // if it's a Readonly region, status has to be enabled
sal_uInt16 nSlot = SwFieldTypesEnum::Postit == nTypeId ? FN_POSTIT : FN_JAVAEDIT;
SfxBoolItem aItem(nSlot, true);
rVFrame.GetBindings().SetState(aItem);
rVFrame.GetBindings().Execute(nSlot); break;
} case SwFieldTypesEnum::Authority :
rVFrame.GetBindings().Execute(FN_EDIT_AUTH_ENTRY_DLG); break; case SwFieldTypesEnum::Input: case SwFieldTypesEnum::Dropdown: case SwFieldTypesEnum::SetInput:
rVFrame.GetBindings().Execute(FN_UPDATE_INPUTFIELDS); break; default:
rVFrame.GetBindings().Execute(FN_EDIT_FIELD);
}
} return;
} elseif (pField && pField->ExpandField(true, nullptr).getLength())
{
ResetMouseButtonDownFlags();
GetView().GetViewFrame().GetBindings().Execute(FN_COPY_FIELD);
}
} // in extended mode double and triple // click has no effect. if ( rSh.IsExtMode() || rSh.IsBlockMode() ) return;
// select word, AdditionalMode if applicable if (KEY_MOD1 == aMEvt.GetModifier() && !rSh.IsAddMode())
{
rSh.EnterAddMode();
rSh.SelWrd( &aDocPos );
rSh.LeaveAddMode();
} else
{ if (!rSh.SelWrd(&aDocPos) && comphelper::LibreOfficeKit::isActive()) // Double click did not select any word: try to // select the current cell in case we are in a // table.
rSh.SelTableBox();
}
g_bHoldSelection = true; return;
} case 3: case 4:
{
g_bFrameDrag = false; // in extended mode double and triple // click has no effect. if ( rSh.IsExtMode() ) return;
// if the cursor position was corrected or if a Fly // was selected in ReadOnlyMode, no word selection. if ( !g_bValidCursorPos || rSh.IsFrameSelected() ) return;
// Are we clicking on a field? if (rSh.GetContentAtPos(aDocPos, aFieldAtPos))
{ bool bEditableField = (aFieldAtPos.pFndTextAttr != nullptr
&& aFieldAtPos.pFndTextAttr->Which() == RES_TXTATR_INPUTFIELD);
if (!bEditableField)
{
rSh.CallSetCursor(&aDocPos, bOnlyText); // Unfortunately the cursor may be on field // position or on position after field depending on which // half of the field was clicked on.
SwTextAttr const*const pTextField(aFieldAtPos.pFndTextAttr); if (pTextField &&
rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() != pTextField->GetStart())
{
assert(rSh.GetCurrentShellCursor().GetPoint()->GetContentIndex() == (pTextField->GetStart() + 1));
rSh.Left( SwCursorSkipMode::Chars, false, 1, false );
} // don't go into the !bOverSelect block below - it moves // the cursor break;
} else
{
bEditableFieldClicked = true;
}
}
if ( !bOverSelect || rSh.IsInSelect() )
{
MoveCursor( rSh, aDocPos, bOnlyText, bLockView);
bCallBase = false;
} if (!bOverURLGrf && !bExecDrawTextLink && !bOnlyText)
{ const SelectionType nSelType = rSh.GetSelectionType(); // Check in general, if an object is selectable at given position. // Thus, also text fly frames in background become selectable via Ctrl-Click. if ( ( nSelType & SelectionType::Ole ||
nSelType & SelectionType::Graphic ||
rSh.IsObjSelectable( aDocPos ) ) && !lcl_urlOverBackground( rSh, aDocPos ) )
{
SwMvContext aMvContext( &rSh );
rSh.EnterSelFrameMode();
bCallBase = false;
}
} if ( !bOverSelect && bEditableFieldClicked && (!pCursorField ||
pCursorField != aFieldAtPos.pFndTextAttr->GetFormatField().GetField()))
{ // select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART // and CH_TXT_ATR_INPUTFIELDEND
rSh.SttSelect();
rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
*(aFieldAtPos.pFndTextAttr->End()) - 1 );
} // don't reset here any longer so that, in case through MouseMove // with pressed Ctrl key a multiple-selection should happen, // the previous selection is not released in Drag. break;
}
}
} elseif (MOUSE_RIGHT == aMEvt.GetButtons())
{ // If right-click while dragging to resize the comment width, stop resizing if (mbIsDragSidebar)
{
ReleaseCommentGuideLine();
ReleaseMouse(); return;
}
// as long as an action is running the MouseMove should be disconnected // otherwise bug 40102 occurs
SwWrtShell &rSh = m_rView.GetWrtShell(); if( rSh.ActionPend() ) return ;
if (rSh.GetViewOptions()->IsShowOutlineContentVisibilityButton())
{ // add/remove outline content hide button const SwNodes& rNds = rSh.GetDoc()->GetNodes();
SwOutlineNodes::size_type nPos;
SwContentAtPos aSwContentAtPos(IsAttrAtPos::Outline); if (rSh.GetContentAtPos(PixelToLogic(rMEvt.GetPosPixel()), aSwContentAtPos))
{ // mouse pointer is on an outline paragraph node if(aSwContentAtPos.aFnd.pNode && aSwContentAtPos.aFnd.pNode->IsTextNode())
{ // Get the outline paragraph frame and compare it to the saved outline frame. If they // are not the same, remove the fold button from the saved outline frame, if not // already removed, and then add a fold button to the mouse over outline frame if // the content is not folded.
SwContentFrame* pContentFrame =
aSwContentAtPos.aFnd.pNode->GetTextNode()->getLayoutFrame(rSh.GetLayout()); if (pContentFrame != m_pSavedOutlineFrame)
{ if (m_pSavedOutlineFrame)
{ if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
{
SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst(); if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
rSh.GetAttrOutlineContentVisible(nPos))
{
GetFrameControlsManager().RemoveControlsByType(
FrameControlType::Outline, m_pSavedOutlineFrame);
}
}
}
m_pSavedOutlineFrame = static_cast<SwTextFrame*>(pContentFrame);
} // show fold button if outline content is visible if (rNds.GetOutLineNds().Seek_Entry(aSwContentAtPos.aFnd.pNode->GetTextNode(), &nPos) &&
rSh.GetAttrOutlineContentVisible(nPos))
GetFrameControlsManager().SetOutlineContentVisibilityButton(pContentFrame);
}
} elseif (m_pSavedOutlineFrame)
{ // The saved frame may not still be in the document, e.g., when an outline paragraph // is deleted. This causes the call to GetTextNodeFirst to behave badly. Use // isFrameAreaDefinitionValid to check if the frame is still in the document. if (m_pSavedOutlineFrame->isFrameAreaDefinitionValid())
{ // current pointer pos is not over an outline frame // previous pointer pos was over an outline frame // remove outline content visibility button if showing
SwTextNode* pTextNode = m_pSavedOutlineFrame->GetTextNodeFirst(); if (pTextNode && rNds.GetOutLineNds().Seek_Entry(pTextNode, &nPos) &&
rSh.GetAttrOutlineContentVisible(nPos))
{
GetFrameControlsManager().RemoveControlsByType(
FrameControlType::Outline, m_pSavedOutlineFrame);
}
}
m_pSavedOutlineFrame = nullptr;
}
}
//aPixPt == Point in Pixel, relative to ChildWin //aDocPt == Point in Twips, document coordinates const Point aPixPt( rMEvt.GetPosPixel() ); const Point aDocPt( PixelToLogic( aPixPt ) );
// position is necessary for OS/2 because obviously after a MB-Down // a MB-Move is called immediately. if( g_bDDTimerStarted )
{
Point aDD( SwEditWin::s_nDDStartPosX, SwEditWin::s_nDDStartPosY );
aDD = LogicToPixel( aDD );
tools::Rectangle aRect( aDD.X()-3, aDD.Y()-3, aDD.X()+3, aDD.Y()+3 ); if ( !aRect.Contains( aPixPt ) )
StopDDTimer( &rSh, aDocPt );
}
// determine if we only change the mouse pointer and return if (!bIsViewReadOnly && bInsWin && !m_pApplyTempl && !rSh.IsInSelect() && changeMousePointer(aDocPt))
{ return;
}
bool bDelShadCursor = true;
switch ( rMEvt.GetModifier() + rMEvt.GetButtons() )
{ case MOUSE_LEFT: if( m_pAnchorMarker )
{ // Now we need to refresh the SdrHdl pointer of m_pAnchorMarker. // This looks a little bit tricky, but it solves the following // problem: the m_pAnchorMarker contains a pointer to an SdrHdl, // if the FindAnchorPos-call cause a scrolling of the visible // area, it's possible that the SdrHdl will be destroyed and a // new one will initialized at the original position(GetHdlPos). // So the m_pAnchorMarker has to find the right SdrHdl, if it's // the old one, it will find it with position aOld, if this one // is destroyed, it will find a new one at position GetHdlPos().
if (pSdrView)
{ // Resize proportionally when media is selected and the user drags on a corner const Point aSttPt(PixelToLogic(m_aStartPos));
SdrHdl* pHdl = pSdrView->PickHandle(aSttPt); if (pHdl)
bResizeKeepRatio = bResizeKeepRatio && pHdl->IsCornerHdl();
if (pSdrView->GetDragMode() == SdrDragMode::Crop)
bisResize = false; if (rMEvt.IsShift())
{
pSdrView->SetAngleSnapEnabled(!bResizeKeepRatio); if (bisResize)
pSdrView->SetOrtho(!bResizeKeepRatio); else
pSdrView->SetOrtho(true);
} else
{
pSdrView->SetAngleSnapEnabled(bResizeKeepRatio); if (bisResize)
pSdrView->SetOrtho(bResizeKeepRatio); else
pSdrView->SetOrtho(false);
}
}
// should be over an InternetField with an // embedded macro? if( m_aSaveCallEvent != aLastCallEvent )
{ if( aLastCallEvent.HasEvent() )
rSh.CallEvent( SvMacroItemId::OnMouseOut,
aLastCallEvent, true ); // 0 says that the object doesn't have any table if( !rSh.CallEvent( SvMacroItemId::OnMouseOver,
m_aSaveCallEvent ))
m_aSaveCallEvent.Clear();
}
} elseif( aLastCallEvent.HasEvent() )
{ // cursor was on an object
rSh.CallEvent( SvMacroItemId::OnMouseOut,
aLastCallEvent, true );
}
/** * Button Up
*/ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt)
{ if (comphelper::LibreOfficeKit::isActive())
{ if (vcl::Window* pWindow = m_rView.GetPostItMgr()->IsHitSidebarWindow(rMEvt.GetPosPixel()))
{
pWindow->MouseButtonUp(rMEvt); return;
}
}
if (mbIsDragSidebar)
{
SetSidebarWidth(rMEvt.GetPosPixel()); // While dragging the mouse is captured, so we need to release it here
ReleaseMouse();
ReleaseCommentGuideLine(); return;
}
SwWrtShell &rSh = m_rView.GetWrtShell();
CurrShell aCurr( &rSh );
SdrView *pSdrView = rSh.GetDrawView(); if ( pSdrView )
{ // tdf34555: ortho was always reset before being used in EndSdrDrag // Now, it is reset only if not in Crop mode. if (pSdrView->GetDragMode() != SdrDragMode::Crop && !rMEvt.IsShift())
pSdrView->SetOrtho(false);
if ( pSdrView->MouseButtonUp( rMEvt,GetOutDev() ) )
{
rSh.GetView().GetViewFrame().GetBindings().InvalidateAll(false); return; // SdrView's event evaluated
}
} // only process MouseButtonUp when the Down went to that windows as well. if ( !m_bMBPressed )
{ // Undo for the watering can is already in CommandHdl // that's the way it should be!
return;
}
Point aDocPt( PixelToLogic( rMEvt.GetPosPixel() ) );
if ( g_bDDTimerStarted )
{
StopDDTimer( &rSh, aDocPt );
m_bMBPressed = false; if ( rSh.IsSelFrameMode() )
{
rSh.EndDrag( &aDocPt, false );
g_bFrameDrag = false;
}
g_bNoInterrupt = false; const Point aDocPos( PixelToLogic( rMEvt.GetPosPixel() ) ); if ((PixelToLogic(m_aStartPos).Y() == (aDocPos.Y())) && (PixelToLogic(m_aStartPos).X() == (aDocPos.X())))//To make sure it was not moved
{
SdrPageView* pPV = nullptr;
SdrObject* pObj = pSdrView ? pSdrView->PickObj(aDocPos, pSdrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr; if (pObj)
{ if (SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)))
{
SwFrameFormat* pFormat = pContact->GetFormat();
SwFrameFormat* pShapeFormat
= SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT); if (!pShapeFormat)
{
pSdrView->UnmarkAllObj();
pSdrView->MarkObj(pObj, pPV); if (rMEvt.IsLeft() && rMEvt.GetClicks() == 1 &&
SwModule::get()->GetUsrPref( dynamic_cast<const SwWebView*>(&m_rView) != nullptr)->
IsClickChangeRotation())
m_rView.ToggleRotate();
} else
{ // If the fly frame is a textbox of a shape, then select the shape instead.
SdrObject* pShape = pShapeFormat->FindSdrObject();
pSdrView->UnmarkAllObj();
pSdrView->MarkObj(pShape, pPV);
}
}
}
}
ReleaseMouse(); return;
}
Point aPnt( m_pAnchorMarker->GetLastPos() );
m_pAnchorMarker.reset(); if( aPnt.X() || aPnt.Y() )
rSh.FindAnchorPos( aPnt, true );
} if ( m_bInsDraw && m_rView.GetDrawFuncPtr() )
{ if ( m_rView.GetDrawFuncPtr()->MouseButtonUp( rMEvt ) )
{ if (m_rView.GetDrawFuncPtr()) // could have been destroyed in MouseButtonUp
{
m_rView.GetDrawFuncPtr()->Deactivate();
if( rSh.GetContentAtPos( aDocPt, aContentAtPos ) )
{ // Do it again if we're not on a field/hyperlink to update the cursor accordingly if ( IsAttrAtPos::Field != aContentAtPos.eContentAtPos
&& IsAttrAtPos::InetAttr != aContentAtPos.eContentAtPos )
rSh.GetContentAtPos( aDocPt, aContentAtPos, true );
// reset pushed mode in Down again if applicable if ( bPopMode && g_bModePushed )
{
rSh.PopMode();
g_bModePushed = false;
bCallBase = false;
} break;
default:
ReleaseMouse(); return;
}
if( m_pApplyTempl )
{
SelectionType eSelection = rSh.GetSelectionType();
SwFormatClipboard* pFormatClipboard = m_pApplyTempl->m_pFormatClipboard; if( pFormatClipboard )//apply format paintbrush
{ //get some parameters
SwWrtShell& rWrtShell = m_rView.GetWrtShell();
SfxStyleSheetBasePool* pPool=nullptr; bool bNoCharacterFormats = false; // Paste paragraph properties if the selection contains a whole paragraph or // there was no selection at all (i.e. just a left click) bool bNoParagraphFormats = rSh.HasSelection() && rSh.IsSelOnePara() && !rSh.IsSelFullPara();
}
ReleaseMouse(); // Only processed MouseEvents arrive here; only at these this mode can // be reset.
m_bMBPressed = false;
// Make this call just to be sure. Selecting has finished surely by now. // Otherwise the timeout's timer could give problems.
EnterArea();
g_bNoInterrupt = false;
if (bCallBase)
Window::MouseButtonUp(rMEvt);
// tdf#161717 - Track changes: Clicking on change in document should highlight related change // in "Manage Changes" window/sidebar if (m_rView.GetWrtShell().GetCurrRedline())
{
SwDocShell* pDocSh = m_rView.GetDocShell(); if (pDocSh)
pDocSh->Broadcast(SfxHint(SfxHintId::SwRedlineContentAtPos));
}
if (!(pSdrView && rMEvt.GetClicks() == 1 && comphelper::LibreOfficeKit::isActive())) return;
// When tiled rendering, single click on a shape text starts editing already.
SdrViewEvent aViewEvent;
SdrHitKind eHit = pSdrView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aViewEvent); const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); if (eHit == SdrHitKind::TextEditObj && rMarkList.GetMarkCount() == 1)
{ if (SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj())
{
EnterDrawTextMode(pObj->GetLogicRect().Center()); if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
pSwDrawTextShell->Init();
}
}
}
// TemplatePointer for colors should be reset without // selection after single click, but not after double-click (tdf#122442)
m_aTemplateTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
m_aTemplateTimer.SetInvokeHandler(LINK(this, SwEditWin, TemplateTimerHdl));
// temporary solution!!! Should set the font of the current // insert position at every cursor movement! if( !rMyView.GetDocShell()->IsReadOnly() )
{
SetInputContext( InputContext(vcl::Font(), InputContextFlags::Text |
InputContextFlags::ExtText ) );
}
}
void SwEditWin::Command( const CommandEvent& rCEvt )
{ if (isDisposed())
{ // If ViewFrame dies shortly, no popup anymore!
Window::Command(rCEvt); return;
}
SwWrtShell &rSh = m_rView.GetWrtShell();
// The command event is send to the window after a possible context // menu from an inplace client has been closed. Now we have the chance // to deactivate the inplace client without any problem regarding parent // windows and code on the stack.
SfxInPlaceClient* pIPClient = rSh.GetSfxViewShell()->GetIPClient(); bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() ); if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu ))
{
rSh.FinishOLEObj(); return;
}
bool bCallBase = true;
switch ( rCEvt.GetCommand() )
{ case CommandEventId::ContextMenu:
{ const sal_uInt16 nId = SwInputChild::GetChildWindowId();
SwInputChild* pChildWin = static_cast<SwInputChild*>(GetView().GetViewFrame().
GetChildWindow( nId ));
if (m_rView.GetPostItMgr()->IsHit(rCEvt.GetMousePosPixel())) return;
Point aDocPos( PixelToLogic( rCEvt.GetMousePosPixel() ) ); if ( !rCEvt.IsMouseEvent() )
aDocPos = rSh.GetCharRect().Center();
// Don't trigger the command on a frame anchored to header/footer is not editing it
FrameControlType eControl; bool bOverFly = false; bool bPageAnchored = false; bool bOverHeaderFooterFly = IsOverHeaderFooterFly( aDocPos, eControl, bOverFly, bPageAnchored ); // !bOverHeaderFooterFly doesn't mean we have a frame to select if ( !bPageAnchored && rCEvt.IsMouseEvent( ) &&
( ( rSh.IsHeaderFooterEdit( ) && !bOverHeaderFooterFly && bOverFly ) ||
( !rSh.IsHeaderFooterEdit( ) && bOverHeaderFooterFly ) ) )
{ return;
}
if ( !sRecord.isEmpty() )
{ // convert quotes in IME text // works on the last input character, this is especially in Korean text often done // quotes that are inside of the string are not replaced! const sal_Unicode aCh = sRecord[sRecord.getLength() - 1];
SvxAutoCorrCfg& rACfg = SvxAutoCorrCfg::Get();
SvxAutoCorrect* pACorr = rACfg.GetAutoCorrect(); if(pACorr &&
(( pACorr->IsAutoCorrFlag( ACFlags::ChgQuotes ) && ('\"' == aCh ))||
( pACorr->IsAutoCorrFlag( ACFlags::ChgSglQuotes ) && ( '\'' == aCh))))
{
rSh.DelLeft();
rSh.AutoCorrect( *pACorr, aCh );
}
if ( xRecorder.is() )
{ // determine Shell
SfxShell *pSfxShell = lcl_GetTextShellFromDispatcher( m_rView ); // generate request and record if (pSfxShell)
{
SfxRequest aReq(m_rView.GetViewFrame(), FN_INSERT_STRING);
aReq.AppendItem( SfxStringItem( FN_INSERT_STRING, sRecord ) );
aReq.Done();
}
}
}
}
}
} break; case CommandEventId::ExtTextInput:
{ bool bIsViewReadOnly = IsViewReadonly();
if (rSh.HasReadonlySel())
{ // Inform the user that the request has been ignored.
rSh.InfoReadOnlyDialog(true);
}
} break; case CommandEventId::CursorPos: // will be handled by the base class break;
/* i#18686 select the object/cursor at the mouse
position of the context menu request */ void SwEditWin::SelectMenuPosition(SwWrtShell& rSh, const Point& rMousePos )
{ const Point aDocPos( PixelToLogic( rMousePos ) ); constbool bIsInsideSelectedObj( rSh.IsInsideSelectedObj( aDocPos ) ); //create a synthetic mouse event out of the coordinates
MouseEvent aMEvt(rMousePos);
SdrView *pSdrView = rSh.GetDrawView(); if ( pSdrView )
{ // no close of insert_draw and reset of // draw mode, if context menu position is inside a selected object. if ( !bIsInsideSelectedObj && m_rView.GetDrawFuncPtr() )
{
// if draw text is active and there's a text selection // at the mouse position then do nothing if(rSh.GetSelectionType() & SelectionType::DrawObjectEditMode)
{
OutlinerView* pOLV = pSdrView->GetTextEditOutlinerView();
ESelection aSelection = pOLV->GetSelection(); if(aSelection != ESelection())
{
SdrOutliner* pOutliner = pSdrView->GetTextEditOutliner(); bool bVertical = pOutliner->IsVertical(); const EditEngine& rEditEng = pOutliner->GetEditEngine();
Point aEEPos(aDocPos); const tools::Rectangle& rOutputArea = pOLV->GetOutputArea(); // regard vertical mode if(bVertical)
{
aEEPos -= rOutputArea.TopRight(); //invert the horizontal direction and exchange X and Y
tools::Long nTemp = -aEEPos.X();
aEEPos.setX( aEEPos.Y() );
aEEPos.setY( nTemp );
} else
aEEPos -= rOutputArea.TopLeft();
ESelection aCompare(rEditEng.FindDocPosition(aEEPos)); // make it a forward selection - otherwise the IsLess/IsGreater do not work :-(
aSelection.Adjust(); if(!(aCompare < aSelection) && !(aCompare > aSelection))
{ return;
}
}
if ( EnterDrawMode( aMEvt, aDocPos ) )
{ return;
} if ( m_rView.GetDrawFuncPtr() && m_bInsFrame )
{
StopInsFrame();
rSh.Edit();
}
UpdatePointer( aDocPos );
if( !rSh.IsSelFrameMode() &&
!GetView().GetViewFrame().GetDispatcher()->IsLocked() )
{ // Test if there is a draw object at that position and if it should be selected. bool bShould = rSh.ShouldObjectBeSelected(aDocPos);
if( bSelObj )
{ // in case the frame was deselected in the macro // just the cursor has to be displayed again. if( FrameTypeFlags::NONE == rSh.GetSelFrameType() )
rSh.ShowCursor(); else
{ if (rSh.IsFrameSelected() && m_rView.GetDrawFuncPtr())
{
m_rView.GetDrawFuncPtr()->Deactivate();
m_rView.SetDrawFuncPtr(nullptr);
m_rView.LeaveDrawCreate();
m_rView.AttrChangedNotify(nullptr);
}
if ( !bOverSelect )
{ // create only temporary move context because otherwise // the query against the content form doesn't work!!!
SwMvContext aMvContext( &rSh ); if (rSh.HasSelection())
rSh.ResetSelect(&aDocPos, false, ScrollSizeMode::ScrollSizeDefault);
rSh.SwCursorShell::SetCursor(aDocPos, false, /*Block=*/false, /*FieldInfo=*/true);
} if( !bOverURLGrf )
{ const SelectionType nSelType = rSh.GetSelectionType(); if( nSelType == SelectionType::Ole ||
nSelType == SelectionType::Graphic )
{
SwMvContext aMvContext( &rSh ); if( !rSh.IsFrameSelected() )
rSh.GotoNextFly();
rSh.EnterSelFrameMode();
}
}
}
void SwEditWin::DrawCommentGuideLine(Point aPointPixel)
{ const Point aPointLogic = PixelToLogic(aPointPixel);
sw::sidebarwindows::SidebarPosition eSidebarPosition
= m_rView.GetPostItMgr()->GetSidebarPos(aPointLogic); if (eSidebarPosition == sw::sidebarwindows::SidebarPosition::NONE) // should never happen return;
// We need two InvertTracking calls here to "erase" the previous and draw the new position at each mouse move
InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split); const tools::Long nHeight = GetOutDev()->GetOutputSizePixel().Height();
aLastCommentSidebarPos
= tools::Rectangle(PixelToLogic(Point(nPosX, 0)), PixelToLogic(Point(nPosX, nHeight)));
InvertTracking(aLastCommentSidebarPos, ShowTrackFlags::Clip | ShowTrackFlags::Split);
}
void SwEditWin::SetSidebarWidth(const Point& rPointPixel)
{ if (aLastCommentSidebarPos.IsEmpty()) return; // aLastCommentSidebarPos right and left positions are the same so either can be used here
m_rView.GetPostItMgr()->SetSidebarWidth(
Point(aLastCommentSidebarPos.Right(), PixelToLogic(rPointPixel).Y()));
}
//fdo#33092. If the current input language is the default //language that text would appear in if typed, then don't //force a language on for the ExtTextInput.
LanguageType eInputLanguage = rWin.GetInputLanguage(); if (lcl_isNonDefaultLanguage(eInputLanguage,
rSh.GetView(), sStr) == INVALID_HINT)
{
eInputLanguage = LANGUAGE_DONTKNOW;
}
// Add matching calendar month and day names for ( constauto& aNames : { rCalendar.getMonths(), rCalendar.getDays() } )
{ for ( constauto& rName : aNames )
{ const OUString& rStr( rName.FullName ); // Check string longer than word and case insensitive match if( rStr.getLength() > rWord.getLength() &&
rCC.lowercase( rStr, 0, rWord.getLength() ) == sWordLower )
{
OUString sStr;
//fdo#61251 if it's an exact match, ensure unchanged replacement //exists as a candidate if (rStr.startsWith(rWord))
m_aHelpStrings.emplace_back(rStr, rWord.getLength()); else
sStr = rStr; // to be added if no case conversion is performed below
if (!sStr.isEmpty())
m_aHelpStrings.emplace_back(sStr, rWord.getLength());
}
}
}
// Add matching current date in ISO 8601 format, for example 2016-01-30
OUString rStrToday;
// do not suggest for single years, for example for "2016", // only for "201" or "2016-..." (to avoid unintentional text // insertion at line ending, for example typing "30 January 2016") if (!rWord.isEmpty() && rWord.getLength() != 4 && rWord[0] == '2')
{
rStrToday = utl::toISO8601(DateTime(Date(Date::SYSTEM)).GetUNODateTime()); if (rStrToday.startsWith(rWord))
m_aHelpStrings.emplace_back(rStrToday, rWord.getLength());
}
// Add matching words from AutoCompleteWord list const SwAutoCompleteWord& rACList = SwEditShell::GetAutoCompleteWords();
std::vector<OUString> strings;
if ( !rACList.GetWordsMatching( rWord, strings ) ) return;
for (const OUString & aCompletedString : strings)
{ // when we have a matching current date, avoid to suggest // other words with the same matching starting characters, // for example 2016-01-3 instead of 2016-01-30 if (!rStrToday.isEmpty() && aCompletedString.startsWith(rWord)) continue;
OUString sStr;
//fdo#61251 if it's an exact match, ensure unchanged replacement //exists as a candidate if (aCompletedString.startsWith(rWord))
m_aHelpStrings.emplace_back(aCompletedString, rWord.getLength()); else
sStr = aCompletedString; // to be added if no case conversion is performed below
// TODO Implement an i18n aware sort void QuickHelpData::SortAndFilter(const OUString &rOrigWord)
{
std::sort( m_aHelpStrings.begin(),
m_aHelpStrings.end(),
CompareIgnoreCaseAsciiFavorExact(rOrigWord) );
constauto it
= std::unique(m_aHelpStrings.begin(), m_aHelpStrings.end(), EqualIgnoreCaseAscii());
m_aHelpStrings.erase( it, m_aHelpStrings.end() );
nCurArrPos = 0;
}
// For a given chunk of typed text between 3 and 9 characters long that may start at a word boundary // or in a whitespace and may include whitespaces, SwEditShell::GetChunkForAutoTextcreates a list of // possible candidates for long AutoText names. Let's say, we have typed text "lorem ipsum dr f"; // and the cursor is right after the "f". SwEditShell::GetChunkForAutoText would take " dr f", // since it's the longest chunk to the left of the cursor no longer than 9 characters, not starting // in the middle of a word. Then it would create this list from it (in this order, longest first): // " dr f" // " dr f" // "dr f" // It cannot add "r f", because it starts in the middle of the word "dr"; also it cannot give " f", // because it's only 2 characters long. // Now the result of SwEditShell::GetChunkForAutoText is passed here to SwEditWin::ShowAutoText, and // then to SwGlossaryList::HasLongName, where all existing autotext entries' long names are tested // if they start with one of the list elements. The matches are sorted according the position of the // candidate that matched first, then alphabetically inside the group of suggestions for a given // candidate. Say, if we have these AutoText entry long names: // "Dr Frodo" // "Dr Credo" // "Or Bilbo" // "dr foo" // " Dr Fuzz" // " dr Faust" // the resulting list would be: // " Dr Fuzz" -> matches the first (longest) item in the candidates list // " dr Faust" -> matches the second candidate item // "Dr Foo" -> first item of the two matching the third candidate; alphabetically sorted // "Dr Frodo" -> second item of the two matching the third candidate; alphabetically sorted // Each of the resulting suggestions knows the length of the candidate it replaces, so accepting the // first suggestion would replace 6 characters before cursor, while tabbing to and accepting the // last suggestion would replace only 4 characters to the left of cursor. bool SwEditWin::ShowAutoText(const std::vector<OUString>& rChunkCandidates)
{
s_pQuickHlpData->ClearContent(); if (!rChunkCandidates.empty())
{
SwGlossaryList* pList = ::GetGlossaryList();
pList->HasLongName(rChunkCandidates, s_pQuickHlpData->m_aHelpStrings);
}
if (!s_pQuickHlpData->m_aHelpStrings.empty())
{
s_pQuickHlpData->Start(m_rView.GetWrtShell(), true);
} return !s_pQuickHlpData->m_aHelpStrings.empty();
}
// get the sentence around the cursor
rSh.HideCursor();
rSh.GoStartSentence();
rSh.SetMark();
rSh.GoEndSentence();
rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
if (bCreateSelection)
m_rView.GetWrtShell().SttSelect();
// If the mark is to be updated, then exchange the point and mark before // and after, as we can't easily set the mark. if (!bPoint)
rShell.getShellCursor(/*bBlock=*/false)->Exchange();
rShell.SetCursor(rPosition); if (!bPoint)
rShell.getShellCursor(/*bBlock=*/false)->Exchange();
}
if (bCreateSelection)
m_rView.GetWrtShell().EndSelect();
}
void SwEditWin::ToggleOutlineContentVisibility(const size_t nOutlinePos, constbool bSubs)
{ // bSubs purpose is to set all sub level outline content to the same visibility as // nOutlinePos outline content visibility is toggled. It is only applicable when not treating // sub outline levels as content.
SwWrtShell& rSh = GetView().GetWrtShell();
if (GetView().GetDrawView()->IsTextEdit())
rSh.EndTextEdit(); if (GetView().IsDrawMode())
GetView().LeaveDrawCreate();
rSh.EnterStdMode();
if (!bSubs || rSh.GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
{
SwNode* pNode = rSh.GetNodes().GetOutLineNds()[nOutlinePos]; bool bVisible = pNode->GetTextNode()->GetAttrOutlineContentVisible();
pNode->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
} elseif (bSubs)
{ // also toggle sub levels to the same content visibility
SwOutlineNodes::size_type nPos = nOutlinePos;
SwOutlineNodes::size_type nOutlineNodesCount
= rSh.getIDocumentOutlineNodesAccess()->getOutlineNodesCount(); int nLevel = rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nOutlinePos); bool bVisible = rSh.IsOutlineContentVisible(nOutlinePos); do
{ if (rSh.IsOutlineContentVisible(nPos) == bVisible)
rSh.GetNodes().GetOutLineNds()[nPos]->GetTextNode()->SetAttrOutlineContentVisible(!bVisible);
} while (++nPos < nOutlineNodesCount
&& rSh.getIDocumentOutlineNodesAccess()->getOutlineLevel(nPos) > nLevel);
}
¤ 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.0.266Bemerkung:
(vorverarbeitet am 2026-05-08)
¤
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.