1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <svx/svdocapt.hxx>
21 #include <svx/svdundo.hxx>
22 #include <vcl/cursor.hxx>
23 
24 #include <global.hxx>
25 #include <drwlayer.hxx>
26 #include <userdat.hxx>
27 #include <tabvwsh.hxx>
28 #include <document.hxx>
29 #include <futext.hxx>
30 #include <docsh.hxx>
31 #include <postit.hxx>
32 #include <globstr.hrc>
33 #include <scresid.hxx>
34 #include <drawview.hxx>
35 #include <undocell.hxx>
36 
37 //  Editing of Note-Key-Objects has to be stopped always via StopEditMode,
38 //  so that changes are taken over into the document!
39 //  (Fontwork-Execute in drawsh and drtxtob does not happen for Key-Objects)
40 
StopEditMode()41 void FuText::StopEditMode()
42 {
43     SdrObject* pObject = pView->GetTextEditObject();
44     if( !pObject ) return;
45 
46     // relock the internal layer that has been unlocked in FuText::SetInEditMode()
47     if ( pObject->GetLayer() == SC_LAYER_INTERN )
48         pView->LockInternalLayer();
49 
50     ScViewData& rViewData = rViewShell.GetViewData();
51     ScDocument& rDoc = *rViewData.GetDocument();
52     ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
53     OSL_ENSURE( pDrawLayer && (pDrawLayer == pDrDoc), "FuText::StopEditMode - missing or different drawing layers" );
54 
55     ScAddress aNotePos;
56     ScPostIt* pNote = nullptr;
57     if( const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObject, rViewData.GetTabNo() ) )
58     {
59         aNotePos = pCaptData->maStart;
60         pNote = rDoc.GetNote( aNotePos );
61         OSL_ENSURE( pNote && (pNote->GetCaption() == pObject), "FuText::StopEditMode - missing or invalid cell note" );
62     }
63 
64     ScDocShell* pDocShell = rViewData.GetDocShell();
65     SfxUndoManager* pUndoMgr = rDoc.IsUndoEnabled() ? pDocShell->GetUndoManager() : nullptr;
66     bool bNewNote = false;
67     if( pNote && pUndoMgr )
68     {
69         /*  Put all undo actions already collected (e.g. create caption object)
70             and all following undo actions (text changed) together into a ListAction. */
71         std::unique_ptr<SdrUndoGroup> pCalcUndo = pDrawLayer->GetCalcUndo();
72 
73         if(pCalcUndo)
74         {
75             const OUString aUndoStr = ScResId( STR_UNDO_EDITNOTE );
76             pUndoMgr->EnterListAction( aUndoStr, aUndoStr, 0, rViewShell.GetViewShellId() );
77 
78             /*  Note has been created before editing, if first undo action is
79                 an insert action. Needed below to decide whether to drop the
80                 undo if editing a new note has been cancelled. */
81             bNewNote = (pCalcUndo->GetActionCount() > 0) && dynamic_cast< SdrUndoNewObj* >(pCalcUndo->GetAction( 0 ));
82 
83             // create a "insert note" undo action if needed
84             if( bNewNote )
85                 pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( *pDocShell, aNotePos, pNote->GetNoteData(), true, std::move(pCalcUndo) ) );
86             else
87                 pUndoMgr->AddUndoAction( std::move(pCalcUndo) );
88         }
89     }
90 
91     if( pNote )
92         rDoc.LockStreamValid(true);     // only the affected sheet is invalidated below
93 
94     /*  SdrObjEditView::SdrEndTextEdit() may try to delete the entire drawing
95         object, if it does not contain text and has invisible border and fill.
96         This must not happen for note caption objects. They will be removed
97         below together with the cell note if the text is empty (independent of
98         border and area formatting). It is possible to prevent automatic
99         deletion by passing sal_True to this function. The return value changes
100         from SdrEndTextEditKind::Deleted to SdrEndTextEditKind::ShouldBeDeleted in this
101         case. */
102     /*SdrEndTextEditKind eResult =*/ pView->SdrEndTextEdit( pNote != nullptr );
103 
104     // or ScEndTextEdit (with drawview.hxx)
105     rViewShell.SetDrawTextUndo( nullptr );
106 
107     vcl::Cursor* pCur = pWindow->GetCursor();
108     if( pCur && pCur->IsVisible() )
109         pCur->Hide();
110 
111     if( pNote )
112     {
113         ScTabView::OnLOKNoteStateChanged( pNote );
114 
115         // hide the caption object if it is in hidden state
116         pNote->ShowCaptionTemp( aNotePos, false );
117 
118         // update author and date
119         pNote->AutoStamp();
120 
121         /*  If the entire text has been cleared, the cell note and its caption
122             object have to be removed. */
123         SdrTextObj* pTextObject = dynamic_cast< SdrTextObj* >( pObject );
124         bool bDeleteNote = !pTextObject || !pTextObject->HasText();
125         if( bDeleteNote )
126         {
127             if( pUndoMgr )
128             {
129                 // collect the "remove object" drawing undo action created by DeleteNote()
130                 pDrawLayer->BeginCalcUndo(false);
131                 // rescue note data before deletion
132                 ScNoteData aNoteData( pNote->GetNoteData() );
133                 // delete note from document (removes caption, but does not delete it)
134                 rDoc.ReleaseNote(aNotePos);
135                 // create undo action for removed note
136                 pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( *pDocShell, aNotePos, aNoteData, false, pDrawLayer->GetCalcUndo() ) );
137             }
138             else
139             {
140                 rDoc.ReleaseNote(aNotePos);
141             }
142             // ScDocument::DeleteNote has deleted the note that pNote points to
143             pNote = nullptr;
144         }
145 
146         // finalize the undo list action
147         if( pUndoMgr )
148         {
149             pUndoMgr->LeaveListAction();
150 
151             /*  #i94039# Update the default name "Edit Note" of the undo action
152                 if the note has been created before editing or is deleted due
153                 to deleted text. If the note has been created *and* is deleted,
154                 the last undo action can be removed completely. Note: The
155                 function LeaveListAction() removes the last action by itself,
156                 if it is empty (when result is SdrEndTextEditKind::Unchanged). */
157             if( bNewNote && bDeleteNote )
158             {
159                 pUndoMgr->RemoveLastUndoAction();
160 
161                 // Make sure the former area of the note anchor is invalidated.
162                 ScRangeList aRangeList(aNotePos);
163                 ScMarkData aMarkData(rDoc.MaxRow(), rDoc.MaxCol(), aRangeList);
164                 rViewShell.UpdateSelectionArea(aMarkData);
165             }
166             else if( bNewNote || bDeleteNote )
167             {
168                 SfxListUndoAction* pAction = dynamic_cast< SfxListUndoAction* >( pUndoMgr->GetUndoAction() );
169                 OSL_ENSURE( pAction, "FuText::StopEditMode - list undo action expected" );
170                 if( pAction )
171                     pAction->SetComment( ScResId( bNewNote ? STR_UNDO_INSERTNOTE : STR_UNDO_DELETENOTE ) );
172             }
173         }
174 
175         // invalidate stream positions only for the affected sheet
176         rDoc.LockStreamValid(false);
177         rDoc.SetStreamValid(aNotePos.Tab(), false);
178     }
179 }
180 
181 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
182