xref: /AOO41X/main/sfx2/source/dialog/splitwin.cxx (revision 54628ca40d27d15cc98fe861da7fff7e60c2f7d6)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26 
27 #ifdef SOLARIS
28 // HACK: prevent conflict between STLPORT and Workshop headers on Solaris 8
29 #include <ctime>
30 #endif
31 
32 #include <string> // HACK: prevent conflict between STLPORT and Workshop headers
33 
34 #ifndef _WRKWIN_HXX //autogen
35 #include <vcl/wrkwin.hxx>
36 #endif
37 #include <unotools/viewoptions.hxx>
38 #ifndef GCC
39 #endif
40 
41 #include <vcl/timer.hxx>
42 
43 #include "splitwin.hxx"
44 #include "workwin.hxx"
45 #include <sfx2/dockwin.hxx>
46 #include <sfx2/app.hxx>
47 #include "dialog.hrc"
48 #include "sfx2/sfxresid.hxx"
49 #include <sfx2/mnumgr.hxx>
50 #include "virtmenu.hxx"
51 #include <sfx2/msgpool.hxx>
52 #include <sfx2/viewfrm.hxx>
53 
54 using namespace ::com::sun::star::uno;
55 using namespace ::rtl;
56 
57 #define VERSION 1
58 #define nPixel  30L
59 #define USERITEM_NAME           OUString::createFromAscii( "UserItem" )
60 
61 struct SfxDock_Impl
62 {
63     sal_uInt16              nType;
64     SfxDockingWindow*   pWin;           // SplitWindow hat dieses Fenster
65     sal_Bool                bNewLine;
66     sal_Bool                bHide;          // SplitWindow hatte dieses Fenster
67     long                nSize;
68 };
69 
70 typedef SfxDock_Impl* SfxDockPtr;
71 SV_DECL_PTRARR_DEL( SfxDockArr_Impl, SfxDockPtr, 4, 4)
72 SV_IMPL_PTRARR( SfxDockArr_Impl, SfxDockPtr);
73 
74 class SfxEmptySplitWin_Impl : public SplitWindow
75 {
76 /*  [Beschreibung]
77 
78     Das SfxEmptySplitWin_Impldow ist ein leeres SplitWindow, das das SfxSplitWindow
79     im AutoHide-Modus ersetzt. Es dient nur als Platzhalter, um MouseMoves
80     zu empfangen und ggf. das eigentlichte SplitWindow einzublenden
81 */
82 friend class SfxSplitWindow;
83 
84     SfxSplitWindow*     pOwner;
85     sal_Bool                bFadeIn;
86     sal_Bool                bAutoHide;
87     sal_Bool                bSplit;
88     sal_Bool                bEndAutoHide;
89     Timer               aTimer;
90     Point               aLastPos;
91     sal_uInt16              nState;
92 
93                         SfxEmptySplitWin_Impl( SfxSplitWindow *pParent )
94                             : SplitWindow( pParent->GetParent(), WinBits( WB_BORDER | WB_3DLOOK ) )
95                             , pOwner( pParent )
96                             , bFadeIn( sal_False )
97                             , bAutoHide( sal_False )
98                             , bSplit( sal_False )
99                             , bEndAutoHide( sal_False )
100                             , nState( 1 )
101                         {
102                             aTimer.SetTimeoutHdl(
103                                 LINK(pOwner, SfxSplitWindow, TimerHdl ) );
104                             aTimer.SetTimeout( 200 );
105 //                            EnableDrop( sal_True );
106                             SetAlign( pOwner->GetAlign() );
107                             Actualize();
108                             ShowAutoHideButton( pOwner->IsAutoHideButtonVisible() );
109                             ShowFadeInHideButton( sal_True );
110                         }
111 
112                         ~SfxEmptySplitWin_Impl()
113                         {
114                             aTimer.Stop();
115                         }
116 
117     virtual void        MouseMove( const MouseEvent& );
118     virtual void        AutoHide();
119     virtual void        FadeIn();
120     void                Actualize();
121 };
122 
123 void SfxEmptySplitWin_Impl::Actualize()
124 {
125     Size aSize( pOwner->GetSizePixel() );
126     switch ( pOwner->GetAlign() )
127     {
128         case WINDOWALIGN_LEFT:
129         case WINDOWALIGN_RIGHT:
130             aSize.Width() = GetFadeInSize();
131             break;
132         case WINDOWALIGN_TOP:
133         case WINDOWALIGN_BOTTOM:
134             aSize.Height() = GetFadeInSize();
135             break;
136     }
137 
138     SetSizePixel( aSize );
139 }
140 
141 void SfxEmptySplitWin_Impl::AutoHide()
142 {
143     pOwner->SetPinned_Impl( !pOwner->bPinned );
144     pOwner->SaveConfig_Impl();
145     bAutoHide = sal_True;
146     FadeIn();
147 }
148 
149 void SfxEmptySplitWin_Impl::FadeIn()
150 {
151     if (!bAutoHide )
152         bAutoHide = IsFadeNoButtonMode();
153     pOwner->SetFadeIn_Impl( sal_True );
154     pOwner->Show_Impl();
155     if ( bAutoHide )
156     {
157         // Timer zum Schlie\sen aufsetzen; der Aufrufer mu\s selbst sicherstellen,
158         // da\s das Window nicht gleich wieder zu geht ( z.B. durch Setzen des
159         // Focus oder einen modal mode )
160         aLastPos = GetPointerPosPixel();
161         aTimer.Start();
162     }
163     else
164         pOwner->SaveConfig_Impl();
165 }
166 
167 //-------------------------------------------------------------------------
168 
169 void SfxSplitWindow::MouseButtonDown( const MouseEvent& rMEvt )
170 {
171     if ( rMEvt.GetClicks() != 2 )
172         SplitWindow::MouseButtonDown( rMEvt );
173 }
174 
175 void SfxEmptySplitWin_Impl::MouseMove( const MouseEvent& rMEvt )
176 {
177     SplitWindow::MouseMove( rMEvt );
178 }
179 
180 //-------------------------------------------------------------------------
181 
182 SfxSplitWindow::SfxSplitWindow( Window* pParent, SfxChildAlignment eAl,
183         SfxWorkWindow *pW, sal_Bool bWithButtons, WinBits nBits )
184 
185 /*  [Beschreibung]
186 
187     Ein SfxSplitWindow verbirgt die rekursive Struktur des SV-Splitwindows
188     nach au\sen, indem es einen tabellenartigen Aufbau mit Zeilen und Spalten
189     ( also maximale Rekursionstiefe 2 ) simuliert.
190     Au\erdem sichert es die Persistenz der Anordnung der SfxDockingWindows.
191 */
192 
193 :   SplitWindow ( pParent, nBits | WB_HIDE ),
194     eAlign(eAl),
195     pWorkWin(pW),
196     pDockArr( new SfxDockArr_Impl ),
197     bLocked(sal_False),
198     bPinned(sal_True),
199     pEmptyWin(NULL),
200     pActive(NULL)
201 {
202     if ( bWithButtons )
203     {
204         ShowAutoHideButton( sal_False );    // no autohide button (pin) anymore
205         ShowFadeOutButton( sal_True );
206     }
207 
208     // SV-Alignment setzen
209     WindowAlign eTbxAlign;
210     switch ( eAlign )
211     {
212         case SFX_ALIGN_LEFT:
213             eTbxAlign = WINDOWALIGN_LEFT;
214             break;
215         case SFX_ALIGN_RIGHT:
216             eTbxAlign = WINDOWALIGN_RIGHT;
217             break;
218         case SFX_ALIGN_TOP:
219             eTbxAlign = WINDOWALIGN_TOP;
220             break;
221         case SFX_ALIGN_BOTTOM:
222             eTbxAlign = WINDOWALIGN_BOTTOM;
223             bPinned = sal_True;
224             break;
225         default:
226             eTbxAlign = WINDOWALIGN_TOP;  // some sort of default...
227             break;  // -Wall lots not handled..
228     }
229 
230     SetAlign (eTbxAlign);
231     pEmptyWin = new SfxEmptySplitWin_Impl( this );
232     if ( bPinned )
233     {
234         pEmptyWin->bFadeIn = sal_True;
235         pEmptyWin->nState = 2;
236     }
237 
238     if ( bWithButtons )
239     {
240         // Konfiguration einlesen
241         String aWindowId = String::CreateFromAscii("SplitWindow");
242         aWindowId += String::CreateFromInt32( (sal_Int32) eTbxAlign );
243         SvtViewOptions aWinOpt( E_WINDOW, aWindowId );
244         String aWinData;
245         Any aUserItem = aWinOpt.GetUserItem( USERITEM_NAME );
246         OUString aTemp;
247         if ( aUserItem >>= aTemp )
248             aWinData = String( aTemp );
249         if ( aWinData.Len() && aWinData.GetChar( (sal_uInt16) 0 ) == 'V' )
250         {
251             pEmptyWin->nState = (sal_uInt16) aWinData.GetToken( 1, ',' ).ToInt32();
252             if ( pEmptyWin->nState & 2 )
253                 pEmptyWin->bFadeIn = sal_True;
254             //bPinned = !( pEmptyWin->nState & 1 );
255             bPinned = sal_True; // always assume pinned - floating mode not used anymore
256 
257             sal_uInt16 i=2;
258             sal_uInt16 nCount = (sal_uInt16) aWinData.GetToken(i++, ',').ToInt32();
259             for ( sal_uInt16 n=0; n<nCount; n++ )
260             {
261                 SfxDock_Impl *pDock = new SfxDock_Impl;
262                 pDock->pWin = 0;
263                 pDock->bNewLine = sal_False;
264                 pDock->bHide = sal_True;
265                 pDock->nType = (sal_uInt16) aWinData.GetToken(i++, ',').ToInt32();
266                 if ( !pDock->nType )
267                 {
268                     // K"onnte NewLine bedeuten
269                     pDock->nType = (sal_uInt16) aWinData.GetToken(i++, ',').ToInt32();
270                     if ( !pDock->nType )
271                     {
272                         // Lesefehler
273                         delete pDock;
274                         break;
275                     }
276                     else
277                         pDock->bNewLine = sal_True;
278                 }
279 
280                 pDockArr->Insert(pDock,n);
281             }
282         }
283     }
284     else
285     {
286         bPinned = sal_True;
287         pEmptyWin->bFadeIn = sal_True;
288         pEmptyWin->nState = 2;
289     }
290 
291     SetAutoHideState( !bPinned );
292     pEmptyWin->SetAutoHideState( !bPinned );
293 }
294 
295 //-------------------------------------------------------------------------
296 
297 SfxSplitWindow::~SfxSplitWindow()
298 {
299     if ( !pWorkWin->GetParent_Impl() )
300         SaveConfig_Impl();
301 
302     if ( pEmptyWin )
303     {
304         // pOwner auf NULL setzen, sonst versucht pEmptyWin, nochmal zu
305         // l"oschen; es wird n"amlich von au\sen immer das Fenster deleted,
306         // das gerade angedockt ist
307         pEmptyWin->pOwner = NULL;
308         delete pEmptyWin;
309     }
310 
311     delete pDockArr;
312 }
313 
314 void SfxSplitWindow::SaveConfig_Impl()
315 {
316     // Konfiguration abspeichern
317     String aWinData('V');
318     aWinData += String::CreateFromInt32( VERSION );
319     aWinData += ',';
320     aWinData += String::CreateFromInt32( pEmptyWin->nState );
321     aWinData += ',';
322 
323     sal_uInt16 nCount = 0;
324     sal_uInt16 n;
325     for ( n=0; n<pDockArr->Count(); n++ )
326     {
327         SfxDock_Impl *pDock = (*pDockArr)[n];
328         if ( pDock->bHide || pDock->pWin )
329             nCount++;
330     }
331 
332     aWinData += String::CreateFromInt32( nCount );
333 
334     for ( n=0; n<pDockArr->Count(); n++ )
335     {
336         SfxDock_Impl *pDock = (*pDockArr)[n];
337         if ( !pDock->bHide && !pDock->pWin )
338             continue;
339         if ( pDock->bNewLine )
340             aWinData += DEFINE_CONST_UNICODE(",0");
341         aWinData += ',';
342         aWinData += String::CreateFromInt32( pDock->nType);
343     }
344 
345     String aWindowId = String::CreateFromAscii("SplitWindow");
346     aWindowId += String::CreateFromInt32( (sal_Int32) GetAlign() );
347     SvtViewOptions aWinOpt( E_WINDOW, aWindowId );
348     aWinOpt.SetUserItem( USERITEM_NAME, makeAny( OUString( aWinData ) ) );
349 }
350 
351 //-------------------------------------------------------------------------
352 
353 void SfxSplitWindow::StartSplit()
354 {
355     long nSize = 0;
356     Size aSize = GetSizePixel();
357 
358     if ( pEmptyWin )
359     {
360         pEmptyWin->bFadeIn = sal_True;
361         pEmptyWin->bSplit = sal_True;
362     }
363 
364     Rectangle aRect = pWorkWin->GetFreeArea( !bPinned );
365     switch ( GetAlign() )
366     {
367         case WINDOWALIGN_LEFT:
368         case WINDOWALIGN_RIGHT:
369             nSize = aSize.Width() + aRect.GetWidth();
370             break;
371         case WINDOWALIGN_TOP:
372         case WINDOWALIGN_BOTTOM:
373             nSize = aSize.Height() + aRect.GetHeight();
374             break;
375     }
376 
377     SetMaxSizePixel( nSize );
378 }
379 
380 //-------------------------------------------------------------------------
381 
382 void SfxSplitWindow::SplitResize()
383 {
384     if ( bPinned )
385     {
386         pWorkWin->ArrangeChilds_Impl();
387         pWorkWin->ShowChilds_Impl();
388     }
389     else
390         pWorkWin->ArrangeAutoHideWindows( this );
391 }
392 
393 //-------------------------------------------------------------------------
394 
395 void SfxSplitWindow::Split()
396 {
397     if ( pEmptyWin )
398         pEmptyWin->bSplit = sal_False;
399 
400     SplitWindow::Split();
401 
402     sal_uInt16 nCount = pDockArr->Count();
403     for ( sal_uInt16 n=0; n<nCount; n++ )
404     {
405         SfxDock_Impl *pD = (*pDockArr)[n];
406         if ( pD->pWin )
407         {
408             sal_uInt16 nId = pD->nType;
409             long nSize    = GetItemSize( nId, SWIB_FIXED );
410             long nSetSize = GetItemSize( GetSet( nId ) );
411             Size aSize;
412 
413             if ( IsHorizontal() )
414             {
415                 aSize.Width()  = nSize;
416                 aSize.Height() = nSetSize;
417             }
418             else
419             {
420                 aSize.Width()  = nSetSize;
421                 aSize.Height() = nSize;
422             }
423 
424             pD->pWin->SetItemSize_Impl( aSize );
425         }
426     }
427 
428     SaveConfig_Impl();
429 }
430 
431 //-------------------------------------------------------------------------
432 
433 void SfxSplitWindow::InsertWindow( SfxDockingWindow* pDockWin, const Size& rSize)
434 
435 /*  [Beschreibung]
436 
437     Zum Einf"ugen von SfxDockingWindows kann auch keine Position "ubergeben
438     werden. Das SfxSplitWindow sucht dann die zuletzt gemerkte zu dem
439     "ubergebenen SfxDockingWindow heraus oder h"angt es als letztes neu an.
440 
441 */
442 {
443     short nLine = -1;       // damit erstes Fenster nLine auf 0 hochsetzen kann
444     sal_uInt16 nL;
445     sal_uInt16 nPos = 0;
446     sal_Bool bNewLine = sal_True;
447     sal_Bool bSaveConfig = sal_False;
448     SfxDock_Impl *pFoundDock=0;
449     sal_uInt16 nCount = pDockArr->Count();
450     for ( sal_uInt16 n=0; n<nCount; n++ )
451     {
452         SfxDock_Impl *pDock = (*pDockArr)[n];
453         if ( pDock->bNewLine )
454         {
455             // Das Fenster er"offnet eine neue Zeile
456             if ( pFoundDock )
457                 // Aber hinter dem gerade eingef"ugten Fenster
458                 break;
459 
460             // Neue Zeile
461             nPos = 0;
462             bNewLine = sal_True;
463         }
464 
465         if ( pDock->pWin )
466         {
467             // Es gibt an dieser Stelle gerade ein Fenster
468             if ( bNewLine && !pFoundDock )
469             {
470                 // Bisher ist nicht bekannt, in welcher realen Zeile es liegt
471                 GetWindowPos( pDock->pWin, nL, nPos );
472                 nLine = (short) nL;
473             }
474 
475             if ( !pFoundDock )
476             {
477                 // Fenster liegt vor dem eingef"ugten
478                 nPos++;
479             }
480 
481             // Zeile ist schon er"offnet
482             bNewLine = sal_False;
483             if ( pFoundDock )
484                 break;
485         }
486 
487         if ( pDock->nType == pDockWin->GetType() )
488         {
489             DBG_ASSERT( !pFoundDock && !pDock->pWin, "Fenster ist schon vorhanden!");
490             pFoundDock = pDock;
491             if ( !bNewLine )
492                 break;
493             else
494             {
495                 // Es wurde zuletzt eine neue Reihe gestartet, aber noch kein
496                 // darin liegendes Fenster gefunden; daher weitersuchen, ob noch
497                 // ein Fenster in dieser Zeile folgt, um bNewLine korrekt zu setzen.
498                 // Dabei darf aber nLine oder nPos nicht mehr ver"andert werden!
499                 nLine++;
500             }
501         }
502     }
503 
504     if ( !pFoundDock )
505     {
506         // Nicht gefunden, am Ende einf"ugen
507         pFoundDock = new SfxDock_Impl;
508         pFoundDock->bHide = sal_True;
509         pDockArr->Insert( pFoundDock, nCount );
510         pFoundDock->nType = pDockWin->GetType();
511         nLine++;
512         nPos = 0;
513         bNewLine = sal_True;
514         pFoundDock->bNewLine = bNewLine;
515         bSaveConfig = sal_True;
516     }
517 
518     pFoundDock->pWin = pDockWin;
519     pFoundDock->bHide = sal_False;
520     InsertWindow_Impl( pFoundDock, rSize, nLine, nPos, bNewLine );
521     if ( bSaveConfig )
522         SaveConfig_Impl();
523 }
524 
525 //-------------------------------------------------------------------------
526 
527 void SfxSplitWindow::ReleaseWindow_Impl(SfxDockingWindow *pDockWin, sal_Bool bSave)
528 
529 /*  [Beschreibung]
530 
531     Das DockingWindow wird nicht mehr in den internen Daten gespeichert.
532 */
533 
534 {
535     SfxDock_Impl *pDock=0;
536     sal_uInt16 nCount = pDockArr->Count();
537     sal_Bool bFound = sal_False;
538     for ( sal_uInt16 n=0; n<nCount; n++ )
539     {
540         pDock = (*pDockArr)[n];
541         if ( pDock->nType == pDockWin->GetType() )
542         {
543             if ( pDock->bNewLine && n<nCount-1 )
544                 (*pDockArr)[n+1]->bNewLine = sal_True;
545 
546             // Fenster hat schon eine Position, die vergessen wir
547             bFound = sal_True;
548             pDockArr->Remove(n);
549             break;
550         }
551     }
552 
553     if ( bFound )
554         delete pDock;
555 
556     if ( bSave )
557         SaveConfig_Impl();
558 }
559 
560 //-------------------------------------------------------------------------
561 
562 void SfxSplitWindow::MoveWindow( SfxDockingWindow* pDockWin, const Size& rSize,
563                         sal_uInt16 nLine, sal_uInt16 nPos, sal_Bool bNewLine)
564 
565 /*  [Beschreibung]
566 
567     Das DockingWindow wird innerhalb des Splitwindows verschoben.
568 
569 */
570 
571 {
572     sal_uInt16 nL, nP;
573     GetWindowPos( pDockWin, nL, nP );
574 
575     if ( nLine > nL && GetItemCount( GetItemId( nL, 0 ) ) == 1 )
576     {
577         // Wenn das letzte Fenster aus seiner Zeile entfernt wird, rutscht
578         // alles eine Zeile nach vorne!
579         nLine--;
580     }
581 /*
582     else if ( nLine == nL && nPos > nP )
583     {
584         nPos--;
585     }
586 */
587     RemoveWindow( pDockWin );
588     InsertWindow( pDockWin, rSize, nLine, nPos, bNewLine );
589 }
590 
591 //-------------------------------------------------------------------------
592 
593 void SfxSplitWindow::InsertWindow( SfxDockingWindow* pDockWin, const Size& rSize,
594                         sal_uInt16 nLine, sal_uInt16 nPos, sal_Bool bNewLine)
595 
596 /*  [Beschreibung]
597 
598     Das DockingWindow wird in dieses Splitwindow geschoben und soll die
599     "ubergebene Position und Gr"o\se haben.
600 
601 */
602 {
603     ReleaseWindow_Impl( pDockWin, sal_False );
604     SfxDock_Impl *pDock = new SfxDock_Impl;
605     pDock->bHide = sal_False;
606     pDock->nType = pDockWin->GetType();
607     pDock->bNewLine = bNewLine;
608     pDock->pWin = pDockWin;
609 
610     DBG_ASSERT( nPos==0 || !bNewLine, "Falsche Paramenter!");
611     if ( bNewLine )
612         nPos = 0;
613 
614     // Das Fenster mu\s vor dem ersten Fenster eingef"ugt werden, das die
615     // gleiche oder eine gr"o\sere Position hat als pDockWin.
616     sal_uInt16 nCount = pDockArr->Count();
617 
618     // Wenn gar kein Fenster gefunden wird, wird als erstes eingef"ugt
619     sal_uInt16 nInsertPos = 0;
620     for ( sal_uInt16 n=0; n<nCount; n++ )
621     {
622         SfxDock_Impl *pD = (*pDockArr)[n];
623 
624         if (pD->pWin)
625         {
626             // Ein angedocktes Fenster wurde gefunden
627             // Wenn kein geeignetes Fenster hinter der gew"unschten Einf"ugeposition
628             // gefunden wird, wird am Ende eingef"ugt
629             nInsertPos = nCount;
630             sal_uInt16 nL=0, nP=0;
631             GetWindowPos( pD->pWin, nL, nP );
632 
633             if ( (nL == nLine && nP == nPos) || nL > nLine )
634             {
635                 DBG_ASSERT( nL == nLine || bNewLine || nPos > 0, "Falsche Parameter!" );
636                 if ( nL == nLine && nPos == 0 && !bNewLine )
637                 {
638                     DBG_ASSERT(pD->bNewLine, "Keine neue Zeile?");
639 
640                     // Das Fenster wird auf nPos==0 eingeschoben
641                     pD->bNewLine = sal_False;
642                     pDock->bNewLine = sal_True;
643                 }
644 
645                 nInsertPos = n;
646                 break;
647             }
648         }
649     }
650 
651     pDockArr->Insert(pDock, nInsertPos);
652     InsertWindow_Impl( pDock, rSize, nLine, nPos, bNewLine );
653     SaveConfig_Impl();
654 }
655 
656 //-------------------------------------------------------------------------
657 
658 void SfxSplitWindow::InsertWindow_Impl( SfxDock_Impl* pDock,
659                         const Size& rSize,
660                         sal_uInt16 nLine, sal_uInt16 nPos, sal_Bool bNewLine)
661 
662 /*  [Beschreibung]
663 
664     F"ugt ein DockingWindow ein und veranla\st die Neuberechnung der Gr"o\se
665     des Splitwindows.
666 */
667 
668 {
669     SfxDockingWindow* pDockWin = pDock->pWin;
670 
671     sal_uInt16 nItemBits = pDockWin->GetWinBits_Impl();
672 
673     long nWinSize, nSetSize;
674     if ( IsHorizontal() )
675     {
676         nWinSize = rSize.Width();
677         nSetSize = rSize.Height();
678     }
679     else
680     {
681         nSetSize = rSize.Width();
682         nWinSize = rSize.Height();
683     }
684 
685     pDock->nSize = nWinSize;
686 
687     sal_Bool bUpdateMode = IsUpdateMode();
688     if ( bUpdateMode )
689         SetUpdateMode( sal_False );
690 
691     if ( bNewLine || nLine == GetItemCount( 0 ) )
692     {
693         // Es soll nicht in eine vorhandene Zeile eingef"ugt werden, sondern
694         // eine neue erzeugt werden
695 
696         sal_uInt16 nId = 1;
697         for ( sal_uInt16 n=0; n<GetItemCount(0); n++ )
698         {
699             if ( GetItemId(n) >= nId )
700                 nId = GetItemId(n)+1;
701         }
702 
703         // Eine neue nLine-te Zeile erzeugen
704         sal_uInt16 nBits = nItemBits;
705         if ( GetAlign() == WINDOWALIGN_TOP || GetAlign() == WINDOWALIGN_BOTTOM )
706             nBits |= SWIB_COLSET;
707         InsertItem( nId, nSetSize, nLine, 0, nBits );
708     }
709 
710     // In Zeile mit Position nLine das Fenster einf"ugen
711     // ItemWindowSize auf "Prozentual" setzen, da SV dann das Umgr"o\sern
712     // so macht, wie man erwartet; "Pixel" macht eigentlich nur Sinn, wenn
713     // auch Items mit prozentualen oder relativen Gr"o\sen dabei sind.
714     nItemBits |= SWIB_PERCENTSIZE;
715     bLocked = sal_True;
716     sal_uInt16 nSet = GetItemId( nLine );
717     InsertItem( pDockWin->GetType(), pDockWin, nWinSize, nPos, nSet, nItemBits );
718 
719     // Splitwindows werden im SFX einmal angelegt und beim Einf"ugen des ersten
720     // DockingWindows sichtbar gemacht.
721     if ( GetItemCount( 0 ) == 1 && GetItemCount( 1 ) == 1 )
722     {
723         // Das Neuarrangieren am WorkWindow und ein Show() auf das SplitWindow
724         // wird vom SfxDockingwindow veranla\st (->SfxWorkWindow::ConfigChild_Impl)
725         if ( !bPinned && !IsFloatingMode() )
726         {
727             bPinned = sal_True;
728             sal_Bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
729             pEmptyWin->bFadeIn = sal_False;
730             SetPinned_Impl( sal_False );
731             pEmptyWin->Actualize();
732             DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
733             pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign, sal_True )->nVisible = CHILD_VISIBLE;
734             pWorkWin->ArrangeChilds_Impl();
735             if ( bFadeIn )
736                 FadeIn();
737         }
738         else
739         {
740             sal_Bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
741             pEmptyWin->bFadeIn = sal_False;
742             pEmptyWin->Actualize();
743 #ifdef DBG_UTIL
744             if ( !bPinned || !pEmptyWin->bFadeIn )
745             {
746                 DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
747             }
748             else
749             {
750                 DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering real Splitwindow" );
751             }
752 #endif
753             pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign, sal_True )->nVisible = CHILD_VISIBLE;
754             pWorkWin->ArrangeChilds_Impl();
755             if ( bFadeIn )
756                 FadeIn();
757         }
758 
759         pWorkWin->ShowChilds_Impl();
760     }
761 
762     if ( bUpdateMode )
763         SetUpdateMode( sal_True );
764     bLocked = sal_False;
765 }
766 
767 //-------------------------------------------------------------------------
768 
769 void SfxSplitWindow::RemoveWindow( SfxDockingWindow* pDockWin, sal_Bool bHide )
770 
771 /*  [Beschreibung]
772 
773     Entfernt ein DockingWindow. Wenn es das letzte war, wird das SplitWindow
774     gehidet.
775 */
776 {
777     sal_uInt16 nSet = GetSet( pDockWin->GetType() );
778 
779     // Splitwindows werden im SFX einmal angelegt und nach dem Entfernen
780     // des letzten DockingWindows unsichtbar gemacht.
781     if ( GetItemCount( nSet ) == 1 && GetItemCount( 0 ) == 1 )
782     {
783         // Das Neuarrangieren am WorkWindow wird vom SfxDockingwindow
784         // veranla\st!
785         Hide();
786         pEmptyWin->aTimer.Stop();
787         sal_uInt16 nRealState = pEmptyWin->nState;
788         FadeOut_Impl();
789         pEmptyWin->Hide();
790 #ifdef DBG_UTIL
791         if ( !bPinned || !pEmptyWin->bFadeIn )
792         {
793             DBG_TRACE( "SfxSplitWindow::RemoveWindow - releasing empty Splitwindow" );
794         }
795         else
796         {
797             DBG_TRACE( "SfxSplitWindow::RemoveWindow - releasing real Splitwindow" );
798         }
799 #endif
800         pWorkWin->ReleaseChild_Impl( *GetSplitWindow() );
801         pEmptyWin->nState = nRealState;
802         pWorkWin->ArrangeAutoHideWindows( this );
803     }
804 
805     SfxDock_Impl *pDock=0;
806     sal_uInt16 nCount = pDockArr->Count();
807     for ( sal_uInt16 n=0; n<nCount; n++ )
808     {
809         pDock = (*pDockArr)[n];
810         if ( pDock->nType == pDockWin->GetType() )
811         {
812             pDock->pWin = 0;
813             pDock->bHide = bHide;
814             break;
815         }
816     }
817 
818     // Fenster removen, und wenn es das letzte der Zeile war, auch die Zeile
819     // ( Zeile = ItemSet )
820     sal_Bool bUpdateMode = IsUpdateMode();
821     if ( bUpdateMode )
822         SetUpdateMode( sal_False );
823     bLocked = sal_True;
824 
825     RemoveItem( pDockWin->GetType() );
826 
827     if ( nSet && !GetItemCount( nSet ) )
828         RemoveItem( nSet );
829 
830     if ( bUpdateMode )
831         SetUpdateMode( sal_True );
832     bLocked = sal_False;
833 };
834 
835 //-------------------------------------------------------------------------
836 
837 sal_Bool SfxSplitWindow::GetWindowPos( const SfxDockingWindow* pWindow,
838                                         sal_uInt16& rLine, sal_uInt16& rPos ) const
839 /*  [Beschreibung]
840 
841     Liefert die Id des Itemsets und die des Items f"ur das "ubergebene
842     DockingWindow in der alten Zeilen/Spalten-Bezeichnung zur"uck.
843 */
844 
845 {
846     sal_uInt16 nSet = GetSet ( pWindow->GetType() );
847     if ( nSet == SPLITWINDOW_ITEM_NOTFOUND )
848         return sal_False;
849 
850     rPos  = GetItemPos( pWindow->GetType(), nSet );
851     rLine = GetItemPos( nSet );
852     return sal_True;
853 }
854 
855 //-------------------------------------------------------------------------
856 
857 sal_Bool SfxSplitWindow::GetWindowPos( const Point& rTestPos,
858                                       sal_uInt16& rLine, sal_uInt16& rPos ) const
859 /*  [Beschreibung]
860 
861     Liefert die Id des Itemsets und die des Items f"ur das DockingWindow
862     an der "ubergebenen Position in der alten Zeilen/Spalten-Bezeichnung
863     zur"uck.
864 */
865 
866 {
867     sal_uInt16 nId = GetItemId( rTestPos );
868     if ( nId == 0 )
869         return sal_False;
870 
871     sal_uInt16 nSet = GetSet ( nId );
872     rPos  = GetItemPos( nId, nSet );
873     rLine = GetItemPos( nSet );
874     return sal_True;
875 }
876 
877 //-------------------------------------------------------------------------
878 
879 sal_uInt16 SfxSplitWindow::GetLineCount() const
880 
881 /*  [Beschreibung]
882 
883     Liefert die Zeilenzahl = Zahl der Sub-Itemsets im Root-Set.
884 */
885 {
886     return GetItemCount( 0 );
887 }
888 
889 //-------------------------------------------------------------------------
890 
891 long SfxSplitWindow::GetLineSize( sal_uInt16 nLine ) const
892 
893 /*  [Beschreibung]
894 
895     Liefert die "Zeilenh"ohe" des nLine-ten Itemsets.
896 */
897 {
898     sal_uInt16 nId = GetItemId( nLine );
899     return GetItemSize( nId );
900 }
901 
902 //-------------------------------------------------------------------------
903 
904 sal_uInt16 SfxSplitWindow::GetWindowCount( sal_uInt16 nLine ) const
905 
906 /*  [Beschreibung]
907 
908     Liefert die
909 */
910 {
911     sal_uInt16 nId = GetItemId( nLine );
912     return GetItemCount( nId );
913 }
914 
915 //-------------------------------------------------------------------------
916 
917 sal_uInt16 SfxSplitWindow::GetWindowCount() const
918 
919 /*  [Beschreibung]
920 
921     Liefert die Gesamtzahl aller Fenstert
922 */
923 {
924     return GetItemCount( 0 );
925 }
926 
927 //-------------------------------------------------------------------------
928 
929 void SfxSplitWindow::Command( const CommandEvent& rCEvt )
930 {
931     SplitWindow::Command( rCEvt );
932 }
933 
934 //-------------------------------------------------------------------------
935 
936 IMPL_LINK( SfxSplitWindow, TimerHdl, Timer*, pTimer)
937 {
938     if ( pTimer )
939         pTimer->Stop();
940 
941     if ( CursorIsOverRect( sal_False ) || !pTimer )
942     {
943         // Wenn der Mauszeiger innerhalb des Fensters liegt, SplitWindow anzeigen
944         // und Timer zum Schlie\sen aufsetzen
945         pEmptyWin->bAutoHide = sal_True;
946         if ( !IsVisible() )
947             pEmptyWin->FadeIn();
948 
949         pEmptyWin->aLastPos = GetPointerPosPixel();
950         pEmptyWin->aTimer.Start();
951     }
952     else if ( pEmptyWin->bAutoHide )
953     {
954         if ( GetPointerPosPixel() != pEmptyWin->aLastPos )
955         {
956             // Die Maus wurd innerhalb der Timerlaugzeit bewegt, also erst einmal
957             // nichts tun
958             pEmptyWin->aLastPos = GetPointerPosPixel();
959             pEmptyWin->aTimer.Start();
960             return 0L;
961         }
962 
963         // Speziell f"ur TF_AUTOSHOW_ON_MOUSEMOVE :
964         // Wenn das Fenster nicht sichtbar ist, gibt es nichts zu tun
965         // (Benutzer ist einfach mit der Maus "uber pEmptyWin gefahren)
966         if ( IsVisible() )
967         {
968             pEmptyWin->bEndAutoHide = sal_False;
969             if ( !Application::IsInModalMode() &&
970                   !PopupMenu::IsInExecute() &&
971                   !pEmptyWin->bSplit && !HasChildPathFocus( sal_True ) )
972             {
973                 // W"ahrend ein modaler Dialog oder ein Popupmenu offen sind
974                 // oder w"ahrend des Splittens auf keinen Fall zumachen; auch
975                 // solange eines der Children den Focus hat, bleibt das
976                 // das Fenster offen
977                 pEmptyWin->bEndAutoHide = sal_True;
978             }
979 
980             if ( pEmptyWin->bEndAutoHide )
981             {
982                 // Von mir aus kann Schlu\s sein mit AutoShow
983                 // Aber vielleicht will noch ein anderes SfxSplitWindow offen bleiben,
984                 // dann bleiben auch alle anderen offen
985                 if ( !pWorkWin->IsAutoHideMode( this ) )
986                 {
987                     FadeOut_Impl();
988                     pWorkWin->ArrangeAutoHideWindows( this );
989                 }
990                 else
991                 {
992                     pEmptyWin->aLastPos = GetPointerPosPixel();
993                     pEmptyWin->aTimer.Start();
994                 }
995             }
996             else
997             {
998                 pEmptyWin->aLastPos = GetPointerPosPixel();
999                 pEmptyWin->aTimer.Start();
1000             }
1001         }
1002     }
1003 
1004     return 0L;
1005 }
1006 
1007 //-------------------------------------------------------------------------
1008 
1009 sal_Bool SfxSplitWindow::CursorIsOverRect( sal_Bool bForceAdding ) const
1010 {
1011     sal_Bool bVisible = IsVisible();
1012 
1013     // Auch das kollabierte SplitWindow ber"ucksichtigen
1014     Point aPos = pEmptyWin->GetParent()->OutputToScreenPixel( pEmptyWin->GetPosPixel() );
1015     Size aSize = pEmptyWin->GetSizePixel();
1016 
1017     if ( bForceAdding )
1018     {
1019         // Um +/- ein paar Pixel erweitern, sonst ist es zu nerv"os
1020         aPos.X() -= nPixel;
1021         aPos.Y() -= nPixel;
1022         aSize.Width() += 2 * nPixel;
1023         aSize.Height() += 2 * nPixel;
1024     }
1025 
1026     Rectangle aRect( aPos, aSize );
1027 
1028     if ( bVisible )
1029     {
1030         Point aVisPos = GetPosPixel();
1031         Size aVisSize = GetSizePixel();
1032 
1033         // Um +/- ein paar Pixel erweitern, sonst ist es zu nerv"os
1034         aVisPos.X() -= nPixel;
1035         aVisPos.Y() -= nPixel;
1036         aVisSize.Width() += 2 * nPixel;
1037         aVisSize.Height() += 2 * nPixel;
1038 
1039         Rectangle aVisRect( aVisPos, aVisSize );
1040         aRect = aRect.GetUnion( aVisRect );
1041     }
1042 
1043     if ( aRect.IsInside( OutputToScreenPixel( ((Window*)this)->GetPointerPosPixel() ) ) )
1044         return sal_True;
1045     return sal_False;
1046 }
1047 
1048 //-------------------------------------------------------------------------
1049 
1050 SplitWindow* SfxSplitWindow::GetSplitWindow()
1051 {
1052     if ( !bPinned || !pEmptyWin->bFadeIn )
1053         return pEmptyWin;
1054     return this;
1055 }
1056 
1057 //-------------------------------------------------------------------------
1058 sal_Bool SfxSplitWindow::IsFadeIn() const
1059 {
1060     return pEmptyWin->bFadeIn;
1061 }
1062 
1063 sal_Bool SfxSplitWindow::IsAutoHide( sal_Bool bSelf ) const
1064 {
1065     return bSelf ? pEmptyWin->bAutoHide && !pEmptyWin->bEndAutoHide : pEmptyWin->bAutoHide;
1066 }
1067 
1068 //-------------------------------------------------------------------------
1069 
1070 void SfxSplitWindow::SetPinned_Impl( sal_Bool bOn )
1071 {
1072     if ( bPinned == bOn )
1073         return;
1074 
1075     bPinned = bOn;
1076     if ( GetItemCount( 0 ) == 0 )
1077         return;
1078 
1079     if ( !bOn )
1080     {
1081         pEmptyWin->nState |= 1;
1082         if ( pEmptyWin->bFadeIn )
1083         {
1084             // Ersatzfenster anmelden
1085             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - releasing real Splitwindow" );
1086             pWorkWin->ReleaseChild_Impl( *this );
1087             Hide();
1088             pEmptyWin->Actualize();
1089             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - registering empty Splitwindow" );
1090             pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1091         }
1092 
1093         Point aPos( GetPosPixel() );
1094         aPos = GetParent()->OutputToScreenPixel( aPos );
1095         SetFloatingPos( aPos );
1096         SetFloatingMode( sal_True );
1097         GetFloatingWindow()->SetOutputSizePixel( GetOutputSizePixel() );
1098 
1099         if ( pEmptyWin->bFadeIn )
1100             Show();
1101     }
1102     else
1103     {
1104         pEmptyWin->nState &= ~1;
1105         SetOutputSizePixel( GetFloatingWindow()->GetOutputSizePixel() );
1106         SetFloatingMode( sal_False );
1107 
1108         if ( pEmptyWin->bFadeIn )
1109         {
1110             // Ersatzfenster abmelden
1111             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - releasing empty Splitwindow" );
1112             pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1113             pEmptyWin->Hide();
1114             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - registering real Splitwindow" );
1115             pWorkWin->RegisterChild_Impl( *this, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1116         }
1117     }
1118 
1119     SetAutoHideState( !bPinned );
1120     pEmptyWin->SetAutoHideState( !bPinned );
1121 }
1122 
1123 //-------------------------------------------------------------------------
1124 
1125 void SfxSplitWindow::SetFadeIn_Impl( sal_Bool bOn )
1126 {
1127     if ( bOn == pEmptyWin->bFadeIn )
1128         return;
1129 
1130     if ( GetItemCount( 0 ) == 0 )
1131         return;
1132 
1133     pEmptyWin->bFadeIn = bOn;
1134     if ( bOn )
1135     {
1136         pEmptyWin->nState |= 2;
1137         if ( IsFloatingMode() )
1138         {
1139             // FloatingWindow ist nicht sichtbar, also anzeigen
1140             pWorkWin->ArrangeAutoHideWindows( this );
1141             Show();
1142         }
1143         else
1144         {
1145             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - releasing empty Splitwindow" );
1146             pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1147             pEmptyWin->Hide();
1148             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - registering real Splitwindow" );
1149             pWorkWin->RegisterChild_Impl( *this, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1150             pWorkWin->ArrangeChilds_Impl();
1151             pWorkWin->ShowChilds_Impl();
1152         }
1153     }
1154     else
1155     {
1156         pEmptyWin->bAutoHide = sal_False;
1157         pEmptyWin->nState &= ~2;
1158         if ( !IsFloatingMode() )
1159         {
1160             // Das Fenster "schwebt" nicht, soll aber ausgeblendet werden,
1161             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - releasing real Splitwindow" );
1162             pWorkWin->ReleaseChild_Impl( *this );
1163             Hide();
1164             pEmptyWin->Actualize();
1165             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - registering empty Splitwindow" );
1166             pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1167             pWorkWin->ArrangeChilds_Impl();
1168             pWorkWin->ShowChilds_Impl();
1169             pWorkWin->ArrangeAutoHideWindows( this );
1170         }
1171         else
1172         {
1173             Hide();
1174             pWorkWin->ArrangeAutoHideWindows( this );
1175         }
1176     }
1177 }
1178 
1179 void SfxSplitWindow::AutoHide()
1180 {
1181     // Wenn dieser Handler am "echten" SplitWindow aufgerufen wird, ist es
1182     // entweder angedockt und soll "schwebend" angezeigt werden oder umgekehrt
1183     if ( !bPinned )
1184     {
1185         // Es "schwebt", also wieder andocken
1186         SetPinned_Impl( sal_True );
1187         pWorkWin->ArrangeChilds_Impl();
1188     }
1189     else
1190     {
1191         // In den "Schwebezustand" bringen
1192         SetPinned_Impl( sal_False );
1193         pWorkWin->ArrangeChilds_Impl();
1194         pWorkWin->ArrangeAutoHideWindows( this );
1195     }
1196 
1197     pWorkWin->ShowChilds_Impl();
1198     SaveConfig_Impl();
1199 }
1200 
1201 void SfxSplitWindow::FadeOut_Impl()
1202 {
1203     if ( pEmptyWin->aTimer.IsActive() )
1204     {
1205         pEmptyWin->bAutoHide = sal_False;
1206         pEmptyWin->aTimer.Stop();
1207     }
1208 
1209     SetFadeIn_Impl( sal_False );
1210     Show_Impl();
1211 }
1212 
1213 void SfxSplitWindow::FadeOut()
1214 {
1215     FadeOut_Impl();
1216     SaveConfig_Impl();
1217 }
1218 
1219 void SfxSplitWindow::FadeIn()
1220 {
1221     SetFadeIn_Impl( sal_True );
1222     Show_Impl();
1223 }
1224 
1225 void SfxSplitWindow::Show_Impl()
1226 {
1227     sal_uInt16 nCount = pDockArr->Count();
1228     for ( sal_uInt16 n=0; n<nCount; n++ )
1229     {
1230         SfxDock_Impl *pDock = (*pDockArr)[n];
1231         if ( pDock->pWin )
1232             pDock->pWin->FadeIn( pEmptyWin->bFadeIn );
1233     }
1234 }
1235 /*
1236 void SfxSplitWindow::Pin_Impl( sal_Bool bPin )
1237 {
1238     if ( bPinned != bPin )
1239         AutoHide();
1240 }
1241 */
1242 sal_Bool SfxSplitWindow::ActivateNextChild_Impl( sal_Bool bForward )
1243 {
1244     // Wenn kein pActive, auf erstes bzw. letztes Fenster gehen ( bei !bForward wird erst in der loop dekrementiert )
1245     sal_uInt16 nCount = pDockArr->Count();
1246     sal_uInt16 n = bForward ? 0 : nCount;
1247 
1248     // Wenn Focus innerhalb, dann ein Fenster vor oder zur"uck, wenn m"oglich
1249     if ( pActive )
1250     {
1251         // Aktives Fenster ermitteln
1252         for ( n=0; n<nCount; n++ )
1253         {
1254             SfxDock_Impl *pD = (*pDockArr)[n];
1255             if ( pD->pWin && pD->pWin->HasChildPathFocus() )
1256                 break;
1257         }
1258 
1259         if ( bForward )
1260             // ein Fenster weiter ( wenn dann n>nCount, wird die Schleife unten gar nicht durchlaufen )
1261             n++;
1262     }
1263 
1264     if ( bForward )
1265     {
1266         // N"achstes Fenster suchen
1267         for ( sal_uInt16 nNext=n; nNext<nCount; nNext++ )
1268         {
1269             SfxDock_Impl *pD = (*pDockArr)[nNext];
1270             if ( pD->pWin )
1271             {
1272                 pD->pWin->GrabFocus();
1273                 return sal_True;
1274             }
1275         }
1276     }
1277     else
1278     {
1279         // Vorheriges Fenster suchen
1280         for ( sal_uInt16 nNext=n; nNext--; )
1281         {
1282             SfxDock_Impl *pD = (*pDockArr)[nNext];
1283             if ( pD->pWin )
1284             {
1285                 pD->pWin->GrabFocus();
1286                 return sal_True;
1287             }
1288         }
1289     }
1290 
1291     return sal_False;
1292 }
1293 
1294 void SfxSplitWindow::SetActiveWindow_Impl( SfxDockingWindow* pWin )
1295 {
1296     pActive = pWin;
1297     pWorkWin->SetActiveChild_Impl( this );
1298 }
1299 
1300 
1301