Files
libreoffice/sc/source/ui/view/viewfunc.cxx

2840 lines
99 KiB
C++
Raw Normal View History

2000-09-18 16:07:07 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 16:07:07 +00:00
*
* $RCSfile: viewfunc.cxx,v $
2000-09-18 16:07:07 +00:00
*
* $Revision: 1.39 $
2000-09-18 16:07:07 +00:00
*
* last change: $Author: obo $ $Date: 2008-01-10 13:21:43 $
2000-09-18 16:07:07 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-09-18 16:07:07 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-09-18 16:07:07 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-09-18 16:07:07 +00:00
*
* This library 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 for more details.
2000-09-18 16:07:07 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
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 "scitems.hxx"
#include <svx/eeitem.hxx>
#include <sfx2/app.hxx>
2000-09-18 16:07:07 +00:00
#include <svx/algitem.hxx>
#include <svx/boxitem.hxx>
#include <svx/editobj.hxx>
#include <svx/editview.hxx>
#include <svx/langitem.hxx>
#include <svx/scripttypeitem.hxx>
2000-09-18 16:07:07 +00:00
#include <sfx2/bindings.hxx>
#include <svtools/zforlist.hxx>
#include <svtools/zformat.hxx>
#include <vcl/msgbox.hxx>
#include <vcl/sound.hxx>
#include <vcl/virdev.hxx>
#include <vcl/waitobj.hxx>
#include <vcl/wrkwin.hxx>
#include <stdlib.h> // qsort
#include "viewfunc.hxx"
#include "tabvwsh.hxx"
#include "docsh.hxx"
#include "attrib.hxx"
#include "patattr.hxx"
#include "docpool.hxx"
#include "uiitems.hxx"
#include "sc.hrc"
#include "undocell.hxx"
#include "undoblk.hxx"
#include "undotab.hxx"
#include "refundo.hxx"
#include "dbcolect.hxx"
#include "olinetab.hxx"
#include "rangeutl.hxx"
#include "rangenam.hxx"
#include "globstr.hrc"
#include "global.hxx"
#include "stlsheet.hxx"
#include "editutil.hxx"
//CHINA001 #include "namecrea.hxx" // wegen Flags
2000-09-18 16:07:07 +00:00
#include "cell.hxx"
#include "scresid.hxx"
#include "inputhdl.hxx"
#include "scmod.hxx"
#include "inputopt.hxx"
#include "compiler.hxx"
#include "docfunc.hxx"
#include "appoptio.hxx"
#include "dociter.hxx"
#include "sizedev.hxx"
#include "editable.hxx"
#include "scui_def.hxx" //CHINA001
2000-09-18 16:07:07 +00:00
//==================================================================
ScViewFunc::ScViewFunc( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
ScTabView( pParent, rDocSh, pViewShell ),
bFormatValid( FALSE )
{
}
ScViewFunc::ScViewFunc( Window* pParent, const ScViewFunc& rViewFunc, ScTabViewShell* pViewShell ) :
ScTabView( pParent, rViewFunc, pViewShell ),
bFormatValid( FALSE )
{
}
ScViewFunc::~ScViewFunc()
{
}
//------------------------------------------------------------------------------------
void ScViewFunc::StartFormatArea()
{
// ueberhaupt aktiviert?
if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
return;
// start only with single cell (marked or cursor position)
ScRange aMarkRange;
BOOL bOk = GetViewData()->GetSimpleArea( aMarkRange );
if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
2000-09-18 16:07:07 +00:00
bOk = FALSE;
if (bOk)
{
bFormatValid = TRUE;
aFormatSource = aMarkRange.aStart;
aFormatArea = ScRange( aFormatSource );
2000-09-18 16:07:07 +00:00
}
else
bFormatValid = FALSE; // keinen alten Bereich behalten
}
BOOL ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, BOOL bAttrChanged )
2000-09-18 16:07:07 +00:00
{
// ueberhaupt aktiviert?
if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
return FALSE;
// Test: Eingabe mit Zahlformat (bAttrChanged) immer als neue Attributierung behandeln
// (alte Area verwerfen). Wenn das nicht gewollt ist, den if-Teil weglassen:
if ( bAttrChanged )
{
StartFormatArea();
return FALSE;
}
//! Abfrage, ob Zelle leer war ???
BOOL bFound = FALSE;
ScRange aNewRange = aFormatArea;
if ( bFormatValid && nTab == aFormatSource.Tab() )
{
if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
{
// innerhalb ?
if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
{
bFound = TRUE; // Bereich nicht aendern
}
// links ?
if ( nCol+1 == aFormatArea.aStart.Col() )
{
bFound = TRUE;
aNewRange.aStart.SetCol( nCol );
}
// rechts ?
if ( nCol == aFormatArea.aEnd.Col()+1 )
{
bFound = TRUE;
aNewRange.aEnd.SetCol( nCol );
}
}
if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
{
// oben ?
if ( nRow+1 == aFormatArea.aStart.Row() )
{
bFound = TRUE;
aNewRange.aStart.SetRow( nRow );
}
// unten ?
if ( nRow == aFormatArea.aEnd.Row()+1 )
{
bFound = TRUE;
aNewRange.aEnd.SetRow( nRow );
}
}
}
if (bFound)
aFormatArea = aNewRange; // erweitern
else
{
bFormatValid = FALSE; // ausserhalb -> abbrechen
if ( bAttrChanged ) // Wert mit Zahlformat eingegeben?
StartFormatArea(); // dann ggf. neu starten
}
return bFound;
}
void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
2000-09-18 16:07:07 +00:00
BOOL bAttrChanged, BOOL bAddUndo )
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
if (bAddUndo && !pDoc->IsUndoEnabled())
bAddUndo = FALSE;
2000-09-18 16:07:07 +00:00
const ScPatternAttr* pSource = pDoc->GetPattern(
aFormatSource.Col(), aFormatSource.Row(), nTab );
if ( !((const ScMergeAttr&)pSource->GetItem(ATTR_MERGE)).IsMerged() )
{
const ScPatternAttr* pDocOld = pDoc->GetPattern( nCol, nRow, nTab );
// pDocOld ist nur bis zum Apply... gueltig!
ScPatternAttr* pOldPattern = NULL;
if ( bAddUndo )
pOldPattern = new ScPatternAttr( *pDocOld );
const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
if ( pSrcStyle && pSrcStyle != pDocOld->GetStyleSheet() )
pDoc->ApplyStyle( nCol, nRow, nTab, *pSrcStyle );
pDoc->ApplyPattern( nCol, nRow, nTab, *pSource );
AdjustRowHeight( nRow, nRow, TRUE ); //! nicht doppelt ?
if ( bAddUndo )
{
const ScPatternAttr* pNewPattern = pDoc->GetPattern( nCol, nRow, nTab );
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoCursorAttr( pDocSh, nCol, nRow, nTab,
pOldPattern, pNewPattern, pSource,
TRUE ) );
delete pOldPattern; // wird im Undo kopiert (Pool)
}
}
if ( bAttrChanged ) // Wert mit Zahlformat eingegeben?
aFormatSource.Set( nCol, nRow, nTab ); // dann als neue Quelle
}
//------------------------------------------------------------------------------------
// Hilfsroutinen
USHORT ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, BOOL bFormula )
2000-09-18 16:07:07 +00:00
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
2000-09-18 16:07:07 +00:00
ScMarkData& rMark = GetViewData()->GetMarkData();
double nPPTX = GetViewData()->GetPPTX();
double nPPTY = GetViewData()->GetPPTY();
Fraction aZoomX = GetViewData()->GetZoomX();
Fraction aZoomY = GetViewData()->GetZoomY();
ScSizeDeviceProvider aProv(pDocSh);
if (aProv.IsPrinter())
{
nPPTX = aProv.GetPPTX();
nPPTY = aProv.GetPPTY();
aZoomX = aZoomY = Fraction( 1, 1 );
}
USHORT nTwips = pDoc->GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
2000-09-18 16:07:07 +00:00
return nTwips;
}
BOOL ScViewFunc::SelectionEditable( BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ )
{
BOOL bRet;
ScDocument* pDoc = GetViewData()->GetDocument();
ScMarkData& rMark = GetViewData()->GetMarkData();
if (rMark.IsMarked() || rMark.IsMultiMarked())
bRet = pDoc->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
else
{
SCCOL nCol = GetViewData()->GetCurX();
SCROW nRow = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
bRet = pDoc->IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
pOnlyNotBecauseOfMatrix );
}
return bRet;
}
#ifndef LRU_MAX
#define LRU_MAX 10
#endif
BOOL lcl_FunctionKnown( USHORT nOpCode )
{
const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
if ( pFuncList )
{
ULONG nCount = pFuncList->GetCount();
for (ULONG i=0; i<nCount; i++)
if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
return TRUE;
}
return FALSE;
}
BOOL lcl_AddFunction( ScAppOptions& rAppOpt, USHORT nOpCode )
{
USHORT nOldCount = rAppOpt.GetLRUFuncListCount();
USHORT* pOldList = rAppOpt.GetLRUFuncList();
USHORT nPos;
for (nPos=0; nPos<nOldCount; nPos++)
if (pOldList[nPos] == nOpCode) // is the function already in the list?
{
if ( nPos == 0 )
return FALSE; // already at the top -> no change
// count doesn't change, so the original array is modified
for (USHORT nCopy=nPos; nCopy>0; nCopy--)
pOldList[nCopy] = pOldList[nCopy-1];
pOldList[0] = nOpCode;
return TRUE; // list has changed
}
if ( !lcl_FunctionKnown( nOpCode ) )
return FALSE; // not in function list -> no change
USHORT nNewCount = Min( (USHORT)(nOldCount + 1), (USHORT)LRU_MAX );
USHORT nNewList[LRU_MAX];
nNewList[0] = nOpCode;
for (nPos=1; nPos<nNewCount; nPos++)
nNewList[nPos] = pOldList[nPos-1];
rAppOpt.SetLRUFuncList( nNewList, nNewCount );
return TRUE; // list has changed
}
// eigentliche Funktionen
// Eingabe - Undo OK
void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString,
2000-09-18 16:07:07 +00:00
BOOL bRecord )
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScMarkData& rMark = GetViewData()->GetMarkData();
SCTAB nTabCount = pDoc->GetTableCount();
SCTAB nSelCount = rMark.GetSelectCount();
SCTAB i;
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocShellModificator aModificator( *pDocSh );
ScEditableTester aTester( pDoc, nCol,nRow, nCol,nRow, rMark );
if (aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
BOOL bEditDeleted = FALSE;
BYTE nOldScript = 0;
2000-09-18 16:07:07 +00:00
ScBaseCell** ppOldCells = NULL;
BOOL* pHasFormat = NULL;
ULONG* pOldFormats = NULL;
SCTAB* pTabs = NULL;
SCTAB nUndoPos = 0;
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
ppOldCells = new ScBaseCell*[nSelCount];
pHasFormat = new BOOL[nSelCount];
pOldFormats = new ULONG[nSelCount];
pTabs = new SCTAB[nSelCount];
2000-09-18 16:07:07 +00:00
nUndoPos = 0;
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
{
pTabs[nUndoPos] = i;
ScBaseCell* pDocCell;
pDoc->GetCell( nCol, nRow, i, pDocCell );
if ( pDocCell )
{
ppOldCells[nUndoPos] = pDocCell->Clone(pDoc);
if ( pDocCell->GetCellType() == CELLTYPE_EDIT )
bEditDeleted = TRUE;
BYTE nDocScript = pDoc->GetScriptType( nCol, nRow, i, pDocCell );
if ( nOldScript == 0 )
nOldScript = nDocScript;
else if ( nDocScript != nOldScript )
bEditDeleted = TRUE;
2000-09-18 16:07:07 +00:00
}
else
{
ppOldCells[nUndoPos] = NULL;
}
const SfxPoolItem* pItem;
const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, i);
if ( SFX_ITEM_SET == pPattern->GetItemSet().GetItemState(
ATTR_VALUE_FORMAT,FALSE,&pItem) )
{
pHasFormat[nUndoPos] = TRUE;
pOldFormats[nUndoPos] = ((const SfxUInt32Item*)pItem)->GetValue();
}
else
pHasFormat[nUndoPos] = FALSE;
++nUndoPos;
}
DBG_ASSERT( nUndoPos==nSelCount, "nUndoPos!=nSelCount" );
}
bool bFormula = false;
// a single '=' character is handled as string (needed for special filters)
if ( rString.Len() > 1 )
{
if ( rString.GetChar(0) == '=' )
{
// handle as formula
bFormula = true;
}
else if ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' )
{
// if there is more than one leading '+' or '-' character, remove the additional ones
String aString( rString );
xub_StrLen nIndex = 1;
xub_StrLen nLen = aString.Len();
while ( nIndex < nLen && ( aString.GetChar( nIndex ) == '+' || aString.GetChar( nIndex ) == '-' ) )
{
++nIndex;
}
aString.Erase( 1, nIndex - 1 );
// if the remaining part without the leading '+' or '-' character
// is non-empty and not a number, handle as formula
if ( aString.Len() > 1 )
{
sal_uInt32 nFormat = 0;
pDoc->GetNumberFormat( nCol, nRow, nTab, nFormat );
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
double fNumber = 0;
if ( !pFormatter->IsNumberFormat( aString, nFormat, fNumber ) )
{
bFormula = true;
}
}
}
}
2000-09-18 16:07:07 +00:00
BOOL bNumFmtChanged = FALSE;
if ( bFormula )
2000-09-18 16:07:07 +00:00
{ // Formel, compile mit AutoCorrection
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
break;
ScAddress aPos( nCol, nRow, i );
ScCompiler aComp( pDoc, aPos );
//2do: AutoCorrection via CalcOptions abschaltbar machen
aComp.SetAutoCorrection( TRUE );
String aFormula( rString );
ScTokenArray* pArr;
BOOL bAgain;
do
{
bAgain = FALSE;
BOOL bAddEqual = FALSE;
ScTokenArray* pArrFirst = pArr = aComp.CompileString( aFormula );
BOOL bCorrected = aComp.IsCorrected();
if ( bCorrected )
{ // probieren, mit erster Parser-Korrektur neu zu parsen
pArr = aComp.CompileString( aComp.GetCorrectedFormula() );
}
if ( !pArr->GetError() )
{
bAddEqual = TRUE;
aComp.CompileTokenArray();
bCorrected |= aComp.IsCorrected();
}
if ( bCorrected )
{
String aCorrectedFormula;
if ( bAddEqual )
{
aCorrectedFormula = '=';
aCorrectedFormula += aComp.GetCorrectedFormula();
}
else
aCorrectedFormula = aComp.GetCorrectedFormula();
short nResult;
if ( aCorrectedFormula.Len() == 1 )
nResult = RET_NO; // leere Formel, nur '='
else
{
String aMessage( ScResId( SCSTR_FORMULA_AUTOCORRECTION ) );
aMessage += aCorrectedFormula;
nResult = QueryBox( GetViewData()->GetDialogParent(),
WinBits(WB_YES_NO | WB_DEF_YES),
aMessage ).Execute();
}
if ( nResult == RET_YES )
{
aFormula = aCorrectedFormula;
if ( pArr != pArrFirst )
delete pArrFirst;
bAgain = TRUE;
}
else
{
if ( pArr != pArrFirst )
{
delete pArr;
pArr = pArrFirst;
}
}
}
} while ( bAgain );
// um in mehreren Tabellen eingesetzt zu werden, muss die Formel
// via ScFormulaCell copy-ctor evtl. wegen RangeNames neu kompiliert
// werden, gleiches Code-Array fuer alle Zellen geht nicht.
// Wenn das Array einen Fehler enthaelt, muss in den neu erzeugten
// Zellen RPN geloescht und der Fehler explizit gesetzt werden, da
// via FormulaCell copy-ctor und Interpreter das, wenn moeglich,
// wieder glattgebuegelt wird, zu intelligent.. z.B.: =1))
USHORT nError = pArr->GetError();
if ( !nError )
{
// #68693# update list of recent functions with all functions that
// are not within parentheses
ScModule* pScMod = SC_MOD();
ScAppOptions aAppOpt = pScMod->GetAppOptions();
BOOL bOptChanged = FALSE;
ScToken** ppToken = pArr->GetArray();
USHORT nTokens = pArr->GetLen();
USHORT nLevel = 0;
for (USHORT nTP=0; nTP<nTokens; nTP++)
{
ScToken* pTok = ppToken[nTP];
OpCode eOp = pTok->GetOpCode();
if ( eOp == ocOpen )
++nLevel;
else if ( eOp == ocClose && nLevel )
--nLevel;
if ( nLevel == 0 && pTok->IsFunction() &&
lcl_AddFunction( aAppOpt, sal::static_int_cast<USHORT>( eOp ) ) )
2000-09-18 16:07:07 +00:00
bOptChanged = TRUE;
}
if ( bOptChanged )
{
pScMod->SetAppOptions(aAppOpt);
pScMod->RecentFunctionsChanged();
}
}
ScFormulaCell aCell( pDoc, aPos, pArr, 0 );
delete pArr;
BOOL bAutoCalc = pDoc->GetAutoCalc();
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
for ( ; i<nTabCount; i++)
{
if (rMark.GetTableSelect(i))
{
aPos.SetTab( i );
ULONG nIndex = (ULONG) ((SfxUInt32Item*) pDoc->GetAttr(
nCol, nRow, i, ATTR_VALUE_FORMAT ))->GetValue();
if ( pFormatter->GetType( nIndex ) == NUMBERFORMAT_TEXT ||
( ( rString.GetChar(0) == '+' || rString.GetChar(0) == '-' ) && nError && rString.Equals( aFormula ) ) )
2000-09-18 16:07:07 +00:00
{
ScStringCell* pCell = new ScStringCell( aFormula );
pDoc->PutCell( aPos, pCell );
}
else
{
ScFormulaCell* pCell = new ScFormulaCell( pDoc, aPos, aCell );
if ( nError )
{
pCell->GetCode()->DelRPN();
pCell->SetErrCode( nError );
if(pCell->GetCode()->IsHyperLink())
pCell->GetCode()->SetHyperLink(FALSE);
2000-09-18 16:07:07 +00:00
}
pDoc->PutCell( aPos, pCell );
if ( !bAutoCalc )
{ // einmal nur die Zelle berechnen und wieder dirty setzen
pCell->Interpret();
pCell->SetDirtyVar();
pDoc->PutInFormulaTree( pCell );
}
}
}
}
}
else
{
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
if (pDoc->SetString( nCol, nRow, i, rString ))
bNumFmtChanged = TRUE;
}
// row height must be changed if new text has a different script type
for (i=0; i<nTabCount && !bEditDeleted; i++)
if (rMark.GetTableSelect(i))
if ( pDoc->GetScriptType( nCol, nRow, i ) != nOldScript )
bEditDeleted = TRUE;
2000-09-18 16:07:07 +00:00
HideAllCursors();
if (bEditDeleted || pDoc->HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ))
AdjustRowHeight(nRow,nRow);
BOOL bAutoFormat = TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
if (bAutoFormat)
DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged, bRecord);
if ( bRecord )
{ // wg. ChangeTrack erst jetzt
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nUndoPos, pTabs,
ppOldCells, pHasFormat, pOldFormats,
rString, NULL ) );
}
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
pDocSh->PostPaintCell( nCol, nRow, i );
ShowAllCursors();
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
}
else
{
ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
PaintArea( nCol, nRow, nCol, nRow ); // da steht evtl. noch die Edit-Engine
}
}
// Wert in einzele Zelle eintragen (nur auf nTab)
//! umbenennen in EnterValue !!!!
void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
2000-09-18 16:07:07 +00:00
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
if ( pDoc && pDocSh )
{
ScDocShellModificator aModificator( *pDocSh );
ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
if (aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
ScBaseCell* pOldCell;
pDoc->GetCell( nCol, nRow, nTab, pOldCell );
BOOL bNeedHeight = ( pOldCell && pOldCell->GetCellType() == CELLTYPE_EDIT )
|| pDoc->HasAttrib(
nCol,nRow,nTab, nCol,nRow,nTab, HASATTR_NEEDHEIGHT );
// Undo
ScBaseCell* pUndoCell = NULL;
if (bUndo)
{
pUndoCell = pOldCell ? pOldCell->Clone(pDoc) : NULL;
}
2000-09-18 16:07:07 +00:00
pDoc->SetValue( nCol, nRow, nTab, rValue );
// wg. ChangeTrack nach Aenderung im Dokument
if (bUndo)
{
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoEnterValue( pDocSh, ScAddress(nCol,nRow,nTab),
pUndoCell, rValue, bNeedHeight ) );
}
2000-09-18 16:07:07 +00:00
/*! Zeilenhoehe anpassen? Dann auch bei Undo...
if (bNeedHeight)
AdjustRowHeight(nRow,nRow);
*/
pDocSh->PostPaintCell( nCol, nRow, nTab );
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
}
else
ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
}
}
void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const EditTextObject* pData,
2000-09-18 16:07:07 +00:00
BOOL bRecord, BOOL bTestSimple )
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScMarkData& rMark = GetViewData()->GetMarkData();
ScDocument* pDoc = pDocSh->GetDocument();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( *pDocSh );
ScEditableTester aTester( pDoc, nTab, nCol,nRow, nCol,nRow );
if (aTester.IsEditable())
2000-09-18 16:07:07 +00:00
{
//
// Test auf Attribute
//
BOOL bSimple = FALSE;
BOOL bCommon = FALSE;
ScPatternAttr* pCellAttrs = NULL;
EditTextObject* pNewData = NULL;
String aString;
if (bTestSimple) // Testen, ob einfacher String ohne Attribute
{
const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab );
ScTabEditEngine aEngine( *pOldPattern, pDoc->GetEnginePool() );
aEngine.SetText(*pData);
ScEditAttrTester aAttrTester( &aEngine );
bSimple = !aAttrTester.NeedsObject();
bCommon = aAttrTester.NeedsCellAttr();
2000-09-18 16:07:07 +00:00
// formulas have to be recognized even if they're formatted
// (but commmon attributes are still collected)
if ( !bSimple && aEngine.GetParagraphCount() == 1 )
{
String aParStr = aEngine.GetText( (USHORT) 0 );
if ( aParStr.GetChar(0) == '=' )
bSimple = TRUE;
}
2000-09-18 16:07:07 +00:00
if (bCommon) // Attribute fuer Tabelle
{
pCellAttrs = new ScPatternAttr( *pOldPattern );
pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
2000-09-18 16:07:07 +00:00
//! remove common attributes from EditEngine?
}
if (bSimple)
aString = aEngine.GetText();
}
//
// Undo
//
SCTAB nTabCount = pDoc->GetTableCount();
SCTAB nSelCount = rMark.GetSelectCount();
SCTAB i;
2000-09-18 16:07:07 +00:00
ScBaseCell** ppOldCells = NULL;
SCTAB* pTabs = NULL;
SCTAB nPos = 0;
2000-09-18 16:07:07 +00:00
EditTextObject* pUndoData = NULL;
if (bRecord && !bSimple)
{
ppOldCells = new ScBaseCell*[nSelCount];
pTabs = new SCTAB[nSelCount];
2000-09-18 16:07:07 +00:00
nPos = 0;
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
{
pTabs[nPos] = i;
ScBaseCell* pDocCell;
pDoc->GetCell( nCol, nRow, i, pDocCell );
if ( pDocCell )
ppOldCells[nPos] = pDocCell->Clone( pDoc );
else
ppOldCells[nPos] = NULL;
++nPos;
}
DBG_ASSERT( nPos==nSelCount, "nPos!=nSelCount" );
pUndoData = pData->Clone();
}
//
// Daten eintragen
//
if (bCommon)
pDoc->ApplyPattern(nCol,nRow,nTab,*pCellAttrs); //! Undo
if (bSimple)
{
if (bCommon)
AdjustRowHeight(nRow,nRow);
EnterData(nCol,nRow,nTab,aString,bRecord);
}
else
{
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
pDoc->PutCell( nCol, nRow, i, new ScEditCell( pData, pDoc, NULL ) );
if ( bRecord )
{ // wg. ChangeTrack erst jetzt
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nPos, pTabs,
ppOldCells, NULL, NULL, String(),
pUndoData ) );
}
HideAllCursors();
AdjustRowHeight(nRow,nRow);
for (i=0; i<nTabCount; i++)
if (rMark.GetTableSelect(i))
pDocSh->PostPaintCell( nCol, nRow, i );
ShowAllCursors();
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
}
delete pCellAttrs;
delete pNewData;
}
else
{
ErrorMessage(aTester.GetMessageId());
2000-09-18 16:07:07 +00:00
PaintArea( nCol, nRow, nCol, nRow ); // da steht evtl. noch die Edit-Engine
}
}
void ScViewFunc::EnterDataAtCursor( const String& rString )
{
SCCOL nPosX = GetViewData()->GetCurX();
SCROW nPosY = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
EnterData( nPosX, nPosY, nTab, rString );
}
void ScViewFunc::EnterMatrix( const String& rString )
{
ScViewData* pData = GetViewData();
const ScMarkData& rMark = pData->GetMarkData();
if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
{
// nichts markiert -> automatisch Block mit Groesse des Ergebnisses
// Formel temporaer berechnen, um an die Groesse heranzukommen
ScDocument* pDoc = pData->GetDocument();
SCCOL nCol = pData->GetCurX();
SCROW nRow = pData->GetCurY();
SCTAB nTab = pData->GetTabNo();
ScFormulaCell aFormCell( pDoc, ScAddress(nCol,nRow,nTab), rString, ScAddress::CONV_UNSPECIFIED, MM_FORMULA );
2000-09-18 16:07:07 +00:00
SCSIZE nSizeX;
SCSIZE nSizeY;
2000-09-18 16:07:07 +00:00
aFormCell.GetResultDimensions( nSizeX, nSizeY );
if ( nSizeX != 0 && nSizeY != 0 &&
nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(MAXCOL) &&
nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(MAXROW) )
2000-09-18 16:07:07 +00:00
{
ScRange aResult( nCol, nRow, nTab,
sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
2000-09-18 16:07:07 +00:00
MarkRange( aResult, FALSE );
}
}
ScRange aRange;
if (pData->GetSimpleArea(aRange))
{
ScDocShell* pDocSh = pData->GetDocShell();
BOOL bSuccess = pDocSh->GetDocFunc().EnterMatrix( aRange, &rMark, NULL, rString, FALSE, FALSE );
2000-09-18 16:07:07 +00:00
if (bSuccess)
pDocSh->UpdateOle(GetViewData());
}
else
ErrorMessage(STR_NOMULTISELECT);
}
BYTE ScViewFunc::GetSelectionScriptType()
{
BYTE nScript = 0;
ScDocument* pDoc = GetViewData()->GetDocument();
const ScMarkData& rMark = GetViewData()->GetMarkData();
if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
{
// no selection -> cursor
nScript = pDoc->GetScriptType( GetViewData()->GetCurX(),
GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
}
else
{
ScRangeList aRanges;
rMark.FillRangeListWithMarks( &aRanges, FALSE );
ULONG nCount = aRanges.Count();
for (ULONG i=0; i<nCount; i++)
{
ScRange aRange = *aRanges.GetObject(i);
ScCellIterator aIter( pDoc, aRange );
ScBaseCell* pCell = aIter.GetFirst();
while ( pCell )
{
nScript |= pDoc->GetScriptType( aIter.GetCol(), aIter.GetRow(), aIter.GetTab(), pCell );
pCell = aIter.GetNext();
}
}
}
if (nScript == 0)
nScript = ScGlobal::GetDefaultScriptType();
return nScript;
}
2000-09-18 16:07:07 +00:00
const ScPatternAttr* ScViewFunc::GetSelectionPattern()
{
// Don't use UnmarkFiltered in slot state functions, for performance reasons.
// The displayed state is always that of the whole selection including filtered rows.
2000-09-18 16:07:07 +00:00
const ScMarkData& rMark = GetViewData()->GetMarkData();
ScDocument* pDoc = GetViewData()->GetDocument();
if ( rMark.IsMarked() || rMark.IsMultiMarked() )
{
// MarkToMulti is no longer necessary for pDoc->GetSelectionPattern
2000-09-18 16:07:07 +00:00
const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( rMark );
return pAttr;
}
else
{
SCCOL nCol = GetViewData()->GetCurX();
SCROW nRow = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
ScMarkData aTempMark( rMark ); // copy sheet selection
2000-09-18 16:07:07 +00:00
aTempMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
const ScPatternAttr* pAttr = pDoc->GetSelectionPattern( aTempMark );
return pAttr;
}
}
void ScViewFunc::GetSelectionFrame( SvxBoxItem& rLineOuter,
SvxBoxInfoItem& rLineInner )
{
ScDocument* pDoc = GetViewData()->GetDocument();
const ScMarkData& rMark = GetViewData()->GetMarkData();
2000-09-18 16:07:07 +00:00
if ( rMark.IsMarked() || rMark.IsMultiMarked() )
{
if ( rMark.IsMultiMarked() )
{
ScMarkData aNewMark( rMark ); // use local copy for MarkToSimple
aNewMark.MarkToSimple(); // simple block is needed for GetSelectionFrame
pDoc->GetSelectionFrame( aNewMark, rLineOuter, rLineInner );
}
else
pDoc->GetSelectionFrame( rMark, rLineOuter, rLineInner );
2000-09-18 16:07:07 +00:00
}
else
{
const ScPatternAttr* pAttrs =
pDoc->GetPattern( GetViewData()->GetCurX(),
GetViewData()->GetCurY(),
GetViewData()->GetTabNo() );
rLineOuter = (const SvxBoxItem&) (pAttrs->GetItem( ATTR_BORDER ));
rLineInner = (const SvxBoxInfoItem&)(pAttrs->GetItem( ATTR_BORDER_INNER ));
rLineInner.SetTable(FALSE);
rLineInner.SetDist(TRUE);
2000-09-18 16:07:07 +00:00
rLineInner.SetMinDist(FALSE);
}
}
//
// Attribute anwenden - Undo OK
//
// kompletter Set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
//
void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
const SfxItemSet* pOldSet,
BOOL bRecord )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
ScPatternAttr aOldAttrs( new SfxItemSet(*pOldSet) );
ScPatternAttr aNewAttrs( new SfxItemSet(*pDialogSet) );
aNewAttrs.DeleteUnchanged( &aOldAttrs );
if ( pDialogSet->GetItemState( ATTR_VALUE_FORMAT ) == SFX_ITEM_SET )
{ // #82521# don't reset to default SYSTEM GENERAL if not intended
sal_uInt32 nOldFormat =
((const SfxUInt32Item&)pOldSet->Get( ATTR_VALUE_FORMAT )).GetValue();
sal_uInt32 nNewFormat =
((const SfxUInt32Item&)pDialogSet->Get( ATTR_VALUE_FORMAT )).GetValue();
if ( nNewFormat != nOldFormat )
2000-09-18 16:07:07 +00:00
{
SvNumberFormatter* pFormatter =
GetViewData()->GetDocument()->GetFormatTable();
const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
LanguageType eOldLang =
pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
LanguageType eNewLang =
pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
if ( eNewLang != eOldLang )
{
aNewAttrs.GetItemSet().Put(
SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
// #40606# nur die Sprache geaendert -> Zahlformat-Attribut nicht anfassen
sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
nNewMod <= SV_MAX_ANZ_STANDARD_FORMATE )
aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
}
2000-09-18 16:07:07 +00:00
}
}
const SvxBoxItem* pOldOuter = (const SvxBoxItem*) &pOldSet->Get( ATTR_BORDER );
const SvxBoxItem* pNewOuter = (const SvxBoxItem*) &pDialogSet->Get( ATTR_BORDER );
const SvxBoxInfoItem* pOldInner = (const SvxBoxInfoItem*) &pOldSet->Get( ATTR_BORDER_INNER );
const SvxBoxInfoItem* pNewInner = (const SvxBoxInfoItem*) &pDialogSet->Get( ATTR_BORDER_INNER );
SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
SfxItemPool* pNewPool = rNewSet.GetPool();
pNewPool->Put( *pNewOuter ); // noch nicht loeschen
pNewPool->Put( *pNewInner );
rNewSet.ClearItem( ATTR_BORDER );
rNewSet.ClearItem( ATTR_BORDER_INNER );
/*
* Feststellen, ob Rahmenattribute zu setzen sind:
* 1. Neu != Alt
* 2. Ist eine der Linien nicht-DontCare (seit 238.f: IsxxValid())
*
*/
BOOL bFrame = (pDialogSet->GetItemState( ATTR_BORDER ) != SFX_ITEM_DEFAULT)
|| (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SFX_ITEM_DEFAULT);
if ( pNewOuter==pOldOuter && pNewInner==pOldInner )
bFrame = FALSE;
// das sollte doch der Pool abfangen: ?!??!??
if ( bFrame && pNewOuter && pNewInner )
if ( *pNewOuter == *pOldOuter && *pNewInner == *pOldInner )
bFrame = FALSE;
if ( pNewInner )
{
bFrame = bFrame
&& ( pNewInner->IsValid(VALID_LEFT)
|| pNewInner->IsValid(VALID_RIGHT)
|| pNewInner->IsValid(VALID_TOP)
|| pNewInner->IsValid(VALID_BOTTOM)
|| pNewInner->IsValid(VALID_HORI)
|| pNewInner->IsValid(VALID_VERT) );
}
else
bFrame = FALSE;
if (!bFrame)
ApplySelectionPattern( aNewAttrs, bRecord ); // nur normale
else
{
// wenn neue Items Default-Items sind, so muessen die
// alten Items geputtet werden:
BOOL bDefNewOuter = ( SFX_ITEMS_STATICDEFAULT == pNewOuter->GetKind() );
BOOL bDefNewInner = ( SFX_ITEMS_STATICDEFAULT == pNewInner->GetKind() );
2000-09-18 16:07:07 +00:00
ApplyPatternLines( aNewAttrs,
bDefNewOuter ? pOldOuter : pNewOuter,
bDefNewInner ? pOldInner : pNewInner,
bRecord );
}
pNewPool->Remove( *pNewOuter ); // freigeben
pNewPool->Remove( *pNewInner );
// Hoehen anpassen
AdjustBlockHeight();
// CellContentChanged wird von ApplySelectionPattern / ApplyPatternLines gerufen
}
void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
ScPatternAttr aNewAttrs( new SfxItemSet( *GetViewData()->GetDocument()->GetPool(),
ATTR_PATTERN_START, ATTR_PATTERN_END ) );
aNewAttrs.GetItemSet().Put( rAttrItem );
// Wenn Ausrichtung eingestellt wird (ueber Buttons), immer Einzug 0
if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
aNewAttrs.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, 0 ) );
ApplySelectionPattern( aNewAttrs );
AdjustBlockHeight();
// CellContentChanged wird von ApplySelectionPattern gerufen
}
// Pattern und Rahmen
void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem* pNewOuter,
const SvxBoxInfoItem* pNewInner, BOOL bRecord )
{
ScDocument* pDoc = GetViewData()->GetDocument();
ScMarkData& rMark = GetViewData()->GetMarkData();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
SCCOL nStartCol;
SCROW nStartRow;
SCTAB nStartTab;
SCCOL nEndCol;
SCROW nEndRow;
SCTAB nEndTab;
2000-09-18 16:07:07 +00:00
if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab))
2000-09-18 16:07:07 +00:00
{
bool bChangeSelection = false;
ScRange aMarkRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
if ( ScViewUtil::HasFiltered( aMarkRange, pDoc ) )
{
ScMarkData aVisibleMark( rMark );
ScViewUtil::UnmarkFiltered( aVisibleMark, pDoc );
ScRangeList aRangeList;
aVisibleMark.FillRangeListWithMarks( &aRangeList, FALSE );
if ( aRangeList.Count() > 0 )
{
// use the first range of visible cells
// (might also show an error message instead, or, later, allow multiple ranges)
aMarkRange = *aRangeList.GetObject(0);
}
else // all hidden -> cursor position
{
aMarkRange.aStart.SetCol(GetViewData()->GetCurX());
aMarkRange.aStart.SetRow(GetViewData()->GetCurY());
aMarkRange.aStart.SetTab(GetViewData()->GetTabNo());
aMarkRange.aEnd = aMarkRange.aStart;
}
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
bChangeSelection = true; // change the selection to only the affected cells
}
rMark.MarkToSimple(); // not done by GetSimpleArea anymore
2000-09-18 16:07:07 +00:00
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocShellModificator aModificator( *pDocSh );
if (!rMark.IsMarked() || bChangeSelection)
2000-09-18 16:07:07 +00:00
{
DoneBlockMode();
InitOwnBlockMode();
rMark.SetMarkArea( ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) );
}
if (bRecord)
{
SCTAB nTabCount = pDoc->GetTableCount();
2000-09-18 16:07:07 +00:00
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
for (SCTAB i=0; i<nTabCount; i++)
2000-09-18 16:07:07 +00:00
if (i != nStartTab && rMark.GetTableSelect(i))
pUndoDoc->AddUndoTab( i, i );
pDoc->CopyToDocument( nStartCol, nStartRow, 0, nEndCol, nEndRow, nTabCount-1,
IDF_ATTRIB, FALSE, pUndoDoc );
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoSelectionAttr( pDocSh, rMark,
nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab,
pUndoDoc, FALSE, &rAttr, pNewOuter, pNewInner ) );
}
USHORT nExt = SC_PF_TESTMERGE;
pDocSh->UpdatePaintExt( nExt, nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab ); // content before the change
2000-09-18 16:07:07 +00:00
pDoc->ApplySelectionFrame( rMark, pNewOuter, pNewInner );
pDocSh->UpdatePaintExt( nExt, nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab ); // content after the change
2000-09-18 16:07:07 +00:00
rMark.MarkToMulti();
pDoc->ApplySelectionPattern( rAttr, rMark );
pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab,
PAINT_GRID, nExt );
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
CellContentChanged();
rMark.MarkToSimple();
}
else
{ // "Rahmen nicht auf Mehrfachselektion"
ErrorMessage(STR_MSSG_APPLYPATTLINES_0);
}
StartFormatArea();
}
// nur Pattern
void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr,
BOOL bRecord, BOOL bCursorOnly )
{
ScViewData* pViewData = GetViewData();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
ScMarkData aFuncMark( pViewData->GetMarkData() ); // local copy for UnmarkFiltered
ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
// State from old ItemSet doesn't matter for paint flags, as any change will be
// from SFX_ITEM_SET in the new ItemSet (default is ignored in ApplyPattern).
// New alignment is checked (check in PostPaint isn't enough) in case a right
// alignment is changed to left.
const SfxItemSet& rNewSet = rAttr.GetItemSet();
BOOL bSetLines = rNewSet.GetItemState( ATTR_BORDER, TRUE ) == SFX_ITEM_SET ||
rNewSet.GetItemState( ATTR_SHADOW, TRUE ) == SFX_ITEM_SET;
BOOL bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY, TRUE ) == SFX_ITEM_SET;
USHORT nExtFlags = 0;
if ( bSetLines )
nExtFlags |= SC_PF_LINES;
if ( bSetAlign )
nExtFlags |= SC_PF_WHOLEROWS;
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( *pDocSh );
2000-09-18 16:07:07 +00:00
BOOL bMulti = aFuncMark.IsMultiMarked();
aFuncMark.MarkToMulti();
BOOL bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
2000-09-18 16:07:07 +00:00
if (bOnlyTab)
{
SCCOL nCol = pViewData->GetCurX();
SCROW nRow = pViewData->GetCurY();
SCTAB nTab = pViewData->GetTabNo();
aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
aFuncMark.MarkToMulti();
2000-09-18 16:07:07 +00:00
}
if (aFuncMark.IsMultiMarked() && !bCursorOnly)
2000-09-18 16:07:07 +00:00
{
ScRange aMarkRange;
aFuncMark.GetMultiMarkArea( aMarkRange );
SCCOL nStartCol = aMarkRange.aStart.Col();
SCROW nStartRow = aMarkRange.aStart.Row();
SCTAB nStartTab = aMarkRange.aStart.Tab();
SCCOL nEndCol = aMarkRange.aEnd.Col();
SCROW nEndRow = aMarkRange.aEnd.Row();
SCTAB nEndTab = aMarkRange.aEnd.Tab();
2000-09-18 16:07:07 +00:00
if (bRecord)
{
ScRange aCopyRange = aMarkRange;
SCTAB nTabCount = pDoc->GetTableCount();
2000-09-18 16:07:07 +00:00
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nStartTab, nStartTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nStartTab && aFuncMark.GetTableSelect(i))
2000-09-18 16:07:07 +00:00
pUndoDoc->AddUndoTab( i, i );
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, bMulti, pUndoDoc, &aFuncMark );
2000-09-18 16:07:07 +00:00
aFuncMark.MarkToMulti();
2000-09-18 16:07:07 +00:00
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoSelectionAttr(
pDocSh, aFuncMark,
2000-09-18 16:07:07 +00:00
nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab,
pUndoDoc, bMulti, &rAttr ) );
}
pDoc->ApplySelectionPattern( rAttr, aFuncMark );
2000-09-18 16:07:07 +00:00
pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
nEndCol, nEndRow, nEndTab,
PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
2000-09-18 16:07:07 +00:00
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
CellContentChanged();
}
else // einzelne Zelle - Undo einfacher
{
SCCOL nCol = pViewData->GetCurX();
SCROW nRow = pViewData->GetCurY();
SCTAB nTab = pViewData->GetTabNo();
2000-09-18 16:07:07 +00:00
ScPatternAttr* pOldPat = new ScPatternAttr(*pDoc->GetPattern( nCol, nRow, nTab ));
pDoc->ApplyPattern( nCol, nRow, nTab, rAttr );
const ScPatternAttr* pNewPat = pDoc->GetPattern( nCol, nRow, nTab );
if (bRecord)
{
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoCursorAttr( pDocSh,
nCol, nRow, nTab,
pOldPat, pNewPat, &rAttr,
FALSE ) ); // FALSE = nicht automatisch
}
delete pOldPat; // wird im Undo kopiert (Pool)
pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PAINT_GRID, nExtFlags | SC_PF_TESTMERGE );
2000-09-18 16:07:07 +00:00
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
CellContentChanged();
}
StartFormatArea();
}
void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
{
// ItemSet from UI, may have different pool
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
ScPatternAttr aNewAttrs( GetViewData()->GetDocument()->GetPool() );
SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
rNewSet.Put( rItemSet, FALSE );
ApplySelectionPattern( aNewAttrs );
AdjustBlockHeight();
}
2000-09-18 16:07:07 +00:00
const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
{
// Don't use UnmarkFiltered in slot state functions, for performance reasons.
// The displayed state is always that of the whole selection including filtered rows.
2000-09-18 16:07:07 +00:00
const ScStyleSheet* pSheet = NULL;
ScViewData* pViewData = GetViewData();
ScDocument* pDoc = pViewData->GetDocument();
ScMarkData& rMark = pViewData->GetMarkData();
if ( rMark.IsMarked() || rMark.IsMultiMarked() )
pSheet = pDoc->GetSelectionStyle( rMark ); // MarkToMulti isn't necessary
2000-09-18 16:07:07 +00:00
else
pSheet = pDoc->GetStyle( pViewData->GetCurX(),
pViewData->GetCurY(),
pViewData->GetTabNo() );
return pSheet;
}
void ScViewFunc::SetStyleSheetToMarked( SfxStyleSheet* pStyleSheet, BOOL bRecord )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
if ( !pStyleSheet) return;
// -------------------------------------------------------------------
ScViewData* pViewData = GetViewData();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
ScMarkData aFuncMark( pViewData->GetMarkData() ); // local copy for UnmarkFiltered
ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
SCTAB nTabCount = pDoc->GetTableCount();
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( *pDocSh );
if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
2000-09-18 16:07:07 +00:00
{
ScRange aMarkRange;
aFuncMark.MarkToMulti();
aFuncMark.GetMultiMarkArea( aMarkRange );
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
SCTAB nTab = pViewData->GetTabNo();
2000-09-18 16:07:07 +00:00
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nTab && aFuncMark.GetTableSelect(i))
2000-09-18 16:07:07 +00:00
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aMarkRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, TRUE, pUndoDoc, &aFuncMark );
aFuncMark.MarkToMulti();
2000-09-18 16:07:07 +00:00
String aName = pStyleSheet->GetName();
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoSelectionStyle( pDocSh, aFuncMark, aMarkRange, aName, pUndoDoc ) );
2000-09-18 16:07:07 +00:00
}
pDoc->ApplySelectionStyle( (ScStyleSheet&)*pStyleSheet, aFuncMark );
2000-09-18 16:07:07 +00:00
if (!AdjustBlockHeight())
pViewData->GetDocShell()->PostPaint( aMarkRange, PAINT_GRID );
aFuncMark.MarkToSimple();
2000-09-18 16:07:07 +00:00
}
else
{
SCCOL nCol = pViewData->GetCurX();
SCROW nRow = pViewData->GetCurY();
SCTAB nTab = pViewData->GetTabNo();
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab );
for (SCTAB i=0; i<nTabCount; i++)
if (i != nTab && aFuncMark.GetTableSelect(i))
2000-09-18 16:07:07 +00:00
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
pDoc->CopyToDocument( aCopyRange, IDF_ATTRIB, FALSE, pUndoDoc );
ScRange aMarkRange ( nCol, nRow, nTab );
ScMarkData aUndoMark = aFuncMark;
2000-09-18 16:07:07 +00:00
aUndoMark.SetMultiMarkArea( aMarkRange );
String aName = pStyleSheet->GetName();
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoSelectionStyle( pDocSh, aUndoMark, aMarkRange, aName, pUndoDoc ) );
}
for (SCTAB i=0; i<nTabCount; i++)
if (aFuncMark.GetTableSelect(i))
2000-09-18 16:07:07 +00:00
pDoc->ApplyStyle( nCol, nRow, i, (ScStyleSheet&)*pStyleSheet );
if (!AdjustBlockHeight())
pViewData->GetDocShell()->PostPaintCell( nCol, nRow, nTab );
}
aModificator.SetDocumentModified();
StartFormatArea();
}
void ScViewFunc::RemoveStyleSheetInUse( SfxStyleSheet* pStyleSheet )
{
if ( !pStyleSheet) return;
// -------------------------------------------------------------------
ScViewData* pViewData = GetViewData();
ScDocument* pDoc = pViewData->GetDocument();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocShellModificator aModificator( *pDocSh );
VirtualDevice aVirtDev;
aVirtDev.SetMapMode(MAP_PIXEL);
pDoc->StyleSheetChanged( pStyleSheet, TRUE, &aVirtDev,
pViewData->GetPPTX(),
pViewData->GetPPTY(),
pViewData->GetZoomX(),
pViewData->GetZoomY() );
pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
aModificator.SetDocumentModified();
ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
if (pHdl)
pHdl->ForgetLastPattern();
}
void ScViewFunc::UpdateStyleSheetInUse( SfxStyleSheet* pStyleSheet )
{
if ( !pStyleSheet) return;
// -------------------------------------------------------------------
ScViewData* pViewData = GetViewData();
ScDocument* pDoc = pViewData->GetDocument();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScDocShellModificator aModificator( *pDocSh );
VirtualDevice aVirtDev;
aVirtDev.SetMapMode(MAP_PIXEL);
pDoc->StyleSheetChanged( pStyleSheet, FALSE, &aVirtDev,
pViewData->GetPPTX(),
pViewData->GetPPTY(),
pViewData->GetZoomX(),
pViewData->GetZoomY() );
pDocSh->PostPaint( 0,0,0, MAXCOL,MAXROW,MAXTAB, PAINT_GRID|PAINT_LEFT );
aModificator.SetDocumentModified();
ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
if (pHdl)
pHdl->ForgetLastPattern();
}
// Zellen einfuegen - Undo OK
BOOL ScViewFunc::InsertCells( InsCellCmd eCmd, BOOL bRecord, BOOL bPartOfPaste )
2000-09-18 16:07:07 +00:00
{
ScRange aRange;
if (GetViewData()->GetSimpleArea(aRange))
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
BOOL bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, eCmd, bRecord, FALSE, bPartOfPaste );
2000-09-18 16:07:07 +00:00
if (bSuccess)
{
pDocSh->UpdateOle(GetViewData());
CellContentChanged();
}
return bSuccess;
}
else
{
ErrorMessage(STR_NOMULTISELECT);
return FALSE;
}
}
// Zellen loeschen - Undo OK
void ScViewFunc::DeleteCells( DelCellCmd eCmd, BOOL bRecord )
{
ScRange aRange;
if ( GetViewData()->GetSimpleArea( aRange ) &&
!ScViewUtil::HasFiltered( aRange, GetViewData()->GetDocument() ) )
2000-09-18 16:07:07 +00:00
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
pDocSh->GetDocFunc().DeleteCells( aRange, eCmd, bRecord, FALSE );
pDocSh->UpdateOle(GetViewData());
CellContentChanged();
// #58106# Cursor direkt hinter den geloeschten Bereich setzen
SCCOL nCurX = GetViewData()->GetCurX();
SCROW nCurY = GetViewData()->GetCurY();
2000-09-18 16:07:07 +00:00
if ( eCmd==DEL_CELLSLEFT || eCmd==DEL_DELCOLS )
nCurX = aRange.aStart.Col();
else
nCurY = aRange.aStart.Row();
SetCursor( nCurX, nCurY );
}
else
{
if (eCmd == DEL_DELCOLS)
DeleteMulti( FALSE, bRecord );
else if (eCmd == DEL_DELROWS)
DeleteMulti( TRUE, bRecord );
else
ErrorMessage(STR_NOMULTISELECT);
}
Unmark();
}
void ScViewFunc::DeleteMulti( BOOL bRows, BOOL bRecord )
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocShellModificator aModificator( *pDocSh );
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
ScDocument* pDoc = pDocSh->GetDocument();
ScMarkData aFuncMark( GetViewData()->GetMarkData() ); // local copy for UnmarkFiltered
ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
SCCOLROW nRangeCnt = bRows ? aFuncMark.GetMarkRowRanges( pRanges ) :
aFuncMark.GetMarkColumnRanges( pRanges );
if (nRangeCnt == 0)
2000-09-18 16:07:07 +00:00
{
pRanges[0] = pRanges[1] = bRows ? static_cast<SCCOLROW>(GetViewData()->GetCurY()) : static_cast<SCCOLROW>(GetViewData()->GetCurX());
2000-09-18 16:07:07 +00:00
nRangeCnt = 1;
}
// Test ob erlaubt
SCCOLROW* pOneRange = pRanges;
USHORT nErrorId = 0;
BOOL bNeedRefresh = FALSE;
SCCOLROW nRangeNo;
for (nRangeNo=0; nRangeNo<nRangeCnt && !nErrorId; nRangeNo++)
2000-09-18 16:07:07 +00:00
{
SCCOLROW nStart = *(pOneRange++);
SCCOLROW nEnd = *(pOneRange++);
2000-09-18 16:07:07 +00:00
SCCOL nStartCol, nEndCol;
SCROW nStartRow, nEndRow;
if ( bRows )
{
nStartCol = 0;
nEndCol = MAXCOL;
nStartRow = static_cast<SCROW>(nStart);
nEndRow = static_cast<SCROW>(nEnd);
}
else
{
nStartCol = static_cast<SCCOL>(nStart);
nEndCol = static_cast<SCCOL>(nEnd);
nStartRow = 0;
nEndRow = MAXROW;
}
// cell protection (only needed for first range, as all following cells are moved)
if ( nRangeNo == 0 )
{
// test to the end of the sheet
ScEditableTester aTester( pDoc, nTab, nStartCol, nStartRow, MAXCOL, MAXROW );
if (!aTester.IsEditable())
nErrorId = aTester.GetMessageId();
}
// merged cells
SCCOL nMergeStartX = nStartCol;
SCROW nMergeStartY = nStartRow;
SCCOL nMergeEndX = nEndCol;
SCROW nMergeEndY = nEndRow;
pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
{
// Disallow deleting parts of a merged cell.
// Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
nErrorId = STR_MSSG_DELETECELLS_0;
}
if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
{
// detect if the start of a merged cell is deleted, so the merge flags can be refreshed
bNeedRefresh = TRUE;
}
}
if ( nErrorId )
{
ErrorMessage( nErrorId );
delete[] pRanges;
return;
2000-09-18 16:07:07 +00:00
}
// ausfuehren
WaitObject aWait( GetFrameWin() ); // wichtig wegen TrackFormulas bei UpdateReference
ScDocument* pUndoDoc = NULL;
ScRefUndoData* pUndoData = NULL;
if (bRecord)
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
pUndoDoc->InitUndo( pDoc, nTab, nTab, !bRows, bRows ); // Zeilenhoehen
pOneRange = pRanges;
for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
{
SCCOLROW nStart = *(pOneRange++);
SCCOLROW nEnd = *(pOneRange++);
2000-09-18 16:07:07 +00:00
if (bRows)
pDoc->CopyToDocument( 0,nStart,nTab, MAXCOL,nEnd,nTab, IDF_ALL,FALSE,pUndoDoc );
else
pDoc->CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
static_cast<SCCOL>(nEnd),MAXROW,nTab,
IDF_ALL,FALSE,pUndoDoc );
2000-09-18 16:07:07 +00:00
}
// alle Formeln wegen Referenzen
SCTAB nTabCount = pDoc->GetTableCount();
2000-09-18 16:07:07 +00:00
pUndoDoc->AddUndoTab( 0, nTabCount-1, FALSE, FALSE );
pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA,FALSE,pUndoDoc );
pUndoData = new ScRefUndoData( pDoc );
pDoc->BeginDrawUndo();
}
pOneRange = &pRanges[2*nRangeCnt]; // rueckwaerts
for (nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
2000-09-18 16:07:07 +00:00
{
SCCOLROW nEnd = *(--pOneRange);
SCCOLROW nStart = *(--pOneRange);
2000-09-18 16:07:07 +00:00
if (bRows)
pDoc->DeleteRow( 0,nTab, MAXCOL,nTab, nStart, static_cast<SCSIZE>(nEnd-nStart+1) );
2000-09-18 16:07:07 +00:00
else
pDoc->DeleteCol( 0,nTab, MAXROW,nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
2000-09-18 16:07:07 +00:00
}
if (bNeedRefresh)
{
SCCOLROW nFirstStart = pRanges[0];
SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
SCCOL nEndCol = MAXCOL;
SCROW nEndRow = MAXROW;
pDoc->RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, TRUE );
}
2000-09-18 16:07:07 +00:00
if (bRecord)
{
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoDeleteMulti( pDocSh, bRows, bNeedRefresh, nTab, pRanges, nRangeCnt,
2000-09-18 16:07:07 +00:00
pUndoDoc, pUndoData ) );
}
if (!AdjustRowHeight(0, MAXROW))
if (bRows)
pDocSh->PostPaint( 0,pRanges[0],nTab, MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_LEFT );
else
pDocSh->PostPaint( static_cast<SCCOL>(pRanges[0]),0,nTab,
MAXCOL,MAXROW,nTab, PAINT_GRID | PAINT_TOP );
2000-09-18 16:07:07 +00:00
aModificator.SetDocumentModified();
CellContentChanged();
// #58106# Cursor direkt hinter den ersten geloeschten Bereich setzen
SCCOL nCurX = GetViewData()->GetCurX();
SCROW nCurY = GetViewData()->GetCurY();
2000-09-18 16:07:07 +00:00
if ( bRows )
nCurY = pRanges[0];
else
nCurX = static_cast<SCCOL>(pRanges[0]);
2000-09-18 16:07:07 +00:00
SetCursor( nCurX, nCurY );
delete[] pRanges;
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
2000-09-18 16:07:07 +00:00
}
// Inhalte loeschen
void ScViewFunc::DeleteContents( USHORT nFlags, BOOL bRecord )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
BOOL bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
if ( !bEditable )
{
if ( !(bOnlyNotBecauseOfMatrix &&
((nFlags & (IDF_ATTRIB | IDF_EDITATTR)) == nFlags)) )
{
ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
2000-09-18 16:07:07 +00:00
return;
}
}
ScRange aMarkRange;
BOOL bSimple = FALSE;
ScDocument* pDoc = GetViewData()->GetDocument();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScMarkData aFuncMark( GetViewData()->GetMarkData() ); // local copy for UnmarkFiltered
ScViewUtil::UnmarkFiltered( aFuncMark, pDoc );
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( *pDocSh );
if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
2000-09-18 16:07:07 +00:00
{
aMarkRange.aStart.SetCol(GetViewData()->GetCurX());
aMarkRange.aStart.SetRow(GetViewData()->GetCurY());
aMarkRange.aStart.SetTab(GetViewData()->GetTabNo());
aMarkRange.aEnd = aMarkRange.aStart;
if ( pDoc->HasAttrib( aMarkRange, HASATTR_MERGED ) )
{
// InitOwnBlockMode();
aFuncMark.SetMarkArea( aMarkRange );
2000-09-18 16:07:07 +00:00
}
else
bSimple = TRUE;
}
aFuncMark.SetMarking(FALSE); // for MarkToMulti
aFuncMark.MarkToSimple(); // before bMulti test below
2000-09-18 16:07:07 +00:00
DBG_ASSERT( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() || bSimple, "delete what?" )
2000-09-18 16:07:07 +00:00
ScDocument* pUndoDoc = NULL;
BOOL bMulti = !bSimple && aFuncMark.IsMultiMarked();
2000-09-18 16:07:07 +00:00
if (!bSimple)
{
aFuncMark.MarkToMulti();
aFuncMark.GetMultiMarkArea( aMarkRange );
2000-09-18 16:07:07 +00:00
}
ScRange aExtendedRange(aMarkRange);
if (!bSimple)
{
if ( pDoc->ExtendMerge( aExtendedRange, TRUE ) )
bMulti = FALSE;
}
// keine Objekte auf geschuetzten Tabellen
BOOL bObjects = FALSE;
if ( nFlags & IDF_OBJECTS )
{
bObjects = TRUE;
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
if (aFuncMark.GetTableSelect(nTab) && pDoc->IsTabProtected(nTab))
2000-09-18 16:07:07 +00:00
bObjects = FALSE;
}
USHORT nExtFlags = 0; // extra flags are needed only if attributes are deleted
if ( nFlags & IDF_ATTRIB )
pDocSh->UpdatePaintExt( nExtFlags, aMarkRange );
2000-09-18 16:07:07 +00:00
// Reihenfolge:
// 1) BeginDrawUndo
// 2) Objekte loeschen (DrawUndo wird gefuellt)
// 3) Inhalte fuer Undo kopieren
// 4) Inhalte loeschen
// 5) Undo-Aktion anlegen
BOOL bDrawUndo = bObjects || ( nFlags & IDF_NOTE ); // needed for shown notes
if ( bDrawUndo && bRecord )
pDoc->BeginDrawUndo();
2000-09-18 16:07:07 +00:00
if (bObjects)
{
if (bMulti)
pDoc->DeleteObjectsInSelection( aFuncMark );
2000-09-18 16:07:07 +00:00
else
pDoc->DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
/*!*/ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
aFuncMark );
2000-09-18 16:07:07 +00:00
}
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
SCTAB nTab = aMarkRange.aStart.Tab();
2000-09-18 16:07:07 +00:00
pUndoDoc->InitUndo( pDoc, nTab, nTab );
SCTAB nTabCount = pDoc->GetTableCount();
for (SCTAB i=0; i<nTabCount; i++)
if (i != nTab && aFuncMark.GetTableSelect(i))
2000-09-18 16:07:07 +00:00
pUndoDoc->AddUndoTab( i, i );
ScRange aCopyRange = aExtendedRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(nTabCount-1);
// bei "Format/Standard" alle Attribute kopieren, weil CopyToDocument
// nur mit IDF_HARDATTR zu langsam ist:
USHORT nUndoDocFlags = nFlags;
if (nFlags & IDF_ATTRIB)
nUndoDocFlags |= IDF_ATTRIB;
if (nFlags & IDF_EDITATTR) // Edit-Engine-Attribute
nUndoDocFlags |= IDF_STRING; // -> Zellen werden geaendert
if (nFlags & IDF_NOTE)
nUndoDocFlags |= IDF_CONTENTS; // #68795# copy all cells with their notes
pDoc->CopyToDocument( aCopyRange, nUndoDocFlags, bMulti, pUndoDoc, &aFuncMark );
2000-09-18 16:07:07 +00:00
}
HideAllCursors(); // falls Zusammenfassung aufgehoben wird
if (bSimple)
pDoc->DeleteArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
aFuncMark, nFlags );
2000-09-18 16:07:07 +00:00
else
{
pDoc->DeleteSelection( nFlags, aFuncMark );
aFuncMark.MarkToSimple();
2000-09-18 16:07:07 +00:00
}
if ( bRecord )
{
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoDeleteContents( pDocSh, aFuncMark, aExtendedRange,
pUndoDoc, bMulti, nFlags, bDrawUndo ) );
2000-09-18 16:07:07 +00:00
}
if (!AdjustRowHeight( aExtendedRange.aStart.Row(), aExtendedRange.aEnd.Row() ))
pDocSh->PostPaint( aExtendedRange, PAINT_GRID, nExtFlags );
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
CellContentChanged();
ShowAllCursors();
if ( nFlags & IDF_ATTRIB )
{
if ( nFlags & IDF_CONTENTS )
ForgetFormatArea();
else
StartFormatArea(); // Attribute loeschen ist auch Attributierung
}
}
// Spaltenbreiten/Zeilenhoehen (ueber Header) - Undo OK
void ScViewFunc::SetWidthOrHeight( BOOL bWidth, SCCOLROW nRangeCnt, SCCOLROW* pRanges,
ScSizeMode eMode, USHORT nSizeTwips,
BOOL bRecord, BOOL bPaint, ScMarkData* pMarkData )
2000-09-18 16:07:07 +00:00
{
if (nRangeCnt == 0)
2000-09-18 16:07:07 +00:00
return;
// use view's mark if none specified
if ( !pMarkData )
pMarkData = &GetViewData()->GetMarkData();
2000-09-18 16:07:07 +00:00
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
SCTAB nTabCount = pDoc->GetTableCount();
SCTAB nFirstTab = pMarkData->GetFirstSelected();
SCTAB nCurTab = GetViewData()->GetTabNo();
SCTAB nTab;
if (bRecord && !pDoc->IsUndoEnabled())
bRecord = FALSE;
2000-09-18 16:07:07 +00:00
ScDocShellModificator aModificator( *pDocSh );
BOOL bAllowed = TRUE;
for (nTab=0; nTab<nTabCount && bAllowed; nTab++)
if (pMarkData->GetTableSelect(nTab))
{
for ( SCCOLROW i=0; i<nRangeCnt && bAllowed; i++ )
{
BOOL bOnlyMatrix;
if (bWidth)
bAllowed = pDoc->IsBlockEditable( nTab,
static_cast<SCCOL>(pRanges[2*i]),0,
static_cast<SCCOL>(pRanges[2*i+1]),MAXROW,
&bOnlyMatrix ) || bOnlyMatrix;
else
bAllowed = pDoc->IsBlockEditable( nTab, 0,pRanges[2*i],
MAXCOL,pRanges[2*i+1], &bOnlyMatrix ) ||
bOnlyMatrix;
}
}
2000-09-18 16:07:07 +00:00
if ( !bAllowed )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
SCCOLROW nStart = pRanges[0];
SCCOLROW nEnd = pRanges[2*nRangeCnt-1];
2000-09-18 16:07:07 +00:00
BOOL bFormula = FALSE;
if ( eMode == SC_SIZE_OPTIMAL )
{
const ScViewOptions& rOpts = GetViewData()->GetOptions();
bFormula = rOpts.GetOption( VOPT_FORMULAS );
}
ScDocument* pUndoDoc = NULL;
ScOutlineTable* pUndoTab = NULL;
SCCOLROW* pUndoRanges = NULL;
2000-09-18 16:07:07 +00:00
if ( bRecord )
{
pDoc->BeginDrawUndo(); // Drawing Updates
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
for (nTab=0; nTab<nTabCount; nTab++)
if (pMarkData->GetTableSelect(nTab))
{
if (bWidth)
{
if ( nTab == nFirstTab )
pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, FALSE );
else
pUndoDoc->AddUndoTab( nTab, nTab, TRUE, FALSE );
pDoc->CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab,
static_cast<SCCOL>(nEnd), MAXROW, nTab, IDF_NONE,
FALSE, pUndoDoc );
}
else
{
if ( nTab == nFirstTab )
pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
else
pUndoDoc->AddUndoTab( nTab, nTab, FALSE, TRUE );
pDoc->CopyToDocument( 0, nStart, nTab, MAXCOL, nEnd, nTab, IDF_NONE, FALSE, pUndoDoc );
}
}
2000-09-18 16:07:07 +00:00
pUndoRanges = new SCCOLROW[ 2*nRangeCnt ];
memmove( pUndoRanges, pRanges, 2*nRangeCnt*sizeof(SCCOLROW) );
2000-09-18 16:07:07 +00:00
//! outlines from all tables?
ScOutlineTable* pTable = pDoc->GetOutlineTable( nCurTab );
2000-09-18 16:07:07 +00:00
if (pTable)
pUndoTab = new ScOutlineTable( *pTable );
}
if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
pMarkData->MarkToMulti();
2000-09-18 16:07:07 +00:00
BOOL bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
BOOL bOutline = FALSE;
for (nTab=0; nTab<nTabCount; nTab++)
if (pMarkData->GetTableSelect(nTab))
2000-09-18 16:07:07 +00:00
{
const SCCOLROW* pTabRanges = pRanges;
pDoc->IncSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln
for (SCCOLROW nRangeNo=0; nRangeNo<nRangeCnt; nRangeNo++)
2000-09-18 16:07:07 +00:00
{
SCCOLROW nStartNo = *(pTabRanges++);
SCCOLROW nEndNo = *(pTabRanges++);
if ( !bWidth ) // Hoehen immer blockweise
2000-09-18 16:07:07 +00:00
{
if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
{
BOOL bAll = ( eMode==SC_SIZE_OPTIMAL );
if (!bAll)
{
// fuer alle eingeblendeten CR_MANUALSIZE loeschen,
// dann SetOptimalHeight mit bShrink = FALSE
ScCompressedArrayIterator< SCROW, BYTE> aIter(
pDoc->GetRowFlagsArray( nTab), nStartNo,
nEndNo);
do
{
BYTE nOld = *aIter;
if ( (nOld & CR_HIDDEN) == 0 && ( nOld & CR_MANUALSIZE ) )
{
SCROW nRangeEnd = aIter.GetRangeEnd();
pDoc->SetRowFlags( aIter.GetRangeStart(),
nRangeEnd, nTab,
nOld & ~CR_MANUALSIZE);
aIter.Resync( nRangeEnd);
// Range may be extended due to merges and
// now aIter.GetRangeEnd() may point behind
// the previous row, but all flags of this
// range have the CR_MANUALSIZE bit
// removed, so it is safe to continue with
// the next range, not necessary to catch
// up with the remaining rows.
}
} while (aIter.NextRange());
}
double nPPTX = GetViewData()->GetPPTX();
double nPPTY = GetViewData()->GetPPTY();
Fraction aZoomX = GetViewData()->GetZoomX();
Fraction aZoomY = GetViewData()->GetZoomY();
ScSizeDeviceProvider aProv(pDocSh);
if (aProv.IsPrinter())
{
nPPTX = aProv.GetPPTX();
nPPTY = aProv.GetPPTY();
aZoomX = aZoomY = Fraction( 1, 1 );
}
pDoc->SetOptimalHeight( nStartNo, nEndNo, nTab, nSizeTwips, aProv.GetDevice(),
nPPTX, nPPTY, aZoomX, aZoomY, bAll );
if (bAll)
pDoc->ShowRows( nStartNo, nEndNo, nTab, TRUE );
// Manual-Flag wird bei bAll=TRUE schon in SetOptimalHeight gesetzt
// (an bei Extra-Height, sonst aus).
}
else if ( eMode==SC_SIZE_DIRECT )
{
if (nSizeTwips)
{
pDoc->SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
pDoc->SetManualHeight( nStartNo, nEndNo, nTab, TRUE ); // height was set manually
}
pDoc->ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
}
else if ( eMode==SC_SIZE_SHOW )
2000-09-18 16:07:07 +00:00
{
pDoc->ShowRows( nStartNo, nEndNo, nTab, TRUE );
2000-09-18 16:07:07 +00:00
}
}
else // Spaltenbreiten
2000-09-18 16:07:07 +00:00
{
for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
{
if ( eMode != SC_SIZE_VISOPT ||
(pDoc->GetColFlags( nCol, nTab ) & CR_HIDDEN) == 0 )
{
USHORT nThisSize = nSizeTwips;
2000-09-18 16:07:07 +00:00
if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
if ( nThisSize )
pDoc->SetColWidth( nCol, nTab, nThisSize );
2000-09-18 16:07:07 +00:00
pDoc->ShowCol( nCol, nTab, bShow );
}
}
}
// Outline anpassen
if (bWidth)
{
if ( pDoc->UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
static_cast<SCCOL>(nEndNo), nTab, bShow ) )
bOutline = TRUE;
}
else
{
if ( pDoc->UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
bOutline = TRUE;
2000-09-18 16:07:07 +00:00
}
}
pDoc->DecSizeRecalcLevel( nTab ); // nicht fuer jede Spalte einzeln
2000-09-18 16:07:07 +00:00
}
if (!bOutline)
DELETEZ(pUndoTab);
if (bRecord)
{
pDocSh->GetUndoManager()->AddUndoAction(
new ScUndoWidthOrHeight( pDocSh, *pMarkData,
nStart, nCurTab, nEnd, nCurTab,
2000-09-18 16:07:07 +00:00
pUndoDoc, nRangeCnt, pUndoRanges,
pUndoTab, eMode, nSizeTwips, bWidth ) );
}
for (nTab=0; nTab<nTabCount; nTab++)
if (pMarkData->GetTableSelect(nTab))
pDoc->UpdatePageBreaks( nTab );
2000-09-18 16:07:07 +00:00
GetViewData()->GetView()->UpdateScrollBars();
if (bPaint)
{
HideCursor();
for (nTab=0; nTab<nTabCount; nTab++)
if (pMarkData->GetTableSelect(nTab))
{
if (bWidth)
{
if (pDoc->HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
static_cast<SCCOL>(nEnd),MAXROW,nTab,
HASATTR_MERGED | HASATTR_OVERLAPPED ))
nStart = 0;
if (nStart > 0) // weiter oben anfangen wegen Linien und Cursor
--nStart;
pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_TOP );
}
else
{
if (pDoc->HasAttrib( 0,nStart,nTab, MAXCOL,nEnd,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
nStart = 0;
if (nStart != 0)
--nStart;
pDocSh->PostPaint( 0, nStart, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_LEFT );
}
}
2000-09-18 16:07:07 +00:00
pDocSh->UpdateOle(GetViewData());
aModificator.SetDocumentModified();
ShowCursor();
}
}
// Spaltenbreiten/Zeilenhoehen (ueber Blockmarken)
void ScViewFunc::SetMarkedWidthOrHeight( BOOL bWidth, ScSizeMode eMode, USHORT nSizeTwips,
BOOL bRecord, BOOL bPaint )
{
ScMarkData& rMark = GetViewData()->GetMarkData();
rMark.MarkToMulti();
if (!rMark.IsMultiMarked())
{
SCCOL nCol = GetViewData()->GetCurX();
SCROW nRow = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
DoneBlockMode();
InitOwnBlockMode();
rMark.SetMultiMarkArea( ScRange( nCol,nRow,nTab ), TRUE );
}
SCCOLROW* pRanges = new SCCOLROW[MAXCOLROWCOUNT];
SCCOLROW nRangeCnt = 0;
2000-09-18 16:07:07 +00:00
if ( bWidth )
nRangeCnt = rMark.GetMarkColumnRanges( pRanges );
else
nRangeCnt = rMark.GetMarkRowRanges( pRanges );
SetWidthOrHeight( bWidth, nRangeCnt, pRanges, eMode, nSizeTwips, bRecord, bPaint );
delete[] pRanges;
rMark.MarkToSimple();
}
void ScViewFunc::ModifyCellSize( ScDirection eDir, BOOL bOptimal )
{
//! Schrittweiten einstellbar
// Schrittweite ist auch Minimum
USHORT nStepX = STD_COL_WIDTH / 5;
USHORT nStepY = ScGlobal::nStdRowHeight;
ScModule* pScMod = SC_MOD();
BOOL bAnyEdit = pScMod->IsInputMode();
SCCOL nCol = GetViewData()->GetCurX();
SCROW nRow = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
2000-09-18 16:07:07 +00:00
BOOL bAllowed, bOnlyMatrix;
if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
bAllowed = pDoc->IsBlockEditable( nTab, nCol,0, nCol,MAXROW, &bOnlyMatrix );
else
bAllowed = pDoc->IsBlockEditable( nTab, 0,nRow, MAXCOL,nRow, &bOnlyMatrix );
if ( !bAllowed && !bOnlyMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
HideAllCursors();
USHORT nWidth = pDoc->GetColWidth( nCol, nTab );
USHORT nHeight = pDoc->GetRowHeight( nRow, nTab );
SCCOLROW nRange[2];
2000-09-18 16:07:07 +00:00
if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
{
if (bOptimal) // Breite dieser einen Zelle
{
if ( bAnyEdit )
{
// beim Editieren die aktuelle Breite der Eingabe
ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
if (pHdl)
{
long nEdit = pHdl->GetTextSize().Width(); // in 1/100mm
const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
const SvxMarginItem& rMItem =
(const SvxMarginItem&)pPattern->GetItem(ATTR_MARGIN);
USHORT nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
if ( ((const SvxHorJustifyItem&) pPattern->
GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_LEFT )
nMargin = sal::static_int_cast<USHORT>(
nMargin + ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue() );
2000-09-18 16:07:07 +00:00
nWidth = (USHORT)(nEdit * pDocSh->GetOutputFactor() / HMM_PER_TWIPS)
+ nMargin + STD_EXTRA_WIDTH;
}
}
else
{
double nPPTX = GetViewData()->GetPPTX();
double nPPTY = GetViewData()->GetPPTY();
Fraction aZoomX = GetViewData()->GetZoomX();
Fraction aZoomY = GetViewData()->GetZoomY();
ScSizeDeviceProvider aProv(pDocSh);
if (aProv.IsPrinter())
{
nPPTX = aProv.GetPPTX();
nPPTY = aProv.GetPPTY();
aZoomX = aZoomY = Fraction( 1, 1 );
}
long nPixel = pDoc->GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
nPPTX, nPPTY, aZoomX, aZoomY, TRUE );
USHORT nTwips = (USHORT)( nPixel / nPPTX );
2000-09-18 16:07:07 +00:00
if (nTwips != 0)
nWidth = nTwips + STD_EXTRA_WIDTH;
else
nWidth = STD_COL_WIDTH;
}
}
else // vergroessern / verkleinern
{
if ( eDir == DIR_RIGHT )
nWidth = sal::static_int_cast<USHORT>( nWidth + nStepX );
2000-09-18 16:07:07 +00:00
else if ( nWidth > nStepX )
nWidth = sal::static_int_cast<USHORT>( nWidth - nStepX );
2000-09-18 16:07:07 +00:00
if ( nWidth < nStepX ) nWidth = nStepX;
if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
}
nRange[0] = nRange[1] = nCol;
SetWidthOrHeight( TRUE, 1, nRange, SC_SIZE_DIRECT, nWidth );
// hier bei Breite auch Hoehe anpassen (nur die eine Zeile)
if (!bAnyEdit)
{
const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
BOOL bNeedHeight =
((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue() ||
((const SvxHorJustifyItem&)pPattern->
GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK;
if (bNeedHeight)
AdjustRowHeight( nRow, nRow );
}
}
else
{
ScSizeMode eMode;
if (bOptimal)
{
eMode = SC_SIZE_OPTIMAL;
nHeight = 0;
}
else
{
eMode = SC_SIZE_DIRECT;
if ( eDir == DIR_BOTTOM )
nHeight = sal::static_int_cast<USHORT>( nHeight + nStepY );
2000-09-18 16:07:07 +00:00
else if ( nHeight > nStepY )
nHeight = sal::static_int_cast<USHORT>( nHeight - nStepY );
2000-09-18 16:07:07 +00:00
if ( nHeight < nStepY ) nHeight = nStepY;
if ( nHeight > MAX_COL_HEIGHT ) nHeight = MAX_COL_HEIGHT;
//! MAX_COL_HEIGHT umbenennen in MAX_ROW_HEIGHT in global.hxx !!!!!!
}
nRange[0] = nRange[1] = nRow;
SetWidthOrHeight( FALSE, 1, nRange, eMode, nHeight );
}
if ( bAnyEdit )
{
UpdateEditView();
if ( pDoc->HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_NEEDHEIGHT ) )
{
ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData()->GetViewShell() );
if (pHdl)
pHdl->SetModified(); // damit bei Enter die Hoehe angepasst wird
}
}
ShowAllCursors();
}
void ScViewFunc::Protect( SCTAB nTab, const String& rPassword )
2000-09-18 16:07:07 +00:00
{
ScMarkData& rMark = GetViewData()->GetMarkData();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
2000-09-18 16:07:07 +00:00
ScDocFunc aFunc(*pDocSh);
BOOL bUndo(pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
aFunc.Protect( nTab, rPassword, FALSE );
else
{
// modifying several tables is handled here
if (bUndo)
{
String aUndo = ScGlobal::GetRscString( STR_UNDO_PROTECT_TAB );
pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
}
2000-09-18 16:07:07 +00:00
SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
for ( SCTAB i=0; i<nCount; i++ )
2000-09-18 16:07:07 +00:00
if ( rMark.GetTableSelect(i) )
aFunc.Protect( i, rPassword, FALSE );
if (bUndo)
pDocSh->GetUndoManager()->LeaveListAction();
2000-09-18 16:07:07 +00:00
}
UpdateLayerLocks(); //! broadcast to all views
}
BOOL ScViewFunc::Unprotect( SCTAB nTab, const String& rPassword )
2000-09-18 16:07:07 +00:00
{
ScMarkData& rMark = GetViewData()->GetMarkData();
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
2000-09-18 16:07:07 +00:00
ScDocFunc aFunc(*pDocSh);
BOOL bChanged = FALSE;
BOOL bUndo (pDoc->IsUndoEnabled());
2000-09-18 16:07:07 +00:00
if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
bChanged = aFunc.Unprotect( nTab, rPassword, FALSE );
else
{
// modifying several tables is handled here
if (bUndo)
{
String aUndo = ScGlobal::GetRscString( STR_UNDO_UNPROTECT_TAB );
pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
}
2000-09-18 16:07:07 +00:00
SCTAB nCount = pDocSh->GetDocument()->GetTableCount();
for ( SCTAB i=0; i<nCount; i++ )
2000-09-18 16:07:07 +00:00
if ( rMark.GetTableSelect(i) )
if ( aFunc.Unprotect( i, rPassword, FALSE ) )
bChanged = TRUE;
if (bUndo)
pDocSh->GetUndoManager()->LeaveListAction();
2000-09-18 16:07:07 +00:00
}
if (bChanged)
UpdateLayerLocks(); //! broadcast to all views
return bChanged;
}
void ScViewFunc::SetNote( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPostIt& rNote )
2000-09-18 16:07:07 +00:00
{
ScDocShell* pDocSh = GetViewData()->GetDocShell();
pDocSh->GetDocFunc().SetNote( ScAddress(nCol,nRow,nTab), rNote, FALSE );
}
void ScViewFunc::SetNumberFormat( short nFormatType, ULONG nAdd )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
sal_uInt32 nNumberFormat = 0;
2000-09-18 16:07:07 +00:00
ScViewData* pViewData = GetViewData();
ScDocument* pDoc = pViewData->GetDocument();
SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
LanguageType eLanguage = ScGlobal::eLnge;
ScPatternAttr aNewAttrs( pDoc->GetPool() );
// #67936# always take language from cursor position, even if there is a selection
sal_uInt32 nCurrentNumberFormat;
2000-09-18 16:07:07 +00:00
pDoc->GetNumberFormat( pViewData->GetCurX(),
pViewData->GetCurY(),
pViewData->GetTabNo(),
nCurrentNumberFormat );
const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
if (pEntry)
eLanguage = pEntry->GetLanguage(); // sonst ScGlobal::eLnge behalten
nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
SfxItemSet& rSet = aNewAttrs.GetItemSet();
rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
// ATTR_LANGUAGE_FORMAT nicht
ApplySelectionPattern( aNewAttrs, TRUE );
}
void ScViewFunc::SetNumFmtByStr( const String& rCode )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
ScViewData* pViewData = GetViewData();
ScDocument* pDoc = pViewData->GetDocument();
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
// Sprache immer von Cursorposition
sal_uInt32 nCurrentNumberFormat;
2000-09-18 16:07:07 +00:00
pDoc->GetNumberFormat( pViewData->GetCurX(), pViewData->GetCurY(),
pViewData->GetTabNo(), nCurrentNumberFormat );
const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
// Index fuer String bestimmen
BOOL bOk = TRUE;
sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
2000-09-18 16:07:07 +00:00
if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
{
// neu eintragen
String aFormat = rCode; // wird veraendert
xub_StrLen nErrPos = 0;
short nType = 0; //! ???
bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
}
if ( bOk ) // gueltiges Format?
{
ScPatternAttr aNewAttrs( pDoc->GetPool() );
SfxItemSet& rSet = aNewAttrs.GetItemSet();
rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
ApplySelectionPattern( aNewAttrs, TRUE );
}
//! sonst Fehler zuerueckgeben / Meldung ausgeben ???
}
void ScViewFunc::ChangeNumFmtDecimals( BOOL bIncrement )
{
// nur wegen Matrix nicht editierbar? Attribute trotzdem ok
BOOL bOnlyNotBecauseOfMatrix;
if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
{
ErrorMessage(STR_PROTECTIONERR);
return;
}
ScDocument* pDoc = GetViewData()->GetDocument();
SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
SCCOL nCol = GetViewData()->GetCurX();
SCROW nRow = GetViewData()->GetCurY();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
sal_uInt32 nOldFormat;
2000-09-18 16:07:07 +00:00
pDoc->GetNumberFormat( nCol, nRow, nTab, nOldFormat );
const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
if (!pOldEntry)
{
DBG_ERROR("Zahlformat nicht gefunden !!!");
return;
}
// was haben wir denn da?
sal_uInt32 nNewFormat = nOldFormat;
2000-09-18 16:07:07 +00:00
BOOL bError = FALSE;
LanguageType eLanguage = pOldEntry->GetLanguage();
BOOL bThousand, bNegRed;
USHORT nPrecision, nLeading;
2001-01-26 16:50:11 +00:00
pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
2000-09-18 16:07:07 +00:00
short nOldType = pOldEntry->GetType();
if ( 0 == ( nOldType & (
NUMBERFORMAT_NUMBER | NUMBERFORMAT_CURRENCY | NUMBERFORMAT_PERCENT ) ) )
{
// Datum, Zeit, Bruch, logisch, Text kann nicht angepasst werden
//! bei Wisssenschaftlich kann es der Numberformatter auch nicht
bError = TRUE;
}
//! Das SvNumberformat hat einen Member bStandard, verraet ihn aber nicht
BOOL bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
if (bWasStandard)
{
// bei "Standard" die Nachkommastellen abhaengig vom Zellinhalt
// 0 bei leer oder Text -> keine Nachkommastellen
double nVal = pDoc->GetValue( ScAddress( nCol, nRow, nTab ) );
// Die Wege des Numberformatters sind unergruendlich, darum ausprobieren:
String aOut;
Color* pCol;
((SvNumberformat*)pOldEntry)->GetOutputString( nVal, aOut, &pCol );
nPrecision = 0;
// 'E' fuer Exponential ist fest im Numberformatter
if ( aOut.Search('E') != STRING_NOTFOUND )
bError = TRUE; // Exponential nicht veraendern
else
{
String aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
xub_StrLen nPos = aOut.Search( aDecSep );
2000-09-18 16:07:07 +00:00
if ( nPos != STRING_NOTFOUND )
nPrecision = aOut.Len() - nPos - aDecSep.Len();
2000-09-18 16:07:07 +00:00
// sonst 0 behalten
}
}
if (!bError)
{
if (bIncrement)
{
if (nPrecision<20)
++nPrecision; // erhoehen
else
bError = TRUE; // 20 ist Maximum
}
else
{
if (nPrecision)
--nPrecision; // vermindern
else
bError = TRUE; // weniger als 0 geht nicht
}
}
if (!bError)
{
String aNewPicture;
pFormatter->GenerateFormat( aNewPicture, nOldFormat, eLanguage,
bThousand, bNegRed, nPrecision, nLeading );
nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
{
xub_StrLen nErrPos = 0;
short nNewType = 0;
BOOL bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
nNewType, nNewFormat, eLanguage );
DBG_ASSERT( bOk, "falsches Zahlformat generiert" );
if (!bOk)
bError = TRUE;
}
}
if (!bError)
{
ScPatternAttr aNewAttrs( pDoc->GetPool() );
SfxItemSet& rSet = aNewAttrs.GetItemSet();
rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
// ATTR_LANGUAGE_FORMAT nicht
ApplySelectionPattern( aNewAttrs, TRUE );
}
else
Sound::Beep(); // war nix
}
void ScViewFunc::ChangeIndent( BOOL bIncrement )
{
ScViewData* pViewData = GetViewData();
ScDocShell* pDocSh = pViewData->GetDocShell();
ScMarkData& rMark = pViewData->GetMarkData();
ScMarkData aWorkMark = rMark;
ScViewUtil::UnmarkFiltered( aWorkMark, pDocSh->GetDocument() );
2000-09-18 16:07:07 +00:00
aWorkMark.MarkToMulti();
if (!aWorkMark.IsMultiMarked())
{
SCCOL nCol = pViewData->GetCurX();
SCROW nRow = pViewData->GetCurY();
SCTAB nTab = pViewData->GetTabNo();
2000-09-18 16:07:07 +00:00
aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
}
BOOL bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, FALSE );
if (bSuccess)
{
pDocSh->UpdateOle(pViewData);
StartFormatArea();
}
}
BOOL ScViewFunc::InsertName( const String& rName, const String& rSymbol,
const String& rType )
{
// Type = P,R,C,F (und Kombinationen)
//! Undo...
BOOL bOk = FALSE;
ScDocShell* pDocSh = GetViewData()->GetDocShell();
ScDocument* pDoc = pDocSh->GetDocument();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
ScRangeName* pList = pDoc->GetRangeName();
RangeType nType = RT_NAME;
ScRangeData* pNewEntry = new ScRangeData( pDoc, rName, rSymbol,
ScAddress( GetViewData()->GetCurX(), GetViewData()->GetCurY(),
nTab), nType );
2000-09-18 16:07:07 +00:00
String aUpType = rType;
aUpType.ToUpperAscii();
if ( aUpType.Search( 'P' ) != STRING_NOTFOUND )
nType |= RT_PRINTAREA;
if ( aUpType.Search( 'R' ) != STRING_NOTFOUND )
nType |= RT_ROWHEADER;
if ( aUpType.Search( 'C' ) != STRING_NOTFOUND )
nType |= RT_COLHEADER;
if ( aUpType.Search( 'F' ) != STRING_NOTFOUND )
nType |= RT_CRITERIA;
pNewEntry->AddType(nType);
if ( !pNewEntry->GetErrCode() ) // Text gueltig?
{
ScDocShellModificator aModificator( *pDocSh );
pDoc->CompileNameFormula( TRUE ); // CreateFormulaString
// Eintrag bereits vorhanden? Dann vorher entfernen (=Aendern)
USHORT nFoundAt;
if ( pList->SearchName( rName, nFoundAt ) )
{ // alten Index uebernehmen
pNewEntry->SetIndex( ((ScRangeData*)pList->At(nFoundAt))->GetIndex() );
pList->AtFree( nFoundAt );
}
if ( pList->Insert( pNewEntry ) )
{
pNewEntry = NULL; // nicht loeschen
bOk = TRUE;
}
pDoc->CompileNameFormula( FALSE ); // CompileFormulaString
aModificator.SetDocumentModified();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
}
delete pNewEntry; // wenn er nicht eingefuegt wurde
return bOk;
}
void ScViewFunc::CreateNames( USHORT nFlags )
{
BOOL bDone = FALSE;
ScRange aRange;
if ( GetViewData()->GetSimpleArea(aRange) )
bDone = GetViewData()->GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, FALSE );
if (!bDone)
ErrorMessage(STR_CREATENAME_MARKERR);
}
USHORT ScViewFunc::GetCreateNameFlags()
{
USHORT nFlags = 0;
SCCOL nStartCol, nEndCol;
SCROW nStartRow, nEndRow;
SCTAB nDummy;
2000-09-18 16:07:07 +00:00
if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy))
{
ScDocument* pDoc = GetViewData()->GetDocument();
SCTAB nTab = GetViewData()->GetTabNo();
2000-09-18 16:07:07 +00:00
BOOL bOk;
SCCOL i;
SCROW j;
2000-09-18 16:07:07 +00:00
bOk = TRUE;
SCCOL nFirstCol = nStartCol;
SCCOL nLastCol = nEndCol;
2000-09-18 16:07:07 +00:00
if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
for (i=nFirstCol; i<=nLastCol && bOk; i++)
if (!pDoc->HasStringData( i,nStartRow,nTab ))
bOk = FALSE;
if (bOk)
nFlags |= NAME_TOP;
else // Bottom nur wenn nicht Top
{
bOk = TRUE;
for (i=nFirstCol; i<=nLastCol && bOk; i++)
if (!pDoc->HasStringData( i,nEndRow,nTab ))
bOk = FALSE;
if (bOk)
nFlags |= NAME_BOTTOM;
}
bOk = TRUE;
SCROW nFirstRow = nStartRow;
SCROW nLastRow = nEndRow;
2000-09-18 16:07:07 +00:00
if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
for (j=nFirstRow; j<=nLastRow && bOk; j++)
if (!pDoc->HasStringData( nStartCol,j,nTab ))
2000-09-18 16:07:07 +00:00
bOk = FALSE;
if (bOk)
nFlags |= NAME_LEFT;
else // Right nur wenn nicht Left
{
bOk = TRUE;
for (j=nFirstRow; j<=nLastRow && bOk; j++)
if (!pDoc->HasStringData( nEndCol,j,nTab ))
2000-09-18 16:07:07 +00:00
bOk = FALSE;
if (bOk)
nFlags |= NAME_RIGHT;
}
}
if (nStartCol == nEndCol)
nFlags &= ~( NAME_LEFT | NAME_RIGHT );
if (nStartRow == nEndRow)
nFlags &= ~( NAME_TOP | NAME_BOTTOM );
return nFlags;
}
void ScViewFunc::InsertNameList()
{
ScAddress aPos( GetViewData()->GetCurX(), GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
ScDocShell* pDocSh = GetViewData()->GetDocShell();
if ( pDocSh->GetDocFunc().InsertNameList( aPos, FALSE ) )
pDocSh->UpdateOle(GetViewData());
}