1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <sfx2/bindings.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <unotools/charclass.hxx>
25 #include <osl/diagnose.h>
31 #include <undodat.hxx>
33 #include <globstr.hrc>
34 #include <scresid.hxx>
36 #include <dbdocfun.hxx>
37 #include <editable.hxx>
38 #include <queryentry.hxx>
39 #include <markdata.hxx>
40 #include <tabvwsh.hxx>
41 #include <sortparam.hxx>
43 ScDBFunc::ScDBFunc( vcl::Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
44 ScViewFunc( pParent
, rDocSh
, pViewShell
)
52 // auxiliary functions
54 void ScDBFunc::GotoDBArea( const OUString
& rDBName
)
56 ScDocument
& rDoc
= GetViewData().GetDocument();
57 ScDBCollection
* pDBCol
= rDoc
.GetDBCollection();
58 ScDBData
* pData
= pDBCol
->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName
));
68 pData
->GetArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
71 MoveCursorAbs( nStartCol
, nStartRow
, SC_FOLLOW_JUMP
,
72 false, false ); // bShift,bControl
74 InitBlockMode( nStartCol
, nStartRow
, nTab
);
75 MarkCursor( nEndCol
, nEndRow
, nTab
);
79 // search current datarange for sort / filter
81 ScDBData
* ScDBFunc::GetDBData( bool bMark
, ScGetDBMode eMode
, ScGetDBSelection eSel
)
83 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
84 ScDBData
* pData
= nullptr;
86 ScMarkType eMarkType
= GetViewData().GetSimpleArea(aRange
);
87 if ( eMarkType
== SC_MARK_SIMPLE
|| eMarkType
== SC_MARK_SIMPLE_FILTERED
)
89 bool bShrinkColumnsOnly
= false;
90 if (eSel
== ScGetDBSelection::RowDown
)
92 // Don't alter row range, additional rows may have been selected on
93 // purpose to append data, or to have a fake header row.
94 bShrinkColumnsOnly
= true;
95 // Select further rows only if only one row or a portion thereof is
97 if (aRange
.aStart
.Row() != aRange
.aEnd
.Row())
99 // If an area is selected shrink that to the actual used
100 // columns, don't draw filter buttons for empty columns.
101 eSel
= ScGetDBSelection::ShrinkToUsedData
;
103 else if (aRange
.aStart
.Col() == aRange
.aEnd
.Col())
105 // One cell only, if it is not marked obtain entire used data
107 const ScMarkData
& rMarkData
= GetViewData().GetMarkData();
108 if (!(rMarkData
.IsMarked() || rMarkData
.IsMultiMarked()))
109 eSel
= ScGetDBSelection::Keep
;
114 case ScGetDBSelection::ShrinkToUsedData
:
115 case ScGetDBSelection::RowDown
:
117 // Shrink the selection to actual used area.
118 ScDocument
& rDoc
= pDocSh
->GetDocument();
119 SCCOL nCol1
= aRange
.aStart
.Col(), nCol2
= aRange
.aEnd
.Col();
120 SCROW nRow1
= aRange
.aStart
.Row(), nRow2
= aRange
.aEnd
.Row();
122 rDoc
.ShrinkToUsedDataArea( bShrunk
, aRange
.aStart
.Tab(),
123 nCol1
, nRow1
, nCol2
, nRow2
, bShrinkColumnsOnly
);
126 aRange
.aStart
.SetCol(nCol1
);
127 aRange
.aEnd
.SetCol(nCol2
);
128 aRange
.aStart
.SetRow(nRow1
);
129 aRange
.aEnd
.SetRow(nRow2
);
136 pData
= pDocSh
->GetDBData( aRange
, eMode
, eSel
);
138 else if ( eMode
!= SC_DB_OLD
)
139 pData
= pDocSh
->GetDBData(
140 ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(),
141 GetViewData().GetTabNo() ),
142 eMode
, ScGetDBSelection::Keep
);
150 pData
->GetArea(aFound
);
151 MarkRange( aFound
, false );
156 ScDBData
* ScDBFunc::GetAnonymousDBData()
158 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
160 ScMarkType eMarkType
= GetViewData().GetSimpleArea(aRange
);
161 if (eMarkType
!= SC_MARK_SIMPLE
&& eMarkType
!= SC_MARK_SIMPLE_FILTERED
)
164 // Expand to used data area if not explicitly marked.
165 const ScMarkData
& rMarkData
= GetViewData().GetMarkData();
166 if (!rMarkData
.IsMarked() && !rMarkData
.IsMultiMarked())
168 SCCOL nCol1
= aRange
.aStart
.Col();
169 SCCOL nCol2
= aRange
.aEnd
.Col();
170 SCROW nRow1
= aRange
.aStart
.Row();
171 SCROW nRow2
= aRange
.aEnd
.Row();
172 pDocSh
->GetDocument().GetDataArea(aRange
.aStart
.Tab(), nCol1
, nRow1
, nCol2
, nRow2
, false, false);
173 aRange
.aStart
.SetCol(nCol1
);
174 aRange
.aStart
.SetRow(nRow1
);
175 aRange
.aEnd
.SetCol(nCol2
);
176 aRange
.aEnd
.SetRow(nRow2
);
179 return pDocSh
->GetAnonymousDBData(aRange
);
186 void ScDBFunc::UISort( const ScSortParam
& rSortParam
)
188 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
189 ScDocument
& rDoc
= pDocSh
->GetDocument();
190 SCTAB nTab
= GetViewData().GetTabNo();
191 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
192 rSortParam
.nCol2
, rSortParam
.nRow2
);
195 OSL_FAIL( "Sort: no DBData" );
199 ScSubTotalParam aSubTotalParam
;
200 pDBData
->GetSubTotalParam( aSubTotalParam
);
201 if (aSubTotalParam
.aGroups
[0].bActive
&& !aSubTotalParam
.bRemoveOnly
)
203 // repeat subtotals, with new sortorder
205 DoSubTotals( aSubTotalParam
, true/*bRecord*/, &rSortParam
);
209 Sort( rSortParam
); // just sort
213 void ScDBFunc::Sort( const ScSortParam
& rSortParam
, bool bRecord
, bool bPaint
)
215 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
216 SCTAB nTab
= GetViewData().GetTabNo();
217 ScDBDocFunc
aDBDocFunc( *pDocSh
);
218 bool bSuccess
= aDBDocFunc
.Sort( nTab
, rSortParam
, bRecord
, bPaint
, false );
219 if ( bSuccess
&& !rSortParam
.bInplace
)
222 ScRange
aDestRange( rSortParam
.nDestCol
, rSortParam
.nDestRow
, rSortParam
.nDestTab
,
223 rSortParam
.nDestCol
+ rSortParam
.nCol2
- rSortParam
.nCol1
,
224 rSortParam
.nDestRow
+ rSortParam
.nRow2
- rSortParam
.nRow1
,
225 rSortParam
.nDestTab
);
226 MarkRange( aDestRange
);
229 ResetAutoSpellForContentChange();
234 void ScDBFunc::Query( const ScQueryParam
& rQueryParam
, const ScRange
* pAdvSource
, bool bRecord
)
236 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
237 SCTAB nTab
= GetViewData().GetTabNo();
238 ScDBDocFunc
aDBDocFunc( *pDocSh
);
239 bool bSuccess
= aDBDocFunc
.Query( nTab
, rQueryParam
, pAdvSource
, bRecord
, false );
244 bool bCopy
= !rQueryParam
.bInplace
;
247 // mark target range (data base range has been set up if applicable)
248 ScDocument
& rDoc
= pDocSh
->GetDocument();
249 ScDBData
* pDestData
= rDoc
.GetDBAtCursor(
250 rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
251 rQueryParam
.nDestTab
, ScDBDataPortion::TOP_LEFT
);
255 pDestData
->GetArea(aDestRange
);
256 MarkRange( aDestRange
);
262 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
263 GetViewData().GetViewShell(),
264 false /* bColumns */, true /* bRows */,
265 false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
266 false /* bGroups */, nTab
);
267 UpdateScrollBars(ROW_HEADER
);
268 SelectionChanged(); // for attribute states (filtered rows are ignored)
271 GetViewData().GetBindings().Invalidate( SID_UNFILTER
);
274 // autofilter-buttons show / hide
276 void ScDBFunc::ToggleAutoFilter()
278 ScViewData
* pViewData
= &GetViewData();
279 ScDocShell
* pDocSh
= pViewData
->GetDocShell();
282 ScDocument
& rDoc
= pViewData
->GetDocument();
283 ScDBData
* pDBData
= GetDBData(false, SC_DB_AUTOFILTER
, ScGetDBSelection::RowDown
);
285 pDBData
->SetByRow( true ); //! undo, retrieve beforehand ??
286 pDBData
->GetQueryParam( aParam
);
289 SCROW nRow
= aParam
.nRow1
;
290 SCTAB nTab
= pViewData
->GetTabNo();
292 bool bHasAuto
= true;
293 bool bHeader
= pDBData
->HasHeader();
295 //! instead retrieve from DB-range?
297 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
&& bHasAuto
; nCol
++)
299 nFlag
= rDoc
.GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
301 if ( !(nFlag
& ScMF::Auto
) )
305 if (bHasAuto
) // remove
307 // hide filter buttons
309 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
311 nFlag
= rDoc
.GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
312 rDoc
.ApplyAttr( nCol
, nRow
, nTab
, ScMergeFlagAttr( nFlag
& ~ScMF::Auto
) );
315 // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
317 OUString aUndo
= ScResId( STR_UNDO_QUERY
);
318 pDocSh
->GetUndoManager()->EnterListAction( aUndo
, aUndo
, 0, pViewData
->GetViewShell()->GetViewShellId() );
321 pDBData
->GetArea( aRange
);
322 pDocSh
->GetUndoManager()->AddUndoAction(
323 std::make_unique
<ScUndoAutoFilter
>( pDocSh
, aRange
, pDBData
->GetName(), false ) );
325 pDBData
->SetAutoFilter(false);
327 // remove filter (incl. Paint / Undo)
329 SCSIZE nEC
= aParam
.GetEntryCount();
330 for (SCSIZE i
=0; i
<nEC
; i
++)
331 aParam
.GetEntry(i
).bDoQuery
= false;
332 aParam
.bDuplicate
= true;
333 Query( aParam
, nullptr, true );
335 pDocSh
->GetUndoManager()->LeaveListAction();
337 ScDBFunc::ModifiedAutoFilter(pDocSh
);
339 else // show filter buttons
341 if ( !rDoc
.IsBlockEmpty( aParam
.nCol1
, aParam
.nRow1
,
342 aParam
.nCol2
, aParam
.nRow2
, nTab
) )
346 std::shared_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pViewData
->GetDialogParent(),
347 VclMessageType::Question
,
348 VclButtonsType::YesNo
,
349 // header from first row?
350 ScResId(STR_MSSG_MAKEAUTOFILTER_0
)));
351 xBox
->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0
)); // "StarCalc"
352 xBox
->set_default_response(RET_YES
);
353 xBox
->SetInstallLOKNotifierHdl(LINK(this, ScDBFunc
, InstallLOKNotifierHdl
));
354 xBox
->runAsync(xBox
, [pDocSh
, pViewData
, pDBData
, nRow
, nTab
, aParam
] (sal_Int32 nResult
) {
355 if (nResult
== RET_YES
)
357 pDBData
->SetHeader( true ); //! Undo ??
360 ApplyAutoFilter(pDocSh
, pViewData
, pDBData
, nRow
, nTab
, aParam
);
364 ApplyAutoFilter(pDocSh
, pViewData
, pDBData
, nRow
, nTab
, aParam
);
368 std::shared_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(pViewData
->GetDialogParent(),
369 VclMessageType::Warning
, VclButtonsType::Ok
,
370 ScResId(STR_ERR_AUTOFILTER
)));
371 xErrorBox
->SetInstallLOKNotifierHdl(LINK(this, ScDBFunc
, InstallLOKNotifierHdl
));
372 xErrorBox
->runAsync(xErrorBox
, [] (sal_Int32
) {});
377 IMPL_STATIC_LINK_NOARG(ScDBFunc
, InstallLOKNotifierHdl
, void*, vcl::ILibreOfficeKitNotifier
*)
382 void ScDBFunc::ApplyAutoFilter(ScDocShell
* pDocSh
, ScViewData
* pViewData
, ScDBData
* pDBData
,
383 SCROW nRow
, SCTAB nTab
, const ScQueryParam
& aParam
)
385 ScDocument
& rDoc
= pViewData
->GetDocument();
387 pDBData
->GetArea(aRange
);
388 pDocSh
->GetUndoManager()->AddUndoAction(
389 std::make_unique
<ScUndoAutoFilter
>(pDocSh
, aRange
, pDBData
->GetName(), true));
391 pDBData
->SetAutoFilter(true);
393 for (SCCOL nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
395 ScMF nFlag
= rDoc
.GetAttr(nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
396 rDoc
.ApplyAttr(nCol
, nRow
, nTab
, ScMergeFlagAttr(nFlag
| ScMF::Auto
));
398 pDocSh
->PostPaint(ScRange(aParam
.nCol1
, nRow
, nTab
, aParam
.nCol2
, nRow
, nTab
),
399 PaintPartFlags::Grid
);
401 ScDBFunc::ModifiedAutoFilter(pDocSh
);
404 void ScDBFunc::ModifiedAutoFilter(ScDocShell
* pDocSh
)
406 ScDocShellModificator
aModificator(*pDocSh
);
407 aModificator
.SetDocumentModified();
409 if (SfxBindings
* pBindings
= pDocSh
->GetViewBindings())
411 pBindings
->Invalidate(SID_AUTO_FILTER
);
412 pBindings
->Invalidate(SID_AUTOFILTER_HIDE
);
416 // just hide, no data change
418 void ScDBFunc::HideAutoFilter()
420 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
421 ScDocShellModificator
aModificator( *pDocSh
);
423 ScDocument
& rDoc
= pDocSh
->GetDocument();
425 ScDBData
* pDBData
= GetDBData( false );
430 pDBData
->GetArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
432 for (SCCOL nCol
=nCol1
; nCol
<=nCol2
; nCol
++)
434 ScMF nFlag
= rDoc
.GetAttr( nCol
, nRow1
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
435 rDoc
.ApplyAttr( nCol
, nRow1
, nTab
, ScMergeFlagAttr( nFlag
& ~ScMF::Auto
) );
439 pDBData
->GetArea( aRange
);
440 pDocSh
->GetUndoManager()->AddUndoAction(
441 std::make_unique
<ScUndoAutoFilter
>( pDocSh
, aRange
, pDBData
->GetName(), false ) );
443 pDBData
->SetAutoFilter(false);
445 pDocSh
->PostPaint(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow1
, nTab
), PaintPartFlags::Grid
);
446 aModificator
.SetDocumentModified();
448 SfxBindings
& rBindings
= GetViewData().GetBindings();
449 rBindings
.Invalidate( SID_AUTO_FILTER
);
450 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
455 bool ScDBFunc::ImportData( const ScImportParam
& rParam
)
457 ScDocument
& rDoc
= GetViewData().GetDocument();
458 ScEditableTester
aTester( rDoc
, GetViewData().GetTabNo(), rParam
.nCol1
,rParam
.nRow1
,
459 rParam
.nCol2
,rParam
.nRow2
);
460 if ( !aTester
.IsEditable() )
462 ErrorMessage(aTester
.GetMessageId());
466 ScDBDocFunc
aDBDocFunc( *GetViewData().GetDocShell() );
467 return aDBDocFunc
.DoImport( GetViewData().GetTabNo(), rParam
, nullptr );
470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */