1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
29 #include <vcl/commandevent.hxx>
30 #include <swtypes.hxx>
33 #include <swmodule.hxx>
34 #include <redlndlg.hxx>
37 #include <o3tl/string_view.hxx>
40 #include <strings.hrc>
44 #include <SwRewriter.hxx>
48 #include <svx/svxdlg.hxx>
49 #include <osl/diagnose.h>
50 #include <bitmaps.hlst>
54 #include <IDocumentRedlineAccess.hxx>
55 #include <usrpref.hxx>
58 SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SwRedlineAcceptChild
, FN_REDLINE_ACCEPT
)
60 SwRedlineAcceptChild::SwRedlineAcceptChild(vcl::Window
* _pParent
,
62 SfxBindings
* pBindings
,
63 SfxChildWinInfo
* pInfo
)
64 : SwChildWinWrapper(_pParent
, nId
)
66 auto xDlg
= std::make_shared
<SwModelessRedlineAcceptDlg
>(pBindings
, this, _pParent
->GetFrameWeld());
68 xDlg
->Initialize(pInfo
);
71 // newly initialise dialog after document switch
72 bool SwRedlineAcceptChild::ReInitDlg(SwDocShell
*pDocSh
)
74 bool bRet
= SwChildWinWrapper::ReInitDlg(pDocSh
);
75 if (bRet
) // update immediately, doc switch!
76 static_cast<SwModelessRedlineAcceptDlg
*>(GetController().get())->Activate();
81 SwModelessRedlineAcceptDlg::SwModelessRedlineAcceptDlg(
82 SfxBindings
* _pBindings
, SwChildWinWrapper
* pChild
, weld::Window
*pParent
)
83 : SfxModelessDialogController(_pBindings
, pChild
, pParent
,
84 u
"svx/ui/acceptrejectchangesdialog.ui"_ustr
, u
"AcceptRejectChangesDialog"_ustr
)
85 , m_xContentArea(m_xBuilder
->weld_container(u
"container"_ustr
))
88 m_xImplDlg
.reset(new SwRedlineAcceptDlg(m_xDialog
, m_xBuilder
.get(), m_xContentArea
.get()));
91 void SwModelessRedlineAcceptDlg::Activate()
96 SwView
*pView
= ::GetActiveView();
97 if (!pView
) // can happen when switching to another app, when a Listbox in dialog
98 return; // had the focus previously (actually THs Bug)
100 SwDocShell
*pDocSh
= pView
->GetDocShell();
102 if (m_pChildWin
->GetOldDocShell() != pDocSh
)
104 SwWait
aWait( *pDocSh
, false );
105 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
109 m_pChildWin
->SetOldDocShell(pDocSh
); // avoid recursion (using modified-Hdl)
111 bool bMod
= pSh
->IsModified();
112 SfxBoolItem
aShow(FN_REDLINE_SHOW
, true);
113 pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(
114 FN_REDLINE_SHOW
, SfxCallMode::SYNCHRON
|SfxCallMode::RECORD
,
117 pSh
->ResetModified();
119 SfxModelessDialogController::Activate();
124 SfxModelessDialogController::Activate();
125 m_xImplDlg
->Activate();
128 void SwModelessRedlineAcceptDlg::Initialize(SfxChildWinInfo
* pInfo
)
130 if (pInfo
!= nullptr)
131 m_xImplDlg
->Initialize(pInfo
->aExtraString
);
133 SfxModelessDialogController::Initialize(pInfo
);
136 void SwModelessRedlineAcceptDlg::FillInfo(SfxChildWinInfo
& rInfo
) const
138 SfxModelessDialogController::FillInfo(rInfo
);
139 m_xImplDlg
->FillInfo(rInfo
.aExtraString
);
142 SwModelessRedlineAcceptDlg::~SwModelessRedlineAcceptDlg()
144 mbInDestruction
= true;
149 const SwRedlineData
* lcl_get_selected_redlinedata(weld::TreeView
& rTreeView
)
151 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator());
152 if (rTreeView
.get_selected(xEntry
.get()))
154 RedlinData
* pRedlinData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(*xEntry
));
155 if (rTreeView
.get_iter_depth(*xEntry
))
156 return static_cast<SwRedlineDataChild
*>(pRedlinData
->pData
)->pChild
;
158 return static_cast<SwRedlineDataParent
*>(pRedlinData
->pData
)->pData
;
163 void lcl_reselect(weld::TreeView
& rTreeView
, const SwRedlineData
* pSelectedEntryRedlineData
)
165 if (!pSelectedEntryRedlineData
)
167 rTreeView
.set_cursor(-1);
170 rTreeView
.all_foreach(
171 [&rTreeView
, &pSelectedEntryRedlineData
](weld::TreeIter
& rIter
)
173 RedlinData
* pRedlinData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(rIter
));
174 const SwRedlineData
* pRedlineData
;
175 if (rTreeView
.get_iter_depth(rIter
))
176 pRedlineData
= static_cast<SwRedlineDataChild
*>(pRedlinData
->pData
)->pChild
;
178 pRedlineData
= static_cast<SwRedlineDataParent
*>(pRedlinData
->pData
)->pData
;
179 if (pRedlineData
== pSelectedEntryRedlineData
)
181 rTreeView
.set_cursor(rIter
);
189 SwRedlineAcceptDlg::SwRedlineAcceptDlg(std::shared_ptr
<weld::Window
> xParent
, weld::Builder
*pBuilder
,
190 weld::Container
*pContentArea
, bool bAutoFormat
)
191 : m_xParentDlg(std::move(xParent
))
192 , m_aSelectTimer("SwRedlineAcceptDlg m_aSelectTimer")
193 , m_sInserted(SwResId(STR_REDLINE_INSERTED
))
194 , m_sDeleted(SwResId(STR_REDLINE_DELETED
))
195 , m_sFormated(SwResId(STR_REDLINE_FORMATTED
))
196 , m_sTableChgd(SwResId(STR_REDLINE_TABLECHG
))
197 , m_sFormatCollSet(SwResId(STR_REDLINE_FMTCOLLSET
))
198 , m_sAutoFormat(SwResId(STR_REDLINE_AUTOFMT
))
199 , m_bOnlyFormatedRedlines(false)
200 , m_bRedlnAutoFormat(bAutoFormat
)
201 , m_bInhibitActivate(false)
202 , m_bHasTrackedColumn(false)
203 , m_xTabPagesCTRL(new SvxAcceptChgCtr(pContentArea
))
204 , m_xPopup(pBuilder
->weld_menu(u
"writermenu"_ustr
))
205 , m_xSortMenu(pBuilder
->weld_menu(u
"writersortmenu"_ustr
))
207 m_pTPView
= m_xTabPagesCTRL
->GetViewPage();
209 m_pTable
= m_pTPView
->GetTableControl();
210 m_pTable
->SetWriterView();
212 m_pTPView
->GetSortByComboBoxControl()->set_active(4);
214 m_pTPView
->SetSortByComboBoxChangedHdl(
215 LINK(this, SwRedlineAcceptDlg
, SortByComboBoxChangedHdl
));
217 m_pTPView
->SetAcceptClickHdl(LINK(this, SwRedlineAcceptDlg
, AcceptHdl
));
218 m_pTPView
->SetAcceptAllClickHdl(LINK(this, SwRedlineAcceptDlg
, AcceptAllHdl
));
219 m_pTPView
->SetRejectClickHdl(LINK(this, SwRedlineAcceptDlg
, RejectHdl
));
220 m_pTPView
->SetRejectAllClickHdl(LINK(this, SwRedlineAcceptDlg
, RejectAllHdl
));
221 m_pTPView
->SetUndoClickHdl(LINK(this, SwRedlineAcceptDlg
, UndoHdl
));
222 //tdf#89227 default to disabled, and only enable if possible to accept/reject
223 m_pTPView
->EnableAccept(false);
224 m_pTPView
->EnableReject(false);
225 m_pTPView
->EnableClearFormat(false);
226 m_pTPView
->EnableAcceptAll(false);
227 m_pTPView
->EnableRejectAll(false);
228 m_pTPView
->EnableClearFormatAll(false);
230 m_xTabPagesCTRL
->GetFilterPage()->SetReadyHdl(LINK(this, SwRedlineAcceptDlg
, FilterChangedHdl
));
232 weld::ComboBox
* pActLB
= m_xTabPagesCTRL
->GetFilterPage()->GetLbAction();
233 pActLB
->append_text(m_sInserted
);
234 pActLB
->append_text(m_sDeleted
);
235 pActLB
->append_text(m_sFormated
);
236 pActLB
->append_text(m_sTableChgd
);
238 if (HasRedlineAutoFormat())
240 pActLB
->append_text(m_sFormatCollSet
);
241 pActLB
->append_text(m_sAutoFormat
);
242 m_pTPView
->ShowUndo();
243 m_pTPView
->DisableUndo(); // no UNDO events yet
246 pActLB
->set_active(0);
248 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
249 rTreeView
.set_selection_mode(SelectionMode::Multiple
);
251 rTreeView
.connect_selection_changed(LINK(this, SwRedlineAcceptDlg
, SelectHdl
));
252 rTreeView
.connect_popup_menu(LINK(this, SwRedlineAcceptDlg
, CommandHdl
));
254 // avoid multiple selection of the same texts:
255 m_aSelectTimer
.SetTimeout(100);
256 m_aSelectTimer
.SetInvokeHandler(LINK(this, SwRedlineAcceptDlg
, GotoHdl
));
258 // we want to receive SfxHintId::SwRedlineContentAtPos
259 StartListening(*(SwModule::get()->GetView()->GetDocShell()));
262 SwRedlineAcceptDlg::~SwRedlineAcceptDlg()
266 void SwRedlineAcceptDlg::Init(SwRedlineTable::size_type nStart
)
268 std::optional
<SwWait
> oWait
;
269 SwView
* pView
= GetActiveView();
271 oWait
.emplace(*pView
->GetDocShell(), false);
272 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
273 m_aUsedSeqNo
.clear();
275 // tdf#162018 keep the selected entry selected
276 const SwRedlineData
* pSelectedEntryRedlineData
= lcl_get_selected_redlinedata(rTreeView
);
278 // tdf#162337 tracked change selection when the Manage Changes dialog is initially opened
279 if (pView
&& m_bInitialSelect
)
281 m_bInitialSelect
= false;
282 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
285 const SwRangeRedline
* pCurrRedline
= pSh
->GetCurrRedline();
288 // Select current redline
289 SwRedlineTable::size_type nPos
290 = pSh
->FindRedlineOfData(pCurrRedline
->GetRedlineData());
291 pSh
->GotoRedline(nPos
, true);
296 // Select the next redline if there is one
297 pSh
->AssureStdMode();
298 pCurrRedline
= pSh
->SelNextRedline();
301 pSelectedEntryRedlineData
= &pCurrRedline
->GetRedlineData();
307 RemoveParents(nStart
, m_RedlineParents
.size() - 1);
311 m_RedlinData
.clear();
312 m_RedlineChildren
.clear();
313 m_RedlineParents
.erase(m_RedlineParents
.begin() + nStart
, m_RedlineParents
.end());
318 InsertParents(nStart
);
321 lcl_reselect(rTreeView
, pSelectedEntryRedlineData
);
324 void SwRedlineAcceptDlg::InitAuthors()
326 if (!m_xTabPagesCTRL
)
329 SwView
*pView
= ::GetActiveView();
332 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
334 SvxTPFilter
*pFilterPage
= m_xTabPagesCTRL
->GetFilterPage();
336 std::vector
<OUString
> aStrings
;
337 OUString
sOldAuthor(pFilterPage
->GetSelectedAuthor());
338 pFilterPage
->ClearAuthors();
340 SwRedlineTable::size_type nCount
= pSh
? pSh
->GetRedlineCount() : 0;
342 m_bOnlyFormatedRedlines
= true;
343 bool bIsNotFormated
= false;
346 for ( SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
348 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
350 if( m_bOnlyFormatedRedlines
&& RedlineType::Format
!= rRedln
.GetType() )
351 m_bOnlyFormatedRedlines
= false;
353 aStrings
.push_back(rRedln
.GetAuthorString());
355 for (sal_uInt16 nStack
= 1; nStack
< rRedln
.GetStackCount(); nStack
++)
357 aStrings
.push_back(rRedln
.GetAuthorString(nStack
));
361 std::sort(aStrings
.begin(), aStrings
.end());
362 aStrings
.erase(std::unique(aStrings
.begin(), aStrings
.end()), aStrings
.end());
364 for (auto const & i
: aStrings
)
365 pFilterPage
->InsertAuthor(i
);
367 if (pFilterPage
->SelectAuthor(sOldAuthor
) == -1 && !aStrings
.empty())
368 pFilterPage
->SelectAuthor(aStrings
[0]);
370 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
371 SwDocShell
* pShell
= pSh
? pSh
->GetDoc()->GetDocShell() : nullptr;
372 bool const bEnable
= pShell
&& !pShell
->IsReadOnly()
373 && rTreeView
.n_children() != 0
374 && !pSh
->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
375 bool bSel
= rTreeView
.get_selected(nullptr);
377 rTreeView
.selected_foreach([this, pSh
, &bIsNotFormated
](weld::TreeIter
& rEntry
){
378 // find the selected redline
379 // (fdo#57874: ignore, if the redline is already gone)
380 SwRedlineTable::size_type nPos
= GetRedlinePos(rEntry
);
381 if( nPos
!= SwRedlineTable::npos
)
383 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
385 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
390 m_pTPView
->EnableAccept( bEnable
&& bSel
);
391 m_pTPView
->EnableReject( bEnable
&& bSel
);
392 m_pTPView
->EnableClearFormat( bEnable
&& !bIsNotFormated
&& bSel
);
393 m_pTPView
->EnableAcceptAll( bEnable
);
394 m_pTPView
->EnableRejectAll( bEnable
);
395 m_pTPView
->EnableClearFormatAll( bEnable
&&
396 m_bOnlyFormatedRedlines
);
399 const OUString
& SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline
& rRedln
, sal_uInt16 nStack
,
400 bool bTableChanges
, bool bRowChanges
)
402 switch (rRedln
.GetType(nStack
))
404 case RedlineType::Insert
: return bTableChanges
406 ? BMP_REDLINE_ROW_INSERTION
407 : BMP_REDLINE_COL_INSERTION
409 ? BMP_REDLINE_MOVED_INSERTION
410 : rRedln
.IsAnnotation()
411 ? BMP_REDLINE_COMMENT_INSERTION
412 : BMP_REDLINE_INSERTED
;
413 case RedlineType::Delete
: return bTableChanges
415 ? BMP_REDLINE_ROW_DELETION
416 : BMP_REDLINE_COL_DELETION
418 ? BMP_REDLINE_MOVED_DELETION
419 : rRedln
.IsAnnotation()
420 ? BMP_REDLINE_COMMENT_DELETION
421 : BMP_REDLINE_DELETED
;
422 case RedlineType::Format
: return BMP_REDLINE_FORMATTED
;
423 case RedlineType::ParagraphFormat
: return BMP_REDLINE_FORMATTED
;
424 case RedlineType::Table
: return BMP_REDLINE_TABLECHG
;
425 case RedlineType::FmtColl
: return BMP_REDLINE_FMTCOLLSET
;
429 return EMPTY_OUSTRING
;
432 const OUString
& SwRedlineAcceptDlg::GetActionText(const SwRangeRedline
& rRedln
, sal_uInt16 nStack
)
434 switch( rRedln
.GetType(nStack
) )
436 case RedlineType::Insert
: return m_sInserted
;
437 case RedlineType::Delete
: return m_sDeleted
;
438 case RedlineType::Format
: return m_sFormated
;
439 case RedlineType::ParagraphFormat
: return m_sFormated
;
440 case RedlineType::Table
: return m_sTableChgd
;
441 case RedlineType::FmtColl
: return m_sFormatCollSet
;
442 default:;//prevent warning
445 return EMPTY_OUSTRING
;
448 // newly initialise after activation
449 void SwRedlineAcceptDlg::Activate()
451 // prevent update if flag is set (#102547#)
452 if( m_bInhibitActivate
)
455 SwView
*pView
= ::GetActiveView();
456 if (!pView
) // can happen when switching to another app
458 m_pTPView
->EnableAccept(false);
459 m_pTPView
->EnableReject(false);
460 m_pTPView
->EnableClearFormat(false);
461 m_pTPView
->EnableAcceptAll(false);
462 m_pTPView
->EnableRejectAll(false);
463 m_pTPView
->EnableClearFormatAll(false);
464 return; // had the focus previously
467 SwWait
aWait( *pView
->GetDocShell(), false );
469 if (pView
->GetDocShell()->IsReadOnly())
471 m_pTPView
->EnableAccept(false);
472 m_pTPView
->EnableReject(false);
473 m_pTPView
->EnableClearFormat(false);
474 m_pTPView
->EnableAcceptAll(false);
475 m_pTPView
->EnableRejectAll(false);
476 m_pTPView
->EnableClearFormatAll(false);
477 // note: enabling is done in InitAuthors below
480 m_aUsedSeqNo
.clear();
482 // did something change?
483 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
487 // tdf#162018 keep the selected entry selected
488 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
489 const SwRedlineData
* pSelectedEntryRedlineData
= lcl_get_selected_redlinedata(m_pTable
->GetWidget());
491 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
493 // check the number of pointers
494 for ( SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
496 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
498 if (i
>= m_RedlineParents
.size())
500 // new entries have been appended
505 SwRedlineDataParent
*const pParent
= m_RedlineParents
[i
].get();
506 if (&rRedln
.GetRedlineData() != pParent
->pData
)
508 // Redline-Parents were inserted, changed or deleted
509 i
= CalcDiff(i
, false);
510 if (i
== SwRedlineTable::npos
)
512 lcl_reselect(rTreeView
, pSelectedEntryRedlineData
);
518 const SwRedlineData
*pRedlineData
= rRedln
.GetRedlineData().Next();
519 const SwRedlineDataChild
*pBackupData
= pParent
->pNext
;
521 if (!pRedlineData
&& pBackupData
)
523 // Redline-Children were deleted
524 i
= CalcDiff(i
, true);
525 if (i
== SwRedlineTable::npos
)
527 lcl_reselect(rTreeView
, pSelectedEntryRedlineData
);
536 if (!pBackupData
|| pRedlineData
!= pBackupData
->pChild
)
538 // Redline-Children were inserted, changed or deleted
539 i
= CalcDiff(i
, true);
540 if (i
== SwRedlineTable::npos
)
542 lcl_reselect(rTreeView
, pSelectedEntryRedlineData
);
546 // here was a continue; targetted to the outer loop
547 // now a break will do, as there is nothing after it in the outer loop
550 pBackupData
= pBackupData
->pNext
;
551 pRedlineData
= pRedlineData
->Next();
556 if (nCount
!= m_RedlineParents
.size())
558 // Redlines were deleted at the end
564 bool bIsShowChangesInMargin
= SwModule::get()->GetUsrPref(false)->IsShowChangesInMargin();
565 for (SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
567 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
568 SwRedlineDataParent
*const pParent
= m_RedlineParents
[i
].get();
570 if(rRedln
.GetComment() != pParent
->sComment
)
572 bool bShowDeletedTextAsComment
= bIsShowChangesInMargin
&&
573 RedlineType::Delete
== rRedln
.GetType() && rRedln
.GetComment().isEmpty();
574 const OUString sComment
= bShowDeletedTextAsComment
575 ? const_cast<SwRangeRedline
&>(rRedln
).GetDescr()
576 : rRedln
.GetComment();
577 if (pParent
->xTLBParent
)
579 // update only comment
580 rTreeView
.set_text(*pParent
->xTLBParent
, sComment
.replace('\n', ' '), 3);
582 pParent
->sComment
= sComment
;
588 lcl_reselect(rTreeView
, pSelectedEntryRedlineData
);
591 void SwRedlineAcceptDlg::Notify(SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
593 if (rHint
.GetId() == SfxHintId::SwRedlineContentAtPos
)
595 SwView
* pView
= GetActiveView();
599 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
603 const SwRangeRedline
* pRangeRedline
= pSh
->GetCurrRedline();
607 const SwRedlineData
& rRedlineData
= pRangeRedline
->GetRedlineData();
609 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
610 rTreeView
.all_foreach([&rTreeView
, &rRedlineData
](weld::TreeIter
& rIter
) {
611 RedlinData
* pRedlinData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(rIter
));
612 const SwRedlineData
* pRedlineData
;
613 if (rTreeView
.get_iter_depth(rIter
))
614 pRedlineData
= static_cast<SwRedlineDataChild
*>(pRedlinData
->pData
)->pChild
;
616 pRedlineData
= static_cast<SwRedlineDataParent
*>(pRedlinData
->pData
)->pData
;
617 if (pRedlineData
== &rRedlineData
)
619 rTreeView
.set_cursor(rIter
);
627 SwRedlineTable::size_type
SwRedlineAcceptDlg::CalcDiff(SwRedlineTable::size_type nStart
, bool bChild
)
629 if (!nStart
|| m_bHasTrackedColumn
)
632 return SwRedlineTable::npos
;
635 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
637 SwView
*pView
= ::GetActiveView();
639 return SwRedlineTable::npos
;
641 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
643 return SwRedlineTable::npos
;
645 bool bHasRedlineAutoFormat
= HasRedlineAutoFormat();
646 SwRedlineDataParent
*const pParent
= m_RedlineParents
[nStart
].get();
647 const SwRangeRedline
& rRedln
= pSh
->GetRedline(nStart
);
649 if (bChild
) // should actually never happen, but just in case...
651 // throw away all entry's children and initialise newly
652 SwRedlineDataChild
* pBackupData
= const_cast<SwRedlineDataChild
*>(pParent
->pNext
);
653 SwRedlineDataChild
* pNext
;
657 pNext
= const_cast<SwRedlineDataChild
*>(pBackupData
->pNext
);
658 if (pBackupData
->xTLBChild
)
659 rTreeView
.remove(*pBackupData
->xTLBChild
);
661 auto it
= std::find_if(m_RedlineChildren
.begin(), m_RedlineChildren
.end(),
662 [&pBackupData
](const std::unique_ptr
<SwRedlineDataChild
>& rChildPtr
) { return rChildPtr
.get() == pBackupData
; });
663 if (it
!= m_RedlineChildren
.end())
664 m_RedlineChildren
.erase(it
);
668 pParent
->pNext
= nullptr;
670 // insert new children
671 InsertChildren(pParent
, rRedln
, bHasRedlineAutoFormat
);
677 // have entries been deleted?
678 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
679 for (SwRedlineTable::size_type i
= nStart
+ 1; i
< m_RedlineParents
.size(); i
++)
681 if (m_RedlineParents
[i
]->pData
== pRedlineData
)
683 // remove entries from nStart to i-1
684 RemoveParents(nStart
, i
- 1);
690 // entries been inserted?
691 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
692 pRedlineData
= m_RedlineParents
[nStart
]->pData
;
694 for (SwRedlineTable::size_type i
= nStart
+ 1; i
< nCount
; i
++)
696 if (&pSh
->GetRedline(i
).GetRedlineData() == pRedlineData
)
699 // insert entries from nStart to i-1
700 InsertParents(nStart
, i
- 1);
706 Init(nStart
); // adjust all entries until the end
707 return SwRedlineTable::npos
;
710 void SwRedlineAcceptDlg::InsertChildren(SwRedlineDataParent
*pParent
, const SwRangeRedline
& rRedln
, bool bHasRedlineAutoFormat
)
712 SwRedlineDataChild
*pLastRedlineChild
= nullptr;
713 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
714 bool bAutoFormatRedline
= rRedln
.IsAutoFormat();
716 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
718 OUString sAction
= GetActionText(rRedln
);
719 bool bValidParent
= m_sFilterAction
.isEmpty() || m_sFilterAction
== sAction
;
720 bValidParent
= bValidParent
&& m_pTable
->IsValidEntry(rRedln
.GetAuthorString(), rRedln
.GetTimeStamp(), rRedln
.GetComment());
721 if (bHasRedlineAutoFormat
)
724 if (pParent
->pData
->GetSeqNo())
726 std::pair
<SwRedlineDataParentSortArr::const_iterator
,bool> const ret
727 = m_aUsedSeqNo
.insert(pParent
);
728 if (ret
.second
) // already there
730 if (pParent
->xTLBParent
)
732 rTreeView
.set_text(*(*ret
.first
)->xTLBParent
, m_sAutoFormat
, 0);
733 rTreeView
.remove(*pParent
->xTLBParent
);
734 pParent
->xTLBParent
.reset();
739 bValidParent
= bValidParent
&& bAutoFormatRedline
;
741 bool bValidTree
= bValidParent
;
743 for (sal_uInt16 nStack
= 1; nStack
< rRedln
.GetStackCount(); nStack
++)
745 pRedlineData
= pRedlineData
->Next();
747 SwRedlineDataChild
* pRedlineChild
= new SwRedlineDataChild
;
748 pRedlineChild
->pChild
= pRedlineData
;
749 m_RedlineChildren
.push_back(std::unique_ptr
<SwRedlineDataChild
>(pRedlineChild
));
751 if ( pLastRedlineChild
)
752 pLastRedlineChild
->pNext
= pRedlineChild
;
754 pParent
->pNext
= pRedlineChild
;
756 sAction
= GetActionText(rRedln
, nStack
);
757 bool bValidChild
= m_sFilterAction
.isEmpty() || m_sFilterAction
== sAction
;
758 bValidChild
= bValidChild
&& m_pTable
->IsValidEntry(rRedln
.GetAuthorString(nStack
), rRedln
.GetTimeStamp(nStack
), rRedln
.GetComment());
759 if (bHasRedlineAutoFormat
)
760 bValidChild
= bValidChild
&& bAutoFormatRedline
;
761 bValidTree
|= bValidChild
;
765 std::unique_ptr
<RedlinData
> pData(new RedlinData
);
766 pData
->pData
= pRedlineChild
;
767 pData
->bDisabled
= true;
769 OUString
sImage(GetActionImage(rRedln
, nStack
));
770 const OUString
& sAuthor
= rRedln
.GetAuthorString(nStack
);
771 pData
->aDateTime
= rRedln
.GetTimeStamp(nStack
);
772 pData
->eType
= rRedln
.GetType(nStack
);
773 OUString sDateEntry
= GetAppLangDateTimeString(pData
->aDateTime
);
774 const OUString
& sComment
= rRedln
.GetComment(nStack
);
776 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator());
777 OUString
sId(weld::toId(pData
.get()));
778 rTreeView
.insert(pParent
->xTLBParent
.get(), -1, nullptr, &sId
, nullptr, nullptr,
779 false, xChild
.get());
780 m_RedlinData
.push_back(std::move(pData
));
782 rTreeView
.set_image(*xChild
, sImage
, -1);
783 rTreeView
.set_text(*xChild
, sAuthor
, 1);
784 rTreeView
.set_text(*xChild
, sDateEntry
, 2);
785 rTreeView
.set_text(*xChild
, sComment
, 3);
787 pRedlineChild
->xTLBChild
= std::move(xChild
);
789 rTreeView
.expand_row(*pParent
->xTLBParent
);
792 pRedlineChild
->xTLBChild
.reset();
794 pLastRedlineChild
= pRedlineChild
;
797 if (pLastRedlineChild
)
798 pLastRedlineChild
->pNext
= nullptr;
800 if (!bValidTree
&& pParent
->xTLBParent
)
802 rTreeView
.remove(*pParent
->xTLBParent
);
803 pParent
->xTLBParent
.reset();
804 if (bHasRedlineAutoFormat
)
805 m_aUsedSeqNo
.erase(pParent
);
809 void SwRedlineAcceptDlg::RemoveParents(SwRedlineTable::size_type nStart
, SwRedlineTable::size_type nEnd
)
811 SwView
*pView
= ::GetActiveView();
815 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
819 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
821 std::vector
<const weld::TreeIter
*> aLBoxArr
;
823 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
825 // because of Bug of TLB that ALWAYS calls the SelectHandler at Remove:
826 rTreeView
.connect_selection_changed(Link
<weld::TreeView
&, void>());
828 bool bChildrenRemoved
= false;
830 rTreeView
.unselect_all();
832 // set the cursor after the last entry because otherwise performance problem in TLB.
833 // TLB would otherwise reset the cursor at every Remove (expensive)
834 SwRedlineTable::size_type nPos
= std::min(nCount
, m_RedlineParents
.size());
835 weld::TreeIter
*pCurEntry
= nullptr;
836 while( ( pCurEntry
== nullptr ) && ( nPos
> 0 ) )
839 pCurEntry
= m_RedlineParents
[nPos
]->xTLBParent
.get();
843 rTreeView
.set_cursor(*pCurEntry
);
847 for (SwRedlineTable::size_type i
= nStart
; i
<= nEnd
; i
++)
849 if (!bChildrenRemoved
&& m_RedlineParents
[i
]->pNext
)
851 SwRedlineDataChild
* pChildPtr
=
852 const_cast<SwRedlineDataChild
*>(m_RedlineParents
[i
]->pNext
);
853 auto it
= std::find_if(m_RedlineChildren
.begin(), m_RedlineChildren
.end(),
854 [&pChildPtr
](const std::unique_ptr
<SwRedlineDataChild
>& rChildPtr
) { return rChildPtr
.get() == pChildPtr
; });
855 if (it
!= m_RedlineChildren
.end())
857 sal_uInt16 nChildren
= 0;
860 pChildPtr
= const_cast<SwRedlineDataChild
*>(pChildPtr
->pNext
);
864 m_RedlineChildren
.erase(it
, it
+ nChildren
);
865 bChildrenRemoved
= true;
868 weld::TreeIter
*const pEntry
= m_RedlineParents
[i
]->xTLBParent
.get();
870 aLBoxArr
.push_back(pEntry
);
873 std::sort(aLBoxArr
.begin(), aLBoxArr
.end(), [&rTreeView
](const weld::TreeIter
* a
, const weld::TreeIter
* b
) {
874 return rTreeView
.iter_compare(*a
, *b
) == -1;
876 // clear TLB from behind
877 for (auto it
= aLBoxArr
.rbegin(); it
!= aLBoxArr
.rend(); ++it
)
879 const weld::TreeIter
* pIter
= *it
;
880 rTreeView
.remove(*pIter
);
884 rTreeView
.connect_selection_changed(LINK(this, SwRedlineAcceptDlg
, SelectHdl
));
885 // unfortunately by Remove it was selected from the TLB always again ...
886 rTreeView
.unselect_all();
889 m_RedlineParents
.erase(m_RedlineParents
.begin() + nStart
, m_RedlineParents
.begin() + nEnd
+ 1);
892 void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart
, SwRedlineTable::size_type nEnd
)
894 SwView
*pView
= ::GetActiveView();
898 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
902 bool bHasRedlineAutoFormat
= HasRedlineAutoFormat();
904 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
905 nEnd
= std::min(nEnd
, (nCount
- 1)); // also treats nEnd=SwRedlineTable::npos (until the end)
907 // reset m_bHasTrackedColumn before searching tracked column again
908 if ( m_bHasTrackedColumn
&& nStart
== 0 )
909 m_bHasTrackedColumn
= false;
911 if (nEnd
== SwRedlineTable::npos
)
912 return; // no redlines in the document
914 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
916 SwRedlineDataParent
* pRedlineParent
;
919 if (m_pTable
->IsSorted())
920 rTreeView
.make_unsorted();
922 bool bIsShowChangesInMargin
= SwModule::get()->GetUsrPref(false)->IsShowChangesInMargin();
924 // collect redlines of tracked table/row/column insertion/deletions under a single tree list
925 // item to accept/reject the table change with a single click on Accept/Reject
926 // Note: because update of the tree list depends on parent count, we don't modify
927 // m_RedlineParents, only store the 2nd and more redlines as children of the tree list
928 // item of the first redline
930 // count of items stored as children (to adjust parent position)
931 SwRedlineTable::size_type nSkipRedlines
= 0;
932 // count of items of the actual table change stored as children =
933 // redlines of the change - 1 (first redline is associated to the parent tree list item)
934 SwRedlineTable::size_type nSkipRedline
= 0;
936 // descriptor redline of the tracked table row/column
937 SwRedlineTable::size_type nRowChange
= 0;
939 // first redlines of the tracked table rows/columns, base of the parent tree lists
940 // of the other SwRangeRedlines of the tracked table rows or columns
941 std::vector
<SwRedlineTable::size_type
> aTableParents
;
943 // show all redlines as tree list items,
944 // redlines of a tracked table (row) insertion/deletion showed as children of a single parent
945 for (SwRedlineTable::size_type i
= nStart
; i
<= nEnd
; i
++)
947 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
948 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
949 // redline is a child associated to this table row/column change
950 SwRedlineTable::size_type nTableParent
= SwRedlineTable::npos
;
952 pRedlineParent
= new SwRedlineDataParent
;
953 pRedlineParent
->pData
= pRedlineData
;
954 pRedlineParent
->pNext
= nullptr;
956 // handle tracked table row changes
957 const SwTableBox
* pTableBox
;
958 const SwTableLine
* pTableLine
;
959 bool bChange
= false;
960 bool bRowChange
= false;
961 if ( // not recognized yet as tracked table row change
962 nullptr != ( pTableBox
= pSh
->GetRedline(i
).Start()->GetNode().GetTableBox() ) &&
963 nullptr != ( pTableLine
= pTableBox
->GetUpper() ) &&
964 // it's a tracked row (or column change) based on the cached row data
965 ( RedlineType::None
!= pTableLine
->GetRedlineType() ||
966 RedlineType::None
!= pTableBox
->GetRedlineType() ) )
968 // start redline search from the start from the tracked row/column change
969 SwRedlineTable::size_type nStartPos
=
970 nRowChange
> nSkipRedline
? nRowChange
- nSkipRedline
: 0;
972 bRowChange
= RedlineType::None
!= pTableLine
->GetRedlineType();
973 nRowChange
= bRowChange
974 ? pTableLine
->UpdateTextChangesOnly(nStartPos
)
975 : pTableBox
->GetRedline();
976 // redline is there in a tracked table change
977 if ( SwRedlineTable::npos
!= nRowChange
)
979 // join the consecutive deleted/inserted rows/columns under a single treebox item,
980 // if they have the same redline data (equal type, author and time stamp)
981 for (size_t j
= 0; j
< aTableParents
.size(); j
++)
983 // note: CanCombine() allows a time frame to join the changes within a short
984 // time period: this avoid of falling apart of the tracked columns inserted
986 if ( pSh
->GetRedline(nRowChange
).GetRedlineData()
987 .CanCombine(pSh
->GetRedline(aTableParents
[j
]).GetRedlineData()) )
990 nTableParent
= aTableParents
[j
];
996 if ( SwRedlineTable::npos
== nTableParent
)
998 // table redline didn't fit in the stored ones, create new parent
999 aTableParents
.push_back(i
);
1002 // it needs major tree update later because of tracked table columns
1003 if ( !m_bHasTrackedColumn
&& !bRowChange
)
1005 m_bHasTrackedColumn
= true;
1010 // redline is not in a tracked table change
1011 bChange
= bRowChange
= false;
1015 // empty parent cache for the last table
1018 aTableParents
.clear();
1021 bool bShowDeletedTextAsComment
= bIsShowChangesInMargin
&&
1022 RedlineType::Delete
== rRedln
.GetType() && rRedln
.GetComment().isEmpty();
1023 const OUString sComment
= bShowDeletedTextAsComment
1024 ? const_cast<SwRangeRedline
&>(rRedln
).GetDescr()
1025 : rRedln
.GetComment();
1026 pRedlineParent
->sComment
= sComment
.replace('\n', ' ');
1027 m_RedlineParents
.insert(m_RedlineParents
.begin() + i
,
1028 std::unique_ptr
<SwRedlineDataParent
>(pRedlineParent
));
1030 std::unique_ptr
<RedlinData
> pData(new RedlinData
);
1031 pData
->pData
= pRedlineParent
;
1032 pData
->bDisabled
= false;
1034 // use descriptor SwRangeRedline of the changed row, if needed to show
1035 // the correct redline type, author and time stamp of the tracked row change
1036 const SwRangeRedline
& rChangeRedln
= pSh
->GetRedline(bChange
? nRowChange
: i
);
1038 OUString sImage
= GetActionImage(rChangeRedln
, 0, bChange
&& aTableParents
.back() == i
, bRowChange
);
1039 OUString sAuthor
= rChangeRedln
.GetAuthorString(0);
1040 pData
->aDateTime
= rChangeRedln
.GetTimeStamp(0);
1041 pData
->eType
= rChangeRedln
.GetType(0);
1042 OUString sDateEntry
= GetAppLangDateTimeString(pData
->aDateTime
);
1044 OUString sId
= weld::toId(pData
.get());
1045 std::unique_ptr
<weld::TreeIter
> xParent(rTreeView
.make_iterator());
1047 if ( !bChange
|| aTableParents
.back() == i
)
1049 rTreeView
.insert(nullptr, i
- nSkipRedlines
, nullptr, &sId
, nullptr, nullptr, false, xParent
.get());
1050 // before this was a tracked table change with more than a single redline
1051 if ( nSkipRedline
> 0 )
1053 nSkipRedlines
+= nSkipRedline
;
1059 // put 2nd or more redlines of deleted/inserted rows as children of their first redline
1060 SwRedlineDataParent
*const pParent
= m_RedlineParents
[nTableParent
].get();
1061 rTreeView
.insert(pParent
->xTLBParent
.get(), -1, nullptr, &sId
, nullptr, nullptr, false, xParent
.get());
1064 m_RedlinData
.push_back(std::move(pData
));
1066 rTreeView
.set_image(*xParent
, sImage
, -1);
1067 rTreeView
.set_text(*xParent
, sAuthor
, 1);
1068 rTreeView
.set_text(*xParent
, sDateEntry
, 2);
1069 rTreeView
.set_text(*xParent
, sComment
, 3);
1071 pRedlineParent
->xTLBParent
= std::move(xParent
);
1073 InsertChildren(pRedlineParent
, rRedln
, bHasRedlineAutoFormat
);
1076 if (m_pTable
->IsSorted())
1077 rTreeView
.make_sorted();
1080 void SwRedlineAcceptDlg::CallAcceptReject( bool bSelect
, bool bAccept
)
1082 SwView
*pView
= ::GetActiveView();
1086 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1092 typedef std::vector
<std::unique_ptr
<weld::TreeIter
>> ListBoxEntries_t
;
1093 ListBoxEntries_t aRedlines
;
1096 OSL_ENSURE( !m_bInhibitActivate
,
1097 "recursive call of CallAcceptReject?");
1098 m_bInhibitActivate
= true;
1100 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1102 auto lambda
= [this, pSh
, bSelect
, bAccept
, &rTreeView
, &nPos
, &aRedlines
](weld::TreeIter
& rEntry
) {
1103 if (!rTreeView
.get_iter_depth(rEntry
))
1105 if (bSelect
&& nPos
== -1)
1106 nPos
= rTreeView
.get_iter_index_in_parent(rEntry
);
1108 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(rEntry
));
1110 bool bIsNotFormatted
= true;
1112 // first remove only changes with insertion/deletion, if they exist
1113 // (format-only changes haven't had real rejection yet, only an
1114 // approximation: clear direct formatting, so try to warn
1115 // with the extended button label "Reject All/Clear formatting")
1116 if ( !bSelect
&& !bAccept
&& !m_bOnlyFormatedRedlines
)
1118 SwRedlineTable::size_type nPosition
= GetRedlinePos(rEntry
);
1119 const SwRangeRedline
& rRedln
= pSh
->GetRedline(nPosition
);
1121 if( RedlineType::Format
== rRedln
.GetType() )
1122 bIsNotFormatted
= false;
1125 if (!pData
->bDisabled
&& bIsNotFormatted
)
1126 aRedlines
.emplace_back(rTreeView
.make_iterator(&rEntry
));
1131 // collect redlines-to-be-accepted/rejected in aRedlines vector
1133 rTreeView
.selected_foreach(lambda
);
1135 rTreeView
.all_foreach(lambda
);
1137 bool (SwEditShell::*FnAccRej
)( SwRedlineTable::size_type
) = &SwEditShell::AcceptRedline
;
1139 FnAccRej
= &SwEditShell::RejectRedline
;
1141 SwWait
aWait( *pSh
->GetView().GetDocShell(), true );
1144 bool bMoreRedlines( aRedlines
.size() > 1 ||
1145 // single item with children, e.g. multiple redlines of a table or table row deletion/insertion
1146 ( aRedlines
.size() == 1 && rTreeView
.iter_n_children(*aRedlines
[0]) > 0 ) );
1148 // don't add extra Undo label to a single item only with redline stack (i.e. old changes
1149 // on the same text range, stored only in OOXML)
1150 if ( bMoreRedlines
&& aRedlines
.size() == 1 )
1152 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*aRedlines
[0] ));
1153 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(*xChild
));
1154 if ( pData
->bDisabled
)
1155 bMoreRedlines
= false;
1158 if ( bMoreRedlines
)
1162 SwRewriter aRewriter
;
1163 aRewriter
.AddRule(UndoArg1
,
1164 OUString::number(aRedlines
.size()));
1165 aTmpStr
= aRewriter
.Apply(SwResId(STR_N_REDLINES
));
1168 SwRewriter aRewriter
;
1169 aRewriter
.AddRule(UndoArg1
, aTmpStr
);
1171 pSh
->StartUndo(bAccept
? SwUndoId::ACCEPT_REDLINE
: SwUndoId::REJECT_REDLINE
,
1175 // accept/reject the redlines in aRedlines. The absolute
1176 // position may change during the process (e.g. when two redlines
1177 // are merged in result of another one being deleted), so the
1178 // position must be resolved late and checked before using it.
1180 for (const auto& rRedLine
: aRedlines
)
1182 SwRedlineTable::size_type nPosition
= GetRedlinePos( *rRedLine
);
1183 if( nPosition
!= SwRedlineTable::npos
)
1184 (pSh
->*FnAccRej
)( nPosition
);
1186 // handle redlines of table rows, stored as children of the item associated
1187 // to the deleted/inserted table row(s)
1188 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*rRedLine
));
1189 if ( rTreeView
.iter_children(*xChild
) )
1191 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(*xChild
));
1192 // disabled for redline stack, but not for redlines of table rows
1193 if ( !pData
->bDisabled
)
1197 nPosition
= GetRedlinePos( *xChild
);
1198 if( nPosition
!= SwRedlineTable::npos
)
1199 (pSh
->*FnAccRej
)( nPosition
);
1201 while ( rTreeView
.iter_next_sibling(*xChild
) );
1206 if ( bMoreRedlines
)
1213 m_bInhibitActivate
= false;
1216 if (nPos
!= -1 && rTreeView
.n_children())
1218 if (nPos
>= rTreeView
.n_children())
1219 nPos
= rTreeView
.n_children() - 1;
1220 rTreeView
.select(nPos
);
1221 rTreeView
.scroll_to_row(nPos
);
1222 rTreeView
.set_cursor(nPos
);
1223 SelectHdl(rTreeView
);
1225 m_pTPView
->EnableUndo();
1228 SwRedlineTable::size_type
SwRedlineAcceptDlg::GetRedlinePos(const weld::TreeIter
& rEntry
)
1230 SwView
* pView
= GetActiveView();
1232 return SwRedlineTable::npos
;
1234 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1236 return SwRedlineTable::npos
;
1238 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1239 return pSh
->FindRedlineOfData( *static_cast<SwRedlineDataParent
*>(weld::fromId
<RedlinData
*>(
1240 rTreeView
.get_id(rEntry
))->pData
)->pData
);
1243 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, SortByComboBoxChangedHdl
, SvxTPView
*, void)
1245 SwView
* pView
= GetActiveView();
1248 SwWait
aWait(*pView
->GetDocShell(), false);
1249 auto nSortMode
= m_pTPView
->GetSortByComboBoxControl()->get_active();
1252 m_pTable
->HeaderBarClick(nSortMode
);
1253 if (nSortMode
== -1)
1257 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, AcceptHdl
, SvxTPView
*, void)
1259 CallAcceptReject( true, true );
1262 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, AcceptAllHdl
, SvxTPView
*, void)
1264 CallAcceptReject( false, true );
1267 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, RejectHdl
, SvxTPView
*, void)
1269 CallAcceptReject( true, false );
1272 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, RejectAllHdl
, SvxTPView
*, void)
1274 CallAcceptReject( false, false );
1277 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, UndoHdl
, SvxTPView
*, void)
1279 if (SwView
* pView
= GetActiveView())
1281 pView
->GetViewFrame().GetDispatcher()->
1282 Execute(SID_UNDO
, SfxCallMode::SYNCHRON
);
1283 const SfxPoolItemHolder
aResult(pView
->GetSlotState(SID_UNDO
));
1284 m_pTPView
->EnableUndo(aResult
.is());
1290 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, FilterChangedHdl
, SvxTPFilter
*, void)
1292 SvxTPFilter
*pFilterTP
= m_xTabPagesCTRL
->GetFilterPage();
1294 if (pFilterTP
->IsAction())
1295 m_sFilterAction
= pFilterTP
->GetLbAction()->get_active_text();
1297 m_sFilterAction
.clear();
1302 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, SelectHdl
, weld::TreeView
&, void)
1304 m_aSelectTimer
.Start();
1307 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, GotoHdl
, Timer
*, void)
1309 m_aSelectTimer
.Stop();
1311 SwView
* pView
= GetActiveView();
1315 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1319 bool bIsNotFormated
= false;
1322 //#98883# don't select redlines while the dialog is not focused
1323 //#107938# But not only ask pTable if it has the focus. To move
1324 // the selection to the selected redline any child of pParentDlg
1326 if (!m_xParentDlg
|| m_xParentDlg
->has_toplevel_focus())
1328 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1329 std::unique_ptr
<weld::TreeIter
> xActEntry(rTreeView
.make_iterator());
1330 if (rTreeView
.get_selected(xActEntry
.get()))
1333 pSh
->EnterStdMode();
1334 SwViewShell::SetCareDialog(m_xParentDlg
);
1336 rTreeView
.selected_foreach([this, pSh
, &rTreeView
, &xActEntry
, &bIsNotFormated
, &bSel
](weld::TreeIter
& rEntry
){
1337 rTreeView
.copy_iterator(rEntry
, *xActEntry
);
1338 if (rTreeView
.get_iter_depth(rEntry
))
1340 rTreeView
.iter_parent(*xActEntry
);
1341 if (rTreeView
.is_selected(*xActEntry
))
1342 return false; // don't select twice
1347 // #98864# find the selected redline (ignore, if the redline is already gone)
1348 SwRedlineTable::size_type nPos
= GetRedlinePos(*xActEntry
);
1349 if (nPos
!= SwRedlineTable::npos
)
1352 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
1353 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
1355 if (pSh
->GotoRedline(nPos
, true))
1358 pSh
->EnterAddMode();
1362 // select all redlines of tracked table rows
1363 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*xActEntry
));
1364 if ( rTreeView
.iter_children(*xChild
) )
1366 RedlinData
*pData
= reinterpret_cast<RedlinData
*>(rTreeView
.get_id(*xChild
).toInt64());
1367 // disabled for redline stack, but not for redlines of table rows
1368 if ( !pData
->bDisabled
)
1372 nPos
= GetRedlinePos(*xChild
);
1373 if (nPos
!= SwRedlineTable::npos
)
1375 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
1376 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
1378 if (pSh
->GotoRedline(nPos
, true))
1381 pSh
->EnterAddMode();
1385 while ( rTreeView
.iter_next_sibling(*xChild
) );
1391 pSh
->LeaveAddMode();
1393 SwViewShell::SetCareDialog(nullptr);
1397 SwDocShell
* pShell
= pSh
->GetDoc()->GetDocShell();
1398 bool const bEnable
= pShell
&& !pShell
->IsReadOnly()
1399 && !pSh
->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
1400 m_pTPView
->EnableAccept( bEnable
&& bSel
/*&& !bReadonlySel*/ );
1401 m_pTPView
->EnableReject( bEnable
&& bSel
/*&& !bReadonlySel*/ );
1402 m_pTPView
->EnableClearFormat( bEnable
&& bSel
&& !bIsNotFormated
/*&& !bReadonlySel*/ );
1403 m_pTPView
->EnableAcceptAll( bEnable
);
1404 m_pTPView
->EnableRejectAll( bEnable
);
1405 m_pTPView
->EnableClearFormatAll( bEnable
&& m_bOnlyFormatedRedlines
);
1408 IMPL_LINK(SwRedlineAcceptDlg
, CommandHdl
, const CommandEvent
&, rCEvt
, bool)
1410 if (rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1413 SwView
* pView
= GetActiveView();
1417 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1421 const SwRangeRedline
*pRed
= nullptr;
1423 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1424 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator());
1425 bool bEntry
= rTreeView
.get_selected(xEntry
.get());
1428 std::unique_ptr
<weld::TreeIter
> xTopEntry(rTreeView
.make_iterator(xEntry
.get()));
1430 if (rTreeView
.get_iter_depth(*xTopEntry
))
1431 rTreeView
.iter_parent(*xTopEntry
);
1433 SwRedlineTable::size_type nPos
= GetRedlinePos(*xTopEntry
);
1435 // disable commenting for protected areas
1436 if (nPos
!= SwRedlineTable::npos
&& (pRed
= pSh
->GotoRedline(nPos
, true)) != nullptr)
1438 if( pSh
->IsCursorPtAtEnd() )
1444 m_xPopup
->set_sensitive(u
"writeredit"_ustr
, bEntry
&& pRed
&&
1445 !rTreeView
.get_iter_depth(*xEntry
) &&
1446 rTreeView
.count_selected_rows() == 1);
1447 m_xPopup
->set_sensitive(u
"writersort"_ustr
, rTreeView
.n_children() != 0);
1448 int nColumn
= rTreeView
.get_sort_column();
1451 for (sal_Int32 i
= 0; i
< 5; ++i
)
1452 m_xSortMenu
->set_active(u
"writersort" + OUString::number(i
), i
== nColumn
);
1454 OUString sCommand
= m_xPopup
->popup_at_rect(&rTreeView
, tools::Rectangle(rCEvt
.GetMousePosPixel(), Size(1,1)));
1456 if (sCommand
== "writeredit")
1460 if (rTreeView
.get_iter_depth(*xEntry
))
1461 rTreeView
.iter_parent(*xEntry
);
1463 SwRedlineTable::size_type nPos
= GetRedlinePos(*xEntry
);
1465 if (nPos
== SwRedlineTable::npos
)
1468 const SwRangeRedline
&rRedline
= pSh
->GetRedline(nPos
);
1470 OUString sComment
= convertLineEnd(rRedline
.GetComment(), GetSystemLineEnd());
1471 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
1472 ::DialogGetRanges fnGetRange
= pFact
->GetDialogGetRangesFunc();
1473 SfxItemSet
aSet( pSh
->GetAttrPool(), fnGetRange() );
1475 aSet
.Put(SvxPostItTextItem(sComment
, SID_ATTR_POSTIT_TEXT
));
1476 aSet
.Put(SvxPostItAuthorItem(rRedline
.GetAuthorString(), SID_ATTR_POSTIT_AUTHOR
));
1478 aSet
.Put(SvxPostItDateItem( GetAppLangDateTimeString(
1479 rRedline
.GetRedlineData().GetTimeStamp() ),
1480 SID_ATTR_POSTIT_DATE
));
1482 ScopedVclPtr
<AbstractSvxPostItDialog
> pDlg(pFact
->CreateSvxPostItDialog(&rTreeView
, aSet
));
1487 switch( rRedline
.GetType() )
1489 case RedlineType::Insert
:
1490 pResId
= STR_REDLINE_INSERTED
;
1492 case RedlineType::Delete
:
1493 pResId
= STR_REDLINE_DELETED
;
1495 case RedlineType::Format
:
1496 case RedlineType::ParagraphFormat
:
1497 pResId
= STR_REDLINE_FORMATTED
;
1499 case RedlineType::Table
:
1500 pResId
= STR_REDLINE_TABLECHG
;
1502 default:;//prevent warning
1504 OUString
sTitle(SwResId(STR_REDLINE_COMMENT
));
1506 sTitle
+= SwResId(pResId
);
1507 pDlg
->SetText(sTitle
);
1509 SwViewShell::SetCareDialog(pDlg
->GetDialog());
1511 if ( pDlg
->Execute() == RET_OK
)
1513 const SfxItemSet
* pOutSet
= pDlg
->GetOutputItemSet();
1514 OUString
sMsg(pOutSet
->Get(SID_ATTR_POSTIT_TEXT
).GetValue());
1516 // insert / change comment
1517 pSh
->SetRedlineComment(sMsg
);
1518 rTreeView
.set_text(*xEntry
, sMsg
.replace('\n', ' '), 3);
1521 SwViewShell::SetCareDialog(nullptr);
1522 pDlg
.disposeAndClear();
1525 else if (!sCommand
.isEmpty())
1527 int nSortMode
= o3tl::toInt32(sCommand
.subView(10));
1529 if (nSortMode
== 4 && nColumn
== 4)
1530 return true; // we already have it
1532 m_pTPView
->GetSortByComboBoxControl()->set_active(nSortMode
);
1535 nSortMode
= -1; // unsorted / sorted by position
1537 SwWait
aWait( *pView
->GetDocShell(), false );
1538 m_pTable
->HeaderBarClick(nSortMode
);
1539 if (nSortMode
== -1)
1540 Init(); // newly fill everything
1547 OUString
lcl_StripAcceptChgDat(OUString
&rExtraString
)
1552 sal_Int32 nPos
= rExtraString
.indexOf("AcceptChgDat:");
1555 // try to read the alignment string "ALIGN:(...)"; if none existing,
1556 // it's an old version
1557 sal_Int32 n1
= rExtraString
.indexOf('(', nPos
);
1560 sal_Int32 n2
= rExtraString
.indexOf(')', n1
);
1563 // cut out the alignment string
1564 aStr
= rExtraString
.copy(nPos
, n2
- nPos
+ 1);
1565 rExtraString
= rExtraString
.replaceAt(nPos
, n2
- nPos
+ 1, u
"");
1566 aStr
= aStr
.copy(n1
- nPos
+ 1);
1574 void SwRedlineAcceptDlg::Initialize(OUString
& rExtraString
)
1576 if (rExtraString
.isEmpty())
1579 OUString aStr
= lcl_StripAcceptChgDat(rExtraString
);
1583 int nCount
= aStr
.toInt32();
1587 std::vector
<int> aEndPos
;
1589 for (int i
= 0; i
< nCount
; ++i
)
1591 sal_Int32 n1
= aStr
.indexOf(';');
1592 aStr
= aStr
.copy( n1
+1 );
1593 aEndPos
.push_back(aStr
.toInt32());
1596 bool bUseless
= false;
1598 std::vector
<int> aWidths
;
1599 for (int i
= 1; i
< nCount
; ++i
)
1601 aWidths
.push_back(aEndPos
[i
] - aEndPos
[i
- 1]);
1602 if (aWidths
.back() <= 0)
1608 // turn column end points back to column widths, ignoring the small
1609 // value used for the expander column
1610 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1611 rTreeView
.set_column_fixed_widths(aWidths
);
1615 void SwRedlineAcceptDlg::FillInfo(OUString
&rExtraData
) const
1617 //remove any old one before adding a new one
1618 lcl_StripAcceptChgDat(rExtraData
);
1619 rExtraData
+= "AcceptChgDat:(";
1621 const int nTabCount
= 4;
1623 rExtraData
+= OUString::number(nTabCount
);
1626 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1627 std::vector
<int> aWidths
;
1628 // turn column widths back into column end points for compatibility
1629 // with how they used to be stored, including a small value for the
1631 aWidths
.push_back(rTreeView
.get_checkbox_column_width());
1632 for (int i
= 0; i
< nTabCount
- 1; ++i
)
1634 int nWidth
= rTreeView
.get_column_width(i
);
1635 assert(nWidth
> 0 && "suspicious to get a value like this");
1636 aWidths
.push_back(aWidths
.back() + nWidth
);
1639 for (auto a
: aWidths
)
1641 rExtraData
+= OUString::number(a
);
1647 SwRedlineAcceptPanel::SwRedlineAcceptPanel(weld::Widget
* pParent
)
1648 : PanelLayout(pParent
, u
"ManageChangesPanel"_ustr
, u
"modules/swriter/ui/managechangessidebar.ui"_ustr
)
1649 , mxContentArea(m_xBuilder
->weld_container(u
"content_area"_ustr
))
1651 mpImplDlg
.reset(new SwRedlineAcceptDlg(nullptr, m_xBuilder
.get(), mxContentArea
.get()));
1655 // we want to receive SfxHintId::DocChanged
1656 StartListening(*(SwModule::get()->GetView()->GetDocShell()));
1659 SwRedlineAcceptPanel::~SwRedlineAcceptPanel()
1663 void SwRedlineAcceptPanel::Notify(SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1665 if (mpImplDlg
&& rHint
.GetId() == SfxHintId::DocChanged
)
1666 mpImplDlg
->Activate();
1669 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */