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 "svx/ui/acceptrejectchangesdialog.ui", "AcceptRejectChangesDialog")
85 , m_xContentArea(m_xDialog
->weld_content_area())
88 m_xImplDlg
.reset(new SwRedlineAcceptDlg(m_xDialog
, m_xBuilder
.get(), m_xContentArea
.get()));
91 void SwModelessRedlineAcceptDlg::Activate()
93 SwView
*pView
= ::GetActiveView();
94 if (!pView
) // can happen when switching to another app, when a Listbox in dialog
95 return; // had the focus previously (actually THs Bug)
97 SwDocShell
*pDocSh
= pView
->GetDocShell();
99 if (m_pChildWin
->GetOldDocShell() != pDocSh
)
101 SwWait
aWait( *pDocSh
, false );
102 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
106 m_pChildWin
->SetOldDocShell(pDocSh
); // avoid recursion (using modified-Hdl)
108 bool bMod
= pSh
->IsModified();
109 SfxBoolItem
aShow(FN_REDLINE_SHOW
, true);
110 pSh
->GetView().GetViewFrame().GetDispatcher()->ExecuteList(
111 FN_REDLINE_SHOW
, SfxCallMode::SYNCHRON
|SfxCallMode::RECORD
,
114 pSh
->ResetModified();
116 SfxModelessDialogController::Activate();
121 SfxModelessDialogController::Activate();
122 m_xImplDlg
->Activate();
125 void SwModelessRedlineAcceptDlg::Initialize(SfxChildWinInfo
* pInfo
)
127 if (pInfo
!= nullptr)
128 m_xImplDlg
->Initialize(pInfo
->aExtraString
);
130 SfxModelessDialogController::Initialize(pInfo
);
133 void SwModelessRedlineAcceptDlg::FillInfo(SfxChildWinInfo
& rInfo
) const
135 SfxModelessDialogController::FillInfo(rInfo
);
136 m_xImplDlg
->FillInfo(rInfo
.aExtraString
);
139 SwModelessRedlineAcceptDlg::~SwModelessRedlineAcceptDlg()
143 SwRedlineAcceptDlg::SwRedlineAcceptDlg(std::shared_ptr
<weld::Window
> xParent
, weld::Builder
*pBuilder
,
144 weld::Container
*pContentArea
, bool bAutoFormat
)
145 : m_xParentDlg(std::move(xParent
))
146 , m_aSelectTimer("SwRedlineAcceptDlg m_aSelectTimer")
147 , m_sInserted(SwResId(STR_REDLINE_INSERTED
))
148 , m_sDeleted(SwResId(STR_REDLINE_DELETED
))
149 , m_sFormated(SwResId(STR_REDLINE_FORMATTED
))
150 , m_sTableChgd(SwResId(STR_REDLINE_TABLECHG
))
151 , m_sFormatCollSet(SwResId(STR_REDLINE_FMTCOLLSET
))
152 , m_sAutoFormat(SwResId(STR_REDLINE_AUTOFMT
))
153 , m_bOnlyFormatedRedlines(false)
154 , m_bRedlnAutoFormat(bAutoFormat
)
155 , m_bInhibitActivate(false)
156 , m_bHasTrackedColumn(false)
157 , m_xTabPagesCTRL(new SvxAcceptChgCtr(pContentArea
))
158 , m_xPopup(pBuilder
->weld_menu("writermenu"))
159 , m_xSortMenu(pBuilder
->weld_menu("writersortmenu"))
161 m_pTPView
= m_xTabPagesCTRL
->GetViewPage();
163 m_pTable
= m_pTPView
->GetTableControl();
164 m_pTable
->SetWriterView();
166 m_pTPView
->SetAcceptClickHdl(LINK(this, SwRedlineAcceptDlg
, AcceptHdl
));
167 m_pTPView
->SetAcceptAllClickHdl(LINK(this, SwRedlineAcceptDlg
, AcceptAllHdl
));
168 m_pTPView
->SetRejectClickHdl(LINK(this, SwRedlineAcceptDlg
, RejectHdl
));
169 m_pTPView
->SetRejectAllClickHdl(LINK(this, SwRedlineAcceptDlg
, RejectAllHdl
));
170 m_pTPView
->SetUndoClickHdl(LINK(this, SwRedlineAcceptDlg
, UndoHdl
));
171 //tdf#89227 default to disabled, and only enable if possible to accept/reject
172 m_pTPView
->EnableAccept(false);
173 m_pTPView
->EnableReject(false);
174 m_pTPView
->EnableClearFormat(false);
175 m_pTPView
->EnableAcceptAll(false);
176 m_pTPView
->EnableRejectAll(false);
177 m_pTPView
->EnableClearFormatAll(false);
179 m_xTabPagesCTRL
->GetFilterPage()->SetReadyHdl(LINK(this, SwRedlineAcceptDlg
, FilterChangedHdl
));
181 weld::ComboBox
* pActLB
= m_xTabPagesCTRL
->GetFilterPage()->GetLbAction();
182 pActLB
->append_text(m_sInserted
);
183 pActLB
->append_text(m_sDeleted
);
184 pActLB
->append_text(m_sFormated
);
185 pActLB
->append_text(m_sTableChgd
);
187 if (HasRedlineAutoFormat())
189 pActLB
->append_text(m_sFormatCollSet
);
190 pActLB
->append_text(m_sAutoFormat
);
191 m_pTPView
->ShowUndo();
192 m_pTPView
->DisableUndo(); // no UNDO events yet
195 pActLB
->set_active(0);
197 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
198 rTreeView
.set_selection_mode(SelectionMode::Multiple
);
200 rTreeView
.connect_changed(LINK(this, SwRedlineAcceptDlg
, SelectHdl
));
201 rTreeView
.connect_popup_menu(LINK(this, SwRedlineAcceptDlg
, CommandHdl
));
203 // avoid multiple selection of the same texts:
204 m_aSelectTimer
.SetTimeout(100);
205 m_aSelectTimer
.SetInvokeHandler(LINK(this, SwRedlineAcceptDlg
, GotoHdl
));
208 SwRedlineAcceptDlg::~SwRedlineAcceptDlg()
212 void SwRedlineAcceptDlg::Init(SwRedlineTable::size_type nStart
)
214 std::optional
<SwWait
> oWait
;
215 if (SwView
*pView
= GetActiveView())
216 oWait
.emplace(*pView
->GetDocShell(), false);
217 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
218 m_aUsedSeqNo
.clear();
222 RemoveParents(nStart
, m_RedlineParents
.size() - 1);
226 m_RedlinData
.clear();
227 m_RedlineChildren
.clear();
228 m_RedlineParents
.erase(m_RedlineParents
.begin() + nStart
, m_RedlineParents
.end());
233 InsertParents(nStart
);
236 // #i69618# this moves the list box to the right position, visually
237 std::unique_ptr
<weld::TreeIter
> xSelEntry(rTreeView
.make_iterator());
238 if (rTreeView
.get_selected(xSelEntry
.get()))
239 rTreeView
.scroll_to_row(*xSelEntry
); //#i70937#, force the scroll
242 void SwRedlineAcceptDlg::InitAuthors()
244 if (!m_xTabPagesCTRL
)
247 SwView
*pView
= ::GetActiveView();
250 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
252 SvxTPFilter
*pFilterPage
= m_xTabPagesCTRL
->GetFilterPage();
254 std::vector
<OUString
> aStrings
;
255 OUString
sOldAuthor(pFilterPage
->GetSelectedAuthor());
256 pFilterPage
->ClearAuthors();
258 SwRedlineTable::size_type nCount
= pSh
? pSh
->GetRedlineCount() : 0;
260 m_bOnlyFormatedRedlines
= true;
261 bool bIsNotFormated
= false;
264 for ( SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
266 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
268 if( m_bOnlyFormatedRedlines
&& RedlineType::Format
!= rRedln
.GetType() )
269 m_bOnlyFormatedRedlines
= false;
271 aStrings
.push_back(rRedln
.GetAuthorString());
273 for (sal_uInt16 nStack
= 1; nStack
< rRedln
.GetStackCount(); nStack
++)
275 aStrings
.push_back(rRedln
.GetAuthorString(nStack
));
279 std::sort(aStrings
.begin(), aStrings
.end());
280 aStrings
.erase(std::unique(aStrings
.begin(), aStrings
.end()), aStrings
.end());
282 for (auto const & i
: aStrings
)
283 pFilterPage
->InsertAuthor(i
);
285 if (pFilterPage
->SelectAuthor(sOldAuthor
) == -1 && !aStrings
.empty())
286 pFilterPage
->SelectAuthor(aStrings
[0]);
288 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
289 bool const bEnable
= pSh
&& !pSh
->GetDoc()->GetDocShell()->IsReadOnly()
290 && rTreeView
.n_children() != 0
291 && !pSh
->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
292 bool bSel
= rTreeView
.get_selected(nullptr);
294 rTreeView
.selected_foreach([this, pSh
, &bIsNotFormated
](weld::TreeIter
& rEntry
){
295 // find the selected redline
296 // (fdo#57874: ignore, if the redline is already gone)
297 SwRedlineTable::size_type nPos
= GetRedlinePos(rEntry
);
298 if( nPos
!= SwRedlineTable::npos
)
300 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
302 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
307 m_pTPView
->EnableAccept( bEnable
&& bSel
);
308 m_pTPView
->EnableReject( bEnable
&& bSel
);
309 m_pTPView
->EnableClearFormat( bEnable
&& !bIsNotFormated
&& bSel
);
310 m_pTPView
->EnableAcceptAll( bEnable
);
311 m_pTPView
->EnableRejectAll( bEnable
);
312 m_pTPView
->EnableClearFormatAll( bEnable
&&
313 m_bOnlyFormatedRedlines
);
316 OUString
SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline
& rRedln
, sal_uInt16 nStack
,
317 bool bTableChanges
, bool bRowChanges
)
319 switch (rRedln
.GetType(nStack
))
321 case RedlineType::Insert
: return bTableChanges
323 ? OUString(BMP_REDLINE_ROW_INSERTION
)
324 : OUString(BMP_REDLINE_COL_INSERTION
)
326 ? OUString(BMP_REDLINE_MOVED_INSERTION
)
327 : rRedln
.IsAnnotation()
328 ? OUString(BMP_REDLINE_COMMENT_INSERTION
)
329 : OUString(BMP_REDLINE_INSERTED
);
330 case RedlineType::Delete
: return bTableChanges
332 ? OUString(BMP_REDLINE_ROW_DELETION
)
333 : OUString(BMP_REDLINE_COL_DELETION
)
335 ? OUString(BMP_REDLINE_MOVED_DELETION
)
336 : rRedln
.IsAnnotation()
337 ? OUString(BMP_REDLINE_COMMENT_DELETION
)
338 : OUString(BMP_REDLINE_DELETED
);
339 case RedlineType::Format
: return BMP_REDLINE_FORMATTED
;
340 case RedlineType::ParagraphFormat
: return BMP_REDLINE_FORMATTED
;
341 case RedlineType::Table
: return BMP_REDLINE_TABLECHG
;
342 case RedlineType::FmtColl
: return BMP_REDLINE_FMTCOLLSET
;
349 OUString
SwRedlineAcceptDlg::GetActionText(const SwRangeRedline
& rRedln
, sal_uInt16 nStack
)
351 switch( rRedln
.GetType(nStack
) )
353 case RedlineType::Insert
: return m_sInserted
;
354 case RedlineType::Delete
: return m_sDeleted
;
355 case RedlineType::Format
: return m_sFormated
;
356 case RedlineType::ParagraphFormat
: return m_sFormated
;
357 case RedlineType::Table
: return m_sTableChgd
;
358 case RedlineType::FmtColl
: return m_sFormatCollSet
;
359 default:;//prevent warning
365 // newly initialise after activation
366 void SwRedlineAcceptDlg::Activate()
368 // prevent update if flag is set (#102547#)
369 if( m_bInhibitActivate
)
372 SwView
*pView
= ::GetActiveView();
373 if (!pView
) // can happen when switching to another app
375 m_pTPView
->EnableAccept(false);
376 m_pTPView
->EnableReject(false);
377 m_pTPView
->EnableClearFormat(false);
378 m_pTPView
->EnableAcceptAll(false);
379 m_pTPView
->EnableRejectAll(false);
380 m_pTPView
->EnableClearFormatAll(false);
381 return; // had the focus previously
384 SwWait
aWait( *pView
->GetDocShell(), false );
386 if (pView
->GetDocShell()->IsReadOnly())
388 m_pTPView
->EnableAccept(false);
389 m_pTPView
->EnableReject(false);
390 m_pTPView
->EnableClearFormat(false);
391 m_pTPView
->EnableAcceptAll(false);
392 m_pTPView
->EnableRejectAll(false);
393 m_pTPView
->EnableClearFormatAll(false);
394 // note: enabling is done in InitAuthors below
397 m_aUsedSeqNo
.clear();
399 // did something change?
400 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
404 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
406 // check the number of pointers
407 for ( SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
409 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
411 if (i
>= m_RedlineParents
.size())
413 // new entries have been appended
418 SwRedlineDataParent
*const pParent
= m_RedlineParents
[i
].get();
419 if (&rRedln
.GetRedlineData() != pParent
->pData
)
421 // Redline-Parents were inserted, changed or deleted
422 i
= CalcDiff(i
, false);
423 if (i
== SwRedlineTable::npos
)
428 const SwRedlineData
*pRedlineData
= rRedln
.GetRedlineData().Next();
429 const SwRedlineDataChild
*pBackupData
= pParent
->pNext
;
431 if (!pRedlineData
&& pBackupData
)
433 // Redline-Children were deleted
434 i
= CalcDiff(i
, true);
435 if (i
== SwRedlineTable::npos
)
443 if (pRedlineData
!= pBackupData
->pChild
)
445 // Redline-Children were inserted, changed or deleted
446 i
= CalcDiff(i
, true);
447 if (i
== SwRedlineTable::npos
)
451 pBackupData
= pBackupData
->pNext
;
452 pRedlineData
= pRedlineData
->Next();
457 if (nCount
!= m_RedlineParents
.size())
459 // Redlines were deleted at the end
465 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
466 bool bIsShowChangesInMargin
= SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin();
467 for (SwRedlineTable::size_type i
= 0; i
< nCount
; i
++)
469 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
470 SwRedlineDataParent
*const pParent
= m_RedlineParents
[i
].get();
472 if(rRedln
.GetComment() != pParent
->sComment
)
474 bool bShowDeletedTextAsComment
= bIsShowChangesInMargin
&&
475 RedlineType::Delete
== rRedln
.GetType() && rRedln
.GetComment().isEmpty();
476 const OUString sComment
= bShowDeletedTextAsComment
477 ? const_cast<SwRangeRedline
&>(rRedln
).GetDescr()
478 : rRedln
.GetComment();
479 if (pParent
->xTLBParent
)
481 // update only comment
482 rTreeView
.set_text(*pParent
->xTLBParent
, sComment
.replace('\n', ' '), 3);
484 pParent
->sComment
= sComment
;
491 SwRedlineTable::size_type
SwRedlineAcceptDlg::CalcDiff(SwRedlineTable::size_type nStart
, bool bChild
)
493 if (!nStart
|| m_bHasTrackedColumn
)
496 return SwRedlineTable::npos
;
499 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
501 SwView
*pView
= ::GetActiveView();
503 return SwRedlineTable::npos
;
505 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
507 return SwRedlineTable::npos
;
509 bool bHasRedlineAutoFormat
= HasRedlineAutoFormat();
510 SwRedlineDataParent
*const pParent
= m_RedlineParents
[nStart
].get();
511 const SwRangeRedline
& rRedln
= pSh
->GetRedline(nStart
);
513 if (bChild
) // should actually never happen, but just in case...
515 // throw away all entry's children and initialise newly
516 SwRedlineDataChild
* pBackupData
= const_cast<SwRedlineDataChild
*>(pParent
->pNext
);
517 SwRedlineDataChild
* pNext
;
521 pNext
= const_cast<SwRedlineDataChild
*>(pBackupData
->pNext
);
522 if (pBackupData
->xTLBChild
)
523 rTreeView
.remove(*pBackupData
->xTLBChild
);
525 auto it
= std::find_if(m_RedlineChildren
.begin(), m_RedlineChildren
.end(),
526 [&pBackupData
](const std::unique_ptr
<SwRedlineDataChild
>& rChildPtr
) { return rChildPtr
.get() == pBackupData
; });
527 if (it
!= m_RedlineChildren
.end())
528 m_RedlineChildren
.erase(it
);
532 pParent
->pNext
= nullptr;
534 // insert new children
535 InsertChildren(pParent
, rRedln
, bHasRedlineAutoFormat
);
541 // have entries been deleted?
542 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
543 for (SwRedlineTable::size_type i
= nStart
+ 1; i
< m_RedlineParents
.size(); i
++)
545 if (m_RedlineParents
[i
]->pData
== pRedlineData
)
547 // remove entries from nStart to i-1
548 RemoveParents(nStart
, i
- 1);
554 // entries been inserted?
555 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
556 pRedlineData
= m_RedlineParents
[nStart
]->pData
;
558 for (SwRedlineTable::size_type i
= nStart
+ 1; i
< nCount
; i
++)
560 if (&pSh
->GetRedline(i
).GetRedlineData() == pRedlineData
)
563 // insert entries from nStart to i-1
564 InsertParents(nStart
, i
- 1);
570 Init(nStart
); // adjust all entries until the end
571 return SwRedlineTable::npos
;
574 void SwRedlineAcceptDlg::InsertChildren(SwRedlineDataParent
*pParent
, const SwRangeRedline
& rRedln
, bool bHasRedlineAutoFormat
)
576 SwRedlineDataChild
*pLastRedlineChild
= nullptr;
577 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
578 bool bAutoFormatRedline
= rRedln
.IsAutoFormat();
580 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
582 OUString sAction
= GetActionText(rRedln
);
583 bool bValidParent
= m_sFilterAction
.isEmpty() || m_sFilterAction
== sAction
;
584 bValidParent
= bValidParent
&& m_pTable
->IsValidEntry(rRedln
.GetAuthorString(), rRedln
.GetTimeStamp(), rRedln
.GetComment());
585 if (bHasRedlineAutoFormat
)
588 if (pParent
->pData
->GetSeqNo())
590 std::pair
<SwRedlineDataParentSortArr::const_iterator
,bool> const ret
591 = m_aUsedSeqNo
.insert(pParent
);
592 if (ret
.second
) // already there
594 if (pParent
->xTLBParent
)
596 rTreeView
.set_text(*(*ret
.first
)->xTLBParent
, m_sAutoFormat
, 0);
597 rTreeView
.remove(*pParent
->xTLBParent
);
598 pParent
->xTLBParent
.reset();
603 bValidParent
= bValidParent
&& bAutoFormatRedline
;
605 bool bValidTree
= bValidParent
;
607 for (sal_uInt16 nStack
= 1; nStack
< rRedln
.GetStackCount(); nStack
++)
609 pRedlineData
= pRedlineData
->Next();
611 SwRedlineDataChild
* pRedlineChild
= new SwRedlineDataChild
;
612 pRedlineChild
->pChild
= pRedlineData
;
613 m_RedlineChildren
.push_back(std::unique_ptr
<SwRedlineDataChild
>(pRedlineChild
));
615 if ( pLastRedlineChild
)
616 pLastRedlineChild
->pNext
= pRedlineChild
;
618 pParent
->pNext
= pRedlineChild
;
620 sAction
= GetActionText(rRedln
, nStack
);
621 bool bValidChild
= m_sFilterAction
.isEmpty() || m_sFilterAction
== sAction
;
622 bValidChild
= bValidChild
&& m_pTable
->IsValidEntry(rRedln
.GetAuthorString(nStack
), rRedln
.GetTimeStamp(nStack
), rRedln
.GetComment());
623 if (bHasRedlineAutoFormat
)
624 bValidChild
= bValidChild
&& bAutoFormatRedline
;
625 bValidTree
|= bValidChild
;
629 std::unique_ptr
<RedlinData
> pData(new RedlinData
);
630 pData
->pData
= pRedlineChild
;
631 pData
->bDisabled
= true;
633 OUString
sImage(GetActionImage(rRedln
, nStack
));
634 OUString sAuthor
= rRedln
.GetAuthorString(nStack
);
635 pData
->aDateTime
= rRedln
.GetTimeStamp(nStack
);
636 pData
->eType
= rRedln
.GetType(nStack
);
637 OUString sDateEntry
= GetAppLangDateTimeString(pData
->aDateTime
);
638 OUString sComment
= rRedln
.GetComment(nStack
);
640 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator());
641 OUString
sId(weld::toId(pData
.get()));
642 rTreeView
.insert(pParent
->xTLBParent
.get(), -1, nullptr, &sId
, nullptr, nullptr,
643 false, xChild
.get());
644 m_RedlinData
.push_back(std::move(pData
));
646 rTreeView
.set_image(*xChild
, sImage
, -1);
647 rTreeView
.set_text(*xChild
, sAuthor
, 1);
648 rTreeView
.set_text(*xChild
, sDateEntry
, 2);
649 rTreeView
.set_text(*xChild
, sComment
, 3);
651 pRedlineChild
->xTLBChild
= std::move(xChild
);
653 rTreeView
.expand_row(*pParent
->xTLBParent
);
656 pRedlineChild
->xTLBChild
.reset();
658 pLastRedlineChild
= pRedlineChild
;
661 if (pLastRedlineChild
)
662 pLastRedlineChild
->pNext
= nullptr;
664 if (!bValidTree
&& pParent
->xTLBParent
)
666 rTreeView
.remove(*pParent
->xTLBParent
);
667 pParent
->xTLBParent
.reset();
668 if (bHasRedlineAutoFormat
)
669 m_aUsedSeqNo
.erase(pParent
);
673 void SwRedlineAcceptDlg::RemoveParents(SwRedlineTable::size_type nStart
, SwRedlineTable::size_type nEnd
)
675 SwView
*pView
= ::GetActiveView();
679 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
683 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
685 std::vector
<const weld::TreeIter
*> aLBoxArr
;
687 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
689 // because of Bug of TLB that ALWAYS calls the SelectHandler at Remove:
690 rTreeView
.connect_changed(Link
<weld::TreeView
&,void>());
692 bool bChildrenRemoved
= false;
694 rTreeView
.unselect_all();
696 // set the cursor after the last entry because otherwise performance problem in TLB.
697 // TLB would otherwise reset the cursor at every Remove (expensive)
698 SwRedlineTable::size_type nPos
= std::min(nCount
, m_RedlineParents
.size());
699 weld::TreeIter
*pCurEntry
= nullptr;
700 while( ( pCurEntry
== nullptr ) && ( nPos
> 0 ) )
703 pCurEntry
= m_RedlineParents
[nPos
]->xTLBParent
.get();
707 rTreeView
.set_cursor(*pCurEntry
);
711 for (SwRedlineTable::size_type i
= nStart
; i
<= nEnd
; i
++)
713 if (!bChildrenRemoved
&& m_RedlineParents
[i
]->pNext
)
715 SwRedlineDataChild
* pChildPtr
=
716 const_cast<SwRedlineDataChild
*>(m_RedlineParents
[i
]->pNext
);
717 auto it
= std::find_if(m_RedlineChildren
.begin(), m_RedlineChildren
.end(),
718 [&pChildPtr
](const std::unique_ptr
<SwRedlineDataChild
>& rChildPtr
) { return rChildPtr
.get() == pChildPtr
; });
719 if (it
!= m_RedlineChildren
.end())
721 sal_uInt16 nChildren
= 0;
724 pChildPtr
= const_cast<SwRedlineDataChild
*>(pChildPtr
->pNext
);
728 m_RedlineChildren
.erase(it
, it
+ nChildren
);
729 bChildrenRemoved
= true;
732 weld::TreeIter
*const pEntry
= m_RedlineParents
[i
]->xTLBParent
.get();
734 aLBoxArr
.push_back(pEntry
);
737 std::sort(aLBoxArr
.begin(), aLBoxArr
.end(), [&rTreeView
](const weld::TreeIter
* a
, const weld::TreeIter
* b
) {
738 return rTreeView
.iter_compare(*a
, *b
) == -1;
740 // clear TLB from behind
741 for (auto it
= aLBoxArr
.rbegin(); it
!= aLBoxArr
.rend(); ++it
)
743 const weld::TreeIter
* pIter
= *it
;
744 rTreeView
.remove(*pIter
);
748 rTreeView
.connect_changed(LINK(this, SwRedlineAcceptDlg
, SelectHdl
));
749 // unfortunately by Remove it was selected from the TLB always again ...
750 rTreeView
.unselect_all();
753 m_RedlineParents
.erase(m_RedlineParents
.begin() + nStart
, m_RedlineParents
.begin() + nEnd
+ 1);
756 void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart
, SwRedlineTable::size_type nEnd
)
758 SwView
*pView
= ::GetActiveView();
762 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
766 bool bHasRedlineAutoFormat
= HasRedlineAutoFormat();
768 SwRedlineTable::size_type nCount
= pSh
->GetRedlineCount();
769 nEnd
= std::min(nEnd
, (nCount
- 1)); // also treats nEnd=SwRedlineTable::npos (until the end)
771 // reset m_bHasTrackedColumn before searching tracked column again
772 if ( m_bHasTrackedColumn
&& nStart
== 0 )
773 m_bHasTrackedColumn
= false;
775 if (nEnd
== SwRedlineTable::npos
)
776 return; // no redlines in the document
778 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
780 SwRedlineDataParent
* pRedlineParent
;
781 const SwRangeRedline
* pCurrRedline
;
782 if (!nStart
&& !rTreeView
.get_selected(nullptr))
784 pCurrRedline
= pSh
->GetCurrRedline();
787 pSh
->SwCursorShell::Push();
788 pCurrRedline
= pSh
->SelNextRedline();
789 if( nullptr == pCurrRedline
)
790 pCurrRedline
= pSh
->SelPrevRedline();
791 pSh
->SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent
);
795 pCurrRedline
= nullptr;
798 if (m_pTable
->IsSorted())
799 rTreeView
.make_unsorted();
801 bool bIsShowChangesInMargin
= SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin();
803 // collect redlines of tracked table/row/column insertion/deletions under a single tree list
804 // item to accept/reject the table change with a single click on Accept/Reject
805 // Note: because update of the tree list depends on parent count, we don't modify
806 // m_RedlineParents, only store the 2nd and more redlines as children of the tree list
807 // item of the first redline
809 // count of items stored as children (to adjust parent position)
810 SwRedlineTable::size_type nSkipRedlines
= 0;
811 // count of items of the actual table change stored as children =
812 // redlines of the change - 1 (first redline is associated to the parent tree list item)
813 SwRedlineTable::size_type nSkipRedline
= 0;
815 // descriptor redline of the tracked table row/column
816 SwRedlineTable::size_type nRowChange
= 0;
818 // first redlines of the tracked table rows/columns, base of the parent tree lists
819 // of the other SwRangeRedlines of the tracked table rows or columns
820 std::vector
<SwRedlineTable::size_type
> aTableParents
;
822 // show all redlines as tree list items,
823 // redlines of a tracked table (row) insertion/deletion showed as children of a single parent
824 for (SwRedlineTable::size_type i
= nStart
; i
<= nEnd
; i
++)
826 const SwRangeRedline
& rRedln
= pSh
->GetRedline(i
);
827 const SwRedlineData
*pRedlineData
= &rRedln
.GetRedlineData();
828 // redline is a child associated to this table row/column change
829 SwRedlineTable::size_type nTableParent
= SwRedlineTable::npos
;
831 pRedlineParent
= new SwRedlineDataParent
;
832 pRedlineParent
->pData
= pRedlineData
;
833 pRedlineParent
->pNext
= nullptr;
835 // handle tracked table row changes
836 const SwTableBox
* pTableBox
;
837 const SwTableLine
* pTableLine
;
838 bool bChange
= false;
839 bool bRowChange
= false;
840 if ( // not recognized yet as tracked table row change
841 nullptr != ( pTableBox
= pSh
->GetRedline(i
).Start()->GetNode().GetTableBox() ) &&
842 nullptr != ( pTableLine
= pTableBox
->GetUpper() ) &&
843 // it's a tracked row (or column change) based on the cached row data
844 ( RedlineType::None
!= pTableLine
->GetRedlineType() ||
845 RedlineType::None
!= pTableBox
->GetRedlineType() ) )
847 // start redline search from the start from the tracked row/column change
848 SwRedlineTable::size_type nStartPos
=
849 nRowChange
> nSkipRedline
? nRowChange
- nSkipRedline
: 0;
851 bRowChange
= RedlineType::None
!= pTableLine
->GetRedlineType();
852 nRowChange
= bRowChange
853 ? pTableLine
->UpdateTextChangesOnly(nStartPos
)
854 : pTableBox
->GetRedline();
855 // redline is there in a tracked table change
856 if ( SwRedlineTable::npos
!= nRowChange
)
858 // join the consecutive deleted/inserted rows/columns under a single treebox item,
859 // if they have the same redline data (equal type, author and time stamp)
860 for (size_t j
= 0; j
< aTableParents
.size(); j
++)
862 // note: CanCombine() allows a time frame to join the changes within a short
863 // time period: this avoid of falling apart of the tracked columns inserted
865 if ( pSh
->GetRedline(nRowChange
).GetRedlineData()
866 .CanCombine(pSh
->GetRedline(aTableParents
[j
]).GetRedlineData()) )
869 nTableParent
= aTableParents
[j
];
875 if ( SwRedlineTable::npos
== nTableParent
)
877 // table redline didn't fit in the stored ones, create new parent
878 aTableParents
.push_back(i
);
881 // it needs major tree update later because of tracked table columns
882 if ( !m_bHasTrackedColumn
&& !bRowChange
)
884 m_bHasTrackedColumn
= true;
889 // redline is not in a tracked table change
890 bChange
= bRowChange
= false;
894 // empty parent cache for the last table
897 aTableParents
.clear();
900 bool bShowDeletedTextAsComment
= bIsShowChangesInMargin
&&
901 RedlineType::Delete
== rRedln
.GetType() && rRedln
.GetComment().isEmpty();
902 const OUString
& sComment
= bShowDeletedTextAsComment
903 ? const_cast<SwRangeRedline
&>(rRedln
).GetDescr()
904 : rRedln
.GetComment();
905 pRedlineParent
->sComment
= sComment
.replace('\n', ' ');
906 m_RedlineParents
.insert(m_RedlineParents
.begin() + i
,
907 std::unique_ptr
<SwRedlineDataParent
>(pRedlineParent
));
909 std::unique_ptr
<RedlinData
> pData(new RedlinData
);
910 pData
->pData
= pRedlineParent
;
911 pData
->bDisabled
= false;
913 // use descriptor SwRangeRedline of the changed row, if needed to show
914 // the correct redline type, author and time stamp of the tracked row change
915 const SwRangeRedline
& rChangeRedln
= pSh
->GetRedline(bChange
? nRowChange
: i
);
917 OUString sImage
= GetActionImage(rChangeRedln
, 0, bChange
&& aTableParents
.back() == i
, bRowChange
);
918 OUString sAuthor
= rChangeRedln
.GetAuthorString(0);
919 pData
->aDateTime
= rChangeRedln
.GetTimeStamp(0);
920 pData
->eType
= rChangeRedln
.GetType(0);
921 OUString sDateEntry
= GetAppLangDateTimeString(pData
->aDateTime
);
923 OUString sId
= weld::toId(pData
.get());
924 std::unique_ptr
<weld::TreeIter
> xParent(rTreeView
.make_iterator());
926 if ( !bChange
|| aTableParents
.back() == i
)
928 rTreeView
.insert(nullptr, i
- nSkipRedlines
, nullptr, &sId
, nullptr, nullptr, false, xParent
.get());
929 // before this was a tracked table change with more than a single redline
930 if ( nSkipRedline
> 0 )
932 nSkipRedlines
+= nSkipRedline
;
938 // put 2nd or more redlines of deleted/inserted rows as children of their first redline
939 SwRedlineDataParent
*const pParent
= m_RedlineParents
[nTableParent
].get();
940 rTreeView
.insert(pParent
->xTLBParent
.get(), -1, nullptr, &sId
, nullptr, nullptr, false, xParent
.get());
943 m_RedlinData
.push_back(std::move(pData
));
945 rTreeView
.set_image(*xParent
, sImage
, -1);
946 rTreeView
.set_text(*xParent
, sAuthor
, 1);
947 rTreeView
.set_text(*xParent
, sDateEntry
, 2);
948 rTreeView
.set_text(*xParent
, sComment
, 3);
950 if (pCurrRedline
== &rRedln
)
953 rTreeView
.set_cursor(*xParent
);
954 rTreeView
.select(*xParent
);
955 rTreeView
.scroll_to_row(*xParent
);
959 pRedlineParent
->xTLBParent
= std::move(xParent
);
961 InsertChildren(pRedlineParent
, rRedln
, bHasRedlineAutoFormat
);
964 if (m_pTable
->IsSorted())
965 rTreeView
.make_sorted();
968 void SwRedlineAcceptDlg::CallAcceptReject( bool bSelect
, bool bAccept
)
970 SwView
*pView
= ::GetActiveView();
974 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
980 typedef std::vector
<std::unique_ptr
<weld::TreeIter
>> ListBoxEntries_t
;
981 ListBoxEntries_t aRedlines
;
984 OSL_ENSURE( !m_bInhibitActivate
,
985 "recursive call of CallAcceptReject?");
986 m_bInhibitActivate
= true;
988 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
990 auto lambda
= [this, pSh
, bSelect
, bAccept
, &rTreeView
, &nPos
, &aRedlines
](weld::TreeIter
& rEntry
) {
991 if (!rTreeView
.get_iter_depth(rEntry
))
993 if (bSelect
&& nPos
== -1)
994 nPos
= rTreeView
.get_iter_index_in_parent(rEntry
);
996 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(rEntry
));
998 bool bIsNotFormatted
= true;
1000 // first remove only changes with insertion/deletion, if they exist
1001 // (format-only changes haven't had real rejection yet, only an
1002 // approximation: clear direct formatting, so try to warn
1003 // with the extended button label "Reject All/Clear formatting")
1004 if ( !bSelect
&& !bAccept
&& !m_bOnlyFormatedRedlines
)
1006 SwRedlineTable::size_type nPosition
= GetRedlinePos(rEntry
);
1007 const SwRangeRedline
& rRedln
= pSh
->GetRedline(nPosition
);
1009 if( RedlineType::Format
== rRedln
.GetType() )
1010 bIsNotFormatted
= false;
1013 if (!pData
->bDisabled
&& bIsNotFormatted
)
1014 aRedlines
.emplace_back(rTreeView
.make_iterator(&rEntry
));
1019 // collect redlines-to-be-accepted/rejected in aRedlines vector
1021 rTreeView
.selected_foreach(lambda
);
1023 rTreeView
.all_foreach(lambda
);
1025 bool (SwEditShell::*FnAccRej
)( SwRedlineTable::size_type
) = &SwEditShell::AcceptRedline
;
1027 FnAccRej
= &SwEditShell::RejectRedline
;
1029 SwWait
aWait( *pSh
->GetView().GetDocShell(), true );
1032 bool bMoreRedlines( aRedlines
.size() > 1 ||
1033 // single item with children, e.g. multiple redlines of a table or table row deletion/insertion
1034 ( aRedlines
.size() == 1 && rTreeView
.iter_n_children(*aRedlines
[0]) > 0 ) );
1036 // don't add extra Undo label to a single item only with redline stack (i.e. old changes
1037 // on the same text range, stored only in OOXML)
1038 if ( bMoreRedlines
&& aRedlines
.size() == 1 )
1040 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*aRedlines
[0] ));
1041 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(*xChild
));
1042 if ( pData
->bDisabled
)
1043 bMoreRedlines
= false;
1046 if ( bMoreRedlines
)
1050 SwRewriter aRewriter
;
1051 aRewriter
.AddRule(UndoArg1
,
1052 OUString::number(aRedlines
.size()));
1053 aTmpStr
= aRewriter
.Apply(SwResId(STR_N_REDLINES
));
1056 SwRewriter aRewriter
;
1057 aRewriter
.AddRule(UndoArg1
, aTmpStr
);
1059 pSh
->StartUndo(bAccept
? SwUndoId::ACCEPT_REDLINE
: SwUndoId::REJECT_REDLINE
,
1063 // accept/reject the redlines in aRedlines. The absolute
1064 // position may change during the process (e.g. when two redlines
1065 // are merged in result of another one being deleted), so the
1066 // position must be resolved late and checked before using it.
1068 for (const auto& rRedLine
: aRedlines
)
1070 SwRedlineTable::size_type nPosition
= GetRedlinePos( *rRedLine
);
1071 if( nPosition
!= SwRedlineTable::npos
)
1072 (pSh
->*FnAccRej
)( nPosition
);
1074 // handle redlines of table rows, stored as children of the item associated
1075 // to the deleted/inserted table row(s)
1076 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*rRedLine
));
1077 if ( rTreeView
.iter_children(*xChild
) )
1079 RedlinData
*pData
= weld::fromId
<RedlinData
*>(rTreeView
.get_id(*xChild
));
1080 // disabled for redline stack, but not for redlines of table rows
1081 if ( !pData
->bDisabled
)
1085 nPosition
= GetRedlinePos( *xChild
);
1086 if( nPosition
!= SwRedlineTable::npos
)
1087 (pSh
->*FnAccRej
)( nPosition
);
1089 while ( rTreeView
.iter_next_sibling(*xChild
) );
1094 if ( bMoreRedlines
)
1101 m_bInhibitActivate
= false;
1104 if (nPos
!= -1 && rTreeView
.n_children())
1106 if (nPos
>= rTreeView
.n_children())
1107 nPos
= rTreeView
.n_children() - 1;
1108 rTreeView
.select(nPos
);
1109 rTreeView
.scroll_to_row(nPos
);
1110 rTreeView
.set_cursor(nPos
);
1111 SelectHdl(rTreeView
);
1113 m_pTPView
->EnableUndo();
1116 SwRedlineTable::size_type
SwRedlineAcceptDlg::GetRedlinePos(const weld::TreeIter
& rEntry
)
1118 SwView
* pView
= GetActiveView();
1120 return SwRedlineTable::npos
;
1122 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1124 return SwRedlineTable::npos
;
1126 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1127 return pSh
->FindRedlineOfData( *static_cast<SwRedlineDataParent
*>(weld::fromId
<RedlinData
*>(
1128 rTreeView
.get_id(rEntry
))->pData
)->pData
);
1131 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, AcceptHdl
, SvxTPView
*, void)
1133 CallAcceptReject( true, true );
1136 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, AcceptAllHdl
, SvxTPView
*, void)
1138 CallAcceptReject( false, true );
1141 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, RejectHdl
, SvxTPView
*, void)
1143 CallAcceptReject( true, false );
1146 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, RejectAllHdl
, SvxTPView
*, void)
1148 CallAcceptReject( false, false );
1151 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, UndoHdl
, SvxTPView
*, void)
1153 if (SwView
* pView
= GetActiveView())
1155 pView
->GetViewFrame().GetDispatcher()->
1156 Execute(SID_UNDO
, SfxCallMode::SYNCHRON
);
1157 m_pTPView
->EnableUndo(pView
->GetSlotState(SID_UNDO
) != nullptr);
1163 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, FilterChangedHdl
, SvxTPFilter
*, void)
1165 SvxTPFilter
*pFilterTP
= m_xTabPagesCTRL
->GetFilterPage();
1167 if (pFilterTP
->IsAction())
1168 m_sFilterAction
= pFilterTP
->GetLbAction()->get_active_text();
1170 m_sFilterAction
.clear();
1175 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, SelectHdl
, weld::TreeView
&, void)
1177 m_aSelectTimer
.Start();
1180 IMPL_LINK_NOARG(SwRedlineAcceptDlg
, GotoHdl
, Timer
*, void)
1182 m_aSelectTimer
.Stop();
1184 SwView
* pView
= GetActiveView();
1188 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1192 bool bIsNotFormated
= false;
1195 //#98883# don't select redlines while the dialog is not focused
1196 //#107938# But not only ask pTable if it has the focus. To move
1197 // the selection to the selected redline any child of pParentDlg
1199 if (!m_xParentDlg
|| m_xParentDlg
->has_toplevel_focus())
1201 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1202 std::unique_ptr
<weld::TreeIter
> xActEntry(rTreeView
.make_iterator());
1203 if (rTreeView
.get_selected(xActEntry
.get()))
1206 pSh
->EnterStdMode();
1207 SwViewShell::SetCareDialog(m_xParentDlg
);
1209 rTreeView
.selected_foreach([this, pSh
, &rTreeView
, &xActEntry
, &bIsNotFormated
, &bSel
](weld::TreeIter
& rEntry
){
1210 rTreeView
.copy_iterator(rEntry
, *xActEntry
);
1211 if (rTreeView
.get_iter_depth(rEntry
))
1213 rTreeView
.iter_parent(*xActEntry
);
1214 if (rTreeView
.is_selected(*xActEntry
))
1215 return false; // don't select twice
1220 // #98864# find the selected redline (ignore, if the redline is already gone)
1221 SwRedlineTable::size_type nPos
= GetRedlinePos(*xActEntry
);
1222 if (nPos
!= SwRedlineTable::npos
)
1225 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
1226 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
1228 if (pSh
->GotoRedline(nPos
, true))
1231 pSh
->EnterAddMode();
1235 // select all redlines of tracked table rows
1236 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator( &*xActEntry
));
1237 if ( rTreeView
.iter_children(*xChild
) )
1239 RedlinData
*pData
= reinterpret_cast<RedlinData
*>(rTreeView
.get_id(*xChild
).toInt64());
1240 // disabled for redline stack, but not for redlines of table rows
1241 if ( !pData
->bDisabled
)
1245 nPos
= GetRedlinePos(*xChild
);
1246 if (nPos
!= SwRedlineTable::npos
)
1248 const SwRangeRedline
& rRedln
= pSh
->GetRedline( nPos
);
1249 bIsNotFormated
|= RedlineType::Format
!= rRedln
.GetType();
1251 if (pSh
->GotoRedline(nPos
, true))
1254 pSh
->EnterAddMode();
1258 while ( rTreeView
.iter_next_sibling(*xChild
) );
1264 pSh
->LeaveAddMode();
1266 SwViewShell::SetCareDialog(nullptr);
1270 bool const bEnable
= !pSh
->GetDoc()->GetDocShell()->IsReadOnly()
1271 && !pSh
->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
1272 m_pTPView
->EnableAccept( bEnable
&& bSel
/*&& !bReadonlySel*/ );
1273 m_pTPView
->EnableReject( bEnable
&& bSel
/*&& !bReadonlySel*/ );
1274 m_pTPView
->EnableClearFormat( bEnable
&& bSel
&& !bIsNotFormated
/*&& !bReadonlySel*/ );
1275 m_pTPView
->EnableAcceptAll( bEnable
);
1276 m_pTPView
->EnableRejectAll( bEnable
);
1277 m_pTPView
->EnableClearFormatAll( bEnable
&& m_bOnlyFormatedRedlines
);
1280 IMPL_LINK(SwRedlineAcceptDlg
, CommandHdl
, const CommandEvent
&, rCEvt
, bool)
1282 if (rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1285 SwView
* pView
= GetActiveView();
1289 SwWrtShell
* pSh
= pView
->GetWrtShellPtr();
1293 const SwRangeRedline
*pRed
= nullptr;
1295 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1296 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator());
1297 bool bEntry
= rTreeView
.get_selected(xEntry
.get());
1300 std::unique_ptr
<weld::TreeIter
> xTopEntry(rTreeView
.make_iterator(xEntry
.get()));
1302 if (rTreeView
.get_iter_depth(*xTopEntry
))
1303 rTreeView
.iter_parent(*xTopEntry
);
1305 SwRedlineTable::size_type nPos
= GetRedlinePos(*xTopEntry
);
1307 // disable commenting for protected areas
1308 if (nPos
!= SwRedlineTable::npos
&& (pRed
= pSh
->GotoRedline(nPos
, true)) != nullptr)
1310 if( pSh
->IsCursorPtAtEnd() )
1316 m_xPopup
->set_sensitive("writeredit", bEntry
&& pRed
&&
1317 !rTreeView
.get_iter_depth(*xEntry
) &&
1318 rTreeView
.count_selected_rows() == 1);
1319 m_xPopup
->set_sensitive("writersort", rTreeView
.n_children() != 0);
1320 int nColumn
= rTreeView
.get_sort_column();
1323 for (sal_Int32 i
= 0; i
< 5; ++i
)
1324 m_xSortMenu
->set_active(u
"writersort" + OUString::number(i
), i
== nColumn
);
1326 OUString sCommand
= m_xPopup
->popup_at_rect(&rTreeView
, tools::Rectangle(rCEvt
.GetMousePosPixel(), Size(1,1)));
1328 if (sCommand
== "writeredit")
1332 if (rTreeView
.get_iter_depth(*xEntry
))
1333 rTreeView
.iter_parent(*xEntry
);
1335 SwRedlineTable::size_type nPos
= GetRedlinePos(*xEntry
);
1337 if (nPos
== SwRedlineTable::npos
)
1340 const SwRangeRedline
&rRedline
= pSh
->GetRedline(nPos
);
1342 /* enable again once we have redline comments in the margin
1343 sComment = rRedline.GetComment();
1344 if ( !sComment.Len() )
1345 GetActiveView()->GetDocShell()->Broadcast(SwRedlineHint(&rRedline,SWREDLINE_INSERTED));
1346 const_cast<SwRangeRedline&>(rRedline).Broadcast(SwRedlineHint(&rRedline,SWREDLINE_FOCUS));
1349 OUString sComment
= convertLineEnd(rRedline
.GetComment(), GetSystemLineEnd());
1350 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
1351 ::DialogGetRanges fnGetRange
= pFact
->GetDialogGetRangesFunc();
1352 SfxItemSet
aSet( pSh
->GetAttrPool(), fnGetRange() );
1354 aSet
.Put(SvxPostItTextItem(sComment
, SID_ATTR_POSTIT_TEXT
));
1355 aSet
.Put(SvxPostItAuthorItem(rRedline
.GetAuthorString(), SID_ATTR_POSTIT_AUTHOR
));
1357 aSet
.Put(SvxPostItDateItem( GetAppLangDateTimeString(
1358 rRedline
.GetRedlineData().GetTimeStamp() ),
1359 SID_ATTR_POSTIT_DATE
));
1361 ScopedVclPtr
<AbstractSvxPostItDialog
> pDlg(pFact
->CreateSvxPostItDialog(&rTreeView
, aSet
));
1366 switch( rRedline
.GetType() )
1368 case RedlineType::Insert
:
1369 pResId
= STR_REDLINE_INSERTED
;
1371 case RedlineType::Delete
:
1372 pResId
= STR_REDLINE_DELETED
;
1374 case RedlineType::Format
:
1375 case RedlineType::ParagraphFormat
:
1376 pResId
= STR_REDLINE_FORMATTED
;
1378 case RedlineType::Table
:
1379 pResId
= STR_REDLINE_TABLECHG
;
1381 default:;//prevent warning
1383 OUString
sTitle(SwResId(STR_REDLINE_COMMENT
));
1385 sTitle
+= SwResId(pResId
);
1386 pDlg
->SetText(sTitle
);
1388 SwViewShell::SetCareDialog(pDlg
->GetDialog());
1390 if ( pDlg
->Execute() == RET_OK
)
1392 const SfxItemSet
* pOutSet
= pDlg
->GetOutputItemSet();
1393 OUString
sMsg(pOutSet
->Get(SID_ATTR_POSTIT_TEXT
).GetValue());
1395 // insert / change comment
1396 pSh
->SetRedlineComment(sMsg
);
1397 rTreeView
.set_text(*xEntry
, sMsg
.replace('\n', ' '), 3);
1401 SwViewShell::SetCareDialog(nullptr);
1402 pDlg
.disposeAndClear();
1405 else if (!sCommand
.isEmpty())
1407 int nSortMode
= o3tl::toInt32(sCommand
.subView(10));
1409 if (nSortMode
== 4 && nColumn
== 4)
1410 return true; // we already have it
1412 nSortMode
= -1; // unsorted / sorted by position
1414 SwWait
aWait( *pView
->GetDocShell(), false );
1415 m_pTable
->HeaderBarClick(nSortMode
);
1416 if (nSortMode
== -1)
1417 Init(); // newly fill everything
1424 OUString
lcl_StripAcceptChgDat(OUString
&rExtraString
)
1429 sal_Int32 nPos
= rExtraString
.indexOf("AcceptChgDat:");
1432 // try to read the alignment string "ALIGN:(...)"; if none existing,
1433 // it's an old version
1434 sal_Int32 n1
= rExtraString
.indexOf('(', nPos
);
1437 sal_Int32 n2
= rExtraString
.indexOf(')', n1
);
1440 // cut out the alignment string
1441 aStr
= rExtraString
.copy(nPos
, n2
- nPos
+ 1);
1442 rExtraString
= rExtraString
.replaceAt(nPos
, n2
- nPos
+ 1, u
"");
1443 aStr
= aStr
.copy(n1
- nPos
+ 1);
1451 void SwRedlineAcceptDlg::Initialize(OUString
& rExtraString
)
1453 if (rExtraString
.isEmpty())
1456 OUString aStr
= lcl_StripAcceptChgDat(rExtraString
);
1460 int nCount
= aStr
.toInt32();
1464 std::vector
<int> aEndPos
;
1466 for (int i
= 0; i
< nCount
; ++i
)
1468 sal_Int32 n1
= aStr
.indexOf(';');
1469 aStr
= aStr
.copy( n1
+1 );
1470 aEndPos
.push_back(aStr
.toInt32());
1473 bool bUseless
= false;
1475 std::vector
<int> aWidths
;
1476 for (int i
= 1; i
< nCount
; ++i
)
1478 aWidths
.push_back(aEndPos
[i
] - aEndPos
[i
- 1]);
1479 if (aWidths
.back() <= 0)
1485 // turn column end points back to column widths, ignoring the small
1486 // value used for the expander column
1487 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1488 rTreeView
.set_column_fixed_widths(aWidths
);
1492 void SwRedlineAcceptDlg::FillInfo(OUString
&rExtraData
) const
1494 //remove any old one before adding a new one
1495 lcl_StripAcceptChgDat(rExtraData
);
1496 rExtraData
+= "AcceptChgDat:(";
1498 const int nTabCount
= 4;
1500 rExtraData
+= OUString::number(nTabCount
);
1503 weld::TreeView
& rTreeView
= m_pTable
->GetWidget();
1504 std::vector
<int> aWidths
;
1505 // turn column widths back into column end points for compatibility
1506 // with how they used to be stored, including a small value for the
1508 aWidths
.push_back(rTreeView
.get_checkbox_column_width());
1509 for (int i
= 0; i
< nTabCount
- 1; ++i
)
1511 int nWidth
= rTreeView
.get_column_width(i
);
1512 assert(nWidth
> 0 && "suspicious to get a value like this");
1513 aWidths
.push_back(aWidths
.back() + nWidth
);
1516 for (auto a
: aWidths
)
1518 rExtraData
+= OUString::number(a
);
1524 SwRedlineAcceptPanel::SwRedlineAcceptPanel(weld::Widget
* pParent
)
1525 : PanelLayout(pParent
, "ManageChangesPanel", "modules/swriter/ui/managechangessidebar.ui")
1526 , mxContentArea(m_xBuilder
->weld_container("content_area"))
1528 mpImplDlg
.reset(new SwRedlineAcceptDlg(nullptr, m_xBuilder
.get(), mxContentArea
.get()));
1532 // we want to receive SfxHintId::DocChanged
1533 StartListening(*(SW_MOD()->GetView()->GetDocShell()));
1536 SwRedlineAcceptPanel::~SwRedlineAcceptPanel()
1540 void SwRedlineAcceptPanel::Notify(SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1542 if (mpImplDlg
&& rHint
.GetId() == SfxHintId::DocChanged
)
1543 mpImplDlg
->Activate();
1546 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */