Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "scitems.hxx"
21 : #include <sfx2/app.hxx>
22 : #include <sfx2/bindings.hxx>
23 : #include <vcl/msgbox.hxx>
24 :
25 : #include <com/sun/star/sdbc/XResultSet.hpp>
26 :
27 : #include "dbfunc.hxx"
28 : #include "docsh.hxx"
29 : #include "attrib.hxx"
30 : #include "sc.hrc"
31 : #include "undodat.hxx"
32 : #include "dbdata.hxx"
33 : #include "globstr.hrc"
34 : #include "global.hxx"
35 : #include "dbdocfun.hxx"
36 : #include "editable.hxx"
37 : #include "queryentry.hxx"
38 : #include "markdata.hxx"
39 :
40 546 : ScDBFunc::ScDBFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
41 546 : ScViewFunc( pParent, rDocSh, pViewShell )
42 : {
43 546 : }
44 :
45 546 : ScDBFunc::~ScDBFunc()
46 : {
47 546 : }
48 :
49 : // auxiliary functions
50 :
51 0 : void ScDBFunc::GotoDBArea( const OUString& rDBName )
52 : {
53 0 : ScDocument* pDoc = GetViewData().GetDocument();
54 0 : ScDBCollection* pDBCol = pDoc->GetDBCollection();
55 0 : ScDBData* pData = pDBCol->getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rDBName));
56 0 : if (pData)
57 : {
58 0 : SCTAB nTab = 0;
59 0 : SCCOL nStartCol = 0;
60 0 : SCROW nStartRow = 0;
61 0 : SCCOL nEndCol = 0;
62 0 : SCROW nEndRow = 0;
63 :
64 0 : pData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
65 0 : SetTabNo( nTab );
66 :
67 : MoveCursorAbs( nStartCol, nStartRow, ScFollowMode( SC_FOLLOW_JUMP ),
68 0 : false, false ); // bShift,bControl
69 0 : DoneBlockMode();
70 0 : InitBlockMode( nStartCol, nStartRow, nTab );
71 0 : MarkCursor( nEndCol, nEndRow, nTab );
72 0 : SelectionChanged();
73 : }
74 0 : }
75 :
76 : // search current datarange for sort / filter
77 :
78 0 : ScDBData* ScDBFunc::GetDBData( bool bMark, ScGetDBMode eMode, ScGetDBSelection eSel )
79 : {
80 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
81 0 : ScDBData* pData = NULL;
82 0 : ScRange aRange;
83 0 : ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
84 0 : if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
85 : {
86 0 : bool bShrinkColumnsOnly = false;
87 0 : if (eSel == SC_DBSEL_ROW_DOWN)
88 : {
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 0 : bShrinkColumnsOnly = true;
92 : // Select further rows only if only one row or a portion thereof is
93 : // selected.
94 0 : if (aRange.aStart.Row() != aRange.aEnd.Row())
95 : {
96 : // If an area is selected shrink that to the actual used
97 : // columns, don't draw filter buttons for empty columns.
98 0 : eSel = SC_DBSEL_SHRINK_TO_USED_DATA;
99 : }
100 0 : else if (aRange.aStart.Col() == aRange.aEnd.Col())
101 : {
102 : // One cell only, if it is not marked obtain entire used data
103 : // area.
104 0 : const ScMarkData& rMarkData = GetViewData().GetMarkData();
105 0 : if (!(rMarkData.IsMarked() || rMarkData.IsMultiMarked()))
106 0 : eSel = SC_DBSEL_KEEP;
107 : }
108 : }
109 0 : switch (eSel)
110 : {
111 : case SC_DBSEL_SHRINK_TO_SHEET_DATA:
112 : {
113 : // Shrink the selection to sheet data area.
114 0 : ScDocument& rDoc = pDocSh->GetDocument();
115 0 : SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
116 0 : SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
117 0 : if (rDoc.ShrinkToDataArea( aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2))
118 : {
119 0 : aRange.aStart.SetCol(nCol1);
120 0 : aRange.aEnd.SetCol(nCol2);
121 0 : aRange.aStart.SetRow(nRow1);
122 0 : aRange.aEnd.SetRow(nRow2);
123 : }
124 : }
125 0 : break;
126 : case SC_DBSEL_SHRINK_TO_USED_DATA:
127 : case SC_DBSEL_ROW_DOWN:
128 : {
129 : // Shrink the selection to actual used area.
130 0 : ScDocument& rDoc = pDocSh->GetDocument();
131 0 : SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
132 0 : SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
133 : bool bShrunk;
134 0 : rDoc.ShrinkToUsedDataArea( bShrunk, aRange.aStart.Tab(),
135 0 : nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly);
136 0 : if (bShrunk)
137 : {
138 0 : aRange.aStart.SetCol(nCol1);
139 0 : aRange.aEnd.SetCol(nCol2);
140 0 : aRange.aStart.SetRow(nRow1);
141 0 : aRange.aEnd.SetRow(nRow2);
142 : }
143 : }
144 0 : break;
145 : default:
146 : ; // nothing
147 : }
148 0 : pData = pDocSh->GetDBData( aRange, eMode, eSel );
149 : }
150 0 : else if ( eMode != SC_DB_OLD )
151 : pData = pDocSh->GetDBData(
152 0 : ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(),
153 0 : GetViewData().GetTabNo() ),
154 0 : eMode, SC_DBSEL_KEEP );
155 :
156 0 : if (!pData)
157 0 : return NULL;
158 :
159 0 : if (bMark)
160 : {
161 0 : ScRange aFound;
162 0 : pData->GetArea(aFound);
163 0 : MarkRange( aFound, false );
164 : }
165 0 : return pData;
166 : }
167 :
168 0 : ScDBData* ScDBFunc::GetAnonymousDBData()
169 : {
170 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
171 0 : ScRange aRange;
172 0 : ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
173 0 : if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
174 0 : return NULL;
175 :
176 : // Expand to used data area if not explicitly marked.
177 0 : const ScMarkData& rMarkData = GetViewData().GetMarkData();
178 0 : if (!rMarkData.IsMarked() && !rMarkData.IsMultiMarked())
179 : {
180 0 : SCCOL nCol1 = aRange.aStart.Col();
181 0 : SCCOL nCol2 = aRange.aEnd.Col();
182 0 : SCROW nRow1 = aRange.aStart.Row();
183 0 : SCROW nRow2 = aRange.aEnd.Row();
184 0 : pDocSh->GetDocument().GetDataArea(aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2, false, false);
185 0 : aRange.aStart.SetCol(nCol1);
186 0 : aRange.aStart.SetRow(nRow1);
187 0 : aRange.aEnd.SetCol(nCol2);
188 0 : aRange.aEnd.SetRow(nRow2);
189 : }
190 :
191 0 : return pDocSh->GetAnonymousDBData(aRange);
192 : }
193 :
194 : // main functions
195 :
196 : // Sort
197 :
198 0 : void ScDBFunc::UISort( const ScSortParam& rSortParam, bool bRecord )
199 : {
200 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
201 0 : ScDocument& rDoc = pDocSh->GetDocument();
202 0 : SCTAB nTab = GetViewData().GetTabNo();
203 : ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
204 0 : rSortParam.nCol2, rSortParam.nRow2 );
205 0 : if (!pDBData)
206 : {
207 : OSL_FAIL( "Sort: no DBData" );
208 0 : return;
209 : }
210 :
211 0 : ScSubTotalParam aSubTotalParam;
212 0 : pDBData->GetSubTotalParam( aSubTotalParam );
213 0 : if (aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly)
214 : {
215 : // repeat subtotals, with new sortorder
216 :
217 0 : DoSubTotals( aSubTotalParam, bRecord, &rSortParam );
218 : }
219 : else
220 : {
221 0 : Sort( rSortParam, bRecord ); // just sort
222 : }
223 : }
224 :
225 0 : void ScDBFunc::Sort( const ScSortParam& rSortParam, bool bRecord, bool bPaint )
226 : {
227 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
228 0 : SCTAB nTab = GetViewData().GetTabNo();
229 0 : ScDBDocFunc aDBDocFunc( *pDocSh );
230 0 : bool bSuccess = aDBDocFunc.Sort( nTab, rSortParam, bRecord, bPaint, false );
231 0 : if ( bSuccess && !rSortParam.bInplace )
232 : {
233 : // mark target
234 : ScRange aDestRange( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab,
235 : rSortParam.nDestCol + rSortParam.nCol2 - rSortParam.nCol1,
236 0 : rSortParam.nDestRow + rSortParam.nRow2 - rSortParam.nRow1,
237 0 : rSortParam.nDestTab );
238 0 : MarkRange( aDestRange );
239 : }
240 :
241 0 : ResetAutoSpell();
242 0 : }
243 :
244 : // filters
245 :
246 6 : void ScDBFunc::Query( const ScQueryParam& rQueryParam, const ScRange* pAdvSource, bool bRecord )
247 : {
248 6 : ScDocShell* pDocSh = GetViewData().GetDocShell();
249 6 : SCTAB nTab = GetViewData().GetTabNo();
250 6 : ScDBDocFunc aDBDocFunc( *pDocSh );
251 6 : bool bSuccess = aDBDocFunc.Query( nTab, rQueryParam, pAdvSource, bRecord, false );
252 :
253 6 : if (bSuccess)
254 : {
255 6 : bool bCopy = !rQueryParam.bInplace;
256 6 : if (bCopy)
257 : {
258 : // mark target range (data base range has been set up if applicable)
259 0 : ScDocument& rDoc = pDocSh->GetDocument();
260 : ScDBData* pDestData = rDoc.GetDBAtCursor(
261 : rQueryParam.nDestCol, rQueryParam.nDestRow,
262 0 : rQueryParam.nDestTab, true );
263 0 : if (pDestData)
264 : {
265 0 : ScRange aDestRange;
266 0 : pDestData->GetArea(aDestRange);
267 0 : MarkRange( aDestRange );
268 : }
269 : }
270 :
271 6 : if (!bCopy)
272 : {
273 6 : UpdateScrollBars();
274 6 : SelectionChanged(); // for attribute states (filtered rows are ignored)
275 : }
276 :
277 6 : GetViewData().GetBindings().Invalidate( SID_UNFILTER );
278 6 : }
279 6 : }
280 :
281 : // autofilter-buttons show / hide
282 :
283 0 : void ScDBFunc::ToggleAutoFilter()
284 : {
285 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
286 0 : ScDocShellModificator aModificator( *pDocSh );
287 :
288 0 : ScQueryParam aParam;
289 0 : ScDocument* pDoc = GetViewData().GetDocument();
290 0 : ScDBData* pDBData = GetDBData(false, SC_DB_MAKE, SC_DBSEL_ROW_DOWN);
291 :
292 0 : pDBData->SetByRow( true ); //! undo, retrieve beforehand ??
293 0 : pDBData->GetQueryParam( aParam );
294 :
295 : SCCOL nCol;
296 0 : SCROW nRow = aParam.nRow1;
297 0 : SCTAB nTab = GetViewData().GetTabNo();
298 : sal_Int16 nFlag;
299 0 : bool bHasAuto = true;
300 0 : bool bHeader = pDBData->HasHeader();
301 0 : bool bPaint = false;
302 :
303 : //! instead retrieve from DB-range?
304 :
305 0 : for (nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAuto; nCol++)
306 : {
307 : nFlag = static_cast<const ScMergeFlagAttr*>( pDoc->
308 0 : GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
309 :
310 0 : if ( (nFlag & SC_MF_AUTO) == 0 )
311 0 : bHasAuto = false;
312 : }
313 :
314 0 : if (bHasAuto) // remove
315 : {
316 : // hide filter buttons
317 :
318 0 : for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
319 : {
320 : nFlag = static_cast<const ScMergeFlagAttr*>( pDoc->
321 0 : GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
322 0 : pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag & ~SC_MF_AUTO ) );
323 : }
324 :
325 : // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
326 :
327 0 : OUString aUndo = ScGlobal::GetRscString( STR_UNDO_QUERY );
328 0 : pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
329 :
330 0 : ScRange aRange;
331 0 : pDBData->GetArea( aRange );
332 0 : pDocSh->GetUndoManager()->AddUndoAction(
333 0 : new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), false ) );
334 :
335 0 : pDBData->SetAutoFilter(false);
336 :
337 : // remove filter (incl. Paint / Undo)
338 :
339 0 : SCSIZE nEC = aParam.GetEntryCount();
340 0 : for (SCSIZE i=0; i<nEC; i++)
341 0 : aParam.GetEntry(i).bDoQuery = false;
342 0 : aParam.bDuplicate = true;
343 0 : Query( aParam, NULL, true );
344 :
345 0 : pDocSh->GetUndoManager()->LeaveListAction();
346 :
347 0 : bPaint = true;
348 : }
349 : else // show filter buttons
350 : {
351 0 : if ( !pDoc->IsBlockEmpty( nTab,
352 : aParam.nCol1, aParam.nRow1,
353 0 : aParam.nCol2, aParam.nRow2 ) )
354 : {
355 0 : if (!bHeader)
356 : {
357 0 : if ( MessBox( GetViewData().GetDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
358 0 : ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ), // "StarCalc"
359 0 : ScGlobal::GetRscString( STR_MSSG_MAKEAUTOFILTER_0 ) // header from first row?
360 0 : ).Execute() == RET_YES )
361 : {
362 0 : pDBData->SetHeader( true ); //! Undo ??
363 0 : bHeader = true;
364 : }
365 : }
366 :
367 0 : ScRange aRange;
368 0 : pDBData->GetArea( aRange );
369 0 : pDocSh->GetUndoManager()->AddUndoAction(
370 0 : new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), true ) );
371 :
372 0 : pDBData->SetAutoFilter(true);
373 :
374 0 : for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
375 : {
376 : nFlag = static_cast<const ScMergeFlagAttr*>( pDoc->
377 0 : GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
378 0 : pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag | SC_MF_AUTO ) );
379 : }
380 : pDocSh->PostPaint(ScRange(aParam.nCol1, nRow, nTab, aParam.nCol2, nRow, nTab),
381 0 : PAINT_GRID);
382 0 : bPaint = true;
383 : }
384 : else
385 : {
386 0 : MessageDialog aErrorBox(GetViewData().GetDialogParent(),
387 0 : ScGlobal::GetRscString(STR_ERR_AUTOFILTER));
388 0 : aErrorBox.Execute();
389 : }
390 : }
391 :
392 0 : if ( bPaint )
393 : {
394 0 : aModificator.SetDocumentModified();
395 :
396 0 : SfxBindings& rBindings = GetViewData().GetBindings();
397 0 : rBindings.Invalidate( SID_AUTO_FILTER );
398 0 : rBindings.Invalidate( SID_AUTOFILTER_HIDE );
399 0 : }
400 0 : }
401 :
402 : // just hide, no data change
403 :
404 0 : void ScDBFunc::HideAutoFilter()
405 : {
406 0 : ScDocShell* pDocSh = GetViewData().GetDocShell();
407 0 : ScDocShellModificator aModificator( *pDocSh );
408 :
409 0 : ScDocument& rDoc = pDocSh->GetDocument();
410 :
411 0 : ScQueryParam aParam;
412 0 : ScDBData* pDBData = GetDBData( false );
413 :
414 : SCTAB nTab;
415 : SCCOL nCol1, nCol2;
416 : SCROW nRow1, nRow2;
417 0 : pDBData->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
418 :
419 0 : for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
420 : {
421 : sal_Int16 nFlag = static_cast<const ScMergeFlagAttr*>( rDoc.
422 0 : GetAttr( nCol, nRow1, nTab, ATTR_MERGE_FLAG ))->GetValue();
423 0 : rDoc.ApplyAttr( nCol, nRow1, nTab, ScMergeFlagAttr( nFlag & ~SC_MF_AUTO ) );
424 : }
425 :
426 0 : ScRange aRange;
427 0 : pDBData->GetArea( aRange );
428 0 : pDocSh->GetUndoManager()->AddUndoAction(
429 0 : new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), false ) );
430 :
431 0 : pDBData->SetAutoFilter(false);
432 :
433 0 : pDocSh->PostPaint(ScRange(nCol1, nRow1, nTab, nCol2, nRow1, nTab), PAINT_GRID );
434 0 : aModificator.SetDocumentModified();
435 :
436 0 : SfxBindings& rBindings = GetViewData().GetBindings();
437 0 : rBindings.Invalidate( SID_AUTO_FILTER );
438 0 : rBindings.Invalidate( SID_AUTOFILTER_HIDE );
439 0 : }
440 :
441 : // Re-Import
442 :
443 0 : bool ScDBFunc::ImportData( const ScImportParam& rParam, bool bRecord )
444 : {
445 0 : ScDocument* pDoc = GetViewData().GetDocument();
446 0 : ScEditableTester aTester( pDoc, GetViewData().GetTabNo(), rParam.nCol1,rParam.nRow1,
447 0 : rParam.nCol2,rParam.nRow2 );
448 0 : if ( !aTester.IsEditable() )
449 : {
450 0 : ErrorMessage(aTester.GetMessageId());
451 0 : return false;
452 : }
453 :
454 0 : ScDBDocFunc aDBDocFunc( *GetViewData().GetDocShell() );
455 0 : return aDBDocFunc.DoImport( GetViewData().GetTabNo(), rParam, NULL, bRecord );
456 228 : }
457 :
458 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|