tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / miscdlgs / conflictsdlg.cxx
blob524b887816da3dd1c14dfc73ef1a6ed698403d5a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <osl/diagnose.h>
23 #include <conflictsdlg.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <strings.hrc>
26 #include <scresid.hxx>
27 #include <viewdata.hxx>
28 #include <dbfunc.hxx>
29 #include <chgtrack.hxx>
31 // struct ScConflictsListEntry
33 bool ScConflictsListEntry::HasSharedAction( sal_uLong nSharedAction ) const
35 auto aEnd = maSharedActions.cend();
36 auto aItr = std::find(maSharedActions.cbegin(), aEnd, nSharedAction);
38 return aItr != aEnd;
41 bool ScConflictsListEntry::HasOwnAction( sal_uLong nOwnAction ) const
43 auto aEnd = maOwnActions.cend();
44 auto aItr = std::find(maOwnActions.cbegin(), aEnd, nOwnAction);
46 return aItr != aEnd;
50 bool ScConflictsListHelper::HasOwnAction( ScConflictsList& rConflictsList, sal_uLong nOwnAction )
52 return std::any_of(rConflictsList.begin(), rConflictsList.end(),
53 [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); });
56 ScConflictsListEntry* ScConflictsListHelper::GetSharedActionEntry( ScConflictsList& rConflictsList, sal_uLong nSharedAction )
58 auto aEnd = rConflictsList.end();
59 auto aItr = std::find_if(rConflictsList.begin(), aEnd,
60 [nSharedAction](ScConflictsListEntry& rConflict) { return rConflict.HasSharedAction( nSharedAction ); });
62 if (aItr != aEnd)
63 return &(*aItr);
65 return nullptr;
68 ScConflictsListEntry* ScConflictsListHelper::GetOwnActionEntry( ScConflictsList& rConflictsList, sal_uLong nOwnAction )
70 auto aEnd = rConflictsList.end();
71 auto aItr = std::find_if(rConflictsList.begin(), aEnd,
72 [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); });
74 if (aItr != aEnd)
75 return &(*aItr);
77 return nullptr;
80 void ScConflictsListHelper::Transform_Impl( std::vector<sal_uLong>& rActionList, ScChangeActionMergeMap* pMergeMap )
82 if ( !pMergeMap )
84 return;
87 for ( auto aItr = rActionList.begin(); aItr != rActionList.end(); )
89 ScChangeActionMergeMap::iterator aItrMap = pMergeMap->find( *aItr );
90 if ( aItrMap != pMergeMap->end() )
92 *aItr = aItrMap->second;
93 ++aItr;
95 else
97 aItr = rActionList.erase( aItr );
98 OSL_FAIL( "ScConflictsListHelper::Transform_Impl: erased action from conflicts list!" );
103 void ScConflictsListHelper::TransformConflictsList( ScConflictsList& rConflictsList,
104 ScChangeActionMergeMap* pSharedMap, ScChangeActionMergeMap* pOwnMap )
106 for ( auto& rConflictEntry : rConflictsList )
108 if ( pSharedMap )
110 ScConflictsListHelper::Transform_Impl( rConflictEntry.maSharedActions, pSharedMap );
113 if ( pOwnMap )
115 ScConflictsListHelper::Transform_Impl( rConflictEntry.maOwnActions, pOwnMap );
121 ScConflictsFinder::ScConflictsFinder( ScChangeTrack* pTrack, sal_uLong nStartShared, sal_uLong nEndShared,
122 sal_uLong nStartOwn, sal_uLong nEndOwn, ScConflictsList& rConflictsList )
123 :mpTrack( pTrack )
124 ,mnStartShared( nStartShared )
125 ,mnEndShared( nEndShared )
126 ,mnStartOwn( nStartOwn )
127 ,mnEndOwn( nEndOwn )
128 ,mrConflictsList( rConflictsList )
132 bool ScConflictsFinder::DoActionsIntersect( const ScChangeAction* pAction1, const ScChangeAction* pAction2 )
134 return pAction1 && pAction2 && pAction1->GetBigRange().Intersects( pAction2->GetBigRange() );
137 ScConflictsListEntry* ScConflictsFinder::GetIntersectingEntry( const ScChangeAction* pAction ) const
139 auto doActionsIntersect = [this, pAction](const sal_uLong& aAction) { return DoActionsIntersect( mpTrack->GetAction( aAction ), pAction ); };
141 for ( auto& rConflict : mrConflictsList )
143 if (std::any_of( rConflict.maSharedActions.cbegin(), rConflict.maSharedActions.cend(), doActionsIntersect ))
144 return &rConflict;
146 if (std::any_of( rConflict.maOwnActions.cbegin(), rConflict.maOwnActions.cend(), doActionsIntersect ))
147 return &rConflict;
150 return nullptr;
153 ScConflictsListEntry& ScConflictsFinder::GetEntry( sal_uLong nSharedAction, const std::vector<sal_uLong>& rOwnActions )
155 // try to get a list entry which already contains the shared action
156 ScConflictsListEntry* pEntry = ScConflictsListHelper::GetSharedActionEntry( mrConflictsList, nSharedAction );
157 if ( pEntry )
159 return *pEntry;
162 // try to get a list entry for which the shared action intersects with any
163 // other action of this entry
164 pEntry = GetIntersectingEntry( mpTrack->GetAction( nSharedAction ) );
165 if ( pEntry )
167 pEntry->maSharedActions.push_back( nSharedAction );
168 return *pEntry;
171 // try to get a list entry for which any of the own actions intersects with
172 // any other action of this entry
173 for ( auto& rOwnAction : rOwnActions )
175 pEntry = GetIntersectingEntry( mpTrack->GetAction( rOwnAction ) );
176 if ( pEntry )
178 pEntry->maSharedActions.push_back( nSharedAction );
179 return *pEntry;
183 // if no entry was found, create a new one
184 ScConflictsListEntry aEntry;
185 aEntry.meConflictAction = SC_CONFLICT_ACTION_NONE;
186 aEntry.maSharedActions.push_back( nSharedAction );
187 mrConflictsList.push_back( aEntry );
188 return mrConflictsList.back();
191 bool ScConflictsFinder::Find()
193 if ( !mpTrack )
195 return false;
198 bool bReturn = false;
199 ScChangeAction* pSharedAction = mpTrack->GetAction( mnStartShared );
200 while ( pSharedAction && pSharedAction->GetActionNumber() <= mnEndShared )
202 std::vector<sal_uLong> aOwnActions;
203 ScChangeAction* pOwnAction = mpTrack->GetAction( mnStartOwn );
204 while ( pOwnAction && pOwnAction->GetActionNumber() <= mnEndOwn )
206 if ( DoActionsIntersect( pSharedAction, pOwnAction ) )
208 aOwnActions.push_back( pOwnAction->GetActionNumber() );
210 pOwnAction = pOwnAction->GetNext();
213 if ( !aOwnActions.empty() )
215 ScConflictsListEntry& rEntry = GetEntry(pSharedAction->GetActionNumber(), aOwnActions);
216 for ( const auto& aOwnAction : aOwnActions )
218 if (!ScConflictsListHelper::HasOwnAction(mrConflictsList, aOwnAction))
220 rEntry.maOwnActions.push_back(aOwnAction);
223 bReturn = true;
226 pSharedAction = pSharedAction->GetNext();
229 return bReturn;
233 ScConflictsResolver::ScConflictsResolver( ScChangeTrack* pTrack, ScConflictsList& rConflictsList )
234 :mpTrack ( pTrack )
235 ,mrConflictsList ( rConflictsList )
237 OSL_ENSURE( mpTrack, "ScConflictsResolver CTOR: mpTrack is null!" );
240 void ScConflictsResolver::HandleAction( ScChangeAction* pAction, bool bIsSharedAction,
241 bool bHandleContentAction, bool bHandleNonContentAction )
243 if ( !mpTrack || !pAction )
245 return;
248 if ( bIsSharedAction )
250 ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetSharedActionEntry(
251 mrConflictsList, pAction->GetActionNumber() );
252 if ( pConflictEntry )
254 ScConflictAction eConflictAction = pConflictEntry->meConflictAction;
255 if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE )
257 if ( pAction->GetType() == SC_CAT_CONTENT )
259 if ( bHandleContentAction )
261 mpTrack->Reject( pAction );
264 else
266 if ( bHandleNonContentAction )
268 mpTrack->Reject( pAction );
274 else
276 ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetOwnActionEntry(
277 mrConflictsList, pAction->GetActionNumber() );
278 if ( pConflictEntry )
280 ScConflictAction eConflictAction = pConflictEntry->meConflictAction;
281 if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE )
283 if ( pAction->GetType() == SC_CAT_CONTENT )
285 if ( bHandleContentAction )
287 // do nothing
288 //mpTrack->SelectContent( pAction );
291 else
293 if ( bHandleNonContentAction )
295 // do nothing
296 //mpTrack->Accept( pAction );
300 else if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_OTHER )
302 if ( pAction->GetType() == SC_CAT_CONTENT )
304 if ( bHandleContentAction )
306 mpTrack->Reject( pAction );
309 else
311 if ( bHandleNonContentAction )
313 mpTrack->Reject( pAction );
322 ScConflictsDlg::ScConflictsDlg(weld::Window* pParent, ScViewData* pViewData, ScDocument* pSharedDoc, ScConflictsList& rConflictsList)
323 : GenericDialogController(pParent, u"modules/scalc/ui/conflictsdialog.ui"_ustr, u"ConflictsDialog"_ustr)
324 , maStrUnknownUser ( ScResId( STR_UNKNOWN_USER_CONFLICT ) )
325 , mpViewData ( pViewData )
326 , mpOwnDoc ( nullptr )
327 , mpOwnTrack ( nullptr )
328 , mpSharedDoc ( pSharedDoc )
329 , mpSharedTrack ( nullptr )
330 , mrConflictsList ( rConflictsList )
331 , maSelectionIdle ( "ScConflictsDlg maSelectionIdle" )
332 , mbInSelectHdl ( false )
333 , m_xBtnKeepMine(m_xBuilder->weld_button(u"keepmine"_ustr))
334 , m_xBtnKeepOther(m_xBuilder->weld_button(u"keepother"_ustr))
335 , m_xBtnKeepAllMine(m_xBuilder->weld_button(u"keepallmine"_ustr))
336 , m_xBtnKeepAllOthers(m_xBuilder->weld_button(u"keepallothers"_ustr))
337 , m_xLbConflicts(new SvxRedlinTable(m_xBuilder->weld_tree_view(u"container"_ustr), nullptr,
338 nullptr))
340 OSL_ENSURE( mpViewData, "ScConflictsDlg CTOR: mpViewData is null!" );
341 mpOwnDoc = ( mpViewData ? &mpViewData->GetDocument() : nullptr );
342 OSL_ENSURE( mpOwnDoc, "ScConflictsDlg CTOR: mpOwnDoc is null!" );
343 mpOwnTrack = ( mpOwnDoc ? mpOwnDoc->GetChangeTrack() : nullptr );
344 OSL_ENSURE( mpOwnTrack, "ScConflictsDlg CTOR: mpOwnTrack is null!" );
345 OSL_ENSURE( mpSharedDoc, "ScConflictsDlg CTOR: mpSharedDoc is null!" );
346 mpSharedTrack = ( mpSharedDoc ? mpSharedDoc->GetChangeTrack() : nullptr );
347 OSL_ENSURE( mpSharedTrack, "ScConflictsDlg CTOR: mpSharedTrack is null!" );
349 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
351 auto nDigitWidth = rTreeView.get_approximate_digit_width();
352 std::vector<int> aWidths
354 o3tl::narrowing<int>(nDigitWidth * 60),
355 o3tl::narrowing<int>(nDigitWidth * 20)
357 rTreeView.set_column_fixed_widths(aWidths);
359 rTreeView.set_selection_mode(SelectionMode::Multiple);
360 rTreeView.set_size_request(-1, rTreeView.get_height_rows(16));
362 maSelectionIdle.SetInvokeHandler( LINK( this, ScConflictsDlg, UpdateSelectionHdl ) );
364 rTreeView.connect_selection_changed(LINK(this, ScConflictsDlg, SelectHandle));
366 m_xBtnKeepMine->connect_clicked( LINK( this, ScConflictsDlg, KeepMineHandle ) );
367 m_xBtnKeepOther->connect_clicked( LINK( this, ScConflictsDlg, KeepOtherHandle ) );
368 m_xBtnKeepAllMine->connect_clicked( LINK( this, ScConflictsDlg, KeepAllMineHandle ) );
369 m_xBtnKeepAllOthers->connect_clicked( LINK( this, ScConflictsDlg, KeepAllOthersHandle ) );
371 UpdateView();
373 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
374 if (rTreeView.get_iter_first(*xEntry))
375 rTreeView.select(*xEntry);
378 ScConflictsDlg::~ScConflictsDlg()
382 OUString ScConflictsDlg::GetConflictString( const ScConflictsListEntry& rConflictEntry )
384 OUString aString;
385 if ( mpOwnTrack )
387 const ScChangeAction* pAction = mpOwnTrack->GetAction( rConflictEntry.maOwnActions[ 0 ] );
388 if ( pAction && mpOwnDoc )
390 SCTAB nTab = pAction->GetBigRange().MakeRange( *mpOwnDoc ).aStart.Tab();
391 mpOwnDoc->GetName( nTab, aString );
394 return aString;
397 void ScConflictsDlg::SetActionString(const ScChangeAction* pAction, ScDocument* pDoc, const weld::TreeIter& rEntry)
399 OSL_ENSURE( pAction, "ScConflictsDlg::GetActionString(): pAction is null!" );
400 OSL_ENSURE( pDoc, "ScConflictsDlg::GetActionString(): pDoc is null!" );
401 if (!pAction || !pDoc)
402 return;
404 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
405 OUString aDesc = pAction->GetDescription(*pDoc, true, false);
406 rTreeView.set_text(rEntry, aDesc, 0);
408 OUString aUser = comphelper::string::strip(pAction->GetUser(), ' ');
409 if ( aUser.isEmpty() )
411 aUser = maStrUnknownUser;
413 rTreeView.set_text(rEntry, aUser, 1);
415 DateTime aDateTime = pAction->GetDateTime();
416 OUString aString = ScGlobal::getLocaleData().getDate( aDateTime ) + " " +
417 ScGlobal::getLocaleData().getTime( aDateTime, false );
418 rTreeView.set_text(rEntry, aString, 2);
421 void ScConflictsDlg::HandleListBoxSelection()
423 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
424 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
425 bool bSelEntry = rTreeView.get_cursor(xEntry.get());
426 if (!bSelEntry)
427 bSelEntry = rTreeView.get_selected(xEntry.get());
428 if (!bSelEntry)
429 return;
431 bool bSelectHandle = rTreeView.is_selected(*xEntry);
433 while (rTreeView.get_iter_depth(*xEntry))
434 rTreeView.iter_parent(*xEntry);
436 if (bSelectHandle)
437 rTreeView.unselect_all();
438 if (!rTreeView.is_selected(*xEntry))
439 rTreeView.select(*xEntry);
440 if (rTreeView.iter_children(*xEntry))
444 if (!rTreeView.is_selected(*xEntry))
445 rTreeView.select(*xEntry);
446 } while (rTreeView.iter_next_sibling(*xEntry));
450 IMPL_LINK_NOARG(ScConflictsDlg, SelectHandle, weld::TreeView&, void)
452 if (mbInSelectHdl)
453 return;
455 mbInSelectHdl = true;
456 HandleListBoxSelection();
457 maSelectionIdle.Start();
458 mbInSelectHdl = false;
461 IMPL_LINK_NOARG(ScConflictsDlg, UpdateSelectionHdl, Timer *, void)
463 if ( !mpViewData || !mpOwnDoc )
465 return;
468 ScTabView* pTabView = mpViewData->GetView();
469 pTabView->DoneBlockMode();
471 std::vector<const ScChangeAction*> aActions;
473 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
474 rTreeView.selected_foreach([&rTreeView, &aActions](weld::TreeIter& rEntry){
475 if (rTreeView.get_iter_depth(rEntry))
477 RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rEntry));
478 if (pUserData)
480 ScChangeAction* pAction = static_cast< ScChangeAction* >( pUserData->pData );
481 if ( pAction && ( pAction->GetType() != SC_CAT_DELETE_TABS ) &&
482 ( pAction->IsClickable() || pAction->IsVisible() ) )
484 aActions.push_back(pAction);
488 return false;
491 bool bContMark = false;
492 for (size_t i = 0, nCount = aActions.size(); i < nCount; ++i)
494 const ScBigRange& rBigRange = aActions[i]->GetBigRange();
495 if (rBigRange.IsValid(*mpOwnDoc))
497 bool bSetCursor = i == nCount - 1;
498 pTabView->MarkRange(rBigRange.MakeRange( *mpOwnDoc ), bSetCursor, bContMark);
499 bContMark = true;
504 void ScConflictsDlg::SetConflictAction(const weld::TreeIter& rRootEntry, ScConflictAction eConflictAction)
506 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
507 RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rRootEntry));
508 ScConflictsListEntry* pConflictEntry = static_cast< ScConflictsListEntry* >( pUserData ? pUserData->pData : nullptr );
509 if ( pConflictEntry )
511 pConflictEntry->meConflictAction = eConflictAction;
515 void ScConflictsDlg::KeepHandler(bool bMine)
517 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
518 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
519 if (!rTreeView.get_selected(xEntry.get()))
520 return;
522 while (rTreeView.get_iter_depth(*xEntry))
523 rTreeView.iter_parent(*xEntry);
525 m_xDialog->set_busy_cursor(true);
526 ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER );
527 SetConflictAction(*xEntry, eConflictAction);
528 rTreeView.remove(*xEntry);
529 m_xDialog->set_busy_cursor(false);
530 if (rTreeView.n_children() == 0)
531 m_xDialog->response(RET_OK);
534 void ScConflictsDlg::KeepAllHandler( bool bMine )
536 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
537 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
538 if (!rTreeView.get_iter_first(*xEntry))
539 return;
541 while (rTreeView.get_iter_depth(*xEntry))
542 rTreeView.iter_parent(*xEntry);
544 m_xDialog->set_busy_cursor(true);
546 ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER );
549 SetConflictAction(*xEntry, eConflictAction);
550 } while (rTreeView.iter_next_sibling(*xEntry));
552 rTreeView.freeze();
553 rTreeView.clear();
554 rTreeView.thaw();
556 m_xDialog->set_busy_cursor(false);
558 m_xDialog->response(RET_OK);
561 IMPL_LINK_NOARG(ScConflictsDlg, KeepMineHandle, weld::Button&, void)
563 KeepHandler( true );
566 IMPL_LINK_NOARG(ScConflictsDlg, KeepOtherHandle, weld::Button&, void)
568 KeepHandler( false );
571 IMPL_LINK_NOARG(ScConflictsDlg, KeepAllMineHandle, weld::Button&, void)
573 KeepAllHandler( true );
576 IMPL_LINK_NOARG(ScConflictsDlg, KeepAllOthersHandle, weld::Button&, void)
578 KeepAllHandler( false );
581 void ScConflictsDlg::UpdateView()
583 weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
584 for ( ScConflictsListEntry& rConflictEntry : mrConflictsList )
586 if (rConflictEntry.meConflictAction == SC_CONFLICT_ACTION_NONE)
588 std::unique_ptr<RedlinData> pRootUserData(new RedlinData());
589 pRootUserData->pData = static_cast<void*>(&rConflictEntry);
590 OUString sString(GetConflictString(rConflictEntry));
591 OUString sId(weld::toId(pRootUserData.release()));
592 std::unique_ptr<weld::TreeIter> xRootEntry(rTreeView.make_iterator());
593 std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
594 rTreeView.insert(nullptr, -1, &sString, &sId, nullptr, nullptr, false, xRootEntry.get());
596 for ( const auto& aSharedAction : rConflictEntry.maSharedActions )
598 ScChangeAction* pAction = mpSharedTrack ? mpSharedTrack->GetAction(aSharedAction) : nullptr;
599 if ( pAction )
601 // only display shared top content entries
602 if ( pAction->GetType() == SC_CAT_CONTENT )
604 ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent();
605 if ( pNextContent && rConflictEntry.HasSharedAction( pNextContent->GetActionNumber() ) )
607 continue;
611 rTreeView.insert(xRootEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get());
612 SetActionString(pAction, mpSharedDoc, *xEntry);
616 for ( const auto& aOwnAction : rConflictEntry.maOwnActions )
618 ScChangeAction* pAction = mpOwnTrack ? mpOwnTrack->GetAction(aOwnAction) : nullptr;
619 if ( pAction )
621 // only display own top content entries
622 if ( pAction->GetType() == SC_CAT_CONTENT )
624 ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent();
625 if ( pNextContent && rConflictEntry.HasOwnAction( pNextContent->GetActionNumber() ) )
627 continue;
631 std::unique_ptr<RedlinData> pUserData(new RedlinData());
632 pUserData->pData = static_cast< void* >( pAction );
633 OUString aId(weld::toId(pUserData.release()));
634 rTreeView.insert(xRootEntry.get(), -1, nullptr, &aId, nullptr, nullptr, false, xEntry.get());
635 SetActionString(pAction, mpOwnDoc, *xEntry);
639 rTreeView.expand_row(*xRootEntry);
644 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */