/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: */ |