xref: /aoo41x/main/sc/source/ui/view/dbfunc.cxx (revision cdf0e10c)
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