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