summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/view/dbfunc.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sc/source/ui/view/dbfunc.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--sc/source/ui/view/dbfunc.cxx466
1 files changed, 466 insertions, 0 deletions
diff --git a/sc/source/ui/view/dbfunc.cxx b/sc/source/ui/view/dbfunc.cxx
new file mode 100644
index 0000000000..8f1b9e8fc5
--- /dev/null
+++ b/sc/source/ui/view/dbfunc.cxx
@@ -0,0 +1,466 @@
+/* -*- 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/bindings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <dbfunc.hxx>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <sc.hrc>
+#include <undodat.hxx>
+#include <dbdata.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <dbdocfun.hxx>
+#include <editable.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <tabvwsh.hxx>
+#include <sortparam.hxx>
+
+ScDBFunc::ScDBFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
+ ScViewFunc( pParent, rDocSh, pViewShell )
+{
+}
+
+ScDBFunc::~ScDBFunc()
+{
+}
+
+// auxiliary functions
+
+void ScDBFunc::GotoDBArea( const OUString& rDBName )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDBCollection* pDBCol = rDoc.GetDBCollection();
+ ScDBData* pData = pDBCol->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
+ if (!pData)
+ return;
+
+ SCTAB nTab = 0;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+
+ pData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ SetTabNo( nTab );
+
+ MoveCursorAbs( nStartCol, nStartRow, SC_FOLLOW_JUMP,
+ false, false ); // bShift,bControl
+ DoneBlockMode();
+ InitBlockMode( nStartCol, nStartRow, nTab );
+ MarkCursor( nEndCol, nEndRow, nTab );
+ SelectionChanged();
+}
+
+// search current datarange for sort / filter
+
+ScDBData* ScDBFunc::GetDBData( bool bMark, ScGetDBMode eMode, ScGetDBSelection eSel )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDBData* pData = nullptr;
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
+ if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
+ {
+ bool bShrinkColumnsOnly = false;
+ if (eSel == ScGetDBSelection::RowDown)
+ {
+ // Don't alter row range, additional rows may have been selected on
+ // purpose to append data, or to have a fake header row.
+ bShrinkColumnsOnly = true;
+ // Select further rows only if only one row or a portion thereof is
+ // selected.
+ if (aRange.aStart.Row() != aRange.aEnd.Row())
+ {
+ // If an area is selected shrink that to the actual used
+ // columns, don't draw filter buttons for empty columns.
+ eSel = ScGetDBSelection::ShrinkToUsedData;
+ }
+ else if (aRange.aStart.Col() == aRange.aEnd.Col())
+ {
+ // One cell only, if it is not marked obtain entire used data
+ // area.
+ const ScMarkData& rMarkData = GetViewData().GetMarkData();
+ if (!(rMarkData.IsMarked() || rMarkData.IsMultiMarked()))
+ eSel = ScGetDBSelection::Keep;
+ }
+ }
+ switch (eSel)
+ {
+ case ScGetDBSelection::ShrinkToUsedData:
+ case ScGetDBSelection::RowDown:
+ {
+ // Shrink the selection to actual used area.
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
+ SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
+ bool bShrunk;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aRange.aStart.Tab(),
+ nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly);
+ if (bShrunk)
+ {
+ aRange.aStart.SetCol(nCol1);
+ aRange.aEnd.SetCol(nCol2);
+ aRange.aStart.SetRow(nRow1);
+ aRange.aEnd.SetRow(nRow2);
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ pData = pDocSh->GetDBData( aRange, eMode, eSel );
+ }
+ else if ( eMode != SC_DB_OLD )
+ pData = pDocSh->GetDBData(
+ ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(),
+ GetViewData().GetTabNo() ),
+ eMode, ScGetDBSelection::Keep );
+
+ if (!pData)
+ return nullptr;
+
+ if (bMark)
+ {
+ ScRange aFound;
+ pData->GetArea(aFound);
+ MarkRange( aFound, false );
+ }
+ return pData;
+}
+
+ScDBData* ScDBFunc::GetAnonymousDBData()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ return nullptr;
+
+ // Expand to used data area if not explicitly marked.
+ const ScMarkData& rMarkData = GetViewData().GetMarkData();
+ if (!rMarkData.IsMarked() && !rMarkData.IsMultiMarked())
+ {
+ SCCOL nCol1 = aRange.aStart.Col();
+ SCCOL nCol2 = aRange.aEnd.Col();
+ SCROW nRow1 = aRange.aStart.Row();
+ SCROW nRow2 = aRange.aEnd.Row();
+ pDocSh->GetDocument().GetDataArea(aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2, false, false);
+ aRange.aStart.SetCol(nCol1);
+ aRange.aStart.SetRow(nRow1);
+ aRange.aEnd.SetCol(nCol2);
+ aRange.aEnd.SetRow(nRow2);
+ }
+
+ return pDocSh->GetAnonymousDBData(aRange);
+}
+
+// main functions
+
+// Sort
+
+void ScDBFunc::UISort( const ScSortParam& rSortParam )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
+ rSortParam.nCol2, rSortParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "Sort: no DBData" );
+ return;
+ }
+
+ ScSubTotalParam aSubTotalParam;
+ pDBData->GetSubTotalParam( aSubTotalParam );
+ if (aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly)
+ {
+ // repeat subtotals, with new sortorder
+
+ DoSubTotals( aSubTotalParam, true/*bRecord*/, &rSortParam );
+ }
+ else
+ {
+ Sort( rSortParam ); // just sort
+ }
+}
+
+void ScDBFunc::Sort( const ScSortParam& rSortParam, bool bRecord, bool bPaint )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBDocFunc aDBDocFunc( *pDocSh );
+ bool bSuccess = aDBDocFunc.Sort( nTab, rSortParam, bRecord, bPaint, false );
+ if ( bSuccess && !rSortParam.bInplace )
+ {
+ // mark target
+ ScRange aDestRange( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab,
+ rSortParam.nDestCol + rSortParam.nCol2 - rSortParam.nCol1,
+ rSortParam.nDestRow + rSortParam.nRow2 - rSortParam.nRow1,
+ rSortParam.nDestTab );
+ MarkRange( aDestRange );
+ }
+
+ ResetAutoSpellForContentChange();
+}
+
+// filters
+
+void ScDBFunc::Query( const ScQueryParam& rQueryParam, const ScRange* pAdvSource, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBDocFunc aDBDocFunc( *pDocSh );
+ bool bSuccess = aDBDocFunc.Query( nTab, rQueryParam, pAdvSource, bRecord, false );
+
+ if (!bSuccess)
+ return;
+
+ bool bCopy = !rQueryParam.bInplace;
+ if (bCopy)
+ {
+ // mark target range (data base range has been set up if applicable)
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDBData* pDestData = rDoc.GetDBAtCursor(
+ rQueryParam.nDestCol, rQueryParam.nDestRow,
+ rQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDestData)
+ {
+ ScRange aDestRange;
+ pDestData->GetArea(aDestRange);
+ MarkRange( aDestRange );
+ }
+ }
+
+ if (!bCopy)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(),
+ false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+ UpdateScrollBars(ROW_HEADER);
+ SelectionChanged(); // for attribute states (filtered rows are ignored)
+ }
+
+ GetViewData().GetBindings().Invalidate( SID_UNFILTER );
+}
+
+// autofilter-buttons show / hide
+
+void ScDBFunc::ToggleAutoFilter()
+{
+ ScViewData* pViewData = &GetViewData();
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+
+ ScQueryParam aParam;
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScDBData* pDBData = GetDBData(false, SC_DB_AUTOFILTER, ScGetDBSelection::RowDown);
+
+ pDBData->SetByRow( true ); //! undo, retrieve beforehand ??
+ pDBData->GetQueryParam( aParam );
+
+ SCCOL nCol;
+ SCROW nRow = aParam.nRow1;
+ SCTAB nTab = pViewData->GetTabNo();
+ ScMF nFlag;
+ bool bHasAuto = true;
+ bool bHeader = pDBData->HasHeader();
+
+ //! instead retrieve from DB-range?
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAuto; nCol++)
+ {
+ nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
+
+ if ( !(nFlag & ScMF::Auto) )
+ bHasAuto = false;
+ }
+
+ if (bHasAuto) // remove
+ {
+ // hide filter buttons
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
+ {
+ nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag & ~ScMF::Auto ) );
+ }
+
+ // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
+
+ OUString aUndo = ScResId( STR_UNDO_QUERY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, pViewData->GetViewShell()->GetViewShellId() );
+
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>( pDocSh, aRange, pDBData->GetName(), false ) );
+
+ pDBData->SetAutoFilter(false);
+
+ // remove filter (incl. Paint / Undo)
+
+ SCSIZE nEC = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ aParam.GetEntry(i).bDoQuery = false;
+ aParam.bDuplicate = true;
+ Query( aParam, nullptr, true );
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+
+ ScDBFunc::ModifiedAutoFilter(pDocSh);
+ }
+ else // show filter buttons
+ {
+ if ( !rDoc.IsBlockEmpty( aParam.nCol1, aParam.nRow1,
+ aParam.nCol2, aParam.nRow2, nTab ) )
+ {
+ if (!bHeader)
+ {
+ std::shared_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pViewData->GetDialogParent(),
+ VclMessageType::Question,
+ VclButtonsType::YesNo, ScResId(STR_MSSG_MAKEAUTOFILTER_0))); // header from first row?
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); // "StarCalc"
+ xBox->set_default_response(RET_YES);
+ xBox->SetInstallLOKNotifierHdl(LINK(this, ScDBFunc, InstallLOKNotifierHdl));
+ xBox->runAsync(xBox, [pDocSh, pViewData, pDBData, nCol, nRow, nTab, aParam] (sal_Int32 nResult) {
+ if (nResult == RET_YES)
+ {
+ pDBData->SetHeader( true ); //! Undo ??
+ }
+
+ ApplyAutoFilter(pDocSh, pViewData, pDBData, nCol, nRow, nTab, aParam);
+ });
+ }
+ else
+ ApplyAutoFilter(pDocSh, pViewData, pDBData, nCol, nRow, nTab, aParam);
+ }
+ else
+ {
+ std::shared_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pViewData->GetDialogParent(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_ERR_AUTOFILTER)));
+ xErrorBox->SetInstallLOKNotifierHdl(LINK(this, ScDBFunc, InstallLOKNotifierHdl));
+ xErrorBox->runAsync(xErrorBox, [] (sal_Int32) {});
+ }
+ }
+}
+
+IMPL_STATIC_LINK_NOARG(ScDBFunc, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
+{
+ return GetpApp();
+}
+
+void ScDBFunc::ApplyAutoFilter(ScDocShell* pDocSh, ScViewData* pViewData, ScDBData* pDBData,
+ SCCOL nCol, SCROW nRow, SCTAB nTab, ScQueryParam aParam)
+{
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>(pDocSh, aRange, pDBData->GetName(), true));
+
+ pDBData->SetAutoFilter(true);
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
+ {
+ ScMF nFlag = rDoc.GetAttr(nCol, nRow, nTab, ATTR_MERGE_FLAG)->GetValue();
+ rDoc.ApplyAttr(nCol, nRow, nTab, ScMergeFlagAttr(nFlag | ScMF::Auto));
+ }
+ pDocSh->PostPaint(ScRange(aParam.nCol1, nRow, nTab, aParam.nCol2, nRow, nTab),
+ PaintPartFlags::Grid);
+
+ ScDBFunc::ModifiedAutoFilter(pDocSh);
+}
+
+void ScDBFunc::ModifiedAutoFilter(ScDocShell* pDocSh)
+{
+ ScDocShellModificator aModificator(*pDocSh);
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+ pBindings->Invalidate(SID_AUTO_FILTER);
+ pBindings->Invalidate(SID_AUTOFILTER_HIDE);
+}
+
+// just hide, no data change
+
+void ScDBFunc::HideAutoFilter()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ ScDBData* pDBData = GetDBData( false );
+
+ SCTAB nTab;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ pDBData->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
+
+ for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
+ {
+ ScMF nFlag = rDoc.GetAttr( nCol, nRow1, nTab, ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, nRow1, nTab, ScMergeFlagAttr( nFlag & ~ScMF::Auto ) );
+ }
+
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>( pDocSh, aRange, pDBData->GetName(), false ) );
+
+ pDBData->SetAutoFilter(false);
+
+ pDocSh->PostPaint(ScRange(nCol1, nRow1, nTab, nCol2, nRow1, nTab), PaintPartFlags::Grid );
+ aModificator.SetDocumentModified();
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_AUTO_FILTER );
+ rBindings.Invalidate( SID_AUTOFILTER_HIDE );
+}
+
+// Re-Import
+
+bool ScDBFunc::ImportData( const ScImportParam& rParam )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScEditableTester aTester( rDoc, GetViewData().GetTabNo(), rParam.nCol1,rParam.nRow1,
+ rParam.nCol2,rParam.nRow2 );
+ if ( !aTester.IsEditable() )
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ ScDBDocFunc aDBDocFunc( *GetViewData().GetDocShell() );
+ return aDBDocFunc.DoImport( GetViewData().GetTabNo(), rParam, nullptr );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */