| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sw.hxx" |
| |
| #include <editeng/boxitem.hxx> |
| #include <editeng/protitem.hxx> |
| |
| #include <hintids.hxx> |
| #include <fmtanchr.hxx> |
| #include <fmtfsize.hxx> |
| #include <frmatr.hxx> |
| #include <tblsel.hxx> |
| #include <crsrsh.hxx> |
| #include <doc.hxx> |
| #include <IDocumentUndoRedo.hxx> |
| #include <docary.hxx> |
| #include <pam.hxx> |
| #include <ndtxt.hxx> |
| #include <ndole.hxx> |
| #include <swtable.hxx> |
| #include <cntfrm.hxx> |
| #include <tabfrm.hxx> |
| #include <rowfrm.hxx> |
| #include <cellfrm.hxx> |
| #include <pagefrm.hxx> |
| #include <rootfrm.hxx> |
| #include <viscrs.hxx> |
| #include <swtblfmt.hxx> |
| #include <UndoTable.hxx> |
| #include <mvsave.hxx> |
| #include <sectfrm.hxx> |
| #include <frmtool.hxx> |
| #include <switerator.hxx> |
| #include <deque> |
| |
| //siehe auch swtable.cxx |
| #define COLFUZZY 20L |
| |
| // defines, die bestimmen, wie Tabellen Boxen gemergt werden: |
| // - 1. alle leeren Zeilen entfernen, alle Boxen werden mit Blank, |
| // alle Lines mit ParaBreak getrennt |
| // - 2. alle leeren Zeilen und alle leeren Boxen am Anfang und Ende |
| // entfernen, alle Boxen werden mit Blank, |
| // alle Lines mit ParaBreak getrennt |
| // - 3. alle leeren Boxen entfernen, alle Boxen werden mit Blank, |
| // alle Lines mit ParaBreak getrennt |
| |
| #undef DEL_ONLY_EMPTY_LINES |
| #undef DEL_EMPTY_BOXES_AT_START_AND_END |
| #define DEL_ALL_EMPTY_BOXES |
| |
| |
| _SV_IMPL_SORTAR_ALG( SwSelBoxes, SwTableBoxPtr ) |
| sal_Bool SwSelBoxes::Seek_Entry( const SwTableBoxPtr rSrch, sal_uInt16* pFndPos ) const |
| { |
| sal_uLong nIdx = rSrch->GetSttIdx(); |
| |
| sal_uInt16 nO = Count(), nM, nU = 0; |
| if( nO > 0 ) |
| { |
| nO--; |
| while( nU <= nO ) |
| { |
| nM = nU + ( nO - nU ) / 2; |
| if( (*this)[ nM ]->GetSttNd() == rSrch->GetSttNd() ) |
| { |
| if( pFndPos ) |
| *pFndPos = nM; |
| return sal_True; |
| } |
| else if( (*this)[ nM ]->GetSttIdx() < nIdx ) |
| nU = nM + 1; |
| else if( nM == 0 ) |
| { |
| if( pFndPos ) |
| *pFndPos = nU; |
| return sal_False; |
| } |
| else |
| nO = nM - 1; |
| } |
| } |
| if( pFndPos ) |
| *pFndPos = nU; |
| return sal_False; |
| } |
| |
| |
| SV_IMPL_PTRARR( SwCellFrms, SwCellFrm* ) |
| |
| struct _CmpLPt |
| { |
| Point aPos; |
| const SwTableBox* pSelBox; |
| sal_Bool bVert; |
| |
| _CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical ); |
| |
| sal_Bool operator==( const _CmpLPt& rCmp ) const |
| { return X() == rCmp.X() && Y() == rCmp.Y() ? sal_True : sal_False; } |
| |
| sal_Bool operator<( const _CmpLPt& rCmp ) const |
| { |
| if ( bVert ) |
| return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() ) |
| ? sal_True : sal_False; |
| else |
| return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() ) |
| ? sal_True : sal_False; |
| } |
| |
| long X() const { return aPos.X(); } |
| long Y() const { return aPos.Y(); } |
| }; |
| |
| |
| SV_DECL_VARARR_SORT( _MergePos, _CmpLPt, 0, 40 ) |
| SV_IMPL_VARARR_SORT( _MergePos, _CmpLPt ) |
| |
| SV_IMPL_PTRARR( _FndBoxes, _FndBox* ) |
| SV_IMPL_PTRARR( _FndLines, _FndLine* ) |
| |
| |
| struct _Sort_CellFrm |
| { |
| const SwCellFrm* pFrm; |
| |
| _Sort_CellFrm( const SwCellFrm& rCFrm ) |
| : pFrm( &rCFrm ) {} |
| }; |
| |
| typedef std::deque< _Sort_CellFrm > _Sort_CellFrms; |
| |
| SV_IMPL_PTRARR( SwChartBoxes, SwTableBoxPtr ); |
| SV_IMPL_PTRARR( SwChartLines, SwChartBoxes* ); |
| |
| const SwLayoutFrm *lcl_FindCellFrm( const SwLayoutFrm *pLay ) |
| { |
| while ( pLay && !pLay->IsCellFrm() ) |
| pLay = pLay->GetUpper(); |
| return pLay; |
| } |
| |
| const SwLayoutFrm *lcl_FindNextCellFrm( const SwLayoutFrm *pLay ) |
| { |
| //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche) |
| const SwLayoutFrm *pTmp = pLay; |
| do { |
| pTmp = pTmp->GetNextLayoutLeaf(); |
| } while( pLay->IsAnLower( pTmp ) ); |
| |
| while( pTmp && !pTmp->IsCellFrm() ) |
| pTmp = pTmp->GetUpper(); |
| return pTmp; |
| } |
| |
| void GetTblSelCrs( const SwCrsrShell &rShell, SwSelBoxes& rBoxes ) |
| { |
| if( rBoxes.Count() ) |
| rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); |
| if( rShell.IsTableMode() && ((SwCrsrShell&)rShell).UpdateTblSelBoxes()) |
| rBoxes.Insert( &rShell.GetTableCrsr()->GetBoxes() ); |
| } |
| |
| void GetTblSelCrs( const SwTableCursor& rTblCrsr, SwSelBoxes& rBoxes ) |
| { |
| if( rBoxes.Count() ) |
| rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); |
| |
| if( rTblCrsr.IsChgd() || !rTblCrsr.GetBoxesCount() ) |
| { |
| SwTableCursor* pTCrsr = (SwTableCursor*)&rTblCrsr; |
| pTCrsr->GetDoc()->GetCurrentLayout()->MakeTblCrsrs( *pTCrsr ); //swmod 080218 |
| } |
| |
| if( rTblCrsr.GetBoxesCount() ) |
| rBoxes.Insert( &rTblCrsr.GetBoxes() ); |
| } |
| |
| void GetTblSel( const SwCrsrShell& rShell, SwSelBoxes& rBoxes, |
| const SwTblSearchType eSearchType ) |
| { |
| //Start- und Endzelle besorgen und den naechsten fragen. |
| if ( !rShell.IsTableMode() ) |
| rShell.GetCrsr(); |
| |
| GetTblSel( *rShell.getShellCrsr(false), rBoxes, eSearchType ); |
| } |
| |
| void GetTblSel( const SwCursor& rCrsr, SwSelBoxes& rBoxes, |
| const SwTblSearchType eSearchType ) |
| { |
| //Start- und Endzelle besorgen und den naechsten fragen. |
| ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ), |
| "Tabselection nicht auf Cnt." ); |
| |
| // Zeilen-Selektion: |
| // teste ob Tabelle komplex ist. Wenn ja, dann immer uebers Layout |
| // die selektierten Boxen zusammen suchen. Andernfalls ueber die |
| // Tabellen-Struktur (fuer Makros !!) |
| const SwCntntNode* pContentNd = rCrsr.GetNode()->GetCntntNode(); |
| const SwTableNode* pTblNd = pContentNd ? pContentNd->FindTableNode() : 0; |
| if( pTblNd && pTblNd->GetTable().IsNewModel() ) |
| { |
| SwTable::SearchType eSearch; |
| switch( nsSwTblSearchType::TBLSEARCH_COL & eSearchType ) |
| { |
| case nsSwTblSearchType::TBLSEARCH_ROW: eSearch = SwTable::SEARCH_ROW; break; |
| case nsSwTblSearchType::TBLSEARCH_COL: eSearch = SwTable::SEARCH_COL; break; |
| default: eSearch = SwTable::SEARCH_NONE; break; |
| } |
| const bool bChkP = 0 != ( nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); |
| pTblNd->GetTable().CreateSelection( rCrsr, rBoxes, eSearch, bChkP ); |
| return; |
| } |
| if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) && |
| pTblNd && !pTblNd->GetTable().IsTblComplex() ) |
| { |
| const SwTable& rTbl = pTblNd->GetTable(); |
| const SwTableLines& rLines = rTbl.GetTabLines(); |
| |
| const SwNode* pMarkNode = rCrsr.GetNode( sal_False ); |
| const sal_uLong nMarkSectionStart = pMarkNode->StartOfSectionIndex(); |
| const SwTableBox* pMarkBox = rTbl.GetTblBox( nMarkSectionStart ); |
| |
| ASSERT( pMarkBox, "Point in table, mark outside?" ) |
| |
| const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : 0; |
| sal_uInt16 nSttPos = rLines.GetPos( pLine ); |
| ASSERT( USHRT_MAX != nSttPos, "Wo ist meine Zeile in der Tabelle?" ); |
| pLine = rTbl.GetTblBox( rCrsr.GetNode( sal_True )->StartOfSectionIndex() )->GetUpper(); |
| sal_uInt16 nEndPos = rLines.GetPos( pLine ); |
| ASSERT( USHRT_MAX != nEndPos, "Wo ist meine Zeile in der Tabelle?" ); |
| // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX |
| if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX ) |
| { |
| if( nEndPos < nSttPos ) // vertauschen |
| { |
| sal_uInt16 nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp; |
| } |
| |
| int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType; |
| for( ; nSttPos <= nEndPos; ++nSttPos ) |
| { |
| pLine = rLines[ nSttPos ]; |
| for( sal_uInt16 n = pLine->GetTabBoxes().Count(); n ; ) |
| { |
| SwTableBox* pBox = pLine->GetTabBoxes()[ --n ]; |
| // Zellenschutzt beachten ?? |
| if( !bChkProtected || |
| !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) |
| rBoxes.Insert( pBox ); |
| } |
| } |
| } |
| } |
| else |
| { |
| Point aPtPos, aMkPos; |
| const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); |
| if( pShCrsr ) |
| { |
| aPtPos = pShCrsr->GetPtPos(); |
| aMkPos = pShCrsr->GetMkPos(); |
| } |
| const SwCntntNode *pCntNd = rCrsr.GetCntntNode(); |
| const SwLayoutFrm *pStart = pCntNd ? |
| pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aPtPos )->GetUpper() : 0; |
| pCntNd = rCrsr.GetCntntNode(sal_False); |
| const SwLayoutFrm *pEnd = pCntNd ? |
| pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aMkPos )->GetUpper() : 0; |
| if( pStart && pEnd ) |
| GetTblSel( pStart, pEnd, rBoxes, 0, eSearchType ); |
| } |
| } |
| |
| void GetTblSel( const SwLayoutFrm* pStart, const SwLayoutFrm* pEnd, |
| SwSelBoxes& rBoxes, SwCellFrms* pCells, |
| const SwTblSearchType eSearchType ) |
| { |
| // #112697# Robust: |
| const SwTabFrm* pStartTab = pStart->FindTabFrm(); |
| if ( !pStartTab ) |
| { |
| ASSERT( false, "GetTblSel without start table" ) |
| return; |
| } |
| |
| int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType; |
| |
| sal_Bool bTblIsValid; |
| // --> FME 2006-01-25 #i55421# Reduced value 10 |
| int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292 |
| // <-- |
| sal_uInt16 i; |
| |
| do { |
| bTblIsValid = sal_True; |
| |
| //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. |
| SwSelUnions aUnions; |
| ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType ); |
| |
| Point aCurrentTopLeft( LONG_MAX, LONG_MAX ); |
| Point aCurrentTopRight( 0, LONG_MAX ); |
| Point aCurrentBottomLeft( LONG_MAX, 0 ); |
| Point aCurrentBottomRight( 0, 0 ); |
| const SwCellFrm* pCurrentTopLeftFrm = 0; |
| const SwCellFrm* pCurrentTopRightFrm = 0; |
| const SwCellFrm* pCurrentBottomLeftFrm = 0; |
| const SwCellFrm* pCurrentBottomRightFrm = 0; |
| |
| //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. |
| for( i = 0; i < aUnions.Count() && bTblIsValid; ++i ) |
| { |
| SwSelUnion *pUnion = aUnions[i]; |
| const SwTabFrm *pTable = pUnion->GetTable(); |
| if( !pTable->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while( pRow && bTblIsValid ) |
| { |
| if( !pRow->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) |
| { |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while( bTblIsValid && pCell && pRow->IsAnLower( pCell ) ) |
| { |
| if( !pCell->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) |
| { |
| SwTableBox* pBox = (SwTableBox*) |
| ((SwCellFrm*)pCell)->GetTabBox(); |
| // Zellenschutzt beachten ?? |
| if( !bChkProtected || |
| !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) |
| rBoxes.Insert( pBox ); |
| |
| if ( pCells ) |
| { |
| const Point aTopLeft( pCell->Frm().TopLeft() ); |
| const Point aTopRight( pCell->Frm().TopRight() ); |
| const Point aBottomLeft( pCell->Frm().BottomLeft() ); |
| const Point aBottomRight( pCell->Frm().BottomRight() ); |
| |
| if ( aTopLeft.Y() < aCurrentTopLeft.Y() || |
| ( aTopLeft.Y() == aCurrentTopLeft.Y() && |
| aTopLeft.X() < aCurrentTopLeft.X() ) ) |
| { |
| aCurrentTopLeft = aTopLeft; |
| pCurrentTopLeftFrm = static_cast<const SwCellFrm*>( pCell ); |
| } |
| |
| if ( aTopRight.Y() < aCurrentTopRight.Y() || |
| ( aTopRight.Y() == aCurrentTopRight.Y() && |
| aTopRight.X() > aCurrentTopRight.X() ) ) |
| { |
| aCurrentTopRight = aTopRight; |
| pCurrentTopRightFrm = static_cast<const SwCellFrm*>( pCell ); |
| } |
| |
| if ( aBottomLeft.Y() > aCurrentBottomLeft.Y() || |
| ( aBottomLeft.Y() == aCurrentBottomLeft.Y() && |
| aBottomLeft.X() < aCurrentBottomLeft.X() ) ) |
| { |
| aCurrentBottomLeft = aBottomLeft; |
| pCurrentBottomLeftFrm = static_cast<const SwCellFrm*>( pCell ); |
| } |
| |
| if ( aBottomRight.Y() > aCurrentBottomRight.Y() || |
| ( aBottomRight.Y() == aCurrentBottomRight.Y() && |
| aBottomRight.X() > aCurrentBottomRight.X() ) ) |
| { |
| aCurrentBottomRight = aBottomRight; |
| pCurrentBottomRightFrm = static_cast<const SwCellFrm*>( pCell ); |
| } |
| |
| } |
| } |
| if ( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| } |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| } |
| |
| if ( pCells ) |
| { |
| pCells->Remove( 0, pCells->Count() ); |
| pCells->Insert( pCurrentTopLeftFrm, 0 ); |
| pCells->Insert( pCurrentTopRightFrm, 1 ); |
| pCells->Insert( pCurrentBottomLeftFrm, 2 ); |
| pCells->Insert( pCurrentBottomRightFrm, 3 ); |
| } |
| |
| if( bTblIsValid ) |
| break; |
| |
| SwDeletionChecker aDelCheck( pStart ); |
| |
| // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen |
| // und nochmals neu aufsetzen |
| SwTabFrm *pTable = aUnions[0]->GetTable(); |
| while( pTable ) |
| { |
| if( pTable->IsValid() ) |
| pTable->InvalidatePos(); |
| pTable->SetONECalcLowers(); |
| pTable->Calc(); |
| pTable->SetCompletePaint(); |
| if( 0 == (pTable = pTable->GetFollow()) ) |
| break; |
| } |
| |
| // --> FME 2005-10-13 #125337# Make code robust, check if pStart has |
| // been deleted due to the formatting of the table: |
| if ( aDelCheck.HasBeenDeleted() ) |
| { |
| ASSERT( false, "Current box has been deleted during GetTblSel()" ) |
| break; |
| } |
| // <-- |
| |
| i = 0; |
| rBoxes.Remove( i, rBoxes.Count() ); |
| --nLoopMax; |
| |
| } while( sal_True ); |
| ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" ); |
| } |
| |
| |
| |
| sal_Bool ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd, |
| SwChartLines* pGetCLines ) |
| { |
| const SwTableNode* pTNd = rSttNd.FindTableNode(); |
| if( !pTNd ) |
| return sal_False; |
| |
| Point aNullPos; |
| SwNodeIndex aIdx( rSttNd ); |
| const SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); |
| if( !pCNd ) |
| pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False ); |
| |
| // #109394# if table is invisible, return |
| // (layout needed for forming table selection further down, so we can't |
| // continue with invisible tables) |
| // OD 07.11.2003 #i22135# - Also the content of the table could be |
| // invisible - e.g. in a hidden section |
| // Robust: check, if content was found (e.g. empty table cells) |
| if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL ) |
| return sal_False; |
| |
| const SwLayoutFrm *pStart = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0; |
| ASSERT( pStart, "ohne Frame geht gar nichts" ); |
| |
| aIdx = rEndNd; |
| pCNd = aIdx.GetNode().GetCntntNode(); |
| if( !pCNd ) |
| pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False ); |
| |
| // OD 07.11.2003 #i22135# - Robust: check, if content was found and if it's visible |
| if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL ) |
| { |
| return sal_False; |
| } |
| |
| const SwLayoutFrm *pEnd = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0; |
| ASSERT( pEnd, "ohne Frame geht gar nichts" ); |
| |
| |
| sal_Bool bTblIsValid, bValidChartSel; |
| // --> FME 2006-01-25 #i55421# Reduced value 10 |
| int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292 |
| // <-- |
| sal_uInt16 i = 0; |
| |
| do { |
| bTblIsValid = sal_True; |
| bValidChartSel = sal_True; |
| |
| sal_uInt16 nRowCells = USHRT_MAX; |
| |
| //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. |
| SwSelUnions aUnions; |
| ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT ); |
| |
| //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. |
| for( i = 0; i < aUnions.Count() && bTblIsValid && |
| bValidChartSel; ++i ) |
| { |
| SwSelUnion *pUnion = aUnions[i]; |
| const SwTabFrm *pTable = pUnion->GetTable(); |
| |
| SWRECTFN( pTable ) |
| sal_Bool bRTL = pTable->IsRightToLeft(); |
| |
| if( !pTable->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| _Sort_CellFrms aCellFrms; |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while( pRow && bTblIsValid && bValidChartSel ) |
| { |
| if( !pRow->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) |
| { |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while( bValidChartSel && bTblIsValid && pCell && |
| pRow->IsAnLower( pCell ) ) |
| { |
| if( !pCell->IsValid() && nLoopMax ) |
| { |
| bTblIsValid = sal_False; |
| break; |
| } |
| |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| const SwRect& rUnion = pUnion->GetUnion(), |
| & rFrmRect = pCell->Frm(); |
| |
| const long nUnionRight = rUnion.Right(); |
| const long nUnionBottom = rUnion.Bottom(); |
| const long nFrmRight = rFrmRect.Right(); |
| const long nFrmBottom = rFrmRect.Bottom(); |
| |
| // liegt das FrmRect ausserhalb der Union, kann es |
| // ignoriert werden. |
| |
| const long nXFuzzy = bVert ? 0 : 20; |
| const long nYFuzzy = bVert ? 20 : 0; |
| |
| if( !( rUnion.Top() + nYFuzzy > nFrmBottom || |
| nUnionBottom < rFrmRect.Top() + nYFuzzy || |
| rUnion.Left() + nXFuzzy > nFrmRight || |
| nUnionRight < rFrmRect.Left() + nXFuzzy )) |
| { |
| // ok, rUnion is _not_ completely outside of rFrmRect |
| |
| // wenn es aber nicht komplett in der Union liegt, |
| // dann ist es fuers Chart eine ungueltige |
| // Selektion. |
| if( rUnion.Left() <= rFrmRect.Left() + nXFuzzy && |
| rFrmRect.Left() <= nUnionRight && |
| rUnion.Left() <= nFrmRight && |
| nFrmRight <= nUnionRight + nXFuzzy && |
| rUnion.Top() <= rFrmRect.Top() + nYFuzzy && |
| rFrmRect.Top() <= nUnionBottom && |
| rUnion.Top() <= nFrmBottom && |
| nFrmBottom <= nUnionBottom+ nYFuzzy ) |
| |
| aCellFrms.push_back( |
| _Sort_CellFrm( *(SwCellFrm*)pCell) ); |
| else |
| { |
| bValidChartSel = sal_False; |
| break; |
| } |
| } |
| if ( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| } |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| |
| if( !bValidChartSel ) |
| break; |
| |
| // alle Zellen der (Teil-)Tabelle zusammen. Dann teste mal ob |
| // all huebsch nebeneinander liegen. |
| size_t n; |
| sal_uInt16 nCellCnt = 0; |
| long nYPos = LONG_MAX; |
| long nXPos = 0; |
| long nHeight = 0; |
| |
| for( n = 0 ; n < aCellFrms.size(); ++n ) |
| { |
| const _Sort_CellFrm& rCF = aCellFrms[ n ]; |
| if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) |
| { |
| // neue Zeile |
| if( n ) |
| { |
| if( USHRT_MAX == nRowCells ) // 1. Zeilenwechsel |
| nRowCells = nCellCnt; |
| else if( nRowCells != nCellCnt ) |
| { |
| bValidChartSel = sal_False; |
| break; |
| } |
| } |
| nCellCnt = 1; |
| nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); |
| nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)(); |
| |
| nXPos = bRTL ? |
| (rCF.pFrm->Frm().*fnRect->fnGetLeft)() : |
| (rCF.pFrm->Frm().*fnRect->fnGetRight)(); |
| } |
| else if( nXPos == ( bRTL ? |
| (rCF.pFrm->Frm().*fnRect->fnGetRight)() : |
| (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) && |
| nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() ) |
| { |
| nXPos += ( bRTL ? (-1) : 1 ) * |
| (rCF.pFrm->Frm().*fnRect->fnGetWidth)(); |
| ++nCellCnt; |
| } |
| else |
| { |
| bValidChartSel = sal_False; |
| break; |
| } |
| } |
| if( bValidChartSel ) |
| { |
| if( USHRT_MAX == nRowCells ) |
| nRowCells = nCellCnt; |
| else if( nRowCells != nCellCnt ) |
| bValidChartSel = sal_False; |
| } |
| |
| if( bValidChartSel && pGetCLines ) |
| { |
| nYPos = LONG_MAX; |
| SwChartBoxes* pBoxes = 0; |
| for( n = 0; n < aCellFrms.size(); ++n ) |
| { |
| const _Sort_CellFrm& rCF = aCellFrms[ n ]; |
| if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) |
| { |
| pBoxes = new SwChartBoxes( 255 < nRowCells |
| ? 255 : (sal_uInt8)nRowCells); |
| pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() ); |
| nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); |
| } |
| SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox(); |
| pBoxes->Insert( pBox, pBoxes->Count() ); |
| } |
| } |
| } |
| |
| if( bTblIsValid ) |
| break; |
| |
| // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen |
| // und nochmals neu aufsetzen |
| SwTabFrm *pTable = aUnions[0]->GetTable(); |
| for( i = 0; i < aUnions.Count(); ++i ) |
| { |
| if( pTable->IsValid() ) |
| pTable->InvalidatePos(); |
| pTable->SetONECalcLowers(); |
| pTable->Calc(); |
| pTable->SetCompletePaint(); |
| if( 0 == (pTable = pTable->GetFollow()) ) |
| break; |
| } |
| --nLoopMax; |
| if( pGetCLines ) |
| pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); |
| } while( sal_True ); |
| |
| ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" ); |
| |
| if( !bValidChartSel && pGetCLines ) |
| pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); |
| |
| return bValidChartSel; |
| } |
| |
| |
| sal_Bool IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell ) |
| { |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" ); |
| |
| if( pCell->FindTabFrm()->IsVertical() ) |
| return ( rUnion.Right() >= pCell->Frm().Right() && |
| rUnion.Left() <= pCell->Frm().Left() && |
| (( rUnion.Top() <= pCell->Frm().Top()+20 && |
| rUnion.Bottom() > pCell->Frm().Top() ) || |
| ( rUnion.Top() >= pCell->Frm().Top() && |
| rUnion.Bottom() < pCell->Frm().Bottom() )) ? sal_True : sal_False ); |
| |
| return ( |
| rUnion.Top() <= pCell->Frm().Top() && |
| rUnion.Bottom() >= pCell->Frm().Bottom() && |
| |
| (( rUnion.Left() <= pCell->Frm().Left()+20 && |
| rUnion.Right() > pCell->Frm().Left() ) || |
| |
| ( rUnion.Left() >= pCell->Frm().Left() && |
| rUnion.Right() < pCell->Frm().Right() )) ? sal_True : sal_False ); |
| } |
| |
| sal_Bool GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes ) |
| { |
| SwShellCrsr* pCrsr = rShell.pCurCrsr; |
| if ( rShell.IsTableMode() ) |
| pCrsr = rShell.pTblCrsr; |
| |
| const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->getLayoutFrm( rShell.GetLayout(), |
| &pCrsr->GetPtPos() )->GetUpper(), |
| *pEnd = pCrsr->GetCntntNode(sal_False)->getLayoutFrm( rShell.GetLayout(), |
| &pCrsr->GetMkPos() )->GetUpper(); |
| |
| const SwLayoutFrm* pSttCell = pStart; |
| while( pSttCell && !pSttCell->IsCellFrm() ) |
| pSttCell = pSttCell->GetUpper(); |
| |
| //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. |
| SwSelUnions aUnions; |
| |
| // default erstmal nach oben testen, dann nach links |
| ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL ); |
| |
| sal_Bool bTstRow = sal_True, bFound = sal_False; |
| sal_uInt16 i; |
| |
| // 1. teste ob die darueber liegende Box Value/Formel enhaelt: |
| for( i = 0; i < aUnions.Count(); ++i ) |
| { |
| SwSelUnion *pUnion = aUnions[i]; |
| const SwTabFrm *pTable = pUnion->GetTable(); |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while( pRow ) |
| { |
| if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) |
| { |
| const SwCellFrm* pUpperCell = 0; |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while( pCell && pRow->IsAnLower( pCell ) ) |
| { |
| if( pCell == pSttCell ) |
| { |
| sal_uInt16 nWhichId = 0; |
| for( sal_uInt16 n = rBoxes.Count(); n; ) |
| if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] |
| ->GetTabBox()->IsFormulaOrValueBox() )) |
| break; |
| |
| // alle Boxen zusammen, nicht mehr die Zeile |
| // pruefen, wenn eine Formel oder Value gefunden wurde |
| bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId; |
| bFound = sal_True; |
| break; |
| } |
| |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) |
| pUpperCell = (SwCellFrm*)pCell; |
| |
| if( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| |
| if( pUpperCell ) |
| rBoxes.Insert( pUpperCell, rBoxes.Count() ); |
| } |
| if( bFound ) |
| { |
| i = aUnions.Count(); |
| break; |
| } |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| } |
| |
| |
| // 2. teste ob die links liegende Box Value/Formel enhaelt: |
| if( bTstRow ) |
| { |
| bFound = sal_False; |
| |
| rBoxes.Remove( 0, rBoxes.Count() ); |
| aUnions.DeleteAndDestroy( 0, aUnions.Count() ); |
| ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW ); |
| |
| for( i = 0; i < aUnions.Count(); ++i ) |
| { |
| SwSelUnion *pUnion = aUnions[i]; |
| const SwTabFrm *pTable = pUnion->GetTable(); |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while( pRow ) |
| { |
| if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) |
| { |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while( pCell && pRow->IsAnLower( pCell ) ) |
| { |
| if( pCell == pSttCell ) |
| { |
| sal_uInt16 nWhichId = 0; |
| for( sal_uInt16 n = rBoxes.Count(); n; ) |
| if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] |
| ->GetTabBox()->IsFormulaOrValueBox() )) |
| break; |
| |
| // alle Boxen zusammen, nicht mehr die Zeile |
| // pruefen, wenn eine Formel oder Value gefunden wurde |
| bFound = 0 != nWhichId && USHRT_MAX != nWhichId; |
| bTstRow = sal_False; |
| break; |
| } |
| |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) |
| { |
| const SwCellFrm* pC = (SwCellFrm*)pCell; |
| rBoxes.Insert( pC, rBoxes.Count() ); |
| } |
| if( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| } |
| if( !bTstRow ) |
| { |
| i = aUnions.Count(); |
| break; |
| } |
| |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| } |
| } |
| |
| return bFound; |
| } |
| |
| sal_Bool HasProtectedCells( const SwSelBoxes& rBoxes ) |
| { |
| sal_Bool bRet = sal_False; |
| for( sal_uInt16 n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n ) |
| if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() ) |
| { |
| bRet = sal_True; |
| break; |
| } |
| return bRet; |
| } |
| |
| |
| _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical ) |
| : aPos( rPt ), pSelBox( pBox ), bVert( bVertical ) |
| {} |
| |
| void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox, |
| sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 ) |
| { |
| ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" ); |
| SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ] |
| ->GetCntntNode(); |
| if( pCNd && pCNd->IsTxtNode() ) |
| pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), |
| (SwTableBoxFmt*)pBox->GetFrmFmt(), |
| ((SwTxtNode*)pCNd)->GetTxtColl(), |
| pCNd->GetpSwAttrSet(), |
| nInsPos, nCnt ); |
| else |
| pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), |
| (SwTableBoxFmt*)pBox->GetFrmFmt(), |
| (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0, |
| nInsPos, nCnt ); |
| } |
| |
| sal_Bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam ) |
| { |
| rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode(); |
| rPam.Move( fnMoveBackward, fnGoCntnt ); |
| rPam.SetMark(); |
| rPam.GetPoint()->nNode = *rBox.GetSttNd(); |
| rPam.Move( fnMoveForward, fnGoCntnt ); |
| sal_Bool bRet = *rPam.GetMark() == *rPam.GetPoint() |
| && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() ); |
| |
| if( bRet ) |
| { |
| // dann teste mal auf absatzgebundenen Flys |
| const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts(); |
| sal_uLong nSttIdx = rPam.GetPoint()->nNode.GetIndex(), |
| nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(), |
| nIdx; |
| |
| for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) |
| { |
| const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor(); |
| const SwPosition* pAPos = rAnchor.GetCntntAnchor(); |
| if (pAPos && |
| ((FLY_AT_PARA == rAnchor.GetAnchorId()) || |
| (FLY_AT_CHAR == rAnchor.GetAnchorId())) && |
| nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) && |
| nIdx < nEndIdx ) |
| { |
| bRet = sal_False; |
| break; |
| } |
| } |
| } |
| return bRet; |
| } |
| |
| |
| void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes, |
| SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo ) |
| { |
| if( rBoxes.Count() ) |
| rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); |
| |
| //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. |
| ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( sal_False ), |
| "Tabselection nicht auf Cnt." ); |
| |
| //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht |
| // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, |
| // das die 1. Headline mit drin ist. |
| // Point aPt( rShell.GetCharRect().Pos() ); |
| Point aPt( 0, 0 ); |
| |
| const SwCntntNode* pCntNd = rPam.GetCntntNode(); |
| const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aPt )->GetUpper(); |
| pCntNd = rPam.GetCntntNode(sal_False); |
| const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aPt )->GetUpper(); |
| |
| SwSelUnions aUnions; |
| ::MakeSelUnions( aUnions, pStart, pEnd ); |
| if( !aUnions.Count() ) |
| return; |
| |
| const SwTable *pTable = aUnions[0]->GetTable()->GetTable(); |
| SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc(); |
| SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]-> |
| GetSttNd()->FindTableNode(); |
| |
| _MergePos aPosArr; // Sort-Array mit den Positionen der Frames |
| long nWidth; |
| SwTableBox* pLastBox = 0; |
| |
| SWRECTFN( pStart->GetUpper() ) |
| |
| for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) |
| { |
| const SwTabFrm *pTabFrm = aUnions[i]->GetTable(); |
| |
| SwRect &rUnion = aUnions[i]->GetUnion(); |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTabFrm->IsFollow() ? |
| pTabFrm->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTabFrm->Lower(); |
| |
| while ( pRow ) |
| { |
| if ( pRow->Frm().IsOver( rUnion ) ) |
| { |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while ( pCell && pRow->IsAnLower( pCell ) ) |
| { |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| // in der vollen Breite ueberlappend ? |
| if( rUnion.Top() <= pCell->Frm().Top() && |
| rUnion.Bottom() >= pCell->Frm().Bottom() ) |
| { |
| SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox(); |
| |
| // nur nach rechts ueberlappend |
| if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() && |
| ( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() ) |
| { |
| if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) |
| { |
| sal_uInt16 nInsPos = pBox->GetUpper()-> |
| GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1; |
| lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos ); |
| pBox->ClaimFrmFmt(); |
| SwFmtFrmSize aNew( |
| pBox->GetFrmFmt()->GetFrmSize() ); |
| nWidth = rUnion.Right() - pCell->Frm().Left(); |
| nWidth = nWidth * aNew.GetWidth() / |
| pCell->Frm().Width(); |
| long nTmpWidth = aNew.GetWidth() - nWidth; |
| aNew.SetWidth( nWidth ); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| // diese Box ist selektiert |
| pLastBox = pBox; |
| rBoxes.Insert( pBox ); |
| aPosArr.Insert( |
| _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), |
| pBox, bVert ) ); |
| |
| pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; |
| aNew.SetWidth( nTmpWidth ); |
| pBox->ClaimFrmFmt(); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| |
| if( pUndo ) |
| pUndo->AddNewBox( pBox->GetSttIdx() ); |
| } |
| else |
| { |
| // diese Box ist selektiert |
| pLastBox = pBox; |
| rBoxes.Insert( pBox ); |
| #if OSL_DEBUG_LEVEL > 1 |
| Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() ); |
| #endif |
| aPosArr.Insert( |
| _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), |
| pBox, bVert ) ); |
| } |
| } |
| // oder rechts und links ueberlappend |
| else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() && |
| ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) |
| { |
| sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). |
| C40_GETPOS( SwTableBox, pBox )+1; |
| lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 ); |
| pBox->ClaimFrmFmt(); |
| SwFmtFrmSize aNew( |
| pBox->GetFrmFmt()->GetFrmSize() ); |
| long nLeft = rUnion.Left() - pCell->Frm().Left(); |
| nLeft = nLeft * aNew.GetWidth() / |
| pCell->Frm().Width(); |
| long nRight = pCell->Frm().Right() - rUnion.Right(); |
| nRight = nRight * aNew.GetWidth() / |
| pCell->Frm().Width(); |
| nWidth = aNew.GetWidth() - nLeft - nRight; |
| |
| aNew.SetWidth( nLeft ); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| |
| { |
| const SfxPoolItem* pItem; |
| if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet() |
| .GetItemState( RES_BOX, sal_False, &pItem )) |
| { |
| SvxBoxItem aBox( *(SvxBoxItem*)pItem ); |
| aBox.SetLine( 0, BOX_LINE_RIGHT ); |
| pBox->GetFrmFmt()->SetFmtAttr( aBox ); |
| } |
| } |
| |
| pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; |
| aNew.SetWidth( nWidth ); |
| pBox->ClaimFrmFmt(); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| |
| if( pUndo ) |
| pUndo->AddNewBox( pBox->GetSttIdx() ); |
| |
| // diese Box ist selektiert |
| pLastBox = pBox; |
| rBoxes.Insert( pBox ); |
| aPosArr.Insert( |
| _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), |
| pBox, bVert ) ); |
| |
| pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ]; |
| aNew.SetWidth( nRight ); |
| pBox->ClaimFrmFmt(); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| |
| if( pUndo ) |
| pUndo->AddNewBox( pBox->GetSttIdx() ); |
| } |
| // oder reicht die rechte Kante der Box in den |
| // selektierten Bereich? |
| else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() && |
| ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() && |
| ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() ) |
| { |
| // dann muss eine neue Box einfuegt und die |
| // Breiten angepasst werden |
| sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). |
| C40_GETPOS( SwTableBox, pBox )+1; |
| lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 ); |
| |
| SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() ); |
| long nLeft = rUnion.Left() - pCell->Frm().Left(), |
| nRight = pCell->Frm().Right() - rUnion.Left(); |
| |
| nLeft = nLeft * aNew.GetWidth() / |
| pCell->Frm().Width(); |
| nRight = nRight * aNew.GetWidth() / |
| pCell->Frm().Width(); |
| |
| aNew.SetWidth( nLeft ); |
| pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); |
| |
| // diese Box ist selektiert |
| pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; |
| aNew.SetWidth( nRight ); |
| pBox->ClaimFrmFmt(); |
| pBox->GetFrmFmt()->SetFmtAttr( aNew ); |
| |
| pLastBox = pBox; |
| rBoxes.Insert( pBox ); |
| aPosArr.Insert( _CmpLPt( Point( rUnion.Left(), |
| pCell->Frm().Top()), pBox, bVert )); |
| |
| if( pUndo ) |
| pUndo->AddNewBox( pBox->GetSttIdx() ); |
| } |
| } |
| if ( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| // --> FME 2005-11-03 #125288# Check if table cell is not empty |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| } |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| } |
| |
| // keine SSelection / keine gefundenen Boxen |
| if( 1 >= rBoxes.Count() ) |
| return; |
| |
| // dann suche mal alle Boxen, die nebeneinander liegen, und verbinde |
| // deren Inhalte mit Blanks. Alle untereinander liegende werden als |
| // Absaetze zusammengefasst |
| |
| // 1. Loesung: gehe ueber das Array und |
| // alle auf der gleichen Y-Ebene werden mit Blanks getrennt |
| // alle anderen werden als Absaetze getrennt. |
| sal_Bool bCalcWidth = sal_True; |
| const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox; |
| |
| // JP 27.03.98: Optimierung - falls die Boxen einer Line leer sind, |
| // dann werden jetzt dafuer keine Blanks und |
| // kein Umbruch mehr eingefuegt. |
| //Block damit SwPaM, SwPosition vom Stack geloescht werden |
| { |
| SwPaM aPam( pDoc->GetNodes() ); |
| |
| #if defined( DEL_ONLY_EMPTY_LINES ) |
| nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); |
| sal_Bool bEmptyLine = sal_True; |
| sal_uInt16 n, nSttPos = 0; |
| |
| for( n = 0; n < aPosArr.Count(); ++n ) |
| { |
| const _CmpLPt& rPt = aPosArr[ n ]; |
| if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? |
| { |
| if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam )) |
| bEmptyLine = sal_False; |
| if( bCalcWidth ) |
| nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); |
| } |
| else |
| { |
| if( bCalcWidth && n ) |
| bCalcWidth = sal_False; // eine Zeile fertig |
| |
| if( bEmptyLine && nSttPos < n ) |
| { |
| // dann ist die gesamte Line leer und braucht |
| // nicht mit Blanks aufgefuellt und als Absatz |
| // eingefuegt werden. |
| if( pUndo ) |
| for( sal_uInt16 i = nSttPos; i < n; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| |
| aPosArr.Remove( nSttPos, n - nSttPos ); |
| n = nSttPos; |
| } |
| else |
| nSttPos = n; |
| |
| bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam ); |
| } |
| } |
| if( bEmptyLine && nSttPos < n ) |
| { |
| if( pUndo ) |
| for( sal_uInt16 i = nSttPos; i < n; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| aPosArr.Remove( nSttPos, n - nSttPos ); |
| } |
| #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END ) |
| |
| nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); |
| sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0; |
| |
| for( n = 0; n < aPosArr.Count(); ++n ) |
| { |
| const _CmpLPt& rPt = aPosArr[ n ]; |
| if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? |
| { |
| sal_Bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam ); |
| if( bEmptyBox ) |
| { |
| if( nSEndPos == n ) // der Anfang ist leer |
| nESttPos = ++nSEndPos; |
| } |
| else // das Ende kann leer sein |
| nESttPos = n+1; |
| |
| if( bCalcWidth ) |
| nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); |
| } |
| else |
| { |
| if( bCalcWidth && n ) |
| bCalcWidth = sal_False; // eine Zeile fertig |
| |
| // zuerst die vom Anfang |
| if( nSttPos < nSEndPos ) |
| { |
| // dann ist der vorder Teil der Line leer und braucht |
| // nicht mit Blanks aufgefuellt werden. |
| if( pUndo ) |
| for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| |
| sal_uInt16 nCnt = nSEndPos - nSttPos; |
| aPosArr.Remove( nSttPos, nCnt ); |
| nESttPos -= nCnt; |
| n -= nCnt; |
| } |
| |
| if( nESttPos < n ) |
| { |
| // dann ist der vorder Teil der Line leer und braucht |
| // nicht mit Blanks aufgefuellt werden. |
| if( pUndo ) |
| for( sal_uInt16 i = nESttPos; i < n; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| |
| sal_uInt16 nCnt = n - nESttPos; |
| aPosArr.Remove( nESttPos, nCnt ); |
| n -= nCnt; |
| } |
| |
| nSttPos = nSEndPos = nESttPos = n; |
| if( IsEmptyBox( *aPosArr[n].pSelBox, aPam )) |
| ++nSEndPos; |
| else |
| ++nESttPos; |
| } |
| } |
| |
| // zuerst die vom Anfang |
| if( nSttPos < nSEndPos ) |
| { |
| // dann ist der vorder Teil der Line leer und braucht |
| // nicht mit Blanks aufgefuellt werden. |
| if( pUndo ) |
| for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| |
| sal_uInt16 nCnt = nSEndPos - nSttPos; |
| aPosArr.Remove( nSttPos, nCnt ); |
| nESttPos -= nCnt; |
| n -= nCnt; |
| } |
| if( nESttPos < n ) |
| { |
| // dann ist der vorder Teil der Line leer und braucht |
| // nicht mit Blanks aufgefuellt werden. |
| if( pUndo ) |
| for( sal_uInt16 i = nESttPos; i < n; ++i ) |
| pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); |
| |
| sal_uInt16 nCnt = n - nESttPos; |
| aPosArr.Remove( nESttPos, nCnt ); |
| } |
| #else |
| // DEL_ALL_EMPTY_BOXES |
| |
| nWidth = 0; |
| long nY = aPosArr.Count() ? |
| ( bVert ? |
| aPosArr[ 0 ].X() : |
| aPosArr[ 0 ].Y() ) : |
| 0; |
| |
| for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) |
| { |
| const _CmpLPt& rPt = aPosArr[ n ]; |
| if( bCalcWidth ) |
| { |
| if( nY == ( bVert ? rPt.X() : rPt.Y() ) ) // gleiche Ebene ? |
| nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); |
| else |
| bCalcWidth = sal_False; // eine Zeile fertig |
| } |
| |
| if( IsEmptyBox( *rPt.pSelBox, aPam ) ) |
| { |
| if( pUndo ) |
| pUndo->SaveCollection( *rPt.pSelBox ); |
| |
| aPosArr.Remove( n, 1 ); |
| --n; |
| } |
| } |
| #endif |
| } |
| |
| // lege schon mal die neue Box an |
| { |
| SwTableBox* pTmpBox = rBoxes[0]; |
| SwTableLine* pInsLine = pTmpBox->GetUpper(); |
| sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox ); |
| |
| lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos ); |
| (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ]; |
| pInsLine->GetTabBoxes().Remove( nInsPos ); // wieder austragen |
| (*ppMergeBox)->SetUpper( 0 ); |
| (*ppMergeBox)->ClaimFrmFmt(); |
| |
| // setze die Umrandung: von der 1. Box die linke/obere von der |
| // letzten Box die rechte/untere Kante: |
| if( pLastBox && pFirstBox ) |
| { |
| SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() ); |
| const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox(); |
| aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); |
| aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); |
| if( aBox.GetLeft() || aBox.GetTop() || |
| aBox.GetRight() || aBox.GetBottom() ) |
| (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox ); |
| } |
| } |
| |
| //Block damit SwPaM, SwPosition vom Stack geloescht werden |
| if( aPosArr.Count() ) |
| { |
| SwTxtNode* pTxtNd = 0; |
| SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() ); |
| SwNodeIndex& rInsPosNd = aInsPos.nNode; |
| |
| SwPaM aPam( aInsPos ); |
| |
| for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) |
| { |
| const _CmpLPt& rPt = aPosArr[ n ]; |
| aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()-> |
| EndOfSectionNode(), -1 ); |
| SwCntntNode* pCNd = aPam.GetCntntNode(); |
| sal_uInt16 nL = pCNd ? pCNd->Len() : 0; |
| aPam.GetPoint()->nContent.Assign( pCNd, nL ); |
| |
| SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 ); |
| // ein Node muss in der Box erhalten bleiben (sonst wird beim |
| // Move die gesamte Section geloescht) |
| bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo()); |
| if( pUndo ) |
| { |
| pDoc->GetIDocumentUndoRedo().DoUndo(false); |
| } |
| pDoc->AppendTxtNode( *aPam.GetPoint() ); |
| if( pUndo ) |
| { |
| pDoc->GetIDocumentUndoRedo().DoUndo(bUndo); |
| } |
| SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode ); |
| rInsPosNd++; |
| if( pUndo ) |
| pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd ); |
| else |
| { |
| pDoc->MoveNodeRange( aRg, rInsPosNd, |
| IDocumentContentOperations::DOC_MOVEDEFAULT ); |
| } |
| // wo steht jetzt aInsPos ?? |
| |
| if( bCalcWidth ) |
| bCalcWidth = sal_False; // eine Zeile fertig |
| |
| // den initialen TextNode ueberspringen |
| rInsPosNd.Assign( pDoc->GetNodes(), |
| rInsPosNd.GetNode().EndOfSectionIndex() - 2 ); |
| pTxtNd = rInsPosNd.GetNode().GetTxtNode(); |
| if( pTxtNd ) |
| aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() ); |
| } |
| |
| // in der MergeBox sollte jetzt der gesamte Text stehen |
| // loesche jetzt noch den initialen TextNode |
| ASSERT( (*ppMergeBox)->GetSttIdx()+2 < |
| (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(), |
| "leere Box" ); |
| SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 ); |
| pDoc->GetNodes().Delete( aIdx, 1 ); |
| } |
| |
| // setze die Breite der Box |
| (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); |
| if( pUndo ) |
| pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() ); |
| } |
| |
| |
| static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ); |
| |
| static sal_Bool lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara ) |
| { |
| ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara ); |
| return *(sal_Bool*)pPara; |
| } |
| |
| static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ) |
| { |
| if( !rpFndBox->GetBox()->GetSttNd() ) |
| { |
| if( rpFndBox->GetLines().Count() != |
| rpFndBox->GetBox()->GetTabLines().Count() ) |
| *((sal_Bool*)pPara) = sal_False; |
| else |
| ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara ); |
| } |
| // Box geschuetzt ?? |
| else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() ) |
| *((sal_Bool*)pPara) = sal_False; |
| return *(sal_Bool*)pPara; |
| } |
| |
| |
| sal_uInt16 CheckMergeSel( const SwPaM& rPam ) |
| { |
| SwSelBoxes aBoxes; |
| //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht |
| // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, |
| // das die 1. Headline mit drin ist. |
| Point aPt; |
| const SwCntntNode* pCntNd = rPam.GetCntntNode(); |
| const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aPt )->GetUpper(); |
| pCntNd = rPam.GetCntntNode(sal_False); |
| const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aPt )->GetUpper(); |
| GetTblSel( pStart, pEnd, aBoxes, 0 ); |
| return CheckMergeSel( aBoxes ); |
| } |
| |
| sal_uInt16 CheckMergeSel( const SwSelBoxes& rBoxes ) |
| { |
| sal_uInt16 eRet = TBLMERGE_NOSELECTION; |
| if( rBoxes.Count() ) |
| { |
| eRet = TBLMERGE_OK; |
| |
| _FndBox aFndBox( 0, 0 ); |
| _FndPara aPara( rBoxes, &aFndBox ); |
| const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode(); |
| ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach( |
| &_FndLineCopyCol, &aPara ); |
| if( aFndBox.GetLines().Count() ) |
| { |
| sal_Bool bMergeSelOk = sal_True; |
| _FndBox* pFndBox = &aFndBox; |
| _FndLine* pFndLine = 0; |
| while( pFndBox && 1 == pFndBox->GetLines().Count() ) |
| { |
| pFndLine = pFndBox->GetLines()[0]; |
| if( 1 == pFndLine->GetBoxes().Count() ) |
| pFndBox = pFndLine->GetBoxes()[0]; |
| else |
| pFndBox = 0; |
| } |
| if( pFndBox ) |
| pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk ); |
| else if( pFndLine ) |
| pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk ); |
| if( !bMergeSelOk ) |
| eRet = TBLMERGE_TOOCOMPLEX; |
| } |
| else |
| eRet = TBLMERGE_NOSELECTION; |
| } |
| return eRet; |
| } |
| |
| //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die |
| //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen. |
| SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* ); |
| |
| SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish, |
| const long nAct ) |
| { |
| const SwLayoutFrm *pTmp = pCell; |
| if ( !nWish ) |
| nWish = 1; |
| |
| const sal_Bool bRTL = pCell->IsRightToLeft(); |
| SwTwips nRet = bRTL ? |
| nAct - pCell->Frm().Width() : |
| 0; |
| |
| while ( pTmp ) |
| { |
| while ( pTmp->GetPrev() ) |
| { |
| pTmp = (SwLayoutFrm*)pTmp->GetPrev(); |
| long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth(); |
| nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish; |
| } |
| pTmp = pTmp->GetUpper()->GetUpper(); |
| if ( pTmp && !pTmp->IsCellFrm() ) |
| pTmp = 0; |
| } |
| return nRet; |
| } |
| |
| void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart, |
| const SwLayoutFrm *&rpEnd, |
| const int bChkProtected ) |
| { |
| //Start an den Anfang seiner Zeile setzen. |
| //End an das Ende seiner Zeile setzen. |
| rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower(); |
| while ( rpEnd->GetNext() ) |
| rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); |
| |
| SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 ); |
| const SwLayoutFrm *pTmp; |
| for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType(); |
| pTmp = pTmp->GetUpper() ) |
| { |
| void* p = (void*)pTmp; |
| aSttArr.Insert( p, 0 ); |
| } |
| for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType(); |
| pTmp = pTmp->GetUpper() ) |
| { |
| void* p = (void*)pTmp; |
| aEndArr.Insert( p, 0 ); |
| } |
| |
| for( sal_uInt16 n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n ) |
| if( aSttArr[ n ] != aEndArr[ n ] ) |
| { |
| // first unequal line or box - all odds are |
| if( n & 1 ) // 1, 3, 5, ... are boxes |
| { |
| rpStart = (SwLayoutFrm*)aSttArr[ n ]; |
| rpEnd = (SwLayoutFrm*)aEndArr[ n ]; |
| } |
| else // 0, 2, 4, ... are lines |
| { |
| // check if start & end line are the first & last Line of the |
| // box. If not return these cells. |
| // Else the hole line with all Boxes has to be deleted. |
| rpStart = (SwLayoutFrm*)aSttArr[ n+1 ]; |
| rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ]; |
| if( n ) |
| { |
| const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ]; |
| const SwTableLines& rLns = pCellFrm-> |
| GetTabBox()->GetTabLines(); |
| if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() && |
| rLns[ rLns.Count() - 1 ] == |
| ((SwRowFrm*)aEndArr[ n ])->GetTabLine() ) |
| { |
| rpStart = rpEnd = pCellFrm; |
| while ( rpStart->GetPrev() ) |
| rpStart = (SwLayoutFrm*)rpStart->GetPrev(); |
| while ( rpEnd->GetNext() ) |
| rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); |
| } |
| } |
| } |
| break; |
| } |
| |
| if( !bChkProtected ) // geschuetzte Zellen beachten ? |
| return; |
| |
| |
| //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. |
| while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) |
| rpStart = (SwLayoutFrm*)rpStart->GetNext(); |
| while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) |
| rpEnd = (SwLayoutFrm*)rpEnd->GetPrev(); |
| } |
| |
| |
| void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart, |
| const SwLayoutFrm *&rpEnd, |
| const int bChkProtected ) |
| { |
| //Start und End senkrecht bis an den Rand der Tabelle denken; es muss |
| //die Gesamttabelle betrachtet werden, also inklusive Masters und |
| //Follows. |
| //Fuer den Start brauchen wir den Mutter-TabellenFrm. |
| if( !rpStart ) |
| return; |
| const SwTabFrm *pOrg = rpStart->FindTabFrm(); |
| const SwTabFrm *pTab = pOrg; |
| |
| SWRECTFN( pTab ) |
| |
| sal_Bool bRTL = pTab->IsRightToLeft(); |
| const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth(); |
| const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1; |
| |
| while ( pTab->IsFollow() ) |
| { |
| const SwFrm *pTmp = pTab->FindPrev(); |
| ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." ); |
| pTab = (const SwTabFrm*)pTmp; |
| } |
| |
| SwTwips nSX = 0; |
| SwTwips nSX2 = 0; |
| |
| if ( pTab->GetTable()->IsNewModel() ) |
| { |
| nSX = (rpStart->Frm().*fnRect->fnGetLeft )(); |
| nSX2 = (rpStart->Frm().*fnRect->fnGetRight)(); |
| } |
| else |
| { |
| const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); |
| nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); |
| nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish); |
| } |
| |
| const SwLayoutFrm *pTmp = pTab->FirstCell(); |
| |
| while ( pTmp && |
| (!pTmp->IsCellFrm() || |
| ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX && |
| (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) || |
| ( bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX && |
| (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) ) ) |
| pTmp = pTmp->GetNextLayoutLeaf(); |
| |
| if ( pTmp ) |
| rpStart = pTmp; |
| |
| pTab = pOrg; |
| |
| const SwTabFrm* pLastValidTab = pTab; |
| while ( pTab->GetFollow() ) |
| { |
| // |
| // Check if pTab->GetFollow() is a valid follow table: |
| // Only follow tables with at least on non-FollowFlowLine |
| // should be considered. |
| // |
| if ( pTab->HasFollowFlowLine() ) |
| { |
| pTab = pTab->GetFollow(); |
| const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow(); |
| if ( pTmpRow && pTmpRow->GetNext() ) |
| pLastValidTab = pTab; |
| } |
| else |
| pLastValidTab = pTab = pTab->GetFollow(); |
| } |
| pTab = pLastValidTab; |
| |
| SwTwips nEX = 0; |
| |
| if ( pTab->GetTable()->IsNewModel() ) |
| { |
| nEX = (rpEnd->Frm().*fnRect->fnGetLeft )(); |
| } |
| else |
| { |
| const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); |
| nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); |
| } |
| |
| const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt(); |
| rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0; |
| // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower, |
| // we would crash here. |
| if ( !pLastCntnt ) return; |
| // <-- |
| |
| while( !rpEnd->IsCellFrm() ) |
| rpEnd = rpEnd->GetUpper(); |
| |
| while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) || |
| ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) ) |
| { |
| const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf(); |
| if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) ) |
| break; |
| rpEnd = pTmpLeaf; |
| } |
| |
| if( !bChkProtected ) // geschuetzte Zellen beachten ? |
| return; |
| |
| //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. |
| //Also muss ggf. nocheinmal rueckwaerts gesucht werden. |
| while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) |
| { |
| const SwLayoutFrm *pTmpLeaf = rpStart; |
| pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); |
| while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr. |
| pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); |
| while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX && |
| (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 ) |
| pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); |
| const SwTabFrm *pTmpTab = rpStart->FindTabFrm(); |
| if ( !pTmpTab->IsAnLower( pTmpLeaf ) ) |
| { |
| pTmpTab = pTmpTab->GetFollow(); |
| rpStart = pTmpTab->FirstCell(); |
| while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX && |
| (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 ) |
| rpStart = rpStart->GetNextLayoutLeaf(); |
| } |
| else |
| rpStart = pTmpLeaf; |
| } |
| while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) |
| { |
| const SwLayoutFrm *pTmpLeaf = rpEnd; |
| pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); |
| while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr. |
| pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); |
| while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX ) |
| pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); |
| const SwTabFrm *pTmpTab = rpEnd->FindTabFrm(); |
| if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) ) |
| { |
| pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev(); |
| ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master."); |
| rpEnd = pTmpTab->FindLastCntnt()->GetUpper(); |
| while( !rpEnd->IsCellFrm() ) |
| rpEnd = rpEnd->GetUpper(); |
| while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) |
| rpEnd = rpEnd->GetPrevLayoutLeaf(); |
| } |
| else |
| rpEnd = pTmpLeaf; |
| } |
| } |
| |
| |
| void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart, |
| const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType ) |
| { |
| while ( pStart && !pStart->IsCellFrm() ) |
| pStart = pStart->GetUpper(); |
| while ( pEnd && !pEnd->IsCellFrm() ) |
| pEnd = pEnd->GetUpper(); |
| |
| // #112697# Robust: |
| if ( !pStart || !pEnd ) |
| { |
| ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" ) |
| return; |
| } |
| |
| const SwTabFrm *pTable = pStart->FindTabFrm(); |
| const SwTabFrm *pEndTable = pEnd->FindTabFrm(); |
| if( !pTable || !pEndTable ) |
| return; |
| sal_Bool bExchange = sal_False; |
| |
| if ( pTable != pEndTable ) |
| { |
| if ( !pTable->IsAnFollow( pEndTable ) ) |
| { |
| ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." ); |
| bExchange = sal_True; |
| } |
| } |
| else |
| { |
| SWRECTFN( pTable ) |
| long nSttTop = (pStart->Frm().*fnRect->fnGetTop)(); |
| long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)(); |
| if( nSttTop == nEndTop ) |
| { |
| if( (pStart->Frm().*fnRect->fnGetLeft)() > |
| (pEnd->Frm().*fnRect->fnGetLeft)() ) |
| bExchange = sal_True; |
| } |
| else if( bVert == ( nSttTop < nEndTop ) ) |
| bExchange = sal_True; |
| } |
| if ( bExchange ) |
| { |
| const SwLayoutFrm *pTmp = pStart; |
| pStart = pEnd; |
| pEnd = pTmp; |
| //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt. |
| //MA: 28. Dec. 93 Bug: 5190 |
| } |
| |
| //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls |
| //erwuenscht noch versetzt werden. |
| if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) |
| ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); |
| else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) |
| ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); |
| |
| // --> FME 2006-07-17 #134385# Made code robust. |
| if ( !pEnd ) return; |
| // <-- |
| |
| //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190 |
| pTable = pStart->FindTabFrm(); |
| pEndTable = pEnd->FindTabFrm(); |
| |
| const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth(); |
| const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth(); |
| const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() ); |
| while ( pTable ) |
| { |
| SWRECTFN( pTable ) |
| const long nOfst = (pTable->*fnRect->fnGetPrtLeft)(); |
| const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)(); |
| long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst; |
| long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst; |
| |
| if ( nSt1 <= nEd1 ) |
| nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1; |
| else |
| nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1; |
| |
| long nSt2; |
| long nEd2; |
| if( pTable->IsAnLower( pStart ) ) |
| nSt2 = (pStart->Frm().*fnRect->fnGetTop)(); |
| else |
| nSt2 = (pTable->Frm().*fnRect->fnGetTop)(); |
| if( pTable->IsAnLower( pEnd ) ) |
| nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)(); |
| else |
| nEd2 = (pTable->Frm().*fnRect->fnGetBottom)(); |
| Point aSt, aEd; |
| if( nSt1 > nEd1 ) |
| { |
| long nTmp = nSt1; |
| nSt1 = nEd1; |
| nEd1 = nTmp; |
| } |
| if( nSt2 > nEd2 ) |
| { |
| long nTmp = nSt2; |
| nSt2 = nEd2; |
| nEd2 = nTmp; |
| } |
| if( bVert ) |
| { |
| aSt = Point( nSt2, nSt1 ); |
| aEd = Point( nEd2, nEd1 ); |
| } |
| else |
| { |
| aSt = Point( nSt1, nSt2 ); |
| aEd = Point( nEd1, nEd2 ); |
| } |
| |
| const Point aDiff( aEd - aSt ); |
| SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) ); |
| aUnion.Justify(); |
| |
| // fuers |
| if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType )) |
| { |
| //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch |
| //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen. |
| //Um dies zu vermeiden werden jetzt fuer die Table die erste und |
| //letzte Zelle innerhalb der Union ermittelt und aus genau deren |
| //Werten wird die Union neu gebildet. |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while ( pRow && !pRow->Frm().IsOver( aUnion ) ) |
| pRow = (SwLayoutFrm*)pRow->GetNext(); |
| |
| // --> FME 2004-07-26 #i31976# |
| // A follow flow row may contain emtpy cells. These are not |
| // considered by FirstCell(). Therefore we have to find |
| // the first cell manually: |
| const SwFrm* pTmpCell = 0; |
| if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() ) |
| { |
| const SwFrm* pTmpRow = pRow; |
| while ( pTmpRow && pTmpRow->IsRowFrm() ) |
| { |
| pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower(); |
| pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower(); |
| } |
| ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" ) |
| } |
| // <-- |
| |
| const SwLayoutFrm* pFirst = pTmpCell ? |
| static_cast<const SwLayoutFrm*>(pTmpCell) : |
| pRow ? |
| pRow->FirstCell() : |
| 0; |
| |
| while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) ) |
| { |
| if ( pFirst->GetNext() ) |
| { |
| pFirst = (const SwLayoutFrm*)pFirst->GetNext(); |
| if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() ) |
| pFirst = pFirst->FirstCell(); |
| } |
| else |
| pFirst = ::lcl_FindNextCellFrm( pFirst ); |
| } |
| const SwLayoutFrm* pLast = 0; |
| const SwFrm* pLastCntnt = pTable->FindLastCntnt(); |
| if ( pLastCntnt ) |
| pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() ); |
| |
| while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) ) |
| pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() ); |
| |
| if ( pFirst && pLast ) //Robust |
| { |
| aUnion = pFirst->Frm(); |
| aUnion.Union( pLast->Frm() ); |
| } |
| else |
| aUnion.Width( 0 ); |
| } |
| |
| if( (aUnion.*fnRect->fnGetWidth)() ) |
| { |
| SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable ); |
| rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() ); |
| } |
| |
| pTable = pTable->GetFollow(); |
| if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) ) |
| pTable = 0; |
| } |
| } |
| |
| sal_Bool CheckSplitCells( const SwCrsrShell& rShell, sal_uInt16 nDiv, |
| const SwTblSearchType eSearchType ) |
| { |
| if( !rShell.IsTableMode() ) |
| rShell.GetCrsr(); |
| |
| return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType ); |
| } |
| |
| sal_Bool CheckSplitCells( const SwCursor& rCrsr, sal_uInt16 nDiv, |
| const SwTblSearchType eSearchType ) |
| { |
| if( 1 >= nDiv ) |
| return sal_False; |
| |
| sal_uInt16 nMinValue = nDiv * MINLAY; |
| |
| //Start- und Endzelle besorgen und den naechsten fragen. |
| Point aPtPos, aMkPos; |
| const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); |
| if( pShCrsr ) |
| { |
| aPtPos = pShCrsr->GetPtPos(); |
| aMkPos = pShCrsr->GetMkPos(); |
| } |
| |
| const SwCntntNode* pCntNd = rCrsr.GetCntntNode(); |
| const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aPtPos )->GetUpper(); |
| pCntNd = rCrsr.GetCntntNode(sal_False); |
| const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), |
| &aMkPos )->GetUpper(); |
| |
| SWRECTFN( pStart->GetUpper() ) |
| |
| //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. |
| SwSelUnions aUnions; |
| |
| ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType ); |
| |
| //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. |
| for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) |
| { |
| SwSelUnion *pUnion = aUnions[i]; |
| const SwTabFrm *pTable = pUnion->GetTable(); |
| |
| // Skip any repeated headlines in the follow: |
| const SwLayoutFrm* pRow = pTable->IsFollow() ? |
| pTable->GetFirstNonHeadlineRow() : |
| (const SwLayoutFrm*)pTable->Lower(); |
| |
| while ( pRow ) |
| { |
| if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) |
| { |
| const SwLayoutFrm *pCell = pRow->FirstCell(); |
| |
| while ( pCell && pRow->IsAnLower( pCell ) ) |
| { |
| ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); |
| if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) |
| { |
| if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue ) |
| return sal_False; |
| } |
| |
| if ( pCell->GetNext() ) |
| { |
| pCell = (const SwLayoutFrm*)pCell->GetNext(); |
| if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) |
| pCell = pCell->FirstCell(); |
| } |
| else |
| pCell = ::lcl_FindNextCellFrm( pCell ); |
| } |
| } |
| pRow = (const SwLayoutFrm*)pRow->GetNext(); |
| } |
| } |
| return sal_True; |
| } |
| |
| // ------------------------------------------------------------------- |
| // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes) |
| // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur |
| // neu: SS zum gezielten Loeschen/Retaurieren des Layouts. |
| |
| void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling ) |
| { |
| SwRowFrm *pRow = new SwRowFrm( rLine, pUpper ); |
| if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() ) |
| { |
| SwTabFrm* pTabFrm = (SwTabFrm*)pUpper; |
| pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen |
| |
| if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) ) |
| { |
| // Skip any repeated headlines in the follow: |
| pSibling = pTabFrm->GetFirstNonHeadlineRow(); |
| } |
| } |
| pRow->Paste( pUpper, pSibling ); |
| pRow->RegistFlys(); |
| } |
| |
| |
| sal_Bool _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara ) |
| { |
| _FndPara* pFndPara = (_FndPara*)pPara; |
| _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine ); |
| if( rpBox->GetTabLines().Count() ) |
| { |
| _FndPara aPara( *pFndPara, pFndBox ); |
| pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); |
| if( !pFndBox->GetLines().Count() ) |
| { |
| delete pFndBox; |
| return sal_True; |
| } |
| } |
| else |
| { |
| SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox; |
| sal_uInt16 nFndPos; |
| if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos )) |
| { |
| delete pFndBox; |
| return sal_True; |
| } |
| } |
| pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, |
| pFndPara->pFndLine->GetBoxes().Count() ); |
| return sal_True; |
| } |
| |
| sal_Bool _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara ) |
| { |
| _FndPara* pFndPara = (_FndPara*)pPara; |
| _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox ); |
| _FndPara aPara( *pFndPara, pFndLine ); |
| pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara ); |
| if( pFndLine->GetBoxes().Count() ) |
| { |
| pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine, |
| pFndPara->pFndBox->GetLines().Count() ); |
| } |
| else |
| delete pFndLine; |
| return sal_True; |
| } |
| |
| void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable ) |
| { |
| //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich |
| //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen |
| //sind, so bleiben die Pointer eben einfach 0. |
| //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen |
| //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden |
| //kann werden die Positionen um 1 nach oben versetzt! |
| |
| sal_uInt16 nStPos = USHRT_MAX; |
| sal_uInt16 nEndPos= 0; |
| |
| for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) |
| { |
| SwTableLine *pLine = rBoxes[i]->GetUpper(); |
| while ( pLine->GetUpper() ) |
| pLine = pLine->GetUpper()->GetUpper(); |
| const sal_uInt16 nPos = rTable.GetTabLines().GetPos( |
| (const SwTableLine*&)pLine ) + 1; |
| |
| ASSERT( nPos != USHRT_MAX, "TableLine not found." ); |
| |
| if( nStPos > nPos ) |
| nStPos = nPos; |
| |
| if( nEndPos < nPos ) |
| nEndPos = nPos; |
| } |
| if ( nStPos > 1 ) |
| pLineBefore = rTable.GetTabLines()[nStPos - 2]; |
| if ( nEndPos < rTable.GetTabLines().Count() ) |
| pLineBehind = rTable.GetTabLines()[nEndPos]; |
| } |
| |
| void _FndBox::SetTableLines( const SwTable &rTable ) |
| { |
| // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich |
| // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen |
| // sind, so bleiben die Pointer eben einfach 0. |
| // Die Positionen der ersten/letzten betroffenen Line im Array der |
| // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand |
| // werdenkann werden die Positionen um 1 nach oben versetzt! |
| |
| if( !GetLines().Count() ) |
| return; |
| |
| SwTableLine* pTmpLine = GetLines()[0]->GetLine(); |
| sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); |
| ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); |
| if( nPos ) |
| pLineBefore = rTable.GetTabLines()[ nPos - 1 ]; |
| |
| pTmpLine = GetLines()[GetLines().Count()-1]->GetLine(); |
| nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); |
| ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); |
| if( ++nPos < rTable.GetTabLines().Count() ) |
| pLineBehind = rTable.GetTabLines()[nPos]; |
| } |
| |
| inline void UnsetFollow( SwFlowFrm *pTab ) |
| { |
| pTab->bIsFollow = sal_False; |
| } |
| |
| //Solution:When bAccTableDispose is FALSE,the acc table should not be disposed. |
| //void _FndBox::DelFrms( SwTable &rTable ) |
| void _FndBox::DelFrms( SwTable &rTable,sal_Bool bAccTableDispose ) |
| { |
| //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem |
| //Layout ausgeschnitten und geloescht werden. |
| //Entstehen dabei leere Follows so muessen diese vernichtet werden. |
| //Wird ein Master vernichtet, so muss der Follow Master werden. |
| //Ein TabFrm muss immer uebrigbleiben. |
| |
| sal_uInt16 nStPos = 0; |
| sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; |
| if( rTable.IsNewModel() && pLineBefore ) |
| rTable.CheckRowSpan( pLineBefore, true ); |
| if ( pLineBefore ) |
| { |
| nStPos = rTable.GetTabLines().GetPos( |
| (const SwTableLine*&)pLineBefore ); |
| ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); |
| ++nStPos; |
| } |
| if( rTable.IsNewModel() && pLineBehind ) |
| rTable.CheckRowSpan( pLineBehind, false ); |
| if ( pLineBehind ) |
| { |
| nEndPos = rTable.GetTabLines().GetPos( |
| (const SwTableLine*&)pLineBehind ); |
| ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); |
| --nEndPos; |
| } |
| |
| for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i) |
| { |
| SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt(); |
| SwIterator<SwRowFrm,SwFmt> aIter( *pFmt ); |
| for ( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) |
| { |
| if ( pFrm->GetTabLine() == rTable.GetTabLines()[i] ) |
| { |
| sal_Bool bDel = sal_True; |
| SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ? |
| (SwTabFrm*)pFrm->GetUpper() : 0; |
| if ( !pUp ) |
| { |
| const sal_uInt16 nRepeat = |
| ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat(); |
| if ( nRepeat > 0 && |
| ((SwTabFrm*)pFrm->GetUpper())->IsFollow() ) |
| { |
| if ( !pFrm->GetNext() ) |
| { |
| SwRowFrm* pFirstNonHeadline = |
| ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow(); |
| if ( pFirstNonHeadline == pFrm ) |
| { |
| pUp = (SwTabFrm*)pFrm->GetUpper(); |
| } |
| } |
| } |
| } |
| if ( pUp ) |
| { |
| SwTabFrm *pFollow = pUp->GetFollow(); |
| SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0; |
| if ( pPrev ) |
| { |
| SwFrm *pTmp = pPrev->FindPrev(); |
| ASSERT( pTmp->IsTabFrm(), |
| "Vorgaenger vom Follow kein Master."); |
| pPrev = (SwTabFrm*)pTmp; |
| } |
| if ( pPrev ) |
| { |
| pPrev->SetFollow( pFollow ); |
| // --> FME 2006-01-31 #i60340# Do not transfer the |
| // flag from pUp to pPrev. pUp may still have the |
| // flag set although there is not more follow flow |
| // line associated with pUp. |
| pPrev->SetFollowFlowLine( sal_False ); |
| // <-- |
| } |
| else if ( pFollow ) |
| ::UnsetFollow( pFollow ); |
| |
| //Ein TabellenFrm muss immer stehenbleiben! |
| if ( pPrev || pFollow ) |
| { |
| // OD 26.08.2003 #i18103# - if table is in a section, |
| // lock the section, to avoid its delete. |
| { |
| SwSectionFrm* pSctFrm = pUp->FindSctFrm(); |
| bool bOldSectLock = false; |
| if ( pSctFrm ) |
| { |
| bOldSectLock = pSctFrm->IsColLocked(); |
| pSctFrm->ColLock(); |
| } |
| pUp->Cut(); |
| if ( pSctFrm && !bOldSectLock ) |
| { |
| pSctFrm->ColUnlock(); |
| } |
| } |
| delete pUp; |
| bDel = sal_False;//Die Row wird mit in den Abgrund |
| //gerissen. |
| } |
| } |
| if ( bDel ) |
| { |
| SwFrm* pTabFrm = pFrm->GetUpper(); |
| if ( pTabFrm->IsTabFrm() && |
| !pFrm->GetNext() && |
| ((SwTabFrm*)pTabFrm)->GetFollow() ) |
| { |
| // We do not delete the follow flow line, |
| // this will be done automatically in the |
| // next turn. |
| ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( sal_False ); |
| } |
| //Solution:Set acc table dispose state |
| pFrm->SetAccTableDispose( bAccTableDispose ); |
| pFrm->Cut(); |
| //Solution:Set acc table dispose state to default value. |
| pFrm->SetAccTableDispose( sal_True ); |
| delete pFrm; |
| } |
| } |
| } |
| } |
| } |
| |
| sal_Bool lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk ) |
| { |
| const SwTabFrm* pTblFrm = rChk.FindTabFrm(); |
| if( pTblFrm->IsFollow() ) |
| pTblFrm = pTblFrm->FindMaster( true ); |
| return &rTable == pTblFrm; |
| } |
| |
| /* |
| * lcl_UpdateRepeatedHeadlines |
| */ |
| void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers ) |
| { |
| ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" ) |
| |
| // Delete remaining headlines: |
| SwRowFrm* pLower = 0; |
| while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() ) |
| { |
| pLower->Cut(); |
| delete pLower; |
| } |
| |
| // Insert fresh set of headlines: |
| pLower = (SwRowFrm*)rTabFrm.Lower(); |
| SwTable& rTable = *rTabFrm.GetTable(); |
| const sal_uInt16 nRepeat = rTable.GetRowsToRepeat(); |
| for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx ) |
| { |
| SwRowFrm* pHeadline = new SwRowFrm( *rTable.GetTabLines()[ nIdx ], &rTabFrm ); |
| pHeadline->SetRepeatedHeadline( true ); |
| pHeadline->Paste( &rTabFrm, pLower ); |
| pHeadline->RegistFlys(); |
| } |
| |
| if ( bCalcLowers ) |
| rTabFrm.SetCalcLowers(); |
| } |
| |
| void _FndBox::MakeFrms( SwTable &rTable ) |
| { |
| //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout |
| //wieder neu erzeugt werden. |
| //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss). |
| |
| sal_uInt16 nStPos = 0; |
| sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; |
| if ( pLineBefore ) |
| { |
| nStPos = rTable.GetTabLines().GetPos( |
| (const SwTableLine*&)pLineBefore ); |
| ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); |
| ++nStPos; |
| |
| } |
| if ( pLineBehind ) |
| { |
| nEndPos = rTable.GetTabLines().GetPos( |
| (const SwTableLine*&)pLineBehind ); |
| ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); |
| --nEndPos; |
| } |
| //Jetzt die grosse Einfuegeoperation fuer alle Tabllen. |
| SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); |
| for ( SwTabFrm *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) |
| { |
| if ( !pTable->IsFollow() ) |
| { |
| SwRowFrm *pSibling = 0; |
| SwFrm *pUpperFrm = 0; |
| int i; |
| for ( i = rTable.GetTabLines().Count()-1; |
| i >= 0 && !pSibling; --i ) |
| { |
| SwTableLine *pLine = pLineBehind ? pLineBehind : |
| rTable.GetTabLines()[static_cast<sal_uInt16>(i)]; |
| SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); |
| pSibling = aIter.First(); |
| while ( pSibling && ( |
| pSibling->GetTabLine() != pLine || |
| !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || |
| pSibling->IsRepeatedHeadline() || |
| // --> FME 2005-08-24 #i53647# If !pLineBehind, |
| // IsInSplitTableRow() should be checked. |
| ( pLineBehind && pSibling->IsInFollowFlowRow() ) || |
| (!pLineBehind && pSibling->IsInSplitTableRow() ) ) ) |
| // <-- |
| { |
| pSibling = aIter.Next(); |
| } |
| } |
| if ( pSibling ) |
| { |
| pUpperFrm = pSibling->GetUpper(); |
| if ( !pLineBehind ) |
| pSibling = 0; |
| } |
| else |
| // ???? oder das der Letzte Follow der Tabelle ???? |
| pUpperFrm = pTable; |
| |
| for ( i = nStPos; (sal_uInt16)i <= nEndPos; ++i ) |
| ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<sal_uInt16>(i)], |
| (SwLayoutFrm*)pUpperFrm, pSibling ); |
| if ( pUpperFrm->IsTabFrm() ) |
| ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); |
| } |
| else if ( rTable.GetRowsToRepeat() > 0 ) |
| { |
| // Insert new headlines: |
| lcl_UpdateRepeatedHeadlines( *pTable, true ); |
| } |
| } |
| } |
| |
| void _FndBox::MakeNewFrms( SwTable &rTable, const sal_uInt16 nNumber, |
| const sal_Bool bBehind ) |
| { |
| //Frms fuer neu eingefuege Zeilen erzeugen. |
| //bBehind == sal_True: vor pLineBehind |
| // == sal_False: hinter pLineBefore |
| const sal_uInt16 nBfPos = pLineBefore ? |
| rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) : |
| USHRT_MAX; |
| const sal_uInt16 nBhPos = pLineBehind ? |
| rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) : |
| USHRT_MAX; |
| |
| //nNumber: wie oft ist eingefuegt worden. |
| //nCnt: wieviele sind nNumber mal eingefuegt worden. |
| |
| const sal_uInt16 nCnt = |
| ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) - |
| (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1); |
| |
| //Den Master-TabFrm suchen |
| SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); |
| SwTabFrm *pTable; |
| for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) |
| { |
| if( !pTable->IsFollow() ) |
| { |
| SwRowFrm* pSibling = 0; |
| SwLayoutFrm *pUpperFrm = 0; |
| if ( bBehind ) |
| { |
| if ( pLineBehind ) |
| { |
| SwIterator<SwRowFrm,SwFmt> aIter( *pLineBehind->GetFrmFmt() ); |
| pSibling = aIter.First(); |
| while ( pSibling && ( |
| // only consider row frames associated with pLineBehind: |
| pSibling->GetTabLine() != pLineBehind || |
| // only consider row frames that are in pTables Master-Follow chain: |
| !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || |
| // only consider row frames that are not repeated headlines: |
| pSibling->IsRepeatedHeadline() || |
| // only consider row frames that are not follow flow rows |
| pSibling->IsInFollowFlowRow() ) ) |
| { |
| pSibling = aIter.Next(); |
| } |
| } |
| if ( pSibling ) |
| pUpperFrm = pSibling->GetUpper(); |
| else |
| { |
| while( pTable->GetFollow() ) |
| pTable = pTable->GetFollow(); |
| pUpperFrm = pTable; |
| } |
| const sal_uInt16 nMax = nBhPos != USHRT_MAX ? |
| nBhPos : rTable.GetTabLines().Count(); |
| |
| sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt; |
| |
| for ( ; i < nMax; ++i ) |
| ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling ); |
| if ( pUpperFrm->IsTabFrm() ) |
| ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); |
| } |
| else //davor einfuegen |
| { |
| sal_uInt16 i; |
| |
| // We are looking for the frame that is behind the row frame |
| // that should be inserted. |
| for ( i = 0; !pSibling; ++i ) |
| { |
| SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i]; |
| |
| SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); |
| pSibling = aIter.First(); |
| |
| while ( pSibling && ( |
| // only consider row frames associated with pLineBefore: |
| pSibling->GetTabLine() != pLine || |
| // only consider row frames that are in pTables Master-Follow chain: |
| !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || |
| // only consider row frames that are not repeated headlines: |
| pSibling->IsRepeatedHeadline() || |
| // 1. case: pLineBefore == 0: |
| // only consider row frames that are not follow flow rows |
| // 2. case: pLineBefore != 0: |
| // only consider row frames that are not split table rows |
| // --> FME 2004-11-23 #i37476# If !pLineBefore, |
| // check IsInFollowFlowRow instead of IsInSplitTableRow. |
| ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) || |
| ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) ) |
| // <-- |
| { |
| pSibling = aIter.Next(); |
| } |
| } |
| |
| pUpperFrm = pSibling->GetUpper(); |
| if ( pLineBefore ) |
| pSibling = (SwRowFrm*) pSibling->GetNext(); |
| |
| sal_uInt16 nMax = nBhPos != USHRT_MAX ? |
| nBhPos - nCnt : |
| rTable.GetTabLines().Count() - nCnt; |
| |
| i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0; |
| for ( ; i < nMax; ++i ) |
| ::lcl_InsertRow( *rTable.GetTabLines()[i], |
| pUpperFrm, pSibling ); |
| if ( pUpperFrm->IsTabFrm() ) |
| ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); |
| } |
| } |
| } |
| |
| //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden |
| //Code nicht zu zerfasern wird hier nochmals iteriert. |
| const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat(); |
| if ( nRowsToRepeat > 0 && |
| ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) || |
| ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) ) |
| { |
| for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) |
| { |
| if ( pTable->Lower() ) |
| { |
| if ( pTable->IsFollow() ) |
| { |
| lcl_UpdateRepeatedHeadlines( *pTable, true ); |
| } |
| |
| ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() == |
| rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" ) |
| } |
| } |
| } |
| } |
| |
| sal_Bool _FndBox::AreLinesToRestore( const SwTable &rTable ) const |
| { |
| //Lohnt es sich MakeFrms zu rufen? |
| |
| if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() ) |
| return sal_True; |
| |
| sal_uInt16 nBfPos; |
| if(pLineBefore) |
| { |
| const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore; |
| nBfPos = rTable.GetTabLines().GetPos( rLBefore ); |
| } |
| else |
| nBfPos = USHRT_MAX; |
| |
| sal_uInt16 nBhPos; |
| if(pLineBehind) |
| { |
| const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind; |
| nBhPos = rTable.GetTabLines().GetPos( rLBehind ); |
| } |
| else |
| nBhPos = USHRT_MAX; |
| |
| if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen. |
| { |
| ASSERT( sal_False, "Table, Loeschen auf keinem Bereich !?!" ); |
| return sal_False; |
| } |
| |
| if ( rTable.GetRowsToRepeat() > 0 ) |
| { |
| // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden |
| // sein?? |
| SwIterator<SwTabFrm,SwFmt> aIter( *rTable.GetFrmFmt() ); |
| for( SwTabFrm* pTable = aIter.First(); pTable; pTable = aIter.Next() ) |
| { |
| if( pTable->IsFollow() ) |
| { |
| // Insert new headlines: |
| lcl_UpdateRepeatedHeadlines( *pTable, false ); |
| } |
| } |
| } |
| |
| // Some adjacent lines at the beginning of the table have been deleted: |
| if ( nBfPos == USHRT_MAX && nBhPos == 0 ) |
| return sal_False; |
| |
| // Some adjacent lines at the end of the table have been deleted: |
| if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) ) |
| return sal_False; |
| |
| // Some adjacent lines in the middle of the table have been deleted: |
| if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos ) |
| return sal_False; |
| |
| // The structure of the deleted lines is more complex due to split lines. |
| // A call of MakeFrms() is necessary. |
| return sal_True; |
| } |
| |
| |