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