1083 lines
29 KiB
C++
1083 lines
29 KiB
C++
/* -*- 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 .
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <hintids.hxx>
|
|
#include <sfx2/bindings.hxx>
|
|
#include <sfx2/viewfrm.hxx>
|
|
#include <svl/eitem.hxx>
|
|
#include <svl/macitem.hxx>
|
|
#include <unotools/charclass.hxx>
|
|
#include <sfx2/event.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <cmdid.h>
|
|
#include <view.hxx>
|
|
#include <basesh.hxx>
|
|
#include <wrtsh.hxx>
|
|
#include <frmatr.hxx>
|
|
#include <mdiexp.hxx>
|
|
#include <fmtcol.hxx>
|
|
#include <frmfmt.hxx>
|
|
#include <swdtflvr.hxx>
|
|
#include <doc.hxx>
|
|
#include <wordcountdialog.hxx>
|
|
#include <memory>
|
|
#include <vcl/uitest/logger.hxx>
|
|
#include <vcl/uitest/eventdescription.hxx>
|
|
|
|
#include <vcl/weld.hxx>
|
|
#include <vcl/builder.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <unotools/configmgr.hxx>
|
|
#include <bitmaps.hlst>
|
|
|
|
#include <svx/svdview.hxx>
|
|
|
|
namespace com::sun::star::util {
|
|
struct SearchOptions2;
|
|
}
|
|
|
|
using namespace ::com::sun::star::util;
|
|
|
|
static tools::Long nStartDragX = 0, nStartDragY = 0;
|
|
static bool bStartDrag = false;
|
|
|
|
void SwWrtShell::Invalidate()
|
|
{
|
|
// to avoid making the slot volatile, invalidate it every time if something could have been changed
|
|
// this is still much cheaper than asking for the state every 200 ms (and avoid background processing)
|
|
GetView().GetViewFrame().GetBindings().Invalidate( FN_STAT_SELMODE );
|
|
GetView().GetViewFrame().GetBindings().Update(FN_STAT_SELMODE); // make selection mode control icon update immediately
|
|
SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
|
|
if (pWrdCnt)
|
|
pWrdCnt->UpdateCounts();
|
|
}
|
|
|
|
bool SwWrtShell::SelNearestWrd()
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
if( !IsInWord() && !IsEndWrd() && !IsStartWord() )
|
|
PrvWrd();
|
|
if( IsEndWrd() )
|
|
Left(SwCursorSkipMode::Cells, false, 1, false );
|
|
return SelWrd();
|
|
}
|
|
|
|
bool SwWrtShell::SelWrd(const Point *pPt, sal_Int16 nWordType )
|
|
{
|
|
bool bRet;
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
SttSelect();
|
|
bRet = SwCursorShell::SelectWordWT( pPt, nWordType );
|
|
}
|
|
EndSelect();
|
|
if( bRet )
|
|
{
|
|
m_bSelWrd = true;
|
|
if(pPt)
|
|
m_aStart = *pPt;
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
void SwWrtShell::SelSentence(const Point *pPt )
|
|
{
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
ClearMark();
|
|
SwCursorShell::GoStartSentence();
|
|
SttSelect();
|
|
SwCursorShell::GoEndSentence();
|
|
}
|
|
EndSelect();
|
|
if(pPt)
|
|
m_aStart = *pPt;
|
|
m_bSelLn = true;
|
|
m_bSelWrd = false; // disable SelWord, otherwise no SelLine goes on
|
|
}
|
|
|
|
void SwWrtShell::SelPara(const Point *pPt )
|
|
{
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
ClearMark();
|
|
SwCursorShell::MovePara( GoCurrPara, fnParaStart );
|
|
SttSelect();
|
|
SwCursorShell::MovePara( GoCurrPara, fnParaEnd );
|
|
}
|
|
EndSelect();
|
|
if(pPt)
|
|
m_aStart = *pPt;
|
|
m_bSelLn = false;
|
|
m_bSelWrd = false; // disable SelWord, otherwise no SelLine goes on
|
|
}
|
|
|
|
void SwWrtShell::SelAll()
|
|
{
|
|
const bool bLockedView = IsViewLocked();
|
|
LockView( true );
|
|
{
|
|
if(m_bBlockMode)
|
|
LeaveBlockMode();
|
|
SwMvContext aMvContext(this);
|
|
bool bMoveTable = false;
|
|
std::optional<SwPosition> oStartPos;
|
|
std::optional<SwPosition> oEndPos;
|
|
SwShellCursor* pTmpCursor = nullptr;
|
|
|
|
// Query these early, before we move the cursor.
|
|
bool bHasWholeTabSelection = HasWholeTabSelection();
|
|
bool bIsCursorInTable = IsCursorInTable();
|
|
|
|
if (!bHasWholeTabSelection
|
|
&& ( !bIsCursorInTable
|
|
|| getShellCursor(false)->GetMarkNode().FindTableNode() == nullptr
|
|
|| !ExtendedSelectedAll())) // ESA inside table -> else branch
|
|
{
|
|
if ( IsSelection() && IsCursorPtAtEnd() )
|
|
SwapPam();
|
|
pTmpCursor = getShellCursor( false );
|
|
if( pTmpCursor )
|
|
{
|
|
oStartPos.emplace( *pTmpCursor->GetPoint() );
|
|
oEndPos.emplace( *pTmpCursor->GetMark() );
|
|
}
|
|
Push();
|
|
bool bIsFullSel = !MoveSection( GoCurrSection, fnSectionStart);
|
|
SwapPam();
|
|
bIsFullSel &= !MoveSection( GoCurrSection, fnSectionEnd);
|
|
Pop(SwCursorShell::PopMode::DeleteCurrent);
|
|
GoStart(true, &bMoveTable, false, !bIsFullSel);
|
|
SttSelect();
|
|
GoEnd(true, &bMoveTable);
|
|
}
|
|
else
|
|
{
|
|
if (MoveOutOfTable())
|
|
{ // select outer text
|
|
EnterStdMode(); // delete m_pTableCursor
|
|
// GoStart(true, &bMoveTable, false, true);
|
|
MoveSection(GoCurrSection, fnSectionStart); // don't move into prev table
|
|
SttSelect();
|
|
MoveSection(GoCurrSection, fnSectionEnd); // don't move to different cell
|
|
}
|
|
else
|
|
{
|
|
TrySelectOuterTable();
|
|
}
|
|
}
|
|
|
|
bool bNeedsExtendedSelectAll = StartsWith_() != StartsWith::None;
|
|
|
|
// the GoEnd() could have created a table selection, if so avoid ESA.
|
|
if (bNeedsExtendedSelectAll && bIsCursorInTable)
|
|
{
|
|
bNeedsExtendedSelectAll = !HasWholeTabSelection();
|
|
}
|
|
|
|
if (bNeedsExtendedSelectAll)
|
|
{
|
|
ExtendedSelectAll(/*bFootnotes =*/ false);
|
|
}
|
|
|
|
SwDoc *pDoc = GetDoc();
|
|
if ( pDoc )
|
|
{
|
|
pDoc->SetPrepareSelAll();
|
|
}
|
|
|
|
if( oStartPos )
|
|
{
|
|
pTmpCursor = getShellCursor( false );
|
|
if( pTmpCursor )
|
|
{
|
|
// Some special handling for sections (e.g. TOC) at the beginning of the document body
|
|
// to avoid the selection of the first section
|
|
// if the last selection was behind the first section or
|
|
// if the last selection was already the first section
|
|
// In this both cases we select to the end of document
|
|
if( ( *pTmpCursor->GetPoint() < *oEndPos ||
|
|
( *oStartPos == *pTmpCursor->GetMark() &&
|
|
*oEndPos == *pTmpCursor->GetPoint() ) ) && !bNeedsExtendedSelectAll)
|
|
SwCursorShell::SttEndDoc(false);
|
|
}
|
|
}
|
|
}
|
|
EndSelect();
|
|
LockView( bLockedView );
|
|
}
|
|
|
|
// Description: Text search
|
|
|
|
sal_Int32 SwWrtShell::SearchPattern( const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes,
|
|
SwDocPositions eStt, SwDocPositions eEnd,
|
|
FindRanges eFlags, bool bReplace )
|
|
{
|
|
// no enhancement of existing selections
|
|
if(!(eFlags & FindRanges::InSel))
|
|
ClearMark();
|
|
bool bCancel = false;
|
|
sal_Int32 nRet = Find_Text(rSearchOpt, bSearchInNotes, eStt, eEnd, bCancel, eFlags, bReplace);
|
|
if(bCancel)
|
|
{
|
|
Undo();
|
|
nRet = SAL_MAX_INT32;
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
// Description: search for templates
|
|
|
|
sal_Int32 SwWrtShell::SearchTempl( const OUString &rTempl,
|
|
SwDocPositions eStt, SwDocPositions eEnd,
|
|
FindRanges eFlags, const OUString* pReplTempl )
|
|
{
|
|
// no enhancement of existing selections
|
|
if(!(eFlags & FindRanges::InSel))
|
|
ClearMark();
|
|
SwTextFormatColl *pColl = GetParaStyle(rTempl, SwWrtShell::GETSTYLE_CREATESOME);
|
|
SwTextFormatColl *pReplaceColl = nullptr;
|
|
if( pReplTempl )
|
|
pReplaceColl = GetParaStyle(*pReplTempl, SwWrtShell::GETSTYLE_CREATESOME );
|
|
|
|
bool bCancel = false;
|
|
sal_Int32 nRet = FindFormat(pColl ? *pColl : GetDfltTextFormatColl(),
|
|
eStt,eEnd, bCancel, eFlags, pReplaceColl);
|
|
if(bCancel)
|
|
{
|
|
Undo();
|
|
nRet = SAL_MAX_INT32;
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
// search for attributes
|
|
|
|
sal_Int32 SwWrtShell::SearchAttr( const SfxItemSet& rFindSet, bool bNoColls,
|
|
SwDocPositions eStart, SwDocPositions eEnd,
|
|
FindRanges eFlags, const i18nutil::SearchOptions2* pSearchOpt,
|
|
const SfxItemSet* pReplaceSet )
|
|
{
|
|
// no enhancement of existing selections
|
|
if (!(eFlags & FindRanges::InSel))
|
|
ClearMark();
|
|
|
|
// Searching
|
|
bool bCancel = false;
|
|
sal_Int32 nRet = FindAttrs(rFindSet, bNoColls, eStart, eEnd, bCancel, eFlags, pSearchOpt, pReplaceSet);
|
|
|
|
if(bCancel)
|
|
{
|
|
Undo();
|
|
nRet = SAL_MAX_INT32;
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
// Selection modes
|
|
|
|
void SwWrtShell::PushMode()
|
|
{
|
|
m_pModeStack = new ModeStack( m_pModeStack, m_bIns, m_bExtMode, m_bAddMode, m_bBlockMode );
|
|
}
|
|
|
|
void SwWrtShell::PopMode()
|
|
{
|
|
if ( nullptr == m_pModeStack )
|
|
return;
|
|
|
|
if ( m_bExtMode && !m_pModeStack->bExt )
|
|
LeaveExtMode();
|
|
if ( m_bAddMode && !m_pModeStack->bAdd )
|
|
LeaveAddMode();
|
|
if ( m_bBlockMode && !m_pModeStack->bBlock )
|
|
LeaveBlockMode();
|
|
m_bIns = m_pModeStack->bIns;
|
|
|
|
m_pModeStack = std::move(m_pModeStack->pNext);
|
|
}
|
|
|
|
// Two methods for setting cursors: the first maps at the
|
|
// eponymous methods in the CursorShell, the second removes
|
|
// all selections at first.
|
|
|
|
tools::Long SwWrtShell::SetCursor(const Point *pPt, bool bTextOnly)
|
|
{
|
|
// Remove a possibly present selection at the position
|
|
// of the mouseclick
|
|
|
|
if(!IsInSelect() && TestCurrPam(*pPt)) {
|
|
ClearMark();
|
|
}
|
|
|
|
return SwCursorShell::SetCursor(*pPt, bTextOnly);
|
|
}
|
|
|
|
tools::Long SwWrtShell::SetCursorKillSel(const Point *pPt, bool bTextOnly )
|
|
{
|
|
SwActContext aActContext(this);
|
|
ResetSelect(pPt,false);
|
|
return SwCursorShell::SetCursor(*pPt, bTextOnly);
|
|
}
|
|
|
|
void SwWrtShell::UnSelectFrame()
|
|
{
|
|
// Remove Frame selection with guaranteed invalid position
|
|
Point aPt(LONG_MIN, LONG_MIN);
|
|
SelectObj(aPt);
|
|
SwTransferable::ClearSelection( *this );
|
|
}
|
|
|
|
// Remove of all selections
|
|
|
|
tools::Long SwWrtShell::ResetSelect(const Point *,bool)
|
|
{
|
|
if(IsSelFrameMode())
|
|
{
|
|
UnSelectFrame();
|
|
LeaveSelFrameMode();
|
|
}
|
|
else
|
|
{
|
|
// SwActContext opens an Action -
|
|
// to avoid problems in the basic process with the
|
|
// shell switching, GetChgLnk().Call() may be called
|
|
// after EndAction().
|
|
{
|
|
SwActContext aActContext(this);
|
|
m_bSelWrd = m_bSelLn = false;
|
|
KillPams();
|
|
ClearMark();
|
|
m_fnKillSel = &SwWrtShell::Ignore;
|
|
m_fnSetCursor = &SwWrtShell::SetCursor;
|
|
}
|
|
|
|
// After canceling of all selections an update of Attr-Controls
|
|
// could be necessary.
|
|
GetChgLnk().Call(nullptr);
|
|
|
|
if ( GetEnhancedTableSelection() != SwTable::SEARCH_NONE )
|
|
UnsetEnhancedTableSelection();
|
|
}
|
|
Invalidate();
|
|
SwTransferable::ClearSelection( *this );
|
|
return 1;
|
|
}
|
|
|
|
bool SwWrtShell::IsSplitVerticalByDefault() const
|
|
{
|
|
return GetDoc()->IsSplitVerticalByDefault();
|
|
}
|
|
|
|
void SwWrtShell::SetSplitVerticalByDefault(bool value)
|
|
{
|
|
GetDoc()->SetSplitVerticalByDefault(value);
|
|
}
|
|
|
|
// Do nothing
|
|
|
|
tools::Long SwWrtShell::Ignore(const Point *, bool ) {
|
|
return 1;
|
|
}
|
|
|
|
// Begin of a selection process.
|
|
|
|
void SwWrtShell::SttSelect()
|
|
{
|
|
if(m_bInSelect)
|
|
return;
|
|
if(!HasMark())
|
|
SetMark();
|
|
if( m_bBlockMode )
|
|
{
|
|
SwShellCursor* pTmp = getShellCursor( true );
|
|
if( !pTmp->HasMark() )
|
|
pTmp->SetMark();
|
|
}
|
|
m_fnKillSel = &SwWrtShell::Ignore;
|
|
m_fnSetCursor = &SwWrtShell::SetCursor;
|
|
m_bInSelect = true;
|
|
Invalidate();
|
|
SwTransferable::CreateSelection( *this );
|
|
}
|
|
|
|
namespace {
|
|
|
|
void collectUIInformation(SwShellCursor* pCursor)
|
|
{
|
|
EventDescription aDescription;
|
|
OUString aSelStart = OUString::number(pCursor->Start()->GetContentIndex());
|
|
OUString aSelEnd = OUString::number(pCursor->End()->GetContentIndex());
|
|
|
|
aDescription.aParameters = {{"START_POS", aSelStart}, {"END_POS", aSelEnd}};
|
|
aDescription.aAction = "SELECT";
|
|
aDescription.aID = "writer_edit";
|
|
aDescription.aKeyWord = "SwEditWinUIObject";
|
|
aDescription.aParent = "MainWindow";
|
|
|
|
UITestLogger::getInstance().logEvent(aDescription);
|
|
}
|
|
|
|
}
|
|
|
|
// End of a selection process.
|
|
|
|
void SwWrtShell::EndSelect()
|
|
{
|
|
if(m_bInSelect && !m_bExtMode)
|
|
{
|
|
m_bInSelect = false;
|
|
if (m_bAddMode)
|
|
{
|
|
AddLeaveSelect();
|
|
}
|
|
else
|
|
{
|
|
SttLeaveSelect();
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
}
|
|
}
|
|
SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
|
|
if (pWrdCnt)
|
|
pWrdCnt->UpdateCounts();
|
|
|
|
collectUIInformation(GetCursor_());
|
|
}
|
|
|
|
void SwWrtShell::ExtSelWrd(const Point *pPt, bool )
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
if( IsTableMode() )
|
|
return;
|
|
|
|
// Bug 66823: actual crsr has in additional mode no selection?
|
|
// Then destroy the actual and go to prev, this will be expand
|
|
if( !HasMark() && GoPrevCursor() )
|
|
{
|
|
bool bHasMark = HasMark(); // that's wrong!
|
|
GoNextCursor();
|
|
if( bHasMark )
|
|
{
|
|
DestroyCursor();
|
|
GoPrevCursor();
|
|
}
|
|
}
|
|
|
|
// check the direction of the selection with the new point
|
|
bool bMoveCursor = true, bToTop = false;
|
|
SwCursorShell::SelectWord( &m_aStart ); // select the startword
|
|
SwCursorShell::Push(); // save the cursor
|
|
SwCursorShell::SetCursor( *pPt ); // and check the direction
|
|
|
|
switch( SwCursorShell::CompareCursorStackMkCurrPt())
|
|
{
|
|
case -1: bToTop = false; break;
|
|
case 1: bToTop = true; break;
|
|
default: bMoveCursor = false; break;
|
|
}
|
|
|
|
SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent); // restore the saved cursor
|
|
|
|
if( !bMoveCursor )
|
|
return;
|
|
|
|
// select to Top but cursor select to Bottom? or
|
|
// select to Bottom but cursor select to Top? --> swap the cursor
|
|
if( bToTop )
|
|
SwapPam();
|
|
|
|
SwCursorShell::Push(); // save cur cursor
|
|
if( SwCursorShell::SelectWord( pPt )) // select the current word
|
|
{
|
|
if( bToTop )
|
|
SwapPam();
|
|
Combine();
|
|
}
|
|
else
|
|
{
|
|
SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
|
|
if( bToTop )
|
|
SwapPam();
|
|
}
|
|
}
|
|
|
|
void SwWrtShell::ExtSelLn(const Point *pPt, bool )
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
SwCursorShell::SetCursor(*pPt);
|
|
if( IsTableMode() )
|
|
return;
|
|
|
|
// Bug 66823: actual crsr has in additional mode no selection?
|
|
// Then destroy the actual and go to prev, this will be expand
|
|
if( !HasMark() && GoPrevCursor() )
|
|
{
|
|
bool bHasMark = HasMark(); // that's wrong!
|
|
GoNextCursor();
|
|
if( bHasMark )
|
|
{
|
|
DestroyCursor();
|
|
GoPrevCursor();
|
|
}
|
|
}
|
|
|
|
// if applicable fit the selection to the "Mark"
|
|
bool bToTop = !IsCursorPtAtEnd();
|
|
SwapPam();
|
|
|
|
// The "Mark" has to be at the end or the beginning of the line.
|
|
if( bToTop ? !IsEndSentence() : !IsStartSentence() )
|
|
{
|
|
if( bToTop )
|
|
{
|
|
if( !IsEndPara() )
|
|
SwCursorShell::Right(1,SwCursorSkipMode::Chars);
|
|
SwCursorShell::GoEndSentence();
|
|
}
|
|
else
|
|
SwCursorShell::GoStartSentence();
|
|
}
|
|
SwapPam();
|
|
|
|
if (bToTop)
|
|
SwCursorShell::GoStartSentence();
|
|
else
|
|
SwCursorShell::GoEndSentence();
|
|
}
|
|
|
|
// Back into the standard mode: no mode, no selections.
|
|
|
|
void SwWrtShell::EnterStdMode()
|
|
{
|
|
if(m_bAddMode)
|
|
LeaveAddMode();
|
|
if(m_bBlockMode)
|
|
LeaveBlockMode();
|
|
m_bBlockMode = false;
|
|
m_bExtMode = false;
|
|
m_bInSelect = false;
|
|
if(IsSelFrameMode())
|
|
{
|
|
UnSelectFrame();
|
|
LeaveSelFrameMode();
|
|
}
|
|
else
|
|
{
|
|
// SwActContext opens and action which has to be
|
|
// closed prior to the call of
|
|
// GetChgLnk().Call()
|
|
SwActContext aActContext(this);
|
|
m_bSelWrd = m_bSelLn = false;
|
|
if( !IsRetainSelection() )
|
|
KillPams();
|
|
ClearMark();
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
}
|
|
Invalidate();
|
|
SwTransferable::ClearSelection( *this );
|
|
}
|
|
|
|
void SwWrtShell::AssureStdMode()
|
|
{
|
|
// deselect any drawing or frame and leave editing mode
|
|
if (SdrView* pSdrView = GetDrawView())
|
|
{
|
|
if (pSdrView->IsTextEdit())
|
|
{
|
|
bool bLockView = IsViewLocked();
|
|
LockView(true);
|
|
EndTextEdit();
|
|
LockView(bLockView);
|
|
}
|
|
// go out of the frame
|
|
Point aPt(LONG_MIN, LONG_MIN);
|
|
SelectObj(aPt, SW_LEAVE_FRAME);
|
|
}
|
|
if (IsSelFrameMode() || IsObjSelected())
|
|
{
|
|
UnSelectFrame();
|
|
LeaveSelFrameMode();
|
|
GetView().LeaveDrawCreate();
|
|
EnterStdMode();
|
|
DrawSelChanged();
|
|
GetView().StopShellTimer();
|
|
}
|
|
else
|
|
EnterStdMode();
|
|
}
|
|
|
|
// Extended Mode
|
|
|
|
void SwWrtShell::EnterExtMode()
|
|
{
|
|
if(m_bBlockMode)
|
|
{
|
|
LeaveBlockMode();
|
|
KillPams();
|
|
ClearMark();
|
|
}
|
|
m_bExtMode = true;
|
|
m_bAddMode = false;
|
|
m_bBlockMode = false;
|
|
SttSelect();
|
|
}
|
|
|
|
void SwWrtShell::LeaveExtMode()
|
|
{
|
|
m_bExtMode = false;
|
|
EndSelect();
|
|
}
|
|
|
|
// End of a selection; if the selection is empty,
|
|
// ClearMark().
|
|
|
|
void SwWrtShell::SttLeaveSelect()
|
|
{
|
|
if(SwCursorShell::HasSelection() && !IsSelTableCells() && m_bClearMark) {
|
|
return;
|
|
}
|
|
ClearMark();
|
|
}
|
|
|
|
// Leaving of the selection mode in additional mode
|
|
|
|
void SwWrtShell::AddLeaveSelect()
|
|
{
|
|
if(IsTableMode()) LeaveAddMode();
|
|
else if(SwCursorShell::HasSelection())
|
|
CreateCursor();
|
|
}
|
|
|
|
// Additional Mode
|
|
|
|
void SwWrtShell::EnterAddMode()
|
|
{
|
|
if(IsTableMode()) return;
|
|
if(m_bBlockMode)
|
|
LeaveBlockMode();
|
|
m_fnKillSel = &SwWrtShell::Ignore;
|
|
m_fnSetCursor = &SwWrtShell::SetCursor;
|
|
m_bAddMode = true;
|
|
m_bBlockMode = false;
|
|
m_bExtMode = false;
|
|
if(SwCursorShell::HasSelection())
|
|
CreateCursor();
|
|
Invalidate();
|
|
}
|
|
|
|
void SwWrtShell::LeaveAddMode()
|
|
{
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_bAddMode = false;
|
|
Invalidate();
|
|
}
|
|
|
|
// Block Mode
|
|
|
|
void SwWrtShell::EnterBlockMode()
|
|
{
|
|
m_bBlockMode = false;
|
|
EnterStdMode();
|
|
m_bBlockMode = true;
|
|
CursorToBlockCursor();
|
|
Invalidate();
|
|
}
|
|
|
|
void SwWrtShell::LeaveBlockMode()
|
|
{
|
|
m_bBlockMode = false;
|
|
BlockCursorToCursor();
|
|
EndSelect();
|
|
Invalidate();
|
|
}
|
|
|
|
// Insert mode
|
|
|
|
void SwWrtShell::ImplSetInsMode(bool bOn)
|
|
{
|
|
m_bIns = bOn;
|
|
SwCursorShell::SetOverwriteCursor( !m_bIns );
|
|
const SfxBoolItem aTmp( SID_ATTR_INSERT, m_bIns );
|
|
GetView().GetViewFrame().GetBindings().SetState( aTmp );
|
|
StartAction();
|
|
EndAction();
|
|
Invalidate();
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class QuerySetInsModeDialog : public weld::GenericDialogController
|
|
{
|
|
std::unique_ptr<weld::Image> m_xImage;
|
|
std::unique_ptr<weld::CheckButton> m_xCheckBox;
|
|
public:
|
|
QuerySetInsModeDialog(weld::Window* pParent)
|
|
: GenericDialogController(pParent, u"cui/ui/querysetinsmodedialog.ui"_ustr, u"SetInsModeDialog"_ustr)
|
|
, m_xImage(m_xBuilder->weld_image(u"imSetInsMode"_ustr))
|
|
, m_xCheckBox(m_xBuilder->weld_check_button(u"cbDontShowAgain"_ustr))
|
|
{
|
|
m_xImage->set_from_icon_name(RID_BMP_QUERYINSMODE);
|
|
}
|
|
bool GetDoNotShowAgain() const
|
|
{
|
|
return m_xCheckBox->get_active();
|
|
}
|
|
};
|
|
}
|
|
|
|
void SwWrtShell::SetInsMode( bool bOn )
|
|
{
|
|
const bool bDoAsk = officecfg::Office::Common::Misc::QuerySetInsMode::get();
|
|
if (!bOn && bDoAsk)
|
|
{
|
|
auto xDialog = std::make_shared<QuerySetInsModeDialog>(GetView().GetFrameWeld());
|
|
weld::DialogController::runAsync(xDialog, [this, bOn, xDialog](sal_Int32 nResult){
|
|
|
|
std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
|
|
comphelper::ConfigurationChanges::create());
|
|
officecfg::Office::Common::Misc::QuerySetInsMode::set(!xDialog->GetDoNotShowAgain(), xChanges);
|
|
xChanges->commit();
|
|
|
|
if ( nResult == static_cast<int>(RET_NO) )
|
|
return;
|
|
|
|
ImplSetInsMode(bOn);
|
|
});
|
|
return;
|
|
}
|
|
ImplSetInsMode(bOn);
|
|
}
|
|
|
|
//Overwrite mode is incompatible with red-lining
|
|
void SwWrtShell::SetRedlineFlagsAndCheckInsMode( RedlineFlags eMode )
|
|
{
|
|
SetRedlineFlags( eMode );
|
|
if (IsRedlineOn())
|
|
SetInsMode();
|
|
}
|
|
|
|
// Edit frame
|
|
|
|
void SwWrtShell::BeginFrameDrag(const Point *pPt, bool bIsShift)
|
|
{
|
|
m_fnDrag = &SwFEShell::Drag;
|
|
if(bStartDrag)
|
|
{
|
|
Point aTmp( nStartDragX, nStartDragY );
|
|
SwFEShell::BeginDrag( &aTmp, bIsShift );
|
|
}
|
|
else
|
|
SwFEShell::BeginDrag( pPt, bIsShift );
|
|
}
|
|
|
|
void SwWrtShell::EnterSelFrameMode(const Point *pPos)
|
|
{
|
|
if(pPos)
|
|
{
|
|
nStartDragX = pPos->X();
|
|
nStartDragY = pPos->Y();
|
|
bStartDrag = true;
|
|
}
|
|
m_bLayoutMode = true;
|
|
HideCursor();
|
|
|
|
// equal call of BeginDrag in the SwFEShell
|
|
m_fnDrag = &SwWrtShell::BeginFrameDrag;
|
|
m_fnEndDrag = &SwWrtShell::UpdateLayoutFrame;
|
|
SwBaseShell::SetFrameMode( FLY_DRAG_START, this );
|
|
Invalidate();
|
|
}
|
|
|
|
void SwWrtShell::LeaveSelFrameMode()
|
|
{
|
|
m_fnDrag = &SwWrtShell::BeginDrag;
|
|
m_fnEndDrag = &SwWrtShell::DefaultEndDrag;
|
|
m_bLayoutMode = false;
|
|
bStartDrag = false;
|
|
Edit();
|
|
SwBaseShell::SetFrameMode( FLY_DRAG_END, this );
|
|
Invalidate();
|
|
}
|
|
|
|
// Description: execute framebound macro
|
|
|
|
IMPL_LINK( SwWrtShell, ExecFlyMac, const SwFlyFrameFormat*, pFlyFormat, void )
|
|
{
|
|
const SwFrameFormat *pFormat = pFlyFormat ? static_cast<const SwFrameFormat*>(pFlyFormat) : GetFlyFrameFormat();
|
|
assert(pFormat && "no frame format");
|
|
const SvxMacroItem &rFormatMac = pFormat->GetMacro();
|
|
|
|
if(rFormatMac.HasMacro(SvMacroItemId::SwObjectSelect))
|
|
{
|
|
const SvxMacro &rMac = rFormatMac.GetMacro(SvMacroItemId::SwObjectSelect);
|
|
if( IsFrameSelected() )
|
|
m_bLayoutMode = true;
|
|
CallChgLnk();
|
|
ExecMacro( rMac );
|
|
}
|
|
}
|
|
|
|
void SwWrtShell::UpdateLayoutFrame(const Point *, bool )
|
|
{
|
|
// still a dummy
|
|
SwFEShell::EndDrag();
|
|
m_fnDrag = &SwWrtShell::BeginFrameDrag;
|
|
}
|
|
|
|
// Handler for toggling the modes. Returns back the old mode.
|
|
|
|
void SwWrtShell::ToggleAddMode()
|
|
{
|
|
m_bAddMode ? LeaveAddMode(): EnterAddMode();
|
|
Invalidate();
|
|
}
|
|
|
|
void SwWrtShell::ToggleBlockMode()
|
|
{
|
|
m_bBlockMode ? LeaveBlockMode(): EnterBlockMode();
|
|
Invalidate();
|
|
}
|
|
|
|
void SwWrtShell::ToggleExtMode()
|
|
{
|
|
m_bExtMode ? LeaveExtMode() : EnterExtMode();
|
|
Invalidate();
|
|
}
|
|
|
|
// Dragging in standard mode (Selecting of content)
|
|
|
|
void SwWrtShell::BeginDrag(const Point * /*pPt*/, bool )
|
|
{
|
|
if(m_bSelWrd)
|
|
{
|
|
m_bInSelect = true;
|
|
if( !IsCursorPtAtEnd() )
|
|
SwapPam();
|
|
|
|
m_fnDrag = &SwWrtShell::ExtSelWrd;
|
|
m_fnSetCursor = &SwWrtShell::Ignore;
|
|
}
|
|
else if(m_bSelLn)
|
|
{
|
|
m_bInSelect = true;
|
|
m_fnDrag = &SwWrtShell::ExtSelLn;
|
|
m_fnSetCursor = &SwWrtShell::Ignore;
|
|
}
|
|
else
|
|
{
|
|
m_fnDrag = &SwWrtShell::DefaultDrag;
|
|
SttSelect();
|
|
}
|
|
}
|
|
|
|
void SwWrtShell::DefaultDrag(const Point *, bool )
|
|
{
|
|
if( IsSelTableCells() )
|
|
m_aSelTableLink.Call(*this);
|
|
}
|
|
|
|
void SwWrtShell::DefaultEndDrag(const Point * /*pPt*/, bool )
|
|
{
|
|
m_fnDrag = &SwWrtShell::BeginDrag;
|
|
if( IsExtSel() )
|
|
LeaveExtSel();
|
|
|
|
if( IsSelTableCells() )
|
|
m_aSelTableLink.Call(*this);
|
|
EndSelect();
|
|
}
|
|
|
|
// #i32329# Enhanced table selection
|
|
bool SwWrtShell::SelectTableRowCol( const Point& rPt, const Point* pEnd, bool bRowDrag )
|
|
{
|
|
SwMvContext aMvContext(this);
|
|
SttSelect();
|
|
if(SelTableRowCol( rPt, pEnd, bRowDrag ))
|
|
{
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Description: Selection of a table line or column
|
|
|
|
void SwWrtShell::SelectTableRow()
|
|
{
|
|
if ( SelTableRow() )
|
|
{
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
}
|
|
}
|
|
|
|
void SwWrtShell::SelectTableCol()
|
|
{
|
|
if ( SelTableCol() )
|
|
{
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
}
|
|
}
|
|
|
|
void SwWrtShell::SelectTableCell()
|
|
{
|
|
if ( SelTableBox() )
|
|
{
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
}
|
|
}
|
|
|
|
// Description: Check if a word selection is present.
|
|
// According to the rules for intelligent cut / paste
|
|
// surrounding spaces are cut out.
|
|
// Return: Delivers the type of the word selection.
|
|
|
|
int SwWrtShell::IntelligentCut(SelectionType nSelection, bool bCut)
|
|
{
|
|
// On multiple selection no intelligent drag and drop
|
|
// there are multiple cursors, since a second was placed
|
|
// already at the target position.
|
|
if( IsAddMode() || !(nSelection & SelectionType::Text) )
|
|
return NO_WORD;
|
|
|
|
OUString sText;
|
|
CharClass& rCC = GetAppCharClass();
|
|
|
|
// If the first character is no word character,
|
|
// no word selected.
|
|
sal_Unicode cPrev = GetChar(false);
|
|
sal_Unicode cNext = GetChar(true, -1);
|
|
if( !cPrev || !cNext ||
|
|
!rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) ||
|
|
!rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
|
|
return NO_WORD;
|
|
|
|
cPrev = GetChar(false, -1);
|
|
cNext = GetChar();
|
|
|
|
int cWord = NO_WORD;
|
|
// is a word selected?
|
|
if (cPrev && cNext &&
|
|
CH_TXTATR_BREAKWORD != cPrev && CH_TXTATR_INWORD != cPrev &&
|
|
CH_TXTATR_BREAKWORD != cNext && CH_TXTATR_INWORD != cNext &&
|
|
!rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) &&
|
|
!rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
|
|
cWord = WORD_NO_SPACE;
|
|
|
|
if(cWord == WORD_NO_SPACE && ' ' == cPrev )
|
|
{
|
|
cWord = WORD_SPACE_BEFORE;
|
|
// delete the space before
|
|
if(bCut)
|
|
{
|
|
Push();
|
|
if(IsCursorPtAtEnd())
|
|
SwapPam();
|
|
ClearMark();
|
|
SetMark();
|
|
SwCursorShell::Left(1,SwCursorSkipMode::Chars);
|
|
SwFEShell::Delete(true);
|
|
Pop(SwCursorShell::PopMode::DeleteCurrent);
|
|
}
|
|
}
|
|
else if(cWord == WORD_NO_SPACE && cNext == ' ')
|
|
{
|
|
cWord = WORD_SPACE_AFTER;
|
|
// delete the space behind
|
|
if(bCut) {
|
|
Push();
|
|
if(!IsCursorPtAtEnd()) SwapPam();
|
|
ClearMark();
|
|
SetMark();
|
|
SwCursorShell::Right(1,SwCursorSkipMode::Chars);
|
|
SwFEShell::Delete(true);
|
|
Pop(SwCursorShell::PopMode::DeleteCurrent);
|
|
}
|
|
}
|
|
return cWord;
|
|
}
|
|
|
|
// jump to the next / previous hyperlink - inside text and also
|
|
// on graphics
|
|
void SwWrtShell::SelectNextPrevHyperlink( bool bNext )
|
|
{
|
|
StartAction();
|
|
bool bRet = SwCursorShell::SelectNxtPrvHyperlink( bNext );
|
|
if( !bRet ) // didn't find? wrap and check again
|
|
{
|
|
SwShellCursor* pCursor = GetCursor_();
|
|
SwCursorSaveState aSaveState(*pCursor);
|
|
EnterStdMode();
|
|
if( bNext )
|
|
SttEndDoc(true);
|
|
else
|
|
SttEndDoc(false);
|
|
bRet = SwCursorShell::SelectNxtPrvHyperlink(bNext);
|
|
if (!bRet) // didn't find again? restore cursor position and bail
|
|
{
|
|
pCursor->RestoreSavePos();
|
|
EndAction(true); // don't scroll to restored cursor position
|
|
return;
|
|
}
|
|
}
|
|
EndAction();
|
|
|
|
bool bCreateXSelection = false;
|
|
const bool bFrameSelected = IsFrameSelected() || IsObjSelected();
|
|
if( IsSelection() )
|
|
{
|
|
if ( bFrameSelected )
|
|
UnSelectFrame();
|
|
|
|
// Set the function pointer for the canceling of the selection
|
|
// set at cursor
|
|
m_fnKillSel = &SwWrtShell::ResetSelect;
|
|
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
|
|
bCreateXSelection = true;
|
|
}
|
|
else if( bFrameSelected )
|
|
{
|
|
EnterSelFrameMode();
|
|
bCreateXSelection = true;
|
|
}
|
|
else if( (CNT_GRF | CNT_OLE ) & GetCntType() )
|
|
{
|
|
SelectObj( GetCharRect().Pos() );
|
|
EnterSelFrameMode();
|
|
bCreateXSelection = true;
|
|
}
|
|
|
|
if( bCreateXSelection )
|
|
SwTransferable::CreateSelection( *this );
|
|
}
|
|
|
|
// For the preservation of the selection the cursor will be moved left
|
|
// after SetMark(), so that the cursor is not moved by inserting text.
|
|
// Because a present selection at the CORE page is cleared at the
|
|
// current cursor position, the cursor will be pushed on the stack.
|
|
// After moving, they will again resummarized.
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|