diff options
Diffstat (limited to 'sc/source/ui/miscdlgs/acredlin.cxx')
-rw-r--r-- | sc/source/ui/miscdlgs/acredlin.cxx | 1792 |
1 files changed, 1792 insertions, 0 deletions
diff --git a/sc/source/ui/miscdlgs/acredlin.cxx b/sc/source/ui/miscdlgs/acredlin.cxx new file mode 100644 index 000000000..87292fe06 --- /dev/null +++ b/sc/source/ui/miscdlgs/acredlin.cxx @@ -0,0 +1,1792 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svl/undo.hxx> +#include <unotools/textsearch.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/collatorwrapper.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/basedlgs.hxx> +#include <vcl/commandevent.hxx> +#include <o3tl/string_view.hxx> + +#include <acredlin.hxx> +#include <global.hxx> +#include <reffact.hxx> +#include <document.hxx> +#include <docsh.hxx> +#include <scresid.hxx> +#include <strings.hrc> +#include <scmod.hxx> +#include <tabvwsh.hxx> + +// defines ------------------------------------------------------------------- + +#define RD_SPECIAL_NONE 0 +#define RD_SPECIAL_CONTENT 1 +#define RD_SPECIAL_VISCONTENT 2 + + +ScRedlinData::ScRedlinData() +{ + nInfo=RD_SPECIAL_NONE; + nActionNo=0; + pData=nullptr; + bDisabled=false; + bIsRejectable=false; + bIsAcceptable=false; + nTable=SCTAB_MAX; + nCol=SCCOL_MAX; + nRow=SCROW_MAX; +} + +ScRedlinData::~ScRedlinData() +{ + nInfo=RD_SPECIAL_NONE; + nActionNo=0; + pData=nullptr; + bDisabled=false; + bIsRejectable=false; + bIsAcceptable=false; +} + + +ScAcceptChgDlg::ScAcceptChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScViewData* ptrViewData) + : SfxModelessDialogController(pB, pCW, pParent, + "svx/ui/acceptrejectchangesdialog.ui", "AcceptRejectChangesDialog") + , aSelectionIdle( "ScAcceptChgDlg aSelectionIdle" ) + , aReOpenIdle("ScAcceptChgDlg ReOpenIdle") + , pViewData( ptrViewData ) + , pDoc( &ptrViewData->GetDocument() ) + , aStrInsertCols(ScResId(STR_CHG_INSERT_COLS)) + , aStrInsertRows(ScResId(STR_CHG_INSERT_ROWS)) + , aStrInsertTabs(ScResId(STR_CHG_INSERT_TABS)) + , aStrDeleteCols(ScResId(STR_CHG_DELETE_COLS)) + , aStrDeleteRows(ScResId(STR_CHG_DELETE_ROWS)) + , aStrDeleteTabs(ScResId(STR_CHG_DELETE_TABS)) + , aStrMove(ScResId(STR_CHG_MOVE)) + , aStrContent(ScResId(STR_CHG_CONTENT)) + , aStrReject(ScResId(STR_CHG_REJECT)) + , aStrAllAccepted(ScResId(STR_CHG_ACCEPTED)) + , aStrAllRejected(ScResId(STR_CHG_REJECTED)) + , aStrNoEntry(ScResId(STR_CHG_NO_ENTRY)) + , aStrContentWithChild(ScResId(STR_CHG_CONTENT_WITH_CHILD)) + , aStrChildContent(ScResId(STR_CHG_CHILD_CONTENT)) + , aStrChildOrgContent(ScResId(STR_CHG_CHILD_ORGCONTENT)) + , aStrEmpty(ScResId(STR_CHG_EMPTY)) + , aUnknown("Unknown") + , bIgnoreMsg(false) + , bNoSelection(false) + , bHasFilterEntry(false) + , bUseColor(false) + , m_xContentArea(m_xDialog->weld_content_area()) + , m_xPopup(m_xBuilder->weld_menu("calcmenu")) + , m_xSortMenu(m_xBuilder->weld_menu("calcsortmenu")) +{ + m_xAcceptChgCtr.reset(new SvxAcceptChgCtr(m_xContentArea.get())); + nAcceptCount=0; + nRejectCount=0; + aReOpenIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, ReOpenTimerHdl )); + + pTPFilter = m_xAcceptChgCtr->GetFilterPage(); + pTPView = m_xAcceptChgCtr->GetViewPage(); + + // tdf#136062 Don't use "Reject/Clear formatting" instead of "Reject" buttons in Calc + pTPView->EnableClearFormat(false); + pTPView->EnableClearFormatAll(false); + + pTheView = pTPView->GetTableControl(); + pTheView->SetCalcView(); + aSelectionIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, UpdateSelectionHdl )); + + pTPFilter->SetReadyHdl(LINK( this, ScAcceptChgDlg, FilterHandle )); + pTPFilter->SetRefHdl(LINK( this, ScAcceptChgDlg, RefHandle )); + pTPFilter->HideRange(false); + pTPView->SetRejectClickHdl( LINK( this, ScAcceptChgDlg,RejectHandle)); + pTPView->SetAcceptClickHdl( LINK(this, ScAcceptChgDlg, AcceptHandle)); + pTPView->SetRejectAllClickHdl( LINK( this, ScAcceptChgDlg,RejectAllHandle)); + pTPView->SetAcceptAllClickHdl( LINK(this, ScAcceptChgDlg, AcceptAllHandle)); + + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.connect_expanding(LINK(this, ScAcceptChgDlg, ExpandingHandle)); + rTreeView.connect_changed(LINK(this, ScAcceptChgDlg, SelectHandle)); + rTreeView.connect_popup_menu(LINK(this, ScAcceptChgDlg, CommandHdl)); + rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){ + return ColCompareHdl(rLeft, rRight); + }); + rTreeView.set_selection_mode(SelectionMode::Multiple); + + Init(); + + UpdateView(); + + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xEntry)) + rTreeView.select(*xEntry); +} + +ScAcceptChgDlg::~ScAcceptChgDlg() +{ + ClearView(); + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if (pChanges) + { + Link<ScChangeTrack&,void> aLink; + pChanges->SetModifiedLink(aLink); + } +} + +void ScAcceptChgDlg::ReInit(ScViewData* ptrViewData) +{ + pViewData=ptrViewData; + if (pViewData) + pDoc = &ptrViewData->GetDocument(); + else + pDoc = nullptr; + + bNoSelection=false; + bIgnoreMsg=false; + nAcceptCount=0; + nRejectCount=0; + + // don't call Init here (switching between views), just set link below + // (dialog is just hidden, not deleted anymore, when switching views) + ClearView(); + UpdateView(); + + if ( pDoc ) + { + ScChangeTrack* pChanges = pDoc->GetChangeTrack(); + if ( pChanges ) + pChanges->SetModifiedLink( LINK( this, ScAcceptChgDlg, ChgTrackModHdl ) ); + } +} + +void ScAcceptChgDlg::Init() +{ + OSL_ENSURE( pViewData && pDoc, "ViewData or Document not found!" ); + + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if(pChanges!=nullptr) + { + pChanges->SetModifiedLink( LINK( this, ScAcceptChgDlg,ChgTrackModHdl)); + aChangeViewSet.SetTheAuthorToShow(pChanges->GetUser()); + pTPFilter->ClearAuthors(); + const std::set<OUString>& rUserColl = pChanges->GetUserCollection(); + for (const auto& rItem : rUserColl) + pTPFilter->InsertAuthor(rItem); + } + + ScChangeViewSettings* pViewSettings=pDoc->GetChangeViewSettings(); + if ( pViewSettings!=nullptr ) + aChangeViewSet = *pViewSettings; + // adjust TimeField for filter tabpage + aChangeViewSet.AdjustDateMode( *pDoc ); + + pTPFilter->CheckDate(aChangeViewSet.HasDate()); + + DateTime aEmpty(DateTime::EMPTY); + + DateTime aDateTime(aChangeViewSet.GetTheFirstDateTime()); + if (aDateTime != aEmpty) + { + pTPFilter->SetFirstDate(aDateTime); + pTPFilter->SetFirstTime(aDateTime); + } + aDateTime = aChangeViewSet.GetTheLastDateTime(); + if (aDateTime != aEmpty) + { + pTPFilter->SetLastDate(aDateTime); + pTPFilter->SetLastTime(aDateTime); + } + + pTPFilter->SetDateMode(static_cast<sal_uInt16>(aChangeViewSet.GetTheDateMode())); + pTPFilter->CheckComment(aChangeViewSet.HasComment()); + pTPFilter->SetComment(aChangeViewSet.GetTheComment()); + + pTPFilter->CheckAuthor(aChangeViewSet.HasAuthor()); + OUString aString=aChangeViewSet.GetTheAuthorToShow(); + if(!aString.isEmpty()) + { + pTPFilter->SelectAuthor(aString); + if(pTPFilter->GetSelectedAuthor()!=aString) + { + pTPFilter->InsertAuthor(aString); + pTPFilter->SelectAuthor(aString); + } + } + else + pTPFilter->SelectedAuthorPos(0); + + pTPFilter->CheckRange(aChangeViewSet.HasRange()); + + aRangeList=aChangeViewSet.GetTheRangeList(); + + if( !aChangeViewSet.GetTheRangeList().empty() ) + { + const ScRange & rRangeEntry = aChangeViewSet.GetTheRangeList().front(); + OUString aRefStr(rRangeEntry.Format(*pDoc, ScRefFlags::RANGE_ABS_3D)); + pTPFilter->SetRange(aRefStr); + } + + // init filter + if(!(pTPFilter->IsDate()||pTPFilter->IsRange()|| + pTPFilter->IsAuthor()||pTPFilter->IsComment())) + return; + + pTheView->SetFilterDate(pTPFilter->IsDate()); + pTheView->SetDateTimeMode(pTPFilter->GetDateMode()); + pTheView->SetFirstDate(pTPFilter->GetFirstDate()); + pTheView->SetLastDate(pTPFilter->GetLastDate()); + pTheView->SetFirstTime(pTPFilter->GetFirstTime()); + pTheView->SetLastTime(pTPFilter->GetLastTime()); + pTheView->SetFilterAuthor(pTPFilter->IsAuthor()); + pTheView->SetAuthor(pTPFilter->GetSelectedAuthor()); + + pTheView->SetFilterComment(pTPFilter->IsComment()); + + utl::SearchParam aSearchParam( pTPFilter->GetComment(), + utl::SearchParam::SearchType::Regexp,false ); + + pTheView->SetCommentParams(&aSearchParam); + + pTheView->UpdateFilterTest(); +} + +void ScAcceptChgDlg::ClearView() +{ + nAcceptCount=0; + nRejectCount=0; + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.all_foreach( + [&rTreeView](weld::TreeIter& rEntry) + { + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry)); + delete pEntryData; + return false; + }); + rTreeView.freeze(); + rTreeView.clear(); + rTreeView.thaw(); +} + +OUString* ScAcceptChgDlg::MakeTypeString(ScChangeActionType eType) +{ + OUString* pStr; + + switch(eType) + { + + case SC_CAT_INSERT_COLS: pStr=&aStrInsertCols;break; + case SC_CAT_INSERT_ROWS: pStr=&aStrInsertRows;break; + case SC_CAT_INSERT_TABS: pStr=&aStrInsertTabs;break; + case SC_CAT_DELETE_COLS: pStr=&aStrDeleteCols;break; + case SC_CAT_DELETE_ROWS: pStr=&aStrDeleteRows;break; + case SC_CAT_DELETE_TABS: pStr=&aStrDeleteTabs;break; + case SC_CAT_MOVE: pStr=&aStrMove;break; + case SC_CAT_CONTENT: pStr=&aStrContent;break; + case SC_CAT_REJECT: pStr=&aStrReject;break; + default: pStr=&aUnknown;break; + } + return pStr; +} + +bool ScAcceptChgDlg::IsValidAction(const ScChangeAction* pScChangeAction) +{ + if(pScChangeAction==nullptr) return false; + + bool bFlag = false; + + ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc); + OUString aUser=pScChangeAction->GetUser(); + DateTime aDateTime=pScChangeAction->GetDateTime(); + + ScChangeActionType eType=pScChangeAction->GetType(); + OUString aDesc; + + OUString aComment = pScChangeAction->GetComment().replaceAll("\n", ""); + + if(eType==SC_CAT_CONTENT) + { + if(!pScChangeAction->IsDialogParent()) + aDesc = pScChangeAction->GetDescription(*pDoc, true); + } + else + aDesc = pScChangeAction->GetDescription(*pDoc, !pScChangeAction->IsMasterDelete()); + + if (!aDesc.isEmpty()) + { + aComment += " (" + aDesc + ")"; + } + + if (pTheView->IsValidEntry(aUser, aDateTime, aComment)) + { + if(pTPFilter->IsRange()) + { + for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i ) + { + ScRange const & rRangeEntry = aRangeList[ i ]; + if (rRangeEntry.Intersects(aRef)) { + bFlag = true; + break; + } + } + } + else + bFlag=true; + } + + return bFlag; +} + +std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::AppendChangeAction( + const ScChangeAction* pScChangeAction, bool bCreateOnDemand, + const weld::TreeIter* pParent, bool bDelMaster, bool bDisabled) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr; + + bool bFlag = false; + + ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc); + DateTime aDateTime=pScChangeAction->GetDateTime(); + + ScChangeActionType eType=pScChangeAction->GetType(); + OUString aActionString; + OUString aRefStr; + OUString aUser; + OUString aDate; + OUString aDesc; + + std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData); + pNewData->pData=const_cast<ScChangeAction *>(pScChangeAction); + pNewData->nActionNo=pScChangeAction->GetActionNumber(); + pNewData->bIsAcceptable=pScChangeAction->IsClickable(); + pNewData->bIsRejectable=pScChangeAction->IsRejectable(); + pNewData->bDisabled=!pNewData->bIsAcceptable || bDisabled; + pNewData->aDateTime=aDateTime; + pNewData->nRow = aRef.aStart.Row(); + pNewData->nCol = aRef.aStart.Col(); + pNewData->nTable= aRef.aStart.Tab(); + + if(eType==SC_CAT_CONTENT) + { + if(pScChangeAction->IsDialogParent()) + { + aActionString = aStrContentWithChild; + pNewData->nInfo=RD_SPECIAL_VISCONTENT; + pNewData->bIsRejectable=false; + pNewData->bIsAcceptable=false; + } + else + { + aActionString = *MakeTypeString(eType); + aDesc = pScChangeAction->GetDescription(*pDoc, true); + } + } + else + { + aActionString = *MakeTypeString(eType); + + if(bDelMaster) + { + aDesc = pScChangeAction->GetDescription(*pDoc,true); + pNewData->bDisabled=true; + pNewData->bIsRejectable=false; + } + else + aDesc = pScChangeAction->GetDescription(*pDoc, !pScChangeAction->IsMasterDelete()); + + } + + aRefStr = pScChangeAction->GetRefString(*pDoc, true); + + bool bIsGenerated = false; + + if(!pChanges->IsGenerated(pScChangeAction->GetActionNumber())) + { + aUser = pScChangeAction->GetUser(); + aDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime); + bIsGenerated = false; + } + else + { + bIsGenerated = true; + } + + OUString aComment = pScChangeAction->GetComment().replaceAll("\n", ""); + + if (!aDesc.isEmpty()) + { + aComment += " (" + aDesc + ")"; + } + + if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated) + { + if (pTheView->IsValidComment(aComment)) + { + if(pTPFilter->IsRange()) + { + for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i ) + { + ScRange const & rRangeEntry = aRangeList[ i ]; + if( rRangeEntry.Intersects(aRef) ) + { + bHasFilterEntry=true; + bFlag=true; + break; + } + } + } + else if(!bIsGenerated) + { + bHasFilterEntry=true; + bFlag=true; + } + } + } + + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + OUString sId(weld::toId(pNewData.release())); + rTreeView.insert(pParent, -1, &aActionString, &sId, nullptr, nullptr, bCreateOnDemand, xEntry.get()); + rTreeView.set_text( *xEntry, aRefStr, 1); + if (!aUser.isEmpty()) + rTreeView.set_text( *xEntry, aUser, 2); + if (!aDate.isEmpty()) + rTreeView.set_text( *xEntry, aDate, 3); + if (!aComment.isEmpty()) + rTreeView.set_text( *xEntry, aComment, 4); + if (!bFlag && bUseColor && !pParent) + { + rTreeView.set_font_color(*xEntry, COL_LIGHTBLUE); + } + else if (bFlag && bUseColor && pParent) + { + rTreeView.set_font_color(*xEntry, COL_GREEN); + + std::unique_ptr<weld::TreeIter> xExpEntry(rTreeView.make_iterator(pParent)); + + while (!rTreeView.get_row_expanded(*xExpEntry)) + { + if (rTreeView.get_iter_depth(*xExpEntry)) + rTreeView.expand_row(*xExpEntry); + + if (!rTreeView.iter_parent(*xExpEntry)) + break; + } + } + return xEntry; +} + +std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::AppendFilteredAction( + const ScChangeAction* pScChangeAction, ScChangeActionState eState, + bool bCreateOnDemand, + const weld::TreeIter* pParent, bool bDelMaster, bool bDisabled) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr; + + bool bIsGenerated = pChanges->IsGenerated(pScChangeAction->GetActionNumber()); + + bool bFlag = false; + + ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc); + OUString aUser=pScChangeAction->GetUser(); + DateTime aDateTime=pScChangeAction->GetDateTime(); + + if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated) + { + if(pTPFilter->IsRange()) + { + for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i ) + { + ScRange const & rRangeEntry=aRangeList[ i ]; + if( rRangeEntry.Intersects(aRef) ) + { + if( pScChangeAction->GetState()==eState ) + bFlag = true; + break; + } + } + } + else if(pScChangeAction->GetState()==eState && !bIsGenerated) + bFlag = true; + } + + std::unique_ptr<weld::TreeIter> xEntry; + if(bFlag) + { + ScChangeActionType eType=pScChangeAction->GetType(); + OUString aActionString; + OUString aDesc; + + std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData); + pNewData->pData=const_cast<ScChangeAction *>(pScChangeAction); + pNewData->nActionNo=pScChangeAction->GetActionNumber(); + pNewData->bIsAcceptable=pScChangeAction->IsClickable(); + pNewData->bIsRejectable=pScChangeAction->IsRejectable(); + pNewData->bDisabled=!pNewData->bIsAcceptable || bDisabled; + pNewData->aDateTime=aDateTime; + pNewData->nRow = aRef.aStart.Row(); + pNewData->nCol = aRef.aStart.Col(); + pNewData->nTable= aRef.aStart.Tab(); + + if(eType==SC_CAT_CONTENT) + { + if(pScChangeAction->IsDialogParent()) + { + aActionString=aStrContentWithChild; + pNewData->nInfo=RD_SPECIAL_VISCONTENT; + pNewData->bIsRejectable=false; + pNewData->bIsAcceptable=false; + } + else + { + aActionString=*MakeTypeString(eType); + aDesc = pScChangeAction->GetDescription(*pDoc, true); + } + } + else + { + aActionString=*MakeTypeString(eType); + + if(bDelMaster) + { + aDesc = pScChangeAction->GetDescription(*pDoc,true); + pNewData->bDisabled=true; + pNewData->bIsRejectable=false; + } + else + aDesc = pScChangeAction->GetDescription(*pDoc,!pScChangeAction->IsMasterDelete()); + + } + + + OUString aComment = pScChangeAction->GetComment().replaceAll("\n", ""); + if (!aDesc.isEmpty()) + { + aComment += " (" + aDesc + ")"; + } + if (pTheView->IsValidComment(aComment)) + { + weld::TreeView& rTreeView = pTheView->GetWidget(); + xEntry = rTreeView.make_iterator(); + OUString sId(weld::toId(pNewData.release())); + rTreeView.insert(pParent, -1, &aActionString, &sId, nullptr, nullptr, bCreateOnDemand, xEntry.get()); + + OUString aRefStr = pScChangeAction->GetRefString(*pDoc, true); + rTreeView.set_text(*xEntry, aRefStr, 1); + + if (!bIsGenerated) + { + rTreeView.set_text(*xEntry, aUser, 2); + OUString sDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime); + rTreeView.set_text(*xEntry, sDate, 3); + } + + rTreeView.set_text(*xEntry, aComment, 4); + } + } + return xEntry; +} + +std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::InsertChangeActionContent(const ScChangeActionContent* pScChangeAction, + const weld::TreeIter& rParent, sal_uLong nSpecial) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr; + + bool bIsGenerated = pChanges->IsGenerated(pScChangeAction->GetActionNumber()); + + bool bFlag = false; + + ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc); + OUString aUser=pScChangeAction->GetUser(); + DateTime aDateTime=pScChangeAction->GetDateTime(); + + if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated) + { + if(pTPFilter->IsRange()) + { + for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i ) + { + ScRange const & rRangeEntry = aRangeList[ i ]; + if( rRangeEntry.Intersects(aRef) ) + { + bFlag=true; + break; + } + } + } + else if(!bIsGenerated) + bFlag=true; + } + + OUString aContent; + OUString aRefStr; + OUString aDate; + OUString aDesc; + + if(nSpecial==RD_SPECIAL_CONTENT) + { + aContent = pScChangeAction->GetOldString(pDoc); + if (aContent.isEmpty()) + aContent = aStrEmpty; + aDesc = aStrChildOrgContent + ": " + aContent; + } + else + { + const OUString aTmp( pScChangeAction->GetNewString(pDoc)); + if (aTmp.isEmpty()) + aContent = aStrEmpty; + else + aContent = "\'" + aTmp + "\'"; + aDesc = aStrChildContent + aContent; + } + + aRefStr = pScChangeAction->GetRefString(*pDoc, true); + + if(!bIsGenerated) + { + // aUser is kept. + aDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime); + } + else + { + aUser.clear(); + } + + OUString aComment = pScChangeAction->GetComment().replaceAll("\n", ""); + + if(!aDesc.isEmpty()) + { + aComment += " (" + aDesc + ")"; + } + + std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData); + pNewData->nInfo=nSpecial; + pNewData->pData=const_cast<ScChangeActionContent *>(pScChangeAction); + pNewData->nActionNo=pScChangeAction->GetActionNumber(); + pNewData->bIsAcceptable=pScChangeAction->IsClickable(); + pNewData->bIsRejectable=false; + pNewData->bDisabled=!pNewData->bIsAcceptable; + pNewData->aDateTime=aDateTime; + pNewData->nRow = aRef.aStart.Row(); + pNewData->nCol = aRef.aStart.Col(); + pNewData->nTable= aRef.aStart.Tab(); + + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + OUString sId(weld::toId(pNewData.release())); + rTreeView.insert(&rParent, -1, &aContent, &sId, nullptr, nullptr, false, xEntry.get()); + rTreeView.set_text( *xEntry, aRefStr, 1); + if (!aUser.isEmpty()) + rTreeView.set_text( *xEntry, aUser, 2); + if (!aDate.isEmpty()) + rTreeView.set_text( *xEntry, aDate, 3); + if (!aComment.isEmpty()) + rTreeView.set_text( *xEntry, aComment, 4); + if (pTheView->IsValidComment(aComment) && bFlag) + bHasFilterEntry=true; + else + { + rTreeView.set_font_color(*xEntry, COL_LIGHTBLUE); + } + return xEntry; +} + +void ScAcceptChgDlg::UpdateView() +{ + std::unique_ptr<weld::TreeIter> xParent; + ScChangeTrack* pChanges=nullptr; + const ScChangeAction* pScChangeAction=nullptr; + m_xDialog->set_busy_cursor(true); + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.freeze(); + bool bFilterFlag = pTPFilter->IsDate() || pTPFilter->IsRange() || + pTPFilter->IsAuthor() || pTPFilter->IsComment(); + + bUseColor = bFilterFlag; + + if(pDoc!=nullptr) + { + pChanges=pDoc->GetChangeTrack(); + if(pChanges!=nullptr) + pScChangeAction=pChanges->GetFirst(); + } + bool bTheFlag = false; + + while(pScChangeAction!=nullptr) + { + bHasFilterEntry=false; + switch (pScChangeAction->GetState()) + { + case SC_CAS_VIRGIN: + + if (pScChangeAction->IsDialogRoot()) + { + bool bOnDemandChildren = !bFilterFlag && pScChangeAction->IsDialogParent(); + if (pScChangeAction->IsDialogParent()) + xParent = AppendChangeAction(pScChangeAction, bOnDemandChildren); + else + xParent = AppendFilteredAction(pScChangeAction, SC_CAS_VIRGIN, bOnDemandChildren); + } + else + xParent.reset(); + + bTheFlag=true; + break; + + case SC_CAS_ACCEPTED: + xParent.reset(); + nAcceptCount++; + break; + + case SC_CAS_REJECTED: + xParent.reset(); + nRejectCount++; + break; + } + + if (xParent && pScChangeAction->IsDialogParent() && bFilterFlag) + { + bool bTestFlag = bHasFilterEntry; + bHasFilterEntry=false; + if (Expand(pChanges, pScChangeAction, *xParent, !bTestFlag) && !bTestFlag) + rTreeView.remove(*xParent); + } + + pScChangeAction=pScChangeAction->GetNext(); + } + + if( bTheFlag && (!pDoc->IsDocEditable() || pChanges->IsProtected()) ) + bTheFlag=false; + + pTPView->EnableAccept(bTheFlag); + pTPView->EnableAcceptAll(bTheFlag); + pTPView->EnableReject(bTheFlag); + pTPView->EnableRejectAll(bTheFlag); + + if (nAcceptCount>0) + rTreeView.insert(nullptr, -1, &aStrAllAccepted, nullptr, nullptr, nullptr, true, nullptr); + if (nRejectCount>0) + rTreeView.insert(nullptr, -1, &aStrAllRejected, nullptr, nullptr, nullptr, true, nullptr); + rTreeView.thaw(); + m_xDialog->set_busy_cursor(false); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xEntry)) + rTreeView.select(*xEntry); +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, RefHandle, SvxTPFilter*, void) +{ + sal_uInt16 nId =ScSimpleRefDlgWrapper::GetChildWindowId(); + + SC_MOD()->SetRefDialog( nId, true ); + + SfxViewFrame* pViewFrm = pViewData->GetViewShell()->GetViewFrame(); + ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId )); + + if(pWnd!=nullptr) + { + sal_uInt16 nAcceptId=ScAcceptChgDlgWrapper::GetChildWindowId(); + pViewFrm->ShowChildWindow(nAcceptId,false); + pWnd->SetCloseHdl(LINK( this, ScAcceptChgDlg,RefInfoHandle)); + pWnd->SetRefString(pTPFilter->GetRange()); + ScSimpleRefDlgWrapper::SetAutoReOpen(false); + auto xWin = pWnd->GetController(); + m_xDialog->hide(); + xWin->set_title(m_xDialog->get_title()); + pWnd->StartRefInput(); + } +} + +IMPL_LINK( ScAcceptChgDlg, RefInfoHandle, const OUString*, pResult, void) +{ + sal_uInt16 nId = ScAcceptChgDlgWrapper::GetChildWindowId(); + + ScSimpleRefDlgWrapper::SetAutoReOpen(true); + + SfxViewFrame* pViewFrm = pViewData->GetViewShell()->GetViewFrame(); + if (pResult) + { + pTPFilter->SetRange(*pResult); + FilterHandle(pTPFilter); + + pViewFrm->ShowChildWindow(nId); + } + else + { + pViewFrm->SetChildWindow(nId, false); + } +} + +IMPL_LINK( ScAcceptChgDlg, FilterHandle, SvxTPFilter*, pRef, void ) +{ + if(pRef!=nullptr) + { + ClearView(); + aRangeList.RemoveAll(); + aRangeList.Parse(pTPFilter->GetRange(), *pDoc); + UpdateView(); + } +} + +IMPL_LINK( ScAcceptChgDlg, RejectHandle, SvxTPView*, pRef, void ) +{ + m_xDialog->set_busy_cursor(true); + + bIgnoreMsg=true; + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + if(pRef!=nullptr) + { + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.selected_foreach([this, pChanges, &rTreeView](weld::TreeIter& rEntry){ + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry)); + if (pEntryData) + { + ScChangeAction* pScChangeAction= static_cast<ScChangeAction*>(pEntryData->pData); + if (pScChangeAction->GetType()==SC_CAT_INSERT_TABS) + pViewData->SetTabNo(0); + pChanges->Reject(pScChangeAction); + } + return false; + }); + ScDocShell* pDocSh=pViewData->GetDocShell(); + pDocSh->PostPaintExtras(); + pDocSh->PostPaintGridAll(); + pDocSh->GetUndoManager()->Clear(); + pDocSh->SetDocumentModified(); + ClearView(); + UpdateView(); + } + + m_xDialog->set_busy_cursor(false); + + bIgnoreMsg=false; +} +IMPL_LINK( ScAcceptChgDlg, AcceptHandle, SvxTPView*, pRef, void ) +{ + m_xDialog->set_busy_cursor(true); + + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + bIgnoreMsg=true; + if(pRef!=nullptr) + { + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.selected_foreach([pChanges, &rTreeView](weld::TreeIter& rEntry) { + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry)); + if (pEntryData) + { + ScChangeAction* pScChangeAction= + static_cast<ScChangeAction*>(pEntryData->pData); + if(pScChangeAction->GetType()==SC_CAT_CONTENT) + { + if(pEntryData->nInfo==RD_SPECIAL_CONTENT) + pChanges->SelectContent(pScChangeAction,true); + else + pChanges->SelectContent(pScChangeAction); + } + else + pChanges->Accept(pScChangeAction); + } + return false; + }); + ScDocShell* pDocSh=pViewData->GetDocShell(); + pDocSh->PostPaintExtras(); + pDocSh->PostPaintGridAll(); + pDocSh->SetDocumentModified(); + ClearView(); + UpdateView(); + } + m_xDialog->set_busy_cursor(false); + bIgnoreMsg=false; +} + +void ScAcceptChgDlg::RejectFiltered() +{ + if(pDoc==nullptr) return; + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + const ScChangeAction* pScChangeAction=nullptr; + + if(pChanges!=nullptr) + { + pScChangeAction=pChanges->GetLast(); + } + + while(pScChangeAction!=nullptr) + { + if(pScChangeAction->IsDialogRoot()) + if(IsValidAction(pScChangeAction)) + pChanges->Reject(const_cast<ScChangeAction*>(pScChangeAction)); + + pScChangeAction=pScChangeAction->GetPrev(); + } +} +void ScAcceptChgDlg::AcceptFiltered() +{ + if(pDoc==nullptr) return; + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + const ScChangeAction* pScChangeAction=nullptr; + + if(pChanges!=nullptr) + pScChangeAction=pChanges->GetLast(); + + while(pScChangeAction!=nullptr) + { + if(pScChangeAction->IsDialogRoot()) + if(IsValidAction(pScChangeAction)) + pChanges->Accept(const_cast<ScChangeAction*>(pScChangeAction)); + + pScChangeAction=pScChangeAction->GetPrev(); + } +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, RejectAllHandle, SvxTPView*, void) +{ + m_xDialog->set_busy_cursor(true); + bIgnoreMsg=true; + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + if(pChanges!=nullptr) + { + if(pTPFilter->IsDate()||pTPFilter->IsAuthor()||pTPFilter->IsRange()||pTPFilter->IsComment()) + RejectFiltered(); + else + pChanges->RejectAll(); + + pViewData->SetTabNo(0); + + ScDocShell* pDocSh=pViewData->GetDocShell(); + pDocSh->PostPaintExtras(); + pDocSh->PostPaintGridAll(); + pDocSh->GetUndoManager()->Clear(); + pDocSh->SetDocumentModified(); + ClearView(); + UpdateView(); + } + m_xDialog->set_busy_cursor(false); + + bIgnoreMsg=false; +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, AcceptAllHandle, SvxTPView*, void) +{ + m_xDialog->set_busy_cursor(true); + + bIgnoreMsg=true; + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + if(pChanges!=nullptr) + { + if(pTPFilter->IsDate()||pTPFilter->IsAuthor()||pTPFilter->IsRange()||pTPFilter->IsComment()) + AcceptFiltered(); + else + pChanges->AcceptAll(); + + ScDocShell* pDocSh=pViewData->GetDocShell(); + pDocSh->PostPaintExtras(); + pDocSh->PostPaintGridAll(); + pDocSh->SetDocumentModified(); + ClearView(); + UpdateView(); + } + bIgnoreMsg=false; + + m_xDialog->set_busy_cursor(false); +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, SelectHandle, weld::TreeView&, void) +{ + if (!bNoSelection) + aSelectionIdle.Start(); + + bNoSelection=false; +} + +void ScAcceptChgDlg::GetDependents(const ScChangeAction* pScChangeAction, + ScChangeActionMap& aActionMap, + const weld::TreeIter& rEntry) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry)); + if (rTreeView.iter_parent(*xParent)) + { + ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xParent)); + ScChangeAction* pParentAction=static_cast<ScChangeAction*>(pParentData->pData); + + if(pParentAction!=pScChangeAction) + pChanges->GetDependents(const_cast<ScChangeAction*>(pScChangeAction), + aActionMap,pScChangeAction->IsMasterDelete()); + else + pChanges->GetDependents( const_cast<ScChangeAction*>(pScChangeAction), + aActionMap ); + } + else + pChanges->GetDependents(const_cast<ScChangeAction*>(pScChangeAction), + aActionMap, pScChangeAction->IsMasterDelete() ); +} + +bool ScAcceptChgDlg::InsertContentChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent) +{ + bool bTheTestFlag = true; + weld::TreeView& rTreeView = pTheView->GetWidget(); + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rParent)); + const ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData); + bool bParentInserted = false; + // If the parent is a MatrixOrigin then place it in the right order before + // the MatrixReferences. Also if it is the first content change at this + // position don't insert the first dependent MatrixReference as the special + // content (original value) but insert the predecessor of the MatrixOrigin + // itself instead. + if ( pScChangeAction->GetType() == SC_CAT_CONTENT && + static_cast<const ScChangeActionContent*>(pScChangeAction)->IsMatrixOrigin() ) + { + pActionMap->insert( ::std::make_pair( pScChangeAction->GetActionNumber(), + const_cast<ScChangeAction*>( pScChangeAction ) ) ); + bParentInserted = true; + } + + ScChangeActionMap::iterator itChangeAction = std::find_if(pActionMap->begin(), pActionMap->end(), + [](const std::pair<sal_uLong, ScChangeAction*>& rEntry) { return rEntry.second->GetState() == SC_CAS_VIRGIN; }); + + if( itChangeAction == pActionMap->end() ) + return true; + + std::unique_ptr<weld::TreeIter> xOriginal = InsertChangeActionContent( + dynamic_cast<const ScChangeActionContent*>( itChangeAction->second ), + rParent, RD_SPECIAL_CONTENT ); + + if (xOriginal) + { + bTheTestFlag=false; + ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xOriginal)); + pParentData->pData=const_cast<ScChangeAction *>(pScChangeAction); + pParentData->nActionNo=pScChangeAction->GetActionNumber(); + pParentData->bIsAcceptable=pScChangeAction->IsRejectable(); // select old value + pParentData->bIsRejectable=false; + pParentData->bDisabled=false; + } + while( itChangeAction != pActionMap->end() ) + { + if( itChangeAction->second->GetState() == SC_CAS_VIRGIN ) + { + std::unique_ptr<weld::TreeIter> xEntry = + InsertChangeActionContent( dynamic_cast<const ScChangeActionContent*>( itChangeAction->second ), + rParent, RD_SPECIAL_NONE ); + + if (xEntry) + bTheTestFlag=false; + } + ++itChangeAction; + } + + if ( !bParentInserted ) + { + std::unique_ptr<weld::TreeIter> xEntry = + InsertChangeActionContent(static_cast<const ScChangeActionContent*>( + pScChangeAction),rParent,RD_SPECIAL_NONE); + + if (xEntry) + { + bTheTestFlag=false; + ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + pParentData->pData=const_cast<ScChangeAction *>(pScChangeAction); + pParentData->nActionNo=pScChangeAction->GetActionNumber(); + pParentData->bIsAcceptable=pScChangeAction->IsClickable(); + pParentData->bIsRejectable=false; + pParentData->bDisabled=false; + } + } + + return bTheTestFlag; +} + +bool ScAcceptChgDlg::InsertAcceptedORejected(const weld::TreeIter& rParent) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + bool bTheTestFlag = true; + + ScChangeActionState eState = SC_CAS_VIRGIN; + weld::TreeView& rTreeView = pTheView->GetWidget(); + OUString aString = rTreeView.get_text(rParent, 0); + OUString a2String = aString.copy(0, aStrAllAccepted.getLength()); + if (a2String == aStrAllAccepted) + eState=SC_CAS_ACCEPTED; + else + { + a2String = aString.copy(0, aStrAllRejected.getLength()); + if (a2String == aStrAllRejected) + eState=SC_CAS_REJECTED; + } + + ScChangeAction* pScChangeAction = pChanges->GetFirst(); + while (pScChangeAction) + { + if (pScChangeAction->GetState()==eState && + AppendFilteredAction(pScChangeAction, eState, false, &rParent)) + bTheTestFlag=false; + pScChangeAction=pScChangeAction->GetNext(); + } + return bTheTestFlag; +} + +bool ScAcceptChgDlg::InsertChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + bool bTheTestFlag = true; + + for( const auto& rChangeAction : *pActionMap ) + { + std::unique_ptr<weld::TreeIter> xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, false, true); + + if (xEntry) + { + bTheTestFlag=false; + + weld::TreeView& rTreeView = pTheView->GetWidget(); + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + pEntryData->bIsRejectable=false; + pEntryData->bIsAcceptable=false; + pEntryData->bDisabled=true; + + if (rChangeAction.second->IsDialogParent()) + Expand(pChanges, rChangeAction.second, *xEntry); + } + } + return bTheTestFlag; +} + +bool ScAcceptChgDlg::InsertDeletedChildren(const ScChangeAction* pScChangeAction, + ScChangeActionMap* pActionMap, const weld::TreeIter& rParent) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + bool bTheTestFlag = true; + std::unique_ptr<weld::TreeIter> xEntry; + + for( const auto& rChangeAction : *pActionMap ) + { + + if( pScChangeAction != rChangeAction.second ) + xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, false, true); + else + xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, true, true); + + if (xEntry) + { + weld::TreeView& rTreeView = pTheView->GetWidget(); + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + pEntryData->bIsRejectable=false; + pEntryData->bIsAcceptable=false; + pEntryData->bDisabled=true; + + bTheTestFlag=false; + + if (rChangeAction.second->IsDialogParent()) + Expand(pChanges, rChangeAction.second, *xEntry); + } + } + return bTheTestFlag; +} + +bool ScAcceptChgDlg::Expand(const ScChangeTrack* pChanges, const ScChangeAction* pScChangeAction, + const weld::TreeIter& rEntry, bool bFilter) +{ + bool bTheTestFlag = true; + + if (pChanges && pScChangeAction) + { + ScChangeActionMap aActionMap; + + GetDependents(pScChangeAction, aActionMap, rEntry); + + switch(pScChangeAction->GetType()) + { + case SC_CAT_CONTENT: + { + InsertContentChildren(&aActionMap, rEntry); + bTheTestFlag=!bHasFilterEntry; + break; + } + case SC_CAT_DELETE_COLS: + case SC_CAT_DELETE_ROWS: + case SC_CAT_DELETE_TABS: + { + InsertDeletedChildren(pScChangeAction, &aActionMap, rEntry); + bTheTestFlag=!bHasFilterEntry; + break; + } + default: + { + if(!bFilter) + bTheTestFlag = InsertChildren(&aActionMap, rEntry); + break; + } + } + aActionMap.clear(); + } + return bTheTestFlag; +} + +IMPL_LINK(ScAcceptChgDlg, ExpandingHandle, const weld::TreeIter&, rEntry, bool) +{ + ScChangeTrack* pChanges=pDoc->GetChangeTrack(); + if (pChanges) + { + m_xDialog->set_busy_cursor(true); + ScChangeActionMap aActionMap; + weld::TreeView& rTreeView = pTheView->GetWidget(); + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry)); + if (!rTreeView.iter_has_child(rEntry)) + { + bool bTheTestFlag = true; + + if (pEntryData) + { + ScChangeAction* pScChangeAction=static_cast<ScChangeAction*>(pEntryData->pData); + + GetDependents(pScChangeAction, aActionMap, rEntry); + + switch (pScChangeAction->GetType()) + { + case SC_CAT_CONTENT: + { + bTheTestFlag = InsertContentChildren( &aActionMap, rEntry ); + break; + } + case SC_CAT_DELETE_COLS: + case SC_CAT_DELETE_ROWS: + case SC_CAT_DELETE_TABS: + { + bTheTestFlag = InsertDeletedChildren( pScChangeAction, &aActionMap, rEntry ); + break; + } + default: + { + bTheTestFlag = InsertChildren( &aActionMap, rEntry ); + break; + } + } + aActionMap.clear(); + + } + else + { + bTheTestFlag = InsertAcceptedORejected(rEntry); + } + if (bTheTestFlag) + { + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + rTreeView.insert(&rEntry, -1, &aStrNoEntry, nullptr, nullptr, nullptr, false, xEntry.get()); + rTreeView.set_font_color(*xEntry, COL_GRAY); + } + } + m_xDialog->set_busy_cursor(false); + } + return true; +} + +void ScAcceptChgDlg::AppendChanges(const ScChangeTrack* pChanges,sal_uLong nStartAction, + sal_uLong nEndAction) +{ + if(pChanges==nullptr) + return; + + std::unique_ptr<weld::TreeIter> xParent; + m_xDialog->set_busy_cursor(true); + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.freeze(); + + bool bTheFlag = false; + + bool bFilterFlag = pTPFilter->IsDate() || pTPFilter->IsRange() || + pTPFilter->IsAuthor() || pTPFilter->IsComment(); + + bUseColor = bFilterFlag; + + for(sal_uLong i=nStartAction;i<=nEndAction;i++) + { + const ScChangeAction* pScChangeAction=pChanges->GetAction(i); + if(pScChangeAction==nullptr) continue; + + switch (pScChangeAction->GetState()) + { + case SC_CAS_VIRGIN: + + if (pScChangeAction->IsDialogRoot()) + { + bool bOnDemandChildren = !bFilterFlag && pScChangeAction->IsDialogParent(); + if (pScChangeAction->IsDialogParent()) + xParent = AppendChangeAction(pScChangeAction, bOnDemandChildren); + else + xParent = AppendFilteredAction(pScChangeAction, SC_CAS_VIRGIN, bOnDemandChildren); + } + else + xParent.reset(); + + bTheFlag=true; + break; + + case SC_CAS_ACCEPTED: + xParent.reset(); + nAcceptCount++; + break; + + case SC_CAS_REJECTED: + xParent.reset(); + nRejectCount++; + break; + } + + if (xParent && pScChangeAction->IsDialogParent() && bFilterFlag) + { + bool bTestFlag = bHasFilterEntry; + bHasFilterEntry = false; + if (Expand(pChanges,pScChangeAction,*xParent,!bTestFlag)&&!bTestFlag) + rTreeView.remove(*xParent); + } + } + + if( bTheFlag && (!pDoc->IsDocEditable() || pChanges->IsProtected()) ) + bTheFlag=false; + + pTPView->EnableAccept(bTheFlag); + pTPView->EnableAcceptAll(bTheFlag); + pTPView->EnableReject(bTheFlag); + pTPView->EnableRejectAll(bTheFlag); + + rTreeView.thaw(); + m_xDialog->set_busy_cursor(false); +} + +void ScAcceptChgDlg::RemoveEntries(sal_uLong nStartAction,sal_uLong nEndAction) +{ + weld::TreeView& rTreeView = pTheView->GetWidget(); + + ScRedlinData *pEntryData=nullptr; + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (rTreeView.get_cursor(xEntry.get())) + pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + + if (!rTreeView.get_iter_first(*xEntry)) + return; + + sal_uLong nAction=0; + if (pEntryData) + nAction=pEntryData->nActionNo; + + if (nAction>=nStartAction && nAction<=nEndAction) + rTreeView.set_cursor(*xEntry); + + std::vector<OUString> aIdsToRemove; + + do + { + OUString sId(rTreeView.get_id(*xEntry)); + pEntryData = weld::fromId<ScRedlinData*>(sId); + if (pEntryData) + { + nAction = pEntryData->nActionNo; + if (nStartAction <= nAction && nAction <= nEndAction) + { + aIdsToRemove.push_back(sId); + delete pEntryData; + } + } + } + while (rTreeView.iter_next(*xEntry)); + + rTreeView.freeze(); + + // MUST do it backwards, don't delete parents before children and GPF + for (auto it = aIdsToRemove.rbegin(); it != aIdsToRemove.rend(); ++it) + rTreeView.remove_id(*it); + + rTreeView.thaw(); +} + +void ScAcceptChgDlg::UpdateEntries(const ScChangeTrack* pChgTrack, sal_uLong nStartAction,sal_uLong nEndAction) +{ + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.freeze(); + + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + std::unique_ptr<weld::TreeIter> xLastEntry(rTreeView.make_iterator()); + std::unique_ptr<weld::TreeIter> xNextEntry(rTreeView.make_iterator()); + + bool bEntry = rTreeView.get_iter_first(*xEntry); + bool bLastEntry = false; + + while (bEntry) + { + bool bRemove = false; + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + if (pEntryData) + { + ScChangeAction* pScChangeAction= + static_cast<ScChangeAction*>(pEntryData->pData); + + sal_uLong nAction=pScChangeAction->GetActionNumber(); + + if(nStartAction<=nAction && nAction<=nEndAction) bRemove=true; + } + + bool bNextEntry; + if (bRemove) + { + rTreeView.remove(*xEntry); + delete pEntryData; + + if (!bLastEntry) + bLastEntry = rTreeView.get_iter_first(*xLastEntry); + if (bLastEntry) + { + rTreeView.copy_iterator(*xLastEntry, *xNextEntry); + bNextEntry = rTreeView.iter_next(*xNextEntry); + if (!bNextEntry) + { + rTreeView.copy_iterator(*xLastEntry, *xNextEntry); + bLastEntry = false; + } + } + else + bNextEntry = false; + } + else + { + rTreeView.copy_iterator(*xEntry, *xLastEntry); + bLastEntry = true; + + rTreeView.copy_iterator(*xEntry, *xNextEntry); + bNextEntry = rTreeView.iter_next(*xNextEntry); + } + + rTreeView.copy_iterator(*xNextEntry, *xEntry); + bEntry = bNextEntry; + } + + AppendChanges(pChgTrack,nStartAction,nEndAction); + + rTreeView.thaw(); +} + +IMPL_LINK( ScAcceptChgDlg, ChgTrackModHdl, ScChangeTrack&, rChgTrack, void) +{ + ScChangeTrackMsgQueue& aMsgQueue= rChgTrack.GetMsgQueue(); + + sal_uLong nStartAction; + sal_uLong nEndAction; + + for (const auto& rMsg : aMsgQueue) + { + nStartAction = rMsg.nStartAction; + nEndAction = rMsg.nEndAction; + + if(!bIgnoreMsg) + { + bNoSelection=true; + + switch(rMsg.eMsgType) + { + case ScChangeTrackMsgType::Append: + AppendChanges(&rChgTrack,nStartAction,nEndAction); + break; + case ScChangeTrackMsgType::Remove: + RemoveEntries(nStartAction,nEndAction); + break; + case ScChangeTrackMsgType::Parent: + case ScChangeTrackMsgType::Change: //bNeedsUpdate=true; + UpdateEntries(&rChgTrack,nStartAction,nEndAction); + break; + default: assert(false); break; + } + } + } + + aMsgQueue.clear(); +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, ReOpenTimerHdl, Timer *, void) +{ + ScSimpleRefDlgWrapper::SetAutoReOpen(true); + m_xAcceptChgCtr->ShowFilterPage(); + RefHandle(nullptr); +} + +IMPL_LINK_NOARG(ScAcceptChgDlg, UpdateSelectionHdl, Timer *, void) +{ + ScTabView* pTabView = pViewData->GetView(); + + bool bAcceptFlag = true; + bool bRejectFlag = true; + + pTabView->DoneBlockMode(); // clears old marking + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::vector<const ScChangeAction*> aActions; + rTreeView.selected_foreach([&rTreeView, &bAcceptFlag, &bRejectFlag, &aActions](weld::TreeIter& rEntry){ + ScRedlinData* pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry)); + if (pEntryData) + { + bRejectFlag &= pEntryData->bIsRejectable; + bAcceptFlag &= pEntryData->bIsAcceptable; + + const ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData); + if( pScChangeAction && (pScChangeAction->GetType() != SC_CAT_DELETE_TABS) && + (!pEntryData->bDisabled || pScChangeAction->IsVisible()) ) + { + aActions.push_back(pScChangeAction); + } + } + else + { + bAcceptFlag = false; + bRejectFlag = false; + } + return false; + }); + + bool bContMark = false; + for (size_t i = 0, nCount = aActions.size(); i < nCount; ++i) + { + const ScBigRange& rBigRange = aActions[i]->GetBigRange(); + if (rBigRange.IsValid(*pDoc) && m_xDialog->has_toplevel_focus()) + { + bool bSetCursor = i == nCount - 1; + pTabView->MarkRange(rBigRange.MakeRange(*pDoc), bSetCursor, bContMark); + bContMark = true; + } + } + + ScChangeTrack* pChanges = pDoc->GetChangeTrack(); + bool bEnable = pDoc->IsDocEditable() && pChanges && !pChanges->IsProtected(); + pTPView->EnableAccept( bAcceptFlag && bEnable ); + pTPView->EnableReject( bRejectFlag && bEnable ); +} + +IMPL_LINK(ScAcceptChgDlg, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + bool bEntry = rTreeView.get_cursor(xEntry.get()); + if (bEntry) + rTreeView.select(*xEntry); + + int nSortedCol = rTreeView.get_sort_column(); + for (sal_Int32 i = 0; i < 5; ++i) + m_xSortMenu->set_active("calcsort" + OString::number(i), i == nSortedCol); + + m_xPopup->set_sensitive("calcedit", false); + + if (pDoc->IsDocEditable() && bEntry) + { + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + if (pEntryData) + { + ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData); + if (pScChangeAction && !rTreeView.get_iter_depth(*xEntry)) + m_xPopup->set_sensitive("calcedit", true); + } + } + + OString sCommand = m_xPopup->popup_at_rect(&rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))); + + if (!sCommand.isEmpty()) + { + if (sCommand == "calcedit") + { + if (bEntry) + { + ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry)); + if (pEntryData) + { + ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData); + pViewData->GetDocShell()->ExecuteChangeCommentDialog(pScChangeAction, m_xDialog.get(), false); + } + } + } + else + { + int nDialogCol = o3tl::toInt32(sCommand.subView(8)); + pTheView->HeaderBarClick(nDialogCol); + } + } + + return true; +} + +namespace +{ + //at one point we were writing multiple AcceptChgDat strings, + //so strip all of them and keep the results of the last one + OUString lcl_StripAcceptChgDat(OUString &rExtraString) + { + OUString aStr; + while (true) + { + sal_Int32 nPos = rExtraString.indexOf("AcceptChgDat:"); + if (nPos == -1) + break; + // Try to read the alignment string "ALIGN:(...)"; if it is missing + // we have an old version + sal_Int32 n1 = rExtraString.indexOf('(', nPos); + if ( n1 != -1 ) + { + sal_Int32 n2 = rExtraString.indexOf(')', n1); + if ( n2 != -1 ) + { + // cut out alignment string + aStr = rExtraString.copy(nPos, n2 - nPos + 1); + rExtraString = rExtraString.replaceAt(nPos, n2 - nPos + 1, u""); + aStr = aStr.copy( n1-nPos+1 ); + } + } + } + return aStr; + } +} + +void ScAcceptChgDlg::Initialize(SfxChildWinInfo* pInfo) +{ + OUString aStr; + if (pInfo && !pInfo->aExtraString.isEmpty()) + aStr = lcl_StripAcceptChgDat(pInfo->aExtraString); + + SfxModelessDialogController::Initialize(pInfo); + + if (aStr.isEmpty()) + return; + + int nCount = aStr.toInt32(); + if (nCount <= 2) + return; + + std::vector<int> aEndPos; + + for (int i = 0; i < nCount; ++i) + { + sal_Int32 n1 = aStr.indexOf(';'); + aStr = aStr.copy( n1+1 ); + aEndPos.push_back(aStr.toInt32()); + } + + std::vector<int> aWidths; + for (int i = 1; i < nCount; ++i) + aWidths.push_back(aEndPos[i] - aEndPos[i - 1]); + + // turn column end points back to column widths, ignoring the small + // value used for the expander column + weld::TreeView& rTreeView = pTheView->GetWidget(); + rTreeView.set_column_fixed_widths(aWidths); +} + +void ScAcceptChgDlg::FillInfo(SfxChildWinInfo& rInfo) const +{ + SfxModelessDialogController::FillInfo(rInfo); + //remove any old one before adding a new one + lcl_StripAcceptChgDat(rInfo.aExtraString); + rInfo.aExtraString += "AcceptChgDat:("; + + const int nTabCount = 5; + + rInfo.aExtraString += OUString::number(nTabCount); + rInfo.aExtraString += ";"; + + weld::TreeView& rTreeView = pTheView->GetWidget(); + std::vector<int> aWidths; + // turn column widths back into column end points for compatibility + // with how they used to be stored, including a small value for the + // expander column + aWidths.push_back(rTreeView.get_checkbox_column_width()); + for (int i = 0; i < nTabCount - 1; ++i) + aWidths.push_back(aWidths.back() + rTreeView.get_column_width(i)); + + for (auto a : aWidths) + { + rInfo.aExtraString += OUString::number(a); + rInfo.aExtraString += ";"; + } + rInfo.aExtraString += ")"; +} + +#define CALC_DATE 3 +#define CALC_POS 1 + +int ScAcceptChgDlg::ColCompareHdl(const weld::TreeIter& rLeft, const weld::TreeIter& rRight) const +{ + weld::TreeView& rTreeView = pTheView->GetWidget(); + + sal_Int32 nCompare = 0; + SCCOL nSortCol = rTreeView.get_sort_column(); + + if (CALC_DATE == nSortCol) + { + RedlinData *pLeftData = weld::fromId<RedlinData*>(rTreeView.get_id(rLeft)); + RedlinData *pRightData = weld::fromId<RedlinData*>(rTreeView.get_id(rRight)); + if (pLeftData && pRightData) + { + if(pLeftData->aDateTime < pRightData->aDateTime) + nCompare = -1; + else if(pLeftData->aDateTime > pRightData->aDateTime) + nCompare = 1; + return nCompare; + } + } + else if (CALC_POS == nSortCol) + { + ScRedlinData *pLeftData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rLeft)); + ScRedlinData *pRightData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rRight)); + if (pLeftData && pRightData) + { + nCompare = 1; + + if(pLeftData->nTable < pRightData->nTable) + nCompare = -1; + else if(pLeftData->nTable == pRightData->nTable) + { + if(pLeftData->nRow < pRightData->nRow) + nCompare = -1; + else if(pLeftData->nRow == pRightData->nRow) + { + if(pLeftData->nCol < pRightData->nCol) + nCompare = -1; + else if(pLeftData->nCol == pRightData->nCol) + nCompare = 0; + } + } + + return nCompare; + } + } + + return ScGlobal::GetCaseCollator().compareString(rTreeView.get_text(rLeft, nSortCol), + rTreeView.get_text(rRight, nSortCol)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |