1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <editeng/lrspitem.hxx>
24 #include <drawbase.hxx>
25 #include <unobaseclass.hxx>
26 #include <fmtanchr.hxx>
30 #include <docufld.hxx>
31 #include <IDocumentUndoRedo.hxx>
32 #include <i18nutil/unicode.hxx>
33 #include <rtl/character.hxx>
36 inline void SwWrtShell::OpenMark()
44 inline void SwWrtShell::CloseMark( bool bOkFlag
)
58 bool SwWrtShell::TryRemoveIndent()
62 SfxItemSet
aAttrSet(GetAttrPool(), svl::Items
<RES_LR_SPACE
, RES_LR_SPACE
>{});
65 SvxLRSpaceItem aItem
= aAttrSet
.Get(RES_LR_SPACE
);
66 short aOldFirstLineOfst
= aItem
.GetTextFirstLineOffset();
68 if (aOldFirstLineOfst
> 0)
70 aItem
.SetTextFirstLineOffset(0);
73 else if (aOldFirstLineOfst
< 0)
75 aItem
.SetTextFirstLineOffset(0);
76 aItem
.SetLeft(aItem
.GetLeft() + aOldFirstLineOfst
);
80 else if (aItem
.GetLeft() != 0)
95 /** Description: Erase the line. */
97 void SwWrtShell::DelLine()
99 SwActContext
aActContext(this);
101 // remember the old cursor
104 SwCursorShell::LeftMargin();
106 SwCursorShell::RightMargin();
108 bool bRet
= Delete();
109 Pop(SwCursorShell::PopMode::DeleteCurrent
);
114 void SwWrtShell::DelToStartOfLine()
117 SwCursorShell::LeftMargin();
118 bool bRet
= Delete();
122 void SwWrtShell::DelToEndOfLine()
125 SwCursorShell::RightMargin();
126 bool bRet
= Delete();
130 bool SwWrtShell::DelLeft()
132 // If it's a Fly, throw it away
133 SelectionType nSelType
= GetSelectionType();
134 const SelectionType nCmp
= SelectionType::Frame
| SelectionType::Graphic
| SelectionType::Ole
| SelectionType::DrawObject
;
135 if( nCmp
& nSelType
)
137 // #108205# Remember object's position.
138 Point aTmpPt
= GetObjRect().TopLeft();
142 // #108205# Set cursor to remembered position.
148 nSelType
= GetSelectionType();
149 if ( nCmp
& nSelType
)
158 // If a selection exists, erase this
161 if( !IsBlockMode() || HasSelection() )
163 //OS: Once again Basic: SwActContext must be leaved
164 //before EnterStdMode!
166 SwActContext
aActContext(this);
185 // JP 29.06.95: never erase a table standing in front of it.
187 const SwTableNode
* pWasInTableNd
= SwCursorShell::IsCursorInTable();
189 if( SwCursorShell::IsSttPara())
191 // Start/EndAllAction to avoid cursor flickering
192 UnoActionContext
c(GetDoc());
193 SwCursorShell::Push();
195 // #i4032# Don't actually call a 'delete' if we
196 // changed the table cell, compare DelRight().
197 const SwStartNode
* pSNdOld
= pWasInTableNd
?
198 GetSwCursor()->GetNode().FindTableBoxStartNode() :
201 // If the cursor is at the beginning of a paragraph, try to step
202 // backwards. On failure we are done.
203 bool bDoSomething
= SwCursorShell::Left(1,CRSR_SKIP_CHARS
);
207 // If the cursor entered or left a table (or both) we are done.
208 const SwTableNode
* pIsInTableNd
= SwCursorShell::IsCursorInTable();
209 bDoSomething
= pIsInTableNd
== pWasInTableNd
;
213 const SwStartNode
* pSNdNew
= pIsInTableNd
?
214 GetSwCursor()->GetNode().FindTableBoxStartNode() :
217 // #i4032# Don't actually call a 'delete' if we
218 // changed the table cell, compare DelRight().
219 bDoSomething
= pSNdOld
== pSNdNew
;
225 // tdf#115132 Restore previous position and we are done
226 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent
);
230 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteStack
);
233 SwCursorShell::Right(1,CRSR_SKIP_CHARS
);
234 SwCursorShell::SwapPam();
239 // If we are just to the right to a fieldmark, then remove it completely
240 const SwPosition
* pCurPos
= GetCursor()->GetPoint();
241 SwPosition
aPrevChar(*pCurPos
);
242 --aPrevChar
.nContent
;
243 sw::mark::IFieldmark
* pFm
= getIDocumentMarkAccess()->getFieldmarkAt(aPrevChar
);
244 if (pFm
&& pFm
->GetMarkEnd() == *pCurPos
)
246 mxDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
247 IDocumentMarkAccess::DeleteFieldmarkCommand(*pFm
);
248 getIDocumentMarkAccess()->deleteMark(pFm
);
249 mxDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
254 SwCursorShell::Left(1, CRSR_SKIP_CHARS
);
255 if (SvtScriptType::ASIAN
== GetScriptType())
257 sal_uInt32 nCode
= GetChar(false);
258 if ( rtl::isSurrogate( nCode
) )
260 OUString sStr
= GetSelText();
261 sal_Int32 nIndex
= 0;
262 nCode
= sStr
.iterateCodePoints( &nIndex
);
265 if ( unicode::isIVSSelector( nCode
) )
267 SwCursorShell::Push();
268 SwCursorShell::Left(1, CRSR_SKIP_CHARS
);
269 OUString sStr
= GetSelText();
270 sal_Int32 nIndex
= 0;
271 nCode
= sStr
.iterateCodePoints( &nIndex
);
272 if ( unicode::isCJKIVSCharacter( nCode
) )
273 SwCursorShell::Pop( SwCursorShell::PopMode::DeleteStack
);
275 SwCursorShell::Pop( SwCursorShell::PopMode::DeleteCurrent
); // For the weak script.
279 bool bRet
= Delete();
281 SwCursorShell::SwapPam();
284 { // false indicates HasReadonlySel failed
285 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui"));
286 std::unique_ptr
<weld::MessageDialog
> xInfo(xBuilder
->weld_message_dialog("InfoReadonlyDialog"));
292 bool SwWrtShell::DelRight()
294 // Will be or'ed, if a tableselection exists;
295 // will here be implemented on SelectionType::Table
297 SelectionType nSelection
= GetSelectionType();
298 if(nSelection
& SelectionType::TableCell
)
299 nSelection
= SelectionType::Table
;
300 if(nSelection
& SelectionType::Text
)
301 nSelection
= SelectionType::Text
;
303 switch( nSelection
& ~SelectionType::Ornament
)
305 case SelectionType::PostIt
:
306 case SelectionType::Text
:
307 case SelectionType::Table
:
308 case SelectionType::NumberList
:
309 // If a selection exists, erase it.
312 if( !IsBlockMode() || HasSelection() )
314 //OS: And once again Basic: SwActContext must be
315 //leaved before EnterStdMode !
317 SwActContext
aActContext(this);
337 if (SwCursorShell::IsEndPara())
339 // Start/EndAllAction to avoid cursor flickering
340 UnoActionContext
c(GetDoc());
342 const SwTableNode
* pWasInTableNd
= IsCursorInTable();
343 // #108049# Save the startnode of the current cell
344 const SwStartNode
* pSNdOld
= pWasInTableNd
?
345 GetSwCursor()->GetNode().FindTableBoxStartNode() : nullptr;
346 bool bCheckDelFull
= SelectionType::Text
& nSelection
&& SwCursorShell::IsSttPara();
347 bool bDelFull
= false;
348 bool bDoNothing
= false;
350 // #i41424# Introduced a couple of
351 // Push()-Pop() pairs here. The reason for this is that a
352 // Right()-Left() combination does not make sure, that
353 // the cursor will be in its initial state, because there
354 // may be a numbering in front of the next paragraph.
355 SwCursorShell::Push();
357 if (SwCursorShell::Right(1, CRSR_SKIP_CHARS
))
359 const SwTableNode
* pCurrTableNd
= IsCursorInTable();
360 bDelFull
= bCheckDelFull
&& pCurrTableNd
&& pCurrTableNd
!= pWasInTableNd
;
361 if (!bDelFull
&& (IsCursorInTable() || (pCurrTableNd
!= pWasInTableNd
)))
363 // #108049# Save the startnode of the current cell.
364 // May be different to pSNdOld as we have moved.
365 const SwStartNode
* pSNdNew
= pCurrTableNd
?
366 GetSwCursor()->GetNode().FindTableBoxStartNode() : nullptr;
368 // tdf#115132 Only keep cursor position instead of deleting
369 // if we have moved to a different cell
370 bDoNothing
= pSNdOld
!= pSNdNew
;
375 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent
);
382 if (bDelFull
|| bDoNothing
)
387 // If we are just ahead of a fieldmark, then remove it completely
388 sw::mark::IFieldmark
*const pFm
= getIDocumentMarkAccess()->getFieldmarkAt(*GetCursor()->GetPoint());
389 if (pFm
&& pFm
->GetMarkStart() == *GetCursor()->GetPoint())
391 mxDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
392 IDocumentMarkAccess::DeleteFieldmarkCommand(*pFm
);
393 getIDocumentMarkAccess()->deleteMark(pFm
);
394 mxDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
401 SwCursorShell::Right(1, CRSR_SKIP_CELLS
);
405 { // false indicates HasReadonlySel failed
406 std::unique_ptr
<weld::Builder
> xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui"));
407 std::unique_ptr
<weld::MessageDialog
> xInfo(xBuilder
->weld_message_dialog("InfoReadonlyDialog"));
412 case SelectionType::Frame
:
413 case SelectionType::Graphic
:
414 case SelectionType::Ole
:
415 case SelectionType::DrawObject
:
416 case SelectionType::DrawObjectEditMode
:
417 case SelectionType::DbForm
:
419 // #108205# Remember object's position.
420 Point aTmpPt
= GetObjRect().TopLeft();
422 // Remember the anchor of the selected object before deletion.
423 std::unique_ptr
<SwPosition
> pAnchor
;
424 SwFlyFrame
* pFly
= GetSelectedFlyFrame();
427 SwFrameFormat
* pFormat
= pFly
->GetFormat();
430 RndStdIds eAnchorId
= pFormat
->GetAnchor().GetAnchorId();
431 if ((eAnchorId
== RndStdIds::FLY_AS_CHAR
|| eAnchorId
== RndStdIds::FLY_AT_CHAR
)
432 && pFormat
->GetAnchor().GetContentAnchor())
434 pAnchor
.reset(new SwPosition(*pFormat
->GetAnchor().GetContentAnchor()));
439 // Group deletion of the object and its comment together.
440 mxDoc
->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY
, nullptr);
446 SwTextNode
* pTextNode
= pAnchor
->nNode
.GetNode().GetTextNode();
449 const SwTextField
* pField(
450 pTextNode
->GetFieldTextAttrAt(pAnchor
->nContent
.GetIndex(), true));
452 && dynamic_cast<const SwPostItField
*>(pField
->GetFormatField().GetField()))
454 // Remove the comment of the deleted object.
455 *GetCurrentShellCursor().GetPoint() = *pAnchor
;
461 mxDoc
->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY
, nullptr);
463 // #108205# Set cursor to remembered position.
468 OSL_ENSURE( !IsFrameSelected(),
469 "<SwWrtShell::DelRight(..)> - <SwWrtShell::UnSelectFrame()> should unmark all objects" );
470 // leave draw mode, if necessary.
472 if (GetView().GetDrawFuncPtr())
474 GetView().GetDrawFuncPtr()->Deactivate();
475 GetView().SetDrawFuncPtr(nullptr);
477 if ( GetView().IsDrawMode() )
479 GetView().LeaveDrawCreate();
484 // <IsFrameSelected()> can't be true - see above.
486 nSelection
= GetSelectionType();
487 if ( SelectionType::Frame
& nSelection
||
488 SelectionType::Graphic
& nSelection
||
489 SelectionType::Ole
& nSelection
||
490 SelectionType::DrawObject
& nSelection
)
503 void SwWrtShell::DelToEndOfPara()
505 SwActContext
aActContext(this);
509 if( !MovePara(GoCurrPara
,fnParaEnd
))
511 Pop(SwCursorShell::PopMode::DeleteCurrent
);
514 bool bRet
= Delete();
515 Pop(SwCursorShell::PopMode::DeleteCurrent
);
520 void SwWrtShell::DelToStartOfPara()
522 SwActContext
aActContext(this);
526 if( !MovePara(GoCurrPara
,fnParaStart
))
528 Pop(SwCursorShell::PopMode::DeleteCurrent
);
531 bool bRet
= Delete();
532 Pop(SwCursorShell::PopMode::DeleteCurrent
);
537 // All erase operations should work with Find instead with
538 // Nxt-/PrvDelim, because the latter works with Wrap Around
539 // -- that's probably not wished.
541 void SwWrtShell::DelToStartOfSentence()
546 bool bRet
= BwdSentence_() && Delete();
550 bool SwWrtShell::DelToEndOfSentence()
556 // fdo#60967: special case that is documented in help: delete
557 // paragraph following table if cursor is at end of last cell in table
562 if (SwCursorShell::Right(1,CRSR_SKIP_CHARS
))
565 if (!IsEndPara()) // can only be at the end if it's empty
566 { // for an empty paragraph this would actually select the _next_
567 SwCursorShell::MovePara(GoCurrPara
, fnParaEnd
);
569 if (!IsEndOfDoc()) // do not delete last paragraph in body text
571 bRet
= DelFullPara();
574 Pop(SwCursorShell::PopMode::DeleteCurrent
);
578 bRet
= FwdSentence_() && Delete();
584 void SwWrtShell::DelNxtWord()
588 SwActContext
aActContext(this);
592 if(IsEndWrd() && !IsStartWord())
593 NxtWrdForDelete(); // #i92468#
594 if(IsStartWord() || IsEndPara())
595 NxtWrdForDelete(); // #i92468#
599 bool bRet
= Delete();
607 void SwWrtShell::DelPrvWord()
611 SwActContext
aActContext(this);
615 if ( !IsStartWord() ||
616 !PrvWrdForDelete() ) // #i92468#
618 if (IsEndWrd() || IsSttPara())
619 PrvWrdForDelete(); // #i92468#
623 bool bRet
= Delete();
631 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */