xref: /trunk/main/sfx2/source/dialog/splitwin.cxx (revision 61dff127b6698e0bae836c8aedd6ec62111483d1)
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;           // This window has SplitWindow
69     sal_Bool                bNewLine;
70     sal_Bool                bHide;          // SplitWindow had this window
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     SfxEmptySplitWin_Impldow is an empty split window replacing the SfxSplitWindow
83     in AutoHide mode. It works as a placeholder to receive mouse MouseMoves.
84     the actual light split window display
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         // Put timer to close; the caller must make sure it is,
162         // that the window does not stay or leave ( z.B. by setting the
163         // Focus mode or modal )
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     To insert SfxDockingWindows with no position can also be transfered.
442     The SfxSplitWindow then searches out the noted recently transfered
443     to the newly SfxDockingWindow or it depends on the last.
444 
445 */
446 {
447     short nLine = -1;       // so first window can be set to 0 nLine high
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             // The window opens a new line
460             if ( pFoundDock )
461                 // But behind the window just inserted
462                 break;
463 
464             // new line
465             nPos = 0;
466             bNewLine = sal_True;
467         }
468 
469         if ( pDock->pWin )
470         {
471             // It is at this point just a window
472             if ( bNewLine && !pFoundDock )
473             {
474                 // It is not known, in which real line is the one
475                 GetWindowPos( pDock->pWin, nL, nPos );
476                 nLine = (short) nL;
477             }
478 
479             if ( !pFoundDock )
480             {
481                 // before the window is attached
482                 nPos++;
483             }
484 
485             // Line is now open
486             bNewLine = sal_False;
487             if ( pFoundDock )
488                 break;
489         }
490 
491         if ( pDock->nType == pDockWin->GetType() )
492         {
493             DBG_ASSERT( !pFoundDock && !pDock->pWin, "Window is already available!");
494             pFoundDock = pDock;
495             if ( !bNewLine )
496                 break;
497             else
498             {
499                 // It was most recently a new series started, but not found a
500                 // window above it, so keep looking if nochein window follows
501                 // this line to bNewLine to set correctly. But it must be nLine
502                 // or nPos shouldn't be changed.
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     The DockinWindow is no longer stored in the  internal data.
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, "Wrong Parameter!");
615     if ( bNewLine )
616         nPos = 0;
617 
618     // The window introduced before the first window are suffices that the
619     // body or a greater position as the pDockWin.
620     sal_uInt16 nCount = pDockArr->Count();
621     sal_uInt16 nLastWindowIdx(0);
622 
623     // If window not found, is inserted as the first
624     sal_uInt16 nInsertPos = 0;
625     for ( sal_uInt16 n=0; n<nCount; n++ )
626     {
627         SfxDock_Impl *pD = (*pDockArr)[n];
628 
629         if (pD->pWin)
630         {
631             // Ein angedocktes Fenster wurde gefunden
632             // Wenn kein geeignetes Fenster hinter der gew"unschten Einf"ugeposition
633             // gefunden wird, wird am Ende eingef"ugt
634             nInsertPos = nCount;
635             nLastWindowIdx = n;
636             sal_uInt16 nL=0, nP=0;
637             GetWindowPos( pD->pWin, nL, nP );
638 
639             if ( (nL == nLine && nP == nPos) || nL > nLine )
640             {
641                 DBG_ASSERT( nL == nLine || bNewLine || nPos > 0, "Wrong Parameter!" );
642                 if ( nL == nLine && nPos == 0 && !bNewLine )
643                 {
644                     DBG_ASSERT(pD->bNewLine, "No new line?");
645 
646                     // Das Fenster wird auf nPos==0 eingeschoben
647                     pD->bNewLine = sal_False;
648                     pDock->bNewLine = sal_True;
649                 }
650 
651                 nInsertPos = n != 0 ? nLastWindowIdx + 1 : 0;    // ignore all non-windows after the last window
652                 break;
653             }
654         }
655     }
656     if (nInsertPos == nCount && nLastWindowIdx != nCount - 1)
657     {
658         nInsertPos = nLastWindowIdx + 1;    // ignore all non-windows after the last window
659     }
660 
661     pDockArr->Insert(pDock, nInsertPos);
662     InsertWindow_Impl( pDock, rSize, nLine, nPos, bNewLine );
663     SaveConfig_Impl();
664 }
665 
666 //-------------------------------------------------------------------------
667 
668 void SfxSplitWindow::InsertWindow_Impl( SfxDock_Impl* pDock,
669                         const Size& rSize,
670                         sal_uInt16 nLine, sal_uInt16 nPos, sal_Bool bNewLine)
671 
672 /*  [Beschreibung]
673 
674     F"ugt ein DockingWindow ein und veranla\st die Neuberechnung der Gr"o\se
675     des Splitwindows.
676 */
677 
678 {
679     SfxDockingWindow* pDockWin = pDock->pWin;
680 
681     sal_uInt16 nItemBits = pDockWin->GetWinBits_Impl();
682 
683     long nWinSize, nSetSize;
684     if ( IsHorizontal() )
685     {
686         nWinSize = rSize.Width();
687         nSetSize = rSize.Height();
688     }
689     else
690     {
691         nSetSize = rSize.Width();
692         nWinSize = rSize.Height();
693     }
694 
695     pDock->nSize = nWinSize;
696 
697     sal_Bool bUpdateMode = IsUpdateMode();
698     if ( bUpdateMode )
699         SetUpdateMode( sal_False );
700 
701     if ( bNewLine || nLine == GetItemCount( 0 ) )
702     {
703         // Es soll nicht in eine vorhandene Zeile eingef"ugt werden, sondern
704         // eine neue erzeugt werden
705 
706         sal_uInt16 nId = 1;
707         for ( sal_uInt16 n=0; n<GetItemCount(0); n++ )
708         {
709             if ( GetItemId(n) >= nId )
710                 nId = GetItemId(n)+1;
711         }
712 
713         // Eine neue nLine-te Zeile erzeugen
714         sal_uInt16 nBits = nItemBits;
715         if ( GetAlign() == WINDOWALIGN_TOP || GetAlign() == WINDOWALIGN_BOTTOM )
716             nBits |= SWIB_COLSET;
717         InsertItem( nId, nSetSize, nLine, 0, nBits );
718     }
719 
720     // In Zeile mit Position nLine das Fenster einf"ugen
721     // ItemWindowSize auf "Prozentual" setzen, da SV dann das Umgr"o\sern
722     // so macht, wie man erwartet; "Pixel" macht eigentlich nur Sinn, wenn
723     // auch Items mit prozentualen oder relativen Gr"o\sen dabei sind.
724     nItemBits |= SWIB_PERCENTSIZE;
725     bLocked = sal_True;
726     sal_uInt16 nSet = GetItemId( nLine );
727     InsertItem( pDockWin->GetType(), pDockWin, nWinSize, nPos, nSet, nItemBits );
728 
729     // Splitwindows werden im SFX einmal angelegt und beim Einf"ugen des ersten
730     // DockingWindows sichtbar gemacht.
731     if ( GetItemCount( 0 ) == 1 && GetItemCount( 1 ) == 1 )
732     {
733         // Das Neuarrangieren am WorkWindow und ein Show() auf das SplitWindow
734         // wird vom SfxDockingwindow veranla\st (->SfxWorkWindow::ConfigChild_Impl)
735         if ( !bPinned && !IsFloatingMode() )
736         {
737             bPinned = sal_True;
738             sal_Bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
739             pEmptyWin->bFadeIn = sal_False;
740             SetPinned_Impl( sal_False );
741             pEmptyWin->Actualize();
742             DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
743             pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign, sal_True )->nVisible = CHILD_VISIBLE;
744             pWorkWin->ArrangeChilds_Impl();
745             if ( bFadeIn )
746                 FadeIn();
747         }
748         else
749         {
750             sal_Bool bFadeIn = ( pEmptyWin->nState & 2 ) != 0;
751             pEmptyWin->bFadeIn = sal_False;
752             pEmptyWin->Actualize();
753 #ifdef DBG_UTIL
754             if ( !bPinned || !pEmptyWin->bFadeIn )
755             {
756                 DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering empty Splitwindow" );
757             }
758             else
759             {
760                 DBG_TRACE( "SfxSplitWindow::InsertWindow_Impl - registering real Splitwindow" );
761             }
762 #endif
763             pWorkWin->RegisterChild_Impl( *GetSplitWindow(), eAlign, sal_True )->nVisible = CHILD_VISIBLE;
764             pWorkWin->ArrangeChilds_Impl();
765             if ( bFadeIn )
766                 FadeIn();
767         }
768 
769         pWorkWin->ShowChilds_Impl();
770     }
771 
772     if ( bUpdateMode )
773         SetUpdateMode( sal_True );
774     bLocked = sal_False;
775 }
776 
777 //-------------------------------------------------------------------------
778 
779 void SfxSplitWindow::RemoveWindow( SfxDockingWindow* pDockWin, sal_Bool bHide )
780 
781 /*  [Beschreibung]
782 
783     Entfernt ein DockingWindow. Wenn es das letzte war, wird das SplitWindow
784     gehidet.
785 */
786 {
787     sal_uInt16 nSet = GetSet( pDockWin->GetType() );
788 
789     // Splitwindows werden im SFX einmal angelegt und nach dem Entfernen
790     // des letzten DockingWindows unsichtbar gemacht.
791     if ( GetItemCount( nSet ) == 1 && GetItemCount( 0 ) == 1 )
792     {
793         // Das Neuarrangieren am WorkWindow wird vom SfxDockingwindow
794         // veranla\st!
795         Hide();
796         pEmptyWin->aTimer.Stop();
797         sal_uInt16 nRealState = pEmptyWin->nState;
798         FadeOut_Impl();
799         pEmptyWin->Hide();
800 #ifdef DBG_UTIL
801         if ( !bPinned || !pEmptyWin->bFadeIn )
802         {
803             DBG_TRACE( "SfxSplitWindow::RemoveWindow - releasing empty Splitwindow" );
804         }
805         else
806         {
807             DBG_TRACE( "SfxSplitWindow::RemoveWindow - releasing real Splitwindow" );
808         }
809 #endif
810         pWorkWin->ReleaseChild_Impl( *GetSplitWindow() );
811         pEmptyWin->nState = nRealState;
812         pWorkWin->ArrangeAutoHideWindows( this );
813     }
814 
815     SfxDock_Impl *pDock=0;
816     sal_uInt16 nCount = pDockArr->Count();
817     for ( sal_uInt16 n=0; n<nCount; n++ )
818     {
819         pDock = (*pDockArr)[n];
820         if ( pDock->nType == pDockWin->GetType() )
821         {
822             pDock->pWin = 0;
823             pDock->bHide = bHide;
824             break;
825         }
826     }
827 
828     // Fenster removen, und wenn es das letzte der Zeile war, auch die Zeile
829     // ( Zeile = ItemSet )
830     sal_Bool bUpdateMode = IsUpdateMode();
831     if ( bUpdateMode )
832         SetUpdateMode( sal_False );
833     bLocked = sal_True;
834 
835     RemoveItem( pDockWin->GetType() );
836 
837     if ( nSet && !GetItemCount( nSet ) )
838         RemoveItem( nSet );
839 
840     if ( bUpdateMode )
841         SetUpdateMode( sal_True );
842     bLocked = sal_False;
843 };
844 
845 //-------------------------------------------------------------------------
846 
847 sal_Bool SfxSplitWindow::GetWindowPos( const SfxDockingWindow* pWindow,
848                                         sal_uInt16& rLine, sal_uInt16& rPos ) const
849 /*  [Beschreibung]
850 
851     Liefert die Id des Itemsets und die des Items f"ur das "ubergebene
852     DockingWindow in der alten Zeilen/Spalten-Bezeichnung zur"uck.
853 */
854 
855 {
856     sal_uInt16 nSet = GetSet ( pWindow->GetType() );
857     if ( nSet == SPLITWINDOW_ITEM_NOTFOUND )
858         return sal_False;
859 
860     rPos  = GetItemPos( pWindow->GetType(), nSet );
861     rLine = GetItemPos( nSet );
862     return sal_True;
863 }
864 
865 //-------------------------------------------------------------------------
866 
867 sal_Bool SfxSplitWindow::GetWindowPos( const Point& rTestPos,
868                                       sal_uInt16& rLine, sal_uInt16& rPos ) const
869 /*  [Beschreibung]
870 
871     Liefert die Id des Itemsets und die des Items f"ur das DockingWindow
872     an der "ubergebenen Position in der alten Zeilen/Spalten-Bezeichnung
873     zur"uck.
874 */
875 
876 {
877     sal_uInt16 nId = GetItemId( rTestPos );
878     if ( nId == 0 )
879         return sal_False;
880 
881     sal_uInt16 nSet = GetSet ( nId );
882     rPos  = GetItemPos( nId, nSet );
883     rLine = GetItemPos( nSet );
884     return sal_True;
885 }
886 
887 //-------------------------------------------------------------------------
888 
889 sal_uInt16 SfxSplitWindow::GetLineCount() const
890 
891 /*  [Beschreibung]
892 
893     Liefert die Zeilenzahl = Zahl der Sub-Itemsets im Root-Set.
894 */
895 {
896     return GetItemCount( 0 );
897 }
898 
899 //-------------------------------------------------------------------------
900 
901 long SfxSplitWindow::GetLineSize( sal_uInt16 nLine ) const
902 
903 /*  [Beschreibung]
904 
905     Liefert die "Zeilenh"ohe" des nLine-ten Itemsets.
906 */
907 {
908     sal_uInt16 nId = GetItemId( nLine );
909     return GetItemSize( nId );
910 }
911 
912 //-------------------------------------------------------------------------
913 
914 sal_uInt16 SfxSplitWindow::GetWindowCount( sal_uInt16 nLine ) const
915 
916 /*  [Beschreibung]
917 
918     Liefert die
919 */
920 {
921     sal_uInt16 nId = GetItemId( nLine );
922     return GetItemCount( nId );
923 }
924 
925 //-------------------------------------------------------------------------
926 
927 sal_uInt16 SfxSplitWindow::GetWindowCount() const
928 
929 /*  [Beschreibung]
930 
931     Liefert die Gesamtzahl aller Fenstert
932 */
933 {
934     return GetItemCount( 0 );
935 }
936 
937 //-------------------------------------------------------------------------
938 
939 void SfxSplitWindow::Command( const CommandEvent& rCEvt )
940 {
941     SplitWindow::Command( rCEvt );
942 }
943 
944 //-------------------------------------------------------------------------
945 
946 IMPL_LINK( SfxSplitWindow, TimerHdl, Timer*, pTimer)
947 {
948     if ( pTimer )
949         pTimer->Stop();
950 
951     if ( CursorIsOverRect( sal_False ) || !pTimer )
952     {
953         // Wenn der Mauszeiger innerhalb des Fensters liegt, SplitWindow anzeigen
954         // und Timer zum Schlie\sen aufsetzen
955         pEmptyWin->bAutoHide = sal_True;
956         if ( !IsVisible() )
957             pEmptyWin->FadeIn();
958 
959         pEmptyWin->aLastPos = GetPointerPosPixel();
960         pEmptyWin->aTimer.Start();
961     }
962     else if ( pEmptyWin->bAutoHide )
963     {
964         if ( GetPointerPosPixel() != pEmptyWin->aLastPos )
965         {
966             // Die Maus wurd innerhalb der Timerlaugzeit bewegt, also erst einmal
967             // nichts tun
968             pEmptyWin->aLastPos = GetPointerPosPixel();
969             pEmptyWin->aTimer.Start();
970             return 0L;
971         }
972 
973         // Speziell f"ur TF_AUTOSHOW_ON_MOUSEMOVE :
974         // Wenn das Fenster nicht sichtbar ist, gibt es nichts zu tun
975         // (Benutzer ist einfach mit der Maus "uber pEmptyWin gefahren)
976         if ( IsVisible() )
977         {
978             pEmptyWin->bEndAutoHide = sal_False;
979             if ( !Application::IsInModalMode() &&
980                   !PopupMenu::IsInExecute() &&
981                   !pEmptyWin->bSplit && !HasChildPathFocus( sal_True ) )
982             {
983                 // W"ahrend ein modaler Dialog oder ein Popupmenu offen sind
984                 // oder w"ahrend des Splittens auf keinen Fall zumachen; auch
985                 // solange eines der Children den Focus hat, bleibt das
986                 // das Fenster offen
987                 pEmptyWin->bEndAutoHide = sal_True;
988             }
989 
990             if ( pEmptyWin->bEndAutoHide )
991             {
992                 // Von mir aus kann Schlu\s sein mit AutoShow
993                 // Aber vielleicht will noch ein anderes SfxSplitWindow offen bleiben,
994                 // dann bleiben auch alle anderen offen
995                 if ( !pWorkWin->IsAutoHideMode( this ) )
996                 {
997                     FadeOut_Impl();
998                     pWorkWin->ArrangeAutoHideWindows( this );
999                 }
1000                 else
1001                 {
1002                     pEmptyWin->aLastPos = GetPointerPosPixel();
1003                     pEmptyWin->aTimer.Start();
1004                 }
1005             }
1006             else
1007             {
1008                 pEmptyWin->aLastPos = GetPointerPosPixel();
1009                 pEmptyWin->aTimer.Start();
1010             }
1011         }
1012     }
1013 
1014     return 0L;
1015 }
1016 
1017 //-------------------------------------------------------------------------
1018 
1019 sal_Bool SfxSplitWindow::CursorIsOverRect( sal_Bool bForceAdding ) const
1020 {
1021     sal_Bool bVisible = IsVisible();
1022 
1023     // Auch das kollabierte SplitWindow ber"ucksichtigen
1024     Point aPos = pEmptyWin->GetParent()->OutputToScreenPixel( pEmptyWin->GetPosPixel() );
1025     Size aSize = pEmptyWin->GetSizePixel();
1026 
1027     if ( bForceAdding )
1028     {
1029         // Um +/- ein paar Pixel erweitern, sonst ist es zu nerv"os
1030         aPos.X() -= nPixel;
1031         aPos.Y() -= nPixel;
1032         aSize.Width() += 2 * nPixel;
1033         aSize.Height() += 2 * nPixel;
1034     }
1035 
1036     Rectangle aRect( aPos, aSize );
1037 
1038     if ( bVisible )
1039     {
1040         Point aVisPos = GetPosPixel();
1041         Size aVisSize = GetSizePixel();
1042 
1043         // Um +/- ein paar Pixel erweitern, sonst ist es zu nerv"os
1044         aVisPos.X() -= nPixel;
1045         aVisPos.Y() -= nPixel;
1046         aVisSize.Width() += 2 * nPixel;
1047         aVisSize.Height() += 2 * nPixel;
1048 
1049         Rectangle aVisRect( aVisPos, aVisSize );
1050         aRect = aRect.GetUnion( aVisRect );
1051     }
1052 
1053     if ( aRect.IsInside( OutputToScreenPixel( ((Window*)this)->GetPointerPosPixel() ) ) )
1054         return sal_True;
1055     return sal_False;
1056 }
1057 
1058 //-------------------------------------------------------------------------
1059 
1060 SplitWindow* SfxSplitWindow::GetSplitWindow()
1061 {
1062     if ( !bPinned || !pEmptyWin->bFadeIn )
1063         return pEmptyWin;
1064     return this;
1065 }
1066 
1067 //-------------------------------------------------------------------------
1068 sal_Bool SfxSplitWindow::IsFadeIn() const
1069 {
1070     return pEmptyWin->bFadeIn;
1071 }
1072 
1073 sal_Bool SfxSplitWindow::IsAutoHide( sal_Bool bSelf ) const
1074 {
1075     return bSelf ? pEmptyWin->bAutoHide && !pEmptyWin->bEndAutoHide : pEmptyWin->bAutoHide;
1076 }
1077 
1078 //-------------------------------------------------------------------------
1079 
1080 void SfxSplitWindow::SetPinned_Impl( sal_Bool bOn )
1081 {
1082     if ( bPinned == bOn )
1083         return;
1084 
1085     bPinned = bOn;
1086     if ( GetItemCount( 0 ) == 0 )
1087         return;
1088 
1089     if ( !bOn )
1090     {
1091         pEmptyWin->nState |= 1;
1092         if ( pEmptyWin->bFadeIn )
1093         {
1094             // Ersatzfenster anmelden
1095             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - releasing real Splitwindow" );
1096             pWorkWin->ReleaseChild_Impl( *this );
1097             Hide();
1098             pEmptyWin->Actualize();
1099             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - registering empty Splitwindow" );
1100             pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1101         }
1102 
1103         Point aPos( GetPosPixel() );
1104         aPos = GetParent()->OutputToScreenPixel( aPos );
1105         SetFloatingPos( aPos );
1106         SetFloatingMode( sal_True );
1107         GetFloatingWindow()->SetOutputSizePixel( GetOutputSizePixel() );
1108 
1109         if ( pEmptyWin->bFadeIn )
1110             Show();
1111     }
1112     else
1113     {
1114         pEmptyWin->nState &= ~1;
1115         SetOutputSizePixel( GetFloatingWindow()->GetOutputSizePixel() );
1116         SetFloatingMode( sal_False );
1117 
1118         if ( pEmptyWin->bFadeIn )
1119         {
1120             // Ersatzfenster abmelden
1121             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - releasing empty Splitwindow" );
1122             pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1123             pEmptyWin->Hide();
1124             DBG_TRACE( "SfxSplitWindow::SetPinned_Impl - registering real Splitwindow" );
1125             pWorkWin->RegisterChild_Impl( *this, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1126         }
1127     }
1128 
1129     SetAutoHideState( !bPinned );
1130     pEmptyWin->SetAutoHideState( !bPinned );
1131 }
1132 
1133 //-------------------------------------------------------------------------
1134 
1135 void SfxSplitWindow::SetFadeIn_Impl( sal_Bool bOn )
1136 {
1137     if ( bOn == pEmptyWin->bFadeIn )
1138         return;
1139 
1140     if ( GetItemCount( 0 ) == 0 )
1141         return;
1142 
1143     pEmptyWin->bFadeIn = bOn;
1144     if ( bOn )
1145     {
1146         pEmptyWin->nState |= 2;
1147         if ( IsFloatingMode() )
1148         {
1149             // FloatingWindow ist nicht sichtbar, also anzeigen
1150             pWorkWin->ArrangeAutoHideWindows( this );
1151             Show();
1152         }
1153         else
1154         {
1155             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - releasing empty Splitwindow" );
1156             pWorkWin->ReleaseChild_Impl( *pEmptyWin );
1157             pEmptyWin->Hide();
1158             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - registering real Splitwindow" );
1159             pWorkWin->RegisterChild_Impl( *this, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1160             pWorkWin->ArrangeChilds_Impl();
1161             pWorkWin->ShowChilds_Impl();
1162         }
1163     }
1164     else
1165     {
1166         pEmptyWin->bAutoHide = sal_False;
1167         pEmptyWin->nState &= ~2;
1168         if ( !IsFloatingMode() )
1169         {
1170             // Das Fenster "schwebt" nicht, soll aber ausgeblendet werden,
1171             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - releasing real Splitwindow" );
1172             pWorkWin->ReleaseChild_Impl( *this );
1173             Hide();
1174             pEmptyWin->Actualize();
1175             DBG_TRACE( "SfxSplitWindow::SetFadeIn_Impl - registering empty Splitwindow" );
1176             pWorkWin->RegisterChild_Impl( *pEmptyWin, eAlign, sal_True )->nVisible = CHILD_VISIBLE;
1177             pWorkWin->ArrangeChilds_Impl();
1178             pWorkWin->ShowChilds_Impl();
1179             pWorkWin->ArrangeAutoHideWindows( this );
1180         }
1181         else
1182         {
1183             Hide();
1184             pWorkWin->ArrangeAutoHideWindows( this );
1185         }
1186     }
1187 }
1188 
1189 void SfxSplitWindow::AutoHide()
1190 {
1191     // Wenn dieser Handler am "echten" SplitWindow aufgerufen wird, ist es
1192     // entweder angedockt und soll "schwebend" angezeigt werden oder umgekehrt
1193     if ( !bPinned )
1194     {
1195         // Es "schwebt", also wieder andocken
1196         SetPinned_Impl( sal_True );
1197         pWorkWin->ArrangeChilds_Impl();
1198     }
1199     else
1200     {
1201         // In den "Schwebezustand" bringen
1202         SetPinned_Impl( sal_False );
1203         pWorkWin->ArrangeChilds_Impl();
1204         pWorkWin->ArrangeAutoHideWindows( this );
1205     }
1206 
1207     pWorkWin->ShowChilds_Impl();
1208     SaveConfig_Impl();
1209 }
1210 
1211 void SfxSplitWindow::FadeOut_Impl()
1212 {
1213     if ( pEmptyWin->aTimer.IsActive() )
1214     {
1215         pEmptyWin->bAutoHide = sal_False;
1216         pEmptyWin->aTimer.Stop();
1217     }
1218 
1219     SetFadeIn_Impl( sal_False );
1220     Show_Impl();
1221 }
1222 
1223 void SfxSplitWindow::FadeOut()
1224 {
1225     FadeOut_Impl();
1226     SaveConfig_Impl();
1227 }
1228 
1229 void SfxSplitWindow::FadeIn()
1230 {
1231     SetFadeIn_Impl( sal_True );
1232     Show_Impl();
1233 }
1234 
1235 void SfxSplitWindow::Show_Impl()
1236 {
1237     sal_uInt16 nCount = pDockArr->Count();
1238     for ( sal_uInt16 n=0; n<nCount; n++ )
1239     {
1240         SfxDock_Impl *pDock = (*pDockArr)[n];
1241         if ( pDock->pWin )
1242             pDock->pWin->FadeIn( pEmptyWin->bFadeIn );
1243     }
1244 }
1245 /*
1246 void SfxSplitWindow::Pin_Impl( sal_Bool bPin )
1247 {
1248     if ( bPinned != bPin )
1249         AutoHide();
1250 }
1251 */
1252 sal_Bool SfxSplitWindow::ActivateNextChild_Impl( sal_Bool bForward )
1253 {
1254     // Wenn kein pActive, auf erstes bzw. letztes Fenster gehen ( bei !bForward wird erst in der loop dekrementiert )
1255     sal_uInt16 nCount = pDockArr->Count();
1256     sal_uInt16 n = bForward ? 0 : nCount;
1257 
1258     // Wenn Focus innerhalb, dann ein Fenster vor oder zur"uck, wenn m"oglich
1259     if ( pActive )
1260     {
1261         // Aktives Fenster ermitteln
1262         for ( n=0; n<nCount; n++ )
1263         {
1264             SfxDock_Impl *pD = (*pDockArr)[n];
1265             if ( pD->pWin && pD->pWin->HasChildPathFocus() )
1266                 break;
1267         }
1268 
1269         if ( bForward )
1270             // ein Fenster weiter ( wenn dann n>nCount, wird die Schleife unten gar nicht durchlaufen )
1271             n++;
1272     }
1273 
1274     if ( bForward )
1275     {
1276         // N"achstes Fenster suchen
1277         for ( sal_uInt16 nNext=n; nNext<nCount; nNext++ )
1278         {
1279             SfxDock_Impl *pD = (*pDockArr)[nNext];
1280             if ( pD->pWin )
1281             {
1282                 pD->pWin->GrabFocus();
1283                 return sal_True;
1284             }
1285         }
1286     }
1287     else
1288     {
1289         // Vorheriges Fenster suchen
1290         for ( sal_uInt16 nNext=n; nNext--; )
1291         {
1292             SfxDock_Impl *pD = (*pDockArr)[nNext];
1293             if ( pD->pWin )
1294             {
1295                 pD->pWin->GrabFocus();
1296                 return sal_True;
1297             }
1298         }
1299     }
1300 
1301     return sal_False;
1302 }
1303 
1304 void SfxSplitWindow::SetActiveWindow_Impl( SfxDockingWindow* pWin )
1305 {
1306     pActive = pWin;
1307     pWorkWin->SetActiveChild_Impl( this );
1308 }
1309 
1310 
1311