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/app.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <vcl/msgbox.hxx>
25 #include <com/sun/star/sdbc/XResultSet.hpp>
31 #include "undodat.hxx"
33 #include "globstr.hrc"
35 #include "dbdocfun.hxx"
36 #include "editable.hxx"
37 #include "queryentry.hxx"
38 #include "markdata.hxx"
40 ScDBFunc::ScDBFunc( vcl::Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
41 ScViewFunc( pParent
, rDocSh
, pViewShell
)
49 // auxiliary functions
51 void ScDBFunc::GotoDBArea( const OUString
& rDBName
)
53 ScDocument
* pDoc
= GetViewData().GetDocument();
54 ScDBCollection
* pDBCol
= pDoc
->GetDBCollection();
55 ScDBData
* pData
= pDBCol
->getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rDBName
));
64 pData
->GetArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
67 MoveCursorAbs( nStartCol
, nStartRow
, ScFollowMode( SC_FOLLOW_JUMP
),
68 false, false ); // bShift,bControl
70 InitBlockMode( nStartCol
, nStartRow
, nTab
);
71 MarkCursor( nEndCol
, nEndRow
, nTab
);
76 // search current datarange for sort / filter
78 ScDBData
* ScDBFunc::GetDBData( bool bMark
, ScGetDBMode eMode
, ScGetDBSelection eSel
)
80 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
81 ScDBData
* pData
= NULL
;
83 ScMarkType eMarkType
= GetViewData().GetSimpleArea(aRange
);
84 if ( eMarkType
== SC_MARK_SIMPLE
|| eMarkType
== SC_MARK_SIMPLE_FILTERED
)
86 bool bShrinkColumnsOnly
= false;
87 if (eSel
== SC_DBSEL_ROW_DOWN
)
89 // Don't alter row range, additional rows may have been selected on
90 // purpose to append data, or to have a fake header row.
91 bShrinkColumnsOnly
= true;
92 // Select further rows only if only one row or a portion thereof is
94 if (aRange
.aStart
.Row() != aRange
.aEnd
.Row())
96 // If an area is selected shrink that to the actual used
97 // columns, don't draw filter buttons for empty columns.
98 eSel
= SC_DBSEL_SHRINK_TO_USED_DATA
;
100 else if (aRange
.aStart
.Col() == aRange
.aEnd
.Col())
102 // One cell only, if it is not marked obtain entire used data
104 const ScMarkData
& rMarkData
= GetViewData().GetMarkData();
105 if (!(rMarkData
.IsMarked() || rMarkData
.IsMultiMarked()))
106 eSel
= SC_DBSEL_KEEP
;
111 case SC_DBSEL_SHRINK_TO_SHEET_DATA
:
113 // Shrink the selection to sheet data area.
114 ScDocument
& rDoc
= pDocSh
->GetDocument();
115 SCCOL nCol1
= aRange
.aStart
.Col(), nCol2
= aRange
.aEnd
.Col();
116 SCROW nRow1
= aRange
.aStart
.Row(), nRow2
= aRange
.aEnd
.Row();
117 if (rDoc
.ShrinkToDataArea( aRange
.aStart
.Tab(), nCol1
, nRow1
, nCol2
, nRow2
))
119 aRange
.aStart
.SetCol(nCol1
);
120 aRange
.aEnd
.SetCol(nCol2
);
121 aRange
.aStart
.SetRow(nRow1
);
122 aRange
.aEnd
.SetRow(nRow2
);
126 case SC_DBSEL_SHRINK_TO_USED_DATA
:
127 case SC_DBSEL_ROW_DOWN
:
129 // Shrink the selection to actual used area.
130 ScDocument
& rDoc
= pDocSh
->GetDocument();
131 SCCOL nCol1
= aRange
.aStart
.Col(), nCol2
= aRange
.aEnd
.Col();
132 SCROW nRow1
= aRange
.aStart
.Row(), nRow2
= aRange
.aEnd
.Row();
134 rDoc
.ShrinkToUsedDataArea( bShrunk
, aRange
.aStart
.Tab(),
135 nCol1
, nRow1
, nCol2
, nRow2
, bShrinkColumnsOnly
);
138 aRange
.aStart
.SetCol(nCol1
);
139 aRange
.aEnd
.SetCol(nCol2
);
140 aRange
.aStart
.SetRow(nRow1
);
141 aRange
.aEnd
.SetRow(nRow2
);
148 pData
= pDocSh
->GetDBData( aRange
, eMode
, eSel
);
150 else if ( eMode
!= SC_DB_OLD
)
151 pData
= pDocSh
->GetDBData(
152 ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(),
153 GetViewData().GetTabNo() ),
154 eMode
, SC_DBSEL_KEEP
);
162 pData
->GetArea(aFound
);
163 MarkRange( aFound
, false );
168 ScDBData
* ScDBFunc::GetAnonymousDBData()
170 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
172 ScMarkType eMarkType
= GetViewData().GetSimpleArea(aRange
);
173 if (eMarkType
!= SC_MARK_SIMPLE
&& eMarkType
!= SC_MARK_SIMPLE_FILTERED
)
176 // Expand to used data area if not explicitly marked.
177 const ScMarkData
& rMarkData
= GetViewData().GetMarkData();
178 if (!rMarkData
.IsMarked() && !rMarkData
.IsMultiMarked())
180 SCCOL nCol1
= aRange
.aStart
.Col();
181 SCCOL nCol2
= aRange
.aEnd
.Col();
182 SCROW nRow1
= aRange
.aStart
.Row();
183 SCROW nRow2
= aRange
.aEnd
.Row();
184 pDocSh
->GetDocument().GetDataArea(aRange
.aStart
.Tab(), nCol1
, nRow1
, nCol2
, nRow2
, false, false);
185 aRange
.aStart
.SetCol(nCol1
);
186 aRange
.aStart
.SetRow(nRow1
);
187 aRange
.aEnd
.SetCol(nCol2
);
188 aRange
.aEnd
.SetRow(nRow2
);
191 return pDocSh
->GetAnonymousDBData(aRange
);
198 void ScDBFunc::UISort( const ScSortParam
& rSortParam
, bool bRecord
)
200 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
201 ScDocument
& rDoc
= pDocSh
->GetDocument();
202 SCTAB nTab
= GetViewData().GetTabNo();
203 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
204 rSortParam
.nCol2
, rSortParam
.nRow2
);
207 OSL_FAIL( "Sort: no DBData" );
211 ScSubTotalParam aSubTotalParam
;
212 pDBData
->GetSubTotalParam( aSubTotalParam
);
213 if (aSubTotalParam
.bGroupActive
[0] && !aSubTotalParam
.bRemoveOnly
)
215 // repeat subtotals, with new sortorder
217 DoSubTotals( aSubTotalParam
, bRecord
, &rSortParam
);
221 Sort( rSortParam
, bRecord
); // just sort
225 void ScDBFunc::Sort( const ScSortParam
& rSortParam
, bool bRecord
, bool bPaint
)
227 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
228 SCTAB nTab
= GetViewData().GetTabNo();
229 ScDBDocFunc
aDBDocFunc( *pDocSh
);
230 bool bSuccess
= aDBDocFunc
.Sort( nTab
, rSortParam
, bRecord
, bPaint
, false );
231 if ( bSuccess
&& !rSortParam
.bInplace
)
234 ScRange
aDestRange( rSortParam
.nDestCol
, rSortParam
.nDestRow
, rSortParam
.nDestTab
,
235 rSortParam
.nDestCol
+ rSortParam
.nCol2
- rSortParam
.nCol1
,
236 rSortParam
.nDestRow
+ rSortParam
.nRow2
- rSortParam
.nRow1
,
237 rSortParam
.nDestTab
);
238 MarkRange( aDestRange
);
246 void ScDBFunc::Query( const ScQueryParam
& rQueryParam
, const ScRange
* pAdvSource
, bool bRecord
)
248 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
249 SCTAB nTab
= GetViewData().GetTabNo();
250 ScDBDocFunc
aDBDocFunc( *pDocSh
);
251 bool bSuccess
= aDBDocFunc
.Query( nTab
, rQueryParam
, pAdvSource
, bRecord
, false );
255 bool bCopy
= !rQueryParam
.bInplace
;
258 // mark target range (data base range has been set up if applicable)
259 ScDocument
& rDoc
= pDocSh
->GetDocument();
260 ScDBData
* pDestData
= rDoc
.GetDBAtCursor(
261 rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
262 rQueryParam
.nDestTab
, true );
266 pDestData
->GetArea(aDestRange
);
267 MarkRange( aDestRange
);
274 SelectionChanged(); // for attribute states (filtered rows are ignored)
277 GetViewData().GetBindings().Invalidate( SID_UNFILTER
);
281 // autofilter-buttons show / hide
283 void ScDBFunc::ToggleAutoFilter()
285 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
286 ScDocShellModificator
aModificator( *pDocSh
);
289 ScDocument
* pDoc
= GetViewData().GetDocument();
290 ScDBData
* pDBData
= GetDBData(false, SC_DB_MAKE
, SC_DBSEL_ROW_DOWN
);
292 pDBData
->SetByRow( true ); //! undo, retrieve beforehand ??
293 pDBData
->GetQueryParam( aParam
);
296 SCROW nRow
= aParam
.nRow1
;
297 SCTAB nTab
= GetViewData().GetTabNo();
299 bool bHasAuto
= true;
300 bool bHeader
= pDBData
->HasHeader();
303 //! instead retrieve from DB-range?
305 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
&& bHasAuto
; nCol
++)
307 nFlag
= static_cast<const ScMergeFlagAttr
*>( pDoc
->
308 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
310 if ( (nFlag
& SC_MF_AUTO
) == 0 )
314 if (bHasAuto
) // remove
316 // hide filter buttons
318 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
320 nFlag
= static_cast<const ScMergeFlagAttr
*>( pDoc
->
321 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
322 pDoc
->ApplyAttr( nCol
, nRow
, nTab
, ScMergeFlagAttr( nFlag
& ~SC_MF_AUTO
) );
325 // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
327 OUString aUndo
= ScGlobal::GetRscString( STR_UNDO_QUERY
);
328 pDocSh
->GetUndoManager()->EnterListAction( aUndo
, aUndo
);
331 pDBData
->GetArea( aRange
);
332 pDocSh
->GetUndoManager()->AddUndoAction(
333 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), false ) );
335 pDBData
->SetAutoFilter(false);
337 // remove filter (incl. Paint / Undo)
339 SCSIZE nEC
= aParam
.GetEntryCount();
340 for (SCSIZE i
=0; i
<nEC
; i
++)
341 aParam
.GetEntry(i
).bDoQuery
= false;
342 aParam
.bDuplicate
= true;
343 Query( aParam
, NULL
, true );
345 pDocSh
->GetUndoManager()->LeaveListAction();
349 else // show filter buttons
351 if ( !pDoc
->IsBlockEmpty( nTab
,
352 aParam
.nCol1
, aParam
.nRow1
,
353 aParam
.nCol2
, aParam
.nRow2
) )
357 if ( ScopedVclPtr
<MessBox
>::Create( GetViewData().GetDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
358 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0
), // "StarCalc"
359 ScGlobal::GetRscString( STR_MSSG_MAKEAUTOFILTER_0
) // header from first row?
360 )->Execute() == RET_YES
)
362 pDBData
->SetHeader( true ); //! Undo ??
368 pDBData
->GetArea( aRange
);
369 pDocSh
->GetUndoManager()->AddUndoAction(
370 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), true ) );
372 pDBData
->SetAutoFilter(true);
374 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
376 nFlag
= static_cast<const ScMergeFlagAttr
*>( pDoc
->
377 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
378 pDoc
->ApplyAttr( nCol
, nRow
, nTab
, ScMergeFlagAttr( nFlag
| SC_MF_AUTO
) );
380 pDocSh
->PostPaint(ScRange(aParam
.nCol1
, nRow
, nTab
, aParam
.nCol2
, nRow
, nTab
),
386 ScopedVclPtrInstance
<MessageDialog
> aErrorBox(GetViewData().GetDialogParent(),
387 ScGlobal::GetRscString(STR_ERR_AUTOFILTER
));
388 aErrorBox
->Execute();
394 aModificator
.SetDocumentModified();
396 SfxBindings
& rBindings
= GetViewData().GetBindings();
397 rBindings
.Invalidate( SID_AUTO_FILTER
);
398 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
402 // just hide, no data change
404 void ScDBFunc::HideAutoFilter()
406 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
407 ScDocShellModificator
aModificator( *pDocSh
);
409 ScDocument
& rDoc
= pDocSh
->GetDocument();
412 ScDBData
* pDBData
= GetDBData( false );
417 pDBData
->GetArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
419 for (SCCOL nCol
=nCol1
; nCol
<=nCol2
; nCol
++)
421 sal_Int16 nFlag
= static_cast<const ScMergeFlagAttr
*>( rDoc
.
422 GetAttr( nCol
, nRow1
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
423 rDoc
.ApplyAttr( nCol
, nRow1
, nTab
, ScMergeFlagAttr( nFlag
& ~SC_MF_AUTO
) );
427 pDBData
->GetArea( aRange
);
428 pDocSh
->GetUndoManager()->AddUndoAction(
429 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), false ) );
431 pDBData
->SetAutoFilter(false);
433 pDocSh
->PostPaint(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow1
, nTab
), PAINT_GRID
);
434 aModificator
.SetDocumentModified();
436 SfxBindings
& rBindings
= GetViewData().GetBindings();
437 rBindings
.Invalidate( SID_AUTO_FILTER
);
438 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
443 bool ScDBFunc::ImportData( const ScImportParam
& rParam
, bool bRecord
)
445 ScDocument
* pDoc
= GetViewData().GetDocument();
446 ScEditableTester
aTester( pDoc
, GetViewData().GetTabNo(), rParam
.nCol1
,rParam
.nRow1
,
447 rParam
.nCol2
,rParam
.nRow2
);
448 if ( !aTester
.IsEditable() )
450 ErrorMessage(aTester
.GetMessageId());
454 ScDBDocFunc
aDBDocFunc( *GetViewData().GetDocShell() );
455 return aDBDocFunc
.DoImport( GetViewData().GetTabNo(), rParam
, NULL
, bRecord
);
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */