nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / uibase / wrtsh / delete.cxx
blob0dbc7eb89cc5f7653dc171adb3470dfb26e50998
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <wrtsh.hxx>
21 #include <swcrsr.hxx>
22 #include <editeng/lrspitem.hxx>
23 #include <view.hxx>
24 #include <drawbase.hxx>
25 #include <unobaseclass.hxx>
26 #include <fmtanchr.hxx>
27 #include <flyfrm.hxx>
28 #include <ndtxt.hxx>
29 #include <txtfld.hxx>
30 #include <docufld.hxx>
31 #include <IDocumentUndoRedo.hxx>
32 #include <i18nutil/unicode.hxx>
33 #include <rtl/character.hxx>
34 #include <doc.hxx>
36 inline void SwWrtShell::OpenMark()
38 StartAllAction();
39 ResetCursorStack();
40 KillPams();
41 SetMark();
44 inline void SwWrtShell::CloseMark( bool bOkFlag )
46 if( bOkFlag )
47 UpdateAttr();
48 else
49 SwapPam();
51 ClearMark();
52 EndAllAction();
57 // #i23725#
58 bool SwWrtShell::TryRemoveIndent()
60 bool bResult = false;
62 SfxItemSet aAttrSet(GetAttrPool(), svl::Items<RES_LR_SPACE, RES_LR_SPACE>{});
63 GetCurAttr(aAttrSet);
65 SvxLRSpaceItem aItem = aAttrSet.Get(RES_LR_SPACE);
66 short aOldFirstLineOfst = aItem.GetTextFirstLineOffset();
68 if (aOldFirstLineOfst > 0)
70 aItem.SetTextFirstLineOffset(0);
71 bResult = true;
73 else if (aOldFirstLineOfst < 0)
75 aItem.SetTextFirstLineOffset(0);
76 aItem.SetLeft(aItem.GetLeft() + aOldFirstLineOfst);
78 bResult = true;
80 else if (aItem.GetLeft() != 0)
82 aItem.SetLeft(0);
83 bResult = true;
86 if (bResult)
88 aAttrSet.Put(aItem);
89 SetAttrSet(aAttrSet);
92 return bResult;
95 /** Description: Erase the line. */
97 void SwWrtShell::DelLine()
99 SwActContext aActContext(this);
100 ResetCursorStack();
101 // remember the old cursor
102 Push();
103 ClearMark();
104 SwCursorShell::LeftMargin();
105 SetMark();
106 SwCursorShell::RightMargin();
108 bool bRet = Delete();
109 Pop(SwCursorShell::PopMode::DeleteCurrent);
110 if( bRet )
111 UpdateAttr();
114 void SwWrtShell::DelToStartOfLine()
116 OpenMark();
117 SwCursorShell::LeftMargin();
118 bool bRet = Delete();
119 CloseMark( bRet );
122 void SwWrtShell::DelToEndOfLine()
124 OpenMark();
125 SwCursorShell::RightMargin();
126 bool bRet = Delete();
127 CloseMark( bRet );
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();
140 DelSelectedObj();
142 // #108205# Set cursor to remembered position.
143 SetCursor(&aTmpPt);
145 LeaveSelFrameMode();
146 UnSelectFrame();
148 nSelType = GetSelectionType();
149 if ( nCmp & nSelType )
151 EnterSelFrameMode();
152 GotoNextFly();
155 return true;
158 // If a selection exists, erase this
159 if ( IsSelection() )
161 if( !IsBlockMode() || HasSelection() )
163 //OS: Once again Basic: SwActContext must be leaved
164 //before EnterStdMode!
166 SwActContext aActContext(this);
167 ResetCursorStack();
168 Delete();
169 UpdateAttr();
171 if( IsBlockMode() )
173 NormalizePam();
174 ClearMark();
175 EnterBlockMode();
177 else
178 EnterStdMode();
179 return true;
181 else
182 EnterStdMode();
185 // JP 29.06.95: never erase a table standing in front of it.
186 bool bSwap = false;
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() :
199 nullptr;
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);
205 if (bDoSomething)
207 // If the cursor entered or left a table (or both) we are done.
208 const SwTableNode* pIsInTableNd = SwCursorShell::IsCursorInTable();
209 bDoSomething = pIsInTableNd == pWasInTableNd;
211 if (bDoSomething)
213 const SwStartNode* pSNdNew = pIsInTableNd ?
214 GetSwCursor()->GetNode().FindTableBoxStartNode() :
215 nullptr;
217 // #i4032# Don't actually call a 'delete' if we
218 // changed the table cell, compare DelRight().
219 bDoSomething = pSNdOld == pSNdNew;
223 if (!bDoSomething)
225 // tdf#115132 Restore previous position and we are done
226 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
227 return false;
230 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteStack);
232 OpenMark();
233 SwCursorShell::Right(1,CRSR_SKIP_CHARS);
234 SwCursorShell::SwapPam();
235 bSwap = true;
237 else
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);
250 return true;
253 OpenMark();
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 );
274 else
275 SwCursorShell::Pop( SwCursorShell::PopMode::DeleteCurrent ); // For the weak script.
279 bool bRet = Delete();
280 if( !bRet && bSwap )
281 SwCursorShell::SwapPam();
282 CloseMark( bRet );
283 if (!bRet)
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"));
287 xInfo->run();
289 return bRet;
292 bool SwWrtShell::DelRight()
294 // Will be or'ed, if a tableselection exists;
295 // will here be implemented on SelectionType::Table
296 bool bRet = false;
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.
310 if( IsSelection() )
312 if( !IsBlockMode() || HasSelection() )
314 //OS: And once again Basic: SwActContext must be
315 //leaved before EnterStdMode !
317 SwActContext aActContext(this);
318 ResetCursorStack();
319 Delete();
320 UpdateAttr();
322 if( IsBlockMode() )
324 NormalizePam();
325 ClearMark();
326 EnterBlockMode();
328 else
329 EnterStdMode();
330 bRet = true;
331 break;
333 else
334 EnterStdMode();
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;
374 // restore cursor
375 SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
377 if (bDelFull)
379 DelFullPara();
380 UpdateAttr();
382 if (bDelFull || bDoNothing)
383 break;
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);
395 bRet = true;
396 break;
400 OpenMark();
401 SwCursorShell::Right(1, CRSR_SKIP_CELLS);
402 bRet = Delete();
403 CloseMark( bRet );
404 if (!bRet)
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"));
408 xInfo->run();
410 break;
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();
425 if (pFly)
427 SwFrameFormat* pFormat = pFly->GetFormat();
428 if (pFormat)
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);
442 DelSelectedObj();
444 if (pAnchor)
446 SwTextNode* pTextNode = pAnchor->nNode.GetNode().GetTextNode();
447 if (pTextNode)
449 const SwTextField* pField(
450 pTextNode->GetFieldTextAttrAt(pAnchor->nContent.GetIndex(), true));
451 if (pField
452 && dynamic_cast<const SwPostItField*>(pField->GetFormatField().GetField()))
454 // Remove the comment of the deleted object.
455 *GetCurrentShellCursor().GetPoint() = *pAnchor;
456 DelRight();
461 mxDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
463 // #108205# Set cursor to remembered position.
464 SetCursor(&aTmpPt);
466 LeaveSelFrameMode();
467 UnSelectFrame();
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 )
492 EnterSelFrameMode();
493 GotoNextFly();
496 bRet = true;
497 break;
498 default: break;
500 return bRet;
503 void SwWrtShell::DelToEndOfPara()
505 SwActContext aActContext(this);
506 ResetCursorStack();
507 Push();
508 SetMark();
509 if( !MovePara(GoCurrPara,fnParaEnd))
511 Pop(SwCursorShell::PopMode::DeleteCurrent);
512 return;
514 bool bRet = Delete();
515 Pop(SwCursorShell::PopMode::DeleteCurrent);
516 if( bRet )
517 UpdateAttr();
520 void SwWrtShell::DelToStartOfPara()
522 SwActContext aActContext(this);
523 ResetCursorStack();
524 Push();
525 SetMark();
526 if( !MovePara(GoCurrPara,fnParaStart))
528 Pop(SwCursorShell::PopMode::DeleteCurrent);
529 return;
531 bool bRet = Delete();
532 Pop(SwCursorShell::PopMode::DeleteCurrent);
533 if( bRet )
534 UpdateAttr();
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()
543 if(IsStartOfDoc())
544 return;
545 OpenMark();
546 bool bRet = BwdSentence_() && Delete();
547 CloseMark( bRet );
550 bool SwWrtShell::DelToEndOfSentence()
552 if(IsEndOfDoc())
553 return false;
554 OpenMark();
555 bool bRet(false);
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
558 if (IsEndOfTable())
560 Push();
561 ClearMark();
562 if (SwCursorShell::Right(1,CRSR_SKIP_CHARS))
564 SetMark();
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);
576 else
578 bRet = FwdSentence_() && Delete();
580 CloseMark( bRet );
581 return bRet;
584 void SwWrtShell::DelNxtWord()
586 if(IsEndOfDoc())
587 return;
588 SwActContext aActContext(this);
589 ResetCursorStack();
590 EnterStdMode();
591 SetMark();
592 if(IsEndWrd() && !IsStartWord())
593 NxtWrdForDelete(); // #i92468#
594 if(IsStartWord() || IsEndPara())
595 NxtWrdForDelete(); // #i92468#
596 else
597 EndWrd();
599 bool bRet = Delete();
600 if( bRet )
601 UpdateAttr();
602 else
603 SwapPam();
604 ClearMark();
607 void SwWrtShell::DelPrvWord()
609 if(IsStartOfDoc())
610 return;
611 SwActContext aActContext(this);
612 ResetCursorStack();
613 EnterStdMode();
614 SetMark();
615 if ( !IsStartWord() ||
616 !PrvWrdForDelete() ) // #i92468#
618 if (IsEndWrd() || IsSttPara())
619 PrvWrdForDelete(); // #i92468#
620 else
621 SttWrd();
623 bool bRet = Delete();
624 if( bRet )
625 UpdateAttr();
626 else
627 SwapPam();
628 ClearMark();
631 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */