LibreOffice Module sw (master)  1
redlndlg.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 <redline.hxx>
21 #include <tools/datetime.hxx>
22 #include <tools/lineend.hxx>
23 #include <svl/eitem.hxx>
24 #include <sfx2/viewfrm.hxx>
25 #include <sfx2/dispatch.hxx>
26 #include <svx/ctredlin.hxx>
27 #include <svx/postattr.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <swtypes.hxx>
30 #include <wrtsh.hxx>
31 #include <view.hxx>
32 #include <swmodule.hxx>
33 #include <redlndlg.hxx>
34 #include <swwait.hxx>
35 #include <uitool.hxx>
36 #include <o3tl/string_view.hxx>
37 
38 #include <cmdid.h>
39 #include <strings.hrc>
40 
41 // -> #111827#
42 #include <swundo.hxx>
43 #include <SwRewriter.hxx>
44 // <- #111827#
45 
46 #include <vector>
47 #include <svx/svxdlg.hxx>
48 #include <osl/diagnose.h>
49 #include <bitmaps.hlst>
50 
51 #include <docsh.hxx>
52 
54 #include <usrpref.hxx>
55 #include <memory>
56 
58 
60  sal_uInt16 nId,
61  SfxBindings* pBindings,
62  SfxChildWinInfo* pInfo)
63  : SwChildWinWrapper(_pParent, nId)
64 {
65  auto xDlg = std::make_shared<SwModelessRedlineAcceptDlg>(pBindings, this, _pParent->GetFrameWeld());
66  SetController(xDlg);
67  xDlg->Initialize(pInfo);
68 }
69 
70 // newly initialise dialog after document switch
72 {
73  bool bRet = SwChildWinWrapper::ReInitDlg(pDocSh);
74  if (bRet) // update immediately, doc switch!
75  static_cast<SwModelessRedlineAcceptDlg*>(GetController().get())->Activate();
76 
77  return bRet;
78 }
79 
81  SfxBindings* _pBindings, SwChildWinWrapper* pChild, weld::Window *pParent)
82  : SfxModelessDialogController(_pBindings, pChild, pParent,
83  "svx/ui/acceptrejectchangesdialog.ui", "AcceptRejectChangesDialog")
84  , m_xContentArea(m_xDialog->weld_content_area())
85  , m_pChildWin(pChild)
86 {
87  m_xImplDlg.reset(new SwRedlineAcceptDlg(m_xDialog, m_xBuilder.get(), m_xContentArea.get()));
88 }
89 
91 {
92  SwView *pView = ::GetActiveView();
93  if (!pView) // can happen when switching to another app, when a Listbox in dialog
94  return; // had the focus previously (actually THs Bug)
95 
96  SwDocShell *pDocSh = pView->GetDocShell();
97 
98  if (m_pChildWin->GetOldDocShell() != pDocSh)
99  { // doc-switch
100  SwWait aWait( *pDocSh, false );
101  SwWrtShell* pSh = pView->GetWrtShellPtr();
102 
103  m_pChildWin->SetOldDocShell(pDocSh); // avoid recursion (using modified-Hdl)
104 
105  bool bMod = pSh->IsModified();
106  SfxBoolItem aShow(FN_REDLINE_SHOW, true);
108  FN_REDLINE_SHOW, SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
109  { &aShow });
110  if (!bMod)
111  pSh->ResetModified();
112  m_xImplDlg->Init();
114 
115  return;
116  }
117 
119  m_xImplDlg->Activate();
120 }
121 
123 {
124  if (pInfo != nullptr)
125  m_xImplDlg->Initialize(pInfo->aExtraString);
126 
128 }
129 
131 {
133  m_xImplDlg->FillInfo(rInfo.aExtraString);
134 }
135 
137 {
138 }
139 
140 SwRedlineAcceptDlg::SwRedlineAcceptDlg(const std::shared_ptr<weld::Window>& rParent, weld::Builder *pBuilder,
141  weld::Container *pContentArea, bool bAutoFormat)
142  : m_xParentDlg(rParent)
143  , m_aSelectTimer("SwRedlineAcceptDlg m_aSelectTimer")
144  , m_sInserted(SwResId(STR_REDLINE_INSERTED))
145  , m_sDeleted(SwResId(STR_REDLINE_DELETED))
146  , m_sFormated(SwResId(STR_REDLINE_FORMATTED))
147  , m_sTableChgd(SwResId(STR_REDLINE_TABLECHG))
148  , m_sFormatCollSet(SwResId(STR_REDLINE_FMTCOLLSET))
149  , m_sAutoFormat(SwResId(STR_REDLINE_AUTOFMT))
150  , m_bOnlyFormatedRedlines(false)
151  , m_bRedlnAutoFormat(bAutoFormat)
152  , m_bInhibitActivate(false)
153  , m_xTabPagesCTRL(new SvxAcceptChgCtr(pContentArea))
154  , m_xPopup(pBuilder->weld_menu("writermenu"))
155  , m_xSortMenu(pBuilder->weld_menu("writersortmenu"))
156 {
157  m_pTPView = m_xTabPagesCTRL->GetViewPage();
158 
161 
163  m_pTPView->SetAcceptAllClickHdl(LINK(this, SwRedlineAcceptDlg, AcceptAllHdl));
165  m_pTPView->SetRejectAllClickHdl(LINK(this, SwRedlineAcceptDlg, RejectAllHdl));
167  //tdf#89227 default to disabled, and only enable if possible to accept/reject
168  m_pTPView->EnableAccept(false);
169  m_pTPView->EnableReject(false);
171  m_pTPView->EnableAcceptAll(false);
172  m_pTPView->EnableRejectAll(false);
174 
175  m_xTabPagesCTRL->GetFilterPage()->SetReadyHdl(LINK(this, SwRedlineAcceptDlg, FilterChangedHdl));
176 
177  weld::ComboBox* pActLB = m_xTabPagesCTRL->GetFilterPage()->GetLbAction();
178  pActLB->append_text(m_sInserted);
179  pActLB->append_text(m_sDeleted);
180  pActLB->append_text(m_sFormated);
181  pActLB->append_text(m_sTableChgd);
182 
183  if (HasRedlineAutoFormat())
184  {
185  pActLB->append_text(m_sFormatCollSet);
186  pActLB->append_text(m_sAutoFormat);
187  m_pTPView->ShowUndo();
188  m_pTPView->DisableUndo(); // no UNDO events yet
189  }
190 
191  pActLB->set_active(0);
192 
193  weld::TreeView& rTreeView = m_pTable->GetWidget();
194  rTreeView.set_selection_mode(SelectionMode::Multiple);
195 
196  rTreeView.connect_changed(LINK(this, SwRedlineAcceptDlg, SelectHdl));
197  rTreeView.connect_popup_menu(LINK(this, SwRedlineAcceptDlg, CommandHdl));
198 
199  // avoid multiple selection of the same texts:
202 }
203 
205 {
206 }
207 
209 {
210  SwWait aWait( *::GetActiveView()->GetDocShell(), false );
211  weld::TreeView& rTreeView = m_pTable->GetWidget();
213 
214  rTreeView.freeze();
215  if (nStart)
216  RemoveParents(nStart, m_RedlineParents.size() - 1);
217  else
218  {
219  rTreeView.clear();
220  m_RedlinData.clear();
221  m_RedlineChildren.clear();
222  m_RedlineParents.erase(m_RedlineParents.begin() + nStart, m_RedlineParents.end());
223  }
224  rTreeView.thaw();
225 
226  // insert parents
227  InsertParents(nStart);
228  InitAuthors();
229 
230  // #i69618# this moves the list box to the right position, visually
231  std::unique_ptr<weld::TreeIter> xSelEntry(rTreeView.make_iterator());
232  if (rTreeView.get_selected(xSelEntry.get()))
233  rTreeView.scroll_to_row(*xSelEntry); //#i70937#, force the scroll
234 }
235 
237 {
239 
240  if (!m_xTabPagesCTRL)
241  return;
242 
243  SvxTPFilter *pFilterPage = m_xTabPagesCTRL->GetFilterPage();
244 
245  std::vector<OUString> aStrings;
246  OUString sOldAuthor(pFilterPage->GetSelectedAuthor());
247  pFilterPage->ClearAuthors();
248 
250 
252  bool bIsNotFormated = false;
253 
254  // determine authors
255  for ( SwRedlineTable::size_type i = 0; i < nCount; i++)
256  {
257  const SwRangeRedline& rRedln = pSh->GetRedline(i);
258 
259  if( m_bOnlyFormatedRedlines && RedlineType::Format != rRedln.GetType() )
260  m_bOnlyFormatedRedlines = false;
261 
262  aStrings.push_back(rRedln.GetAuthorString());
263 
264  for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
265  {
266  aStrings.push_back(rRedln.GetAuthorString(nStack));
267  }
268  }
269 
270  std::sort(aStrings.begin(), aStrings.end());
271  aStrings.erase(std::unique(aStrings.begin(), aStrings.end()), aStrings.end());
272 
273  for (auto const & i: aStrings)
274  pFilterPage->InsertAuthor(i);
275 
276  if (pFilterPage->SelectAuthor(sOldAuthor) == -1 && !aStrings.empty())
277  pFilterPage->SelectAuthor(aStrings[0]);
278 
279  weld::TreeView& rTreeView = m_pTable->GetWidget();
280  bool const bEnable = !pSh->GetDoc()->GetDocShell()->IsReadOnly()
281  && rTreeView.n_children() != 0
282  && !pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
283  bool bSel = rTreeView.get_selected(nullptr);
284 
285  rTreeView.selected_foreach([this, pSh, &bIsNotFormated](weld::TreeIter& rEntry){
286  // find the selected redline
287  // (fdo#57874: ignore, if the redline is already gone)
289  if( nPos != SwRedlineTable::npos )
290  {
291  const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
292 
293  bIsNotFormated |= RedlineType::Format != rRedln.GetType();
294  }
295  return false;
296  });
297 
298  m_pTPView->EnableAccept( bEnable && bSel );
299  m_pTPView->EnableReject( bEnable && bSel );
300  m_pTPView->EnableClearFormat( bEnable && !bIsNotFormated && bSel );
301  m_pTPView->EnableAcceptAll( bEnable );
302  m_pTPView->EnableRejectAll( bEnable );
303  m_pTPView->EnableClearFormatAll( bEnable &&
305 }
306 
307 OUString SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack, bool bRowChanges)
308 {
309  switch (rRedln.GetType(nStack))
310  {
311  case RedlineType::Insert: return bRowChanges
312  ? OUString(BMP_REDLINE_ROW_INSERTION)
313  : rRedln.IsMoved()
314  ? OUString(BMP_REDLINE_MOVED_INSERTION)
315  : rRedln.IsAnnotation()
316  ? OUString(BMP_REDLINE_COMMENT_INSERTION)
317  : OUString(BMP_REDLINE_INSERTED);
318  case RedlineType::Delete: return bRowChanges
319  ? OUString(BMP_REDLINE_ROW_DELETION)
320  : rRedln.IsMoved()
321  ? OUString(BMP_REDLINE_MOVED_DELETION)
322  : rRedln.IsAnnotation()
323  ? OUString(BMP_REDLINE_COMMENT_DELETION)
324  : OUString(BMP_REDLINE_DELETED);
325  case RedlineType::Format: return BMP_REDLINE_FORMATTED;
326  case RedlineType::ParagraphFormat: return BMP_REDLINE_FORMATTED;
327  case RedlineType::Table: return BMP_REDLINE_TABLECHG;
328  case RedlineType::FmtColl: return BMP_REDLINE_FMTCOLLSET;
329  default: break;
330  }
331 
332  return OUString();
333 }
334 
335 OUString SwRedlineAcceptDlg::GetActionText(const SwRangeRedline& rRedln, sal_uInt16 nStack)
336 {
337  switch( rRedln.GetType(nStack) )
338  {
339  case RedlineType::Insert: return m_sInserted;
340  case RedlineType::Delete: return m_sDeleted;
341  case RedlineType::Format: return m_sFormated;
342  case RedlineType::ParagraphFormat: return m_sFormated;
343  case RedlineType::Table: return m_sTableChgd;
344  case RedlineType::FmtColl: return m_sFormatCollSet;
345  default:;//prevent warning
346  }
347 
348  return OUString();
349 }
350 
351 // newly initialise after activation
353 {
354  // prevent update if flag is set (#102547#)
355  if( m_bInhibitActivate )
356  return;
357 
358  SwView *pView = ::GetActiveView();
359  if (!pView) // can happen when switching to another app
360  {
361  m_pTPView->EnableAccept(false);
362  m_pTPView->EnableReject(false);
364  m_pTPView->EnableAcceptAll(false);
365  m_pTPView->EnableRejectAll(false);
367  return; // had the focus previously
368  }
369 
370  SwWait aWait( *pView->GetDocShell(), false );
371 
372  if (pView->GetDocShell()->IsReadOnly())
373  {
374  m_pTPView->EnableAccept(false);
375  m_pTPView->EnableReject(false);
377  m_pTPView->EnableAcceptAll(false);
378  m_pTPView->EnableRejectAll(false);
380  // note: enabling is done in InitAuthors below
381  }
382 
384 
385  // did something change?
386  SwWrtShell* pSh = pView->GetWrtShellPtr();
388 
389  // check the number of pointers
390  for ( SwRedlineTable::size_type i = 0; i < nCount; i++)
391  {
392  const SwRangeRedline& rRedln = pSh->GetRedline(i);
393 
394  if (i >= m_RedlineParents.size())
395  {
396  // new entries have been appended
397  Init(i);
398  return;
399  }
400 
401  SwRedlineDataParent *const pParent = m_RedlineParents[i].get();
402  if (&rRedln.GetRedlineData() != pParent->pData)
403  {
404  // Redline-Parents were inserted, changed or deleted
405  i = CalcDiff(i, false);
406  if (i == SwRedlineTable::npos)
407  return;
408  continue;
409  }
410 
411  const SwRedlineData *pRedlineData = rRedln.GetRedlineData().Next();
412  const SwRedlineDataChild *pBackupData = pParent->pNext;
413 
414  if (!pRedlineData && pBackupData)
415  {
416  // Redline-Children were deleted
417  i = CalcDiff(i, true);
418  if (i == SwRedlineTable::npos)
419  return;
420  continue;
421  }
422  else
423  {
424  while (pRedlineData)
425  {
426  if (pRedlineData != pBackupData->pChild)
427  {
428  // Redline-Children were inserted, changed or deleted
429  i = CalcDiff(i, true);
430  if (i == SwRedlineTable::npos)
431  return;
432  continue;
433  }
434  pBackupData = pBackupData->pNext;
435  pRedlineData = pRedlineData->Next();
436  }
437  }
438  }
439 
440  if (nCount != m_RedlineParents.size())
441  {
442  // Redlines were deleted at the end
443  Init(nCount);
444  return;
445  }
446 
447  // check comment
448  weld::TreeView& rTreeView = m_pTable->GetWidget();
449  bool bIsShowChangesInMargin = SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin();
450  for (SwRedlineTable::size_type i = 0; i < nCount; i++)
451  {
452  const SwRangeRedline& rRedln = pSh->GetRedline(i);
453  SwRedlineDataParent *const pParent = m_RedlineParents[i].get();
454 
455  if(rRedln.GetComment() != pParent->sComment)
456  {
457  bool bShowDeletedTextAsComment = bIsShowChangesInMargin &&
458  RedlineType::Delete == rRedln.GetType() && rRedln.GetComment().isEmpty();
459  const OUString sComment = bShowDeletedTextAsComment
460  ? const_cast<SwRangeRedline&>(rRedln).GetDescr()
461  : rRedln.GetComment();
462  if (pParent->xTLBParent)
463  {
464  // update only comment
465  rTreeView.set_text(*pParent->xTLBParent, sComment.replace('\n', ' '), 3);
466  }
467  pParent->sComment = sComment;
468  }
469  }
470 
471  InitAuthors();
472 }
473 
475 {
476  if (!nStart)
477  {
478  Init();
479  return SwRedlineTable::npos;
480  }
481 
482  weld::TreeView& rTreeView = m_pTable->GetWidget();
483  rTreeView.freeze();
484  SwView *pView = ::GetActiveView();
485  SwWrtShell* pSh = pView->GetWrtShellPtr();
486  bool bHasRedlineAutoFormat = HasRedlineAutoFormat();
487  SwRedlineDataParent *const pParent = m_RedlineParents[nStart].get();
488  const SwRangeRedline& rRedln = pSh->GetRedline(nStart);
489 
490  if (bChild) // should actually never happen, but just in case...
491  {
492  // throw away all entry's children and initialise newly
493  SwRedlineDataChild* pBackupData = const_cast<SwRedlineDataChild*>(pParent->pNext);
494  SwRedlineDataChild* pNext;
495 
496  while (pBackupData)
497  {
498  pNext = const_cast<SwRedlineDataChild*>(pBackupData->pNext);
499  if (pBackupData->xTLBChild)
500  rTreeView.remove(*pBackupData->xTLBChild);
501 
502  auto it = std::find_if(m_RedlineChildren.begin(), m_RedlineChildren.end(),
503  [&pBackupData](const std::unique_ptr<SwRedlineDataChild>& rChildPtr) { return rChildPtr.get() == pBackupData; });
504  if (it != m_RedlineChildren.end())
505  m_RedlineChildren.erase(it);
506 
507  pBackupData = pNext;
508  }
509  pParent->pNext = nullptr;
510 
511  // insert new children
512  InsertChildren(pParent, rRedln, bHasRedlineAutoFormat);
513 
514  rTreeView.thaw();
515  return nStart;
516  }
517 
518  // have entries been deleted?
519  const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
520  for (SwRedlineTable::size_type i = nStart + 1; i < m_RedlineParents.size(); i++)
521  {
522  if (m_RedlineParents[i]->pData == pRedlineData)
523  {
524  // remove entries from nStart to i-1
525  RemoveParents(nStart, i - 1);
526  rTreeView.thaw();
527  return nStart - 1;
528  }
529  }
530 
531  // entries been inserted?
533  pRedlineData = m_RedlineParents[nStart]->pData;
534 
535  for (SwRedlineTable::size_type i = nStart + 1; i < nCount; i++)
536  {
537  if (&pSh->GetRedline(i).GetRedlineData() == pRedlineData)
538  {
539  // insert entries from nStart to i-1
540  InsertParents(nStart, i - 1);
541  rTreeView.thaw();
542  return nStart - 1;
543  }
544  }
545 
546  rTreeView.thaw();
547  Init(nStart); // adjust all entries until the end
548  return SwRedlineTable::npos;
549 }
550 
551 void SwRedlineAcceptDlg::InsertChildren(SwRedlineDataParent *pParent, const SwRangeRedline& rRedln, bool bHasRedlineAutoFormat)
552 {
553  SwRedlineDataChild *pLastRedlineChild = nullptr;
554  const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
555  bool bAutoFormatRedline = rRedln.IsAutoFormat();
556 
557  weld::TreeView& rTreeView = m_pTable->GetWidget();
558 
559  OUString sAction = GetActionText(rRedln);
560  bool bValidParent = m_sFilterAction.isEmpty() || m_sFilterAction == sAction;
561  bValidParent = bValidParent && m_pTable->IsValidEntry(rRedln.GetAuthorString(), rRedln.GetTimeStamp(), rRedln.GetComment());
562  if (bHasRedlineAutoFormat)
563  {
564 
565  if (pParent->pData->GetSeqNo())
566  {
567  std::pair<SwRedlineDataParentSortArr::const_iterator,bool> const ret
568  = m_aUsedSeqNo.insert(pParent);
569  if (ret.second) // already there
570  {
571  if (pParent->xTLBParent)
572  {
573  rTreeView.set_text(*(*ret.first)->xTLBParent, m_sAutoFormat, 0);
574  rTreeView.remove(*pParent->xTLBParent);
575  pParent->xTLBParent.reset();
576  }
577  return;
578  }
579  }
580  bValidParent = bValidParent && bAutoFormatRedline;
581  }
582  bool bValidTree = bValidParent;
583 
584  for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
585  {
586  pRedlineData = pRedlineData->Next();
587 
588  SwRedlineDataChild* pRedlineChild = new SwRedlineDataChild;
589  pRedlineChild->pChild = pRedlineData;
590  m_RedlineChildren.push_back(std::unique_ptr<SwRedlineDataChild>(pRedlineChild));
591 
592  if ( pLastRedlineChild )
593  pLastRedlineChild->pNext = pRedlineChild;
594  else
595  pParent->pNext = pRedlineChild;
596 
597  sAction = GetActionText(rRedln, nStack);
598  bool bValidChild = m_sFilterAction.isEmpty() || m_sFilterAction == sAction;
599  bValidChild = bValidChild && m_pTable->IsValidEntry(rRedln.GetAuthorString(nStack), rRedln.GetTimeStamp(nStack), rRedln.GetComment());
600  if (bHasRedlineAutoFormat)
601  bValidChild = bValidChild && bAutoFormatRedline;
602  bValidTree |= bValidChild;
603 
604  if (bValidChild)
605  {
606  std::unique_ptr<RedlinData> pData(new RedlinData);
607  pData->pData = pRedlineChild;
608  pData->bDisabled = true;
609 
610  OUString sImage(GetActionImage(rRedln, nStack));
611  OUString sAuthor = rRedln.GetAuthorString(nStack);
612  pData->aDateTime = rRedln.GetTimeStamp(nStack);
613  pData->eType = rRedln.GetType(nStack);
614  OUString sDateEntry = GetAppLangDateTimeString(pData->aDateTime);
615  OUString sComment = rRedln.GetComment(nStack);
616 
617  std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator());
618  OUString sId(weld::toId(pData.get()));
619  rTreeView.insert(pParent->xTLBParent.get(), -1, nullptr, &sId, nullptr, nullptr,
620  false, xChild.get());
621  m_RedlinData.push_back(std::move(pData));
622 
623  rTreeView.set_image(*xChild, sImage, -1);
624  rTreeView.set_text(*xChild, sAuthor, 1);
625  rTreeView.set_text(*xChild, sDateEntry, 2);
626  rTreeView.set_text(*xChild, sComment, 3);
627 
628  pRedlineChild->xTLBChild = std::move(xChild);
629  if (!bValidParent)
630  rTreeView.expand_row(*pParent->xTLBParent);
631  }
632  else
633  pRedlineChild->xTLBChild.reset();
634 
635  pLastRedlineChild = pRedlineChild;
636  }
637 
638  if (pLastRedlineChild)
639  pLastRedlineChild->pNext = nullptr;
640 
641  if (!bValidTree && pParent->xTLBParent)
642  {
643  rTreeView.remove(*pParent->xTLBParent);
644  pParent->xTLBParent.reset();
645  if (bHasRedlineAutoFormat)
646  m_aUsedSeqNo.erase(pParent);
647  }
648 }
649 
651 {
654 
655  std::vector<const weld::TreeIter*> aLBoxArr;
656 
657  weld::TreeView& rTreeView = m_pTable->GetWidget();
658 
659  // because of Bug of TLB that ALWAYS calls the SelectHandler at Remove:
661 
662  bool bChildrenRemoved = false;
663  rTreeView.thaw();
664  rTreeView.unselect_all();
665 
666  // set the cursor after the last entry because otherwise performance problem in TLB.
667  // TLB would otherwise reset the cursor at every Remove (expensive)
669  weld::TreeIter *pCurEntry = nullptr;
670  while( ( pCurEntry == nullptr ) && ( nPos > 0 ) )
671  {
672  --nPos;
673  pCurEntry = m_RedlineParents[nPos]->xTLBParent.get();
674  }
675 
676  if (pCurEntry)
677  rTreeView.set_cursor(*pCurEntry);
678 
679  rTreeView.freeze();
680 
681  for (SwRedlineTable::size_type i = nStart; i <= nEnd; i++)
682  {
683  if (!bChildrenRemoved && m_RedlineParents[i]->pNext)
684  {
685  SwRedlineDataChild * pChildPtr =
686  const_cast<SwRedlineDataChild*>(m_RedlineParents[i]->pNext);
687  auto it = std::find_if(m_RedlineChildren.begin(), m_RedlineChildren.end(),
688  [&pChildPtr](const std::unique_ptr<SwRedlineDataChild>& rChildPtr) { return rChildPtr.get() == pChildPtr; });
689  if (it != m_RedlineChildren.end())
690  {
691  sal_uInt16 nChildren = 0;
692  while (pChildPtr)
693  {
694  pChildPtr = const_cast<SwRedlineDataChild*>(pChildPtr->pNext);
695  nChildren++;
696  }
697 
698  m_RedlineChildren.erase(it, it + nChildren);
699  bChildrenRemoved = true;
700  }
701  }
702  weld::TreeIter *const pEntry = m_RedlineParents[i]->xTLBParent.get();
703  if (pEntry)
704  aLBoxArr.push_back(pEntry);
705  }
706 
707  std::sort(aLBoxArr.begin(), aLBoxArr.end(), [&rTreeView](const weld::TreeIter* a, const weld::TreeIter* b) {
708  return rTreeView.iter_compare(*a, *b) == -1;
709  });
710  // clear TLB from behind
711  for (auto it = aLBoxArr.rbegin(); it != aLBoxArr.rend(); ++it)
712  {
713  const weld::TreeIter* pIter = *it;
714  rTreeView.remove(*pIter);
715  }
716 
717  rTreeView.thaw();
718  rTreeView.connect_changed(LINK(this, SwRedlineAcceptDlg, SelectHdl));
719  // unfortunately by Remove it was selected from the TLB always again ...
720  rTreeView.unselect_all();
721  rTreeView.freeze();
722 
723  m_RedlineParents.erase(m_RedlineParents.begin() + nStart, m_RedlineParents.begin() + nEnd + 1);
724 }
725 
727 {
728  SwView *pView = ::GetActiveView();
729  SwWrtShell* pSh = pView->GetWrtShellPtr();
730  bool bHasRedlineAutoFormat = HasRedlineAutoFormat();
731 
733  nEnd = std::min(nEnd, (nCount - 1)); // also treats nEnd=SwRedlineTable::npos (until the end)
734 
735  if (nEnd == SwRedlineTable::npos)
736  return; // no redlines in the document
737 
738  weld::TreeView& rTreeView = m_pTable->GetWidget();
739 
740  SwRedlineDataParent* pRedlineParent;
741  const SwRangeRedline* pCurrRedline;
742  if (!nStart && !rTreeView.get_selected(nullptr))
743  {
744  pCurrRedline = pSh->GetCurrRedline();
745  if( !pCurrRedline )
746  {
747  pSh->SwCursorShell::Push();
748  pCurrRedline = pSh->SelNextRedline();
749  if( nullptr == pCurrRedline )
750  pCurrRedline = pSh->SelPrevRedline();
751  pSh->SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
752  }
753  }
754  else
755  pCurrRedline = nullptr;
756 
757  rTreeView.freeze();
758  if (m_pTable->IsSorted())
759  rTreeView.make_unsorted();
760 
761  bool bIsShowChangesInMargin = SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin();
762 
763  // collect redlines of tracked table or table row insertion/deletions under a single tree list
764  // item to accept/reject table (row) insertion/deletion with a single click on Accept/Reject
765  // Note: because update of the tree list depends on parent count, we don't modify
766  // m_RedlineParents, only store the 2nd and more redlines as children of the tree list
767  // item of the first redline
768 
769  // count of items stored as children (to adjust parent position)
770  sal_Int32 nSkipRedlines = 0;
771  // count of items of the actual table row (or joined table rows) stored as children =
772  // redlines of the row(s) - 1 (first redline is associated to the parent tree list item)
773  sal_Int32 nSkipRedline = 0;
774  // nSkipRedline of the previous table row (to join multiple table rows, if it's possible)
775  sal_Int32 nPrevSkipRedline = 0;
776 
777  // last SwRangeRedline in the table row
779  // descriptor redline of the tracked table row
781  // descriptor redline of the previous table row to join the table rows
783 
784  // show all redlines as tree list items,
785  // redlines of a tracked table (row) insertion/deletion showed as children of a single parent
786  for (SwRedlineTable::size_type i = nStart; i <= nEnd; i++)
787  {
788  const SwRangeRedline& rRedln = pSh->GetRedline(i);
789  const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
790 
791  pRedlineParent = new SwRedlineDataParent;
792  pRedlineParent->pData = pRedlineData;
793  pRedlineParent->pNext = nullptr;
794 
795  // handle tracked table row changes
796  const SwTableBox* pTableBox;
797  const SwTableLine* pTableLine;
798  // first SwRangeRedline of the tracked table row(s), base of the parent tree list
799  // of the other SwRangeRedlines of the tracked table row(s)
801  if ( // not recognized yet as tracked table row change
802  nLastChangeInRow == SwRedlineTable::npos &&
803  nullptr != ( pTableBox = pSh->GetRedline(i).Start()->nNode.GetNode().GetTableBox() ) &&
804  nullptr != ( pTableLine = pTableBox->GetUpper() ) &&
805  // it's a tracked row change based on the cached row data
806  RedlineType::None != pTableLine->GetRedlineType() )
807  {
808  SwRedlineTable::size_type nRedline = i;
809  nRowChange = pTableLine->UpdateTextChangesOnly(nRedline);
810  if ( SwRedlineTable::npos != nRowChange )
811  {
812  nSkipRedline = nRedline - i - 1;
813  nLastChangeInRow = nRedline - 1;
814  // join the consecutive deleted/inserted rows under a single treebox item,
815  // if they have the same redline data (equal type, author and time stamp)
816  if ( nPrevRowChange != SwRedlineTable::npos &&
817  pSh->GetRedline(nRowChange).GetRedlineData() == pSh->GetRedline(nPrevRowChange).GetRedlineData() )
818  {
819  nSkipRedline += nPrevSkipRedline + 1;
820  nPrevSkipRedline = 0;
821  nPrevRowChange = SwRedlineTable::npos;
822  }
823  else
824  nNewTableParent = i;
825  }
826  }
827 
828  bool bRowChange(SwRedlineTable::npos != nLastChangeInRow);
829 
830  bool bShowDeletedTextAsComment = bIsShowChangesInMargin &&
831  RedlineType::Delete == rRedln.GetType() && rRedln.GetComment().isEmpty();
832  const OUString& sComment = bShowDeletedTextAsComment
833  ? const_cast<SwRangeRedline&>(rRedln).GetDescr()
834  : rRedln.GetComment();
835  pRedlineParent->sComment = sComment.replace('\n', ' ');
836  m_RedlineParents.insert(m_RedlineParents.begin() + i,
837  std::unique_ptr<SwRedlineDataParent>(pRedlineParent));
838 
839  std::unique_ptr<RedlinData> pData(new RedlinData);
840  pData->pData = pRedlineParent;
841  pData->bDisabled = false;
842 
843  // use descriptor SwRangeRedline of the changed row, if needed to show
844  // the correct redline type, author and time stamp of the tracked row change
845  const SwRangeRedline& rChangeRedln = pSh->GetRedline(bRowChange ? nRowChange : i);
846 
847  OUString sImage = GetActionImage(rChangeRedln, 0, bRowChange && nNewTableParent != SwRedlineTable::npos );
848  OUString sAuthor = rChangeRedln.GetAuthorString(0);
849  pData->aDateTime = rChangeRedln.GetTimeStamp(0);
850  pData->eType = rChangeRedln.GetType(0);
851  OUString sDateEntry = GetAppLangDateTimeString(pData->aDateTime);
852 
853  OUString sId = weld::toId(pData.get());
854  std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator());
855 
856  if ( !bRowChange || nNewTableParent != SwRedlineTable::npos )
857  rTreeView.insert(nullptr, i - nSkipRedlines, nullptr, &sId, nullptr, nullptr, false, xParent.get());
858  else
859  {
860  // put 2nd or more redlines of deleted/inserted rows as children of their first redline
861  SwRedlineDataParent *const pParent = m_RedlineParents[nLastChangeInRow - nSkipRedline].get();
862  rTreeView.insert(pParent->xTLBParent.get(), -1, nullptr, &sId, nullptr, nullptr, false, xParent.get());
863  }
864 
865  m_RedlinData.push_back(std::move(pData));
866 
867  rTreeView.set_image(*xParent, sImage, -1);
868  rTreeView.set_text(*xParent, sAuthor, 1);
869  rTreeView.set_text(*xParent, sDateEntry, 2);
870  rTreeView.set_text(*xParent, sComment, 3);
871 
872  if (pCurrRedline == &rRedln)
873  {
874  rTreeView.thaw();
875  rTreeView.set_cursor(*xParent);
876  rTreeView.select(*xParent);
877  rTreeView.scroll_to_row(*xParent);
878  rTreeView.freeze();
879  }
880 
881  pRedlineParent->xTLBParent = std::move(xParent);
882 
883  InsertChildren(pRedlineParent, rRedln, bHasRedlineAutoFormat);
884 
885  // end of a tracked deletion/insertion of a table row
886  if ( nLastChangeInRow != SwRedlineTable::npos && i == nLastChangeInRow )
887  {
888  nSkipRedlines += nSkipRedline;
889  nPrevSkipRedline = nSkipRedline;
890  nSkipRedline = 0;
891  nPrevRowChange = nRowChange;
892  nNewTableParent = SwRedlineTable::npos;
893  nLastChangeInRow = SwRedlineTable::npos;
894  }
895  }
896  rTreeView.thaw();
897  if (m_pTable->IsSorted())
898  rTreeView.make_sorted();
899 }
900 
901 void SwRedlineAcceptDlg::CallAcceptReject( bool bSelect, bool bAccept )
902 {
904  int nPos = -1;
905 
906  typedef std::vector<std::unique_ptr<weld::TreeIter>> ListBoxEntries_t;
907  ListBoxEntries_t aRedlines;
908 
909  // don't activate
910  OSL_ENSURE( !m_bInhibitActivate,
911  "recursive call of CallAcceptReject?");
912  m_bInhibitActivate = true;
913 
914  weld::TreeView& rTreeView = m_pTable->GetWidget();
915 
916  auto lambda = [this, pSh, bSelect, bAccept, &rTreeView, &nPos, &aRedlines](weld::TreeIter& rEntry) {
917  if (!rTreeView.get_iter_depth(rEntry))
918  {
919  if (bSelect && nPos == -1)
920  nPos = rTreeView.get_iter_index_in_parent(rEntry);
921 
922  RedlinData *pData = weld::fromId<RedlinData*>(rTreeView.get_id(rEntry));
923 
924  bool bIsNotFormatted = true;
925 
926  // first remove only changes with insertion/deletion, if they exist
927  // (format-only changes haven't had real rejection yet, only an
928  // approximation: clear direct formatting, so try to warn
929  // with the extended button label "Reject All/Clear formatting")
930  if ( !bSelect && !bAccept && !m_bOnlyFormatedRedlines )
931  {
932  SwRedlineTable::size_type nPosition = GetRedlinePos(rEntry);
933  const SwRangeRedline& rRedln = pSh->GetRedline(nPosition);
934 
935  if( RedlineType::Format == rRedln.GetType() )
936  bIsNotFormatted = false;
937  }
938 
939  if (!pData->bDisabled && bIsNotFormatted)
940  aRedlines.emplace_back(rTreeView.make_iterator(&rEntry));
941  }
942  return false;
943  };
944 
945  // collect redlines-to-be-accepted/rejected in aRedlines vector
946  if (bSelect)
947  rTreeView.selected_foreach(lambda);
948  else
949  rTreeView.all_foreach(lambda);
950 
952  if( !bAccept )
953  FnAccRej = &SwEditShell::RejectRedline;
954 
955  SwWait aWait( *pSh->GetView().GetDocShell(), true );
956  pSh->StartAction();
957 
958  bool bMoreRedlines( aRedlines.size() > 1 ||
959  // single item with children, e.g. multiple redlines of a table or table row deletion/insertion
960  ( aRedlines.size() == 1 && rTreeView.iter_n_children(*aRedlines[0]) > 0 ) );
961 
962  // don't add extra Undo label to a single item only with redline stack (i.e. old changes
963  // on the same text range, stored only in OOXML)
964  if ( bMoreRedlines && aRedlines.size() == 1 )
965  {
966  std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*aRedlines[0] ));
967  RedlinData *pData = weld::fromId<RedlinData*>(rTreeView.get_id(*xChild));
968  if ( pData->bDisabled )
969  bMoreRedlines = false;
970  }
971 
972  if ( bMoreRedlines )
973  {
974  OUString aTmpStr;
975  {
976  SwRewriter aRewriter;
977  aRewriter.AddRule(UndoArg1,
978  OUString::number(aRedlines.size()));
979  aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
980  }
981 
982  SwRewriter aRewriter;
983  aRewriter.AddRule(UndoArg1, aTmpStr);
984 
986  &aRewriter);
987  }
988 
989  // accept/reject the redlines in aRedlines. The absolute
990  // position may change during the process (e.g. when two redlines
991  // are merged in result of another one being deleted), so the
992  // position must be resolved late and checked before using it.
993  // (cf #102547#)
994  for (const auto& rRedLine : aRedlines)
995  {
996  SwRedlineTable::size_type nPosition = GetRedlinePos( *rRedLine );
997  if( nPosition != SwRedlineTable::npos )
998  (pSh->*FnAccRej)( nPosition );
999 
1000  // handle redlines of table rows, stored as children of the item associated
1001  // to the deleted/inserted table row(s)
1002  std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*rRedLine ));
1003  if ( rTreeView.iter_children(*xChild) )
1004  {
1005  RedlinData *pData = weld::fromId<RedlinData*>(rTreeView.get_id(*xChild));
1006  // disabled for redline stack, but not for redlines of table rows
1007  if ( !pData->bDisabled )
1008  {
1009  do
1010  {
1011  nPosition = GetRedlinePos( *xChild );
1012  if( nPosition != SwRedlineTable::npos )
1013  (pSh->*FnAccRej)( nPosition );
1014  }
1015  while ( rTreeView.iter_next_sibling(*xChild) );
1016  }
1017  }
1018  }
1019 
1020  if ( bMoreRedlines )
1021  {
1022  pSh->EndUndo();
1023  }
1024 
1025  pSh->EndAction();
1026 
1027  m_bInhibitActivate = false;
1028  Activate();
1029 
1030  if (nPos != -1 && rTreeView.n_children())
1031  {
1032  if (nPos >= rTreeView.n_children())
1033  nPos = rTreeView.n_children() - 1;
1034  rTreeView.select(nPos);
1035  rTreeView.scroll_to_row(nPos);
1036  rTreeView.set_cursor(nPos);
1037  SelectHdl(rTreeView);
1038  }
1039  m_pTPView->EnableUndo();
1040 }
1041 
1043 {
1045  weld::TreeView& rTreeView = m_pTable->GetWidget();
1046  return pSh->FindRedlineOfData( *static_cast<SwRedlineDataParent*>(weld::fromId<RedlinData*>(
1047  rTreeView.get_id(rEntry))->pData)->pData );
1048 }
1049 
1051 {
1052  CallAcceptReject( true, true );
1053 }
1054 
1056 {
1057  CallAcceptReject( false, true );
1058 }
1059 
1061 {
1062  CallAcceptReject( true, false );
1063 }
1064 
1066 {
1067  CallAcceptReject( false, false );
1068 }
1069 
1071 {
1072  SwView * pView = ::GetActiveView();
1073  pView->GetViewFrame()->GetDispatcher()->
1074  Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1075  m_pTPView->EnableUndo(pView->GetSlotState(SID_UNDO) != nullptr);
1076 
1077  Activate();
1078 }
1079 
1081 {
1082  SvxTPFilter *pFilterTP = m_xTabPagesCTRL->GetFilterPage();
1083 
1084  if (pFilterTP->IsAction())
1085  m_sFilterAction = pFilterTP->GetLbAction()->get_active_text();
1086  else
1087  m_sFilterAction.clear();
1088 
1089  Init();
1090 }
1091 
1093 {
1094  m_aSelectTimer.Start();
1095 }
1096 
1098 {
1100  m_aSelectTimer.Stop();
1101 
1102  bool bIsNotFormated = false;
1103  bool bSel = false;
1104 
1105  //#98883# don't select redlines while the dialog is not focused
1106  //#107938# But not only ask pTable if it has the focus. To move
1107  // the selection to the selected redline any child of pParentDlg
1108  // may the focus.
1109  if (!m_xParentDlg || m_xParentDlg->has_toplevel_focus())
1110  {
1111  weld::TreeView& rTreeView = m_pTable->GetWidget();
1112  std::unique_ptr<weld::TreeIter> xActEntry(rTreeView.make_iterator());
1113  if (rTreeView.get_selected(xActEntry.get()))
1114  {
1115  pSh->StartAction();
1116  pSh->EnterStdMode();
1117  SwViewShell::SetCareDialog(m_xParentDlg);
1118 
1119  rTreeView.selected_foreach([this, pSh, &rTreeView, &xActEntry, &bIsNotFormated, &bSel](weld::TreeIter& rEntry){
1120  rTreeView.copy_iterator(rEntry, *xActEntry);
1121  if (rTreeView.get_iter_depth(rEntry))
1122  {
1123  rTreeView.iter_parent(*xActEntry);
1124  if (rTreeView.is_selected(*xActEntry))
1125  return false; // don't select twice
1126  }
1127  else
1128  bSel = true;
1129 
1130  // #98864# find the selected redline (ignore, if the redline is already gone)
1131  SwRedlineTable::size_type nPos = GetRedlinePos(*xActEntry);
1132  if (nPos != SwRedlineTable::npos)
1133  {
1134 
1135  const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
1136  bIsNotFormated |= RedlineType::Format != rRedln.GetType();
1137 
1138  if (pSh->GotoRedline(nPos, true))
1139  {
1140  pSh->SetInSelect();
1141  pSh->EnterAddMode();
1142  }
1143  }
1144 
1145  // select all redlines of tracked table rows
1146  std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*xActEntry ));
1147  if ( rTreeView.iter_children(*xChild) )
1148  {
1149  RedlinData *pData = reinterpret_cast<RedlinData*>(rTreeView.get_id(*xChild).toInt64());
1150  // disabled for redline stack, but not for redlines of table rows
1151  if ( !pData->bDisabled )
1152  {
1153  do
1154  {
1155  nPos = GetRedlinePos(*xChild);
1156  if (nPos != SwRedlineTable::npos)
1157  {
1158  const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
1159  bIsNotFormated |= RedlineType::Format != rRedln.GetType();
1160 
1161  if (pSh->GotoRedline(nPos, true))
1162  {
1163  pSh->SetInSelect();
1164  pSh->EnterAddMode();
1165  }
1166  }
1167  }
1168  while ( rTreeView.iter_next_sibling(*xChild) );
1169  }
1170  }
1171  return false;
1172  });
1173 
1174  pSh->LeaveAddMode();
1175  pSh->EndAction();
1176  SwViewShell::SetCareDialog(nullptr);
1177  }
1178  }
1179 
1180  bool const bEnable = !pSh->GetDoc()->GetDocShell()->IsReadOnly()
1181  && !pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
1182  m_pTPView->EnableAccept( bEnable && bSel /*&& !bReadonlySel*/ );
1183  m_pTPView->EnableReject( bEnable && bSel /*&& !bReadonlySel*/ );
1184  m_pTPView->EnableClearFormat( bEnable && bSel && !bIsNotFormated /*&& !bReadonlySel*/ );
1185  m_pTPView->EnableAcceptAll( bEnable );
1186  m_pTPView->EnableRejectAll( bEnable );
1187  m_pTPView->EnableClearFormatAll( bEnable && m_bOnlyFormatedRedlines );
1188 }
1189 
1190 IMPL_LINK(SwRedlineAcceptDlg, CommandHdl, const CommandEvent&, rCEvt, bool)
1191 {
1192  if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1193  return false;
1194 
1196  const SwRangeRedline *pRed = nullptr;
1197 
1198  weld::TreeView& rTreeView = m_pTable->GetWidget();
1199  std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
1200  bool bEntry = rTreeView.get_selected(xEntry.get());
1201  if (bEntry)
1202  {
1203  std::unique_ptr<weld::TreeIter> xTopEntry(rTreeView.make_iterator(xEntry.get()));
1204 
1205  if (rTreeView.get_iter_depth(*xTopEntry))
1206  rTreeView.iter_parent(*xTopEntry);
1207 
1208  SwRedlineTable::size_type nPos = GetRedlinePos(*xTopEntry);
1209 
1210  // disable commenting for protected areas
1211  if (nPos != SwRedlineTable::npos && (pRed = pSh->GotoRedline(nPos, true)) != nullptr)
1212  {
1213  if( pSh->IsCursorPtAtEnd() )
1214  pSh->SwapPam();
1215  pSh->SetInSelect();
1216  }
1217  }
1218 
1219  m_xPopup->set_sensitive("writeredit", bEntry && pRed &&
1220  !rTreeView.get_iter_depth(*xEntry) &&
1221  rTreeView.count_selected_rows() == 1);
1222  m_xPopup->set_sensitive("writersort", rTreeView.n_children() != 0);
1223  int nColumn = rTreeView.get_sort_column();
1224  if (nColumn == -1)
1225  nColumn = 4;
1226  for (sal_Int32 i = 0; i < 5; ++i)
1227  m_xSortMenu->set_active("writersort" + OString::number(i), i == nColumn);
1228 
1229  OString sCommand = m_xPopup->popup_at_rect(&rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1230 
1231  if (sCommand == "writeredit")
1232  {
1233  if (bEntry)
1234  {
1235  if (rTreeView.get_iter_depth(*xEntry))
1236  rTreeView.iter_parent(*xEntry);
1237 
1238  SwRedlineTable::size_type nPos = GetRedlinePos(*xEntry);
1239 
1240  if (nPos == SwRedlineTable::npos)
1241  return true;
1242 
1243  const SwRangeRedline &rRedline = pSh->GetRedline(nPos);
1244 
1245  /* enable again once we have redline comments in the margin
1246  sComment = rRedline.GetComment();
1247  if ( !sComment.Len() )
1248  GetActiveView()->GetDocShell()->Broadcast(SwRedlineHint(&rRedline,SWREDLINE_INSERTED));
1249  const_cast<SwRangeRedline&>(rRedline).Broadcast(SwRedlineHint(&rRedline,SWREDLINE_FOCUS));
1250  */
1251 
1252  OUString sComment = convertLineEnd(rRedline.GetComment(), GetSystemLineEnd());
1254  ::DialogGetRanges fnGetRange = pFact->GetDialogGetRangesFunc();
1255  SfxItemSet aSet( pSh->GetAttrPool(), fnGetRange() );
1256 
1257  aSet.Put(SvxPostItTextItem(sComment, SID_ATTR_POSTIT_TEXT));
1258  aSet.Put(SvxPostItAuthorItem(rRedline.GetAuthorString(), SID_ATTR_POSTIT_AUTHOR));
1259 
1261  rRedline.GetRedlineData().GetTimeStamp() ),
1262  SID_ATTR_POSTIT_DATE ));
1263 
1264  ScopedVclPtr<AbstractSvxPostItDialog> pDlg(pFact->CreateSvxPostItDialog(&rTreeView, aSet));
1265 
1266  pDlg->HideAuthor();
1267 
1268  TranslateId pResId;
1269  switch( rRedline.GetType() )
1270  {
1271  case RedlineType::Insert:
1272  pResId = STR_REDLINE_INSERTED;
1273  break;
1274  case RedlineType::Delete:
1275  pResId = STR_REDLINE_DELETED;
1276  break;
1277  case RedlineType::Format:
1278  case RedlineType::ParagraphFormat:
1279  pResId = STR_REDLINE_FORMATTED;
1280  break;
1281  case RedlineType::Table:
1282  pResId = STR_REDLINE_TABLECHG;
1283  break;
1284  default:;//prevent warning
1285  }
1286  OUString sTitle(SwResId(STR_REDLINE_COMMENT));
1287  if (pResId)
1288  sTitle += SwResId(pResId);
1289  pDlg->SetText(sTitle);
1290 
1291  SwViewShell::SetCareDialog(pDlg->GetDialog());
1292 
1293  if ( pDlg->Execute() == RET_OK )
1294  {
1295  const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
1296  OUString sMsg(pOutSet->Get(SID_ATTR_POSTIT_TEXT).GetValue());
1297 
1298  // insert / change comment
1299  pSh->SetRedlineComment(sMsg);
1300  rTreeView.set_text(*xEntry, sMsg.replace('\n', ' '), 3);
1301  Init();
1302  }
1303 
1304  SwViewShell::SetCareDialog(nullptr);
1305  pDlg.disposeAndClear();
1306  }
1307  }
1308  else if (!sCommand.isEmpty())
1309  {
1310  int nSortMode = o3tl::toInt32(sCommand.subView(10));
1311 
1312  if (nSortMode == 4 && nColumn == 4)
1313  return true; // we already have it
1314  if (nSortMode == 4)
1315  nSortMode = -1; // unsorted / sorted by position
1316 
1317  SwWait aWait( *::GetActiveView()->GetDocShell(), false );
1318  m_pTable->HeaderBarClick(nSortMode);
1319  if (nSortMode == -1)
1320  Init(); // newly fill everything
1321  }
1322  return true;
1323 }
1324 
1325 namespace
1326 {
1327  OUString lcl_StripAcceptChgDat(OUString &rExtraString)
1328  {
1329  OUString aStr;
1330  while(true)
1331  {
1332  sal_Int32 nPos = rExtraString.indexOf("AcceptChgDat:");
1333  if (nPos == -1)
1334  break;
1335  // try to read the alignment string "ALIGN:(...)"; if none existing,
1336  // it's an old version
1337  sal_Int32 n1 = rExtraString.indexOf('(', nPos);
1338  if (n1 != -1)
1339  {
1340  sal_Int32 n2 = rExtraString.indexOf(')', n1);
1341  if (n2 != -1)
1342  {
1343  // cut out the alignment string
1344  aStr = rExtraString.copy(nPos, n2 - nPos + 1);
1345  rExtraString = rExtraString.replaceAt(nPos, n2 - nPos + 1, u"");
1346  aStr = aStr.copy(n1 - nPos + 1);
1347  }
1348  }
1349  }
1350  return aStr;
1351  }
1352 }
1353 
1354 void SwRedlineAcceptDlg::Initialize(OUString& rExtraString)
1355 {
1356  if (rExtraString.isEmpty())
1357  return;
1358 
1359  OUString aStr = lcl_StripAcceptChgDat(rExtraString);
1360  if (aStr.isEmpty())
1361  return;
1362 
1363  int nCount = aStr.toInt32();
1364  if (nCount <= 2)
1365  return;
1366 
1367  std::vector<int> aEndPos;
1368 
1369  for (int i = 0; i < nCount; ++i)
1370  {
1371  sal_Int32 n1 = aStr.indexOf(';');
1372  aStr = aStr.copy( n1+1 );
1373  aEndPos.push_back(aStr.toInt32());
1374  }
1375 
1376  bool bUseless = false;
1377 
1378  std::vector<int> aWidths;
1379  for (int i = 1; i < nCount; ++i)
1380  {
1381  aWidths.push_back(aEndPos[i] - aEndPos[i - 1]);
1382  if (aWidths.back() <= 0)
1383  bUseless = true;
1384  }
1385 
1386  if (!bUseless)
1387  {
1388  // turn column end points back to column widths, ignoring the small
1389  // value used for the expander column
1390  weld::TreeView& rTreeView = m_pTable->GetWidget();
1391  rTreeView.set_column_fixed_widths(aWidths);
1392  }
1393 }
1394 
1395 void SwRedlineAcceptDlg::FillInfo(OUString &rExtraData) const
1396 {
1397  //remove any old one before adding a new one
1398  lcl_StripAcceptChgDat(rExtraData);
1399  rExtraData += "AcceptChgDat:(";
1400 
1401  const int nTabCount = 4;
1402 
1403  rExtraData += OUString::number(nTabCount);
1404  rExtraData += ";";
1405 
1406  weld::TreeView& rTreeView = m_pTable->GetWidget();
1407  std::vector<int> aWidths;
1408  // turn column widths back into column end points for compatibility
1409  // with how they used to be stored, including a small value for the
1410  // expander column
1411  aWidths.push_back(rTreeView.get_checkbox_column_width());
1412  for (int i = 0; i < nTabCount - 1; ++i)
1413  {
1414  int nWidth = rTreeView.get_column_width(i);
1415  assert(nWidth > 0 && "suspicious to get a value like this");
1416  aWidths.push_back(aWidths.back() + nWidth);
1417  }
1418 
1419  for (auto a : aWidths)
1420  {
1421  rExtraData += OUString::number(a);
1422  rExtraData += ";";
1423  }
1424  rExtraData += ")";
1425 }
1426 
1428  : PanelLayout(pParent, "ManageChangesPanel", "modules/swriter/ui/managechangessidebar.ui")
1429  , mxContentArea(m_xBuilder->weld_container("content_area"))
1430 {
1431  mpImplDlg.reset(new SwRedlineAcceptDlg(nullptr, m_xBuilder.get(), mxContentArea.get()));
1432 
1433  mpImplDlg->Init();
1434 
1435  // we want to receive SfxHintId::DocChanged
1436  StartListening(*(SW_MOD()->GetView()->GetDocShell()));
1437 }
1438 
1440 {
1441 }
1442 
1444 {
1445  if (mpImplDlg && rHint.GetId() == SfxHintId::DocChanged)
1446  mpImplDlg->Activate();
1447 }
1448 
1449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsSorted() const
virtual void FillInfo(SfxChildWinInfo &) const
virtual void set_text(int row, const OUString &rText, int col=-1)=0
std::shared_ptr< SfxDialogController > & GetController()
SfxViewFrame * GetViewFrame() const
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
sal_uInt16 GetSeqNo() const
Definition: redline.hxx:150
virtual int get_iter_index_in_parent(const TreeIter &rIter) const =0
const SfxPoolItem * ExecuteList(sal_uInt16 nSlot, SfxCallMode nCall, std::initializer_list< SfxPoolItem const * > args, std::initializer_list< SfxPoolItem const * > internalargs=std::initializer_list< SfxPoolItem const * >())
OUString aExtraString
const SwRangeRedline & GetRedline(SwRedlineTable::size_type nPos) const
Definition: edredln.cxx:53
TOOLS_DLLPUBLIC OString convertLineEnd(const OString &rIn, LineEnd eLineEnd)
virtual int count_selected_rows() const =0
void Init()
void SetRejectAllClickHdl(const Link< SvxTPView *, void > &rLink)
void Initialize(SfxChildWinInfo const *pInfo)
SwTableBox * GetTableBox() const
If node is in a table return the respective table box.
Definition: node.cxx:754
OUString const & GetAuthorString(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1919
std::unique_ptr< SvxAcceptChgCtr > m_xTabPagesCTRL
Definition: redlndlg.hxx:80
virtual const css::uno::Sequence< sal_Int8 > & GetRedlinePassword() const =0
OUString m_sInserted
Definition: redlndlg.hxx:67
SwView * GetActiveView()
Definition: swmodul1.cxx:116
virtual bool iter_parent(TreeIter &rIter) const =0
void SetWriterView()
SwDocShell * GetDocShell()
Definition: doc.hxx:1351
virtual void copy_iterator(const TreeIter &rSource, TreeIter &rDest) const =0
void FillInfo(OUString &rExtraData) const
Definition: redlndlg.cxx:1395
const SwRedlineData * Next() const
Definition: redline.hxx:131
const SwRangeRedline * SelNextRedline()
Definition: crstrvl.cxx:2362
void unselect_all()
virtual void insert(const TreeIter *pParent, int pos, const OUString *pStr, const OUString *pId, const OUString *pIconName, VirtualDevice *pImageSurface, bool bChildrenOnDemand, TreeIter *pRet)=0
SAL_DLLPRIVATE OUString GetActionText(const SwRangeRedline &rRedln, sal_uInt16 nStack=0)
Definition: redlndlg.cxx:335
SwNodeIndex nNode
Definition: pam.hxx:38
int n1
std::unique_ptr< sal_Int32[]> pData
SfxDispatcher * GetDispatcher()
static SAL_DLLPRIVATE OUString GetActionImage(const SwRangeRedline &rRedln, sal_uInt16 nStack=0, bool bRowChanges=false)
Definition: redlndlg.cxx:307
static SvxAbstractDialogFactory * Create()
bool IsModified() const
Changes in document?
Definition: edws.cxx:65
virtual void make_unsorted()=0
const ::avmedia::MediaItem * Execute(const SdrMarkView *pSdrView, SfxRequest const &rReq)
virtual void Activate() override
Definition: redlndlg.cxx:90
std::unique_ptr< weld::TreeIter > xTLBParent
Definition: redlndlg.hxx:47
SwUndoId EndUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Closes parenthesis of nUndoId, not used by UI.
Definition: edws.cxx:234
SwDocShell * GetOldDocShell()
Definition: chldwrap.hxx:41
virtual void clear()=0
SwTableLine is one table row in the document model.
Definition: swtable.hxx:357
SwNode & GetNode() const
Definition: ndindex.hxx:128
const SwRangeRedline * GotoRedline(SwRedlineTable::size_type nArrPos, bool bSelect)
Definition: move.cxx:717
void EnterStdMode()
Definition: select.cxx:551
bool HasRedlineAutoFormat() const
Definition: redlndlg.hxx:114
void EnableRejectAll(bool bFlag)
virtual bool is_selected(int pos) const =0
bool IsAnnotation() const
Definition: docredln.cxx:1934
OUString GetAppLangDateTimeString(const DateTime &)
Definition: uitool.cxx:862
void EnableClearFormat(bool bFlag)
SAL_DLLPRIVATE SwRedlineTable::size_type CalcDiff(SwRedlineTable::size_type nStart, bool bChild)
Definition: redlndlg.cxx:474
SfxHintId GetId() const
virtual ~SwModelessRedlineAcceptDlg() override
Definition: redlndlg.cxx:136
virtual std::unique_ptr< TreeIter > make_iterator(const TreeIter *pOrig=nullptr) const =0
void ClearAuthors()
void SetRejectClickHdl(const Link< SvxTPView *, void > &rLink)
void SwapPam()
Definition: crsrsh.cxx:976
virtual void thaw()=0
virtual int get_column_width(int nCol) const =0
Used by the UI to modify the document model.
Definition: wrtsh.hxx:96
OUString SwResId(TranslateId aId)
Definition: swmodule.cxx:164
std::unique_ptr< weld::Container > mxContentArea
Definition: redlndlg.hxx:157
SwChildWinWrapper * m_pChildWin
Definition: redlndlg.hxx:129
std::unique_ptr< weld::Builder > m_xBuilder
void connect_changed(const Link< TreeView &, void > &rLink)
std::vector< std::unique_ptr< SwRedlineDataChild > > m_RedlineChildren
Definition: redlndlg.hxx:61
const SwView & GetView() const
Definition: wrtsh.hxx:437
int n2
OUString m_sAutoFormat
Definition: redlndlg.hxx:73
void LeaveAddMode()
Definition: select.cxx:641
weld::ComboBox * GetLbAction()
const DateTime & GetTimeStamp(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1924
int nCount
virtual int n_children() const =0
OUString m_sTableChgd
Definition: redlndlg.hxx:70
LineEnd GetSystemLineEnd()
void ShowUndo()
virtual void set_column_fixed_widths(const std::vector< int > &rWidths)=0
virtual void selected_foreach(const std::function< bool(TreeIter &)> &func)=0
SwRedlineTable::size_type UpdateTextChangesOnly(SwRedlineTable::size_type &rRedlinePos, bool bUpdateProperty=true) const
Definition: swtable.cxx:1610
OUString m_sFormated
Definition: redlndlg.hxx:69
virtual OUString get_id(int pos) const =0
IMPL_LINK(SwRedlineAcceptDlg, CommandHdl, const CommandEvent &, rCEvt, bool)
Definition: redlndlg.cxx:1190
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
We need to be a SfxListener to be able to update the list of changes when we get SfxHintId::DocChange...
Definition: redlndlg.cxx:1443
SwDoc * GetDoc() const
Definition: viewsh.hxx:282
std::vector< std::unique_ptr< SwRedlineDataParent > > m_RedlineParents
Definition: redlndlg.hxx:59
const IDocumentRedlineAccess & getIDocumentRedlineAccess() const
Provides access to the document redline interface.
Definition: viewsh.cxx:2785
sal_uInt16 GetStackCount() const
Definition: docredln.cxx:1906
SvxTPView * m_pTPView
Definition: redlndlg.hxx:82
const SwRedlineData & GetRedlineData(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1952
SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SvxContourDlgChildWindow, SID_CONTOUR_DLG)
void SetInSelect()
Definition: wrtsh.hxx:145
bool AcceptRedline(SwRedlineTable::size_type nPos)
Definition: edredln.cxx:67
const SfxItemPool & GetAttrPool() const
Definition: viewsh.hxx:617
OUString m_sFilterAction
Definition: redlndlg.hxx:72
bool IsAutoFormat() const
Definition: redline.hxx:204
#define SW_MOD()
Definition: swmodule.hxx:255
SAL_DLLPRIVATE SwRedlineTable::size_type GetRedlinePos(const weld::TreeIter &rEntry)
Definition: redlndlg.cxx:1042
SAL_DLLPRIVATE void InitAuthors()
Definition: redlndlg.cxx:236
int i
const SfxPoolItem * GetSlotState(sal_uInt16 nSlotId, const SfxInterface *pIF=nullptr, SfxItemSet *pStateSet=nullptr)
std::unique_ptr< SwRedlineAcceptDlg > mpImplDlg
Definition: redlndlg.hxx:156
uno_Any a
bool SetRedlineComment(const OUString &rS)
Set comment to Redline at position.
Definition: edredln.cxx:150
std::unique_ptr< weld::TreeIter > xTLBChild
Definition: redlndlg.hxx:40
OUString Apply(const OUString &rStr) const
Definition: SwRewriter.cxx:39
void Initialize(SfxChildWinInfo *pInfo)
Definition: redlndlg.cxx:122
SwRedlineTable::size_type GetRedlineCount() const
Definition: edredln.cxx:48
const SwRangeRedline * SelPrevRedline()
Definition: crstrvl.cxx:2390
virtual void freeze()=0
void EnableClearFormatAll(bool bFlag)
vector_type::size_type size_type
Definition: docary.hxx:222
SwRedlineAcceptDlg(SwRedlineAcceptDlg const &)=delete
SwRedlineTable::size_type FindRedlineOfData(const SwRedlineData &) const
Search Redline for this Data and.
Definition: edredln.cxx:186
const SwRedlineDataChild * pNext
Definition: redlndlg.hxx:46
SwUndoId StartUndo(SwUndoId eUndoId=SwUndoId::EMPTY, const SwRewriter *pRewriter=nullptr)
Undo: set up Undo parenthesis, return nUndoId of this parenthesis.
Definition: edws.cxx:223
void AddRule(SwUndoArg eWhat, const OUString &rWith)
Definition: SwRewriter.cxx:25
const DateTime & GetTimeStamp() const
Definition: redline.hxx:130
const SwRedlineData * pChild
Definition: redlndlg.hxx:38
OUString GetSelectedAuthor() const
virtual void set_active(int pos)=0
void StartListening(SfxBroadcaster &rBroadcaster, DuplicateHandling eDuplicateHanding=DuplicateHandling::Unexpected)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
SvxRedlinTable * m_pTable
Definition: redlndlg.hxx:83
virtual ~SwRedlineAcceptPanel() override
Definition: redlndlg.cxx:1439
virtual void expand_row(const TreeIter &rIter)=0
void SetTimeout(sal_uInt64 nTimeoutMs)
void SetOldDocShell(SwDocShell *pDcSh)
Definition: chldwrap.hxx:42
std::unique_ptr< weld::Container > m_xContentArea
Definition: redlndlg.hxx:127
std::unique_ptr< SwRedlineAcceptDlg > m_xImplDlg
Definition: redlndlg.hxx:128
void DisableUndo()
const SwPosition * Start() const
Definition: pam.hxx:213
SwDocShell * GetDocShell()
Definition: view.cxx:1132
bool IsReadOnly() const
SAL_DLLPRIVATE void InsertParents(SwRedlineTable::size_type nStart, SwRedlineTable::size_type nEnd=SwRedlineTable::npos)
Definition: redlndlg.cxx:726
virtual bool iter_children(TreeIter &rIter) const =0
IMPL_LINK_NOARG(SwRedlineAcceptDlg, AcceptHdl, SvxTPView *, void)
Definition: redlndlg.cxx:1050
virtual void remove(int pos)=0
void StartAction()
Definition: crsrsh.cxx:227
int get_checkbox_column_width() const
const OUString & GetComment(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1939
void EnableUndo(bool bFlag=true)
bool IsValidEntry(std::u16string_view rAuthor, const DateTime &rDateTime, const OUString &rComment)
const SwRangeRedline * GetCurrRedline() const
Definition: edredln.cxx:161
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
OUString toId(const void *pValue)
bool bDisabled
virtual void select(int pos)=0
void SetUndoClickHdl(const Link< SvxTPView *, void > &rLink)
virtual void Activate() override
SwRedlineAcceptPanel(weld::Widget *pParent)
Definition: redlndlg.cxx:1427
SwWrtShell * GetWrtShellPtr() const
Definition: view.hxx:414
bool IsMoved() const
Definition: redline.hxx:273
void CallAcceptReject(bool bSelect, bool bAccept)
Definition: redlndlg.cxx:901
void EnableReject(bool bFlag)
static void SetCareDialog(const std::shared_ptr< weld::Window > &rNew)
Definition: viewsh.cxx:2667
virtual int get_sort_column() const =0
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
sal_Int32 SelectAuthor(const OUString &aString)
SwModelessRedlineAcceptDlg(SfxBindings *, SwChildWinWrapper *, weld::Window *pParent)
Definition: redlndlg.cxx:80
virtual bool get_selected(TreeIter *pIter) const =0
bool IsAction() const
weld::TreeView & GetWidget()
bool RejectRedline(SwRedlineTable::size_type nPos)
Definition: edredln.cxx:78
void EnableAccept(bool bFlag)
bool IsCursorPtAtEnd() const
Definition: crsrsh.hxx:903
void ResetModified()
Definition: edws.cxx:75
virtual bool ReInitDlg(SwDocShell *pDocSh) override
Definition: redlndlg.cxx:71
void SetAcceptAllClickHdl(const Link< SvxTPView *, void > &rLink)
RET_OK
Reference< XExecutableDialog > m_xDialog
RedlineType GetType(sal_uInt16 nPos=0) const
Definition: docredln.cxx:1929
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:418
RedlineType GetRedlineType() const
Definition: swtable.cxx:1768
virtual void set_cursor(int pos)=0
void SetInvokeHandler(const Link< Timer *, void > &rLink)
SvxRedlinTable * GetTableControl()
virtual void set_selection_mode(SelectionMode eMode)=0
SAL_DLLPRIVATE void InsertChildren(SwRedlineDataParent *pParent, const SwRangeRedline &rRedln, bool bHasRedlineAutoFormat)
Definition: redlndlg.cxx:551
virtual void set_image(int row, const OUString &rImage, int col=-1)=0
bool m_bOnlyFormatedRedlines
Definition: redlndlg.hxx:74
const SwRedlineData * pData
Definition: redlndlg.hxx:45
void Initialize(OUString &rExtraData)
Definition: redlndlg.cxx:1354
SAL_DLLPRIVATE void RemoveParents(SwRedlineTable::size_type nStart, SwRedlineTable::size_type nEnd)
Definition: redlndlg.cxx:650
virtual bool iter_next_sibling(TreeIter &rIter) const =0
OUString m_sDeleted
Definition: redlndlg.hxx:68
void append_text(const OUString &rStr)
OUString m_sFormatCollSet
Definition: redlndlg.hxx:71
const SwRedlineDataChild * pNext
Definition: redlndlg.hxx:39
virtual void FillInfo(SfxChildWinInfo &) const override
Definition: redlndlg.cxx:130
virtual bool ReInitDlg(SwDocShell *pDocSh)
Definition: fldwrap.cxx:46
std::pair< const_iterator, bool > insert(Value &&x)
SwRedlineDataParentSortArr m_aUsedSeqNo
Definition: redlndlg.hxx:65
void EnterAddMode()
Definition: select.cxx:626
#define FN_REDLINE_SHOW
Definition: cmdid.h:129
SwTableLine * GetUpper()
Definition: swtable.hxx:453
void InsertAuthor(const OUString &rString)
static constexpr size_type npos
Definition: docary.hxx:223
virtual void connect_popup_menu(const Link< const CommandEvent &, bool > &rLink)
void Init(SwRedlineTable::size_type nStart=0)
Definition: redlndlg.cxx:208
virtual void make_sorted()=0
#define FN_REDLINE_ACCEPT
Definition: cmdid.h:137
aStr
void EnableAcceptAll(bool bFlag)
void SetAcceptClickHdl(const Link< SvxTPView *, void > &rLink)
Definition: view.hxx:144
sal_uInt16 nPos
std::vector< std::unique_ptr< RedlinData > > m_RedlinData
Definition: redlndlg.hxx:64
size_type erase(const Value &x)
virtual OUString get_active_text() const =0
virtual int iter_compare(const TreeIter &a, const TreeIter &b) const =0
virtual int get_iter_depth(const TreeIter &rIter) const =0
void EndAction(const bool bIdleEnd=false)
Definition: crsrsh.cxx:244
bool m_bDetectedRangeSegmentation false
OUString sId
virtual void scroll_to_row(int row)=0