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