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 //==================================================================
42 ScDBFunc::ScDBFunc( Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
43 ScViewFunc( pParent
, rDocSh
, pViewShell
)
52 // auxiliary functions
55 void ScDBFunc::GotoDBArea( const OUString
& rDBName
)
57 ScDocument
* pDoc
= GetViewData()->GetDocument();
58 ScDBCollection
* pDBCol
= pDoc
->GetDBCollection();
59 ScDBData
* pData
= pDBCol
->getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rDBName
));
68 pData
->GetArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
71 MoveCursorAbs( nStartCol
, nStartRow
, ScFollowMode( SC_FOLLOW_JUMP
),
72 false, false ); // bShift,bControl
74 InitBlockMode( nStartCol
, nStartRow
, nTab
);
75 MarkCursor( nEndCol
, nEndRow
, nTab
);
80 // search current datarange for sort / filter
82 ScDBData
* ScDBFunc::GetDBData( bool bMark
, ScGetDBMode eMode
, ScGetDBSelection eSel
)
84 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
85 ScDBData
* pData
= NULL
;
87 ScMarkType eMarkType
= GetViewData()->GetSimpleArea(aRange
);
88 if ( eMarkType
== SC_MARK_SIMPLE
|| eMarkType
== SC_MARK_SIMPLE_FILTERED
)
90 bool bShrinkColumnsOnly
= false;
91 if (eSel
== SC_DBSEL_ROW_DOWN
)
93 // Don't alter row range, additional rows may have been selected on
94 // purpose to append data, or to have a fake header row.
95 bShrinkColumnsOnly
= true;
96 // Select further rows only if only one row or a portion thereof is
98 if (aRange
.aStart
.Row() != aRange
.aEnd
.Row())
100 // If an area is selected shrink that to the actual used
101 // columns, don't draw filter buttons for empty columns.
102 eSel
= SC_DBSEL_SHRINK_TO_USED_DATA
;
104 else if (aRange
.aStart
.Col() == aRange
.aEnd
.Col())
106 // One cell only, if it is not marked obtain entire used data
108 const ScMarkData
& rMarkData
= GetViewData()->GetMarkData();
109 if (!(rMarkData
.IsMarked() || rMarkData
.IsMultiMarked()))
110 eSel
= SC_DBSEL_KEEP
;
115 case SC_DBSEL_SHRINK_TO_SHEET_DATA
:
117 // Shrink the selection to sheet data area.
118 ScDocument
* pDoc
= pDocSh
->GetDocument();
119 SCCOL nCol1
= aRange
.aStart
.Col(), nCol2
= aRange
.aEnd
.Col();
120 SCROW nRow1
= aRange
.aStart
.Row(), nRow2
= aRange
.aEnd
.Row();
121 if (pDoc
->ShrinkToDataArea( aRange
.aStart
.Tab(), nCol1
, nRow1
, nCol2
, nRow2
))
123 aRange
.aStart
.SetCol(nCol1
);
124 aRange
.aEnd
.SetCol(nCol2
);
125 aRange
.aStart
.SetRow(nRow1
);
126 aRange
.aEnd
.SetRow(nRow2
);
130 case SC_DBSEL_SHRINK_TO_USED_DATA
:
131 case SC_DBSEL_ROW_DOWN
:
133 // Shrink the selection to actual used area.
134 ScDocument
* pDoc
= pDocSh
->GetDocument();
135 SCCOL nCol1
= aRange
.aStart
.Col(), nCol2
= aRange
.aEnd
.Col();
136 SCROW nRow1
= aRange
.aStart
.Row(), nRow2
= aRange
.aEnd
.Row();
138 pDoc
->ShrinkToUsedDataArea( bShrunk
, aRange
.aStart
.Tab(),
139 nCol1
, nRow1
, nCol2
, nRow2
, bShrinkColumnsOnly
);
142 aRange
.aStart
.SetCol(nCol1
);
143 aRange
.aEnd
.SetCol(nCol2
);
144 aRange
.aStart
.SetRow(nRow1
);
145 aRange
.aEnd
.SetRow(nRow2
);
152 pData
= pDocSh
->GetDBData( aRange
, eMode
, eSel
);
154 else if ( eMode
!= SC_DB_OLD
)
155 pData
= pDocSh
->GetDBData(
156 ScRange( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
157 GetViewData()->GetTabNo() ),
158 eMode
, SC_DBSEL_KEEP
);
166 pData
->GetArea(aFound
);
167 MarkRange( aFound
, false );
172 ScDBData
* ScDBFunc::GetAnonymousDBData()
174 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
176 ScMarkType eMarkType
= GetViewData()->GetSimpleArea(aRange
);
177 if (eMarkType
!= SC_MARK_SIMPLE
&& eMarkType
!= SC_MARK_SIMPLE_FILTERED
)
180 // Expand to used data area if not explicitly marked.
181 const ScMarkData
& rMarkData
= GetViewData()->GetMarkData();
182 if (!rMarkData
.IsMarked() && !rMarkData
.IsMultiMarked())
184 SCCOL nCol1
= aRange
.aStart
.Col();
185 SCCOL nCol2
= aRange
.aEnd
.Col();
186 SCROW nRow1
= aRange
.aStart
.Row();
187 SCROW nRow2
= aRange
.aEnd
.Row();
188 pDocSh
->GetDocument()->GetDataArea(aRange
.aStart
.Tab(), nCol1
, nRow1
, nCol2
, nRow2
, false, false);
189 aRange
.aStart
.SetCol(nCol1
);
190 aRange
.aStart
.SetRow(nRow1
);
191 aRange
.aEnd
.SetCol(nCol2
);
192 aRange
.aEnd
.SetRow(nRow2
);
195 return pDocSh
->GetAnonymousDBData(aRange
);
198 // change database range (dialog)
200 void ScDBFunc::NotifyCloseDbNameDlg( const ScDBCollection
& rNewColl
, const std::vector
<ScRange
> &rDelAreaList
)
203 ScDocShell
* pDocShell
= GetViewData()->GetDocShell();
204 ScDocShellModificator
aModificator( *pDocShell
);
205 ScDocument
* pDoc
= pDocShell
->GetDocument();
206 ScDBCollection
* pOldColl
= pDoc
->GetDBCollection();
207 ScDBCollection
* pUndoColl
= NULL
;
208 const sal_Bool
bRecord (pDoc
->IsUndoEnabled());
210 std::vector
<ScRange
>::const_iterator iter
;
211 for (iter
= rDelAreaList
.begin(); iter
!= rDelAreaList
.end(); ++iter
)
213 // unregistering target in SBA no longer necessary
214 const ScAddress
& rStart
= iter
->aStart
;
215 const ScAddress
& rEnd
= iter
->aEnd
;
216 pDocShell
->DBAreaDeleted( rStart
.Tab(),
217 rStart
.Col(), rStart
.Row(),
218 rEnd
.Col(), rEnd
.Row() );
223 pUndoColl
= new ScDBCollection( *pOldColl
);
225 // register target in SBA no longer necessary
227 pDoc
->CompileDBFormula( sal_True
); // CreateFormulaString
228 pDoc
->SetDBCollection( new ScDBCollection( rNewColl
) );
229 pDoc
->CompileDBFormula( false ); // CompileFormulaString
231 pDocShell
->PostPaint(ScRange(0, 0, 0, MAXCOL
, MAXROW
, MAXTAB
), PAINT_GRID
);
232 aModificator
.SetDocumentModified();
233 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
237 ScDBCollection
* pRedoColl
= new ScDBCollection( rNewColl
);
238 pDocShell
->GetUndoManager()->AddUndoAction(
239 new ScUndoDBData( pDocShell
, pUndoColl
, pRedoColl
) );
249 void ScDBFunc::UISort( const ScSortParam
& rSortParam
, sal_Bool bRecord
)
251 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
252 ScDocument
* pDoc
= pDocSh
->GetDocument();
253 SCTAB nTab
= GetViewData()->GetTabNo();
254 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
255 rSortParam
.nCol2
, rSortParam
.nRow2
);
258 OSL_FAIL( "Sort: no DBData" );
262 ScSubTotalParam aSubTotalParam
;
263 pDBData
->GetSubTotalParam( aSubTotalParam
);
264 if (aSubTotalParam
.bGroupActive
[0] && !aSubTotalParam
.bRemoveOnly
)
266 // repeat subtotals, with new sortorder
268 DoSubTotals( aSubTotalParam
, bRecord
, &rSortParam
);
272 Sort( rSortParam
, bRecord
); // just sort
276 void ScDBFunc::Sort( const ScSortParam
& rSortParam
, sal_Bool bRecord
, sal_Bool bPaint
)
278 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
279 SCTAB nTab
= GetViewData()->GetTabNo();
280 ScDBDocFunc
aDBDocFunc( *pDocSh
);
281 sal_Bool bSuccess
= aDBDocFunc
.Sort( nTab
, rSortParam
, bRecord
, bPaint
, false );
282 if ( bSuccess
&& !rSortParam
.bInplace
)
285 ScRange
aDestRange( rSortParam
.nDestCol
, rSortParam
.nDestRow
, rSortParam
.nDestTab
,
286 rSortParam
.nDestCol
+ rSortParam
.nCol2
- rSortParam
.nCol1
,
287 rSortParam
.nDestRow
+ rSortParam
.nRow2
- rSortParam
.nRow1
,
288 rSortParam
.nDestTab
);
289 MarkRange( aDestRange
);
297 void ScDBFunc::Query( const ScQueryParam
& rQueryParam
, const ScRange
* pAdvSource
, sal_Bool bRecord
)
299 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
300 SCTAB nTab
= GetViewData()->GetTabNo();
301 ScDBDocFunc
aDBDocFunc( *pDocSh
);
302 sal_Bool bSuccess
= aDBDocFunc
.Query( nTab
, rQueryParam
, pAdvSource
, bRecord
, false );
306 sal_Bool bCopy
= !rQueryParam
.bInplace
;
309 // mark target range (data base range has been set up if applicable)
310 ScDocument
* pDoc
= pDocSh
->GetDocument();
311 ScDBData
* pDestData
= pDoc
->GetDBAtCursor(
312 rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
313 rQueryParam
.nDestTab
, sal_True
);
317 pDestData
->GetArea(aDestRange
);
318 MarkRange( aDestRange
);
325 SelectionChanged(); // for attribute states (filtered rows are ignored)
328 GetViewData()->GetBindings().Invalidate( SID_UNFILTER
);
332 // autofilter-buttons show / hide
334 void ScDBFunc::ToggleAutoFilter()
336 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
337 ScDocShellModificator
aModificator( *pDocSh
);
340 ScDocument
* pDoc
= GetViewData()->GetDocument();
341 ScDBData
* pDBData
= GetDBData(false, SC_DB_MAKE
, SC_DBSEL_ROW_DOWN
);
343 pDBData
->SetByRow( sal_True
); //! undo, retrieve beforehand ??
344 pDBData
->GetQueryParam( aParam
);
348 SCROW nRow
= aParam
.nRow1
;
349 SCTAB nTab
= GetViewData()->GetTabNo();
351 sal_Bool bHasAuto
= sal_True
;
352 sal_Bool bHeader
= pDBData
->HasHeader();
353 sal_Bool bPaint
= false;
355 //! instead retrieve from DB-range?
357 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
&& bHasAuto
; nCol
++)
359 nFlag
= ((ScMergeFlagAttr
*) pDoc
->
360 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
362 if ( (nFlag
& SC_MF_AUTO
) == 0 )
366 if (bHasAuto
) // remove
368 // hide filter buttons
370 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
372 nFlag
= ((ScMergeFlagAttr
*) pDoc
->
373 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
374 pDoc
->ApplyAttr( nCol
, nRow
, nTab
, ScMergeFlagAttr( nFlag
& ~SC_MF_AUTO
) );
377 // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
379 OUString aUndo
= ScGlobal::GetRscString( STR_UNDO_QUERY
);
380 pDocSh
->GetUndoManager()->EnterListAction( aUndo
, aUndo
);
383 pDBData
->GetArea( aRange
);
384 pDocSh
->GetUndoManager()->AddUndoAction(
385 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), false ) );
387 pDBData
->SetAutoFilter(false);
389 // remove filter (incl. Paint / Undo)
391 SCSIZE nEC
= aParam
.GetEntryCount();
392 for (SCSIZE i
=0; i
<nEC
; i
++)
393 aParam
.GetEntry(i
).bDoQuery
= false;
394 aParam
.bDuplicate
= sal_True
;
395 Query( aParam
, NULL
, sal_True
);
397 pDocSh
->GetUndoManager()->LeaveListAction();
401 else // show filter buttons
403 if ( !pDoc
->IsBlockEmpty( nTab
,
404 aParam
.nCol1
, aParam
.nRow1
,
405 aParam
.nCol2
, aParam
.nRow2
) )
409 if ( MessBox( GetViewData()->GetDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
410 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0
), // "StarCalc"
411 ScGlobal::GetRscString( STR_MSSG_MAKEAUTOFILTER_0
) // header from first row?
412 ).Execute() == RET_YES
)
414 pDBData
->SetHeader( sal_True
); //! Undo ??
420 pDBData
->GetArea( aRange
);
421 pDocSh
->GetUndoManager()->AddUndoAction(
422 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), sal_True
) );
424 pDBData
->SetAutoFilter(sal_True
);
426 for (nCol
=aParam
.nCol1
; nCol
<=aParam
.nCol2
; nCol
++)
428 nFlag
= ((ScMergeFlagAttr
*) pDoc
->
429 GetAttr( nCol
, nRow
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
430 pDoc
->ApplyAttr( nCol
, nRow
, nTab
, ScMergeFlagAttr( nFlag
| SC_MF_AUTO
) );
432 pDocSh
->PostPaint(ScRange(aParam
.nCol1
, nRow
, nTab
, aParam
.nCol2
, nRow
, nTab
),
438 ErrorBox
aErrorBox( GetViewData()->GetDialogParent(), WinBits( WB_OK
| WB_DEF_OK
),
439 ScGlobal::GetRscString( STR_ERR_AUTOFILTER
) );
446 aModificator
.SetDocumentModified();
448 SfxBindings
& rBindings
= GetViewData()->GetBindings();
449 rBindings
.Invalidate( SID_AUTO_FILTER
);
450 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
454 // just hide, no data change
456 void ScDBFunc::HideAutoFilter()
458 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
459 ScDocShellModificator
aModificator( *pDocSh
);
461 ScDocument
* pDoc
= pDocSh
->GetDocument();
464 ScDBData
* pDBData
= GetDBData( false );
469 pDBData
->GetArea(nTab
, nCol1
, nRow1
, nCol2
, nRow2
);
471 for (SCCOL nCol
=nCol1
; nCol
<=nCol2
; nCol
++)
473 sal_Int16 nFlag
= ((ScMergeFlagAttr
*) pDoc
->
474 GetAttr( nCol
, nRow1
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
475 pDoc
->ApplyAttr( nCol
, nRow1
, nTab
, ScMergeFlagAttr( nFlag
& ~SC_MF_AUTO
) );
479 pDBData
->GetArea( aRange
);
480 pDocSh
->GetUndoManager()->AddUndoAction(
481 new ScUndoAutoFilter( pDocSh
, aRange
, pDBData
->GetName(), false ) );
483 pDBData
->SetAutoFilter(false);
485 pDocSh
->PostPaint(ScRange(nCol1
, nRow1
, nTab
, nCol2
, nRow1
, nTab
), PAINT_GRID
);
486 aModificator
.SetDocumentModified();
488 SfxBindings
& rBindings
= GetViewData()->GetBindings();
489 rBindings
.Invalidate( SID_AUTO_FILTER
);
490 rBindings
.Invalidate( SID_AUTOFILTER_HIDE
);
495 sal_Bool
ScDBFunc::ImportData( const ScImportParam
& rParam
, sal_Bool bRecord
)
497 ScDocument
* pDoc
= GetViewData()->GetDocument();
498 ScEditableTester
aTester( pDoc
, GetViewData()->GetTabNo(), rParam
.nCol1
,rParam
.nRow1
,
499 rParam
.nCol2
,rParam
.nRow2
);
500 if ( !aTester
.IsEditable() )
502 ErrorMessage(aTester
.GetMessageId());
506 ScDBDocFunc
aDBDocFunc( *GetViewData()->GetDocShell() );
507 return aDBDocFunc
.DoImport( GetViewData()->GetTabNo(), rParam
, NULL
, bRecord
);
512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */