xref: /trunk/main/sc/source/ui/view/tabview2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include "scitems.hxx"
36 #include <editeng/eeitem.hxx>
37 
38 
39 #include <vcl/timer.hxx>
40 #include <vcl/msgbox.hxx>
41 #include <sfx2/app.hxx>
42 #include <sfx2/viewfrm.hxx>
43 #include <sfx2/bindings.hxx>
44 #include <sfx2/childwin.hxx>
45 
46 #include "attrib.hxx"
47 #include "pagedata.hxx"
48 #include "tabview.hxx"
49 #include "tabvwsh.hxx"
50 #include "printfun.hxx"
51 #include "stlpool.hxx"
52 #include "docsh.hxx"
53 #include "gridwin.hxx"
54 #include "olinewin.hxx"
55 #include "uiitems.hxx"
56 #include "sc.hrc"
57 #include "viewutil.hxx"
58 #include "colrowba.hxx"
59 #include "waitoff.hxx"
60 #include "globstr.hrc"
61 #include "scmod.hxx"
62 
63 #define SC_BLOCKMODE_NONE       0
64 #define SC_BLOCKMODE_NORMAL     1
65 #define SC_BLOCKMODE_OWN        2
66 
67 
68 
69 //
70 //          Markier - Funktionen
71 //
72 
73 void ScTabView::PaintMarks(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
74 {
75     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
76     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
77     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
78     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
79 
80     sal_Bool bLeft = (nStartCol==0 && nEndCol==MAXCOL);
81     sal_Bool bTop = (nStartRow==0 && nEndRow==MAXROW);
82 
83     if (bLeft)
84         PaintLeftArea( nStartRow, nEndRow );
85     if (bTop)
86         PaintTopArea( nStartCol, nEndCol );
87 
88     aViewData.GetDocument()->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow,
89                                             aViewData.GetTabNo() );
90     PaintArea( nStartCol, nStartRow, nEndCol, nEndRow, SC_UPDATE_MARKS );
91 }
92 
93 sal_Bool ScTabView::IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
94 {
95     return bIsBlockMode
96         && nBlockStartX == nCol
97         && nBlockStartY == nRow
98         && nBlockStartZ == nTab;
99 }
100 
101 void ScTabView::InitOwnBlockMode()
102 {
103     if (!bIsBlockMode)
104     {
105         //  Wenn keine (alte) Markierung mehr da ist, Anker in SelectionEngine loeschen:
106 
107         ScMarkData& rMark = aViewData.GetMarkData();
108         if (!rMark.IsMarked() && !rMark.IsMultiMarked())
109             GetSelEngine()->CursorPosChanging( sal_False, sal_False );
110 
111 //      bIsBlockMode = sal_True;
112         bIsBlockMode = SC_BLOCKMODE_OWN;            //! Variable umbenennen!
113         nBlockStartX = 0;
114         nBlockStartY = 0;
115         nBlockStartZ = 0;
116         nBlockEndX = 0;
117         nBlockEndY = 0;
118         nBlockEndZ = 0;
119 
120         SelectionChanged();     // Status wird mit gesetzer Markierung abgefragt
121     }
122 }
123 
124 void ScTabView::InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
125                                 sal_Bool bTestNeg, sal_Bool bCols, sal_Bool bRows )
126 {
127     if (!bIsBlockMode)
128     {
129         if (!ValidCol(nCurX)) nCurX = MAXCOL;
130         if (!ValidRow(nCurY)) nCurY = MAXROW;
131 
132         ScMarkData& rMark = aViewData.GetMarkData();
133         SCTAB nTab = aViewData.GetTabNo();
134 
135         //  Teil von Markierung aufheben?
136         if (bTestNeg)
137         {
138             if ( bCols )
139                 bBlockNeg = rMark.IsColumnMarked( nCurX );
140             else if ( bRows )
141                 bBlockNeg = rMark.IsRowMarked( nCurY );
142             else
143                 bBlockNeg = rMark.IsCellMarked( nCurX, nCurY );
144         }
145         else
146             bBlockNeg = sal_False;
147         rMark.SetMarkNegative(bBlockNeg);
148 
149 //      bIsBlockMode = sal_True;
150         bIsBlockMode = SC_BLOCKMODE_NORMAL;         //! Variable umbenennen!
151         bBlockCols = bCols;
152         bBlockRows = bRows;
153         nBlockStartX = nBlockStartXOrig = nCurX;
154         nBlockStartY = nBlockStartYOrig = nCurY;
155         nBlockStartZ = nCurZ;
156         nBlockEndX = nOldCurX = nBlockStartX;
157         nBlockEndY = nOldCurY = nBlockStartY;
158         nBlockEndZ = nBlockStartZ;
159 
160         if (bBlockCols)
161         {
162             nBlockStartY = nBlockStartYOrig = 0;
163             nBlockEndY = MAXROW;
164         }
165 
166         if (bBlockRows)
167         {
168             nBlockStartX = nBlockStartXOrig = 0;
169             nBlockEndX = MAXCOL;
170         }
171 
172         rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, nBlockEndX,nBlockEndY, nTab ) );
173 
174 #ifdef OLD_SELECTION_PAINT
175         InvertBlockMark( nBlockStartX,nBlockStartY,nBlockEndX,nBlockEndY );
176 #endif
177         UpdateSelectionOverlay();
178 
179         bNewStartIfMarking = sal_False;     // use only once
180     }
181 }
182 
183 void ScTabView::SetNewStartIfMarking()
184 {
185     bNewStartIfMarking = sal_True;
186 }
187 
188 void ScTabView::DoneBlockMode( sal_Bool bContinue )            // Default FALSE
189 {
190     //  Wenn zwischen Tabellen- und Header SelectionEngine gewechselt wird,
191     //  wird evtl. DeselectAll gerufen, weil die andere Engine keinen Anker hat.
192     //  Mit bMoveIsShift wird verhindert, dass dann die Selektion aufgehoben wird.
193 
194     if (bIsBlockMode && !bMoveIsShift)
195     {
196         ScMarkData& rMark = aViewData.GetMarkData();
197         sal_Bool bFlag = rMark.GetMarkingFlag();
198         rMark.SetMarking(sal_False);
199 
200         if (bBlockNeg && !bContinue)
201             rMark.MarkToMulti();
202 
203         if (bContinue)
204             rMark.MarkToMulti();
205         else
206         {
207             //  Die Tabelle kann an dieser Stelle ungueltig sein, weil DoneBlockMode
208             //  aus SetTabNo aufgerufen wird
209             //  (z.B. wenn die aktuelle Tabelle von einer anderen View aus geloescht wird)
210 
211             SCTAB nTab = aViewData.GetTabNo();
212             ScDocument* pDoc = aViewData.GetDocument();
213             if ( pDoc->HasTable(nTab) )
214                 PaintBlock( sal_True );                             // sal_True -> Block loeschen
215             else
216                 rMark.ResetMark();
217         }
218 //      bIsBlockMode = sal_False;
219         bIsBlockMode = SC_BLOCKMODE_NONE;           //! Variable umbenennen!
220 
221         rMark.SetMarking(bFlag);
222         rMark.SetMarkNegative(sal_False);
223     }
224 }
225 
226 void ScTabView::MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
227                             sal_Bool bCols, sal_Bool bRows, sal_Bool bCellSelection )
228 {
229     if (!ValidCol(nCurX)) nCurX = MAXCOL;
230     if (!ValidRow(nCurY)) nCurY = MAXROW;
231 
232     if (!bIsBlockMode)
233     {
234         DBG_ERROR( "MarkCursor nicht im BlockMode" );
235         InitBlockMode( nCurX, nCurY, nCurZ, sal_False, bCols, bRows );
236     }
237 
238     if (bCols)
239         nCurY = MAXROW;
240     if (bRows)
241         nCurX = MAXCOL;
242 
243     ScMarkData& rMark = aViewData.GetMarkData();
244     DBG_ASSERT(rMark.IsMarked() || rMark.IsMultiMarked(), "MarkCursor, !IsMarked()");
245     ScRange aMarkRange;
246     rMark.GetMarkArea(aMarkRange);
247     if (( aMarkRange.aStart.Col() != nBlockStartX && aMarkRange.aEnd.Col() != nBlockStartX ) ||
248         ( aMarkRange.aStart.Row() != nBlockStartY && aMarkRange.aEnd.Row() != nBlockStartY ) ||
249         ( bIsBlockMode == SC_BLOCKMODE_OWN ))
250     {
251         //  Markierung ist veraendert worden
252         //  (z.B. MarkToSimple, wenn per negativ alles bis auf ein Rechteck geloescht wurde)
253         //  oder nach InitOwnBlockMode wird mit Shift-Klick weitermarkiert...
254 
255         sal_Bool bOldShift = bMoveIsShift;
256         bMoveIsShift = sal_False;               //  wirklich umsetzen
257         DoneBlockMode(sal_False);               //! direkt Variablen setzen? (-> kein Geflacker)
258         bMoveIsShift = bOldShift;
259 
260         InitBlockMode( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
261                         nBlockStartZ, rMark.IsMarkNegative(), bCols, bRows );
262     }
263 
264     SCCOL nOldBlockEndX = nBlockEndX;
265     SCROW nOldBlockEndY = nBlockEndY;
266 
267     if ( nCurX != nOldCurX || nCurY != nOldCurY )
268     {
269         // Current cursor has moved
270 
271         SCTAB       nTab = nCurZ;
272 
273 #ifdef OLD_SELECTION_PAINT
274         SCCOL       nDrawStartCol;
275         SCROW       nDrawStartRow;
276         SCCOL       nDrawEndCol;
277         SCROW       nDrawEndRow;
278 #endif
279 
280         // Set old selection area
281         ScUpdateRect aRect( nBlockStartX, nBlockStartY, nOldBlockEndX, nOldBlockEndY );
282 
283         if ( bCellSelection )
284         {
285             // Expand selection area accordingly when the current selection ends
286             // with a merged cell.
287             SCsCOL nCurXOffset = 0;
288             SCsCOL nBlockStartXOffset = 0;
289             SCsROW nCurYOffset = 0;
290             SCsROW nBlockStartYOffset = 0;
291             sal_Bool bBlockStartMerged = sal_False;
292             const ScMergeAttr* pMergeAttr = NULL;
293             ScDocument* pDocument = aViewData.GetDocument();
294 
295             // The following block checks whether or not the "BlockStart" (anchor)
296             // cell is merged.  If it's merged, it'll then move the position of the
297             // anchor cell to the corner that's diagonally opposite of the
298             // direction of a current selection area.  For instance, if a current
299             // selection is moving in the upperleft direction, the anchor cell will
300             // move to the lower-right corner of the merged anchor cell, and so on.
301 
302             pMergeAttr = static_cast<const ScMergeAttr*>(
303                 pDocument->GetAttr( nBlockStartXOrig, nBlockStartYOrig, nTab, ATTR_MERGE ) );
304             if ( pMergeAttr->IsMerged() )
305             {
306                 SCsCOL nColSpan = pMergeAttr->GetColMerge();
307                 SCsROW nRowSpan = pMergeAttr->GetRowMerge();
308 
309                 if ( !( nCurX >= nBlockStartXOrig + nColSpan - 1 && nCurY >= nBlockStartYOrig + nRowSpan - 1 ) )
310                 {
311                     nBlockStartX = nCurX >= nBlockStartXOrig ? nBlockStartXOrig : nBlockStartXOrig + nColSpan - 1;
312                     nBlockStartY = nCurY >= nBlockStartYOrig ? nBlockStartYOrig : nBlockStartYOrig + nRowSpan - 1;
313                     nCurXOffset  = nCurX >= nBlockStartXOrig && nCurX < nBlockStartXOrig + nColSpan - 1 ?
314                         nBlockStartXOrig - nCurX + nColSpan - 1 : 0;
315                     nCurYOffset  = nCurY >= nBlockStartYOrig && nCurY < nBlockStartYOrig + nRowSpan - 1 ?
316                         nBlockStartYOrig - nCurY + nRowSpan - 1 : 0;
317                     bBlockStartMerged = sal_True;
318                 }
319             }
320 
321             // The following block checks whether or not the current cell is
322             // merged.  If it is, it'll then set the appropriate X & Y offset
323             // values (nCurXOffset & nCurYOffset) such that the selection area will
324             // grow by those specified offset amounts.  Note that the values of
325             // nCurXOffset/nCurYOffset may also be specified in the previous code
326             // block, in which case whichever value is greater will take on.
327 
328             pMergeAttr = static_cast<const ScMergeAttr*>(
329                 pDocument->GetAttr( nCurX, nCurY, nTab, ATTR_MERGE ) );
330             if ( pMergeAttr->IsMerged() )
331             {
332                 SCsCOL nColSpan = pMergeAttr->GetColMerge();
333                 SCsROW nRowSpan = pMergeAttr->GetRowMerge();
334 
335                 if ( !( nBlockStartX >= nCurX + nColSpan - 1 && nBlockStartY >= nCurY + nRowSpan - 1 ) )
336                 {
337                     if ( nBlockStartX <= nCurX + nColSpan - 1 )
338                     {
339                         SCsCOL nCurXOffsetTemp = nCurX < nCurX + nColSpan - 1 ? nColSpan - 1 : 0;
340                         nCurXOffset = nCurXOffset > nCurXOffsetTemp ? nCurXOffset : nCurXOffsetTemp;
341                     }
342                     if ( nBlockStartY <= nCurY + nRowSpan - 1 )
343                     {
344                         SCsROW nCurYOffsetTemp = nCurY < nCurY + nRowSpan - 1 ? nRowSpan - 1 : 0;
345                         nCurYOffset = nCurYOffset > nCurYOffsetTemp ? nCurYOffset : nCurYOffsetTemp;
346                     }
347                     if ( !( nBlockStartX <= nCurX && nBlockStartY <= nCurY ) &&
348                          !( nBlockStartX > nCurX + nColSpan - 1 && nBlockStartY > nCurY + nRowSpan - 1 ) )
349                     {
350                         nBlockStartXOffset = nBlockStartX > nCurX && nBlockStartX <= nCurX + nColSpan - 1 ? nCurX - nBlockStartX : 0;
351                         nBlockStartYOffset = nBlockStartY > nCurY && nBlockStartY <= nCurY + nRowSpan - 1 ? nCurY - nBlockStartY : 0;
352                     }
353                 }
354             }
355             else
356             {
357                 // The current cell is not merged.  Move the anchor cell to its
358                 // original position.
359                 if ( !bBlockStartMerged )
360                 {
361                     nBlockStartX = nBlockStartXOrig;
362                     nBlockStartY = nBlockStartYOrig;
363                 }
364             }
365 
366             nBlockStartX = nBlockStartX + nBlockStartXOffset >= 0 ? nBlockStartX + nBlockStartXOffset : 0;
367             nBlockStartY = nBlockStartY + nBlockStartYOffset >= 0 ? nBlockStartY + nBlockStartYOffset : 0;
368             nBlockEndX = nCurX + nCurXOffset > MAXCOL ? MAXCOL : nCurX + nCurXOffset;
369             nBlockEndY = nCurY + nCurYOffset > MAXROW ? MAXROW : nCurY + nCurYOffset;
370         }
371         else
372         {
373             nBlockEndX = nCurX;
374             nBlockEndY = nCurY;
375         }
376         // end of "if ( bCellSelection )"
377 
378         // Set new selection area
379         aRect.SetNew( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY );
380         rMark.SetMarkArea( ScRange( nBlockStartX, nBlockStartY, nTab, nBlockEndX, nBlockEndY, nTab ) );
381 
382 #ifdef OLD_SELECTION_PAINT
383         sal_Bool bCont;
384         sal_Bool bDraw = aRect.GetXorDiff( nDrawStartCol, nDrawStartRow,
385                                         nDrawEndCol, nDrawEndRow, bCont );
386         if ( bDraw )
387         {
388 //?         PutInOrder( nDrawStartCol, nDrawEndCol );
389 //?         PutInOrder( nDrawStartRow, nDrawEndRow );
390 
391             HideAllCursors();
392             InvertBlockMark( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow );
393             if (bCont)
394             {
395                 aRect.GetContDiff( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow );
396                 InvertBlockMark( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow );
397             }
398             ShowAllCursors();
399         }
400 #endif
401         UpdateSelectionOverlay();
402 
403         nOldCurX = nCurX;
404         nOldCurY = nCurY;
405 
406         aViewData.GetViewShell()->UpdateInputHandler();
407 //      InvalidateAttribs();
408     }
409 
410     if ( !bCols && !bRows )
411         aHdrFunc.SetAnchorFlag( sal_False );
412 }
413 
414 void ScTabView::UpdateSelectionOverlay()
415 {
416     for (sal_uInt16 i=0; i<4; i++)
417         if ( pGridWin[i] && pGridWin[i]->IsVisible() )
418             pGridWin[i]->UpdateSelectionOverlay();
419 }
420 
421 void ScTabView::UpdateShrinkOverlay()
422 {
423     for (sal_uInt16 i=0; i<4; i++)
424         if ( pGridWin[i] && pGridWin[i]->IsVisible() )
425             pGridWin[i]->UpdateShrinkOverlay();
426 }
427 
428 void ScTabView::UpdateAllOverlays()
429 {
430     for (sal_uInt16 i=0; i<4; i++)
431         if ( pGridWin[i] && pGridWin[i]->IsVisible() )
432             pGridWin[i]->UpdateAllOverlays();
433 }
434 
435 //!
436 //! PaintBlock in zwei Methoden aufteilen: RepaintBlock und RemoveBlock o.ae.
437 //!
438 
439 void ScTabView::PaintBlock( sal_Bool bReset )
440 {
441     ScDocument* pDoc = aViewData.GetDocument();
442     ScMarkData& rMark = aViewData.GetMarkData();
443     SCTAB nTab = aViewData.GetTabNo();
444     sal_Bool bMark = rMark.IsMarked();
445     sal_Bool bMulti = rMark.IsMultiMarked();
446     if (bMark || bMulti)
447     {
448         ScRange aMarkRange;
449         HideAllCursors();
450         if (bMulti)
451         {
452             sal_Bool bFlag = rMark.GetMarkingFlag();
453             rMark.SetMarking(sal_False);
454             rMark.MarkToMulti();
455             rMark.GetMultiMarkArea(aMarkRange);
456             rMark.MarkToSimple();
457             rMark.SetMarking(bFlag);
458 
459             bMark = rMark.IsMarked();
460             bMulti = rMark.IsMultiMarked();
461         }
462         else
463             rMark.GetMarkArea(aMarkRange);
464 
465         nBlockStartX = aMarkRange.aStart.Col();
466         nBlockStartY = aMarkRange.aStart.Row();
467         nBlockStartZ = aMarkRange.aStart.Tab();
468         nBlockEndX = aMarkRange.aEnd.Col();
469         nBlockEndY = aMarkRange.aEnd.Row();
470         nBlockEndZ = aMarkRange.aEnd.Tab();
471 
472         sal_Bool bDidReset = sal_False;
473 
474         if ( nTab>=nBlockStartZ && nTab<=nBlockEndZ )
475         {
476             if ( bReset )
477             {
478                 // Invertieren beim Loeschen nur auf aktiver View
479                 if ( aViewData.IsActive() )
480                 {
481                     sal_uInt16 i;
482                     if ( bMulti )
483                     {
484 #ifdef OLD_SELECTION_PAINT
485                         for (i=0; i<4; i++)
486                             if (pGridWin[i] && pGridWin[i]->IsVisible())
487                                 pGridWin[i]->InvertSimple( nBlockStartX, nBlockStartY,
488                                                             nBlockEndX, nBlockEndY,
489                                                             sal_True, sal_True );
490 #endif
491                         rMark.ResetMark();
492                         UpdateSelectionOverlay();
493                         bDidReset = sal_True;
494                     }
495                     else
496                     {
497 #ifdef OLD_SELECTION_PAINT
498                         // (mis)use InvertBlockMark to remove all of the selection
499                         // -> set bBlockNeg (like when removing parts of a selection)
500                         //    and convert everything to Multi
501 
502                         rMark.MarkToMulti();
503                         sal_Bool bOld = bBlockNeg;
504                         bBlockNeg = sal_True;
505                         // #73130# (negative) MarkArea must be set in case of repaint
506                         rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab,
507                                                     nBlockEndX,nBlockEndY, nTab ) );
508 
509                         InvertBlockMark( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY );
510 
511                         bBlockNeg = bOld;
512 #endif
513                         rMark.ResetMark();
514                         UpdateSelectionOverlay();
515                         bDidReset = sal_True;
516                     }
517 
518                     //  repaint if controls are touched (#69680# in both cases)
519                     // #i74768# Forms are rendered by DrawingLayer's EndDrawLayers()
520                     static bool bSuppressControlExtraStuff(true);
521 
522                     if(!bSuppressControlExtraStuff)
523                     {
524                         Rectangle aMMRect = pDoc->GetMMRect(nBlockStartX,nBlockStartY,nBlockEndX,nBlockEndY, nTab);
525                         if (pDoc->HasControl( nTab, aMMRect ))
526                         {
527                             for (i=0; i<4; i++)
528                             {
529                                 if (pGridWin[i] && pGridWin[i]->IsVisible())
530                                 {
531                                     //  MapMode muss logischer (1/100mm) sein !!!
532                                     pDoc->InvalidateControls( pGridWin[i], nTab, aMMRect );
533                                     pGridWin[i]->Update();
534                                 }
535                             }
536                         }
537                     }
538                 }
539             }
540             else
541                 PaintMarks( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY );
542         }
543 
544         if ( bReset && !bDidReset )
545             rMark.ResetMark();
546 
547         ShowAllCursors();
548     }
549 }
550 
551 void ScTabView::SelectAll( sal_Bool bContinue )
552 {
553     ScMarkData& rMark = aViewData.GetMarkData();
554     SCTAB nTab = aViewData.GetTabNo();
555 
556     if (rMark.IsMarked())
557     {
558         ScRange aMarkRange;
559         rMark.GetMarkArea( aMarkRange );
560         if ( aMarkRange == ScRange( 0,0,nTab, MAXCOL,MAXROW,nTab ) )
561             return;
562     }
563 
564     DoneBlockMode( bContinue );
565     InitBlockMode( 0,0,nTab );
566     MarkCursor( MAXCOL,MAXROW,nTab );
567 
568     SelectionChanged();
569 }
570 
571 void ScTabView::SelectAllTables()
572 {
573     ScDocument* pDoc = aViewData.GetDocument();
574     ScMarkData& rMark = aViewData.GetMarkData();
575 //    SCTAB nTab = aViewData.GetTabNo();
576     SCTAB nCount = pDoc->GetTableCount();
577 
578     if (nCount>1)
579     {
580         for (SCTAB i=0; i<nCount; i++)
581             rMark.SelectTable( i, sal_True );
582 
583         //      Markierungen werden per Default nicht pro Tabelle gehalten
584 //      pDoc->ExtendMarksFromTable( nTab );
585 
586         aViewData.GetDocShell()->PostPaintExtras();
587         SfxBindings& rBind = aViewData.GetBindings();
588         rBind.Invalidate( FID_FILL_TAB );
589         rBind.Invalidate( FID_TAB_DESELECTALL );
590     }
591 }
592 
593 void ScTabView::DeselectAllTables()
594 {
595     ScDocument* pDoc = aViewData.GetDocument();
596     ScMarkData& rMark = aViewData.GetMarkData();
597     SCTAB nTab = aViewData.GetTabNo();
598     SCTAB nCount = pDoc->GetTableCount();
599 
600     for (SCTAB i=0; i<nCount; i++)
601         rMark.SelectTable( i, ( i == nTab ) );
602 
603     aViewData.GetDocShell()->PostPaintExtras();
604     SfxBindings& rBind = aViewData.GetBindings();
605     rBind.Invalidate( FID_FILL_TAB );
606     rBind.Invalidate( FID_TAB_DESELECTALL );
607 }
608 
609 sal_Bool lcl_FitsInWindow( double fScaleX, double fScaleY, sal_uInt16 nZoom,
610                         long nWindowX, long nWindowY, ScDocument* pDoc, SCTAB nTab,
611                         SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
612                         SCCOL nFixPosX, SCROW nFixPosY )
613 {
614     double fZoomFactor = (double)Fraction(nZoom,100);
615     fScaleX *= fZoomFactor;
616     fScaleY *= fZoomFactor;
617 
618     long nBlockX = 0;
619     SCCOL nCol;
620     for (nCol=0; nCol<nFixPosX; nCol++)
621     {
622         //  for frozen panes, add both parts
623         sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
624         if (nColTwips)
625         {
626             nBlockX += (long)(nColTwips * fScaleX);
627             if (nBlockX > nWindowX)
628                 return sal_False;
629         }
630     }
631     for (nCol=nStartCol; nCol<=nEndCol; nCol++)
632     {
633         sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
634         if (nColTwips)
635         {
636             nBlockX += (long)(nColTwips * fScaleX);
637             if (nBlockX > nWindowX)
638                 return sal_False;
639         }
640     }
641 
642     long nBlockY = 0;
643     for (SCROW nRow = 0; nRow <= nFixPosY-1; ++nRow)
644     {
645         if (pDoc->RowHidden(nRow, nTab))
646             continue;
647 
648         //  for frozen panes, add both parts
649         sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
650         if (nRowTwips)
651         {
652             nBlockY += (long)(nRowTwips * fScaleY);
653             if (nBlockY > nWindowY)
654                 return sal_False;
655         }
656     }
657     for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
658     {
659         sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
660         if (nRowTwips)
661         {
662             nBlockY += (long)(nRowTwips * fScaleY);
663             if (nBlockY > nWindowY)
664                 return sal_False;
665         }
666     }
667 
668     return sal_True;
669 }
670 
671 sal_uInt16 ScTabView::CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom )
672 {
673     sal_uInt16 nZoom = 0; // Ergebnis
674 
675     switch ( eType )
676     {
677         case SVX_ZOOM_PERCENT: // rZoom ist kein besonderer prozentualer Wert
678             nZoom = nOldZoom;
679             break;
680 
681         case SVX_ZOOM_OPTIMAL:  // nZoom entspricht der optimalen Gr"o\se
682             {
683                 ScMarkData& rMark = aViewData.GetMarkData();
684                 ScDocument* pDoc = aViewData.GetDocument();
685 
686                 if (!rMark.IsMarked() && !rMark.IsMultiMarked())
687                     nZoom = 100;                // nothing selected
688                 else
689                 {
690                     SCTAB   nTab = aViewData.GetTabNo();
691                     ScRange aMarkRange;
692                     if ( aViewData.GetSimpleArea( aMarkRange ) != SC_MARK_SIMPLE )
693                         rMark.GetMultiMarkArea( aMarkRange );
694 
695                     SCCOL   nStartCol = aMarkRange.aStart.Col();
696                     SCROW   nStartRow = aMarkRange.aStart.Row();
697                     SCTAB   nStartTab = aMarkRange.aStart.Tab();
698                     SCCOL   nEndCol = aMarkRange.aEnd.Col();
699                     SCROW   nEndRow = aMarkRange.aEnd.Row();
700                     SCTAB   nEndTab = aMarkRange.aEnd.Tab();
701 
702                     if ( nTab < nStartTab && nTab > nEndTab )
703                         nTab = nStartTab;
704 
705                     ScSplitPos eUsedPart = aViewData.GetActivePart();
706 
707                     SCCOL nFixPosX = 0;
708                     SCROW nFixPosY = 0;
709                     if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
710                     {
711                         //  use right part
712                         eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
713                         nFixPosX = aViewData.GetFixPosX();
714                         if ( nStartCol < nFixPosX )
715                             nStartCol = nFixPosX;
716                     }
717                     if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
718                     {
719                         //  use bottom part
720                         eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
721                         nFixPosY = aViewData.GetFixPosY();
722                         if ( nStartRow < nFixPosY )
723                             nStartRow = nFixPosY;
724                     }
725 
726                     if (pGridWin[eUsedPart])
727                     {
728                         //  Because scale is rounded to pixels, the only reliable way to find
729                         //  the right scale is to check if a zoom fits
730 
731                         Size aWinSize = pGridWin[eUsedPart]->GetOutputSizePixel();
732 
733                         //  for frozen panes, use sum of both parts for calculation
734 
735                         if ( nFixPosX != 0 )
736                             aWinSize.Width() += GetGridWidth( SC_SPLIT_LEFT );
737                         if ( nFixPosY != 0 )
738                             aWinSize.Height() += GetGridHeight( SC_SPLIT_TOP );
739 
740                         ScDocShell* pDocSh = aViewData.GetDocShell();
741                         double nPPTX = ScGlobal::nScreenPPTX / pDocSh->GetOutputFactor();
742                         double nPPTY = ScGlobal::nScreenPPTY;
743 
744                         sal_uInt16 nMin = MINZOOM;
745                         sal_uInt16 nMax = MAXZOOM;
746                         while ( nMax > nMin )
747                         {
748                             sal_uInt16 nTest = (nMin+nMax+1)/2;
749                             if ( lcl_FitsInWindow(
750                                         nPPTX, nPPTY, nTest, aWinSize.Width(), aWinSize.Height(),
751                                         pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow,
752                                         nFixPosX, nFixPosY ) )
753                                 nMin = nTest;
754                             else
755                                 nMax = nTest-1;
756                         }
757                         DBG_ASSERT( nMin == nMax, "Schachtelung ist falsch" );
758                         nZoom = nMin;
759 
760                         if ( nZoom != nOldZoom )
761                         {
762                             // scroll to block only in active split part
763                             // (the part for which the size was calculated)
764 
765                             if ( nStartCol <= nEndCol )
766                                 aViewData.SetPosX( WhichH(eUsedPart), nStartCol );
767                             if ( nStartRow <= nEndRow )
768                                 aViewData.SetPosY( WhichV(eUsedPart), nStartRow );
769                         }
770                     }
771                 }
772             }
773             break;
774 
775             case SVX_ZOOM_WHOLEPAGE:    // nZoom entspricht der ganzen Seite oder
776             case SVX_ZOOM_PAGEWIDTH:    // nZoom entspricht der Seitenbreite
777                 {
778                     SCTAB               nCurTab     = aViewData.GetTabNo();
779                     ScDocument*         pDoc        = aViewData.GetDocument();
780                     ScStyleSheetPool*   pStylePool  = pDoc->GetStyleSheetPool();
781                     SfxStyleSheetBase*  pStyleSheet =
782                                             pStylePool->Find( pDoc->GetPageStyle( nCurTab ),
783                                                               SFX_STYLE_FAMILY_PAGE );
784 
785                     DBG_ASSERT( pStyleSheet, "PageStyle not found :-/" );
786 
787                     if ( pStyleSheet )
788                     {
789                         ScPrintFunc aPrintFunc( aViewData.GetDocShell(),
790                                                 aViewData.GetViewShell()->GetPrinter(sal_True),
791                                                 nCurTab );
792 
793                         Size aPageSize = aPrintFunc.GetDataSize();
794 
795                         //  use the size of the largest GridWin for normal split,
796                         //  or both combined for frozen panes, with the (document) size
797                         //  of the frozen part added to the page size
798                         //  (with frozen panes, the size of the individual parts
799                         //  depends on the scale that is to be calculated)
800 
801                         if ( !pGridWin[SC_SPLIT_BOTTOMLEFT] ) return 0;
802                         Size aWinSize = pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutputSizePixel();
803                         ScSplitMode eHMode = aViewData.GetHSplitMode();
804                         if ( eHMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_BOTTOMRIGHT] )
805                         {
806                             long nOtherWidth = pGridWin[SC_SPLIT_BOTTOMRIGHT]->
807                                                         GetOutputSizePixel().Width();
808                             if ( eHMode == SC_SPLIT_FIX )
809                             {
810                                 aWinSize.Width() += nOtherWidth;
811                                 for ( SCCOL nCol = aViewData.GetPosX(SC_SPLIT_LEFT);
812                                         nCol < aViewData.GetFixPosX(); nCol++ )
813                                     aPageSize.Width() += pDoc->GetColWidth( nCol, nCurTab );
814                             }
815                             else if ( nOtherWidth > aWinSize.Width() )
816                                 aWinSize.Width() = nOtherWidth;
817                         }
818                         ScSplitMode eVMode = aViewData.GetVSplitMode();
819                         if ( eVMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_TOPLEFT] )
820                         {
821                             long nOtherHeight = pGridWin[SC_SPLIT_TOPLEFT]->
822                                                         GetOutputSizePixel().Height();
823                             if ( eVMode == SC_SPLIT_FIX )
824                             {
825                                 aWinSize.Height() += nOtherHeight;
826                                 aPageSize.Height() += pDoc->GetRowHeight(
827                                         aViewData.GetPosY(SC_SPLIT_TOP),
828                                         aViewData.GetFixPosY()-1, nCurTab);
829                             }
830                             else if ( nOtherHeight > aWinSize.Height() )
831                                 aWinSize.Height() = nOtherHeight;
832                         }
833 
834                         double nPPTX = ScGlobal::nScreenPPTX / aViewData.GetDocShell()->GetOutputFactor();
835                         double nPPTY = ScGlobal::nScreenPPTY;
836 
837                         long nZoomX = (long) ( aWinSize.Width() * 100 /
838                                                ( aPageSize.Width() * nPPTX ) );
839                         long nZoomY = (long) ( aWinSize.Height() * 100 /
840                                                ( aPageSize.Height() * nPPTY ) );
841                         long nNew = nZoomX;
842 
843                         if (eType == SVX_ZOOM_WHOLEPAGE && nZoomY < nNew)
844                             nNew = nZoomY;
845 
846                         nZoom = (sal_uInt16) nNew;
847                     }
848                 }
849                 break;
850 
851         default:
852             DBG_ERROR("Unknown Zoom-Revision");
853             nZoom = 0;
854     }
855 
856     return nZoom;
857 }
858 
859 //  wird z.B. gerufen, wenn sich das View-Fenster verschiebt:
860 
861 void ScTabView::StopMarking()
862 {
863     ScSplitPos eActive = aViewData.GetActivePart();
864     if (pGridWin[eActive])
865         pGridWin[eActive]->StopMarking();
866 
867     ScHSplitPos eH = WhichH(eActive);
868     if (pColBar[eH])
869         pColBar[eH]->StopMarking();
870 
871     ScVSplitPos eV = WhichV(eActive);
872     if (pRowBar[eV])
873         pRowBar[eV]->StopMarking();
874 }
875 
876 void ScTabView::HideNoteMarker()
877 {
878     for (sal_uInt16 i=0; i<4; i++)
879         if (pGridWin[i] && pGridWin[i]->IsVisible())
880             pGridWin[i]->HideNoteMarker();
881 }
882 
883 void ScTabView::MakeDrawLayer()
884 {
885     if (!pDrawView)
886     {
887         aViewData.GetDocShell()->MakeDrawLayer();
888 
889         //  pDrawView wird per Notify gesetzt
890         DBG_ASSERT(pDrawView,"ScTabView::MakeDrawLayer funktioniert nicht");
891 
892         // #114409#
893         for(sal_uInt16 a(0); a < 4; a++)
894         {
895             if(pGridWin[a])
896             {
897                 pGridWin[a]->DrawLayerCreated();
898             }
899         }
900     }
901 }
902 
903 void ScTabView::ErrorMessage( sal_uInt16 nGlobStrId )
904 {
905     if ( SC_MOD()->IsInExecuteDrop() )
906     {
907         // #i28468# don't show error message when called from Drag&Drop, silently abort instead
908         return;
909     }
910 
911     StopMarking();      // falls per Focus aus MouseButtonDown aufgerufen
912 
913     Window* pParent = aViewData.GetDialogParent();
914     ScWaitCursorOff aWaitOff( pParent );
915     sal_Bool bFocus = pParent && pParent->HasFocus();
916 
917     if(nGlobStrId==STR_PROTECTIONERR)
918     {
919         if(aViewData.GetDocShell()->IsReadOnly())
920         {
921             nGlobStrId=STR_READONLYERR;
922         }
923     }
924 
925     InfoBox aBox( pParent, ScGlobal::GetRscString( nGlobStrId ) );
926     aBox.Execute();
927     if (bFocus)
928         pParent->GrabFocus();
929 }
930 
931 Window* ScTabView::GetParentOrChild( sal_uInt16 nChildId )
932 {
933     SfxViewFrame* pViewFrm = aViewData.GetViewShell()->GetViewFrame();
934 
935     if ( pViewFrm->HasChildWindow(nChildId) )
936     {
937         SfxChildWindow* pChild = pViewFrm->GetChildWindow(nChildId);
938         if (pChild)
939         {
940             Window* pWin = pChild->GetWindow();
941             if (pWin && pWin->IsVisible())
942                 return pWin;
943         }
944     }
945 
946     return aViewData.GetDialogParent();
947 }
948 
949 void ScTabView::UpdatePageBreakData( sal_Bool bForcePaint )
950 {
951     ScPageBreakData* pNewData = NULL;
952 
953     if (aViewData.IsPagebreakMode())
954     {
955         ScDocShell* pDocSh = aViewData.GetDocShell();
956         ScDocument* pDoc = pDocSh->GetDocument();
957         SCTAB nTab = aViewData.GetTabNo();
958 
959         sal_uInt16 nCount = pDoc->GetPrintRangeCount(nTab);
960         if (!nCount)
961             nCount = 1;
962         pNewData = new ScPageBreakData(nCount);
963 
964         ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab, 0,0,NULL, NULL, pNewData );
965         //  ScPrintFunc fuellt im ctor die PageBreakData
966         if ( nCount > 1 )
967         {
968             aPrintFunc.ResetBreaks(nTab);
969             pNewData->AddPages();
970         }
971 
972         //  Druckbereiche veraendert?
973         if ( bForcePaint || ( pPageBreakData && !pPageBreakData->IsEqual( *pNewData ) ) )
974             PaintGrid();
975     }
976 
977     delete pPageBreakData;
978     pPageBreakData = pNewData;
979 }
980 
981 
982 
983