Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/misc/redlndlg.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <redline.hxx>
21
#include <tools/datetime.hxx>
22
#include <tools/lineend.hxx>
23
#include <svl/eitem.hxx>
24
#include <sfx2/viewfrm.hxx>
25
#include <sfx2/dispatch.hxx>
26
#include <svx/ctredlin.hxx>
27
#include <svx/postattr.hxx>
28
#include <utility>
29
#include <vcl/commandevent.hxx>
30
#include <vcl/weld/Dialog.hxx>
31
#include <vcl/weld/Menu.hxx>
32
#include <vcl/weld/weldutils.hxx>
33
#include <swtypes.hxx>
34
#include <wrtsh.hxx>
35
#include <view.hxx>
36
#include <swmodule.hxx>
37
#include <redlndlg.hxx>
38
#include <swwait.hxx>
39
#include <uitool.hxx>
40
#include <o3tl/string_view.hxx>
41
#include <o3tl/temporary.hxx>
42
43
#include <cmdid.h>
44
#include <strings.hrc>
45
46
// -> #111827#
47
#include <swundo.hxx>
48
#include <SwRewriter.hxx>
49
// <- #111827#
50
51
#include <vector>
52
#include <svx/svxdlg.hxx>
53
#include <osl/diagnose.h>
54
#include <bitmaps.hlst>
55
56
#include <docsh.hxx>
57
58
#include <IDocumentRedlineAccess.hxx>
59
#include <usrpref.hxx>
60
#include <memory>
61
62
SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(SwRedlineAcceptChild, FN_REDLINE_ACCEPT)
63
64
SwRedlineAcceptChild::SwRedlineAcceptChild(vcl::Window* _pParent, sal_uInt16 nId,
65
                                           SfxBindings& rBindings, SfxChildWinInfo& rInfo)
66
0
    : SwChildWinWrapper(_pParent, nId)
67
0
{
68
0
    auto xDlg
69
0
        = std::make_shared<SwModelessRedlineAcceptDlg>(&rBindings, this, _pParent->GetFrameWeld());
70
0
    SetController(xDlg);
71
0
    xDlg->Initialize(rInfo);
72
0
}
73
74
SwModelessRedlineAcceptDlg::SwModelessRedlineAcceptDlg(
75
    SfxBindings* _pBindings, SwChildWinWrapper* pChild, weld::Window *pParent)
76
0
    : SfxModelessDialogController(_pBindings, pChild, pParent,
77
0
        u"svx/ui/acceptrejectchangesdialog.ui"_ustr, u"AcceptRejectChangesDialog"_ustr)
78
0
    , m_xContentArea(m_xBuilder->weld_container(u"container"_ustr))
79
0
    , m_pChildWin(pChild)
80
0
{
81
0
    m_xImplDlg.reset(new SwRedlineAcceptDlg(m_xDialog, m_xBuilder.get(), m_xContentArea.get()));
82
0
}
83
84
void SwModelessRedlineAcceptDlg::Activate()
85
0
{
86
0
    if (mbInDestruction)
87
0
        return;
88
89
0
    SwView *pView = ::GetActiveView();
90
0
    if (!pView) // can happen when switching to another app, when a Listbox in dialog
91
0
        return; // had the focus previously (actually THs Bug)
92
93
0
    SwDocShell *pDocSh = pView->GetDocShell();
94
95
0
    if (m_pChildWin->GetOldDocShell() != pDocSh)
96
0
    {   // doc-switch
97
0
        SwWait aWait( *pDocSh, false );
98
0
        SwWrtShell* pSh = pView->GetWrtShellPtr();
99
0
        if (!pSh)
100
0
            return;
101
102
0
        m_pChildWin->SetOldDocShell(pDocSh);  // avoid recursion (using modified-Hdl)
103
104
0
        bool bMod = pSh->IsModified();
105
0
        SfxBoolItem aShow(FN_REDLINE_SHOW, true);
106
0
        pSh->GetView().GetViewFrame().GetDispatcher()->ExecuteList(
107
0
            FN_REDLINE_SHOW, SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
108
0
            { &aShow });
109
0
        if (!bMod)
110
0
            pSh->ResetModified();
111
0
        m_xImplDlg->Init();
112
0
        SfxModelessDialogController::Activate();
113
114
0
        return;
115
0
    }
116
117
0
    SfxModelessDialogController::Activate();
118
0
    m_xImplDlg->Activate();
119
0
}
120
121
void SwModelessRedlineAcceptDlg::Initialize(SfxChildWinInfo& rInfo)
122
0
{
123
0
    m_xImplDlg->Initialize(rInfo.aExtraString);
124
125
0
    SfxModelessDialogController::Initialize(rInfo);
126
0
}
127
128
void SwModelessRedlineAcceptDlg::FillInfo(SfxChildWinInfo& rInfo) const
129
0
{
130
0
    SfxModelessDialogController::FillInfo(rInfo);
131
0
    m_xImplDlg->FillInfo(rInfo.aExtraString);
132
0
}
133
134
SwModelessRedlineAcceptDlg::~SwModelessRedlineAcceptDlg()
135
0
{
136
0
    mbInDestruction = true;
137
0
}
138
139
namespace
140
{
141
const SwRedlineData* lcl_get_selected_redlinedata(const weld::TreeView& rTreeView)
142
0
{
143
0
    if (std::unique_ptr<weld::TreeIter> xEntry = rTreeView.get_selected())
144
0
    {
145
0
        RedlineData* pRedlinData = weld::fromId<RedlineData*>(rTreeView.get_id(*xEntry));
146
0
        if (rTreeView.get_iter_depth(*xEntry))
147
0
            return static_cast<SwRedlineDataChild*>(pRedlinData->pData)->pChild;
148
0
        else
149
0
            return static_cast<SwRedlineDataParent*>(pRedlinData->pData)->pData;
150
0
    }
151
0
    return nullptr;
152
0
}
153
154
void lcl_reselect(weld::TreeView& rTreeView, const SwRedlineData* pSelectedEntryRedlineData)
155
0
{
156
0
    if (!pSelectedEntryRedlineData)
157
0
    {
158
0
        rTreeView.set_cursor(-1);
159
0
        return;
160
0
    }
161
0
    rTreeView.all_foreach(
162
0
        [&rTreeView, &pSelectedEntryRedlineData](weld::TreeIter& rIter)
163
0
        {
164
0
            RedlineData* pRedlinData = weld::fromId<RedlineData*>(rTreeView.get_id(rIter));
165
0
            const SwRedlineData* pRedlineData;
166
0
            if (rTreeView.get_iter_depth(rIter))
167
0
                pRedlineData = static_cast<SwRedlineDataChild*>(pRedlinData->pData)->pChild;
168
0
            else
169
0
                pRedlineData = static_cast<SwRedlineDataParent*>(pRedlinData->pData)->pData;
170
0
            if (pRedlineData == pSelectedEntryRedlineData)
171
0
            {
172
0
                rTreeView.set_cursor(rIter);
173
0
                return true;
174
0
            }
175
0
            return false;
176
0
        });
177
0
}
178
}
179
180
SwRedlineAcceptDlg::SwRedlineAcceptDlg(std::shared_ptr<weld::Window> xParent, weld::Builder *pBuilder,
181
                                       weld::Container *pContentArea, bool bAutoFormat)
182
0
    : m_xParentDlg(std::move(xParent))
183
0
    , m_aSelectTimer("SwRedlineAcceptDlg m_aSelectTimer")
184
0
    , m_sInserted(SwResId(STR_REDLINE_INSERTED))
185
0
    , m_sDeleted(SwResId(STR_REDLINE_DELETED))
186
0
    , m_sFormated(SwResId(STR_REDLINE_FORMATTED))
187
0
    , m_sTableChgd(SwResId(STR_REDLINE_TABLECHG))
188
0
    , m_sFormatCollSet(SwResId(STR_REDLINE_FMTCOLLSET))
189
0
    , m_sAutoFormat(SwResId(STR_REDLINE_AUTOFMT))
190
0
    , m_bOnlyFormatedRedlines(false)
191
0
    , m_bRedlnAutoFormat(bAutoFormat)
192
0
    , m_bInhibitActivate(false)
193
0
    , m_bHasTrackedColumn(false)
194
0
    , m_xTabPagesCTRL(new SvxAcceptChgCtr(pContentArea))
195
0
    , m_xPopup(pBuilder->weld_menu(u"writermenu"_ustr))
196
0
    , m_xSortMenu(pBuilder->weld_menu(u"writersortmenu"_ustr))
197
0
    , m_rTPView(m_xTabPagesCTRL->GetViewPage())
198
0
{
199
0
    m_pTable = m_rTPView.GetTableControl();
200
0
    m_pTable->SetWriterView();
201
202
0
    m_rTPView.GetSortByComboBoxControl()->set_active(4);
203
204
0
    m_rTPView.SetSortByComboBoxChangedHdl(
205
0
        LINK(this, SwRedlineAcceptDlg, SortByComboBoxChangedHdl));
206
207
0
    m_rTPView.SetAcceptClickHdl(LINK(this, SwRedlineAcceptDlg, AcceptHdl));
208
0
    m_rTPView.SetAcceptAllClickHdl(LINK(this, SwRedlineAcceptDlg, AcceptAllHdl));
209
0
    m_rTPView.SetRejectClickHdl(LINK(this, SwRedlineAcceptDlg, RejectHdl));
210
0
    m_rTPView.SetRejectAllClickHdl(LINK(this, SwRedlineAcceptDlg, RejectAllHdl));
211
0
    m_rTPView.SetUndoClickHdl(LINK(this, SwRedlineAcceptDlg, UndoHdl));
212
    //tdf#89227 default to disabled, and only enable if possible to accept/reject
213
0
    m_rTPView.EnableAccept(false);
214
0
    m_rTPView.EnableReject(false);
215
0
    m_rTPView.EnableClearFormat(false);
216
0
    m_rTPView.EnableAcceptAll(false);
217
0
    m_rTPView.EnableRejectAll(false);
218
0
    m_rTPView.EnableClearFormatAll(false);
219
220
0
    m_xTabPagesCTRL->GetFilterPage()->SetReadyHdl(LINK(this, SwRedlineAcceptDlg, FilterChangedHdl));
221
222
0
    weld::ComboBox* pActLB = m_xTabPagesCTRL->GetFilterPage()->GetLbAction();
223
0
    pActLB->append_text(m_sInserted);
224
0
    pActLB->append_text(m_sDeleted);
225
0
    pActLB->append_text(m_sFormated);
226
0
    pActLB->append_text(m_sTableChgd);
227
228
0
    if (HasRedlineAutoFormat())
229
0
    {
230
0
        pActLB->append_text(m_sFormatCollSet);
231
0
        pActLB->append_text(m_sAutoFormat);
232
0
        m_rTPView.ShowUndo();
233
0
        m_rTPView.DisableUndo();     // no UNDO events yet
234
0
    }
235
236
0
    pActLB->set_active(0);
237
238
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
239
0
    rTreeView.set_selection_mode(SelectionMode::Multiple);
240
241
0
    rTreeView.connect_selection_changed(LINK(this, SwRedlineAcceptDlg, SelectHdl));
242
0
    rTreeView.connect_command(LINK(this, SwRedlineAcceptDlg, CommandHdl));
243
244
    // avoid multiple selection of the same texts:
245
0
    m_aSelectTimer.SetTimeout(100);
246
0
    m_aSelectTimer.SetInvokeHandler(LINK(this, SwRedlineAcceptDlg, GotoHdl));
247
248
    // we want to receive SfxHintId::SwRedlineContentAtPos
249
0
    StartListening(*(SwModule::get()->GetView()->GetDocShell()));
250
0
}
251
252
SwRedlineAcceptDlg::~SwRedlineAcceptDlg()
253
0
{
254
0
}
255
256
void SwRedlineAcceptDlg::Init(SwRedlineTable::size_type nStart)
257
0
{
258
0
    std::optional<SwWait> oWait;
259
0
    SwView* pView = GetActiveView();
260
0
    if (pView)
261
0
        oWait.emplace(*pView->GetDocShell(), false);
262
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
263
0
    m_aUsedSeqNo.clear();
264
265
    // tdf#162018 keep the selected entry selected
266
0
    const SwRedlineData* pSelectedEntryRedlineData = lcl_get_selected_redlinedata(rTreeView);
267
268
    // tdf#162337 tracked change selection when the Manage Changes dialog is initially opened
269
0
    if (pView && m_bInitialSelect)
270
0
    {
271
0
        m_bInitialSelect = false;
272
0
        SwWrtShell* pSh = pView->GetWrtShellPtr();
273
0
        if (pSh)
274
0
        {
275
0
            const SwRangeRedline* pCurrRedline = pSh->GetCurrRedline();
276
0
            if (pCurrRedline)
277
0
            {
278
                // Select current redline
279
0
                SwRedlineTable::size_type nPos
280
0
                    = pSh->FindRedlineOfData(pCurrRedline->GetRedlineData());
281
0
                pSh->GotoRedline(nPos, true);
282
0
                pSh->SetInSelect();
283
0
            }
284
0
            else
285
0
            {
286
                // Select the next redline if there is one
287
0
                pSh->AssureStdMode();
288
0
                pCurrRedline = pSh->SelNextRedline();
289
0
            }
290
0
            if (pCurrRedline)
291
0
                pSelectedEntryRedlineData = &pCurrRedline->GetRedlineData();
292
0
        }
293
0
    }
294
295
0
    rTreeView.freeze();
296
0
    if (nStart)
297
0
        RemoveParents(nStart, m_RedlineParents.size() - 1);
298
0
    else
299
0
    {
300
0
        rTreeView.clear();
301
0
        m_RedlineData.clear();
302
0
        m_RedlineChildren.clear();
303
0
        m_RedlineParents.erase(m_RedlineParents.begin() + nStart, m_RedlineParents.end());
304
0
    }
305
0
    rTreeView.thaw();
306
307
    // insert parents
308
0
    InsertParents(nStart);
309
0
    InitAuthors();
310
311
0
    lcl_reselect(rTreeView, pSelectedEntryRedlineData);
312
0
    EnableControls(pView);
313
0
}
314
315
static bool isAcceptRejectCommandsEnabled(const SwView& rView)
316
0
{
317
    // Check the state of the command, including read-only mode and special cases
318
    // like LOK AllowChangeComments mode
319
0
    return rView.GetViewFrame().GetDispatcher()->QueryState(FN_REDLINE_ACCEPT_ALL,
320
0
                                                            o3tl::temporary(SfxPoolItemHolder()))
321
0
           != SfxItemState::DISABLED;
322
0
}
323
324
void SwRedlineAcceptDlg::InitAuthors()
325
0
{
326
0
    if (!m_xTabPagesCTRL)
327
0
        return;
328
329
0
    SwView *pView = ::GetActiveView();
330
0
    if (!pView)
331
0
        return;
332
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
333
334
0
    SvxTPFilter *pFilterPage = m_xTabPagesCTRL->GetFilterPage();
335
336
0
    std::vector<OUString> aStrings;
337
0
    OUString sOldAuthor(pFilterPage->GetSelectedAuthor());
338
0
    pFilterPage->ClearAuthors();
339
340
0
    SwRedlineTable::size_type nCount = pSh ? pSh->GetRedlineCount() : 0;
341
342
0
    m_bOnlyFormatedRedlines = true;
343
344
    // determine authors
345
0
    for ( SwRedlineTable::size_type i = 0; i < nCount; i++)
346
0
    {
347
0
        const SwRangeRedline& rRedln = pSh->GetRedline(i);
348
349
0
        if( m_bOnlyFormatedRedlines && RedlineType::Format != rRedln.GetType() )
350
0
            m_bOnlyFormatedRedlines = false;
351
352
0
        aStrings.push_back(rRedln.GetAuthorString());
353
354
0
        for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
355
0
        {
356
0
            aStrings.push_back(rRedln.GetAuthorString(nStack));
357
0
        }
358
0
    }
359
360
0
    std::sort(aStrings.begin(), aStrings.end());
361
0
    aStrings.erase(std::unique(aStrings.begin(), aStrings.end()), aStrings.end());
362
363
0
    for (auto const & i: aStrings)
364
0
        pFilterPage->InsertAuthor(i);
365
366
0
    if (pFilterPage->SelectAuthor(sOldAuthor) == -1 && !aStrings.empty())
367
0
        pFilterPage->SelectAuthor(aStrings[0]);
368
0
}
369
370
void SwRedlineAcceptDlg::EnableControls(const SwView* pView)
371
0
{
372
0
    if (!pView)
373
0
        return;
374
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
375
0
    if (!pSh)
376
0
        return;
377
378
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
379
0
    bool const bEnable = isAcceptRejectCommandsEnabled(*pView)
380
0
        && rTreeView.n_children() != 0
381
0
        && !pSh->getIDocumentRedlineAccess().GetRedlinePassword().hasElements();
382
383
0
    bool bAcceptReject = false;
384
0
    bool bIsNotFormated = false;
385
0
    rTreeView.selected_foreach([this, pSh, &bIsNotFormated, &bAcceptReject](weld::TreeIter& rEntry){
386
        // Only enable these controls for top-level redlines
387
0
        if (m_pTable->GetWidget().get_iter_depth(rEntry) == 0)
388
0
            bAcceptReject = true;
389
390
        // find the selected redline
391
        // (fdo#57874: ignore, if the redline is already gone)
392
0
        SwRedlineTable::size_type nPos = GetRedlinePos(rEntry);
393
0
        if( nPos != SwRedlineTable::npos )
394
0
        {
395
0
            const SwRangeRedline& rRedln = pSh->GetRedline( nPos );
396
397
0
            bIsNotFormated |= RedlineType::Format != rRedln.GetType();
398
0
        }
399
0
        return false;
400
0
    });
401
402
0
    m_rTPView.EnableAccept(bEnable && bAcceptReject);
403
0
    m_rTPView.EnableReject(bEnable && bAcceptReject);
404
0
    m_rTPView.EnableClearFormat(bEnable && !bIsNotFormated && bAcceptReject);
405
0
    m_rTPView.EnableAcceptAll(bEnable);
406
0
    m_rTPView.EnableRejectAll(bEnable);
407
0
    m_rTPView.EnableClearFormatAll(bEnable && m_bOnlyFormatedRedlines);
408
0
}
409
410
const OUString & SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack,
411
                                            bool bTableChanges, bool bRowChanges)
412
0
{
413
0
    switch (rRedln.GetType(nStack))
414
0
    {
415
0
        case RedlineType::Insert:  return bTableChanges
416
0
            ? bRowChanges
417
0
                ? BMP_REDLINE_ROW_INSERTION
418
0
                : BMP_REDLINE_COL_INSERTION
419
0
            : rRedln.IsMoved()
420
0
                ? BMP_REDLINE_MOVED_INSERTION
421
0
                : rRedln.IsAnnotation()
422
0
                    ? BMP_REDLINE_COMMENT_INSERTION
423
0
                    : BMP_REDLINE_INSERTED;
424
0
        case RedlineType::Delete:  return bTableChanges
425
0
            ? bRowChanges
426
0
                 ? BMP_REDLINE_ROW_DELETION
427
0
                 : BMP_REDLINE_COL_DELETION
428
0
            : rRedln.IsMoved()
429
0
                ? BMP_REDLINE_MOVED_DELETION
430
0
                : rRedln.IsAnnotation()
431
0
                    ? BMP_REDLINE_COMMENT_DELETION
432
0
                    : BMP_REDLINE_DELETED;
433
0
        case RedlineType::Format:  return BMP_REDLINE_FORMATTED;
434
0
        case RedlineType::ParagraphFormat: return BMP_REDLINE_FORMATTED;
435
0
        case RedlineType::Table:   return BMP_REDLINE_TABLECHG;
436
0
        case RedlineType::FmtColl: return BMP_REDLINE_FMTCOLLSET;
437
0
        default: break;
438
0
    }
439
440
0
    return EMPTY_OUSTRING;
441
0
}
442
443
const OUString & SwRedlineAcceptDlg::GetActionText(const SwRangeRedline& rRedln, sal_uInt16 nStack)
444
0
{
445
0
    switch( rRedln.GetType(nStack) )
446
0
    {
447
0
        case RedlineType::Insert:   return m_sInserted;
448
0
        case RedlineType::Delete:   return m_sDeleted;
449
0
        case RedlineType::Format:   return m_sFormated;
450
0
        case RedlineType::ParagraphFormat:   return m_sFormated;
451
0
        case RedlineType::Table:    return m_sTableChgd;
452
0
        case RedlineType::FmtColl:  return m_sFormatCollSet;
453
0
        default:;//prevent warning
454
0
    }
455
456
0
    return EMPTY_OUSTRING;
457
0
}
458
459
// newly initialise after activation
460
void SwRedlineAcceptDlg::Activate()
461
0
{
462
    // prevent update if flag is set (#102547#)
463
0
    if( m_bInhibitActivate )
464
0
        return;
465
466
0
    SwView *pView = ::GetActiveView();
467
0
    if (!pView) // can happen when switching to another app
468
0
    {
469
0
        m_rTPView.EnableAccept(false);
470
0
        m_rTPView.EnableReject(false);
471
0
        m_rTPView.EnableClearFormat(false);
472
0
        m_rTPView.EnableAcceptAll(false);
473
0
        m_rTPView.EnableRejectAll(false);
474
0
        m_rTPView.EnableClearFormatAll(false);
475
0
        return; // had the focus previously
476
0
    }
477
478
0
    SwWait aWait( *pView->GetDocShell(), false );
479
480
0
    if (pView->GetDocShell()->IsReadOnly())
481
0
    {
482
0
        m_rTPView.EnableAccept(false);
483
0
        m_rTPView.EnableReject(false);
484
0
        m_rTPView.EnableClearFormat(false);
485
0
        m_rTPView.EnableAcceptAll(false);
486
0
        m_rTPView.EnableRejectAll(false);
487
0
        m_rTPView.EnableClearFormatAll(false);
488
        // note: enabling is done in EnableControls below
489
0
    }
490
491
0
    m_aUsedSeqNo.clear();
492
493
    // did something change?
494
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
495
0
    if (!pSh)
496
0
        return;
497
498
    // tdf#162018 keep the selected entry selected
499
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
500
0
    const SwRedlineData* pSelectedEntryRedlineData = lcl_get_selected_redlinedata(m_pTable->GetWidget());
501
502
0
    SwRedlineTable::size_type nCount = pSh->GetRedlineCount();
503
504
    // check the number of pointers
505
0
    for ( SwRedlineTable::size_type i = 0; i < nCount; i++)
506
0
    {
507
0
        const SwRangeRedline& rRedln = pSh->GetRedline(i);
508
509
0
        if (i >= m_RedlineParents.size())
510
0
        {
511
            // new entries have been appended
512
0
            Init(i);
513
0
            return;
514
0
        }
515
516
0
        SwRedlineDataParent *const pParent = m_RedlineParents[i].get();
517
0
        if (&rRedln.GetRedlineData() != pParent->pData)
518
0
        {
519
            // Redline-Parents were inserted, changed or deleted
520
0
            i = CalcDiff(i, false);
521
0
            if (i == SwRedlineTable::npos)
522
0
            {
523
0
                lcl_reselect(rTreeView, pSelectedEntryRedlineData);
524
0
                return;
525
0
            }
526
0
            continue;
527
0
        }
528
529
0
        const SwRedlineData *pRedlineData = rRedln.GetRedlineData().Next();
530
0
        const SwRedlineDataChild *pBackupData = pParent->pNext;
531
532
0
        if (!pRedlineData && pBackupData)
533
0
        {
534
            // Redline-Children were deleted
535
0
            i = CalcDiff(i, true);
536
0
            if (i == SwRedlineTable::npos)
537
0
            {
538
0
                lcl_reselect(rTreeView, pSelectedEntryRedlineData);
539
0
                return;
540
0
            }
541
0
            continue;
542
0
        }
543
0
        else
544
0
        {
545
0
            while (pRedlineData)
546
0
            {
547
0
                if (!pBackupData || pRedlineData != pBackupData->pChild)
548
0
                {
549
                    // Redline-Children were inserted, changed or deleted
550
0
                    i = CalcDiff(i, true);
551
0
                    if (i == SwRedlineTable::npos)
552
0
                    {
553
0
                        lcl_reselect(rTreeView, pSelectedEntryRedlineData);
554
0
                        return;
555
0
                    }
556
557
                    // here was a continue; targetted to the outer loop
558
                    // now a break will do, as there is nothing after it in the outer loop
559
0
                    break;
560
0
                }
561
0
                pBackupData = pBackupData->pNext;
562
0
                pRedlineData = pRedlineData->Next();
563
0
            }
564
0
        }
565
0
    }
566
567
0
    if (nCount != m_RedlineParents.size())
568
0
    {
569
        // Redlines were deleted at the end
570
0
        Init(nCount);
571
0
        return;
572
0
    }
573
574
    // check comment
575
0
    bool bIsShowChangesInMargin = SwModule::get()->GetUsrPref(false)->IsShowChangesInMargin();
576
0
    for (SwRedlineTable::size_type i = 0; i < nCount; i++)
577
0
    {
578
0
        const SwRangeRedline& rRedln = pSh->GetRedline(i);
579
0
        SwRedlineDataParent *const pParent = m_RedlineParents[i].get();
580
581
0
        if(rRedln.GetComment() != pParent->sComment)
582
0
        {
583
0
            bool bShowDeletedTextAsComment = bIsShowChangesInMargin &&
584
0
                RedlineType::Delete == rRedln.GetType() && rRedln.GetComment().isEmpty();
585
0
            const OUString sComment = bShowDeletedTextAsComment
586
0
                    ? rRedln.GetDescr()
587
0
                    : rRedln.GetComment();
588
0
            if (pParent->xTLBParent)
589
0
            {
590
                // update only comment
591
0
                rTreeView.set_text(*pParent->xTLBParent, sComment.replace('\n', ' '), 3);
592
0
            }
593
0
            pParent->sComment = sComment;
594
0
        }
595
0
    }
596
597
0
    InitAuthors();
598
599
0
    lcl_reselect(rTreeView, pSelectedEntryRedlineData);
600
0
    EnableControls(pView);
601
0
}
602
603
void SwRedlineAcceptDlg::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
604
0
{
605
0
    if (rHint.GetId() == SfxHintId::SwRedlineContentAtPos)
606
0
    {
607
0
        SwView* pView = GetActiveView();
608
0
        if (!pView)
609
0
            return;
610
611
0
        SwWrtShell* pSh = pView->GetWrtShellPtr();
612
0
        if (!pSh)
613
0
            return;
614
615
0
        const SwRangeRedline* pRangeRedline = pSh->GetCurrRedline();
616
0
        if (!pRangeRedline)
617
0
            return;
618
619
0
        const SwRedlineData& rRedlineData = pRangeRedline->GetRedlineData();
620
621
0
        weld::TreeView& rTreeView = m_pTable->GetWidget();
622
0
        rTreeView.all_foreach([&rTreeView, &rRedlineData](weld::TreeIter& rIter) {
623
0
            RedlineData* pRedlinData = weld::fromId<RedlineData*>(rTreeView.get_id(rIter));
624
0
            const SwRedlineData* pRedlineData;
625
0
            if (rTreeView.get_iter_depth(rIter))
626
0
                pRedlineData = static_cast<SwRedlineDataChild*>(pRedlinData->pData)->pChild;
627
0
            else
628
0
                pRedlineData = static_cast<SwRedlineDataParent*>(pRedlinData->pData)->pData;
629
0
            if (pRedlineData == &rRedlineData)
630
0
            {
631
0
                rTreeView.set_cursor(rIter);
632
0
                return true;
633
0
            }
634
0
            return false;
635
0
        });
636
0
    }
637
0
}
638
639
SwRedlineTable::size_type SwRedlineAcceptDlg::CalcDiff(SwRedlineTable::size_type nStart, bool bChild)
640
0
{
641
0
    if (!nStart || m_bHasTrackedColumn)
642
0
    {
643
0
        Init();
644
0
        return SwRedlineTable::npos;
645
0
    }
646
647
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
648
0
    rTreeView.freeze();
649
0
    SwView *pView = ::GetActiveView();
650
0
    if (!pView)
651
0
        return SwRedlineTable::npos;
652
653
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
654
0
    if (!pSh)
655
0
        return SwRedlineTable::npos;
656
657
0
    bool bHasRedlineAutoFormat = HasRedlineAutoFormat();
658
0
    SwRedlineDataParent *const pParent = m_RedlineParents[nStart].get();
659
0
    const SwRangeRedline& rRedln = pSh->GetRedline(nStart);
660
661
0
    if (bChild)     // should actually never happen, but just in case...
662
0
    {
663
        // throw away all entry's children and initialise newly
664
0
        SwRedlineDataChild* pBackupData = const_cast<SwRedlineDataChild*>(pParent->pNext);
665
0
        SwRedlineDataChild* pNext;
666
667
0
        while (pBackupData)
668
0
        {
669
0
            pNext = const_cast<SwRedlineDataChild*>(pBackupData->pNext);
670
0
            if (pBackupData->xTLBChild)
671
0
                rTreeView.remove(*pBackupData->xTLBChild);
672
673
0
            auto it = std::find_if(m_RedlineChildren.begin(), m_RedlineChildren.end(),
674
0
                [&pBackupData](const std::unique_ptr<SwRedlineDataChild>& rChildPtr) { return rChildPtr.get() == pBackupData; });
675
0
            if (it != m_RedlineChildren.end())
676
0
                m_RedlineChildren.erase(it);
677
678
0
            pBackupData = pNext;
679
0
        }
680
0
        pParent->pNext = nullptr;
681
682
        // insert new children
683
0
        InsertChildren(pParent, rRedln, bHasRedlineAutoFormat);
684
685
0
        rTreeView.thaw();
686
0
        return nStart;
687
0
    }
688
689
    // have entries been deleted?
690
0
    const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
691
0
    for (SwRedlineTable::size_type i = nStart + 1; i < m_RedlineParents.size(); i++)
692
0
    {
693
0
        if (m_RedlineParents[i]->pData == pRedlineData)
694
0
        {
695
            // remove entries from nStart to i-1
696
0
            RemoveParents(nStart, i - 1);
697
0
            rTreeView.thaw();
698
0
            return nStart - 1;
699
0
        }
700
0
    }
701
702
    // entries been inserted?
703
0
    SwRedlineTable::size_type nCount = pSh->GetRedlineCount();
704
0
    pRedlineData = m_RedlineParents[nStart]->pData;
705
706
0
    for (SwRedlineTable::size_type i = nStart + 1; i < nCount; i++)
707
0
    {
708
0
        if (&pSh->GetRedline(i).GetRedlineData() == pRedlineData)
709
0
        {
710
0
            rTreeView.thaw();
711
            // insert entries from nStart to i-1
712
0
            InsertParents(nStart, i - 1);
713
0
            return nStart - 1;
714
0
        }
715
0
    }
716
717
0
    rTreeView.thaw();
718
0
    Init(nStart);   // adjust all entries until the end
719
0
    return SwRedlineTable::npos;
720
0
}
721
722
void SwRedlineAcceptDlg::InsertChildren(SwRedlineDataParent *pParent, const SwRangeRedline& rRedln, bool bHasRedlineAutoFormat)
723
0
{
724
0
    SwRedlineDataChild *pLastRedlineChild = nullptr;
725
0
    const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
726
0
    bool bAutoFormatRedline = rRedln.IsAutoFormat();
727
728
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
729
730
0
    OUString sAction = GetActionText(rRedln);
731
0
    bool bValidParent = m_sFilterAction.isEmpty() || m_sFilterAction == sAction;
732
0
    bValidParent = bValidParent && m_pTable->IsValidEntry(rRedln.GetAuthorString(), rRedln.GetTimeStamp(), rRedln.GetComment());
733
0
    if (bHasRedlineAutoFormat)
734
0
    {
735
736
0
        if (pParent->pData->GetSeqNo())
737
0
        {
738
0
            std::pair<SwRedlineDataParentSortArr::const_iterator,bool> const ret
739
0
                = m_aUsedSeqNo.insert(pParent);
740
0
            if (ret.second) // already there
741
0
            {
742
0
                if (pParent->xTLBParent)
743
0
                {
744
0
                    rTreeView.set_text(*(*ret.first)->xTLBParent, m_sAutoFormat, 0);
745
0
                    rTreeView.remove(*pParent->xTLBParent);
746
0
                    pParent->xTLBParent.reset();
747
0
                }
748
0
                return;
749
0
            }
750
0
        }
751
0
        bValidParent = bValidParent && bAutoFormatRedline;
752
0
    }
753
0
    bool bValidTree = bValidParent;
754
755
0
    for (sal_uInt16 nStack = 1; nStack < rRedln.GetStackCount(); nStack++)
756
0
    {
757
0
        pRedlineData = pRedlineData->Next();
758
759
0
        SwRedlineDataChild* pRedlineChild = new SwRedlineDataChild;
760
0
        pRedlineChild->pChild = pRedlineData;
761
0
        m_RedlineChildren.push_back(std::unique_ptr<SwRedlineDataChild>(pRedlineChild));
762
763
0
        if ( pLastRedlineChild )
764
0
            pLastRedlineChild->pNext = pRedlineChild;
765
0
        else
766
0
            pParent->pNext = pRedlineChild;
767
768
0
        sAction = GetActionText(rRedln, nStack);
769
0
        bool bValidChild = m_sFilterAction.isEmpty() || m_sFilterAction == sAction;
770
0
        bValidChild = bValidChild && m_pTable->IsValidEntry(rRedln.GetAuthorString(nStack), rRedln.GetTimeStamp(nStack), rRedln.GetComment());
771
0
        if (bHasRedlineAutoFormat)
772
0
            bValidChild = bValidChild && bAutoFormatRedline;
773
0
        bValidTree |= bValidChild;
774
775
0
        if (bValidChild)
776
0
        {
777
0
            std::unique_ptr<RedlineData> pData(new RedlineData);
778
0
            pData->pData = pRedlineChild;
779
0
            pData->bDisabled = true;
780
781
0
            OUString sImage(GetActionImage(rRedln, nStack));
782
0
            const OUString& sAuthor = rRedln.GetAuthorString(nStack);
783
0
            pData->aDateTime = rRedln.GetTimeStamp(nStack);
784
0
            pData->eType = rRedln.GetType(nStack);
785
0
            OUString sDateEntry = GetAppLangDateTimeString(pData->aDateTime);
786
0
            const OUString& sComment = rRedln.GetComment(nStack);
787
788
0
            std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator());
789
0
            OUString sId(weld::toId(pData.get()));
790
0
            rTreeView.insert(pParent->xTLBParent.get(), -1, nullptr, &sId, nullptr, nullptr,
791
0
                             false, xChild.get());
792
0
            m_RedlineData.push_back(std::move(pData));
793
794
0
            rTreeView.set_image(*xChild, sImage, -1);
795
0
            rTreeView.set_text(*xChild, sAuthor, 1);
796
0
            rTreeView.set_text(*xChild, sDateEntry, 2);
797
0
            rTreeView.set_text(*xChild, sComment, 3);
798
799
0
            pRedlineChild->xTLBChild = std::move(xChild);
800
0
            if (!bValidParent)
801
0
                rTreeView.expand_row(*pParent->xTLBParent);
802
0
        }
803
0
        else
804
0
            pRedlineChild->xTLBChild.reset();
805
806
0
        pLastRedlineChild = pRedlineChild;
807
0
    }
808
809
0
    if (pLastRedlineChild)
810
0
        pLastRedlineChild->pNext = nullptr;
811
812
0
    if (!bValidTree && pParent->xTLBParent)
813
0
    {
814
0
        rTreeView.remove(*pParent->xTLBParent);
815
0
        pParent->xTLBParent.reset();
816
0
        if (bHasRedlineAutoFormat)
817
0
            m_aUsedSeqNo.erase(pParent);
818
0
    }
819
0
}
820
821
void SwRedlineAcceptDlg::RemoveParents(SwRedlineTable::size_type nStart, SwRedlineTable::size_type nEnd)
822
0
{
823
0
    SwView *pView = ::GetActiveView();
824
0
    if (!pView)
825
0
        return;
826
827
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
828
0
    if (!pSh)
829
0
        return;
830
831
0
    SwRedlineTable::size_type nCount = pSh->GetRedlineCount();
832
833
0
    std::vector<const weld::TreeIter*> aLBoxArr;
834
835
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
836
837
    // because of Bug of TLB that ALWAYS calls the SelectHandler at Remove:
838
0
    rTreeView.connect_selection_changed(Link<weld::ItemView&, void>());
839
840
0
    bool bChildrenRemoved = false;
841
0
    rTreeView.thaw();
842
0
    rTreeView.unselect_all();
843
844
    // set the cursor after the last entry because otherwise performance problem in TLB.
845
    // TLB would otherwise reset the cursor at every Remove (expensive)
846
0
    SwRedlineTable::size_type nPos = std::min(nCount, m_RedlineParents.size());
847
0
    weld::TreeIter *pCurEntry = nullptr;
848
0
    while( ( pCurEntry == nullptr ) && ( nPos > 0 ) )
849
0
    {
850
0
        --nPos;
851
0
        pCurEntry = m_RedlineParents[nPos]->xTLBParent.get();
852
0
    }
853
854
0
    if (pCurEntry)
855
0
        rTreeView.set_cursor(*pCurEntry);
856
857
0
    rTreeView.freeze();
858
859
0
    for (SwRedlineTable::size_type i = nStart; i <= nEnd; i++)
860
0
    {
861
0
        if (!bChildrenRemoved && m_RedlineParents[i]->pNext)
862
0
        {
863
0
            SwRedlineDataChild * pChildPtr =
864
0
                const_cast<SwRedlineDataChild*>(m_RedlineParents[i]->pNext);
865
0
            auto it = std::find_if(m_RedlineChildren.begin(), m_RedlineChildren.end(),
866
0
                [&pChildPtr](const std::unique_ptr<SwRedlineDataChild>& rChildPtr) { return rChildPtr.get() == pChildPtr; });
867
0
            if (it != m_RedlineChildren.end())
868
0
            {
869
0
                sal_uInt16 nChildren = 0;
870
0
                while (pChildPtr)
871
0
                {
872
0
                    pChildPtr = const_cast<SwRedlineDataChild*>(pChildPtr->pNext);
873
0
                    nChildren++;
874
0
                }
875
876
0
                m_RedlineChildren.erase(it, it + nChildren);
877
0
                bChildrenRemoved = true;
878
0
            }
879
0
        }
880
0
        weld::TreeIter *const pEntry = m_RedlineParents[i]->xTLBParent.get();
881
0
        if (pEntry)
882
0
            aLBoxArr.push_back(pEntry);
883
0
    }
884
885
0
    std::sort(aLBoxArr.begin(), aLBoxArr.end(), [&rTreeView](const weld::TreeIter* a, const weld::TreeIter* b) {
886
0
        return rTreeView.iter_compare(*a, *b) == -1;
887
0
    });
888
    // clear TLB from behind
889
0
    for (auto it = aLBoxArr.rbegin(); it != aLBoxArr.rend(); ++it)
890
0
    {
891
0
        const weld::TreeIter* pIter = *it;
892
0
        rTreeView.remove(*pIter);
893
0
    }
894
895
0
    rTreeView.thaw();
896
0
    rTreeView.connect_selection_changed(LINK(this, SwRedlineAcceptDlg, SelectHdl));
897
    // unfortunately by Remove it was selected from the TLB always again ...
898
0
    rTreeView.unselect_all();
899
0
    rTreeView.freeze();
900
901
0
    m_RedlineParents.erase(m_RedlineParents.begin() + nStart, m_RedlineParents.begin() + nEnd + 1);
902
0
}
903
904
void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedlineTable::size_type nEnd)
905
0
{
906
0
    SwView *pView = ::GetActiveView();
907
0
    if (!pView)
908
0
        return;
909
910
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
911
0
    if (!pSh)
912
0
        return;
913
914
0
    bool bHasRedlineAutoFormat = HasRedlineAutoFormat();
915
916
0
    SwRedlineTable::size_type nCount = pSh->GetRedlineCount();
917
0
    nEnd = std::min(nEnd, (nCount - 1)); // also treats nEnd=SwRedlineTable::npos (until the end)
918
919
    // reset m_bHasTrackedColumn before searching tracked column again
920
0
    if ( m_bHasTrackedColumn && nStart == 0 )
921
0
        m_bHasTrackedColumn = false;
922
923
0
    if (nEnd == SwRedlineTable::npos)
924
0
        return;     // no redlines in the document
925
926
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
927
928
0
    SwRedlineDataParent* pRedlineParent;
929
930
0
    rTreeView.freeze();
931
0
    if (m_pTable->IsSorted())
932
0
        rTreeView.make_unsorted();
933
934
0
    bool bIsShowChangesInMargin = SwModule::get()->GetUsrPref(false)->IsShowChangesInMargin();
935
936
    // collect redlines of tracked table/row/column insertion/deletions under a single tree list
937
    // item to accept/reject the table change with a single click on Accept/Reject
938
    // Note: because update of the tree list depends on parent count, we don't modify
939
    // m_RedlineParents, only store the 2nd and more redlines as children of the tree list
940
    // item of the first redline
941
942
    // count of items stored as children (to adjust parent position)
943
0
    SwRedlineTable::size_type nSkipRedlines = 0;
944
    // count of items of the actual table change stored as children =
945
    // redlines of the change - 1 (first redline is associated to the parent tree list item)
946
0
    SwRedlineTable::size_type nSkipRedline = 0;
947
948
    // descriptor redline of the tracked table row/column
949
0
    SwRedlineTable::size_type nRowChange = 0;
950
951
    // first redlines of the tracked table rows/columns, base of the parent tree lists
952
    // of the other SwRangeRedlines of the tracked table rows or columns
953
0
    std::vector<SwRedlineTable::size_type> aTableParents;
954
955
    // show all redlines as tree list items,
956
    // redlines of a tracked table (row) insertion/deletion showed as children of a single parent
957
0
    for (SwRedlineTable::size_type i = nStart; i <= nEnd; i++)
958
0
    {
959
0
        const SwRangeRedline& rRedln = pSh->GetRedline(i);
960
0
        const SwRedlineData *pRedlineData = &rRedln.GetRedlineData();
961
        // redline is a child associated to this table row/column change
962
0
        SwRedlineTable::size_type nTableParent = SwRedlineTable::npos;
963
964
0
        pRedlineParent = new SwRedlineDataParent;
965
0
        pRedlineParent->pData    = pRedlineData;
966
0
        pRedlineParent->pNext    = nullptr;
967
968
        // handle tracked table row changes
969
0
        const SwTableBox* pTableBox;
970
0
        const SwTableLine* pTableLine;
971
0
        bool bChange = false;
972
0
        bool bRowChange = false;
973
0
        if ( // not recognized yet as tracked table row change
974
0
             nullptr != ( pTableBox = pSh->GetRedline(i).Start()->GetNode().GetTableBox() ) &&
975
0
             nullptr != ( pTableLine = pTableBox->GetUpper() ) &&
976
             // it's a tracked row (or column change) based on the cached row data
977
0
             ( RedlineType::None != pTableLine->GetRedlineType() ||
978
0
               RedlineType::None != pTableBox->GetRedlineType() ) )
979
0
        {
980
            // start redline search from the start from the tracked row/column change
981
0
            SwRedlineTable::size_type nStartPos =
982
0
                                        nRowChange > nSkipRedline ? nRowChange - nSkipRedline : 0;
983
0
            bChange = true;
984
0
            bRowChange = RedlineType::None != pTableLine->GetRedlineType();
985
0
            nRowChange = bRowChange
986
0
                            ? pTableLine->UpdateTextChangesOnly(nStartPos)
987
0
                            : pTableBox->GetRedline();
988
            // redline is there in a tracked table change
989
0
            if ( SwRedlineTable::npos != nRowChange )
990
0
            {
991
                // join the consecutive deleted/inserted rows/columns under a single treebox item,
992
                // if they have the same redline data (equal type, author and time stamp)
993
0
                for (size_t j = 0; j < aTableParents.size(); j++)
994
0
                {
995
                    // note: CanCombine() allows a time frame to join the changes within a short
996
                    // time period: this avoid of falling apart of the tracked columns inserted
997
                    // by several clicks
998
0
                    if ( pSh->GetRedline(nRowChange).GetRedlineData()
999
0
                             .CanCombine(pSh->GetRedline(aTableParents[j]).GetRedlineData()) )
1000
0
                    {
1001
0
                        nSkipRedline++;
1002
0
                        nTableParent = aTableParents[j];
1003
0
                        break;
1004
0
                    }
1005
1006
0
                }
1007
1008
0
                if ( SwRedlineTable::npos == nTableParent )
1009
0
                {
1010
                    // table redline didn't fit in the stored ones, create new parent
1011
0
                    aTableParents.push_back(i);
1012
0
                }
1013
1014
                // it needs major tree update later because of tracked table columns
1015
0
                if ( !m_bHasTrackedColumn && !bRowChange )
1016
0
                {
1017
0
                    m_bHasTrackedColumn = true;
1018
0
                }
1019
0
            }
1020
0
            else
1021
0
            {
1022
                // redline is not in a tracked table change
1023
0
                bChange = bRowChange = false;
1024
0
            }
1025
0
        }
1026
1027
        // empty parent cache for the last table
1028
0
        if ( !pTableBox )
1029
0
        {
1030
0
            aTableParents.clear();
1031
0
        }
1032
1033
0
        bool bShowDeletedTextAsComment = bIsShowChangesInMargin &&
1034
0
                RedlineType::Delete == rRedln.GetType() && rRedln.GetComment().isEmpty();
1035
0
        const OUString sComment = bShowDeletedTextAsComment
1036
0
                    ? rRedln.GetDescr()
1037
0
                    : rRedln.GetComment();
1038
0
        pRedlineParent->sComment = sComment.replace('\n', ' ');
1039
0
        m_RedlineParents.insert(m_RedlineParents.begin() + i,
1040
0
                std::unique_ptr<SwRedlineDataParent>(pRedlineParent));
1041
1042
0
        std::unique_ptr<RedlineData> pData(new RedlineData);
1043
0
        pData->pData = pRedlineParent;
1044
0
        pData->bDisabled = false;
1045
1046
        // use descriptor SwRangeRedline of the changed row, if needed to show
1047
        // the correct redline type, author and time stamp of the tracked row change
1048
0
        const SwRangeRedline& rChangeRedln = pSh->GetRedline(bChange ? nRowChange : i);
1049
1050
0
        OUString sImage = GetActionImage(rChangeRedln, 0, bChange && aTableParents.back() == i, bRowChange );
1051
0
        OUString sAuthor = rChangeRedln.GetAuthorString(0);
1052
0
        pData->aDateTime = rChangeRedln.GetTimeStamp(0);
1053
0
        pData->eType = rChangeRedln.GetType(0);
1054
0
        OUString sDateEntry = GetAppLangDateTimeString(pData->aDateTime);
1055
1056
0
        OUString sId = weld::toId(pData.get());
1057
0
        std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator());
1058
1059
0
        if ( !bChange || aTableParents.back() == i )
1060
0
        {
1061
0
            const int nPos = std::min(int(i - nSkipRedlines), rTreeView.n_children());
1062
0
            rTreeView.insert(nullptr, nPos, nullptr, &sId, nullptr, nullptr, false, xParent.get());
1063
            // before this was a tracked table change with more than a single redline
1064
0
            if ( nSkipRedline > 0 )
1065
0
            {
1066
0
                nSkipRedlines += nSkipRedline;
1067
0
                nSkipRedline = 0;
1068
0
            }
1069
0
        }
1070
0
        else
1071
0
        {
1072
            // put 2nd or more redlines of deleted/inserted rows as children of their first redline
1073
0
            SwRedlineDataParent *const pParent = m_RedlineParents[nTableParent].get();
1074
0
            rTreeView.insert(pParent->xTLBParent.get(), -1, nullptr, &sId, nullptr, nullptr, false, xParent.get());
1075
0
        }
1076
1077
0
        m_RedlineData.push_back(std::move(pData));
1078
1079
0
        rTreeView.set_image(*xParent, sImage, -1);
1080
0
        rTreeView.set_text(*xParent, sAuthor, 1);
1081
0
        rTreeView.set_text(*xParent, sDateEntry, 2);
1082
0
        rTreeView.set_text(*xParent, sComment, 3);
1083
1084
0
        pRedlineParent->xTLBParent = std::move(xParent);
1085
1086
0
        InsertChildren(pRedlineParent, rRedln, bHasRedlineAutoFormat);
1087
0
    }
1088
0
    rTreeView.thaw();
1089
0
    if (m_pTable->IsSorted())
1090
0
        rTreeView.make_sorted();
1091
0
}
1092
1093
void SwRedlineAcceptDlg::CallAcceptReject( bool bSelect, bool bAccept )
1094
0
{
1095
0
    SwView *pView = ::GetActiveView();
1096
0
    if (!pView)
1097
0
        return;
1098
1099
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
1100
0
    if (!pSh)
1101
0
        return;
1102
1103
0
    int nPos = -1;
1104
1105
0
    typedef std::vector<std::unique_ptr<weld::TreeIter>> ListBoxEntries_t;
1106
0
    ListBoxEntries_t aRedlines;
1107
1108
    // don't activate
1109
0
    OSL_ENSURE( !m_bInhibitActivate,
1110
0
                "recursive call of CallAcceptReject?");
1111
0
    m_bInhibitActivate = true;
1112
1113
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
1114
1115
0
    auto lambda = [bSelect, &rTreeView, &nPos, &aRedlines](weld::TreeIter& rEntry) {
1116
0
        if (!rTreeView.get_iter_depth(rEntry))
1117
0
        {
1118
0
            if (bSelect && nPos == -1)
1119
0
                nPos = rTreeView.get_iter_index_in_parent(rEntry);
1120
1121
0
            RedlineData* pData = weld::fromId<RedlineData*>(rTreeView.get_id(rEntry));
1122
1123
0
            if (!pData->bDisabled)
1124
0
                aRedlines.emplace_back(rTreeView.make_iterator(&rEntry));
1125
0
        }
1126
0
        return false;
1127
0
    };
1128
1129
    // collect redlines-to-be-accepted/rejected in aRedlines vector
1130
0
    if (bSelect)
1131
0
        rTreeView.selected_foreach(lambda);
1132
0
    else
1133
0
        rTreeView.all_foreach(lambda);
1134
1135
0
    bool (SwEditShell::*FnAccRej)( SwRedlineTable::size_type, bool ) = &SwEditShell::AcceptRedline;
1136
0
    if( !bAccept )
1137
0
        FnAccRej = &SwEditShell::RejectRedline;
1138
1139
0
    SwWait aWait( *pSh->GetView().GetDocShell(), true );
1140
0
    pSh->StartAction();
1141
1142
0
    bool bMoreRedlines( aRedlines.size() > 1 ||
1143
        // single item with children, e.g. multiple redlines of a table or table row deletion/insertion
1144
0
        ( aRedlines.size() == 1 && rTreeView.iter_n_children(*aRedlines[0]) > 0 ) );
1145
1146
    // don't add extra Undo label to a single item only with redline stack (i.e. old changes
1147
    // on the same text range, stored only in OOXML)
1148
0
    if ( bMoreRedlines && aRedlines.size() == 1 )
1149
0
    {
1150
0
        std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*aRedlines[0] ));
1151
0
        RedlineData* pData = weld::fromId<RedlineData*>(rTreeView.get_id(*xChild));
1152
0
        if ( pData->bDisabled )
1153
0
            bMoreRedlines = false;
1154
0
    }
1155
1156
0
    if ( bMoreRedlines )
1157
0
    {
1158
0
        OUString aTmpStr;
1159
0
        {
1160
0
            SwRewriter aRewriter;
1161
0
            aRewriter.AddRule(UndoArg1,
1162
0
                              OUString::number(aRedlines.size()));
1163
0
            aTmpStr = aRewriter.Apply(SwResId(STR_N_REDLINES));
1164
0
        }
1165
1166
0
        SwRewriter aRewriter;
1167
0
        aRewriter.AddRule(UndoArg1, aTmpStr);
1168
1169
0
        pSh->StartUndo(bAccept? SwUndoId::ACCEPT_REDLINE : SwUndoId::REJECT_REDLINE,
1170
0
                       &aRewriter);
1171
0
    }
1172
1173
    // accept/reject the redlines in aRedlines. The absolute
1174
    // position may change during the process (e.g. when two redlines
1175
    // are merged in result of another one being deleted), so the
1176
    // position must be resolved late and checked before using it.
1177
    // (cf #102547#)
1178
0
    for (const auto& rRedLine : aRedlines)
1179
0
    {
1180
0
        SwRedlineTable::size_type nPosition = GetRedlinePos( *rRedLine );
1181
1182
        // bSelect is false for "accept/reject all", true when only accepting/rejecting one or more
1183
        // selected changes. Only use direct accept/reject for explicitly selected changes.
1184
0
        bool bDirect = bSelect;
1185
1186
0
        if( nPosition != SwRedlineTable::npos )
1187
0
            (pSh->*FnAccRej)( nPosition, bDirect );
1188
1189
        // handle redlines of table rows, stored as children of the item associated
1190
        // to the deleted/inserted table row(s)
1191
0
        std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*rRedLine ));
1192
0
        if ( rTreeView.iter_children(*xChild) )
1193
0
        {
1194
0
            RedlineData* pData = weld::fromId<RedlineData*>(rTreeView.get_id(*xChild));
1195
            // disabled for redline stack, but not for redlines of table rows
1196
0
            if ( !pData->bDisabled )
1197
0
            {
1198
0
                do
1199
0
                {
1200
0
                    nPosition = GetRedlinePos( *xChild );
1201
0
                    if( nPosition != SwRedlineTable::npos )
1202
0
                        (pSh->*FnAccRej)( nPosition, bDirect );
1203
0
                }
1204
0
                while ( rTreeView.iter_next_sibling(*xChild) );
1205
0
            }
1206
0
        }
1207
0
    }
1208
1209
0
    if ( bMoreRedlines )
1210
0
    {
1211
0
        pSh->EndUndo();
1212
0
    }
1213
1214
0
    pSh->EndAction();
1215
1216
0
    m_bInhibitActivate = false;
1217
0
    Activate();
1218
1219
0
    if (nPos != -1 && rTreeView.n_children())
1220
0
    {
1221
0
        if (nPos >= rTreeView.n_children())
1222
0
            nPos = rTreeView.n_children() - 1;
1223
0
        rTreeView.select(nPos);
1224
0
        rTreeView.scroll_to_row(nPos);
1225
0
        rTreeView.set_cursor(nPos);
1226
0
        SelectHdl(rTreeView);
1227
0
    }
1228
0
    m_rTPView.EnableUndo();
1229
0
}
1230
1231
SwRedlineTable::size_type SwRedlineAcceptDlg::GetRedlinePos(const weld::TreeIter& rEntry)
1232
0
{
1233
0
    SwView* pView = GetActiveView();
1234
0
    if (!pView)
1235
0
        return SwRedlineTable::npos;
1236
1237
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
1238
0
    if (!pSh)
1239
0
        return SwRedlineTable::npos;
1240
1241
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
1242
0
    return pSh->FindRedlineOfData( *static_cast<SwRedlineDataParent*>(weld::fromId<RedlineData*>(
1243
0
                                    rTreeView.get_id(rEntry))->pData)->pData );
1244
0
}
1245
1246
IMPL_LINK_NOARG(SwRedlineAcceptDlg, SortByComboBoxChangedHdl, SvxTPView*, void)
1247
0
{
1248
0
    SwView* pView = GetActiveView();
1249
0
    if (!pView)
1250
0
        return;
1251
0
    SwWait aWait(*pView->GetDocShell(), false);
1252
0
    auto nSortMode = m_rTPView.GetSortByComboBoxControl()->get_active();
1253
0
    if (nSortMode == 4)
1254
0
        nSortMode = -1;
1255
0
    m_pTable->HeaderBarClick(nSortMode);
1256
0
    if (nSortMode == -1)
1257
0
        Init();
1258
0
}
1259
1260
IMPL_LINK_NOARG(SwRedlineAcceptDlg, AcceptHdl, SvxTPView*, void)
1261
0
{
1262
0
    CallAcceptReject( true, true );
1263
0
}
1264
1265
IMPL_LINK_NOARG(SwRedlineAcceptDlg, AcceptAllHdl, SvxTPView*, void)
1266
0
{
1267
0
    CallAcceptReject( false, true );
1268
0
}
1269
1270
IMPL_LINK_NOARG(SwRedlineAcceptDlg, RejectHdl, SvxTPView*, void)
1271
0
{
1272
0
    CallAcceptReject( true, false );
1273
0
}
1274
1275
IMPL_LINK_NOARG(SwRedlineAcceptDlg, RejectAllHdl, SvxTPView*, void)
1276
0
{
1277
0
    CallAcceptReject( false, false );
1278
0
}
1279
1280
IMPL_LINK_NOARG(SwRedlineAcceptDlg, UndoHdl, SvxTPView*, void)
1281
0
{
1282
0
    if (SwView* pView = GetActiveView())
1283
0
    {
1284
0
        pView->GetViewFrame().GetDispatcher()->
1285
0
                    Execute(SID_UNDO, SfxCallMode::SYNCHRON);
1286
0
        const SfxPoolItemHolder aResult(pView->GetSlotState(SID_UNDO));
1287
0
        m_rTPView.EnableUndo(aResult.is());
1288
0
    }
1289
1290
0
    Activate();
1291
0
}
1292
1293
IMPL_LINK_NOARG(SwRedlineAcceptDlg, FilterChangedHdl, SvxTPFilter*, void)
1294
0
{
1295
0
    SvxTPFilter *pFilterTP = m_xTabPagesCTRL->GetFilterPage();
1296
1297
0
    if (pFilterTP->IsAction())
1298
0
        m_sFilterAction = pFilterTP->GetLbAction()->get_active_text();
1299
0
    else
1300
0
        m_sFilterAction.clear();
1301
1302
0
    Init();
1303
0
}
1304
1305
IMPL_LINK_NOARG(SwRedlineAcceptDlg, SelectHdl, weld::ItemView&, void)
1306
0
{
1307
0
    m_aSelectTimer.Start();
1308
0
}
1309
1310
IMPL_LINK_NOARG(SwRedlineAcceptDlg, GotoHdl, Timer *, void)
1311
0
{
1312
0
    m_aSelectTimer.Stop();
1313
1314
0
    SwView* pView = GetActiveView();
1315
0
    if (!pView)
1316
0
        return;
1317
1318
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
1319
0
    if (!pSh)
1320
0
        return;
1321
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
1325
    //         may the focus.
1326
0
    if (!m_xParentDlg || m_xParentDlg->has_toplevel_focus())
1327
0
    {
1328
0
        weld::TreeView& rTreeView = m_pTable->GetWidget();
1329
0
        if (std::unique_ptr<weld::TreeIter> xActEntry = rTreeView.get_selected())
1330
0
        {
1331
0
            pSh->StartAction();
1332
0
            pSh->EnterStdMode();
1333
0
            SwViewShell::SetCareDialog(m_xParentDlg);
1334
1335
0
            rTreeView.selected_foreach([this, pSh, &rTreeView, &xActEntry](weld::TreeIter& rEntry){
1336
0
                rTreeView.copy_iterator(rEntry, *xActEntry);
1337
0
                if (rTreeView.get_iter_depth(rEntry))
1338
0
                {
1339
0
                    rTreeView.iter_parent(*xActEntry);
1340
0
                    if (rTreeView.is_selected(*xActEntry))
1341
0
                        return false;   // don't select twice
1342
0
                }
1343
1344
                // #98864# find the selected redline (ignore, if the redline is already gone)
1345
0
                SwRedlineTable::size_type nPos = GetRedlinePos(*xActEntry);
1346
0
                if (nPos != SwRedlineTable::npos)
1347
0
                {
1348
0
                    if (pSh->GotoRedline(nPos, true))
1349
0
                    {
1350
0
                        pSh->SetInSelect();
1351
0
                        pSh->EnterAddMode();
1352
0
                    }
1353
0
                }
1354
1355
                // select all redlines of tracked table rows
1356
0
                std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator( &*xActEntry ));
1357
0
                if ( rTreeView.iter_children(*xChild) )
1358
0
                {
1359
0
                    RedlineData *pData = reinterpret_cast<RedlineData*>(rTreeView.get_id(*xChild).toInt64());
1360
                    // disabled for redline stack, but not for redlines of table rows
1361
0
                    if ( !pData->bDisabled )
1362
0
                    {
1363
0
                        do
1364
0
                        {
1365
0
                            nPos = GetRedlinePos(*xChild);
1366
0
                            if (nPos != SwRedlineTable::npos)
1367
0
                            {
1368
0
                                if (pSh->GotoRedline(nPos, true))
1369
0
                                {
1370
0
                                    pSh->SetInSelect();
1371
0
                                    pSh->EnterAddMode();
1372
0
                                }
1373
0
                            }
1374
0
                        }
1375
0
                        while ( rTreeView.iter_next_sibling(*xChild) );
1376
0
                    }
1377
0
                }
1378
0
                return false;
1379
0
            });
1380
1381
0
            pSh->LeaveAddMode();
1382
0
            pSh->EndAction();
1383
0
            SwViewShell::SetCareDialog(nullptr);
1384
0
        }
1385
0
    }
1386
1387
0
    EnableControls(pView);
1388
0
}
1389
1390
IMPL_LINK(SwRedlineAcceptDlg, CommandHdl, const CommandEvent&, rCEvt, bool)
1391
0
{
1392
0
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1393
0
        return false;
1394
1395
0
    SwView* pView = GetActiveView();
1396
0
    if (!pView)
1397
0
        return false;
1398
1399
0
    SwWrtShell* pSh = pView->GetWrtShellPtr();
1400
0
    if (!pSh)
1401
0
        return false;
1402
1403
0
    const SwRangeRedline *pRed = nullptr;
1404
1405
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
1406
0
    std::unique_ptr<weld::TreeIter> xEntry = rTreeView.get_selected();
1407
0
    if (xEntry)
1408
0
    {
1409
0
        std::unique_ptr<weld::TreeIter> xTopEntry(rTreeView.make_iterator(xEntry.get()));
1410
1411
0
        if (rTreeView.get_iter_depth(*xTopEntry))
1412
0
            rTreeView.iter_parent(*xTopEntry);
1413
1414
0
        SwRedlineTable::size_type nPos = GetRedlinePos(*xTopEntry);
1415
1416
        // disable commenting for protected areas
1417
0
        if (nPos != SwRedlineTable::npos && (pRed = pSh->GotoRedline(nPos, true)) != nullptr)
1418
0
        {
1419
0
            if( pSh->IsCursorPtAtEnd() )
1420
0
                pSh->SwapPam();
1421
0
            pSh->SetInSelect();
1422
0
        }
1423
0
    }
1424
1425
0
    m_xPopup->set_sensitive(u"writeredit"_ustr, xEntry && pRed &&
1426
0
                                          !rTreeView.get_iter_depth(*xEntry) &&
1427
0
                                          rTreeView.count_selected_rows() == 1);
1428
0
    m_xPopup->set_sensitive(u"writersort"_ustr, rTreeView.n_children() != 0);
1429
0
    int nColumn = rTreeView.get_sort_column();
1430
0
    if (nColumn == -1)
1431
0
        nColumn = 4;
1432
0
    for (sal_Int32 i = 0; i < 5; ++i)
1433
0
        m_xSortMenu->set_active(u"writersort" + OUString::number(i), i == nColumn);
1434
1435
0
    OUString sCommand = m_xPopup->popup_at_rect(&rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
1436
1437
0
    if (sCommand == "writeredit")
1438
0
    {
1439
0
        if (xEntry)
1440
0
        {
1441
0
            if (rTreeView.get_iter_depth(*xEntry))
1442
0
                rTreeView.iter_parent(*xEntry);
1443
1444
0
            SwRedlineTable::size_type nPos = GetRedlinePos(*xEntry);
1445
1446
0
            if (nPos == SwRedlineTable::npos)
1447
0
                return true;
1448
1449
0
            const SwRangeRedline &rRedline = pSh->GetRedline(nPos);
1450
1451
0
            OUString sComment = convertLineEnd(rRedline.GetComment(), GetSystemLineEnd());
1452
0
            SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1453
0
            ::DialogGetRanges fnGetRange = pFact->GetDialogGetRangesFunc();
1454
0
            SfxItemSet aSet( pSh->GetAttrPool(), fnGetRange() );
1455
1456
0
            aSet.Put(SvxPostItTextItem(sComment, SID_ATTR_POSTIT_TEXT));
1457
0
            aSet.Put(SvxPostItAuthorItem(rRedline.GetAuthorString(), SID_ATTR_POSTIT_AUTHOR));
1458
1459
0
            aSet.Put(SvxPostItDateItem( GetAppLangDateTimeString(
1460
0
                        rRedline.GetRedlineData().GetTimeStamp() ),
1461
0
                        SID_ATTR_POSTIT_DATE ));
1462
1463
0
            ScopedVclPtr<AbstractSvxPostItDialog> pDlg(pFact->CreateSvxPostItDialog(&rTreeView, aSet));
1464
1465
0
            pDlg->HideAuthor();
1466
1467
0
            TranslateId pResId;
1468
0
            switch( rRedline.GetType() )
1469
0
            {
1470
0
                case RedlineType::Insert:
1471
0
                    pResId = STR_REDLINE_INSERTED;
1472
0
                    break;
1473
0
                case RedlineType::Delete:
1474
0
                    pResId = STR_REDLINE_DELETED;
1475
0
                    break;
1476
0
                case RedlineType::Format:
1477
0
                case RedlineType::ParagraphFormat:
1478
0
                    pResId = STR_REDLINE_FORMATTED;
1479
0
                    break;
1480
0
                case RedlineType::Table:
1481
0
                    pResId = STR_REDLINE_TABLECHG;
1482
0
                    break;
1483
0
                default:;//prevent warning
1484
0
            }
1485
0
            OUString sTitle(SwResId(STR_REDLINE_COMMENT));
1486
0
            if (pResId)
1487
0
                sTitle += SwResId(pResId);
1488
0
            pDlg->SetText(sTitle);
1489
1490
0
            SwViewShell::SetCareDialog(pDlg->GetDialog());
1491
1492
0
            if ( pDlg->Execute() == RET_OK )
1493
0
            {
1494
0
                const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
1495
0
                OUString sMsg(pOutSet->Get(SID_ATTR_POSTIT_TEXT).GetValue());
1496
1497
                // insert / change comment
1498
0
                pSh->SetRedlineComment(sMsg);
1499
0
                rTreeView.set_text(*xEntry, sMsg.replace('\n', ' '), 3);
1500
0
            }
1501
1502
0
            SwViewShell::SetCareDialog(nullptr);
1503
0
            pDlg.disposeAndClear();
1504
0
        }
1505
0
    }
1506
0
    else if (!sCommand.isEmpty())
1507
0
    {
1508
0
        int nSortMode = o3tl::toInt32(sCommand.subView(10));
1509
1510
0
        if (nSortMode == 4 && nColumn == 4)
1511
0
            return true;  // we already have it
1512
1513
0
        m_rTPView.GetSortByComboBoxControl()->set_active(nSortMode);
1514
1515
0
        if (nSortMode == 4)
1516
0
            nSortMode = -1; // unsorted / sorted by position
1517
1518
0
        SwWait aWait( *pView->GetDocShell(), false );
1519
0
        m_pTable->HeaderBarClick(nSortMode);
1520
0
        if (nSortMode == -1)
1521
0
            Init();             // newly fill everything
1522
0
    }
1523
0
    return true;
1524
0
}
1525
1526
namespace
1527
{
1528
    OUString lcl_StripAcceptChgDat(OUString &rExtraString)
1529
0
    {
1530
0
        OUString aStr;
1531
0
        while(true)
1532
0
        {
1533
0
            sal_Int32 nPos = rExtraString.indexOf("AcceptChgDat:");
1534
0
            if (nPos == -1)
1535
0
                break;
1536
            // try to read the alignment string "ALIGN:(...)"; if none existing,
1537
            // it's an old version
1538
0
            sal_Int32 n1 = rExtraString.indexOf('(', nPos);
1539
0
            if (n1 != -1)
1540
0
            {
1541
0
                sal_Int32 n2 = rExtraString.indexOf(')', n1);
1542
0
                if (n2 != -1)
1543
0
                {
1544
                    // cut out the alignment string
1545
0
                    aStr = rExtraString.copy(nPos, n2 - nPos + 1);
1546
0
                    rExtraString = rExtraString.replaceAt(nPos, n2 - nPos + 1, u"");
1547
0
                    aStr = aStr.copy(n1 - nPos + 1);
1548
0
                }
1549
0
            }
1550
0
        }
1551
0
        return aStr;
1552
0
    }
1553
}
1554
1555
void SwRedlineAcceptDlg::Initialize(OUString& rExtraString)
1556
0
{
1557
0
    if (rExtraString.isEmpty())
1558
0
        return;
1559
1560
0
    OUString aStr = lcl_StripAcceptChgDat(rExtraString);
1561
0
    if (aStr.isEmpty())
1562
0
        return;
1563
1564
0
    int nCount = aStr.toInt32();
1565
0
    if (nCount <= 2)
1566
0
        return;
1567
1568
0
    std::vector<int> aEndPos;
1569
1570
0
    for (int i = 0; i < nCount; ++i)
1571
0
    {
1572
0
        sal_Int32 n1 = aStr.indexOf(';');
1573
0
        aStr = aStr.copy( n1+1 );
1574
0
        aEndPos.push_back(aStr.toInt32());
1575
0
    }
1576
1577
0
    bool bUseless = false;
1578
1579
0
    std::vector<int> aWidths;
1580
0
    for (int i = 1; i < nCount; ++i)
1581
0
    {
1582
0
        aWidths.push_back(aEndPos[i] - aEndPos[i - 1]);
1583
0
        if (aWidths.back() <= 0)
1584
0
            bUseless = true;
1585
0
    }
1586
1587
0
    if (!bUseless)
1588
0
    {
1589
        // turn column end points back to column widths, ignoring the small
1590
        // value used for the expander column
1591
0
        weld::TreeView& rTreeView = m_pTable->GetWidget();
1592
0
        rTreeView.set_column_fixed_widths(aWidths);
1593
0
    }
1594
0
}
1595
1596
void SwRedlineAcceptDlg::FillInfo(OUString &rExtraData) const
1597
0
{
1598
    //remove any old one before adding a new one
1599
0
    lcl_StripAcceptChgDat(rExtraData);
1600
0
    rExtraData += "AcceptChgDat:(";
1601
1602
0
    const int nTabCount = 4;
1603
1604
0
    rExtraData += OUString::number(nTabCount);
1605
0
    rExtraData += ";";
1606
1607
0
    weld::TreeView& rTreeView = m_pTable->GetWidget();
1608
0
    std::vector<int> aWidths;
1609
    // turn column widths back into column end points for compatibility
1610
    // with how they used to be stored, including a small value for the
1611
    // expander column
1612
0
    aWidths.push_back(rTreeView.get_checkbox_column_width());
1613
0
    for (int i = 0; i < nTabCount - 1; ++i)
1614
0
    {
1615
0
        int nWidth = rTreeView.get_column_width(i);
1616
0
        assert(nWidth > 0 && "suspicious to get a value like this");
1617
0
        aWidths.push_back(aWidths.back() + nWidth);
1618
0
    }
1619
1620
0
    for (auto a : aWidths)
1621
0
    {
1622
0
        rExtraData += OUString::number(a);
1623
0
        rExtraData += ";";
1624
0
    }
1625
0
    rExtraData += ")";
1626
0
}
1627
1628
SwRedlineAcceptPanel::SwRedlineAcceptPanel(weld::Widget* pParent)
1629
0
    : PanelLayout(pParent, u"ManageChangesPanel"_ustr, u"modules/swriter/ui/managechangessidebar.ui"_ustr)
1630
0
    , mxContentArea(m_xBuilder->weld_container(u"content_area"_ustr))
1631
0
{
1632
0
    mpImplDlg.reset(new SwRedlineAcceptDlg(nullptr, m_xBuilder.get(), mxContentArea.get()));
1633
1634
0
    mpImplDlg->Init();
1635
1636
    // we want to receive SfxHintId::DocChanged
1637
0
    StartListening(*(SwModule::get()->GetView()->GetDocShell()));
1638
0
}
1639
1640
SwRedlineAcceptPanel::~SwRedlineAcceptPanel()
1641
0
{
1642
0
}
1643
1644
void SwRedlineAcceptPanel::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1645
0
{
1646
0
    if (mpImplDlg && rHint.GetId() == SfxHintId::DocChanged)
1647
0
        mpImplDlg->Activate();
1648
0
}
1649
1650
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */