xref: /trunk/main/sc/source/ui/view/dbfunc.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include "scitems.hxx"
36 #include <sfx2/app.hxx>
37 #include <sfx2/bindings.hxx>
38 #include <vcl/msgbox.hxx>
39 
40 #include <com/sun/star/sdbc/XResultSet.hpp>
41 
42 #include "dbfunc.hxx"
43 #include "docsh.hxx"
44 #include "attrib.hxx"
45 #include "sc.hrc"
46 #include "undodat.hxx"
47 #include "dbcolect.hxx"
48 #include "globstr.hrc"
49 #include "global.hxx"
50 #include "dbdocfun.hxx"
51 #include "editable.hxx"
52 
53 //==================================================================
54 
55 ScDBFunc::ScDBFunc( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
56     ScViewFunc( pParent, rDocSh, pViewShell )
57 {
58 }
59 
60 //UNUSED2008-05  ScDBFunc::ScDBFunc( Window* pParent, const ScDBFunc& rDBFunc, ScTabViewShell* pViewShell ) :
61 //UNUSED2008-05      ScViewFunc( pParent, rDBFunc, pViewShell )
62 //UNUSED2008-05  {
63 //UNUSED2008-05  }
64 
65 ScDBFunc::~ScDBFunc()
66 {
67 }
68 
69 //
70 //      Hilfsfunktionen
71 //
72 
73 void ScDBFunc::GotoDBArea( const String& rDBName )
74 {
75     ScDocument* pDoc = GetViewData()->GetDocument();
76     ScDBCollection* pDBCol = pDoc->GetDBCollection();
77 
78     sal_uInt16 nFoundAt = 0;
79     if ( pDBCol->SearchName( rDBName, nFoundAt ) )
80     {
81         ScDBData* pData = (*pDBCol)[nFoundAt];
82         DBG_ASSERT( pData, "GotoDBArea: Datenbankbereich nicht gefunden!" );
83 
84         if ( pData )
85         {
86             SCTAB nTab = 0;
87             SCCOL nStartCol = 0;
88             SCROW nStartRow = 0;
89             SCCOL nEndCol = 0;
90             SCROW nEndRow = 0;
91 
92             pData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
93             SetTabNo( nTab );
94 
95             MoveCursorAbs( nStartCol, nStartRow, ScFollowMode( SC_FOLLOW_JUMP ),
96                                sal_False, sal_False );  // bShift,bControl
97             DoneBlockMode();
98             InitBlockMode( nStartCol, nStartRow, nTab );
99             MarkCursor( nEndCol, nEndRow, nTab );
100             SelectionChanged();
101         }
102     }
103 }
104 
105 //  aktuellen Datenbereich fuer Sortieren / Filtern suchen
106 
107 ScDBData* ScDBFunc::GetDBData( sal_Bool bMark, ScGetDBMode eMode, ScGetDBSelection eSel )
108 {
109     ScDocShell* pDocSh = GetViewData()->GetDocShell();
110     ScDBData* pData = NULL;
111     ScRange aRange;
112     ScMarkType eMarkType = GetViewData()->GetSimpleArea(aRange);
113     if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
114     {
115         bool bShrinkColumnsOnly = false;
116         if (eSel == SC_DBSEL_ROW_DOWN)
117         {
118             // Don't alter row range, additional rows may have been selected on
119             // purpose to append data, or to have a fake header row.
120             bShrinkColumnsOnly = true;
121             // Select further rows only if only one row or a portion thereof is
122             // selected.
123             if (aRange.aStart.Row() != aRange.aEnd.Row())
124             {
125                 // If an area is selected shrink that to the actual used
126                 // columns, don't draw filter buttons for empty columns.
127                 eSel = SC_DBSEL_SHRINK_TO_USED_DATA;
128             }
129             else if (aRange.aStart.Col() == aRange.aEnd.Col())
130             {
131                 // One cell only, if it is not marked obtain entire used data
132                 // area.
133                 const ScMarkData& rMarkData = GetViewData()->GetMarkData();
134                 if (!(rMarkData.IsMarked() || rMarkData.IsMultiMarked()))
135                     eSel = SC_DBSEL_KEEP;
136             }
137         }
138         switch (eSel)
139         {
140             case SC_DBSEL_SHRINK_TO_SHEET_DATA:
141                 {
142                     // Shrink the selection to sheet data area.
143                     ScDocument* pDoc = pDocSh->GetDocument();
144                     SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
145                     SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
146                     if (pDoc->ShrinkToDataArea( aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2))
147                     {
148                         aRange.aStart.SetCol(nCol1);
149                         aRange.aEnd.SetCol(nCol2);
150                         aRange.aStart.SetRow(nRow1);
151                         aRange.aEnd.SetRow(nRow2);
152                     }
153                 }
154                 break;
155             case SC_DBSEL_SHRINK_TO_USED_DATA:
156             case SC_DBSEL_ROW_DOWN:
157                 {
158                     // Shrink the selection to actual used area.
159                     ScDocument* pDoc = pDocSh->GetDocument();
160                     SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
161                     SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
162                     bool bShrunk;
163                     pDoc->ShrinkToUsedDataArea( bShrunk, aRange.aStart.Tab(),
164                             nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly);
165                     if (bShrunk)
166                     {
167                         aRange.aStart.SetCol(nCol1);
168                         aRange.aEnd.SetCol(nCol2);
169                         aRange.aStart.SetRow(nRow1);
170                         aRange.aEnd.SetRow(nRow2);
171                     }
172                 }
173                 break;
174             default:
175                 ;   // nothing
176         }
177         pData = pDocSh->GetDBData( aRange, eMode, eSel );
178     }
179     else if ( eMode != SC_DB_OLD )
180         pData = pDocSh->GetDBData(
181                     ScRange( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
182                              GetViewData()->GetTabNo() ),
183                     eMode, SC_DBSEL_KEEP );
184 
185     if ( pData && bMark )
186     {
187         ScRange aFound;
188         pData->GetArea(aFound);
189         MarkRange( aFound, sal_False );
190     }
191     return pData;
192 }
193 
194 //  Datenbankbereiche aendern (Dialog)
195 
196 void ScDBFunc::NotifyCloseDbNameDlg( const ScDBCollection& rNewColl, const List& rDelAreaList )
197 {
198 
199     ScDocShell* pDocShell = GetViewData()->GetDocShell();
200     ScDocShellModificator aModificator( *pDocShell );
201     ScDocument* pDoc = pDocShell->GetDocument();
202     ScDBCollection* pOldColl = pDoc->GetDBCollection();
203     ScDBCollection* pUndoColl = NULL;
204     ScDBCollection* pRedoColl = NULL;
205     const sal_Bool bRecord (pDoc->IsUndoEnabled());
206 
207     long nDelCount = rDelAreaList.Count();
208     for (long nDelPos=0; nDelPos<nDelCount; nDelPos++)
209     {
210         ScRange* pEntry = (ScRange*) rDelAreaList.GetObject(nDelPos);
211 
212         if ( pEntry )
213         {
214             ScAddress& rStart = pEntry->aStart;
215             ScAddress& rEnd   = pEntry->aEnd;
216             pDocShell->DBAreaDeleted( rStart.Tab(),
217                                        rStart.Col(), rStart.Row(),
218                                        rEnd.Col(),   rEnd.Row() );
219 
220             //  Targets am SBA abmelden nicht mehr noetig
221         }
222     }
223 
224     if (bRecord)
225         pUndoColl = new ScDBCollection( *pOldColl );
226 
227     //  neue Targets am SBA anmelden nicht mehr noetig
228 
229     pDoc->CompileDBFormula( sal_True );     // CreateFormulaString
230     pDoc->SetDBCollection( new ScDBCollection( rNewColl ) );
231     pDoc->CompileDBFormula( sal_False );    // CompileFormulaString
232     pOldColl = NULL;
233     pDocShell->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID );
234     aModificator.SetDocumentModified();
235     SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
236 
237     if (bRecord)
238     {
239         pRedoColl = new ScDBCollection( rNewColl );
240         pDocShell->GetUndoManager()->AddUndoAction(
241             new ScUndoDBData( pDocShell, pUndoColl, pRedoColl ) );
242     }
243 }
244 
245 //
246 //      wirkliche Funktionen
247 //
248 
249 // Sortieren
250 
251 void ScDBFunc::UISort( const ScSortParam& rSortParam, sal_Bool bRecord )
252 {
253     ScDocShell* pDocSh = GetViewData()->GetDocShell();
254     ScDocument* pDoc = pDocSh->GetDocument();
255     SCTAB nTab = GetViewData()->GetTabNo();
256     ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
257                                                     rSortParam.nCol2, rSortParam.nRow2 );
258     if (!pDBData)
259     {
260         DBG_ERROR( "Sort: keine DBData" );
261         return;
262     }
263 
264     ScSubTotalParam aSubTotalParam;
265     pDBData->GetSubTotalParam( aSubTotalParam );
266     if (aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly)
267     {
268         //  Subtotals wiederholen, mit neuer Sortierung
269 
270         DoSubTotals( aSubTotalParam, bRecord, &rSortParam );
271     }
272     else
273     {
274         Sort( rSortParam, bRecord );        // nur sortieren
275     }
276 }
277 
278 void ScDBFunc::Sort( const ScSortParam& rSortParam, sal_Bool bRecord, sal_Bool bPaint )
279 {
280     ScDocShell* pDocSh = GetViewData()->GetDocShell();
281     SCTAB nTab = GetViewData()->GetTabNo();
282     ScDBDocFunc aDBDocFunc( *pDocSh );
283     sal_Bool bSuccess = aDBDocFunc.Sort( nTab, rSortParam, bRecord, bPaint, sal_False );
284     if ( bSuccess && !rSortParam.bInplace )
285     {
286         //  Ziel markieren
287         ScRange aDestRange( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab,
288                             rSortParam.nDestCol + rSortParam.nCol2 - rSortParam.nCol1,
289                             rSortParam.nDestRow + rSortParam.nRow2 - rSortParam.nRow1,
290                             rSortParam.nDestTab );
291         MarkRange( aDestRange );
292     }
293 }
294 
295 //  Filtern
296 
297 void ScDBFunc::Query( const ScQueryParam& rQueryParam, const ScRange* pAdvSource, sal_Bool bRecord )
298 {
299     ScDocShell* pDocSh = GetViewData()->GetDocShell();
300     SCTAB nTab = GetViewData()->GetTabNo();
301     ScDBDocFunc aDBDocFunc( *pDocSh );
302     sal_Bool bSuccess = aDBDocFunc.Query( nTab, rQueryParam, pAdvSource, bRecord, sal_False );
303 
304     if (bSuccess)
305     {
306         sal_Bool bCopy = !rQueryParam.bInplace;
307         if (bCopy)
308         {
309             //  Zielbereich markieren (DB-Bereich wurde ggf. angelegt)
310             ScDocument* pDoc = pDocSh->GetDocument();
311             ScDBData* pDestData = pDoc->GetDBAtCursor(
312                                             rQueryParam.nDestCol, rQueryParam.nDestRow,
313                                             rQueryParam.nDestTab, sal_True );
314             if (pDestData)
315             {
316                 ScRange aDestRange;
317                 pDestData->GetArea(aDestRange);
318                 MarkRange( aDestRange );
319             }
320         }
321 
322         if (!bCopy)
323         {
324             UpdateScrollBars();
325             SelectionChanged();     // for attribute states (filtered rows are ignored)
326         }
327 
328         GetViewData()->GetBindings().Invalidate( SID_UNFILTER );
329     }
330 }
331 
332 //  Autofilter-Knoepfe ein-/ausblenden
333 
334 void ScDBFunc::ToggleAutoFilter()
335 {
336     ScDocShell* pDocSh = GetViewData()->GetDocShell();
337     ScDocShellModificator aModificator( *pDocSh );
338 
339     ScQueryParam    aParam;
340     ScDocument*     pDoc    = GetViewData()->GetDocument();
341     ScDBData*       pDBData = GetDBData( sal_False, SC_DB_MAKE, SC_DBSEL_ROW_DOWN );
342 
343     pDBData->SetByRow( sal_True );              //! Undo, vorher abfragen ??
344     pDBData->GetQueryParam( aParam );
345 
346 
347     SCCOL  nCol;
348     SCROW  nRow = aParam.nRow1;
349     SCTAB  nTab = GetViewData()->GetTabNo();
350     sal_Int16   nFlag;
351     sal_Bool    bHasAuto = sal_True;
352     sal_Bool    bHeader  = pDBData->HasHeader();
353     sal_Bool    bPaint   = sal_False;
354 
355     //!     stattdessen aus DB-Bereich abfragen?
356 
357     for (nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAuto; nCol++)
358     {
359         nFlag = ((ScMergeFlagAttr*) pDoc->
360                 GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
361 
362         if ( (nFlag & SC_MF_AUTO) == 0 )
363             bHasAuto = sal_False;
364     }
365 
366     if (bHasAuto)                               // aufheben
367     {
368         //  Filterknoepfe ausblenden
369 
370         for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
371         {
372             nFlag = ((ScMergeFlagAttr*) pDoc->
373                     GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
374             pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag & ~SC_MF_AUTO ) );
375         }
376 
377         // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
378 
379         String aUndo = ScGlobal::GetRscString( STR_UNDO_QUERY );
380         pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
381 
382         ScRange aRange;
383         pDBData->GetArea( aRange );
384         pDocSh->GetUndoManager()->AddUndoAction(
385             new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), sal_False ) );
386 
387         pDBData->SetAutoFilter(sal_False);
388 
389         //  Filter aufheben (incl. Paint / Undo)
390 
391         SCSIZE nEC = aParam.GetEntryCount();
392         for (SCSIZE i=0; i<nEC; i++)
393             aParam.GetEntry(i).bDoQuery = sal_False;
394         aParam.bDuplicate = sal_True;
395         Query( aParam, NULL, sal_True );
396 
397         pDocSh->GetUndoManager()->LeaveListAction();
398 
399         bPaint = sal_True;
400     }
401     else                                    // Filterknoepfe einblenden
402     {
403         if ( !pDoc->IsBlockEmpty( nTab,
404                                   aParam.nCol1, aParam.nRow1,
405                                   aParam.nCol2, aParam.nRow2 ) )
406         {
407             if (!bHeader)
408             {
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 )     // Koepfe aus erster Zeile?
412                     ).Execute() == RET_YES )
413                 {
414                     pDBData->SetHeader( sal_True );     //! Undo ??
415                     bHeader = sal_True;
416                 }
417             }
418 
419             ScRange aRange;
420             pDBData->GetArea( aRange );
421             pDocSh->GetUndoManager()->AddUndoAction(
422                 new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), sal_True ) );
423 
424             pDBData->SetAutoFilter(sal_True);
425 
426             for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
427             {
428                 nFlag = ((ScMergeFlagAttr*) pDoc->
429                         GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->GetValue();
430                 pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag | SC_MF_AUTO ) );
431             }
432             pDocSh->PostPaint( aParam.nCol1, nRow, nTab, aParam.nCol2, nRow, nTab,
433                                                      PAINT_GRID );
434             bPaint = sal_True;
435         }
436         else
437         {
438             ErrorBox aErrorBox( GetViewData()->GetDialogParent(), WinBits( WB_OK | WB_DEF_OK ),
439                                 ScGlobal::GetRscString( STR_ERR_AUTOFILTER ) );
440             aErrorBox.Execute();
441         }
442     }
443 
444     if ( bPaint )
445     {
446         aModificator.SetDocumentModified();
447 
448         SfxBindings& rBindings = GetViewData()->GetBindings();
449         rBindings.Invalidate( SID_AUTO_FILTER );
450         rBindings.Invalidate( SID_AUTOFILTER_HIDE );
451     }
452 }
453 
454 //      nur ausblenden, keine Daten veraendern
455 
456 void ScDBFunc::HideAutoFilter()
457 {
458     ScDocShell* pDocSh = GetViewData()->GetDocShell();
459     ScDocShellModificator aModificator( *pDocSh );
460 
461     ScDocument* pDoc = pDocSh->GetDocument();
462 
463     ScQueryParam aParam;
464     ScDBData* pDBData = GetDBData( sal_False );
465 
466     SCTAB nTab;
467     SCCOL nCol1, nCol2;
468     SCROW nRow1, nRow2;
469     pDBData->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
470 
471     for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
472     {
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 ) );
476     }
477 
478     ScRange aRange;
479     pDBData->GetArea( aRange );
480     pDocSh->GetUndoManager()->AddUndoAction(
481         new ScUndoAutoFilter( pDocSh, aRange, pDBData->GetName(), sal_False ) );
482 
483     pDBData->SetAutoFilter(sal_False);
484 
485     pDocSh->PostPaint( nCol1,nRow1,nTab, nCol2,nRow1,nTab, PAINT_GRID );
486     aModificator.SetDocumentModified();
487 
488     SfxBindings& rBindings = GetViewData()->GetBindings();
489     rBindings.Invalidate( SID_AUTO_FILTER );
490     rBindings.Invalidate( SID_AUTOFILTER_HIDE );
491 }
492 
493 //      Re-Import
494 
495 sal_Bool ScDBFunc::ImportData( const ScImportParam& rParam, sal_Bool bRecord )
496 {
497     ScDocument* pDoc = GetViewData()->GetDocument();
498     ScEditableTester aTester( pDoc, GetViewData()->GetTabNo(), rParam.nCol1,rParam.nRow1,
499                                                             rParam.nCol2,rParam.nRow2 );
500     if ( !aTester.IsEditable() )
501     {
502         ErrorMessage(aTester.GetMessageId());
503         return sal_False;
504     }
505 
506     ScDBDocFunc aDBDocFunc( *GetViewData()->GetDocShell() );
507     return aDBDocFunc.DoImport( GetViewData()->GetTabNo(), rParam, NULL, bRecord );
508 }
509 
510 
511 
512