1
0
Fork 0
libreoffice/sc/source/ui/dbgui/dbnamdlg.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

635 lines
21 KiB
C++

/* -*- 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 <sal/config.h>
#include <cassert>
#include <comphelper/string.hxx>
#include <unotools/charclass.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <o3tl/string_view.hxx>
#include <reffact.hxx>
#include <document.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <rangenam.hxx>
#include <globalnames.hxx>
#include <dbnamdlg.hxx>
#include <dbdocfun.hxx>
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();
}
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<DBSaveData> xSaveObj;
ScDbNameDlg::ScDbNameDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
ScViewData& rViewData)
: ScAnyRefDlgController(pB, pCW, pParent,
u"modules/scalc/ui/definedatabaserangedialog.ui"_ustr, u"DefineDatabaseRangeDialog"_ustr)
, m_rViewData(rViewData)
, rDoc(rViewData.GetDocument())
, bRefInputMode(false)
, aAddrDetails(rDoc.GetAddressConvention(), 0, 0)
, aLocalDbCol(*(rDoc.GetDBCollection()))
, m_xEdName(m_xBuilder->weld_entry_tree_view(u"entrygrid"_ustr, u"entry"_ustr, u"entry-list"_ustr))
, m_xAssignFrame(m_xBuilder->weld_frame(u"RangeFrame"_ustr))
, m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry(u"assign"_ustr)))
, m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button(u"assignrb"_ustr)))
, m_xOptions(m_xBuilder->weld_widget(u"Options"_ustr))
, m_xBtnHeader(m_xBuilder->weld_check_button(u"ContainsColumnLabels"_ustr))
, m_xBtnTotals(m_xBuilder->weld_check_button(u"ContainsTotalsRow"_ustr))
, m_xBtnDoSize(m_xBuilder->weld_check_button(u"InsertOrDeleteCells"_ustr))
, m_xBtnKeepFmt(m_xBuilder->weld_check_button(u"KeepFormatting"_ustr))
, m_xBtnStripData(m_xBuilder->weld_check_button(u"DontSaveImportedData"_ustr))
, m_xFTSource(m_xBuilder->weld_label(u"Source"_ustr))
, m_xFTOperations(m_xBuilder->weld_label(u"Operations"_ustr))
, m_xBtnOk(m_xBuilder->weld_button(u"ok"_ustr))
, m_xBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
, m_xBtnAdd(m_xBuilder->weld_button(u"add"_ustr))
, m_xBtnRemove(m_xBuilder->weld_button(u"delete"_ustr))
, m_xModifyPB(m_xBuilder->weld_button(u"modify"_ustr))
, m_xInvalidFT(m_xBuilder->weld_label(u"invalid"_ustr))
, m_xFrameLabel(m_xAssignFrame->weld_label_widget())
, m_xExpander(m_xBuilder->weld_expander(u"more"_ustr))
{
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<ScDBData> 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<ScDBData> 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<weld::MessageDialog> 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: */