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 
27 #include <vcl/edit.hxx>
28 #include <vcl/menu.hxx>
29 #include <vcl/scrbar.hxx>
30 #include <vcl/svapp.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 <viewopt.hxx>
54 #include <wrtsh.hxx>
55 #include <docsh.hxx>
56 #include <doc.hxx>
57 #include <IDocumentUndoRedo.hxx>
58 #include <SwUndoField.hxx>
59 #include <edtwin.hxx>
60 #include "ShadowOverlayObject.hxx"
61 #include "AnchorOverlayObject.hxx"
62 #include "OverlayRanges.hxx"
63 #include "SidebarTxtControl.hxx"
64 
65 #include <memory>
66 
67 namespace sw::annotation {
68 
70  SwPostItMgr& aMgr,
71  SwSidebarItem& rSidebarItem,
72  SwFormatField* aField )
73  : Window(&rEditWin)
74  , maBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/annotationmenu.ui", "")
75  , mrMgr(aMgr)
76  , mrView(rEditWin.GetView())
77  , mnEventId(nullptr)
78  , mpSidebarTextControl(nullptr)
79  , mpVScrollbar(nullptr)
80  , mpMetadataAuthor(nullptr)
81  , mpMetadataDate(nullptr)
82  , mpMenuButton(nullptr)
83  , mColorAnchor()
84  , mColorDark()
85  , mColorLight()
86  , mChangeColor()
87  , meSidebarPosition(sw::sidebarwindows::SidebarPosition::NONE)
88  , mPosSize()
89  , mAnchorRect()
90  , mPageBorder(0)
91  , mbAnchorRectChanged(false)
92  , mbResolvedStateUpdated(false)
93  , mbMouseOver(false)
94  , mLayoutStatus(SwPostItHelper::INVISIBLE)
95  , mbReadonly(false)
96  , mbIsFollow(false)
97  , mrSidebarItem(rSidebarItem)
98  , mpAnchorFrame(rSidebarItem.maLayoutInfo.mpAnchorFrame)
99  , mpFormatField(aField)
100  , mpField( static_cast<SwPostItField*>(aField->GetField()))
101  , mpButtonPopup(nullptr)
102 {
104  if ( mpShadow )
105  {
106  mpShadow->setVisible(false);
107  }
108 
111  *this );
112 
114  // When double-buffering, allow parents to paint on our area. That's
115  // necessary when parents paint the complete buffer.
116  SetParentClipMode(ParentClipMode::NoClip);
117 }
118 
120 {
121  disposeOnce();
122 }
123 
125 {
128 
129  if (IsDisposed())
130  return;
131 
133  *this );
134 
135  Disable();
136 
137  if ( mpSidebarTextControl )
138  {
139  if ( mpOutlinerView )
140  {
141  mpOutlinerView->SetWindow( nullptr );
142  }
143  }
145 
146  mpOutlinerView.reset();
147  mpOutliner.reset();
148 
149  if (mpMetadataAuthor)
150  {
151  mpMetadataAuthor->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
152  }
154 
155  if (mpMetadataResolved)
156  {
157  mpMetadataResolved->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
158  }
160 
161  if (mpMetadataDate)
162  {
163  mpMetadataDate->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
164  }
166 
167  if (mpVScrollbar)
168  {
169  mpVScrollbar->RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
170  }
172 
173  RemoveEventListener( LINK( this, SwAnnotationWin, WindowEventListener ) );
174 
175  mpAnchor.reset();
176  mpShadow.reset();
177 
178  mpTextRangeOverlay.reset();
179 
181 
182  if (mnEventId)
184 
186 }
187 
189 {
190  //If the cursor was visible, then make it visible again after
191  //changing text, e.g. fdo#33599
193  bool bCursorVisible = pCursor && pCursor->IsVisible();
194 
195  //If the new text is the same as the old text, keep the same insertion
196  //point .e.g. fdo#33599
197  mpField = static_cast<SwPostItField*>(mpFormatField->GetField());
198  OUString sNewText = mpField->GetPar2();
199  bool bTextUnchanged = sNewText == mpOutliner->GetEditEngine().GetText();
200  ESelection aOrigSelection(GetOutlinerView()->GetEditView().GetSelection());
201 
202  // get text from SwPostItField and insert into our textview
203  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
204  mpOutliner->EnableUndo( false );
205  if( mpField->GetTextObject() )
206  mpOutliner->SetText( *mpField->GetTextObject() );
207  else
208  {
209  mpOutliner->Clear();
211  GetOutlinerView()->InsertText(sNewText);
212  }
213 
214  mpOutliner->ClearModifyFlag();
215  mpOutliner->GetUndoManager().Clear();
216  mpOutliner->EnableUndo( true );
217  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
218  if (bTextUnchanged)
219  GetOutlinerView()->GetEditView().SetSelection(aOrigSelection);
220  if (bCursorVisible)
222  Invalidate();
223 }
224 
225 void SwAnnotationWin::SetResolved(bool resolved)
226 {
227  bool oldState = IsResolved();
228  static_cast<SwPostItField*>(mpFormatField->GetField())->SetResolved(resolved);
229  const SwViewOption* pVOpt = mrView.GetWrtShellPtr()->GetViewOptions();
230  mrSidebarItem.bShow = !IsResolved() || (pVOpt->IsResolvedPostIts());
231 
232  mpTextRangeOverlay.reset();
233 
234  if(IsResolved())
236  else
238 
239  if(IsResolved() != oldState)
240  mbResolvedStateUpdated = true;
241  UpdateData();
242  Invalidate();
243 }
244 
246 {
248 }
249 
251 {
255 }
256 
258 {
259  return static_cast<SwPostItField*>(mpFormatField->GetField())->GetResolved();
260 }
261 
263 {
264  // Not const because GetTopReplyNote isn't.
265  return GetTopReplyNote()->IsResolved();
266 }
267 
269 {
270  if ( mpOutliner->IsModified() || mbResolvedStateUpdated )
271  {
272  IDocumentUndoRedo & rUndoRedo(
274  std::unique_ptr<SwField> pOldField;
275  if (rUndoRedo.DoesUndo())
276  {
277  pOldField = mpField->Copy();
278  }
279  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
280  mpField->SetTextObject(mpOutliner->CreateParaObject());
281  if (rUndoRedo.DoesUndo())
282  {
283  SwTextField *const pTextField = mpFormatField->GetTextField();
284  SwPosition aPosition( pTextField->GetTextNode() );
285  aPosition.nContent = pTextField->GetStart();
286  rUndoRedo.AppendUndo(
287  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
288  }
289  // so we get a new layout of notes (anchor position is still the same and we would otherwise not get one)
290  mrMgr.SetLayout();
291  // #i98686# if we have several views, all notes should update their text
294  else
297  }
298  mpOutliner->ClearModifyFlag();
299  mpOutliner->GetUndoManager().Clear();
300  mbResolvedStateUpdated = false;
301 }
302 
304 {
306  {
307  if ( mrMgr.GetActiveSidebarWin() == this)
308  {
309  mrMgr.SetActiveSidebarWin(nullptr);
310  // if the note is empty, the previous line will send a delete event, but we are already there
311  if (mnEventId)
312  {
314  mnEventId = nullptr;
315  }
316  }
317  // we delete the field directly, the Mgr cleans up the PostIt by listening
321  }
322 }
323 
325 {
327 }
328 
330 {
331  // if this is an answer, do not skip over all following ones, but insert directly behind the current one
332  // but when just leaving a note, skip all following ones as well to continue typing
333  return mrMgr.IsAnswer()
334  ? 1
335  : 1 + CountFollowing();
336 }
337 
338 // returns a non-zero postit parent id, if exists, otherwise 0 for root comments
340 {
341  SwTextField* pTextField = mpFormatField->GetTextField();
342  SwPosition aPosition( pTextField->GetTextNode() );
343  aPosition.nContent = pTextField->GetStart();
344  SwTextAttr * const pTextAttr =
345  pTextField->GetTextNode().GetTextAttrForCharAt(
346  aPosition.nContent.GetIndex() - 1,
348  const SwField* pField = pTextAttr ? pTextAttr->GetFormatField().GetField() : nullptr;
349  sal_uInt32 nParentId = 0;
350  if (pField && pField->Which() == SwFieldIds::Postit)
351  {
352  const SwPostItField* pPostItField = static_cast<const SwPostItField*>(pField);
353  nParentId = pPostItField->GetPostItId();
354  }
355  return nParentId;
356 }
357 
358 // counts how many SwPostItField we have right after the current one
360 {
361  sal_uInt32 aCount = 1; // we start with 1, so we have to subtract one at the end again
362  SwTextField* pTextField = mpFormatField->GetTextField();
363  SwPosition aPosition( pTextField->GetTextNode() );
364  aPosition.nContent = pTextField->GetStart();
365 
366  SwTextAttr * pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
367  aPosition.nContent.GetIndex() + 1,
369  SwField* pField = pTextAttr
370  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
371  : nullptr;
372  while ( pField && ( pField->Which()== SwFieldIds::Postit ) )
373  {
374  aCount++;
375  pTextAttr = pTextField->GetTextNode().GetTextAttrForCharAt(
376  aPosition.nContent.GetIndex() + aCount,
378  pField = pTextAttr
379  ? const_cast<SwField*>(pTextAttr->GetFormatField().GetField())
380  : nullptr;
381  }
382  return aCount - 1;
383 }
384 
386 {
387  mpButtonPopup = maBuilder.get_menu("menu");
388  sal_uInt16 nByAuthorId = mpButtonPopup->GetItemId("deleteby");
389  OUString aText = mpButtonPopup->GetItemText(nByAuthorId);
390  SwRewriter aRewriter;
391  aRewriter.AddRule(UndoArg1,GetAuthor());
392  aText = aRewriter.Apply(aText);
393  mpButtonPopup->SetItemText(nByAuthorId, aText);
394  VclPtrInstance<AnnotationMenuButton> pMenuButton( *this );
395  pMenuButton->SetPopupMenu( mpButtonPopup );
396  pMenuButton->Show();
397  return pMenuButton;
398 }
399 
401 {
402  // If tiled annotations is off in lok case, skip adding additional reply text.
404  return;
405 
406  //collect our old meta data
408  const SvtSysLocale aSysLocale;
409  const LocaleDataWrapper& rLocalData = aSysLocale.GetLocaleData();
410  SwRewriter aRewriter;
411  aRewriter.AddRule(UndoArg1, pWin->GetAuthor());
412  const OUString aText = aRewriter.Apply(SwResId(STR_REPLY))
413  + " (" + rLocalData.getDate( pWin->GetDate())
414  + ", " + rLocalData.getTime( pWin->GetTime(), false)
415  + "): \"";
416  GetOutlinerView()->InsertText(aText);
417 
418  // insert old, selected text or "..."
419  // TODO: iterate over all paragraphs, not only first one to find out if it is empty
420  if (!pText->GetTextObject().GetText(0).isEmpty())
422  else
423  GetOutlinerView()->InsertText("...");
424  GetOutlinerView()->InsertText("\"\n");
425 
427  SfxItemSet aAnswerSet( mrView.GetDocShell()->GetPool() );
428  aAnswerSet.Put(SvxFontHeightItem(200,80,EE_CHAR_FONTHEIGHT));
430  GetOutlinerView()->SetAttribs(aAnswerSet);
432 
433  //remove all attributes and reset our standard ones
436  // lets insert an undo step so the initial text can be easily deleted
437  // but do not use UpdateData() directly, would set modified state again and reentrance into Mgr
438  mpOutliner->SetModifyHdl( Link<LinkParamNone*,void>() );
439  IDocumentUndoRedo & rUndoRedo(
441  std::unique_ptr<SwField> pOldField;
442  if (rUndoRedo.DoesUndo())
443  {
444  pOldField = mpField->Copy();
445  }
446  mpField->SetPar2(mpOutliner->GetEditEngine().GetText());
447  mpField->SetTextObject(mpOutliner->CreateParaObject());
448  if (rUndoRedo.DoesUndo())
449  {
450  SwTextField *const pTextField = mpFormatField->GetTextField();
451  SwPosition aPosition( pTextField->GetTextNode() );
452  aPosition.nContent = pTextField->GetStart();
453  rUndoRedo.AppendUndo(
454  std::make_unique<SwUndoFieldFromDoc>(aPosition, *pOldField, *mpField, nullptr, true));
455  }
456  mpOutliner->SetModifyHdl( LINK( this, SwAnnotationWin, ModifyHdl ) );
457  mpOutliner->ClearModifyFlag();
458  mpOutliner->GetUndoManager().Clear();
459 }
460 
461 void SwAnnotationWin::UpdateText(const OUString& aText)
462 {
463  mpOutliner->Clear();
464  GetOutlinerView()->InsertText(aText);
465  UpdateData();
466 }
467 
469 {
470  // set initial language for outliner
472  sal_uInt16 nLangWhichId = 0;
473  switch (nScriptType)
474  {
475  case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE ; break;
476  case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
477  case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
478  default: OSL_FAIL("GetLanguage: wrong script type");
479  }
480  return SvxLanguageItem(mpField->GetLanguage(),nLangWhichId);
481 }
482 
484 {
485  return mbReadonly ||
488 }
489 
491 {
492  return mpField->GetPar1();
493 }
494 
496 {
497  return mpField->GetDate();
498 }
499 
501 {
502  return mpField->GetTime();
503 }
504 
505 } // end of namespace sw::annotation
506 
507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Date GetDate() const
Definition: docufld.hxx:474
virtual void SetModified(bool=true) override
Definition: docsh2.cxx:1377
Marks a position in the document model.
Definition: pam.hxx:35
#define EE_CHAR_LANGUAGE_CJK
const SwField * GetField() const
Definition: fmtfld.hxx:70
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:393
const SwFrame * mpAnchorFrame
VclPtr< MenuButton > mpMenuButton
SwPostItHelper::SwLayoutStatus GetLayoutStatus() const
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:280
virtual void SetPar2(const OUString &rStr) override
set the PostIt's text
Definition: docufld.cxx:1804
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:1798
void SetParentClipMode(ParentClipMode nMode=ParentClipMode::NONE)
void SetActiveSidebarWin(sw::annotation::SwAnnotationWin *p)
Definition: PostItMgr.cxx:2145
void SetTextObject(std::unique_ptr< OutlinerParaObject > pText)
Definition: docufld.cxx:1822
Dialog to specify the properties of date form field.
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:143
virtual void dispose() override
bool DelRight()
Definition: delete.cxx:285
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:3050
SvxLanguageItem GetLanguage() const
const LocaleDataWrapper & GetLocaleData() const
NONE
std::unique_ptr< sw::overlay::OverlayRanges > mpTextRangeOverlay
void DisconnectSidebarWinFromFrame(const SwFrame &rFrame, sw::annotation::SwAnnotationWin &rSidebarWin)
Definition: PostItMgr.cxx:2385
SwIndex nContent
Definition: pam.hxx:38
const SwTextField * GetTextField() const
Definition: fmtfld.hxx:88
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:2368
sal_uInt32 GetPostItId() const
Definition: docufld.hxx:476
const EditTextObject & GetTextObject() const
SvtScriptType
virtual std::unique_ptr< SwField > Copy() const override
Definition: docufld.cxx:1779
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)
const SwFrame * mpAnchorFrame
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)
const sal_Int16 mnEventId
void InsertText(const OUString &rNew, bool bSelect=false)
OUString SwResId(const char *pId)
Definition: swmodule.cxx:178
OUString GetItemText(sal_uInt16 nItemId) const
sal_uInt32 CalcParent()
Calculate parent postit id of current annotation window.
SwDocShell * GetDocShell()
Definition: view.cxx:1107
void Disable(bool bChild=true)
SwLayoutInfo maLayoutInfo
void LayoutPostIts()
Definition: PostItMgr.cxx:679
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:65
void disposeBuilder()
SwFieldIds Which() const
ResId.
Definition: fldbas.cxx:192
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:247
SlideSorterView & mrView
void UpdateResolvedStatus(const sw::annotation::SwAnnotationWin *topNote)
Definition: PostItMgr.cxx:2448
#define EE_TEXTPOS_MAX_COUNT
PopupMenu * get_menu(const OString &sID)
void ClearMark()
Definition: crsrsh.cxx:930
bool IsDisposed() const
bool IsVisible() const
sw::annotation::SwAnnotationWin * GetActiveSidebarWin()
Definition: PostItMgr.hxx:236
void SetSelection(const ESelection &rNewSel)
sw::annotation::SwAnnotationWin * GetNextPostIt(sal_uInt16 aDirection, sw::annotation::SwAnnotationWin *aPostIt)
Definition: PostItMgr.cxx:1753
VclPtr< ScrollBar > mpVScrollbar
virtual OUString GetPar2() const override
Text.
Definition: docufld.cxx:1810
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)