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