Coverage Report

Created: 2025-12-31 10:39

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