diff options
Diffstat (limited to 'sc/source/ui/miscdlgs')
41 files changed, 13342 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: */ diff --git a/sc/source/ui/miscdlgs/anyrefdg.cxx b/sc/source/ui/miscdlgs/anyrefdg.cxx new file mode 100644 index 000000000..0ffad93cf --- /dev/null +++ b/sc/source/ui/miscdlgs/anyrefdg.cxx @@ -0,0 +1,784 @@ +/* -*- 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 <rangelst.hxx> +#include <comphelper/string.hxx> +#include <sfx2/app.hxx> +#include <sfx2/viewsh.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> + +#include <anyrefdg.hxx> +#include <sc.hrc> +#include <inputhdl.hxx> +#include <scmod.hxx> +#include <inputwin.hxx> +#include <tabvwsh.hxx> +#include <docsh.hxx> +#include <rfindlst.hxx> +#include <compiler.hxx> +#include <inputopt.hxx> +#include <rangeutl.hxx> +#include <tokenarray.hxx> +#include <comphelper/lok.hxx> +#include <output.hxx> + +#include <memory> + +ScFormulaReferenceHelper::ScFormulaReferenceHelper(IAnyRefDialog* _pDlg,SfxBindings* _pBindings) + : m_pDlg(_pDlg) + , m_pRefEdit (nullptr) + , m_pRefBtn (nullptr) + , m_pDialog(nullptr) + , m_pBindings(_pBindings) + , m_nRefTab(0) + , m_bHighlightRef(false) +{ + ScInputOptions aInputOption=SC_MOD()->GetInputOptions(); + m_bEnableColorRef=aInputOption.GetRangeFinder(); +} + +ScFormulaReferenceHelper::~ScFormulaReferenceHelper() COVERITY_NOEXCEPT_FALSE +{ + dispose(); +} + +void ScFormulaReferenceHelper::dispose() +{ + // common cleanup for ScAnyRefDlg and ScFormulaDlg is done here + HideReference(); + enableInput( true ); + + ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(); + if ( pInputHdl ) + pInputHdl->ResetDelayTimer(); // stop the timer for disabling the input line + + m_pDialog = nullptr; +} + +void ScFormulaReferenceHelper::enableInput( bool bEnable ) +{ + ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>)); + while( pDocShell ) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell ); + while( pFrame ) + { + // enable everything except InPlace, including bean frames + if ( !pFrame->GetFrame().IsInPlace() ) + { + SfxViewShell* p = pFrame->GetViewShell(); + ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p ); + if(pViewSh!=nullptr) + { + vcl::Window *pWin=pViewSh->GetWindow(); + if(pWin) + { + vcl::Window *pParent=pWin->GetParent(); + if(pParent) + { + pParent->EnableInput(bEnable); + pViewSh->EnableRefInput(bEnable); + } + } + } + } + pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell ); + } + + pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>)); + } +} + +void ScFormulaReferenceHelper::ShowSimpleReference(std::u16string_view rStr) +{ + if (!m_bEnableColorRef) + return; + + m_bHighlightRef = true; + ScViewData* pViewData=ScDocShell::GetViewData(); + if ( !pViewData ) + return; + + ScDocument& rDoc = pViewData->GetDocument(); + ScTabViewShell* pTabViewShell=pViewData->GetViewShell(); + + ScRangeList aRangeList; + + pTabViewShell->DoneRefMode(); + pTabViewShell->ClearHighlightRanges(); + + if( ParseWithNames( aRangeList, rStr, rDoc ) ) + { + for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i ) + { + ScRange const & rRangeEntry = aRangeList[ i ]; + Color aColName = ScRangeFindList::GetColorName( i ); + pTabViewShell->AddHighlightRange( rRangeEntry, aColName ); + } + } +} + +bool ScFormulaReferenceHelper::ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& rDoc ) +{ + rRanges.RemoveAll(); + + if (rStr.empty()) + return true; + + ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0); + + bool bError = false; + sal_Int32 nIdx {0}; + do + { + ScRange aRange; + OUString aRangeStr( o3tl::getToken(rStr, 0, ';', nIdx ) ); + + ScRefFlags nFlags = aRange.ParseAny( aRangeStr, rDoc, aDetails ); + if ( nFlags & ScRefFlags::VALID ) + { + if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO ) + aRange.aStart.SetTab( m_nRefTab ); + if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO ) + aRange.aEnd.SetTab( aRange.aStart.Tab() ); + rRanges.push_back( aRange ); + } + else if ( ScRangeUtil::MakeRangeFromName( aRangeStr, rDoc, m_nRefTab, aRange, RUTL_NAMES, aDetails ) ) + rRanges.push_back( aRange ); + else + bError = true; + } + while (nIdx>0); + + return !bError; +} + +void ScFormulaReferenceHelper::ShowFormulaReference(const OUString& rStr) +{ + if( !m_bEnableColorRef) + return; + + m_bHighlightRef=true; + ScViewData* pViewData=ScDocShell::GetViewData(); + if ( !(pViewData && m_pRefComp) ) + return; + + ScTabViewShell* pTabViewShell=pViewData->GetViewShell(); + SCCOL nCol = pViewData->GetCurX(); + SCROW nRow = pViewData->GetCurY(); + SCTAB nTab = pViewData->GetTabNo(); + ScAddress aPos( nCol, nRow, nTab ); + + std::unique_ptr<ScTokenArray> pScTokA(m_pRefComp->CompileString(rStr)); + + if (!(pTabViewShell && pScTokA)) + return; + + const ScViewData& rViewData = pTabViewShell->GetViewData(); + ScDocument& rDoc = rViewData.GetDocument(); + pTabViewShell->DoneRefMode(); + pTabViewShell->ClearHighlightRanges(); + + formula::FormulaTokenArrayPlainIterator aIter(*pScTokA); + const formula::FormulaToken* pToken = aIter.GetNextReference(); + + sal_uInt16 nIndex=0; + + while(pToken!=nullptr) + { + bool bDoubleRef=(pToken->GetType()==formula::svDoubleRef); + + if(pToken->GetType()==formula::svSingleRef || bDoubleRef) + { + ScRange aRange; + if(bDoubleRef) + { + ScComplexRefData aRef( *pToken->GetDoubleRef() ); + aRange = aRef.toAbs(rDoc, aPos); + } + else + { + ScSingleRefData aRef( *pToken->GetSingleRef() ); + aRange.aStart = aRef.toAbs(rDoc, aPos); + aRange.aEnd = aRange.aStart; + } + Color aColName=ScRangeFindList::GetColorName(nIndex++); + pTabViewShell->AddHighlightRange(aRange, aColName); + } + + pToken = aIter.GetNextReference(); + } +} + +void ScFormulaReferenceHelper::HideReference( bool bDoneRefMode ) +{ + ScViewData* pViewData=ScDocShell::GetViewData(); + + if( !(pViewData && m_bHighlightRef && m_bEnableColorRef)) + return; + + ScTabViewShell* pTabViewShell=pViewData->GetViewShell(); + + if(pTabViewShell!=nullptr) + { + // bDoneRefMode is sal_False when called from before SetReference. + // In that case, RefMode was just started and must not be ended now. + + if ( bDoneRefMode ) + pTabViewShell->DoneRefMode(); + pTabViewShell->ClearHighlightRanges(); + + if( comphelper::LibreOfficeKit::isActive() ) + { + // Clear + std::vector<ReferenceMark> aReferenceMarks; + ScInputHandler::SendReferenceMarks( pTabViewShell, aReferenceMarks ); + } + } + m_bHighlightRef=false; +} + +void ScFormulaReferenceHelper::ShowReference(const OUString& rStr) +{ + if( !m_bEnableColorRef ) + return; + + if( rStr.indexOf('(') != -1 || + rStr.indexOf('+') != -1 || + rStr.indexOf('*') != -1 || + rStr.indexOf('-') != -1 || + rStr.indexOf('/') != -1 || + rStr.indexOf('&') != -1 || + rStr.indexOf('<') != -1 || + rStr.indexOf('>') != -1 || + rStr.indexOf('=') != -1 || + rStr.indexOf('^') != -1 ) + { + ShowFormulaReference(rStr); + } + else + { + ShowSimpleReference(rStr); + } +} + +void ScFormulaReferenceHelper::ReleaseFocus( formula::RefEdit* pEdit ) +{ + if( !m_pRefEdit && pEdit ) + { + m_pDlg->RefInputStart( pEdit ); + } + + ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); + if( !pViewShell ) + return; + + pViewShell->ActiveGrabFocus(); + if( !m_pRefEdit ) + return; + + const ScViewData& rViewData = pViewShell->GetViewData(); + ScDocument& rDoc = rViewData.GetDocument(); + ScRangeList aRangeList; + if( !ParseWithNames( aRangeList, m_pRefEdit->GetText(), rDoc ) ) + return; + + if ( !aRangeList.empty() ) + { + const ScRange & rRange = aRangeList.front(); + pViewShell->SetTabNo( rRange.aStart.Tab() ); + pViewShell->MoveCursorAbs( rRange.aStart.Col(), + rRange.aStart.Row(), SC_FOLLOW_JUMP, false, false ); + pViewShell->MoveCursorAbs( rRange.aEnd.Col(), + rRange.aEnd.Row(), SC_FOLLOW_JUMP, true, false ); + m_pDlg->SetReference( rRange, rDoc ); + } +} + +void ScFormulaReferenceHelper::Init() +{ + ScViewData* pViewData=ScDocShell::GetViewData(); //! use pScViewShell? + if ( !pViewData ) + return; + + ScDocument& rDoc = pViewData->GetDocument(); + SCCOL nCol = pViewData->GetCurX(); + SCROW nRow = pViewData->GetCurY(); + SCTAB nTab = pViewData->GetTabNo(); + ScAddress aCursorPos( nCol, nRow, nTab ); + + m_pRefComp.reset( new ScCompiler( rDoc, aCursorPos, rDoc.GetGrammar()) ); + m_pRefComp->EnableJumpCommandReorder(false); + m_pRefComp->EnableStopOnError(false); + + m_nRefTab = nTab; +} + +IMPL_LINK_NOARG(ScFormulaReferenceHelper, ActivateHdl, weld::Widget&, bool) +{ + if (m_pRefEdit) + m_pRefEdit->GrabFocus(); + m_pDlg->RefInputDone(true); + return true; +} + +void ScFormulaReferenceHelper::RefInputDone( bool bForced ) +{ + if ( !CanInputDone( bForced ) ) + return; + + if (!m_pDialog) + return; + + // Adjust window title + m_pDialog->set_title(m_sOldDialogText); + + if (m_pRefEdit) + m_pRefEdit->SetActivateHdl(Link<weld::Widget&, bool>()); + + // set button image + if (m_pRefBtn) + { + m_pRefBtn->SetActivateHdl(Link<weld::Widget&, bool>()); + m_pRefBtn->SetStartImage(); + } + + m_pDialog->undo_collapse(); + + m_pRefEdit = nullptr; + m_pRefBtn = nullptr; +} + +void ScFormulaReferenceHelper::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton ) +{ + if (m_pRefEdit) + return; + + m_pRefEdit = pEdit; + m_pRefBtn = pButton; + + // Save and adjust window title + m_sOldDialogText = m_pDialog->get_title(); + if (weld::Label *pLabel = m_pRefEdit->GetLabelWidgetForShrinkMode()) + { + const OUString sLabel = pLabel->get_label(); + if (!sLabel.isEmpty()) + { + const OUString sNewDialogText = m_sOldDialogText + ": " + comphelper::string::stripEnd(sLabel, ':'); + m_pDialog->set_title(pLabel->strip_mnemonic(sNewDialogText)); + } + } + + m_pDialog->collapse(pEdit->GetWidget(), pButton ? pButton->GetWidget() : nullptr); + + // set button image + if (pButton) + pButton->SetEndImage(); + + m_pRefEdit->SetActivateHdl(LINK(this, ScFormulaReferenceHelper, ActivateHdl)); + if (m_pRefBtn) + m_pRefBtn->SetActivateHdl(LINK(this, ScFormulaReferenceHelper, ActivateHdl)); +} + +void ScFormulaReferenceHelper::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton ) +{ + if( !pEdit ) + return; + + if( m_pRefEdit == pEdit ) // is this the active ref edit field? + { + m_pRefEdit->GrabFocus(); // before RefInputDone() + m_pDlg->RefInputDone( true ); // finish ref input + } + else + { + m_pDlg->RefInputDone( true ); // another active ref edit? + m_pDlg->RefInputStart( pEdit, pButton ); // start ref input + // pRefEdit might differ from pEdit after RefInputStart() (i.e. ScFormulaDlg) + if( m_pRefEdit ) + m_pRefEdit->GrabFocus(); + } +} + +void ScFormulaReferenceHelper::DoClose( sal_uInt16 nId ) +{ + SfxApplication* pSfxApp = SfxGetpApp(); + + SetDispatcherLock( false ); //! here and in dtor ? + + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if ( pViewFrm && pViewFrm->HasChildWindow(FID_INPUTLINE_STATUS) ) + { + // The input row is disabled with ToolBox::Disable disabled, thus it must be + // reenabled with ToolBox::Enable (before the AppWindow is enabled) + // for the buttons to be drawn as enabled. + SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_INPUTLINE_STATUS); + if (pChild) + { + ScInputWindow* pWin = static_cast<ScInputWindow*>(pChild->GetWindow()); + pWin->Enable(); + } + } + + // find parent view frame to close dialog + SfxViewFrame* pMyViewFrm = nullptr; + if ( m_pBindings ) + { + SfxDispatcher* pMyDisp = m_pBindings->GetDispatcher(); + if (pMyDisp) + pMyViewFrm = pMyDisp->GetFrame(); + } + SC_MOD()->SetRefDialog( nId, false, pMyViewFrm ); + + pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) ); + + ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell(); + if ( pScViewShell ) + pScViewShell->UpdateInputHandler(true); +} + +void ScFormulaReferenceHelper::SetDispatcherLock( bool bLock ) +{ + if (!comphelper::LibreOfficeKit::isActive()) + { + // lock / unlock only the dispatchers of Calc documents + ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>)); + while (pDocShell) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst(pDocShell); + while (pFrame) + { + SfxDispatcher* pDisp = pFrame->GetDispatcher(); + if (pDisp) + pDisp->Lock(bLock); + pFrame = SfxViewFrame::GetNext(*pFrame, pDocShell); + } + pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>)); + } + return; + // if a new view is created while the dialog is open, + // that view's dispatcher is locked when trying to create the dialog + // for that view (ScTabViewShell::CreateRefDialog) + } + + // lock / unlock only the dispatcher of Calc document + SfxDispatcher* pDisp = nullptr; + if ( m_pBindings ) + { + pDisp = m_pBindings->GetDispatcher(); + } + else if(SfxViewFrame* pViewFrame = SfxViewFrame::Current()) + { + if (dynamic_cast< ScTabViewShell* >(pViewFrame->GetViewShell())) + pDisp = pViewFrame->GetDispatcher(); + } + + if (pDisp) + pDisp->Lock(bLock); +} + +void ScFormulaReferenceHelper::ViewShellChanged() +{ + enableInput( false ); + + EnableSpreadsheets(); +} +void ScFormulaReferenceHelper::EnableSpreadsheets(bool bFlag) +{ + ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>)); + while( pDocShell ) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell ); + while( pFrame ) + { + // enable everything except InPlace, including bean frames + if ( !pFrame->GetFrame().IsInPlace() ) + { + SfxViewShell* p = pFrame->GetViewShell(); + ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p ); + if(pViewSh!=nullptr) + { + vcl::Window *pWin=pViewSh->GetWindow(); + if(pWin) + { + vcl::Window *pParent=pWin->GetParent(); + if(pParent) + { + pParent->EnableInput(bFlag,false); + pViewSh->EnableRefInput(bFlag); + } + } + } + } + pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell ); + } + + pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>)); + } +} + +static void lcl_InvalidateWindows() +{ + ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>)); + while( pDocShell ) + { + SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell ); + while( pFrame ) + { + // enable everything except InPlace, including bean frames + if ( !pFrame->GetFrame().IsInPlace() ) + { + SfxViewShell* p = pFrame->GetViewShell(); + ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p ); + if(pViewSh!=nullptr) + { + vcl::Window *pWin=pViewSh->GetWindow(); + if(pWin) + { + vcl::Window *pParent=pWin->GetParent(); + if(pParent) + pParent->Invalidate(); + } + } + } + pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell ); + } + + pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>)); + } +} + +static void lcl_HideAllReferences() +{ + SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> ); + while ( pSh ) + { + static_cast<ScTabViewShell*>(pSh)->ClearHighlightRanges(); + pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> ); + } +} + +ScRefHandler::ScRefHandler(SfxDialogController& rController, SfxBindings* pB, bool bBindRef) + : m_pController(&rController) + , m_bInRefMode(false) + , m_aHelper(this, pB) + , m_pMyBindings(pB) +{ + m_aHelper.SetDialog(rController.getDialog()); + + if( bBindRef ) EnterRefMode(); +} + +bool ScRefHandler::EnterRefMode() +{ + if( m_bInRefMode ) return false; + + SC_MOD()->InputEnterHandler(); + + ScTabViewShell* pScViewShell = nullptr; + + // title has to be from the view that opened the dialog, + // even if it's not the current view + + SfxObjectShell* pParentDoc = nullptr; + if ( m_pMyBindings ) + { + SfxDispatcher* pMyDisp = m_pMyBindings->GetDispatcher(); + if (pMyDisp) + { + SfxViewFrame* pMyViewFrm = pMyDisp->GetFrame(); + if (pMyViewFrm) + { + pScViewShell = dynamic_cast<ScTabViewShell*>( pMyViewFrm->GetViewShell() ); + if( pScViewShell ) + pScViewShell->UpdateInputHandler(true); + pParentDoc = pMyViewFrm->GetObjectShell(); + } + } + } + if ( !pParentDoc && pScViewShell ) // use current only if above fails + pParentDoc = pScViewShell->GetObjectShell(); + if ( pParentDoc ) + m_aDocName = pParentDoc->GetTitle(); + + ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(pScViewShell); + + OSL_ENSURE( pInputHdl, "Missing input handler :-/" ); + + if ( pInputHdl ) + pInputHdl->NotifyChange( nullptr ); + + ScFormulaReferenceHelper::enableInput( false ); + + ScFormulaReferenceHelper::EnableSpreadsheets(); + + m_aHelper.Init(); + + m_aHelper.SetDispatcherLock( true ); + + m_bInRefMode = true; + return m_bInRefMode; +} + +ScRefHandler::~ScRefHandler() COVERITY_NOEXCEPT_FALSE +{ + disposeRefHandler(); +} + +void ScRefHandler::disposeRefHandler() +{ + m_pController = nullptr; + LeaveRefMode(); + m_aHelper.dispose(); +} + +bool ScRefHandler::LeaveRefMode() +{ + if( !m_bInRefMode ) return false; + + lcl_HideAllReferences(); + + SetDispatcherLock( false ); //! here and in DoClose ? + + ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell(); + if( pScViewShell ) + pScViewShell->UpdateInputHandler(true); + + lcl_InvalidateWindows(); + + m_bInRefMode = false; + return true; +} + +void ScRefHandler::SwitchToDocument() +{ + ScTabViewShell* pCurrent = ScTabViewShell::GetActiveViewShell(); + if (pCurrent) + { + SfxObjectShell* pObjSh = pCurrent->GetObjectShell(); + if ( pObjSh && pObjSh->GetTitle() == m_aDocName ) + { + // right document already visible -> nothing to do + return; + } + } + + SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> ); + while ( pSh ) + { + SfxObjectShell* pObjSh = pSh->GetObjectShell(); + if ( pObjSh && pObjSh->GetTitle() == m_aDocName ) + { + // switch to first TabViewShell for document + static_cast<ScTabViewShell*>(pSh)->SetActive(); + return; + } + pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> ); + } +} + +bool ScRefHandler::IsDocAllowed(SfxObjectShell* pDocSh) const // pDocSh may be 0 +{ + // if aDocName isn't initialized, allow + if ( m_aDocName.isEmpty() ) + return true; + + if ( !pDocSh ) + return false; + + // default: allow only same document (overridden in function dialog) + return m_aDocName==pDocSh->GetTitle(); +} + +bool ScRefHandler::IsRefInputMode() const +{ + return m_pController->getDialog()->get_visible(); +} + +bool ScRefHandler::DoClose( sal_uInt16 nId ) +{ + m_aHelper.DoClose(nId); + return true; +} + +void ScRefHandler::SetDispatcherLock( bool bLock ) +{ + m_aHelper.SetDispatcherLock( bLock ); +} + +void ScRefHandler::ViewShellChanged() +{ + ScFormulaReferenceHelper::ViewShellChanged(); +} + +void ScRefHandler::AddRefEntry() +{ + // override this for multi-references +} + +bool ScRefHandler::IsTableLocked() const +{ + // the default is that the sheet can be switched during while the reference is edited + + return false; +} + +// RefInputStart/Done: Zoom-In (AutoHide) on single field +// (using button or movement) + +void ScRefHandler::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton ) +{ + m_aHelper.RefInputStart( pEdit, pButton ); +} + +void ScRefHandler::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton ) +{ + m_aHelper.ToggleCollapsed( pEdit, pButton ); +} + +bool ScRefHandler::ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& rDoc ) +{ + return m_aHelper.ParseWithNames( rRanges, rStr, rDoc ); +} + +void ScRefHandler::HideReference( bool bDoneRefMode ) +{ + m_aHelper.HideReference( bDoneRefMode ); +} + +void ScRefHandler::ShowReference(const OUString& rStr) +{ + m_aHelper.ShowReference(rStr); +} + +void ScRefHandler::ReleaseFocus( formula::RefEdit* pEdit ) +{ + m_aHelper.ReleaseFocus( pEdit ); +} + +void ScRefHandler::RefInputDone( bool bForced ) +{ + m_aHelper.RefInputDone( bForced ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/autofmt.cxx b/sc/source/ui/miscdlgs/autofmt.cxx new file mode 100644 index 000000000..877c412a5 --- /dev/null +++ b/sc/source/ui/miscdlgs/autofmt.cxx @@ -0,0 +1,531 @@ +/* -*- 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 <scitems.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/justifyitem.hxx> +#include <editeng/lineitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <o3tl/unit_conversion.hxx> +#include <osl/diagnose.h> +#include <svl/numformat.hxx> +#include <svtools/scriptedtext.hxx> +#include <svx/framelink.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <comphelper/processfactory.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> + +#include <strings.hrc> +#include <zforauto.hxx> +#include <global.hxx> +#include <autoform.hxx> +#include <autofmt.hxx> +#include <scresid.hxx> +#include <document.hxx> +#include <viewdata.hxx> +#include <svtools/colorcfg.hxx> +#include <scmod.hxx> + +#define FRAME_OFFSET 4 + +// ScAutoFmtPreview + +ScAutoFmtPreview::ScAutoFmtPreview() + : pCurData(nullptr) + , bFitWidth(false) + , mbRTL(false) + , aStrJan(ScResId(STR_JAN)) + , aStrFeb(ScResId(STR_FEB)) + , aStrMar(ScResId(STR_MAR)) + , aStrNorth(ScResId(STR_NORTH)) + , aStrMid(ScResId(STR_MID)) + , aStrSouth(ScResId(STR_SOUTH)) + , aStrSum(ScResId(STR_SUM)) + , pNumFmt(new SvNumberFormatter(::comphelper::getProcessComponentContext(), ScGlobal::eLnge)) +{ + Init(); +} + +void ScAutoFmtPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + aVD.disposeAndReset(VclPtr<VirtualDevice>::Create(pDrawingArea->get_ref_device())); + CustomWidgetController::SetDrawingArea(pDrawingArea); +} + +void ScAutoFmtPreview::Resize() +{ + Size aSize(GetOutputSizePixel()); + aPrvSize = Size(aSize.Width() - 6, aSize.Height() - 30); + mnLabelColWidth = (aPrvSize.Width() - 4) / 4 - 12; + mnDataColWidth1 = (aPrvSize.Width() - 4 - 2 * mnLabelColWidth) / 3; + mnDataColWidth2 = (aPrvSize.Width() - 4 - 2 * mnLabelColWidth) / 4; + mnRowHeight = (aPrvSize.Height() - 4) / 5; + NotifyChange(pCurData); +} + +ScAutoFmtPreview::~ScAutoFmtPreview() +{ +} + +static void lcl_SetFontProperties( + vcl::Font& rFont, + const SvxFontItem& rFontItem, + const SvxWeightItem& rWeightItem, + const SvxPostureItem& rPostureItem ) +{ + rFont.SetFamily ( rFontItem.GetFamily() ); + rFont.SetFamilyName ( rFontItem.GetFamilyName() ); + rFont.SetStyleName ( rFontItem.GetStyleName() ); + rFont.SetCharSet ( rFontItem.GetCharSet() ); + rFont.SetPitch ( rFontItem.GetPitch() ); + rFont.SetWeight ( rWeightItem.GetValue() ); + rFont.SetItalic ( rPostureItem.GetValue() ); +} + +void ScAutoFmtPreview::MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt16 nIndex, vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont) +{ + if ( !pCurData ) + return; + + rFont = rCJKFont = rCTLFont = rRenderContext.GetFont(); + Size aFontSize(rFont.GetFontSize().Width(), 10 * rRenderContext.GetDPIScaleFactor()); + + const SvxFontItem* pFontItem = pCurData->GetItem( nIndex, ATTR_FONT ); + const SvxWeightItem* pWeightItem = pCurData->GetItem( nIndex, ATTR_FONT_WEIGHT ); + const SvxPostureItem* pPostureItem = pCurData->GetItem( nIndex, ATTR_FONT_POSTURE ); + const SvxFontItem* pCJKFontItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT ); + const SvxWeightItem* pCJKWeightItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT_WEIGHT ); + const SvxPostureItem* pCJKPostureItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT_POSTURE ); + const SvxFontItem* pCTLFontItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT ); + const SvxWeightItem* pCTLWeightItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT_WEIGHT ); + const SvxPostureItem* pCTLPostureItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT_POSTURE ); + const SvxUnderlineItem* pUnderlineItem = pCurData->GetItem( nIndex, ATTR_FONT_UNDERLINE ); + const SvxOverlineItem* pOverlineItem = pCurData->GetItem( nIndex, ATTR_FONT_OVERLINE ); + const SvxCrossedOutItem* pCrossedOutItem = pCurData->GetItem( nIndex, ATTR_FONT_CROSSEDOUT ); + const SvxContourItem* pContourItem = pCurData->GetItem( nIndex, ATTR_FONT_CONTOUR ); + const SvxShadowedItem* pShadowedItem = pCurData->GetItem( nIndex, ATTR_FONT_SHADOWED ); + const SvxColorItem* pColorItem = pCurData->GetItem( nIndex, ATTR_FONT_COLOR ); + + lcl_SetFontProperties( rFont, *pFontItem, *pWeightItem, *pPostureItem ); + lcl_SetFontProperties( rCJKFont, *pCJKFontItem, *pCJKWeightItem, *pCJKPostureItem ); + lcl_SetFontProperties( rCTLFont, *pCTLFontItem, *pCTLWeightItem, *pCTLPostureItem ); + + Color aColor( pColorItem->GetValue() ); + if( aColor == COL_TRANSPARENT ) + aColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor(); + +#define SETONALLFONTS( MethodName, Value ) \ +rFont.MethodName( Value ); rCJKFont.MethodName( Value ); rCTLFont.MethodName( Value ); + + SETONALLFONTS( SetUnderline, pUnderlineItem->GetValue() ) + SETONALLFONTS( SetOverline, pOverlineItem->GetValue() ) + SETONALLFONTS( SetStrikeout, pCrossedOutItem->GetValue() ) + SETONALLFONTS( SetOutline, pContourItem->GetValue() ) + SETONALLFONTS( SetShadow, pShadowedItem->GetValue() ) + SETONALLFONTS( SetColor, aColor ) + SETONALLFONTS( SetFontSize, aFontSize ) + SETONALLFONTS( SetTransparent, true ) + +#undef SETONALLFONTS +} + +sal_uInt16 ScAutoFmtPreview::GetFormatIndex( size_t nCol, size_t nRow ) const +{ + static const sal_uInt16 pnFmtMap[] = + { + 0, 1, 2, 1, 3, + 4, 5, 6, 5, 7, + 8, 9, 10, 9, 11, + 4, 5, 6, 5, 7, + 12, 13, 14, 13, 15 + }; + return pnFmtMap[ maArray.GetCellIndex( nCol, nRow, mbRTL ) ]; +} + +const SvxBoxItem& ScAutoFmtPreview::GetBoxItem( size_t nCol, size_t nRow ) const +{ + OSL_ENSURE( pCurData, "ScAutoFmtPreview::GetBoxItem - no format data found" ); + return * pCurData->GetItem( GetFormatIndex( nCol, nRow ), ATTR_BORDER ); +} + +const SvxLineItem& ScAutoFmtPreview::GetDiagItem( size_t nCol, size_t nRow, bool bTLBR ) const +{ + OSL_ENSURE( pCurData, "ScAutoFmtPreview::GetDiagItem - no format data found" ); + return * pCurData->GetItem( GetFormatIndex( nCol, nRow ), bTLBR ? ATTR_BORDER_TLBR : ATTR_BORDER_BLTR ); +} + +void ScAutoFmtPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow) +{ + if (!pCurData) + { + return; + } + + // Emit the cell text + + OUString cellString; + bool bNumFormat = pCurData->GetIncludeValueFormat(); + sal_uInt32 nNum; + double nVal; + const Color* pDummy = nullptr; + sal_uInt16 nIndex = static_cast<sal_uInt16>(maArray.GetCellIndex(nCol, nRow, mbRTL)); + + switch (nIndex) + { + case 1: cellString = aStrJan; break; + case 2: cellString = aStrFeb; break; + case 3: cellString = aStrMar; break; + case 5: cellString = aStrNorth; break; + case 10: cellString = aStrMid; break; + case 15: cellString = aStrSouth; break; + case 4: + case 20: cellString = aStrSum; break; + + case 6: + case 8: + case 16: + case 18: nVal = nIndex; + nNum = 5; + goto mknum; + case 17: + case 7: nVal = nIndex; + nNum = 6; + goto mknum; + case 11: + case 12: + case 13: nVal = nIndex; + nNum = 12 == nIndex ? 10 : 9; + goto mknum; + + case 9: nVal = 21; nNum = 7; goto mknum; + case 14: nVal = 36; nNum = 11; goto mknum; + case 19: nVal = 51; nNum = 7; goto mknum; + case 21: nVal = 33; nNum = 13; goto mknum; + case 22: nVal = 36; nNum = 14; goto mknum; + case 23: nVal = 39; nNum = 13; goto mknum; + case 24: nVal = 108; nNum = 15; + mknum: + if (bNumFormat) + { + ScNumFormatAbbrev& rNumFormat = const_cast<ScNumFormatAbbrev&>(pCurData->GetNumFormat(sal_uInt16(nNum))); + nNum = rNumFormat.GetFormatIndex(*pNumFmt); + } + else + nNum = 0; + pNumFmt->GetOutputString(nVal, nNum, cellString, &pDummy); + break; + } + + if (cellString.isEmpty()) + return; + + Size aStrSize; + sal_uInt16 nFmtIndex = GetFormatIndex( nCol, nRow ); + const basegfx::B2DRange cellRange(maArray.GetCellRange( nCol, nRow )); + Point aPos(basegfx::fround(cellRange.getMinX()), basegfx::fround(cellRange.getMinY())); + sal_uInt16 nRightX = 0; + bool bJustify = pCurData->GetIncludeJustify(); + SvxCellHorJustify eJustification; + + SvtScriptedTextHelper aScriptedText(rRenderContext); + + // Justification: + + eJustification = mbRTL ? SvxCellHorJustify::Right : bJustify ? + pCurData->GetItem(nFmtIndex, ATTR_HOR_JUSTIFY)->GetValue() : + SvxCellHorJustify::Standard; + + if (pCurData->GetIncludeFont()) + { + vcl::Font aFont, aCJKFont, aCTLFont; + Size theMaxStrSize; + + MakeFonts(rRenderContext, nFmtIndex, aFont, aCJKFont, aCTLFont); + + theMaxStrSize = Size(basegfx::fround(cellRange.getWidth()), basegfx::fround(cellRange.getHeight())); + theMaxStrSize.AdjustWidth( -(FRAME_OFFSET) ); + theMaxStrSize.AdjustHeight( -(FRAME_OFFSET) ); + + aScriptedText.SetFonts( &aFont, &aCJKFont, &aCTLFont ); + aScriptedText.SetText(cellString, xBreakIter); + aStrSize = aScriptedText.GetTextSize(); + + if (theMaxStrSize.Height() < aStrSize.Height()) + { + // if the string does not fit in the row using this font, + // the default font is used + aScriptedText.SetDefaultFont(); + aStrSize = aScriptedText.GetTextSize(); + } + while((theMaxStrSize.Width() <= aStrSize.Width()) && (cellString.getLength() > 1)) + { + if( eJustification == SvxCellHorJustify::Right ) + cellString = cellString.copy(1); + else + cellString = cellString.copy(0, cellString.getLength() - 1 ); + + aScriptedText.SetText( cellString, xBreakIter ); + aStrSize = aScriptedText.GetTextSize(); + } + } + else + { + aScriptedText.SetDefaultFont(); + aScriptedText.SetText( cellString, xBreakIter ); + aStrSize = aScriptedText.GetTextSize(); + } + + nRightX = sal_uInt16(basegfx::fround(cellRange.getWidth()) - aStrSize.Width() - FRAME_OFFSET); + + // vertical (always center): + + aPos.AdjustY((mnRowHeight - static_cast<sal_uInt16>(aStrSize.Height())) / 2 ); + + // horizontal + + if (eJustification != SvxCellHorJustify::Standard) + { + sal_uInt16 nHorPos = sal_uInt16((basegfx::fround(cellRange.getWidth())-aStrSize.Width()) / 2); + //sal_uInt16 nHorPos = sal_uInt16((basegfx::fround(cellRange.getWidth())-aStrSize.Width()) / 2); + + switch (eJustification) + { + case SvxCellHorJustify::Left: + aPos.AdjustX(FRAME_OFFSET ); + break; + case SvxCellHorJustify::Right: + aPos.AdjustX(nRightX ); + break; + case SvxCellHorJustify::Block: + case SvxCellHorJustify::Repeat: + case SvxCellHorJustify::Center: + aPos.AdjustX(nHorPos ); + break; + // coverity[dead_error_line] - following conditions exist to avoid compiler warning + case SvxCellHorJustify::Standard: + default: + // Standard is not handled here + break; + } + } + else + { + + // Standard justification + + if (nCol == 0 || nRow == 0) + { + // Text label to the left or sum left adjusted + aPos.AdjustX(FRAME_OFFSET ); + } + else + { + // Numbers/Dates right adjusted + aPos.AdjustX(nRightX ); + } + } + aScriptedText.DrawText(aPos); +} + +#undef FRAME_OFFSET + +void ScAutoFmtPreview::DrawBackground(vcl::RenderContext& rRenderContext) +{ + if (!pCurData) + return; + + for(size_t nRow = 0; nRow < 5; ++nRow) + { + for(size_t nCol = 0; nCol < 5; ++nCol) + { + const SvxBrushItem* pItem = + pCurData->GetItem( GetFormatIndex( nCol, nRow ), ATTR_BACKGROUND ); + + rRenderContext.Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor( pItem->GetColor() ); + + const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow )); + rRenderContext.DrawRect( + tools::Rectangle( + basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()), + basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()))); + + rRenderContext.Pop(); + } + } +} + +void ScAutoFmtPreview::PaintCells(vcl::RenderContext& rRenderContext) +{ + if (!pCurData) + return; + + // 1) background + if (pCurData->GetIncludeBackground()) + DrawBackground(rRenderContext); + + // 2) values + for(size_t nRow = 0; nRow < 5; ++nRow) + for(size_t nCol = 0; nCol < 5; ++nCol) + DrawString(rRenderContext, nCol, nRow); + + // 3) border + if (!pCurData->GetIncludeFrame()) + return; + + const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D; + std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D( + drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice( + rRenderContext, + aNewViewInformation2D)); + + pProcessor2D->process(maArray.CreateB2DPrimitiveArray()); + pProcessor2D.reset(); +} + +void ScAutoFmtPreview::Init() +{ + maArray.Initialize( 5, 5 ); + mnLabelColWidth = 0; + mnDataColWidth1 = 0; + mnDataColWidth2 = 0; + mnRowHeight = 0; + CalcCellArray( false ); + CalcLineMap(); +} + +void ScAutoFmtPreview::DetectRTL(const ScViewData& rViewData) +{ + SCTAB nCurrentTab = rViewData.GetTabNo(); + ScDocument& rDoc = rViewData.GetDocument(); + mbRTL = rDoc.IsLayoutRTL(nCurrentTab); + xBreakIter = rDoc.GetBreakIterator(); +} + +void ScAutoFmtPreview::CalcCellArray( bool bFitWidthP ) +{ + maArray.SetXOffset( 2 ); + maArray.SetAllColWidths( bFitWidthP ? mnDataColWidth2 : mnDataColWidth1 ); + maArray.SetColWidth( 0, mnLabelColWidth ); + maArray.SetColWidth( 4, mnLabelColWidth ); + + maArray.SetYOffset( 2 ); + maArray.SetAllRowHeights( mnRowHeight ); + + aPrvSize.setWidth( maArray.GetWidth() + 4 ); + aPrvSize.setHeight( maArray.GetHeight() + 4 ); +} + +static void lclSetStyleFromBorder( svx::frame::Style& rStyle, const ::editeng::SvxBorderLine* pBorder ) +{ + rStyle.Set(pBorder, o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::pt), 5); +} + +void ScAutoFmtPreview::CalcLineMap() +{ + if ( !pCurData ) + return; + + for( size_t nRow = 0; nRow < 5; ++nRow ) + { + for( size_t nCol = 0; nCol < 5; ++nCol ) + { + svx::frame::Style aStyle; + + const SvxBoxItem& rItem = GetBoxItem( nCol, nRow ); + lclSetStyleFromBorder( aStyle, rItem.GetLeft() ); + maArray.SetCellStyleLeft( nCol, nRow, aStyle ); + lclSetStyleFromBorder( aStyle, rItem.GetRight() ); + maArray.SetCellStyleRight( nCol, nRow, aStyle ); + lclSetStyleFromBorder( aStyle, rItem.GetTop() ); + maArray.SetCellStyleTop( nCol, nRow, aStyle ); + lclSetStyleFromBorder( aStyle, rItem.GetBottom() ); + maArray.SetCellStyleBottom( nCol, nRow, aStyle ); + + lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, true ).GetLine() ); + maArray.SetCellStyleTLBR( nCol, nRow, aStyle ); + lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, false ).GetLine() ); + maArray.SetCellStyleBLTR( nCol, nRow, aStyle ); + } + } +} + +void ScAutoFmtPreview::NotifyChange( ScAutoFormatData* pNewData ) +{ + if (pNewData) + { + pCurData = pNewData; + bFitWidth = pNewData->GetIncludeWidthHeight(); + } + + CalcCellArray( bFitWidth ); + CalcLineMap(); + + Invalidate(); +} + +void ScAutoFmtPreview::DoPaint(vcl::RenderContext& rRenderContext) +{ + rRenderContext.Push(vcl::PushFlags::ALL); + DrawModeFlags nOldDrawMode = aVD->GetDrawMode(); + + Size aWndSize(GetOutputSizePixel()); + vcl::Font aFont(aVD->GetFont()); + const Color& aBackCol = SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor; + tools::Rectangle aRect(Point(), aWndSize); + + aFont.SetTransparent( true ); + aVD->SetFont(aFont); + aVD->SetLineColor(); + aVD->SetFillColor(aBackCol); + aVD->SetOutputSize(aWndSize); + aVD->DrawRect(aRect); + + PaintCells(*aVD); + + rRenderContext.SetLineColor(); + rRenderContext.SetFillColor(aBackCol); + rRenderContext.DrawRect(aRect); + + Point aPos((aWndSize.Width() - aPrvSize.Width()) / 2, (aWndSize.Height() - aPrvSize.Height()) / 2); + if (AllSettings::GetLayoutRTL()) + aPos.setX( -aPos.X() ); + rRenderContext.DrawOutDev(aPos, aWndSize, Point(), aWndSize, *aVD); + aVD->SetDrawMode(nOldDrawMode); + rRenderContext.Pop(); +} + +void ScAutoFmtPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +{ + DoPaint(rRenderContext); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/conflictsdlg.cxx b/sc/source/ui/miscdlgs/conflictsdlg.cxx new file mode 100644 index 000000000..3a48325aa --- /dev/null +++ b/sc/source/ui/miscdlgs/conflictsdlg.cxx @@ -0,0 +1,643 @@ +/* -*- 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 <comphelper/string.hxx> +#include <osl/diagnose.h> + +#include <conflictsdlg.hxx> +#include <o3tl/safeint.hxx> +#include <strings.hrc> +#include <scresid.hxx> +#include <viewdata.hxx> +#include <dbfunc.hxx> +#include <chgtrack.hxx> + +// struct ScConflictsListEntry + +bool ScConflictsListEntry::HasSharedAction( sal_uLong nSharedAction ) const +{ + auto aEnd = maSharedActions.cend(); + auto aItr = std::find(maSharedActions.cbegin(), aEnd, nSharedAction); + + return aItr != aEnd; +} + +bool ScConflictsListEntry::HasOwnAction( sal_uLong nOwnAction ) const +{ + auto aEnd = maOwnActions.cend(); + auto aItr = std::find(maOwnActions.cbegin(), aEnd, nOwnAction); + + return aItr != aEnd; +} + + +bool ScConflictsListHelper::HasOwnAction( ScConflictsList& rConflictsList, sal_uLong nOwnAction ) +{ + return std::any_of(rConflictsList.begin(), rConflictsList.end(), + [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); }); +} + +ScConflictsListEntry* ScConflictsListHelper::GetSharedActionEntry( ScConflictsList& rConflictsList, sal_uLong nSharedAction ) +{ + auto aEnd = rConflictsList.end(); + auto aItr = std::find_if(rConflictsList.begin(), aEnd, + [nSharedAction](ScConflictsListEntry& rConflict) { return rConflict.HasSharedAction( nSharedAction ); }); + + if (aItr != aEnd) + return &(*aItr); + + return nullptr; +} + +ScConflictsListEntry* ScConflictsListHelper::GetOwnActionEntry( ScConflictsList& rConflictsList, sal_uLong nOwnAction ) +{ + auto aEnd = rConflictsList.end(); + auto aItr = std::find_if(rConflictsList.begin(), aEnd, + [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); }); + + if (aItr != aEnd) + return &(*aItr); + + return nullptr; +} + +void ScConflictsListHelper::Transform_Impl( std::vector<sal_uLong>& rActionList, ScChangeActionMergeMap* pMergeMap ) +{ + if ( !pMergeMap ) + { + return; + } + + for ( auto aItr = rActionList.begin(); aItr != rActionList.end(); ) + { + ScChangeActionMergeMap::iterator aItrMap = pMergeMap->find( *aItr ); + if ( aItrMap != pMergeMap->end() ) + { + *aItr = aItrMap->second; + ++aItr; + } + else + { + aItr = rActionList.erase( aItr ); + OSL_FAIL( "ScConflictsListHelper::Transform_Impl: erased action from conflicts list!" ); + } + } +} + +void ScConflictsListHelper::TransformConflictsList( ScConflictsList& rConflictsList, + ScChangeActionMergeMap* pSharedMap, ScChangeActionMergeMap* pOwnMap ) +{ + for ( auto& rConflictEntry : rConflictsList ) + { + if ( pSharedMap ) + { + ScConflictsListHelper::Transform_Impl( rConflictEntry.maSharedActions, pSharedMap ); + } + + if ( pOwnMap ) + { + ScConflictsListHelper::Transform_Impl( rConflictEntry.maOwnActions, pOwnMap ); + } + } +} + + +ScConflictsFinder::ScConflictsFinder( ScChangeTrack* pTrack, sal_uLong nStartShared, sal_uLong nEndShared, + sal_uLong nStartOwn, sal_uLong nEndOwn, ScConflictsList& rConflictsList ) + :mpTrack( pTrack ) + ,mnStartShared( nStartShared ) + ,mnEndShared( nEndShared ) + ,mnStartOwn( nStartOwn ) + ,mnEndOwn( nEndOwn ) + ,mrConflictsList( rConflictsList ) +{ +} + +bool ScConflictsFinder::DoActionsIntersect( const ScChangeAction* pAction1, const ScChangeAction* pAction2 ) +{ + return pAction1 && pAction2 && pAction1->GetBigRange().Intersects( pAction2->GetBigRange() ); +} + +ScConflictsListEntry* ScConflictsFinder::GetIntersectingEntry( const ScChangeAction* pAction ) const +{ + auto doActionsIntersect = [this, pAction](const sal_uLong& aAction) { return DoActionsIntersect( mpTrack->GetAction( aAction ), pAction ); }; + + for ( auto& rConflict : mrConflictsList ) + { + if (std::any_of( rConflict.maSharedActions.cbegin(), rConflict.maSharedActions.cend(), doActionsIntersect )) + return &rConflict; + + if (std::any_of( rConflict.maOwnActions.cbegin(), rConflict.maOwnActions.cend(), doActionsIntersect )) + return &rConflict; + } + + return nullptr; +} + +ScConflictsListEntry& ScConflictsFinder::GetEntry( sal_uLong nSharedAction, const std::vector<sal_uLong>& rOwnActions ) +{ + // try to get a list entry which already contains the shared action + ScConflictsListEntry* pEntry = ScConflictsListHelper::GetSharedActionEntry( mrConflictsList, nSharedAction ); + if ( pEntry ) + { + return *pEntry; + } + + // try to get a list entry for which the shared action intersects with any + // other action of this entry + pEntry = GetIntersectingEntry( mpTrack->GetAction( nSharedAction ) ); + if ( pEntry ) + { + pEntry->maSharedActions.push_back( nSharedAction ); + return *pEntry; + } + + // try to get a list entry for which any of the own actions intersects with + // any other action of this entry + for ( auto& rOwnAction : rOwnActions ) + { + pEntry = GetIntersectingEntry( mpTrack->GetAction( rOwnAction ) ); + if ( pEntry ) + { + pEntry->maSharedActions.push_back( nSharedAction ); + return *pEntry; + } + } + + // if no entry was found, create a new one + ScConflictsListEntry aEntry; + aEntry.meConflictAction = SC_CONFLICT_ACTION_NONE; + aEntry.maSharedActions.push_back( nSharedAction ); + mrConflictsList.push_back( aEntry ); + return mrConflictsList.back(); +} + +bool ScConflictsFinder::Find() +{ + if ( !mpTrack ) + { + return false; + } + + bool bReturn = false; + ScChangeAction* pSharedAction = mpTrack->GetAction( mnStartShared ); + while ( pSharedAction && pSharedAction->GetActionNumber() <= mnEndShared ) + { + std::vector<sal_uLong> aOwnActions; + ScChangeAction* pOwnAction = mpTrack->GetAction( mnStartOwn ); + while ( pOwnAction && pOwnAction->GetActionNumber() <= mnEndOwn ) + { + if ( DoActionsIntersect( pSharedAction, pOwnAction ) ) + { + aOwnActions.push_back( pOwnAction->GetActionNumber() ); + } + pOwnAction = pOwnAction->GetNext(); + } + + if ( !aOwnActions.empty() ) + { + ScConflictsListEntry& rEntry = GetEntry(pSharedAction->GetActionNumber(), aOwnActions); + for ( const auto& aOwnAction : aOwnActions ) + { + if (!ScConflictsListHelper::HasOwnAction(mrConflictsList, aOwnAction)) + { + rEntry.maOwnActions.push_back(aOwnAction); + } + } + bReturn = true; + } + + pSharedAction = pSharedAction->GetNext(); + } + + return bReturn; +} + + +ScConflictsResolver::ScConflictsResolver( ScChangeTrack* pTrack, ScConflictsList& rConflictsList ) + :mpTrack ( pTrack ) + ,mrConflictsList ( rConflictsList ) +{ + OSL_ENSURE( mpTrack, "ScConflictsResolver CTOR: mpTrack is null!" ); +} + +void ScConflictsResolver::HandleAction( ScChangeAction* pAction, bool bIsSharedAction, + bool bHandleContentAction, bool bHandleNonContentAction ) +{ + if ( !mpTrack || !pAction ) + { + return; + } + + if ( bIsSharedAction ) + { + ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetSharedActionEntry( + mrConflictsList, pAction->GetActionNumber() ); + if ( pConflictEntry ) + { + ScConflictAction eConflictAction = pConflictEntry->meConflictAction; + if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE ) + { + if ( pAction->GetType() == SC_CAT_CONTENT ) + { + if ( bHandleContentAction ) + { + mpTrack->Reject( pAction ); + } + } + else + { + if ( bHandleNonContentAction ) + { + mpTrack->Reject( pAction ); + } + } + } + } + } + else + { + ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetOwnActionEntry( + mrConflictsList, pAction->GetActionNumber() ); + if ( pConflictEntry ) + { + ScConflictAction eConflictAction = pConflictEntry->meConflictAction; + if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE ) + { + if ( pAction->GetType() == SC_CAT_CONTENT ) + { + if ( bHandleContentAction ) + { + // do nothing + //mpTrack->SelectContent( pAction ); + } + } + else + { + if ( bHandleNonContentAction ) + { + // do nothing + //mpTrack->Accept( pAction ); + } + } + } + else if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_OTHER ) + { + if ( pAction->GetType() == SC_CAT_CONTENT ) + { + if ( bHandleContentAction ) + { + mpTrack->Reject( pAction ); + } + } + else + { + if ( bHandleNonContentAction ) + { + mpTrack->Reject( pAction ); + } + } + } + } + } +} + + +ScConflictsDlg::ScConflictsDlg(weld::Window* pParent, ScViewData* pViewData, ScDocument* pSharedDoc, ScConflictsList& rConflictsList) + : GenericDialogController(pParent, "modules/scalc/ui/conflictsdialog.ui", "ConflictsDialog") + , maStrUnknownUser ( ScResId( STR_UNKNOWN_USER_CONFLICT ) ) + , mpViewData ( pViewData ) + , mpOwnDoc ( nullptr ) + , mpOwnTrack ( nullptr ) + , mpSharedDoc ( pSharedDoc ) + , mpSharedTrack ( nullptr ) + , mrConflictsList ( rConflictsList ) + , maSelectionIdle ( "ScConflictsDlg maSelectionIdle" ) + , mbInSelectHdl ( false ) + , m_xBtnKeepMine(m_xBuilder->weld_button("keepmine")) + , m_xBtnKeepOther(m_xBuilder->weld_button("keepother")) + , m_xBtnKeepAllMine(m_xBuilder->weld_button("keepallmine")) + , m_xBtnKeepAllOthers(m_xBuilder->weld_button("keepallothers")) + , m_xLbConflicts(new SvxRedlinTable(m_xBuilder->weld_tree_view("container"), nullptr)) +{ + OSL_ENSURE( mpViewData, "ScConflictsDlg CTOR: mpViewData is null!" ); + mpOwnDoc = ( mpViewData ? &mpViewData->GetDocument() : nullptr ); + OSL_ENSURE( mpOwnDoc, "ScConflictsDlg CTOR: mpOwnDoc is null!" ); + mpOwnTrack = ( mpOwnDoc ? mpOwnDoc->GetChangeTrack() : nullptr ); + OSL_ENSURE( mpOwnTrack, "ScConflictsDlg CTOR: mpOwnTrack is null!" ); + OSL_ENSURE( mpSharedDoc, "ScConflictsDlg CTOR: mpSharedDoc is null!" ); + mpSharedTrack = ( mpSharedDoc ? mpSharedDoc->GetChangeTrack() : nullptr ); + OSL_ENSURE( mpSharedTrack, "ScConflictsDlg CTOR: mpSharedTrack is null!" ); + + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + + auto nDigitWidth = rTreeView.get_approximate_digit_width(); + std::vector<int> aWidths + { + o3tl::narrowing<int>(nDigitWidth * 60), + o3tl::narrowing<int>(nDigitWidth * 20) + }; + rTreeView.set_column_fixed_widths(aWidths); + + rTreeView.set_selection_mode(SelectionMode::Multiple); + rTreeView.set_size_request(-1, rTreeView.get_height_rows(16)); + + maSelectionIdle.SetInvokeHandler( LINK( this, ScConflictsDlg, UpdateSelectionHdl ) ); + + rTreeView.connect_changed(LINK(this, ScConflictsDlg, SelectHandle)); + + m_xBtnKeepMine->connect_clicked( LINK( this, ScConflictsDlg, KeepMineHandle ) ); + m_xBtnKeepOther->connect_clicked( LINK( this, ScConflictsDlg, KeepOtherHandle ) ); + m_xBtnKeepAllMine->connect_clicked( LINK( this, ScConflictsDlg, KeepAllMineHandle ) ); + m_xBtnKeepAllOthers->connect_clicked( LINK( this, ScConflictsDlg, KeepAllOthersHandle ) ); + + UpdateView(); + + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xEntry)) + rTreeView.select(*xEntry); +} + +ScConflictsDlg::~ScConflictsDlg() +{ +} + +OUString ScConflictsDlg::GetConflictString( const ScConflictsListEntry& rConflictEntry ) +{ + OUString aString; + if ( mpOwnTrack ) + { + const ScChangeAction* pAction = mpOwnTrack->GetAction( rConflictEntry.maOwnActions[ 0 ] ); + if ( pAction && mpOwnDoc ) + { + SCTAB nTab = pAction->GetBigRange().MakeRange( *mpOwnDoc ).aStart.Tab(); + mpOwnDoc->GetName( nTab, aString ); + } + } + return aString; +} + +void ScConflictsDlg::SetActionString(const ScChangeAction* pAction, ScDocument* pDoc, const weld::TreeIter& rEntry) +{ + OSL_ENSURE( pAction, "ScConflictsDlg::GetActionString(): pAction is null!" ); + OSL_ENSURE( pDoc, "ScConflictsDlg::GetActionString(): pDoc is null!" ); + if (!pAction || !pDoc) + return; + + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + OUString aDesc = pAction->GetDescription(*pDoc, true, false); + rTreeView.set_text(rEntry, aDesc, 0); + + OUString aUser = comphelper::string::strip(pAction->GetUser(), ' '); + if ( aUser.isEmpty() ) + { + aUser = maStrUnknownUser; + } + rTreeView.set_text(rEntry, aUser, 1); + + DateTime aDateTime = pAction->GetDateTime(); + OUString aString = ScGlobal::getLocaleData().getDate( aDateTime ) + " " + + ScGlobal::getLocaleData().getTime( aDateTime, false ); + rTreeView.set_text(rEntry, aString, 2); +} + +void ScConflictsDlg::HandleListBoxSelection() +{ + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + bool bSelEntry = rTreeView.get_cursor(xEntry.get()); + if (!bSelEntry) + bSelEntry = rTreeView.get_selected(xEntry.get()); + if (!bSelEntry) + return; + + bool bSelectHandle = rTreeView.is_selected(*xEntry); + + while (rTreeView.get_iter_depth(*xEntry)) + rTreeView.iter_parent(*xEntry); + + if (bSelectHandle) + rTreeView.unselect_all(); + if (!rTreeView.is_selected(*xEntry)) + rTreeView.select(*xEntry); + if (rTreeView.iter_children(*xEntry)) + { + do + { + if (!rTreeView.is_selected(*xEntry)) + rTreeView.select(*xEntry); + } while (rTreeView.iter_next_sibling(*xEntry)); + } +} + +IMPL_LINK_NOARG(ScConflictsDlg, SelectHandle, weld::TreeView&, void) +{ + if (mbInSelectHdl) + return; + + mbInSelectHdl = true; + HandleListBoxSelection(); + maSelectionIdle.Start(); + mbInSelectHdl = false; +} + +IMPL_LINK_NOARG(ScConflictsDlg, UpdateSelectionHdl, Timer *, void) +{ + if ( !mpViewData || !mpOwnDoc ) + { + return; + } + + ScTabView* pTabView = mpViewData->GetView(); + pTabView->DoneBlockMode(); + + std::vector<const ScChangeAction*> aActions; + + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + rTreeView.selected_foreach([&rTreeView, &aActions](weld::TreeIter& rEntry){ + if (rTreeView.get_iter_depth(rEntry)) + { + RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rEntry)); + if (pUserData) + { + ScChangeAction* pAction = static_cast< ScChangeAction* >( pUserData->pData ); + if ( pAction && ( pAction->GetType() != SC_CAT_DELETE_TABS ) && + ( pAction->IsClickable() || pAction->IsVisible() ) ) + { + aActions.push_back(pAction); + } + } + } + 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(*mpOwnDoc)) + { + bool bSetCursor = i == nCount - 1; + pTabView->MarkRange(rBigRange.MakeRange( *mpOwnDoc ), bSetCursor, bContMark); + bContMark = true; + } + } +} + +void ScConflictsDlg::SetConflictAction(const weld::TreeIter& rRootEntry, ScConflictAction eConflictAction) +{ + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rRootEntry)); + ScConflictsListEntry* pConflictEntry = static_cast< ScConflictsListEntry* >( pUserData ? pUserData->pData : nullptr ); + if ( pConflictEntry ) + { + pConflictEntry->meConflictAction = eConflictAction; + } +} + +void ScConflictsDlg::KeepHandler(bool bMine) +{ + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (!rTreeView.get_selected(xEntry.get())) + return; + + while (rTreeView.get_iter_depth(*xEntry)) + rTreeView.iter_parent(*xEntry); + + m_xDialog->set_busy_cursor(true); + ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER ); + SetConflictAction(*xEntry, eConflictAction); + rTreeView.remove(*xEntry); + m_xDialog->set_busy_cursor(false); + if (rTreeView.n_children() == 0) + m_xDialog->response(RET_OK); +} + +void ScConflictsDlg::KeepAllHandler( bool bMine ) +{ + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + if (!rTreeView.get_iter_first(*xEntry)) + return; + + while (rTreeView.get_iter_depth(*xEntry)) + rTreeView.iter_parent(*xEntry); + + m_xDialog->set_busy_cursor(true); + + ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER ); + do + { + SetConflictAction(*xEntry, eConflictAction); + } while (rTreeView.iter_next_sibling(*xEntry)); + + rTreeView.freeze(); + rTreeView.clear(); + rTreeView.thaw(); + + m_xDialog->set_busy_cursor(false); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ScConflictsDlg, KeepMineHandle, weld::Button&, void) +{ + KeepHandler( true ); +} + +IMPL_LINK_NOARG(ScConflictsDlg, KeepOtherHandle, weld::Button&, void) +{ + KeepHandler( false ); +} + +IMPL_LINK_NOARG(ScConflictsDlg, KeepAllMineHandle, weld::Button&, void) +{ + KeepAllHandler( true ); +} + +IMPL_LINK_NOARG(ScConflictsDlg, KeepAllOthersHandle, weld::Button&, void) +{ + KeepAllHandler( false ); +} + +void ScConflictsDlg::UpdateView() +{ + weld::TreeView& rTreeView = m_xLbConflicts->GetWidget(); + for ( ScConflictsListEntry& rConflictEntry : mrConflictsList ) + { + if (rConflictEntry.meConflictAction == SC_CONFLICT_ACTION_NONE) + { + std::unique_ptr<RedlinData> pRootUserData(new RedlinData()); + pRootUserData->pData = static_cast<void*>(&rConflictEntry); + OUString sString(GetConflictString(rConflictEntry)); + OUString sId(weld::toId(pRootUserData.release())); + std::unique_ptr<weld::TreeIter> xRootEntry(rTreeView.make_iterator()); + std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator()); + rTreeView.insert(nullptr, -1, &sString, &sId, nullptr, nullptr, false, xRootEntry.get()); + + for ( const auto& aSharedAction : rConflictEntry.maSharedActions ) + { + ScChangeAction* pAction = mpSharedTrack ? mpSharedTrack->GetAction(aSharedAction) : nullptr; + if ( pAction ) + { + // only display shared top content entries + if ( pAction->GetType() == SC_CAT_CONTENT ) + { + ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent(); + if ( pNextContent && rConflictEntry.HasSharedAction( pNextContent->GetActionNumber() ) ) + { + continue; + } + } + + rTreeView.insert(xRootEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get()); + SetActionString(pAction, mpSharedDoc, *xEntry); + } + } + + for ( const auto& aOwnAction : rConflictEntry.maOwnActions ) + { + ScChangeAction* pAction = mpOwnTrack ? mpOwnTrack->GetAction(aOwnAction) : nullptr; + if ( pAction ) + { + // only display own top content entries + if ( pAction->GetType() == SC_CAT_CONTENT ) + { + ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent(); + if ( pNextContent && rConflictEntry.HasOwnAction( pNextContent->GetActionNumber() ) ) + { + continue; + } + } + + std::unique_ptr<RedlinData> pUserData(new RedlinData()); + pUserData->pData = static_cast< void* >( pAction ); + OUString aId(weld::toId(pUserData.release())); + rTreeView.insert(xRootEntry.get(), -1, nullptr, &aId, nullptr, nullptr, false, xEntry.get()); + SetActionString(pAction, mpOwnDoc, *xEntry); + } + } + + rTreeView.expand_row(*xRootEntry); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/crdlg.cxx b/sc/source/ui/miscdlgs/crdlg.cxx new file mode 100644 index 000000000..9d778595e --- /dev/null +++ b/sc/source/ui/miscdlgs/crdlg.cxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <crdlg.hxx> +#include <scui_def.hxx> + +ScColOrRowDlg::ScColOrRowDlg(weld::Window* pParent, const OUString& rStrTitle, + const OUString& rStrLabel) + : GenericDialogController(pParent, "modules/scalc/ui/colorrowdialog.ui", "ColOrRowDialog") + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xBtnRows(m_xBuilder->weld_radio_button("rows")) + , m_xBtnCols(m_xBuilder->weld_radio_button("columns")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + m_xDialog->set_title(rStrTitle); + m_xFrame->set_label(rStrLabel); + m_xBtnOk->connect_clicked(LINK(this, ScColOrRowDlg, OkHdl)); +} + +ScColOrRowDlg::~ScColOrRowDlg() {} + +IMPL_LINK_NOARG(ScColOrRowDlg, OkHdl, weld::Button&, void) +{ + m_xDialog->response(m_xBtnCols->get_active() ? SCRET_COLS : SCRET_ROWS); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/crnrdlg.cxx b/sc/source/ui/miscdlgs/crnrdlg.cxx new file mode 100644 index 000000000..38a0cfe66 --- /dev/null +++ b/sc/source/ui/miscdlgs/crnrdlg.cxx @@ -0,0 +1,800 @@ +/* -*- 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 <reffact.hxx> +#include <document.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <docsh.hxx> +#include <crnrdlg.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <o3tl/string_view.hxx> +#include <memory> + +namespace +{ + void ERRORBOX(weld::Window* pParent, const OUString& rString) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent, + VclMessageType::Warning, VclButtonsType::Ok, + rString)); + xBox->run(); + } + + int QUERYBOX(weld::Window* pParent, const OUString& rString) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent, + VclMessageType::Question, VclButtonsType::YesNo, + rString)); + xBox->set_default_response(RET_YES); + return xBox->run(); + } + +} + +const sal_uLong nEntryDataCol = 0; +const sal_uLong nEntryDataRow = 1; +const sal_uLong nEntryDataDelim = 2; + + +// note: some of the initialisation is done in Init +ScColRowNameRangesDlg::ScColRowNameRangesDlg( SfxBindings* pB, + SfxChildWindow* pCW, + weld::Window* pParent, + ScViewData& rViewData ) + + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/namerangesdialog.ui", "NameRangesDialog") + , m_rViewData(rViewData) + , rDoc(rViewData.GetDocument()) + , bDlgLostFocus(false) + , m_pEdActive(nullptr) + , m_xLbRange(m_xBuilder->weld_tree_view("range")) + , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("edassign"))) + , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("rbassign"))) + , m_xBtnColHead(m_xBuilder->weld_radio_button("colhead")) + , m_xBtnRowHead(m_xBuilder->weld_radio_button("rowhead")) + , m_xEdAssign2(new formula::RefEdit(m_xBuilder->weld_entry("edassign2"))) + , m_xRbAssign2(new formula::RefButton(m_xBuilder->weld_button("rbassign2"))) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnRemove(m_xBuilder->weld_button("delete")) + , m_xRangeFrame(m_xBuilder->weld_frame("rangeframe")) + , m_xRangeFT(m_xRangeFrame->weld_label_widget()) + , m_xDataFT(m_xBuilder->weld_label("datarange")) +{ + m_xRbAssign->SetReferences(this, m_xEdAssign.get()); + m_xEdAssign->SetReferences(this, m_xRangeFT.get()); + m_xRbAssign2->SetReferences(this, m_xEdAssign2.get()); + m_xEdAssign2->SetReferences(this, m_xDataFT.get()); + + xColNameRanges = rDoc.GetColNameRanges()->Clone(); + xRowNameRanges = rDoc.GetRowNameRanges()->Clone(); + Init(); +} + +ScColRowNameRangesDlg::~ScColRowNameRangesDlg() +{ +} + +// initialises event handlers and start parameters in the dialog +void ScColRowNameRangesDlg::Init() +{ + m_xBtnOk->connect_clicked ( LINK( this, ScColRowNameRangesDlg, OkBtnHdl ) ); + m_xBtnCancel->connect_clicked ( LINK( this, ScColRowNameRangesDlg, CancelBtnHdl ) ); + m_xBtnAdd->connect_clicked ( LINK( this, ScColRowNameRangesDlg, AddBtnHdl ) ); + m_xBtnRemove->connect_clicked ( LINK( this, ScColRowNameRangesDlg, RemoveBtnHdl ) ); + m_xLbRange->connect_changed( LINK( this, ScColRowNameRangesDlg, Range1SelectHdl ) ); + m_xEdAssign->SetModifyHdl ( LINK( this, ScColRowNameRangesDlg, Range1DataModifyHdl ) ); + m_xBtnColHead->connect_toggled ( LINK( this, ScColRowNameRangesDlg, ColRowToggleHdl ) ); + m_xEdAssign2->SetModifyHdl ( LINK( this, ScColRowNameRangesDlg, Range2DataModifyHdl ) ); + + Link<formula::RefEdit&,void> aEditLink = LINK( this, ScColRowNameRangesDlg, GetEditFocusHdl ); + m_xEdAssign->SetGetFocusHdl( aEditLink ); + m_xEdAssign2->SetGetFocusHdl( aEditLink ); + + Link<formula::RefButton&,void> aButtonLink = LINK( this, ScColRowNameRangesDlg, GetButtonFocusHdl ); + m_xRbAssign->SetGetFocusHdl( aButtonLink ); + m_xRbAssign2->SetGetFocusHdl( aButtonLink ); + + aEditLink = LINK( this, ScColRowNameRangesDlg, LoseEditFocusHdl ); + m_xEdAssign->SetLoseFocusHdl( aEditLink ); + m_xEdAssign2->SetLoseFocusHdl( aEditLink ); + + aButtonLink = LINK( this, ScColRowNameRangesDlg, LoseButtonFocusHdl ); + m_xRbAssign2->SetLoseFocusHdl( aButtonLink ); + m_xRbAssign->SetLoseFocusHdl( aButtonLink ); + + m_pEdActive = m_xEdAssign.get(); + + UpdateNames(); + + SCCOL nStartCol = 0; + SCROW nStartRow = 0; + SCTAB nStartTab = 0; + SCCOL nEndCol = 0; + SCROW nEndRow = 0; + SCTAB nEndTab = 0; + m_rViewData.GetSimpleArea(nStartCol, nStartRow, nStartTab, + nEndCol, nEndRow, nEndTab ); + SetColRowData( ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab)); + + m_xBtnColHead->set_sensitive(true); + m_xBtnRowHead->set_sensitive(true); + m_xEdAssign->GetWidget()->set_sensitive(true); + m_xEdAssign->GrabFocus(); + m_xRbAssign->GetWidget()->set_sensitive(true); + + Range1SelectHdl( *m_xLbRange ); +} + +// set data range of a labeled range to default values and set the +// form elements for the reference +void ScColRowNameRangesDlg::SetColRowData( const ScRange& rLabelRange, bool bRef) +{ + theCurData = theCurArea = rLabelRange; + bool bValid = true; + SCCOL nCol1 = theCurArea.aStart.Col(); + SCCOL nCol2 = theCurArea.aEnd.Col(); + SCROW nRow1 = theCurArea.aStart.Row(); + SCROW nRow2 = theCurArea.aEnd.Row(); + if ( (static_cast<SCCOLROW>(nCol2 - nCol1) >= nRow2 - nRow1) || (nCol1 == 0 && nCol2 == rDoc.MaxCol()) ) + { // Column headers and the limiting case of the whole sheet + m_xBtnColHead->set_active(true); + m_xBtnRowHead->set_active(false); + if ( nRow2 == rDoc.MaxRow() ) + { + if ( nRow1 == 0 ) + bValid = false; // limiting case of the whole sheet + else + { // Header at bottom, data above + theCurData.aStart.SetRow( 0 ); + theCurData.aEnd.SetRow( nRow1 - 1 ); + } + } + else + { // Header at top, data below + theCurData.aStart.SetRow( nRow2 + 1 ); + theCurData.aEnd.SetRow( rDoc.MaxRow() ); + } + } + else + { // Column headers + m_xBtnRowHead->set_active(true); + m_xBtnColHead->set_active(false); + if ( nCol2 == rDoc.MaxCol() ) + { // Header at the right, data to the left + theCurData.aStart.SetCol( 0 ); + theCurData.aEnd.SetCol( nCol2 - 1 ); + } + else + { // Header at the left, data to the right + theCurData.aStart.SetCol( nCol2 + 1 ); + theCurData.aEnd.SetCol( rDoc.MaxCol() ); + } + } + if ( bValid ) + { + const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention(); + OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv)); + + if(bRef) + m_xEdAssign->SetRefString( aStr ); + else + m_xEdAssign->SetText( aStr ); + + m_xEdAssign->SetCursorAtLast(); + aStr = theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv); + + if(bRef) + m_xEdAssign2->SetRefString( aStr ); + else + m_xEdAssign2->SetText( aStr ); + } + else + { + theCurData = theCurArea = ScRange(); + + if(bRef) + { + m_xEdAssign->SetRefString( OUString() ); + m_xEdAssign2->SetRefString( OUString() ); + } + else + { + m_xEdAssign->SetText( OUString() ); + m_xEdAssign2->SetText( OUString() ); + } + + m_xBtnColHead->set_sensitive(false); + m_xBtnRowHead->set_sensitive(false); + m_xEdAssign2->GetWidget()->set_sensitive(false); + m_xRbAssign2->GetWidget()->set_sensitive(false); + } +} + +// adjust label range and set the data reference form element +void ScColRowNameRangesDlg::AdjustColRowData( const ScRange& rDataRange, bool bRef) +{ + theCurData = rDataRange; + if ( m_xBtnColHead->get_active() ) + { // Data range is the same columns as the header + theCurData.aStart.SetCol( theCurArea.aStart.Col() ); + theCurData.aEnd.SetCol( theCurArea.aEnd.Col() ); + if ( theCurData.Intersects( theCurArea ) ) + { + SCROW nRow1 = theCurArea.aStart.Row(); + SCROW nRow2 = theCurArea.aEnd.Row(); + if ( nRow1 > 0 + && (theCurData.aEnd.Row() < nRow2 || nRow2 == rDoc.MaxRow()) ) + { // Data above header + theCurData.aEnd.SetRow( nRow1 - 1 ); + if ( theCurData.aStart.Row() > theCurData.aEnd.Row() ) + theCurData.aStart.SetRow( theCurData.aEnd.Row() ); + } + else + { // Data below header + theCurData.aStart.SetRow( nRow2 + 1 ); + if ( theCurData.aStart.Row() > theCurData.aEnd.Row() ) + theCurData.aEnd.SetRow( theCurData.aStart.Row() ); + } + } + } + else + { // Data range in the same rows as header + theCurData.aStart.SetRow( theCurArea.aStart.Row() ); + theCurData.aEnd.SetRow( theCurArea.aEnd.Row() ); + if ( theCurData.Intersects( theCurArea ) ) + { + SCCOL nCol1 = theCurArea.aStart.Col(); + SCCOL nCol2 = theCurArea.aEnd.Col(); + if ( nCol1 > 0 + && (theCurData.aEnd.Col() < nCol2 || nCol2 == rDoc.MaxCol()) ) + { // Data left of header + theCurData.aEnd.SetCol( nCol1 - 1 ); + if ( theCurData.aStart.Col() > theCurData.aEnd.Col() ) + theCurData.aStart.SetCol( theCurData.aEnd.Col() ); + } + else + { // Data right of header + theCurData.aStart.SetCol( nCol2 + 1 ); + if ( theCurData.aStart.Col() > theCurData.aEnd.Col() ) + theCurData.aEnd.SetCol( theCurData.aStart.Col() ); + } + } + } + OUString aStr(theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention())); + + if(bRef) + m_xEdAssign2->SetRefString( aStr ); + else + m_xEdAssign2->SetText( aStr ); + + m_xEdAssign2->SetCursorAtLast(); +} + +// Set the reference to a cell range selected with the mouse and update +// the selection form element +void ScColRowNameRangesDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ ) +{ + if ( !m_pEdActive ) + return; + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart( m_pEdActive ); + + if (m_pEdActive == m_xEdAssign.get()) + SetColRowData( rRef, true ); + else + AdjustColRowData( rRef, true ); + m_xBtnColHead->set_sensitive(true); + m_xBtnRowHead->set_sensitive(true); + m_xBtnAdd->set_sensitive(true); + m_xBtnRemove->set_sensitive(false); +} + +void ScColRowNameRangesDlg::Close() +{ + DoClose( ScColRowNameRangesDlgWrapper::GetChildWindowId() ); +} + +void ScColRowNameRangesDlg::SetActive() +{ + if ( bDlgLostFocus ) + { + bDlgLostFocus = false; + if( m_pEdActive ) + m_pEdActive->GrabFocus(); + } + else + m_xDialog->grab_focus(); + + if( m_pEdActive == m_xEdAssign.get() ) + Range1DataModifyHdl( *m_xEdAssign ); + else if( m_pEdActive == m_xEdAssign2.get() ) + Range2DataModifyHdl( *m_xEdAssign2 ); + + RefInputDone(); +} + +void ScColRowNameRangesDlg::UpdateNames() +{ + m_xLbRange->freeze(); + + m_xLbRange->clear(); + aRangeMap.clear(); + m_xEdAssign->SetText( OUString() ); + + size_t nCount, j; + + SCCOL nCol1; + SCROW nRow1; //Extension for range names + SCTAB nTab1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab2; + OUString rString; + const ScAddress::Details aDetails(rDoc.GetAddressConvention()); + + OUString strDelim(" --- "); + OUString aString = strDelim + ScResId( STR_COLUMN ) + strDelim; + m_xLbRange->append(OUString::number(nEntryDataDelim), aString); + if ( xColNameRanges->size() > 0 ) + { + std::vector<const ScRangePair*> aSortArray(xColNameRanges->CreateNameSortedArray( + rDoc )); + nCount = aSortArray.size(); + for ( j=0; j < nCount; j++ ) + { + const ScRange aRange(aSortArray[j]->GetRange(0)); + aString = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aDetails); + + //@008 get range parameters from document + aSortArray[j]->GetRange(0).GetVars( nCol1, nRow1, nTab1, + nCol2, nRow2, nTab2 ); + SCCOL q=nCol1+3; + if(q>nCol2) q=nCol2; + //@008 construct string + OUStringBuffer strShow = " ["; + rString = rDoc.GetString(nCol1, nRow1, nTab1); + strShow.append(rString); + for(SCCOL i=nCol1+1;i<=q;i++) + { + strShow.append(", "); + rString = rDoc.GetString(i, nRow1, nTab1); + strShow.append(rString); + } + if(q<nCol2) // Too long? Add ",..." + { + strShow.append(", ..."); + } + strShow.append("]"); + + //@008 Add string to listbox + OUString aInsStr = aString + strShow; + aRangeMap.emplace( aInsStr, aRange ); + m_xLbRange->append(OUString::number(nEntryDataCol), aInsStr); + } + } + aString = strDelim + ScResId( STR_ROW ) + strDelim; + m_xLbRange->append(OUString::number(nEntryDataDelim), aString); + if ( xRowNameRanges->size() > 0 ) + { + std::vector<const ScRangePair*> aSortArray(xRowNameRanges->CreateNameSortedArray( + rDoc )); + nCount = aSortArray.size(); + for ( j=0; j < nCount; j++ ) + { + const ScRange aRange(aSortArray[j]->GetRange(0)); + aString = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aDetails); + + //@008 Build string for rows below + aSortArray[j]->GetRange(0).GetVars( nCol1, nRow1, nTab1, + nCol2, nRow2, nTab2 ); + SCROW q=nRow1+3; + if(q>nRow2) q=nRow2; + OUStringBuffer strShow = " ["; + rString = rDoc.GetString(nCol1, nRow1, nTab1); + strShow.append(rString); + for(SCROW i=nRow1+1;i<=q;i++) + { + strShow.append(", "); + rString = rDoc.GetString(nCol1, i, nTab1); + strShow.append(rString); + } + if(q<nRow2) + { + strShow.append(", ..."); + } + strShow.append("]"); + + OUString aInsStr = aString + strShow; + aRangeMap.emplace( aInsStr, aRange ); + m_xLbRange->append(OUString::number(nEntryDataRow), aInsStr); + } + } + + m_xLbRange->thaw(); +} + +void ScColRowNameRangesDlg::UpdateRangeData( const ScRange& rRange, bool bColName ) +{ + ScRangePair* pPair = nullptr; + bool bFound = false; + if ( bColName && (pPair = xColNameRanges->Find( rRange )) != nullptr ) + bFound = true; + else if ( !bColName && (pPair = xRowNameRanges->Find( rRange )) != nullptr ) + bFound = true; + + if ( bFound ) + { + const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention(); + theCurArea = rRange; + OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv)); + m_xEdAssign->SetText( aStr ); + m_xBtnAdd->set_sensitive(false); + m_xBtnRemove->set_sensitive(true); + m_xBtnColHead->set_active(bColName); + m_xBtnRowHead->set_active(!bColName); + theCurData = pPair->GetRange(1); + aStr = theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv); + m_xEdAssign2->SetText( aStr ); + } + else + { + m_xBtnAdd->set_sensitive(true); + m_xBtnRemove->set_sensitive(false); + } + m_xBtnColHead->set_sensitive(true); + m_xBtnRowHead->set_sensitive(true); + m_xEdAssign2->GetWidget()->set_sensitive(true); + m_xRbAssign2->GetWidget()->set_sensitive(true); +} + +bool ScColRowNameRangesDlg::IsRefInputMode() const +{ + return (m_pEdActive != nullptr); +} + +// Handler: + +// handler called when OK is clicked, calls the add button handler before +// passing the range lists to the document +IMPL_LINK_NOARG(ScColRowNameRangesDlg, OkBtnHdl, weld::Button&, void) +{ + AddBtnHdl(*m_xBtnAdd); + + // assign RangeLists to the references in the document + rDoc.GetColNameRangesRef() = xColNameRanges; + rDoc.GetRowNameRangesRef() = xRowNameRanges; + // changed ranges need to take effect + rDoc.CompileColRowNameFormula(); + ScDocShell* pDocShell = m_rViewData.GetDocShell(); + pDocShell->PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid); + pDocShell->SetDocumentModified(); + + response(RET_OK); +} + +IMPL_LINK_NOARG(ScColRowNameRangesDlg, CancelBtnHdl, weld::Button&, void) +{ + response(RET_CANCEL); +} + +// handler called when add button clicked: set ranges and add to listbox +IMPL_LINK_NOARG(ScColRowNameRangesDlg, AddBtnHdl, weld::Button&, void) +{ + OUString aNewArea( m_xEdAssign->GetText() ); + OUString aNewData( m_xEdAssign2->GetText() ); + + if (aNewArea.isEmpty() || aNewData.isEmpty()) + return; + + const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention(); + ScRange aRange1, aRange2; + bool bOk1 = (aRange1.ParseAny( aNewArea, rDoc, eConv ) & ScRefFlags::VALID) == ScRefFlags::VALID; + if ( bOk1 && (aRange2.ParseAny( aNewData, rDoc, eConv ) & ScRefFlags::VALID) == ScRefFlags::VALID) + { + theCurArea = aRange1; + AdjustColRowData( aRange2 ); + ScRangePair* pPair; + if ( ( pPair = xColNameRanges->Find( theCurArea ) ) != nullptr ) + { + xColNameRanges->Remove( *pPair ); + } + if ( ( pPair = xRowNameRanges->Find( theCurArea ) ) != nullptr ) + { + xRowNameRanges->Remove( *pPair ); + } + if ( m_xBtnColHead->get_active() ) + xColNameRanges->Join( ScRangePair( theCurArea, theCurData ) ); + else + xRowNameRanges->Join( ScRangePair( theCurArea, theCurData ) ); + + UpdateNames(); + + m_xEdAssign->GrabFocus(); + m_xBtnAdd->set_sensitive(false); + m_xBtnRemove->set_sensitive(false); + m_xEdAssign->SetText( OUString() ); + m_xBtnColHead->set_active(true); + m_xBtnRowHead->set_active(false); + m_xEdAssign2->SetText( OUString() ); + theCurArea = ScRange(); + theCurData = theCurArea; + Range1SelectHdl( *m_xLbRange ); + } + else + { + ERRORBOX(m_xDialog.get(), ScResId(STR_INVALIDTABNAME)); + if ( !bOk1 ) + m_xEdAssign->GrabFocus(); + else + m_xEdAssign2->GrabFocus(); + } +} + +IMPL_LINK_NOARG(ScColRowNameRangesDlg, RemoveBtnHdl, weld::Button&, void) +{ + OUString aRangeStr = m_xLbRange->get_selected_text(); + sal_Int32 nSelectPos = m_xLbRange->get_selected_index(); + bool bColName = nSelectPos != -1 && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataCol; + NameRangeMap::const_iterator itr = aRangeMap.find(aRangeStr); + if (itr == aRangeMap.end()) + return; + const ScRange& rRange = itr->second; + + ScRangePair* pPair = nullptr; + bool bFound = false; + if ( bColName && (pPair = xColNameRanges->Find( rRange )) != nullptr ) + bFound = true; + else if ( !bColName && (pPair = xRowNameRanges->Find( rRange )) != nullptr ) + bFound = true; + if ( !bFound ) + return; + + OUString aStrDelMsg = ScResId( STR_QUERY_DELENTRY ); + OUString aMsg = o3tl::getToken(aStrDelMsg, 0, '#' ) + + aRangeStr + + o3tl::getToken(aStrDelMsg, 1, '#' ); + + if (RET_YES != QUERYBOX(m_xDialog.get(), aMsg)) + return; + + if ( bColName ) + xColNameRanges->Remove( *pPair ); + else + xRowNameRanges->Remove( *pPair ); + + UpdateNames(); + const sal_Int32 nCnt = m_xLbRange->n_children(); + if ( nSelectPos >= nCnt ) + { + if ( nCnt ) + nSelectPos = nCnt - 1; + else + nSelectPos = 0; + } + m_xLbRange->select(nSelectPos); + if (nSelectPos && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataDelim) + m_xLbRange->select( --nSelectPos ); // ---Row--- + + m_xLbRange->grab_focus(); + m_xBtnAdd->set_sensitive(false); + m_xBtnRemove->set_sensitive(false); + m_xEdAssign->SetText( OUString() ); + theCurArea = theCurData = ScRange(); + m_xBtnColHead->set_active(true); + m_xBtnRowHead->set_active(false); + m_xEdAssign2->SetText( OUString() ); + Range1SelectHdl( *m_xLbRange ); +} + +// handler called when a row in the listbox is selected, updates form input fields +IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range1SelectHdl, weld::TreeView&, void) +{ + sal_Int32 nSelectPos = m_xLbRange->get_selected_index(); + const sal_Int32 nCnt = m_xLbRange->n_children(); + sal_uInt16 nMoves = 0; + while (nSelectPos != -1 && nSelectPos < nCnt && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataDelim) + { // skip Delimiter + ++nMoves; + ++nSelectPos; + } + OUString aRangeStr = m_xLbRange->get_selected_text(); + if ( nMoves ) + { + if ( nSelectPos > 1 && nSelectPos >= nCnt ) + { // if entries exist before the " --- Row --- " Delimiter then + // do not stop at the delimiter + nSelectPos = nCnt - 2; + m_xLbRange->select(nSelectPos); + aRangeStr = m_xLbRange->get_selected_text(); + } + else if ( nSelectPos > 2 && nSelectPos < nCnt && !aRangeStr.isEmpty() + && aRangeStr == m_xEdAssign->GetText() ) + { // move upwards instead of below to the previous position + nSelectPos -= 2; + m_xLbRange->select( nSelectPos ); + aRangeStr = m_xLbRange->get_selected_text(); + } + else + m_xLbRange->select(nSelectPos); + } + NameRangeMap::const_iterator itr = aRangeMap.find(aRangeStr); + if ( itr != aRangeMap.end() ) + { + bool bColName = m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataCol; + UpdateRangeData( itr->second, bColName ); + m_xBtnAdd->set_sensitive(false); + m_xBtnRemove->set_sensitive(true); + } + else + { + if ( !m_xEdAssign->GetText().isEmpty() ) + { + if ( !m_xEdAssign2->GetText().isEmpty() ) + m_xBtnAdd->set_sensitive(true); + else + m_xBtnAdd->set_sensitive(false); + m_xBtnColHead->set_sensitive(true); + m_xBtnRowHead->set_sensitive(true); + m_xEdAssign2->GetWidget()->set_sensitive(true); + m_xRbAssign2->GetWidget()->set_sensitive(true); + } + else + { + m_xBtnAdd->set_sensitive(false); + m_xBtnColHead->set_sensitive(false); + m_xBtnRowHead->set_sensitive(false); + m_xEdAssign2->GetWidget()->set_sensitive(false); + m_xRbAssign2->GetWidget()->set_sensitive(false); + } + m_xBtnRemove->set_sensitive(false); + m_xEdAssign->GrabFocus(); + } + + m_xEdAssign->GetWidget()->set_sensitive(true); + m_xRbAssign->GetWidget()->set_sensitive(true); +} + +// handler called when the label range has changed +IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range1DataModifyHdl, formula::RefEdit&, void) +{ + OUString aNewArea( m_xEdAssign->GetText() ); + bool bValid = false; + if (!aNewArea.isEmpty()) + { + ScRange aRange; + if ( (aRange.ParseAny(aNewArea, rDoc, rDoc.GetAddressConvention() ) & ScRefFlags::VALID) == ScRefFlags::VALID) + { + SetColRowData( aRange ); + bValid = true; + } + } + if ( bValid ) + { + m_xBtnAdd->set_sensitive(true); + m_xBtnColHead->set_sensitive(true); + m_xBtnRowHead->set_sensitive(true); + m_xEdAssign2->GetWidget()->set_sensitive(true); + m_xRbAssign2->GetWidget()->set_sensitive(true); + } + else + { + m_xBtnAdd->set_sensitive(false); + m_xBtnColHead->set_sensitive(false); + m_xBtnRowHead->set_sensitive(false); + m_xEdAssign2->GetWidget()->set_sensitive(false); + m_xRbAssign2->GetWidget()->set_sensitive(false); + } + m_xBtnRemove->set_sensitive(false); +} + +// handler called when the data range has changed +IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range2DataModifyHdl, formula::RefEdit&, void) +{ + OUString aNewData( m_xEdAssign2->GetText() ); + if ( !aNewData.isEmpty() ) + { + ScRange aRange; + if ( (aRange.ParseAny(aNewData, rDoc, rDoc.GetAddressConvention() ) & ScRefFlags::VALID) == ScRefFlags::VALID) + { + AdjustColRowData( aRange ); + m_xBtnAdd->set_sensitive(true); + } + else + m_xBtnAdd->set_sensitive(false); + } + else + { + m_xBtnAdd->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(ScColRowNameRangesDlg, ColRowToggleHdl, weld::Toggleable&, void) +{ + if (m_xBtnColHead->get_active()) + { + // handler for the radio button for columns, adjust ranges + if ( theCurArea.aStart.Row() == 0 && theCurArea.aEnd.Row() == rDoc.MaxRow() ) + { + theCurArea.aEnd.SetRow( rDoc.MaxRow() - 1 ); + OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention())); + m_xEdAssign->SetText( aStr ); + } + ScRange aRange( theCurData ); + aRange.aStart.SetRow( std::min( static_cast<tools::Long>(theCurArea.aEnd.Row() + 1), static_cast<tools::Long>(rDoc.MaxRow()) ) ); + aRange.aEnd.SetRow( rDoc.MaxRow() ); + AdjustColRowData( aRange ); + } + else if (m_xBtnRowHead->get_active()) + { + // handler for the radio button for columns, adjust range + if ( theCurArea.aStart.Col() == 0 && theCurArea.aEnd.Col() == rDoc.MaxCol() ) + { + theCurArea.aEnd.SetCol( rDoc.MaxCol() - 1 ); + OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention())); + m_xEdAssign->SetText( aStr ); + } + ScRange aRange( theCurData ); + aRange.aStart.SetCol( static_cast<SCCOL>(std::min( static_cast<tools::Long>(theCurArea.aEnd.Col() + 1), static_cast<tools::Long>(rDoc.MaxCol()) )) ); + aRange.aEnd.SetCol( rDoc.MaxCol() ); + AdjustColRowData( aRange ); + } +} + +IMPL_LINK( ScColRowNameRangesDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void ) +{ + if (&rCtrl == m_xEdAssign.get()) + m_pEdActive = m_xEdAssign.get(); + else if (&rCtrl == m_xEdAssign2.get()) + m_pEdActive = m_xEdAssign2.get(); + else + m_pEdActive = nullptr; + + if( m_pEdActive ) + m_pEdActive->SelectAll(); +} + +IMPL_LINK( ScColRowNameRangesDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void ) +{ + if (&rCtrl == m_xRbAssign.get()) + m_pEdActive = m_xEdAssign.get(); + else if (&rCtrl == m_xRbAssign2.get()) + m_pEdActive = m_xEdAssign2.get(); + else + m_pEdActive = nullptr; + + if( m_pEdActive ) + m_pEdActive->SelectAll(); +} + +IMPL_LINK_NOARG(ScColRowNameRangesDlg, LoseEditFocusHdl, formula::RefEdit&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(ScColRowNameRangesDlg, LoseButtonFocusHdl, formula::RefButton&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/datafdlg.cxx b/sc/source/ui/miscdlgs/datafdlg.cxx new file mode 100644 index 000000000..0ed421cba --- /dev/null +++ b/sc/source/ui/miscdlgs/datafdlg.cxx @@ -0,0 +1,355 @@ +/* -*- 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/. + */ + +#undef SC_DLLIMPLEMENTATION + +#include <datafdlg.hxx> +#include <viewdata.hxx> +#include <docsh.hxx> +#include <tabvwsh.hxx> + +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> + +ScDataFormDlg::ScDataFormDlg(weld::Window* pParent, ScTabViewShell* pTabViewShellOri) + : GenericDialogController(pParent, "modules/scalc/ui/dataform.ui", "DataFormDialog") + , pTabViewShell(pTabViewShellOri) + , aColLength(0) + , nCurrentRow(0) + , nStartCol(0) + , nEndCol(0) + , nStartRow(0) + , nEndRow(0) + , nTab(0) + , m_xBtnNew(m_xBuilder->weld_button("new")) + , m_xBtnDelete(m_xBuilder->weld_button("delete")) + , m_xBtnRestore(m_xBuilder->weld_button("restore")) + , m_xBtnPrev(m_xBuilder->weld_button("prev")) + , m_xBtnNext(m_xBuilder->weld_button("next")) + , m_xBtnClose(m_xBuilder->weld_button("close")) + , m_xSlider(m_xBuilder->weld_scrolled_window("scrollbar", true)) + , m_xGrid(m_xBuilder->weld_container("grid")) + , m_xFixedText(m_xBuilder->weld_label("label")) +{ + sNewRecord = m_xFixedText->get_label(); + + //read header from current document, and add new controls + OSL_ENSURE( pTabViewShell, "pTabViewShell is NULL! :-/" ); + ScViewData& rViewData = pTabViewShell->GetViewData(); + + pDoc = &rViewData.GetDocument(); + + { + ScRange aRange; + rViewData.GetSimpleArea( aRange ); + ScAddress aStart = aRange.aStart; + ScAddress aEnd = aRange.aEnd; + + nStartCol = aStart.Col(); + nEndCol = aEnd.Col(); + nStartRow = aStart.Row(); + nEndRow = aEnd.Row(); + + nTab = rViewData.GetTabNo(); + bool bNoSelection(false); + //if there is no selection + if ((nStartCol == nEndCol) && (nStartRow == nEndRow)) + bNoSelection = true; + + if (bNoSelection) + { + //find last not blank cell in row + for (int i=1;i<=MAX_DATAFORM_COLS;i++) + { + nEndCol++; + OUString aColName = pDoc->GetString(nEndCol, nStartRow, nTab); + int nColWidth = pDoc->GetColWidth( nEndCol, nTab ); + if (aColName.isEmpty() && nColWidth) + { + nEndCol--; + break; + } + } + + //find first not blank cell in row + for (int i=1;i<=MAX_DATAFORM_COLS;i++) + { + if (nStartCol <= 0) + break; + nStartCol--; + + OUString aColName = pDoc->GetString(nStartCol, nStartRow, nTab); + int nColWidth = pDoc->GetColWidth( nEndCol, nTab ); + if (aColName.isEmpty() && nColWidth) + { + nStartCol++; + break; + } + } + + //skip leading hide column + for (int i=1;i<=MAX_DATAFORM_COLS;i++) + { + int nColWidth = pDoc->GetColWidth( nStartCol, nTab ); + if (nColWidth) + break; + nStartCol++; + } + + if (nEndCol < nStartCol) + nEndCol = nStartCol; + + //find last not blank cell in row + for (int i=1;i<=MAX_DATAFORM_ROWS;i++) + { + nEndRow++; + OUString aColName = pDoc->GetString(nStartCol, nEndRow, nTab); + if (aColName.isEmpty()) + { + nEndRow--; + break; + } + } + + //find first not blank cell in row + for (int i=1;i<=MAX_DATAFORM_ROWS;i++) + { + if (nStartRow <= 0) + break; + nStartRow--; + + OUString aColName = pDoc->GetString(nStartCol, nStartRow, nTab); + if (aColName.isEmpty()) + { + nStartRow++; + break; + } + } + + if (nEndRow < nStartRow) + nEndRow = nStartRow; + } + + nCurrentRow = nStartRow + 1; + + aColLength = nEndCol - nStartCol + 1; + + //new the controls + m_aEntries.reserve(aColLength); + + sal_Int32 nGridRow = 0; + for(sal_uInt16 nIndex = 0; nIndex < aColLength; ++nIndex) + { + OUString aFieldName = pDoc->GetString(nIndex + nStartCol, nStartRow, nTab); + int nColWidth = pDoc->GetColWidth( nIndex + nStartCol, nTab ); + if (nColWidth) + { + m_aEntries.emplace_back(new ScDataFormFragment(m_xGrid.get(), nGridRow)); + + ++nGridRow; + + m_aEntries[nIndex]->m_xLabel->set_label(aFieldName); + m_aEntries[nIndex]->m_xLabel->show(); + m_aEntries[nIndex]->m_xEdit->show(); + } + else + { + m_aEntries.emplace_back(nullptr ); + } + if (m_aEntries[nIndex] != nullptr) + { + m_aEntries[nIndex]->m_xEdit->connect_changed(LINK( this, ScDataFormDlg, Impl_DataModifyHdl)); + m_aEntries[nIndex]->m_xEdit->save_value(); + } + } + } + + FillCtrls(); + + m_xSlider->vadjustment_configure(0, 0, nEndRow - nStartRow + 1, 1, 10, 1); + + m_xBtnNew->connect_clicked(LINK( this, ScDataFormDlg, Impl_NewHdl)); + m_xBtnPrev->connect_clicked(LINK( this, ScDataFormDlg, Impl_PrevHdl)); + m_xBtnNext->connect_clicked(LINK( this, ScDataFormDlg, Impl_NextHdl)); + + m_xBtnRestore->connect_clicked(LINK( this, ScDataFormDlg, Impl_RestoreHdl)); + m_xBtnDelete->connect_clicked(LINK( this, ScDataFormDlg, Impl_DeleteHdl)); + m_xBtnClose->connect_clicked(LINK( this, ScDataFormDlg, Impl_CloseHdl)); + + m_xSlider->connect_vadjustment_changed(LINK( this, ScDataFormDlg, Impl_ScrollHdl)); + + SetButtonState(); +} + +ScDataFormDlg::~ScDataFormDlg() +{ +} + +void ScDataFormDlg::FillCtrls() +{ + for (sal_uInt16 i = 0; i < aColLength; ++i) + { + if (m_aEntries[i]) + { + if (nCurrentRow<=nEndRow && pDoc) + { + OUString aFieldName(pDoc->GetString(i + nStartCol, nCurrentRow, nTab)); + m_aEntries[i]->m_xEdit->set_text(aFieldName); + } + else + m_aEntries[i]->m_xEdit->set_text(OUString()); + } + } + + if (nCurrentRow <= nEndRow) + { + OUString sLabel = + OUString::number(static_cast<sal_Int32>(nCurrentRow - nStartRow)) + + " / " + + OUString::number(static_cast<sal_Int32>(nEndRow - nStartRow)); + m_xFixedText->set_label(sLabel); + } + else + m_xFixedText->set_label(sNewRecord); + + m_xSlider->vadjustment_set_value(nCurrentRow-nStartRow-1); +} + +IMPL_LINK( ScDataFormDlg, Impl_DataModifyHdl, weld::Entry&, rEdit, void) +{ + if (rEdit.get_value_changed_from_saved()) + m_xBtnRestore->set_sensitive(true); +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_NewHdl, weld::Button&, void) +{ + ScViewData& rViewData = pTabViewShell->GetViewData(); + ScDocShell* pDocSh = rViewData.GetDocShell(); + if ( !pDoc ) + return; + + bool bHasData = std::any_of(m_aEntries.begin(), m_aEntries.end(), + [](const std::unique_ptr<ScDataFormFragment>& rElem) { return (rElem != nullptr) && (!rElem->m_xEdit->get_text().isEmpty()); }); + + if ( !bHasData ) + return; + + pTabViewShell->DataFormPutData(nCurrentRow, nStartRow, nStartCol, nEndRow, nEndCol, m_aEntries, aColLength); + nCurrentRow++; + if (nCurrentRow >= nEndRow + 2) + { + nEndRow++; + m_xSlider->vadjustment_set_upper(nEndRow - nStartRow + 1); + } + SetButtonState(); + FillCtrls(); + pDocSh->SetDocumentModified(); + pDocSh->PostPaintGridAll(); +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_PrevHdl, weld::Button&, void) +{ + if (pDoc) + { + if ( nCurrentRow > nStartRow +1 ) + nCurrentRow--; + + SetButtonState(); + FillCtrls(); + } +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_NextHdl, weld::Button&, void) +{ + if (pDoc) + { + if ( nCurrentRow <= nEndRow) + nCurrentRow++; + + SetButtonState(); + FillCtrls(); + } +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_RestoreHdl, weld::Button&, void) +{ + if (pDoc) + { + FillCtrls(); + } +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_DeleteHdl, weld::Button&, void) +{ + ScViewData& rViewData = pTabViewShell->GetViewData(); + ScDocShell* pDocSh = rViewData.GetDocShell(); + if (!pDoc) + return; + + ScRange aRange(nStartCol, nCurrentRow, nTab, nEndCol, nCurrentRow, nTab); + pDoc->DeleteRow(aRange); + nEndRow--; + + SetButtonState(); + pDocSh->GetUndoManager()->Clear(); + + FillCtrls(); + pDocSh->SetDocumentModified(); + pDocSh->PostPaintGridAll(); +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_CloseHdl, weld::Button&, void) +{ + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(ScDataFormDlg, Impl_ScrollHdl, weld::ScrolledWindow&, void) +{ + auto nOffset = m_xSlider->vadjustment_get_value(); + nCurrentRow = nStartRow + nOffset + 1; + SetButtonState(); + FillCtrls(); +} + +void ScDataFormDlg::SetButtonState() +{ + if (nCurrentRow > nEndRow) + { + m_xBtnDelete->set_sensitive( false ); + m_xBtnNext->set_sensitive( false ); + } + else + { + m_xBtnDelete->set_sensitive(true); + m_xBtnNext->set_sensitive(true); + } + + if (nCurrentRow == nStartRow + 1) + m_xBtnPrev->set_sensitive( false ); + else + m_xBtnPrev->set_sensitive(true); + + m_xBtnRestore->set_sensitive( false ); + if (!m_aEntries.empty() && m_aEntries[0] != nullptr) + m_aEntries[0]->m_xEdit->grab_focus(); +} + +ScDataFormFragment::ScDataFormFragment(weld::Container* pGrid, int nLine) + : m_xBuilder(Application::CreateBuilder(pGrid, "modules/scalc/ui/dataformfragment.ui")) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xEdit(m_xBuilder->weld_entry("entry")) +{ + m_xLabel->set_grid_left_attach(0); + m_xLabel->set_grid_top_attach(nLine); + + m_xEdit->set_grid_left_attach(1); + m_xEdit->set_grid_top_attach(nLine); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/dataproviderdlg.cxx b/sc/source/ui/miscdlgs/dataproviderdlg.cxx new file mode 100644 index 000000000..f26e2ae7a --- /dev/null +++ b/sc/source/ui/miscdlgs/dataproviderdlg.cxx @@ -0,0 +1,1125 @@ +/* -*- 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/. + */ + +#include <dataproviderdlg.hxx> + +#include <document.hxx> +#include <dataprovider.hxx> +#include <datatransformation.hxx> +#include <datamapper.hxx> +#include <dbdata.hxx> + +#include <comphelper/string.hxx> +#include <sal/log.hxx> +#include <sfx2/filedlghelper.hxx> +#include <unotools/charclass.hxx> +#include <vcl/svapp.hxx> + +#include <utility> + +class ScDataTransformationBaseControl +{ +protected: + std::unique_ptr<weld::Builder> mxBuilder; + std::unique_ptr<weld::Container> mxGrid; + weld::Container* mpContainer; + + sal_uInt32 mnIndex; + +public: + ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex); + virtual ~ScDataTransformationBaseControl(); + + void updateIndex(sal_uInt32 nIndex) { mnIndex = nIndex; } + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() = 0; + + static SCROW getLastRow(const ScDocument& rDoc); + static SCCOL getLastCol(const ScDocument& rDoc); +}; + +SCROW ScDataTransformationBaseControl::getLastRow(const ScDocument& rDoc) +{ + SCROW nEndRow = rDoc.MaxRow(); + return rDoc.GetLastDataRow(0, 0, 0, nEndRow); +} + +SCCOL ScDataTransformationBaseControl::getLastCol(const ScDocument& rDoc) +{ + for (SCCOL nCol = 1; nCol <= rDoc.MaxCol(); ++nCol) + { + if (rDoc.GetCellType(nCol, 0, 0) == CELLTYPE_NONE) + { + return static_cast<SCCOL>(nCol - 1 ); + } + } + return rDoc.MaxCol(); +} + +ScDataTransformationBaseControl::ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex) + : mxBuilder(Application::CreateBuilder(pParent, rUIFile)) + , mxGrid(mxBuilder->weld_container("grid")) + , mpContainer(pParent) + , mnIndex(nIndex) +{ +} + +ScDataTransformationBaseControl::~ScDataTransformationBaseControl() +{ + mpContainer->move(mxGrid.get(), nullptr); +} + +namespace { + +struct MenuData +{ + const char* aTransformationName; + std::function<void(ScDataProviderDlg*)> maCallback; +}; + +MenuData aTransformationData[] = { + { "Delete Column", &ScDataProviderDlg::deleteColumn }, + { "Delete Row", &ScDataProviderDlg::deleteRowTransformation}, + { "Swap Rows", &ScDataProviderDlg::swapRowsTransformation}, + { "Split Column", &ScDataProviderDlg::splitColumn }, + { "Merge Columns", &ScDataProviderDlg::mergeColumns }, + { "Text Transformation", &ScDataProviderDlg::textTransformation }, + { "Sort Columns", &ScDataProviderDlg::sortTransformation }, + { "Aggregate Functions", &ScDataProviderDlg::aggregateFunction}, + { "Number Transformations", &ScDataProviderDlg::numberTransformation }, + { "Replace Null Transformations", &ScDataProviderDlg::replaceNullTransformation }, + { "Date & Time Transformations", &ScDataProviderDlg::dateTimeTransformation }, + { "Find Replace Transformation", &ScDataProviderDlg::findReplaceTransformation} +}; + +class ScDeleteColumnTransformationControl : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScDeleteColumnTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 aIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScDeleteColumnTransformationControl::ScDeleteColumnTransformationControl( + const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/deletecolumnentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScDeleteColumnTransformationControl, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScDeleteColumnTransformationControl::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> ColNums; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + ColNums.insert(nCol - 1); + } + + return std::make_shared<sc::ColumnRemoveTransformation>(std::move(ColNums)); +} + +class ScSplitColumnTransformationControl : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxSeparator; + std::unique_ptr<weld::Entry> mxNumColumns; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScSplitColumnTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScSplitColumnTransformationControl::ScSplitColumnTransformationControl( + const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/splitcolumnentry.ui", nIndex) + , mxSeparator(mxBuilder->weld_entry("ed_separator")) + , mxNumColumns(mxBuilder->weld_entry("num_cols")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScSplitColumnTransformationControl, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScSplitColumnTransformationControl::getTransformation() +{ + OUString aSeparator = mxSeparator->get_text(); + sal_Unicode cSeparator = aSeparator.isEmpty() ? ',' : aSeparator[0]; + OUString aColStr = mxNumColumns->get_text(); + SCCOL mnCol = -1; + sal_Int32 nCol = aColStr.toInt32(); + if (nCol > 0 && nCol <= mpDoc->MaxCol()) + mnCol = nCol - 1; + return std::make_shared<sc::SplitColumnTransformation>(mnCol, cSeparator); +} + +class ScMergeColumnTransformationControl : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxSeparator; + std::unique_ptr<weld::Entry> mxEdColumns; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScMergeColumnTransformationControl(const ScDocument *pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScMergeColumnTransformationControl::ScMergeColumnTransformationControl( + const ScDocument* pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/mergecolumnentry.ui", nIndex) + , mxSeparator(mxBuilder->weld_entry("ed_separator")) + , mxEdColumns(mxBuilder->weld_entry("ed_columns")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScMergeColumnTransformationControl, DeleteHdl)); + + OUStringBuffer aBuffer; + + // map from zero based to one based column numbers + aBuffer.append(static_cast<sal_Int32>(nStartCol + 1)); + for ( SCCOL nCol = nStartCol + 1; nCol <= nEndCol; ++nCol) + { + aBuffer.append(";" + OUString::number(nCol + 1)); + } + + mxEdColumns->set_text(aBuffer.makeStringAndClear()); +} + +std::shared_ptr<sc::DataTransformation> ScMergeColumnTransformationControl::getTransformation() +{ + OUString aColumnString = mxEdColumns->get_text(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aMergedColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aMergedColumns.insert(nCol - 1); + } + return std::make_shared<sc::MergeColumnTransformation>(std::move(aMergedColumns), mxSeparator->get_text()); +} + +class ScSortTransformationControl : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::ComboBox> mxType; + std::unique_ptr<weld::Entry> mxEdColumns; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScSortTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScSortTransformationControl::ScSortTransformationControl( + const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/sorttransformationentry.ui", nIndex) + , mxType(mxBuilder->weld_combo_box("ed_ascending")) + , mxEdColumns(mxBuilder->weld_entry("ed_columns")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScSortTransformationControl, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScSortTransformationControl::getTransformation() +{ + OUString aColStr = mxEdColumns->get_text(); + bool aIsAscending = mxType->get_active(); + SCCOL aColumn = 0; + sal_Int32 nCol = aColStr.toInt32(); + if (nCol > 0 && nCol <= mpDoc->MaxCol()) + aColumn = nCol - 1; // translate from 1-based column notations to internal Calc one + + ScSortParam aSortParam; + aSortParam.nRow1=0; + aSortParam.nRow2=getLastRow(*mpDoc); + aSortParam.nCol1=0; + aSortParam.nCol2=getLastCol(*mpDoc); + aSortParam.maKeyState[0].bDoSort = true; + aSortParam.maKeyState[0].nField = aColumn; + aSortParam.maKeyState[0].bAscending = aIsAscending; + return std::make_shared<sc::SortTransformation>(aSortParam); +} + +class ScColumnTextTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::ComboBox> mxType; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScColumnTextTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScColumnTextTransformation::ScColumnTextTransformation( + const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/texttransformationentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxType(mxBuilder->weld_combo_box("ed_lst")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScColumnTextTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScColumnTextTransformation::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aColumns.insert(nCol - 1); + } + + sal_Int32 nPos = mxType->get_active(); + switch (nPos) + { + case 0: + return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TO_LOWER); + case 1: + return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TO_UPPER); + case 2: + return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::CAPITALIZE); + case 3: + return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TRIM); + default: + assert(false); + } + + return nullptr; +} + +class ScAggregateFunction : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::ComboBox> mxType; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScAggregateFunction::ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/aggregatefunctionentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxType(mxBuilder->weld_combo_box("ed_lst")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScAggregateFunction, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScAggregateFunction::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + sal_Int32 nPos = mxType->get_active(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aColumns.insert(nCol - 1); + } + switch (nPos) + { + case 0: + return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::SUM); + case 1: + return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::AVERAGE); + case 2: + return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::MIN); + case 3: + return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::MAX); + default: + assert(false); + } + + return nullptr; +} + +class ScNumberTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::ComboBox> mxType; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScNumberTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScNumberTransformation::ScNumberTransformation( + const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/numbertransformationentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxType(mxBuilder->weld_combo_box("ed_lst")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScNumberTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScNumberTransformation::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + sal_Int32 nPos = mxType->get_active(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aColumns.insert(nCol - 1); + } + switch (nPos) + { + case 0: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SIGN); + case 1: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND); + case 2: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND_UP); + case 3: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN); + case 4: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE); + case 5: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::LOG_E); + case 6: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::LOG_10); + case 7: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::CUBE); + case 8: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SQUARE); + case 9: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT); + case 10: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::EXPONENT); + case 11: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::IS_EVEN); + case 12: + return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::IS_ODD); + default: + assert(false); + } + + return nullptr; +} + +class ScReplaceNullTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::Entry> mxReplaceString; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument *mpDoc; + +public: + + ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScReplaceNullTransformation::ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/replacenulltransformationentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxReplaceString(mxBuilder->weld_entry("ed_str")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(aDeleteTransformation) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScReplaceNullTransformation, DeleteHdl)); +} + + +std::shared_ptr<sc::DataTransformation> ScReplaceNullTransformation::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + OUString aReplaceWithString = mxReplaceString->get_text(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aColumns.insert(nCol - 1); + } + + return std::make_shared<sc::ReplaceNullTransformation>(std::move(aColumns),aReplaceWithString); +} + +class ScDateTimeTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxColumnNums; + std::unique_ptr<weld::ComboBox> mxType; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + + ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScDateTimeTransformation::ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/datetimetransformationentry.ui", nIndex) + , mxColumnNums(mxBuilder->weld_entry("ed_columns")) + , mxType(mxBuilder->weld_combo_box("ed_lst")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(aDeleteTransformation) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this,ScDateTimeTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScDateTimeTransformation::getTransformation() +{ + OUString aColumnString = mxColumnNums->get_text(); + sal_Int32 nPos = mxType->get_active(); + std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';'); + std::set<SCCOL> aColumns; + for (const auto& rColStr : aSplitColumns) + { + sal_Int32 nCol = rColStr.toInt32(); + if (nCol <= 0) + continue; + + if (nCol > mpDoc->MaxCol()) + continue; + + // translate from 1-based column notations to internal Calc one + aColumns.insert(nCol - 1); + } + switch (nPos) + { + case 0: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING); + case 1: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::YEAR); + case 2: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR); + case 3: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR); + case 4: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MONTH); + case 5: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME); + case 6: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH); + case 7: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH); + case 8: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY); + case 9: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK); + case 10: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR); + case 11: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::QUARTER); + case 12: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER); + case 13: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER); + case 14: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::HOUR); + case 15: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MINUTE); + case 16: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::SECOND); + case 17: + return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::TIME); + default: + assert(false); + } + + return nullptr; +} + +class ScFindReplaceTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxFindString; + std::unique_ptr<weld::Entry> mxReplaceString; + std::unique_ptr<weld::Entry> mxEdColumns; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScFindReplaceTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScFindReplaceTransformation::ScFindReplaceTransformation( + const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/findreplaceentry.ui", nIndex) + , mxFindString(mxBuilder->weld_entry("ed_find")) + , mxReplaceString(mxBuilder->weld_entry("ed_replace")) + , mxEdColumns(mxBuilder->weld_entry("ed_columns")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this, ScFindReplaceTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScFindReplaceTransformation::getTransformation() +{ + OUString aColStr = mxEdColumns->get_text(); + SCCOL aColumn = -1; + sal_Int32 nCol = aColStr.toInt32(); + if (nCol > 0 && nCol <= mpDoc->MaxCol()) + aColumn = nCol - 1; + return std::make_shared<sc::FindReplaceTransformation>(aColumn, mxFindString->get_text(), mxReplaceString->get_text()); +} + +class ScDeleteRowTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxFindString; + std::unique_ptr<weld::Entry> mxEdColumns; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScDeleteRowTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScDeleteRowTransformation::ScDeleteRowTransformation( + const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/deleterowentry.ui", nIndex) + , mxFindString(mxBuilder->weld_entry("ed_find")) + , mxEdColumns(mxBuilder->weld_entry("ed_columns")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this, ScDeleteRowTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScDeleteRowTransformation::getTransformation() +{ + OUString aColStr = mxEdColumns->get_text(); + SCCOL aColumn = -1; + sal_Int32 nCol = aColStr.toInt32(); + if (nCol > 0 && nCol <= mpDoc->MaxCol()) + aColumn = nCol - 1; + return std::make_shared<sc::DeleteRowTransformation>(aColumn, mxFindString->get_text()); +} + +class ScSwapRowsTransformation : public ScDataTransformationBaseControl +{ +private: + std::unique_ptr<weld::Entry> mxRow; + std::unique_ptr<weld::Entry> nxRow; + std::unique_ptr<weld::Button> mxDelete; + std::function<void(sal_uInt32&)> maDeleteTransformation; + const ScDocument* mpDoc; + +public: + ScSwapRowsTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation); + + virtual std::shared_ptr<sc::DataTransformation> getTransformation() override; + DECL_LINK(DeleteHdl, weld::Button&, void); +}; + +ScSwapRowsTransformation::ScSwapRowsTransformation( + const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, + std::function<void(sal_uInt32&)> aDeleteTransformation) + : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/swaprowsentry.ui", nIndex) + , mxRow(mxBuilder->weld_entry("ed_row1")) + , nxRow(mxBuilder->weld_entry("ed_row2")) + , mxDelete(mxBuilder->weld_button("ed_delete")) + , maDeleteTransformation(std::move(aDeleteTransformation)) + , mpDoc(pDoc) +{ + mxDelete->connect_clicked(LINK(this, ScSwapRowsTransformation, DeleteHdl)); +} + +std::shared_ptr<sc::DataTransformation> ScSwapRowsTransformation::getTransformation() +{ + OUString aRowStr = mxRow->get_text(); + OUString bRowStr = nxRow->get_text(); + SCROW aRow = -1; + SCROW bRow = -1; + sal_Int32 mRow = aRowStr.toInt32(); + sal_Int32 nRow = bRowStr.toInt32(); + if (mRow > 0 && mRow <= mpDoc->MaxRow()) + aRow = mRow - 1; + if (nRow > 0 && nRow <= mpDoc->MaxRow()) + bRow = nRow - 1; + return std::make_shared<sc::SwapRowsTransformation>(aRow, bRow); +} + +} + +ScDataProviderDlg::ScDataProviderDlg(weld::Window* pParent, std::shared_ptr<ScDocument> pDoc, + const ScDocument* pDocument) + : GenericDialogController(pParent, "modules/scalc/ui/dataproviderdlg.ui", "dataproviderdlg") + , mxDoc(std::move(pDoc)) + , mxBox(m_xBuilder->weld_container("data_table")) + , m_xTableParent(mxBox->CreateChildFrame()) + , mxTable(VclPtr<ScDataTableView>::Create(m_xTableParent, mxDoc)) + , mxDBRanges(m_xBuilder->weld_combo_box("select_db_range")) + , mxOKBtn(m_xBuilder->weld_button("okay")) + , mxCancelBtn(m_xBuilder->weld_button("cancel")) + , mxAddTransformationBtn(m_xBuilder->weld_button("add_transformation")) + , mxScroll(m_xBuilder->weld_scrolled_window("scroll")) + , mxTransformationList(m_xBuilder->weld_container("transformation_ctrl")) + , mxTransformationBox(m_xBuilder->weld_combo_box("transformation_box")) + , mxProviderList(m_xBuilder->weld_combo_box("provider_lst")) + , mxEditURL(m_xBuilder->weld_entry("ed_url")) + , mxEditID(m_xBuilder->weld_entry("ed_id")) + , mxApplyBtn(m_xBuilder->weld_button("apply")) + , mxBrowseBtn(m_xBuilder->weld_button("browse")) + , maIdle("ScDataProviderDlg maIdle") + , mnIndex(0) +{ + Size aPrefSize = mxTable->GetOptimalSize(); + mxBox->set_size_request(aPrefSize.Width(), aPrefSize.Height()); + mxTable->Show(); + + ScDBCollection* pDBCollection = pDocument->GetDBCollection(); + auto& rNamedDBs = pDBCollection->getNamedDBs(); + for (auto& rNamedDB : rNamedDBs) + { + mxDBRanges->append_text(rNamedDB->GetName()); + } + + for (const auto& i : aTransformationData) + { + mxTransformationBox->append_text(OUString::createFromAscii(i.aTransformationName)); + } + + pDBData = new ScDBData("data", 0, 0, 0, mxDoc->MaxCol(), mxDoc->MaxRow()); + bool bSuccess = mxDoc->GetDBCollection()->getNamedDBs().insert(std::unique_ptr<ScDBData>(pDBData)); + SAL_WARN_IF(!bSuccess, "sc", "temporary warning"); + + auto aDataProvider = sc::DataProviderFactory::getDataProviders(); + for (const auto& rDataProvider : aDataProvider) + { + mxProviderList->append_text(rDataProvider); + } + + mxOKBtn->connect_clicked(LINK(this, ScDataProviderDlg, ApplyQuitHdl)); + mxCancelBtn->connect_clicked(LINK(this, ScDataProviderDlg, CancelQuitHdl)); + mxAddTransformationBtn->connect_clicked(LINK(this, ScDataProviderDlg, TransformationListHdl)); + mxApplyBtn->connect_clicked(LINK(this, ScDataProviderDlg, ApplyBtnHdl)); + mxBrowseBtn->connect_clicked(LINK(this, ScDataProviderDlg, BrowseBtnHdl)); + mxTransformationBox->connect_changed(LINK(this, ScDataProviderDlg, TransformationSelectHdl)); + mxProviderList->connect_changed(LINK(this, ScDataProviderDlg, ProviderSelectHdl)); + mxEditID->connect_changed(LINK(this, ScDataProviderDlg, IDEditHdl)); + mxEditURL->connect_changed(LINK(this, ScDataProviderDlg, URLEditHdl)); + + msApplyTooltip = mxApplyBtn->get_tooltip_text(); + msAddTransformationToolTip = mxAddTransformationBtn->get_tooltip_text(); + mxAddTransformationBtn->set_sensitive(false); + mxAddTransformationBtn->set_tooltip_text(OUString()); + isValid(); + + maIdle.SetPriority( TaskPriority::LOWEST ); + maIdle.SetInvokeHandler( LINK( this, ScDataProviderDlg, ScrollToEnd) ); +} + +ScDataProviderDlg::~ScDataProviderDlg() +{ + mxTable.disposeAndClear(); + m_xTableParent->dispose(); + m_xTableParent.clear(); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, ScrollToEnd, Timer*, void) +{ + mxScroll->vadjustment_set_value(mxScroll->vadjustment_get_upper()); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, ApplyQuitHdl, weld::Button&, void) +{ + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, CancelQuitHdl, weld::Button&, void) +{ + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, TransformationListHdl, weld::Button&, void) +{ + OUString transformation_string = mxTransformationBox->get_active_text(); + for (auto& i: aTransformationData) + { + if (transformation_string == OUString::createFromAscii(i.aTransformationName)) + { + i.maCallback(this); + maIdle.Start(); + return; + } + } +} + +IMPL_LINK_NOARG(ScDataProviderDlg, ProviderSelectHdl, weld::ComboBox&, void) +{ + isValid(); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, IDEditHdl, weld::Entry&, void) +{ + isValid(); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, URLEditHdl, weld::Entry&, void) +{ + isValid(); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, ApplyBtnHdl, weld::Button&, void) +{ + updateApplyBtn(true); + import(*mxDoc, true); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, BrowseBtnHdl, weld::Button&, void) +{ + sfx2::FileDialogHelper aFileDialog(0, FileDialogFlags::NONE, m_xDialog.get()); + aFileDialog.SetContext(sfx2::FileDialogHelper::CalcDataProvider); + if (aFileDialog.Execute() != ERRCODE_NONE) + return; + + mxEditURL->set_text(aFileDialog.GetPath()); + isValid(); +} + +IMPL_LINK_NOARG(ScDataProviderDlg, TransformationSelectHdl, weld::ComboBox&, void) +{ + mxAddTransformationBtn->set_sensitive(true); + mxAddTransformationBtn->set_tooltip_text(msAddTransformationToolTip); +} + +sc::ExternalDataSource ScDataProviderDlg::getDataSource(ScDocument* pDoc) +{ + OUString aURL = mxEditURL->get_text(); + OUString aProvider = mxProviderList->get_active_text(); + sc::ExternalDataSource aSource(aURL, aProvider, pDoc); + + OUString aID = mxEditID->get_text(); + aSource.setID(aID); + return aSource; +} + +void ScDataProviderDlg::isValid() +{ + bool bValid = !mxProviderList->get_active_text().isEmpty(); + bValid &= !mxEditURL->get_text().isEmpty(); + updateApplyBtn(bValid); +} + +void ScDataProviderDlg::updateApplyBtn(bool bValidConfig) +{ + if (!bValidConfig) + { + mxApplyBtn->set_sensitive(false); + mxApplyBtn->set_tooltip_text(OUString()); + return; + } + + mxApplyBtn->set_sensitive(true); + mxApplyBtn->set_tooltip_text(msApplyTooltip); +} + +void ScDataProviderDlg::deleteColumn() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScDeleteColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::splitColumn() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScSplitColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::mergeColumns() +{ + SCCOL nStartCol = -1; + SCCOL nEndCol = -1; + mxTable->getColRange(nStartCol, nEndCol); + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScMergeColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), nStartCol, nEndCol, mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::textTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScColumnTextTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::sortTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScSortTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::aggregateFunction() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScAggregateFunction>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::numberTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScNumberTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::replaceNullTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScReplaceNullTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::dateTimeTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScDateTimeTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::findReplaceTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScFindReplaceTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::deleteRowTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScDeleteRowTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +void ScDataProviderDlg::swapRowsTransformation() +{ + std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1); + maControls.emplace_back(std::make_unique<ScSwapRowsTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation)); +} + +namespace { + +bool hasDBName(const OUString& rName, ScDBCollection* pDBCollection) +{ + if (pDBCollection->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName))) + return true; + + return false; +} + +} + +void ScDataProviderDlg::import(ScDocument& rDoc, bool bInternal) +{ + sc::ExternalDataSource aSource = getDataSource(&rDoc); + + for (size_t i = 0; i < maControls.size(); ++i) + { + ScDataTransformationBaseControl* pTransformationCtrl = maControls[i].get(); + aSource.AddDataTransformation(pTransformationCtrl->getTransformation()); + } + if (bInternal) + aSource.setDBData(pDBData->GetName()); + else + { + aSource.setDBData(mxDBRanges->get_active_text()); + if (!hasDBName(aSource.getDBName(), rDoc.GetDBCollection())) + return; + rDoc.GetExternalDataMapper().insertDataSource(aSource); + } + aSource.refresh(&rDoc, true); + mxTable->Invalidate(); +} + +void ScDataProviderDlg::deletefromList(sal_uInt32 nIndex) +{ + auto itr = maControls.erase(maControls.begin() + nIndex); + while (itr != maControls.end()) + { + (*itr)->updateIndex(nIndex++); + ++itr; + } + --mnIndex; +} + +IMPL_LINK_NOARG(ScDeleteColumnTransformationControl, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScSplitColumnTransformationControl, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScMergeColumnTransformationControl, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScNumberTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScAggregateFunction, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScSortTransformationControl, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScColumnTextTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScReplaceNullTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScDateTimeTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScFindReplaceTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScDeleteRowTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} + +IMPL_LINK_NOARG(ScSwapRowsTransformation, DeleteHdl, weld::Button&, void) +{ + maDeleteTransformation(mnIndex); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/datastreamdlg.cxx b/sc/source/ui/miscdlgs/datastreamdlg.cxx new file mode 100644 index 000000000..cd03a3e66 --- /dev/null +++ b/sc/source/ui/miscdlgs/datastreamdlg.cxx @@ -0,0 +1,178 @@ +/* -*- 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/. + */ + +#include <datastreamdlg.hxx> + +#include <sfx2/filedlghelper.hxx> +#include <svtools/inettbc.hxx> +#include <address.hxx> +#include <docsh.hxx> +#include <datastream.hxx> + +namespace sc +{ +DataStreamDlg::DataStreamDlg(ScDocShell* pDocShell, weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/datastreams.ui", "DataStreamDialog") + , m_pDocShell(pDocShell) + , m_xCbUrl(new SvtURLBox(m_xBuilder->weld_combo_box("url"))) + , m_xBtnBrowse(m_xBuilder->weld_button("browse")) + , m_xRBValuesInLine(m_xBuilder->weld_radio_button("valuesinline")) + , m_xRBAddressValue(m_xBuilder->weld_radio_button("addressvalue")) + , m_xCBRefreshOnEmpty(m_xBuilder->weld_check_button("refresh_ui")) + , m_xRBDataDown(m_xBuilder->weld_radio_button("datadown")) + , m_xRBRangeDown(m_xBuilder->weld_radio_button("rangedown")) + , m_xRBNoMove(m_xBuilder->weld_radio_button("nomove")) + , m_xRBMaxLimit(m_xBuilder->weld_radio_button("maxlimit")) + , m_xRBUnlimited(m_xBuilder->weld_radio_button("unlimited")) + , m_xEdRange(m_xBuilder->weld_entry("range")) + , m_xEdLimit(m_xBuilder->weld_entry("limit")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xVclFrameLimit(m_xBuilder->weld_frame("framelimit")) + , m_xVclFrameMove(m_xBuilder->weld_frame("framemove")) +{ + m_xCbUrl->connect_changed(LINK(this, DataStreamDlg, UpdateComboBoxHdl)); + m_xRBAddressValue->connect_toggled(LINK(this, DataStreamDlg, UpdateClickHdl)); + m_xRBAddressValue->set_sensitive(false); + m_xRBNoMove->hide(); + m_xRBValuesInLine->connect_toggled(LINK(this, DataStreamDlg, UpdateClickHdl)); + m_xEdRange->connect_changed(LINK(this, DataStreamDlg, UpdateHdl)); + m_xBtnBrowse->connect_clicked(LINK(this, DataStreamDlg, BrowseHdl)); + UpdateEnable(); +} + +DataStreamDlg::~DataStreamDlg() {} + +IMPL_LINK_NOARG(DataStreamDlg, BrowseHdl, weld::Button&, void) +{ + sfx2::FileDialogHelper aFileDialog(0, FileDialogFlags::NONE, m_xDialog.get()); + aFileDialog.SetContext(sfx2::FileDialogHelper::CalcDataStream); + if (aFileDialog.Execute() != ERRCODE_NONE) + return; + + m_xCbUrl->set_entry_text(aFileDialog.GetPath()); + UpdateEnable(); +} + +IMPL_LINK_NOARG(DataStreamDlg, UpdateClickHdl, weld::Toggleable&, void) { UpdateEnable(); } + +IMPL_LINK_NOARG(DataStreamDlg, UpdateComboBoxHdl, weld::ComboBox&, void) { UpdateEnable(); } + +IMPL_LINK_NOARG(DataStreamDlg, UpdateHdl, weld::Entry&, void) { UpdateEnable(); } + +void DataStreamDlg::UpdateEnable() +{ + bool bOk = !m_xCbUrl->GetURL().isEmpty(); + if (m_xRBAddressValue->get_active()) + { + m_xVclFrameLimit->set_sensitive(false); + m_xVclFrameMove->set_sensitive(false); + m_xEdRange->set_sensitive(false); + } + else + { + m_xVclFrameLimit->set_sensitive(true); + m_xVclFrameMove->set_sensitive(true); + m_xEdRange->set_sensitive(true); + if (bOk) + { + // Check the given range to make sure it's valid. + ScRange aTest = GetStartRange(); + if (!aTest.IsValid()) + bOk = false; + } + } + m_xBtnOk->set_sensitive(bOk); + // setOptimalLayoutSize(); +} + +ScRange DataStreamDlg::GetStartRange() +{ + OUString aStr = m_xEdRange->get_text(); + ScDocument& rDoc = m_pDocShell->GetDocument(); + ScRange aRange; + ScRefFlags nRes = aRange.Parse(aStr, rDoc, rDoc.GetAddressConvention()); + if (((nRes & ScRefFlags::VALID) == ScRefFlags::ZERO) || !aRange.IsValid()) + { + // Invalid range. + aRange.SetInvalid(); + return aRange; + } + + // Make sure it's only one row tall. + if (aRange.aStart.Row() != aRange.aEnd.Row()) + aRange.SetInvalid(); + + return aRange; +} + +void DataStreamDlg::Init(const DataStream& rStrm) +{ + m_xCbUrl->set_entry_text(rStrm.GetURL()); + ScDocument& rDoc = m_pDocShell->GetDocument(); + + ScRange aRange = rStrm.GetRange(); + ScRange aTopRange = aRange; + aTopRange.aEnd.SetRow(aTopRange.aStart.Row()); + OUString aStr = aTopRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()); + m_xEdRange->set_text(aStr); + SCROW nRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1; + + if (aRange.aEnd.Row() == rDoc.MaxRow()) + m_xRBUnlimited->set_active(true); + else + { + m_xRBMaxLimit->set_active(true); + m_xEdLimit->set_text(OUString::number(nRows)); + } + + DataStream::MoveType eMove = rStrm.GetMove(); + switch (eMove) + { + case DataStream::MOVE_DOWN: + m_xRBDataDown->set_active(true); + break; + case DataStream::RANGE_DOWN: + m_xRBRangeDown->set_active(true); + break; + case DataStream::MOVE_UP: + case DataStream::NO_MOVE: + default:; + } + + m_xCBRefreshOnEmpty->set_active(rStrm.IsRefreshOnEmptyLine()); + + UpdateEnable(); +} + +void DataStreamDlg::StartStream() +{ + ScRange aStartRange = GetStartRange(); + if (!aStartRange.IsValid()) + // Don't start the stream without a valid range. + return; + + sal_Int32 nLimit = 0; + if (m_xRBMaxLimit->get_active()) + nLimit = m_xEdLimit->get_text().toInt32(); + OUString rURL = m_xCbUrl->get_active_text(); + sal_uInt32 nSettings = 0; + if (m_xRBValuesInLine->get_active()) + nSettings |= DataStream::VALUES_IN_LINE; + + DataStream::MoveType eMove + = m_xRBRangeDown->get_active() ? DataStream::RANGE_DOWN : DataStream::MOVE_DOWN; + + DataStream* pStream = DataStream::Set(m_pDocShell, rURL, aStartRange, nLimit, eMove, nSettings); + pStream->SetRefreshOnEmptyLine(m_xCBRefreshOnEmpty->get_active()); + DataStream::MakeToolbarVisible(); + pStream->StartImport(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/datatableview.cxx b/sc/source/ui/miscdlgs/datatableview.cxx new file mode 100644 index 000000000..d74df0e81 --- /dev/null +++ b/sc/source/ui/miscdlgs/datatableview.cxx @@ -0,0 +1,320 @@ +/* -*- 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 <datatableview.hxx> + +#include <document.hxx> +#include <utility> +#include <viewdata.hxx> +#include <output.hxx> +#include <fillinfo.hxx> +#include <table.hxx> + +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/scrbar.hxx> +#include <vcl/seleng.hxx> +#include <sal/log.hxx> + +constexpr double nPPTX = 0.06666; +constexpr double nPPTY = 0.06666; + +constexpr sal_uInt16 nRowHeaderWidth = 100; +constexpr sal_uInt16 nColHeaderHeight = 20; +constexpr sal_uInt16 nScrollBarSize = 10; + +ScDataTableColView::ScDataTableColView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine): + ScHeaderControl(pParent, pSelectionEngine, pDoc->MaxCol()+1, false, nullptr), + mpDoc(pDoc), + mnCol(0) +{ +} + +void ScDataTableColView::SetPos(SCCOLROW nCol) +{ + mnCol = nCol; +} + +SCCOLROW ScDataTableColView::GetPos() const +{ + return mnCol; +} + +sal_uInt16 ScDataTableColView::GetEntrySize(SCCOLROW nPos) const +{ + return ScViewData::ToPixel(mpDoc->GetColWidth(nPos, 0), nPPTX); +} + +OUString ScDataTableColView::GetEntryText(SCCOLROW nPos) const +{ + return "Col: " + OUString::number(nPos + 1); +} + +bool ScDataTableColView::IsLayoutRTL() const +{ + return false; +} + +void ScDataTableColView::SetEntrySize(SCCOLROW nPos, sal_uInt16 nColWidth) +{ + mpDoc->SetColWidthOnly(nPos, 0, nColWidth/nPPTX); +} + +void ScDataTableColView::HideEntries(SCCOLROW nPos, SCCOLROW nEndPos) +{ + for (SCCOLROW nCol = nPos; nCol <= nEndPos; ++nCol) + { + mpDoc->ShowCol(nCol, 0, false); + } +} + + +ScDataTableRowView::ScDataTableRowView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine): + ScHeaderControl(pParent, pSelectionEngine, pDoc->MaxRow()+1, true, nullptr), + mpDoc(pDoc), + mnRow(0) +{ +} + +void ScDataTableRowView::SetPos(SCCOLROW nRow) +{ + mnRow = nRow; +} + +SCCOLROW ScDataTableRowView::GetPos() const +{ + return mnRow; +} + +sal_uInt16 ScDataTableRowView::GetEntrySize(SCCOLROW nPos) const +{ + return ScViewData::ToPixel(mpDoc->GetRowHeight(nPos, SCTAB(0), true), nPPTX); +} + +OUString ScDataTableRowView::GetEntryText(SCCOLROW nPos) const +{ + return OUString::number(nPos + 1); +} + +bool ScDataTableRowView::IsLayoutRTL() const +{ + return false; +} + +void ScDataTableRowView::SetEntrySize(SCCOLROW nPos, sal_uInt16 nColWidth) +{ + mpDoc->SetRowHeight(nPos, 0, nColWidth/nPPTX); +} + +void ScDataTableRowView::HideEntries(SCCOLROW nPos, SCCOLROW nEndPos) +{ + for (SCCOLROW nCol = nPos; nCol <= nEndPos; ++nCol) + { + mpDoc->ShowRow(nCol, 0, false); + } +} + +ScDataTableView::ScDataTableView(const css::uno::Reference<css::awt::XWindow> &rParent, std::shared_ptr<ScDocument> pDoc) : + Control(VCLUnoHelper::GetWindow(rParent)), + mpDoc(std::move(pDoc)), + mpSelectionEngine(new SelectionEngine(this)), + mpTopLeft(VclPtr<ScrollBarBox>::Create(this, WB_SIZEABLE)), + mpColView(VclPtr<ScDataTableColView>::Create(this, mpDoc.get(), mpSelectionEngine.get())), + mpRowView(VclPtr<ScDataTableRowView>::Create(this, mpDoc.get(), mpSelectionEngine.get())), + mpVScroll(VclPtr<ScrollBar>::Create(this, WinBits(WB_VSCROLL | WB_DRAG))), + mpHScroll(VclPtr<ScrollBar>::Create(this, WinBits(WB_HSCROLL | WB_DRAG))), + mnFirstVisibleRow(0), + mnFirstVisibleCol(0) +{ + mpTopLeft->setPosSizePixel(0, 0, nRowHeaderWidth, nColHeaderHeight); + mpColView->setPosSizePixel(nRowHeaderWidth, 0, nRowHeaderWidth, nColHeaderHeight); + mpRowView->setPosSizePixel(0, nColHeaderHeight, nRowHeaderWidth, nColHeaderHeight); + + mpVScroll->SetRangeMin(0); + mpVScroll->SetRangeMax(100); + mpVScroll->SetEndScrollHdl(LINK(this, ScDataTableView, ScrollHdl)); + + mpHScroll->SetRangeMin(0); + mpHScroll->SetRangeMax(50); + mpHScroll->SetEndScrollHdl(LINK(this, ScDataTableView, ScrollHdl)); + + mpTopLeft->Show(); + mpColView->Show(); + mpRowView->Show(); + mpVScroll->Show(); + mpHScroll->Show(); +} + +ScDataTableView::~ScDataTableView() +{ + disposeOnce(); +} + +void ScDataTableView::dispose() +{ + mpTopLeft.disposeAndClear(); + mpColView.disposeAndClear(); + mpRowView.disposeAndClear(); + mpVScroll.disposeAndClear(); + mpHScroll.disposeAndClear(); + Control::dispose(); +} + +void ScDataTableView::MouseButtonDown(const MouseEvent& rMEvt) +{ + if (!rMEvt.IsLeft()) + return; + + mpMouseEvent.reset(new MouseEvent(rMEvt)); +} + +namespace { + +SCCOL findColFromPos(sal_uInt16 nPixelPos, const ScDocument* pDoc, SCCOL nStartCol = 0) +{ + nPixelPos -= nRowHeaderWidth; + sal_uInt32 nPixelLength = 0; + for (SCCOL nCol : pDoc->GetColumnsRange(0, nStartCol, pDoc->MaxCol())) + { + sal_uInt16 nColWidth = pDoc->GetColWidth(nCol, 0, true); + sal_uInt32 nPixel = ScViewData::ToPixel(nColWidth, nPPTX); + nPixelLength += nPixel; + + if (nPixelLength >= nPixelPos) + { + return nCol; + } + } + + SAL_WARN("sc", "Could not find the corresponding column"); + return pDoc->MaxCol(); +} + +SCROW findRowFromPos(sal_uInt16 nPixelPos, const ScDocument* pDoc, SCROW nStartRow = 0) +{ + nPixelPos -= nColHeaderHeight; + sal_uInt32 nPixelLength = 0; + for (SCROW nRow = nStartRow; nRow <= pDoc->MaxRow(); ++nRow) + { + sal_uInt16 nColWidth = pDoc->GetRowHeight(nRow, SCTAB(0), true); + sal_uInt32 nPixel = ScViewData::ToPixel(nColWidth, nPPTX); + nPixelLength += nPixel; + + if (nPixelLength >= nPixelPos) + { + return nRow; + } + } + + SAL_WARN("sc", "Could not find the corresponding row"); + return pDoc->MaxRow(); +} + +} + +void ScDataTableView::MouseButtonUp(const MouseEvent& rMEvt) +{ + if (!rMEvt.IsLeft()) + return; + if (!mpMouseEvent) // tdf#120528 The event originated in another window, like context menu + return; + + SCCOL nStartCol = findColFromPos(mpMouseEvent->GetPosPixel().getX(), mpDoc.get()); + SCCOL nEndCol = findColFromPos(rMEvt.GetPosPixel().getX(), mpDoc.get()); + SCROW nStartRow = findRowFromPos(mpMouseEvent->GetPosPixel().getY(), mpDoc.get()); + SCROW nEndRow = findRowFromPos(rMEvt.GetPosPixel().getY(), mpDoc.get()); + PutInOrder(nStartCol, nEndCol); + PutInOrder(nStartRow, nEndRow); + mpColView->SetMark(true, nStartCol, nEndCol); + mpRowView->SetMark(true, nStartRow, nEndRow); + + mpMouseEvent.reset(); +} + +void ScDataTableView::Resize() +{ + Size aSize = GetSizePixel(); + mpTopLeft->setPosSizePixel(0, 0, nRowHeaderWidth, nColHeaderHeight); + mpColView->setPosSizePixel(nRowHeaderWidth, 0, aSize.Width() - nScrollBarSize, nColHeaderHeight); + mpRowView->setPosSizePixel(0, nColHeaderHeight, nRowHeaderWidth, aSize.Height()); + + mpVScroll->setPosSizePixel(aSize.Width() - nScrollBarSize, nColHeaderHeight, nScrollBarSize, aSize.Height() - nColHeaderHeight - nScrollBarSize); + mpHScroll->setPosSizePixel(nRowHeaderWidth, aSize.Height() - nScrollBarSize, aSize.Width() - nRowHeaderWidth - nScrollBarSize, nScrollBarSize); +} + +void ScDataTableView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRectangle) +{ + Size aSize = GetSizePixel(); + SCCOL nMaxVisibleCol = findColFromPos(aSize.Width() - nScrollBarSize, mpDoc.get(), mnFirstVisibleCol); + SCROW nMaxVisibleRow = findRowFromPos(aSize.Height(), mpDoc.get(), mnFirstVisibleRow); + + ScTableInfo aTableInfo; + mpDoc->FillInfo(aTableInfo, mnFirstVisibleCol, mnFirstVisibleRow, nMaxVisibleCol, nMaxVisibleRow, 0, 0.06666, 0.06666, false, false); + ScOutputData aOutput(&rRenderContext, OUTTYPE_WINDOW, aTableInfo, mpDoc.get(), 0, + nRowHeaderWidth, nColHeaderHeight, mnFirstVisibleCol, mnFirstVisibleRow, nMaxVisibleCol, nMaxVisibleRow, nPPTX, nPPTY); + + aOutput.SetGridColor(COL_BLACK); + aOutput.SetSolidBackground(true); + aOutput.DrawClear(); + aOutput.DrawDocumentBackground(); + aOutput.DrawGrid(rRenderContext, true, false); + aOutput.DrawStrings(); + Control::Paint(rRenderContext, rRectangle); +} + +Size ScDataTableView::GetOptimalSize() const +{ + return Size(450, 400); +} + +void ScDataTableView::getColRange(SCCOL& rStartCol, SCCOL& rEndCol) const +{ + SCCOLROW aStart = 0; + SCCOLROW aEnd = 0; + mpColView->GetMarkRange(aStart, aEnd); + rStartCol = static_cast<SCCOL>(aStart); + rEndCol = static_cast<SCCOL>(aEnd); +} + +void ScDataTableView::getRowRange(SCROW& rStartCol, SCROW& rEndCol) const +{ + SCCOLROW aStart = 0; + SCCOLROW aEnd = 0; + mpRowView->GetMarkRange(aStart, aEnd); + rStartCol = static_cast<SCROW>(aStart); + rEndCol = static_cast<SCROW>(aEnd); +} + +IMPL_LINK(ScDataTableView, ScrollHdl, ScrollBar*, pScrollBar, void) +{ + if (pScrollBar == mpVScroll.get()) + { + mnFirstVisibleRow = pScrollBar->GetThumbPos(); + pScrollBar->SetRangeMax(std::min(mpDoc->MaxRow(), static_cast<SCROW>(mnFirstVisibleRow + 100))); + mpRowView->SetPos(mnFirstVisibleRow); + } + else + { + mnFirstVisibleCol = pScrollBar->GetThumbPos(); + pScrollBar->SetRangeMax(std::min(mpDoc->MaxCol(), static_cast<SCCOL>(mnFirstVisibleCol + 50))); + mpColView->SetPos(mnFirstVisibleCol); + } + Invalidate(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/delcldlg.cxx b/sc/source/ui/miscdlgs/delcldlg.cxx new file mode 100644 index 000000000..71ce6b99e --- /dev/null +++ b/sc/source/ui/miscdlgs/delcldlg.cxx @@ -0,0 +1,101 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <delcldlg.hxx> + +static sal_uInt8 nDelItemChecked = 0; + +ScDeleteCellDlg::ScDeleteCellDlg(weld::Window* pParent, bool bDisallowCellMove) + : GenericDialogController(pParent, "modules/scalc/ui/deletecells.ui", "DeleteCellsDialog") + , m_xBtnCellsUp(m_xBuilder->weld_radio_button("up")) + , m_xBtnCellsLeft(m_xBuilder->weld_radio_button("left")) + , m_xBtnDelRows(m_xBuilder->weld_radio_button("rows")) + , m_xBtnDelCols(m_xBuilder->weld_radio_button("cols")) +{ + if (bDisallowCellMove) + { + m_xBtnCellsUp->set_sensitive(false); + m_xBtnCellsLeft->set_sensitive(false); + + switch (nDelItemChecked) + { + case 2: + m_xBtnDelRows->set_active(true); + break; + case 3: + m_xBtnDelCols->set_active(true); + break; + default: + m_xBtnDelRows->set_active(true); + break; + } + } + else + { + switch (nDelItemChecked) + { + case 0: + m_xBtnCellsUp->set_active(true); + break; + case 1: + m_xBtnCellsLeft->set_active(true); + break; + case 2: + m_xBtnDelRows->set_active(true); + break; + case 3: + m_xBtnDelCols->set_active(true); + break; + } + } +} + +ScDeleteCellDlg::~ScDeleteCellDlg() {} + +DelCellCmd ScDeleteCellDlg::GetDelCellCmd() const +{ + DelCellCmd nReturn = DelCellCmd::NONE; + + if (m_xBtnCellsUp->get_active()) + { + nDelItemChecked = 0; + nReturn = DelCellCmd::CellsUp; + } + else if (m_xBtnCellsLeft->get_active()) + { + nDelItemChecked = 1; + nReturn = DelCellCmd::CellsLeft; + } + else if (m_xBtnDelRows->get_active()) + { + nDelItemChecked = 2; + nReturn = DelCellCmd::Rows; + } + else if (m_xBtnDelCols->get_active()) + { + nDelItemChecked = 3; + nReturn = DelCellCmd::Cols; + } + + return nReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/delcodlg.cxx b/sc/source/ui/miscdlgs/delcodlg.cxx new file mode 100644 index 000000000..9d804c252 --- /dev/null +++ b/sc/source/ui/miscdlgs/delcodlg.cxx @@ -0,0 +1,125 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <delcodlg.hxx> + +bool ScDeleteContentsDlg::bPreviousAllCheck = false; +InsertDeleteFlags ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | + InsertDeleteFlags::NOTE | InsertDeleteFlags::FORMULA | + InsertDeleteFlags::VALUE; + +ScDeleteContentsDlg::ScDeleteContentsDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/deletecontents.ui", "DeleteContentsDialog") + , m_bObjectsDisabled(false) + , m_xBtnDelAll(m_xBuilder->weld_check_button("deleteall")) + , m_xBtnDelStrings(m_xBuilder->weld_check_button("text")) + , m_xBtnDelNumbers(m_xBuilder->weld_check_button("numbers")) + , m_xBtnDelDateTime(m_xBuilder->weld_check_button("datetime")) + , m_xBtnDelFormulas(m_xBuilder->weld_check_button("formulas")) + , m_xBtnDelNotes(m_xBuilder->weld_check_button("comments")) + , m_xBtnDelAttrs(m_xBuilder->weld_check_button("formats")) + , m_xBtnDelObjects(m_xBuilder->weld_check_button("objects")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + m_xBtnDelAll->set_active( ScDeleteContentsDlg::bPreviousAllCheck ); + m_xBtnDelStrings->set_active( bool(InsertDeleteFlags::STRING & ScDeleteContentsDlg::nPreviousChecks) ); + m_xBtnDelNumbers->set_active( bool(InsertDeleteFlags::VALUE & ScDeleteContentsDlg::nPreviousChecks) ); + m_xBtnDelDateTime->set_active( bool(InsertDeleteFlags::DATETIME & ScDeleteContentsDlg::nPreviousChecks) ); + m_xBtnDelFormulas->set_active( bool(InsertDeleteFlags::FORMULA & ScDeleteContentsDlg::nPreviousChecks) ); + m_xBtnDelNotes->set_active( bool(InsertDeleteFlags::NOTE & ScDeleteContentsDlg::nPreviousChecks) ); + m_xBtnDelAttrs->set_active( (InsertDeleteFlags::ATTRIB & ScDeleteContentsDlg::nPreviousChecks) == InsertDeleteFlags::ATTRIB ); + m_xBtnDelObjects->set_active( bool(InsertDeleteFlags::OBJECTS & ScDeleteContentsDlg::nPreviousChecks) ); + + DisableChecks( m_xBtnDelAll->get_active() ); + + m_xBtnDelAll->connect_toggled( LINK( this, ScDeleteContentsDlg, DelAllHdl ) ); +} + +ScDeleteContentsDlg::~ScDeleteContentsDlg() +{ +} + +InsertDeleteFlags ScDeleteContentsDlg::GetDelContentsCmdBits() const +{ + ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::NONE; + + if ( m_xBtnDelStrings->get_active() ) + ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::STRING; + if ( m_xBtnDelNumbers->get_active() ) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::VALUE; + if ( m_xBtnDelDateTime->get_active()) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::DATETIME; + if ( m_xBtnDelFormulas->get_active()) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::FORMULA; + if ( m_xBtnDelNotes->get_active() ) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::NOTE; + if ( m_xBtnDelAttrs->get_active() ) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::ATTRIB; + if ( m_xBtnDelObjects->get_active() ) + ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::OBJECTS; + + ScDeleteContentsDlg::bPreviousAllCheck = m_xBtnDelAll->get_active(); + + return ( ScDeleteContentsDlg::bPreviousAllCheck + ? InsertDeleteFlags::ALL + : ScDeleteContentsDlg::nPreviousChecks ); +} + +void ScDeleteContentsDlg::DisableChecks( bool bDelAllChecked ) +{ + if ( bDelAllChecked ) + { + m_xBtnDelStrings->set_sensitive(false); + m_xBtnDelNumbers->set_sensitive(false); + m_xBtnDelDateTime->set_sensitive(false); + m_xBtnDelFormulas->set_sensitive(false); + m_xBtnDelNotes->set_sensitive(false); + m_xBtnDelAttrs->set_sensitive(false); + m_xBtnDelObjects->set_sensitive(false); + } + else + { + m_xBtnDelStrings->set_sensitive(true); + m_xBtnDelNumbers->set_sensitive(true); + m_xBtnDelDateTime->set_sensitive(true); + m_xBtnDelFormulas->set_sensitive(true); + m_xBtnDelNotes->set_sensitive(true); + m_xBtnDelAttrs->set_sensitive(true); + if (m_bObjectsDisabled) + m_xBtnDelObjects->set_sensitive(false); + else + m_xBtnDelObjects->set_sensitive(true); + } +} + +void ScDeleteContentsDlg::DisableObjects() +{ + m_bObjectsDisabled = true; + m_xBtnDelObjects->set_active(false); + m_xBtnDelObjects->set_sensitive(false); +} + +IMPL_LINK_NOARG(ScDeleteContentsDlg, DelAllHdl, weld::Toggleable&, void) +{ + DisableChecks( m_xBtnDelAll->get_active() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/filldlg.cxx b/sc/source/ui/miscdlgs/filldlg.cxx new file mode 100644 index 000000000..c72201d26 --- /dev/null +++ b/sc/source/ui/miscdlgs/filldlg.cxx @@ -0,0 +1,290 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <svl/numformat.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <scresid.hxx> +#include <document.hxx> +#include <strings.hrc> +#include <filldlg.hxx> +#include <scui_def.hxx> + + +ScFillSeriesDlg::ScFillSeriesDlg( weld::Window* pParent, + ScDocument& rDocument, + FillDir eFillDir, + FillCmd eFillCmd, + FillDateCmd eFillDateCmd, + const OUString& aStartStr, + double fStep, + double fMax, + const SCSIZE nSelectHeight, + const SCSIZE nSelectWidth, + sal_uInt16 nPossDir ) + : GenericDialogController(pParent, "modules/scalc/ui/filldlg.ui", "FillSeriesDialog") + , aStartStrVal(aStartStr) + , aErrMsgInvalidVal(ScResId(SCSTR_VALERR)) + , rDoc(rDocument) + , theFillDir(eFillDir) + , theFillCmd(eFillCmd) + , theFillDateCmd(eFillDateCmd) + , fIncrement(fStep) + , fEndVal(fMax) + , m_nSelectHeight(nSelectHeight) + , m_nSelectWidth(nSelectWidth) + , m_xFtStartVal(m_xBuilder->weld_label("startL")) + , m_xEdStartVal(m_xBuilder->weld_entry("startValue")) + , m_xFtEndVal(m_xBuilder->weld_label("endL")) + , m_xEdEndVal(m_xBuilder->weld_entry("endValue")) + , m_xFtIncrement(m_xBuilder->weld_label("incrementL")) + , m_xEdIncrement(m_xBuilder->weld_entry("increment")) + , m_xBtnDown(m_xBuilder->weld_radio_button("down")) + , m_xBtnRight(m_xBuilder->weld_radio_button("right")) + , m_xBtnUp(m_xBuilder->weld_radio_button("up")) + , m_xBtnLeft(m_xBuilder->weld_radio_button("left")) + , m_xBtnArithmetic(m_xBuilder->weld_radio_button("linear")) + , m_xBtnGeometric(m_xBuilder->weld_radio_button("growth")) + , m_xBtnDate(m_xBuilder->weld_radio_button("date")) + , m_xBtnAutoFill(m_xBuilder->weld_radio_button("autofill")) + , m_xFtTimeUnit(m_xBuilder->weld_label("tuL")) + , m_xBtnDay(m_xBuilder->weld_radio_button("day")) + , m_xBtnDayOfWeek(m_xBuilder->weld_radio_button("week")) + , m_xBtnMonth(m_xBuilder->weld_radio_button("month")) + , m_xBtnYear(m_xBuilder->weld_radio_button("year")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + Init(nPossDir); +} + +ScFillSeriesDlg::~ScFillSeriesDlg() +{ +} + +void ScFillSeriesDlg::SetEdStartValEnabled(bool bFlag) +{ + if(bFlag) + { + m_xFtStartVal->set_sensitive(true); + m_xEdStartVal->set_sensitive(true); + } + else + { + m_xFtStartVal->set_sensitive(false); + m_xEdStartVal->set_sensitive(false); + } +} + +void ScFillSeriesDlg::Init( sal_uInt16 nPossDir ) +{ + m_xBtnOk->connect_clicked ( LINK( this, ScFillSeriesDlg, OKHdl ) ); + m_xBtnArithmetic->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) ); + m_xBtnGeometric->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) ); + m_xBtnDate->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) ); + m_xBtnAutoFill->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) ); + + if( nPossDir == FDS_OPT_NONE ) + { + m_xBtnLeft->set_sensitive(false); + m_xBtnRight->set_sensitive(false); + m_xBtnDown->set_sensitive(false); + m_xBtnUp->set_sensitive(false); + } + + if( nPossDir == FDS_OPT_HORZ ) + { + m_xBtnDown->set_sensitive(false); + m_xBtnUp->set_sensitive(false); + } + + if( nPossDir == FDS_OPT_VERT ) + { + m_xBtnLeft->set_sensitive(false); + m_xBtnRight->set_sensitive(false); + } + + switch ( theFillDir ) + { + case FILL_TO_LEFT: m_xBtnLeft->set_active(true); break; + case FILL_TO_RIGHT: m_xBtnRight->set_active(true); break; + case FILL_TO_BOTTOM: m_xBtnDown->set_active(true); break; + case FILL_TO_TOP: m_xBtnUp->set_active(true); break; + default: + break; + } + + switch ( theFillCmd ) + { + case FILL_LINEAR: + m_xBtnArithmetic->set_active(true); + DisableHdl(*m_xBtnArithmetic); + break; + case FILL_GROWTH: + m_xBtnGeometric->set_active(true); + DisableHdl(*m_xBtnGeometric ); + break; + case FILL_DATE: + m_xBtnDate->set_active(true); + DisableHdl(*m_xBtnDate); + break; + case FILL_AUTO: + m_xBtnAutoFill->set_active(true); + DisableHdl(*m_xBtnAutoFill); + break; + default: + break; + } + + switch ( theFillDateCmd ) + { + case FILL_DAY: m_xBtnDay->set_active(true); break; + case FILL_WEEKDAY: m_xBtnDayOfWeek->set_active(true); break; + case FILL_MONTH: m_xBtnMonth->set_active(true); break; + case FILL_YEAR: m_xBtnYear->set_active(true); break; + default: + break; + } + + fStartVal = MAXDOUBLE; + + m_xEdStartVal->set_text( aStartStrVal); + + OUString aIncrTxt; + rDoc.GetFormatTable()->GetInputLineString( fIncrement, 0, aIncrTxt ); + m_xEdIncrement->set_text( aIncrTxt ); + + OUString aEndTxt; + if ( fEndVal != MAXDOUBLE ) + rDoc.GetFormatTable()->GetInputLineString( fEndVal, 0, aEndTxt ); + m_xEdEndVal->set_text( aEndTxt ); +} + +weld::Entry* ScFillSeriesDlg::CheckValues() +{ + OUString aStartStr = m_xEdStartVal->get_text(); + OUString aIncStr = m_xEdIncrement->get_text(); + OUString aEndStr = m_xEdEndVal->get_text(); + sal_uInt32 nKey = 0; + + // If entry is filled, capture value before handling special cases. + if ( !aStartStr.isEmpty() + && theFillCmd != FILL_AUTO + && !rDoc.GetFormatTable()->IsNumberFormat( aStartStr, nKey, fStartVal ) ) + return m_xEdStartVal.get(); + if ( !aIncStr.isEmpty() + && !rDoc.GetFormatTable()->IsNumberFormat( aIncStr, nKey, fIncrement ) ) + return m_xEdIncrement.get(); + if ( !aEndStr.isEmpty() + && !rDoc.GetFormatTable()->IsNumberFormat( aEndStr, nKey, fEndVal ) ) + return m_xEdEndVal.get(); + + if ( theFillCmd == FILL_LINEAR && !aEndStr.isEmpty() + && aStartStr.isEmpty() != aIncStr.isEmpty() + && ( ( m_nSelectHeight == 1 ) != ( m_nSelectWidth == 1 ) ) ) + { + SCSIZE nStepAmount = ( theFillDir == FILL_TO_BOTTOM || theFillDir == FILL_TO_TOP ) ? + m_nSelectHeight - 1 : m_nSelectWidth - 1 ; + if ( aStartStr.isEmpty() ) + fStartVal = fEndVal - fIncrement * nStepAmount; + if ( aIncStr.isEmpty() && nStepAmount != 0 ) + fIncrement = (fEndVal - fStartVal) / nStepAmount; + } + else + { + if ( aStartStr.isEmpty() || m_xBtnAutoFill->get_active() ) + fStartVal = MAXDOUBLE; + if ( aIncStr.isEmpty() ) + return m_xEdIncrement.get(); + if ( aEndStr.isEmpty() ) + fEndVal = ( fIncrement < 0 ) ? -MAXDOUBLE : MAXDOUBLE; + } + return nullptr; +} + +// Handler: +IMPL_LINK(ScFillSeriesDlg, DisableHdl, weld::Toggleable&, rBtn, void) +{ + if (&rBtn == m_xBtnDate.get()) + { + m_xBtnDay->set_sensitive(true); + m_xBtnDayOfWeek->set_sensitive(true); + m_xBtnMonth->set_sensitive(true); + m_xBtnYear->set_sensitive(true); + m_xFtTimeUnit->set_sensitive(true); + } + else + { + m_xBtnDay->set_sensitive(false); + m_xBtnDayOfWeek->set_sensitive(false); + m_xBtnMonth->set_sensitive(false); + m_xBtnYear->set_sensitive(false); + m_xFtTimeUnit->set_sensitive(false); + } + + if (&rBtn != m_xBtnAutoFill.get()) + { + m_xFtIncrement->set_sensitive(true); + m_xEdIncrement->set_sensitive(true); + m_xFtEndVal->set_sensitive(true); + m_xEdEndVal->set_sensitive(true); + } + else + { + m_xFtIncrement->set_sensitive(false); + m_xEdIncrement->set_sensitive(false); + m_xFtEndVal->set_sensitive(false); + m_xEdEndVal->set_sensitive(false); + } +} + +IMPL_LINK_NOARG(ScFillSeriesDlg, OKHdl, weld::Button&, void) +{ + if ( m_xBtnLeft->get_active() ) theFillDir = FILL_TO_LEFT; + else if ( m_xBtnRight->get_active() ) theFillDir = FILL_TO_RIGHT; + else if ( m_xBtnDown->get_active() ) theFillDir = FILL_TO_BOTTOM; + else if ( m_xBtnUp->get_active() ) theFillDir = FILL_TO_TOP; + + if ( m_xBtnArithmetic->get_active() ) theFillCmd = FILL_LINEAR; + else if ( m_xBtnGeometric->get_active() ) theFillCmd = FILL_GROWTH; + else if ( m_xBtnDate->get_active() ) theFillCmd = FILL_DATE; + else if ( m_xBtnAutoFill->get_active() ) theFillCmd = FILL_AUTO; + + if ( m_xBtnDay->get_active() ) theFillDateCmd = FILL_DAY; + else if ( m_xBtnDayOfWeek->get_active() ) theFillDateCmd = FILL_WEEKDAY; + else if ( m_xBtnMonth->get_active() ) theFillDateCmd = FILL_MONTH; + else if ( m_xBtnYear->get_active() ) theFillDateCmd = FILL_YEAR; + + weld::Entry* pEdWrong = CheckValues(); + if ( pEdWrong == nullptr ) + { + m_xDialog->response(RET_OK); + } + else + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning, + VclButtonsType::Ok, aErrMsgInvalidVal)); + xBox->run(); + pEdWrong->grab_focus(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/gototabdlg.cxx b/sc/source/ui/miscdlgs/gototabdlg.cxx new file mode 100644 index 000000000..e38e67100 --- /dev/null +++ b/sc/source/ui/miscdlgs/gototabdlg.cxx @@ -0,0 +1,81 @@ +/* -*- 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/. + * + */ + +#undef SC_DLLIMPLEMENTATION + +#include <gototabdlg.hxx> + +ScGoToTabDlg::ScGoToTabDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/gotosheetdialog.ui", "GoToSheetDialog") + , m_xFrameMask(m_xBuilder->weld_frame("frame-mask")) + , m_xEnNameMask(m_xBuilder->weld_entry("entry-mask")) + , m_xFrameSheets(m_xBuilder->weld_frame("frame-sheets")) + , m_xLb(m_xBuilder->weld_tree_view("treeview")) +{ + m_xLb->set_selection_mode(SelectionMode::Single); + m_xLb->set_size_request(-1, m_xLb->get_height_rows(10)); + m_xLb->connect_row_activated(LINK(this, ScGoToTabDlg, DblClkHdl)); + m_xEnNameMask->connect_changed(LINK(this, ScGoToTabDlg, FindNameHdl)); +} + +ScGoToTabDlg::~ScGoToTabDlg() {} + +void ScGoToTabDlg::SetDescription(const OUString& rTitle, const OUString& rEntryLabel, + const OUString& rListLabel, const OString& rDlgHelpId, + const OString& rEnHelpId, const OString& rLbHelpId) +{ + m_xDialog->set_title(rTitle); + m_xFrameMask->set_label(rEntryLabel); + m_xFrameSheets->set_label(rListLabel); + m_xDialog->set_help_id(rDlgHelpId); + m_xEnNameMask->set_help_id(rEnHelpId); + m_xLb->set_help_id(rLbHelpId); +} + +void ScGoToTabDlg::Insert(const OUString& rString, bool bSelected) +{ + maCacheSheetsNames.push_back(rString); + m_xLb->append_text(rString); + if (bSelected) + m_xLb->select(m_xLb->n_children() - 1); +} + +OUString ScGoToTabDlg::GetSelectedEntry() const { return m_xLb->get_selected_text(); } + +IMPL_LINK_NOARG(ScGoToTabDlg, DblClkHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +IMPL_LINK_NOARG(ScGoToTabDlg, FindNameHdl, weld::Entry&, void) +{ + const OUString aMask = m_xEnNameMask->get_text(); + m_xLb->clear(); + if (aMask.isEmpty()) + { + for (const OUString& s : maCacheSheetsNames) + { + m_xLb->append_text(s); + } + } + else + { + for (const OUString& s : maCacheSheetsNames) + { + if (s.indexOf(aMask) >= 0) + { + m_xLb->append_text(s); + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/groupdlg.cxx b/sc/source/ui/miscdlgs/groupdlg.cxx new file mode 100644 index 000000000..839cc4f74 --- /dev/null +++ b/sc/source/ui/miscdlgs/groupdlg.cxx @@ -0,0 +1,52 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <groupdlg.hxx> + +ScGroupDlg::ScGroupDlg(weld::Window* pParent, bool bUngroup, bool bRows) + : GenericDialogController(pParent, + bUngroup ? + OUString("modules/scalc/ui/ungroupdialog.ui") : + OUString("modules/scalc/ui/groupdialog.ui") + , + bUngroup ? + OString("UngroupDialog") : + OString("GroupDialog")) + , m_xBtnRows(m_xBuilder->weld_radio_button("rows")) + , m_xBtnCols(m_xBuilder->weld_radio_button("cols")) +{ + if (bRows) + m_xBtnRows->set_active(true); + else + m_xBtnCols->set_active(true); + m_xBtnRows->grab_focus(); +} + +ScGroupDlg::~ScGroupDlg() +{ +} + +bool ScGroupDlg::GetColsChecked() const +{ + return m_xBtnCols->get_active(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/highred.cxx b/sc/source/ui/miscdlgs/highred.cxx new file mode 100644 index 000000000..fa655f80e --- /dev/null +++ b/sc/source/ui/miscdlgs/highred.cxx @@ -0,0 +1,221 @@ +/* -*- 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 <reffact.hxx> +#include <document.hxx> +#include <docsh.hxx> +#include <chgtrack.hxx> + +#include <highred.hxx> + + +ScHighlightChgDlg::ScHighlightChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScViewData& rViewData) + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/showchangesdialog.ui", "ShowChangesDialog") + , m_rViewData(rViewData) + , rDoc(rViewData.GetDocument()) + , m_xHighlightBox(m_xBuilder->weld_check_button("showchanges")) + , m_xCbAccept(m_xBuilder->weld_check_button("showaccepted")) + , m_xCbReject(m_xBuilder->weld_check_button("showrejected")) + , m_xOkButton(m_xBuilder->weld_button("ok")) + , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("range"))) + , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("rangeref"))) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xFilterCtr(new SvxTPFilter(m_xBox.get())) +{ + m_xEdAssign->SetReferences(this, nullptr); + m_xRbAssign->SetReferences(this, m_xEdAssign.get()); + + m_xOkButton->connect_clicked(LINK( this, ScHighlightChgDlg, OKBtnHdl)); + m_xHighlightBox->connect_toggled(LINK( this, ScHighlightChgDlg, HighlightHandle )); + m_xFilterCtr->SetRefHdl(LINK( this, ScHighlightChgDlg, RefHandle )); + m_xFilterCtr->HideRange(false); + m_xFilterCtr->Show(); + SetDispatcherLock( true ); + + Init(); +} + +ScHighlightChgDlg::~ScHighlightChgDlg() +{ + SetDispatcherLock( false ); +} + +void ScHighlightChgDlg::Init() +{ + ScChangeTrack* pChanges = rDoc.GetChangeTrack(); + if(pChanges!=nullptr) + { + aChangeViewSet.SetTheAuthorToShow(pChanges->GetUser()); + m_xFilterCtr->ClearAuthors(); + const std::set<OUString>& rUserColl = pChanges->GetUserCollection(); + for (const auto& rItem : rUserColl) + m_xFilterCtr->InsertAuthor(rItem); + } + + ScChangeViewSettings* pViewSettings = rDoc.GetChangeViewSettings(); + + if(pViewSettings!=nullptr) + aChangeViewSet=*pViewSettings; + m_xHighlightBox->set_active(aChangeViewSet.ShowChanges()); + m_xFilterCtr->CheckDate(aChangeViewSet.HasDate()); + + DateTime aEmpty(DateTime::EMPTY); + + DateTime aDateTime(aChangeViewSet.GetTheFirstDateTime()); + if (aDateTime != aEmpty) + { + m_xFilterCtr->SetFirstDate(aDateTime); + m_xFilterCtr->SetFirstTime(aDateTime); + } + aDateTime = aChangeViewSet.GetTheLastDateTime(); + if (aDateTime != aEmpty) + { + m_xFilterCtr->SetLastDate(aDateTime); + m_xFilterCtr->SetLastTime(aDateTime); + } + + m_xFilterCtr->SetDateMode(static_cast<sal_uInt16>(aChangeViewSet.GetTheDateMode())); + m_xFilterCtr->CheckAuthor(aChangeViewSet.HasAuthor()); + m_xFilterCtr->CheckComment(aChangeViewSet.HasComment()); + m_xFilterCtr->SetComment(aChangeViewSet.GetTheComment()); + + m_xCbAccept->set_active(aChangeViewSet.IsShowAccepted()); + m_xCbReject->set_active(aChangeViewSet.IsShowRejected()); + + OUString aString=aChangeViewSet.GetTheAuthorToShow(); + if(!aString.isEmpty()) + { + m_xFilterCtr->SelectAuthor(aString); + } + else + { + m_xFilterCtr->SelectedAuthorPos(0); + } + + m_xFilterCtr->CheckRange(aChangeViewSet.HasRange()); + + if ( !aChangeViewSet.GetTheRangeList().empty() ) + { + const ScRange & rRangeEntry = aChangeViewSet.GetTheRangeList().front(); + OUString aRefStr(rRangeEntry.Format(rDoc, ScRefFlags::RANGE_ABS_3D)); + m_xFilterCtr->SetRange(aRefStr); + } + m_xFilterCtr->Enable(true); + HighlightHandle(*m_xHighlightBox); +} + +// Set the reference to a cell range selected with the mouse. This is then +// shown as the new selection in the reference field. +void ScHighlightChgDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if (m_xEdAssign->GetWidget()->get_visible()) + { + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(m_xEdAssign.get()); + OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, rDocP.GetAddressConvention())); + m_xEdAssign->SetRefString( aRefStr ); + m_xFilterCtr->SetRange(aRefStr); + } +} + +void ScHighlightChgDlg::Close() +{ + DoClose( ScHighlightChgDlgWrapper::GetChildWindowId() ); +} + +void ScHighlightChgDlg::RefInputDone( bool bForced) +{ + ScAnyRefDlgController::RefInputDone(bForced); + if (bForced || !m_xRbAssign->GetWidget()->get_visible()) + { + m_xFilterCtr->SetRange(m_xEdAssign->GetText()); + m_xFilterCtr->SetFocusToRange(); + m_xEdAssign->GetWidget()->hide(); + m_xRbAssign->GetWidget()->hide(); + } +} + +void ScHighlightChgDlg::SetActive() +{ +} + +bool ScHighlightChgDlg::IsRefInputMode() const +{ + return m_xEdAssign->GetWidget()->get_visible(); +} + +IMPL_LINK_NOARG(ScHighlightChgDlg, HighlightHandle, weld::Toggleable&, void) +{ + if (m_xHighlightBox->get_active()) + { + m_xFilterCtr->Enable(true); + m_xCbAccept->set_sensitive(true); + m_xCbReject->set_sensitive(true); + } + else + { + m_xFilterCtr->Enable(false); + m_xCbAccept->set_sensitive(false); + m_xCbReject->set_sensitive(false); + } +} + +IMPL_LINK( ScHighlightChgDlg, RefHandle, SvxTPFilter*, pRef, void ) +{ + if(pRef!=nullptr) + { + SetDispatcherLock( true ); + m_xEdAssign->GetWidget()->show(); + m_xRbAssign->GetWidget()->show(); + m_xEdAssign->SetText(m_xFilterCtr->GetRange()); + m_xEdAssign->GrabFocus(); + ScAnyRefDlgController::RefInputStart(m_xEdAssign.get(), m_xRbAssign.get()); + } +} + +IMPL_LINK_NOARG(ScHighlightChgDlg, OKBtnHdl, weld::Button&, void) +{ + aChangeViewSet.SetShowChanges(m_xHighlightBox->get_active()); + aChangeViewSet.SetHasDate(m_xFilterCtr->IsDate()); + SvxRedlinDateMode eMode = m_xFilterCtr->GetDateMode(); + aChangeViewSet.SetTheDateMode( eMode ); + Date aFirstDate( m_xFilterCtr->GetFirstDate() ); + tools::Time aFirstTime( m_xFilterCtr->GetFirstTime() ); + Date aLastDate( m_xFilterCtr->GetLastDate() ); + tools::Time aLastTime( m_xFilterCtr->GetLastTime() ); + aChangeViewSet.SetTheFirstDateTime( DateTime( aFirstDate, aFirstTime ) ); + aChangeViewSet.SetTheLastDateTime( DateTime( aLastDate, aLastTime ) ); + aChangeViewSet.SetHasAuthor(m_xFilterCtr->IsAuthor()); + aChangeViewSet.SetTheAuthorToShow(m_xFilterCtr->GetSelectedAuthor()); + aChangeViewSet.SetHasRange(m_xFilterCtr->IsRange()); + aChangeViewSet.SetShowAccepted(m_xCbAccept->get_active()); + aChangeViewSet.SetShowRejected(m_xCbReject->get_active()); + aChangeViewSet.SetHasComment(m_xFilterCtr->IsComment()); + aChangeViewSet.SetTheComment(m_xFilterCtr->GetComment()); + ScRangeList aLocalRangeList; + aLocalRangeList.Parse(m_xFilterCtr->GetRange(), rDoc); + aChangeViewSet.SetTheRangeList(aLocalRangeList); + aChangeViewSet.AdjustDateMode( rDoc ); + rDoc.SetChangeViewSettings(aChangeViewSet); + m_rViewData.GetDocShell()->PostPaintGridAll(); + response(RET_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/inscldlg.cxx b/sc/source/ui/miscdlgs/inscldlg.cxx new file mode 100644 index 000000000..ac97c6ac3 --- /dev/null +++ b/sc/source/ui/miscdlgs/inscldlg.cxx @@ -0,0 +1,110 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <inscldlg.hxx> +#include <viewdata.hxx> +#include <strings.hrc> +#include <scresid.hxx> + +static sal_uInt8 nInsItemChecked = 0; + +ScInsertCellDlg::ScInsertCellDlg(weld::Window* pParent, bool bDisallowCellMove) + : GenericDialogController(pParent, "modules/scalc/ui/insertcells.ui", "InsertCellsDialog") + , m_xBtnCellsDown(m_xBuilder->weld_radio_button("down")) + , m_xBtnCellsRight(m_xBuilder->weld_radio_button("right")) + , m_xBtnInsRow(m_xBuilder->weld_radio_button("rows")) + , m_xBtnInsCol(m_xBuilder->weld_radio_button("cols")) + , m_xLbCellsRight(m_xBuilder->weld_label("right")) +{ + const ScViewData* pViewData = ScDocShell::GetViewData(); + if (pViewData && pViewData->GetDocument().IsLayoutRTL(pViewData->GetTabNo())) + m_xLbCellsRight->set_label(ScResId(SCSTR_INSERT_RTL)); + + if (bDisallowCellMove) + { + m_xBtnCellsDown->set_sensitive(false); + m_xBtnCellsRight->set_sensitive(false); + m_xBtnInsRow->set_active(true); + + switch (nInsItemChecked) + { + case 2: + m_xBtnInsRow->set_active(true); + break; + case 3: + m_xBtnInsCol->set_active(true); + break; + default: + m_xBtnInsRow->set_active(true); + break; + } + } + else + { + switch (nInsItemChecked) + { + case 0: + m_xBtnCellsDown->set_active(true); + break; + case 1: + m_xBtnCellsRight->set_active(true); + break; + case 2: + m_xBtnInsRow->set_active(true); + break; + case 3: + m_xBtnInsCol->set_active(true); + break; + } + } +} + +ScInsertCellDlg::~ScInsertCellDlg() {} + +InsCellCmd ScInsertCellDlg::GetInsCellCmd() const +{ + InsCellCmd nReturn = INS_NONE; + + if (m_xBtnCellsDown->get_active()) + { + nInsItemChecked = 0; + nReturn = INS_CELLSDOWN; + } + else if (m_xBtnCellsRight->get_active()) + { + nInsItemChecked = 1; + nReturn = INS_CELLSRIGHT; + } + else if (m_xBtnInsRow->get_active()) + { + nInsItemChecked = 2; + nReturn = INS_INSROWS_BEFORE; + } + else if (m_xBtnInsCol->get_active()) + { + nInsItemChecked = 3; + nReturn = INS_INSCOLS_BEFORE; + } + + return nReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/inscodlg.cxx b/sc/source/ui/miscdlgs/inscodlg.cxx new file mode 100644 index 000000000..879ed2835 --- /dev/null +++ b/sc/source/ui/miscdlgs/inscodlg.cxx @@ -0,0 +1,367 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <inscodlg.hxx> + +InsertDeleteFlags ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING; +ScPasteFunc ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::NONE; +InsertContentsFlags ScInsertContentsDlg::nPreviousChecks2 = InsertContentsFlags::NONE; +InsCellCmd ScInsertContentsDlg::nPreviousMoveMode = InsCellCmd::INS_NONE; + +ScInsertContentsDlg::ScInsertContentsDlg(weld::Window* pParent, + const OUString* pStrTitle ) + : GenericDialogController(pParent, "modules/scalc/ui/pastespecial.ui", "PasteSpecial") + , bOtherDoc(false) + , bFillMode(false) + , bChangeTrack(false) + , bMoveDownDisabled(false) + , bMoveRightDisabled(false) + , mxBtnInsAll(m_xBuilder->weld_check_button("paste_all")) + , mxBtnInsStrings(m_xBuilder->weld_check_button("text")) + , mxBtnInsNumbers(m_xBuilder->weld_check_button("numbers")) + , mxBtnInsDateTime(m_xBuilder->weld_check_button("datetime")) + , mxBtnInsFormulas(m_xBuilder->weld_check_button("formulas")) + , mxBtnInsNotes(m_xBuilder->weld_check_button("comments")) + , mxBtnInsAttrs(m_xBuilder->weld_check_button("formats")) + , mxBtnInsObjects(m_xBuilder->weld_check_button("objects")) + , mxBtnSkipEmptyCells(m_xBuilder->weld_check_button("skip_empty")) + , mxBtnTranspose(m_xBuilder->weld_check_button("transpose")) + , mxBtnLink(m_xBuilder->weld_check_button("link")) + , mxRbNoOp(m_xBuilder->weld_radio_button("none")) + , mxRbAdd(m_xBuilder->weld_radio_button("add")) + , mxRbSub(m_xBuilder->weld_radio_button("subtract")) + , mxRbMul(m_xBuilder->weld_radio_button("multiply")) + , mxRbDiv(m_xBuilder->weld_radio_button("divide")) + , mxRbMoveNone(m_xBuilder->weld_radio_button("no_shift")) + , mxRbMoveDown(m_xBuilder->weld_radio_button("move_down")) + , mxRbMoveRight(m_xBuilder->weld_radio_button("move_right")) + , mxBtnShortCutPasteValuesOnly(m_xBuilder->weld_button("paste_values_only")) + , mxBtnShortCutPasteValuesFormats(m_xBuilder->weld_button("paste_values_formats")) + , mxBtnShortCutPasteTranspose(m_xBuilder->weld_button("paste_transpose")) + , mxBtnShortCutPasteFormats(m_xBuilder->weld_button("paste_formats")) + , mxImmediately(m_xBuilder->weld_check_button("cbImmediately")) +{ + if (pStrTitle) + m_xDialog->set_title(*pStrTitle); + + SetInsContentsCmdBits( ScInsertContentsDlg::nPreviousChecks ); + SetFormulaCmdBits( ScInsertContentsDlg::nPreviousFormulaChecks ); + SetCellCmdFlags( ScInsertContentsDlg::nPreviousMoveMode ); + SetContentsFlags( ScInsertContentsDlg::nPreviousChecks2 ); + DisableChecks( mxBtnInsAll->get_active() ); + + mxBtnInsAll->connect_toggled( LINK( this, ScInsertContentsDlg, InsAllHdl ) ); + mxBtnLink->connect_toggled( LINK( this, ScInsertContentsDlg, LinkBtnHdl ) ); + mxBtnShortCutPasteValuesOnly->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) ); + mxBtnShortCutPasteValuesFormats->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) ); + mxBtnShortCutPasteTranspose->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) ); + mxBtnShortCutPasteFormats->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) ); +} + +InsertDeleteFlags ScInsertContentsDlg::GetInsContentsCmdBits() const +{ + ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::NONE; + + if ( mxBtnInsStrings->get_active() ) + ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::STRING; + if ( mxBtnInsNumbers->get_active() ) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::VALUE; + if ( mxBtnInsDateTime->get_active()) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::DATETIME; + if ( mxBtnInsFormulas->get_active()) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::FORMULA; + if ( mxBtnInsNotes->get_active() ) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::NOTE; + if ( mxBtnInsAttrs->get_active() ) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::ATTRIB; + if ( mxBtnInsObjects->get_active() ) + ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::OBJECTS; + + return ( mxBtnInsAll->get_active() + ? InsertDeleteFlags::ALL + : ScInsertContentsDlg::nPreviousChecks ); +} + +void ScInsertContentsDlg::SetInsContentsCmdBits(const InsertDeleteFlags eFlags) +{ + mxBtnInsNumbers->set_active((InsertDeleteFlags::VALUE & eFlags) == InsertDeleteFlags::VALUE); + mxBtnInsDateTime->set_active((InsertDeleteFlags::DATETIME & eFlags) == InsertDeleteFlags::DATETIME); + mxBtnInsStrings->set_active((InsertDeleteFlags::STRING & eFlags) == InsertDeleteFlags::STRING); + mxBtnInsNotes->set_active((InsertDeleteFlags::NOTE & eFlags) == InsertDeleteFlags::NOTE); + mxBtnInsFormulas->set_active((InsertDeleteFlags::FORMULA & eFlags) == InsertDeleteFlags::FORMULA); + mxBtnInsAttrs->set_active((InsertDeleteFlags::ATTRIB & eFlags) == InsertDeleteFlags::ATTRIB); + mxBtnInsObjects->set_active((InsertDeleteFlags::OBJECTS & eFlags) == InsertDeleteFlags::OBJECTS); + mxBtnInsAll->set_active((InsertDeleteFlags::ALL & eFlags) == InsertDeleteFlags::ALL); + DisableChecks( mxBtnInsAll->get_active() ); +} + +void ScInsertContentsDlg::SetFormulaCmdBits(const ScPasteFunc eFlags) +{ + switch( eFlags ) + { + case ScPasteFunc::NONE: mxRbNoOp->set_active(true); break; + case ScPasteFunc::ADD: mxRbAdd->set_active(true); break; + case ScPasteFunc::SUB: mxRbSub->set_active(true); break; + case ScPasteFunc::MUL: mxRbMul->set_active(true); break; + case ScPasteFunc::DIV: mxRbDiv->set_active(true); break; + } +} + +void ScInsertContentsDlg::SetCellCmdFlags(const InsCellCmd eFlags) +{ + switch( eFlags ) + { + case INS_NONE: mxRbMoveNone->set_active(true); break; + case INS_CELLSDOWN: mxRbMoveDown->set_active(true); break; + case INS_CELLSRIGHT: mxRbMoveRight->set_active(true); break; + case INS_INSROWS_BEFORE: + case INS_INSCOLS_BEFORE: + case INS_INSROWS_AFTER: + case INS_INSCOLS_AFTER: break; + } +} + +void ScInsertContentsDlg::SetContentsFlags(const InsertContentsFlags eFlags) +{ + mxBtnSkipEmptyCells->set_active(bool(InsertContentsFlags::NoEmpty & eFlags)); + mxBtnTranspose->set_active(bool(InsertContentsFlags::Trans & eFlags)); + mxBtnLink->set_active(bool(InsertContentsFlags::Link & eFlags)); +} + +InsCellCmd ScInsertContentsDlg::GetMoveMode() const +{ + if ( mxRbMoveDown->get_active() ) + return INS_CELLSDOWN; + if ( mxRbMoveRight->get_active() ) + return INS_CELLSRIGHT; + + return INS_NONE; +} + +bool ScInsertContentsDlg::IsSkipEmptyCells() const +{ + return mxBtnSkipEmptyCells->get_active(); +} + +bool ScInsertContentsDlg::IsTranspose() const +{ + return mxBtnTranspose->get_active(); +} + +bool ScInsertContentsDlg::IsLink() const +{ + return mxBtnLink->get_active(); +} + +void ScInsertContentsDlg::DisableChecks( bool bInsAllChecked ) +{ + if ( bInsAllChecked ) + { + mxBtnInsStrings->set_sensitive(false); + mxBtnInsNumbers->set_sensitive(false); + mxBtnInsDateTime->set_sensitive(false); + mxBtnInsFormulas->set_sensitive(false); + mxBtnInsNotes->set_sensitive(false); + mxBtnInsAttrs->set_sensitive(false); + mxBtnInsObjects->set_sensitive(false); + } + else + { + mxBtnInsStrings->set_sensitive(true); + mxBtnInsNumbers->set_sensitive(true); + mxBtnInsDateTime->set_sensitive(true); + mxBtnInsFormulas->set_sensitive(true); + mxBtnInsNotes->set_sensitive(true); + mxBtnInsAttrs->set_sensitive(true); + + // "Objects" is disabled for "Fill Tables" + if ( bFillMode ) + mxBtnInsObjects->set_sensitive(false); + else + mxBtnInsObjects->set_sensitive(true); + } +} + +// Link to other document -> everything else is disabled + +void ScInsertContentsDlg::TestModes() +{ + if ( bOtherDoc && mxBtnLink->get_active() ) + { + mxBtnSkipEmptyCells->set_sensitive(false); + mxBtnTranspose->set_sensitive(false); + mxRbNoOp->set_sensitive(false); + mxRbAdd->set_sensitive(false); + mxRbSub->set_sensitive(false); + mxRbMul->set_sensitive(false); + mxRbDiv->set_sensitive(false); + + mxRbMoveNone->set_sensitive(false); + mxRbMoveDown->set_sensitive(false); + mxRbMoveRight->set_sensitive(false); + + mxBtnInsAll->set_sensitive(false); + DisableChecks(true); + } + else + { + mxBtnSkipEmptyCells->set_sensitive(true); + mxBtnTranspose->set_sensitive(!bFillMode); + mxRbNoOp->set_sensitive(true); + mxRbAdd->set_sensitive(true); + mxRbSub->set_sensitive(true); + mxRbMul->set_sensitive(true); + mxRbDiv->set_sensitive(true); + + mxRbMoveNone->set_sensitive(!bFillMode && !bChangeTrack && !(bMoveDownDisabled && bMoveRightDisabled)); + mxRbMoveDown->set_sensitive(!bFillMode && !bChangeTrack && !bMoveDownDisabled); + mxRbMoveRight->set_sensitive(!bFillMode && !bChangeTrack && !bMoveRightDisabled); + + mxBtnInsAll->set_sensitive(true); + DisableChecks( mxBtnInsAll->get_active() ); + } +} + +void ScInsertContentsDlg::SetOtherDoc( bool bSet ) +{ + if ( bSet != bOtherDoc ) + { + bOtherDoc = bSet; + TestModes(); + if ( bSet ) + mxRbMoveNone->set_active(true); + } +} + +void ScInsertContentsDlg::SetFillMode( bool bSet ) +{ + if ( bSet != bFillMode ) + { + bFillMode = bSet; + TestModes(); + if ( bSet ) + mxRbMoveNone->set_active(true); + } +} + +void ScInsertContentsDlg::SetChangeTrack( bool bSet ) +{ + if ( bSet != bChangeTrack ) + { + bChangeTrack = bSet; + TestModes(); + if ( bSet ) + mxRbMoveNone->set_active(true); + } +} + +void ScInsertContentsDlg::SetCellShiftDisabled( CellShiftDisabledFlags nDisable ) +{ + bool bDown(nDisable & CellShiftDisabledFlags::Down); + bool bRight(nDisable & CellShiftDisabledFlags::Right); + if ( bDown != bMoveDownDisabled || bRight != bMoveRightDisabled ) + { + bMoveDownDisabled = bDown; + bMoveRightDisabled = bRight; + TestModes(); + if ( bMoveDownDisabled && mxRbMoveDown->get_active() ) + mxRbMoveNone->set_active(true); + if ( bMoveRightDisabled && mxRbMoveRight->get_active() ) + mxRbMoveNone->set_active(true); + } +} + +IMPL_LINK(ScInsertContentsDlg, ShortCutHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == mxBtnShortCutPasteValuesOnly.get()) + { + SetInsContentsCmdBits( InsertDeleteFlags::STRING | InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME ); + SetContentsFlags( InsertContentsFlags::NONE ); + } + else if (&rBtn == mxBtnShortCutPasteValuesFormats.get()) + { + SetInsContentsCmdBits( InsertDeleteFlags::STRING | InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::ATTRIB ); + SetContentsFlags( InsertContentsFlags::NONE ); + } + else if (&rBtn == mxBtnShortCutPasteTranspose.get()) + { + SetInsContentsCmdBits( InsertDeleteFlags::ALL ); + SetContentsFlags( InsertContentsFlags::Trans ); + } + else if (&rBtn == mxBtnShortCutPasteFormats.get()) + { + SetInsContentsCmdBits( InsertDeleteFlags::ATTRIB ); + SetContentsFlags( InsertContentsFlags::NONE ); + } + else + return; + + SetCellCmdFlags( InsCellCmd::INS_NONE ); + SetFormulaCmdBits(ScPasteFunc::NONE); + if (mxImmediately->get_active()) m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ScInsertContentsDlg, InsAllHdl, weld::Toggleable&, void) +{ + DisableChecks( mxBtnInsAll->get_active() ); +} + +IMPL_LINK_NOARG(ScInsertContentsDlg, LinkBtnHdl, weld::Toggleable&, void) +{ + TestModes(); +} + +ScInsertContentsDlg::~ScInsertContentsDlg() +{ + ScInsertContentsDlg::nPreviousChecks2 = InsertContentsFlags::NONE; + if(mxBtnSkipEmptyCells->get_active()) + ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::NoEmpty; + if( mxBtnTranspose->get_active()) + ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::Trans; + if( mxBtnLink->get_active() ) + ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::Link; + + if (!bFillMode) // in FillMode, None is checked and all three options are disabled + { + if ( mxRbMoveNone->get_active() ) + ScInsertContentsDlg::nPreviousMoveMode = INS_NONE; + else if ( mxRbMoveDown->get_active() ) + ScInsertContentsDlg::nPreviousMoveMode = INS_CELLSDOWN; + else if ( mxRbMoveRight->get_active() ) + ScInsertContentsDlg::nPreviousMoveMode = INS_CELLSRIGHT; + } +} + +ScPasteFunc ScInsertContentsDlg::GetFormulaCmdBits() const +{ + ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::NONE; + if(mxRbAdd->get_active()) + ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::ADD; + else if(mxRbSub->get_active()) + ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::SUB; + else if(mxRbMul->get_active()) + ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::MUL; + else if(mxRbDiv->get_active()) + ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::DIV; + return ScInsertContentsDlg::nPreviousFormulaChecks; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/instbdlg.cxx b/sc/source/ui/miscdlgs/instbdlg.cxx new file mode 100644 index 000000000..947b983ec --- /dev/null +++ b/sc/source/ui/miscdlgs/instbdlg.cxx @@ -0,0 +1,356 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <sfx2/docfile.hxx> +#include <sfx2/docinsert.hxx> +#include <sfx2/filedlghelper.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <docsh.hxx> +#include <viewdata.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <instbdlg.hxx> + +ScInsertTableDlg::ScInsertTableDlg(weld::Window* pParent, ScViewData& rData, SCTAB nTabCount, bool bFromFile) + : GenericDialogController(pParent, "modules/scalc/ui/insertsheet.ui", "InsertSheetDialog") + , aBrowseTimer("ScInsertTableDlg aBrowseTimer") + , rViewData(rData) + , rDoc(rData.GetDocument()) + , pDocShTables(nullptr) + , bMustClose(false) + , nSelTabIndex(0) + , nTableCount(nTabCount) + , m_xBtnBefore(m_xBuilder->weld_radio_button("before")) + , m_xBtnBehind(m_xBuilder->weld_radio_button("after")) + , m_xBtnNew(m_xBuilder->weld_radio_button("new")) + , m_xBtnFromFile(m_xBuilder->weld_radio_button("fromfile")) + , m_xFtCount(m_xBuilder->weld_label("countft")) + , m_xNfCount(m_xBuilder->weld_spin_button("countnf")) + , m_xFtName(m_xBuilder->weld_label("nameft")) + , m_xEdName(m_xBuilder->weld_entry("nameed")) + , m_xLbTables(m_xBuilder->weld_tree_view("tables")) + , m_xFtPath(m_xBuilder->weld_label("path")) + , m_xBtnBrowse(m_xBuilder->weld_button("browse")) + , m_xBtnLink(m_xBuilder->weld_check_button("link")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + m_sSheetDotDotDot = m_xEdName->get_text(); + m_xLbTables->set_size_request(-1, m_xLbTables->get_height_rows(8)); + Init_Impl(bFromFile); +} + +ScInsertTableDlg::~ScInsertTableDlg() +{ + if (pDocShTables) + pDocShTables->DoClose(); + pDocInserter.reset(); +} + +void ScInsertTableDlg::Init_Impl( bool bFromFile ) +{ + m_xLbTables->set_selection_mode(SelectionMode::Multiple); + m_xBtnBrowse->connect_clicked( LINK( this, ScInsertTableDlg, BrowseHdl_Impl ) ); + m_xBtnNew->connect_toggled( LINK( this, ScInsertTableDlg, ChoiceHdl_Impl ) ); + m_xBtnFromFile->connect_toggled( LINK( this, ScInsertTableDlg, ChoiceHdl_Impl ) ); + m_xLbTables->connect_changed( LINK( this, ScInsertTableDlg, SelectHdl_Impl ) ); + m_xNfCount->connect_value_changed( LINK( this, ScInsertTableDlg, CountHdl_Impl)); + m_xBtnOk->connect_clicked( LINK( this, ScInsertTableDlg, DoEnterHdl )); + m_xBtnBefore->set_active(true); + + m_xNfCount->set_max(MAXTAB - rDoc.GetTableCount() + 1); + m_xNfCount->set_value(nTableCount); + + if(nTableCount==1) + { + OUString aName; + rDoc.CreateValidTabName( aName ); + m_xEdName->set_text( aName ); + } + else + { + m_xEdName->set_text(m_sSheetDotDotDot); + m_xFtName->set_sensitive(false); + m_xEdName->set_sensitive(false); + } + + bool bShared = rViewData.GetDocShell() && rViewData.GetDocShell()->IsDocShared(); + + if ( !bFromFile || bShared ) + { + m_xBtnNew->set_active(true); + SetNewTable_Impl(); + if ( bShared ) + { + m_xBtnFromFile->set_sensitive(false); + } + } + else + { + m_xBtnFromFile->set_active(true); + SetFromTo_Impl(); + + aBrowseTimer.SetInvokeHandler( LINK( this, ScInsertTableDlg, BrowseTimeoutHdl ) ); + aBrowseTimer.SetTimeout( 200 ); + } +} + +short ScInsertTableDlg::run() +{ + if (m_xBtnFromFile->get_active()) + aBrowseTimer.Start(); + + return GenericDialogController::run(); +} + +void ScInsertTableDlg::SetNewTable_Impl() +{ + if (!m_xBtnNew->get_active() ) + return; + + m_xNfCount->set_sensitive(true); + m_xFtCount->set_sensitive(true); + m_xLbTables->set_sensitive(false); + m_xFtPath->set_sensitive(false); + m_xBtnBrowse->set_sensitive(false); + m_xBtnLink->set_sensitive(false); + + if(nTableCount==1) + { + m_xEdName->set_sensitive(true); + m_xFtName->set_sensitive(true); + } +} + +void ScInsertTableDlg::SetFromTo_Impl() +{ + if (m_xBtnFromFile->get_active() ) + { + m_xEdName->set_sensitive(false); + m_xFtName->set_sensitive(false); + m_xFtCount->set_sensitive(false); + m_xNfCount->set_sensitive(false); + m_xLbTables->set_sensitive(true); + m_xFtPath->set_sensitive(true); + m_xBtnBrowse->set_sensitive(true); + m_xBtnLink->set_sensitive(true); + } +} + +void ScInsertTableDlg::FillTables_Impl( const ScDocument* pSrcDoc ) +{ + m_xLbTables->freeze(); + m_xLbTables->clear(); + + if ( pSrcDoc ) + { + SCTAB nCount = pSrcDoc->GetTableCount(); + OUString aName; + + for (SCTAB i=0; i<nCount; ++i) + { + pSrcDoc->GetName( i, aName ); + m_xLbTables->append_text(aName); + } + } + + m_xLbTables->thaw(); + + if (m_xLbTables->n_children() == 1) + m_xLbTables->select(0); +} + +const OUString* ScInsertTableDlg::GetFirstTable( sal_uInt16* pN ) +{ + const OUString* pStr = nullptr; + + if ( m_xBtnNew->get_active() ) + { + aStrCurSelTable = m_xEdName->get_text(); + pStr = &aStrCurSelTable; + } + else + { + std::vector<int> aRows(m_xLbTables->get_selected_rows()); + if (nSelTabIndex < aRows.size()) + { + aStrCurSelTable = m_xLbTables->get_text(aRows[0]); + pStr = &aStrCurSelTable; + if ( pN ) + *pN = aRows[0]; + nSelTabIndex = 1; + } + } + + return pStr; +} + +const OUString* ScInsertTableDlg::GetNextTable( sal_uInt16* pN ) +{ + if (m_xBtnNew->get_active()) + return nullptr; + + std::vector<int> aRows(m_xLbTables->get_selected_rows()); + + const OUString* pStr = nullptr; + if (nSelTabIndex < aRows.size()) + { + aStrCurSelTable = m_xLbTables->get_text(aRows[nSelTabIndex]); + pStr = &aStrCurSelTable; + if ( pN ) + *pN = aRows[nSelTabIndex]; + nSelTabIndex++; + } + + return pStr; +} + +// Handler: + +IMPL_LINK_NOARG(ScInsertTableDlg, CountHdl_Impl, weld::SpinButton&, void) +{ + nTableCount = static_cast<SCTAB>(m_xNfCount->get_value()); + if ( nTableCount==1) + { + OUString aName; + rDoc.CreateValidTabName( aName ); + m_xEdName->set_text( aName ); + m_xFtName->set_sensitive(true); + m_xEdName->set_sensitive(true); + } + else + { + m_xEdName->set_text(m_sSheetDotDotDot); + m_xFtName->set_sensitive(false); + m_xEdName->set_sensitive(false); + } + + DoEnable_Impl(); +} + +IMPL_LINK(ScInsertTableDlg, ChoiceHdl_Impl, weld::Toggleable&, rButton, void) +{ + if (!rButton.get_active()) + return; + + if ( m_xBtnNew->get_active() ) + SetNewTable_Impl(); + else + SetFromTo_Impl(); + + DoEnable_Impl(); +} + +IMPL_LINK_NOARG(ScInsertTableDlg, BrowseHdl_Impl, weld::Button&, void) +{ + pDocInserter.reset(); + pDocInserter.reset( new ::sfx2::DocumentInserter(m_xDialog.get(), ScDocShell::Factory().GetFactoryName()) ); + pDocInserter->StartExecuteModal( LINK( this, ScInsertTableDlg, DialogClosedHdl ) ); +} + +IMPL_LINK_NOARG(ScInsertTableDlg, SelectHdl_Impl, weld::TreeView&, void) +{ + DoEnable_Impl(); +} + +void ScInsertTableDlg::DoEnable_Impl() +{ + if ( m_xBtnNew->get_active() || ( pDocShTables && m_xLbTables->count_selected_rows() ) ) + m_xBtnOk->set_sensitive(true); + else + m_xBtnOk->set_sensitive(false); +} + +IMPL_LINK_NOARG(ScInsertTableDlg, DoEnterHdl, weld::Button&, void) +{ + if (nTableCount > 1 || ScDocument::ValidTabName(m_xEdName->get_text())) + { + m_xDialog->response(RET_OK); + } + else + { + OUString aErrMsg ( ScResId( STR_INVALIDTABNAME ) ); + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning, + VclButtonsType::Ok, aErrMsg)); + xBox->run(); + } +} + +IMPL_LINK_NOARG(ScInsertTableDlg, BrowseTimeoutHdl, Timer *, void) +{ + bMustClose = true; + BrowseHdl_Impl(*m_xBtnBrowse); +} + +IMPL_LINK( ScInsertTableDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void ) +{ + if ( ERRCODE_NONE == _pFileDlg->GetError() ) + { + std::unique_ptr<SfxMedium> pMed = pDocInserter->CreateMedium(); + if ( pMed ) + { + // ERRCTX_SFX_OPENDOC -> "Error loading document" + SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() ); + + if ( pDocShTables ) + pDocShTables->DoClose(); // deletion is done when assigning to the reference + + pMed->UseInteractionHandler( true ); // to enable the filter options dialog + + pDocShTables = new ScDocShell; + aDocShTablesRef = pDocShTables; + + { + weld::WaitObject aWait(m_xDialog.get()); + pDocShTables->DoLoad(pMed.release()); + } + + ErrCode nErr = pDocShTables->GetErrorCode(); + if ( nErr ) + ErrorHandler::HandleError(nErr, m_xDialog.get()); // warnings, too + + if ( !pDocShTables->GetError() ) // errors only + { + FillTables_Impl( &pDocShTables->GetDocument() ); + m_xFtPath->set_label(pDocShTables->GetTitle(SFX_TITLE_FULLNAME)); + } + else + { + pDocShTables->DoClose(); + aDocShTablesRef.clear(); + pDocShTables = nullptr; + + FillTables_Impl( nullptr ); + m_xFtPath->set_label(OUString()); + } + } + + DoEnable_Impl(); + } + else if ( bMustClose ) + // execute slot FID_INS_TABLE_EXT and cancel file dialog + m_xDialog->response(RET_CANCEL); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/lbseldlg.cxx b/sc/source/ui/miscdlgs/lbseldlg.cxx new file mode 100644 index 000000000..4c0b592c7 --- /dev/null +++ b/sc/source/ui/miscdlgs/lbseldlg.cxx @@ -0,0 +1,54 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <lbseldlg.hxx> + +ScSelEntryDlg::ScSelEntryDlg(weld::Window* pParent, const std::vector<OUString> &rEntryList) + : GenericDialogController(pParent, "modules/scalc/ui/selectrange.ui", "SelectRangeDialog") + , m_xLb(m_xBuilder->weld_tree_view("treeview")) +{ + m_xLb->set_size_request(m_xLb->get_approximate_digit_width() * 32, + m_xLb->get_height_rows(8)); + m_xLb->connect_row_activated(LINK(this, ScSelEntryDlg, DblClkHdl)); + + for (const auto& rEntry : rEntryList) + m_xLb->append_text(rEntry); + + if (m_xLb->n_children() > 0) + m_xLb->select(0); +} + +ScSelEntryDlg::~ScSelEntryDlg() +{ +} + +OUString ScSelEntryDlg::GetSelectedEntry() const +{ + return m_xLb->get_selected_text(); +} + +IMPL_LINK_NOARG(ScSelEntryDlg, DblClkHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/linkarea.cxx b/sc/source/ui/miscdlgs/linkarea.cxx new file mode 100644 index 000000000..09cfe6c3c --- /dev/null +++ b/sc/source/ui/miscdlgs/linkarea.cxx @@ -0,0 +1,336 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/docinsert.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/filedlghelper.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/inettbc.hxx> +#include <svtools/sfxecode.hxx> +#include <o3tl/string_view.hxx> + +#include <linkarea.hxx> +#include <docsh.hxx> +#include <tablink.hxx> +#include <scresid.hxx> +#include <strings.hrc> + +ScLinkedAreaDlg::ScLinkedAreaDlg(weld::Widget* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/externaldata.ui", "ExternalDataDialog") + , m_pSourceShell(nullptr) + , m_xCbUrl(new SvtURLBox(m_xBuilder->weld_combo_box("url"))) + , m_xBtnBrowse(m_xBuilder->weld_button("browse")) + , m_xLbRanges(m_xBuilder->weld_tree_view("ranges")) + , m_xBtnReload(m_xBuilder->weld_check_button("reload")) + , m_xNfDelay(m_xBuilder->weld_spin_button("delay")) + , m_xFtSeconds(m_xBuilder->weld_label("secondsft")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + m_xLbRanges->set_selection_mode(SelectionMode::Multiple); + + m_xCbUrl->connect_entry_activate(LINK(this, ScLinkedAreaDlg, FileHdl)); + m_xBtnBrowse->connect_clicked(LINK( this, ScLinkedAreaDlg, BrowseHdl)); + m_xLbRanges->connect_changed(LINK( this, ScLinkedAreaDlg, RangeHdl)); + m_xLbRanges->set_size_request(m_xLbRanges->get_approximate_digit_width() * 54, + m_xLbRanges->get_height_rows(5)); + m_xBtnReload->connect_toggled(LINK( this, ScLinkedAreaDlg, ReloadHdl)); + UpdateEnable(); +} + +ScLinkedAreaDlg::~ScLinkedAreaDlg() +{ +} + +constexpr OUStringLiteral FILTERNAME_HTML = u"HTML (StarCalc)"; +constexpr OUStringLiteral FILTERNAME_QUERY = u"calc_HTML_WebQuery"; + +IMPL_LINK_NOARG(ScLinkedAreaDlg, BrowseHdl, weld::Button&, void) +{ + m_xDocInserter.reset( new sfx2::DocumentInserter(m_xDialog.get(), ScDocShell::Factory().GetFactoryName()) ); + m_xDocInserter->StartExecuteModal( LINK( this, ScLinkedAreaDlg, DialogClosedHdl ) ); +} + +IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, weld::ComboBox&, bool) +{ + OUString aEntered = m_xCbUrl->GetURL(); + if (m_pSourceShell) + { + SfxMedium* pMed = m_pSourceShell->GetMedium(); + if ( aEntered == pMed->GetName() ) + { + // already loaded - nothing to do + return true; + } + } + + OUString aFilter; + OUString aOptions; + // get filter name by looking at the file content (bWithContent = true) + // Break operation if any error occurred inside. + if (!ScDocumentLoader::GetFilterName( aEntered, aFilter, aOptions, true, false )) + return true; + + // #i53241# replace HTML filter with DataQuery filter + if (aFilter == FILTERNAME_HTML) + aFilter = FILTERNAME_QUERY; + + LoadDocument( aEntered, aFilter, aOptions ); + + UpdateSourceRanges(); + UpdateEnable(); + + return true; +} + +void ScLinkedAreaDlg::LoadDocument( const OUString& rFile, const OUString& rFilter, const OUString& rOptions ) +{ + if (m_pSourceShell) + { + // unload old document + m_pSourceShell->DoClose(); + m_pSourceShell = nullptr; + aSourceRef.clear(); + } + + if ( rFile.isEmpty() ) + return; + + weld::WaitObject aWait(m_xDialog.get()); + + OUString aNewFilter = rFilter; + OUString aNewOptions = rOptions; + + SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, rFile ); + + ScDocumentLoader aLoader( rFile, aNewFilter, aNewOptions, 0, m_xDialog.get() ); // with interaction + m_pSourceShell = aLoader.GetDocShell(); + if (m_pSourceShell) + { + ErrCode nErr = m_pSourceShell->GetErrorCode(); + if (nErr) + ErrorHandler::HandleError( nErr ); // including warnings + + aSourceRef = m_pSourceShell; + aLoader.ReleaseDocRef(); // don't call DoClose in DocLoader dtor + } +} + +void ScLinkedAreaDlg::InitFromOldLink( const OUString& rFile, const OUString& rFilter, + const OUString& rOptions, std::u16string_view rSource, + sal_Int32 nRefreshDelaySeconds ) +{ + LoadDocument( rFile, rFilter, rOptions ); + if (m_pSourceShell) + { + SfxMedium* pMed = m_pSourceShell->GetMedium(); + m_xCbUrl->set_entry_text(pMed->GetName()); + } + else + m_xCbUrl->set_entry_text(OUString()); + + UpdateSourceRanges(); + + if (!rSource.empty()) + { + sal_Int32 nIdx {0}; + do + { + m_xLbRanges->select_text(OUString(o3tl::getToken(rSource, 0, ';', nIdx))); + } + while (nIdx>0); + } + + bool bDoRefresh = (nRefreshDelaySeconds != 0); + m_xBtnReload->set_active(bDoRefresh); + if (bDoRefresh) + m_xNfDelay->set_value(nRefreshDelaySeconds); + + UpdateEnable(); +} + +IMPL_LINK_NOARG(ScLinkedAreaDlg, RangeHdl, weld::TreeView&, void) +{ + UpdateEnable(); +} + +IMPL_LINK_NOARG(ScLinkedAreaDlg, ReloadHdl, weld::Toggleable&, void) +{ + UpdateEnable(); +} + +IMPL_LINK( ScLinkedAreaDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void ) +{ + if ( _pFileDlg->GetError() != ERRCODE_NONE ) + return; + + std::unique_ptr<SfxMedium> pMed = m_xDocInserter->CreateMedium(); + if ( pMed ) + { + weld::WaitObject aWait(m_xDialog.get()); + + // replace HTML filter with DataQuery filter + std::shared_ptr<const SfxFilter> pFilter = pMed->GetFilter(); + if (pFilter && FILTERNAME_HTML == pFilter->GetFilterName()) + { + std::shared_ptr<const SfxFilter> pNewFilter = + ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( FILTERNAME_QUERY ); + if( pNewFilter ) + pMed->SetFilter( pNewFilter ); + } + + // ERRCTX_SFX_OPENDOC -> "Error loading document" + SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() ); + + if (m_pSourceShell) + m_pSourceShell->DoClose(); // deleted when assigning aSourceRef + + pMed->UseInteractionHandler( true ); // to enable the filter options dialog + + m_pSourceShell = new ScDocShell; + aSourceRef = m_pSourceShell; + m_pSourceShell->DoLoad( pMed.get() ); + + ErrCode nErr = m_pSourceShell->GetErrorCode(); + if (nErr) + ErrorHandler::HandleError( nErr ); // including warnings + + if (!m_pSourceShell->GetError()) // only errors + { + m_xCbUrl->set_entry_text(pMed->GetName()); + } + else + { + m_pSourceShell->DoClose(); + m_pSourceShell = nullptr; + aSourceRef.clear(); + + m_xCbUrl->set_entry_text(OUString()); + } + pMed.release(); // DoLoad takes ownership + } + + UpdateSourceRanges(); + UpdateEnable(); +} + +#undef FILTERNAME_HTML +#undef FILTERNAME_QUERY + +void ScLinkedAreaDlg::UpdateSourceRanges() +{ + m_xLbRanges->freeze(); + + m_xLbRanges->clear(); + if ( m_pSourceShell ) + { + std::shared_ptr<const SfxFilter> pFilter = m_pSourceShell->GetMedium()->GetFilter(); + if (pFilter && pFilter->GetFilterName() == SC_TEXT_CSV_FILTER_NAME) + { + // Insert dummy All range to have something selectable. + m_xLbRanges->append_text("CSV_all"); + } + + // tdf#142600 - list tables in order of their appearance in the document's source + const ScRangeName* pRangeName = m_pSourceShell->GetDocument().GetRangeName(); + for (size_t i = 1; i <= pRangeName->index_size(); i++) + { + if (const ScRangeData* pRangeData = pRangeName->findByIndex(i)) + { + m_xLbRanges->append_text(pRangeData->GetName()); + } + } + } + + m_xLbRanges->thaw(); + + if (m_xLbRanges->n_children() >= 1) + m_xLbRanges->select(0); + else + { + m_xLbRanges->append_text(ScResId(STR_NO_NAMED_RANGES_AVAILABLE)); + m_xLbRanges->set_sensitive(false); + } +} + +void ScLinkedAreaDlg::UpdateEnable() +{ + bool bEnable = ( m_pSourceShell && m_xLbRanges->count_selected_rows() ); + m_xBtnOk->set_sensitive(bEnable); + + bool bReload = m_xBtnReload->get_active(); + m_xNfDelay->set_sensitive(bReload); + m_xFtSeconds->set_sensitive(bReload); +} + +OUString ScLinkedAreaDlg::GetURL() const +{ + if (m_pSourceShell) + { + SfxMedium* pMed = m_pSourceShell->GetMedium(); + return pMed->GetName(); + } + return OUString(); +} + +OUString ScLinkedAreaDlg::GetFilter() const +{ + if (m_pSourceShell) + { + SfxMedium* pMed = m_pSourceShell->GetMedium(); + return pMed->GetFilter()->GetFilterName(); + } + return OUString(); +} + +OUString ScLinkedAreaDlg::GetOptions() const +{ + if (m_pSourceShell) + { + SfxMedium* pMed = m_pSourceShell->GetMedium(); + return ScDocumentLoader::GetOptions( *pMed ); + } + return OUString(); +} + +OUString ScLinkedAreaDlg::GetSource() const +{ + OUStringBuffer aBuf; + std::vector<OUString> aSelection = m_xLbRanges->get_selected_rows_text(); + for (size_t i = 0; i < aSelection.size(); ++i) + { + if (i > 0) + aBuf.append(';'); + aBuf.append(aSelection[i]); + } + return aBuf.makeStringAndClear(); +} + +sal_Int32 ScLinkedAreaDlg::GetRefreshDelaySeconds() const +{ + if (m_xBtnReload->get_active()) + return m_xNfDelay->get_value(); + else + return 0; // disabled +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/mergecellsdialog.cxx b/sc/source/ui/miscdlgs/mergecellsdialog.cxx new file mode 100644 index 000000000..2bfcc5da3 --- /dev/null +++ b/sc/source/ui/miscdlgs/mergecellsdialog.cxx @@ -0,0 +1,36 @@ +/* -*- 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/. + * + */ + +#include <mergecellsdialog.hxx> + +ScMergeCellsDialog::ScMergeCellsDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/mergecellsdialog.ui", "MergeCellsDialog") + , m_xRBMoveContent(m_xBuilder->weld_radio_button("move-cells-radio")) + , m_xRBKeepContent(m_xBuilder->weld_radio_button("keep-content-radio")) + , m_xRBEmptyContent(m_xBuilder->weld_radio_button("empty-cells-radio")) +{ + m_xRBKeepContent->set_active(true); +} + +ScMergeCellsDialog::~ScMergeCellsDialog() {} + +ScMergeCellsOption ScMergeCellsDialog::GetMergeCellsOption() const +{ + if (m_xRBMoveContent->get_active()) + return MoveContentHiddenCells; + if (m_xRBKeepContent->get_active()) + return KeepContentHiddenCells; + if (m_xRBEmptyContent->get_active()) + return EmptyContentHiddenCells; + assert(!"Unknown selection for merge cells."); + return KeepContentHiddenCells; // default value +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/mtrindlg.cxx b/sc/source/ui/miscdlgs/mtrindlg.cxx new file mode 100644 index 000000000..7f234131f --- /dev/null +++ b/sc/source/ui/miscdlgs/mtrindlg.cxx @@ -0,0 +1,104 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <mtrindlg.hxx> + +ScMetricInputDlg::ScMetricInputDlg( weld::Window* pParent, + const OString& sDialogName, + tools::Long nCurrent, + tools::Long nDefault, + FieldUnit eFUnit, + sal_uInt16 nDecimals, + tools::Long nMaximum, + tools::Long nMinimum) + + : GenericDialogController(pParent, "modules/scalc/ui/" + OStringToOUString( + sDialogName.toAsciiLowerCase(), RTL_TEXTENCODING_UTF8) + ".ui", sDialogName) + , m_xEdValue(m_xBuilder->weld_metric_spin_button("value", FieldUnit::CM)) + , m_xBtnDefVal(m_xBuilder->weld_check_button("default")) +{ + m_xBtnDefVal->connect_toggled(LINK(this, ScMetricInputDlg, SetDefValHdl)); + m_xEdValue->connect_value_changed(LINK( this, ScMetricInputDlg, ModifyHdl)); + + m_xEdValue->set_unit(eFUnit); + m_xEdValue->set_digits(nDecimals); + m_xEdValue->set_range(m_xEdValue->normalize(nMinimum), + m_xEdValue->normalize(nMaximum), FieldUnit::TWIP); + + sal_Int64 nMin(0), nMax(0); + m_xEdValue->get_range(nMin, nMax, FieldUnit::TWIP); + + auto nIncrement = m_xEdValue->normalize(1); + m_xEdValue->set_increments(nIncrement / 10, nIncrement, FieldUnit::NONE); + m_xEdValue->set_value(m_xEdValue->normalize(nDefault), FieldUnit::TWIP); + nDefaultValue = m_xEdValue->get_value(FieldUnit::NONE); + m_xEdValue->set_value(m_xEdValue->normalize(nCurrent), FieldUnit::TWIP); + nCurrentValue = m_xEdValue->get_value(FieldUnit::NONE); + m_xBtnDefVal->set_active(nCurrentValue == nDefaultValue); +} + +ScMetricInputDlg::~ScMetricInputDlg() +{ +} + +int ScMetricInputDlg::GetInputValue() const +{ +/* + with decimal digits + + double nVal = m_xEdValue->GetValue( eUnit ); + sal_uInt16 nDecs = m_xEdValue->GetDecimalDigits(); + double nFactor = 0.0; + + // static long ImpPower10( sal_uInt16 nDecs ) + { + nFactor = 1.0; + + for ( sal_uInt16 i=0; i < nDecs; i++ ) + nFactor *= 10.0; + } + + return nVal / nFactor; +*/ + // first cut off the decimal digits - not that great... + + return m_xEdValue->denormalize(m_xEdValue->get_value(FieldUnit::TWIP)); +} + +// Handler: + +IMPL_LINK_NOARG(ScMetricInputDlg, SetDefValHdl, weld::Toggleable&, void) +{ + if (m_xBtnDefVal->get_active()) + { + nCurrentValue = m_xEdValue->get_value(FieldUnit::NONE); + m_xEdValue->set_value(nDefaultValue, FieldUnit::NONE); + } + else + m_xEdValue->set_value(nCurrentValue, FieldUnit::NONE); +} + +IMPL_LINK_NOARG(ScMetricInputDlg, ModifyHdl, weld::MetricSpinButton&, void) +{ + m_xBtnDefVal->set_active(nDefaultValue == m_xEdValue->get_value(FieldUnit::NONE)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/mvtabdlg.cxx b/sc/source/ui/miscdlgs/mvtabdlg.cxx new file mode 100644 index 000000000..80eeaeade --- /dev/null +++ b/sc/source/ui/miscdlgs/mvtabdlg.cxx @@ -0,0 +1,319 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <mvtabdlg.hxx> +#include <document.hxx> +#include <docsh.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <comphelper/lok.hxx> + +ScMoveTableDlg::ScMoveTableDlg(weld::Window* pParent, const OUString& rDefault) + : GenericDialogController(pParent, "modules/scalc/ui/movecopysheet.ui", "MoveCopySheetDialog") + , maDefaultName(rDefault) + , mnCurrentDocPos(0) + , nDocument(0) + , nTable(0) + , bCopyTable(false) + , bRenameTable(false) + , mbEverEdited(false) + , m_xBtnMove(m_xBuilder->weld_radio_button("move")) + , m_xBtnCopy(m_xBuilder->weld_radio_button("copy")) + , m_xFtDoc(m_xBuilder->weld_label("toDocumentLabel")) + , m_xLbDoc(m_xBuilder->weld_combo_box("toDocument")) + , m_xLbTable(m_xBuilder->weld_tree_view("insertBefore")) + , m_xEdTabName(m_xBuilder->weld_entry("newName")) + , m_xFtWarn(m_xBuilder->weld_label("newNameWarn")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xUnusedLabel(m_xBuilder->weld_label("warnunused")) + , m_xEmptyLabel(m_xBuilder->weld_label("warnempty")) + , m_xInvalidLabel(m_xBuilder->weld_label("warninvalid")) +{ + assert(m_xLbDoc->get_count() == 2); + msCurrentDoc = m_xLbDoc->get_text(0); + msNewDoc = m_xLbDoc->get_text(1); + m_xLbDoc->clear(); + assert(m_xLbDoc->get_count() == 0); + + m_xLbTable->set_size_request(-1, m_xLbTable->get_height_rows(8)); + + msStrTabNameUsed = m_xUnusedLabel->get_label(); + msStrTabNameEmpty = m_xEmptyLabel->get_label(); + msStrTabNameInvalid = m_xInvalidLabel->get_label(); + + Init(); +} + +ScMoveTableDlg::~ScMoveTableDlg() {} + +void ScMoveTableDlg::GetTabNameString(OUString& rString) const +{ + rString = m_xEdTabName->get_text(); +} + +void ScMoveTableDlg::SetForceCopyTable() +{ + m_xBtnCopy->set_active(true); + m_xBtnMove->set_sensitive(false); + m_xBtnCopy->set_sensitive(false); + SetOkBtnLabel(); +} + +void ScMoveTableDlg::EnableRenameTable(bool bFlag) +{ + bRenameTable = bFlag; + m_xEdTabName->set_sensitive(bFlag); + ResetRenameInput(); +} + +void ScMoveTableDlg::ResetRenameInput() +{ + if (mbEverEdited) + { + // Don't reset the name when the sheet name has ever been edited. + // But check the name, as this is also called for change of copy/move + // buttons and document listbox selection. + CheckNewTabName(); + return; + } + + if (!m_xEdTabName->get_sensitive()) + { + m_xEdTabName->set_text(OUString()); + return; + } + + bool bVal = m_xBtnCopy->get_active(); + if (bVal) + { + // copy + ScDocument* pDoc = GetSelectedDoc(); + if (pDoc) + { + OUString aStr = maDefaultName; + pDoc->CreateValidTabName(aStr); + m_xEdTabName->set_text(aStr); + } + else + m_xEdTabName->set_text(maDefaultName); + } + else + { + // move + m_xEdTabName->set_text(maDefaultName); + } + + CheckNewTabName(); +} + +void ScMoveTableDlg::CheckNewTabName() +{ + const OUString aNewName = m_xEdTabName->get_text(); + if (aNewName.isEmpty()) + { + // New sheet name is empty. This is not good. + m_xFtWarn->show(); + //TODO m_xFtWarn->SetControlBackground(COL_YELLOW); + m_xFtWarn->set_label(msStrTabNameEmpty); + m_xBtnOk->set_sensitive(false); + return; + } + + if (!ScDocument::ValidTabName(aNewName)) + { + // New sheet name contains invalid characters. + m_xFtWarn->show(); + //TODO m_xFtWarn->SetControlBackground(COL_YELLOW); + m_xFtWarn->set_label(msStrTabNameInvalid); + m_xBtnOk->set_sensitive(false); + return; + } + + bool bMoveInCurrentDoc = m_xBtnMove->get_active() && m_xLbDoc->get_active() == mnCurrentDocPos; + bool bFound = false; + const int nLast = m_xLbTable->n_children(); + for (int i = 0; i < nLast && !bFound; ++i) + { + if (aNewName == m_xLbTable->get_text(i)) + { + // Only for move within same document the same name is allowed. + if (!bMoveInCurrentDoc || maDefaultName != m_xEdTabName->get_text()) + bFound = true; + } + } + + if (bFound) + { + m_xFtWarn->show(); + //TODO m_xFtWarn->SetControlBackground(COL_YELLOW); + m_xFtWarn->set_label(msStrTabNameUsed); + m_xBtnOk->set_sensitive(false); + } + else + { + m_xFtWarn->hide(); + //TODO m_xFtWarn->SetControlBackground(); + m_xFtWarn->set_label(OUString()); + m_xBtnOk->set_sensitive(true); + } +} + +ScDocument* ScMoveTableDlg::GetSelectedDoc() +{ + return weld::fromId<ScDocument*>(m_xLbDoc->get_active_id()); +} + +void ScMoveTableDlg::Init() +{ + m_xBtnOk->connect_clicked(LINK(this, ScMoveTableDlg, OkHdl)); + m_xLbDoc->connect_changed(LINK(this, ScMoveTableDlg, SelHdl)); + m_xBtnCopy->connect_toggled(LINK(this, ScMoveTableDlg, CheckBtnHdl)); + m_xBtnMove->connect_toggled(LINK(this, ScMoveTableDlg, CheckBtnHdl)); + m_xEdTabName->connect_changed(LINK(this, ScMoveTableDlg, CheckNameHdl)); + m_xBtnMove->set_active(true); + m_xBtnCopy->set_active(false); + m_xEdTabName->set_sensitive(false); + m_xFtWarn->hide(); + InitDocListBox(); + SelHdl(*m_xLbDoc); + if (comphelper::LibreOfficeKit::isActive()) + { + m_xFtDoc->hide(); + m_xLbDoc->hide(); + } + SetOkBtnLabel(); +} + +void ScMoveTableDlg::InitDocListBox() +{ + SfxObjectShell* pSh = SfxObjectShell::GetFirst(); + ScDocShell* pScSh = nullptr; + sal_uInt16 nSelPos = 0; + sal_uInt16 i = 0; + + m_xLbDoc->clear(); + m_xLbDoc->freeze(); + + while (pSh) + { + pScSh = dynamic_cast<ScDocShell*>(pSh); + + if (pScSh) + { + OUString aEntryName = pScSh->GetTitle(); + + if (pScSh == SfxObjectShell::Current()) + { + mnCurrentDocPos = nSelPos = i; + aEntryName += " " + msCurrentDoc; + } + + OUString sId(weld::toId(&pScSh->GetDocument())); + m_xLbDoc->insert(i, aEntryName, &sId, nullptr, nullptr); + + i++; + } + pSh = SfxObjectShell::GetNext(*pSh); + } + + m_xLbDoc->thaw(); + m_xLbDoc->append_text(msNewDoc); + m_xLbDoc->set_active(nSelPos); +} + +void ScMoveTableDlg::SetOkBtnLabel() +{ + // tdf#139464 Write "Copy" or "Move" on OK button + m_xBtnOk->set_label(m_xBtnCopy->get_active() ? m_xBtnCopy->get_label() + : m_xBtnMove->get_label()); +} + +// Handler: + +IMPL_LINK(ScMoveTableDlg, CheckBtnHdl, weld::Toggleable&, rBtn, void) +{ + if (&rBtn == m_xBtnCopy.get()) + ResetRenameInput(); + SetOkBtnLabel(); +} + +IMPL_LINK_NOARG(ScMoveTableDlg, OkHdl, weld::Button&, void) +{ + const sal_Int32 nDocSel = m_xLbDoc->get_active(); + const sal_Int32 nDocLast = m_xLbDoc->get_count() - 1; + const sal_Int32 nTabSel = m_xLbTable->get_selected_index(); + const sal_Int32 nTabLast = m_xLbTable->n_children() - 1; + + nDocument = (nDocSel != nDocLast) ? nDocSel : SC_DOC_NEW; + nTable = (nTabSel != nTabLast) ? static_cast<SCTAB>(nTabSel) : SC_TAB_APPEND; + bCopyTable = m_xBtnCopy->get_active(); + + if (bCopyTable) + { + // Return an empty string when the new name is the same as the + // automatic name assigned by the document. + OUString aCopyName = maDefaultName; + ScDocument* pDoc = GetSelectedDoc(); + if (pDoc) + pDoc->CreateValidTabName(aCopyName); + if (aCopyName == m_xEdTabName->get_text()) + m_xEdTabName->set_text(OUString()); + } + else + { + // Return an empty string, when the new name is the same as the + // original name. + if (maDefaultName == m_xEdTabName->get_text()) + m_xEdTabName->set_text(OUString()); + } + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ScMoveTableDlg, SelHdl, weld::ComboBox&, void) +{ + ScDocument* pDoc = GetSelectedDoc(); + OUString aName; + + m_xLbTable->clear(); + m_xLbTable->freeze(); + if (pDoc) + { + SCTAB nLast = pDoc->GetTableCount() - 1; + for (SCTAB i = 0; i <= nLast; ++i) + { + pDoc->GetName(i, aName); + m_xLbTable->append_text(aName); + } + } + m_xLbTable->append_text(ScResId(STR_MOVE_TO_END)); + m_xLbTable->thaw(); + m_xLbTable->select(0); + ResetRenameInput(); +} + +IMPL_LINK_NOARG(ScMoveTableDlg, CheckNameHdl, weld::Entry&, void) +{ + mbEverEdited = true; + CheckNewTabName(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/namecrea.cxx b/sc/source/ui/miscdlgs/namecrea.cxx new file mode 100644 index 000000000..334b89d8b --- /dev/null +++ b/sc/source/ui/miscdlgs/namecrea.cxx @@ -0,0 +1,55 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <namecrea.hxx> + +ScNameCreateDlg::ScNameCreateDlg(weld::Window* pParent, CreateNameFlags nFlags) + : GenericDialogController(pParent, "modules/scalc/ui/createnamesdialog.ui", "CreateNamesDialog") + , m_xTopBox(m_xBuilder->weld_check_button("top")) + , m_xLeftBox(m_xBuilder->weld_check_button("left")) + , m_xBottomBox(m_xBuilder->weld_check_button("bottom")) + , m_xRightBox(m_xBuilder->weld_check_button("right")) +{ + m_xTopBox->set_active(bool(nFlags & CreateNameFlags::Top)); + m_xLeftBox->set_active(bool(nFlags & CreateNameFlags::Left)); + m_xBottomBox->set_active(bool(nFlags & CreateNameFlags::Bottom)); + m_xRightBox->set_active(bool(nFlags & CreateNameFlags::Right)); +} + +ScNameCreateDlg::~ScNameCreateDlg() {} + +CreateNameFlags ScNameCreateDlg::GetFlags() const +{ + CreateNameFlags nResult = CreateNameFlags::NONE; + + if (m_xTopBox->get_active()) + nResult |= CreateNameFlags::Top; + if (m_xLeftBox->get_active()) + nResult |= CreateNameFlags::Left; + if (m_xBottomBox->get_active()) + nResult |= CreateNameFlags::Bottom; + if (m_xRightBox->get_active()) + nResult |= CreateNameFlags::Right; + + return nResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/optsolver.cxx b/sc/source/ui/miscdlgs/optsolver.cxx new file mode 100644 index 000000000..f0f5eb30c --- /dev/null +++ b/sc/source/ui/miscdlgs/optsolver.cxx @@ -0,0 +1,1075 @@ +/* -*- 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 <rangelst.hxx> +#include <sfx2/bindings.hxx> +#include <svl/numformat.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/weld.hxx> +#include <vcl/svapp.hxx> + +#include <reffact.hxx> +#include <docsh.hxx> +#include <docfunc.hxx> +#include <rangeutl.hxx> +#include <convuno.hxx> +#include <unonames.hxx> +#include <solveroptions.hxx> +#include <solverutil.hxx> +#include <globstr.hrc> +#include <scresid.hxx> + +#include <optsolver.hxx> + +#include <com/sun/star/sheet/SolverConstraint.hpp> +#include <com/sun/star/sheet/SolverConstraintOperator.hpp> +#include <com/sun/star/sheet/XSolverDescription.hpp> +#include <com/sun/star/sheet/XSolver.hpp> + +using namespace com::sun::star; + +ScSolverProgressDialog::ScSolverProgressDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/solverprogressdialog.ui", + "SolverProgressDialog") + , m_xFtTime(m_xBuilder->weld_label("progress")) +{ +} + +ScSolverProgressDialog::~ScSolverProgressDialog() +{ +} + +void ScSolverProgressDialog::HideTimeLimit() +{ + m_xFtTime->hide(); +} + +void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds ) +{ + OUString aOld = m_xFtTime->get_label(); + OUString aNew = aOld.replaceFirst("#", OUString::number(nSeconds)); + m_xFtTime->set_label(aNew); +} + +ScSolverNoSolutionDialog::ScSolverNoSolutionDialog(weld::Window* pParent, const OUString& rErrorText) + : GenericDialogController(pParent, "modules/scalc/ui/nosolutiondialog.ui", "NoSolutionDialog") + , m_xFtErrorText(m_xBuilder->weld_label("error")) +{ + m_xFtErrorText->set_label(rErrorText); +} + +ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog() +{ +} + +ScSolverSuccessDialog::ScSolverSuccessDialog(weld::Window* pParent, std::u16string_view rSolution) + : GenericDialogController(pParent, "modules/scalc/ui/solversuccessdialog.ui", "SolverSuccessDialog") + , m_xFtResult(m_xBuilder->weld_label("result")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) +{ + m_xBtnOk->connect_clicked(LINK(this, ScSolverSuccessDialog, ClickHdl)); + m_xBtnCancel->connect_clicked(LINK(this, ScSolverSuccessDialog, ClickHdl)); + OUString aMessage = m_xFtResult->get_label() + " " + rSolution; + m_xFtResult->set_label(aMessage); +} + +ScSolverSuccessDialog::~ScSolverSuccessDialog() +{ +} + +IMPL_LINK(ScSolverSuccessDialog, ClickHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == m_xBtnOk.get()) + m_xDialog->response(RET_OK); + else + m_xDialog->response(RET_CANCEL); +} + +ScCursorRefEdit::ScCursorRefEdit(std::unique_ptr<weld::Entry> xControl) + : formula::RefEdit(std::move(xControl)) +{ + xEntry->connect_key_press(Link<const KeyEvent&, bool>()); //acknowledge we first remove the old one + xEntry->connect_key_press(LINK(this, ScCursorRefEdit, KeyInputHdl)); +} + +void ScCursorRefEdit::SetCursorLinks( const Link<ScCursorRefEdit&,void>& rUp, const Link<ScCursorRefEdit&,void>& rDown ) +{ + maCursorUpLink = rUp; + maCursorDownLink = rDown; +} + +IMPL_LINK(ScCursorRefEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + vcl::KeyCode aCode = rKEvt.GetKeyCode(); + bool bUp = (aCode.GetCode() == KEY_UP); + bool bDown = (aCode.GetCode() == KEY_DOWN); + if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) ) + { + if ( bUp ) + maCursorUpLink.Call( *this ); + else + maCursorDownLink.Call( *this ); + return true; + } + return formula::RefEdit::KeyInput(rKEvt); +} + +ScOptSolverSave::ScOptSolverSave( const OUString& rObjective, bool bMax, bool bMin, bool bValue, + const OUString& rTarget, const OUString& rVariable, + std::vector<ScOptConditionRow>&& rConditions, + const OUString& rEngine, + const uno::Sequence<beans::PropertyValue>& rProperties ) : + maObjective( rObjective ), + mbMax( bMax ), + mbMin( bMin ), + mbValue( bValue ), + maTarget( rTarget ), + maVariable( rVariable ), + maConditions( std::move(rConditions) ), + maEngine( rEngine ), + maProperties( rProperties ) +{ +} + +ScOptSolverDlg::ScOptSolverDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScDocShell* pDocSh, const ScAddress& aCursorPos) + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/solverdlg.ui", "SolverDialog") + , maInputError(ScResId(STR_INVALIDINPUT)) + , maConditionError(ScResId(STR_INVALIDCONDITION)) + + , mpDocShell(pDocSh) + , mrDoc(pDocSh->GetDocument()) + , mnCurTab(aCursorPos.Tab()) + , mbDlgLostFocus(false) + , nScrollPos(0) + , mpEdActive(nullptr) + , m_xFtObjectiveCell(m_xBuilder->weld_label("targetlabel")) + , m_xEdObjectiveCell(new formula::RefEdit(m_xBuilder->weld_entry("targetedit"))) + , m_xRBObjectiveCell(new formula::RefButton(m_xBuilder->weld_button("targetbutton"))) + , m_xRbMax(m_xBuilder->weld_radio_button("max")) + , m_xRbMin(m_xBuilder->weld_radio_button("min")) + , m_xRbValue(m_xBuilder->weld_radio_button("value")) + , m_xEdTargetValue(new formula::RefEdit(m_xBuilder->weld_entry("valueedit"))) + , m_xRBTargetValue(new formula::RefButton(m_xBuilder->weld_button("valuebutton"))) + , m_xFtVariableCells(m_xBuilder->weld_label("changelabel")) + , m_xEdVariableCells(new formula::RefEdit(m_xBuilder->weld_entry("changeedit"))) + , m_xRBVariableCells(new formula::RefButton(m_xBuilder->weld_button("changebutton"))) + , m_xFtCellRef(m_xBuilder->weld_label("cellreflabel")) + , m_xEdLeft1(new ScCursorRefEdit(m_xBuilder->weld_entry("ref1edit"))) + , m_xRBLeft1(new formula::RefButton(m_xBuilder->weld_button("ref1button"))) + , m_xFtOperator(m_xBuilder->weld_label("oplabel")) + , m_xLbOp1(m_xBuilder->weld_combo_box("op1list")) + , m_xFtConstraint(m_xBuilder->weld_label("constraintlabel")) + , m_xEdRight1(new ScCursorRefEdit(m_xBuilder->weld_entry("val1edit"))) + , m_xRBRight1(new formula::RefButton(m_xBuilder->weld_button("val1button"))) + , m_xBtnDel1(m_xBuilder->weld_button("del1")) + , m_xEdLeft2(new ScCursorRefEdit(m_xBuilder->weld_entry("ref2edit"))) + , m_xRBLeft2(new formula::RefButton(m_xBuilder->weld_button("ref2button"))) + , m_xLbOp2(m_xBuilder->weld_combo_box("op2list")) + , m_xEdRight2(new ScCursorRefEdit(m_xBuilder->weld_entry("val2edit"))) + , m_xRBRight2(new formula::RefButton(m_xBuilder->weld_button("val2button"))) + , m_xBtnDel2(m_xBuilder->weld_button("del2")) + , m_xEdLeft3(new ScCursorRefEdit(m_xBuilder->weld_entry("ref3edit"))) + , m_xRBLeft3(new formula::RefButton(m_xBuilder->weld_button("ref3button"))) + , m_xLbOp3(m_xBuilder->weld_combo_box("op3list")) + , m_xEdRight3(new ScCursorRefEdit(m_xBuilder->weld_entry("val3edit"))) + , m_xRBRight3(new formula::RefButton(m_xBuilder->weld_button("val3button"))) + , m_xBtnDel3(m_xBuilder->weld_button("del3")) + , m_xEdLeft4(new ScCursorRefEdit(m_xBuilder->weld_entry("ref4edit"))) + , m_xRBLeft4(new formula::RefButton(m_xBuilder->weld_button("ref4button"))) + , m_xLbOp4(m_xBuilder->weld_combo_box("op4list")) + , m_xEdRight4(new ScCursorRefEdit(m_xBuilder->weld_entry("val4edit"))) + , m_xRBRight4(new formula::RefButton(m_xBuilder->weld_button("val4button"))) + , m_xBtnDel4(m_xBuilder->weld_button("del4")) + , m_xScrollBar(m_xBuilder->weld_scrolled_window("scrollbar", true)) + , m_xBtnOpt(m_xBuilder->weld_button("options")) + , m_xBtnClose(m_xBuilder->weld_button("close")) + , m_xBtnSolve(m_xBuilder->weld_button("ok")) + , m_xBtnResetAll(m_xBuilder->weld_button("resetall")) + , m_xResultFT(m_xBuilder->weld_label("result")) + , m_xContents(m_xBuilder->weld_widget("grid")) +{ + m_xEdObjectiveCell->SetReferences(this, m_xFtObjectiveCell.get()); + m_xRBObjectiveCell->SetReferences(this, m_xEdObjectiveCell.get()); + m_xEdTargetValue->SetReferences(this, m_xResultFT.get()); + m_xRBTargetValue->SetReferences(this, m_xEdTargetValue.get()); + m_xEdVariableCells->SetReferences(this, m_xFtVariableCells.get()); + m_xRBVariableCells->SetReferences(this, m_xEdVariableCells.get()); + m_xEdLeft1->SetReferences(this, m_xFtCellRef.get()); + m_xRBLeft1->SetReferences(this, m_xEdLeft1.get()); + m_xEdRight1->SetReferences(this, m_xFtConstraint.get()); + m_xRBRight1->SetReferences(this, m_xEdRight1.get()); + m_xEdLeft2->SetReferences(this, m_xFtCellRef.get()); + m_xRBLeft2->SetReferences(this, m_xEdLeft2.get()); + m_xEdRight2->SetReferences(this, m_xFtConstraint.get()); + m_xRBRight2->SetReferences(this, m_xEdRight2.get()); + m_xEdLeft3->SetReferences(this, m_xFtCellRef.get()); + m_xRBLeft3->SetReferences(this, m_xEdLeft3.get()); + m_xEdRight3->SetReferences(this, m_xFtConstraint.get()); + m_xRBRight3->SetReferences(this, m_xEdRight3.get()); + m_xEdLeft4->SetReferences(this, m_xFtCellRef.get()); + m_xRBLeft4->SetReferences(this, m_xEdLeft4.get()); + m_xEdRight4->SetReferences(this, m_xFtConstraint.get()); + m_xRBRight4->SetReferences(this, m_xEdRight4.get()); + + mpLeftEdit[0] = m_xEdLeft1.get(); + mpLeftButton[0] = m_xRBLeft1.get(); + mpRightEdit[0] = m_xEdRight1.get(); + mpRightButton[0] = m_xRBRight1.get(); + mpOperator[0] = m_xLbOp1.get(); + mpDelButton[0] = m_xBtnDel1.get(); + + mpLeftEdit[1] = m_xEdLeft2.get(); + mpLeftButton[1] = m_xRBLeft2.get(); + mpRightEdit[1] = m_xEdRight2.get(); + mpRightButton[1] = m_xRBRight2.get(); + mpOperator[1] = m_xLbOp2.get(); + mpDelButton[1] = m_xBtnDel2.get(); + + mpLeftEdit[2] = m_xEdLeft3.get(); + mpLeftButton[2] = m_xRBLeft3.get(); + mpRightEdit[2] = m_xEdRight3.get(); + mpRightButton[2] = m_xRBRight3.get(); + mpOperator[2] = m_xLbOp3.get(); + mpDelButton[2] = m_xBtnDel3.get(); + + mpLeftEdit[3] = m_xEdLeft4.get(); + mpLeftButton[3] = m_xRBLeft4.get(); + mpRightEdit[3] = m_xEdRight4.get(); + mpRightButton[3] = m_xRBRight4.get(); + mpOperator[3] = m_xLbOp4.get(); + mpDelButton[3] = m_xBtnDel4.get(); + + Init( aCursorPos ); +} + +ScOptSolverDlg::~ScOptSolverDlg() +{ +} + +void ScOptSolverDlg::Init(const ScAddress& rCursorPos) +{ + uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame(); + auto xDelNm = vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:DeleteRows", xFrame); + for (weld::Button* pButton : mpDelButton) + pButton->set_image(xDelNm); + + m_xBtnOpt->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) ); + m_xBtnClose->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) ); + m_xBtnSolve->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) ); + m_xBtnResetAll->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) ); + + Link<formula::RefEdit&,void> aEditLink = LINK( this, ScOptSolverDlg, GetEditFocusHdl ); + Link<formula::RefButton&,void> aButtonLink = LINK( this, ScOptSolverDlg, GetButtonFocusHdl ); + m_xEdObjectiveCell->SetGetFocusHdl( aEditLink ); + m_xRBObjectiveCell->SetGetFocusHdl( aButtonLink ); + m_xEdTargetValue->SetGetFocusHdl( aEditLink ); + m_xRBTargetValue->SetGetFocusHdl( aButtonLink ); + m_xEdVariableCells->SetGetFocusHdl( aEditLink ); + m_xRBVariableCells->SetGetFocusHdl( aButtonLink ); + Link<weld::Widget&,void> aLink = LINK(this, ScOptSolverDlg, GetFocusHdl); + m_xRbValue->connect_focus_in(aLink); + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + mpLeftEdit[nRow]->SetGetFocusHdl( aEditLink ); + mpLeftButton[nRow]->SetGetFocusHdl( aButtonLink ); + mpRightEdit[nRow]->SetGetFocusHdl( aEditLink ); + mpRightButton[nRow]->SetGetFocusHdl( aButtonLink ); + mpOperator[nRow]->connect_focus_in(aLink); + } + + aEditLink = LINK( this, ScOptSolverDlg, LoseEditFocusHdl ); + aButtonLink = LINK( this, ScOptSolverDlg, LoseButtonFocusHdl ); + m_xEdObjectiveCell->SetLoseFocusHdl( aEditLink ); + m_xRBObjectiveCell->SetLoseFocusHdl( aButtonLink ); + m_xEdTargetValue->SetLoseFocusHdl( aEditLink ); + m_xRBTargetValue-> SetLoseFocusHdl( aButtonLink ); + m_xEdVariableCells->SetLoseFocusHdl( aEditLink ); + m_xRBVariableCells->SetLoseFocusHdl( aButtonLink ); + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + mpLeftEdit[nRow]->SetLoseFocusHdl( aEditLink ); + mpLeftButton[nRow]->SetLoseFocusHdl( aButtonLink ); + mpRightEdit[nRow]->SetLoseFocusHdl( aEditLink ); + mpRightButton[nRow]->SetLoseFocusHdl( aButtonLink ); + } + + Link<ScCursorRefEdit&,void> aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl ); + Link<ScCursorRefEdit&,void> aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl ); + Link<formula::RefEdit&,void> aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl ); + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); + mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown ); + mpLeftEdit[nRow]->SetModifyHdl( aCondModify ); + mpRightEdit[nRow]->SetModifyHdl( aCondModify ); + mpDelButton[nRow]->connect_clicked( LINK( this, ScOptSolverDlg, DelBtnHdl ) ); + mpOperator[nRow]->connect_changed( LINK( this, ScOptSolverDlg, SelectHdl ) ); + } + m_xEdTargetValue->SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) ); + + Size aSize(m_xContents->get_preferred_size()); + m_xContents->set_size_request(aSize.Width(), aSize.Height()); + m_xScrollBar->connect_vadjustment_changed( LINK( this, ScOptSolverDlg, ScrollHdl ) ); + + m_xScrollBar->vadjustment_set_page_increment( EDIT_ROW_COUNT ); + m_xScrollBar->vadjustment_set_page_size( EDIT_ROW_COUNT ); + // Range is set in ShowConditions + + // get available solver implementations + //! sort by descriptions? + ScSolverUtil::GetImplementations( maImplNames, maDescriptions ); + bool bImplHasElements = maImplNames.hasElements(); + + const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData(); + if ( pOldData ) + { + m_xEdObjectiveCell->SetRefString( pOldData->GetObjective() ); + m_xRbMax->set_active( pOldData->GetMax() ); + m_xRbMin->set_active( pOldData->GetMin() ); + m_xRbValue->set_active( pOldData->GetValue() ); + m_xEdTargetValue->SetRefString( pOldData->GetTarget() ); + m_xEdVariableCells->SetRefString( pOldData->GetVariable() ); + maConditions = pOldData->GetConditions(); + maEngine = pOldData->GetEngine(); + maProperties = pOldData->GetProperties(); + } + else + { + m_xRbMax->set_active(true); + OUString aCursorStr; + if ( !mrDoc.GetRangeAtBlock( ScRange(rCursorPos), aCursorStr ) ) + aCursorStr = rCursorPos.Format(ScRefFlags::ADDR_ABS, nullptr, mrDoc.GetAddressConvention()); + m_xEdObjectiveCell->SetRefString( aCursorStr ); + if ( bImplHasElements ) + maEngine = maImplNames[0]; // use first implementation + } + ShowConditions(); + + m_xEdObjectiveCell->GrabFocus(); + mpEdActive = m_xEdObjectiveCell.get(); +} + +void ScOptSolverDlg::ReadConditions() +{ + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + ScOptConditionRow aRowEntry; + aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText(); + aRowEntry.aRightStr = mpRightEdit[nRow]->GetText(); + aRowEntry.nOperator = mpOperator[nRow]->get_active(); + + tools::Long nVecPos = nScrollPos + nRow; + if ( nVecPos >= static_cast<tools::Long>(maConditions.size()) && !aRowEntry.IsDefault() ) + maConditions.resize( nVecPos + 1 ); + + if ( nVecPos < static_cast<tools::Long>(maConditions.size()) ) + maConditions[nVecPos] = aRowEntry; + + // remove default entries at the end + size_t nSize = maConditions.size(); + while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() ) + --nSize; + maConditions.resize( nSize ); + } +} + +void ScOptSolverDlg::ShowConditions() +{ + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + ScOptConditionRow aRowEntry; + + tools::Long nVecPos = nScrollPos + nRow; + if ( nVecPos < static_cast<tools::Long>(maConditions.size()) ) + aRowEntry = maConditions[nVecPos]; + + mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr ); + mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr ); + mpOperator[nRow]->set_active( aRowEntry.nOperator ); + } + + // allow to scroll one page behind the visible or stored rows + tools::Long nVisible = nScrollPos + EDIT_ROW_COUNT; + tools::Long nMax = std::max( nVisible, static_cast<tools::Long>(maConditions.size()) ); + m_xScrollBar->vadjustment_configure(nScrollPos, 0, nMax + EDIT_ROW_COUNT, 1, + EDIT_ROW_COUNT - 1, EDIT_ROW_COUNT); + + EnableButtons(); +} + +void ScOptSolverDlg::EnableButtons() +{ + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + tools::Long nVecPos = nScrollPos + nRow; + mpDelButton[nRow]->set_sensitive(nVecPos < static_cast<tools::Long>(maConditions.size())); + } +} + +void ScOptSolverDlg::Close() +{ + if (m_xOptDlg) + m_xOptDlg->response(RET_CANCEL); + assert(!m_xOptDlg); + DoClose( ScOptSolverDlgWrapper::GetChildWindowId() ); +} + +void ScOptSolverDlg::SetActive() +{ + if ( mbDlgLostFocus ) + { + mbDlgLostFocus = false; + if( mpEdActive ) + mpEdActive->GrabFocus(); + } + else + { + m_xDialog->grab_focus(); + } + RefInputDone(); +} + +void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if( !mpEdActive ) + return; + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(mpEdActive); + + // "target"/"value": single cell + bool bSingle = ( mpEdActive == m_xEdObjectiveCell.get() || mpEdActive == m_xEdTargetValue.get() ); + + OUString aStr; + ScAddress aAdr = rRef.aStart; + ScRange aNewRef( rRef ); + if ( bSingle ) + aNewRef.aEnd = aAdr; + + OUString aName; + if ( rDocP.GetRangeAtBlock( aNewRef, aName ) ) // named range: show name + aStr = aName; + else // format cell/range reference + { + ScRefFlags nFmt = ( aAdr.Tab() == mnCurTab ) ? ScRefFlags::ADDR_ABS : ScRefFlags::ADDR_ABS_3D; + if ( bSingle ) + aStr = aAdr.Format(nFmt, &rDocP, rDocP.GetAddressConvention()); + else + aStr = rRef.Format(rDocP, nFmt | ScRefFlags::RANGE_ABS, rDocP.GetAddressConvention()); + } + + // variable cells can be several ranges, so only the selection is replaced + if ( mpEdActive == m_xEdVariableCells.get() ) + { + OUString aVal = mpEdActive->GetText(); + Selection aSel = mpEdActive->GetSelection(); + aSel.Justify(); + aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aStr ); + Selection aNewSel( aSel.Min(), aSel.Min()+aStr.getLength() ); + mpEdActive->SetRefString( aVal ); + mpEdActive->SetSelection( aNewSel ); + } + else + mpEdActive->SetRefString( aStr ); + + ReadConditions(); + EnableButtons(); + + // select "Value of" if a ref is input into "target" edit + if ( mpEdActive == m_xEdTargetValue.get() ) + m_xRbValue->set_active(true); +} + +bool ScOptSolverDlg::IsRefInputMode() const +{ + return mpEdActive != nullptr; +} + +// Handler: + +IMPL_LINK(ScOptSolverDlg, BtnHdl, weld::Button&, rBtn, void) +{ + auto xKeepAlive = shared_from_this(); + if (&rBtn == m_xBtnSolve.get() || &rBtn == m_xBtnClose.get()) + { + bool bSolve = ( &rBtn == m_xBtnSolve.get() ); + + SetDispatcherLock( false ); + SwitchToDocument(); + + bool bClose = true; + if ( bSolve ) + bClose = CallSolver(); + + if ( bClose ) + { + // Close: write dialog settings to DocShell for subsequent calls + ReadConditions(); + std::unique_ptr<ScOptSolverSave> pSave( new ScOptSolverSave( + m_xEdObjectiveCell->GetText(), m_xRbMax->get_active(), m_xRbMin->get_active(), m_xRbValue->get_active(), + m_xEdTargetValue->GetText(), m_xEdVariableCells->GetText(), std::vector(maConditions), maEngine, maProperties ) ); + mpDocShell->SetSolverSaveData( std::move(pSave) ); + response(RET_CLOSE); + } + else + { + // no solution -> dialog is kept open + SetDispatcherLock( true ); + } + } + else if (&rBtn == m_xBtnOpt.get()) + { + //! move options dialog to UI lib? + m_xOptDlg = std::make_shared<ScSolverOptionsDialog>(m_xDialog.get(), maImplNames, maDescriptions, maEngine, maProperties); + weld::DialogController::runAsync(m_xOptDlg, [this](sal_Int32 nResult){ + if (nResult == RET_OK) + { + maEngine = m_xOptDlg->GetEngine(); + maProperties = m_xOptDlg->GetProperties(); + } + m_xOptDlg.reset(); + }); + } + else if (&rBtn == m_xBtnResetAll.get()) + { + OUString sEmpty; + m_xEdObjectiveCell->SetText(sEmpty); + m_xEdTargetValue->SetText(sEmpty); + m_xEdVariableCells->SetText(sEmpty); + + // Get default property values of solver implementations + maEngine = maImplNames[0]; + maProperties = ScSolverUtil::GetDefaults( maEngine ); + + // Clear all conditions (Constraints) + maConditions.clear(); + std::unique_ptr<ScOptSolverSave> pEmpty( new ScOptSolverSave( + sEmpty, true, false, false, + sEmpty, sEmpty, std::vector(maConditions), maEngine, maProperties ) ); + mpDocShell->SetSolverSaveData( std::move(pEmpty) ); + ShowConditions(); + + m_xRbMax->set_active(true); + m_xEdObjectiveCell->GrabFocus(); + mpEdActive = m_xEdObjectiveCell.get(); + } +} + +IMPL_LINK( ScOptSolverDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void ) +{ + formula::RefEdit* pEdit = nullptr; + mpEdActive = nullptr; + + if( &rCtrl == m_xEdObjectiveCell.get() ) + pEdit = mpEdActive = m_xEdObjectiveCell.get(); + else if( &rCtrl == m_xEdTargetValue.get() ) + pEdit = mpEdActive = m_xEdTargetValue.get(); + else if( &rCtrl == m_xEdVariableCells.get() ) + pEdit = mpEdActive = m_xEdVariableCells.get(); + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + if( &rCtrl == mpLeftEdit[nRow] ) + pEdit = mpEdActive = mpLeftEdit[nRow]; + else if( &rCtrl == mpRightEdit[nRow] ) + pEdit = mpEdActive = mpRightEdit[nRow]; + } + + if( pEdit ) + pEdit->SelectAll(); +} + +IMPL_LINK( ScOptSolverDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void ) +{ + formula::RefEdit* pEdit = nullptr; + mpEdActive = nullptr; + + if( &rCtrl == m_xRBObjectiveCell.get() ) + pEdit = mpEdActive = m_xEdObjectiveCell.get(); + else if( &rCtrl == m_xRBTargetValue.get() ) + pEdit = mpEdActive = m_xEdTargetValue.get(); + else if( &rCtrl == m_xRBVariableCells.get() ) + pEdit = mpEdActive = m_xEdVariableCells.get(); + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + if( &rCtrl == mpLeftButton[nRow] ) + pEdit = mpEdActive = mpLeftEdit[nRow]; + else if( &rCtrl == mpRightButton[nRow] ) + pEdit = mpEdActive = mpRightEdit[nRow]; + } + + if( pEdit ) + pEdit->SelectAll(); +} + + +IMPL_LINK(ScOptSolverDlg, GetFocusHdl, weld::Widget&, rCtrl, void) +{ + if( &rCtrl == m_xRbValue.get() ) // focus on "Value of" radio button + mpEdActive = m_xEdTargetValue.get(); // use value edit for ref input, but don't change selection + else + { + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + { + if( &rCtrl == mpOperator[nRow] ) // focus on "operator" list box + mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection + } + } +} + +IMPL_LINK_NOARG(ScOptSolverDlg, LoseEditFocusHdl, formula::RefEdit&, void) +{ + mbDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(ScOptSolverDlg, LoseButtonFocusHdl, formula::RefButton&, void) +{ + mbDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK(ScOptSolverDlg, DelBtnHdl, weld::Button&, rBtn, void) +{ + for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow ) + if (&rBtn == mpDelButton[nRow]) + { + bool bHadFocus = rBtn.has_focus(); + + ReadConditions(); + tools::Long nVecPos = nScrollPos + nRow; + if ( nVecPos < static_cast<tools::Long>(maConditions.size()) ) + { + maConditions.erase( maConditions.begin() + nVecPos ); + ShowConditions(); + + if ( bHadFocus && !rBtn.get_sensitive() ) + { + // If the button is disabled, focus would normally move to the next control, + // (left edit of the next row). Move it to left edit of this row instead. + + mpEdActive = mpLeftEdit[nRow]; + mpEdActive->GrabFocus(); + } + } + } +} + +IMPL_LINK_NOARG(ScOptSolverDlg, TargetModifyHdl, formula::RefEdit&, void) +{ + // modify handler for the target edit: + // select "Value of" if something is input into the edit + if ( !m_xEdTargetValue->GetText().isEmpty() ) + m_xRbValue->set_active(true); +} + +IMPL_LINK_NOARG(ScOptSolverDlg, CondModifyHdl, formula::RefEdit&, void) +{ + // modify handler for the condition edits, just to enable/disable "delete" buttons + ReadConditions(); + EnableButtons(); +} + +IMPL_LINK_NOARG(ScOptSolverDlg, SelectHdl, weld::ComboBox&, void) +{ + // select handler for operator list boxes, just to enable/disable "delete" buttons + ReadConditions(); + EnableButtons(); +} + +IMPL_LINK_NOARG(ScOptSolverDlg, ScrollHdl, weld::ScrolledWindow&, void) +{ + ReadConditions(); + nScrollPos = m_xScrollBar->vadjustment_get_value(); + ShowConditions(); + if( mpEdActive ) + mpEdActive->SelectAll(); +} + +IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit&, rEdit, void ) +{ + if ( &rEdit == mpLeftEdit[0] || &rEdit == mpRightEdit[0] ) + { + if ( nScrollPos > 0 ) + { + ReadConditions(); + --nScrollPos; + ShowConditions(); + if( mpEdActive ) + mpEdActive->SelectAll(); + } + } + else + { + formula::RefEdit* pFocus = nullptr; + for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus + { + if ( &rEdit == mpLeftEdit[nRow] ) + pFocus = mpLeftEdit[nRow-1]; + else if ( &rEdit == mpRightEdit[nRow] ) + pFocus = mpRightEdit[nRow-1]; + } + if (pFocus) + { + mpEdActive = pFocus; + pFocus->GrabFocus(); + } + } +} + +IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit&, rEdit, void ) +{ + if ( &rEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || &rEdit == mpRightEdit[EDIT_ROW_COUNT-1] ) + { + //! limit scroll position? + ReadConditions(); + ++nScrollPos; + ShowConditions(); + if( mpEdActive ) + mpEdActive->SelectAll(); + } + else + { + formula::RefEdit* pFocus = nullptr; + for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus + { + if ( &rEdit == mpLeftEdit[nRow] ) + pFocus = mpLeftEdit[nRow+1]; + else if ( &rEdit == mpRightEdit[nRow] ) + pFocus = mpRightEdit[nRow+1]; + } + if (pFocus) + { + mpEdActive = pFocus; + pFocus->GrabFocus(); + } + } +} + +void ScOptSolverDlg::ShowError( bool bCondition, formula::RefEdit* pFocus ) +{ + OUString aMessage = bCondition ? maConditionError : maInputError; + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + aMessage)); + xBox->run(); + if (pFocus) + { + mpEdActive = pFocus; + pFocus->GrabFocus(); + } +} + +bool ScOptSolverDlg::ParseRef( ScRange& rRange, const OUString& rInput, bool bAllowRange ) +{ + ScAddress::Details aDetails(mrDoc.GetAddressConvention(), 0, 0); + ScRefFlags nFlags = rRange.ParseAny( rInput, mrDoc, aDetails ); + if ( nFlags & ScRefFlags::VALID ) + { + if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO) + rRange.aStart.SetTab( mnCurTab ); + if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO) + rRange.aEnd.SetTab( rRange.aStart.Tab() ); + return ( bAllowRange || rRange.aStart == rRange.aEnd ); + } + else if ( ScRangeUtil::MakeRangeFromName( rInput, mrDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) ) + return ( bAllowRange || rRange.aStart == rRange.aEnd ); + + return false; // not recognized +} + +bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout ) +{ + bool bFound = false; + + if ( !maProperties.hasElements() ) + maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component + + sal_Int32 nPropCount = maProperties.getLength(); + for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp) + { + const beans::PropertyValue& rValue = maProperties[nProp]; + if ( rValue.Name == SC_UNONAME_TIMEOUT ) + bFound = ( rValue.Value >>= rTimeout ); + } + return bFound; +} + +bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling +{ + // show progress dialog + + auto xProgress = std::make_shared<ScSolverProgressDialog>(m_xDialog.get()); + sal_Int32 nTimeout = 0; + if ( FindTimeout( nTimeout ) ) + xProgress->SetTimeLimit( nTimeout ); + else + xProgress->HideTimeLimit(); + + weld::DialogController::runAsync(xProgress, [](sal_Int32 /*nResult*/){}); + + // try to make sure the progress dialog is painted before continuing + Application::Reschedule(true); + + // collect solver parameters + + ReadConditions(); + + uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY ); + + ScRange aObjRange; + if ( !ParseRef( aObjRange, m_xEdObjectiveCell->GetText(), false ) ) + { + ShowError( false, m_xEdObjectiveCell.get() ); + return false; + } + table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() ); + + // "changing cells" can be several ranges + ScRangeList aVarRanges; + if ( !ParseWithNames( aVarRanges, m_xEdVariableCells->GetText(), mrDoc ) ) + { + ShowError( false, m_xEdVariableCells.get() ); + return false; + } + uno::Sequence<table::CellAddress> aVariables; + sal_Int32 nVarPos = 0; + + for ( size_t nRangePos=0, nRange = aVarRanges.size(); nRangePos < nRange; ++nRangePos ) + { + ScRange aRange( aVarRanges[ nRangePos ] ); + aRange.PutInOrder(); + SCTAB nTab = aRange.aStart.Tab(); + + // resolve into single cells + + sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) * + ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 ); + aVariables.realloc( nVarPos + nAdd ); + auto pVariables = aVariables.getArray(); + + for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow) + for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol) + pVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow ); + } + + uno::Sequence<sheet::SolverConstraint> aConstraints; + sal_Int32 nConstrPos = 0; + for ( const auto& rConstr : maConditions ) + { + if ( !rConstr.aLeftStr.isEmpty() ) + { + sheet::SolverConstraint aConstraint; + // order of list box entries must match enum values + aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(rConstr.nOperator); + + ScRange aLeftRange; + if ( !ParseRef( aLeftRange, rConstr.aLeftStr, true ) ) + { + ShowError( true, nullptr ); + return false; + } + + bool bIsRange = false; + ScRange aRightRange; + if ( ParseRef( aRightRange, rConstr.aRightStr, true ) ) + { + if ( aRightRange.aStart == aRightRange.aEnd ) + aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), + aRightRange.aStart.Col(), aRightRange.aStart.Row() ); + else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() && + aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() ) + bIsRange = true; // same size as "left" range, resolve into single cells + else + { + ShowError( true, nullptr ); + return false; + } + } + else + { + sal_uInt32 nFormat = 0; //! explicit language? + double fValue = 0.0; + if ( mrDoc.GetFormatTable()->IsNumberFormat( rConstr.aRightStr, nFormat, fValue ) ) + aConstraint.Right <<= fValue; + else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER && + aConstraint.Operator != sheet::SolverConstraintOperator_BINARY ) + { + ShowError( true, nullptr ); + return false; + } + } + + // resolve into single cells + + sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) * + ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 ); + aConstraints.realloc( nConstrPos + nAdd ); + auto pConstraints = aConstraints.getArray(); + + for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow) + for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol) + { + aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow ); + if ( bIsRange ) + aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), + aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ), + aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) ); + + pConstraints[nConstrPos++] = aConstraint; + } + } + } + + bool bMaximize = m_xRbMax->get_active(); + if ( m_xRbValue->get_active() ) + { + // handle "value of" with an additional constraint (and then minimize) + + sheet::SolverConstraint aConstraint; + aConstraint.Left = aObjective; + aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL; + + OUString aValStr = m_xEdTargetValue->GetText(); + ScRange aRightRange; + if ( ParseRef( aRightRange, aValStr, false ) ) + aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(), + aRightRange.aStart.Col(), aRightRange.aStart.Row() ); + else + { + sal_uInt32 nFormat = 0; //! explicit language? + double fValue = 0.0; + if ( mrDoc.GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) ) + aConstraint.Right <<= fValue; + else + { + ShowError( false, m_xEdTargetValue.get() ); + return false; + } + } + + aConstraints.realloc( nConstrPos + 1 ); + aConstraints.getArray()[nConstrPos++] = aConstraint; + } + + // copy old document values + + sal_Int32 nVarCount = aVariables.getLength(); + uno::Sequence<double> aOldValues( nVarCount ); + std::transform(std::cbegin(aVariables), std::cend(aVariables), aOldValues.getArray(), + [this](const table::CellAddress& rVariable) -> double { + ScAddress aCellPos; + ScUnoConversion::FillScAddress( aCellPos, rVariable ); + return mrDoc.GetValue( aCellPos ); + }); + + // create and initialize solver + + uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine ); + OSL_ENSURE( xSolver.is(), "can't get solver component" ); + if ( !xSolver.is() ) + return false; + + xSolver->setDocument( xDocument ); + xSolver->setObjective( aObjective ); + xSolver->setVariables( aVariables ); + xSolver->setConstraints( aConstraints ); + xSolver->setMaximize( bMaximize ); + + // set options + uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY); + if ( xOptProp.is() ) + { + for (const beans::PropertyValue& rValue : std::as_const(maProperties)) + { + try + { + xOptProp->setPropertyValue( rValue.Name, rValue.Value ); + } + catch ( uno::Exception & ) + { + OSL_FAIL("Exception in solver option property"); + } + } + } + + xSolver->solve(); + bool bSuccess = xSolver->getSuccess(); + + xProgress->response(RET_CLOSE); + + bool bClose = false; + bool bRestore = true; // restore old values unless a solution is accepted + if ( bSuccess ) + { + // put solution into document so it is visible when asking + uno::Sequence<double> aSolution = xSolver->getSolution(); + if ( aSolution.getLength() == nVarCount ) + { + mpDocShell->LockPaint(); + ScDocFunc &rFunc = mpDocShell->GetDocFunc(); + for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) + { + ScAddress aCellPos; + ScUnoConversion::FillScAddress( aCellPos, std::as_const(aVariables)[nVarPos] ); + rFunc.SetValueCell(aCellPos, aSolution[nVarPos], false); + } + mpDocShell->UnlockPaint(); + } + //! else error? + + // take formatted result from document (result value from component is ignored) + OUString aResultStr = mrDoc.GetString( + static_cast<SCCOL>(aObjective.Column), static_cast<SCROW>(aObjective.Row), + static_cast<SCTAB>(aObjective.Sheet)); + + ScSolverSuccessDialog aDialog(m_xDialog.get(), aResultStr); + if (aDialog.run() == RET_OK) + { + // keep results and close dialog + bRestore = false; + bClose = true; + } + } + else + { + OUString aError; + uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY ); + if ( xDesc.is() ) + aError = xDesc->getStatusDescription(); // error description from component + ScSolverNoSolutionDialog aDialog(m_xDialog.get(), aError); + aDialog.run(); + } + + if ( bRestore ) // restore old values + { + mpDocShell->LockPaint(); + ScDocFunc &rFunc = mpDocShell->GetDocFunc(); + for (nVarPos=0; nVarPos<nVarCount; ++nVarPos) + { + ScAddress aCellPos; + ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] ); + rFunc.SetValueCell(aCellPos, std::as_const(aOldValues)[nVarPos], false); + } + mpDocShell->UnlockPaint(); + } + + return bClose; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/protectiondlg.cxx b/sc/source/ui/miscdlgs/protectiondlg.cxx new file mode 100644 index 000000000..920e7bfc4 --- /dev/null +++ b/sc/source/ui/miscdlgs/protectiondlg.cxx @@ -0,0 +1,154 @@ +/* -*- 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 <protectiondlg.hxx> +#include <tabprotection.hxx> + +#include <vector> + +namespace { + +// The order must match that of the list box. +const std::vector<ScTableProtection::Option> aOptions = { + ScTableProtection::SELECT_LOCKED_CELLS, + ScTableProtection::SELECT_UNLOCKED_CELLS, + ScTableProtection::INSERT_COLUMNS, + ScTableProtection::INSERT_ROWS, + ScTableProtection::DELETE_COLUMNS, + ScTableProtection::DELETE_ROWS, +}; + +} + +ScTableProtectionDlg::ScTableProtectionDlg(weld::Window* pParent) + : weld::GenericDialogController(pParent, "modules/scalc/ui/protectsheetdlg.ui", "ProtectSheetDialog") + , m_xBtnProtect(m_xBuilder->weld_check_button("protect")) + , m_xPasswords(m_xBuilder->weld_container("passwords")) + , m_xOptions(m_xBuilder->weld_container("options")) + , m_xPassword1Edit(m_xBuilder->weld_entry("password1")) + , m_xPassword2Edit(m_xBuilder->weld_entry("password2")) + , m_xOptionsListBox(m_xBuilder->weld_tree_view("checklist")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xProtected(m_xBuilder->weld_label("protected")) + , m_xUnprotected(m_xBuilder->weld_label("unprotected")) + , m_xInsertColumns(m_xBuilder->weld_label("insert-columns")) + , m_xInsertRows(m_xBuilder->weld_label("insert-rows")) + , m_xDeleteColumns(m_xBuilder->weld_label("delete-columns")) + , m_xDeleteRows(m_xBuilder->weld_label("delete-rows")) +{ + m_aSelectLockedCells = m_xProtected->get_label(); + m_aSelectUnlockedCells = m_xUnprotected->get_label(); + m_aInsertColumns = m_xInsertColumns->get_label(); + m_aInsertRows = m_xInsertRows->get_label(); + m_aDeleteColumns = m_xDeleteColumns->get_label(); + m_aDeleteRows = m_xDeleteRows->get_label(); + + m_xOptionsListBox->enable_toggle_buttons(weld::ColumnToggleType::Check); + + Init(); +} + +ScTableProtectionDlg::~ScTableProtectionDlg() +{ +} + +void ScTableProtectionDlg::SetDialogData(const ScTableProtection& rData) +{ + for (size_t i = 0; i < aOptions.size(); ++i) + m_xOptionsListBox->set_toggle(i, rData.isOptionEnabled(aOptions[i]) ? TRISTATE_TRUE : TRISTATE_FALSE); +} + +void ScTableProtectionDlg::WriteData(ScTableProtection& rData) const +{ + rData.setProtected(m_xBtnProtect->get_active()); + + // We assume that the two password texts match. + rData.setPassword(m_xPassword1Edit->get_text()); + + for (size_t i = 0; i < aOptions.size(); ++i) + rData.setOption(aOptions[i], m_xOptionsListBox->get_toggle(i) == TRISTATE_TRUE); +} + +void ScTableProtectionDlg::InsertEntry(const OUString& rTxt) +{ + m_xOptionsListBox->append(); + const int nRow = m_xOptionsListBox->n_children() - 1; + m_xOptionsListBox->set_toggle(nRow, TRISTATE_FALSE); + m_xOptionsListBox->set_text(nRow, rTxt, 0); +} + +void ScTableProtectionDlg::Init() +{ + m_xBtnProtect->connect_toggled(LINK(this, ScTableProtectionDlg, CheckBoxHdl)); + + m_xBtnOk->connect_clicked(LINK(this, ScTableProtectionDlg, OKHdl)); + + Link<weld::Entry&,void> aLink = LINK(this, ScTableProtectionDlg, PasswordModifyHdl); + m_xPassword1Edit->connect_changed(aLink); + m_xPassword2Edit->connect_changed(aLink); + + m_xOptionsListBox->freeze(); + m_xOptionsListBox->clear(); + + InsertEntry(m_aSelectLockedCells); + InsertEntry(m_aSelectUnlockedCells); + InsertEntry(m_aInsertColumns); + InsertEntry(m_aInsertRows); + InsertEntry(m_aDeleteColumns); + InsertEntry(m_aDeleteRows); + + m_xOptionsListBox->set_toggle(0, TRISTATE_TRUE); + m_xOptionsListBox->set_toggle(1, TRISTATE_TRUE); + + m_xOptionsListBox->thaw(); + + // Set the default state of the dialog. + m_xBtnProtect->set_active(true); + m_xPassword1Edit->grab_focus(); +} + +void ScTableProtectionDlg::EnableOptionalWidgets(bool bEnable) +{ + m_xPasswords->set_sensitive(bEnable); + m_xOptions->set_sensitive(bEnable); +} + +IMPL_LINK(ScTableProtectionDlg, CheckBoxHdl, weld::Toggleable&, rBtn, void) +{ + if (&rBtn == m_xBtnProtect.get()) + { + bool bChecked = m_xBtnProtect->get_active(); + EnableOptionalWidgets(bChecked); + m_xBtnOk->set_sensitive(bChecked); + } +} + +IMPL_LINK_NOARG(ScTableProtectionDlg, OKHdl, weld::Button&, void) +{ + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ScTableProtectionDlg, PasswordModifyHdl, weld::Entry&, void) +{ + OUString aPass1 = m_xPassword1Edit->get_text(); + OUString aPass2 = m_xPassword2Edit->get_text(); + m_xBtnOk->set_sensitive(aPass1 == aPass2); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/redcom.cxx b/sc/source/ui/miscdlgs/redcom.cxx new file mode 100644 index 000000000..ef04bd57e --- /dev/null +++ b/sc/source/ui/miscdlgs/redcom.cxx @@ -0,0 +1,167 @@ +/* -*- 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 <unotools/localedatawrapper.hxx> + +#include <chgtrack.hxx> +#include <redcom.hxx> +#include <docsh.hxx> +#include <dbfunc.hxx> +#include <tabview.hxx> +#include <viewutil.hxx> +#include <svx/svxdlg.hxx> + +ScRedComDialog::ScRedComDialog( weld::Window* pParent, const SfxItemSet& rCoreSet, + ScDocShell *pShell, ScChangeAction *pAction, bool bPrevNext) + : pChangeAction(nullptr) + , pDocShell(nullptr) + , pDlg(nullptr) +{ + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + pDlg = pFact->CreateSvxPostItDialog( pParent, rCoreSet, bPrevNext ); + pDocShell=pShell; + pDlg->DontChangeAuthor(); + pDlg->HideAuthor(); + + pDlg->SetPrevHdl(LINK( this, ScRedComDialog, PrevHdl)); + pDlg->SetNextHdl(LINK( this, ScRedComDialog, NextHdl)); + + ReInit(pAction); +} + +ScRedComDialog::~ScRedComDialog() +{ + pDlg.disposeAndClear(); +} + +ScChangeAction *ScRedComDialog::FindPrev(ScChangeAction *pAction) +{ + if(pAction!=nullptr && pDocShell !=nullptr) + { + ScDocument& rDoc = pDocShell->GetDocument(); + ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings(); + + pAction=pAction->GetPrev(); + + while(pAction!=nullptr) + { + if( pAction->GetState()==SC_CAS_VIRGIN && + pAction->IsDialogRoot() && + ScViewUtil::IsActionShown(*pAction,*pSettings,rDoc)) break; + + pAction=pAction->GetPrev(); + } + } + return pAction; +} + +ScChangeAction *ScRedComDialog::FindNext(ScChangeAction *pAction) +{ + if(pAction!=nullptr && pDocShell !=nullptr) + { + ScDocument& rDoc = pDocShell->GetDocument(); + ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings(); + + pAction=pAction->GetNext(); + + while(pAction!=nullptr) + { + if( pAction->GetState()==SC_CAS_VIRGIN && + pAction->IsDialogRoot() && + ScViewUtil::IsActionShown(*pAction,*pSettings,rDoc)) break; + + pAction=pAction->GetNext(); + } + } + return pAction; +} + +void ScRedComDialog::ReInit(ScChangeAction *pAction) +{ + pChangeAction=pAction; + if(pChangeAction==nullptr || pDocShell ==nullptr) + return; + + OUString aTitle = pChangeAction->GetDescription(pDocShell->GetDocument()); + pDlg->SetText(aTitle); + aComment=pChangeAction->GetComment(); + + bool bNext=FindNext(pChangeAction)!=nullptr; + bool bPrev=FindPrev(pChangeAction)!=nullptr; + pDlg->EnableTravel(bNext,bPrev); + + OUString aAuthor = pChangeAction->GetUser(); + + DateTime aDT = pChangeAction->GetDateTime(); + OUString aDate = ScGlobal::getLocaleData().getDate( aDT ) + " " + + ScGlobal::getLocaleData().getTime( aDT, false ); + + pDlg->ShowLastAuthor(aAuthor, aDate); + pDlg->SetNote(aComment); +} + +void ScRedComDialog::Execute() +{ + short nRet=pDlg->Execute(); + + if(nRet== RET_OK ) + { + if ( pDocShell!=nullptr && pDlg->GetNote() != aComment ) + pDocShell->SetChangeComment( pChangeAction, pDlg->GetNote()); + } +} + +void ScRedComDialog::SelectCell() +{ + if (!pChangeAction || !pDocShell) + return; + + const ScChangeAction* pAction=pChangeAction; + const ScBigRange& rRange = pAction->GetBigRange(); + + if(rRange.IsValid(pDocShell->GetDocument())) + { + if (ScViewData* pViewData = ScDocShell::GetViewData()) + { + ScRange aRef = rRange.MakeRange(pDocShell->GetDocument()); + ScTabView* pTabView = pViewData->GetView(); + pTabView->MarkRange(aRef); + } + } +} + +IMPL_LINK(ScRedComDialog, PrevHdl, AbstractSvxPostItDialog&, rDlgP, void ) +{ + if (pDocShell!=nullptr && rDlgP.GetNote() != aComment ) + pDocShell->SetChangeComment( pChangeAction, rDlgP.GetNote()); + + ReInit(FindPrev(pChangeAction)); + SelectCell(); +} + +IMPL_LINK(ScRedComDialog, NextHdl, AbstractSvxPostItDialog&, rDlgP, void ) +{ + if ( pDocShell!=nullptr && rDlgP.GetNote() != aComment ) + pDocShell->SetChangeComment( pChangeAction, rDlgP.GetNote()); + + ReInit(FindNext(pChangeAction)); + SelectCell(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/retypepassdlg.cxx b/sc/source/ui/miscdlgs/retypepassdlg.cxx new file mode 100644 index 000000000..c7b9084a8 --- /dev/null +++ b/sc/source/ui/miscdlgs/retypepassdlg.cxx @@ -0,0 +1,366 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <strings.hrc> +#include <retypepassdlg.hxx> +#include <scresid.hxx> +#include <document.hxx> +#include <tabprotection.hxx> + +ScRetypePassDlg::ScRetypePassDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/retypepassdialog.ui", "RetypePass") + , maTextNotProtected(ScResId(STR_NOT_PROTECTED)) + , maTextNotPassProtected(ScResId(STR_NOT_PASS_PROTECTED)) + , maTextHashBad(ScResId(STR_HASH_BAD)) + , maTextHashGood(ScResId(STR_HASH_GOOD)) + , meDesiredHash(PASSHASH_SHA1) + , mxBtnOk(m_xBuilder->weld_button("ok")) + , mxTextDocStatus(m_xBuilder->weld_label("docStatusLabel")) + , mxBtnRetypeDoc(m_xBuilder->weld_button("retypeDocButton")) + , mxScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow")) + , mxSheetsBox(m_xBuilder->weld_container("sheetsBox")) +{ + mxScrolledWindow->set_size_request(mxScrolledWindow->get_approximate_digit_width() * 46, + mxScrolledWindow->get_text_height() * 10); + Init(); +} + +ScRetypePassDlg::~ScRetypePassDlg() {} + +void ScRetypePassDlg::DeleteSheets() { maSheets.clear(); } + +short ScRetypePassDlg::run() +{ + PopulateDialog(); + CheckHashStatus(); + return GenericDialogController::run(); +} + +PassFragment::PassFragment(weld::Widget* pParent) + : m_xBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/passfragment.ui")) + , m_xSheetsBox(m_xBuilder->weld_container("PassEntry")) + , m_xName(m_xBuilder->weld_label("name")) + , m_xStatus(m_xBuilder->weld_label("status")) + , m_xButton(m_xBuilder->weld_button("button")) +{ + m_xButton->set_label(ScResId(STR_RETYPE)); +} + +void ScRetypePassDlg::SetDataFromDocument(const ScDocument& rDoc) +{ + DeleteSheets(); + const ScDocProtection* pDocProtect = rDoc.GetDocProtection(); + if (pDocProtect && pDocProtect->isProtected()) + mpDocItem = std::make_shared<ScDocProtection>(*pDocProtect); + + SCTAB nTabCount = rDoc.GetTableCount(); + maTableItems.reserve(nTabCount); + maSheets.reserve(nTabCount); + for (SCTAB i = 0; i < nTabCount; ++i) + { + TableItem aTabItem; + rDoc.GetName(i, aTabItem.maName); + + const ScTableProtection* pTabProtect = rDoc.GetTabProtection(i); + if (pTabProtect && pTabProtect->isProtected()) + aTabItem.mpProtect = std::make_shared<ScTableProtection>(*pTabProtect); + + maTableItems.push_back(aTabItem); + maSheets.emplace_back(new PassFragment(mxSheetsBox.get())); + maSheets.back()->m_xButton->connect_clicked(LINK(this, ScRetypePassDlg, RetypeBtnHdl)); + } +} + +void ScRetypePassDlg::SetDesiredHash(ScPasswordHash eHash) { meDesiredHash = eHash; } + +void ScRetypePassDlg::WriteNewDataToDocument(ScDocument& rDoc) const +{ + if (mpDocItem) + rDoc.SetDocProtection(mpDocItem.get()); + + size_t nTabCount = static_cast<size_t>(rDoc.GetTableCount()); + size_t n = maTableItems.size(); + for (size_t i = 0; i < n; ++i) + { + if (i >= nTabCount) + break; + + ScTableProtection* pTabProtect = maTableItems[i].mpProtect.get(); + if (pTabProtect) + rDoc.SetTabProtection(static_cast<SCTAB>(i), pTabProtect); + } +} + +void ScRetypePassDlg::Init() +{ + Link<weld::Button&, void> aLink = LINK(this, ScRetypePassDlg, OKHdl); + mxBtnOk->connect_clicked(aLink); + + aLink = LINK(this, ScRetypePassDlg, RetypeBtnHdl); + mxBtnRetypeDoc->connect_clicked(aLink); + + mxTextDocStatus->set_label(maTextNotProtected); + mxBtnRetypeDoc->set_sensitive(false); +} + +void ScRetypePassDlg::PopulateDialog() +{ + // Document protection first. + SetDocData(); + + // Sheet protection next. + for (size_t i = 0; i < maTableItems.size(); ++i) + SetTableData(i, static_cast<SCTAB>(i)); +} + +void ScRetypePassDlg::SetDocData() +{ + bool bBtnEnabled = false; + if (mpDocItem && mpDocItem->isProtected()) + { + if (mpDocItem->isPasswordEmpty()) + mxTextDocStatus->set_label(maTextNotPassProtected); + else if (mpDocItem->hasPasswordHash(meDesiredHash)) + mxTextDocStatus->set_label(maTextHashGood); + else + { + // incompatible hash + mxTextDocStatus->set_label(maTextHashBad); + bBtnEnabled = true; + } + } + mxBtnRetypeDoc->set_sensitive(bBtnEnabled); +} + +void ScRetypePassDlg::SetTableData(size_t nRowPos, SCTAB nTab) +{ + if (nRowPos >= maSheets.size()) + return; + + weld::Label& rName = *maSheets[nRowPos]->m_xName; + weld::Label& rStatus = *maSheets[nRowPos]->m_xStatus; + weld::Button& rBtn = *maSheets[nRowPos]->m_xButton; + + bool bBtnEnabled = false; + rName.set_label(maTableItems[nTab].maName); + const ScTableProtection* pTabProtect = maTableItems[nTab].mpProtect.get(); + if (pTabProtect && pTabProtect->isProtected()) + { + if (pTabProtect->isPasswordEmpty()) + rStatus.set_label(maTextNotPassProtected); + else if (pTabProtect->hasPasswordHash(meDesiredHash)) + rStatus.set_label(maTextHashGood); + else + { + // incompatible hash + rStatus.set_label(maTextHashBad); + bBtnEnabled = true; + } + } + else + rStatus.set_label(maTextNotProtected); + + rBtn.set_sensitive(bBtnEnabled); +} + +static bool lcl_IsInGoodStatus(const ScPassHashProtectable* pProtected, ScPasswordHash eDesiredHash) +{ + if (!pProtected || !pProtected->isProtected()) + // Not protected. + return true; + + if (pProtected->isPasswordEmpty()) + return true; + + if (pProtected->hasPasswordHash(eDesiredHash)) + return true; + + return false; +} + +void ScRetypePassDlg::CheckHashStatus() +{ + do + { + if (!lcl_IsInGoodStatus(mpDocItem.get(), meDesiredHash)) + break; + + bool bStatusGood = true; + size_t nTabCount = maTableItems.size(); + for (size_t i = 0; i < nTabCount && bStatusGood; ++i) + { + if (!lcl_IsInGoodStatus(maTableItems[i].mpProtect.get(), meDesiredHash)) + bStatusGood = false; + } + if (!bStatusGood) + break; + + mxBtnOk->set_sensitive(true); + return; + } while (false); + + mxBtnOk->set_sensitive(false); +} + +IMPL_LINK_NOARG(ScRetypePassDlg, OKHdl, weld::Button&, void) { m_xDialog->response(RET_OK); } + +IMPL_LINK(ScRetypePassDlg, RetypeBtnHdl, weld::Button&, rBtn, void) +{ + ScPassHashProtectable* pProtected = nullptr; + if (&rBtn == mxBtnRetypeDoc.get()) + { + // document protection. + pProtected = mpDocItem.get(); + } + else + { + // sheet protection. + size_t aPos = 0; + while (aPos < maSheets.size() && &rBtn != maSheets[aPos]->m_xButton.get()) + ++aPos; + + pProtected = aPos < maSheets.size() ? maTableItems[aPos].mpProtect.get() : nullptr; + } + + if (!pProtected) + // What the ... !? + return; + + ScRetypePassInputDlg aDlg(m_xDialog.get(), pProtected); + if (aDlg.run() != RET_OK) + return; + + // OK is pressed. Update the protected item. + if (aDlg.IsRemovePassword()) + { + // Remove password from this item. + pProtected->setPassword(OUString()); + } + else + { + // Set a new password. + OUString aNewPass = aDlg.GetNewPassword(); + pProtected->setPassword(aNewPass); + } + + SetDocData(); + CheckHashStatus(); +} + +ScRetypePassInputDlg::ScRetypePassInputDlg(weld::Window* pParent, ScPassHashProtectable* pProtected) + : GenericDialogController(pParent, "modules/scalc/ui/retypepassworddialog.ui", + "RetypePasswordDialog") + , m_pProtected(pProtected) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnRetypePassword(m_xBuilder->weld_radio_button("retypepassword")) + , m_xPasswordGrid(m_xBuilder->weld_widget("passwordgrid")) + , m_xPassword1Edit(m_xBuilder->weld_entry("newpassEntry")) + , m_xPassword2Edit(m_xBuilder->weld_entry("confirmpassEntry")) + , m_xBtnMatchOldPass(m_xBuilder->weld_check_button("mustmatch")) + , m_xBtnRemovePassword(m_xBuilder->weld_radio_button("removepassword")) +{ + Init(); +} + +ScRetypePassInputDlg::~ScRetypePassInputDlg() {} + +bool ScRetypePassInputDlg::IsRemovePassword() const { return m_xBtnRemovePassword->get_active(); } + +OUString ScRetypePassInputDlg::GetNewPassword() const { return m_xPassword1Edit->get_text(); } + +void ScRetypePassInputDlg::Init() +{ + m_xBtnOk->connect_clicked(LINK(this, ScRetypePassInputDlg, OKHdl)); + m_xBtnRetypePassword->connect_toggled(LINK(this, ScRetypePassInputDlg, RadioBtnHdl)); + m_xBtnRemovePassword->connect_toggled(LINK(this, ScRetypePassInputDlg, RadioBtnHdl)); + m_xBtnMatchOldPass->connect_toggled(LINK(this, ScRetypePassInputDlg, CheckBoxHdl)); + Link<weld::Entry&, void> aLink2 = LINK(this, ScRetypePassInputDlg, PasswordModifyHdl); + m_xPassword1Edit->connect_changed(aLink2); + m_xPassword2Edit->connect_changed(aLink2); + + m_xBtnOk->set_sensitive(false); + m_xBtnRetypePassword->set_active(true); + m_xBtnMatchOldPass->set_active(true); + m_xPassword1Edit->grab_focus(); +} + +void ScRetypePassInputDlg::CheckPasswordInput() +{ + OUString aPass1 = m_xPassword1Edit->get_text(); + OUString aPass2 = m_xPassword2Edit->get_text(); + + if (aPass1.isEmpty() || aPass2.isEmpty()) + { + // Empty password is not allowed. + m_xBtnOk->set_sensitive(false); + return; + } + + if (aPass1 != aPass2) + { + // The two passwords differ. + m_xBtnOk->set_sensitive(false); + return; + } + + if (!m_xBtnMatchOldPass->get_active()) + { + m_xBtnOk->set_sensitive(true); + return; + } + + if (!m_pProtected) + { + // This should never happen! + m_xBtnOk->set_sensitive(false); + return; + } + + bool bPassGood = m_pProtected->verifyPassword(aPass1); + m_xBtnOk->set_sensitive(bPassGood); +} + +IMPL_LINK_NOARG(ScRetypePassInputDlg, OKHdl, weld::Button&, void) { m_xDialog->response(RET_OK); } + +IMPL_LINK_NOARG(ScRetypePassInputDlg, RadioBtnHdl, weld::Toggleable&, void) +{ + if (m_xBtnRetypePassword->get_active()) + { + m_xPasswordGrid->set_sensitive(true); + CheckPasswordInput(); + } + else + { + m_xPasswordGrid->set_sensitive(false); + m_xBtnOk->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(ScRetypePassInputDlg, CheckBoxHdl, weld::Toggleable&, void) +{ + CheckPasswordInput(); +} + +IMPL_LINK_NOARG(ScRetypePassInputDlg, PasswordModifyHdl, weld::Entry&, void) +{ + CheckPasswordInput(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/scuiautofmt.cxx b/sc/source/ui/miscdlgs/scuiautofmt.cxx new file mode 100644 index 000000000..ecf446081 --- /dev/null +++ b/sc/source/ui/miscdlgs/scuiautofmt.cxx @@ -0,0 +1,385 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/strings.hrc> +#include <sfx2/sfxresid.hxx> +#include <o3tl/string_view.hxx> +#include <strings.hrc> +#include <global.hxx> +#include <globstr.hrc> +#include <autoform.hxx> +#include <strindlg.hxx> +#include <scuiautofmt.hxx> +#include <scresid.hxx> +#include <helpids.h> + +// AutoFormat-Dialog: + +ScAutoFormatDlg::ScAutoFormatDlg(weld::Window* pParent, + ScAutoFormat* pAutoFormat, + const ScAutoFormatData* pSelFormatData, + const ScViewData& rViewData) + : GenericDialogController(pParent, "modules/scalc/ui/autoformattable.ui", "AutoFormatTableDialog") + , aStrTitle(ScResId(STR_ADD_AUTOFORMAT_TITLE)) + , aStrLabel(ScResId(STR_ADD_AUTOFORMAT_LABEL)) + , aStrClose(ScResId(STR_BTN_AUTOFORMAT_CLOSE)) + , aStrDelMsg(ScResId(STR_DEL_AUTOFORMAT_MSG)) + , aStrRename(ScResId(STR_RENAME_AUTOFORMAT_TITLE)) + , pFormat(pAutoFormat) + , pSelFmtData(pSelFormatData) + , nIndex(0) + , bCoreDataChanged(false) + , bFmtInserted(false) + , m_xLbFormat(m_xBuilder->weld_tree_view("formatlb")) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) + , m_xBtnAdd(m_xBuilder->weld_button("add")) + , m_xBtnRemove(m_xBuilder->weld_button("remove")) + , m_xBtnRename(m_xBuilder->weld_button("rename")) + , m_xBtnNumFormat(m_xBuilder->weld_check_button("numformatcb")) + , m_xBtnBorder(m_xBuilder->weld_check_button("bordercb")) + , m_xBtnFont(m_xBuilder->weld_check_button("fontcb")) + , m_xBtnPattern(m_xBuilder->weld_check_button("patterncb")) + , m_xBtnAlignment(m_xBuilder->weld_check_button("alignmentcb")) + , m_xBtnAdjust(m_xBuilder->weld_check_button("autofitcb")) + , m_xWndPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aWndPreview)) +{ + m_aWndPreview.DetectRTL(rViewData); + + const int nWidth = m_xLbFormat->get_approximate_digit_width() * 32; + const int nHeight = m_xLbFormat->get_height_rows(8); + m_xLbFormat->set_size_request(nWidth, nHeight); + m_xWndPreview->set_size_request(nWidth, nHeight); + + Init(); + ScAutoFormat::iterator it = pFormat->begin(); + m_aWndPreview.NotifyChange(it->second.get()); +} + +ScAutoFormatDlg::~ScAutoFormatDlg() +{ +} + +void ScAutoFormatDlg::Init() +{ + m_xLbFormat->connect_changed( LINK( this, ScAutoFormatDlg, SelFmtHdl ) ); + m_xBtnNumFormat->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnBorder->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnFont->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnPattern->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnAlignment->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnAdjust->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) ); + m_xBtnAdd->connect_clicked ( LINK( this, ScAutoFormatDlg, AddHdl ) ); + m_xBtnRemove->connect_clicked ( LINK( this, ScAutoFormatDlg, RemoveHdl ) ); + m_xBtnOk->connect_clicked ( LINK( this, ScAutoFormatDlg, CloseHdl ) ); + m_xBtnCancel->connect_clicked ( LINK( this, ScAutoFormatDlg, CloseHdl ) ); + m_xBtnRename->connect_clicked ( LINK( this, ScAutoFormatDlg, RenameHdl ) ); + m_xLbFormat->connect_row_activated( LINK( this, ScAutoFormatDlg, DblClkHdl ) ); + + for (const auto& rEntry : *pFormat) + m_xLbFormat->append_text(rEntry.second->GetName()); + + if (pFormat->size() == 1) + m_xBtnRemove->set_sensitive(false); + + m_xLbFormat->select(0); + m_xBtnRename->set_sensitive(false); + m_xBtnRemove->set_sensitive(false); + + nIndex = 0; + UpdateChecks(); + + if ( !pSelFmtData ) + { + m_xBtnAdd->set_sensitive(false); + m_xBtnRemove->set_sensitive(false); + bFmtInserted = true; + } +} + +void ScAutoFormatDlg::UpdateChecks() +{ + const ScAutoFormatData* pData = pFormat->findByIndex(nIndex); + + m_xBtnNumFormat->set_active( pData->GetIncludeValueFormat() ); + m_xBtnBorder->set_active( pData->GetIncludeFrame() ); + m_xBtnFont->set_active( pData->GetIncludeFont() ); + m_xBtnPattern->set_active( pData->GetIncludeBackground() ); + m_xBtnAlignment->set_active( pData->GetIncludeJustify() ); + m_xBtnAdjust->set_active( pData->GetIncludeWidthHeight() ); +} + +// Handler: + +IMPL_LINK(ScAutoFormatDlg, CloseHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == m_xBtnOk.get() || &rBtn == m_xBtnCancel.get()) + { + if ( bCoreDataChanged ) + ScGlobal::GetOrCreateAutoFormat()->Save(); + + m_xDialog->response( (&rBtn == m_xBtnOk.get()) ? RET_OK : RET_CANCEL ); + } +} + +IMPL_LINK_NOARG(ScAutoFormatDlg, DblClkHdl, weld::TreeView&, bool) +{ + if ( bCoreDataChanged ) + ScGlobal::GetOrCreateAutoFormat()->Save(); + + m_xDialog->response( RET_OK ); + + return true; +} + +IMPL_LINK(ScAutoFormatDlg, CheckHdl, weld::Toggleable&, rBtn, void) +{ + ScAutoFormatData* pData = pFormat->findByIndex(nIndex); + bool bCheck = rBtn.get_active(); + + if (&rBtn == m_xBtnNumFormat.get()) + pData->SetIncludeValueFormat( bCheck ); + else if (&rBtn == m_xBtnBorder.get()) + pData->SetIncludeFrame( bCheck ); + else if (&rBtn == m_xBtnFont.get()) + pData->SetIncludeFont( bCheck ); + else if (&rBtn == m_xBtnPattern.get()) + pData->SetIncludeBackground( bCheck ); + else if (&rBtn == m_xBtnAlignment.get()) + pData->SetIncludeJustify( bCheck ); + else if (&rBtn == m_xBtnAdjust.get()) + pData->SetIncludeWidthHeight( bCheck ); + + if ( !bCoreDataChanged ) + { + m_xBtnCancel->set_label(aStrClose); + bCoreDataChanged = true; + } + + m_aWndPreview.NotifyChange( pData ); +} + +IMPL_LINK_NOARG(ScAutoFormatDlg, AddHdl, weld::Button&, void) +{ + if ( bFmtInserted || !pSelFmtData ) + return; + + OUString aStrStandard( SfxResId(STR_STANDARD) ); + OUString aFormatName; + bool bOk = false; + + while ( !bOk ) + { + ScStringInputDlg aDlg(m_xDialog.get(), aStrTitle, aStrLabel, aFormatName, + HID_SC_ADD_AUTOFMT, HID_SC_AUTOFMT_NAME); + + if (aDlg.run() == RET_OK) + { + aFormatName = aDlg.GetInputString(); + + if ( !aFormatName.isEmpty() && aFormatName != aStrStandard && pFormat->find(aFormatName) == pFormat->end() ) + { + std::unique_ptr<ScAutoFormatData> pNewData( + new ScAutoFormatData( *pSelFmtData )); + + pNewData->SetName( aFormatName ); + ScAutoFormat::iterator it = pFormat->insert(std::move(pNewData)); + bFmtInserted = it != pFormat->end(); + + if ( bFmtInserted ) + { + size_t nPos = std::distance(pFormat->begin(), it); + m_xLbFormat->insert_text(nPos, aFormatName); + m_xLbFormat->select_text( aFormatName ); + m_xBtnAdd->set_sensitive(false); + + if ( !bCoreDataChanged ) + { + m_xBtnCancel->set_label( aStrClose ); + bCoreDataChanged = true; + } + + SelFmtHdl( *m_xLbFormat ); + bOk = true; + } + } + + if ( !bFmtInserted ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Error, VclButtonsType::OkCancel, + ScResId(STR_INVALID_AFNAME))); + + sal_uInt16 nRet = xBox->run(); + + bOk = ( nRet == RET_CANCEL ); + } + } + else + bOk = true; + } +} + +IMPL_LINK_NOARG(ScAutoFormatDlg, RemoveHdl, weld::Button&, void) +{ + if ( (nIndex > 0) && (m_xLbFormat->n_children() > 0) ) + { + OUString aMsg = o3tl::getToken(aStrDelMsg, 0, '#' ) + + m_xLbFormat->get_selected_text() + + o3tl::getToken(aStrDelMsg, 1, '#' ); + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Question, VclButtonsType::YesNo, + aMsg)); + xQueryBox->set_default_response(RET_YES); + + if (RET_YES == xQueryBox->run()) + { + m_xLbFormat->remove(nIndex); + m_xLbFormat->select(nIndex-1); + + if ( nIndex-1 == 0 ) + m_xBtnRemove->set_sensitive(false); + + if ( !bCoreDataChanged ) + { + m_xBtnCancel->set_label( aStrClose ); + bCoreDataChanged = true; + } + + ScAutoFormat::iterator it = pFormat->begin(); + std::advance(it, nIndex); + pFormat->erase(it); + nIndex--; + + SelFmtHdl( *m_xLbFormat ); + } + } + + SelFmtHdl( *m_xLbFormat ); +} + +IMPL_LINK_NOARG(ScAutoFormatDlg, RenameHdl, weld::Button&, void) +{ + bool bOk = false; + while( !bOk ) + { + + OUString aFormatName = m_xLbFormat->get_selected_text(); + OUString aEntry; + + ScStringInputDlg aDlg(m_xDialog.get(), aStrRename, aStrLabel, aFormatName, + HID_SC_REN_AFMT_DLG, HID_SC_REN_AFMT_NAME); + if (aDlg.run() == RET_OK) + { + bool bFmtRenamed = false; + aFormatName = aDlg.GetInputString(); + + if (!aFormatName.isEmpty()) + { + ScAutoFormat::iterator it = pFormat->begin(), itEnd = pFormat->end(); + for (; it != itEnd; ++it) + { + aEntry = it->second->GetName(); + if (aFormatName == aEntry) + break; + } + if (it == itEnd) + { + // no format with this name yet, so we can rename + + m_xLbFormat->remove(nIndex); + const ScAutoFormatData* p = pFormat->findByIndex(nIndex); + std::unique_ptr<ScAutoFormatData> pNewData(new ScAutoFormatData(*p)); + + it = pFormat->begin(); + std::advance(it, nIndex); + pFormat->erase(it); + + pNewData->SetName( aFormatName ); + + pFormat->insert(std::move(pNewData)); + + m_xLbFormat->freeze(); + m_xLbFormat->clear(); + for (it = pFormat->begin(); it != itEnd; ++it) + { + aEntry = it->second->GetName(); + m_xLbFormat->append_text(aEntry); + } + + m_xLbFormat->thaw(); + m_xLbFormat->select_text(aFormatName); + + if ( !bCoreDataChanged ) + { + m_xBtnCancel->set_label( aStrClose ); + bCoreDataChanged = true; + } + + SelFmtHdl( *m_xLbFormat ); + bOk = true; + bFmtRenamed = true; + } + } + if( !bFmtRenamed ) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Error, VclButtonsType::OkCancel, + ScResId(STR_INVALID_AFNAME))); + + bOk = RET_CANCEL == xBox->run(); + } + } + else + bOk = true; + } +} + +IMPL_LINK_NOARG(ScAutoFormatDlg, SelFmtHdl, weld::TreeView&, void) +{ + nIndex = m_xLbFormat->get_selected_index(); + UpdateChecks(); + + if ( nIndex == 0 ) + { + m_xBtnRename->set_sensitive(false); + m_xBtnRemove->set_sensitive(false); + } + else + { + m_xBtnRename->set_sensitive(true); + m_xBtnRemove->set_sensitive(true); + } + + ScAutoFormatData* p = pFormat->findByIndex(nIndex); + m_aWndPreview.NotifyChange(p); +} + +OUString ScAutoFormatDlg::GetCurrFormatName() +{ + const ScAutoFormatData* p = pFormat->findByIndex(nIndex); + return p ? p->GetName() : OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/sharedocdlg.cxx b/sc/source/ui/miscdlgs/sharedocdlg.cxx new file mode 100644 index 000000000..9abf05c6b --- /dev/null +++ b/sc/source/ui/miscdlgs/sharedocdlg.cxx @@ -0,0 +1,213 @@ +/* -*- 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 <o3tl/safeint.hxx> +#include <osl/security.hxx> +#include <osl/diagnose.h> +#include <sfx2/dialoghelper.hxx> +#include <svl/sharecontrolfile.hxx> +#include <unotools/useroptions.hxx> +#include <tools/diagnose_ex.h> +#include <o3tl/string_view.hxx> + +#include <docsh.hxx> + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include <scresid.hxx> +#include <sharedocdlg.hxx> +#include <strings.hrc> +#include <viewdata.hxx> + +using namespace ::com::sun::star; + +IMPL_LINK(ScShareDocumentDlg, SizeAllocated, const Size&, rSize, void) +{ + OUString sWidestAccessString = getWidestDateTime(ScGlobal::getLocaleData(), false); + const int nAccessWidth = m_xLbUsers->get_pixel_size(sWidestAccessString).Width() * 2; + std::vector<int> aWidths + { + o3tl::narrowing<int>(rSize.Width() - nAccessWidth) + }; + m_xLbUsers->set_column_fixed_widths(aWidths); +} + + +ScShareDocumentDlg::ScShareDocumentDlg(weld::Window* pParent, const ScViewData* pViewData) + : GenericDialogController(pParent, "modules/scalc/ui/sharedocumentdlg.ui", + "ShareDocumentDialog") + , m_aStrNoUserData(ScResId(STR_NO_USER_DATA_AVAILABLE)) + , m_aStrUnknownUser(ScResId(STR_UNKNOWN_USER_CONFLICT)) + , m_aStrExclusiveAccess(ScResId(STR_EXCLUSIVE_ACCESS)) + , mpDocShell(nullptr) + , m_xCbShare(m_xBuilder->weld_check_button("share")) + , m_xFtWarning(m_xBuilder->weld_label("warning")) + , m_xLbUsers(m_xBuilder->weld_tree_view("users")) +{ + + OSL_ENSURE( pViewData, "ScShareDocumentDlg CTOR: mpViewData is null!" ); + mpDocShell = ( pViewData ? pViewData->GetDocShell() : nullptr ); + OSL_ENSURE( mpDocShell, "ScShareDocumentDlg CTOR: mpDocShell is null!" ); + + std::vector<int> aWidths + { + o3tl::narrowing<int>(m_xLbUsers->get_approximate_digit_width() * 25) + }; + m_xLbUsers->set_column_fixed_widths(aWidths); + + m_xLbUsers->set_size_request(-1, m_xLbUsers->get_height_rows(9)); + m_xLbUsers->connect_size_allocate(LINK(this, ScShareDocumentDlg, SizeAllocated)); + + bool bIsDocShared = mpDocShell && mpDocShell->IsDocShared(); + m_xCbShare->set_active(bIsDocShared); + m_xCbShare->connect_toggled( LINK( this, ScShareDocumentDlg, ToggleHandle ) ); + m_xFtWarning->set_sensitive(bIsDocShared); + + m_xLbUsers->set_selection_mode(SelectionMode::NONE); + + UpdateView(); +} + +ScShareDocumentDlg::~ScShareDocumentDlg() +{ +} + +IMPL_LINK_NOARG(ScShareDocumentDlg, ToggleHandle, weld::Toggleable&, void) +{ + m_xFtWarning->set_sensitive(m_xCbShare->get_active()); +} + +bool ScShareDocumentDlg::IsShareDocumentChecked() const +{ + return m_xCbShare->get_active(); +} + +void ScShareDocumentDlg::UpdateView() +{ + if ( !mpDocShell ) + { + return; + } + + if ( mpDocShell->IsDocShared() ) + { + try + { + ::svt::ShareControlFile aControlFile( mpDocShell->GetSharedFileURL() ); + std::vector<LockFileEntry> aUsersData = aControlFile.GetUsersData(); + sal_Int32 nLength = aUsersData.size(); + + if ( nLength > 0 ) + { + sal_Int32 nUnknownUser = 1; + + for ( sal_Int32 i = 0; i < nLength; ++i ) + { + if ( !aUsersData[i][LockFileComponent::EDITTIME].isEmpty() ) + { + OUString aUser; + if ( !aUsersData[i][LockFileComponent::OOOUSERNAME].isEmpty() ) + { + aUser = aUsersData[i][LockFileComponent::OOOUSERNAME]; + } + else if ( !aUsersData[i][LockFileComponent::SYSUSERNAME].isEmpty() ) + { + aUser = aUsersData[i][LockFileComponent::SYSUSERNAME]; + } + else + { + aUser = m_aStrUnknownUser + " " + OUString::number( nUnknownUser++ ); + } + + // parse the edit time string of the format "DD.MM.YYYY hh:mm" + OUString aDateTimeStr = aUsersData[i][LockFileComponent::EDITTIME]; + sal_Int32 nIndex = 0; + std::u16string_view aDateStr = o3tl::getToken(aDateTimeStr, 0, ' ', nIndex ); + std::u16string_view aTimeStr = o3tl::getToken(aDateTimeStr, 0, ' ', nIndex ); + nIndex = 0; + sal_uInt16 nDay = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) ); + sal_uInt16 nMonth = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) ); + sal_uInt16 nYear = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) ); + nIndex = 0; + sal_uInt16 nHours = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', nIndex )) ); + sal_uInt16 nMinutes = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', nIndex )) ); + Date aDate( nDay, nMonth, nYear ); + tools::Time aTime( nHours, nMinutes ); + DateTime aDateTime( aDate, aTime ); + + OUString aString = formatDateTime(aDateTime, ScGlobal::getLocaleData(), false); + + m_xLbUsers->append_text(aUser); + m_xLbUsers->set_text(m_xLbUsers->n_children() - 1, aString, 1); + } + } + } + else + { + m_xLbUsers->append_text(m_aStrNoUserData); + } + } + catch ( uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "sc", "ScShareDocumentDlg::UpdateView()" ); + m_xLbUsers->clear(); + m_xLbUsers->append_text(m_aStrNoUserData); + } + } + else + { + // get OOO user name + SvtUserOptions aUserOpt; + OUString aUser = aUserOpt.GetFirstName(); + if ( !aUser.isEmpty() ) + { + aUser += " "; + } + aUser += aUserOpt.GetLastName(); + if ( aUser.isEmpty() ) + { + // get sys user name + OUString aUserName; + ::osl::Security aSecurity; + aSecurity.getUserName( aUserName ); + aUser = aUserName; + } + if ( aUser.isEmpty() ) + { + // unknown user name + aUser = m_aStrUnknownUser; + } + aUser += " " + m_aStrExclusiveAccess; + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS(mpDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties(); + + util::DateTime uDT(xDocProps->getModificationDate()); + DateTime aDateTime(uDT); + + OUString aString = formatDateTime(aDateTime, ScGlobal::getLocaleData(), false) + " " + + ScGlobal::getLocaleData().getTime( aDateTime, false ); + + m_xLbUsers->append_text(aUser); + m_xLbUsers->set_text(m_xLbUsers->n_children() - 1, aString, 1); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/shtabdlg.cxx b/sc/source/ui/miscdlgs/shtabdlg.cxx new file mode 100644 index 000000000..cf0c10918 --- /dev/null +++ b/sc/source/ui/miscdlgs/shtabdlg.cxx @@ -0,0 +1,66 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <shtabdlg.hxx> + +ScShowTabDlg::ScShowTabDlg(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/showsheetdialog.ui", "ShowSheetDialog") + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xLb(m_xBuilder->weld_tree_view("treeview")) +{ + m_xLb->set_selection_mode(SelectionMode::Multiple); + m_xLb->set_size_request(-1, m_xLb->get_height_rows(10)); + m_xLb->connect_row_activated(LINK(this, ScShowTabDlg, DblClkHdl)); +} + +ScShowTabDlg::~ScShowTabDlg() {} + +void ScShowTabDlg::SetDescription(const OUString& rTitle, const OUString& rFixedText, + const OString& rDlgHelpId, const OString& sLbHelpId) +{ + m_xDialog->set_title(rTitle); + m_xFrame->set_label(rFixedText); + m_xDialog->set_help_id(rDlgHelpId); + m_xLb->set_help_id(sLbHelpId); +} + +void ScShowTabDlg::Insert(const OUString& rString, bool bSelected) +{ + m_xLb->append_text(rString); + if (bSelected) + m_xLb->select(m_xLb->n_children() - 1); +} + +std::vector<sal_Int32> ScShowTabDlg::GetSelectedRows() const +{ + auto aTmp = m_xLb->get_selected_rows(); + return std::vector<sal_Int32>(aTmp.begin(), aTmp.end()); +} + +OUString ScShowTabDlg::GetEntry(sal_Int32 nIndex) const { return m_xLb->get_text(nIndex); } + +IMPL_LINK_NOARG(ScShowTabDlg, DblClkHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/simpref.cxx b/sc/source/ui/miscdlgs/simpref.cxx new file mode 100644 index 000000000..27e8e3bb6 --- /dev/null +++ b/sc/source/ui/miscdlgs/simpref.cxx @@ -0,0 +1,190 @@ +/* -*- 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 <reffact.hxx> +#include <document.hxx> +#include <simpref.hxx> + +ScSimpleRefDlg::ScSimpleRefDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent) + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/simplerefdialog.ui", "SimpleRefDialog") + , bAutoReOpen(true) + , bCloseOnButtonUp(false) + , bSingleCell(false) + , bMultiSelection(false) + , m_xFtAssign(m_xBuilder->weld_label("area")) + , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("assign"))) + , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assignref"))) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) +{ + m_xEdAssign->SetReferences(this, m_xFtAssign.get()); + m_xRbAssign->SetReferences(this, m_xEdAssign.get()); + + // in order to keep the Strings with the FixedTexts in the resource: + Init(); + SetDispatcherLock( true ); // activate modal mode +} + +ScSimpleRefDlg::~ScSimpleRefDlg() +{ + SetDispatcherLock( false ); // deactivate modal mode +} + +void ScSimpleRefDlg::FillInfo(SfxChildWinInfo& rWinInfo) const +{ + ScAnyRefDlgController::FillInfo(rWinInfo); + rWinInfo.bVisible = bAutoReOpen; +} + +void ScSimpleRefDlg::SetRefString(const OUString &rStr) +{ + m_xEdAssign->SetText(rStr); +} + +void ScSimpleRefDlg::Init() +{ + m_xBtnOk->connect_clicked( LINK( this, ScSimpleRefDlg, OkBtnHdl ) ); + m_xBtnCancel->connect_clicked( LINK( this, ScSimpleRefDlg, CancelBtnHdl ) ); + bCloseFlag=false; +} + +// Set the reference to a cell range selected with the mouse. This is then +// shown as the new selection in the reference field. +void ScSimpleRefDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if (!m_xEdAssign->GetWidget()->get_sensitive()) + return; + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(m_xEdAssign.get()); + + theCurArea = rRef; + OUString aRefStr; + if ( bSingleCell ) + { + ScAddress aAdr = rRef.aStart; + aRefStr = aAdr.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, rDocP.GetAddressConvention()); + } + else + aRefStr = theCurArea.Format(rDocP, ScRefFlags::RANGE_ABS_3D, rDocP.GetAddressConvention()); + + if ( bMultiSelection ) + { + OUString aVal = m_xEdAssign->GetText(); + Selection aSel = m_xEdAssign->GetSelection(); + aSel.Justify(); + aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aRefStr ); + Selection aNewSel( aSel.Min(), aSel.Min()+aRefStr.getLength() ); + m_xEdAssign->SetRefString( aVal ); + m_xEdAssign->SetSelection( aNewSel ); + } + else + m_xEdAssign->SetRefString( aRefStr ); + + aChangeHdl.Call( aRefStr ); +} + +void ScSimpleRefDlg::Close() +{ + CancelBtnHdl(*m_xBtnCancel); +} + +void ScSimpleRefDlg::SetActive() +{ + m_xEdAssign->GrabFocus(); + + // no NameModifyHdl. Otherwise ranges could not be altered + // (after marking the reference, the old field content would be shown) + // (also, the selected DB name has also not been altered) + + RefInputDone(); +} + +bool ScSimpleRefDlg::IsRefInputMode() const +{ + return true; +} + +void ScSimpleRefDlg::SetCloseHdl( const Link<const OUString*,void>& rLink ) +{ + aCloseHdl=rLink; +} + +void ScSimpleRefDlg::SetUnoLinks( const Link<const OUString&,void>& rDone, + const Link<const OUString&,void>& rAbort, + const Link<const OUString&,void>& rChange ) +{ + aDoneHdl = rDone; + aAbortedHdl = rAbort; + aChangeHdl = rChange; +} + +void ScSimpleRefDlg::SetFlags( bool bSetCloseOnButtonUp, bool bSetSingleCell, bool bSetMultiSelection ) +{ + bCloseOnButtonUp = bSetCloseOnButtonUp; + bSingleCell = bSetSingleCell; + bMultiSelection = bSetMultiSelection; +} + +void ScSimpleRefDlg::StartRefInput() +{ + if ( bMultiSelection ) + { + // initially select the whole string, so it gets replaced by default + m_xEdAssign->SelectAll(); + } + + m_xRbAssign->DoRef(); + bCloseFlag = true; +} + +void ScSimpleRefDlg::RefInputDone( bool bForced) +{ + ScAnyRefDlgController::RefInputDone(bForced); + if ( (bForced || bCloseOnButtonUp) && bCloseFlag ) + OkBtnHdl(*m_xBtnOk); +} + +// Handler: + +IMPL_LINK_NOARG(ScSimpleRefDlg, OkBtnHdl, weld::Button&, void) +{ + if (IsClosing()) + return; + bAutoReOpen = false; + OUString aResult=m_xEdAssign->GetText(); + aCloseHdl.Call(&aResult); + Link<const OUString&,void> aUnoLink = aDoneHdl; // stack var because this is deleted in DoClose + DoClose( ScSimpleRefDlgWrapper::GetChildWindowId() ); + aUnoLink.Call( aResult ); +} + +IMPL_LINK_NOARG(ScSimpleRefDlg, CancelBtnHdl, weld::Button&, void) +{ + if (IsClosing()) + return; + bAutoReOpen = false; + OUString aResult=m_xEdAssign->GetText(); + aCloseHdl.Call(nullptr); + Link<const OUString&,void> aUnoLink = aAbortedHdl; // stack var because this is deleted in DoClose + DoClose( ScSimpleRefDlgWrapper::GetChildWindowId() ); + aUnoLink.Call( aResult ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/solveroptions.cxx b/sc/source/ui/miscdlgs/solveroptions.cxx new file mode 100644 index 000000000..41603b6d5 --- /dev/null +++ b/sc/source/ui/miscdlgs/solveroptions.cxx @@ -0,0 +1,415 @@ +/* -*- 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 <memory> +#include <solveroptions.hxx> +#include <global.hxx> +#include <miscuno.hxx> +#include <solverutil.hxx> + +#include <rtl/math.hxx> +#include <unotools/collatorwrapper.hxx> +#include <unotools/localedatawrapper.hxx> +#include <osl/diagnose.h> + +#include <algorithm> + +#include <com/sun/star/sheet/XSolver.hpp> +#include <com/sun/star/sheet/XSolverDescription.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +using namespace com::sun::star; + +namespace { + +/// Helper for sorting properties +struct ScSolverOptionsEntry +{ + sal_Int32 nPosition; + OUString aDescription; + + ScSolverOptionsEntry() : nPosition(0) {} + + bool operator< (const ScSolverOptionsEntry& rOther) const + { + return (ScGlobal::GetCollator().compareString( aDescription, rOther.aDescription ) < 0); + } +}; + +} + +ScSolverOptionsDialog::ScSolverOptionsDialog(weld::Window* pParent, + const uno::Sequence<OUString>& rImplNames, + const uno::Sequence<OUString>& rDescriptions, + const OUString& rEngine, + const uno::Sequence<beans::PropertyValue>& rProperties ) + : GenericDialogController(pParent, "modules/scalc/ui/solveroptionsdialog.ui", "SolverOptionsDialog") + , maImplNames(rImplNames) + , maEngine(rEngine) + , maProperties(rProperties) + , m_xLbEngine(m_xBuilder->weld_combo_box("engine")) + , m_xLbSettings(m_xBuilder->weld_tree_view("settings")) + , m_xBtnEdit(m_xBuilder->weld_button("edit")) +{ + m_xLbSettings->set_size_request(m_xLbSettings->get_approximate_digit_width() * 32, + m_xLbSettings->get_height_rows(6)); + + m_xLbSettings->enable_toggle_buttons(weld::ColumnToggleType::Check); + + m_xLbEngine->connect_changed( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) ); + + m_xBtnEdit->connect_clicked( LINK( this, ScSolverOptionsDialog, ButtonHdl ) ); + + m_xLbSettings->connect_changed( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) ); + m_xLbSettings->connect_row_activated( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) ); + + sal_Int32 nSelect = -1; + sal_Int32 nImplCount = maImplNames.getLength(); + for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl) + { + OUString aImplName( maImplNames[nImpl] ); + OUString aDescription( rDescriptions[nImpl] ); // user-visible descriptions in list box + m_xLbEngine->append_text(aDescription); + if ( aImplName == maEngine ) + nSelect = nImpl; + } + if ( nSelect < 0 ) // no (valid) engine given + { + if ( nImplCount > 0 ) + { + maEngine = maImplNames[0]; // use first implementation + nSelect = 0; + } + else + maEngine.clear(); + maProperties.realloc(0); // don't use options from different engine + } + if ( nSelect >= 0 ) // select in list box + m_xLbEngine->set_active(nSelect); + + if ( !maProperties.hasElements() ) + ReadFromComponent(); // fill maProperties from component (using maEngine) + FillListBox(); // using maProperties +} + +ScSolverOptionsDialog::~ScSolverOptionsDialog() +{ + if (m_xIntDialog) + m_xIntDialog->response(RET_CANCEL); + assert(!m_xIntDialog); + if (m_xValDialog) + m_xValDialog->response(RET_CANCEL); + assert(!m_xValDialog); +} + +const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties() +{ + // update maProperties from list box content + // order of entries in list box and maProperties is the same + sal_Int32 nEntryCount = maProperties.getLength(); + if (nEntryCount == m_xLbSettings->n_children()) + { + auto maPropertiesRange = asNonConstRange(maProperties); + for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos) + { + uno::Any& rValue = maPropertiesRange[nEntryPos].Value; + if (ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntryPos))) + { + if (pStringItem->IsDouble()) + rValue <<= pStringItem->GetDoubleValue(); + else + rValue <<= pStringItem->GetIntValue(); + } + else + rValue <<= m_xLbSettings->get_toggle(nEntryPos) == TRISTATE_TRUE; + } + } + else + { + OSL_FAIL( "wrong count" ); + } + + return maProperties; +} + +void ScSolverOptionsDialog::FillListBox() +{ + // get property descriptions, sort by them + + uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY ); + sal_Int32 nCount = maProperties.getLength(); + std::vector<ScSolverOptionsEntry> aDescriptions( nCount ); + for (sal_Int32 nPos=0; nPos<nCount; nPos++) + { + OUString aPropName( maProperties[nPos].Name ); + OUString aVisName; + if ( xDesc.is() ) + aVisName = xDesc->getPropertyDescription( aPropName ); + if ( aVisName.isEmpty() ) + aVisName = aPropName; + aDescriptions[nPos].nPosition = nPos; + aDescriptions[nPos].aDescription = aVisName; + } + std::sort( aDescriptions.begin(), aDescriptions.end() ); + + // also update maProperties to the order of descriptions + + uno::Sequence<beans::PropertyValue> aNewSeq; + aNewSeq.realloc( nCount ); + std::transform(aDescriptions.begin(), aDescriptions.end(), aNewSeq.getArray(), + [this](const ScSolverOptionsEntry& rDescr) -> beans::PropertyValue { return maProperties[ rDescr.nPosition ]; }); + maProperties = aNewSeq; + + // fill the list box + + m_xLbSettings->freeze(); + m_xLbSettings->clear(); + + for (sal_Int32 nPos=0; nPos<nCount; nPos++) + { + OUString aVisName = aDescriptions[nPos].aDescription; + + uno::Any aValue = maProperties[nPos].Value; + uno::TypeClass eClass = aValue.getValueTypeClass(); + + m_xLbSettings->append(); + + if ( eClass == uno::TypeClass_BOOLEAN ) + { + // check box entry + m_xLbSettings->set_toggle(nPos, ScUnoHelpFunctions::GetBoolFromAny(aValue) ? TRISTATE_TRUE : TRISTATE_FALSE); + m_xLbSettings->set_text(nPos, aVisName, 0); + } + else + { + // value entry + m_xLbSettings->set_text(nPos, aVisName, 0); + m_aOptions.emplace_back(new ScSolverOptionsString(aVisName)); + if (eClass == uno::TypeClass_DOUBLE) + { + double fDoubleValue = 0.0; + if (aValue >>= fDoubleValue) + m_aOptions.back()->SetDoubleValue(fDoubleValue); + + OUString sTxt = aVisName + ": "; + sTxt += rtl::math::doubleToUString(fDoubleValue, + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + ScGlobal::getLocaleData().getNumDecimalSep()[0], true ); + + m_xLbSettings->set_text(nPos, sTxt, 0); + } + else + { + sal_Int32 nIntValue = 0; + if (aValue >>= nIntValue) + m_aOptions.back()->SetIntValue(nIntValue); + + OUString sTxt = aVisName + ": " + OUString::number(nIntValue); + + m_xLbSettings->set_text(nPos, sTxt, 0); + } + m_xLbSettings->set_id(nPos, weld::toId(m_aOptions.back().get())); + } + } + + m_xLbSettings->thaw(); +} + +void ScSolverOptionsDialog::ReadFromComponent() +{ + maProperties = ScSolverUtil::GetDefaults( maEngine ); +} + +void ScSolverOptionsDialog::EditOption() +{ + int nEntry = m_xLbSettings->get_selected_index(); + if (nEntry == -1) + return; + ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntry)); + if (!pStringItem) + return; + + if (pStringItem->IsDouble()) + { + m_xValDialog = std::make_shared<ScSolverValueDialog>(m_xDialog.get()); + m_xValDialog->SetOptionName(pStringItem->GetText()); + if (maProperties[nEntry].Name == "DECR") + m_xValDialog->SetMax(1.0); + else if (maProperties[nEntry].Name == "DEFactorMax") + m_xValDialog->SetMax(1.2); + else if (maProperties[nEntry].Name == "DEFactorMin") + m_xValDialog->SetMax(1.2); + else if (maProperties[nEntry].Name == "PSCL") + m_xValDialog->SetMax(0.005); + m_xValDialog->SetValue(pStringItem->GetDoubleValue()); + weld::DialogController::runAsync(m_xValDialog, [nEntry, pStringItem, this](sal_Int32 nResult){ + if (nResult == RET_OK) + { + pStringItem->SetDoubleValue(m_xValDialog->GetValue()); + + OUString sTxt(pStringItem->GetText() + ": "); + sTxt += rtl::math::doubleToUString(pStringItem->GetDoubleValue(), + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + ScGlobal::getLocaleData().getNumDecimalSep()[0], true ); + + m_xLbSettings->set_text(nEntry, sTxt, 0); + } + m_xValDialog.reset(); + }); + } + else + { + m_xIntDialog = std::make_shared<ScSolverIntegerDialog>(m_xDialog.get()); + m_xIntDialog->SetOptionName( pStringItem->GetText() ); + if (maProperties[nEntry].Name == "EpsilonLevel") + m_xIntDialog->SetMax(3); + else if (maProperties[nEntry].Name == "Algorithm") + m_xIntDialog->SetMax(1); + m_xIntDialog->SetValue( pStringItem->GetIntValue() ); + weld::DialogController::runAsync(m_xIntDialog, [nEntry, pStringItem, this](sal_Int32 nResult){ + if (nResult == RET_OK) + { + pStringItem->SetIntValue(m_xIntDialog->GetValue()); + + OUString sTxt( + pStringItem->GetText() + ": " + OUString::number(pStringItem->GetIntValue())); + + m_xLbSettings->set_text(nEntry, sTxt, 0); + } + m_xIntDialog.reset(); + }); + } +} + +IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, weld::Button&, rBtn, void ) +{ + if (&rBtn == m_xBtnEdit.get()) + EditOption(); +} + +IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsDoubleClickHdl, weld::TreeView&, bool) +{ + EditOption(); + return true; +} + +IMPL_LINK_NOARG(ScSolverOptionsDialog, EngineSelectHdl, weld::ComboBox&, void) +{ + const sal_Int32 nSelectPos = m_xLbEngine->get_active(); + if ( nSelectPos < maImplNames.getLength() ) + { + OUString aNewEngine( maImplNames[nSelectPos] ); + if ( aNewEngine != maEngine ) + { + maEngine = aNewEngine; + ReadFromComponent(); // fill maProperties from component (using maEngine) + FillListBox(); // using maProperties + } + } +} + +IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsSelHdl, weld::TreeView&, void) +{ + bool bCheckbox = false; + + int nEntry = m_xLbSettings->get_selected_index(); + if (nEntry != -1) + { + ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntry)); + if (!pStringItem) + bCheckbox = true; + } + + m_xBtnEdit->set_sensitive(!bCheckbox); +} + +ScSolverIntegerDialog::ScSolverIntegerDialog(weld::Window * pParent) + : GenericDialogController(pParent, "modules/scalc/ui/integerdialog.ui", "IntegerDialog") + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xNfValue(m_xBuilder->weld_spin_button("value")) +{ +} + +ScSolverIntegerDialog::~ScSolverIntegerDialog() +{ +} + +void ScSolverIntegerDialog::SetOptionName( const OUString& rName ) +{ + m_xFrame->set_label(rName); +} + +void ScSolverIntegerDialog::SetValue( sal_Int32 nValue ) +{ + m_xNfValue->set_value( nValue ); +} + +void ScSolverIntegerDialog::SetMax( sal_Int32 nMax ) +{ + m_xNfValue->set_range(0, nMax); +} + +sal_Int32 ScSolverIntegerDialog::GetValue() const +{ + return m_xNfValue->get_value(); +} + +ScSolverValueDialog::ScSolverValueDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/scalc/ui/doubledialog.ui", "DoubleDialog") + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xEdValue(m_xBuilder->weld_entry("value")) + , m_fMaxValue(std::numeric_limits<double>::quiet_NaN()) +{ +} + +ScSolverValueDialog::~ScSolverValueDialog() +{ +} + +void ScSolverValueDialog::SetOptionName( const OUString& rName ) +{ + m_xFrame->set_label(rName); +} + +void ScSolverValueDialog::SetValue( double fValue ) +{ + m_xEdValue->set_text( rtl::math::doubleToUString( fValue, + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + ScGlobal::getLocaleData().getNumDecimalSep()[0], true ) ); +} + +void ScSolverValueDialog::SetMax(double fMax) +{ + m_fMaxValue = fMax; +} + +double ScSolverValueDialog::GetValue() const +{ + OUString aInput = m_xEdValue->get_text(); + + rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; + sal_Int32 nParseEnd = 0; + double fValue = ScGlobal::getLocaleData().stringToDouble( aInput, true, &eStatus, &nParseEnd); + /* TODO: shouldn't there be some error checking? */ + if (!std::isnan(m_fMaxValue) && fValue > m_fMaxValue) + fValue = m_fMaxValue; + return fValue; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/solverutil.cxx b/sc/source/ui/miscdlgs/solverutil.cxx new file mode 100644 index 000000000..6ba270786 --- /dev/null +++ b/sc/source/ui/miscdlgs/solverutil.cxx @@ -0,0 +1,175 @@ +/* -*- 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 <solverutil.hxx> + +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/sheet/XSolver.hpp> +#include <com/sun/star/sheet/XSolverDescription.hpp> + +#include <osl/diagnose.h> +#include <comphelper/processfactory.hxx> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +using namespace com::sun::star; + +constexpr OUStringLiteral SCSOLVER_SERVICE = u"com.sun.star.sheet.Solver"; + +void ScSolverUtil::GetImplementations( uno::Sequence<OUString>& rImplNames, + uno::Sequence<OUString>& rDescriptions ) +{ + rImplNames.realloc(0); // clear + rDescriptions.realloc(0); + + uno::Reference<uno::XComponentContext> xCtx( + comphelper::getProcessComponentContext() ); + + uno::Reference<container::XContentEnumerationAccess> xEnAc( + xCtx->getServiceManager(), uno::UNO_QUERY ); + if ( !xEnAc.is() ) + return; + + uno::Reference<container::XEnumeration> xEnum = + xEnAc->createContentEnumeration( SCSOLVER_SERVICE ); + if ( !xEnum.is() ) + return; + + sal_Int32 nCount = 0; + while ( xEnum->hasMoreElements() ) + { + uno::Any aAny = xEnum->nextElement(); + uno::Reference<lang::XServiceInfo> xInfo; + aAny >>= xInfo; + if ( xInfo.is() ) + { + uno::Reference<lang::XSingleComponentFactory> xCFac( xInfo, uno::UNO_QUERY ); + if ( xCFac.is() ) + { + OUString sName = xInfo->getImplementationName(); + + try + { + uno::Reference<sheet::XSolver> xSolver( + xCFac->createInstanceWithContext(xCtx), uno::UNO_QUERY ); + uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY ); + OUString sDescription; + if ( xDesc.is() ) + sDescription = xDesc->getComponentDescription(); + + if ( sDescription.isEmpty() ) + sDescription = sName; // use implementation name if no description available + + rImplNames.realloc( nCount+1 ); + rImplNames.getArray()[nCount] = sName; + rDescriptions.realloc( nCount+1 ); + rDescriptions.getArray()[nCount] = sDescription; + ++nCount; + } + catch (const css::uno::Exception&) + { + TOOLS_INFO_EXCEPTION("sc.ui", "ScSolverUtil::GetImplementations: cannot instantiate: " << sName); + } + } + } + } +} + +uno::Reference<sheet::XSolver> ScSolverUtil::GetSolver( std::u16string_view rImplName ) +{ + uno::Reference<sheet::XSolver> xSolver; + + uno::Reference<uno::XComponentContext> xCtx( + comphelper::getProcessComponentContext() ); + + uno::Reference<container::XContentEnumerationAccess> xEnAc( + xCtx->getServiceManager(), uno::UNO_QUERY ); + if ( xEnAc.is() ) + { + uno::Reference<container::XEnumeration> xEnum = + xEnAc->createContentEnumeration( SCSOLVER_SERVICE ); + if ( xEnum.is() ) + { + while ( xEnum->hasMoreElements() && !xSolver.is() ) + { + uno::Any aAny = xEnum->nextElement(); + uno::Reference<lang::XServiceInfo> xInfo; + aAny >>= xInfo; + if ( xInfo.is() ) + { + uno::Reference<lang::XSingleComponentFactory> xCFac( xInfo, uno::UNO_QUERY ); + if ( xCFac.is() ) + { + OUString sName = xInfo->getImplementationName(); + if ( sName == rImplName ) + xSolver.set( xCFac->createInstanceWithContext(xCtx), uno::UNO_QUERY ); + } + } + } + } + } + + SAL_WARN_IF( !xSolver.is(), "sc.ui", "can't get solver" ); + return xSolver; +} + +uno::Sequence<beans::PropertyValue> ScSolverUtil::GetDefaults( std::u16string_view rImplName ) +{ + uno::Sequence<beans::PropertyValue> aDefaults; + + uno::Reference<sheet::XSolver> xSolver = GetSolver( rImplName ); + uno::Reference<beans::XPropertySet> xPropSet( xSolver, uno::UNO_QUERY ); + if ( !xPropSet.is() ) + { + // no XPropertySet - no options + return aDefaults; + } + + // fill maProperties + + uno::Reference<beans::XPropertySetInfo> xInfo = xPropSet->getPropertySetInfo(); + OSL_ENSURE( xInfo.is(), "can't get property set info" ); + if ( !xInfo.is() ) + return aDefaults; + + const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties(); + const sal_Int32 nSize = aPropSeq.getLength(); + aDefaults.realloc(nSize); + auto pDefaults = aDefaults.getArray(); + sal_Int32 nValid = 0; + for (const beans::Property& rProp : aPropSeq) + { + uno::Any aValue = xPropSet->getPropertyValue( rProp.Name ); + uno::TypeClass eClass = aValue.getValueTypeClass(); + // only use properties of supported types + if ( eClass == uno::TypeClass_BOOLEAN || eClass == uno::TypeClass_LONG || eClass == uno::TypeClass_DOUBLE ) + pDefaults[nValid++] = beans::PropertyValue( rProp.Name, -1, aValue, beans::PropertyState_DIRECT_VALUE ); + } + aDefaults.realloc(nValid); + + //! get user-visible names, sort by them + + return aDefaults; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/solvrdlg.cxx b/sc/source/ui/miscdlgs/solvrdlg.cxx new file mode 100644 index 000000000..f7cd8e27b --- /dev/null +++ b/sc/source/ui/miscdlgs/solvrdlg.cxx @@ -0,0 +1,282 @@ +/* -*- 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 <scitems.hxx> +#include <sfx2/dispatch.hxx> +#include <svl/numformat.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <uiitems.hxx> +#include <reffact.hxx> +#include <document.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <sc.hrc> +#include <solvrdlg.hxx> + +ScSolverDlg::ScSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScDocument* pDocument, + const ScAddress& aCursorPos ) + + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/goalseekdlg.ui", "GoalSeekDialog") + , theFormulaCell(aCursorPos) + , theVariableCell(aCursorPos) + , pDoc(pDocument) + , nCurTab(aCursorPos.Tab()) + , bDlgLostFocus(false) + , errMsgInvalidVar(ScResId(STR_INVALIDVAR)) + , errMsgInvalidForm(ScResId(STR_INVALIDFORM)) + , errMsgNoFormula(ScResId(STR_NOFORMULA)) + , errMsgInvalidVal(ScResId(STR_INVALIDVAL)) + , m_pEdActive(nullptr) + , m_xFtFormulaCell(m_xBuilder->weld_label("formulatext")) + , m_xEdFormulaCell(new formula::RefEdit(m_xBuilder->weld_entry("formulaedit"))) + , m_xRBFormulaCell(new formula::RefButton(m_xBuilder->weld_button("formulabutton"))) + , m_xEdTargetVal(m_xBuilder->weld_entry("target")) + , m_xFtVariableCell(m_xBuilder->weld_label("vartext")) + , m_xEdVariableCell(new formula::RefEdit(m_xBuilder->weld_entry("varedit"))) + , m_xRBVariableCell(new formula::RefButton(m_xBuilder->weld_button("varbutton"))) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) +{ + m_xEdFormulaCell->SetReferences(this, m_xFtFormulaCell.get()); + m_xRBFormulaCell->SetReferences(this, m_xEdFormulaCell.get()); + m_xEdVariableCell->SetReferences(this, m_xFtVariableCell.get()); + m_xRBVariableCell->SetReferences(this, m_xEdVariableCell.get()); + Init(); +} + +ScSolverDlg::~ScSolverDlg() +{ + if (m_xMessageBox) + m_xMessageBox->response(RET_CANCEL); + assert(!m_xMessageBox); +} + +void ScSolverDlg::Init() +{ + m_xBtnOk->connect_clicked( LINK( this, ScSolverDlg, BtnHdl ) ); + m_xBtnCancel->connect_clicked( LINK( this, ScSolverDlg, BtnHdl ) ); + + Link<formula::RefEdit&,void> aEditLink = LINK( this, ScSolverDlg, GetEditFocusHdl ); + m_xEdFormulaCell->SetGetFocusHdl( aEditLink ); + m_xEdVariableCell->SetGetFocusHdl( aEditLink ); + + Link<formula::RefButton&,void> aButtonLink = LINK( this, ScSolverDlg, GetButtonFocusHdl ); + m_xRBFormulaCell->SetGetFocusHdl( aButtonLink ); + m_xRBVariableCell->SetGetFocusHdl( aButtonLink ); + + m_xEdTargetVal->connect_focus_in(LINK(this, ScSolverDlg, GetFocusHdl)); + + aEditLink = LINK( this, ScSolverDlg, LoseEditFocusHdl ); + m_xEdFormulaCell->SetLoseFocusHdl ( aEditLink ); + m_xEdVariableCell->SetLoseFocusHdl ( aEditLink ); + + aButtonLink = LINK( this, ScSolverDlg, LoseButtonFocusHdl ); + m_xRBFormulaCell->SetLoseFocusHdl ( aButtonLink ); + m_xRBVariableCell->SetLoseFocusHdl ( aButtonLink ); + + OUString aStr(theFormulaCell.Format(ScRefFlags::ADDR_ABS, nullptr, pDoc->GetAddressConvention())); + + m_xEdFormulaCell->SetText( aStr ); + m_xEdFormulaCell->GrabFocus(); + m_pEdActive = m_xEdFormulaCell.get(); +} + +void ScSolverDlg::Close() +{ + DoClose( ScSolverDlgWrapper::GetChildWindowId() ); +} + +void ScSolverDlg::SetActive() +{ + if ( bDlgLostFocus ) + { + bDlgLostFocus = false; + if( m_pEdActive ) + m_pEdActive->GrabFocus(); + } + else + { + m_xDialog->grab_focus(); + } + RefInputDone(); +} + +void ScSolverDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if( !m_pEdActive ) + return; + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(m_pEdActive); + + ScAddress aAdr = rRef.aStart; + ScRefFlags nFmt = ( aAdr.Tab() == nCurTab ) + ? ScRefFlags::ADDR_ABS + : ScRefFlags::ADDR_ABS_3D; + + OUString aStr(aAdr.Format(nFmt, &rDocP, rDocP.GetAddressConvention())); + m_pEdActive->SetRefString( aStr ); + + if (m_pEdActive == m_xEdFormulaCell.get()) + theFormulaCell = aAdr; + else if (m_pEdActive == m_xEdVariableCell.get()) + theVariableCell = aAdr; +} + +void ScSolverDlg::RaiseError( ScSolverErr eError ) +{ + OUString sMessage; + + switch (eError) + { + case SOLVERR_NOFORMULA: + sMessage = errMsgNoFormula; + break; + case SOLVERR_INVALID_FORMULA: + sMessage = errMsgInvalidForm; + break; + case SOLVERR_INVALID_VARIABLE: + sMessage = errMsgInvalidVar; + break; + case SOLVERR_INVALID_TARGETVALUE: + sMessage = errMsgInvalidVal; + break; + } + + m_xMessageBox.reset(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sMessage)); + m_xMessageBox->runAsync(m_xMessageBox, [this](sal_Int32 /*nResult*/) { + m_xEdTargetVal->grab_focus(); + m_xMessageBox.reset(); + }); +} + +bool ScSolverDlg::IsRefInputMode() const +{ + return m_pEdActive != nullptr; +} + +bool ScSolverDlg::CheckTargetValue( const OUString& rStrVal ) +{ + sal_uInt32 n1 = 0; + double n2; + + return pDoc->GetFormatTable()->IsNumberFormat( rStrVal, n1, n2 ); +} + +// Handler: + +IMPL_LINK(ScSolverDlg, BtnHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == m_xBtnOk.get()) + { + theTargetValStr = m_xEdTargetVal->get_text(); + + // The following code checks: + // 1. do the strings contain correct references / defined names? + // 2. does the formula coordinate refer to a cell containing a formula? + // 3. has a valid target value been entered? + + const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); + ScRefFlags nRes1 = theFormulaCell .Parse( m_xEdFormulaCell->GetText(), *pDoc, eConv ); + ScRefFlags nRes2 = theVariableCell.Parse( m_xEdVariableCell->GetText(), *pDoc, eConv ); + + if ( (nRes1 & ScRefFlags::VALID) == ScRefFlags::VALID ) + { + if ( (nRes2 & ScRefFlags::VALID) == ScRefFlags::VALID ) + { + if ( CheckTargetValue( theTargetValStr ) ) + { + CellType eType = pDoc->GetCellType( theFormulaCell.Col(), + theFormulaCell.Row(), + theFormulaCell.Tab()); + + if ( CELLTYPE_FORMULA == eType ) + { + ScSolveParam aOutParam( theFormulaCell, + theVariableCell, + theTargetValStr ); + ScSolveItem aOutItem( SCITEM_SOLVEDATA, &aOutParam ); + + SetDispatcherLock( false ); + + SwitchToDocument(); + GetBindings().GetDispatcher()->ExecuteList(SID_SOLVE, + SfxCallMode::SLOT | SfxCallMode::RECORD, + { &aOutItem }); + response(RET_OK); + } + else RaiseError( SOLVERR_NOFORMULA ); + } + else RaiseError( SOLVERR_INVALID_TARGETVALUE ); + } + else RaiseError( SOLVERR_INVALID_VARIABLE ); + } + else RaiseError( SOLVERR_INVALID_FORMULA ); + } + else if (&rBtn == m_xBtnCancel.get()) + { + response(RET_CANCEL); + } +} + +IMPL_LINK(ScSolverDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void) +{ + if (&rCtrl == m_xEdFormulaCell.get()) + m_pEdActive = m_xEdFormulaCell.get(); + else if (&rCtrl == m_xEdVariableCell.get()) + m_pEdActive = m_xEdVariableCell.get(); + + if (m_pEdActive) + m_pEdActive->SelectAll(); +} + +IMPL_LINK_NOARG(ScSolverDlg, GetFocusHdl, weld::Widget&, void) +{ + m_pEdActive = nullptr; + m_xEdTargetVal->select_region(0, -1); +} + +IMPL_LINK(ScSolverDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void) +{ + if (&rCtrl == m_xRBFormulaCell.get()) + m_pEdActive = m_xEdFormulaCell.get(); + else if (&rCtrl == m_xRBVariableCell.get()) + m_pEdActive = m_xEdVariableCell.get(); + + if (m_pEdActive) + m_pEdActive->SelectAll(); +} + +IMPL_LINK_NOARG(ScSolverDlg, LoseEditFocusHdl, formula::RefEdit&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(ScSolverDlg, LoseButtonFocusHdl, formula::RefButton&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/strindlg.cxx b/sc/source/ui/miscdlgs/strindlg.cxx new file mode 100644 index 000000000..61ba77534 --- /dev/null +++ b/sc/source/ui/miscdlgs/strindlg.cxx @@ -0,0 +1,42 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <strindlg.hxx> + +ScStringInputDlg::ScStringInputDlg(weld::Window* pParent, + const OUString& rTitle, + const OUString& rEditTitle, + const OUString& rDefault, + const OString& rHelpId, const OString& rEditHelpId) + : GenericDialogController(pParent, "modules/scalc/ui/inputstringdialog.ui", + "InputStringDialog") + , m_xLabel(m_xBuilder->weld_label("description_label")) + , m_xEdInput(m_xBuilder->weld_entry("name_entry")) +{ + m_xLabel->set_label(rEditTitle); + m_xDialog->set_title(rTitle); + m_xDialog->set_help_id(rHelpId); + m_xEdInput->set_text(rDefault); + m_xEdInput->set_help_id(rEditHelpId); + m_xEdInput->select_region(0, -1); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/tabbgcolordlg.cxx b/sc/source/ui/miscdlgs/tabbgcolordlg.cxx new file mode 100644 index 000000000..7a346a4e3 --- /dev/null +++ b/sc/source/ui/miscdlgs/tabbgcolordlg.cxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <tabbgcolordlg.hxx> + +#include <tools/color.hxx> +#include <vcl/event.hxx> + +#include <officecfg/Office/Common.hxx> + +ScTabBgColorDlg::ScTabBgColorDlg(weld::Window* pParent, const OUString& rTitle, + const OUString& rTabBgColorNoColorText, const Color& rDefaultColor) + : GenericDialogController(pParent, "modules/scalc/ui/tabcolordialog.ui", "TabColorDialog") + , m_aTabBgColor(rDefaultColor) + , m_xSelectPalette(m_xBuilder->weld_combo_box("paletteselector")) + , m_xTabBgColorSet(new ScTabBgColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true))) + , m_xTabBgColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *m_xTabBgColorSet)) + , m_xBtnOk(m_xBuilder->weld_button("ok")) +{ + m_xTabBgColorSet->SetDialog(this); + m_xTabBgColorSet->SetColCount(SvxColorValueSet::getColumnCount()); + + m_xDialog->set_title(rTitle); + + const WinBits nBits(m_xTabBgColorSet->GetStyle() | WB_NAMEFIELD | WB_ITEMBORDER | WB_NONEFIELD | WB_3DLOOK | WB_NO_DIRECTSELECT); + m_xTabBgColorSet->SetStyle(nBits); + m_xTabBgColorSet->SetText(rTabBgColorNoColorText); + + const sal_uInt32 nColCount = SvxColorValueSet::getColumnCount(); + const sal_uInt32 nRowCount(10); + const sal_uInt32 nLength = SvxColorValueSet::getEntryEdgeLength(); + Size aSize(m_xTabBgColorSet->CalcWindowSizePixel(Size(nLength, nLength), nColCount, nRowCount)); + m_xTabBgColorSetWin->set_size_request(aSize.Width() + 8, aSize.Height() + 8); + + FillPaletteLB(); + + m_xSelectPalette->connect_changed(LINK(this, ScTabBgColorDlg, SelectPaletteLBHdl)); + m_xTabBgColorSet->SetDoubleClickHdl(LINK(this, ScTabBgColorDlg, TabBgColorDblClickHdl_Impl)); + m_xBtnOk->connect_clicked(LINK(this, ScTabBgColorDlg, TabBgColorOKHdl_Impl)); +} + +ScTabBgColorDlg::~ScTabBgColorDlg() +{ +} + +void ScTabBgColorDlg::GetSelectedColor( Color& rColor ) const +{ + rColor = m_aTabBgColor; +} + +void ScTabBgColorDlg::FillPaletteLB() +{ + m_xSelectPalette->clear(); + std::vector<OUString> aPaletteList = m_aPaletteManager.GetPaletteList(); + for (auto const& palette : aPaletteList) + { + m_xSelectPalette->append_text(palette); + } + OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() ); + m_xSelectPalette->set_active_text(aPaletteName); + if (m_xSelectPalette->get_active() != -1) + { + SelectPaletteLBHdl(*m_xSelectPalette); + } +} + +IMPL_LINK_NOARG(ScTabBgColorDlg, SelectPaletteLBHdl, weld::ComboBox&, void) +{ + m_xTabBgColorSet->Clear(); + sal_Int32 nPos = m_xSelectPalette->get_active(); + m_aPaletteManager.SetPalette( nPos ); + m_aPaletteManager.ReloadColorSet(*m_xTabBgColorSet); + m_xTabBgColorSet->Resize(); + m_xTabBgColorSet->SelectItem(0); +} + +// Handler, called when color selection is changed +IMPL_LINK_NOARG(ScTabBgColorDlg, TabBgColorDblClickHdl_Impl, ValueSet*, void) +{ + sal_uInt16 nItemId = m_xTabBgColorSet->GetSelectedItemId(); + Color aColor = nItemId ? ( m_xTabBgColorSet->GetItemColor( nItemId ) ) : COL_AUTO; + m_aTabBgColor = aColor; + m_xDialog->response(RET_OK); +} + +// Handler, called when the OK button is pushed +IMPL_LINK_NOARG(ScTabBgColorDlg, TabBgColorOKHdl_Impl, weld::Button&, void) +{ + sal_uInt16 nItemId = m_xTabBgColorSet->GetSelectedItemId(); + Color aColor = nItemId ? ( m_xTabBgColorSet->GetItemColor( nItemId ) ) : COL_AUTO; + m_aTabBgColor = aColor; + m_xDialog->response(RET_OK); +} + +ScTabBgColorDlg::ScTabBgColorValueSet::ScTabBgColorValueSet(std::unique_ptr<weld::ScrolledWindow> pWindow) + : SvxColorValueSet(std::move(pWindow)) + , m_pTabBgColorDlg(nullptr) +{ +} + +ScTabBgColorDlg::ScTabBgColorValueSet::~ScTabBgColorValueSet() +{ +} + +bool ScTabBgColorDlg::ScTabBgColorValueSet::KeyInput( const KeyEvent& rKEvt ) +{ + switch ( rKEvt.GetKeyCode().GetCode() ) + { + case KEY_SPACE: + case KEY_RETURN: + { + sal_uInt16 nItemId = GetSelectedItemId(); + const Color& aColor = nItemId ? ( GetItemColor( nItemId ) ) : COL_AUTO; + m_pTabBgColorDlg->m_aTabBgColor = aColor; + m_pTabBgColorDlg->response(RET_OK); + return true; + } + break; + } + return SvxColorValueSet::KeyInput(rKEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/tabopdlg.cxx b/sc/source/ui/miscdlgs/tabopdlg.cxx new file mode 100644 index 000000000..7e9be6ea8 --- /dev/null +++ b/sc/source/ui/miscdlgs/tabopdlg.cxx @@ -0,0 +1,345 @@ +/* -*- 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 <sfx2/dispatch.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <uiitems.hxx> +#include <document.hxx> +#include <scresid.hxx> +#include <sc.hrc> +#include <strings.hrc> +#include <reffact.hxx> + +#include <tabopdlg.hxx> + + +ScTabOpDlg::ScTabOpDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, + ScDocument* pDocument, + const ScRefAddress& rCursorPos ) + : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/multipleoperationsdialog.ui", + "MultipleOperationsDialog") + , theFormulaCell(rCursorPos) + , pDoc(pDocument) + , nCurTab(theFormulaCell.Tab()) + , bDlgLostFocus(false) + , errMsgNoFormula(ScResId(STR_NOFORMULASPECIFIED)) + , errMsgNoColRow(ScResId(STR_NOCOLROW)) + , errMsgWrongFormula(ScResId(STR_WRONGFORMULA)) + , errMsgWrongRowCol(ScResId(STR_WRONGROWCOL)) + , errMsgNoColFormula(ScResId(STR_NOCOLFORMULA)) + , errMsgNoRowFormula(ScResId(STR_NOROWFORMULA)) + , m_pEdActive(nullptr) + , m_xFtFormulaRange(m_xBuilder->weld_label("formulasft")) + , m_xEdFormulaRange(new formula::RefEdit(m_xBuilder->weld_entry("formulas"))) + , m_xRBFormulaRange(new formula::RefButton(m_xBuilder->weld_button("formulasref"))) + , m_xFtRowCell(m_xBuilder->weld_label("rowft")) + , m_xEdRowCell(new formula::RefEdit(m_xBuilder->weld_entry("row"))) + , m_xRBRowCell(new formula::RefButton(m_xBuilder->weld_button("rowref"))) + , m_xFtColCell(m_xBuilder->weld_label("colft")) + , m_xEdColCell(new formula::RefEdit(m_xBuilder->weld_entry("col"))) + , m_xRBColCell(new formula::RefButton(m_xBuilder->weld_button("colref"))) + , m_xBtnOk(m_xBuilder->weld_button("ok")) + , m_xBtnCancel(m_xBuilder->weld_button("cancel")) +{ + m_xEdFormulaRange->SetReferences(this, m_xFtFormulaRange.get()); + m_xRBFormulaRange->SetReferences(this, m_xEdFormulaRange.get()); + + m_xEdRowCell->SetReferences(this, m_xFtRowCell.get()); + m_xRBRowCell->SetReferences(this, m_xEdRowCell.get()); + + m_xEdColCell->SetReferences(this, m_xFtColCell.get()); + m_xRBColCell->SetReferences(this, m_xEdColCell.get()); + + Init(); +} + +ScTabOpDlg::~ScTabOpDlg() +{ +} + +void ScTabOpDlg::Init() +{ + m_xBtnOk->connect_clicked( LINK( this, ScTabOpDlg, BtnHdl ) ); + m_xBtnCancel->connect_clicked( LINK( this, ScTabOpDlg, BtnHdl ) ); + + Link<formula::RefEdit&,void> aEditLink = LINK( this, ScTabOpDlg, GetEditFocusHdl ); + m_xEdFormulaRange->SetGetFocusHdl( aEditLink ); + m_xEdRowCell->SetGetFocusHdl( aEditLink ); + m_xEdColCell->SetGetFocusHdl( aEditLink ); + + Link<formula::RefButton&,void> aButtonLink = LINK( this, ScTabOpDlg, GetButtonFocusHdl ); + m_xRBFormulaRange->SetGetFocusHdl( aButtonLink ); + m_xRBRowCell->SetGetFocusHdl( aButtonLink ); + m_xRBColCell->SetGetFocusHdl( aButtonLink ); + + aEditLink = LINK( this, ScTabOpDlg, LoseEditFocusHdl ); + m_xEdFormulaRange->SetLoseFocusHdl( aEditLink ); + m_xEdRowCell->SetLoseFocusHdl( aEditLink ); + m_xEdColCell->SetLoseFocusHdl( aEditLink ); + + aButtonLink = LINK( this, ScTabOpDlg, LoseButtonFocusHdl ); + m_xRBFormulaRange->SetLoseFocusHdl( aButtonLink ); + m_xRBRowCell->SetLoseFocusHdl( aButtonLink ); + m_xRBColCell->SetLoseFocusHdl( aButtonLink ); + + m_xEdFormulaRange->GrabFocus(); + m_pEdActive = m_xEdFormulaRange.get(); +} + +void ScTabOpDlg::Close() +{ + DoClose( ScTabOpDlgWrapper::GetChildWindowId() ); +} + +void ScTabOpDlg::SetActive() +{ + if ( bDlgLostFocus ) + { + bDlgLostFocus = false; + if (m_pEdActive) + m_pEdActive->GrabFocus(); + } + else + m_xDialog->grab_focus(); + + RefInputDone(); +} + +void ScTabOpDlg::SetReference( const ScRange& rRef, ScDocument& rDocP ) +{ + if (!m_pEdActive) + return; + + ScAddress::Details aDetails(rDocP.GetAddressConvention(), 0, 0); + + if ( rRef.aStart != rRef.aEnd ) + RefInputStart(m_pEdActive); + + OUString aStr; + ScRefFlags nFmt = ( rRef.aStart.Tab() == nCurTab ) + ? ScRefFlags::RANGE_ABS + : ScRefFlags::RANGE_ABS_3D; + + if (m_pEdActive == m_xEdFormulaRange.get()) + { + theFormulaCell.Set( rRef.aStart, false, false, false); + theFormulaEnd.Set( rRef.aEnd, false, false, false); + aStr = rRef.Format(rDocP, nFmt, aDetails); + } + else if (m_pEdActive == m_xEdRowCell.get()) + { + theRowCell.Set( rRef.aStart, false, false, false); + aStr = rRef.aStart.Format(nFmt, &rDocP, aDetails); + } + else if (m_pEdActive == m_xEdColCell.get()) + { + theColCell.Set( rRef.aStart, false, false, false); + aStr = rRef.aStart.Format(nFmt, &rDocP, aDetails); + } + + m_pEdActive->SetRefString( aStr ); +} + +void ScTabOpDlg::RaiseError( ScTabOpErr eError ) +{ + const OUString* pMsg = &errMsgNoFormula; + formula::RefEdit* pEd = m_xEdFormulaRange.get(); + + switch ( eError ) + { + case TABOPERR_NOFORMULA: + pMsg = &errMsgNoFormula; + pEd = m_xEdFormulaRange.get(); + break; + + case TABOPERR_NOCOLROW: + pMsg = &errMsgNoColRow; + pEd = m_xEdRowCell.get(); + break; + + case TABOPERR_WRONGFORMULA: + pMsg = &errMsgWrongFormula; + pEd = m_xEdFormulaRange.get(); + break; + + case TABOPERR_WRONGROW: + pMsg = &errMsgWrongRowCol; + pEd = m_xEdRowCell.get(); + break; + + case TABOPERR_NOCOLFORMULA: + pMsg = &errMsgNoColFormula; + pEd = m_xEdFormulaRange.get(); + break; + + case TABOPERR_WRONGCOL: + pMsg = &errMsgWrongRowCol; + pEd = m_xEdColCell.get(); + break; + + case TABOPERR_NOROWFORMULA: + pMsg = &errMsgNoRowFormula; + pEd = m_xEdFormulaRange.get(); + break; + } + + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Error, VclButtonsType::OkCancel, *pMsg)); + xBox->run(); + pEd->GrabFocus(); +} + +static bool lcl_Parse( const OUString& rString, const ScDocument& rDoc, SCTAB nCurTab, + ScRefAddress& rStart, ScRefAddress& rEnd ) +{ + bool bRet = false; + const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention(); + if ( rString.indexOf(':') != -1 ) + bRet = ConvertDoubleRef( rDoc, rString, nCurTab, rStart, rEnd, eConv ); + else + { + bRet = ConvertSingleRef( rDoc, rString, nCurTab, rStart, eConv ); + rEnd = rStart; + } + return bRet; +} + +// Handler: + +IMPL_LINK(ScTabOpDlg, BtnHdl, weld::Button&, rBtn, void) +{ + if (&rBtn == m_xBtnOk.get()) + { + ScTabOpParam::Mode eMode = ScTabOpParam::Column; + sal_uInt16 nError = 0; + + // The following code checks: + // 1. do the strings contain correct cell references / defined names? + // 2. is formula range row if row is empty or column if column is empty + // or single reference if both? + // 3. is at least one of row or column non-empty? + + if (m_xEdFormulaRange->GetText().isEmpty()) + nError = TABOPERR_NOFORMULA; + else if (m_xEdRowCell->GetText().isEmpty() && + m_xEdColCell->GetText().isEmpty()) + nError = TABOPERR_NOCOLROW; + else if ( !lcl_Parse( m_xEdFormulaRange->GetText(), *pDoc, nCurTab, + theFormulaCell, theFormulaEnd ) ) + nError = TABOPERR_WRONGFORMULA; + else + { + const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention(); + if (!m_xEdRowCell->GetText().isEmpty()) + { + if (!ConvertSingleRef( *pDoc, m_xEdRowCell->GetText(), nCurTab, + theRowCell, eConv )) + nError = TABOPERR_WRONGROW; + else + { + if (m_xEdColCell->GetText().isEmpty() && + theFormulaCell.Col() != theFormulaEnd.Col()) + nError = TABOPERR_NOCOLFORMULA; + else + eMode = ScTabOpParam::Row; + } + } + if (!m_xEdColCell->GetText().isEmpty()) + { + if (!ConvertSingleRef( *pDoc, m_xEdColCell->GetText(), nCurTab, + theColCell, eConv )) + nError = TABOPERR_WRONGCOL; + else + { + if (eMode == ScTabOpParam::Row) // both + { + eMode = ScTabOpParam::Both; + ConvertSingleRef( *pDoc, m_xEdFormulaRange->GetText(), nCurTab, + theFormulaCell, eConv ); + } + else if (theFormulaCell.Row() != theFormulaEnd.Row()) + nError = TABOPERR_NOROWFORMULA; + else + eMode = ScTabOpParam::Column; + } + } + } + + if (nError) + RaiseError( static_cast<ScTabOpErr>(nError) ); + else + { + ScTabOpParam aOutParam(theFormulaCell, theFormulaEnd, theRowCell, theColCell, eMode); + ScTabOpItem aOutItem( SID_TABOP, &aOutParam ); + + SetDispatcherLock( false ); + SwitchToDocument(); + GetBindings().GetDispatcher()->ExecuteList(SID_TABOP, + SfxCallMode::SLOT | SfxCallMode::RECORD, + { &aOutItem }); + response(RET_OK); + } + } + else if (&rBtn == m_xBtnCancel.get()) + response(RET_CANCEL); +} + +IMPL_LINK( ScTabOpDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void ) +{ + if (&rCtrl == m_xEdFormulaRange.get()) + m_pEdActive = m_xEdFormulaRange.get(); + else if (&rCtrl == m_xEdRowCell.get()) + m_pEdActive = m_xEdRowCell.get(); + else if (&rCtrl == m_xEdColCell.get()) + m_pEdActive = m_xEdColCell.get(); + else + m_pEdActive = nullptr; + + if( m_pEdActive ) + m_pEdActive->SelectAll(); +} + +IMPL_LINK( ScTabOpDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void ) +{ + if (&rCtrl == m_xRBFormulaRange.get()) + m_pEdActive = m_xEdFormulaRange.get(); + else if (&rCtrl == m_xRBRowCell.get()) + m_pEdActive = m_xEdRowCell.get(); + else if (&rCtrl == m_xRBColCell.get()) + m_pEdActive = m_xEdColCell.get(); + else + m_pEdActive = nullptr; + + if( m_pEdActive ) + m_pEdActive->SelectAll(); +} + +IMPL_LINK_NOARG(ScTabOpDlg, LoseEditFocusHdl, formula::RefEdit&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +IMPL_LINK_NOARG(ScTabOpDlg, LoseButtonFocusHdl, formula::RefButton&, void) +{ + bDlgLostFocus = !m_xDialog->has_toplevel_focus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/textdlgs.cxx b/sc/source/ui/miscdlgs/textdlgs.cxx new file mode 100644 index 000000000..40a84a626 --- /dev/null +++ b/sc/source/ui/miscdlgs/textdlgs.cxx @@ -0,0 +1,94 @@ +/* -*- 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 . + */ + +#undef SC_DLLIMPLEMENTATION + +#include <svx/svxids.hrc> +#include <svx/dialogs.hrc> + +#include <editeng/flstitem.hxx> +#include <sfx2/objsh.hxx> +#include <svl/cjkoptions.hxx> + +#include <textdlgs.hxx> +#include <svl/intitem.hxx> +#include <svx/flagsdef.hxx> + +ScCharDlg::ScCharDlg(weld::Window* pParent, const SfxItemSet* pAttr, const SfxObjectShell* pDocShell, bool bDrawText) + : SfxTabDialogController(pParent, "modules/scalc/ui/chardialog.ui", "CharDialog", pAttr) + , rDocShell(*pDocShell) +{ + AddTabPage("font", RID_SVXPAGE_CHAR_NAME); + AddTabPage("fonteffects", RID_SVXPAGE_CHAR_EFFECTS); + AddTabPage("position", RID_SVXPAGE_CHAR_POSITION); + + if (bDrawText) + AddTabPage("background", RID_SVXPAGE_BKG); + else + RemoveTabPage("background"); +} + +void ScCharDlg::PageCreated(const OString& rId, SfxTabPage &rPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "font") + { + SvxFontListItem aItem(*static_cast<const SvxFontListItem*>( + ( rDocShell.GetItem( SID_ATTR_CHAR_FONTLIST) ) ) ); + + aSet.Put (SvxFontListItem( aItem.GetFontList(), SID_ATTR_CHAR_FONTLIST)); + rPage.PageCreated(aSet); + } + else if (rId == "fonteffects") + { + aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP)); + rPage.PageCreated(aSet); + } + else if (rId == "background") + { + aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR))); + rPage.PageCreated(aSet); + } +} + +ScParagraphDlg::ScParagraphDlg(weld::Window* pParent, const SfxItemSet* pAttr) + : SfxTabDialogController(pParent, "modules/scalc/ui/paradialog.ui", "ParagraphDialog", pAttr) +{ + AddTabPage("labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH); + AddTabPage("labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH); + if (SvtCJKOptions::IsAsianTypographyEnabled() ) + AddTabPage("labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN); + else + RemoveTabPage("labelTP_PARA_ASIAN"); + AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR); +} + +void ScParagraphDlg::PageCreated(const OString& rId, SfxTabPage &rPage) +{ + if (rId == "labelTP_TABULATOR") + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + TabulatorDisableFlags const nFlags((TabulatorDisableFlags::TypeMask &~TabulatorDisableFlags::TypeLeft) | + (TabulatorDisableFlags::FillMask &~TabulatorDisableFlags::FillNone)); + aSet.Put(SfxUInt16Item(SID_SVXTABULATORTABPAGE_DISABLEFLAGS, static_cast<sal_uInt16>(nFlags))); + rPage.PageCreated(aSet); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/ui/miscdlgs/warnbox.cxx b/sc/source/ui/miscdlgs/warnbox.cxx new file mode 100644 index 000000000..8bb0a37d1 --- /dev/null +++ b/sc/source/ui/miscdlgs/warnbox.cxx @@ -0,0 +1,52 @@ +/* -*- 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 <warnbox.hxx> + +#include <scmod.hxx> +#include <inputopt.hxx> + +ScReplaceWarnBox::ScReplaceWarnBox(weld::Window* pParent) + : MessageDialogController(pParent, "modules/scalc/ui/checkwarningdialog.ui", + "CheckWarningDialog", "ask") + // By default, the check box is ON, and the user needs to un-check it to + // disable all future warnings. + , m_xWarningOnBox(m_xBuilder->weld_check_button("ask")) +{ + m_xDialog->set_default_response(RET_YES); +} + +short ScReplaceWarnBox::run() +{ + short nRet = RET_YES; + if (SC_MOD()->GetInputOptions().GetReplaceCellsWarn()) + { + nRet = MessageDialogController::run(); + if (!m_xWarningOnBox->get_active()) + { + ScModule* pScMod = SC_MOD(); + ScInputOptions aInputOpt(pScMod->GetInputOptions()); + aInputOpt.SetReplaceCellsWarn(false); + pScMod->SetInputOptions(aInputOpt); + } + } + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |