Files
libreoffice/sc/source/ui/docshell/dbdocfun.cxx

1502 lines
55 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2000-09-18 16:07:07 +00:00
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2000-09-18 16:07:07 +00:00
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
2000-09-18 16:07:07 +00:00
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 16:07:07 +00:00
*
* This file is part of OpenOffice.org.
2000-09-18 16:07:07 +00:00
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
2000-09-18 16:07:07 +00:00
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
2000-09-18 16:07:07 +00:00
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
2000-09-18 16:07:07 +00:00
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
2000-09-18 16:07:07 +00:00
// INCLUDE ---------------------------------------------------------------
#include <sfx2/app.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/waitobj.hxx>
#include <com/sun/star/sdbc/XResultSet.hpp>
2000-09-18 16:07:07 +00:00
#include "dbdocfun.hxx"
#include "sc.hrc"
#include "dbcolect.hxx"
#include "undodat.hxx"
#include "docsh.hxx"
#include "docfunc.hxx"
#include "globstr.hrc"
#include "tabvwsh.hxx"
#include "patattr.hxx"
#include "rangenam.hxx"
#include "olinetab.hxx"
#include "dpobject.hxx"
#include "dociter.hxx" // for lcl_EmptyExcept
#include "cell.hxx" // for lcl_EmptyExcept
#include "editable.hxx"
#include "attrib.hxx"
#include "drwlayer.hxx"
CWS-TOOLING: integrate CWS calc50 2009-05-28 12:32:46 +0200 nn r272399 : gcc warning 2009-05-28 10:56:48 +0200 nn r272382 : CWS-TOOLING: rebase CWS calc50 to trunk@272291 (milestone: DEV300:m49) 2009-05-27 14:24:52 +0200 nn r272343 : #i50825# DataPilotUpdate: prevent overwriting source data above the table 2009-05-26 18:29:21 +0200 nn r272316 : #i50019# allow borders for multiple cell ranges 2009-05-26 13:43:36 +0200 nn r272300 : #i101960# UpdateExternalRefLinks: set document modified 2009-05-25 18:01:23 +0200 nn r272267 : #i102056# copied from CWS calc311fixes 2009-05-20 12:24:22 +0200 nn r272114 : #i59672# ExecFilter/SC_AUTOFILTER_CUSTOM: select database range (patch from gaozm) 2009-05-15 18:24:44 +0200 nn r271961 : #i100544# correct ScTokenConversion::ConvertToTokenArray 2009-05-13 17:45:02 +0200 nn r271866 : #i101869# DeleteRange: before broadcasting, check if EndListening removed the note cells 2009-05-13 12:43:31 +0200 nn r271856 : #i101806# correct reference undo for inserting/deleting columns/rows across sheets 2009-05-11 18:44:46 +0200 nn r271783 : #i101725# don't copy hash_set with pointers from the other collection 2009-05-11 17:54:21 +0200 nn r271780 : #i101690# correct merge error in frmdlg integration 2009-05-07 15:28:55 +0200 nn r271674 : #i96940# check for negative count in fillAuto 2009-05-07 13:47:58 +0200 nn r271661 : #i101512# SetCompileForFAP is in formula::FormulaCompiler 2009-05-07 13:47:27 +0200 nn r271660 : #i101512# use SetCompileForFAP for CompileTokenArray 2009-05-05 18:47:03 +0200 nn r271551 : #i73074# RepeatDB: re-evaluate advanced filter source range 2009-05-05 18:23:21 +0200 nn r271546 : #i97857# use GetInputString for direct reference as validity range source 2009-05-05 17:38:23 +0200 nn r271538 : #i95834# better enable/disable handling of next/previous buttons (patch by cmc)
2009-06-15 10:46:14 +00:00
#include "dpshttab.hxx"
#include "hints.hxx"
2000-09-18 16:07:07 +00:00
// -----------------------------------------------------------------
BOOL ScDBDocFunc::AddDBRange( const String& rName, const ScRange& rRange, BOOL /* bApi */ )
2000-09-18 16:07:07 +00:00
{
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
ScDBCollection* pDocColl = pDoc->GetDBCollection();
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
ScDBCollection* pUndoColl = NULL;
if (bUndo)
pUndoColl = new ScDBCollection( *pDocColl );
2000-09-18 16:07:07 +00:00
ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(),
rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row() );
// #i55926# While loading XML, formula cells only have a single string token,
// so CompileDBFormula would never find any name (index) tokens, and would
// unnecessarily loop through all cells.
BOOL bCompile = !pDoc->IsImportingXML();
if ( bCompile )
pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
2000-09-18 16:07:07 +00:00
BOOL bOk = pDocColl->Insert( pNew );
if ( bCompile )
pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
2000-09-18 16:07:07 +00:00
if (!bOk)
{
delete pNew;
delete pUndoColl;
return FALSE;
}
if (bUndo)
{
ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
}
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
return TRUE;
}
BOOL ScDBDocFunc::DeleteDBRange( const String& rName, BOOL /* bApi */ )
2000-09-18 16:07:07 +00:00
{
BOOL bDone = FALSE;
ScDocument* pDoc = rDocShell.GetDocument();
ScDBCollection* pDocColl = pDoc->GetDBCollection();
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
USHORT nPos = 0;
if (pDocColl->SearchName( rName, nPos ))
{
ScDocShellModificator aModificator( rDocShell );
ScDBCollection* pUndoColl = NULL;
if (bUndo)
pUndoColl = new ScDBCollection( *pDocColl );
2000-09-18 16:07:07 +00:00
pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
pDocColl->AtFree( nPos );
pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
if (bUndo)
{
ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
}
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
bDone = TRUE;
}
return bDone;
}
BOOL ScDBDocFunc::RenameDBRange( const String& rOld, const String& rNew, BOOL /* bApi */ )
2000-09-18 16:07:07 +00:00
{
BOOL bDone = FALSE;
ScDocument* pDoc = rDocShell.GetDocument();
ScDBCollection* pDocColl = pDoc->GetDBCollection();
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
USHORT nPos = 0;
USHORT nDummy = 0;
if ( pDocColl->SearchName( rOld, nPos ) &&
!pDocColl->SearchName( rNew, nDummy ) )
{
ScDocShellModificator aModificator( rDocShell );
ScDBData* pData = (*pDocColl)[nPos];
ScDBData* pNewData = new ScDBData(*pData);
pNewData->SetName(rNew);
ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl );
pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
pDocColl->AtFree( nPos );
BOOL bInserted = pDocColl->Insert( pNewData );
if (!bInserted) // Fehler -> alten Zustand wiederherstellen
{
delete pNewData;
pDoc->SetDBCollection( pUndoColl ); // gehoert dann dem Dokument
}
pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
if (bInserted) // Einfuegen hat geklappt
{
if (bUndo)
{
ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
}
else
delete pUndoColl;
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
bDone = TRUE;
}
}
return bDone;
}
BOOL ScDBDocFunc::ModifyDBData( const ScDBData& rNewData, BOOL /* bApi */ )
2000-09-18 16:07:07 +00:00
{
BOOL bDone = FALSE;
ScDocument* pDoc = rDocShell.GetDocument();
ScDBCollection* pDocColl = pDoc->GetDBCollection();
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
USHORT nPos = 0;
if (pDocColl->SearchName( rNewData.GetName(), nPos ))
{
ScDocShellModificator aModificator( rDocShell );
ScDBData* pData = (*pDocColl)[nPos];
ScRange aOldRange, aNewRange;
pData->GetArea(aOldRange);
rNewData.GetArea(aNewRange);
BOOL bAreaChanged = ( aOldRange != aNewRange ); // dann muss neu compiliert werden
ScDBCollection* pUndoColl = NULL;
if (bUndo)
pUndoColl = new ScDBCollection( *pDocColl );
2000-09-18 16:07:07 +00:00
*pData = rNewData;
if (bAreaChanged)
pDoc->CompileDBFormula();
if (bUndo)
{
ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
}
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
bDone = TRUE;
}
return bDone;
}
// -----------------------------------------------------------------
BOOL ScDBDocFunc::RepeatDB( const String& rDBName, BOOL bRecord, BOOL bApi )
{
//! auch fuer ScDBFunc::RepeatDB benutzen!
BOOL bDone = FALSE;
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDBCollection* pColl = pDoc->GetDBCollection();
USHORT nIndex;
if ( pColl && pColl->SearchName( rDBName, nIndex ) )
{
ScDBData* pDBData = (*pColl)[nIndex];
ScQueryParam aQueryParam;
pDBData->GetQueryParam( aQueryParam );
BOOL bQuery = aQueryParam.GetEntry(0).bDoQuery;
ScSortParam aSortParam;
pDBData->GetSortParam( aSortParam );
BOOL bSort = aSortParam.bDoSort[0];
ScSubTotalParam aSubTotalParam;
pDBData->GetSubTotalParam( aSubTotalParam );
BOOL bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
if ( bQuery || bSort || bSubTotal )
{
BOOL bQuerySize = FALSE;
ScRange aOldQuery;
ScRange aNewQuery;
if (bQuery && !aQueryParam.bInplace)
{
ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
aQueryParam.nDestTab, TRUE );
if (pDest && pDest->IsDoSize())
{
pDest->GetArea( aOldQuery );
bQuerySize = TRUE;
}
}
SCTAB nTab;
SCCOL nStartCol;
SCROW nStartRow;
SCCOL nEndCol;
SCROW nEndRow;
2000-09-18 16:07:07 +00:00
pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
//! Undo nur benoetigte Daten ?
ScDocument* pUndoDoc = NULL;
ScOutlineTable* pUndoTab = NULL;
ScRangeName* pUndoRange = NULL;
ScDBCollection* pUndoDB = NULL;
if (bRecord)
{
SCTAB nTabCount = pDoc->GetTableCount();
2000-09-18 16:07:07 +00:00
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
if (pTable)
{
pUndoTab = new ScOutlineTable( *pTable );
// column/row state
SCCOLROW nOutStartCol, nOutEndCol;
SCCOLROW nOutStartRow, nOutEndRow;
2000-09-18 16:07:07 +00:00
pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0,
nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab,
IDF_NONE, FALSE, pUndoDoc );
pDoc->CopyToDocument( 0, static_cast<SCROW>(nOutStartRow),
nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab,
IDF_NONE, FALSE, pUndoDoc );
2000-09-18 16:07:07 +00:00
}
else
pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
// Datenbereich sichern - incl. Filter-Ergebnis
pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, FALSE, pUndoDoc );
// alle Formeln wegen Referenzen
pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, FALSE, pUndoDoc );
// DB- und andere Bereiche
ScRangeName* pDocRange = pDoc->GetRangeName();
if (pDocRange->GetCount())
pUndoRange = new ScRangeName( *pDocRange );
ScDBCollection* pDocDB = pDoc->GetDBCollection();
if (pDocDB->GetCount())
pUndoDB = new ScDBCollection( *pDocDB );
}
if (bSort && bSubTotal)
{
// Sortieren ohne SubTotals
aSubTotalParam.bRemoveOnly = TRUE; // wird unten wieder zurueckgesetzt
DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi );
}
if (bSort)
{
pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
Sort( nTab, aSortParam, FALSE, FALSE, bApi );
}
if (bQuery)
{
pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
ScRange aAdvSource;
if (pDBData->GetAdvancedQuerySource(aAdvSource))
Query( nTab, aQueryParam, &aAdvSource, FALSE, bApi );
else
Query( nTab, aQueryParam, NULL, FALSE, bApi );
// bei nicht-inplace kann die Tabelle umgestellt worden sein
// if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
// SetTabNo( nTab );
}
if (bSubTotal)
{
pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
aSubTotalParam.bRemoveOnly = FALSE;
DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi );
}
if (bRecord)
{
SCTAB nDummyTab;
SCCOL nDummyCol;
SCROW nDummyRow;
SCROW nNewEndRow;
pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
2000-09-18 16:07:07 +00:00
const ScRange* pOld = NULL;
const ScRange* pNew = NULL;
if (bQuerySize)
{
ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
aQueryParam.nDestTab, TRUE );
if (pDest)
{
pDest->GetArea( aNewQuery );
pOld = &aOldQuery;
pNew = &aNewQuery;
}
}
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoRepeatDB( &rDocShell, nTab,
nStartCol, nStartRow, nEndCol, nEndRow,
nNewEndRow,
//nCurX, nCurY,
nStartCol, nStartRow,
pUndoDoc, pUndoTab,
pUndoRange, pUndoDB,
pOld, pNew ) );
}
rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
bDone = TRUE;
}
else if (!bApi) // "Keine Operationen auszufuehren"
rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
}
return bDone;
}
// -----------------------------------------------------------------
BOOL ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
2000-09-18 16:07:07 +00:00
BOOL bRecord, BOOL bPaint, BOOL bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
SCTAB nSrcTab = nTab;
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
2000-09-18 16:07:07 +00:00
ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
rSortParam.nCol2, rSortParam.nRow2 );
if (!pDBData)
{
DBG_ERROR( "Sort: keine DBData" );
return FALSE;
}
ScDBData* pDestData = NULL;
ScRange aOldDest;
BOOL bCopy = !rSortParam.bInplace;
if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
bCopy = FALSE;
ScSortParam aLocalParam( rSortParam );
if ( bCopy )
{
aLocalParam.MoveToDest();
if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PASTE_FULL);
return FALSE;
}
2000-09-18 16:07:07 +00:00
nTab = rSortParam.nDestTab;
pDestData = pDoc->GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow,
rSortParam.nDestTab, TRUE );
if (pDestData)
pDestData->GetArea(aOldDest);
}
ScEditableTester aTester( pDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1,
aLocalParam.nCol2,aLocalParam.nRow2 );
if (!aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
return FALSE;
}
if ( aLocalParam.bIncludePattern && pDoc->HasAttrib(
aLocalParam.nCol1, aLocalParam.nRow1, nTab,
aLocalParam.nCol2, aLocalParam.nRow2, nTab,
HASATTR_MERGED | HASATTR_OVERLAPPED ) )
{
// Merge-Attribute wuerden beim Sortieren durcheinanderkommen
if (!bApi)
rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
return FALSE;
}
// ausfuehren
WaitObject aWait( rDocShell.GetActiveDialogParent() );
2000-09-18 16:07:07 +00:00
BOOL bRepeatQuery = FALSE; // bestehenden Filter wiederholen?
ScQueryParam aQueryParam;
pDBData->GetQueryParam( aQueryParam );
if ( aQueryParam.GetEntry(0).bDoQuery )
bRepeatQuery = TRUE;
if (bRepeatQuery && bCopy)
{
if ( aQueryParam.bInplace ||
aQueryParam.nDestCol != rSortParam.nDestCol ||
aQueryParam.nDestRow != rSortParam.nDestRow ||
aQueryParam.nDestTab != rSortParam.nDestTab ) // Query auf selben Zielbereich?
bRepeatQuery = FALSE;
}
ScUndoSort* pUndoAction = 0;
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
// Referenzen ausserhalb des Bereichs werden nicht veraendert !
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
// Zeilenhoehen immer (wegen automatischer Anpassung)
//! auf ScBlockUndo umstellen
pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
/* #i59745# Do not copy note captions to undo document. All existing
caption objects will be repositioned while sorting which is tracked
in drawing undo. When undo is executed, the old positions will be
restored, and the cells with the old notes (which still refer to the
existing captions) will be copied back into the source document. */
2000-09-18 16:07:07 +00:00
pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
aLocalParam.nCol2, aLocalParam.nRow2, nTab,
IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
2000-09-18 16:07:07 +00:00
const ScRange* pR = 0;
if (pDestData)
{
/* #i59745# Do not copy note captions from destination range to
undo document. All existing caption objects will be removed
which is tracked in drawing undo. When undo is executed, the
caption objects are reinserted with drawing undo, and the cells
with the old notes (which still refer to the existing captions)
will be copied back into the source document. */
pDoc->CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
2000-09-18 16:07:07 +00:00
pR = &aOldDest;
}
// Zeilenhoehen immer (wegen automatischer Anpassung)
//! auf ScBlockUndo umstellen
// if (bRepeatQuery)
2000-09-18 16:07:07 +00:00
pDoc->CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab,
IDF_NONE, FALSE, pUndoDoc );
ScDBCollection* pUndoDB = NULL;
ScDBCollection* pDocDB = pDoc->GetDBCollection();
if (pDocDB->GetCount())
pUndoDB = new ScDBCollection( *pDocDB );
pUndoAction = new ScUndoSort( &rDocShell, nTab, rSortParam, bRepeatQuery, pUndoDoc, pUndoDB, pR );
rDocShell.GetUndoManager()->AddUndoAction( pUndoAction );
2000-09-18 16:07:07 +00:00
// #i59745# collect all drawing undo actions affecting cell note captions
if( pDrawLayer )
pDrawLayer->BeginCalcUndo();
2000-09-18 16:07:07 +00:00
}
if ( bCopy )
{
if (pDestData)
pDoc->DeleteAreaTab(aOldDest, IDF_CONTENTS); // Zielbereich vorher loeschen
ScRange aSource( rSortParam.nCol1,rSortParam.nRow1,nSrcTab,
rSortParam.nCol2,rSortParam.nRow2,nSrcTab );
ScAddress aDest( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab );
rDocShell.GetDocFunc().MoveBlock( aSource, aDest, FALSE, FALSE, FALSE, TRUE );
}
// #105780# don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
if ( aLocalParam.bDoSort[0] )
pDoc->Sort( nTab, aLocalParam, bRepeatQuery );
2000-09-18 16:07:07 +00:00
BOOL bSave = TRUE;
if (bCopy)
{
ScSortParam aOldSortParam;
pDBData->GetSortParam( aOldSortParam );
if ( aOldSortParam.bDoSort[0] && aOldSortParam.bInplace ) // Inplace-Sortierung gemerkt?
{
bSave = FALSE;
aOldSortParam.nDestCol = rSortParam.nDestCol;
aOldSortParam.nDestRow = rSortParam.nDestRow;
aOldSortParam.nDestTab = rSortParam.nDestTab;
pDBData->SetSortParam( aOldSortParam ); // dann nur DestPos merken
}
}
if (bSave) // Parameter merken
{
pDBData->SetSortParam( rSortParam );
pDBData->SetHeader( rSortParam.bHasHeader ); //! ???
pDBData->SetByRow( rSortParam.bByRow ); //! ???
}
if (bCopy) // neuen DB-Bereich merken
{
// Tabelle umschalten von aussen (View)
//! SetCursor ??!?!
ScRange aDestPos( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
aLocalParam.nCol2, aLocalParam.nRow2, nTab );
ScDBData* pNewData;
if (pDestData)
pNewData = pDestData; // Bereich vorhanden -> anpassen
else // Bereich ab Cursor/Markierung wird angelegt
pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
2000-09-18 16:07:07 +00:00
if (pNewData)
{
pNewData->SetArea( nTab,
aLocalParam.nCol1,aLocalParam.nRow1,
aLocalParam.nCol2,aLocalParam.nRow2 );
pNewData->SetSortParam( aLocalParam );
pNewData->SetHeader( aLocalParam.bHasHeader ); //! ???
pNewData->SetByRow( aLocalParam.bByRow );
}
else
{
2000-09-18 16:07:07 +00:00
DBG_ERROR("Zielbereich nicht da");
}
2000-09-18 16:07:07 +00:00
}
ScRange aDirtyRange( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
aLocalParam.nCol2, aLocalParam.nRow2, nTab );
pDoc->SetDirty( aDirtyRange );
if (bPaint)
{
USHORT nPaint = PAINT_GRID;
SCCOL nStartX = aLocalParam.nCol1;
SCROW nStartY = aLocalParam.nRow1;
SCCOL nEndX = aLocalParam.nCol2;
SCROW nEndY = aLocalParam.nRow2;
2000-09-18 16:07:07 +00:00
if ( bRepeatQuery )
{
nPaint |= PAINT_LEFT;
nStartX = 0;
nEndX = MAXCOL;
}
if (pDestData)
{
if ( nEndX < aOldDest.aEnd.Col() )
nEndX = aOldDest.aEnd.Col();
if ( nEndY < aOldDest.aEnd.Row() )
nEndY = aOldDest.aEnd.Row();
}
rDocShell.PostPaint( nStartX, nStartY, nTab, nEndX, nEndY, nTab, nPaint );
}
// AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, bPaint );
2000-09-18 16:07:07 +00:00
rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab );
// #i59745# set collected drawing undo actions at sorting undo action
if( pUndoAction && pDrawLayer )
pUndoAction->SetDrawUndoAction( pDrawLayer->GetCalcUndo() );
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
return TRUE;
}
// -----------------------------------------------------------------
BOOL ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
2000-09-18 16:07:07 +00:00
const ScRange* pAdvSource, BOOL bRecord, BOOL bApi )
{
ScDocShellModificator aModificator( rDocShell );
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
rQueryParam.nCol2, rQueryParam.nRow2 );
if (!pDBData)
{
DBG_ERROR( "Query: keine DBData" );
return FALSE;
}
// Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
// (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
{
ScQueryParam aOldQuery;
pDBData->GetQueryParam(aOldQuery);
if (aOldQuery.bInplace)
{
// alte Filterung aufheben
SCSIZE nEC = aOldQuery.GetEntryCount();
for (SCSIZE i=0; i<nEC; i++)
2000-09-18 16:07:07 +00:00
aOldQuery.GetEntry(i).bDoQuery = FALSE;
aOldQuery.bDuplicate = TRUE;
Query( nTab, aOldQuery, NULL, bRecord, bApi );
}
}
ScQueryParam aLocalParam( rQueryParam ); // fuer Paint / Zielbereich
BOOL bCopy = !rQueryParam.bInplace; // kopiert wird in Table::Query
ScDBData* pDestData = NULL; // Bereich, in den kopiert wird
BOOL bDoSize = FALSE; // Zielgroesse anpassen (einf./loeschen)
SCCOL nFormulaCols = 0; // nur bei bDoSize
2000-09-18 16:07:07 +00:00
BOOL bKeepFmt = FALSE;
ScRange aOldDest;
ScRange aDestTotal;
if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
bCopy = FALSE;
SCTAB nDestTab = nTab;
2000-09-18 16:07:07 +00:00
if ( bCopy )
{
aLocalParam.MoveToDest();
nDestTab = rQueryParam.nDestTab;
if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_PASTE_FULL);
return FALSE;
}
2000-09-18 16:07:07 +00:00
ScEditableTester aTester( pDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
aLocalParam.nCol2,aLocalParam.nRow2);
if (!aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
return FALSE;
}
pDestData = pDoc->GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
rQueryParam.nDestTab, TRUE );
if (pDestData)
{
pDestData->GetArea( aOldDest );
aDestTotal=ScRange( rQueryParam.nDestCol,
rQueryParam.nDestRow,
nDestTab,
rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
nDestTab );
bDoSize = pDestData->IsDoSize();
// Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
{
SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // neben dem Bereich
SCROW nTestRow = rQueryParam.nDestRow +
2000-09-18 16:07:07 +00:00
( aLocalParam.bHasHeader ? 1 : 0 );
while ( nTestCol <= MAXCOL &&
pDoc->GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
++nTestCol, ++nFormulaCols;
}
bKeepFmt = pDestData->IsKeepFmt();
if ( bDoSize && !pDoc->CanFitBlock( aOldDest, aDestTotal ) )
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // kann keine Zeilen einfuegen
return FALSE;
}
}
}
// ausfuehren
WaitObject aWait( rDocShell.GetActiveDialogParent() );
2000-09-18 16:07:07 +00:00
BOOL bKeepSub = FALSE; // bestehende Teilergebnisse wiederholen?
ScSubTotalParam aSubTotalParam;
if (rQueryParam.GetEntry(0).bDoQuery) // nicht beim Aufheben
{
pDBData->GetSubTotalParam( aSubTotalParam ); // Teilergebnisse vorhanden?
if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
bKeepSub = TRUE;
}
ScDocument* pUndoDoc = NULL;
ScDBCollection* pUndoDB = NULL;
const ScRange* pOld = NULL;
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2000-09-18 16:07:07 +00:00
if (bCopy)
{
pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE );
pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
IDF_ALL, FALSE, pUndoDoc );
// Attribute sichern, falls beim Filtern mitkopiert
if (pDestData)
{
pDoc->CopyToDocument( aOldDest, IDF_ALL, FALSE, pUndoDoc );
pOld = &aOldDest;
}
}
else
{
pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
pDoc->CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab,
IDF_NONE, FALSE, pUndoDoc );
}
ScDBCollection* pDocDB = pDoc->GetDBCollection();
if (pDocDB->GetCount())
pUndoDB = new ScDBCollection( *pDocDB );
pDoc->BeginDrawUndo();
2000-09-18 16:07:07 +00:00
}
ScDocument* pAttribDoc = NULL;
ScRange aAttribRange;
if (pDestData) // Zielbereich loeschen
{
if ( bKeepFmt )
{
// kleinere der End-Spalten, Header+1 Zeile
aAttribRange = aOldDest;
if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
( aLocalParam.bHasHeader ? 1 : 0 ) );
// auch fuer aufgefuellte Formeln
aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
pAttribDoc = new ScDocument( SCDOCMODE_UNDO );
pAttribDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE );
pDoc->CopyToDocument( aAttribRange, IDF_ATTRIB, FALSE, pAttribDoc );
}
if ( bDoSize )
pDoc->FitBlock( aOldDest, aDestTotal );
else
pDoc->DeleteAreaTab(aOldDest, IDF_ALL); // einfach loeschen
}
// Filtern am Dokument ausfuehren
SCSIZE nCount = pDoc->Query( nTab, rQueryParam, bKeepSub );
2000-09-18 16:07:07 +00:00
if (bCopy)
{
aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
if (!aLocalParam.bHasHeader && nCount > 0)
2000-09-18 16:07:07 +00:00
--aLocalParam.nRow2;
if ( bDoSize )
{
// auf wirklichen Ergebnis-Bereich anpassen
// (das hier ist immer eine Verkleinerung)
ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
pDoc->FitBlock( aDestTotal, aNewDest, FALSE ); // FALSE - nicht loeschen
if ( nFormulaCols > 0 )
2000-09-18 16:07:07 +00:00
{
// Formeln ausfuellen
//! Undo (Query und Repeat) !!!
ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
ScRange aOldForm = aNewForm;
aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
pDoc->FitBlock( aOldForm, aNewForm, FALSE );
ScMarkData aMark;
aMark.SelectOneTable(nDestTab);
SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
2000-09-18 16:07:07 +00:00
pDoc->Fill( aLocalParam.nCol2+1, nFStartY,
aLocalParam.nCol2+nFormulaCols, nFStartY, aMark,
aLocalParam.nRow2 - nFStartY,
FILL_TO_BOTTOM, FILL_SIMPLE );
}
}
if ( pAttribDoc ) // gemerkte Attribute zurueckkopieren
{
// Header
if (aLocalParam.bHasHeader)
{
ScRange aHdrRange = aAttribRange;
aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, FALSE, pDoc );
}
// Daten
SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
2000-09-18 16:07:07 +00:00
{
const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
nCol, nAttrRow, nDestTab );
DBG_ASSERT(pSrcPattern,"Pattern ist 0");
if (pSrcPattern)
pDoc->ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
nDestTab, *pSrcPattern );
const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
if (pStyle)
pDoc->ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
nDestTab, *pStyle );
}
delete pAttribDoc;
}
}
// speichern: Inplace immer, sonst je nach Einstellung
// alter Inplace-Filter ist ggf. schon aufgehoben
BOOL bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
if (bSave) // merken
{
pDBData->SetQueryParam( rQueryParam );
pDBData->SetHeader( rQueryParam.bHasHeader ); //! ???
pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam
}
if (bCopy) // neuen DB-Bereich merken
{
// selektieren wird hinterher von aussen (dbfunc)
// momentan ueber DB-Bereich an der Zielposition, darum muss dort
// auf jeden Fall ein Bereich angelegt werden.
ScDBData* pNewData;
if (pDestData)
pNewData = pDestData; // Bereich vorhanden -> anpassen (immer!)
else // Bereich anlegen
pNewData = rDocShell.GetDBData(
ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
2000-09-18 16:07:07 +00:00
if (pNewData)
{
pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
aLocalParam.nCol2, aLocalParam.nRow2 );
// Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
// und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
}
else
{
2000-09-18 16:07:07 +00:00
DBG_ERROR("Zielbereich nicht da");
}
2000-09-18 16:07:07 +00:00
}
if (!bCopy)
{
pDoc->InvalidatePageBreaks(nTab);
2000-09-18 16:07:07 +00:00
pDoc->UpdatePageBreaks( nTab );
}
2000-09-18 16:07:07 +00:00
// #i23299# Subtotal functions depend on cell's filtered states.
ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, MAXCOL, aLocalParam.nRow2, nDestTab);
pDoc->SetSubTotalCellsDirty(aDirtyRange);
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
// create undo action after executing, because of drawing layer undo
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB,
pOld, bDoSize, pAdvSource ) );
}
2000-09-18 16:07:07 +00:00
if (bCopy)
{
SCCOL nEndX = aLocalParam.nCol2;
SCROW nEndY = aLocalParam.nRow2;
2000-09-18 16:07:07 +00:00
if (pDestData)
{
if ( aOldDest.aEnd.Col() > nEndX )
nEndX = aOldDest.aEnd.Col();
if ( aOldDest.aEnd.Row() > nEndY )
nEndY = aOldDest.aEnd.Row();
}
if (bDoSize)
nEndY = MAXROW;
rDocShell.PostPaint( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
nEndX, nEndY, nDestTab, PAINT_GRID );
}
else
rDocShell.PostPaint( 0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab,
PAINT_GRID | PAINT_LEFT );
aModificator.SetDocumentModified();
return TRUE;
}
// -----------------------------------------------------------------
BOOL ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
2000-09-18 16:07:07 +00:00
const ScSortParam* pForceNewSort, BOOL bRecord, BOOL bApi )
{
//! auch fuer ScDBFunc::DoSubTotals benutzen!
// dann bleibt aussen:
// - neuen Bereich (aus DBData) markieren
// - SelectionChanged (?)
BOOL bDo = !rParam.bRemoveOnly; // FALSE = nur loeschen
BOOL bRet = FALSE;
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
rParam.nCol2, rParam.nRow2 );
if (!pDBData)
{
DBG_ERROR( "SubTotals: keine DBData" );
return FALSE;
}
ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
if (!aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
if (!bApi)
rDocShell.ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
return FALSE;
}
if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
{
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
return FALSE;
}
BOOL bOk = TRUE;
if (rParam.bReplace)
if (pDoc->TestRemoveSubTotals( nTab, rParam ))
{
bOk = ( MessBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
2000-09-18 16:07:07 +00:00
// "StarCalc" "Daten loeschen?"
ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
== RET_YES );
}
if (bOk)
{
WaitObject aWait( rDocShell.GetActiveDialogParent() );
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( rDocShell );
ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
ScDocument* pUndoDoc = NULL;
ScOutlineTable* pUndoTab = NULL;
ScRangeName* pUndoRange = NULL;
ScDBCollection* pUndoDB = NULL;
if (bRecord) // alte Daten sichern
{
BOOL bOldFilter = bDo && rParam.bDoSort;
SCTAB nTabCount = pDoc->GetTableCount();
2000-09-18 16:07:07 +00:00
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
if (pTable)
{
pUndoTab = new ScOutlineTable( *pTable );
// column/row state
SCCOLROW nOutStartCol, nOutEndCol;
SCCOLROW nOutStartRow, nOutEndRow;
2000-09-18 16:07:07 +00:00
pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc );
2000-09-18 16:07:07 +00:00
pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc );
}
else
pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, bOldFilter );
// Datenbereich sichern - incl. Filter-Ergebnis
pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
IDF_ALL, FALSE, pUndoDoc );
// alle Formeln wegen Referenzen
pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
IDF_FORMULA, FALSE, pUndoDoc );
// DB- und andere Bereiche
ScRangeName* pDocRange = pDoc->GetRangeName();
if (pDocRange->GetCount())
pUndoRange = new ScRangeName( *pDocRange );
ScDBCollection* pDocDB = pDoc->GetDBCollection();
if (pDocDB->GetCount())
pUndoDB = new ScDBCollection( *pDocDB );
}
// pDoc->SetOutlineTable( nTab, NULL );
ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
if (pOut)
pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
if (rParam.bReplace)
pDoc->RemoveSubTotals( nTab, aNewParam );
BOOL bSuccess = TRUE;
if (bDo)
{
// Sortieren
if ( rParam.bDoSort || pForceNewSort )
{
pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
// Teilergebnis-Felder vor die Sortierung setzen
// (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
ScSortParam aOldSort;
pDBData->GetSortParam( aOldSort );
ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
Sort( nTab, aSortParam, FALSE, FALSE, bApi );
}
bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
}
ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
aNewParam.nCol2, aNewParam.nRow2, nTab );
pDoc->SetDirty( aDirtyRange );
if (bRecord)
{
// ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
rDocShell.GetUndoManager()->AddUndoAction(
new ScUndoSubTotals( &rDocShell, nTab,
rParam, aNewParam.nRow2,
pUndoDoc, pUndoTab, // pUndoDBData,
pUndoRange, pUndoDB ) );
}
if (!bSuccess)
{
// "Kann keine Zeilen einfuegen"
if (!bApi)
rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
}
// merken
pDBData->SetSubTotalParam( aNewParam );
pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
pDoc->CompileDBFormula();
rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
aModificator.SetDocumentModified();
bRet = bSuccess;
}
return bRet;
}
//==================================================================
BOOL lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept )
{
ScCellIterator aIter( pDoc, rRange );
ScBaseCell* pCell = aIter.GetFirst();
while (pCell)
{
if ( !pCell->IsBlank() ) // real content?
{
if ( !rExcept.In( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) ) )
return FALSE; // cell found
}
pCell = aIter.GetNext();
}
return TRUE; // nothing found - empty
}
2000-09-18 16:07:07 +00:00
BOOL ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
BOOL bRecord, BOOL bApi, BOOL bAllowMove )
2000-09-18 16:07:07 +00:00
{
ScDocShellModificator aModificator( rDocShell );
WaitObject aWait( rDocShell.GetActiveDialogParent() );
2000-09-18 16:07:07 +00:00
BOOL bDone = FALSE;
BOOL bUndoSelf = FALSE;
USHORT nErrId = 0;
ScDocument* pOldUndoDoc = NULL;
ScDocument* pNewUndoDoc = NULL;
ScDPObject* pUndoDPObj = NULL;
if ( bRecord && pOldObj )
pUndoDPObj = new ScDPObject( *pOldObj ); // copy old settings for undo
ScDocument* pDoc = rDocShell.GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
if ( !rDocShell.IsEditable() || pDoc->GetChangeTrack() )
2000-09-18 16:07:07 +00:00
{
// not recorded -> disallow
//! different error messages?
nErrId = STR_PROTECTIONERR;
}
if ( pOldObj && !nErrId )
{
ScRange aOldOut = pOldObj->GetOutRange();
ScEditableTester aTester( pDoc, aOldOut );
if ( !aTester.IsEditable() )
nErrId = aTester.GetMessageId();
2000-09-18 16:07:07 +00:00
}
if ( pNewObj && !nErrId )
{
// at least one cell at the output position must be editable
// -> check in advance
// (start of output range in pNewObj is valid)
ScRange aNewStart( pNewObj->GetOutRange().aStart );
ScEditableTester aTester( pDoc, aNewStart );
if ( !aTester.IsEditable() )
nErrId = aTester.GetMessageId();
2000-09-18 16:07:07 +00:00
}
ScDPObject* pDestObj = NULL;
if ( !nErrId )
{
if ( pOldObj && !pNewObj )
{
// delete table
ScRange aRange = pOldObj->GetOutRange();
SCTAB nTab = aRange.aStart.Tab();
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pOldUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc );
}
pDoc->DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(),
nTab, IDF_ALL );
pDoc->RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
aRange.aEnd.Col(), aRange.aEnd.Row(),
nTab, SC_MF_AUTO );
2000-09-18 16:07:07 +00:00
pDoc->GetDPCollection()->FreeTable( pOldObj ); // object is deleted here
2000-09-18 16:07:07 +00:00
rDocShell.PostPaintGridAll(); //! only necessary parts
rDocShell.PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), nTab,
aRange.aEnd.Col(), aRange.aEnd.Row(), nTab,
PAINT_GRID );
bDone = TRUE;
}
else if ( pNewObj )
{
if ( pOldObj )
{
if ( bRecord )
{
ScRange aRange = pOldObj->GetOutRange();
SCTAB nTab = aRange.aStart.Tab();
2000-09-18 16:07:07 +00:00
pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pOldUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc );
}
if ( pNewObj == pOldObj )
{
// refresh only - no settings modified
}
else
{
pNewObj->WriteSourceDataTo( *pOldObj ); // copy source data
ScDPSaveData* pData = pNewObj->GetSaveData();
DBG_ASSERT( pData, "no SaveData from living DPObject" );
if ( pData )
pOldObj->SetSaveData( *pData ); // copy SaveData
}
pDestObj = pOldObj;
pDestObj->SetAllowMove( bAllowMove );
2000-09-18 16:07:07 +00:00
}
else
{
// output range must be set at pNewObj
pDestObj = new ScDPObject( *pNewObj );
// #i94570# When changing the output position in the dialog, a new table is created
// with the settings from the old table, including the name.
// So we have to check for duplicate names here (before inserting).
if ( pDoc->GetDPCollection()->GetByName(pDestObj->GetName()) )
pDestObj->SetName( String() ); // ignore the invalid name, create a new name below
2000-09-18 16:07:07 +00:00
pDestObj->SetAlive(TRUE);
if ( !pDoc->GetDPCollection()->InsertNewTable(pDestObj) )
2000-09-18 16:07:07 +00:00
{
DBG_ERROR("cannot insert DPObject");
DELETEZ( pDestObj );
}
}
if ( pDestObj )
{
// #78541# create new database connection for "refresh"
// (and re-read column entry collections)
// so all changes take effect
if ( pNewObj == pOldObj && pDestObj->IsImportData() )
pDestObj->InvalidateSource();
2000-09-18 16:07:07 +00:00
pDestObj->InvalidateData(); // before getting the new output area
// make sure the table has a name (not set by dialog)
if ( !pDestObj->GetName().Len() )
pDestObj->SetName( pDoc->GetDPCollection()->CreateNewName() );
2011-01-13 23:10:37 -05:00
bool bOverflow = false;
ScRange aNewOut = pDestObj->GetNewOutputRange( bOverflow );
CWS-TOOLING: integrate CWS calc50 2009-05-28 12:32:46 +0200 nn r272399 : gcc warning 2009-05-28 10:56:48 +0200 nn r272382 : CWS-TOOLING: rebase CWS calc50 to trunk@272291 (milestone: DEV300:m49) 2009-05-27 14:24:52 +0200 nn r272343 : #i50825# DataPilotUpdate: prevent overwriting source data above the table 2009-05-26 18:29:21 +0200 nn r272316 : #i50019# allow borders for multiple cell ranges 2009-05-26 13:43:36 +0200 nn r272300 : #i101960# UpdateExternalRefLinks: set document modified 2009-05-25 18:01:23 +0200 nn r272267 : #i102056# copied from CWS calc311fixes 2009-05-20 12:24:22 +0200 nn r272114 : #i59672# ExecFilter/SC_AUTOFILTER_CUSTOM: select database range (patch from gaozm) 2009-05-15 18:24:44 +0200 nn r271961 : #i100544# correct ScTokenConversion::ConvertToTokenArray 2009-05-13 17:45:02 +0200 nn r271866 : #i101869# DeleteRange: before broadcasting, check if EndListening removed the note cells 2009-05-13 12:43:31 +0200 nn r271856 : #i101806# correct reference undo for inserting/deleting columns/rows across sheets 2009-05-11 18:44:46 +0200 nn r271783 : #i101725# don't copy hash_set with pointers from the other collection 2009-05-11 17:54:21 +0200 nn r271780 : #i101690# correct merge error in frmdlg integration 2009-05-07 15:28:55 +0200 nn r271674 : #i96940# check for negative count in fillAuto 2009-05-07 13:47:58 +0200 nn r271661 : #i101512# SetCompileForFAP is in formula::FormulaCompiler 2009-05-07 13:47:27 +0200 nn r271660 : #i101512# use SetCompileForFAP for CompileTokenArray 2009-05-05 18:47:03 +0200 nn r271551 : #i73074# RepeatDB: re-evaluate advanced filter source range 2009-05-05 18:23:21 +0200 nn r271546 : #i97857# use GetInputString for direct reference as validity range source 2009-05-05 17:38:23 +0200 nn r271538 : #i95834# better enable/disable handling of next/previous buttons (patch by cmc)
2009-06-15 10:46:14 +00:00
//! test for overlap with other data pilot tables
if( pOldObj )
{
const ScSheetSourceDesc* pSheetDesc = pOldObj->GetSheetDesc();
2011-01-21 14:59:06 -05:00
if( pSheetDesc && pSheetDesc->GetSourceRange().Intersects( aNewOut ) )
CWS-TOOLING: integrate CWS calc50 2009-05-28 12:32:46 +0200 nn r272399 : gcc warning 2009-05-28 10:56:48 +0200 nn r272382 : CWS-TOOLING: rebase CWS calc50 to trunk@272291 (milestone: DEV300:m49) 2009-05-27 14:24:52 +0200 nn r272343 : #i50825# DataPilotUpdate: prevent overwriting source data above the table 2009-05-26 18:29:21 +0200 nn r272316 : #i50019# allow borders for multiple cell ranges 2009-05-26 13:43:36 +0200 nn r272300 : #i101960# UpdateExternalRefLinks: set document modified 2009-05-25 18:01:23 +0200 nn r272267 : #i102056# copied from CWS calc311fixes 2009-05-20 12:24:22 +0200 nn r272114 : #i59672# ExecFilter/SC_AUTOFILTER_CUSTOM: select database range (patch from gaozm) 2009-05-15 18:24:44 +0200 nn r271961 : #i100544# correct ScTokenConversion::ConvertToTokenArray 2009-05-13 17:45:02 +0200 nn r271866 : #i101869# DeleteRange: before broadcasting, check if EndListening removed the note cells 2009-05-13 12:43:31 +0200 nn r271856 : #i101806# correct reference undo for inserting/deleting columns/rows across sheets 2009-05-11 18:44:46 +0200 nn r271783 : #i101725# don't copy hash_set with pointers from the other collection 2009-05-11 17:54:21 +0200 nn r271780 : #i101690# correct merge error in frmdlg integration 2009-05-07 15:28:55 +0200 nn r271674 : #i96940# check for negative count in fillAuto 2009-05-07 13:47:58 +0200 nn r271661 : #i101512# SetCompileForFAP is in formula::FormulaCompiler 2009-05-07 13:47:27 +0200 nn r271660 : #i101512# use SetCompileForFAP for CompileTokenArray 2009-05-05 18:47:03 +0200 nn r271551 : #i73074# RepeatDB: re-evaluate advanced filter source range 2009-05-05 18:23:21 +0200 nn r271546 : #i97857# use GetInputString for direct reference as validity range source 2009-05-05 17:38:23 +0200 nn r271538 : #i95834# better enable/disable handling of next/previous buttons (patch by cmc)
2009-06-15 10:46:14 +00:00
{
ScRange aOldRange = pOldObj->GetOutRange();
SCsROW nDiff = aOldRange.aStart.Row()-aNewOut.aStart.Row();
aNewOut.aStart.SetRow( aOldRange.aStart.Row() );
aNewOut.aEnd.SetRow( aNewOut.aEnd.Row()+nDiff );
if( !ValidRow( aNewOut.aStart.Row() ) || !ValidRow( aNewOut.aEnd.Row() ) )
bOverflow = TRUE;
}
}
if ( bOverflow )
{
// like with STR_PROTECTIONERR, use undo to reverse everything
DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
bUndoSelf = TRUE;
nErrId = STR_PIVOT_ERROR;
}
else
2000-09-18 16:07:07 +00:00
{
ScEditableTester aTester( pDoc, aNewOut );
if ( !aTester.IsEditable() )
{
// destination area isn't editable
//! reverse everything done so far, don't proceed
// quick solution: proceed to end, use undo action
// to reverse everything:
DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
bUndoSelf = TRUE;
nErrId = aTester.GetMessageId();
}
2000-09-18 16:07:07 +00:00
}
// test if new output area is empty except for old area
if ( !bApi )
{
BOOL bEmpty;
if ( pOldObj ) // OutRange of pOldObj (pDestObj) is still old area
bEmpty = lcl_EmptyExcept( pDoc, aNewOut, pOldObj->GetOutRange() );
else
bEmpty = pDoc->IsBlockEmpty( aNewOut.aStart.Tab(),
aNewOut.aStart.Col(), aNewOut.aStart.Row(),
aNewOut.aEnd.Col(), aNewOut.aEnd.Row() );
if ( !bEmpty )
{
QueryBox aBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
if (aBox.Execute() == RET_NO)
{
//! like above (not editable), use undo to reverse everything
DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
bUndoSelf = TRUE;
}
}
}
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
SCTAB nTab = aNewOut.aStart.Tab();
2000-09-18 16:07:07 +00:00
pNewUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pNewUndoDoc->InitUndo( pDoc, nTab, nTab );
pDoc->CopyToDocument( aNewOut, IDF_ALL, FALSE, pNewUndoDoc );
}
CWS-TOOLING: integrate CWS calc50 2009-05-28 12:32:46 +0200 nn r272399 : gcc warning 2009-05-28 10:56:48 +0200 nn r272382 : CWS-TOOLING: rebase CWS calc50 to trunk@272291 (milestone: DEV300:m49) 2009-05-27 14:24:52 +0200 nn r272343 : #i50825# DataPilotUpdate: prevent overwriting source data above the table 2009-05-26 18:29:21 +0200 nn r272316 : #i50019# allow borders for multiple cell ranges 2009-05-26 13:43:36 +0200 nn r272300 : #i101960# UpdateExternalRefLinks: set document modified 2009-05-25 18:01:23 +0200 nn r272267 : #i102056# copied from CWS calc311fixes 2009-05-20 12:24:22 +0200 nn r272114 : #i59672# ExecFilter/SC_AUTOFILTER_CUSTOM: select database range (patch from gaozm) 2009-05-15 18:24:44 +0200 nn r271961 : #i100544# correct ScTokenConversion::ConvertToTokenArray 2009-05-13 17:45:02 +0200 nn r271866 : #i101869# DeleteRange: before broadcasting, check if EndListening removed the note cells 2009-05-13 12:43:31 +0200 nn r271856 : #i101806# correct reference undo for inserting/deleting columns/rows across sheets 2009-05-11 18:44:46 +0200 nn r271783 : #i101725# don't copy hash_set with pointers from the other collection 2009-05-11 17:54:21 +0200 nn r271780 : #i101690# correct merge error in frmdlg integration 2009-05-07 15:28:55 +0200 nn r271674 : #i96940# check for negative count in fillAuto 2009-05-07 13:47:58 +0200 nn r271661 : #i101512# SetCompileForFAP is in formula::FormulaCompiler 2009-05-07 13:47:27 +0200 nn r271660 : #i101512# use SetCompileForFAP for CompileTokenArray 2009-05-05 18:47:03 +0200 nn r271551 : #i73074# RepeatDB: re-evaluate advanced filter source range 2009-05-05 18:23:21 +0200 nn r271546 : #i97857# use GetInputString for direct reference as validity range source 2009-05-05 17:38:23 +0200 nn r271538 : #i95834# better enable/disable handling of next/previous buttons (patch by cmc)
2009-06-15 10:46:14 +00:00
pDestObj->Output( aNewOut.aStart );
2000-09-18 16:07:07 +00:00
rDocShell.PostPaintGridAll(); //! only necessary parts
bDone = TRUE;
}
}
// else nothing (no old, no new)
}
if ( bRecord && bDone )
{
SfxUndoAction* pAction = new ScUndoDataPilot( &rDocShell,
pOldUndoDoc, pNewUndoDoc, pUndoDPObj, pDestObj, bAllowMove );
2000-09-18 16:07:07 +00:00
pOldUndoDoc = NULL;
pNewUndoDoc = NULL; // pointers are used in undo action
// pUndoDPObj is copied
if (bUndoSelf)
{
// use undo action to restore original state
//! prevent setting the document modified? (ScDocShellModificator)
pAction->Undo();
delete pAction;
bDone = FALSE;
}
else
rDocShell.GetUndoManager()->AddUndoAction( pAction );
}
delete pOldUndoDoc; // if not used for undo
delete pNewUndoDoc;
delete pUndoDPObj;
if (bDone)
{
// notify API objects
if (pDestObj)
pDoc->BroadcastUno( ScDataPilotModifiedHint( pDestObj->GetName() ) );
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
}
2000-09-18 16:07:07 +00:00
if ( nErrId && !bApi )
rDocShell.ErrorMessage( nErrId );
return bDone;
}
//==================================================================
//
// Datenbank-Import...
void ScDBDocFunc::UpdateImport( const String& rTarget, const String& rDBName,
const String& rTableName, const String& rStatement, BOOL bNative,
BYTE nType, const ::com::sun::star::uno::Reference<
::com::sun::star::sdbc::XResultSet >& xResultSet,
const SbaSelectionList* pSelection )
2000-09-18 16:07:07 +00:00
{
// Target ist jetzt einfach der Bereichsname
ScDocument* pDoc = rDocShell.GetDocument();
ScDBCollection& rDBColl = *pDoc->GetDBCollection();
ScDBData* pData = NULL;
2000-09-18 16:07:07 +00:00
ScImportParam aImportParam;
BOOL bFound = FALSE;
USHORT nCount = rDBColl.GetCount();
for (USHORT i=0; i<nCount && !bFound; i++)
{
pData = rDBColl[i];
if (pData->GetName() == rTarget)
bFound = TRUE;
}
if (!bFound)
{
InfoBox aInfoBox(rDocShell.GetActiveDialogParent(),
2000-09-18 16:07:07 +00:00
ScGlobal::GetRscString( STR_TARGETNOTFOUND ) );
aInfoBox.Execute();
return;
}
SCTAB nTab;
SCCOL nDummyCol;
SCROW nDummyRow;
pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
2000-09-18 16:07:07 +00:00
pData->GetImportParam( aImportParam );
BOOL bSql = ( rStatement.Len() != 0 );
aImportParam.aDBName = rDBName;
aImportParam.bSql = bSql;
aImportParam.aStatement = bSql ? rStatement : rTableName;
aImportParam.bNative = bNative;
aImportParam.nType = nType;
aImportParam.bImport = TRUE;
BOOL bContinue = DoImport( nTab, aImportParam, xResultSet, pSelection, TRUE );
2000-09-18 16:07:07 +00:00
// DB-Operationen wiederholen
ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
if (pViewSh)
{
ScRange aRange;
pData->GetArea(aRange);
pViewSh->MarkRange(aRange); // selektieren
if ( bContinue ) // #41905# Fehler beim Import -> Abbruch
{
// interne Operationen, wenn welche gespeichert
if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
pViewSh->RepeatDB();
// Pivottabellen die den Bereich als Quelldaten haben
rDocShell.RefreshPivotTables(aRange);
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */