/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { void ERRORBOX(weld::Window* pParent, const OUString& rString) { std::unique_ptr xBox(Application::CreateMessageDialog(pParent, VclMessageType::Warning, VclButtonsType::Ok, rString)); xBox->run(); } class DBSaveData { public: DBSaveData( formula::RefEdit& rEd, weld::CheckButton& rHdr, weld::CheckButton& rTot, weld::CheckButton& rSize, weld::CheckButton& rFmt, weld::CheckButton& rStrip, ScRange& rArea ) : rEdAssign(rEd) , rBtnHeader(rHdr) , rBtnTotals(rTot) , rBtnSize(rSize) , rBtnFormat(rFmt) , rBtnStrip(rStrip) , rCurArea(rArea) , bHeader(false) , bTotals(false) , bSize(false) , bFormat(false) , bStrip(false) , bDirty(false) { } void Save(); void Restore(); private: formula::RefEdit& rEdAssign; weld::CheckButton& rBtnHeader; weld::CheckButton& rBtnTotals; weld::CheckButton& rBtnSize; weld::CheckButton& rBtnFormat; weld::CheckButton& rBtnStrip; ScRange& rCurArea; OUString aStr; ScRange aArea; bool bHeader:1; bool bTotals:1; bool bSize:1; bool bFormat:1; bool bStrip:1; bool bDirty:1; }; } void DBSaveData::Save() { aArea = rCurArea; aStr = rEdAssign.GetText(); bHeader = rBtnHeader.get_active(); bTotals = rBtnTotals.get_active(); bSize = rBtnSize.get_active(); bFormat = rBtnFormat.get_active(); bStrip = rBtnStrip.get_active(); bDirty = true; } void DBSaveData::Restore() { if ( bDirty ) { rCurArea = aArea; rEdAssign.SetText( aStr ); rBtnHeader.set_active ( bHeader ); rBtnTotals.set_active ( bTotals ); rBtnSize.set_active ( bSize ); rBtnFormat.set_active ( bFormat ); rBtnStrip.set_active ( bStrip ); bDirty = false; } } static std::unique_ptr xSaveObj; ScDbNameDlg::ScDbNameDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScViewData& rViewData) : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/definedatabaserangedialog.ui", "DefineDatabaseRangeDialog") , m_rViewData(rViewData) , rDoc(rViewData.GetDocument()) , bRefInputMode(false) , aAddrDetails(rDoc.GetAddressConvention(), 0, 0) , aLocalDbCol(*(rDoc.GetDBCollection())) , m_xEdName(m_xBuilder->weld_entry_tree_view("entrygrid", "entry", "entry-list")) , m_xAssignFrame(m_xBuilder->weld_frame("RangeFrame")) , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("assign"))) , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assignrb"))) , m_xOptions(m_xBuilder->weld_widget("Options")) , m_xBtnHeader(m_xBuilder->weld_check_button("ContainsColumnLabels")) , m_xBtnTotals(m_xBuilder->weld_check_button("ContainsTotalsRow")) , m_xBtnDoSize(m_xBuilder->weld_check_button("InsertOrDeleteCells")) , m_xBtnKeepFmt(m_xBuilder->weld_check_button("KeepFormatting")) , m_xBtnStripData(m_xBuilder->weld_check_button("DontSaveImportedData")) , m_xFTSource(m_xBuilder->weld_label("Source")) , m_xFTOperations(m_xBuilder->weld_label("Operations")) , 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_xModifyPB(m_xBuilder->weld_button("modify")) , m_xInvalidFT(m_xBuilder->weld_label("invalid")) , m_xFrameLabel(m_xAssignFrame->weld_label_widget()) { m_xEdName->set_height_request_by_rows(4); m_xEdAssign->SetReferences(this, m_xFrameLabel.get()); m_xRbAssign->SetReferences(this, m_xEdAssign.get()); aStrAdd = m_xBtnAdd->get_label(); aStrModify = m_xModifyPB->get_label(); aStrInvalid = m_xInvalidFT->get_label(); // so that the strings in the resource can stay with fixed texts: aStrSource = m_xFTSource->get_label(); aStrOperations = m_xFTOperations->get_label(); xSaveObj.reset(new DBSaveData( *m_xEdAssign, *m_xBtnHeader, *m_xBtnTotals, *m_xBtnDoSize, *m_xBtnKeepFmt, *m_xBtnStripData, theCurArea )); Init(); } ScDbNameDlg::~ScDbNameDlg() { xSaveObj.reset(); } void ScDbNameDlg::Init() { m_xBtnHeader->set_active(true); // Default: with column headers m_xBtnTotals->set_active( false ); // Default: without totals row m_xBtnDoSize->set_active(true); m_xBtnKeepFmt->set_active(true); m_xBtnOk->connect_clicked ( LINK( this, ScDbNameDlg, OkBtnHdl ) ); m_xBtnCancel->connect_clicked ( LINK( this, ScDbNameDlg, CancelBtnHdl ) ); m_xBtnAdd->connect_clicked ( LINK( this, ScDbNameDlg, AddBtnHdl ) ); m_xBtnRemove->connect_clicked ( LINK( this, ScDbNameDlg, RemoveBtnHdl ) ); m_xEdName->connect_changed( LINK( this, ScDbNameDlg, NameModifyHdl ) ); m_xEdAssign->SetModifyHdl ( LINK( this, ScDbNameDlg, AssModifyHdl ) ); UpdateNames(); OUString theAreaStr; SCCOL nStartCol = 0; SCROW nStartRow = 0; SCTAB nStartTab = 0; SCCOL nEndCol = 0; SCROW nEndRow = 0; SCTAB nEndTab = 0; ScDBCollection* pDBColl = rDoc.GetDBCollection(); m_rViewData.GetSimpleArea( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ); theCurArea = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab); theAreaStr = theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aAddrDetails); if ( pDBColl ) { // determine if the defined DB area has been marked: ScDBData* pDBData = pDBColl->GetDBAtCursor( nStartCol, nStartRow, nStartTab, ScDBDataPortion::TOP_LEFT ); if ( pDBData ) { ScAddress& rStart = theCurArea.aStart; ScAddress& rEnd = theCurArea.aEnd; SCCOL nCol1; SCCOL nCol2; SCROW nRow1; SCROW nRow2; SCTAB nTab; pDBData->GetArea( nTab, nCol1, nRow1, nCol2, nRow2 ); if ( (rStart.Tab() == nTab) && (rStart.Col() == nCol1) && (rStart.Row() == nRow1) && (rEnd.Col() == nCol2) && (rEnd.Row() == nRow2 ) ) { OUString aDBName = pDBData->GetName(); if ( aDBName != STR_DB_LOCAL_NONAME ) m_xEdName->set_entry_text(aDBName); m_xBtnHeader->set_active( pDBData->HasHeader() ); m_xBtnTotals->set_active( pDBData->HasTotals() ); m_xBtnDoSize->set_active( pDBData->IsDoSize() ); m_xBtnKeepFmt->set_active( pDBData->IsKeepFmt() ); m_xBtnStripData->set_active( pDBData->IsStripData() ); SetInfoStrings( pDBData ); } } } m_xEdAssign->SetText( theAreaStr ); m_xEdName->grab_focus(); bSaved = true; xSaveObj->Save(); NameModifyHdl( *m_xEdName ); bInvalid = false; } void ScDbNameDlg::SetInfoStrings( const ScDBData* pDBData ) { OUStringBuffer aBuf(aStrSource); if (pDBData) { aBuf.append(" " + pDBData->GetSourceString()); } m_xFTSource->set_label(aBuf.makeStringAndClear()); aBuf.append(aStrOperations); if (pDBData) { aBuf.append(" " + pDBData->GetOperations()); } m_xFTOperations->set_label(aBuf.makeStringAndClear()); } // Transfer of a table area selected with the mouse, which is then displayed // as a new selection in the reference window. void ScDbNameDlg::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(theCurArea.Format(rDocP, ScRefFlags::RANGE_ABS_3D, aAddrDetails)); m_xEdAssign->SetRefString( aRefStr ); m_xOptions->set_sensitive(true); m_xBtnAdd->set_sensitive(true); bSaved = true; xSaveObj->Save(); } void ScDbNameDlg::Close() { DoClose( ScDbNameDlgWrapper::GetChildWindowId() ); } void ScDbNameDlg::SetActive() { m_xEdAssign->GrabFocus(); // No NameModifyHdl, because otherwise areas can not be changed // (the old content would be displayed again after the reference selection is pulled) // (the selected DB name has not changed either) RefInputDone(); } void ScDbNameDlg::UpdateNames() { typedef ScDBCollection::NamedDBs DBsType; const DBsType& rDBs = aLocalDbCol.getNamedDBs(); m_xEdName->freeze(); m_xEdName->clear(); m_xEdAssign->SetText( OUString() ); if (!rDBs.empty()) { for (const auto& rxDB : rDBs) m_xEdName->append_text(rxDB->GetName()); } else { m_xBtnAdd->set_label( aStrAdd ); m_xBtnAdd->set_sensitive(false); m_xBtnRemove->set_sensitive(false); } m_xEdName->thaw(); } void ScDbNameDlg::UpdateDBData( const OUString& rStrName ) { const ScDBData* pData = aLocalDbCol.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rStrName)); if ( pData ) { SCCOL nColStart = 0; SCROW nRowStart = 0; SCCOL nColEnd = 0; SCROW nRowEnd = 0; SCTAB nTab = 0; pData->GetArea( nTab, nColStart, nRowStart, nColEnd, nRowEnd ); theCurArea = ScRange( ScAddress( nColStart, nRowStart, nTab ), ScAddress( nColEnd, nRowEnd, nTab ) ); OUString theArea(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aAddrDetails)); m_xEdAssign->SetText( theArea ); m_xBtnAdd->set_label( aStrModify ); m_xBtnHeader->set_active( pData->HasHeader() ); m_xBtnTotals->set_active( pData->HasTotals() ); m_xBtnDoSize->set_active( pData->IsDoSize() ); m_xBtnKeepFmt->set_active( pData->IsKeepFmt() ); m_xBtnStripData->set_active( pData->IsStripData() ); SetInfoStrings( pData ); } m_xBtnAdd->set_label( aStrModify ); m_xBtnAdd->set_sensitive(true); m_xBtnRemove->set_sensitive(true); m_xOptions->set_sensitive(true); } bool ScDbNameDlg::IsRefInputMode() const { return bRefInputMode; } // Handler: IMPL_LINK_NOARG(ScDbNameDlg, OkBtnHdl, weld::Button&, void) { bInvalid = false; AddBtnHdl(*m_xBtnAdd); // Pass the changes and the remove list to the view: both are // transferred as a reference only, so that no dead memory can // be created at this point: if (!bInvalid) { ScDBDocFunc aFunc(*m_rViewData.GetDocShell()); aFunc.ModifyAllDBData(aLocalDbCol, aRemoveList); response(RET_OK); } } IMPL_LINK_NOARG(ScDbNameDlg, CancelBtnHdl, weld::Button&, void) { response(RET_CANCEL); } IMPL_LINK_NOARG(ScDbNameDlg, AddBtnHdl, weld::Button&, void) { OUString aNewName = comphelper::string::strip(m_xEdName->get_active_text(), ' '); OUString aNewArea = m_xEdAssign->GetText(); if ( aNewName.isEmpty() || aNewArea.isEmpty() ) return; if (ScRangeData::IsNameValid(aNewName, rDoc) == ScRangeData::IsNameValidType::NAME_VALID && aNewName != STR_DB_LOCAL_NONAME) { // because editing can be done now, parsing is needed first ScRange aTmpRange; OUString aText = m_xEdAssign->GetText(); if ( aTmpRange.ParseAny( aText, rDoc, aAddrDetails ) & ScRefFlags::VALID ) { theCurArea = aTmpRange; ScAddress aStart = theCurArea.aStart; ScAddress aEnd = theCurArea.aEnd; ScDBData* pOldEntry = aLocalDbCol.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aNewName)); if (pOldEntry) { // modify area pOldEntry->MoveTo( aStart.Tab(), aStart.Col(), aStart.Row(), aEnd.Col(), aEnd.Row() ); pOldEntry->SetByRow( true ); pOldEntry->SetHeader( m_xBtnHeader->get_active() ); pOldEntry->SetTotals( m_xBtnTotals->get_active() ); pOldEntry->SetDoSize( m_xBtnDoSize->get_active() ); pOldEntry->SetKeepFmt( m_xBtnKeepFmt->get_active() ); pOldEntry->SetStripData( m_xBtnStripData->get_active() ); } else { // insert new area std::unique_ptr pNewEntry(new ScDBData( aNewName, aStart.Tab(), aStart.Col(), aStart.Row(), aEnd.Col(), aEnd.Row(), true, m_xBtnHeader->get_active(), m_xBtnTotals->get_active() )); pNewEntry->SetDoSize( m_xBtnDoSize->get_active() ); pNewEntry->SetKeepFmt( m_xBtnKeepFmt->get_active() ); pNewEntry->SetStripData( m_xBtnStripData->get_active() ); bool ins = aLocalDbCol.getNamedDBs().insert(std::move(pNewEntry)); assert(ins); (void)ins; } UpdateNames(); m_xEdName->set_entry_text( OUString() ); m_xEdName->grab_focus(); m_xBtnAdd->set_label( aStrAdd ); m_xBtnAdd->set_sensitive(false); m_xBtnRemove->set_sensitive(false); m_xEdAssign->SetText( OUString() ); m_xBtnHeader->set_active(true); // Default: with column headers m_xBtnTotals->set_active( false ); // Default: without totals row m_xBtnDoSize->set_active( false ); m_xBtnKeepFmt->set_active( false ); m_xBtnStripData->set_active( false ); SetInfoStrings( nullptr ); // empty theCurArea = ScRange(); bSaved = true; xSaveObj->Save(); NameModifyHdl( *m_xEdName ); } else { ERRORBOX(m_xDialog.get(), aStrInvalid); m_xEdAssign->SelectAll(); m_xEdAssign->GrabFocus(); bInvalid = true; } } else { ERRORBOX(m_xDialog.get(), ScResId(STR_INVALIDNAME)); m_xEdName->select_entry_region(0, -1); m_xEdName->grab_focus(); bInvalid = true; } } namespace { class FindByName { const OUString& mrName; public: explicit FindByName(const OUString& rName) : mrName(rName) {} bool operator() (std::unique_ptr const& p) const { return p->GetName() == mrName; } }; } IMPL_LINK_NOARG(ScDbNameDlg, RemoveBtnHdl, weld::Button&, void) { OUString aStrEntry = m_xEdName->get_active_text(); ScDBCollection::NamedDBs& rDBs = aLocalDbCol.getNamedDBs(); ScDBCollection::NamedDBs::iterator itr = ::std::find_if(rDBs.begin(), rDBs.end(), FindByName(aStrEntry)); if (itr == rDBs.end()) return; OUString aStrDelMsg = ScResId( STR_QUERY_DELENTRY ); OUString sMsg{ o3tl::getToken(aStrDelMsg, 0, '#') + aStrEntry + o3tl::getToken(aStrDelMsg, 1, '#') }; std::unique_ptr xQueryBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Question, VclButtonsType::YesNo, sMsg)); xQueryBox->set_default_response(RET_YES); if (RET_YES != xQueryBox->run()) return; SCTAB nTab; SCCOL nColStart, nColEnd; SCROW nRowStart, nRowEnd; (*itr)->GetArea( nTab, nColStart, nRowStart, nColEnd, nRowEnd ); aRemoveList.emplace_back( ScAddress( nColStart, nRowStart, nTab ), ScAddress( nColEnd, nRowEnd, nTab ) ); rDBs.erase(itr); UpdateNames(); m_xEdName->set_entry_text( OUString() ); m_xEdName->grab_focus(); m_xBtnAdd->set_label( aStrAdd ); m_xBtnAdd->set_sensitive(false); m_xBtnRemove->set_sensitive(false); m_xEdAssign->SetText( OUString() ); theCurArea = ScRange(); m_xBtnHeader->set_active(true); // Default: with column headers m_xBtnTotals->set_active( false ); // Default: without totals row m_xBtnDoSize->set_active( false ); m_xBtnKeepFmt->set_active( false ); m_xBtnStripData->set_active( false ); SetInfoStrings( nullptr ); // empty bSaved=false; xSaveObj->Restore(); NameModifyHdl( *m_xEdName ); } IMPL_LINK_NOARG(ScDbNameDlg, NameModifyHdl, weld::ComboBox&, void) { OUString theName = m_xEdName->get_active_text(); bool bNameFound = m_xEdName->find_text(theName) != -1; if ( theName.isEmpty() ) { if (m_xBtnAdd->get_label() != aStrAdd) m_xBtnAdd->set_label( aStrAdd ); m_xBtnAdd->set_sensitive(false); m_xBtnRemove->set_sensitive(false); m_xAssignFrame->set_sensitive(false); m_xOptions->set_sensitive(false); //bSaved=sal_False; //xSaveObj->Restore(); //@BugID 54702 enable/disable in the base class only //SFX_APPWINDOW->Disable(sal_False); //! general method in ScAnyRefDlg bRefInputMode = false; } else { if ( bNameFound ) { if (m_xBtnAdd->get_label() != aStrModify) m_xBtnAdd->set_label( aStrModify ); if(!bSaved) { bSaved = true; xSaveObj->Save(); } UpdateDBData( theName ); } else { if (m_xBtnAdd->get_label() != aStrAdd) m_xBtnAdd->set_label( aStrAdd ); bSaved=false; xSaveObj->Restore(); if ( !m_xEdAssign->GetText().isEmpty() ) { m_xBtnAdd->set_sensitive(true); m_xOptions->set_sensitive(true); } else { m_xBtnAdd->set_sensitive(false); m_xOptions->set_sensitive(false); } m_xBtnRemove->set_sensitive(false); } m_xAssignFrame->set_sensitive(true); //@BugID 54702 enable/disable in the base class only //SFX_APPWINDOW->set_sensitive(true); bRefInputMode = true; } } IMPL_LINK_NOARG(ScDbNameDlg, AssModifyHdl, formula::RefEdit&, void) { // parse here for Save(), etc. ScRange aTmpRange; OUString aText = m_xEdAssign->GetText(); if ( aTmpRange.ParseAny( aText, rDoc, aAddrDetails ) & ScRefFlags::VALID ) theCurArea = aTmpRange; if (!aText.isEmpty() && !m_xEdName->get_active_text().isEmpty()) { m_xBtnAdd->set_sensitive(true); m_xBtnHeader->set_sensitive(true); m_xBtnTotals->set_sensitive(true); m_xBtnDoSize->set_sensitive(true); m_xBtnKeepFmt->set_sensitive(true); m_xBtnStripData->set_sensitive(true); m_xFTSource->set_sensitive(true); m_xFTOperations->set_sensitive(true); } else { m_xBtnAdd->set_sensitive(false); m_xBtnHeader->set_sensitive(false); m_xBtnTotals->set_sensitive(false); m_xBtnDoSize->set_sensitive(false); m_xBtnKeepFmt->set_sensitive(false); m_xBtnStripData->set_sensitive(false); m_xFTSource->set_sensitive(false); m_xFTOperations->set_sensitive(false); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */