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 
32 #include <svl/undo.hxx>
34 #include <unotools/syslocale.hxx>
35 #include <svl/languageoptions.hxx>
36 
37 #include <editeng/eeitem.hxx>
38 #include <editeng/postitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/langitem.hxx>
41 
42 #include <editeng/editview.hxx>
43 #include <editeng/outliner.hxx>
44 #include <editeng/editeng.hxx>
45 #include <editeng/editobj.hxx>
46 #include <editeng/outlobj.hxx>
47 
48 #include <comphelper/lok.hxx>
49 #include <docufld.hxx>
50 #include <txtfld.hxx>
51 #include <ndtxt.hxx>
52 #include <view.hxx>
53 #include <wrtsh.hxx>
54 #include <docsh.hxx>
55 #include <doc.hxx>
56 #include <IDocumentUndoRedo.hxx>
57 #include <SwUndoField.hxx>
58 #include <edtwin.hxx>
59 #include "ShadowOverlayObject.hxx"
60 #include "AnchorOverlayObject.hxx"
61 #include "OverlayRanges.hxx"
62 #include "SidebarTxtControl.hxx"
63 
64 #include <memory>
65 
66 namespace sw { namespace annotation {
67 
69  SwPostItMgr& aMgr,
70  SwSidebarItem& rSidebarItem,
71  SwFormatField* aField )
72  : Window(&rEditWin)
73  , maBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/annotationmenu.ui", "")
74  , mrMgr(aMgr)
75  , mrView(rEditWin.GetView())
76  , mnEventId(nullptr)
77  , mpSidebarTextControl(nullptr)
78  , mpVScrollbar(nullptr)
79  , mpMetadataAuthor(nullptr)
80  , mpMetadataDate(nullptr)
81  , mpMenuButton(nullptr)
82  , mColorAnchor()
83  , mColorDark()
84  , mColorLight()
85  , mChangeColor()
86  , meSidebarPosition(sw::sidebarwindows::SidebarPosition::NONE)
87  , mPosSize()
88  , mAnchorRect()
89  , mPageBorder(0)
90  , mbAnchorRectChanged(false)
91  , mbMouseOver(false)
92  , mLayoutStatus(SwPostItHelper::INVISIBLE)
93  , mbReadonly(false)
94  , mbIsFollow(false)
95  , mrSidebarItem(rSidebarItem)
96  , mpAnchorFrame(rSidebarItem.maLayoutInfo.mpAnchorFrame)
97  , mpFormatField(aField)
98  , mpField( static_cast<SwPostItField*>(aField->GetField()))
99  , mpButtonPopup(nullptr)
100 {
102  if ( mpShadow )
103  {
104  mpShadow->setVisible(false);
105  }
106 
109  *this );
110 
112  // When double-buffering, allow parents to paint on our area. That's
113  // necessary when parents paint the complete buffer.
114  SetParentClipMode(ParentClipMode::NoClip);
115 }
116 
118 {
119  disposeOnce();
120 }
121 
123 {
126 
127  if (IsDisposed())
128  return;
129 
131  *this );
132 
133  Disable();
134 
135  if ( mpSidebarTextControl )
136  {
137  if ( mpOutlinerView )
138  {
139  mpOutlinerView->SetWindow( nullptr );
140  }
141  }
143 
144  mpOutlinerView.reset();
145  mpOutliner.reset();
146 
147  if (mpMetadataAuthor)
148  {
149  mpMetadataAuthor->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
150  }
152 
153  if (mpMetadataDate)
154  {
155  mpMetadataDate->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
156  }
158 
159  if (mpVScrollbar)
160  {
161  mpVScrollbar->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
162  }
164 
165  RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
166 
167  mpAnchor.reset();
168  mpShadow.reset();
169 
170  mpTextRangeOverlay.reset();
171 
173 
174  if (mnEventId)
176 
178 }
179 
181 {
182  //If the cursor was visible, then make it visible again after
183  //changing text, e.g. fdo#33599
185  bool bCursorVisible = pCursor && pCursor->IsVisible();
186 
187  //If the new text is the same as the old text, keep the same insertion
188  //point .e.g. fdo#33599
189  mpField = static_cast<SwPostItField*>(mpFormatField->GetField());
190  OUString sNewText = mpField->GetPar2();
191  bool bTextUnchanged = sNewText == mpOutliner->GetEditEngine().GetText();
192  ESelection aOrigSelection(GetOutlinerView()->GetEditView().GetSelection());
193 
194  // get text from SwPostItField and insert into our textview
195  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
196  mpOutliner->EnableUndo( false );
197  if( mpField->GetTextObject() )
198  mpOutliner->SetText( *mpField->GetTextObject() );
199  else
200  {
201  mpOutliner->Clear();
203  GetOutlinerView()->InsertText(sNewText);
204  }
205 
206  mpOutliner->ClearModifyFlag();
207  mpOutliner->GetUndoManager().Clear();
208  mpOutliner->EnableUndo( true );
209  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
210  if (bTextUnchanged)
211  GetOutlinerView()->GetEditView().SetSelection(aOrigSelection);
212  if (bCursorVisible)
214  Invalidate();
215 }
216 
218 {
219  if ( mpOutliner->IsModified() )
220  {
221  IDocumentUndoRedo & rUndoRedo(
223  std::unique_ptr<SwField> pOldField;
224  if (rUndoRedo.DoesUndo())
225  {
226  pOldField = mpField->Copy();
227  }
228  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
229  mpField->SetTextObject(mpOutliner->CreateParaObject());
230  if (rUndoRedo.DoesUndo())
231  {
232  SwTextField *const pTextField = mpFormatField->GetTextField();
233  SwPosition aPosition( pTextField->GetTextNode() );
234  aPosition.nContent = pTextField->GetStart();
235  rUndoRedo.AppendUndo(
236  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
237  }
238  // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one)
239  mrMgr.SetLayout();
240  // #i98686# if we have several views, all notes should update their text
243  }
244  mpOutliner->ClearModifyFlag();
245  mpOutliner->GetUndoManager().Clear();
246 }
247 
249 {
251  {
252  if ( mrMgr.GetActiveSidebarWin() == this)
253  {
254  mrMgr.SetActiveSidebarWin(nullptr);
255  // if the note is empty, the previous line will send a delete event, but we are already there
256  if (mnEventId)
257  {
259  mnEventId = nullptr;
260  }
261  }
262  // we delete the field directly, the Mgr cleans up the PostIt by listening
266  }
267 }
268 
270 {
272 }
273 
275 {
276  // if this is an answer, do not skip over all following ones, but insert directly behind the current one
277  // but when just leaving a note, skip all following ones as well to continue typing
278  return mrMgr.IsAnswer()
279  ? 1
280  : 1 + CountFollowing();
281 }
282 
283 // returns a non-zero postit parent id, if exists, otherwise 0 for root comments
285 {
286  SwTextField* pTextField = mpFormatField->GetTextField();
287  SwPosition aPosition( pTextField->GetTextNode() );
288  aPosition.nContent = pTextField->GetStart();
289  SwTextAttr * const pTextAttr =
290  pTextField->GetTextNode().GetTextAttrForCharAt(
291  aPosition.nContent.GetIndex() - 1,
293  const SwField* pField = pTextAttr ? pTextAttr->GetFormatField().GetField() : nullptr;
294  sal_uInt32 nParentId = 0;
295  if (pField && pField->Which() == SwFieldIds::Postit)
296  {
297  const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pField);
298  nParentId = pPostItField->GetPostItId();
299  }
300  return nParentId;
301 }
302 
303 // counts how many SwPostItField we have right after the current one
305 {
306  sal_uInt32 aCount = 1; // we start with 1, so we have to subtract one at the end again
307  SwTextField* pTextField = mpFormatField->GetTextField();
308  SwPosition aPosition( pTextField->GetTextNode() );
309  aPosition.nContent = pTextField->GetStart();
310 
311  SwTextAttr * pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
312  aPosition.nContent.GetIndex() + 1,
314  SwField* pField = pTextAttr
315  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
316  : nullptr;
317  while ( pField && ( pField->Which()== SwFieldIds::Postit ) )
318  {
319  aCount++;
320  pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
321  aPosition.nContent.GetIndex() + aCount,
323  pField = pTextAttr
324  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
325  : nullptr;
326  }
327  return aCount - 1;
328 }
329 
331 {
332  mpButtonPopup = maBuilder.get_menu("menu");
333  sal_uInt16 nByAuthorId = mpButtonPopup->GetItemId("deleteby");
334  OUString aText = mpButtonPopup->GetItemText(nByAuthorId);
335  SwRewriter aRewriter;
336  aRewriter.AddRule(UndoArg1,GetAuthor());
337  aText = aRewriter.Apply(aText);
338  mpButtonPopup->SetItemText(nByAuthorId, aText);
339  VclPtrInstance<AnnotationMenuButton> pMenuButton( *this );
340  pMenuButton->SetPopupMenu( mpButtonPopup );
341  pMenuButton->Show();
342  return pMenuButton;
343 }
344 
346 {
347  // If tiled annotations is off in lok case, skip adding additional reply text.
349  return;
350 
351  //collect our old meta data
353  const SvtSysLocale aSysLocale;
354  const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
355  SwRewriter aRewriter;
356  aRewriter.AddRule(UndoArg1, pWin->GetAuthor());
357  const OUString aText = aRewriter.Apply(SwResId(STR_REPLY))
358  + " (" + rLocalData.getDate( pWin->GetDate())
359  + ", " + rLocalData.getTime( pWin->GetTime(), false)
360  + "): \"";
361  GetOutlinerView()->InsertText(aText);
362 
363  // insert old, selected text or "..."
364  // TODO: iterate over all paragraphs, not only first one to find out if it is empty
365  if (!pText->GetTextObject().GetText(0).isEmpty())
367  else
368  GetOutlinerView()->InsertText("...");
369  GetOutlinerView()->InsertText("\"\n");
370 
372  SfxItemSet aAnswerSet( mrView.GetDocShell()->GetPool() );
373  aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT));
375  GetOutlinerView()->SetAttribs(aAnswerSet);
377 
378  //remove all attributes and reset our standard ones
381  // lets insert an undo step so the initial text can be easily deleted
382  // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr
383  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
384  IDocumentUndoRedo & rUndoRedo(
386  std::unique_ptr<SwField> pOldField;
387  if (rUndoRedo.DoesUndo())
388  {
389  pOldField = mpField->Copy();
390  }
391  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
392  mpField->SetTextObject(mpOutliner->CreateParaObject());
393  if (rUndoRedo.DoesUndo())
394  {
395  SwTextField *const pTextField = mpFormatField->GetTextField();
396  SwPosition aPosition( pTextField->GetTextNode() );
397  aPosition.nContent = pTextField->GetStart();
398  rUndoRedo.AppendUndo(
399  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
400  }
401  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
402  mpOutliner->ClearModifyFlag();
403  mpOutliner->GetUndoManager().Clear();
404 }
405 
406 void SwAnnotationWin::UpdateText(const OUString& aText)
407 {
408  mpOutliner->Clear();
409  GetOutlinerView()->InsertText(aText);
410  UpdateData();
411 }
412 
414 {
415  // set initial language for outliner
417  sal_uInt16 nLangWhichId = 0;
418  switch (nScriptType)
419  {
420  case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
421  case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
422  case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
423  default: OSL_FAIL("GetLanguage: wrong script type");
424  }
425  return SvxLanguageItem(mpField->GetLanguage(),nLangWhichId);
426 }
427 
429 {
430  return mbReadonly ||
433 }
434 
436 {
437  return mpField->GetPar1();
438 }
439 
441 {
442  return mpField->GetDate();
443 }
444 
446 {
447  return mpField->GetTime();
448 }
449 
450 } } // end of namespace sw::annotation
451 
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
virtual void SetModified(bool=true) override
Definition: docsh2.cxx:1406
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:254
#define EE_CHAR_LANGUAGE
bool IsProtect() const
Definition: atrfld.cxx:335
#define KEY_PAGEUP
void ShowCursor(bool bGotoCursor=true, bool bActivate=false)
const tools::Time GetTime() const
Definition: docufld.hxx:473
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:1793
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:1787
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
void SetActiveSidebarWin(sw::annotation::SwAnnotationWin *p)
Definition: PostItMgr.cxx:2113
void SetTextObject(std::unique_ptr< OutlinerParaObject > pText)
Definition: docufld.cxx:1811
Dialog to specify the properties of drop-down form field.
Definition: accfrmobj.cxx:40
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
virtual void dispose() override
bool DelRight()
Definition: delete.cxx:292
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:3060
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:2353
SwIndex nContent
Definition: pam.hxx:38
const SwTextField * GetTextField() const
Definition: fmtfld.hxx:89
vcl::Cursor * GetCursor() const
#define EE_CHAR_ITALIC
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:185
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:202
void ConnectSidebarWinToFrame(const SwFrame &rFrame, const SwFormatField &rFormatField, sw::annotation::SwAnnotationWin &rSidebarWin)
Definition: PostItMgr.cxx:2336
sal_uInt32 GetPostItId() const
Definition: docufld.hxx:474
const EditTextObject & GetTextObject() const
SvtScriptType
virtual std::unique_ptr< SwField > Copy() const override
Definition: docufld.cxx:1768
std::unique_ptr< OutlinerView > mpOutlinerView
void SetAttribs(const SfxItemSet &)
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:59
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:43
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:223
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:1115
void Disable(bool bChild=true)
SwLayoutInfo maLayoutInfo
OUString getDate(const Date &rDate) const
void Broadcast(const SfxHint &rHint)
void SetSelection(const ESelection &)
const OutlinerParaObject * GetTextObject() const
Definition: docufld.hxx:488
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
const Date GetDate() const
Definition: docufld.hxx:472
ITALIC_NORMAL
VclPtr< sw::sidebarwindows::SidebarTextControl > mpSidebarTextControl
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:927
bool IsDisposed() const
bool IsVisible() const
sw::annotation::SwAnnotationWin * GetActiveSidebarWin()
Definition: PostItMgr.hxx:232
void SetSelection(const ESelection &rNewSel)
sw::annotation::SwAnnotationWin * GetNextPostIt(sal_uInt16 aDirection, sw::annotation::SwAnnotationWin *aPostIt)
Definition: PostItMgr.cxx:1721
VclPtr< ScrollBar > mpVScrollbar
virtual OUString GetPar2() const override
Text.
Definition: docufld.cxx:1799
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 SetItemText(sal_uInt16 nItemId, const OUString &rStr)