LibreOffice Module sw (master)  1
AnnotationWin.cxx
Go to the documentation of this file.
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 <AnnotationWin.hxx>
21 
22 #include "AnnotationMenuButton.hxx"
23 #include <PostItMgr.hxx>
24 
25 #include <strings.hrc>
26 #include <cmdid.h>
27 
28 #include <vcl/edit.hxx>
29 #include <vcl/menu.hxx>
30 #include <vcl/scrbar.hxx>
31 #include <vcl/svapp.hxx>
32 
33 #include <svl/undo.hxx>
35 #include <unotools/syslocale.hxx>
36 #include <svl/languageoptions.hxx>
37 
38 #include <editeng/eeitem.hxx>
39 #include <editeng/postitem.hxx>
40 #include <editeng/fhgtitem.hxx>
41 #include <editeng/langitem.hxx>
42 
43 #include <editeng/editview.hxx>
44 #include <editeng/outliner.hxx>
45 #include <editeng/editeng.hxx>
46 #include <editeng/editobj.hxx>
47 #include <editeng/outlobj.hxx>
48 
49 #include <comphelper/lok.hxx>
50 #include <docufld.hxx>
51 #include <txtfld.hxx>
52 #include <ndtxt.hxx>
53 #include <view.hxx>
54 #include <viewopt.hxx>
55 #include <wrtsh.hxx>
56 #include <docsh.hxx>
57 #include <doc.hxx>
58 #include <IDocumentUndoRedo.hxx>
59 #include <SwUndoField.hxx>
60 #include <edtwin.hxx>
61 #include "ShadowOverlayObject.hxx"
62 #include "AnchorOverlayObject.hxx"
63 #include "OverlayRanges.hxx"
64 #include "SidebarTxtControl.hxx"
65 
66 #include <memory>
67 
68 namespace sw { namespace annotation {
69 
71  SwPostItMgr& aMgr,
72  SwSidebarItem& rSidebarItem,
73  SwFormatField* aField )
74  : Window(&rEditWin)
75  , maBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/annotationmenu.ui", "")
76  , mrMgr(aMgr)
77  , mrView(rEditWin.GetView())
78  , mnEventId(nullptr)
79  , mpSidebarTextControl(nullptr)
80  , mpVScrollbar(nullptr)
81  , mpMetadataAuthor(nullptr)
82  , mpMetadataDate(nullptr)
83  , mpMenuButton(nullptr)
84  , mColorAnchor()
85  , mColorDark()
86  , mColorLight()
87  , mChangeColor()
88  , meSidebarPosition(sw::sidebarwindows::SidebarPosition::NONE)
89  , mPosSize()
90  , mAnchorRect()
91  , mPageBorder(0)
92  , mbAnchorRectChanged(false)
93  , mbResolvedStateUpdated(false)
94  , mbMouseOver(false)
95  , mLayoutStatus(SwPostItHelper::INVISIBLE)
96  , mbReadonly(false)
97  , mbIsFollow(false)
98  , mrSidebarItem(rSidebarItem)
99  , mpAnchorFrame(rSidebarItem.maLayoutInfo.mpAnchorFrame)
100  , mpFormatField(aField)
101  , mpField( static_cast<SwPostItField*>(aField->GetField()))
102  , mpButtonPopup(nullptr)
103 {
105  if ( mpShadow )
106  {
107  mpShadow->setVisible(false);
108  }
109 
112  *this );
113 
115  // When double-buffering, allow parents to paint on our area. That's
116  // necessary when parents paint the complete buffer.
117  SetParentClipMode(ParentClipMode::NoClip);
118 }
119 
121 {
122  disposeOnce();
123 }
124 
126 {
129 
130  if (IsDisposed())
131  return;
132 
134  *this );
135 
136  Disable();
137 
138  if ( mpSidebarTextControl )
139  {
140  if ( mpOutlinerView )
141  {
142  mpOutlinerView->SetWindow( nullptr );
143  }
144  }
146 
147  mpOutlinerView.reset();
148  mpOutliner.reset();
149 
150  if (mpMetadataAuthor)
151  {
152  mpMetadataAuthor->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
153  }
155 
156  if (mpMetadataResolved)
157  {
158  mpMetadataResolved->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
159  }
161 
162  if (mpMetadataDate)
163  {
164  mpMetadataDate->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
165  }
167 
168  if (mpVScrollbar)
169  {
170  mpVScrollbar->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
171  }
173 
174  RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
175 
176  mpAnchor.reset();
177  mpShadow.reset();
178 
179  mpTextRangeOverlay.reset();
180 
182 
183  if (mnEventId)
185 
187 }
188 
190 {
191  //If the cursor was visible, then make it visible again after
192  //changing text, e.g. fdo#33599
194  bool bCursorVisible = pCursor && pCursor->IsVisible();
195 
196  //If the new text is the same as the old text, keep the same insertion
197  //point .e.g. fdo#33599
198  mpField = static_cast<SwPostItField*>(mpFormatField->GetField());
199  OUString sNewText = mpField->GetPar2();
200  bool bTextUnchanged = sNewText == mpOutliner->GetEditEngine().GetText();
201  ESelection aOrigSelection(GetOutlinerView()->GetEditView().GetSelection());
202 
203  // get text from SwPostItField and insert into our textview
204  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
205  mpOutliner->EnableUndo( false );
206  if( mpField->GetTextObject() )
207  mpOutliner->SetText( *mpField->GetTextObject() );
208  else
209  {
210  mpOutliner->Clear();
212  GetOutlinerView()->InsertText(sNewText);
213  }
214 
215  mpOutliner->ClearModifyFlag();
216  mpOutliner->GetUndoManager().Clear();
217  mpOutliner->EnableUndo( true );
218  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
219  if (bTextUnchanged)
220  GetOutlinerView()->GetEditView().SetSelection(aOrigSelection);
221  if (bCursorVisible)
223  Invalidate();
224 }
225 
226 void SwAnnotationWin::SetResolved(bool resolved)
227 {
228  bool oldState = IsResolved();
229  static_cast<SwPostItField*>(mpFormatField->GetField())->SetResolved(resolved);
230  const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
231  mrSidebarItem.bShow = !IsResolved() || (pVOpt->IsResolvedPostIts());
232 
233  mpTextRangeOverlay.reset();
234 
235  if(IsResolved())
237  else
239 
240  if(IsResolved() != oldState)
241  mbResolvedStateUpdated = true;
242  UpdateData();
243  Invalidate();
244 }
245 
247 {
249 }
250 
252 {
256 }
257 
259 {
260  return static_cast<SwPostItField*>(mpFormatField->GetField())->GetResolved();
261 }
262 
264 {
265  // Not const because GetTopReplyNote isn't.
266  return GetTopReplyNote()->IsResolved();
267 }
268 
270 {
271  if ( mpOutliner->IsModified() || mbResolvedStateUpdated )
272  {
273  IDocumentUndoRedo & rUndoRedo(
275  std::unique_ptr<SwField> pOldField;
276  if (rUndoRedo.DoesUndo())
277  {
278  pOldField = mpField->Copy();
279  }
280  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
281  mpField->SetTextObject(mpOutliner->CreateParaObject());
282  if (rUndoRedo.DoesUndo())
283  {
284  SwTextField *const pTextField = mpFormatField->GetTextField();
285  SwPosition aPosition( pTextField->GetTextNode() );
286  aPosition.nContent = pTextField->GetStart();
287  rUndoRedo.AppendUndo(
288  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
289  }
290  // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one)
291  mrMgr.SetLayout();
292  // #i98686# if we have several views, all notes should update their text
295  else
298  }
299  mpOutliner->ClearModifyFlag();
300  mpOutliner->GetUndoManager().Clear();
301  mbResolvedStateUpdated = false;
302 }
303 
305 {
307  {
308  if ( mrMgr.GetActiveSidebarWin() == this)
309  {
310  mrMgr.SetActiveSidebarWin(nullptr);
311  // if the note is empty, the previous line will send a delete event, but we are already there
312  if (mnEventId)
313  {
315  mnEventId = nullptr;
316  }
317  }
318  // we delete the field directly, the Mgr cleans up the PostIt by listening
322  }
323 }
324 
326 {
328 }
329 
331 {
332  // if this is an answer, do not skip over all following ones, but insert directly behind the current one
333  // but when just leaving a note, skip all following ones as well to continue typing
334  return mrMgr.IsAnswer()
335  ? 1
336  : 1 + CountFollowing();
337 }
338 
339 // returns a non-zero postit parent id, if exists, otherwise 0 for root comments
341 {
342  SwTextField* pTextField = mpFormatField->GetTextField();
343  SwPosition aPosition( pTextField->GetTextNode() );
344  aPosition.nContent = pTextField->GetStart();
345  SwTextAttr * const pTextAttr =
346  pTextField->GetTextNode().GetTextAttrForCharAt(
347  aPosition.nContent.GetIndex() - 1,
349  const SwField* pField = pTextAttr ? pTextAttr->GetFormatField().GetField() : nullptr;
350  sal_uInt32 nParentId = 0;
351  if (pField && pField->Which() == SwFieldIds::Postit)
352  {
353  const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pField);
354  nParentId = pPostItField->GetPostItId();
355  }
356  return nParentId;
357 }
358 
359 // counts how many SwPostItField we have right after the current one
361 {
362  sal_uInt32 aCount = 1; // we start with 1, so we have to subtract one at the end again
363  SwTextField* pTextField = mpFormatField->GetTextField();
364  SwPosition aPosition( pTextField->GetTextNode() );
365  aPosition.nContent = pTextField->GetStart();
366 
367  SwTextAttr * pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
368  aPosition.nContent.GetIndex() + 1,
370  SwField* pField = pTextAttr
371  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
372  : nullptr;
373  while ( pField && ( pField->Which()== SwFieldIds::Postit ) )
374  {
375  aCount++;
376  pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
377  aPosition.nContent.GetIndex() + aCount,
379  pField = pTextAttr
380  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
381  : nullptr;
382  }
383  return aCount - 1;
384 }
385 
387 {
388  mpButtonPopup = maBuilder.get_menu("menu");
389  sal_uInt16 nByAuthorId = mpButtonPopup->GetItemId("deleteby");
390  OUString aText = mpButtonPopup->GetItemText(nByAuthorId);
391  SwRewriter aRewriter;
392  aRewriter.AddRule(UndoArg1,GetAuthor());
393  aText = aRewriter.Apply(aText);
394  mpButtonPopup->SetItemText(nByAuthorId, aText);
395  VclPtrInstance<AnnotationMenuButton> pMenuButton( *this );
396  pMenuButton->SetPopupMenu( mpButtonPopup );
397  pMenuButton->Show();
398  return pMenuButton;
399 }
400 
402 {
403  // If tiled annotations is off in lok case, skip adding additional reply text.
405  return;
406 
407  //collect our old meta data
409  const SvtSysLocale aSysLocale;
410  const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
411  SwRewriter aRewriter;
412  aRewriter.AddRule(UndoArg1, pWin->GetAuthor());
413  const OUString aText = aRewriter.Apply(SwResId(STR_REPLY))
414  + " (" + rLocalData.getDate( pWin->GetDate())
415  + ", " + rLocalData.getTime( pWin->GetTime(), false)
416  + "): \"";
417  GetOutlinerView()->InsertText(aText);
418 
419  // insert old, selected text or "..."
420  // TODO: iterate over all paragraphs, not only first one to find out if it is empty
421  if (!pText->GetTextObject().GetText(0).isEmpty())
423  else
424  GetOutlinerView()->InsertText("...");
425  GetOutlinerView()->InsertText("\"\n");
426 
428  SfxItemSet aAnswerSet( mrView.GetDocShell()->GetPool() );
429  aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT));
431  GetOutlinerView()->SetAttribs(aAnswerSet);
433 
434  //remove all attributes and reset our standard ones
437  // lets insert an undo step so the initial text can be easily deleted
438  // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr
439  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
440  IDocumentUndoRedo & rUndoRedo(
442  std::unique_ptr<SwField> pOldField;
443  if (rUndoRedo.DoesUndo())
444  {
445  pOldField = mpField->Copy();
446  }
447  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
448  mpField->SetTextObject(mpOutliner->CreateParaObject());
449  if (rUndoRedo.DoesUndo())
450  {
451  SwTextField *const pTextField = mpFormatField->GetTextField();
452  SwPosition aPosition( pTextField->GetTextNode() );
453  aPosition.nContent = pTextField->GetStart();
454  rUndoRedo.AppendUndo(
455  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
456  }
457  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
458  mpOutliner->ClearModifyFlag();
459  mpOutliner->GetUndoManager().Clear();
460 }
461 
462 void SwAnnotationWin::UpdateText(const OUString& aText)
463 {
464  mpOutliner->Clear();
465  GetOutlinerView()->InsertText(aText);
466  UpdateData();
467 }
468 
470 {
471  // set initial language for outliner
473  sal_uInt16 nLangWhichId = 0;
474  switch (nScriptType)
475  {
476  case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
477  case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
478  case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
479  default: OSL_FAIL("GetLanguage: wrong script type");
480  }
481  return SvxLanguageItem(mpField->GetLanguage(),nLangWhichId);
482 }
483 
485 {
486  return mbReadonly ||
489 }
490 
492 {
493  return mpField->GetPar1();
494 }
495 
497 {
498  return mpField->GetDate();
499 }
500 
502 {
503  return mpField->GetTime();
504 }
505 
506 } } // end of namespace sw::annotation
507 
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Date GetDate() const
Definition: docufld.hxx:474
virtual void SetModified(bool=true) override
Definition: docsh2.cxx:1402
Marks a position in the document model.
Definition: pam.hxx:35
#define EE_CHAR_LANGUAGE_CJK
const SwField * GetField() const
Definition: fmtfld.hxx:71
void GetSelection(struct ESelection &rSel, SvxTextForwarder const *pForwarder)
void InsertText(const OUString &rNew, bool bSelect=false)
LanguageType GetLanguage() const
Language at field position.
Definition: fldbas.hxx:392
const SwFrame * mpAnchorFrame
VclPtr< MenuButton > mpMenuButton
static std::unique_ptr< ShadowOverlayObject > CreateShadowOverlayObject(SwView const &rDocView)
OutlinerParaObject * IsAnswer()
Definition: PostItMgr.hxx:258
#define EE_CHAR_LANGUAGE
bool IsProtect() const
Definition: atrfld.cxx:335
#define KEY_PAGEUP
void ShowCursor(bool bGotoCursor=true, bool bActivate=false)
void disposeAndClear()
Base class of all fields.
Definition: fldbas.hxx:279
virtual void SetPar2(const OUString &rStr) override
set the PostIt's text
Definition: docufld.cxx:1811
tools::Time GetTime() const
Definition: docufld.hxx:475
std::unique_ptr< sw::sidebarwindows::ShadowOverlayObject > mpShadow
SwAnnotationWin(SwEditWin &rEditWin, SwPostItMgr &aMgr, SwSidebarItem &rSidebarItem, SwFormatField *aField)
virtual OUString GetPar1() const override
Author.
Definition: docufld.cxx:1805
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
void SetActiveSidebarWin(sw::annotation::SwAnnotationWin *p)
Definition: PostItMgr.cxx:2152
void SetTextObject(std::unique_ptr< OutlinerParaObject > pText)
Definition: docufld.cxx:1829
Dialog to specify the properties of date form field.
Definition: accfrmobj.cxx:38
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
virtual void dispose() override
bool DelRight()
Definition: delete.cxx:282
SwTextAttr * GetTextAttrForCharAt(const sal_Int32 nIndex, const sal_uInt16 nWhich=RES_TXTATR_END) const
get the text attribute at position nIndex which owns the dummy character CH_TXTATR_* at that position...
Definition: ndtxt.cxx:3059
SwPostItHelper::SwLayoutStatus GetLayoutStatus()
const LocaleDataWrapper & GetLocaleData() const
NONE
std::unique_ptr< sw::overlay::OverlayRanges > mpTextRangeOverlay
void DisconnectSidebarWinFromFrame(const SwFrame &rFrame, sw::annotation::SwAnnotationWin &rSidebarWin)
Definition: PostItMgr.cxx:2392
SwIndex nContent
Definition: pam.hxx:38
const SwTextField * GetTextField() const
Definition: fmtfld.hxx:89
vcl::Cursor * GetCursor() const
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
#define EE_CHAR_ITALIC
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
static SvtScriptType GetScriptTypeOfLanguage(LanguageType nLang)
OUString GetText(sal_Int32 nPara) const
EditView & GetEditView() const
SfxItemPool & GetPool() const
std::unique_ptr< Outliner > mpOutliner
static void RemoveUserEvent(ImplSVEvent *nUserEvent)
virtual ~SwAnnotationWin() override
SwDoc * GetDoc()
returns Doc. But be careful!
Definition: docsh.hxx:203
void ConnectSidebarWinToFrame(const SwFrame &rFrame, const SwFormatField &rFormatField, sw::annotation::SwAnnotationWin &rSidebarWin)
Definition: PostItMgr.cxx:2375
sal_uInt32 GetPostItId() const
Definition: docufld.hxx:476
const EditTextObject & GetTextObject() const
SvtScriptType
virtual std::unique_ptr< SwField > Copy() const override
Definition: docufld.cxx:1786
std::unique_ptr< OutlinerView > mpOutlinerView
void SetAttribs(const SfxItemSet &)
SwAnnotationWin * GetTopReplyNote()
Find the first annotation for the thread which this annotation is in.
void InitAnswer(OutlinerParaObject const *pText)
#define EE_PARA_ALL
Window class for the Writer edit area, this is the one handling mouse and keyboard events and doing t...
Definition: edtwin.hxx:58
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:43
bool IsResolvedPostIts() const
Definition: viewopt.hxx:261
sal_uInt16 GetItemId(sal_uInt16 nPos) const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:29
SwWrtShell * GetWrtShell()
Access to the SwWrtShell belonging to SwView.
Definition: docsh.hxx:224
void GrabFocusToDocument()
#define EE_CHAR_FONTHEIGHT
void UpdateText(const OUString &aText)
void InsertText(const OUString &rNew, bool bSelect=false)
OUString SwResId(const char *pId)
Definition: swmodule.cxx:191
OUString GetItemText(sal_uInt16 nItemId) const
sal_uInt32 CalcParent()
Calculate parent postit id of current annotation window.
SwDocShell * GetDocShell()
Definition: view.cxx:1127
void Disable(bool bChild=true)
SwLayoutInfo maLayoutInfo
void LayoutPostIts()
Definition: PostItMgr.cxx:690
OUString getDate(const Date &rDate) const
void Broadcast(const SfxHint &rHint)
void SetSelection(const ESelection &)
const OutlinerParaObject * GetTextObject() const
Definition: docufld.hxx:490
SwWrtShell * GetWrtShellPtr() const
Definition: view.hxx:401
bool GotoField(const SwFormatField &rField)
Definition: wrtsh3.cxx:70
void disposeBuilder()
SwFieldIds Which() const
ResId.
Definition: fldbas.cxx:202
std::unique_ptr< sw::sidebarwindows::AnchorOverlayObject > mpAnchor
ITALIC_NORMAL
VclPtr< sw::sidebarwindows::SidebarTextControl > mpSidebarTextControl
const SwViewOption * GetViewOptions() const
Definition: viewsh.hxx:426
void SetLayout()
Definition: PostItMgr.hxx:203
#define RES_TXTATR_ANNOTATION
Definition: hintids.hxx:153
SlideSorterView & mrView
#define EE_TEXTPOS_MAX_COUNT
PopupMenu * get_menu(const OString &sID)
void ClearMark()
Definition: crsrsh.cxx:926
bool IsDisposed() const
bool IsVisible() const
sw::annotation::SwAnnotationWin * GetActiveSidebarWin()
Definition: PostItMgr.hxx:236
void SetSelection(const ESelection &rNewSel)
void UpdateResolvedStatus(sw::annotation::SwAnnotationWin *topNote)
Definition: PostItMgr.cxx:2455
sw::annotation::SwAnnotationWin * GetNextPostIt(sal_uInt16 aDirection, sw::annotation::SwAnnotationWin *aPostIt)
Definition: PostItMgr.cxx:1760
VclPtr< ScrollBar > mpVScrollbar
virtual OUString GetPar2() const override
Text.
Definition: docufld.cxx:1817
void RemoveEventListener(const Link< VclWindowEvent &, void > &rEventListener)
OUString getTime(const tools::Time &rTime, bool bSec=true, bool b100Sec=false) const
SwTextNode & GetTextNode() const
Definition: txtfld.hxx:53
#define EE_PARA_MAX_COUNT
#define EE_CHAR_LANGUAGE_CTL
bool SupportsDoubleBuffering() const
virtual const SwFormatField & GetFormatField() const =0
virtual void dispose() override
void RemoveAttribsKeepLanguages(bool bRemoveParaAttribs)
#define EE_TEXTPOS_ALL
VclPtr< PopupMenu > mpButtonPopup
VclPtr< MenuButton > CreateMenuButton()
void Show(bool bVisible=true, ShowFlags nFlags=ShowFlags::NONE)
void SetItemText(sal_uInt16 nItemId, const OUString &rStr)