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