/src/libreoffice/sw/source/uibase/docvw/AnnotationWin.cxx
Line | Count | Source |
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 <config_wasm_strip.h> |
21 | | |
22 | | #include <AnnotationWin.hxx> |
23 | | |
24 | | #include <PostItMgr.hxx> |
25 | | |
26 | | #include <strings.hrc> |
27 | | |
28 | | #include <uiobject.hxx> |
29 | | |
30 | | #include <vcl/svapp.hxx> |
31 | | #include <vcl/uitest/logger.hxx> |
32 | | #include <vcl/uitest/eventdescription.hxx> |
33 | | |
34 | | #include <svl/undo.hxx> |
35 | | #include <svtools/svparser.hxx> |
36 | | #include <unotools/localedatawrapper.hxx> |
37 | | #include <unotools/syslocale.hxx> |
38 | | #include <svl/languageoptions.hxx> |
39 | | #include <osl/diagnose.h> |
40 | | |
41 | | #include <editeng/eeitem.hxx> |
42 | | #include <editeng/postitem.hxx> |
43 | | #include <editeng/fhgtitem.hxx> |
44 | | #include <editeng/langitem.hxx> |
45 | | #include <editeng/editund2.hxx> |
46 | | |
47 | | #include <editeng/editview.hxx> |
48 | | #include <editeng/outliner.hxx> |
49 | | #include <editeng/editeng.hxx> |
50 | | #include <editeng/editobj.hxx> |
51 | | #include <editeng/outlobj.hxx> |
52 | | |
53 | | #include <comphelper/lok.hxx> |
54 | | #include <comphelper/random.hxx> |
55 | | #include <docufld.hxx> |
56 | | #include <txtfld.hxx> |
57 | | #include <ndtxt.hxx> |
58 | | #include <view.hxx> |
59 | | #include <viewopt.hxx> |
60 | | #include <wrtsh.hxx> |
61 | | #include <docsh.hxx> |
62 | | #include <doc.hxx> |
63 | | #include <IDocumentUndoRedo.hxx> |
64 | | #if ENABLE_YRS |
65 | | #include <IDocumentState.hxx> |
66 | | #endif |
67 | | #include <SwUndoField.hxx> |
68 | | #include <edtwin.hxx> |
69 | | #include "ShadowOverlayObject.hxx" |
70 | | #include "AnchorOverlayObject.hxx" |
71 | | #include "OverlayRanges.hxx" |
72 | | #include "SidebarTxtControl.hxx" |
73 | | #include "SidebarWinAcc.hxx" |
74 | | |
75 | | #include <memory> |
76 | | |
77 | | namespace{ |
78 | | |
79 | | void collectUIInformation( const OUString& aevent , const OUString& aID ) |
80 | 0 | { |
81 | 0 | EventDescription aDescription; |
82 | 0 | aDescription.aID = aID; |
83 | 0 | aDescription.aParameters = {{"" , ""}}; |
84 | 0 | aDescription.aAction = aevent; |
85 | 0 | aDescription.aParent = "MainWindow"; |
86 | 0 | aDescription.aKeyWord = "SwEditWinUIObject"; |
87 | 0 | UITestLogger::getInstance().logEvent(aDescription); |
88 | 0 | } |
89 | | |
90 | | } |
91 | | |
92 | | namespace SwPostItHelper { |
93 | | |
94 | | void ImportHTML(Outliner& rOutliner, const OUString& rHtml) |
95 | 0 | { |
96 | 0 | OString sHtmlContent(rHtml.toUtf8()); |
97 | 0 | SvMemoryStream aHTMLStream(const_cast<char*>(sHtmlContent.getStr()), |
98 | 0 | sHtmlContent.getLength(), StreamMode::READ); |
99 | 0 | SvKeyValueIteratorRef xValues(new SvKeyValueIterator); |
100 | | // Insert newlines for divs, not normally done, so to keep things simple |
101 | | // only enable that for this case. |
102 | 0 | xValues->Append(SvKeyValue("newline-on-div", "true")); |
103 | 0 | xValues->Append(SvKeyValue("content-type", "text/html;charset=utf-8")); |
104 | 0 | rOutliner.Read(aHTMLStream, "", EETextFormat::Html, xValues.get()); |
105 | 0 | } |
106 | | |
107 | | } |
108 | | |
109 | | namespace sw::annotation { |
110 | | |
111 | | // see AnnotationContents in sd for something similar |
112 | | SwAnnotationWin::SwAnnotationWin( SwEditWin& rEditWin, |
113 | | SwPostItMgr& aMgr, |
114 | | SwAnnotationItem& rSidebarItem, |
115 | | SwFormatField* aField ) |
116 | 0 | : InterimItemWindow(&rEditWin, u"modules/swriter/ui/annotation.ui"_ustr, u"Annotation"_ustr) |
117 | 0 | , mrMgr(aMgr) |
118 | 0 | , mrView(rEditWin.GetView()) |
119 | 0 | , mnDeleteEventId(nullptr) |
120 | 0 | , meSidebarPosition(sw::sidebarwindows::SidebarPosition::NONE) |
121 | 0 | , mPageBorder(0) |
122 | 0 | , mbAnchorRectChanged(false) |
123 | 0 | , mbResolvedStateUpdated(false) |
124 | 0 | , mbMouseOver(false) |
125 | 0 | , mLayoutStatus(SwPostItHelper::INVISIBLE) |
126 | 0 | , mbReadonly(false) |
127 | 0 | , mbIsFollow(false) |
128 | 0 | , mpSidebarItem(&rSidebarItem) |
129 | 0 | , mpAnchorFrame(rSidebarItem.maLayoutInfo.mpAnchorFrame) |
130 | 0 | , mpFormatField(aField) |
131 | 0 | , mpField( static_cast<SwPostItField*>(aField->GetField())) |
132 | 0 | { |
133 | 0 | set_id("Comment"+OUString::number(mpField->GetPostItId())); |
134 | |
|
135 | 0 | m_xContainer->connect_mouse_move(LINK(this, SwAnnotationWin, MouseMoveHdl)); |
136 | |
|
137 | 0 | mpShadow = sidebarwindows::ShadowOverlayObject::CreateShadowOverlayObject( mrView ); |
138 | 0 | if ( mpShadow ) |
139 | 0 | { |
140 | 0 | mpShadow->setVisible(false); |
141 | 0 | } |
142 | |
|
143 | 0 | #if !ENABLE_WASM_STRIP_ACCESSIBILITY |
144 | 0 | if (rSidebarItem.maLayoutInfo.mpAnchorFrame) |
145 | 0 | { |
146 | 0 | mrMgr.ConnectSidebarWinToFrame( *(rSidebarItem.maLayoutInfo.mpAnchorFrame), |
147 | 0 | mpSidebarItem->GetFormatField(), |
148 | 0 | *this ); |
149 | 0 | } |
150 | 0 | #endif |
151 | |
|
152 | 0 | if (SupportsDoubleBuffering()) |
153 | | // When double-buffering, allow parents to paint on our area. That's |
154 | | // necessary when parents paint the complete buffer. |
155 | 0 | SetParentClipMode(ParentClipMode::NoClip); |
156 | 0 | } Unexecuted instantiation: sw::annotation::SwAnnotationWin::SwAnnotationWin(SwEditWin&, SwPostItMgr&, SwAnnotationItem&, SwFormatField*) Unexecuted instantiation: sw::annotation::SwAnnotationWin::SwAnnotationWin(SwEditWin&, SwPostItMgr&, SwAnnotationItem&, SwFormatField*) |
157 | | |
158 | | SwAnnotationWin::~SwAnnotationWin() |
159 | 0 | { |
160 | 0 | disposeOnce(); |
161 | 0 | } |
162 | | |
163 | | void SwAnnotationWin::dispose() |
164 | 0 | { |
165 | 0 | #if !ENABLE_WASM_STRIP_ACCESSIBILITY |
166 | 0 | mrMgr.DisconnectSidebarWinFromFrame( *(mpSidebarItem->maLayoutInfo.mpAnchorFrame), |
167 | 0 | *this ); |
168 | 0 | #endif |
169 | 0 | Disable(); |
170 | |
|
171 | 0 | mxSidebarTextControlWin.reset(); |
172 | 0 | mxSidebarTextControl.reset(); |
173 | |
|
174 | 0 | mxMetadataAuthor.reset(); |
175 | 0 | mxMetadataResolved.reset(); |
176 | 0 | mxMetadataDate.reset(); |
177 | 0 | mxVScrollbar.reset(); |
178 | |
|
179 | 0 | mpAnchor.reset(); |
180 | 0 | mpShadow.reset(); |
181 | |
|
182 | 0 | mpTextRangeOverlay.reset(); |
183 | |
|
184 | 0 | mxMenuButton.reset(); |
185 | |
|
186 | 0 | if (mnDeleteEventId) |
187 | 0 | Application::RemoveUserEvent(mnDeleteEventId); |
188 | |
|
189 | 0 | mpOutliner.reset(); |
190 | 0 | mpOutlinerView.reset(); |
191 | |
|
192 | 0 | InterimItemWindow::dispose(); |
193 | 0 | } |
194 | | |
195 | | void SwAnnotationWin::SetPostItText() |
196 | 0 | { |
197 | | //If the cursor was visible, then make it visible again after |
198 | | //changing text, e.g. fdo#33599 |
199 | 0 | vcl::Cursor *pCursor = GetOutlinerView()->GetEditView().GetCursor(); |
200 | 0 | bool bCursorVisible = pCursor && pCursor->IsVisible(); |
201 | | |
202 | | //If the new text is the same as the old text, keep the same insertion |
203 | | //point .e.g. fdo#33599 |
204 | 0 | mpField = static_cast<SwPostItField*>(mpFormatField->GetField()); |
205 | 0 | OUString sNewText = mpField->GetPar2(); |
206 | 0 | bool bTextUnchanged = sNewText == mpOutliner->GetEditEngine().GetText(); |
207 | 0 | ESelection aOrigSelection(GetOutlinerView()->GetEditView().GetSelection()); |
208 | | |
209 | | // get text from SwPostItField and insert into our textview |
210 | 0 | mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() ); |
211 | 0 | mpOutliner->EnableUndo( false ); |
212 | | #if ENABLE_YRS |
213 | | auto const mode = mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(IYrsTransactionSupplier::Mode::Replay); |
214 | | #endif |
215 | 0 | if( mpField->GetTextObject() ) |
216 | 0 | mpOutliner->SetText( *mpField->GetTextObject() ); |
217 | 0 | else |
218 | 0 | { |
219 | 0 | mpOutliner->Clear(); |
220 | 0 | GetOutlinerView()->SetStyleSheet(SwResId(STR_POOLCOLL_COMMENT)); |
221 | 0 | GetOutlinerView()->InsertText(sNewText); |
222 | 0 | } |
223 | | #if ENABLE_YRS |
224 | | mrView.GetDocShell()->GetDoc()->getIDocumentState().SetYrsMode(mode); |
225 | | #endif |
226 | |
|
227 | 0 | mpOutliner->ClearModifyFlag(); |
228 | 0 | mpOutliner->GetUndoManager().Clear(); |
229 | 0 | mpOutliner->EnableUndo( true ); |
230 | 0 | mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) ); |
231 | 0 | if (bTextUnchanged) |
232 | 0 | GetOutlinerView()->GetEditView().SetSelection(aOrigSelection); |
233 | 0 | if (bCursorVisible) |
234 | 0 | GetOutlinerView()->ShowCursor(); |
235 | 0 | Invalidate(); |
236 | 0 | } |
237 | | |
238 | | void SwAnnotationWin::GeneratePostItName() |
239 | 0 | { |
240 | 0 | if (mpField && mpField->GetName().isEmpty()) |
241 | 0 | { |
242 | 0 | mpField->SetName(sw::mark::MarkBase::GenerateNewName(u"__Annotation__")); |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | | void SwAnnotationWin::SetResolved(bool resolved) |
247 | 0 | { |
248 | 0 | bool oldState = IsResolved(); |
249 | 0 | static_cast<SwPostItField*>(mpFormatField->GetField())->SetResolved(resolved); |
250 | 0 | if (SwWrtShell* pWrtShell = mrView.GetWrtShellPtr()) |
251 | 0 | { |
252 | 0 | const SwViewOption* pVOpt = pWrtShell->GetViewOptions(); |
253 | 0 | mpSidebarItem->mbShow = !IsResolved() || (pVOpt->IsResolvedPostIts()); |
254 | 0 | } |
255 | |
|
256 | 0 | mpTextRangeOverlay.reset(); |
257 | |
|
258 | 0 | if(IsResolved()) |
259 | 0 | mxMetadataResolved->show(); |
260 | 0 | else |
261 | 0 | mxMetadataResolved->hide(); |
262 | |
|
263 | 0 | if(IsResolved() != oldState) |
264 | 0 | { |
265 | 0 | mbResolvedStateUpdated = true; |
266 | | #if ENABLE_YRS |
267 | | // for undo, before UpdateData() |
268 | | mrView.GetDocShell()->GetDoc()->getIDocumentState().YrsNotifySetResolved( |
269 | | GetOutlinerView()->GetEditView().GetYrsCommentId(), |
270 | | *static_cast<SwPostItField const*>(mpFormatField->GetField())); |
271 | | #endif |
272 | 0 | } |
273 | 0 | UpdateData(); |
274 | 0 | Invalidate(); |
275 | 0 | collectUIInformation(u"SETRESOLVED"_ustr,get_id()); |
276 | 0 | } |
277 | | |
278 | | void SwAnnotationWin::ToggleResolved() |
279 | 0 | { |
280 | 0 | SetResolved(!IsResolved()); |
281 | 0 | } |
282 | | |
283 | | void SwAnnotationWin::ToggleResolvedForThread() |
284 | 0 | { |
285 | 0 | auto pTop = GetTopReplyNote(); |
286 | 0 | pTop->ToggleResolved(); |
287 | 0 | mrMgr.UpdateResolvedStatus(pTop); |
288 | 0 | mrMgr.LayoutPostIts(); |
289 | 0 | } |
290 | | |
291 | | sal_uInt32 SwAnnotationWin::GetParaId() |
292 | 0 | { |
293 | 0 | auto pField = static_cast<SwPostItField*>(mpFormatField->GetField()); |
294 | 0 | auto nParaId = pField->GetParaId(); |
295 | 0 | if (nParaId == 0) |
296 | 0 | { |
297 | | // The parent annotation does not have a paraId. This happens when the annotation was just |
298 | | // created, and not imported. paraIds are regenerated upon export, thus this new paraId |
299 | | // is only generated so that children annotations can refer to it |
300 | 0 | nParaId = CreateUniqueParaId(); |
301 | 0 | pField->SetParaId(nParaId); |
302 | 0 | } |
303 | 0 | return nParaId; |
304 | 0 | } |
305 | | |
306 | | sal_uInt32 SwAnnotationWin::CreateUniqueParaId() |
307 | 0 | { |
308 | 0 | return comphelper::rng::uniform_uint_distribution(0, std::numeric_limits<sal_uInt32>::max()); |
309 | 0 | } |
310 | | |
311 | | void SwAnnotationWin::DeleteThread() |
312 | 0 | { |
313 | | // Go to the top and delete each comment one by one |
314 | 0 | SwAnnotationWin* topNote = GetTopReplyNote(); |
315 | 0 | for (SwAnnotationWin* current = topNote;;) |
316 | 0 | { |
317 | 0 | SwAnnotationWin* next = mrMgr.GetNextPostIt(KEY_PAGEDOWN, current); |
318 | 0 | current->mnDeleteEventId = Application::PostUserEvent( LINK( current, SwAnnotationWin, DeleteHdl), nullptr, true ); |
319 | 0 | if (!next || next->GetTopReplyNote() != topNote) |
320 | 0 | return; |
321 | 0 | current = next; |
322 | 0 | } |
323 | 0 | } |
324 | | |
325 | | bool SwAnnotationWin::IsResolved() const |
326 | 0 | { |
327 | 0 | return static_cast<SwPostItField*>(mpFormatField->GetField())->GetResolved(); |
328 | 0 | } |
329 | | |
330 | | bool SwAnnotationWin::IsThreadResolved() |
331 | 0 | { |
332 | | /// First Get the top note |
333 | | // then iterate downwards checking resolved status |
334 | 0 | SwAnnotationWin* topNote = GetTopReplyNote(); |
335 | 0 | for (SwAnnotationWin* current = topNote;;) |
336 | 0 | { |
337 | 0 | if (!current->IsResolved()) |
338 | 0 | return false; |
339 | 0 | current = mrMgr.GetNextPostIt(KEY_PAGEDOWN, current); |
340 | 0 | if (!current || current->GetTopReplyNote() != topNote) |
341 | 0 | return true; |
342 | 0 | } |
343 | 0 | } |
344 | | |
345 | | bool SwAnnotationWin::IsRootNote() const |
346 | 0 | { |
347 | 0 | return static_cast<SwPostItField*>(mpFormatField->GetField())->GetParentPostItId() == 0; |
348 | 0 | } |
349 | | |
350 | | void SwAnnotationWin::SetAsRoot() |
351 | 0 | { |
352 | 0 | if (!IsRootNote()) |
353 | 0 | { |
354 | 0 | SwPostItField* pPostIt = static_cast<SwPostItField*>(mpFormatField->GetField()); |
355 | 0 | pPostIt->SetParentId(0); |
356 | 0 | pPostIt->SetParentPostItId(0); |
357 | 0 | pPostIt->SetParentName(SwMarkName()); |
358 | 0 | mrMgr.MoveSubthreadToRoot(this); |
359 | 0 | mpFormatField->Broadcast(SwFormatFieldHint(nullptr, SwFormatFieldHintWhich::CHANGED)); |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | | void SwAnnotationWin::UpdateData() |
364 | 0 | { |
365 | 0 | if ( mpOutliner->IsModified() || mbResolvedStateUpdated ) |
366 | 0 | { |
367 | 0 | IDocumentUndoRedo & rUndoRedo( |
368 | 0 | mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo()); |
369 | 0 | std::unique_ptr<SwField> pOldField; |
370 | 0 | if (rUndoRedo.DoesUndo()) |
371 | 0 | { |
372 | 0 | pOldField = mpField->Copy(); |
373 | 0 | } |
374 | 0 | mpField->SetPar2(mpOutliner->GetEditEngine().GetText()); |
375 | 0 | mpField->SetTextObject(mpOutliner->CreateParaObject()); |
376 | 0 | if (rUndoRedo.DoesUndo()) |
377 | 0 | { |
378 | 0 | SwTextField *const pTextField = mpFormatField->GetTextField(); |
379 | 0 | SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() ); |
380 | 0 | rUndoRedo.AppendUndo( |
381 | 0 | std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, true)); |
382 | | #if ENABLE_YRS |
383 | | mrView.GetDocShell()->GetDoc()->getIDocumentState().YrsEndUndo(); |
384 | | #endif |
385 | 0 | } |
386 | | // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one) |
387 | 0 | mrMgr.SetLayout(); |
388 | | // #i98686# if we have several views, all notes should update their text |
389 | 0 | if(mbResolvedStateUpdated) |
390 | 0 | mpFormatField->Broadcast(SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::RESOLVED)); |
391 | 0 | else |
392 | 0 | mpFormatField->Broadcast(SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::CHANGED)); |
393 | 0 | mrView.GetDocShell()->SetModified(); |
394 | 0 | } |
395 | 0 | mpOutliner->ClearModifyFlag(); |
396 | 0 | mpOutliner->GetUndoManager().Clear(); |
397 | 0 | mbResolvedStateUpdated = false; |
398 | 0 | } |
399 | | |
400 | | void SwAnnotationWin::Delete() |
401 | 0 | { |
402 | 0 | collectUIInformation(u"DELETE"_ustr,get_id()); |
403 | 0 | SwWrtShell* pWrtShell = mrView.GetWrtShellPtr(); |
404 | 0 | if (!(pWrtShell && pWrtShell->GotoField(*mpFormatField))) |
405 | 0 | return; |
406 | | |
407 | 0 | if ( mrMgr.GetActiveSidebarWin() == this) |
408 | 0 | { |
409 | 0 | mrMgr.SetActiveSidebarWin(nullptr); |
410 | | // if the note is empty, the previous line will send a delete event, but we are already there |
411 | 0 | if (mnDeleteEventId) |
412 | 0 | { |
413 | 0 | Application::RemoveUserEvent(mnDeleteEventId); |
414 | 0 | mnDeleteEventId = nullptr; |
415 | 0 | } |
416 | 0 | } |
417 | | // we delete the field directly, the Mgr cleans up the PostIt by listening |
418 | 0 | GrabFocusToDocument(); |
419 | 0 | pWrtShell->ClearMark(); |
420 | 0 | auto restoreGuard = mrMgr.ConfigureForCommentDelete(); |
421 | 0 | pWrtShell->DelRight(); |
422 | 0 | } |
423 | | |
424 | | void SwAnnotationWin::GotoPos() |
425 | 0 | { |
426 | 0 | mrView.GetDocShell()->GetWrtShell()->GotoField(*mpFormatField); |
427 | 0 | } |
428 | | |
429 | | sal_uInt32 SwAnnotationWin::MoveCaret() |
430 | 0 | { |
431 | | // if this is an answer, do not skip over all following ones, but insert directly behind the current one |
432 | | // but when just leaving a note, skip all following ones as well to continue typing |
433 | 0 | return mrMgr.IsAnswer() |
434 | 0 | ? 1 |
435 | 0 | : 1 + CountFollowing(); |
436 | 0 | } |
437 | | |
438 | | // counts how many SwPostItField we have right after the current one |
439 | | sal_uInt32 SwAnnotationWin::CountFollowing() |
440 | 0 | { |
441 | 0 | SwTextField* pTextField = mpFormatField->GetTextField(); |
442 | 0 | SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() ); |
443 | |
|
444 | 0 | for (sal_Int32 n = 1;; ++n) |
445 | 0 | { |
446 | 0 | SwTextAttr * pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt( |
447 | 0 | aPosition.GetContentIndex() + n, |
448 | 0 | RES_TXTATR_ANNOTATION ); |
449 | 0 | if (!pTextAttr) |
450 | 0 | return n - 1; |
451 | 0 | const SwField* pField = pTextAttr->GetFormatField().GetField(); |
452 | 0 | if (!pField || pField->Which() != SwFieldIds::Postit) |
453 | 0 | return n - 1; |
454 | 0 | } |
455 | 0 | } |
456 | | |
457 | | void SwAnnotationWin::InitAnswer(OutlinerParaObject const & rText) |
458 | 0 | { |
459 | | // If tiled annotations is off in lok case, skip adding additional reply text. |
460 | 0 | if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations()) |
461 | 0 | return; |
462 | | |
463 | | //collect our old meta data |
464 | 0 | SwAnnotationWin* pWin = mrMgr.GetNextPostIt(KEY_PAGEUP, this); |
465 | 0 | if (!pWin) |
466 | 0 | return; |
467 | | |
468 | 0 | const SvtSysLocale aSysLocale; |
469 | 0 | const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData(); |
470 | 0 | SwRewriter aRewriter; |
471 | 0 | aRewriter.AddRule(UndoArg1, pWin->GetAuthor()); |
472 | 0 | const OUString aText = aRewriter.Apply(SwResId(STR_REPLY)) |
473 | 0 | + " (" + rLocalData.getDate( pWin->GetDate()) |
474 | 0 | + ", " + rLocalData.getTime( pWin->GetTime(), false) |
475 | 0 | + "): \""; |
476 | 0 | GetOutlinerView()->InsertText(aText); |
477 | | |
478 | | // insert old, selected text or "..." |
479 | | // TODO: iterate over all paragraphs, not only first one to find out if it is empty |
480 | 0 | if (rText.GetTextObject().HasText(0)) |
481 | 0 | GetOutlinerView()->GetEditView().InsertText(rText.GetTextObject()); |
482 | 0 | else |
483 | 0 | GetOutlinerView()->InsertText(u"..."_ustr); |
484 | 0 | GetOutlinerView()->InsertText(u"\"\n"_ustr); |
485 | |
|
486 | 0 | GetOutlinerView()->SetSelection(ESelection::All()); |
487 | 0 | SfxItemSet aAnswerSet( mrView.GetDocShell()->GetPool() ); |
488 | 0 | aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT)); |
489 | 0 | aAnswerSet.Put(SvxPostureItem(ITALIC_NORMAL,EE_CHAR_ITALIC)); |
490 | 0 | GetOutlinerView()->SetAttribs(aAnswerSet); |
491 | 0 | GetOutlinerView()->SetSelection(ESelection::AtEnd()); |
492 | | |
493 | | //remove all attributes and reset our standard ones |
494 | 0 | GetOutlinerView()->GetEditView().RemoveAttribsKeepLanguages(true); |
495 | | // let's insert an undo step so the initial text can be easily deleted |
496 | | // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr |
497 | 0 | mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() ); |
498 | 0 | IDocumentUndoRedo & rUndoRedo( |
499 | 0 | mrView.GetDocShell()->GetDoc()->GetIDocumentUndoRedo()); |
500 | 0 | std::unique_ptr<SwField> pOldField; |
501 | 0 | if (rUndoRedo.DoesUndo()) |
502 | 0 | { |
503 | 0 | pOldField = mpField->Copy(); |
504 | 0 | } |
505 | 0 | mpField->SetPar2(mpOutliner->GetEditEngine().GetText()); |
506 | 0 | mpField->SetTextObject(mpOutliner->CreateParaObject()); |
507 | 0 | if (rUndoRedo.DoesUndo()) |
508 | 0 | { |
509 | 0 | SwTextField *const pTextField = mpFormatField->GetTextField(); |
510 | 0 | SwPosition aPosition( pTextField->GetTextNode(), pTextField->GetStart() ); |
511 | 0 | rUndoRedo.AppendUndo( |
512 | 0 | std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, true)); |
513 | | #if ENABLE_YRS |
514 | | // no! there is a StartUndo wrapping this mrView.GetDocShell()->GetDoc()->getIDocumentState().YrsEndUndo(); |
515 | | #endif |
516 | 0 | } |
517 | 0 | mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) ); |
518 | 0 | mpOutliner->ClearModifyFlag(); |
519 | 0 | mpOutliner->GetUndoManager().Clear(); |
520 | 0 | } |
521 | | |
522 | | void SwAnnotationWin::UpdateText(const OUString& aText) |
523 | 0 | { |
524 | 0 | mpOutliner->Clear(); |
525 | 0 | GetOutlinerView()->InsertText(aText); |
526 | 0 | UpdateData(); |
527 | 0 | } |
528 | | |
529 | | void SwAnnotationWin::UpdateHTML(const OUString& rHtml) |
530 | 0 | { |
531 | 0 | mpOutliner->Clear(); |
532 | 0 | SwPostItHelper::ImportHTML(*mpOutliner, rHtml); |
533 | 0 | UpdateData(); |
534 | 0 | } |
535 | | |
536 | | OString SwAnnotationWin::GetSimpleHtml() const |
537 | 0 | { |
538 | 0 | return GetOutlinerView()->GetEditView().GetSimpleHtml(); |
539 | 0 | } |
540 | | |
541 | | bool SwAnnotationWin::IsReadOnly() const |
542 | 0 | { |
543 | 0 | return mbReadonly; |
544 | 0 | } |
545 | | |
546 | | bool SwAnnotationWin::IsReadOnlyOrProtected() const |
547 | 0 | { |
548 | 0 | return IsReadOnly() || |
549 | 0 | GetLayoutStatus() == SwPostItHelper::DELETED || |
550 | 0 | ( mpFormatField && mpFormatField->IsProtect() ); |
551 | 0 | } |
552 | | |
553 | | OUString SwAnnotationWin::GetAuthor() const |
554 | 0 | { |
555 | 0 | return mpField->GetPar1(); |
556 | 0 | } |
557 | | |
558 | | Date SwAnnotationWin::GetDate() const |
559 | 0 | { |
560 | 0 | return mpField->GetDate(); |
561 | 0 | } |
562 | | |
563 | | tools::Time SwAnnotationWin::GetTime() const |
564 | 0 | { |
565 | 0 | return mpField->GetTime(); |
566 | 0 | } |
567 | | |
568 | | FactoryFunction SwAnnotationWin::GetUITestFactory() const |
569 | 0 | { |
570 | 0 | return CommentUIObject::create; |
571 | 0 | } |
572 | | |
573 | | } // end of namespace sw::annotation |
574 | | |
575 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |