diff options
Diffstat (limited to 'vcl/source/window')
49 files changed, 59163 insertions, 0 deletions
diff --git a/vcl/source/window/abstdlg.cxx b/vcl/source/window/abstdlg.cxx new file mode 100644 index 000000000000..7f00b73b0808 --- /dev/null +++ b/vcl/source/window/abstdlg.cxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <vcl/abstdlg.hxx> +#include "cuilib.hxx" + +#include <osl/module.hxx> +#include <tools/string.hxx> + +typedef VclAbstractDialogFactory* (__LOADONCALLAPI *FuncPtrCreateDialogFactory)(); + +extern "C" { static void SAL_CALL thisModule() {} } + +VclAbstractDialogFactory* VclAbstractDialogFactory::Create() +{ + FuncPtrCreateDialogFactory fp = 0; + static ::osl::Module aDialogLibrary; + if ( aDialogLibrary.is() || aDialogLibrary.loadRelative( &thisModule, String( RTL_CONSTASCII_USTRINGPARAM( DLL_NAME ) ) ) ) + fp = ( VclAbstractDialogFactory* (__LOADONCALLAPI*)() ) + aDialogLibrary.getFunctionSymbol( ::rtl::OUString::createFromAscii("CreateDialogFactory") ); + if ( fp ) + return fp(); + return 0; +} + +VclAbstractDialog::~VclAbstractDialog() +{ +} + +// virtual +VclAbstractDialog2::~VclAbstractDialog2() +{ +} + +VclAbstractDialogFactory::~VclAbstractDialogFactory() +{ +} diff --git a/vcl/source/window/accel.cxx b/vcl/source/window/accel.cxx new file mode 100644 index 000000000000..3018236fff1a --- /dev/null +++ b/vcl/source/window/accel.cxx @@ -0,0 +1,731 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/list.hxx> +#ifndef _TABLE_HXX +#include <tools/table.hxx> +#endif +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <vcl/accel.h> +#include <vcl/accel.hxx> +#ifndef _RC_H +#include <tools/rc.h> +#endif + + + +// ======================================================================= + +DECLARE_TABLE( ImplAccelTable, ImplAccelEntry* ) +DECLARE_LIST( ImplAccelList, ImplAccelEntry* ) + +#define ACCELENTRY_NOTFOUND ((USHORT)0xFFFF) + +// ======================================================================= + +class ImplAccelData +{ +public: + ImplAccelTable maKeyTable; // Fuer KeyCodes, die mit einem Code erzeugt wurden + ImplAccelList maIdList; // Id-List +}; + +// ======================================================================= + +DBG_NAME( Accelerator ) + +// ======================================================================= + +USHORT ImplAccelEntryGetIndex( ImplAccelList* pList, USHORT nId, + USHORT* pIndex = NULL ) +{ + ULONG nLow; + ULONG nHigh; + ULONG nMid; + ULONG nCount = pList->Count(); + USHORT nCompareId; + + // Abpruefen, ob der erste Key groesser als der Vergleichskey ist + if ( !nCount || (nId < pList->GetObject( 0 )->mnId) ) + { + if ( pIndex ) + *pIndex = 0; + return ACCELENTRY_NOTFOUND; + } + + // Binaeres Suchen + nLow = 0; + nHigh = nCount-1; + do + { + nMid = (nLow + nHigh) / 2; + nCompareId = pList->GetObject( nMid )->mnId; + if ( nId < nCompareId ) + nHigh = nMid-1; + else + { + if ( nId > nCompareId ) + nLow = nMid + 1; + else + return (USHORT)nMid; + } + } + while ( nLow <= nHigh ); + + if ( pIndex ) + { + if ( nId > nCompareId ) + *pIndex = (USHORT)(nMid+1); + else + *pIndex = (USHORT)nMid; + } + + return ACCELENTRY_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +static void ImplAccelEntryInsert( ImplAccelList* pList, ImplAccelEntry* pEntry ) +{ + USHORT nInsIndex; + USHORT nIndex = ImplAccelEntryGetIndex( pList, pEntry->mnId, &nInsIndex ); + + if ( nIndex != ACCELENTRY_NOTFOUND ) + { + do + { + nIndex++; + ImplAccelEntry* pTempEntry = pList->GetObject( nIndex ); + if ( !pTempEntry || (pTempEntry->mnId != pEntry->mnId) ) + break; + } + while ( nIndex < pList->Count() ); + + pList->Insert( pEntry, (ULONG)nIndex ); + } + else + pList->Insert( pEntry, (ULONG)nInsIndex ); +} + +// ----------------------------------------------------------------------- + +static USHORT ImplAccelEntryGetFirstPos( ImplAccelList* pList, USHORT nId ) +{ + USHORT nIndex = ImplAccelEntryGetIndex( pList, nId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + { + while ( nIndex ) + { + nIndex--; + if ( pList->GetObject( nIndex )->mnId != nId ) + break; + } + + if ( pList->GetObject( nIndex )->mnId != nId ) + nIndex++; + } + + return nIndex; +} + +// ======================================================================= + +void Accelerator::ImplInit() +{ + mnCurId = 0; + mnCurRepeat = 0; + mbIsCancel = FALSE; + mpDel = NULL; +} + +// ----------------------------------------------------------------------- + +ImplAccelEntry* Accelerator::ImplGetAccelData( const KeyCode& rKeyCode ) const +{ + return mpData->maKeyTable.Get( rKeyCode.GetFullKeyCode() ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::ImplCopyData( ImplAccelData& rAccelData ) +{ + // Tabellen kopieren + ImplAccelEntry* pEntry = rAccelData.maIdList.First(); + while ( pEntry ) + { + pEntry = new ImplAccelEntry( *pEntry ); + + // Folge-Accelerator, dann auch kopieren + if ( pEntry->mpAccel ) + { + pEntry->mpAccel = new Accelerator( *(pEntry->mpAccel) ); + pEntry->mpAutoAccel = pEntry->mpAccel; + } + else + pEntry->mpAutoAccel = NULL; + + mpData->maKeyTable.Insert( (ULONG)pEntry->maKeyCode.GetFullKeyCode(), pEntry ); + mpData->maIdList.Insert( pEntry, LIST_APPEND ); + + pEntry = rAccelData.maIdList.Next(); + } +} + +// ----------------------------------------------------------------------- + +void Accelerator::ImplDeleteData() +{ + // Accelerator-Eintraege ueber die Id-Tabelle loeschen + ImplAccelEntry* pEntry = mpData->maIdList.First(); + while ( pEntry ) + { + // AutoResAccel zerstoeren + if ( pEntry->mpAutoAccel ) + delete pEntry->mpAutoAccel; + delete pEntry; + + pEntry = mpData->maIdList.Next(); + } +} + +// ----------------------------------------------------------------------- + +void Accelerator::ImplInsertAccel( USHORT nItemId, const KeyCode& rKeyCode, + BOOL bEnable, Accelerator* pAutoAccel ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + DBG_ASSERT( nItemId, "Accelerator::InsertItem(): ItemId == 0" ); + + if ( rKeyCode.IsFunction() ) + { + USHORT nCode1; + USHORT nCode2; + USHORT nCode3; + USHORT nCode4; + ImplGetKeyCode( rKeyCode.GetFunction(), nCode1, nCode2, nCode3, nCode4 ); + if ( nCode1 ) + ImplInsertAccel( nItemId, KeyCode( nCode1, nCode1 ), bEnable, pAutoAccel ); + if ( nCode2 ) + { + if ( pAutoAccel ) + pAutoAccel = new Accelerator( *pAutoAccel ); + ImplInsertAccel( nItemId, KeyCode( nCode2, nCode2 ), bEnable, pAutoAccel ); + if ( nCode3 ) + { + if ( pAutoAccel ) + pAutoAccel = new Accelerator( *pAutoAccel ); + ImplInsertAccel( nItemId, KeyCode( nCode3, nCode3 ), bEnable, pAutoAccel ); + } + } + return; + } + + // Neuen Eintrag holen und fuellen + ImplAccelEntry* pEntry = new ImplAccelEntry; + pEntry->mnId = nItemId; + pEntry->maKeyCode = rKeyCode; + pEntry->mpAccel = pAutoAccel; + pEntry->mpAutoAccel = pAutoAccel; + pEntry->mbEnabled = bEnable; + + // Ab in die Tabellen + ULONG nCode = rKeyCode.GetFullKeyCode(); + if ( !nCode ) + { + DBG_ERROR( "Accelerator::InsertItem(): KeyCode with KeyCode 0 not allowed" ); + delete pEntry; + } + else if ( !mpData->maKeyTable.Insert( nCode, pEntry ) ) + { + DBG_ERROR1( "Accelerator::InsertItem(): KeyCode (Key: %lx) already exists", nCode ); + delete pEntry; + } + else + ImplAccelEntryInsert( &(mpData->maIdList), pEntry ); +} + +// ----------------------------------------------------------------------- + +Accelerator::Accelerator() +{ + DBG_CTOR( Accelerator, NULL ); + + ImplInit(); + mpData = new ImplAccelData; +} + +// ----------------------------------------------------------------------- + +Accelerator::Accelerator( const Accelerator& rAccel ) : + Resource(), + maHelpStr( rAccel.maHelpStr ), + maCurKeyCode( rAccel.maCurKeyCode ) +{ + DBG_CTOR( Accelerator, NULL ); + DBG_CHKOBJ( &rAccel, Accelerator, NULL ); + + ImplInit(); + mpData = new ImplAccelData; + ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) ); +} + +// ----------------------------------------------------------------------- + +Accelerator::Accelerator( const ResId& rResId ) +{ + DBG_CTOR( Accelerator, NULL ); + + ImplInit(); + mpData = new ImplAccelData; + rResId.SetRT( RSC_ACCEL ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::ImplLoadRes( const ResId& rResId ) +{ + GetRes( rResId ); + + maHelpStr = ReadStringRes(); + ULONG nObjFollows = ReadLongRes(); + + for( ULONG i = 0; i < nObjFollows; i++ ) + { + InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) ); + } +} + +// ----------------------------------------------------------------------- + +Accelerator::~Accelerator() +{ + DBG_DTOR( Accelerator, NULL ); + + // AccelManager benachrichtigen, das Accelrator geloescht wurde + if ( mpDel ) + *mpDel = TRUE; + + ImplDeleteData(); + delete mpData; +} + +// ----------------------------------------------------------------------- + +void Accelerator::Activate() +{ + maActivateHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::Deactivate() +{ + maDeactivateHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::Select() +{ + maSelectHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::InsertItem( USHORT nItemId, const KeyCode& rKeyCode ) +{ + ImplInsertAccel( nItemId, rKeyCode, TRUE, NULL ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::InsertItem( const ResId& rResId ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ULONG nObjMask; + USHORT nAccelKeyId; + USHORT bDisable; + KeyCode aKeyCode; + Accelerator* pAutoAccel = NULL; + + GetRes( rResId.SetRT( RSC_ACCELITEM ) ); + nObjMask = ReadLongRes(); + nAccelKeyId = sal::static_int_cast<USHORT>(ReadLongRes()); + bDisable = ReadShortRes(); + + if ( nObjMask & ACCELITEM_KEY ) + { + // es wird ein neuer Kontext aufgespannt + RSHEADER_TYPE * pKeyCodeRes = (RSHEADER_TYPE *)GetClassRes(); + ResId aResId( pKeyCodeRes, *rResId.GetResMgr()); + aKeyCode = KeyCode( aResId ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) ); + } + + if ( nObjMask & ACCELITEM_ACCEL ) + { + pAutoAccel = new Accelerator( ResId( (RSHEADER_TYPE *)GetClassRes(), *rResId.GetResMgr() ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) ); + } + + ImplInsertAccel( nAccelKeyId, aKeyCode, !bDisable, pAutoAccel ); +} + +// ----------------------------------------------------------------------- + +void Accelerator::RemoveItem( USHORT nItemId ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + // Aus der Id-Liste entfernen + USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + { + USHORT nItemCount = GetItemCount(); + do + { + ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex ); + if ( pEntry && pEntry->mnId == nItemId ) + { + mpData->maKeyTable.Remove( pEntry->maKeyCode.GetFullKeyCode() ); + mpData->maIdList.Remove( (ULONG)nIndex ); + + // AutoResAccel zerstoeren + if ( pEntry->mpAutoAccel ) + delete pEntry->mpAutoAccel; + + delete pEntry; + } + else + break; + } + while ( nIndex < nItemCount ); + } +} + +// ----------------------------------------------------------------------- + +void Accelerator::RemoveItem( const KeyCode rKeyCode ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + { + // Aus der Id-Liste entfernen + USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), pEntry->mnId ); + USHORT nItemCount = GetItemCount(); + do + { + if ( mpData->maIdList.GetObject( (ULONG)nIndex ) == pEntry ) + break; + nIndex++; + } + while ( nIndex < nItemCount ); + + mpData->maKeyTable.Remove( rKeyCode.GetFullKeyCode() ); + mpData->maIdList.Remove( (ULONG)nIndex ); + + // AutoResAccel zerstoeren + if ( pEntry->mpAutoAccel ) + delete pEntry->mpAutoAccel; + + delete pEntry; + } +} + +// ----------------------------------------------------------------------- + +void Accelerator::Clear() +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplDeleteData(); + mpData->maKeyTable.Clear(); + mpData->maIdList.Clear(); +} + +// ----------------------------------------------------------------------- + +USHORT Accelerator::GetItemCount() const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + return (USHORT)mpData->maIdList.Count(); +} + +// ----------------------------------------------------------------------- + +USHORT Accelerator::GetItemId( USHORT nPos ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos ); + if ( pEntry ) + return pEntry->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +KeyCode Accelerator::GetItemKeyCode( USHORT nPos ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nPos ); + if ( pEntry ) + return pEntry->maKeyCode; + else + return KeyCode(); +} + +// ----------------------------------------------------------------------- + +USHORT Accelerator::GetItemId( const KeyCode& rKeyCode ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + return pEntry->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +KeyCode Accelerator::GetKeyCode( USHORT nItemId ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + return mpData->maIdList.GetObject( (ULONG)nIndex )->maKeyCode; + else + return KeyCode(); +} + +// ----------------------------------------------------------------------- + +BOOL Accelerator::IsIdValid( USHORT nItemId ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId ); + return (nIndex != ACCELENTRY_NOTFOUND); +} + +// ----------------------------------------------------------------------- + +BOOL Accelerator::IsKeyCodeValid( const KeyCode rKeyCode ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + return (pEntry != NULL); +} + +// ----------------------------------------------------------------------- + +BOOL Accelerator::Call( const KeyCode& rKeyCode, USHORT nRepeat ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + { + if ( pEntry->mbEnabled ) + { + BOOL bDel = FALSE; + mnCurId = pEntry->mnId; + maCurKeyCode = rKeyCode; + mnCurRepeat = nRepeat; + mpDel = &bDel; + Select(); + if ( !bDel ) + { + mnCurId = 0; + maCurKeyCode = KeyCode(); + mnCurRepeat = 0; + } + + return TRUE; + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Accelerator::SetAccel( USHORT nItemId, Accelerator* pAccel ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + { + USHORT nItemCount = GetItemCount(); + do + { + ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex ); + if ( pEntry->mnId != nItemId ) + break; + + pEntry->mpAccel = pAccel; + nIndex++; + } + while ( nIndex < nItemCount ); + } +} + +// ----------------------------------------------------------------------- + +Accelerator* Accelerator::GetAccel( USHORT nItemId ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + return mpData->maIdList.GetObject( (ULONG)nIndex )->mpAccel; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void Accelerator::SetAccel( const KeyCode rKeyCode, Accelerator* pAccel ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + pEntry->mpAccel = pAccel; +} + +// ----------------------------------------------------------------------- + +Accelerator* Accelerator::GetAccel( const KeyCode rKeyCode ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + return pEntry->mpAccel; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Accelerator::EnableItem( USHORT nItemId, BOOL bEnable ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetFirstPos( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + { + USHORT nItemCount = GetItemCount(); + do + { + ImplAccelEntry* pEntry = mpData->maIdList.GetObject( (ULONG)nIndex ); + if ( pEntry->mnId != nItemId ) + break; + + pEntry->mbEnabled = bEnable; + nIndex++; + } + while ( nIndex < nItemCount ); + } +} + +// ----------------------------------------------------------------------- + +BOOL Accelerator::IsItemEnabled( USHORT nItemId ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + USHORT nIndex = ImplAccelEntryGetIndex( &(mpData->maIdList), nItemId ); + if ( nIndex != ACCELENTRY_NOTFOUND ) + return mpData->maIdList.GetObject( (ULONG)nIndex )->mbEnabled; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Accelerator::EnableItem( const KeyCode rKeyCode, BOOL bEnable ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + pEntry->mbEnabled = bEnable; +} + +// ----------------------------------------------------------------------- + +BOOL Accelerator::IsItemEnabled( const KeyCode rKeyCode ) const +{ + DBG_CHKTHIS( Accelerator, NULL ); + + ImplAccelEntry* pEntry = ImplGetAccelData( rKeyCode ); + if ( pEntry ) + return pEntry->mbEnabled; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +Accelerator& Accelerator::operator=( const Accelerator& rAccel ) +{ + DBG_CHKTHIS( Accelerator, NULL ); + DBG_CHKOBJ( &rAccel, Accelerator, NULL ); + + // Neue Daten zuweisen + maHelpStr = rAccel.maHelpStr; + maCurKeyCode = KeyCode(); + mnCurId = 0; + mnCurRepeat = 0; + mbIsCancel = FALSE; + + // Tabellen loeschen und kopieren + ImplDeleteData(); + mpData->maKeyTable.Clear(); + mpData->maIdList.Clear(); + ImplCopyData( *((ImplAccelData*)(rAccel.mpData)) ); + + return *this; +} diff --git a/vcl/source/window/accmgr.cxx b/vcl/source/window/accmgr.cxx new file mode 100644 index 000000000000..81699bcaabb0 --- /dev/null +++ b/vcl/source/window/accmgr.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <vcl/accel.h> +#include <vcl/accel.hxx> +#include <vcl/accmgr.hxx> + + + +// ======================================================================= + +DECLARE_LIST( ImplAccelList, Accelerator* ) + +// ======================================================================= + +DBG_NAMEEX( Accelerator ) + +// ======================================================================= + +ImplAccelManager::~ImplAccelManager() +{ + if ( mpAccelList ) + delete mpAccelList; + if ( mpSequenceList ) + delete mpSequenceList; +} + +// ----------------------------------------------------------------------- + +BOOL ImplAccelManager::InsertAccel( Accelerator* pAccel ) +{ + if ( !mpAccelList ) + mpAccelList = new ImplAccelList; + else + { + // Gibts den schon ? + if ( mpAccelList->GetPos( pAccel ) != LIST_ENTRY_NOTFOUND ) + return FALSE; + } + + // Am Anfang der Liste einfuegen + mpAccelList->Insert( pAccel, (ULONG)0 ); + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ImplAccelManager::RemoveAccel( Accelerator* pAccel ) +{ + // Haben wir ueberhaupt eine Liste ? + if ( !mpAccelList ) + return; + + //e.g. #i90599#. Someone starts typing a sequence in a dialog, but doesn't + //end it, and then closes the dialog, deleting the accelerators. So if + //we're removing an accelerator that a sub-accelerator which is in the + //sequence list, throw away the entire sequence + if ( mpSequenceList ) + { + for (USHORT i = 0; i < pAccel->GetItemCount(); ++i) + { + Accelerator* pSubAccel = pAccel->GetAccel(pAccel->GetItemId(i)); + if ( mpSequenceList->GetPos( pSubAccel ) != LIST_ENTRY_NOTFOUND ) + { + EndSequence( true ); + break; + } + } + } + + // Raus damit + mpAccelList->Remove( pAccel ); +} + +// ----------------------------------------------------------------------- + +void ImplAccelManager::EndSequence( BOOL bCancel ) +{ + // Sind wir ueberhaupt in einer Sequenz ? + if ( !mpSequenceList ) + return; + + // Alle Deactivate-Handler der Acceleratoren in der Sequenz rufen + Accelerator* pTempAccel = mpSequenceList->First(); + while( pTempAccel ) + { + BOOL bDel = FALSE; + pTempAccel->mbIsCancel = bCancel; + pTempAccel->mpDel = &bDel; + pTempAccel->Deactivate(); + if ( !bDel ) + { + pTempAccel->mbIsCancel = FALSE; + pTempAccel->mpDel = NULL; + } + + pTempAccel = mpSequenceList->Next(); + } + + // Sequenz-Liste loeschen + delete mpSequenceList; + mpSequenceList = NULL; +} + +// ----------------------------------------------------------------------- + +BOOL ImplAccelManager::IsAccelKey( const KeyCode& rKeyCode, USHORT nRepeat ) +{ + Accelerator* pAccel; + + // Haben wir ueberhaupt Acceleratoren ?? + if ( !mpAccelList ) + return FALSE; + if ( !mpAccelList->Count() ) + return FALSE; + + // Sind wir in einer Sequenz ? + if ( mpSequenceList ) + { + pAccel = mpSequenceList->GetObject( 0 ); + DBG_CHKOBJ( pAccel, Accelerator, NULL ); + + // Nicht Gefunden ? + if ( !pAccel ) + { + // Sequenz abbrechen + FlushAccel(); + return FALSE; + } + + // Ist der Eintrag da drin ? + ImplAccelEntry* pEntry = pAccel->ImplGetAccelData( rKeyCode ); + if ( pEntry ) + { + Accelerator* pNextAccel = pEntry->mpAccel; + + // Ist da ein Accelerator hinter ? + if ( pNextAccel ) + { + DBG_CHKOBJ( pNextAccel, Accelerator, NULL ); + + mpSequenceList->Insert( pNextAccel, (ULONG)0 ); + + // Activate-Handler vom Neuen rufen + pNextAccel->Activate(); + return TRUE; + } + else + { + // Hat ihn schon ! + if ( pEntry->mbEnabled ) + { + // Sequence beenden (Deactivate-Handler vorher rufen) + EndSequence(); + + // Dem Accelerator das aktuelle Item setzen + // und Handler rufen + BOOL bDel = FALSE; + pAccel->maCurKeyCode = rKeyCode; + pAccel->mnCurId = pEntry->mnId; + pAccel->mnCurRepeat = nRepeat; + pAccel->mpDel = &bDel; + pAccel->Select(); + + // Hat Accel den Aufruf ueberlebt + if ( !bDel ) + { + DBG_CHKOBJ( pAccel, Accelerator, NULL ); + pAccel->maCurKeyCode = KeyCode(); + pAccel->mnCurId = 0; + pAccel->mnCurRepeat = 0; + pAccel->mpDel = NULL; + } + + return TRUE; + } + else + { + // Sequenz abbrechen, weil Acceleraor disabled + // Taste wird weitergeleitet (ans System) + FlushAccel(); + return FALSE; + } + } + } + else + { + // Sequenz abbrechen wegen falscher Taste + FlushAccel(); + return FALSE; + } + } + + // Durch die Liste der Acceleratoren wuehlen + pAccel = mpAccelList->First(); + while ( pAccel ) + { + DBG_CHKOBJ( pAccel, Accelerator, NULL ); + + // Ist der Eintrag da drin ? + ImplAccelEntry* pEntry = pAccel->ImplGetAccelData( rKeyCode ); + if ( pEntry ) + { + Accelerator* pNextAccel = pEntry->mpAccel; + + // Ist da ein Accelerator hinter ? + if ( pNextAccel ) + { + DBG_CHKOBJ( pNextAccel, Accelerator, NULL ); + + // Sequenz-Liste erzeugen + mpSequenceList = new ImplAccelList; + mpSequenceList->Insert( pAccel, (ULONG)0 ); + mpSequenceList->Insert( pNextAccel, (ULONG)0 ); + + // Activate-Handler vom Neuen rufen + pNextAccel->Activate(); + + return TRUE; + } + else + { + // Hat ihn schon ! + if ( pEntry->mbEnabled ) + { + // Activate/Deactivate-Handler vorher rufen + pAccel->Activate(); + pAccel->Deactivate(); + + // Dem Accelerator das aktuelle Item setzen + // und Handler rufen + BOOL bDel = FALSE; + pAccel->maCurKeyCode = rKeyCode; + pAccel->mnCurId = pEntry->mnId; + pAccel->mnCurRepeat = nRepeat; + pAccel->mpDel = &bDel; + pAccel->Select(); + + // Hat Accel den Aufruf ueberlebt + if ( !bDel ) + { + DBG_CHKOBJ( pAccel, Accelerator, NULL ); + pAccel->maCurKeyCode = KeyCode(); + pAccel->mnCurId = 0; + pAccel->mnCurRepeat = 0; + pAccel->mpDel = NULL; + } + + return TRUE; + } + else + return FALSE; + } + } + + // Nicht gefunden, vielleicht im naechsten Accelerator + pAccel = mpAccelList->Next(); + } + + return FALSE; +} diff --git a/vcl/source/window/arrange.cxx b/vcl/source/window/arrange.cxx new file mode 100644 index 000000000000..f016ef2c053b --- /dev/null +++ b/vcl/source/window/arrange.cxx @@ -0,0 +1,1074 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/arrange.hxx" +#include "vcl/edit.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/awt/Rectangle.hpp" + +#include "osl/diagnose.h" + +using namespace vcl; +using namespace com::sun::star; + +// ---------------------------------------- +// vcl::WindowArranger +//----------------------------------------- + +long WindowArranger::getDefaultBorder() +{ + ImplSVData* pSVData = ImplGetSVData(); + long nResult = pSVData->maAppData.mnDefaultLayoutBorder; + if( nResult < 0 ) + { + OutputDevice* pDefDev = Application::GetDefaultDevice(); + if( pDefDev ) + { + Size aBorder( pDefDev->LogicToPixel( Size( 3, 3 ), MapMode( MAP_APPFONT ) ) ); + nResult = pSVData->maAppData.mnDefaultLayoutBorder = aBorder.Height(); + } + } + return nResult > 0 ? nResult : 0; +} + +WindowArranger::~WindowArranger() +{} + +void WindowArranger::setParent( WindowArranger* i_pParent ) +{ + OSL_VERIFY( i_pParent->m_pParentWindow == m_pParentWindow || m_pParentWindow == NULL ); + + m_pParentArranger = i_pParent; + m_pParentWindow = i_pParent->m_pParentWindow; + setParentWindow( m_pParentWindow ); +} + +void WindowArranger::setParentWindow( Window* i_pNewParent ) +{ + m_pParentWindow = i_pNewParent; + + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle ) // sanity check + { + #if OSL_DEBUG_LEVEL > 0 + if( pEle->m_pElement ) + { + OSL_VERIFY( pEle->m_pElement->GetParent() == i_pNewParent ); + } + #endif + if( pEle->m_pChild ) + pEle->m_pChild->setParentWindow( i_pNewParent ); + } + } +} + +void WindowArranger::show( bool i_bShow, bool i_bImmediateUpdate ) +{ + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle ) // sanity check + { + pEle->m_bHidden = ! i_bShow; + if( pEle->m_pElement ) + pEle->m_pElement->Show( i_bShow ); + if( pEle->m_pChild.get() ) + pEle->m_pChild->show( i_bShow, false ); + } + } + if( m_pParentArranger ) + { + nEle = m_pParentArranger->countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = m_pParentArranger->getElement( i ); + if( pEle && pEle->m_pChild.get() == this ) + { + pEle->m_bHidden = ! i_bShow; + break; + } + } + } + if( i_bImmediateUpdate ) + { + // find the topmost parent + WindowArranger* pResize = this; + while( pResize->m_pParentArranger ) + pResize = pResize->m_pParentArranger; + pResize->resize(); + } +} + +bool WindowArranger::isVisible() const +{ + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + const Element* pEle = getConstElement( i ); + if( pEle->isVisible() ) + return true; + } + return false; +} + +bool WindowArranger::Element::isVisible() const +{ + bool bVisible = false; + if( ! m_bHidden ) + { + if( m_pElement ) + bVisible = m_pElement->IsVisible(); + else if( m_pChild ) + bVisible = m_pChild->isVisible(); + } + return bVisible; +} + +sal_Int32 WindowArranger::Element::getExpandPriority() const +{ + sal_Int32 nPrio = m_nExpandPriority; + if( m_pChild && m_nExpandPriority >= 0 ) + { + size_t nElements = m_pChild->countElements(); + for( size_t i = 0; i < nElements; i++ ) + { + sal_Int32 nCPrio = m_pChild->getExpandPriority( i ); + if( nCPrio > nPrio ) + nPrio = nCPrio; + } + } + return nPrio; +} + +Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aResult; + if( ! m_bHidden ) + { + bool bVisible = false; + if( m_pElement && m_pElement->IsVisible() ) + { + aResult = m_pElement->GetOptimalSize( i_eType ); + bVisible = true; + } + else if( m_pChild && m_pChild->isVisible() ) + { + aResult = m_pChild->getOptimalSize( i_eType ); + bVisible = true; + } + if( bVisible ) + { + if( aResult.Width() < m_aMinSize.Width() ) + aResult.Width() = m_aMinSize.Width(); + if( aResult.Height() < m_aMinSize.Height() ) + aResult.Height() = m_aMinSize.Height(); + aResult.Width() += getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); + aResult.Height() += getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); + } + } + + return aResult; +} + +void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSize ) +{ + Point aPoint( i_rPos ); + Size aSize( i_rSize ); + aPoint.X() += getBorderValue( m_nLeftBorder ); + aPoint.Y() += getBorderValue( m_nTopBorder ); + aSize.Width() -= getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); + aSize.Height() -= getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); + if( m_pElement ) + m_pElement->SetPosSizePixel( aPoint, aSize ); + else if( m_pChild ) + m_pChild->setManagedArea( Rectangle( aPoint, aSize ) ); +} + +uno::Sequence< beans::PropertyValue > WindowArranger::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aRet( 3 ); + aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OuterBorder" ) ); + aRet[0].Value = uno::makeAny( sal_Int32( getBorderValue( m_nOuterBorder ) ) ); + aRet[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ManagedArea" ) ); + awt::Rectangle aArea( m_aManagedArea.getX(), m_aManagedArea.getY(), m_aManagedArea.getWidth(), m_aManagedArea.getHeight() ); + aRet[1].Value = uno::makeAny( aArea ); + aRet[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aRet[2].Value = uno::makeAny( sal_Bool( isVisible() ) ); + return aRet; +} + +void WindowArranger::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pProps = i_rProps.getConstArray(); + bool bResize = false; + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) + { + if( pProps[i].Name.equalsAscii( "OuterBorder" ) ) + { + sal_Int32 nVal = 0; + if( pProps[i].Value >>= nVal ) + { + if( getBorderValue( m_nOuterBorder ) != nVal ) + { + m_nOuterBorder = nVal; + bResize = true; + } + } + } + else if( pProps[i].Name.equalsAscii( "ManagedArea" ) ) + { + awt::Rectangle aArea( 0, 0, 0, 0 ); + if( pProps[i].Value >>= aArea ) + { + m_aManagedArea.setX( aArea.X ); + m_aManagedArea.setY( aArea.Y ); + m_aManagedArea.setWidth( aArea.Width ); + m_aManagedArea.setHeight( aArea.Height ); + bResize = true; + } + } + else if( pProps[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_False; + if( pProps[i].Value >>= bVal ) + { + show( bVal, false ); + bResize = true; + } + } + } + if( bResize ) + resize(); +} + + +// ---------------------------------------- +// vcl::RowOrColumn +//----------------------------------------- + +RowOrColumn::~RowOrColumn() +{ + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + it->deleteChild(); + } +} + +Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aRet( 0, 0 ); + long nDistance = getBorderValue( m_nBorderWidth ); + for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->isVisible() ) + { + // get the size of type of the managed element + Size aElementSize( it->getOptimalSize( i_eType ) ); + if( m_bColumn ) + { + // add the distance between elements + aRet.Height() += nDistance; + // check if the width needs adjustment + if( aRet.Width() < aElementSize.Width() ) + aRet.Width() = aElementSize.Width(); + aRet.Height() += aElementSize.Height(); + } + else + { + // add the distance between elements + aRet.Width() += nDistance; + // check if the height needs adjustment + if( aRet.Height() < aElementSize.Height() ) + aRet.Height() = aElementSize.Height(); + aRet.Width() += aElementSize.Width(); + } + } + } + + if( aRet.Width() != 0 || aRet.Height() != 0 ) + { + // subtract the border for the first element + if( m_bColumn ) + aRet.Height() -= nDistance; + else + aRet.Width() -= nDistance; + + // add the outer border + long nOuterBorder = getBorderValue( m_nOuterBorder ); + aRet.Width() += 2*nOuterBorder; + aRet.Height() += 2*nOuterBorder; + } + + return aRet; +} + +void RowOrColumn::distributeRowWidth( std::vector<Size>& io_rSizes, long /*i_nUsedWidth*/, long i_nExtraWidth ) +{ + if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) + { + // find all elements with the highest expand priority + size_t nElements = m_aElements.size(); + std::vector< size_t > aIndices; + sal_Int32 nHighPrio = 0; + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[ i ].isVisible() ) + { + sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); + if( nCurPrio > nHighPrio ) + { + aIndices.clear(); + nHighPrio = nCurPrio; + } + if( nCurPrio == nHighPrio ) + aIndices.push_back( i ); + } + } + + // distribute extra space evenly among collected elements + nElements = aIndices.size(); + if( nElements > 0 ) + { + long nDelta = i_nExtraWidth / nElements; + for( size_t i = 0; i < nElements; i++ ) + { + io_rSizes[ aIndices[i] ].Width() += nDelta; + i_nExtraWidth -= nDelta; + } + // add the last pixels to the last row element + if( i_nExtraWidth > 0 && nElements > 0 ) + io_rSizes[aIndices.back()].Width() += i_nExtraWidth; + } + } +} + +void RowOrColumn::distributeColumnHeight( std::vector<Size>& io_rSizes, long /*i_nUsedHeight*/, long i_nExtraHeight ) +{ + if( ! io_rSizes.empty() && io_rSizes.size() == m_aElements.size() ) + { + // find all elements with the highest expand priority + size_t nElements = m_aElements.size(); + std::vector< size_t > aIndices; + sal_Int32 nHighPrio = 3; + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[ i ].isVisible() ) + { + sal_Int32 nCurPrio = m_aElements[ i ].getExpandPriority(); + if( nCurPrio > nHighPrio ) + { + aIndices.clear(); + nHighPrio = nCurPrio; + } + if( nCurPrio == nHighPrio ) + aIndices.push_back( i ); + } + } + + // distribute extra space evenly among collected elements + nElements = aIndices.size(); + if( nElements > 0 ) + { + long nDelta = i_nExtraHeight / nElements; + for( size_t i = 0; i < nElements; i++ ) + { + io_rSizes[ aIndices[i] ].Height() += nDelta; + i_nExtraHeight -= nDelta; + } + // add the last pixels to the last row element + if( i_nExtraHeight > 0 && nElements > 0 ) + io_rSizes[aIndices.back()].Height() += i_nExtraHeight; + } + } +} + +void RowOrColumn::resize() +{ + // check if we can get optimal size, else fallback to minimal size + Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED ) ); + WindowSizeType eType = WINDOWSIZE_PREFERRED; + if( m_bColumn ) + { + if( aOptSize.Height() > m_aManagedArea.GetHeight() ) + eType = WINDOWSIZE_MINIMUM; + } + else + { + if( aOptSize.Width() > m_aManagedArea.GetWidth() ) + eType = WINDOWSIZE_MINIMUM; + } + + size_t nElements = m_aElements.size(); + // get all element sizes for sizing + std::vector<Size> aElementSizes( nElements ); + long nDistance = getBorderValue( m_nBorderWidth ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nUsedWidth = 2*nOuterBorder - (nElements ? nDistance : 0); + for( size_t i = 0; i < nElements; i++ ) + { + if( m_aElements[i].isVisible() ) + { + aElementSizes[i] = m_aElements[i].getOptimalSize( eType ); + if( m_bColumn ) + { + aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2 * nOuterBorder; + nUsedWidth += aElementSizes[i].Height() + nDistance; + } + else + { + aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2 * nOuterBorder; + nUsedWidth += aElementSizes[i].Width() + nDistance; + } + } + } + + long nExtraWidth = (m_bColumn ? m_aManagedArea.GetHeight() : m_aManagedArea.GetWidth()) - nUsedWidth; + if( nExtraWidth > 0 ) + { + if( m_bColumn ) + distributeColumnHeight( aElementSizes, nUsedWidth, nExtraWidth ); + else + distributeRowWidth( aElementSizes, nUsedWidth, nExtraWidth ); + } + + // get starting position + Point aElementPos( m_aManagedArea.TopLeft() ); + // outer border + aElementPos.X() += nOuterBorder; + aElementPos.Y() += nOuterBorder; + + // position managed windows + for( size_t i = 0; i < nElements; i++ ) + { + // get the size of type of the managed element + if( m_aElements[i].isVisible() ) + { + m_aElements[i].setPosSize( aElementPos, aElementSizes[i] ); + if( m_bColumn ) + aElementPos.Y() += nDistance + aElementSizes[i].Height(); + else + aElementPos.X() += nDistance + aElementSizes[i].Width(); + } + } +} + +size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, const Size& i_rMinSize, size_t i_nIndex ) +{ + size_t nIndex = i_nIndex; + if( i_nIndex >= m_aElements.size() ) + { + nIndex = m_aElements.size(); + m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); + } + else + { + std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + while( i_nIndex-- ) + ++it; + m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); + } + return nIndex; +} + +size_t RowOrColumn::addChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio, size_t i_nIndex ) +{ + size_t nIndex = i_nIndex; + if( i_nIndex >= m_aElements.size() ) + { + nIndex = m_aElements.size(); + m_aElements.push_back( WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); + } + else + { + std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + while( i_nIndex-- ) + ++it; + m_aElements.insert( it, WindowArranger::Element( NULL, i_pChild, i_nExpandPrio ) ); + } + return nIndex; +} + +void RowOrColumn::remove( Window* i_pWindow ) +{ + if( i_pWindow ) + { + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pElement == i_pWindow ) + { + m_aElements.erase( it ); + return; + } + } + } +} + +void RowOrColumn::remove( boost::shared_ptr<WindowArranger> const & i_pChild ) +{ + if( i_pChild ) + { + for( std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pChild == i_pChild ) + { + m_aElements.erase( it ); + return; + } + } + } +} + +// ---------------------------------------- +// vcl::LabeledElement +//----------------------------------------- + +LabeledElement::~LabeledElement() +{ + m_aLabel.deleteChild(); + m_aElement.deleteChild(); +} + +Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aRet( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + if( aRet.Width() != 0 ) + { + if( m_nLabelColumnWidth != 0 ) + aRet.Width() = m_nLabelColumnWidth; + else + aRet.Width() += getBorderValue( m_nDistance ); + } + Size aElementSize( m_aElement.getOptimalSize( i_eType ) ); + aRet.Width() += aElementSize.Width(); + if( aElementSize.Height() > aRet.Height() ) + aRet.Height() = aElementSize.Height(); + if( aRet.Height() != 0 ) + aRet.Height() += 2 * getBorderValue( m_nOuterBorder ); + + return aRet; +} + +void LabeledElement::resize() +{ + Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) ); + long nDistance = getBorderValue( m_nDistance ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + if( nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() ) + aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM ); + + // align label and element vertically in LabeledElement + long nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aLabelSize.Height()) / 2; + Point aPos( m_aManagedArea.Left(), + m_aManagedArea.Top() + nOuterBorder + nYOff ); + Size aSize( aLabelSize ); + if( m_nLabelColumnWidth != 0 ) + aSize.Width() = m_nLabelColumnWidth; + m_aLabel.setPosSize( aPos, aSize ); + + aPos.X() += aSize.Width() + nDistance; + nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aElementSize.Height()) / 2; + aPos.Y() = m_aManagedArea.Top() + nOuterBorder + nYOff; + aSize.Width() = aElementSize.Width(); + aSize.Height() = m_aManagedArea.GetHeight() - 2*nOuterBorder; + + // label style + // 0: position left and right + // 1: keep the element close to label and grow it + // 2: keep the element close and don't grow it + if( m_nLabelStyle == 0) + { + if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) + aPos.X() = m_aManagedArea.Right() - aSize.Width(); + } + else if( m_nLabelStyle == 1 ) + { + if( aPos.X() + aSize.Width() < m_aManagedArea.Right() ) + aSize.Width() = m_aManagedArea.Right() - aPos.X(); + } + m_aElement.setPosSize( aPos, aSize ); +} + +void LabeledElement::setLabel( Window* i_pLabel ) +{ + m_aLabel.m_pElement = i_pLabel; + m_aLabel.m_pChild.reset(); +} + +void LabeledElement::setLabel( boost::shared_ptr<WindowArranger> const & i_pLabel ) +{ + m_aLabel.m_pElement = NULL; + m_aLabel.m_pChild = i_pLabel; +} + +void LabeledElement::setElement( Window* i_pElement ) +{ + m_aElement.m_pElement = i_pElement; + m_aElement.m_pChild.reset(); +} + +void LabeledElement::setElement( boost::shared_ptr<WindowArranger> const & i_pElement ) +{ + m_aElement.m_pElement = NULL; + m_aElement.m_pChild = i_pElement; +} + +// ---------------------------------------- +// vcl::LabelColumn +//----------------------------------------- +LabelColumn::~LabelColumn() +{ +} + +long LabelColumn::getLabelWidth() const +{ + long nWidth = 0; + + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + const Element* pEle = getConstElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) + { + Window* pLW = pLabel->getWindow( 0 ); + if( pLW ) + { + Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) ); + long nLB = 0; + pLabel->getBorders(0, &nLB); + aLabSize.Width() += getBorderValue( nLB ); + if( aLabSize.Width() > nWidth ) + nWidth = aLabSize.Width(); + } + } + } + } + return nWidth + getBorderValue( getBorderWidth() ); +} + +Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const +{ + long nWidth = getLabelWidth(); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + Size aColumnSize; + + // every child is a LabeledElement + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Size aElementSize; + const Element* pEle = getConstElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + const LabeledElement* pLabel = dynamic_cast< const LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) // we have a label + { + aElementSize = pLabel->getLabelSize( WINDOWSIZE_MINIMUM ); + if( aElementSize.Width() ) + aElementSize.Width() = nWidth; + Size aSize( pLabel->getElementSize( i_eType ) ); + aElementSize.Width() += aSize.Width(); + if( aSize.Height() > aElementSize.Height() ) + aElementSize.Height() = aSize.Height(); + } + else // a non label, just treat it as a row + { + aElementSize = pEle->getOptimalSize( i_eType ); + } + } + else if( pEle && pEle->m_pElement ) // a general window, treat is as a row + { + aElementSize = pEle->getOptimalSize( i_eType ); + } + if( aElementSize.Width() ) + { + aElementSize.Width() += 2*nOuterBorder; + if( aElementSize.Width() > aColumnSize.Width() ) + aColumnSize.Width() = aElementSize.Width(); + } + if( aElementSize.Height() ) + { + aColumnSize.Height() += getBorderValue( getBorderWidth() ) + aElementSize.Height(); + } + } + if( nEle > 0 && aColumnSize.Height() ) + { + aColumnSize.Height() -= getBorderValue( getBorderWidth() ); // for the first element + aColumnSize.Height() += 2*nOuterBorder; + } + return aColumnSize; +} + +void LabelColumn::resize() +{ + long nWidth = getLabelWidth(); + size_t nEle = countElements(); + for( size_t i = 0; i < nEle; i++ ) + { + Element* pEle = getElement( i ); + if( pEle && pEle->m_pChild.get() ) + { + LabeledElement* pLabel = dynamic_cast< LabeledElement* >(pEle->m_pChild.get()); + if( pLabel ) + pLabel->setLabelColumnWidth( nWidth ); + } + } + RowOrColumn::resize(); +} + +size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent ) +{ + boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); + xLabel->setLabel( i_pLabel ); + xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); + xLabel->setElement( i_rElement ); + size_t nIndex = addChild( xLabel ); + resize(); + return nIndex; +} + +size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent, const Size& i_rElementMinSize ) +{ + boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); + xLabel->setLabel( i_pLabel ); + xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); + xLabel->setElement( i_pElement ); + xLabel->setMinimumSize( 1, i_rElementMinSize ); + size_t nIndex = addChild( xLabel ); + resize(); + return nIndex; +} + +// ---------------------------------------- +// vcl::Indenter +//----------------------------------------- + +Indenter::~Indenter() +{ + m_aElement.deleteChild(); +} + +Size Indenter::getOptimalSize( WindowSizeType i_eType ) const +{ + Size aSize( m_aElement.getOptimalSize( i_eType ) ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nIndent = getBorderValue( m_nIndent ); + aSize.Width() += 2*nOuterBorder + nIndent; + aSize.Height() += 2*nOuterBorder; + return aSize; +} + +void Indenter::resize() +{ + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nIndent = getBorderValue( m_nIndent ); + Point aPt( m_aManagedArea.TopLeft() ); + aPt.X() += nOuterBorder + nIndent; + aPt.Y() += nOuterBorder; + Size aSz( m_aManagedArea.GetSize() ); + aSz.Width() -= 2*nOuterBorder + nIndent; + aSz.Height() -= 2*nOuterBorder; + m_aElement.setPosSize( aPt, aSz ); +} + +void Indenter::setWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio ) +{ + OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0) || i_pWindow == 0 ); + OSL_VERIFY( i_pWindow == 0 || i_pWindow->GetParent() == m_pParentWindow ); + m_aElement.m_pElement = i_pWindow; + m_aElement.m_nExpandPriority = i_nExpandPrio; +} + +void Indenter::setChild( boost::shared_ptr<WindowArranger> const & i_pChild, sal_Int32 i_nExpandPrio ) +{ + OSL_VERIFY( (m_aElement.m_pElement == 0 && m_aElement.m_pChild == 0 ) || i_pChild == 0 ); + m_aElement.m_pChild = i_pChild; + m_aElement.m_nExpandPriority = i_nExpandPrio; +} + +// ---------------------------------------- +// vcl::MatrixArranger +//----------------------------------------- +MatrixArranger::~MatrixArranger() +{ +} + +Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, + std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights, + std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio + ) const +{ + long nOuterBorder = getBorderValue( m_nOuterBorder ); + Size aMatrixSize( 2*nOuterBorder, 2*nOuterBorder ); + + // first find out the current number of rows and columns + sal_uInt32 nRows = 0, nColumns = 0; + for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_nX >= nColumns ) + nColumns = it->m_nX+1; + if( it->m_nY >= nRows ) + nRows = it->m_nY+1; + } + + // now allocate row and column depth vectors + o_rColumnWidths = std::vector< long >( nColumns, 0 ); + o_rRowHeights = std::vector< long >( nRows, 0 ); + o_rColumnPrio = std::vector< sal_Int32 >( nColumns, 0 ); + o_rRowPrio = std::vector< sal_Int32 >( nRows, 0 ); + + // get sizes an allocate them into rows/columns + for( std::vector< MatrixElement >::const_iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + Size aSize( it->getOptimalSize( i_eType ) ); + if( aSize.Width() > o_rColumnWidths[ it->m_nX ] ) + o_rColumnWidths[ it->m_nX ] = aSize.Width(); + if( aSize.Height() > o_rRowHeights[ it->m_nY ] ) + o_rRowHeights[ it->m_nY ] = aSize.Height(); + if( it->m_nExpandPriority > o_rColumnPrio[ it->m_nX ] ) + o_rColumnPrio[ it->m_nX ] = it->m_nExpandPriority; + if( it->m_nExpandPriority > o_rRowPrio[ it->m_nY ] ) + o_rRowPrio[ it->m_nY ] = it->m_nExpandPriority; + } + + // add up sizes + long nDistanceX = getBorderValue( m_nBorderX ); + long nDistanceY = getBorderValue( m_nBorderY ); + for( sal_uInt32 i = 0; i < nColumns; i++ ) + aMatrixSize.Width() += o_rColumnWidths[i] + nDistanceX; + if( nColumns > 0 ) + aMatrixSize.Width() -= nDistanceX; + + for( sal_uInt32 i = 0; i < nRows; i++ ) + aMatrixSize.Height() += o_rRowHeights[i] + nDistanceY; + if( nRows > 0 ) + aMatrixSize.Height() -= nDistanceY; + + return aMatrixSize; +} + +Size MatrixArranger::getOptimalSize( WindowSizeType i_eType ) const +{ + std::vector<long> aColumnWidths, aRowHeights; + std::vector<sal_Int32> aColumnPrio, aRowPrio; + return getOptimalSize( i_eType, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio ); +} + +void MatrixArranger::distributeExtraSize( std::vector<long>& io_rSizes, const std::vector<sal_Int32>& i_rPrios, long i_nExtraWidth ) +{ + if( ! io_rSizes.empty() && io_rSizes.size() == i_rPrios.size() ) // sanity check + { + // find all elements with the highest expand priority + size_t nElements = io_rSizes.size(); + std::vector< size_t > aIndices; + sal_Int32 nHighPrio = 0; + for( size_t i = 0; i < nElements; i++ ) + { + sal_Int32 nCurPrio = i_rPrios[ i ]; + if( nCurPrio > nHighPrio ) + { + aIndices.clear(); + nHighPrio = nCurPrio; + } + if( nCurPrio == nHighPrio ) + aIndices.push_back( i ); + } + + // distribute extra space evenly among collected elements + nElements = aIndices.size(); + if( nElements > 0 ) + { + long nDelta = i_nExtraWidth / nElements; + for( size_t i = 0; i < nElements; i++ ) + { + io_rSizes[ aIndices[i] ] += nDelta; + i_nExtraWidth -= nDelta; + } + // add the last pixels to the last row element + if( i_nExtraWidth > 0 && nElements > 0 ) + io_rSizes[aIndices.back()] += i_nExtraWidth; + } + } +} + + +void MatrixArranger::resize() +{ + // assure that we have at least one row and column + if( m_aElements.empty() ) + return; + + // check if we can get optimal size, else fallback to minimal size + std::vector<long> aColumnWidths, aRowHeights; + std::vector<sal_Int32> aColumnPrio, aRowPrio; + Size aOptSize( getOptimalSize( WINDOWSIZE_PREFERRED, aColumnWidths, aRowHeights, aColumnPrio, aRowPrio ) ); + if( aOptSize.Height() > m_aManagedArea.GetHeight() || + aOptSize.Width() > m_aManagedArea.GetWidth() ) + { + std::vector<long> aMinColumnWidths, aMinRowHeights; + getOptimalSize( WINDOWSIZE_MINIMUM, aMinColumnWidths, aMinRowHeights, aColumnPrio, aRowPrio ); + if( aOptSize.Height() > m_aManagedArea.GetHeight() ) + aRowHeights = aMinRowHeights; + if( aOptSize.Width() > m_aManagedArea.GetWidth() ) + aColumnWidths = aMinColumnWidths; + } + + // distribute extra space available + long nExtraSize = m_aManagedArea.GetWidth(); + for( size_t i = 0; i < aColumnWidths.size(); ++i ) + nExtraSize -= aColumnWidths[i] + m_nBorderX; + if( nExtraSize > 0 ) + distributeExtraSize( aColumnWidths, aColumnPrio, nExtraSize ); + nExtraSize = m_aManagedArea.GetHeight(); + for( size_t i = 0; i < aRowHeights.size(); ++i ) + nExtraSize -= aRowHeights[i] + m_nBorderY; + if( nExtraSize > 0 ) + distributeExtraSize( aRowHeights, aRowPrio, nExtraSize ); + + // prepare offsets + long nDistanceX = getBorderValue( m_nBorderX ); + long nDistanceY = getBorderValue( m_nBorderY ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + std::vector<long> aColumnX( aColumnWidths.size() ); + aColumnX[0] = m_aManagedArea.Left() + nOuterBorder; + for( size_t i = 1; i < aColumnX.size(); i++ ) + aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + nDistanceX; + + std::vector<long> aRowY( aRowHeights.size() ); + aRowY[0] = m_aManagedArea.Top() + nOuterBorder; + for( size_t i = 1; i < aRowY.size(); i++ ) + aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + nDistanceY; + + // now iterate over the elements and assign their positions + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + Point aCellPos( aColumnX[it->m_nX], aRowY[it->m_nY] ); + Size aCellSize( aColumnWidths[it->m_nX], aRowHeights[it->m_nY] ); + it->setPosSize( aCellPos, aCellSize ); + } +} + +size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio, const Size& i_rMinSize ) +{ + sal_uInt64 nMapValue = getMap( i_nX, i_nY ); + std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); + size_t nIndex = 0; + if( it == m_aMatrixMap.end() ) + { + m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); + m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); + } + else + { + MatrixElement& rEle( m_aElements[ it->second ] ); + rEle.m_pElement = i_pWindow; + rEle.m_pChild.reset(); + rEle.m_nExpandPriority = i_nExpandPrio; + rEle.m_aMinSize = i_rMinSize; + rEle.m_nX = i_nX; + rEle.m_nY = i_nY; + nIndex = it->second; + } + return nIndex; +} + +void MatrixArranger::remove( Window* i_pWindow ) +{ + if( i_pWindow ) + { + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pElement == i_pWindow ) + { + m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); + m_aElements.erase( it ); + return; + } + } + } +} + +size_t MatrixArranger::addChild( boost::shared_ptr<WindowArranger> const &i_pChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio ) +{ + sal_uInt64 nMapValue = getMap( i_nX, i_nY ); + std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); + size_t nIndex = 0; + if( it == m_aMatrixMap.end() ) + { + m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); + m_aElements.push_back( MatrixElement( NULL, i_nX, i_nY, i_pChild, i_nExpandPrio ) ); + } + else + { + MatrixElement& rEle( m_aElements[ it->second ] ); + rEle.m_pElement = 0; + rEle.m_pChild = i_pChild; + rEle.m_nExpandPriority = i_nExpandPrio; + rEle.m_nX = i_nX; + rEle.m_nY = i_nY; + nIndex = it->second; + } + return nIndex; +} + +void MatrixArranger::remove( boost::shared_ptr<WindowArranger> const &i_pChild ) +{ + if( i_pChild ) + { + for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); + it != m_aElements.end(); ++it ) + { + if( it->m_pChild == i_pChild ) + { + m_aMatrixMap.erase( getMap( it->m_nX, it->m_nY ) ); + m_aElements.erase( it ); + return; + } + } + } +} + diff --git a/vcl/source/window/brdwin.cxx b/vcl/source/window/brdwin.cxx new file mode 100644 index 000000000000..2ff7d0a687e7 --- /dev/null +++ b/vcl/source/window/brdwin.cxx @@ -0,0 +1,2355 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#ifndef _SV_SVIDS_HRC +#include <vcl/svids.hrc> +#endif +#include <vcl/svdata.hxx> +#include <vcl/event.hxx> +#include <vcl/decoview.hxx> +#include <vcl/syswin.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/gradient.hxx> +#include <vcl/image.hxx> +#include <vcl/virdev.hxx> +#include <vcl/help.hxx> +#include <vcl/edit.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/window.h> +#include <vcl/metric.hxx> +#include <tools/debug.hxx> + +using namespace ::com::sun::star::uno; + +// useful caption height for title bar buttons +#define MIN_CAPTION_HEIGHT 18 + +// ======================================================================= + +static void ImplGetPinImage( USHORT nStyle, BOOL bPinIn, Image& rImage ) +{ + // ImageListe laden, wenn noch nicht vorhanden + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maCtrlData.mpPinImgList ) + { + ResMgr* pResMgr = ImplGetResMgr(); + pSVData->maCtrlData.mpPinImgList = new ImageList(); + if( pResMgr ) + { + Color aMaskColor( 0x00, 0x00, 0xFF ); + pSVData->maCtrlData.mpPinImgList->InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_PIN, *pResMgr ), 4, + &aMaskColor, NULL, NULL, 0); + } + } + + // Image ermitteln und zurueckgeben + USHORT nId; + if ( nStyle & BUTTON_DRAW_PRESSED ) + { + if ( bPinIn ) + nId = 4; + else + nId = 3; + } + else + { + if ( bPinIn ) + nId = 2; + else + nId = 1; + } + rImage = pSVData->maCtrlData.mpPinImgList->GetImage( nId ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCalcSymbolRect( Rectangle& rRect ) +{ + // Den Rand den der Button in der nicht Default-Darstellung freilaesst, + // dazuaddieren, da wir diesen bei kleinen Buttons mit ausnutzen wollen + rRect.Left()--; + rRect.Top()--; + rRect.Right()++; + rRect.Bottom()++; + + // Zwischen dem Symbol und dem Button-Rand lassen wir 5% Platz + long nExtraWidth = ((rRect.GetWidth()*50)+500)/1000; + long nExtraHeight = ((rRect.GetHeight()*50)+500)/1000; + rRect.Left() += nExtraWidth; + rRect.Right() -= nExtraWidth; + rRect.Top() += nExtraHeight; + rRect.Bottom() -= nExtraHeight; +} + +// ----------------------------------------------------------------------- + +static void ImplDrawBrdWinSymbol( OutputDevice* pDev, + const Rectangle& rRect, SymbolType eSymbol ) +{ + // Zwischen dem Symbol und dem Button lassen wir 5% Platz + DecorationView aDecoView( pDev ); + Rectangle aTempRect = rRect; + Window::ImplCalcSymbolRect( aTempRect ); + aDecoView.DrawSymbol( aTempRect, eSymbol, + pDev->GetSettings().GetStyleSettings().GetButtonTextColor(), 0 ); +} + +// ----------------------------------------------------------------------- + +static void ImplDrawBrdWinSymbolButton( OutputDevice* pDev, + const Rectangle& rRect, + SymbolType eSymbol, USHORT nState ) +{ + BOOL bMouseOver = (nState & BUTTON_DRAW_HIGHLIGHT) != 0; + nState &= ~BUTTON_DRAW_HIGHLIGHT; + + Rectangle aTempRect; + Window *pWin = dynamic_cast< Window* >(pDev); + if( pWin ) + { + if( bMouseOver ) + { + // provide a bright background for selection effect + pWin->SetFillColor( pDev->GetSettings().GetStyleSettings().GetWindowColor() ); + pWin->SetLineColor(); + pWin->DrawRect( rRect ); + pWin->DrawSelectionBackground( rRect, 2, (nState & BUTTON_DRAW_PRESSED) ? TRUE : FALSE, + TRUE, FALSE ); + } + aTempRect = rRect; + aTempRect.nLeft+=3; + aTempRect.nRight-=4; + aTempRect.nTop+=3; + aTempRect.nBottom-=4; + } + else + { + DecorationView aDecoView( pDev ); + aTempRect = aDecoView.DrawButton( rRect, nState|BUTTON_DRAW_FLAT ); + } + ImplDrawBrdWinSymbol( pDev, aTempRect, eSymbol ); +} + + +// ======================================================================= + +// ------------------------ +// - ImplBorderWindowView - +// ------------------------ + +ImplBorderWindowView::~ImplBorderWindowView() +{ +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::MouseMove( const MouseEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::MouseButtonDown( const MouseEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::Tracking( const TrackingEvent& ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +String ImplBorderWindowView::RequestHelp( const Point&, Rectangle& ) +{ + return String(); +} + +// ----------------------------------------------------------------------- + +Rectangle ImplBorderWindowView::GetMenuRect() const +{ + return Rectangle(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindowView::ImplInitTitle( ImplBorderFrameData* pData ) +{ + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + + if ( !(pBorderWindow->GetStyle() & WB_MOVEABLE) || + (pData->mnTitleType == BORDERWINDOW_TITLE_NONE) ) + { + pData->mnTitleType = BORDERWINDOW_TITLE_NONE; + pData->mnTitleHeight = 0; + } + else + { + const StyleSettings& rStyleSettings = pData->mpOutDev->GetSettings().GetStyleSettings(); + if ( pData->mnTitleType == BORDERWINDOW_TITLE_TEAROFF ) + pData->mnTitleHeight = rStyleSettings.GetTearOffTitleHeight(); + else + { + if ( pData->mnTitleType == BORDERWINDOW_TITLE_SMALL ) + { + pBorderWindow->SetPointFont( rStyleSettings.GetFloatTitleFont() ); + pData->mnTitleHeight = rStyleSettings.GetFloatTitleHeight(); + } + else // pData->mnTitleType == BORDERWINDOW_TITLE_NORMAL + { + pBorderWindow->SetPointFont( rStyleSettings.GetTitleFont() ); + pData->mnTitleHeight = rStyleSettings.GetTitleHeight(); + } + long nTextHeight = pBorderWindow->GetTextHeight(); + if ( nTextHeight > pData->mnTitleHeight ) + pData->mnTitleHeight = nTextHeight; + } + } +} + +// ----------------------------------------------------------------------- + +USHORT ImplBorderWindowView::ImplHitTest( ImplBorderFrameData* pData, const Point& rPos ) +{ + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + + if ( pData->maTitleRect.IsInside( rPos ) ) + { + if ( pData->maCloseRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_CLOSE; + else if ( pData->maRollRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_ROLL; + else if ( pData->maMenuRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_MENU; + else if ( pData->maDockRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_DOCK; + else if ( pData->maHideRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_HIDE; + else if ( pData->maHelpRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_HELP; + else if ( pData->maPinRect.IsInside( rPos ) ) + return BORDERWINDOW_HITTEST_PIN; + else + return BORDERWINDOW_HITTEST_TITLE; + } + + if ( (pBorderWindow->GetStyle() & WB_SIZEABLE) && + !pBorderWindow->mbRollUp ) + { + long nSizeWidth = pData->mnNoTitleTop+pData->mnTitleHeight; + if ( nSizeWidth < 16 ) + nSizeWidth = 16; + + // no corner resize for floating toolbars, which would lead to jumps while formatting + // setting nSizeWidth = 0 will only return pure left,top,right,bottom + if( pBorderWindow->GetStyle() & WB_OWNERDRAWDECORATION ) + nSizeWidth = 0; + + if ( rPos.X() < pData->mnLeftBorder ) + { + if ( rPos.Y() < nSizeWidth ) + return BORDERWINDOW_HITTEST_TOPLEFT; + else if ( rPos.Y() >= pData->mnHeight-nSizeWidth ) + return BORDERWINDOW_HITTEST_BOTTOMLEFT; + else + return BORDERWINDOW_HITTEST_LEFT; + } + else if ( rPos.X() >= pData->mnWidth-pData->mnRightBorder ) + { + if ( rPos.Y() < nSizeWidth ) + return BORDERWINDOW_HITTEST_TOPRIGHT; + else if ( rPos.Y() >= pData->mnHeight-nSizeWidth ) + return BORDERWINDOW_HITTEST_BOTTOMRIGHT; + else + return BORDERWINDOW_HITTEST_RIGHT; + } + else if ( rPos.Y() < pData->mnNoTitleTop ) + { + if ( rPos.X() < nSizeWidth ) + return BORDERWINDOW_HITTEST_TOPLEFT; + else if ( rPos.X() >= pData->mnWidth-nSizeWidth ) + return BORDERWINDOW_HITTEST_TOPRIGHT; + else + return BORDERWINDOW_HITTEST_TOP; + } + else if ( rPos.Y() >= pData->mnHeight-pData->mnBottomBorder ) + { + if ( rPos.X() < nSizeWidth ) + return BORDERWINDOW_HITTEST_BOTTOMLEFT; + else if ( rPos.X() >= pData->mnWidth-nSizeWidth ) + return BORDERWINDOW_HITTEST_BOTTOMRIGHT; + else + return BORDERWINDOW_HITTEST_BOTTOM; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::ImplMouseMove( ImplBorderFrameData* pData, const MouseEvent& rMEvt ) +{ + USHORT oldCloseState = pData->mnCloseState; + USHORT oldMenuState = pData->mnMenuState; + pData->mnCloseState &= ~BUTTON_DRAW_HIGHLIGHT; + pData->mnMenuState &= ~BUTTON_DRAW_HIGHLIGHT; + + Point aMousePos = rMEvt.GetPosPixel(); + USHORT nHitTest = ImplHitTest( pData, aMousePos ); + PointerStyle ePtrStyle = POINTER_ARROW; + if ( nHitTest & BORDERWINDOW_HITTEST_LEFT ) + ePtrStyle = POINTER_WINDOW_WSIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_RIGHT ) + ePtrStyle = POINTER_WINDOW_ESIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_TOP ) + ePtrStyle = POINTER_WINDOW_NSIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOM ) + ePtrStyle = POINTER_WINDOW_SSIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_TOPLEFT ) + ePtrStyle = POINTER_WINDOW_NWSIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOMRIGHT ) + ePtrStyle = POINTER_WINDOW_SESIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_TOPRIGHT ) + ePtrStyle = POINTER_WINDOW_NESIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_BOTTOMLEFT ) + ePtrStyle = POINTER_WINDOW_SWSIZE; + else if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE ) + pData->mnCloseState |= BUTTON_DRAW_HIGHLIGHT; + else if ( nHitTest & BORDERWINDOW_HITTEST_MENU ) + pData->mnMenuState |= BUTTON_DRAW_HIGHLIGHT; + pData->mpBorderWindow->SetPointer( Pointer( ePtrStyle ) ); + + if( pData->mnCloseState != oldCloseState ) + pData->mpBorderWindow->Invalidate( pData->maCloseRect ); + if( pData->mnMenuState != oldMenuState ) + pData->mpBorderWindow->Invalidate( pData->maMenuRect ); + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::ImplMouseButtonDown( ImplBorderFrameData* pData, const MouseEvent& rMEvt ) +{ + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + + if ( rMEvt.IsLeft() || rMEvt.IsRight() ) + { + pData->maMouseOff = rMEvt.GetPosPixel(); + pData->mnHitTest = ImplHitTest( pData, pData->maMouseOff ); + USHORT nDragFullTest = 0; + if ( pData->mnHitTest ) + { + BOOL bTracking = TRUE; + BOOL bHitTest = TRUE; + + if ( pData->mnHitTest & BORDERWINDOW_HITTEST_CLOSE ) + { + pData->mnCloseState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_CLOSE ); + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_ROLL ) + { + pData->mnRollState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_ROLL ); + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_DOCK ) + { + pData->mnDockState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_DOCK ); + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_MENU ) + { + pData->mnMenuState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_MENU ); + + // call handler already on mouse down + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + pClientWindow->TitleButtonClick( TITLE_BUTTON_MENU ); + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HIDE ) + { + pData->mnHideState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HIDE ); + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HELP ) + { + pData->mnHelpState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HELP ); + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_PIN ) + { + pData->mnPinState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_PIN ); + } + else + { + if ( rMEvt.GetClicks() == 1 ) + { + if ( bTracking ) + { + Point aPos = pBorderWindow->GetPosPixel(); + Size aSize = pBorderWindow->GetOutputSizePixel(); + pData->mnTrackX = aPos.X(); + pData->mnTrackY = aPos.Y(); + pData->mnTrackWidth = aSize.Width(); + pData->mnTrackHeight = aSize.Height(); + + if ( pData->mnHitTest & BORDERWINDOW_HITTEST_TITLE ) + nDragFullTest = DRAGFULL_OPTION_WINDOWMOVE; + else + nDragFullTest = DRAGFULL_OPTION_WINDOWSIZE; + } + } + else + { + bTracking = FALSE; + + if ( (pData->mnHitTest & BORDERWINDOW_DRAW_TITLE) && + ((rMEvt.GetClicks() % 2) == 0) ) + { + pData->mnHitTest = 0; + bHitTest = FALSE; + + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + if ( TRUE /*pBorderWindow->mbDockBtn*/ ) // always perform docking on double click, no button required + pClientWindow->TitleButtonClick( TITLE_BUTTON_DOCKING ); + else if ( pBorderWindow->GetStyle() & WB_ROLLABLE ) + { + if ( pClientWindow->IsRollUp() ) + pClientWindow->RollDown(); + else + pClientWindow->RollUp(); + pClientWindow->Roll(); + } + } + } + } + } + + if ( bTracking ) + { + pData->mbDragFull = FALSE; + if ( nDragFullTest ) + pData->mbDragFull = TRUE; // always fulldrag for proper docking, ignore system settings + pBorderWindow->StartTracking(); + } + else if ( bHitTest ) + pData->mnHitTest = 0; + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplBorderWindowView::ImplTracking( ImplBorderFrameData* pData, const TrackingEvent& rTEvt ) +{ + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + + if ( rTEvt.IsTrackingEnded() ) + { + USHORT nHitTest = pData->mnHitTest; + pData->mnHitTest = 0; + + if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE ) + { + if ( pData->mnCloseState & BUTTON_DRAW_PRESSED ) + { + pData->mnCloseState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_CLOSE ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + // dispatch to correct window type (why is Close() not virtual ??? ) + // TODO: make Close() virtual + Window *pWin = pBorderWindow->ImplGetClientWindow()->ImplGetWindow(); + SystemWindow *pSysWin = dynamic_cast<SystemWindow* >(pWin); + DockingWindow *pDockWin = dynamic_cast<DockingWindow*>(pWin); + if ( pSysWin ) + pSysWin->Close(); + else if ( pDockWin ) + pDockWin->Close(); + } + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_ROLL ) + { + if ( pData->mnRollState & BUTTON_DRAW_PRESSED ) + { + pData->mnRollState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_ROLL ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + if ( pClientWindow->IsRollUp() ) + pClientWindow->RollDown(); + else + pClientWindow->RollUp(); + pClientWindow->Roll(); + } + } + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_DOCK ) + { + if ( pData->mnDockState & BUTTON_DRAW_PRESSED ) + { + pData->mnDockState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_DOCK ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + pClientWindow->TitleButtonClick( TITLE_BUTTON_DOCKING ); + } + } + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_MENU ) + { + if ( pData->mnMenuState & BUTTON_DRAW_PRESSED ) + { + pData->mnMenuState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_MENU ); + + // handler already called on mouse down + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_HIDE ) + { + if ( pData->mnHideState & BUTTON_DRAW_PRESSED ) + { + pData->mnHideState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HIDE ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + pClientWindow->TitleButtonClick( TITLE_BUTTON_HIDE ); + } + } + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_HELP ) + { + if ( pData->mnHelpState & BUTTON_DRAW_PRESSED ) + { + pData->mnHelpState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HELP ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + } + } + } + else if ( nHitTest & BORDERWINDOW_HITTEST_PIN ) + { + if ( pData->mnPinState & BUTTON_DRAW_PRESSED ) + { + pData->mnPinState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_PIN ); + + // Bei Abbruch kein Click-Handler rufen + if ( !rTEvt.IsTrackingCanceled() ) + { + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + SystemWindow* pClientWindow = (SystemWindow*)(pBorderWindow->ImplGetClientWindow()); + pClientWindow->SetPin( !pClientWindow->IsPined() ); + pClientWindow->Pin(); + } + } + } + } + else + { + if ( pData->mbDragFull ) + { + // Bei Abbruch alten Zustand wieder herstellen + if ( rTEvt.IsTrackingCanceled() ) + pBorderWindow->SetPosSizePixel( Point( pData->mnTrackX, pData->mnTrackY ), Size( pData->mnTrackWidth, pData->mnTrackHeight ) ); + } + else + { + pBorderWindow->HideTracking(); + if ( !rTEvt.IsTrackingCanceled() ) + pBorderWindow->SetPosSizePixel( Point( pData->mnTrackX, pData->mnTrackY ), Size( pData->mnTrackWidth, pData->mnTrackHeight ) ); + } + + if ( !rTEvt.IsTrackingCanceled() ) + { + if ( pBorderWindow->ImplGetClientWindow()->ImplIsFloatingWindow() ) + { + if ( ((FloatingWindow*)pBorderWindow->ImplGetClientWindow())->IsInPopupMode() ) + ((FloatingWindow*)pBorderWindow->ImplGetClientWindow())->EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF ); + } + } + } + } + else if ( !rTEvt.GetMouseEvent().IsSynthetic() ) + { + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + + if ( pData->mnHitTest & BORDERWINDOW_HITTEST_CLOSE ) + { + if ( pData->maCloseRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnCloseState & BUTTON_DRAW_PRESSED) ) + { + pData->mnCloseState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_CLOSE ); + } + } + else + { + if ( pData->mnCloseState & BUTTON_DRAW_PRESSED ) + { + pData->mnCloseState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_CLOSE ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_ROLL ) + { + if ( pData->maRollRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnRollState & BUTTON_DRAW_PRESSED) ) + { + pData->mnRollState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_ROLL ); + } + } + else + { + if ( pData->mnRollState & BUTTON_DRAW_PRESSED ) + { + pData->mnRollState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_ROLL ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_DOCK ) + { + if ( pData->maDockRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnDockState & BUTTON_DRAW_PRESSED) ) + { + pData->mnDockState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_DOCK ); + } + } + else + { + if ( pData->mnDockState & BUTTON_DRAW_PRESSED ) + { + pData->mnDockState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_DOCK ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_MENU ) + { + if ( pData->maMenuRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnMenuState & BUTTON_DRAW_PRESSED) ) + { + pData->mnMenuState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_MENU ); + + } + } + else + { + if ( pData->mnMenuState & BUTTON_DRAW_PRESSED ) + { + pData->mnMenuState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_MENU ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HIDE ) + { + if ( pData->maHideRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnHideState & BUTTON_DRAW_PRESSED) ) + { + pData->mnHideState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HIDE ); + } + } + else + { + if ( pData->mnHideState & BUTTON_DRAW_PRESSED ) + { + pData->mnHideState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HIDE ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_HELP ) + { + if ( pData->maHelpRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnHelpState & BUTTON_DRAW_PRESSED) ) + { + pData->mnHelpState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HELP ); + } + } + else + { + if ( pData->mnHelpState & BUTTON_DRAW_PRESSED ) + { + pData->mnHelpState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_HELP ); + } + } + } + else if ( pData->mnHitTest & BORDERWINDOW_HITTEST_PIN ) + { + if ( pData->maPinRect.IsInside( aMousePos ) ) + { + if ( !(pData->mnPinState & BUTTON_DRAW_PRESSED) ) + { + pData->mnPinState |= BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_PIN ); + } + } + else + { + if ( pData->mnPinState & BUTTON_DRAW_PRESSED ) + { + pData->mnPinState &= ~BUTTON_DRAW_PRESSED; + DrawWindow( BORDERWINDOW_DRAW_PIN ); + } + } + } + else + { + /* + // adjusting mousepos not required, we allow the whole screen (no desktop anymore...) + Point aFrameMousePos = pBorderWindow->ImplOutputToFrame( aMousePos ); + Size aFrameSize = pBorderWindow->ImplGetFrameWindow()->GetOutputSizePixel(); + if ( aFrameMousePos.X() < 0 ) + aFrameMousePos.X() = 0; + if ( aFrameMousePos.Y() < 0 ) + aFrameMousePos.Y() = 0; + if ( aFrameMousePos.X() > aFrameSize.Width()-1 ) + aFrameMousePos.X() = aFrameSize.Width()-1; + if ( aFrameMousePos.Y() > aFrameSize.Height()-1 ) + aFrameMousePos.Y() = aFrameSize.Height()-1; + aMousePos = pBorderWindow->ImplFrameToOutput( aFrameMousePos ); + */ + + aMousePos.X() -= pData->maMouseOff.X(); + aMousePos.Y() -= pData->maMouseOff.Y(); + + if ( pData->mnHitTest & BORDERWINDOW_HITTEST_TITLE ) + { + pData->mpBorderWindow->SetPointer( Pointer( POINTER_MOVE ) ); + + Point aPos = pBorderWindow->GetPosPixel(); + aPos.X() += aMousePos.X(); + aPos.Y() += aMousePos.Y(); + if ( pData->mbDragFull ) + { + pBorderWindow->SetPosPixel( aPos ); + pBorderWindow->ImplUpdateAll(); + pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll(); + } + else + { + pData->mnTrackX = aPos.X(); + pData->mnTrackY = aPos.Y(); + pBorderWindow->ShowTracking( Rectangle( pBorderWindow->ScreenToOutputPixel( aPos ), pBorderWindow->GetOutputSizePixel() ), SHOWTRACK_BIG ); + } + } + else + { + Point aOldPos = pBorderWindow->GetPosPixel(); + Size aSize = pBorderWindow->GetSizePixel(); + Rectangle aNewRect( aOldPos, aSize ); + long nOldWidth = aSize.Width(); + long nOldHeight = aSize.Height(); + long nBorderWidth = pData->mnLeftBorder+pData->mnRightBorder; + long nBorderHeight = pData->mnTopBorder+pData->mnBottomBorder; + long nMinWidth = pBorderWindow->mnMinWidth+nBorderWidth; + long nMinHeight = pBorderWindow->mnMinHeight+nBorderHeight; + long nMinWidth2 = nBorderWidth; + long nMaxWidth = pBorderWindow->mnMaxWidth+nBorderWidth; + long nMaxHeight = pBorderWindow->mnMaxHeight+nBorderHeight; + + if ( pData->mnTitleHeight ) + { + nMinWidth2 += 4; + + if ( pBorderWindow->GetStyle() & WB_CLOSEABLE ) + nMinWidth2 += pData->maCloseRect.GetWidth(); + } + if ( nMinWidth2 > nMinWidth ) + nMinWidth = nMinWidth2; + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_LEFT | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_BOTTOMLEFT) ) + { + aNewRect.Left() += aMousePos.X(); + if ( aNewRect.GetWidth() < nMinWidth ) + aNewRect.Left() = aNewRect.Right()-nMinWidth+1; + else if ( aNewRect.GetWidth() > nMaxWidth ) + aNewRect.Left() = aNewRect.Right()-nMaxWidth+1; + } + else if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_RIGHT | BORDERWINDOW_HITTEST_TOPRIGHT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) ) + { + aNewRect.Right() += aMousePos.X(); + if ( aNewRect.GetWidth() < nMinWidth ) + aNewRect.Right() = aNewRect.Left()+nMinWidth+1; + else if ( aNewRect.GetWidth() > nMaxWidth ) + aNewRect.Right() = aNewRect.Left()+nMaxWidth+1; + } + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_TOP | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_TOPRIGHT) ) + { + aNewRect.Top() += aMousePos.Y(); + if ( aNewRect.GetHeight() < nMinHeight ) + aNewRect.Top() = aNewRect.Bottom()-nMinHeight+1; + else if ( aNewRect.GetHeight() > nMaxHeight ) + aNewRect.Top() = aNewRect.Bottom()-nMaxHeight+1; + } + else if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_BOTTOM | BORDERWINDOW_HITTEST_BOTTOMLEFT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) ) + { + aNewRect.Bottom() += aMousePos.Y(); + if ( aNewRect.GetHeight() < nMinHeight ) + aNewRect.Bottom() = aNewRect.Top()+nMinHeight+1; + else if ( aNewRect.GetHeight() > nMaxHeight ) + aNewRect.Bottom() = aNewRect.Top()+nMaxHeight+1; + } + + // call Resizing-Handler for SystemWindows + if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) + { + // adjust size for Resizing-call + aSize = aNewRect.GetSize(); + aSize.Width() -= nBorderWidth; + aSize.Height() -= nBorderHeight; + ((SystemWindow*)pBorderWindow->ImplGetClientWindow())->Resizing( aSize ); + aSize.Width() += nBorderWidth; + aSize.Height() += nBorderHeight; + if ( aSize.Width() < nMinWidth ) + aSize.Width() = nMinWidth; + if ( aSize.Height() < nMinHeight ) + aSize.Height() = nMinHeight; + if ( aSize.Width() > nMaxWidth ) + aSize.Width() = nMaxWidth; + if ( aSize.Height() > nMaxHeight ) + aSize.Height() = nMaxHeight; + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_LEFT | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_BOTTOMLEFT) ) + aNewRect.Left() = aNewRect.Right()-aSize.Width()+1; + else + aNewRect.Right() = aNewRect.Left()+aSize.Width()-1; + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_TOP | BORDERWINDOW_HITTEST_TOPLEFT | BORDERWINDOW_HITTEST_TOPRIGHT) ) + aNewRect.Top() = aNewRect.Bottom()-aSize.Height()+1; + else + aNewRect.Bottom() = aNewRect.Top()+aSize.Height()-1; + } + + if ( pData->mbDragFull ) + { + // no move (only resize) if position did not change + if( aOldPos != aNewRect.TopLeft() ) + pBorderWindow->SetPosSizePixel( aNewRect.Left(), aNewRect.Top(), + aNewRect.GetWidth(), aNewRect.GetHeight(), WINDOW_POSSIZE_POSSIZE ); + else + pBorderWindow->SetPosSizePixel( aNewRect.Left(), aNewRect.Top(), + aNewRect.GetWidth(), aNewRect.GetHeight(), WINDOW_POSSIZE_SIZE ); + + pBorderWindow->ImplUpdateAll(); + pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll(); + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_RIGHT | BORDERWINDOW_HITTEST_TOPRIGHT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) ) + pData->maMouseOff.X() += aNewRect.GetWidth()-nOldWidth; + if ( pData->mnHitTest & (BORDERWINDOW_HITTEST_BOTTOM | BORDERWINDOW_HITTEST_BOTTOMLEFT | BORDERWINDOW_HITTEST_BOTTOMRIGHT) ) + pData->maMouseOff.Y() += aNewRect.GetHeight()-nOldHeight; + } + else + { + pData->mnTrackX = aNewRect.Left(); + pData->mnTrackY = aNewRect.Top(); + pData->mnTrackWidth = aNewRect.GetWidth(); + pData->mnTrackHeight = aNewRect.GetHeight(); + pBorderWindow->ShowTracking( Rectangle( pBorderWindow->ScreenToOutputPixel( aNewRect.TopLeft() ), aNewRect.GetSize() ), SHOWTRACK_BIG ); + } + } + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +String ImplBorderWindowView::ImplRequestHelp( ImplBorderFrameData* pData, + const Point& rPos, + Rectangle& rHelpRect ) +{ + USHORT nHelpId = 0; + String aHelpStr; + USHORT nHitTest = ImplHitTest( pData, rPos ); + if ( nHitTest ) + { + if ( nHitTest & BORDERWINDOW_HITTEST_CLOSE ) + { + nHelpId = SV_HELPTEXT_CLOSE; + rHelpRect = pData->maCloseRect; + } + else if ( nHitTest & BORDERWINDOW_HITTEST_ROLL ) + { + if ( pData->mpBorderWindow->mbRollUp ) + nHelpId = SV_HELPTEXT_ROLLDOWN; + else + nHelpId = SV_HELPTEXT_ROLLUP; + rHelpRect = pData->maRollRect; + } + else if ( nHitTest & BORDERWINDOW_HITTEST_DOCK ) + { + nHelpId = SV_HELPTEXT_MAXIMIZE; + rHelpRect = pData->maDockRect; + } + /* no help string available + else if ( nHitTest & BORDERWINDOW_HITTEST_MENU ) + { + nHelpId = SV_HELPTEXT_MENU; + rHelpRect = pData->maMenuRect; + }*/ + else if ( nHitTest & BORDERWINDOW_HITTEST_HIDE ) + { + nHelpId = SV_HELPTEXT_MINIMIZE; + rHelpRect = pData->maHideRect; + } + else if ( nHitTest & BORDERWINDOW_HITTEST_HELP ) + { + nHelpId = SV_HELPTEXT_HELP; + rHelpRect = pData->maHelpRect; + } + else if ( nHitTest & BORDERWINDOW_HITTEST_PIN ) + { + nHelpId = SV_HELPTEXT_ALWAYSVISIBLE; + rHelpRect = pData->maPinRect; + } + else if ( nHitTest & BORDERWINDOW_HITTEST_TITLE ) + { + if( !pData->maTitleRect.IsEmpty() ) + { + // tooltip only if title truncated + if( pData->mbTitleClipped ) + { + rHelpRect = pData->maTitleRect; + // no help id, use window title as help string + aHelpStr = pData->mpBorderWindow->GetText(); + } + } + } + } + + if( nHelpId && ImplGetResMgr() ) + aHelpStr = String( ResId( nHelpId, *ImplGetResMgr() ) ); + + return aHelpStr; +} + +// ----------------------------------------------------------------------- + +long ImplBorderWindowView::ImplCalcTitleWidth( const ImplBorderFrameData* pData ) const +{ + // kein sichtbarer Title, dann auch keine Breite + if ( !pData->mnTitleHeight ) + return 0; + + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + long nTitleWidth = pBorderWindow->GetTextWidth( pBorderWindow->GetText() )+6; + nTitleWidth += pData->maPinRect.GetWidth(); + nTitleWidth += pData->maCloseRect.GetWidth(); + nTitleWidth += pData->maRollRect.GetWidth(); + nTitleWidth += pData->maDockRect.GetWidth(); + nTitleWidth += pData->maMenuRect.GetWidth(); + nTitleWidth += pData->maHideRect.GetWidth(); + nTitleWidth += pData->maHelpRect.GetWidth(); + nTitleWidth += pData->mnLeftBorder+pData->mnRightBorder; + return nTitleWidth; +} + +// ======================================================================= + +// -------------------------- +// - ImplNoBorderWindowView - +// -------------------------- + +ImplNoBorderWindowView::ImplNoBorderWindowView( ImplBorderWindow* ) +{ +} + +// ----------------------------------------------------------------------- + +void ImplNoBorderWindowView::Init( OutputDevice*, long, long ) +{ +} + +// ----------------------------------------------------------------------- + +void ImplNoBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + rLeftBorder = 0; + rTopBorder = 0; + rRightBorder = 0; + rBottomBorder = 0; +} + +// ----------------------------------------------------------------------- + +long ImplNoBorderWindowView::CalcTitleWidth() const +{ + return 0; +} + +// ----------------------------------------------------------------------- + +void ImplNoBorderWindowView::DrawWindow( USHORT, OutputDevice*, const Point* ) +{ +} + +// ======================================================================= + +// ----------------------------- +// - ImplSmallBorderWindowView - +// ----------------------------- + +// ======================================================================= + +ImplSmallBorderWindowView::ImplSmallBorderWindowView( ImplBorderWindow* pBorderWindow ) +{ + mpBorderWindow = pBorderWindow; +} + +// ----------------------------------------------------------------------- + +void ImplSmallBorderWindowView::Init( OutputDevice* pDev, long nWidth, long nHeight ) +{ + mpOutDev = pDev; + mnWidth = nWidth; + mnHeight = nHeight; + mbNWFBorder = false; + + USHORT nBorderStyle = mpBorderWindow->GetBorderStyle(); + if ( nBorderStyle & WINDOW_BORDER_NOBORDER ) + { + mnLeftBorder = 0; + mnTopBorder = 0; + mnRightBorder = 0; + mnBottomBorder = 0; + } + else + { + // FIXME: this is currently only on aqua, check with other + // platforms + if( ImplGetSVData()->maNWFData.mbNoFocusRects ) + { + // for native widget drawing we must find out what + // control this border belongs to + Window *pWin = NULL, *pCtrl = NULL; + if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW ) + pWin = (Window*) mpOutDev; + + ControlType aCtrlType = 0; + if( pWin && (pCtrl = mpBorderWindow->GetWindow( WINDOW_CLIENT )) != NULL ) + { + switch( pCtrl->GetType() ) + { + case WINDOW_LISTBOX: + if( pCtrl->GetStyle() & WB_DROPDOWN ) + { + aCtrlType = CTRL_LISTBOX; + mbNWFBorder = true; + } + break; + case WINDOW_COMBOBOX: + if( pCtrl->GetStyle() & WB_DROPDOWN ) + { + aCtrlType = CTRL_COMBOBOX; + mbNWFBorder = true; + } + break; + case WINDOW_MULTILINEEDIT: + aCtrlType = CTRL_MULTILINE_EDITBOX; + mbNWFBorder = true; + break; + case WINDOW_EDIT: + case WINDOW_PATTERNFIELD: + case WINDOW_METRICFIELD: + case WINDOW_CURRENCYFIELD: + case WINDOW_DATEFIELD: + case WINDOW_TIMEFIELD: + case WINDOW_LONGCURRENCYFIELD: + case WINDOW_NUMERICFIELD: + case WINDOW_SPINFIELD: + mbNWFBorder = true; + aCtrlType = (pCtrl->GetStyle() & WB_SPIN) ? CTRL_SPINBOX : CTRL_EDITBOX; + break; + default: + break; + } + } + if( mbNWFBorder ) + { + ImplControlValue aControlValue; + Rectangle aCtrlRegion( (const Point&)Point(), Size( mnWidth < 10 ? 10 : mnWidth, mnHeight < 10 ? 10 : mnHeight ) ); + Rectangle aBounds( aCtrlRegion ); + Rectangle aContent( aCtrlRegion ); + if( pWin->GetNativeControlRegion( aCtrlType, PART_ENTIRE_CONTROL, aCtrlRegion, + CTRL_STATE_ENABLED, aControlValue, rtl::OUString(), + aBounds, aContent ) ) + { + mnLeftBorder = aContent.Left() - aBounds.Left(); + mnRightBorder = aBounds.Right() - aContent.Right(); + mnTopBorder = aContent.Top() - aBounds.Top(); + mnBottomBorder = aBounds.Bottom() - aContent.Bottom(); + if( mnWidth && mnHeight ) + { + + mpBorderWindow->SetPaintTransparent( TRUE ); + mpBorderWindow->SetBackground(); + pCtrl->SetPaintTransparent( TRUE ); + + Window* pCompoundParent = NULL; + if( pWin->GetParent() && pWin->GetParent()->IsCompoundControl() ) + pCompoundParent = pWin->GetParent(); + + if( pCompoundParent ) + pCompoundParent->SetPaintTransparent( TRUE ); + + if( mnWidth < aBounds.GetWidth() || mnHeight < aBounds.GetHeight() ) + { + if( ! pCompoundParent ) // compound controls have to fix themselves + { + Point aPos( mpBorderWindow->GetPosPixel() ); + if( mnWidth < aBounds.GetWidth() ) + aPos.X() -= (aBounds.GetWidth() - mnWidth) / 2; + if( mnHeight < aBounds.GetHeight() ) + aPos.Y() -= (aBounds.GetHeight() - mnHeight) / 2; + mpBorderWindow->SetPosSizePixel( aPos, aBounds.GetSize() ); + } + } + } + } + else + mbNWFBorder = false; + } + } + + if( ! mbNWFBorder ) + { + USHORT nStyle = FRAME_DRAW_NODRAW; + // Wenn Border umgesetzt wurde oder BorderWindow ein Frame-Fenster + // ist, dann Border nach aussen + if ( (nBorderStyle & WINDOW_BORDER_DOUBLEOUT) || mpBorderWindow->mbSmallOutBorder ) + nStyle |= FRAME_DRAW_DOUBLEOUT; + else + nStyle |= FRAME_DRAW_DOUBLEIN; + if ( nBorderStyle & WINDOW_BORDER_MONO ) + nStyle |= FRAME_DRAW_MONO; + + DecorationView aDecoView( mpOutDev ); + Rectangle aRect( 0, 0, 10, 10 ); + Rectangle aCalcRect = aDecoView.DrawFrame( aRect, nStyle ); + mnLeftBorder = aCalcRect.Left(); + mnTopBorder = aCalcRect.Top(); + mnRightBorder = aRect.Right()-aCalcRect.Right(); + mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom(); + } + } +} + +// ----------------------------------------------------------------------- + +void ImplSmallBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + rLeftBorder = mnLeftBorder; + rTopBorder = mnTopBorder; + rRightBorder = mnRightBorder; + rBottomBorder = mnBottomBorder; +} + +// ----------------------------------------------------------------------- + +long ImplSmallBorderWindowView::CalcTitleWidth() const +{ + return 0; +} + +// ----------------------------------------------------------------------- + +void ImplSmallBorderWindowView::DrawWindow( USHORT nDrawFlags, OutputDevice*, const Point* ) +{ + USHORT nBorderStyle = mpBorderWindow->GetBorderStyle(); + if ( nBorderStyle & WINDOW_BORDER_NOBORDER ) + return; + + BOOL bNativeOK = FALSE; + // for native widget drawing we must find out what + // control this border belongs to + Window *pWin = NULL, *pCtrl = NULL; + if( mpOutDev->GetOutDevType() == OUTDEV_WINDOW ) + pWin = (Window*) mpOutDev; + + ControlType aCtrlType = 0; + ControlPart aCtrlPart = PART_ENTIRE_CONTROL; + + if( pWin && (pCtrl = mpBorderWindow->GetWindow( WINDOW_CLIENT )) != NULL ) + { + switch( pCtrl->GetType() ) + { + case WINDOW_MULTILINEEDIT: + aCtrlType = CTRL_MULTILINE_EDITBOX; + break; + case WINDOW_EDIT: + case WINDOW_PATTERNFIELD: + case WINDOW_METRICFIELD: + case WINDOW_CURRENCYFIELD: + case WINDOW_DATEFIELD: + case WINDOW_TIMEFIELD: + case WINDOW_LONGCURRENCYFIELD: + case WINDOW_NUMERICFIELD: + case WINDOW_SPINFIELD: + if( pCtrl->GetStyle() & WB_SPIN ) + aCtrlType = CTRL_SPINBOX; + else + aCtrlType = CTRL_EDITBOX; + break; + + case WINDOW_LISTBOX: + case WINDOW_MULTILISTBOX: + case WINDOW_TREELISTBOX: + aCtrlType = CTRL_LISTBOX; + if( pCtrl->GetStyle() & WB_DROPDOWN ) + aCtrlPart = PART_ENTIRE_CONTROL; + else + aCtrlPart = PART_WINDOW; + break; + + case WINDOW_LISTBOXWINDOW: + aCtrlType = CTRL_LISTBOX; + aCtrlPart = PART_WINDOW; + break; + + case WINDOW_COMBOBOX: + case WINDOW_PATTERNBOX: + case WINDOW_NUMERICBOX: + case WINDOW_METRICBOX: + case WINDOW_CURRENCYBOX: + case WINDOW_DATEBOX: + case WINDOW_TIMEBOX: + case WINDOW_LONGCURRENCYBOX: + if( pCtrl->GetStyle() & WB_DROPDOWN ) + { + aCtrlType = CTRL_COMBOBOX; + aCtrlPart = PART_ENTIRE_CONTROL; + } + else + { + aCtrlType = CTRL_LISTBOX; + aCtrlPart = PART_WINDOW; + } + break; + + default: + break; + } + } + + if ( aCtrlType && pCtrl->IsNativeControlSupported(aCtrlType, aCtrlPart) ) + { + ImplControlValue aControlValue; + ControlState nState = CTRL_STATE_ENABLED; + + if ( !pWin->IsEnabled() ) + nState &= ~CTRL_STATE_ENABLED; + if ( pWin->HasFocus() ) + nState |= CTRL_STATE_FOCUSED; + else if( mbNWFBorder ) + { + // FIXME: this is curently only on aqua, see if other platforms can profit + + // FIXME: for aqua focus rings all controls need to support GetNativeControlRegion + // for the dropdown style + if( pCtrl->HasFocus() || pCtrl->HasChildPathFocus() ) + nState |= CTRL_STATE_FOCUSED; + } + + BOOL bMouseOver = FALSE; + Window *pCtrlChild = pCtrl->GetWindow( WINDOW_FIRSTCHILD ); + while( pCtrlChild && (bMouseOver = pCtrlChild->IsMouseOver()) == FALSE ) + pCtrlChild = pCtrlChild->GetWindow( WINDOW_NEXT ); + + if( bMouseOver ) + nState |= CTRL_STATE_ROLLOVER; + + Point aPoint; + Rectangle aCtrlRegion( aPoint, Size( mnWidth, mnHeight ) ); + + Rectangle aBoundingRgn( aPoint, Size( mnWidth, mnHeight ) ); + Rectangle aContentRgn( aCtrlRegion ); + if( ! ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize && + pWin->GetNativeControlRegion( aCtrlType, aCtrlPart, aCtrlRegion, + nState, aControlValue, rtl::OUString(), + aBoundingRgn, aContentRgn )) + { + aCtrlRegion=aContentRgn; + } + + bNativeOK = pWin->DrawNativeControl( aCtrlType, aCtrlPart, aCtrlRegion, nState, + aControlValue, rtl::OUString() ); + + // if the native theme draws the spinbuttons in one call, make sure the proper settings + // are passed, this might force a redraw though.... (TODO: improve) + if ( (aCtrlType == CTRL_SPINBOX) && !pCtrl->IsNativeControlSupported( CTRL_SPINBOX, PART_BUTTON_UP ) ) + { + Edit *pEdit = ((Edit*) pCtrl)->GetSubEdit(); + if ( pEdit ) + pCtrl->Paint( Rectangle() ); // make sure the buttons are also drawn as they might overwrite the border + } + } + + if( bNativeOK ) + return; + + if ( nDrawFlags & BORDERWINDOW_DRAW_FRAME ) + { + if ( nBorderStyle & WINDOW_BORDER_ACTIVE ) + { + Color aColor = mpOutDev->GetSettings().GetStyleSettings().GetHighlightColor(); + mpOutDev->SetLineColor(); + mpOutDev->SetFillColor( aColor ); + mpOutDev->DrawRect( Rectangle( 0, 0, mnWidth-1, mnTopBorder ) ); + mpOutDev->DrawRect( Rectangle( 0, mnHeight-mnBottomBorder, mnWidth-1, mnHeight-1 ) ); + mpOutDev->DrawRect( Rectangle( 0, 0, mnLeftBorder, mnHeight-1 ) ); + mpOutDev->DrawRect( Rectangle( mnWidth-mnRightBorder, 0, mnWidth-1, mnHeight-1 ) ); + } + else + { + USHORT nStyle = 0; + // Wenn Border umgesetzt wurde oder BorderWindow ein Frame-Fenster + // ist, dann Border nach aussen + if ( (nBorderStyle & WINDOW_BORDER_DOUBLEOUT) || mpBorderWindow->mbSmallOutBorder ) + nStyle |= FRAME_DRAW_DOUBLEOUT; + else + nStyle |= FRAME_DRAW_DOUBLEIN; + if ( nBorderStyle & WINDOW_BORDER_MONO ) + nStyle |= FRAME_DRAW_MONO; + if ( nBorderStyle & WINDOW_BORDER_MENU ) + nStyle |= FRAME_DRAW_MENU; + // tell DrawFrame that we're drawing a window border of a frame window to avoid round corners + if( pWin && pWin == pWin->ImplGetFrameWindow() ) + nStyle |= FRAME_DRAW_WINDOWBORDER; + + DecorationView aDecoView( mpOutDev ); + Point aTmpPoint; + Rectangle aInRect( aTmpPoint, Size( mnWidth, mnHeight ) ); + aDecoView.DrawFrame( aInRect, nStyle ); + } + } +} + +// ======================================================================= + +// --------------------------- +// - ImplStdBorderWindowView - +// --------------------------- + +ImplStdBorderWindowView::ImplStdBorderWindowView( ImplBorderWindow* pBorderWindow ) +{ + maFrameData.mpBorderWindow = pBorderWindow; + maFrameData.mbDragFull = FALSE; + maFrameData.mnHitTest = 0; + maFrameData.mnPinState = 0; + maFrameData.mnCloseState = 0; + maFrameData.mnRollState = 0; + maFrameData.mnDockState = 0; + maFrameData.mnMenuState = 0; + maFrameData.mnHideState = 0; + maFrameData.mnHelpState = 0; + maFrameData.mbTitleClipped = 0; + + mpATitleVirDev = NULL; + mpDTitleVirDev = NULL; +} + +// ----------------------------------------------------------------------- + +ImplStdBorderWindowView::~ImplStdBorderWindowView() +{ + if ( mpATitleVirDev ) + delete mpATitleVirDev; + if ( mpDTitleVirDev ) + delete mpDTitleVirDev; +} + +// ----------------------------------------------------------------------- + +BOOL ImplStdBorderWindowView::MouseMove( const MouseEvent& rMEvt ) +{ + return ImplMouseMove( &maFrameData, rMEvt ); +} + +// ----------------------------------------------------------------------- + +BOOL ImplStdBorderWindowView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + return ImplMouseButtonDown( &maFrameData, rMEvt ); +} + +// ----------------------------------------------------------------------- + +BOOL ImplStdBorderWindowView::Tracking( const TrackingEvent& rTEvt ) +{ + return ImplTracking( &maFrameData, rTEvt ); +} + +// ----------------------------------------------------------------------- + +String ImplStdBorderWindowView::RequestHelp( const Point& rPos, Rectangle& rHelpRect ) +{ + return ImplRequestHelp( &maFrameData, rPos, rHelpRect ); +} + +// ----------------------------------------------------------------------- + +Rectangle ImplStdBorderWindowView::GetMenuRect() const +{ + return maFrameData.maMenuRect; +} + +// ----------------------------------------------------------------------- + +void ImplStdBorderWindowView::Init( OutputDevice* pDev, long nWidth, long nHeight ) +{ + ImplBorderFrameData* pData = &maFrameData; + ImplBorderWindow* pBorderWindow = maFrameData.mpBorderWindow; + const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings(); + DecorationView aDecoView( pDev ); + Rectangle aRect( 0, 0, 10, 10 ); + Rectangle aCalcRect = aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEOUT | FRAME_DRAW_NODRAW ); + + pData->mpOutDev = pDev; + pData->mnWidth = nWidth; + pData->mnHeight = nHeight; + + pData->mnTitleType = pBorderWindow->mnTitleType; + pData->mbFloatWindow = pBorderWindow->mbFloatWindow; + + if ( !(pBorderWindow->GetStyle() & WB_MOVEABLE) || (pData->mnTitleType == BORDERWINDOW_TITLE_NONE) ) + pData->mnBorderSize = 0; + else if ( pData->mnTitleType == BORDERWINDOW_TITLE_TEAROFF ) + pData->mnBorderSize = 0; + else + pData->mnBorderSize = rStyleSettings.GetBorderSize(); + pData->mnLeftBorder = aCalcRect.Left(); + pData->mnTopBorder = aCalcRect.Top(); + pData->mnRightBorder = aRect.Right()-aCalcRect.Right(); + pData->mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom(); + pData->mnLeftBorder += pData->mnBorderSize; + pData->mnTopBorder += pData->mnBorderSize; + pData->mnRightBorder += pData->mnBorderSize; + pData->mnBottomBorder += pData->mnBorderSize; + pData->mnNoTitleTop = pData->mnTopBorder; + + ImplInitTitle( &maFrameData ); + if ( pData->mnTitleHeight ) + { + // to improve symbol display force a minum title height + if( pData->mnTitleHeight < MIN_CAPTION_HEIGHT ) + pData->mnTitleHeight = MIN_CAPTION_HEIGHT; + + // set a proper background for drawing + // highlighted buttons in the title + pBorderWindow->SetBackground( rStyleSettings.GetWindowColor() ); + + pData->maTitleRect.Left() = pData->mnLeftBorder; + pData->maTitleRect.Right() = nWidth-pData->mnRightBorder-1; + pData->maTitleRect.Top() = pData->mnTopBorder; + pData->maTitleRect.Bottom() = pData->maTitleRect.Top()+pData->mnTitleHeight-1; + + if ( pData->mnTitleType & (BORDERWINDOW_TITLE_NORMAL | BORDERWINDOW_TITLE_SMALL) ) + { + long nLeft = pData->maTitleRect.Left(); + long nRight = pData->maTitleRect.Right(); + long nItemTop = pData->maTitleRect.Top(); + long nItemBottom = pData->maTitleRect.Bottom(); + nLeft += 1; + nRight -= 3; + nItemTop += 2; + nItemBottom -= 2; + + if ( pBorderWindow->GetStyle() & WB_PINABLE ) + { + Image aImage; + ImplGetPinImage( 0, 0, aImage ); + pData->maPinRect.Top() = nItemTop; + pData->maPinRect.Bottom() = nItemBottom; + pData->maPinRect.Left() = nLeft; + pData->maPinRect.Right() = pData->maPinRect.Left()+aImage.GetSizePixel().Width(); + nLeft += pData->maPinRect.GetWidth()+3; + } + + if ( pBorderWindow->GetStyle() & WB_CLOSEABLE ) + { + pData->maCloseRect.Top() = nItemTop; + pData->maCloseRect.Bottom() = nItemBottom; + pData->maCloseRect.Right() = nRight; + pData->maCloseRect.Left() = pData->maCloseRect.Right()-pData->maCloseRect.GetHeight()+1; + nRight -= pData->maCloseRect.GetWidth()+3; + } + + if ( pBorderWindow->mbMenuBtn ) + { + pData->maMenuRect.Top() = nItemTop; + pData->maMenuRect.Bottom() = nItemBottom; + pData->maMenuRect.Right() = nRight; + pData->maMenuRect.Left() = pData->maMenuRect.Right()-pData->maMenuRect.GetHeight()+1; + nRight -= pData->maMenuRect.GetWidth(); + } + + if ( pBorderWindow->mbDockBtn ) + { + pData->maDockRect.Top() = nItemTop; + pData->maDockRect.Bottom() = nItemBottom; + pData->maDockRect.Right() = nRight; + pData->maDockRect.Left() = pData->maDockRect.Right()-pData->maDockRect.GetHeight()+1; + nRight -= pData->maDockRect.GetWidth(); + if ( !pBorderWindow->mbHideBtn && + !(pBorderWindow->GetStyle() & WB_ROLLABLE) ) + nRight -= 3; + } + + if ( pBorderWindow->mbHideBtn ) + { + pData->maHideRect.Top() = nItemTop; + pData->maHideRect.Bottom() = nItemBottom; + pData->maHideRect.Right() = nRight; + pData->maHideRect.Left() = pData->maHideRect.Right()-pData->maHideRect.GetHeight()+1; + nRight -= pData->maHideRect.GetWidth(); + if ( !(pBorderWindow->GetStyle() & WB_ROLLABLE) ) + nRight -= 3; + } + + if ( pBorderWindow->GetStyle() & WB_ROLLABLE ) + { + pData->maRollRect.Top() = nItemTop; + pData->maRollRect.Bottom() = nItemBottom; + pData->maRollRect.Right() = nRight; + pData->maRollRect.Left() = pData->maRollRect.Right()-pData->maRollRect.GetHeight()+1; + nRight -= pData->maRollRect.GetWidth(); + } + + if ( pBorderWindow->mbHelpBtn ) + { + pData->maHelpRect.Top() = nItemTop; + pData->maHelpRect.Bottom() = nItemBottom; + pData->maHelpRect.Right() = nRight; + pData->maHelpRect.Left() = pData->maHelpRect.Right()-pData->maHelpRect.GetHeight()+1; + nRight -= pData->maHelpRect.GetWidth()+3; + } + } + else + { + pData->maPinRect.SetEmpty(); + pData->maCloseRect.SetEmpty(); + pData->maDockRect.SetEmpty(); + pData->maMenuRect.SetEmpty(); + pData->maHideRect.SetEmpty(); + pData->maRollRect.SetEmpty(); + pData->maHelpRect.SetEmpty(); + } + + pData->mnTopBorder += pData->mnTitleHeight; + } + else + { + pData->maTitleRect.SetEmpty(); + pData->maPinRect.SetEmpty(); + pData->maCloseRect.SetEmpty(); + pData->maDockRect.SetEmpty(); + pData->maMenuRect.SetEmpty(); + pData->maHideRect.SetEmpty(); + pData->maRollRect.SetEmpty(); + pData->maHelpRect.SetEmpty(); + } +} + +// ----------------------------------------------------------------------- + +void ImplStdBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + rLeftBorder = maFrameData.mnLeftBorder; + rTopBorder = maFrameData.mnTopBorder; + rRightBorder = maFrameData.mnRightBorder; + rBottomBorder = maFrameData.mnBottomBorder; +} + +// ----------------------------------------------------------------------- + +long ImplStdBorderWindowView::CalcTitleWidth() const +{ + return ImplCalcTitleWidth( &maFrameData ); +} + +// ----------------------------------------------------------------------- + +void ImplStdBorderWindowView::DrawWindow( USHORT nDrawFlags, OutputDevice* pOutDev, const Point* pOffset ) +{ + ImplBorderFrameData* pData = &maFrameData; + OutputDevice* pDev = pOutDev ? pOutDev : pData->mpOutDev; + ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; + Point aTmpPoint = pOffset ? Point(*pOffset) : Point(); + Rectangle aInRect( aTmpPoint, Size( pData->mnWidth, pData->mnHeight ) ); + const StyleSettings& rStyleSettings = pData->mpOutDev->GetSettings().GetStyleSettings(); + DecorationView aDecoView( pDev ); + Color aFrameColor( rStyleSettings.GetFaceColor() ); + + aFrameColor.DecreaseContrast( (UINT8) (0.50 * 255)); + + // Draw Frame + if ( nDrawFlags & BORDERWINDOW_DRAW_FRAME ) + { + // single line frame + pDev->SetLineColor( aFrameColor ); + pDev->SetFillColor(); + pDev->DrawRect( aInRect ); + aInRect.nLeft++; aInRect.nRight--; + aInRect.nTop++; aInRect.nBottom--; + } + else + aInRect = aDecoView.DrawFrame( aInRect, FRAME_DRAW_DOUBLEOUT | FRAME_DRAW_NODRAW); + + // Draw Border + pDev->SetLineColor(); + long nBorderSize = pData->mnBorderSize; + if ( (nDrawFlags & BORDERWINDOW_DRAW_BORDER) && nBorderSize ) + { + pDev->SetFillColor( rStyleSettings.GetFaceColor() ); + pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Top() ), + Size( aInRect.GetWidth(), nBorderSize ) ) ); + pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Top()+nBorderSize ), + Size( nBorderSize, aInRect.GetHeight()-nBorderSize ) ) ); + pDev->DrawRect( Rectangle( Point( aInRect.Left(), aInRect.Bottom()-nBorderSize+1 ), + Size( aInRect.GetWidth(), nBorderSize ) ) ); + pDev->DrawRect( Rectangle( Point( aInRect.Right()-nBorderSize+1, aInRect.Top()+nBorderSize ), + Size( nBorderSize, aInRect.GetHeight()-nBorderSize ) ) ); + } + + // Draw Title + if ( (nDrawFlags & BORDERWINDOW_DRAW_TITLE) && !pData->maTitleRect.IsEmpty() ) + { + aInRect = pData->maTitleRect; + + // use no gradient anymore, just a static titlecolor + pDev->SetFillColor( aFrameColor ); + pDev->SetTextColor( rStyleSettings.GetButtonTextColor() ); + Rectangle aTitleRect( pData->maTitleRect ); + if( pOffset ) + aTitleRect.Move( pOffset->X(), pOffset->Y() ); + pDev->DrawRect( aTitleRect ); + + + if ( pData->mnTitleType != BORDERWINDOW_TITLE_TEAROFF ) + { + aInRect.Left() += 2; + aInRect.Right() -= 2; + + if ( !pData->maPinRect.IsEmpty() ) + aInRect.Left() = pData->maPinRect.Right()+2; + + if ( !pData->maHelpRect.IsEmpty() ) + aInRect.Right() = pData->maHelpRect.Left()-2; + else if ( !pData->maRollRect.IsEmpty() ) + aInRect.Right() = pData->maRollRect.Left()-2; + else if ( !pData->maHideRect.IsEmpty() ) + aInRect.Right() = pData->maHideRect.Left()-2; + else if ( !pData->maDockRect.IsEmpty() ) + aInRect.Right() = pData->maDockRect.Left()-2; + else if ( !pData->maMenuRect.IsEmpty() ) + aInRect.Right() = pData->maMenuRect.Left()-2; + else if ( !pData->maCloseRect.IsEmpty() ) + aInRect.Right() = pData->maCloseRect.Left()-2; + + if ( pOffset ) + aInRect.Move( pOffset->X(), pOffset->Y() ); + + USHORT nTextStyle = TEXT_DRAW_LEFT | TEXT_DRAW_VCENTER | TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_CLIP; + + // must show tooltip ? + TextRectInfo aInfo; + pDev->GetTextRect( aInRect, pBorderWindow->GetText(), nTextStyle, &aInfo ); + pData->mbTitleClipped = aInfo.IsEllipses(); + + pDev->DrawText( aInRect, pBorderWindow->GetText(), nTextStyle ); + } + } + + if ( ((nDrawFlags & BORDERWINDOW_DRAW_CLOSE) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maCloseRect.IsEmpty() ) + { + Rectangle aSymbolRect( pData->maCloseRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_CLOSE, pData->mnCloseState ); + } + if ( ((nDrawFlags & BORDERWINDOW_DRAW_DOCK) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maDockRect.IsEmpty() ) + { + Rectangle aSymbolRect( pData->maDockRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_DOCK, pData->mnDockState ); + } + if ( ((nDrawFlags & BORDERWINDOW_DRAW_MENU) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maMenuRect.IsEmpty() ) + { + Rectangle aSymbolRect( pData->maMenuRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_MENU, pData->mnMenuState ); + } + if ( ((nDrawFlags & BORDERWINDOW_DRAW_HIDE) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maHideRect.IsEmpty() ) + { + Rectangle aSymbolRect( pData->maHideRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_HIDE, pData->mnHideState ); + } + if ( ((nDrawFlags & BORDERWINDOW_DRAW_ROLL) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maRollRect.IsEmpty() ) + { + SymbolType eType; + if ( pBorderWindow->mbRollUp ) + eType = SYMBOL_ROLLDOWN; + else + eType = SYMBOL_ROLLUP; + Rectangle aSymbolRect( pData->maRollRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, eType, pData->mnRollState ); + } + + if ( ((nDrawFlags & BORDERWINDOW_DRAW_HELP) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maHelpRect.IsEmpty() ) + { + Rectangle aSymbolRect( pData->maHelpRect ); + if ( pOffset ) + aSymbolRect.Move( pOffset->X(), pOffset->Y() ); + ImplDrawBrdWinSymbolButton( pDev, aSymbolRect, SYMBOL_HELP, pData->mnHelpState ); + } + if ( ((nDrawFlags & BORDERWINDOW_DRAW_PIN) || (nDrawFlags & BORDERWINDOW_DRAW_TITLE)) && + !pData->maPinRect.IsEmpty() ) + { + Image aImage; + ImplGetPinImage( pData->mnPinState, pBorderWindow->mbPined, aImage ); + Size aImageSize = aImage.GetSizePixel(); + long nRectHeight = pData->maPinRect.GetHeight(); + Point aPos( pData->maPinRect.TopLeft() ); + if ( pOffset ) + aPos.Move( pOffset->X(), pOffset->Y() ); + if ( nRectHeight < aImageSize.Height() ) + { + pDev->DrawImage( aPos, Size( aImageSize.Width(), nRectHeight ), aImage ); + } + else + { + aPos.Y() += (nRectHeight-aImageSize.Height())/2; + pDev->DrawImage( aPos, aImage ); + } + } +} + + +// ======================================================================= +void ImplBorderWindow::ImplInit( Window* pParent, + WinBits nStyle, USHORT nTypeStyle, + const ::com::sun::star::uno::Any& ) +{ + ImplInit( pParent, nStyle, nTypeStyle, NULL ); +} + +void ImplBorderWindow::ImplInit( Window* pParent, + WinBits nStyle, USHORT nTypeStyle, + SystemParentData* pSystemParentData + ) +{ + // Alle WindowBits entfernen, die wir nicht haben wollen + WinBits nOrgStyle = nStyle; + WinBits nTestStyle = (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_PINABLE | WB_CLOSEABLE | WB_STANDALONE | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_SYSTEMFLOATWIN | WB_INTROWIN | WB_DEFAULTWIN | WB_TOOLTIPWIN | WB_NOSHADOW | WB_OWNERDRAWDECORATION | WB_SYSTEMCHILDWINDOW | WB_NEEDSFOCUS); + if ( nTypeStyle & BORDERWINDOW_STYLE_APP ) + nTestStyle |= WB_APP; + nStyle &= nTestStyle; + + mpWindowImpl->mbBorderWin = TRUE; + mbSmallOutBorder = FALSE; + if ( nTypeStyle & BORDERWINDOW_STYLE_FRAME ) + { + if( (nStyle & WB_SYSTEMCHILDWINDOW) ) + { + mpWindowImpl->mbOverlapWin = TRUE; + mpWindowImpl->mbFrame = TRUE; + mbFrameBorder = FALSE; + } + else if( (nStyle & WB_OWNERDRAWDECORATION) ) + { + mpWindowImpl->mbOverlapWin = TRUE; + mpWindowImpl->mbFrame = TRUE; + mbFrameBorder = (nOrgStyle & WB_NOBORDER) ? FALSE : TRUE; + } + else + { + mpWindowImpl->mbOverlapWin = TRUE; + mpWindowImpl->mbFrame = TRUE; + mbFrameBorder = FALSE; + // closeable windows may have a border as well, eg. system floating windows without caption + if ( (nOrgStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE/* | WB_CLOSEABLE*/)) == WB_BORDER ) + mbSmallOutBorder = TRUE; + } + } + else if ( nTypeStyle & BORDERWINDOW_STYLE_OVERLAP ) + { + mpWindowImpl->mbOverlapWin = TRUE; + mbFrameBorder = TRUE; + } + else + mbFrameBorder = FALSE; + + if ( nTypeStyle & BORDERWINDOW_STYLE_FLOAT ) + mbFloatWindow = TRUE; + else + mbFloatWindow = FALSE; + + Window::ImplInit( pParent, nStyle, pSystemParentData ); + SetBackground(); + SetTextFillColor(); + + mpMenuBarWindow = NULL; + mnMinWidth = 0; + mnMinHeight = 0; + mnMaxWidth = SHRT_MAX; + mnMaxHeight = SHRT_MAX; + mnRollHeight = 0; + mnOrgMenuHeight = 0; + mbPined = FALSE; + mbRollUp = FALSE; + mbMenuHide = FALSE; + mbDockBtn = FALSE; + mbMenuBtn = FALSE; + mbHideBtn = FALSE; + mbHelpBtn = FALSE; + mbDisplayActive = IsActive(); + + if ( nTypeStyle & BORDERWINDOW_STYLE_FLOAT ) + mnTitleType = BORDERWINDOW_TITLE_SMALL; + else + mnTitleType = BORDERWINDOW_TITLE_NORMAL; + mnBorderStyle = WINDOW_BORDER_NORMAL; + InitView(); +} + +// ======================================================================= + +ImplBorderWindow::ImplBorderWindow( Window* pParent, + SystemParentData* pSystemParentData, + WinBits nStyle, USHORT nTypeStyle + ) : Window( WINDOW_BORDERWINDOW ) +{ + ImplInit( pParent, nStyle, nTypeStyle, pSystemParentData ); +} + +// ----------------------------------------------------------------------- + +ImplBorderWindow::ImplBorderWindow( Window* pParent, WinBits nStyle , + USHORT nTypeStyle ) : + Window( WINDOW_BORDERWINDOW ) +{ + ImplInit( pParent, nStyle, nTypeStyle, ::com::sun::star::uno::Any() ); +} + +ImplBorderWindow::ImplBorderWindow( Window* pParent, + WinBits nStyle, USHORT nTypeStyle, + const ::com::sun::star::uno::Any& aSystemToken ) : + Window( WINDOW_BORDERWINDOW ) +{ + ImplInit( pParent, nStyle, nTypeStyle, aSystemToken ); +} + +// ----------------------------------------------------------------------- + +ImplBorderWindow::~ImplBorderWindow() +{ + delete mpBorderView; +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::MouseMove( const MouseEvent& rMEvt ) +{ + mpBorderView->MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + mpBorderView->MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::Tracking( const TrackingEvent& rTEvt ) +{ + mpBorderView->Tracking( rTEvt ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::Paint( const Rectangle& ) +{ + mpBorderView->DrawWindow( BORDERWINDOW_DRAW_ALL ); +} + +void ImplBorderWindow::Draw( const Rectangle&, OutputDevice* pOutDev, const Point& rPos ) +{ + mpBorderView->DrawWindow( BORDERWINDOW_DRAW_ALL, pOutDev, &rPos ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::Activate() +{ + SetDisplayActive( TRUE ); + Window::Activate(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::Deactivate() +{ + // Fenster die immer Active sind, nehmen wir von dieser Regel aus, + // genauso, wenn ein Menu aktiv wird, ignorieren wir das Deactivate + if ( GetActivateMode() && !ImplGetSVData()->maWinData.mbNoDeactivate ) + SetDisplayActive( FALSE ); + Window::Deactivate(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + // no keyboard help for border win + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) && !rHEvt.KeyboardActivated() ) + { + Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() ); + Rectangle aHelpRect; + String aHelpStr( mpBorderView->RequestHelp( aMousePosPixel, aHelpRect ) ); + + // Rechteck ermitteln + if ( aHelpStr.Len() ) + { + aHelpRect.SetPos( OutputToScreenPixel( aHelpRect.TopLeft() ) ); + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aHelpStr ); + else + Help::ShowQuickHelp( this, aHelpRect, aHelpStr ); + return; + } + } + + Window::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::Resize() +{ + Size aSize = GetOutputSizePixel(); + + if ( !mbRollUp ) + { + Window* pClientWindow = ImplGetClientWindow(); + + if ( mpMenuBarWindow ) + { + sal_Int32 nLeftBorder; + sal_Int32 nTopBorder; + sal_Int32 nRightBorder; + sal_Int32 nBottomBorder; + long nMenuHeight = mpMenuBarWindow->GetSizePixel().Height(); + if ( mbMenuHide ) + { + if ( nMenuHeight ) + mnOrgMenuHeight = nMenuHeight; + nMenuHeight = 0; + } + else + { + if ( !nMenuHeight ) + nMenuHeight = mnOrgMenuHeight; + } + mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + mpMenuBarWindow->SetPosSizePixel( nLeftBorder, + nTopBorder, + aSize.Width()-nLeftBorder-nRightBorder, + nMenuHeight, + WINDOW_POSSIZE_POS | + WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT ); + } + + GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder, + pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder ); + pClientWindow->ImplPosSizeWindow( pClientWindow->mpWindowImpl->mnLeftBorder, + pClientWindow->mpWindowImpl->mnTopBorder, + aSize.Width()-pClientWindow->mpWindowImpl->mnLeftBorder-pClientWindow->mpWindowImpl->mnRightBorder, + aSize.Height()-pClientWindow->mpWindowImpl->mnTopBorder-pClientWindow->mpWindowImpl->mnBottomBorder, + WINDOW_POSSIZE_X | WINDOW_POSSIZE_Y | + WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT ); + } + + // UpdateView + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); + + Window::Resize(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::StateChanged( StateChangedType nType ) +{ + if ( (nType == STATE_CHANGE_TEXT) || + (nType == STATE_CHANGE_IMAGE) || + (nType == STATE_CHANGE_DATA) ) + { + if ( IsReallyVisible() && mbFrameBorder ) + { + if ( HasPaintEvent() ) + InvalidateBorder(); + else + mpBorderView->DrawWindow( BORDERWINDOW_DRAW_TITLE ); + } + } + + Window::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + if ( !mpWindowImpl->mbFrame || (GetStyle() & WB_OWNERDRAWDECORATION) ) + UpdateView( TRUE, ImplGetWindow()->GetOutputSizePixel() ); + } + + Window::DataChanged( rDCEvt ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::InitView() +{ + if ( mbSmallOutBorder ) + mpBorderView = new ImplSmallBorderWindowView( this ); + else if ( mpWindowImpl->mbFrame ) + { + if( mbFrameBorder ) + mpBorderView = new ImplStdBorderWindowView( this ); + else + mpBorderView = new ImplNoBorderWindowView( this ); + } + else if ( !mbFrameBorder ) + mpBorderView = new ImplSmallBorderWindowView( this ); + else + mpBorderView = new ImplStdBorderWindowView( this ); + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::UpdateView( BOOL bNewView, const Size& rNewOutSize ) +{ + sal_Int32 nLeftBorder; + sal_Int32 nTopBorder; + sal_Int32 nRightBorder; + sal_Int32 nBottomBorder; + Size aOldSize = GetSizePixel(); + Size aOutputSize = rNewOutSize; + + if ( bNewView ) + { + delete mpBorderView; + InitView(); + } + else + { + Size aSize = aOutputSize; + mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + aSize.Width() += nLeftBorder+nRightBorder; + aSize.Height() += nTopBorder+nBottomBorder; + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + } + + Window* pClientWindow = ImplGetClientWindow(); + if ( pClientWindow ) + { + GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder, + pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder ); + } + GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + if ( aOldSize.Width() || aOldSize.Height() ) + { + aOutputSize.Width() += nLeftBorder+nRightBorder; + aOutputSize.Height() += nTopBorder+nBottomBorder; + if ( aOutputSize == GetSizePixel() ) + InvalidateBorder(); + else + SetSizePixel( aOutputSize ); + } +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::InvalidateBorder() +{ + if ( IsReallyVisible() ) + { + // Nur wenn wir einen Border haben, muessen wir auch invalidieren + sal_Int32 nLeftBorder; + sal_Int32 nTopBorder; + sal_Int32 nRightBorder; + sal_Int32 nBottomBorder; + mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); + if ( nLeftBorder || nTopBorder || nRightBorder || nBottomBorder ) + { + Rectangle aWinRect( Point( 0, 0 ), GetOutputSizePixel() ); + Region aRegion( aWinRect ); + aWinRect.Left() += nLeftBorder; + aWinRect.Top() += nTopBorder; + aWinRect.Right() -= nRightBorder; + aWinRect.Bottom() -= nBottomBorder; + // kein Output-Bereich mehr, dann alles invalidieren + if ( (aWinRect.Right() < aWinRect.Left()) || + (aWinRect.Bottom() < aWinRect.Top()) ) + Invalidate( INVALIDATE_NOCHILDREN ); + else + { + aRegion.Exclude( aWinRect ); + Invalidate( aRegion, INVALIDATE_NOCHILDREN ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetDisplayActive( BOOL bActive ) +{ + if ( mbDisplayActive != bActive ) + { + mbDisplayActive = bActive; + if ( mbFrameBorder ) + InvalidateBorder(); + } +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetTitleType( USHORT nTitleType, const Size& rSize ) +{ + mnTitleType = nTitleType; + UpdateView( FALSE, rSize ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetBorderStyle( USHORT nStyle ) +{ + if ( !mbFrameBorder && (mnBorderStyle != nStyle) ) + { + mnBorderStyle = nStyle; + UpdateView( FALSE, ImplGetWindow()->GetOutputSizePixel() ); + } +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetPin( BOOL bPin ) +{ + mbPined = bPin; + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetRollUp( BOOL bRollUp, const Size& rSize ) +{ + mbRollUp = bRollUp; + mnRollHeight = rSize.Height(); + UpdateView( FALSE, rSize ); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetCloser() +{ + SetStyle( GetStyle() | WB_CLOSEABLE ); + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetDockButton( BOOL bDockButton ) +{ + mbDockBtn = bDockButton; + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetHideButton( BOOL bHideButton ) +{ + mbHideBtn = bHideButton; + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetHelpButton( BOOL bHelpButton ) +{ + mbHelpBtn = bHelpButton; + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetMenuButton( BOOL bMenuButton ) +{ + mbMenuBtn = bMenuButton; + Size aSize = GetOutputSizePixel(); + mpBorderView->Init( this, aSize.Width(), aSize.Height() ); + InvalidateBorder(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::UpdateMenuHeight() +{ + Resize(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetMenuBarWindow( Window* pWindow ) +{ + mpMenuBarWindow = pWindow; + UpdateMenuHeight(); + if ( pWindow ) + pWindow->Show(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::SetMenuBarMode( BOOL bHide ) +{ + mbMenuHide = bHide; + UpdateMenuHeight(); +} + +// ----------------------------------------------------------------------- + +void ImplBorderWindow::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + mpBorderView->GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder ); + if ( mpMenuBarWindow && !mbMenuHide ) + rTopBorder += mpMenuBarWindow->GetSizePixel().Height(); +} + +// ----------------------------------------------------------------------- + +long ImplBorderWindow::CalcTitleWidth() const +{ + return mpBorderView->CalcTitleWidth(); +} + +Rectangle ImplBorderWindow::GetMenuRect() const +{ + return mpBorderView->GetMenuRect(); +} diff --git a/vcl/source/window/btndlg.cxx b/vcl/source/window/btndlg.cxx new file mode 100644 index 000000000000..9a0452027737 --- /dev/null +++ b/vcl/source/window/btndlg.cxx @@ -0,0 +1,548 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <tools/ref.hxx> +#include <tools/debug.hxx> +#include <vcl/svdata.hxx> +#include <vcl/button.hxx> +#include <vcl/btndlg.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif + + + +// ======================================================================= + +struct ImplBtnDlgItem +{ + USHORT mnId; + BOOL mbOwnButton; + BOOL mbDummyAlign; + long mnSepSize; + PushButton* mpPushButton; +}; + +DECLARE_LIST( ImplBtnDlgItemList, ImplBtnDlgItem* ) + +// ======================================================================= + +void ButtonDialog::ImplInitButtonDialogData() +{ + mpItemList = new ImplBtnDlgItemList( 8, 8 ); + mnButtonSize = 0; + mnCurButtonId = 0; + mnFocusButtonId = BUTTONDIALOG_BUTTON_NOTFOUND; + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +ButtonDialog::ButtonDialog( WindowType nType ) : + Dialog( nType ) +{ + ImplInitButtonDialogData(); +} + +// ----------------------------------------------------------------------- + +ButtonDialog::ButtonDialog( Window* pParent, WinBits nStyle ) : + Dialog( WINDOW_BUTTONDIALOG ) +{ + ImplInitButtonDialogData(); + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ButtonDialog::ButtonDialog( Window* pParent, const ResId& rResId ) : + Dialog( WINDOW_BUTTONDIALOG ) +{ + ImplInitButtonDialogData(); + rResId.SetRT( RSC_DIALOG ); // !!!!!!!!!! RSC_BUTTONDIALOG !!!!!!!! + ImplInit( pParent, ImplInitRes( rResId ) ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +ButtonDialog::~ButtonDialog() +{ + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mpPushButton && pItem->mbOwnButton ) + delete pItem->mpPushButton; + delete pItem; + pItem = mpItemList->Next(); + } + + delete mpItemList; +} + +// ----------------------------------------------------------------------- + +PushButton* ButtonDialog::ImplCreatePushButton( USHORT nBtnFlags ) +{ + PushButton* pBtn; + WinBits nStyle = 0; + + if ( nBtnFlags & BUTTONDIALOG_DEFBUTTON ) + nStyle |= WB_DEFBUTTON; + if ( nBtnFlags & BUTTONDIALOG_CANCELBUTTON ) + pBtn = new CancelButton( this, nStyle ); + else if ( nBtnFlags & BUTTONDIALOG_OKBUTTON ) + pBtn = new OKButton( this, nStyle ); + else if ( nBtnFlags & BUTTONDIALOG_HELPBUTTON ) + pBtn = new HelpButton( this, nStyle ); + else + pBtn = new PushButton( this, nStyle ); + + if ( !(nBtnFlags & BUTTONDIALOG_HELPBUTTON) ) + pBtn->SetClickHdl( LINK( this, ButtonDialog, ImplClickHdl ) ); + + return pBtn; +} + +// ----------------------------------------------------------------------- + +ImplBtnDlgItem* ButtonDialog::ImplGetItem( USHORT nId ) const +{ + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nId ) + return pItem; + + pItem = mpItemList->Next(); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +long ButtonDialog::ImplGetButtonSize() +{ + if ( !mbFormat ) + return mnButtonSize; + + // Calculate ButtonSize + long nLastSepSize = 0; + long nSepSize = 0; + long nButtonCount = 0; + maCtrlSize = Size( IMPL_MINSIZE_BUTTON_WIDTH, IMPL_MINSIZE_BUTTON_HEIGHT ); + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + nSepSize += nLastSepSize; + + long nTxtWidth = pItem->mpPushButton->GetCtrlTextWidth( pItem->mpPushButton->GetText() ); + nTxtWidth += IMPL_EXTRA_BUTTON_WIDTH; + if ( nTxtWidth > maCtrlSize.Width() ) + maCtrlSize.Width() = nTxtWidth; + long nTxtHeight = pItem->mpPushButton->GetTextHeight(); + nTxtHeight += IMPL_EXTRA_BUTTON_HEIGHT; + if ( nTxtHeight > maCtrlSize.Height() ) + maCtrlSize.Height() = nTxtHeight; + + nSepSize += pItem->mnSepSize; + + if ( GetStyle() & WB_HORZ ) + nLastSepSize = IMPL_SEP_BUTTON_X; + else + nLastSepSize = IMPL_SEP_BUTTON_Y; + + nButtonCount++; + + pItem = mpItemList->Next(); + } + + if ( GetStyle() & WB_HORZ ) + mnButtonSize = nSepSize + (nButtonCount*maCtrlSize.Width()); + else + mnButtonSize = nSepSize + (nButtonCount*maCtrlSize.Height()); + + return mnButtonSize; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::ImplPosControls() +{ + if ( !mbFormat ) + return; + + // Create PushButtons and determine Sizes + ImplGetButtonSize(); + + // determine dialog size + ImplBtnDlgItem* pItem; + Size aDlgSize = maPageSize; + long nX; + long nY; + if ( GetStyle() & WB_HORZ ) + { + if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Width() ) + aDlgSize.Width() = mnButtonSize+(IMPL_DIALOG_OFFSET*2); + if ( GetStyle() & WB_LEFT ) + nX = IMPL_DIALOG_OFFSET; + else if ( GetStyle() & WB_RIGHT ) + nX = aDlgSize.Width()-mnButtonSize-IMPL_DIALOG_OFFSET; + else + nX = (aDlgSize.Width()-mnButtonSize)/2; + + aDlgSize.Height() += IMPL_DIALOG_OFFSET+maCtrlSize.Height(); + nY = aDlgSize.Height()-maCtrlSize.Height()-IMPL_DIALOG_OFFSET; + } + else + { + if ( mnButtonSize+(IMPL_DIALOG_OFFSET*2) > aDlgSize.Height() ) + aDlgSize.Height() = mnButtonSize+(IMPL_DIALOG_OFFSET*2); + if ( GetStyle() & WB_BOTTOM ) + nY = aDlgSize.Height()-mnButtonSize-IMPL_DIALOG_OFFSET; + else if ( GetStyle() & WB_VCENTER ) + nY = (aDlgSize.Height()-mnButtonSize)/2; + else + nY = IMPL_DIALOG_OFFSET; + + aDlgSize.Width() += IMPL_DIALOG_OFFSET+maCtrlSize.Width(); + nX = aDlgSize.Width()-maCtrlSize.Width()-IMPL_DIALOG_OFFSET; + } + + // Arrange PushButtons + pItem = mpItemList->First(); + while ( pItem ) + { + if ( GetStyle() & WB_HORZ ) + nX += pItem->mnSepSize; + else + nY += pItem->mnSepSize; + pItem->mpPushButton->SetPosSizePixel( Point( nX, nY ), maCtrlSize ); + pItem->mpPushButton->Show(); + if ( GetStyle() & WB_HORZ ) + nX += maCtrlSize.Width()+IMPL_SEP_BUTTON_X; + else + nY += maCtrlSize.Height()+IMPL_SEP_BUTTON_Y; + + pItem = mpItemList->Next(); + } + + SetOutputSizePixel( aDlgSize ); + + mbFormat = FALSE; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ButtonDialog, ImplClickHdl, PushButton*, pBtn ) +{ + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mpPushButton == pBtn ) + { + mnCurButtonId = pItem->mnId; + Click(); + break; + } + + pItem = mpItemList->Next(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::Resize() +{ +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_INITSHOW ) + { + ImplPosControls(); + + // Focus evt. auf den entsprechenden Button setzen + if ( mnFocusButtonId != BUTTONDIALOG_BUTTON_NOTFOUND ) + { + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == mnFocusButtonId ) + { + if ( pItem->mpPushButton->IsVisible() ) + pItem->mpPushButton->GrabFocus(); + break; + } + + pItem = mpItemList->Next(); + } + } + } + + Dialog::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::Click() +{ + if ( !maClickHdl ) + { + if ( IsInExecute() ) + EndDialog( GetCurButtonId() ); + } + else + maClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::AddButton( const XubString& rText, USHORT nId, + USHORT nBtnFlags, long nSepPixel ) +{ + // PageItem anlegen + ImplBtnDlgItem* pItem = new ImplBtnDlgItem; + pItem->mnId = nId; + pItem->mbOwnButton = TRUE; + pItem->mnSepSize = nSepPixel; + pItem->mpPushButton = ImplCreatePushButton( nBtnFlags ); + if ( rText.Len() ) + pItem->mpPushButton->SetText( rText ); + + // In die Liste eintragen + mpItemList->Insert( pItem, LIST_APPEND ); + + if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON ) + mnFocusButtonId = nId; + + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::AddButton( StandardButtonType eType, USHORT nId, + USHORT nBtnFlags, long nSepPixel ) +{ + // PageItem anlegen + ImplBtnDlgItem* pItem = new ImplBtnDlgItem; + pItem->mnId = nId; + pItem->mbOwnButton = TRUE; + pItem->mnSepSize = nSepPixel; + + if ( eType == BUTTON_OK ) + nBtnFlags |= BUTTONDIALOG_OKBUTTON; + else if ( eType == BUTTON_HELP ) + nBtnFlags |= BUTTONDIALOG_HELPBUTTON; + else if ( (eType == BUTTON_CANCEL) || (eType == BUTTON_CLOSE) ) + nBtnFlags |= BUTTONDIALOG_CANCELBUTTON; + pItem->mpPushButton = ImplCreatePushButton( nBtnFlags ); + + // Standard-Buttons have the right text already + if ( !((eType == BUTTON_OK) && (pItem->mpPushButton->GetType() == WINDOW_OKBUTTON)) || + !((eType == BUTTON_CANCEL) && (pItem->mpPushButton->GetType() == WINDOW_CANCELBUTTON)) || + !((eType == BUTTON_HELP) && (pItem->mpPushButton->GetType() == WINDOW_HELPBUTTON)) ) + { + pItem->mpPushButton->SetText( Button::GetStandardText( eType ) ); + pItem->mpPushButton->SetHelpText( Button::GetStandardHelpText( eType ) ); + } + + if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON ) + mnFocusButtonId = nId; + + // In die Liste eintragen + mpItemList->Insert( pItem, LIST_APPEND ); + + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::AddButton( PushButton* pBtn, USHORT nId, + USHORT nBtnFlags, long nSepPixel ) +{ + // PageItem anlegen + ImplBtnDlgItem* pItem = new ImplBtnDlgItem; + pItem->mnId = nId; + pItem->mbOwnButton = FALSE; + pItem->mnSepSize = nSepPixel; + pItem->mpPushButton = pBtn; + + if ( nBtnFlags & BUTTONDIALOG_FOCUSBUTTON ) + mnFocusButtonId = nId; + + // In die View-Liste eintragen + mpItemList->Insert( pItem, LIST_APPEND ); + + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::RemoveButton( USHORT nId ) +{ + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nId ) + { + pItem->mpPushButton->Hide(); + if ( pItem->mbOwnButton ) + delete pItem->mpPushButton; + delete pItem; + mpItemList->Remove(); + mbFormat = TRUE; + break; + } + + pItem = mpItemList->Next(); + } + + DBG_ERRORFILE( "ButtonDialog::RemoveButton(): ButtonId invalid" ); +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::Clear() +{ + ImplBtnDlgItem* pItem = mpItemList->First(); + while ( pItem ) + { + pItem->mpPushButton->Hide(); + if ( pItem->mbOwnButton ) + delete pItem->mpPushButton; + delete pItem; + pItem = mpItemList->Next(); + } + + mpItemList->Clear(); + mbFormat = TRUE; +} + +// ----------------------------------------------------------------------- + +USHORT ButtonDialog::GetButtonCount() const +{ + return (USHORT)mpItemList->Count(); +} + +// ----------------------------------------------------------------------- + +USHORT ButtonDialog::GetButtonId( USHORT nButton ) const +{ + if ( nButton < mpItemList->Count() ) + return (USHORT)mpItemList->GetObject( nButton )->mnId; + else + return BUTTONDIALOG_BUTTON_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +PushButton* ButtonDialog::GetPushButton( USHORT nId ) const +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + return pItem->mpPushButton; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::SetButtonText( USHORT nId, const XubString& rText ) +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + { + pItem->mpPushButton->SetText( rText ); + mbFormat = TRUE; + } +} + +// ----------------------------------------------------------------------- + +XubString ButtonDialog::GetButtonText( USHORT nId ) const +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + return pItem->mpPushButton->GetText(); + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::SetButtonHelpText( USHORT nId, const XubString& rText ) +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + pItem->mpPushButton->SetHelpText( rText ); +} + +// ----------------------------------------------------------------------- + +XubString ButtonDialog::GetButtonHelpText( USHORT nId ) const +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + return pItem->mpPushButton->GetHelpText(); + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ButtonDialog::SetButtonHelpId( USHORT nId, const rtl::OString& rHelpId ) +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + if ( pItem ) + pItem->mpPushButton->SetHelpId( rHelpId ); +} + +// ----------------------------------------------------------------------- + +rtl::OString ButtonDialog::GetButtonHelpId( USHORT nId ) const +{ + ImplBtnDlgItem* pItem = ImplGetItem( nId ); + + return pItem ? rtl::OString( pItem->mpPushButton->GetHelpId() ) : rtl::OString(); +} diff --git a/vcl/source/window/cmdevt.cxx b/vcl/source/window/cmdevt.cxx new file mode 100644 index 000000000000..03e01c96742b --- /dev/null +++ b/vcl/source/window/cmdevt.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _STRING_H +#include <string.h> +#endif + +#ifndef _SV_CMDEVT_HXX +#include <vcl/cmdevt.hxx> +#endif + +// ======================================================================= + +CommandExtTextInputData::CommandExtTextInputData() +{ + mpTextAttr = NULL; + mnCursorPos = 0; + mnDeltaStart = 0; + mnOldTextLen = 0; + mnCursorFlags = 0; + mbOnlyCursor = FALSE; +} + +// ----------------------------------------------------------------------- + +CommandExtTextInputData::CommandExtTextInputData( const XubString& rText, + const USHORT* pTextAttr, + xub_StrLen nCursorPos, + USHORT nCursorFlags, + xub_StrLen nDeltaStart, + xub_StrLen nOldTextLen, + BOOL bOnlyCursor ) : + maText( rText ) +{ + if ( pTextAttr && maText.Len() ) + { + mpTextAttr = new USHORT[maText.Len()]; + memcpy( mpTextAttr, pTextAttr, maText.Len()*sizeof(USHORT) ); + } + else + mpTextAttr = NULL; + mnCursorPos = nCursorPos; + mnDeltaStart = nDeltaStart; + mnOldTextLen = nOldTextLen; + mnCursorFlags = nCursorFlags; + mbOnlyCursor = bOnlyCursor; +} + +// ----------------------------------------------------------------------- + +CommandExtTextInputData::CommandExtTextInputData( const CommandExtTextInputData& rData ) : + maText( rData.maText ) +{ + if ( rData.mpTextAttr && maText.Len() ) + { + mpTextAttr = new USHORT[maText.Len()]; + memcpy( mpTextAttr, rData.mpTextAttr, maText.Len()*sizeof(USHORT) ); + } + else + mpTextAttr = NULL; + mnCursorPos = rData.mnCursorPos; + mnDeltaStart = rData.mnDeltaStart; + mnOldTextLen = rData.mnOldTextLen; + mnCursorFlags = rData.mnCursorFlags; + mbOnlyCursor = rData.mbOnlyCursor; +} + +// ----------------------------------------------------------------------- + +CommandExtTextInputData::~CommandExtTextInputData() +{ + if ( mpTextAttr ) + delete [] mpTextAttr; +} diff --git a/vcl/source/window/cursor.cxx b/vcl/source/window/cursor.cxx new file mode 100644 index 000000000000..5725189e10c3 --- /dev/null +++ b/vcl/source/window/cursor.cxx @@ -0,0 +1,462 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <vcl/settings.hxx> +#include <vcl/window.hxx> +#include <vcl/window.h> +#include <tools/poly.hxx> +#include <vcl/cursor.hxx> + + +// ======================================================================= + +struct ImplCursorData +{ + AutoTimer maTimer; // Timer + Point maPixPos; // Pixel-Position + Point maPixRotOff; // Pixel-Offset-Position + Size maPixSize; // Pixel-Size + long mnPixSlant; // Pixel-Slant + short mnOrientation; // Pixel-Orientation + unsigned char mnDirection; // indicates writing direction + USHORT mnStyle; // Cursor-Style + BOOL mbCurVisible; // Ist Cursor aktuell sichtbar + Window* mpWindow; // Zugeordnetes Windows +}; + +// ======================================================================= + +static void ImplCursorInvert( ImplCursorData* pData ) +{ + Window* pWindow = pData->mpWindow; + BOOL bMapMode = pWindow->IsMapModeEnabled(); + pWindow->EnableMapMode( FALSE ); + USHORT nInvertStyle; + if ( pData->mnStyle & CURSOR_SHADOW ) + nInvertStyle = INVERT_50; + else + nInvertStyle = 0; + + Rectangle aRect( pData->maPixPos, pData->maPixSize ); + if ( pData->mnDirection || pData->mnOrientation || pData->mnPixSlant ) + { + Polygon aPoly( aRect ); + if( aPoly.GetSize() == 5 ) + { + aPoly[1].X() += 1; // include the right border + aPoly[2].X() += 1; + if ( pData->mnPixSlant ) + { + Point aPoint = aPoly.GetPoint( 0 ); + aPoint.X() += pData->mnPixSlant; + aPoly.SetPoint( aPoint, 0 ); + aPoly.SetPoint( aPoint, 4 ); + aPoint = aPoly.GetPoint( 1 ); + aPoint.X() += pData->mnPixSlant; + aPoly.SetPoint( aPoint, 1 ); + } + + // apply direction flag after slant to use the correct shape + if ( pData->mnDirection ) + { + Point pAry[7]; + int delta = 3*aRect.getWidth()+1; + if( pData->mnDirection == CURSOR_DIRECTION_LTR ) + { + // left-to-right + pAry[0] = aPoly.GetPoint( 0 ); + pAry[1] = aPoly.GetPoint( 1 ); + pAry[2] = pAry[1]; + pAry[2].X() += delta; + pAry[3] = pAry[1]; + pAry[3].Y() += delta; + pAry[4] = aPoly.GetPoint( 2 ); + pAry[5] = aPoly.GetPoint( 3 ); + pAry[6] = aPoly.GetPoint( 4 ); + } + else if( pData->mnDirection == CURSOR_DIRECTION_RTL ) + { + // right-to-left + pAry[0] = aPoly.GetPoint( 0 ); + pAry[1] = aPoly.GetPoint( 1 ); + pAry[2] = aPoly.GetPoint( 2 ); + pAry[3] = aPoly.GetPoint( 3 ); + pAry[4] = pAry[0]; + pAry[4].Y() += delta; + pAry[5] = pAry[0]; + pAry[5].X() -= delta; + pAry[6] = aPoly.GetPoint( 4 ); + } + aPoly = Polygon( 7, pAry); + } + + if ( pData->mnOrientation ) + aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation ); + pWindow->Invert( aPoly, nInvertStyle ); + } + } + else + pWindow->Invert( aRect, nInvertStyle ); + pWindow->EnableMapMode( bMapMode ); +} + +// ----------------------------------------------------------------------- + +void Cursor::ImplDraw() +{ + if ( mpData && mpData->mpWindow && !mpData->mbCurVisible ) + { + Window* pWindow = mpData->mpWindow; + mpData->maPixPos = pWindow->LogicToPixel( maPos ); + mpData->maPixSize = pWindow->LogicToPixel( maSize ); + mpData->mnPixSlant = pWindow->LogicToPixel( Size( mnSlant, 0 ) ).Width(); + mpData->mnOrientation = mnOrientation; + mpData->mnDirection = mnDirection; + long nOffsetY = pWindow->LogicToPixel( Size( 0, mnOffsetY ) ).Height(); + + // Position um den Offset korrigieren + mpData->maPixPos.Y() -= nOffsetY; + mpData->maPixRotOff = mpData->maPixPos; + mpData->maPixRotOff.Y() += nOffsetY; + + // Wenn groesse 0 ist, nehmen wir die breite, die in den + // Settings eingestellt ist + if ( !mpData->maPixSize.Width() ) + mpData->maPixSize.Width() = pWindow->GetSettings().GetStyleSettings().GetCursorSize(); + + // Ausgabeflaeche berechnen und ausgeben + ImplCursorInvert( mpData ); + mpData->mbCurVisible = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void Cursor::ImplRestore() +{ + if ( mpData && mpData->mbCurVisible ) + { + ImplCursorInvert( mpData ); + mpData->mbCurVisible = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Cursor::ImplShow( BOOL bDrawDirect ) +{ + if ( mbVisible ) + { + Window* pWindow; + if ( mpWindow ) + pWindow = mpWindow; + else + { + // Gibt es ein aktives Fenster und ist der Cursor in dieses Fenster + // selektiert, dann zeige den Cursor an + pWindow = Application::GetFocusWindow(); + if ( !pWindow || (pWindow->mpWindowImpl->mpCursor != this) || pWindow->mpWindowImpl->mbInPaint + || !pWindow->mpWindowImpl->mpFrameData->mbHasFocus ) + pWindow = NULL; + } + + if ( pWindow ) + { + if ( !mpData ) + { + mpData = new ImplCursorData; + mpData->mbCurVisible = FALSE; + mpData->maTimer.SetTimeoutHdl( LINK( this, Cursor, ImplTimerHdl ) ); + } + + mpData->mpWindow = pWindow; + mpData->mnStyle = mnStyle; + if ( bDrawDirect ) + ImplDraw(); + + if ( !mpWindow ) + { + mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() ); + if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME ) + mpData->maTimer.Start(); + else if ( !mpData->mbCurVisible ) + ImplDraw(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Cursor::ImplHide() +{ + if ( mpData && mpData->mpWindow ) + { + if ( mpData->mbCurVisible ) + ImplRestore(); + + mpData->maTimer.Stop(); + mpData->mpWindow = NULL; + } +} + +// ----------------------------------------------------------------------- + +void Cursor::ImplNew() +{ + if ( mbVisible && mpData && mpData->mpWindow ) + { + if ( mpData->mbCurVisible ) + ImplRestore(); + + ImplDraw(); + if ( !mpWindow ) + { + if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME ) + mpData->maTimer.Start(); + } + } +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Cursor, ImplTimerHdl, AutoTimer*, EMPTYARG ) +{ + if ( mpData->mbCurVisible ) + ImplRestore(); + else + ImplDraw(); + return 0; +} + +// ======================================================================= + +Cursor::Cursor() +{ + mpData = NULL; + mpWindow = NULL; + mnSlant = 0; + mnOffsetY = 0; + mnOrientation = 0; + mnDirection = 0; + mnStyle = 0; + mbVisible = FALSE; +} + +// ----------------------------------------------------------------------- + +Cursor::Cursor( const Cursor& rCursor ) : + maSize( rCursor.maSize ), + maPos( rCursor.maPos ) +{ + mpData = NULL; + mpWindow = NULL; + mnSlant = rCursor.mnSlant; + mnOrientation = rCursor.mnOrientation; + mnDirection = rCursor.mnDirection; + mnStyle = 0; + mbVisible = rCursor.mbVisible; +} + +// ----------------------------------------------------------------------- + +Cursor::~Cursor() +{ + if ( mpData ) + { + if ( mpData->mbCurVisible ) + ImplRestore(); + + delete mpData; + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetStyle( USHORT nStyle ) +{ + if ( mnStyle != nStyle ) + { + mnStyle = nStyle; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::Show() +{ + if ( !mbVisible ) + { + mbVisible = TRUE; + ImplShow(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::Hide() +{ + if ( mbVisible ) + { + mbVisible = FALSE; + ImplHide(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetWindow( Window* pWindow ) +{ + if ( mpWindow != pWindow ) + { + mpWindow = pWindow; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetPos( const Point& rPoint ) +{ + if ( maPos != rPoint ) + { + maPos = rPoint; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetOffsetY( long nNewOffsetY ) +{ + if ( mnOffsetY != nNewOffsetY ) + { + mnOffsetY = nNewOffsetY; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetSize( const Size& rSize ) +{ + if ( maSize != rSize ) + { + maSize = rSize; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetWidth( long nNewWidth ) +{ + if ( maSize.Width() != nNewWidth ) + { + maSize.Width() = nNewWidth; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetHeight( long nNewHeight ) +{ + if ( maSize.Height() != nNewHeight ) + { + maSize.Height() = nNewHeight; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetSlant( long nNewSlant ) +{ + if ( mnSlant != nNewSlant ) + { + mnSlant = nNewSlant; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetOrientation( short nNewOrientation ) +{ + if ( mnOrientation != nNewOrientation ) + { + mnOrientation = nNewOrientation; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +void Cursor::SetDirection( unsigned char nNewDirection ) +{ + if ( mnDirection != nNewDirection ) + { + mnDirection = nNewDirection; + ImplNew(); + } +} + +// ----------------------------------------------------------------------- + +Cursor& Cursor::operator=( const Cursor& rCursor ) +{ + maPos = rCursor.maPos; + maSize = rCursor.maSize; + mnSlant = rCursor.mnSlant; + mnOrientation = rCursor.mnOrientation; + mnDirection = rCursor.mnDirection; + mbVisible = rCursor.mbVisible; + ImplNew(); + + return *this; +} + +// ----------------------------------------------------------------------- + +BOOL Cursor::operator==( const Cursor& rCursor ) const +{ + if ( (maPos == rCursor.maPos) && + (maSize == rCursor.maSize) && + (mnSlant == rCursor.mnSlant) && + (mnOrientation == rCursor.mnOrientation) && + (mnDirection == rCursor.mnDirection) && + (mbVisible == rCursor.mbVisible) ) + return TRUE; + else + return FALSE; +} diff --git a/vcl/source/window/decoview.cxx b/vcl/source/window/decoview.cxx new file mode 100644 index 000000000000..d51988d4d5d3 --- /dev/null +++ b/vcl/source/window/decoview.cxx @@ -0,0 +1,1288 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <vcl/settings.hxx> +#include <tools/poly.hxx> +#include <vcl/outdev.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/decoview.hxx> +#include <vcl/window.hxx> +#include <vcl/ctrl.hxx> + +// ======================================================================= + +#define BUTTON_DRAW_FLATTEST (BUTTON_DRAW_FLAT | \ + BUTTON_DRAW_PRESSED | \ + BUTTON_DRAW_CHECKED | \ + BUTTON_DRAW_HIGHLIGHT) + +// ======================================================================= + +static void ImplDrawSymbol( OutputDevice* pDev, const Rectangle& rRect, + SymbolType eType ) +{ + // Groessen vorberechnen + long nMin = Min( rRect.GetWidth(), rRect.GetHeight() ); + long nSize = nMin; + + if ( nMin & 0x01 ) + nMin--; + Point aCenter = rRect.Center(); + long nCenterX = aCenter.X(); + long nCenterY = aCenter.Y(); + long n2 = nMin / 2; + long n4 = nMin / 4; + long nLeft; + long nTop; + long nRight; + long nBottom; + long nTemp; + long i; + + switch ( eType ) + { + case SYMBOL_ARROW_UP: + { + if ( !(nMin & 0x01) ) + { + n2--; + n4--; + } + nTop = nCenterY-n2; + nBottom = nCenterY; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nTop++; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + pDev->DrawRect( Rectangle( nCenterX-n4, nBottom, + nCenterX+n4, nBottom+n2 ) ); + } + break; + + case SYMBOL_ARROW_DOWN: + { + if ( !(nMin & 0x01) ) + { + n2--; + n4--; + } + nTop = nCenterY; + nBottom = nCenterY+n2; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nBottom--; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + pDev->DrawRect( Rectangle( nCenterX-n4, nTop-n2, + nCenterX+n4, nTop ) ); + } + break; + + case SYMBOL_ARROW_LEFT: + { + if ( !(nMin & 0x01) ) + { + n2--; + n4--; + } + nLeft = nCenterX-n2; + nRight = nCenterX; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + i = 1; + while ( i <= n2 ) + { + nLeft++; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + i++; + } + pDev->DrawRect( Rectangle( nRight, nCenterY-n4, + nRight+n2, nCenterY+n4 ) ); + } + break; + + case SYMBOL_ARROW_RIGHT: + { + if ( !(nMin & 0x01) ) + { + n2--; + n4--; + } + nLeft = nCenterX; + nRight = nCenterX+n2; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + i = 1; + while ( i <= n2 ) + { + nRight--; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + i++; + } + pDev->DrawRect( Rectangle( nLeft-n2, nCenterY-n4, + nLeft, nCenterY+n4 ) ); + } + break; + + + case SYMBOL_SPIN_UP: + { + if ( !(nMin & 0x01) ) + n2--; + nTop = nCenterY-n4; + nBottom = nTop+n2; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nTop++; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + } + break; + + case SYMBOL_SPIN_DOWN: + { + if ( !(nMin & 0x01) ) + n2--; + nTop = nCenterY-n4; + nBottom = nTop+n2; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nBottom--; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + } + break; + + case SYMBOL_SPIN_LEFT: + case SYMBOL_FIRST: + case SYMBOL_PREV: + case SYMBOL_REVERSEPLAY: + { + if ( !(nMin & 0x01) ) + n2--; + nLeft = nCenterX-n4; + if ( eType == SYMBOL_FIRST ) + nLeft++; + nRight = nLeft+n2; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + i = 1; + while ( i <= n2 ) + { + nLeft++; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + i++; + } + if ( eType == SYMBOL_FIRST ) + { + pDev->DrawRect( Rectangle( nCenterX-n4-1, nCenterY-n2, + nCenterX-n4-1, nCenterY+n2 ) ); + } + } + break; + + case SYMBOL_SPIN_RIGHT: + case SYMBOL_LAST: + case SYMBOL_NEXT: + case SYMBOL_PLAY: + { + if ( !(nMin & 0x01) ) + n2--; + nLeft = nCenterX-n4; + if ( eType == SYMBOL_LAST ) + nLeft--; + nRight = nLeft+n2; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + i = 1; + while ( i <= n2 ) + { + nRight--; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + i++; + } + if ( eType == SYMBOL_LAST ) + { + pDev->DrawRect( Rectangle( nCenterX+n4+1, nCenterY-n2, + nCenterX+n4+1, nCenterY+n2 ) ); + } + } + break; + + case SYMBOL_PAGEUP: + case SYMBOL_PAGEDOWN: + { + if ( !( nSize & 0x01 )) + { + // An even rectangle size means we have to use a smaller size for + // our arrows as we want to use one pixel for the spearhead! Otherwise + // it will be clipped! + nCenterX++; + n2 = ( nMin-1 ) / 2; + n4 = ( nMin-1 ) / 4; + } + + nTop = nCenterY-n2; + nBottom = nCenterY-1; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + pDev->DrawRect( Rectangle( nCenterX, nTop+n2+1, nCenterX, nBottom+n2+1 ) ); + i = 1; + while ( i < n2 ) + { + ( eType == SYMBOL_PAGEUP ) ? nTop++ : nBottom--; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + pDev->DrawRect( Rectangle( nTemp, nTop+n2+1, nTemp, nBottom+n2+1 ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + pDev->DrawRect( Rectangle( nTemp, nTop+n2+1, nTemp, nBottom+n2+1 ) ); + i++; + } + } + break; + + case SYMBOL_RADIOCHECKMARK: + case SYMBOL_RECORD: + { + const long nExt = ( n2 << 1 ) + 1; + Bitmap aBmp( Size( nExt, nExt ), 1 ); + BitmapWriteAccess* pWAcc = aBmp.AcquireWriteAccess(); + + if( pWAcc ) + { + const Color aWhite( COL_WHITE ); + const Color aBlack( COL_BLACK ); + + pWAcc->Erase( aWhite ); + pWAcc->SetLineColor( aBlack ); + pWAcc->SetFillColor( aBlack ); + pWAcc->DrawPolygon( Polygon( Point( n2, n2 ), n2, n2 ) ); + aBmp.ReleaseAccess( pWAcc ); + pDev->DrawMask( Point( nCenterX - n2, nCenterY - n2 ), aBmp, pDev->GetFillColor() ); + } + else + pDev->DrawPolygon( Polygon( Point( nCenterX, nCenterY ), n2, n2 ) ); + } + break; + + case SYMBOL_STOP: + { + nLeft = nCenterX-n2; + nRight = nCenterX+n2; + nTop = nCenterY-n2; + nBottom = nCenterY+n2; + pDev->DrawRect( Rectangle( nLeft, nTop, nRight, nBottom ) ); + } + break; + + case SYMBOL_PAUSE: + { + nLeft = nCenterX-n2; + nRight = nCenterX+n2-1; + nTop = nCenterY-n2; + nBottom = nCenterY+n2; + pDev->DrawRect( Rectangle( nLeft, nTop, nCenterX-2, nBottom ) ); + pDev->DrawRect( Rectangle( nCenterX+1, nTop, nRight, nBottom ) ); + } + break; + + case SYMBOL_WINDSTART: + case SYMBOL_WINDBACKWARD: + { + nLeft = nCenterX-n2+1; + nRight = nCenterX; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nCenterY, nRight+n2, nCenterY ) ); + i = 1; + while ( i < n2 ) + { + nLeft++; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) ); + i++; + } + if ( eType == SYMBOL_WINDSTART ) + { + pDev->DrawRect( Rectangle( nCenterX-n2, nCenterY-n2, + nCenterX-n2, nCenterY+n2 ) ); + } + } + break; + + case SYMBOL_WINDEND: + case SYMBOL_WINDFORWARD: + { + nLeft = nCenterX-n2; + nRight = nCenterX-1; + pDev->DrawRect( Rectangle( nLeft, nCenterY, nRight, nCenterY ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nCenterY, nRight+n2, nCenterY ) ); + i = 1; + while ( i < n2 ) + { + nRight--; + nTemp = nCenterY-i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) ); + nTemp = nCenterY+i; + pDev->DrawRect( Rectangle( nLeft, nTemp, nRight, nTemp ) ); + pDev->DrawRect( Rectangle( nLeft+n2, nTemp, nRight+n2, nTemp ) ); + i++; + } + if ( eType == SYMBOL_WINDEND ) + { + pDev->DrawRect( Rectangle( nCenterX+n2, nCenterY-n2, + nCenterX+n2, nCenterY+n2 ) ); + } + } + break; + + case SYMBOL_CLOSE: + { + Size aRectSize( 2, 1 ); + if ( nMin < 8 ) + aRectSize.Width() = 1; + else if ( nMin > 20 ) + aRectSize.Width() = nMin/10; + nLeft = nCenterX-n2+1; + nTop = nCenterY-n2+1; + nBottom = nCenterY-n2+nMin-aRectSize.Width()+1; + i = 0; + while ( i < nMin-aRectSize.Width()+1 ) + { + pDev->DrawRect( Rectangle( Point( nLeft+i, nTop+i ), aRectSize ) ); + pDev->DrawRect( Rectangle( Point( nLeft+i, nBottom-i ), aRectSize ) ); + i++; + } + } + break; + + case SYMBOL_ROLLUP: + case SYMBOL_ROLLDOWN: + { + Rectangle aRect( nCenterX-n2, nCenterY-n2, + nCenterX+n2, nCenterY-n2+1 ); + pDev->DrawRect( aRect ); + if ( eType == SYMBOL_ROLLDOWN ) + { + Rectangle aTempRect = aRect; + aTempRect.Bottom() = nCenterY+n2; + aTempRect.Right() = aRect.Left(); + pDev->DrawRect( aTempRect ); + aTempRect.Left() = aRect.Right(); + aTempRect.Right() = aRect.Right(); + pDev->DrawRect( aTempRect ); + aTempRect.Top() = aTempRect.Bottom(); + aTempRect.Left() = aRect.Left(); + pDev->DrawRect( aTempRect ); + } + } + break; + case SYMBOL_CHECKMARK: + { + // #106953# never mirror checkmarks + BOOL bRTL = pDev->ImplHasMirroredGraphics() && pDev->IsRTLEnabled(); + Point aPos1( bRTL ? rRect.Right() : rRect.Left(), + rRect.Bottom() - rRect.GetHeight() / 3 ); + Point aPos2( bRTL ? rRect.Right() - rRect.GetWidth()/3 : rRect.Left() + rRect.GetWidth()/3, + rRect.Bottom() ); + Point aPos3( bRTL ? rRect.TopLeft() : rRect.TopRight() ); + Size aRectSize( 1, 2 ); + long nStepsY = aPos2.Y()-aPos1.Y(); + long nX = aPos1.X(); + long nY = aPos1.Y(); + long n; + for ( n = 0; n <= nStepsY; n++ ) + { + if( bRTL ) + nX--; + pDev->DrawRect( Rectangle( Point( nX, nY++ ), aRectSize ) ); + if( !bRTL ) + nX++; + } + nStepsY = aPos2.Y()-aPos3.Y(); + nX = aPos2.X(); + nY = aPos2.Y(); + for ( n = 0; n <= nStepsY; n++ ) + { + if( bRTL ) + if ( --nX < rRect.Left() ) + break; + pDev->DrawRect( Rectangle( Point( nX, nY-- ), aRectSize ) ); + if( !bRTL ) + if ( ++nX > rRect.Right() ) + break; + } + } + break; + + case SYMBOL_SPIN_UPDOWN: + { + nTop = nCenterY-n2-1; + nBottom = nTop+n2; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nTop++; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + nTop = nCenterY+1; + nBottom = nTop+n2; + pDev->DrawRect( Rectangle( nCenterX, nTop, nCenterX, nBottom ) ); + i = 1; + while ( i <= n2 ) + { + nBottom--; + nTemp = nCenterX-i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + nTemp = nCenterX+i; + pDev->DrawRect( Rectangle( nTemp, nTop, nTemp, nBottom ) ); + i++; + } + } + break; + + + case SYMBOL_FLOAT: + { + Rectangle aRect( nCenterX-n2, nCenterY-n2+3, + nCenterX+n2-2, nCenterY-n2+4 ); + pDev->DrawRect( aRect ); + Rectangle aTempRect = aRect; + aTempRect.Bottom() = nCenterY+n2; + aTempRect.Right() = aRect.Left(); + pDev->DrawRect( aTempRect ); + aTempRect.Left() = aRect.Right(); + aTempRect.Right() = aRect.Right(); + pDev->DrawRect( aTempRect ); + aTempRect.Top() = aTempRect.Bottom(); + aTempRect.Left() = aRect.Left(); + pDev->DrawRect( aTempRect ); + aRect = Rectangle( nCenterX-n2+2, nCenterY-n2, + nCenterX+n2, nCenterY-n2+1 ); + pDev->DrawRect( aRect ); + aTempRect = aRect; + aTempRect.Bottom() = nCenterY+n2-3; + aTempRect.Right() = aRect.Left(); + pDev->DrawRect( aTempRect ); + aTempRect.Left() = aRect.Right(); + aTempRect.Right() = aRect.Right(); + pDev->DrawRect( aTempRect ); + aTempRect.Top() = aTempRect.Bottom(); + aTempRect.Left() = aRect.Left(); + pDev->DrawRect( aTempRect ); + } + break; + case SYMBOL_DOCK: + { + Rectangle aRect( nCenterX-n2, nCenterY-n2, + nCenterX+n2, nCenterY-n2 ); + pDev->DrawRect( aRect ); + Rectangle aTempRect = aRect; + aTempRect.Bottom() = nCenterY+n2; + aTempRect.Right() = aRect.Left(); + pDev->DrawRect( aTempRect ); + aTempRect.Left() = aRect.Right(); + aTempRect.Right() = aRect.Right(); + pDev->DrawRect( aTempRect ); + aTempRect.Top() = aTempRect.Bottom(); + aTempRect.Left() = aRect.Left(); + pDev->DrawRect( aTempRect ); + } + break; + case SYMBOL_HIDE: + { + long nExtra = nMin / 8; + Rectangle aRect( nCenterX-n2+nExtra, nCenterY+n2-1, + nCenterX+n2-nExtra, nCenterY+n2 ); + pDev->DrawRect( aRect ); + } + break; + } +} + +// ----------------------------------------------------------------------- + +void DecorationView::DrawSymbol( const Rectangle& rRect, SymbolType eType, + const Color& rColor, USHORT nStyle ) +{ + const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings(); + Rectangle aRect = mpOutDev->LogicToPixel( rRect ); + Color aOldLineColor = mpOutDev->GetLineColor(); + Color aOldFillColor = mpOutDev->GetFillColor(); + BOOL bOldMapMode = mpOutDev->IsMapModeEnabled(); + mpOutDev->SetLineColor(); + mpOutDev->SetFillColor( rColor ); + mpOutDev->EnableMapMode( FALSE ); + + if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) || + (mpOutDev->GetOutDevType() == OUTDEV_PRINTER) ) + nStyle |= BUTTON_DRAW_MONO; + + if ( nStyle & SYMBOL_DRAW_MONO ) + { + if ( nStyle & SYMBOL_DRAW_DISABLE ) + mpOutDev->SetFillColor( Color( COL_GRAY ) ); + else + mpOutDev->SetFillColor( Color( COL_BLACK ) ); + } + else + { + if ( nStyle & SYMBOL_DRAW_DISABLE ) + { + // Als Embosed ausgeben + mpOutDev->SetFillColor( rStyleSettings.GetLightColor() ); + Rectangle aTempRect = aRect; + aTempRect.Move( 1, 1 ); + ImplDrawSymbol( mpOutDev, aTempRect, eType ); + mpOutDev->SetFillColor( rStyleSettings.GetShadowColor() ); + } + else + mpOutDev->SetFillColor( rColor ); + } + + ImplDrawSymbol( mpOutDev, aRect, eType ); + + mpOutDev->SetLineColor( aOldLineColor ); + mpOutDev->SetFillColor( aOldFillColor ); + mpOutDev->EnableMapMode( bOldMapMode ); +} + +// ======================================================================= + +void DecorationView::DrawFrame( const Rectangle& rRect, + const Color& rLeftTopColor, + const Color& rRightBottomColor ) +{ + Rectangle aRect = mpOutDev->LogicToPixel( rRect ); + Color aOldLineColor = mpOutDev->GetLineColor(); + Color aOldFillColor = mpOutDev->GetFillColor(); + BOOL bOldMapMode = mpOutDev->IsMapModeEnabled(); + mpOutDev->EnableMapMode( FALSE ); + mpOutDev->SetLineColor(); + mpOutDev->ImplDraw2ColorFrame( aRect, rLeftTopColor, rRightBottomColor ); + mpOutDev->SetLineColor( aOldLineColor ); + mpOutDev->SetFillColor( aOldFillColor ); + mpOutDev->EnableMapMode( bOldMapMode ); +} + +// ======================================================================= + +void DecorationView::DrawHighlightFrame( const Rectangle& rRect, + USHORT nStyle ) +{ + const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings(); + Color aLightColor = rStyleSettings.GetLightColor(); + Color aShadowColor = rStyleSettings.GetShadowColor(); + + if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) || + (mpOutDev->GetOutDevType() == OUTDEV_PRINTER) ) + { + aLightColor = Color( COL_BLACK ); + aShadowColor = Color( COL_BLACK ); + } + else if ( nStyle & FRAME_HIGHLIGHT_TESTBACKGROUND ) + { + Wallpaper aBackground = mpOutDev->GetBackground(); + if ( aBackground.IsBitmap() || aBackground.IsGradient() ) + { + aLightColor = rStyleSettings.GetFaceColor(); + aShadowColor = Color( COL_BLACK ); + } + else + { + Color aBackColor = aBackground.GetColor(); + if ( (aLightColor.GetColorError( aBackColor ) < 32) || + (aShadowColor.GetColorError( aBackColor ) < 32) ) + { + aLightColor = Color( COL_WHITE ); + aShadowColor = Color( COL_BLACK ); + + if ( aLightColor.GetColorError( aBackColor ) < 32 ) + aLightColor.DecreaseLuminance( 64 ); + if ( aShadowColor.GetColorError( aBackColor ) < 32 ) + aShadowColor.IncreaseLuminance( 64 ); + } + } + } + + if ( (nStyle & FRAME_HIGHLIGHT_STYLE) == FRAME_HIGHLIGHT_IN ) + { + Color aTempColor = aLightColor; + aLightColor = aShadowColor; + aShadowColor = aTempColor; + } + + DrawFrame( rRect, aLightColor, aShadowColor ); +} + +// ======================================================================= + +static void ImplDrawDPILineRect( OutputDevice* pDev, Rectangle& rRect, + const Color* pColor, BOOL bRound = FALSE ) +{ + long nLineWidth = pDev->ImplGetDPIX()/300; + long nLineHeight = pDev->ImplGetDPIY()/300; + if ( !nLineWidth ) + nLineWidth = 1; + if ( !nLineHeight ) + nLineHeight = 1; + + if ( pColor ) + { + if ( (nLineWidth == 1) && (nLineHeight == 1) ) + { + pDev->SetLineColor( *pColor ); + pDev->SetFillColor(); + if( bRound ) + { + pDev->DrawLine( Point( rRect.Left()+1, rRect.Top()), Point( rRect.Right()-1, rRect.Top()) ); + pDev->DrawLine( Point( rRect.Left()+1, rRect.Bottom()), Point( rRect.Right()-1, rRect.Bottom()) ); + pDev->DrawLine( Point( rRect.Left(), rRect.Top()+1), Point( rRect.Left(), rRect.Bottom()-1) ); + pDev->DrawLine( Point( rRect.Right(), rRect.Top()+1), Point( rRect.Right(), rRect.Bottom()-1) ); + } + else + pDev->DrawRect( rRect ); + } + else + { + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + pDev->SetLineColor(); + pDev->SetFillColor( *pColor ); + pDev->DrawRect( Rectangle( rRect.TopLeft(), Size( nWidth, nLineHeight ) ) ); + pDev->DrawRect( Rectangle( rRect.TopLeft(), Size( nLineWidth, nHeight ) ) ); + pDev->DrawRect( Rectangle( Point( rRect.Left(), rRect.Bottom()-nLineHeight ), + Size( nWidth, nLineHeight ) ) ); + pDev->DrawRect( Rectangle( Point( rRect.Right()-nLineWidth, rRect.Top() ), + Size( nLineWidth, nHeight ) ) ); + } + } + + rRect.Left() += nLineWidth; + rRect.Top() += nLineHeight; + rRect.Right() -= nLineWidth; + rRect.Bottom() -= nLineHeight; +} + +// ======================================================================= + +static void ImplDrawFrame( OutputDevice* pDev, Rectangle& rRect, + const StyleSettings& rStyleSettings, USHORT nStyle ) +{ + // mask menu style + BOOL bMenuStyle = (nStyle & FRAME_DRAW_MENU) ? TRUE : FALSE; + nStyle &= ~FRAME_DRAW_MENU; + + Window *pWin = NULL; + if( pDev->GetOutDevType() == OUTDEV_WINDOW ) + pWin = (Window*) pDev; + + // UseFlatBorders disables 3D style for all frames except menus + // menus may use different border colors (eg on XP) + // normal frames will be drawn using the shadow color + // whereas window frame borders will use black + BOOL bFlatBorders = ( !bMenuStyle && rStyleSettings.GetUseFlatBorders() ); + + // no flat borders for standard VCL controls (ie formcontrols that keep their classic look) + // will not affect frame windows (like dropdowns) + if( bFlatBorders && pWin && pWin->GetType() == WINDOW_BORDERWINDOW && (pWin != pWin->ImplGetFrameWindow()) ) + { + // check for formcontrol, i.e., a control without NWF enabled + Control *pControl = dynamic_cast< Control* >( pWin->GetWindow( WINDOW_CLIENT ) ); + if( pControl && pControl->IsNativeWidgetEnabled() ) + bFlatBorders = TRUE; + else + bFlatBorders = FALSE; + } + + // no round corners for window frame borders + BOOL bRound = (bFlatBorders && !(nStyle & FRAME_DRAW_WINDOWBORDER)); + + if ( (rStyleSettings.GetOptions() & STYLE_OPTION_MONO) || + (pDev->GetOutDevType() == OUTDEV_PRINTER) || + bFlatBorders ) + nStyle |= FRAME_DRAW_MONO; + + if ( nStyle & FRAME_DRAW_NODRAW ) + { + USHORT nValueStyle = bMenuStyle ? nStyle | FRAME_DRAW_MENU : nStyle; + if( pWin->GetType() == WINDOW_BORDERWINDOW ) + nValueStyle |= FRAME_DRAW_BORDERWINDOWBORDER; + ImplControlValue aControlValue( nValueStyle ); + Rectangle aBound, aContent; + Rectangle aNatRgn( rRect ); + if(pWin && pWin->GetNativeControlRegion(CTRL_FRAME, PART_BORDER, + aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + rRect = aContent; + } + else if ( nStyle & FRAME_DRAW_MONO ) + ImplDrawDPILineRect( pDev, rRect, NULL, bRound ); + else + { + USHORT nFrameStyle = nStyle & FRAME_DRAW_STYLE; + + if ( nFrameStyle == FRAME_DRAW_GROUP ) + { + rRect.Left() += 2; + rRect.Top() += 2; + rRect.Right() -= 2; + rRect.Bottom() -= 2; + } + else if ( (nFrameStyle == FRAME_DRAW_IN) || + (nFrameStyle == FRAME_DRAW_OUT) ) + { + rRect.Left()++; + rRect.Top()++; + rRect.Right()--; + rRect.Bottom()--; + } + else // FRAME_DRAW_DOUBLEIN || FRAME_DRAW_DOUBLEOUT + { + rRect.Left() += 2; + rRect.Top() += 2; + rRect.Right() -= 2; + rRect.Bottom() -= 2; + } + } + } + else + { + if( pWin && pWin->IsNativeControlSupported(CTRL_FRAME, PART_BORDER) ) + { + USHORT nValueStyle = bMenuStyle ? nStyle | FRAME_DRAW_MENU : nStyle; + if( pWin->GetType() == WINDOW_BORDERWINDOW ) + nValueStyle |= FRAME_DRAW_BORDERWINDOWBORDER; + ImplControlValue aControlValue( nValueStyle ); + Rectangle aBound, aContent; + Rectangle aNatRgn( rRect ); + if( pWin->GetNativeControlRegion(CTRL_FRAME, PART_BORDER, + aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + if( pWin->DrawNativeControl( CTRL_FRAME, PART_BORDER, aContent, CTRL_STATE_ENABLED, + aControlValue, rtl::OUString()) ) + { + rRect = aContent; + return; + } + } + } + + if ( nStyle & FRAME_DRAW_MONO ) + { + Color aColor = bRound ? rStyleSettings.GetShadowColor() + : pDev->GetSettings().GetStyleSettings().GetMonoColor(); + // when the MonoColor wasn't set, check face color + if ( + (bRound && aColor.IsDark()) || + ( + (aColor == Color(COL_BLACK)) && + (pDev->GetSettings().GetStyleSettings().GetFaceColor().IsDark()) + ) + ) + { + aColor = Color( COL_WHITE ); + } + ImplDrawDPILineRect( pDev, rRect, &aColor, bRound ); + } + else + { + USHORT nFrameStyle = nStyle & FRAME_DRAW_STYLE; + if ( nFrameStyle == FRAME_DRAW_GROUP ) + { + pDev->SetFillColor(); + pDev->SetLineColor( rStyleSettings.GetLightColor() ); + rRect.Top()++; + rRect.Left()++; + pDev->DrawRect( rRect ); + rRect.Top()--; + rRect.Left()--; + pDev->SetLineColor( rStyleSettings.GetShadowColor() ); + rRect.Right()--; + rRect.Bottom()--; + pDev->DrawRect( rRect ); + rRect.Right()++; + rRect.Bottom()++; + } + else + { + pDev->SetLineColor(); + + if ( (nFrameStyle == FRAME_DRAW_IN) || + (nFrameStyle == FRAME_DRAW_OUT) ) + { + if ( nFrameStyle == FRAME_DRAW_IN ) + { + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetShadowColor(), + rStyleSettings.GetLightColor() ); + } + else + { + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetLightColor(), + rStyleSettings.GetShadowColor() ); + } + + rRect.Left()++; + rRect.Top()++; + rRect.Right()--; + rRect.Bottom()--; + } + else // FRAME_DRAW_DOUBLEIN || FRAME_DRAW_DOUBLEOUT + { + if ( nFrameStyle == FRAME_DRAW_DOUBLEIN ) + { + if( bFlatBorders ) // no 3d effect + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetShadowColor(), + rStyleSettings.GetShadowColor() ); + else + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetShadowColor(), + rStyleSettings.GetLightColor() ); + } + else + { + if( bMenuStyle ) + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetMenuBorderColor(), + rStyleSettings.GetDarkShadowColor() ); + else + pDev->ImplDraw2ColorFrame( rRect, + bFlatBorders ? // no 3d effect + rStyleSettings.GetDarkShadowColor() : + rStyleSettings.GetLightBorderColor(), + rStyleSettings.GetDarkShadowColor() ); + + } + + rRect.Left()++; + rRect.Top()++; + rRect.Right()--; + rRect.Bottom()--; + + BOOL bDrawn = TRUE; + if ( nFrameStyle == FRAME_DRAW_DOUBLEIN ) + { + if( bFlatBorders ) // no 3d effect + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetFaceColor(), + rStyleSettings.GetFaceColor() ); + else + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetDarkShadowColor(), + rStyleSettings.GetLightBorderColor() ); + } + else + { + // flat menues have no shadow border + if( !bMenuStyle || !rStyleSettings.GetUseFlatMenues() ) + pDev->ImplDraw2ColorFrame( rRect, + rStyleSettings.GetLightColor(), + rStyleSettings.GetShadowColor() ); + else + bDrawn = FALSE; + } + if( bDrawn ) + { + rRect.Left()++; + rRect.Top()++; + rRect.Right()--; + rRect.Bottom()--; + } + } + } + } + } +} + +// ----------------------------------------------------------------------- + +Rectangle DecorationView::DrawFrame( const Rectangle& rRect, USHORT nStyle ) +{ + Rectangle aRect = rRect; + BOOL bOldMap = mpOutDev->IsMapModeEnabled(); + if ( bOldMap ) + { + aRect = mpOutDev->LogicToPixel( aRect ); + mpOutDev->EnableMapMode( FALSE ); + } + + if ( !rRect.IsEmpty() ) + { + if ( nStyle & FRAME_DRAW_NODRAW ) + ImplDrawFrame( mpOutDev, aRect, mpOutDev->GetSettings().GetStyleSettings(), nStyle ); + else + { + Color maOldLineColor = mpOutDev->GetLineColor(); + Color maOldFillColor = mpOutDev->GetFillColor(); + ImplDrawFrame( mpOutDev, aRect, mpOutDev->GetSettings().GetStyleSettings(), nStyle ); + mpOutDev->SetLineColor( maOldLineColor ); + mpOutDev->SetFillColor( maOldFillColor ); + } + } + + if ( bOldMap ) + { + mpOutDev->EnableMapMode( bOldMap ); + aRect = mpOutDev->PixelToLogic( aRect ); + } + + return aRect; +} + +// ======================================================================= + +static void ImplDrawButton( OutputDevice* pDev, Rectangle& rRect, + const StyleSettings& rStyleSettings, USHORT nStyle ) +{ + Rectangle aFillRect = rRect; + + if ( nStyle & BUTTON_DRAW_MONO ) + { + if ( !(nStyle & BUTTON_DRAW_NODRAW) ) + { + Color aBlackColor( COL_BLACK ); + + if ( nStyle & BUTTON_DRAW_DEFAULT ) + ImplDrawDPILineRect( pDev, aFillRect, &aBlackColor ); + + ImplDrawDPILineRect( pDev, aFillRect, &aBlackColor ); + + Size aBrdSize( 1, 1 ); + if ( pDev->GetOutDevType() == OUTDEV_PRINTER ) + { + MapMode aResMapMode( MAP_100TH_MM ); + aBrdSize = pDev->LogicToPixel( Size( 20, 20 ), aResMapMode ); + if ( !aBrdSize.Width() ) + aBrdSize.Width() = 1; + if ( !aBrdSize.Height() ) + aBrdSize.Height() = 1; + } + pDev->SetLineColor(); + pDev->SetFillColor( aBlackColor ); + Rectangle aRect1; + Rectangle aRect2; + aRect1.Left() = aFillRect.Left(); + aRect1.Right() = aFillRect.Right(), + aRect2.Top() = aFillRect.Top(); + aRect2.Bottom() = aFillRect.Bottom(); + if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) ) + { + aRect1.Top() = aFillRect.Top(); + aRect1.Bottom() = aBrdSize.Height()-1; + aRect2.Left() = aFillRect.Left(); + aRect2.Right() = aFillRect.Left()+aBrdSize.Width()-1; + aFillRect.Left() += aBrdSize.Width(); + aFillRect.Top() += aBrdSize.Height(); + } + else + { + aRect1.Top() = aFillRect.Bottom()-aBrdSize.Height()+1; + aRect1.Bottom() = aFillRect.Bottom(); + aRect2.Left() = aFillRect.Right()-aBrdSize.Width()+1; + aRect2.Right() = aFillRect.Right(), + aFillRect.Right() -= aBrdSize.Width(); + aFillRect.Bottom() -= aBrdSize.Height(); + } + pDev->DrawRect( aRect1 ); + pDev->DrawRect( aRect2 ); + } + } + else + { + if ( !(nStyle & BUTTON_DRAW_NODRAW) ) + { + if ( nStyle & BUTTON_DRAW_DEFAULT ) + { + Color aDefBtnColor = rStyleSettings.GetDarkShadowColor(); + ImplDrawDPILineRect( pDev, aFillRect, &aDefBtnColor ); + } + } + + if ( !(nStyle & BUTTON_DRAW_NODRAW) ) + { + pDev->SetLineColor(); + if ( nStyle & BUTTON_DRAW_NOLEFTLIGHTBORDER ) + { + pDev->SetFillColor( rStyleSettings.GetLightBorderColor() ); + pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Top(), + aFillRect.Left(), aFillRect.Bottom() ) ); + aFillRect.Left()++; + } + if ( (nStyle & BUTTON_DRAW_NOTOPLIGHTBORDER) && + !(nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED)) ) + { + pDev->SetFillColor( rStyleSettings.GetLightBorderColor() ); + pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Top(), + aFillRect.Right(), aFillRect.Top() ) ); + aFillRect.Top()++; + } + if ( (( (nStyle & BUTTON_DRAW_NOBOTTOMSHADOWBORDER) | BUTTON_DRAW_FLAT) == (BUTTON_DRAW_NOBOTTOMSHADOWBORDER | BUTTON_DRAW_FLAT)) && + !(nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED | BUTTON_DRAW_HIGHLIGHT)) ) + { + pDev->SetFillColor( rStyleSettings.GetDarkShadowColor() ); + pDev->DrawRect( Rectangle( aFillRect.Left(), aFillRect.Bottom(), + aFillRect.Right(), aFillRect.Bottom() ) ); + aFillRect.Bottom()--; + } + + Color aColor1; + Color aColor2; + if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) ) + { + aColor1 = rStyleSettings.GetDarkShadowColor(); + aColor2 = rStyleSettings.GetLightColor(); + } + else + { + if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER ) + aColor1 = rStyleSettings.GetLightBorderColor(); + else + aColor1 = rStyleSettings.GetLightColor(); + if ( (nStyle & BUTTON_DRAW_FLATTEST) == BUTTON_DRAW_FLAT ) + aColor2 = rStyleSettings.GetShadowColor(); + else + aColor2 = rStyleSettings.GetDarkShadowColor(); + } + pDev->ImplDraw2ColorFrame( aFillRect, aColor1, aColor2 ); + aFillRect.Left()++; + aFillRect.Top()++; + aFillRect.Right()--; + aFillRect.Bottom()--; + + if ( !((nStyle & BUTTON_DRAW_FLATTEST) == BUTTON_DRAW_FLAT) ) + { + if ( nStyle & (BUTTON_DRAW_PRESSED | BUTTON_DRAW_CHECKED) ) + { + aColor1 = rStyleSettings.GetShadowColor(); + aColor2 = rStyleSettings.GetLightBorderColor(); + } + else + { + if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER ) + aColor1 = rStyleSettings.GetLightColor(); + else + aColor1 = rStyleSettings.GetLightBorderColor(); + aColor2 = rStyleSettings.GetShadowColor(); + } + pDev->ImplDraw2ColorFrame( aFillRect, aColor1, aColor2 ); + aFillRect.Left()++; + aFillRect.Top()++; + aFillRect.Right()--; + aFillRect.Bottom()--; + } + } + } + + if ( !(nStyle & (BUTTON_DRAW_NOFILL | BUTTON_DRAW_NODRAW)) ) + { + pDev->SetLineColor(); + if ( nStyle & BUTTON_DRAW_MONO ) + { + // Hack: Auf Druckern wollen wir im MonoChrom-Modus trotzdem + // erstmal graue Buttons haben + if ( pDev->GetOutDevType() == OUTDEV_PRINTER ) + pDev->SetFillColor( Color( COL_LIGHTGRAY ) ); + else + pDev->SetFillColor( Color( COL_WHITE ) ); + } + else + { + if ( nStyle & (BUTTON_DRAW_CHECKED | BUTTON_DRAW_DONTKNOW) ) + pDev->SetFillColor( rStyleSettings.GetCheckedColor() ); + else + pDev->SetFillColor( rStyleSettings.GetFaceColor() ); + } + pDev->DrawRect( aFillRect ); + } + + // Ein Border freilassen, der jedoch bei Default-Darstellung + // mitbenutzt wird + rRect.Left()++; + rRect.Top()++; + rRect.Right()--; + rRect.Bottom()--; + + if ( nStyle & BUTTON_DRAW_NOLIGHTBORDER ) + { + rRect.Left()++; + rRect.Top()++; + } + else if ( nStyle & BUTTON_DRAW_NOLEFTLIGHTBORDER ) + rRect.Left()++; + + if ( nStyle & BUTTON_DRAW_PRESSED ) + { + if ( (rRect.GetHeight() > 10) && (rRect.GetWidth() > 10) ) + { + rRect.Left() += 4; + rRect.Top() += 4; + rRect.Right() -= 1; + rRect.Bottom() -= 1; + } + else + { + rRect.Left() += 3; + rRect.Top() += 3; + rRect.Right() -= 2; + rRect.Bottom() -= 2; + } + } + else if ( nStyle & BUTTON_DRAW_CHECKED ) + { + rRect.Left() += 3; + rRect.Top() += 3; + rRect.Right() -= 2; + rRect.Bottom() -= 2; + } + else + { + rRect.Left() += 2; + rRect.Top() += 2; + rRect.Right() -= 3; + rRect.Bottom() -= 3; + } +} + +// ----------------------------------------------------------------------- + +Rectangle DecorationView::DrawButton( const Rectangle& rRect, USHORT nStyle ) +{ + Rectangle aRect = rRect; + BOOL bOldMap = mpOutDev->IsMapModeEnabled(); + if ( bOldMap ) + { + aRect = mpOutDev->LogicToPixel( aRect ); + mpOutDev->EnableMapMode( FALSE ); + } + + if ( !rRect.IsEmpty() ) + { + const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings(); + + if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO ) + nStyle |= BUTTON_DRAW_MONO; + + if ( nStyle & BUTTON_DRAW_NODRAW ) + ImplDrawButton( mpOutDev, aRect, rStyleSettings, nStyle ); + else + { + Color maOldLineColor = mpOutDev->GetLineColor(); + Color maOldFillColor = mpOutDev->GetFillColor(); + ImplDrawButton( mpOutDev, aRect, rStyleSettings, nStyle ); + mpOutDev->SetLineColor( maOldLineColor ); + mpOutDev->SetFillColor( maOldFillColor ); + } + } + + if ( bOldMap ) + { + mpOutDev->EnableMapMode( bOldMap ); + aRect = mpOutDev->PixelToLogic( aRect ); + } + + return aRect; +} + +// ----------------------------------------------------------------------- + +void DecorationView::DrawSeparator( const Point& rStart, const Point& rStop, bool bVertical ) +{ + Point aStart( rStart ), aStop( rStop ); + const StyleSettings& rStyleSettings = mpOutDev->GetSettings().GetStyleSettings(); + + mpOutDev->Push( PUSH_LINECOLOR ); + if ( rStyleSettings.GetOptions() & STYLE_OPTION_MONO ) + mpOutDev->SetLineColor( Color( COL_BLACK ) ); + else + mpOutDev->SetLineColor( rStyleSettings.GetShadowColor() ); + + mpOutDev->DrawLine( aStart, aStop ); + if ( !(rStyleSettings.GetOptions() & STYLE_OPTION_MONO) ) + { + mpOutDev->SetLineColor( rStyleSettings.GetLightColor() ); + if( bVertical ) + { + aStart.X()++; + aStop.X()++; + } + else + { + aStart.Y()++; + aStop.Y()++; + } + mpOutDev->DrawLine( aStart, aStop ); + } + mpOutDev->Pop(); +} + diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx new file mode 100644 index 000000000000..3b5585d3bc63 --- /dev/null +++ b/vcl/source/window/dialog.cxx @@ -0,0 +1,1028 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/debug.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.h> +#include <vcl/event.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/button.hxx> +#include <vcl/mnemonic.hxx> +#include <vcl/dialog.hxx> +#include <vcl/decoview.hxx> + +#ifdef DBG_UTIL +#include <vcl/msgbox.hxx> +#endif + +#include <vcl/unowrap.hxx> + + + +// ======================================================================= + +#ifdef DBG_UTIL + +static ByteString ImplGetDialogText( Dialog* pDialog ) +{ + ByteString aErrorStr( pDialog->GetText(), RTL_TEXTENCODING_UTF8 ); + if ( (pDialog->GetType() == WINDOW_MESSBOX) || + (pDialog->GetType() == WINDOW_INFOBOX) || + (pDialog->GetType() == WINDOW_WARNINGBOX) || + (pDialog->GetType() == WINDOW_ERRORBOX) || + (pDialog->GetType() == WINDOW_QUERYBOX) ) + { + aErrorStr += ", "; + aErrorStr += ByteString( ((MessBox*)pDialog)->GetMessText(), RTL_TEXTENCODING_UTF8 ); + } + return aErrorStr; +} + +#endif + +// ======================================================================= + +static BOOL ImplIsMnemonicCtrl( Window* pWindow ) +{ + if( ! pWindow->GetSettings().GetStyleSettings().GetAutoMnemonic() ) + return FALSE; + + if ( (pWindow->GetType() == WINDOW_RADIOBUTTON) || + (pWindow->GetType() == WINDOW_CHECKBOX) || + (pWindow->GetType() == WINDOW_TRISTATEBOX) || + (pWindow->GetType() == WINDOW_PUSHBUTTON) ) + return TRUE; + + if ( pWindow->GetType() == WINDOW_FIXEDTEXT ) + { + if ( pWindow->GetStyle() & (WB_INFO | WB_NOLABEL) ) + return FALSE; + Window* pNextWindow = pWindow->GetWindow( WINDOW_NEXT ); + if ( !pNextWindow ) + return FALSE; + pNextWindow = pNextWindow->GetWindow( WINDOW_CLIENT ); + if ( !(pNextWindow->GetStyle() & WB_TABSTOP) || + (pNextWindow->GetType() == WINDOW_FIXEDTEXT) || + (pNextWindow->GetType() == WINDOW_GROUPBOX) || + (pNextWindow->GetType() == WINDOW_RADIOBUTTON) || + (pNextWindow->GetType() == WINDOW_CHECKBOX) || + (pNextWindow->GetType() == WINDOW_TRISTATEBOX) || + (pNextWindow->GetType() == WINDOW_PUSHBUTTON) ) + return FALSE; + + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ImplWindowAutoMnemonic( Window* pWindow ) +{ + MnemonicGenerator aMnemonicGenerator; + Window* pGetChild; + Window* pChild; + + // Die schon vergebenen Mnemonics registieren + pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD ); + while ( pGetChild ) + { + pChild = pGetChild->ImplGetWindow(); + aMnemonicGenerator.RegisterMnemonic( pChild->GetText() ); + pGetChild = pGetChild->GetWindow( WINDOW_NEXT ); + } + + // Bei TabPages auch noch die Controls vom Dialog beruecksichtigen + if ( pWindow->GetType() == WINDOW_TABPAGE ) + { + Window* pParent = pWindow->GetParent(); + if ( pParent->GetType() == WINDOW_TABCONTROL ) + pParent = pParent->GetParent(); + + if ( (pParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL ) + { + pGetChild = pParent->GetWindow( WINDOW_FIRSTCHILD ); + while ( pGetChild ) + { + pChild = pGetChild->ImplGetWindow(); + aMnemonicGenerator.RegisterMnemonic( pChild->GetText() ); + pGetChild = pGetChild->GetWindow( WINDOW_NEXT ); + } + } + } + + // Die Mnemonics an die Controls vergeben, die noch keinen haben + pGetChild = pWindow->GetWindow( WINDOW_FIRSTCHILD ); + while ( pGetChild ) + { + pChild = pGetChild->ImplGetWindow(); + if ( ImplIsMnemonicCtrl( pChild ) ) + { + XubString aText = pChild->GetText(); + if ( aMnemonicGenerator.CreateMnemonic( aText ) ) + pChild->SetText( aText ); + } + + pGetChild = pGetChild->GetWindow( WINDOW_NEXT ); + } +} + +// ======================================================================= + +static PushButton* ImplGetDefaultButton( Dialog* pDialog ) +{ + Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild ) + { + if ( pChild->ImplIsPushButton() ) + { + PushButton* pPushButton = (PushButton*)pChild; + if ( pPushButton->ImplIsDefButton() ) + return pPushButton; + } + + pChild = pChild->GetWindow( WINDOW_NEXT ); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static PushButton* ImplGetOKButton( Dialog* pDialog ) +{ + Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild ) + { + if ( pChild->GetType() == WINDOW_OKBUTTON ) + return (PushButton*)pChild; + + pChild = pChild->GetWindow( WINDOW_NEXT ); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static PushButton* ImplGetCancelButton( Dialog* pDialog ) +{ + Window* pChild = pDialog->GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild ) + { + if ( pChild->GetType() == WINDOW_CANCELBUTTON ) + return (PushButton*)pChild; + + pChild = pChild->GetWindow( WINDOW_NEXT ); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static void ImplMouseAutoPos( Dialog* pDialog ) +{ + ULONG nMouseOptions = pDialog->GetSettings().GetMouseSettings().GetOptions(); + if ( nMouseOptions & MOUSE_OPTION_AUTOCENTERPOS ) + { + Size aSize = pDialog->GetOutputSizePixel(); + pDialog->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) ); + } + else if ( nMouseOptions & MOUSE_OPTION_AUTODEFBTNPOS ) + { + Window* pWindow = ImplGetDefaultButton( pDialog ); + if ( !pWindow ) + pWindow = ImplGetOKButton( pDialog ); + if ( !pWindow ) + pWindow = ImplGetCancelButton( pDialog ); + if ( !pWindow ) + pWindow = pDialog; + Size aSize = pWindow->GetOutputSizePixel(); + pWindow->SetPointerPosPixel( Point( aSize.Width()/2, aSize.Height()/2 ) ); + } +} + +// ======================================================================= + +struct DialogImpl +{ + long mnResult; + bool mbStartedModal; + Link maEndDialogHdl; + + DialogImpl() : mnResult( -1 ), mbStartedModal( false ) {} +}; + +// ======================================================================= + +void Dialog::ImplInitDialogData() +{ + mpWindowImpl->mbDialog = TRUE; + mpDialogParent = NULL; + mpPrevExecuteDlg = NULL; + mbInExecute = FALSE; + mbOldSaveBack = FALSE; + mbInClose = FALSE; + mbModalMode = FALSE; + mnMousePositioned = 0; + mpDialogImpl = new DialogImpl; +} + +// ----------------------------------------------------------------------- + +void Dialog::ImplInit( Window* pParent, WinBits nStyle ) +{ + USHORT nSysWinMode = Application::GetSystemWindowMode(); + + if ( !(nStyle & WB_NODIALOGCONTROL) ) + nStyle |= WB_DIALOGCONTROL; + nStyle |= WB_ROLLABLE; + + // Now, all Dialogs are per default system windows !!! + nStyle |= WB_SYSTEMWINDOW; + + + // parent is NULL: get the default Dialog parent + if ( !pParent ) + { + pParent = Application::GetDefDialogParent(); + if ( !pParent && !(nStyle & WB_SYSTEMWINDOW) ) + pParent = ImplGetSVData()->maWinData.mpAppWin; + + // If Parent is disabled, then we search for a modal dialog + // in this frame + if ( pParent && (!pParent->IsInputEnabled() || pParent->IsInModalMode()) ) + { + ImplSVData* pSVData = ImplGetSVData(); + Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg; + while ( pExeDlg ) + { + // Nur wenn er sichtbar und enabled ist + if ( pParent->ImplGetFirstOverlapWindow()->IsWindowOrChild( pExeDlg, TRUE ) && + pExeDlg->IsReallyVisible() && + pExeDlg->IsEnabled() && pExeDlg->IsInputEnabled() && !pExeDlg->IsInModalMode() ) + { + pParent = pExeDlg; + break; + } + + pExeDlg = pExeDlg->mpPrevExecuteDlg; + } + } + } + // DIALOG_NO_PARENT: explicitly don't have a parent for this Dialog + else if( pParent == DIALOG_NO_PARENT ) + pParent = NULL; + +/* + // Now, all Dialogs are per default system windows !!! + if ( pParent && !(nSysWinMode & SYSTEMWINDOW_MODE_NOAUTOMODE) ) + { + if ( !pParent->mpWindowImpl->mpFrameWindow->IsVisible() ) + pParent = NULL; + else + { + if ( pParent->mpWindowImpl->mpFrameWindow->IsDialog() ) + { + Size aOutSize = pParent->mpWindowImpl->mpFrameWindow->GetOutputSizePixel(); + if ( (aOutSize.Width() < 210) ||(aOutSize.Height() < 160) ) + nStyle |= WB_SYSTEMWINDOW; + } + } + } +*/ + + if ( !pParent || (nStyle & WB_SYSTEMWINDOW) || + (pParent->mpWindowImpl->mpFrameData->mbNeedSysWindow && !(nSysWinMode & SYSTEMWINDOW_MODE_NOAUTOMODE)) || + (nSysWinMode & SYSTEMWINDOW_MODE_DIALOG) ) + { + // create window with a small border ? + if ( (nStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE)) == WB_BORDER ) + { + ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_FRAME ); + SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL ); + pBorderWin->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpWindowImpl->mpBorderWindow = pBorderWin; + mpWindowImpl->mpRealParent = pParent; + } + else + { + mpWindowImpl->mbFrame = TRUE; + mpWindowImpl->mbOverlapWin = TRUE; + SystemWindow::ImplInit( pParent, (nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE)) | WB_CLOSEABLE, NULL ); + // Now set all style bits + mpWindowImpl->mnStyle = nStyle; + } + } + else + { + ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle, BORDERWINDOW_STYLE_OVERLAP | BORDERWINDOW_STYLE_BORDER ); + SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL ); + pBorderWin->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpWindowImpl->mpBorderWindow = pBorderWin; + mpWindowImpl->mpRealParent = pParent; + } + + SetActivateMode( ACTIVATE_MODE_GRABFOCUS ); + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +void Dialog::ImplInitSettings() +{ + // user override + if ( IsControlBackground() ) + SetBackground( GetControlBackground() ); + // NWF background + else if( IsNativeControlSupported( CTRL_WINDOW_BACKGROUND, PART_BACKGROUND_DIALOG ) ) + { + mpWindowImpl->mnNativeBackground = PART_BACKGROUND_DIALOG; + EnableChildTransparentMode( TRUE ); + } + // fallback to settings color + else + SetBackground( GetSettings().GetStyleSettings().GetDialogColor() ); + +} + +// ----------------------------------------------------------------------- + +void Dialog::ImplCenterDialog() +{ + Rectangle aDeskRect = ImplGetFrameWindow()->GetDesktopRectPixel(); + Point aDeskPos = aDeskRect.TopLeft(); + Size aDeskSize = aDeskRect.GetSize(); + Size aWinSize = GetSizePixel(); + Window *pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + Point aWinPos( ((aDeskSize.Width() - aWinSize.Width()) / 2) + aDeskPos.X(), + ((aDeskSize.Height() - aWinSize.Height()) / 2) + aDeskPos.Y() ); + + // Pruefen, ob Dialogbox ausserhalb des Desks liegt + if ( (aWinPos.X() + aWinSize.Width()) > (aDeskPos.X()+aDeskSize.Width()) ) + aWinPos.X() = aDeskPos.X()+aDeskSize.Width() - aWinSize.Width(); + if ( (aWinPos.Y()+aWinSize.Height()) > (aDeskPos.Y()+aDeskSize.Height()) ) + aWinPos.Y() = aDeskPos.Y()+aDeskSize.Height() - aWinSize.Height(); + // Linke Ecke bevorzugen, da Titelbar oben ist + if ( aWinPos.X() < aDeskPos.X() ) + aWinPos.X() = aDeskPos.X(); + if ( aWinPos.Y() < aDeskPos.Y() ) + aWinPos.Y() = aDeskPos.Y(); + + //SetPosPixel( aWinPos ); + SetPosPixel( pWindow->ScreenToOutputPixel( aWinPos ) ); +} + +// ----------------------------------------------------------------------- + +Dialog::Dialog( WindowType nType ) : + SystemWindow( nType ) +{ + ImplInitDialogData(); +} + +// ----------------------------------------------------------------------- + +Dialog::Dialog( Window* pParent, WinBits nStyle ) : + SystemWindow( WINDOW_DIALOG ) +{ + ImplInitDialogData(); + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +Dialog::Dialog( Window* pParent, const ResId& rResId ) : + SystemWindow( WINDOW_DIALOG ) +{ + ImplInitDialogData(); + rResId.SetRT( RSC_DIALOG ); + ImplInit( pParent, ImplInitRes( rResId ) ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +Dialog::~Dialog() +{ + delete mpDialogImpl; + mpDialogImpl = NULL; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Dialog, ImplAsyncCloseHdl, void*, EMPTYARG ) +{ + Close(); + return 0; +} + +// ----------------------------------------------------------------------- + +long Dialog::Notify( NotifyEvent& rNEvt ) +{ + // Zuerst Basisklasse rufen wegen TabSteuerung + long nRet = SystemWindow::Notify( rNEvt ); + if ( !nRet ) + { + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( (nKeyCode == KEY_ESCAPE) && + ((GetStyle() & WB_CLOSEABLE) || ImplGetCancelButton( this ) || ImplGetOKButton( this )) ) + { + // #i89505# for the benefit of slightly mentally challenged implementations + // like e.g. SfxModelessDialog which destroy themselves inside Close() + // post this Close asynchronous so we can leave our key handler before + // we get destroyed + PostUserEvent( LINK( this, Dialog, ImplAsyncCloseHdl ), this ); + return TRUE; + } + } + else if ( rNEvt.GetType() == EVENT_GETFOCUS ) + { + // make sure the dialog is still modal + // changing focus between application frames may + // have re-enabled input for our parent + if( mbInExecute && mbModalMode ) + { + // do not change modal counter (pSVData->maAppData.mnModalDialog) + SetModalInputMode( FALSE ); + SetModalInputMode( TRUE ); + + // #93022# def-button might have changed after show + if( !mnMousePositioned ) + { + mnMousePositioned = 1; + ImplMouseAutoPos( this ); + } + + } + } + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +void Dialog::StateChanged( StateChangedType nType ) +{ + SystemWindow::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + { + if ( GetSettings().GetStyleSettings().GetAutoMnemonic() ) + ImplWindowAutoMnemonic( this ); + + //if ( IsDefaultPos() && !mpWindowImpl->mbFrame ) + // ImplCenterDialog(); + if ( !HasChildPathFocus() || HasFocus() ) + GrabFocusToFirstControl(); + if ( !(GetStyle() & WB_CLOSEABLE) ) + { + if ( ImplGetCancelButton( this ) || ImplGetOKButton( this ) ) + { + if ( ImplGetBorderWindow() ) + ((ImplBorderWindow*)ImplGetBorderWindow())->SetCloser(); + } + } + + ImplMouseAutoPos( this ); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void Dialog::DataChanged( const DataChangedEvent& rDCEvt ) +{ + SystemWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +BOOL Dialog::Close() +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE ); + if ( aDelData.IsDelete() ) + return FALSE; + ImplRemoveDel( &aDelData ); + + if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() ) + return FALSE; + + mbInClose = TRUE; + + if ( !(GetStyle() & WB_CLOSEABLE) ) + { + BOOL bRet = TRUE; + ImplAddDel( &aDelData ); + PushButton* pButton = ImplGetCancelButton( this ); + if ( pButton ) + pButton->Click(); + else + { + pButton = ImplGetOKButton( this ); + if ( pButton ) + pButton->Click(); + else + bRet = FALSE; + } + if ( aDelData.IsDelete() ) + return TRUE; + ImplRemoveDel( &aDelData ); + return bRet; + } + + if ( IsInExecute() ) + { + EndDialog( FALSE ); + mbInClose = FALSE; + return TRUE; + } + else + { + mbInClose = FALSE; + return SystemWindow::Close(); + } +} + +// ----------------------------------------------------------------------- + +BOOL Dialog::ImplStartExecuteModal() +{ + if ( mbInExecute ) + { +#ifdef DBG_UTIL + ByteString aErrorStr( "Dialog::StartExecuteModal() is called in Dialog::StartExecuteModal(): " ); + aErrorStr += ImplGetDialogText( this ); + DBG_ERROR( aErrorStr.GetBuffer() ); +#endif + return FALSE; + } + + if ( Application::IsDialogCancelEnabled() ) + { +#ifdef DBG_UTIL + ByteString aErrorStr( "Dialog::StartExecuteModal() is called in a none UI application: " ); + aErrorStr += ImplGetDialogText( this ); + DBG_ERROR( aErrorStr.GetBuffer() ); +#endif + return FALSE; + } + +#ifdef DBG_UTIL + Window* pParent = GetParent(); + if ( pParent ) + { + pParent = pParent->ImplGetFirstOverlapWindow(); + DBG_ASSERT( pParent->IsReallyVisible(), + "Dialog::StartExecuteModal() - Parent not visible" ); + DBG_ASSERT( pParent->IsInputEnabled(), + "Dialog::StartExecuteModal() - Parent input disabled, use another parent to ensure modality!" ); + DBG_ASSERT( ! pParent->IsInModalMode(), + "Dialog::StartExecuteModal() - Parent already modally disabled, use another parent to ensure modality!" ); + + } +#endif + + ImplSVData* pSVData = ImplGetSVData(); + + // Dialoge, die sich in Execute befinden, miteinander verketten + mpPrevExecuteDlg = pSVData->maWinData.mpLastExecuteDlg; + pSVData->maWinData.mpLastExecuteDlg = this; + + // Capture beenden, damit der Dialog bedient werden kann + if ( pSVData->maWinData.mpTrackWin ) + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL ); + if ( pSVData->maWinData.mpCaptureWin ) + pSVData->maWinData.mpCaptureWin->ReleaseMouse(); + EnableInput( TRUE, TRUE ); + + if ( GetParent() ) + { + NotifyEvent aNEvt( EVENT_EXECUTEDIALOG, this ); + GetParent()->Notify( aNEvt ); + } + mbInExecute = TRUE; + SetModalInputMode( TRUE ); + mbOldSaveBack = IsSaveBackgroundEnabled(); + EnableSaveBackground(); + + // FIXME: no layouting, workaround some clipping issues + ImplAdjustNWFSizes(); + + Show(); + + pSVData->maAppData.mnModalMode++; + return TRUE; +} + +// ----------------------------------------------------------------------- + +void Dialog::ImplEndExecuteModal() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mnModalMode--; +} + +// ----------------------------------------------------------------------- + +short Dialog::Execute() +{ + if ( !ImplStartExecuteModal() ) + return 0; + + ImplDelData aDelData; + ImplAddDel( &aDelData ); + +#ifdef DBG_UTIL + ImplDelData aParentDelData; + Window* pDialogParent = mpDialogParent; + if( pDialogParent ) + pDialogParent->ImplAddDel( &aParentDelData ); +#endif + + // Yield util EndDialog is called or dialog gets destroyed + // (the latter should not happen, but better safe than sorry + while ( !aDelData.IsDelete() && mbInExecute ) + Application::Yield(); + + ImplEndExecuteModal(); + +#ifdef DBG_UTIL + if( pDialogParent ) + { + if( ! aParentDelData.IsDelete() ) + pDialogParent->ImplRemoveDel( &aParentDelData ); + else + DBG_ERROR( "Dialog::Execute() - Parent of dialog destroyed in Execute()" ); + } +#endif + if ( !aDelData.IsDelete() ) + ImplRemoveDel( &aDelData ); +#ifdef DBG_UTIL + else + { + DBG_ERROR( "Dialog::Execute() - Dialog destroyed in Execute()" ); + } +#endif + + long nRet = mpDialogImpl->mnResult; + mpDialogImpl->mnResult = -1; + return (short)nRet; +} + +// ----------------------------------------------------------------------- + +// virtual +void Dialog::StartExecuteModal( const Link& rEndDialogHdl ) +{ + if ( !ImplStartExecuteModal() ) + return; + + mpDialogImpl->maEndDialogHdl = rEndDialogHdl; + mpDialogImpl->mbStartedModal = true; +} + +// ----------------------------------------------------------------------- + +BOOL Dialog::IsStartedModal() const +{ + return mpDialogImpl->mbStartedModal; +} + +// ----------------------------------------------------------------------- + +void Dialog::EndDialog( long nResult ) +{ + if ( mbInExecute ) + { + SetModalInputMode( FALSE ); + + // Dialog aus der Kette der Dialoge die in Execute stehen entfernen + ImplSVData* pSVData = ImplGetSVData(); + Dialog* pExeDlg = pSVData->maWinData.mpLastExecuteDlg; + while ( pExeDlg ) + { + if ( pExeDlg == this ) + { + pSVData->maWinData.mpLastExecuteDlg = mpPrevExecuteDlg; + break; + } + pExeDlg = pExeDlg->mpPrevExecuteDlg; + } + // set focus to previous modal dialogue if it is modal for + // the same frame parent (or NULL) + if( mpPrevExecuteDlg ) + { + Window* pFrameParent = ImplGetFrameWindow()->ImplGetParent(); + Window* pPrevFrameParent = mpPrevExecuteDlg->ImplGetFrameWindow()->ImplGetParent(); + if( ( !pFrameParent && !pPrevFrameParent ) || + ( pFrameParent && pPrevFrameParent && pFrameParent->ImplGetFrame() == pPrevFrameParent->ImplGetFrame() ) + ) + { + mpPrevExecuteDlg->GrabFocus(); + } + } + mpPrevExecuteDlg = NULL; + + Hide(); + EnableSaveBackground( mbOldSaveBack ); + if ( GetParent() ) + { + NotifyEvent aNEvt( EVENT_ENDEXECUTEDIALOG, this ); + GetParent()->Notify( aNEvt ); + } + + mpDialogImpl->mnResult = nResult; + + if ( mpDialogImpl->mbStartedModal ) + { + ImplEndExecuteModal(); + mpDialogImpl->maEndDialogHdl.Call( this ); + + mpDialogImpl->maEndDialogHdl = Link(); + mpDialogImpl->mbStartedModal = false; + mpDialogImpl->mnResult = -1; + } + mbInExecute = FALSE; + } +} + +// ----------------------------------------------------------------------- + +long Dialog::GetResult() const +{ + return mpDialogImpl->mnResult; +} + +// ----------------------------------------------------------------------- + +void Dialog::EndAllDialogs( Window* pParent ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Dialog* pTempModDialog; + Dialog* pModDialog = pSVData->maWinData.mpLastExecuteDlg; + while ( pModDialog ) + { + pTempModDialog = pModDialog->mpPrevExecuteDlg; + if( !pParent || ( pParent && pParent->IsWindowOrChild( pModDialog, TRUE ) ) ) + { + pModDialog->EndDialog( FALSE ); + pModDialog->PostUserEvent( Link() ); + } + pModDialog = pTempModDialog; + } +} + +// ----------------------------------------------------------------------- + +void Dialog::SetModalInputMode( BOOL bModal ) +{ + if ( bModal == mbModalMode ) + return; + + ImplSVData* pSVData = ImplGetSVData(); + mbModalMode = bModal; + if ( bModal ) + { + pSVData->maAppData.mnModalDialog++; + + // Diable the prev Modal Dialog, because our dialog must close at first, + // before the other dialog can be closed (because the other dialog + // is on stack since our dialog returns) + if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, TRUE ) ) + mpPrevExecuteDlg->EnableInput( FALSE, TRUE, TRUE, this ); + + // determine next overlap dialog parent + Window* pParent = GetParent(); + if ( pParent ) + { + // #103716# dialogs should always be modal to the whole frame window + // #115933# disable the whole frame hierarchie, useful if our parent + // is a modeless dialog + mpDialogParent = pParent->mpWindowImpl->mpFrameWindow; + mpDialogParent->ImplIncModalCount(); + } + + } + else + { + pSVData->maAppData.mnModalDialog--; + + if ( mpDialogParent ) + { + // #115933# re-enable the whole frame hierarchie again (see above) + // note that code in getfocus assures that we do not accidentally enable + // windows that were disabled before + mpDialogParent->ImplDecModalCount(); + } + + // Enable the prev Modal Dialog + if ( mpPrevExecuteDlg && !mpPrevExecuteDlg->IsWindowOrChild( this, TRUE ) ) + { + mpPrevExecuteDlg->EnableInput( TRUE, TRUE, TRUE, this ); + // ensure continued modality of prev dialog + // do not change modality counter + mpPrevExecuteDlg->SetModalInputMode( FALSE ); + mpPrevExecuteDlg->SetModalInputMode( TRUE ); + } + } +} + +// ----------------------------------------------------------------------- + +void Dialog::SetModalInputMode( BOOL bModal, BOOL bSubModalDialogs ) +{ + if ( bSubModalDialogs ) + { + Window* pOverlap = ImplGetFirstOverlapWindow(); + pOverlap = pOverlap->mpWindowImpl->mpFirstOverlap; + while ( pOverlap ) + { + if ( pOverlap->IsDialog() ) + ((Dialog*)pOverlap)->SetModalInputMode( bModal, TRUE ); + pOverlap = pOverlap->mpWindowImpl->mpNext; + } + } + + SetModalInputMode( bModal ); +} + +// ----------------------------------------------------------------------- + +void Dialog::GrabFocusToFirstControl() +{ + Window* pFocusControl; + + // Wenn Dialog den Focus hat, versuchen wr trotzdem + // ein Focus-Control zu finden + if ( HasFocus() ) + pFocusControl = NULL; + else + { + // Wenn schon ein Child-Fenster mal den Focus hatte, + // dann dieses bevorzugen + pFocusControl = ImplGetFirstOverlapWindow()->mpWindowImpl->mpLastFocusWindow; + // Control aus der Dialog-Steuerung suchen + if ( pFocusControl ) + pFocusControl = ImplFindDlgCtrlWindow( pFocusControl ); + } + // Kein Control hatte vorher den Focus, oder das Control + // befindet sich nicht in der Tab-Steuerung, dann das erste + // Control in der TabSteuerung den Focus geben + if ( !pFocusControl || + !(pFocusControl->GetStyle() & WB_TABSTOP) || + !pFocusControl->IsVisible() || + !pFocusControl->IsEnabled() || !pFocusControl->IsInputEnabled() ) + { + USHORT n = 0; + pFocusControl = ImplGetDlgWindow( n, DLGWINDOW_FIRST ); + } + if ( pFocusControl ) + pFocusControl->ImplControlFocus( GETFOCUS_INIT ); +} + +void Dialog::GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + ImplBorderWindow aImplWin( (Window*)this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP ); +// aImplWin.SetText( GetText() ); +// aImplWin.SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() ); +// aImplWin.SetDisplayActive( TRUE ); +// aImplWin.InitView(); + aImplWin.GetBorder( rLeftBorder, rTopBorder, rRightBorder, rBottomBorder ); +} + + +void Dialog::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG ) +{ + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = pDev->LogicToPixel( rSize ); + + Wallpaper aWallpaper = GetBackground(); + if ( !aWallpaper.IsBitmap() ) + ImplInitSettings(); + + pDev->Push(); + pDev->SetMapMode(); + pDev->SetLineColor(); + + if ( aWallpaper.IsBitmap() ) + pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() ); + else + { + pDev->SetFillColor( aWallpaper.GetColor() ); + pDev->DrawRect( Rectangle( aPos, aSize ) ); + } + + if (!( GetStyle() & WB_NOBORDER )) + { + ImplBorderWindow aImplWin( this, WB_BORDER|WB_STDWORK, BORDERWINDOW_STYLE_OVERLAP ); + aImplWin.SetText( GetText() ); + aImplWin.SetPosSizePixel( aPos.X(), aPos.Y(), aSize.Width(), aSize.Height() ); + aImplWin.SetDisplayActive( TRUE ); + aImplWin.InitView(); + + aImplWin.Draw( Rectangle( aPos, aSize ), pDev, aPos ); + } + + pDev->Pop(); +} + + +// ======================================================================= + +ModelessDialog::ModelessDialog( Window* pParent, WinBits nStyle ) : + Dialog( WINDOW_MODELESSDIALOG ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ModelessDialog::ModelessDialog( Window* pParent, const ResId& rResId ) : + Dialog( WINDOW_MODELESSDIALOG ) +{ + rResId.SetRT( RSC_MODELESSDIALOG ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ======================================================================= + +ModalDialog::ModalDialog( Window* pParent, WinBits nStyle ) : + Dialog( WINDOW_MODALDIALOG ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ModalDialog::ModalDialog( Window* pParent, const ResId& rResId ) : + Dialog( WINDOW_MODALDIALOG ) +{ + rResId.SetRT( RSC_MODALDIALOG ); + ImplInit( pParent, ImplInitRes( rResId ) ); + ImplLoadRes( rResId ); +} diff --git a/vcl/source/window/dlgctrl.cxx b/vcl/source/window/dlgctrl.cxx new file mode 100644 index 000000000000..055b7e9fe80b --- /dev/null +++ b/vcl/source/window/dlgctrl.cxx @@ -0,0 +1,1267 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/debug.hxx> +#include <vcl/svdata.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/tabpage.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/tabdlg.hxx> +#include <vcl/button.hxx> +#include <vcl/window.h> + +#include <vcl/unohelp.hxx> +#include <com/sun/star/i18n/XCharacterClassification.hpp> + +using namespace ::com::sun::star; + +// ======================================================================= + +static BOOL ImplHasIndirectTabParent( Window* pWindow ) +{ + // The window has inderect tab parent if it is included in tab hierarchy + // of the indirect parent window + + return ( pWindow && pWindow->GetParent() + && ( pWindow->GetParent()->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) ); +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetTopParentOfTabHierarchy( Window* pParent ) +{ + // The method allows to find the most close parent containing all the + // window from the current tab-hierarchy + // The direct parent should be provided as a parameter here + + Window* pResult = pParent; + + if ( pResult ) + { + while ( pResult->GetParent() && ( pResult->ImplGetWindow()->GetStyle() & WB_CHILDDLGCTRL ) ) + pResult = pResult->GetParent(); + } + + return pResult; +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetSubChildWindow( Window* pParent, USHORT n, USHORT& nIndex ) +{ + Window* pTabPage = NULL; + Window* pFoundWindow = NULL; + + Window* pWindow = pParent->GetWindow( WINDOW_FIRSTCHILD ); + Window* pNextWindow = pWindow; + while ( pWindow ) + { + pWindow = pWindow->ImplGetWindow(); + + // Unsichtbare und disablte Fenster werden uebersprungen + if ( pTabPage || pWindow->IsVisible() ) + { + // Wenn das letzte Control ein TabControl war, wird von + // diesem die TabPage genommen + if ( pTabPage ) + { + pFoundWindow = ImplGetSubChildWindow( pTabPage, n, nIndex ); + pTabPage = NULL; + } + else + { + pFoundWindow = pWindow; + + // Bei einem TabControl sich die aktuelle TabPage merken, + // damit diese dann genommen wird + if ( pWindow->GetType() == WINDOW_TABCONTROL ) + { + TabControl* pTabControl = ((TabControl*)pWindow); + // Feststellen, ob TabPage Child vom TabControl ist + // und auch noch existiert (deshalb durch Vergleich, + // indem alle ChildFenster getestet werden). Denn es + // kann sein, das TabPages schon in einem Dialog-Dtor + // zerstoert wurden, obwohl das TabControl noch + // existiert. + TabPage* pTempTabPage = pTabControl->GetTabPage( pTabControl->GetCurPageId() ); + if ( pTempTabPage ) + { + Window* pTempWindow = pTabControl->GetWindow( WINDOW_FIRSTCHILD ); + while ( pTempWindow ) + { + if ( pTempWindow->ImplGetWindow() == pTempTabPage ) + { + pTabPage = pTempTabPage; + break; + } + pTempWindow = pTempWindow->GetWindow( WINDOW_NEXT ); + } + } + } + else if ( ( pWindow->GetStyle() & WB_DIALOGCONTROL ) + || ( pWindow->GetStyle() & WB_CHILDDLGCTRL ) ) + pFoundWindow = ImplGetSubChildWindow( pWindow, n, nIndex ); + } + + if ( n == nIndex ) + return pFoundWindow; + nIndex++; + } + + if ( pTabPage ) + pWindow = pTabPage; + else + { + pWindow = pNextWindow->GetWindow( WINDOW_NEXT ); + pNextWindow = pWindow; + } + } + + nIndex--; + return pFoundWindow; +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetChildWindow( Window* pParent, USHORT n, USHORT& nIndex, BOOL bTestEnable ) +{ + pParent = ImplGetTopParentOfTabHierarchy( pParent ); + + nIndex = 0; + Window* pWindow = ImplGetSubChildWindow( pParent, n, nIndex ); + if ( bTestEnable ) + { + USHORT n2 = nIndex; + while ( pWindow && (!pWindow->IsEnabled() || !pWindow->IsInputEnabled()) ) + { + n2 = nIndex+1; + nIndex = 0; + pWindow = ImplGetSubChildWindow( pParent, n2, nIndex ); + if ( nIndex < n2 ) + break; + } + + if ( (nIndex < n2) && n ) + { + do + { + n--; + nIndex = 0; + pWindow = ImplGetSubChildWindow( pParent, n, nIndex ); + } + while ( pWindow && n && (!pWindow->IsEnabled() || !pWindow->IsInputEnabled()) ); + } + } + return pWindow; +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetNextWindow( Window* pParent, USHORT n, USHORT& nIndex, BOOL bTestEnable ) +{ + Window* pWindow = ImplGetChildWindow( pParent, n+1, nIndex, bTestEnable ); + if ( n == nIndex ) + { + n = 0; + pWindow = ImplGetChildWindow( pParent, n, nIndex, bTestEnable ); + } + return pWindow; +} + +// ----------------------------------------------------------------------- + +Window* Window::ImplGetDlgWindow( USHORT nIndex, USHORT nType, + USHORT nFormStart, USHORT nFormEnd, + USHORT* pIndex ) +{ + DBG_ASSERT( (nIndex >= nFormStart) && (nIndex <= nFormEnd), + "Window::ImplGetDlgWindow() - nIndex not in Form" ); + + Window* pWindow = NULL; + USHORT i; + USHORT nTemp; + USHORT nStartIndex; + + if ( nType == DLGWINDOW_PREV ) + { + i = nIndex; + do + { + if ( i > nFormStart ) + i--; + else + i = nFormEnd; + pWindow = ImplGetChildWindow( this, i, nTemp, TRUE ); + if ( !pWindow ) + break; + if ( (i == nTemp) && (pWindow->GetStyle() & WB_TABSTOP) ) + break; + } + while ( i != nIndex ); + } + else + { + i = nIndex; + pWindow = ImplGetChildWindow( this, i, i, (nType == DLGWINDOW_FIRST) ); + if ( pWindow ) + { + nStartIndex = i; + + if ( nType == DLGWINDOW_NEXT ) + { + if ( i < nFormEnd ) + { + pWindow = ImplGetNextWindow( this, i, i, TRUE ); + if ( (i > nFormEnd) || (i < nFormStart) ) + pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE ); + } + else + pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE ); + } + + if ( i <= nFormEnd ) + { + // 2ten Index mitfuehren, falls alle Controls disablte + USHORT nStartIndex2 = i; + USHORT nOldIndex = i+1; + + do + { + if ( pWindow->GetStyle() & WB_TABSTOP ) + break; + if( i == nOldIndex ) // only disabled controls ? + { + i = nStartIndex2; + break; + } + nOldIndex = i; + if ( (i > nFormEnd) || (i < nFormStart) ) + pWindow = ImplGetChildWindow( this, nFormStart, i, TRUE ); + else + pWindow = ImplGetNextWindow( this, i, i, TRUE ); + } + while ( (i != nStartIndex) && (i != nStartIndex2) ); + + if ( (i == nStartIndex2) && + (!(pWindow->GetStyle() & WB_TABSTOP) || !pWindow->IsEnabled()) ) + i = nStartIndex; + } + } + + if ( nType == DLGWINDOW_FIRST ) + { + if ( pWindow ) + { + if ( pWindow->GetType() == WINDOW_TABCONTROL ) + { + Window* pNextWindow = ImplGetDlgWindow( i, DLGWINDOW_NEXT ); + if ( pNextWindow ) + { + if ( pWindow->IsChild( pNextWindow ) ) + pWindow = pNextWindow; + } + } + + if ( !(pWindow->GetStyle() & WB_TABSTOP) ) + pWindow = NULL; + } + } + } + + if ( pIndex ) + *pIndex = i; + + return pWindow; +} + +// ----------------------------------------------------------------------- + +static Window* ImplFindDlgCtrlWindow( Window* pParent, Window* pWindow, USHORT& rIndex, + USHORT& rFormStart, USHORT& rFormEnd ) +{ + Window* pSWindow; + Window* pSecondWindow = NULL; + Window* pTempWindow = NULL; + USHORT i; + USHORT nSecond_i = 0; + USHORT nFormStart = 0; + USHORT nSecondFormStart = 0; + USHORT nFormEnd; + + // Focus-Fenster in der Child-Liste suchen + Window* pFirstChildWindow = pSWindow = ImplGetChildWindow( pParent, 0, i, FALSE ); + + if( pWindow == NULL ) + pWindow = pSWindow; + + while ( pSWindow ) + { + // the DialogControlStart mark is only accepted for the direct children + if ( !ImplHasIndirectTabParent( pSWindow ) + && pSWindow->ImplGetWindow()->IsDialogControlStart() ) + nFormStart = i; + + // SecondWindow wegen zusammengesetzten Controls wie + // ComboBoxen und Feldern + if ( pSWindow->ImplIsWindowOrChild( pWindow ) ) + { + pSecondWindow = pSWindow; + nSecond_i = i; + nSecondFormStart = nFormStart; + if ( pSWindow == pWindow ) + break; + } + + pSWindow = ImplGetNextWindow( pParent, i, i, FALSE ); + if ( !i ) + pSWindow = NULL; + } + + if ( !pSWindow ) + { + // Fenster nicht gefunden, dann koennen wir auch keine + // Steuerung uebernehmen + if ( !pSecondWindow ) + return NULL; + else + { + pSWindow = pSecondWindow; + i = nSecond_i; + nFormStart = nSecondFormStart; + } + } + + // Start-Daten setzen + rIndex = i; + rFormStart = nFormStart; + + // Formularende suchen + nFormEnd = nFormStart; + pTempWindow = pSWindow; + sal_Int32 nIteration = 0; + do + { + nFormEnd = i; + pTempWindow = ImplGetNextWindow( pParent, i, i, FALSE ); + + // the DialogControlStart mark is only accepted for the direct children + if ( !i + || ( pTempWindow && !ImplHasIndirectTabParent( pTempWindow ) + && pTempWindow->ImplGetWindow()->IsDialogControlStart() ) ) + break; + + if ( pTempWindow && pTempWindow == pFirstChildWindow ) + { + // It is possible to go through the begin of hierarchy once + // while looking for DialogControlStart mark. + // If it happens second time, it looks like an endless loop, + // that should be impossible, but just for the case... + nIteration++; + if ( nIteration >= 2 ) + { + // this is an unexpected scenario + DBG_ASSERT( FALSE, "It seems to be an endless loop!" ); + rFormStart = 0; + break; + } + } + } + while ( pTempWindow ); + rFormEnd = nFormEnd; + + return pSWindow; +} + +// ----------------------------------------------------------------------- + +static Window* ImplFindAccelWindow( Window* pParent, USHORT& rIndex, xub_Unicode cCharCode, + USHORT nFormStart, USHORT nFormEnd, BOOL bCheckEnable = TRUE ) +{ + DBG_ASSERT( (rIndex >= nFormStart) && (rIndex <= nFormEnd), + "Window::ImplFindAccelWindow() - rIndex not in Form" ); + + xub_Unicode cCompareChar; + USHORT nStart = rIndex; + USHORT i = rIndex; + int bSearch = TRUE; + Window* pWindow; + + // MT: Where can we keep the CharClass?! + static uno::Reference< i18n::XCharacterClassification > xCharClass; + if ( !xCharClass.is() ) + xCharClass = vcl::unohelper::CreateCharacterClassification(); + + const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale(); + cCharCode = xCharClass->toUpper( String(cCharCode), 0, 1, rLocale )[0]; + + if ( i < nFormEnd ) + pWindow = ImplGetNextWindow( pParent, i, i, TRUE ); + else + pWindow = ImplGetChildWindow( pParent, nFormStart, i, TRUE ); + while( bSearch && pWindow ) + { + const XubString aStr = pWindow->GetText(); + USHORT nPos = aStr.Search( '~' ); + while ( nPos != STRING_NOTFOUND ) + { + cCompareChar = aStr.GetChar( nPos+1 ); + cCompareChar = xCharClass->toUpper( String(cCompareChar), 0, 1, rLocale )[0]; + if ( cCompareChar == cCharCode ) + { + // Bei Static-Controls auf das naechste Controlm weiterschalten + if ( (pWindow->GetType() == WINDOW_FIXEDTEXT) || + (pWindow->GetType() == WINDOW_FIXEDLINE) || + (pWindow->GetType() == WINDOW_GROUPBOX) ) + pWindow = pParent->ImplGetDlgWindow( i, DLGWINDOW_NEXT ); + rIndex = i; + return pWindow; + } + nPos = aStr.Search( '~', nPos+1 ); + } + + // #i93011# it would have made sense to have this really recursive + // right from the start. However this would cause unpredictable side effects now + // so instead we have a style bit for some child windows, that want their + // children checked for accelerators + if( (pWindow->GetStyle() & WB_CHILDDLGCTRL) != 0 ) + { + USHORT nChildIndex; + USHORT nChildFormStart; + USHORT nChildFormEnd; + + // get form start and end + ::ImplFindDlgCtrlWindow( pWindow, NULL, + nChildIndex, nChildFormStart, nChildFormEnd ); + Window* pAccelWin = ImplFindAccelWindow( pWindow, nChildIndex, cCharCode, + nChildFormStart, nChildFormEnd, + bCheckEnable ); + if( pAccelWin ) + return pAccelWin; + } + + if ( i == nStart ) + break; + + if ( i < nFormEnd ) + { + pWindow = ImplGetNextWindow( pParent, i, i, bCheckEnable ); + if( ! pWindow ) + pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable ); + } + else + pWindow = ImplGetChildWindow( pParent, nFormStart, i, bCheckEnable ); + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +void Window::ImplControlFocus( USHORT nFlags ) +{ + if ( nFlags & GETFOCUS_MNEMONIC ) + { + if ( GetType() == WINDOW_RADIOBUTTON ) + { + if ( !((RadioButton*)this)->IsChecked() ) + ((RadioButton*)this)->ImplCallClick( TRUE, nFlags ); + else + ImplGrabFocus( nFlags ); + } + else + { + ImplGrabFocus( nFlags ); + if ( nFlags & GETFOCUS_UNIQUEMNEMONIC ) + { + if ( GetType() == WINDOW_CHECKBOX ) + ((CheckBox*)this)->ImplCheck(); + else if ( mpWindowImpl->mbPushButton ) + { + ((PushButton*)this)->SetPressed( TRUE ); + ((PushButton*)this)->SetPressed( FALSE ); + ((PushButton*)this)->Click(); + } + } + } + } + else + { + if ( GetType() == WINDOW_RADIOBUTTON ) + { + if ( !((RadioButton*)this)->IsChecked() ) + ((RadioButton*)this)->ImplCallClick( TRUE, nFlags ); + else + ImplGrabFocus( nFlags ); + } + else + ImplGrabFocus( nFlags ); + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplDlgCtrl( const KeyEvent& rKEvt, BOOL bKeyInput ) +{ + KeyCode aKeyCode = rKEvt.GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + Window* pSWindow; + Window* pTempWindow; + Window* pButtonWindow; + USHORT i; + USHORT iButton; + USHORT iButtonStart; + USHORT iTemp; + USHORT nIndex; + USHORT nFormStart; + USHORT nFormEnd; + USHORT nDlgCtrlFlags; + + // Ohne Focus-Window koennen wir auch keine Steuerung uebernehmen + Window* pFocusWindow = Application::GetFocusWindow(); + if ( !pFocusWindow || !ImplIsWindowOrChild( pFocusWindow ) ) + return FALSE; + + // Focus-Fenster in der Child-Liste suchen + pSWindow = ::ImplFindDlgCtrlWindow( this, pFocusWindow, + nIndex, nFormStart, nFormEnd ); + if ( !pSWindow ) + return FALSE; + i = nIndex; + + nDlgCtrlFlags = 0; + pTempWindow = pSWindow; + do + { + nDlgCtrlFlags |= pTempWindow->GetDialogControlFlags(); + if ( pTempWindow == this ) + break; + pTempWindow = pTempWindow->ImplGetParent(); + } + while ( pTempWindow ); + + pButtonWindow = NULL; + + if ( nKeyCode == KEY_RETURN ) + { + // Wir suchen zuerst nach einem DefPushButton/CancelButton + pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, TRUE ); + iButtonStart = iButton; + while ( pButtonWindow ) + { + if ( (pButtonWindow->GetStyle() & WB_DEFBUTTON) && + pButtonWindow->mpWindowImpl->mbPushButton ) + break; + + pButtonWindow = ImplGetNextWindow( this, iButton, iButton, TRUE ); + if ( (iButton <= iButtonStart) || (iButton > nFormEnd) ) + pButtonWindow = NULL; + } + + if ( bKeyInput && !pButtonWindow && (nDlgCtrlFlags & WINDOW_DLGCTRL_RETURN) ) + { + USHORT nType; + USHORT nGetFocusFlags = GETFOCUS_TAB; + USHORT nNewIndex; + USHORT iStart; + if ( aKeyCode.IsShift() ) + { + nType = DLGWINDOW_PREV; + nGetFocusFlags |= GETFOCUS_BACKWARD; + } + else + { + nType = DLGWINDOW_NEXT; + nGetFocusFlags |= GETFOCUS_FORWARD; + } + iStart = i; + pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex ); + while ( pTempWindow && (pTempWindow != pSWindow) ) + { + if ( !pTempWindow->mpWindowImpl->mbPushButton ) + { + // Around-Flag ermitteln + if ( nType == DLGWINDOW_PREV ) + { + if ( nNewIndex > iStart ) + nGetFocusFlags |= GETFOCUS_AROUND; + } + else + { + if ( nNewIndex < iStart ) + nGetFocusFlags |= GETFOCUS_AROUND; + } + pTempWindow->ImplControlFocus( nGetFocusFlags ); + return TRUE; + } + else + { + i = nNewIndex; + pTempWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex ); + } + if ( (i <= iStart) || (i > nFormEnd) ) + pTempWindow = NULL; + } + // Wenn es das gleiche Fenster ist, ein Get/LoseFocus + // simulieren, falls AROUND ausgewertet wird + if ( pTempWindow && (pTempWindow == pSWindow) ) + { + NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow ); + if ( !ImplCallPreNotify( aNEvt1 ) ) + pSWindow->LoseFocus(); + pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND; + NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow ); + if ( !ImplCallPreNotify( aNEvt2 ) ) + pSWindow->GetFocus(); + pSWindow->mpWindowImpl->mnGetFocusFlags = 0; + return TRUE; + } + } + } + else if ( nKeyCode == KEY_ESCAPE ) + { + // Wir suchen zuerst nach einem DefPushButton/CancelButton + pButtonWindow = ImplGetChildWindow( this, nFormStart, iButton, TRUE ); + iButtonStart = iButton; + while ( pButtonWindow ) + { + if ( pButtonWindow->GetType() == WINDOW_CANCELBUTTON ) + break; + + pButtonWindow = ImplGetNextWindow( this, iButton, iButton, TRUE ); + if ( (iButton <= iButtonStart) || (iButton > nFormEnd) ) + pButtonWindow = NULL; + } + + if ( bKeyInput && mpWindowImpl->mpDlgCtrlDownWindow ) + { + if ( mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow ) + { + ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE ); + mpWindowImpl->mpDlgCtrlDownWindow = NULL; + return TRUE; + } + } + } + else if ( bKeyInput ) + { + if ( nKeyCode == KEY_TAB ) + { + // keine Alt-Taste abfangen, wegen Windows + if ( !aKeyCode.IsMod2() ) + { + USHORT nType; + USHORT nGetFocusFlags = GETFOCUS_TAB; + USHORT nNewIndex; + BOOL bFormular = FALSE; + + // Bei Ctrl-Tab erstmal testen, ob zwischen Formularen + // gesprungen werden soll + if ( aKeyCode.IsMod1() ) + { + // Gruppe suchen + Window* pFormularFirstWindow = NULL; + Window* pLastFormularFirstWindow = NULL; + pTempWindow = ImplGetChildWindow( this, 0, iTemp, FALSE ); + Window* pPrevFirstFormularFirstWindow = NULL; + Window* pFirstFormularFirstWindow = pTempWindow; + while ( pTempWindow ) + { + if ( pTempWindow->ImplGetWindow()->IsDialogControlStart() ) + { + if ( iTemp != 0 ) + bFormular = TRUE; + if ( aKeyCode.IsShift() ) + { + if ( iTemp <= nIndex ) + pFormularFirstWindow = pPrevFirstFormularFirstWindow; + pPrevFirstFormularFirstWindow = pTempWindow; + } + else + { + if ( (iTemp > nIndex) && !pFormularFirstWindow ) + pFormularFirstWindow = pTempWindow; + } + pLastFormularFirstWindow = pTempWindow; + } + + pTempWindow = ImplGetNextWindow( this, iTemp, iTemp, FALSE ); + if ( !iTemp ) + pTempWindow = NULL; + } + + if ( bFormular ) + { + if ( !pFormularFirstWindow ) + { + if ( aKeyCode.IsShift() ) + pFormularFirstWindow = pLastFormularFirstWindow; + else + pFormularFirstWindow = pFirstFormularFirstWindow; + } + + USHORT nFoundFormStart = 0; + USHORT nFoundFormEnd = 0; + USHORT nTempIndex = 0; + if ( ::ImplFindDlgCtrlWindow( this, pFormularFirstWindow, nTempIndex, + nFoundFormStart, nFoundFormEnd ) ) + { + nTempIndex = nFoundFormStart; + pFormularFirstWindow = ImplGetDlgWindow( nTempIndex, DLGWINDOW_FIRST, nFoundFormStart, nFoundFormEnd ); + if ( pFormularFirstWindow ) + { + pFormularFirstWindow->ImplControlFocus(); + return TRUE; + } + } + } + } + + if ( !bFormular ) + { + // Only use Ctrl-TAB if it was allowed for the whole + // dialog or for the current control (#103667#) + if ( !aKeyCode.IsMod1() || (nDlgCtrlFlags & WINDOW_DLGCTRL_MOD1TAB) || + ( pSWindow->GetStyle() & WINDOW_DLGCTRL_MOD1TAB) ) + { + if ( aKeyCode.IsShift() ) + { + nType = DLGWINDOW_PREV; + nGetFocusFlags |= GETFOCUS_BACKWARD; + } + else + { + nType = DLGWINDOW_NEXT; + nGetFocusFlags |= GETFOCUS_FORWARD; + } + Window* pWindow = ImplGetDlgWindow( i, nType, nFormStart, nFormEnd, &nNewIndex ); + // Wenn es das gleiche Fenster ist, ein Get/LoseFocus + // simulieren, falls AROUND ausgewertet wird + if ( pWindow == pSWindow ) + { + NotifyEvent aNEvt1( EVENT_LOSEFOCUS, pSWindow ); + if ( !ImplCallPreNotify( aNEvt1 ) ) + pSWindow->LoseFocus(); + pSWindow->mpWindowImpl->mnGetFocusFlags = nGetFocusFlags | GETFOCUS_AROUND; + NotifyEvent aNEvt2( EVENT_GETFOCUS, pSWindow ); + if ( !ImplCallPreNotify( aNEvt2 ) ) + pSWindow->GetFocus(); + pSWindow->mpWindowImpl->mnGetFocusFlags = 0; + return TRUE; + } + else if ( pWindow ) + { + // Around-Flag ermitteln + if ( nType == DLGWINDOW_PREV ) + { + if ( nNewIndex > i ) + nGetFocusFlags |= GETFOCUS_AROUND; + } + else + { + if ( nNewIndex < i ) + nGetFocusFlags |= GETFOCUS_AROUND; + } + pWindow->ImplControlFocus( nGetFocusFlags ); + return TRUE; + } + } + } + } + } + else if ( (nKeyCode == KEY_LEFT) || (nKeyCode == KEY_UP) ) + { + Window* pWindow = pSWindow; + WinBits nStyle = pSWindow->GetStyle(); + if ( !(nStyle & WB_GROUP) ) + { + pWindow = pWindow->GetWindow( WINDOW_PREV ); + while ( pWindow ) + { + pWindow = pWindow->ImplGetWindow(); + + nStyle = pWindow->GetStyle(); + + if ( pWindow->IsVisible() && pWindow->IsEnabled() && pWindow->IsInputEnabled() ) + { + if ( pWindow != pSWindow ) + pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD ); + return TRUE; + } + + if ( nStyle & WB_GROUP ) + break; + + pWindow = pWindow->GetWindow( WINDOW_PREV ); + } + } + } + else if ( (nKeyCode == KEY_RIGHT) || (nKeyCode == KEY_DOWN) ) + { + Window* pWindow; + WinBits nStyle; + pWindow = pSWindow->GetWindow( WINDOW_NEXT ); + while ( pWindow ) + { + pWindow = pWindow->ImplGetWindow(); + + nStyle = pWindow->GetStyle(); + + if ( nStyle & WB_GROUP ) + break; + + if ( pWindow->IsVisible() && pWindow->IsEnabled() && pWindow->IsInputEnabled() ) + { + pWindow->ImplControlFocus( GETFOCUS_CURSOR | GETFOCUS_BACKWARD ); + return TRUE; + } + + pWindow = pWindow->GetWindow( WINDOW_NEXT ); + } + } + else + { + xub_Unicode c = rKEvt.GetCharCode(); + if ( c ) + { + pSWindow = ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd ); + if ( pSWindow ) + { + USHORT nGetFocusFlags = GETFOCUS_MNEMONIC; + if ( pSWindow == ::ImplFindAccelWindow( this, i, c, nFormStart, nFormEnd ) ) + nGetFocusFlags |= GETFOCUS_UNIQUEMNEMONIC; + pSWindow->ImplControlFocus( nGetFocusFlags ); + return TRUE; + } + } + } + } + + if ( pButtonWindow && pButtonWindow->IsVisible() && pButtonWindow->IsEnabled() && pButtonWindow->IsInputEnabled() ) + { + if ( bKeyInput ) + { + if ( mpWindowImpl->mpDlgCtrlDownWindow && (mpWindowImpl->mpDlgCtrlDownWindow != pButtonWindow) ) + { + ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE ); + mpWindowImpl->mpDlgCtrlDownWindow = NULL; + } + + ((PushButton*)pButtonWindow)->SetPressed( TRUE ); + mpWindowImpl->mpDlgCtrlDownWindow = pButtonWindow; + } + else if ( mpWindowImpl->mpDlgCtrlDownWindow == pButtonWindow ) + { + mpWindowImpl->mpDlgCtrlDownWindow = NULL; + ((PushButton*)pButtonWindow)->SetPressed( FALSE ); + ((PushButton*)pButtonWindow)->Click(); + } + + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +// checks if this window has dialog control +BOOL Window::ImplHasDlgCtrl() +{ + Window* pDlgCtrlParent; + Window* pDlgCtrl; + + // lookup window for dialog control + pDlgCtrl = this; + pDlgCtrlParent = ImplGetParent(); + while ( pDlgCtrlParent && + !pDlgCtrlParent->ImplIsOverlapWindow() && + ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) ) + pDlgCtrlParent = pDlgCtrlParent->ImplGetParent(); + + if ( !pDlgCtrlParent || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) ) + return FALSE; + else + return TRUE; +} + +void Window::ImplDlgCtrlNextWindow() +{ + Window* pDlgCtrlParent; + Window* pDlgCtrl; + Window* pSWindow; + USHORT nIndex; + USHORT nFormStart; + USHORT nFormEnd; + + // lookup window for dialog control + pDlgCtrl = this; + pDlgCtrlParent = ImplGetParent(); + while ( pDlgCtrlParent && + !pDlgCtrlParent->ImplIsOverlapWindow() && + ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) ) + pDlgCtrlParent = pDlgCtrlParent->ImplGetParent(); + +if ( !pDlgCtrlParent || (GetStyle() & WB_NODIALOGCONTROL) || ((pDlgCtrlParent->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) ) + return; + + // lookup window in child list + pSWindow = ::ImplFindDlgCtrlWindow( pDlgCtrlParent, pDlgCtrl, + nIndex, nFormStart, nFormEnd ); + if ( !pSWindow ) + return; + + Window* pWindow = pDlgCtrlParent->ImplGetDlgWindow( nIndex, DLGWINDOW_NEXT, nFormStart, nFormEnd ); + if ( pWindow && (pWindow != pSWindow) ) + pWindow->ImplControlFocus(); +} + +// ----------------------------------------------------------------------- + +static void ImplDlgCtrlUpdateDefButton( Window* pParent, Window* pFocusWindow, + BOOL bGetFocus ) +{ + PushButton* pOldDefButton = NULL; + PushButton* pNewDefButton = NULL; + Window* pSWindow; + USHORT i; + USHORT nFormStart; + USHORT nFormEnd; + + // Formular suchen + pSWindow = ::ImplFindDlgCtrlWindow( pParent, pFocusWindow, i, nFormStart, nFormEnd ); + if ( !pSWindow ) + { + nFormStart = 0; + nFormEnd = 0xFFFF; + } + + pSWindow = ImplGetChildWindow( pParent, nFormStart, i, FALSE ); + while ( pSWindow ) + { + if ( pSWindow->ImplIsPushButton() ) + { + PushButton* pPushButton = (PushButton*)pSWindow; + if ( pPushButton->ImplIsDefButton() ) + pOldDefButton = pPushButton; + if ( pPushButton->HasChildPathFocus() ) + pNewDefButton = pPushButton; + else if ( !pNewDefButton && (pPushButton->GetStyle() & WB_DEFBUTTON) ) + pNewDefButton = pPushButton; + } + + pSWindow = ImplGetNextWindow( pParent, i, i, FALSE ); + if ( !i || (i > nFormEnd) ) + pSWindow = NULL; + } + + if ( !bGetFocus ) + { + USHORT nDummy; + Window* pNewFocusWindow = Application::GetFocusWindow(); + if ( !pNewFocusWindow || !pParent->ImplIsWindowOrChild( pNewFocusWindow ) ) + pNewDefButton = NULL; + else if ( !::ImplFindDlgCtrlWindow( pParent, pNewFocusWindow, i, nDummy, nDummy ) || + (i < nFormStart) || (i > nFormEnd) ) + pNewDefButton = NULL; + } + + if ( pOldDefButton != pNewDefButton ) + { + if ( pOldDefButton ) + pOldDefButton->ImplSetDefButton( FALSE ); + if ( pNewDefButton ) + pNewDefButton->ImplSetDefButton( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplDlgCtrlFocusChanged( Window* pWindow, BOOL bGetFocus ) +{ + if ( mpWindowImpl->mpDlgCtrlDownWindow && !bGetFocus ) + { + ((PushButton*)mpWindowImpl->mpDlgCtrlDownWindow)->SetPressed( FALSE ); + mpWindowImpl->mpDlgCtrlDownWindow = NULL; + } + + ImplDlgCtrlUpdateDefButton( this, pWindow, bGetFocus ); +} + +// ----------------------------------------------------------------------- + +Window* Window::ImplFindDlgCtrlWindow( Window* pWindow ) +{ + USHORT nIndex; + USHORT nFormStart; + USHORT nFormEnd; + + // Focus-Fenster in der Child-Liste suchen und zurueckgeben + return ::ImplFindDlgCtrlWindow( this, pWindow, nIndex, nFormStart, nFormEnd ); +} + + +// ----------------------------------------------------------------------- + +Window* Window::GetParentLabelFor( const Window* ) const +{ + return NULL; +} + +// ----------------------------------------------------------------------- + +Window* Window::GetParentLabeledBy( const Window* ) const +{ + return NULL; +} + +// ----------------------------------------------------------------------- + +static sal_Unicode getAccel( const String& rStr ) +{ + sal_Unicode nChar = 0; + USHORT nPos = 0; + do + { + nPos = rStr.Search( '~', nPos ); + if( nPos != STRING_NOTFOUND && nPos < rStr.Len() ) + nChar = rStr.GetChar( ++nPos ); + else + nChar = 0; + } while( nChar == '~' ); + return nChar; +} + +static Window* ImplGetLabelFor( Window* pFrameWindow, WindowType nMyType, Window* pLabel, sal_Unicode nAccel ) +{ + Window* pWindow = NULL; + + if( nMyType == WINDOW_FIXEDTEXT || + nMyType == WINDOW_FIXEDLINE || + nMyType == WINDOW_GROUPBOX ) + { + // #i100833# MT 2010/02: Group box and fixed lines can also lable a fixed text. + // See tools/options/print for example. + BOOL bThisIsAGroupControl = (nMyType == WINDOW_GROUPBOX) || (nMyType == WINDOW_FIXEDLINE); + Window* pSWindow = NULL; + // get index, form start and form end + USHORT nIndex=0, nFormStart=0, nFormEnd=0; + pSWindow = ::ImplFindDlgCtrlWindow( pFrameWindow, + pLabel, + nIndex, + nFormStart, + nFormEnd ); + if( nAccel ) + { + // find the accelerated window + pWindow = ::ImplFindAccelWindow( pFrameWindow, + nIndex, + nAccel, + nFormStart, + nFormEnd, + FALSE ); + } + else + { + // find the next control; if that is a fixed text + // fixed line or group box, then return NULL + while( nIndex < nFormEnd ) + { + nIndex++; + pSWindow = ::ImplGetChildWindow( pFrameWindow, + nIndex, + nIndex, + FALSE ); + if( pSWindow && pSWindow->IsVisible() && ! (pSWindow->GetStyle() & WB_NOLABEL) ) + { + WindowType nType = pSWindow->GetType(); + if( nType != WINDOW_FIXEDTEXT && + nType != WINDOW_FIXEDLINE && + nType != WINDOW_GROUPBOX ) + { + pWindow = pSWindow; + } + else if( bThisIsAGroupControl && ( nType == WINDOW_FIXEDTEXT ) ) + { + pWindow = pSWindow; + } + break; + } + } + } + } + + return pWindow; +} + +Window* Window::GetLabelFor() const +{ + if ( mpWindowImpl->mbDisableAccessibleLabelForRelation ) + return NULL; + + Window* pWindow = NULL; + Window* pFrameWindow = ImplGetFrameWindow(); + + WinBits nFrameStyle = pFrameWindow->GetStyle(); + if( ! ( nFrameStyle & WB_DIALOGCONTROL ) + || ( nFrameStyle & WB_NODIALOGCONTROL ) + ) + return NULL; + + if ( mpWindowImpl->mpRealParent ) + pWindow = mpWindowImpl->mpRealParent->GetParentLabelFor( this ); + + if( pWindow ) + return pWindow; + + sal_Unicode nAccel = getAccel( GetText() ); + + pWindow = ImplGetLabelFor( pFrameWindow, GetType(), const_cast<Window*>(this), nAccel ); + if( ! pWindow && mpWindowImpl->mpRealParent ) + pWindow = ImplGetLabelFor( mpWindowImpl->mpRealParent, GetType(), const_cast<Window*>(this), nAccel ); + return pWindow; +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetLabeledBy( Window* pFrameWindow, WindowType nMyType, Window* pLabeled ) +{ + Window* pWindow = NULL; + if ( (nMyType != WINDOW_GROUPBOX) && (nMyType != WINDOW_FIXEDLINE) ) + { + // search for a control that labels this window + // a label is considered the last fixed text, fixed line or group box + // that comes before this control; with the exception of push buttons + // which are labeled only if the fixed text, fixed line or group box + // is directly before the control + + // get form start and form end and index of this control + USHORT nIndex, nFormStart, nFormEnd; + Window* pSWindow = ::ImplFindDlgCtrlWindow( pFrameWindow, + pLabeled, + nIndex, + nFormStart, + nFormEnd ); + if( pSWindow && nIndex != nFormStart ) + { + if( nMyType == WINDOW_PUSHBUTTON || + nMyType == WINDOW_HELPBUTTON || + nMyType == WINDOW_OKBUTTON || + nMyType == WINDOW_CANCELBUTTON ) + { + nFormStart = nIndex-1; + } + for( USHORT nSearchIndex = nIndex-1; nSearchIndex >= nFormStart; nSearchIndex-- ) + { + USHORT nFoundIndex = 0; + pSWindow = ::ImplGetChildWindow( pFrameWindow, + nSearchIndex, + nFoundIndex, + FALSE ); + if( pSWindow && pSWindow->IsVisible() && !(pSWindow->GetStyle() & WB_NOLABEL) ) + { + WindowType nType = pSWindow->GetType(); + if ( ( nType == WINDOW_FIXEDTEXT || + nType == WINDOW_FIXEDLINE || + nType == WINDOW_GROUPBOX ) ) + { + // a fixed text can't be labeld by a fixed text. + if ( ( nMyType != WINDOW_FIXEDTEXT ) || ( nType != WINDOW_FIXEDTEXT ) ) + pWindow = pSWindow; + break; + } + } + if( nFoundIndex > nSearchIndex || nSearchIndex == 0 ) + break; + } + } + } + return pWindow; +} + +Window* Window::GetLabeledBy() const +{ + if ( mpWindowImpl->mbDisableAccessibleLabeledByRelation ) + return NULL; + + Window* pWindow = NULL; + Window* pFrameWindow = ImplGetFrameWindow(); + + if ( mpWindowImpl->mpRealParent ) + { + pWindow = mpWindowImpl->mpRealParent->GetParentLabeledBy( this ); + + if( pWindow ) + return pWindow; + } + + // #i62723#, #104191# checkboxes and radiobuttons are not supposed to have labels + if( GetType() == WINDOW_CHECKBOX || GetType() == WINDOW_RADIOBUTTON ) + return NULL; + +// if( ! ( GetType() == WINDOW_FIXEDTEXT || +// GetType() == WINDOW_FIXEDLINE || +// GetType() == WINDOW_GROUPBOX ) ) + // #i100833# MT 2010/02: Group box and fixed lines can also lable a fixed text. + // See tools/options/print for example. + + pWindow = ImplGetLabeledBy( pFrameWindow, GetType(), const_cast<Window*>(this) ); + if( ! pWindow && mpWindowImpl->mpRealParent ) + pWindow = ImplGetLabeledBy( mpWindowImpl->mpRealParent, GetType(), const_cast<Window*>(this) ); + + return pWindow; +} + +// ----------------------------------------------------------------------- + +KeyEvent Window::GetActivationKey() const +{ + KeyEvent aKeyEvent; + + sal_Unicode nAccel = getAccel( GetText() ); + if( ! nAccel ) + { + Window* pWindow = GetLabeledBy(); + if( pWindow ) + nAccel = getAccel( pWindow->GetText() ); + } + if( nAccel ) + { + USHORT nCode = 0; + if( nAccel >= 'a' && nAccel <= 'z' ) + nCode = KEY_A + (nAccel-'a'); + else if( nAccel >= 'A' && nAccel <= 'Z' ) + nCode = KEY_A + (nAccel-'A'); + else if( nAccel >= '0' && nAccel <= '9' ) + nCode = KEY_0 + (nAccel-'0'); + KeyCode aKeyCode( nCode, FALSE, FALSE, TRUE, FALSE ); + aKeyEvent = KeyEvent( nAccel, aKeyCode ); + } + return aKeyEvent; +} diff --git a/vcl/source/window/dndevdis.cxx b/vcl/source/window/dndevdis.cxx new file mode 100644 index 000000000000..e4d5a8c4c0eb --- /dev/null +++ b/vcl/source/window/dndevdis.cxx @@ -0,0 +1,564 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <vcl/dndevdis.hxx> +#include <vcl/dndlcon.hxx> +#include <vcl/window.h> + +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/svdata.hxx> +using namespace ::osl; +using namespace ::vos; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +//================================================================================================== +// DNDEventDispatcher::DNDEventDispatcher +//================================================================================================== + +DNDEventDispatcher::DNDEventDispatcher( Window * pTopWindow ): + m_pTopWindow( pTopWindow ), + m_pCurrentWindow( NULL ) +{ +} + +//================================================================================================== +// DNDEventDispatcher::~DNDEventDispatcher +//================================================================================================== + +DNDEventDispatcher::~DNDEventDispatcher() +{ +} + +//================================================================================================== +// DNDEventDispatcher::drop +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::drop( const DropTargetDropEvent& dtde ) + throw(RuntimeException) +{ + MutexGuard aImplGuard( m_aMutex ); + + Point location( dtde.LocationX, dtde.LocationY ); + + // find the window that is toplevel for this coordinates + OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + // because those coordinates come from outside, they must be mirrored if RTL layout is active + if( Application::GetSettings().GetLayoutRTL() ) + m_pTopWindow->ImplMirrorFramePos( location ); + Window * pChildWindow = m_pTopWindow->ImplFindWindow( location ); + + if( NULL == pChildWindow ) + pChildWindow = m_pTopWindow; + + while( pChildWindow->ImplGetClientWindow() ) + pChildWindow = pChildWindow->ImplGetClientWindow(); + + if( pChildWindow->ImplIsAntiparallel() ) + pChildWindow->ImplReMirror( location ); + + aSolarGuard.clear(); + + // handle the case that drop is in an other vcl window than the last dragOver + if( pChildWindow != m_pCurrentWindow ) + { + // fire dragExit on listeners of previous window + fireDragExitEvent( m_pCurrentWindow ); + + fireDragEnterEvent( pChildWindow, static_cast < XDropTargetDragContext * > (this), + dtde.DropAction, location, dtde.SourceActions, m_aDataFlavorList ); + } + + sal_Int32 nListeners = 0; + + // send drop event to the child window + nListeners = fireDropEvent( pChildWindow, dtde.Context, dtde.DropAction, + location, dtde.SourceActions, dtde.Transferable ); + + // reject drop if no listeners found + if( nListeners == 0 ) { + OSL_TRACE( "rejecting drop due to missing listeners." ); + dtde.Context->rejectDrop(); + } + + // this is a drop -> no further drag overs + m_pCurrentWindow = NULL; + m_aDataFlavorList.realloc( 0 ); +} + +//================================================================================================== +// DNDEventDispatcher::dragEnter +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::dragEnter( const DropTargetDragEnterEvent& dtdee ) + throw(RuntimeException) +{ + MutexGuard aImplGuard( m_aMutex ); + Point location( dtdee.LocationX, dtdee.LocationY ); + + // find the window that is toplevel for this coordinates + OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + // because those coordinates come from outside, they must be mirrored if RTL layout is active + if( Application::GetSettings().GetLayoutRTL() ) + m_pTopWindow->ImplMirrorFramePos( location ); + Window * pChildWindow = m_pTopWindow->ImplFindWindow( location ); + + if( NULL == pChildWindow ) + pChildWindow = m_pTopWindow; + + while( pChildWindow->ImplGetClientWindow() ) + pChildWindow = pChildWindow->ImplGetClientWindow(); + + if( pChildWindow->ImplIsAntiparallel() ) + pChildWindow->ImplReMirror( location ); + + aSolarGuard.clear(); + + // assume pointer write operation to be atomic + m_pCurrentWindow = pChildWindow; + m_aDataFlavorList = dtdee.SupportedDataFlavors; + + // fire dragEnter on listeners of current window + sal_Int32 nListeners = fireDragEnterEvent( pChildWindow, dtdee.Context, dtdee.DropAction, location, + dtdee.SourceActions, dtdee.SupportedDataFlavors ); + + // reject drag if no listener found + if( nListeners == 0 ) { + OSL_TRACE( "rejecting drag enter due to missing listeners." ); + dtdee.Context->rejectDrag(); + } + +} + +//================================================================================================== +// DNDEventDispatcher::dragExit +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::dragExit( const DropTargetEvent& /*dte*/ ) + throw(RuntimeException) +{ + MutexGuard aImplGuard( m_aMutex ); + + fireDragExitEvent( m_pCurrentWindow ); + + // reset member values + m_pCurrentWindow = NULL; + m_aDataFlavorList.realloc( 0 ); +} + +//================================================================================================== +// DNDEventDispatcher::dragOver +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::dragOver( const DropTargetDragEvent& dtde ) + throw(RuntimeException) +{ + MutexGuard aImplGuard( m_aMutex ); + + Point location( dtde.LocationX, dtde.LocationY ); + sal_Int32 nListeners; + + // find the window that is toplevel for this coordinates + OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + // because those coordinates come from outside, they must be mirrored if RTL layout is active + if( Application::GetSettings().GetLayoutRTL() ) + m_pTopWindow->ImplMirrorFramePos( location ); + Window * pChildWindow = m_pTopWindow->ImplFindWindow( location ); + + if( NULL == pChildWindow ) + pChildWindow = m_pTopWindow; + + while( pChildWindow->ImplGetClientWindow() ) + pChildWindow = pChildWindow->ImplGetClientWindow(); + + if( pChildWindow->ImplIsAntiparallel() ) + pChildWindow->ImplReMirror( location ); + + aSolarGuard.clear(); + + if( pChildWindow != m_pCurrentWindow ) + { + // fire dragExit on listeners of previous window + fireDragExitEvent( m_pCurrentWindow ); + + // remember new window + m_pCurrentWindow = pChildWindow; + + // fire dragEnter on listeners of current window + nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location, + dtde.SourceActions, m_aDataFlavorList ); + } + else + { + // fire dragOver on listeners of current window + nListeners = fireDragOverEvent( pChildWindow, dtde.Context, dtde.DropAction, location, + dtde.SourceActions ); + } + + // reject drag if no listener found + if( nListeners == 0 ) + { + OSL_TRACE( "rejecting drag over due to missing listeners." ); + dtde.Context->rejectDrag(); + } +} + +//================================================================================================== +// DNDEventDispatcher::dropActionChanged +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::dropActionChanged( const DropTargetDragEvent& dtde ) + throw(RuntimeException) +{ + MutexGuard aImplGuard( m_aMutex ); + + Point location( dtde.LocationX, dtde.LocationY ); + sal_Int32 nListeners; + + // find the window that is toplevel for this coordinates + OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + // because those coordinates come from outside, they must be mirrored if RTL layout is active + if( Application::GetSettings().GetLayoutRTL() ) + m_pTopWindow->ImplMirrorFramePos( location ); + Window * pChildWindow = m_pTopWindow->ImplFindWindow( location ); + + if( NULL == pChildWindow ) + pChildWindow = m_pTopWindow; + + while( pChildWindow->ImplGetClientWindow() ) + pChildWindow = pChildWindow->ImplGetClientWindow(); + + if( pChildWindow->ImplIsAntiparallel() ) + pChildWindow->ImplReMirror( location ); + + aSolarGuard.clear(); + + if( pChildWindow != m_pCurrentWindow ) + { + // fire dragExit on listeners of previous window + fireDragExitEvent( m_pCurrentWindow ); + + // remember new window + m_pCurrentWindow = pChildWindow; + + // fire dragEnter on listeners of current window + nListeners = fireDragEnterEvent( pChildWindow, dtde.Context, dtde.DropAction, location, + dtde.SourceActions, m_aDataFlavorList ); + } + else + { + // fire dropActionChanged on listeners of current window + nListeners = fireDropActionChangedEvent( pChildWindow, dtde.Context, dtde.DropAction, location, + dtde.SourceActions ); + } + + // reject drag if no listener found + if( nListeners == 0 ) + { + OSL_TRACE( "rejecting dropActionChanged due to missing listeners." ); + dtde.Context->rejectDrag(); + } +} + + +//================================================================================================== +// DNDEventDispatcher::dragGestureRecognized +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::dragGestureRecognized( const DragGestureEvent& dge ) + throw(RuntimeException) +{ MutexGuard aImplGuard( m_aMutex ); + + Point origin( dge.DragOriginX, dge.DragOriginY ); + + // find the window that is toplevel for this coordinates + OClearableGuard aSolarGuard( Application::GetSolarMutex() ); + + // because those coordinates come from outside, they must be mirrored if RTL layout is active + if( Application::GetSettings().GetLayoutRTL() ) + m_pTopWindow->ImplMirrorFramePos( origin ); + Window * pChildWindow = m_pTopWindow->ImplFindWindow( origin ); + + if( NULL == pChildWindow ) + pChildWindow = m_pTopWindow; + + while( pChildWindow->ImplGetClientWindow() ) + pChildWindow = pChildWindow->ImplGetClientWindow(); + + if( pChildWindow->ImplIsAntiparallel() ) + pChildWindow->ImplReMirror( origin ); + + aSolarGuard.clear(); + + fireDragGestureEvent( pChildWindow, dge.DragSource, dge.Event, origin, dge.DragAction ); +} + +//================================================================================================== +// DNDEventDispatcher::disposing +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::disposing( const EventObject& ) + throw(RuntimeException) +{ +} + +//================================================================================================== +// DNDEventDispatcher::acceptDrag +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::acceptDrag( sal_Int8 /*dropAction*/ ) throw(RuntimeException) +{ +} + +//================================================================================================== +// DNDEventDispatcher::rejectDrag +//================================================================================================== + +void SAL_CALL DNDEventDispatcher::rejectDrag() throw(RuntimeException) +{ +} + +//================================================================================================== +// DNDEventDispatcher::fireDragEnterEvent +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDragEnterEvent( Window *pWindow, + const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction, + const Point& rLocation, const sal_Int8 nSourceActions, const Sequence< DataFlavor >& aFlavorList +) + throw(RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // set an UI lock + pWindow->IncrementLockCount(); + + // query DropTarget from window + Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget(); + + if( xDropTarget.is() ) + { + // retrieve relative mouse position + Point relLoc = pWindow->ImplFrameToOutput( rLocation ); + aGuard.clear(); + + n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragEnterEvent( + xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, aFlavorList ); + } + } + + return n; +} + +//================================================================================================== +// DNDEventDispatcher::fireDragOverEvent +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDragOverEvent( Window *pWindow, + const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction, + const Point& rLocation, const sal_Int8 nSourceActions +) + throw(RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // query DropTarget from window + Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget(); + + if( xDropTarget.is() ) + { + // retrieve relative mouse position + Point relLoc = pWindow->ImplFrameToOutput( rLocation ); + aGuard.clear(); + + n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragOverEvent( + xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions ); + } + } + + return n; +} + +//================================================================================================== +// DNDEventDispatcher::fireDragExitEvent +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDragExitEvent( Window *pWindow ) throw(RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // query DropTarget from window + Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget(); + + aGuard.clear(); + + if( xDropTarget.is() ) + n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDragExitEvent(); + + // release UI lock + pWindow->DecrementLockCount(); + } + + return n; +} + +//================================================================================================== +// DNDEventDispatcher::fireDropActionChangedEvent +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDropActionChangedEvent( Window *pWindow, + const Reference< XDropTargetDragContext >& xContext, const sal_Int8 nDropAction, + const Point& rLocation, const sal_Int8 nSourceActions +) + throw(RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // query DropTarget from window + Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget(); + + if( xDropTarget.is() ) + { + // retrieve relative mouse position + Point relLoc = pWindow->ImplFrameToOutput( rLocation ); + aGuard.clear(); + + n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropActionChangedEvent( + xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions ); + } + } + + return n; +} + +//================================================================================================== +// DNDEventDispatcher::fireDropEvent +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDropEvent( Window *pWindow, + const Reference< XDropTargetDropContext >& xContext, const sal_Int8 nDropAction, const Point& rLocation, + const sal_Int8 nSourceActions, const Reference< XTransferable >& xTransferable +) + throw(RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // query DropTarget from window + Reference< XDropTarget > xDropTarget = pWindow->GetDropTarget(); + + // window may be destroyed in drop event handler + ImplDelData aDelData; + pWindow->ImplAddDel( &aDelData ); + + if( xDropTarget.is() ) + { + // retrieve relative mouse position + Point relLoc = pWindow->ImplFrameToOutput( rLocation ); + aGuard.clear(); + + n = static_cast < DNDListenerContainer * > ( xDropTarget.get() )->fireDropEvent( + xContext, nDropAction, relLoc.X(), relLoc.Y(), nSourceActions, xTransferable ); + } + + if ( !aDelData.IsDelete() ) + { + pWindow->ImplRemoveDel( &aDelData ); + // release UI lock + pWindow->DecrementLockCount(); + } + + } + + return n; +} + +//================================================================================================== +// DNDEventDispatcher::fireDragGestureRecognized +//================================================================================================== + +sal_Int32 DNDEventDispatcher::fireDragGestureEvent( Window *pWindow, + const Reference< XDragSource >& xSource, const Any event, + const Point& rOrigin, const sal_Int8 nDragAction +) + throw(::com::sun::star::uno::RuntimeException) +{ + sal_Int32 n = 0; + + if( pWindow && pWindow->IsInputEnabled() && ! pWindow->IsInModalMode() ) + { + OClearableGuard aGuard( Application::GetSolarMutex() ); + + // query DropTarget from window + Reference< XDragGestureRecognizer > xDragGestureRecognizer = pWindow->GetDragGestureRecognizer(); + + if( xDragGestureRecognizer.is() ) + { + // retrieve relative mouse position + Point relLoc = pWindow->ImplFrameToOutput( rOrigin ); + aGuard.clear(); + + n = static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent( + nDragAction, relLoc.X(), relLoc.Y(), xSource, event ); + } + + // release UI lock + pWindow->DecrementLockCount(); + } + + return n; +} diff --git a/vcl/source/window/dndlcon.cxx b/vcl/source/window/dndlcon.cxx new file mode 100644 index 000000000000..07819e76f957 --- /dev/null +++ b/vcl/source/window/dndlcon.cxx @@ -0,0 +1,567 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <vcl/dndlcon.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::dnd; + +//================================================================================================== +// +//================================================================================================== + +DNDListenerContainer::DNDListenerContainer( sal_Int8 nDefaultActions ) + : WeakComponentImplHelper4< XDragGestureRecognizer, XDropTargetDragContext, XDropTargetDropContext, XDropTarget >(GetMutex()) +{ + m_bActive = sal_True; + m_nDefaultActions = nDefaultActions; +} + +//================================================================================================== +// +//================================================================================================== + +DNDListenerContainer::~DNDListenerContainer() +{ +} + +//================================================================================================== +// DNDListenerContainer::addDragGestureListener +//================================================================================================== + +void SAL_CALL DNDListenerContainer::addDragGestureListener( const Reference< XDragGestureListener >& dgl ) + throw(RuntimeException) +{ + rBHelper.addListener( getCppuType( ( const Reference< XDragGestureListener > * ) 0 ), dgl ); +} + +//================================================================================================== +// DNDListenerContainer::removeDragGestureListener +//================================================================================================== + +void SAL_CALL DNDListenerContainer::removeDragGestureListener( const Reference< XDragGestureListener >& dgl ) + throw(RuntimeException) +{ + rBHelper.removeListener( getCppuType( ( const Reference< XDragGestureListener > * ) 0 ), dgl ); +} + +//================================================================================================== +// DNDListenerContainer::resetRecognizer +//================================================================================================== + +void SAL_CALL DNDListenerContainer::resetRecognizer( ) + throw(RuntimeException) +{ +} + +//================================================================================================== +// DNDListenerContainer::addDropTargetListener +//================================================================================================== + +void SAL_CALL DNDListenerContainer::addDropTargetListener( const Reference< XDropTargetListener >& dtl ) + throw(RuntimeException) +{ + rBHelper.addListener( getCppuType( ( const Reference< XDropTargetListener > * ) 0 ), dtl ); +} + +//================================================================================================== +// DNDListenerContainer::removeDropTargetListener +//================================================================================================== + +void SAL_CALL DNDListenerContainer::removeDropTargetListener( const Reference< XDropTargetListener >& dtl ) + throw(RuntimeException) +{ + rBHelper.removeListener( getCppuType( ( const Reference< XDropTargetListener > * ) 0 ), dtl ); +} + +//================================================================================================== +// DNDListenerContainer::isActive +//================================================================================================== + +sal_Bool SAL_CALL DNDListenerContainer::isActive( ) + throw(RuntimeException) +{ + return m_bActive; +} + +//================================================================================================== +// DNDListenerContainer::setActive +//================================================================================================== + +void SAL_CALL DNDListenerContainer::setActive( sal_Bool active ) + throw(RuntimeException) +{ + m_bActive = active; +} + +//================================================================================================== +// DNDListenerContainer::getDefaultActions +//================================================================================================== + +sal_Int8 SAL_CALL DNDListenerContainer::getDefaultActions( ) + throw(RuntimeException) +{ + return m_nDefaultActions; +} + +//================================================================================================== +// DNDListenerContainer::setDefaultActions +//================================================================================================== + +void SAL_CALL DNDListenerContainer::setDefaultActions( sal_Int8 actions ) + throw(RuntimeException) +{ + m_nDefaultActions = actions; +} + +//================================================================================================== +// DNDListenerContainer::fireDropEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDropEvent( const Reference< XDropTargetDropContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions, + const Reference< XTransferable >& transferable ) +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) ); + + if( pContainer && m_bActive ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // remember context to use in own context methods + m_xDropTargetDropContext = context; + + // do not construct the event before you are sure at least one listener is registered + DropTargetDropEvent aEvent( static_cast < XDropTarget * > (this), 0, + static_cast < XDropTargetDropContext * > (this), dropAction, + locationX, locationY, sourceActions, transferable ); + + while (aIterator.hasMoreElements()) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDropTargetListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + // fire drop until the first one has accepted + if( m_xDropTargetDropContext.is() ) + xListener->drop( aEvent ); + else + { + DropTargetEvent aDTEvent( static_cast < XDropTarget * > (this), 0 ); + xListener->dragExit( aDTEvent ); + } + + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + + // if context still valid, then reject drop + if( m_xDropTargetDropContext.is() ) + { + m_xDropTargetDropContext.clear(); + + try + { + context->rejectDrop(); + } + + catch( RuntimeException exc ) + { + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::fireDragExitEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDragExitEvent() +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) ); + + if( pContainer && m_bActive ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // do not construct the event before you are sure at least one listener is registered + DropTargetEvent aEvent( static_cast < XDropTarget * > (this), 0 ); + + while (aIterator.hasMoreElements()) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDropTargetListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + xListener->dragExit( aEvent ); + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::fireDragOverEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDragOverEvent( const Reference< XDropTargetDragContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions ) +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) ); + + if( pContainer && m_bActive ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // remember context to use in own context methods + m_xDropTargetDragContext = context; + + // do not construct the event before you are sure at least one listener is registered + DropTargetDragEvent aEvent( static_cast < XDropTarget * > (this), 0, + static_cast < XDropTargetDragContext * > (this), + dropAction, locationX, locationY, sourceActions ); + + while (aIterator.hasMoreElements()) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDropTargetListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + if( m_xDropTargetDragContext.is() ) + xListener->dragOver( aEvent ); + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + + // if context still valid, then reject drag + if( m_xDropTargetDragContext.is() ) + { + m_xDropTargetDragContext.clear(); + + try + { + context->rejectDrag(); + } + + catch( RuntimeException exc ) + { + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::fireDragEnterEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDragEnterEvent( const Reference< XDropTargetDragContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions, + const Sequence< DataFlavor >& dataFlavors ) +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) ); + + if( pContainer && m_bActive ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // remember context to use in own context methods + m_xDropTargetDragContext = context; + + // do not construct the event before you are sure at least one listener is registered + DropTargetDragEnterEvent aEvent( static_cast < XDropTarget * > (this), 0, + static_cast < XDropTargetDragContext * > (this), + dropAction, locationX, locationY, sourceActions, dataFlavors ); + + while (aIterator.hasMoreElements()) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDropTargetListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + if( m_xDropTargetDragContext.is() ) + xListener->dragEnter( aEvent ); + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + + // if context still valid, then reject drag + if( m_xDropTargetDragContext.is() ) + { + m_xDropTargetDragContext.clear(); + + try + { + context->rejectDrag(); + } + + catch( RuntimeException exc ) + { + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::fireDropActionChangedEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDropActionChangedEvent( const Reference< XDropTargetDragContext >& context, + sal_Int8 dropAction, sal_Int32 locationX, sal_Int32 locationY, sal_Int8 sourceActions ) +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDropTargetListener > * ) 0) ); + + if( pContainer && m_bActive ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // remember context to use in own context methods + m_xDropTargetDragContext = context; + + // do not construct the event before you are sure at least one listener is registered + DropTargetDragEvent aEvent( static_cast < XDropTarget * > (this), 0, + static_cast < XDropTargetDragContext * > (this), + dropAction, locationX, locationY, sourceActions ); + + while (aIterator.hasMoreElements()) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDropTargetListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + if( m_xDropTargetDragContext.is() ) + xListener->dropActionChanged( aEvent ); + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + + // if context still valid, then reject drag + if( m_xDropTargetDragContext.is() ) + { + m_xDropTargetDragContext.clear(); + + try + { + context->rejectDrag(); + } + + catch( RuntimeException exc ) + { + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::fireDragGestureEvent +//================================================================================================== + +sal_uInt32 DNDListenerContainer::fireDragGestureEvent( sal_Int8 dragAction, sal_Int32 dragOriginX, + sal_Int32 dragOriginY, const Reference< XDragSource >& dragSource, const Any& triggerEvent ) +{ + sal_uInt32 nRet = 0; + + // fire DropTargetDropEvent on all XDropTargetListeners + OInterfaceContainerHelper *pContainer = rBHelper.getContainer( getCppuType( ( Reference < XDragGestureListener > * ) 0) ); + + if( pContainer ) + { + OInterfaceIteratorHelper aIterator( *pContainer ); + + // do not construct the event before you are sure at least one listener is registered + DragGestureEvent aEvent( static_cast < XDragGestureRecognizer * > (this), dragAction, + dragOriginX, dragOriginY, dragSource, triggerEvent ); + + while( aIterator.hasMoreElements() ) + { + // FIXME: this can be simplified as soon as the Iterator has a remove method + Reference< XInterface > xElement( aIterator.next() ); + + try + { + // this may result in a runtime exception + Reference < XDragGestureListener > xListener( xElement, UNO_QUERY ); + + if( xListener.is() ) + { + xListener->dragGestureRecognized( aEvent ); + nRet++; + } + } + + catch( RuntimeException exc ) + { + pContainer->removeInterface( xElement ); + } + } + } + + return nRet; +} + +//================================================================================================== +// DNDListenerContainer::acceptDrag +//================================================================================================== + +void SAL_CALL DNDListenerContainer::acceptDrag( sal_Int8 dragOperation ) throw (RuntimeException) +{ + if( m_xDropTargetDragContext.is() ) + { + m_xDropTargetDragContext->acceptDrag( dragOperation ); + m_xDropTargetDragContext.clear(); + } +} + +//================================================================================================== +// DNDListenerContainer::rejectDrag +//================================================================================================== + +void SAL_CALL DNDListenerContainer::rejectDrag( ) throw (RuntimeException) +{ + // nothing to do here +} + +//================================================================================================== +// DNDListenerContainer::acceptDrop +//================================================================================================== + +void SAL_CALL DNDListenerContainer::acceptDrop( sal_Int8 dropOperation ) throw (RuntimeException) +{ + if( m_xDropTargetDropContext.is() ) + m_xDropTargetDropContext->acceptDrop( dropOperation ); +} + +//================================================================================================== +// DNDListenerContainer::rejectDrop +//================================================================================================== + +void SAL_CALL DNDListenerContainer::rejectDrop( ) throw (RuntimeException) +{ + // nothing to do here +} + +//================================================================================================== +// DNDListenerContainer::dropComplete +//================================================================================================== + +void SAL_CALL DNDListenerContainer::dropComplete( sal_Bool success ) throw (RuntimeException) +{ + if( m_xDropTargetDropContext.is() ) + { + m_xDropTargetDropContext->dropComplete( success ); + m_xDropTargetDropContext.clear(); + } +} diff --git a/vcl/source/window/dockingarea.cxx b/vcl/source/window/dockingarea.cxx new file mode 100644 index 000000000000..9ea407e52ee3 --- /dev/null +++ b/vcl/source/window/dockingarea.cxx @@ -0,0 +1,246 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/debug.hxx> +#include <vcl/dockingarea.hxx> +#include <vcl/syswin.hxx> +#include <vcl/menu.hxx> +#include <vcl/svdata.hxx> + +#include <map> + +// ======================================================================= + +class DockingAreaWindow::ImplData +{ +public: + ImplData(); + ~ImplData(); + + WindowAlign meAlign; +}; + +DockingAreaWindow::ImplData::ImplData() +{ + meAlign = WINDOWALIGN_TOP; +} + +DockingAreaWindow::ImplData::~ImplData() +{ +} + +// ======================================================================= + +static void ImplInitBackground( DockingAreaWindow* pThis ) +{ + if( !pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) ) + { + Wallpaper aWallpaper; + aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT ); + pThis->SetBackground( aWallpaper ); + } + else + pThis->SetBackground( Wallpaper( pThis->GetSettings().GetStyleSettings().GetFaceColor() ) ); +} + +DockingAreaWindow::DockingAreaWindow( Window* pParent ) : + Window( WINDOW_DOCKINGAREA ) +{ + ImplInit( pParent, WB_CLIPCHILDREN|WB_3DLOOK, NULL ); + + mpImplData = new ImplData; + ImplInitBackground( this ); +} + +DockingAreaWindow::~DockingAreaWindow() +{ + delete mpImplData; +} + +// ----------------------------------------------------------------------- + +void DockingAreaWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitBackground( this ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplInvalidateMenubar( DockingAreaWindow* pThis ) +{ + // due to a possible comon gradient covering menubar and top dockingarea + // the menubar must be repainted if the top dockingarea changes size or visibility + if( ImplGetSVData()->maNWFData.mbMenuBarDockingAreaCommonBG && + (pThis->GetAlign() == WINDOWALIGN_TOP) + && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) + && pThis->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + SystemWindow *pSysWin = pThis->GetSystemWindow(); + if( pSysWin && pSysWin->GetMenuBar() ) + { + Window *pMenubarWin = pSysWin->GetMenuBar()->GetWindow(); + if( pMenubarWin ) + pMenubarWin->Invalidate(); + } + } +} + +void DockingAreaWindow::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_VISIBLE ) + ImplInvalidateMenubar( this ); +} + +// ----------------------------------------------------------------------- + +BOOL DockingAreaWindow::IsHorizontal() const +{ + return ( mpImplData->meAlign == WINDOWALIGN_TOP || mpImplData->meAlign == WINDOWALIGN_BOTTOM ); +} + +void DockingAreaWindow::SetAlign( WindowAlign eNewAlign ) +{ + if( eNewAlign != mpImplData->meAlign ) + { + mpImplData->meAlign = eNewAlign; + Invalidate(); + } +} + +WindowAlign DockingAreaWindow::GetAlign() const +{ + return mpImplData->meAlign; +} + +// ----------------------------------------------------------------------- + +void DockingAreaWindow::Paint( const Rectangle& ) +{ + EnableNativeWidget( TRUE ); // only required because the toolkit curently switches this flag off + if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) ) + { + ToolbarValue aControlValue; + + if( GetAlign() == WINDOWALIGN_TOP && ImplGetSVData()->maNWFData.mbMenuBarDockingAreaCommonBG ) + { + // give NWF a hint that this dockingarea is adjacent to the menubar + // useful for special gradient effects that should cover both windows + aControlValue.mbIsTopDockingArea = TRUE; + } + ControlState nState = CTRL_STATE_ENABLED; + + if( !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB ) + { + // draw a single toolbar background covering the whole docking area + Point tmp; + Rectangle aCtrlRegion( tmp, GetOutputSizePixel() ); + + DrawNativeControl( CTRL_TOOLBAR, IsHorizontal() ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT, + aCtrlRegion, nState, aControlValue, rtl::OUString() ); + + // each toolbar gets a thin border to better recognize its borders on the homogeneous docking area + USHORT nChildren = GetChildCount(); + for( USHORT n = 0; n < nChildren; n++ ) + { + Window* pChild = GetChild( n ); + if ( pChild->IsVisible() ) + { + Point aPos = pChild->GetPosPixel(); + Size aSize = pChild->GetSizePixel(); + Rectangle aRect( aPos, aSize ); + + SetLineColor( GetSettings().GetStyleSettings().GetLightColor() ); + DrawLine( aRect.TopLeft(), aRect.TopRight() ); + DrawLine( aRect.TopLeft(), aRect.BottomLeft() ); + + SetLineColor( GetSettings().GetStyleSettings().GetSeparatorColor() ); + DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); + DrawLine( aRect.TopRight(), aRect.BottomRight() ); + } + } + } + else + { + // create map to find toolbar lines + Size aOutSz = GetOutputSizePixel(); + std::map< int, int > ranges; + USHORT nChildren = GetChildCount(); + for( USHORT n = 0; n < nChildren; n++ ) + { + Window* pChild = GetChild( n ); + Point aPos = pChild->GetPosPixel(); + Size aSize = pChild->GetSizePixel(); + if( IsHorizontal() ) + ranges[ aPos.Y() ] = aSize.Height(); + else + ranges[ aPos.X() ] = aSize.Width(); + } + + + // draw multiple toolbar backgrounds, i.e., one for each toolbar line + for( std::map<int,int>::const_iterator it = ranges.begin(); it != ranges.end(); ++it ) + { + Rectangle aTBRect; + if( IsHorizontal() ) + { + aTBRect.Left() = 0; + aTBRect.Right() = aOutSz.Width() - 1; + aTBRect.Top() = it->first; + aTBRect.Bottom() = it->first + it->second - 1; + } + else + { + aTBRect.Left() = it->first; + aTBRect.Right() = it->first + it->second - 1; + aTBRect.Top() = 0; + aTBRect.Bottom() = aOutSz.Height() - 1; + } + DrawNativeControl( CTRL_TOOLBAR, IsHorizontal() ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT, + aTBRect, nState, aControlValue, rtl::OUString() ); + } + } + } +} + +void DockingAreaWindow::Resize() +{ + ImplInvalidateMenubar( this ); + if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + diff --git a/vcl/source/window/dockmgr.cxx b/vcl/source/window/dockmgr.cxx new file mode 100644 index 000000000000..e67c2d9ecfd5 --- /dev/null +++ b/vcl/source/window/dockmgr.cxx @@ -0,0 +1,1689 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <tools/time.hxx> +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/event.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/svapp.hxx> +#include <vcl/svdata.hxx> +#include <vcl/timer.hxx> +#include <vcl/lineinfo.hxx> +#include <vcl/window.h> +#include <vcl/unowrap.hxx> +#include <vcl/salframe.hxx> + + +// ======================================================================= + +#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_PINABLE | WB_ROLLABLE ) + +// ======================================================================= + + +// ======================================================================= + +class ImplDockFloatWin2 : public FloatingWindow +{ +private: + ImplDockingWindowWrapper* mpDockWin; + ULONG mnLastTicks; + Timer maDockTimer; + Timer maEndDockTimer; + Point maDockPos; + Rectangle maDockRect; + BOOL mbInMove; + ULONG mnLastUserEvent; + + DECL_LINK( DockingHdl, ImplDockFloatWin2* ); + DECL_LINK( DockTimerHdl, ImplDockFloatWin2* ); + DECL_LINK( EndDockTimerHdl, ImplDockFloatWin2* ); +public: + ImplDockFloatWin2( Window* pParent, WinBits nWinBits, + ImplDockingWindowWrapper* pDockingWin ); + ~ImplDockFloatWin2(); + + virtual void Move(); + virtual void Resize(); + virtual void TitleButtonClick( USHORT nButton ); + virtual void Pin(); + virtual void Roll(); + virtual void PopupModeEnd(); + virtual void Resizing( Size& rSize ); + virtual BOOL Close(); + using Window::SetPosSizePixel; + virtual void SetPosSizePixel( long nX, long nY, + long nWidth, long nHeight, + USHORT nFlags = WINDOW_POSSIZE_ALL ); + + ULONG GetLastTicks() const { return mnLastTicks; } +}; + +// ======================================================================= + +ImplDockFloatWin2::ImplDockFloatWin2( Window* pParent, WinBits nWinBits, + ImplDockingWindowWrapper* pDockingWin ) : + FloatingWindow( pParent, nWinBits ), + mpDockWin( pDockingWin ), + mnLastTicks( Time::GetSystemTicks() ), + mbInMove( FALSE ), + mnLastUserEvent( 0 ) +{ + // Daten vom DockingWindow uebernehmen + if ( pDockingWin ) + { + SetSettings( pDockingWin->GetWindow()->GetSettings() ); + Enable( pDockingWin->GetWindow()->IsEnabled(), FALSE ); + EnableInput( pDockingWin->GetWindow()->IsInputEnabled(), FALSE ); + AlwaysEnableInput( pDockingWin->GetWindow()->IsAlwaysEnableInput(), FALSE ); + EnableAlwaysOnTop( pDockingWin->GetWindow()->IsAlwaysOnTopEnabled() ); + SetActivateMode( pDockingWin->GetWindow()->GetActivateMode() ); + } + + SetBackground( GetSettings().GetStyleSettings().GetFaceColor() ); + + maDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin2, DockTimerHdl ) ); + maDockTimer.SetTimeout( 50 ); + maEndDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin2, EndDockTimerHdl ) ); + maEndDockTimer.SetTimeout( 50 ); +} + +// ----------------------------------------------------------------------- + +ImplDockFloatWin2::~ImplDockFloatWin2() +{ + if( mnLastUserEvent ) + Application::RemoveUserEvent( mnLastUserEvent ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ImplDockFloatWin2, DockTimerHdl, ImplDockFloatWin2*, EMPTYARG ) +{ + DBG_ASSERT( mpDockWin->IsFloatingMode(), "docktimer called but not floating" ); + + maDockTimer.Stop(); + PointerState aState = GetPointerState(); + + if( aState.mnState & KEY_MOD1 ) + { + // i43499 CTRL disables docking now + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) + maDockTimer.Start(); + } + else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) ) + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, FALSE ); + } + else + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW ); + maDockTimer.Start(); + } + + return 0; +} + +IMPL_LINK( ImplDockFloatWin2, EndDockTimerHdl, ImplDockFloatWin2*, EMPTYARG ) +{ + DBG_ASSERT( mpDockWin->IsFloatingMode(), "enddocktimer called but not floating" ); + + maEndDockTimer.Stop(); + PointerState aState = GetPointerState(); + if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) ) + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, TRUE ); + } + else + { + maEndDockTimer.Start(); + } + + return 0; +} + + +IMPL_LINK( ImplDockFloatWin2, DockingHdl, ImplDockFloatWin2*, EMPTYARG ) +{ + // called during move of a floating window + mnLastUserEvent = 0; + + Window *pDockingArea = mpDockWin->GetWindow()->GetParent(); + PointerState aState = pDockingArea->GetPointerState(); + + BOOL bRealMove = TRUE; + if( GetStyle() & WB_OWNERDRAWDECORATION ) + { + // for windows with ownerdraw decoration + // we allow docking only when the window was moved + // by dragging its caption + // and ignore move request due to resizing + Window *pBorder = GetWindow( WINDOW_BORDER ); + if( pBorder != this ) + { + Point aPt; + Rectangle aBorderRect( aPt, pBorder->GetSizePixel() ); + sal_Int32 nLeft, nTop, nRight, nBottom; + GetBorder( nLeft, nTop, nRight, nBottom ); + // limit borderrect to the caption part only and without the resizing borders + aBorderRect.nBottom = aBorderRect.nTop + nTop; + aBorderRect.nLeft += nLeft; + aBorderRect.nRight -= nRight; + + PointerState aBorderState = pBorder->GetPointerState(); + if( aBorderRect.IsInside( aBorderState.maPos ) ) + bRealMove = TRUE; + else + bRealMove = FALSE; + } + } + + if( mpDockWin->IsDockable() && + mpDockWin->GetWindow()->IsVisible() && + (Time::GetSystemTicks() - mnLastTicks > 500) && + ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) && + !(aState.mnState & KEY_MOD1) && // i43499 CTRL disables docking now + bRealMove ) + { + maDockPos = Point( pDockingArea->OutputToScreenPixel( pDockingArea->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) ) ); + maDockRect = Rectangle( maDockPos, mpDockWin->GetSizePixel() ); + + // mouse pos in screen pixels + Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos ); + + if( ! mpDockWin->IsDocking() ) + mpDockWin->StartDocking( aMousePos, maDockRect ); + + BOOL bFloatMode = mpDockWin->Docking( aMousePos, maDockRect ); + + if( ! bFloatMode ) + { + // indicates that the window could be docked at maDockRect + maDockRect.SetPos( mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ScreenToOutputPixel( + maDockRect.TopLeft() ) ); + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW ); + maEndDockTimer.Stop(); + DockTimerHdl( this ); + } + else + { + mpDockWin->GetWindow()->GetParent()->ImplGetFrameWindow()->HideTracking(); + maDockTimer.Stop(); + EndDockTimerHdl( this ); + } + } + mbInMove = FALSE; + return 0; +} +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::Move() +{ + if( mbInMove ) + return; + + mbInMove = TRUE; + FloatingWindow::Move(); + mpDockWin->GetWindow()->Move(); + + /* + * note: the window should only dock if KEY_MOD1 is pressed + * and the user releases all mouse buttons. The real problem here + * is that we don't get mouse events (at least not on X) + * if the mouse is on the decoration. So we have to start an + * awkward timer based process that polls the modifier/buttons + * to see whether they are in the right condition shortly after the + * last Move message. + */ + if( ! mnLastUserEvent ) + mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin2, DockingHdl ) ); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::Resize() +{ + // forwarding of resize only required if we have no borderwindow ( GetWindow() then returns 'this' ) + if( GetWindow( WINDOW_BORDER ) == this ) + { + FloatingWindow::Resize(); + Size aSize( GetSizePixel() ); + mpDockWin->GetWindow()->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_POSSIZE ); // is this needed ??? + } +} + +void ImplDockFloatWin2::SetPosSizePixel( long nX, long nY, + long nWidth, long nHeight, + USHORT nFlags ) +{ + FloatingWindow::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +// ----------------------------------------------------------------------- + + +void ImplDockFloatWin2::TitleButtonClick( USHORT nButton ) +{ + FloatingWindow::TitleButtonClick( nButton ); + mpDockWin->TitleButtonClick( nButton ); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::Pin() +{ + FloatingWindow::Pin(); + mpDockWin->Pin(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::Roll() +{ + FloatingWindow::Roll(); + mpDockWin->Roll(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::PopupModeEnd() +{ + FloatingWindow::PopupModeEnd(); + mpDockWin->PopupModeEnd(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin2::Resizing( Size& rSize ) +{ + FloatingWindow::Resizing( rSize ); + mpDockWin->Resizing( rSize ); +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockFloatWin2::Close() +{ + return mpDockWin->Close(); +} + +// ======================================================================= + +DockingManager::DockingManager() +{ +} + +DockingManager::~DockingManager() +{ + ::std::vector< ImplDockingWindowWrapper* >::iterator p; + p = mDockingWindows.begin(); + for(; p != mDockingWindows.end(); ++p ) + { + delete (*p); + } + mDockingWindows.clear(); +} + +ImplDockingWindowWrapper* DockingManager::GetDockingWindowWrapper( const Window *pWindow ) +{ + ::std::vector< ImplDockingWindowWrapper* >::iterator p; + p = mDockingWindows.begin(); + while( p != mDockingWindows.end() ) + { + if( (*p)->mpDockingWindow == pWindow ) + return (*p); + else + p++; + } + return NULL; +} + +BOOL DockingManager::IsDockable( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + + /* + if( pWindow->HasDockingHandler() ) + return TRUE; + */ + return (pWrapper != NULL); +} + +BOOL DockingManager::IsFloating( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + return pWrapper->IsFloatingMode(); + else + return FALSE; +} + +BOOL DockingManager::IsLocked( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper && pWrapper->IsLocked() ) + return TRUE; + else + return FALSE; +} + +void DockingManager::Lock( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->Lock(); +} + +void DockingManager::Unlock( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->Unlock(); +} + +void DockingManager::SetFloatingMode( const Window *pWindow, BOOL bFloating ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->SetFloatingMode( bFloating ); +} + +void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const Window *pWindow, ULONG nFlags ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->StartPopupMode( pParentToolBox, nFlags ); +} + +void DockingManager::StartPopupMode( ToolBox *pParentToolBox, const Window *pWindow ) +{ + StartPopupMode( pParentToolBox, pWindow, FLOATWIN_POPUPMODE_ALLOWTEAROFF | + FLOATWIN_POPUPMODE_NOFOCUSCLOSE | + FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE | + FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE ); +} + +BOOL DockingManager::IsInPopupMode( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper && pWrapper->IsInPopupMode() ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void DockingManager::EndPopupMode( const Window *pWin ) +{ + ImplDockingWindowWrapper *pWrapper = GetDockingWindowWrapper( pWin ); + if( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() ) + pWrapper->GetFloatingWindow()->EndPopupMode(); +} + +// ----------------------------------------------------------------------- + +void DockingManager::AddWindow( const Window *pWindow ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + return; + else + pWrapper = new ImplDockingWindowWrapper( pWindow ); + + mDockingWindows.push_back( pWrapper ); +} + +void DockingManager::RemoveWindow( const Window *pWindow ) +{ + ::std::vector< ImplDockingWindowWrapper* >::iterator p; + p = mDockingWindows.begin(); + while( p != mDockingWindows.end() ) + { + if( (*p)->mpDockingWindow == pWindow ) + { + delete (*p); + mDockingWindows.erase( p ); + break; + } + else + p++; + } +} + +void DockingManager::SetPosSizePixel( Window *pWindow, long nX, long nY, + long nWidth, long nHeight, + USHORT nFlags ) +{ + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + pWrapper->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +Rectangle DockingManager::GetPosSizePixel( const Window *pWindow ) +{ + Rectangle aRect; + ImplDockingWindowWrapper* pWrapper = GetDockingWindowWrapper( pWindow ); + if( pWrapper ) + aRect = Rectangle( pWrapper->GetPosPixel(), pWrapper->GetSizePixel() ); + + return aRect; +} + +// ======================================================================= +// special floating window for popup mode +// main purpose: provides tear-off area for undocking +// ======================================================================= + +// if TEAROFF_DASHED defined a single dashed line is used +// otherwise multiple smaller lines will be painted +//#define TEAROFF_DASHED + +// size of the drag area +#ifdef TEAROFF_DASHED +#define POPUP_DRAGBORDER 2 +#define POPUP_DRAGGRIP 5 +#else +#define POPUP_DRAGBORDER 3 +#define POPUP_DRAGGRIP 5 +#endif +#define POPUP_DRAGHEIGHT (POPUP_DRAGGRIP+POPUP_DRAGBORDER+POPUP_DRAGBORDER) +#define POPUP_DRAGWIDTH 20 + +class ImplPopupFloatWin : public FloatingWindow +{ +private: + ImplDockingWindowWrapper* mpDockingWin; + BOOL mbHighlight; + BOOL mbMoving; + bool mbTrackingEnabled; + Point maDelta; + Point maTearOffPosition; + bool mbGripAtBottom; + bool mbHasGrip; + void ImplSetBorder(); + +public: + ImplPopupFloatWin( Window* pParent, ImplDockingWindowWrapper* pDockingWin, bool bHasGrip ); + ~ImplPopupFloatWin(); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + virtual void Paint( const Rectangle& rRect ); + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); + virtual void Tracking( const TrackingEvent& rTEvt ); + virtual void Resize(); + virtual Window* GetPreferredKeyInputWindow(); + + Rectangle GetDragRect() const; + Point GetToolboxPosition() const; + Point GetTearOffPosition() const; + void DrawGrip(); + void DrawBorder(); + + bool hasGrip() const { return mbHasGrip; } +}; + +ImplPopupFloatWin::ImplPopupFloatWin( Window* pParent, ImplDockingWindowWrapper* pDockingWin, bool bHasGrip ) : + FloatingWindow( pParent, WB_NOBORDER | WB_SYSTEMWINDOW | WB_NOSHADOW) +{ + mpWindowImpl->mbToolbarFloatingWindow = TRUE; // indicate window type, required for accessibility + // which should not see this window as a toplevel window + mpDockingWin = pDockingWin; + mbHighlight = FALSE; + mbMoving = FALSE; + mbTrackingEnabled = FALSE; + mbGripAtBottom = TRUE; + mbHasGrip = bHasGrip; + + ImplSetBorder(); +} + +ImplPopupFloatWin::~ImplPopupFloatWin() +{ + mpDockingWin = NULL; +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > ImplPopupFloatWin::CreateAccessible() +{ + // switch off direct accessibilty support for this window + + // this is to avoid appearance of this window as standalone window in the accessibility hierarchy + // as this window is only used as a helper for subtoolbars that are not teared-off, the parent toolbar + // has to provide accessibility support (as implemented in the toolkit) + // so the contained toolbar should appear as child of the correponsing toolbar item of the parent toolbar + return ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >(); +} + +Window* ImplPopupFloatWin::GetPreferredKeyInputWindow() +{ + if( mpWindowImpl->mpClientWindow ) + return mpWindowImpl->mpClientWindow; + else + return FloatingWindow::GetPreferredKeyInputWindow(); +} + + +void ImplPopupFloatWin::ImplSetBorder() +{ + // although we have no border in the sense of a borderwindow + // we're using a special border for the grip + // by setting those members the method SetOutputSizePixel() can + // be used to set the proper window size + mpWindowImpl->mnTopBorder = 1; + if( hasGrip() ) + mpWindowImpl->mnTopBorder += POPUP_DRAGHEIGHT+2; + mpWindowImpl->mnBottomBorder = 1; + mpWindowImpl->mnLeftBorder = 1; + mpWindowImpl->mnRightBorder = 1; +} + +void ImplPopupFloatWin::Resize() +{ + // the borderview overwrites the border during resize so restore it + ImplSetBorder(); +} + +Rectangle ImplPopupFloatWin::GetDragRect() const +{ + Rectangle aRect; + if( hasGrip() ) + { + aRect = Rectangle( 1,1, GetOutputSizePixel().Width()-1, 2+POPUP_DRAGHEIGHT ); + if( mbGripAtBottom ) + { + int height = GetOutputSizePixel().Height(); + aRect.Top() = height - 3 - POPUP_DRAGHEIGHT; + aRect.Bottom() = aRect.Top() + 1 + POPUP_DRAGHEIGHT; + } + } + return aRect; +} + +Point ImplPopupFloatWin::GetToolboxPosition() const +{ + // return inner position where a toolbox could be placed + Point aPt( 1, 1 + ((mbGripAtBottom || !hasGrip()) ? 0 : GetDragRect().getHeight()) ); // grip + border + + return aPt; +} + +Point ImplPopupFloatWin::GetTearOffPosition() const +{ + Point aPt( maTearOffPosition ); + //aPt += GetToolboxPosition(); // remove 'decoration' + return aPt; +} + +void ImplPopupFloatWin::DrawBorder() +{ + SetFillColor(); + Point aPt; + Rectangle aRect( aPt, GetOutputSizePixel() ); + + Region oldClipRgn( GetClipRegion( ) ); + Region aClipRgn( aRect ); + Rectangle aItemClipRect( ImplGetItemEdgeClipRect() ); + if( !aItemClipRect.IsEmpty() ) + { + aItemClipRect.SetPos( AbsoluteScreenToOutputPixel( aItemClipRect.TopLeft() ) ); + + // draw the excluded border part with the background color of a toolbox + SetClipRegion( Region( aItemClipRect ) ); + SetLineColor( GetSettings().GetStyleSettings().GetFaceColor() ); + DrawRect( aRect ); + + aClipRgn.Exclude( aItemClipRect ); + SetClipRegion( aClipRgn ); + } + SetLineColor( GetSettings().GetStyleSettings().GetShadowColor() ); + DrawRect( aRect ); + SetClipRegion( oldClipRgn ); +} + +void ImplPopupFloatWin::DrawGrip() +{ + BOOL bLinecolor = IsLineColor(); + Color aLinecolor = GetLineColor(); + BOOL bFillcolor = IsFillColor(); + Color aFillcolor = GetFillColor(); + + // draw background + Rectangle aRect( GetDragRect() ); + aRect.nTop += POPUP_DRAGBORDER; + aRect.nBottom -= POPUP_DRAGBORDER; + aRect.nLeft+=3; + aRect.nRight-=3; + + if( mbHighlight ) + { + Erase( aRect ); + DrawSelectionBackground( aRect, 2, FALSE, TRUE, FALSE ); + } + else + { + SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() ); + SetLineColor(); + DrawRect( aRect ); + } + + if( !ToolBox::AlwaysLocked() ) // no grip if toolboxes are locked + { +#ifdef TEAROFF_DASHED + // draw single dashed line + LineInfo aLineInfo( LINE_DASH ); + aLineInfo.SetDistance( 4 ); + aLineInfo.SetDashLen( 12 ); + aLineInfo.SetDashCount( 1 ); + + aRect.nLeft+=2; aRect.nRight-=2; + + aRect.nTop+=2; + aRect.nBottom = aRect.nTop; + SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() ); + DrawLine( aRect.TopLeft(), aRect.TopRight(), aLineInfo ); + + if( !mbHighlight ) + { + aRect.nTop++; aRect.nBottom++; + SetLineColor( GetSettings().GetStyleSettings().GetLightColor() ); + DrawLine( aRect.TopLeft(), aRect.TopRight(), aLineInfo ); + } + +#else + // draw several grip lines + SetFillColor( GetSettings().GetStyleSettings().GetShadowColor() ); + aRect.nTop++; + aRect.nBottom = aRect.nTop; + + int width = POPUP_DRAGWIDTH; + while( width >= aRect.getWidth() ) + width -= 4; + if( width <= 0 ) + width = aRect.getWidth(); + //aRect.nLeft = aRect.nLeft + (aRect.getWidth() - width) / 2; + aRect.nLeft = (aRect.nLeft + aRect.nRight - width) / 2; + aRect.nRight = aRect.nLeft + width; + + int i=0; + while( i< POPUP_DRAGGRIP ) + { + DrawRect( aRect ); + aRect.nTop+=2; + aRect.nBottom+=2; + i+=2; + } +#endif + } + + if( bLinecolor ) + SetLineColor( aLinecolor ); + else + SetLineColor(); + if( bFillcolor ) + SetFillColor( aFillcolor ); + else + SetFillColor(); +} + +void ImplPopupFloatWin::Paint( const Rectangle& ) +{ + Point aPt; + Rectangle aRect( aPt, GetOutputSizePixel() ); + DrawWallpaper( aRect, Wallpaper( GetSettings().GetStyleSettings().GetFaceGradientColor() ) ); + DrawBorder(); + if( hasGrip() ) + DrawGrip(); +} + +void ImplPopupFloatWin::MouseMove( const MouseEvent& rMEvt ) +{ + Point aMousePos = rMEvt.GetPosPixel(); + + if( !ToolBox::AlwaysLocked() ) // no tear off if locking is enabled + { + if( mbTrackingEnabled && rMEvt.IsLeft() && GetDragRect().IsInside( aMousePos ) ) + { + // start window move + mbMoving = TRUE; + StartTracking( STARTTRACK_NOKEYCANCEL ); + return; + } + if( !mbHighlight && GetDragRect().IsInside( aMousePos ) ) + { + mbHighlight = TRUE; + DrawGrip(); + } + if( mbHighlight && ( rMEvt.IsLeaveWindow() || !GetDragRect().IsInside( aMousePos ) ) ) + { + mbHighlight = FALSE; + DrawGrip(); + } + } +} + +void ImplPopupFloatWin::MouseButtonUp( const MouseEvent& rMEvt ) +{ + mbTrackingEnabled = false; + FloatingWindow::MouseButtonUp( rMEvt ); +} + +void ImplPopupFloatWin::MouseButtonDown( const MouseEvent& rMEvt ) +{ + Point aMousePos = rMEvt.GetPosPixel(); + if( GetDragRect().IsInside( aMousePos ) ) + { + // get mouse pos at a static window to have a fixed reference point + PointerState aState = GetParent()->GetPointerState(); + if (ImplHasMirroredGraphics() && IsRTLEnabled()) + ImplMirrorFramePos(aState.maPos); + maTearOffPosition = GetWindow( WINDOW_BORDER )->GetPosPixel(); + maDelta = aState.maPos - maTearOffPosition; + mbTrackingEnabled = true; + } + else + { + mbTrackingEnabled = false; + } +} + +void ImplPopupFloatWin::Tracking( const TrackingEvent& rTEvt ) +{ + if( mbMoving ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbMoving = FALSE; + EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF ); + } + else if ( !rTEvt.GetMouseEvent().IsSynthetic() ) + { + // move the window according to mouse pos + PointerState aState = GetParent()->GetPointerState(); + if (ImplHasMirroredGraphics() && IsRTLEnabled()) + ImplMirrorFramePos(aState.maPos); + maTearOffPosition = aState.maPos - maDelta; + GetWindow( WINDOW_BORDER )->SetPosPixel( maTearOffPosition ); + } + } +} + + +// ======================================================================= + +ImplDockingWindowWrapper::ImplDockingWindowWrapper( const Window *pWindow ) +{ + ImplInitData(); + + mpDockingWindow = (Window*) pWindow; + mpParent = pWindow->GetParent(); + mbDockable = TRUE; + mbLocked = FALSE; + mnFloatBits = WB_BORDER | WB_CLOSEABLE | WB_SIZEABLE | (pWindow->GetStyle() & DOCKWIN_FLOATSTYLES); + DockingWindow *pDockWin = dynamic_cast< DockingWindow* > ( mpDockingWindow ); + if( pDockWin ) + mnFloatBits = pDockWin->GetFloatStyle(); + + // must be enabled in Window::Notify to prevent permanent docking during mouse move + mbStartDockingEnabled = FALSE; +} + +ImplDockingWindowWrapper::~ImplDockingWindowWrapper() +{ + if ( IsFloatingMode() ) + { + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + SetFloatingMode( FALSE ); + } +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockingWindowWrapper::ImplStartDocking( const Point& rPos ) +{ + if ( !mbDockable ) + return FALSE; + + if( !mbStartDockingEnabled ) + return FALSE; + + maMouseOff = rPos; + maMouseStart = maMouseOff; + mbDocking = TRUE; + mbLastFloatMode = IsFloatingMode(); + mbStartFloat = mbLastFloatMode; + + // FloatingBorder berechnen + FloatingWindow* pWin; + if ( mpFloatWin ) + pWin = mpFloatWin; + else + pWin = new ImplDockFloatWin2( mpParent, mnFloatBits, NULL ); + pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom ); + if ( !mpFloatWin ) + delete pWin; + + Point aPos = GetWindow()->ImplOutputToFrame( Point() ); + Size aSize = GetWindow()->GetOutputSizePixel(); + mnTrackX = aPos.X(); + mnTrackY = aPos.Y(); + mnTrackWidth = aSize.Width(); + mnTrackHeight = aSize.Height(); + + if ( mbLastFloatMode ) + { + maMouseOff.X() += mnDockLeft; + maMouseOff.Y() += mnDockTop; + mnTrackX -= mnDockLeft; + mnTrackY -= mnDockTop; + mnTrackWidth += mnDockLeft+mnDockRight; + mnTrackHeight += mnDockTop+mnDockBottom; + } + + Window *pDockingArea = GetWindow()->GetParent(); + Window::PointerState aState = pDockingArea->GetPointerState(); + + // mouse pos in screen pixels + Point aMousePos = pDockingArea->OutputToScreenPixel( aState.maPos ); + Point aDockPos = Point( pDockingArea->AbsoluteScreenToOutputPixel( GetWindow()->OutputToAbsoluteScreenPixel( GetWindow()->GetPosPixel() ) ) ); + Rectangle aDockRect( aDockPos, GetWindow()->GetSizePixel() ); + StartDocking( aMousePos, aDockRect ); + + GetWindow()->ImplUpdateAll(); + GetWindow()->ImplGetFrameWindow()->ImplUpdateAll(); + + GetWindow()->StartTracking( STARTTRACK_KEYMOD ); + return TRUE; +} + +// ======================================================================= + +void ImplDockingWindowWrapper::ImplInitData() +{ + mpDockingWindow = NULL; + + //GetWindow()->mpWindowImpl->mbDockWin = TRUE; // TODO: must be eliminated + mpFloatWin = NULL; + mbDockCanceled = FALSE; + mbFloatPrevented = FALSE; + mbDocking = FALSE; + mbPined = FALSE; + mbRollUp = FALSE; + mbDockBtn = FALSE; + mbHideBtn = FALSE; + maMaxOutSize = Size( SHRT_MAX, SHRT_MAX ); +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::Tracking( const TrackingEvent& rTEvt ) +{ + // used during docking of a currently docked window + if ( mbDocking ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbDocking = FALSE; + GetWindow()->HideTracking(); + if ( rTEvt.IsTrackingCanceled() ) + { + mbDockCanceled = TRUE; + EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + mbDockCanceled = FALSE; + } + else + EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + } + // Docking only upon non-synthetic MouseEvents + else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() ) + { + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + Point aFrameMousePos = GetWindow()->ImplOutputToFrame( aMousePos ); + Size aFrameSize = GetWindow()->ImplGetFrameWindow()->GetOutputSizePixel(); + if ( aFrameMousePos.X() < 0 ) + aFrameMousePos.X() = 0; + if ( aFrameMousePos.Y() < 0 ) + aFrameMousePos.Y() = 0; + if ( aFrameMousePos.X() > aFrameSize.Width()-1 ) + aFrameMousePos.X() = aFrameSize.Width()-1; + if ( aFrameMousePos.Y() > aFrameSize.Height()-1 ) + aFrameMousePos.Y() = aFrameSize.Height()-1; + aMousePos = GetWindow()->ImplFrameToOutput( aFrameMousePos ); + aMousePos.X() -= maMouseOff.X(); + aMousePos.Y() -= maMouseOff.Y(); + Point aPos = GetWindow()->ImplOutputToFrame( aMousePos ); + Rectangle aTrackRect( aPos, Size( mnTrackWidth, mnTrackHeight ) ); + Rectangle aCompRect = aTrackRect; + aPos.X() += maMouseOff.X(); + aPos.Y() += maMouseOff.Y(); + + BOOL bFloatMode = Docking( aPos, aTrackRect ); + + mbFloatPrevented = FALSE; + if ( mbLastFloatMode != bFloatMode ) + { + if ( bFloatMode ) + { + aTrackRect.Left() -= mnDockLeft; + aTrackRect.Top() -= mnDockTop; + aTrackRect.Right() += mnDockRight; + aTrackRect.Bottom() += mnDockBottom; + } + else + { + if ( aCompRect == aTrackRect ) + { + aTrackRect.Left() += mnDockLeft; + aTrackRect.Top() += mnDockTop; + aTrackRect.Right() -= mnDockRight; + aTrackRect.Bottom() -= mnDockBottom; + } + } + mbLastFloatMode = bFloatMode; + } + + USHORT nTrackStyle; + if ( bFloatMode ) + nTrackStyle = SHOWTRACK_OBJECT; + else + nTrackStyle = SHOWTRACK_BIG; + Rectangle aShowTrackRect = aTrackRect; + aShowTrackRect.SetPos( GetWindow()->ImplFrameToOutput( aShowTrackRect.TopLeft() ) ); + //if( bFloatMode ) + GetWindow()->ShowTracking( aShowTrackRect, nTrackStyle ); + /*else + { + GetWindow()->HideTracking(); + Point aPt( GetWindow()->GetParent()->ScreenToOutputPixel( aTrackRect.TopLeft() ) ); + GetWindow()->SetPosPixel( aPt ); + }*/ + + // Maus-Offset neu berechnen, da Rechteck veraendert werden + // konnte + maMouseOff.X() = aPos.X() - aTrackRect.Left(); + maMouseOff.Y() = aPos.Y() - aTrackRect.Top(); + + mnTrackX = aTrackRect.Left(); + mnTrackY = aTrackRect.Top(); + mnTrackWidth = aTrackRect.GetWidth(); + mnTrackHeight = aTrackRect.GetHeight(); + } + } +} + + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::StartDocking( const Point& rPoint, Rectangle& rRect ) +{ + DockingData data( rPoint, rRect, IsFloatingMode() ); + + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_STARTDOCKING, &data ); + mbDocking = TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockingWindowWrapper::Docking( const Point& rPoint, Rectangle& rRect ) +{ + DockingData data( rPoint, rRect, IsFloatingMode() ); + + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_DOCKING, &data ); + rRect = data.maTrackRect; + return data.mbFloating; +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::EndDocking( const Rectangle& rRect, BOOL bFloatMode ) +{ + Rectangle aRect( rRect ); + + if ( !IsDockingCanceled() ) + { + BOOL bShow = FALSE; + if ( bFloatMode != IsFloatingMode() ) + { + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + SetFloatingMode( bFloatMode ); + bShow = TRUE; + if ( bFloatMode ) + { + // #i44800# always use outputsize - as in all other places + mpFloatWin->SetOutputSizePixel( aRect.GetSize() ); + mpFloatWin->SetPosPixel( aRect.TopLeft() ); + } + } + if ( !bFloatMode ) + { + Point aPos = aRect.TopLeft(); + aPos = GetWindow()->GetParent()->ScreenToOutputPixel( aPos ); + GetWindow()->SetPosSizePixel( aPos, aRect.GetSize() ); + } + + if ( bShow ) + GetWindow()->Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE ); + } + + EndDockingData data( aRect, IsFloatingMode(), IsDockingCanceled() ); + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_ENDDOCKING, &data ); + + mbDocking = FALSE; + + // must be enabled in Window::Notify to prevent permanent docking during mouse move + mbStartDockingEnabled = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockingWindowWrapper::PrepareToggleFloatingMode() +{ + BOOL bFloating = TRUE; + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_PREPARETOGGLEFLOATING, &bFloating ); + return bFloating; +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockingWindowWrapper::Close() +{ + // TODO: send event +/* + ImplDelData aDelData; + ImplAddDel( &aDelData ); + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE ); + if ( aDelData.IsDelete() ) + return FALSE; + ImplRemoveDel( &aDelData ); + + if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() ) + return FALSE; + + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + */ + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::ToggleFloatingMode() +{ + // notify dockingwindow/toolbox + // note: this must be done *before* notifying the + // listeners to have the toolbox in the proper state + if( GetWindow()->ImplIsDockingWindow() ) + ((DockingWindow*) GetWindow())->ToggleFloatingMode(); + + // now notify listeners + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_TOGGLEFLOATING ); + + // must be enabled in Window::Notify to prevent permanent docking during mouse move + mbStartDockingEnabled = FALSE; +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::TitleButtonClick( USHORT nType ) +{ + if( nType == TITLE_BUTTON_MENU ) + { + ToolBox *pToolBox = dynamic_cast< ToolBox* >( GetWindow() ); + if( pToolBox ) + { + pToolBox->ExecuteCustomMenu(); + } + } + if( nType == TITLE_BUTTON_DOCKING ) + { + SetFloatingMode( !IsFloatingMode() ); + } +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::Pin() +{ + // TODO: send event +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::Roll() +{ + // TODO: send event +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::PopupModeEnd() +{ + // TODO: send event +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::Resizing( Size& rSize ) +{ + // TODO: add virtual Resizing() to class Window, so we can get rid of class DockingWindow + DockingWindow *pDockingWindow = dynamic_cast< DockingWindow* >( GetWindow() ); + if( pDockingWindow ) + pDockingWindow->Resizing( rSize ); +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::ShowTitleButton( USHORT nButton, BOOL bVisible ) +{ + if ( mpFloatWin ) + mpFloatWin->ShowTitleButton( nButton, bVisible ); + else + { + if ( nButton == TITLE_BUTTON_DOCKING ) + mbDockBtn = bVisible; + else // if ( nButton == TITLE_BUTTON_HIDE ) + mbHideBtn = bVisible; + } +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockingWindowWrapper::IsTitleButtonVisible( USHORT nButton ) const +{ + if ( mpFloatWin ) + return mpFloatWin->IsTitleButtonVisible( nButton ); + else + { + if ( nButton == TITLE_BUTTON_DOCKING ) + return mbDockBtn; + else // if ( nButton == TITLE_BUTTON_HIDE ) + return mbHideBtn; + } +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::StartPopupMode( ToolBox *pParentToolBox, ULONG nFlags ) +{ + // do nothing if window is floating + if( IsFloatingMode() ) + return; + + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // prepare reparenting + Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT ); + mpOldBorderWin = GetWindow()->GetWindow( WINDOW_BORDER ); + if( mpOldBorderWin == GetWindow() ) + mpOldBorderWin = NULL; // no border window found + + // the new parent for popup mode + ImplPopupFloatWin* pWin = new ImplPopupFloatWin( mpParent, this, (nFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF) != 0 ); + + pWin->SetPopupModeEndHdl( LINK( this, ImplDockingWindowWrapper, PopupModeEnd ) ); + pWin->SetText( GetWindow()->GetText() ); + + pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() ); + + GetWindow()->mpWindowImpl->mpBorderWindow = NULL; + GetWindow()->mpWindowImpl->mnLeftBorder = 0; + GetWindow()->mpWindowImpl->mnTopBorder = 0; + GetWindow()->mpWindowImpl->mnRightBorder = 0; + GetWindow()->mpWindowImpl->mnBottomBorder = 0; + + // position toolbox below dragrect + GetWindow()->SetPosPixel( pWin->GetToolboxPosition() ); + + // reparent borderwindow and window + if ( mpOldBorderWin ) + mpOldBorderWin->SetParent( pWin ); + GetWindow()->SetParent( pWin ); + + // correct border window pointers + GetWindow()->mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = GetWindow(); + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + // set mpFloatWin not until all window positioning is done !!! + // (SetPosPixel etc. check for valid mpFloatWin pointer) + mpFloatWin = pWin; + + // if the subtoolbar was opened via keyboard make sure that key events + // will go into subtoolbar + if( pParentToolBox->IsKeyEvent() ) + nFlags |= FLOATWIN_POPUPMODE_GRABFOCUS; + + mpFloatWin->StartPopupMode( pParentToolBox, nFlags ); + GetWindow()->Show(); + + if( pParentToolBox->IsKeyEvent() ) + { + // send HOME key to subtoolbar in order to select first item + KeyEvent aEvent( 0, KeyCode( KEY_HOME ) ); + mpFloatWin->GetPreferredKeyInputWindow()->KeyInput( aEvent ); + } +} + +IMPL_LINK( ImplDockingWindowWrapper, PopupModeEnd, void*, EMPTYARG ) +{ + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // set parameter for handler before destroying floating window + ImplPopupFloatWin *pPopupFloatWin = (ImplPopupFloatWin*) mpFloatWin; + EndPopupModeData aData( pPopupFloatWin->GetTearOffPosition(), mpFloatWin->IsPopupModeTearOff() ); + + // before deleting change parent back, so we can delete the floating window alone + Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT ); + GetWindow()->mpWindowImpl->mpBorderWindow = NULL; + if ( mpOldBorderWin ) + { + GetWindow()->SetParent( mpOldBorderWin ); + ((ImplBorderWindow*)mpOldBorderWin)->GetBorder( + GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder, + GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder ); + mpOldBorderWin->Resize(); + } + GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin; + GetWindow()->SetParent( pRealParent ); + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + delete mpFloatWin; + mpFloatWin = NULL; + + // call handler - which will destroy the window and thus the wrapper as well ! + GetWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_ENDPOPUPMODE, &aData ); + + return 0; +} + + +BOOL ImplDockingWindowWrapper::IsInPopupMode() const +{ + if( GetFloatingWindow() ) + return GetFloatingWindow()->IsInPopupMode(); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetFloatingMode( BOOL bFloatMode ) +{ + // do nothing if window is docked and locked + if( !IsFloatingMode() && IsLocked() ) + return; + + if ( IsFloatingMode() != bFloatMode ) + { + if ( PrepareToggleFloatingMode() ) + { + BOOL bVisible = GetWindow()->IsVisible(); + + if ( bFloatMode ) + { + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + + maDockPos = GetWindow()->GetPosPixel(); + + Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT ); + mpOldBorderWin = GetWindow()->GetWindow( WINDOW_BORDER ); + if( mpOldBorderWin == mpDockingWindow ) + mpOldBorderWin = NULL; // no border window found + + ImplDockFloatWin2* pWin = + new ImplDockFloatWin2( + mpParent, + mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? + mnFloatBits | WB_SYSTEMWINDOW +//#ifdef __USE_OWNERDRAWDECORATION__ + | WB_OWNERDRAWDECORATION +//#endif + : mnFloatBits, + this ); + + // reduce the border width for seamless NWF painting + // (especially for the toolbar gradient on Windows XP) + /*AllSettings aSettings( pWin->GetSettings() ); + StyleSettings aStyleSettings( aSettings.GetStyleSettings() ); + aStyleSettings.SetBorderSize( 0 ); + aSettings.SetStyleSettings( aStyleSettings ); + pWin->SetSettings( aSettings );*/ + +// mpFloatWin = pWin; + + + GetWindow()->mpWindowImpl->mpBorderWindow = NULL; + GetWindow()->mpWindowImpl->mnLeftBorder = 0; + GetWindow()->mpWindowImpl->mnTopBorder = 0; + GetWindow()->mpWindowImpl->mnRightBorder = 0; + GetWindow()->mpWindowImpl->mnBottomBorder = 0; + + // Falls Parent zerstoert wird, muessen wir auch vom + // BorderWindow den Parent umsetzen + if ( mpOldBorderWin ) + mpOldBorderWin->SetParent( pWin ); + GetWindow()->SetParent( pWin ); + pWin->SetPosPixel( Point() ); + + GetWindow()->mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = mpDockingWindow; + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + pWin->SetText( GetWindow()->GetText() ); + pWin->SetOutputSizePixel( GetWindow()->GetSizePixel() ); + pWin->SetPosPixel( maFloatPos ); + // DockingDaten ans FloatingWindow weiterreichen + pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, mbDockBtn ); + pWin->ShowTitleButton( TITLE_BUTTON_HIDE, mbHideBtn ); + pWin->SetPin( mbPined ); + if ( mbRollUp ) + pWin->RollUp(); + else + pWin->RollDown(); + pWin->SetRollUpOutputSizePixel( maRollUpOutSize ); + pWin->SetMinOutputSizePixel( maMinOutSize ); + pWin->SetMaxOutputSizePixel( maMaxOutSize ); + + mpFloatWin = pWin; + + if ( bVisible ) + GetWindow()->Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE ); + + ToggleFloatingMode(); + } + else + { + GetWindow()->Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // FloatingDaten wird im FloatingWindow speichern + maFloatPos = mpFloatWin->GetPosPixel(); + mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING ); + mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE ); + mbPined = mpFloatWin->IsPined(); + mbRollUp = mpFloatWin->IsRollUp(); + maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel(); + maMinOutSize = mpFloatWin->GetMinOutputSizePixel(); + maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel(); + + Window* pRealParent = GetWindow()->GetWindow( WINDOW_PARENT ); //mpWindowImpl->mpRealParent; + GetWindow()->mpWindowImpl->mpBorderWindow = NULL; + if ( mpOldBorderWin ) + { + GetWindow()->SetParent( mpOldBorderWin ); + ((ImplBorderWindow*)mpOldBorderWin)->GetBorder( + GetWindow()->mpWindowImpl->mnLeftBorder, GetWindow()->mpWindowImpl->mnTopBorder, + GetWindow()->mpWindowImpl->mnRightBorder, GetWindow()->mpWindowImpl->mnBottomBorder ); + mpOldBorderWin->Resize(); + } + GetWindow()->mpWindowImpl->mpBorderWindow = mpOldBorderWin; + GetWindow()->SetParent( pRealParent ); + GetWindow()->mpWindowImpl->mpRealParent = pRealParent; + + delete static_cast<ImplDockFloatWin2*>(mpFloatWin); + mpFloatWin = NULL; + GetWindow()->SetPosPixel( maDockPos ); + + if ( bVisible ) + GetWindow()->Show(); + + ToggleFloatingMode(); + + } + } + } +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetFloatStyle( WinBits nStyle ) +{ + mnFloatBits = nStyle; +} + +// ----------------------------------------------------------------------- + +WinBits ImplDockingWindowWrapper::GetFloatStyle() const +{ + return mnFloatBits; +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetTabStop() +{ + GetWindow()->SetStyle( GetWindow()->GetStyle() | (WB_GROUP | WB_TABSTOP) ); +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetPosSizePixel( long nX, long nY, + long nWidth, long nHeight, + USHORT nFlags ) +{ + if ( mpFloatWin ) + mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); + else + GetWindow()->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +// ----------------------------------------------------------------------- + +Point ImplDockingWindowWrapper::GetPosPixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetPosPixel(); + else + return mpDockingWindow->GetPosPixel(); +} + +// ----------------------------------------------------------------------- + +Size ImplDockingWindowWrapper::GetSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetSizePixel(); + else + return mpDockingWindow->GetSizePixel(); +} + +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetOutputSizePixel( const Size& rNewSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetOutputSizePixel( rNewSize ); + else + GetWindow()->SetOutputSizePixel( rNewSize ); +} + +// ----------------------------------------------------------------------- + +Size ImplDockingWindowWrapper::GetOutputSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetOutputSizePixel(); + else + return mpDockingWindow->GetOutputSizePixel(); +} + +Point ImplDockingWindowWrapper::GetFloatingPos() const +{ + if ( mpFloatWin ) + { + //Rectangle aRect = mpFloatWin->GetWindow( WINDOW_CLIENT)->GetWindowExtentsRelative( mpFloatWin->GetParent() ); + WindowStateData aData; + aData.SetMask( WINDOWSTATE_MASK_POS ); + mpFloatWin->GetWindowStateData( aData ); + Point aPos( aData.GetX(), aData.GetY() ); + aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos ); + return aPos; + } + else + return maFloatPos; +} + +// ----------------------------------------------------------------------- +// old inlines from DockingWindow +// ----------------------------------------------------------------------- + +void ImplDockingWindowWrapper::SetPin( BOOL bPin ) +{ + if ( mpFloatWin ) + mpFloatWin->SetPin( bPin ); + mbPined = bPin; +} + +BOOL ImplDockingWindowWrapper::IsPined() const +{ + if ( mpFloatWin ) + return mpFloatWin->IsPined(); + return mbPined; +} + +void ImplDockingWindowWrapper::RollUp() +{ + if ( mpFloatWin ) + mpFloatWin->RollUp(); + mbRollUp = TRUE; +} + +void ImplDockingWindowWrapper::RollDown() +{ + if ( mpFloatWin ) + mpFloatWin->RollDown(); + mbRollUp = FALSE; +} + +BOOL ImplDockingWindowWrapper::IsRollUp() const +{ + if ( mpFloatWin ) + return mpFloatWin->IsRollUp(); + return mbRollUp; +} + +void ImplDockingWindowWrapper::SetRollUpOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetRollUpOutputSizePixel( rSize ); + maRollUpOutSize = rSize; +} + +Size ImplDockingWindowWrapper::GetRollUpOutputSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetRollUpOutputSizePixel(); + return maRollUpOutSize; +} + +void ImplDockingWindowWrapper::SetMinOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetMinOutputSizePixel( rSize ); + maMinOutSize = rSize; +} + +void ImplDockingWindowWrapper::SetMaxOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetMaxOutputSizePixel( rSize ); + maMaxOutSize = rSize; +} + +const Size& ImplDockingWindowWrapper::GetMinOutputSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetMinOutputSizePixel(); + return maMinOutSize; +} + +const Size& ImplDockingWindowWrapper::GetMaxOutputSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetMaxOutputSizePixel(); + return maMaxOutSize; +} + +void ImplDockingWindowWrapper::SetFloatingPos( const Point& rNewPos ) +{ + if ( mpFloatWin ) + mpFloatWin->SetPosPixel( rNewPos ); + else + maFloatPos = rNewPos; +} + +BOOL ImplDockingWindowWrapper::IsFloatingMode() const +{ + return (mpFloatWin != NULL); +} + + +void ImplDockingWindowWrapper::SetDragArea( const Rectangle& rRect ) +{ + maDragArea = rRect; +} + +Rectangle ImplDockingWindowWrapper::GetDragArea() const +{ + return maDragArea; +} + +void ImplDockingWindowWrapper::Lock() +{ + mbLocked = TRUE; + // only toolbars support locking + ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() ); + if( pToolBox ) + pToolBox->Lock( mbLocked ); +} + +void ImplDockingWindowWrapper::Unlock() +{ + mbLocked = FALSE; + // only toolbars support locking + ToolBox *pToolBox = dynamic_cast< ToolBox * >( GetWindow() ); + if( pToolBox ) + pToolBox->Lock( mbLocked ); +} + +BOOL ImplDockingWindowWrapper::IsLocked() const +{ + return mbLocked; +} diff --git a/vcl/source/window/dockwin.cxx b/vcl/source/window/dockwin.cxx new file mode 100644 index 000000000000..c8e382bad982 --- /dev/null +++ b/vcl/source/window/dockwin.cxx @@ -0,0 +1,1120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <tools/time.hxx> +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/event.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/svapp.hxx> +#include <vcl/svdata.hxx> +#include <vcl/timer.hxx> +#include <vcl/window.h> +#include <vcl/unowrap.hxx> +#include <vcl/salframe.hxx> + + + +// ======================================================================= + +#define DOCKWIN_FLOATSTYLES (WB_SIZEABLE | WB_MOVEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_PINABLE | WB_ROLLABLE ) + +// ======================================================================= + +// ----------------------------------------------------------------------- + +class DockingWindow::ImplData +{ +public: + ImplData(); + ~ImplData(); + + Window* mpParent; + Size maMaxOutSize; +}; + +DockingWindow::ImplData::ImplData() +{ + mpParent = NULL; + maMaxOutSize = Size( SHRT_MAX, SHRT_MAX ); +} + +DockingWindow::ImplData::~ImplData() +{ +} + +// ----------------------------------------------------------------------- + +class ImplDockFloatWin : public FloatingWindow +{ +private: + DockingWindow* mpDockWin; + ULONG mnLastTicks; + Timer maDockTimer; + Point maDockPos; + Rectangle maDockRect; + BOOL mbInMove; + ULONG mnLastUserEvent; + + DECL_LINK( DockingHdl, ImplDockFloatWin* ); + DECL_LINK( DockTimerHdl, ImplDockFloatWin* ); +public: + ImplDockFloatWin( Window* pParent, WinBits nWinBits, + DockingWindow* pDockingWin ); + ~ImplDockFloatWin(); + + virtual void Move(); + virtual void Resize(); + virtual void TitleButtonClick( USHORT nButton ); + virtual void Pin(); + virtual void Roll(); + virtual void PopupModeEnd(); + virtual void Resizing( Size& rSize ); + virtual BOOL Close(); + + ULONG GetLastTicks() const { return mnLastTicks; } +}; + + +ImplDockFloatWin::ImplDockFloatWin( Window* pParent, WinBits nWinBits, + DockingWindow* pDockingWin ) : + FloatingWindow( pParent, nWinBits ), + mpDockWin( pDockingWin ), + mnLastTicks( Time::GetSystemTicks() ), + mbInMove( FALSE ), + mnLastUserEvent( 0 ) +{ + // Daten vom DockingWindow uebernehmen + if ( pDockingWin ) + { + SetSettings( pDockingWin->GetSettings() ); + Enable( pDockingWin->IsEnabled(), FALSE ); + EnableInput( pDockingWin->IsInputEnabled(), FALSE ); + AlwaysEnableInput( pDockingWin->IsAlwaysEnableInput(), FALSE ); + EnableAlwaysOnTop( pDockingWin->IsAlwaysOnTopEnabled() ); + SetActivateMode( pDockingWin->GetActivateMode() ); + } + + SetBackground(); + + maDockTimer.SetTimeoutHdl( LINK( this, ImplDockFloatWin, DockTimerHdl ) ); + maDockTimer.SetTimeout( 50 ); +} + +// ----------------------------------------------------------------------- + +ImplDockFloatWin::~ImplDockFloatWin() +{ + if( mnLastUserEvent ) + Application::RemoveUserEvent( mnLastUserEvent ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ImplDockFloatWin, DockTimerHdl, ImplDockFloatWin*, EMPTYARG ) +{ + DBG_ASSERT( mpDockWin->IsFloatingMode(), "docktimer called but not floating" ); + + maDockTimer.Stop(); + PointerState aState = GetPointerState(); + + if( aState.mnState & KEY_MOD1 ) + { + // i43499 CTRL disables docking now + mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, TRUE ); + if( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) + maDockTimer.Start(); + } + else if( ! ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) ) + { + mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking(); + mpDockWin->EndDocking( maDockRect, FALSE ); + } + else + { + mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_BIG | SHOWTRACK_WINDOW ); + maDockTimer.Start(); + } + + return 0; +} + +IMPL_LINK( ImplDockFloatWin, DockingHdl, ImplDockFloatWin*, EMPTYARG ) +{ + PointerState aState = mpDockWin->GetParent()->GetPointerState(); + + mnLastUserEvent = 0; + if( mpDockWin->IsDockable() && + (Time::GetSystemTicks() - mnLastTicks > 500) && + ( aState.mnState & ( MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT ) ) && + !(aState.mnState & KEY_MOD1) ) // i43499 CTRL disables docking now + { + maDockPos = Point( mpDockWin->GetParent()->AbsoluteScreenToOutputPixel( OutputToAbsoluteScreenPixel( Point() ) ) ); + maDockPos = mpDockWin->GetParent()->OutputToScreenPixel( maDockPos ); // sfx expects screen coordinates + + if( ! mpDockWin->IsDocking() ) + mpDockWin->StartDocking(); + maDockRect = Rectangle( maDockPos, mpDockWin->GetSizePixel() ); + + // mouse pos also in screen pixels + Point aMousePos = mpDockWin->GetParent()->OutputToScreenPixel( aState.maPos ); + + BOOL bFloatMode = mpDockWin->Docking( aMousePos, maDockRect ); + if( ! bFloatMode ) + { + mpDockWin->GetParent()->ImplGetFrameWindow()->ShowTracking( maDockRect, SHOWTRACK_OBJECT | SHOWTRACK_WINDOW ); + DockTimerHdl( this ); + } + else + { + mpDockWin->GetParent()->ImplGetFrameWindow()->HideTracking(); + maDockTimer.Stop(); + mpDockWin->EndDocking( maDockRect, TRUE ); + } + } + mbInMove = FALSE; + return 0; +} +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::Move() +{ + if( mbInMove ) + return; + + mbInMove = TRUE; + FloatingWindow::Move(); + mpDockWin->Move(); + + /* + * note: the window should only dock if + * the user releases all mouse buttons. The real problem here + * is that we don't get mouse events (at least not on X) + * if the mouse is on the decoration. So we have to start an + * awkward timer based process that polls the modifier/buttons + * to see whether they are in the right condition shortly after the + * last Move message. + */ + if( ! mnLastUserEvent ) + mnLastUserEvent = Application::PostUserEvent( LINK( this, ImplDockFloatWin, DockingHdl ) ); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::Resize() +{ + FloatingWindow::Resize(); + Size aSize( GetSizePixel() ); + mpDockWin->ImplPosSizeWindow( 0, 0, aSize.Width(), aSize.Height(), WINDOW_POSSIZE_POSSIZE ); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::TitleButtonClick( USHORT nButton ) +{ + FloatingWindow::TitleButtonClick( nButton ); + mpDockWin->TitleButtonClick( nButton ); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::Pin() +{ + FloatingWindow::Pin(); + mpDockWin->Pin(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::Roll() +{ + FloatingWindow::Roll(); + mpDockWin->Roll(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::PopupModeEnd() +{ + FloatingWindow::PopupModeEnd(); + mpDockWin->PopupModeEnd(); +} + +// ----------------------------------------------------------------------- + +void ImplDockFloatWin::Resizing( Size& rSize ) +{ + FloatingWindow::Resizing( rSize ); + mpDockWin->Resizing( rSize ); +} + +// ----------------------------------------------------------------------- + +BOOL ImplDockFloatWin::Close() +{ + return mpDockWin->Close(); +} + +// ======================================================================= + +BOOL DockingWindow::ImplStartDocking( const Point& rPos ) +{ + if ( !mbDockable ) + return FALSE; + + maMouseOff = rPos; + maMouseStart = maMouseOff; + mbDocking = TRUE; + mbLastFloatMode = IsFloatingMode(); + mbStartFloat = mbLastFloatMode; + + // FloatingBorder berechnen + FloatingWindow* pWin; + if ( mpFloatWin ) + pWin = mpFloatWin; + else + pWin = new ImplDockFloatWin( mpImplData->mpParent, mnFloatBits, NULL ); + pWin->GetBorder( mnDockLeft, mnDockTop, mnDockRight, mnDockBottom ); + if ( !mpFloatWin ) + delete pWin; + + Point aPos = ImplOutputToFrame( Point() ); + Size aSize = Window::GetOutputSizePixel(); + mnTrackX = aPos.X(); + mnTrackY = aPos.Y(); + mnTrackWidth = aSize.Width(); + mnTrackHeight = aSize.Height(); + + if ( mbLastFloatMode ) + { + maMouseOff.X() += mnDockLeft; + maMouseOff.Y() += mnDockTop; + mnTrackX -= mnDockLeft; + mnTrackY -= mnDockTop; + mnTrackWidth += mnDockLeft+mnDockRight; + mnTrackHeight += mnDockTop+mnDockBottom; + } + + if ( GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_DOCKING && + !( mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ) ) // no full drag when migrating to system window + mbDragFull = TRUE; + else + { + StartDocking(); + mbDragFull = FALSE; + ImplUpdateAll(); + ImplGetFrameWindow()->ImplUpdateAll(); + } + + StartTracking( STARTTRACK_KEYMOD ); + return TRUE; +} + +// ======================================================================= + +void DockingWindow::ImplInitDockingWindowData() +{ + mpImplData = new ImplData; + mpWindowImpl->mbDockWin = TRUE; + + mpFloatWin = NULL; + mbDockCanceled = FALSE; + mbDockPrevented = FALSE; + mbFloatPrevented = FALSE; + mbDocking = FALSE; + mbPined = FALSE; + mbRollUp = FALSE; + mbDockBtn = FALSE; + mbHideBtn = FALSE; +} + +// ----------------------------------------------------------------------- + +void DockingWindow::ImplInit( Window* pParent, WinBits nStyle ) +{ + if ( !(nStyle & WB_NODIALOGCONTROL) ) + nStyle |= WB_DIALOGCONTROL; + + mpImplData->mpParent = pParent; + mbDockable = (nStyle & WB_DOCKABLE) != 0; + mnFloatBits = WB_BORDER | (nStyle & DOCKWIN_FLOATSTYLES); + nStyle &= ~(DOCKWIN_FLOATSTYLES | WB_BORDER); + if ( nStyle & WB_DOCKBORDER ) + nStyle |= WB_BORDER; + + Window::ImplInit( pParent, nStyle, NULL ); + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::ImplInitSettings() +{ + // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann + // und noch nicht alles umgestellt ist + if ( IsBackground() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + SetBackground( aColor ); + } +} + +// ----------------------------------------------------------------------- + +void DockingWindow::ImplLoadRes( const ResId& rResId ) +{ + Window::ImplLoadRes( rResId ); + + ULONG nMask = ReadLongRes(); + + if ( (RSC_DOCKINGWINDOW_XYMAPMODE | RSC_DOCKINGWINDOW_X | + RSC_DOCKINGWINDOW_Y) & nMask ) + { + // Groessenangabe aus der Resource verwenden + Point aPos; + MapUnit ePosMap = MAP_PIXEL; + + if ( RSC_DOCKINGWINDOW_XYMAPMODE & nMask ) + ePosMap = (MapUnit)ReadLongRes(); + + if ( RSC_DOCKINGWINDOW_X & nMask ) + { + aPos.X() = ReadShortRes(); + aPos.X() = ImplLogicUnitToPixelX( aPos.X(), ePosMap ); + } + + if ( RSC_DOCKINGWINDOW_Y & nMask ) + { + aPos.Y() = ReadShortRes(); + aPos.Y() = ImplLogicUnitToPixelY( aPos.Y(), ePosMap ); + } + + SetFloatingPos( aPos ); + } + + if ( nMask & RSC_DOCKINGWINDOW_FLOATING ) + { + if ( (BOOL)ReadShortRes() ) + SetFloatingMode( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +DockingWindow::DockingWindow( WindowType nType ) : + Window( nType ) +{ + ImplInitDockingWindowData(); +} + +// ----------------------------------------------------------------------- + +DockingWindow::DockingWindow( Window* pParent, WinBits nStyle ) : + Window( WINDOW_DOCKINGWINDOW ) +{ + ImplInitDockingWindowData(); + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +DockingWindow::DockingWindow( Window* pParent, const ResId& rResId ) : + Window( WINDOW_DOCKINGWINDOW ) +{ + ImplInitDockingWindowData(); + rResId.SetRT( RSC_DOCKINGWINDOW ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +DockingWindow::~DockingWindow() +{ + if ( IsFloatingMode() ) + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + SetFloatingMode( FALSE ); + } + delete mpImplData; +} + +// ----------------------------------------------------------------------- + +void DockingWindow::Tracking( const TrackingEvent& rTEvt ) +{ + if( GetDockingManager()->IsDockable( this ) ) // new docking interface + return Window::Tracking( rTEvt ); + + if ( mbDocking ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbDocking = FALSE; + if ( mbDragFull ) + { + // Bei Abbruch alten Zustand wieder herstellen + if ( rTEvt.IsTrackingCanceled() ) + { + StartDocking(); + Rectangle aRect( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ); + EndDocking( aRect, mbStartFloat ); + } + } + else + { + HideTracking(); + if ( rTEvt.IsTrackingCanceled() ) + { + mbDockCanceled = TRUE; + EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + mbDockCanceled = FALSE; + } + else + EndDocking( Rectangle( Point( mnTrackX, mnTrackY ), Size( mnTrackWidth, mnTrackHeight ) ), mbLastFloatMode ); + } + } + // Docking nur bei nicht synthetischen MouseEvents + else if ( !rTEvt.GetMouseEvent().IsSynthetic() || rTEvt.GetMouseEvent().IsModifierChanged() ) + { + Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); + Point aFrameMousePos = ImplOutputToFrame( aMousePos ); + Size aFrameSize = mpWindowImpl->mpFrameWindow->GetOutputSizePixel(); + if ( aFrameMousePos.X() < 0 ) + aFrameMousePos.X() = 0; + if ( aFrameMousePos.Y() < 0 ) + aFrameMousePos.Y() = 0; + if ( aFrameMousePos.X() > aFrameSize.Width()-1 ) + aFrameMousePos.X() = aFrameSize.Width()-1; + if ( aFrameMousePos.Y() > aFrameSize.Height()-1 ) + aFrameMousePos.Y() = aFrameSize.Height()-1; + aMousePos = ImplFrameToOutput( aFrameMousePos ); + aMousePos.X() -= maMouseOff.X(); + aMousePos.Y() -= maMouseOff.Y(); + Point aFramePos = ImplOutputToFrame( aMousePos ); + Rectangle aTrackRect( aFramePos, Size( mnTrackWidth, mnTrackHeight ) ); + Rectangle aCompRect = aTrackRect; + aFramePos.X() += maMouseOff.X(); + aFramePos.Y() += maMouseOff.Y(); + if ( mbDragFull ) + StartDocking(); + BOOL bFloatMode = Docking( aFramePos, aTrackRect ); + mbDockPrevented = FALSE; + mbFloatPrevented = FALSE; + if ( mbLastFloatMode != bFloatMode ) + { + if ( bFloatMode ) + { + aTrackRect.Left() -= mnDockLeft; + aTrackRect.Top() -= mnDockTop; + aTrackRect.Right() += mnDockRight; + aTrackRect.Bottom() += mnDockBottom; + } + else + { + if ( aCompRect == aTrackRect ) + { + aTrackRect.Left() += mnDockLeft; + aTrackRect.Top() += mnDockTop; + aTrackRect.Right() -= mnDockRight; + aTrackRect.Bottom() -= mnDockBottom; + } + } + mbLastFloatMode = bFloatMode; + } + if ( mbDragFull ) + { + Point aPos; + Point aOldPos = OutputToScreenPixel( aPos ); + EndDocking( aTrackRect, mbLastFloatMode ); + // Wenn der Status bzw. die Position sich + // geaendert hat, dann neu ausgeben + if ( aOldPos != OutputToScreenPixel( aPos ) ) + { + ImplUpdateAll(); + ImplGetFrameWindow()->ImplUpdateAll(); + } +// EndDocking( aTrackRect, mbLastFloatMode ); + } + else + { + USHORT nTrackStyle; + if ( bFloatMode ) + nTrackStyle = SHOWTRACK_BIG; + else + nTrackStyle = SHOWTRACK_OBJECT; + Rectangle aShowTrackRect = aTrackRect; + aShowTrackRect.SetPos( ImplFrameToOutput( aShowTrackRect.TopLeft() ) ); + ShowTracking( aShowTrackRect, nTrackStyle ); + + // Maus-Offset neu berechnen, da Rechteck veraendert werden + // konnte + maMouseOff.X() = aFramePos.X() - aTrackRect.Left(); + maMouseOff.Y() = aFramePos.Y() - aTrackRect.Top(); + } + + mnTrackX = aTrackRect.Left(); + mnTrackY = aTrackRect.Top(); + mnTrackWidth = aTrackRect.GetWidth(); + mnTrackHeight = aTrackRect.GetHeight(); + } + } +} + +// ----------------------------------------------------------------------- + +long DockingWindow::Notify( NotifyEvent& rNEvt ) +{ + if( GetDockingManager()->IsDockable( this ) ) // new docking interface + return Window::Notify( rNEvt ); + + if ( mbDockable ) + { + if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) + { + const MouseEvent* pMEvt = rNEvt.GetMouseEvent(); + if ( pMEvt->IsLeft() ) + { + if ( pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) ) + { + SetFloatingMode( !IsFloatingMode() ); + return TRUE; + } + else if ( pMEvt->GetClicks() == 1 ) + { + // check if window is floating standalone (IsFloating()) + // or only partially floating and still docked with one border + // ( !mpWindowImpl->mbFrame) + if( ! IsFloatingMode() || ! mpFloatWin->mpWindowImpl->mbFrame ) + { + Point aPos = pMEvt->GetPosPixel(); + Window* pWindow = rNEvt.GetWindow(); + if ( pWindow != this ) + { + aPos = pWindow->OutputToScreenPixel( aPos ); + aPos = ScreenToOutputPixel( aPos ); + } + ImplStartDocking( aPos ); + } + return TRUE; + } + } + } + else if( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode(); + if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() && + rKey.IsShift() && rKey.IsMod1() ) + { + SetFloatingMode( !IsFloatingMode() ); + return TRUE; + } + } + } + + return Window::Notify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::StartDocking() +{ + mbDocking = TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL DockingWindow::Docking( const Point&, Rectangle& ) +{ + return IsFloatingMode(); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::EndDocking( const Rectangle& rRect, BOOL bFloatMode ) +{ + if ( !IsDockingCanceled() ) + { + BOOL bShow = FALSE; + if ( bFloatMode != IsFloatingMode() ) + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + SetFloatingMode( bFloatMode ); + bShow = TRUE; + if ( bFloatMode && mpFloatWin ) + mpFloatWin->SetPosSizePixel( rRect.TopLeft(), rRect.GetSize() ); + } + if ( !bFloatMode ) + { + Point aPos = rRect.TopLeft(); + aPos = GetParent()->ScreenToOutputPixel( aPos ); + Window::SetPosSizePixel( aPos, rRect.GetSize() ); + } + + if ( bShow ) + Show(); + } + mbDocking = FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL DockingWindow::PrepareToggleFloatingMode() +{ + return TRUE; +} + +// ----------------------------------------------------------------------- + +BOOL DockingWindow::Close() +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE ); + if ( aDelData.IsDelete() ) + return FALSE; + ImplRemoveDel( &aDelData ); + + if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() ) + return FALSE; + + Show( FALSE, SHOW_NOFOCUSCHANGE ); + return TRUE; +} + +// ----------------------------------------------------------------------- + +void DockingWindow::ToggleFloatingMode() +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::TitleButtonClick( USHORT ) +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::Pin() +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::Roll() +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::PopupModeEnd() +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::Resizing( Size& ) +{ +} + +// ----------------------------------------------------------------------- + +void DockingWindow::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } + + Window::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } + else + Window::DataChanged( rDCEvt ); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::ShowTitleButton( USHORT nButton, BOOL bVisible ) +{ + if ( mpFloatWin ) + mpFloatWin->ShowTitleButton( nButton, bVisible ); + else + { + if ( nButton == TITLE_BUTTON_DOCKING ) + mbDockBtn = bVisible; + else /* if ( nButton == TITLE_BUTTON_HIDE ) */ + mbHideBtn = bVisible; + } +} + +// ----------------------------------------------------------------------- + +BOOL DockingWindow::IsTitleButtonVisible( USHORT nButton ) const +{ + if ( mpFloatWin ) + return mpFloatWin->IsTitleButtonVisible( nButton ); + else + { + if ( nButton == TITLE_BUTTON_DOCKING ) + return mbDockBtn; + else /* if ( nButton == TITLE_BUTTON_HIDE ) */ + return mbHideBtn; + } +} + +// ----------------------------------------------------------------------- + +void DockingWindow::SetFloatingMode( BOOL bFloatMode ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + pWrapper->SetFloatingMode( bFloatMode ); + return; + } + if ( IsFloatingMode() != bFloatMode ) + { + if ( PrepareToggleFloatingMode() ) // changes to floating mode can be vetoed + { + BOOL bVisible = IsVisible(); + + if ( bFloatMode ) + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + maDockPos = Window::GetPosPixel(); + + Window* pRealParent = mpWindowImpl->mpRealParent; + mpOldBorderWin = mpWindowImpl->mpBorderWindow; + + ImplDockFloatWin* pWin = + new ImplDockFloatWin( + mpImplData->mpParent, + mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits, + this ); + mpFloatWin = pWin; + mpWindowImpl->mpBorderWindow = NULL; + mpWindowImpl->mnLeftBorder = 0; + mpWindowImpl->mnTopBorder = 0; + mpWindowImpl->mnRightBorder = 0; + mpWindowImpl->mnBottomBorder = 0; + // Falls Parent zerstoert wird, muessen wir auch vom + // BorderWindow den Parent umsetzen + if ( mpOldBorderWin ) + mpOldBorderWin->SetParent( pWin ); + SetParent( pWin ); + SetPosPixel( Point() ); + mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = this; + mpWindowImpl->mpRealParent = pRealParent; + pWin->SetText( Window::GetText() ); + pWin->SetOutputSizePixel( Window::GetSizePixel() ); + pWin->SetPosPixel( maFloatPos ); + // DockingDaten ans FloatingWindow weiterreichen + pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, mbDockBtn ); + pWin->ShowTitleButton( TITLE_BUTTON_HIDE, mbHideBtn ); + pWin->SetPin( mbPined ); + if ( mbRollUp ) + pWin->RollUp(); + else + pWin->RollDown(); + pWin->SetRollUpOutputSizePixel( maRollUpOutSize ); + pWin->SetMinOutputSizePixel( maMinOutSize ); + pWin->SetMaxOutputSizePixel( mpImplData->maMaxOutSize ); + + ToggleFloatingMode(); + + if ( bVisible ) + Show(); + } + else + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // FloatingDaten wird im FloatingWindow speichern + maFloatPos = mpFloatWin->GetPosPixel(); + mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING ); + mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE ); + mbPined = mpFloatWin->IsPined(); + mbRollUp = mpFloatWin->IsRollUp(); + maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel(); + maMinOutSize = mpFloatWin->GetMinOutputSizePixel(); + mpImplData->maMaxOutSize = mpFloatWin->GetMaxOutputSizePixel(); + + Window* pRealParent = mpWindowImpl->mpRealParent; + mpWindowImpl->mpBorderWindow = NULL; + if ( mpOldBorderWin ) + { + SetParent( mpOldBorderWin ); + ((ImplBorderWindow*)mpOldBorderWin)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpOldBorderWin->Resize(); + } + mpWindowImpl->mpBorderWindow = mpOldBorderWin; + SetParent( pRealParent ); + mpWindowImpl->mpRealParent = pRealParent; + delete static_cast<ImplDockFloatWin*>(mpFloatWin); + mpFloatWin = NULL; + SetPosPixel( maDockPos ); + + ToggleFloatingMode(); + + if ( bVisible ) + Show(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void DockingWindow::SetFloatStyle( WinBits nStyle ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + pWrapper->SetFloatStyle( nStyle ); + return; + } + + mnFloatBits = nStyle; +} + +// ----------------------------------------------------------------------- + +WinBits DockingWindow::GetFloatStyle() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + return pWrapper->GetFloatStyle(); + } + + return mnFloatBits; +} + +// ----------------------------------------------------------------------- + +void DockingWindow::SetTabStop() +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + pWrapper->SetTabStop(); + return; + } + + mpWindowImpl->mnStyle |= WB_GROUP | WB_TABSTOP; +} + +// ----------------------------------------------------------------------- + +void DockingWindow::SetPosSizePixel( long nX, long nY, + long nWidth, long nHeight, + USHORT nFlags ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + pWrapper->mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); + else + Window::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); + return; + } + + if ( mpFloatWin ) + mpFloatWin->SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); + else + Window::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags ); +} + +// ----------------------------------------------------------------------- + +Point DockingWindow::GetPosPixel() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + return pWrapper->mpFloatWin->GetPosPixel(); + else + return Window::GetPosPixel(); + } + + if ( mpFloatWin ) + return mpFloatWin->GetPosPixel(); + else + return Window::GetPosPixel(); +} + +// ----------------------------------------------------------------------- + +Size DockingWindow::GetSizePixel() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + return pWrapper->mpFloatWin->GetSizePixel(); + else + return Window::GetSizePixel(); + } + + if ( mpFloatWin ) + return mpFloatWin->GetSizePixel(); + else + return Window::GetSizePixel(); +} + +// ----------------------------------------------------------------------- + +void DockingWindow::SetOutputSizePixel( const Size& rNewSize ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + pWrapper->mpFloatWin->SetOutputSizePixel( rNewSize ); + else + Window::SetOutputSizePixel( rNewSize ); + return; + } + + if ( mpFloatWin ) + mpFloatWin->SetOutputSizePixel( rNewSize ); + else + Window::SetOutputSizePixel( rNewSize ); +} + +// ----------------------------------------------------------------------- + +Size DockingWindow::GetOutputSizePixel() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + return pWrapper->mpFloatWin->GetOutputSizePixel(); + else + return Window::GetOutputSizePixel(); + } + + if ( mpFloatWin ) + return mpFloatWin->GetOutputSizePixel(); + else + return Window::GetOutputSizePixel(); +} + +Point DockingWindow::GetFloatingPos() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + { + if ( pWrapper->mpFloatWin ) + { + WindowStateData aData; + aData.SetMask( WINDOWSTATE_MASK_POS ); + pWrapper->mpFloatWin->GetWindowStateData( aData ); + Point aPos( aData.GetX(), aData.GetY() ); + aPos = pWrapper->mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos ); + return aPos; + } + else + return maFloatPos; + } + + if ( mpFloatWin ) + { + WindowStateData aData; + aData.SetMask( WINDOWSTATE_MASK_POS ); + mpFloatWin->GetWindowStateData( aData ); + Point aPos( aData.GetX(), aData.GetY() ); + aPos = mpFloatWin->GetParent()->ImplGetFrameWindow()->AbsoluteScreenToOutputPixel( aPos ); + return aPos; + } + else + return maFloatPos; +} + +BOOL DockingWindow::IsFloatingMode() const +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + return pWrapper->IsFloatingMode(); + else + return (mpFloatWin != NULL); +} + +void DockingWindow::SetMaxOutputSizePixel( const Size& rSize ) +{ + if ( mpFloatWin ) + mpFloatWin->SetMaxOutputSizePixel( rSize ); + mpImplData->maMaxOutSize = rSize; +} + +const Size& DockingWindow::GetMaxOutputSizePixel() const +{ + if ( mpFloatWin ) + return mpFloatWin->GetMaxOutputSizePixel(); + return mpImplData->maMaxOutSize; +} diff --git a/vcl/source/window/floatwin.cxx b/vcl/source/window/floatwin.cxx new file mode 100644 index 000000000000..323bbe3b0d74 --- /dev/null +++ b/vcl/source/window/floatwin.cxx @@ -0,0 +1,878 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/event.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/window.h> +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/salframe.hxx> +#include <tools/debug.hxx> + + +// ======================================================================= + +class FloatingWindow::ImplData +{ +public: + ImplData(); + ~ImplData(); + + ToolBox* mpBox; + Rectangle maItemEdgeClipRect; // used to clip the common edge between a toolbar item and the border of this window +}; + +FloatingWindow::ImplData::ImplData() +{ + mpBox = NULL; +} + +FloatingWindow::ImplData::~ImplData() +{ +} + +Rectangle& FloatingWindow::ImplGetItemEdgeClipRect() +{ + return mpImplData->maItemEdgeClipRect; +} + +// ======================================================================= + +void FloatingWindow::ImplInit( Window* pParent, WinBits nStyle ) +{ + mpImplData = new ImplData; + + mpWindowImpl->mbFloatWin = TRUE; + mbInCleanUp = FALSE; + mbGrabFocus = FALSE; + + DBG_ASSERT( pParent, "FloatWindow::FloatingWindow(): - pParent == NULL!" ); + + if ( !pParent ) + pParent = ImplGetSVData()->maWinData.mpAppWin; + + DBG_ASSERT( pParent, "FloatWindow::FloatingWindow(): - pParent == NULL and no AppWindow exists" ); + + // no Border, then we dont need a border window + if ( !nStyle ) + { + mpWindowImpl->mbOverlapWin = TRUE; + nStyle |= WB_DIALOGCONTROL; + SystemWindow::ImplInit( pParent, nStyle, NULL ); + } + else + { + if ( !(nStyle & WB_NODIALOGCONTROL) ) + nStyle |= WB_DIALOGCONTROL; + + if( nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_ROLLABLE | WB_CLOSEABLE | WB_STANDALONE) + && !(nStyle & WB_OWNERDRAWDECORATION) ) + { + WinBits nFloatWinStyle = nStyle; + // #99154# floaters are not closeable by default anymore, eg fullscreen floater + // nFloatWinStyle |= WB_CLOSEABLE; + mpWindowImpl->mbFrame = TRUE; + mpWindowImpl->mbOverlapWin = TRUE; + SystemWindow::ImplInit( pParent, nFloatWinStyle & ~WB_BORDER, NULL ); + } + else + { + ImplBorderWindow* pBorderWin; + USHORT nBorderStyle = BORDERWINDOW_STYLE_BORDER | BORDERWINDOW_STYLE_FLOAT; + + if( nStyle & WB_OWNERDRAWDECORATION ) nBorderStyle |= BORDERWINDOW_STYLE_FRAME; + else nBorderStyle |= BORDERWINDOW_STYLE_OVERLAP; + + if ( (nStyle & WB_SYSTEMWINDOW) && !(nStyle & (WB_MOVEABLE | WB_SIZEABLE)) ) + { + nBorderStyle |= BORDERWINDOW_STYLE_FRAME; + nStyle |= WB_CLOSEABLE; // make undecorated floaters closeable + } + pBorderWin = new ImplBorderWindow( pParent, nStyle, nBorderStyle ); + SystemWindow::ImplInit( pBorderWin, nStyle & ~WB_BORDER, NULL ); + pBorderWin->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + pBorderWin->SetDisplayActive( TRUE ); + mpWindowImpl->mpBorderWindow = pBorderWin; + mpWindowImpl->mpRealParent = pParent; + } + } + SetActivateMode( 0 ); + + mpNextFloat = NULL; + mpFirstPopupModeWin = NULL; + mnPostId = 0; + mnTitle = (nStyle & WB_MOVEABLE) ? FLOATWIN_TITLE_NORMAL : FLOATWIN_TITLE_NONE; + mnOldTitle = mnTitle; + mnPopupModeFlags = 0; + mbInPopupMode = FALSE; + mbPopupMode = FALSE; + mbPopupModeCanceled = FALSE; + mbPopupModeTearOff = FALSE; + mbMouseDown = FALSE; + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::ImplInitSettings() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + SetBackground( aColor ); +} + +// ======================================================================= + +FloatingWindow::FloatingWindow( Window* pParent, WinBits nStyle ) : + SystemWindow( WINDOW_FLOATINGWINDOW ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +FloatingWindow::FloatingWindow( Window* pParent, const ResId& rResId ) : + SystemWindow( WINDOW_FLOATINGWINDOW ) +{ + rResId.SetRT( RSC_FLOATINGWINDOW ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::ImplLoadRes( const ResId& rResId ) +{ + SystemWindow::ImplLoadRes( rResId ); + + ULONG nObjMask = ReadLongRes(); + + if ( (RSC_FLOATINGWINDOW_WHMAPMODE | RSC_FLOATINGWINDOW_WIDTH | + RSC_FLOATINGWINDOW_HEIGHT) & nObjMask ) + { + // Groessenangabe aus der Resource verwenden + Size aSize; + MapUnit eSizeMap = MAP_PIXEL; + + if ( RSC_FLOATINGWINDOW_WHMAPMODE & nObjMask ) + eSizeMap = (MapUnit) ReadShortRes(); + if ( RSC_FLOATINGWINDOW_WIDTH & nObjMask ) + aSize.Width() = ReadShortRes(); + if ( RSC_FLOATINGWINDOW_HEIGHT & nObjMask ) + aSize.Height() = ReadShortRes(); + + SetRollUpOutputSizePixel( LogicToPixel( aSize, eSizeMap ) ); + } + + if (nObjMask & RSC_FLOATINGWINDOW_ZOOMIN ) + { + if ( ReadShortRes() ) + RollUp(); + } +} + +// ----------------------------------------------------------------------- + +FloatingWindow::~FloatingWindow() +{ + if( mbPopupModeCanceled ) + // indicates that ESC key was pressed + // will be handled in Window::ImplGrabFocus() + SetDialogControlFlags( GetDialogControlFlags() | WINDOW_DLGCTRL_FLOATWIN_POPUPMODEEND_CANCEL ); + + if ( IsInPopupMode() ) + EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL | FLOATWIN_POPUPMODEEND_DONTCALLHDL ); + + if ( mnPostId ) + Application::RemoveUserEvent( mnPostId ); + + delete mpImplData; +} + +// ----------------------------------------------------------------------- + +Point FloatingWindow::CalcFloatingPosition( Window* pWindow, const Rectangle& rRect, ULONG nFlags, USHORT& rArrangeIndex ) +{ + return ImplCalcPos( pWindow, rRect, nFlags, rArrangeIndex ); +} + +// ----------------------------------------------------------------------- + +Point FloatingWindow::ImplCalcPos( Window* pWindow, + const Rectangle& rRect, ULONG nFlags, + USHORT& rArrangeIndex ) +{ + // Fenster-Position ermitteln + Point aPos; + Size aSize = pWindow->GetSizePixel(); + Rectangle aScreenRect = pWindow->ImplGetFrameWindow()->GetDesktopRectPixel(); + FloatingWindow *pFloatingWindow = dynamic_cast<FloatingWindow*>( pWindow ); + + // convert.... + Window* pW = pWindow; + if ( pW->mpWindowImpl->mpRealParent ) + pW = pW->mpWindowImpl->mpRealParent; + + Rectangle normRect( rRect ); // rRect is already relative to top-level window + normRect.SetPos( pW->ScreenToOutputPixel( normRect.TopLeft() ) ); + + BOOL bRTL = Application::GetSettings().GetLayoutRTL(); + + Rectangle devRect( pW->OutputToAbsoluteScreenPixel( normRect.TopLeft() ), + pW->OutputToAbsoluteScreenPixel( normRect.BottomRight() ) ); + + Rectangle devRectRTL( devRect ); + if( bRTL ) + // create a rect that can be compared to desktop coordinates + devRectRTL = pW->ImplOutputToUnmirroredAbsoluteScreenPixel( normRect ); + if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() ) + aScreenRect = Application::GetScreenPosSizePixel( + Application::GetBestScreen( bRTL ? devRectRTL : devRect ) ); + + + USHORT nArrangeAry[5]; + USHORT nArrangeIndex; + BOOL bBreak; + Point e1,e2; // the common edge between the item rect and the floating window + + if ( nFlags & FLOATWIN_POPUPMODE_LEFT ) + { + nArrangeAry[0] = FLOATWIN_POPUPMODE_LEFT; + nArrangeAry[1] = FLOATWIN_POPUPMODE_RIGHT; + nArrangeAry[2] = FLOATWIN_POPUPMODE_UP; + nArrangeAry[3] = FLOATWIN_POPUPMODE_DOWN; + nArrangeAry[4] = FLOATWIN_POPUPMODE_LEFT; + } + else if ( nFlags & FLOATWIN_POPUPMODE_RIGHT ) + { + nArrangeAry[0] = FLOATWIN_POPUPMODE_RIGHT; + nArrangeAry[1] = FLOATWIN_POPUPMODE_LEFT; + nArrangeAry[2] = FLOATWIN_POPUPMODE_UP; + nArrangeAry[3] = FLOATWIN_POPUPMODE_DOWN; + nArrangeAry[4] = FLOATWIN_POPUPMODE_RIGHT; + } + else if ( nFlags & FLOATWIN_POPUPMODE_UP ) + { + nArrangeAry[0] = FLOATWIN_POPUPMODE_UP; + nArrangeAry[1] = FLOATWIN_POPUPMODE_DOWN; + nArrangeAry[2] = FLOATWIN_POPUPMODE_RIGHT; + nArrangeAry[3] = FLOATWIN_POPUPMODE_LEFT; + nArrangeAry[4] = FLOATWIN_POPUPMODE_UP; + } + else + { + nArrangeAry[0] = FLOATWIN_POPUPMODE_DOWN; + nArrangeAry[1] = FLOATWIN_POPUPMODE_UP; + nArrangeAry[2] = FLOATWIN_POPUPMODE_RIGHT; + nArrangeAry[3] = FLOATWIN_POPUPMODE_LEFT; + nArrangeAry[4] = FLOATWIN_POPUPMODE_DOWN; + } + if ( nFlags & FLOATWIN_POPUPMODE_NOAUTOARRANGE ) + nArrangeIndex = 4; + else + nArrangeIndex = 0; + + for ( ; nArrangeIndex < 5; nArrangeIndex++ ) + { + bBreak = TRUE; + switch ( nArrangeAry[nArrangeIndex] ) + { + + case FLOATWIN_POPUPMODE_LEFT: + aPos.X() = devRect.Left()-aSize.Width()+1; + aPos.Y() = devRect.Top(); + aPos.Y() -= pWindow->mpWindowImpl->mnTopBorder; + if( bRTL ) // --- RTL --- we're comparing screen coordinates here + { + if( (devRectRTL.Right()+aSize.Width()) > aScreenRect.Right() ) + bBreak = FALSE; + } + else + { + if ( aPos.X() < aScreenRect.Left() ) + bBreak = FALSE; + } + if( bBreak ) + { + e1 = devRect.TopLeft(); + e2 = devRect.BottomLeft(); + // set non-zero width + e2.X()++; + // don't clip corners + e1.Y()++; + e2.Y()--; + } + break; + case FLOATWIN_POPUPMODE_RIGHT: + aPos = devRect.TopRight(); + aPos.Y() -= pWindow->mpWindowImpl->mnTopBorder; + if( bRTL ) // --- RTL --- we're comparing screen coordinates here + { + if( (devRectRTL.Left() - aSize.Width()) < aScreenRect.Left() ) + bBreak = FALSE; + } + else + { + if ( aPos.X()+aSize.Width() > aScreenRect.Right() ) + bBreak = FALSE; + } + if( bBreak ) + { + e1 = devRect.TopRight(); + e2 = devRect.BottomRight(); + // set non-zero width + e2.X()++; + // don't clip corners + e1.Y()++; + e2.Y()--; + } + break; + case FLOATWIN_POPUPMODE_UP: + aPos.X() = devRect.Left(); + aPos.Y() = devRect.Top()-aSize.Height()+1; + if ( aPos.Y() < aScreenRect.Top() ) + bBreak = FALSE; + if( bBreak ) + { + e1 = devRect.TopLeft(); + e2 = devRect.TopRight(); + // set non-zero height + e2.Y()++; + // don't clip corners + e1.X()++; + e2.X()--; + } + break; + case FLOATWIN_POPUPMODE_DOWN: + aPos = devRect.BottomLeft(); + if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() ) + bBreak = FALSE; + if( bBreak ) + { + e1 = devRect.BottomLeft(); + e2 = devRect.BottomRight(); + // set non-zero height + e2.Y()++; + // don't clip corners + e1.X()++; + e2.X()--; + } + break; + } + + // Evt. noch anpassen + if ( bBreak && !(nFlags & FLOATWIN_POPUPMODE_NOAUTOARRANGE) ) + { + if ( (nArrangeAry[nArrangeIndex] == FLOATWIN_POPUPMODE_LEFT) || + (nArrangeAry[nArrangeIndex] == FLOATWIN_POPUPMODE_RIGHT) ) + { + if ( aPos.Y()+aSize.Height() > aScreenRect.Bottom() ) + { + aPos.Y() = devRect.Bottom()-aSize.Height()+1; + if ( aPos.Y() < aScreenRect.Top() ) + aPos.Y() = aScreenRect.Top(); + } + } + else + { + if( bRTL ) // --- RTL --- we're comparing screen coordinates here + { + if( devRectRTL.Right()-aSize.Width()+1 < aScreenRect.Left() ) + aPos.X() -= aScreenRect.Left() - devRectRTL.Right() + aSize.Width() - 1; + else if( aPos.X() + aSize.Width() > aScreenRect.Right() ) + { + aPos.X() -= aSize.Width()-2; // popup to left instead + aPos.Y() -= 2; + } + } + else if ( aPos.X()+aSize.Width() > aScreenRect.Right() ) + { + aPos.X() = devRect.Right()-aSize.Width()+1; + if ( aPos.X() < aScreenRect.Left() ) + aPos.X() = aScreenRect.Left(); + } + } + } + + if ( bBreak ) + break; + } + if ( nArrangeIndex > 4 ) + nArrangeIndex = 4; + + rArrangeIndex = nArrangeIndex; + + aPos = pW->AbsoluteScreenToOutputPixel( aPos ); + + // store a cliprect that can be used to clip the common edge of the itemrect and the floating window + if( pFloatingWindow ) + { + pFloatingWindow->mpImplData->maItemEdgeClipRect = + Rectangle( e1, e2 ); + } + + // caller expects cordinates relative to top-level win + return pW->OutputToScreenPixel( aPos ); +} + +// ----------------------------------------------------------------------- + +FloatingWindow* FloatingWindow::ImplFloatHitTest( Window* pReference, const Point& rPos, USHORT& rHitTest ) +{ + FloatingWindow* pWin = this; + + Point aAbsolute( rPos ); + + // compare coordinates in absolute screen coordinates + if( pReference->ImplHasMirroredGraphics() ) + { + if(!pReference->IsRTLEnabled() ) + // --- RTL --- re-mirror back to get device coordiantes + pReference->ImplReMirror( aAbsolute ); + + Rectangle aRect( pReference->ScreenToOutputPixel(aAbsolute), Size(1,1) ) ; + aRect = pReference->ImplOutputToUnmirroredAbsoluteScreenPixel( aRect ); + aAbsolute = aRect.TopLeft(); + } + else + aAbsolute = Point( pReference->OutputToAbsoluteScreenPixel( + pReference->ScreenToOutputPixel(rPos) ) ); + + do + { + // compute the floating window's size in absolute screen coordinates + + // use the border window to have the exact position + Window *pBorderWin = pWin->GetWindow( WINDOW_BORDER ); + + Point aPt; // the top-left corner in output coordinates ie (0,0) + Rectangle devRect( pBorderWin->ImplOutputToUnmirroredAbsoluteScreenPixel( Rectangle( aPt, pBorderWin->GetSizePixel()) ) ) ; + if ( devRect.IsInside( aAbsolute ) ) + { + rHitTest = IMPL_FLOATWIN_HITTEST_WINDOW; + return pWin; + } + + // test, if mouse is in rectangle, (this is typically the rect of the active + // toolbox item or similar) + // note: maFloatRect is set in FloatingWindow::StartPopupMode() and + // is already in absolute device coordinates + if ( pWin->maFloatRect.IsInside( aAbsolute ) ) + { + rHitTest = IMPL_FLOATWIN_HITTEST_RECT; + return pWin; + } + + pWin = pWin->mpNextFloat; + } + while ( pWin ); + + rHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE; + return NULL; +} + +// ----------------------------------------------------------------------- + +FloatingWindow* FloatingWindow::ImplFindLastLevelFloat() +{ + FloatingWindow* pWin = this; + FloatingWindow* pLastFoundWin = pWin; + + do + { + if ( pWin->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NEWLEVEL ) + pLastFoundWin = pWin; + + pWin = pWin->mpNextFloat; + } + while ( pWin ); + + return pLastFoundWin; +} + +// ----------------------------------------------------------------------- + +BOOL FloatingWindow::ImplIsFloatPopupModeWindow( const Window* pWindow ) +{ + FloatingWindow* pWin = this; + + do + { + if ( pWin->mpFirstPopupModeWin == pWindow ) + return TRUE; + + pWin = pWin->mpNextFloat; + } + while ( pWin ); + + return FALSE; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( FloatingWindow, ImplEndPopupModeHdl, void*, EMPTYARG ) +{ + mnPostId = 0; + mnPopupModeFlags = 0; + mbPopupMode = FALSE; + PopupModeEnd(); + return 0; +} + +// ----------------------------------------------------------------------- + +long FloatingWindow::Notify( NotifyEvent& rNEvt ) +{ + // Zuerst Basisklasse rufen wegen TabSteuerung + long nRet = SystemWindow::Notify( rNEvt ); + if ( !nRet ) + { + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + KeyCode aKeyCode = pKEvt->GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + + if ( (nKeyCode == KEY_ESCAPE) && (GetStyle() & WB_CLOSEABLE) ) + { + Close(); + return TRUE; + } + } + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::StateChanged( StateChangedType nType ) +{ + SystemWindow::StateChanged( nType ); + + if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + SystemWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::ImplCallPopupModeEnd() +{ + // PopupMode wurde beendet + mbInPopupMode = FALSE; + + // Handler asyncron rufen + if ( !mnPostId ) + Application::PostUserEvent( mnPostId, LINK( this, FloatingWindow, ImplEndPopupModeHdl ) ); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::PopupModeEnd() +{ + maPopupModeEndHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::SetTitleType( USHORT nTitle ) +{ + if ( (mnTitle != nTitle) && mpWindowImpl->mpBorderWindow ) + { + mnTitle = nTitle; + Size aOutSize = GetOutputSizePixel(); + USHORT nTitleStyle; + if ( nTitle == FLOATWIN_TITLE_NORMAL ) + nTitleStyle = BORDERWINDOW_TITLE_SMALL; + else if ( nTitle == FLOATWIN_TITLE_TEAROFF ) + nTitleStyle = BORDERWINDOW_TITLE_TEAROFF; + else // nTitle == FLOATWIN_TITLE_NONE + nTitleStyle = BORDERWINDOW_TITLE_NONE; + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetTitleType( nTitleStyle, aOutSize ); + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + } +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::StartPopupMode( const Rectangle& rRect, ULONG nFlags ) +{ + // avoid flickering + if ( IsVisible() ) + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + if ( IsRollUp() ) + RollDown(); + + // remove title + mnOldTitle = mnTitle; + if ( nFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF ) + SetTitleType( FLOATWIN_TITLE_TEAROFF ); + else + SetTitleType( FLOATWIN_TITLE_NONE ); + + // avoid close on focus change for decorated floating windows only + if( mpWindowImpl->mbFrame && (GetStyle() & WB_MOVEABLE) ) + nFlags |= FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + + // #102010# For debugging Accessibility + static const char* pEnv = getenv("SAL_FLOATWIN_NOAPPFOCUSCLOSE" ); + if( pEnv && *pEnv ) + nFlags |= FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + + // compute window position according to flags and arrangement + USHORT nArrangeIndex; + SetPosPixel( ImplCalcPos( this, rRect, nFlags, nArrangeIndex ) ); + + // set data and display window + // convert maFloatRect to absolute device coordinates + // so they can be compared across different frames + // !!! rRect is expected to be in screen coordinates of the parent frame window !!! + maFloatRect = rRect; + if( GetParent()->ImplHasMirroredGraphics() ) + { + maFloatRect.SetPos( GetParent()->ScreenToOutputPixel( rRect.TopLeft() ) ); + maFloatRect = GetParent()->ImplOutputToUnmirroredAbsoluteScreenPixel( maFloatRect ); + } + else + maFloatRect.SetPos( GetParent()->OutputToAbsoluteScreenPixel( GetParent()->ScreenToOutputPixel( rRect.TopLeft() ) ) ); + + maFloatRect.Left() -= 2; + maFloatRect.Top() -= 2; + maFloatRect.Right() += 2; + maFloatRect.Bottom() += 2; + mnPopupModeFlags = nFlags; + mbInPopupMode = TRUE; + mbPopupMode = TRUE; + mbPopupModeCanceled = FALSE; + mbPopupModeTearOff = FALSE; + mbMouseDown = FALSE; + + mbOldSaveBackMode = IsSaveBackgroundEnabled(); + EnableSaveBackground(); + + // add FloatingWindow to list of windows that are in popup mode + ImplSVData* pSVData = ImplGetSVData(); + mpNextFloat = pSVData->maWinData.mpFirstFloat; + pSVData->maWinData.mpFirstFloat = this; + if( nFlags & FLOATWIN_POPUPMODE_GRABFOCUS ) + { + // force key input even without focus (useful for menues) + mbGrabFocus = TRUE; + } + Show( TRUE, SHOW_NOACTIVATE ); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::StartPopupMode( ToolBox* pBox, ULONG nFlags ) +{ + // get selected button + USHORT nItemId = pBox->GetDownItemId(); + if ( !nItemId ) + return; + + mpImplData->mpBox = pBox; + pBox->ImplFloatControl( TRUE, this ); + + // retrieve some data from the ToolBox + Rectangle aRect = pBox->GetItemRect( nItemId ); + Point aPos; + // convert to parent's screen coordinates + aPos = GetParent()->OutputToScreenPixel( GetParent()->AbsoluteScreenToOutputPixel( pBox->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ) ); + aRect.SetPos( aPos ); + + nFlags |= + FLOATWIN_POPUPMODE_NOFOCUSCLOSE | +// FLOATWIN_POPUPMODE_NOMOUSECLOSE | + FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE | +// FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE | // #105968# floating toolboxes should close when clicked in (parent's) float rect + FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; +// | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE; + +/* + * FLOATWIN_POPUPMODE_NOKEYCLOSE | + * don't set since it disables closing floaters with escape + */ + + // Flags fuer Positionierung bestimmen + if ( !(nFlags & (FLOATWIN_POPUPMODE_DOWN | FLOATWIN_POPUPMODE_UP | + FLOATWIN_POPUPMODE_LEFT | FLOATWIN_POPUPMODE_RIGHT | + FLOATWIN_POPUPMODE_NOAUTOARRANGE)) ) + { + if ( pBox->IsHorizontal() ) + nFlags |= FLOATWIN_POPUPMODE_DOWN; + else + nFlags |= FLOATWIN_POPUPMODE_RIGHT; + } + + // FloatingModus starten + StartPopupMode( aRect, nFlags ); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::ImplEndPopupMode( USHORT nFlags, ULONG nFocusId ) +{ + if ( !mbInPopupMode ) + return; + + ImplSVData* pSVData = ImplGetSVData(); + + mbInCleanUp = TRUE; // prevent killing this window due to focus change while working with it + + // Bei allen nachfolgenden PopupMode-Fenster den Modus auch beenden + while ( pSVData->maWinData.mpFirstFloat && pSVData->maWinData.mpFirstFloat != this ) + pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL ); + + + // Fenster aus der Liste austragen + pSVData->maWinData.mpFirstFloat = mpNextFloat; + mpNextFloat = NULL; + + ULONG nPopupModeFlags = mnPopupModeFlags; + + // Wenn nicht abgerissen wurde, dann Fenster wieder Hiden + if ( !(nFlags & FLOATWIN_POPUPMODEEND_TEAROFF) || + !(nPopupModeFlags & FLOATWIN_POPUPMODE_ALLOWTEAROFF) ) + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // Focus evt. auf ein entsprechendes FloatingWindow weiterschalten + if ( nFocusId ) + Window::EndSaveFocus( nFocusId ); + else if ( pSVData->maWinData.mpFocusWin && pSVData->maWinData.mpFirstFloat && + ImplIsWindowOrChild( pSVData->maWinData.mpFocusWin ) ) + pSVData->maWinData.mpFirstFloat->GrabFocus(); + mbPopupModeTearOff = FALSE; + } + else + { + mbPopupModeTearOff = TRUE; + if ( nFocusId ) + Window::EndSaveFocus( nFocusId, FALSE ); + } + EnableSaveBackground( mbOldSaveBackMode ); + + mbPopupModeCanceled = (nFlags & FLOATWIN_POPUPMODEEND_CANCEL) != 0; + + // Gegebenenfalls den Title wieder herstellen + SetTitleType( mnOldTitle ); + + // ToolBox wieder auf normal schalten + if ( mpImplData->mpBox ) + { + mpImplData->mpBox->ImplFloatControl( FALSE, this ); + mpImplData->mpBox = NULL; + } + + // Je nach Parameter den PopupModeEnd-Handler rufen + if ( !(nFlags & FLOATWIN_POPUPMODEEND_DONTCALLHDL) ) + ImplCallPopupModeEnd(); + + // Je nach Parameter die restlichen Fenster auch noch schliessen + if ( nFlags & FLOATWIN_POPUPMODEEND_CLOSEALL ) + { + if ( !(nPopupModeFlags & FLOATWIN_POPUPMODE_NEWLEVEL) ) + { + if ( pSVData->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + } + } + + mbInCleanUp = FALSE; +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::EndPopupMode( USHORT nFlags ) +{ + ImplEndPopupMode( nFlags ); +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::AddPopupModeWindow( Window* pWindow ) +{ + // !!! bisher erst 1 Fenster und noch keine Liste + mpFirstPopupModeWin = pWindow; +} + +// ----------------------------------------------------------------------- + +void FloatingWindow::RemovePopupModeWindow( Window* pWindow ) +{ + // !!! bisher erst 1 Fenster und noch keine Liste + if ( mpFirstPopupModeWin == pWindow ) + mpFirstPopupModeWin = NULL; +} + diff --git a/vcl/source/window/introwin.cxx b/vcl/source/window/introwin.cxx new file mode 100644 index 000000000000..03f88adc3566 --- /dev/null +++ b/vcl/source/window/introwin.cxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salframe.hxx> +#include <tools/debug.hxx> +#include <vcl/svdata.hxx> +#include <vcl/wrkwin.hxx> + +#include <vcl/bitmap.hxx> +#include <vcl/impbmp.hxx> +#include <vcl/introwin.hxx> + + + + +// ======================================================================= + +void IntroWindow::ImplInitIntroWindowData() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->mpIntroWindow = this; +} + +// ----------------------------------------------------------------------- + +IntroWindow::IntroWindow( ) : + WorkWindow( WINDOW_INTROWINDOW ) +{ + ImplInitIntroWindowData(); + WorkWindow::ImplInit( 0, WB_INTROWIN, NULL ); +} + +// ----------------------------------------------------------------------- + +IntroWindow::~IntroWindow() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->mpIntroWindow == this ) + pSVData->mpIntroWindow = NULL; +} + +void IntroWindow::SetBackgroundBitmap( const Bitmap& rBitmap ) +{ + if( ! rBitmap.IsEmpty() ) + { + SalBitmap* pBmp = rBitmap.ImplGetImpBitmap()->ImplGetSalBitmap(); + ImplGetFrame()->SetBackgroundBitmap( pBmp ); + } +} + +void IntroWindow::SetBackgroundBitmap( const BitmapEx& rBitmapEx ) +{ + if( ! rBitmapEx.IsEmpty() ) + { + SalBitmap* pBmp = rBitmapEx.ImplGetBitmapImpBitmap()->ImplGetSalBitmap(); + ImplGetFrame()->SetBackgroundBitmap( pBmp ); + } +} diff --git a/vcl/source/window/javachild.cxx b/vcl/source/window/javachild.cxx new file mode 100644 index 000000000000..aa198c85c138 --- /dev/null +++ b/vcl/source/window/javachild.cxx @@ -0,0 +1,63 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: javachild.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <vcl/javachild.hxx> + +// ------------------- +// - JavaChildWindow - +// ------------------- + +JavaChildWindow::JavaChildWindow( Window* pParent, WinBits nStyle ) : + SystemChildWindow( pParent, nStyle ) +{ +} + +// ----------------------------------------------------------------------- + +JavaChildWindow::JavaChildWindow( Window* pParent, const ResId& rResId ) : + SystemChildWindow( pParent, rResId ) +{ +} + +// ----------------------------------------------------------------------- + +JavaChildWindow::~JavaChildWindow() +{ +} + +// ----------------------------------------------------------------------- + +sal_IntPtr JavaChildWindow::getParentWindowHandleForJava() +{ + return SystemChildWindow::GetParentWindowHandle( sal_True ); +} diff --git a/vcl/source/window/keycod.cxx b/vcl/source/window/keycod.cxx new file mode 100644 index 000000000000..bcc5536fd028 --- /dev/null +++ b/vcl/source/window/keycod.cxx @@ -0,0 +1,160 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salinst.hxx> +#include <vcl/salframe.hxx> +#include <vcl/svdata.hxx> +#include <vcl/window.hxx> +#ifndef _SV_KEYCOD_HXX +#include <vcl/keycod.hxx> +#endif + +#ifndef _RC_H +#include <tools/rc.h> +#endif + + + +// ======================================================================= +static USHORT aImplKeyFuncTab[(KEYFUNC_FRONT+1)*4] = +{ + 0, 0, 0, 0, // KEYFUNC_DONTKNOW + KEY_N | KEY_MOD1, 0, 0, 0, // KEYFUNC_NEW + KEY_O | KEY_MOD1, KEY_OPEN, 0, 0, // KEYFUNC_OPEN + KEY_S | KEY_MOD1, 0, 0, 0, // KEYFUNC_SAVE + 0, 0, 0, 0, // KEYFUNC_SAVEAS + KEY_P | KEY_MOD1, 0, 0, 0, // KEYFUNC_PRINT + KEY_W | KEY_MOD1, KEY_F4 | KEY_MOD1, 0, 0, // KEYFUNC_CLOSE + KEY_Q | KEY_MOD1, KEY_F4 | KEY_MOD2, 0, 0, // KEYFUNC_QUIT + KEY_X | KEY_MOD1, KEY_DELETE | KEY_SHIFT, KEY_CUT, 0, // KEYFUNC_CUT + KEY_C | KEY_MOD1, KEY_INSERT | KEY_MOD1, KEY_COPY, 0, // KEYFUNC_COPY + KEY_V | KEY_MOD1, KEY_INSERT | KEY_SHIFT, KEY_PASTE, 0, // KEYFUNC_PASTE + KEY_Z | KEY_MOD1, KEY_BACKSPACE | KEY_MOD2, KEY_UNDO, 0, // KEYFUNC_UNDO + 0, 0, 0, 0, // KEYFUNC_REDO + KEY_DELETE, 0, 0, 0, // KEYFUNC_DELETE + KEY_REPEAT, 0, 0, 0, // KEYFUNC_REPEAT + KEY_F | KEY_MOD1, KEY_FIND, 0, 0, // KEYFUNC_FIND + KEY_F | KEY_SHIFT | KEY_MOD1, KEY_SHIFT | KEY_FIND, 0, 0, // KEYFUNC_FINDBACKWARD + KEY_RETURN | KEY_MOD2, 0, 0, 0, // KEYFUNC_PROPERTIES + 0, 0, 0, 0 // KEYFUNC_FRONT +}; + +// ----------------------------------------------------------------------- + +void ImplGetKeyCode( KeyFuncType eFunc, USHORT& rCode1, USHORT& rCode2, USHORT& rCode3, USHORT& rCode4 ) +{ + USHORT nIndex = (USHORT)eFunc; + nIndex *= 4; + rCode1 = aImplKeyFuncTab[nIndex]; + rCode2 = aImplKeyFuncTab[nIndex+1]; + rCode3 = aImplKeyFuncTab[nIndex+2]; + rCode4 = aImplKeyFuncTab[nIndex+3]; +} + +// ======================================================================= + +KeyCode::KeyCode( KeyFuncType eFunction ) +{ + USHORT nDummy; + ImplGetKeyCode( eFunction, nCode, nDummy, nDummy, nDummy ); + eFunc = eFunction; +} + +// ----------------------------------------------------------------------- + +KeyCode::KeyCode( const ResId& rResId ) +{ + rResId.SetRT( RSC_KEYCODE ); + + ResMgr* pResMgr = rResId.GetResMgr(); + if ( pResMgr && pResMgr->GetResource( rResId ) ) + { + pResMgr->Increment( sizeof( RSHEADER_TYPE ) ); + + ULONG nKeyCode = pResMgr->ReadLong(); + ULONG nModifier = pResMgr->ReadLong(); + ULONG nKeyFunc = pResMgr->ReadLong(); + + eFunc = (KeyFuncType)nKeyFunc; + if ( eFunc != KEYFUNC_DONTKNOW ) + { + USHORT nDummy; + ImplGetKeyCode( eFunc, nCode, nDummy, nDummy, nDummy ); + } + else + nCode = sal::static_int_cast<USHORT>(nKeyCode | nModifier); + } +} + +// ----------------------------------------------------------------------- + +XubString KeyCode::GetName( Window* pWindow ) const +{ + if ( !pWindow ) + pWindow = ImplGetDefaultWindow(); + return pWindow ? pWindow->ImplGetFrame()->GetKeyName( GetFullCode() ) : XubString(); +} + +// ----------------------------------------------------------------------- + +XubString KeyCode::GetSymbolName( const XubString& rFontName, Window* pWindow ) const +{ + if ( !pWindow ) + pWindow = ImplGetDefaultWindow(); + return pWindow ? pWindow->ImplGetFrame()->GetSymbolKeyName( rFontName, GetFullCode() ) : XubString(); +} + +// ----------------------------------------------------------------------- + +KeyFuncType KeyCode::GetFunction() const +{ + if ( eFunc != KEYFUNC_DONTKNOW ) + return eFunc; + + USHORT nCompCode = GetModifier() | GetCode(); + if ( nCompCode ) + { + for ( USHORT i = (USHORT)KEYFUNC_NEW; i < (USHORT)KEYFUNC_FRONT; i++ ) + { + USHORT nKeyCode1; + USHORT nKeyCode2; + USHORT nKeyCode3; + USHORT nKeyCode4; + ImplGetKeyCode( (KeyFuncType)i, nKeyCode1, nKeyCode2, nKeyCode3, nKeyCode4 ); + if ( (nCompCode == nKeyCode1) || (nCompCode == nKeyCode2) || (nCompCode == nKeyCode3) || (nCompCode == nKeyCode4) ) + return (KeyFuncType)i; + } + } + + return KEYFUNC_DONTKNOW; +} diff --git a/vcl/source/window/keyevent.cxx b/vcl/source/window/keyevent.cxx new file mode 100644 index 000000000000..f4011b9be16e --- /dev/null +++ b/vcl/source/window/keyevent.cxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <com/sun/star/awt/KeyEvent.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <tools/debug.hxx> +#include <vcl/event.hxx> + +KeyEvent::KeyEvent (const KeyEvent& rKeyEvent) : + maKeyCode (rKeyEvent.maKeyCode), + mnRepeat (rKeyEvent.mnRepeat), + mnCharCode(rKeyEvent.mnCharCode) +{} + +/** inits this vcl KeyEvent with all settings from the given awt event **/ +KeyEvent::KeyEvent( const ::com::sun::star::awt::KeyEvent& rEvent ) +{ + maKeyCode = KeyCode( + rEvent.KeyCode, + (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::SHIFT) != 0, + (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD1) != 0, + (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD2) != 0, + (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD3) != 0); + mnRepeat = 0; + mnCharCode = rEvent.KeyChar; +} + +/** fills out the given awt KeyEvent with all settings from this vcl event **/ +void KeyEvent::InitKeyEvent( ::com::sun::star::awt::KeyEvent& rEvent ) const +{ + rEvent.Modifiers = 0; + if( GetKeyCode().IsShift() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::SHIFT; + if( GetKeyCode().IsMod1() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD1; + if( GetKeyCode().IsMod2() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD2; + if( GetKeyCode().IsMod3() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD3; + + rEvent.KeyCode = GetKeyCode().GetCode(); + rEvent.KeyChar = GetCharCode(); + rEvent.KeyFunc = sal::static_int_cast< sal_Int16 >(GetKeyCode().GetFunction()); +} + +KeyEvent KeyEvent::LogicalTextDirectionality (TextDirectionality eMode) const +{ + KeyEvent aClone(*this); + + USHORT nCode = maKeyCode.GetCode(); + USHORT nMod = maKeyCode.GetAllModifier(); + + switch (eMode) + { + case TextDirectionality_RightToLeft_TopToBottom: + switch (nCode) + { + case KEY_LEFT: aClone.maKeyCode = KeyCode(KEY_RIGHT, nMod); break; + case KEY_RIGHT: aClone.maKeyCode = KeyCode(KEY_LEFT, nMod); break; + } + break; + + case TextDirectionality_TopToBottom_RightToLeft: + switch (nCode) + { + case KEY_DOWN: aClone.maKeyCode = KeyCode(KEY_RIGHT, nMod); break; + case KEY_UP: aClone.maKeyCode = KeyCode(KEY_LEFT, nMod); break; + case KEY_LEFT: aClone.maKeyCode = KeyCode(KEY_DOWN, nMod); break; + case KEY_RIGHT: aClone.maKeyCode = KeyCode(KEY_UP, nMod); break; + } + break; + + case TextDirectionality_LeftToRight_TopToBottom: + /* do nothing */ + break; + } + + return aClone; +} + + +// ------------------------------------------------------- + +const Point& HelpEvent::GetMousePosPixel() const +{ + //DBG_ASSERT( !mbKeyboardActivated, "Keyboard help has no mouse position !"); + return maPos; +} + diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk new file mode 100644 index 000000000000..1c63376dfda5 --- /dev/null +++ b/vcl/source/window/makefile.mk @@ -0,0 +1,106 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=vcl +TARGET=win +ENABLE_EXCEPTIONS=TRUE + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/arrange.obj \ + $(SLO)$/abstdlg.obj \ + $(SLO)$/accel.obj \ + $(SLO)$/accmgr.obj \ + $(SLO)$/brdwin.obj \ + $(SLO)$/btndlg.obj \ + $(SLO)$/cmdevt.obj \ + $(SLO)$/cursor.obj \ + $(SLO)$/decoview.obj \ + $(SLO)$/dialog.obj \ + $(SLO)$/dlgctrl.obj \ + $(SLO)$/dndevdis.obj \ + $(SLO)$/dndlcon.obj \ + $(SLO)$/dockingarea.obj \ + $(SLO)$/dockmgr.obj \ + $(SLO)$/dockwin.obj \ + $(SLO)$/floatwin.obj \ + $(SLO)$/introwin.obj \ + $(SLO)$/keycod.obj \ + $(SLO)$/keyevent.obj \ + $(SLO)$/mouseevent.obj \ + $(SLO)$/menu.obj \ + $(SLO)$/mnemonic.obj \ + $(SLO)$/mnemonicengine.obj \ + $(SLO)$/msgbox.obj \ + $(SLO)$/popupmenuwindow.obj \ + $(SLO)$/scrwnd.obj \ + $(SLO)$/printdlg.obj \ + $(SLO)$/seleng.obj \ + $(SLO)$/split.obj \ + $(SLO)$/splitwin.obj \ + $(SLO)$/status.obj \ + $(SLO)$/syschild.obj \ + $(SLO)$/javachild.obj \ + $(SLO)$/syswin.obj \ + $(SLO)$/tabdlg.obj \ + $(SLO)$/tabpage.obj \ + $(SLO)$/taskpanelist.obj \ + $(SLO)$/toolbox.obj \ + $(SLO)$/toolbox2.obj \ + $(SLO)$/window.obj \ + $(SLO)$/winproc.obj \ + $(SLO)$/window2.obj \ + $(SLO)$/window3.obj \ + $(SLO)$/window4.obj \ + $(SLO)$/wpropset.obj \ + $(SLO)$/wrkwin.obj + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +.INCLUDE : $(PRJ)$/util$/target.pmk + +$(INCCOM)$/cuilib.hxx: makefile.mk +.IF "$(GUI)"=="UNX" + @$(RM) $@ + @echo \#define DLL_NAME \"libcui$(DLLPOSTFIX)$(DLLPOST)\" >$@ +.ELSE + @echo $(EMQ)#define DLL_NAME $(EMQ)"cui$(DLLPOSTFIX)$(DLLPOST)$(EMQ)" >$@ +.ENDIF + +$(SLO)$/abstdlg.obj : $(INCCOM)$/cuilib.hxx diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx new file mode 100755 index 000000000000..5909ab9f8489 --- /dev/null +++ b/vcl/source/window/menu.cxx @@ -0,0 +1,6161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "svsys.h" +#include "vcl/salinst.hxx" +#include "tools/list.hxx" +#include "tools/debug.hxx" +#include "tools/diagnose_ex.h" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" +#include "vcl/mnemonic.hxx" +#include "vcl/image.hxx" +#include "vcl/event.hxx" +#include "vcl/help.hxx" +#include "vcl/svids.hrc" +#include "vcl/floatwin.hxx" +#include "vcl/wrkwin.hxx" +#include "vcl/timer.hxx" +#include "vcl/sound.hxx" +#include "vcl/decoview.hxx" +#include "vcl/bitmap.hxx" +#include "tools/rc.h" +#include "vcl/menu.hxx" +#include "vcl/button.hxx" +#include "vcl/gradient.hxx" +#include "vcl/i18nhelp.hxx" +#include "vcl/taskpanelist.hxx" +#include "vcl/window.h" +#include "vcl/controllayout.hxx" +#include "vcl/toolbox.hxx" +#include "tools/stream.hxx" +#include "vcl/salmenu.hxx" +#include "vcl/salframe.hxx" +#include "vcl/dockingarea.hxx" + + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/i18n/XCharacterClassification.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <vcl/unowrap.hxx> + +#include <vcl/unohelp.hxx> +#include <vcl/configsettings.hxx> + +#include "vcl/lazydelete.hxx" + +#include <map> + +namespace vcl +{ + +struct MenuLayoutData : public ControlLayoutData +{ + std::vector< USHORT > m_aLineItemIds; + std::vector< USHORT > m_aLineItemPositions; + std::map< USHORT, Rectangle > m_aVisibleItemBoundRects; +}; + +} + +using namespace ::com::sun::star; +using namespace vcl; + +DBG_NAME( Menu ) + +#define ITEMPOS_INVALID 0xFFFF + +#define EXTRASPACEY 2 +#define EXTRAITEMHEIGHT 4 +#define GUTTERBORDER 8 + +// document closer +#define IID_DOCUMENTCLOSE 1 + +#ifdef OS2 + +#include <xwphook.h> + +// return TRUE if hilite should be executed: left mouse button down +// or xwp mouse hook enabled +static BOOL ImplHilite( const MouseEvent& rMEvt ) +{ + static BOOL init = FALSE; + static HOOKCONFIG hc; + + // read XWP settings at program startup + if (init == FALSE) { + BOOL rc; + ULONG cb = sizeof(HOOKCONFIG); + memset(&hc, 0, sizeof(HOOKCONFIG)); + rc = PrfQueryProfileData( HINI_USER, INIAPP_XWPHOOK, INIKEY_HOOK_CONFIG, + &hc, &cb); + init = TRUE; + } + // check mouse left button + if (rMEvt.GetButtons() == MOUSE_LEFT) + return TRUE; + // return xwp flag + return hc.fSlidingMenus; +} + +#endif + +static BOOL ImplAccelDisabled() +{ + // display of accelerator strings may be suppressed via configuration + static int nAccelDisabled = -1; + + if( nAccelDisabled == -1 ) + { + rtl::OUString aStr = + vcl::SettingsConfigItem::get()-> + getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Menu" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SuppressAccelerators" ) ) ); + nAccelDisabled = aStr.equalsIgnoreAsciiCaseAscii( "true" ) ? 1 : 0; + } + return (nAccelDisabled == 1) ? TRUE : FALSE; +} + +struct MenuItemData +{ + USHORT nId; // SV Id + MenuItemType eType; // MenuItem-Type + MenuItemBits nBits; // MenuItem-Bits + Menu* pSubMenu; // Pointer auf das SubMenu + Menu* pAutoSubMenu; // Pointer auf SubMenu aus Resource + XubString aText; // Menu-Text + XubString aHelpText; // Help-String + XubString aTipHelpText; // TipHelp-String (eg, expanded filenames) + XubString aCommandStr; // CommandString + XubString aHelpCommandStr; // Help command string (to reference external help) + rtl::OString aHelpId; // Help-Id + ULONG nUserValue; // User value + Image aImage; // Image + KeyCode aAccelKey; // Accelerator-Key + BOOL bChecked; // Checked + BOOL bEnabled; // Enabled + BOOL bVisible; // Visible (note: this flag will not override MENU_FLAG_HIDEDISABLEDENTRIES when true) + BOOL bIsTemporary; // Temporary inserted ('No selection possible') + BOOL bMirrorMode; + long nItemImageAngle; + Size aSz; // nur temporaer gueltig + XubString aAccessibleName; // accessible name + XubString aAccessibleDescription; // accessible description + + SalMenuItem* pSalMenuItem; // access to native menu + + MenuItemData() : + pSalMenuItem ( NULL ) + {} + MenuItemData( const XubString& rStr, const Image& rImage ) : + aText( rStr ), + aImage( rImage ), + pSalMenuItem ( NULL ) + {} + ~MenuItemData(); + bool HasCheck() + { + return bChecked || ( nBits & ( MIB_RADIOCHECK | MIB_CHECKABLE | MIB_AUTOCHECK ) ); + } +}; + +MenuItemData::~MenuItemData() +{ + if( pAutoSubMenu ) + { + ((PopupMenu*)pAutoSubMenu)->pRefAutoSubMenu = NULL; + delete pAutoSubMenu; + pAutoSubMenu = NULL; + } + if( pSalMenuItem ) + ImplGetSVData()->mpDefInst->DestroyMenuItem( pSalMenuItem ); +} + +class MenuItemList : public List +{ +private: + uno::Reference< i18n::XCharacterClassification > xCharClass; + + +public: + MenuItemList() : List( 16, 4 ) {} + ~MenuItemList(); + + MenuItemData* Insert( USHORT nId, MenuItemType eType, MenuItemBits nBits, + const XubString& rStr, const Image& rImage, + Menu* pMenu, USHORT nPos ); + void InsertSeparator( USHORT nPos ); + void Remove( USHORT nPos ); + + + MenuItemData* GetData( USHORT nSVId, USHORT& rPos ) const; + MenuItemData* GetData( USHORT nSVId ) const + { USHORT nTemp; return GetData( nSVId, nTemp ); } + MenuItemData* GetDataFromPos( ULONG nPos ) const + { return (MenuItemData*)List::GetObject( nPos ); } + + MenuItemData* SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const; + USHORT GetItemCount( xub_Unicode cSelectChar ) const; + USHORT GetItemCount( KeyCode aKeyCode ) const; + + uno::Reference< i18n::XCharacterClassification > GetCharClass() const; +}; + + + +MenuItemList::~MenuItemList() +{ + for ( ULONG n = Count(); n; ) + { + MenuItemData* pData = GetDataFromPos( --n ); + delete pData; + } +} + +MenuItemData* MenuItemList::Insert( USHORT nId, MenuItemType eType, + MenuItemBits nBits, + const XubString& rStr, const Image& rImage, + Menu* pMenu, USHORT nPos ) +{ + MenuItemData* pData = new MenuItemData( rStr, rImage ); + pData->nId = nId; + pData->eType = eType; + pData->nBits = nBits; + pData->pSubMenu = NULL; + pData->pAutoSubMenu = NULL; + pData->nUserValue = 0; + pData->bChecked = FALSE; + pData->bEnabled = TRUE; + pData->bVisible = TRUE; + pData->bIsTemporary = FALSE; + pData->bMirrorMode = FALSE; + pData->nItemImageAngle = 0; + + SalItemParams aSalMIData; + aSalMIData.nId = nId; + aSalMIData.eType = eType; + aSalMIData.nBits = nBits; + aSalMIData.pMenu = pMenu; + aSalMIData.aText = rStr; + aSalMIData.aImage = rImage; + + // Native-support: returns NULL if not supported + pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData ); + + List::Insert( (void*)pData, nPos ); + return pData; +} + +void MenuItemList::InsertSeparator( USHORT nPos ) +{ + MenuItemData* pData = new MenuItemData; + pData->nId = 0; + pData->eType = MENUITEM_SEPARATOR; + pData->nBits = 0; + pData->pSubMenu = NULL; + pData->pAutoSubMenu = NULL; + pData->nUserValue = 0; + pData->bChecked = FALSE; + pData->bEnabled = TRUE; + pData->bVisible = TRUE; + pData->bIsTemporary = FALSE; + pData->bMirrorMode = FALSE; + pData->nItemImageAngle = 0; + + SalItemParams aSalMIData; + aSalMIData.nId = 0; + aSalMIData.eType = MENUITEM_SEPARATOR; + aSalMIData.nBits = 0; + aSalMIData.pMenu = NULL; + aSalMIData.aText = XubString(); + aSalMIData.aImage = Image(); + + // Native-support: returns NULL if not supported + pData->pSalMenuItem = ImplGetSVData()->mpDefInst->CreateMenuItem( &aSalMIData ); + + List::Insert( (void*)pData, nPos ); +} + +void MenuItemList::Remove( USHORT nPos ) +{ + MenuItemData* pData = (MenuItemData*)List::Remove( (ULONG)nPos ); + if ( pData ) + delete pData; +} + +MenuItemData* MenuItemList::GetData( USHORT nSVId, USHORT& rPos ) const +{ + rPos = 0; + MenuItemData* pData = (MenuItemData*)GetObject( rPos ); + while ( pData ) + { + if ( pData->nId == nSVId ) + return pData; + + rPos++; + pData = (MenuItemData*)GetObject( rPos ); + } + + return NULL; +} + +MenuItemData* MenuItemList::SearchItem( xub_Unicode cSelectChar, KeyCode aKeyCode, USHORT& rPos, USHORT& nDuplicates, USHORT nCurrentPos ) const +{ + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + + USHORT nListCount = (USHORT)Count(); + + // try character code first + nDuplicates = GetItemCount( cSelectChar ); // return number of duplicates + if( nDuplicates ) + { + for ( rPos = 0; rPos < nListCount; rPos++) + { + MenuItemData* pData = GetDataFromPos( rPos ); + if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) ) + { + if( nDuplicates > 1 && rPos == nCurrentPos ) + continue; // select next entry with the same mnemonic + else + return pData; + } + } + } + + // nothing found, try keycode instead + nDuplicates = GetItemCount( aKeyCode ); // return number of duplicates + + if( nDuplicates ) + { + char ascii = 0; + if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z ) + ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A)); + + for ( rPos = 0; rPos < nListCount; rPos++) + { + MenuItemData* pData = GetDataFromPos( rPos ); + if ( pData->bEnabled ) + { + USHORT n = pData->aText.Search( '~' ); + if ( n != STRING_NOTFOUND ) + { + KeyCode mnKeyCode; + xub_Unicode mnUnicode = pData->aText.GetChar(n+1); + Window* pDefWindow = ImplGetDefaultWindow(); + if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( mnUnicode, Application::GetSettings().GetUILanguage(), mnKeyCode ) + && aKeyCode.GetCode() == mnKeyCode.GetCode()) + || (ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) ) + + { + if( nDuplicates > 1 && rPos == nCurrentPos ) + continue; // select next entry with the same mnemonic + else + return pData; + } + } + } + } + } + + return NULL; +} + +USHORT MenuItemList::GetItemCount( xub_Unicode cSelectChar ) const +{ + // returns number of entries with same mnemonic + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + + USHORT nItems = 0, nPos; + for ( nPos = (USHORT)Count(); nPos; ) + { + MenuItemData* pData = GetDataFromPos( --nPos ); + if ( pData->bEnabled && rI18nHelper.MatchMnemonic( pData->aText, cSelectChar ) ) + nItems++; + } + + return nItems; +} + +USHORT MenuItemList::GetItemCount( KeyCode aKeyCode ) const +{ + // returns number of entries with same mnemonic + // uses key codes instead of character codes + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + char ascii = 0; + if( aKeyCode.GetCode() >= KEY_A && aKeyCode.GetCode() <= KEY_Z ) + ascii = sal::static_int_cast<char>('A' + (aKeyCode.GetCode() - KEY_A)); + + USHORT nItems = 0, nPos; + for ( nPos = (USHORT)Count(); nPos; ) + { + MenuItemData* pData = GetDataFromPos( --nPos ); + if ( pData->bEnabled ) + { + USHORT n = pData->aText.Search( '~' ); + if ( n != STRING_NOTFOUND ) + { + KeyCode mnKeyCode; + // if MapUnicodeToKeyCode fails or is unsupported we try the pure ascii mapping of the keycodes + // so we have working shortcuts when ascii mnemonics are used + Window* pDefWindow = ImplGetDefaultWindow(); + if( (pDefWindow && pDefWindow->ImplGetFrame()->MapUnicodeToKeyCode( pData->aText.GetChar(n+1), Application::GetSettings().GetUILanguage(), mnKeyCode ) + && aKeyCode.GetCode() == mnKeyCode.GetCode()) + || ( ascii && rI18nHelper.MatchMnemonic( pData->aText, ascii ) ) ) + nItems++; + } + } + } + + return nItems; +} + +uno::Reference< i18n::XCharacterClassification > MenuItemList::GetCharClass() const +{ + if ( !xCharClass.is() ) + ((MenuItemList*)this)->xCharClass = vcl::unohelper::CreateCharacterClassification(); + return xCharClass; +} + + + +// ---------------------- +// - MenuFloatingWindow - +// ---------------------- + +class MenuFloatingWindow : public FloatingWindow +{ + friend void Menu::ImplFillLayoutData() const; + friend Menu::~Menu(); + +private: + Menu* pMenu; + PopupMenu* pActivePopup; + Timer aHighlightChangedTimer; + Timer aSubmenuCloseTimer; + Timer aScrollTimer; + ULONG nSaveFocusId; +// long nStartY; + USHORT nHighlightedItem; // gehighlightetes/selektiertes Item + USHORT nMBDownPos; + USHORT nScrollerHeight; + USHORT nFirstEntry; + USHORT nBorder; + USHORT nPosInParent; + BOOL bInExecute; + + BOOL bScrollMenu; + BOOL bScrollUp; + BOOL bScrollDown; + BOOL bIgnoreFirstMove; + BOOL bKeyInput; + + DECL_LINK( PopupEnd, FloatingWindow* ); + DECL_LINK( HighlightChanged, Timer* ); + DECL_LINK( SubmenuClose, Timer* ); + DECL_LINK( AutoScroll, Timer* ); + DECL_LINK( ShowHideListener, VclWindowEvent* ); + + void StateChanged( StateChangedType nType ); + void DataChanged( const DataChangedEvent& rDCEvt ); +protected: + Region ImplCalcClipRegion( BOOL bIncludeLogo = TRUE ) const; + void ImplInitClipRegion(); + void ImplDrawScroller( BOOL bUp ); + using Window::ImplScroll; + void ImplScroll( const Point& rMousePos ); + void ImplScroll( BOOL bUp ); + void ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd = FALSE ); + void ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown ); + long ImplGetStartY() const; + Rectangle ImplGetItemRect( USHORT nPos ); + +public: + MenuFloatingWindow( Menu* pMenu, Window* pParent, WinBits nStyle ); + ~MenuFloatingWindow(); + + void doShutdown(); + + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); + virtual void KeyInput( const KeyEvent& rKEvent ); + virtual void Command( const CommandEvent& rCEvt ); + virtual void Paint( const Rectangle& rRect ); + virtual void RequestHelp( const HelpEvent& rHEvt ); + virtual void Resize(); + + void SetFocusId( ULONG nId ) { nSaveFocusId = nId; } + ULONG GetFocusId() const { return nSaveFocusId; } + + void EnableScrollMenu( BOOL b ); + BOOL IsScrollMenu() const { return bScrollMenu; } + USHORT GetScrollerHeight() const { return nScrollerHeight; } + + void Execute(); + void StopExecute( ULONG nFocusId = 0 ); + void EndExecute(); + void EndExecute( USHORT nSelectId ); + + PopupMenu* GetActivePopup() const { return pActivePopup; } + void KillActivePopup( PopupMenu* pThisOnly = NULL ); + + void HighlightItem( USHORT nPos, BOOL bHighlight ); + void ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer ); + USHORT GetHighlightedItem() const { return nHighlightedItem; } + + void SetPosInParent( USHORT nPos ) { nPosInParent = nPos; } + USHORT GetPosInParent() const { return nPosInParent; } + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); +}; + +// To get the transparent mouse-over look, the closer is actually a toolbox +// overload DataChange to handle style changes correctly +class DecoToolBox : public ToolBox +{ + long lastSize; + Size maMinSize; + + using Window::ImplInit; +public: + DecoToolBox( Window* pParent, WinBits nStyle = 0 ); + DecoToolBox( Window* pParent, const ResId& rResId ); + void ImplInit(); + + void DataChanged( const DataChangedEvent& rDCEvt ); + + void SetImages( long nMaxHeight = 0, bool bForce = false ); + + void calcMinSize(); + Size getMinSize(); + + Image maImage; + Image maImageHC; +}; + +DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) : + ToolBox( pParent, nStyle ) +{ + ImplInit(); +} +DecoToolBox::DecoToolBox( Window* pParent, const ResId& rResId ) : + ToolBox( pParent, rResId ) +{ + ImplInit(); +} + +void DecoToolBox::ImplInit() +{ + lastSize = -1; + calcMinSize(); +} + +void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( rDCEvt.GetFlags() & SETTINGS_STYLE ) + { + calcMinSize(); + SetBackground(); + SetImages( 0, true); + } +} + +void DecoToolBox::calcMinSize() +{ + ToolBox aTbx( GetParent() ); + if( GetItemCount() == 0 ) + { + ResMgr* pResMgr = ImplGetResMgr(); + + Bitmap aBitmap; + if( pResMgr ) + aBitmap = Bitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) ); + aTbx.InsertItem( IID_DOCUMENTCLOSE, Image( aBitmap ) ); + } + else + { + USHORT nItems = GetItemCount(); + for( USHORT i = 0; i < nItems; i++ ) + { + USHORT nId = GetItemId( i ); + aTbx.InsertItem( nId, GetItemImage( nId ) ); + } + } + aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT ); + maMinSize = aTbx.CalcWindowSizePixel(); +} + +Size DecoToolBox::getMinSize() +{ + return maMinSize; +} + +void DecoToolBox::SetImages( long nMaxHeight, bool bForce ) +{ + long border = getMinSize().Height() - maImage.GetSizePixel().Height(); + + if( !nMaxHeight && lastSize != -1 ) + nMaxHeight = lastSize + border; // don't change anything if called with 0 + + if( nMaxHeight < getMinSize().Height() ) + nMaxHeight = getMinSize().Height(); + + if( (lastSize != nMaxHeight - border) || bForce ) + { + lastSize = nMaxHeight - border; + + Color aEraseColor( 255, 255, 255, 255 ); + BitmapEx aBmpExDst( maImage.GetBitmapEx() ); + BitmapEx aBmpExSrc( GetSettings().GetStyleSettings().GetHighContrastMode() ? + maImageHC.GetBitmapEx() : aBmpExDst ); + + aEraseColor.SetTransparency( 255 ); + aBmpExDst.Erase( aEraseColor ); + aBmpExDst.SetSizePixel( Size( lastSize, lastSize ) ); + + Rectangle aSrcRect( Point(0,0), maImage.GetSizePixel() ); + Rectangle aDestRect( Point((lastSize - maImage.GetSizePixel().Width())/2, + (lastSize - maImage.GetSizePixel().Height())/2 ), + maImage.GetSizePixel() ); + + + aBmpExDst.CopyPixel( aDestRect, aSrcRect, &aBmpExSrc ); + SetItemImage( IID_DOCUMENTCLOSE, Image( aBmpExDst ) ); + } +} + + +// Eine Basicklasse fuer beide (wegen pActivePopup, Timer, ...) waere nett, +// aber dann musste eine 'Container'-Klasse gemacht werden, da von +// unterschiedlichen Windows abgeleitet... +// In den meisten Funktionen muessen dann sowieso Sonderbehandlungen fuer +// MenuBar, PopupMenu gemacht werden, also doch zwei verschiedene Klassen. + +class MenuBarWindow : public Window +{ + friend class MenuBar; + friend class Menu; + +private: + struct AddButtonEntry + { + USHORT m_nId; + Link m_aSelectLink; + Link m_aHighlightLink; + + AddButtonEntry() : m_nId( 0 ) {} + }; + + Menu* pMenu; + PopupMenu* pActivePopup; + USHORT nHighlightedItem; + ULONG nSaveFocusId; + BOOL mbAutoPopup; + BOOL bIgnoreFirstMove; + BOOL bStayActive; + + DecoToolBox aCloser; + PushButton aFloatBtn; + PushButton aHideBtn; + + std::map< USHORT, AddButtonEntry > m_aAddButtons; + + void HighlightItem( USHORT nPos, BOOL bHighlight ); + void ChangeHighlightItem( USHORT n, BOOL bSelectPopupEntry, BOOL bAllowRestoreFocus = TRUE, BOOL bDefaultToDocument = TRUE ); + + USHORT ImplFindEntry( const Point& rMousePos ) const; + void ImplCreatePopup( BOOL bPreSelectFirst ); + BOOL ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu = TRUE ); + Rectangle ImplGetItemRect( USHORT nPos ); + + void ImplInitStyleSettings(); + + DECL_LINK( CloserHdl, PushButton* ); + DECL_LINK( FloatHdl, PushButton* ); + DECL_LINK( HideHdl, PushButton* ); + DECL_LINK( ToolboxEventHdl, VclWindowEvent* ); + DECL_LINK( ShowHideListener, VclWindowEvent* ); + + void StateChanged( StateChangedType nType ); + void DataChanged( const DataChangedEvent& rDCEvt ); + void LoseFocus(); + void GetFocus(); + +public: + MenuBarWindow( Window* pParent ); + ~MenuBarWindow(); + + void ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide ); + + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonDown( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); + virtual void KeyInput( const KeyEvent& rKEvent ); + virtual void Paint( const Rectangle& rRect ); + virtual void Resize(); + virtual void RequestHelp( const HelpEvent& rHEvt ); + + void SetFocusId( ULONG nId ) { nSaveFocusId = nId; } + ULONG GetFocusId() const { return nSaveFocusId; } + + void SetMenu( MenuBar* pMenu ); + void KillActivePopup(); + PopupMenu* GetActivePopup() const { return pActivePopup; } + void PopupClosed( Menu* pMenu ); + USHORT GetHighlightedItem() const { return nHighlightedItem; } + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > CreateAccessible(); + + void SetAutoPopup( BOOL bAuto ) { mbAutoPopup = bAuto; } + void ImplLayoutChanged(); + Size MinCloseButtonSize(); + + // add an arbitrary button to the menubar (will appear next to closer) + USHORT AddMenuBarButton( const Image&, const Link&, const String&, USHORT nPos ); + void SetMenuBarButtonHighlightHdl( USHORT nId, const Link& ); + Rectangle GetMenuBarButtonRectPixel( USHORT nId ); + void RemoveMenuBarButton( USHORT nId ); + bool HandleMenuButtonEvent( USHORT i_nButtonId ); +}; + +static void ImplAddNWFSeparator( Window *pThis, const MenubarValue& rMenubarValue ) +{ + // add a separator if + // - we have an adjacent docking area + // - and if toolbars would draw them as well (mbDockingAreaSeparateTB must not be set, see dockingarea.cxx) + if( rMenubarValue.maTopDockingAreaHeight && !ImplGetSVData()->maNWFData.mbDockingAreaSeparateTB ) + { + // note: the menubar only provides the upper (dark) half of it, the rest (bright part) is drawn by the docking area + + pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetSeparatorColor() ); + Point aPt; + Rectangle aRect( aPt, pThis->GetOutputSizePixel() ); + pThis->DrawLine( aRect.BottomLeft(), aRect.BottomRight() ); + } +} + +static void ImplSetMenuItemData( MenuItemData* pData ) +{ + // Daten umsetzen + if ( !pData->aImage ) + pData->eType = MENUITEM_STRING; + else if ( !pData->aText.Len() ) + pData->eType = MENUITEM_IMAGE; + else + pData->eType = MENUITEM_STRINGIMAGE; +} + +static ULONG ImplChangeTipTimeout( ULONG nTimeout, Window *pWindow ) +{ + AllSettings aAllSettings( pWindow->GetSettings() ); + HelpSettings aHelpSettings( aAllSettings.GetHelpSettings() ); + ULONG nRet = aHelpSettings.GetTipTimeout(); + aHelpSettings.SetTipTimeout( nTimeout ); + aAllSettings.SetHelpSettings( aHelpSettings ); + pWindow->SetSettings( aAllSettings ); + return nRet; +} + +static BOOL ImplHandleHelpEvent( Window* pMenuWindow, Menu* pMenu, USHORT nHighlightedItem, const HelpEvent& rHEvt, const Rectangle &rHighlightRect ) +{ + if( ! pMenu ) + return FALSE; + + BOOL bDone = FALSE; + USHORT nId = 0; + + if ( nHighlightedItem != ITEMPOS_INVALID ) + { + MenuItemData* pItemData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ); + if ( pItemData ) + nId = pItemData->nId; + } + + if ( ( rHEvt.GetMode() & HELPMODE_BALLOON ) && pMenuWindow ) + { + Point aPos; + if( rHEvt.KeyboardActivated() ) + aPos = rHighlightRect.Center(); + else + aPos = rHEvt.GetMousePosPixel(); + + Rectangle aRect( aPos, Size() ); + if( pMenu->GetHelpText( nId ).Len() ) + Help::ShowBalloon( pMenuWindow, aPos, pMenu->GetHelpText( nId ) ); + else + { + // give user a chance to read the full filename + ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow ); + // call always, even when strlen==0 to correctly remove tip + Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) ); + ImplChangeTipTimeout( oldTimeout, pMenuWindow ); + } + bDone = TRUE; + } + else if ( ( rHEvt.GetMode() & HELPMODE_QUICK ) && pMenuWindow ) + { + Point aPos = rHEvt.GetMousePosPixel(); + Rectangle aRect( aPos, Size() ); + // give user a chance to read the full filename + ULONG oldTimeout=ImplChangeTipTimeout( 60000, pMenuWindow ); + // call always, even when strlen==0 to correctly remove tip + Help::ShowQuickHelp( pMenuWindow, aRect, pMenu->GetTipHelpText( nId ) ); + ImplChangeTipTimeout( oldTimeout, pMenuWindow ); + bDone = TRUE; + } + else if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) + { + // Ist eine Hilfe in die Applikation selektiert + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + // Ist eine ID vorhanden, dann Hilfe mit der ID aufrufen, sonst + // den Hilfe-Index + String aCommand = pMenu->GetItemCommand( nId ); + rtl::OString aHelpId( pMenu->GetHelpId( nId ) ); + if( ! aHelpId.getLength() ) + aHelpId = OOO_HELP_INDEX; + + if ( aCommand.Len() ) + pHelp->Start( aCommand, NULL ); + else + pHelp->Start( rtl::OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), NULL ); + } + bDone = TRUE; + } + return bDone; +} + +static int ImplGetTopDockingAreaHeight( Window *pWindow ) +{ + // find docking area that is top aligned and return its height + // note: dockingareas are direct children of the SystemWindow + int height=0; + BOOL bDone = FALSE; + if( pWindow->ImplGetFrameWindow() ) + { + Window *pWin = pWindow->ImplGetFrameWindow()->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild; + while( pWin && !bDone ) + { + if( pWin->IsSystemWindow() ) + { + pWin = pWin->GetWindow( WINDOW_FIRSTCHILD); //mpWindowImpl->mpFirstChild; + while( pWin && !bDone ) + { + DockingAreaWindow *pDockingArea = dynamic_cast< DockingAreaWindow* >( pWin ); + if( pDockingArea && pDockingArea->GetAlign() == WINDOWALIGN_TOP ) + { + bDone = TRUE; + if( pDockingArea->IsVisible() ) + height = pDockingArea->GetOutputSizePixel().Height(); + } + else + pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext; + } + + } + else + pWin = pWin->GetWindow( WINDOW_NEXT ); //mpWindowImpl->mpNext; + } + } + return height; +} + +Menu::Menu() +{ + DBG_CTOR( Menu, NULL ); + bIsMenuBar = FALSE; + ImplInit(); +} + +// this constructor makes sure we're creating the native menu +// with the correct type (ie, MenuBar vs. PopupMenu) +Menu::Menu( BOOL bMenubar ) +{ + DBG_CTOR( Menu, NULL ); + bIsMenuBar = bMenubar; + ImplInit(); +} + +Menu::~Menu() +{ + DBG_DTOR( Menu, NULL ); + + vcl::LazyDeletor<Menu>::Undelete( this ); + + ImplCallEventListeners( VCLEVENT_OBJECT_DYING, ITEMPOS_INVALID ); + + // at the window free the reference to the accessible component + // and make sure the MenuFloatingWindow knows about our destruction + if ( pWindow ) + { + MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow; + if( pFloat->pMenu == this ) + pFloat->pMenu = NULL; + pWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() ); + } + + // dispose accessible components + if ( mxAccessible.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xComponent( mxAccessible, ::com::sun::star::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + } + + if ( nEventId ) + Application::RemoveUserEvent( nEventId ); + + // Notify deletion of this menu + ImplMenuDelData* pDelData = mpFirstDel; + while ( pDelData ) + { + pDelData->mpMenu = NULL; + pDelData = pDelData->mpNext; + } + + bKilled = TRUE; + + delete pItemList; + delete pLogo; + delete mpLayoutData; + + // Native-support: destroy SalMenu + ImplSetSalMenu( NULL ); +} + +void Menu::doLazyDelete() +{ + vcl::LazyDeletor<Menu>::Delete( this ); +} + +void Menu::ImplInit() +{ + mnHighlightedItemPos = ITEMPOS_INVALID; + mpSalMenu = NULL; + nMenuFlags = MENU_FLAG_SHOWCHECKIMAGES; + nDefaultItem = 0; + //bIsMenuBar = FALSE; // this is now set in the ctor, must not be changed here!!! + nSelectedId = 0; + pItemList = new MenuItemList; + pLogo = NULL; + pStartedFrom = NULL; + pWindow = NULL; + nEventId = 0; + bCanceled = FALSE; + bInCallback = FALSE; + bKilled = FALSE; + mpLayoutData = NULL; + mpFirstDel = NULL; // Dtor notification list + // Native-support: returns NULL if not supported + mpSalMenu = ImplGetSVData()->mpDefInst->CreateMenu( bIsMenuBar, this ); +} + +Menu* Menu::ImplGetStartedFrom() const +{ + return pStartedFrom; +} + +void Menu::ImplLoadRes( const ResId& rResId ) +{ + ResMgr* pMgr = rResId.GetResMgr(); + if( ! pMgr ) + return; + + rResId.SetRT( RSC_MENU ); + GetRes( rResId ); + + ULONG nObjMask = ReadLongRes(); + + if( nObjMask & RSC_MENU_ITEMS ) + { + ULONG nObjFollows = ReadLongRes(); + // MenuItems einfuegen + for( ULONG i = 0; i < nObjFollows; i++ ) + { + InsertItem( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + } + } + + if( nObjMask & RSC_MENU_TEXT ) + { + if( bIsMenuBar ) // Kein Titel im Menubar + ReadStringRes(); + else + aTitleText = ReadStringRes(); + } + if( nObjMask & RSC_MENU_DEFAULTITEMID ) + SetDefaultItem( sal::static_int_cast<USHORT>(ReadLongRes()) ); +} + +void Menu::CreateAutoMnemonics() +{ + MnemonicGenerator aMnemonicGenerator; + ULONG n; + for ( n = 0; n < pItemList->Count(); n++ ) + { + MenuItemData* pData = pItemList->GetDataFromPos(n); + if ( ! (pData->nBits & MIB_NOSELECT ) ) + aMnemonicGenerator.RegisterMnemonic( pData->aText ); + } + for ( n = 0; n < pItemList->Count(); n++ ) + { + MenuItemData* pData = pItemList->GetDataFromPos(n); + if ( ! (pData->nBits & MIB_NOSELECT ) ) + aMnemonicGenerator.CreateMnemonic( pData->aText ); + } +} + +void Menu::Activate() +{ + bInCallback = TRUE; + + ImplMenuDelData aDelData( this ); + + ImplCallEventListeners( VCLEVENT_MENU_ACTIVATE, ITEMPOS_INVALID ); + + if( !aDelData.isDeleted() ) + { + if ( !aActivateHdl.Call( this ) ) + { + if( !aDelData.isDeleted() ) + { + Menu* pStartMenu = ImplGetStartMenu(); + if ( pStartMenu && ( pStartMenu != this ) ) + { + pStartMenu->bInCallback = TRUE; + // MT 11/01: Call EventListener here? I don't know... + pStartMenu->aActivateHdl.Call( this ); + pStartMenu->bInCallback = FALSE; + } + } + } + bInCallback = FALSE; + } +} + +void Menu::Deactivate() +{ + for ( USHORT n = (USHORT)pItemList->Count(); n; ) + { + MenuItemData* pData = pItemList->GetDataFromPos( --n ); + if ( pData->bIsTemporary ) + pItemList->Remove( n ); + } + + bInCallback = TRUE; + + ImplMenuDelData aDelData( this ); + + Menu* pStartMenu = ImplGetStartMenu(); + ImplCallEventListeners( VCLEVENT_MENU_DEACTIVATE, ITEMPOS_INVALID ); + + if( !aDelData.isDeleted() ) + { + if ( !aDeactivateHdl.Call( this ) ) + { + if( !aDelData.isDeleted() ) + { + if ( pStartMenu && ( pStartMenu != this ) ) + { + pStartMenu->bInCallback = TRUE; + pStartMenu->aDeactivateHdl.Call( this ); + pStartMenu->bInCallback = FALSE; + } + } + } + } + + if( !aDelData.isDeleted() ) + { + bInCallback = FALSE; + + if ( this == pStartMenu ) + GetpApp()->HideHelpStatusText(); + } +} + +void Menu::Highlight() +{ + ImplMenuDelData aDelData( this ); + + Menu* pStartMenu = ImplGetStartMenu(); + if ( !aHighlightHdl.Call( this ) && !aDelData.isDeleted() ) + { + if ( pStartMenu && ( pStartMenu != this ) ) + pStartMenu->aHighlightHdl.Call( this ); + } + + if ( !aDelData.isDeleted() && GetCurItemId() ) + GetpApp()->ShowHelpStatusText( GetHelpText( GetCurItemId() ) ); +} + +void Menu::ImplSelect() +{ + MenuItemData* pData = GetItemList()->GetData( nSelectedId ); + if ( pData && (pData->nBits & MIB_AUTOCHECK) ) + { + BOOL bChecked = IsItemChecked( nSelectedId ); + if ( pData->nBits & MIB_RADIOCHECK ) + { + if ( !bChecked ) + CheckItem( nSelectedId, TRUE ); + } + else + CheckItem( nSelectedId, !bChecked ); + } + + // Select rufen + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mpActivePopupMenu = NULL; // Falls neues Execute im Select() + Application::PostUserEvent( nEventId, LINK( this, Menu, ImplCallSelect ) ); +} + +void Menu::Select() +{ + ImplMenuDelData aDelData( this ); + + ImplCallEventListeners( VCLEVENT_MENU_SELECT, GetItemPos( GetCurItemId() ) ); + if ( !aDelData.isDeleted() && !aSelectHdl.Call( this ) ) + { + if( !aDelData.isDeleted() ) + { + Menu* pStartMenu = ImplGetStartMenu(); + if ( pStartMenu && ( pStartMenu != this ) ) + { + pStartMenu->nSelectedId = nSelectedId; + pStartMenu->aSelectHdl.Call( this ); + } + } + } +} + +void Menu::ImplSelectWithStart( Menu* pSMenu ) +{ + Menu* pOldStartedFrom = pStartedFrom; + pStartedFrom = pSMenu; + Menu* pOldStartedStarted = pOldStartedFrom ? pOldStartedFrom->pStartedFrom : NULL; + Select(); + if( pOldStartedFrom ) + pOldStartedFrom->pStartedFrom = pOldStartedStarted; + pStartedFrom = pOldStartedFrom; +} + +void Menu::RequestHelp( const HelpEvent& ) +{ +} + +void Menu::ImplCallEventListeners( ULONG nEvent, USHORT nPos ) +{ + ImplMenuDelData aDelData( this ); + + VclMenuEvent aEvent( this, nEvent, nPos ); + + // This is needed by atk accessibility bridge + if ( nEvent == VCLEVENT_MENU_HIGHLIGHT ) + { + ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent ); + } + + if ( !aDelData.isDeleted() && !maEventListeners.empty() ) + maEventListeners.Call( &aEvent ); + + if( !aDelData.isDeleted() ) + { + Menu* pMenu = this; + while ( pMenu ) + { + if ( !maChildEventListeners.empty() ) + maChildEventListeners.Call( &aEvent ); + + if( aDelData.isDeleted() ) + break; + + pMenu = ( pMenu->pStartedFrom != pMenu ) ? pMenu->pStartedFrom : NULL; + } + } +} + +void Menu::AddEventListener( const Link& rEventListener ) +{ + maEventListeners.push_back( rEventListener ); +} + +void Menu::RemoveEventListener( const Link& rEventListener ) +{ + maEventListeners.remove( rEventListener ); +} + +// ----------------------------------------------------------------------- + +//void Menu::AddChildEventListener( const Link& rEventListener ) +//{ +// mpDummy4_WindowChildEventListeners->push_back( rEventListener ); +//} + +// ----------------------------------------------------------------------- + +//void Menu::RemoveChildEventListener( const Link& rEventListener ) +//{ +// mpDummy4_WindowChildEventListeners->remove( rEventListener ); +//} + +void Menu::InsertItem( USHORT nItemId, const XubString& rStr, MenuItemBits nItemBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "Menu::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == MENU_ITEM_NOTFOUND, + "Menu::InsertItem(): ItemId already exists" ); + + // if Position > ItemCount, append + if ( nPos >= (USHORT)pItemList->Count() ) + nPos = MENU_APPEND; + + // put Item in MenuItemList + MenuItemData* pData = pItemList->Insert( nItemId, MENUITEM_STRING, + nItemBits, rStr, Image(), this, nPos ); + + // update native menu + if( ImplGetSalMenu() && pData->pSalMenuItem ) + ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos ); + + Window* pWin = ImplGetWindow(); + delete mpLayoutData, mpLayoutData = NULL; + if ( pWin ) + { + ImplCalcSize( pWin ); + if ( pWin->IsVisible() ) + pWin->Invalidate(); + } + ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos ); +} + +void Menu::InsertItem( USHORT nItemId, const Image& rImage, + MenuItemBits nItemBits, USHORT nPos ) +{ + InsertItem( nItemId, ImplGetSVEmptyStr(), nItemBits, nPos ); + SetItemImage( nItemId, rImage ); +} + +void Menu::InsertItem( USHORT nItemId, + const XubString& rStr, const Image& rImage, + MenuItemBits nItemBits, USHORT nPos ) +{ + InsertItem( nItemId, rStr, nItemBits, nPos ); + SetItemImage( nItemId, rImage ); +} + +void Menu::InsertItem( const ResId& rResId, USHORT nPos ) +{ + ResMgr* pMgr = rResId.GetResMgr(); + if( ! pMgr ) + return; + + ULONG nObjMask; + + GetRes( rResId.SetRT( RSC_MENUITEM ) ); + nObjMask = ReadLongRes(); + + BOOL bSep = FALSE; + if ( nObjMask & RSC_MENUITEM_SEPARATOR ) + bSep = (BOOL)ReadShortRes(); + + USHORT nItemId = 1; + if ( nObjMask & RSC_MENUITEM_ID ) + nItemId = sal::static_int_cast<USHORT>(ReadLongRes()); + + MenuItemBits nStatus = 0; + if ( nObjMask & RSC_MENUITEM_STATUS ) + nStatus = sal::static_int_cast<MenuItemBits>(ReadLongRes()); + + String aText; + if ( nObjMask & RSC_MENUITEM_TEXT ) + aText = ReadStringRes(); + + // Item erzeugen + if ( nObjMask & RSC_MENUITEM_BITMAP ) + { + if ( !bSep ) + { + Bitmap aBmp( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ); + if ( aText.Len() ) + InsertItem( nItemId, aText, aBmp, nStatus, nPos ); + else + InsertItem( nItemId, aBmp, nStatus, nPos ); + } + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + } + else if ( !bSep ) + InsertItem( nItemId, aText, nStatus, nPos ); + if ( bSep ) + InsertSeparator( nPos ); + + String aHelpText; + if ( nObjMask & RSC_MENUITEM_HELPTEXT ) + { + aHelpText = ReadStringRes(); + if( !bSep ) + SetHelpText( nItemId, aHelpText ); + } + + if ( nObjMask & RSC_MENUITEM_HELPID ) + { + rtl::OString aHelpId( ReadByteStringRes() ); + if ( !bSep ) + SetHelpId( nItemId, aHelpId ); + } + + if( !bSep ) + SetHelpText( nItemId, aHelpText ); + + if ( nObjMask & RSC_MENUITEM_KEYCODE ) + { + if ( !bSep ) + SetAccelKey( nItemId, KeyCode( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + } + if( nObjMask & RSC_MENUITEM_CHECKED ) + { + if ( !bSep ) + CheckItem( nItemId, (BOOL)ReadShortRes() ); + } + if ( nObjMask & RSC_MENUITEM_DISABLE ) + { + if ( !bSep ) + EnableItem( nItemId, !(BOOL)ReadShortRes() ); + } + if ( nObjMask & RSC_MENUITEM_COMMAND ) + { + String aCommandStr = ReadStringRes(); + if ( !bSep ) + SetItemCommand( nItemId, aCommandStr ); + } + if ( nObjMask & RSC_MENUITEM_MENU ) + { + if ( !bSep ) + { + MenuItemData* pData = GetItemList()->GetData( nItemId ); + if ( pData ) + { + PopupMenu* pSubMenu = new PopupMenu( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ); + pData->pAutoSubMenu = pSubMenu; + // #111060# keep track of this pointer, may be it will be deleted from outside + pSubMenu->pRefAutoSubMenu = &pData->pAutoSubMenu; + SetPopupMenu( nItemId, pSubMenu ); + } + } + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + } + delete mpLayoutData, mpLayoutData = NULL; +} + +void Menu::InsertSeparator( USHORT nPos ) +{ + // do nothing if its a menu bar + if ( bIsMenuBar ) + return; + + // if position > ItemCount, append + if ( nPos >= (USHORT)pItemList->Count() ) + nPos = MENU_APPEND; + + // put separator in item list + pItemList->InsertSeparator( nPos ); + + // update native menu + USHORT itemPos = nPos != MENU_APPEND ? nPos : (USHORT)pItemList->Count() - 1; + MenuItemData *pData = pItemList->GetDataFromPos( itemPos ); + if( ImplGetSalMenu() && pData && pData->pSalMenuItem ) + ImplGetSalMenu()->InsertItem( pData->pSalMenuItem, nPos ); + + delete mpLayoutData, mpLayoutData = NULL; + + ImplCallEventListeners( VCLEVENT_MENU_INSERTITEM, nPos ); +} + +void Menu::RemoveItem( USHORT nPos ) +{ + BOOL bRemove = FALSE; + + if ( nPos < GetItemCount() ) + { + // update native menu + if( ImplGetSalMenu() ) + ImplGetSalMenu()->RemoveItem( nPos ); + + pItemList->Remove( nPos ); + bRemove = TRUE; + } + + Window* pWin = ImplGetWindow(); + if ( pWin ) + { + ImplCalcSize( pWin ); + if ( pWin->IsVisible() ) + pWin->Invalidate(); + } + delete mpLayoutData, mpLayoutData = NULL; + + if ( bRemove ) + ImplCallEventListeners( VCLEVENT_MENU_REMOVEITEM, nPos ); +} + +void ImplCopyItem( Menu* pThis, const Menu& rMenu, USHORT nPos, USHORT nNewPos, + USHORT nMode = 0 ) +{ + MenuItemType eType = rMenu.GetItemType( nPos ); + + if ( eType == MENUITEM_DONTKNOW ) + return; + + if ( eType == MENUITEM_SEPARATOR ) + pThis->InsertSeparator( nNewPos ); + else + { + USHORT nId = rMenu.GetItemId( nPos ); + + DBG_ASSERT( pThis->GetItemPos( nId ) == MENU_ITEM_NOTFOUND, + "Menu::CopyItem(): ItemId already exists" ); + + MenuItemData* pData = rMenu.GetItemList()->GetData( nId ); + + if ( eType == MENUITEM_STRINGIMAGE ) + pThis->InsertItem( nId, pData->aText, pData->aImage, pData->nBits, nNewPos ); + else if ( eType == MENUITEM_STRING ) + pThis->InsertItem( nId, pData->aText, pData->nBits, nNewPos ); + else + pThis->InsertItem( nId, pData->aImage, pData->nBits, nNewPos ); + + if ( rMenu.IsItemChecked( nId ) ) + pThis->CheckItem( nId, TRUE ); + if ( !rMenu.IsItemEnabled( nId ) ) + pThis->EnableItem( nId, FALSE ); + pThis->SetHelpId( nId, pData->aHelpId ); + pThis->SetHelpText( nId, pData->aHelpText ); + pThis->SetAccelKey( nId, pData->aAccelKey ); + pThis->SetItemCommand( nId, pData->aCommandStr ); + pThis->SetHelpCommand( nId, pData->aHelpCommandStr ); + + PopupMenu* pSubMenu = rMenu.GetPopupMenu( nId ); + if ( pSubMenu ) + { + // AutoKopie anlegen + if ( nMode == 1 ) + { + PopupMenu* pNewMenu = new PopupMenu( *pSubMenu ); + pThis->SetPopupMenu( nId, pNewMenu ); +// SetAutoMenu( pThis, nId, pNewMenu ); + } + else + pThis->SetPopupMenu( nId, pSubMenu ); + } + } +} + +void Menu::CopyItem( const Menu& rMenu, USHORT nPos, USHORT nNewPos ) +{ + ImplCopyItem( this, rMenu, nPos, nNewPos ); +} + +void Menu::Clear() +{ + for ( USHORT i = GetItemCount(); i; i-- ) + RemoveItem( 0 ); +} + +USHORT Menu::GetItemCount() const +{ + return (USHORT)pItemList->Count(); +} + +USHORT Menu::ImplGetVisibleItemCount() const +{ + USHORT nItems = 0; + for ( USHORT n = (USHORT)pItemList->Count(); n; ) + { + if ( ImplIsVisible( --n ) ) + nItems++; + } + return nItems; +} + +USHORT Menu::ImplGetFirstVisible() const +{ + for ( USHORT n = 0; n < pItemList->Count(); n++ ) + { + if ( ImplIsVisible( n ) ) + return n; + } + return ITEMPOS_INVALID; +} + +USHORT Menu::ImplGetPrevVisible( USHORT nPos ) const +{ + for ( USHORT n = nPos; n; ) + { + if ( n && ImplIsVisible( --n ) ) + return n; + } + return ITEMPOS_INVALID; +} + +USHORT Menu::ImplGetNextVisible( USHORT nPos ) const +{ + for ( USHORT n = nPos+1; n < pItemList->Count(); n++ ) + { + if ( ImplIsVisible( n ) ) + return n; + } + return ITEMPOS_INVALID; +} + +USHORT Menu::GetItemId( USHORT nPos ) const +{ + MenuItemData* pData = pItemList->GetDataFromPos( nPos ); + + if ( pData ) + return pData->nId; + else + return 0; +} + +USHORT Menu::GetItemPos( USHORT nItemId ) const +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( pData ) + return nPos; + else + return MENU_ITEM_NOTFOUND; +} + +MenuItemType Menu::GetItemType( USHORT nPos ) const +{ + MenuItemData* pData = pItemList->GetDataFromPos( nPos ); + + if ( pData ) + return pData->eType; + else + return MENUITEM_DONTKNOW; +} + +USHORT Menu::GetCurItemId() const +{ + return nSelectedId; +} + +void Menu::SetItemBits( USHORT nItemId, MenuItemBits nBits ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + if ( pData ) + pData->nBits = nBits; +} + +MenuItemBits Menu::GetItemBits( USHORT nItemId ) const +{ + MenuItemBits nBits = 0; + MenuItemData* pData = pItemList->GetData( nItemId ); + if ( pData ) + nBits = pData->nBits; + return nBits; +} + +void Menu::SetUserValue( USHORT nItemId, ULONG nValue ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + if ( pData ) + pData->nUserValue = nValue; +} + +ULONG Menu::GetUserValue( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + return pData ? pData->nUserValue : 0; +} + +void Menu::SetPopupMenu( USHORT nItemId, PopupMenu* pMenu ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + // Item does not exist -> return NULL + if ( !pData ) + return; + + // same menu, nothing to do + if ( (PopupMenu*)pData->pSubMenu == pMenu ) + return; + + // data exchange + pData->pSubMenu = pMenu; + + // #112023# Make sure pStartedFrom does not point to invalid (old) data + if ( pData->pSubMenu ) + pData->pSubMenu->pStartedFrom = 0; + + // set native submenu + if( ImplGetSalMenu() && pData->pSalMenuItem ) + { + if( pMenu ) + ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, pMenu->ImplGetSalMenu(), nPos ); + else + ImplGetSalMenu()->SetSubMenu( pData->pSalMenuItem, NULL, nPos ); + } + + ImplCallEventListeners( VCLEVENT_MENU_SUBMENUCHANGED, nPos ); +} + +PopupMenu* Menu::GetPopupMenu( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return (PopupMenu*)(pData->pSubMenu); + else + return NULL; +} + +void Menu::SetAccelKey( USHORT nItemId, const KeyCode& rKeyCode ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData ) + return; + + if ( pData->aAccelKey == rKeyCode ) + return; + + pData->aAccelKey = rKeyCode; + + // update native menu + if( ImplGetSalMenu() && pData->pSalMenuItem ) + ImplGetSalMenu()->SetAccelerator( nPos, pData->pSalMenuItem, rKeyCode, rKeyCode.GetName() ); +} + +KeyCode Menu::GetAccelKey( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aAccelKey; + else + return KeyCode(); +} + +KeyEvent Menu::GetActivationKey( USHORT nItemId ) const +{ + KeyEvent aRet; + MenuItemData* pData = pItemList->GetData( nItemId ); + if( pData ) + { + USHORT nPos = pData->aText.Search( '~' ); + if( nPos != STRING_NOTFOUND && nPos < pData->aText.Len()-1 ) + { + USHORT nCode = 0; + sal_Unicode cAccel = pData->aText.GetChar( nPos+1 ); + if( cAccel >= 'a' && cAccel <= 'z' ) + nCode = KEY_A + (cAccel-'a'); + else if( cAccel >= 'A' && cAccel <= 'Z' ) + nCode = KEY_A + (cAccel-'A'); + else if( cAccel >= '0' && cAccel <= '9' ) + nCode = KEY_0 + (cAccel-'0'); + if(nCode ) + aRet = KeyEvent( cAccel, KeyCode( nCode, KEY_MOD2 ) ); + } + + } + return aRet; +} + +void Menu::CheckItem( USHORT nItemId, BOOL bCheck ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData || pData->bChecked == bCheck ) + return; + + // Wenn RadioCheck, dann vorherigen unchecken + if ( bCheck && (pData->nBits & MIB_AUTOCHECK) && + (pData->nBits & MIB_RADIOCHECK) ) + { + MenuItemData* pGroupData; + USHORT nGroupPos; + USHORT nItemCount = GetItemCount(); + BOOL bFound = FALSE; + + nGroupPos = nPos; + while ( nGroupPos ) + { + pGroupData = pItemList->GetDataFromPos( nGroupPos-1 ); + if ( pGroupData->nBits & MIB_RADIOCHECK ) + { + if ( IsItemChecked( pGroupData->nId ) ) + { + CheckItem( pGroupData->nId, FALSE ); + bFound = TRUE; + break; + } + } + else + break; + nGroupPos--; + } + + if ( !bFound ) + { + nGroupPos = nPos+1; + while ( nGroupPos < nItemCount ) + { + pGroupData = pItemList->GetDataFromPos( nGroupPos ); + if ( pGroupData->nBits & MIB_RADIOCHECK ) + { + if ( IsItemChecked( pGroupData->nId ) ) + { + CheckItem( pGroupData->nId, FALSE ); + break; + } + } + else + break; + nGroupPos++; + } + } + } + + pData->bChecked = bCheck; + + // update native menu + if( ImplGetSalMenu() ) + ImplGetSalMenu()->CheckItem( nPos, bCheck ); + + ImplCallEventListeners( bCheck ? VCLEVENT_MENU_ITEMCHECKED : VCLEVENT_MENU_ITEMUNCHECKED, nPos ); +} + +BOOL Menu::IsItemChecked( USHORT nItemId ) const +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData ) + return FALSE; + + return pData->bChecked; +} + +void Menu::EnableItem( USHORT nItemId, BOOL bEnable ) +{ + USHORT nPos; + MenuItemData* pItemData = pItemList->GetData( nItemId, nPos ); + + if ( pItemData && ( pItemData->bEnabled != bEnable ) ) + { + pItemData->bEnabled = bEnable; + + Window* pWin = ImplGetWindow(); + if ( pWin && pWin->IsVisible() ) + { + DBG_ASSERT( bIsMenuBar, "Menu::EnableItem - Popup visible!" ); + long nX = 0; + ULONG nCount = pItemList->Count(); + for ( ULONG n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + pWin->Invalidate( Rectangle( Point( nX, 0 ), Size( pData->aSz.Width(), pData->aSz.Height() ) ) ); + break; + } + nX += pData->aSz.Width(); + } + } + // update native menu + if( ImplGetSalMenu() ) + ImplGetSalMenu()->EnableItem( nPos, bEnable ); + + ImplCallEventListeners( bEnable ? VCLEVENT_MENU_ENABLE : VCLEVENT_MENU_DISABLE, nPos ); + } +} + +BOOL Menu::IsItemEnabled( USHORT nItemId ) const +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData ) + return FALSE; + + return pData->bEnabled; +} + +void Menu::ShowItem( USHORT nItemId, BOOL bVisible ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + DBG_ASSERT( !bIsMenuBar, "Menu::ShowItem - ignored for menu bar entries!" ); + if ( !bIsMenuBar && pData && ( pData->bVisible != bVisible ) ) + { + Window* pWin = ImplGetWindow(); + if ( pWin && pWin->IsVisible() ) + { + DBG_ASSERT( 0, "Menu::ShowItem - ignored for visible popups!" ); + return; + } + pData->bVisible = bVisible; + + // update native menu + // as long as there is no support to hide native menu entries, we just disable them + // TODO: add support to show/hide native menu entries + if( ImplGetSalMenu() ) + ImplGetSalMenu()->EnableItem( nPos, bVisible ); + } +} + +void Menu::SetItemText( USHORT nItemId, const XubString& rStr ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData ) + return; + + if ( !rStr.Equals( pData->aText ) ) + { + pData->aText = rStr; + ImplSetMenuItemData( pData ); + // update native menu + if( ImplGetSalMenu() && pData->pSalMenuItem ) + ImplGetSalMenu()->SetItemText( nPos, pData->pSalMenuItem, rStr ); + + Window* pWin = ImplGetWindow(); + delete mpLayoutData, mpLayoutData = NULL; + if ( pWin && IsMenuBar() ) + { + ImplCalcSize( pWin ); + if ( pWin->IsVisible() ) + pWin->Invalidate(); + } + + ImplCallEventListeners( VCLEVENT_MENU_ITEMTEXTCHANGED, nPos ); + } +} + +XubString Menu::GetItemText( USHORT nItemId ) const +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( pData ) + return pData->aText; + else + return ImplGetSVEmptyStr(); +} + +void Menu::SetItemImage( USHORT nItemId, const Image& rImage ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( !pData ) + return; + + pData->aImage = rImage; + ImplSetMenuItemData( pData ); + + // update native menu + if( ImplGetSalMenu() && pData->pSalMenuItem ) + ImplGetSalMenu()->SetItemImage( nPos, pData->pSalMenuItem, rImage ); +} + +static inline Image ImplRotImage( const Image& rImage, long nAngle10 ) +{ + Image aRet; + BitmapEx aBmpEx( rImage.GetBitmapEx() ); + + aBmpEx.Rotate( nAngle10, COL_WHITE ); + + return Image( aBmpEx ); +} + +void Menu::SetItemImageAngle( USHORT nItemId, long nAngle10 ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( pData ) + { + long nDeltaAngle = (nAngle10 - pData->nItemImageAngle) % 3600; + while( nDeltaAngle < 0 ) + nDeltaAngle += 3600; + + pData->nItemImageAngle = nAngle10; + if( nDeltaAngle && !!pData->aImage ) + pData->aImage = ImplRotImage( pData->aImage, nDeltaAngle ); + } +} + +static inline Image ImplMirrorImage( const Image& rImage ) +{ + Image aRet; + BitmapEx aBmpEx( rImage.GetBitmapEx() ); + + aBmpEx.Mirror( BMP_MIRROR_HORZ ); + + return Image( aBmpEx ); +} + +void Menu::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( pData ) + { + if( ( pData->bMirrorMode && ! bMirror ) || + ( ! pData->bMirrorMode && bMirror ) + ) + { + pData->bMirrorMode = bMirror ? true : false; + if( !!pData->aImage ) + pData->aImage = ImplMirrorImage( pData->aImage ); + } + } +} + +Image Menu::GetItemImage( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aImage; + else + return Image(); +} + +long Menu::GetItemImageAngle( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->nItemImageAngle; + else + return 0; +} + +BOOL Menu::GetItemImageMirrorMode( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->bMirrorMode; + else + return FALSE; +} + +void Menu::SetItemCommand( USHORT nItemId, const String& rCommand ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aCommandStr = rCommand; +} + +const XubString& Menu::GetItemCommand( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aCommandStr; + else + return ImplGetSVEmptyStr(); +} + +void Menu::SetHelpCommand( USHORT nItemId, const XubString& rStr ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aHelpCommandStr = rStr; +} + +const XubString& Menu::GetHelpCommand( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aHelpCommandStr; + else + return ImplGetSVEmptyStr(); +} + +void Menu::SetHelpText( USHORT nItemId, const XubString& rStr ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aHelpText = rStr; +} + +const XubString& Menu::ImplGetHelpText( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + { + if ( !pData->aHelpText.Len() && + (( pData->aHelpId.getLength() ) || ( pData->aCommandStr.Len() ))) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if ( pData->aCommandStr.Len() ) + pData->aHelpText = pHelp->GetHelpText( pData->aCommandStr, NULL ); + + if( !pData->aHelpText.Len() && pData->aHelpId.getLength() ) + pData->aHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pData->aHelpId, RTL_TEXTENCODING_UTF8 ), NULL ); + } + } + + return pData->aHelpText; + } + else + return ImplGetSVEmptyStr(); +} + +const XubString& Menu::GetHelpText( USHORT nItemId ) const +{ + return ImplGetHelpText( nItemId ); +} + +void Menu::SetTipHelpText( USHORT nItemId, const XubString& rStr ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aTipHelpText = rStr; +} + +const XubString& Menu::GetTipHelpText( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aTipHelpText; + else + return ImplGetSVEmptyStr(); +} + +void Menu::SetHelpId( USHORT nItemId, const rtl::OString& rHelpId ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aHelpId = rHelpId; +} + +rtl::OString Menu::GetHelpId( USHORT nItemId ) const +{ + rtl::OString aRet; + + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + { + if ( pData->aHelpId.getLength() ) + aRet = pData->aHelpId; + else + aRet = ::rtl::OUStringToOString( pData->aCommandStr, RTL_TEXTENCODING_UTF8 ); + } + + return aRet; +} + +Menu& Menu::operator=( const Menu& rMenu ) +{ + // Aufraeumen + Clear(); + + // Items kopieren + USHORT nCount = rMenu.GetItemCount(); + for ( USHORT i = 0; i < nCount; i++ ) + ImplCopyItem( this, rMenu, i, MENU_APPEND, 1 ); + + nDefaultItem = rMenu.nDefaultItem; + aActivateHdl = rMenu.aActivateHdl; + aDeactivateHdl = rMenu.aDeactivateHdl; + aHighlightHdl = rMenu.aHighlightHdl; + aSelectHdl = rMenu.aSelectHdl; + aTitleText = rMenu.aTitleText; + bIsMenuBar = rMenu.bIsMenuBar; + + return *this; +} + +BOOL Menu::ImplIsVisible( USHORT nPos ) const +{ + BOOL bVisible = TRUE; + + MenuItemData* pData = pItemList->GetDataFromPos( nPos ); + // check general visibility first + if( pData && !pData->bVisible ) + bVisible = FALSE; + + if ( bVisible && pData && pData->eType == MENUITEM_SEPARATOR ) + { + if( nPos == 0 ) // no separator should be shown at the very beginning + bVisible = FALSE; + else + { + // always avoid adjacent separators + USHORT nCount = (USHORT) pItemList->Count(); + USHORT n; + MenuItemData* pNextData = NULL; + // search next visible item + for( n = nPos + 1; n < nCount; n++ ) + { + pNextData = pItemList->GetDataFromPos( n ); + if( pNextData && pNextData->bVisible ) + { + if( pNextData->eType == MENUITEM_SEPARATOR || ImplIsVisible(n) ) + break; + } + } + if( n == nCount ) // no next visible item + bVisible = FALSE; + // check for separator + if( pNextData && pNextData->bVisible && pNextData->eType == MENUITEM_SEPARATOR ) + bVisible = FALSE; + + if( bVisible ) + { + for( n = nPos; n > 0; n-- ) + { + pNextData = pItemList->GetDataFromPos( n-1 ); + if( pNextData && pNextData->bVisible ) + { + if( pNextData->eType != MENUITEM_SEPARATOR && ImplIsVisible(n-1) ) + break; + } + } + if( n == 0 ) // no previous visible item + bVisible = FALSE; + } + } + } + + // Fuer den Menubar nicht erlaubt, weil ich nicht mitbekomme + // ob dadurch ein Eintrag verschwindet oder wieder da ist. + if ( bVisible && !bIsMenuBar && ( nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) && + !( nMenuFlags & MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ) ) + { + if( !pData ) // e.g. nPos == ITEMPOS_INVALID + bVisible = FALSE; + else if ( pData->eType != MENUITEM_SEPARATOR ) // separators handled above + { + // bVisible = pData->bEnabled && ( !pData->pSubMenu || pData->pSubMenu->HasValidEntries( TRUE ) ); + bVisible = pData->bEnabled; // SubMenus nicht pruefen, weil sie ggf. erst im Activate() gefuellt werden. + } + } + + return bVisible; +} + +BOOL Menu::IsItemVisible( USHORT nItemId ) const +{ + return IsMenuVisible() && ImplIsVisible( GetItemPos( nItemId ) ); +} + +BOOL Menu::IsItemPosVisible( USHORT nItemPos ) const +{ + return IsMenuVisible() && ImplIsVisible( nItemPos ); +} + +BOOL Menu::IsMenuVisible() const +{ + return pWindow && pWindow->IsReallyVisible(); +} + +BOOL Menu::ImplIsSelectable( USHORT nPos ) const +{ + BOOL bSelectable = TRUE; + + MenuItemData* pData = pItemList->GetDataFromPos( nPos ); + // check general visibility first + if ( pData && ( pData->nBits & MIB_NOSELECT ) ) + bSelectable = FALSE; + + return bSelectable; +} + +void Menu::SelectItem( USHORT nItemId ) +{ + if( bIsMenuBar ) + static_cast<MenuBar*>(this)->SelectEntry( nItemId ); + else + static_cast<PopupMenu*>(this)->SelectEntry( nItemId ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Menu::GetAccessible() +{ + // Since PopupMenu are sometimes shared by different instances of MenuBar, the mxAccessible member gets + // overwritten and may contain a disposed object when the initial menubar gets set again. So use the + // mxAccessible member only for sub menus. + if ( pStartedFrom ) + { + for ( sal_uInt16 i = 0, nCount = pStartedFrom->GetItemCount(); i < nCount; ++i ) + { + sal_uInt16 nItemId = pStartedFrom->GetItemId( i ); + if ( static_cast< Menu* >( pStartedFrom->GetPopupMenu( nItemId ) ) == this ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xParent = pStartedFrom->GetAccessible(); + if ( xParent.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + if ( xParentContext.is() ) + return xParentContext->getAccessibleChild( i ); + } + } + } + } + else if ( !mxAccessible.is() ) + { + UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); + if ( pWrapper ) + mxAccessible = pWrapper->CreateAccessible( this, bIsMenuBar ); + } + + return mxAccessible; +} + +void Menu::SetAccessible( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& rxAccessible ) +{ + mxAccessible = rxAccessible; +} + +long Menu::ImplGetNativeCheckAndRadioSize( Window* pWin, long& rCheckHeight, long& rRadioHeight, long &rMaxWidth ) const +{ + rMaxWidth = rCheckHeight = rRadioHeight = 0; + + if( ! bIsMenuBar ) + { + ImplControlValue aVal; + Rectangle aNativeBounds; + Rectangle aNativeContent; + Point tmp( 0, 0 ); + Rectangle aCtrlRegion( Rectangle( tmp, Size( 100, 15 ) ) ); + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_CHECK_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_CHECK_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rCheckHeight = aNativeBounds.GetHeight(); + rMaxWidth = aNativeContent.GetWidth(); + } + } + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM_RADIO_MARK ) ) + { + if( pWin->GetNativeControlRegion( ControlType(CTRL_MENU_POPUP), + ControlPart(PART_MENU_ITEM_RADIO_MARK), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + rRadioHeight = aNativeBounds.GetHeight(); + rMaxWidth = Max (rMaxWidth, aNativeContent.GetWidth()); + } + } + } + return (rCheckHeight > rRadioHeight) ? rCheckHeight : rRadioHeight; +} + +// ----------------------------------------------------------------------- + +void Menu::ImplAddDel( ImplMenuDelData& rDel ) +{ + DBG_ASSERT( !rDel.mpMenu, "Menu::ImplAddDel(): cannot add ImplMenuDelData twice !" ); + if( !rDel.mpMenu ) + { + rDel.mpMenu = this; + rDel.mpNext = mpFirstDel; + mpFirstDel = &rDel; + } +} + +// ----------------------------------------------------------------------- + +void Menu::ImplRemoveDel( ImplMenuDelData& rDel ) +{ + rDel.mpMenu = NULL; + if ( mpFirstDel == &rDel ) + { + mpFirstDel = rDel.mpNext; + } + else + { + ImplMenuDelData* pData = mpFirstDel; + while ( pData && (pData->mpNext != &rDel) ) + pData = pData->mpNext; + + DBG_ASSERT( pData, "Menu::ImplRemoveDel(): ImplMenuDelData not registered !" ); + if( pData ) + pData->mpNext = rDel.mpNext; + } +} + +// ----------------------------------------------------------------------- + +Size Menu::ImplCalcSize( Window* pWin ) +{ + // | Checked| Image| Text| Accel/Popup| + + // Fuer Symbole: nFontHeight x nFontHeight + long nFontHeight = pWin->GetTextHeight(); + long nExtra = nFontHeight/4; + + + Size aSz; + Size aMaxImgSz; + long nMaxWidth = 0; + long nMinMenuItemHeight = nFontHeight; + long nCheckHeight = 0, nRadioHeight = 0; + long nCheckWidth = 0, nMaxCheckWidth = 0; + long nMax = ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth ); + if( nMax > nMinMenuItemHeight ) + nMinMenuItemHeight = nMax; + + const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings(); + if ( rSettings.GetUseImagesInMenus() ) + { + nMinMenuItemHeight = 16; + for ( USHORT i = (USHORT)pItemList->Count(); i; ) + { + MenuItemData* pData = pItemList->GetDataFromPos( --i ); + if ( ImplIsVisible( i ) && (( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ))) + { + Size aImgSz = pData->aImage.GetSizePixel(); + if ( aImgSz.Height() > aMaxImgSz.Height() ) + aMaxImgSz.Height() = aImgSz.Height(); + if ( aImgSz.Height() > nMinMenuItemHeight ) + nMinMenuItemHeight = aImgSz.Height(); + break; + } + } + } + + for ( USHORT n = (USHORT)pItemList->Count(); n; ) + { + MenuItemData* pData = pItemList->GetDataFromPos( --n ); + + pData->aSz.Height() = 0; + pData->aSz.Width() = 0; + + if ( ImplIsVisible( n ) ) + { + long nWidth = 0; + + // Separator + if ( !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) ) + { + DBG_ASSERT( !bIsMenuBar, "Separator in MenuBar ?! " ); + pData->aSz.Height() = 4; + } + + // Image: + if ( !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) ) + { + Size aImgSz = pData->aImage.GetSizePixel(); + aImgSz.Height() += 4; // add a border for native marks + aImgSz.Width() += 4; // add a border for native marks + if ( aImgSz.Width() > aMaxImgSz.Width() ) + aMaxImgSz.Width() = aImgSz.Width(); + if ( aImgSz.Height() > aMaxImgSz.Height() ) + aMaxImgSz.Height() = aImgSz.Height(); + if ( aImgSz.Height() > pData->aSz.Height() ) + pData->aSz.Height() = aImgSz.Height(); + } + + // Check Buttons: + if ( !bIsMenuBar && pData->HasCheck() ) + { + nCheckWidth = nMaxCheckWidth; + if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) + { + // checks / images take the same place + if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) ) + nWidth += nCheckWidth + nExtra * 2; + } + } + + // Text: + if ( (pData->eType == MENUITEM_STRING) || (pData->eType == MENUITEM_STRINGIMAGE) ) + { + long nTextWidth = pWin->GetCtrlTextWidth( pData->aText ); + long nTextHeight = pWin->GetTextHeight(); + +// if ( nTextHeight > pData->aSz.Height() ) +// pData->aSz.Height() = nTextHeight; + + if ( bIsMenuBar ) + { + if ( nTextHeight > pData->aSz.Height() ) + pData->aSz.Height() = nTextHeight; + + pData->aSz.Width() = nTextWidth + 4*nExtra; + aSz.Width() += pData->aSz.Width(); + } + else + pData->aSz.Height() = Max( Max( nTextHeight, pData->aSz.Height() ), nMinMenuItemHeight ); + + nWidth += nTextWidth; + } + + // Accel + if ( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) + { + String aName = pData->aAccelKey.GetName(); + long nAccWidth = pWin->GetTextWidth( aName ); + nAccWidth += nExtra; + nWidth += nAccWidth; + } + + // SubMenu? + if ( !bIsMenuBar && pData->pSubMenu ) + { + if ( nFontHeight > nWidth ) + nWidth += nFontHeight; + + pData->aSz.Height() = Max( Max( nFontHeight, pData->aSz.Height() ), nMinMenuItemHeight ); + } + + pData->aSz.Height() += EXTRAITEMHEIGHT; // Etwas mehr Abstand: + + if ( !bIsMenuBar ) + aSz.Height() += (long)pData->aSz.Height(); + + if ( nWidth > nMaxWidth ) + nMaxWidth = nWidth; + + } + } + + if ( !bIsMenuBar ) + { + // popup menus should not be wider than half the screen + // except on rather small screens + // TODO: move GetScreenNumber from SystemWindow to Window ? + // currently we rely on internal privileges + unsigned int nScreenNumber = pWin->ImplGetWindowImpl()->mpFrame->maGeometry.nScreenNumber; + Rectangle aDispRect( Application::GetScreenPosSizePixel( nScreenNumber ) ); + long nScreenWidth = aDispRect.GetWidth() >= 800 ? aDispRect.GetWidth() : 800; + if( nMaxWidth > nScreenWidth/2 ) + nMaxWidth = nScreenWidth/2; + + USHORT gfxExtra = (USHORT) Max( nExtra, 7L ); // #107710# increase space between checkmarks/images/text + nCheckPos = (USHORT)nExtra; + if (nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) + { + long nImgOrChkWidth = 0; + nImagePos = nCheckPos; + if( nMax > 0 ) // NWF case + nImgOrChkWidth = nMax + nExtra; + else // non NWF case + nImgOrChkWidth = nFontHeight/2 + gfxExtra; + nImgOrChkWidth = Max( nImgOrChkWidth, aMaxImgSz.Width() + gfxExtra ); + nTextPos = (USHORT)(nImagePos + nImgOrChkWidth); + } + else + { + nImagePos = nCheckPos; + nTextPos = (USHORT)(nImagePos + Max( aMaxImgSz.Width(), nCheckWidth )); + } + nTextPos = nTextPos + gfxExtra; + + aSz.Width() = nTextPos + nMaxWidth + nExtra; + aSz.Width() += 4*nExtra; // a _little_ more ... + + int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder; + aSz.Width() += 2*nOuterSpace; + aSz.Height() += 2*nOuterSpace; + } + else + { + nTextPos = (USHORT)(2*nExtra); + aSz.Height() = nFontHeight+6; + + // get menubar height from native methods if supported + if( pWindow->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aVal; + Rectangle aNativeBounds; + Rectangle aNativeContent; + Point tmp( 0, 0 ); + Rectangle aCtrlRegion( tmp, Size( 100, 15 ) ); + if( pWindow->GetNativeControlRegion( ControlType(CTRL_MENUBAR), + ControlPart(PART_ENTIRE_CONTROL), + aCtrlRegion, + ControlState(CTRL_STATE_ENABLED), + aVal, + OUString(), + aNativeBounds, + aNativeContent ) + ) + { + int nNativeHeight = aNativeBounds.GetHeight(); + if( nNativeHeight > aSz.Height() ) + aSz.Height() = nNativeHeight; + } + } + + // account for the size of the close button, which actually is a toolbox + // due to NWF this is variable + long nCloserHeight = ((MenuBarWindow*) pWindow)->MinCloseButtonSize().Height(); + if( aSz.Height() < nCloserHeight ) + aSz.Height() = nCloserHeight; + } + + if ( pLogo ) + aSz.Width() += pLogo->aBitmap.GetSizePixel().Width(); + + return aSz; +} + +static void ImplPaintCheckBackground( Window* i_pWindow, const Rectangle& i_rRect, bool i_bHighlight ) +{ + BOOL bNativeOk = FALSE; + if( i_pWindow->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + ImplControlValue aControlValue; + Rectangle aCtrlRegion( i_rRect ); + ControlState nState = CTRL_STATE_PRESSED | CTRL_STATE_ENABLED; + + aControlValue.setTristateVal( BUTTONVALUE_ON ); + + bNativeOk = i_pWindow->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, + aCtrlRegion, nState, aControlValue, + rtl::OUString() ); + } + + if( ! bNativeOk ) + { + const StyleSettings& rSettings = i_pWindow->GetSettings().GetStyleSettings(); + Color aColor( i_bHighlight ? rSettings.GetMenuHighlightTextColor() : rSettings.GetHighlightColor() ); + i_pWindow->DrawSelectionBackground( i_rRect, 0, i_bHighlight, TRUE, FALSE, 2, NULL, &aColor ); + } +} + +static String getShortenedString( const String& i_rLong, Window* i_pWin, long i_nMaxWidth ) +{ + xub_StrLen nPos = STRING_NOTFOUND; + String aNonMnem( OutputDevice::GetNonMnemonicString( i_rLong, nPos ) ); + aNonMnem = i_pWin->GetEllipsisString( aNonMnem, i_nMaxWidth, TEXT_DRAW_CENTERELLIPSIS ); + // re-insert mnemonic + if( nPos != STRING_NOTFOUND ) + { + if( nPos < aNonMnem.Len() && i_rLong.GetChar(nPos+1) == aNonMnem.GetChar(nPos) ) + { + rtl::OUStringBuffer aBuf( i_rLong.Len() ); + aBuf.append( aNonMnem.GetBuffer(), nPos ); + aBuf.append( sal_Unicode('~') ); + aBuf.append( aNonMnem.GetBuffer()+nPos ); + aNonMnem = aBuf.makeStringAndClear(); + } + } + return aNonMnem; +} + +void Menu::ImplPaint( Window* pWin, USHORT nBorder, long nStartY, MenuItemData* pThisItemOnly, BOOL bHighlighted, bool bLayout ) const +{ + // Fuer Symbole: nFontHeight x nFontHeight + long nFontHeight = pWin->GetTextHeight(); + long nExtra = nFontHeight/4; + + long nCheckHeight = 0, nRadioHeight = 0, nMaxCheckWidth = 0; + ImplGetNativeCheckAndRadioSize( pWin, nCheckHeight, nRadioHeight, nMaxCheckWidth ); + + DecorationView aDecoView( pWin ); + const StyleSettings& rSettings = pWin->GetSettings().GetStyleSettings(); + + Point aTopLeft, aTmpPos; + + if ( pLogo ) + aTopLeft.X() = pLogo->aBitmap.GetSizePixel().Width(); + + int nOuterSpace = 0; + if( !bIsMenuBar ) + { + nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder; + aTopLeft.X() += nOuterSpace; + aTopLeft.Y() += nOuterSpace; + } + + Size aOutSz = pWin->GetOutputSizePixel(); + USHORT nCount = (USHORT)pItemList->Count(); + if( bLayout ) + mpLayoutData->m_aVisibleItemBoundRects.clear(); + for ( USHORT n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pItemList->GetDataFromPos( n ); + if ( ImplIsVisible( n ) && ( !pThisItemOnly || ( pData == pThisItemOnly ) ) ) + { + if ( pThisItemOnly && bHighlighted ) + pWin->SetTextColor( rSettings.GetMenuHighlightTextColor() ); + + Point aPos( aTopLeft ); + aPos.Y() += nBorder; + aPos.Y() += nStartY; + + if ( aPos.Y() >= 0 ) + { + long nTextOffsetY = ((pData->aSz.Height()-nFontHeight)/2); + if( bIsMenuBar ) + nTextOffsetY += (aOutSz.Height()-pData->aSz.Height()) / 2; + USHORT nTextStyle = 0; + USHORT nSymbolStyle = 0; + USHORT nImageStyle = 0; + // SubMenus ohne Items werden nicht mehr disablte dargestellt, + // wenn keine Items enthalten sind, da die Anwendung selber + // darauf achten muss. Ansonsten gibt es Faelle, wo beim + // asyncronen laden die Eintraege disablte dargestellt werden. + if ( !pData->bEnabled ) + { + nTextStyle |= TEXT_DRAW_DISABLE; + nSymbolStyle |= SYMBOL_DRAW_DISABLE; + nImageStyle |= IMAGE_DRAW_DISABLE; + } + + // Separator + if ( !bLayout && !bIsMenuBar && ( pData->eType == MENUITEM_SEPARATOR ) ) + { + bool bNativeOk = false; + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, + PART_MENU_SEPARATOR ) ) + { + ControlState nState = 0; + if ( pData->bEnabled ) + nState |= CTRL_STATE_ENABLED; + if ( bHighlighted ) + nState |= CTRL_STATE_SELECTED; + Size aSz( pData->aSz ); + aSz.Width() = aOutSz.Width() - 2*nOuterSpace; + Rectangle aItemRect( aPos, aSz ); + MenupopupValue aVal( nTextPos-GUTTERBORDER, aItemRect ); + bNativeOk = pWin->DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_SEPARATOR, + aItemRect, + nState, + aVal, + OUString() ); + } + if( ! bNativeOk ) + { + aTmpPos.Y() = aPos.Y() + ((pData->aSz.Height()-2)/2); + aTmpPos.X() = aPos.X() + 2 + nOuterSpace; + pWin->SetLineColor( rSettings.GetShadowColor() ); + pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + aTmpPos.Y()++; + pWin->SetLineColor( rSettings.GetLightColor() ); + pWin->DrawLine( aTmpPos, Point( aOutSz.Width() - 3 - 2*nOuterSpace, aTmpPos.Y() ) ); + pWin->SetLineColor(); + } + } + + Rectangle aOuterCheckRect( Point( aPos.X()+nCheckPos, aPos.Y() ), Size( pData->aSz.Height(), pData->aSz.Height() ) ); + aOuterCheckRect.Left() += 1; + aOuterCheckRect.Right() -= 1; + aOuterCheckRect.Top() += 1; + aOuterCheckRect.Bottom() -= 1; + + // CheckMark + if ( !bLayout && !bIsMenuBar && pData->HasCheck() ) + { + // draw selection transparent marker if checked + // onto that either a checkmark or the item image + // will be painted + // however do not do this if native checks will be painted since + // the selection color too often does not fit the theme's check and/or radio + + if( ! ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) ) + { + if ( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, + (pData->nBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_CHECK_MARK + : PART_MENU_ITEM_RADIO_MARK ) ) + { + ControlPart nPart = ((pData->nBits & MIB_RADIOCHECK) + ? PART_MENU_ITEM_RADIO_MARK + : PART_MENU_ITEM_CHECK_MARK); + + ControlState nState = 0; + + if ( pData->bChecked ) + nState |= CTRL_STATE_PRESSED; + + if ( pData->bEnabled ) + nState |= CTRL_STATE_ENABLED; + + if ( bHighlighted ) + nState |= CTRL_STATE_SELECTED; + + long nCtrlHeight = (pData->nBits & MIB_RADIOCHECK) ? nCheckHeight : nRadioHeight; + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - nCtrlHeight)/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - nCtrlHeight)/2; + + Rectangle aCheckRect( aTmpPos, Size( nCtrlHeight, nCtrlHeight ) ); + MenupopupValue aVal( nTextPos-GUTTERBORDER, Rectangle( aPos, pData->aSz ) ); + pWin->DrawNativeControl( CTRL_MENU_POPUP, nPart, + aCheckRect, + nState, + aVal, + OUString() ); + } + else if ( pData->bChecked ) // by default do nothing for unchecked items + { + ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted ); + + SymbolType eSymbol; + Size aSymbolSize; + if ( pData->nBits & MIB_RADIOCHECK ) + { + eSymbol = SYMBOL_RADIOCHECKMARK; + aSymbolSize = Size( nFontHeight/2, nFontHeight/2 ); + } + else + { + eSymbol = SYMBOL_CHECKMARK; + aSymbolSize = Size( (nFontHeight*25)/40, nFontHeight/2 ); + } + aTmpPos.X() = aOuterCheckRect.Left() + (aOuterCheckRect.GetWidth() - aSymbolSize.Width())/2; + aTmpPos.Y() = aOuterCheckRect.Top() + (aOuterCheckRect.GetHeight() - aSymbolSize.Height())/2; + Rectangle aRect( aTmpPos, aSymbolSize ); + aDecoView.DrawSymbol( aRect, eSymbol, pWin->GetTextColor(), nSymbolStyle ); + } + } + } + + // Image: + if ( !bLayout && !bIsMenuBar && ( ( pData->eType == MENUITEM_IMAGE ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) ) + { + // Don't render an image for a check thing + if ((nMenuFlags & MENU_FLAG_SHOWCHECKIMAGES) || !pData->HasCheck() ) + { + if( pData->bChecked ) + ImplPaintCheckBackground( pWin, aOuterCheckRect, pThisItemOnly && bHighlighted ); + aTmpPos = aOuterCheckRect.TopLeft(); + aTmpPos.X() += (aOuterCheckRect.GetWidth()-pData->aImage.GetSizePixel().Width())/2; + aTmpPos.Y() += (aOuterCheckRect.GetHeight()-pData->aImage.GetSizePixel().Height())/2; + pWin->DrawImage( aTmpPos, pData->aImage, nImageStyle ); + } + } + + // Text: + if ( ( pData->eType == MENUITEM_STRING ) || ( pData->eType == MENUITEM_STRINGIMAGE ) ) + { + aTmpPos.X() = aPos.X() + nTextPos; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + USHORT nStyle = nTextStyle|TEXT_DRAW_MNEMONIC; + if ( pData->bIsTemporary ) + nStyle |= TEXT_DRAW_DISABLE; + MetricVector* pVector = bLayout ? &mpLayoutData->m_aUnicodeBoundRects : NULL; + String* pDisplayText = bLayout ? &mpLayoutData->m_aDisplayText : NULL; + if( bLayout ) + { + mpLayoutData->m_aLineIndices.push_back( mpLayoutData->m_aDisplayText.Len() ); + mpLayoutData->m_aLineItemIds.push_back( pData->nId ); + mpLayoutData->m_aLineItemPositions.push_back( n ); + } + // #i47946# with NWF painted menus the background is transparent + // since DrawCtrlText can depend on the background (e.g. for + // TEXT_DRAW_DISABLE), temporarily set a background which + // hopefully matches the NWF background since it is read + // from the system style settings + bool bSetTmpBackground = !pWin->IsBackground() && pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ); + if( bSetTmpBackground ) + { + Color aBg = bIsMenuBar ? + pWin->GetSettings().GetStyleSettings().GetMenuBarColor() : + pWin->GetSettings().GetStyleSettings().GetMenuColor(); + pWin->SetBackground( Wallpaper( aBg ) ); + } + // how much space is there for the text ? + long nMaxItemTextWidth = aOutSz.Width() - aTmpPos.X() - nExtra - nOuterSpace; + if( !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) + { + XubString aAccText = pData->aAccelKey.GetName(); + nMaxItemTextWidth -= pWin->GetTextWidth( aAccText ) + 3*nExtra; + } + if( !bIsMenuBar && pData->pSubMenu ) + { + nMaxItemTextWidth -= nFontHeight - nExtra; + } + String aItemText( getShortenedString( pData->aText, pWin, nMaxItemTextWidth ) ); + pWin->DrawCtrlText( aTmpPos, aItemText, 0, aItemText.Len(), nStyle, pVector, pDisplayText ); + if( bSetTmpBackground ) + pWin->SetBackground(); + } + + // Accel + if ( !bLayout && !bIsMenuBar && pData->aAccelKey.GetCode() && !ImplAccelDisabled() ) + { + XubString aAccText = pData->aAccelKey.GetName(); + aTmpPos.X() = aOutSz.Width() - pWin->GetTextWidth( aAccText ); + aTmpPos.X() -= 4*nExtra; + + aTmpPos.X() -= nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nTextOffsetY; + pWin->DrawCtrlText( aTmpPos, aAccText, 0, aAccText.Len(), nTextStyle ); + } + + // SubMenu? + if ( !bLayout && !bIsMenuBar && pData->pSubMenu ) + { + aTmpPos.X() = aOutSz.Width() - nFontHeight + nExtra - nOuterSpace; + aTmpPos.Y() = aPos.Y(); + aTmpPos.Y() += nExtra/2; + aTmpPos.Y() += ( pData->aSz.Height() / 2 ) - ( nFontHeight/4 ); + if ( pData->nBits & MIB_POPUPSELECT ) + { + pWin->SetTextColor( rSettings.GetMenuTextColor() ); + Point aTmpPos2( aPos ); + aTmpPos2.X() = aOutSz.Width() - nFontHeight - nFontHeight/4; + aDecoView.DrawFrame( + Rectangle( aTmpPos2, Size( nFontHeight+nFontHeight/4, pData->aSz.Height() ) ), FRAME_DRAW_GROUP ); + } + aDecoView.DrawSymbol( + Rectangle( aTmpPos, Size( nFontHeight/2, nFontHeight/2 ) ), + SYMBOL_SPIN_RIGHT, pWin->GetTextColor(), nSymbolStyle ); + } + + if ( pThisItemOnly && bHighlighted ) + { + // This restores the normal menu or menu bar text + // color for when it is no longer highlighted. + if ( bIsMenuBar ) + pWin->SetTextColor( rSettings.GetMenuBarTextColor() ); + else + pWin->SetTextColor( rSettings.GetMenuTextColor() ); + } + } + if( bLayout ) + { + if ( !bIsMenuBar ) + mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, Size( aOutSz.Width(), pData->aSz.Height() ) ); + else + mpLayoutData->m_aVisibleItemBoundRects[ n ] = Rectangle( aTopLeft, pData->aSz ); + } + } + + if ( !bIsMenuBar ) + { + aTopLeft.Y() += pData->aSz.Height(); + } + else + { + aTopLeft.X() += pData->aSz.Width(); + } + } + + if ( !bLayout && !pThisItemOnly && pLogo ) + { + Size aLogoSz = pLogo->aBitmap.GetSizePixel(); + + Rectangle aRect( Point( 0, 0 ), Point( aLogoSz.Width()-1, aOutSz.Height() ) ); + if ( pWin->GetColorCount() >= 256 ) + { + Gradient aGrad( GRADIENT_LINEAR, pLogo->aStartColor, pLogo->aEndColor ); + aGrad.SetAngle( 1800 ); + aGrad.SetBorder( 15 ); + pWin->DrawGradient( aRect, aGrad ); + } + else + { + pWin->SetFillColor( pLogo->aStartColor ); + pWin->DrawRect( aRect ); + } + + Point aLogoPos( 0, aOutSz.Height() - aLogoSz.Height() ); + pLogo->aBitmap.Draw( pWin, aLogoPos ); + } +} + +Menu* Menu::ImplGetStartMenu() +{ + Menu* pStart = this; + while ( pStart && pStart->pStartedFrom && ( pStart->pStartedFrom != pStart ) ) + pStart = pStart->pStartedFrom; + return pStart; +} + +void Menu::ImplCallHighlight( USHORT nHighlightedItem ) +{ + ImplMenuDelData aDelData( this ); + + nSelectedId = 0; + MenuItemData* pData = pItemList->GetDataFromPos( nHighlightedItem ); + if ( pData ) + nSelectedId = pData->nId; + ImplCallEventListeners( VCLEVENT_MENU_HIGHLIGHT, GetItemPos( GetCurItemId() ) ); + + if( !aDelData.isDeleted() ) + { + Highlight(); + nSelectedId = 0; + } +} + +IMPL_LINK( Menu, ImplCallSelect, Menu*, EMPTYARG ) +{ + nEventId = 0; + Select(); + return 0; +} + +Menu* Menu::ImplFindSelectMenu() +{ + Menu* pSelMenu = nEventId ? this : NULL; + + for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; ) + { + MenuItemData* pData = GetItemList()->GetDataFromPos( --n ); + + if ( pData->pSubMenu ) + pSelMenu = pData->pSubMenu->ImplFindSelectMenu(); + } + + return pSelMenu; +} + +Menu* Menu::ImplFindMenu( USHORT nItemId ) +{ + Menu* pSelMenu = NULL; + + for ( ULONG n = GetItemList()->Count(); n && !pSelMenu; ) + { + MenuItemData* pData = GetItemList()->GetDataFromPos( --n ); + + if( pData->nId == nItemId ) + pSelMenu = this; + else if ( pData->pSubMenu ) + pSelMenu = pData->pSubMenu->ImplFindMenu( nItemId ); + } + + return pSelMenu; +} + +void Menu::RemoveDisabledEntries( BOOL bCheckPopups, BOOL bRemoveEmptyPopups ) +{ + for ( USHORT n = 0; n < GetItemCount(); n++ ) + { + BOOL bRemove = FALSE; + MenuItemData* pItem = pItemList->GetDataFromPos( n ); + if ( pItem->eType == MENUITEM_SEPARATOR ) + { + if ( !n || ( GetItemType( n-1 ) == MENUITEM_SEPARATOR ) ) + bRemove = TRUE; + } + else + bRemove = !pItem->bEnabled; + + if ( bCheckPopups && pItem->pSubMenu ) + { + pItem->pSubMenu->RemoveDisabledEntries( TRUE ); + if ( bRemoveEmptyPopups && !pItem->pSubMenu->GetItemCount() ) + bRemove = TRUE; + } + + if ( bRemove ) + RemoveItem( n-- ); + } + + if ( GetItemCount() ) + { + USHORT nLast = GetItemCount() - 1; + MenuItemData* pItem = pItemList->GetDataFromPos( nLast ); + if ( pItem->eType == MENUITEM_SEPARATOR ) + RemoveItem( nLast ); + } + delete mpLayoutData, mpLayoutData = NULL; +} + +BOOL Menu::HasValidEntries( BOOL bCheckPopups ) +{ + BOOL bValidEntries = FALSE; + USHORT nCount = GetItemCount(); + for ( USHORT n = 0; !bValidEntries && ( n < nCount ); n++ ) + { + MenuItemData* pItem = pItemList->GetDataFromPos( n ); + if ( pItem->bEnabled && ( pItem->eType != MENUITEM_SEPARATOR ) ) + { + if ( bCheckPopups && pItem->pSubMenu ) + bValidEntries = pItem->pSubMenu->HasValidEntries( TRUE ); + else + bValidEntries = TRUE; + } + } + return bValidEntries; +} + +void Menu::SetLogo( const MenuLogo& rLogo ) +{ + delete pLogo; + pLogo = new MenuLogo( rLogo ); +} + +void Menu::SetLogo() +{ + delete pLogo; + pLogo = NULL; +} + +MenuLogo Menu::GetLogo() const +{ + MenuLogo aLogo; + if ( pLogo ) + aLogo = *pLogo; + return aLogo; +} + +void Menu::ImplKillLayoutData() const +{ + delete mpLayoutData, mpLayoutData = NULL; +} + +void Menu::ImplFillLayoutData() const +{ + if( pWindow && pWindow->IsReallyVisible() ) + { + mpLayoutData = new MenuLayoutData(); + if( bIsMenuBar ) + { + ImplPaint( pWindow, 0, 0, 0, FALSE, true ); + } + else + { + MenuFloatingWindow* pFloat = (MenuFloatingWindow*)pWindow; + ImplPaint( pWindow, pFloat->nScrollerHeight, pFloat->ImplGetStartY(), 0, FALSE, true ); + } + } +} + +String Menu::GetDisplayText() const +{ + if( ! mpLayoutData ) + ImplFillLayoutData(); + return mpLayoutData ? mpLayoutData->m_aDisplayText : String(); +} + +Rectangle Menu::GetCharacterBounds( USHORT nItemID, long nIndex ) const +{ + long nItemIndex = -1; + if( ! mpLayoutData ) + ImplFillLayoutData(); + if( mpLayoutData ) + { + for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ ) + { + if( mpLayoutData->m_aLineItemIds[i] == nItemID ) + { + nItemIndex = mpLayoutData->m_aLineIndices[i]; + break; + } + } + } + return (mpLayoutData && nItemIndex != -1) ? mpLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle(); +} + + +long Menu::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const +{ + long nIndex = -1; + rItemID = 0; + if( ! mpLayoutData ) + ImplFillLayoutData(); + if( mpLayoutData ) + { + nIndex = mpLayoutData->GetIndexForPoint( rPoint ); + for( size_t i = 0; i < mpLayoutData->m_aLineIndices.size(); i++ ) + { + if( mpLayoutData->m_aLineIndices[i] <= nIndex && + (i == mpLayoutData->m_aLineIndices.size()-1 || mpLayoutData->m_aLineIndices[i+1] > nIndex) ) + { + // make index relative to item + nIndex -= mpLayoutData->m_aLineIndices[i]; + rItemID = mpLayoutData->m_aLineItemIds[i]; + break; + } + } + } + return nIndex; +} + +long Menu::GetLineCount() const +{ + if( ! mpLayoutData ) + ImplFillLayoutData(); + return mpLayoutData ? mpLayoutData->GetLineCount() : 0; +} + +Pair Menu::GetLineStartEnd( long nLine ) const +{ + if( ! mpLayoutData ) + ImplFillLayoutData(); + return mpLayoutData ? mpLayoutData->GetLineStartEnd( nLine ) : Pair( -1, -1 ); +} + +Pair Menu::GetItemStartEnd( USHORT nItem ) const +{ + if( ! mpLayoutData ) + ImplFillLayoutData(); + + for( size_t i = 0; i < mpLayoutData->m_aLineItemIds.size(); i++ ) + if( mpLayoutData->m_aLineItemIds[i] == nItem ) + return GetLineStartEnd( i ); + + return Pair( -1, -1 ); +} + +USHORT Menu::GetDisplayItemId( long nLine ) const +{ + USHORT nItemId = 0; + if( ! mpLayoutData ) + ImplFillLayoutData(); + if( mpLayoutData && ( nLine >= 0 ) && ( nLine < (long)mpLayoutData->m_aLineItemIds.size() ) ) + nItemId = mpLayoutData->m_aLineItemIds[nLine]; + return nItemId; +} + +BOOL Menu::ConvertPoint( Point& rPoint, Window* pReferenceWindow ) const +{ + BOOL bRet = FALSE; + if( pWindow && pReferenceWindow ) + { + rPoint = pReferenceWindow->OutputToAbsoluteScreenPixel( rPoint ); + rPoint = pWindow->AbsoluteScreenToOutputPixel( rPoint ); + bRet = TRUE; + } + return bRet; +} + +Rectangle Menu::GetBoundingRectangle( USHORT nPos ) const +{ + Rectangle aRet; + + if( ! mpLayoutData ) + ImplFillLayoutData(); + if( mpLayoutData ) + { + std::map< USHORT, Rectangle >::const_iterator it = mpLayoutData->m_aVisibleItemBoundRects.find( nPos ); + if( it != mpLayoutData->m_aVisibleItemBoundRects.end() ) + aRet = it->second; + } + return aRet; +} + +void Menu::SetAccessibleName( USHORT nItemId, const XubString& rStr ) +{ + USHORT nPos; + MenuItemData* pData = pItemList->GetData( nItemId, nPos ); + + if ( pData && !rStr.Equals( pData->aAccessibleName ) ) + { + pData->aAccessibleName = rStr; + ImplCallEventListeners( VCLEVENT_MENU_ACCESSIBLENAMECHANGED, nPos ); + } +} + +XubString Menu::GetAccessibleName( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aAccessibleName; + else + return ImplGetSVEmptyStr(); +} + +void Menu::SetAccessibleDescription( USHORT nItemId, const XubString& rStr ) +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + pData->aAccessibleDescription = rStr; +} + +XubString Menu::GetAccessibleDescription( USHORT nItemId ) const +{ + MenuItemData* pData = pItemList->GetData( nItemId ); + + if ( pData ) + return pData->aAccessibleDescription; + else + return ImplGetSVEmptyStr(); +} + +void Menu::ImplSetSalMenu( SalMenu *pSalMenu ) +{ + if( mpSalMenu ) + ImplGetSVData()->mpDefInst->DestroyMenu( mpSalMenu ); + mpSalMenu = pSalMenu; +} + +BOOL Menu::GetSystemMenuData( SystemMenuData* pData ) const +{ + Menu* pMenu = (Menu*)this; + if( pData && pMenu->ImplGetSalMenu() ) + { + pMenu->ImplGetSalMenu()->GetSystemMenuData( pData ); + return TRUE; + } + else + return FALSE; +} + +bool Menu::IsHighlighted( USHORT nItemPos ) const +{ + bool bRet = false; + + if( pWindow ) + { + if( bIsMenuBar ) + bRet = ( nItemPos == static_cast< MenuBarWindow * > (pWindow)->GetHighlightedItem() ); + else + bRet = ( nItemPos == static_cast< MenuFloatingWindow * > (pWindow)->GetHighlightedItem() ); + } + + return bRet; +} + +void Menu::HighlightItem( USHORT nItemPos ) +{ + if ( pWindow ) + { + if ( bIsMenuBar ) + { + MenuBarWindow* pMenuWin = static_cast< MenuBarWindow* >( pWindow ); + pMenuWin->SetAutoPopup( FALSE ); + pMenuWin->ChangeHighlightItem( nItemPos, FALSE ); + } + else + { + static_cast< MenuFloatingWindow* >( pWindow )->ChangeHighlightItem( nItemPos, FALSE ); + } + } +} + +// ----------- +// - MenuBar - +// ----------- + +MenuBar::MenuBar() : Menu( TRUE ) +{ + mbDisplayable = TRUE; + mbCloserVisible = FALSE; + mbFloatBtnVisible = FALSE; + mbHideBtnVisible = FALSE; +} + +MenuBar::MenuBar( const MenuBar& rMenu ) : Menu( TRUE ) +{ + mbDisplayable = TRUE; + mbCloserVisible = FALSE; + mbFloatBtnVisible = FALSE; + mbHideBtnVisible = FALSE; + *this = rMenu; + bIsMenuBar = TRUE; +} + +MenuBar::MenuBar( const ResId& rResId ) : Menu ( TRUE ) +{ + mbDisplayable = TRUE; + mbCloserVisible = FALSE; + mbFloatBtnVisible = FALSE; + mbHideBtnVisible = FALSE; + ImplLoadRes( rResId ); +} + +MenuBar::~MenuBar() +{ + ImplDestroy( this, TRUE ); +} + +void MenuBar::ShowCloser( BOOL bShow ) +{ + ShowButtons( bShow, mbFloatBtnVisible, mbHideBtnVisible ); +} + +void MenuBar::ShowFloatButton( BOOL bShow ) +{ + ShowButtons( mbCloserVisible, bShow, mbHideBtnVisible ); +} + +void MenuBar::ShowHideButton( BOOL bShow ) +{ + ShowButtons( mbCloserVisible, mbFloatBtnVisible, bShow ); +} + +void MenuBar::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide ) +{ + if ( (bClose != mbCloserVisible) || + (bFloat != mbFloatBtnVisible) || + (bHide != mbHideBtnVisible) ) + { + mbCloserVisible = bClose; + mbFloatBtnVisible = bFloat; + mbHideBtnVisible = bHide; + if ( ImplGetWindow() ) + ((MenuBarWindow*)ImplGetWindow())->ShowButtons( bClose, bFloat, bHide ); + } +} + +void MenuBar::SetDisplayable( BOOL bDisplayable ) +{ + if( bDisplayable != mbDisplayable ) + { + mbDisplayable = bDisplayable; + MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow(); + if( pMenuWin ) + pMenuWin->ImplLayoutChanged(); + } +} + +Window* MenuBar::ImplCreate( Window* pParent, Window* pWindow, MenuBar* pMenu ) +{ + if ( !pWindow ) + pWindow = new MenuBarWindow( pParent ); + + pMenu->pStartedFrom = 0; + pMenu->pWindow = pWindow; + ((MenuBarWindow*)pWindow)->SetMenu( pMenu ); + long nHeight = pMenu->ImplCalcSize( pWindow ).Height(); + + // depending on the native implementation or the displayable flag + // the menubar windows is supressed (ie, height=0) + if( !((MenuBar*) pMenu)->IsDisplayable() || + ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) ) + nHeight = 0; + + pWindow->SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT ); + return pWindow; +} + +void MenuBar::ImplDestroy( MenuBar* pMenu, BOOL bDelete ) +{ + MenuBarWindow* pWindow = (MenuBarWindow*) pMenu->ImplGetWindow(); + if ( pWindow && bDelete ) + { + pWindow->KillActivePopup(); + delete pWindow; + } + pMenu->pWindow = NULL; +} + +BOOL MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu ) +{ + BOOL bDone = FALSE; + + // No keyboard processing when system handles the menu or our menubar is invisible + if( !IsDisplayable() || + ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) ) + return bDone; + + // Enabled-Abfragen, falls diese Methode von einem anderen Fenster gerufen wurde... + Window* pWin = ImplGetWindow(); + if ( pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && ! pWin->IsInModalMode() ) + bDone = ((MenuBarWindow*)pWin)->ImplHandleKeyEvent( rKEvent, bFromMenu ); + return bDone; +} + +// ----------------------------------------------------------------------- + +void MenuBar::SelectEntry( USHORT nId ) +{ + MenuBarWindow* pMenuWin = (MenuBarWindow*) ImplGetWindow(); + + if( pMenuWin ) + { + pMenuWin->GrabFocus(); + nId = GetItemPos( nId ); + + // #99705# popup the selected menu + pMenuWin->SetAutoPopup( TRUE ); + if( ITEMPOS_INVALID != pMenuWin->nHighlightedItem ) + { + pMenuWin->KillActivePopup(); + pMenuWin->ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + } + if( nId != ITEMPOS_INVALID ) + pMenuWin->ChangeHighlightItem( nId, FALSE ); + } +} + +// ----------------------------------------------------------------------- + +// handler for native menu selection and command events + +BOOL MenuBar::HandleMenuActivateEvent( Menu *pMenu ) const +{ + if( pMenu ) + { + ImplMenuDelData aDelData( this ); + + pMenu->pStartedFrom = (Menu*)this; + pMenu->bInCallback = TRUE; + pMenu->Activate(); + + if( !aDelData.isDeleted() ) + pMenu->bInCallback = FALSE; + } + return TRUE; +} + +BOOL MenuBar::HandleMenuDeActivateEvent( Menu *pMenu ) const +{ + if( pMenu ) + { + ImplMenuDelData aDelData( this ); + + pMenu->pStartedFrom = (Menu*)this; + pMenu->bInCallback = TRUE; + pMenu->Deactivate(); + if( !aDelData.isDeleted() ) + pMenu->bInCallback = FALSE; + } + return TRUE; +} + +BOOL MenuBar::HandleMenuHighlightEvent( Menu *pMenu, USHORT nHighlightEventId ) const +{ + if( !pMenu ) + pMenu = ((Menu*) this)->ImplFindMenu( nHighlightEventId ); + if( pMenu ) + { + ImplMenuDelData aDelData( pMenu ); + + if( mnHighlightedItemPos != ITEMPOS_INVALID ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, mnHighlightedItemPos ); + + if( !aDelData.isDeleted() ) + { + pMenu->mnHighlightedItemPos = pMenu->GetItemPos( nHighlightEventId ); + pMenu->nSelectedId = nHighlightEventId; + pMenu->pStartedFrom = (Menu*)this; + pMenu->ImplCallHighlight( pMenu->mnHighlightedItemPos ); + } + return TRUE; + } + else + return FALSE; +} + +BOOL MenuBar::HandleMenuCommandEvent( Menu *pMenu, USHORT nCommandEventId ) const +{ + if( !pMenu ) + pMenu = ((Menu*) this)->ImplFindMenu( nCommandEventId ); + if( pMenu ) + { + pMenu->nSelectedId = nCommandEventId; + pMenu->pStartedFrom = (Menu*)this; + pMenu->ImplSelect(); + return TRUE; + } + else + return FALSE; +} + +USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, USHORT i_nPos ) +{ + return AddMenuBarButton( i_rImage, i_rLink, String(), i_nPos ); +} + +USHORT MenuBar::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos ) +{ + return pWindow ? static_cast<MenuBarWindow*>(pWindow)->AddMenuBarButton( i_rImage, i_rLink, i_rToolTip, i_nPos ) : 0; +} + +void MenuBar::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink ) +{ + if( pWindow ) + static_cast<MenuBarWindow*>(pWindow)->SetMenuBarButtonHighlightHdl( nId, rLink ); +} + +Rectangle MenuBar::GetMenuBarButtonRectPixel( USHORT nId ) +{ + return pWindow ? static_cast<MenuBarWindow*>(pWindow)->GetMenuBarButtonRectPixel( nId ) : Rectangle(); +} + +void MenuBar::RemoveMenuBarButton( USHORT nId ) +{ + if( pWindow ) + static_cast<MenuBarWindow*>(pWindow)->RemoveMenuBarButton( nId ); +} + +BOOL MenuBar::HandleMenuButtonEvent( Menu *, USHORT i_nButtonId ) const +{ + return static_cast<MenuBarWindow*>(pWindow)->HandleMenuButtonEvent( i_nButtonId ); +} + +// ----------------------------------------------------------------------- + +// BOOL PopupMenu::bAnyPopupInExecute = FALSE; + +PopupMenu::PopupMenu() +{ + pRefAutoSubMenu = NULL; +} + +PopupMenu::PopupMenu( const ResId& rResId ) +{ + pRefAutoSubMenu = NULL; + ImplLoadRes( rResId ); +} + +PopupMenu::PopupMenu( const PopupMenu& rMenu ) : Menu() +{ + pRefAutoSubMenu = NULL; + *this = rMenu; +} + +PopupMenu::~PopupMenu() +{ + if( pRefAutoSubMenu && *pRefAutoSubMenu == this ) + *pRefAutoSubMenu = NULL; // #111060# avoid second delete in ~MenuItemData +} + +BOOL PopupMenu::IsInExecute() +{ + return GetActivePopupMenu() ? TRUE : FALSE; +} + +PopupMenu* PopupMenu::GetActivePopupMenu() +{ + ImplSVData* pSVData = ImplGetSVData(); + return pSVData->maAppData.mpActivePopupMenu; +} + +void PopupMenu::EndExecute( USHORT nSelectId ) +{ + if ( ImplGetWindow() ) + ImplGetFloatingWindow()->EndExecute( nSelectId ); +} + +void PopupMenu::SelectEntry( USHORT nId ) +{ + if ( ImplGetWindow() ) + { + if( nId != ITEMPOS_INVALID ) + { + USHORT nPos; + MenuItemData* pData = GetItemList()->GetData( nId, nPos ); + if ( pData->pSubMenu ) + ImplGetFloatingWindow()->ChangeHighlightItem( nPos, TRUE ); + else + ImplGetFloatingWindow()->EndExecute( nId ); + } + else + { + MenuFloatingWindow* pFloat = ImplGetFloatingWindow(); + pFloat->GrabFocus(); + USHORT nPos; + for( nPos = 0; nPos < GetItemList()->Count(); nPos++ ) + { + MenuItemData* pData = (MenuItemData*)GetItemList()->GetObject( nPos ); + if( pData->pSubMenu ) + { + pFloat->KillActivePopup(); + } + } + pFloat->ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + } + } +} + +void PopupMenu::SetSelectedEntry( USHORT nId ) +{ + nSelectedId = nId; +} + +USHORT PopupMenu::Execute( Window* pExecWindow, const Point& rPopupPos ) +{ + return Execute( pExecWindow, Rectangle( rPopupPos, rPopupPos ), POPUPMENU_EXECUTE_DOWN ); +} + +USHORT PopupMenu::Execute( Window* pExecWindow, const Rectangle& rRect, USHORT nFlags ) +{ + ENSURE_OR_RETURN( pExecWindow, "PopupMenu::Execute: need a non-NULL window!", 0 ); + + + ULONG nPopupModeFlags = 0; + if ( nFlags & POPUPMENU_EXECUTE_DOWN ) + nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN; + else if ( nFlags & POPUPMENU_EXECUTE_UP ) + nPopupModeFlags = FLOATWIN_POPUPMODE_UP; + else if ( nFlags & POPUPMENU_EXECUTE_LEFT ) + nPopupModeFlags = FLOATWIN_POPUPMODE_LEFT; + else if ( nFlags & POPUPMENU_EXECUTE_RIGHT ) + nPopupModeFlags = FLOATWIN_POPUPMODE_RIGHT; + else + nPopupModeFlags = FLOATWIN_POPUPMODE_DOWN; + + if (nFlags & POPUPMENU_NOMOUSEUPCLOSE ) // allow popup menus to stay open on mouse button up + nPopupModeFlags |= FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE; // useful if the menu was opened on mousebutton down (eg toolbox configuration) + + return ImplExecute( pExecWindow, rRect, nPopupModeFlags, 0, FALSE ); +} + +USHORT PopupMenu::ImplExecute( Window* pW, const Rectangle& rRect, ULONG nPopupModeFlags, Menu* pSFrom, BOOL bPreSelectFirst ) +{ + if ( !pSFrom && ( PopupMenu::IsInExecute() || !GetItemCount() ) ) + return 0; + + delete mpLayoutData, mpLayoutData = NULL; + + ImplSVData* pSVData = ImplGetSVData(); + + pStartedFrom = pSFrom; + nSelectedId = 0; + bCanceled = FALSE; + + ULONG nFocusId = 0; + BOOL bRealExecute = FALSE; + if ( !pStartedFrom ) + { + pSVData->maWinData.mbNoDeactivate = TRUE; + nFocusId = Window::SaveFocus(); + bRealExecute = TRUE; + } + else + { + // assure that only one menu is open at a time + if( pStartedFrom->bIsMenuBar && pSVData->maWinData.mpFirstFloat ) + pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + + DBG_ASSERT( !ImplGetWindow(), "Win?!" ); + Rectangle aRect( rRect ); + aRect.SetPos( pW->OutputToScreenPixel( aRect.TopLeft() ) ); + + WinBits nStyle = WB_BORDER; + if ( bRealExecute ) + nPopupModeFlags |= FLOATWIN_POPUPMODE_NEWLEVEL; + if ( !pStartedFrom || !pStartedFrom->bIsMenuBar ) + nPopupModeFlags |= FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK | FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE; + + nPopupModeFlags |= FLOATWIN_POPUPMODE_NOKEYCLOSE; + + // Kann beim Debuggen hilfreich sein. + // nPopupModeFlags |= FLOATWIN_POPUPMODE_NOFOCUSCLOSE; + + ImplDelData aDelData; + pW->ImplAddDel( &aDelData ); + + bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen + Activate(); + bInCallback = FALSE; + + if ( aDelData.IsDelete() ) + return 0; // Error + + pW->ImplRemoveDel( &aDelData ); + + if ( bCanceled || bKilled ) + return 0; + + if ( !GetItemCount() ) + return 0; + + // Das Flag MENU_FLAG_HIDEDISABLEDENTRIES wird vererbt. + if ( pSFrom ) + { + if ( pSFrom->nMenuFlags & MENU_FLAG_HIDEDISABLEDENTRIES ) + nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES; + else + nMenuFlags &= ~MENU_FLAG_HIDEDISABLEDENTRIES; + } + else + // #102790# context menues shall never show disabled entries + nMenuFlags |= MENU_FLAG_HIDEDISABLEDENTRIES; + + + USHORT nVisibleEntries = ImplGetVisibleItemCount(); + if ( !nVisibleEntries ) + { + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + { + String aTmpEntryText( ResId( SV_RESID_STRING_NOSELECTIONPOSSIBLE, *pResMgr ) ); + MenuItemData* pData = pItemList->Insert( + 0xFFFF, MENUITEM_STRING, 0, aTmpEntryText, Image(), NULL, 0xFFFF ); + pData->bIsTemporary = TRUE; + } + } + else if ( Application::GetSettings().GetStyleSettings().GetAutoMnemonic() && !( nMenuFlags & MENU_FLAG_NOAUTOMNEMONICS ) ) + { + CreateAutoMnemonics(); + } + + MenuFloatingWindow* pWin = new MenuFloatingWindow( this, pW, nStyle | WB_SYSTEMWINDOW ); + if( pSVData->maNWFData.mbFlatMenu ) + pWin->SetBorderStyle( WINDOW_BORDER_NOBORDER ); + else + pWin->SetBorderStyle( pWin->GetBorderStyle() | WINDOW_BORDER_MENU ); + pWindow = pWin; + + Size aSz = ImplCalcSize( pWin ); + + long nMaxHeight = pWin->GetDesktopRectPixel().GetHeight(); + if( Application::GetScreenCount() > 1 && ! Application::IsMultiDisplay() ) + { + Window* pDeskW = pWindow->GetWindow( WINDOW_REALPARENT ); + if( ! pDeskW ) + pDeskW = pWindow; + Point aDesktopTL( pDeskW->OutputToAbsoluteScreenPixel( aRect.TopLeft() ) ); + nMaxHeight = Application::GetWorkAreaPosSizePixel( + Application::GetBestScreen( Rectangle( aDesktopTL, aRect.GetSize() ) ) + ).GetHeight(); + } + if ( pStartedFrom && pStartedFrom->bIsMenuBar ) + nMaxHeight -= pW->GetSizePixel().Height(); + sal_Int32 nLeft, nTop, nRight, nBottom; + pWindow->GetBorder( nLeft, nTop, nRight, nBottom ); + nMaxHeight -= nTop+nBottom; + if ( aSz.Height() > nMaxHeight ) + { + pWin->EnableScrollMenu( TRUE ); + USHORT nStart = ImplGetFirstVisible(); + USHORT nEntries = ImplCalcVisEntries( nMaxHeight, nStart ); + aSz.Height() = ImplCalcHeight( nEntries ); + } + + pWin->SetFocusId( nFocusId ); + pWin->SetOutputSizePixel( aSz ); + // #102158# menus must never grab the focus, otherwise + // they will be closed immediately + // from now on focus grabbing is only prohibited automatically if + // FLOATWIN_POPUPMODE_GRABFOCUS was set (which is done below), because some + // floaters (like floating toolboxes) may grab the focus + // pWin->GrabFocus(); + if ( GetItemCount() ) + { + SalMenu* pMenu = ImplGetSalMenu(); + if( pMenu && bRealExecute && pMenu->ShowNativePopupMenu( pWin, aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ) ) + { + pWin->StopExecute(0); + pWin->doShutdown(); + pWindow->doLazyDelete(); + pWindow = NULL; + return nSelectedId; + } + else + { + pWin->StartPopupMode( aRect, nPopupModeFlags | FLOATWIN_POPUPMODE_GRABFOCUS ); + } + if( pSFrom ) + { + USHORT aPos; + if( pSFrom->bIsMenuBar ) + aPos = ((MenuBarWindow *) pSFrom->pWindow)->GetHighlightedItem(); + else + aPos = ((MenuFloatingWindow *) pSFrom->pWindow)->GetHighlightedItem(); + + pWin->SetPosInParent( aPos ); // store position to be sent in SUBMENUDEACTIVATE + pSFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUACTIVATE, aPos ); + } + } + if ( bPreSelectFirst ) + { + USHORT nCount = (USHORT)pItemList->Count(); + for ( USHORT n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pItemList->GetDataFromPos( n ); + if ( ( pData->bEnabled || !Application::GetSettings().GetStyleSettings().GetSkipDisabledInMenus() ) + && ( pData->eType != MENUITEM_SEPARATOR ) && ImplIsVisible( n ) && ImplIsSelectable( n ) ) + { + pWin->ChangeHighlightItem( n, FALSE ); + break; + } + } + } + if ( bRealExecute ) + { + pWin->ImplAddDel( &aDelData ); + + ImplDelData aModalWinDel; + pW->ImplAddDel( &aModalWinDel ); + pW->ImplIncModalCount(); + + pWin->Execute(); + + DBG_ASSERT( ! aModalWinDel.IsDead(), "window for popup died, modal count incorrect !" ); + if( ! aModalWinDel.IsDead() ) + pW->ImplDecModalCount(); + + if ( !aDelData.IsDelete() ) + pWin->ImplRemoveDel( &aDelData ); + else + return 0; + + // Focus wieder herstellen (kann schon im Select wieder + // hergestellt wurden sein + nFocusId = pWin->GetFocusId(); + if ( nFocusId ) + { + pWin->SetFocusId( 0 ); + pSVData->maWinData.mbNoDeactivate = FALSE; + } + pWin->ImplEndPopupMode( 0, nFocusId ); + + if ( nSelectedId ) // Dann abraeumen... ( sonst macht TH das ) + { + PopupMenu* pSub = pWin->GetActivePopup(); + while ( pSub ) + { + pSub->ImplGetFloatingWindow()->EndPopupMode(); + pSub = pSub->ImplGetFloatingWindow()->GetActivePopup(); + } + } + pWin->doShutdown(); + pWindow->doLazyDelete(); + pWindow = NULL; + + // Steht noch ein Select aus? + Menu* pSelect = ImplFindSelectMenu(); + if ( pSelect ) + { + // Beim Popup-Menu muss das Select vor dem Verlassen von Execute gerufen werden! + Application::RemoveUserEvent( pSelect->nEventId ); + pSelect->nEventId = 0; + pSelect->Select(); + } + } + + return bRealExecute ? nSelectedId : 0; +} + +USHORT PopupMenu::ImplCalcVisEntries( long nMaxHeight, USHORT nStartEntry, USHORT* pLastVisible ) const +{ + nMaxHeight -= 2 * ImplGetFloatingWindow()->GetScrollerHeight(); + + long nHeight = 0; + USHORT nEntries = (USHORT) pItemList->Count(); + USHORT nVisEntries = 0; + + if ( pLastVisible ) + *pLastVisible = 0; + + for ( USHORT n = nStartEntry; n < nEntries; n++ ) + { + if ( ImplIsVisible( n ) ) + { + MenuItemData* pData = pItemList->GetDataFromPos( n ); + nHeight += pData->aSz.Height(); + if ( nHeight > nMaxHeight ) + break; + + if ( pLastVisible ) + *pLastVisible = n; + nVisEntries++; + } + } + return nVisEntries; +} + +long PopupMenu::ImplCalcHeight( USHORT nEntries ) const +{ + long nHeight = 0; + + USHORT nFound = 0; + for ( USHORT n = 0; ( nFound < nEntries ) && ( n < pItemList->Count() ); n++ ) + { + if ( ImplIsVisible( (USHORT) n ) ) + { + MenuItemData* pData = pItemList->GetDataFromPos( n ); + nHeight += pData->aSz.Height(); + nFound++; + } + } + + nHeight += 2*ImplGetFloatingWindow()->GetScrollerHeight(); + + return nHeight; +} + + +static void ImplInitMenuWindow( Window* pWin, BOOL bFont, BOOL bMenuBar ) +{ + const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings(); + + if ( bFont ) + pWin->SetPointFont( rStyleSettings.GetMenuFont() ); + if( bMenuBar ) + { + if( pWin->IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + pWin->SetBackground(); // background will be drawn by NWF + } + else + { + Wallpaper aWallpaper; + aWallpaper.SetStyle( WALLPAPER_APPLICATIONGRADIENT ); + pWin->SetBackground( aWallpaper ); + pWin->SetPaintTransparent( FALSE ); + pWin->SetParentClipMode( 0 ); + } + } + else + { + if( pWin->IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) + { + pWin->SetBackground(); // background will be drawn by NWF + } + else + pWin->SetBackground( Wallpaper( rStyleSettings.GetMenuColor() ) ); + } + + if ( bMenuBar ) + pWin->SetTextColor( rStyleSettings.GetMenuBarTextColor() ); + else + pWin->SetTextColor( rStyleSettings.GetMenuTextColor() ); + pWin->SetTextFillColor(); + pWin->SetLineColor(); +} + +MenuFloatingWindow::MenuFloatingWindow( Menu* pMen, Window* pParent, WinBits nStyle ) : + FloatingWindow( pParent, nStyle ) +{ + mpWindowImpl->mbMenuFloatingWindow= TRUE; + pMenu = pMen; + pActivePopup = 0; + nSaveFocusId = 0; + bInExecute = FALSE; + bScrollMenu = FALSE; + nHighlightedItem = ITEMPOS_INVALID; + nMBDownPos = ITEMPOS_INVALID; + nPosInParent = ITEMPOS_INVALID; + nScrollerHeight = 0; +// nStartY = 0; + nBorder = EXTRASPACEY; + nFirstEntry = 0; + bScrollUp = FALSE; + bScrollDown = FALSE; + bIgnoreFirstMove = TRUE; + bKeyInput = FALSE; + + EnableSaveBackground(); + ImplInitMenuWindow( this, TRUE, FALSE ); + + SetPopupModeEndHdl( LINK( this, MenuFloatingWindow, PopupEnd ) ); + + aHighlightChangedTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, HighlightChanged ) ); + aHighlightChangedTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() ); + aSubmenuCloseTimer.SetTimeout( GetSettings().GetMouseSettings().GetMenuDelay() ); + aSubmenuCloseTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, SubmenuClose ) ); + aScrollTimer.SetTimeoutHdl( LINK( this, MenuFloatingWindow, AutoScroll ) ); + + AddEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) ); +} + +void MenuFloatingWindow::doShutdown() +{ + if( pMenu ) + { + // #105373# notify toolkit that highlight was removed + // otherwise the entry will not be read when the menu is opened again + if( nHighlightedItem != ITEMPOS_INVALID ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); + + if( !bKeyInput && pMenu && pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar ) + { + // #102461# remove highlight in parent + MenuItemData* pData; + USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count(); + for(i = 0; i < nCount; i++) + { + pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i ); + if( pData && ( pData->pSubMenu == pMenu ) ) + break; + } + if( i < nCount ) + { + MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow(); + if( pPWin ) + pPWin->HighlightItem( i, FALSE ); + } + } + + // free the reference to the accessible component + SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() ); + + aHighlightChangedTimer.Stop(); + + // #95056# invalidate screen area covered by system window + // so this can be taken into account if the commandhandler performs a scroll operation + if( GetParent() ) + { + Rectangle aInvRect( GetWindowExtentsRelative( GetParent() ) ); + GetParent()->Invalidate( aInvRect ); + } + pMenu = NULL; + RemoveEventListener( LINK( this, MenuFloatingWindow, ShowHideListener ) ); + } +} + +MenuFloatingWindow::~MenuFloatingWindow() +{ + doShutdown(); +} + +void MenuFloatingWindow::Resize() +{ + ImplInitClipRegion(); +} + +long MenuFloatingWindow::ImplGetStartY() const +{ + long nY = 0; + if( pMenu ) + { + for ( USHORT n = 0; n < nFirstEntry; n++ ) + nY += pMenu->GetItemList()->GetDataFromPos( n )->aSz.Height(); + } + return -nY; +} + +Region MenuFloatingWindow::ImplCalcClipRegion( BOOL bIncludeLogo ) const +{ + Size aOutSz = GetOutputSizePixel(); + Point aPos; + Rectangle aRect( aPos, aOutSz ); + aRect.Top() += nScrollerHeight; + aRect.Bottom() -= nScrollerHeight; + + if ( pMenu && pMenu->pLogo && !bIncludeLogo ) + aRect.Left() += pMenu->pLogo->aBitmap.GetSizePixel().Width(); + + Region aRegion = aRect; + if ( pMenu && pMenu->pLogo && bIncludeLogo && nScrollerHeight ) + aRegion.Union( Rectangle( Point(), Size( pMenu->pLogo->aBitmap.GetSizePixel().Width(), aOutSz.Height() ) ) ); + + return aRegion; +} + +void MenuFloatingWindow::ImplInitClipRegion() +{ + if ( IsScrollMenu() ) + { + SetClipRegion( ImplCalcClipRegion() ); + } + else + { + SetClipRegion(); + } +} + +void MenuFloatingWindow::ImplHighlightItem( const MouseEvent& rMEvt, BOOL bMBDown ) +{ + if( ! pMenu ) + return; + + long nY = nScrollerHeight; + long nMouseY = rMEvt.GetPosPixel().Y(); + Size aOutSz = GetOutputSizePixel(); + if ( ( nMouseY >= nY ) && ( nMouseY < ( aOutSz.Height() - nY ) ) ) + { + BOOL bHighlighted = FALSE; + USHORT nCount = (USHORT)pMenu->pItemList->Count(); + nY += ImplGetStartY(); // ggf. gescrollt. + for ( USHORT n = 0; !bHighlighted && ( n < nCount ); n++ ) + { + if ( pMenu->ImplIsVisible( n ) ) + { + MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( n ); + long nOldY = nY; + nY += pItemData->aSz.Height(); + if ( ( nOldY <= nMouseY ) && ( nY > nMouseY ) && pMenu->ImplIsSelectable( n ) ) + { + BOOL bPopupArea = TRUE; + if ( pItemData->nBits & MIB_POPUPSELECT ) + { + // Nur wenn ueber dem Pfeil geklickt wurde... + Size aSz = GetOutputSizePixel(); + long nFontHeight = GetTextHeight(); + bPopupArea = ( rMEvt.GetPosPixel().X() >= ( aSz.Width() - nFontHeight - nFontHeight/4 ) ); + } + + if ( bMBDown ) + { + if ( n != nHighlightedItem ) + { + ChangeHighlightItem( (USHORT)n, FALSE ); + } + + BOOL bAllowNewPopup = TRUE; + if ( pActivePopup ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + bAllowNewPopup = pData && ( pData->pSubMenu != pActivePopup ); + if ( bAllowNewPopup ) + KillActivePopup(); + } + + if ( bPopupArea && bAllowNewPopup ) + { + HighlightChanged( NULL ); + } + } + else + { + if ( n != nHighlightedItem ) + { + ChangeHighlightItem( (USHORT)n, TRUE ); + } + else if ( pItemData->nBits & MIB_POPUPSELECT ) + { + if ( bPopupArea && ( pActivePopup != pItemData->pSubMenu ) ) + HighlightChanged( NULL ); + } + } + bHighlighted = TRUE; + } + } + } + if ( !bHighlighted ) + ChangeHighlightItem( ITEMPOS_INVALID, TRUE ); + } + else + { + ImplScroll( rMEvt.GetPosPixel() ); + ChangeHighlightItem( ITEMPOS_INVALID, TRUE ); + } +} + +IMPL_LINK( MenuFloatingWindow, PopupEnd, FloatingWindow*, EMPTYARG ) +{ + // "this" will be deleted before the end of this method! + Menu* pM = pMenu; + if ( bInExecute ) + { + if ( pActivePopup ) + { + //DBG_ASSERT( !pActivePopup->ImplGetWindow(), "PopupEnd, obwohl pActivePopup MIT Window!" ); + KillActivePopup(); // should be ok to just remove it + //pActivePopup->bCanceled = TRUE; + } + bInExecute = FALSE; + pMenu->bInCallback = TRUE; + pMenu->Deactivate(); + pMenu->bInCallback = FALSE; + } + else + { + if( pMenu ) + { + // Wenn dies Fenster von TH geschlossen wurde, hat noch ein anderes + // Menu dieses Fenster als pActivePopup. + if ( pMenu->pStartedFrom ) + { + // Das pWin am 'Parent' kann aber schon 0 sein, falls die Kette von + // vorne abgeraeumt wurde und jetzt die EndPopup-Events eintrudeln + if ( pMenu->pStartedFrom->bIsMenuBar ) + { + MenuBarWindow* p = (MenuBarWindow*) pMenu->pStartedFrom->ImplGetWindow(); + if ( p ) + p->PopupClosed( pMenu ); + } + else + { + MenuFloatingWindow* p = (MenuFloatingWindow*) pMenu->pStartedFrom->ImplGetWindow(); + if ( p ) + p->KillActivePopup( (PopupMenu*)pMenu ); + } + } + } + } + + if ( pM ) + pM->pStartedFrom = 0; + + return 0; +} + +IMPL_LINK( MenuFloatingWindow, AutoScroll, Timer*, EMPTYARG ) +{ + ImplScroll( GetPointerPosPixel() ); + return 1; +} + +IMPL_LINK( MenuFloatingWindow, HighlightChanged, Timer*, pTimer ) +{ + if( ! pMenu ) + return 0; + + MenuItemData* pItemData = pMenu->pItemList->GetDataFromPos( nHighlightedItem ); + if ( pItemData ) + { + if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) ) + { + ULONG nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE ); + KillActivePopup(); + SetPopupModeFlags( nOldFlags ); + } + if ( pItemData->bEnabled && pItemData->pSubMenu && pItemData->pSubMenu->GetItemCount() && ( pItemData->pSubMenu != pActivePopup ) ) + { + pActivePopup = (PopupMenu*)pItemData->pSubMenu; + long nY = nScrollerHeight+ImplGetStartY(); + MenuItemData* pData = 0; + for ( ULONG n = 0; n < nHighlightedItem; n++ ) + { + pData = pMenu->pItemList->GetDataFromPos( n ); + nY += pData->aSz.Height(); + } + pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem ); + Size MySize = GetOutputSizePixel(); +// Point MyPos = GetPosPixel(); +// Point aItemTopLeft( MyPos.X(), MyPos.Y()+nY ); + Point aItemTopLeft( 0, nY ); + Point aItemBottomRight( aItemTopLeft ); + aItemBottomRight.X() += MySize.Width(); + aItemBottomRight.Y() += pData->aSz.Height(); + + // Popups leicht versetzen: + aItemTopLeft.X() += 2; + aItemBottomRight.X() -= 2; + if ( nHighlightedItem ) + aItemTopLeft.Y() -= 2; + else + { + sal_Int32 nL, nT, nR, nB; + GetBorder( nL, nT, nR, nB ); + aItemTopLeft.Y() -= nT; + } + + // pTest: Wegen Abstuerzen durch Reschedule() im Aufruf von Activate() + // Ausserdem wird damit auch verhindert, dass SubMenus angezeigt werden, + // die lange im Activate Rescheduled haben und jetzt schon nicht mehr + // angezeigt werden sollen. + Menu* pTest = pActivePopup; + ULONG nOldFlags = GetPopupModeFlags(); + SetPopupModeFlags( GetPopupModeFlags() | FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE ); + USHORT nRet = pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_RIGHT, pMenu, pTimer ? FALSE : TRUE ); + SetPopupModeFlags( nOldFlags ); + + // nRet != 0, wenn es waerend Activate() abgeschossen wurde... + if ( !nRet && ( pActivePopup == pTest ) && pActivePopup->ImplGetWindow() ) + pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this ); + } + } + + return 0; +} + +IMPL_LINK( MenuFloatingWindow, SubmenuClose, Timer*, EMPTYARG ) +{ + if( pMenu && pMenu->pStartedFrom ) + { + MenuFloatingWindow* pWin = (MenuFloatingWindow*) pMenu->pStartedFrom->GetWindow(); + if( pWin ) + pWin->KillActivePopup(); + } + return 0; +} + +IMPL_LINK( MenuFloatingWindow, ShowHideListener, VclWindowEvent*, pEvent ) +{ + if( ! pMenu ) + return 0; + + if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID ); + else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID ); + return 0; +} + +void MenuFloatingWindow::EnableScrollMenu( BOOL b ) +{ + bScrollMenu = b; + nScrollerHeight = b ? (USHORT) GetSettings().GetStyleSettings().GetScrollBarSize() /2 : 0; + bScrollDown = TRUE; + ImplInitClipRegion(); +} + +void MenuFloatingWindow::Execute() +{ + ImplSVData* pSVData = ImplGetSVData(); + + pSVData->maAppData.mpActivePopupMenu = (PopupMenu*)pMenu; + + bInExecute = TRUE; +// bCallingSelect = FALSE; + + while ( bInExecute ) + Application::Yield(); + + pSVData->maAppData.mpActivePopupMenu = NULL; + +// while ( bCallingSelect ) +// Application::Yield(); +} + +void MenuFloatingWindow::StopExecute( ULONG nFocusId ) +{ + // Focus wieder herstellen + // (kann schon im Select wieder hergestellt wurden sein) + if ( nSaveFocusId ) + { + Window::EndSaveFocus( nFocusId, FALSE ); + nFocusId = nSaveFocusId; + if ( nFocusId ) + { + nSaveFocusId = 0; + ImplGetSVData()->maWinData.mbNoDeactivate = FALSE; + } + } + ImplEndPopupMode( 0, nFocusId ); + + aHighlightChangedTimer.Stop(); + bInExecute = FALSE; + if ( pActivePopup ) + { + KillActivePopup(); + } + // notify parent, needed for accessibility + if( pMenu && pMenu->pStartedFrom ) + pMenu->pStartedFrom->ImplCallEventListeners( VCLEVENT_MENU_SUBMENUDEACTIVATE, nPosInParent ); +} + +void MenuFloatingWindow::KillActivePopup( PopupMenu* pThisOnly ) +{ + if ( pActivePopup && ( !pThisOnly || ( pThisOnly == pActivePopup ) ) ) + { + if( pActivePopup->pWindow != NULL ) + if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() ) + return; // kill it later + if ( pActivePopup->bInCallback ) + pActivePopup->bCanceled = TRUE; + + // Vor allen Aktionen schon pActivePopup = 0, falls z.B. + // PopupModeEndHdl des zu zerstoerenden Popups mal synchron gerufen wird. + PopupMenu* pPopup = pActivePopup; + pActivePopup = NULL; + pPopup->bInCallback = TRUE; + pPopup->Deactivate(); + pPopup->bInCallback = FALSE; + if ( pPopup->ImplGetWindow() ) + { + pPopup->ImplGetFloatingWindow()->StopExecute(); + pPopup->ImplGetFloatingWindow()->doShutdown(); + pPopup->pWindow->doLazyDelete(); + pPopup->pWindow = NULL; + + Update(); + } + } +} + +void MenuFloatingWindow::EndExecute() +{ + Menu* pStart = pMenu ? pMenu->ImplGetStartMenu() : NULL; + ULONG nFocusId = 0; + if ( pStart && pStart->bIsMenuBar ) + { + nFocusId = ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->GetFocusId(); + if ( nFocusId ) + { + ((MenuBarWindow*)((MenuBar*)pStart)->ImplGetWindow())->SetFocusId( 0 ); + ImplGetSVData()->maWinData.mbNoDeactivate = FALSE; + } + } + + // Wenn von woanders gestartet, dann ab dort aufraumen: + MenuFloatingWindow* pCleanUpFrom = this; + MenuFloatingWindow* pWin = this; + while ( pWin && !pWin->bInExecute && + pWin->pMenu->pStartedFrom && !pWin->pMenu->pStartedFrom->bIsMenuBar ) + { + pWin = ((PopupMenu*)pWin->pMenu->pStartedFrom)->ImplGetFloatingWindow(); + } + if ( pWin ) + pCleanUpFrom = pWin; + + // Dies Fenster wird gleich zerstoert => Daten lokal merken... + Menu* pM = pMenu; + USHORT nItem = nHighlightedItem; + + pCleanUpFrom->StopExecute( nFocusId ); + + if ( nItem != ITEMPOS_INVALID && pM ) + { + MenuItemData* pItemData = pM->GetItemList()->GetDataFromPos( nItem ); + if ( pItemData && !pItemData->bIsTemporary ) + { + pM->nSelectedId = pItemData->nId; + if ( pStart ) + pStart->nSelectedId = pItemData->nId; + + pM->ImplSelect(); + } + } +} + +void MenuFloatingWindow::EndExecute( USHORT nId ) +{ + USHORT nPos; + if ( pMenu && pMenu->GetItemList()->GetData( nId, nPos ) ) + nHighlightedItem = nPos; + else + nHighlightedItem = ITEMPOS_INVALID; + + EndExecute(); +} + +void MenuFloatingWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // TH macht ein ToTop auf dieses Fenster, aber das aktive Popup + // soll oben bleiben... + // due to focus chage this would close all menues -> don't do it (#94123) + //if ( pActivePopup && pActivePopup->ImplGetWindow() && !pActivePopup->ImplGetFloatingWindow()->pActivePopup ) + // pActivePopup->ImplGetFloatingWindow()->ToTop( TOTOP_NOGRABFOCUS ); + + ImplHighlightItem( rMEvt, TRUE ); + + nMBDownPos = nHighlightedItem; +} + +void MenuFloatingWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + MenuItemData* pData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL; + // nMBDownPos in lokaler Variable merken und gleich zuruecksetzen, + // weil nach EndExecute zu spaet + USHORT _nMBDownPos = nMBDownPos; + nMBDownPos = ITEMPOS_INVALID; + if ( pData && pData->bEnabled && ( pData->eType != MENUITEM_SEPARATOR ) ) + { + if ( !pData->pSubMenu ) + { + EndExecute(); + } + else if ( ( pData->nBits & MIB_POPUPSELECT ) && ( nHighlightedItem == _nMBDownPos ) && ( rMEvt.GetClicks() == 2 ) ) + { + // Nicht wenn ueber dem Pfeil geklickt wurde... + Size aSz = GetOutputSizePixel(); + long nFontHeight = GetTextHeight(); + if ( rMEvt.GetPosPixel().X() < ( aSz.Width() - nFontHeight - nFontHeight/4 ) ) + EndExecute(); + } + } + +} + +void MenuFloatingWindow::MouseMove( const MouseEvent& rMEvt ) +{ + if ( !IsVisible() || rMEvt.IsSynthetic() || rMEvt.IsEnterWindow() ) + return; + + if ( rMEvt.IsLeaveWindow() ) + { +#ifdef OS2 + if ( ImplHilite(rMEvt) ) + { +#endif + // #102461# do not remove highlight if a popup menu is open at this position + MenuItemData* pData = pMenu ? pMenu->pItemList->GetDataFromPos( nHighlightedItem ) : NULL; + // close popup with some delayed if we leave somewhere else + if( pActivePopup && pData && pData->pSubMenu != pActivePopup ) + pActivePopup->ImplGetFloatingWindow()->aSubmenuCloseTimer.Start(); + + if( !pActivePopup || (pData && pData->pSubMenu != pActivePopup ) ) + ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); +#ifdef OS2 + } +#endif + + if ( IsScrollMenu() ) + ImplScroll( rMEvt.GetPosPixel() ); + } + else +#ifdef OS2 + if ( ImplHilite(rMEvt) ) +#endif + { + aSubmenuCloseTimer.Stop(); + if( bIgnoreFirstMove ) + bIgnoreFirstMove = FALSE; + else + ImplHighlightItem( rMEvt, FALSE ); + } +} + +void MenuFloatingWindow::ImplScroll( BOOL bUp ) +{ + KillActivePopup(); + Update(); + + if( ! pMenu ) + return; + + HighlightItem( nHighlightedItem, FALSE ); + + pMenu->ImplKillLayoutData(); + + if ( bScrollUp && bUp ) + { + nFirstEntry = pMenu->ImplGetPrevVisible( nFirstEntry ); + DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" ); + + long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height(); + +// nStartY += nEntryHeight; + + if ( !bScrollDown ) + { + bScrollDown = TRUE; + ImplDrawScroller( FALSE ); + } + + if ( pMenu->ImplGetPrevVisible( nFirstEntry ) == ITEMPOS_INVALID ) + { + bScrollUp = FALSE; + ImplDrawScroller( TRUE ); + } + + Scroll( 0, nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP ); + } + else if ( bScrollDown && !bUp ) + { + long nScrollEntryHeight = pMenu->GetItemList()->GetDataFromPos( nFirstEntry )->aSz.Height(); + + nFirstEntry = pMenu->ImplGetNextVisible( nFirstEntry ); + DBG_ASSERT( nFirstEntry != ITEMPOS_INVALID, "Scroll?!" ); + + + if ( !bScrollUp ) + { + bScrollUp = TRUE; + ImplDrawScroller( TRUE ); + } + + long nHeight = GetOutputSizePixel().Height(); + USHORT nLastVisible; + ((PopupMenu*)pMenu)->ImplCalcVisEntries( nHeight, nFirstEntry, &nLastVisible ); + if ( pMenu->ImplGetNextVisible( nLastVisible ) == ITEMPOS_INVALID ) + { + bScrollDown = FALSE; + ImplDrawScroller( FALSE ); + } + +// nStartY -= nEntryHeight; + Scroll( 0, -nScrollEntryHeight, ImplCalcClipRegion( FALSE ).GetBoundRect(), SCROLL_CLIP ); + } + + HighlightItem( nHighlightedItem, TRUE ); +} + +void MenuFloatingWindow::ImplScroll( const Point& rMousePos ) +{ + Size aOutSz = GetOutputSizePixel(); + + long nY = nScrollerHeight; + long nMouseY = rMousePos.Y(); + long nDelta = 0; + + if ( bScrollUp && ( nMouseY < nY ) ) + { + ImplScroll( TRUE ); + nDelta = nY - nMouseY; + } + else if ( bScrollDown && ( nMouseY > ( aOutSz.Height() - nY ) ) ) + { + ImplScroll( FALSE ); + nDelta = nMouseY - ( aOutSz.Height() - nY ); + } + + if ( nDelta ) + { + aScrollTimer.Stop(); // Falls durch MouseMove gescrollt. + long nTimeout; + if ( nDelta < 3 ) + nTimeout = 200; + else if ( nDelta < 5 ) + nTimeout = 100; + else if ( nDelta < 8 ) + nTimeout = 70; + else if ( nDelta < 12 ) + nTimeout = 40; + else + nTimeout = 20; + aScrollTimer.SetTimeout( nTimeout ); + aScrollTimer.Start(); + } +} +void MenuFloatingWindow::ChangeHighlightItem( USHORT n, BOOL bStartPopupTimer ) +{ + // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert. + // #65750# Dann verzichten wir lieber auf den schmalen Streifen Hintergrundsicherung. + // Sonst lassen sich die Menus schlecht bedienen. +// MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n ); +// if ( pActivePopup && pNextData && ( pActivePopup != pNextData->pSubMenu ) ) +// KillActivePopup(); + + aSubmenuCloseTimer.Stop(); + if( ! pMenu ) + return; + + if ( nHighlightedItem != ITEMPOS_INVALID ) + { + HighlightItem( nHighlightedItem, FALSE ); + pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); + } + + nHighlightedItem = (USHORT)n; + DBG_ASSERT( pMenu->ImplIsVisible( nHighlightedItem ) || nHighlightedItem == ITEMPOS_INVALID, "ChangeHighlightItem: Not visible!" ); + if( nHighlightedItem != ITEMPOS_INVALID ) + { + if( pMenu->pStartedFrom && !pMenu->pStartedFrom->bIsMenuBar ) + { + // #102461# make sure parent entry is highlighted as well + MenuItemData* pData; + USHORT i, nCount = (USHORT)pMenu->pStartedFrom->pItemList->Count(); + for(i = 0; i < nCount; i++) + { + pData = pMenu->pStartedFrom->pItemList->GetDataFromPos( i ); + if( pData && ( pData->pSubMenu == pMenu ) ) + break; + } + if( i < nCount ) + { + MenuFloatingWindow* pPWin = (MenuFloatingWindow*)pMenu->pStartedFrom->ImplGetWindow(); + if( pPWin && pPWin->nHighlightedItem != i ) + { + pPWin->HighlightItem( i, TRUE ); + pPWin->nHighlightedItem = i; + } + } + } + HighlightItem( nHighlightedItem, TRUE ); + pMenu->ImplCallHighlight( nHighlightedItem ); + } + else + pMenu->nSelectedId = 0; + + if ( bStartPopupTimer ) + { + // #102438# Menu items are not selectable + // If a menu item is selected by an AT-tool via the XAccessibleAction, XAccessibleValue + // or XAccessibleSelection interface, and the parent popup menus are not executed yet, + // the parent popup menus must be executed SYNCHRONOUSLY, before the menu item is selected. + if ( GetSettings().GetMouseSettings().GetMenuDelay() ) + aHighlightChangedTimer.Start(); + else + HighlightChanged( &aHighlightChangedTimer ); + } +} + +void MenuFloatingWindow::HighlightItem( USHORT nPos, BOOL bHighlight ) +{ + if( ! pMenu ) + return; + + Size aSz = GetOutputSizePixel(); + long nStartY = ImplGetStartY(); + long nY = nScrollerHeight+nStartY; + long nX = 0; + + if ( pMenu->pLogo ) + nX = pMenu->pLogo->aBitmap.GetSizePixel().Width(); + + int nOuterSpace = ImplGetSVData()->maNWFData.mnMenuFormatExtraBorder; + nY += nOuterSpace; + + USHORT nCount = (USHORT)pMenu->pItemList->Count(); + for ( USHORT n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + DBG_ASSERT( pMenu->ImplIsVisible( n ), "Highlight: Item not visible!" ); + if ( pData->eType != MENUITEM_SEPARATOR ) + { + BOOL bRestoreLineColor = FALSE; + Color oldLineColor; + bool bDrawItemRect = true; + + Rectangle aItemRect( Point( nX+nOuterSpace, nY ), Size( aSz.Width()-2*nOuterSpace, pData->aSz.Height() ) ); + if ( pData->nBits & MIB_POPUPSELECT ) + { + long nFontHeight = GetTextHeight(); + aItemRect.Right() -= nFontHeight + nFontHeight/4; + } + + if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) + { + Size aPxSize( GetOutputSizePixel() ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ) ); + Rectangle aCtrlRect( Point( nX, 0 ), Size( aPxSize.Width()-nX, aPxSize.Height() ) ); + MenupopupValue aVal( pMenu->nTextPos-GUTTERBORDER, aItemRect ); + DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, + aCtrlRect, + CTRL_STATE_ENABLED, + aVal, + OUString() ); + if( bHighlight && + IsNativeControlSupported( CTRL_MENU_POPUP, PART_MENU_ITEM ) ) + { + bDrawItemRect = false; + if( FALSE == DrawNativeControl( CTRL_MENU_POPUP, PART_MENU_ITEM, + aItemRect, + CTRL_STATE_SELECTED | ( pData->bEnabled? CTRL_STATE_ENABLED: 0 ), + aVal, + OUString() ) ) + { + bDrawItemRect = bHighlight; + } + } + else + bDrawItemRect = bHighlight; + Pop(); + } + if( bDrawItemRect ) + { + if ( bHighlight ) + { + if( pData->bEnabled ) + SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + else + { + SetFillColor(); + oldLineColor = GetLineColor(); + SetLineColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + bRestoreLineColor = TRUE; + } + } + else + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + + DrawRect( aItemRect ); + } + pMenu->ImplPaint( this, nScrollerHeight, nStartY, pData, bHighlight ); + if( bRestoreLineColor ) + SetLineColor( oldLineColor ); + } + return; + } + + nY += pData->aSz.Height(); + } +} + +Rectangle MenuFloatingWindow::ImplGetItemRect( USHORT nPos ) +{ + if( ! pMenu ) + return Rectangle(); + + Rectangle aRect; + Size aSz = GetOutputSizePixel(); + long nStartY = ImplGetStartY(); + long nY = nScrollerHeight+nStartY; + long nX = 0; + + if ( pMenu->pLogo ) + nX = pMenu->pLogo->aBitmap.GetSizePixel().Width(); + + USHORT nCount = (USHORT)pMenu->pItemList->Count(); + for ( USHORT n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + DBG_ASSERT( pMenu->ImplIsVisible( n ), "ImplGetItemRect: Item not visible!" ); + if ( pData->eType != MENUITEM_SEPARATOR ) + { + aRect = Rectangle( Point( nX, nY ), Size( aSz.Width(), pData->aSz.Height() ) ); + if ( pData->nBits & MIB_POPUPSELECT ) + { + long nFontHeight = GetTextHeight(); + aRect.Right() -= nFontHeight + nFontHeight/4; + } + } + break; + } + nY += pData->aSz.Height(); + } + return aRect; +} + + +void MenuFloatingWindow::ImplCursorUpDown( BOOL bUp, BOOL bHomeEnd ) +{ + if( ! pMenu ) + return; + + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + + USHORT n = nHighlightedItem; + if ( n == ITEMPOS_INVALID ) + { + if ( bUp ) + n = 0; + else + n = pMenu->GetItemCount()-1; + } + + USHORT nLoop = n; + + if( bHomeEnd ) + { + // absolute positioning + if( bUp ) + { + n = pMenu->GetItemCount(); + nLoop = n-1; + } + else + { + n = (USHORT)-1; + nLoop = n+1; + } + } + + do + { + if ( bUp ) + { + if ( n ) + n--; + else + if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) ) + n = pMenu->GetItemCount()-1; + else + break; + } + else + { + n++; + if ( n >= pMenu->GetItemCount() ) + { + if ( !IsScrollMenu() || ( nHighlightedItem == ITEMPOS_INVALID ) ) + n = 0; + else + break; + } + } + + MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n ); + if ( ( pData->bEnabled || !rSettings.GetSkipDisabledInMenus() ) + && ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) && pMenu->ImplIsSelectable( n ) ) + { + // Selektion noch im sichtbaren Bereich? + if ( IsScrollMenu() ) + { + ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + + while ( n < nFirstEntry ) + ImplScroll( TRUE ); + + Size aOutSz = GetOutputSizePixel(); + USHORT nLastVisible; + ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible ); + while ( n > nLastVisible ) + { + ImplScroll( FALSE ); + ((PopupMenu*)pMenu)->ImplCalcVisEntries( aOutSz.Height(), nFirstEntry, &nLastVisible ); + } + } + ChangeHighlightItem( n, FALSE ); + break; + } + } while ( n != nLoop ); +} + +void MenuFloatingWindow::KeyInput( const KeyEvent& rKEvent ) +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + USHORT nCode = rKEvent.GetKeyCode().GetCode(); + bKeyInput = TRUE; + switch ( nCode ) + { + case KEY_UP: + case KEY_DOWN: + { + ImplCursorUpDown( nCode == KEY_UP ); + } + break; + case KEY_END: + case KEY_HOME: + { + ImplCursorUpDown( nCode == KEY_END, TRUE ); + } + break; + case KEY_F6: + case KEY_ESCAPE: + { + // Ctrl-F6 acts like ESC here, the menu bar however will then put the focus in the document + if( nCode == KEY_F6 && !rKEvent.GetKeyCode().IsMod1() ) + break; + if( pMenu ) + { + if ( !pMenu->pStartedFrom ) + { + StopExecute(); + KillActivePopup(); + } + else if ( pMenu->pStartedFrom->bIsMenuBar ) + { + // Forward... + ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent ); + } + else + { + StopExecute(); + PopupMenu* pPopupMenu = (PopupMenu*)pMenu->pStartedFrom; + MenuFloatingWindow* pFloat = pPopupMenu->ImplGetFloatingWindow(); + pFloat->GrabFocus(); + pFloat->KillActivePopup(); + pPopupMenu->ImplCallHighlight(pFloat->nHighlightedItem); + } + } + } + break; + case KEY_LEFT: + { + if ( pMenu && pMenu->pStartedFrom ) + { + StopExecute(); + if ( pMenu->pStartedFrom->bIsMenuBar ) + { + // Forward... + ((MenuBarWindow*)((MenuBar*)pMenu->pStartedFrom)->ImplGetWindow())->KeyInput( rKEvent ); + } + else + { + MenuFloatingWindow* pFloat = ((PopupMenu*)pMenu->pStartedFrom)->ImplGetFloatingWindow(); + pFloat->GrabFocus(); + pFloat->KillActivePopup(); + } + } + } + break; + case KEY_RIGHT: + { + if( pMenu ) + { + BOOL bDone = FALSE; + if ( nHighlightedItem != ITEMPOS_INVALID ) + { + MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ); + if ( pData && pData->pSubMenu ) + { + HighlightChanged( 0 ); + bDone = TRUE; + } + } + if ( !bDone ) + { + Menu* pStart = pMenu->ImplGetStartMenu(); + if ( pStart && pStart->bIsMenuBar ) + { + // Forward... + pStart->ImplGetWindow()->KeyInput( rKEvent ); + } + } + } + } + break; + case KEY_RETURN: + { + if( pMenu ) + { + MenuItemData* pData = pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ); + if ( pData && pData->bEnabled ) + { + if ( pData->pSubMenu ) + HighlightChanged( 0 ); + else + EndExecute(); + } + else + StopExecute(); + } + } + break; + case KEY_MENU: + { + if( pMenu ) + { + Menu* pStart = pMenu->ImplGetStartMenu(); + if ( pStart && pStart->bIsMenuBar ) + { + // Forward... + pStart->ImplGetWindow()->KeyInput( rKEvent ); + } + } + } + break; + default: + { + xub_Unicode nCharCode = rKEvent.GetCharCode(); + USHORT nPos = 0; + USHORT nDuplicates = 0; + MenuItemData* pData = (nCharCode && pMenu) ? pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nPos, nDuplicates, nHighlightedItem ) : NULL; + if ( pData ) + { + if ( pData->pSubMenu || nDuplicates > 1 ) + { + ChangeHighlightItem( nPos, FALSE ); + HighlightChanged( 0 ); + } + else + { + nHighlightedItem = nPos; + EndExecute(); + } + } + else + { + // Bei ungueltigen Tasten Beepen, aber nicht bei HELP und F-Tasten + if ( !rKEvent.GetKeyCode().IsMod2() && ( nCode != KEY_HELP ) && ( rKEvent.GetKeyCode().GetGroup() != KEYGROUP_FKEYS ) ) + Sound::Beep(); + FloatingWindow::KeyInput( rKEvent ); + } + } + } + // #105474# check if menu window was not destroyed + if ( !aDelData.IsDelete() ) + { + ImplRemoveDel( &aDelData ); + bKeyInput = FALSE; + } +} + +void MenuFloatingWindow::Paint( const Rectangle& ) +{ + if( ! pMenu ) + return; + + if( IsNativeControlSupported( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL ) ) + { + SetClipRegion(); + long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0; + Size aPxSize( GetOutputSizePixel() ); + aPxSize.Width() -= nX; + ImplControlValue aVal( pMenu->nTextPos-GUTTERBORDER ); + DrawNativeControl( CTRL_MENU_POPUP, PART_ENTIRE_CONTROL, + Rectangle( Point( nX, 0 ), aPxSize ), + CTRL_STATE_ENABLED, + aVal, + OUString() ); + ImplInitClipRegion(); + } + if ( IsScrollMenu() ) + { + ImplDrawScroller( TRUE ); + ImplDrawScroller( FALSE ); + } + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + pMenu->ImplPaint( this, nScrollerHeight, ImplGetStartY() ); + if ( nHighlightedItem != ITEMPOS_INVALID ) + HighlightItem( nHighlightedItem, TRUE ); +} + +void MenuFloatingWindow::ImplDrawScroller( BOOL bUp ) +{ + if( ! pMenu ) + return; + + SetClipRegion(); + + Size aOutSz = GetOutputSizePixel(); + long nY = bUp ? 0 : ( aOutSz.Height() - nScrollerHeight ); + long nX = pMenu->pLogo ? pMenu->pLogo->aBitmap.GetSizePixel().Width() : 0; + Rectangle aRect( Point( nX, nY ), Size( aOutSz.Width()-nX, nScrollerHeight ) ); + + DecorationView aDecoView( this ); + SymbolType eSymbol = bUp ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN; + + USHORT nStyle = 0; + if ( ( bUp && !bScrollUp ) || ( !bUp && !bScrollDown ) ) + nStyle |= SYMBOL_DRAW_DISABLE; + + aDecoView.DrawSymbol( aRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle ); + + ImplInitClipRegion(); +} + +void MenuFloatingWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + USHORT nId = nHighlightedItem; + Menu* pM = pMenu; + Window* pW = this; + + // #102618# Get item rect before destroying the window in EndExecute() call + Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) ); + + if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) + { + nHighlightedItem = ITEMPOS_INVALID; + EndExecute(); + pW = NULL; + } + + if( !ImplHandleHelpEvent( pW, pM, nId, rHEvt, aHighlightRect ) ) + Window::RequestHelp( rHEvt ); +} + +void MenuFloatingWindow::StateChanged( StateChangedType nType ) +{ + FloatingWindow::StateChanged( nType ); + + if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) + { + ImplInitMenuWindow( this, FALSE, FALSE ); + Invalidate(); + } +} + +void MenuFloatingWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + FloatingWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplInitMenuWindow( this, FALSE, FALSE ); + Invalidate(); + } +} + +void MenuFloatingWindow::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) ) + { +// ImplCursorUpDown( pData->GetDelta() > 0L ); + ImplScroll( pData->GetDelta() > 0L ); + MouseMove( MouseEvent( GetPointerPosPixel(), 0 ) ); + } + } +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuFloatingWindow::CreateAccessible() +{ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc; + + if ( pMenu && !pMenu->pStartedFrom ) + xAcc = pMenu->GetAccessible(); + + return xAcc; +} + +MenuBarWindow::MenuBarWindow( Window* pParent ) : + Window( pParent, 0 ), + aCloser( this ), + aFloatBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ), + aHideBtn( this, WB_NOPOINTERFOCUS | WB_SMALLSTYLE | WB_RECTSTYLE ) +{ + SetType( WINDOW_MENUBARWINDOW ); + pMenu = NULL; + pActivePopup = NULL; + nSaveFocusId = 0; + nHighlightedItem = ITEMPOS_INVALID; + mbAutoPopup = TRUE; + nSaveFocusId = 0; + bIgnoreFirstMove = TRUE; + bStayActive = FALSE; + + ResMgr* pResMgr = ImplGetResMgr(); + + if( pResMgr ) + { + BitmapEx aBitmap( ResId( SV_RESID_BITMAP_CLOSEDOC, *pResMgr ) ); + BitmapEx aBitmapHC( ResId( SV_RESID_BITMAP_CLOSEDOCHC, *pResMgr ) ); + + aCloser.maImage = Image( aBitmap ); + aCloser.maImageHC = Image( aBitmapHC ); + + aCloser.SetOutStyle( TOOLBOX_STYLE_FLAT ); + aCloser.SetBackground(); + aCloser.SetPaintTransparent( TRUE ); + aCloser.SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + + aCloser.InsertItem( IID_DOCUMENTCLOSE, + GetSettings().GetStyleSettings().GetHighContrastMode() ? aCloser.maImageHC : aCloser.maImage, 0 ); + aCloser.SetSelectHdl( LINK( this, MenuBarWindow, CloserHdl ) ); + aCloser.AddEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) ); + aCloser.SetQuickHelpText( IID_DOCUMENTCLOSE, XubString( ResId( SV_HELPTEXT_CLOSEDOCUMENT, *pResMgr ) ) ); + + aFloatBtn.SetClickHdl( LINK( this, MenuBarWindow, FloatHdl ) ); + aFloatBtn.SetSymbol( SYMBOL_FLOAT ); + aFloatBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_RESTORE, *pResMgr ) ) ); + + aHideBtn.SetClickHdl( LINK( this, MenuBarWindow, HideHdl ) ); + aHideBtn.SetSymbol( SYMBOL_HIDE ); + aHideBtn.SetQuickHelpText( XubString( ResId( SV_HELPTEXT_MINIMIZE, *pResMgr ) ) ); + } + + ImplInitStyleSettings(); + + AddEventListener( LINK( this, MenuBarWindow, ShowHideListener ) ); +} + +MenuBarWindow::~MenuBarWindow() +{ + aCloser.RemoveEventListener( LINK( this, MenuBarWindow, ToolboxEventHdl ) ); + RemoveEventListener( LINK( this, MenuBarWindow, ShowHideListener ) ); +} + +void MenuBarWindow::SetMenu( MenuBar* pMen ) +{ + pMenu = pMen; + KillActivePopup(); + nHighlightedItem = ITEMPOS_INVALID; + ImplInitMenuWindow( this, TRUE, TRUE ); + if ( pMen ) + { + aCloser.ShowItem( IID_DOCUMENTCLOSE, pMen->HasCloser() ); + aCloser.Show( pMen->HasCloser() || !m_aAddButtons.empty() ); + aFloatBtn.Show( pMen->HasFloatButton() ); + aHideBtn.Show( pMen->HasHideButton() ); + } + Invalidate(); + + // show and connect native menubar + if( pMenu && pMenu->ImplGetSalMenu() ) + { + if( pMenu->ImplGetSalMenu()->VisibleMenuBar() ) + ImplGetFrame()->SetMenu( pMenu->ImplGetSalMenu() ); + + pMenu->ImplGetSalMenu()->SetFrame( ImplGetFrame() ); + } +} + +void MenuBarWindow::ShowButtons( BOOL bClose, BOOL bFloat, BOOL bHide ) +{ + aCloser.ShowItem( IID_DOCUMENTCLOSE, bClose ); + aCloser.Show( bClose || ! m_aAddButtons.empty() ); + aFloatBtn.Show( bFloat ); + aHideBtn.Show( bHide ); + Resize(); +} + +Size MenuBarWindow::MinCloseButtonSize() +{ + return aCloser.getMinSize(); +} + +IMPL_LINK( MenuBarWindow, CloserHdl, PushButton*, EMPTYARG ) +{ + if( ! pMenu ) + return 0; + + if( aCloser.GetCurItemId() == IID_DOCUMENTCLOSE ) + { + // #i106052# call close hdl asynchronously to ease handler implementation + // this avoids still being in the handler while the DecoToolBox already + // gets destroyed + Application::PostUserEvent( ((MenuBar*)pMenu)->GetCloserHdl(), pMenu ); + } + else + { + std::map<USHORT,AddButtonEntry>::iterator it = m_aAddButtons.find( aCloser.GetCurItemId() ); + if( it != m_aAddButtons.end() ) + { + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = it->first; + aArg.bHighlight = (aCloser.GetHighlightItemId() == it->first); + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + return it->second.m_aSelectLink.Call( &aArg ); + } + } + return 0; +} + +IMPL_LINK( MenuBarWindow, ToolboxEventHdl, VclWindowEvent*, pEvent ) +{ + if( ! pMenu ) + return 0; + + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = 0xffff; + aArg.bHighlight = (pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT); + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHT ) + aArg.nId = aCloser.GetHighlightItemId(); + else if( pEvent->GetId() == VCLEVENT_TOOLBOX_HIGHLIGHTOFF ) + { + USHORT nPos = static_cast< USHORT >(reinterpret_cast<sal_IntPtr>(pEvent->GetData())); + aArg.nId = aCloser.GetItemId( nPos ); + } + std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( aArg.nId ); + if( it != m_aAddButtons.end() ) + { + it->second.m_aHighlightLink.Call( &aArg ); + } + return 0; +} + +IMPL_LINK( MenuBarWindow, ShowHideListener, VclWindowEvent*, pEvent ) +{ + if( ! pMenu ) + return 0; + + if( pEvent->GetId() == VCLEVENT_WINDOW_SHOW ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_SHOW, ITEMPOS_INVALID ); + else if( pEvent->GetId() == VCLEVENT_WINDOW_HIDE ) + pMenu->ImplCallEventListeners( VCLEVENT_MENU_HIDE, ITEMPOS_INVALID ); + return 0; +} + +IMPL_LINK( MenuBarWindow, FloatHdl, PushButton*, EMPTYARG ) +{ + return pMenu ? ((MenuBar*)pMenu)->GetFloatButtonClickHdl().Call( pMenu ) : 0; +} + +IMPL_LINK( MenuBarWindow, HideHdl, PushButton*, EMPTYARG ) +{ + return pMenu ? ((MenuBar*)pMenu)->GetHideButtonClickHdl().Call( pMenu ) : 0; +} + +void MenuBarWindow::ImplCreatePopup( BOOL bPreSelectFirst ) +{ + MenuItemData* pItemData = pMenu ? pMenu->GetItemList()->GetDataFromPos( nHighlightedItem ) : NULL; + if ( pItemData ) + { + bIgnoreFirstMove = TRUE; + if ( pActivePopup && ( pActivePopup != pItemData->pSubMenu ) ) + { + KillActivePopup(); + } + if ( pItemData->bEnabled && pItemData->pSubMenu && ( nHighlightedItem != ITEMPOS_INVALID ) && ( pItemData->pSubMenu != pActivePopup ) ) + { + pActivePopup = (PopupMenu*)pItemData->pSubMenu; + long nX = 0; + MenuItemData* pData = 0; + for ( ULONG n = 0; n < nHighlightedItem; n++ ) + { + pData = pMenu->GetItemList()->GetDataFromPos( n ); + nX += pData->aSz.Width(); + } + pData = pMenu->pItemList->GetDataFromPos( nHighlightedItem ); +// Point MyPos = GetPosPixel(); +// Point aItemTopLeft( MyPos.X()+nX, MyPos.Y() ); + Point aItemTopLeft( nX, 0 ); + Point aItemBottomRight( aItemTopLeft ); + aItemBottomRight.X() += pData->aSz.Width(); + + // Im Vollbild-Modus hat die MenuBar ggf. die Hoehe 0: + // Nicht immer einfach die Window-Hoehe nehmen, weil ItemHeight < WindowHeight. + if ( GetSizePixel().Height() ) + { + // #107747# give menuitems the height of the menubar + aItemBottomRight.Y() += GetOutputSizePixel().Height()-1; + } + + // ImplExecute ist doch nicht modal... + // #99071# do not grab the focus, otherwise it will be restored to the menubar + // when the frame is reactivated later + //GrabFocus(); + pActivePopup->ImplExecute( this, Rectangle( aItemTopLeft, aItemBottomRight ), FLOATWIN_POPUPMODE_DOWN, pMenu, bPreSelectFirst ); + if ( pActivePopup ) + { + // Hat kein Window, wenn vorher abgebrochen oder keine Eintraege + if ( pActivePopup->ImplGetFloatingWindow() ) + pActivePopup->ImplGetFloatingWindow()->AddPopupModeWindow( this ); + else + pActivePopup = NULL; + } + } + } +} + + +void MenuBarWindow::KillActivePopup() +{ + if ( pActivePopup ) + { + if( pActivePopup->pWindow != NULL ) + if( ((FloatingWindow *) pActivePopup->pWindow)->IsInCleanUp() ) + return; // kill it later + + if ( pActivePopup->bInCallback ) + pActivePopup->bCanceled = TRUE; + + pActivePopup->bInCallback = TRUE; + pActivePopup->Deactivate(); + pActivePopup->bInCallback = FALSE; + // Abfrage auf pActivePopup, falls im Deactivate abgeschossen... + if ( pActivePopup && pActivePopup->ImplGetWindow() ) + { + pActivePopup->ImplGetFloatingWindow()->StopExecute(); + pActivePopup->ImplGetFloatingWindow()->doShutdown(); + pActivePopup->pWindow->doLazyDelete(); + pActivePopup->pWindow = NULL; + } + pActivePopup = 0; + } +} + +void MenuBarWindow::PopupClosed( Menu* pPopup ) +{ + if ( pPopup == pActivePopup ) + { + KillActivePopup(); + ChangeHighlightItem( ITEMPOS_INVALID, FALSE, ImplGetFrameWindow()->ImplGetFrameData()->mbHasFocus, FALSE ); + } +} + +void MenuBarWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + mbAutoPopup = TRUE; + USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); + if ( ( nEntry != ITEMPOS_INVALID ) && ( nEntry != nHighlightedItem ) ) + { + ChangeHighlightItem( nEntry, FALSE ); + } + else + { + KillActivePopup(); + ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + } +} + +void MenuBarWindow::MouseButtonUp( const MouseEvent& ) +{ +} + +void MenuBarWindow::MouseMove( const MouseEvent& rMEvt ) +{ + // Im Move nur Highlighten, wenn schon eins gehighlightet. + if ( rMEvt.IsSynthetic() || rMEvt.IsLeaveWindow() || rMEvt.IsEnterWindow() || ( nHighlightedItem == ITEMPOS_INVALID ) ) + return; + + if( bIgnoreFirstMove ) + { + bIgnoreFirstMove = FALSE; + return; + } + + USHORT nEntry = ImplFindEntry( rMEvt.GetPosPixel() ); + if ( ( nEntry != ITEMPOS_INVALID ) +#ifdef OS2 + && ( ImplHilite(rMEvt) ) +#endif + && ( nEntry != nHighlightedItem ) ) + ChangeHighlightItem( nEntry, FALSE ); +} + +void MenuBarWindow::ChangeHighlightItem( USHORT n, BOOL bSelectEntry, BOOL bAllowRestoreFocus, BOOL bDefaultToDocument) +{ + if( ! pMenu ) + return; + + // #57934# ggf. das aktive Popup sofort schliessen, damit TH's Hintergrundsicherung funktioniert. + MenuItemData* pNextData = pMenu->pItemList->GetDataFromPos( n ); + if ( pActivePopup && pActivePopup->ImplGetWindow() && ( !pNextData || ( pActivePopup != pNextData->pSubMenu ) ) ) + KillActivePopup(); // pActivePopup ggf. ohne pWin, wenn in Activate() Rescheduled wurde + + // Activate am MenuBar immer nur einmal pro Vorgang... + BOOL bJustActivated = FALSE; + if ( ( nHighlightedItem == ITEMPOS_INVALID ) && ( n != ITEMPOS_INVALID ) ) + { + ImplGetSVData()->maWinData.mbNoDeactivate = TRUE; + if( !bStayActive ) + { + // #105406# avoid saving the focus when we already have the focus + BOOL bNoSaveFocus = (this == ImplGetSVData()->maWinData.mpFocusWin ); + + if( nSaveFocusId ) + { + if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) + { + // we didn't clean up last time + Window::EndSaveFocus( nSaveFocusId, FALSE ); // clean up + nSaveFocusId = 0; + if( !bNoSaveFocus ) + nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated + } + else { + ; // do nothing: we 're activated again from taskpanelist, focus was already saved + } + } + else + { + if( !bNoSaveFocus ) + nSaveFocusId = Window::SaveFocus(); // only save focus when initially activated + } + } + else + bStayActive = FALSE; + pMenu->bInCallback = TRUE; // hier schon setzen, falls Activate ueberladen + pMenu->Activate(); + pMenu->bInCallback = FALSE; + bJustActivated = TRUE; + } + else if ( ( nHighlightedItem != ITEMPOS_INVALID ) && ( n == ITEMPOS_INVALID ) ) + { + pMenu->bInCallback = TRUE; + pMenu->Deactivate(); + pMenu->bInCallback = FALSE; + ImplGetSVData()->maWinData.mbNoDeactivate = FALSE; + if( !ImplGetSVData()->maWinData.mbNoSaveFocus ) + { + ULONG nTempFocusId = nSaveFocusId; + nSaveFocusId = 0; + Window::EndSaveFocus( nTempFocusId, bAllowRestoreFocus ); + // #105406# restore focus to document if we could not save focus before + if( bDefaultToDocument && !nTempFocusId && bAllowRestoreFocus ) + GrabFocusToDocument(); + } + } + + if ( nHighlightedItem != ITEMPOS_INVALID ) + { + HighlightItem( nHighlightedItem, FALSE ); + pMenu->ImplCallEventListeners( VCLEVENT_MENU_DEHIGHLIGHT, nHighlightedItem ); + } + + nHighlightedItem = (USHORT)n; + DBG_ASSERT( ( nHighlightedItem == ITEMPOS_INVALID ) || pMenu->ImplIsVisible( nHighlightedItem ), "ChangeHighlightItem: Not visible!" ); + HighlightItem( nHighlightedItem, TRUE ); + pMenu->ImplCallHighlight( nHighlightedItem ); + + if( mbAutoPopup ) + ImplCreatePopup( bSelectEntry ); + + // #58935# #73659# Focus, wenn kein Popup drunter haengt... + if ( bJustActivated && !pActivePopup ) + GrabFocus(); +} + +void MenuBarWindow::HighlightItem( USHORT nPos, BOOL bHighlight ) +{ + if( ! pMenu ) + return; + + long nX = 0; + ULONG nCount = pMenu->pItemList->Count(); + for ( ULONG n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + if ( pData->eType != MENUITEM_SEPARATOR ) + { + // #107747# give menuitems the height of the menubar + Rectangle aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) ); + Push( PUSH_CLIPREGION ); + IntersectClipRegion( aRect ); + if ( bHighlight ) + { + if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) && + IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + // draw background (transparency) + MenubarValue aControlValue; + aControlValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + Point tmp(0,0); + Rectangle aBgRegion( tmp, GetOutputSizePixel() ); + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, + aBgRegion, + CTRL_STATE_ENABLED, + aControlValue, + OUString() ); + ImplAddNWFSeparator( this, aControlValue ); + + // draw selected item + DrawNativeControl( CTRL_MENUBAR, PART_MENU_ITEM, + aRect, + CTRL_STATE_ENABLED | CTRL_STATE_SELECTED, + aControlValue, + OUString() ); + } + else + { + SetFillColor( GetSettings().GetStyleSettings().GetMenuHighlightColor() ); + SetLineColor(); + DrawRect( aRect ); + } + } + else + { + if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) ) + { + MenubarValue aMenubarValue; + aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + // use full window size to get proper gradient + // but clip accordingly + Point aPt; + Rectangle aCtrlRect( aPt, GetOutputSizePixel() ); + + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRect, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() ); + ImplAddNWFSeparator( this, aMenubarValue ); + } + else + Erase( aRect ); + } + Pop(); + pMenu->ImplPaint( this, 0, 0, pData, bHighlight ); + } + return; + } + + nX += pData->aSz.Width(); + } +} + +Rectangle MenuBarWindow::ImplGetItemRect( USHORT nPos ) +{ + Rectangle aRect; + if( pMenu ) + { + long nX = 0; + ULONG nCount = pMenu->pItemList->Count(); + for ( ULONG n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( n == nPos ) + { + if ( pData->eType != MENUITEM_SEPARATOR ) + // #107747# give menuitems the height of the menubar + aRect = Rectangle( Point( nX, 1 ), Size( pData->aSz.Width(), GetOutputSizePixel().Height()-2 ) ); + break; + } + + nX += pData->aSz.Width(); + } + } + return aRect; +} + +void MenuBarWindow::KeyInput( const KeyEvent& rKEvent ) +{ + if ( !ImplHandleKeyEvent( rKEvent ) ) + Window::KeyInput( rKEvent ); +} + +BOOL MenuBarWindow::ImplHandleKeyEvent( const KeyEvent& rKEvent, BOOL bFromMenu ) +{ + if( ! pMenu ) + return FALSE; + + if ( pMenu->bInCallback ) + return TRUE; // schlucken + + BOOL bDone = FALSE; + USHORT nCode = rKEvent.GetKeyCode().GetCode(); + + if( GetParent() ) + { + if( GetParent()->GetWindow( WINDOW_CLIENT )->IsSystemWindow() ) + { + SystemWindow *pSysWin = (SystemWindow*)GetParent()->GetWindow( WINDOW_CLIENT ); + if( pSysWin->GetTaskPaneList() ) + if( pSysWin->GetTaskPaneList()->HandleKeyEvent( rKEvent ) ) + return TRUE; + } + } + + if ( nCode == KEY_MENU && !rKEvent.GetKeyCode().IsShift() ) // only F10, not Shift-F10 + { + mbAutoPopup = ImplGetSVData()->maNWFData.mbOpenMenuOnF10; + if ( nHighlightedItem == ITEMPOS_INVALID ) + { + ChangeHighlightItem( 0, FALSE ); + GrabFocus(); + } + else + { + ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + nSaveFocusId = 0; + } + bDone = TRUE; + } + else if ( bFromMenu ) + { + if ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) || + ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) + { + USHORT n = nHighlightedItem; + if ( n == ITEMPOS_INVALID ) + { + if ( nCode == KEY_LEFT) + n = 0; + else + n = pMenu->GetItemCount()-1; + } + + // handling gtk like (aka mbOpenMenuOnF10) + // do not highlight an item when opening a sub menu + // unless there already was a higlighted sub menu item + bool bWasHighlight = false; + if( pActivePopup ) + { + MenuFloatingWindow* pSubWindow = dynamic_cast<MenuFloatingWindow*>(pActivePopup->ImplGetWindow()); + if( pSubWindow ) + bWasHighlight = (pSubWindow->GetHighlightedItem() != ITEMPOS_INVALID); + } + + USHORT nLoop = n; + + if( nCode == KEY_HOME ) + { n = (USHORT)-1; nLoop = n+1; } + if( nCode == KEY_END ) + { n = pMenu->GetItemCount(); nLoop = n-1; } + + do + { + if ( nCode == KEY_LEFT || nCode == KEY_END ) + { + if ( n ) + n--; + else + n = pMenu->GetItemCount()-1; + } + if ( nCode == KEY_RIGHT || nCode == KEY_HOME ) + { + n++; + if ( n >= pMenu->GetItemCount() ) + n = 0; + } + + MenuItemData* pData = (MenuItemData*)pMenu->GetItemList()->GetDataFromPos( n ); + if ( ( pData->eType != MENUITEM_SEPARATOR ) && pMenu->ImplIsVisible( n ) ) + { + BOOL bDoSelect = TRUE; + if( ImplGetSVData()->maNWFData.mbOpenMenuOnF10 ) + bDoSelect = bWasHighlight; + ChangeHighlightItem( n, bDoSelect ); + break; + } + } while ( n != nLoop ); + bDone = TRUE; + } + else if ( nCode == KEY_RETURN ) + { + if( pActivePopup ) KillActivePopup(); + else + if ( !mbAutoPopup ) + { + ImplCreatePopup( TRUE ); + mbAutoPopup = TRUE; + } + bDone = TRUE; + } + else if ( ( nCode == KEY_UP ) || ( nCode == KEY_DOWN ) ) + { + if ( !mbAutoPopup ) + { + ImplCreatePopup( TRUE ); + mbAutoPopup = TRUE; + } + bDone = TRUE; + } + else if ( nCode == KEY_ESCAPE || ( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) ) + { + if( pActivePopup ) + { + // bring focus to menu bar without any open popup + mbAutoPopup = FALSE; + USHORT n = nHighlightedItem; + nHighlightedItem = ITEMPOS_INVALID; + bStayActive = TRUE; + ChangeHighlightItem( n, FALSE ); + bStayActive = FALSE; + KillActivePopup(); + GrabFocus(); + } + else + ChangeHighlightItem( ITEMPOS_INVALID, FALSE ); + + if( nCode == KEY_F6 && rKEvent.GetKeyCode().IsMod1() ) + { + // put focus into document + GrabFocusToDocument(); + } + + bDone = TRUE; + } + } + + if ( !bDone && ( bFromMenu || rKEvent.GetKeyCode().IsMod2() ) ) + { + xub_Unicode nCharCode = rKEvent.GetCharCode(); + if ( nCharCode ) + { + USHORT nEntry, nDuplicates; + MenuItemData* pData = pMenu->GetItemList()->SearchItem( nCharCode, rKEvent.GetKeyCode(), nEntry, nDuplicates, nHighlightedItem ); + if ( pData && (nEntry != ITEMPOS_INVALID) ) + { + mbAutoPopup = TRUE; + ChangeHighlightItem( nEntry, TRUE ); + bDone = TRUE; + } + else + { + // Wegen Systemmenu und anderen System-HotKeys, nur + // eigenstaendige Character-Kombinationen auswerten + USHORT nKeyCode = rKEvent.GetKeyCode().GetCode(); + if ( ((nKeyCode >= KEY_A) && (nKeyCode <= KEY_Z)) ) + Sound::Beep(); + } + } + } + return bDone; +} + +void MenuBarWindow::Paint( const Rectangle& ) +{ + if( ! pMenu ) + return; + + // no VCL paint if native menus + if( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) + { + ImplGetFrame()->DrawMenuBar(); + return; + } + + if( IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) ) + { + Point aPt; + Rectangle aCtrlRegion( aPt, GetOutputSizePixel() ); + + MenubarValue aMenubarValue; + aMenubarValue.maTopDockingAreaHeight = ImplGetTopDockingAreaHeight( this ); + + DrawNativeControl( CTRL_MENUBAR, PART_ENTIRE_CONTROL, aCtrlRegion, CTRL_STATE_ENABLED, aMenubarValue, rtl::OUString() ); + ImplAddNWFSeparator( this, aMenubarValue ); + } + SetFillColor( GetSettings().GetStyleSettings().GetMenuColor() ); + pMenu->ImplPaint( this, 0 ); + if ( nHighlightedItem != ITEMPOS_INVALID ) + HighlightItem( nHighlightedItem, TRUE ); + + // in high contrast mode draw a separating line on the lower edge + if( ! IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL) && + GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + Push( PUSH_LINECOLOR | PUSH_MAPMODE ); + SetLineColor( Color( COL_WHITE ) ); + SetMapMode( MapMode( MAP_PIXEL ) ); + Size aSize = GetSizePixel(); + DrawLine( Point( 0, aSize.Height()-1 ), Point( aSize.Width()-1, aSize.Height()-1 ) ); + Pop(); + } + +} + +void MenuBarWindow::Resize() +{ + Size aOutSz = GetOutputSizePixel(); + long n = aOutSz.Height()-4; + long nX = aOutSz.Width()-3; + long nY = 2; + + if ( aCloser.IsVisible() ) + { + aCloser.Hide(); + aCloser.SetImages( n ); + Size aTbxSize( aCloser.CalcWindowSizePixel() ); + nX -= aTbxSize.Width(); + long nTbxY = (aOutSz.Height() - aTbxSize.Height())/2; + aCloser.SetPosSizePixel( nX, nTbxY, aTbxSize.Width(), aTbxSize.Height() ); + nX -= 3; + aCloser.Show(); + } + if ( aFloatBtn.IsVisible() ) + { + nX -= n; + aFloatBtn.SetPosSizePixel( nX, nY, n, n ); + } + if ( aHideBtn.IsVisible() ) + { + nX -= n; + aHideBtn.SetPosSizePixel( nX, nY, n, n ); + } + + aFloatBtn.SetSymbol( SYMBOL_FLOAT ); + aHideBtn.SetSymbol( SYMBOL_HIDE ); + //aCloser.SetSymbol( SYMBOL_CLOSE ); //is a toolbox now + + Invalidate(); +} + +USHORT MenuBarWindow::ImplFindEntry( const Point& rMousePos ) const +{ + if( pMenu ) + { + long nX = 0; + USHORT nCount = (USHORT)pMenu->pItemList->Count(); + for ( USHORT n = 0; n < nCount; n++ ) + { + MenuItemData* pData = pMenu->pItemList->GetDataFromPos( n ); + if ( pMenu->ImplIsVisible( n ) ) + { + nX += pData->aSz.Width(); + if ( nX > rMousePos.X() ) + return (USHORT)n; + } + } + } + return ITEMPOS_INVALID; +} + +void MenuBarWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + USHORT nId = nHighlightedItem; + if ( rHEvt.GetMode() & (HELPMODE_CONTEXT | HELPMODE_EXTENDED) ) + ChangeHighlightItem( ITEMPOS_INVALID, TRUE ); + + Rectangle aHighlightRect( ImplGetItemRect( nHighlightedItem ) ); + if( !ImplHandleHelpEvent( this, pMenu, nId, rHEvt, aHighlightRect ) ) + Window::RequestHelp( rHEvt ); +} + +void MenuBarWindow::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( ( nType == STATE_CHANGE_CONTROLFOREGROUND ) || + ( nType == STATE_CHANGE_CONTROLBACKGROUND ) ) + { + ImplInitMenuWindow( this, FALSE, TRUE ); + Invalidate(); + } + else if( pMenu ) + pMenu->ImplKillLayoutData(); + +} + +void MenuBarWindow::ImplLayoutChanged() +{ + if( pMenu ) + { + ImplInitMenuWindow( this, TRUE, TRUE ); + // Falls sich der Font geaendert hat. + long nHeight = pMenu->ImplCalcSize( this ).Height(); + + // depending on the native implementation or the displayable flag + // the menubar windows is supressed (ie, height=0) + if( !((MenuBar*) pMenu)->IsDisplayable() || + ( pMenu->ImplGetSalMenu() && pMenu->ImplGetSalMenu()->VisibleMenuBar() ) ) + nHeight = 0; + + SetPosSizePixel( 0, 0, 0, nHeight, WINDOW_POSSIZE_HEIGHT ); + GetParent()->Resize(); + Invalidate(); + Resize(); + if( pMenu ) + pMenu->ImplKillLayoutData(); + } +} + +void MenuBarWindow::ImplInitStyleSettings() +{ + if( IsNativeControlSupported( CTRL_MENUBAR, PART_MENU_ITEM ) && + IsNativeControlSupported( CTRL_MENUBAR, PART_ENTIRE_CONTROL ) ) + { + Color aHighlightTextColor = ImplGetSVData()->maNWFData.maMenuBarHighlightTextColor; + if( aHighlightTextColor != Color( COL_TRANSPARENT ) ) + { + AllSettings aSettings( GetSettings() ); + StyleSettings aStyle( aSettings.GetStyleSettings() ); + aStyle.SetMenuHighlightTextColor( aHighlightTextColor ); + aSettings.SetStyleSettings( aStyle ); + OutputDevice::SetSettings( aSettings ); + } + } +} + +void MenuBarWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + ImplLayoutChanged(); + ImplInitStyleSettings(); + } +} + +void MenuBarWindow::LoseFocus() +{ + if ( !HasChildPathFocus( TRUE ) ) + ChangeHighlightItem( ITEMPOS_INVALID, FALSE, FALSE ); +} + +void MenuBarWindow::GetFocus() +{ + if ( nHighlightedItem == ITEMPOS_INVALID ) + { + mbAutoPopup = FALSE; // do not open menu when activated by focus handling like taskpane cycling + ChangeHighlightItem( 0, FALSE ); + } +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > MenuBarWindow::CreateAccessible() +{ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc; + + if ( pMenu ) + xAcc = pMenu->GetAccessible(); + + return xAcc; +} + +USHORT MenuBarWindow::AddMenuBarButton( const Image& i_rImage, const Link& i_rLink, const String& i_rToolTip, USHORT i_nPos ) +{ + // find first free button id + USHORT nId = IID_DOCUMENTCLOSE; + std::map< USHORT, AddButtonEntry >::const_iterator it; + if( i_nPos > m_aAddButtons.size() ) + i_nPos = static_cast<USHORT>(m_aAddButtons.size()); + do + { + nId++; + it = m_aAddButtons.find( nId ); + } while( it != m_aAddButtons.end() && nId < 128 ); + DBG_ASSERT( nId < 128, "too many addbuttons in menubar" ); + AddButtonEntry& rNewEntry = m_aAddButtons[nId]; + rNewEntry.m_nId = nId; + rNewEntry.m_aSelectLink = i_rLink; + aCloser.InsertItem( nId, i_rImage, 0, 0 ); + aCloser.calcMinSize(); + ShowButtons( aCloser.IsItemVisible( IID_DOCUMENTCLOSE ), + aFloatBtn.IsVisible(), + aHideBtn.IsVisible() ); + ImplLayoutChanged(); + + if( pMenu->mpSalMenu ) + pMenu->mpSalMenu->AddMenuBarButton( SalMenuButtonItem( nId, i_rImage, i_rToolTip ) ); + + return nId; +} + +void MenuBarWindow::SetMenuBarButtonHighlightHdl( USHORT nId, const Link& rLink ) +{ + std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( nId ); + if( it != m_aAddButtons.end() ) + it->second.m_aHighlightLink = rLink; +} + +Rectangle MenuBarWindow::GetMenuBarButtonRectPixel( USHORT nId ) +{ + Rectangle aRect; + if( m_aAddButtons.find( nId ) != m_aAddButtons.end() ) + { + if( pMenu->mpSalMenu ) + { + aRect = pMenu->mpSalMenu->GetMenuBarButtonRectPixel( nId, ImplGetWindowImpl()->mpFrame ); + if( aRect == Rectangle( Point( -1, -1 ), Size( 1, 1 ) ) ) + { + // system menu button is somehwere but location cannot be determined + return Rectangle(); + } + } + + if( aRect.IsEmpty() ) + { + aRect = aCloser.GetItemRect( nId ); + Point aOffset = aCloser.OutputToScreenPixel( Point() ); + aRect.Move( aOffset.X(), aOffset.Y() ); + } + } + return aRect; +} + +void MenuBarWindow::RemoveMenuBarButton( USHORT nId ) +{ + USHORT nPos = aCloser.GetItemPos( nId ); + aCloser.RemoveItem( nPos ); + m_aAddButtons.erase( nId ); + aCloser.calcMinSize(); + ImplLayoutChanged(); + + if( pMenu->mpSalMenu ) + pMenu->mpSalMenu->RemoveMenuBarButton( nId ); +} + +bool MenuBarWindow::HandleMenuButtonEvent( USHORT i_nButtonId ) +{ + std::map< USHORT, AddButtonEntry >::iterator it = m_aAddButtons.find( i_nButtonId ); + if( it != m_aAddButtons.end() ) + { + MenuBar::MenuBarButtonCallbackArg aArg; + aArg.nId = it->first; + aArg.bHighlight = true; + aArg.pMenuBar = dynamic_cast<MenuBar*>(pMenu); + return it->second.m_aSelectLink.Call( &aArg ); + } + return FALSE; +} + +ImplMenuDelData::ImplMenuDelData( const Menu* pMenu ) +: mpNext( 0 ) +, mpMenu( 0 ) +{ + if( pMenu ) + const_cast< Menu* >( pMenu )->ImplAddDel( *this ); +} + +ImplMenuDelData::~ImplMenuDelData() +{ + if( mpMenu ) + const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this ); +} diff --git a/vcl/source/window/mnemonic.cxx b/vcl/source/window/mnemonic.cxx new file mode 100644 index 000000000000..c2c6c18135f2 --- /dev/null +++ b/vcl/source/window/mnemonic.cxx @@ -0,0 +1,419 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <string.h> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/mnemonic.hxx> + +#include <vcl/unohelp.hxx> +#include <com/sun/star/i18n/XCharacterClassification.hpp> + +using namespace ::com::sun::star; + + +// ======================================================================= + +MnemonicGenerator::MnemonicGenerator() +{ + memset( maMnemonics, 1, sizeof( maMnemonics ) ); +} + +// ----------------------------------------------------------------------- + +USHORT MnemonicGenerator::ImplGetMnemonicIndex( sal_Unicode c ) +{ + static USHORT const aImplMnemonicRangeTab[MNEMONIC_RANGES*2] = + { + MNEMONIC_RANGE_1_START, MNEMONIC_RANGE_1_END, + MNEMONIC_RANGE_2_START, MNEMONIC_RANGE_2_END, + MNEMONIC_RANGE_3_START, MNEMONIC_RANGE_3_END, + MNEMONIC_RANGE_4_START, MNEMONIC_RANGE_4_END + }; + + USHORT nMnemonicIndex = 0; + for ( USHORT i = 0; i < MNEMONIC_RANGES; i++ ) + { + if ( (c >= aImplMnemonicRangeTab[i*2]) && + (c <= aImplMnemonicRangeTab[i*2+1]) ) + return nMnemonicIndex+c-aImplMnemonicRangeTab[i*2]; + + nMnemonicIndex += aImplMnemonicRangeTab[i*2+1]-aImplMnemonicRangeTab[i*2]; + } + + return MNEMONIC_INDEX_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +sal_Unicode MnemonicGenerator::ImplFindMnemonic( const XubString& rKey ) +{ + xub_StrLen nIndex = 0; + while ( (nIndex = rKey.Search( MNEMONIC_CHAR, nIndex )) != STRING_NOTFOUND ) + { + sal_Unicode cMnemonic = rKey.GetChar( nIndex+1 ); + if ( cMnemonic != MNEMONIC_CHAR ) + return cMnemonic; + nIndex += 2; + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void MnemonicGenerator::RegisterMnemonic( const XubString& rKey ) +{ + const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale(); + uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass(); + + // Don't crash even when we don't have access to i18n service + if ( !xCharClass.is() ) + return; + + XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale ); + + // If we find a Mnemonic, set the flag. In other case count the + // characters, because we need this to set most as possible + // Mnemonics + sal_Unicode cMnemonic = ImplFindMnemonic( aKey ); + if ( cMnemonic ) + { + USHORT nMnemonicIndex = ImplGetMnemonicIndex( cMnemonic ); + if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) + maMnemonics[nMnemonicIndex] = 0; + } + else + { + xub_StrLen nIndex = 0; + xub_StrLen nLen = aKey.Len(); + while ( nIndex < nLen ) + { + sal_Unicode c = aKey.GetChar( nIndex ); + + USHORT nMnemonicIndex = ImplGetMnemonicIndex( c ); + if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) + { + if ( maMnemonics[nMnemonicIndex] && (maMnemonics[nMnemonicIndex] < 0xFF) ) + maMnemonics[nMnemonicIndex]++; + } + + nIndex++; + } + } +} + +// ----------------------------------------------------------------------- + +BOOL MnemonicGenerator::CreateMnemonic( XubString& rKey ) +{ + if ( !rKey.Len() || ImplFindMnemonic( rKey ) ) + return FALSE; + + const ::com::sun::star::lang::Locale& rLocale = Application::GetSettings().GetUILocale(); + uno::Reference < i18n::XCharacterClassification > xCharClass = GetCharClass(); + + // Don't crash even when we don't have access to i18n service + if ( !xCharClass.is() ) + return FALSE; + + XubString aKey = xCharClass->toUpper( rKey, 0, rKey.Len(), rLocale ); + + BOOL bChanged = FALSE; + xub_StrLen nLen = aKey.Len(); + + BOOL bCJK = FALSE; + switch( Application::GetSettings().GetUILanguage() ) + { + case LANGUAGE_JAPANESE: + case LANGUAGE_CHINESE_TRADITIONAL: + case LANGUAGE_CHINESE_SIMPLIFIED: + case LANGUAGE_CHINESE_HONGKONG: + case LANGUAGE_CHINESE_SINGAPORE: + case LANGUAGE_CHINESE_MACAU: + case LANGUAGE_KOREAN: + case LANGUAGE_KOREAN_JOHAB: + bCJK = TRUE; + break; + default: + break; + } + // #107889# in CJK versions ALL strings (even those that contain latin characters) + // will get mnemonics in the form: xyz (M) + // thus steps 1) and 2) are skipped for CJK locales + + // #110720#, avoid CJK-style mnemonics for latin-only strings that do not contain useful mnemonic chars + if( bCJK ) + { + BOOL bLatinOnly = TRUE; + BOOL bMnemonicIndexFound = FALSE; + sal_Unicode c; + xub_StrLen nIndex; + + for( nIndex=0; nIndex < nLen; nIndex++ ) + { + c = aKey.GetChar( nIndex ); + if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk + ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms + { + bLatinOnly = FALSE; + break; + } + if( ImplGetMnemonicIndex( c ) != MNEMONIC_INDEX_NOTFOUND ) + bMnemonicIndexFound = TRUE; + } + if( bLatinOnly && !bMnemonicIndexFound ) + return FALSE; + } + + + int nCJK = 0; + USHORT nMnemonicIndex; + sal_Unicode c; + xub_StrLen nIndex = 0; + if( !bCJK ) + { + // 1) first try the first character of a word + do + { + c = aKey.GetChar( nIndex ); + + if ( nCJK != 2 ) + { + if ( ((c >= 0x3000) && (c <= 0xD7FF)) || // cjk + ((c >= 0xFF61) && (c <= 0xFFDC)) ) // halfwidth forms + nCJK = 1; + else if ( ((c >= 0x0030) && (c <= 0x0039)) || // digits + ((c >= 0x0041) && (c <= 0x005A)) || // latin capitals + ((c >= 0x0061) && (c <= 0x007A)) || // latin small + ((c >= 0x0370) && (c <= 0x037F)) || // greek numeral signs + ((c >= 0x0400) && (c <= 0x04FF)) ) // cyrillic + nCJK = 2; + } + + nMnemonicIndex = ImplGetMnemonicIndex( c ); + if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) + { + if ( maMnemonics[nMnemonicIndex] ) + { + maMnemonics[nMnemonicIndex] = 0; + rKey.Insert( MNEMONIC_CHAR, nIndex ); + bChanged = TRUE; + break; + } + } + + // Search for next word + do + { + nIndex++; + c = aKey.GetChar( nIndex ); + if ( c == ' ' ) + break; + } + while ( nIndex < nLen ); + nIndex++; + } + while ( nIndex < nLen ); + + // 2) search for a unique/uncommon character + if ( !bChanged ) + { + USHORT nBestCount = 0xFFFF; + USHORT nBestMnemonicIndex = 0; + xub_StrLen nBestIndex = 0; + nIndex = 0; + do + { + c = aKey.GetChar( nIndex ); + nMnemonicIndex = ImplGetMnemonicIndex( c ); + if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) + { + if ( maMnemonics[nMnemonicIndex] ) + { + if ( maMnemonics[nMnemonicIndex] < nBestCount ) + { + nBestCount = maMnemonics[nMnemonicIndex]; + nBestIndex = nIndex; + nBestMnemonicIndex = nMnemonicIndex; + if ( nBestCount == 2 ) + break; + } + } + } + + nIndex++; + } + while ( nIndex < nLen ); + + if ( nBestCount != 0xFFFF ) + { + maMnemonics[nBestMnemonicIndex] = 0; + rKey.Insert( MNEMONIC_CHAR, nBestIndex ); + bChanged = TRUE; + } + } + } + else + nCJK = 1; + + // 3) Add English Mnemonic for CJK Text + if ( !bChanged && (nCJK == 1) && rKey.Len() ) + { + // Append Ascii Mnemonic + for ( c = MNEMONIC_RANGE_2_START; c <= MNEMONIC_RANGE_2_END; c++ ) + { + nMnemonicIndex = ImplGetMnemonicIndex( c ); + if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) + { + if ( maMnemonics[nMnemonicIndex] ) + { + maMnemonics[nMnemonicIndex] = 0; + UniString aStr( '(' ); + aStr += MNEMONIC_CHAR; + aStr += c; + aStr += ')'; + nIndex = rKey.Len(); + if( nIndex >= 2 ) + { + static sal_Unicode cGreaterGreater[] = { 0xFF1E, 0xFF1E }; + if ( rKey.EqualsAscii( ">>", nIndex-2, 2 ) || + rKey.Equals( cGreaterGreater, nIndex-2, 2 ) ) + nIndex -= 2; + } + if( nIndex >= 3 ) + { + static sal_Unicode cDotDotDot[] = { 0xFF0E, 0xFF0E, 0xFF0E }; + if ( rKey.EqualsAscii( "...", nIndex-3, 3 ) || + rKey.Equals( cDotDotDot, nIndex-3, 3 ) ) + nIndex -= 3; + } + if( nIndex >= 1) + { + sal_Unicode cLastChar = rKey.GetChar( nIndex-1 ); + if ( (cLastChar == ':') || (cLastChar == 0xFF1A) || + (cLastChar == '.') || (cLastChar == 0xFF0E) || + (cLastChar == '?') || (cLastChar == 0xFF1F) || + (cLastChar == ' ') ) + nIndex--; + } + rKey.Insert( aStr, nIndex ); + bChanged = TRUE; + break; + } + } + } + } + +// #i87415# Duplicates mnemonics are bad for consistent keyboard accessibility +// It's probably better to not have mnemonics for some widgets, than to have ambiguous ones. +// if( ! bChanged ) +// { +// /* +// * #97809# if all else fails use the first character of a word +// * anyway and live with duplicate mnemonics +// */ +// nIndex = 0; +// do +// { +// c = aKey.GetChar( nIndex ); +// +// nMnemonicIndex = ImplGetMnemonicIndex( c ); +// if ( nMnemonicIndex != MNEMONIC_INDEX_NOTFOUND ) +// { +// maMnemonics[nMnemonicIndex] = 0; +// rKey.Insert( MNEMONIC_CHAR, nIndex ); +// bChanged = TRUE; +// break; +// } +// +// // Search for next word +// do +// { +// nIndex++; +// c = aKey.GetChar( nIndex ); +// if ( c == ' ' ) +// break; +// } +// while ( nIndex < nLen ); +// nIndex++; +// } +// while ( nIndex < nLen ); +// } + + return bChanged; +} + +// ----------------------------------------------------------------------- + +uno::Reference< i18n::XCharacterClassification > MnemonicGenerator::GetCharClass() +{ + if ( !mxCharClass.is() ) + mxCharClass = vcl::unohelper::CreateCharacterClassification(); + return mxCharClass; +} + +// ----------------------------------------------------------------------- + +String MnemonicGenerator::EraseAllMnemonicChars( const String& rStr ) +{ + String aStr = rStr; + xub_StrLen nLen = aStr.Len(); + xub_StrLen i = 0; + + while ( i < nLen ) + { + if ( aStr.GetChar( i ) == '~' ) + { + // check for CJK-style mnemonic + if( i > 0 && (i+2) < nLen ) + { + sal_Unicode c = aStr.GetChar(i+1); + if( aStr.GetChar( i-1 ) == '(' && + aStr.GetChar( i+2 ) == ')' && + c >= MNEMONIC_RANGE_2_START && c <= MNEMONIC_RANGE_2_END ) + { + aStr.Erase( i-1, 4 ); + nLen -= 4; + i--; + continue; + } + } + + // remove standard mnemonics + aStr.Erase( i, 1 ); + nLen--; + } + else + i++; + } + + return aStr; +} diff --git a/vcl/source/window/mnemonicengine.cxx b/vcl/source/window/mnemonicengine.cxx new file mode 100644 index 000000000000..241aea1cf336 --- /dev/null +++ b/vcl/source/window/mnemonicengine.cxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <vcl/mnemonicengine.hxx> + +#include <vcl/i18nhelp.hxx> +#include <vcl/svapp.hxx> +#include <vcl/event.hxx> + +//........................................................................ +namespace vcl +{ +//........................................................................ + + //==================================================================== + //= MnemonicEngine_Data + //==================================================================== + struct MnemonicEngine_Data + { + IMnemonicEntryList& rEntryList; + + MnemonicEngine_Data( IMnemonicEntryList& _rEntryList ) + :rEntryList( _rEntryList ) + { + } + }; + + //-------------------------------------------------------------------- + namespace + { + const void* lcl_getEntryForMnemonic( IMnemonicEntryList& _rEntryList, sal_Unicode _cMnemonic, bool& _rbAmbiguous ) + { + _rbAmbiguous = false; + + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + + String sEntryText; + const void* pSearchEntry = _rEntryList.FirstSearchEntry( sEntryText ); + + const void* pFirstFoundEntry = NULL; + bool bCheckingAmbiguity = false; + const void* pStartedWith = pSearchEntry; + while ( pSearchEntry ) + { + if ( rI18nHelper.MatchMnemonic( sEntryText, _cMnemonic ) ) + { + if ( bCheckingAmbiguity ) + { + // that's the second (at least) entry with this mnemonic + _rbAmbiguous = true; + return pFirstFoundEntry; + } + + pFirstFoundEntry = pSearchEntry; + bCheckingAmbiguity = true; + } + + pSearchEntry = _rEntryList.NextSearchEntry( pSearchEntry, sEntryText ); + if ( pSearchEntry == pStartedWith ) + break; + } + + return pFirstFoundEntry; + } + } + + //==================================================================== + //= MnemonicEngine + //==================================================================== + //-------------------------------------------------------------------- + MnemonicEngine::MnemonicEngine( IMnemonicEntryList& _rEntryList ) + :m_pData( new MnemonicEngine_Data( _rEntryList ) ) + { + } + + //-------------------------------------------------------------------- + bool MnemonicEngine::HandleKeyEvent( const KeyEvent& _rKEvt ) + { + BOOL bAccelKey = _rKEvt.GetKeyCode().IsMod2(); + if ( !bAccelKey ) + return false; + + sal_Unicode cChar = _rKEvt.GetCharCode(); + bool bAmbiguous = false; + const void* pEntry = lcl_getEntryForMnemonic( m_pData->rEntryList, cChar, bAmbiguous ); + if ( !pEntry ) + return false; + + m_pData->rEntryList.SelectSearchEntry( pEntry ); + if ( !bAmbiguous ) + m_pData->rEntryList.ExecuteSearchEntry( pEntry ); + + // handled + return true; + } + + //-------------------------------------------------------------------- + MnemonicEngine::~MnemonicEngine() + { + } + +//........................................................................ +} // namespace vcl +//........................................................................ diff --git a/vcl/source/window/mouseevent.cxx b/vcl/source/window/mouseevent.cxx new file mode 100644 index 000000000000..4bfe08b3f3d8 --- /dev/null +++ b/vcl/source/window/mouseevent.cxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <com/sun/star/awt/MouseEvent.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <tools/debug.hxx> +#include <vcl/event.hxx> + +/** inits this vcl KeyEvent with all settings from the given awt event **/ +MouseEvent::MouseEvent( const ::com::sun::star::awt::MouseEvent& rEvent ) +: maPos( rEvent.X, rEvent.Y ) +, mnMode( 0 ) +, mnClicks( static_cast< USHORT >( rEvent.ClickCount ) ) +, mnCode( 0 ) +{ + if( rEvent.Modifiers ) + { + if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::SHIFT) != 0 ) + mnCode |= KEY_SHIFT; + if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD1) != 0 ) + mnCode |= KEY_MOD1; + if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD2) != 0 ) + mnCode |= KEY_MOD2; + if( (rEvent.Modifiers & ::com::sun::star::awt::KeyModifier::MOD3) != 0 ) + mnCode |= KEY_MOD3; + } + + if( rEvent.Buttons ) + { + if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::LEFT) != 0 ) + mnCode |= MOUSE_LEFT; + if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::RIGHT) != 0 ) + mnCode |= MOUSE_RIGHT; + if( (rEvent.Buttons & ::com::sun::star::awt::MouseButton::MIDDLE) != 0 ) + mnCode |= MOUSE_MIDDLE; + } +} + +/** fills out the given awt KeyEvent with all settings from this vcl event **/ +void MouseEvent::InitMouseEvent( ::com::sun::star::awt::MouseEvent& rEvent ) const +{ + rEvent.Modifiers = 0; + if ( IsShift() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::SHIFT; + if ( IsMod1() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD1; + if ( IsMod2() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD2; + if ( IsMod3() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD3; + + rEvent.Buttons = 0; + if ( IsLeft() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::LEFT; + if ( IsRight() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::RIGHT; + if ( IsMiddle() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::MIDDLE; + + rEvent.X = GetPosPixel().X(); + rEvent.Y = GetPosPixel().Y(); + rEvent.ClickCount = GetClicks(); + rEvent.PopupTrigger = sal_False; +} diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx new file mode 100644 index 000000000000..d00d569883d5 --- /dev/null +++ b/vcl/source/window/msgbox.cxx @@ -0,0 +1,693 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVIDS_HRC +#include <vcl/svids.hrc> +#endif +#include <vcl/svdata.hxx> +#include <vcl/metric.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/fixed.hxx> +#include <vcl/sound.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/button.hxx> +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/mnemonic.hxx> +#include <vcl/window.h> + + + +// ======================================================================= + +static void ImplInitMsgBoxImageList() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maWinData.mpMsgBoxImgList ) + { + ResMgr* pResMgr = ImplGetResMgr(); + pSVData->maWinData.mpMsgBoxImgList = new ImageList(4); + pSVData->maWinData.mpMsgBoxHCImgList = new ImageList(4); + if( pResMgr ) + { + Color aNonAlphaMask( 0xC0, 0xC0, 0xC0 ); + pSVData->maWinData.mpMsgBoxImgList->InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_MSGBOX, *pResMgr ), 4, &aNonAlphaMask ); + pSVData->maWinData.mpMsgBoxHCImgList->InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_MSGBOX_HC, *pResMgr ), 4, &aNonAlphaMask ); + } + } +} + +// ======================================================================= + +void MessBox::ImplInitMessBoxData() +{ + mpFixedText = NULL; + mpFixedImage = NULL; + mnSoundType = 0; + mbHelpBtn = FALSE; + mbSound = TRUE; + mpCheckBox = NULL; + mbCheck = FALSE; +} + +// ----------------------------------------------------------------------- + +void MessBox::ImplInitButtons() +{ + WinBits nStyle = GetStyle(); + USHORT nOKFlags = BUTTONDIALOG_OKBUTTON; + USHORT nCancelFlags = BUTTONDIALOG_CANCELBUTTON; + USHORT nRetryFlags = 0; + USHORT nYesFlags = 0; + USHORT nNoFlags = 0; + + if ( nStyle & WB_OK_CANCEL ) + { + if ( nStyle & WB_DEF_CANCEL ) + nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else // WB_DEF_OK + nOKFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + + AddButton( BUTTON_OK, BUTTONID_OK, nOKFlags ); + AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags ); + } + else if ( nStyle & WB_YES_NO ) + { + if ( nStyle & WB_DEF_YES ) + nYesFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else // WB_DEF_NO + nNoFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + nNoFlags |= BUTTONDIALOG_CANCELBUTTON; + + AddButton( BUTTON_YES, BUTTONID_YES, nYesFlags ); + AddButton( BUTTON_NO, BUTTONID_NO, nNoFlags ); + } + else if ( nStyle & WB_YES_NO_CANCEL ) + { + if ( nStyle & WB_DEF_YES ) + nYesFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else if ( nStyle & WB_DEF_NO ) + nNoFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else + nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + + AddButton( BUTTON_YES, BUTTONID_YES, nYesFlags ); + AddButton( BUTTON_NO, BUTTONID_NO, nNoFlags ); + AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags ); + } + else if ( nStyle & WB_RETRY_CANCEL ) + { + if ( nStyle & WB_DEF_CANCEL ) + nCancelFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else // WB_DEF_RETRY + nRetryFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + + AddButton( BUTTON_RETRY, BUTTONID_RETRY, nRetryFlags ); + AddButton( BUTTON_CANCEL, BUTTONID_CANCEL, nCancelFlags ); + } + else if ( nStyle & WB_ABORT_RETRY_IGNORE ) + { + USHORT nAbortFlags = 0; + USHORT nIgnoreFlags = 0; + + if ( nStyle & WB_DEF_CANCEL ) + nAbortFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else if ( nStyle & WB_DEF_RETRY ) + nRetryFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + else if ( nStyle & WB_DEF_IGNORE ) + nIgnoreFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + + AddButton( BUTTON_ABORT, BUTTONID_CANCEL, nAbortFlags ); + AddButton( BUTTON_RETRY, BUTTONID_RETRY, nRetryFlags ); + AddButton( BUTTON_IGNORE, BUTTONID_IGNORE, nIgnoreFlags ); + } + else if ( nStyle & WB_OK ) + { + nOKFlags |= BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_FOCUSBUTTON; + + AddButton( BUTTON_OK, BUTTONID_OK, nOKFlags ); + } +} + +// ----------------------------------------------------------------------- + +MessBox::MessBox( WindowType ) : + ButtonDialog( WINDOW_MESSBOX ) +{ + ImplInitMessBoxData(); +} + +// ----------------------------------------------------------------------- + +MessBox::MessBox( Window* pParent, WinBits nStyle, + const XubString& rTitle, const XubString& rMessage ) : + ButtonDialog( WINDOW_MESSBOX ), + maMessText( rMessage ) +{ + ImplInitMessBoxData(); + ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER ); + ImplInitButtons(); + + if ( rTitle.Len() ) + SetText( rTitle ); +} + +// ----------------------------------------------------------------------- + +MessBox::MessBox( Window* pParent, const ResId& rResId ) : + ButtonDialog( WINDOW_MESSBOX ) +{ + ImplInitMessBoxData(); + + GetRes( rResId.SetRT( RSC_MESSBOX ) ); + USHORT nHiButtons = ReadShortRes(); + USHORT nLoButtons = ReadShortRes(); + USHORT nHiDefButton = ReadShortRes(); + USHORT nLoDefButton = ReadShortRes(); + rtl::OString aHelpId( ReadByteStringRes() ); + /* USHORT bSysModal = */ ReadShortRes(); + SetHelpId( aHelpId ); + WinBits nBits = (((ULONG)nHiButtons << 16) + nLoButtons) | + (((ULONG)nHiDefButton << 16) + nLoDefButton); + ImplInit( pParent, nBits | WB_MOVEABLE | WB_HORZ | WB_CENTER ); + + ImplLoadRes( rResId ); + ImplInitButtons(); +} + +// ----------------------------------------------------------------------- + +void MessBox::ImplLoadRes( const ResId& ) +{ + SetText( ReadStringRes() ); + SetMessText( ReadStringRes() ); + SetHelpText( ReadStringRes() ); +} + +// ----------------------------------------------------------------------- + +MessBox::~MessBox() +{ + if ( mpFixedText ) + delete mpFixedText; + if ( mpFixedImage ) + delete mpFixedImage; + if ( mpCheckBox ) + delete mpCheckBox; +} + +// ----------------------------------------------------------------------- + +void MessBox::ImplPosControls() +{ + if ( GetHelpId().getLength() ) + { + if ( !mbHelpBtn ) + { + AddButton( BUTTON_HELP, BUTTONID_HELP, BUTTONDIALOG_HELPBUTTON, 3 ); + mbHelpBtn = TRUE; + } + } + else + { + if ( mbHelpBtn ) + { + RemoveButton( BUTTONID_HELP ); + mbHelpBtn = FALSE; + } + } + + XubString aMessText( maMessText ); + TextRectInfo aTextInfo; + Rectangle aRect( 0, 0, 30000, 30000 ); + Rectangle aFormatRect; + Point aTextPos( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+IMPL_MSGBOX_OFFSET_EXTRA_Y ); + Size aImageSize; + Size aPageSize; + Size aFixedSize; + long nTitleWidth; + long nButtonSize = ImplGetButtonSize(); + long nMaxWidth = GetDesktopRectPixel().GetWidth()-8; + long nMaxLineWidth; + long nWidth; + WinBits nWinStyle = WB_LEFT | WB_WORDBREAK | WB_NOLABEL | WB_INFO; + USHORT nTextStyle = TEXT_DRAW_MULTILINE | TEXT_DRAW_TOP | TEXT_DRAW_LEFT; + + if ( mpFixedText ) + delete mpFixedText; + if ( mpFixedImage ) + { + delete mpFixedImage; + mpFixedImage = NULL; + } + if ( mpCheckBox ) + { + mbCheck = mpCheckBox->IsChecked(); + delete mpCheckBox; + mpCheckBox = NULL; + } + + + // Message-Text um Tabs bereinigen + XubString aTabStr( RTL_CONSTASCII_USTRINGPARAM( " " ) ); + USHORT nIndex = 0; + while ( nIndex != STRING_NOTFOUND ) + nIndex = aMessText.SearchAndReplace( '\t', aTabStr, nIndex ); + + // Wenn Fenster zu schmall, machen wir Dialog auch breiter + if ( mpWindowImpl->mbFrame ) + nMaxWidth = 630; + else if ( nMaxWidth < 120 ) + nMaxWidth = 120; + + nMaxWidth -= mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder+4; + + // MessageBox sollte min. so breit sein, das auch Title sichtbar ist + // Extra-Width for Closer, because Closer is set after this call + nTitleWidth = CalcTitleWidth(); + nTitleWidth += mpWindowImpl->mnTopBorder; + + nMaxWidth -= (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2); + + // Wenn wir ein Image haben, dann deren Groesse ermitteln und das + // entsprechende Control anlegen und positionieren + aImageSize = maImage.GetSizePixel(); + if ( aImageSize.Width() ) + { + aImageSize.Width() += 4; + aImageSize.Height() += 4; + aTextPos.X() += aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE; + mpFixedImage = new FixedImage( this ); + mpFixedImage->SetPosSizePixel( Point( IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_X, + IMPL_DIALOG_OFFSET-2+IMPL_MSGBOX_OFFSET_EXTRA_Y ), + aImageSize ); + mpFixedImage->SetImage( maImage ); + // forward the HC image + if( !!maImageHC ) + mpFixedImage->SetModeImage( maImageHC, BMP_COLOR_HIGHCONTRAST ); + mpFixedImage->Show(); + nMaxWidth -= aImageSize.Width()+IMPL_SEP_MSGBOX_IMAGE; + } + else + aTextPos.X() += IMPL_MSGBOX_OFFSET_EXTRA_X; + + // Maximale Zeilenlaenge ohne Wordbreak ermitteln + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + nMaxLineWidth = aFormatRect.GetWidth(); + nTextStyle |= TEXT_DRAW_WORDBREAK; + + // Breite fuer Textformatierung ermitteln + if ( nMaxLineWidth > 450 ) + nWidth = 450; + else if ( nMaxLineWidth > 300 ) + nWidth = nMaxLineWidth+5; + else + nWidth = 300; + if ( nButtonSize > nWidth ) + nWidth = nButtonSize-(aTextPos.X()-IMPL_DIALOG_OFFSET); + if ( nWidth > nMaxWidth ) + nWidth = nMaxWidth; + + aRect.Right() = nWidth; + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + if ( aTextInfo.GetMaxLineWidth() > nWidth ) + { + nWidth = aTextInfo.GetMaxLineWidth()+8; + aRect.Right() = nWidth; + aFormatRect = GetTextRect( aRect, aMessText, nTextStyle, &aTextInfo ); + } + + // Style fuer FixedText ermitteln + aPageSize.Width() = aImageSize.Width(); + aFixedSize.Width() = aTextInfo.GetMaxLineWidth()+1; + aFixedSize.Height() = aFormatRect.GetHeight(); + if ( aFixedSize.Height() < aImageSize.Height() ) + { + nWinStyle |= WB_VCENTER; + aPageSize.Height() = aImageSize.Height(); + aFixedSize.Height() = aImageSize.Height(); + } + else + { + nWinStyle |= WB_TOP; + aPageSize.Height() = aFixedSize.Height(); + } + if ( aImageSize.Width() ) + aPageSize.Width() += IMPL_SEP_MSGBOX_IMAGE; + aPageSize.Width() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_X*2); + aPageSize.Width() += aFixedSize.Width()+1; + aPageSize.Height() += (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); + + if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH ) + aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH; + if ( aPageSize.Width() < nTitleWidth ) + aPageSize.Width() = nTitleWidth; + + if ( maCheckBoxText.Len() ) + { + Size aMinCheckboxSize ( aFixedSize ); + if ( aPageSize.Width() < IMPL_MINSIZE_MSGBOX_WIDTH+80 ) + { + aPageSize.Width() = IMPL_MINSIZE_MSGBOX_WIDTH+80; + aMinCheckboxSize.Width() += 80; + } + + // #104492# auto mnemonics for CJK strings may increase the length, so measure the + // checkbox length including a temporary mnemonic, the correct auto mnemonic will be + // generated later in the dialog (see init_show) + + String aMnemonicString( maCheckBoxText ); + if( GetSettings().GetStyleSettings().GetAutoMnemonic() ) + { + if( aMnemonicString == GetNonMnemonicString( maCheckBoxText ) ) + { + // no mnemonic found -> create one + MnemonicGenerator aMnemonicGenerator; + aMnemonicGenerator.CreateMnemonic( aMnemonicString ); + } + } + + mpCheckBox = new CheckBox( this ); + mpCheckBox->Check( mbCheck ); + mpCheckBox->SetText( aMnemonicString ); + mpCheckBox->SetStyle( mpCheckBox->GetStyle() | WB_WORDBREAK ); + mpCheckBox->SetHelpId( GetHelpId() ); // DR: Check box and dialog have same HID + + // align checkbox with message text + Size aSize = mpCheckBox->CalcMinimumSize( aMinCheckboxSize.Width() ); + + // now set the original non-mnemonic string + mpCheckBox->SetText( maCheckBoxText ); + + Point aPos( aTextPos ); + aPos.Y() += aFixedSize.Height() + (IMPL_DIALOG_OFFSET)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); + + // increase messagebox + aPageSize.Height() += aSize.Height() + (IMPL_DIALOG_OFFSET*2)+(IMPL_MSGBOX_OFFSET_EXTRA_Y*2); + + mpCheckBox->SetPosSizePixel( aPos, aSize ); + mpCheckBox->Show(); + } + + mpFixedText = new FixedText( this, nWinStyle ); + mpFixedText->SetPosSizePixel( aTextPos, aFixedSize ); + mpFixedText->SetText( aMessText ); + mpFixedText->Show(); + SetPageSizePixel( aPageSize ); +} + +// ----------------------------------------------------------------------- + +void MessBox::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_INITSHOW ) + { + ImplPosControls(); + if ( mbSound && mnSoundType ) + Sound::Beep( (SoundType)(mnSoundType-1), this ); + } + ButtonDialog::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +BOOL MessBox::GetCheckBoxState() const +{ + return mpCheckBox ? mpCheckBox->IsChecked() : mbCheck; +} + +// ----------------------------------------------------------------------- + +void MessBox::SetCheckBoxState( BOOL bCheck ) +{ + if( mpCheckBox ) mpCheckBox->Check( bCheck ); + mbCheck = bCheck; +} + +// ----------------------------------------------------------------------- + +void MessBox::SetDefaultCheckBoxText() +{ + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTHINTAGAIN, *pResMgr ) ); +} + +// ----------------------------------------------------------------------- + +BOOL MessBox::SetModeImage( const Image& rImage, BmpColorMode eMode ) +{ + if( eMode == BMP_COLOR_NORMAL ) + SetImage( rImage ); + else if( eMode == BMP_COLOR_HIGHCONTRAST ) + maImageHC = rImage; + else + return FALSE; + return TRUE; +} + +// ----------------------------------------------------------------------- + +const Image& MessBox::GetModeImage( BmpColorMode eMode ) const +{ + if( eMode == BMP_COLOR_HIGHCONTRAST ) + return maImageHC; + else + return maImage; +} + +// ----------------------------------------------------------------------- + +void InfoBox::ImplInitInfoBoxData() +{ + // Default Text is the display title from the application + if ( !GetText().Len() ) + SetText( Application::GetDisplayName() ); + + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? + InfoBox::GetStandardImageHC() : InfoBox::GetStandardImage() ); + mnSoundType = ((USHORT)SOUND_INFO)+1; +} + +// ----------------------------------------------------------------------- + +InfoBox::InfoBox( Window* pParent, const XubString& rMessage ) : + MessBox( pParent, WB_OK | WB_DEF_OK, ImplGetSVEmptyStr(), rMessage ) +{ + ImplInitInfoBoxData(); +} + +// ----------------------------------------------------------------------- + +InfoBox::InfoBox( Window* pParent, const ResId & rResId ) : + MessBox( pParent, rResId.SetRT( RSC_INFOBOX ) ) +{ + ImplInitInfoBoxData(); +} + +// ----------------------------------------------------------------------- + +Image InfoBox::GetStandardImage() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 4 ); +} + +// ----------------------------------------------------------------------- + +Image InfoBox::GetStandardImageHC() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 4 ); +} + +// ----------------------------------------------------------------------- + +void WarningBox::ImplInitWarningBoxData() +{ + // Default Text is the display title from the application + if ( !GetText().Len() ) + SetText( Application::GetDisplayName() ); + + SetImage( WarningBox::GetStandardImage() ); + mnSoundType = ((USHORT)SOUND_WARNING)+1; +} + +// ----------------------------------------------------------------------- + +WarningBox::WarningBox( Window* pParent, WinBits nStyle, + const XubString& rMessage ) : + MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage ) +{ + ImplInitWarningBoxData(); +} + +// ----------------------------------------------------------------------- + +WarningBox::WarningBox( Window* pParent, const ResId& rResId ) : + MessBox( pParent, rResId.SetRT( RSC_WARNINGBOX ) ) +{ + ImplInitWarningBoxData(); +} + +// ----------------------------------------------------------------------- + +void WarningBox::SetDefaultCheckBoxText() +{ + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTWARNAGAIN, *pResMgr ) ); +} + +// ----------------------------------------------------------------------- + +Image WarningBox::GetStandardImage() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 3 ); +} + +// ----------------------------------------------------------------------- + +void ErrorBox::ImplInitErrorBoxData() +{ + // Default Text is the display title from the application + if ( !GetText().Len() ) + SetText( Application::GetDisplayName() ); + + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? + ErrorBox::GetStandardImageHC() : ErrorBox::GetStandardImage() ); + mnSoundType = ((USHORT)SOUND_ERROR)+1; +} + +// ----------------------------------------------------------------------- + +ErrorBox::ErrorBox( Window* pParent, WinBits nStyle, + const XubString& rMessage ) : + MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage ) +{ + ImplInitErrorBoxData(); +} + +// ----------------------------------------------------------------------- + +ErrorBox::ErrorBox( Window* pParent, const ResId& rResId ) : + MessBox( pParent, rResId.SetRT( RSC_ERRORBOX ) ) +{ + ImplInitErrorBoxData(); +} + +// ----------------------------------------------------------------------- + +Image ErrorBox::GetStandardImage() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 1 ); +} + +// ----------------------------------------------------------------------- + +Image ErrorBox::GetStandardImageHC() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 1 ); +} + +// ----------------------------------------------------------------------- + +void QueryBox::ImplInitQueryBoxData() +{ + // Default Text is the display title from the application + if ( !GetText().Len() ) + SetText( Application::GetDisplayName() ); + + SetImage( GetSettings().GetStyleSettings().GetHighContrastMode() ? + QueryBox::GetStandardImageHC() : QueryBox::GetStandardImage() ); + mnSoundType = ((USHORT)SOUND_QUERY)+1; +} + +// ----------------------------------------------------------------------- + +QueryBox::QueryBox( Window* pParent, WinBits nStyle, const XubString& rMessage ) : + MessBox( pParent, nStyle, ImplGetSVEmptyStr(), rMessage ) +{ + ImplInitQueryBoxData(); +} + +// ----------------------------------------------------------------------- + +QueryBox::QueryBox( Window* pParent, const ResId& rResId ) : + MessBox( pParent, rResId.SetRT( RSC_QUERYBOX ) ) +{ + ImplInitQueryBoxData(); +} + +// ----------------------------------------------------------------------- + +void QueryBox::SetDefaultCheckBoxText() +{ + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + maCheckBoxText = XubString( ResId( SV_STDTEXT_DONTASKAGAIN, *pResMgr ) ); +} + +// ----------------------------------------------------------------------- + +Image QueryBox::GetStandardImage() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxImgList->GetImage( 2 ); +} + +// ----------------------------------------------------------------------- + +Image QueryBox::GetStandardImageHC() +{ + ImplInitMsgBoxImageList(); + return ImplGetSVData()->maWinData.mpMsgBoxHCImgList->GetImage( 2 ); +} + +// ----------------------------------------------------------------------- + +Size MessBox::GetOptimalSize(WindowSizeType eType) const +{ + switch( eType ) { + case WINDOWSIZE_MINIMUM: + // FIXME: base me on the font size ? + return Size( 250, 100 ); + default: + return Window::GetOptimalSize( eType ); + } +} diff --git a/vcl/source/window/popupmenuwindow.cxx b/vcl/source/window/popupmenuwindow.cxx new file mode 100644 index 000000000000..78ef0bcf1068 --- /dev/null +++ b/vcl/source/window/popupmenuwindow.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "vcl/popupmenuwindow.hxx" + +#include <limits> + +struct PopupMenuFloatingWindow::ImplData +{ + sal_uInt16 mnMenuStackLevel; // Store the stack level of a popup menu. 0 = top-level menu. + + ImplData(); + ~ImplData(); +}; + +PopupMenuFloatingWindow::ImplData::ImplData() : + mnMenuStackLevel( ::std::numeric_limits<sal_uInt16>::max() ) +{ +} + +PopupMenuFloatingWindow::ImplData::~ImplData() +{ +} + +// ============================================================================ + +PopupMenuFloatingWindow::PopupMenuFloatingWindow( Window* pParent, WinBits nStyle ) : + FloatingWindow(pParent, nStyle), + mpImplData(new ImplData) +{ +} + +PopupMenuFloatingWindow::~PopupMenuFloatingWindow() +{ + delete mpImplData; +} + +sal_uInt16 PopupMenuFloatingWindow::GetMenuStackLevel() const +{ + return mpImplData->mnMenuStackLevel; +} + +void PopupMenuFloatingWindow::SetMenuStackLevel( sal_uInt16 nLevel ) +{ + mpImplData->mnMenuStackLevel = nLevel; +} + +bool PopupMenuFloatingWindow::IsPopupMenu() const +{ + return mpImplData->mnMenuStackLevel != ::std::numeric_limits<sal_uInt16>::max(); +} + diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx new file mode 100644 index 000000000000..574cef4e5a07 --- /dev/null +++ b/vcl/source/window/printdlg.cxx @@ -0,0 +1,2582 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/print.hxx" +#include "vcl/prndlg.hxx" +#include "vcl/dialog.hxx" +#include "vcl/button.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svids.hrc" +#include "vcl/wall.hxx" +#include "vcl/jobset.h" +#include "vcl/status.hxx" +#include "vcl/decoview.hxx" +#include "vcl/arrange.hxx" +#include "vcl/configsettings.hxx" +#include "vcl/help.hxx" +#include "vcl/decoview.hxx" +#include "vcl/svapp.hxx" +#include "vcl/unohelp.hxx" + +#include "unotools/localedatawrapper.hxx" + +#include "rtl/strbuf.hxx" + +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/container/XNameAccess.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/awt/Size.hpp" + +using namespace vcl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::beans; + +PrintDialog::PrintPreviewWindow::PrintPreviewWindow( Window* i_pParent, const ResId& i_rId ) + : Window( i_pParent, i_rId ) + , maOrigSize( 10, 10 ) + , maPageVDev( *this ) + , maToolTipString( String( VclResId( SV_PRINT_PRINTPREVIEW_TXT ) ) ) + , mbGreyscale( false ) + , maHorzDim( this, WB_HORZ | WB_CENTER ) + , maVertDim( this, WB_VERT | WB_VCENTER ) +{ + SetPaintTransparent( TRUE ); + SetBackground(); + if( useHCColorReplacement() ) + maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() ); + else + maPageVDev.SetBackground( Color( COL_WHITE ) ); + maHorzDim.Show(); + maVertDim.Show(); + + maHorzDim.SetText( String( RTL_CONSTASCII_USTRINGPARAM( "2.0in" ) ) ); + maVertDim.SetText( String( RTL_CONSTASCII_USTRINGPARAM( "2.0in" ) ) ); +} + +PrintDialog::PrintPreviewWindow::~PrintPreviewWindow() +{ +} + +bool PrintDialog::PrintPreviewWindow::useHCColorReplacement() const +{ + bool bRet = false; + if( GetSettings().GetStyleSettings().GetHighContrastMode() ) + { + try + { + // get service provider + Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() ); + // create configuration hierachical access name + if( xSMgr.is() ) + { + try + { + Reference< XMultiServiceFactory > xConfigProvider( + Reference< XMultiServiceFactory >( + xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationProvider" ))), + UNO_QUERY ) + ); + if( xConfigProvider.is() ) + { + Sequence< Any > aArgs(1); + PropertyValue aVal; + aVal.Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); + aVal.Value <<= rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Accessibility" ) ); + aArgs.getArray()[0] <<= aVal; + Reference< XNameAccess > xConfigAccess( + Reference< XNameAccess >( + xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationAccess" )), + aArgs ), + UNO_QUERY ) + ); + if( xConfigAccess.is() ) + { + try + { + sal_Bool bValue = sal_False; + Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsForPagePreviews" ) ) ); + if( aAny >>= bValue ) + bRet = bool(bValue); + } + catch( NoSuchElementException& ) + { + } + catch( WrappedTargetException& ) + { + } + } + } + } + catch( Exception& ) + { + } + } + } + catch( WrappedTargetException& ) + { + } + } + return bRet; +} + +void PrintDialog::PrintPreviewWindow::DataChanged( const DataChangedEvent& i_rDCEvt ) +{ + // react on settings changed + if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS ) + { + if( useHCColorReplacement() ) + maPageVDev.SetBackground( GetSettings().GetStyleSettings().GetWindowColor() ); + else + maPageVDev.SetBackground( Color( COL_WHITE ) ); + } + Window::DataChanged( i_rDCEvt ); +} + +void PrintDialog::PrintPreviewWindow::Resize() +{ + Size aNewSize( GetSizePixel() ); + long nTextHeight = maHorzDim.GetTextHeight(); + // leave small space for decoration + aNewSize.Width() -= nTextHeight + 2; + aNewSize.Height() -= nTextHeight + 2; + Size aScaledSize; + double fScale = 1.0; + + // #i106435# catch corner case of Size(0,0) + Size aOrigSize( maOrigSize ); + if( aOrigSize.Width() < 1 ) + aOrigSize.Width() = aNewSize.Width(); + if( aOrigSize.Height() < 1 ) + aOrigSize.Height() = aNewSize.Height(); + if( aOrigSize.Width() > aOrigSize.Height() ) + { + aScaledSize = Size( aNewSize.Width(), aNewSize.Width() * aOrigSize.Height() / aOrigSize.Width() ); + if( aScaledSize.Height() > aNewSize.Height() ) + fScale = double(aNewSize.Height())/double(aScaledSize.Height()); + } + else + { + aScaledSize = Size( aNewSize.Height() * aOrigSize.Width() / aOrigSize.Height(), aNewSize.Height() ); + if( aScaledSize.Width() > aNewSize.Width() ) + fScale = double(aNewSize.Width())/double(aScaledSize.Width()); + } + aScaledSize.Width() = long(aScaledSize.Width()*fScale); + aScaledSize.Height() = long(aScaledSize.Height()*fScale); + + maPreviewSize = aScaledSize; + + // #i104784# if we render the page too small then rounding issues result in + // layout artifacts looking really bad. So scale the page unto a device that is not + // full page size but not too small either. This also results in much better visual + // quality of the preview, e.g. when its height approaches the number of text lines + // find a good scaling factor + Size aPreviewMMSize( maPageVDev.PixelToLogic( aScaledSize, MapMode( MAP_100TH_MM ) ) ); + double fZoom = double(maOrigSize.Height())/double(aPreviewMMSize.Height()); + while( fZoom > 10 ) + { + aScaledSize.Width() *= 2; + aScaledSize.Height() *= 2; + fZoom /= 2.0; + } + + maPageVDev.SetOutputSizePixel( aScaledSize, FALSE ); + + // position dimension lines + Point aRef( nTextHeight + (aNewSize.Width() - maPreviewSize.Width())/2, + nTextHeight + (aNewSize.Height() - maPreviewSize.Height())/2 ); + maHorzDim.SetPosSizePixel( Point( aRef.X(), aRef.Y() - nTextHeight ), + Size( maPreviewSize.Width(), nTextHeight ) ); + maVertDim.SetPosSizePixel( Point( aRef.X() - nTextHeight, aRef.Y() ), + Size( nTextHeight, maPreviewSize.Height() ) ); + +} + +void PrintDialog::PrintPreviewWindow::Paint( const Rectangle& ) +{ + long nTextHeight = maHorzDim.GetTextHeight(); + Size aSize( GetSizePixel() ); + aSize.Width() -= nTextHeight; + aSize.Height() -= nTextHeight; + if( maReplacementString.getLength() != 0 ) + { + // replacement is active + Push(); + Rectangle aTextRect( Point( nTextHeight, nTextHeight ), aSize ); + DecorationView aVw( this ); + aVw.DrawFrame( aTextRect, FRAME_DRAW_GROUP ); + aTextRect.Left() += 2; + aTextRect.Top() += 2; + aTextRect.Right() -= 2; + aTextRect.Bottom() -= 2; + Font aFont( GetSettings().GetStyleSettings().GetLabelFont() ); + SetZoomedPointFont( aFont ); + DrawText( aTextRect, maReplacementString, + TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE + ); + Pop(); + } + else + { + GDIMetaFile aMtf( maMtf ); + + Point aOffset( (aSize.Width() - maPreviewSize.Width()) / 2 + nTextHeight, + (aSize.Height() - maPreviewSize.Height()) / 2 + nTextHeight ); + + Size aVDevSize( maPageVDev.GetOutputSizePixel() ); + const Size aLogicSize( maPageVDev.PixelToLogic( aVDevSize, MapMode( MAP_100TH_MM ) ) ); + Size aOrigSize( maOrigSize ); + if( aOrigSize.Width() < 1 ) + aOrigSize.Width() = aLogicSize.Width(); + if( aOrigSize.Height() < 1 ) + aOrigSize.Height() = aLogicSize.Height(); + double fScale = double(aLogicSize.Width())/double(aOrigSize.Width()); + + + maPageVDev.Erase(); + maPageVDev.Push(); + maPageVDev.SetMapMode( MAP_100TH_MM ); + ULONG nOldDrawMode = maPageVDev.GetDrawMode(); + if( mbGreyscale ) + maPageVDev.SetDrawMode( maPageVDev.GetDrawMode() | + ( DRAWMODE_GRAYLINE | DRAWMODE_GRAYFILL | DRAWMODE_GRAYTEXT | + DRAWMODE_GRAYBITMAP | DRAWMODE_GRAYGRADIENT ) ); + aMtf.WindStart(); + aMtf.Scale( fScale, fScale ); + aMtf.WindStart(); + aMtf.Play( &maPageVDev, Point( 0, 0 ), aLogicSize ); + maPageVDev.Pop(); + + SetMapMode( MAP_PIXEL ); + maPageVDev.SetMapMode( MAP_PIXEL ); + DrawOutDev( aOffset, maPreviewSize, Point( 0, 0 ), aVDevSize, maPageVDev ); + maPageVDev.SetDrawMode( nOldDrawMode ); + + DecorationView aVw( this ); + Rectangle aFrame( aOffset + Point( -1, -1 ), Size( maPreviewSize.Width() + 2, maPreviewSize.Height() + 2 ) ); + aVw.DrawFrame( aFrame, FRAME_DRAW_GROUP ); + } +} + +void PrintDialog::PrintPreviewWindow::Command( const CommandEvent& rEvt ) +{ + if( rEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pWheelData = rEvt.GetWheelData(); + PrintDialog* pDlg = dynamic_cast<PrintDialog*>(GetParent()); + if( pDlg ) + { + if( pWheelData->GetDelta() > 0 ) + pDlg->previewForward(); + else if( pWheelData->GetDelta() < 0 ) + pDlg->previewBackward(); + /* + else + huh ? + */ + } + } +} + +void PrintDialog::PrintPreviewWindow::setPreview( const GDIMetaFile& i_rNewPreview, + const Size& i_rOrigSize, + const rtl::OUString& i_rReplacement, + sal_Int32 i_nDPIX, + sal_Int32 i_nDPIY, + bool i_bGreyscale + ) +{ + rtl::OUStringBuffer aBuf( 256 ); + aBuf.append( maToolTipString ); + SetQuickHelpText( aBuf.makeStringAndClear() ); + maMtf = i_rNewPreview; + if( useHCColorReplacement() ) + { + maMtf.ReplaceColors( Color( COL_BLACK ), Color( COL_WHITE ), 30 ); + } + + maOrigSize = i_rOrigSize; + maReplacementString = i_rReplacement; + mbGreyscale = i_bGreyscale; + maPageVDev.SetReferenceDevice( i_nDPIX, i_nDPIY ); + maPageVDev.EnableOutput( TRUE ); + + // use correct measurements + const LocaleDataWrapper& rLocWrap( GetSettings().GetLocaleDataWrapper() ); + MapUnit eUnit = MAP_MM; + int nDigits = 0; + if( rLocWrap.getMeasurementSystemEnum() == MEASURE_US ) + { + eUnit = MAP_100TH_INCH; + nDigits = 2; + } + Size aLogicPaperSize( LogicToLogic( i_rOrigSize, MapMode( MAP_100TH_MM ), MapMode( eUnit ) ) ); + String aNumText( rLocWrap.getNum( aLogicPaperSize.Width(), nDigits ) ); + aBuf.append( aNumText ); + aBuf.appendAscii( eUnit == MAP_MM ? "mm" : "in" ); + maHorzDim.SetText( aBuf.makeStringAndClear() ); + + aNumText = rLocWrap.getNum( aLogicPaperSize.Height(), nDigits ); + aBuf.append( aNumText ); + aBuf.appendAscii( eUnit == MAP_MM ? "mm" : "in" ); + maVertDim.SetText( aBuf.makeStringAndClear() ); + + Resize(); + Invalidate(); +} + +PrintDialog::ShowNupOrderWindow::ShowNupOrderWindow( Window* i_pParent ) + : Window( i_pParent, WB_NOBORDER ) + , mnOrderMode( 0 ) + , mnRows( 1 ) + , mnColumns( 1 ) +{ + ImplInitSettings(); +} + +PrintDialog::ShowNupOrderWindow::~ShowNupOrderWindow() +{ +} + +void PrintDialog::ShowNupOrderWindow::ImplInitSettings() +{ + SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFieldColor() ) ); +} + +void PrintDialog::ShowNupOrderWindow::Paint( const Rectangle& i_rRect ) +{ + Window::Paint( i_rRect ); + SetMapMode( MAP_PIXEL ); + SetTextColor( GetSettings().GetStyleSettings().GetFieldTextColor() ); + + int nPages = mnRows * mnColumns; + Font aFont( GetSettings().GetStyleSettings().GetFieldFont() ); + aFont.SetSize( Size( 0, 24 ) ); + SetFont( aFont ); + Size aSampleTextSize( GetTextWidth( rtl::OUString::valueOf( sal_Int32(nPages+1) ) ), GetTextHeight() ); + + Size aOutSize( GetOutputSizePixel() ); + Size aSubSize( aOutSize.Width() / mnColumns, aOutSize.Height() / mnRows ); + // calculate font size: shrink the sample text so it fits + double fX = double(aSubSize.Width())/double(aSampleTextSize.Width()); + double fY = double(aSubSize.Height())/double(aSampleTextSize.Height()); + double fScale = (fX < fY) ? fX : fY; + long nFontHeight = long(24.0*fScale) - 3; + if( nFontHeight < 5 ) + nFontHeight = 5; + aFont.SetSize( Size( 0, nFontHeight ) ); + SetFont( aFont ); + long nTextHeight = GetTextHeight(); + for( int i = 0; i < nPages; i++ ) + { + rtl::OUString aPageText( rtl::OUString::valueOf( sal_Int32(i+1) ) ); + int nX = 0, nY = 0; + switch( mnOrderMode ) + { + case SV_PRINT_PRT_NUP_ORDER_LRTB: + nX = (i % mnColumns); nY = (i / mnColumns); + break; + case SV_PRINT_PRT_NUP_ORDER_TBLR: + nX = (i / mnRows); nY = (i % mnRows); + break; + case SV_PRINT_PRT_NUP_ORDER_RLTB: + nX = mnColumns - 1 - (i % mnColumns); nY = (i / mnColumns); + break; + case SV_PRINT_PRT_NUP_ORDER_TBRL: + nX = mnColumns - 1 - (i / mnRows); nY = (i % mnRows); + break; + } + Size aTextSize( GetTextWidth( aPageText ), nTextHeight ); + int nDeltaX = (aSubSize.Width() - aTextSize.Width()) / 2; + int nDeltaY = (aSubSize.Height() - aTextSize.Height()) / 2; + DrawText( Point( nX * aSubSize.Width() + nDeltaX, + nY * aSubSize.Height() + nDeltaY ), + aPageText ); + } + DecorationView aVw( this ); + aVw.DrawFrame( Rectangle( Point( 0, 0), aOutSize ), FRAME_DRAW_GROUP ); +} + +PrintDialog::NUpTabPage::NUpTabPage( Window* i_pParent, const ResId& rResId ) + : TabPage( i_pParent, rResId ) + , maNupLine( this, VclResId( SV_PRINT_PRT_NUP_LAYOUT_FL ) ) + , maPagesBtn( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BTN ) ) + , maBrochureBtn( this, VclResId( SV_PRINT_PRT_NUP_BROCHURE_BTN ) ) + , maPagesBoxTitleTxt( this, 0 ) + , maNupPagesBox( this, VclResId( SV_PRINT_PRT_NUP_PAGES_BOX ) ) + , maNupNumPagesTxt( this, VclResId( SV_PRINT_PRT_NUP_NUM_PAGES_TXT ) ) + , maNupColEdt( this, VclResId( SV_PRINT_PRT_NUP_COLS_EDT ) ) + , maNupTimesTxt( this, VclResId( SV_PRINT_PRT_NUP_TIMES_TXT ) ) + , maNupRowsEdt( this, VclResId( SV_PRINT_PRT_NUP_ROWS_EDT ) ) + , maPageMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_1_TXT ) ) + , maPageMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_EDT ) ) + , maPageMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_PAGES_2_TXT ) ) + , maSheetMarginTxt1( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_1_TXT ) ) + , maSheetMarginEdt( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_EDT ) ) + , maSheetMarginTxt2( this, VclResId( SV_PRINT_PRT_NUP_MARGINS_SHEET_2_TXT ) ) + , maNupOrientationTxt( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_TXT ) ) + , maNupOrientationBox( this, VclResId( SV_PRINT_PRT_NUP_ORIENTATION_BOX ) ) + , maNupOrderTxt( this, VclResId( SV_PRINT_PRT_NUP_ORDER_TXT ) ) + , maNupOrderBox( this, VclResId( SV_PRINT_PRT_NUP_ORDER_BOX ) ) + , maNupOrderWin( this ) + , maBorderCB( this, VclResId( SV_PRINT_PRT_NUP_BORDER_CB ) ) +{ + FreeResource(); + + maNupOrderWin.Show(); + maPagesBtn.Check( TRUE ); + maBrochureBtn.Show( FALSE ); + + // setup field units for metric fields + const LocaleDataWrapper& rLocWrap( maPageMarginEdt.GetLocaleDataWrapper() ); + FieldUnit eUnit = FUNIT_MM; + USHORT nDigits = 0; + if( rLocWrap.getMeasurementSystemEnum() == MEASURE_US ) + { + eUnit = FUNIT_INCH; + nDigits = 2; + } + // set units + maPageMarginEdt.SetUnit( eUnit ); + maSheetMarginEdt.SetUnit( eUnit ); + + // set precision + maPageMarginEdt.SetDecimalDigits( nDigits ); + maSheetMarginEdt.SetDecimalDigits( nDigits ); + + setupLayout(); +} + +PrintDialog::NUpTabPage::~NUpTabPage() +{ +} + +void PrintDialog::NUpTabPage::enableNupControls( bool bEnable ) +{ + maNupPagesBox.Enable( TRUE ); + maNupNumPagesTxt.Enable( bEnable ); + maNupColEdt.Enable( bEnable ); + maNupTimesTxt.Enable( bEnable ); + maNupRowsEdt.Enable( bEnable ); + maPageMarginTxt1.Enable( bEnable ); + maPageMarginEdt.Enable( bEnable ); + maPageMarginTxt2.Enable( bEnable ); + maSheetMarginTxt1.Enable( bEnable ); + maSheetMarginEdt.Enable( bEnable ); + maSheetMarginTxt2.Enable( bEnable ); + maNupOrientationTxt.Enable( bEnable ); + maNupOrientationBox.Enable( bEnable ); + maNupOrderTxt.Enable( bEnable ); + maNupOrderBox.Enable( bEnable ); + maNupOrderWin.Enable( bEnable ); + maBorderCB.Enable( bEnable ); +} + +void PrintDialog::NUpTabPage::showAdvancedControls( bool i_bShow ) +{ + maNupNumPagesTxt.Show( i_bShow ); + maNupColEdt.Show( i_bShow ); + maNupTimesTxt.Show( i_bShow ); + maNupRowsEdt.Show( i_bShow ); + maPageMarginTxt1.Show( i_bShow ); + maPageMarginEdt.Show( i_bShow ); + maPageMarginTxt2.Show( i_bShow ); + maSheetMarginTxt1.Show( i_bShow ); + maSheetMarginEdt.Show( i_bShow ); + maSheetMarginTxt2.Show( i_bShow ); + maNupOrientationTxt.Show( i_bShow ); + maNupOrientationBox.Show( i_bShow ); + getLayout()->resize(); +} + +void PrintDialog::NUpTabPage::setupLayout() +{ + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); + Size aBorder( LogicToPixel( Size( 6, 6 ), MapMode( MAP_APPFONT ) ) ); + /* According to OOo style guide, the horizontal indentation of child + elements to their parent element should always be 6 map units. */ + long nIndent = aBorder.Width(); + + xLayout->addWindow( &maNupLine ); + boost::shared_ptr< vcl::RowOrColumn > xRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xRow ); + boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xRow.get() ) ); + xRow->addChild( xIndent ); + + boost::shared_ptr< vcl::RowOrColumn > xShowNupCol( new vcl::RowOrColumn( xRow.get() ) ); + xRow->addChild( xShowNupCol, -1 ); + xShowNupCol->setMinimumSize( xShowNupCol->addWindow( &maNupOrderWin ), Size( 70, 70 ) ); + boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( xShowNupCol.get() ) ); + xShowNupCol->addChild( xSpacer ); + + boost::shared_ptr< vcl::LabelColumn > xMainCol( new vcl::LabelColumn( xIndent.get() ) ); + xIndent->setChild( xMainCol ); + + size_t nPagesIndex = xMainCol->addRow( &maPagesBtn, &maNupPagesBox ); + mxPagesBtnLabel = boost::dynamic_pointer_cast<vcl::LabeledElement>( xMainCol->getChild( nPagesIndex ) ); + + xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) ); + xMainCol->addRow( &maNupNumPagesTxt, xRow, nIndent ); + xRow->addWindow( &maNupColEdt ); + xRow->addWindow( &maNupTimesTxt ); + xRow->addWindow( &maNupRowsEdt ); + + boost::shared_ptr< vcl::LabeledElement > xLab( new vcl::LabeledElement( xMainCol.get(), 2 ) ); + xLab->setLabel( &maPageMarginEdt ); + xLab->setElement( &maPageMarginTxt2 ); + xMainCol->addRow( &maPageMarginTxt1, xLab, nIndent ); + + xLab.reset( new vcl::LabeledElement( xMainCol.get(), 2 ) ); + xLab->setLabel( &maSheetMarginEdt ); + xLab->setElement( &maSheetMarginTxt2 ); + xMainCol->addRow( &maSheetMarginTxt1, xLab, nIndent ); + + xMainCol->addRow( &maNupOrientationTxt, &maNupOrientationBox, nIndent ); + xMainCol->addRow( &maNupOrderTxt, &maNupOrderBox, nIndent ); + xMainCol->setBorders( xMainCol->addWindow( &maBorderCB ), nIndent, 0, 0, 0 ); + + xSpacer.reset( new vcl::Spacer( xMainCol.get(), 0, Size( 10, WindowArranger::getDefaultBorder() ) ) ); + xMainCol->addChild( xSpacer ); + + xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) ); + xMainCol->addRow( &maBrochureBtn, xRow ); + // remember brochure row for dependencies + mxBrochureDep = xRow; + + // initially advanced controls are not shown, rows=columns=1 + showAdvancedControls( false ); +} + +void PrintDialog::NUpTabPage::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& i_rMPS ) +{ + maSheetMarginEdt.SetValue( maSheetMarginEdt.Normalize( i_rMPS.nLeftMargin ), FUNIT_100TH_MM ); + maPageMarginEdt.SetValue( maPageMarginEdt.Normalize( i_rMPS.nHorizontalSpacing ), FUNIT_100TH_MM ); + maBorderCB.Check( i_rMPS.bDrawBorder ); + maNupRowsEdt.SetValue( i_rMPS.nRows ); + maNupColEdt.SetValue( i_rMPS.nColumns ); +} + +void PrintDialog::NUpTabPage::readFromSettings() +{ +} + +void PrintDialog::NUpTabPage::storeToSettings() +{ +} + +PrintDialog::JobTabPage::JobTabPage( Window* i_pParent, const ResId& rResId ) + : TabPage( i_pParent, rResId ) + , maPrinterFL( this, VclResId( SV_PRINT_PRINTERS_FL ) ) + , maPrinters( this, VclResId( SV_PRINT_PRINTERS ) ) + , maDetailsBtn( this, VclResId( SV_PRINT_DETAILS_BTN ) ) + , maStatusLabel( this, VclResId( SV_PRINT_STATUS_TXT ) ) + , maStatusTxt( this, 0 ) + , maLocationLabel( this, VclResId( SV_PRINT_LOCATION_TXT ) ) + , maLocationTxt( this, 0 ) + , maCommentLabel( this, VclResId( SV_PRINT_COMMENT_TXT ) ) + , maCommentTxt( this, 0 ) + , maSetupButton( this, VclResId( SV_PRINT_PRT_SETUP ) ) + , maCopies( this, VclResId( SV_PRINT_COPIES ) ) + , maCopySpacer( this, WB_VERT ) + , maCopyCount( this, VclResId( SV_PRINT_COPYCOUNT ) ) + , maCopyCountField( this, VclResId( SV_PRINT_COPYCOUNT_FIELD ) ) + , maCollateBox( this, VclResId( SV_PRINT_COLLATE ) ) + , maCollateImage( this, VclResId( SV_PRINT_COLLATE_IMAGE ) ) + , maCollateImg( VclResId( SV_PRINT_COLLATE_IMG ) ) + , maCollateHCImg( VclResId( SV_PRINT_COLLATE_HC_IMG ) ) + , maNoCollateImg( VclResId( SV_PRINT_NOCOLLATE_IMG ) ) + , maNoCollateHCImg( VclResId( SV_PRINT_NOCOLLATE_HC_IMG ) ) + , mnCollateUIMode( 0 ) +{ + FreeResource(); + + maCopySpacer.Show(); + maStatusTxt.Show(); + maCommentTxt.Show(); + maLocationTxt.Show(); + + setupLayout(); +} + +PrintDialog::JobTabPage::~JobTabPage() +{ +} + +void PrintDialog::JobTabPage::setupLayout() +{ + // HACK: this is not a dropdown box, but the dropdown line count + // sets the results of GetOptimalSize in a normal ListBox + maPrinters.SetDropDownLineCount( 4 ); + + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); + + // add printer fixed line + xLayout->addWindow( &maPrinterFL ); + // add print LB + xLayout->addWindow( &maPrinters, 3 ); + + // create a row for details button/text and properties button + boost::shared_ptr< vcl::RowOrColumn > xDetRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xDetRow ); + xDetRow->addWindow( &maDetailsBtn ); + xDetRow->addChild( new vcl::Spacer( xDetRow.get(), 2 ) ); + xDetRow->addWindow( &maSetupButton ); + + // create an indent for details + boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xLayout.get() ) ); + xLayout->addChild( xIndent ); + // remember details controls + mxDetails = xIndent; + // create a column for the details + boost::shared_ptr< vcl::LabelColumn > xLabelCol( new vcl::LabelColumn( xIndent.get() ) ); + xIndent->setChild( xLabelCol ); + xLabelCol->addRow( &maStatusLabel, &maStatusTxt ); + xLabelCol->addRow( &maLocationLabel, &maLocationTxt ); + xLabelCol->addRow( &maCommentLabel, &maCommentTxt ); + + // add print range and copies columns + xLayout->addWindow( &maCopies ); + boost::shared_ptr< vcl::RowOrColumn > xRangeRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xRangeRow ); + + // create print range and add to range row + mxPrintRange.reset( new vcl::RowOrColumn( xRangeRow.get() ) ); + xRangeRow->addChild( mxPrintRange ); + xRangeRow->addWindow( &maCopySpacer ); + + boost::shared_ptr< vcl::RowOrColumn > xCopyCollateCol( new vcl::RowOrColumn( xRangeRow.get() ) ); + xRangeRow->addChild( xCopyCollateCol ); + + // add copies row to copy/collate column + boost::shared_ptr< vcl::LabeledElement > xCopiesRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) ); + xCopyCollateCol->addChild( xCopiesRow ); + xCopiesRow->setLabel( &maCopyCount ); + xCopiesRow->setElement( &maCopyCountField ); + boost::shared_ptr< vcl::LabeledElement > xCollateRow( new vcl::LabeledElement( xCopyCollateCol.get(), 2 ) ); + xCopyCollateCol->addChild( xCollateRow ); + xCollateRow->setLabel( &maCollateBox ); + xCollateRow->setElement( &maCollateImage ); + + // maDetailsBtn.SetStyle( maDetailsBtn.GetStyle() | (WB_SMALLSTYLE | WB_BEVELBUTTON) ); + mxDetails->show( false, false ); +} + +void PrintDialog::JobTabPage::readFromSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue; + + #if 0 + // do not actually make copy count persistent + // the assumption is that this would lead to a lot of unwanted copies + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ) ); + sal_Int32 nVal = aValue.toInt32(); + maCopyCountField.SetValue( sal_Int64(nVal > 1 ? nVal : 1) ); + #endif + + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CollateBox" ) ) ); + if( aValue.equalsIgnoreAsciiCaseAscii( "alwaysoff" ) ) + { + mnCollateUIMode = 1; + maCollateBox.Check( FALSE ); + maCollateBox.Enable( FALSE ); + } + else + { + mnCollateUIMode = 0; + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ); + maCollateBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) ); + } + Resize(); +} + +void PrintDialog::JobTabPage::storeToSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ), + maCopyCountField.GetText() ); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + rtl::OUString::createFromAscii( maCollateBox.IsChecked() ? "true" : "false" ) ); +} + +PrintDialog::OutputOptPage::OutputOptPage( Window* i_pParent, const ResId& i_rResId ) + : TabPage( i_pParent, i_rResId ) + , maOptionsLine( this, VclResId( SV_PRINT_OPT_PRINT_FL ) ) + , maToFileBox( this, VclResId( SV_PRINT_OPT_TOFILE ) ) + , maCollateSingleJobsBox( this, VclResId( SV_PRINT_OPT_SINGLEJOBS ) ) + , maReverseOrderBox( this, VclResId( SV_PRINT_OPT_REVERSE ) ) +{ + FreeResource(); + + setupLayout(); +} + +PrintDialog::OutputOptPage::~OutputOptPage() +{ +} + +void PrintDialog::OutputOptPage::setupLayout() +{ + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); + + xLayout->addWindow( &maOptionsLine ); + boost::shared_ptr<vcl::Indenter> xIndent( new vcl::Indenter( xLayout.get(), -1 ) ); + xLayout->addChild( xIndent ); + boost::shared_ptr<vcl::RowOrColumn> xCol( new vcl::RowOrColumn( xIndent.get() ) ); + xIndent->setChild( xCol ); + mxOptGroup = xCol; + xCol->addWindow( &maToFileBox ); + xCol->addWindow( &maCollateSingleJobsBox ); + xCol->addWindow( &maReverseOrderBox ); +} + +void PrintDialog::OutputOptPage::readFromSettings() +{ + #if 0 + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue; + + aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ) ); + maToFileBox.Check( aValue.equalsIgnoreAsciiCaseAscii( "true" ) ); + #endif +} + +void PrintDialog::OutputOptPage::storeToSettings() +{ + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ToFile" ) ), + rtl::OUString::createFromAscii( maToFileBox.IsChecked() ? "true" : "false" ) ); +} + +PrintDialog::PrintDialog( Window* i_pParent, const boost::shared_ptr<PrinterController>& i_rController ) + : ModalDialog( i_pParent, VclResId( SV_DLG_PRINT ) ) + , maOKButton( this, VclResId( SV_PRINT_OK ) ) + , maCancelButton( this, VclResId( SV_PRINT_CANCEL ) ) + , maHelpButton( this, VclResId( SV_PRINT_HELP ) ) + , maPreviewWindow( this, VclResId( SV_PRINT_PAGE_PREVIEW ) ) + , maPageEdit( this, VclResId( SV_PRINT_PAGE_EDIT ) ) + , maNumPagesText( this, VclResId( SV_PRINT_PAGE_TXT ) ) + , maBackwardBtn( this, VclResId( SV_PRINT_PAGE_BACKWARD ) ) + , maForwardBtn( this, VclResId( SV_PRINT_PAGE_FORWARD ) ) + , maTabCtrl( this, VclResId( SV_PRINT_TABCTRL ) ) + , maNUpPage( &maTabCtrl, VclResId( SV_PRINT_TAB_NUP ) ) + , maJobPage( &maTabCtrl, VclResId( SV_PRINT_TAB_JOB ) ) + , maOptionsPage( &maTabCtrl, VclResId( SV_PRINT_TAB_OPT ) ) + , maButtonLine( this, VclResId( SV_PRINT_BUTTONLINE ) ) + , maPController( i_rController ) + , maNoPageStr( String( VclResId( SV_PRINT_NOPAGES ) ) ) + , mnCurPage( 0 ) + , mnCachedPages( 0 ) + , maPrintToFileText( String( VclResId( SV_PRINT_TOFILE_TXT ) ) ) + , maDefPrtText( String( VclResId( SV_PRINT_DEFPRT_TXT ) ) ) + , mbShowLayoutPage( sal_True ) +{ + FreeResource(); + + // save printbutton text, gets exchanged occasionally with print to file + maPrintText = maOKButton.GetText(); + + // setup preview controls + maForwardBtn.SetStyle( maForwardBtn.GetStyle() | WB_BEVELBUTTON ); + maBackwardBtn.SetStyle( maBackwardBtn.GetStyle() | WB_BEVELBUTTON ); + + // insert the job (general) tab page first + maTabCtrl.InsertPage( SV_PRINT_TAB_JOB, maJobPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_JOB, &maJobPage ); + + // set symbols on forward and backward button + maBackwardBtn.SetSymbol( SYMBOL_PREV ); + maForwardBtn.SetSymbol( SYMBOL_NEXT ); + maBackwardBtn.ImplSetSmallSymbol( TRUE ); + maForwardBtn.ImplSetSmallSymbol( TRUE ); + + maPageStr = maNumPagesText.GetText(); + + // init reverse print + maOptionsPage.maReverseOrderBox.Check( maPController->getReversePrint() ); + + // fill printer listbox + const std::vector< rtl::OUString >& rQueues( Printer::GetPrinterQueues() ); + for( std::vector< rtl::OUString >::const_iterator it = rQueues.begin(); + it != rQueues.end(); ++it ) + { + maJobPage.maPrinters.InsertEntry( *it ); + } + // select current printer + if( maJobPage.maPrinters.GetEntryPos( maPController->getPrinter()->GetName() ) != LISTBOX_ENTRY_NOTFOUND ) + { + maJobPage.maPrinters.SelectEntry( maPController->getPrinter()->GetName() ); + } + else + { + // fall back to last printer + SettingsConfigItem* pItem = SettingsConfigItem::get(); + String aValue( pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ) ) ); + if( maJobPage.maPrinters.GetEntryPos( aValue ) != LISTBOX_ENTRY_NOTFOUND ) + { + maJobPage.maPrinters.SelectEntry( aValue ); + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aValue ) ) ); + } + else + { + // fall back to default printer + maJobPage.maPrinters.SelectEntry( Printer::GetDefaultPrinterName() ); + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( Printer::GetDefaultPrinterName() ) ) ); + } + } + // not printing to file + maPController->resetPrinterOptions( false ); + + // get the first page + preparePreview( true, true ); + + // update the text fields for the printer + updatePrinterText(); + + // set a select handler + maJobPage.maPrinters.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + + // setup sizes for N-Up + Size aNupSize( maPController->getPrinter()->PixelToLogic( + maPController->getPrinter()->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ) ); + if( maPController->getPrinter()->GetOrientation() == ORIENTATION_LANDSCAPE ) + { + maNupLandscapeSize = aNupSize; + maNupPortraitSize = Size( aNupSize.Height(), aNupSize.Width() ); + } + else + { + maNupPortraitSize = aNupSize; + maNupLandscapeSize = Size( aNupSize.Height(), aNupSize.Width() ); + } + maNUpPage.initFromMultiPageSetup( maPController->getMultipage() ); + + + // setup click handler on the various buttons + maOKButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + #if OSL_DEBUG_LEVEL > 1 + maCancelButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + #endif + maHelpButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maForwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maBackwardBtn.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maCollateBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maSetupButton.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maJobPage.maDetailsBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maNUpPage.maBorderCB.SetClickHdl( LINK( this, PrintDialog, ClickHdl ) ); + maOptionsPage.maToFileBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maOptionsPage.maReverseOrderBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maOptionsPage.maCollateSingleJobsBox.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + maNUpPage.maPagesBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + + // setup modify hdl + maPageEdit.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maJobPage.maCopyCountField.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maNupRowsEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maNupColEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maPageMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + maNUpPage.maSheetMarginEdt.SetModifyHdl( LINK( this, PrintDialog, ModifyHdl ) ); + + // setup select hdl + maNUpPage.maNupPagesBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + maNUpPage.maNupOrientationBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + maNUpPage.maNupOrderBox.SetSelectHdl( LINK( this, PrintDialog, SelectHdl ) ); + + // setup the layout + setupLayout(); + + // setup optional UI options set by application + setupOptionalUI(); + + // set change handler for UI options + maPController->setOptionChangeHdl( LINK( this, PrintDialog, UIOptionsChanged ) ); + + // set min size pixel to current size + Size aOutSize( GetOutputSizePixel() ); + SetMinOutputSizePixel( aOutSize ); + + // if there is space enough, enlarge the preview so it gets roughly as + // high as the tab control + if( aOutSize.Width() < 768 ) + { + Size aJobPageSize( getJobPageSize() ); + Size aTabSize( maTabCtrl.GetSizePixel() ); + if( aJobPageSize.Width() < 1 ) + aJobPageSize.Width() = aTabSize.Width(); + if( aJobPageSize.Height() < 1 ) + aJobPageSize.Height() = aTabSize.Height(); + long nOptPreviewWidth = aTabSize.Height() * aJobPageSize.Width() / aJobPageSize.Height(); + // add space for borders + nOptPreviewWidth += 15; + if( aOutSize.Width() - aTabSize.Width() < nOptPreviewWidth ) + { + aOutSize.Width() = aTabSize.Width() + nOptPreviewWidth; + if( aOutSize.Width() > 768 ) // don't enlarge the dialog too much + aOutSize.Width() = 768; + SetOutputSizePixel( aOutSize ); + } + } + + // append further tab pages + if( mbShowLayoutPage ) + { + maTabCtrl.InsertPage( SV_PRINT_TAB_NUP, maNUpPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_NUP, &maNUpPage ); + } + maTabCtrl.InsertPage( SV_PRINT_TAB_OPT, maOptionsPage.GetText() ); + maTabCtrl.SetTabPage( SV_PRINT_TAB_OPT, &maOptionsPage ); + + // restore settings from last run + readFromSettings(); + + // setup dependencies + checkControlDependencies(); + +} + +PrintDialog::~PrintDialog() +{ + while( ! maControls.empty() ) + { + delete maControls.front(); + maControls.pop_front(); + } +} + +void PrintDialog::setupLayout() +{ + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); + xLayout->setOuterBorder( 0 ); + + + boost::shared_ptr< vcl::RowOrColumn > xPreviewAndTab( new vcl::RowOrColumn( xLayout.get(), false ) ); + size_t nIndex = xLayout->addChild( xPreviewAndTab, 5 ); + xLayout->setBorders( nIndex, -1, -1, -1, 0 ); + + // setup column for preview and sub controls + boost::shared_ptr< vcl::RowOrColumn > xPreview( new vcl::RowOrColumn( xPreviewAndTab.get() ) ); + xPreviewAndTab->addChild( xPreview, 5 ); + xPreview->addWindow( &maPreviewWindow, 5 ); + // get a row for the preview controls + mxPreviewCtrls.reset( new vcl::RowOrColumn( xPreview.get(), false ) ); + nIndex = xPreview->addChild( mxPreviewCtrls ); + boost::shared_ptr< vcl::Spacer > xSpacer( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + mxPreviewCtrls->addWindow( &maPageEdit ); + mxPreviewCtrls->addWindow( &maNumPagesText ); + xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + mxPreviewCtrls->addWindow( &maBackwardBtn ); + mxPreviewCtrls->addWindow( &maForwardBtn ); + xSpacer.reset( new vcl::Spacer( mxPreviewCtrls.get(), 2 ) ); + mxPreviewCtrls->addChild( xSpacer ); + + // continue with the tab ctrl + xPreviewAndTab->addWindow( &maTabCtrl ); + + // add the button line + xLayout->addWindow( &maButtonLine ); + + // add the row for the buttons + boost::shared_ptr< vcl::RowOrColumn > xButtons( new vcl::RowOrColumn( xLayout.get(), false ) ); + nIndex = xLayout->addChild( xButtons ); + xLayout->setBorders( nIndex, -1, 0, -1, -1 ); + + Size aMinSize( maCancelButton.GetSizePixel() ); + // insert help button + xButtons->setMinimumSize( xButtons->addWindow( &maHelpButton ), aMinSize ); + // insert a spacer, cancel and OK buttons are right aligned + xSpacer.reset( new vcl::Spacer( xButtons.get(), 2 ) ); + xButtons->addChild( xSpacer ); + xButtons->setMinimumSize( xButtons->addWindow( &maOKButton ), aMinSize ); + xButtons->setMinimumSize( xButtons->addWindow( &maCancelButton ), aMinSize ); +} + +void PrintDialog::readFromSettings() +{ + maJobPage.readFromSettings(); + maNUpPage.readFromSettings(); + maOptionsPage.readFromSettings(); + + // read last selected tab page; if it exists, actiavte it + SettingsConfigItem* pItem = SettingsConfigItem::get(); + rtl::OUString aValue = pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ) ); + USHORT nCount = maTabCtrl.GetPageCount(); + for( USHORT i = 0; i < nCount; i++ ) + { + USHORT nPageId = maTabCtrl.GetPageId( i ); + if( aValue.equals( maTabCtrl.GetPageText( nPageId ) ) ) + { + maTabCtrl.SelectTabPage( nPageId ); + break; + } + } + maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText ); + if( maOptionsPage.maToFileBox.IsChecked() ) + { + maPController->resetPrinterOptions( true ); + preparePreview( true, true ); + } +} + +void PrintDialog::storeToSettings() +{ + maJobPage.storeToSettings(); + maNUpPage.storeToSettings(); + maOptionsPage.storeToSettings(); + + // store last selected printer + SettingsConfigItem* pItem = SettingsConfigItem::get(); + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPrinter" ) ), + maJobPage.maPrinters.GetSelectEntry() ); + + pItem->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintDialog" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "LastPage" ) ), + maTabCtrl.GetPageText( maTabCtrl.GetCurPageId() ) ); + pItem->Commit(); +} + +bool PrintDialog::isPrintToFile() +{ + return maOptionsPage.maToFileBox.IsChecked(); +} + +int PrintDialog::getCopyCount() +{ + return static_cast<int>(maJobPage.maCopyCountField.GetValue()); +} + +bool PrintDialog::isCollate() +{ + return maJobPage.maCopyCountField.GetValue() > 1 ? maJobPage.maCollateBox.IsChecked() : FALSE; +} + +bool PrintDialog::isSingleJobs() +{ + return maOptionsPage.maCollateSingleJobsBox.IsChecked(); +} + +void setHelpId( Window* i_pWindow, const Sequence< rtl::OUString >& i_rHelpIds, sal_Int32 i_nIndex ) +{ + if( i_nIndex >= 0 && i_nIndex < i_rHelpIds.getLength() ) + i_pWindow->SetHelpId( rtl::OUStringToOString( i_rHelpIds.getConstArray()[i_nIndex], RTL_TEXTENCODING_UTF8 ) ); +} + +static void setHelpText( Window* i_pWindow, const Sequence< rtl::OUString >& i_rHelpTexts, sal_Int32 i_nIndex ) +{ + // without a help text set and the correct smartID, + // help texts will be retrieved from the online help system + if( i_nIndex >= 0 && i_nIndex < i_rHelpTexts.getLength() ) + i_pWindow->SetHelpText( i_rHelpTexts.getConstArray()[i_nIndex] ); +} + +void updateMaxSize( const Size& i_rCheckSize, Size& o_rMaxSize ) +{ + if( i_rCheckSize.Width() > o_rMaxSize.Width() ) + o_rMaxSize.Width() = i_rCheckSize.Width(); + if( i_rCheckSize.Height() > o_rMaxSize.Height() ) + o_rMaxSize.Height() = i_rCheckSize.Height(); +} + +void PrintDialog::setupOptionalUI() +{ + std::vector< boost::shared_ptr<vcl::RowOrColumn> > aDynamicColumns; + boost::shared_ptr< vcl::RowOrColumn > pCurColumn; + + Window* pCurParent = 0, *pDynamicPageParent = 0; + USHORT nOptPageId = 9, nCurSubGroup = 0; + bool bOnStaticPage = false; + bool bSubgroupOnStaticPage = false; + + std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> > aPropertyToDependencyRowMap; + + const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() ); + for( int i = 0; i < rOptions.getLength(); i++ ) + { + Sequence< beans::PropertyValue > aOptProp; + rOptions[i].Value >>= aOptProp; + + // extract ui element + bool bEnabled = true; + rtl::OUString aCtrlType; + rtl::OUString aText; + rtl::OUString aPropertyName; + Sequence< rtl::OUString > aChoices; + Sequence< sal_Bool > aChoicesDisabled; + Sequence< rtl::OUString > aHelpTexts; + Sequence< rtl::OUString > aHelpIds; + sal_Int64 nMinValue = 0, nMaxValue = 0; + sal_Int32 nCurHelpText = 0; + rtl::OUString aGroupingHint; + rtl::OUString aDependsOnName; + sal_Int32 nDependsOnValue = 0; + sal_Bool bUseDependencyRow = sal_False; + + for( int n = 0; n < aOptProp.getLength(); n++ ) + { + const beans::PropertyValue& rEntry( aOptProp[ n ] ); + if( rEntry.Name.equalsAscii( "Text" ) ) + { + rEntry.Value >>= aText; + } + else if( rEntry.Name.equalsAscii( "ControlType" ) ) + { + rEntry.Value >>= aCtrlType; + } + else if( rEntry.Name.equalsAscii( "Choices" ) ) + { + rEntry.Value >>= aChoices; + } + else if( rEntry.Name.equalsAscii( "ChoicesDisabled" ) ) + { + rEntry.Value >>= aChoicesDisabled; + } + else if( rEntry.Name.equalsAscii( "Property" ) ) + { + PropertyValue aVal; + rEntry.Value >>= aVal; + aPropertyName = aVal.Name; + } + else if( rEntry.Name.equalsAscii( "Enabled" ) ) + { + sal_Bool bValue = sal_True; + rEntry.Value >>= bValue; + bEnabled = bValue; + } + else if( rEntry.Name.equalsAscii( "GroupingHint" ) ) + { + rEntry.Value >>= aGroupingHint; + } + else if( rEntry.Name.equalsAscii( "DependsOnName" ) ) + { + rEntry.Value >>= aDependsOnName; + } + else if( rEntry.Name.equalsAscii( "DependsOnEntry" ) ) + { + rEntry.Value >>= nDependsOnValue; + } + else if( rEntry.Name.equalsAscii( "AttachToDependency" ) ) + { + rEntry.Value >>= bUseDependencyRow; + } + else if( rEntry.Name.equalsAscii( "MinValue" ) ) + { + rEntry.Value >>= nMinValue; + } + else if( rEntry.Name.equalsAscii( "MaxValue" ) ) + { + rEntry.Value >>= nMaxValue; + } + else if( rEntry.Name.equalsAscii( "HelpText" ) ) + { + if( ! (rEntry.Value >>= aHelpTexts) ) + { + rtl::OUString aHelpText; + if( (rEntry.Value >>= aHelpText) ) + { + aHelpTexts.realloc( 1 ); + *aHelpTexts.getArray() = aHelpText; + } + } + } + else if( rEntry.Name.equalsAscii( "HelpId" ) ) + { + if( ! (rEntry.Value >>= aHelpIds ) ) + { + rtl::OUString aHelpId; + if( (rEntry.Value >>= aHelpId) ) + { + aHelpIds.realloc( 1 ); + *aHelpIds.getArray() = aHelpId; + } + } + } + else if( rEntry.Name.equalsAscii( "HintNoLayoutPage" ) ) + { + sal_Bool bNoLayoutPage = sal_False; + rEntry.Value >>= bNoLayoutPage; + mbShowLayoutPage = ! bNoLayoutPage; + } + } + + // bUseDependencyRow should only be true if a dependency exists + bUseDependencyRow = bUseDependencyRow && (aDependsOnName.getLength() != 0); + + // is it necessary to switch between static and dynamic pages ? + bool bSwitchPage = false; + if( aGroupingHint.getLength() ) + bSwitchPage = true; + else if( aCtrlType.equalsAscii( "Subgroup" ) || (bOnStaticPage && ! bSubgroupOnStaticPage ) ) + bSwitchPage = true; + if( bSwitchPage ) + { + // restore to dynamic + pCurParent = pDynamicPageParent; + if( ! aDynamicColumns.empty() ) + pCurColumn = aDynamicColumns.back(); + else + pCurColumn.reset(); + bOnStaticPage = false; + bSubgroupOnStaticPage = false; + + if( aGroupingHint.equalsAscii( "PrintRange" ) ) + { + pCurColumn = maJobPage.mxPrintRange; + pCurParent = &maJobPage; // set job page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "OptionsPage" ) ) + { + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maOptionsPage.getLayout()); + pCurParent = &maOptionsPage; // set options page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "OptionsPageOptGroup" ) ) + { + pCurColumn = maOptionsPage.mxOptGroup; + pCurParent = &maOptionsPage; // set options page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.equalsAscii( "LayoutPage" ) ) + { + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maNUpPage.getLayout()); + pCurParent = &maNUpPage; // set layout page as current parent + bOnStaticPage = true; + } + else if( aGroupingHint.getLength() ) + { + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maJobPage.getLayout()); + pCurParent = &maJobPage; // set job page as current parent + bOnStaticPage = true; + } + } + + if( aCtrlType.equalsAscii( "Group" ) || + ( ! pCurParent && ! (bOnStaticPage || aGroupingHint.getLength() ) ) ) + { + // add new tab page + TabPage* pNewGroup = new TabPage( &maTabCtrl ); + maControls.push_front( pNewGroup ); + pDynamicPageParent = pCurParent = pNewGroup; + pNewGroup->SetText( aText ); + maTabCtrl.InsertPage( ++nOptPageId, aText ); + maTabCtrl.SetTabPage( nOptPageId, pNewGroup ); + + // set help id + setHelpId( pNewGroup, aHelpIds, 0 ); + // set help text + setHelpText( pNewGroup, aHelpTexts, 0 ); + + // reset subgroup counter + nCurSubGroup = 0; + + aDynamicColumns.push_back( boost::dynamic_pointer_cast<vcl::RowOrColumn>(pNewGroup->getLayout()) ); + pCurColumn = aDynamicColumns.back(); + pCurColumn->setParentWindow( pNewGroup ); + bSubgroupOnStaticPage = false; + bOnStaticPage = false; + } + else if( aCtrlType.equalsAscii( "Subgroup" ) && (pCurParent || aGroupingHint.getLength() ) ) + { + bSubgroupOnStaticPage = (aGroupingHint.getLength() != 0); + // create group FixedLine + if( ! aGroupingHint.equalsAscii( "PrintRange" ) || + ! pCurColumn->countElements() == 0 + ) + { + Window* pNewSub = NULL; + if( aGroupingHint.equalsAscii( "PrintRange" ) ) + pNewSub = new FixedText( pCurParent, WB_VCENTER ); + else + pNewSub = new FixedLine( pCurParent ); + maControls.push_front( pNewSub ); + pNewSub->SetText( aText ); + pNewSub->Show(); + + // set help id + setHelpId( pNewSub, aHelpIds, 0 ); + // set help text + setHelpText( pNewSub, aHelpTexts, 0 ); + // add group to current column + pCurColumn->addWindow( pNewSub ); + } + + // add an indent to the current column + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), -1 ); + pCurColumn->addChild( pIndent ); + // and create a column inside the indent + pCurColumn.reset( new vcl::RowOrColumn( pIndent ) ); + pIndent->setChild( pCurColumn ); + } + // EVIL + else if( aCtrlType.equalsAscii( "Bool" ) && + aGroupingHint.equalsAscii( "LayoutPage" ) && + aPropertyName.equalsAscii( "PrintProspect" ) + ) + { + maNUpPage.maBrochureBtn.SetText( aText ); + maNUpPage.maBrochureBtn.Show(); + setHelpText( &maNUpPage.maBrochureBtn, aHelpTexts, 0 ); + + sal_Bool bVal = sal_False; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + maNUpPage.maBrochureBtn.Check( bVal ); + maNUpPage.maBrochureBtn.Enable( maPController->isUIOptionEnabled( aPropertyName ) && pVal != NULL ); + maNUpPage.maBrochureBtn.SetToggleHdl( LINK( this, PrintDialog, ClickHdl ) ); + + maPropertyToWindowMap[ aPropertyName ].push_back( &maNUpPage.maBrochureBtn ); + maControlToPropertyMap[&maNUpPage.maBrochureBtn] = aPropertyName; + + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, maNUpPage.mxBrochureDep ) ); + } + else + { + boost::shared_ptr<vcl::RowOrColumn> pSaveCurColumn( pCurColumn ); + + if( bUseDependencyRow ) + { + // find the correct dependency row (if any) + std::pair< std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator, + std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator > aDepRange; + aDepRange = aPropertyToDependencyRowMap.equal_range( aDependsOnName ); + if( aDepRange.first != aDepRange.second ) + { + while( nDependsOnValue && aDepRange.first != aDepRange.second ) + { + nDependsOnValue--; + ++aDepRange.first; + } + if( aDepRange.first != aPropertyToDependencyRowMap.end() ) + { + pCurColumn = aDepRange.first->second; + maReverseDependencySet.insert( aPropertyName ); + } + } + } + if( aCtrlType.equalsAscii( "Bool" ) && pCurParent ) + { + // add a check box + CheckBox* pNewBox = new CheckBox( pCurParent ); + maControls.push_front( pNewBox ); + pNewBox->SetText( aText ); + pNewBox->Show(); + + sal_Bool bVal = sal_False; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal ) + pVal->Value >>= bVal; + pNewBox->Check( bVal ); + pNewBox->SetToggleHdl( LINK( this, PrintDialog, UIOption_CheckHdl ) ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pNewBox ); + maControlToPropertyMap[pNewBox] = aPropertyName; + + // set help id + setHelpId( pNewBox, aHelpIds, 0 ); + // set help text + setHelpText( pNewBox, aHelpTexts, 0 ); + + boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pCurColumn.get(), false ) ); + pCurColumn->addChild( pDependencyRow ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) ); + + // add checkbox to current column + pDependencyRow->addWindow( pNewBox ); + } + else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) + { + boost::shared_ptr<vcl::RowOrColumn> pRadioColumn( pCurColumn ); + if( aText.getLength() ) + { + // add a FixedText: + FixedText* pHeading = new FixedText( pCurParent ); + maControls.push_front( pHeading ); + pHeading->SetText( aText ); + pHeading->Show(); + + // set help id + setHelpId( pHeading, aHelpIds, nCurHelpText ); + // set help text + setHelpText( pHeading, aHelpTexts, nCurHelpText ); + nCurHelpText++; + // add fixed text to current column + pCurColumn->addWindow( pHeading ); + // add an indent to the current column + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), 15 ); + pCurColumn->addChild( pIndent ); + // and create a column inside the indent + pRadioColumn.reset( new vcl::RowOrColumn( pIndent ) ); + pIndent->setChild( pRadioColumn ); + } + // iterate options + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn.get(), 1 ) ); + pRadioColumn->addChild( pLabel ); + boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pLabel.get(), false ) ); + pLabel->setElement( pDependencyRow ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) ); + + RadioButton* pBtn = new RadioButton( pCurParent, m == 0 ? WB_GROUP : 0 ); + maControls.push_front( pBtn ); + pBtn->SetText( aChoices[m] ); + pBtn->Check( m == nSelectVal ); + pBtn->SetToggleHdl( LINK( this, PrintDialog, UIOption_RadioHdl ) ); + if( aChoicesDisabled.getLength() > m && aChoicesDisabled[m] == sal_True ) + pBtn->Enable( FALSE ); + pBtn->Show(); + maPropertyToWindowMap[ aPropertyName ].push_back( pBtn ); + maControlToPropertyMap[pBtn] = aPropertyName; + maControlToNumValMap[pBtn] = m; + + // set help id + setHelpId( pBtn, aHelpIds, nCurHelpText ); + // set help text + setHelpText( pBtn, aHelpTexts, nCurHelpText ); + nCurHelpText++; + // add the radio button to the column + pLabel->setLabel( pBtn ); + } + } + else if( ( aCtrlType.equalsAscii( "List" ) || + aCtrlType.equalsAscii( "Range" ) || + aCtrlType.equalsAscii( "Edit" ) + ) && pCurParent ) + { + // create a row in the current column + boost::shared_ptr<vcl::RowOrColumn> pFieldColumn( new vcl::RowOrColumn( pCurColumn.get(), false ) ); + pCurColumn->addChild( pFieldColumn ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pFieldColumn ) ); + + vcl::LabeledElement* pLabel = NULL; + if( aText.getLength() ) + { + // add a FixedText: + FixedText* pHeading = new FixedText( pCurParent, WB_VCENTER ); + maControls.push_front( pHeading ); + pHeading->SetText( aText ); + pHeading->Show(); + + // add to row + pLabel = new vcl::LabeledElement( pFieldColumn.get(), 2 ); + pFieldColumn->addChild( pLabel ); + pLabel->setLabel( pHeading ); + } + + if( aCtrlType.equalsAscii( "List" ) ) + { + ListBox* pList = new ListBox( pCurParent, WB_DROPDOWN | WB_BORDER ); + maControls.push_front( pList ); + + // iterate options + for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) + { + pList->InsertEntry( aChoices[m] ); + } + sal_Int32 nSelectVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nSelectVal; + pList->SelectEntryPos( static_cast<USHORT>(nSelectVal) ); + pList->SetSelectHdl( LINK( this, PrintDialog, UIOption_SelectHdl ) ); + pList->SetDropDownLineCount( static_cast<USHORT>(aChoices.getLength()) ); + pList->Show(); + + // set help id + setHelpId( pList, aHelpIds, 0 ); + // set help text + setHelpText( pList, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pList ); + maControlToPropertyMap[pList] = aPropertyName; + + // finish the pair + if( pLabel ) + pLabel->setElement( pList ); + else + pFieldColumn->addWindow( pList ); + } + else if( aCtrlType.equalsAscii( "Range" ) ) + { + NumericField* pField = new NumericField( pCurParent, WB_BORDER | WB_SPIN ); + maControls.push_front( pField ); + + // set min/max and current value + if( nMinValue != nMaxValue ) + { + pField->SetMin( nMinValue ); + pField->SetMax( nMaxValue ); + } + sal_Int64 nCurVal = 0; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= nCurVal; + pField->SetValue( nCurVal ); + pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) ); + pField->Show(); + + // set help id + setHelpId( pField, aHelpIds, 0 ); + // set help text + setHelpText( pField, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pField ); + maControlToPropertyMap[pField] = aPropertyName; + + // add to row + if( pLabel ) + pLabel->setElement( pField ); + else + pFieldColumn->addWindow( pField ); + } + else if( aCtrlType.equalsAscii( "Edit" ) ) + { + Edit* pField = new Edit( pCurParent, WB_BORDER ); + maControls.push_front( pField ); + + rtl::OUString aCurVal; + PropertyValue* pVal = maPController->getValue( aPropertyName ); + if( pVal && pVal->Value.hasValue() ) + pVal->Value >>= aCurVal; + pField->SetText( aCurVal ); + pField->SetModifyHdl( LINK( this, PrintDialog, UIOption_ModifyHdl ) ); + pField->Show(); + + // set help id + setHelpId( pField, aHelpIds, 0 ); + // set help text + setHelpText( pField, aHelpTexts, 0 ); + + maPropertyToWindowMap[ aPropertyName ].push_back( pField ); + maControlToPropertyMap[pField] = aPropertyName; + + // add to row + if( pLabel ) + pLabel->setElement( pField ); + else + pFieldColumn->addWindow( pField, 2 ); + } + } + else + { + DBG_ERROR( "Unsupported UI option" ); + } + + pCurColumn = pSaveCurColumn; + } + } + + // #i106506# if no brochure button, then the singular Pages radio button + // makes no sense, so replace it by a FixedText label + if( ! maNUpPage.maBrochureBtn.IsVisible() ) + { + if( maNUpPage.mxPagesBtnLabel.get() ) + { + maNUpPage.maPagesBoxTitleTxt.SetText( maNUpPage.maPagesBtn.GetText() ); + maNUpPage.maPagesBoxTitleTxt.Show( TRUE ); + maNUpPage.mxPagesBtnLabel->setLabel( &maNUpPage.maPagesBoxTitleTxt ); + maNUpPage.maPagesBtn.Show( FALSE ); + } + } + + // update enable states + checkOptionalControlDependencies(); + + // print range empty (currently math only) -> hide print range and spacer line + if( maJobPage.mxPrintRange->countElements() == 0 ) + { + maJobPage.mxPrintRange->show( false, false ); + maJobPage.maCopySpacer.Show( FALSE ); + } + +#ifdef WNT + // FIXME: the GetNativeControlRegion call on Windows has some issues + // (which skew the results of GetOptimalSize()) + // however fixing this thoroughly needs to take interaction with paint into + // account, making the right fix less simple. Fix this the right way + // at some point. For now simply add some space at the lowest element + size_t nIndex = maJobPage.getLayout()->countElements(); + if( nIndex > 0 ) // sanity check + maJobPage.getLayout()->setBorders( nIndex-1, 0, 0, 0, -1 ); +#endif + + // create auto mnemomnics now so they can be calculated in layout + ImplWindowAutoMnemonic( &maJobPage ); + ImplWindowAutoMnemonic( &maNUpPage ); + ImplWindowAutoMnemonic( &maOptionsPage ); + ImplWindowAutoMnemonic( this ); + + // calculate job page + Size aMaxSize = maJobPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ); + // and layout page + updateMaxSize( maNUpPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + // and options page + updateMaxSize( maOptionsPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + + for( std::vector< boost::shared_ptr<vcl::RowOrColumn> >::iterator it = aDynamicColumns.begin(); + it != aDynamicColumns.end(); ++it ) + { + Size aPageSize( (*it)->getOptimalSize( WINDOWSIZE_PREFERRED ) ); + updateMaxSize( aPageSize, aMaxSize ); + } + + // resize dialog if necessary + Size aTabSize = maTabCtrl.GetTabPageSizePixel(); + maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() ); + if( aMaxSize.Height() > aTabSize.Height() || aMaxSize.Width() > aTabSize.Width() ) + { + Size aCurSize( GetOutputSizePixel() ); + if( aMaxSize.Height() > aTabSize.Height() ) + { + aCurSize.Height() += aMaxSize.Height() - aTabSize.Height(); + aTabSize.Height() = aMaxSize.Height(); + } + if( aMaxSize.Width() > aTabSize.Width() ) + { + aCurSize.Width() += aMaxSize.Width() - aTabSize.Width(); + // and the tab ctrl needs more space, too + aTabSize.Width() = aMaxSize.Width(); + } + maTabCtrl.SetTabPageSizePixel( aTabSize ); + maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() ); + } + + Size aSz = getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ); + SetOutputSizePixel( aSz ); +} + +void PrintDialog::DataChanged( const DataChangedEvent& i_rDCEvt ) +{ + // react on settings changed + if( i_rDCEvt.GetType() == DATACHANGED_SETTINGS ) + checkControlDependencies(); + ModalDialog::DataChanged( i_rDCEvt ); +} + +void PrintDialog::checkControlDependencies() +{ + if( maJobPage.maCopyCountField.GetValue() > 1 ) + maJobPage.maCollateBox.Enable( maJobPage.mnCollateUIMode == 0 ); + else + maJobPage.maCollateBox.Enable( FALSE ); + + Image aImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateImg : maJobPage.maNoCollateImg ); + Image aHCImg( maJobPage.maCollateBox.IsChecked() ? maJobPage.maCollateHCImg : maJobPage.maNoCollateHCImg ); + bool bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + + Size aImgSize( aImg.GetSizePixel() ); + Size aHCImgSize( aHCImg.GetSizePixel() ); + + if( aHCImgSize.Width() > aImgSize.Width() ) + aImgSize.Width() = aHCImgSize.Width(); + if( aHCImgSize.Height() > aImgSize.Height() ) + aImgSize.Height() = aHCImgSize.Height(); + + // adjust size of image + maJobPage.maCollateImage.SetSizePixel( aImgSize ); + maJobPage.maCollateImage.SetImage( bHC ? aHCImg : aImg ); + maJobPage.maCollateImage.SetModeImage( aHCImg, BMP_COLOR_HIGHCONTRAST ); + maJobPage.getLayout()->resize(); + + // enable setup button only for printers that can be setup + bool bHaveSetup = maPController->getPrinter()->HasSupport( SUPPORT_SETUPDIALOG ); + maJobPage.maSetupButton.Enable( bHaveSetup ); + if( bHaveSetup ) + { + if( ! maJobPage.maSetupButton.IsVisible() ) + { + Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() ); + Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() ); + Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() ); + aPrinterSize.Width() = aSetupPos.X() - aPrinterPos.X() - LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ).Width(); + maJobPage.maPrinters.SetSizePixel( aPrinterSize ); + maJobPage.maSetupButton.Show(); + getLayout()->resize(); + } + } + else + { + if( maJobPage.maSetupButton.IsVisible() ) + { + Point aPrinterPos( maJobPage.maPrinters.GetPosPixel() ); + Point aSetupPos( maJobPage.maSetupButton.GetPosPixel() ); + Size aPrinterSize( maJobPage.maPrinters.GetSizePixel() ); + Size aSetupSize( maJobPage.maSetupButton.GetSizePixel() ); + aPrinterSize.Width() = aSetupPos.X() + aSetupSize.Width() - aPrinterPos.X(); + maJobPage.maPrinters.SetSizePixel( aPrinterSize ); + maJobPage.maSetupButton.Hide(); + getLayout()->resize(); + } + } +} + +void PrintDialog::checkOptionalControlDependencies() +{ + for( std::map< Window*, rtl::OUString >::iterator it = maControlToPropertyMap.begin(); + it != maControlToPropertyMap.end(); ++it ) + { + bool bShouldbeEnabled = maPController->isUIOptionEnabled( it->second ); + if( ! bShouldbeEnabled ) + { + // enable controls that are directly attached to a dependency anyway + // if the normally disabled controls get modified, change the dependency + // so the control would be enabled + // example: in print range "Print All" is selected, "Page Range" is then of course + // not selected and the Edit for the Page Range would be disabled + // as a convenience we should enable the Edit anyway and automatically select + // "Page Range" instead of "Print All" if the Edit gets modified + if( maReverseDependencySet.find( it->second ) != maReverseDependencySet.end() ) + { + rtl::OUString aDep( maPController->getDependency( it->second ) ); + // if the dependency is at least enabled, then enable this control anyway + if( aDep.getLength() && maPController->isUIOptionEnabled( aDep ) ) + bShouldbeEnabled = true; + } + } + + if( bShouldbeEnabled && dynamic_cast<RadioButton*>(it->first) ) + { + std::map< Window*, sal_Int32 >::const_iterator r_it = maControlToNumValMap.find( it->first ); + if( r_it != maControlToNumValMap.end() ) + { + bShouldbeEnabled = maPController->isUIChoiceEnabled( it->second, r_it->second ); + } + } + + + bool bIsEnabled = it->first->IsEnabled(); + // Enable does not do a change check first, so can be less cheap than expected + if( bShouldbeEnabled != bIsEnabled ) + it->first->Enable( bShouldbeEnabled ); + } +} + +static rtl::OUString searchAndReplace( const rtl::OUString& i_rOrig, const char* i_pRepl, sal_Int32 i_nReplLen, const rtl::OUString& i_rRepl ) +{ + sal_Int32 nPos = i_rOrig.indexOfAsciiL( i_pRepl, i_nReplLen ); + if( nPos != -1 ) + { + rtl::OUStringBuffer aBuf( i_rOrig.getLength() ); + aBuf.append( i_rOrig.getStr(), nPos ); + aBuf.append( i_rRepl ); + if( nPos + i_nReplLen < i_rOrig.getLength() ) + aBuf.append( i_rOrig.getStr() + nPos + i_nReplLen ); + return aBuf.makeStringAndClear(); + } + return i_rOrig; +} + +void PrintDialog::updatePrinterText() +{ + String aDefPrt( Printer::GetDefaultPrinterName() ); + const QueueInfo* pInfo = Printer::GetQueueInfo( maJobPage.maPrinters.GetSelectEntry(), true ); + if( pInfo ) + { + maJobPage.maLocationTxt.SetText( pInfo->GetLocation() ); + maJobPage.maCommentTxt.SetText( pInfo->GetComment() ); + // FIXME: status text + rtl::OUString aStatus; + if( aDefPrt == pInfo->GetPrinterName() ) + aStatus = maDefPrtText; + maJobPage.maStatusTxt.SetText( aStatus ); + } + else + { + maJobPage.maLocationTxt.SetText( String() ); + maJobPage.maCommentTxt.SetText( String() ); + maJobPage.maStatusTxt.SetText( String() ); + } +} + +void PrintDialog::setPreviewText( sal_Int32 ) +{ + rtl::OUString aNewText( searchAndReplace( maPageStr, "%n", 2, rtl::OUString::valueOf( mnCachedPages ) ) ); + maNumPagesText.SetText( aNewText ); + + // if layout is already established the refresh layout of + // preview controls since text length may have changes + if( mxPreviewCtrls.get() ) + mxPreviewCtrls->setManagedArea( mxPreviewCtrls->getManagedArea() ); +} + +void PrintDialog::preparePreview( bool i_bNewPage, bool i_bMayUseCache ) +{ + // page range may have changed depending on options + sal_Int32 nPages = maPController->getFilteredPageCount(); + mnCachedPages = nPages; + + if( mnCurPage >= nPages ) + mnCurPage = nPages-1; + if( mnCurPage < 0 ) + mnCurPage = 0; + + setPreviewText( mnCurPage ); + + maPageEdit.SetMin( 1 ); + maPageEdit.SetMax( nPages ); + + if( i_bNewPage ) + { + const MapMode aMapMode( MAP_100TH_MM ); + GDIMetaFile aMtf; + boost::shared_ptr<Printer> aPrt( maPController->getPrinter() ); + if( nPages > 0 ) + { + PrinterController::PageSize aPageSize = + maPController->getFilteredPageFile( mnCurPage, aMtf, i_bMayUseCache ); + if( ! aPageSize.bFullPaper ) + { + Point aOff( aPrt->PixelToLogic( aPrt->GetPageOffsetPixel(), aMapMode ) ); + aMtf.Move( aOff.X(), aOff.Y() ); + } + } + + Size aCurPageSize = aPrt->PixelToLogic( aPrt->GetPaperSizePixel(), MapMode( MAP_100TH_MM ) ); + maPreviewWindow.setPreview( aMtf, aCurPageSize, nPages > 0 ? rtl::OUString() : maNoPageStr, + aPrt->ImplGetDPIX(), aPrt->ImplGetDPIY(), + aPrt->GetPrinterOptions().IsConvertToGreyscales() + ); + + maForwardBtn.Enable( mnCurPage < nPages-1 ); + maBackwardBtn.Enable( mnCurPage != 0 ); + maPageEdit.Enable( nPages > 1 ); + } +} + +Size PrintDialog::getJobPageSize() +{ + if( maFirstPageSize.Width() == 0 && maFirstPageSize.Height() == 0) + { + maFirstPageSize = maNupPortraitSize; + GDIMetaFile aMtf; + if( maPController->getPageCountProtected() > 0 ) + { + PrinterController::PageSize aPageSize = maPController->getPageFile( 0, aMtf, true ); + maFirstPageSize = aPageSize.aSize; + } + } + return maFirstPageSize; +} + +void PrintDialog::updateNupFromPages() +{ + long nPages = long(maNUpPage.maNupPagesBox.GetEntryData(maNUpPage.maNupPagesBox.GetSelectEntryPos())); + int nRows = int(maNUpPage.maNupRowsEdt.GetValue()); + int nCols = int(maNUpPage.maNupColEdt.GetValue()); + long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM ))); + long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM ))); + bool bCustom = false; + + if( nPages == 1 ) + { + nRows = nCols = 1; + nSheetMargin = 0; + nPageMargin = 0; + } + else if( nPages == 2 || nPages == 4 || nPages == 6 || nPages == 9 || nPages == 16 ) + { + Size aJobPageSize( getJobPageSize() ); + bool bPortrait = aJobPageSize.Width() < aJobPageSize.Height(); + if( nPages == 2 ) + { + if( bPortrait ) + nRows = 1, nCols = 2; + else + nRows = 2, nCols = 1; + } + else if( nPages == 4 ) + nRows = nCols = 2; + else if( nPages == 6 ) + { + if( bPortrait ) + nRows = 2, nCols = 3; + else + nRows = 3, nCols = 2; + } + else if( nPages == 9 ) + nRows = nCols = 3; + else if( nPages == 16 ) + nRows = nCols = 4; + nPageMargin = 0; + nSheetMargin = 0; + } + else + bCustom = true; + + if( nPages > 1 ) + { + // set upper limits for margins based on job page size and rows/columns + Size aSize( getJobPageSize() ); + + // maximum sheet distance: 1/2 sheet + long nHorzMax = aSize.Width()/2; + long nVertMax = aSize.Height()/2; + if( nSheetMargin > nHorzMax ) + nSheetMargin = nHorzMax; + if( nSheetMargin > nVertMax ) + nSheetMargin = nVertMax; + + maNUpPage.maSheetMarginEdt.SetMax( + maNUpPage.maSheetMarginEdt.Normalize( + nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM ); + + // maximum page distance + nHorzMax = (aSize.Width() - 2*nSheetMargin); + if( nCols > 1 ) + nHorzMax /= (nCols-1); + nVertMax = (aSize.Height() - 2*nSheetMargin); + if( nRows > 1 ) + nHorzMax /= (nRows-1); + + if( nPageMargin > nHorzMax ) + nPageMargin = nHorzMax; + if( nPageMargin > nVertMax ) + nPageMargin = nVertMax; + + maNUpPage.maPageMarginEdt.SetMax( + maNUpPage.maSheetMarginEdt.Normalize( + nHorzMax > nVertMax ? nVertMax : nHorzMax ), FUNIT_100TH_MM ); + } + + maNUpPage.maNupRowsEdt.SetValue( nRows ); + maNUpPage.maNupColEdt.SetValue( nCols ); + maNUpPage.maPageMarginEdt.SetValue( maNUpPage.maPageMarginEdt.Normalize( nPageMargin ), FUNIT_100TH_MM ); + maNUpPage.maSheetMarginEdt.SetValue( maNUpPage.maSheetMarginEdt.Normalize( nSheetMargin ), FUNIT_100TH_MM ); + + maNUpPage.showAdvancedControls( bCustom ); + if( bCustom ) + { + // see if we have to enlarge the dialog to make the tab page fit + Size aCurSize( maNUpPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ) ); + Size aTabSize( maTabCtrl.GetTabPageSizePixel() ); + if( aTabSize.Height() < aCurSize.Height() ) + { + Size aDlgSize( GetSizePixel() ); + aDlgSize.Height() += aCurSize.Height() - aTabSize.Height(); + SetSizePixel( aDlgSize ); + } + } + + updateNup(); +} + +void PrintDialog::updateNup() +{ + int nRows = int(maNUpPage.maNupRowsEdt.GetValue()); + int nCols = int(maNUpPage.maNupColEdt.GetValue()); + long nPageMargin = long(maNUpPage.maPageMarginEdt.Denormalize(maNUpPage.maPageMarginEdt.GetValue( FUNIT_100TH_MM ))); + long nSheetMargin = long(maNUpPage.maSheetMarginEdt.Denormalize(maNUpPage.maSheetMarginEdt.GetValue( FUNIT_100TH_MM ))); + + PrinterController::MultiPageSetup aMPS; + aMPS.nRows = nRows; + aMPS.nColumns = nCols; + aMPS.nRepeat = 1; + aMPS.nLeftMargin = + aMPS.nTopMargin = + aMPS.nRightMargin = + aMPS.nBottomMargin = nSheetMargin; + + aMPS.nHorizontalSpacing = + aMPS.nVerticalSpacing = nPageMargin; + + aMPS.bDrawBorder = maNUpPage.maBorderCB.IsChecked(); + + int nOrderMode = int(sal_IntPtr(maNUpPage.maNupOrderBox.GetEntryData( + maNUpPage.maNupOrderBox.GetSelectEntryPos() ))); + if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_LRTB ) + aMPS.nOrder = PrinterController::LRTB; + else if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_TBLR ) + aMPS.nOrder = PrinterController::TBLR; + else if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_RLTB ) + aMPS.nOrder = PrinterController::RLTB; + else if( nOrderMode == SV_PRINT_PRT_NUP_ORDER_TBRL ) + aMPS.nOrder = PrinterController::TBRL; + + int nOrientationMode = int(sal_IntPtr(maNUpPage.maNupOrientationBox.GetEntryData( + maNUpPage.maNupOrientationBox.GetSelectEntryPos() ))); + if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_LANDSCAPE ) + aMPS.aPaperSize = maNupLandscapeSize; + else if( nOrientationMode == SV_PRINT_PRT_NUP_ORIENTATION_PORTRAIT ) + aMPS.aPaperSize = maNupPortraitSize; + else // automatic mode + { + // get size of first real page to see if it is portrait or landscape + // we assume same page sizes for all the pages for this + Size aPageSize = getJobPageSize(); + + Size aMultiSize( aPageSize.Width() * nCols, aPageSize.Height() * nRows ); + if( aMultiSize.Width() > aMultiSize.Height() ) // fits better on landscape + aMPS.aPaperSize = maNupLandscapeSize; + else + aMPS.aPaperSize = maNupPortraitSize; + } + + maPController->setMultipage( aMPS ); + + maNUpPage.maNupOrderWin.setValues( nOrderMode, nCols, nRows ); + + preparePreview( true, true ); +} + +IMPL_LINK( PrintDialog, SelectHdl, ListBox*, pBox ) +{ + if( pBox == &maJobPage.maPrinters ) + { + String aNewPrinter( pBox->GetSelectEntry() ); + // set new printer + maPController->setPrinter( boost::shared_ptr<Printer>( new Printer( aNewPrinter ) ) ); + maPController->resetPrinterOptions( maOptionsPage.maToFileBox.IsChecked() ); + // update text fields + updatePrinterText(); + } + else if( pBox == &maNUpPage.maNupOrientationBox || pBox == &maNUpPage.maNupOrderBox ) + { + updateNup(); + } + else if( pBox == &maNUpPage.maNupPagesBox ) + { + if( !maNUpPage.maPagesBtn.IsChecked() ) + maNUpPage.maPagesBtn.Check(); + updateNupFromPages(); + } + + return 0; +} + +IMPL_LINK( PrintDialog, ClickHdl, Button*, pButton ) +{ + if( pButton == &maOKButton || pButton == &maCancelButton ) + { + storeToSettings(); + EndDialog( pButton == &maOKButton ); + } + else if( pButton == &maHelpButton ) + { + // start help system + Help* pHelp = Application::GetHelp(); + if( pHelp ) + { + pHelp->Start( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".HelpID:vcl:PrintDialog:OK" ) ), &maOKButton ); + } + } + else if( pButton == &maForwardBtn ) + { + previewForward(); + } + else if( pButton == &maBackwardBtn ) + { + previewBackward(); + } + else if( pButton == &maOptionsPage.maToFileBox ) + { + maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText ); + maPController->resetPrinterOptions( maOptionsPage.maToFileBox.IsChecked() ); + getLayout()->resize(); + preparePreview( true, true ); + } + else if( pButton == &maNUpPage.maBrochureBtn ) + { + PropertyValue* pVal = getValueForWindow( pButton ); + if( pVal ) + { + sal_Bool bVal = maNUpPage.maBrochureBtn.IsChecked(); + pVal->Value <<= bVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + if( maNUpPage.maBrochureBtn.IsChecked() ) + { + maNUpPage.maNupPagesBox.SelectEntryPos( 0 ); + updateNupFromPages(); + maNUpPage.showAdvancedControls( false ); + maNUpPage.enableNupControls( false ); + } + } + else if( pButton == &maNUpPage.maPagesBtn ) + { + maNUpPage.enableNupControls( true ); + updateNupFromPages(); + } + else if( pButton == &maJobPage.maDetailsBtn ) + { + bool bShow = maJobPage.maDetailsBtn.IsChecked(); + maJobPage.mxDetails->show( bShow ); + if( bShow ) + { + maDetailsCollapsedSize = GetOutputSizePixel(); + // enlarge dialog if necessary + Size aMinSize( maJobPage.getLayout()->getOptimalSize( WINDOWSIZE_MINIMUM ) ); + Size aCurSize( maJobPage.GetSizePixel() ); + if( aCurSize.Height() < aMinSize.Height() ) + { + Size aDlgSize( GetOutputSizePixel() ); + aDlgSize.Height() += aMinSize.Height() - aCurSize.Height(); + SetOutputSizePixel( aDlgSize ); + } + maDetailsExpandedSize = GetOutputSizePixel(); + } + else if( maDetailsCollapsedSize.Width() > 0 && + maDetailsCollapsedSize.Height() > 0 ) + { + // if the user did not resize the dialog + // make it smaller again on collapsing the details + Size aDlgSize( GetOutputSizePixel() ); + if( aDlgSize == maDetailsExpandedSize && + aDlgSize.Height() > maDetailsCollapsedSize.Height() ) + { + SetOutputSizePixel( maDetailsCollapsedSize ); + } + } + } + else if( pButton == &maJobPage.maCollateBox ) + { + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + makeAny( sal_Bool(isCollate()) ) ); + checkControlDependencies(); + } + else if( pButton == &maOptionsPage.maReverseOrderBox ) + { + sal_Bool bChecked = maOptionsPage.maReverseOrderBox.IsChecked(); + maPController->setReversePrint( bChecked ); + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintReverse" ) ), + makeAny( bChecked ) ); + preparePreview( true, true ); + } + else if( pButton == &maNUpPage.maBorderCB ) + { + updateNup(); + } + else + { + if( pButton == &maJobPage.maSetupButton ) + { + maPController->setupPrinter( this ); + preparePreview( true, true ); + } + checkControlDependencies(); + } + return 0; +} + +IMPL_LINK( PrintDialog, ModifyHdl, Edit*, pEdit ) +{ + checkControlDependencies(); + if( pEdit == &maNUpPage.maNupRowsEdt || pEdit == &maNUpPage.maNupColEdt || + pEdit == &maNUpPage.maSheetMarginEdt || pEdit == &maNUpPage.maPageMarginEdt + ) + { + updateNupFromPages(); + } + else if( pEdit == &maPageEdit ) + { + mnCurPage = sal_Int32( maPageEdit.GetValue() - 1 ); + preparePreview( true, true ); + } + else if( pEdit == &maJobPage.maCopyCountField ) + { + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CopyCount" ) ), + makeAny( sal_Int32(maJobPage.maCopyCountField.GetValue()) ) ); + maPController->setValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ), + makeAny( sal_Bool(isCollate()) ) ); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOptionsChanged, void*, EMPTYARG ) +{ + checkOptionalControlDependencies(); + return 0; +} + +PropertyValue* PrintDialog::getValueForWindow( Window* i_pWindow ) const +{ + PropertyValue* pVal = NULL; + std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow ); + if( it != maControlToPropertyMap.end() ) + { + pVal = maPController->getValue( it->second ); + DBG_ASSERT( pVal, "property value not found" ); + } + else + { + DBG_ERROR( "changed control not in property map" ); + } + return pVal; +} + +void PrintDialog::updateWindowFromProperty( const rtl::OUString& i_rProperty ) +{ + beans::PropertyValue* pValue = maPController->getValue( i_rProperty ); + std::map< rtl::OUString, std::vector< Window* > >::const_iterator it = maPropertyToWindowMap.find( i_rProperty ); + if( pValue && it != maPropertyToWindowMap.end() ) + { + const std::vector< Window* >& rWindows( it->second ); + if( ! rWindows.empty() ) + { + sal_Bool bVal = sal_False; + sal_Int32 nVal = -1; + if( pValue->Value >>= bVal ) + { + // we should have a CheckBox for this one + CheckBox* pBox = dynamic_cast< CheckBox* >( rWindows.front() ); + if( pBox ) + { + pBox->Check( bVal ); + } + else if( i_rProperty.equalsAscii( "PrintProspect" ) ) + { + // EVIL special case + if( bVal ) + maNUpPage.maBrochureBtn.Check(); + else + maNUpPage.maPagesBtn.Check(); + } + else + { + DBG_ASSERT( 0, "missing a checkbox" ); + } + } + else if( pValue->Value >>= nVal ) + { + // this could be a ListBox or a RadioButtonGroup + ListBox* pList = dynamic_cast< ListBox* >( rWindows.front() ); + if( pList ) + { + pList->SelectEntryPos( static_cast< USHORT >(nVal) ); + } + else if( nVal >= 0 && nVal < sal_Int32(rWindows.size() ) ) + { + RadioButton* pBtn = dynamic_cast< RadioButton* >( rWindows[nVal] ); + DBG_ASSERT( pBtn, "unexpected control for property" ); + if( pBtn ) + pBtn->Check(); + } + } + } + } +} + +void PrintDialog::makeEnabled( Window* i_pWindow ) +{ + std::map< Window*, rtl::OUString >::const_iterator it = maControlToPropertyMap.find( i_pWindow ); + if( it != maControlToPropertyMap.end() ) + { + rtl::OUString aDependency( maPController->makeEnabled( it->second ) ); + if( aDependency.getLength() ) + updateWindowFromProperty( aDependency ); + } +} + +IMPL_LINK( PrintDialog, UIOption_CheckHdl, CheckBox*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + sal_Bool bVal = i_pBox->IsChecked(); + pVal->Value <<= bVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_RadioHdl, RadioButton*, i_pBtn ) +{ + // this handler gets called for all radiobuttons that get unchecked, too + // however we only want one notificaction for the new value (that is for + // the button that gets checked) + if( i_pBtn->IsChecked() ) + { + PropertyValue* pVal = getValueForWindow( i_pBtn ); + std::map< Window*, sal_Int32 >::const_iterator it = maControlToNumValMap.find( i_pBtn ); + if( pVal && it != maControlToNumValMap.end() ) + { + makeEnabled( i_pBtn ); + + sal_Int32 nVal = it->second; + pVal->Value <<= nVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_SelectHdl, ListBox*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + sal_Int32 nVal( i_pBox->GetSelectEntryPos() ); + pVal->Value <<= nVal; + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +IMPL_LINK( PrintDialog, UIOption_ModifyHdl, Edit*, i_pBox ) +{ + PropertyValue* pVal = getValueForWindow( i_pBox ); + if( pVal ) + { + makeEnabled( i_pBox ); + + NumericField* pNum = dynamic_cast<NumericField*>(i_pBox); + MetricField* pMetric = dynamic_cast<MetricField*>(i_pBox); + if( pNum ) + { + sal_Int64 nVal = pNum->GetValue(); + pVal->Value <<= nVal; + } + else if( pMetric ) + { + sal_Int64 nVal = pMetric->GetValue(); + pVal->Value <<= nVal; + } + else + { + rtl::OUString aVal( i_pBox->GetText() ); + pVal->Value <<= aVal; + } + + checkOptionalControlDependencies(); + + // update preview and page settings + preparePreview(); + } + return 0; +} + +void PrintDialog::Command( const CommandEvent& rEvt ) +{ + if( rEvt.GetCommand() == COMMAND_WHEEL ) + { + const CommandWheelData* pWheelData = rEvt.GetWheelData(); + if( pWheelData->GetDelta() > 0 ) + previewForward(); + else if( pWheelData->GetDelta() < 0 ) + previewBackward(); + /* + else + huh ? + */ + } +} + +void PrintDialog::Resize() +{ + // maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); + // and do the preview; however the metafile does not need to be gotten anew + preparePreview( false ); + + // do an invalidate for the benefit of the grouping elements + Invalidate(); +} + +void PrintDialog::previewForward() +{ + maPageEdit.Up(); +} + +void PrintDialog::previewBackward() +{ + maPageEdit.Down(); +} + +// ----------------------------------------------------------------------------- +// +// PrintProgressDialog +// +// ----------------------------------------------------------------------------- + +PrintProgressDialog::PrintProgressDialog( Window* i_pParent, int i_nMax ) : + ModelessDialog( i_pParent, VclResId( SV_DLG_PRINT_PROGRESS ) ), + maText( this, VclResId( SV_PRINT_PROGRESS_TEXT ) ), + maButton( this, VclResId( SV_PRINT_PROGRESS_CANCEL ) ), + mbCanceled( false ), + mnCur( 0 ), + mnMax( i_nMax ), + mnProgressHeight( 15 ), + mbNativeProgress( false ) +{ + FreeResource(); + + if( mnMax < 1 ) + mnMax = 1; + + maStr = maText.GetText(); + + maButton.SetClickHdl( LINK( this, PrintProgressDialog, ClickHdl ) ); + +} + +PrintProgressDialog::~PrintProgressDialog() +{ +} + +IMPL_LINK( PrintProgressDialog, ClickHdl, Button*, pButton ) +{ + if( pButton == &maButton ) + mbCanceled = true; + + return 0; +} + +void PrintProgressDialog::implCalcProgressRect() +{ + if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Rectangle aControlRegion( Point(), Size( 100, mnProgressHeight ) ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) ) + { + mnProgressHeight = aNativeControlRegion.GetHeight(); + } + mbNativeProgress = true; + } + maProgressRect = Rectangle( Point( 10, maText.GetPosPixel().Y() + maText.GetSizePixel().Height() + 8 ), + Size( GetSizePixel().Width() - 20, mnProgressHeight ) ); +} + +void PrintProgressDialog::setProgress( int i_nCurrent, int i_nMax ) +{ + if( maProgressRect.IsEmpty() ) + implCalcProgressRect(); + + mnCur = i_nCurrent; + if( i_nMax != -1 ) + mnMax = i_nMax; + + if( mnMax < 1 ) + mnMax = 1; + + rtl::OUString aNewText( searchAndReplace( maStr, "%p", 2, rtl::OUString::valueOf( mnCur ) ) ); + aNewText = searchAndReplace( aNewText, "%n", 2, rtl::OUString::valueOf( mnMax ) ); + maText.SetText( aNewText ); + + // update progress + Invalidate( maProgressRect, INVALIDATE_UPDATE ); +} + +void PrintProgressDialog::tick() +{ + if( mnCur < mnMax ) + setProgress( ++mnCur ); +} + +void PrintProgressDialog::reset() +{ + mbCanceled = false; + setProgress( 0 ); +} + +void PrintProgressDialog::Paint( const Rectangle& ) +{ + if( maProgressRect.IsEmpty() ) + implCalcProgressRect(); + + Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aPrgsColor = rStyleSettings.GetHighlightColor(); + if ( aPrgsColor == rStyleSettings.GetFaceColor() ) + aPrgsColor = rStyleSettings.GetDarkShadowColor(); + SetLineColor(); + SetFillColor( aPrgsColor ); + + const long nOffset = 3; + const long nWidth = 3*mnProgressHeight/2; + const long nFullWidth = nWidth + nOffset; + const long nMaxCount = maProgressRect.GetWidth() / nFullWidth; + DrawProgress( this, maProgressRect.TopLeft(), + nOffset, + nWidth, + mnProgressHeight, + static_cast<USHORT>(0), + static_cast<USHORT>(10000*mnCur/mnMax), + static_cast<USHORT>(10000/nMaxCount), + maProgressRect + ); + Pop(); + + if( ! mbNativeProgress ) + { + DecorationView aDecoView( this ); + Rectangle aFrameRect( maProgressRect ); + aFrameRect.Left() -= nOffset; + aFrameRect.Right() += nOffset; + aFrameRect.Top() -= nOffset; + aFrameRect.Bottom() += nOffset; + aDecoView.DrawFrame( aFrameRect ); + } +} + diff --git a/vcl/source/window/scrwnd.cxx b/vcl/source/window/scrwnd.cxx new file mode 100644 index 000000000000..735add842518 --- /dev/null +++ b/vcl/source/window/scrwnd.cxx @@ -0,0 +1,420 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +// #include <math.h> +#include <limits.h> +#include <tools/time.hxx> +#include <tools/debug.hxx> + +#ifndef _SV_SVIDS_HRC +#include <vcl/svids.hrc> +#endif +#include <vcl/svdata.hxx> +#ifndef _VCL_TIMER_HXX +#include <vcl/timer.hxx> +#endif +#ifndef _VCL_EVENT_HXX +#include <vcl/event.hxx> +#endif +#ifndef _VCL_SCRWND_HXX +#include <scrwnd.hxx> +#endif + +#include <math.h> +#include <limits.h> + +// ----------- +// - Defines - +// ----------- + +#define WHEEL_WIDTH 25 +#define WHEEL_RADIUS ((WHEEL_WIDTH) >> 1 ) +#define MAX_TIME 300 +#define MIN_TIME 20 +#define DEF_TIMEOUT 50 + +// ------------------- +// - ImplWheelWindow - +// ------------------- + +ImplWheelWindow::ImplWheelWindow( Window* pParent ) : + FloatingWindow ( pParent, 0 ), + mnRepaintTime ( 1UL ), + mnTimeout ( DEF_TIMEOUT ), + mnWheelMode ( WHEELMODE_NONE ), + mnActDist ( 0UL ), + mnActDeltaX ( 0L ), + mnActDeltaY ( 0L ) +{ + // we need a parent + DBG_ASSERT( pParent, "ImplWheelWindow::ImplWheelWindow(): Parent not set!" ); + + const Size aSize( pParent->GetOutputSizePixel() ); + const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; + const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; + const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; + + // calculate maximum speed distance + mnMaxWidth = (ULONG) ( 0.4 * hypot( (double) aSize.Width(), aSize.Height() ) ); + + // create wheel window + SetTitleType( FLOATWIN_TITLE_NONE ); + ImplCreateImageList(); + ResMgr* pResMgr = ImplGetResMgr(); + Bitmap aBmp; + if( pResMgr ) + aBmp = Bitmap( ResId( SV_RESID_BITMAP_SCROLLMSK, *pResMgr ) ); + ImplSetRegion( aBmp ); + + // set wheel mode + if( bHorz && bVert ) + ImplSetWheelMode( WHEELMODE_VH ); + else if( bHorz ) + ImplSetWheelMode( WHEELMODE_H ); + else + ImplSetWheelMode( WHEELMODE_V ); + + // init timer + mpTimer = new Timer; + mpTimer->SetTimeoutHdl( LINK( this, ImplWheelWindow, ImplScrollHdl ) ); + mpTimer->SetTimeout( mnTimeout ); + mpTimer->Start(); + + CaptureMouse(); +} + +// ------------------------------------------------------------------------ + +ImplWheelWindow::~ImplWheelWindow() +{ + ImplStop(); + delete mpTimer; +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplStop() +{ + ReleaseMouse(); + mpTimer->Stop(); + Show(FALSE); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplSetRegion( const Bitmap& rRegionBmp ) +{ + Point aPos( GetPointerPosPixel() ); + const Size aSize( rRegionBmp.GetSizePixel() ); + Point aPoint; + const Rectangle aRect( aPoint, aSize ); + + maCenter = maLastMousePos = aPos; + aPos.X() -= aSize.Width() >> 1; + aPos.Y() -= aSize.Height() >> 1; + + SetPosSizePixel( aPos, aSize ); + SetWindowRegionPixel( rRegionBmp.CreateRegion( COL_BLACK, aRect ) ); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplCreateImageList() +{ + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + maImgList.InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_SCROLLBMP, *pResMgr ), 6, NULL ); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplSetWheelMode( ULONG nWheelMode ) +{ + if( nWheelMode != mnWheelMode ) + { + mnWheelMode = nWheelMode; + + if( WHEELMODE_NONE == mnWheelMode ) + { + if( IsVisible() ) + Hide(); + } + else + { + if( !IsVisible() ) + Show(); + + ImplDrawWheel(); + } + } +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplDrawWheel() +{ + USHORT nId; + + switch( mnWheelMode ) + { + case( WHEELMODE_VH ): nId = 1; break; + case( WHEELMODE_V ): nId = 2; break; + case( WHEELMODE_H ): nId = 3; break; + case( WHEELMODE_SCROLL_VH ):nId = 4; break; + case( WHEELMODE_SCROLL_V ): nId = 5; break; + case( WHEELMODE_SCROLL_H ): nId = 6; break; + default: nId = 0; break; + } + + if( nId ) + DrawImage( Point(), maImgList.GetImage( nId ) ); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::ImplRecalcScrollValues() +{ + if( mnActDist < WHEEL_RADIUS ) + { + mnActDeltaX = mnActDeltaY = 0L; + mnTimeout = DEF_TIMEOUT; + } + else + { + ULONG nCurTime; + + // calc current time + if( mnMaxWidth ) + { + const double fExp = ( (double) mnActDist / mnMaxWidth ) * log10( (double) MAX_TIME / MIN_TIME ); + nCurTime = (ULONG) ( MAX_TIME / pow( 10., fExp ) ); + } + else + nCurTime = MAX_TIME; + + if( !nCurTime ) + nCurTime = 1UL; + + if( mnRepaintTime <= nCurTime ) + mnTimeout = nCurTime - mnRepaintTime; + else + { + long nMult = mnRepaintTime / nCurTime; + + if( !( mnRepaintTime % nCurTime ) ) + mnTimeout = 0UL; + else + mnTimeout = ++nMult * nCurTime - mnRepaintTime; + + double fValX = (double) mnActDeltaX * nMult; + double fValY = (double) mnActDeltaY * nMult; + + if( fValX > LONG_MAX ) + mnActDeltaX = LONG_MAX; + else if( fValX < LONG_MIN ) + mnActDeltaX = LONG_MIN; + else + mnActDeltaX = (long) fValX; + + if( fValY > LONG_MAX ) + mnActDeltaY = LONG_MAX; + else if( fValY < LONG_MIN ) + mnActDeltaY = LONG_MIN; + else + mnActDeltaY = (long) fValY; + } + } +} + +// ------------------------------------------------------------------------ + +PointerStyle ImplWheelWindow::ImplGetMousePointer( long nDistX, long nDistY ) +{ + PointerStyle eStyle; + const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; + const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; + const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; + + if( bHorz || bVert ) + { + if( mnActDist < WHEEL_RADIUS ) + { + if( bHorz && bVert ) + eStyle = POINTER_AUTOSCROLL_NSWE; + else if( bHorz ) + eStyle = POINTER_AUTOSCROLL_WE; + else + eStyle = POINTER_AUTOSCROLL_NS; + } + else + { + double fAngle = atan2( (double) -nDistY, nDistX ) / F_PI180; + + if( fAngle < 0.0 ) + fAngle += 360.; + + if( bHorz && bVert ) + { + if( fAngle >= 22.5 && fAngle <= 67.5 ) + eStyle = POINTER_AUTOSCROLL_NE; + else if( fAngle >= 67.5 && fAngle <= 112.5 ) + eStyle = POINTER_AUTOSCROLL_N; + else if( fAngle >= 112.5 && fAngle <= 157.5 ) + eStyle = POINTER_AUTOSCROLL_NW; + else if( fAngle >= 157.5 && fAngle <= 202.5 ) + eStyle = POINTER_AUTOSCROLL_W; + else if( fAngle >= 202.5 && fAngle <= 247.5 ) + eStyle = POINTER_AUTOSCROLL_SW; + else if( fAngle >= 247.5 && fAngle <= 292.5 ) + eStyle = POINTER_AUTOSCROLL_S; + else if( fAngle >= 292.5 && fAngle <= 337.5 ) + eStyle = POINTER_AUTOSCROLL_SE; + else + eStyle = POINTER_AUTOSCROLL_E; + } + else if( bHorz ) + { + if( fAngle >= 270. || fAngle <= 90. ) + eStyle = POINTER_AUTOSCROLL_E; + else + eStyle = POINTER_AUTOSCROLL_W; + } + else + { + if( fAngle >= 0. && fAngle <= 180. ) + eStyle = POINTER_AUTOSCROLL_N; + else + eStyle = POINTER_AUTOSCROLL_S; + } + } + } + else + eStyle = POINTER_ARROW; + + return eStyle; +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::Paint( const Rectangle& ) +{ + ImplDrawWheel(); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt ) +{ + FloatingWindow::MouseMove( rMEvt ); + + const Point aMousePos( OutputToScreenPixel( rMEvt.GetPosPixel() ) ); + const long nDistX = aMousePos.X() - maCenter.X(); + const long nDistY = aMousePos.Y() - maCenter.Y(); + + mnActDist = (ULONG) hypot( (double) nDistX, nDistY ); + + const PointerStyle eActStyle = ImplGetMousePointer( nDistX, nDistY ); + const USHORT nFlags = ImplGetSVData()->maWinData.mnAutoScrollFlags; + const BOOL bHorz = ( nFlags & AUTOSCROLL_HORZ ) != 0; + const BOOL bVert = ( nFlags & AUTOSCROLL_VERT ) != 0; + const BOOL bOuter = mnActDist > WHEEL_RADIUS; + + if( bOuter && ( maLastMousePos != aMousePos ) ) + { + switch( eActStyle ) + { + case( POINTER_AUTOSCROLL_N ): mnActDeltaX = +0L, mnActDeltaY = +1L; break; + case( POINTER_AUTOSCROLL_S ): mnActDeltaX = +0L, mnActDeltaY = -1L; break; + case( POINTER_AUTOSCROLL_W ): mnActDeltaX = +1L, mnActDeltaY = +0L; break; + case( POINTER_AUTOSCROLL_E ): mnActDeltaX = -1L, mnActDeltaY = +0L; break; + case( POINTER_AUTOSCROLL_NW ): mnActDeltaX = +1L, mnActDeltaY = +1L; break; + case( POINTER_AUTOSCROLL_NE ): mnActDeltaX = -1L, mnActDeltaY = +1L; break; + case( POINTER_AUTOSCROLL_SW ): mnActDeltaX = +1L, mnActDeltaY = -1L; break; + case( POINTER_AUTOSCROLL_SE ): mnActDeltaX = -1L, mnActDeltaY = -1L; break; + + default: + break; + } + } + + ImplRecalcScrollValues(); + maLastMousePos = aMousePos; + SetPointer( eActStyle ); + + if( bHorz && bVert ) + ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_VH : WHEELMODE_VH ); + else if( bHorz ) + ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_H : WHEELMODE_H ); + else + ImplSetWheelMode( bOuter ? WHEELMODE_SCROLL_V : WHEELMODE_V ); +} + +// ------------------------------------------------------------------------ + +void ImplWheelWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if( mnActDist > WHEEL_RADIUS ) + GetParent()->EndAutoScroll(); + else + FloatingWindow::MouseButtonUp( rMEvt ); +} + +// ------------------------------------------------------------------------ + +IMPL_LINK( ImplWheelWindow, ImplScrollHdl, Timer*, EMPTYARG ) +{ + if ( mnActDeltaX || mnActDeltaY ) + { + Window* pWindow = GetParent(); + const Point aMousePos( pWindow->OutputToScreenPixel( pWindow->GetPointerPosPixel() ) ); + Point aCmdMousePos( pWindow->ImplFrameToOutput( aMousePos ) ); + CommandScrollData aScrollData( mnActDeltaX, mnActDeltaY ); + CommandEvent aCEvt( aCmdMousePos, COMMAND_AUTOSCROLL, TRUE, &aScrollData ); + NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); + + if ( !ImplCallPreNotify( aNCmdEvt ) ) + { + const ULONG nTime = Time::GetSystemTicks(); + ImplDelData aDel( this ); + pWindow->Command( aCEvt ); + if( aDel.IsDead() ) + return 0; + mnRepaintTime = Max( Time::GetSystemTicks() - nTime, 1UL ); + ImplRecalcScrollValues(); + } + } + + if ( mnTimeout != mpTimer->GetTimeout() ) + mpTimer->SetTimeout( mnTimeout ); + mpTimer->Start(); + + return 0L; +} diff --git a/vcl/source/window/scrwnd.hxx b/vcl/source/window/scrwnd.hxx new file mode 100644 index 000000000000..d808fa73e321 --- /dev/null +++ b/vcl/source/window/scrwnd.hxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <vcl/floatwin.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/image.hxx> + +// ----------- +// - Defines - +// ----------- + +#define WHEELMODE_NONE 0x00000000UL +#define WHEELMODE_VH 0x00000001UL +#define WHEELMODE_V 0x00000002UL +#define WHEELMODE_H 0x00000004UL +#define WHEELMODE_SCROLL_VH 0x00000008UL +#define WHEELMODE_SCROLL_V 0x00000010UL +#define WHEELMODE_SCROLL_H 0x00000020UL + +// ------------------- +// - ImplWheelWindow - +// ------------------- + +class Timer; + +class ImplWheelWindow : public FloatingWindow +{ +private: + + ImageList maImgList; + Bitmap maWheelBmp; + CommandScrollData maCommandScrollData; + Point maLastMousePos; + Point maCenter; + Timer* mpTimer; + ULONG mnRepaintTime; + ULONG mnTimeout; + ULONG mnWheelMode; + ULONG mnMaxWidth; + ULONG mnActWidth; + ULONG mnActDist; + long mnActDeltaX; + long mnActDeltaY; + + void ImplCreateImageList(); + void ImplSetRegion( const Bitmap& rRegionBmp ); + using Window::ImplGetMousePointer; + PointerStyle ImplGetMousePointer( long nDistX, long nDistY ); + void ImplDrawWheel(); + void ImplRecalcScrollValues(); + + DECL_LINK( ImplScrollHdl, Timer* pTimer ); + +protected: + + virtual void Paint( const Rectangle& rRect ); + virtual void MouseMove( const MouseEvent& rMEvt ); + virtual void MouseButtonUp( const MouseEvent& rMEvt ); + +public: + + ImplWheelWindow( Window* pParent ); + ~ImplWheelWindow(); + + void ImplStop(); + void ImplSetWheelMode( ULONG nWheelMode ); + ULONG ImplGetWheelMode() const { return mnWheelMode; } +}; diff --git a/vcl/source/window/seleng.cxx b/vcl/source/window/seleng.cxx new file mode 100644 index 000000000000..322b2937b5c9 --- /dev/null +++ b/vcl/source/window/seleng.cxx @@ -0,0 +1,502 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <tools/ref.hxx> +#include <vcl/window.hxx> +#include <vcl/seleng.hxx> +#include <tools/debug.hxx> + + + + +inline BOOL SelectionEngine::ShouldDeselect( BOOL bModifierKey1 ) const +{ +// return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 ); + return eSelMode != MULTIPLE_SELECTION || !bModifierKey1; +} + + +// TODO: FunctionSet::SelectAtPoint raus + +/************************************************************************* +|* +|* SelectionEngine::SelectionEngine() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet ) : + pWin( pWindow ) +{ + eSelMode = SINGLE_SELECTION; + pFunctionSet = pFuncSet; + nFlags = SELENG_EXPANDONMOVE; + nLockedMods = 0; + + aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) ); + aWTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL ); +} + +/************************************************************************* +|* +|* SelectionEngine::~SelectionEngine() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +SelectionEngine::~SelectionEngine() +{ + aWTimer.Stop(); +} + +/************************************************************************* +|* +|* SelectionEngine::ImpWatchDog() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +IMPL_LINK( SelectionEngine, ImpWatchDog, Timer*, EMPTYARG ) +{ + if ( !aArea.IsInside( aLastMove.GetPosPixel() ) ) + SelMouseMove( aLastMove ); + return 0; +} + +/************************************************************************* +|* +|* SelectionEngine::SetSelectionMode() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +void SelectionEngine::SetSelectionMode( SelectionMode eMode ) +{ + eSelMode = eMode; +} + +/************************************************************************* +|* +|* SelectionEngine::ActivateDragMode() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +void SelectionEngine::ActivateDragMode() +{ + DBG_ERRORFILE( "SelectionEngine::ActivateDragMode not implemented" ); +} + +/************************************************************************* +|* +|* SelectionEngine::CursorPosChanging() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung GT 2002-04-04 +|* +*************************************************************************/ + +void SelectionEngine::CursorPosChanging( BOOL bShift, BOOL bMod1 ) +{ + if ( !pFunctionSet ) + return; + + if ( bShift && eSelMode != SINGLE_SELECTION ) + { + if ( IsAddMode() ) + { + if ( !(nFlags & SELENG_HAS_ANCH) ) + { + pFunctionSet->CreateAnchor(); + nFlags |= SELENG_HAS_ANCH; + } + } + else + { + if ( !(nFlags & SELENG_HAS_ANCH) ) + { + if( ShouldDeselect( bMod1 ) ) + pFunctionSet->DeselectAll(); + pFunctionSet->CreateAnchor(); + nFlags |= SELENG_HAS_ANCH; + } + } + } + else + { + if ( IsAddMode() ) + { + if ( nFlags & SELENG_HAS_ANCH ) + { + // pFunctionSet->CreateCursor(); + pFunctionSet->DestroyAnchor(); + nFlags &= (~SELENG_HAS_ANCH); + } + } + else + { + if( ShouldDeselect( bMod1 ) ) + pFunctionSet->DeselectAll(); + else + pFunctionSet->DestroyAnchor(); + nFlags &= (~SELENG_HAS_ANCH); + } + } +} + +/************************************************************************* +|* +|* SelectionEngine::SelMouseButtonDown() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 07.06.95 +|* +*************************************************************************/ + +BOOL SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt ) +{ + nFlags &= (~SELENG_CMDEVT); + if ( !pFunctionSet || !pWin ) + return FALSE; + const bool bRightClickCursorPositioning = + rMEvt.IsRight() && rMEvt.GetClicks() == 1 && !IsInSelection(); + if ( (rMEvt.GetClicks() > 1 || rMEvt.IsRight()) && !bRightClickCursorPositioning ) + return FALSE; + + USHORT nModifier = rMEvt.GetModifier() | nLockedMods; + if ( nModifier & KEY_MOD2 ) + return FALSE; + // in SingleSelection: Control-Taste filtern (damit auch + // mit Ctrl-Click ein D&D gestartet werden kann) + if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION ) + nModifier = 0; + + Point aPos = rMEvt.GetPosPixel(); + aLastMove = rMEvt; + + if( !rMEvt.IsRight() ) + { + pWin->CaptureMouse(); + nFlags |= SELENG_IN_SEL; + } + else + { + nModifier = 0; + } + + switch ( nModifier ) + { + case 0: // KEY_NO_KEY + { + BOOL bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos ); + nFlags &= (~SELENG_IN_ADD); + if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint ) + { + nFlags |= SELENG_WAIT_UPEVT; + nFlags &= ~(SELENG_IN_SEL); + pWin->ReleaseMouse(); + return TRUE; //auf STARTDRAG-Command-Event warten + } + if ( eSelMode != SINGLE_SELECTION ) + { + if( !IsAddMode() ) + pFunctionSet->DeselectAll(); + else + pFunctionSet->DestroyAnchor(); + nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = FALSE; + } + pFunctionSet->SetCursorAtPoint( aPos ); + // Sonderbehandlung Single-Selection, damit Select+Drag + // in einem Zug moeglich ist + if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB)) + nFlags |= SELENG_WAIT_UPEVT; + return TRUE; + } + + case KEY_SHIFT: + if ( eSelMode == SINGLE_SELECTION ) + { + pWin->ReleaseMouse(); + nFlags &= (~SELENG_IN_SEL); + return FALSE; + } + if ( nFlags & SELENG_ADD_ALW ) + nFlags |= SELENG_IN_ADD; + else + nFlags &= (~SELENG_IN_ADD); + + if( !(nFlags & SELENG_HAS_ANCH) ) + { + if ( !(nFlags & SELENG_IN_ADD) ) + pFunctionSet->DeselectAll(); + pFunctionSet->CreateAnchor(); + nFlags |= SELENG_HAS_ANCH; + } + pFunctionSet->SetCursorAtPoint( aPos ); + return TRUE; + + case KEY_MOD1: + // Control nur bei Mehrfachselektion erlaubt + if ( eSelMode != MULTIPLE_SELECTION ) + { + nFlags &= (~SELENG_IN_SEL); + pWin->ReleaseMouse(); + return TRUE; // Mausclick verschlucken + } + if ( nFlags & SELENG_HAS_ANCH ) + { + // pFunctionSet->CreateCursor(); + pFunctionSet->DestroyAnchor(); + nFlags &= (~SELENG_HAS_ANCH); + } + if ( pFunctionSet->IsSelectionAtPoint( aPos ) ) + { + pFunctionSet->DeselectAtPoint( aPos ); + pFunctionSet->SetCursorAtPoint( aPos, TRUE ); + } + else + { + pFunctionSet->SetCursorAtPoint( aPos ); + } + return TRUE; + + case KEY_SHIFT + KEY_MOD1: + if ( eSelMode != MULTIPLE_SELECTION ) + { + pWin->ReleaseMouse(); + nFlags &= (~SELENG_IN_SEL); + return FALSE; + } + nFlags |= SELENG_IN_ADD; //bIsInAddMode = TRUE; + if ( !(nFlags & SELENG_HAS_ANCH) ) + { + pFunctionSet->CreateAnchor(); + nFlags |= SELENG_HAS_ANCH; + } + pFunctionSet->SetCursorAtPoint( aPos ); + return TRUE; + } + + return FALSE; +} + +/************************************************************************* +|* +|* SelectionEngine::SelMouseButtonUp() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +BOOL SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt ) +{ + aWTimer.Stop(); + //DbgOut("Up"); + if( !pFunctionSet || !pWin ) + { + nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL); + return FALSE; + } + + if( !rMEvt.IsRight() ) + { + pWin->ReleaseMouse(); + } + + if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) && + eSelMode != SINGLE_SELECTION) + { + // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt + // ==> deselektieren + USHORT nModifier = aLastMove.GetModifier() | nLockedMods; + if( nModifier == KEY_MOD1 || IsAlwaysAdding() ) + { + if( !(nModifier & KEY_SHIFT) ) + { + pFunctionSet->DestroyAnchor(); + nFlags &= (~SELENG_HAS_ANCH); // nix Anker + } + pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() ); + nFlags &= (~SELENG_HAS_ANCH); // nix Anker + pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), TRUE ); + } + else + { + pFunctionSet->DeselectAll(); + nFlags &= (~SELENG_HAS_ANCH); // nix Anker + pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() ); + } + } + + nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL); + return TRUE; +} + +/************************************************************************* +|* +|* SelectionEngine::SelMouseMove() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +BOOL SelectionEngine::SelMouseMove( const MouseEvent& rMEvt ) +{ + + if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) || + (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) ) + return FALSE; + + if( !(nFlags & SELENG_EXPANDONMOVE) ) + return FALSE; // auf DragEvent warten! + + aLastMove = rMEvt; + // wenn die Maus ausserhalb der Area steht, dann wird die + // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt + if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() )) + return TRUE; + + + aWTimer.Start(); + if ( eSelMode != SINGLE_SELECTION ) + { + if ( !(nFlags & SELENG_HAS_ANCH) ) + { + pFunctionSet->CreateAnchor(); + //DbgOut("Move:Creating anchor"); + nFlags |= SELENG_HAS_ANCH; + } + } + + //DbgOut("Move:SetCursor"); + pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() ); + + return TRUE; +} + +/************************************************************************* +|* +|* SelectionEngine::SetWindow() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 10.10.94 +|* Letzte Aenderung OV 10.10.94 +|* +*************************************************************************/ + +void SelectionEngine::SetWindow( Window* pNewWin ) +{ + if( pNewWin != pWin ) + { + if ( pWin && (nFlags & SELENG_IN_SEL) ) + pWin->ReleaseMouse(); + pWin = pNewWin; + if ( pWin && ( nFlags & SELENG_IN_SEL ) ) + pWin->CaptureMouse(); + } +} + +/************************************************************************* +|* +|* SelectionEngine::Reset() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 07.07.95 +|* Letzte Aenderung OV 07.07.95 +|* +*************************************************************************/ + +void SelectionEngine::Reset() +{ + aWTimer.Stop(); + if ( nFlags & SELENG_IN_SEL ) + pWin->ReleaseMouse(); + nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL); + nLockedMods = 0; +} + +/************************************************************************* +|* +|* SelectionEngine::Command() +|* +|* Beschreibung SELENG.SDW +|* Ersterstellung OV 07.07.95 +|* Letzte Aenderung OV 07.07.95 +|* +*************************************************************************/ + +void SelectionEngine::Command( const CommandEvent& rCEvt ) +{ + // Timer aWTimer ist beim Aufspannen einer Selektion aktiv + if ( !pFunctionSet || !pWin || aWTimer.IsActive() ) + return; + aWTimer.Stop(); + nFlags |= SELENG_CMDEVT; + if ( rCEvt.GetCommand() == COMMAND_STARTDRAG ) + { + if ( nFlags & SELENG_DRG_ENAB ) + { + DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" ); + if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) ) + { + aLastMove = MouseEvent( rCEvt.GetMousePosPixel(), + aLastMove.GetClicks(), aLastMove.GetMode(), + aLastMove.GetButtons(), aLastMove.GetModifier() ); + pFunctionSet->BeginDrag(); + nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL); + } + else + nFlags &= ~SELENG_CMDEVT; + } + else + nFlags &= ~SELENG_CMDEVT; + } +} diff --git a/vcl/source/window/split.cxx b/vcl/source/window/split.cxx new file mode 100644 index 000000000000..b4553a4cf8a7 --- /dev/null +++ b/vcl/source/window/split.cxx @@ -0,0 +1,806 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/event.hxx> +#include <vcl/split.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syswin.hxx> +#include <vcl/taskpanelist.hxx> +#include <vcl/gradient.hxx> +#include <tools/poly.hxx> +#include <vcl/lineinfo.hxx> +#include <rtl/instance.hxx> +#include <vcl/window.h> + +namespace +{ + struct ImplBlackWall + : public rtl::StaticWithInit<Wallpaper, ImplBlackWall> { + Wallpaper operator () () { + return Wallpaper(COL_BLACK); + } + }; + struct ImplWhiteWall + : public rtl::StaticWithInit<Wallpaper, ImplWhiteWall> { + Wallpaper operator () () { + return Wallpaper(COL_LIGHTGRAY); + } + }; +} + +// ======================================================================= + +void Splitter::ImplInitSplitterData() +{ + ImplGetWindowImpl()->mbSplitter = TRUE; + mpRefWin = NULL; + mnSplitPos = 0; + mnLastSplitPos = 0; + mnStartSplitPos = 0; + mbDragFull = FALSE; + mbKbdSplitting = FALSE; + mbInKeyEvent = 0; + mnKeyboardStepSize = SPLITTER_DEFAULTSTEPSIZE; +} + +// ----------------------------------------------------------------------- + +void Splitter::ImplInit( Window* pParent, WinBits nWinStyle ) +{ + Window::ImplInit( pParent, nWinStyle, NULL ); + + mpRefWin = pParent; + + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + long nA = rSettings.GetScrollBarSize(); + long nB = rSettings.GetSplitSize(); + + PointerStyle ePointerStyle; + + if ( nWinStyle & WB_HSCROLL ) + { + ePointerStyle = POINTER_HSPLIT; + mbHorzSplit = TRUE; + SetSizePixel( Size( nB, nA ) ); + } + else + { + ePointerStyle = POINTER_VSPLIT; + mbHorzSplit = FALSE; + SetSizePixel( Size( nA, nB ) ); + } + + SetPointer( Pointer( ePointerStyle ) ); + + if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + SetBackground( ImplWhiteWall::get() ); + else + SetBackground( ImplBlackWall::get() ); + + TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList(); + pTList->AddWindow( this ); +} + +// ----------------------------------------------------------------------- + +void Splitter::ImplSplitMousePos( Point& rPos ) +{ + if ( mbHorzSplit ) + { + if ( rPos.X() > maDragRect.Right()-1 ) + rPos.X() = maDragRect.Right()-1; + if ( rPos.X() < maDragRect.Left()+1 ) + rPos.X() = maDragRect.Left()+1; + } + else + { + if ( rPos.Y() > maDragRect.Bottom()-1 ) + rPos.Y() = maDragRect.Bottom()-1; + if ( rPos.Y() < maDragRect.Top()+1 ) + rPos.Y() = maDragRect.Top()+1; + } +} + +// ----------------------------------------------------------------------- + +void Splitter::ImplDrawSplitter() +{ + Rectangle aInvRect( maDragRect ); + + if ( mbHorzSplit ) + { + aInvRect.Left() = maDragPos.X() - 1; + aInvRect.Right() = maDragPos.X() + 1; + } + else + { + aInvRect.Top() = maDragPos.Y() - 1; + aInvRect.Bottom() = maDragPos.Y() + 1; + } + + mpRefWin->InvertTracking( mpRefWin->PixelToLogic(aInvRect), SHOWTRACK_SPLIT ); +} + +// ----------------------------------------------------------------------- + +Splitter::Splitter( Window* pParent, WinBits nStyle ) : + Window( WINDOW_SPLITTER ) +{ + ImplInitSplitterData(); + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +Splitter::Splitter( Window* pParent, const ResId& rResId ) : + Window( WINDOW_SPLITTER ) +{ + ImplInitSplitterData(); + rResId.SetRT( RSC_SPLITTER ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +Splitter::~Splitter() +{ + TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList(); + pTList->RemoveWindow( this ); +} + +// ----------------------------------------------------------------------- + +void Splitter::SetKeyboardStepSize( long nStepSize ) +{ + mnKeyboardStepSize = nStepSize; +} + +// ----------------------------------------------------------------------- + +long Splitter::GetKeyboardStepSize() const +{ + return mnKeyboardStepSize; +} + +// ----------------------------------------------------------------------- + +Splitter* Splitter::ImplFindSibling() +{ + // look for another splitter with the same parent but different orientation + Window *pWin = GetParent()->GetWindow( WINDOW_FIRSTCHILD ); + Splitter *pSplitter = NULL; + while( pWin ) + { + if( pWin->ImplIsSplitter() ) + { + pSplitter = (Splitter*) pWin; + if( pSplitter != this && IsHorizontal() != pSplitter->IsHorizontal() ) + return pSplitter; + } + pWin = pWin->GetWindow( WINDOW_NEXT ); + } + return NULL; +} + +// ----------------------------------------------------------------------- + +BOOL Splitter::ImplSplitterActive() +{ + // is splitter in document or at scrollbar handle ? + + BOOL bActive = TRUE; + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + long nA = rSettings.GetScrollBarSize(); + long nB = rSettings.GetSplitSize(); + + Size aSize = GetOutputSize(); + if ( mbHorzSplit ) + { + if( aSize.Width() == nB && aSize.Height() == nA ) + bActive = FALSE; + } + else + { + if( aSize.Width() == nA && aSize.Height() == nB ) + bActive = FALSE; + } + return bActive; +} + +// ----------------------------------------------------------------------- + +void Splitter::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.GetClicks() == 2 ) + { + if ( mnLastSplitPos != mnSplitPos ) + { + StartSplit(); + Point aPos = rMEvt.GetPosPixel(); + if ( mbHorzSplit ) + aPos.X() = mnLastSplitPos; + else + aPos.Y() = mnLastSplitPos; + ImplSplitMousePos( aPos ); + Splitting( aPos ); + ImplSplitMousePos( aPos ); + long nTemp = mnSplitPos; + if ( mbHorzSplit ) + SetSplitPosPixel( aPos.X() ); + else + SetSplitPosPixel( aPos.Y() ); + mnLastSplitPos = nTemp; + Split(); + EndSplit(); + } + } + else + StartDrag(); +} + +// ----------------------------------------------------------------------- + +void Splitter::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + if ( !mbDragFull ) + ImplDrawSplitter(); + + if ( !rTEvt.IsTrackingCanceled() ) + { + long nNewPos; + if ( mbHorzSplit ) + nNewPos = maDragPos.X(); + else + nNewPos = maDragPos.Y(); + if ( nNewPos != mnStartSplitPos ) + { + SetSplitPosPixel( nNewPos ); + mnLastSplitPos = 0; + Split(); + } + EndSplit(); + } + else if ( mbDragFull ) + { + SetSplitPosPixel( mnStartSplitPos ); + Split(); + } + mnStartSplitPos = 0; + } + else + { + //Point aNewPos = mpRefWin->ScreenToOutputPixel( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) ); + Point aNewPos = mpRefWin->NormalizedScreenToOutputPixel( OutputToNormalizedScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) ); + ImplSplitMousePos( aNewPos ); + Splitting( aNewPos ); + ImplSplitMousePos( aNewPos ); + + if ( mbHorzSplit ) + { + if ( aNewPos.X() == maDragPos.X() ) + return; + } + else + { + if ( aNewPos.Y() == maDragPos.Y() ) + return; + } + + if ( mbDragFull ) + { + maDragPos = aNewPos; + long nNewPos; + if ( mbHorzSplit ) + nNewPos = maDragPos.X(); + else + nNewPos = maDragPos.Y(); + if ( nNewPos != mnSplitPos ) + { + SetSplitPosPixel( nNewPos ); + mnLastSplitPos = 0; + Split(); + } + + GetParent()->Update(); + } + else + { + ImplDrawSplitter(); + maDragPos = aNewPos; + ImplDrawSplitter(); + } + } +} + +// ----------------------------------------------------------------------- + +void Splitter::ImplKbdTracking( KeyCode aKeyCode ) +{ + USHORT nCode = aKeyCode.GetCode(); + if ( nCode == KEY_ESCAPE || nCode == KEY_RETURN ) + { + if( !mbKbdSplitting ) + return; + else + mbKbdSplitting = FALSE; + + if ( nCode != KEY_ESCAPE ) + { + long nNewPos; + if ( mbHorzSplit ) + nNewPos = maDragPos.X(); + else + nNewPos = maDragPos.Y(); + if ( nNewPos != mnStartSplitPos ) + { + SetSplitPosPixel( nNewPos ); + mnLastSplitPos = 0; + Split(); + } + } + else + { + SetSplitPosPixel( mnStartSplitPos ); + Split(); + EndSplit(); + } + mnStartSplitPos = 0; + } + else + { + Point aNewPos; + Size aSize = mpRefWin->GetOutputSize(); + Point aPos = GetPosPixel(); + // depending on the position calc allows continous moves or snaps to row/columns + // continous mode is active when position is at the origin or end of the splitter + // otherwise snap mode is active + // default here is snap, holding shift sets continous mode + if( mbHorzSplit ) + aNewPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aKeyCode.IsShift() ? 0 : aSize.Height()/2); + else + aNewPos = Point( aKeyCode.IsShift() ? 0 : aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos ); + + Point aOldWindowPos = GetPosPixel(); + + int maxiter = 500; // avoid endless loop + int delta=0; + int delta_step = mbHorzSplit ? aSize.Width()/10 : aSize.Height()/10; + + // use the specified step size if it was set + if( mnKeyboardStepSize != SPLITTER_DEFAULTSTEPSIZE ) + delta_step = mnKeyboardStepSize; + + while( maxiter-- && aOldWindowPos == GetPosPixel() ) + { + // inc/dec position until application performs changes + // thus a single key press really moves the splitter + if( aKeyCode.IsShift() ) + delta++; + else + delta += delta_step; + + switch( nCode ) + { + case KEY_LEFT: + aNewPos.X()-=delta; + break; + case KEY_RIGHT: + aNewPos.X()+=delta; + break; + case KEY_UP: + aNewPos.Y()-=delta; + break; + case KEY_DOWN: + aNewPos.Y()+=delta; + break; + default: + maxiter = 0; // leave loop + break; + } + ImplSplitMousePos( aNewPos ); + Splitting( aNewPos ); + ImplSplitMousePos( aNewPos ); + + if ( mbHorzSplit ) + { + if ( aNewPos.X() == maDragPos.X() ) + continue; + } + else + { + if ( aNewPos.Y() == maDragPos.Y() ) + continue; + } + + maDragPos = aNewPos; + long nNewPos; + if ( mbHorzSplit ) + nNewPos = maDragPos.X(); + else + nNewPos = maDragPos.Y(); + if ( nNewPos != mnSplitPos ) + { + SetSplitPosPixel( nNewPos ); + mnLastSplitPos = 0; + Split(); + } + GetParent()->Update(); + } + } +} + +// ----------------------------------------------------------------------- + +void Splitter::StartSplit() +{ + maStartSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Splitter::Split() +{ + maSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Splitter::EndSplit() +{ + if ( maEndSplitHdl.IsSet() ) + maEndSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void Splitter::Splitting( Point& /* rSplitPos */ ) +{ +} + +// ----------------------------------------------------------------------- + +void Splitter::SetDragRectPixel( const Rectangle& rDragRect, Window* _pRefWin ) +{ + maDragRect = rDragRect; + if ( !_pRefWin ) + mpRefWin = GetParent(); + else + mpRefWin = _pRefWin; +} + +// ----------------------------------------------------------------------- + +void Splitter::SetSplitPosPixel( long nNewPos ) +{ + mnSplitPos = nNewPos; +} + +// ----------------------------------------------------------------------- + +void Splitter::SetLastSplitPosPixel( long nNewPos ) +{ + mnLastSplitPos = nNewPos; +} + +// ----------------------------------------------------------------------- + +void Splitter::StartDrag() +{ + if ( IsTracking() ) + return; + + StartSplit(); + + // Tracking starten + StartTracking(); + + // Start-Positon ermitteln + maDragPos = mpRefWin->GetPointerPosPixel(); + ImplSplitMousePos( maDragPos ); + Splitting( maDragPos ); + ImplSplitMousePos( maDragPos ); + if ( mbHorzSplit ) + mnStartSplitPos = maDragPos.X(); + else + mnStartSplitPos = maDragPos.Y(); + + mbDragFull = (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0; + if ( !mbDragFull ) + ImplDrawSplitter(); +} + + +// ----------------------------------------------------------------------- + +void Splitter::ImplStartKbdSplitting() +{ + if( mbKbdSplitting ) + return; + + mbKbdSplitting = TRUE; + + StartSplit(); + + // determine start position + // because we have no mouse position we take either the position + // of the splitter window or the last split position + // the other coordinate is just the center of the reference window + Size aSize = mpRefWin->GetOutputSize(); + Point aPos = GetPosPixel(); + if( mbHorzSplit ) + maDragPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aSize.Height()/2 ); + else + maDragPos = Point( aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos ); + ImplSplitMousePos( maDragPos ); + Splitting( maDragPos ); + ImplSplitMousePos( maDragPos ); + if ( mbHorzSplit ) + mnStartSplitPos = maDragPos.X(); + else + mnStartSplitPos = maDragPos.Y(); +} + +// ----------------------------------------------------------------------- + +void Splitter::ImplRestoreSplitter() +{ + // set splitter in the center of the ref window + StartSplit(); + Size aSize = mpRefWin->GetOutputSize(); + Point aPos = Point( aSize.Width()/2 , aSize.Height()/2); + if ( mnLastSplitPos != mnSplitPos && mnLastSplitPos > 5 ) + { + // restore last pos if it was a useful position (>5) + if ( mbHorzSplit ) + aPos.X() = mnLastSplitPos; + else + aPos.Y() = mnLastSplitPos; + } + + ImplSplitMousePos( aPos ); + Splitting( aPos ); + ImplSplitMousePos( aPos ); + long nTemp = mnSplitPos; + if ( mbHorzSplit ) + SetSplitPosPixel( aPos.X() ); + else + SetSplitPosPixel( aPos.Y() ); + mnLastSplitPos = nTemp; + Split(); + EndSplit(); +} + + +// ----------------------------------------------------------------------- + +void Splitter::GetFocus() +{ + if( !ImplSplitterActive() ) + ImplRestoreSplitter(); + + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void Splitter::LoseFocus() +{ + if( mbKbdSplitting ) + { + KeyCode aReturnKey( KEY_RETURN ); + ImplKbdTracking( aReturnKey ); + mbKbdSplitting = FALSE; + } + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void Splitter::KeyInput( const KeyEvent& rKEvt ) +{ + if( mbInKeyEvent ) + return; + + mbInKeyEvent = 1; + + Splitter *pSibling = ImplFindSibling(); + KeyCode aKeyCode = rKEvt.GetKeyCode(); + USHORT nCode = aKeyCode.GetCode(); + switch ( nCode ) + { + case KEY_UP: + case KEY_DOWN: + if( !mbHorzSplit ) + { + ImplStartKbdSplitting(); + ImplKbdTracking( aKeyCode ); + } + else + { + if( pSibling ) + { + pSibling->GrabFocus(); + pSibling->KeyInput( rKEvt ); + } + } + break; + case KEY_RIGHT: + case KEY_LEFT: + if( mbHorzSplit ) + { + ImplStartKbdSplitting(); + ImplKbdTracking( aKeyCode ); + } + else + { + if( pSibling ) + { + pSibling->GrabFocus(); + pSibling->KeyInput( rKEvt ); + } + } + break; + + case KEY_DELETE: + if( ImplSplitterActive() ) + { + if( mbKbdSplitting ) + { + KeyCode aKey( KEY_ESCAPE ); + ImplKbdTracking( aKey ); + } + + StartSplit(); + Point aPos; + if ( mbHorzSplit ) + aPos.X() = 0; + else + aPos.Y() = 0; + ImplSplitMousePos( aPos ); + Splitting( aPos ); + ImplSplitMousePos( aPos ); + long nTemp = mnSplitPos; + if ( mbHorzSplit ) + SetSplitPosPixel( aPos.X() ); + else + SetSplitPosPixel( aPos.Y() ); + mnLastSplitPos = nTemp; + Split(); + EndSplit(); + + // Shift-Del deletes both splitters + if( aKeyCode.IsShift() && pSibling ) + pSibling->KeyInput( rKEvt ); + + GrabFocusToDocument(); + } + break; + + case KEY_ESCAPE: + if( mbKbdSplitting ) + ImplKbdTracking( aKeyCode ); + else + GrabFocusToDocument(); + break; + + case KEY_RETURN: + ImplKbdTracking( aKeyCode ); + GrabFocusToDocument(); + break; + default: // let any key input fix the splitter + Window::KeyInput( rKEvt ); + GrabFocusToDocument(); + break; + } + mbInKeyEvent = 0; +} + +// ----------------------------------------------------------------------- + +long Splitter::Notify( NotifyEvent& rNEvt ) +{ + return Window::Notify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +void Splitter::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + if( rDCEvt.GetType() == DATACHANGED_SETTINGS ) + { + Color oldFaceColor = ((AllSettings *) rDCEvt.GetData())->GetStyleSettings().GetFaceColor(); + Color newFaceColor = Application::GetSettings().GetStyleSettings().GetFaceColor(); + if( oldFaceColor.IsDark() != newFaceColor.IsDark() ) + { + if( newFaceColor.IsDark() ) + SetBackground( ImplWhiteWall::get() ); + else + SetBackground( ImplBlackWall::get() ); + } + } +} + +// ----------------------------------------------------------------------- + +void Splitter::Paint( const Rectangle& rPaintRect ) +{ + if( HasFocus() || mbKbdSplitting ) + { + Color oldFillCol = GetFillColor(); + Color oldLineCol = GetLineColor(); + + SetLineColor(); + SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() ); + DrawRect( rPaintRect ); + + Color aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() ); + SetFillColor( aSelectionBorderCol ); + SetLineColor(); + + Polygon aPoly( rPaintRect ); + PolyPolygon aPolyPoly( aPoly ); + DrawTransparent( aPolyPoly, 85 ); + + SetLineColor( aSelectionBorderCol ); + SetFillColor(); + + if( mbKbdSplitting ) + { + LineInfo aInfo( LINE_DASH ); + //aInfo.SetDashLen( 2 ); + //aInfo.SetDashCount( 1 ); + aInfo.SetDistance( 1 ); + aInfo.SetDotLen( 2 ); + aInfo.SetDotCount( 1 ); + + DrawPolyLine( aPoly, aInfo ); + } + else + DrawRect( rPaintRect ); + + SetFillColor( oldFillCol); + SetLineColor( oldLineCol); + } + else + { + Window::Paint( rPaintRect ); + } +} diff --git a/vcl/source/window/splitwin.cxx b/vcl/source/window/splitwin.cxx new file mode 100644 index 000000000000..62fbe2e507f3 --- /dev/null +++ b/vcl/source/window/splitwin.cxx @@ -0,0 +1,3940 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <string.h> +#include <tools/list.hxx> +#include <tools/debug.hxx> +#include <tools/rcid.h> +#include <vcl/event.hxx> +#include <vcl/wall.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/decoview.hxx> +#include <vcl/symbol.hxx> +#ifndef _SV_SVIDS_HRC +#include <vcl/svids.hrc> +#endif +#include <vcl/image.hxx> +#include <vcl/svdata.hxx> +#include <vcl/help.hxx> +#include <vcl/splitwin.hxx> + + + +// ======================================================================= + +// Attention: Must not contain non-PODs because array is enlarged/copied +// with the use of memmove/memcpy. +struct ImplSplitItem +{ + long mnSize; + long mnPixSize; + long mnLeft; + long mnTop; + long mnWidth; + long mnHeight; + long mnSplitPos; + long mnSplitSize; + long mnOldSplitPos; + long mnOldSplitSize; + long mnOldWidth; + long mnOldHeight; + ImplSplitSet* mpSet; + Window* mpWindow; + Window* mpOrgParent; + USHORT mnId; + SplitWindowItemBits mnBits; + BOOL mbFixed; + BOOL mbSubSize; + /// Minimal width or height of the item. -1 means no restriction. + long mnMinSize; + /// Maximal width or height of the item. -1 means no restriction. + long mnMaxSize; +}; + +struct ImplSplitSet +{ + ImplSplitItem* mpItems; + Wallpaper* mpWallpaper; + Bitmap* mpBitmap; + long mnLastSize; + long mnSplitSize; + USHORT mnItems; + USHORT mnId; + BOOL mbCalcPix; +}; + + + +/** Check whether the given size is inside the valid range defined by + [rItem.mnMinSize,rItem.mnMaxSize]. When it is not inside it then return + the upper or lower bound, respectively. Otherwise return the given size + unmodified. + Note that either mnMinSize and/or mnMaxSize can be -1 in which case the + size has not lower or upper bound. +*/ +namespace { + long ValidateSize (const long nSize, const ImplSplitItem rItem) + { + if (rItem.mnMinSize>=0 && nSize<rItem.mnMinSize) + return rItem.mnMinSize; + else if (rItem.mnMaxSize>0 && nSize>rItem.mnMaxSize) + return rItem.mnMaxSize; + else + return nSize; + } +} + + +#define SPLITWIN_SPLITSIZE 3 +#define SPLITWIN_SPLITSIZEEX 4 +#define SPLITWIN_SPLITSIZEEXLN 6 +#define SPLITWIN_SPLITSIZEAUTOHIDE 36 +#define SPLITWIN_SPLITSIZEFADE 36 + +#define SPLIT_HORZ ((USHORT)0x0001) +#define SPLIT_VERT ((USHORT)0x0002) +#define SPLIT_WINDOW ((USHORT)0x0004) +#define SPLIT_NOSPLIT ((USHORT)0x8000) + +// ----------------------------------------------------------------------- + +DECLARE_LIST( ImplSplitList, SplitWindow* ) + +// ======================================================================= + +static void ImplCalcBorder( WindowAlign eAlign, BOOL bNoAlign, + long& rLeft, long& rTop, + long& rRight, long& rBottom ) +{ + if ( bNoAlign ) + { + rLeft = 2; + rTop = 2; + rRight = 2; + rBottom = 2; + } + else + { + if ( eAlign == WINDOWALIGN_TOP ) + { + rLeft = 2; + rTop = 2; + rRight = 2; + rBottom = 0; + } + else if ( eAlign == WINDOWALIGN_LEFT ) + { + rLeft = 2; + rTop = 2; + rRight = 0; + rBottom = 2; + } + else if ( eAlign == WINDOWALIGN_BOTTOM ) + { + rLeft = 2; + rTop = 0; + rRight = 2; + rBottom = 2; + } + else + { + rLeft = 0; + rTop = 2; + rRight = 2; + rBottom = 2; + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawBorder( SplitWindow* pWin ) +{ + const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings(); + long nDX = pWin->mnDX; + long nDY = pWin->mnDY; + + if ( pWin->mbNoAlign ) + { + DecorationView aDecoView( pWin ); + Point aTmpPoint; + Rectangle aRect( aTmpPoint, Size( nDX, nDY ) ); + aDecoView.DrawFrame( aRect, FRAME_DRAW_DOUBLEIN ); + } + else + {/* + if ( pWin->meAlign == WINDOWALIGN_BOTTOM ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + else + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) ); + if ( (pWin->meAlign == WINDOWALIGN_LEFT) || (pWin->meAlign == WINDOWALIGN_RIGHT) ) + { + if ( pWin->meAlign == WINDOWALIGN_LEFT ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + else + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + } + }*/ + if ( pWin->meAlign == WINDOWALIGN_BOTTOM ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) ); + + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) ); + pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) ); + } + else if ( pWin->meAlign == WINDOWALIGN_TOP ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) ); + pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) ); + + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, 1 ), Point( nDX-3, 1 ) ); + pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-1 ) ); + pWin->DrawLine( Point( nDX-1, 1 ), Point( nDX-1, nDY-1 ) ); + } + else if ( pWin->meAlign == WINDOWALIGN_LEFT ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) ); + pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, 1 ), Point( nDX-1, 1 ) ); + pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) ); + pWin->DrawLine( Point( 1, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + else + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( nDX-2, 0 ) ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) ); + + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, 1 ), Point( nDX-3, 1 ) ); + pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawBorderLine( SplitWindow* pWin ) +{ + if ( pWin->mbFadeOut || pWin->mbAutoHide ) + { + const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings(); + long nDX = pWin->mnDX; + long nDY = pWin->mnDY; + + if ( pWin->meAlign == WINDOWALIGN_LEFT ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN-1, nDY-3 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( nDX-SPLITWIN_SPLITSIZEEXLN, 1 ), Point( nDX-SPLITWIN_SPLITSIZEEXLN, nDY-4 ) ); + } + else if ( pWin->meAlign == WINDOWALIGN_RIGHT ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( SPLITWIN_SPLITSIZEEXLN-1, 0 ), Point( SPLITWIN_SPLITSIZEEXLN-1, nDY-3 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( SPLITWIN_SPLITSIZEEXLN, 1 ), Point( SPLITWIN_SPLITSIZEEXLN, nDY-4 ) ); + } + else if ( pWin->meAlign == WINDOWALIGN_TOP ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, nDY-SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-3, nDY-SPLITWIN_SPLITSIZEEXLN-1 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, nDY-SPLITWIN_SPLITSIZEEXLN ), Point( nDX-4, nDY-SPLITWIN_SPLITSIZEEXLN ) ); + } + else if ( pWin->meAlign == WINDOWALIGN_BOTTOM ) + { + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, SPLITWIN_SPLITSIZEEXLN-1 ), Point( nDX-3, SPLITWIN_SPLITSIZEEXLN-1 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, SPLITWIN_SPLITSIZEEXLN ), Point( nDX-4, SPLITWIN_SPLITSIZEEXLN ) ); + } + } +} + +// ----------------------------------------------------------------------- + +static ImplSplitSet* ImplFindSet( ImplSplitSet* pSet, USHORT nId ) +{ + if ( pSet->mnId == nId ) + return pSet; + + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnId == nId ) + return pItems[i].mpSet; + } + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + { + ImplSplitSet* pFindSet = ImplFindSet( pItems[i].mpSet, nId ); + if ( pFindSet ) + return pFindSet; + } + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static ImplSplitSet* ImplFindItem( ImplSplitSet* pSet, USHORT nId, USHORT& rPos ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnId == nId ) + { + rPos = i; + return pSet; + } + } + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + { + ImplSplitSet* pFindSet = ImplFindItem( pItems[i].mpSet, nId, rPos ); + if ( pFindSet ) + return pFindSet; + } + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +static USHORT ImplFindItem( ImplSplitSet* pSet, Window* pWindow ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpWindow == pWindow ) + return pItems[i].mnId; + else + { + if ( pItems[i].mpSet ) + { + USHORT nId = ImplFindItem( pItems[i].mpSet, pWindow ); + if ( nId ) + return nId; + } + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +static USHORT ImplFindItem( ImplSplitSet* pSet, const Point& rPos, + BOOL bRows, BOOL bDown = TRUE ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnWidth && pItems[i].mnHeight ) + { + // Wegen ICC auftrennen + Point aPoint( pItems[i].mnLeft, pItems[i].mnTop ); + Size aSize( pItems[i].mnWidth, pItems[i].mnHeight ); + Rectangle aRect( aPoint, aSize ); + if ( bRows ) + { + if ( bDown ) + aRect.Bottom() += pSet->mnSplitSize; + else + aRect.Top() -= pSet->mnSplitSize; + } + else + { + if ( bDown ) + aRect.Right() += pSet->mnSplitSize; + else + aRect.Left() -= pSet->mnSplitSize; + } + + if ( aRect.IsInside( rPos ) ) + { + if ( pItems[i].mpSet && pItems[i].mpSet->mpItems ) + { + return ImplFindItem( pItems[i].mpSet, rPos, + ((pItems[i].mnBits & SWIB_COLSET) == 0) ); + } + else + return pItems[i].mnId; + } + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +static void ImplDeleteSet( ImplSplitSet* pSet ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + ImplDeleteSet( pItems[i].mpSet ); + } + + if ( pSet->mpWallpaper ) + delete pSet->mpWallpaper; + + if ( pSet->mpBitmap ) + delete pSet->mpBitmap; + + delete [] pItems; + delete pSet; +} + +// ----------------------------------------------------------------------- + +static void ImplSetSplitSize( ImplSplitSet* pSet, long nNewSize ) +{ + pSet->mnSplitSize = nNewSize; + for ( USHORT i = 0; i < pSet->mnItems; i++ ) + { + if ( pSet->mpItems[i].mpSet ) + ImplSetSplitSize( pSet->mpItems[i].mpSet, nNewSize ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplCalcSet( ImplSplitSet* pSet, + long nSetLeft, long nSetTop, + long nSetWidth, long nSetHeight, + BOOL bRows, BOOL bDown = TRUE ) +{ + if ( !pSet->mpItems ) + return; + + USHORT i; + USHORT j; + USHORT nMins; + USHORT nCalcItems; + USHORT nItems = pSet->mnItems; + USHORT nVisItems; + USHORT nAbsItems; + long nCalcSize; + long nSizeDelta; + long nCurSize; + long nSizeWinSize; + long nNewSizeWinSize; + long nTemp; + long nTempErr; + long nErrorSum; + long nCurSizeDelta; + long nPos; + long nMaxPos; + long* pSize; + ImplSplitItem* pItems = pSet->mpItems; + BOOL bEmpty; + + // Anzahl sichtbarer Items ermitteln + nVisItems = 0; + for ( i = 0; i < nItems; i++ ) + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + nVisItems++; + } + + // Groessen berechnen + if ( bRows ) + nCalcSize = nSetHeight; + else + nCalcSize = nSetWidth; + nCalcSize -= (nVisItems-1)*pSet->mnSplitSize; + nCurSize = 0; + if ( pSet->mbCalcPix || (pSet->mnLastSize != nCalcSize) ) + { + long nPercentFactor = 10; + long nRelCount = 0; + long nPercent = 0; + long nRelPercent = 0; + long nAbsSize = 0; + for ( i = 0; i < nItems; i++ ) + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + { + if ( pItems[i].mnBits & SWIB_RELATIVESIZE ) + nRelCount += pItems[i].mnSize; + else if ( pItems[i].mnBits & SWIB_PERCENTSIZE ) + nPercent += pItems[i].mnSize; + else + nAbsSize += pItems[i].mnSize; + } + } + // Relative-Werte auf prozentual mappen (Percent bei uns 10tel Prozent) + nPercent *= nPercentFactor; + if ( nRelCount ) + { + long nRelPercentBase = 1000; + while ( (nRelCount > nRelPercentBase) && (nPercentFactor < 100000) ) + { + nRelPercentBase *= 10; + nPercentFactor *= 10; + } + if ( nPercent < nRelPercentBase ) + { + nRelPercent = (nRelPercentBase-nPercent)/nRelCount; + nPercent += nRelPercent*nRelCount; + } + else + nRelPercent = 0; + } + if ( !nPercent ) + nPercent = 1; + nSizeDelta = nCalcSize-nAbsSize; + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnBits & SWIB_INVISIBLE ) + pItems[i].mnPixSize = 0; + else if ( pItems[i].mnBits & SWIB_RELATIVESIZE ) + { + if ( nSizeDelta <= 0 ) + pItems[i].mnPixSize = 0; + else + pItems[i].mnPixSize = (nSizeDelta*pItems[i].mnSize*nRelPercent)/nPercent; + } + else if ( pItems[i].mnBits & SWIB_PERCENTSIZE ) + { + if ( nSizeDelta <= 0 ) + pItems[i].mnPixSize = 0; + else + pItems[i].mnPixSize = (nSizeDelta*pItems[i].mnSize*nPercentFactor)/nPercent; + } + else + pItems[i].mnPixSize = pItems[i].mnSize; + nCurSize += pItems[i].mnPixSize; + } + + pSet->mbCalcPix = FALSE; + pSet->mnLastSize = nCalcSize; + + // Fenster einpassen + nSizeDelta = nCalcSize-nCurSize; + if ( nSizeDelta ) + { + nAbsItems = 0; + nSizeWinSize = 0; + nNewSizeWinSize = 0; + + // Zuerst die absoluten Items relativ resizen + for ( i = 0; i < nItems; i++ ) + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + { + if ( !(pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) ) + { + nAbsItems++; + nSizeWinSize += pItems[i].mnPixSize; + } + } + } + // Rundungsfehler werden hier nicht ausgelichen + if ( (nAbsItems < (USHORT)(Abs( nSizeDelta ))) && nSizeWinSize ) + { + for ( i = 0; i < nItems; i++ ) + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + { + if ( !(pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) ) + { + pItems[i].mnPixSize += (nSizeDelta*pItems[i].mnPixSize)/nSizeWinSize; + nNewSizeWinSize += pItems[i].mnPixSize; + } + } + } + nSizeDelta -= nNewSizeWinSize-nSizeWinSize; + } + + // Jetzt die Rundunsfehler ausgleichen + j = 0; + nMins = 0; + while ( nSizeDelta && (nItems != nMins) ) + { + // Feststellen, welche Items berechnet werden duerfen + nCalcItems = 0; + while ( !nCalcItems ) + { + for ( i = 0; i < nItems; i++ ) + { + pItems[i].mbSubSize = FALSE; + + if ( j >= 2 ) + pItems[i].mbSubSize = TRUE; + else + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + { + if ( (nSizeDelta > 0) || pItems[i].mnPixSize ) + { + if ( j >= 1 ) + pItems[i].mbSubSize = TRUE; + else + { + if ( (j == 0) && (pItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE)) ) + pItems[i].mbSubSize = TRUE; + } + } + } + } + + if ( pItems[i].mbSubSize ) + nCalcItems++; + } + + j++; + } + + // Groessen von den einzelnen Items abziehen + nErrorSum = nSizeDelta % nCalcItems; + nCurSizeDelta = nSizeDelta / nCalcItems; + nMins = 0; + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnBits & SWIB_INVISIBLE ) + nMins++; + else if ( pItems[i].mbSubSize ) + { + pSize = &(pItems[i].mnPixSize); + + if ( nErrorSum ) + { + if ( nErrorSum < 0 ) + nTempErr = -1; + else + nTempErr = 1; + } + else + nTempErr = 0; + + if ( (*pSize+nCurSizeDelta+nTempErr) <= 0 ) + { + nTemp = *pSize; + if ( nTemp ) + { + *pSize -= nTemp; + nSizeDelta += nTemp; + } + nMins++; + } + else + { + *pSize += nCurSizeDelta; + nSizeDelta -= nCurSizeDelta; + if ( nTempErr && (*pSize || (nTempErr > 0)) ) + { + *pSize += nTempErr; + nSizeDelta -= nTempErr; + nErrorSum -= nTempErr; + } + } + } + } + } + } + } + else + { + for ( i = 0; i < nItems; i++ ) + { + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + nCurSize += pItems[i].mnPixSize; + } + } + + // Maximale Groesse berechnen + if ( bRows ) + { + nPos = nSetTop; + if ( !bDown ) + nMaxPos = nSetTop-nSetHeight; + else + nMaxPos = nSetTop+nSetHeight; + } + else + { + nPos = nSetLeft; + if ( !bDown ) + nMaxPos = nSetLeft-nSetWidth; + else + nMaxPos = nSetLeft+nSetWidth; + } + + // Fenster anordnen und Werte anpassen + for ( i = 0; i < nItems; i++ ) + { + pItems[i].mnOldSplitPos = pItems[i].mnSplitPos; + pItems[i].mnOldSplitSize = pItems[i].mnSplitSize; + pItems[i].mnOldWidth = pItems[i].mnWidth; + pItems[i].mnOldHeight = pItems[i].mnHeight; + + if ( pItems[i].mnBits & SWIB_INVISIBLE ) + bEmpty = TRUE; + else + { + bEmpty = FALSE; + if ( bDown ) + { + if ( nPos+pItems[i].mnPixSize > nMaxPos ) + bEmpty = TRUE; + } + else + { + nPos -= pItems[i].mnPixSize; + if ( nPos < nMaxPos ) + bEmpty = TRUE; + } + } + + if ( bEmpty ) + { + pItems[i].mnWidth = 0; + pItems[i].mnHeight = 0; + pItems[i].mnSplitSize = 0; + } + else + { + if ( bRows ) + { + pItems[i].mnLeft = nSetLeft; + pItems[i].mnTop = nPos; + pItems[i].mnWidth = nSetWidth; + pItems[i].mnHeight = pItems[i].mnPixSize; + } + else + { + pItems[i].mnLeft = nPos; + pItems[i].mnTop = nSetTop; + pItems[i].mnWidth = pItems[i].mnPixSize; + pItems[i].mnHeight = nSetHeight; + } + + if ( i > nItems-1 ) + pItems[i].mnSplitSize = 0; + else + { + pItems[i].mnSplitSize = pSet->mnSplitSize; + if ( bDown ) + { + pItems[i].mnSplitPos = nPos+pItems[i].mnPixSize; + if ( pItems[i].mnSplitPos+pItems[i].mnSplitSize > nMaxPos ) + pItems[i].mnSplitSize = nMaxPos-pItems[i].mnSplitPos; + } + else + { + pItems[i].mnSplitPos = nPos-pSet->mnSplitSize; + if ( pItems[i].mnSplitPos < nMaxPos ) + pItems[i].mnSplitSize = pItems[i].mnSplitPos+pSet->mnSplitSize-nMaxPos; + } + } + } + + if ( !(pItems[i].mnBits & SWIB_INVISIBLE) ) + { + if ( !bDown ) + nPos -= pSet->mnSplitSize; + else + nPos += pItems[i].mnPixSize+pSet->mnSplitSize; + } + } + + // Sub-Set's berechnen + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet && pItems[i].mnWidth && pItems[i].mnHeight ) + { + ImplCalcSet( pItems[i].mpSet, + pItems[i].mnLeft, pItems[i].mnTop, + pItems[i].mnWidth, pItems[i].mnHeight, + ((pItems[i].mnBits & SWIB_COLSET) == 0) ); + } + } + + // Fixed setzen + for ( i = 0; i < nItems; i++ ) + { + pItems[i].mbFixed = FALSE; + if ( pItems[i].mnBits & SWIB_FIXED ) + pItems[i].mbFixed = TRUE; + else + { + // Wenn Child-Set vorhanden, ist dieses Item auch Fixed, wenn + // ein Child fixed ist + if ( pItems[i].mpSet ) + { + for ( j = 0; j < pItems[i].mpSet->mnItems; j++ ) + { + if ( pItems[i].mpSet->mpItems[j].mbFixed ) + { + pItems[i].mbFixed = TRUE; + break; + } + } + } + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplCalcSet2( SplitWindow* pWindow, ImplSplitSet* pSet, BOOL bHide, + BOOL bRows, BOOL /*bDown*/ ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + if ( pWindow->IsReallyVisible() && pWindow->IsUpdateMode() && pWindow->mbInvalidate ) + { + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnSplitSize ) + { + // Evt. alles invalidieren oder nur einen kleinen Teil + if ( (pItems[i].mnOldSplitPos != pItems[i].mnSplitPos) || + (pItems[i].mnOldSplitSize != pItems[i].mnSplitSize) || + (pItems[i].mnOldWidth != pItems[i].mnWidth) || + (pItems[i].mnOldHeight != pItems[i].mnHeight) ) + { + Rectangle aRect; + + // Old Rect invalidieren + if ( bRows ) + { + aRect.Left() = pItems[i].mnLeft; + aRect.Right() = pItems[i].mnLeft+pItems[i].mnOldWidth-1; + aRect.Top() = pItems[i].mnOldSplitPos; + aRect.Bottom() = aRect.Top() + pItems[i].mnOldSplitSize; + } + else + { + aRect.Top() = pItems[i].mnTop; + aRect.Bottom() = pItems[i].mnTop+pItems[i].mnOldHeight-1; + aRect.Left() = pItems[i].mnOldSplitPos; + aRect.Right() = aRect.Left() + pItems[i].mnOldSplitSize; + } + pWindow->Invalidate( aRect ); + // New Rect invalidieren + if ( bRows ) + { + aRect.Left() = pItems[i].mnLeft; + aRect.Right() = pItems[i].mnLeft+pItems[i].mnWidth-1; + aRect.Top() = pItems[i].mnSplitPos; + aRect.Bottom() = aRect.Top() + pItems[i].mnSplitSize; + } + else + { + aRect.Top() = pItems[i].mnTop; + aRect.Bottom() = pItems[i].mnTop+pItems[i].mnHeight-1; + aRect.Left() = pItems[i].mnSplitPos; + aRect.Right() = aRect.Left() + pItems[i].mnSplitSize; + } + pWindow->Invalidate( aRect ); + + // Leere Sets komplett invalidieren, da diese Flaechen + // nicht von Fenstern ueberladen werden + if ( pItems[i].mpSet && !pItems[i].mpSet->mpItems ) + { + aRect.Left() = pItems[i].mnLeft; + aRect.Top() = pItems[i].mnTop; + aRect.Right() = pItems[i].mnLeft+pItems[i].mnWidth-1; + aRect.Bottom() = pItems[i].mnTop+pItems[i].mnHeight-1; + pWindow->Invalidate( aRect ); + } + } + } + } + } + + // Fenster positionieren + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + { + BOOL bTempHide = bHide; + if ( !pItems[i].mnWidth || !pItems[i].mnHeight ) + bTempHide = TRUE; + ImplCalcSet2( pWindow, pItems[i].mpSet, bTempHide, + ((pItems[i].mnBits & SWIB_COLSET) == 0) ); + } + else + { + if ( pItems[i].mnWidth && pItems[i].mnHeight && !bHide ) + { + Point aPos( pItems[i].mnLeft, pItems[i].mnTop ); + Size aSize( pItems[i].mnWidth, pItems[i].mnHeight ); + pItems[i].mpWindow->SetPosSizePixel( aPos, aSize ); + } + else + pItems[i].mpWindow->Hide(); + } + } + + // Fenster anzeigen und Flag zuruecksetzen + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpWindow && pItems[i].mnWidth && pItems[i].mnHeight && !bHide ) + pItems[i].mpWindow->Show(); + } +} + +// ----------------------------------------------------------------------- + +static void ImplCalcLogSize( ImplSplitItem* pItems, USHORT nItems ) +{ + // Original-Groessen updaten + USHORT i; + long nRelSize = 0; + long nPerSize = 0; + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnBits & SWIB_RELATIVESIZE ) + nRelSize += pItems[i].mnPixSize; + else if ( pItems[i].mnBits & SWIB_PERCENTSIZE ) + nPerSize += pItems[i].mnPixSize; + } + nPerSize += nRelSize; + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mnBits & SWIB_RELATIVESIZE ) + { + if ( nRelSize ) + pItems[i].mnSize = (pItems[i].mnPixSize+(nRelSize/2))/nRelSize; + else + pItems[i].mnSize = 1; + } + else if ( pItems[i].mnBits & SWIB_PERCENTSIZE ) + { + if ( nPerSize ) + pItems[i].mnSize = (pItems[i].mnPixSize*100)/nPerSize; + else + pItems[i].mnSize = 1; + } + else + pItems[i].mnSize = pItems[i].mnPixSize; + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawBack( SplitWindow* pWindow, const Rectangle& rRect, + const Wallpaper* pWall, const Bitmap* pBitmap ) +{ + if ( pBitmap ) + { + Point aPos = rRect.TopLeft(); + Size aBmpSize = pBitmap->GetSizePixel(); + pWindow->Push( PUSH_CLIPREGION ); + pWindow->IntersectClipRegion( rRect ); + do + { + aPos.X() = rRect.Left(); + do + { + pWindow->DrawBitmap( aPos, *pBitmap ); + aPos.X() += aBmpSize.Width(); + } + while ( aPos.X() < rRect.Right() ); + aPos.Y() += aBmpSize.Height(); + } + while ( aPos.Y() < rRect.Bottom() ); + pWindow->Pop(); + } + else + pWindow->DrawWallpaper( rRect, *pWall ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawBack( SplitWindow* pWindow, ImplSplitSet* pSet ) +{ + USHORT i; + USHORT nItems = pSet->mnItems; + ImplSplitItem* pItems = pSet->mpItems; + + // Beim Mainset auch den Hintergrund zeichnen + if ( pSet->mnId == 0 ) + { + if ( pSet->mpBitmap ) + { + Rectangle aRect( pWindow->mnLeftBorder, + pWindow->mnTopBorder, + pWindow->mnDX-pWindow->mnRightBorder-1, + pWindow->mnDY-pWindow->mnBottomBorder-1 ); + ImplDrawBack( pWindow, aRect, pSet->mpWallpaper, pSet->mpBitmap ); + } + } + + for ( i = 0; i < nItems; i++ ) + { + pSet = pItems[i].mpSet; + if ( pSet ) + { + if ( pSet->mpBitmap || pSet->mpWallpaper ) + { + // Wegen ICC auftrennen + Point aPoint( pItems[i].mnLeft, pItems[i].mnTop ); + Size aSize( pItems[i].mnWidth, pItems[i].mnHeight ); + Rectangle aRect( aPoint, aSize ); + ImplDrawBack( pWindow, aRect, pSet->mpWallpaper, pSet->mpBitmap ); + } + } + } + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + ImplDrawBack( pWindow, pItems[i].mpSet ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplDrawSplit( SplitWindow* pWindow, ImplSplitSet* pSet, + BOOL bRows, BOOL bDown = TRUE ) +{ + if ( !pSet->mpItems ) + return; + + USHORT i; + USHORT nItems = pSet->mnItems; + long nPos; + long nTop; + long nBottom; + ImplSplitItem* pItems = pSet->mpItems; + const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings(); + + BOOL bFlat = (pWindow->GetStyle() & WB_FLATSPLITDRAW) == WB_FLATSPLITDRAW; + + for ( i = 0; i < nItems-1; i++ ) + { + if ( pItems[i].mnSplitSize ) + { + nPos = pItems[i].mnSplitPos; + + long nItemSplitSize = pItems[i].mnSplitSize; + long nSplitSize = pSet->mnSplitSize; + if ( bRows ) + { + nTop = pItems[i].mnLeft; + nBottom = pItems[i].mnLeft+pItems[i].mnWidth-1; + + if ( bFlat ) nPos--; + + if ( bDown || (nItemSplitSize >= nSplitSize) ) + { + pWindow->SetLineColor( rStyleSettings.GetLightColor() ); + pWindow->DrawLine( Point( nTop, nPos+1 ), Point( nBottom, nPos+1 ) ); + } + nPos += nSplitSize-2; + if ( bFlat ) nPos+=2; + if ( (!bDown && (nItemSplitSize >= 2)) || + (bDown && (nItemSplitSize >= nSplitSize-1)) ) + { + pWindow->SetLineColor( rStyleSettings.GetShadowColor() ); + pWindow->DrawLine( Point( nTop, nPos ), Point( nBottom, nPos ) ); + } + if ( !bFlat ) + { + nPos++; + if ( !bDown || (nItemSplitSize >= nSplitSize) ) + { + pWindow->SetLineColor( rStyleSettings.GetDarkShadowColor() ); + pWindow->DrawLine( Point( nTop, nPos ), Point( nBottom, nPos ) ); + } + } + } + else + { + nTop = pItems[i].mnTop; + nBottom = pItems[i].mnTop+pSet->mpItems[i].mnHeight-1; + + if ( bFlat ) nPos--; + if ( bDown || (nItemSplitSize >= nSplitSize) ) + { + pWindow->SetLineColor( rStyleSettings.GetLightColor() ); + pWindow->DrawLine( Point( nPos+1, nTop ), Point( nPos+1, nBottom ) ); + } + nPos += pSet->mnSplitSize-2; + if ( bFlat ) nPos+=2; + if ( (!bDown && (nItemSplitSize >= 2)) || + (bDown && (nItemSplitSize >= nSplitSize-1)) ) + { + pWindow->SetLineColor( rStyleSettings.GetShadowColor() ); + pWindow->DrawLine( Point( nPos, nTop ), Point( nPos, nBottom ) ); + } + if( !bFlat ) + { + nPos++; + if ( !bDown || (nItemSplitSize >= nSplitSize) ) + { + pWindow->SetLineColor( rStyleSettings.GetDarkShadowColor() ); + pWindow->DrawLine( Point( nPos, nTop ), Point( nPos, nBottom ) ); + } + } + } + } + } + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet && pItems[i].mnWidth && pItems[i].mnHeight ) + ImplDrawSplit( pWindow, pItems[i].mpSet, ((pItems[i].mnBits & SWIB_COLSET) == 0) ); + } +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::ImplTestSplit( ImplSplitSet* pSet, const Point& rPos, + long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos, + BOOL bRows, BOOL /*bDown*/ ) +{ + if ( !pSet->mpItems ) + return 0; + + USHORT i; + USHORT nSplitTest; + USHORT nItems = pSet->mnItems; + long nMPos1; + long nMPos2; + long nPos; + long nTop; + long nBottom; + ImplSplitItem* pItems = pSet->mpItems; + + if ( bRows ) + { + nMPos1 = rPos.X(); + nMPos2 = rPos.Y(); + } + else + { + nMPos1 = rPos.Y(); + nMPos2 = rPos.X(); + } + + for ( i = 0; i < nItems-1; i++ ) + { + if ( pItems[i].mnSplitSize ) + { + if ( bRows ) + { + nTop = pItems[i].mnLeft; + nBottom = pItems[i].mnLeft+pItems[i].mnWidth-1; + } + else + { + nTop = pItems[i].mnTop; + nBottom = pItems[i].mnTop+pItems[i].mnHeight-1; + } + nPos = pItems[i].mnSplitPos; + + if ( (nMPos1 >= nTop) && (nMPos1 <= nBottom) && + (nMPos2 >= nPos) && (nMPos2 <= nPos+pItems[i].mnSplitSize) ) + { + if ( !pItems[i].mbFixed && !pItems[i+1].mbFixed ) + { + rMouseOff = nMPos2-nPos; + *ppFoundSet = pSet; + rFoundPos = i; + if ( bRows ) + return SPLIT_VERT; + else + return SPLIT_HORZ; + } + else + return SPLIT_NOSPLIT; + } + } + } + + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mpSet ) + { + nSplitTest = ImplTestSplit( pItems[i].mpSet, rPos, + rMouseOff, ppFoundSet, rFoundPos, + ((pItems[i].mnBits & SWIB_COLSET) == 0) ); + if ( nSplitTest ) + return nSplitTest; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::ImplTestSplit( SplitWindow* pWindow, const Point& rPos, + long& rMouseOff, ImplSplitSet** ppFoundSet, USHORT& rFoundPos ) +{ + // Resizeable SplitWindow muss anders behandelt werden + if ( pWindow->mnWinStyle & WB_SIZEABLE ) + { + long nTPos; + long nPos; + long nBorder; + + if ( pWindow->mbHorz ) + { + if ( pWindow->mbBottomRight ) + { + nBorder = pWindow->mnBottomBorder; + nPos = 0; + } + else + { + nBorder = pWindow->mnTopBorder; + nPos = pWindow->mnDY-nBorder; + } + nTPos = rPos.Y(); + } + else + { + if ( pWindow->mbBottomRight ) + { + nBorder = pWindow->mnRightBorder; + nPos = 0; + } + else + { + nBorder = pWindow->mnLeftBorder; + nPos = pWindow->mnDX-nBorder; + } + nTPos = rPos.X(); + } + long nSplitSize = pWindow->mpMainSet->mnSplitSize-2; + if ( pWindow->mbAutoHide || pWindow->mbFadeOut ) + nSplitSize += SPLITWIN_SPLITSIZEEXLN; + if ( !pWindow->mbBottomRight ) + nPos -= nSplitSize; + if ( (nTPos >= nPos) && (nTPos <= nPos+nSplitSize+nBorder) ) + { + rMouseOff = nTPos-nPos; + *ppFoundSet = pWindow->mpMainSet; + if ( pWindow->mpMainSet->mpItems ) + rFoundPos = pWindow->mpMainSet->mnItems-1; + else + rFoundPos = 0; + if ( pWindow->mbHorz ) + return SPLIT_VERT | SPLIT_WINDOW; + else + return SPLIT_HORZ | SPLIT_WINDOW; + } + } + + return ImplTestSplit( pWindow->mpMainSet, rPos, rMouseOff, ppFoundSet, rFoundPos, + pWindow->mbHorz, !pWindow->mbBottomRight ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawSplitTracking( SplitWindow* pThis, const Point& rPos ) +{ + Rectangle aRect; + + if ( pThis->mnSplitTest & SPLIT_HORZ ) + { + aRect.Top() = pThis->maDragRect.Top(); + aRect.Bottom() = pThis->maDragRect.Bottom(); + aRect.Left() = rPos.X(); + aRect.Right() = aRect.Left()+pThis->mpSplitSet->mnSplitSize-1; + if ( !(pThis->mnWinStyle & WB_NOSPLITDRAW) ) + aRect.Right()--; + if ( (pThis->mnSplitTest & SPLIT_WINDOW) && + (pThis->mbAutoHide || pThis->mbFadeOut) ) + { + aRect.Left() += SPLITWIN_SPLITSIZEEXLN; + aRect.Right() += SPLITWIN_SPLITSIZEEXLN; + } + } + else + { + aRect.Left() = pThis->maDragRect.Left(); + aRect.Right() = pThis->maDragRect.Right(); + aRect.Top() = rPos.Y(); + aRect.Bottom() = aRect.Top()+pThis->mpSplitSet->mnSplitSize-1; + if ( !(pThis->mnWinStyle & WB_NOSPLITDRAW) ) + aRect.Bottom()--; + if ( (pThis->mnSplitTest & SPLIT_WINDOW) && + (pThis->mbAutoHide || pThis->mbFadeOut) ) + { + aRect.Top() += SPLITWIN_SPLITSIZEEXLN; + aRect.Bottom() += SPLITWIN_SPLITSIZEEXLN; + } + } + pThis->ShowTracking( aRect, SHOWTRACK_SPLIT ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplInit( Window* pParent, WinBits nStyle ) +{ + ImplSplitSet* pNewSet = new ImplSplitSet; + pNewSet->mpItems = NULL; + pNewSet->mpWallpaper = NULL; + pNewSet->mpBitmap = NULL; + pNewSet->mnLastSize = 0; + pNewSet->mnItems = 0; + pNewSet->mnId = 0; + pNewSet->mnSplitSize = SPLITWIN_SPLITSIZE; + pNewSet->mbCalcPix = TRUE; + + mpMainSet = pNewSet; + mpBaseSet = pNewSet; + mpSplitSet = NULL; + mpLastSizes = NULL; + mnDX = 0; + mnDY = 0; + mnLeftBorder = 0; + mnTopBorder = 0; + mnRightBorder = 0; + mnBottomBorder = 0; + mnMaxSize = 0; + mnMouseOff = 0; + meAlign = WINDOWALIGN_TOP; + mnWinStyle = nStyle; + mnSplitTest = 0; + mnSplitPos = 0; + mnMouseModifier = 0; + mnMStartPos = 0; + mnMSplitPos = 0; + mbDragFull = FALSE; + mbHorz = TRUE; + mbBottomRight = FALSE; + mbCalc = FALSE; + mbRecalc = TRUE; + mbInvalidate = TRUE; + mbAutoHide = FALSE; + mbFadeIn = FALSE; + mbFadeOut = FALSE; + mbAutoHideIn = FALSE; + mbAutoHideDown = FALSE; + mbFadeInDown = FALSE; + mbFadeOutDown = FALSE; + mbAutoHidePressed = FALSE; + mbFadeInPressed = FALSE; + mbFadeOutPressed = FALSE; + mbFadeNoButtonMode = FALSE; + mbNoAlign = FALSE; + + if ( nStyle & WB_NOSPLITDRAW ) + { + pNewSet->mnSplitSize -= 2; + mbInvalidate = FALSE; + } + + if ( nStyle & WB_BORDER ) + { + ImplCalcBorder( meAlign, mbNoAlign, mnLeftBorder, mnTopBorder, + mnRightBorder, mnBottomBorder ); + } + else + { + mnLeftBorder = 0; + mnTopBorder = 0; + mnRightBorder = 0; + mnBottomBorder = 0; + } + + DockingWindow::ImplInit( pParent, (nStyle | WB_CLIPCHILDREN) & ~(WB_BORDER | WB_SIZEABLE) ); + + ImplInitSettings(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplInitSettings() +{ + // Wenn fuer das MainSet eine Bitmap gesetzt wird, dann + // brauchen wir nicht mehr den Hintergrund loeschen + // Wenn MainSet Wallpaper hat, dann ist das der Hintergrund, ansonsten + // sind es die Standard-Farben + if ( mpMainSet->mpBitmap ) + SetBackground(); + else if ( mpMainSet->mpWallpaper ) + SetBackground( *mpMainSet->mpWallpaper ); + else + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + SetBackground( aColor ); + } +} + +// ======================================================================= + +SplitWindow::SplitWindow( Window* pParent, WinBits nStyle ) : + DockingWindow( WINDOW_SPLITWINDOW ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +SplitWindow::SplitWindow( Window* pParent, const ResId& rResId ) : + DockingWindow( WINDOW_SPLITWINDOW ) +{ + rResId.SetRT( RSC_SPLITWINDOW ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +SplitWindow::~SplitWindow() +{ + // Sets loeschen + ImplDeleteSet( mpMainSet ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplSetWindowSize( long nDelta ) +{ + if ( !nDelta ) + return; + + Size aSize = GetSizePixel(); + if ( meAlign == WINDOWALIGN_TOP ) + { + aSize.Height() += nDelta; + SetSizePixel( aSize ); + } + else if ( meAlign == WINDOWALIGN_BOTTOM ) + { + maDragRect.Top() += nDelta; + Point aPos = GetPosPixel(); + aPos.Y() -= nDelta; + aSize.Height() += nDelta; + SetPosSizePixel( aPos, aSize ); + } + else if ( meAlign == WINDOWALIGN_LEFT ) + { + aSize.Width() += nDelta; + SetSizePixel( aSize ); + } + else // meAlign == WINDOWALIGN_RIGHT + { + maDragRect.Left() += nDelta; + Point aPos = GetPosPixel(); + aPos.X() -= nDelta; + aSize.Width() += nDelta; + SetPosSizePixel( aPos, aSize ); + } + + SplitResize(); +} + +// ----------------------------------------------------------------------- + +Size SplitWindow::CalcLayoutSizePixel( const Size& aNewSize ) +{ + Size aSize( aNewSize ); + long nSplitSize = mpMainSet->mnSplitSize-2; + + if ( mbAutoHide || mbFadeOut ) + nSplitSize += SPLITWIN_SPLITSIZEEXLN; + + // Wenn Fenster sizeable ist, wird die groesse automatisch nach + // dem MainSet festgelegt, wenn kein relatives Fenster enthalten + // ist + if ( mnWinStyle & WB_SIZEABLE ) + { + long nCurSize; + long nCalcSize = 0; + USHORT i; + + for ( i = 0; i < mpMainSet->mnItems; i++ ) + { + if ( mpMainSet->mpItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE) ) + break; + else + nCalcSize += mpMainSet->mpItems[i].mnSize; + } + + if ( i == mpMainSet->mnItems ) + { + long nDelta = 0; + Point aPos = GetPosPixel(); + + if ( mbHorz ) + nCurSize = aNewSize.Height()-mnTopBorder-mnBottomBorder; + else + nCurSize = aNewSize.Width()-mnLeftBorder-mnRightBorder; + nCurSize -= nSplitSize; + nCurSize -= (mpMainSet->mnItems-1)*mpMainSet->mnSplitSize; + + nDelta = nCalcSize-nCurSize; + if ( !nDelta ) + return aSize; + + if ( meAlign == WINDOWALIGN_TOP ) + { + aSize.Height() += nDelta; + } + else if ( meAlign == WINDOWALIGN_BOTTOM ) + { + aPos.Y() -= nDelta; + aSize.Height() += nDelta; + } + else if ( meAlign == WINDOWALIGN_LEFT ) + { + aSize.Width() += nDelta; + } + else // meAlign == WINDOWALIGN_RIGHT + { + aPos.X() -= nDelta; + aSize.Width() += nDelta; + } + } + } + + return aSize; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplCalcLayout() +{ + if ( !mbCalc || !mbRecalc || !mpMainSet->mpItems ) + return; + + long nSplitSize = mpMainSet->mnSplitSize-2; + if ( mbAutoHide || mbFadeOut ) + nSplitSize += SPLITWIN_SPLITSIZEEXLN; + + // Wenn Fenster sizeable ist, wird die groesse automatisch nach + // dem MainSet festgelegt, wenn kein relatives Fenster enthalten + // ist + if ( mnWinStyle & WB_SIZEABLE ) + { + long nCurSize; + long nCalcSize = 0; + USHORT i; + + for ( i = 0; i < mpMainSet->mnItems; i++ ) + { + if ( mpMainSet->mpItems[i].mnBits & (SWIB_RELATIVESIZE | SWIB_PERCENTSIZE) ) + break; + else + nCalcSize += mpMainSet->mpItems[i].mnSize; + } + + if ( i == mpMainSet->mnItems ) + { + if ( mbHorz ) + nCurSize = mnDY-mnTopBorder-mnBottomBorder; + else + nCurSize = mnDX-mnLeftBorder-mnRightBorder; + nCurSize -= nSplitSize; + nCurSize -= (mpMainSet->mnItems-1)*mpMainSet->mnSplitSize; + + mbRecalc = FALSE; + ImplSetWindowSize( nCalcSize-nCurSize ); + mbRecalc = TRUE; + } + } + + if ( (mnDX <= 0) || (mnDY <= 0) ) + return; + + // Groessen/Position vorberechnen + long nL; + long nT; + long nW; + long nH; + + if ( mbHorz ) + { + if ( mbBottomRight ) + nT = mnDY-mnBottomBorder; + else + nT = mnTopBorder; + nL = mnLeftBorder; + } + else + { + if ( mbBottomRight ) + nL = mnDX-mnRightBorder; + else + nL = mnLeftBorder; + nT = mnTopBorder; + } + nW = mnDX-mnLeftBorder-mnRightBorder; + nH = mnDY-mnTopBorder-mnBottomBorder; + if ( mnWinStyle & WB_SIZEABLE ) + { + if ( mbHorz ) + nH -= nSplitSize; + else + nW -= nSplitSize; + } + + // Sets rekursiv berechnen + ImplCalcSet( mpMainSet, nL, nT, nW, nH, mbHorz, !mbBottomRight ); + ImplCalcSet2( this, mpMainSet, FALSE, mbHorz, !mbBottomRight ); + mbCalc = FALSE; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplUpdate() +{ + mbCalc = TRUE; + + if ( IsReallyShown() && IsUpdateMode() && mbRecalc ) + { + if ( mpMainSet->mpItems ) + ImplCalcLayout(); + else + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplUpdateSet( ImplSplitSet* pSet ) +{ + if ( IsReallyShown() && IsUpdateMode() && mbRecalc ) + { + // Wenn wir noch berechnen muessen, dann alles invalidieren. + if ( mbCalc ) + { + // Wenn nicht NOSPLITDRAW gesetzt ist, koennen wir uns das + // invalidieren sparen, da bei ImplCalcSet2() die freien flaechen + // sowieso invalidiert werden + if ( !mpMainSet->mpItems || (mnWinStyle & WB_NOSPLITDRAW) ) + pSet = mpMainSet; + else + return; + } + + Rectangle aRect; + if ( pSet == mpMainSet ) + { + aRect.Left() = mnLeftBorder; + aRect.Top() = mnTopBorder; + aRect.Right() = mnDX-mnRightBorder-1; + aRect.Bottom() = mnDY-mnBottomBorder-1; + } + else + { + ImplSplitItem* pItem; + USHORT nPos; + + pSet = ImplFindItem( mpMainSet, pSet->mnId, nPos ); + pItem = &(pSet->mpItems[nPos]); + aRect.Left() = pItem->mnLeft; + aRect.Top() = pItem->mnTop; + aRect.Right() = aRect.Left()+pItem->mnWidth; + aRect.Bottom() = aRect.Top()+pItem->mnHeight; + } + Invalidate( aRect ); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplSplitMousePos( Point& rMousePos ) +{ + if ( mnSplitTest & SPLIT_HORZ ) + { + rMousePos.X() -= mnMouseOff; + if ( rMousePos.X() < maDragRect.Left() ) + rMousePos.X() = maDragRect.Left(); + else if ( rMousePos.X()+mpSplitSet->mnSplitSize+1 > maDragRect.Right() ) + rMousePos.X() = maDragRect.Right()-mpSplitSet->mnSplitSize+1; + // Wegen FullDrag in Screen-Koordinaaten merken + mnMSplitPos = OutputToScreenPixel( rMousePos ).X(); + } + else + { + rMousePos.Y() -= mnMouseOff; + if ( rMousePos.Y() < maDragRect.Top() ) + rMousePos.Y() = maDragRect.Top(); + else if ( rMousePos.Y()+mpSplitSet->mnSplitSize+1 > maDragRect.Bottom() ) + rMousePos.Y() = maDragRect.Bottom()-mpSplitSet->mnSplitSize+1; + mnMSplitPos = OutputToScreenPixel( rMousePos ).Y(); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplGetButtonRect( Rectangle& rRect, long nEx, BOOL bTest ) const +{ + long nSplitSize = mpMainSet->mnSplitSize-2; + if ( mbAutoHide || mbFadeOut || mbFadeIn ) + nSplitSize += SPLITWIN_SPLITSIZEEX; + + long nButtonSize = 0; + if ( mbFadeIn ) + nButtonSize += SPLITWIN_SPLITSIZEFADE+1; + if ( mbFadeOut ) + nButtonSize += SPLITWIN_SPLITSIZEFADE+1; + if ( mbAutoHide ) + nButtonSize += SPLITWIN_SPLITSIZEAUTOHIDE+1; + long nCenterEx = 0; + if ( mbHorz ) + nCenterEx += ((mnDX-mnLeftBorder-mnRightBorder)-nButtonSize)/2; + else + nCenterEx += ((mnDY-mnTopBorder-mnBottomBorder)-nButtonSize)/2; + if ( nCenterEx > 0 ) + nEx += nCenterEx; + + if ( meAlign == WINDOWALIGN_TOP ) + { + rRect.Left() = mnLeftBorder+nEx; + rRect.Top() = mnDY-mnBottomBorder-nSplitSize; + rRect.Right() = rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE; + rRect.Bottom() = mnDY-mnBottomBorder-1; + if ( bTest ) + { + rRect.Top() -= mnTopBorder; + rRect.Bottom() += mnBottomBorder; + } + } + else if ( meAlign == WINDOWALIGN_BOTTOM ) + { + rRect.Left() = mnLeftBorder+nEx; + rRect.Top() = mnTopBorder; + rRect.Right() = rRect.Left()+SPLITWIN_SPLITSIZEAUTOHIDE; + rRect.Bottom() = mnTopBorder+nSplitSize-1; + if ( bTest ) + { + rRect.Top() -= mnTopBorder; + rRect.Bottom() += mnBottomBorder; + } + } + else if ( meAlign == WINDOWALIGN_LEFT ) + { + rRect.Left() = mnDX-mnRightBorder-nSplitSize; + rRect.Top() = mnTopBorder+nEx; + rRect.Right() = mnDX-mnRightBorder-1; + rRect.Bottom() = rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE; + if ( bTest ) + { + rRect.Left() -= mnLeftBorder; + rRect.Right() += mnRightBorder; + } + } + else if ( meAlign == WINDOWALIGN_RIGHT ) + { + rRect.Left() = mnLeftBorder; + rRect.Top() = mnTopBorder+nEx; + rRect.Right() = mnLeftBorder+nSplitSize-1; + rRect.Bottom() = rRect.Top()+SPLITWIN_SPLITSIZEAUTOHIDE; + if ( bTest ) + { + rRect.Left() -= mnLeftBorder; + rRect.Right() += mnRightBorder; + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplGetAutoHideRect( Rectangle& rRect, BOOL bTest ) const +{ + Rectangle aRect; + + if ( mbAutoHide ) + { + long nEx = 0; + if ( mbFadeIn || mbFadeOut ) + nEx = SPLITWIN_SPLITSIZEFADE+1; + ImplGetButtonRect( aRect, nEx, bTest && mbFadeIn ); + } + + rRect = aRect; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplGetFadeInRect( Rectangle& rRect, BOOL bTest ) const +{ + Rectangle aRect; + + if ( mbFadeIn ) + ImplGetButtonRect( aRect, 0, bTest ); + + rRect = aRect; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplGetFadeOutRect( Rectangle& rRect, BOOL ) const +{ + Rectangle aRect; + + if ( mbFadeOut ) + ImplGetButtonRect( aRect, 0, FALSE ); + + rRect = aRect; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawButtonRect( const Rectangle& rRect, long nSize ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( mbHorz ) + { + long nLeft = rRect.Left(); + long nRight = rRect.Right(); + long nCenter = rRect.Center().Y(); + long nEx1 = nLeft+((rRect.GetWidth()-nSize)/2)-2; + long nEx2 = nEx1+nSize+3; + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Left(), rRect.Bottom() ) ); + DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Right(), rRect.Top() ) ); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( rRect.Right(), rRect.Top() ), Point( rRect.Right(), rRect.Bottom() ) ); + DrawLine( Point( rRect.Left(), rRect.Bottom() ), Point( rRect.Right(), rRect.Bottom() ) ); + long i = nLeft+2; + while ( i < nRight-3 ) + { + if ( (i < nEx1) || (i > nEx2 ) ) + { + DrawPixel( Point( i, nCenter-2 ), rStyleSettings.GetLightColor() ); + DrawPixel( Point( i+1, nCenter-2+1 ), rStyleSettings.GetShadowColor() ); + } + i++; + if ( (i < nEx1) || ((i > nEx2 ) && (i < nRight-3)) ) + { + DrawPixel( Point( i, nCenter+2 ), rStyleSettings.GetLightColor() ); + DrawPixel( Point( i+1, nCenter+2+1 ), rStyleSettings.GetShadowColor() ); + } + i += 2; + } + } + else + { + long nTop = rRect.Top(); + long nBottom = rRect.Bottom(); + long nCenter = rRect.Center().X(); + long nEx1 = nTop+((rRect.GetHeight()-nSize)/2)-2; + long nEx2 = nEx1+nSize+3; + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Right(), rRect.Top() ) ); + DrawLine( Point( rRect.Left(), rRect.Top() ), Point( rRect.Left(), rRect.Bottom() ) ); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( rRect.Right(), rRect.Top() ), Point( rRect.Right(), rRect.Bottom() ) ); + DrawLine( Point( rRect.Left(), rRect.Bottom() ), Point( rRect.Right(), rRect.Bottom() ) ); + long i = nTop+2; + while ( i < nBottom-3 ) + { + if ( (i < nEx1) || (i > nEx2 ) ) + { + DrawPixel( Point( nCenter-2, i ), rStyleSettings.GetLightColor() ); + DrawPixel( Point( nCenter-2+1, i+1 ), rStyleSettings.GetShadowColor() ); + } + i++; + if ( (i < nEx1) || ((i > nEx2 ) && (i < nBottom-3)) ) + { + DrawPixel( Point( nCenter+2, i ), rStyleSettings.GetLightColor() ); + DrawPixel( Point( nCenter+2+1, i+1 ), rStyleSettings.GetShadowColor() ); + } + i += 2; + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawAutoHide( BOOL bInPaint ) +{ + if ( mbAutoHide ) + { + Rectangle aTempRect; + ImplGetAutoHideRect( aTempRect ); + + if ( !bInPaint ) + Erase( aTempRect ); + + // ImageListe laden, wenn noch nicht vorhanden + ImplSVData* pSVData = ImplGetSVData(); + ImageList* pImageList; + if ( mbHorz ) + { + if ( !pSVData->maCtrlData.mpSplitHPinImgList ) + { + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + { + Color aNonAlphaMask( 0x00, 0x00, 0xFF ); + pSVData->maCtrlData.mpSplitHPinImgList = new ImageList(4); + pSVData->maCtrlData.mpSplitHPinImgList->InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_SPLITHPIN, *pResMgr ), 4, &aNonAlphaMask ); + } + } + pImageList = pSVData->maCtrlData.mpSplitHPinImgList; + } + else + { + if ( !pSVData->maCtrlData.mpSplitVPinImgList ) + { + ResMgr* pResMgr = ImplGetResMgr(); + pSVData->maCtrlData.mpSplitVPinImgList = new ImageList(4); + if( pResMgr ) + { + Color aNonAlphaMask( 0x00, 0x00, 0xFF ); + pSVData->maCtrlData.mpSplitVPinImgList->InsertFromHorizontalBitmap + ( ResId( SV_RESID_BITMAP_SPLITVPIN, *pResMgr ), 4, &aNonAlphaMask ); + } + } + pImageList = pSVData->maCtrlData.mpSplitVPinImgList; + } + + // Image ermitteln und zurueckgeben + USHORT nId; + if ( mbAutoHidePressed ) + { + if ( mbAutoHideIn ) + nId = 3; + else + nId = 4; + } + else + { + if ( mbAutoHideIn ) + nId = 1; + else + nId = 2; + } + + Image aImage = pImageList->GetImage( nId ); + Size aImageSize = aImage.GetSizePixel(); + Point aPos( aTempRect.Left()+((aTempRect.GetWidth()-aImageSize.Width())/2), + aTempRect.Top()+((aTempRect.GetHeight()-aImageSize.Height())/2) ); + long nSize; + if ( mbHorz ) + nSize = aImageSize.Width(); + else + nSize = aImageSize.Height(); + ImplDrawButtonRect( aTempRect, nSize ); + DrawImage( aPos, aImage ); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawFadeArrow( const Point& rPt, BOOL bHorz, BOOL bLeft ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + int x( rPt.X() ); + int y( rPt.Y() ); + + Color aCol; + if( !bHorz ) + { + int dx = 1; + if( bLeft ) + { + x ++; + dx = -1; + } + + x++; y++; + aCol = Color( COL_WHITE ); + DrawPixel( Point(x, y), aCol ); + DrawPixel( Point(x, y+1), aCol ); + DrawPixel( Point(x, y+2), aCol ); + DrawPixel( Point(x+dx, y+1), aCol ); + + x--; y--; + aCol = rStyleSettings.GetDarkShadowColor(); + DrawPixel( Point(x, y), rStyleSettings.GetDarkShadowColor() ); + DrawPixel( Point(x, y+1), rStyleSettings.GetDarkShadowColor() ); + DrawPixel( Point(x, y+2), rStyleSettings.GetDarkShadowColor() ); + DrawPixel( Point(x+dx, y+1), rStyleSettings.GetDarkShadowColor() ); + } + else + { + int dy = 1; + if( bLeft ) + { + y ++; + dy = -1; + } + + x++; y++; + aCol = Color( COL_WHITE ); + DrawPixel( Point(x, y), aCol ); + DrawPixel( Point(x+1, y), aCol ); + DrawPixel( Point(x+2, y), aCol ); + DrawPixel( Point(x+1, y+dy), aCol ); + + x--; y--; + aCol = rStyleSettings.GetDarkShadowColor(); + DrawPixel( Point(x, y), aCol ); + DrawPixel( Point(x+1, y), aCol ); + DrawPixel( Point(x+2, y), aCol ); + DrawPixel( Point(x+1, y+dy), aCol ); + } +} + +void SplitWindow::ImplDrawGrip( const Rectangle& rRect, BOOL bHorz, BOOL bLeft ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if( rRect.IsInside( GetPointerPosPixel() ) ) + { + DrawWallpaper( rRect, Wallpaper( Color( COL_WHITE ) ) ); + DrawSelectionBackground( rRect, 2, FALSE, FALSE, FALSE ); + } + + if( bHorz ) + { + int width = (int) (0.5 * rRect.getWidth() + 0.5); + int i = rRect.nLeft + (rRect.getWidth() - width) / 2; + width += i; + const int y = rRect.nTop + 1; + ImplDrawFadeArrow( Point( i-8, y), bHorz, bLeft ); + while( i <= width ) + { + + DrawPixel( Point(i, y), rStyleSettings.GetDarkShadowColor() ); + DrawPixel( Point(i+1, y), rStyleSettings.GetShadowColor() ); + + DrawPixel( Point(i, y+1), rStyleSettings.GetShadowColor() ); + DrawPixel( Point(i+1, y+1), rStyleSettings.GetFaceColor() ); + DrawPixel( Point(i+2, y+1), Color(COL_WHITE) ); + + DrawPixel( Point(i+1, y+2), Color(COL_WHITE) ); + DrawPixel( Point(i+2, y+2), Color(COL_WHITE) ); + i+=4; + } + ImplDrawFadeArrow( Point( i+3, y), bHorz, bLeft ); + } + else + { + int height = (int) (0.5 * rRect.getHeight() + 0.5); + int i = rRect.nTop + (rRect.getHeight() - height) / 2; + height += i; + const int x = rRect.nLeft + 1; + ImplDrawFadeArrow( Point( x, i-8), bHorz, bLeft ); + while( i <= height ) + { + + DrawPixel( Point(x, i), rStyleSettings.GetDarkShadowColor() ); + DrawPixel( Point(x+1, i), rStyleSettings.GetShadowColor() ); + + DrawPixel( Point(x, i+1), rStyleSettings.GetShadowColor() ); + DrawPixel( Point(x+1, i+1), rStyleSettings.GetFaceColor() ); + DrawPixel( Point(x+2, i+1), Color(COL_WHITE) ); + + DrawPixel( Point(x+1, i+2), Color(COL_WHITE) ); + DrawPixel( Point(x+2, i+2), Color(COL_WHITE) ); + i+=4; + } + ImplDrawFadeArrow( Point( x, i+3), bHorz, bLeft ); + } +} + +void SplitWindow::ImplDrawFadeIn( BOOL bInPaint ) +{ + if ( mbFadeIn ) + { + Rectangle aTempRect; + Image aImage; + ImplGetFadeInRect( aTempRect ); + + BOOL bLeft; + if ( meAlign == WINDOWALIGN_TOP ) + bLeft = FALSE; + else if ( meAlign == WINDOWALIGN_BOTTOM ) + bLeft = TRUE; + else if ( meAlign == WINDOWALIGN_LEFT ) + bLeft = FALSE; + else if ( meAlign == WINDOWALIGN_RIGHT ) + bLeft = TRUE; + else + bLeft = TRUE; + + if ( !bInPaint ) + Erase( aTempRect ); + + ImplDrawGrip( aTempRect, (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM), bLeft ); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplDrawFadeOut( BOOL bInPaint ) +{ + if ( mbFadeOut ) + { + Rectangle aTempRect; + Image aImage; + ImplGetFadeOutRect( aTempRect ); + + BOOL bLeft; + if ( meAlign == WINDOWALIGN_TOP ) + bLeft = TRUE; + else if ( meAlign == WINDOWALIGN_BOTTOM ) + bLeft = FALSE; + else if ( meAlign == WINDOWALIGN_LEFT ) + bLeft = TRUE; + else if ( meAlign == WINDOWALIGN_RIGHT ) + bLeft = FALSE; + else + bLeft = TRUE; + + if ( !bInPaint ) + Erase( aTempRect ); + + ImplDrawGrip( aTempRect, (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM), bLeft ); + } +} + +// ----------------------------------------------------------------------- +void SplitWindow::ImplStartSplit( const MouseEvent& rMEvt ) +{ + Point aMousePosPixel = rMEvt.GetPosPixel(); + mnSplitTest = ImplTestSplit( this, aMousePosPixel, mnMouseOff, &mpSplitSet, mnSplitPos ); + + if ( mnSplitTest && !(mnSplitTest & SPLIT_NOSPLIT) ) + { + ImplSplitItem* pSplitItem; + long nCurMaxSize; + USHORT nTemp; + BOOL bDown; + BOOL bPropSmaller; + + mnMouseModifier = rMEvt.GetModifier(); + if ( !(mnMouseModifier & KEY_SHIFT) || (mnSplitPos+1 >= mpSplitSet->mnItems) ) + bPropSmaller = FALSE; + else + bPropSmaller = TRUE; + + // Hier kann noch die maximale Groesse gesetzt werden + StartSplit(); + + if ( mnMaxSize ) + nCurMaxSize = mnMaxSize; + else + { + Size aSize = GetParent()->GetOutputSizePixel(); + if ( mbHorz ) + nCurMaxSize = aSize.Height(); + else + nCurMaxSize = aSize.Width(); + } + + if ( mpSplitSet->mpItems ) + { + bDown = TRUE; + if ( (mpSplitSet == mpMainSet) && mbBottomRight ) + bDown = FALSE; + + pSplitItem = &(mpSplitSet->mpItems[mnSplitPos]); + maDragRect.Left() = pSplitItem->mnLeft; + maDragRect.Top() = pSplitItem->mnTop; + maDragRect.Right() = pSplitItem->mnLeft+pSplitItem->mnWidth-1; + maDragRect.Bottom() = pSplitItem->mnTop+pSplitItem->mnHeight-1; + + if ( mnSplitTest & SPLIT_HORZ ) + { + if ( bDown ) + maDragRect.Right() += mpSplitSet->mnSplitSize; + else + maDragRect.Left() -= mpSplitSet->mnSplitSize; + } + else + { + if ( bDown ) + maDragRect.Bottom() += mpSplitSet->mnSplitSize; + else + maDragRect.Top() -= mpSplitSet->mnSplitSize; + } + + if ( mnSplitPos ) + { + nTemp = mnSplitPos; + while ( nTemp ) + { + pSplitItem = &(mpSplitSet->mpItems[nTemp-1]); + if ( pSplitItem->mbFixed ) + break; + else + { + if ( mnSplitTest & SPLIT_HORZ ) + { + if ( bDown ) + maDragRect.Left() -= pSplitItem->mnPixSize; + else + maDragRect.Right() += pSplitItem->mnPixSize; + } + else + { + if ( bDown ) + maDragRect.Top() -= pSplitItem->mnPixSize; + else + maDragRect.Bottom() += pSplitItem->mnPixSize; + } + } + nTemp--; + } + } + + if ( (mpSplitSet == mpMainSet) && (mnWinStyle & WB_SIZEABLE) && !bPropSmaller ) + { + if ( bDown ) + { + if ( mbHorz ) + maDragRect.Bottom() += nCurMaxSize-mnDY-mnTopBorder; + else + maDragRect.Right() += nCurMaxSize-mnDX-mnLeftBorder; + } + else + { + if ( mbHorz ) + maDragRect.Top() -= nCurMaxSize-mnDY-mnBottomBorder; + else + maDragRect.Left() -= nCurMaxSize-mnDX-mnRightBorder; + } + } + else + { + nTemp = mnSplitPos+1; + while ( nTemp < mpSplitSet->mnItems ) + { + pSplitItem = &(mpSplitSet->mpItems[nTemp]); + if ( pSplitItem->mbFixed ) + break; + else + { + if ( mnSplitTest & SPLIT_HORZ ) + { + if ( bDown ) + maDragRect.Right() += pSplitItem->mnPixSize; + else + maDragRect.Left() -= pSplitItem->mnPixSize; + } + else + { + if ( bDown ) + maDragRect.Bottom() += pSplitItem->mnPixSize; + else + maDragRect.Top() -= pSplitItem->mnPixSize; + } + } + nTemp++; + } + } + } + else + { + maDragRect.Left() = mnLeftBorder; + maDragRect.Top() = mnTopBorder; + maDragRect.Right() = mnDX-mnRightBorder-1; + maDragRect.Bottom() = mnDY-mnBottomBorder-1; + if ( mbHorz ) + { + if ( mbBottomRight ) + maDragRect.Top() -= nCurMaxSize-mnDY-mnBottomBorder; + else + maDragRect.Bottom() += nCurMaxSize-mnDY-mnTopBorder; + } + else + { + if ( mbBottomRight ) + maDragRect.Left() -= nCurMaxSize-mnDX-mnRightBorder; + else + maDragRect.Right() += nCurMaxSize-mnDX-mnLeftBorder; + } + } + + StartTracking(); + + mbDragFull = (GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0; + + ImplSplitMousePos( aMousePosPixel ); + + if ( !mbDragFull ) + ImplDrawSplitTracking( this, aMousePosPixel ); + else + { + ImplSplitItem* pItems = mpSplitSet->mpItems; + USHORT nItems = mpSplitSet->mnItems; + mpLastSizes = new long[nItems*2]; + for ( USHORT i = 0; i < nItems; i++ ) + { + mpLastSizes[i*2] = pItems[i].mnSize; + mpLastSizes[i*2+1] = pItems[i].mnPixSize; + } + } + mnMStartPos = mnMSplitPos; + + PointerStyle eStyle = POINTER_ARROW; + if ( mnSplitTest & SPLIT_HORZ ) + eStyle = POINTER_HSPLIT; + else if ( mnSplitTest & SPLIT_VERT ) + eStyle = POINTER_VSPLIT; + + Pointer aPtr( eStyle ); + SetPointer( aPtr ); + } +} + + +// ----------------------------------------------------------------------- + +void SplitWindow::StartSplit() +{ + maStartSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Split() +{ + maSplitHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SplitResize() +{ + maSplitResizeHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::AutoHide() +{ + maAutoHideHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::FadeIn() +{ + maFadeInHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::FadeOut() +{ + maFadeOutHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( !rMEvt.IsLeft() || rMEvt.IsMod2() ) + { + DockingWindow::MouseButtonDown( rMEvt ); + return; + } + + Point aMousePosPixel = rMEvt.GetPosPixel(); + Rectangle aTestRect; + + mbFadeNoButtonMode = FALSE; + ImplGetAutoHideRect( aTestRect, TRUE ); + if ( aTestRect.IsInside( aMousePosPixel ) ) + { + mbAutoHideDown = TRUE; + mbAutoHidePressed = TRUE; + ImplDrawAutoHide( FALSE ); + } + else + { + ImplGetFadeOutRect( aTestRect, TRUE ); + if ( aTestRect.IsInside( aMousePosPixel ) ) + { + mbFadeOutDown = TRUE; + mbFadeOutPressed = TRUE; + ImplDrawFadeOut( FALSE ); + } + else + { + ImplGetFadeInRect( aTestRect, TRUE ); + if ( aTestRect.IsInside( aMousePosPixel ) ) + { + mbFadeInDown = TRUE; + mbFadeInPressed = TRUE; + ImplDrawFadeIn( FALSE ); + } + else if ( !aTestRect.IsEmpty() && !(mnWinStyle & WB_SIZEABLE) ) + { + mbFadeNoButtonMode = TRUE; + FadeIn(); + return; + } + } + } + + if ( mbAutoHideDown || mbFadeInDown || mbFadeOutDown ) + StartTracking(); + else + ImplStartSplit( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::MouseMove( const MouseEvent& rMEvt ) +{ + if ( !IsTracking() ) + { + Point aPos = rMEvt.GetPosPixel(); + long nTemp; + ImplSplitSet* pTempSplitSet; + USHORT nTempSplitPos; + USHORT nSplitTest = ImplTestSplit( this, aPos, nTemp, &pTempSplitSet, nTempSplitPos ); + PointerStyle eStyle = POINTER_ARROW; + Rectangle aAutoHideRect; + Rectangle aFadeInRect; + Rectangle aFadeOutRect; + + ImplGetAutoHideRect( aAutoHideRect ); + ImplGetFadeInRect( aFadeInRect ); + ImplGetFadeOutRect( aFadeOutRect ); + if ( !aAutoHideRect.IsInside( aPos ) && + !aFadeInRect.IsInside( aPos ) && + !aFadeOutRect.IsInside( aPos ) ) + { + if ( nSplitTest && !(nSplitTest & SPLIT_NOSPLIT) ) + { + if ( nSplitTest & SPLIT_HORZ ) + eStyle = POINTER_HSPLIT; + else if ( nSplitTest & SPLIT_VERT ) + eStyle = POINTER_VSPLIT; + } + } + + Pointer aPtr( eStyle ); + SetPointer( aPtr ); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Tracking( const TrackingEvent& rTEvt ) +{ + Point aMousePosPixel = rTEvt.GetMouseEvent().GetPosPixel(); + + if ( mbAutoHideDown ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbAutoHideDown = FALSE; + if ( mbAutoHidePressed ) + { + mbAutoHidePressed = FALSE; + + if ( !rTEvt.IsTrackingCanceled() ) + { + mbAutoHideIn = !mbAutoHideIn; + ImplDrawAutoHide( FALSE ); + AutoHide(); + } + else + ImplDrawAutoHide( FALSE ); + } + } + else + { + Rectangle aTestRect; + ImplGetAutoHideRect( aTestRect, TRUE ); + BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel ); + if ( bNewPressed != mbAutoHidePressed ) + { + mbAutoHidePressed = bNewPressed; + ImplDrawAutoHide( FALSE ); + } + } + } + else if ( mbFadeInDown ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbFadeInDown = FALSE; + if ( mbFadeInPressed ) + { + mbFadeInPressed = FALSE; + ImplDrawFadeIn( FALSE ); + + if ( !rTEvt.IsTrackingCanceled() ) + FadeIn(); + } + } + else + { + Rectangle aTestRect; + ImplGetFadeInRect( aTestRect, TRUE ); + BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel ); + if ( bNewPressed != mbFadeInPressed ) + { + mbFadeInPressed = bNewPressed; + ImplDrawFadeIn( FALSE ); + } + } + } + else if ( mbFadeOutDown ) + { + if ( rTEvt.IsTrackingEnded() ) + { + mbFadeOutDown = FALSE; + if ( mbFadeOutPressed ) + { + mbFadeOutPressed = FALSE; + ImplDrawFadeOut( FALSE ); + + if ( !rTEvt.IsTrackingCanceled() ) + FadeOut(); + } + } + else + { + Rectangle aTestRect; + ImplGetFadeOutRect( aTestRect, TRUE ); + BOOL bNewPressed = aTestRect.IsInside( aMousePosPixel ); + if ( bNewPressed == FALSE ) + { + mbFadeOutPressed = bNewPressed; + ImplDrawFadeOut( FALSE ); + + // We need a mouseevent with a position inside the button for the + // ImplStartSplit function! + MouseEvent aOrgMEvt = rTEvt.GetMouseEvent(); + MouseEvent aNewMEvt = MouseEvent( aTestRect.Center(), aOrgMEvt.GetClicks(), + aOrgMEvt.GetMode(), aOrgMEvt.GetButtons(), + aOrgMEvt.GetModifier() ); + + ImplStartSplit( aNewMEvt ); + mbFadeOutDown = FALSE; + } + } + } + else + { + ImplSplitMousePos( aMousePosPixel ); + BOOL bSplit = TRUE; + if ( mbDragFull ) + { + if ( rTEvt.IsTrackingEnded() ) + { + if ( rTEvt.IsTrackingCanceled() ) + { + ImplSplitItem* pItems = mpSplitSet->mpItems; + USHORT nItems = mpSplitSet->mnItems; + for ( USHORT i = 0; i < nItems; i++ ) + { + pItems[i].mnSize = mpLastSizes[i*2]; + pItems[i].mnPixSize = mpLastSizes[i*2+1]; + } + ImplUpdate(); + Split(); + } + bSplit = FALSE; + } + } + else + { + if ( rTEvt.IsTrackingEnded() ) + { + HideTracking(); + bSplit = !rTEvt.IsTrackingCanceled(); + } + else + { + ImplDrawSplitTracking( this, aMousePosPixel ); + bSplit = FALSE; + } + } + + if ( bSplit ) + { + BOOL bPropSmaller = (mnMouseModifier & KEY_SHIFT) ? TRUE : FALSE; + BOOL bPropGreater = (mnMouseModifier & KEY_MOD1) ? TRUE : FALSE; + long nDelta = mnMSplitPos-mnMStartPos; + + if ( (mnSplitTest & SPLIT_WINDOW) && !mpMainSet->mpItems ) + { + if ( (mpSplitSet == mpMainSet) && mbBottomRight ) + nDelta *= -1; + ImplSetWindowSize( nDelta ); + } + else + { + long nNewSize = mpSplitSet->mpItems[mnSplitPos].mnPixSize; + if ( (mpSplitSet == mpMainSet) && mbBottomRight ) + nNewSize -= nDelta; + else + nNewSize += nDelta; + SplitItem( mpSplitSet->mpItems[mnSplitPos].mnId, nNewSize, + bPropSmaller, bPropGreater ); + } + + Split(); + + if ( mbDragFull ) + { + Update(); + mnMStartPos = mnMSplitPos; + } + } + + if ( rTEvt.IsTrackingEnded() ) + { + if ( mpLastSizes ) + delete mpLastSizes; + mpLastSizes = NULL; + mpSplitSet = NULL; + mnMouseOff = 0; + mnMStartPos = 0; + mnMSplitPos = 0; + mnMouseModifier = 0; + mnSplitTest = 0; + mnSplitPos = 0; + } + } +} + +// ----------------------------------------------------------------------- + +long SplitWindow::PreNotify( NotifyEvent& rNEvt ) +{ + const MouseEvent* pMouseEvt = NULL; + + if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL ) + { + if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() ) + { + // trigger redraw if mouse over state has changed + Rectangle aFadeInRect; + Rectangle aFadeOutRect; + ImplGetFadeInRect( aFadeInRect ); + ImplGetFadeOutRect( aFadeOutRect ); + + if ( aFadeInRect.IsInside( GetPointerPosPixel() ) != aFadeInRect.IsInside( GetLastPointerPosPixel() ) ) + Invalidate( aFadeInRect ); + if ( aFadeOutRect.IsInside( GetPointerPosPixel() ) != aFadeOutRect.IsInside( GetLastPointerPosPixel() ) ) + Invalidate( aFadeOutRect ); + + if( pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() ) + { + Invalidate( aFadeInRect ); + Invalidate( aFadeOutRect ); + } + } + } + return Window::PreNotify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Paint( const Rectangle& ) +{ + if ( mnWinStyle & WB_BORDER ) + ImplDrawBorder( this ); + + ImplDrawBorderLine( this ); + ImplDrawFadeOut( TRUE ); + ImplDrawFadeIn( TRUE ); + ImplDrawAutoHide( TRUE ); + + // FrameSet-Hintergruende zeichnen + ImplDrawBack( this, mpMainSet ); + + // Splitter zeichnen + if ( !(mnWinStyle & WB_NOSPLITDRAW) ) + ImplDrawSplit( this, mpMainSet, mbHorz, !mbBottomRight ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Move() +{ + DockingWindow::Move(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Resize() +{ + Size aSize = GetOutputSizePixel(); + mnDX = aSize.Width(); + mnDY = aSize.Height(); + + ImplUpdate(); + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + // no keyboard help for splitwin + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) && !rHEvt.KeyboardActivated() ) + { + Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() ); + Rectangle aHelpRect; + USHORT nHelpResId = 0; + + ImplGetAutoHideRect( aHelpRect, TRUE ); + if ( aHelpRect.IsInside( aMousePosPixel ) ) + { + if ( mbAutoHideIn ) + nHelpResId = SV_HELPTEXT_SPLITFIXED; + else + nHelpResId = SV_HELPTEXT_SPLITFLOATING; + } + else + { + ImplGetFadeInRect( aHelpRect, TRUE ); + if ( aHelpRect.IsInside( aMousePosPixel ) ) + nHelpResId = SV_HELPTEXT_FADEIN; + else + { + ImplGetFadeOutRect( aHelpRect, TRUE ); + if ( aHelpRect.IsInside( aMousePosPixel ) ) + nHelpResId = SV_HELPTEXT_FADEOUT; + } + } + + // Rechteck ermitteln + if ( nHelpResId ) + { + Point aPt = OutputToScreenPixel( aHelpRect.TopLeft() ); + aHelpRect.Left() = aPt.X(); + aHelpRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aHelpRect.BottomRight() ); + aHelpRect.Right() = aPt.X(); + aHelpRect.Bottom() = aPt.Y(); + + // Text ermitteln und anzeigen + XubString aStr; + ResMgr* pResMgr = ImplGetResMgr(); + if( pResMgr ) + aStr = XubString( ResId( nHelpResId, *pResMgr ) ); + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aStr ); + else + Help::ShowQuickHelp( this, aHelpRect, aStr ); + return; + } + } + + DockingWindow::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_INITSHOW ) + { + if ( IsUpdateMode() ) + ImplCalcLayout(); + } + else if ( nType == STATE_CHANGE_UPDATEMODE ) + { + if ( IsUpdateMode() && IsReallyShown() ) + ImplCalcLayout(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } + + DockingWindow::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } + else + DockingWindow::DataChanged( rDCEvt ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::InsertItem( USHORT nId, Window* pWindow, long nSize, + USHORT nPos, USHORT nSetId, + SplitWindowItemBits nBits ) +{ +#ifdef DBG_UTIL + USHORT nDbgDummy; + DBG_ASSERT( ImplFindSet( mpMainSet, nSetId ), "SplitWindow::InsertItem() - Set not exists" ); + DBG_ASSERT( !ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::InsertItem() - Id already exists" ); +#endif + + // Size has to be at least 1. + if ( nSize < 1 ) + nSize = 1; + + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + ImplSplitSet* pNewSet; + ImplSplitItem* pItem; + + // Make room for the new item. + if ( nPos > pSet->mnItems ) + nPos = pSet->mnItems; + ImplSplitItem* pNewItems = new ImplSplitItem[pSet->mnItems+1]; + if ( nPos ) + memcpy( pNewItems, pSet->mpItems, sizeof( ImplSplitItem )*nPos ); + if ( nPos < pSet->mnItems ) + memcpy( pNewItems+nPos+1, pSet->mpItems+nPos, sizeof( ImplSplitItem )*(pSet->mnItems-nPos) ); + delete[] pSet->mpItems; + pSet->mpItems = pNewItems; + pSet->mnItems++; + pSet->mbCalcPix = TRUE; + + // Create and initialize item. + pItem = &(pSet->mpItems[nPos]); + memset( pItem, 0, sizeof( ImplSplitItem ) ); + pItem->mnSize = nSize; + pItem->mnId = nId; + pItem->mnBits = nBits; + pItem->mnMinSize=-1; + pItem->mnMaxSize=-1; + + if ( pWindow ) + { + pItem->mpWindow = pWindow; + pItem->mpOrgParent = pWindow->GetParent(); + + // Attach window to SplitWindow. + pWindow->Hide(); + pWindow->SetParent( this ); + } + else + { + pNewSet = new ImplSplitSet; + pNewSet->mpItems = NULL; + pNewSet->mpWallpaper = NULL; + pNewSet->mpBitmap = NULL; + pNewSet->mnLastSize = 0; + pNewSet->mnItems = 0; + pNewSet->mnId = nId; + pNewSet->mnSplitSize = pSet->mnSplitSize; + pNewSet->mbCalcPix = TRUE; + + pItem->mpSet = pNewSet; + } + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::InsertItem( USHORT nId, long nSize, + USHORT nPos, USHORT nSetId, + SplitWindowItemBits nBits ) +{ + InsertItem( nId, NULL, nSize, nPos, nSetId, nBits ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::MoveItem( USHORT nId, USHORT nNewPos, USHORT nNewSetId ) +{ +#ifdef DBG_UTIL + USHORT nDbgDummy; + DBG_ASSERT( ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::MoveItem() - Id not found" ); + DBG_ASSERT( ImplFindSet( mpMainSet, nNewSetId ), "SplitWindow::MoveItem() - Set not exists" ); +#endif + + USHORT nPos; + ImplSplitSet* pNewSet = ImplFindSet( mpMainSet, nNewSetId ); + ImplSplitSet* pSet = ImplFindItem( mpMainSet, nId, nPos ); + ImplSplitItem aTempItem; + + if ( pNewSet == pSet ) + { + if ( nNewPos >= pNewSet->mnItems ) + nNewPos = pNewSet->mnItems-1; + if ( nPos != nNewPos ) + { + memcpy( &aTempItem, &(pSet->mpItems[nPos]), sizeof( aTempItem ) ); + if ( nPos < nNewPos ) + { + memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1, + (nNewPos-nPos)*sizeof( ImplSplitItem ) ); + } + else + { + memmove( pSet->mpItems+nNewPos+1, pSet->mpItems+nNewPos, + (nPos-nNewPos)*sizeof( ImplSplitItem ) ); + } + memcpy( &(pSet->mpItems[nNewPos]), &aTempItem, sizeof( aTempItem ) ); + + ImplUpdate(); + } + } + else + { + if ( nNewPos >= pNewSet->mnItems ) + nNewPos = pNewSet->mnItems; + memcpy( &aTempItem, &(pSet->mpItems[nPos]), sizeof( aTempItem ) ); + pSet->mnItems--; + pSet->mbCalcPix = TRUE; + if ( pSet->mnItems ) + { + memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1, + (pSet->mnItems-nPos)*sizeof( ImplSplitItem ) ); + } + else + { + delete[] pSet->mpItems; + pSet->mpItems = NULL; + } + ImplSplitItem* pNewItems = new ImplSplitItem[pNewSet->mnItems+1]; + if ( nNewPos ) + memcpy( pNewItems, pNewSet->mpItems, sizeof( ImplSplitItem )*nNewPos ); + if ( nNewPos < pNewSet->mnItems ) + { + memcpy( pNewItems+nNewPos+1, pNewSet->mpItems+nNewPos, + sizeof( ImplSplitItem )*(pNewSet->mnItems-nNewPos) ); + } + delete[] pNewSet->mpItems; + pNewSet->mpItems = pNewItems; + pNewSet->mnItems++; + pNewSet->mbCalcPix = TRUE; + memcpy( &(pNewSet->mpItems[nNewPos]), &aTempItem, sizeof( aTempItem ) ); + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::RemoveItem( USHORT nId, BOOL bHide ) +{ +#ifdef DBG_UTIL + USHORT nDbgDummy; + DBG_ASSERT( ImplFindItem( mpMainSet, nId, nDbgDummy ), "SplitWindow::RemoveItem() - Id not found" ); +#endif + + // Set suchen + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpMainSet, nId, nPos ); + ImplSplitItem* pItem = &(pSet->mpItems[nPos]); + Window* pWindow = pItem->mpWindow; + Window* pOrgParent = pItem->mpOrgParent; + + // Evt. Set loeschen + if ( !pWindow ) + ImplDeleteSet( pItem->mpSet ); + + // Item entfernen + pSet->mnItems--; + pSet->mbCalcPix = TRUE; + if ( pSet->mnItems ) + { + memmove( pSet->mpItems+nPos, pSet->mpItems+nPos+1, + (pSet->mnItems-nPos)*sizeof( ImplSplitItem ) ); + } + else + { + delete[] pSet->mpItems; + pSet->mpItems = NULL; + } + + ImplUpdate(); + + // Window erst hier loeschen, um weniger Paints zu haben + if ( pWindow ) + { + // Fenster wieder herstellen + if ( bHide || (pOrgParent != this) ) + { + pWindow->Hide(); + pWindow->SetParent( pOrgParent ); + } + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::Clear() +{ + // Alle Sets loeschen + ImplDeleteSet( mpMainSet ); + + // Main-Set wieder anlegen + mpMainSet = new ImplSplitSet; + mpMainSet->mpItems = NULL; + mpMainSet->mpWallpaper = NULL; + mpMainSet->mpBitmap = NULL; + mpMainSet->mnLastSize = 0; + mpMainSet->mnItems = 0; + mpMainSet->mnId = 0; + mpMainSet->mnSplitSize = SPLITWIN_SPLITSIZE; + mpMainSet->mbCalcPix = TRUE; + if ( mnWinStyle & WB_NOSPLITDRAW ) + mpMainSet->mnSplitSize -= 2; + mpBaseSet = mpMainSet; + + // Und neu invalidieren + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetBaseSet( USHORT nSetId ) +{ + mpBaseSet = ImplFindSet( mpMainSet, nSetId ); +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetBaseSet() const +{ + return mpBaseSet->mnId; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetSplitSize( USHORT nSetId, long nSplitSize, + BOOL bWithChilds ) +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + if ( pSet ) + { + if ( bWithChilds ) + ImplSetSplitSize( pSet, nSplitSize ); + else + pSet->mnSplitSize = nSplitSize; + } + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +long SplitWindow::GetSplitSize( USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + if ( pSet ) + return pSet->mnSplitSize; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetItemBackground( USHORT nSetId ) +{ + Wallpaper aWall; + SetItemBackground( nSetId, aWall ); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetItemBackground( USHORT nSetId, const Wallpaper& rWallpaper ) +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + + if ( pSet ) + { + BOOL bUpdate = TRUE; + + if ( rWallpaper.GetStyle() == WALLPAPER_NULL ) + { + if ( pSet->mpWallpaper ) + { + delete pSet->mpWallpaper; + pSet->mpWallpaper = NULL; + } + else + bUpdate = FALSE; + } + else + { + // Ab jetzt muss immer invalidiert werden + mbInvalidate = TRUE; + + if ( !pSet->mpWallpaper ) + pSet->mpWallpaper = new Wallpaper( rWallpaper ); + else + *(pSet->mpWallpaper) = rWallpaper; + } + + // Beim MainSet koennen wir den Background umsetzen + if ( pSet == mpMainSet ) + ImplInitSettings(); + + if ( bUpdate ) + ImplUpdateSet( pSet ); + } +} + +// ----------------------------------------------------------------------- + +Wallpaper SplitWindow::GetItemBackground( USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + + if ( pSet && pSet->mpWallpaper ) + return *(pSet->mpWallpaper); + else + { + Wallpaper aWall; + return aWall; + } +} + +// ----------------------------------------------------------------------- + +BOOL SplitWindow::IsItemBackground( USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + + if ( pSet && pSet->mpWallpaper ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetItemBitmap( USHORT nSetId, const Bitmap& rBitmap ) +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + + if ( pSet ) + { + BOOL bUpdate = TRUE; + + if ( !rBitmap ) + { + if ( pSet->mpBitmap ) + { + delete pSet->mpBitmap; + pSet->mpBitmap = NULL; + } + else + bUpdate = FALSE; + } + else + { + // Ab jetzt muss immer invalidiert werden + mbInvalidate = TRUE; + + if ( !pSet->mpBitmap ) + pSet->mpBitmap = new Bitmap( rBitmap ); + else + *(pSet->mpBitmap) = rBitmap; + } + + // Beim MainSet koennen wir den Background umsetzen + if ( pSet == mpMainSet ) + ImplInitSettings(); + + if ( bUpdate ) + ImplUpdateSet( pSet ); + } +} + +// ----------------------------------------------------------------------- + +Bitmap SplitWindow::GetItemBitmap( USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpMainSet, nSetId ); + + if ( pSet && pSet->mpBitmap ) + return *(pSet->mpBitmap); + else + { + Bitmap aBitmap; + return aBitmap; + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SplitItem( USHORT nId, long nNewSize, + BOOL bPropSmall, BOOL bPropGreat ) +{ + USHORT nItems; + USHORT nPos; + USHORT nMin; + USHORT nMax; + USHORT i; + USHORT n; + long nDelta; + long nTempDelta; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + ImplSplitItem* pItems; + + if ( !pSet ) + return; + + nItems = pSet->mnItems; + pItems = pSet->mpItems; + + // When there is an explicit minimum or maximum size then move nNewSize + // into that range (when it is not yet already in it.) + nNewSize = ValidateSize(nNewSize, pItems[nPos]); + + if ( mbCalc ) + { + pItems[nPos].mnSize = nNewSize; + return; + } + + nDelta = nNewSize-pItems[nPos].mnPixSize; + if ( !nDelta ) + return; + + // Bereich berechnen, der beim Splitten betroffen sein kann + nMin = 0; + nMax = nItems; + for ( i = 0; i < nItems; i++ ) + { + if ( pItems[i].mbFixed ) + { + if ( i < nPos ) + nMin = i+1; + else + nMax = i; + } + } + + // Wenn das Fenster sizeable ist, wird das TopSet anders behandelt + BOOL bSmall = TRUE; + BOOL bGreat = TRUE; + if ( (pSet == mpMainSet) && (mnWinStyle & WB_SIZEABLE) ) + { + if ( nPos < pSet->mnItems-1 ) + { + if ( !((bPropSmall && bPropGreat) || + ((nDelta > 0) && bPropSmall) || + ((nDelta < 0) && bPropGreat)) ) + { + if ( nDelta < 0 ) + bGreat = FALSE; + else + bSmall = FALSE; + } + } + else + { + if ( nDelta < 0 ) + bGreat = FALSE; + else + bSmall = FALSE; + } + } + else if ( nPos >= nMax ) + { + bSmall = FALSE; + bGreat = FALSE; + } + else if ( nPos && (nPos >= pSet->mnItems-1) ) + { + nPos--; + nDelta *= -1; + BOOL bTemp = bPropSmall; + bPropSmall = bPropGreat; + bPropGreat = bTemp; + } + + // Jetzt die Fenster splitten + if ( nDelta < 0 ) + { + if ( bGreat ) + { + if ( bPropGreat ) + { + nTempDelta = nDelta; + do + { + n = nPos+1; + do + { + if ( nTempDelta ) + { + pItems[n].mnPixSize++; + nTempDelta++; + } + n++; + } + while ( n < nMax ); + } + while ( nTempDelta ); + } + else + pItems[nPos+1].mnPixSize -= nDelta; + } + + if ( bSmall ) + { + if ( bPropSmall ) + { + do + { + n = nPos+1; + do + { + if ( nDelta && pItems[n-1].mnPixSize ) + { + pItems[n-1].mnPixSize--; + nDelta++; + } + + n--; + } + while ( n > nMin ); + } + while ( nDelta ); + } + else + { + n = nPos+1; + do + { + if ( pItems[n-1].mnPixSize+nDelta < 0 ) + { + nDelta += pItems[n-1].mnPixSize; + pItems[n-1].mnPixSize = 0; + } + else + { + pItems[n-1].mnPixSize += nDelta; + break; + } + n--; + } + while ( n > nMin ); + } + } + } + else + { + if ( bGreat ) + { + if ( bPropGreat ) + { + nTempDelta = nDelta; + do + { + n = nPos+1; + do + { + if ( nTempDelta ) + { + pItems[n-1].mnPixSize++; + nTempDelta--; + } + n--; + } + while ( n > nMin ); + } + while ( nTempDelta ); + } + else + pItems[nPos].mnPixSize += nDelta; + } + + if ( bSmall ) + { + if ( bPropSmall ) + { + do + { + n = nPos+1; + do + { + if ( nDelta && pItems[n].mnPixSize ) + { + pItems[n].mnPixSize--; + nDelta--; + } + + n++; + } + while ( n < nMax ); + } + while ( nDelta ); + } + else + { + n = nPos+1; + do + { + if ( pItems[n].mnPixSize-nDelta < 0 ) + { + nDelta -= pItems[n].mnPixSize; + pItems[n].mnPixSize = 0; + } + else + { + pItems[n].mnPixSize -= nDelta; + break; + } + n++; + } + while ( n < nMax ); + } + } + } + + // Original-Groessen updaten + ImplCalcLogSize( pItems, nItems ); + + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetItemSize( USHORT nId, long nNewSize ) +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + ImplSplitItem* pItem; + + if ( !pSet ) + return; + + // Testen, ob sich Groesse aendert + pItem = &(pSet->mpItems[nPos]); + if ( pItem->mnSize != nNewSize ) + { + // Neue Groesse setzen und neu durchrechnen + pItem->mnSize = nNewSize; + pSet->mbCalcPix = TRUE; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +long SplitWindow::GetItemSize( USHORT nId ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + return pSet->mpItems[nPos].mnSize; + else + return 0; +} + +// ----------------------------------------------------------------------- + +long SplitWindow::GetItemSize( USHORT nId, SplitWindowItemBits nBits ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + { + if ( nBits == pSet->mpItems[nPos].mnBits ) + return pSet->mpItems[nPos].mnSize; + else + { + ((SplitWindow*)this)->ImplCalcLayout(); + + long nRelSize = 0; + long nPerSize = 0; + ImplSplitItem* pItems; + USHORT nItems; + SplitWindowItemBits nTempBits; + USHORT i; + nItems = pSet->mnItems; + pItems = pSet->mpItems; + for ( i = 0; i < nItems; i++ ) + { + if ( i == nPos ) + nTempBits = nBits; + else + nTempBits = pItems[i].mnBits; + if ( nTempBits & SWIB_RELATIVESIZE ) + nRelSize += pItems[i].mnPixSize; + else if ( nTempBits & SWIB_PERCENTSIZE ) + nPerSize += pItems[i].mnPixSize; + } + nPerSize += nRelSize; + if ( nBits & SWIB_RELATIVESIZE ) + { + if ( nRelSize ) + return (pItems[nPos].mnPixSize+(nRelSize/2))/nRelSize; + else + return 1; + } + else if ( nBits & SWIB_PERCENTSIZE ) + { + if ( nPerSize ) + return (pItems[nPos].mnPixSize*100)/nPerSize; + else + return 1; + } + else + return pItems[nPos].mnPixSize; + } + } + else + return 0; +} + + + + +void SplitWindow::SetItemSizeRange (USHORT nId, const Range aRange) +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem(mpBaseSet, nId, nPos); + + if (pSet != NULL) + { + pSet->mpItems[nPos].mnMinSize = aRange.Min(); + pSet->mpItems[nPos].mnMaxSize = aRange.Max(); + } +} + + + + +Range SplitWindow::GetItemSizeRange (USHORT nId) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem(mpBaseSet, nId, nPos); + + if (pSet != NULL) + return Range (pSet->mpItems[nPos].mnMinSize, pSet->mpItems[nPos].mnMaxSize); + else + return Range(-1,-1); +} + + +// ----------------------------------------------------------------------- + +void SplitWindow::SetItemBits( USHORT nId, SplitWindowItemBits nNewBits ) +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + ImplSplitItem* pItem; + + if ( !pSet ) + return; + + pItem = &(pSet->mpItems[nPos]); + if ( pItem->mpWindow ) + nNewBits &= ~SWIB_COLSET; + + if ( pItem->mnBits != nNewBits ) + { + // Neue Bits setzen und neu durchrechnen + pItem->mnBits = nNewBits; + pSet->mbCalcPix = TRUE; + ImplUpdate(); + } +} + +// ----------------------------------------------------------------------- + +SplitWindowItemBits SplitWindow::GetItemBits( USHORT nId ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + return pSet->mpItems[nPos].mnBits; + else + return 0; +} + +// ----------------------------------------------------------------------- + +Window* SplitWindow::GetItemWindow( USHORT nId ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + return pSet->mpItems[nPos].mpWindow; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetSet( USHORT nId ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + return pSet->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +BOOL SplitWindow::GetSet( USHORT nId, USHORT& rSetId, USHORT& rPos ) const +{ + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, rPos ); + if ( pSet ) + { + rSetId = pSet->mnId; + return TRUE; + } + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL SplitWindow::IsItemValid( USHORT nId ) const +{ + USHORT nPos; + ImplSplitSet* pSet = ImplFindItem( mpBaseSet, nId, nPos ); + + if ( pSet ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetItemId( Window* pWindow ) const +{ + return ImplFindItem( mpBaseSet, pWindow ); +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetItemId( const Point& rPos ) const +{ + return ImplFindItem( mpBaseSet, rPos, mbHorz, !mbBottomRight ); +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetItemPos( USHORT nId, USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId ); + USHORT nPos = SPLITWINDOW_ITEM_NOTFOUND; + + if ( pSet ) + { + for ( USHORT i = 0; i < pSet->mnItems; i++ ) + { + if ( pSet->mpItems[i].mnId == nId ) + { + nPos = i; + break; + } + } + } + + return nPos; +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetItemId( USHORT nPos, USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId ); + if ( pSet && (nPos < pSet->mnItems) ) + return pSet->mpItems[nPos].mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT SplitWindow::GetItemCount( USHORT nSetId ) const +{ + ImplSplitSet* pSet = ImplFindSet( mpBaseSet, nSetId ); + if ( pSet ) + return pSet->mnItems; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ImplNewAlign() +{ + if ( mbNoAlign ) + { + mbHorz = FALSE; + mbBottomRight = FALSE; + } + else if ( meAlign == WINDOWALIGN_TOP ) + { + mbHorz = TRUE; + mbBottomRight = FALSE; + } + else if ( meAlign == WINDOWALIGN_BOTTOM ) + { + mbHorz = TRUE; + mbBottomRight = TRUE; + } + else if ( meAlign == WINDOWALIGN_LEFT ) + { + mbHorz = FALSE; + mbBottomRight = FALSE; + } + else if ( meAlign == WINDOWALIGN_RIGHT ) + { + mbHorz = FALSE; + mbBottomRight = TRUE; + } + + if ( mnWinStyle & WB_BORDER ) + { + ImplCalcBorder( meAlign, mbNoAlign, mnLeftBorder, mnTopBorder, + mnRightBorder, mnBottomBorder ); + } + + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetNoAlign( BOOL bNoAlign ) +{ + bNoAlign = bNoAlign != 0; + if ( mbNoAlign != bNoAlign ) + { + mbNoAlign = bNoAlign; + ImplNewAlign(); + } +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetAlign( WindowAlign eNewAlign ) +{ + if ( meAlign != eNewAlign ) + { + meAlign = eNewAlign; + ImplNewAlign(); + } +} + +// ----------------------------------------------------------------------- + +Size SplitWindow::CalcWindowSizePixel( const Size& rSize, WindowAlign eAlign, + WinBits nWinStyle, BOOL bExtra ) +{ + long nLeft; + long nTop; + long nRight; + long nBottom; + Size aSize = rSize; + + ImplCalcBorder( eAlign, FALSE, nLeft, nTop, nRight, nBottom ); + aSize.Width() += nLeft+nRight; + aSize.Height() += nTop+nBottom; + + if ( nWinStyle & WB_SIZEABLE ) + { + if ( (eAlign == WINDOWALIGN_TOP) || (eAlign == WINDOWALIGN_BOTTOM) ) + { + aSize.Height() += SPLITWIN_SPLITSIZE-2; + if ( bExtra ) + aSize.Height() += SPLITWIN_SPLITSIZEEXLN; + } + else + { + aSize.Width() += SPLITWIN_SPLITSIZE-2; + if ( bExtra ) + aSize.Width() += SPLITWIN_SPLITSIZEEXLN; + } + } + + return aSize; +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ShowAutoHideButton( BOOL bShow ) +{ + mbAutoHide = bShow; + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ShowFadeInHideButton( BOOL bShow ) +{ + mbFadeIn = bShow; + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::ShowFadeOutButton( BOOL bShow ) +{ + mbFadeOut = bShow; + ImplUpdate(); +} + +// ----------------------------------------------------------------------- + +void SplitWindow::SetAutoHideState( BOOL bAutoHide ) +{ + mbAutoHideIn = bAutoHide; + if ( IsReallyVisible() ) + { + Rectangle aRect; + ImplGetAutoHideRect( aRect ); + Invalidate( aRect ); + } +} + +// ----------------------------------------------------------------------- + +long SplitWindow::GetFadeInSize() const +{ + long n = 0; + + if ( mbHorz ) + n = mnTopBorder+mnBottomBorder; + else + n = mnLeftBorder+mnRightBorder; + + return n+SPLITWIN_SPLITSIZE+SPLITWIN_SPLITSIZEEX-2; +} + +// ----------------------------------------------------------------------- + +Rectangle SplitWindow::GetAutoHideRect() const +{ + Rectangle aRect; + ImplGetAutoHideRect( aRect, TRUE ); + return aRect; +} + +// ----------------------------------------------------------------------- + +Rectangle SplitWindow::GetFadeInRect() const +{ + Rectangle aRect; + ImplGetFadeInRect( aRect, TRUE ); + return aRect; +} + +// ----------------------------------------------------------------------- + +Rectangle SplitWindow::GetFadeOutRect() const +{ + Rectangle aRect; + ImplGetFadeOutRect( aRect, TRUE ); + return aRect; +} diff --git a/vcl/source/window/status.cxx b/vcl/source/window/status.cxx new file mode 100644 index 000000000000..36f27b1ceee7 --- /dev/null +++ b/vcl/source/window/status.cxx @@ -0,0 +1,1802 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/list.hxx> +#include <tools/debug.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/event.hxx> +#include <vcl/decoview.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> +#include <vcl/status.hxx> +#include <vcl/virdev.hxx> +#include <vcl/window.h> + +// ======================================================================= + +#define STATUSBAR_OFFSET_X STATUSBAR_OFFSET +#define STATUSBAR_OFFSET_Y 2 +#define STATUSBAR_OFFSET_TEXTY 3 + +#define STATUSBAR_PRGS_OFFSET 3 +#define STATUSBAR_PRGS_COUNT 100 +#define STATUSBAR_PRGS_MIN 5 + +// ----------------------------------------------------------------------- + +class StatusBar::ImplData +{ +public: + ImplData(); + ~ImplData(); + + VirtualDevice* mpVirDev; + long mnItemBorderWidth; + bool mbTopBorder:1; + bool mbDrawItemFrames:1; +}; + +StatusBar::ImplData::ImplData() +{ + mpVirDev = NULL; + mbTopBorder = false; + mbDrawItemFrames = false; + mnItemBorderWidth = 0; +} + +StatusBar::ImplData::~ImplData() +{ +} + +struct ImplStatusItem +{ + USHORT mnId; + StatusBarItemBits mnBits; + long mnWidth; + long mnOffset; + long mnExtraWidth; + long mnX; + XubString maText; + XubString maHelpText; + XubString maQuickHelpText; + rtl::OString maHelpId; + void* mpUserData; + BOOL mbVisible; + XubString maAccessibleName; + XubString maCommand; +}; + +DECLARE_LIST( ImplStatusItemList, ImplStatusItem* ) + +// ======================================================================= + +inline long ImplCalcProgessWidth( USHORT nMax, long nSize ) +{ + return ((nMax*(nSize+(nSize/2)))-(nSize/2)+(STATUSBAR_PRGS_OFFSET*2)); +} + +// ----------------------------------------------------------------------- + +static Point ImplGetItemTextPos( const Size& rRectSize, const Size& rTextSize, + USHORT nStyle ) +{ + long nX; + long nY; + long delta = (rTextSize.Height()/4) + 1; + if( delta + rTextSize.Width() > rRectSize.Width() ) + delta = 0; + + if ( nStyle & SIB_LEFT ) + nX = delta; + else if ( nStyle & SIB_RIGHT ) + nX = rRectSize.Width()-rTextSize.Width()-delta; + else // SIB_CENTER + nX = (rRectSize.Width()-rTextSize.Width())/2; + nY = (rRectSize.Height()-rTextSize.Height())/2 + 1; + return Point( nX, nY ); +} + +// ----------------------------------------------------------------------- + +BOOL StatusBar::ImplIsItemUpdate() +{ + if ( !mbProgressMode && mbVisibleItems && IsReallyVisible() && IsUpdateMode() ) + return TRUE; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplInit( Window* pParent, WinBits nStyle ) +{ + mpImplData = new ImplData; + + // Default ist RightAlign + if ( !(nStyle & (WB_LEFT | WB_RIGHT)) ) + nStyle |= WB_RIGHT; + + Window::ImplInit( pParent, nStyle & ~WB_BORDER, NULL ); + + // WinBits merken + mpItemList = new ImplStatusItemList; + mpImplData->mpVirDev = new VirtualDevice( *this ); + mnCurItemId = 0; + mbFormat = TRUE; + mbVisibleItems = TRUE; + mbProgressMode = FALSE; + mbInUserDraw = FALSE; + mbBottomBorder = FALSE; + mnItemsWidth = STATUSBAR_OFFSET_X; + mnDX = 0; + mnDY = 0; + mnCalcHeight = 0; + mnItemY = STATUSBAR_OFFSET_Y; + mnTextY = STATUSBAR_OFFSET_TEXTY; + + ImplInitSettings( TRUE, TRUE, TRUE ); + SetLineColor(); + + SetOutputSizePixel( CalcWindowSizePixel() ); +} + +// ----------------------------------------------------------------------- + +StatusBar::StatusBar( Window* pParent, WinBits nStyle ) : + Window( WINDOW_STATUSBAR ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +StatusBar::StatusBar( Window* pParent, const ResId& rResId ) : + Window( WINDOW_STATUSBAR ) +{ + rResId.SetRT( RSC_STATUSBAR ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +StatusBar::~StatusBar() +{ + // Alle Items loeschen + ImplStatusItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + delete mpItemList; + + // VirtualDevice loeschen + delete mpImplData->mpVirDev; + + delete mpImplData; +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aFont = rStyleSettings.GetToolFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } + + if ( bForeground || bFont ) + { + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else if ( GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetButtonTextColor(); + else + aColor = rStyleSettings.GetWindowTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + + mpImplData->mpVirDev->SetFont( GetFont() ); + mpImplData->mpVirDev->SetTextColor( GetTextColor() ); + mpImplData->mpVirDev->SetTextAlign( GetTextAlign() ); + mpImplData->mpVirDev->SetTextFillColor(); + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + aColor = GetControlBackground(); + else if ( GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + SetBackground( aColor ); + mpImplData->mpVirDev->SetBackground( GetBackground() ); + + // NWF background + if( ! IsControlBackground() && + IsNativeControlSupported( CTRL_WINDOW_BACKGROUND, PART_BACKGROUND_WINDOW ) ) + { + ImplGetWindowImpl()->mnNativeBackground = PART_BACKGROUND_WINDOW; + EnableChildTransparentMode( TRUE ); + } + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplFormat() +{ + ImplStatusItem* pItem; + long nExtraWidth; + long nExtraWidth2; + long nX; + USHORT nAutoSizeItems = 0; + + // Breiten zusammenrechnen + mnItemsWidth = STATUSBAR_OFFSET_X; + long nOffset = 0; + pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mbVisible ) + { + if ( pItem->mnBits & SIB_AUTOSIZE ) + nAutoSizeItems++; + + mnItemsWidth += pItem->mnWidth + nOffset; + nOffset = pItem->mnOffset; + } + + pItem = mpItemList->Next(); + } + + if ( GetStyle() & WB_RIGHT ) + { + // Bei rechtsbuendiger Ausrichtung wird kein AutoSize ausgewertet, + // da wir links den Text anzeigen, der mit SetText gesetzt wird + nX = mnDX - mnItemsWidth; + nExtraWidth = 0; + nExtraWidth2 = 0; + } + else + { + mnItemsWidth += STATUSBAR_OFFSET_X; + + // Bei linksbuendiger Ausrichtung muessen wir gegebenenfalls noch + // AutoSize auswerten + if ( nAutoSizeItems && (mnDX > (mnItemsWidth - STATUSBAR_OFFSET)) ) + { + nExtraWidth = (mnDX - mnItemsWidth - 1) / nAutoSizeItems; + nExtraWidth2 = (mnDX - mnItemsWidth - 1) % nAutoSizeItems; + } + else + { + nExtraWidth = 0; + nExtraWidth2 = 0; + } + nX = STATUSBAR_OFFSET_X; + if( ImplHasMirroredGraphics() && IsRTLEnabled() ) + nX += ImplGetSVData()->maNWFData.mnStatusBarLowerRightOffset; + } + + pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mbVisible ) + { + if ( pItem->mnBits & SIB_AUTOSIZE ) + { + pItem->mnExtraWidth = nExtraWidth; + if ( nExtraWidth2 ) + { + pItem->mnExtraWidth++; + nExtraWidth2--; + } + } + else + pItem->mnExtraWidth = 0; + + pItem->mnX = nX; + nX += pItem->mnWidth + pItem->mnExtraWidth + pItem->mnOffset; + } + + pItem = mpItemList->Next(); + } + + mbFormat = FALSE; +} + +// ----------------------------------------------------------------------- + +Rectangle StatusBar::ImplGetItemRectPos( USHORT nPos ) const +{ + Rectangle aRect; + ImplStatusItem* pItem; + pItem = mpItemList->GetObject( nPos ); + if ( pItem ) + { + if ( pItem->mbVisible ) + { + aRect.Left() = pItem->mnX; + aRect.Right() = aRect.Left() + pItem->mnWidth + pItem->mnExtraWidth; + aRect.Top() = mnItemY; + aRect.Bottom() = mnCalcHeight - STATUSBAR_OFFSET_Y; + if( IsTopBorder() ) + aRect.Bottom()+=2; + } + } + + return aRect; +} + +// ----------------------------------------------------------------------- + +USHORT StatusBar::ImplGetFirstVisiblePos() const +{ + ImplStatusItem* pItem; + + for( USHORT nPos = 0; nPos < mpItemList->Count(); nPos++ ) + { + pItem = mpItemList->GetObject( nPos ); + if ( pItem ) + { + if ( pItem->mbVisible ) + return nPos; + } + } + + return ~0; +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplDrawText( BOOL bOffScreen, long nOldTextWidth ) +{ + // Das ueberschreiben der Item-Box verhindern + Rectangle aTextRect; + aTextRect.Left() = STATUSBAR_OFFSET_X+1; + aTextRect.Top() = mnTextY; + if ( mbVisibleItems && (GetStyle() & WB_RIGHT) ) + aTextRect.Right() = mnDX - mnItemsWidth - 1; + else + aTextRect.Right() = mnDX - 1; + if ( aTextRect.Right() > aTextRect.Left() ) + { + // Position ermitteln + XubString aStr = GetText(); + USHORT nPos = aStr.Search( _LF ); + if ( nPos != STRING_NOTFOUND ) + aStr.Erase( nPos ); + + aTextRect.Bottom() = aTextRect.Top()+GetTextHeight()+1; + + if ( bOffScreen ) + { + long nMaxWidth = Max( nOldTextWidth, GetTextWidth( aStr ) ); + Size aVirDevSize( nMaxWidth, aTextRect.GetHeight() ); + mpImplData->mpVirDev->SetOutputSizePixel( aVirDevSize ); + Rectangle aTempRect = aTextRect; + aTempRect.SetPos( Point( 0, 0 ) ); + mpImplData->mpVirDev->DrawText( aTempRect, aStr, TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS ); + DrawOutDev( aTextRect.TopLeft(), aVirDevSize, Point(), aVirDevSize, *mpImplData->mpVirDev ); + } + else + DrawText( aTextRect, aStr, TEXT_DRAW_LEFT | TEXT_DRAW_TOP | TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS ); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplDrawItem( BOOL bOffScreen, USHORT nPos, BOOL bDrawText, BOOL bDrawFrame ) +{ + Rectangle aRect = ImplGetItemRectPos( nPos ); + + if ( aRect.IsEmpty() ) + return; + + // Ausgabebereich berechnen + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + long nW = mpImplData->mnItemBorderWidth + 1; + Rectangle aTextRect( aRect.Left()+nW, aRect.Top()+nW, + aRect.Right()-nW, aRect.Bottom()-nW ); + Size aTextRectSize( aTextRect.GetSize() ); + + if ( bOffScreen ) + mpImplData->mpVirDev->SetOutputSizePixel( aTextRectSize ); + else + { + Region aRegion( aTextRect ); + SetClipRegion( aRegion ); + } + + // Text ausgeben + if ( bDrawText ) + { + Size aTextSize( GetTextWidth( pItem->maText ), GetTextHeight() ); + Point aTextPos = ImplGetItemTextPos( aTextRectSize, aTextSize, pItem->mnBits ); + if ( bOffScreen ) + mpImplData->mpVirDev->DrawText( aTextPos, pItem->maText ); + else + { + aTextPos.X() += aTextRect.Left(); + aTextPos.Y() += aTextRect.Top(); + DrawText( aTextPos, pItem->maText ); + } + } + + // Gegebenenfalls auch DrawItem aufrufen + if ( pItem->mnBits & SIB_USERDRAW ) + { + if ( bOffScreen ) + { + mbInUserDraw = TRUE; + mpImplData->mpVirDev->EnableRTL( IsRTLEnabled() ); + UserDrawEvent aODEvt( mpImplData->mpVirDev, Rectangle( Point(), aTextRectSize ), pItem->mnId ); + UserDraw( aODEvt ); + mpImplData->mpVirDev->EnableRTL( FALSE ); + mbInUserDraw = FALSE; + } + else + { + UserDrawEvent aODEvt( this, aTextRect, pItem->mnId ); + UserDraw( aODEvt ); + } + } + + if ( bOffScreen ) + DrawOutDev( aTextRect.TopLeft(), aTextRectSize, Point(), aTextRectSize, *mpImplData->mpVirDev ); + else + SetClipRegion(); + + // Frame ausgeben + if ( bDrawFrame ) + { + if( mpImplData->mbDrawItemFrames ) + { + if( !(pItem->mnBits & SIB_FLAT) ) + { + USHORT nStyle; + + if ( pItem->mnBits & SIB_IN ) + nStyle = FRAME_DRAW_IN; + else + nStyle = FRAME_DRAW_OUT; + + DecorationView aDecoView( this ); + aDecoView.DrawFrame( aRect, nStyle ); + } + } + else if( nPos != ImplGetFirstVisiblePos() ) + { + // draw separator + Point aFrom( aRect.TopLeft() ); + aFrom.X()--; + aFrom.Y()++; + Point aTo( aRect.BottomLeft() ); + aTo.X()--; + aTo.Y()--; + + DecorationView aDecoView( this ); + aDecoView.DrawSeparator( aFrom, aTo ); + } + } + + if ( !ImplIsRecordLayout() ) + ImplCallEventListeners( VCLEVENT_STATUSBAR_DRAWITEM, (void*) sal_IntPtr(pItem->mnId) ); +} + +// ----------------------------------------------------------------------- + +void DrawProgress( Window* pWindow, const Point& rPos, + long nOffset, long nPrgsWidth, long nPrgsHeight, + USHORT nPercent1, USHORT nPercent2, USHORT nPercentCount, + const Rectangle& rFramePosSize + ) +{ + if( pWindow->IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + bool bNeedErase = ImplGetSVData()->maNWFData.mbProgressNeedsErase; + + long nFullWidth = (nPrgsWidth + nOffset) * (10000 / nPercentCount); + long nPerc = (nPercent2 > 10000) ? 10000 : nPercent2; + ImplControlValue aValue( nFullWidth * (long)nPerc / 10000 ); + Rectangle aDrawRect( rPos, Size( nFullWidth, nPrgsHeight ) ); + Rectangle aControlRegion( aDrawRect ); + if( bNeedErase ) + { + Window* pEraseWindow = pWindow; + while( pEraseWindow->IsPaintTransparent() && + ! pEraseWindow->ImplGetWindowImpl()->mbFrame ) + { + pEraseWindow = pEraseWindow->ImplGetWindowImpl()->mpParent; + } + if( pEraseWindow == pWindow ) + // restore background of pWindow + pEraseWindow->Erase( rFramePosSize ); + else + { + // restore transparent background + Point aTL( pWindow->OutputToAbsoluteScreenPixel( rFramePosSize.TopLeft() ) ); + aTL = pEraseWindow->AbsoluteScreenToOutputPixel( aTL ); + Rectangle aRect( aTL, rFramePosSize.GetSize() ); + pEraseWindow->Invalidate( aRect, INVALIDATE_NOCHILDREN | + INVALIDATE_NOCLIPCHILDREN | + INVALIDATE_TRANSPARENT ); + pEraseWindow->Update(); + } + pWindow->Push( PUSH_CLIPREGION ); + pWindow->IntersectClipRegion( rFramePosSize ); + } + BOOL bNativeOK = pWindow->DrawNativeControl( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString() ); + if( bNeedErase ) + pWindow->Pop(); + if( bNativeOK ) + { + pWindow->Flush(); + return; + } + } + + // Werte vorberechnen + USHORT nPerc1 = nPercent1 / nPercentCount; + USHORT nPerc2 = nPercent2 / nPercentCount; + + if ( nPerc1 > nPerc2 ) + { + // Support progress that can also decrease + + // Rechteck berechnen + long nDX = nPrgsWidth + nOffset; + long nLeft = rPos.X()+((nPerc1-1)*nDX); + Rectangle aRect( nLeft, rPos.Y(), nLeft+nPrgsWidth, rPos.Y()+nPrgsHeight ); + + do + { + pWindow->Erase( aRect ); + aRect.Left() -= nDX; + aRect.Right() -= nDX; + nPerc1--; + } + while ( nPerc1 > nPerc2 ); + + pWindow->Flush(); + } + else if ( nPerc1 < nPerc2 ) + { + // Percent-Rechtecke malen + // Wenn Percent2 ueber 100%, Werte anpassen + if ( nPercent2 > 10000 ) + { + nPerc2 = 10000 / nPercentCount; + if ( nPerc1 >= nPerc2 ) + nPerc1 = nPerc2-1; + } + + // Rechteck berechnen + long nDX = nPrgsWidth + nOffset; + long nLeft = rPos.X()+(nPerc1*nDX); + Rectangle aRect( nLeft, rPos.Y(), nLeft+nPrgsWidth, rPos.Y()+nPrgsHeight ); + + do + { + pWindow->DrawRect( aRect ); + aRect.Left() += nDX; + aRect.Right() += nDX; + nPerc1++; + } + while ( nPerc1 < nPerc2 ); + + // Bei mehr als 100%, lassen wir das Rechteck blinken + if ( nPercent2 > 10000 ) + { + // an/aus-Status festlegen + if ( ((nPercent2 / nPercentCount) & 0x01) == (nPercentCount & 0x01) ) + { + aRect.Left() -= nDX; + aRect.Right() -= nDX; + pWindow->Erase( aRect ); + } + } + + pWindow->Flush(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplDrawProgress( BOOL bPaint, + USHORT nPercent1, USHORT nPercent2 ) +{ + bool bNative = IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ); + // bPaint: draw text also, else only update progress + if ( bPaint ) + { + DrawText( maPrgsTxtPos, maPrgsTxt ); + if( ! bNative ) + { + DecorationView aDecoView( this ); + aDecoView.DrawFrame( maPrgsFrameRect, FRAME_DRAW_IN ); + } + } + + Point aPos( maPrgsFrameRect.Left()+STATUSBAR_PRGS_OFFSET, + maPrgsFrameRect.Top()+STATUSBAR_PRGS_OFFSET ); + long nPrgsHeight = mnPrgsSize; + if( bNative ) + { + aPos = maPrgsFrameRect.TopLeft(); + nPrgsHeight = maPrgsFrameRect.GetHeight(); + } + DrawProgress( this, aPos, mnPrgsSize/2, mnPrgsSize, nPrgsHeight, + nPercent1*100, nPercent2*100, mnPercentCount, maPrgsFrameRect ); +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplCalcProgressRect() +{ + // calculate text size + Size aPrgsTxtSize( GetTextWidth( maPrgsTxt ), GetTextHeight() ); + maPrgsTxtPos.X() = STATUSBAR_OFFSET_X+1; + + // calculate progress frame + maPrgsFrameRect.Left() = maPrgsTxtPos.X()+aPrgsTxtSize.Width()+STATUSBAR_OFFSET; + maPrgsFrameRect.Top() = mnItemY; + maPrgsFrameRect.Bottom() = mnCalcHeight - STATUSBAR_OFFSET_Y; + if( IsTopBorder() ) + maPrgsFrameRect.Bottom()+=2; + + // calculate size of progress rects + mnPrgsSize = maPrgsFrameRect.Bottom()-maPrgsFrameRect.Top()-(STATUSBAR_PRGS_OFFSET*2); + USHORT nMaxPercent = STATUSBAR_PRGS_COUNT; + + long nMaxWidth = mnDX-STATUSBAR_OFFSET-1; + + // make smaller if there are too many rects + while ( maPrgsFrameRect.Left()+ImplCalcProgessWidth( nMaxPercent, mnPrgsSize ) > nMaxWidth ) + { + nMaxPercent--; + if ( nMaxPercent <= STATUSBAR_PRGS_MIN ) + break; + } + maPrgsFrameRect.Right() = maPrgsFrameRect.Left() + ImplCalcProgessWidth( nMaxPercent, mnPrgsSize ); + + // save the divisor for later + mnPercentCount = 10000 / nMaxPercent; + BOOL bNativeOK = FALSE; + if( IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Rectangle aControlRegion( Rectangle( (const Point&)Point(), maPrgsFrameRect.GetSize() ) ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( (bNativeOK = GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) ) != FALSE ) + { + long nProgressHeight = aNativeControlRegion.GetHeight(); + if( nProgressHeight > maPrgsFrameRect.GetHeight() ) + { + long nDelta = nProgressHeight - maPrgsFrameRect.GetHeight(); + maPrgsFrameRect.Top() -= (nDelta - nDelta/2); + maPrgsFrameRect.Bottom() += nDelta/2; + } + maPrgsTxtPos.Y() = maPrgsFrameRect.Top() + (nProgressHeight - GetTextHeight())/2; + } + } + if( ! bNativeOK ) + maPrgsTxtPos.Y() = mnTextY; +} + +// ----------------------------------------------------------------------- + +void StatusBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // Nur bei linker Maustaste ToolBox ausloesen + if ( rMEvt.IsLeft() ) + { + if ( mbVisibleItems ) + { + Point aMousePos = rMEvt.GetPosPixel(); + USHORT i = 0; + + // Item suchen, das geklickt wurde + ImplStatusItem* pItem = mpItemList->First(); + while ( pItem ) + { + // Ist es dieses Item + if ( ImplGetItemRectPos( i ).IsInside( aMousePos ) ) + { + mnCurItemId = pItem->mnId; + if ( rMEvt.GetClicks() == 2 ) + DoubleClick(); + else + Click(); + mnCurItemId = 0; + + // Item wurde gefunden + return; + } + + i++; + pItem = mpItemList->Next(); + } + } + + // Kein Item, dann nur Click oder DoubleClick + if ( rMEvt.GetClicks() == 2 ) + DoubleClick(); + else + Click(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::Paint( const Rectangle& ) +{ + if ( mbFormat ) + ImplFormat(); + + USHORT nItemCount = (USHORT)mpItemList->Count(); + + if ( mbProgressMode ) + ImplDrawProgress( TRUE, 0, mnPercent ); + else + { + // Text zeichen + if ( !mbVisibleItems || (GetStyle() & WB_RIGHT) ) + ImplDrawText( FALSE, 0 ); + + // Items zeichnen + if ( mbVisibleItems ) + { + // Items zeichnen + for ( USHORT i = 0; i < nItemCount; i++ ) + ImplDrawItem( FALSE, i, TRUE, TRUE ); + } + } + + // draw borders + if( IsTopBorder() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( 0, 0 ), Point( mnDX-1, 0 ) ); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( 0, 1 ), Point( mnDX-1, 1 ) ); + } + + if ( IsBottomBorder() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetLineColor( rStyleSettings.GetShadowColor() ); + DrawLine( Point( 0, mnDY-2 ), Point( mnDX-1, mnDY-2 ) ); + SetLineColor( rStyleSettings.GetLightColor() ); + DrawLine( Point( 0, mnDY-1 ), Point( mnDX-1, mnDY-1 ) ); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::Move() +{ + Window::Move(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::Resize() +{ + // Breite und Hoehe abfragen und merken + Size aSize = GetOutputSizePixel(); + mnDX = aSize.Width() - ImplGetSVData()->maNWFData.mnStatusBarLowerRightOffset; + mnDY = aSize.Height(); + mnCalcHeight = mnDY; + // subtract border + if( IsTopBorder() ) + mnCalcHeight -= 2; + if ( IsBottomBorder() ) + mnCalcHeight -= 2; + + mnItemY = STATUSBAR_OFFSET_Y; + if( IsTopBorder() ) + mnItemY += 2; + mnTextY = (mnCalcHeight-GetTextHeight())/2; + if( IsTopBorder() ) + mnTextY += 2; + + // Formatierung neu ausloesen + mbFormat = TRUE; + + if ( mbProgressMode ) + ImplCalcProgressRect(); + + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::RequestHelp( const HelpEvent& rHEvt ) +{ + // no keyboard help in status bar + if( rHEvt.KeyboardActivated() ) + return; + + USHORT nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + + if ( nItemId ) + { + Rectangle aItemRect = GetItemRect( nItemId ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + { + XubString aStr = GetHelpText( nItemId ); + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); + return; + } + else if ( rHEvt.GetMode() & HELPMODE_QUICK ) + { + XubString aStr = GetQuickHelpText( nItemId ); + // Show quickhelp if available + if( aStr.Len() ) + { + Help::ShowQuickHelp( this, aItemRect, aStr ); + return; + } + aStr = GetItemText( nItemId ); + // show a quick help if item text doesn't fit + if ( GetTextWidth( aStr ) > aItemRect.GetWidth() ) + { + Help::ShowQuickHelp( this, aItemRect, aStr ); + return; + } + } + else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) + { + String aCommand = GetItemCommand( nItemId ); + rtl::OString aHelpId( GetHelpId( nItemId ) ); + + if ( aCommand.Len() || aHelpId.getLength() ) + { + // Wenn eine Hilfe existiert, dann ausloesen + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if ( aCommand.Len() ) + pHelp->Start( aCommand, this ); + else if ( aHelpId.getLength() ) + pHelp->Start( rtl::OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + return; + } + } + } + + Window::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +void StatusBar::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + ImplFormat(); + else if ( nType == STATE_CHANGE_UPDATEMODE ) + Invalidate(); + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + mbFormat = TRUE; + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_DISPLAY) || + (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + mbFormat = TRUE; + ImplInitSettings( TRUE, TRUE, TRUE ); + ImplStatusItem* pItem = mpItemList->First(); + long nFudge = GetTextHeight() / 4; + while ( pItem ) + { + long nWidth = GetTextWidth( pItem->maText ) + nFudge; + if( nWidth > pItem->mnWidth + STATUSBAR_OFFSET ) + pItem->mnWidth = nWidth + STATUSBAR_OFFSET; + pItem = mpItemList->Next(); + } + Size aSize = GetSizePixel(); + // do not disturb current width, since + // CalcWindowSizePixel calculates a minimum width + aSize.Height() = CalcWindowSizePixel().Height(); + SetSizePixel( aSize ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::Click() +{ + ImplCallEventListeners( VCLEVENT_STATUSBAR_CLICK ); + maClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void StatusBar::DoubleClick() +{ + ImplCallEventListeners( VCLEVENT_STATUSBAR_DOUBLECLICK ); + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void StatusBar::UserDraw( const UserDrawEvent& ) +{ +} + +// ----------------------------------------------------------------------- + +void StatusBar::InsertItem( USHORT nItemId, ULONG nWidth, + StatusBarItemBits nBits, + long nOffset, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "StatusBar::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == STATUSBAR_ITEM_NOTFOUND, + "StatusBar::InsertItem(): ItemId already exists" ); + + // IN und CENTER sind Default + if ( !(nBits & (SIB_IN | SIB_OUT | SIB_FLAT)) ) + nBits |= SIB_IN; + if ( !(nBits & (SIB_LEFT | SIB_RIGHT | SIB_CENTER)) ) + nBits |= SIB_CENTER; + + // Item anlegen + long nFudge = GetTextHeight()/4; + ImplStatusItem* pItem = new ImplStatusItem; + pItem->mnId = nItemId; + pItem->mnBits = nBits; + pItem->mnWidth = (long)nWidth+nFudge+STATUSBAR_OFFSET; + pItem->mnOffset = nOffset; + pItem->mpUserData = 0; + pItem->mbVisible = TRUE; + + // Item in die Liste einfuegen + mpItemList->Insert( pItem, nPos ); + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_ITEMADDED, (void*) sal_IntPtr(nItemId) ); +} + +// ----------------------------------------------------------------------- + +void StatusBar::RemoveItem( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->Remove( nPos ); + delete pItem; + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_ITEMREMOVED, (void*) sal_IntPtr(nItemId) ); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::ShowItem( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + if ( !pItem->mbVisible ) + { + pItem->mbVisible = TRUE; + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_SHOWITEM, (void*) sal_IntPtr(nItemId) ); + } + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::HideItem( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem->mbVisible ) + { + pItem->mbVisible = FALSE; + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_HIDEITEM, (void*) sal_IntPtr(nItemId) ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL StatusBar::IsItemVisible( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mbVisible; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void StatusBar::ShowItems() +{ + if ( !mbVisibleItems ) + { + mbVisibleItems = TRUE; + if ( !mbProgressMode ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_SHOWALLITEMS ); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::HideItems() +{ + if ( mbVisibleItems ) + { + mbVisibleItems = FALSE; + if ( !mbProgressMode ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_HIDEALLITEMS ); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::CopyItems( const StatusBar& rStatusBar ) +{ + // Alle Items entfernen + ImplStatusItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + // Items aus der Liste loeschen + mpItemList->Clear(); + + // Items kopieren + ULONG i = 0; + pItem = rStatusBar.mpItemList->GetObject( i ); + while ( pItem ) + { + mpItemList->Insert( new ImplStatusItem( *pItem ), LIST_APPEND ); + i++; + pItem = rStatusBar.mpItemList->GetObject( i ); + } + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::Clear() +{ + // Alle Item loeschen + ImplStatusItem* pItem = mpItemList->First(); + while ( pItem ) + { + delete pItem; + pItem = mpItemList->Next(); + } + + // Items aus der Liste loeschen + mpItemList->Clear(); + + mbFormat = TRUE; + if ( ImplIsItemUpdate() ) + Invalidate(); + + ImplCallEventListeners( VCLEVENT_STATUSBAR_ALLITEMSREMOVED ); +} + +// ----------------------------------------------------------------------- + +USHORT StatusBar::GetItemCount() const +{ + return (USHORT)mpItemList->Count(); +} + +// ----------------------------------------------------------------------- + +USHORT StatusBar::GetItemId( USHORT nPos ) const +{ + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem ) + return pItem->mnId; + else + return 0; +} + +// ----------------------------------------------------------------------- + +USHORT StatusBar::GetItemPos( USHORT nItemId ) const +{ + ImplStatusItem* pItem = mpItemList->First(); + while ( pItem ) + { + if ( pItem->mnId == nItemId ) + return (USHORT)mpItemList->GetCurPos(); + + pItem = mpItemList->Next(); + } + + return STATUSBAR_ITEM_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +USHORT StatusBar::GetItemId( const Point& rPos ) const +{ + if ( AreItemsVisible() && !mbFormat ) + { + USHORT nItemCount = GetItemCount(); + USHORT nPos; + for ( nPos = 0; nPos < nItemCount; nPos++ ) + { + // Rechteck holen + Rectangle aRect = ImplGetItemRectPos( nPos ); + if ( aRect.IsInside( rPos ) ) + return mpItemList->GetObject( nPos )->mnId; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +Rectangle StatusBar::GetItemRect( USHORT nItemId ) const +{ + Rectangle aRect; + + if ( AreItemsVisible() && !mbFormat ) + { + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + // Rechteck holen und Rahmen abziehen + aRect = ImplGetItemRectPos( nPos ); + long nW = mpImplData->mnItemBorderWidth+1; + aRect.Top() += nW-1; + aRect.Bottom() -= nW-1; + aRect.Left() += nW; + aRect.Right() -= nW; + return aRect; + } + } + + return aRect; +} + +// ----------------------------------------------------------------------- + +Point StatusBar::GetItemTextPos( USHORT nItemId ) const +{ + if ( !mbFormat ) + { + USHORT nPos = GetItemPos( nItemId ); + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + // Rechteck holen + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + Rectangle aRect = ImplGetItemRectPos( nPos ); + long nW = mpImplData->mnItemBorderWidth + 1; + Rectangle aTextRect( aRect.Left()+nW, aRect.Top()+nW, + aRect.Right()-nW, aRect.Bottom()-nW ); + Point aPos = ImplGetItemTextPos( aTextRect.GetSize(), + Size( GetTextWidth( pItem->maText ), GetTextHeight() ), + pItem->mnBits ); + if ( !mbInUserDraw ) + { + aPos.X() += aTextRect.Left(); + aPos.Y() += aTextRect.Top(); + } + return aPos; + } + } + + return Point(); +} + +// ----------------------------------------------------------------------- + +ULONG StatusBar::GetItemWidth( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mnWidth; + else + return 0; +} + +// ----------------------------------------------------------------------- + +StatusBarItemBits StatusBar::GetItemBits( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mnBits; + else + return 0; +} + +// ----------------------------------------------------------------------- + +long StatusBar::GetItemOffset( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mnOffset; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetItemText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->maText != rText ) + { + pItem->maText = rText; + + // adjust item width - see also DataChanged() + long nFudge = GetTextHeight()/4; + long nWidth = GetTextWidth( pItem->maText ) + nFudge; + if( (nWidth > pItem->mnWidth + STATUSBAR_OFFSET) || + ((nWidth < pItem->mnWidth) && (mnDX - STATUSBAR_OFFSET) < mnItemsWidth )) + { + pItem->mnWidth = nWidth + STATUSBAR_OFFSET; + ImplFormat(); + Invalidate(); + } + + // Item neu Zeichen, wenn StatusBar sichtbar und + // UpdateMode gesetzt ist + if ( pItem->mbVisible && !mbFormat && ImplIsItemUpdate() ) + { + Update(); + ImplDrawItem( TRUE, nPos, TRUE, FALSE ); + Flush(); + } + } + } +} + +// ----------------------------------------------------------------------- + +const XubString& StatusBar::GetItemText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->maText; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetItemCommand( USHORT nItemId, const XubString& rCommand ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->maCommand != rCommand ) + pItem->maCommand = rCommand; + } +} + +// ----------------------------------------------------------------------- + +const XubString& StatusBar::GetItemCommand( USHORT nItemId ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->maCommand; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetItemData( USHORT nItemId, void* pNewData ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + pItem->mpUserData = pNewData; + + // Wenn es ein User-Item ist, DrawItem-Aufrufen + if ( (pItem->mnBits & SIB_USERDRAW) && pItem->mbVisible && + !mbFormat && ImplIsItemUpdate() ) + { + Update(); + ImplDrawItem( TRUE, nPos, FALSE, FALSE ); + Flush(); + } + } +} + +// ----------------------------------------------------------------------- + +void* StatusBar::GetItemData( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->mpUserData; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetHelpText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + mpItemList->GetObject( nPos )->maHelpText = rText; +} + +// ----------------------------------------------------------------------- + +const XubString& StatusBar::GetHelpText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + if ( !pItem->maHelpText.Len() && ( pItem->maHelpId.getLength() || pItem->maCommand.Len() )) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if ( pItem->maCommand.Len() ) + pItem->maHelpText = pHelp->GetHelpText( pItem->maCommand, this ); + if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() ) + pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + } + + return pItem->maHelpText; + } + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetQuickHelpText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + mpItemList->GetObject( nPos )->maQuickHelpText = rText; +} + +// ----------------------------------------------------------------------- + +const XubString& StatusBar::GetQuickHelpText( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + return pItem->maQuickHelpText; + } + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetHelpId( USHORT nItemId, const rtl::OString& rHelpId ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + mpItemList->GetObject( nPos )->maHelpId = rHelpId; +} + +// ----------------------------------------------------------------------- + +rtl::OString StatusBar::GetHelpId( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + rtl::OString aRet; + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + if ( pItem->maHelpId.getLength() ) + aRet = pItem->maHelpId; + else + aRet = ::rtl::OUStringToOString( pItem->maCommand, RTL_TEXTENCODING_UTF8 ); + } + + return aRet; +} + +// ----------------------------------------------------------------------- + +void StatusBar::ImplCalcBorder( ) +{ + mnCalcHeight = mnDY; + // subtract border + if( IsTopBorder() ) + { + mnCalcHeight -= 2; + mnTextY += 2; + mnItemY += 2; + } + if ( IsBottomBorder() ) + mnCalcHeight -= 2; + mbFormat = TRUE; + Invalidate(); +} + +void StatusBar::SetBottomBorder( BOOL bBottomBorder ) +{ + if ( mbBottomBorder != bBottomBorder ) + { + mbBottomBorder = bBottomBorder; + ImplCalcBorder(); + } +} + +void StatusBar::SetTopBorder( BOOL bTopBorder ) +{ + if ( mpImplData->mbTopBorder != static_cast<bool>(bTopBorder) ) + { + mpImplData->mbTopBorder = static_cast<bool>(bTopBorder); + ImplCalcBorder(); + } +} + +BOOL StatusBar::IsTopBorder() const +{ + return mpImplData->mbTopBorder; +} + +// ----------------------------------------------------------------------- + +void StatusBar::StartProgressMode( const XubString& rText ) +{ + DBG_ASSERT( !mbProgressMode, "StatusBar::StartProgressMode(): progress mode is active" ); + + mbProgressMode = TRUE; + mnPercent = 0; + maPrgsTxt = rText; + + // Groessen berechnen + ImplCalcProgressRect(); + + // Paint ausloesen (dort wird der Text und der Frame gemalt) + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Color aPrgsColor = rStyleSettings.GetHighlightColor(); + if ( aPrgsColor == rStyleSettings.GetFaceColor() ) + aPrgsColor = rStyleSettings.GetDarkShadowColor(); + SetLineColor(); + SetFillColor( aPrgsColor ); + if ( IsReallyVisible() ) + { + Invalidate(); + Update(); + Flush(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetProgressValue( USHORT nNewPercent ) +{ + DBG_ASSERT( mbProgressMode, "StatusBar::SetProgressValue(): no progrss mode" ); + DBG_ASSERTWARNING( nNewPercent <= 100, "StatusBar::SetProgressValue(): nPercent > 100" ); + + if ( mbProgressMode + && IsReallyVisible() + && (!mnPercent || (mnPercent != nNewPercent)) ) + { + Update(); + SetLineColor(); + ImplDrawProgress( FALSE, mnPercent, nNewPercent ); + Flush(); + } + mnPercent = nNewPercent; +} + +// ----------------------------------------------------------------------- + +void StatusBar::EndProgressMode() +{ + DBG_ASSERT( mbProgressMode, "StatusBar::EndProgressMode(): no progress mode" ); + + mbProgressMode = FALSE; + maPrgsTxt.Erase(); + + // Paint neu ausloesen um StatusBar wieder herzustellen + SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() ); + if ( IsReallyVisible() ) + { + Invalidate(); + Update(); + Flush(); + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::ResetProgressMode() +{ + if ( mbProgressMode ) + { + mnPercent = 0; + maPrgsTxt.Erase(); + if ( IsReallyVisible() ) + { + Invalidate(); + Update(); + Flush(); + } + } +} + +// ----------------------------------------------------------------------- + +void StatusBar::SetText( const XubString& rText ) +{ + if ( (!mbVisibleItems || (GetStyle() & WB_RIGHT)) && !mbProgressMode && + IsReallyVisible() && IsUpdateMode() ) + { + if ( mbFormat ) + { + Invalidate(); + Window::SetText( rText ); + } + else + { + Update(); + long nOldTextWidth = GetTextWidth( GetText() ); + Window::SetText( rText ); + ImplDrawText( TRUE, nOldTextWidth ); + Flush(); + } + } + else if ( mbProgressMode ) + { + maPrgsTxt = rText; + if ( IsReallyVisible() ) + { + Invalidate(); + Update(); + Flush(); + } + } + else + Window::SetText( rText ); +} + +// ----------------------------------------------------------------------- + +Size StatusBar::CalcWindowSizePixel() const +{ + ULONG i = 0; + ULONG nCount = mpItemList->Count(); + long nOffset = 0; + long nCalcWidth = (STATUSBAR_OFFSET_X*2); + long nCalcHeight; + + while ( i < nCount ) + { + ImplStatusItem* pItem = mpItemList->GetObject( i ); + nCalcWidth += pItem->mnWidth + nOffset; + nOffset = pItem->mnOffset; + i++; + } + + long nMinHeight = GetTextHeight(); + const long nBarTextOffset = STATUSBAR_OFFSET_TEXTY*2; + long nProgressHeight = nMinHeight + nBarTextOffset; + // FIXME: IsNativeControlSupported and GetNativeControlRegion should be const ? + StatusBar* pThis = const_cast<StatusBar*>( this ); + if( pThis->IsNativeControlSupported( CTRL_PROGRESS, PART_ENTIRE_CONTROL ) ) + { + ImplControlValue aValue; + Rectangle aControlRegion( (const Point&)Point(), Size( nCalcWidth, nMinHeight ) ); + Rectangle aNativeControlRegion, aNativeContentRegion; + if( pThis->GetNativeControlRegion( CTRL_PROGRESS, PART_ENTIRE_CONTROL, aControlRegion, + CTRL_STATE_ENABLED, aValue, rtl::OUString(), + aNativeControlRegion, aNativeContentRegion ) ) + { + nProgressHeight = aNativeControlRegion.GetHeight(); + } + } + + if( mpImplData->mbDrawItemFrames && + pThis->IsNativeControlSupported( CTRL_FRAME, PART_BORDER ) ) + { + ImplControlValue aControlValue( FRAME_DRAW_NODRAW ); + Rectangle aBound, aContent; + Rectangle aNatRgn( Point( 0, 0 ), Size( 150, 50 ) ); + if( pThis->GetNativeControlRegion(CTRL_FRAME, PART_BORDER, + aNatRgn, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + mpImplData->mnItemBorderWidth = + ( aBound.GetHeight() - aContent.GetHeight() ) / 2; + } + } + + nCalcHeight = nMinHeight+nBarTextOffset + 2*mpImplData->mnItemBorderWidth; + if( nCalcHeight < nProgressHeight+2 ) + nCalcHeight = nProgressHeight+2; + + // add border + if( IsTopBorder() ) + nCalcHeight += 2; + if ( IsBottomBorder() ) + nCalcHeight += 2; + + return Size( nCalcWidth, nCalcHeight ); +} + + +// ----------------------------------------------------------------------- + +void StatusBar::SetAccessibleName( USHORT nItemId, const XubString& rName ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + { + ImplStatusItem* pItem = mpItemList->GetObject( nPos ); + + if ( pItem->maAccessibleName != rName ) + { + pItem->maAccessibleName = rName; + ImplCallEventListeners( VCLEVENT_STATUSBAR_NAMECHANGED, (void*) sal_IntPtr(pItem->mnId) ); + } + } +} + +// ----------------------------------------------------------------------- + +const XubString& StatusBar::GetAccessibleName( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != STATUSBAR_ITEM_NOTFOUND ) + return mpItemList->GetObject( nPos )->maAccessibleName; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- diff --git a/vcl/source/window/syschild.cxx b/vcl/source/window/syschild.cxx new file mode 100644 index 000000000000..4e897eef4a8b --- /dev/null +++ b/vcl/source/window/syschild.cxx @@ -0,0 +1,338 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <svsys.h> +#include <rtl/process.h> +#include <rtl/ref.hxx> +#include <tools/rc.h> +#include <vcl/window.h> +#include <vcl/salinst.hxx> +#include <vcl/salframe.hxx> +#include <vcl/window.hxx> +#include <vcl/salobj.hxx> +#include <vcl/svdata.hxx> +#include <vcl/sysdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syschild.hxx> +#include <vcl/unohelp.hxx> + +#ifdef SOLAR_JAVA +#include <jni.h> +#endif + +#include <comphelper/processfactory.hxx> +#include <jvmaccess/virtualmachine.hxx> +#include <com/sun/star/java/XJavaVM.hpp> +#include <com/sun/star/java/XJavaThreadRegister_11.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <vcl/syschild.hxx> + +using namespace ::com::sun::star; + +// ======================================================================= + +long ImplSysChildProc( void* pInst, SalObject* /* pObject */, + USHORT nEvent, const void* /* pEvent */ ) +{ + SystemChildWindow* pWindow = (SystemChildWindow*)pInst; + long nRet = 0; + + ImplDelData aDogTag( pWindow ); + switch ( nEvent ) + { + case SALOBJ_EVENT_GETFOCUS: + // Focus holen und zwar so, das alle Handler gerufen + // werden, als ob dieses Fenster den Focus bekommt, + // ohne das der Frame den Focus wieder klaut + pWindow->ImplGetFrameData()->mbSysObjFocus = TRUE; + pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = TRUE; + pWindow->ToTop( TOTOP_NOGRABFOCUS ); + if( aDogTag.IsDead() ) + break; + pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = FALSE; + pWindow->ImplGetFrameData()->mbInSysObjFocusHdl = TRUE; + pWindow->GrabFocus(); + if( aDogTag.IsDead() ) + break; + pWindow->ImplGetFrameData()->mbInSysObjFocusHdl = FALSE; + break; + + case SALOBJ_EVENT_LOSEFOCUS: + // Hintenrum einen LoseFocus ausloesen, das der Status + // der Fenster dem entsprechenden Activate-Status + // entspricht + pWindow->ImplGetFrameData()->mbSysObjFocus = FALSE; + if ( !pWindow->ImplGetFrameData()->mnFocusId ) + { + pWindow->ImplGetFrameData()->mbStartFocusState = TRUE; + Application::PostUserEvent( pWindow->ImplGetFrameData()->mnFocusId, LINK( pWindow->ImplGetFrameWindow(), Window, ImplAsyncFocusHdl ) ); + } + break; + + case SALOBJ_EVENT_TOTOP: + pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = TRUE; + if ( !Application::GetFocusWindow() || pWindow->HasChildPathFocus() ) + pWindow->ToTop( TOTOP_NOGRABFOCUS ); + else + pWindow->ToTop(); + if( aDogTag.IsDead() ) + break; + pWindow->GrabFocus(); + if( aDogTag.IsDead() ) + break; + pWindow->ImplGetFrameData()->mbInSysObjToTopHdl = FALSE; + break; + } + + return nRet; +} + +// ======================================================================= + +void SystemChildWindow::ImplInitSysChild( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow ) +{ + mpWindowImpl->mpSysObj = ImplGetSVData()->mpDefInst->CreateObject( pParent->ImplGetFrame(), pData, bShow ); + + Window::ImplInit( pParent, nStyle, NULL ); + + // Wenn es ein richtiges SysChild ist, dann painten wir auch nicht + if ( GetSystemData() ) + { + mpWindowImpl->mpSysObj->SetCallback( this, ImplSysChildProc ); + SetParentClipMode( PARENTCLIPMODE_CLIP ); + SetBackground(); + } +} + +// ----------------------------------------------------------------------- + +SystemChildWindow::SystemChildWindow( Window* pParent, WinBits nStyle ) : + Window( WINDOW_SYSTEMCHILDWINDOW ) +{ + ImplInitSysChild( pParent, nStyle, NULL ); +} + +// ----------------------------------------------------------------------- + +SystemChildWindow::SystemChildWindow( Window* pParent, WinBits nStyle, SystemWindowData *pData, BOOL bShow ) : + Window( WINDOW_SYSTEMCHILDWINDOW ) +{ + ImplInitSysChild( pParent, nStyle, pData, bShow ); +} + +// ----------------------------------------------------------------------- + +SystemChildWindow::SystemChildWindow( Window* pParent, const ResId& rResId ) : + Window( WINDOW_SYSTEMCHILDWINDOW ) +{ + rResId.SetRT( RSC_WINDOW ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInitSysChild( pParent, nStyle, NULL ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +SystemChildWindow::~SystemChildWindow() +{ + Hide(); + if ( mpWindowImpl->mpSysObj ) + { + ImplGetSVData()->mpDefInst->DestroyObject( mpWindowImpl->mpSysObj ); + mpWindowImpl->mpSysObj = NULL; + } +} + +// ----------------------------------------------------------------------- + +const SystemEnvData* SystemChildWindow::GetSystemData() const +{ + if ( mpWindowImpl->mpSysObj ) + return mpWindowImpl->mpSysObj->GetSystemData(); + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void SystemChildWindow::EnableEraseBackground( BOOL bEnable ) +{ + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->EnableEraseBackground( bEnable ); +} + +// ----------------------------------------------------------------------- + +BOOL SystemChildWindow::IsEraseBackgroundEnabled() +{ + if ( mpWindowImpl->mpSysObj ) + return mpWindowImpl->mpSysObj->IsEraseBackgroundEnabled(); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void SystemChildWindow::ImplTestJavaException( void* pEnv ) +{ +#ifdef SOLAR_JAVA + JNIEnv* pJavaEnv = reinterpret_cast< JNIEnv* >( pEnv ); + jthrowable jtThrowable = pJavaEnv->ExceptionOccurred(); + + if( jtThrowable ) + { // is it a java exception ? +#if OSL_DEBUG_LEVEL > 1 + pJavaEnv->ExceptionDescribe(); +#endif // OSL_DEBUG_LEVEL > 1 + pJavaEnv->ExceptionClear(); + + jclass jcThrowable = pJavaEnv->FindClass("java/lang/Throwable"); + jmethodID jmThrowable_getMessage = pJavaEnv->GetMethodID(jcThrowable, "getMessage", "()Ljava/lang/String;"); + jstring jsMessage = (jstring) pJavaEnv->CallObjectMethod(jtThrowable, jmThrowable_getMessage); + ::rtl::OUString ouMessage; + + if(jsMessage) + { + const jchar * jcMessage = pJavaEnv->GetStringChars(jsMessage, NULL); + ouMessage = ::rtl::OUString(jcMessage); + pJavaEnv->ReleaseStringChars(jsMessage, jcMessage); + } + + throw uno::RuntimeException(ouMessage, uno::Reference<uno::XInterface>()); + } +#endif // SOLAR_JAVA +} + +// ----------------------------------------------------------------------- + +sal_IntPtr SystemChildWindow::GetParentWindowHandle( sal_Bool bUseJava ) +{ + sal_IntPtr nRet = 0; + +#if defined WNT + nRet = reinterpret_cast< sal_IntPtr >( GetSystemData()->hWnd ); +#elif defined QUARTZ + // FIXME: this is wrong + nRet = reinterpret_cast< sal_IntPtr >( GetSystemData()->pView ); +#elif defined UNX + if( !bUseJava ) + { + nRet = (sal_IntPtr) GetSystemData()->aWindow; + } +#ifdef SOLAR_JAVA + else + { + uno::Reference< lang::XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() ); + + if( xFactory.is() && ( GetSystemData()->aWindow > 0 ) ) + { + try + { + ::rtl::Reference< ::jvmaccess::VirtualMachine > xVM; + uno::Reference< java::XJavaVM > xJavaVM( xFactory->createInstance( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.java.JavaVirtualMachine") ) ), uno::UNO_QUERY ); + uno::Sequence< sal_Int8 > aProcessID( 17 ); + + rtl_getGlobalProcessId( (sal_uInt8*) aProcessID.getArray() ); + aProcessID[ 16 ] = 0; + OSL_ENSURE(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *), "Pointer cannot be represented as sal_Int64"); + sal_Int64 nPointer = reinterpret_cast< sal_Int64 >( static_cast< jvmaccess::VirtualMachine * >(0)); + xJavaVM->getJavaVM(aProcessID) >>= nPointer; + xVM = reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer); + + if( xVM.is() ) + { + try + { + ::jvmaccess::VirtualMachine::AttachGuard aVMAttachGuard( xVM ); + JNIEnv* pEnv = aVMAttachGuard.getEnvironment(); + + jclass jcToolkit = pEnv->FindClass("java/awt/Toolkit"); + ImplTestJavaException(pEnv); + + jmethodID jmToolkit_getDefaultToolkit = pEnv->GetStaticMethodID( jcToolkit, "getDefaultToolkit", "()Ljava/awt/Toolkit;" ); + ImplTestJavaException(pEnv); + + pEnv->CallStaticObjectMethod(jcToolkit, jmToolkit_getDefaultToolkit); + ImplTestJavaException(pEnv); + + jclass jcMotifAppletViewer = pEnv->FindClass("sun/plugin/navig/motif/MotifAppletViewer"); + if( pEnv->ExceptionOccurred() ) + { + pEnv->ExceptionClear(); + + jcMotifAppletViewer = pEnv->FindClass( "sun/plugin/viewer/MNetscapePluginContext"); + ImplTestJavaException(pEnv); + } + + jclass jcClassLoader = pEnv->FindClass("java/lang/ClassLoader"); + ImplTestJavaException(pEnv); + + jmethodID jmClassLoader_loadLibrary = pEnv->GetStaticMethodID( jcClassLoader, "loadLibrary", "(Ljava/lang/Class;Ljava/lang/String;Z)V"); + ImplTestJavaException(pEnv); + + jstring jsplugin = pEnv->NewStringUTF("javaplugin_jni"); + ImplTestJavaException(pEnv); + + pEnv->CallStaticVoidMethod(jcClassLoader, jmClassLoader_loadLibrary, jcMotifAppletViewer, jsplugin, JNI_FALSE); + ImplTestJavaException(pEnv); + + jmethodID jmMotifAppletViewer_getWidget = pEnv->GetStaticMethodID( jcMotifAppletViewer, "getWidget", "(IIIII)I" ); + ImplTestJavaException(pEnv); + + const Size aSize( GetOutputSizePixel() ); + jint ji_widget = pEnv->CallStaticIntMethod( jcMotifAppletViewer, jmMotifAppletViewer_getWidget, + GetSystemData()->aWindow, 0, 0, aSize.Width(), aSize.Height() ); + ImplTestJavaException(pEnv); + + nRet = static_cast< sal_IntPtr >( ji_widget ); + } + catch( uno::RuntimeException& ) + { + } + + if( !nRet ) + nRet = static_cast< sal_IntPtr >( GetSystemData()->aWindow ); + } + } + catch( ... ) + { + } + } + } +#endif // SOLAR_JAVA +#else // WNT || QUARTZ || UNX +#endif + + return nRet; +} diff --git a/vcl/source/window/syswin.cxx b/vcl/source/window/syswin.cxx new file mode 100644 index 000000000000..f6a37658b79f --- /dev/null +++ b/vcl/source/window/syswin.cxx @@ -0,0 +1,1086 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/debug.hxx> + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salframe.hxx> +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/menu.hxx> +#include <vcl/window.h> +#include <vcl/brdwin.hxx> +#include <vcl/sound.hxx> +#include <vcl/svapp.hxx> +#include <vcl/event.hxx> +#include <vcl/syswin.hxx> +#include <vcl/taskpanelist.hxx> +#include <vcl/unowrap.hxx> + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// ======================================================================= +class SystemWindow::ImplData +{ +public: + ImplData(); + ~ImplData(); + + TaskPaneList* mpTaskPaneList; + Size maMaxOutSize; + rtl::OUString maRepresentedURL; +}; + +SystemWindow::ImplData::ImplData() +{ + mpTaskPaneList = NULL; + maMaxOutSize = Size( SHRT_MAX, SHRT_MAX ); +} + +SystemWindow::ImplData::~ImplData() +{ + if( mpTaskPaneList ) + delete mpTaskPaneList; +} + +// ======================================================================= + +SystemWindow::SystemWindow( WindowType nType ) : + Window( nType ) +{ + mpImplData = new ImplData; + mpWindowImpl->mbSysWin = TRUE; + mpWindowImpl->mnActivateMode = ACTIVATE_MODE_GRABFOCUS; + + mpMenuBar = NULL; + mbPined = FALSE; + mbRollUp = FALSE; + mbRollFunc = FALSE; + mbDockBtn = FALSE; + mbHideBtn = FALSE; + mbSysChild = FALSE; + mnMenuBarMode = MENUBAR_MODE_NORMAL; + mnIcon = 0; +} + +SystemWindow::~SystemWindow() +{ + delete mpImplData; + mpImplData = NULL; +} + +// ----------------------------------------------------------------------- + +long SystemWindow::Notify( NotifyEvent& rNEvt ) +{ + // capture KeyEvents for menu handling + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + MenuBar* pMBar = mpMenuBar; + if ( !pMBar && ( GetType() == WINDOW_FLOATINGWINDOW ) ) + { + Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); + if( pWin && pWin->IsSystemWindow() ) + pMBar = ((SystemWindow*)pWin)->GetMenuBar(); + } + if ( pMBar && pMBar->ImplHandleKeyEvent( *rNEvt.GetKeyEvent(), FALSE ) ) + return TRUE; + } + + return Window::Notify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +long SystemWindow::PreNotify( NotifyEvent& rNEvt ) +{ + // capture KeyEvents for taskpane cycling + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + if( rNEvt.GetKeyEvent()->GetKeyCode().GetCode() == KEY_F6 && + rNEvt.GetKeyEvent()->GetKeyCode().IsMod1() && + !rNEvt.GetKeyEvent()->GetKeyCode().IsShift() ) + { + // Ctrl-F6 goes directly to the document + GrabFocusToDocument(); + return TRUE; + } + else + { + TaskPaneList *pTList = mpImplData->mpTaskPaneList; + if( !pTList && ( GetType() == WINDOW_FLOATINGWINDOW ) ) + { + Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); + if( pWin && pWin->IsSystemWindow() ) + pTList = ((SystemWindow*)pWin)->mpImplData->mpTaskPaneList; + } + if( !pTList ) + { + // search topmost system window which is the one to handle dialog/toolbar cycling + SystemWindow *pSysWin = this; + Window *pWin = this; + while( pWin ) + { + pWin = pWin->GetParent(); + if( pWin && pWin->IsSystemWindow() ) + pSysWin = (SystemWindow*) pWin; + } + pTList = pSysWin->mpImplData->mpTaskPaneList; + } + if( pTList && pTList->HandleKeyEvent( *rNEvt.GetKeyEvent() ) ) + return TRUE; + } + } + return Window::PreNotify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +TaskPaneList* SystemWindow::GetTaskPaneList() +{ + if( mpImplData->mpTaskPaneList ) + return mpImplData->mpTaskPaneList ; + else + { + mpImplData->mpTaskPaneList = new TaskPaneList(); + MenuBar* pMBar = mpMenuBar; + if ( !pMBar && ( GetType() == WINDOW_FLOATINGWINDOW ) ) + { + Window* pWin = ImplGetFrameWindow()->ImplGetWindow(); + if ( pWin && pWin->IsSystemWindow() ) + pMBar = ((SystemWindow*)pWin)->GetMenuBar(); + } + if( pMBar ) + mpImplData->mpTaskPaneList->AddWindow( pMBar->ImplGetWindow() ); + return mpImplData->mpTaskPaneList; + } +} + +// ----------------------------------------------------------------------- + +BOOL SystemWindow::Close() +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + ImplCallEventListeners( VCLEVENT_WINDOW_CLOSE ); + if ( aDelData.IsDelete() ) + return FALSE; + ImplRemoveDel( &aDelData ); + + if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() ) + return FALSE; + + // Is Window not closeable, ignore close + Window* pBorderWin = ImplGetBorderWindow(); + WinBits nStyle; + if ( pBorderWin ) + nStyle = pBorderWin->GetStyle(); + else + nStyle = GetStyle(); + if ( !(nStyle & WB_CLOSEABLE) ) + { + Sound::Beep( SOUND_DISABLE, this ); + return FALSE; + } + + Hide(); + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::TitleButtonClick( USHORT ) +{ +} + +// ----------------------------------------------------------------------- + +void SystemWindow::Pin() +{ +} + +// ----------------------------------------------------------------------- + +void SystemWindow::Roll() +{ +} + +// ----------------------------------------------------------------------- + +void SystemWindow::Resizing( Size& ) +{ +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetZLevel( BYTE nLevel ) +{ + Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + if ( pWindow->mpWindowImpl->mbOverlapWin && !pWindow->mpWindowImpl->mbFrame ) + { + BYTE nOldLevel = pWindow->mpWindowImpl->mpOverlapData->mnTopLevel; + pWindow->mpWindowImpl->mpOverlapData->mnTopLevel = nLevel; + // Wenn der neue Level groesser als der alte ist, schieben + // wir das Fenster nach hinten + if ( !IsReallyVisible() && (nLevel > nOldLevel) && pWindow->mpWindowImpl->mpNext ) + { + // Fenster aus der Liste entfernen + if ( pWindow->mpWindowImpl->mpPrev ) + pWindow->mpWindowImpl->mpPrev->mpWindowImpl->mpNext = pWindow->mpWindowImpl->mpNext; + else + pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = pWindow->mpWindowImpl->mpNext; + pWindow->mpWindowImpl->mpNext->mpWindowImpl->mpPrev = pWindow->mpWindowImpl->mpPrev; + pWindow->mpWindowImpl->mpNext = NULL; + // und Fenster wieder in die Liste am Ende eintragen + pWindow->mpWindowImpl->mpPrev = pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap; + pWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = pWindow; + pWindow->mpWindowImpl->mpPrev->mpWindowImpl->mpNext = pWindow; + } + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetRepresentedURL( const rtl::OUString& i_rURL ) +{ + bool bChanged = (i_rURL != mpImplData->maRepresentedURL); + mpImplData->maRepresentedURL = i_rURL; + if ( !mbSysChild && bChanged ) + { + const Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + pWindow->mpWindowImpl->mpFrame->SetRepresentedURL( i_rURL ); + } +} +// ----------------------------------------------------------------------- + +const rtl::OUString& SystemWindow::GetRepresentedURL() const +{ + return mpImplData->maRepresentedURL; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetIcon( USHORT nIcon ) +{ + if ( mnIcon == nIcon ) + return; + + mnIcon = nIcon; + + if ( !mbSysChild ) + { + const Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + pWindow->mpWindowImpl->mpFrame->SetIcon( nIcon ); + } +} + +// ----------------------------------------------------------------------- + +BYTE SystemWindow::GetZLevel() const +{ + const Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + if ( pWindow->mpWindowImpl->mpOverlapData ) + return pWindow->mpWindowImpl->mpOverlapData->mnTopLevel; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::EnableSaveBackground( BOOL bSave ) +{ + if( ImplGetSVData()->maWinData.mbNoSaveBackground ) + bSave = false; + + Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + if ( pWindow->mpWindowImpl->mbOverlapWin && !pWindow->mpWindowImpl->mbFrame ) + { + pWindow->mpWindowImpl->mpOverlapData->mbSaveBack = bSave; + if ( !bSave ) + pWindow->ImplDeleteOverlapBackground(); + } +} + +// ----------------------------------------------------------------------- + +BOOL SystemWindow::IsSaveBackgroundEnabled() const +{ + const Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + if ( pWindow->mpWindowImpl->mpOverlapData ) + return pWindow->mpWindowImpl->mpOverlapData->mbSaveBack; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::ShowTitleButton( USHORT nButton, BOOL bVisible ) +{ + if ( nButton == TITLE_BUTTON_DOCKING ) + { + if ( mbDockBtn != bVisible ) + { + mbDockBtn = bVisible; + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetDockButton( bVisible ); + } + } + else if ( nButton == TITLE_BUTTON_HIDE ) + { + if ( mbHideBtn != bVisible ) + { + mbHideBtn = bVisible; + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetHideButton( bVisible ); + } + } + else if ( nButton == TITLE_BUTTON_MENU ) + { + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuButton( bVisible ); + } + else + return; +} + +// ----------------------------------------------------------------------- + +BOOL SystemWindow::IsTitleButtonVisible( USHORT nButton ) const +{ + if ( nButton == TITLE_BUTTON_DOCKING ) + return mbDockBtn; + else /* if ( nButton == TITLE_BUTTON_HIDE ) */ + return mbHideBtn; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetPin( BOOL bPin ) +{ + if ( bPin != mbPined ) + { + mbPined = bPin; + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetPin( bPin ); + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::RollUp() +{ + if ( !mbRollUp ) + { + maOrgSize = GetOutputSizePixel(); + mbRollFunc = TRUE; + Size aSize = maRollUpOutSize; + if ( !aSize.Width() ) + aSize.Width() = GetOutputSizePixel().Width(); + mbRollUp = TRUE; + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetRollUp( TRUE, aSize ); + else + SetOutputSizePixel( aSize ); + mbRollFunc = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::RollDown() +{ + if ( mbRollUp ) + { + mbRollUp = FALSE; + if ( mpWindowImpl->mpBorderWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetRollUp( FALSE, maOrgSize ); + else + SetOutputSizePixel( maOrgSize ); + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetMinOutputSizePixel( const Size& rSize ) +{ + maMinOutSize = rSize; + if ( mpWindowImpl->mpBorderWindow ) + { + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMinOutputSize( rSize.Width(), rSize.Height() ); + if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) + mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() ); + } + else if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetMinClientSize( rSize.Width(), rSize.Height() ); +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetMaxOutputSizePixel( const Size& rSize ) +{ + Size aSize( rSize ); + if( aSize.Width() > SHRT_MAX || aSize.Width() <= 0 ) + aSize.Width() = SHRT_MAX; + if( aSize.Height() > SHRT_MAX || aSize.Height() <= 0 ) + aSize.Height() = SHRT_MAX; + + mpImplData->maMaxOutSize = aSize; + if ( mpWindowImpl->mpBorderWindow ) + { + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMaxOutputSize( aSize.Width(), aSize.Height() ); + if ( mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame ) + mpWindowImpl->mpBorderWindow->mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() ); + } + else if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetMaxClientSize( aSize.Width(), aSize.Height() ); +} + +const Size& SystemWindow::GetMaxOutputSizePixel() const +{ + return mpImplData->maMaxOutSize; +} +// ----------------------------------------------------------------------- + +Size SystemWindow::GetResizeOutputSizePixel() const +{ + Size aSize = GetOutputSizePixel(); + if ( aSize.Width() < maMinOutSize.Width() ) + aSize.Width() = maMinOutSize.Width(); + if ( aSize.Height() < maMinOutSize.Height() ) + aSize.Height() = maMinOutSize.Height(); + return aSize; +} + +// ----------------------------------------------------------------------- + +static void ImplWindowStateFromStr( WindowStateData& rData, const ByteString& rStr ) +{ + ULONG nValidMask = 0; + xub_StrLen nIndex = 0; + ByteString aTokenStr; + + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetX( aTokenStr.ToInt32() ); + if( rData.GetX() > -16384 && rData.GetX() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_X; + else + rData.SetX( 0 ); + } + else + rData.SetX( 0 ); + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetY( aTokenStr.ToInt32() ); + if( rData.GetY() > -16384 && rData.GetY() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_Y; + else + rData.SetY( 0 ); + } + else + rData.SetY( 0 ); + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetWidth( aTokenStr.ToInt32() ); + if( rData.GetWidth() > 0 && rData.GetWidth() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_WIDTH; + else + rData.SetWidth( 0 ); + } + else + rData.SetWidth( 0 ); + aTokenStr = rStr.GetToken( 0, ';', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetHeight( aTokenStr.ToInt32() ); + if( rData.GetHeight() > 0 && rData.GetHeight() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_HEIGHT; + else + rData.SetHeight( 0 ); + } + else + rData.SetHeight( 0 ); + aTokenStr = rStr.GetToken( 0, ';', nIndex ); + if ( aTokenStr.Len() ) + { + // #94144# allow Minimize again, should be masked out when read from configuration + // 91625 - ignore Minimize + ULONG nState = (ULONG)aTokenStr.ToInt32(); + //nState &= ~(WINDOWSTATE_STATE_MINIMIZED); + rData.SetState( nState ); + nValidMask |= WINDOWSTATE_MASK_STATE; + } + else + rData.SetState( 0 ); + + // read maximized pos/size + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetMaximizedX( aTokenStr.ToInt32() ); + if( rData.GetMaximizedX() > -16384 && rData.GetMaximizedX() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_X; + else + rData.SetMaximizedX( 0 ); + } + else + rData.SetMaximizedX( 0 ); + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetMaximizedY( aTokenStr.ToInt32() ); + if( rData.GetMaximizedY() > -16384 && rData.GetMaximizedY() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_Y; + else + rData.SetMaximizedY( 0 ); + } + else + rData.SetMaximizedY( 0 ); + aTokenStr = rStr.GetToken( 0, ',', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetMaximizedWidth( aTokenStr.ToInt32() ); + if( rData.GetMaximizedWidth() > 0 && rData.GetMaximizedWidth() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_WIDTH; + else + rData.SetMaximizedWidth( 0 ); + } + else + rData.SetMaximizedWidth( 0 ); + aTokenStr = rStr.GetToken( 0, ';', nIndex ); + if ( aTokenStr.Len() ) + { + rData.SetMaximizedHeight( aTokenStr.ToInt32() ); + if( rData.GetMaximizedHeight() > 0 && rData.GetMaximizedHeight() < 16384 ) + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_HEIGHT; + else + rData.SetMaximizedHeight( 0 ); + } + else + rData.SetMaximizedHeight( 0 ); + + // mark valid fields + rData.SetMask( nValidMask ); +} + +// ----------------------------------------------------------------------- + +static void ImplWindowStateToStr( const WindowStateData& rData, ByteString& rStr ) +{ + ULONG nValidMask = rData.GetMask(); + if ( !nValidMask ) + return; + + if ( nValidMask & WINDOWSTATE_MASK_X ) + rStr.Append( ByteString::CreateFromInt32( rData.GetX() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_Y ) + rStr.Append( ByteString::CreateFromInt32( rData.GetY() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_WIDTH ) + rStr.Append( ByteString::CreateFromInt32( rData.GetWidth() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_HEIGHT ) + rStr.Append( ByteString::CreateFromInt32( rData.GetHeight() ) ); + rStr.Append( ';' ); + if ( nValidMask & WINDOWSTATE_MASK_STATE ) + { + // #94144# allow Minimize again, should be masked out when read from configuration + // 91625 - ignore Minimize + ULONG nState = rData.GetState(); + //nState &= ~(WINDOWSTATE_STATE_MINIMIZED); + rStr.Append( ByteString::CreateFromInt32( (long)nState ) ); + } + rStr.Append( ';' ); + if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_X ) + rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedX() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_Y ) + rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedY() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_WIDTH ) + rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedWidth() ) ); + rStr.Append( ',' ); + if ( nValidMask & WINDOWSTATE_MASK_MAXIMIZED_HEIGHT ) + rStr.Append( ByteString::CreateFromInt32( rData.GetMaximizedHeight() ) ); + rStr.Append( ';' ); +} + +// ----------------------------------------------------------------------- + +void SystemWindow::ImplMoveToScreen( long& io_rX, long& io_rY, long i_nWidth, long i_nHeight, Window* i_pConfigureWin ) +{ + Rectangle aScreenRect; + if( Application::IsMultiDisplay() ) + { + aScreenRect = Application::GetScreenPosSizePixel( GetScreenNumber() ); + } + else + { + aScreenRect = Application::GetScreenPosSizePixel( 0 ); + for( unsigned int i = 1; i < Application::GetScreenCount(); i++ ) + aScreenRect.Union( Application::GetScreenPosSizePixel( i ) ); + } + // unfortunately most of the time width and height are not really known + if( i_nWidth < 1 ) + i_nWidth = 50; + if( i_nHeight < 1 ) + i_nHeight = 50; + + // check left border + bool bMove = false; + if( io_rX + i_nWidth < aScreenRect.Left() ) + { + bMove = true; + io_rX = aScreenRect.Left(); + } + // check right border + if( io_rX > aScreenRect.Right() - i_nWidth ) + { + bMove = true; + io_rX = aScreenRect.Right() - i_nWidth; + } + // check top border + if( io_rY + i_nHeight < aScreenRect.Top() ) + { + bMove = true; + io_rY = aScreenRect.Top(); + } + // check bottom border + if( io_rY > aScreenRect.Bottom() - i_nHeight ) + { + bMove = true; + io_rY = aScreenRect.Bottom() - i_nHeight; + } + Window* pParent = i_pConfigureWin->GetParent(); + if( bMove && pParent ) + { + // calculate absolute screen pos here, since that is what is contained in WindowState + Point aParentAbsPos( pParent->OutputToAbsoluteScreenPixel( Point(0,0) ) ); + Size aParentSizePixel( pParent->GetOutputSizePixel() ); + Point aPos( (aParentSizePixel.Width() - i_nWidth) / 2, + (aParentSizePixel.Height() - i_nHeight) / 2 ); + io_rX = aParentAbsPos.X() + aPos.X(); + io_rY = aParentAbsPos.Y() + aPos.Y(); + } +} + +void SystemWindow::SetWindowStateData( const WindowStateData& rData ) +{ + ULONG nValidMask = rData.GetMask(); + if ( !nValidMask ) + return; + + if ( mbSysChild ) + return; + + Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + { + ULONG nState = rData.GetState(); + SalFrameState aState; + aState.mnMask = rData.GetMask(); + aState.mnX = rData.GetX(); + aState.mnY = rData.GetY(); + aState.mnWidth = rData.GetWidth(); + aState.mnHeight = rData.GetHeight(); + + if( rData.GetMask() & (WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) ) + { + // #i43799# adjust window state sizes if a minimial output size was set + // otherwise the frame and the client might get different sizes + if( maMinOutSize.Width() > aState.mnWidth ) + aState.mnWidth = maMinOutSize.Width(); + if( maMinOutSize.Height() > aState.mnHeight ) + aState.mnHeight = maMinOutSize.Height(); + } + + aState.mnMaximizedX = rData.GetMaximizedX(); + aState.mnMaximizedY = rData.GetMaximizedY(); + aState.mnMaximizedWidth = rData.GetMaximizedWidth(); + aState.mnMaximizedHeight = rData.GetMaximizedHeight(); + // #94144# allow Minimize again, should be masked out when read from configuration + // 91625 - ignore Minimize + //nState &= ~(WINDOWSTATE_STATE_MINIMIZED); + aState.mnState = nState & SAL_FRAMESTATE_SYSTEMMASK; + + // normalize window positions onto screen + ImplMoveToScreen( aState.mnX, aState.mnY, aState.mnWidth, aState.mnHeight, pWindow ); + ImplMoveToScreen( aState.mnMaximizedX, aState.mnMaximizedY, aState.mnMaximizedWidth, aState.mnMaximizedHeight, pWindow ); + + // #96568# avoid having multiple frames at the same screen location + // do the check only if not maximized + if( !((rData.GetMask() & WINDOWSTATE_MASK_STATE) && (nState & WINDOWSTATE_STATE_MAXIMIZED)) ) + if( rData.GetMask() & (WINDOWSTATE_MASK_POS|WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) ) + { + Rectangle aDesktop = GetDesktopRectPixel(); + ImplSVData *pSVData = ImplGetSVData(); + Window *pWin = pSVData->maWinData.mpFirstFrame; + BOOL bWrapped = FALSE; + while( pWin ) + { + if( !pWin->ImplIsRealParentPath( this ) && ( pWin != this ) && + pWin->ImplGetWindow()->IsTopWindow() && pWin->mpWindowImpl->mbReallyVisible ) + { + SalFrameGeometry g = pWin->mpWindowImpl->mpFrame->GetGeometry(); + if( abs(g.nX-aState.mnX) < 2 && abs(g.nY-aState.mnY) < 5 ) + { + long displacement = g.nTopDecoration ? g.nTopDecoration : 20; + if( (unsigned long) (aState.mnX + displacement + aState.mnWidth + g.nRightDecoration) > (unsigned long) aDesktop.nRight || + (unsigned long) (aState.mnY + displacement + aState.mnHeight + g.nBottomDecoration) > (unsigned long) aDesktop.nBottom ) + { + // displacing would leave screen + aState.mnX = g.nLeftDecoration ? g.nLeftDecoration : 10; // should result in (0,0) + aState.mnY = displacement; + if( bWrapped || + (unsigned long) (aState.mnX + displacement + aState.mnWidth + g.nRightDecoration) > (unsigned long) aDesktop.nRight || + (unsigned long) (aState.mnY + displacement + aState.mnHeight + g.nBottomDecoration) > (unsigned long) aDesktop.nBottom ) + break; // further displacement not possible -> break + // avoid endless testing + bWrapped = TRUE; + } + else + { + // displace + aState.mnX += displacement; + aState.mnY += displacement; + } + pWin = pSVData->maWinData.mpFirstFrame; // check new pos again + } + } + pWin = pWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + } + + mpWindowImpl->mpFrame->SetWindowState( &aState ); + + // do a synchronous resize for layout reasons + // but use rData only when the window is not to be maximized (#i38089#) + // otherwise we have no useful size information + if( (rData.GetMask() & WINDOWSTATE_MASK_STATE) && (nState & WINDOWSTATE_STATE_MAXIMIZED) ) + { + // query maximized size from frame + SalFrameGeometry aGeometry = mpWindowImpl->mpFrame->GetGeometry(); + + // but use it only if it is different from the restore size (rData) + // as currently only on windows the exact size of a maximized window + // can be computed without actually showing the window + if( aGeometry.nWidth != rData.GetWidth() || aGeometry.nHeight != rData.GetHeight() ) + ImplHandleResize( pWindow, aGeometry.nWidth, aGeometry.nHeight ); + } + else + if( rData.GetMask() & (WINDOWSTATE_MASK_WIDTH|WINDOWSTATE_MASK_HEIGHT) ) + ImplHandleResize( pWindow, aState.mnWidth, aState.mnHeight ); // #i43799# use aState and not rData, see above + } + else + { + USHORT nPosSize = 0; + if ( nValidMask & WINDOWSTATE_MASK_X ) + nPosSize |= WINDOW_POSSIZE_X; + if ( nValidMask & WINDOWSTATE_MASK_Y ) + nPosSize |= WINDOW_POSSIZE_Y; + if ( nValidMask & WINDOWSTATE_MASK_WIDTH ) + nPosSize |= WINDOW_POSSIZE_WIDTH; + if ( nValidMask & WINDOWSTATE_MASK_HEIGHT ) + nPosSize |= WINDOW_POSSIZE_HEIGHT; + + if( IsRollUp() ) + RollDown(); + + long nX = rData.GetX(); + long nY = rData.GetY(); + long nWidth = rData.GetWidth(); + long nHeight = rData.GetHeight(); + const SalFrameGeometry& rGeom = pWindow->mpWindowImpl->mpFrame->GetGeometry(); + if( nX < 0 ) + nX = 0; + if( nX + nWidth > (long) rGeom.nWidth ) + nX = rGeom.nWidth - nWidth; + if( nY < 0 ) + nY = 0; + if( nY + nHeight > (long) rGeom.nHeight ) + nY = rGeom.nHeight - nHeight; + SetPosSizePixel( nX, nY, nWidth, nHeight, nPosSize ); + maOrgSize = Size( nWidth, nHeight ); + + // 91625 - ignore Minimize + if ( nValidMask & WINDOWSTATE_MASK_STATE ) + { + ULONG nState = rData.GetState(); + if ( nState & WINDOWSTATE_STATE_ROLLUP ) + RollUp(); + else + RollDown(); + } + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::GetWindowStateData( WindowStateData& rData ) const +{ + ULONG nValidMask = rData.GetMask(); + if ( !nValidMask ) + return; + + if ( mbSysChild ) + return; + + const Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + { + SalFrameState aState; + aState.mnMask = 0xFFFFFFFF; + if ( mpWindowImpl->mpFrame->GetWindowState( &aState ) ) + { + if ( nValidMask & WINDOWSTATE_MASK_X ) + rData.SetX( aState.mnX ); + if ( nValidMask & WINDOWSTATE_MASK_Y ) + rData.SetY( aState.mnY ); + if ( nValidMask & WINDOWSTATE_MASK_WIDTH ) + rData.SetWidth( aState.mnWidth ); + if ( nValidMask & WINDOWSTATE_MASK_HEIGHT ) + rData.SetHeight( aState.mnHeight ); + if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_X ) + { + rData.SetMaximizedX( aState.mnMaximizedX ); + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_X; + } + if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_Y ) + { + rData.SetMaximizedY( aState.mnMaximizedY ); + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_Y; + } + if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_WIDTH ) + { + rData.SetMaximizedWidth( aState.mnMaximizedWidth ); + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_WIDTH; + } + if ( aState.mnMask & SAL_FRAMESTATE_MASK_MAXIMIZED_HEIGHT ) + { + rData.SetMaximizedHeight( aState.mnMaximizedHeight ); + nValidMask |= WINDOWSTATE_MASK_MAXIMIZED_HEIGHT; + } + if ( nValidMask & WINDOWSTATE_MASK_STATE ) + { + // #94144# allow Minimize again, should be masked out when read from configuration + // 91625 - ignore Minimize + if ( !(nValidMask&WINDOWSTATE_MASK_MINIMIZED) ) + aState.mnState &= ~(WINDOWSTATE_STATE_MINIMIZED); + rData.SetState( aState.mnState ); + } + rData.SetMask( nValidMask ); + } + else + rData.SetMask( 0 ); + } + else + { + Point aPos = GetPosPixel(); + Size aSize = GetSizePixel(); + ULONG nState = 0; + + if ( IsRollUp() ) + { + aSize.Height() += maOrgSize.Height(); + nState |= WINDOWSTATE_STATE_ROLLUP; + } + + if ( nValidMask & WINDOWSTATE_MASK_X ) + rData.SetX( aPos.X() ); + if ( nValidMask & WINDOWSTATE_MASK_Y ) + rData.SetY( aPos.Y() ); + if ( nValidMask & WINDOWSTATE_MASK_WIDTH ) + rData.SetWidth( aSize.Width() ); + if ( nValidMask & WINDOWSTATE_MASK_HEIGHT ) + rData.SetHeight( aSize.Height() ); + if ( nValidMask & WINDOWSTATE_MASK_STATE ) + rData.SetState( nState ); + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetWindowState( const ByteString& rStr ) +{ + if ( !rStr.Len() ) + return; + + WindowStateData aData; + ImplWindowStateFromStr( aData, rStr ); + SetWindowStateData( aData ); +} + +// ----------------------------------------------------------------------- + +ByteString SystemWindow::GetWindowState( ULONG nMask ) const +{ + WindowStateData aData; + aData.SetMask( nMask ); + GetWindowStateData( aData ); + + ByteString aStr; + ImplWindowStateToStr( aData, aStr ); + return aStr; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetMenuBar( MenuBar* pMenuBar ) +{ + if ( mpMenuBar != pMenuBar ) + { + MenuBar* pOldMenuBar = mpMenuBar; + Window* pOldWindow = NULL; + Window* pNewWindow=NULL; + mpMenuBar = pMenuBar; + + if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) ) + { + if ( pOldMenuBar ) + pOldWindow = pOldMenuBar->ImplGetWindow(); + else + pOldWindow = NULL; + if ( pOldWindow ) + { + ImplCallEventListeners( VCLEVENT_WINDOW_MENUBARREMOVED, (void*) pOldMenuBar ); + pOldWindow->SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >() ); + } + if ( pMenuBar ) + { + DBG_ASSERT( !pMenuBar->pWindow, "SystemWindow::SetMenuBar() - MenuBars can only set in one SystemWindow at time" ); + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarWindow( pNewWindow = MenuBar::ImplCreate( mpWindowImpl->mpBorderWindow, pOldWindow, pMenuBar ) ); + ImplCallEventListeners( VCLEVENT_WINDOW_MENUBARADDED, (void*) pMenuBar ); + } + else + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarWindow( NULL ); + ImplToBottomChild(); + if ( pOldMenuBar ) + { + BOOL bDelete = (pMenuBar == 0) ? TRUE : FALSE; + if( bDelete && pOldWindow ) + { + if( mpImplData->mpTaskPaneList ) + mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow ); + } + MenuBar::ImplDestroy( pOldMenuBar, bDelete ); + if( bDelete ) + pOldWindow = NULL; // will be deleted in MenuBar::ImplDestroy, + } + + } + else + { + if( pMenuBar ) + pNewWindow = pMenuBar->ImplGetWindow(); + if( pOldMenuBar ) + pOldWindow = pOldMenuBar->ImplGetWindow(); + } + + // update taskpane list to make menubar accessible + if( mpImplData->mpTaskPaneList ) + { + if( pOldWindow ) + mpImplData->mpTaskPaneList->RemoveWindow( pOldWindow ); + if( pNewWindow ) + mpImplData->mpTaskPaneList->AddWindow( pNewWindow ); + } + } +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetMenuBarMode( USHORT nMode ) +{ + if ( mnMenuBarMode != nMode ) + { + mnMenuBarMode = nMode; + if ( mpWindowImpl->mpBorderWindow && (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) ) + { + if ( nMode == MENUBAR_MODE_HIDE ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarMode( TRUE ); + else + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetMenuBarMode( FALSE ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL SystemWindow::ImplIsInTaskPaneList( Window* pWin ) +{ + if( mpImplData && mpImplData->mpTaskPaneList ) + return mpImplData->mpTaskPaneList->IsInList( pWin ); + return FALSE; +} + +// ----------------------------------------------------------------------- + +unsigned int SystemWindow::GetScreenNumber() const +{ + return mpWindowImpl->mpFrame->maGeometry.nScreenNumber; +} + +// ----------------------------------------------------------------------- + +void SystemWindow::SetScreenNumber( unsigned int nScreen) +{ + mpWindowImpl->mpFrame->SetScreenNumber( nScreen ); +} diff --git a/vcl/source/window/tabdlg.cxx b/vcl/source/window/tabdlg.cxx new file mode 100644 index 000000000000..874881c0c5ef --- /dev/null +++ b/vcl/source/window/tabdlg.cxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <vcl/fixed.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/tabdlg.hxx> +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif + + + +// ======================================================================= + +void TabDialog::ImplInitTabDialogData() +{ + mpFixedLine = NULL; + mpViewWindow = NULL; + meViewAlign = WINDOWALIGN_LEFT; + mbPosControls = TRUE; +} + +// ----------------------------------------------------------------------- + +void TabDialog::ImplPosControls() +{ + Size aCtrlSize( IMPL_MINSIZE_BUTTON_WIDTH, IMPL_MINSIZE_BUTTON_HEIGHT ); + long nDownCtrl = 0; + long nOffY = 0; + TabControl* pTabControl = NULL; + + Window* pChild = GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild ) + { + if ( pChild->IsVisible() && (pChild != mpViewWindow) ) + { + if ( pChild->GetType() == WINDOW_TABCONTROL ) + pTabControl = (TabControl*)pChild; + else if ( pTabControl ) + { + long nTxtWidth = pChild->GetCtrlTextWidth( pChild->GetText() ); + nTxtWidth += IMPL_EXTRA_BUTTON_WIDTH; + if ( nTxtWidth > aCtrlSize.Width() ) + aCtrlSize.Width() = nTxtWidth; + long nTxtHeight = pChild->GetTextHeight(); + nTxtHeight += IMPL_EXTRA_BUTTON_HEIGHT; + if ( nTxtHeight > aCtrlSize.Height() ) + aCtrlSize.Height() = nTxtHeight; + nDownCtrl++; + } + else + { + long nHeight = pChild->GetSizePixel().Height(); + if ( nHeight > nOffY ) + nOffY = nHeight; + } + } + + pChild = pChild->GetWindow( WINDOW_NEXT ); + } + + // Haben wir ueberhaupt ein TabControl + if ( pTabControl ) + { + // Offset bei weiteren Controls um einen weiteren Abstand anpassen + if ( nOffY ) + nOffY += IMPL_DIALOG_BAR_OFFSET*2 + 2; + + Point aTabOffset( IMPL_DIALOG_OFFSET, IMPL_DIALOG_OFFSET+nOffY ); + Size aTabSize = pTabControl->GetSizePixel(); + Size aDlgSize( aTabSize.Width() + IMPL_DIALOG_OFFSET*2, + aTabSize.Height() + IMPL_DIALOG_OFFSET*2 + nOffY ); + long nBtnEx = 0; + + // Preview-Fenster beruecksichtigen und die Groessen/Offsets anpassen + if ( mpViewWindow && mpViewWindow->IsVisible() ) + { + long nViewOffX = 0; + long nViewOffY = 0; + long nViewWidth = 0; + long nViewHeight = 0; + USHORT nViewPosFlags = WINDOW_POSSIZE_POS; + Size aViewSize = mpViewWindow->GetSizePixel(); + if ( meViewAlign == WINDOWALIGN_TOP ) + { + nViewOffX = aTabOffset.X(); + nViewOffY = nOffY+IMPL_DIALOG_OFFSET; + nViewWidth = aTabSize.Width(); + nViewPosFlags |= WINDOW_POSSIZE_WIDTH; + aTabOffset.Y() += aViewSize.Height()+IMPL_DIALOG_OFFSET; + aDlgSize.Height() += aViewSize.Height()+IMPL_DIALOG_OFFSET; + } + else if ( meViewAlign == WINDOWALIGN_BOTTOM ) + { + nViewOffX = aTabOffset.X(); + nViewOffY = aTabOffset.Y()+aTabSize.Height()+IMPL_DIALOG_OFFSET; + nViewWidth = aTabSize.Width(); + nViewPosFlags |= WINDOW_POSSIZE_WIDTH; + aDlgSize.Height() += aViewSize.Height()+IMPL_DIALOG_OFFSET; + } + else if ( meViewAlign == WINDOWALIGN_RIGHT ) + { + nViewOffX = aTabOffset.X()+aTabSize.Width()+IMPL_DIALOG_OFFSET; + nViewOffY = aTabOffset.Y(); + nViewHeight = aTabSize.Height(); + nViewPosFlags |= WINDOW_POSSIZE_HEIGHT; + aDlgSize.Width() += aViewSize.Width()+IMPL_DIALOG_OFFSET; + nBtnEx = aViewSize.Width()+IMPL_DIALOG_OFFSET; + } + else // meViewAlign == WINDOWALIGN_LEFT + { + nViewOffX = IMPL_DIALOG_OFFSET; + nViewOffY = aTabOffset.Y(); + nViewHeight = aTabSize.Height(); + nViewPosFlags |= WINDOW_POSSIZE_HEIGHT; + aTabOffset.X() += aViewSize.Width()+IMPL_DIALOG_OFFSET; + aDlgSize.Width() += aViewSize.Width()+IMPL_DIALOG_OFFSET; + nBtnEx = aViewSize.Width()+IMPL_DIALOG_OFFSET; + } + + mpViewWindow->SetPosSizePixel( nViewOffX, nViewOffY, + nViewWidth, nViewHeight, + nViewPosFlags ); + } + + // Positionierung vornehmen + pTabControl->SetPosPixel( aTabOffset ); + + // Alle anderen Childs positionieren + BOOL bTabCtrl = FALSE; + int nLines = 0; + long nX; + long nY = aDlgSize.Height(); + long nTopX = IMPL_DIALOG_OFFSET; + + // Unter Windows 95 werden die Buttons rechtsbuendig angeordnet + nX = IMPL_DIALOG_OFFSET; + long nCtrlBarWidth = ((aCtrlSize.Width()+IMPL_DIALOG_OFFSET)*nDownCtrl)-IMPL_DIALOG_OFFSET; + if ( nCtrlBarWidth <= (aTabSize.Width()+nBtnEx) ) + nX = (aTabSize.Width()+nBtnEx) - nCtrlBarWidth + IMPL_DIALOG_OFFSET; + + Window* pChild2 = GetWindow( WINDOW_FIRSTCHILD ); + while ( pChild2 ) + { + if ( pChild2->IsVisible() && (pChild2 != mpViewWindow) ) + { + if ( pChild2 == pTabControl ) + bTabCtrl = TRUE; + else if ( bTabCtrl ) + { + if ( !nLines ) + nLines = 1; + + if ( nX+aCtrlSize.Width()-IMPL_DIALOG_OFFSET > (aTabSize.Width()+nBtnEx) ) + { + nY += aCtrlSize.Height()+IMPL_DIALOG_OFFSET; + nX = IMPL_DIALOG_OFFSET; + nLines++; + } + + pChild2->SetPosSizePixel( Point( nX, nY ), aCtrlSize ); + nX += aCtrlSize.Width()+IMPL_DIALOG_OFFSET; + } + else + { + Size aChildSize = pChild2->GetSizePixel(); + pChild2->SetPosPixel( Point( nTopX, (nOffY-aChildSize.Height())/2 ) ); + nTopX += aChildSize.Width()+2; + } + } + + pChild2 = pChild2->GetWindow( WINDOW_NEXT ); + } + + aDlgSize.Height() += nLines * (aCtrlSize.Height()+IMPL_DIALOG_OFFSET); + SetOutputSizePixel( aDlgSize ); + } + + // Offset merken + if ( nOffY ) + { + Size aDlgSize = GetOutputSizePixel(); + if ( !mpFixedLine ) + mpFixedLine = new FixedLine( this ); + mpFixedLine->SetPosSizePixel( Point( 0, nOffY ), + Size( aDlgSize.Width(), 2 ) ); + mpFixedLine->Show(); + } + + mbPosControls = FALSE; +} + +// ----------------------------------------------------------------------- + +TabDialog::TabDialog( Window* pParent, WinBits nStyle ) : + Dialog( WINDOW_TABDIALOG ) +{ + ImplInitTabDialogData(); + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +TabDialog::TabDialog( Window* pParent, const ResId& rResId ) : + Dialog( WINDOW_TABDIALOG ) +{ + ImplInitTabDialogData(); + rResId.SetRT( RSC_TABDIALOG ); + ImplInit( pParent, ImplInitRes( rResId ) ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +TabDialog::~TabDialog() +{ + if ( mpFixedLine ) + delete mpFixedLine; +} + +// ----------------------------------------------------------------------- + +void TabDialog::Resize() +{ +// !!! In the future the controls should be automaticly rearrange +// !!! if the window is resized +// !!! if ( !IsRollUp() ) +// !!! ImplPosControls(); +} + +// ----------------------------------------------------------------------- + +void TabDialog::StateChanged( StateChangedType nType ) +{ + if ( nType == STATE_CHANGE_INITSHOW ) + { + // Calculate the Layout only for the initialized state + if ( mbPosControls ) + ImplPosControls(); + } + Dialog::StateChanged( nType ); +} + +// ----------------------------------------------------------------------- + +void TabDialog::AdjustLayout() +{ + ImplPosControls(); +} + diff --git a/vcl/source/window/tabpage.cxx b/vcl/source/window/tabpage.cxx new file mode 100644 index 000000000000..0589d57009f4 --- /dev/null +++ b/vcl/source/window/tabpage.cxx @@ -0,0 +1,216 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <tools/ref.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/event.hxx> +#include <vcl/tabpage.hxx> +#include <vcl/tabctrl.hxx> +#include <vcl/bitmapex.hxx> +#include <com/sun/star/accessibility/XAccessible.hpp> + + + + +// ======================================================================= + +void TabPage::ImplInit( Window* pParent, WinBits nStyle ) +{ + if ( !(nStyle & WB_NODIALOGCONTROL) ) + nStyle |= WB_DIALOGCONTROL; + + Window::ImplInit( pParent, nStyle, NULL ); + + ImplInitSettings(); + + // if the tabpage is drawn (ie filled) by a native widget, make sure all contols will have transparent background + // otherwise they will paint with a wrong background + if( IsNativeControlSupported(CTRL_TAB_BODY, PART_ENTIRE_CONTROL) && GetParent() && (GetParent()->GetType() == WINDOW_TABCONTROL) ) + EnableChildTransparentMode( TRUE ); +} + +// ----------------------------------------------------------------------- + +void TabPage::ImplInitSettings() +{ + Window* pParent = GetParent(); + if ( pParent->IsChildTransparentModeEnabled() && !IsControlBackground() ) + { + EnableChildTransparentMode( TRUE ); + SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + SetPaintTransparent( TRUE ); + SetBackground(); + } + else + { + EnableChildTransparentMode( FALSE ); + SetParentClipMode( 0 ); + SetPaintTransparent( FALSE ); + + if ( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( pParent->GetBackground() ); + } +} + +// ----------------------------------------------------------------------- + +TabPage::TabPage( Window* pParent, WinBits nStyle ) : + Window( WINDOW_TABPAGE ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +TabPage::TabPage( Window* pParent, const ResId& rResId ) : + Window( WINDOW_TABPAGE ) +{ + rResId.SetRT( RSC_TABPAGE ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +void TabPage::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + { + if ( GetSettings().GetStyleSettings().GetAutoMnemonic() ) + ImplWindowAutoMnemonic( this ); + // FIXME: no layouting, workaround some clipping issues + ImplAdjustNWFSizes(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabPage::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void TabPage::Paint( const Rectangle& ) +{ + // draw native tabpage only inside tabcontrols, standalone tabpages look ugly (due to bad dialog design) + if( IsNativeControlSupported(CTRL_TAB_BODY, PART_ENTIRE_CONTROL) && GetParent() && (GetParent()->GetType() == WINDOW_TABCONTROL) ) + { + const ImplControlValue aControlValue; + + ControlState nState = CTRL_STATE_ENABLED; + int part = PART_ENTIRE_CONTROL; + if ( !IsEnabled() ) + nState &= ~CTRL_STATE_ENABLED; + if ( HasFocus() ) + nState |= CTRL_STATE_FOCUSED; + Point aPoint; + // pass the whole window region to NWF as the tab body might be a gradient or bitmap + // that has to be scaled properly, clipping makes sure that we do not paint too much + Rectangle aCtrlRegion( aPoint, GetOutputSizePixel() ); + DrawNativeControl( CTRL_TAB_BODY, part, aCtrlRegion, nState, + aControlValue, rtl::OUString() ); + } +} + +// ----------------------------------------------------------------------- +void TabPage::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG ) +{ + Point aPos = pDev->LogicToPixel( rPos ); + Size aSize = pDev->LogicToPixel( rSize ); + + Wallpaper aWallpaper = GetBackground(); + if ( !aWallpaper.IsBitmap() ) + ImplInitSettings(); + + pDev->Push(); + pDev->SetMapMode(); + pDev->SetLineColor(); + + if ( aWallpaper.IsBitmap() ) + pDev->DrawBitmapEx( aPos, aSize, aWallpaper.GetBitmap() ); + else + { + if( aWallpaper.GetColor() == COL_AUTO ) + pDev->SetFillColor( GetSettings().GetStyleSettings().GetDialogColor() ); + else + pDev->SetFillColor( aWallpaper.GetColor() ); + pDev->DrawRect( Rectangle( aPos, aSize ) ); + } + + pDev->Pop(); +} + +// ----------------------------------------------------------------------- + +void TabPage::ActivatePage() +{ +} + +// ----------------------------------------------------------------------- + +void TabPage::DeactivatePage() +{ +} + +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > TabPage::CreateAccessible() +{ + // TODO: remove this method (incompatible) + + return Window::CreateAccessible(); +} diff --git a/vcl/source/window/taskpanelist.cxx b/vcl/source/window/taskpanelist.cxx new file mode 100644 index 000000000000..1adabe487492 --- /dev/null +++ b/vcl/source/window/taskpanelist.cxx @@ -0,0 +1,398 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <vcl/svdata.hxx> +#include <tools/rcid.h> +#include <vcl/dockwin.hxx> + +#include <vcl/taskpanelist.hxx> +#include <functional> +#include <algorithm> + +// can't have static linkage because SUNPRO 5.2 complains +Point ImplTaskPaneListGetPos( const Window *w ) +{ + Point pos; + if( w->ImplIsDockingWindow() ) + { + pos = ((DockingWindow*)w)->GetPosPixel(); + Window *pF = ((DockingWindow*)w)->GetFloatingWindow(); + if( pF ) + pos = pF->OutputToAbsoluteScreenPixel( pF->ScreenToOutputPixel( pos ) ); + else + pos = w->OutputToAbsoluteScreenPixel( pos ); + } + else + pos = w->OutputToAbsoluteScreenPixel( w->GetPosPixel() ); + + return pos; +} + +// compares window pos left-to-right +struct LTRSort : public ::std::binary_function< const Window*, const Window*, bool > +{ + bool operator()( const Window* w1, const Window* w2 ) const + { + Point pos1(ImplTaskPaneListGetPos( w1 )); + Point pos2(ImplTaskPaneListGetPos( w2 )); + + if( pos1.X() == pos2.X() ) + return ( pos1.Y() < pos2.Y() ); + else + return ( pos1.X() < pos2.X() ); + } +}; +struct LTRSortBackward : public ::std::binary_function< const Window*, const Window*, bool > +{ + bool operator()( const Window* w2, const Window* w1 ) const + { + Point pos1(ImplTaskPaneListGetPos( w1 )); + Point pos2(ImplTaskPaneListGetPos( w2 )); + + if( pos1.X() == pos2.X() ) + return ( pos1.Y() < pos2.Y() ); + else + return ( pos1.X() < pos2.X() ); + } +}; + +// -------------------------------------------------- + +static void ImplTaskPaneListGrabFocus( Window *pWindow ) +{ + // put focus in child of floating windows which is typically a toolbar + // that can deal with the focus + if( pWindow->ImplIsFloatingWindow() && pWindow->GetWindow( WINDOW_FIRSTCHILD ) ) + pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD ); + pWindow->GrabFocus(); +} + +// -------------------------------------------------- + +TaskPaneList::TaskPaneList() +{ +} + +TaskPaneList::~TaskPaneList() +{ +} + +// -------------------------------------------------- + +void TaskPaneList::AddWindow( Window *pWindow ) +{ +#if OSL_DEBUG_LEVEL > 0 + bool bDockingWindow=false; + bool bToolbox=false; + bool bDialog=false; + bool bUnknown=false; +#endif + + if( pWindow ) + { +#if OSL_DEBUG_LEVEL > 0 + if( pWindow->GetType() == RSC_DOCKINGWINDOW ) + bDockingWindow = true; + else if( pWindow->GetType() == RSC_TOOLBOX ) + bToolbox = true; + else if( pWindow->IsDialog() ) + bDialog = true; + else + bUnknown = true; +#endif + + ::std::vector< Window* >::iterator insertionPos = mTaskPanes.end(); + for ( ::std::vector< Window* >::iterator p = mTaskPanes.begin(); + p != mTaskPanes.end(); + ++p + ) + { + if ( *p == pWindow ) + // avoid duplicates + return; + + // If the new window is the child of an existing pane window, or vice versa, + // ensure that in our pane list, *first* the child window appears, *then* + // the ancestor window. + // This is necessary for HandleKeyEvent: There, the list is traveled from the + // beginning, until the first window is found which has the ChildPathFocus. Now + // if this would be the ancestor window of another pane window, this would fudge + // the result + // 2004-09-27 - fs@openoffice.org, while fixing #i33573#, which included replacing + // the original fix for #98916# with this one here. + if ( pWindow->IsWindowOrChild( *p ) ) + { + insertionPos = p + 1; + break; + } + if ( (*p)->IsWindowOrChild( pWindow ) ) + { + insertionPos = p; + break; + } + } + + mTaskPanes.insert( insertionPos, pWindow ); + pWindow->ImplIsInTaskPaneList( TRUE ); + } +} + +// -------------------------------------------------- + +void TaskPaneList::RemoveWindow( Window *pWindow ) +{ + ::std::vector< Window* >::iterator p; + p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); + if( p != mTaskPanes.end() ) + { + mTaskPanes.erase( p ); + pWindow->ImplIsInTaskPaneList( FALSE ); + } +} + +// -------------------------------------------------- + +BOOL TaskPaneList::IsInList( Window *pWindow ) +{ + ::std::vector< Window* >::iterator p; + p = ::std::find( mTaskPanes.begin(), mTaskPanes.end(), pWindow ); + if( p != mTaskPanes.end() ) + return TRUE; + else + return FALSE; +} + +// -------------------------------------------------- + +BOOL TaskPaneList::HandleKeyEvent( KeyEvent aKeyEvent ) +{ + + // F6 cycles through everything and works always + + // MAV, #i104204# + // The old design was the following one: + // < Ctrl-TAB cycles through Menubar, Toolbars and Floatingwindows only and is + // < only active if one of those items has the focus + // + // Since the design of Ctrl-Tab looks to be inconsistent ( non-modal dialogs are not reachable + // and the shortcut conflicts with tab-control shortcut ), it is no more supported + BOOL bSplitterOnly = FALSE; + BOOL bFocusInList = FALSE; + KeyCode aKeyCode = aKeyEvent.GetKeyCode(); + BOOL bForward = !aKeyCode.IsShift(); + if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6 + { + bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift(); + + // is the focus in the list ? + ::std::vector< Window* >::iterator p = mTaskPanes.begin(); + while( p != mTaskPanes.end() ) + { + Window *pWin = *p; + if( pWin->HasChildPathFocus( TRUE ) ) + { + bFocusInList = TRUE; + + // Ctrl-F6 goes directly to the document + if( !pWin->IsDialog() && aKeyCode.IsMod1() && !aKeyCode.IsShift() ) + { + pWin->GrabFocusToDocument(); + return TRUE; + } + + // activate next task pane + Window *pNextWin = NULL; + + if( bSplitterOnly ) + pNextWin = FindNextSplitter( *p, TRUE ); + else + pNextWin = FindNextFloat( *p, bForward ); + + if( pNextWin != pWin ) + { + ImplGetSVData()->maWinData.mbNoSaveFocus = TRUE; + ImplTaskPaneListGrabFocus( pNextWin ); + ImplGetSVData()->maWinData.mbNoSaveFocus = FALSE; + } + else + { + // forward key if no splitter found + if( bSplitterOnly ) + return FALSE; + + // we did not find another taskpane, so + // put focus back into document + pWin->GrabFocusToDocument(); + } + + return TRUE; + } + else + p++; + } + + // the focus is not in the list: activate first float if F6 was pressed + if( !bFocusInList ) + { + Window *pWin; + if( bSplitterOnly ) + pWin = FindNextSplitter( NULL, TRUE ); + else + pWin = FindNextFloat( NULL, bForward ); + if( pWin ) + { + ImplTaskPaneListGrabFocus( pWin ); + return TRUE; + } + } + } + + return FALSE; +} + +// -------------------------------------------------- + +// returns next valid pane +Window* TaskPaneList::FindNextPane( Window *pWindow, BOOL bForward ) +{ + if( bForward ) + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); + else + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); + + ::std::vector< Window* >::iterator p = mTaskPanes.begin(); + while( p != mTaskPanes.end() ) + { + if( *p == pWindow ) + { + unsigned n = mTaskPanes.size(); + while( --n ) + { + if( ++p == mTaskPanes.end() ) + p = mTaskPanes.begin(); + if( (*p)->IsReallyVisible() && !(*p)->IsDialog() && !(*p)->ImplIsSplitter() ) + { + pWindow = *p; + break; + } + } + break; + } + else + ++p; + } + + return pWindow; +} + +// -------------------------------------------------- + +// returns next splitter +Window* TaskPaneList::FindNextSplitter( Window *pWindow, BOOL bForward ) +{ + if( bForward ) + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); + else + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); + + ::std::vector< Window* >::iterator p = mTaskPanes.begin(); + while( p != mTaskPanes.end() ) + { + if( !pWindow || *p == pWindow ) + { + unsigned n = mTaskPanes.size(); + while( --n ) + { + if( pWindow ) // increment before test + ++p; + if( p == mTaskPanes.end() ) + p = mTaskPanes.begin(); + if( (*p)->ImplIsSplitter() && (*p)->IsReallyVisible() && !(*p)->IsDialog() && (*p)->GetParent()->HasChildPathFocus() ) + { + pWindow = *p; + break; + } + if( !pWindow ) // increment after test, otherwise first element is skipped + ++p; + } + break; + } + else + ++p; + } + + return pWindow; +} + +// -------------------------------------------------- + +// returns first valid item (regardless of type) if pWindow==0, otherwise returns next valid float +Window* TaskPaneList::FindNextFloat( Window *pWindow, BOOL bForward ) +{ + if( bForward ) + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSort() ); + else + ::std::stable_sort( mTaskPanes.begin(), mTaskPanes.end(), LTRSortBackward() ); + + ::std::vector< Window* >::iterator p = mTaskPanes.begin(); + while( p != mTaskPanes.end() ) + { + if( !pWindow || *p == pWindow ) + { + while( p != mTaskPanes.end() ) + { + if( pWindow ) // increment before test + ++p; + if( p == mTaskPanes.end() ) + break; // do not wrap, send focus back to document at end of list + /* #i83908# do not use the menubar if it is native and invisible + this relies on MenuBar::ImplCreate setting the height of the menubar + to 0 in this case + */ + if( (*p)->IsReallyVisible() && !(*p)->ImplIsSplitter() && + ( (*p)->GetType() != WINDOW_MENUBARWINDOW || (*p)->GetSizePixel().Height() > 0 ) + ) + { + pWindow = *p; + break; + } + if( !pWindow ) // increment after test, otherwise first element is skipped + ++p; + } + break; + } + else + ++p; + } + + return pWindow; +} + +// -------------------------------------------------- + diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx new file mode 100644 index 000000000000..b71cf1c13c8d --- /dev/null +++ b/vcl/source/window/toolbox.cxx @@ -0,0 +1,6335 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <rtl/logfile.hxx> +#include <tools/list.hxx> +#include <tools/debug.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/event.hxx> +#include <vcl/decoview.hxx> +#include <vcl/accel.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> +#include <vcl/sound.hxx> +#include <vcl/virdev.hxx> +#include <vcl/spin.h> +#include <vcl/toolbox.hxx> +#include <vcl/toolbox.h> +#include <vcl/bitmap.hxx> +#include <tools/poly.hxx> +#include <vcl/salframe.hxx> +#include <vcl/mnemonic.hxx> +#include <vcl/gradient.hxx> +#include <vcl/menu.hxx> +#include <vcl/window.h> + +#include <string.h> +#include <vector> +#include <math.h> + +// ======================================================================= + +DBG_NAMEEX( Window ) + +// ======================================================================= + +#define SMALLBUTTON_HSIZE 7 +#define SMALLBUTTON_VSIZE 7 + +#define SMALLBUTTON_OFF_NORMAL_X 3 +#define SMALLBUTTON_OFF_NORMAL_Y 3 +#define SMALLBUTTON_OFF_CHECKED_X 4 +#define SMALLBUTTON_OFF_CHECKED_Y 4 +#define SMALLBUTTON_OFF_PRESSED_X 5 +#define SMALLBUTTON_OFF_PRESSED_Y 5 + +#define OUTBUTTON_SIZE 6 +#define OUTBUTTON_BORDER 4 +#define OUTBUTTON_OFF_NORMAL_X 1 +#define OUTBUTTON_OFF_NORMAL_Y 1 + +// ----------------------------------------------------------------------- + +#define DEF_MIN_WIDTH 8 +#define DEF_MIN_HEIGHT 8 +#define DEF_TEXT_WIDTH 40 + +#define TB_TEXTOFFSET 2 +#define TB_IMAGETEXTOFFSET 3 +#define TB_LINESPACING 3 +#define TB_SPIN_SIZE 14 +#define TB_SPIN_OFFSET 2 +#define TB_NEXT_SIZE 22 +#define TB_NEXT_OFFSET 2 +#define TB_BORDER_OFFSET1 4 +#define TB_BORDER_OFFSET2 2 +#define TB_CUSTOMIZE_OFFSET 2 +#define TB_RESIZE_OFFSET 3 +#define TB_MAXLINES 5 +#define TB_MAXNOSCROLL 32765 + +#define TB_MIN_WIN_WIDTH 20 + +#define TB_CALCMODE_HORZ 1 +#define TB_CALCMODE_VERT 2 +#define TB_CALCMODE_FLOAT 3 + +#define TB_WBLINESIZING (WB_SIZEABLE | WB_DOCKABLE | WB_SCROLL) + +#define TB_MAX_GROUPS 100 + +#define DOCK_LINEHSIZE ((USHORT)0x0001) +#define DOCK_LINEVSIZE ((USHORT)0x0002) +#define DOCK_LINERIGHT ((USHORT)0x1000) +#define DOCK_LINEBOTTOM ((USHORT)0x2000) +#define DOCK_LINELEFT ((USHORT)0x4000) +#define DOCK_LINETOP ((USHORT)0x8000) +#define DOCK_LINEOFFSET 3 + + +// ----------------------------------------------------------------------- +static void ImplDrawButton( ToolBox* pThis, const Rectangle &rRect, USHORT highlight, BOOL bChecked, BOOL bEnabled, BOOL bIsWindow ); +// ----------------------------------------------------------------------- + +struct ImplToolSize +{ + long mnWidth; + long mnHeight; + USHORT mnLines; +}; + +struct ImplToolSizeArray +{ + long mnLength; + long mnLastEntry; + ImplToolSize* mpSize; + + ImplToolSizeArray() { mpSize = NULL; mnLength = 0; mnLastEntry = 0; } + ~ImplToolSizeArray() { if( mpSize ) delete [] mpSize; mnLength = 0; } +}; + +// ----------------------------------------------------------------------- + +DECLARE_LIST( ImplTBList, ToolBox* ) + +class ImplTBDragMgr +{ +private: + ImplTBList* mpBoxList; + ToolBox* mpDragBox; + Point maMouseOff; + Rectangle maRect; + Rectangle maStartRect; + Accelerator maAccel; + long mnMinWidth; + long mnMaxWidth; + USHORT mnLineMode; + USHORT mnStartLines; + void* mpCustomizeData; + BOOL mbCustomizeMode; + BOOL mbResizeMode; + BOOL mbShowDragRect; + +public: + ImplTBDragMgr(); + ~ImplTBDragMgr(); + + void Insert( ToolBox* pBox ) + { mpBoxList->Insert( pBox ); } + void Remove( ToolBox* pBox ) + { mpBoxList->Remove( pBox ); } + ULONG Count() const + { return mpBoxList->Count(); } + + ToolBox* FindToolBox( const Rectangle& rRect ); + + void StartDragging( ToolBox* pDragBox, + const Point& rPos, const Rectangle& rRect, + USHORT nLineMode, BOOL bResizeItem, + void* pData = NULL ); + void Dragging( const Point& rPos ); + void EndDragging( BOOL bOK = TRUE ); + void HideDragRect() { if ( mbShowDragRect ) mpDragBox->HideTracking(); } + void UpdateDragRect(); + DECL_LINK( SelectHdl, Accelerator* ); + + void StartCustomizeMode(); + void EndCustomizeMode(); + BOOL IsCustomizeMode() { return mbCustomizeMode; } + BOOL IsResizeMode() { return mbResizeMode; } +}; + +// ----------------------------------------------------------------------- + +static ImplTBDragMgr* ImplGetTBDragMgr() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maCtrlData.mpTBDragMgr ) + pSVData->maCtrlData.mpTBDragMgr = new ImplTBDragMgr; + return pSVData->maCtrlData.mpTBDragMgr; +} + +// ----------------------------------------------------------------------- + +int ToolBox::ImplGetDragWidth( ToolBox* pThis ) +{ + #define TB_DRAGWIDTH 8 // the default width of the grip + + int width = TB_DRAGWIDTH; + if( pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) ) + { + + ImplControlValue aControlValue; + Point aPoint; + Rectangle aContent, aBound; + Rectangle aArea( aPoint, pThis->GetOutputSizePixel() ); + + if ( pThis->GetNativeControlRegion(CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_VERT : PART_THUMB_HORZ, + aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) ) + { + width = pThis->mbHorz ? aContent.GetWidth() : aContent.GetHeight(); + } + } + return width; +} + +ButtonType determineButtonType( ImplToolItem* pItem, ButtonType defaultType ) +{ + ButtonType tmpButtonType = defaultType; + ToolBoxItemBits nBits( pItem->mnBits & 0x300 ); + if ( nBits & TIB_TEXTICON ) // item has custom setting + { + tmpButtonType = BUTTON_SYMBOLTEXT; + if ( nBits == TIB_TEXT_ONLY ) + tmpButtonType = BUTTON_TEXT; + else if ( nBits == TIB_ICON_ONLY ) + tmpButtonType = BUTTON_SYMBOL; + } + return tmpButtonType; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplUpdateDragArea( ToolBox *pThis ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis ); + if( pWrapper ) + { + if ( pThis->ImplIsFloatingMode() || pWrapper->IsLocked() ) + pWrapper->SetDragArea( Rectangle() ); + else + { + if( pThis->meAlign == WINDOWALIGN_TOP || pThis->meAlign == WINDOWALIGN_BOTTOM ) + pWrapper->SetDragArea( Rectangle( 0, 0, ImplGetDragWidth( pThis ), pThis->GetOutputSizePixel().Height() ) ); + else + pWrapper->SetDragArea( Rectangle( 0, 0, pThis->GetOutputSizePixel().Width(), ImplGetDragWidth( pThis ) ) ); + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplCalcBorder( WindowAlign eAlign, long& rLeft, long& rTop, + long& rRight, long& rBottom, const ToolBox *pThis ) +{ + if( pThis->ImplIsFloatingMode() || !(pThis->mnWinStyle & WB_BORDER) ) + { + // no border in floating mode + rLeft = rTop = rRight = rBottom = 0; + return; + } + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis ); + + // reserve dragarea only for dockable toolbars + int dragwidth = ( pWrapper && !pWrapper->IsLocked() ) ? ImplGetDragWidth( (ToolBox*)pThis ) : 0; + + // no shadow border for dockable toolbars + int borderwidth = pWrapper ? 0: 2; + + if ( eAlign == WINDOWALIGN_TOP ) + { + rLeft = borderwidth+dragwidth; + rTop = borderwidth; + rRight = borderwidth; + rBottom = 0; + } + else if ( eAlign == WINDOWALIGN_LEFT ) + { + rLeft = borderwidth; + rTop = borderwidth+dragwidth; + rRight = 0; + rBottom = borderwidth; + } + else if ( eAlign == WINDOWALIGN_BOTTOM ) + { + rLeft = borderwidth+dragwidth; + rTop = 0; + rRight = borderwidth; + rBottom = borderwidth; + } + else + { + rLeft = 0; + rTop = borderwidth+dragwidth; + rRight = borderwidth; + rBottom = borderwidth; + } +} + +// ----------------------------------------------------------------------- + +static void ImplCheckUpdate( ToolBox *pThis ) +{ + // remove any pending invalidates to avoid + // have them triggered when paint is locked (see mpData->mbIsPaintLocked) + // which would result in erasing the background only and not painting any items + // this must not be done when we're already in Paint() + + // this is only required for transparent toolbars (see ImplDrawTransparentBackground() ) + if( !pThis->IsBackground() && pThis->HasPaintEvent() && !pThis->IsInPaint() ) + pThis->Update(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDrawGrip( ToolBox* pThis ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis ); + if( pWrapper && !pWrapper->GetDragArea().IsEmpty() ) + { + // execute pending paint requests + ImplCheckUpdate( pThis ); + + BOOL bNativeOk = FALSE; + if( pThis->IsNativeControlSupported( CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_HORZ : PART_THUMB_VERT ) ) + { + ToolbarValue aToolbarValue; + aToolbarValue.maGripRect = pWrapper->GetDragArea(); + Point aPt; + Rectangle aCtrlRegion( aPt, pThis->GetOutputSizePixel() ); + ControlState nState = CTRL_STATE_ENABLED; + + bNativeOk = pThis->DrawNativeControl( CTRL_TOOLBAR, pThis->mbHorz ? PART_THUMB_VERT : PART_THUMB_HORZ, + aCtrlRegion, nState, aToolbarValue, rtl::OUString() ); + } + + if( bNativeOk ) + return; + + const StyleSettings& rStyleSettings = pThis->GetSettings().GetStyleSettings(); + pThis->SetLineColor( rStyleSettings.GetShadowColor() ); + + Size aSz ( pThis->GetOutputSizePixel() ); + + if ( pThis->meAlign == WINDOWALIGN_TOP || pThis->meAlign == WINDOWALIGN_BOTTOM ) + { + int height = (int) (0.6 * aSz.Height() + 0.5); + int i = (aSz.Height() - height) / 2; + height += i; + while( i <= height ) + { + int x = ImplGetDragWidth( pThis ) / 2; + + pThis->DrawPixel( Point(x, i), rStyleSettings.GetDarkShadowColor() ); + pThis->DrawPixel( Point(x+1, i), rStyleSettings.GetShadowColor() ); + + pThis->DrawPixel( Point(x, i+1), rStyleSettings.GetShadowColor() ); + pThis->DrawPixel( Point(x+1, i+1), rStyleSettings.GetFaceColor() ); + pThis->DrawPixel( Point(x+2, i+1), Color(COL_WHITE) ); + + pThis->DrawPixel( Point(x+1, i+2), Color(COL_WHITE) ); + pThis->DrawPixel( Point(x+2, i+2), Color(COL_WHITE) ); + i+=4; + } + } + else + { + int width = (int) (0.6 * aSz.Width() + 0.5); + int i = (aSz.Width() - width) / 2; + width += i; + while( i <= width ) + { + int y = ImplGetDragWidth(pThis) / 2; + + pThis->DrawPixel( Point(i, y), rStyleSettings.GetDarkShadowColor() ); + pThis->DrawPixel( Point(i+1, y), rStyleSettings.GetShadowColor() ); + + pThis->DrawPixel( Point(i, y+1), rStyleSettings.GetShadowColor() ); + pThis->DrawPixel( Point(i+1, y+1), rStyleSettings.GetFaceColor() ); + pThis->DrawPixel( Point(i+2, y+1), Color(COL_WHITE) ); + + pThis->DrawPixel( Point(i+1, y+2), Color(COL_WHITE) ); + pThis->DrawPixel( Point(i+2, y+2), Color(COL_WHITE) ); + i+=4; + } + } + } +} + +void ToolBox::ImplDrawGradientBackground( ToolBox* pThis, ImplDockingWindowWrapper * ) +{ + // draw a nice gradient + + Color startCol, endCol; + startCol = pThis->GetSettings().GetStyleSettings().GetFaceGradientColor(); + endCol = pThis->GetSettings().GetStyleSettings().GetFaceColor(); + if( pThis->GetSettings().GetStyleSettings().GetHighContrastMode() ) + // no 'extreme' gradient when high contrast + startCol = endCol; + + Gradient g; + g.SetAngle( pThis->mbHorz ? 0 : 900 ); + g.SetStyle( GRADIENT_LINEAR ); + + g.SetStartColor( startCol ); + g.SetEndColor( endCol ); + + BOOL bLineColor = pThis->IsLineColor(); + Color aOldCol = pThis->GetLineColor(); + pThis->SetLineColor( pThis->GetSettings().GetStyleSettings().GetShadowColor() ); + + Size aFullSz( pThis->GetOutputSizePixel() ); + Size aLineSz( aFullSz ); + + // use the linesize only when floating + // full window height is used when docked (single line) + if( pThis->ImplIsFloatingMode() ) + { + long nLineSize; + if( pThis->mbHorz ) + { + nLineSize = pThis->mnMaxItemHeight; + if ( pThis->mnWinHeight > pThis->mnMaxItemHeight ) + nLineSize = pThis->mnWinHeight; + + aLineSz.Height() = nLineSize; + } + else + { + nLineSize = pThis->mnMaxItemWidth; + aLineSz.Width() = nLineSize; + } + } + + long nLeft, nTop, nRight, nBottom; + ImplCalcBorder( pThis->meAlign, nLeft, nTop, nRight, nBottom, pThis ); + + Size aTopLineSz( aLineSz ); + Size aBottomLineSz( aLineSz ); + + if ( pThis->mnWinStyle & WB_BORDER ) + { + if( pThis->mbHorz ) + { + aTopLineSz.Height() += TB_BORDER_OFFSET2 + nTop; + aBottomLineSz.Height() += TB_BORDER_OFFSET2 + nBottom; + + if( pThis->mnCurLines == 1 ) + aTopLineSz.Height() += TB_BORDER_OFFSET2 + nBottom; + } + else + { + aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft; + aBottomLineSz.Width() += TB_BORDER_OFFSET1 + nRight; + + if( pThis->mnCurLines == 1 ) + aTopLineSz.Width() += TB_BORDER_OFFSET1 + nLeft; + } + } + + if( pThis->mbHorz ) + { + aTopLineSz.Height() += pThis->mnBorderY; + if( pThis->mnCurLines == 1 ) + aTopLineSz.Height() += pThis->mnBorderY; + + aBottomLineSz.Height() += pThis->mnBorderY; + } + else + { + aTopLineSz.Width() += pThis->mnBorderX; + if( pThis->mnCurLines == 1 ) + aTopLineSz.Width() += pThis->mnBorderX; + + aBottomLineSz.Width() += pThis->mnBorderX; + } + + + if ( pThis->mnWinStyle & WB_LINESPACING ) + { + if( pThis->mbHorz ) + { + aLineSz.Height() += TB_LINESPACING; + if( pThis->mnCurLines > 1 ) + aTopLineSz.Height() += TB_LINESPACING; + } + else + { + aLineSz.Width() += TB_LINESPACING; + if( pThis->mnCurLines > 1 ) + aTopLineSz.Width() += TB_LINESPACING; + } + } + + if( pThis->mbHorz ) + { + long y = 0; + BOOL bDrawSep = FALSE; // pThis->ImplIsFloatingMode() && ( pThis->mnWinStyle & WB_LINESPACING ); + + pThis->DrawGradient( Rectangle( 0, y, aTopLineSz.Width(), y+aTopLineSz.Height()), g ); + y += aTopLineSz.Height(); + + if ( bDrawSep ) + pThis->DrawLine( Point(0, y-2), Point(aTopLineSz.Width(), y-2) ); + + while( y < (pThis->mnDY - aBottomLineSz.Height()) ) + { + pThis->DrawGradient( Rectangle( 0, y, aLineSz.Width(), y+aLineSz.Height()), g); + y += aLineSz.Height(); + + if ( bDrawSep ) + pThis->DrawLine( Point(0, y-2), Point(aLineSz.Width(), y-2) ); + } + + pThis->DrawGradient( Rectangle( 0, y, aBottomLineSz.Width(), y+aBottomLineSz.Height()), g ); + if ( bDrawSep ) + pThis->DrawLine( Point(0, y-2), Point(aBottomLineSz.Width(), y-2) ); + } + else + { + long x = 0; + + pThis->DrawGradient( Rectangle( x, 0, x+aTopLineSz.Width(), aTopLineSz.Height()), g ); + x += aTopLineSz.Width(); + + while( x < (pThis->mnDX - aBottomLineSz.Width()) ) + { + pThis->DrawGradient( Rectangle( x, 0, x+aLineSz.Width(), aLineSz.Height()), g); + x += aLineSz.Width(); + } + + pThis->DrawGradient( Rectangle( x, 0, x+aBottomLineSz.Width(), aBottomLineSz.Height()), g ); + } + + if( bLineColor ) + pThis->SetLineColor( aOldCol ); + +} + +BOOL ToolBox::ImplDrawNativeBackground( ToolBox* pThis, const Region & ) +{ + // use NWF + Point aPt; + Rectangle aCtrlRegion( aPt, pThis->GetOutputSizePixel() ); + ControlState nState = CTRL_STATE_ENABLED; + + return pThis->DrawNativeControl( CTRL_TOOLBAR, pThis->mbHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT, + aCtrlRegion, nState, ImplControlValue(), rtl::OUString() ); +} + +void ToolBox::ImplDrawTransparentBackground( ToolBox* pThis, const Region &rRegion ) +{ + // just invalidate to trigger paint of the parent + + const bool bOldPaintLock = pThis->mpData->mbIsPaintLocked; + pThis->mpData->mbIsPaintLocked = true; + + // send an invalidate to the first opaque parent and invalidate the whole hierarchy from there (noclipchildren) + pThis->Invalidate( rRegion, INVALIDATE_UPDATE|INVALIDATE_NOCLIPCHILDREN ); + + pThis->mpData->mbIsPaintLocked = bOldPaintLock; +} + +void ToolBox::ImplDrawConstantBackground( ToolBox* pThis, const Region &rRegion, BOOL bIsInPopupMode ) +{ + // draw a constant color + if( !bIsInPopupMode ) + // default background + pThis->Erase( rRegion.GetBoundRect() ); + else + { + // use different color in popupmode + pThis->DrawWallpaper( rRegion.GetBoundRect(), + Wallpaper( pThis->GetSettings().GetStyleSettings().GetFaceGradientColor() ) ); + } +} + + +void ToolBox::ImplDrawBackground( ToolBox* pThis, const Rectangle &rRect ) +{ + // execute pending paint requests + ImplCheckUpdate( pThis ); + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis ); + BOOL bIsInPopupMode = pThis->ImplIsInPopupMode(); + + Region aPaintRegion( rRect ); + + // make sure we do not invalidate/erase too much + if( pThis->IsInPaint() ) + aPaintRegion.Intersect( pThis->GetActiveClipRegion() ); + + pThis->Push( PUSH_CLIPREGION ); + pThis->IntersectClipRegion( aPaintRegion ); + + + if( !pWrapper /*|| bIsInPopupMode*/ ) + { + // no gradient for ordinary toolbars (not dockable) + if( !pThis->IsBackground() && !pThis->IsInPaint() ) + ImplDrawTransparentBackground( pThis, aPaintRegion ); + else + ImplDrawConstantBackground( pThis, aPaintRegion, bIsInPopupMode ); + } + else + { + // toolbars known to the dockingmanager will be drawn using NWF or a gradient + // docked toolbars are transparent and NWF is already used in the docking area which is their common background + // so NWF is used here for floating toolbars only + BOOL bNativeOk = FALSE; + if( pThis->ImplIsFloatingMode() && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL) ) + bNativeOk = ImplDrawNativeBackground( pThis, aPaintRegion ); + + if( !bNativeOk ) + { + if( !pThis->IsBackground() ) + { + if( !pThis->IsInPaint() ) + ImplDrawTransparentBackground( pThis, aPaintRegion ); + } + else + ImplDrawGradientBackground( pThis, pWrapper ); + } + } + + // restore clip region + pThis->Pop(); +} + +void ToolBox::ImplErase( ToolBox* pThis, const Rectangle &rRect, BOOL bHighlight, BOOL bHasOpenPopup ) +{ + // the background of non NWF buttons is painted in a constant color + // to have the same highlight color (transparency in DrawSelectionBackground()) + // items with open popups will also painted using a constant color + if( !pThis->mpData->mbNativeButtons && + (bHighlight || ! (((Window*) pThis)->GetStyle() & WB_3DLOOK ) ) ) + { + if( (((Window*) pThis)->GetStyle() & WB_3DLOOK ) ) + { + pThis->Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); + pThis->SetLineColor(); + if( bHasOpenPopup ) + // choose the same color as the popup will use + pThis->SetFillColor( pThis->GetSettings().GetStyleSettings().GetFaceGradientColor() ); + else + pThis->SetFillColor( Color( COL_WHITE ) ); + + pThis->DrawRect( rRect ); + pThis->Pop(); + } + else + ImplDrawBackground( pThis, rRect ); + } + else + ImplDrawBackground( pThis, rRect ); +} + +void ToolBox::ImplDrawBorder( ToolBox* pWin ) +{ + const StyleSettings& rStyleSettings = pWin->GetSettings().GetStyleSettings(); + long nDX = pWin->mnDX; + long nDY = pWin->mnDY; + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pWin ); + + // draw borders for ordinary toolbars only (not dockable) + if( pWrapper ) + return; + + if ( pWin->meAlign == WINDOWALIGN_BOTTOM ) + { + // draw bottom border + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + else + { + // draw top border + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( nDX-1, 0 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 0, 1 ), Point( nDX-1, 1 ) ); + + if ( (pWin->meAlign == WINDOWALIGN_LEFT) || (pWin->meAlign == WINDOWALIGN_RIGHT) ) + { + if ( pWin->meAlign == WINDOWALIGN_LEFT ) + { + // draw left-bottom border + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( 0, 0 ), Point( 0, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-1, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( 1, 1 ), Point( 1, nDY-3 ) ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + else + { + // draw right-bottom border + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-3 ) ); + pWin->DrawLine( Point( 0, nDY-2 ), Point( nDX-2, nDY-2 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) ); + pWin->DrawLine( Point( 0, nDY-1 ), Point( nDX-1, nDY-1 ) ); + } + } + } + + + if ( pWin->meAlign == WINDOWALIGN_BOTTOM || pWin->meAlign == WINDOWALIGN_TOP ) + { + // draw right border + pWin->SetLineColor( rStyleSettings.GetShadowColor() ); + pWin->DrawLine( Point( nDX-2, 0 ), Point( nDX-2, nDY-1 ) ); + pWin->SetLineColor( rStyleSettings.GetLightColor() ); + pWin->DrawLine( Point( nDX-1, 0 ), Point( nDX-1, nDY-1 ) ); + } +} + +// ----------------------------------------------------------------------- + +static bool ImplIsFixedControl( const ImplToolItem *pItem ) +{ + return ( pItem->mpWindow && + (pItem->mpWindow->GetType() == WINDOW_FIXEDTEXT || + pItem->mpWindow->GetType() == WINDOW_FIXEDLINE || + pItem->mpWindow->GetType() == WINDOW_GROUPBOX) ); +} + +// ----------------------------------------------------------------------- + +const ImplToolItem *ToolBox::ImplGetFirstClippedItem( const ToolBox* pThis ) +{ + std::vector< ImplToolItem >::const_iterator it; + it = pThis->mpData->m_aItems.begin(); + while ( it != pThis->mpData->m_aItems.end() ) + { + if( it->IsClipped() ) + return &(*it); + ++it; + } + return NULL; +} + +// ----------------------------------------------------------------------- + +Size ToolBox::ImplCalcSize( const ToolBox* pThis, USHORT nCalcLines, USHORT nCalcMode ) +{ + long nMax; + long nLeft = 0; + long nTop = 0; + long nRight = 0; + long nBottom = 0; + Size aSize; + WindowAlign eOldAlign = pThis->meAlign; + BOOL bOldHorz = pThis->mbHorz; + BOOL bOldAssumeDocked = pThis->mpData->mbAssumeDocked; + BOOL bOldAssumeFloating = pThis->mpData->mbAssumeFloating; + + if ( nCalcMode ) + { + BOOL bOldFloatingMode = pThis->ImplIsFloatingMode(); + + pThis->mpData->mbAssumeDocked = FALSE; + pThis->mpData->mbAssumeFloating = FALSE; + + if ( nCalcMode == TB_CALCMODE_HORZ ) + { + pThis->mpData->mbAssumeDocked = TRUE; // force non-floating mode during calculation + ImplCalcBorder( WINDOWALIGN_TOP, nLeft, nTop, nRight, nBottom, pThis ); + ((ToolBox*)pThis)->mbHorz = TRUE; + if ( pThis->mbHorz != bOldHorz ) + ((ToolBox*)pThis)->meAlign = WINDOWALIGN_TOP; + } + else if ( nCalcMode == TB_CALCMODE_VERT ) + { + pThis->mpData->mbAssumeDocked = TRUE; // force non-floating mode during calculation + ImplCalcBorder( WINDOWALIGN_LEFT, nLeft, nTop, nRight, nBottom, pThis ); + ((ToolBox*)pThis)->mbHorz = FALSE; + if ( pThis->mbHorz != bOldHorz ) + ((ToolBox*)pThis)->meAlign = WINDOWALIGN_LEFT; + } + else if ( nCalcMode == TB_CALCMODE_FLOAT ) + { + pThis->mpData->mbAssumeFloating = TRUE; // force non-floating mode during calculation + nLeft = nTop = nRight = nBottom = 0; + ((ToolBox*)pThis)->mbHorz = TRUE; + if ( pThis->mbHorz != bOldHorz ) + ((ToolBox*)pThis)->meAlign = WINDOWALIGN_TOP; + } + + if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) || + (pThis->ImplIsFloatingMode() != bOldFloatingMode ) ) + ((ToolBox*)pThis)->mbCalc = TRUE; + } + else + ImplCalcBorder( pThis->meAlign, nLeft, nTop, nRight, nBottom, pThis ); + + ((ToolBox*)pThis)->ImplCalcItem(); + + if( !nCalcMode && pThis->ImplIsFloatingMode() ) + { + aSize = ImplCalcFloatSize( ((ToolBox*)pThis), nCalcLines ); + } + else + { + if ( pThis->mbHorz ) + { + if ( pThis->mnWinHeight > pThis->mnMaxItemHeight ) + aSize.Height() = nCalcLines * pThis->mnWinHeight; + else + aSize.Height() = nCalcLines * pThis->mnMaxItemHeight; + + if ( pThis->mnWinStyle & WB_LINESPACING ) + aSize.Height() += (nCalcLines-1)*TB_LINESPACING; + + if ( pThis->mnWinStyle & WB_BORDER ) + aSize.Height() += (TB_BORDER_OFFSET2*2) + nTop + nBottom; + + nMax = 0; + ((ToolBox*)pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz ); + if ( nMax ) + aSize.Width() += nMax; + + if ( pThis->mnWinStyle & WB_BORDER ) + aSize.Width() += (TB_BORDER_OFFSET1*2) + nLeft + nRight; + } + else + { + aSize.Width() = nCalcLines * pThis->mnMaxItemWidth; + + if ( pThis->mnWinStyle & WB_LINESPACING ) + aSize.Width() += (nCalcLines-1)*TB_LINESPACING; + + if ( pThis->mnWinStyle & WB_BORDER ) + aSize.Width() += (TB_BORDER_OFFSET2*2) + nLeft + nRight; + + nMax = 0; + ((ToolBox*)pThis)->ImplCalcBreaks( TB_MAXNOSCROLL, &nMax, pThis->mbHorz ); + if ( nMax ) + aSize.Height() += nMax; + + if ( pThis->mnWinStyle & WB_BORDER ) + aSize.Height() += (TB_BORDER_OFFSET1*2) + nTop + nBottom; + } + } + // restore previous values + if ( nCalcMode ) + { + pThis->mpData->mbAssumeDocked = bOldAssumeDocked; + pThis->mpData->mbAssumeFloating = bOldAssumeFloating; + if ( (pThis->meAlign != eOldAlign) || (pThis->mbHorz != bOldHorz) ) + { + ((ToolBox*)pThis)->meAlign = eOldAlign; + ((ToolBox*)pThis)->mbHorz = bOldHorz; + ((ToolBox*)pThis)->mbCalc = TRUE; + } + } + + if ( aSize.Width() ) + aSize.Width() += pThis->mnBorderX*2; + if ( aSize.Height() ) + aSize.Height() += pThis->mnBorderY*2; + + return aSize; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplCalcFloatSizes( ToolBox* pThis ) +{ + if ( pThis->mpFloatSizeAry ) + return; + + // calculate the minimal size, i.e. where the biggest item just fits + long nCalcSize = 0; + + std::vector< ImplToolItem >::const_iterator it; + it = pThis->mpData->m_aItems.begin(); + while ( it != pThis->mpData->m_aItems.end() ) + { + if ( it->mbVisible ) + { + if ( it->mpWindow ) + { + long nTempSize = it->mpWindow->GetSizePixel().Width(); + if ( nTempSize > nCalcSize ) + nCalcSize = nTempSize; + } + else + { + if( it->maItemSize.Width() > nCalcSize ) + nCalcSize = it->maItemSize.Width(); + } + } + ++it; + } + + // calc an upper bound for ImplCalcBreaks below + long upperBoundWidth = nCalcSize * pThis->mpData->m_aItems.size(); + + USHORT i; + USHORT nLines; + USHORT nCalcLines; + USHORT nTempLines; + long nHeight; + long nMaxLineWidth; + nCalcLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, TRUE ); + + pThis->mpFloatSizeAry = new ImplToolSizeArray; + pThis->mpFloatSizeAry->mpSize = new ImplToolSize[nCalcLines]; + pThis->mpFloatSizeAry->mnLength = nCalcLines; + + memset( pThis->mpFloatSizeAry->mpSize, 0, sizeof( ImplToolSize )*nCalcLines ); + i = 0; + nTempLines = nLines = nCalcLines; + while ( nLines ) + { + nHeight = ImplCalcSize( pThis, nTempLines, TB_CALCMODE_FLOAT ).Height(); + pThis->mpFloatSizeAry->mnLastEntry = i; + pThis->mpFloatSizeAry->mpSize[i].mnHeight = nHeight; + pThis->mpFloatSizeAry->mpSize[i].mnLines = nTempLines; + pThis->mpFloatSizeAry->mpSize[i].mnWidth = nMaxLineWidth+(TB_BORDER_OFFSET1*2); + nLines--; + if ( nLines ) + { + do + { + nCalcSize += pThis->mnMaxItemWidth; + nTempLines = pThis->ImplCalcBreaks( nCalcSize, &nMaxLineWidth, TRUE ); + } + while ( (nCalcSize < upperBoundWidth) && (nLines < nTempLines) && (nTempLines != 1) ); + if ( nTempLines < nLines ) + nLines = nTempLines; + } + i++; + } +} + +// ----------------------------------------------------------------------- + +Size ToolBox::ImplCalcFloatSize( ToolBox* pThis, USHORT& rLines ) +{ + ImplCalcFloatSizes( pThis ); + + if ( !rLines ) + { + rLines = pThis->mnFloatLines; + if ( !rLines ) + rLines = pThis->mnLines; + } + + USHORT i = 0; + while ( i < pThis->mpFloatSizeAry->mnLastEntry && + rLines < pThis->mpFloatSizeAry->mpSize[i].mnLines ) + i++; + + Size aSize( pThis->mpFloatSizeAry->mpSize[i].mnWidth, + pThis->mpFloatSizeAry->mpSize[i].mnHeight ); + rLines = pThis->mpFloatSizeAry->mpSize[i].mnLines; + if ( pThis->maNextToolBoxStr.Len() && pThis->mbScroll ) + aSize.Width() += TB_NEXT_SIZE-TB_NEXT_OFFSET; + return aSize; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplCalcMinMaxFloatSize( ToolBox* pThis, Size& rMinSize, Size& rMaxSize ) +{ + ImplCalcFloatSizes( pThis ); + + USHORT i = 0; + rMinSize = Size( pThis->mpFloatSizeAry->mpSize[i].mnWidth, pThis->mpFloatSizeAry->mpSize[i].mnHeight ); + rMaxSize = Size( pThis->mpFloatSizeAry->mpSize[i].mnWidth, pThis->mpFloatSizeAry->mpSize[i].mnHeight ); + while ( ++i <= pThis->mpFloatSizeAry->mnLastEntry ) + { + if( pThis->mpFloatSizeAry->mpSize[i].mnWidth < rMinSize.Width() ) + rMinSize.Width() = pThis->mpFloatSizeAry->mpSize[i].mnWidth; + if( pThis->mpFloatSizeAry->mpSize[i].mnHeight < rMinSize.Height() ) + rMinSize.Height() = pThis->mpFloatSizeAry->mpSize[i].mnHeight; + + if( pThis->mpFloatSizeAry->mpSize[i].mnWidth > rMaxSize.Width() ) + rMaxSize.Width() = pThis->mpFloatSizeAry->mpSize[i].mnWidth; + if( pThis->mpFloatSizeAry->mpSize[i].mnHeight > rMaxSize.Height() ) + rMaxSize.Height() = pThis->mpFloatSizeAry->mpSize[i].mnHeight; + } +} + +void ToolBox::ImplSetMinMaxFloatSize( ToolBox *pThis ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( pThis ); + Size aMinSize, aMaxSize; + ImplCalcMinMaxFloatSize( pThis, aMinSize, aMaxSize ); + if( pWrapper ) + { + pWrapper->SetMinOutputSizePixel( aMinSize ); + pWrapper->SetMaxOutputSizePixel( aMaxSize ); + pWrapper->ShowTitleButton( TITLE_BUTTON_MENU, ( pThis->GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE) ? TRUE : FALSE ); + } + else + { + // TODO: change SetMinOutputSizePixel to be not inline + pThis->SetMinOutputSizePixel( aMinSize ); + pThis->SetMaxOutputSizePixel( aMaxSize ); + } +} + +// ----------------------------------------------------------------------- + + +USHORT ToolBox::ImplCalcLines( ToolBox* pThis, long nToolSize ) +{ + long nLineHeight; + + if ( pThis->mbHorz ) + { + if ( pThis->mnWinHeight > pThis->mnMaxItemHeight ) + nLineHeight = pThis->mnWinHeight; + else + nLineHeight = pThis->mnMaxItemHeight; + } + else + nLineHeight = pThis->mnMaxItemWidth; + + if ( pThis->mnWinStyle & WB_BORDER ) + nToolSize -= TB_BORDER_OFFSET2*2; + + if ( pThis->mnWinStyle & WB_LINESPACING ) + { + nLineHeight += TB_LINESPACING; + nToolSize += TB_LINESPACING; + } + + // #i91917# always report at least one line + long nLines = nToolSize/nLineHeight; + if( nLines < 1 ) + nLines = 1; + + return static_cast<USHORT>(nLines); +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::ImplTestLineSize( ToolBox* pThis, const Point& rPos ) +{ + if ( !pThis->ImplIsFloatingMode() && + (!pThis->mbScroll || (pThis->mnLines > 1) || (pThis->mnCurLines > pThis->mnVisLines)) ) + { + WindowAlign eAlign = pThis->GetAlign(); + + if ( eAlign == WINDOWALIGN_LEFT ) + { + if ( rPos.X() > pThis->mnDX-DOCK_LINEOFFSET ) + return DOCK_LINEHSIZE | DOCK_LINERIGHT; + } + else if ( eAlign == WINDOWALIGN_TOP ) + { + if ( rPos.Y() > pThis->mnDY-DOCK_LINEOFFSET ) + return DOCK_LINEVSIZE | DOCK_LINEBOTTOM; + } + else if ( eAlign == WINDOWALIGN_RIGHT ) + { + if ( rPos.X() < DOCK_LINEOFFSET ) + return DOCK_LINEHSIZE | DOCK_LINELEFT; + } + else if ( eAlign == WINDOWALIGN_BOTTOM ) + { + if ( rPos.Y() < DOCK_LINEOFFSET ) + return DOCK_LINEVSIZE | DOCK_LINETOP; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplLineSizing( ToolBox* pThis, const Point& rPos, Rectangle& rRect, + USHORT nLineMode ) +{ + BOOL mbHorz; + long nOneLineSize; + long nCurSize; + long nMaxSize; + long nSize; + Size aSize; + + if ( nLineMode & DOCK_LINERIGHT ) + { + nCurSize = rPos.X() - rRect.Left(); + mbHorz = FALSE; + } + else if ( nLineMode & DOCK_LINEBOTTOM ) + { + nCurSize = rPos.Y() - rRect.Top(); + mbHorz = TRUE; + } + else if ( nLineMode & DOCK_LINELEFT ) + { + nCurSize = rRect.Right() - rPos.X(); + mbHorz = FALSE; + } + else if ( nLineMode & DOCK_LINETOP ) + { + nCurSize = rRect.Bottom() - rPos.Y(); + mbHorz = TRUE; + } + else { + DBG_ERROR( "ImplLineSizing: Trailing else" ); + nCurSize = 0; + mbHorz = FALSE; + } + + Size aWinSize = pThis->GetSizePixel(); + USHORT nMaxLines = (pThis->mnLines > pThis->mnCurLines) ? pThis->mnLines : pThis->mnCurLines; + if ( nMaxLines > TB_MAXLINES ) + nMaxLines = TB_MAXLINES; + if ( mbHorz ) + { + nOneLineSize = ImplCalcSize( pThis, 1 ).Height(); + nMaxSize = pThis->maOutDockRect.GetHeight() - 20; + if ( nMaxSize < aWinSize.Height() ) + nMaxSize = aWinSize.Height(); + } + else + { + nOneLineSize = ImplCalcSize( pThis, 1 ).Width(); + nMaxSize = pThis->maOutDockRect.GetWidth() - 20; + if ( nMaxSize < aWinSize.Width() ) + nMaxSize = aWinSize.Width(); + } + + USHORT i = 1; + if ( nCurSize <= nOneLineSize ) + nSize = nOneLineSize; + else + { + nSize = 0; + while ( (nSize < nCurSize) && (i < nMaxLines) ) + { + i++; + aSize = ImplCalcSize( pThis, i ); + if ( mbHorz ) + nSize = aSize.Height(); + else + nSize = aSize.Width(); + if ( nSize > nMaxSize ) + { + i--; + aSize = ImplCalcSize( pThis, i ); + if ( mbHorz ) + nSize = aSize.Height(); + else + nSize = aSize.Width(); + break; + } + } + } + + if ( nLineMode & DOCK_LINERIGHT ) + rRect.Right() = rRect.Left()+nSize-1; + else if ( nLineMode & DOCK_LINEBOTTOM ) + rRect.Bottom() = rRect.Top()+nSize-1; + else if ( nLineMode & DOCK_LINELEFT ) + rRect.Left() = rRect.Right()-nSize; + else //if ( nLineMode & DOCK_LINETOP ) + rRect.Top() = rRect.Bottom()-nSize; + + pThis->mnDockLines = i; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::ImplFindItemPos( ToolBox* pBox, const Point& rPos ) +{ + USHORT nPos = 0; + long nLast = 0; + Point aPos = rPos; + Size aSize( pBox->mnDX, pBox->mnDY ); + + if ( aPos.X() > aSize.Width()-TB_BORDER_OFFSET1 ) + aPos.X() = aSize.Width()-TB_BORDER_OFFSET1; + if ( aPos.Y() > aSize.Height()-TB_BORDER_OFFSET1 ) + aPos.Y() = aSize.Height()-TB_BORDER_OFFSET1; + + // Item suchen, das geklickt wurde + std::vector< ImplToolItem >::const_iterator it = pBox->mpData->m_aItems.begin(); + while ( it != pBox->mpData->m_aItems.end() ) + { + if ( it->mbVisible ) + { + if ( nLast || !it->maRect.IsEmpty() ) + { + if ( pBox->mbHorz ) + { + if ( nLast && + ((nLast < it->maRect.Top()) || it->maRect.IsEmpty()) ) + return nPos; + + if ( aPos.Y() <= it->maRect.Bottom() ) + { + if ( aPos.X() < it->maRect.Left() ) + return nPos; + else if ( aPos.X() < it->maRect.Right() ) + return nPos+1; + else if ( !nLast ) + nLast = it->maRect.Bottom(); + } + } + else + { + if ( nLast && + ((nLast < it->maRect.Left()) || it->maRect.IsEmpty()) ) + return nPos; + + if ( aPos.X() <= it->maRect.Right() ) + { + if ( aPos.Y() < it->maRect.Top() ) + return nPos; + else if ( aPos.Y() < it->maRect.Bottom() ) + return nPos+1; + else if ( !nLast ) + nLast = it->maRect.Right(); + } + } + } + } + + nPos++; + ++it; + } + + return nPos; +} + +// ----------------------------------------------------------------------- + +ImplTBDragMgr::ImplTBDragMgr() +{ + mpBoxList = new ImplTBList( 4, 4 ); + mnLineMode = 0; + mnStartLines = 0; + mbCustomizeMode = FALSE; + mbResizeMode = FALSE; + mbShowDragRect = FALSE; + mpDragBox = NULL; + + maAccel.InsertItem( KEY_RETURN, KeyCode( KEY_RETURN ) ); + maAccel.InsertItem( KEY_ESCAPE, KeyCode( KEY_ESCAPE ) ); + maAccel.SetSelectHdl( LINK( this, ImplTBDragMgr, SelectHdl ) ); +} + +// ----------------------------------------------------------------------- + +ImplTBDragMgr::~ImplTBDragMgr() +{ + delete mpBoxList; +} + +// ----------------------------------------------------------------------- + +ToolBox* ImplTBDragMgr::FindToolBox( const Rectangle& rRect ) +{ + ToolBox* pBox = mpBoxList->First(); + while ( pBox ) + { + /* + * FIXME: since we can have multiple frames now we cannot + * find the drag target by its position alone. + * As long as the toolbar config dialogue is not a system window + * this works in one frame only anyway. If the dialogue + * changes to a system window, we need a new implementation here + */ + if ( pBox->IsReallyVisible() && pBox->ImplGetWindowImpl()->mpFrame == mpDragBox->ImplGetWindowImpl()->mpFrame ) + { + if ( !pBox->ImplIsFloatingMode() ) + { + Point aPos = pBox->GetPosPixel(); + aPos = pBox->GetParent()->OutputToScreenPixel( aPos ); + Rectangle aTempRect( aPos, pBox->GetSizePixel() ); + if ( aTempRect.IsOver( rRect ) ) + return pBox; + } + } + + pBox = mpBoxList->Next(); + } + + return pBox; +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::StartDragging( ToolBox* pToolBox, + const Point& rPos, const Rectangle& rRect, + USHORT nDragLineMode, BOOL bResizeItem, + void* pData ) +{ + mpDragBox = pToolBox; + pToolBox->CaptureMouse(); + pToolBox->mbDragging = TRUE; + Application::InsertAccel( &maAccel ); + + if ( nDragLineMode ) + { + mnLineMode = nDragLineMode; + mnStartLines = pToolBox->mnDockLines; + } + else + { + mpCustomizeData = pData; + mbResizeMode = bResizeItem; + pToolBox->Activate(); + pToolBox->mnCurItemId = pToolBox->mnConfigItem; + pToolBox->Highlight(); + pToolBox->mnCurItemId = 0; + if ( mbResizeMode ) + { + if ( rRect.GetWidth() < TB_MIN_WIN_WIDTH ) + mnMinWidth = rRect.GetWidth(); + else + mnMinWidth = TB_MIN_WIN_WIDTH; + mnMaxWidth = pToolBox->GetSizePixel().Width()-rRect.Left()- + TB_SPIN_SIZE-TB_BORDER_OFFSET1-(TB_SPIN_OFFSET*2); + } + } + + // MouseOffset berechnen + maMouseOff.X() = rRect.Left() - rPos.X(); + maMouseOff.Y() = rRect.Top() - rPos.Y(); + maRect = rRect; + maStartRect = rRect; + mbShowDragRect = TRUE; + pToolBox->ShowTracking( maRect ); +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::Dragging( const Point& rPos ) +{ + if ( mnLineMode ) + { + ToolBox::ImplLineSizing( mpDragBox, rPos, maRect, mnLineMode ); + Point aOff = mpDragBox->OutputToScreenPixel( Point() ); + maRect.Move( aOff.X(), aOff.Y() ); + mpDragBox->Docking( rPos, maRect ); + maRect.Move( -aOff.X(), -aOff.Y() ); + mpDragBox->ShowTracking( maRect ); + } + else + { + if ( mbResizeMode ) + { + long nXOff = rPos.X()-maStartRect.Left(); + nXOff += maMouseOff.X()+(maStartRect.Right()-maStartRect.Left()); + if ( nXOff < mnMinWidth ) + nXOff = mnMinWidth; + if ( nXOff > mnMaxWidth ) + nXOff = mnMaxWidth; + maRect.Right() = maStartRect.Left()+nXOff; + } + else + { + maRect.SetPos( rPos ); + maRect.Move( maMouseOff.X(), maMouseOff.Y() ); + } + mpDragBox->ShowTracking( maRect ); + } +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::EndDragging( BOOL bOK ) +{ + mpDragBox->HideTracking(); + mpDragBox->ReleaseMouse(); + mpDragBox->mbDragging = FALSE; + mbShowDragRect = FALSE; + Application::RemoveAccel( &maAccel ); + + if ( mnLineMode ) + { + if ( !bOK ) + { + mpDragBox->mnDockLines = mnStartLines; + mpDragBox->EndDocking( maStartRect, FALSE ); + } + else + mpDragBox->EndDocking( maRect, FALSE ); + mnLineMode = 0; + mnStartLines = 0; + } + else + { + USHORT nTempItem = mpDragBox->mnConfigItem; + if ( nTempItem ) + { + mpDragBox->mnConfigItem = 0; + if ( !mbResizeMode ) + mpDragBox->Invalidate( mpDragBox->GetItemRect( nTempItem ) ); + } + + if ( bOK && (maRect != maStartRect) ) + { + if ( mbResizeMode ) + { + ImplToolItem* pItem = mpDragBox->ImplGetItem( nTempItem ); + Size aSize = pItem->mpWindow->GetSizePixel(); + aSize.Width() = maRect.GetWidth(); + pItem->mpWindow->SetSizePixel( aSize ); + + // ToolBox neu brechnen und neu ausgeben + mpDragBox->ImplInvalidate( TRUE ); + mpDragBox->Customize( ToolBoxCustomizeEvent( mpDragBox, nTempItem, + TOOLBOX_CUSTOMIZE_RESIZE, + mpCustomizeData ) ); + } + else + { + Point aOff = mpDragBox->OutputToScreenPixel( Point() ); + Rectangle aScreenRect( maRect ); + aScreenRect.Move( aOff.X(), aOff.Y() ); + ToolBox* pDropBox = FindToolBox( aScreenRect ); + if ( pDropBox ) + { + // Such-Position bestimmen + Point aPos; + if ( pDropBox->mbHorz ) + { + aPos.X() = aScreenRect.Left()-TB_CUSTOMIZE_OFFSET; + aPos.Y() = aScreenRect.Center().Y(); + } + else + { + aPos.X() = aScreenRect.Center().X(); + aPos.Y() = aScreenRect.Top()-TB_CUSTOMIZE_OFFSET; + } + + aPos = pDropBox->ScreenToOutputPixel( aPos ); + USHORT nPos = ToolBox::ImplFindItemPos( pDropBox, aPos ); + mpDragBox->Customize( ToolBoxCustomizeEvent( pDropBox, nTempItem, + nPos, mpCustomizeData ) ); + } + else + { + mpDragBox->Customize( ToolBoxCustomizeEvent( NULL, nTempItem, + 0, mpCustomizeData ) ); + } + } + } + mpCustomizeData = NULL; + mbResizeMode = FALSE; + mpDragBox->Deactivate(); + } + + mpDragBox = NULL; +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::UpdateDragRect() +{ + // Nur Updaten, wenn wir schon im Dragging sind + if ( !mbShowDragRect ) + return; + + mpDragBox->ShowTracking( maRect ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ImplTBDragMgr, SelectHdl, Accelerator*, pAccel ) +{ + if ( pAccel->GetCurItemId() == KEY_ESCAPE ) + EndDragging( FALSE ); + else + EndDragging( TRUE ); + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::StartCustomizeMode() +{ + mbCustomizeMode = TRUE; + + ToolBox* pBox = mpBoxList->First(); + while ( pBox ) + { + pBox->ImplStartCustomizeMode(); + pBox = mpBoxList->Next(); + } +} + +// ----------------------------------------------------------------------- + +void ImplTBDragMgr::EndCustomizeMode() +{ + mbCustomizeMode = FALSE; + + ToolBox* pBox = mpBoxList->First(); + while ( pBox ) + { + pBox->ImplEndCustomizeMode(); + pBox = mpBoxList->Next(); + } +} + +// ----------------------------------------------------------------------- + + +static void ImplDrawOutButton( OutputDevice* pOutDev, const Rectangle& rRect, + USHORT nStyle ) +{ + const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); + Color aShadowColor = rStyleSettings.GetShadowColor(); + Point aPos( rRect.TopLeft() ); + Size aSize( rRect.GetSize() ); + long nOffset = 0; + + if ( pOutDev->GetBackground().GetColor() == aShadowColor ) + aShadowColor = rStyleSettings.GetDarkShadowColor(); + + if ( nStyle & BUTTON_DRAW_PRESSED ) + { + aPos.X()++; + aPos.Y()++; + nOffset++; + } + + // Hintergrund loeschen + pOutDev->Erase( rRect ); + + // Button zeichnen + pOutDev->SetLineColor( rStyleSettings.GetLightColor() ); + pOutDev->DrawLine( aPos, + Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y() ) ); + pOutDev->DrawLine( aPos, + Point( aPos.X(), aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) ); + pOutDev->SetLineColor( aShadowColor ); + pOutDev->DrawLine( Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y() ), + Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) ); + pOutDev->DrawLine( Point( aPos.X(), aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ), + Point( aPos.X()+aSize.Width()-OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-OUTBUTTON_BORDER ) ); + for ( long i = 0; i < OUTBUTTON_BORDER-1-nOffset; i++ ) + { + pOutDev->DrawLine( Point( aPos.X()+aSize.Width()-(OUTBUTTON_BORDER-i-1), aPos.Y()+OUTBUTTON_BORDER ), + Point( aPos.X()+aSize.Width()-(OUTBUTTON_BORDER-i-1), aPos.Y()+aSize.Height()-1 ) ); + pOutDev->DrawLine( Point( aPos.X()+OUTBUTTON_BORDER, aPos.Y()+aSize.Height()-(OUTBUTTON_BORDER-i-1) ), + Point( aPos.X()+aSize.Width()-1, aPos.Y()+aSize.Height()-(OUTBUTTON_BORDER-i-1) ) ); + } +} + + +// ----------------------------------------------------------------------- + +void ToolBox::ImplInit( Window* pParent, WinBits nStyle ) +{ + + // Variablen initialisieren + ImplGetWindowImpl()->mbToolBox = TRUE; + mpBtnDev = NULL; + mpFloatSizeAry = NULL; + mpData = new ImplToolBoxPrivateData; + mpFloatWin = NULL; + mnDX = 0; + mnDY = 0; + mnMaxItemWidth = 0; + mnMaxItemHeight = 0; + mnWinHeight = 0; + mnBorderX = 0; + mnBorderY = 0; + mnLeftBorder = 0; + mnTopBorder = 0; + mnRightBorder = 0; + mnBottomBorder = 0; + mnLastResizeDY = 0; + mnOutStyle = TOOLBOX_STYLE_FLAT; // force flat buttons since NWF + mnHighItemId = 0; + mnCurItemId = 0; + mnDownItemId = 0; + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnFocusPos = TOOLBOX_ITEM_NOTFOUND; // current position during keyboard access + mnLines = 1; + mnCurLine = 1; + mnCurLines = 1; + mnVisLines = 1; + mnFloatLines = 0; + mnConfigItem = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; + mbDrag = FALSE; + mbSelection = FALSE; + mbCommandDrag = FALSE; + mbUpper = FALSE; + mbLower = FALSE; + mbNextTool = FALSE; + mbIn = FALSE; + mbCalc = TRUE; + mbFormat = FALSE; + mbFullPaint = FALSE; + mbHorz = TRUE; + mbScroll = (nStyle & WB_SCROLL) != 0; + mbCustomize = FALSE; + mbCustomizeMode = FALSE; + mbDragging = FALSE; + mbHideStatusText = FALSE; + mbMenuStrings = FALSE; + mbIsShift = FALSE; + mbIsKeyEvent = FALSE; + mbChangingHighlight = FALSE; + meButtonType = BUTTON_SYMBOL; + meAlign = WINDOWALIGN_TOP; + meLastStyle = POINTER_ARROW; + mnWinStyle = nStyle; + mnLastFocusItemId = 0; + mnKeyModifier = 0; + mnActivateCount = 0; + + maTimer.SetTimeout( 50 ); + maTimer.SetTimeoutHdl( LINK( this, ToolBox, ImplUpdateHdl ) ); + + // set timeout and handler for dropdown items + mpData->maDropdownTimer.SetTimeout( 250 ); + mpData->maDropdownTimer.SetTimeoutHdl( LINK( this, ToolBox, ImplDropdownLongClickHdl ) ); + + DockingWindow::ImplInit( pParent, nStyle & ~(WB_BORDER) ); + + + // always set WB_TABSTOP for ToolBars !!! if( mnWinStyle & WB_TABSTOP ) + { + // dockingwindow's ImplInit removes some bits, so restore them here + // to allow keyboard handling for toolbars + ImplGetWindowImpl()->mnStyle |= WB_TABSTOP|WB_NODIALOGCONTROL; + ImplGetWindowImpl()->mnStyle &= ~WB_DIALOGCONTROL; + } + + ImplInitSettings( TRUE, TRUE, TRUE ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplInitSettings( BOOL bFont, + BOOL bForeground, BOOL bBackground ) +{ + mpData->mbNativeButtons = IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + if ( bFont ) + { + Font aFont = rStyleSettings.GetToolFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + } + + if ( bForeground || bFont ) + { + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetButtonTextColor(); + else + aColor = rStyleSettings.GetWindowTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + } + + if ( bBackground ) + { + Color aColor; + if ( IsControlBackground() ) + { + aColor = GetControlBackground(); + SetBackground( aColor ); + SetPaintTransparent( FALSE ); + SetParentClipMode( 0 ); + } + else + { + if( IsNativeControlSupported( CTRL_TOOLBAR, PART_ENTIRE_CONTROL ) ) + { + SetBackground(); + SetPaintTransparent( TRUE ); + SetParentClipMode( PARENTCLIPMODE_NOCLIP ); + mpData->maDisplayBackground = Wallpaper( rStyleSettings.GetFaceColor() ); + } + else + { + if ( Window::GetStyle() & WB_3DLOOK ) + aColor = rStyleSettings.GetFaceColor(); + else + aColor = rStyleSettings.GetWindowColor(); + + SetBackground( aColor ); + SetPaintTransparent( FALSE ); + SetParentClipMode( 0 ); + + ImplUpdateImageList(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplLoadRes( const ResId& rResId ) +{ + ResMgr* pMgr = rResId.GetResMgr(); + if( ! pMgr ) + return; + + DockingWindow::ImplLoadRes( rResId ); + + ULONG nObjMask; + + nObjMask = ReadLongRes(); + + if ( nObjMask & RSC_TOOLBOX_BUTTONTYPE ) + SetButtonType( (ButtonType)ReadLongRes() ); + + if ( nObjMask & RSC_TOOLBOX_ALIGN ) + SetAlign( (WindowAlign)ReadLongRes() ); + + if ( nObjMask & RSC_TOOLBOX_LINECOUNT ) + SetLineCount( sal::static_int_cast<USHORT>(ReadLongRes()) ); + + if ( nObjMask & RSC_TOOLBOX_CUSTOMIZE ) + { + BOOL bCust = (BOOL)ReadShortRes(); + EnableCustomize( bCust ); + } + + if ( nObjMask & RSC_TOOLBOX_MENUSTRINGS ) + { + BOOL bCust = (BOOL)ReadShortRes(); + EnableMenuStrings( bCust ); + } + + if ( nObjMask & RSC_TOOLBOX_FLOATLINES ) + SetFloatingLines( ReadShortRes() ); + + if ( nObjMask & RSC_TOOLBOX_ITEMIMAGELIST ) + { + maImageList = ImageList( ResId( (RSHEADER_TYPE*)GetClassRes(), *pMgr ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + } + + if ( nObjMask & RSC_TOOLBOX_ITEMLIST ) + { + ULONG nEle = ReadLongRes(); + + // Item hinzufuegen + for ( ULONG i = 0; i < nEle; i++ ) + { + InsertItem( ResId( (RSHEADER_TYPE *)GetClassRes(), *pMgr ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE *)GetClassRes() ) ); + } + } +} + +// ----------------------------------------------------------------------- + +ToolBox::ToolBox( Window* pParent, WinBits nStyle ) : + DockingWindow( WINDOW_TOOLBOX ) +{ + ImplInit( pParent, nStyle ); +} + +// ----------------------------------------------------------------------- + +ToolBox::ToolBox( Window* pParent, const ResId& rResId ) : + DockingWindow( WINDOW_TOOLBOX ) +{ + RTL_LOGFILE_CONTEXT( aLog, "vcl: ToolBox::ToolBox( Window* pParent, const ResId& rResId )" ); + + rResId.SetRT( RSC_TOOLBOX ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); + + // Groesse des FloatingWindows berechnen und umschalten, wenn die + // ToolBox initial im FloatingModus ist + if ( ImplIsFloatingMode() ) + mbHorz = TRUE; + else + Resize(); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- + +ToolBox::~ToolBox() +{ + // custom menu event still running? + if( mpData->mnEventId ) + Application::RemoveUserEvent( mpData->mnEventId ); + + // #103005# make sure our activate/deactivate balance is right + while( mnActivateCount > 0 ) + Deactivate(); + + // Falls noch ein Floating-Window connected ist, dann den + // PopupModus beenden + if ( mpFloatWin ) + mpFloatWin->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL ); + + // delete private data + delete mpData; + + // FloatSizeAry gegebenenfalls loeschen + if ( mpFloatSizeAry ) + delete mpFloatSizeAry; + + // Wenn keine ToolBox-Referenzen mehr auf die Listen bestehen, dann + // Listen mit wegloeschen + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maCtrlData.mpTBDragMgr ) + { + // Wenn im TBDrag-Manager, dann wieder rausnehmen + if ( mbCustomize ) + pSVData->maCtrlData.mpTBDragMgr->Remove( this ); + + if ( !pSVData->maCtrlData.mpTBDragMgr->Count() ) + { + delete pSVData->maCtrlData.mpTBDragMgr; + pSVData->maCtrlData.mpTBDragMgr = NULL; + } + } +} + +// ----------------------------------------------------------------------- + +ImplToolItem* ToolBox::ImplGetItem( USHORT nItemId ) const +{ + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if ( it->mnId == nItemId ) + return &(*it); + ++it; + } + + return NULL; +} +// ----------------------------------------------------------------------- + +static void ImplAddButtonBorder( long &rWidth, long& rHeight, USHORT aOutStyle, BOOL bNativeButtons ) +{ + if ( aOutStyle & TOOLBOX_STYLE_OUTBUTTON ) + { + rWidth += OUTBUTTON_SIZE; + rHeight += OUTBUTTON_SIZE; + } + else + { + rWidth += SMALLBUTTON_HSIZE; + rHeight += SMALLBUTTON_VSIZE; + } + + if( bNativeButtons ) + { + // give more border space for rounded buttons + rWidth += 2; + rHeight += 4; + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::ImplCalcItem() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + // recalc required ? + if ( !mbCalc ) + return FALSE; + + ImplDisableFlatButtons(); + + long nDefWidth; + long nDefHeight; + long nMaxWidth = 0; + long nMaxHeight = 0; + long nHeight; + long nMinWidth = 6; + long nMinHeight = 6; + long nDropDownArrowWidth = TB_DROPDOWNARROWWIDTH; + + // set defaults if image or text is needed but empty + nDefWidth = GetDefaultImageSize().Width(); + nDefHeight = GetDefaultImageSize().Height(); + + mnWinHeight = 0; + // determine minimum size necessary in NWF + { + Rectangle aRect( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + Rectangle aReg( aRect ); + ImplControlValue aVal; + Rectangle aNativeBounds, aNativeContent; + if( IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + if( GetNativeControlRegion( CTRL_TOOLBAR, PART_BUTTON, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds; + if( aRect.GetWidth() > nMinWidth ) + nMinWidth = aRect.GetWidth(); + if( aRect.GetHeight() > nMinHeight ) + nMinHeight = aRect.GetHeight(); + if( nDropDownArrowWidth < nMinWidth ) + nDropDownArrowWidth = nMinWidth; + if( nMinWidth > mpData->mnMenuButtonWidth ) + mpData->mnMenuButtonWidth = nMinWidth; + else if( nMinWidth < TB_MENUBUTTON_SIZE ) + mpData->mnMenuButtonWidth = TB_MENUBUTTON_SIZE; + } + } + + // also calculate the area for comboboxes, drop down list boxes and spinfields + // as these are often inserted into toolboxes; set mnWinHeight to the + // greater of those values to prevent toolbar flickering (#i103385#) + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_COMBOBOX, PART_ENTIRE_CONTROL, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds; + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); + } + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_LISTBOX, PART_ENTIRE_CONTROL, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds; + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); + } + aRect = Rectangle( Point( 0, 0 ), Size( nMinWidth, nMinHeight ) ); + aReg = aRect; + if( GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL, + aReg, + CTRL_STATE_ENABLED | CTRL_STATE_ROLLOVER, + aVal, OUString(), + aNativeBounds, aNativeContent ) ) + { + aRect = aNativeBounds; + if( aRect.GetHeight() > mnWinHeight ) + mnWinHeight = aRect.GetHeight(); + } + } + + if ( ! mpData->m_aItems.empty() ) + { + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + BOOL bImage; + BOOL bText; + + it->mbVisibleText = FALSE; // indicates if text will definitely be drawn, influences dropdown pos + + if ( it->meType == TOOLBOXITEM_BUTTON ) + { + // check if image and/or text exists + if ( !(it->maImage) ) + bImage = FALSE; + else + bImage = TRUE; + if ( !it->maText.Len() ) + bText = FALSE; + else + bText = TRUE; + ButtonType tmpButtonType = determineButtonType( &(*it), meButtonType ); // default to toolbox setting + if ( bImage || bText ) + { + + it->mbEmptyBtn = FALSE; + + if ( tmpButtonType == BUTTON_SYMBOL ) + { + // we're drawing images only + if ( bImage || !bText ) + { + it->maItemSize = it->maImage.GetSizePixel(); + } + else + { + it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET, + GetTextHeight() ); + it->mbVisibleText = TRUE; + } + } + else if ( tmpButtonType == BUTTON_TEXT ) + { + // we're drawing text only + if ( bText || !bImage ) + { + it->maItemSize = Size( GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET, + GetTextHeight() ); + it->mbVisibleText = TRUE; + } + else + { + it->maItemSize = it->maImage.GetSizePixel(); + } + } + else + { + // we're drawing images and text + it->maItemSize.Width() = bText ? GetCtrlTextWidth( it->maText )+TB_TEXTOFFSET : 0; + it->maItemSize.Height() = bText ? GetTextHeight() : 0; + + // leave space between image and text + if( bText ) + it->maItemSize.Width() += TB_IMAGETEXTOFFSET; + + // image and text side by side + it->maItemSize.Width() += it->maImage.GetSizePixel().Width(); + if ( it->maImage.GetSizePixel().Height() > it->maItemSize.Height() ) + it->maItemSize.Height() = it->maImage.GetSizePixel().Height(); + + it->mbVisibleText = bText; + } + } + else + { // no image and no text + it->maItemSize = Size( nDefWidth, nDefHeight ); + it->mbEmptyBtn = TRUE; + } + + // Gegebenenfalls die Fensterhoehe mit beruecksichtigen + if ( it->mpWindow ) + { + nHeight = it->mpWindow->GetSizePixel().Height(); + if ( nHeight > mnWinHeight ) + mnWinHeight = nHeight; + } + + // add in drop down arrow + if( it->mnBits & TIB_DROPDOWN ) + { + it->maItemSize.Width() += nDropDownArrowWidth; + it->mnDropDownArrowWidth = nDropDownArrowWidth; + } + + // text items will be rotated in vertical mode + // -> swap width and height + if( it->mbVisibleText && !mbHorz ) + { + long tmp = it->maItemSize.Width(); + it->maItemSize.Width() = it->maItemSize.Height(); + it->maItemSize.Height() = tmp; + } + } + else if ( it->meType == TOOLBOXITEM_SPACE ) + { + it->maItemSize = Size( nDefWidth, nDefHeight ); + } + + if ( it->meType == TOOLBOXITEM_BUTTON || it->meType == TOOLBOXITEM_SPACE ) + { + // add borders + ImplAddButtonBorder( it->maItemSize.Width(), it->maItemSize.Height(), mnOutStyle, mpData->mbNativeButtons ); + + if( it->meType == TOOLBOXITEM_BUTTON ) + { + if( it->maItemSize.Width() < nMinWidth ) + it->maItemSize.Width() = nMinWidth; + if( it->maItemSize.Height() < nMinHeight ) + it->maItemSize.Height() = nMinHeight; + } + + // keep track of max item size + if ( it->maItemSize.Width() > nMaxWidth ) + nMaxWidth = it->maItemSize.Width(); + if ( it->maItemSize.Height() > nMaxHeight ) + nMaxHeight = it->maItemSize.Height(); + } + + ++it; + } + } + else + { + nMaxWidth = nDefWidth; + nMaxHeight = nDefHeight; + + ImplAddButtonBorder( nMaxWidth, nMaxHeight, mnOutStyle, mpData->mbNativeButtons ); + } + + if( !ImplIsFloatingMode() && GetToolboxButtonSize() != TOOLBOX_BUTTONSIZE_DONTCARE ) + { + // make sure all vertical toolbars have the same width and horizontal have the same height + // this depends on the used button sizes + // as this is used for alignement of multiple toolbars + // it is only required for docked toolbars + + long nFixedWidth = nDefWidth+nDropDownArrowWidth; + long nFixedHeight = nDefHeight; + ImplAddButtonBorder( nFixedWidth, nFixedHeight, mnOutStyle, mpData->mbNativeButtons ); + + if( mbHorz ) + nMaxHeight = nFixedHeight; + else + nMaxWidth = nFixedWidth; + } + + mbCalc = FALSE; + mbFormat = TRUE; + + // do we have to recalc the sizes ? + if ( (nMaxWidth != mnMaxItemWidth) || (nMaxHeight != mnMaxItemHeight) ) + { + mnMaxItemWidth = nMaxWidth; + mnMaxItemHeight = nMaxHeight; + + return TRUE; + } + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::ImplCalcBreaks( long nWidth, long* pMaxLineWidth, BOOL bCalcHorz ) +{ + ULONG nLineStart = 0; + ULONG nGroupStart = 0; + long nLineWidth = 0; + long nCurWidth; + long nLastGroupLineWidth = 0; + long nMaxLineWidth = 0; + USHORT nLines = 1; + BOOL bWindow; + BOOL bBreak = FALSE; + long nWidthTotal = nWidth; + + // when docked the menubutton will be in the first line + // ->initialize first linewidth with button + if( IsMenuEnabled() && !ImplIsFloatingMode() ) + nLineWidth = mpData->maMenubuttonItem.maItemSize.Width(); + + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + it->mbBreak = bBreak; + bBreak = FALSE; + + if ( it->mbVisible ) + { + bWindow = FALSE; + bBreak = FALSE; + nCurWidth = 0; + + if ( it->meType == TOOLBOXITEM_BUTTON || it->meType == TOOLBOXITEM_SPACE ) + { + if ( bCalcHorz ) + nCurWidth = it->maItemSize.Width(); + else + nCurWidth = it->maItemSize.Height(); + + if ( it->mpWindow && bCalcHorz ) + { + long nWinItemWidth = it->mpWindow->GetSizePixel().Width(); + if ( !mbScroll || (nWinItemWidth <= nWidthTotal) ) + { + nCurWidth = nWinItemWidth; + bWindow = TRUE; + } + else + { + if ( it->mbEmptyBtn ) + { + nCurWidth = 0; + } + } + } + + // check for line break + if ( (nLineWidth+nCurWidth > nWidthTotal) && mbScroll ) + bBreak = TRUE; + } + else if ( it->meType == TOOLBOXITEM_SEPARATOR ) + nCurWidth = it->mnSepSize; + // treat breaks as separators, except when using old style toolbars (ie. no menu button) + else if ( (it->meType == TOOLBOXITEM_BREAK) && !IsMenuEnabled() ) + bBreak = TRUE; + + if ( bBreak ) + { + nLines++; + + // Gruppe auseinanderbrechen oder ganze Gruppe umbrechen? + if ( (it->meType == TOOLBOXITEM_BREAK) || + (nLineStart == nGroupStart) ) + { + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + nLineWidth = 0; + nLineStart = it - mpData->m_aItems.begin(); + nGroupStart = nLineStart; + it->mbBreak = TRUE; + bBreak = FALSE; + } + else + { + if ( nLastGroupLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLastGroupLineWidth; + + // Wenn ganze Gruppe umgebrochen wird, diese auf + // Zeilenanfang setzen und wieder neu berechnen + nLineWidth = 0; + nLineStart = nGroupStart; + it = mpData->m_aItems.begin() + nGroupStart; + continue; + } + } + else + { + if( ImplIsFloatingMode() || !IsMenuEnabled() ) // no group breaking when being docked single-line + { + if ( (it->meType != TOOLBOXITEM_BUTTON) || bWindow ) + { + // found separator or break + nLastGroupLineWidth = nLineWidth; + nGroupStart = it - mpData->m_aItems.begin(); + if ( !bWindow ) + nGroupStart++; + } + } + } + + nLineWidth += nCurWidth; + } + + ++it; + } + + + if ( pMaxLineWidth ) + { + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + if( ImplIsFloatingMode() && !ImplIsInPopupMode() ) + { + // leave enough space to display buttons in the decoration + long aMinWidth = 2 * GetSettings().GetStyleSettings().GetFloatTitleHeight(); + if( nMaxLineWidth < aMinWidth ) + nMaxLineWidth = aMinWidth; + } + + // Wegen Separatoren kann MaxLineWidth > Width werden, hat aber + // auf die Umbrueche keine Auswirkung + //if ( nMaxLineWidth > nWidth ) + // nMaxLineWidth = nWidth; + + *pMaxLineWidth = nMaxLineWidth; + } + + return nLines; +} + +// ----------------------------------------------------------------------- +namespace +{ + BOOL ImplFollowedByVisibleButton( std::vector< ImplToolItem >::iterator _aSeparator, std::vector< ImplToolItem >::iterator _aEnd ) + { + std::vector< ImplToolItem >::iterator aLookup = _aSeparator; + while ( ++aLookup != _aEnd ) + { + if ( aLookup->meType == TOOLBOXITEM_SEPARATOR ) + return ImplFollowedByVisibleButton( aLookup, _aEnd ); + + if ( ( aLookup->meType == TOOLBOXITEM_BUTTON ) && aLookup->mbVisible ) + return TRUE; + } + return FALSE; + } +} + + +// ----------------------------------------------------------------------- + +Size ToolBox::ImplGetOptimalFloatingSize( FloatingSizeMode eMode ) +{ + if( !ImplIsFloatingMode() ) + return Size(); + + Size aCurrentSize( mnDX, mnDY ); + Size aSize1( aCurrentSize ); + Size aSize2( aCurrentSize ); + + // try to preserve current height + if( eMode == FSMODE_AUTO || eMode == FSMODE_FAVOURHEIGHT ) + { + // calc number of floating lines for current window height + USHORT nFloatLinesHeight = ImplCalcLines( this, mnDY ); + // calc window size according to this number + aSize1 = ImplCalcFloatSize( this, nFloatLinesHeight ); + + if( eMode == FSMODE_FAVOURHEIGHT || aCurrentSize == aSize1 ) + return aSize1; + } + + if( eMode == FSMODE_AUTO || eMode == FSMODE_FAVOURWIDTH ) + { + // try to preserve current width + long nLineHeight = ( mnWinHeight > mnMaxItemHeight ) ? mnWinHeight : mnMaxItemHeight; + int nBorderX = 2*TB_BORDER_OFFSET1 + mnLeftBorder + mnRightBorder + 2*mnBorderX; + int nBorderY = 2*TB_BORDER_OFFSET2 + mnTopBorder + mnBottomBorder + 2*mnBorderY; + Size aSz( aCurrentSize ); + long maxX; + USHORT nLines = ImplCalcBreaks( aSz.Width()-nBorderX, &maxX, mbHorz ); + + USHORT manyLines = 1000; + Size aMinimalFloatSize = ImplCalcFloatSize( this, manyLines ); + + aSz.Height() = nBorderY + nLineHeight * nLines; + // line space when more than one line + if ( mnWinStyle & WB_LINESPACING ) + aSz.Height() += (nLines-1)*TB_LINESPACING; + + aSz.Width() = nBorderX + maxX; + + // avoid clipping of any items + if( aSz.Width() < aMinimalFloatSize.Width() ) + aSize2 = ImplCalcFloatSize( this, nLines ); + else + aSize2 = aSz; + + if( eMode == FSMODE_FAVOURWIDTH || aCurrentSize == aSize2 ) + return aSize2; + else + { + // set the size with the smallest delta as the current size + long dx1 = abs( mnDX - aSize1.Width() ); + long dy1 = abs( mnDY - aSize1.Height() ); + + long dx2 = abs( mnDX - aSize2.Width() ); + long dy2 = abs( mnDY - aSize2.Height() ); + + if( dx1*dy1 < dx2*dy2 ) + aCurrentSize = aSize1; + else + aCurrentSize = aSize2; + } + } + return aCurrentSize; +} + + +void ToolBox::ImplFormat( BOOL bResize ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + // Muss ueberhaupt neu formatiert werden + if ( !mbFormat ) + return; + + mpData->ImplClearLayoutData(); + + // Positionen/Groessen berechnen + Rectangle aEmptyRect; + long nLineSize; + long nLeft; + long nRight; + long nTop; + long nBottom; + long nMax; // width of layoutarea in pixels + long nX; + long nY; + USHORT nFormatLine; + BOOL bMustFullPaint; + BOOL bLastSep; + + std::vector< ImplToolItem >::iterator it; + std::vector< ImplToolItem >::iterator temp_it; + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + BOOL bIsInPopupMode = ImplIsInPopupMode(); + + // FloatSizeAry gegebenenfalls loeschen + if ( mpFloatSizeAry ) + { + delete mpFloatSizeAry; + mpFloatSizeAry = NULL; + } + + // compute border sizes + ImplCalcBorder( meAlign, mnLeftBorder, mnTopBorder, mnRightBorder, mnBottomBorder, this ); + + // update drag area (where the 'grip' will be placed) + Rectangle aOldDragRect; + if( pWrapper ) + aOldDragRect = pWrapper->GetDragArea(); + ImplUpdateDragArea( this ); + + if ( ImplCalcItem() ) + bMustFullPaint = TRUE; + else + bMustFullPaint = FALSE; + + + // calculate new size during interactive resize or + // set computed size when formatting only + if ( ImplIsFloatingMode() ) + { + if ( bResize ) + mnFloatLines = ImplCalcLines( this, mnDY ); + else + SetOutputSizePixel( ImplGetOptimalFloatingSize( FSMODE_AUTO ) ); + } + + // Horizontal + if ( mbHorz ) + { + // nLineSize: height of a single line, will fit highest item + nLineSize = mnMaxItemHeight; + + if ( mnWinHeight > mnMaxItemHeight ) + nLineSize = mnWinHeight; + + if ( mbScroll ) + { + nMax = mnDX; + mnVisLines = ImplCalcLines( this, mnDY ); + } + else + { + // layout over all lines + mnVisLines = mnLines; + nMax = TB_MAXNOSCROLL; + } + + // add in all border offsets + // inner border as well as custom border (mnBorderX, mnBorderY) + if ( mnWinStyle & WB_BORDER ) + { + nLeft = TB_BORDER_OFFSET1 + mnLeftBorder; + nTop = TB_BORDER_OFFSET2 + mnTopBorder; + nBottom = TB_BORDER_OFFSET1 + mnBottomBorder; + nMax -= nLeft + TB_BORDER_OFFSET1 + mnRightBorder; + } + else + { + nLeft = 0; + nTop = 0; + nBottom = 0; + } + + nLeft += mnBorderX; + nTop += mnBorderY; + nBottom += mnBorderY; + nMax -= mnBorderX*2; + + // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu) + // we have to center all items in the window height + if( IsMenuEnabled() && !ImplIsFloatingMode() ) + { + long nWinHeight = mnDY - nTop - nBottom; + if( nWinHeight > nLineSize ) + nLineSize = nWinHeight; + } + } + else + { + nLineSize = mnMaxItemWidth; + + if ( mbScroll ) + { + mnVisLines = ImplCalcLines( this, mnDX ); + nMax = mnDY; + } + else + { + mnVisLines = mnLines; + nMax = TB_MAXNOSCROLL; + } + + if ( mnWinStyle & WB_BORDER ) + { + nTop = TB_BORDER_OFFSET1 + mnTopBorder; + nLeft = TB_BORDER_OFFSET2 + mnLeftBorder; + nRight = TB_BORDER_OFFSET2 + mnRightBorder; + nMax -= nTop + TB_BORDER_OFFSET1 + mnBottomBorder; + } + else + { + nLeft = 0; + nTop = 0; + nRight = 0; + } + + nLeft += mnBorderX; + nRight+= mnBorderX; + nTop += mnBorderY; + nMax -= mnBorderY*2; + + // adjust linesize if docked in single-line mode (i.e. when using a clipped item menu) + // we have to center all items in the window height + if( !ImplIsFloatingMode() && IsMenuEnabled() ) + { + long nWinWidth = mnDX - nLeft - nRight; + if( nWinWidth > nLineSize ) + nLineSize = nWinWidth; + } + } + + // no calculation if the window has no size (nMax=0) + // non scrolling toolboxes must be computed though + if ( (nMax <= 0) && mbScroll ) + { + mnVisLines = 1; + mnCurLine = 1; + mnCurLines = 1; + + it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + it->maRect = aEmptyRect; + + // For items not visible, release resources only needed during + // painting the items (on Win98, for example, these are system-wide + // resources that are easily exhausted, so be nice): + + /* !!! + it->maImage.ClearCaches(); + it->maHighImage.ClearCaches(); + */ + + ++it; + } + + maLowerRect = aEmptyRect; + maUpperRect = aEmptyRect; + maNextToolRect = aEmptyRect; + } + else + { + // init start values + nX = nLeft; // top-left offset + nY = nTop; + nFormatLine = 1; + bLastSep = TRUE; + + // save old scroll rectangles and reset them + Rectangle aOldLowerRect = maLowerRect; + Rectangle aOldUpperRect = maUpperRect; + Rectangle aOldNextToolRect = maNextToolRect; + Rectangle aOldMenubuttonRect = mpData->maMenubuttonItem.maRect; + maUpperRect = aEmptyRect; + maLowerRect = aEmptyRect; + maNextToolRect = aEmptyRect; + mpData->maMenubuttonItem.maRect = aEmptyRect; + + // additional toolboxes require a toggle button (maNextToolRect) + if ( maNextToolBoxStr.Len() && mbScroll ) + { + nMax -= TB_NEXT_SIZE-TB_NEXT_OFFSET; + if ( mbHorz ) + { + maNextToolRect.Left() = nLeft+nMax; + maNextToolRect.Right() = maNextToolRect.Left()+TB_NEXT_SIZE-1; + maNextToolRect.Top() = nTop; + maNextToolRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1; + } + else + { + maNextToolRect.Top() = nTop+nMax; + maNextToolRect.Bottom() = maNextToolRect.Top()+TB_NEXT_SIZE-1; + maNextToolRect.Left() = nLeft; + maNextToolRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1; + } + } + + // do we have any toolbox items at all ? + if ( !mpData->m_aItems.empty() || IsMenuEnabled() ) + { + // compute line breaks and visible lines give the current window width (nMax) + // the break indicators will be stored within each item (it->mbBreak) + mnCurLines = ImplCalcBreaks( nMax, NULL, mbHorz ); + + // check for scrollbar buttons or dropdown menu + // (if a menu is enabled, this will be used to store clipped + // items and no scroll buttons will appear) + if ( (!ImplIsFloatingMode() && (mnCurLines > mnVisLines) && mbScroll ) || + IsMenuEnabled() ) + { + // compute linebreaks again, incorporating scrollbar buttons + if( !IsMenuEnabled() ) + { + nMax -= TB_SPIN_SIZE+TB_SPIN_OFFSET; + mnCurLines = ImplCalcBreaks( nMax, NULL, mbHorz ); + } + + // compute scroll rectangles or menu button + if ( mbHorz ) + { + if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode ) + { + if( !ImplIsFloatingMode() ) + { + mpData->maMenubuttonItem.maRect.Right() = mnDX - 2; + mpData->maMenubuttonItem.maRect.Top() = nTop; + mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1; + } + else + { + mpData->maMenubuttonItem.maRect.Right() = mnDX - mnRightBorder-mnBorderX-TB_BORDER_OFFSET1-1; + mpData->maMenubuttonItem.maRect.Top() = nTop; + mpData->maMenubuttonItem.maRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1; + } + mpData->maMenubuttonItem.maRect.Left() = mpData->maMenubuttonItem.maRect.Right() - mpData->mnMenuButtonWidth; + } + else + { + maUpperRect.Left() = nLeft+nMax+TB_SPIN_OFFSET; + maUpperRect.Right() = maUpperRect.Left()+TB_SPIN_SIZE-1; + maUpperRect.Top() = nTop; + maLowerRect.Bottom() = mnDY-mnBottomBorder-mnBorderY-TB_BORDER_OFFSET2-1; + maLowerRect.Left() = maUpperRect.Left(); + maLowerRect.Right() = maUpperRect.Right(); + maUpperRect.Bottom() = maUpperRect.Top() + + (maLowerRect.Bottom()-maUpperRect.Top())/2; + maLowerRect.Top() = maUpperRect.Bottom(); + } + } + else + { + if( IsMenuEnabled() && !ImplHasExternalMenubutton() && !bIsInPopupMode ) + { + if( !ImplIsFloatingMode() ) + { + mpData->maMenubuttonItem.maRect.Bottom() = mnDY - 2; + mpData->maMenubuttonItem.maRect.Left() = nLeft; + mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1; + } + else + { + mpData->maMenubuttonItem.maRect.Bottom() = mnDY - mnBottomBorder-mnBorderY-TB_BORDER_OFFSET1-1; + mpData->maMenubuttonItem.maRect.Left() = nLeft; + mpData->maMenubuttonItem.maRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1; + } + mpData->maMenubuttonItem.maRect.Top() = mpData->maMenubuttonItem.maRect.Bottom() - mpData->mnMenuButtonWidth; + } + else + { + maUpperRect.Top() = nTop+nMax+TB_SPIN_OFFSET;; + maUpperRect.Bottom() = maUpperRect.Top()+TB_SPIN_SIZE-1; + maUpperRect.Left() = nLeft; + maLowerRect.Right() = mnDX-mnRightBorder-mnBorderX-TB_BORDER_OFFSET2-1; + maLowerRect.Top() = maUpperRect.Top(); + maLowerRect.Bottom() = maUpperRect.Bottom(); + maUpperRect.Right() = maUpperRect.Left() + + (maLowerRect.Right()-maUpperRect.Left())/2; + maLowerRect.Left() = maUpperRect.Right(); + } + } + } + + // no scrolling when there is a "more"-menu + // anything will "fit" in a single line then + if( IsMenuEnabled() ) + mnCurLines = 1; + + // determine the currently visible line + if ( mnVisLines >= mnCurLines ) + mnCurLine = 1; + else if ( mnCurLine+mnVisLines-1 > mnCurLines ) + mnCurLine = mnCurLines - (mnVisLines-1); + + it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + // hide double separators + if ( it->meType == TOOLBOXITEM_SEPARATOR ) + { + it->mbVisible = FALSE; + if ( !bLastSep ) + { + // check if any visible items have to appear behind it + temp_it = it+1; + while ( temp_it != mpData->m_aItems.end() ) + { + if ( (temp_it->meType == TOOLBOXITEM_SEPARATOR) || + ((temp_it->meType == TOOLBOXITEM_BUTTON) && + temp_it->mbVisible) ) + { + it->mbVisible = TRUE; + break; + } + ++temp_it; + } + } + bLastSep = TRUE; + } + else if ( it->mbVisible ) + bLastSep = FALSE; + + it->mbShowWindow = FALSE; + + // check for line break and advance nX/nY accordingly + if ( it->mbBreak ) + { + nFormatLine++; + + // increment starting with the second line + if ( nFormatLine > mnCurLine ) + { + if ( mbHorz ) + { + nX = nLeft; + if ( mnWinStyle & WB_LINESPACING ) + nY += nLineSize+TB_LINESPACING; + else + nY += nLineSize; + } + else + { + nY = nTop; + if ( mnWinStyle & WB_LINESPACING ) + nX += nLineSize+TB_LINESPACING; + else + nX += nLineSize; + } + } + } + + if ( !it->mbVisible || (nFormatLine < mnCurLine) || + (nFormatLine > mnCurLine+mnVisLines-1) ) + // item is not visible + it->maCalcRect = aEmptyRect; + else + { + // 1. determine current item width/height + // take window size and orientation into account, because this affects the size of item windows + + Size aCurrentItemSize( it->GetSize( mbHorz, mbScroll, nMax, Size(mnMaxItemWidth, mnMaxItemHeight) ) ); + + // 2. position item rect and use size from step 1 + // items will be centered horizontally (if mbHorz) or vertically + // advance nX and nY accordingly + if ( mbHorz ) + { + it->maCalcRect.Left() = nX; + it->maCalcRect.Top() = nY+(nLineSize-aCurrentItemSize.Height())/2; + it->maCalcRect.Right() = nX+aCurrentItemSize.Width()-1; + it->maCalcRect.Bottom() = it->maCalcRect.Top()+aCurrentItemSize.Height()-1; + nX += aCurrentItemSize.Width(); + } + else + { + it->maCalcRect.Left() = nX+(nLineSize-aCurrentItemSize.Width())/2; + it->maCalcRect.Top() = nY; + it->maCalcRect.Right() = it->maCalcRect.Left()+aCurrentItemSize.Width()-1; + it->maCalcRect.Bottom() = nY+aCurrentItemSize.Height()-1; + nY += aCurrentItemSize.Height(); + } + } + + // position window items into calculated item rect + if ( it->mpWindow ) + { + if ( it->mbShowWindow ) + { + Point aPos( it->maCalcRect.Left(), it->maCalcRect.Top() ); + it->mpWindow->SetPosPixel( aPos ); + if ( !mbCustomizeMode ) + it->mpWindow->Show(); + } + else + it->mpWindow->Hide(); + } + + ++it; + } // end of loop over all items + } + else + // we have no toolbox items + mnCurLines = 1; + + + if( IsMenuEnabled() && ImplIsFloatingMode() && !ImplHasExternalMenubutton() && !bIsInPopupMode ) + { + // custom menu will be the last button in floating mode + ImplToolItem &rIt = mpData->maMenubuttonItem; + + if ( mbHorz ) + { + rIt.maRect.Left() = nX+TB_MENUBUTTON_OFFSET; + rIt.maRect.Top() = nY; + rIt.maRect.Right() = rIt.maRect.Left() + mpData->mnMenuButtonWidth; + rIt.maRect.Bottom() = nY+nLineSize-1; + nX += rIt.maItemSize.Width(); + } + else + { + rIt.maRect.Left() = nX; + rIt.maRect.Top() = nY+TB_MENUBUTTON_OFFSET; + rIt.maRect.Right() = nX+nLineSize-1; + rIt.maRect.Bottom() = rIt.maRect.Top() + mpData->mnMenuButtonWidth; + nY += rIt.maItemSize.Height(); + } + } + + + // if toolbox visible trigger paint for changed regions + if ( IsVisible() && !mbFullPaint ) + { + if ( bMustFullPaint ) + { + maPaintRect = Rectangle( mnLeftBorder, mnTopBorder, + mnDX-mnRightBorder, mnDY-mnBottomBorder ); + } + else + { + if ( aOldLowerRect != maLowerRect ) + { + maPaintRect.Union( maLowerRect ); + maPaintRect.Union( aOldLowerRect ); + } + if ( aOldUpperRect != maUpperRect ) + { + maPaintRect.Union( maUpperRect ); + maPaintRect.Union( aOldUpperRect ); + } + if ( aOldNextToolRect != maNextToolRect ) + { + maPaintRect.Union( maNextToolRect ); + maPaintRect.Union( aOldNextToolRect ); + } + if ( aOldMenubuttonRect != mpData->maMenubuttonItem.maRect ) + { + maPaintRect.Union( mpData->maMenubuttonItem.maRect ); + maPaintRect.Union( aOldMenubuttonRect ); + } + if ( pWrapper && aOldDragRect != pWrapper->GetDragArea() ) + { + maPaintRect.Union( pWrapper->GetDragArea() ); + maPaintRect.Union( aOldDragRect ); + } + + it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if ( it->maRect != it->maCalcRect ) + { + maPaintRect.Union( it->maRect ); + maPaintRect.Union( it->maCalcRect ); + } + ++it; + } + } + + Invalidate( maPaintRect ); + } + + // store the new calculated item rects + maPaintRect = aEmptyRect; + Rectangle aVisibleRect(Point(0, 0), GetOutputSizePixel()); + it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + it->maRect = it->maCalcRect; + if (!it->maRect.IsOver(aVisibleRect)) + { + // For items not visible, release resources only needed during + // painting the items (on Win98, for example, these are system- + // wide resources that are easily exhausted, so be nice): + + /* !!! + it->maImage.ClearCaches(); + it->maHighImage.ClearCaches(); + */ + } + ++it; + } + } + + // indicate formatting is done + mbFormat = FALSE; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ToolBox, ImplDropdownLongClickHdl, ToolBox*, EMPTYARG ) +{ + if( mnCurPos != TOOLBOX_ITEM_NOTFOUND && + (mpData->m_aItems[ mnCurPos ].mnBits & TIB_DROPDOWN) + ) + { + mpData->mbDropDownByKeyboard = FALSE; + GetDropdownClickHdl().Call( this ); + + // do not reset data if the dropdown handler opened a floating window + // see ImplFloatControl() + if( mpFloatWin == NULL ) + { + // no floater was opened + Deactivate(); + ImplDrawItem( mnCurPos, FALSE ); + + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + mnDownItemId = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; + mnHighItemId = 0; + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ToolBox, ImplUpdateHdl, void*, EMPTYARG ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mbFormat ) + ImplFormat(); + + return 0; +} + +// ----------------------------------------------------------------------- + +static void ImplDrawMoreIndicator( ToolBox *pBox, const Rectangle& rRect, BOOL bSetColor, BOOL bRotate ) +{ + Color aOldFillColor = pBox->GetFillColor(); + Color aOldLineColor = pBox->GetLineColor(); + pBox->SetLineColor(); + + if ( bSetColor ) + { + if ( pBox->GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + pBox->SetFillColor( Color( COL_WHITE ) ); + else + pBox->SetFillColor( Color( COL_BLACK ) ); + } + + if( !bRotate ) + { + long width = 8; + long height = 5; + long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1; + long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1; + while( height >= 1) + { + pBox->DrawRect( Rectangle( x, y, x+1, y ) ); + x+=4; + pBox->DrawRect( Rectangle( x, y, x+1, y ) ); + x-=4; + y++; + if( height <= 3) x--; + else x++; + height--; + } + } + else + { + long width = 5; + long height = 8; + long x = rRect.Left() + (rRect.getWidth() - width)/2 + 1; + long y = rRect.Top() + (rRect.getHeight() - height)/2 + 1; + while( width >= 1) + { + pBox->DrawRect( Rectangle( x, y, x, y+1 ) ); + y+=4; + pBox->DrawRect( Rectangle( x, y, x, y+1 ) ); + y-=4; + x++; + if( width <= 3) y--; + else y++; + width--; + } + } + + pBox->SetFillColor( aOldFillColor ); + pBox->SetLineColor( aOldLineColor ); +} + +static void ImplDrawDropdownArrow( ToolBox *pBox, const Rectangle& rDropDownRect, BOOL bSetColor, BOOL bRotate ) +{ + BOOL bLineColor = pBox->IsLineColor(); + BOOL bFillColor = pBox->IsFillColor(); + Color aOldFillColor = pBox->GetFillColor(); + Color aOldLineColor = pBox->GetLineColor(); + pBox->SetLineColor(); + + if ( bSetColor ) + { + if ( pBox->GetSettings().GetStyleSettings().GetFaceColor().IsDark() ) + pBox->SetFillColor( Color( COL_WHITE ) ); + else + pBox->SetFillColor( Color( COL_BLACK ) ); + } + + if( !bRotate ) + { + long width = 5; + long height = 3; + long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2; + long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2; + while( width >= 1) + { + pBox->DrawRect( Rectangle( x, y, x+width-1, y ) ); + y++; x++; + width -= 2; + } + } + else + { + long width = 3; + long height = 5; + long x = rDropDownRect.Left() + (rDropDownRect.getWidth() - width)/2; + long y = rDropDownRect.Top() + (rDropDownRect.getHeight() - height)/2; + while( height >= 1) + { + pBox->DrawRect( Rectangle( x, y, x, y+height-1 ) ); + y++; x++; + height -= 2; + } + } + + if( bFillColor ) + pBox->SetFillColor( aOldFillColor ); + else + pBox->SetFillColor(); + if( bLineColor ) + pBox->SetLineColor( aOldLineColor ); + else + pBox->SetLineColor( ); +} + +void ToolBox::ImplDrawToolArrow( ToolBox* pBox, long nX, long nY, BOOL bBlack, BOOL bColTransform, + BOOL bLeft, BOOL bTop, long nSize ) +{ + Color aOldFillColor = pBox->GetFillColor(); + WindowAlign eAlign = pBox->meAlign; + long n = 0; + long nHalfSize; + if ( bLeft ) + eAlign = WINDOWALIGN_RIGHT; + else if ( bTop ) + eAlign = WINDOWALIGN_BOTTOM; + + nHalfSize = nSize/2; + + switch ( eAlign ) + { + case WINDOWALIGN_LEFT: + if ( bBlack ) + pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) ); + while ( n <= nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+n, nY+n, nX+n, nY+nSize-n ) ); + n++; + } + if ( bBlack ) + { + pBox->SetFillColor( aOldFillColor ); + n = 1; + while ( n < nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+n, nY+1+n, nX+n, nY+nSize-1-n ) ); + n++; + } + } + break; + case WINDOWALIGN_TOP: + if ( bBlack ) + pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) ); + while ( n <= nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+n, nY+n, nX+nSize-n, nY+n ) ); + n++; + } + if ( bBlack ) + { + pBox->SetFillColor( aOldFillColor ); + n = 1; + while ( n < nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+1+n, nY+n, nX+nSize-1-n, nY+n ) ); + n++; + } + } + break; + case WINDOWALIGN_RIGHT: + if ( bBlack ) + pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) ); + while ( n <= nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+nHalfSize-n, nY+n, nX+nHalfSize-n, nY+nSize-n ) ); + n++; + } + if ( bBlack ) + { + pBox->SetFillColor( aOldFillColor ); + n = 1; + while ( n < nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+nHalfSize-n, nY+1+n, nX+nHalfSize-n, nY+nSize-1-n ) ); + n++; + } + } + break; + case WINDOWALIGN_BOTTOM: + if ( bBlack ) + pBox->SetFillColor( Color( bColTransform ? COL_WHITE : COL_BLACK ) ); + while ( n <= nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+n, nY+nHalfSize-n, nX+nSize-n, nY+nHalfSize-n ) ); + n++; + } + if ( bBlack ) + { + pBox->SetFillColor( aOldFillColor ); + n = 1; + while ( n < nHalfSize ) + { + pBox->DrawRect( Rectangle( nX+1+n, nY+nHalfSize-n, nX+nSize-1-n, nY+nHalfSize-n ) ); + n++; + } + } + break; + } +} + +void ToolBox::SetToolArrowClipregion( ToolBox* pBox, long nX, long nY, + BOOL bLeft, BOOL bTop, long nSize ) +{ + WindowAlign eAlign = pBox->meAlign; + long nHalfSize; + if ( bLeft ) + eAlign = WINDOWALIGN_RIGHT; + else if ( bTop ) + eAlign = WINDOWALIGN_BOTTOM; + + nHalfSize = nSize/2; + + Point p[6]; + + switch ( eAlign ) + { + case WINDOWALIGN_LEFT: + p[0].X() = nX-1; p[0].Y() = nY-1; + p[1].X() = nX-1; p[1].Y() = nY+nSize+1; + p[2].X() = nX+1; p[2].Y() = nY+nSize+1; + p[3].X() = nX+nHalfSize+1; p[3].Y() = nY+nHalfSize+1; + p[4].X() = nX+nHalfSize+1; p[4].Y() = nY+nHalfSize-1; + p[5].X() = nX+1; p[5].Y() = nY-1; + break; + case WINDOWALIGN_TOP: + p[0].X() = nX-1; p[0].Y() = nY-1; + p[1].X() = nX-1; p[1].Y() = nY+1; + p[2].X() = nX+nHalfSize-1; p[2].Y() = nY+nHalfSize+1; + p[3].X() = nX+nHalfSize+1; p[3].Y() = nY+nHalfSize+1; + p[4].X() = nX+nSize+1; p[4].Y() = nY+1; + p[5].X() = nX+nSize+1; p[5].Y() = nY-1; + break; + case WINDOWALIGN_RIGHT: + p[0].X() = nX+nHalfSize-1; p[0].Y() = nY-1; + p[1].X() = nX-1; p[1].Y() = nY+nHalfSize-1; + p[2].X() = nX-1; p[2].Y() = nY+nHalfSize+1; + p[3].X() = nX+nHalfSize-1; p[3].Y() = nY+nSize+1; + p[4].X() = nX+nHalfSize+1; p[4].Y() = nY+nSize+1; + p[5].X() = nX+nHalfSize+1; p[5].Y() = nY-1; + break; + case WINDOWALIGN_BOTTOM: + p[0].X() = nX-1; p[0].Y() = nY+nHalfSize-1; + p[1].X() = nX-1; p[1].Y() = nY+nHalfSize+1; + p[2].X() = nX+nSize+1; p[2].Y() = nY+nHalfSize+1; + p[3].X() = nX+nSize+1; p[3].Y() = nY+nHalfSize-1; + p[4].X() = nX+nHalfSize+1; p[4].Y() = nY-1; + p[5].X() = nX+nHalfSize-1; p[5].Y() = nY-1; + break; + } + Polygon aPoly(6,p); + Region aRgn( aPoly ); + pBox->SetClipRegion( aRgn ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDrawMenubutton( ToolBox *pThis, BOOL bHighlight ) +{ + if( !pThis->mpData->maMenubuttonItem.maRect.IsEmpty() ) + { + // #i53937# paint menu button only if necessary + if( !(pThis->GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE) && !pThis->ImplHasClippedItems() ) + return; + + // execute pending paint requests + ImplCheckUpdate( pThis ); + + BOOL bFillColor = pThis->IsFillColor(); + BOOL bLineColor = pThis->IsLineColor(); + Color aOldFillCol = pThis->GetFillColor(); + Color aOldLineCol = pThis->GetLineColor(); + BOOL bNativeButtons = pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ); + + Rectangle aInnerRect( pThis->mpData->maMenubuttonItem.maRect ); + if( pThis->mpData->mnMenuButtonWidth > TB_MENUBUTTON_SIZE ) + { + long nDiff = pThis->mpData->mnMenuButtonWidth - TB_MENUBUTTON_SIZE; + long nDiff1 = nDiff/2; + long nDiff2 = nDiff - nDiff1; + if( pThis->IsHorizontal() ) + { + aInnerRect.Left() += nDiff1; + aInnerRect.Right() -= nDiff2; + } + else + { + aInnerRect.Top() += nDiff1; + aInnerRect.Bottom() -= nDiff2; + } + } + + if( pThis->IsHorizontal() ) + { + aInnerRect.nLeft+=2; + aInnerRect.nRight-=1; + aInnerRect.nTop+=1; + aInnerRect.nBottom-=1; + } + else + { + aInnerRect.nLeft+=1; + aInnerRect.nRight-=1; + aInnerRect.nTop+=2; + aInnerRect.nBottom-=1; + } + + ImplErase( pThis, bNativeButtons ? pThis->mpData->maMenubuttonItem.maRect : aInnerRect, bHighlight ); + + if( bHighlight ) + { + if( bNativeButtons ) + ImplDrawButton( pThis, pThis->mpData->maMenubuttonItem.maRect, 2, FALSE, TRUE, FALSE ); + else + pThis->DrawSelectionBackground( aInnerRect, 2, FALSE, FALSE, FALSE ); + } + else + { + // improve visibility by using a dark gradient + Gradient g; + g.SetAngle( pThis->mbHorz ? 0 : 900 ); + g.SetStyle( GRADIENT_LINEAR ); + + g.SetStartColor( pThis->GetSettings().GetStyleSettings().GetFaceColor() ); + g.SetEndColor( pThis->GetSettings().GetStyleSettings().GetShadowColor() ); + + pThis->DrawGradient( aInnerRect, g ); + } + + Rectangle aRect( aInnerRect ); + if( pThis->mbHorz ) + aRect.Top() = aRect.Bottom() - aRect.getHeight()/3; + else + aRect.Left() = aRect.Right() - aRect.getWidth()/3; + + if( pThis->mpData->maMenuType & TOOLBOX_MENUTYPE_CUSTOMIZE ) + ImplDrawDropdownArrow( pThis, aRect, TRUE, !pThis->mbHorz ); + + if( pThis->ImplHasClippedItems() ) + { + aRect = aInnerRect; + if( pThis->mbHorz ) + aRect.Bottom() = aRect.Top() + aRect.getHeight()/3; + else + aRect.Right() = aRect.Left() + aRect.getWidth()/3; + + ImplDrawMoreIndicator( pThis, aRect, TRUE, !pThis->mbHorz ); + } + + // store highlight state + pThis->mpData->mbMenubuttonSelected = bHighlight; + + // restore colors + if( bFillColor ) + pThis->SetFillColor( aOldFillCol ); + else + pThis->SetFillColor(); + if( bLineColor ) + pThis->SetLineColor( aOldLineCol ); + else + pThis->SetLineColor(); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDrawSpin( BOOL bUpperIn, BOOL bLowerIn ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + BOOL bTmpUpper; + BOOL bTmpLower; + + if ( maUpperRect.IsEmpty() || maLowerRect.IsEmpty() ) + return; + + if ( mnCurLine > 1 ) + bTmpUpper = TRUE; + else + bTmpUpper = FALSE; + + if ( mnCurLine+mnVisLines-1 < mnCurLines ) + bTmpLower = TRUE; + else + bTmpLower = FALSE; + + if ( !IsEnabled() ) + { + bTmpUpper = FALSE; + bTmpLower = FALSE; + } + + ImplDrawSpinButton( this, maUpperRect, maLowerRect, + bUpperIn, bLowerIn, bTmpUpper, bTmpLower, !mbHorz ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDrawNext( BOOL bIn ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( maNextToolRect.IsEmpty() ) + return; + + DecorationView aDecoView( this ); + + // Button malen + long nX = SMALLBUTTON_OFF_NORMAL_X; + long nY = SMALLBUTTON_OFF_NORMAL_Y; + USHORT nStyle = 0; + if ( bIn == 1 ) + { + nStyle |= BUTTON_DRAW_PRESSED; + nX = SMALLBUTTON_OFF_PRESSED_X; + nY = SMALLBUTTON_OFF_PRESSED_Y; + } + aDecoView.DrawButton( maNextToolRect, nStyle ); + + // Inhalt ausgeben + BOOL bLeft = FALSE; + BOOL bTop = FALSE; + if ( mbHorz ) + { + bLeft = TRUE; + nX += (maNextToolRect.GetWidth()-6)/2-4; + nY += (maNextToolRect.GetHeight()-6)/2-6; + } + else + { + bTop = TRUE; + nY += (maNextToolRect.GetHeight()-6)/2-4; + nX += (maNextToolRect.GetWidth()-6)/2-6; + } + + nX += maNextToolRect.Left(); + nY += maNextToolRect.Top(); + SetLineColor(); + SetFillColor( COL_LIGHTBLUE ); + ImplDrawToolArrow( this, nX, nY, TRUE, FALSE, bLeft, bTop, 10 ); +} + +// ----------------------------------------------------------------------- + +static void ImplDrawButton( ToolBox* pThis, const Rectangle &rRect, USHORT highlight, BOOL bChecked, BOOL bEnabled, BOOL bIsWindow ) +{ + // draws toolbar button background either native or using a coloured selection + // if bIsWindow is TRUE, the corresponding item is a control and only a selection border will be drawn + + BOOL bNativeOk = FALSE; + if( !bIsWindow && pThis->IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + { + ImplControlValue aControlValue; + ControlState nState = 0; + + if ( highlight == 1 ) nState |= CTRL_STATE_PRESSED; + if ( highlight == 2 ) nState |= CTRL_STATE_ROLLOVER; + if ( bEnabled ) nState |= CTRL_STATE_ENABLED; + + aControlValue.setTristateVal( bChecked ? BUTTONVALUE_ON : BUTTONVALUE_OFF ); + + + bNativeOk = pThis->DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, + rRect, nState, aControlValue, rtl::OUString() ); + } + + if( !bNativeOk ) + pThis->DrawSelectionBackground( rRect, bIsWindow ? 3 : highlight, bChecked, TRUE, bIsWindow, 2, NULL, NULL ); +} + +void ToolBox::ImplDrawItem( USHORT nPos, BOOL bHighlight, BOOL bPaint, BOOL bLayout ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( nPos >= mpData->m_aItems.size() ) + return; + + // execute pending paint requests + ImplCheckUpdate( this ); + + ImplDisableFlatButtons(); + + SetFillColor(); + + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + MetricVector* pVector = bLayout ? &mpData->m_pLayoutData->m_aUnicodeBoundRects : NULL; + String* pDisplayText = bLayout ? &mpData->m_pLayoutData->m_aDisplayText : NULL; + + bHighlight = bHighlight && pItem->mbEnabled; + + // Falls Rechteck ausserhalb des sichbaren Bereichs liegt + if ( pItem->maRect.IsEmpty() ) + return; + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // no gradient background for items that have a popup open + BOOL bHasOpenPopup = (mpFloatWin != NULL) && (mnDownItemId==pItem->mnId); + + BOOL bHighContrastWhite = FALSE; + // check the face color as highcontrast indicator + // because the toolbox itself might have a gradient + if( rStyleSettings.GetFaceColor() == Color( COL_WHITE ) ) + bHighContrastWhite = TRUE; + + // draw separators in flat style only + if ( !bLayout && + (mnOutStyle & TOOLBOX_STYLE_FLAT) && + (pItem->meType == TOOLBOXITEM_SEPARATOR) && + nPos > 0 + ) + { + // no separator before or after windows or at breaks + ImplToolItem* pTempItem = &mpData->m_aItems[nPos-1]; + if ( pTempItem && !pTempItem->mbShowWindow && nPos < mpData->m_aItems.size()-1 ) + { + pTempItem = &mpData->m_aItems[nPos+1]; + if ( !pTempItem->mbShowWindow && !pTempItem->mbBreak ) + { + long nCenterPos, nSlim; + SetLineColor( rStyleSettings.GetSeparatorColor() ); + if ( IsHorizontal() ) + { + nSlim = (pItem->maRect.Bottom() - pItem->maRect.Top ()) / 4; + nCenterPos = pItem->maRect.Center().X(); + DrawLine( Point( nCenterPos, pItem->maRect.Top() + nSlim ), + Point( nCenterPos, pItem->maRect.Bottom() - nSlim ) ); + } + else + { + nSlim = (pItem->maRect.Right() - pItem->maRect.Left ()) / 4; + nCenterPos = pItem->maRect.Center().Y(); + DrawLine( Point( pItem->maRect.Left() + nSlim, nCenterPos ), + Point( pItem->maRect.Right() - nSlim, nCenterPos ) ); + } + } + } + } + + // do nothing if item is no button or will be displayed as window + if ( (pItem->meType != TOOLBOXITEM_BUTTON) || + (pItem->mbShowWindow && !mbCustomizeMode) ) + return; + + // we need a TBDragMananger to draw the configuration item + ImplTBDragMgr* pMgr; + if ( pItem->mnId == mnConfigItem ) + { + pMgr = ImplGetTBDragMgr(); + pMgr->HideDragRect(); + } + else + pMgr = NULL; + + // during configuration mode visible windows will be drawn in a special way + if ( mbCustomizeMode && pItem->mbShowWindow ) + { + Font aOldFont = GetFont(); + Color aOldTextColor = GetTextColor(); + + SetZoomedPointFont( rStyleSettings.GetAppFont() ); + SetLineColor( Color( COL_BLACK ) ); + SetFillColor( rStyleSettings.GetFieldColor() ); + SetTextColor( rStyleSettings.GetFieldTextColor() ); + if( !bLayout ) + DrawRect( pItem->maRect ); + + Size aSize( GetCtrlTextWidth( pItem->maText ), GetTextHeight() ); + Point aPos( pItem->maRect.Left()+2, pItem->maRect.Top() ); + aPos.Y() += (pItem->maRect.GetHeight()-aSize.Height())/2; + BOOL bClip; + if ( (aSize.Width() > pItem->maRect.GetWidth()-2) || + (aSize.Height() > pItem->maRect.GetHeight()-2) ) + { + bClip = TRUE; + Rectangle aTempRect( pItem->maRect.Left()+1, pItem->maRect.Top()+1, + pItem->maRect.Right()-1, pItem->maRect.Bottom()-1 ); + Region aTempRegion( aTempRect ); + SetClipRegion( aTempRegion ); + } + else + bClip = FALSE; + if( bLayout ) + { + mpData->m_pLayoutData->m_aLineIndices.push_back( mpData->m_pLayoutData->m_aDisplayText.Len() ); + mpData->m_pLayoutData->m_aLineItemIds.push_back( pItem->mnId ); + mpData->m_pLayoutData->m_aLineItemPositions.push_back( nPos ); + } + DrawCtrlText( aPos, pItem->maText, 0, STRING_LEN, TEXT_DRAW_MNEMONIC, pVector, pDisplayText ); + if ( bClip ) + SetClipRegion(); + SetFont( aOldFont ); + SetTextColor( aOldTextColor ); + + // Gegebenenfalls noch Config-Frame zeichnen + if ( pMgr && !bLayout) + pMgr->UpdateDragRect(); + return; + } + + // draw button + Size aBtnSize = pItem->maRect.GetSize(); + if( ImplGetSVData()->maNWFData.mbToolboxDropDownSeparate ) + { + // separate button not for dropdown only where the whole button is painted + if ( pItem->mnBits & TIB_DROPDOWN && + ((pItem->mnBits & TIB_DROPDOWNONLY) != TIB_DROPDOWNONLY) ) + { + Rectangle aArrowRect = pItem->GetDropDownRect( mbHorz ); + if( aArrowRect.Top() == pItem->maRect.Top() ) // dropdown arrow on right side + aBtnSize.Width() -= aArrowRect.GetWidth(); + else // dropdown arrow on bottom side + aBtnSize.Height() -= aArrowRect.GetHeight(); + } + } + Rectangle aButtonRect( pItem->maRect.TopLeft(), aBtnSize ); + long nOffX = SMALLBUTTON_OFF_NORMAL_X; + long nOffY = SMALLBUTTON_OFF_NORMAL_Y; + long nImageOffX=0; + long nImageOffY=0; + long nTextOffX=0; + long nTextOffY=0; + USHORT nStyle = 0; + + if ( pItem->meState == STATE_CHECK ) + { + nStyle |= BUTTON_DRAW_CHECKED; + } + else if ( pItem->meState == STATE_DONTKNOW ) + { + nStyle |= BUTTON_DRAW_DONTKNOW; + } + if ( bHighlight == 1 ) + { + nStyle |= BUTTON_DRAW_PRESSED; + } + + if ( mnOutStyle & TOOLBOX_STYLE_OUTBUTTON ) + { + nOffX = OUTBUTTON_OFF_NORMAL_X; + nOffY = OUTBUTTON_OFF_NORMAL_Y; + if ( bHighlight ) + { + nOffX++; + nOffY++; + } + } + + if( ! bLayout ) + { + if ( mnOutStyle & TOOLBOX_STYLE_FLAT ) + { + if ( (pItem->meState != STATE_NOCHECK) || !bPaint ) + { + ImplErase( this, pItem->maRect, bHighlight, bHasOpenPopup ); + } + } + else + { + if ( mnOutStyle & TOOLBOX_STYLE_OUTBUTTON ) + ImplDrawOutButton( this, aButtonRect, nStyle ); + else + { + DecorationView aDecoView( this ); + aDecoView.DrawButton( aButtonRect, nStyle ); + } + } + } + + nOffX += pItem->maRect.Left(); + nOffY += pItem->maRect.Top(); + + // determine what has to be drawn on the button: image, text or both + BOOL bImage; + BOOL bText; + ButtonType tmpButtonType = determineButtonType( pItem, meButtonType ); // default to toolbox setting + pItem->DetermineButtonDrawStyle( tmpButtonType, bImage, bText ); + + // compute output values + long nBtnWidth = aBtnSize.Width()-SMALLBUTTON_HSIZE; + long nBtnHeight = aBtnSize.Height()-SMALLBUTTON_VSIZE; + Size aImageSize; + Size aTxtSize; + + if ( bText ) + { + aTxtSize.Width() = GetCtrlTextWidth( pItem->maText ); + aTxtSize.Height() = GetTextHeight(); + } + + if ( bImage && ! bLayout ) + { + const Image* pImage; + if ( bHighlight && (!(pItem->maHighImage)) == FALSE ) + pImage = &(pItem->maHighImage); + else + pImage = &(pItem->maImage); + + aImageSize = pImage->GetSizePixel(); + + // determine drawing flags + USHORT nImageStyle = 0; + + if ( !pItem->mbEnabled || !IsEnabled() ) + nImageStyle |= IMAGE_DRAW_DISABLE; + + // #i35563# the dontknow state indicates different states at the same time + // which should not be rendered disabled but normal + //if ( pItem->meState == STATE_DONTKNOW ) + // nImageStyle |= IMAGE_DRAW_DISABLE; + + // draw the image + nImageOffX = nOffX; + nImageOffY = nOffY; + if ( (pItem->mnBits & (TIB_LEFT|TIB_DROPDOWN)) || bText ) + { + // left align also to leave space for drop down arrow + // and when drawing text+image + // just center in y, except for vertical (ie rotated text) + if( mbHorz || !bText ) + nImageOffY += (nBtnHeight-aImageSize.Height())/2; + } + else + { + nImageOffX += (nBtnWidth-aImageSize.Width())/2; + nImageOffY += (nBtnHeight-aImageSize.Height())/2; + } + if ( bHighlight || (pItem->meState == STATE_CHECK) ) + { + if( bHasOpenPopup ) + ImplDrawFloatwinBorder( pItem ); + else + ImplDrawButton( this, aButtonRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow ? TRUE : FALSE ); + + if( bHighlight ) + { + if( bHighContrastWhite ) + nImageStyle |= IMAGE_DRAW_COLORTRANSFORM; + } + } + DrawImage( Point( nImageOffX, nImageOffY ), *pImage, nImageStyle ); + } + + // draw the text + BOOL bRotate = FALSE; + if ( bText ) + { + nTextOffX = nOffX; + nTextOffY = nOffY; + + // rotate text when vertically docked + Font aOldFont = GetFont(); + if( pItem->mbVisibleText && !ImplIsFloatingMode() && + ((meAlign == WINDOWALIGN_LEFT) || (meAlign == WINDOWALIGN_RIGHT)) ) + { + bRotate = TRUE; + + Font aRotateFont = aOldFont; + /* + if ( meAlign == WINDOWALIGN_LEFT ) + { + aRotateFont.SetOrientation( 900 ); + nTextOffX += (nBtnWidth-aTxtSize.Height())/2; + nTextOffY += aTxtSize.Width(); + nTextOffY += (nBtnHeight-aTxtSize.Width())/2; + } + else*/ + { + aRotateFont.SetOrientation( 2700 ); + + // center horizontally + nTextOffX += aTxtSize.Height(); + nTextOffX += (nBtnWidth-aTxtSize.Height())/2; + + // add in image offset + if( bImage ) + nTextOffY = nImageOffY + aImageSize.Height() + TB_IMAGETEXTOFFSET; + } + + SetFont( aRotateFont ); + } + else + { + // center vertically + nTextOffY += (nBtnHeight-aTxtSize.Height())/2; + + // add in image offset + if( bImage ) + nTextOffX = nImageOffX + aImageSize.Width() + TB_IMAGETEXTOFFSET; + //nTextOffX += TB_TEXTOFFSET/2; + } + + // draw selection only if not already drawn during image output (see above) + if ( !bLayout && !bImage && (bHighlight || (pItem->meState == STATE_CHECK) ) ) + { + if( bHasOpenPopup ) + ImplDrawFloatwinBorder( pItem ); + else + ImplDrawButton( this, pItem->maRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), pItem->mbShowWindow ? TRUE : FALSE ); + } + + USHORT nTextStyle = 0; + if ( !pItem->mbEnabled ) + nTextStyle |= TEXT_DRAW_DISABLE; + if( bLayout ) + { + mpData->m_pLayoutData->m_aLineIndices.push_back( mpData->m_pLayoutData->m_aDisplayText.Len() ); + mpData->m_pLayoutData->m_aLineItemIds.push_back( pItem->mnId ); + mpData->m_pLayoutData->m_aLineItemPositions.push_back( nPos ); + } + DrawCtrlText( Point( nTextOffX, nTextOffY ), pItem->maText, + 0, STRING_LEN, nTextStyle, pVector, pDisplayText ); + if ( bRotate ) + SetFont( aOldFont ); + } + + if( bLayout ) + return; + + // paint optional drop down arrow + if ( pItem->mnBits & TIB_DROPDOWN ) + { + Rectangle aDropDownRect( pItem->GetDropDownRect( mbHorz ) ); + BOOL bSetColor = TRUE; + if ( !pItem->mbEnabled || !IsEnabled() ) + { + bSetColor = FALSE; + SetFillColor( rStyleSettings.GetShadowColor() ); + } + + // dropdown only will be painted without inner border + if( (pItem->mnBits & TIB_DROPDOWNONLY) != TIB_DROPDOWNONLY ) + { + ImplErase( this, aDropDownRect, bHighlight, bHasOpenPopup ); + + if( bHighlight || (pItem->meState == STATE_CHECK) ) + { + if( bHasOpenPopup ) + ImplDrawFloatwinBorder( pItem ); + else + ImplDrawButton( this, aDropDownRect, bHighlight, pItem->meState == STATE_CHECK, pItem->mbEnabled && IsEnabled(), FALSE ); + } + } + ImplDrawDropdownArrow( this, aDropDownRect, bSetColor, bRotate ); + } + + // Gegebenenfalls noch Config-Frame zeichnen + if ( pMgr ) + pMgr->UpdateDragRect(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplStartCustomizeMode() +{ + mbCustomizeMode = TRUE; + + mpData->ImplClearLayoutData(); + + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if ( it->mbShowWindow ) + { + it->mpWindow->Hide(); + + if ( !(it->maRect.IsEmpty()) ) + Invalidate( it->maRect ); + } + + ++it; + } +} + +void ToolBox::SetCustomizeMode( BOOL bSet ) +{ + if ( bSet ) + ImplStartCustomizeMode(); + else + ImplEndCustomizeMode(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplEndCustomizeMode() +{ + mbCustomizeMode = FALSE; + + mpData->ImplClearLayoutData(); + + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if ( it->mbShowWindow ) + { + if ( !(it->maRect.IsEmpty()) ) + Invalidate( it->maRect ); + + it->mpWindow->Show(); + } + + ++it; + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDrawFloatwinBorder( ImplToolItem* pItem ) +{ + if ( !pItem->maRect.IsEmpty() ) + { + Rectangle aRect( mpFloatWin->ImplGetItemEdgeClipRect() ); + aRect.SetPos( AbsoluteScreenToOutputPixel( aRect.TopLeft() ) ); + SetLineColor( GetSettings().GetStyleSettings().GetShadowColor() ); + Point p1, p2; + + p1 = pItem->maRect.TopLeft(); + p1.X()++; + p2 = pItem->maRect.TopRight(); + p2.X()--; + DrawLine( p1, p2); + p1 = pItem->maRect.BottomLeft(); + p1.X()++; + p2 = pItem->maRect.BottomRight(); + p2.X()--; + DrawLine( p1, p2); + + p1 = pItem->maRect.TopLeft(); + p1.Y()++; + p2 = pItem->maRect.BottomLeft(); + p2.Y()--; + DrawLine( p1, p2); + p1 = pItem->maRect.TopRight(); + p1.Y()++; + p2 = pItem->maRect.BottomRight(); + p2.Y()--; + DrawLine( p1, p2); + + //DrawRect( pItem->maRect ); + } +} + +void ToolBox::ImplFloatControl( BOOL bStart, FloatingWindow* pFloatWindow ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( bStart ) + { + mpFloatWin = pFloatWindow; + + // redraw item, to trigger drawing of a special border + ImplDrawItem( mnCurPos, TRUE ); + + mbDrag = FALSE; + EndTracking(); + ReleaseMouse(); + } + else + { + mpFloatWin = NULL; + + // if focus is still in this toolbox, then the floater was opened by keyboard + // draw current item with highlight and keep old state + BOOL bWasKeyboardActivate = mpData->mbDropDownByKeyboard; + + + if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + ImplDrawItem( mnCurPos, bWasKeyboardActivate ? 2 : 0 ); + Deactivate(); + + if( !bWasKeyboardActivate ) + { + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + mnHighItemId = 0; + } + mnDownItemId = 0; + + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ShowLine( BOOL bNext ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mbFormat = TRUE; + + if ( mpData->mbPageScroll ) + { + USHORT delta = mnVisLines; + if ( bNext ) + { + mnCurLine = mnCurLine + delta; + if ( mnCurLine+mnVisLines-1 > mnCurLines ) + mnCurLine = mnCurLines - mnVisLines+1; + } + else + { + if( mnCurLine >= delta+1 ) + mnCurLine = mnCurLine - delta; + else + mnCurLine = 1; + } + } + else + { + if ( bNext ) + mnCurLine++; + else + mnCurLine--; + } + + ImplFormat(); +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::ImplHandleMouseMove( const MouseEvent& rMEvt, BOOL bRepeat ) +{ + Point aMousePos = rMEvt.GetPosPixel(); + + // Ist ToolBox aktiv + if ( mbDrag && mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + { + // Befindet sich Maus ueber dem Item + ImplToolItem* pItem = &mpData->m_aItems[mnCurPos]; + if ( pItem->maRect.IsInside( aMousePos ) ) + { + if ( !mnCurItemId ) + { + ImplDrawItem( mnCurPos, TRUE ); + mnCurItemId = pItem->mnId; + Highlight(); + } + + if ( (pItem->mnBits & TIB_REPEAT) && bRepeat ) + Select(); + } + else + { + if ( mnCurItemId ) + { + ImplDrawItem( mnCurPos ); + mnCurItemId = 0; + ImplDrawItem( mnCurPos ); + Highlight(); + } + } + + return TRUE; + } + + if ( mbUpper ) + { + BOOL bNewIn = maUpperRect.IsInside( aMousePos ); + if ( bNewIn != mbIn ) + { + mbIn = bNewIn; + ImplDrawSpin( mbIn, FALSE ); + } + return TRUE; + } + + if ( mbLower ) + { + BOOL bNewIn = maLowerRect.IsInside( aMousePos ); + if ( bNewIn != mbIn ) + { + mbIn = bNewIn; + ImplDrawSpin( FALSE, mbIn ); + } + return TRUE; + } + + if ( mbNextTool ) + { + BOOL bNewIn = maNextToolRect.IsInside( aMousePos ); + if ( bNewIn != mbIn ) + { + mbIn = bNewIn; + ImplDrawNext( mbIn ); + } + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::ImplHandleMouseButtonUp( const MouseEvent& rMEvt, BOOL bCancel ) +{ + ImplDisableFlatButtons(); + + // stop eventual running dropdown timer + if( mnCurPos < mpData->m_aItems.size() && + (mpData->m_aItems[mnCurPos].mnBits & TIB_DROPDOWN ) ) + { + mpData->maDropdownTimer.Stop(); + } + + if ( mbDrag || mbSelection ) + { + // Hier die MouseDaten setzen, wenn Selection-Modus, da dann kein + // MouseButtonDown-Handler gerufen wird + if ( mbSelection ) + { + mnMouseClicks = rMEvt.GetClicks(); + mnMouseModifier = rMEvt.GetModifier(); + } + + Deactivate(); + + if ( mbDrag ) + mbDrag = FALSE; + else + { + mbSelection = FALSE; + if ( mnCurPos == TOOLBOX_ITEM_NOTFOUND ) + return TRUE; + } + + // Wurde Maus ueber dem Item losgelassen + if( mnCurPos < mpData->m_aItems.size() ) + { + ImplToolItem* pItem = &mpData->m_aItems[mnCurPos]; + if ( pItem->maRect.IsInside( rMEvt.GetPosPixel() ) ) + { + mnCurItemId = pItem->mnId; + if ( !bCancel ) + { + // Gegebenenfalls ein AutoCheck durchfuehren + if ( pItem->mnBits & TIB_AUTOCHECK ) + { + if ( pItem->mnBits & TIB_RADIOCHECK ) + { + if ( pItem->meState != STATE_CHECK ) + SetItemState( pItem->mnId, STATE_CHECK ); + } + else + { + if ( pItem->meState != STATE_CHECK ) + pItem->meState = STATE_CHECK; + else + pItem->meState = STATE_NOCHECK; + } + } + + // Select nicht bei Repeat ausloesen, da dies schon im + // MouseButtonDown ausgeloest wurde + if ( !(pItem->mnBits & TIB_REPEAT) ) + { + // Gegen zerstoeren im Select-Handler sichern + ImplDelData aDelData; + ImplAddDel( &aDelData ); + Select(); + if ( aDelData.IsDelete() ) + return TRUE; + ImplRemoveDel( &aDelData ); + } + } + + { + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + // Items nicht geloescht, im Select-Handler + if ( mnCurItemId ) + { + BOOL bHighlight; + if ( (mnCurItemId == mnHighItemId) && (mnOutStyle & TOOLBOX_STYLE_FLAT) ) + bHighlight = 2; + else + bHighlight = FALSE; + // Get current pos for the case that items are inserted/removed + // in the toolBox + mnCurPos = GetItemPos( mnCurItemId ); + if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplDrawItem( mnCurPos, bHighlight ); + Flush(); + } + } + } + } + + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + mnDownItemId = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; + return TRUE; + } + else if ( mbUpper || mbLower ) + { + if ( mbIn ) + ShowLine( !mbUpper ); + mbUpper = FALSE; + mbLower = FALSE; + mbIn = FALSE; + ImplDrawSpin( FALSE, FALSE ); + return TRUE; + } + else if ( mbNextTool ) + { + mbNextTool = FALSE; + mbIn = FALSE; + ImplDrawNext( FALSE ); + NextToolBox(); + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::MouseMove( const MouseEvent& rMEvt ) +{ + // pressing a modifier generates synthetic mouse moves + // ignore it if keyboard selection is acive + if( HasFocus() && ( rMEvt.GetMode() & MOUSE_MODIFIERCHANGED ) ) + return; + + if ( ImplHandleMouseMove( rMEvt ) ) + return; + + ImplDisableFlatButtons(); + + Point aMousePos = rMEvt.GetPosPixel(); + + // only highlight when the focus is not inside a child window of a toolbox + // eg, in a edit control + // and do not hilight when focus is in a different toolbox + BOOL bDrawHotSpot = TRUE; + Window *pWin = Application::GetFocusWindow(); + if( pWin && pWin->ImplGetWindowImpl()->mbToolBox && pWin != this ) + bDrawHotSpot = FALSE; + /* + else + if( pWin && !pWin->ImplGetWindowImpl()->mbToolBox ) + while( pWin ) + { + pWin = pWin->GetParent(); + if( pWin && pWin->ImplGetWindowImpl()->mbToolBox ) + { + bDrawHotSpot = FALSE; + break; + } + } + */ + + if ( mbSelection && bDrawHotSpot ) + { + USHORT i = 0; + USHORT nNewPos = TOOLBOX_ITEM_NOTFOUND; + + // Item suchen, das geklickt wurde + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + // Wenn Mausposition in diesem Item vorhanden, kann die + // Suche abgebrochen werden + if ( it->maRect.IsInside( aMousePos ) ) + { + // Wenn es ein Button ist, dann wird er selektiert + if ( it->meType == TOOLBOXITEM_BUTTON ) + { + // Wenn er disablet ist, findet keine Aenderung + // statt + if ( !it->mbEnabled || it->mbShowWindow ) + nNewPos = mnCurPos; + else + nNewPos = i; + } + + break; + } + + i++; + ++it; + } + + // was a new entery selected ? + // don't change selection if keyboard selection is active and + // mouse leaves the toolbox + if ( nNewPos != mnCurPos && !( HasFocus() && nNewPos == TOOLBOX_ITEM_NOTFOUND ) ) + { + if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplDrawItem( mnCurPos ); + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( mnCurPos ) ); + } + + mnCurPos = nNewPos; + if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + { + mnCurItemId = mnHighItemId = it->mnId; + ImplDrawItem( mnCurPos, 2 /*TRUE*/ ); // always use shadow effect (2) + } + else + mnCurItemId = mnHighItemId = 0; + + Highlight(); + } + return; + } + + if ( mbDragging ) + { + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + pMgr->Dragging( aMousePos ); + return; + } + + PointerStyle eStyle = POINTER_ARROW; + + // change mouse cursor over drag area + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper && pWrapper->GetDragArea().IsInside( rMEvt.GetPosPixel() ) ) + eStyle = POINTER_MOVE; + + if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING ) + { + if ( rMEvt.GetMode() & MOUSE_SIMPLEMOVE ) + { + USHORT nLinePtr = ImplTestLineSize( this, rMEvt.GetPosPixel() ); + if ( nLinePtr & DOCK_LINEHSIZE ) + { + if ( meAlign == WINDOWALIGN_LEFT ) + eStyle = POINTER_WINDOW_ESIZE; + else + eStyle = POINTER_WINDOW_WSIZE; + } + else if ( nLinePtr & DOCK_LINEVSIZE ) + { + if ( meAlign == WINDOWALIGN_TOP ) + eStyle = POINTER_WINDOW_SSIZE; + else + eStyle = POINTER_WINDOW_NSIZE; + } + } + } + + if ( (eStyle == POINTER_ARROW) && mbCustomizeMode ) + { + // Item suchen, das geklickt wurde + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + // Wenn es ein Customize-Window ist, gegebenenfalls den + // Resize-Pointer anzeigen + if ( it->mbShowWindow ) + { + if ( it->maRect.IsInside( aMousePos ) ) + { + if ( it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X() ) + eStyle = POINTER_HSIZEBAR; + break; + } + } + + ++it; + } + } + + if ( bDrawHotSpot && ( ((eStyle == POINTER_ARROW) && (mnOutStyle & TOOLBOX_STYLE_HANDPOINTER)) || + (mnOutStyle & TOOLBOX_STYLE_FLAT) || !mnOutStyle ) ) + { + BOOL bClearHigh = TRUE; + if ( !rMEvt.IsLeaveWindow() && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) ) + { + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if ( it->maRect.IsInside( aMousePos ) ) + { + if ( (it->meType == TOOLBOXITEM_BUTTON) && it->mbEnabled ) + { + if ( !mnOutStyle || (mnOutStyle & TOOLBOX_STYLE_FLAT) ) + { + bClearHigh = FALSE; + if ( mnHighItemId != it->mnId ) + { + USHORT nTempPos = sal::static_int_cast<USHORT>(it - mpData->m_aItems.begin()); + if ( mnHighItemId ) + { + ImplHideFocus(); + USHORT nPos = GetItemPos( mnHighItemId ); + ImplDrawItem( nPos ); + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) ); + } + if ( mpData->mbMenubuttonSelected ) + { + // remove highlight from menubutton + ImplDrawMenubutton( this, FALSE ); + } + mnHighItemId = it->mnId; + ImplDrawItem( nTempPos, 2 ); + ImplShowFocus(); + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT ); + } + } + if ( mnOutStyle & TOOLBOX_STYLE_HANDPOINTER ) + eStyle = POINTER_REFHAND; + } + break; + } + + ++it; + } + } + + // only clear highlight when focus is not in toolbar + BOOL bMenuButtonHit = mpData->maMenubuttonItem.maRect.IsInside( aMousePos ); + if ( bClearHigh || bMenuButtonHit ) + { + if ( !bMenuButtonHit && mpData->mbMenubuttonSelected ) + { + // remove highlight from menubutton + ImplDrawMenubutton( this, FALSE ); + } + + if( mnHighItemId ) + { + USHORT nClearPos = GetItemPos( mnHighItemId ); + if ( nClearPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplDrawItem( nClearPos, (nClearPos == mnCurPos) ? TRUE : FALSE ); + if( nClearPos != mnCurPos ) + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nClearPos ) ); + } + ImplHideFocus(); + mnHighItemId = 0; + } + + if( bMenuButtonHit ) + { + ImplDrawMenubutton( this, TRUE ); + } + } + } + + if ( meLastStyle != eStyle ) + { + meLastStyle = eStyle; + Pointer aPtr( eStyle ); + SetPointer( aPtr ); + } + + DockingWindow::MouseMove( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // Nur bei linker Maustaste ToolBox ausloesen und wenn wir uns nicht + // noch in der normalen Bearbeitung befinden + if ( rMEvt.IsLeft() && !mbDrag && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) ) + { + // Activate schon hier rufen, da gegebenenfalls noch Items + // ausgetauscht werden + Activate(); + + // ToolBox hier updaten, damit der Anwender weiss, was Sache ist + if ( mbFormat ) + { + ImplFormat(); + Update(); + } + + Point aMousePos = rMEvt.GetPosPixel(); + USHORT i = 0; + USHORT nNewPos = TOOLBOX_ITEM_NOTFOUND; + + // Item suchen, das geklickt wurde + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + // Ist es dieses Item + if ( it->maRect.IsInside( aMousePos ) ) + { + // Ist es ein Separator oder ist das Item disabled, + // dann mache nichts + if ( (it->meType == TOOLBOXITEM_BUTTON) && + (!it->mbShowWindow || mbCustomizeMode) ) + nNewPos = i; + + break; + } + + i++; + ++it; + } + + // Item gefunden + if ( nNewPos != TOOLBOX_ITEM_NOTFOUND ) + { + if ( mbCustomize ) + { + if ( rMEvt.IsMod2() || mbCustomizeMode ) + { + Deactivate(); + + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + Rectangle aItemRect = GetItemRect( it->mnId ); + mnConfigItem = it->mnId; + + BOOL bResizeItem; + if ( mbCustomizeMode && it->mbShowWindow && + (it->maRect.Right()-TB_RESIZE_OFFSET <= aMousePos.X()) ) + bResizeItem = TRUE; + else + bResizeItem = FALSE; + pMgr->StartDragging( this, aMousePos, aItemRect, 0, bResizeItem ); + return; + } + } + + if ( !it->mbEnabled ) + { + Deactivate(); + return; + } + + + // Aktuelle Daten setzen + USHORT nTrackFlags = 0; + mnCurPos = i; + mnCurItemId = it->mnId; + mnDownItemId = mnCurItemId; + mnMouseClicks = rMEvt.GetClicks(); + mnMouseModifier = rMEvt.GetModifier(); + if ( it->mnBits & TIB_REPEAT ) + nTrackFlags |= STARTTRACK_BUTTONREPEAT; + + + if ( mbSelection ) + { + ImplDrawItem( mnCurPos, TRUE ); + Highlight(); + } + else + { + // Hier schon bDrag setzen, da in EndSelection ausgewertet wird + mbDrag = TRUE; + + // Bei Doppelklick nur den Handler rufen, aber bevor der + // Button gehiltet wird, da evt. in diesem Handler der + // Drag-Vorgang abgebrochen wird + if ( rMEvt.GetClicks() == 2 ) + DoubleClick(); + + + if ( mbDrag ) + { + ImplDrawItem( mnCurPos, TRUE ); + Highlight(); + } + + // was dropdown arrow pressed + if( (it->mnBits & TIB_DROPDOWN) ) + { + if( ( (it->mnBits & TIB_DROPDOWNONLY) == TIB_DROPDOWNONLY) || it->GetDropDownRect( mbHorz ).IsInside( aMousePos )) + { + // dropdownonly always triggers the dropdown handler, over the whole button area + + // the drop down arrow should not trigger the item action + mpData->mbDropDownByKeyboard = FALSE; + GetDropdownClickHdl().Call( this ); + + // do not reset data if the dropdown handler opened a floating window + // see ImplFloatControl() + if( mpFloatWin == NULL ) + { + // no floater was opened + Deactivate(); + ImplDrawItem( mnCurPos, FALSE ); + + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + mnDownItemId = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; + mnHighItemId = 0; + } + return; + } + else // activate long click timer + mpData->maDropdownTimer.Start(); + } + + + // Click-Handler aufrufen + if ( rMEvt.GetClicks() != 2 ) + Click(); + + // Bei Repeat auch den Select-Handler rufen + if ( nTrackFlags & STARTTRACK_BUTTONREPEAT ) + Select(); + + // Wenn die Aktion nicht im Click-Handler abgebrochen wurde + if ( mbDrag ) + StartTracking( nTrackFlags ); + } + + // Wenn Maus ueber einem Item gedrueckt wurde, koennen wir + // die Bearbeitung abbrechen + return; + } + + Deactivate(); + + // menu button hit ? + if( mpData->maMenubuttonItem.maRect.IsInside( aMousePos ) ) + { + ExecuteCustomMenu(); + return; + } + + + // Gegebenenfalls noch Scroll- und Next-Buttons ueberpruefen + if ( maUpperRect.IsInside( aMousePos ) ) + { + if ( mnCurLine > 1 ) + { + StartTracking(); + mbUpper = TRUE; + mbIn = TRUE; + ImplDrawSpin( TRUE, FALSE ); + } + return; + } + if ( maLowerRect.IsInside( aMousePos ) ) + { + if ( mnCurLine+mnVisLines-1 < mnCurLines ) + { + StartTracking(); + mbLower = TRUE; + mbIn = TRUE; + ImplDrawSpin( FALSE, TRUE ); + } + return; + } + if ( maNextToolRect.IsInside( aMousePos ) ) + { + StartTracking(); + mbNextTool = TRUE; + mbIn = TRUE; + ImplDrawNext( TRUE ); + return; + } + + // Linesizing testen + if ( (mnWinStyle & TB_WBLINESIZING) == TB_WBLINESIZING ) + { + USHORT nLineMode = ImplTestLineSize( this, aMousePos ); + if ( nLineMode ) + { + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + + // Handler rufen, damit die Dock-Rectangles gesetzt werden + // koenen + StartDocking(); + + Point aPos = GetParent()->OutputToScreenPixel( GetPosPixel() ); + Size aSize = GetSizePixel(); + aPos = ScreenToOutputPixel( aPos ); + + // Dragging starten + pMgr->StartDragging( this, aMousePos, Rectangle( aPos, aSize ), + nLineMode, FALSE ); + return; + } + } + + // Kein Item, dann nur Click oder DoubleClick + if ( rMEvt.GetClicks() == 2 ) + DoubleClick(); + else + Click(); + } + + if ( !mbDrag && !mbSelection && (mnCurPos == TOOLBOX_ITEM_NOTFOUND) ) + DockingWindow::MouseButtonDown( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if ( ImplHandleMouseButtonUp( rMEvt ) ) + return; + + if ( mbDragging && (rMEvt.IsLeft() || mbCommandDrag) ) + { + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + pMgr->EndDragging(); + return; + } + mbCommandDrag = FALSE; + + DockingWindow::MouseButtonUp( rMEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Tracking( const TrackingEvent& rTEvt ) +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + if ( rTEvt.IsTrackingEnded() ) + ImplHandleMouseButtonUp( rTEvt.GetMouseEvent(), rTEvt.IsTrackingCanceled() ); + else + ImplHandleMouseMove( rTEvt.GetMouseEvent(), rTEvt.IsTrackingRepeat() ); + + if ( aDelData.IsDelete() ) + // toolbox was deleted + return; + ImplRemoveDel( &aDelData ); + DockingWindow::Tracking( rTEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Paint( const Rectangle& rPaintRect ) +{ + if( mpData->mbIsPaintLocked ) + return; + if ( rPaintRect == Rectangle( 0, 0, mnDX-1, mnDY-1 ) ) + mbFullPaint = TRUE; + ImplFormat(); + mbFullPaint = FALSE; + + + ImplDrawBackground( this, rPaintRect ); + + if ( (mnWinStyle & WB_BORDER) && !ImplIsFloatingMode() ) + ImplDrawBorder( this ); + + if( !ImplIsFloatingMode() ) + ImplDrawGrip( this ); + + ImplDrawMenubutton( this, mpData->mbMenubuttonSelected ); + + // SpinButtons zeichnen + if ( mnWinStyle & WB_SCROLL ) + { + if ( mnCurLines > mnLines ) + ImplDrawSpin( FALSE, FALSE ); + } + + // NextButton zeichnen + ImplDrawNext( FALSE ); + + // Buttons zeichnen + USHORT nHighPos; + if ( mnHighItemId ) + nHighPos = GetItemPos( mnHighItemId ); + else + nHighPos = TOOLBOX_ITEM_NOTFOUND; + + USHORT nCount = (USHORT)mpData->m_aItems.size(); + for( USHORT i = 0; i < nCount; i++ ) + { + ImplToolItem* pItem = &mpData->m_aItems[i]; + + // Nur malen, wenn Rechteck im PaintRectangle liegt + if ( !pItem->maRect.IsEmpty() && rPaintRect.IsOver( pItem->maRect ) ) + { + BOOL bHighlight = FALSE; + if ( i == mnCurPos ) + bHighlight = 1; + else if ( i == nHighPos ) + bHighlight = 2; + ImplDrawItem( i, bHighlight ); + } + } + ImplShowFocus(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Move() +{ + DockingWindow::Move(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Resize() +{ + Size aSize = GetOutputSizePixel(); + // #i31422# some WindowManagers send (0,0) sizes when + // switching virtual desktops - ignore this and avoid reformatting + if( !aSize.Width() && !aSize.Height() ) + return; + + long nOldDX = mnDX; + long nOldDY = mnDY; + mnDX = aSize.Width(); + mnDY = aSize.Height(); + + mnLastResizeDY = 0; + + // invalidate everything to have gradient backgrounds properly drawn + Invalidate(); + + // Evt. neu formatieren oder neu painten + if ( mbScroll ) + { + if ( !mbFormat ) + { + mbFormat = TRUE; + if( IsReallyVisible() ) + ImplFormat( TRUE ); + } + } + + // Border muss neu ausgegeben werden + if ( mnWinStyle & WB_BORDER ) + { + // Da wir sonst beim Paint denken, das alles neu gepaintet wird + if ( mbFormat && IsReallyVisible() ) + Invalidate(); + else + { + if ( mnRightBorder ) + { + if ( nOldDX > mnDX ) + Invalidate( Rectangle( mnDX-mnRightBorder-1, 0, mnDX, mnDY ) ); + else + Invalidate( Rectangle( nOldDX-mnRightBorder-1, 0, nOldDX, nOldDY ) ); + } + + if ( mnBottomBorder ) + { + if ( nOldDY > mnDY ) + Invalidate( Rectangle( 0, mnDY-mnBottomBorder-1, mnDX, mnDY ) ); + else + Invalidate( Rectangle( 0, nOldDY-mnBottomBorder-1, nOldDX, nOldDY ) ); + } + } + } +} + +// ----------------------------------------------------------------------- +const XubString& ToolBox::ImplGetHelpText( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + { + if ( !pItem->maHelpText.Len() && ( pItem->maHelpId.getLength() || pItem->maCommandStr.Len() )) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if ( pItem->maCommandStr.Len() ) + pItem->maHelpText = pHelp->GetHelpText( pItem->maCommandStr, this ); + if ( !pItem->maHelpText.Len() && pItem->maHelpId.getLength() ) + pItem->maHelpText = pHelp->GetHelpText( rtl::OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + } + + return pItem->maHelpText; + } + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::RequestHelp( const HelpEvent& rHEvt ) +{ + USHORT nItemId; + Point aHelpPos; + + if( !rHEvt.KeyboardActivated() ) + { + nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + aHelpPos = rHEvt.GetMousePosPixel(); + } + else + { + if( !mnHighItemId ) + return; + else + nItemId = mnHighItemId; + Rectangle aRect( GetItemRect( nItemId ) ); + if( aRect.IsEmpty() ) + return; + else + aHelpPos = OutputToScreenPixel( aRect.Center() ); + } + + if ( nItemId ) + { + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) ) + { + // Rechteck ermitteln + Rectangle aTempRect = GetItemRect( nItemId ); + Point aPt = OutputToScreenPixel( aTempRect.TopLeft() ); + aTempRect.Left() = aPt.X(); + aTempRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aTempRect.BottomRight() ); + aTempRect.Right() = aPt.X(); + aTempRect.Bottom() = aPt.Y(); + + // Text ermitteln und anzeigen + XubString aStr = GetQuickHelpText( nItemId ); + const XubString& rHelpStr = GetHelpText( nItemId ); + if ( !aStr.Len() ) + aStr = MnemonicGenerator::EraseAllMnemonicChars( GetItemText( nItemId ) ); + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + { + if ( rHelpStr.Len() ) + aStr = rHelpStr; + Help::ShowBalloon( this, aHelpPos, aTempRect, aStr ); + } + else + Help::ShowQuickHelp( this, aTempRect, aStr, rHelpStr, QUICKHELP_CTRLTEXT ); + return; + } + else if ( rHEvt.GetMode() & HELPMODE_EXTENDED ) + { + String aCommand = GetItemCommand( nItemId ); + rtl::OString aHelpId( GetHelpId( nItemId ) ); + + if ( aCommand.Len() || aHelpId.getLength() ) + { + // Wenn eine Hilfe existiert, dann ausloesen + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if ( aCommand.Len() ) + pHelp->Start( aCommand, this ); + else if ( aHelpId.getLength() ) + pHelp->Start( rtl::OStringToOUString( aHelpId, RTL_TEXTENCODING_UTF8 ), this ); + } + return; + } + } + } + else if ( maNextToolRect.IsInside( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ) ) + { + if ( rHEvt.GetMode() & (HELPMODE_BALLOON | HELPMODE_QUICK) ) + { + // Rechteck ermitteln + Rectangle aTempRect = maNextToolRect; + Point aPt = OutputToScreenPixel( aTempRect.TopLeft() ); + aTempRect.Left() = aPt.X(); + aTempRect.Top() = aPt.Y(); + aPt = OutputToScreenPixel( aTempRect.BottomRight() ); + aTempRect.Right() = aPt.X(); + aTempRect.Bottom() = aPt.Y(); + + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + Help::ShowBalloon( this, aTempRect.Center(), aTempRect, maNextToolBoxStr ); + else + Help::ShowQuickHelp( this, aTempRect, maNextToolBoxStr ); + return; + } + } + + DockingWindow::RequestHelp( rHEvt ); +} + +// ----------------------------------------------------------------------- + +long ToolBox::Notify( NotifyEvent& rNEvt ) +{ + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + KeyEvent aKEvt = *rNEvt.GetKeyEvent(); + KeyCode aKeyCode = aKEvt.GetKeyCode(); + USHORT nKeyCode = aKeyCode.GetCode(); + switch( nKeyCode ) + { + case KEY_TAB: + { + // internal TAB cycling only if parent is not a dialog or if we are the ony child + // otherwise the dialog control will take over + BOOL bNoTabCycling = ( ( ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL && + ImplGetParent()->GetChildCount() != 1 ); + + if( bNoTabCycling && ! (GetStyle() & WB_FORCETABCYCLE) ) + return DockingWindow::Notify( rNEvt ); + else if( ImplChangeHighlightUpDn( aKeyCode.IsShift() ? TRUE : FALSE , bNoTabCycling ) ) + return FALSE; + else + return DockingWindow::Notify( rNEvt ); + } + default: + break; + }; + } + else if( rNEvt.GetType() == EVENT_GETFOCUS ) + { + if( rNEvt.GetWindow() == this ) + { + // the toolbar itself got the focus + if( mnLastFocusItemId != 0 ) + { + // restore last item + ImplChangeHighlight( ImplGetItem( mnLastFocusItemId ) ); + mnLastFocusItemId = 0; + } + else if( (GetGetFocusFlags() & (GETFOCUS_BACKWARD|GETFOCUS_TAB) ) == (GETFOCUS_BACKWARD|GETFOCUS_TAB)) + // Shift-TAB was pressed in the parent + ImplChangeHighlightUpDn( FALSE ); + else + ImplChangeHighlightUpDn( TRUE ); + + mnLastFocusItemId = 0; + + return true; + } + else + { + // a child window got the focus so update current item to + // allow for proper lose focus handling in keyboard navigation + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + if ( it->mbVisible ) + { + if ( it->mpWindow && it->mpWindow->ImplIsWindowOrChild( rNEvt.GetWindow() ) ) + { + mnHighItemId = it->mnId; + break; + } + } + + ++it; + } + return DockingWindow::Notify( rNEvt ); + } + } + else if( rNEvt.GetType() == EVENT_LOSEFOCUS ) + { + // deselect + ImplHideFocus(); + mnHighItemId = 0; + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + } + + return DockingWindow::Notify( rNEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Command( const CommandEvent& rCEvt ) +{ + // StartDrag auf MouseButton/Left/Alt abbilden + if ( (rCEvt.GetCommand() == COMMAND_STARTDRAG) && rCEvt.IsMouseEvent() && + mbCustomize && !mbDragging && !mbDrag && !mbSelection && + (mnCurPos == TOOLBOX_ITEM_NOTFOUND) ) + { + // Wir erlauben nur das Draggen von Items. Deshalb muessen wir + // testen, ob auch ein Item angeklickt wurde, ansonsten wuerden + // wir evt. das Fenster verschieben, was nicht gewollt waere. + // Wir machen dieses jedoch nur im Customize-Mode, da ansonsten + // Items zuhaeufig ausversehen verschoben werden. + if ( mbCustomizeMode ) + { + Point aMousePos = rCEvt.GetMousePosPixel(); + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + // Ist es dieses Item + if ( it->maRect.IsInside( aMousePos ) ) + { + // Ist es ein Separator oder ist das Item disabled, + // dann mache nichts + if ( (it->meType == TOOLBOXITEM_BUTTON) && + !it->mbShowWindow ) + mbCommandDrag = TRUE; + break; + } + + ++it; + } + + if ( mbCommandDrag ) + { + MouseEvent aMEvt( aMousePos, 1, MOUSE_SIMPLECLICK, + MOUSE_LEFT, KEY_MOD2 ); + ToolBox::MouseButtonDown( aMEvt ); + return; + } + } + } + else if ( rCEvt.GetCommand() == COMMAND_WHEEL ) + { + if ( (mnCurLine > 1) || (mnCurLine+mnVisLines-1 < mnCurLines) ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + if ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) + { + if ( (mnCurLine > 1) && (pData->GetDelta() > 0) ) + ShowLine( FALSE ); + else if ( (mnCurLine+mnVisLines-1 < mnCurLines) && (pData->GetDelta() < 0) ) + ShowLine( TRUE ); + ImplDrawSpin( FALSE, FALSE ); + return; + } + } + } + + DockingWindow::Command( rCEvt ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::StateChanged( StateChangedType nType ) +{ + DockingWindow::StateChanged( nType ); + + if ( nType == STATE_CHANGE_INITSHOW ) + ImplFormat(); + else if ( nType == STATE_CHANGE_ENABLE ) + ImplUpdateItem(); + else if ( nType == STATE_CHANGE_UPDATEMODE ) + { + if ( IsUpdateMode() ) + Invalidate(); + } + else if ( (nType == STATE_CHANGE_ZOOM) || + (nType == STATE_CHANGE_CONTROLFONT) ) + { + mbCalc = TRUE; + mbFormat = TRUE; + ImplInitSettings( TRUE, FALSE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) + { + ImplInitSettings( FALSE, TRUE, FALSE ); + Invalidate(); + } + else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) + { + ImplInitSettings( FALSE, FALSE, TRUE ); // font, foreground, background + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + DockingWindow::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DATACHANGED_DISPLAY) || + (rDCEvt.GetType() == DATACHANGED_FONTS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DATACHANGED_SETTINGS) && + (rDCEvt.GetFlags() & SETTINGS_STYLE)) ) + { + mbCalc = TRUE; + mbFormat = TRUE; + ImplInitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::PrepareToggleFloatingMode() +{ + return DockingWindow::PrepareToggleFloatingMode(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ToggleFloatingMode() +{ + DockingWindow::ToggleFloatingMode(); + + BOOL mbOldHorz = mbHorz; + + if ( ImplIsFloatingMode() ) + { + mbHorz = TRUE; + meAlign = WINDOWALIGN_TOP; + mbScroll = TRUE; + + if( mbOldHorz != mbHorz ) + mbCalc = TRUE; // orientation was changed ! + + ImplSetMinMaxFloatSize( this ); + SetOutputSizePixel( ImplCalcFloatSize( this, mnFloatLines ) ); + } + else + { + mbScroll = (mnWinStyle & WB_SCROLL) ? TRUE : FALSE; + if ( (meAlign == WINDOWALIGN_TOP) || (meAlign == WINDOWALIGN_BOTTOM) ) + mbHorz = TRUE; + else + mbHorz = FALSE; + + // set focus back to document + ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus(); + } + + if( mbOldHorz != mbHorz ) + { + // if orientation changes, the toolbox has to be initialized again + // to update the direction of the gradient + mbCalc = TRUE; + ImplInitSettings( TRUE, TRUE, TRUE ); + } + + mbFormat = TRUE; + ImplFormat(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::StartDocking() +{ + meDockAlign = meAlign; + mnDockLines = mnLines; + mbLastFloatMode = ImplIsFloatingMode(); + DockingWindow::StartDocking(); +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::Docking( const Point& rPos, Rectangle& rRect ) +{ + // Wenn Dragging, dann nicht machen, da vorher schon berechnet + if ( mbDragging ) + return FALSE; + + BOOL bFloatMode = FALSE; + + DockingWindow::Docking( rPos, rRect ); + + // Befindet sich die Maus ausserhalb des Bereichs befindet, kann es nur ein + // FloatWindow werden + Rectangle aDockingRect( rRect ); + if ( !ImplIsFloatingMode() ) + { + // don't use tracking rectangle for alignment check, because it will be too large + // to get a floating mode as result - switch to floating size + // so the calculation only depends on the position of the rectangle, not the current + // docking state of the window + USHORT nTemp = 0; + aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) ); + + // in this mode docking is never done by keyboard, so it's OK to use the mouse position + aDockingRect.SetPos( ImplGetFrameWindow()->GetPointerPosPixel() ); + } + + Rectangle aIntersection = maOutDockRect.GetIntersection( aDockingRect ); + if ( !aIntersection.IsEmpty() && !IsDockingPrevented() ) + { + Rectangle aInRect = maInDockRect; + Size aDockSize; + aDockSize.Width() = ImplCalcSize( this, mnLines, TB_CALCMODE_VERT ).Width(); + aDockSize.Height() = ImplCalcSize( this, mnLines, TB_CALCMODE_HORZ ).Height(); + aInRect.Left() += aDockSize.Width()/2; + aInRect.Top() += aDockSize.Height()/2; + aInRect.Right() -= aDockSize.Width()/2; + aInRect.Bottom() -= aDockSize.Height()/2; + + // Wenn Fenster zu klein, wird das gesammte InDock-Rect genommen + if ( aInRect.Left() >= aInRect.Right() ) + { + aInRect.Left() = maInDockRect.Left(); + aInRect.Right() = maInDockRect.Right(); + } + if ( aInRect.Top() >= aInRect.Bottom() ) + { + aInRect.Top() = maInDockRect.Top(); + aInRect.Bottom() = maInDockRect.Bottom(); + } + + // Wenn Maus nicht im Dock-Bereich, dann kann es nur zum + // FloatWindow werden + Rectangle aIntersect = aInRect.GetIntersection( aDockingRect ); + if ( aIntersect == aDockingRect ) + bFloatMode = TRUE; + else + { + // docking rectangle is in the "sensible area" + Point aPos = aDockingRect.TopLeft(); + Point aInPosTL( aPos.X()-aInRect.Left(), aPos.Y()-aInRect.Top() ); + Point aInPosBR( aPos.X()-aInRect.Left() + aDockingRect.GetWidth(), aPos.Y()-aInRect.Top() + aDockingRect.GetHeight() ); + Size aInSize = aInRect.GetSize(); + + if ( aInPosTL.X() <= 0 ) + meDockAlign = WINDOWALIGN_LEFT; + else if ( aInPosTL.Y() <= 0) + meDockAlign = WINDOWALIGN_TOP; + else if ( aInPosBR.X() >= aInSize.Width() ) + meDockAlign = WINDOWALIGN_RIGHT; + else if ( aInPosBR.Y() >= aInSize.Height() ) + meDockAlign = WINDOWALIGN_BOTTOM; + + // Wenn sich Dock-Align geaendert hat, muessen wir die + // neue Dock-Groesse setzen + if ( (meDockAlign == WINDOWALIGN_TOP) || (meDockAlign == WINDOWALIGN_BOTTOM) ) + aDockSize.Width() = maInDockRect.GetWidth(); + else + aDockSize.Height() = maInDockRect.GetHeight(); + + aDockingRect.SetSize( aDockSize ); + + Point aPosTL( maInDockRect.TopLeft() ); + switch ( meDockAlign ) + { + case WINDOWALIGN_TOP : + aDockingRect.SetPos( aPosTL ); + break; + case WINDOWALIGN_LEFT : + aDockingRect.SetPos( aPosTL ); + break; + case WINDOWALIGN_BOTTOM : + { + Point aPosBL( maInDockRect.BottomLeft() ); + aPosBL.Y() -= aDockingRect.GetHeight(); + aDockingRect.SetPos( aPosBL ); + break; + } + case WINDOWALIGN_RIGHT : + { + Point aPosTR( maInDockRect.TopRight() ); + aPosTR.X() -= aDockingRect.GetWidth(); + aDockingRect.SetPos( aPosTR ); + break; + } + } + } + } + else + bFloatMode = TRUE; + + if ( bFloatMode ) + { + meDockAlign = meAlign; + if ( !mbLastFloatMode ) + { + USHORT nTemp = 0; + aDockingRect.SetSize( ImplCalcFloatSize( this, nTemp ) ); + } + } + + rRect = aDockingRect; + mbLastFloatMode = bFloatMode; + + return bFloatMode; +} + +// ----------------------------------------------------------------------- + +void ToolBox::EndDocking( const Rectangle& rRect, BOOL bFloatMode ) +{ + if ( !IsDockingCanceled() ) + { + if ( mnLines != mnDockLines ) + SetLineCount( mnDockLines ); + if ( meAlign != meDockAlign ) + SetAlign( meDockAlign ); + } + if ( bFloatMode || (bFloatMode != ImplIsFloatingMode()) ) + DockingWindow::EndDocking( rRect, bFloatMode ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Resizing( Size& rSize ) +{ + USHORT nCalcLines; + USHORT nTemp; + + // Alle Floatinggroessen berechnen + ImplCalcFloatSizes( this ); + + if ( !mnLastResizeDY ) + mnLastResizeDY = mnDY; + + // Ist vertikales Resizing angesagt + if ( (mnLastResizeDY != rSize.Height()) && (mnDY != rSize.Height()) ) + { + nCalcLines = ImplCalcLines( this, rSize.Height() ); + if ( nCalcLines < 1 ) + nCalcLines = 1; + rSize = ImplCalcFloatSize( this, nCalcLines ); + } + else + { + nCalcLines = 1; + nTemp = nCalcLines; + Size aTempSize = ImplCalcFloatSize( this, nTemp ); + while ( (aTempSize.Width() > rSize.Width()) && + (nCalcLines <= mpFloatSizeAry->mpSize[0].mnLines) ) + { + nCalcLines++; + nTemp = nCalcLines; + aTempSize = ImplCalcFloatSize( this, nTemp ); + } + rSize = aTempSize; + } + + mnLastResizeDY = rSize.Height(); +} + +// ----------------------------------------------------------------------- + +Size ToolBox::CalcWindowSizePixel( USHORT nCalcLines ) const +{ + return ImplCalcSize( this, nCalcLines ); +} + +Size ToolBox::CalcWindowSizePixel( USHORT nCalcLines, WindowAlign eAlign ) const +{ + return ImplCalcSize( this, nCalcLines, + (eAlign == WINDOWALIGN_TOP || eAlign == WINDOWALIGN_BOTTOM) ? TB_CALCMODE_HORZ : TB_CALCMODE_VERT ); +} + +USHORT ToolBox::ImplCountLineBreaks( const ToolBox *pThis ) +{ + USHORT nLines = 0; + + std::vector< ImplToolItem >::const_iterator it = ((ToolBox*)pThis)->mpData->m_aItems.begin(); + while ( it != ((ToolBox*)pThis)->mpData->m_aItems.end() ) + { + if( it->meType == TOOLBOXITEM_BREAK ) + nLines++; + it++; + } + return nLines; +} + +Size ToolBox::CalcPopupWindowSizePixel() const +{ + // count number of breaks and calc corresponding floating window size + USHORT nLines = ImplCountLineBreaks( this ); + + if( nLines ) + nLines++; // add the first line + else + { + // no breaks found: use quadratic layout + nLines = (USHORT) ceil( sqrt( (double) GetItemCount() ) ); + } + + BOOL bPopup = mpData->mbAssumePopupMode; + ToolBox *pThis = (ToolBox*) this; + pThis->mpData->mbAssumePopupMode = TRUE; + + Size aSize = CalcFloatingWindowSizePixel( nLines ); + + pThis->mpData->mbAssumePopupMode = bPopup; + return aSize; +} + +Size ToolBox::CalcFloatingWindowSizePixel() const +{ + USHORT nLines = ImplCountLineBreaks( this ); + nLines++; // add the first line + return CalcFloatingWindowSizePixel( nLines ); +} + +Size ToolBox::CalcFloatingWindowSizePixel( USHORT nCalcLines ) const +{ + BOOL bFloat = mpData->mbAssumeFloating; + BOOL bDocking = mpData->mbAssumeDocked; + + // simulate floating mode and force reformat before calculating + ToolBox *pThis = (ToolBox*) this; + pThis->mpData->mbAssumeFloating = TRUE; + pThis->mpData->mbAssumeDocked = FALSE; + + Size aSize = ImplCalcFloatSize( (ToolBox*) this, nCalcLines ); + + pThis->mbFormat = TRUE; + pThis->mpData->mbAssumeFloating = bFloat; + pThis->mpData->mbAssumeDocked = bDocking; + + return aSize; +} + +// ----------------------------------------------------------------------- + +Size ToolBox::CalcMinimumWindowSizePixel() const +{ + if( ImplIsFloatingMode() ) + return ImplCalcSize( this, mnFloatLines ); + else + { + // create dummy toolbox for measurements + ToolBox *pToolBox = new ToolBox( GetParent(), GetStyle() ); + + // copy until first useful item + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + pToolBox->CopyItem( *this, it->mnId ); + if( (it->meType != TOOLBOXITEM_BUTTON) || + !it->mbVisible || ImplIsFixedControl( &(*it) ) ) + it++; + else + break; + } + + // add to docking manager if required to obtain a drag area + // (which is accounted for in calcwindowsizepixel) + if( ImplGetDockingManager()->GetDockingWindowWrapper( this ) ) + ImplGetDockingManager()->AddWindow( pToolBox ); + + // account for menu + if( IsMenuEnabled() ) + pToolBox->SetMenuType( GetMenuType() ); + + pToolBox->SetAlign( GetAlign() ); + Size aSize = pToolBox->CalcWindowSizePixel( 1 ); + + ImplGetDockingManager()->RemoveWindow( pToolBox ); + pToolBox->Clear(); + delete pToolBox; + + return aSize; + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::EnableCustomize( BOOL bEnable ) +{ + if ( bEnable != mbCustomize ) + { + mbCustomize = bEnable; + + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + if ( bEnable ) + pMgr->Insert( this ); + else + pMgr->Remove( this ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::StartCustomize( const Rectangle& rRect, void* pData ) +{ + DBG_ASSERT( mbCustomize, + "ToolBox::StartCustomize(): ToolBox must be customized" ); + + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + Point aMousePos = GetPointerPosPixel(); + Point aPos = ScreenToOutputPixel( rRect.TopLeft() ); + Rectangle aRect( aPos.X(), aPos.Y(), + aPos.X()+rRect.GetWidth()+SMALLBUTTON_HSIZE, + aPos.Y()+rRect.GetHeight()+SMALLBUTTON_VSIZE ); + aMousePos = ScreenToOutputPixel( aPos ); + Pointer aPtr; + SetPointer( aPtr ); + pMgr->StartDragging( this, aMousePos, aRect, 0, FALSE, pData ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::StartCustomizeMode() +{ + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + pMgr->StartCustomizeMode(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::EndCustomizeMode() +{ + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + pMgr->EndCustomizeMode(); +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::IsCustomizeMode() +{ + ImplTBDragMgr* pMgr = ImplGetTBDragMgr(); + return pMgr->IsCustomizeMode(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::GetFocus() +{ + DockingWindow::GetFocus(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::LoseFocus() +{ + ImplChangeHighlight( NULL, TRUE ); + + DockingWindow::LoseFocus(); +} + +// ----------------------------------------------------------------------- + +// performs the action associated with an item, ie simulates clicking the item +void ToolBox::TriggerItem( USHORT nItemId, BOOL bShift, BOOL bCtrl ) +{ + mnHighItemId = nItemId; + USHORT nModifier = 0; + if( bShift ) + nModifier |= KEY_SHIFT; + if( bCtrl ) + nModifier |= KEY_MOD1; + KeyCode aKeyCode( 0, nModifier ); + ImplActivateItem( aKeyCode ); +} + +// ----------------------------------------------------------------------- + +// calls the button's action handler +// returns TRUE if action was called +BOOL ToolBox::ImplActivateItem( KeyCode aKeyCode ) +{ + BOOL bRet = TRUE; + if( mnHighItemId ) + { + ImplToolItem *pToolItem = ImplGetItem( mnHighItemId ); + + // #107712#, activate can also be called for disabled entries + if( pToolItem && !pToolItem->mbEnabled ) + return TRUE; + + if( pToolItem && pToolItem->mpWindow && HasFocus() ) + { + ImplHideFocus(); + mbChangingHighlight = TRUE; // avoid focus change due to loose focus + pToolItem->mpWindow->ImplControlFocus( GETFOCUS_TAB ); + mbChangingHighlight = FALSE; + } + else + { + mnDownItemId = mnCurItemId = mnHighItemId; + ImplToolItem* pItem = ImplGetItem( mnHighItemId ); + if ( pItem->mnBits & TIB_AUTOCHECK ) + { + if ( pItem->mnBits & TIB_RADIOCHECK ) + { + if ( pItem->meState != STATE_CHECK ) + SetItemState( pItem->mnId, STATE_CHECK ); + } + else + { + if ( pItem->meState != STATE_CHECK ) + pItem->meState = STATE_CHECK; + else + pItem->meState = STATE_NOCHECK; + } + } + mnMouseModifier = aKeyCode.GetModifier(); + mbIsKeyEvent = TRUE; + Activate(); + Click(); + + // #107776# we might be destroyed in the selecthandler + ImplDelData aDelData; + ImplAddDel( &aDelData ); + Select(); + if ( aDelData.IsDelete() ) + return bRet; + ImplRemoveDel( &aDelData ); + + Deactivate(); + mbIsKeyEvent = FALSE; + mnMouseModifier = 0; + } + } + else + bRet = FALSE; + return bRet; +} + +// ----------------------------------------------------------------------- + +BOOL ImplCloseLastPopup( Window *pParent ) +{ + // close last popup toolbox (see also: + // ImplHandleMouseFloatMode(...) in winproc.cxx ) + + if( ImplGetSVData()->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat = ImplGetSVData()->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + // only close the floater if it is not our direct parent, which would kill ourself + if( pLastLevelFloat && pLastLevelFloat != pParent ) + { + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + return TRUE; + } + } + return FALSE; +} + +// opens a drop down toolbox item +// returns TRUE if item was opened +BOOL ToolBox::ImplOpenItem( KeyCode aKeyCode ) +{ + USHORT nCode = aKeyCode.GetCode(); + BOOL bRet = TRUE; + + // arrow keys should work only in the opposite direction of alignment (to not break cursor travelling) + if ( ((nCode == KEY_LEFT || nCode == KEY_RIGHT) && IsHorizontal()) + || ((nCode == KEY_UP || nCode == KEY_DOWN) && !IsHorizontal()) ) + return FALSE; + + if( IsMenuEnabled() && mpData->mbMenubuttonSelected ) + { + if( ImplCloseLastPopup( GetParent() ) ) + return bRet; + + ImplUpdateCustomMenu(); + Application::PostUserEvent( mpData->mnEventId, LINK( this, ToolBox, ImplCallExecuteCustomMenu ) ); + } + else if( mnHighItemId && ImplGetItem( mnHighItemId ) && + (ImplGetItem( mnHighItemId )->mnBits & TIB_DROPDOWN) ) + { + if( ImplCloseLastPopup( GetParent() ) ) + return bRet; + + mnDownItemId = mnCurItemId = mnHighItemId; + mnCurPos = GetItemPos( mnCurItemId ); + mnLastFocusItemId = mnCurItemId; // save item id for possible later focus restore + mnMouseModifier = aKeyCode.GetModifier(); + mbIsShift = TRUE; + mbIsKeyEvent = TRUE; + Activate(); + + mpData->mbDropDownByKeyboard = TRUE; + GetDropdownClickHdl().Call( this ); + + mbIsKeyEvent = FALSE; + mbIsShift = FALSE; + mnMouseModifier = 0; + } + else + bRet = FALSE; + + return bRet; +} + +// ----------------------------------------------------------------------- + +void ToolBox::KeyInput( const KeyEvent& rKEvt ) +{ + KeyCode aKeyCode = rKEvt.GetKeyCode(); + mnKeyModifier = aKeyCode.GetModifier(); + USHORT nCode = aKeyCode.GetCode(); + BOOL bParentIsDialog = ( ( ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL ); + BOOL bForwardKey = FALSE; + BOOL bGrabFocusToDocument = FALSE; + + // #107776# we might be destroyed in the keyhandler + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + switch ( nCode ) + { + case KEY_UP: + { + // Ctrl-Cursor activates next toolbox, indicated by a blue arrow pointing to the left/up + if( aKeyCode.GetModifier() ) // allow only pure cursor keys + break; + if( !IsHorizontal() ) + ImplChangeHighlightUpDn( TRUE ); + else + ImplOpenItem( aKeyCode ); + } + break; + case KEY_LEFT: + { + if( aKeyCode.GetModifier() ) // allow only pure cursor keys + break; + if( IsHorizontal() ) + ImplChangeHighlightUpDn( TRUE ); + else + ImplOpenItem( aKeyCode ); + } + break; + case KEY_DOWN: + { + if( aKeyCode.GetModifier() ) // allow only pure cursor keys + break; + if( !IsHorizontal() ) + ImplChangeHighlightUpDn( FALSE ); + else + ImplOpenItem( aKeyCode ); + } + break; + case KEY_RIGHT: + { + if( aKeyCode.GetModifier() ) // allow only pure cursor keys + break; + if( IsHorizontal() ) + ImplChangeHighlightUpDn( FALSE ); + else + ImplOpenItem( aKeyCode ); + } + break; + case KEY_PAGEUP: + if ( mnCurLine > 1 ) + { + if( mnCurLine > mnVisLines ) + mnCurLine = mnCurLine - mnVisLines; + else + mnCurLine = 1; + mbFormat = TRUE; + ImplFormat(); + ImplDrawSpin( FALSE, FALSE ); + ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) ); + } + break; + case KEY_PAGEDOWN: + if ( mnCurLine+mnVisLines-1 < mnCurLines ) + { + if( mnCurLine + 2*mnVisLines-1 < mnCurLines ) + mnCurLine = mnCurLine + mnVisLines; + else + mnCurLine = mnCurLines; + mbFormat = TRUE; + ImplFormat(); + ImplDrawSpin( FALSE, FALSE ); + ImplChangeHighlight( ImplGetFirstValidItem( mnCurLine ) ); + } + break; + case KEY_END: + { + ImplChangeHighlight( NULL ); + ImplChangeHighlightUpDn( FALSE ); + } + break; + case KEY_HOME: + { + ImplChangeHighlight( NULL ); + ImplChangeHighlightUpDn( TRUE ); + } + break; + case KEY_ESCAPE: + { + if( !ImplIsFloatingMode() && bParentIsDialog ) + DockingWindow::KeyInput( rKEvt ); + else + { + // send focus to document pane + Window *pWin = this; + while( pWin ) + { + if( !pWin->GetParent() ) + { + pWin->ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus(); + break; + } + pWin = pWin->GetParent(); + } + } + } + break; + case KEY_RETURN: + { + // #107712#, disabled entries are selectable now + // leave toolbox and move focus to document + if( mnHighItemId ) + { + ImplToolItem *pItem = ImplGetItem( mnHighItemId ); + if( !pItem->mbEnabled ) + { + Sound::Beep( SOUND_DISABLE, this ); + bGrabFocusToDocument = TRUE; + } + } + if( !bGrabFocusToDocument ) + bForwardKey = !ImplActivateItem( aKeyCode ); + } + break; + default: + { + USHORT aKeyGroup = aKeyCode.GetGroup(); + ImplToolItem *pItem = NULL; + if( mnHighItemId ) + pItem = ImplGetItem( mnHighItemId ); + // #i13931# forward alphanum keyinput into embedded control + if( (aKeyGroup == KEYGROUP_NUM || aKeyGroup == KEYGROUP_ALPHA ) && pItem && pItem->mpWindow && pItem->mbEnabled ) + { + Window *pFocusWindow = Application::GetFocusWindow(); + ImplHideFocus(); + mbChangingHighlight = TRUE; // avoid focus change due to loose focus + pItem->mpWindow->ImplControlFocus( GETFOCUS_TAB ); + mbChangingHighlight = FALSE; + if( pFocusWindow != Application::GetFocusWindow() ) + Application::GetFocusWindow()->KeyInput( rKEvt ); + } + else + { + // do nothing to avoid key presses going into the document + // while the toolbox has the focus + // just forward function and special keys and combinations with Alt-key + if( aKeyGroup == KEYGROUP_FKEYS || aKeyGroup == KEYGROUP_MISC || aKeyCode.IsMod2() ) + bForwardKey = TRUE; + } + } + } + + if ( aDelData.IsDelete() ) + return; + ImplRemoveDel( &aDelData ); + + // #107251# move focus away if this toolbox was disabled during keyinput + if( HasFocus() && mpData->mbKeyInputDisabled && (ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL) ) == WB_DIALOGCONTROL) + { + USHORT n = 0; + Window *pFocusControl = ImplGetParent()->ImplGetDlgWindow( n, DLGWINDOW_FIRST ); + if ( pFocusControl && pFocusControl != this ) + pFocusControl->ImplControlFocus( GETFOCUS_INIT ); + } + + mnKeyModifier = 0; + + // #107712#, leave toolbox + if( bGrabFocusToDocument ) + { + GrabFocusToDocument(); + return; + } + + if( bForwardKey ) + DockingWindow::KeyInput( rKEvt ); +} + +// ----------------------------------------------------------------------- + +// returns the current toolbox line of the item +USHORT ToolBox::ImplGetItemLine( ImplToolItem* pCurrentItem ) +{ + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + USHORT nLine = 1; + while( it != mpData->m_aItems.end() ) + { + if ( it->mbBreak ) + nLine++; + if( &(*it) == pCurrentItem) + break; + ++it; + } + return nLine; +} + +// returns the first displayable item in the given line +ImplToolItem* ToolBox::ImplGetFirstValidItem( USHORT nLine ) +{ + if( !nLine || nLine > mnCurLines ) + return NULL; + + nLine--; + + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + // find correct line + if ( it->mbBreak ) + nLine--; + if( !nLine ) + { + // find first useful item + while( it != mpData->m_aItems.end() && ((it->meType != TOOLBOXITEM_BUTTON) || + /*!it->mbEnabled ||*/ !it->mbVisible || ImplIsFixedControl( &(*it) )) ) + { + ++it; + if( it == mpData->m_aItems.end() || it->mbBreak ) + return NULL; // no valid items in this line + } + return &(*it); + } + ++it; + } + + return (it == mpData->m_aItems.end()) ? NULL : &(*it); +} + +// returns the last displayable item in the given line +ImplToolItem* ToolBox::ImplGetLastValidItem( USHORT nLine ) +{ + if( !nLine || nLine > mnCurLines ) + return NULL; + + nLine--; + ImplToolItem *pFound = NULL; + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + // find correct line + if ( it->mbBreak ) + nLine--; + if( !nLine ) + { + // find last useful item + while( it != mpData->m_aItems.end() && ((it->meType == TOOLBOXITEM_BUTTON) && + /*it->mbEnabled &&*/ it->mbVisible && !ImplIsFixedControl( &(*it) )) ) + { + pFound = &(*it); + ++it; + if( it == mpData->m_aItems.end() || it->mbBreak ) + return pFound; // end of line: return last useful item + } + return pFound; + } + ++it; + } + + return pFound; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::ImplFindItemPos( const ImplToolItem* pItem, const std::vector< ImplToolItem >& rList ) +{ + if( pItem ) + { + USHORT nPos; + for( nPos = 0; nPos < rList.size(); nPos++ ) + if( &rList[ nPos ] == pItem ) + return nPos; + } + return TOOLBOX_ITEM_NOTFOUND; +} + +void ToolBox::ChangeHighlight( USHORT nPos ) +{ + if ( nPos < GetItemCount() ) { + ImplGrabFocus( 0 ); + ImplChangeHighlight ( ImplGetItem ( GetItemId ( (USHORT) nPos ) ), FALSE ); + } +} + +void ToolBox::ImplChangeHighlight( ImplToolItem* pItem, BOOL bNoGrabFocus ) +{ + // avoid recursion due to focus change + if( mbChangingHighlight ) + return; + + mbChangingHighlight = TRUE; + + ImplToolItem* pOldItem = NULL; + + if ( mnHighItemId ) + { + ImplHideFocus(); + USHORT nPos = GetItemPos( mnHighItemId ); + pOldItem = ImplGetItem( mnHighItemId ); + // #i89962# ImplDrawItem can cause Invalidate/Update + // which will in turn ImplShowFocus again + // set mnHighItemId to 0 already to prevent this hen/egg problem + mnHighItemId = 0; + ImplDrawItem( nPos, FALSE ); + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHTOFF, reinterpret_cast< void* >( nPos ) ); + } + + if( !bNoGrabFocus && pItem != pOldItem && pOldItem && pOldItem->mpWindow ) + { + // move focus into toolbox + GrabFocus(); + } + + if( pItem ) + { + USHORT aPos = ToolBox::ImplFindItemPos( pItem, mpData->m_aItems ); + if( aPos != TOOLBOX_ITEM_NOTFOUND) + { + // check for line breaks + USHORT nLine = ImplGetItemLine( pItem ); + + if( nLine >= mnCurLine + mnVisLines ) + { + mnCurLine = nLine - mnVisLines + 1; + mbFormat = TRUE; + } + else if ( nLine < mnCurLine ) + { + mnCurLine = nLine; + mbFormat = TRUE; + } + + if( mbFormat ) + { + ImplFormat(); + } + + mnHighItemId = pItem->mnId; + ImplDrawItem( aPos, 2 ); // always use shadow effect (2) + + if( mbSelection ) + mnCurPos = aPos; + ImplShowFocus(); + + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT ); + } + } + else + { + ImplHideFocus(); + mnHighItemId = 0; + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + } + + mbChangingHighlight = FALSE; +} + +// ----------------------------------------------------------------------- + +// check for keyboard accessible items +static BOOL ImplIsValidItem( const ImplToolItem* pItem, BOOL bNotClipped ) +{ + BOOL bValid = (pItem && pItem->meType == TOOLBOXITEM_BUTTON && pItem->mbVisible && !ImplIsFixedControl( pItem )); + if( bValid && bNotClipped && pItem->IsClipped() ) + bValid = FALSE; + return bValid; +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::ImplChangeHighlightUpDn( BOOL bUp, BOOL bNoCycle ) +{ + ImplToolItem* pToolItem = ImplGetItem( mnHighItemId ); + + if( !pToolItem || !mnHighItemId ) + { + // menubutton highlighted ? + if( mpData->mbMenubuttonSelected ) + { + if( bUp ) + { + // select last valid non-clipped item + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end(); + ImplToolItem* pItem = NULL; + while( it != mpData->m_aItems.begin() ) + { + --it; + if ( ImplIsValidItem( &(*it), TRUE ) ) + { + pItem = &(*it); + break; + } + } + ImplDrawMenubutton( this, FALSE ); + ImplChangeHighlight( pItem ); + } + else + { + // select first valid non-clipped item + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + if ( ImplIsValidItem( &(*it), TRUE ) ) + break; + ++it; + } + if( it != mpData->m_aItems.end() ) + { + ImplDrawMenubutton( this, FALSE ); + ImplChangeHighlight( &(*it) ); + } + } + return TRUE; + } + + if( bUp ) + { + // Select first valid item + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + if ( ImplIsValidItem( &(*it), FALSE ) ) + break; + ++it; + } + + // select the menu button if a clipped item would be selected + if( (it != mpData->m_aItems.end() && &(*it) == ImplGetFirstClippedItem( this )) && IsMenuEnabled() ) + { + ImplChangeHighlight( NULL ); + ImplDrawMenubutton( this, TRUE ); + } + else + ImplChangeHighlight( (it != mpData->m_aItems.end()) ? &(*it) : NULL ); + return TRUE; + } + else + { + // Select last valid item + + // docked toolbars have the menubutton as last item - if this button is enabled + if( IsMenuEnabled() && !ImplIsFloatingMode() ) + { + ImplChangeHighlight( NULL ); + ImplDrawMenubutton( this, TRUE ); + } + else + { + std::vector< ImplToolItem >::iterator it = mpData->m_aItems.end(); + ImplToolItem* pItem = NULL; + while( it != mpData->m_aItems.begin() ) + { + --it; + if ( ImplIsValidItem( &(*it), FALSE ) ) + { + pItem = &(*it); + break; + } + } + ImplChangeHighlight( pItem ); + } + return TRUE; + } + } + + if( pToolItem ) + { + ULONG pos = ToolBox::ImplFindItemPos( pToolItem, mpData->m_aItems ); + ULONG nCount = mpData->m_aItems.size(); + + ULONG i=0; + do + { + if( bUp ) + { + if( !pos-- ) + { + if( bNoCycle ) + return FALSE; + + // highlight the menu button if it is the last item + if( IsMenuEnabled() && !ImplIsFloatingMode() ) + { + ImplChangeHighlight( NULL ); + ImplDrawMenubutton( this, TRUE ); + return TRUE; + } + else + pos = nCount-1; + } + } + else + { + if( ++pos >= nCount ) + { + if( bNoCycle ) + return FALSE; + + // highlight the menu button if it is the last item + if( IsMenuEnabled() && !ImplIsFloatingMode() ) + { + ImplChangeHighlight( NULL ); + ImplDrawMenubutton( this, TRUE ); + return TRUE; + } + else + pos = 0; + } + } + + pToolItem = &mpData->m_aItems[pos]; + + if ( ImplIsValidItem( pToolItem, FALSE ) ) + break; + + } while( ++i < nCount); + + if( pToolItem->IsClipped() && IsMenuEnabled() ) + { + // select the menu button if a clipped item would be selected + ImplChangeHighlight( NULL ); + ImplDrawMenubutton( this, TRUE ); + } + else if( i != nCount ) + ImplChangeHighlight( pToolItem ); + else + return FALSE; + } + return TRUE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplShowFocus() +{ + if( mnHighItemId && HasFocus() ) + { + ImplToolItem* pItem = ImplGetItem( mnHighItemId ); + if( pItem->mpWindow ) + { + Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow : pItem->mpWindow; + pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = TRUE; + pWin->Invalidate( 0 ); + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplHideFocus() +{ + if( mnHighItemId ) + { + ImplToolItem* pItem = ImplGetItem( mnHighItemId ); + if( pItem->mpWindow ) + { + Window *pWin = pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow ? pItem->mpWindow->ImplGetWindowImpl()->mpBorderWindow : pItem->mpWindow; + pWin->ImplGetWindowImpl()->mbDrawSelectionBackground = FALSE; + pWin->Invalidate( 0 ); + } + } + + if ( mpData->mbMenubuttonSelected ) + { + // remove highlight from menubutton + ImplDrawMenubutton( this, FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplDisableFlatButtons() +{ +#ifdef WNT // Check in the Windows registry if an AT tool wants no flat toolboxes + static bool bInit = false, bValue = false; + if( ! bInit ) + { + bInit = true; + HKEY hkey; + + if( ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, + "Software\\OpenOffice.org\\Accessibility\\AtToolSupport", + &hkey) ) + { + DWORD dwType = 0; + WIN_BYTE Data[6]; // possible values: "true", "false", "1", "0", DWORD + DWORD cbData = sizeof(Data); + + if( ERROR_SUCCESS == RegQueryValueEx(hkey, "DisableFlatToolboxButtons", + NULL, &dwType, Data, &cbData) ) + { + switch (dwType) + { + case REG_SZ: + bValue = ((0 == stricmp((const char *) Data, "1")) || (0 == stricmp((const char *) Data, "true"))); + break; + case REG_DWORD: + bValue = (bool)(((DWORD *) Data)[0]); + break; + } + } + RegCloseKey(hkey); + } + } + if( bValue ) + mnOutStyle &= ~TOOLBOX_STYLE_FLAT; +#endif +} diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx new file mode 100644 index 000000000000..35a39676353a --- /dev/null +++ b/vcl/source/window/toolbox2.cxx @@ -0,0 +1,2440 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#include <tools/list.hxx> +#include <tools/debug.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/toolbox.h> +#include <vcl/mnemonic.hxx> +#include <vcl/menu.hxx> +#include <vcl/brdwin.hxx> + +#include <vcl/unohelp.hxx> +#include <unotools/confignode.hxx> + +#include <vcl/ImageListProvider.hxx> +#include <com/sun/star/lang/IllegalArgumentException.hpp> + +using namespace vcl; +using namespace rtl; + +// ======================================================================= + +#define TB_SEP_SIZE 8 + +// ----------------------------------------------------------------------- + +ImplToolBoxPrivateData::ImplToolBoxPrivateData() : + m_pLayoutData( NULL ), + mpImageListProvider( NULL ), + meImageListType( vcl::IMAGELISTTYPE_UNKNOWN ) +{ + meButtonSize = TOOLBOX_BUTTONSIZE_DONTCARE; + mpMenu = new PopupMenu(); + mnEventId = 0; + + maMenuType = TOOLBOX_MENUTYPE_NONE; + maMenubuttonItem.maItemSize = Size( TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET, TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET ); + maMenubuttonItem.meState = STATE_NOCHECK; + mnMenuButtonWidth = TB_MENUBUTTON_SIZE; + + + mbIsLocked = FALSE; + mbNativeButtons = FALSE; + mbIsPaintLocked = FALSE; + mbAssumeDocked = FALSE; + mbAssumePopupMode = FALSE; + mbAssumeFloating = FALSE; + mbKeyInputDisabled = FALSE; + mbMenubuttonSelected = FALSE; + mbPageScroll = FALSE; + mbWillUsePopupMode = FALSE; + mbDropDownByKeyboard = FALSE; +} + +ImplToolBoxPrivateData::~ImplToolBoxPrivateData() +{ + if( m_pLayoutData ) + delete m_pLayoutData; + delete mpMenu; +} + +// ----------------------------------------------------------------------- +ImplToolItem::ImplToolItem() +{ + mnId = 0; + mpWindow = NULL; + mpUserData = NULL; + meType = TOOLBOXITEM_BUTTON; + mnBits = 0; + meState = STATE_NOCHECK; + mbEnabled = TRUE; + mbVisible = TRUE; + mbEmptyBtn = TRUE; + mbShowWindow = FALSE; + mbBreak = FALSE; + mnSepSize = TB_SEP_SIZE; + mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH; + mnImageAngle = 0; + mbMirrorMode = FALSE; + mbVisibleText = FALSE; +} + +// ----------------------------------------------------------------------- + +ImplToolItem::ImplToolItem( USHORT nItemId, const Image& rImage, + ToolBoxItemBits nItemBits ) : + maImage( rImage ) +{ + mnId = nItemId; + mpWindow = NULL; + mpUserData = NULL; + meType = TOOLBOXITEM_BUTTON; + mnBits = nItemBits; + meState = STATE_NOCHECK; + mbEnabled = TRUE; + mbVisible = TRUE; + mbEmptyBtn = FALSE; + mbShowWindow = FALSE; + mbBreak = FALSE; + mnSepSize = TB_SEP_SIZE; + mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH; + mnImageAngle = 0; + mbMirrorMode = false; + mbVisibleText = false; +} + +// ----------------------------------------------------------------------- + +ImplToolItem::ImplToolItem( USHORT nItemId, const XubString& rText, + ToolBoxItemBits nItemBits ) : + maText( rText ) +{ + mnId = nItemId; + mpWindow = NULL; + mpUserData = NULL; + meType = TOOLBOXITEM_BUTTON; + mnBits = nItemBits; + meState = STATE_NOCHECK; + mbEnabled = TRUE; + mbVisible = TRUE; + mbEmptyBtn = FALSE; + mbShowWindow = FALSE; + mbBreak = FALSE; + mnSepSize = TB_SEP_SIZE; + mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH; + mnImageAngle = 0; + mbMirrorMode = false; + mbVisibleText = false; +} + +// ----------------------------------------------------------------------- + +ImplToolItem::ImplToolItem( USHORT nItemId, const Image& rImage, + const XubString& rText, ToolBoxItemBits nItemBits ) : + maImage( rImage ), + maText( rText ) +{ + mnId = nItemId; + mpWindow = NULL; + mpUserData = NULL; + meType = TOOLBOXITEM_BUTTON; + mnBits = nItemBits; + meState = STATE_NOCHECK; + mbEnabled = TRUE; + mbVisible = TRUE; + mbEmptyBtn = FALSE; + mbShowWindow = FALSE; + mbBreak = FALSE; + mnSepSize = TB_SEP_SIZE; + mnDropDownArrowWidth = TB_DROPDOWNARROWWIDTH; + mnImageAngle = 0; + mbMirrorMode = false; + mbVisibleText = false; +} + +// ----------------------------------------------------------------------- + +ImplToolItem::ImplToolItem( const ImplToolItem& rItem ) : + mpWindow ( rItem.mpWindow ), + mpUserData ( rItem.mpUserData ), + maImage ( rItem.maImage ), + maHighImage ( rItem.maHighImage ), + mnImageAngle ( rItem.mnImageAngle ), + mbMirrorMode ( rItem.mbMirrorMode ), + maText ( rItem.maText ), + maQuickHelpText ( rItem.maQuickHelpText ), + maHelpText ( rItem.maHelpText ), + maCommandStr ( rItem.maCommandStr ), + maHelpId ( rItem.maHelpId ), + maRect ( rItem.maRect ), + maCalcRect ( rItem.maCalcRect ), + maItemSize ( rItem.maItemSize ), + mnSepSize ( rItem.mnSepSize ), + mnDropDownArrowWidth ( rItem.mnDropDownArrowWidth ), + meType ( rItem.meType ), + mnBits ( rItem.mnBits ), + meState ( rItem.meState ), + mnId ( rItem.mnId ), + mbEnabled ( rItem.mbEnabled ), + mbVisible ( rItem.mbVisible ), + mbEmptyBtn ( rItem.mbEmptyBtn ), + mbShowWindow ( rItem.mbShowWindow ), + mbBreak ( rItem.mbBreak ), + mbVisibleText ( rItem.mbVisibleText ) +{ +} + +// ----------------------------------------------------------------------- + +ImplToolItem::~ImplToolItem() +{ +} + +// ----------------------------------------------------------------------- + +ImplToolItem& ImplToolItem::operator=( const ImplToolItem& rItem ) +{ + mpWindow = rItem.mpWindow; + mpUserData = rItem.mpUserData; + maImage = rItem.maImage; + maHighImage = rItem.maHighImage; + mnImageAngle = rItem.mnImageAngle; + mbMirrorMode = rItem.mbMirrorMode; + maText = rItem.maText; + maQuickHelpText = rItem.maQuickHelpText; + maHelpText = rItem.maHelpText; + maCommandStr = rItem.maCommandStr; + maHelpId = rItem.maHelpId; + maRect = rItem.maRect; + maCalcRect = rItem.maCalcRect; + mnSepSize = rItem.mnSepSize; + mnDropDownArrowWidth = rItem.mnDropDownArrowWidth; + maItemSize = rItem.maItemSize; + mbVisibleText = rItem.mbVisibleText; + meType = rItem.meType; + mnBits = rItem.mnBits; + meState = rItem.meState; + mnId = rItem.mnId; + mbEnabled = rItem.mbEnabled; + mbVisible = rItem.mbVisible; + mbEmptyBtn = rItem.mbEmptyBtn; + mbShowWindow = rItem.mbShowWindow; + mbBreak = rItem.mbBreak; + return *this; +} + +// ----------------------------------------------------------------------- + +Size ImplToolItem::GetSize( BOOL bHorz, BOOL bCheckMaxWidth, long maxWidth, const Size& rDefaultSize ) +{ + Size aSize( rDefaultSize ); // the size of 'standard' toolbox items + // non-standard items are eg windows or buttons with text + + if ( (meType == TOOLBOXITEM_BUTTON) || (meType == TOOLBOXITEM_SPACE) ) + { + aSize = maItemSize; + + if ( mpWindow && bHorz ) + { + // get size of item window and check if it fits + // no windows in vertical toolbars (the default is mbShowWindow=FALSE) + Size aWinSize = mpWindow->GetSizePixel(); + if ( !bCheckMaxWidth || (aWinSize.Width() <= maxWidth) ) + { + aSize.Width() = aWinSize.Width(); + aSize.Height() = aWinSize.Height(); + mbShowWindow = TRUE; + } + else + { + if ( mbEmptyBtn ) + { + aSize.Width() = 0; + aSize.Height() = 0; + } + } + } + } + else if ( meType == TOOLBOXITEM_SEPARATOR ) + { + if ( bHorz ) + { + aSize.Width() = mnSepSize; + aSize.Height() = rDefaultSize.Height(); + } + else + { + aSize.Width() = rDefaultSize.Width(); + aSize.Height() = mnSepSize; + } + } + else if ( meType == TOOLBOXITEM_BREAK ) + { + aSize.Width() = 0; + aSize.Height() = 0; + } + + return aSize; +} + +// ----------------------------------------------------------------------- + +void ImplToolItem::DetermineButtonDrawStyle( ButtonType eButtonType, BOOL& rbImage, BOOL& rbText ) const +{ + if ( meType != TOOLBOXITEM_BUTTON ) + { + // no button -> draw nothing + rbImage = rbText = FALSE; + return; + } + + BOOL bHasImage; + BOOL bHasText; + + // check for image and/or text + if ( !(maImage) ) + bHasImage = FALSE; + else + bHasImage = TRUE; + if ( !maText.Len() ) + bHasText = FALSE; + else + bHasText = TRUE; + + // prefer images if symbolonly buttons are drawn + // prefer texts if textonly buttons are dreawn + + if ( eButtonType == BUTTON_SYMBOL ) // drawing icons only + { + if( bHasImage || !bHasText ) + { + rbImage = TRUE; + rbText = FALSE; + } + else + { + rbImage = FALSE; + rbText = TRUE; + } + } + else if ( eButtonType == BUTTON_TEXT ) // drawing text only + { + if( bHasText || !bHasImage ) + { + rbImage = FALSE; + rbText = TRUE; + } + else + { + rbImage = TRUE; + rbText = FALSE; + } + } + else // drawing icons and text both + { + rbImage = TRUE; + rbText = TRUE; + } +} + +// ----------------------------------------------------------------------- + +Rectangle ImplToolItem::GetDropDownRect( BOOL bHorz ) const +{ + Rectangle aRect; + if( (mnBits & TIB_DROPDOWN) && !maRect.IsEmpty() ) + { + aRect = maRect; + if( mbVisibleText && !bHorz ) + // item will be rotated -> place dropdown to the bottom + aRect.Top() = aRect.Bottom() - mnDropDownArrowWidth; + else + // place dropdown to the right + aRect.Left() = aRect.Right() - mnDropDownArrowWidth; + } + return aRect; +} + +// ----------------------------------------------------------------------- + +BOOL ImplToolItem::IsClipped() const +{ + return ( meType == TOOLBOXITEM_BUTTON && mbVisible && maRect.IsEmpty() ); +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- + +const XubString& ToolBox::ImplConvertMenuString( const XubString& rStr ) +{ + maCvtStr = rStr; + if ( mbMenuStrings ) + maCvtStr.EraseTrailingChars( '.' ); + maCvtStr = MnemonicGenerator::EraseAllMnemonicChars( maCvtStr ); + return maCvtStr; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplInvalidate( BOOL bNewCalc, BOOL bFullPaint ) +{ + ImplUpdateInputEnable(); + + if ( bNewCalc ) + mbCalc = TRUE; + + if ( bFullPaint ) + { + mbFormat = TRUE; + + // Muss ueberhaupt eine neue Ausgabe erfolgen + if ( IsReallyVisible() && IsUpdateMode() ) + { + Invalidate( Rectangle( mnLeftBorder, mnTopBorder, + mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) ); + maTimer.Stop(); + } + } + else + { + if ( !mbFormat ) + { + mbFormat = TRUE; + + // Muss ueberhaupt eine neue Ausgabe erfolgen + if ( IsReallyVisible() && IsUpdateMode() ) + maTimer.Start(); + } + } + + // request new layout by layoutmanager + ImplCallEventListeners( VCLEVENT_TOOLBOX_FORMATCHANGED ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplUpdateItem( USHORT nIndex ) +{ + // Muss ueberhaupt eine neue Ausgabe erfolgen + if ( IsReallyVisible() && IsUpdateMode() ) + { + if ( nIndex == 0xFFFF ) + { + // #i52217# no immediate draw as this might lead to paint problems + Invalidate( Rectangle( mnLeftBorder, mnTopBorder, + mnDX-mnRightBorder-1, mnDY-mnBottomBorder-1 ) ); + } + else + { + if ( !mbFormat ) + { + // #i52217# no immediate draw as this might lead to paint problems + Invalidate( mpData->m_aItems[nIndex].maRect ); + } + else + maPaintRect.Union( mpData->m_aItems[nIndex].maRect ); + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::Click() +{ + ImplCallEventListeners( VCLEVENT_TOOLBOX_CLICK ); + maClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::DoubleClick() +{ + ImplCallEventListeners( VCLEVENT_TOOLBOX_DOUBLECLICK ); + maDoubleClickHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Activate() +{ + mnActivateCount++; + ImplCallEventListeners( VCLEVENT_TOOLBOX_ACTIVATE ); + maActivateHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Deactivate() +{ + mnActivateCount--; + ImplCallEventListeners( VCLEVENT_TOOLBOX_DEACTIVATE ); + maDeactivateHdl.Call( this ); + + if ( mbHideStatusText ) + { + GetpApp()->HideHelpStatusText(); + mbHideStatusText = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::Highlight() +{ + ImplCallEventListeners( VCLEVENT_TOOLBOX_HIGHLIGHT ); + maHighlightHdl.Call( this ); + + XubString aStr = GetHelpText( mnCurItemId ); + if ( aStr.Len() || mbHideStatusText ) + { + GetpApp()->ShowHelpStatusText( aStr ); + mbHideStatusText = TRUE; + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::Select() +{ + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + ImplCallEventListeners( VCLEVENT_TOOLBOX_SELECT ); + maSelectHdl.Call( this ); + + if ( aDelData.IsDelete() ) + return; + ImplRemoveDel( &aDelData ); + + // TODO: GetFloatingWindow in DockingWindow is currently inline, change it to check dockingwrapper + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() ) + pWrapper->GetFloatingWindow()->EndPopupMode(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::NextToolBox() +{ + maNextToolBoxHdl.Call( this ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Customize( const ToolBoxCustomizeEvent& ) +{ +} + +// ----------------------------------------------------------------------- + +void ToolBox::UserDraw( const UserDrawEvent& ) +{ +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertItem( const ResId& rResId, USHORT nPos ) +{ + ULONG nObjMask; + BOOL bImage = FALSE; // Wurde Image gesetzt + + // Item anlegen + ImplToolItem aItem; + + GetRes( rResId.SetRT( RSC_TOOLBOXITEM ) ); + nObjMask = ReadLongRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_ID ) + aItem.mnId = sal::static_int_cast<USHORT>(ReadLongRes()); + else + aItem.mnId = 1; + + if ( nObjMask & RSC_TOOLBOXITEM_TYPE ) + aItem.meType = (ToolBoxItemType)ReadLongRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_STATUS ) + aItem.mnBits = (ToolBoxItemBits)ReadLongRes(); + + if( nObjMask & RSC_TOOLBOXITEM_HELPID ) + aItem.maHelpId = ReadByteStringRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_TEXT ) + { + aItem.maText = ReadStringRes(); + aItem.maText = ImplConvertMenuString( aItem.maText ); + } + if ( nObjMask & RSC_TOOLBOXITEM_HELPTEXT ) + aItem.maHelpText = ReadStringRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_BITMAP ) + { + Bitmap aBmp = Bitmap( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + aItem.maImage = Image( aBmp, IMAGE_STDBTN_COLOR ); + bImage = TRUE; + } + if ( nObjMask & RSC_TOOLBOXITEM_IMAGE ) + { + aItem.maImage = Image( ResId( (RSHEADER_TYPE*)GetClassRes(), *rResId.GetResMgr() ) ); + IncrementRes( GetObjSizeRes( (RSHEADER_TYPE*)GetClassRes() ) ); + bImage = TRUE; + } + if ( nObjMask & RSC_TOOLBOXITEM_DISABLE ) + aItem.mbEnabled = !(BOOL)ReadShortRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_STATE ) + aItem.meState = (TriState)ReadLongRes(); + + if ( nObjMask & RSC_TOOLBOXITEM_HIDE ) + aItem.mbVisible = !((BOOL)ReadShortRes()); + + if ( nObjMask & RSC_TOOLBOXITEM_COMMAND ) + aItem.maCommandStr = ReadStringRes(); + + // Wenn kein Image geladen wurde, versuchen wir das Image aus der + // Image-Liste zu holen + if ( !bImage && aItem.mnId ) + aItem.maImage = maImageList.GetImage( aItem.mnId ); + + // Wenn es sich um ein ButtonItem handelt, die ID ueberpruefen + BOOL bNewCalc; + if ( aItem.meType != TOOLBOXITEM_BUTTON ) + { + bNewCalc = FALSE; + aItem.mnId = 0; + } + else + { + bNewCalc = TRUE; + + DBG_ASSERT( aItem.mnId, "ToolBox::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( aItem.mnId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::InsertItem(): ItemId already exists" ); + } + + // Item anlegen und in die Liste einfuegen + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + // ToolBox neu brechnen und neu ausgeben + ImplInvalidate( bNewCalc ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertItem( USHORT nItemId, const Image& rImage, + ToolBoxItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, rImage, nBits ) ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( TRUE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >(nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertItem( USHORT nItemId, const Image& rImage, + const XubString& rText, + ToolBoxItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, rImage, ImplConvertMenuString( rText ), nBits ) ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( TRUE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertItem( USHORT nItemId, const XubString& rText, + ToolBoxItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ToolBox::InsertItem(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::InsertItem(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), ImplToolItem( nItemId, ImplConvertMenuString( rText ), nBits ) ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( TRUE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertWindow( USHORT nItemId, Window* pWindow, + ToolBoxItemBits nBits, USHORT nPos ) +{ + DBG_ASSERT( nItemId, "ToolBox::InsertWindow(): ItemId == 0" ); + DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::InsertWindow(): ItemId already exists" ); + + // Item anlegen und in die Liste einfuegen + ImplToolItem aItem; + aItem.mnId = nItemId; + aItem.meType = TOOLBOXITEM_BUTTON; + aItem.mnBits = nBits; + aItem.mpWindow = pWindow; + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + if ( pWindow ) + pWindow->Hide(); + + ImplInvalidate( TRUE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertSpace( USHORT nPos ) +{ + // Item anlegen und in die Liste einfuegen + ImplToolItem aItem; + aItem.meType = TOOLBOXITEM_SPACE; + aItem.mbEnabled = FALSE; + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( FALSE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertSeparator( USHORT nPos, USHORT nPixSize ) +{ + // Item anlegen und in die Liste einfuegen + ImplToolItem aItem; + aItem.meType = TOOLBOXITEM_SEPARATOR; + aItem.mbEnabled = FALSE; + if ( nPixSize ) + aItem.mnSepSize = nPixSize; + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( FALSE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::InsertBreak( USHORT nPos ) +{ + // Item anlegen und in die Liste einfuegen + ImplToolItem aItem; + aItem.meType = TOOLBOXITEM_BREAK; + aItem.mbEnabled = FALSE; + mpData->m_aItems.insert( (nPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + ImplInvalidate( FALSE ); + + // Notify + USHORT nNewPos = sal::static_int_cast<USHORT>(( nPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos ) ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::RemoveItem( USHORT nPos ) +{ + if( nPos < mpData->m_aItems.size() ) + { + BOOL bMustCalc; + if ( mpData->m_aItems[nPos].meType == TOOLBOXITEM_BUTTON ) + bMustCalc = TRUE; + else + bMustCalc = FALSE; + + if ( mpData->m_aItems[nPos].mpWindow ) + mpData->m_aItems[nPos].mpWindow->Hide(); + + // PaintRect um das removete Item erweitern + maPaintRect.Union( mpData->m_aItems[nPos].maRect ); + + // Absichern gegen das Loeschen im Select-Handler + if ( mpData->m_aItems[nPos].mnId == mnCurItemId ) + mnCurItemId = 0; + if ( mpData->m_aItems[nPos].mnId == mnHighItemId ) + mnHighItemId = 0; + + ImplInvalidate( bMustCalc ); + + mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos ); + mpData->ImplClearLayoutData(); + + // Notify + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMREMOVED, reinterpret_cast< void* >( nPos ) ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::MoveItem( USHORT nItemId, USHORT nNewPos ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos == nNewPos ) + return; + + if ( nPos < nNewPos ) + nNewPos--; + + // Existiert Item + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + // ToolBox-Item in der Liste verschieben + ImplToolItem aItem = mpData->m_aItems[nPos]; + mpData->m_aItems.erase( mpData->m_aItems.begin()+nPos ); + mpData->m_aItems.insert( (nNewPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nNewPos : mpData->m_aItems.end(), aItem ); + mpData->ImplClearLayoutData(); + + // ToolBox neu ausgeben + ImplInvalidate( FALSE ); + + // Notify + if( nPos < nNewPos ) // only send one event, all indices above this item are invalid anyway + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMREMOVED, reinterpret_cast< void* >( nPos ) ); + else + { + USHORT nNewPos2 = sal::static_int_cast<USHORT>(( nNewPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nNewPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos2 ) ); + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::CopyItem( const ToolBox& rToolBox, USHORT nItemId, + USHORT nNewPos ) +{ + DBG_ASSERT( GetItemPos( nItemId ) == TOOLBOX_ITEM_NOTFOUND, + "ToolBox::CopyItem(): ItemId already exists" ); + + USHORT nPos = rToolBox.GetItemPos( nItemId ); + + // Existiert Item + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + // ToolBox-Item in der Liste verschieben + ImplToolItem aNewItem = rToolBox.mpData->m_aItems[nPos]; + // Bestimme Daten zuruecksetzen + aNewItem.mpWindow = NULL; + aNewItem.mbShowWindow = FALSE; + + mpData->m_aItems.insert( (nNewPos < mpData->m_aItems.size()) ? mpData->m_aItems.begin()+nNewPos : mpData->m_aItems.end(), aNewItem ); + mpData->ImplClearLayoutData(); + // ToolBox neu ausgeben + ImplInvalidate( FALSE ); + + // Notify + USHORT nNewPos2 = sal::static_int_cast<USHORT>(( nNewPos == TOOLBOX_APPEND ) ? ( mpData->m_aItems.size() - 1 ) : nNewPos); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMADDED, reinterpret_cast< void* >( nNewPos2 ) ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::CopyItems( const ToolBox& rToolBox ) +{ + mpData->ImplClearLayoutData(); + mpData->m_aItems = rToolBox.mpData->m_aItems; + // Absichern gegen das Loeschen im Select-Handler + mnCurItemId = 0; + mnHighItemId = 0; + + for( std::vector< ImplToolItem >::iterator it = mpData->m_aItems.begin(); + it != mpData->m_aItems.end(); ++it ) + { + it->mpWindow = NULL; + it->mbShowWindow = FALSE; + } + + ImplInvalidate( TRUE, TRUE ); + + // Notify + ImplCallEventListeners( VCLEVENT_TOOLBOX_ALLITEMSCHANGED ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::Clear() +{ + mpData->m_aItems.clear(); + mpData->ImplClearLayoutData(); + + // Absichern gegen das Loeschen im Select-Handler + mnCurItemId = 0; + mnHighItemId = 0; + + ImplInvalidate( TRUE, TRUE ); + + // Notify + ImplCallEventListeners( VCLEVENT_TOOLBOX_ALLITEMSCHANGED ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetButtonType( ButtonType eNewType ) +{ + if ( meButtonType != eNewType ) + { + meButtonType = eNewType; + + // Hier besser alles neu ausgeben, da es ansonsten zu Problemen + // mit den per CopyBits kopierten Bereichen geben kann + ImplInvalidate( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetToolboxButtonSize( ToolBoxButtonSize eSize ) +{ + if( mpData->meButtonSize != eSize ) + { + mpData->meButtonSize = eSize; + mbCalc = TRUE; + mbFormat = TRUE; + } +} + +ToolBoxButtonSize ToolBox::GetToolboxButtonSize() const +{ + return mpData->meButtonSize; +} + +// ----------------------------------------------------------------------- + +const Size& ToolBox::GetDefaultImageSize() const +{ + static Size aSmallButtonSize( TB_SMALLIMAGESIZE, TB_SMALLIMAGESIZE ); + + static ULONG s_nSymbolsStyle = STYLE_SYMBOLS_DEFAULT; + static Size aLargeButtonSize( TB_LARGEIMAGESIZE, TB_LARGEIMAGESIZE ); + + ULONG nSymbolsStyle = Application::GetSettings().GetStyleSettings().GetCurrentSymbolsStyle(); + if ( s_nSymbolsStyle != nSymbolsStyle ) + { + s_nSymbolsStyle = nSymbolsStyle; + switch ( nSymbolsStyle ) + { + case STYLE_SYMBOLS_INDUSTRIAL: + aLargeButtonSize = Size( TB_LARGEIMAGESIZE_INDUSTRIAL, TB_LARGEIMAGESIZE_INDUSTRIAL ); + break; + case STYLE_SYMBOLS_CRYSTAL: + aLargeButtonSize = Size( TB_LARGEIMAGESIZE_CRYSTAL, TB_LARGEIMAGESIZE_CRYSTAL ); + break; + case STYLE_SYMBOLS_OXYGEN: + aLargeButtonSize = Size( TB_LARGEIMAGESIZE_OXYGEN, TB_LARGEIMAGESIZE_OXYGEN ); + break; + default: + aLargeButtonSize = Size( TB_LARGEIMAGESIZE, TB_LARGEIMAGESIZE ); + } + } + + return GetToolboxButtonSize() == TOOLBOX_BUTTONSIZE_LARGE ? aLargeButtonSize : aSmallButtonSize; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetAlign( WindowAlign eNewAlign ) +{ + if ( meAlign != eNewAlign ) + { + meAlign = eNewAlign; + + if ( !ImplIsFloatingMode() ) + { + // Setzen, ob Items horizontal oder vertikal angeordnet werden sollen + if ( (eNewAlign == WINDOWALIGN_LEFT) || (eNewAlign == WINDOWALIGN_RIGHT) ) + mbHorz = FALSE; + else + mbHorz = TRUE; + + // Hier alles neu ausgeben, da sich Border auch aendert + mbCalc = TRUE; + mbFormat = TRUE; + if ( IsReallyVisible() && IsUpdateMode() ) + Invalidate(); + } + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetLineCount( USHORT nNewLines ) +{ + if ( !nNewLines ) + nNewLines = 1; + + if ( mnLines != nNewLines ) + { + mnLines = nNewLines; + + // Hier besser alles neu ausgeben, da es ansonsten zu Problemen + // mit den per CopyBits kopierten Bereichen geben kann + ImplInvalidate( FALSE ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetPageScroll( BOOL b ) +{ + mpData->mbPageScroll = b; +} + +BOOL ToolBox::GetPageScroll() +{ + return mpData->mbPageScroll; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetNextToolBox( const XubString& rStr ) +{ + BOOL bCalcNew = (!maNextToolBoxStr.Len() != !rStr.Len()); + maNextToolBoxStr = rStr; + if ( bCalcNew ) + ImplInvalidate( TRUE, FALSE ); +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetItemCount() const +{ + return (USHORT)mpData->m_aItems.size(); +} + +// ----------------------------------------------------------------------- + +ToolBoxItemType ToolBox::GetItemType( USHORT nPos ) const +{ + return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].meType : TOOLBOXITEM_DONTKNOW; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetItemPos( USHORT nItemId ) const +{ + int nCount = mpData->m_aItems.size(); + for( int nPos = 0; nPos < nCount; nPos++ ) + if( mpData->m_aItems[nPos].mnId == nItemId ) + return (USHORT)nPos; + + return TOOLBOX_ITEM_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetItemPos( const Point& rPos ) const +{ + // search the item position on the given point + USHORT nRet = TOOLBOX_ITEM_NOTFOUND; + USHORT nPos = 0; + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + if ( it->maRect.IsInside( rPos ) ) + { + // item found -> save position and break + nRet = nPos; + break; + } + + ++it; + ++nPos; + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetItemId( USHORT nPos ) const +{ + return (nPos < mpData->m_aItems.size()) ? mpData->m_aItems[nPos].mnId : 0; +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetItemId( const Point& rPos ) const +{ + // Item suchen, das geklickt wurde + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while( it != mpData->m_aItems.end() ) + { + // Ist es dieses Item + if ( it->maRect.IsInside( rPos ) ) + { + if ( it->meType == TOOLBOXITEM_BUTTON ) + return it->mnId; + else + return 0; + } + + ++it; + } + + return 0; +} + +// ----------------------------------------------------------------------- + +Point ToolBox::ImplGetPopupPosition( const Rectangle& rRect, const Size& rSize ) const +{ + Point aPos; + if( !rRect.IsEmpty() ) + { + Rectangle aScreen = GetDesktopRectPixel(); + + // the popup should be positioned so that it will not cover + // the item rect and that it fits the desktop + // the preferred direction is always towards the center of + // the application window + + Point devPos; // the position in device coordinates for screen comparison + switch( meAlign ) + { + case WINDOWALIGN_TOP: + aPos = rRect.BottomLeft(); + aPos.Y()++; + devPos = OutputToAbsoluteScreenPixel( aPos ); + if( devPos.Y() + rSize.Height() >= aScreen.Bottom() ) + aPos.Y() = rRect.Top() - rSize.Height(); + break; + case WINDOWALIGN_BOTTOM: + aPos = rRect.TopLeft(); + aPos.Y()--; + devPos = OutputToAbsoluteScreenPixel( aPos ); + if( devPos.Y() - rSize.Height() > aScreen.Top() ) + aPos.Y() -= rSize.Height(); + else + aPos.Y() = rRect.Bottom(); + break; + case WINDOWALIGN_LEFT: + aPos = rRect.TopRight(); + aPos.X()++; + devPos = OutputToAbsoluteScreenPixel( aPos ); + if( devPos.X() + rSize.Width() >= aScreen.Right() ) + aPos.X() = rRect.Left() - rSize.Width(); + break; + case WINDOWALIGN_RIGHT: + aPos = rRect.TopLeft(); + aPos.X()--; + devPos = OutputToAbsoluteScreenPixel( aPos ); + if( devPos.X() - rSize.Width() > aScreen.Left() ) + aPos.X() -= rSize.Width(); + else + aPos.X() = rRect.Right(); + break; + default: + break; + }; + } + return aPos; +} + + +Point ToolBox::GetItemPopupPosition( USHORT nItemId, const Size& rSize ) const +{ + return ImplGetPopupPosition( GetItemRect( nItemId ), rSize ); +} + +// ----------------------------------------------------------------------- + +Rectangle ToolBox::GetItemRect( USHORT nItemId ) const +{ + if ( mbCalc || mbFormat ) + ((ToolBox*)this)->ImplFormat(); + + USHORT nPos = GetItemPos( nItemId ); + return GetItemPosRect( nPos ); +} + +// ----------------------------------------------------------------------- + +Rectangle ToolBox::GetItemPosRect( USHORT nPos ) const +{ + if ( mbCalc || mbFormat ) + ((ToolBox*)this)->ImplFormat(); + + if ( nPos < mpData->m_aItems.size() ) + return mpData->m_aItems[nPos].maRect; + else + return Rectangle(); +} + +// ----------------------------------------------------------------------- +Rectangle ToolBox::GetItemDropDownRect( USHORT nItemId ) const +{ + if ( mbCalc || mbFormat ) + ((ToolBox*)this)->ImplFormat(); + + USHORT nPos = GetItemPos( nItemId ); + return GetItemPosDropDownRect( nPos ); +} + +// ----------------------------------------------------------------------- + +Rectangle ToolBox::GetItemPosDropDownRect( USHORT nPos ) const +{ + if ( mbCalc || mbFormat ) + ((ToolBox*)this)->ImplFormat(); + + if ( nPos < mpData->m_aItems.size() ) + return mpData->m_aItems[nPos].GetDropDownRect( mbHorz ); + else + return Rectangle(); +} + +// ----------------------------------------------------------------------- + +Rectangle ToolBox::GetMenubuttonRect() const +{ + return mpData->maMenubuttonItem.maRect; +} + +BOOL ToolBox::ImplHasExternalMenubutton() +{ + // check if the borderwindow (i.e. the decoration) provides the menu button + BOOL bRet = FALSE; + if( ImplIsFloatingMode() ) + { + // custom menu is placed in the decoration + ImplBorderWindow *pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( WINDOW_BORDER ) ); + if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() ) + bRet = TRUE; + } + return bRet; +} +// ----------------------------------------------------------------------- + +void ToolBox::SetItemBits( USHORT nItemId, ToolBoxItemBits nBits ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos < mpData->m_aItems.size() ) + { + ToolBoxItemBits nOldBits = mpData->m_aItems[nPos].mnBits; + mpData->m_aItems[nPos].mnBits = nBits; + nBits &= TIB_LEFT | TIB_AUTOSIZE | TIB_DROPDOWN; + nOldBits &= TIB_LEFT | TIB_AUTOSIZE | TIB_DROPDOWN; + // trigger reformat when the item width has changed (dropdown arrow) + BOOL bFormat = (nBits & TIB_DROPDOWN) != (nOldBits & TIB_DROPDOWN); + if ( nBits != nOldBits ) + ImplInvalidate( TRUE, bFormat ); + } +} + +// ----------------------------------------------------------------------- + +ToolBoxItemBits ToolBox::GetItemBits( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mnBits; + else + return 0; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemData( USHORT nItemId, void* pNewData ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos < mpData->m_aItems.size() ) + { + mpData->m_aItems[nPos].mpUserData = pNewData; + ImplUpdateItem( nPos ); + } +} + +// ----------------------------------------------------------------------- + +void* ToolBox::GetItemData( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mpUserData; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemImage( USHORT nItemId, const Image& rImage ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + // Nur wenn alles berechnet ist, mehr Aufwand treiben + if ( !mbCalc ) + { + Size aOldSize = pItem->maImage.GetSizePixel(); + pItem->maImage = rImage; + if ( aOldSize != pItem->maImage.GetSizePixel() ) + ImplInvalidate( TRUE ); + else + ImplUpdateItem( nPos ); + } + else + pItem->maImage = rImage; + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetImageList( const ImageList& rImageList ) +{ + maImageList = rImageList; + + USHORT nCount = (USHORT)mpData->m_aItems.size(); + for( USHORT i = 0; i < nCount; i++ ) + { + Image aImage; + if ( mpData->m_aItems[i].mnId ) + aImage = maImageList.GetImage( mpData->m_aItems[i].mnId ); + if( !!aImage ) + SetItemImage( mpData->m_aItems[i].mnId, aImage ); + } +} + +// ----------------------------------------------------------------------- + +static Image ImplRotImage( const Image& rImage, long nAngle10 ) +{ + Image aRet; + BitmapEx aRotBitmapEx( rImage.GetBitmapEx() ); + + aRotBitmapEx.Rotate( nAngle10, Color( COL_WHITE ) ); + + return Image( aRotBitmapEx ); +} + +void ToolBox::SetItemImageAngle( USHORT nItemId, long nAngle10 ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + Size aOldSize = pItem->maImage.GetSizePixel(); + + long nDeltaAngle = (nAngle10 - pItem->mnImageAngle) % 3600; + while( nDeltaAngle < 0 ) + nDeltaAngle += 3600; + + pItem->mnImageAngle = nAngle10; + if( nDeltaAngle && !!pItem->maImage ) + { + pItem->maImage = ImplRotImage( pItem->maImage, nDeltaAngle ); + if( !!pItem->maHighImage ) + pItem->maHighImage = ImplRotImage( pItem->maHighImage, nDeltaAngle ); + } + + if ( !mbCalc ) + { + if ( aOldSize != pItem->maImage.GetSizePixel() ) + ImplInvalidate( TRUE ); + else + ImplUpdateItem( nPos ); + } + } +} + +// ----------------------------------------------------------------------- + +static Image ImplMirrorImage( const Image& rImage ) +{ + Image aRet; + BitmapEx aMirrBitmapEx( rImage.GetBitmapEx() ); + + aMirrBitmapEx.Mirror( BMP_MIRROR_HORZ ); + + return Image( aMirrBitmapEx ); +} + +void ToolBox::SetItemImageMirrorMode( USHORT nItemId, BOOL bMirror ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + + if( ( pItem->mbMirrorMode && ! bMirror ) || + ( ! pItem->mbMirrorMode && bMirror ) + ) + { + pItem->mbMirrorMode = bMirror ? true : false; + if( !!pItem->maImage ) + { + pItem->maImage = ImplMirrorImage( pItem->maImage ); + if( !!pItem->maHighImage ) + pItem->maHighImage = ImplMirrorImage( pItem->maHighImage ); + } + + if ( !mbCalc ) + ImplUpdateItem( nPos ); + } + } +} + +// ----------------------------------------------------------------------- + +Image ToolBox::GetItemImage( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->maImage; + else + return Image(); +} + +// ----------------------------------------------------------------------- + +long ToolBox::GetItemImageAngle( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mnImageAngle; + else + return 0; +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::GetItemImageMirrorMode( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mbMirrorMode; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemHighImage( USHORT nItemId, const Image& rImage ) +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + if ( pItem ) + { + DBG_ASSERT( (pItem->maImage.GetSizePixel() == rImage.GetSizePixel()) || + ((!rImage) == TRUE), "ToolBox::SetItemHighImage() - ImageSize != HighImageSize" ); + pItem->maHighImage = rImage; + } +} + +// ----------------------------------------------------------------------- + +Image ToolBox::GetItemHighImage( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->maHighImage; + else + return Image(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemText( USHORT nItemId, const XubString& rText ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + // Nur wenn alles berechnet ist, mehr Aufwand treiben + if ( !mbCalc && + ((meButtonType != BUTTON_SYMBOL) || !pItem->maImage) ) + { + long nOldWidth = GetCtrlTextWidth( pItem->maText ); + pItem->maText = ImplConvertMenuString( rText ); + mpData->ImplClearLayoutData(); + if ( nOldWidth != GetCtrlTextWidth( pItem->maText ) ) + ImplInvalidate( TRUE ); + else + ImplUpdateItem( nPos ); + } + else + pItem->maText = ImplConvertMenuString( rText ); + + // Notify button changed event to prepare accessibility bridge + ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) ); + + // Notify + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMTEXTCHANGED, reinterpret_cast< void* >( nPos ) ); + } +} + +// ----------------------------------------------------------------------- + +const XubString& ToolBox::GetItemText( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->maText; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemWindow( USHORT nItemId, Window* pNewWindow ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + pItem->mpWindow = pNewWindow; + if ( pNewWindow ) + pNewWindow->Hide(); + ImplInvalidate( TRUE ); + ImplCallEventListeners( VCLEVENT_TOOLBOX_ITEMWINDOWCHANGED, reinterpret_cast< void* >( nPos ) ); + } +} + +// ----------------------------------------------------------------------- + +Window* ToolBox::GetItemWindow( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mpWindow; + else + return NULL; +} + +// ----------------------------------------------------------------------- + +void ToolBox::StartSelection() +{ + if ( mbDrag ) + EndSelection(); + + if ( !mbSelection ) + { + mbSelection = TRUE; + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + Activate(); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::EndSelection() +{ + mbCommandDrag = FALSE; + + if ( mbDrag || mbSelection ) + { + // Daten zuruecksetzen + mbDrag = FALSE; + mbSelection = FALSE; + if ( mnCurPos != TOOLBOX_ITEM_NOTFOUND ) + ImplDrawItem( mnCurPos ); + EndTracking(); + ReleaseMouse(); + Deactivate(); + } + + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + mnCurItemId = 0; + mnDownItemId = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemDown( USHORT nItemId, BOOL bDown, BOOL bRelease ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + if ( bDown ) + { + if ( nPos != mnCurPos ) + { + mnCurPos = nPos; + ImplDrawItem( mnCurPos, TRUE ); + Flush(); + } + } + else + { + if ( nPos == mnCurPos ) + { + ImplDrawItem( mnCurPos, FALSE ); + Flush(); + mnCurPos = TOOLBOX_ITEM_NOTFOUND; + } + } + + if ( bRelease ) + { + if ( mbDrag || mbSelection ) + { + mbDrag = FALSE; + mbSelection = FALSE; + EndTracking(); + ReleaseMouse(); + Deactivate(); + } + + mnCurItemId = 0; + mnDownItemId = 0; + mnMouseClicks = 0; + mnMouseModifier = 0; + } + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::IsItemDown( USHORT nItemId ) const +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + return (nPos == mnCurPos); + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemState( USHORT nItemId, TriState eState ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + + // Hat sich der Status geaendert + if ( pItem->meState != eState ) + { + // Wenn RadioCheck, dann vorherigen unchecken + if ( (eState == STATE_CHECK) && (pItem->mnBits & TIB_AUTOCHECK) && + (pItem->mnBits & TIB_RADIOCHECK) ) + { + ImplToolItem* pGroupItem; + USHORT nGroupPos; + USHORT nItemCount = GetItemCount(); + + nGroupPos = nPos; + while ( nGroupPos ) + { + pGroupItem = &mpData->m_aItems[nGroupPos-1]; + if ( pGroupItem->mnBits & TIB_RADIOCHECK ) + { + if ( pGroupItem->meState != STATE_NOCHECK ) + SetItemState( pGroupItem->mnId, STATE_NOCHECK ); + } + else + break; + nGroupPos--; + } + + nGroupPos = nPos+1; + while ( nGroupPos < nItemCount ) + { + pGroupItem = &mpData->m_aItems[nGroupPos]; + if ( pGroupItem->mnBits & TIB_RADIOCHECK ) + { + if ( pGroupItem->meState != STATE_NOCHECK ) + SetItemState( pGroupItem->mnId, STATE_NOCHECK ); + } + else + break; + nGroupPos++; + } + } + + pItem->meState = eState; + ImplUpdateItem( nPos ); + + // Notify button changed event to prepare accessibility bridge + ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) ); + + // Notify + ImplCallEventListeners( VCLEVENT_TOOLBOX_CLICK, reinterpret_cast< void* >( nPos ) ); + } + } +} + +// ----------------------------------------------------------------------- + +TriState ToolBox::GetItemState( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->meState; + else + return STATE_NOCHECK; +} + +// ----------------------------------------------------------------------- + +void ToolBox::EnableItem( USHORT nItemId, BOOL bEnable ) +{ + USHORT nPos = GetItemPos( nItemId ); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + if ( bEnable ) + bEnable = TRUE; + if ( pItem->mbEnabled != bEnable ) + { + pItem->mbEnabled = bEnable; + + // Gegebenenfalls das Fenster mit updaten + if ( pItem->mpWindow ) + pItem->mpWindow->Enable( pItem->mbEnabled ); + + // Item updaten + ImplUpdateItem( nPos ); + + ImplUpdateInputEnable(); + + // Notify button changed event to prepare accessibility bridge + ImplCallEventListeners( VCLEVENT_TOOLBOX_BUTTONSTATECHANGED, reinterpret_cast< void* >( nPos ) ); + + ImplCallEventListeners( bEnable ? VCLEVENT_TOOLBOX_ITEMENABLED : VCLEVENT_TOOLBOX_ITEMDISABLED, reinterpret_cast< void* >( nPos ) ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::IsItemEnabled( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mbEnabled; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ShowItem( USHORT nItemId, BOOL bVisible ) +{ + USHORT nPos = GetItemPos( nItemId ); + mpData->ImplClearLayoutData(); + + if ( nPos != TOOLBOX_ITEM_NOTFOUND ) + { + ImplToolItem* pItem = &mpData->m_aItems[nPos]; + if ( pItem->mbVisible != bVisible ) + { + pItem->mbVisible = bVisible; + ImplInvalidate( FALSE ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::IsItemVisible( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->mbVisible; + else + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::IsItemReallyVisible( USHORT nItemId ) const +{ + // is the item on the visible area of the toolbox? + BOOL bRet = FALSE; + Rectangle aRect( mnLeftBorder, mnTopBorder, mnDX-mnRightBorder, mnDY-mnBottomBorder ); + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem && pItem->mbVisible && + !pItem->maRect.IsEmpty() && aRect.IsOver( pItem->maRect ) ) + { + bRet = TRUE; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetItemCommand( USHORT nItemId, const XubString& rCommand ) +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + pItem->maCommandStr = rCommand; +} + +// ----------------------------------------------------------------------- + +const XubString& ToolBox::GetItemCommand( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->maCommandStr; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetQuickHelpText( USHORT nItemId, const XubString& rText ) +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + pItem->maQuickHelpText = rText; +} + +// ----------------------------------------------------------------------- + +const XubString& ToolBox::GetQuickHelpText( USHORT nItemId ) const +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + return pItem->maQuickHelpText; + else + return ImplGetSVEmptyStr(); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetHelpText( USHORT nItemId, const XubString& rText ) +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + pItem->maHelpText = rText; +} + +// ----------------------------------------------------------------------- + +const XubString& ToolBox::GetHelpText( USHORT nItemId ) const +{ + return ImplGetHelpText( nItemId ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetHelpId( USHORT nItemId, const rtl::OString& rHelpId ) +{ + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + pItem->maHelpId = rHelpId; +} + +// ----------------------------------------------------------------------- + +rtl::OString ToolBox::GetHelpId( USHORT nItemId ) const +{ + rtl::OString aRet; + + ImplToolItem* pItem = ImplGetItem( nItemId ); + + if ( pItem ) + { + if ( pItem->maHelpId.getLength() ) + aRet = pItem->maHelpId; + else + aRet = ::rtl::OUStringToOString( pItem->maCommandStr, RTL_TEXTENCODING_UTF8 ); + } + + return aRet; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetBorder( long nX, long nY ) +{ + mnBorderX = nX; + mnBorderY = nY; + + ImplInvalidate( TRUE, TRUE ); +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetOutStyle( USHORT nNewStyle ) +{ + // always force flat looking toolbars since NWF + nNewStyle |= TOOLBOX_STYLE_FLAT; + + if ( mnOutStyle != nNewStyle ) + { + mnOutStyle = nNewStyle; + ImplDisableFlatButtons(); + + // Damit das ButtonDevice neu angelegt wird + if ( !(mnOutStyle & TOOLBOX_STYLE_FLAT) ) + { + mnMaxItemWidth = 1; + mnMaxItemHeight = 1; + } + + ImplInvalidate( TRUE, TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::RecalcItems() +{ + ImplInvalidate( TRUE ); +} + +// ----------------------------------------------------------------------- + +// disable key input if all items are disabled + +void ToolBox::ImplUpdateInputEnable() +{ + for( std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + it != mpData->m_aItems.end(); ++it ) + { + if( it->mbEnabled ) + { + // at least one useful entry + mpData->mbKeyInputDisabled = FALSE; + return; + } + } + mpData->mbKeyInputDisabled = TRUE; +} + +// ----------------------------------------------------------------------- + +void ToolBox::ImplFillLayoutData() const +{ + mpData->m_pLayoutData = new ToolBoxLayoutData(); + + USHORT nCount = (USHORT)mpData->m_aItems.size(); + for( USHORT i = 0; i < nCount; i++ ) + { + ImplToolItem* pItem = &mpData->m_aItems[i]; + + // Nur malen, wenn Rechteck im PaintRectangle liegt + if ( !pItem->maRect.IsEmpty() ) + const_cast<ToolBox*>(this)->ImplDrawItem( i, FALSE, FALSE, TRUE ); + } +} + +// ----------------------------------------------------------------------- + +String ToolBox::GetDisplayText() const +{ + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + return mpData->m_pLayoutData ? mpData->m_pLayoutData->m_aDisplayText : String(); +} + +// ----------------------------------------------------------------------- + +Rectangle ToolBox::GetCharacterBounds( USHORT nItemID, long nIndex ) const +{ + long nItemIndex = -1; + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + if( mpData->m_pLayoutData ) + { + for( ULONG i = 0; i < mpData->m_pLayoutData->m_aLineItemIds.size(); i++ ) + { + if( mpData->m_pLayoutData->m_aLineItemIds[i] == nItemID ) + { + nItemIndex = mpData->m_pLayoutData->m_aLineIndices[i]; + break; + } + } + } + return (mpData->m_pLayoutData && nItemIndex != -1) ? mpData->m_pLayoutData->GetCharacterBounds( nItemIndex+nIndex ) : Rectangle(); +} + +// ----------------------------------------------------------------------- + +long ToolBox::GetIndexForPoint( const Point& rPoint, USHORT& rItemID ) const +{ + long nIndex = -1; + rItemID = 0; + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + if( mpData->m_pLayoutData ) + { + nIndex = mpData->m_pLayoutData->GetIndexForPoint( rPoint ); + for( ULONG i = 0; i < mpData->m_pLayoutData->m_aLineIndices.size(); i++ ) + { + if( mpData->m_pLayoutData->m_aLineIndices[i] <= nIndex && + (i == mpData->m_pLayoutData->m_aLineIndices.size()-1 || mpData->m_pLayoutData->m_aLineIndices[i+1] > nIndex) ) + { + rItemID = mpData->m_pLayoutData->m_aLineItemIds[i]; + break; + } + } + } + return nIndex; +} + +// ----------------------------------------------------------------------- + +long ToolBox::GetTextCount() const +{ + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + return mpData->m_pLayoutData ? mpData->m_pLayoutData->GetLineCount() : 0; +} + +// ----------------------------------------------------------------------- + +Pair ToolBox::GetTextStartEnd( long nText ) const +{ + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + return mpData->m_pLayoutData ? mpData->m_pLayoutData->GetLineStartEnd( nText ) : Pair( -1, -1 ); +} + +// ----------------------------------------------------------------------- + +USHORT ToolBox::GetDisplayItemId( long nText ) const +{ + USHORT nItemId = 0; + if( ! mpData->m_pLayoutData ) + ImplFillLayoutData(); + if( mpData->m_pLayoutData && nText >= 0 && (ULONG)nText < mpData->m_pLayoutData->m_aLineItemIds.size() ) + nItemId = mpData->m_pLayoutData->m_aLineItemIds[nText]; + return nItemId; +} + + +// ----------------------------------------------------------------------- + +void ToolBox::SetDropdownClickHdl( const Link& rLink ) +{ + mpData->maDropdownClickHdl = rLink; +} + +const Link& ToolBox::GetDropdownClickHdl() const +{ + return mpData->maDropdownClickHdl; +} + +// ----------------------------------------------------------------------- + +void ToolBox::SetMenuType( USHORT aType ) +{ + if( aType != mpData->maMenuType ) + { + mpData->maMenuType = aType; + if( IsFloatingMode() ) + { + // the menu button may have to be moved into the decoration which changes the layout + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + pWrapper->ShowTitleButton( TITLE_BUTTON_MENU, ( aType & TOOLBOX_MENUTYPE_CUSTOMIZE) ? TRUE : FALSE ); + + mbFormat = TRUE; + ImplFormat(); + ImplSetMinMaxFloatSize( this ); + } + else + { + // trigger redraw of menu button + if( !mpData->maMenubuttonItem.maRect.IsEmpty() ) + Invalidate(mpData->maMenubuttonItem.maRect); + } + } +} + +USHORT ToolBox::GetMenuType() const +{ + return mpData->maMenuType; +} + +BOOL ToolBox::IsMenuEnabled() const +{ + return mpData->maMenuType != TOOLBOX_MENUTYPE_NONE; +} + +PopupMenu* ToolBox::GetMenu() const +{ + return mpData->mpMenu; +} + +void ToolBox::SetMenuButtonHdl( const Link& rLink ) +{ + mpData->maMenuButtonHdl = rLink; +} + +const Link& ToolBox::GetMenuButtonHdl() const +{ + return mpData->maMenuButtonHdl; +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::ImplHasClippedItems() +{ + // are any items currently clipped ? + ImplFormat(); + std::vector< ImplToolItem >::const_iterator it = mpData->m_aItems.begin(); + while ( it != mpData->m_aItems.end() ) + { + if( it->IsClipped() ) + return TRUE; + it++; + } + return FALSE; +} + +void ToolBox::ImplUpdateCustomMenu() +{ + // fill clipped items into menu + if( !IsMenuEnabled() ) + return; + + PopupMenu *pMenu = GetMenu(); + + USHORT i = 0; + // remove old entries + while( i < pMenu->GetItemCount() ) + { + if( pMenu->GetItemId( i ) >= TOOLBOX_MENUITEM_START ) + { + pMenu->RemoveItem( i ); + i = 0; + } + else + i++; + } + + // add menu items, starting from the end and inserting at pos 0 + if ( !mpData->m_aItems.empty() ) + { + for ( std::vector< ImplToolItem >::reverse_iterator it(mpData->m_aItems.rbegin()); + it != mpData->m_aItems.rend(); ++it) + { + if( it->IsClipped() ) + { + USHORT id = it->mnId + TOOLBOX_MENUITEM_START; + pMenu->InsertItem( id, it->maText, it->maImage, 0, 0 ); + pMenu->EnableItem( id, it->mbEnabled ); + pMenu->CheckItem( id, it->meState == STATE_CHECK ); + } + } + } +} + +IMPL_LINK( ToolBox, ImplCustomMenuListener, VclMenuEvent*, pEvent ) +{ + if( pEvent->GetMenu() == GetMenu() && pEvent->GetId() == VCLEVENT_MENU_SELECT ) + { + USHORT id = GetMenu()->GetItemId( pEvent->GetItemPos() ); + if( id >= TOOLBOX_MENUITEM_START ) + TriggerItem( id - TOOLBOX_MENUITEM_START, FALSE, FALSE ); + } + return 0; +} + +IMPL_LINK( ToolBox, ImplCallExecuteCustomMenu, void*, EMPTYARG ) +{ + mpData->mnEventId = 0; + ImplExecuteCustomMenu(); + return 0; +} + +void ToolBox::ImplExecuteCustomMenu() +{ + if( IsMenuEnabled() ) + { + if( GetMenuType() & TOOLBOX_MENUTYPE_CUSTOMIZE ) + // call button handler to allow for menu customization + mpData->maMenuButtonHdl.Call( this ); + + // register handler + GetMenu()->AddEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) ); + + // make sure all disabled entries will be shown + GetMenu()->SetMenuFlags( + GetMenu()->GetMenuFlags() | MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES ); + + // toolbox might be destroyed during execute + ImplDelData aDelData; + ImplAddDel( &aDelData ); + ImplDelData aBorderDel; + bool bBorderDel = false; + + Window *pWin = this; + Rectangle aMenuRect = mpData->maMenubuttonItem.maRect; + if( IsFloatingMode() ) + { + // custom menu is placed in the decoration + ImplBorderWindow *pBorderWin = dynamic_cast<ImplBorderWindow*>( GetWindow( WINDOW_BORDER ) ); + if( pBorderWin && !pBorderWin->GetMenuRect().IsEmpty() ) + { + pWin = pBorderWin; + aMenuRect = pBorderWin->GetMenuRect(); + pWin->ImplAddDel( &aBorderDel ); + bBorderDel = true; + } + } + + USHORT uId = GetMenu()->Execute( pWin, Rectangle( ImplGetPopupPosition( aMenuRect, Size() ), Size() ), + POPUPMENU_EXECUTE_DOWN | POPUPMENU_NOMOUSEUPCLOSE ); + + if ( aDelData.IsDelete() ) + return; + ImplRemoveDel( &aDelData ); + + if( GetMenu() ) + GetMenu()->RemoveEventListener( LINK( this, ToolBox, ImplCustomMenuListener ) ); + if( bBorderDel ) + { + if( aBorderDel.IsDelete() ) + return; + pWin->ImplRemoveDel( &aBorderDel ); + } + + pWin->Invalidate( aMenuRect ); + + if( uId ) + GrabFocusToDocument(); + } +} + +void ToolBox::ExecuteCustomMenu() +{ + if( IsMenuEnabled() ) + { + // handle custom menu asynchronously + // to avoid problems if the toolbox is closed during menu execute + ImplUpdateCustomMenu(); + Application::PostUserEvent( mpData->mnEventId, LINK( this, ToolBox, ImplCallExecuteCustomMenu ) ); + } +} + +// ----------------------------------------------------------------------- + +// checks override first, useful during calculation of sizes +BOOL ToolBox::ImplIsFloatingMode() const +{ + DBG_ASSERT( !(mpData->mbAssumeDocked && mpData->mbAssumeFloating), + "ToolBox::ImplIsFloatingMode(): cannot assume docked and floating" ); + + if( mpData->mbAssumeDocked ) + return FALSE; + else if( mpData->mbAssumeFloating ) + return TRUE; + else + return IsFloatingMode(); +} + +// checks override first, useful during calculation of sizes +BOOL ToolBox::ImplIsInPopupMode() const +{ + if( mpData->mbAssumePopupMode ) + return TRUE; + else + { + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + return ( pWrapper && pWrapper->GetFloatingWindow() && pWrapper->GetFloatingWindow()->IsInPopupMode() ); + } +} + +// ----------------------------------------------------------------------- + +void ToolBox::Lock( BOOL bLock ) +{ + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( !pWrapper ) + return; + if( mpData->mbIsLocked != bLock ) + { + mpData->mbIsLocked = bLock; + if( !ImplIsFloatingMode() ) + { + mbCalc = TRUE; + mbFormat = TRUE; + SetSizePixel( CalcWindowSizePixel(1) ); + Invalidate(); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL ToolBox::AlwaysLocked() +{ + // read config item to determine toolbox behaviour, used for subtoolbars + + static int nAlwaysLocked = -1; + + if( nAlwaysLocked == -1 ) + { + nAlwaysLocked = 0; // ask configuration only once + + utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory( + vcl::unohelper::GetMultiServiceFactory(), + OUString::createFromAscii( "/org.openoffice.Office.UI.GlobalSettings/Toolbars" ) ); // note: case sensisitive ! + if ( aNode.isValid() ) + { + // feature enabled ? + BOOL bStatesEnabled = BOOL(); + ::com::sun::star::uno::Any aValue = aNode.getNodeValue( OUString::createFromAscii( "StatesEnabled" ) ); + if( aValue >>= bStatesEnabled ) + { + if( bStatesEnabled == TRUE ) + { + // now read the locking state + utl::OConfigurationNode aNode2 = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory( + vcl::unohelper::GetMultiServiceFactory(), + OUString::createFromAscii( "/org.openoffice.Office.UI.GlobalSettings/Toolbars/States" ) ); // note: case sensisitive ! + + BOOL bLocked = BOOL(); + ::com::sun::star::uno::Any aValue2 = aNode2.getNodeValue( OUString::createFromAscii( "Locked" ) ); + if( aValue2 >>= bLocked ) + nAlwaysLocked = (bLocked == TRUE) ? 1 : 0; + } + } + } + } + + return nAlwaysLocked == 1 ? TRUE : FALSE; +} + +BOOL ToolBox::WillUsePopupMode() const +{ + return mpData->mbWillUsePopupMode; +} + +void ToolBox::WillUsePopupMode( BOOL b ) +{ + mpData->mbWillUsePopupMode = b; +} + +void ToolBox::ImplUpdateImageList() +{ + if (mpData->mpImageListProvider != NULL) + { + BOOL bHC = GetSettings().GetStyleSettings().GetHighContrastMode(); + try + { + ImageListType eType = bHC ? vcl::HIGHCONTRAST_YES : vcl::HIGHCONTRAST_NO; + + if (eType != mpData->meImageListType) + { + vcl::IImageListProvider* pImageListProvider = mpData->mpImageListProvider; + SetImageList( pImageListProvider->getImageList(eType) ); + mpData->meImageListType = eType; + } + } + catch (com::sun::star::lang::IllegalArgumentException &) {} + } +} + +void ToolBox::SetImageListProvider(vcl::IImageListProvider* _pProvider) +{ + mpData->mpImageListProvider = _pProvider; + ImplUpdateImageList(); +} +// ----------------------------------------------------------------------- diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx new file mode 100644 index 000000000000..0762a07476e2 --- /dev/null +++ b/vcl/source/window/window.cxx @@ -0,0 +1,9978 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" +#ifndef _SV_SVSYS_HXX +#include "svsys.h" +#endif +#include "vcl/salframe.hxx" +#include "vcl/salobj.hxx" +#include "vcl/salinst.hxx" +#include "vcl/salgtype.hxx" +#include "vcl/salgdi.hxx" + +#include "vcl/unohelp.hxx" +#include "tools/time.hxx" +#include "tools/debug.hxx" +#ifndef _SV_RC_H +#include "tools/rc.h" +#endif +#include "vcl/svdata.hxx" +#include "vcl/dbggui.hxx" +#include "vcl/outfont.hxx" +#include "vcl/outdev.h" +#include "vcl/region.h" +#include "vcl/event.hxx" +#include "vcl/help.hxx" +#include "vcl/cursor.hxx" +#include "vcl/svapp.hxx" +#include "vcl/window.h" +#include "vcl/window.hxx" +#include "vcl/syswin.hxx" +#include "vcl/syschild.hxx" +#include "vcl/brdwin.hxx" +#include "vcl/helpwin.hxx" +#include "vcl/dockwin.hxx" +#include "vcl/menu.hxx" +#include "vcl/wrkwin.hxx" +#include "vcl/wall.hxx" +#include "vcl/gradient.hxx" +#include "vcl/toolbox.h" +#include "unotools/fontcfg.hxx" +#include "vcl/sysdata.hxx" +#include "vcl/sallayout.hxx" +#include "vcl/salctype.hxx" +#include "vcl/button.hxx" // Button::GetStandardText +#include "vcl/taskpanelist.hxx" +#include "com/sun/star/awt/XWindowPeer.hpp" +#include "com/sun/star/rendering/XCanvas.hpp" +#include "com/sun/star/rendering/XSpriteCanvas.hpp" +#include "com/sun/star/awt/XWindow.hpp" +#include "comphelper/processfactory.hxx" +#include "com/sun/star/datatransfer/dnd/XDragSource.hpp" +#include "com/sun/star/datatransfer/dnd/XDropTarget.hpp" +#include "com/sun/star/datatransfer/clipboard/XClipboard.hpp" +#include "com/sun/star/awt/XTopWindow.hpp" +#include "com/sun/star/awt/XDisplayConnection.hpp" +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/lang/XComponent.hpp" +#include "com/sun/star/lang/XServiceName.hpp" +#include "com/sun/star/accessibility/XAccessible.hpp" +#include "com/sun/star/accessibility/AccessibleRole.hpp" + +#include "vcl/dialog.hxx" +#include "vcl/unowrap.hxx" +#include "vcl/dndlcon.hxx" +#include "vcl/dndevdis.hxx" +#include "unotools/confignode.hxx" +#include "vcl/gdimtf.hxx" + +#include "vcl/pdfextoutdevdata.hxx" +#include "vcl/lazydelete.hxx" + +#include <set> +#include <typeinfo> + +using namespace rtl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::datatransfer::dnd; +using namespace ::com::sun::star; +using namespace com::sun; + +using ::com::sun::star::awt::XTopWindow; + +// ======================================================================= + +DBG_NAME( Window ) + +// ======================================================================= + +#define IMPL_PAINT_PAINT ((USHORT)0x0001) +#define IMPL_PAINT_PAINTALL ((USHORT)0x0002) +#define IMPL_PAINT_PAINTALLCHILDS ((USHORT)0x0004) +#define IMPL_PAINT_PAINTCHILDS ((USHORT)0x0008) +#define IMPL_PAINT_ERASE ((USHORT)0x0010) +#define IMPL_PAINT_CHECKRTL ((USHORT)0x0020) + +// ----------------------------------------------------------------------- + +typedef Window* PWINDOW; + +// ----------------------------------------------------------------------- + +struct ImplCalcToTopData +{ + ImplCalcToTopData* mpNext; + Window* mpWindow; + Region* mpInvalidateRegion; +}; + +struct ImplAccessibleInfos +{ + USHORT nAccessibleRole; + String* pAccessibleName; + String* pAccessibleDescription; + + ImplAccessibleInfos() + { + nAccessibleRole = 0xFFFF; + pAccessibleName = NULL; + pAccessibleDescription = NULL; + } + + ~ImplAccessibleInfos() + { + delete pAccessibleName; + delete pAccessibleDescription; + } +}; + +// ----------------------------------------------------------------------- + +WindowImpl::WindowImpl() +{ +} + +WindowImpl::~WindowImpl() +{ +} + + +// ----------------------------------------------------------------------- + +// helper method to allow inline constructor even for pWindow!=NULL case +void ImplDelData::AttachToWindow( const Window* pWindow ) +{ + if( pWindow ) + const_cast<Window*>(pWindow)->ImplAddDel( this ); +} + +// ----------------------------------------------------------------------- + +// define dtor for ImplDelData +ImplDelData::~ImplDelData() +{ + // #112873# auto remove of ImplDelData + // due to this code actively calling ImplRemoveDel() is not mandatory anymore + if( !mbDel && mpWindow ) + { + // the window still exists but we were not removed + const_cast<Window*>(mpWindow)->ImplRemoveDel( this ); + mpWindow = NULL; + } +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL +const char* ImplDbgCheckWindow( const void* pObj ) +{ + DBG_TESTSOLARMUTEX(); + + const Window* pWindow = (Window*)pObj; + + if ( (pWindow->GetType() < WINDOW_FIRST) || (pWindow->GetType() > WINDOW_LAST) ) + return "Window data overwrite"; + + // Fenster-Verkettung ueberpruefen + Window* pChild = pWindow->mpWindowImpl->mpFirstChild; + while ( pChild ) + { + if ( pChild->mpWindowImpl->mpParent != pWindow ) + return "Child-Window-Parent wrong"; + pChild = pChild->mpWindowImpl->mpNext; + } + + return NULL; +} +#endif + +// ======================================================================= + +void Window::ImplInitAppFontData( Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + long nTextHeight = pWindow->GetTextHeight(); + long nTextWidth = pWindow->GetTextWidth( XubString( RTL_CONSTASCII_USTRINGPARAM( "aemnnxEM" ) ) ); + long nSymHeight = nTextHeight*4; + // Falls Font zu schmal ist, machen wir die Basis breiter, + // damit die Dialoge symetrisch aussehen und nicht zu schmal + // werden. Wenn der Dialog die gleiche breite hat, geben wir + // noch etwas Spielraum dazu, da etwas mehr Platz besser ist. + if ( nSymHeight > nTextWidth ) + nTextWidth = nSymHeight; + else if ( nSymHeight+5 > nTextWidth ) + nTextWidth = nSymHeight+5; + pSVData->maGDIData.mnAppFontX = nTextWidth * 10 / 8; + pSVData->maGDIData.mnAppFontY = nTextHeight * 10; + + // FIXME: this is currently only on aqua, check with other + // platforms + if( pSVData->maNWFData.mbNoFocusRects ) + { + // try to find out wether there is a large correction + // of control sizes, if yes, make app font scalings larger + // so dialog positioning is not completely off + ImplControlValue aControlValue; + Rectangle aCtrlRegion( Point(), Size( nTextWidth < 10 ? 10 : nTextWidth, nTextHeight < 10 ? 10 : nTextHeight ) ); + Rectangle aBoundingRgn( aCtrlRegion ); + Rectangle aContentRgn( aCtrlRegion ); + if( pWindow->GetNativeControlRegion( CTRL_EDITBOX, PART_ENTIRE_CONTROL, aCtrlRegion, + CTRL_STATE_ENABLED, aControlValue, rtl::OUString(), + aBoundingRgn, aContentRgn ) ) + { + // comment: the magical +6 is for the extra border in bordered + // (which is the standard) edit fields + if( aContentRgn.GetHeight() - nTextHeight > (nTextHeight+4)/4 ) + pSVData->maGDIData.mnAppFontY = (aContentRgn.GetHeight()-4) * 10; + } + } + + + pSVData->maGDIData.mnRealAppFontX = pSVData->maGDIData.mnAppFontX; + if ( pSVData->maAppData.mnDialogScaleX ) + pSVData->maGDIData.mnAppFontX += (pSVData->maGDIData.mnAppFontX*pSVData->maAppData.mnDialogScaleX)/100; +} + +// ----------------------------------------------------------------------- + +bool Window::ImplCheckUIFont( const Font& rFont ) +{ + if( ImplGetSVData()->maGDIData.mbNativeFontConfig ) + return true; + + // create a text string using the localized text of important buttons + String aTestText; + static const StandardButtonType aTestButtons[] = + { + BUTTON_OK, BUTTON_CANCEL, BUTTON_CLOSE, BUTTON_ABORT, + BUTTON_YES, BUTTON_NO, BUTTON_MORE, BUTTON_IGNORE, + BUTTON_RETRY, BUTTON_HELP + }; + + const int nTestButtonCount = sizeof(aTestButtons)/sizeof(*aTestButtons); + for( int n = 0; n < nTestButtonCount; ++n ) + { + String aButtonStr = Button::GetStandardText( aTestButtons[n] ); + // #i115432# ignore mnemonic+accelerator part of each string + // TODO: use a string filtering method when it becomes available + const int nLen = aButtonStr.Len(); + bool bInside = false; + for( int i = 0; i < nLen; ++i ) { + const sal_Unicode c = aButtonStr.GetChar( i ); + if( (c == '(')) + bInside = true; + if( (c == ')')) + bInside = false; + if( (c == '~') + || (c == '(') || (c == ')') + || ((c >= 'A') && (c <= 'Z') && bInside) ) + aButtonStr.SetChar( i, ' ' ); + } + // append sanitized button text to test string + aTestText.Append( aButtonStr ); + } + + const int nFirstChar = HasGlyphs( rFont, aTestText ); + const bool bUIFontOk = (nFirstChar >= aTestText.Len()); + return bUIFontOk; +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl ) +{ + // reset high contrast to false, so the system can either update it + // or AutoDetectSystemHC can kick in (see below) + StyleSettings aTmpSt( rSettings.GetStyleSettings() ); + aTmpSt.SetHighContrastMode( FALSE ); + rSettings.SetStyleSettings( aTmpSt ); + ImplGetFrame()->UpdateSettings( rSettings ); + // reset default border width for layouters + ImplGetSVData()->maAppData.mnDefaultLayoutBorder = -1; + + // Verify availability of the configured UI font, otherwise choose "Andale Sans UI" + String aUserInterfaceFont; + bool bUseSystemFont = rSettings.GetStyleSettings().GetUseSystemUIFonts(); + + // check whether system UI font can display a typical UI text + if( bUseSystemFont ) + bUseSystemFont = ImplCheckUIFont( rSettings.GetStyleSettings().GetAppFont() ); + + if ( !bUseSystemFont ) + { + ImplInitFontList(); + String aConfigFont = utl::DefaultFontConfiguration::get()->getUserInterfaceFont( rSettings.GetUILocale() ); + xub_StrLen nIndex = 0; + while( nIndex != STRING_NOTFOUND ) + { + String aName( aConfigFont.GetToken( 0, ';', nIndex ) ); + if ( aName.Len() && mpWindowImpl->mpFrameData->mpFontList->FindFontFamily( aName ) ) + { + aUserInterfaceFont = aConfigFont; + break; + } + } + + if ( ! aUserInterfaceFont.Len() ) + { + String aFallbackFont (RTL_CONSTASCII_USTRINGPARAM( "Andale Sans UI" )); + if ( mpWindowImpl->mpFrameData->mpFontList->FindFontFamily( aFallbackFont ) ) + aUserInterfaceFont = aFallbackFont; + } + } + + if ( !bUseSystemFont && aUserInterfaceFont.Len() ) + { + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + Font aFont = aStyleSettings.GetAppFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetAppFont( aFont ); + aFont = aStyleSettings.GetHelpFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetHelpFont( aFont ); + aFont = aStyleSettings.GetTitleFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetTitleFont( aFont ); + aFont = aStyleSettings.GetFloatTitleFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetFloatTitleFont( aFont ); + aFont = aStyleSettings.GetMenuFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetMenuFont( aFont ); + aFont = aStyleSettings.GetToolFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetToolFont( aFont ); + aFont = aStyleSettings.GetLabelFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetLabelFont( aFont ); + aFont = aStyleSettings.GetInfoFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetInfoFont( aFont ); + aFont = aStyleSettings.GetRadioCheckFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetRadioCheckFont( aFont ); + aFont = aStyleSettings.GetPushButtonFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetPushButtonFont( aFont ); + aFont = aStyleSettings.GetFieldFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetFieldFont( aFont ); + aFont = aStyleSettings.GetIconFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetIconFont( aFont ); + aFont = aStyleSettings.GetGroupFont(); + aFont.SetName( aUserInterfaceFont ); + aStyleSettings.SetGroupFont( aFont ); + rSettings.SetStyleSettings( aStyleSettings ); + } + + StyleSettings aStyleSettings = rSettings.GetStyleSettings(); + // #97047: Force all fonts except Menu and Help to a fixed height + // to avoid UI scaling due to large fonts + // - but allow bigger fonts on bigger screens (i16682, i21238) + // dialogs were designed to fit 800x600 with an 8pt font, so scale accordingly + int maxFontheight = 9; // #107886#: 9 is default for some asian systems, so always allow if requested + if( GetDesktopRectPixel().getHeight() > 600 ) + maxFontheight = (int) ((( 8.0 * (double) GetDesktopRectPixel().getHeight()) / 600.0) + 1.5); + + Font aFont = aStyleSettings.GetMenuFont(); + int defFontheight = aFont.GetHeight(); + if( defFontheight > maxFontheight ) + defFontheight = maxFontheight; + + // if the UI is korean, chinese or another locale + // where the system font size is kown to be often too small to + // generate readable fonts enforce a minimum font size of 9 points + bool bBrokenLangFontHeight = false; + static const LanguageType eBrokenSystemFontSizeLanguages[] = + { LANGUAGE_KOREAN, LANGUAGE_KOREAN_JOHAB, + LANGUAGE_CHINESE_HONGKONG, LANGUAGE_CHINESE_MACAU, LANGUAGE_CHINESE_SIMPLIFIED, LANGUAGE_CHINESE_SINGAPORE, LANGUAGE_CHINESE_TRADITIONAL + }; + static std::set< LanguageType > aBrokenSystemFontSizeLanguagesSet( + eBrokenSystemFontSizeLanguages, + eBrokenSystemFontSizeLanguages + + (sizeof(eBrokenSystemFontSizeLanguages)/sizeof(eBrokenSystemFontSizeLanguages[0])) + ); + LanguageType aLang = Application::GetSettings().GetUILanguage(); + if( aBrokenSystemFontSizeLanguagesSet.find( aLang ) != aBrokenSystemFontSizeLanguagesSet.end() ) + { + defFontheight = Max(9, defFontheight); + bBrokenLangFontHeight = true; + } + + // i22098, toolfont will be scaled differently to avoid bloated rulers and status bars for big fonts + int toolfontheight = defFontheight; + if( toolfontheight > 9 ) + toolfontheight = (defFontheight+8) / 2; + + aFont = aStyleSettings.GetAppFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetAppFont( aFont ); + aFont = aStyleSettings.GetTitleFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetTitleFont( aFont ); + aFont = aStyleSettings.GetFloatTitleFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetFloatTitleFont( aFont ); + // keep menu and help font size from system unless in broken locale size + if( bBrokenLangFontHeight ) + { + aFont = aStyleSettings.GetMenuFont(); + if( aFont.GetHeight() < defFontheight ) + { + aFont.SetHeight( defFontheight ); + aStyleSettings.SetMenuFont( aFont ); + } + aFont = aStyleSettings.GetHelpFont(); + if( aFont.GetHeight() < defFontheight ) + { + aFont.SetHeight( defFontheight ); + aStyleSettings.SetHelpFont( aFont ); + } + } + + // use different height for toolfont + aFont = aStyleSettings.GetToolFont(); + aFont.SetHeight( toolfontheight ); + aStyleSettings.SetToolFont( aFont ); + + aFont = aStyleSettings.GetLabelFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetLabelFont( aFont ); + aFont = aStyleSettings.GetInfoFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetInfoFont( aFont ); + aFont = aStyleSettings.GetRadioCheckFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetRadioCheckFont( aFont ); + aFont = aStyleSettings.GetPushButtonFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetPushButtonFont( aFont ); + aFont = aStyleSettings.GetFieldFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetFieldFont( aFont ); + aFont = aStyleSettings.GetIconFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetIconFont( aFont ); + aFont = aStyleSettings.GetGroupFont(); + aFont.SetHeight( defFontheight ); + aStyleSettings.SetGroupFont( aFont ); + + // set workspace gradient to black in dark themes + if( aStyleSettings.GetWindowColor().IsDark() ) + aStyleSettings.SetWorkspaceGradient( Wallpaper( Color( COL_BLACK ) ) ); + else + { + Gradient aGrad( GRADIENT_LINEAR, DEFAULT_WORKSPACE_GRADIENT_START_COLOR, DEFAULT_WORKSPACE_GRADIENT_END_COLOR ); + aStyleSettings.SetWorkspaceGradient( Wallpaper( aGrad ) ); + } + + rSettings.SetStyleSettings( aStyleSettings ); + + + // auto detect HC mode; if the system already set it to "yes" + // (see above) then accept that + if( !rSettings.GetStyleSettings().GetHighContrastMode() ) + { + sal_Bool bTmp = sal_False, bAutoHCMode = sal_True; + utl::OConfigurationNode aNode = utl::OConfigurationTreeRoot::tryCreateWithServiceFactory( + vcl::unohelper::GetMultiServiceFactory(), + OUString::createFromAscii( "org.openoffice.Office.Common/Accessibility" ) ); // note: case sensisitive ! + if ( aNode.isValid() ) + { + ::com::sun::star::uno::Any aValue = aNode.getNodeValue( OUString::createFromAscii( "AutoDetectSystemHC" ) ); + if( aValue >>= bTmp ) + bAutoHCMode = bTmp; + } + if( bAutoHCMode ) + { + if( rSettings.GetStyleSettings().GetFaceColor().IsDark() + || rSettings.GetStyleSettings().GetWindowColor().IsDark() ) + { + aStyleSettings = rSettings.GetStyleSettings(); + aStyleSettings.SetHighContrastMode( TRUE ); + rSettings.SetStyleSettings( aStyleSettings ); + } + } + } + + static const char* pEnvHC = getenv( "SAL_FORCE_HC" ); + if( pEnvHC && *pEnvHC ) + { + aStyleSettings.SetHighContrastMode( TRUE ); + rSettings.SetStyleSettings( aStyleSettings ); + } + +#ifdef DBG_UTIL + // Evt. AppFont auf Fett schalten, damit man feststellen kann, + // ob fuer die Texte auf anderen Systemen genuegend Platz + // vorhanden ist + if ( DbgIsBoldAppFont() ) + { + aStyleSettings = rSettings.GetStyleSettings(); + aFont = aStyleSettings.GetAppFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetAppFont( aFont ); + aFont = aStyleSettings.GetGroupFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetGroupFont( aFont ); + aFont = aStyleSettings.GetLabelFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetLabelFont( aFont ); + aFont = aStyleSettings.GetRadioCheckFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetRadioCheckFont( aFont ); + aFont = aStyleSettings.GetPushButtonFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetPushButtonFont( aFont ); + aFont = aStyleSettings.GetFieldFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetFieldFont( aFont ); + aFont = aStyleSettings.GetIconFont(); + aFont.SetWeight( WEIGHT_BOLD ); + aStyleSettings.SetIconFont( aFont ); + rSettings.SetStyleSettings( aStyleSettings ); + } +#endif + + if ( bCallHdl ) + GetpApp()->SystemSettingsChanging( rSettings, this ); +} + +// ----------------------------------------------------------------------- + +MouseEvent ImplTranslateMouseEvent( const MouseEvent& rE, Window* pSource, Window* pDest ) +{ + Point aPos = pSource->OutputToScreenPixel( rE.GetPosPixel() ); + aPos = pDest->ScreenToOutputPixel( aPos ); + return MouseEvent( aPos, rE.GetClicks(), rE.GetMode(), rE.GetButtons(), rE.GetModifier() ); +} + +// ----------------------------------------------------------------------- + +CommandEvent ImplTranslateCommandEvent( const CommandEvent& rCEvt, Window* pSource, Window* pDest ) +{ + if ( !rCEvt.IsMouseEvent() ) + return rCEvt; + + Point aPos = pSource->OutputToScreenPixel( rCEvt.GetMousePosPixel() ); + aPos = pDest->ScreenToOutputPixel( aPos ); + return CommandEvent( aPos, rCEvt.GetCommand(), rCEvt.IsMouseEvent(), rCEvt.GetData() ); +} + +// ======================================================================= + +void Window::ImplInitWindowData( WindowType nType ) +{ + mpWindowImpl = new WindowImpl; + + meOutDevType = OUTDEV_WINDOW; + + mpWindowImpl->maZoom = Fraction( 1, 1 ); + mpWindowImpl->maWinRegion = Region( REGION_NULL ); + mpWindowImpl->maWinClipRegion = Region( REGION_NULL ); + mpWindowImpl->mpWinData = NULL; // Extra Window Data, that we dont need for all windows + mpWindowImpl->mpOverlapData = NULL; // Overlap Data + mpWindowImpl->mpFrameData = NULL; // Frame Data + mpWindowImpl->mpFrame = NULL; // Pointer to frame window + mpWindowImpl->mpSysObj = NULL; + mpWindowImpl->mpFrameWindow = NULL; // window to top level parent (same as frame window) + mpWindowImpl->mpOverlapWindow = NULL; // first overlap parent + mpWindowImpl->mpBorderWindow = NULL; // Border-Window + mpWindowImpl->mpClientWindow = NULL; // Client-Window of a FrameWindow + mpWindowImpl->mpParent = NULL; // parent (inkl. BorderWindow) + mpWindowImpl->mpRealParent = NULL; // real parent (exkl. BorderWindow) + mpWindowImpl->mpFirstChild = NULL; // first child window + mpWindowImpl->mpLastChild = NULL; // last child window + mpWindowImpl->mpFirstOverlap = NULL; // first overlap window (only set in overlap windows) + mpWindowImpl->mpLastOverlap = NULL; // last overlap window (only set in overlap windows) + mpWindowImpl->mpPrev = NULL; // prev window + mpWindowImpl->mpNext = NULL; // next window + mpWindowImpl->mpNextOverlap = NULL; // next overlap window of frame + mpWindowImpl->mpLastFocusWindow = NULL; // window for focus restore + mpWindowImpl->mpDlgCtrlDownWindow = NULL; // window for dialog control + mpWindowImpl->mpFirstDel = NULL; // Dtor notification list + mpWindowImpl->mpUserData = NULL; // user data + mpWindowImpl->mpExtImpl = NULL; // extended implementation data + mpWindowImpl->mpCursor = NULL; // cursor + mpWindowImpl->mpControlFont = NULL; // font propertie + mpWindowImpl->mpVCLXWindow = NULL; + mpWindowImpl->mpAccessibleInfos = NULL; + mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT ); // kein Foreground gesetzt + mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT ); // kein Background gesetzt + mpWindowImpl->mnLeftBorder = 0; // left border + mpWindowImpl->mnTopBorder = 0; // top border + mpWindowImpl->mnRightBorder = 0; // right border + mpWindowImpl->mnBottomBorder = 0; // bottom border + mpWindowImpl->mnX = 0; // X-Position to Parent + mpWindowImpl->mnY = 0; // Y-Position to Parent + mpWindowImpl->mnAbsScreenX = 0; // absolute X-position on screen, used for RTL window positioning + mpWindowImpl->mpChildClipRegion = NULL; // Child-Clip-Region when ClipChildren + mpWindowImpl->mpPaintRegion = NULL; // Paint-ClipRegion + mpWindowImpl->mnStyle = 0; // style (init in ImplInitWindow) + mpWindowImpl->mnPrevStyle = 0; // prevstyle (set in SetStyle) + mpWindowImpl->mnExtendedStyle = 0; // extended style (init in ImplInitWindow) + mpWindowImpl->mnPrevExtendedStyle = 0; // prevstyle (set in SetExtendedStyle) + mpWindowImpl->mnType = nType; // type + mpWindowImpl->mnGetFocusFlags = 0; // Flags fuer GetFocus()-Aufruf + mpWindowImpl->mnWaitCount = 0; // Wait-Count (>1 == Warte-MousePointer) + mpWindowImpl->mnPaintFlags = 0; // Flags for ImplCallPaint + mpWindowImpl->mnParentClipMode = 0; // Flags for Parent-ClipChildren-Mode + mpWindowImpl->mnActivateMode = 0; // Wird bei System/Overlap-Windows umgesetzt + mpWindowImpl->mnDlgCtrlFlags = 0; // DialogControl-Flags + mpWindowImpl->mnLockCount = 0; // LockCount + mpWindowImpl->meAlwaysInputMode = AlwaysInputNone; // neither AlwaysEnableInput nor AlwaysDisableInput called + mpWindowImpl->mbFrame = FALSE; // TRUE: Window is a frame window + mpWindowImpl->mbBorderWin = FALSE; // TRUE: Window is a border window + mpWindowImpl->mbOverlapWin = FALSE; // TRUE: Window is a overlap window + mpWindowImpl->mbSysWin = FALSE; // TRUE: SystemWindow is the base class + mpWindowImpl->mbDialog = FALSE; // TRUE: Dialog is the base class + mpWindowImpl->mbDockWin = FALSE; // TRUE: DockingWindow is the base class + mpWindowImpl->mbFloatWin = FALSE; // TRUE: FloatingWindow is the base class + mpWindowImpl->mbPushButton = FALSE; // TRUE: PushButton is the base class + mpWindowImpl->mbToolBox = FALSE; // TRUE: ToolBox is the base class + mpWindowImpl->mbMenuFloatingWindow= FALSE; // TRUE: MenuFloatingWindow is the base class + mpWindowImpl->mbToolbarFloatingWindow= FALSE; // TRUE: ImplPopupFloatWin is the base class, used for subtoolbars + mpWindowImpl->mbSplitter = FALSE; // TRUE: Splitter is the base class + mpWindowImpl->mbVisible = FALSE; // TRUE: Show( TRUE ) called + mpWindowImpl->mbOverlapVisible = FALSE; // TRUE: Hide called for visible window from ImplHideAllOverlapWindow() + mpWindowImpl->mbDisabled = FALSE; // TRUE: Enable( FALSE ) called + mpWindowImpl->mbInputDisabled = FALSE; // TRUE: EnableInput( FALSE ) called + mpWindowImpl->mbDropDisabled = FALSE; // TRUE: Drop is enabled + mpWindowImpl->mbNoUpdate = FALSE; // TRUE: SetUpdateMode( FALSE ) called + mpWindowImpl->mbNoParentUpdate = FALSE; // TRUE: SetParentUpdateMode( FALSE ) called + mpWindowImpl->mbActive = FALSE; // TRUE: Window Active + mpWindowImpl->mbParentActive = FALSE; // TRUE: OverlapActive from Parent + mpWindowImpl->mbReallyVisible = FALSE; // TRUE: this and all parents to an overlaped window are visible + mpWindowImpl->mbReallyShown = FALSE; // TRUE: this and all parents to an overlaped window are shown + mpWindowImpl->mbInInitShow = FALSE; // TRUE: we are in InitShow + mpWindowImpl->mbChildNotify = FALSE; // TRUE: ChildNotify + mpWindowImpl->mbChildPtrOverwrite = FALSE; // TRUE: PointerStyle overwrites Child-Pointer + mpWindowImpl->mbNoPtrVisible = FALSE; // TRUE: ShowPointer( FALSE ) called + mpWindowImpl->mbMouseMove = FALSE; // TRUE: BaseMouseMove called + mpWindowImpl->mbPaintFrame = FALSE; // TRUE: Paint is visible, but not painted + mpWindowImpl->mbInPaint = FALSE; // TRUE: Inside PaintHdl + mpWindowImpl->mbMouseButtonDown = FALSE; // TRUE: BaseMouseButtonDown called + mpWindowImpl->mbMouseButtonUp = FALSE; // TRUE: BaseMouseButtonUp called + mpWindowImpl->mbKeyInput = FALSE; // TRUE: BaseKeyInput called + mpWindowImpl->mbKeyUp = FALSE; // TRUE: BaseKeyUp called + mpWindowImpl->mbCommand = FALSE; // TRUE: BaseCommand called + mpWindowImpl->mbDefPos = TRUE; // TRUE: Position is not Set + mpWindowImpl->mbDefSize = TRUE; // TRUE: Size is not Set + mpWindowImpl->mbCallMove = TRUE; // TRUE: Move must be called by Show + mpWindowImpl->mbCallResize = TRUE; // TRUE: Resize must be called by Show + mpWindowImpl->mbWaitSystemResize = TRUE; // TRUE: Wait for System-Resize + mpWindowImpl->mbInitWinClipRegion = TRUE; // TRUE: Calc Window Clip Region + mpWindowImpl->mbInitChildRegion = FALSE; // TRUE: InitChildClipRegion + mpWindowImpl->mbWinRegion = FALSE; // TRUE: Window Region + mpWindowImpl->mbClipChildren = FALSE; // TRUE: Child-Fenster muessen evt. geclippt werden + mpWindowImpl->mbClipSiblings = FALSE; // TRUE: Nebeneinanderliegende Child-Fenster muessen evt. geclippt werden + mpWindowImpl->mbChildTransparent = FALSE; // TRUE: Child-Fenster duerfen transparent einschalten (inkl. Parent-CLIPCHILDREN) + mpWindowImpl->mbPaintTransparent = FALSE; // TRUE: Paints muessen auf Parent ausgeloest werden + mpWindowImpl->mbMouseTransparent = FALSE; // TRUE: Window is transparent for Mouse + mpWindowImpl->mbDlgCtrlStart = FALSE; // TRUE: Ab hier eigenes Dialog-Control + mpWindowImpl->mbFocusVisible = FALSE; // TRUE: Focus Visible + mpWindowImpl->mbUseNativeFocus = FALSE; + mpWindowImpl->mbNativeFocusVisible= FALSE; // TRUE: native Focus Visible + mpWindowImpl->mbInShowFocus = FALSE; // prevent recursion + mpWindowImpl->mbInHideFocus = FALSE; // prevent recursion + mpWindowImpl->mbTrackVisible = FALSE; // TRUE: Tracking Visible + mpWindowImpl->mbControlForeground = FALSE; // TRUE: Foreground-Property set + mpWindowImpl->mbControlBackground = FALSE; // TRUE: Background-Property set + mpWindowImpl->mbAlwaysOnTop = FALSE; // TRUE: immer vor allen anderen normalen Fenstern sichtbar + mpWindowImpl->mbCompoundControl = FALSE; // TRUE: Zusammengesetztes Control => Listener... + mpWindowImpl->mbCompoundControlHasFocus = FALSE; // TRUE: Zusammengesetztes Control hat irgendwo den Focus + mpWindowImpl->mbPaintDisabled = FALSE; // TRUE: Paint soll nicht ausgefuehrt werden + mpWindowImpl->mbAllResize = FALSE; // TRUE: Auch ResizeEvents mit 0,0 schicken + mpWindowImpl->mbInDtor = FALSE; // TRUE: Wir befinden uns im Window-Dtor + mpWindowImpl->mbExtTextInput = FALSE; // TRUE: ExtTextInput-Mode is active + mpWindowImpl->mbInFocusHdl = FALSE; // TRUE: Innerhalb vom GetFocus-Handler + mpWindowImpl->mbCreatedWithToolkit = FALSE; + mpWindowImpl->mbSuppressAccessibilityEvents = FALSE; // TRUE: do not send any accessibility events + mpWindowImpl->mbDrawSelectionBackground = FALSE; // TRUE: draws transparent window background to indicate (toolbox) selection + mpWindowImpl->mbIsInTaskPaneList = FALSE; // TRUE: window was added to the taskpanelist in the topmost system window + mpWindowImpl->mnNativeBackground = 0; // initialize later, depends on type + mpWindowImpl->mbCallHandlersDuringInputDisabled = FALSE; // TRUE: call event handlers even if input is disabled + mpWindowImpl->mbDisableAccessibleLabelForRelation = FALSE; // TRUE: do not set LabelFor relation on accessible objects + mpWindowImpl->mbDisableAccessibleLabeledByRelation = FALSE; // TRUE: do not set LabeledBy relation on accessible objects + mpWindowImpl->mbHelpTextDynamic = FALSE; // TRUE: append help id in HELP_DEBUG case + mpWindowImpl->mbFakeFocusSet = FALSE; // TRUE: pretend as if the window has focus. + + mbEnableRTL = Application::GetSettings().GetLayoutRTL(); // TRUE: this outdev will be mirrored if RTL window layout (UI mirroring) is globally active +} + +// ----------------------------------------------------------------------- + +void Window::ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& /*aSystemWorkWindowToken*/ ) +{ + ImplInit( pParent, nStyle, NULL ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData ) +{ + DBG_ASSERT( mpWindowImpl->mbFrame || pParent, "Window::Window(): pParent == NULL" ); + + ImplSVData* pSVData = ImplGetSVData(); + Window* pRealParent = pParent; + + // 3D-Look vererben + if ( !mpWindowImpl->mbOverlapWin && pParent && (pParent->GetStyle() & WB_3DLOOK) ) + nStyle |= WB_3DLOOK; + + // create border window if necessary + if ( !mpWindowImpl->mbFrame && !mpWindowImpl->mbBorderWin && !mpWindowImpl->mpBorderWindow + && (nStyle & (WB_BORDER | WB_SYSTEMCHILDWINDOW) ) ) + { + USHORT nBorderTypeStyle = 0; + if( (nStyle & WB_SYSTEMCHILDWINDOW) ) + { + // handle WB_SYSTEMCHILDWINDOW + // these should be analogous to a top level frame; meaning they + // should have a border window with style BORDERWINDOW_STYLE_FRAME + // which controls their size + nBorderTypeStyle |= BORDERWINDOW_STYLE_FRAME; + nStyle |= WB_BORDER; + } + ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, nStyle & (WB_BORDER | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_NEEDSFOCUS), nBorderTypeStyle ); + ((Window*)pBorderWin)->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpWindowImpl->mpBorderWindow = pBorderWin; + pParent = mpWindowImpl->mpBorderWindow; + } + else if( !mpWindowImpl->mbFrame && ! pParent ) + { + mpWindowImpl->mbOverlapWin = TRUE; + mpWindowImpl->mbFrame = TRUE; + } + + // insert window in list + ImplInsertWindow( pParent ); + mpWindowImpl->mnStyle = nStyle; + + // Overlap-Window-Daten + if ( mpWindowImpl->mbOverlapWin ) + { + mpWindowImpl->mpOverlapData = new ImplOverlapData; + mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL; + mpWindowImpl->mpOverlapData->mpSaveBackRgn = NULL; + mpWindowImpl->mpOverlapData->mpNextBackWin = NULL; + mpWindowImpl->mpOverlapData->mnSaveBackSize = 0; + mpWindowImpl->mpOverlapData->mbSaveBack = FALSE; + mpWindowImpl->mpOverlapData->mnTopLevel = 1; + } + + if( pParent && ! mpWindowImpl->mbFrame ) + mbEnableRTL = pParent->mbEnableRTL; + + // test for frame creation + if ( mpWindowImpl->mbFrame ) + { + // create frame + ULONG nFrameStyle = 0; + + if ( nStyle & WB_MOVEABLE ) + nFrameStyle |= SAL_FRAME_STYLE_MOVEABLE; + if ( nStyle & WB_SIZEABLE ) + nFrameStyle |= SAL_FRAME_STYLE_SIZEABLE; + if ( nStyle & WB_CLOSEABLE ) + nFrameStyle |= SAL_FRAME_STYLE_CLOSEABLE; + if ( nStyle & WB_APP ) + nFrameStyle |= SAL_FRAME_STYLE_DEFAULT; + // check for undecorated floating window + if( // 1. floating windows that are not moveable/sizeable (only closeable allowed) + ( !(nFrameStyle & ~SAL_FRAME_STYLE_CLOSEABLE) && + ( mpWindowImpl->mbFloatWin || ((GetType() == WINDOW_BORDERWINDOW) && ((ImplBorderWindow*)this)->mbFloatWindow) || (nStyle & WB_SYSTEMFLOATWIN) ) ) || + // 2. borderwindows of floaters with ownerdraw decoration + ( ((GetType() == WINDOW_BORDERWINDOW) && ((ImplBorderWindow*)this)->mbFloatWindow && (nStyle & WB_OWNERDRAWDECORATION) ) ) ) + { + nFrameStyle = SAL_FRAME_STYLE_FLOAT; + if( nStyle & WB_OWNERDRAWDECORATION ) + nFrameStyle |= (SAL_FRAME_STYLE_OWNERDRAWDECORATION | SAL_FRAME_STYLE_NOSHADOW); + if( nStyle & WB_NEEDSFOCUS ) + nFrameStyle |= SAL_FRAME_STYLE_FLOAT_FOCUSABLE; + } + else if( mpWindowImpl->mbFloatWin ) + nFrameStyle |= SAL_FRAME_STYLE_TOOLWINDOW; + + if( nStyle & WB_INTROWIN ) + nFrameStyle |= SAL_FRAME_STYLE_INTRO; + if( nStyle & WB_TOOLTIPWIN ) + nFrameStyle |= SAL_FRAME_STYLE_TOOLTIP; + + if( nStyle & WB_NOSHADOW ) + nFrameStyle |= SAL_FRAME_STYLE_NOSHADOW; + + if( nStyle & WB_SYSTEMCHILDWINDOW ) + nFrameStyle |= SAL_FRAME_STYLE_SYSTEMCHILD; + + switch (mpWindowImpl->mnType) + { + case WINDOW_DIALOG: + case WINDOW_TABDIALOG: + case WINDOW_MODALDIALOG: + case WINDOW_MODELESSDIALOG: + case WINDOW_MESSBOX: + case WINDOW_INFOBOX: + case WINDOW_WARNINGBOX: + case WINDOW_ERRORBOX: + case WINDOW_QUERYBOX: + nFrameStyle |= SAL_FRAME_STYLE_DIALOG; + default: + break; + } + + SalFrame* pParentFrame = NULL; + if ( pParent ) + pParentFrame = pParent->mpWindowImpl->mpFrame; + SalFrame* pFrame; + if ( pSystemParentData ) + pFrame = pSVData->mpDefInst->CreateChildFrame( pSystemParentData, nFrameStyle | SAL_FRAME_STYLE_PLUG ); + else + pFrame = pSVData->mpDefInst->CreateFrame( pParentFrame, nFrameStyle ); + if ( !pFrame ) + { + // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario) + throw ::com::sun::star::uno::RuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "Could not create system window!" ) ), + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >() ); + //GetpApp()->Exception( EXC_SYSOBJNOTCREATED ); + } + + pFrame->SetCallback( this, ImplWindowFrameProc ); + + // set window frame data + mpWindowImpl->mpFrameData = new ImplFrameData; + mpWindowImpl->mpFrame = pFrame; + mpWindowImpl->mpFrameWindow = this; + mpWindowImpl->mpOverlapWindow = this; + + // set frame data + mpWindowImpl->mpFrameData->mpNextFrame = pSVData->maWinData.mpFirstFrame; + pSVData->maWinData.mpFirstFrame = this; + mpWindowImpl->mpFrameData->mpFirstOverlap = NULL; + mpWindowImpl->mpFrameData->mpFocusWin = NULL; + mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL; + mpWindowImpl->mpFrameData->mpMouseDownWin = NULL; + mpWindowImpl->mpFrameData->mpFirstBackWin = NULL; + mpWindowImpl->mpFrameData->mpFontList = pSVData->maGDIData.mpScreenFontList; + mpWindowImpl->mpFrameData->mpFontCache = pSVData->maGDIData.mpScreenFontCache; + mpWindowImpl->mpFrameData->mnAllSaveBackSize = 0; + mpWindowImpl->mpFrameData->mnFocusId = 0; + mpWindowImpl->mpFrameData->mnMouseMoveId = 0; + mpWindowImpl->mpFrameData->mnLastMouseX = -1; + mpWindowImpl->mpFrameData->mnLastMouseY = -1; + mpWindowImpl->mpFrameData->mnBeforeLastMouseX = -1; + mpWindowImpl->mpFrameData->mnBeforeLastMouseY = -1; + mpWindowImpl->mpFrameData->mnFirstMouseX = -1; + mpWindowImpl->mpFrameData->mnFirstMouseY = -1; + mpWindowImpl->mpFrameData->mnLastMouseWinX = -1; + mpWindowImpl->mpFrameData->mnLastMouseWinY = -1; + mpWindowImpl->mpFrameData->mnModalMode = 0; + mpWindowImpl->mpFrameData->mnMouseDownTime = 0; + mpWindowImpl->mpFrameData->mnClickCount = 0; + mpWindowImpl->mpFrameData->mnFirstMouseCode = 0; + mpWindowImpl->mpFrameData->mnMouseCode = 0; + mpWindowImpl->mpFrameData->mnMouseMode = 0; + mpWindowImpl->mpFrameData->meMapUnit = MAP_PIXEL; + mpWindowImpl->mpFrameData->mbHasFocus = FALSE; + mpWindowImpl->mpFrameData->mbInMouseMove = FALSE; + mpWindowImpl->mpFrameData->mbMouseIn = FALSE; + mpWindowImpl->mpFrameData->mbStartDragCalled = FALSE; + mpWindowImpl->mpFrameData->mbNeedSysWindow = FALSE; + mpWindowImpl->mpFrameData->mbMinimized = FALSE; + mpWindowImpl->mpFrameData->mbStartFocusState = FALSE; + mpWindowImpl->mpFrameData->mbInSysObjFocusHdl = FALSE; + mpWindowImpl->mpFrameData->mbInSysObjToTopHdl = FALSE; + mpWindowImpl->mpFrameData->mbSysObjFocus = FALSE; + mpWindowImpl->mpFrameData->maPaintTimer.SetTimeout( 30 ); + mpWindowImpl->mpFrameData->maPaintTimer.SetTimeoutHdl( LINK( this, Window, ImplHandlePaintHdl ) ); + mpWindowImpl->mpFrameData->maResizeTimer.SetTimeout( 50 ); + mpWindowImpl->mpFrameData->maResizeTimer.SetTimeoutHdl( LINK( this, Window, ImplHandleResizeTimerHdl ) ); + mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = FALSE; + + if ( pRealParent && IsTopWindow() ) + { + ImplWinData* pParentWinData = pRealParent->ImplGetWinData(); + pParentWinData->maTopWindowChildren.push_back( this ); + } + } + + // init data + mpWindowImpl->mpRealParent = pRealParent; + + // #99318: make sure fontcache and list is available before call to SetSettings + mpFontList = mpWindowImpl->mpFrameData->mpFontList; + mpFontCache = mpWindowImpl->mpFrameData->mpFontCache; + + if ( mpWindowImpl->mbFrame ) + { + if ( pParent ) + { + mpWindowImpl->mpFrameData->mnDPIX = pParent->mpWindowImpl->mpFrameData->mnDPIX; + mpWindowImpl->mpFrameData->mnDPIY = pParent->mpWindowImpl->mpFrameData->mnDPIY; + } + else + { + if ( ImplGetGraphics() ) + { + mpGraphics->GetResolution( mpWindowImpl->mpFrameData->mnDPIX, mpWindowImpl->mpFrameData->mnDPIY ); + } + } + + // add ownerdraw decorated frame windows to list in the top-most frame window + // so they can be hidden on lose focus + if( nStyle & WB_OWNERDRAWDECORATION ) + ImplGetOwnerDrawList().push_back( this ); + + // delay settings initialization until first "real" frame + // this relies on the IntroWindow not needing any system settings + if ( !pSVData->maAppData.mbSettingsInit && + ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) + ) + { + // side effect: ImplUpdateGlobalSettings does an ImplGetFrame()->UpdateSettings + ImplUpdateGlobalSettings( *pSVData->maAppData.mpSettings ); + OutputDevice::SetSettings( *pSVData->maAppData.mpSettings ); + pSVData->maAppData.mbSettingsInit = TRUE; + } + + // If we create a Window with default size, query this + // size directly, because we want resize all Controls to + // the correct size before we display the window + if ( nStyle & (WB_MOVEABLE | WB_SIZEABLE | WB_APP) ) + mpWindowImpl->mpFrame->GetClientSize( mnOutWidth, mnOutHeight ); + } + else + { + if ( pParent ) + { + if ( !ImplIsOverlapWindow() ) + { + mpWindowImpl->mbDisabled = pParent->mpWindowImpl->mbDisabled; + mpWindowImpl->mbInputDisabled = pParent->mpWindowImpl->mbInputDisabled; + mpWindowImpl->meAlwaysInputMode = pParent->mpWindowImpl->meAlwaysInputMode; + } + + OutputDevice::SetSettings( pParent->GetSettings() ); + } + + } + + const StyleSettings& rStyleSettings = maSettings.GetStyleSettings(); + USHORT nScreenZoom = rStyleSettings.GetScreenZoom(); + mnDPIX = (mpWindowImpl->mpFrameData->mnDPIX*nScreenZoom)/100; + mnDPIY = (mpWindowImpl->mpFrameData->mnDPIY*nScreenZoom)/100; + maFont = rStyleSettings.GetAppFont(); + ImplPointToLogic( maFont ); + + if ( nStyle & WB_3DLOOK ) + { + SetTextColor( rStyleSettings.GetButtonTextColor() ); + SetBackground( Wallpaper( rStyleSettings.GetFaceColor() ) ); + } + else + { + SetTextColor( rStyleSettings.GetWindowTextColor() ); + SetBackground( Wallpaper( rStyleSettings.GetWindowColor() ) ); + } + + ImplUpdatePos(); + + // calculate app font res (except for the Intro Window or the default window) + if ( mpWindowImpl->mbFrame && !pSVData->maGDIData.mnAppFontX && ! (nStyle & (WB_INTROWIN|WB_DEFAULTWIN)) ) + ImplInitAppFontData( this ); + + if ( GetAccessibleParentWindow() && GetParent() != Application::GetDefDialogParent() ) + GetAccessibleParentWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CHILDCREATED, this ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplSetFrameParent( const Window* pParent ) +{ + Window* pFrameWindow = ImplGetSVData()->maWinData.mpFirstFrame; + while( pFrameWindow ) + { + // search all frames that are children of this window + // and reparent them + if( ImplIsRealParentPath( pFrameWindow ) ) + { + DBG_ASSERT( mpWindowImpl->mpFrame != pFrameWindow->mpWindowImpl->mpFrame, "SetFrameParent to own" ); + DBG_ASSERT( mpWindowImpl->mpFrame, "no frame" ); + SalFrame* pParentFrame = pParent ? pParent->mpWindowImpl->mpFrame : NULL; + pFrameWindow->mpWindowImpl->mpFrame->SetParent( pParentFrame ); + } + pFrameWindow = pFrameWindow->mpWindowImpl->mpFrameData->mpNextFrame; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInsertWindow( Window* pParent ) +{ + mpWindowImpl->mpParent = pParent; + mpWindowImpl->mpRealParent = pParent; + + if ( pParent && !mpWindowImpl->mbFrame ) + { + // search frame window and set window frame data + Window* pFrameParent = pParent->mpWindowImpl->mpFrameWindow; + mpWindowImpl->mpFrameData = pFrameParent->mpWindowImpl->mpFrameData; + mpWindowImpl->mpFrame = pFrameParent->mpWindowImpl->mpFrame; + mpWindowImpl->mpFrameWindow = pFrameParent; + mpWindowImpl->mbFrame = FALSE; + + // search overlap window and insert window in list + if ( ImplIsOverlapWindow() ) + { + Window* pFirstOverlapParent = pParent; + while ( !pFirstOverlapParent->ImplIsOverlapWindow() ) + pFirstOverlapParent = pFirstOverlapParent->ImplGetParent(); + mpWindowImpl->mpOverlapWindow = pFirstOverlapParent; + + mpWindowImpl->mpNextOverlap = mpWindowImpl->mpFrameData->mpFirstOverlap; + mpWindowImpl->mpFrameData->mpFirstOverlap = this; + + // Overlap-Windows sind per default die obersten + mpWindowImpl->mpNext = pFirstOverlapParent->mpWindowImpl->mpFirstOverlap; + pFirstOverlapParent->mpWindowImpl->mpFirstOverlap = this; + if ( !pFirstOverlapParent->mpWindowImpl->mpLastOverlap ) + pFirstOverlapParent->mpWindowImpl->mpLastOverlap = this; + else + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this; + } + else + { + if ( pParent->ImplIsOverlapWindow() ) + mpWindowImpl->mpOverlapWindow = pParent; + else + mpWindowImpl->mpOverlapWindow = pParent->mpWindowImpl->mpOverlapWindow; + mpWindowImpl->mpPrev = pParent->mpWindowImpl->mpLastChild; + pParent->mpWindowImpl->mpLastChild = this; + if ( !pParent->mpWindowImpl->mpFirstChild ) + pParent->mpWindowImpl->mpFirstChild = this; + else + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplRemoveWindow( BOOL bRemoveFrameData ) +{ + // Fenster aus den Listen austragen + if ( !mpWindowImpl->mbFrame ) + { + if ( ImplIsOverlapWindow() ) + { + if ( mpWindowImpl->mpFrameData->mpFirstOverlap == this ) + mpWindowImpl->mpFrameData->mpFirstOverlap = mpWindowImpl->mpNextOverlap; + else + { + Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pTempWin->mpWindowImpl->mpNextOverlap != this ) + pTempWin = pTempWin->mpWindowImpl->mpNextOverlap; + pTempWin->mpWindowImpl->mpNextOverlap = mpWindowImpl->mpNextOverlap; + } + + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev; + } + else + { + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev; + } + + mpWindowImpl->mpPrev = NULL; + mpWindowImpl->mpNext = NULL; + } + + if ( bRemoveFrameData ) + { + // Graphic freigeben + ImplReleaseGraphics(); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallResize() +{ + mpWindowImpl->mbCallResize = FALSE; + + if( GetBackground().IsGradient() ) + Invalidate(); + + Resize(); + + // #88419# Most classes don't call the base class in Resize() and Move(), + // => Call ImpleResize/Move instead of Resize/Move directly... + ImplCallEventListeners( VCLEVENT_WINDOW_RESIZE ); + + ImplExtResize(); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallMove() +{ + mpWindowImpl->mbCallMove = FALSE; + + if( mpWindowImpl->mbFrame ) + { + // update frame position + SalFrame *pParentFrame = NULL; + Window *pParent = ImplGetParent(); + while( pParent ) + { + if( pParent->mpWindowImpl->mpFrame != mpWindowImpl->mpFrame ) + { + pParentFrame = pParent->mpWindowImpl->mpFrame; + break; + } + pParent = pParent->GetParent(); + } + + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + mpWindowImpl->maPos = Point( g.nX, g.nY ); + if( pParentFrame ) + { + g = pParentFrame->GetGeometry(); + mpWindowImpl->maPos -= Point( g.nX, g.nY ); + } + // the client window and and all its subclients have the same position as the borderframe + // this is important for floating toolbars where the borderwindow is a floating window + // which has another borderwindow (ie the system floating window) + Window *pClientWin = mpWindowImpl->mpClientWindow; + while( pClientWin ) + { + pClientWin->mpWindowImpl->maPos = mpWindowImpl->maPos; + pClientWin = pClientWin->mpWindowImpl->mpClientWindow; + } + } + + Move(); + + ImplCallEventListeners( VCLEVENT_WINDOW_MOVE ); +} + +// ----------------------------------------------------------------------- + +static rtl::OString ImplAutoHelpID( ResMgr* pResMgr ) +{ + rtl::OString aRet; + + if( pResMgr && Application::IsAutoHelpIdEnabled() ) + aRet = pResMgr->GetAutoHelpId(); + + return aRet; +} + +// ----------------------------------------------------------------------- + +WinBits Window::ImplInitRes( const ResId& rResId ) +{ + GetRes( rResId ); + + char* pRes = (char*)GetClassRes(); + pRes += 8; + sal_uInt32 nStyle = (sal_uInt32)GetLongRes( (void*)pRes ); + rResId.SetWinBits( nStyle ); + return nStyle; +} + +// ----------------------------------------------------------------------- + +void Window::ImplLoadRes( const ResId& rResId ) +{ + ULONG nObjMask = ReadLongRes(); + + // we need to calculate auto helpids before the resource gets closed + // if the resource only contains flags, it will be closed before we try to read a help id + // so we always create an auto help id that might be overwritten later + // HelpId + rtl::OString aHelpId = ImplAutoHelpID( rResId.GetResMgr() ); + + // ResourceStyle + ULONG nRSStyle = ReadLongRes(); + // WinBits + ReadLongRes(); + + if( nObjMask & WINDOW_HELPID ) + aHelpId = ReadByteStringRes(); + + SetHelpId( aHelpId ); + + BOOL bPos = FALSE; + BOOL bSize = FALSE; + Point aPos; + Size aSize; + + if ( nObjMask & (WINDOW_XYMAPMODE | WINDOW_X | WINDOW_Y) ) + { + // Groessenangabe aus der Resource verwenden + MapUnit ePosMap = MAP_PIXEL; + + bPos = TRUE; + + if ( nObjMask & WINDOW_XYMAPMODE ) + ePosMap = (MapUnit)ReadLongRes(); + if ( nObjMask & WINDOW_X ) + aPos.X() = ImplLogicUnitToPixelX( ReadLongRes(), ePosMap ); + if ( nObjMask & WINDOW_Y ) + aPos.Y() = ImplLogicUnitToPixelY( ReadLongRes(), ePosMap ); + } + + if ( nObjMask & (WINDOW_WHMAPMODE | WINDOW_WIDTH | WINDOW_HEIGHT) ) + { + // Groessenangabe aus der Resource verwenden + MapUnit eSizeMap = MAP_PIXEL; + + bSize = TRUE; + + if ( nObjMask & WINDOW_WHMAPMODE ) + eSizeMap = (MapUnit)ReadLongRes(); + if ( nObjMask & WINDOW_WIDTH ) + aSize.Width() = ImplLogicUnitToPixelX( ReadLongRes(), eSizeMap ); + if ( nObjMask & WINDOW_HEIGHT ) + aSize.Height() = ImplLogicUnitToPixelY( ReadLongRes(), eSizeMap ); + } + + // Wegen Optimierung so schlimm aussehend + if ( nRSStyle & RSWND_CLIENTSIZE ) + { + if ( bPos ) + SetPosPixel( aPos ); + if ( bSize ) + SetOutputSizePixel( aSize ); + } + else if ( bPos && bSize ) + SetPosSizePixel( aPos, aSize ); + else if ( bPos ) + SetPosPixel( aPos ); + else if ( bSize ) + SetSizePixel( aSize ); + + if ( nRSStyle & RSWND_DISABLED ) + Enable( FALSE ); + + if ( nObjMask & WINDOW_TEXT ) + SetText( ReadStringRes() ); + if ( nObjMask & WINDOW_HELPTEXT ) + { + SetHelpText( ReadStringRes() ); + mpWindowImpl->mbHelpTextDynamic = TRUE; + } + if ( nObjMask & WINDOW_QUICKTEXT ) + SetQuickHelpText( ReadStringRes() ); + if ( nObjMask & WINDOW_EXTRALONG ) + SetData( (void*)ReadLongRes() ); + if ( nObjMask & WINDOW_UNIQUEID ) + SetUniqueId( ReadByteStringRes() ); + + if ( nObjMask & WINDOW_BORDER_STYLE ) + { + USHORT nBorderStyle = (USHORT)ReadLongRes(); + SetBorderStyle( nBorderStyle ); + } +} + +// ----------------------------------------------------------------------- + +ImplWinData* Window::ImplGetWinData() const +{ + if ( !mpWindowImpl->mpWinData ) + { + static const char* pNoNWF = getenv( "SAL_NO_NWF" ); + + ((Window*)this)->mpWindowImpl->mpWinData = new ImplWinData; + mpWindowImpl->mpWinData->mpExtOldText = NULL; + mpWindowImpl->mpWinData->mpExtOldAttrAry = NULL; + mpWindowImpl->mpWinData->mpCursorRect = 0; + mpWindowImpl->mpWinData->mnCursorExtWidth = 0; + mpWindowImpl->mpWinData->mpFocusRect = NULL; + mpWindowImpl->mpWinData->mpTrackRect = NULL; + mpWindowImpl->mpWinData->mnTrackFlags = 0; + mpWindowImpl->mpWinData->mnIsTopWindow = (USHORT) ~0; // not initialized yet, 0/1 will indicate TopWindow (see IsTopWindow()) + mpWindowImpl->mpWinData->mbMouseOver = FALSE; + mpWindowImpl->mpWinData->mbEnableNativeWidget = (pNoNWF && *pNoNWF) ? FALSE : TRUE; // TRUE: try to draw this control with native theme API + } + + return mpWindowImpl->mpWinData; +} + +// ----------------------------------------------------------------------- + +SalGraphics* Window::ImplGetFrameGraphics() const +{ + if ( mpWindowImpl->mpFrameWindow->mpGraphics ) + mpWindowImpl->mpFrameWindow->mbInitClipRegion = TRUE; + else + mpWindowImpl->mpFrameWindow->ImplGetGraphics(); + mpWindowImpl->mpFrameWindow->mpGraphics->ResetClipRegion(); + return mpWindowImpl->mpFrameWindow->mpGraphics; +} + +// ----------------------------------------------------------------------- + +Window* Window::ImplFindWindow( const Point& rFramePos ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Window* pTempWindow; + Window* pFindWindow; + + // Zuerst alle ueberlappenden Fenster ueberpruefen + pTempWindow = mpWindowImpl->mpFirstOverlap; + while ( pTempWindow ) + { + pFindWindow = pTempWindow->ImplFindWindow( rFramePos ); + if ( pFindWindow ) + return pFindWindow; + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } + + // dann testen wir unser Fenster + if ( !mpWindowImpl->mbVisible ) + return NULL; + + USHORT nHitTest = ImplHitTest( rFramePos ); + if ( nHitTest & WINDOW_HITTEST_INSIDE ) + { + // und danach gehen wir noch alle Child-Fenster durch + pTempWindow = mpWindowImpl->mpFirstChild; + while ( pTempWindow ) + { + pFindWindow = pTempWindow->ImplFindWindow( rFramePos ); + if ( pFindWindow ) + return pFindWindow; + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } + + if ( nHitTest & WINDOW_HITTEST_TRANSPARENT ) + return NULL; + else + return this; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +USHORT Window::ImplHitTest( const Point& rFramePos ) +{ + Point aFramePos( rFramePos ); + if( ImplIsAntiparallel() ) + { + // - RTL - re-mirror frame pos at this window + ImplReMirror( aFramePos ); + } + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + if ( !aRect.IsInside( aFramePos ) ) + return 0; + if ( mpWindowImpl->mbWinRegion ) + { + Point aTempPos = aFramePos; + aTempPos.X() -= mnOutOffX; + aTempPos.Y() -= mnOutOffY; + if ( !mpWindowImpl->maWinRegion.IsInside( aTempPos ) ) + return 0; + } + + USHORT nHitTest = WINDOW_HITTEST_INSIDE; + if ( mpWindowImpl->mbMouseTransparent ) + nHitTest |= WINDOW_HITTEST_TRANSPARENT; + return nHitTest; +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplIsRealParentPath( const Window* pWindow ) const +{ + pWindow = pWindow->GetParent(); + while ( pWindow ) + { + if ( pWindow == this ) + return TRUE; + pWindow = pWindow->GetParent(); + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplIsChild( const Window* pWindow, BOOL bSystemWindow ) const +{ + do + { + if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() ) + break; + + pWindow = pWindow->ImplGetParent(); + + if ( pWindow == this ) + return TRUE; + } + while ( pWindow ); + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplIsWindowOrChild( const Window* pWindow, BOOL bSystemWindow ) const +{ + if ( this == pWindow ) + return TRUE; + return ImplIsChild( pWindow, bSystemWindow ); +} + +// ----------------------------------------------------------------------- + +Window* Window::ImplGetSameParent( const Window* pWindow ) const +{ + if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow ) + return NULL; + else + { + if ( pWindow->ImplIsChild( this ) ) + return (Window*)pWindow; + else + { + Window* pTestWindow = (Window*)this; + while ( (pTestWindow == pWindow) || pTestWindow->ImplIsChild( pWindow ) ) + pTestWindow = pTestWindow->ImplGetParent(); + return pTestWindow; + } + } +} + +// ----------------------------------------------------------------------- + +int Window::ImplTestMousePointerSet() +{ + // Wenn Mouse gecaptured ist, dann soll MousePointer umgeschaltet werden + if ( IsMouseCaptured() ) + return TRUE; + + // Wenn sich Mouse ueber dem Fenster befindet, dann soll MousePointer + // umgeschaltet werden + Rectangle aClientRect( Point( 0, 0 ), GetOutputSizePixel() ); + if ( aClientRect.IsInside( GetPointerPosPixel() ) ) + return TRUE; + + return FALSE; +} + +// ----------------------------------------------------------------------- + +PointerStyle Window::ImplGetMousePointer() const +{ + PointerStyle ePointerStyle; + BOOL bWait = FALSE; + + if ( IsEnabled() && IsInputEnabled() && ! IsInModalMode() ) + ePointerStyle = GetPointer().GetStyle(); + else + ePointerStyle = POINTER_ARROW; + + const Window* pWindow = this; + do + { + // Wenn Pointer nicht sichtbar, dann wird suche abgebrochen, da + // dieser Status nicht ueberschrieben werden darf + if ( pWindow->mpWindowImpl->mbNoPtrVisible ) + return POINTER_NULL; + + if ( !bWait ) + { + if ( pWindow->mpWindowImpl->mnWaitCount ) + { + ePointerStyle = POINTER_WAIT; + bWait = TRUE; + } + else + { + if ( pWindow->mpWindowImpl->mbChildPtrOverwrite ) + ePointerStyle = pWindow->GetPointer().GetStyle(); + } + } + + if ( pWindow->ImplIsOverlapWindow() ) + break; + + pWindow = pWindow->ImplGetParent(); + } + while ( pWindow ); + + return ePointerStyle; +} + +// ----------------------------------------------------------------------- + +void Window::ImplResetReallyVisible() +{ + BOOL bBecameReallyInvisible = mpWindowImpl->mbReallyVisible; + + mbDevOutput = FALSE; + mpWindowImpl->mbReallyVisible = FALSE; + mpWindowImpl->mbReallyShown = FALSE; + + // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge. + // For this, the data member of the event must not be NULL. + // Previously, we did this in Window::Show, but there some events got lost in certain situations. + // #104887# - 2004-08-10 - fs@openoffice.org + if( bBecameReallyInvisible && ImplIsAccessibleCandidate() ) + ImplCallEventListeners( VCLEVENT_WINDOW_HIDE, this ); + // TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_HIDE. Normally, we should + // introduce another event which explicitly triggers the Accessibility implementations. + + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + pWindow->ImplResetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } + + pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + pWindow->ImplResetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplSetReallyVisible() +{ + // #i43594# it is possible that INITSHOW was never send, because the visibility state changed between + // ImplCallInitShow() and ImplSetReallyVisible() when called from Show() + // mbReallyShown is a useful indicator + if( !mpWindowImpl->mbReallyShown ) + ImplCallInitShow(); + + BOOL bBecameReallyVisible = !mpWindowImpl->mbReallyVisible; + + mbDevOutput = TRUE; + mpWindowImpl->mbReallyVisible = TRUE; + mpWindowImpl->mbReallyShown = TRUE; + + // the SHOW/HIDE events serve as indicators to send child creation/destroy events to the access bridge. + // For this, the data member of the event must not be NULL. + // Previously, we did this in Window::Show, but there some events got lost in certain situations. Now + // we're doing it when the visibility really changes + // #104887# - 2004-08-10 - fs@openoffice.org + if( bBecameReallyVisible && ImplIsAccessibleCandidate() ) + ImplCallEventListeners( VCLEVENT_WINDOW_SHOW, this ); + // TODO. It's kind of a hack that we're re-using the VCLEVENT_WINDOW_SHOW. Normally, we should + // introduce another event which explicitly triggers the Accessibility implementations. + + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplSetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } + + pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplSetReallyVisible(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallInitShow() +{ + mpWindowImpl->mbReallyShown = TRUE; + mpWindowImpl->mbInInitShow = TRUE; + StateChanged( STATE_CHANGE_INITSHOW ); + mpWindowImpl->mbInInitShow = FALSE; + + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplCallInitShow(); + pWindow = pWindow->mpWindowImpl->mpNext; + } + + pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbVisible ) + pWindow->ImplCallInitShow(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplAddDel( ImplDelData* pDel ) // TODO: make "const" when incompatiblity ok +{ + DBG_ASSERT( !pDel->mpWindow, "Window::ImplAddDel(): cannot add ImplDelData twice !" ); + if( !pDel->mpWindow ) + { + pDel->mpWindow = this; // #112873# store ref to this window, so pDel can remove itself + pDel->mpNext = mpWindowImpl->mpFirstDel; + mpWindowImpl->mpFirstDel = pDel; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplRemoveDel( ImplDelData* pDel ) // TODO: make "const" when incompatiblity ok +{ + pDel->mpWindow = NULL; // #112873# pDel is not associated with a Window anymore + if ( mpWindowImpl->mpFirstDel == pDel ) + mpWindowImpl->mpFirstDel = pDel->mpNext; + else + { + ImplDelData* pData = mpWindowImpl->mpFirstDel; + while ( pData->mpNext != pDel ) + pData = pData->mpNext; + pData->mpNext = pDel->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInitResolutionSettings() +{ + // AppFont-Aufloesung und DPI-Aufloesung neu berechnen + if ( mpWindowImpl->mbFrame ) + { + const StyleSettings& rStyleSettings = maSettings.GetStyleSettings(); + USHORT nScreenZoom = rStyleSettings.GetScreenZoom(); + mnDPIX = (mpWindowImpl->mpFrameData->mnDPIX*nScreenZoom)/100; + mnDPIY = (mpWindowImpl->mpFrameData->mnDPIY*nScreenZoom)/100; + SetPointFont( rStyleSettings.GetAppFont() ); + } + else if ( mpWindowImpl->mpParent ) + { + mnDPIX = mpWindowImpl->mpParent->mnDPIX; + mnDPIY = mpWindowImpl->mpParent->mnDPIY; + } + + // Vorberechnete Werte fuer logische Einheiten updaten und auch + // die entsprechenden Tools dazu + if ( IsMapMode() ) + { + MapMode aMapMode = GetMapMode(); + SetMapMode(); + SetMapMode( aMapMode ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplPointToLogic( Font& rFont ) const +{ + Size aSize = rFont.GetSize(); + USHORT nScreenFontZoom = maSettings.GetStyleSettings().GetScreenFontZoom(); + + if ( aSize.Width() ) + { + aSize.Width() *= mpWindowImpl->mpFrameData->mnDPIX; + aSize.Width() += 72/2; + aSize.Width() /= 72; + aSize.Width() *= nScreenFontZoom; + aSize.Width() /= 100; + } + aSize.Height() *= mpWindowImpl->mpFrameData->mnDPIY; + aSize.Height() += 72/2; + aSize.Height() /= 72; + aSize.Height() *= nScreenFontZoom; + aSize.Height() /= 100; + + if ( IsMapModeEnabled() ) + aSize = PixelToLogic( aSize ); + + rFont.SetSize( aSize ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplLogicToPoint( Font& rFont ) const +{ + Size aSize = rFont.GetSize(); + USHORT nScreenFontZoom = maSettings.GetStyleSettings().GetScreenFontZoom(); + + if ( IsMapModeEnabled() ) + aSize = LogicToPixel( aSize ); + + if ( aSize.Width() ) + { + aSize.Width() *= 100; + aSize.Width() /= nScreenFontZoom; + aSize.Width() *= 72; + aSize.Width() += mpWindowImpl->mpFrameData->mnDPIX/2; + aSize.Width() /= mpWindowImpl->mpFrameData->mnDPIX; + } + aSize.Height() *= 100; + aSize.Height() /= nScreenFontZoom; + aSize.Height() *= 72; + aSize.Height() += mpWindowImpl->mpFrameData->mnDPIY/2; + aSize.Height() /= mpWindowImpl->mpFrameData->mnDPIY; + + rFont.SetSize( aSize ); +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplSysObjClip( const Region* pOldRegion ) +{ + BOOL bUpdate = TRUE; + + if ( mpWindowImpl->mpSysObj ) + { + BOOL bVisibleState = mpWindowImpl->mbReallyVisible; + + if ( bVisibleState ) + { + Region* pWinChildClipRegion = ImplGetWinChildClipRegion(); + + if ( !pWinChildClipRegion->IsEmpty() ) + { + if ( pOldRegion ) + { + Region aNewRegion = *pWinChildClipRegion; + pWinChildClipRegion->Intersect( *pOldRegion ); + bUpdate = aNewRegion == *pWinChildClipRegion; + } + + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + Region aRegion = *pWinChildClipRegion; + Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aWinRectRegion( aWinRect ); + USHORT nClipFlags = mpWindowImpl->mpSysObj->GetClipRegionType(); + + if ( aRegion == aWinRectRegion ) + mpWindowImpl->mpSysObj->ResetClipRegion(); + else + { + if ( nClipFlags & SAL_OBJECT_CLIP_EXCLUDERECTS ) + { + aWinRectRegion.Exclude( aRegion ); + aRegion = aWinRectRegion; + } + if ( !(nClipFlags & SAL_OBJECT_CLIP_ABSOLUTE) ) + aRegion.Move( -mnOutOffX, -mnOutOffY ); + + // ClipRegion setzen/updaten + long nX; + long nY; + long nWidth; + long nHeight; + ULONG nRectCount; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + nRectCount = aRegion.GetRectCount(); + mpWindowImpl->mpSysObj->BeginSetClipRegion( nRectCount ); + bRegionRect = aRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + mpWindowImpl->mpSysObj->UnionClipRegion( nX, nY, nWidth, nHeight ); + bRegionRect = aRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + mpWindowImpl->mpSysObj->EndSetClipRegion(); + } + } + else + bVisibleState = FALSE; + } + + // Visible-Status updaten + mpWindowImpl->mpSysObj->Show( bVisibleState ); + } + + return bUpdate; +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateSysObjChildsClip() +{ + if ( mpWindowImpl->mpSysObj && mpWindowImpl->mbInitWinClipRegion ) + ImplSysObjClip( NULL ); + + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + pWindow->ImplUpdateSysObjChildsClip(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateSysObjOverlapsClip() +{ + ImplUpdateSysObjChildsClip(); + + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + pWindow->ImplUpdateSysObjOverlapsClip(); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateSysObjClip() +{ + if ( !ImplIsOverlapWindow() ) + { + ImplUpdateSysObjChildsClip(); + + // Schwestern muessen ihre ClipRegion auch neu berechnen + if ( mpWindowImpl->mbClipSiblings ) + { + Window* pWindow = mpWindowImpl->mpNext; + while ( pWindow ) + { + pWindow->ImplUpdateSysObjChildsClip(); + pWindow = pWindow->mpWindowImpl->mpNext; + } + } + } + else + mpWindowImpl->mpFrameWindow->ImplUpdateSysObjOverlapsClip(); +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplSetClipFlagChilds( BOOL bSysObjOnlySmaller ) +{ + BOOL bUpdate = TRUE; + if ( mpWindowImpl->mpSysObj ) + { + Region* pOldRegion = NULL; + if ( bSysObjOnlySmaller && !mpWindowImpl->mbInitWinClipRegion ) + pOldRegion = new Region( mpWindowImpl->maWinClipRegion ); + + mbInitClipRegion = TRUE; + mpWindowImpl->mbInitWinClipRegion = TRUE; + + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) ) + bUpdate = FALSE; + pWindow = pWindow->mpWindowImpl->mpNext; + } + + if ( !ImplSysObjClip( pOldRegion ) ) + { + mbInitClipRegion = TRUE; + mpWindowImpl->mbInitWinClipRegion = TRUE; + bUpdate = FALSE; + } + + if ( pOldRegion ) + delete pOldRegion; + } + else + { + mbInitClipRegion = TRUE; + mpWindowImpl->mbInitWinClipRegion = TRUE; + + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) ) + bUpdate = FALSE; + pWindow = pWindow->mpWindowImpl->mpNext; + } + } + return bUpdate; +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplSetClipFlagOverlapWindows( BOOL bSysObjOnlySmaller ) +{ + BOOL bUpdate = ImplSetClipFlagChilds( bSysObjOnlySmaller ); + + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( !pWindow->ImplSetClipFlagOverlapWindows( bSysObjOnlySmaller ) ) + bUpdate = FALSE; + pWindow = pWindow->mpWindowImpl->mpNext; + } + + return bUpdate; +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplSetClipFlag( BOOL bSysObjOnlySmaller ) +{ + if ( !ImplIsOverlapWindow() ) + { + BOOL bUpdate = ImplSetClipFlagChilds( bSysObjOnlySmaller ); + + Window* pParent = ImplGetParent(); + if ( pParent && + ((pParent->GetStyle() & WB_CLIPCHILDREN) || (mpWindowImpl->mnParentClipMode & PARENTCLIPMODE_CLIP)) ) + { + pParent->mbInitClipRegion = TRUE; + pParent->mpWindowImpl->mbInitChildRegion = TRUE; + } + + // Schwestern muessen ihre ClipRegion auch neu berechnen + if ( mpWindowImpl->mbClipSiblings ) + { + Window* pWindow = mpWindowImpl->mpNext; + while ( pWindow ) + { + if ( !pWindow->ImplSetClipFlagChilds( bSysObjOnlySmaller ) ) + bUpdate = FALSE; + pWindow = pWindow->mpWindowImpl->mpNext; + } + } + + return bUpdate; + } + else + return mpWindowImpl->mpFrameWindow->ImplSetClipFlagOverlapWindows( bSysObjOnlySmaller ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplIntersectWindowClipRegion( Region& rRegion ) +{ + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + + rRegion.Intersect( mpWindowImpl->maWinClipRegion ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplIntersectWindowRegion( Region& rRegion ) +{ + rRegion.Intersect( Rectangle( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ) ); + if ( mpWindowImpl->mbWinRegion ) + rRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplExcludeWindowRegion( Region& rRegion ) +{ + if ( mpWindowImpl->mbWinRegion ) + { + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + rRegion.Exclude( aRegion ); + } + else + { + Point aPoint( mnOutOffX, mnOutOffY ); + rRegion.Exclude( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplExcludeOverlapWindows( Region& rRegion ) +{ + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + { + pWindow->ImplExcludeWindowRegion( rRegion ); + pWindow->ImplExcludeOverlapWindows( rRegion ); + } + + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplExcludeOverlapWindows2( Region& rRegion ) +{ + if ( mpWindowImpl->mbReallyVisible ) + ImplExcludeWindowRegion( rRegion ); + + ImplExcludeOverlapWindows( rRegion ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplClipBoundaries( Region& rRegion, BOOL bThis, BOOL bOverlaps ) +{ + if ( bThis ) + ImplIntersectWindowClipRegion( rRegion ); + else if ( ImplIsOverlapWindow() ) + { + // Evt. noch am Frame clippen + if ( !mpWindowImpl->mbFrame ) + rRegion.Intersect( Rectangle( Point( 0, 0 ), Size( mpWindowImpl->mpFrameWindow->mnOutWidth, mpWindowImpl->mpFrameWindow->mnOutHeight ) ) ); + + if ( bOverlaps && !rRegion.IsEmpty() ) + { + // Clip Overlap Siblings + Window* pStartOverlapWindow = this; + while ( !pStartOverlapWindow->mpWindowImpl->mbFrame ) + { + Window* pOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow && (pOverlapWindow != pStartOverlapWindow) ) + { + pOverlapWindow->ImplExcludeOverlapWindows2( rRegion ); + pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + } + pStartOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow; + } + + // Clip Child Overlap Windows + ImplExcludeOverlapWindows( rRegion ); + } + } + else + ImplGetParent()->ImplIntersectWindowClipRegion( rRegion ); +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplClipChilds( Region& rRegion ) +{ + BOOL bOtherClip = FALSE; + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + { + // ParentClipMode-Flags auswerten + USHORT nClipMode = pWindow->GetParentClipMode(); + if ( !(nClipMode & PARENTCLIPMODE_NOCLIP) && + ((nClipMode & PARENTCLIPMODE_CLIP) || (GetStyle() & WB_CLIPCHILDREN)) ) + pWindow->ImplExcludeWindowRegion( rRegion ); + else + bOtherClip = TRUE; + } + + pWindow = pWindow->mpWindowImpl->mpNext; + } + + return bOtherClip; +} + +// ----------------------------------------------------------------------- + +void Window::ImplClipAllChilds( Region& rRegion ) +{ + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + pWindow->ImplExcludeWindowRegion( rRegion ); + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplClipSiblings( Region& rRegion ) +{ + Window* pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow == this ) + break; + + if ( pWindow->mpWindowImpl->mbReallyVisible ) + pWindow->ImplExcludeWindowRegion( rRegion ); + + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInitWinClipRegion() +{ + // Build Window Region + mpWindowImpl->maWinClipRegion = Rectangle( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ); + if ( mpWindowImpl->mbWinRegion ) + mpWindowImpl->maWinClipRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + + // ClipSiblings + if ( mpWindowImpl->mbClipSiblings && !ImplIsOverlapWindow() ) + ImplClipSiblings( mpWindowImpl->maWinClipRegion ); + + // Clip Parent Boundaries + ImplClipBoundaries( mpWindowImpl->maWinClipRegion, FALSE, TRUE ); + + // Clip Children + if ( (GetStyle() & WB_CLIPCHILDREN) || mpWindowImpl->mbClipChildren ) + mpWindowImpl->mbInitChildRegion = TRUE; + + mpWindowImpl->mbInitWinClipRegion = FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::ImplInitWinChildClipRegion() +{ + if ( !mpWindowImpl->mpFirstChild ) + { + if ( mpWindowImpl->mpChildClipRegion ) + { + delete mpWindowImpl->mpChildClipRegion; + mpWindowImpl->mpChildClipRegion = NULL; + } + } + else + { + if ( !mpWindowImpl->mpChildClipRegion ) + mpWindowImpl->mpChildClipRegion = new Region( mpWindowImpl->maWinClipRegion ); + else + *mpWindowImpl->mpChildClipRegion = mpWindowImpl->maWinClipRegion; + + ImplClipChilds( *mpWindowImpl->mpChildClipRegion ); + } + + mpWindowImpl->mbInitChildRegion = FALSE; +} + +// ----------------------------------------------------------------------- + +Region* Window::ImplGetWinChildClipRegion() +{ + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + if ( mpWindowImpl->mbInitChildRegion ) + ImplInitWinChildClipRegion(); + if ( mpWindowImpl->mpChildClipRegion ) + return mpWindowImpl->mpChildClipRegion; + else + return &mpWindowImpl->maWinClipRegion; +} + +// ----------------------------------------------------------------------- + +void Window::ImplIntersectAndUnionOverlapWindows( const Region& rInterRegion, Region& rRegion ) +{ + Window* pWindow = mpWindowImpl->mpFirstOverlap; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + { + Region aTempRegion( rInterRegion ); + pWindow->ImplIntersectWindowRegion( aTempRegion ); + rRegion.Union( aTempRegion ); + pWindow->ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion ); + } + + pWindow = pWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplIntersectAndUnionOverlapWindows2( const Region& rInterRegion, Region& rRegion ) +{ + if ( mpWindowImpl->mbReallyVisible ) + { + Region aTempRegion( rInterRegion ); + ImplIntersectWindowRegion( aTempRegion ); + rRegion.Union( aTempRegion ); + } + + ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCalcOverlapRegionOverlaps( const Region& rInterRegion, Region& rRegion ) +{ + // Clip Overlap Siblings + Window* pStartOverlapWindow; + if ( !ImplIsOverlapWindow() ) + pStartOverlapWindow = mpWindowImpl->mpOverlapWindow; + else + pStartOverlapWindow = this; + while ( !pStartOverlapWindow->mpWindowImpl->mbFrame ) + { + Window* pOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow && (pOverlapWindow != pStartOverlapWindow) ) + { + pOverlapWindow->ImplIntersectAndUnionOverlapWindows2( rInterRegion, rRegion ); + pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + } + pStartOverlapWindow = pStartOverlapWindow->mpWindowImpl->mpOverlapWindow; + } + + // Clip Child Overlap Windows + if ( !ImplIsOverlapWindow() ) + mpWindowImpl->mpOverlapWindow->ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion ); + else + ImplIntersectAndUnionOverlapWindows( rInterRegion, rRegion ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCalcOverlapRegion( const Rectangle& rSourceRect, Region& rRegion, + BOOL bChilds, BOOL bParent, BOOL bSiblings ) +{ + Region aRegion( rSourceRect ); + if ( mpWindowImpl->mbWinRegion ) + rRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + Region aTempRegion; + Window* pWindow; + + ImplCalcOverlapRegionOverlaps( aRegion, rRegion ); + + // Parent-Boundaries + if ( bParent ) + { + pWindow = this; + if ( !ImplIsOverlapWindow() ) + { + pWindow = ImplGetParent(); + do + { + aTempRegion = aRegion; + pWindow->ImplExcludeWindowRegion( aTempRegion ); + rRegion.Union( aTempRegion ); + if ( pWindow->ImplIsOverlapWindow() ) + break; + pWindow = pWindow->ImplGetParent(); + } + while ( pWindow ); + } + if ( !pWindow->mpWindowImpl->mbFrame ) + { + aTempRegion = aRegion; + aTempRegion.Exclude( Rectangle( Point( 0, 0 ), Size( mpWindowImpl->mpFrameWindow->mnOutWidth, mpWindowImpl->mpFrameWindow->mnOutHeight ) ) ); + rRegion.Union( aTempRegion ); + } + } + + // Siblings + if ( bSiblings && !ImplIsOverlapWindow() ) + { + pWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild; + do + { + if ( pWindow->mpWindowImpl->mbReallyVisible && (pWindow != this) ) + { + aTempRegion = aRegion; + pWindow->ImplIntersectWindowRegion( aTempRegion ); + rRegion.Union( aTempRegion ); + } + pWindow = pWindow->mpWindowImpl->mpNext; + } + while ( pWindow ); + } + + // Childs + if ( bChilds ) + { + pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + if ( pWindow->mpWindowImpl->mbReallyVisible ) + { + aTempRegion = aRegion; + pWindow->ImplIntersectWindowRegion( aTempRegion ); + rRegion.Union( aTempRegion ); + } + pWindow = pWindow->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallPaint( const Region* pRegion, USHORT nPaintFlags ) +{ + // call PrePaint. PrePaint may add to the invalidate region as well as + // other parameters used below. + PrePaint(); + + mpWindowImpl->mbPaintFrame = FALSE; + + if ( nPaintFlags & IMPL_PAINT_PAINTALLCHILDS ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALLCHILDS | (nPaintFlags & IMPL_PAINT_PAINTALL); + if ( nPaintFlags & IMPL_PAINT_PAINTCHILDS ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDS; + if ( nPaintFlags & IMPL_PAINT_ERASE ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE; + if ( nPaintFlags & IMPL_PAINT_CHECKRTL ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL; + if ( !mpWindowImpl->mpFirstChild ) + mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALLCHILDS; + + if ( mpWindowImpl->mbPaintDisabled ) + { + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + Invalidate( INVALIDATE_NOCHILDREN | INVALIDATE_NOERASE | INVALIDATE_NOTRANSPARENT | INVALIDATE_NOCLIPCHILDREN ); + else if ( pRegion ) + Invalidate( *pRegion, INVALIDATE_NOCHILDREN | INVALIDATE_NOERASE | INVALIDATE_NOTRANSPARENT | INVALIDATE_NOCLIPCHILDREN ); + return; + } + + nPaintFlags = mpWindowImpl->mnPaintFlags & ~(IMPL_PAINT_PAINT); + + Region* pChildRegion = NULL; + Rectangle aSelectionRect; + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT ) + { + Region* pWinChildClipRegion = ImplGetWinChildClipRegion(); + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + mpWindowImpl->maInvalidateRegion = *pWinChildClipRegion; + else + { + if ( pRegion ) + mpWindowImpl->maInvalidateRegion.Union( *pRegion ); + + if( mpWindowImpl->mpWinData && mpWindowImpl->mbTrackVisible ) + /* #98602# need to repaint all children within the + * tracking rectangle, so the following invert + * operation takes places without traces of the previous + * one. + */ + mpWindowImpl->maInvalidateRegion.Union( *mpWindowImpl->mpWinData->mpTrackRect ); + + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS ) + pChildRegion = new Region( mpWindowImpl->maInvalidateRegion ); + mpWindowImpl->maInvalidateRegion.Intersect( *pWinChildClipRegion ); + } + mpWindowImpl->mnPaintFlags = 0; + if ( !mpWindowImpl->maInvalidateRegion.IsEmpty() ) + { + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplHide(); + + mbInitClipRegion = TRUE; + mpWindowImpl->mbInPaint = TRUE; + + // Paint-Region zuruecksetzen + Region aPaintRegion( mpWindowImpl->maInvalidateRegion ); + Rectangle aPaintRect = aPaintRegion.GetBoundRect(); + + // - RTL - re-mirror paint rect and region at this window + if( ImplIsAntiparallel() ) + { + ImplReMirror( aPaintRect ); + ImplReMirror( aPaintRegion ); + } + aPaintRect = ImplDevicePixelToLogic( aPaintRect); + mpWindowImpl->mpPaintRegion = &aPaintRegion; + mpWindowImpl->maInvalidateRegion.SetEmpty(); + + if ( (nPaintFlags & IMPL_PAINT_ERASE) && IsBackground() ) + { + if ( IsClipRegion() ) + { + Region aOldRegion = GetClipRegion(); + SetClipRegion(); + Erase(); + SetClipRegion( aOldRegion ); + } + else + Erase(); + } + + // #98943# trigger drawing of toolbox selection after all childern are painted + if( mpWindowImpl->mbDrawSelectionBackground ) + aSelectionRect = aPaintRect; + + Paint( aPaintRect ); + + if ( mpWindowImpl->mpWinData ) + { + if ( mpWindowImpl->mbFocusVisible ) + ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) ); + } + mpWindowImpl->mbInPaint = FALSE; + mbInitClipRegion = TRUE; + mpWindowImpl->mpPaintRegion = NULL; + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplShow( FALSE ); + } + } + else + mpWindowImpl->mnPaintFlags = 0; + + if ( nPaintFlags & (IMPL_PAINT_PAINTALLCHILDS | IMPL_PAINT_PAINTCHILDS) ) + { + // die Childfenster ausgeben + Window* pTempWindow = mpWindowImpl->mpFirstChild; + while ( pTempWindow ) + { + if ( pTempWindow->mpWindowImpl->mbVisible ) + pTempWindow->ImplCallPaint( pChildRegion, nPaintFlags ); + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } + } + + if ( mpWindowImpl->mpWinData && mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) ) + /* #98602# need to invert the tracking rect AFTER + * the children have painted + */ + InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags ); + + // #98943# draw toolbox selection + if( !aSelectionRect.IsEmpty() ) + DrawSelectionBackground( aSelectionRect, 3, FALSE, TRUE, FALSE ); + + if ( pChildRegion ) + delete pChildRegion; +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallOverlapPaint() +{ + // Zuerst geben wir die ueberlappenden Fenster aus + Window* pTempWindow = mpWindowImpl->mpFirstOverlap; + while ( pTempWindow ) + { + if ( pTempWindow->mpWindowImpl->mbReallyVisible ) + pTempWindow->ImplCallOverlapPaint(); + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } + + // und dann erst uns selber + if ( mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) ) + { + // - RTL - notify ImplCallPaint to check for re-mirroring (CHECKRTL) + // because we were called from the Sal layer + ImplCallPaint( NULL, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplPostPaint() +{ + if ( !mpWindowImpl->mpFrameData->maPaintTimer.IsActive() ) + mpWindowImpl->mpFrameData->maPaintTimer.Start(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplHandlePaintHdl, void*, EMPTYARG ) +{ + // save paint events until resizing is done + if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData->maResizeTimer.IsActive() ) + mpWindowImpl->mpFrameData->maPaintTimer.Start(); + else if ( mpWindowImpl->mbReallyVisible ) + ImplCallOverlapPaint(); + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplHandleResizeTimerHdl, void*, EMPTYARG ) +{ + if( mpWindowImpl->mbReallyVisible ) + { + ImplCallResize(); + if( mpWindowImpl->mpFrameData->maPaintTimer.IsActive() ) + { + mpWindowImpl->mpFrameData->maPaintTimer.Stop(); + mpWindowImpl->mpFrameData->maPaintTimer.GetTimeoutHdl().Call( NULL ); + } + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvalidateFrameRegion( const Region* pRegion, USHORT nFlags ) +{ + // PAINTCHILDS bei allen Parent-Fenster bis zum ersten OverlapWindow + // setzen + if ( !ImplIsOverlapWindow() ) + { + Window* pTempWindow = this; + USHORT nTranspPaint = IsPaintTransparent() ? IMPL_PAINT_PAINT : 0; + do + { + pTempWindow = pTempWindow->ImplGetParent(); + if ( pTempWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDS ) + break; + pTempWindow->mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTCHILDS | nTranspPaint; + if( ! pTempWindow->IsPaintTransparent() ) + nTranspPaint = 0; + } + while ( !pTempWindow->ImplIsOverlapWindow() ); + } + + // Paint-Flags setzen + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINT; + if ( nFlags & INVALIDATE_CHILDREN ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALLCHILDS; + if ( !(nFlags & INVALIDATE_NOERASE) ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_ERASE; + if ( !pRegion ) + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_PAINTALL; + + // Wenn nicht alles neu ausgegeben werden muss, dann die Region + // dazupacken + if ( !(mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL) ) + mpWindowImpl->maInvalidateRegion.Union( *pRegion ); + + // Handle transparent windows correctly: invalidate must be done on the first opaque parent + if( ((IsPaintTransparent() && !(nFlags & INVALIDATE_NOTRANSPARENT)) || (nFlags & INVALIDATE_TRANSPARENT) ) + && ImplGetParent() ) + { + Window *pParent = ImplGetParent(); + while( pParent && pParent->IsPaintTransparent() ) + pParent = pParent->ImplGetParent(); + if( pParent ) + { + Region *pChildRegion; + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + // invalidate the whole child window region in the parent + pChildRegion = ImplGetWinChildClipRegion(); + else + // invalidate the same region in the parent that has to be repainted in the child + pChildRegion = &mpWindowImpl->maInvalidateRegion; + + nFlags |= INVALIDATE_CHILDREN; // paint should also be done on all children + nFlags &= ~INVALIDATE_NOERASE; // parent should paint and erase to create proper background + pParent->ImplInvalidateFrameRegion( pChildRegion, nFlags ); + } + } + ImplPostPaint(); +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvalidateOverlapFrameRegion( const Region& rRegion ) +{ + Region aRegion = rRegion; + + ImplClipBoundaries( aRegion, TRUE, TRUE ); + if ( !aRegion.IsEmpty() ) + ImplInvalidateFrameRegion( &aRegion, INVALIDATE_CHILDREN ); + + // Dann invalidieren wir die ueberlappenden Fenster + Window* pTempWindow = mpWindowImpl->mpFirstOverlap; + while ( pTempWindow ) + { + if ( pTempWindow->IsVisible() ) + pTempWindow->ImplInvalidateOverlapFrameRegion( rRegion ); + + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvalidateParentFrameRegion( Region& rRegion ) +{ + if ( mpWindowImpl->mbOverlapWin ) + mpWindowImpl->mpFrameWindow->ImplInvalidateOverlapFrameRegion( rRegion ); + else + { + if( ImplGetParent() ) + ImplGetParent()->ImplInvalidateFrameRegion( &rRegion, INVALIDATE_CHILDREN ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvalidate( const Region* pRegion, USHORT nFlags ) +{ + + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + // Feststellen, was neu ausgegeben werden muss + BOOL bInvalidateAll = !pRegion; + + // Transparent-Invalidate beruecksichtigen + Window* pOpaqueWindow = this; + if ( (mpWindowImpl->mbPaintTransparent && !(nFlags & INVALIDATE_NOTRANSPARENT)) || (nFlags & INVALIDATE_TRANSPARENT) ) + { + Window* pTempWindow = pOpaqueWindow->ImplGetParent(); + while ( pTempWindow ) + { + if ( !pTempWindow->IsPaintTransparent() ) + { + pOpaqueWindow = pTempWindow; + nFlags |= INVALIDATE_CHILDREN; + bInvalidateAll = FALSE; + break; + } + + if ( pTempWindow->ImplIsOverlapWindow() ) + break; + + pTempWindow = pTempWindow->ImplGetParent(); + } + } + + // Region zusammenbauen + USHORT nOrgFlags = nFlags; + if ( !(nFlags & (INVALIDATE_CHILDREN | INVALIDATE_NOCHILDREN)) ) + { + if ( GetStyle() & WB_CLIPCHILDREN ) + nFlags |= INVALIDATE_NOCHILDREN; + else + nFlags |= INVALIDATE_CHILDREN; + } + if ( (nFlags & INVALIDATE_NOCHILDREN) && mpWindowImpl->mpFirstChild ) + bInvalidateAll = FALSE; + if ( bInvalidateAll ) + ImplInvalidateFrameRegion( NULL, nFlags ); + else + { + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aRegion( aRect ); + if ( pRegion ) + { + // --- RTL --- remirror region before intersecting it + if ( ImplIsAntiparallel() ) + { + Region aRgn( *pRegion ); + ImplReMirror( aRgn ); + aRegion.Intersect( aRgn ); + } + else + aRegion.Intersect( *pRegion ); + } + ImplClipBoundaries( aRegion, TRUE, TRUE ); + if ( nFlags & INVALIDATE_NOCHILDREN ) + { + nFlags &= ~INVALIDATE_CHILDREN; + if ( !(nFlags & INVALIDATE_NOCLIPCHILDREN) ) + { + if ( nOrgFlags & INVALIDATE_NOCHILDREN ) + ImplClipAllChilds( aRegion ); + else + { + if ( ImplClipChilds( aRegion ) ) + nFlags |= INVALIDATE_CHILDREN; + } + } + } + if ( !aRegion.IsEmpty() ) + ImplInvalidateFrameRegion( &aRegion, nFlags ); // transparency is handled here, pOpaqueWindow not required + } + + if ( nFlags & INVALIDATE_UPDATE ) + pOpaqueWindow->Update(); // start painting at the opaque parent +} + +// ----------------------------------------------------------------------- + +void Window::ImplMoveInvalidateRegion( const Rectangle& rRect, + long nHorzScroll, long nVertScroll, + BOOL bChilds ) +{ + if ( (mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTALL)) == IMPL_PAINT_PAINT ) + { + Region aTempRegion = mpWindowImpl->maInvalidateRegion; + aTempRegion.Intersect( rRect ); + aTempRegion.Move( nHorzScroll, nVertScroll ); + mpWindowImpl->maInvalidateRegion.Union( aTempRegion ); + } + + if ( bChilds && (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTCHILDS) ) + { + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + pWindow->ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, TRUE ); + pWindow = pWindow->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplMoveAllInvalidateRegions( const Rectangle& rRect, + long nHorzScroll, long nVertScroll, + BOOL bChilds ) +{ + // Paint-Region auch verschieben, wenn noch Paints anstehen + ImplMoveInvalidateRegion( rRect, nHorzScroll, nVertScroll, bChilds ); + // Paint-Region muss bei uns verschoben gesetzt werden, die durch + // die Parents gezeichnet werden + if ( !ImplIsOverlapWindow() ) + { + Region aPaintAllRegion; + Window* pPaintAllWindow = this; + do + { + pPaintAllWindow = pPaintAllWindow->ImplGetParent(); + if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS ) + { + if ( pPaintAllWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + { + aPaintAllRegion.SetEmpty(); + break; + } + else + aPaintAllRegion.Union( pPaintAllWindow->mpWindowImpl->maInvalidateRegion ); + } + } + while ( !pPaintAllWindow->ImplIsOverlapWindow() ); + if ( !aPaintAllRegion.IsEmpty() ) + { + aPaintAllRegion.Move( nHorzScroll, nVertScroll ); + USHORT nPaintFlags = 0; + if ( bChilds ) + mpWindowImpl->mnPaintFlags |= INVALIDATE_CHILDREN; + ImplInvalidateFrameRegion( &aPaintAllRegion, nPaintFlags ); + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplValidateFrameRegion( const Region* pRegion, USHORT nFlags ) +{ + if ( !pRegion ) + mpWindowImpl->maInvalidateRegion.SetEmpty(); + else + { + // Wenn alle Childfenster neu ausgegeben werden muessen, + // dann invalidieren wir diese vorher + if ( (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS) && mpWindowImpl->mpFirstChild ) + { + Region aChildRegion = mpWindowImpl->maInvalidateRegion; + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + { + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + aChildRegion = aRect; + } + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->Invalidate( aChildRegion, INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT ); + pChild = pChild->mpWindowImpl->mpNext; + } + } + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALL ) + { + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + mpWindowImpl->maInvalidateRegion = aRect; + } + mpWindowImpl->maInvalidateRegion.Exclude( *pRegion ); + } + mpWindowImpl->mnPaintFlags &= ~IMPL_PAINT_PAINTALL; + + if ( nFlags & VALIDATE_CHILDREN ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplValidateFrameRegion( pRegion, nFlags ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplValidate( const Region* pRegion, USHORT nFlags ) +{ + // Region zusammenbauen + BOOL bValidateAll = !pRegion; + USHORT nOrgFlags = nFlags; + if ( !(nFlags & (VALIDATE_CHILDREN | VALIDATE_NOCHILDREN)) ) + { + if ( GetStyle() & WB_CLIPCHILDREN ) + nFlags |= VALIDATE_NOCHILDREN; + else + nFlags |= VALIDATE_CHILDREN; + } + if ( (nFlags & VALIDATE_NOCHILDREN) && mpWindowImpl->mpFirstChild ) + bValidateAll = FALSE; + if ( bValidateAll ) + ImplValidateFrameRegion( NULL, nFlags ); + else + { + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aRegion( aRect ); + if ( pRegion ) + aRegion.Intersect( *pRegion ); + ImplClipBoundaries( aRegion, TRUE, TRUE ); + if ( nFlags & VALIDATE_NOCHILDREN ) + { + nFlags &= ~VALIDATE_CHILDREN; + if ( nOrgFlags & VALIDATE_NOCHILDREN ) + ImplClipAllChilds( aRegion ); + else + { + if ( ImplClipChilds( aRegion ) ) + nFlags |= VALIDATE_CHILDREN; + } + } + if ( !aRegion.IsEmpty() ) + ImplValidateFrameRegion( &aRegion, nFlags ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplScroll( const Rectangle& rRect, + long nHorzScroll, long nVertScroll, USHORT nFlags ) +{ + if ( !IsDeviceOutputNecessary() ) + return; + + nHorzScroll = ImplLogicWidthToDevicePixel( nHorzScroll ); + nVertScroll = ImplLogicHeightToDevicePixel( nVertScroll ); + + if ( !nHorzScroll && !nVertScroll ) + return; + + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplHide(); + + USHORT nOrgFlags = nFlags; + if ( !(nFlags & (SCROLL_CHILDREN | SCROLL_NOCHILDREN)) ) + { + if ( GetStyle() & WB_CLIPCHILDREN ) + nFlags |= SCROLL_NOCHILDREN; + else + nFlags |= SCROLL_CHILDREN; + } + + Region aInvalidateRegion; + BOOL bScrollChilds = (nFlags & SCROLL_CHILDREN) != 0; + BOOL bErase = (nFlags & SCROLL_NOERASE) == 0; + + if ( !mpWindowImpl->mpFirstChild ) + bScrollChilds = FALSE; + + // --- RTL --- check if this window requires special action + BOOL bReMirror = ( ImplIsAntiparallel() ); + + Rectangle aRectMirror( rRect ); + if( bReMirror ) + { + // --- RTL --- make sure the invalidate region of this window is + // computed in the same coordinate space as the one from the overlap windows + ImplReMirror( aRectMirror ); + } + + // Paint-Bereiche anpassen + ImplMoveAllInvalidateRegions( aRectMirror, nHorzScroll, nVertScroll, bScrollChilds ); + + if ( !(nFlags & SCROLL_NOINVALIDATE) ) + { + ImplCalcOverlapRegion( aRectMirror, aInvalidateRegion, !bScrollChilds, TRUE, FALSE ); + + // --- RTL --- + // if the scrolling on the device is performed in the opposite direction + // then move the overlaps in that direction to compute the invalidate region + // on the correct side, i.e., revert nHorzScroll + + if ( !aInvalidateRegion.IsEmpty() ) + { + aInvalidateRegion.Move( bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll ); + bErase = TRUE; + } + if ( !(nFlags & SCROLL_NOWINDOWINVALIDATE) ) + { + Rectangle aDestRect( aRectMirror ); + aDestRect.Move( bReMirror ? -nHorzScroll : nHorzScroll, nVertScroll ); + Region aWinInvalidateRegion( aRectMirror ); + aWinInvalidateRegion.Exclude( aDestRect ); + + aInvalidateRegion.Union( aWinInvalidateRegion ); + } + } + + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) ); + if ( nFlags & SCROLL_CLIP ) + aRegion.Intersect( rRect ); + if ( mpWindowImpl->mbWinRegion ) + aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + + aRegion.Exclude( aInvalidateRegion ); + + ImplClipBoundaries( aRegion, FALSE, TRUE ); + if ( !bScrollChilds ) + { + if ( nOrgFlags & SCROLL_NOCHILDREN ) + ImplClipAllChilds( aRegion ); + else + ImplClipChilds( aRegion ); + } + if ( mbClipRegion && (nFlags & SCROLL_USECLIPREGION) ) + aRegion.Intersect( maRegion ); + if ( !aRegion.IsEmpty() ) + { + if ( mpWindowImpl->mpWinData ) + { + if ( mpWindowImpl->mbFocusVisible ) + ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) ); + if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) ) + InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags ); + } + + SalGraphics* pGraphics = ImplGetFrameGraphics(); + if ( pGraphics ) + { + if( bReMirror ) + { + // --- RTL --- frame coordinates require re-mirroring + ImplReMirror( aRegion ); + } + + ImplSelectClipRegion( aRegion, pGraphics ); + pGraphics->CopyArea( rRect.Left()+nHorzScroll, rRect.Top()+nVertScroll, + rRect.Left(), rRect.Top(), + rRect.GetWidth(), rRect.GetHeight(), + SAL_COPYAREA_WINDOWINVALIDATE, this ); + } + + if ( mpWindowImpl->mpWinData ) + { + if ( mpWindowImpl->mbFocusVisible ) + ImplInvertFocus( *(mpWindowImpl->mpWinData->mpFocusRect) ); + if ( mpWindowImpl->mbTrackVisible && (mpWindowImpl->mpWinData->mnTrackFlags & SHOWTRACK_WINDOW) ) + InvertTracking( *(mpWindowImpl->mpWinData->mpTrackRect), mpWindowImpl->mpWinData->mnTrackFlags ); + } + } + + if ( !aInvalidateRegion.IsEmpty() ) + { + // --- RTL --- the invalidate region for this windows is already computed in frame coordinates + // so it has to be re-mirrored before calling the Paint-handler + mpWindowImpl->mnPaintFlags |= IMPL_PAINT_CHECKRTL; + + USHORT nPaintFlags = INVALIDATE_CHILDREN; + if ( !bErase ) + nPaintFlags |= INVALIDATE_NOERASE; + if ( !bScrollChilds ) + { + if ( nOrgFlags & SCROLL_NOCHILDREN ) + ImplClipAllChilds( aInvalidateRegion ); + else + ImplClipChilds( aInvalidateRegion ); + } + ImplInvalidateFrameRegion( &aInvalidateRegion, nPaintFlags ); + } + + if ( bScrollChilds ) + { + Window* pWindow = mpWindowImpl->mpFirstChild; + while ( pWindow ) + { + Point aPos = pWindow->GetPosPixel(); + aPos += Point( nHorzScroll, nVertScroll ); + pWindow->SetPosPixel( aPos ); + + pWindow = pWindow->mpWindowImpl->mpNext; + } + } + + if ( nFlags & SCROLL_UPDATE ) + Update(); + + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplShow( FALSE ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateAll( BOOL bOverlapWindows ) +{ + if ( !mpWindowImpl->mbReallyVisible ) + return; + + BOOL bFlush = FALSE; + if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame ) + { + Point aPoint( 0, 0 ); + Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) ); + ImplInvalidateOverlapFrameRegion( aRegion ); + if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ) + bFlush = TRUE; + } + + // Ein Update wirkt immer auf das OverlapWindow, damit bei spaeteren + // Paints nicht zuviel gemalt wird, wenn dort ALLCHILDREN usw. gesetzt + // ist + Window* pWindow = ImplGetFirstOverlapWindow(); + if ( bOverlapWindows ) + pWindow->ImplCallOverlapPaint(); + else + { + if ( pWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) ) + pWindow->ImplCallPaint( NULL, pWindow->mpWindowImpl->mnPaintFlags ); + } + + if ( bFlush ) + Flush(); +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateWindowPtr( Window* pWindow ) +{ + if ( mpWindowImpl->mpFrameWindow != pWindow->mpWindowImpl->mpFrameWindow ) + { + // Graphic freigeben + ImplReleaseGraphics(); + } + + mpWindowImpl->mpFrameData = pWindow->mpWindowImpl->mpFrameData; + mpWindowImpl->mpFrame = pWindow->mpWindowImpl->mpFrame; + mpWindowImpl->mpFrameWindow = pWindow->mpWindowImpl->mpFrameWindow; + if ( pWindow->ImplIsOverlapWindow() ) + mpWindowImpl->mpOverlapWindow = pWindow; + else + mpWindowImpl->mpOverlapWindow = pWindow->mpWindowImpl->mpOverlapWindow; + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplUpdateWindowPtr( pWindow ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateWindowPtr() +{ + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplUpdateWindowPtr( this ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateOverlapWindowPtr( BOOL bNewFrame ) +{ + BOOL bVisible = IsVisible(); + Show( FALSE ); + ImplRemoveWindow( bNewFrame ); + Window* pRealParent = mpWindowImpl->mpRealParent; + ImplInsertWindow( ImplGetParent() ); + mpWindowImpl->mpRealParent = pRealParent; + ImplUpdateWindowPtr(); + if ( ImplUpdatePos() ) + ImplUpdateSysObjPos(); + + if ( bNewFrame ) + { + Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow ) + { + Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame ); + pOverlapWindow = pNextOverlapWindow; + } + } + + if ( bVisible ) + Show( TRUE ); +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplUpdatePos() +{ + BOOL bSysChild = FALSE; + + if ( ImplIsOverlapWindow() ) + { + mnOutOffX = mpWindowImpl->mnX; + mnOutOffY = mpWindowImpl->mnY; + } + else + { + Window* pParent = ImplGetParent(); + + mnOutOffX = mpWindowImpl->mnX + pParent->mnOutOffX; + mnOutOffY = mpWindowImpl->mnY + pParent->mnOutOffY; + } + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + if ( pChild->ImplUpdatePos() ) + bSysChild = TRUE; + pChild = pChild->mpWindowImpl->mpNext; + } + + if ( mpWindowImpl->mpSysObj ) + bSysChild = TRUE; + + return bSysChild; +} + +// ----------------------------------------------------------------------- + +void Window::ImplUpdateSysObjPos() +{ + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->SetPosSize( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ); + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->ImplUpdateSysObjPos(); + pChild = pChild->mpWindowImpl->mpNext; + } +} +// ----------------------------------------------------------------------- + +void Window::ImplPosSizeWindow( long nX, long nY, + long nWidth, long nHeight, USHORT nFlags ) +{ + BOOL bNewPos = FALSE; + BOOL bNewSize = FALSE; + BOOL bNewWidth = FALSE; + BOOL bCopyBits = FALSE; + long nOldOutOffX = mnOutOffX; + long nOldOutOffY = mnOutOffY; + long nOldOutWidth = mnOutWidth; + long nOldOutHeight = mnOutHeight; + Region* pOverlapRegion = NULL; + Region* pOldRegion = NULL; + + if ( IsReallyVisible() ) + { + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + Rectangle aOldWinRect( Point( nOldOutOffX, nOldOutOffY ), + Size( nOldOutWidth, nOldOutHeight ) ); + pOldRegion = new Region( aOldWinRect ); + if ( mpWindowImpl->mbWinRegion ) + pOldRegion->Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + + if ( mnOutWidth && mnOutHeight && !mpWindowImpl->mbPaintTransparent && + !mpWindowImpl->mbInitWinClipRegion && !mpWindowImpl->maWinClipRegion.IsEmpty() && + !HasPaintEvent() ) + bCopyBits = TRUE; + } + + BOOL bnXRecycled = FALSE; // avoid duplicate mirroring in RTL case + if ( nFlags & WINDOW_POSSIZE_WIDTH ) + { + if(!( nFlags & WINDOW_POSSIZE_X )) + { + nX = mpWindowImpl->mnX; + nFlags |= WINDOW_POSSIZE_X; + bnXRecycled = TRUE; // we're using a mnX which was already mirrored in RTL case + } + + if ( nWidth < 0 ) + nWidth = 0; + if ( nWidth != mnOutWidth ) + { + mnOutWidth = nWidth; + bNewSize = TRUE; + bCopyBits = FALSE; + bNewWidth = TRUE; + } + } + if ( nFlags & WINDOW_POSSIZE_HEIGHT ) + { + if ( nHeight < 0 ) + nHeight = 0; + if ( nHeight != mnOutHeight ) + { + mnOutHeight = nHeight; + bNewSize = TRUE; + bCopyBits = FALSE; + } + } + + if ( nFlags & WINDOW_POSSIZE_X ) + { + long nOrgX = nX; + // --- RTL --- (compare the screen coordinates) + Point aPtDev( Point( nX+mnOutOffX, 0 ) ); + if( ImplHasMirroredGraphics() ) + { + mpGraphics->mirror( aPtDev.X(), this ); + + // #106948# always mirror our pos if our parent is not mirroring, even + // if we are also not mirroring + // --- RTL --- check if parent is in different coordinates + if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() ) + { + // --- RTL --- (re-mirror at parent window) + nX = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - nX; + } + /* #i99166# An LTR window in RTL UI that gets sized only would be + expected to not moved its upper left point + */ + if( bnXRecycled ) + { + if( ImplIsAntiparallel() ) + { + aPtDev.X() = mpWindowImpl->mnAbsScreenX; + nOrgX = mpWindowImpl->maPos.X(); + } + } + } + else if( !bnXRecycled && mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() ) + { + // mirrored window in LTR UI + { + // --- RTL --- (re-mirror at parent window) + nX = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - nX; + } + } + + // check maPos as well, as it could have been changed for client windows (ImplCallMove()) + if ( mpWindowImpl->mnAbsScreenX != aPtDev.X() || nX != mpWindowImpl->mnX || nOrgX != mpWindowImpl->maPos.X() ) + { + if ( bCopyBits && !pOverlapRegion ) + { + pOverlapRegion = new Region(); + ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ), + *pOverlapRegion, FALSE, TRUE, TRUE ); + } + mpWindowImpl->mnX = nX; + mpWindowImpl->maPos.X() = nOrgX; + mpWindowImpl->mnAbsScreenX = aPtDev.X(); // --- RTL --- (store real screen pos) + bNewPos = TRUE; + } + } + if ( nFlags & WINDOW_POSSIZE_Y ) + { + // check maPos as well, as it could have been changed for client windows (ImplCallMove()) + if ( nY != mpWindowImpl->mnY || nY != mpWindowImpl->maPos.Y() ) + { + if ( bCopyBits && !pOverlapRegion ) + { + pOverlapRegion = new Region(); + ImplCalcOverlapRegion( Rectangle( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ), + *pOverlapRegion, FALSE, TRUE, TRUE ); + } + mpWindowImpl->mnY = nY; + mpWindowImpl->maPos.Y() = nY; + bNewPos = TRUE; + } + } + +/* if ( nFlags & (WINDOW_POSSIZE_X|WINDOW_POSSIZE_Y) ) + { + POINT aPt; + aPt.x = mpWindowImpl->maPos.X(); + aPt.y = mpWindowImpl->maPos.Y(); + ClientToScreen( mpWindowImpl->mpFrame->maFrameData.mhWnd , &aPt ); + mpWindowImpl->maPos.X() = aPt.x; + mpWindowImpl->maPos.Y() = aPt.y; + } +*/ + if ( bNewPos || bNewSize ) + { + BOOL bUpdateSysObjPos = FALSE; + if ( bNewPos ) + bUpdateSysObjPos = ImplUpdatePos(); + + // the borderwindow always specifies the position for its client window + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->maPos = mpWindowImpl->mpBorderWindow->mpWindowImpl->maPos; + + if ( mpWindowImpl->mpClientWindow ) + { + mpWindowImpl->mpClientWindow->ImplPosSizeWindow( mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder, + mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder, + mnOutWidth-mpWindowImpl->mpClientWindow->mpWindowImpl->mnLeftBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnRightBorder, + mnOutHeight-mpWindowImpl->mpClientWindow->mpWindowImpl->mnTopBorder-mpWindowImpl->mpClientWindow->mpWindowImpl->mnBottomBorder, + WINDOW_POSSIZE_X | WINDOW_POSSIZE_Y | + WINDOW_POSSIZE_WIDTH | WINDOW_POSSIZE_HEIGHT ); + // Wenn wir ein ClientWindow haben, dann hat dieses fuer die + // Applikation auch die Position des FloatingWindows + mpWindowImpl->mpClientWindow->mpWindowImpl->maPos = mpWindowImpl->maPos; + if ( bNewPos ) + { + if ( mpWindowImpl->mpClientWindow->IsVisible() ) + { + mpWindowImpl->mpClientWindow->ImplCallMove(); + } + else + { + mpWindowImpl->mpClientWindow->mpWindowImpl->mbCallMove = TRUE; + } + } + } +// else +// { +// if ( mpWindowImpl->mpBorderWindow ) +// mpWindowImpl->maPos = mpWindowImpl->mpBorderWindow->mpWindowImpl->maPos; +// } + + // Move()/Resize() werden erst bei Show() gerufen, damit min. eins vor + // einem Show() kommt + if ( IsVisible() ) + { + if ( bNewPos ) + { + ImplCallMove(); + } + if ( bNewSize ) + { + ImplCallResize(); + } + } + else + { + if ( bNewPos ) + mpWindowImpl->mbCallMove = TRUE; + if ( bNewSize ) + mpWindowImpl->mbCallResize = TRUE; + } + + BOOL bUpdateSysObjClip = FALSE; + if ( IsReallyVisible() ) + { + if ( bNewPos || bNewSize ) + { + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev ) + ImplDeleteOverlapBackground(); + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + // Clip-Flag neu setzen + bUpdateSysObjClip = !ImplSetClipFlag( TRUE ); + } + + // Fensterinhalt invalidieren ? + if ( bNewPos || (mnOutWidth > nOldOutWidth) || (mnOutHeight > nOldOutHeight) ) + { + if ( bNewPos ) + { + BOOL bInvalidate = FALSE; + BOOL bParentPaint = TRUE; + if ( !ImplIsOverlapWindow() ) + bParentPaint = mpWindowImpl->mpParent->IsPaintEnabled(); + if ( bCopyBits && bParentPaint && !HasPaintEvent() ) + { + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + if ( mpWindowImpl->mbWinRegion ) + aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + ImplClipBoundaries( aRegion, FALSE, TRUE ); + if ( !pOverlapRegion->IsEmpty() ) + { + pOverlapRegion->Move( mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY ); + aRegion.Exclude( *pOverlapRegion ); + } + if ( !aRegion.IsEmpty() ) + { + // Paint-Bereiche anpassen + ImplMoveAllInvalidateRegions( Rectangle( Point( nOldOutOffX, nOldOutOffY ), + Size( nOldOutWidth, nOldOutHeight ) ), + mnOutOffX-nOldOutOffX, mnOutOffY-nOldOutOffY, + TRUE ); + SalGraphics* pGraphics = ImplGetFrameGraphics(); + if ( pGraphics ) + { + const bool bSelectClipRegion = ImplSelectClipRegion( aRegion, pGraphics ); + if ( bSelectClipRegion ) + { + pGraphics->CopyArea( mnOutOffX, mnOutOffY, + nOldOutOffX, nOldOutOffY, + nOldOutWidth, nOldOutHeight, + SAL_COPYAREA_WINDOWINVALIDATE, this ); + } + else + bInvalidate = TRUE; + } + else + bInvalidate = TRUE; + if ( !bInvalidate ) + { + if ( !pOverlapRegion->IsEmpty() ) + ImplInvalidateFrameRegion( pOverlapRegion, INVALIDATE_CHILDREN ); + } + } + else + bInvalidate = TRUE; + } + else + bInvalidate = TRUE; + if ( bInvalidate ) + ImplInvalidateFrameRegion( NULL, INVALIDATE_CHILDREN ); + } + else + { + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + aRegion.Exclude( *pOldRegion ); + if ( mpWindowImpl->mbWinRegion ) + aRegion.Intersect( ImplPixelToDevicePixel( mpWindowImpl->maWinRegion ) ); + ImplClipBoundaries( aRegion, FALSE, TRUE ); + if ( !aRegion.IsEmpty() ) + ImplInvalidateFrameRegion( &aRegion, INVALIDATE_CHILDREN ); + } + } + + // Parent oder Overlaps invalidieren + if ( bNewPos || + (mnOutWidth < nOldOutWidth) || (mnOutHeight < nOldOutHeight) ) + { + Region aRegion( *pOldRegion ); + if ( !mpWindowImpl->mbPaintTransparent ) + ImplExcludeWindowRegion( aRegion ); + ImplClipBoundaries( aRegion, FALSE, TRUE ); + if ( !aRegion.IsEmpty() && !mpWindowImpl->mpBorderWindow ) + ImplInvalidateParentFrameRegion( aRegion ); + } + } + + // System-Objekte anpassen + if ( bUpdateSysObjClip ) + ImplUpdateSysObjClip(); + if ( bUpdateSysObjPos ) + ImplUpdateSysObjPos(); + if ( bNewSize && mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->SetPosSize( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ); + } + + if ( pOverlapRegion ) + delete pOverlapRegion; + if ( pOldRegion ) + delete pOldRegion; +} + +// ----------------------------------------------------------------------- + +void Window::ImplToBottomChild() +{ + if ( !ImplIsOverlapWindow() && !mpWindowImpl->mbReallyVisible && (mpWindowImpl->mpParent->mpWindowImpl->mpLastChild != this) ) + { + // Fenster an das Ende der Liste setzen + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext; + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + mpWindowImpl->mpPrev = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild; + mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this; + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this; + mpWindowImpl->mpNext = NULL; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCalcToTop( ImplCalcToTopData* pPrevData ) +{ + DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplCalcToTop(): Is not a OverlapWindow" ); + + if ( !mpWindowImpl->mbFrame ) + { + if ( IsReallyVisible() ) + { + // Region berechnen, wo das Fenster mit anderen Fenstern ueberlappt + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + Region aInvalidateRegion; + ImplCalcOverlapRegionOverlaps( aRegion, aInvalidateRegion ); + + if ( !aInvalidateRegion.IsEmpty() ) + { + ImplCalcToTopData* pData = new ImplCalcToTopData; + pPrevData->mpNext = pData; + pData->mpNext = NULL; + pData->mpWindow = this; + pData->mpInvalidateRegion = new Region( aInvalidateRegion ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCalcChildOverlapToTop( ImplCalcToTopData* pPrevData ) +{ + DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplCalcChildOverlapToTop(): Is not a OverlapWindow" ); + + ImplCalcToTop( pPrevData ); + if ( pPrevData->mpNext ) + pPrevData = pPrevData->mpNext; + + Window* pOverlap = mpWindowImpl->mpFirstOverlap; + while ( pOverlap ) + { + pOverlap->ImplCalcToTop( pPrevData ); + if ( pPrevData->mpNext ) + pPrevData = pPrevData->mpNext; + pOverlap = pOverlap->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplToTop( USHORT nFlags ) +{ + DBG_ASSERT( ImplIsOverlapWindow(), "Window::ImplToTop(): Is not a OverlapWindow" ); + + if ( mpWindowImpl->mbFrame ) + { + // Wenn in das externe Fenster geklickt wird, ist dieses + // dafuer zustaendig dafuer zu sorgen, das unser Frame + // nach vorne kommt + if ( !mpWindowImpl->mpFrameData->mbHasFocus && + !mpWindowImpl->mpFrameData->mbSysObjFocus && + !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl && + !mpWindowImpl->mpFrameData->mbInSysObjToTopHdl ) + { + // do not bring floating windows on the client to top + if( !ImplGetClientWindow() || !(ImplGetClientWindow()->GetStyle() & WB_SYSTEMFLOATWIN) ) + { + USHORT nSysFlags = 0; + if ( nFlags & TOTOP_RESTOREWHENMIN ) + nSysFlags |= SAL_FRAME_TOTOP_RESTOREWHENMIN; + if ( nFlags & TOTOP_FOREGROUNDTASK ) + nSysFlags |= SAL_FRAME_TOTOP_FOREGROUNDTASK; + if ( nFlags & TOTOP_GRABFOCUSONLY ) + nSysFlags |= SAL_FRAME_TOTOP_GRABFOCUS_ONLY; + mpWindowImpl->mpFrame->ToTop( nSysFlags ); + } + } + } + else + { + if ( mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap != this ) + { + // Fenster aus der Liste entfernen + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev; + + // AlwaysOnTop beruecksichtigen + BOOL bOnTop = IsAlwaysOnTopEnabled(); + Window* pNextWin = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap; + if ( !bOnTop ) + { + while ( pNextWin ) + { + if ( !pNextWin->IsAlwaysOnTopEnabled() ) + break; + pNextWin = pNextWin->mpWindowImpl->mpNext; + } + } + + // TopLevel abpruefen + BYTE nTopLevel = mpWindowImpl->mpOverlapData->mnTopLevel; + while ( pNextWin ) + { + if ( (bOnTop != pNextWin->IsAlwaysOnTopEnabled()) || + (nTopLevel <= pNextWin->mpWindowImpl->mpOverlapData->mnTopLevel) ) + break; + pNextWin = pNextWin->mpWindowImpl->mpNext; + } + + // Fenster in die Liste wieder eintragen + mpWindowImpl->mpNext = pNextWin; + if ( pNextWin ) + { + mpWindowImpl->mpPrev = pNextWin->mpWindowImpl->mpPrev; + pNextWin->mpWindowImpl->mpPrev = this; + } + else + { + mpWindowImpl->mpPrev = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap; + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this; + } + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this; + + // ClipRegion muss von diesem Fenster und allen weiteren + // ueberlappenden Fenstern neu berechnet werden. + if ( IsReallyVisible() ) + { + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + mpWindowImpl->mpOverlapWindow->ImplSetClipFlagOverlapWindows(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplStartToTop( USHORT nFlags ) +{ + ImplCalcToTopData aStartData; + ImplCalcToTopData* pCurData; + ImplCalcToTopData* pNextData; + Window* pOverlapWindow; + if ( ImplIsOverlapWindow() ) + pOverlapWindow = this; + else + pOverlapWindow = mpWindowImpl->mpOverlapWindow; + + // Zuerst die Paint-Bereiche berechnen + Window* pTempOverlapWindow = pOverlapWindow; + aStartData.mpNext = NULL; + pCurData = &aStartData; + do + { + pTempOverlapWindow->ImplCalcToTop( pCurData ); + if ( pCurData->mpNext ) + pCurData = pCurData->mpNext; + pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow; + } + while ( !pTempOverlapWindow->mpWindowImpl->mbFrame ); + // Dann die Paint-Bereiche der ChildOverlap-Windows berechnen + pTempOverlapWindow = mpWindowImpl->mpFirstOverlap; + while ( pTempOverlapWindow ) + { + pTempOverlapWindow->ImplCalcToTop( pCurData ); + if ( pCurData->mpNext ) + pCurData = pCurData->mpNext; + pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpNext; + } + + // Dann die Fenster-Verkettung aendern + pTempOverlapWindow = pOverlapWindow; + do + { + pTempOverlapWindow->ImplToTop( nFlags ); + pTempOverlapWindow = pTempOverlapWindow->mpWindowImpl->mpOverlapWindow; + } + while ( !pTempOverlapWindow->mpWindowImpl->mbFrame ); + // Und zum Schluss invalidieren wir die ungueltigen Bereiche + pCurData = aStartData.mpNext; + while ( pCurData ) + { + pCurData->mpWindow->ImplInvalidateFrameRegion( pCurData->mpInvalidateRegion, INVALIDATE_CHILDREN ); + pNextData = pCurData->mpNext; + delete pCurData->mpInvalidateRegion; + delete pCurData; + pCurData = pNextData; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplFocusToTop( USHORT nFlags, BOOL bReallyVisible ) +{ + // Soll Focus auch geholt werden? + if ( !(nFlags & TOTOP_NOGRABFOCUS) ) + { + // Erstes Fenster mit GrabFocus-Activate bekommt den Focus + Window* pFocusWindow = this; + while ( !pFocusWindow->ImplIsOverlapWindow() ) + { + // Nur wenn Fenster kein Border-Fenster hat, da wir + // immer das dazugehoerende BorderFenster finden wollen + if ( !pFocusWindow->mpWindowImpl->mpBorderWindow ) + { + if ( pFocusWindow->mpWindowImpl->mnActivateMode & ACTIVATE_MODE_GRABFOCUS ) + break; + } + pFocusWindow = pFocusWindow->ImplGetParent(); + } + if ( (pFocusWindow->mpWindowImpl->mnActivateMode & ACTIVATE_MODE_GRABFOCUS) && + !pFocusWindow->HasChildPathFocus( TRUE ) ) + pFocusWindow->GrabFocus(); + } + + if ( bReallyVisible ) + ImplGenerateMouseMove(); +} + +// ----------------------------------------------------------------------- + +void Window::ImplShowAllOverlaps() +{ + Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow ) + { + if ( pOverlapWindow->mpWindowImpl->mbOverlapVisible ) + { + pOverlapWindow->Show( TRUE, SHOW_NOACTIVATE ); + pOverlapWindow->mpWindowImpl->mbOverlapVisible = FALSE; + } + + pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplHideAllOverlaps() +{ + Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow ) + { + if ( pOverlapWindow->IsVisible() ) + { + pOverlapWindow->mpWindowImpl->mbOverlapVisible = TRUE; + pOverlapWindow->Show( FALSE ); + } + + pOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallMouseMove( USHORT nMouseCode, BOOL bModChanged ) +{ + if ( mpWindowImpl->mpFrameData->mbMouseIn && mpWindowImpl->mpFrameWindow->mpWindowImpl->mbReallyVisible ) + { + ULONG nTime = Time::GetSystemTicks(); + long nX = mpWindowImpl->mpFrameData->mnLastMouseX; + long nY = mpWindowImpl->mpFrameData->mnLastMouseY; + USHORT nCode = nMouseCode; + USHORT nMode = mpWindowImpl->mpFrameData->mnMouseMode; + BOOL bLeave; + // Auf MouseLeave testen + if ( ((nX < 0) || (nY < 0) || + (nX >= mpWindowImpl->mpFrameWindow->mnOutWidth) || + (nY >= mpWindowImpl->mpFrameWindow->mnOutHeight)) && + !ImplGetSVData()->maWinData.mpCaptureWin ) + bLeave = TRUE; + else + bLeave = FALSE; + nMode |= MOUSE_SYNTHETIC; + if ( bModChanged ) + nMode |= MOUSE_MODIFIERCHANGED; + ImplHandleMouseEvent( mpWindowImpl->mpFrameWindow, EVENT_MOUSEMOVE, bLeave, nX, nY, nTime, nCode, nMode ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplGenerateMouseMove() +{ + if ( !mpWindowImpl->mpFrameData->mnMouseMoveId ) + Application::PostUserEvent( mpWindowImpl->mpFrameData->mnMouseMoveId, LINK( mpWindowImpl->mpFrameWindow, Window, ImplGenerateMouseMoveHdl ) ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplGenerateMouseMoveHdl, void*, EMPTYARG ) +{ + mpWindowImpl->mpFrameData->mnMouseMoveId = 0; + Window* pCaptureWin = ImplGetSVData()->maWinData.mpCaptureWin; + if( ! pCaptureWin || + (pCaptureWin->mpWindowImpl && pCaptureWin->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame) + ) + { + ImplCallMouseMove( mpWindowImpl->mpFrameData->mnMouseCode ); + } + return 0; +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvertFocus( const Rectangle& rRect ) +{ + InvertTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallFocusChangeActivate( Window* pNewOverlapWindow, + Window* pOldOverlapWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pNewRealWindow; + Window* pOldRealWindow; + Window* pLastRealWindow; + BOOL bCallActivate = TRUE; + BOOL bCallDeactivate = TRUE; + + pOldRealWindow = pOldOverlapWindow->ImplGetWindow(); + pNewRealWindow = pNewOverlapWindow->ImplGetWindow(); + if ( (pOldRealWindow->GetType() != WINDOW_FLOATINGWINDOW) || + pOldRealWindow->GetActivateMode() ) + { + if ( (pNewRealWindow->GetType() == WINDOW_FLOATINGWINDOW) && + !pNewRealWindow->GetActivateMode() ) + { + pSVData->maWinData.mpLastDeacWin = pOldOverlapWindow; + bCallDeactivate = FALSE; + } + } + else if ( (pNewRealWindow->GetType() != WINDOW_FLOATINGWINDOW) || + pNewRealWindow->GetActivateMode() ) + { + if ( pSVData->maWinData.mpLastDeacWin ) + { + if ( pSVData->maWinData.mpLastDeacWin == pNewOverlapWindow ) + bCallActivate = FALSE; + else + { + pLastRealWindow = pSVData->maWinData.mpLastDeacWin->ImplGetWindow(); + pSVData->maWinData.mpLastDeacWin->mpWindowImpl->mbActive = FALSE; + pSVData->maWinData.mpLastDeacWin->Deactivate(); + if ( pLastRealWindow != pSVData->maWinData.mpLastDeacWin ) + { + pLastRealWindow->mpWindowImpl->mbActive = TRUE; + pLastRealWindow->Activate(); + } + } + pSVData->maWinData.mpLastDeacWin = NULL; + } + } + + if ( bCallDeactivate ) + { + if( pOldOverlapWindow->mpWindowImpl->mbActive ) + { + pOldOverlapWindow->mpWindowImpl->mbActive = FALSE; + pOldOverlapWindow->Deactivate(); + } + if ( pOldRealWindow != pOldOverlapWindow ) + { + if( pOldRealWindow->mpWindowImpl->mbActive ) + { + pOldRealWindow->mpWindowImpl->mbActive = FALSE; + pOldRealWindow->Deactivate(); + } + } + } + if ( bCallActivate && ! pNewOverlapWindow->mpWindowImpl->mbActive ) + { + if( ! pNewOverlapWindow->mpWindowImpl->mbActive ) + { + pNewOverlapWindow->mpWindowImpl->mbActive = TRUE; + pNewOverlapWindow->Activate(); + } + if ( pNewRealWindow != pNewOverlapWindow ) + { + if( ! pNewRealWindow->mpWindowImpl->mbActive ) + { + pNewRealWindow->mpWindowImpl->mbActive = TRUE; + pNewRealWindow->Activate(); + } + } + } +} + +static bool IsWindowFocused(const WindowImpl& rWinImpl) +{ + if (rWinImpl.mpSysObj) + return true; + + if (rWinImpl.mpFrameData->mbHasFocus) + return true; + + if (rWinImpl.mbFakeFocusSet) + return true; + + return false; +} + +// ----------------------------------------------------------------------- +void Window::ImplGrabFocus( USHORT nFlags ) +{ + // #143570# no focus for destructing windows + if( mpWindowImpl->mbInDtor ) + return; + + // some event listeners do really bad stuff + // => prepare for the worst + ImplDelData aDogTag( this ); + + // Currently the client window should always get the focus + // Should the border window at some point be focusable + // we need to change all GrabFocus() instances in VCL, + // e.g. in ToTop() + + if ( mpWindowImpl->mpClientWindow ) + { + // For a lack of design we need a little hack here to + // ensure that dialogs on close pass the focus back to + // the correct window + if ( mpWindowImpl->mpLastFocusWindow && (mpWindowImpl->mpLastFocusWindow != this) && + !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) && + mpWindowImpl->mpLastFocusWindow->IsEnabled() && + mpWindowImpl->mpLastFocusWindow->IsInputEnabled() && + ! mpWindowImpl->mpLastFocusWindow->IsInModalMode() + ) + mpWindowImpl->mpLastFocusWindow->GrabFocus(); + else + mpWindowImpl->mpClientWindow->GrabFocus(); + return; + } + else if ( mpWindowImpl->mbFrame ) + { + // For a lack of design we need a little hack here to + // ensure that dialogs on close pass the focus back to + // the correct window + if ( mpWindowImpl->mpLastFocusWindow && (mpWindowImpl->mpLastFocusWindow != this) && + !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) && + mpWindowImpl->mpLastFocusWindow->IsEnabled() && + mpWindowImpl->mpLastFocusWindow->IsInputEnabled() && + ! mpWindowImpl->mpLastFocusWindow->IsInModalMode() + ) + { + mpWindowImpl->mpLastFocusWindow->GrabFocus(); + return; + } + } + + // If the Window is disabled, then we don't change the focus + if ( !IsEnabled() || !IsInputEnabled() || IsInModalMode() ) + return; + + // we only need to set the focus if it is not already set + // note: if some other frame is waiting for an asynchrounous focus event + // we also have to post an asynchronous focus event for this frame + // which is done using ToTop + ImplSVData* pSVData = ImplGetSVData(); + + BOOL bAsyncFocusWaiting = FALSE; + Window *pFrame = pSVData->maWinData.mpFirstFrame; + while( pFrame ) + { + if( pFrame != mpWindowImpl->mpFrameWindow && pFrame->mpWindowImpl->mpFrameData->mnFocusId ) + { + bAsyncFocusWaiting = TRUE; + break; + } + pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame; + } + + bool bHasFocus = IsWindowFocused(*mpWindowImpl); + + BOOL bMustNotGrabFocus = FALSE; + // #100242#, check parent hierarchy if some floater prohibits grab focus + + Window *pParent = this; + while( pParent ) + { + // #102158#, ignore grabfocus only if the floating parent grabs keyboard focus by itself (GrabsFocus()) + // otherwise we cannot set the focus in a floating toolbox + if( ( (pParent->mpWindowImpl->mbFloatWin && ((FloatingWindow*)pParent)->GrabsFocus()) || ( pParent->GetStyle() & WB_SYSTEMFLOATWIN ) ) && !( pParent->GetStyle() & WB_MOVEABLE ) ) + { + bMustNotGrabFocus = TRUE; + break; + } + pParent = pParent->mpWindowImpl->mpParent; + } + + + if ( ( pSVData->maWinData.mpFocusWin != this && ! mpWindowImpl->mbInDtor ) || ( bAsyncFocusWaiting && !bHasFocus && !bMustNotGrabFocus ) ) + { + // EndExtTextInput if it is not the same window + if ( pSVData->maWinData.mpExtTextInputWin && + (pSVData->maWinData.mpExtTextInputWin != this) ) + pSVData->maWinData.mpExtTextInputWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE ); + + // Dieses Fenster als letztes FocusWindow merken + Window* pOverlapWindow = ImplGetFirstOverlapWindow(); + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = this; + mpWindowImpl->mpFrameData->mpFocusWin = this; + + if( !bHasFocus ) + { + // menue windows never get the system focus + // the application will keep the focus + if( bMustNotGrabFocus ) + return; + else + { + // Hier setzen wir schon den Focus um, da ToTop() den Focus + // nicht auf ein anderes Fenster setzen darf + //DBG_WARNING( "Window::GrabFocus() - Frame doesn't have the focus" ); + mpWindowImpl->mpFrame->ToTop( SAL_FRAME_TOTOP_GRABFOCUS | SAL_FRAME_TOTOP_GRABFOCUS_ONLY ); + return; + } + } + + Window* pOldFocusWindow = pSVData->maWinData.mpFocusWin; + ImplDelData aOldFocusDel( pOldFocusWindow ); + + pSVData->maWinData.mpFocusWin = this; + + if ( pOldFocusWindow ) + { + // Cursor hiden + if ( pOldFocusWindow->mpWindowImpl->mpCursor ) + pOldFocusWindow->mpWindowImpl->mpCursor->ImplHide(); + } + + // !!!!! Wegen altem SV-Office Activate/Deavtivate Handling + // !!!!! erstmal so wie frueher + if ( pOldFocusWindow ) + { + // Focus merken + Window* pOldOverlapWindow = pOldFocusWindow->ImplGetFirstOverlapWindow(); + Window* pNewOverlapWindow = ImplGetFirstOverlapWindow(); + if ( pOldOverlapWindow != pNewOverlapWindow ) + ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow ); + } + else + { + Window* pNewOverlapWindow = ImplGetFirstOverlapWindow(); + Window* pNewRealWindow = pNewOverlapWindow->ImplGetWindow(); + pNewOverlapWindow->mpWindowImpl->mbActive = TRUE; + pNewOverlapWindow->Activate(); + if ( pNewRealWindow != pNewOverlapWindow ) + { + pNewRealWindow->mpWindowImpl->mbActive = TRUE; + pNewRealWindow->Activate(); + } + } +/* + // call Deactivate and Activate + Window* pDeactivateParent; + Window* pActivateParent; + Window* pParent; + Window* pLastParent; + pDeactivateParent = pOldFocusWindow; + while ( pDeactivateParent ) + { + pParent = pDeactivateParent; + if ( pParent->ImplIsChild( this ) ) + break; + + if ( pDeactivateParent->ImplIsOverlapWindow() ) + { + if ( !pDeactivateParent->mpWindowImpl->mbParentActive ) + break; + } + + pDeactivateParent = pDeactivateParent->ImplGetParent(); + } + if ( pOldFocusWindow ) + { + pActivateParent = this; + while ( pActivateParent ) + { + pParent = pActivateParent; + if ( pParent->ImplIsChild( pOldFocusWindow ) ) + break; + + if ( pActivateParent->ImplIsOverlapWindow() ) + { + if ( !pActivateParent->mpWindowImpl->mbParentActive ) + break; + } + + pActivateParent = pActivateParent->ImplGetParent(); + } + } + else + { + if ( ImplIsOverlapWindow() ) + pActivateParent = this; + else + pActivateParent = mpWindowImpl->mpOverlapWindow; + while ( pActivateParent ) + { + if ( pActivateParent->ImplIsOverlapWindow() ) + { + if ( !pActivateParent->mpWindowImpl->mbParentActive ) + break; + } + + pActivateParent = pActivateParent->ImplGetParent(); + } + } + if ( pDeactivateParent ) + { + do + { + pLastParent = pOldFocusWindow; + if ( pLastParent != pDeactivateParent ) + { + pParent = pLastParent->ImplGetParent(); + while ( pParent ) + { + if ( pParent == pDeactivateParent ) + break; + pLastParent = pParent; + pParent = pParent->ImplGetParent(); + } + } + else + pParent = pLastParent; + + pParent->mpWindowImpl->mbActive = FALSE; + pParent->Deactivate(); + pDeactivateParent = pLastParent; + } + while ( pDeactivateParent != pOldFocusWindow ); + } + do + { + pLastParent = this; + if ( pLastParent != pActivateParent ) + { + pParent = pLastParent->ImplGetParent(); + while ( pParent ) + { + if ( pParent == pActivateParent ) + break; + pLastParent = pParent; + pParent = pParent->ImplGetParent(); + } + } + else + pParent = pLastParent; + + pParent->mpWindowImpl->mbActive = TRUE; + pParent->Activate(); + pActivateParent = pLastParent; + } + while ( pActivateParent != this ); +*/ + // call Get- and LoseFocus + if ( pOldFocusWindow && ! aOldFocusDel.IsDelete() ) + { + if ( pOldFocusWindow->IsTracking() && + (pSVData->maWinData.mnTrackFlags & STARTTRACK_FOCUSCANCEL) ) + pOldFocusWindow->EndTracking( ENDTRACK_CANCEL | ENDTRACK_FOCUS ); + NotifyEvent aNEvt( EVENT_LOSEFOCUS, pOldFocusWindow ); + if ( !ImplCallPreNotify( aNEvt ) ) + pOldFocusWindow->LoseFocus(); + pOldFocusWindow->ImplCallDeactivateListeners( this ); + } + + if ( pSVData->maWinData.mpFocusWin == this ) + { + if ( mpWindowImpl->mpSysObj ) + { + mpWindowImpl->mpFrameData->mpFocusWin = this; + if ( !mpWindowImpl->mpFrameData->mbInSysObjFocusHdl ) + mpWindowImpl->mpSysObj->GrabFocus(); + } + + if ( pSVData->maWinData.mpFocusWin == this ) + { + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplShow(); + mpWindowImpl->mbInFocusHdl = TRUE; + mpWindowImpl->mnGetFocusFlags = nFlags; + // if we're changing focus due to closing a popup floating window + // notify the new focus window so it can restore the inner focus + // eg, toolboxes can select their recent active item + if( pOldFocusWindow && + ! aOldFocusDel.IsDelete() && + ( pOldFocusWindow->GetDialogControlFlags() & WINDOW_DLGCTRL_FLOATWIN_POPUPMODEEND_CANCEL ) ) + mpWindowImpl->mnGetFocusFlags |= GETFOCUS_FLOATWIN_POPUPMODEEND_CANCEL; + NotifyEvent aNEvt( EVENT_GETFOCUS, this ); + if ( !ImplCallPreNotify( aNEvt ) && !aDogTag.IsDelete() ) + GetFocus(); + if( !aDogTag.IsDelete() ) + ImplCallActivateListeners( (pOldFocusWindow && ! aOldFocusDel.IsDelete()) ? pOldFocusWindow : NULL ); + if( !aDogTag.IsDelete() ) + { + mpWindowImpl->mnGetFocusFlags = 0; + mpWindowImpl->mbInFocusHdl = FALSE; + } + } + } + + GetpApp()->FocusChanged(); + ImplNewInputContext(); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplNewInputContext() +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pFocusWin = pSVData->maWinData.mpFocusWin; + if ( !pFocusWin ) + return; + + // Is InputContext changed? + const InputContext& rInputContext = pFocusWin->GetInputContext(); + if ( rInputContext == pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext ) + return; + + pFocusWin->mpWindowImpl->mpFrameData->maOldInputContext = rInputContext; + + SalInputContext aNewContext; + const Font& rFont = rInputContext.GetFont(); + const XubString& rFontName = rFont.GetName(); + ImplFontEntry* pFontEntry = NULL; + aNewContext.mpFont = NULL; + if ( rFontName.Len() ) + { + Size aSize = pFocusWin->ImplLogicToDevicePixel( rFont.GetSize() ); + if ( !aSize.Height() ) + { + // Nur dann Defaultgroesse setzen, wenn Fonthoehe auch in logischen + // Koordinaaten 0 ist + if ( rFont.GetSize().Height() ) + aSize.Height() = 1; + else + aSize.Height() = (12*pFocusWin->mnDPIY)/72; + } + // TODO: No display device uses ImplDirectFontSubstitution thingy, right? => remove it + ImplDirectFontSubstitution* pFontSubst = NULL; + //if( pFocusWin->mpOutDevData ) + // pFontSubst = &pFocusWin->mpOutDevData->maDevFontSubst; + pFontEntry = pFocusWin->mpFontCache->GetFontEntry( pFocusWin->mpFontList, + rFont, aSize, static_cast<float>(aSize.Height()), pFontSubst ); + if ( pFontEntry ) + aNewContext.mpFont = &pFontEntry->maFontSelData; + } + aNewContext.meLanguage = rFont.GetLanguage(); + aNewContext.mnOptions = rInputContext.GetOptions(); + pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext ); + + if ( pFontEntry ) + pFocusWin->mpFontCache->Release( pFontEntry ); +} + +// ----------------------------------------------------------------------- + +Window::Window( WindowType nType ) +{ + DBG_CTOR( Window, ImplDbgCheckWindow ); + + ImplInitWindowData( nType ); +} + +// ----------------------------------------------------------------------- + +Window::Window( Window* pParent, WinBits nStyle ) +{ + DBG_CTOR( Window, ImplDbgCheckWindow ); + + ImplInitWindowData( WINDOW_WINDOW ); + ImplInit( pParent, nStyle, NULL ); +} + +// ----------------------------------------------------------------------- + +Window::Window( Window* pParent, const ResId& rResId ) +{ + DBG_CTOR( Window, ImplDbgCheckWindow ); + + ImplInitWindowData( WINDOW_WINDOW ); + rResId.SetRT( RSC_WINDOW ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle, NULL ); + ImplLoadRes( rResId ); + + if ( !(nStyle & WB_HIDE) ) + Show(); +} + +// ----------------------------------------------------------------------- +#if OSL_DEBUG_LEVEL > 0 +namespace +{ + void lcl_appendWindowInfo( ByteString& io_rErrorString, const Window& i_rWindow ) + { + // skip border windows, they don't carry information which helps diagnosing the problem + const Window* pWindow( &i_rWindow ); + while ( pWindow && ( pWindow->GetType() == WINDOW_BORDERWINDOW ) ) + pWindow = pWindow->GetWindow( WINDOW_FIRSTCHILD ); + if ( !pWindow ) + pWindow = &i_rWindow; + + io_rErrorString += char(13); + io_rErrorString += typeid( *pWindow ).name(); + io_rErrorString += " (window text: '"; + io_rErrorString += ByteString( pWindow->GetText(), RTL_TEXTENCODING_UTF8 ); + io_rErrorString += "')"; + } +} +#endif +// ----------------------------------------------------------------------- + +Window::~Window() +{ + ImplFreeExtWindowImpl(); + + vcl::LazyDeletor<Window>::Undelete( this ); + + DBG_DTOR( Window, ImplDbgCheckWindow ); + DBG_ASSERT( !mpWindowImpl->mbInDtor, "~Window - already in DTOR!" ); + + + // remove Key and Mouse events issued by Application::PostKey/MouseEvent + Application::RemoveMouseAndKeyEvents( this ); + + // Dispose of the canvas implementation (which, currently, has an + // own wrapper window as a child to this one. + Reference< rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas ); + if( xCanvas.is() ) + { + uno::Reference < lang::XComponent > xCanvasComponent( xCanvas, + uno::UNO_QUERY ); + if( xCanvasComponent.is() ) + xCanvasComponent->dispose(); + } + + mpWindowImpl->mbInDtor = TRUE; + + ImplCallEventListeners( VCLEVENT_OBJECT_DYING ); + + // do not send child events for frames that were registered as native frames + if( !ImplIsAccessibleNativeFrame() && mpWindowImpl->mbReallyVisible ) + if ( ImplIsAccessibleCandidate() && GetAccessibleParentWindow() ) + GetAccessibleParentWindow()->ImplCallEventListeners( VCLEVENT_WINDOW_CHILDDESTROYED, this ); + + // remove associated data structures from dockingmanager + ImplGetDockingManager()->RemoveWindow( this ); + + + // remove ownerdraw decorated windows from list in the top-most frame window + if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame ) + { + ::std::vector< Window* >& rList = ImplGetOwnerDrawList(); + ::std::vector< Window* >::iterator p; + p = ::std::find( rList.begin(), rList.end(), this ); + if( p != rList.end() ) + rList.erase( p ); + } + + // shutdown drag and drop + ::com::sun::star::uno::Reference < ::com::sun::star::lang::XComponent > xDnDComponent( mpWindowImpl->mxDNDListenerContainer, ::com::sun::star::uno::UNO_QUERY ); + + if( xDnDComponent.is() ) + xDnDComponent->dispose(); + + if( mpWindowImpl->mbFrame && mpWindowImpl->mpFrameData ) + { + try + { + // deregister drop target listener + if( mpWindowImpl->mpFrameData->mxDropTargetListener.is() ) + { + Reference< XDragGestureRecognizer > xDragGestureRecognizer = + Reference< XDragGestureRecognizer > (mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY); + if( xDragGestureRecognizer.is() ) + { + xDragGestureRecognizer->removeDragGestureListener( + Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY)); + } + + mpWindowImpl->mpFrameData->mxDropTarget->removeDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener ); + mpWindowImpl->mpFrameData->mxDropTargetListener.clear(); + } + + // shutdown drag and drop for this frame window + Reference< XComponent > xComponent( mpWindowImpl->mpFrameData->mxDropTarget, UNO_QUERY ); + + // DNDEventDispatcher does not hold a reference of the DropTarget, + // so it's ok if it does not support XComponent + if( xComponent.is() ) + xComponent->dispose(); + } + + catch ( Exception exc ) + { + // can be safely ignored here. + } + } + + UnoWrapperBase* pWrapper = Application::GetUnoWrapper( FALSE ); + if ( pWrapper ) + pWrapper->WindowDestroyed( this ); + + // MT: Must be called after WindowDestroyed! + // Otherwise, if the accessible is a VCLXWindow, it will try to destroy this window again! + // But accessibility implementations from applications need this dispose. + if ( mpWindowImpl->mxAccessible.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent> xC( mpWindowImpl->mxAccessible, ::com::sun::star::uno::UNO_QUERY ); + if ( xC.is() ) + xC->dispose(); + } + + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maHelpData.mpHelpWin && (pSVData->maHelpData.mpHelpWin->GetParent() == this) ) + ImplDestroyHelpWindow( true ); + + DBG_ASSERT( pSVData->maWinData.mpTrackWin != this, + "Window::~Window(): Window is in TrackingMode" ); + DBG_ASSERT( pSVData->maWinData.mpCaptureWin != this, + "Window::~Window(): Window has the mouse captured" ); + // #103442# DefModalDialogParent is now determined on-the-fly, so this pointer is unimportant now + //DBG_ASSERT( pSVData->maWinData.mpDefDialogParent != this, + // "Window::~Window(): Window is DefModalDialogParent" ); + + // Wegen alter kompatibilitaet + if ( pSVData->maWinData.mpTrackWin == this ) + EndTracking(); + if ( pSVData->maWinData.mpCaptureWin == this ) + ReleaseMouse(); + if ( pSVData->maWinData.mpDefDialogParent == this ) + pSVData->maWinData.mpDefDialogParent = NULL; + +#ifdef DBG_UTIL + if ( TRUE ) // always perform these tests in non-pro versions + { + ByteString aErrorStr; + BOOL bError = FALSE; + Window* pTempWin = mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pTempWin ) + { + if ( ImplIsRealParentPath( pTempWin ) ) + { + bError = TRUE; + lcl_appendWindowInfo( aErrorStr, *pTempWin ); + } + pTempWin = pTempWin->mpWindowImpl->mpNextOverlap; + } + if ( bError ) + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") with living SystemWindow(s) destroyed: "; + aTempStr += aErrorStr; + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! + } + + bError = FALSE; + pTempWin = pSVData->maWinData.mpFirstFrame; + while ( pTempWin ) + { + if ( ImplIsRealParentPath( pTempWin ) ) + { + bError = TRUE; + lcl_appendWindowInfo( aErrorStr, *pTempWin ); + } + pTempWin = pTempWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + if ( bError ) + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") with living SystemWindow(s) destroyed: "; + aTempStr += aErrorStr; + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! + } + + if ( mpWindowImpl->mpFirstChild ) + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") with living Child(s) destroyed: "; + pTempWin = mpWindowImpl->mpFirstChild; + while ( pTempWin ) + { + lcl_appendWindowInfo( aTempStr, *pTempWin ); + pTempWin = pTempWin->mpWindowImpl->mpNext; + } + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! + } + + if ( mpWindowImpl->mpFirstOverlap ) + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") with living SystemWindow(s) destroyed: "; + pTempWin = mpWindowImpl->mpFirstOverlap; + while ( pTempWin ) + { + lcl_appendWindowInfo( aTempStr, *pTempWin ); + pTempWin = pTempWin->mpWindowImpl->mpNext; + } + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! + } + + Window* pMyParent = this; + SystemWindow* pMySysWin = NULL; + + while ( pMyParent ) + { + if ( pMyParent->IsSystemWindow() ) + pMySysWin = (SystemWindow*)pMyParent; + pMyParent = pMyParent->GetParent(); + } + if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) ) + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") still in TaskPanelList!"; + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! + } + } +#endif + + if( mpWindowImpl->mbIsInTaskPaneList ) + { + Window* pMyParent = this; + SystemWindow* pMySysWin = NULL; + + while ( pMyParent ) + { + if ( pMyParent->IsSystemWindow() ) + pMySysWin = (SystemWindow*)pMyParent; + pMyParent = pMyParent->GetParent(); + } + if ( pMySysWin && pMySysWin->ImplIsInTaskPaneList( this ) ) + { + pMySysWin->GetTaskPaneList()->RemoveWindow( this ); + } + else + { + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") not found in TaskPanelList!"; + DBG_ERROR( aTempStr.GetBuffer() ); + } + } + + // Fenster hiden, um das entsprechende Paint-Handling auszuloesen + Hide(); + + // Mitteilen, das Fenster zerstoert wird + { + NotifyEvent aNEvt( EVENT_DESTROY, this ); + Notify( aNEvt ); + } + + // EndExtTextInputMode + if ( pSVData->maWinData.mpExtTextInputWin == this ) + { + EndExtTextInput( EXTTEXTINPUT_END_COMPLETE ); + if ( pSVData->maWinData.mpExtTextInputWin == this ) + pSVData->maWinData.mpExtTextInputWin = NULL; + } + + // check if the focus window is our child + BOOL bHasFocussedChild = FALSE; + if( pSVData->maWinData.mpFocusWin && ImplIsRealParentPath( pSVData->maWinData.mpFocusWin ) ) + { + // #122232#, this must not happen and is an application bug ! but we try some cleanup to hopefully avoid crashes, see below + bHasFocussedChild = TRUE; +#ifdef DBG_UTIL + ByteString aTempStr( "Window (" ); + aTempStr += ByteString( GetText(), RTL_TEXTENCODING_UTF8 ); + aTempStr += ") with focussed child window destroyed ! THIS WILL LEAD TO CRASHES AND MUST BE FIXED !"; + DBG_ERROR( aTempStr.GetBuffer() ); + GetpApp()->Abort( String( aTempStr, RTL_TEXTENCODING_UTF8 ) ); // abort in non-pro version, this must be fixed! +#endif + } + + // Wenn wir den Focus haben, dann den Focus auf ein anderes Fenster setzen + Window* pOverlapWindow = ImplGetFirstOverlapWindow(); + if ( pSVData->maWinData.mpFocusWin == this + || bHasFocussedChild ) // #122232#, see above, try some cleanup + { + if ( mpWindowImpl->mbFrame ) + { + pSVData->maWinData.mpFocusWin = NULL; + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL; + GetpApp()->FocusChanged(); + } + else + { + Window* pParent = GetParent(); + Window* pBorderWindow = mpWindowImpl->mpBorderWindow; + // Bei ueberlappenden Fenstern wird der Focus auf den + // Parent vom naechsten FrameWindow gesetzt + if ( pBorderWindow ) + { + if ( pBorderWindow->ImplIsOverlapWindow() ) + pParent = pBorderWindow->mpWindowImpl->mpOverlapWindow; + } + else if ( ImplIsOverlapWindow() ) + pParent = mpWindowImpl->mpOverlapWindow; + + if ( pParent && pParent->IsEnabled() && pParent->IsInputEnabled() && ! pParent->IsInModalMode() ) + pParent->GrabFocus(); + else + mpWindowImpl->mpFrameWindow->GrabFocus(); + + // If the focus was set back to 'this' set it to nothing + if ( pSVData->maWinData.mpFocusWin == this ) + { + pSVData->maWinData.mpFocusWin = NULL; + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL; + GetpApp()->FocusChanged(); + } + } + } + + + if ( pOverlapWindow->mpWindowImpl->mpLastFocusWindow == this ) + pOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL; + + // reset hint for DefModalDialogParent + if( pSVData->maWinData.mpActiveApplicationFrame == this ) + pSVData->maWinData.mpActiveApplicationFrame = NULL; + + // gemerkte Fenster zuruecksetzen + if ( mpWindowImpl->mpFrameData->mpFocusWin == this ) + mpWindowImpl->mpFrameData->mpFocusWin = NULL; + if ( mpWindowImpl->mpFrameData->mpMouseMoveWin == this ) + mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL; + if ( mpWindowImpl->mpFrameData->mpMouseDownWin == this ) + mpWindowImpl->mpFrameData->mpMouseDownWin = NULL; + + // Deactivate-Window zuruecksetzen + if ( pSVData->maWinData.mpLastDeacWin == this ) + pSVData->maWinData.mpLastDeacWin = NULL; + + if ( mpWindowImpl->mbFrame ) + { + if ( mpWindowImpl->mpFrameData->mnFocusId ) + Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnFocusId ); + if ( mpWindowImpl->mpFrameData->mnMouseMoveId ) + Application::RemoveUserEvent( mpWindowImpl->mpFrameData->mnMouseMoveId ); + } + + // Graphic freigeben + ImplReleaseGraphics(); + + // Evt. anderen Funktion mitteilen, das das Fenster geloescht + // wurde + ImplDelData* pDelData = mpWindowImpl->mpFirstDel; + while ( pDelData ) + { + pDelData->mbDel = TRUE; + pDelData->mpWindow = NULL; // #112873# pDel is not associated with a Window anymore + pDelData = pDelData->mpNext; + } + + // Fenster aus den Listen austragen + ImplRemoveWindow( TRUE ); + + // de-register as "top window child" at our parent, if necessary + if ( mpWindowImpl->mbFrame ) + { + BOOL bIsTopWindow = mpWindowImpl->mpWinData && ( mpWindowImpl->mpWinData->mnIsTopWindow == 1 ); + if ( mpWindowImpl->mpRealParent && bIsTopWindow ) + { + ImplWinData* pParentWinData = mpWindowImpl->mpRealParent->ImplGetWinData(); + + ::std::list< Window* >::iterator myPos = ::std::find( pParentWinData->maTopWindowChildren.begin(), + pParentWinData->maTopWindowChildren.end(), this ); + DBG_ASSERT( myPos != pParentWinData->maTopWindowChildren.end(), "Window::~Window: inconsistency in top window chain!" ); + if ( myPos != pParentWinData->maTopWindowChildren.end() ) + pParentWinData->maTopWindowChildren.erase( myPos ); + } + } + + // Extra Window Daten loeschen + if ( mpWindowImpl->mpWinData ) + { + if ( mpWindowImpl->mpWinData->mpExtOldText ) + delete mpWindowImpl->mpWinData->mpExtOldText; + if ( mpWindowImpl->mpWinData->mpExtOldAttrAry ) + delete mpWindowImpl->mpWinData->mpExtOldAttrAry; + if ( mpWindowImpl->mpWinData->mpCursorRect ) + delete mpWindowImpl->mpWinData->mpCursorRect; + if ( mpWindowImpl->mpWinData->mpFocusRect ) + delete mpWindowImpl->mpWinData->mpFocusRect; + if ( mpWindowImpl->mpWinData->mpTrackRect ) + delete mpWindowImpl->mpWinData->mpTrackRect; + + delete mpWindowImpl->mpWinData; + } + + + // Overlap-Window-Daten loeschen + if ( mpWindowImpl->mpOverlapData ) + { + delete mpWindowImpl->mpOverlapData; + } + + // Evt. noch BorderWindow oder Frame zerstoeren + if ( mpWindowImpl->mpBorderWindow ) + delete mpWindowImpl->mpBorderWindow; + else if ( mpWindowImpl->mbFrame ) + { + if ( pSVData->maWinData.mpFirstFrame == this ) + pSVData->maWinData.mpFirstFrame = mpWindowImpl->mpFrameData->mpNextFrame; + else + { + Window* pSysWin = pSVData->maWinData.mpFirstFrame; + while ( pSysWin->mpWindowImpl->mpFrameData->mpNextFrame != this ) + pSysWin = pSysWin->mpWindowImpl->mpFrameData->mpNextFrame; + pSysWin->mpWindowImpl->mpFrameData->mpNextFrame = mpWindowImpl->mpFrameData->mpNextFrame; + } + mpWindowImpl->mpFrame->SetCallback( NULL, NULL ); + pSVData->mpDefInst->DestroyFrame( mpWindowImpl->mpFrame ); + delete mpWindowImpl->mpFrameData; + } + + if ( mpWindowImpl->mpChildClipRegion ) + delete mpWindowImpl->mpChildClipRegion; + + delete mpWindowImpl->mpAccessibleInfos; + delete mpWindowImpl->mpControlFont; + + // should be the last statements + delete mpWindowImpl; mpWindowImpl = NULL; +} + +// ----------------------------------------------------------------------- +void Window::doLazyDelete() +{ + SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this); + DockingWindow* pDockWin = dynamic_cast<DockingWindow*>(this); + if( pSysWin || ( pDockWin && pDockWin->IsFloatingMode() ) ) + { + Show( FALSE ); + SetParent( ImplGetDefaultWindow() ); + } + vcl::LazyDeletor<Window>::Delete( this ); +} + +// ----------------------------------------------------------------------- +void Window::InterceptChildWindowKeyDown( sal_Bool bIntercept ) +{ + if( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->InterceptChildWindowKeyDown( bIntercept ); +} + +// ----------------------------------------------------------------------- + +void Window::MouseMove( const MouseEvent& rMEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_MOUSEMOVE, this, &rMEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbMouseMove = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::MouseButtonDown( const MouseEvent& rMEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_MOUSEBUTTONDOWN, this, &rMEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbMouseButtonDown = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::MouseButtonUp( const MouseEvent& rMEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_MOUSEBUTTONUP, this, &rMEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbMouseButtonUp = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::KeyInput( const KeyEvent& rKEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_KEYINPUT, this, &rKEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbKeyInput = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::KeyUp( const KeyEvent& rKEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_KEYUP, this, &rKEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbKeyUp = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::PrePaint() +{ +} + +// ----------------------------------------------------------------------- + +void Window::Paint( const Rectangle& rRect ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + ImplCallEventListeners( VCLEVENT_WINDOW_PAINT, (void*)&rRect ); +} + +// ----------------------------------------------------------------------- + +void Window::PostPaint() +{ +} + +// ----------------------------------------------------------------------- + +void Window::Draw( OutputDevice*, const Point&, const Size&, ULONG ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::Move() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::Resize() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::Activate() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::Deactivate() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::GetFocus() +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + if ( HasFocus() && mpWindowImpl->mpLastFocusWindow && !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) ) + { + ImplDelData aDogtag( this ); + mpWindowImpl->mpLastFocusWindow->GrabFocus(); + if( aDogtag.IsDelete() ) + return; + } + + NotifyEvent aNEvt( EVENT_GETFOCUS, this ); + Notify( aNEvt ); +} + +// ----------------------------------------------------------------------- + +void Window::LoseFocus() +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + NotifyEvent aNEvt( EVENT_LOSEFOCUS, this ); + Notify( aNEvt ); +} + +// ----------------------------------------------------------------------- + +void Window::RequestHelp( const HelpEvent& rHEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + // Wenn Balloon-Help angefordert wird, dann den Balloon mit dem + // gesetzten Hilfetext anzeigen + if ( rHEvt.GetMode() & HELPMODE_BALLOON ) + { + const XubString* pStr = &(GetHelpText()); + if ( !pStr->Len() ) + pStr = &(GetQuickHelpText()); + if ( !pStr->Len() && ImplGetParent() && !ImplIsOverlapWindow() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + Help::ShowBalloon( this, rHEvt.GetMousePosPixel(), *pStr ); + } + else if ( rHEvt.GetMode() & HELPMODE_QUICK ) + { + const XubString* pStr = &(GetQuickHelpText()); + if ( !pStr->Len() && ImplGetParent() && !ImplIsOverlapWindow() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + { + Point aPos = GetPosPixel(); + if ( ImplGetParent() && !ImplIsOverlapWindow() ) + aPos = ImplGetParent()->OutputToScreenPixel( aPos ); + Rectangle aRect( aPos, GetSizePixel() ); + String aHelpText; + if ( pStr->Len() ) + aHelpText = GetHelpText(); + Help::ShowQuickHelp( this, aRect, *pStr, aHelpText, QUICKHELP_CTRLTEXT ); + } + } + else + { + String aStrHelpId( rtl::OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) ); + if ( aStrHelpId.Len() == 0 && ImplGetParent() ) + ImplGetParent()->RequestHelp( rHEvt ); + else + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + if( aStrHelpId.Len() > 0 ) + pHelp->Start( aStrHelpId, this ); + else + pHelp->Start( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OOO_HELP_INDEX ) ), this ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::Command( const CommandEvent& rCEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + ImplCallEventListeners( VCLEVENT_WINDOW_COMMAND, (void*)&rCEvt ); + + NotifyEvent aNEvt( EVENT_COMMAND, this, &rCEvt ); + if ( !Notify( aNEvt ) ) + mpWindowImpl->mbCommand = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::Tracking( const TrackingEvent& rTEvt ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper ) + pWrapper->Tracking( rTEvt ); +} + +// ----------------------------------------------------------------------- + +void Window::UserEvent( ULONG, void* ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::StateChanged( StateChangedType ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::DataChanged( const DataChangedEvent& ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplNotifyKeyMouseCommandEventListeners( NotifyEvent& rNEvt ) +{ + if( rNEvt.GetType() == EVENT_COMMAND ) + { + const CommandEvent* pCEvt = rNEvt.GetCommandEvent(); + if ( pCEvt->GetCommand() != COMMAND_CONTEXTMENU ) + // non context menu events are not to be notified up the chain + // so we return immediately + return; + + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + // not interested in: The event listeners are already called in ::Command, + // and calling them here a second time doesn't make sense + ; + else + { + CommandEvent aCommandEvent = ImplTranslateCommandEvent( *pCEvt, rNEvt.GetWindow(), this ); + ImplCallEventListeners( VCLEVENT_WINDOW_COMMAND, &aCommandEvent ); + } + } + } + + // #82968# notify event listeners for mouse and key events seperately and + // not in PreNotify ( as for focus listeners ) + // this allows for procesing those events internally first and pass it to + // the toolkit later + + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + if( rNEvt.GetType() == EVENT_MOUSEMOVE ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, (void*)rNEvt.GetMouseEvent() ); + else + { + MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ); + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, &aMouseEvent ); + } + } + } + else if( rNEvt.GetType() == EVENT_MOUSEBUTTONUP ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, (void*)rNEvt.GetMouseEvent() ); + else + { + MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ); + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, &aMouseEvent ); + } + } + } + else if( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, (void*)rNEvt.GetMouseEvent() ); + else + { + MouseEvent aMouseEvent = ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ); + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, &aMouseEvent ); + } + } + } + else if( rNEvt.GetType() == EVENT_KEYINPUT ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_KEYINPUT, (void*)rNEvt.GetKeyEvent() ); + } + else if( rNEvt.GetType() == EVENT_KEYUP ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_KEYUP, (void*)rNEvt.GetKeyEvent() ); + } + + if ( aDelData.IsDelete() ) + return; + ImplRemoveDel( &aDelData ); + + // #106721# check if we're part of a compound control and notify + Window *pParent = ImplGetParent(); + while( pParent ) + { + if( pParent->IsCompoundControl() ) + { + pParent->ImplNotifyKeyMouseCommandEventListeners( rNEvt ); + break; + } + pParent = pParent->ImplGetParent(); + } +} + +// ----------------------------------------------------------------------- + +long Window::PreNotify( NotifyEvent& rNEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + long bDone = FALSE; + if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() ) + bDone = mpWindowImpl->mpParent->PreNotify( rNEvt ); + + if ( !bDone ) + { + if( rNEvt.GetType() == EVENT_GETFOCUS ) + { + BOOL bCompoundFocusChanged = FALSE; + if ( mpWindowImpl->mbCompoundControl && !mpWindowImpl->mbCompoundControlHasFocus && HasChildPathFocus() ) + { + mpWindowImpl->mbCompoundControlHasFocus = TRUE; + bCompoundFocusChanged = TRUE; + } + + if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS ); + } + else if( rNEvt.GetType() == EVENT_LOSEFOCUS ) + { + BOOL bCompoundFocusChanged = FALSE; + if ( mpWindowImpl->mbCompoundControl && mpWindowImpl->mbCompoundControlHasFocus && !HasChildPathFocus() ) + { + mpWindowImpl->mbCompoundControlHasFocus = FALSE ; + bCompoundFocusChanged = TRUE; + } + + if ( bCompoundFocusChanged || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS ); + } + + // #82968# mouse and key events will be notified after processing ( in ImplNotifyKeyMouseCommandEventListeners() )! + // see also ImplHandleMouseEvent(), ImplHandleKey() + + /* + else if( rNEvt.GetType() == EVENT_MOUSEMOVE ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, (void*)rNEvt.GetMouseEvent() ); + else + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEMOVE, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) ); + } + } + else if( rNEvt.GetType() == EVENT_MOUSEBUTTONUP ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, (void*)rNEvt.GetMouseEvent() ); + else + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) ); + } + } + else if( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + { + if ( rNEvt.GetWindow() == this ) + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, (void*)rNEvt.GetMouseEvent() ); + else + ImplCallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, &ImplTranslateMouseEvent( *rNEvt.GetMouseEvent(), rNEvt.GetWindow(), this ) ); + } + } + else if( rNEvt.GetType() == EVENT_KEYINPUT ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_KEYINPUT, (void*)rNEvt.GetKeyEvent() ); + } + else if( rNEvt.GetType() == EVENT_KEYUP ) + { + if ( mpWindowImpl->mbCompoundControl || ( rNEvt.GetWindow() == this ) ) + ImplCallEventListeners( VCLEVENT_WINDOW_KEYUP, (void*)rNEvt.GetKeyEvent() ); + } + */ + } + + return bDone; +} + +// ----------------------------------------------------------------------- + +long Window::Notify( NotifyEvent& rNEvt ) +{ + { // Klammerung, da in diesem Handler das Window zerstoert werden darf + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + } + + long nRet = FALSE; + + // check for docking window + // but do nothing if window is docked and locked + ImplDockingWindowWrapper *pWrapper = ImplGetDockingManager()->GetDockingWindowWrapper( this ); + if( pWrapper && !( !pWrapper->IsFloatingMode() && pWrapper->IsLocked() ) ) + { + if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) + { + const MouseEvent* pMEvt = rNEvt.GetMouseEvent(); + BOOL bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() ); + if ( pMEvt->IsLeft() ) + { + if ( pMEvt->IsMod1() && (pMEvt->GetClicks() == 2) ) + { + // ctrl double click toggles floating mode + pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() ); + return TRUE; + } + else if ( pMEvt->GetClicks() == 1 && bHit) + { + // allow start docking during mouse move + pWrapper->ImplEnableStartDocking(); + return TRUE; + } + } + } + else if ( rNEvt.GetType() == EVENT_MOUSEMOVE ) + { + const MouseEvent* pMEvt = rNEvt.GetMouseEvent(); + BOOL bHit = pWrapper->GetDragArea().IsInside( pMEvt->GetPosPixel() ); + if ( pMEvt->IsLeft() ) + { + // check if a single click initiated this sequence ( ImplStartDockingEnabled() ) + // check if window is docked and + if( pWrapper->ImplStartDockingEnabled() && !pWrapper->IsFloatingMode() && + !pWrapper->IsDocking() && bHit ) + { + Point aPos = pMEvt->GetPosPixel(); + Window* pWindow = rNEvt.GetWindow(); + if ( pWindow != this ) + { + aPos = pWindow->OutputToScreenPixel( aPos ); + aPos = ScreenToOutputPixel( aPos ); + } + pWrapper->ImplStartDocking( aPos ); + } + return TRUE; + } + } + else if( rNEvt.GetType() == EVENT_KEYINPUT ) + { + const KeyCode& rKey = rNEvt.GetKeyEvent()->GetKeyCode(); + if( rKey.GetCode() == KEY_F10 && rKey.GetModifier() && + rKey.IsShift() && rKey.IsMod1() ) + { + pWrapper->SetFloatingMode( !pWrapper->IsFloatingMode() ); + /* At this point the floating toolbar frame does not have the + * input focus since these frames don't get the focus per default + * To enable keyboard handling of this toolbar set the input focus + * to the frame. This needs to be done with ToTop since GrabFocus + * would not notice any change since "this" already has the focus. + */ + if( pWrapper->IsFloatingMode() ) + ToTop( TOTOP_GRABFOCUSONLY ); + return TRUE; + } + } + } + + // Dialog-Steuerung + if ( (GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) == WB_DIALOGCONTROL ) + { + // Wenn Parent auch DialogSteuerung aktiviert hat, uebernimmt dieser die Steuerung + if ( (rNEvt.GetType() == EVENT_KEYINPUT) || (rNEvt.GetType() == EVENT_KEYUP) ) + { + if ( ImplIsOverlapWindow() || + ((ImplGetParent()->GetStyle() & (WB_DIALOGCONTROL | WB_NODIALOGCONTROL)) != WB_DIALOGCONTROL) ) + { + nRet = ImplDlgCtrl( *rNEvt.GetKeyEvent(), rNEvt.GetType() == EVENT_KEYINPUT ); + } + } + else if ( (rNEvt.GetType() == EVENT_GETFOCUS) || (rNEvt.GetType() == EVENT_LOSEFOCUS) ) + { + ImplDlgCtrlFocusChanged( rNEvt.GetWindow(), rNEvt.GetType() == EVENT_GETFOCUS ); + if ( (rNEvt.GetWindow() == this) && (rNEvt.GetType() == EVENT_GETFOCUS) && + !(GetStyle() & WB_TABSTOP) && !(mpWindowImpl->mnDlgCtrlFlags & WINDOW_DLGCTRL_WANTFOCUS) ) + { + USHORT n = 0; + Window* pFirstChild = ImplGetDlgWindow( n, DLGWINDOW_FIRST ); + if ( pFirstChild ) + pFirstChild->ImplControlFocus(); + } + } + } + + if ( !nRet ) + { + if ( mpWindowImpl->mpParent && !ImplIsOverlapWindow() ) + nRet = mpWindowImpl->mpParent->Notify( rNEvt ); + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallEventListeners( ULONG nEvent, void* pData ) +{ + // The implementation was moved to CallEventListeners(), + // because derived classes in svtools must be able to + // call the event listeners and ImplCallEventListeners() + // is not exported. + // TODO: replace ImplCallEventListeners() by CallEventListeners() in vcl + + CallEventListeners( nEvent, pData ); +} + +// ----------------------------------------------------------------------- + +void Window::CallEventListeners( ULONG nEvent, void* pData ) +{ + VclWindowEvent aEvent( this, nEvent, pData ); + + ImplDelData aDelData; + ImplAddDel( &aDelData ); + + ImplGetSVData()->mpApp->ImplCallEventListeners( &aEvent ); + + if ( aDelData.IsDelete() ) + return; + + if ( !mpWindowImpl->maEventListeners.empty() ) + mpWindowImpl->maEventListeners.Call( &aEvent ); + + if ( aDelData.IsDelete() ) + return; + + ImplRemoveDel( &aDelData ); + + Window* pWindow = this; + while ( pWindow ) + { + pWindow->ImplAddDel( &aDelData ); + + if ( !pWindow->mpWindowImpl->maChildEventListeners.empty() ) + pWindow->mpWindowImpl->maChildEventListeners.Call( &aEvent ); + + if ( aDelData.IsDelete() ) + return; + + pWindow->ImplRemoveDel( &aDelData ); + + pWindow = pWindow->GetParent(); + } +} + +void Window::FireVclEvent( VclSimpleEvent* pEvent ) +{ + ImplGetSVData()->mpApp->ImplCallEventListeners(pEvent); +} + +// ----------------------------------------------------------------------- + +void Window::AddEventListener( const Link& rEventListener ) +{ + mpWindowImpl->maEventListeners.push_back( rEventListener ); +} + +// ----------------------------------------------------------------------- + +void Window::RemoveEventListener( const Link& rEventListener ) +{ + mpWindowImpl->maEventListeners.remove( rEventListener ); +} + +// ----------------------------------------------------------------------- + +void Window::AddChildEventListener( const Link& rEventListener ) +{ + mpWindowImpl->maChildEventListeners.push_back( rEventListener ); +} + +// ----------------------------------------------------------------------- + +void Window::RemoveChildEventListener( const Link& rEventListener ) +{ + mpWindowImpl->maChildEventListeners.remove( rEventListener ); +} + +// ----------------------------------------------------------------------- + +ULONG Window::PostUserEvent( ULONG nEvent, void* pEventData ) +{ + ULONG nEventId; + PostUserEvent( nEventId, nEvent, pEventData ); + return nEventId; +} + +// ----------------------------------------------------------------------- + +ULONG Window::PostUserEvent( const Link& rLink, void* pCaller ) +{ + ULONG nEventId; + PostUserEvent( nEventId, rLink, pCaller ); + return nEventId; +} + +// ----------------------------------------------------------------------- + +BOOL Window::PostUserEvent( ULONG& rEventId, ULONG nEvent, void* pEventData ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVEvent* pSVEvent = new ImplSVEvent; + pSVEvent->mnEvent = nEvent; + pSVEvent->mpData = pEventData; + pSVEvent->mpLink = NULL; + pSVEvent->mpWindow = this; + pSVEvent->mbCall = TRUE; + ImplAddDel( &(pSVEvent->maDelData) ); + rEventId = (ULONG)pSVEvent; + if ( mpWindowImpl->mpFrame->PostEvent( pSVEvent ) ) + return TRUE; + else + { + rEventId = 0; + ImplRemoveDel( &(pSVEvent->maDelData) ); + delete pSVEvent; + return FALSE; + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::PostUserEvent( ULONG& rEventId, const Link& rLink, void* pCaller ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVEvent* pSVEvent = new ImplSVEvent; + pSVEvent->mnEvent = 0; + pSVEvent->mpData = pCaller; + pSVEvent->mpLink = new Link( rLink ); + pSVEvent->mpWindow = this; + pSVEvent->mbCall = TRUE; + ImplAddDel( &(pSVEvent->maDelData) ); + rEventId = (ULONG)pSVEvent; + if ( mpWindowImpl->mpFrame->PostEvent( pSVEvent ) ) + return TRUE; + else + { + rEventId = 0; + ImplRemoveDel( &(pSVEvent->maDelData) ); + delete pSVEvent; + return FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Window::RemoveUserEvent( ULONG nUserEvent ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVEvent* pSVEvent = (ImplSVEvent*)nUserEvent; + + DBG_ASSERT( pSVEvent->mpWindow == this, + "Window::RemoveUserEvent(): Event doesn't send to this window or is already removed" ); + DBG_ASSERT( pSVEvent->mbCall, + "Window::RemoveUserEvent(): Event is already removed" ); + + if ( pSVEvent->mpWindow ) + { + pSVEvent->mpWindow->ImplRemoveDel( &(pSVEvent->maDelData) ); + pSVEvent->mpWindow = NULL; + } + + pSVEvent->mbCall = FALSE; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplAsyncStateChangedHdl, void*, pState ) +{ + StateChanged( (StateChangedType)(ULONG)pState ); + return 0; +} + +// ----------------------------------------------------------------------- + +void Window::PostStateChanged( StateChangedType nState ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + PostUserEvent( LINK( this, Window, ImplAsyncStateChangedHdl ), (void*)(ULONG)nState ); +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsLocked( BOOL bChilds ) const +{ + if ( mpWindowImpl->mnLockCount != 0 ) + return TRUE; + + if ( bChilds || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + if ( pChild->IsLocked( TRUE ) ) + return TRUE; + pChild = pChild->mpWindowImpl->mpNext; + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::SetStyle( WinBits nStyle ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mnStyle != nStyle ) + { + mpWindowImpl->mnPrevStyle = mpWindowImpl->mnStyle; + mpWindowImpl->mnStyle = nStyle; + StateChanged( STATE_CHANGE_STYLE ); + } +} + +// ----------------------------------------------------------------------- + +void Window::SetExtendedStyle( WinBits nExtendedStyle ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mnExtendedStyle != nExtendedStyle ) + { + Window* pWindow = ImplGetBorderWindow(); + if( ! pWindow ) + pWindow = this; + if( pWindow->mpWindowImpl->mbFrame ) + { + SalExtStyle nExt = 0; + if( (nExtendedStyle & WB_EXT_DOCUMENT) ) + nExt |= SAL_FRAME_EXT_STYLE_DOCUMENT; + if( (nExtendedStyle & WB_EXT_DOCMODIFIED) ) + nExt |= SAL_FRAME_EXT_STYLE_DOCMODIFIED; + + pWindow->ImplGetFrame()->SetExtendedFrameStyle( nExt ); + } + mpWindowImpl->mnPrevExtendedStyle = mpWindowImpl->mnExtendedStyle; + mpWindowImpl->mnExtendedStyle = nExtendedStyle; + StateChanged( STATE_CHANGE_EXTENDEDSTYLE ); + } +} + +// ----------------------------------------------------------------------- + +SystemWindow* Window::GetSystemWindow() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + const Window* pWin = this; + while ( pWin && !pWin->IsSystemWindow() ) + pWin = pWin->GetParent(); + return (SystemWindow*)pWin; +} + +// ----------------------------------------------------------------------- + +void Window::SetBorderStyle( USHORT nBorderStyle ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + if( nBorderStyle == WINDOW_BORDER_REMOVEBORDER && + ! mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && + mpWindowImpl->mpBorderWindow->mpWindowImpl->mpParent + ) + { + // this is a little awkward: some controls (e.g. svtools ProgressBar) + // cannot avoid getting constructed with WB_BORDER but want to disable + // borders in case of NWF drawing. So they need a method to remove their border window + Window* pBorderWin = mpWindowImpl->mpBorderWindow; + // remove us as border window's client + pBorderWin->mpWindowImpl->mpClientWindow = NULL; + mpWindowImpl->mpBorderWindow = NULL; + mpWindowImpl->mpRealParent = pBorderWin->mpWindowImpl->mpParent; + // reparent us above the border window + SetParent( pBorderWin->mpWindowImpl->mpParent ); + // set us to the position and size of our previous border + Point aBorderPos( pBorderWin->GetPosPixel() ); + Size aBorderSize( pBorderWin->GetSizePixel() ); + SetPosSizePixel( aBorderPos.X(), aBorderPos.Y(), aBorderSize.Width(), aBorderSize.Height() ); + // release border window + delete pBorderWin; + + // set new style bits + SetStyle( GetStyle() & (~WB_BORDER) ); + } + else + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->SetBorderStyle( nBorderStyle ); + else + mpWindowImpl->mpBorderWindow->SetBorderStyle( nBorderStyle ); + } + } +} + +// ----------------------------------------------------------------------- + +USHORT Window::GetBorderStyle() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW ) + return ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->GetBorderStyle(); + else + return mpWindowImpl->mpBorderWindow->GetBorderStyle(); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +long Window::CalcTitleWidth() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + if ( mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW ) + return ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->CalcTitleWidth(); + else + return mpWindowImpl->mpBorderWindow->CalcTitleWidth(); + } + else if ( mpWindowImpl->mbFrame && (mpWindowImpl->mnStyle & WB_MOVEABLE) ) + { + // Fuer Frame-Fenster raten wir die Breite, da wir den Border fuer + // externe Dialoge nicht kennen + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Font aFont = GetFont(); + ((Window*)this)->SetPointFont( rStyleSettings.GetTitleFont() ); + long nTitleWidth = GetTextWidth( GetText() ); + ((Window*)this)->SetFont( aFont ); + nTitleWidth += rStyleSettings.GetTitleHeight() * 3; + nTitleWidth += rStyleSettings.GetBorderSize() * 2; + nTitleWidth += 10; + return nTitleWidth; + } + + return 0; +} + +// ----------------------------------------------------------------------- + +void Window::EnableClipSiblings( BOOL bClipSiblings ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->EnableClipSiblings( bClipSiblings ); + + mpWindowImpl->mbClipSiblings = bClipSiblings; +} + +// ----------------------------------------------------------------------- + +void Window::SetMouseTransparent( BOOL bTransparent ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetMouseTransparent( bTransparent ); + + if( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->SetMouseTransparent( bTransparent ); + + mpWindowImpl->mbMouseTransparent = bTransparent; +} + +// ----------------------------------------------------------------------- + +void Window::SetPaintTransparent( BOOL bTransparent ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + // transparency is not useful for frames as the background would have to be provided by a different frame + if( bTransparent && mpWindowImpl->mbFrame ) + return; + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetPaintTransparent( bTransparent ); + + mpWindowImpl->mbPaintTransparent = bTransparent; +} + +// ----------------------------------------------------------------------- + +void Window::SetInputContext( const InputContext& rInputContext ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mpWindowImpl->maInputContext = rInputContext; + if ( !mpWindowImpl->mbInFocusHdl && HasFocus() ) + ImplNewInputContext(); +} + +// ----------------------------------------------------------------------- + +void Window::EndExtTextInput( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbExtTextInput ) + ImplGetFrame()->EndExtTextInput( nFlags ); +} + +// ----------------------------------------------------------------------- + +void Window::SetCursorRect( const Rectangle* pRect, long nExtTextInputWidth ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplWinData* pWinData = ImplGetWinData(); + if ( pWinData->mpCursorRect ) + { + if ( pRect ) + *pWinData->mpCursorRect = *pRect; + else + { + delete pWinData->mpCursorRect; + pWinData->mpCursorRect = NULL; + } + } + else + { + if ( pRect ) + pWinData->mpCursorRect = new Rectangle( *pRect ); + } + + pWinData->mnCursorExtWidth = nExtTextInputWidth; + +} + +// ----------------------------------------------------------------------- + +const Rectangle* Window::GetCursorRect() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplWinData* pWinData = ImplGetWinData(); + return pWinData->mpCursorRect; +} + +// ----------------------------------------------------------------------- + +long Window::GetCursorExtTextInputWidth() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplWinData* pWinData = ImplGetWinData(); + return pWinData->mnCursorExtWidth; +} + +// ----------------------------------------------------------------------- +void Window::SetSettings( const AllSettings& rSettings ) +{ + SetSettings( rSettings, FALSE ); +} + +void Window::SetSettings( const AllSettings& rSettings, BOOL bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->SetSettings( rSettings, FALSE ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) && + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->SetSettings( rSettings, TRUE ); + } + + AllSettings aOldSettings = maSettings; + OutputDevice::SetSettings( rSettings ); + ULONG nChangeFlags = aOldSettings.GetChangeFlags( rSettings ); + + // AppFont-Aufloesung und DPI-Aufloesung neu berechnen + ImplInitResolutionSettings(); + + if ( nChangeFlags ) + { + DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &aOldSettings, nChangeFlags ); + DataChanged( aDCEvt ); + } + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->SetSettings( rSettings, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::UpdateSettings( const AllSettings& rSettings, BOOL bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->UpdateSettings( rSettings, FALSE ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) && + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->UpdateSettings( rSettings, TRUE ); + } + + AllSettings aOldSettings = maSettings; + ULONG nChangeFlags = maSettings.Update( maSettings.GetWindowUpdate(), rSettings ); + nChangeFlags |= SETTINGS_IN_UPDATE_SETTINGS; // Set this flag so the receiver of the data changed + // event can distinguish between the changing of global + // setting and a local change ( with SetSettings ) + + // AppFont-Aufloesung und DPI-Aufloesung neu berechnen + ImplInitResolutionSettings(); + + /* #i73785# + * do not overwrite a WheelBehavior with false + * this looks kind of a hack, but WheelBehavior + * is always a local change, not a system property, + * so we can spare all our users the hassle of reacting on + * this in their respective DataChanged. + */ + MouseSettings aSet( maSettings.GetMouseSettings() ); + aSet.SetWheelBehavior( aOldSettings.GetMouseSettings().GetWheelBehavior() ); + maSettings.SetMouseSettings( aSet ); + + if( (nChangeFlags & SETTINGS_STYLE) && IsBackground() ) + { + Wallpaper aWallpaper = GetBackground(); + if( !aWallpaper.IsBitmap() && !aWallpaper.IsGradient() ) + { + if ( mpWindowImpl->mnStyle & WB_3DLOOK ) + SetBackground( Wallpaper( rSettings.GetStyleSettings().GetFaceColor() ) ); + else + SetBackground( Wallpaper( rSettings.GetStyleSettings().GetWindowColor() ) ); + } + } + + if ( nChangeFlags ) + { + DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &aOldSettings, nChangeFlags ); + DataChanged( aDCEvt ); + // notify data change handler + ImplCallEventListeners( VCLEVENT_WINDOW_DATACHANGED, &aDCEvt); + } + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->UpdateSettings( rSettings, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::NotifyAllChilds( DataChangedEvent& rDCEvt ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + DataChanged( rDCEvt ); + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->NotifyAllChilds( rDCEvt ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +void Window::SetPointFont( const Font& rFont ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Font aFont = rFont; + ImplPointToLogic( aFont ); + SetFont( aFont ); +} + +// ----------------------------------------------------------------------- + +Font Window::GetPointFont() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Font aFont = GetFont(); + ImplLogicToPoint( aFont ); + return aFont; +} + +// ----------------------------------------------------------------------- + +// TODO: remove in next incompatible build +void Window::GetFontResolution( sal_Int32& nDPIX, sal_Int32& nDPIY ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + nDPIX = mpWindowImpl->mpFrameData->mnDPIX; + nDPIY = mpWindowImpl->mpFrameData->mnDPIY; +} + +// ----------------------------------------------------------------------- + +void Window::SetParentClipMode( USHORT nMode ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetParentClipMode( nMode ); + else + { + if ( !ImplIsOverlapWindow() ) + { + mpWindowImpl->mnParentClipMode = nMode; + if ( nMode & PARENTCLIPMODE_CLIP ) + mpWindowImpl->mpParent->mpWindowImpl->mbClipChildren = TRUE; + } + } +} + +// ----------------------------------------------------------------------- + +USHORT Window::GetParentClipMode() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + return mpWindowImpl->mpBorderWindow->GetParentClipMode(); + else + return mpWindowImpl->mnParentClipMode; +} + +// ----------------------------------------------------------------------- + +void Window::SetWindowRegionPixel() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetWindowRegionPixel(); + else if( mpWindowImpl->mbFrame ) + { + mpWindowImpl->maWinRegion = Region( REGION_NULL); + mpWindowImpl->mbWinRegion = FALSE; + mpWindowImpl->mpFrame->ResetClipRegion(); + } + else + { + if ( mpWindowImpl->mbWinRegion ) + { + mpWindowImpl->maWinRegion = Region( REGION_NULL ); + mpWindowImpl->mbWinRegion = FALSE; + ImplSetClipFlag(); + + if ( IsReallyVisible() ) + { + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev ) + ImplDeleteOverlapBackground(); + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aRegion( aRect ); + ImplInvalidateParentFrameRegion( aRegion ); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::SetWindowRegionPixel( const Region& rRegion ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetWindowRegionPixel( rRegion ); + else if( mpWindowImpl->mbFrame ) + { + if( rRegion.GetType() != REGION_NULL ) + { + mpWindowImpl->maWinRegion = rRegion; + mpWindowImpl->mbWinRegion = ! rRegion.IsEmpty(); + if( mpWindowImpl->mbWinRegion ) + { + // ClipRegion setzen/updaten + long nX; + long nY; + long nWidth; + long nHeight; + ULONG nRectCount; + ImplRegionInfo aInfo; + BOOL bRegionRect; + + nRectCount = mpWindowImpl->maWinRegion.GetRectCount(); + mpWindowImpl->mpFrame->BeginSetClipRegion( nRectCount ); + bRegionRect = mpWindowImpl->maWinRegion.ImplGetFirstRect( aInfo, nX, nY, nWidth, nHeight ); + while ( bRegionRect ) + { + mpWindowImpl->mpFrame->UnionClipRegion( nX, nY, nWidth, nHeight ); + bRegionRect = mpWindowImpl->maWinRegion.ImplGetNextRect( aInfo, nX, nY, nWidth, nHeight ); + } + mpWindowImpl->mpFrame->EndSetClipRegion(); + } + else + SetWindowRegionPixel(); + } + else + SetWindowRegionPixel(); + } + else + { + BOOL bInvalidate = FALSE; + + if ( rRegion.GetType() == REGION_NULL ) + { + if ( mpWindowImpl->mbWinRegion ) + { + mpWindowImpl->maWinRegion = Region( REGION_NULL ); + mpWindowImpl->mbWinRegion = FALSE; + ImplSetClipFlag(); + bInvalidate = TRUE; + } + } + else + { + mpWindowImpl->maWinRegion = rRegion; + mpWindowImpl->mbWinRegion = TRUE; + ImplSetClipFlag(); + bInvalidate = TRUE; + } + + if ( IsReallyVisible() ) + { + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mpSaveBackDev ) + ImplDeleteOverlapBackground(); + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + Rectangle aRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aRegion( aRect ); + ImplInvalidateParentFrameRegion( aRegion ); + } + } +} + +// ----------------------------------------------------------------------- + +const Region& Window::GetWindowRegionPixel() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + return mpWindowImpl->mpBorderWindow->GetWindowRegionPixel(); + else + return mpWindowImpl->maWinRegion; +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsWindowRegionPixel() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + return mpWindowImpl->mpBorderWindow->IsWindowRegionPixel(); + else + return mpWindowImpl->mbWinRegion; +} + +// ----------------------------------------------------------------------- + +Region Window::GetWindowClipRegionPixel( USHORT nFlags ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Region aWinClipRegion; + + if ( nFlags & WINDOW_GETCLIPREGION_NOCHILDREN ) + { + if ( mpWindowImpl->mbInitWinClipRegion ) + ((Window*)this)->ImplInitWinClipRegion(); + aWinClipRegion = mpWindowImpl->maWinClipRegion; + } + else + { + Region* pWinChildClipRegion = ((Window*)this)->ImplGetWinChildClipRegion(); + aWinClipRegion = *pWinChildClipRegion; + // --- RTL --- remirror clip region before passing it to somebody + if( ImplIsAntiparallel() ) + ImplReMirror( aWinClipRegion ); + } + + if ( nFlags & WINDOW_GETCLIPREGION_NULL ) + { + Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Region aWinRegion( aWinRect ); + + if ( aWinRegion == aWinClipRegion ) + aWinClipRegion.SetNull(); + } + + aWinClipRegion.Move( -mnOutOffX, -mnOutOffY ); + + return aWinClipRegion; +} + +// ----------------------------------------------------------------------- + +Region Window::GetPaintRegion() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpPaintRegion ) + { + Region aRegion = *mpWindowImpl->mpPaintRegion; + aRegion.Move( -mnOutOffX, -mnOutOffY ); + return PixelToLogic( aRegion ); + } + else + { + Region aPaintRegion( REGION_NULL ); + return aPaintRegion; + } +} + +// ----------------------------------------------------------------------- + +void Window::ExpandPaintClipRegion( const Region& rRegion ) +{ + if( mpWindowImpl->mpPaintRegion ) + { + Region aPixRegion = LogicToPixel( rRegion ); + Region aDevPixRegion = ImplPixelToDevicePixel( aPixRegion ); + + Region aWinChildRegion = *ImplGetWinChildClipRegion(); + // --- RTL -- only this region is in frame coordinates, so re-mirror it + if( ImplIsAntiparallel() ) + ImplReMirror( aWinChildRegion ); + aDevPixRegion.Intersect( aWinChildRegion ); + if( ! aDevPixRegion.IsEmpty() ) + { + mpWindowImpl->mpPaintRegion->Union( aDevPixRegion ); + mbInitClipRegion = TRUE; + } + } +} + +// ----------------------------------------------------------------------- + +static SystemWindow *ImplGetLastSystemWindow( Window *pWin ) +{ + // get the most top-level system window, the one that contains the taskpanelist + SystemWindow *pSysWin = NULL; + if( !pWin ) + return pSysWin; + Window *pMyParent = pWin; + while ( pMyParent ) + { + if ( pMyParent->IsSystemWindow() ) + pSysWin = (SystemWindow*)pMyParent; + pMyParent = pMyParent->GetParent(); + } + return pSysWin; +} + +void Window::SetParent( Window* pNewParent ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + DBG_ASSERT( pNewParent, "Window::SetParent(): pParent == NULL" ); + DBG_ASSERT( pNewParent != this, "someone tried to reparent a window to itself" ); + + if( pNewParent == this ) + return; + + // check if the taskpanelist would change and move the window pointer accordingly + SystemWindow *pSysWin = ImplGetLastSystemWindow(this); + SystemWindow *pNewSysWin = NULL; + BOOL bChangeTaskPaneList = FALSE; + if( pSysWin && pSysWin->ImplIsInTaskPaneList( this ) ) + { + pNewSysWin = ImplGetLastSystemWindow( pNewParent ); + if( pNewSysWin && pNewSysWin != pSysWin ) + { + bChangeTaskPaneList = TRUE; + pSysWin->GetTaskPaneList()->RemoveWindow( this ); + } + } + // remove ownerdraw decorated windows from list in the top-most frame window + if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame ) + { + ::std::vector< Window* >& rList = ImplGetOwnerDrawList(); + ::std::vector< Window* >::iterator p; + p = ::std::find( rList.begin(), rList.end(), this ); + if( p != rList.end() ) + rList.erase( p ); + } + + ImplSetFrameParent( pNewParent ); + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpRealParent = pNewParent; + mpWindowImpl->mpBorderWindow->SetParent( pNewParent ); + return; + } + + if ( mpWindowImpl->mpParent == pNewParent ) + return; + + if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetParent( pNewParent->mpWindowImpl->mpFrame ); + + BOOL bVisible = IsVisible(); + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // Testen, ob sich das Overlap-Window aendert + Window* pOldOverlapWindow; + Window* pNewOverlapWindow = NULL; + if ( ImplIsOverlapWindow() ) + pOldOverlapWindow = NULL; + else + { + pNewOverlapWindow = pNewParent->ImplGetFirstOverlapWindow(); + if ( mpWindowImpl->mpOverlapWindow != pNewOverlapWindow ) + pOldOverlapWindow = mpWindowImpl->mpOverlapWindow; + else + pOldOverlapWindow = NULL; + } + + // Fenster in der Hirachie umsetzen + BOOL bFocusOverlapWin = HasChildPathFocus( TRUE ); + BOOL bFocusWin = HasChildPathFocus(); + BOOL bNewFrame = pNewParent->mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow; + if ( bNewFrame ) + { + if ( mpWindowImpl->mpFrameData->mpFocusWin ) + { + if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpFocusWin ) ) + mpWindowImpl->mpFrameData->mpFocusWin = NULL; + } + if ( mpWindowImpl->mpFrameData->mpMouseMoveWin ) + { + if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseMoveWin ) ) + mpWindowImpl->mpFrameData->mpMouseMoveWin = NULL; + } + if ( mpWindowImpl->mpFrameData->mpMouseDownWin ) + { + if ( IsWindowOrChild( mpWindowImpl->mpFrameData->mpMouseDownWin ) ) + mpWindowImpl->mpFrameData->mpMouseDownWin = NULL; + } + } + ImplRemoveWindow( bNewFrame ); + ImplInsertWindow( pNewParent ); + if ( mpWindowImpl->mnParentClipMode & PARENTCLIPMODE_CLIP ) + pNewParent->mpWindowImpl->mbClipChildren = TRUE; + ImplUpdateWindowPtr(); + if ( ImplUpdatePos() ) + ImplUpdateSysObjPos(); + + // Wenn sich das Overlap-Window geaendert hat, dann muss getestet werden, + // ob auch OverlapWindow die das Child-Fenster als Parent gehabt haben + // in der Window-Hirachie umgesetzt werden muessen + if ( ImplIsOverlapWindow() ) + { + if ( bNewFrame ) + { + Window* pOverlapWindow = mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow ) + { + Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame ); + pOverlapWindow = pNextOverlapWindow; + } + } + } + else if ( pOldOverlapWindow ) + { + // Focus-Save zuruecksetzen + if ( bFocusWin || + (pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow && + IsWindowOrChild( pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow )) ) + pOldOverlapWindow->mpWindowImpl->mpLastFocusWindow = NULL; + + Window* pOverlapWindow = pOldOverlapWindow->mpWindowImpl->mpFirstOverlap; + while ( pOverlapWindow ) + { + Window* pNextOverlapWindow = pOverlapWindow->mpWindowImpl->mpNext; + if ( ImplIsRealParentPath( pOverlapWindow->ImplGetWindow() ) ) + pOverlapWindow->ImplUpdateOverlapWindowPtr( bNewFrame ); + pOverlapWindow = pNextOverlapWindow; + } + + // Activate-Status beim naechsten Overlap-Window updaten + if ( HasChildPathFocus( TRUE ) ) + ImplCallFocusChangeActivate( pNewOverlapWindow, pOldOverlapWindow ); + } + + // Activate-Status mit umsetzen + if ( bNewFrame ) + { + if ( (GetType() == WINDOW_BORDERWINDOW) && + (ImplGetWindow()->GetType() == WINDOW_FLOATINGWINDOW) ) + ((ImplBorderWindow*)this)->SetDisplayActive( mpWindowImpl->mpFrameData->mbHasFocus ); + } + + // Focus evtl. auf den neuen Frame umsetzen, wenn FocusWindow mit + // SetParent() umgesetzt wird + if ( bFocusOverlapWin ) + { + mpWindowImpl->mpFrameData->mpFocusWin = Application::GetFocusWindow(); + if ( !mpWindowImpl->mpFrameData->mbHasFocus ) + { + mpWindowImpl->mpFrame->ToTop( 0 ); + } + } + + // Assure DragSource and DropTarget members are created + if ( bNewFrame ) + { + GetDropTarget(); + } + + if( bChangeTaskPaneList ) + pNewSysWin->GetTaskPaneList()->AddWindow( this ); + + if( (GetStyle() & WB_OWNERDRAWDECORATION) && mpWindowImpl->mbFrame ) + ImplGetOwnerDrawList().push_back( this ); + + if ( bVisible ) + Show( TRUE, SHOW_NOFOCUSCHANGE | SHOW_NOACTIVATE ); +} + +// ----------------------------------------------------------------------- + +void Window::Show( BOOL bVisible, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbVisible == bVisible ) + return; + + ImplDelData aDogTag( this ); + + BOOL bRealVisibilityChanged = FALSE; + mpWindowImpl->mbVisible = (bVisible != 0); + + if ( !bVisible ) + { + ImplHideAllOverlaps(); + if( aDogTag.IsDelete() ) + return; + + if ( mpWindowImpl->mpBorderWindow ) + { + BOOL bOldUpdate = mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate; + if ( mpWindowImpl->mbNoParentUpdate ) + mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = TRUE; + mpWindowImpl->mpBorderWindow->Show( FALSE, nFlags ); + mpWindowImpl->mpBorderWindow->mpWindowImpl->mbNoParentUpdate = bOldUpdate; + } + else if ( mpWindowImpl->mbFrame ) + { + mpWindowImpl->mbSuppressAccessibilityEvents = TRUE; + mpWindowImpl->mpFrame->Show( FALSE, FALSE ); + } + + StateChanged( STATE_CHANGE_VISIBLE ); + + if ( mpWindowImpl->mbReallyVisible ) + { + Region aInvRegion( REGION_EMPTY ); + BOOL bSaveBack = FALSE; + + if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame ) + { + if ( ImplRestoreOverlapBackground( aInvRegion ) ) + bSaveBack = TRUE; + } + + if ( !bSaveBack ) + { + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + aInvRegion = mpWindowImpl->maWinClipRegion; + } + + if( aDogTag.IsDelete() ) + return; + + bRealVisibilityChanged = mpWindowImpl->mbReallyVisible; + ImplResetReallyVisible(); + ImplSetClipFlag(); + + if ( ImplIsOverlapWindow() && !mpWindowImpl->mbFrame ) + { + // Focus umsetzen + if ( !(nFlags & SHOW_NOFOCUSCHANGE) && HasChildPathFocus() ) + { + if ( mpWindowImpl->mpOverlapWindow->IsEnabled() && + mpWindowImpl->mpOverlapWindow->IsInputEnabled() && + ! mpWindowImpl->mpOverlapWindow->IsInModalMode() + ) + mpWindowImpl->mpOverlapWindow->GrabFocus(); + } + } + + if ( !mpWindowImpl->mbFrame ) + { + if( mpWindowImpl->mpWinData && mpWindowImpl->mpWinData->mbEnableNativeWidget ) + { + /* + * #i48371# native theming: some themes draw outside the control + * area we tell them to (bad thing, but we cannot do much about it ). + * On hiding these controls they get invalidated with their window rectangle + * which leads to the parts outside the control area being left and not + * invalidated. Workaround: invalidate an area on the parent, too + */ + const int workaround_border = 5; + Rectangle aBounds( aInvRegion.GetBoundRect() ); + aBounds.Left() -= workaround_border; + aBounds.Top() -= workaround_border; + aBounds.Right() += workaround_border; + aBounds.Bottom() += workaround_border; + aInvRegion = aBounds; + } + if ( !mpWindowImpl->mbNoParentUpdate && !(nFlags & SHOW_NOPARENTUPDATE) ) + { + if ( !aInvRegion.IsEmpty() ) + ImplInvalidateParentFrameRegion( aInvRegion ); + } + ImplGenerateMouseMove(); + } + } + } + else + { + // inherit native widget flag for form controls + // required here, because frames never show up in the child hierarchy - which should be fixed.... + // eg, the drop down of a combobox which is a system floating window + if( mpWindowImpl->mbFrame && GetParent() && GetParent()->IsCompoundControl() && + GetParent()->IsNativeWidgetEnabled() != IsNativeWidgetEnabled() ) + EnableNativeWidget( GetParent()->IsNativeWidgetEnabled() ); + + if ( mpWindowImpl->mbCallMove ) + { + ImplCallMove(); + } + if ( mpWindowImpl->mbCallResize ) + { + ImplCallResize(); + } + + StateChanged( STATE_CHANGE_VISIBLE ); + + Window* pTestParent; + if ( ImplIsOverlapWindow() ) + pTestParent = mpWindowImpl->mpOverlapWindow; + else + pTestParent = ImplGetParent(); + if ( mpWindowImpl->mbFrame || pTestParent->mpWindowImpl->mbReallyVisible ) + { + // Wenn ein Window gerade sichtbar wird, schicken wir allen + // Child-Fenstern ein StateChanged, damit diese sich + // initialisieren koennen + ImplCallInitShow(); + + // Wenn es ein SystemWindow ist, dann kommt es auch automatisch + // nach vorne, wenn es gewuenscht ist + if ( ImplIsOverlapWindow() && !(nFlags & SHOW_NOACTIVATE) ) + { + ImplStartToTop(( nFlags & SHOW_FOREGROUNDTASK ) ? TOTOP_FOREGROUNDTASK : 0 ); + ImplFocusToTop( 0, FALSE ); + } + + // Hintergrund sichern + if ( mpWindowImpl->mpOverlapData && mpWindowImpl->mpOverlapData->mbSaveBack ) + ImplSaveOverlapBackground(); + // adjust mpWindowImpl->mbReallyVisible + bRealVisibilityChanged = !mpWindowImpl->mbReallyVisible; + ImplSetReallyVisible(); + + // Dafuer sorgen, das Clip-Rechtecke neu berechnet werden + ImplSetClipFlag(); + + if ( !mpWindowImpl->mbFrame ) + { + USHORT nInvalidateFlags = INVALIDATE_CHILDREN; + if( ! IsPaintTransparent() ) + nInvalidateFlags |= INVALIDATE_NOTRANSPARENT; + ImplInvalidate( NULL, nInvalidateFlags ); + ImplGenerateMouseMove(); + } + } + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->Show( TRUE, nFlags ); + else if ( mpWindowImpl->mbFrame ) + { + ImplSVData* pSVData = ImplGetSVData(); + // #106431#, hide SplashScreen + if( pSVData->mpIntroWindow && !ImplIsWindowOrChild( pSVData->mpIntroWindow ) ) + pSVData->mpIntroWindow->Hide(); + + //DBG_ASSERT( !mpWindowImpl->mbSuppressAccessibilityEvents, "Window::Show() - Frame reactivated"); + mpWindowImpl->mbSuppressAccessibilityEvents = FALSE; + + mpWindowImpl->mbPaintFrame = TRUE; + BOOL bNoActivate = (nFlags & (SHOW_NOACTIVATE|SHOW_NOFOCUSCHANGE)) ? TRUE : FALSE; + mpWindowImpl->mpFrame->Show( TRUE, bNoActivate ); + if( aDogTag.IsDelete() ) + return; + + // Query the correct size of the window, if we are waiting for + // a system resize + if ( mpWindowImpl->mbWaitSystemResize ) + { + long nOutWidth; + long nOutHeight; + mpWindowImpl->mpFrame->GetClientSize( nOutWidth, nOutHeight ); + ImplHandleResize( this, nOutWidth, nOutHeight ); + } + } + + if( aDogTag.IsDelete() ) + return; + +#ifdef DBG_UTIL + if ( IsDialog() || (GetType() == WINDOW_TABPAGE) || (GetType() == WINDOW_DOCKINGWINDOW) ) + { + DBG_DIALOGTEST( this ); + } +#endif + + ImplShowAllOverlaps(); + } + + if( aDogTag.IsDelete() ) + return; + // invalidate all saved backgrounds + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + // the SHOW/HIDE events also serve as indicators to send child creation/destroy events to the access bridge + // However, the access bridge only uses this event if the data member is not NULL (it's kind of a hack that + // we re-use the SHOW/HIDE events this way, with this particular semantics). + // Since #104887#, the notifications for the access bridge are done in Impl(Set|Reset)ReallyVisible. Here, we + // now only notify with a NULL data pointer, for all other clients except the access bridge. + if ( !bRealVisibilityChanged ) + ImplCallEventListeners( mpWindowImpl->mbVisible ? VCLEVENT_WINDOW_SHOW : VCLEVENT_WINDOW_HIDE, NULL ); + if( aDogTag.IsDelete() ) + return; + + // #107575#, if a floating windows is shown that grabs the focus, we have to notify the toolkit about it + // ImplGrabFocus() is not called in this case + // Because this might lead to problems the task will be shifted to 6.y + // Note: top-level context menues are registered at the access bridge after being shown, + // so this will probably not help here.... + /* + if( mpWindowImpl->mbFloatWin && ((FloatingWindow*) this )->GrabsFocus() ) + { + ImplSVData* pSVData = ImplGetSVData(); + if( !mpWindowImpl->mbVisible ) + { + ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS ); + if( pSVData->maWinData.mpFocusWin ) + pSVData->maWinData.mpFocusWin->ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS ); + } + else + { + if( pSVData->maWinData.mpFocusWin ) + pSVData->maWinData.mpFocusWin->ImplCallEventListeners( VCLEVENT_WINDOW_LOSEFOCUS ); + ImplCallEventListeners( VCLEVENT_WINDOW_GETFOCUS ); + } + } + */ +} + +// ----------------------------------------------------------------------- + +Size Window::GetSizePixel() const +{ + // #i43257# trigger pending resize handler to assure correct window sizes + if( mpWindowImpl->mpFrameData->maResizeTimer.IsActive() ) + { + ImplDelData aDogtag( this ); + mpWindowImpl->mpFrameData->maResizeTimer.Stop(); + mpWindowImpl->mpFrameData->maResizeTimer.GetTimeoutHdl().Call( NULL ); + if( aDogtag.IsDelete() ) + return Size(0,0); + } + + return Size( mnOutWidth+mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder, + mnOutHeight+mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder ); +} + +void Window::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, + sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const +{ + rLeftBorder = mpWindowImpl->mnLeftBorder; + rTopBorder = mpWindowImpl->mnTopBorder; + rRightBorder = mpWindowImpl->mnRightBorder; + rBottomBorder = mpWindowImpl->mnBottomBorder; +} + + +// ----------------------------------------------------------------------- + +void Window::Enable( bool bEnable, bool bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !bEnable ) + { + // Wenn ein Fenster disablte wird, wird automatisch der Tracking-Modus + // beendet oder der Capture geklaut + if ( IsTracking() ) + EndTracking( ENDTRACK_CANCEL ); + if ( IsMouseCaptured() ) + ReleaseMouse(); + // Wenn Fenster den Focus hat und in der Dialog-Steuerung enthalten, + // wird versucht, den Focus auf das naechste Control weiterzuschalten + // mpWindowImpl->mbDisabled darf erst nach Aufruf von ImplDlgCtrlNextWindow() gesetzt + // werden. Ansonsten muss ImplDlgCtrlNextWindow() umgestellt werden + if ( HasFocus() ) + ImplDlgCtrlNextWindow(); + } + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->Enable( bEnable, FALSE ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) && + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->Enable( bEnable, TRUE ); + } + + // #i56102# restore app focus win in case the + // window was disabled when the frame focus changed + ImplSVData* pSVData = ImplGetSVData(); + if( bEnable && + pSVData->maWinData.mpFocusWin == NULL && + mpWindowImpl->mpFrameData->mbHasFocus && + mpWindowImpl->mpFrameData->mpFocusWin == this ) + pSVData->maWinData.mpFocusWin = this; + + if ( mpWindowImpl->mbDisabled != !bEnable ) + { + mpWindowImpl->mbDisabled = !bEnable; + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->Enable( bEnable && !mpWindowImpl->mbInputDisabled ); +// if ( mpWindowImpl->mbFrame ) +// mpWindowImpl->mpFrame->Enable( bEnable && !mpWindowImpl->mbInputDisabled ); + StateChanged( STATE_CHANGE_ENABLE ); + + ImplCallEventListeners( bEnable ? VCLEVENT_WINDOW_ENABLED : VCLEVENT_WINDOW_DISABLED ); + } + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->Enable( bEnable, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } + + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); +} + +// ----------------------------------------------------------------------- + +void Window::SetCallHandlersOnInputDisabled( bool bCall ) +{ + mpWindowImpl->mbCallHandlersDuringInputDisabled = bCall ? TRUE : FALSE; + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->SetCallHandlersOnInputDisabled( bCall ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +// ----------------------------------------------------------------------- + +bool Window::IsCallHandlersOnInputDisabled() const +{ + return mpWindowImpl->mbCallHandlersDuringInputDisabled ? true : false; +} + +// ----------------------------------------------------------------------- + +void Window::EnableInput( BOOL bEnable, BOOL bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + BOOL bNotify = (bEnable != mpWindowImpl->mbInputDisabled); + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->EnableInput( bEnable, FALSE ); + if ( (mpWindowImpl->mpBorderWindow->GetType() == WINDOW_BORDERWINDOW) && + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow ) + ((ImplBorderWindow*)mpWindowImpl->mpBorderWindow)->mpMenuBarWindow->EnableInput( bEnable, TRUE ); + } + + if ( (! bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled) || + ( bEnable && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled) ) + { + // Wenn ein Fenster disablte wird, wird automatisch der + // Tracking-Modus beendet oder der Capture geklaut + if ( !bEnable ) + { + if ( IsTracking() ) + EndTracking( ENDTRACK_CANCEL ); + if ( IsMouseCaptured() ) + ReleaseMouse(); + } + + if ( mpWindowImpl->mbInputDisabled != !bEnable ) + { + mpWindowImpl->mbInputDisabled = !bEnable; + if ( mpWindowImpl->mpSysObj ) + mpWindowImpl->mpSysObj->Enable( !mpWindowImpl->mbDisabled && bEnable ); +// if ( mpWindowImpl->mbFrame ) +// mpWindowImpl->mpFrame->Enable( !mpWindowImpl->mbDisabled && bEnable ); + } + } + + // #i56102# restore app focus win in case the + // window was disabled when the frame focus changed + ImplSVData* pSVData = ImplGetSVData(); + if( bEnable && + pSVData->maWinData.mpFocusWin == NULL && + mpWindowImpl->mpFrameData->mbHasFocus && + mpWindowImpl->mpFrameData->mpFocusWin == this ) + pSVData->maWinData.mpFocusWin = this; + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->EnableInput( bEnable, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } + + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); + + // #104827# notify parent + if ( bNotify ) + { + NotifyEvent aNEvt( bEnable ? EVENT_INPUTENABLE : EVENT_INPUTDISABLE, this ); + Notify( aNEvt ); + } +} + +// ----------------------------------------------------------------------- + +void Window::EnableInput( BOOL bEnable, BOOL bChild, BOOL bSysWin, + const Window* pExcludeWindow ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + EnableInput( bEnable, bChild ); + if ( bSysWin ) + { + // pExculeWindow is the first Overlap-Frame --> if this + // shouldn't be the case, than this must be changed in dialog.cxx + if( pExcludeWindow ) + pExcludeWindow = pExcludeWindow->ImplGetFirstOverlapWindow(); + Window* pSysWin = mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mpFirstOverlap; + while ( pSysWin ) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pSysWin, TRUE ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, than change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pSysWin, TRUE ) ) + pSysWin->EnableInput( bEnable, bChild ); + } + pSysWin = pSysWin->mpWindowImpl->mpNextOverlap; + } + + // enable/disable floating system windows as well + Window* pFrameWin = ImplGetSVData()->maWinData.mpFirstFrame; + while ( pFrameWin ) + { + if( pFrameWin->ImplIsFloatingWindow() ) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( pFrameWin, TRUE ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, than change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( pFrameWin, TRUE ) ) + pFrameWin->EnableInput( bEnable, bChild ); + } + } + pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + + // the same for ownerdraw floating windows + if( mpWindowImpl->mbFrame ) + { + ::std::vector< Window* >& rList = mpWindowImpl->mpFrameData->maOwnerDrawList; + ::std::vector< Window* >::iterator p = rList.begin(); + while( p != rList.end() ) + { + // Is Window in the path from this window + if ( ImplGetFirstOverlapWindow()->ImplIsWindowOrChild( (*p), TRUE ) ) + { + // Is Window not in the exclude window path or not the + // exclude window, than change the status + if ( !pExcludeWindow || !pExcludeWindow->ImplIsWindowOrChild( (*p), TRUE ) ) + (*p)->EnableInput( bEnable, bChild ); + } + p++; + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::AlwaysEnableInput( BOOL bAlways, BOOL bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->AlwaysEnableInput( bAlways, FALSE ); + + if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputEnabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputEnabled; + + if ( bAlways ) + EnableInput( TRUE, FALSE ); + } + else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputNone; + } + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->AlwaysEnableInput( bAlways, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::AlwaysDisableInput( BOOL bAlways, BOOL bChild ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->AlwaysDisableInput( bAlways, FALSE ); + + if( bAlways && mpWindowImpl->meAlwaysInputMode != AlwaysInputDisabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputDisabled; + + if ( bAlways ) + EnableInput( FALSE, FALSE ); + } + else if( ! bAlways && mpWindowImpl->meAlwaysInputMode == AlwaysInputDisabled ) + { + mpWindowImpl->meAlwaysInputMode = AlwaysInputNone; + } + + if ( bChild || mpWindowImpl->mbChildNotify ) + { + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + pChild->AlwaysDisableInput( bAlways, bChild ); + pChild = pChild->mpWindowImpl->mpNext; + } + } +} + +// ----------------------------------------------------------------------- + +void Window::SetActivateMode( USHORT nMode ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetActivateMode( nMode ); + + if ( mpWindowImpl->mnActivateMode != nMode ) + { + mpWindowImpl->mnActivateMode = nMode; + + // Evtl. ein Decativate/Activate ausloesen + if ( mpWindowImpl->mnActivateMode ) + { + if ( (mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW)) && + !HasChildPathFocus( TRUE ) ) + { + mpWindowImpl->mbActive = FALSE; + Deactivate(); + } + } + else + { + if ( !mpWindowImpl->mbActive || (GetType() == WINDOW_BORDERWINDOW) ) + { + mpWindowImpl->mbActive = TRUE; + Activate(); + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::ToTop( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplStartToTop( nFlags ); + ImplFocusToTop( nFlags, IsReallyVisible() ); +} + +// ----------------------------------------------------------------------- + +void Window::SetZOrder( Window* pRefWindow, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->SetZOrder( pRefWindow, nFlags ); + return; + } + + if ( nFlags & WINDOW_ZORDER_FIRST ) + { + if ( ImplIsOverlapWindow() ) + pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap; + else + pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild; + nFlags |= WINDOW_ZORDER_BEFOR; + } + else if ( nFlags & WINDOW_ZORDER_LAST ) + { + if ( ImplIsOverlapWindow() ) + pRefWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap; + else + pRefWindow = mpWindowImpl->mpParent->mpWindowImpl->mpLastChild; + nFlags |= WINDOW_ZORDER_BEHIND; + } + + while ( pRefWindow->mpWindowImpl->mpBorderWindow ) + pRefWindow = pRefWindow->mpWindowImpl->mpBorderWindow; + if ( (pRefWindow == this) || mpWindowImpl->mbFrame ) + return; + + DBG_ASSERT( pRefWindow->mpWindowImpl->mpParent == mpWindowImpl->mpParent, "Window::SetZOrder() - pRefWindow has other parent" ); + if ( nFlags & WINDOW_ZORDER_BEFOR ) + { + if ( pRefWindow->mpWindowImpl->mpPrev == this ) + return; + + if ( ImplIsOverlapWindow() ) + { + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev; + if ( !pRefWindow->mpWindowImpl->mpPrev ) + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = this; + } + else + { + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev; + if ( !pRefWindow->mpWindowImpl->mpPrev ) + mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = this; + } + + mpWindowImpl->mpPrev = pRefWindow->mpWindowImpl->mpPrev; + mpWindowImpl->mpNext = pRefWindow; + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this; + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this; + } + else if ( nFlags & WINDOW_ZORDER_BEHIND ) + { + if ( pRefWindow->mpWindowImpl->mpNext == this ) + return; + + if ( ImplIsOverlapWindow() ) + { + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = mpWindowImpl->mpPrev; + if ( !pRefWindow->mpWindowImpl->mpNext ) + mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpLastOverlap = this; + } + else + { + if ( mpWindowImpl->mpPrev ) + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = mpWindowImpl->mpNext; + else + mpWindowImpl->mpParent->mpWindowImpl->mpFirstChild = mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = mpWindowImpl->mpPrev; + else + mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = mpWindowImpl->mpPrev; + if ( !pRefWindow->mpWindowImpl->mpNext ) + mpWindowImpl->mpParent->mpWindowImpl->mpLastChild = this; + } + + mpWindowImpl->mpPrev = pRefWindow; + mpWindowImpl->mpNext = pRefWindow->mpWindowImpl->mpNext; + if ( mpWindowImpl->mpNext ) + mpWindowImpl->mpNext->mpWindowImpl->mpPrev = this; + mpWindowImpl->mpPrev->mpWindowImpl->mpNext = this; + } + + if ( IsReallyVisible() ) + { + // Hintergrund-Sicherung zuruecksetzen + if ( mpWindowImpl->mpFrameData->mpFirstBackWin ) + ImplInvalidateAllOverlapBackgrounds(); + + if ( mpWindowImpl->mbInitWinClipRegion || !mpWindowImpl->maWinClipRegion.IsEmpty() ) + { + BOOL bInitWinClipRegion = mpWindowImpl->mbInitWinClipRegion; + ImplSetClipFlag(); + + // Wenn ClipRegion noch nicht initalisiert wurde, dann + // gehen wir davon aus, das das Fenster noch nicht + // ausgegeben wurde und loesen somit auch keine + // Invalidates aus. Dies ist eine Optimierung fuer + // HTML-Dokumenten mit vielen Controls. Wenn es mal + // Probleme mit dieser Abfrage gibt, sollte man ein + // Flag einfuehren, ob das Fenster nach Show schon + // einmal ausgegeben wurde. + if ( !bInitWinClipRegion ) + { + // Alle nebeneinanderliegen Fenster invalidieren + // Noch nicht komplett implementiert !!! + Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + Window* pWindow = NULL; + if ( ImplIsOverlapWindow() ) + { + if ( mpWindowImpl->mpOverlapWindow ) + pWindow = mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpFirstOverlap; + } + else + pWindow = ImplGetParent()->mpWindowImpl->mpFirstChild; + // Alle Fenster, die vor uns liegen und von uns verdeckt wurden, + // invalidieren + while ( pWindow ) + { + if ( pWindow == this ) + break; + Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ), + Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) ); + if ( aWinRect.IsOver( aCompRect ) ) + pWindow->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT ); + pWindow = pWindow->mpWindowImpl->mpNext; + } + // Wenn uns ein Fenster welches im Hinterund liegt verdeckt hat, + // dann muessen wir uns neu ausgeben + while ( pWindow ) + { + if ( pWindow != this ) + { + Rectangle aCompRect( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ), + Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) ); + if ( aWinRect.IsOver( aCompRect ) ) + { + Invalidate( INVALIDATE_CHILDREN | INVALIDATE_NOTRANSPARENT ); + break; + } + } + pWindow = pWindow->mpWindowImpl->mpNext; + } + } + } + } +} + +// ----------------------------------------------------------------------- + +void Window::EnableAlwaysOnTop( BOOL bEnable ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mpWindowImpl->mbAlwaysOnTop = bEnable; + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->EnableAlwaysOnTop( bEnable ); + else if ( bEnable && IsReallyVisible() ) + ToTop(); + + if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetAlwaysOnTop( bEnable ); +} + +// ----------------------------------------------------------------------- + +void Window::SetPosSizePixel( long nX, long nY, + long nWidth, long nHeight, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + BOOL bHasValidSize = !mpWindowImpl->mbDefSize; + + if ( nFlags & WINDOW_POSSIZE_POS ) + mpWindowImpl->mbDefPos = FALSE; + if ( nFlags & WINDOW_POSSIZE_SIZE ) + mpWindowImpl->mbDefSize = FALSE; + + // Oberstes BorderWindow ist das Window, welches positioniert werden soll + Window* pWindow = this; + while ( pWindow->mpWindowImpl->mpBorderWindow ) + pWindow = pWindow->mpWindowImpl->mpBorderWindow; + + if ( pWindow->mpWindowImpl->mbFrame ) + { + // Note: if we're positioning a frame, the coordinates are interpreted + // as being the top-left corner of the window's client area and NOT + // as the position of the border ! (due to limitations of several UNIX window managers) + long nOldWidth = pWindow->mnOutWidth; + + if ( !(nFlags & WINDOW_POSSIZE_WIDTH) ) + nWidth = pWindow->mnOutWidth; + if ( !(nFlags & WINDOW_POSSIZE_HEIGHT) ) + nHeight = pWindow->mnOutHeight; + + + USHORT nSysFlags=0; + if( nFlags & WINDOW_POSSIZE_WIDTH ) + nSysFlags |= SAL_FRAME_POSSIZE_WIDTH; + if( nFlags & WINDOW_POSSIZE_HEIGHT ) + nSysFlags |= SAL_FRAME_POSSIZE_HEIGHT; + if( nFlags & WINDOW_POSSIZE_X ) + { + nSysFlags |= SAL_FRAME_POSSIZE_X; + if( pWindow->GetParent() && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) ) + { + Window* pParent = pWindow->GetParent(); + nX += pParent->mnOutOffX; + } + if( GetParent() && GetParent()->ImplIsAntiparallel() ) + { + // --- RTL --- (re-mirror at parent window) + Rectangle aRect( Point ( nX, nY ), Size( nWidth, nHeight ) ); + GetParent()->ImplReMirror( aRect ); + nX = aRect.nLeft; + } + } + if( !(nFlags & WINDOW_POSSIZE_X) && bHasValidSize && pWindow->mpWindowImpl->mpFrame->maGeometry.nWidth ) + { + // --- RTL --- make sure the old right aligned position is not changed + // system windows will always grow to the right + if( pWindow->GetParent() && pWindow->GetParent()->ImplHasMirroredGraphics() ) + { + long myWidth = nOldWidth; + if( !myWidth ) + myWidth = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth; + if( !myWidth ) + myWidth = nWidth; + nFlags |= WINDOW_POSSIZE_X; + nSysFlags |= SAL_FRAME_POSSIZE_X; + nX = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - + mpWindowImpl->mpFrame->GetUnmirroredGeometry().nLeftDecoration; + nX = pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nLeftDecoration + + pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nWidth - myWidth - 1 - mpWindowImpl->mpFrame->GetUnmirroredGeometry().nX; + if(!(nFlags & WINDOW_POSSIZE_Y)) + { + nFlags |= WINDOW_POSSIZE_Y; + nSysFlags |= SAL_FRAME_POSSIZE_Y; + nY = mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY - pWindow->GetParent()->mpWindowImpl->mpFrame->GetUnmirroredGeometry().nY - + mpWindowImpl->mpFrame->GetUnmirroredGeometry().nTopDecoration; + } + } + } + if( nFlags & WINDOW_POSSIZE_Y ) + { + nSysFlags |= SAL_FRAME_POSSIZE_Y; + if( pWindow->GetParent() && (pWindow->GetStyle() & WB_SYSTEMCHILDWINDOW) ) + { + Window* pParent = pWindow->GetParent(); + nY += pParent->mnOutOffY; + } + } + + if( nSysFlags & (SAL_FRAME_POSSIZE_WIDTH|SAL_FRAME_POSSIZE_HEIGHT) ) + { + // check for min/max client size and adjust size accordingly + // otherwise it may happen that the resize event is ignored, i.e. the old size remains + // unchanged but ImplHandleResize() is called with the wrong size + SystemWindow *pSystemWindow = dynamic_cast< SystemWindow* >( pWindow ); + if( pSystemWindow ) + { + Size aMinSize = pSystemWindow->GetMinOutputSizePixel(); + Size aMaxSize = pSystemWindow->GetMaxOutputSizePixel(); + if( nWidth < aMinSize.Width() ) + nWidth = aMinSize.Width(); + if( nHeight < aMinSize.Height() ) + nHeight = aMinSize.Height(); + + if( nWidth > aMaxSize.Width() ) + nWidth = aMaxSize.Width(); + if( nHeight > aMaxSize.Height() ) + nHeight = aMaxSize.Height(); + } + } + + pWindow->mpWindowImpl->mpFrame->SetPosSize( nX, nY, nWidth, nHeight, nSysFlags ); + + // Resize should be called directly. If we havn't + // set the correct size, we get a second resize from + // the system with the correct size. This can be happend + // if the size is to small or to large. + ImplHandleResize( pWindow, nWidth, nHeight ); + } + else + { + pWindow->ImplPosSizeWindow( nX, nY, nWidth, nHeight, nFlags ); + if ( IsReallyVisible() ) + ImplGenerateMouseMove(); + } +} + +// ----------------------------------------------------------------------- + +Point Window::GetPosPixel() const +{ + return mpWindowImpl->maPos; +} + +// ----------------------------------------------------------------------- + +Rectangle Window::GetDesktopRectPixel() const +{ + Rectangle rRect; + mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrame->GetWorkArea( rRect ); + return rRect; +} + +// ----------------------------------------------------------------------- + +Point Window::OutputToScreenPixel( const Point& rPos ) const +{ + // relative to top level parent + return Point( rPos.X()+mnOutOffX, rPos.Y()+mnOutOffY ); +} + +// ----------------------------------------------------------------------- + +Point Window::ScreenToOutputPixel( const Point& rPos ) const +{ + // relative to top level parent + return Point( rPos.X()-mnOutOffX, rPos.Y()-mnOutOffY ); +} + +// ----------------------------------------------------------------------- + +long Window::ImplGetUnmirroredOutOffX() +{ + // revert mnOutOffX changes that were potentially made in ImplPosSizeWindow + long offx = mnOutOffX; + if( ImplHasMirroredGraphics() ) + { + if( mpWindowImpl->mpParent && !mpWindowImpl->mpParent->mpWindowImpl->mbFrame && mpWindowImpl->mpParent->ImplIsAntiparallel() ) + { + if ( !ImplIsOverlapWindow() ) + offx -= mpWindowImpl->mpParent->mnOutOffX; + + offx = mpWindowImpl->mpParent->mnOutWidth - mnOutWidth - offx; + + if ( !ImplIsOverlapWindow() ) + offx += mpWindowImpl->mpParent->mnOutOffX; + + } + } + return offx; +} + +// normalized screen pixel are independent of mirroring +Point Window::OutputToNormalizedScreenPixel( const Point& rPos ) const +{ + // relative to top level parent + long offx = ((Window*) this)->ImplGetUnmirroredOutOffX(); + return Point( rPos.X()+offx, rPos.Y()+mnOutOffY ); +} + +Point Window::NormalizedScreenToOutputPixel( const Point& rPos ) const +{ + // relative to top level parent + long offx = ((Window*) this)->ImplGetUnmirroredOutOffX(); + return Point( rPos.X()-offx, rPos.Y()-mnOutOffY ); +} + +// ----------------------------------------------------------------------- + +Point Window::OutputToAbsoluteScreenPixel( const Point& rPos ) const +{ + // relative to the screen + Point p = OutputToScreenPixel( rPos ); + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + p.X() += g.nX; + p.Y() += g.nY; + return p; +} + +// ----------------------------------------------------------------------- + +Point Window::AbsoluteScreenToOutputPixel( const Point& rPos ) const +{ + // relative to the screen + Point p = ScreenToOutputPixel( rPos ); + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + p.X() -= g.nX; + p.Y() -= g.nY; + return p; +} + +// ----------------------------------------------------------------------- + +Rectangle Window::ImplOutputToUnmirroredAbsoluteScreenPixel( const Rectangle &rRect ) const +{ + // this method creates unmirrored screen coordinates to be compared with the desktop + // and is used for positioning of RTL popup windows correctly on the screen + SalFrameGeometry g = mpWindowImpl->mpFrame->GetUnmirroredGeometry(); + + Point p1 = OutputToScreenPixel( rRect.TopRight() ); + p1.X() = g.nX+g.nWidth-p1.X(); + p1.Y() += g.nY; + + Point p2 = OutputToScreenPixel( rRect.BottomLeft() ); + p2.X() = g.nX+g.nWidth-p2.X(); + p2.Y() += g.nY; + + return Rectangle( p1, p2 ); +} + + +// ----------------------------------------------------------------------- + +Rectangle Window::GetWindowExtentsRelative( Window *pRelativeWindow ) const +{ + // with decoration + return ImplGetWindowExtentsRelative( pRelativeWindow, FALSE ); +} + +Rectangle Window::GetClientWindowExtentsRelative( Window *pRelativeWindow ) const +{ + // without decoration + return ImplGetWindowExtentsRelative( pRelativeWindow, TRUE ); +} + +// ----------------------------------------------------------------------- + +Rectangle Window::ImplGetWindowExtentsRelative( Window *pRelativeWindow, BOOL bClientOnly ) const +{ + SalFrameGeometry g = mpWindowImpl->mpFrame->GetGeometry(); + // make sure we use the extent of our border window, + // otherwise we miss a few pixels + const Window *pWin = (!bClientOnly && mpWindowImpl->mpBorderWindow) ? mpWindowImpl->mpBorderWindow : this; + + Point aPos( pWin->OutputToScreenPixel( Point(0,0) ) ); + aPos.X() += g.nX; + aPos.Y() += g.nY; + Size aSize ( pWin->GetSizePixel() ); + // #104088# do not add decoration to the workwindow to be compatible to java accessibility api + if( !bClientOnly && (mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame && GetType() != WINDOW_WORKWINDOW)) ) + { + aPos.X() -= g.nLeftDecoration; + aPos.Y() -= g.nTopDecoration; + aSize.Width() += g.nLeftDecoration + g.nRightDecoration; + aSize.Height() += g.nTopDecoration + g.nBottomDecoration; + } + if( pRelativeWindow ) + { + // #106399# express coordinates relative to borderwindow + Window *pRelWin = (!bClientOnly && pRelativeWindow->mpWindowImpl->mpBorderWindow) ? pRelativeWindow->mpWindowImpl->mpBorderWindow : pRelativeWindow; + aPos = pRelWin->AbsoluteScreenToOutputPixel( aPos ); + } + return Rectangle( aPos, aSize ); +} + +// ----------------------------------------------------------------------- + +void Window::Scroll( long nHorzScroll, long nVertScroll, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplScroll( Rectangle( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ), + nHorzScroll, nVertScroll, nFlags & ~SCROLL_CLIP ); +} + +// ----------------------------------------------------------------------- + +void Window::Scroll( long nHorzScroll, long nVertScroll, + const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Rectangle aRect = ImplLogicToDevicePixel( rRect ); + aRect.Intersection( Rectangle( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ) ); + if ( !aRect.IsEmpty() ) + ImplScroll( aRect, nHorzScroll, nVertScroll, nFlags ); +} + +// ----------------------------------------------------------------------- + +void Window::Invalidate( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + ImplInvalidate( NULL, nFlags ); +} + +// ----------------------------------------------------------------------- + +void Window::Invalidate( const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + Rectangle aRect = ImplLogicToDevicePixel( rRect ); + if ( !aRect.IsEmpty() ) + { + Region aRegion( aRect ); + ImplInvalidate( &aRegion, nFlags ); + } +} + +// ----------------------------------------------------------------------- + +void Window::Invalidate( const Region& rRegion, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + if ( rRegion.IsNull() ) + ImplInvalidate( NULL, nFlags ); + else + { + Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) ); + if ( !aRegion.IsEmpty() ) + ImplInvalidate( &aRegion, nFlags ); + } +} + +// ----------------------------------------------------------------------- + +void Window::Validate( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + ImplValidate( NULL, nFlags ); +} + +// ----------------------------------------------------------------------- + +void Window::Validate( const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + Rectangle aRect = ImplLogicToDevicePixel( rRect ); + if ( !aRect.IsEmpty() ) + { + Region aRegion( aRect ); + ImplValidate( &aRegion, nFlags ); + } +} + +// ----------------------------------------------------------------------- + +void Window::Validate( const Region& rRegion, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() || !mnOutWidth || !mnOutHeight ) + return; + + if ( rRegion.IsNull() ) + ImplValidate( NULL, nFlags ); + else + { + Region aRegion = ImplPixelToDevicePixel( LogicToPixel( rRegion ) ); + if ( !aRegion.IsEmpty() ) + ImplValidate( &aRegion, nFlags ); + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::HasPaintEvent() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !mpWindowImpl->mbReallyVisible ) + return FALSE; + + if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame ) + return TRUE; + + if ( mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT ) + return TRUE; + + if ( !ImplIsOverlapWindow() ) + { + const Window* pTempWindow = this; + do + { + pTempWindow = pTempWindow->ImplGetParent(); + if ( pTempWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINTCHILDS | IMPL_PAINT_PAINTALLCHILDS) ) + return TRUE; + } + while ( !pTempWindow->ImplIsOverlapWindow() ); + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::Update() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpBorderWindow ) + { + mpWindowImpl->mpBorderWindow->Update(); + return; + } + + if ( !mpWindowImpl->mbReallyVisible ) + return; + + BOOL bFlush = FALSE; + if ( mpWindowImpl->mpFrameWindow->mpWindowImpl->mbPaintFrame ) + { + Point aPoint( 0, 0 ); + Region aRegion( Rectangle( aPoint, Size( mnOutWidth, mnOutHeight ) ) ); + ImplInvalidateOverlapFrameRegion( aRegion ); + if ( mpWindowImpl->mbFrame || (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ) + bFlush = TRUE; + } + + // Zuerst muessen wir alle Fenster ueberspringen, die Paint-Transparent + // sind + Window* pUpdateWindow = this; + Window* pWindow = pUpdateWindow; + while ( !pWindow->ImplIsOverlapWindow() ) + { + if ( !pWindow->mpWindowImpl->mbPaintTransparent ) + { + pUpdateWindow = pWindow; + break; + } + pWindow = pWindow->ImplGetParent(); + } + // Ein Update wirkt immer auf das Window, wo PAINTALLCHILDS gesetzt + // ist, damit nicht zuviel gemalt wird + pWindow = pUpdateWindow; + do + { + if ( pWindow->mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINTALLCHILDS ) + pUpdateWindow = pWindow; + if ( pWindow->ImplIsOverlapWindow() ) + break; + pWindow = pWindow->ImplGetParent(); + } + while ( pWindow ); + + // Wenn es etwas zu malen gibt, dann ein Paint ausloesen + if ( pUpdateWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDS) ) + { + // und fuer alle ueber uns stehende System-Fenster auch ein Update + // ausloesen, damit nicht die ganze Zeit luecken stehen bleiben + Window* pUpdateOverlapWindow = ImplGetFirstOverlapWindow()->mpWindowImpl->mpFirstOverlap; + while ( pUpdateOverlapWindow ) + { + pUpdateOverlapWindow->Update(); + pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext; + } + + pUpdateWindow->ImplCallPaint( NULL, pUpdateWindow->mpWindowImpl->mnPaintFlags ); + } + + if ( bFlush ) + Flush(); +} + +// ----------------------------------------------------------------------- + +void Window::Flush() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + const Rectangle aWinRect( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ) ); + mpWindowImpl->mpFrame->Flush( aWinRect ); +} + +// ----------------------------------------------------------------------- + +void Window::Sync() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mpWindowImpl->mpFrame->Sync(); +} + +// ----------------------------------------------------------------------- + +void Window::SetUpdateMode( BOOL bUpdate ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mpWindowImpl->mbNoUpdate = !bUpdate; + StateChanged( STATE_CHANGE_UPDATEMODE ); +} + +// ----------------------------------------------------------------------- + +void Window::GrabFocus() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplGrabFocus( 0 ); +} + +// ----------------------------------------------------------------------- + +BOOL Window::HasFocus() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + // #107575# the first floating window always has the keyboard focus, see also winproc.cxx: ImplGetKeyInputWindow() + // task was shifted to 6.y, so its commented out + /* + Window* pFocusWin = ImplGetSVData()->maWinData.mpFirstFloat; + if( pFocusWin && pFocusWin->mpWindowImpl->mbFloatWin && ((FloatingWindow *)pFocusWin)->GrabsFocus() ) + pFocusWin = pFocusWin->GetPreferredKeyInputWindow(); + else + pFocusWin = ImplGetSVData()->maWinData.mpFocusWin; + + return (this == pFocusWin); + */ + + return (this == ImplGetSVData()->maWinData.mpFocusWin); +} + +// ----------------------------------------------------------------------- + +void Window::GrabFocusToDocument() +{ + Window *pWin = this; + while( pWin ) + { + if( !pWin->GetParent() ) + { + pWin->ImplGetFrameWindow()->GetWindow( WINDOW_CLIENT )->GrabFocus(); + return; + } + pWin = pWin->GetParent(); + } +} + +void Window::SetFakeFocus( bool bFocus ) +{ + ImplGetWindowImpl()->mbFakeFocusSet = bFocus; +} + +// ----------------------------------------------------------------------- + +BOOL Window::HasChildPathFocus( BOOL bSystemWindow ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + // #107575#, the first floating window always has the keyboard focus, see also winproc.cxx: ImplGetKeyInputWindow() + // task was shifted to 6.y, so its commented out + /* + Window* pFocusWin = ImplGetSVData()->maWinData.mpFirstFloat; + if( pFocusWin && pFocusWin->mpWindowImpl->mbFloatWin && ((FloatingWindow *)pFocusWin)->GrabsFocus() ) + pFocusWin = pFocusWin->GetPreferredKeyInputWindow(); + else + pFocusWin = ImplGetSVData()->maWinData.mpFocusWin; + */ + Window* pFocusWin = ImplGetSVData()->maWinData.mpFocusWin; + if ( pFocusWin ) + return ImplIsWindowOrChild( pFocusWin, bSystemWindow ); + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::CaptureMouse() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + + // Tracking evt. beenden + if ( pSVData->maWinData.mpTrackWin != this ) + { + if ( pSVData->maWinData.mpTrackWin ) + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL ); + } + + if ( pSVData->maWinData.mpCaptureWin != this ) + { + pSVData->maWinData.mpCaptureWin = this; + mpWindowImpl->mpFrame->CaptureMouse( TRUE ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ReleaseMouse() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + + DBG_ASSERTWARNING( pSVData->maWinData.mpCaptureWin == this, + "Window::ReleaseMouse(): window doesn't have the mouse capture" ); + + if ( pSVData->maWinData.mpCaptureWin == this ) + { + pSVData->maWinData.mpCaptureWin = NULL; + mpWindowImpl->mpFrame->CaptureMouse( FALSE ); + ImplGenerateMouseMove(); + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsMouseCaptured() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return (this == ImplGetSVData()->maWinData.mpCaptureWin); +} + +// ----------------------------------------------------------------------- + +void Window::SetPointer( const Pointer& rPointer ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->maPointer == rPointer ) + return; + + mpWindowImpl->maPointer = rPointer; + + // Pointer evt. direkt umsetzen + if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() ) + mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() ); +} + +// ----------------------------------------------------------------------- + +void Window::EnableChildPointerOverwrite( BOOL bOverwrite ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbChildPtrOverwrite == bOverwrite ) + return; + + mpWindowImpl->mbChildPtrOverwrite = bOverwrite; + + // Pointer evt. direkt umsetzen + if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() ) + mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() ); +} + +// ----------------------------------------------------------------------- + +void Window::SetPointerPosPixel( const Point& rPos ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Point aPos = ImplOutputToFrame( rPos ); + if( ImplHasMirroredGraphics() ) + { + if( !IsRTLEnabled() ) + { + // --- RTL --- (re-mirror mouse pos at this window) + ImplReMirror( aPos ); + } + // mirroring is required here, SetPointerPos bypasses SalGraphics + mpGraphics->mirror( aPos.X(), this ); + } + else if( ImplIsAntiparallel() ) + { + ImplReMirror( aPos ); + } + mpWindowImpl->mpFrame->SetPointerPos( aPos.X(), aPos.Y() ); +} + +// ----------------------------------------------------------------------- + +Point Window::GetPointerPosPixel() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Point aPos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY ); + if( ImplIsAntiparallel() ) + { + // --- RTL --- (re-mirror mouse pos at this window) + ImplReMirror( aPos ); + } + return ImplFrameToOutput( aPos ); +} + +// ----------------------------------------------------------------------- + +Point Window::GetLastPointerPosPixel() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Point aPos( mpWindowImpl->mpFrameData->mnBeforeLastMouseX, mpWindowImpl->mpFrameData->mnBeforeLastMouseY ); + if( ImplIsAntiparallel() ) + { + // --- RTL --- (re-mirror mouse pos at this window) + ImplReMirror( aPos ); + } + return ImplFrameToOutput( aPos ); +} + +// ----------------------------------------------------------------------- + +void Window::ShowPointer( BOOL bVisible ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbNoPtrVisible != !bVisible ) + { + mpWindowImpl->mbNoPtrVisible = !bVisible; + + // Pointer evt. direkt umsetzen + if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() ) + mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() ); + } +} + +// ----------------------------------------------------------------------- + +Window::PointerState Window::GetPointerState() +{ + PointerState aState; + aState.mnState = 0; + + if (mpWindowImpl->mpFrame) + { + SalFrame::SalPointerState aSalPointerState; + + aSalPointerState = mpWindowImpl->mpFrame->GetPointerState(); + if( ImplIsAntiparallel() ) + { + // --- RTL --- (re-mirror mouse pos at this window) + ImplReMirror( aSalPointerState.maPos ); + } + aState.maPos = ImplFrameToOutput( aSalPointerState.maPos ); + aState.mnState = aSalPointerState.mnState; + } + return aState; +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsMouseOver() +{ + return ImplGetWinData()->mbMouseOver; +} + +// ----------------------------------------------------------------------- + +void Window::EnterWait() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + mpWindowImpl->mnWaitCount++; + + if ( mpWindowImpl->mnWaitCount == 1 ) + { + // Pointer evt. direkt umsetzen + if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() ) + mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() ); + } +} + +// ----------------------------------------------------------------------- + +void Window::LeaveWait() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mnWaitCount ) + { + mpWindowImpl->mnWaitCount--; + + if ( !mpWindowImpl->mnWaitCount ) + { + // Pointer evt. direkt umsetzen + if ( !mpWindowImpl->mpFrameData->mbInMouseMove && ImplTestMousePointerSet() ) + mpWindowImpl->mpFrame->SetPointer( ImplGetMousePointer() ); + } + } +} + +// ----------------------------------------------------------------------- + +void Window::SetCursor( Cursor* pCursor ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpCursor != pCursor ) + { + if ( mpWindowImpl->mpCursor ) + mpWindowImpl->mpCursor->ImplHide(); + mpWindowImpl->mpCursor = pCursor; + if ( pCursor ) + pCursor->ImplShow(); + } +} + +// ----------------------------------------------------------------------- + +void Window::SetText( const XubString& rStr ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + String oldTitle( mpWindowImpl->maText ); + mpWindowImpl->maText = rStr; + + if ( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->SetText( rStr ); + else if ( mpWindowImpl->mbFrame ) + mpWindowImpl->mpFrame->SetTitle( rStr ); + + ImplCallEventListeners( VCLEVENT_WINDOW_FRAMETITLECHANGED, &oldTitle ); + + // #107247# needed for accessibility + // The VCLEVENT_WINDOW_FRAMETITLECHANGED is (mis)used to notify accessible name changes. + // Therefore a window, which is labeled by this window, must also notify an accessible + // name change. + if ( IsReallyVisible() ) + { + Window* pWindow = GetLabelFor(); + if ( pWindow && pWindow != this ) + pWindow->ImplCallEventListeners( VCLEVENT_WINDOW_FRAMETITLECHANGED, &oldTitle ); + } + + StateChanged( STATE_CHANGE_TEXT ); +} + +// ----------------------------------------------------------------------- + +String Window::GetText() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return mpWindowImpl->maText; +} + +// ----------------------------------------------------------------------- + +String Window::GetDisplayText() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return GetText(); +} + +// ----------------------------------------------------------------------- + +const Wallpaper& Window::GetDisplayBackground() const +{ + // FIXME: fix issue 52349, need to fix this really in + // all NWF enabled controls + const ToolBox* pTB = dynamic_cast<const ToolBox*>(this); + if( pTB ) + { + if( IsNativeWidgetEnabled() ) + return pTB->ImplGetToolBoxPrivateData()->maDisplayBackground; + } + + if( !IsBackground() ) + { + if( mpWindowImpl->mpParent ) + return mpWindowImpl->mpParent->GetDisplayBackground(); + } + + const Wallpaper& rBack = GetBackground(); + if( ! rBack.IsBitmap() && + ! rBack.IsGradient() && + rBack.GetColor().GetColor() == COL_TRANSPARENT && + mpWindowImpl->mpParent ) + return mpWindowImpl->mpParent->GetDisplayBackground(); + return rBack; +} + +// ----------------------------------------------------------------------- + +const XubString& Window::GetHelpText() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + String aStrHelpId( rtl::OStringToOUString( GetHelpId(), RTL_TEXTENCODING_UTF8 ) ); + bool bStrHelpId = (aStrHelpId.Len() > 0); + + if ( !mpWindowImpl->maHelpText.Len() && bStrHelpId ) + { + if ( !IsDialog() && (mpWindowImpl->mnType != WINDOW_TABPAGE) && (mpWindowImpl->mnType != WINDOW_FLOATINGWINDOW) ) + { + Help* pHelp = Application::GetHelp(); + if ( pHelp ) + { + ((Window*)this)->mpWindowImpl->maHelpText = pHelp->GetHelpText( aStrHelpId, this ); + mpWindowImpl->mbHelpTextDynamic = FALSE; + } + } + } + else if( mpWindowImpl->mbHelpTextDynamic && bStrHelpId ) + { + static const char* pEnv = getenv( "HELP_DEBUG" ); + if( pEnv && *pEnv ) + { + rtl::OUStringBuffer aTxt( 64+mpWindowImpl->maHelpText.Len() ); + aTxt.append( mpWindowImpl->maHelpText ); + aTxt.appendAscii( "\n------------------\n" ); + aTxt.append( rtl::OUString( aStrHelpId ) ); + mpWindowImpl->maHelpText = aTxt.makeStringAndClear(); + } + mpWindowImpl->mbHelpTextDynamic = FALSE; + } + + return mpWindowImpl->maHelpText; +} + +// ----------------------------------------------------------------------- + +Window* Window::FindWindow( const Point& rPos ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Point aPos = OutputToScreenPixel( rPos ); + return ((Window*)this)->ImplFindWindow( aPos ); +} + +// ----------------------------------------------------------------------- + +USHORT Window::GetChildCount() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + USHORT nChildCount = 0; + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + nChildCount++; + pChild = pChild->mpWindowImpl->mpNext; + } + + return nChildCount; +} + +// ----------------------------------------------------------------------- + +Window* Window::GetChild( USHORT nChild ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + USHORT nChildCount = 0; + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + if ( nChild == nChildCount ) + return pChild; + pChild = pChild->mpWindowImpl->mpNext; + nChildCount++; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +Window* Window::GetWindow( USHORT nType ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + switch ( nType ) + { + case WINDOW_PARENT: + return mpWindowImpl->mpRealParent; + + case WINDOW_FIRSTCHILD: + return mpWindowImpl->mpFirstChild; + + case WINDOW_LASTCHILD: + return mpWindowImpl->mpLastChild; + + case WINDOW_PREV: + return mpWindowImpl->mpPrev; + + case WINDOW_NEXT: + return mpWindowImpl->mpNext; + + case WINDOW_FIRSTOVERLAP: + return mpWindowImpl->mpFirstOverlap; + + case WINDOW_LASTOVERLAP: + return mpWindowImpl->mpLastOverlap; + + case WINDOW_OVERLAP: + if ( ImplIsOverlapWindow() ) + return (Window*)this; + else + return mpWindowImpl->mpOverlapWindow; + + case WINDOW_PARENTOVERLAP: + if ( ImplIsOverlapWindow() ) + return mpWindowImpl->mpOverlapWindow; + else + return mpWindowImpl->mpOverlapWindow->mpWindowImpl->mpOverlapWindow; + + case WINDOW_CLIENT: + return ((Window*)this)->ImplGetWindow(); + + case WINDOW_REALPARENT: + return ImplGetParent(); + + case WINDOW_FRAME: + return mpWindowImpl->mpFrameWindow; + + case WINDOW_BORDER: + if ( mpWindowImpl->mpBorderWindow ) + return mpWindowImpl->mpBorderWindow->GetWindow( WINDOW_BORDER ); + return (Window*)this; + + case WINDOW_FIRSTTOPWINDOWCHILD: + return ImplGetWinData()->maTopWindowChildren.empty() ? NULL : *ImplGetWinData()->maTopWindowChildren.begin(); + + case WINDOW_LASTTOPWINDOWCHILD: + return ImplGetWinData()->maTopWindowChildren.empty() ? NULL : *ImplGetWinData()->maTopWindowChildren.rbegin(); + + case WINDOW_PREVTOPWINDOWSIBLING: + { + if ( !mpWindowImpl->mpRealParent ) + return NULL; + const ::std::list< Window* >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren ); + ::std::list< Window* >::const_iterator myPos = + ::std::find( rTopWindows.begin(), rTopWindows.end(), this ); + if ( myPos == rTopWindows.end() ) + return NULL; + if ( myPos == rTopWindows.begin() ) + return NULL; + return *--myPos; + } + + case WINDOW_NEXTTOPWINDOWSIBLING: + { + if ( !mpWindowImpl->mpRealParent ) + return NULL; + const ::std::list< Window* >& rTopWindows( mpWindowImpl->mpRealParent->ImplGetWinData()->maTopWindowChildren ); + ::std::list< Window* >::const_iterator myPos = + ::std::find( rTopWindows.begin(), rTopWindows.end(), this ); + if ( ( myPos == rTopWindows.end() ) || ( ++myPos == rTopWindows.end() ) ) + return NULL; + return *myPos; + } + + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsChild( const Window* pWindow, BOOL bSystemWindow ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + DBG_CHKOBJ( pWindow, Window, ImplDbgCheckWindow ); + + do + { + if ( !bSystemWindow && pWindow->ImplIsOverlapWindow() ) + break; + + pWindow = pWindow->ImplGetParent(); + + if ( pWindow == this ) + return TRUE; + } + while ( pWindow ); + + return FALSE; +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsWindowOrChild( const Window* pWindow, BOOL bSystemWindow ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + DBG_CHKOBJ( pWindow, Window, ImplDbgCheckWindow ); + + if ( this == pWindow ) + return TRUE; + return ImplIsChild( pWindow, bSystemWindow ); +} + +// ----------------------------------------------------------------------- + +const SystemEnvData* Window::GetSystemData() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return mpWindowImpl->mpFrame ? mpWindowImpl->mpFrame->GetSystemData() : NULL; +} + +::com::sun::star::uno::Any Window::GetSystemDataAny() const +{ + ::com::sun::star::uno::Any aRet; + const SystemEnvData* pSysData = GetSystemData(); + if( pSysData ) + { + ::com::sun::star::uno::Sequence< sal_Int8 > aSeq( (sal_Int8*)pSysData, pSysData->nSize ); + aRet <<= aSeq; + } + return aRet; +} + +// ----------------------------------------------------------------------- + +void Window::SetWindowPeer( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xPeer, VCLXWindow* pVCLXWindow ) +{ + // be safe against re-entrance: first clear the old ref, then assign the new one + // #133706# / 2006-03-30 / frank.schoenheit@sun.com + mpWindowImpl->mxWindowPeer.clear(); + mpWindowImpl->mxWindowPeer = xPeer; + + mpWindowImpl->mpVCLXWindow = pVCLXWindow; +} + +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > Window::GetComponentInterface( BOOL bCreate ) +{ + if ( !mpWindowImpl->mxWindowPeer.is() && bCreate ) + { + UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); + if ( pWrapper ) + mpWindowImpl->mxWindowPeer = pWrapper->GetWindowInterface( this, sal_True ); + } + return mpWindowImpl->mxWindowPeer; +} + +// ----------------------------------------------------------------------- + +void Window::SetComponentInterface( ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xIFace ) +{ + UnoWrapperBase* pWrapper = Application::GetUnoWrapper(); + DBG_ASSERT( pWrapper, "SetComponentInterface: No Wrapper!" ); + if ( pWrapper ) + pWrapper->SetWindowInterface( this, xIFace ); +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallDeactivateListeners( Window *pNew ) +{ + // no deactivation if the the newly activated window is my child + if ( !pNew || !ImplIsChild( pNew ) ) + { + ImplDelData aDogtag( this ); + ImplCallEventListeners( VCLEVENT_WINDOW_DEACTIVATE ); + if( aDogtag.IsDelete() ) + return; + + // #100759#, avoid walking the wrong frame's hierarchy + // eg, undocked docking windows (ImplDockFloatWin) + if ( ImplGetParent() && mpWindowImpl->mpFrameWindow == ImplGetParent()->mpWindowImpl->mpFrameWindow ) + ImplGetParent()->ImplCallDeactivateListeners( pNew ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplCallActivateListeners( Window *pOld ) +{ + // no activation if the the old active window is my child + if ( !pOld || !ImplIsChild( pOld ) ) + { + ImplDelData aDogtag( this ); + ImplCallEventListeners( VCLEVENT_WINDOW_ACTIVATE, pOld ); + if( aDogtag.IsDelete() ) + return; + + // #106298# revoke the change for 105369, because this change + // disabled the activate event for the parent, + // if the parent is a compound control + //if( !GetParent() || !GetParent()->IsCompoundControl() ) + //{ + // #100759#, avoid walking the wrong frame's hierarchy + // eg, undocked docking windows (ImplDockFloatWin) + // #104714#, revert the changes for 100759 because it has a side effect when pOld is a dialog + // additionally the gallery is not dockable anymore, so 100759 canot occur + if ( ImplGetParent() ) /* && mpWindowImpl->mpFrameWindow == ImplGetParent()->mpWindowImpl->mpFrameWindow ) */ + ImplGetParent()->ImplCallActivateListeners( pOld ); + else if( (mpWindowImpl->mnStyle & WB_INTROWIN) == 0 ) + { + // top level frame reached: store hint for DefModalDialogParent + ImplGetSVData()->maWinData.mpActiveApplicationFrame = mpWindowImpl->mpFrameWindow; + } + //} + } +} + +// ----------------------------------------------------------------------- + +bool Window::ImplStopDnd() +{ + bool bRet = false; + if( mpWindowImpl->mpFrameData && mpWindowImpl->mpFrameData->mxDropTargetListener.is() ) + { + bRet = true; + mpWindowImpl->mpFrameData->mxDropTarget.clear(); + mpWindowImpl->mpFrameData->mxDragSource.clear(); + mpWindowImpl->mpFrameData->mxDropTargetListener.clear(); + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void Window::ImplStartDnd() +{ + GetDropTarget(); +} + +// ----------------------------------------------------------------------- + +Reference< XDropTarget > Window::GetDropTarget() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( ! mpWindowImpl->mxDNDListenerContainer.is() ) + { + sal_Int8 nDefaultActions = 0; + + if( mpWindowImpl->mpFrameData ) + { + if( ! mpWindowImpl->mpFrameData->mxDropTarget.is() ) + { + // initialization is done in GetDragSource + Reference< XDragSource > xDragSource = GetDragSource(); + } + + if( mpWindowImpl->mpFrameData->mxDropTarget.is() ) + { + nDefaultActions = mpWindowImpl->mpFrameData->mxDropTarget->getDefaultActions(); + + if( ! mpWindowImpl->mpFrameData->mxDropTargetListener.is() ) + { + mpWindowImpl->mpFrameData->mxDropTargetListener = new DNDEventDispatcher( mpWindowImpl->mpFrameWindow ); + + try + { + mpWindowImpl->mpFrameData->mxDropTarget->addDropTargetListener( mpWindowImpl->mpFrameData->mxDropTargetListener ); + + // register also as drag gesture listener if directly supported by drag source + Reference< XDragGestureRecognizer > xDragGestureRecognizer = + Reference< XDragGestureRecognizer > (mpWindowImpl->mpFrameData->mxDragSource, UNO_QUERY); + + if( xDragGestureRecognizer.is() ) + { + xDragGestureRecognizer->addDragGestureListener( + Reference< XDragGestureListener > (mpWindowImpl->mpFrameData->mxDropTargetListener, UNO_QUERY)); + } + else + mpWindowImpl->mpFrameData->mbInternalDragGestureRecognizer = TRUE; + + } + + catch( RuntimeException exc ) + { + // release all instances + mpWindowImpl->mpFrameData->mxDropTarget.clear(); + mpWindowImpl->mpFrameData->mxDragSource.clear(); + } + } + } + + } + + mpWindowImpl->mxDNDListenerContainer = static_cast < XDropTarget * > ( new DNDListenerContainer( nDefaultActions ) ); + } + + // this object is located in the same process, so there will be no runtime exception + return Reference< XDropTarget > ( mpWindowImpl->mxDNDListenerContainer, UNO_QUERY ); +} + +// ----------------------------------------------------------------------- + +Reference< XDragSource > Window::GetDragSource() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mpWindowImpl->mpFrameData ) + { + if( ! mpWindowImpl->mpFrameData->mxDragSource.is() ) + { + try + { + Reference< XMultiServiceFactory > xFactory = vcl::unohelper::GetMultiServiceFactory(); + if ( xFactory.is() ) + { + const SystemEnvData * pEnvData = GetSystemData(); + + if( pEnvData ) + { + Sequence< Any > aDragSourceAL( 2 ), aDropTargetAL( 2 ); + OUString aDragSourceSN, aDropTargetSN; +#if defined WNT + aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDragSource" ); + aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDropTarget" ); + aDragSourceAL[ 1 ] = makeAny( (sal_uInt32) pEnvData->hWnd ); + aDropTargetAL[ 0 ] = makeAny( (sal_uInt32) pEnvData->hWnd ); +#elif defined QUARTZ + /* FIXME: Mac OS X specific dnd interface does not exist! * + * Using Windows based dnd as a temporary solution */ + aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDragSource" ); + aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.OleDropTarget" ); + aDragSourceAL[ 1 ] = makeAny( static_cast<sal_uInt64>( reinterpret_cast<sal_IntPtr>(pEnvData->pView) ) ); + aDropTargetAL[ 0 ] = makeAny( static_cast<sal_uInt64>( reinterpret_cast<sal_IntPtr>(pEnvData->pView) ) ); +#elif defined UNX + aDropTargetAL.realloc( 3 ); + aDragSourceAL.realloc( 3 ); + aDragSourceSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.X11DragSource" ); + aDropTargetSN = OUString::createFromAscii( "com.sun.star.datatransfer.dnd.X11DropTarget" ); + + aDragSourceAL[ 0 ] = makeAny( Application::GetDisplayConnection() ); + aDragSourceAL[ 2 ] = makeAny( vcl::createBmpConverter() ); + aDropTargetAL[ 0 ] = makeAny( Application::GetDisplayConnection() ); + aDropTargetAL[ 1 ] = makeAny( (sal_Size)(pEnvData->aShellWindow) ); + aDropTargetAL[ 2 ] = makeAny( vcl::createBmpConverter() ); +#endif + if( aDragSourceSN.getLength() ) + mpWindowImpl->mpFrameData->mxDragSource = Reference< XDragSource > ( xFactory->createInstanceWithArguments( aDragSourceSN, aDragSourceAL ), UNO_QUERY ); + + if( aDropTargetSN.getLength() ) + mpWindowImpl->mpFrameData->mxDropTarget = Reference< XDropTarget > ( xFactory->createInstanceWithArguments( aDropTargetSN, aDropTargetAL ), UNO_QUERY ); + } + } + } + + // createInstance can throw any exception + catch( Exception exc ) + { + // release all instances + mpWindowImpl->mpFrameData->mxDropTarget.clear(); + mpWindowImpl->mpFrameData->mxDragSource.clear(); + } + } + + return mpWindowImpl->mpFrameData->mxDragSource; + } + + return Reference< XDragSource > (); +} + +// ----------------------------------------------------------------------- + +void Window::GetDragSourceDropTarget(Reference< XDragSource >& xDragSource, Reference< XDropTarget > &xDropTarget ) +// only for RVP transmission +{ + if( mpWindowImpl->mpFrameData ) + { + // initialization is done in GetDragSource + xDragSource = GetDragSource(); + xDropTarget = mpWindowImpl->mpFrameData->mxDropTarget; + } + else + { + xDragSource.clear(); + xDropTarget.clear(); + } +} + +// ----------------------------------------------------------------------- + +Reference< XDragGestureRecognizer > Window::GetDragGestureRecognizer() +{ + return Reference< XDragGestureRecognizer > ( GetDropTarget(), UNO_QUERY ); +} + +// ----------------------------------------------------------------------- + +Reference< XClipboard > Window::GetClipboard() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mpWindowImpl->mpFrameData ) + { + if( ! mpWindowImpl->mpFrameData->mxClipboard.is() ) + { + try + { + Reference< XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() ); + + if( xFactory.is() ) + { + mpWindowImpl->mpFrameData->mxClipboard = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboardExt" ) ), UNO_QUERY ); + + if( !mpWindowImpl->mpFrameData->mxClipboard.is() ) + mpWindowImpl->mpFrameData->mxClipboard = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboard" ) ), UNO_QUERY ); + +#if defined(UNX) && !defined(QUARTZ) // unix clipboard needs to be initialized + if( mpWindowImpl->mpFrameData->mxClipboard.is() ) + { + Reference< XInitialization > xInit = Reference< XInitialization >( mpWindowImpl->mpFrameData->mxClipboard, UNO_QUERY ); + + if( xInit.is() ) + { + Sequence< Any > aArgumentList( 3 ); + aArgumentList[ 0 ] = makeAny( Application::GetDisplayConnection() ); + aArgumentList[ 1 ] = makeAny( OUString::createFromAscii( "CLIPBOARD" ) ); + aArgumentList[ 2 ] = makeAny( vcl::createBmpConverter() ); + + xInit->initialize( aArgumentList ); + } + } +#endif + } + } + + // createInstance can throw any exception + catch( Exception exc ) + { + // release all instances + mpWindowImpl->mpFrameData->mxClipboard.clear(); + } + } + + return mpWindowImpl->mpFrameData->mxClipboard; + } + + return static_cast < XClipboard * > (0); +} + +// ----------------------------------------------------------------------- + +Reference< XClipboard > Window::GetPrimarySelection() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mpWindowImpl->mpFrameData ) + { + if( ! mpWindowImpl->mpFrameData->mxSelection.is() ) + { + try + { + Reference< XMultiServiceFactory > xFactory( vcl::unohelper::GetMultiServiceFactory() ); + + if( xFactory.is() ) + { +#if defined(UNX) && !defined(QUARTZ) + Sequence< Any > aArgumentList( 3 ); + aArgumentList[ 0 ] = makeAny( Application::GetDisplayConnection() ); + aArgumentList[ 1 ] = makeAny( OUString::createFromAscii( "PRIMARY" ) ); + aArgumentList[ 2 ] = makeAny( vcl::createBmpConverter() ); + + mpWindowImpl->mpFrameData->mxSelection = Reference< XClipboard >( xFactory->createInstanceWithArguments( + OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.SystemClipboard" ), aArgumentList ), UNO_QUERY ); +# else + static Reference< XClipboard > s_xSelection; + + if ( !s_xSelection.is() ) + s_xSelection = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.GenericClipboardExt" ) ), UNO_QUERY ); + + if ( !s_xSelection.is() ) + s_xSelection = Reference< XClipboard >( xFactory->createInstance( OUString::createFromAscii( "com.sun.star.datatransfer.clipboard.GenericClipboard" ) ), UNO_QUERY ); + + mpWindowImpl->mpFrameData->mxSelection = s_xSelection; +# endif + } + } + + // createInstance can throw any exception + catch( Exception exc ) + { + // release all instances + mpWindowImpl->mpFrameData->mxSelection.clear(); + } + } + + return mpWindowImpl->mpFrameData->mxSelection; + } + + return static_cast < XClipboard * > (0); +} + +// ----------------------------------------------------------------------- +// Accessibility +// ----------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Window::GetAccessible( BOOL bCreate ) +{ + // do not optimize hierarchy for the top level border win (ie, when there is no parent) + /* // do not optimize accessible hierarchy at all to better reflect real VCL hierarchy + if ( GetParent() && ( GetType() == WINDOW_BORDERWINDOW ) && ( GetChildCount() == 1 ) ) + //if( !ImplIsAccessibleCandidate() ) + { + Window* pChild = GetAccessibleChildWindow( 0 ); + if ( pChild ) + return pChild->GetAccessible(); + } + */ + if ( !mpWindowImpl->mxAccessible.is() && bCreate ) + mpWindowImpl->mxAccessible = CreateAccessible(); + + return mpWindowImpl->mxAccessible; +} + +::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > Window::CreateAccessible() +{ + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAcc( GetComponentInterface( TRUE ), ::com::sun::star::uno::UNO_QUERY ); + return xAcc; +} + +void Window::SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > x ) +{ + mpWindowImpl->mxAccessible = x; +} + +// skip all border windows that are no top level frames +BOOL Window::ImplIsAccessibleCandidate() const +{ + if( !mpWindowImpl->mbBorderWin ) + return TRUE; + else + // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menues!) are closeable + if( mpWindowImpl->mbFrame && mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) ) + return TRUE; + else + return FALSE; +} + +BOOL Window::ImplIsAccessibleNativeFrame() const +{ + if( mpWindowImpl->mbFrame ) + // #101741 do not check for WB_CLOSEABLE because undecorated floaters (like menues!) are closeable + if( (mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE)) ) + return TRUE; + else + return FALSE; + else + return FALSE; +} + +USHORT Window::ImplGetAccessibleCandidateChildWindowCount( USHORT nFirstWindowType ) const +{ + USHORT nChildren = 0; + Window* pChild = GetWindow( nFirstWindowType ); + while ( pChild ) + { + if( pChild->ImplIsAccessibleCandidate() ) + nChildren++; + else + nChildren = sal::static_int_cast<USHORT>(nChildren + pChild->ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTCHILD )); + pChild = pChild->mpWindowImpl->mpNext; + } + return nChildren; +} + +Window* Window::ImplGetAccessibleCandidateChild( USHORT nChild, USHORT& rChildCount, USHORT nFirstWindowType, BOOL bTopLevel ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( bTopLevel ) + rChildCount = 0; + + Window* pChild = GetWindow( nFirstWindowType ); + while ( pChild ) + { + Window *pTmpChild = pChild; + + if( !pChild->ImplIsAccessibleCandidate() ) + pTmpChild = pChild->ImplGetAccessibleCandidateChild( nChild, rChildCount, WINDOW_FIRSTCHILD, FALSE ); + + if ( nChild == rChildCount ) + return pTmpChild; + pChild = pChild->mpWindowImpl->mpNext; + rChildCount++; + } + + return NULL; +} + +/* +Window* Window::GetAccessibleParentWindow() const +{ + Window* pParent = GetParent(); + while ( pParent ) + if( pParent->ImplIsAccessibleCandidate() ) + break; + else + pParent = pParent->GetParent(); + return pParent; +} +*/ + +Window* Window::GetAccessibleParentWindow() const +{ + if ( ImplIsAccessibleNativeFrame() ) + return NULL; + + Window* pParent = mpWindowImpl->mpParent; + if( GetType() == WINDOW_MENUBARWINDOW ) + { + // report the menubar as a child of THE workwindow + Window *pWorkWin = GetParent()->mpWindowImpl->mpFirstChild; + while( pWorkWin && (pWorkWin == this) ) + pWorkWin = pWorkWin->mpWindowImpl->mpNext; + pParent = pWorkWin; + } + // If this a floating window which has a native boarder window, this one should be reported as + // accessible parent + else if( GetType() == WINDOW_FLOATINGWINDOW && + mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) + { + pParent = mpWindowImpl->mpBorderWindow; + } + else if( pParent && !pParent->ImplIsAccessibleCandidate() ) + { + pParent = pParent->mpWindowImpl->mpParent; + } + return pParent; +} + +/* +USHORT Window::GetAccessibleChildWindowCount() +{ + USHORT nChildren = ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTCHILD ); + + // Search also for SystemWindows. + Window* pOverlap = GetWindow( WINDOW_OVERLAP ); + nChildren += pOverlap->ImplGetAccessibleCandidateChildWindowCount( WINDOW_FIRSTOVERLAP ); + + return nChildren; +} +*/ + +USHORT Window::GetAccessibleChildWindowCount() +{ + USHORT nChildren = 0; + Window* pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + if( pChild->IsVisible() ) + nChildren++; + pChild = pChild->mpWindowImpl->mpNext; + } + + // #107176# ignore overlapwindows + // this only affects non-system floating windows + // which are either not accessible (like the HelpAgent) or should be changed to system windows anyway + /* + if( ImplIsOverlapWindow() ) + { + Window* pOverlap = GetWindow( WINDOW_FIRSTOVERLAP ); + while ( pOverlap ) + { + if( pOverlap->IsVisible() ) + nChildren++; + pOverlap = pOverlap->GetWindow( WINDOW_NEXT ); + } + } + */ + + // report the menubarwindow as a child of THE workwindow + if( GetType() == WINDOW_BORDERWINDOW ) + { + if( ((ImplBorderWindow *) this)->mpMenuBarWindow && + ((ImplBorderWindow *) this)->mpMenuBarWindow->IsVisible() + ) + --nChildren; + } + else if( GetType() == WINDOW_WORKWINDOW ) + { + if( ((WorkWindow *) this)->GetMenuBar() && + ((WorkWindow *) this)->GetMenuBar()->GetWindow() && + ((WorkWindow *) this)->GetMenuBar()->GetWindow()->IsVisible() + ) + ++nChildren; + } + + return nChildren; +} + +/* +Window* Window::GetAccessibleChildWindow( USHORT n ) +{ + USHORT nChildCount; // will be set in ImplGetAccessibleCandidateChild(...) + Window* pChild = ImplGetAccessibleCandidateChild( n, nChildCount, WINDOW_FIRSTCHILD, TRUE ); + if ( !pChild && ( n >= nChildCount ) ) + { + Window* pOverlap = GetWindow( WINDOW_OVERLAP ); + pChild = pOverlap->ImplGetAccessibleCandidateChild( n, nChildCount, WINDOW_FIRSTOVERLAP, FALSE ); + } + + return pChild; +} +*/ + +Window* Window::GetAccessibleChildWindow( USHORT n ) +{ + // report the menubarwindow as a the first child of THE workwindow + if( GetType() == WINDOW_WORKWINDOW && ((WorkWindow *) this)->GetMenuBar() ) + { + if( n == 0 ) + { + MenuBar *pMenuBar = ((WorkWindow *) this)->GetMenuBar(); + if( pMenuBar->GetWindow() && pMenuBar->GetWindow()->IsVisible() ) + return pMenuBar->GetWindow(); + } + else + --n; + } + + // transform n to child number including invisible children + USHORT nChildren = n; + Window* pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + if( pChild->IsVisible() ) + { + if( ! nChildren ) + break; + nChildren--; + } + pChild = pChild->mpWindowImpl->mpNext; + } + + if( GetType() == WINDOW_BORDERWINDOW && pChild && pChild->GetType() == WINDOW_MENUBARWINDOW ) + { + do pChild = pChild->mpWindowImpl->mpNext; while( pChild && ! pChild->IsVisible() ); + DBG_ASSERT( pChild, "GetAccessibleChildWindow(): wrong index in border window"); + } + if ( !pChild ) + { + // #107176# ignore overlapwindows + /* + if( ImplIsOverlapWindow() ) + { + Window* pOverlap = GetWindow( WINDOW_FIRSTOVERLAP ); + while ( !pChild && pOverlap ) + { + if ( !nChildren && pOverlap->IsVisible() ) + { + pChild = pOverlap; + break; + } + pOverlap = pOverlap->GetWindow( WINDOW_NEXT ); + if( pOverlap && pOverlap->IsVisible() ) + nChildren--; + } + } + */ + + } + if ( pChild && ( pChild->GetType() == WINDOW_BORDERWINDOW ) && ( pChild->GetChildCount() == 1 ) ) + { + pChild = pChild->GetChild( 0 ); + } + return pChild; +} + + +void Window::SetAccessibleRole( USHORT nRole ) +{ + if ( !mpWindowImpl->mpAccessibleInfos ) + mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos; + + DBG_ASSERT( mpWindowImpl->mpAccessibleInfos->nAccessibleRole == 0xFFFF, "AccessibleRole already set!" ); + mpWindowImpl->mpAccessibleInfos->nAccessibleRole = nRole; +} + +USHORT Window::GetAccessibleRole() const +{ + using namespace ::com::sun::star; + + USHORT nRole = mpWindowImpl->mpAccessibleInfos ? mpWindowImpl->mpAccessibleInfos->nAccessibleRole : 0xFFFF; + if ( nRole == 0xFFFF ) + { + switch ( GetType() ) + { + case WINDOW_MESSBOX: // MT: Would be nice to have special roles! + case WINDOW_INFOBOX: + case WINDOW_WARNINGBOX: + case WINDOW_ERRORBOX: + case WINDOW_QUERYBOX: nRole = accessibility::AccessibleRole::ALERT; break; + + case WINDOW_MODELESSDIALOG: + case WINDOW_MODALDIALOG: + case WINDOW_SYSTEMDIALOG: + case WINDOW_PRINTERSETUPDIALOG: + case WINDOW_PRINTDIALOG: + case WINDOW_TABDIALOG: + case WINDOW_BUTTONDIALOG: + case WINDOW_DIALOG: nRole = accessibility::AccessibleRole::DIALOG; break; + + case WINDOW_PUSHBUTTON: + case WINDOW_OKBUTTON: + case WINDOW_CANCELBUTTON: + case WINDOW_HELPBUTTON: + case WINDOW_IMAGEBUTTON: + case WINDOW_MENUBUTTON: + case WINDOW_MOREBUTTON: + case WINDOW_SPINBUTTON: + case WINDOW_BUTTON: nRole = accessibility::AccessibleRole::PUSH_BUTTON; break; + + case WINDOW_PATHDIALOG: nRole = accessibility::AccessibleRole::DIRECTORY_PANE; break; + case WINDOW_FILEDIALOG: nRole = accessibility::AccessibleRole::FILE_CHOOSER; break; + case WINDOW_COLORDIALOG: nRole = accessibility::AccessibleRole::COLOR_CHOOSER; break; + case WINDOW_FONTDIALOG: nRole = accessibility::AccessibleRole::FONT_CHOOSER; break; + + case WINDOW_IMAGERADIOBUTTON: + case WINDOW_RADIOBUTTON: nRole = accessibility::AccessibleRole::RADIO_BUTTON; break; + case WINDOW_TRISTATEBOX: + case WINDOW_CHECKBOX: nRole = accessibility::AccessibleRole::CHECK_BOX; break; + + case WINDOW_MULTILINEEDIT: nRole = accessibility::AccessibleRole::SCROLL_PANE; break; + + case WINDOW_PATTERNFIELD: + case WINDOW_NUMERICFIELD: + case WINDOW_METRICFIELD: + case WINDOW_CURRENCYFIELD: + case WINDOW_LONGCURRENCYFIELD: + case WINDOW_EDIT: nRole = ( GetStyle() & WB_PASSWORD ) ? (accessibility::AccessibleRole::PASSWORD_TEXT) : (accessibility::AccessibleRole::TEXT); break; + + case WINDOW_PATTERNBOX: + case WINDOW_NUMERICBOX: + case WINDOW_METRICBOX: + case WINDOW_CURRENCYBOX: + case WINDOW_LONGCURRENCYBOX: + case WINDOW_COMBOBOX: nRole = accessibility::AccessibleRole::COMBO_BOX; break; + + case WINDOW_LISTBOX: + case WINDOW_MULTILISTBOX: nRole = accessibility::AccessibleRole::LIST; break; + + case WINDOW_TREELISTBOX: nRole = accessibility::AccessibleRole::TREE; break; + + case WINDOW_FIXEDTEXT: nRole = accessibility::AccessibleRole::LABEL; break; + case WINDOW_FIXEDBORDER: + case WINDOW_FIXEDLINE: nRole = accessibility::AccessibleRole::SEPARATOR; break; + case WINDOW_FIXEDBITMAP: + case WINDOW_FIXEDIMAGE: nRole = accessibility::AccessibleRole::ICON; break; + case WINDOW_GROUPBOX: nRole = accessibility::AccessibleRole::GROUP_BOX; break; + case WINDOW_SCROLLBAR: nRole = accessibility::AccessibleRole::SCROLL_BAR; break; + + case WINDOW_SLIDER: + case WINDOW_SPLITTER: + case WINDOW_SPLITWINDOW: nRole = accessibility::AccessibleRole::SPLIT_PANE; break; + + case WINDOW_DATEBOX: + case WINDOW_TIMEBOX: + case WINDOW_DATEFIELD: + case WINDOW_TIMEFIELD: nRole = accessibility::AccessibleRole::DATE_EDITOR; break; + + case WINDOW_SPINFIELD: nRole = accessibility::AccessibleRole::SPIN_BOX; break; + + case WINDOW_TOOLBOX: nRole = accessibility::AccessibleRole::TOOL_BAR; break; + case WINDOW_STATUSBAR: nRole = accessibility::AccessibleRole::STATUS_BAR; break; + + case WINDOW_TABPAGE: nRole = accessibility::AccessibleRole::PANEL; break; + case WINDOW_TABCONTROL: nRole = accessibility::AccessibleRole::PAGE_TAB_LIST; break; + + case WINDOW_DOCKINGWINDOW: + case WINDOW_SYSWINDOW: nRole = (mpWindowImpl->mbFrame) ? accessibility::AccessibleRole::FRAME : + accessibility::AccessibleRole::PANEL; break; + + case WINDOW_FLOATINGWINDOW: nRole = ( mpWindowImpl->mbFrame || + (mpWindowImpl->mpBorderWindow && mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) || + (GetStyle() & WB_OWNERDRAWDECORATION) ) ? accessibility::AccessibleRole::FRAME : + accessibility::AccessibleRole::WINDOW; break; + + case WINDOW_WORKWINDOW: nRole = accessibility::AccessibleRole::ROOT_PANE; break; + + + case WINDOW_SCROLLBARBOX: nRole = accessibility::AccessibleRole::FILLER; break; + + case WINDOW_HELPTEXTWINDOW: nRole = accessibility::AccessibleRole::TOOL_TIP; break; + + case WINDOW_WINDOW: + case WINDOW_CONTROL: + case WINDOW_BORDERWINDOW: + case WINDOW_SYSTEMCHILDWINDOW: + default: + if (ImplIsAccessibleNativeFrame() ) + nRole = accessibility::AccessibleRole::FRAME; + else if( IsScrollable() ) + nRole = accessibility::AccessibleRole::SCROLL_PANE; + else if( ((Window*)this)->ImplGetWindow()->IsMenuFloatingWindow() ) + nRole = accessibility::AccessibleRole::WINDOW; // #106002#, contextmenues are windows (i.e. toplevel) + else + // #104051# WINDOW seems to be a bad default role, use LAYEREDPANE instead + // a WINDOW is interpreted as a top-level window, which is typically not the case + //nRole = accessibility::AccessibleRole::WINDOW; + nRole = accessibility::AccessibleRole::PANEL; + } + } + return nRole; +} + +void Window::SetAccessibleName( const String& rName ) +{ + if ( !mpWindowImpl->mpAccessibleInfos ) + mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos; + + DBG_ASSERT( !mpWindowImpl->mpAccessibleInfos->pAccessibleName, "AccessibleName already set!" ); + delete mpWindowImpl->mpAccessibleInfos->pAccessibleName; + mpWindowImpl->mpAccessibleInfos->pAccessibleName = new String( rName ); +} + +String Window::GetAccessibleName() const +{ + String aAccessibleName; + if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleName ) + { + aAccessibleName = *mpWindowImpl->mpAccessibleInfos->pAccessibleName; + } + else + { + switch ( GetType() ) + { +// case WINDOW_IMAGERADIOBUTTON: +// case WINDOW_RADIOBUTTON: +// case WINDOW_TRISTATEBOX: +// case WINDOW_CHECKBOX: + + case WINDOW_MULTILINEEDIT: + case WINDOW_PATTERNFIELD: + case WINDOW_NUMERICFIELD: + case WINDOW_METRICFIELD: + case WINDOW_CURRENCYFIELD: + case WINDOW_LONGCURRENCYFIELD: + case WINDOW_EDIT: + + case WINDOW_DATEBOX: + case WINDOW_TIMEBOX: + case WINDOW_CURRENCYBOX: + case WINDOW_LONGCURRENCYBOX: + case WINDOW_DATEFIELD: + case WINDOW_TIMEFIELD: + case WINDOW_SPINFIELD: + + case WINDOW_COMBOBOX: + case WINDOW_LISTBOX: + case WINDOW_MULTILISTBOX: + case WINDOW_TREELISTBOX: + + { + Window *pLabel = GetLabeledBy(); + if ( pLabel && pLabel != this ) + aAccessibleName = pLabel->GetText(); + } + break; + + case WINDOW_IMAGEBUTTON: + case WINDOW_PUSHBUTTON: + aAccessibleName = GetText(); + if ( !aAccessibleName.Len() ) + { + aAccessibleName = GetQuickHelpText(); + if ( !aAccessibleName.Len() ) + aAccessibleName = GetHelpText(); + } + break; + + default: + aAccessibleName = GetText(); + break; + } + + aAccessibleName = GetNonMnemonicString( aAccessibleName ); + } + + return aAccessibleName; +} + +void Window::SetAccessibleDescription( const String& rDescription ) +{ + if ( ! mpWindowImpl->mpAccessibleInfos ) + mpWindowImpl->mpAccessibleInfos = new ImplAccessibleInfos; + + DBG_ASSERT( !mpWindowImpl->mpAccessibleInfos->pAccessibleDescription, "AccessibleDescription already set!" ); + delete mpWindowImpl->mpAccessibleInfos->pAccessibleDescription; + mpWindowImpl->mpAccessibleInfos->pAccessibleDescription = new String( rDescription ); +} + +String Window::GetAccessibleDescription() const +{ + String aAccessibleDescription; + if ( mpWindowImpl->mpAccessibleInfos && mpWindowImpl->mpAccessibleInfos->pAccessibleDescription ) + { + aAccessibleDescription = *mpWindowImpl->mpAccessibleInfos->pAccessibleDescription; + } + else + { + // Special code for help text windows. ZT asks the border window for the + // description so we have to forward this request to our inner window. + const Window* pWin = ((Window *)this)->ImplGetWindow(); + if ( pWin->GetType() == WINDOW_HELPTEXTWINDOW ) + aAccessibleDescription = pWin->GetHelpText(); + else + aAccessibleDescription = GetHelpText(); + } + + return aAccessibleDescription; +} + +BOOL Window::IsAccessibilityEventsSuppressed( BOOL bTraverseParentPath ) +{ + if( !bTraverseParentPath ) + return mpWindowImpl->mbSuppressAccessibilityEvents; + else + { + Window *pParent = this; + while ( pParent && pParent->mpWindowImpl) + { + if( pParent->mpWindowImpl->mbSuppressAccessibilityEvents ) + return TRUE; + else + pParent = pParent->mpWindowImpl->mpParent; // do not use GetParent() to find borderwindows that are frames + } + return FALSE; + } +} + +void Window::RecordLayoutData( vcl::ControlLayoutData* pLayout, const Rectangle& rRect ) +{ + if( ! mpOutDevData ) + ImplInitOutDevData(); + mpOutDevData->mpRecordLayout = pLayout; + mpOutDevData->maRecordRect = rRect; + Paint( rRect ); + mpOutDevData->mpRecordLayout = NULL; +} + +// ----------------------------------------------------------------------- +// ----------------------------------------------------------------------- + + +// returns background color used in this control +// false: could not determine color +BOOL Window::ImplGetCurrentBackgroundColor( Color& rCol ) +{ + BOOL bRet = TRUE; + + switch ( GetType() ) + { + // peform special handling here + case WINDOW_PUSHBUTTON: + case WINDOW_OKBUTTON: + case WINDOW_CANCELBUTTON: + // etc. + default: + if( IsControlBackground() ) + rCol = GetControlBackground(); + else if( IsBackground() ) + { + Wallpaper aWall = GetBackground(); + if( !aWall.IsGradient() && !aWall.IsBitmap() ) + rCol = aWall.GetColor(); + else + bRet = FALSE; + } + else + rCol = GetSettings().GetStyleSettings().GetFaceColor(); + break; + } + return bRet; +} + +void Window::DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly ) +{ + DrawSelectionBackground( rRect, highlight, bChecked, bDrawBorder, bDrawExtBorderOnly, 0, NULL, NULL ); +} + +void Window::DrawSelectionBackground( const Rectangle& rRect, USHORT highlight, BOOL bChecked, BOOL bDrawBorder, BOOL bDrawExtBorderOnly, Color* pSelectionTextColor ) +{ + DrawSelectionBackground( rRect, highlight, bChecked, bDrawBorder, bDrawExtBorderOnly, 0, pSelectionTextColor, NULL ); +} + +void Window::DrawSelectionBackground( const Rectangle& rRect, + USHORT highlight, + BOOL bChecked, + BOOL bDrawBorder, + BOOL bDrawExtBorderOnly, + long nCornerRadius, + Color* pSelectionTextColor, + Color* pPaintColor + ) +{ + if( rRect.IsEmpty() ) + return; + + bool bRoundEdges = nCornerRadius > 0; + + const StyleSettings& rStyles = GetSettings().GetStyleSettings(); + + + // colors used for item highlighting + Color aSelectionBorderCol( pPaintColor ? *pPaintColor : rStyles.GetHighlightColor() ); + Color aSelectionFillCol( aSelectionBorderCol ); + + BOOL bDark = rStyles.GetFaceColor().IsDark(); + BOOL bBright = ( rStyles.GetFaceColor() == Color( COL_WHITE ) ); + + int c1 = aSelectionBorderCol.GetLuminance(); + int c2 = GetDisplayBackground().GetColor().GetLuminance(); + + if( !bDark && !bBright && abs( c2-c1 ) < (pPaintColor ? 40 : 75) ) + { + // constrast too low + USHORT h,s,b; + aSelectionFillCol.RGBtoHSB( h, s, b ); + if( b > 50 ) b -= 40; + else b += 40; + aSelectionFillCol.SetColor( Color::HSBtoRGB( h, s, b ) ); + aSelectionBorderCol = aSelectionFillCol; + } + + if( bRoundEdges ) + { + if( aSelectionBorderCol.IsDark() ) + aSelectionBorderCol.IncreaseLuminance( 128 ); + else + aSelectionBorderCol.DecreaseLuminance( 128 ); + } + + Rectangle aRect( rRect ); + if( bDrawExtBorderOnly ) + { + aRect.nLeft -= 1; + aRect.nTop -= 1; + aRect.nRight += 1; + aRect.nBottom += 1; + } + Color oldFillCol = GetFillColor(); + Color oldLineCol = GetLineColor(); + + if( bDrawBorder ) + SetLineColor( bDark ? Color(COL_WHITE) : ( bBright ? Color(COL_BLACK) : aSelectionBorderCol ) ); + else + SetLineColor(); + + USHORT nPercent = 0; + if( !highlight ) + { + if( bDark ) + aSelectionFillCol = COL_BLACK; + else + nPercent = 80; // just checked (light) + } + else + { + if( bChecked && highlight == 2 ) + { + if( bDark ) + aSelectionFillCol = COL_LIGHTGRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + SetLineColor( COL_BLACK ); + nPercent = 0; + } + else + nPercent = bRoundEdges ? 40 : 20; // selected, pressed or checked ( very dark ) + } + else if( bChecked || highlight == 1 ) + { + if( bDark ) + aSelectionFillCol = COL_GRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + SetLineColor( COL_BLACK ); + nPercent = 0; + } + else + nPercent = bRoundEdges ? 60 : 35; // selected, pressed or checked ( very dark ) + } + else + { + if( bDark ) + aSelectionFillCol = COL_LIGHTGRAY; + else if ( bBright ) + { + aSelectionFillCol = COL_BLACK; + SetLineColor( COL_BLACK ); + if( highlight == 3 ) + nPercent = 80; + else + nPercent = 0; + } + else + nPercent = 70; // selected ( dark ) + } + } + + if( bDark && bDrawExtBorderOnly ) + { + SetFillColor(); + if( pSelectionTextColor ) + *pSelectionTextColor = rStyles.GetHighlightTextColor(); + } + else + { + SetFillColor( aSelectionFillCol ); + if( pSelectionTextColor ) + { + Color aTextColor = IsControlBackground() ? GetControlForeground() : rStyles.GetButtonTextColor(); + Color aHLTextColor = rStyles.GetHighlightTextColor(); + int nTextDiff = abs(aSelectionFillCol.GetLuminance() - aTextColor.GetLuminance()); + int nHLDiff = abs(aSelectionFillCol.GetLuminance() - aHLTextColor.GetLuminance()); + *pSelectionTextColor = (nHLDiff >= nTextDiff) ? aHLTextColor : aTextColor; + } + } + + + if( bDark ) + { + DrawRect( aRect ); + } + else + { + if( bRoundEdges ) + { + Polygon aPoly( aRect, nCornerRadius, nCornerRadius ); + PolyPolygon aPolyPoly( aPoly ); + DrawTransparent( aPolyPoly, nPercent ); + } + else + { + Polygon aPoly( aRect ); + PolyPolygon aPolyPoly( aPoly ); + DrawTransparent( aPolyPoly, nPercent ); + } + } + + SetFillColor( oldFillCol ); + SetLineColor( oldLineCol ); +} + +/* +void Window::DbgAssertNoEventListeners() +{ + VclWindowEvent aEvent( this, 0, NULL ); + DBG_ASSERT( mpWindowImpl->maEventListeners.empty(), "Eventlistener: Who is still listening???" ) + if ( !mpWindowImpl->maEventListeners.empty() ) + mpWindowImpl->maEventListeners.Call( &aEvent ); + + DBG_ASSERT( mpWindowImpl->maChildEventListeners.empty(), "ChildEventlistener: Who is still listening???" ) + if ( !mpWindowImpl->maChildEventListeners.empty() ) + mpWindowImpl->maChildEventListeners.Call( &aEvent ); +} +*/ + +// controls should return the window that gets the +// focus by default, so keyevents can be sent to that window directly +Window* Window::GetPreferredKeyInputWindow() +{ + return this; +} + + +BOOL Window::IsScrollable() const +{ + // check for scrollbars + Window *pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + if( pChild->GetType() == WINDOW_SCROLLBAR ) + return true; + else + pChild = pChild->mpWindowImpl->mpNext; + } + return false; +} + +BOOL Window::IsTopWindow() const +{ + if ( mpWindowImpl->mbInDtor ) + return FALSE; + + // topwindows must be frames or they must have a borderwindow which is a frame + if( !mpWindowImpl->mbFrame && (!mpWindowImpl->mpBorderWindow || (mpWindowImpl->mpBorderWindow && !mpWindowImpl->mpBorderWindow->mpWindowImpl->mbFrame) ) ) + return FALSE; + + ImplGetWinData(); + if( mpWindowImpl->mpWinData->mnIsTopWindow == (USHORT)~0) // still uninitialized + { + // #113722#, cache result of expensive queryInterface call + Window *pThisWin = (Window*)this; + Reference< XTopWindow > xTopWindow( pThisWin->GetComponentInterface(), UNO_QUERY ); + pThisWin->mpWindowImpl->mpWinData->mnIsTopWindow = xTopWindow.is() ? 1 : 0; + } + return mpWindowImpl->mpWinData->mnIsTopWindow == 1 ? TRUE : FALSE; +} + +void Window::ImplMirrorFramePos( Point &pt ) const +{ + pt.X() = mpWindowImpl->mpFrame->maGeometry.nWidth-1-pt.X(); +} + +// frame based modal counter (dialogs are not modal to the whole application anymore) +BOOL Window::IsInModalMode() const +{ + return (mpWindowImpl->mpFrameWindow->mpWindowImpl->mpFrameData->mnModalMode != 0); +} +void Window::ImplIncModalCount() +{ + Window* pFrameWindow = mpWindowImpl->mpFrameWindow; + Window* pParent = pFrameWindow; + while( pFrameWindow ) + { + pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode++; + while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow ) + { + pParent = pParent->GetParent(); + } + pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow : NULL; + } +} +void Window::ImplDecModalCount() +{ + Window* pFrameWindow = mpWindowImpl->mpFrameWindow; + Window* pParent = pFrameWindow; + while( pFrameWindow ) + { + pFrameWindow->mpWindowImpl->mpFrameData->mnModalMode--; + while( pParent && pParent->mpWindowImpl->mpFrameWindow == pFrameWindow ) + { + pParent = pParent->GetParent(); + } + pFrameWindow = pParent ? pParent->mpWindowImpl->mpFrameWindow : NULL; + } +} +BOOL Window::ImplIsInTaskPaneList() +{ + return mpWindowImpl->mbIsInTaskPaneList; +} +void Window::ImplIsInTaskPaneList( BOOL mbIsInTaskList ) +{ + mpWindowImpl->mbIsInTaskPaneList = mbIsInTaskList; +} + +void Window::ImplNotifyIconifiedState( BOOL bIconified ) +{ + mpWindowImpl->mpFrameWindow->ImplCallEventListeners( bIconified ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE ); + // #109206# notify client window as well to have toolkit topwindow listeners notified + if( mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow && mpWindowImpl->mpFrameWindow != mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow ) + mpWindowImpl->mpFrameWindow->mpWindowImpl->mpClientWindow->ImplCallEventListeners( bIconified ? VCLEVENT_WINDOW_MINIMIZE : VCLEVENT_WINDOW_NORMALIZE ); +} + +BOOL Window::HasActiveChildFrame() +{ + BOOL bRet = FALSE; + Window *pFrameWin = ImplGetSVData()->maWinData.mpFirstFrame; + while( pFrameWin ) + { + if( pFrameWin != mpWindowImpl->mpFrameWindow ) + { + BOOL bDecorated = FALSE; + Window *pChildFrame = pFrameWin->ImplGetWindow(); + // #i15285# unfortunately WB_MOVEABLE is the same as WB_TABSTOP which can + // be removed for ToolBoxes to influence the keyboard accessibility + // thus WB_MOVEABLE is no indicator for decoration anymore + // but FloatingWindows carry this information in their TitleType... + // TODO: avoid duplicate WinBits !!! + if( pChildFrame && pChildFrame->ImplIsFloatingWindow() ) + bDecorated = ((FloatingWindow*) pChildFrame)->GetTitleType() != FLOATWIN_TITLE_NONE; + if( bDecorated || (pFrameWin->mpWindowImpl->mnStyle & (WB_MOVEABLE | WB_SIZEABLE) ) ) + if( pChildFrame && pChildFrame->IsVisible() && pChildFrame->IsActive() ) + { + if( ImplIsChild( pChildFrame, TRUE ) ) + { + bRet = TRUE; + break; + } + } + } + pFrameWin = pFrameWin->mpWindowImpl->mpFrameData->mpNextFrame; + } + return bRet; +} + +LanguageType Window::GetInputLanguage() const +{ + return mpWindowImpl->mpFrame->GetInputLanguage(); +} + +void Window::EnableNativeWidget( BOOL bEnable ) +{ + static const char* pNoNWF = getenv( "SAL_NO_NWF" ); + if( pNoNWF && *pNoNWF ) + bEnable = FALSE; + + if( bEnable != ImplGetWinData()->mbEnableNativeWidget ) + { + ImplGetWinData()->mbEnableNativeWidget = bEnable; + + // send datachanged event to allow for internal changes required for NWF + // like clipmode, transparency, etc. + DataChangedEvent aDCEvt( DATACHANGED_SETTINGS, &maSettings, SETTINGS_STYLE ); + DataChanged( aDCEvt ); + + // sometimes the borderwindow is queried, so keep it in sync + if( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->ImplGetWinData()->mbEnableNativeWidget = bEnable; + } + + // push down, useful for compound controls + Window *pChild = mpWindowImpl->mpFirstChild; + while( pChild ) + { + pChild->EnableNativeWidget( bEnable ); + pChild = pChild->mpWindowImpl->mpNext; + } +} + +BOOL Window::IsNativeWidgetEnabled() const +{ + return ImplGetWinData()->mbEnableNativeWidget; +} + +#ifdef WNT // see #140456# +#include <salframe.h> +#endif + +Reference< rendering::XCanvas > Window::ImplGetCanvas( const Size& rFullscreenSize, + bool bFullscreen, + bool bSpriteCanvas ) const +{ + // try to retrieve hard reference from weak member + Reference< rendering::XCanvas > xCanvas( mpWindowImpl->mxCanvas ); + + // canvas still valid? Then we're done. + if( xCanvas.is() ) + return xCanvas; + + Sequence< Any > aArg(6); + + // Feed any with operating system's window handle + // ============================================== + + // common: first any is VCL pointer to window (for VCL canvas) + aArg[ 0 ] = makeAny( reinterpret_cast<sal_Int64>(this) ); + + // TODO(Q1): Make GetSystemData method virtual + + // check whether we're a SysChild: have to fetch system data + // directly from SystemChildWindow, because the GetSystemData + // method is unfortunately not virtual + const SystemChildWindow* pSysChild = dynamic_cast< const SystemChildWindow* >( this ); + if( pSysChild ) + { + aArg[ 1 ] = pSysChild->GetSystemDataAny(); + aArg[ 5 ] = pSysChild->GetSystemGfxDataAny(); + } + else + { + aArg[ 1 ] = GetSystemDataAny(); + aArg[ 5 ] = GetSystemGfxDataAny(); + } + + if( bFullscreen ) + aArg[ 2 ] = makeAny( ::com::sun::star::awt::Rectangle( 0, 0, + rFullscreenSize.Width(), + rFullscreenSize.Height() ) ); + else + aArg[ 2 ] = makeAny( ::com::sun::star::awt::Rectangle( mnOutOffX, mnOutOffY, mnOutWidth, mnOutHeight ) ); + + aArg[ 3 ] = makeAny( mpWindowImpl->mbAlwaysOnTop ? sal_True : sal_False ); + aArg[ 4 ] = makeAny( Reference< awt::XWindow >( + const_cast<Window*>(this)->GetComponentInterface(), + uno::UNO_QUERY )); + + Reference< XMultiServiceFactory > xFactory = vcl::unohelper::GetMultiServiceFactory(); + + // Create canvas instance with window handle + // ========================================= + if ( xFactory.is() ) + { + static ::vcl::DeleteUnoReferenceOnDeinit<XMultiServiceFactory> xStaticCanvasFactory( + Reference<XMultiServiceFactory>( + xFactory->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.rendering.CanvasFactory") ) ), + UNO_QUERY )); + uno::Reference<XMultiServiceFactory> xCanvasFactory(xStaticCanvasFactory.get()); + + if(xCanvasFactory.is()) + { +#ifdef WNT + // see #140456# - if we're running on a multiscreen setup, + // request special, multi-screen safe sprite canvas + // implementation (not DX5 canvas, as it cannot cope with + // surfaces spanning multiple displays). Note: canvas + // (without sprite) stays the same) + const sal_uInt32 nDisplay = static_cast< WinSalFrame* >( mpWindowImpl->mpFrame )->mnDisplay; + if( (nDisplay >= Application::GetScreenCount()) ) + { + xCanvas.set( xCanvasFactory->createInstanceWithArguments( + bSpriteCanvas ? + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.rendering.SpriteCanvas.MultiScreen" )) : + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.rendering.Canvas" )), + aArg ), + UNO_QUERY ); + + } + else + { +#endif + xCanvas.set( xCanvasFactory->createInstanceWithArguments( + bSpriteCanvas ? + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.rendering.SpriteCanvas" )) : + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.rendering.Canvas" )), + aArg ), + UNO_QUERY ); + +#ifdef WNT + } +#endif + + mpWindowImpl->mxCanvas = xCanvas; + } + } + + // no factory??? Empty reference, then. + return xCanvas; +} + +Reference< rendering::XCanvas > Window::GetCanvas() const +{ + return ImplGetCanvas( Size(), false, false ); +} + +Reference< rendering::XSpriteCanvas > Window::GetSpriteCanvas() const +{ + Reference< rendering::XSpriteCanvas > xSpriteCanvas( + ImplGetCanvas( Size(), false, true ), uno::UNO_QUERY ); + return xSpriteCanvas; +} + +Reference< ::com::sun::star::rendering::XSpriteCanvas > Window::GetFullscreenSpriteCanvas( const Size& rFullscreenSize ) const +{ + Reference< rendering::XSpriteCanvas > xSpriteCanvas( + ImplGetCanvas( rFullscreenSize, true, true ), uno::UNO_QUERY ); + return xSpriteCanvas; +} + +void Window::ImplPaintToDevice( OutputDevice* i_pTargetOutDev, const Point& i_rPos ) +{ + BOOL bRVisible = mpWindowImpl->mbReallyVisible; + mpWindowImpl->mbReallyVisible = mpWindowImpl->mbVisible; + BOOL bDevOutput = mbDevOutput; + mbDevOutput = TRUE; + + long nOldDPIX = ImplGetDPIX(); + long nOldDPIY = ImplGetDPIY(); + mnDPIX = i_pTargetOutDev->ImplGetDPIX(); + mnDPIY = i_pTargetOutDev->ImplGetDPIY(); + BOOL bOutput = IsOutputEnabled(); + EnableOutput(); + + DBG_ASSERT( GetMapMode().GetMapUnit() == MAP_PIXEL, "MapMode must be PIXEL based" ); + if ( GetMapMode().GetMapUnit() != MAP_PIXEL ) + return; + + // preserve graphicsstate + Push(); + Region aClipRegion( GetClipRegion() ); + SetClipRegion(); + + GDIMetaFile* pOldMtf = GetConnectMetaFile(); + GDIMetaFile aMtf; + SetConnectMetaFile( &aMtf ); + + // put a push action to metafile + Push(); + // copy graphics state to metafile + Font aCopyFont = GetFont(); + if( nOldDPIX != mnDPIX || nOldDPIY != mnDPIY ) + { + aCopyFont.SetHeight( aCopyFont.GetHeight() * mnDPIY / nOldDPIY ); + aCopyFont.SetWidth( aCopyFont.GetWidth() * mnDPIX / nOldDPIX ); + } + SetFont( aCopyFont ); + SetTextColor( GetTextColor() ); + if( IsLineColor() ) + SetLineColor( GetLineColor() ); + else + SetLineColor(); + if( IsFillColor() ) + SetFillColor( GetFillColor() ); + else + SetFillColor(); + if( IsTextLineColor() ) + SetTextLineColor( GetTextLineColor() ); + else + SetTextLineColor(); + if( IsOverlineColor() ) + SetOverlineColor( GetOverlineColor() ); + else + SetOverlineColor(); + if( IsTextFillColor() ) + SetTextFillColor( GetTextFillColor() ); + else + SetTextFillColor(); + SetTextAlign( GetTextAlign() ); + SetRasterOp( GetRasterOp() ); + if( IsRefPoint() ) + SetRefPoint( GetRefPoint() ); + else + SetRefPoint(); + SetLayoutMode( GetLayoutMode() ); + SetDigitLanguage( GetDigitLanguage() ); + Rectangle aPaintRect( Point( 0, 0 ), GetOutputSizePixel() ); + aClipRegion.Intersect( aPaintRect ); + SetClipRegion( aClipRegion ); + + // do the actual paint + + // background + if( ! IsPaintTransparent() && IsBackground() && ! (GetParentClipMode() & PARENTCLIPMODE_NOCLIP ) ) + Erase(); + // foreground + Paint( aPaintRect ); + // put a pop action to metafile + Pop(); + + SetConnectMetaFile( pOldMtf ); + EnableOutput( bOutput ); + mpWindowImpl->mbReallyVisible = bRVisible; + + // paint metafile to VDev + VirtualDevice* pMaskedDevice = new VirtualDevice( *i_pTargetOutDev, 0, 0 ); + pMaskedDevice->SetOutputSizePixel( GetOutputSizePixel() ); + pMaskedDevice->EnableRTL( IsRTLEnabled() ); + aMtf.WindStart(); + aMtf.Play( pMaskedDevice ); + BitmapEx aBmpEx( pMaskedDevice->GetBitmapEx( Point( 0, 0 ), pMaskedDevice->GetOutputSizePixel() ) ); + i_pTargetOutDev->DrawBitmapEx( i_rPos, aBmpEx ); + // get rid of virtual device now so they don't pile up during recursive calls + delete pMaskedDevice, pMaskedDevice = NULL; + + + for( Window* pChild = mpWindowImpl->mpFirstChild; pChild; pChild = pChild->mpWindowImpl->mpNext ) + { + if( pChild->mpWindowImpl->mpFrame == mpWindowImpl->mpFrame && pChild->IsVisible() ) + { + long nDeltaX = pChild->mnOutOffX - mnOutOffX; + if( ImplHasMirroredGraphics() ) + nDeltaX = mnOutWidth - nDeltaX - pChild->mnOutWidth; + long nDeltaY = pChild->GetOutOffYPixel() - GetOutOffYPixel(); + Point aPos( i_rPos ); + Point aDelta( nDeltaX, nDeltaY ); + aPos += aDelta; + pChild->ImplPaintToDevice( i_pTargetOutDev, aPos ); + } + } + + // restore graphics state + Pop(); + + EnableOutput( bOutput ); + mpWindowImpl->mbReallyVisible = bRVisible; + mbDevOutput = bDevOutput; + mnDPIX = nOldDPIX; + mnDPIY = nOldDPIY; +} + +void Window::PaintToDevice( OutputDevice* pDev, const Point& rPos, const Size& /*rSize*/ ) +{ + // FIXME: scaling: currently this is for pixel copying only + + DBG_ASSERT( ! pDev->ImplHasMirroredGraphics(), "PaintToDevice to mirroring graphics" ); + DBG_ASSERT( ! pDev->IsRTLEnabled(), "PaintToDevice to mirroring device" ); + + + Point aPos = pDev->LogicToPixel( rPos ); + + Window* pRealParent = NULL; + if( ! mpWindowImpl->mbVisible ) + { + Window* pTempParent = ImplGetDefaultWindow(); + if( pTempParent ) + pTempParent->EnableChildTransparentMode(); + pRealParent = GetParent(); + SetParent( pTempParent ); + // trigger correct visibility flags for children + Show(); + Hide(); + } + + BOOL bVisible = mpWindowImpl->mbVisible; + mpWindowImpl->mbVisible = TRUE; + + if( mpWindowImpl->mpBorderWindow ) + mpWindowImpl->mpBorderWindow->ImplPaintToDevice( pDev, rPos ); + else + ImplPaintToDevice( pDev, rPos ); + + mpWindowImpl->mbVisible = bVisible; + + if( pRealParent ) + SetParent( pRealParent ); +} + +XubString Window::GetSurroundingText() const +{ + return XubString::EmptyString(); +} + +Selection Window::GetSurroundingTextSelection() const +{ + return Selection( 0, 0 ); +} + diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx new file mode 100644 index 000000000000..e5b58a8b6f3c --- /dev/null +++ b/vcl/source/window/window2.cxx @@ -0,0 +1,1981 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <limits.h> +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salbmp.hxx> +#include <vcl/salgdi.hxx> +#include <vcl/salframe.hxx> +#include <tools/debug.hxx> +#include <vcl/svdata.hxx> +#include <vcl/impbmp.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/event.hxx> +#include <vcl/timer.hxx> +#include <vcl/metric.hxx> +#include <vcl/outfont.hxx> +#include <vcl/outdev.h> +#include <tools/poly.hxx> +#include <vcl/virdev.hxx> +#include <vcl/window.h> +#include <vcl/window.hxx> +#include <vcl/scrbar.hxx> +#ifndef _SV_SCRWND_HXX +#include <scrwnd.hxx> +#endif +#include <vcl/dockwin.hxx> + + + +// ======================================================================= + +DBG_NAMEEX( Window ) + +// ======================================================================= + +#define IMPL_MAXSAVEBACKSIZE (640*480) +#define IMPL_MAXALLSAVEBACKSIZE (800*600*2) + +// ======================================================================= + +struct ImplFocusDelData : public ImplDelData +{ + Window* mpFocusWin; +}; + +// ======================================================================= + +BOOL Window::ImplIsWindowInFront( const Window* pTestWindow ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + DBG_CHKOBJ( pTestWindow, Window, ImplDbgCheckWindow ); + + // Testen, ob es Fenster untereinander liegen + pTestWindow = pTestWindow->ImplGetFirstOverlapWindow(); + const Window* pTempWindow = pTestWindow; + const Window* pThisWindow = ImplGetFirstOverlapWindow(); + if ( pTempWindow == pThisWindow ) + return FALSE; + do + { + if ( pTempWindow == pThisWindow ) + return TRUE; + if ( pTempWindow->mpWindowImpl->mbFrame ) + break; + pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow; + } + while ( pTempWindow ); + pTempWindow = pThisWindow; + do + { + if ( pTempWindow == pTestWindow ) + return FALSE; + if ( pTempWindow->mpWindowImpl->mbFrame ) + break; + pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow; + } + while ( pTempWindow ); + + // Fenster auf gleiche Ebene bringen + if ( pThisWindow->mpWindowImpl->mpOverlapWindow != pTestWindow->mpWindowImpl->mpOverlapWindow ) + { + USHORT nThisLevel = 0; + USHORT nTestLevel = 0; + pTempWindow = pThisWindow; + do + { + nThisLevel++; + pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow; + } + while ( !pTempWindow->mpWindowImpl->mbFrame ); + pTempWindow = pTestWindow; + do + { + nTestLevel++; + pTempWindow = pTempWindow->mpWindowImpl->mpOverlapWindow; + } + while ( !pTempWindow->mpWindowImpl->mbFrame ); + + if ( nThisLevel < nTestLevel ) + { + do + { + if ( pTestWindow->mpWindowImpl->mpOverlapWindow == pThisWindow->mpWindowImpl->mpOverlapWindow ) + break; + if ( pTestWindow->mpWindowImpl->mbFrame ) + break; + pTestWindow = pTestWindow->mpWindowImpl->mpOverlapWindow; + } + while ( pTestWindow ); + } + else + { + do + { + if ( pThisWindow->mpWindowImpl->mpOverlapWindow == pTempWindow->mpWindowImpl->mpOverlapWindow ) + break; + if ( pThisWindow->mpWindowImpl->mbFrame ) + break; + pThisWindow = pThisWindow->mpWindowImpl->mpOverlapWindow; + } + while ( pThisWindow ); + } + } + + // Wenn TestWindow vor ThisWindow kommt, liegt es vorne + pTempWindow = pTestWindow; + do + { + if ( pTempWindow == pThisWindow ) + return TRUE; + pTempWindow = pTempWindow->mpWindowImpl->mpNext; + } + while ( pTempWindow ); + + return FALSE; +} + +// ======================================================================= + +void Window::ImplSaveOverlapBackground() +{ + DBG_ASSERT( !mpWindowImpl->mpOverlapData->mpSaveBackDev, "Window::ImplSaveOverlapBackground() - Background already saved" ); + + if ( !mpWindowImpl->mbFrame ) + { + ULONG nSaveBackSize = mnOutWidth*mnOutHeight; + if ( nSaveBackSize <= IMPL_MAXSAVEBACKSIZE ) + { + if ( nSaveBackSize+mpWindowImpl->mpFrameData->mnAllSaveBackSize <= IMPL_MAXALLSAVEBACKSIZE ) + { + Size aOutSize( mnOutWidth, mnOutHeight ); + mpWindowImpl->mpOverlapData->mpSaveBackDev = new VirtualDevice( *mpWindowImpl->mpFrameWindow ); + if ( mpWindowImpl->mpOverlapData->mpSaveBackDev->SetOutputSizePixel( aOutSize ) ) + { + mpWindowImpl->mpFrameWindow->ImplUpdateAll(); + + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + + mpWindowImpl->mpOverlapData->mnSaveBackSize = nSaveBackSize; + mpWindowImpl->mpFrameData->mnAllSaveBackSize += nSaveBackSize; + Point aDevPt; + mpWindowImpl->mpFrameWindow->ImplGetFrameDev( Point( mnOutOffX, mnOutOffY ), + aDevPt, aOutSize, + *(mpWindowImpl->mpOverlapData->mpSaveBackDev) ); + mpWindowImpl->mpOverlapData->mpNextBackWin = mpWindowImpl->mpFrameData->mpFirstBackWin; + mpWindowImpl->mpFrameData->mpFirstBackWin = this; + } + else + { + delete mpWindowImpl->mpOverlapData->mpSaveBackDev; + mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL; + } + } + } + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::ImplRestoreOverlapBackground( Region& rInvRegion ) +{ + if ( mpWindowImpl->mpOverlapData->mpSaveBackDev ) + { + if ( mpWindowImpl->mbInitWinClipRegion ) + ImplInitWinClipRegion(); + + if ( mpWindowImpl->mpOverlapData->mpSaveBackDev ) + { + Point aDevPt; + Point aDestPt( mnOutOffX, mnOutOffY ); + Size aDevSize = mpWindowImpl->mpOverlapData->mpSaveBackDev->GetOutputSizePixel(); + if ( mpWindowImpl->mpOverlapData->mpSaveBackRgn ) + { + mpWindowImpl->mpOverlapData->mpSaveBackRgn->Intersect( mpWindowImpl->maWinClipRegion ); + rInvRegion = mpWindowImpl->maWinClipRegion; + rInvRegion.Exclude( *mpWindowImpl->mpOverlapData->mpSaveBackRgn ); + mpWindowImpl->mpFrameWindow->ImplDrawFrameDev( aDestPt, aDevPt, aDevSize, + *(mpWindowImpl->mpOverlapData->mpSaveBackDev), + *mpWindowImpl->mpOverlapData->mpSaveBackRgn ); + } + else + { + mpWindowImpl->mpFrameWindow->ImplDrawFrameDev( aDestPt, aDevPt, aDevSize, + *(mpWindowImpl->mpOverlapData->mpSaveBackDev), + mpWindowImpl->maWinClipRegion ); + } + ImplDeleteOverlapBackground(); + } + + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::ImplDeleteOverlapBackground() +{ + if ( mpWindowImpl->mpOverlapData->mpSaveBackDev ) + { + mpWindowImpl->mpFrameData->mnAllSaveBackSize -= mpWindowImpl->mpOverlapData->mnSaveBackSize; + delete mpWindowImpl->mpOverlapData->mpSaveBackDev; + mpWindowImpl->mpOverlapData->mpSaveBackDev = NULL; + if ( mpWindowImpl->mpOverlapData->mpSaveBackRgn ) + { + delete mpWindowImpl->mpOverlapData->mpSaveBackRgn; + mpWindowImpl->mpOverlapData->mpSaveBackRgn = NULL; + } + + // Fenster aus der Liste entfernen + if ( mpWindowImpl->mpFrameData->mpFirstBackWin == this ) + mpWindowImpl->mpFrameData->mpFirstBackWin = mpWindowImpl->mpOverlapData->mpNextBackWin; + else + { + Window* pTemp = mpWindowImpl->mpFrameData->mpFirstBackWin; + while ( pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin != this ) + pTemp = pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin; + pTemp->mpWindowImpl->mpOverlapData->mpNextBackWin = mpWindowImpl->mpOverlapData->mpNextBackWin; + } + mpWindowImpl->mpOverlapData->mpNextBackWin = NULL; + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplInvalidateAllOverlapBackgrounds() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Window* pWindow = mpWindowImpl->mpFrameData->mpFirstBackWin; + while ( pWindow ) + { + // Naechstes Fenster schon hier merken, da dieses Fenster in + // der if-Abfrage aus der Liste entfernt werden kann + Window* pNext = pWindow->mpWindowImpl->mpOverlapData->mpNextBackWin; + + if ( ImplIsWindowInFront( pWindow ) ) + { + Rectangle aRect1( Point( mnOutOffX, mnOutOffY ), + Size( mnOutWidth, mnOutHeight ) ); + Rectangle aRect2( Point( pWindow->mnOutOffX, pWindow->mnOutOffY ), + Size( pWindow->mnOutWidth, pWindow->mnOutHeight ) ); + aRect1.Intersection( aRect2 ); + if ( !aRect1.IsEmpty() ) + { + if ( !pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn ) + pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn = new Region( aRect2 ); + pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn->Exclude( aRect1 ); + if ( pWindow->mpWindowImpl->mpOverlapData->mpSaveBackRgn->IsEmpty() ) + pWindow->ImplDeleteOverlapBackground(); + } + + } + + pWindow = pNext; + } +} + +// ======================================================================= + +Bitmap Window::SnapShot( BOOL bBorder ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Bitmap aBmp; + + if ( IsReallyVisible() ) + { + if ( bBorder && mpWindowImpl->mpBorderWindow ) + aBmp = mpWindowImpl->mpBorderWindow->SnapShot(); + else + { + ((Window*)this)->Update(); + + if ( bBorder && mpWindowImpl->mbFrame ) + { + SalBitmap* pSalBmp = mpWindowImpl->mpFrame->SnapShot(); + + if ( pSalBmp ) + { + ImpBitmap* pImpBmp = new ImpBitmap; + pImpBmp->ImplSetSalBitmap( pSalBmp ); + aBmp.ImplSetImpBitmap( pImpBmp ); + return aBmp; + } + } + + mpWindowImpl->mpFrameWindow->ImplGetFrameBitmap( Point( mnOutOffX, mnOutOffY ), Size( mnOutWidth, mnOutHeight ), aBmp ); + } + } + + return aBmp; +} + +// ----------------------------------------------------------------------- + +Bitmap Window::SnapShot() const +{ + // Should be merged in the next top level build !!! + return SnapShot( TRUE ); +} + +// ----------------------------------------------------------------------- + +void Window::ShowFocus( const Rectangle& rRect ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mpWindowImpl->mbInShowFocus ) + return; + mpWindowImpl->mbInShowFocus = TRUE; + + ImplWinData* pWinData = ImplGetWinData(); + + // native themeing suggest not to use focus rects + if( ! ( mpWindowImpl->mbUseNativeFocus && + IsNativeWidgetEnabled() ) ) + { + if ( !mpWindowImpl->mbInPaint ) + { + if ( mpWindowImpl->mbFocusVisible ) + { + if ( *(pWinData->mpFocusRect) == rRect ) + { + mpWindowImpl->mbInShowFocus = FALSE; + return; + } + + ImplInvertFocus( *(pWinData->mpFocusRect) ); + } + + ImplInvertFocus( rRect ); + } + if ( !pWinData->mpFocusRect ) + pWinData->mpFocusRect = new Rectangle( rRect ); + else + *(pWinData->mpFocusRect) = rRect; + mpWindowImpl->mbFocusVisible = TRUE; + } + else + { + if( ! mpWindowImpl->mbNativeFocusVisible ) + { + mpWindowImpl->mbNativeFocusVisible = TRUE; + if ( !mpWindowImpl->mbInPaint ) + Invalidate(); + } + } + mpWindowImpl->mbInShowFocus = FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::HideFocus() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if( mpWindowImpl->mbInHideFocus ) + return; + mpWindowImpl->mbInHideFocus = TRUE; + + // native themeing can suggest not to use focus rects + if( ! ( mpWindowImpl->mbUseNativeFocus && + IsNativeWidgetEnabled() ) ) + { + if ( !mpWindowImpl->mbFocusVisible ) + { + mpWindowImpl->mbInHideFocus = FALSE; + return; + } + + if ( !mpWindowImpl->mbInPaint ) + ImplInvertFocus( *(ImplGetWinData()->mpFocusRect) ); + mpWindowImpl->mbFocusVisible = FALSE; + } + else + { + if( mpWindowImpl->mbNativeFocusVisible ) + { + mpWindowImpl->mbNativeFocusVisible = FALSE; + if ( !mpWindowImpl->mbInPaint ) + Invalidate(); + } + } + mpWindowImpl->mbInHideFocus = FALSE; +} + +// ----------------------------------------------------------------------- + +void Window::Invert( const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() ) + return; + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + + if ( aRect.IsEmpty() ) + return; + aRect.Justify(); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + SalInvert nSalFlags = 0; + if ( nFlags & INVERT_HIGHLIGHT ) + nSalFlags |= SAL_INVERT_HIGHLIGHT; + if ( nFlags & INVERT_50 ) + nSalFlags |= SAL_INVERT_50; + mpGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), nSalFlags, this ); +} + +// ----------------------------------------------------------------------- + +void Window::Invert( const Polygon& rPoly, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( !IsDeviceOutputNecessary() ) + return; + + USHORT nPoints = rPoly.GetSize(); + + if ( nPoints < 2 ) + return; + + Polygon aPoly( ImplLogicToDevicePixel( rPoly ) ); + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + SalInvert nSalFlags = 0; + if ( nFlags & INVERT_HIGHLIGHT ) + nSalFlags |= SAL_INVERT_HIGHLIGHT; + if ( nFlags & INVERT_50 ) + nSalFlags |= SAL_INVERT_50; + const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); + mpGraphics->Invert( nPoints, pPtAry, nSalFlags, this ); +} + +// ----------------------------------------------------------------------- + +void Window::ShowTracking( const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplWinData* pWinData = ImplGetWinData(); + + if ( !mpWindowImpl->mbInPaint || !(nFlags & SHOWTRACK_WINDOW) ) + { + if ( mpWindowImpl->mbTrackVisible ) + { + if ( (*(pWinData->mpTrackRect) == rRect) && + (pWinData->mnTrackFlags == nFlags) ) + return; + + InvertTracking( *(pWinData->mpTrackRect), pWinData->mnTrackFlags ); + } + + InvertTracking( rRect, nFlags ); + } + + if ( !pWinData->mpTrackRect ) + pWinData->mpTrackRect = new Rectangle( rRect ); + else + *(pWinData->mpTrackRect) = rRect; + pWinData->mnTrackFlags = nFlags; + mpWindowImpl->mbTrackVisible = TRUE; +} + +// ----------------------------------------------------------------------- + +void Window::HideTracking() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbTrackVisible ) + { + ImplWinData* pWinData = ImplGetWinData(); + if ( !mpWindowImpl->mbInPaint || !(pWinData->mnTrackFlags & SHOWTRACK_WINDOW) ) + InvertTracking( *(pWinData->mpTrackRect), pWinData->mnTrackFlags ); + mpWindowImpl->mbTrackVisible = FALSE; + } +} + +// ----------------------------------------------------------------------- + +void Window::InvertTracking( const Rectangle& rRect, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Rectangle aRect( ImplLogicToDevicePixel( rRect ) ); + + if ( aRect.IsEmpty() ) + return; + aRect.Justify(); + + SalGraphics* pGraphics; + + if ( nFlags & SHOWTRACK_WINDOW ) + { + if ( !IsDeviceOutputNecessary() ) + return; + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + pGraphics = mpGraphics; + } + else + { + pGraphics = ImplGetFrameGraphics(); + + if ( nFlags & SHOWTRACK_CLIP ) + { + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + ImplClipBoundaries( aRegion, FALSE, FALSE ); + ImplSelectClipRegion( aRegion, pGraphics ); + } + } + + USHORT nStyle = nFlags & SHOWTRACK_STYLE; + if ( nStyle == SHOWTRACK_OBJECT ) + pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), SAL_INVERT_TRACKFRAME, this ); + else if ( nStyle == SHOWTRACK_SPLIT ) + pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight(), SAL_INVERT_50, this ); + else + { + long nBorder = 1; + if ( nStyle == SHOWTRACK_BIG ) + nBorder = 5; + pGraphics->Invert( aRect.Left(), aRect.Top(), aRect.GetWidth(), nBorder, SAL_INVERT_50, this ); + pGraphics->Invert( aRect.Left(), aRect.Bottom()-nBorder+1, aRect.GetWidth(), nBorder, SAL_INVERT_50, this ); + pGraphics->Invert( aRect.Left(), aRect.Top()+nBorder, nBorder, aRect.GetHeight()-(nBorder*2), SAL_INVERT_50, this ); + pGraphics->Invert( aRect.Right()-nBorder+1, aRect.Top()+nBorder, nBorder, aRect.GetHeight()-(nBorder*2), SAL_INVERT_50, this ); + } +} + +// ----------------------------------------------------------------------- + +void Window::InvertTracking( const Polygon& rPoly, USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + USHORT nPoints = rPoly.GetSize(); + + if ( nPoints < 2 ) + return; + + Polygon aPoly( ImplLogicToDevicePixel( rPoly ) ); + + SalGraphics* pGraphics; + + if ( nFlags & SHOWTRACK_WINDOW ) + { + if ( !IsDeviceOutputNecessary() ) + return; + + // we need a graphics + if ( !mpGraphics ) + { + if ( !ImplGetGraphics() ) + return; + } + + if ( mbInitClipRegion ) + ImplInitClipRegion(); + + if ( mbOutputClipped ) + return; + + pGraphics = mpGraphics; + } + else + { + pGraphics = ImplGetFrameGraphics(); + + if ( nFlags & SHOWTRACK_CLIP ) + { + Point aPoint( mnOutOffX, mnOutOffY ); + Region aRegion( Rectangle( aPoint, + Size( mnOutWidth, mnOutHeight ) ) ); + ImplClipBoundaries( aRegion, FALSE, FALSE ); + ImplSelectClipRegion( aRegion, pGraphics ); + } + } + + const SalPoint* pPtAry = (const SalPoint*)aPoly.GetConstPointAry(); + pGraphics->Invert( nPoints, pPtAry, SAL_INVERT_TRACKFRAME, this ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplTrackTimerHdl, Timer*, pTimer ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + // Bei Button-Repeat muessen wir den Timeout umsetzen + if ( pSVData->maWinData.mnTrackFlags & STARTTRACK_BUTTONREPEAT ) + pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() ); + + // Tracking-Event erzeugen + Point aMousePos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY ); + if( ImplIsAntiparallel() ) + { + // - RTL - re-mirror frame pos at pChild + ImplReMirror( aMousePos ); + } + MouseEvent aMEvt( ImplFrameToOutput( aMousePos ), + mpWindowImpl->mpFrameData->mnClickCount, 0, + mpWindowImpl->mpFrameData->mnMouseCode, mpWindowImpl->mpFrameData->mnMouseCode ); + TrackingEvent aTEvt( aMEvt, TRACKING_REPEAT ); + Tracking( aTEvt ); + + return 0; +} + +// ----------------------------------------------------------------------- + +void Window::StartTracking( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpTrackWin != this ) + { + if ( pSVData->maWinData.mpTrackWin ) + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL ); + } + + if ( nFlags & (STARTTRACK_SCROLLREPEAT | STARTTRACK_BUTTONREPEAT) ) + { + pSVData->maWinData.mpTrackTimer = new AutoTimer; + + if ( nFlags & STARTTRACK_SCROLLREPEAT ) + pSVData->maWinData.mpTrackTimer->SetTimeout( GetSettings().GetMouseSettings().GetScrollRepeat() ); + else + pSVData->maWinData.mpTrackTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() ); + pSVData->maWinData.mpTrackTimer->SetTimeoutHdl( LINK( this, Window, ImplTrackTimerHdl ) ); + pSVData->maWinData.mpTrackTimer->Start(); + } + + pSVData->maWinData.mpTrackWin = this; + pSVData->maWinData.mnTrackFlags = nFlags; + CaptureMouse(); +} + +// ----------------------------------------------------------------------- + +void Window::EndTracking( USHORT nFlags ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpTrackWin == this ) + { + // Hier wegen DbgChkThis geklammert, da Window im Handler zerstoert + // werden kann + { + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( pSVData->maWinData.mpTrackTimer ) + { + delete pSVData->maWinData.mpTrackTimer; + pSVData->maWinData.mpTrackTimer = NULL; + } + + pSVData->maWinData.mpTrackWin = NULL; + pSVData->maWinData.mnTrackFlags = 0; + ReleaseMouse(); + } + + // EndTracking rufen, wenn es gerufen werden soll + if ( !(nFlags & ENDTRACK_DONTCALLHDL) ) + { + Point aMousePos( mpWindowImpl->mpFrameData->mnLastMouseX, mpWindowImpl->mpFrameData->mnLastMouseY ); + if( ImplIsAntiparallel() ) + { + // - RTL - re-mirror frame pos at pChild + ImplReMirror( aMousePos ); + } + + MouseEvent aMEvt( ImplFrameToOutput( aMousePos ), + mpWindowImpl->mpFrameData->mnClickCount, 0, + mpWindowImpl->mpFrameData->mnMouseCode, mpWindowImpl->mpFrameData->mnMouseCode ); + TrackingEvent aTEvt( aMEvt, nFlags | ENDTRACK_END ); + Tracking( aTEvt ); + } + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsTracking() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return (ImplGetSVData()->maWinData.mpTrackWin == this); +} + +// ----------------------------------------------------------------------- + +void Window::StartAutoScroll( USHORT nFlags ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpAutoScrollWin != this ) + { + if ( pSVData->maWinData.mpAutoScrollWin ) + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + } + + pSVData->maWinData.mpAutoScrollWin = this; + pSVData->maWinData.mnAutoScrollFlags = nFlags; + pSVData->maAppData.mpWheelWindow = new ImplWheelWindow( this ); +} + +// ----------------------------------------------------------------------- + +void Window::EndAutoScroll() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpAutoScrollWin == this ) + { + pSVData->maWinData.mpAutoScrollWin = NULL; + pSVData->maWinData.mnAutoScrollFlags = 0; + pSVData->maAppData.mpWheelWindow->ImplStop(); + pSVData->maAppData.mpWheelWindow->doLazyDelete(); + pSVData->maAppData.mpWheelWindow = NULL; + } +} + +// ----------------------------------------------------------------------- + +BOOL Window::IsAutoScroll() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + return (ImplGetSVData()->maWinData.mpAutoScrollWin == this); +} + +// ----------------------------------------------------------------------- + +void Window::SaveBackground( const Point& rPos, const Size& rSize, + const Point& rDestOff, VirtualDevice& rSaveDevice ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpPaintRegion ) + { + Region aClip( *mpWindowImpl->mpPaintRegion ); + const Point aPixPos( LogicToPixel( rPos ) ); + + aClip.Move( -mnOutOffX, -mnOutOffY ); + aClip.Intersect( Rectangle( aPixPos, LogicToPixel( rSize ) ) ); + + if ( !aClip.IsEmpty() ) + { + const Region aOldClip( rSaveDevice.GetClipRegion() ); + const Point aPixOffset( rSaveDevice.LogicToPixel( rDestOff ) ); + const BOOL bMap = rSaveDevice.IsMapModeEnabled(); + + // move clip region to have the same distance to DestOffset + aClip.Move( aPixOffset.X() - aPixPos.X(), aPixOffset.Y() - aPixPos.Y() ); + + // set pixel clip region + rSaveDevice.EnableMapMode( FALSE ); + rSaveDevice.SetClipRegion( aClip ); + rSaveDevice.EnableMapMode( bMap ); + rSaveDevice.DrawOutDev( rDestOff, rSize, rPos, rSize, *this ); + rSaveDevice.SetClipRegion( aOldClip ); + } + } + else + rSaveDevice.DrawOutDev( rDestOff, rSize, rPos, rSize, *this ); +} + +// ----------------------------------------------------------------------- + +sal_uIntPtr Window::SaveFocus() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maWinData.mpFocusWin ) + { + ImplFocusDelData* pDelData = new ImplFocusDelData; + pSVData->maWinData.mpFocusWin->ImplAddDel( pDelData ); + pDelData->mpFocusWin = pSVData->maWinData.mpFocusWin; + return (sal_uIntPtr)(void*)pDelData; + } + else + return 0; +} + +// ----------------------------------------------------------------------- + +BOOL Window::EndSaveFocus( sal_uIntPtr nSaveId, BOOL bRestore ) +{ + if ( !nSaveId ) + return FALSE; + else + { + BOOL bOK = TRUE; + ImplFocusDelData* pDelData = (ImplFocusDelData*)(void*)nSaveId; + if ( !pDelData->IsDelete() ) + { + pDelData->mpFocusWin->ImplRemoveDel( pDelData ); + if ( bRestore ) + pDelData->mpFocusWin->GrabFocus(); + } + else + bOK = !bRestore; + delete pDelData; + return bOK; + } +} + +// ----------------------------------------------------------------------- + +void Window::SetZoom( const Fraction& rZoom ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->maZoom != rZoom ) + { + mpWindowImpl->maZoom = rZoom; + StateChanged( STATE_CHANGE_ZOOM ); + } +} + +// ----------------------------------------------------------------------- + +inline long WinFloatRound( double fVal ) +{ + return( fVal > 0.0 ? (long) ( fVal + 0.5 ) : -(long) ( -fVal + 0.5 ) ); +} + +// ----------------------------------------------------------------------- + +void Window::SetZoomedPointFont( const Font& rFont ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + const Fraction& rZoom = GetZoom(); + if ( rZoom.GetNumerator() != rZoom.GetDenominator() ) + { + Font aFont( rFont ); + Size aSize = aFont.GetSize(); + double n = (double)aSize.Width(); + n *= (double)rZoom.GetNumerator(); + n /= (double)rZoom.GetDenominator(); + aSize.Width() = WinFloatRound( n ); + n = (double)aSize.Height(); + n *= (double)rZoom.GetNumerator(); + n /= (double)rZoom.GetDenominator(); + aSize.Height() = WinFloatRound( n ); + aFont.SetSize( aSize ); + SetPointFont( aFont ); + + // Wenn Darstellung skaliert wird, nehmen wir gegebenenfalls + // einen anderen Font, wenn der aktuelle nicht skalierbar ist + FontMetric aMetric = GetFontMetric(); + long nFontDiff = Abs( GetFont().GetSize().Height()-aMetric.GetSize().Height() ); + if ( (aMetric.GetType() == TYPE_RASTER) && (nFontDiff >= 2) ) + { + USHORT nType; + if ( aMetric.GetPitch() == PITCH_FIXED ) + nType = DEFAULTFONT_FIXED; + else + nType = DEFAULTFONT_UI_SANS; + Font aTempFont = GetDefaultFont( nType, GetSettings().GetLanguage(), 0 ); + aFont.SetName( aTempFont.GetName() ); + SetPointFont( aFont ); + } + } + else + SetPointFont( rFont ); +} + +// ----------------------------------------------------------------------- + +long Window::CalcZoom( long nCalc ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + const Fraction& rZoom = GetZoom(); + if ( rZoom.GetNumerator() != rZoom.GetDenominator() ) + { + double n = (double)nCalc; + n *= (double)rZoom.GetNumerator(); + n /= (double)rZoom.GetDenominator(); + nCalc = WinFloatRound( n ); + } + return nCalc; +} + +// ----------------------------------------------------------------------- + +void Window::SetControlFont() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpControlFont ) + { + delete mpWindowImpl->mpControlFont; + mpWindowImpl->mpControlFont = NULL; + StateChanged( STATE_CHANGE_CONTROLFONT ); + } +} + +// ----------------------------------------------------------------------- + +void Window::SetControlFont( const Font& rFont ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( rFont == Font() ) + { + SetControlFont(); + return; + } + + if ( mpWindowImpl->mpControlFont ) + { + if ( *mpWindowImpl->mpControlFont == rFont ) + return; + *mpWindowImpl->mpControlFont = rFont; + } + else + mpWindowImpl->mpControlFont = new Font( rFont ); + + StateChanged( STATE_CHANGE_CONTROLFONT ); +} + +// ----------------------------------------------------------------------- + +Font Window::GetControlFont() const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mpControlFont ) + return *mpWindowImpl->mpControlFont; + else + { + Font aFont; + return aFont; + } +} + +// ----------------------------------------------------------------------- + +void Window::SetControlForeground() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbControlForeground ) + { + mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT ); + mpWindowImpl->mbControlForeground = FALSE; + StateChanged( STATE_CHANGE_CONTROLFOREGROUND ); + } +} + +// ----------------------------------------------------------------------- + +void Window::SetControlForeground( const Color& rColor ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( rColor.GetTransparency() ) + { + if ( mpWindowImpl->mbControlForeground ) + { + mpWindowImpl->maControlForeground = Color( COL_TRANSPARENT ); + mpWindowImpl->mbControlForeground = FALSE; + StateChanged( STATE_CHANGE_CONTROLFOREGROUND ); + } + } + else + { + if ( mpWindowImpl->maControlForeground != rColor ) + { + mpWindowImpl->maControlForeground = rColor; + mpWindowImpl->mbControlForeground = TRUE; + StateChanged( STATE_CHANGE_CONTROLFOREGROUND ); + } + } +} + +// ----------------------------------------------------------------------- + +void Window::SetControlBackground() +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( mpWindowImpl->mbControlBackground ) + { + mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT ); + mpWindowImpl->mbControlBackground = FALSE; + StateChanged( STATE_CHANGE_CONTROLBACKGROUND ); + } +} + +// ----------------------------------------------------------------------- + +void Window::SetControlBackground( const Color& rColor ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + if ( rColor.GetTransparency() ) + { + if ( mpWindowImpl->mbControlBackground ) + { + mpWindowImpl->maControlBackground = Color( COL_TRANSPARENT ); + mpWindowImpl->mbControlBackground = FALSE; + StateChanged( STATE_CHANGE_CONTROLBACKGROUND ); + } + } + else + { + if ( mpWindowImpl->maControlBackground != rColor ) + { + mpWindowImpl->maControlBackground = rColor; + mpWindowImpl->mbControlBackground = TRUE; + StateChanged( STATE_CHANGE_CONTROLBACKGROUND ); + } + } +} + +// ----------------------------------------------------------------------- + +Size Window::CalcWindowSize( const Size& rOutSz ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Size aSz = rOutSz; + aSz.Width() += mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder; + aSz.Height() += mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder; + return aSz; +} + +// ----------------------------------------------------------------------- + +Size Window::CalcOutputSize( const Size& rWinSz ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Size aSz = rWinSz; + aSz.Width() -= mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder; + aSz.Height() -= mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder; + return aSz; +} + +// ----------------------------------------------------------------------- + +Font Window::GetDrawPixelFont( OutputDevice* pDev ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + Font aFont = GetPointFont(); + Size aFontSize = aFont.GetSize(); + MapMode aPtMapMode( MAP_POINT ); + aFontSize = pDev->LogicToPixel( aFontSize, aPtMapMode ); + aFont.SetSize( aFontSize ); + return aFont; +} + +// ----------------------------------------------------------------------- + +long Window::GetDrawPixel( OutputDevice* pDev, long nPixels ) const +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + long nP = nPixels; + if ( pDev->GetOutDevType() != OUTDEV_WINDOW ) + { + MapMode aMap( MAP_100TH_MM ); + Size aSz( nP, 0 ); + aSz = PixelToLogic( aSz, aMap ); + aSz = pDev->LogicToPixel( aSz, aMap ); + nP = aSz.Width(); + } + return nP; +} + +// ----------------------------------------------------------------------- + +BOOL Window::HandleScrollCommand( const CommandEvent& rCmd, + ScrollBar* pHScrl, ScrollBar* pVScrl ) +{ + DBG_CHKTHIS( Window, ImplDbgCheckWindow ); + + BOOL bRet = FALSE; + + if ( pHScrl || pVScrl ) + { + switch( rCmd.GetCommand() ) + { + case COMMAND_STARTAUTOSCROLL: + { + USHORT nFlags = 0; + if ( pHScrl ) + { + if ( (pHScrl->GetVisibleSize() < pHScrl->GetRangeMax()) && + pHScrl->IsEnabled() && pHScrl->IsInputEnabled() && ! pHScrl->IsInModalMode() ) + nFlags |= AUTOSCROLL_HORZ; + } + if ( pVScrl ) + { + if ( (pVScrl->GetVisibleSize() < pVScrl->GetRangeMax()) && + pVScrl->IsEnabled() && pVScrl->IsInputEnabled() && ! pVScrl->IsInModalMode() ) + nFlags |= AUTOSCROLL_VERT; + } + + if ( nFlags ) + { + StartAutoScroll( nFlags ); + bRet = TRUE; + } + } + break; + + case COMMAND_WHEEL: + { + const CommandWheelData* pData = rCmd.GetWheelData(); + + if ( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) ) + { + ULONG nScrollLines = pData->GetScrollLines(); + long nLines; + if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL ) + { + if ( pData->GetDelta() < 0 ) + nLines = -LONG_MAX; + else + nLines = LONG_MAX; + } + else + nLines = pData->GetNotchDelta() * (long)nScrollLines; + if ( nLines ) + { + ImplHandleScroll( NULL, + 0L, + pData->IsHorz() ? pHScrl : pVScrl, + nLines ); + bRet = TRUE; + } + } + } + break; + + case COMMAND_AUTOSCROLL: + { + const CommandScrollData* pData = rCmd.GetAutoScrollData(); + if ( pData && (pData->GetDeltaX() || pData->GetDeltaY()) ) + { + ImplHandleScroll( pHScrl, pData->GetDeltaX(), + pVScrl, pData->GetDeltaY() ); + bRet = TRUE; + } + } + break; + + default: + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void Window::ImplHandleScroll( ScrollBar* pHScrl, long nX, + ScrollBar* pVScrl, long nY ) +{ + if ( pHScrl && nX && pHScrl->IsEnabled() && pHScrl->IsInputEnabled() && ! pHScrl->IsInModalMode() ) + { + long nNewPos = pHScrl->GetThumbPos(); + + if ( nX == -LONG_MAX ) + nNewPos += pHScrl->GetPageSize(); + else if ( nX == LONG_MAX ) + nNewPos -= pHScrl->GetPageSize(); + else + { + const double fVal = (double)nNewPos - ((double)nX * pHScrl->GetLineSize()); + + if ( fVal < LONG_MIN ) + nNewPos = LONG_MIN; + else if ( fVal > LONG_MAX ) + nNewPos = LONG_MAX; + else + nNewPos = (long)fVal; + } + + pHScrl->DoScroll( nNewPos ); + } + + if ( pVScrl && nY && pVScrl->IsEnabled() && pVScrl->IsInputEnabled() && ! pVScrl->IsInModalMode() ) + { + long nNewPos = pVScrl->GetThumbPos(); + + if ( nY == -LONG_MAX ) + nNewPos += pVScrl->GetPageSize(); + else if ( nY == LONG_MAX ) + nNewPos -= pVScrl->GetPageSize(); + else + { + const double fVal = (double)nNewPos - ((double)nY * pVScrl->GetLineSize()); + + if ( fVal < LONG_MIN ) + nNewPos = LONG_MIN; + else if ( fVal > LONG_MAX ) + nNewPos = LONG_MAX; + else + nNewPos = (long)fVal; + } + + pVScrl->DoScroll( nNewPos ); + } +} + +// support for docking +// this is currently handled in ImplDockingWindowWrapper +/* +void Window::ImplSetFloatingMode( BOOL bFloatMode ) +{ + // if the window is docked, put it into a flaoting window + // if it is floating put it back in the old frame + + ImplDockingWindowWrapper *pWrapper = pDockingMgr->GetDockingWindowWrapper( this ); + if( !pDockingData ) + return; + + if ( pWrapper->IsFloatingMode() != bFloatMode ) + { + if ( pWrapper->PrepareToggleFloatingMode() ) + { + BOOL bVisible = IsVisible(); + + if ( bFloatMode ) + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + pWrapper->maDockPos = GetPosPixel(); + + Window* pRealParent = mpWindowImpl->mpRealParent; + pWrapper->mpOldBorderWin = mpWindowImpl->mpBorderWindow; + + ImplDockFloatWin* pWin = + new ImplDockFloatWin2( + mpWindowImpl->mpParent, + mnFloatBits & ( WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE ) ? mnFloatBits | WB_SYSTEMWINDOW : mnFloatBits, + pWrapper ); + pWrapper->mpFloatWin = pWin; + mpWindowImpl->mpBorderWindow = NULL; + mpWindowImpl->mnLeftBorder = 0; + mpWindowImpl->mnTopBorder = 0; + mpWindowImpl->mnRightBorder = 0; + mpWindowImpl->mnBottomBorder = 0; + // Falls Parent zerstoert wird, muessen wir auch vom + // BorderWindow den Parent umsetzen + if ( pWrapper->mpOldBorderWin ) + pWrapper->mpOldBorderWin->SetParent( pWin ); + SetParent( pWin ); + pWin->SetPosPixel( Point() ); + mpWindowImpl->mpBorderWindow = pWin; + pWin->mpWindowImpl->mpClientWindow = this; + mpWindowImpl->mpRealParent = pRealParent; + pWin->SetText( GetText() ); + pWin->SetOutputSizePixel( GetSizePixel() ); + pWin->SetPosPixel( pWrapper->maFloatPos ); + // DockingDaten ans FloatingWindow weiterreichen + pWin->ShowTitleButton( TITLE_BUTTON_DOCKING, pWrapper->mbDockBtn ); + pWin->ShowTitleButton( TITLE_BUTTON_HIDE, pWrapper->mbHideBtn ); + pWin->SetPin( pWrapper->mbPined ); + if ( pWrapper->mbRollUp ) + pWin->RollUp(); + else + pWin->RollDown(); + pWin->SetRollUpOutputSizePixel( pWrapper->maRollUpOutSize ); + pWin->SetMinOutputSizePixel( pWrapper->maMinOutSize ); + + pWrapper->ToggleFloatingMode(); + + if ( bVisible ) + Show(); + } + else + { + Show( FALSE, SHOW_NOFOCUSCHANGE ); + + // FloatingDaten wird im FloatingWindow speichern + pWrapper->maFloatPos = mpFloatWin->GetPosPixel(); + pWrapper->mbDockBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_DOCKING ); + pWrapper->mbHideBtn = mpFloatWin->IsTitleButtonVisible( TITLE_BUTTON_HIDE ); + pWrapper->mbPined = mpFloatWin->IsPined(); + pWrapper->mbRollUp = mpFloatWin->IsRollUp(); + pWrapper->maRollUpOutSize = mpFloatWin->GetRollUpOutputSizePixel(); + pWrapper->maMinOutSize = mpFloatWin->GetMinOutputSizePixel(); + + Window* pRealParent = mpWindowImpl->mpRealParent; + mpWindowImpl->mpBorderWindow = NULL; + if ( pWrapper->mpOldBorderWin ) + { + SetParent( pWrapper->mpOldBorderWin ); + ((ImplBorderWindow*)pWrapper->mpOldBorderWin)->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + pWrapper->mpOldBorderWin->Resize(); + } + mpWindowImpl->mpBorderWindow = pWrapper->mpOldBorderWin; + SetParent( pRealParent ); + mpWindowImpl->mpRealParent = pRealParent; + delete static_cast<ImplDockFloatWin*>(mpFloatWin); + pWrapper->mpFloatWin = NULL; + SetPosPixel( maDockPos ); + + pWrapper->ToggleFloatingMode(); + + if ( bVisible ) + Show(); + } + } + } +} +*/ + +DockingManager* Window::GetDockingManager() +{ + return ImplGetDockingManager(); +} + +void Window::EnableDocking( BOOL bEnable ) +{ + // update list of dockable windows + if( bEnable ) + ImplGetDockingManager()->AddWindow( this ); + else + ImplGetDockingManager()->RemoveWindow( this ); +} + + +// retrieves the list of owner draw decorated windows for this window hiearchy +::std::vector<Window *>& Window::ImplGetOwnerDrawList() +{ + return ImplGetTopmostFrameWindow()->mpWindowImpl->mpFrameData->maOwnerDrawList; +} + +Window* Window::ImplGetTopmostFrameWindow() +{ + Window *pTopmostParent = this; + while( pTopmostParent->ImplGetParent() ) + pTopmostParent = pTopmostParent->ImplGetParent(); + return pTopmostParent->mpWindowImpl->mpFrameWindow; +} + +void Window::SetHelpId( const rtl::OString& rHelpId ) +{ + mpWindowImpl->maHelpId = rHelpId; +} + +const rtl::OString& Window::GetHelpId() const +{ + return mpWindowImpl->maHelpId; +} + +void Window::SetUniqueId( const rtl::OString& rUniqueId ) +{ + mpWindowImpl->maUniqId = rUniqueId; +} + +const rtl::OString& Window::GetUniqueId() const +{ + return mpWindowImpl->maUniqId; +} + +const rtl::OString& Window::GetUniqueOrHelpId() const +{ + return mpWindowImpl->maUniqId.getLength() ? mpWindowImpl->maUniqId : mpWindowImpl->maHelpId; +} + +// --------- old inline methods --------------- + +Window* Window::ImplGetWindow() +{ + if ( mpWindowImpl->mpClientWindow ) + return mpWindowImpl->mpClientWindow; + else + return this; +} + +ImplFrameData* Window::ImplGetFrameData() +{ + return mpWindowImpl->mpFrameData; +} + +SalFrame* Window::ImplGetFrame() const +{ + return mpWindowImpl->mpFrame; +} + +Window* Window::ImplGetParent() const +{ + return mpWindowImpl->mpParent; +} + +Window* Window::ImplGetClientWindow() const +{ + return mpWindowImpl->mpClientWindow; +} + +Window* Window::ImplGetBorderWindow() const +{ + return mpWindowImpl->mpBorderWindow; +} + +Window* Window::ImplGetFirstOverlapWindow() +{ + if ( mpWindowImpl->mbOverlapWin ) + return this; + else + return mpWindowImpl->mpOverlapWindow; +} + +const Window* Window::ImplGetFirstOverlapWindow() const +{ + if ( mpWindowImpl->mbOverlapWin ) + return this; + else + return mpWindowImpl->mpOverlapWindow; +} + +Window* Window::ImplGetFrameWindow() const +{ + return mpWindowImpl->mpFrameWindow; +} + +BOOL Window::ImplIsDockingWindow() const +{ + return mpWindowImpl->mbDockWin; +} + +BOOL Window::ImplIsFloatingWindow() const +{ + return mpWindowImpl->mbFloatWin; +} + +BOOL Window::ImplIsToolbox() const +{ + return mpWindowImpl->mbToolBox; +} + +BOOL Window::ImplIsSplitter() const +{ + return mpWindowImpl->mbSplitter; +} + +BOOL Window::ImplIsPushButton() const +{ + return mpWindowImpl->mbPushButton; +} + +BOOL Window::ImplIsOverlapWindow() const +{ + return mpWindowImpl->mbOverlapWin; +} + +void Window::ImplSetActive( BOOL bActive ) +{ + mpWindowImpl->mbActive = bActive; +} + +BOOL Window::ImplIsMouseTransparent() const +{ + return mpWindowImpl->mbMouseTransparent; +} + +void Window::ImplSetMouseTransparent( BOOL bTransparent ) +{ + mpWindowImpl->mbMouseTransparent = bTransparent; +} + +Point Window::ImplOutputToFrame( const Point& rPos ) +{ + return Point( rPos.X()+mnOutOffX, rPos.Y()+mnOutOffY ); +} + +Point Window::ImplFrameToOutput( const Point& rPos ) +{ + return Point( rPos.X()-mnOutOffX, rPos.Y()-mnOutOffY ); +} + +void Window::ImplOutputToFrame( Rectangle& rRect ) +{ + rRect.Left()+=mnOutOffX; + rRect.Top()+=mnOutOffY; + rRect.Right()+=mnOutOffX; + rRect.Bottom()+=mnOutOffY; +} + +void Window::ImplFrameToOutput( Rectangle& rRect ) +{ + rRect.Left()-=mnOutOffX; + rRect.Top()-=mnOutOffY; + rRect.Right()-=mnOutOffX; + rRect.Bottom()-=mnOutOffY; +} + +void Window::SetCompoundControl( BOOL bCompound ) +{ + mpWindowImpl->mbCompoundControl = bCompound; +} + +void Window::IncrementLockCount() +{ + mpWindowImpl->mnLockCount++; +} + +void Window::DecrementLockCount() +{ + mpWindowImpl->mnLockCount--; +} + +WinBits Window::GetStyle() const +{ + return mpWindowImpl->mnStyle; +} + +WinBits Window::GetPrevStyle() const +{ + return mpWindowImpl->mnPrevStyle; +} + +WinBits Window::GetExtendedStyle() const +{ + return mpWindowImpl->mnExtendedStyle; +} + +WinBits Window::GetPrevExtendedStyle() const +{ + return mpWindowImpl->mnExtendedStyle; +} + +void Window::SetType( WindowType nType ) +{ + mpWindowImpl->mnType = nType; +} + +WindowType Window::GetType() const +{ + return mpWindowImpl->mnType; +} +BOOL Window::IsSystemWindow() const +{ + return mpWindowImpl->mbSysWin; +} + +BOOL Window::IsDialog() const +{ + return mpWindowImpl->mbDialog; +} + +BOOL Window::IsMenuFloatingWindow() const +{ + return mpWindowImpl->mbMenuFloatingWindow; +} + +BOOL Window::IsToolbarFloatingWindow() const +{ + return mpWindowImpl->mbToolbarFloatingWindow; +} + +void Window::EnableAllResize( BOOL bEnable ) +{ + mpWindowImpl->mbAllResize = bEnable; +} + +BOOL Window::IsAllResizeEnabled() const +{ + return mpWindowImpl->mbAllResize; +} + +BOOL Window::IsClipSiblingsEnabled() const +{ + return mpWindowImpl->mbClipSiblings; +} + +void Window::EnableChildTransparentMode( BOOL bEnable ) +{ + mpWindowImpl->mbChildTransparent = bEnable; +} + +BOOL Window::IsChildTransparentModeEnabled() const +{ + return mpWindowImpl->mbChildTransparent; +} + +BOOL Window::IsMouseTransparent() const +{ + return mpWindowImpl->mbMouseTransparent; +} + +BOOL Window::IsPaintTransparent() const +{ + return mpWindowImpl->mbPaintTransparent; +} + +void Window::SetDialogControlStart( BOOL bStart ) +{ + mpWindowImpl->mbDlgCtrlStart = bStart; +} + +BOOL Window::IsDialogControlStart() const +{ + return mpWindowImpl->mbDlgCtrlStart; +} + +void Window::SetDialogControlFlags( USHORT nFlags ) +{ + mpWindowImpl->mnDlgCtrlFlags = nFlags; +} + +USHORT Window::GetDialogControlFlags() const +{ + return mpWindowImpl->mnDlgCtrlFlags; +} + +const InputContext& Window::GetInputContext() const +{ + return mpWindowImpl->maInputContext; +} + +BOOL Window::IsExtTextInput() const +{ + return mpWindowImpl->mbExtTextInput; +} + +void Window::EnableChildNotify( BOOL bEnable ) +{ + mpWindowImpl->mbChildNotify = bEnable; +} + +BOOL Window::IsChildNotify() const +{ + return mpWindowImpl->mbChildNotify; +} + +BOOL Window::IsControlFont() const +{ + return (mpWindowImpl->mpControlFont != 0); +} + +Color Window::GetControlForeground() const +{ + return mpWindowImpl->maControlForeground; +} + +BOOL Window::IsControlForeground() const +{ + return mpWindowImpl->mbControlForeground; +} + +Color Window::GetControlBackground() const +{ + return mpWindowImpl->maControlBackground; +} + +BOOL Window::IsControlBackground() const +{ + return mpWindowImpl->mbControlBackground; +} + +BOOL Window::IsInPaint() const +{ + return mpWindowImpl->mbInPaint; +} + +Window* Window::GetParent() const +{ + return mpWindowImpl->mpRealParent; +} + +BOOL Window::IsVisible() const +{ + return mpWindowImpl->mbVisible; +} + +BOOL Window::IsReallyVisible() const +{ + return mpWindowImpl->mbReallyVisible; +} + +BOOL Window::IsParentPathVisible() const +{ + return mpWindowImpl->mbReallyVisible; +} + +BOOL Window::IsReallyShown() const +{ + return mpWindowImpl->mbReallyShown; +} + +BOOL Window::IsInInitShow() const +{ + return mpWindowImpl->mbInInitShow; +} + +BOOL Window::IsEnabled() const +{ + return !mpWindowImpl->mbDisabled; +} + +BOOL Window::IsInputEnabled() const +{ + return !mpWindowImpl->mbInputDisabled; +} + +BOOL Window::IsAlwaysEnableInput() const +{ + return mpWindowImpl->meAlwaysInputMode == AlwaysInputEnabled; +} + +BOOL Window::IsAlwaysDisableInput() const +{ + return mpWindowImpl->meAlwaysInputMode == AlwaysInputDisabled; +} + +USHORT Window::GetActivateMode() const +{ + return mpWindowImpl->mnActivateMode; + +} + +BOOL Window::IsAlwaysOnTopEnabled() const +{ + return mpWindowImpl->mbAlwaysOnTop; +} + +BOOL Window::IsDefaultPos() const +{ + return mpWindowImpl->mbDefPos; +} + +BOOL Window::IsDefaultSize() const +{ + return mpWindowImpl->mbDefSize; +} + +void Window::EnablePaint( BOOL bEnable ) +{ + mpWindowImpl->mbPaintDisabled = !bEnable; +} + +BOOL Window::IsPaintEnabled() const +{ + return !mpWindowImpl->mbPaintDisabled; +} + +BOOL Window::IsUpdateMode() const +{ + return !mpWindowImpl->mbNoUpdate; +} + +void Window::SetParentUpdateMode( BOOL bUpdate ) +{ + mpWindowImpl->mbNoParentUpdate = !bUpdate; +} + +BOOL Window::IsParentUpdateMode() const +{ + return !mpWindowImpl->mbNoParentUpdate; +} + +BOOL Window::IsActive() const +{ + return mpWindowImpl->mbActive; +} + +USHORT Window::GetGetFocusFlags() const +{ + return mpWindowImpl->mnGetFocusFlags; +} + +BOOL Window::IsCompoundControl() const +{ + return mpWindowImpl->mbCompoundControl; +} + +BOOL Window::HasCompoundControlFocus() const +{ + return mpWindowImpl->mbCompoundControlHasFocus; +} + +BOOL Window::IsChildPointerOverwrite() const +{ + return mpWindowImpl->mbChildPtrOverwrite; +} + +BOOL Window::IsPointerVisible() const +{ + return !mpWindowImpl->mbNoPtrVisible; +} + +BOOL Window::IsWait() const +{ + return (mpWindowImpl->mnWaitCount != 0); +} + +Cursor* Window::GetCursor() const +{ + return mpWindowImpl->mpCursor; +} + +const Fraction& Window::GetZoom() const +{ + return mpWindowImpl->maZoom; +} + +BOOL Window::IsZoom() const +{ + return mpWindowImpl->maZoom.GetNumerator() != mpWindowImpl->maZoom.GetDenominator(); +} + +void Window::SetHelpText( const XubString& rHelpText ) +{ + mpWindowImpl->maHelpText = rHelpText; + mpWindowImpl->mbHelpTextDynamic = TRUE; +} + +void Window::SetQuickHelpText( const XubString& rHelpText ) +{ + mpWindowImpl->maQuickHelpText = rHelpText; +} + +const XubString& Window::GetQuickHelpText() const +{ + return mpWindowImpl->maQuickHelpText; +} + +void Window::SetData( void* pNewData ) +{ + mpWindowImpl->mpUserData = pNewData; +} + +void* Window::GetData() const +{ + return mpWindowImpl->mpUserData; +} + +BOOL Window::IsCreatedWithToolkit() const +{ + return mpWindowImpl->mbCreatedWithToolkit; +} + +void Window::SetCreatedWithToolkit( BOOL b ) +{ + mpWindowImpl->mbCreatedWithToolkit = b; + +} +const Pointer& Window::GetPointer() const +{ + return mpWindowImpl->maPointer; +} + +VCLXWindow* Window::GetWindowPeer() const +{ + return mpWindowImpl->mpVCLXWindow; +} + +void Window::SetPosPixel( const Point& rNewPos ) +{ + SetPosSizePixel( rNewPos.X(), rNewPos.Y(), 0, 0, WINDOW_POSSIZE_POS ); +} + +void Window::SetSizePixel( const Size& rNewSize ) +{ + SetPosSizePixel( 0, 0, rNewSize.Width(), rNewSize.Height(), + WINDOW_POSSIZE_SIZE ); +} + +void Window::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) +{ + SetPosSizePixel( rNewPos.X(), rNewPos.Y(), + rNewSize.Width(), rNewSize.Height(), + WINDOW_POSSIZE_POSSIZE ); +} + +void Window::SetOutputSizePixel( const Size& rNewSize ) +{ + SetSizePixel( Size( rNewSize.Width()+mpWindowImpl->mnLeftBorder+mpWindowImpl->mnRightBorder, + rNewSize.Height()+mpWindowImpl->mnTopBorder+mpWindowImpl->mnBottomBorder ) ); +} + diff --git a/vcl/source/window/window3.cxx b/vcl/source/window/window3.cxx new file mode 100644 index 000000000000..65019ba2a4af --- /dev/null +++ b/vcl/source/window/window3.cxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "vcl/window.hxx" +#include "vcl/waitobj.hxx" +#include "vcl/button.hxx" + +// ----------------------------------------------------------------------- + +WaitObject::~WaitObject() +{ + if ( mpWindow ) + mpWindow->LeaveWait(); +} + +// ----------------------------------------------------------------------- + +Size Window::GetOptimalSize(WindowSizeType eType) const +{ + switch (eType) { + case WINDOWSIZE_MINIMUM: + return Size(); + case WINDOWSIZE_PREFERRED: + return GetOptimalSize( WINDOWSIZE_MINIMUM ); + case WINDOWSIZE_MAXIMUM: + default: + return Size( LONG_MAX, LONG_MAX ); + } +} + +// ----------------------------------------------------------------------- + +void Window::ImplAdjustNWFSizes() +{ + switch( GetType() ) + { + case WINDOW_CHECKBOX: + ((CheckBox*)this)->ImplSetMinimumNWFSize(); + break; + case WINDOW_RADIOBUTTON: + ((RadioButton*)this)->ImplSetMinimumNWFSize(); + break; + default: + { + // iterate over children + Window* pWin = GetWindow( WINDOW_FIRSTCHILD ); + while( pWin ) + { + pWin->ImplAdjustNWFSizes(); + pWin = pWin->GetWindow( WINDOW_NEXT ); + } + } + break; + } +} diff --git a/vcl/source/window/window4.cxx b/vcl/source/window/window4.cxx new file mode 100644 index 000000000000..577a573c2015 --- /dev/null +++ b/vcl/source/window/window4.cxx @@ -0,0 +1,224 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/window.hxx" +#include "vcl/window.h" +#include "vcl/svdata.hxx" +#include "vcl/arrange.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" + +#include <map> +#include <vector> + +using namespace com::sun::star; + +namespace vcl +{ + struct ExtWindowImpl + { + ExtWindowImpl() + : mbOwnedByParent( false ) + {} + ~ExtWindowImpl() + {} + + boost::shared_ptr< WindowArranger > mxLayout; + bool mbOwnedByParent; + rtl::OUString maIdentifier; + }; +} + +void Window::ImplDeleteOwnedChildren() +{ + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + Window* pDeleteCandidate = pChild; + pChild = pChild->mpWindowImpl->mpNext; + vcl::ExtWindowImpl* pDelImpl = pDeleteCandidate->ImplGetExtWindowImpl(); + if( pDelImpl && pDelImpl->mbOwnedByParent ) + delete pDeleteCandidate; + } +} + +void Window::ImplFreeExtWindowImpl() +{ + ImplDeleteOwnedChildren(); + if( mpWindowImpl ) + { + delete mpWindowImpl->mpExtImpl; + mpWindowImpl->mpExtImpl = NULL; + } +} + +vcl::ExtWindowImpl* Window::ImplGetExtWindowImpl() const +{ + vcl::ExtWindowImpl* pImpl = NULL; + if( mpWindowImpl ) + { + if( ! mpWindowImpl->mpExtImpl && ! mpWindowImpl->mbInDtor ) + mpWindowImpl->mpExtImpl = new vcl::ExtWindowImpl(); + pImpl = mpWindowImpl->mpExtImpl; + } + return pImpl; +} + +void Window::ImplExtResize() +{ + if( mpWindowImpl && mpWindowImpl->mpExtImpl ) + { + if( mpWindowImpl->mpExtImpl->mxLayout.get() ) + mpWindowImpl->mpExtImpl->mxLayout->setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); + } +} + +boost::shared_ptr< vcl::WindowArranger > Window::getLayout() +{ + boost::shared_ptr< vcl::WindowArranger > xRet; + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + { + if( ! pImpl->mxLayout.get() ) + { + pImpl->mxLayout.reset( new vcl::LabelColumn() ); + pImpl->mxLayout->setParentWindow( this ); + pImpl->mxLayout->setOuterBorder( -1 ); + } + xRet = pImpl->mxLayout; + } + + return xRet; +} + +void Window::addWindow( Window* i_pWin, bool i_bTakeOwnership ) +{ + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl && i_pWin ) + { + vcl::ExtWindowImpl* pChildImpl = i_pWin->ImplGetExtWindowImpl(); + if( pChildImpl ) + { + i_pWin->SetParent( this ); + pChildImpl->mbOwnedByParent = i_bTakeOwnership; + } + } +} + +Window* Window::removeWindow( Window* i_pWin, Window* i_pNewParent ) +{ + Window* pRet = NULL; + if( i_pWin ) + { + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + { + vcl::ExtWindowImpl* pChildImpl = i_pWin->ImplGetExtWindowImpl(); + if( pChildImpl ) + { + if( ! i_pNewParent ) + pChildImpl->mbOwnedByParent = false; + i_pWin->SetParent( i_pNewParent ); + pRet = i_pWin; + } + } + } + return pRet; +} + +Window* Window::findWindow( const rtl::OUString& i_rIdentifier ) const +{ + if( getIdentifier() == i_rIdentifier ) + return const_cast<Window*>(this); + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + Window* pResult = pChild->findWindow( i_rIdentifier ); + if( pResult ) + return pResult; + pChild = pChild->mpWindowImpl->mpNext; + } + + return NULL; +} + +const rtl::OUString& Window::getIdentifier() const +{ + static rtl::OUString aEmptyStr; + + return (mpWindowImpl && mpWindowImpl->mpExtImpl) ? mpWindowImpl->mpExtImpl->maIdentifier : aEmptyStr; +} + +void Window::setIdentifier( const rtl::OUString& i_rIdentifier ) +{ + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + pImpl->maIdentifier = i_rIdentifier; +} + +void Window::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pVals = i_rProps.getConstArray(); + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) + { + if( pVals[i].Name.equalsAscii( "Enabled" ) ) + { + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Enable( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Show( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Text" ) ) + { + rtl::OUString aText; + if( pVals[i].Value >>= aText ) + SetText( aText ); + } + } +} + +uno::Sequence< beans::PropertyValue > Window::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aProps( 3 ); + aProps[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); + aProps[0].Value = uno::makeAny( sal_Bool( IsEnabled() ) ); + aProps[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aProps[1].Value = uno::makeAny( sal_Bool( IsVisible() ) ); + aProps[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); + aProps[2].Value = uno::makeAny( rtl::OUString( GetText() ) ); + + return aProps; +} + diff --git a/vcl/source/window/winproc.cxx b/vcl/source/window/winproc.cxx new file mode 100644 index 000000000000..2fce7e52f24c --- /dev/null +++ b/vcl/source/window/winproc.cxx @@ -0,0 +1,2617 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salwtype.hxx> +#include <vcl/salframe.hxx> +#include <tools/debug.hxx> +#ifndef _INTN_HXX +//#include <tools/intn.hxx> +#endif +#include <vcl/i18nhelp.hxx> +#include <vcl/unohelp.hxx> +#include <unotools/localedatawrapper.hxx> +#include <vcl/svdata.hxx> +#include <vcl/dbggui.hxx> +#include <vcl/timer.hxx> +#include <vcl/event.hxx> +#include <vcl/sound.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/cursor.hxx> +#include <vcl/accmgr.hxx> +#include <vcl/print.h> +#include <vcl/window.h> +#include <vcl/wrkwin.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/help.hxx> +#include <vcl/helpwin.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/salgdi.hxx> +#include <vcl/menu.hxx> + +#include <vcl/dndlcon.hxx> +#include <com/sun/star/datatransfer/dnd/XDragSource.hpp> +#include <com/sun/star/awt/MouseEvent.hpp> + +#if OSL_DEBUG_LEVEL > 1 +char dbgbuffer[1024]; +#ifndef WNT +#include <stdio.h> +#define MyOutputDebugString(s) (fprintf(stderr, s )) +#else +extern void MyOutputDebugString( char *s); +#endif +#endif + + +// ======================================================================= + +#define IMPL_MIN_NEEDSYSWIN 49 + +// ======================================================================= + +long ImplCallPreNotify( NotifyEvent& rEvt ) +{ + long nRet = Application::CallEventHooks( rEvt ); + if ( !nRet ) + nRet = rEvt.GetWindow()->PreNotify( rEvt ); + return nRet; +} + +// ======================================================================= + +long ImplCallEvent( NotifyEvent& rEvt ) +{ + long nRet = ImplCallPreNotify( rEvt ); + if ( !nRet ) + { + Window* pWindow = rEvt.GetWindow(); + switch ( rEvt.GetType() ) + { + case EVENT_MOUSEBUTTONDOWN: + pWindow->MouseButtonDown( *rEvt.GetMouseEvent() ); + break; + case EVENT_MOUSEBUTTONUP: + pWindow->MouseButtonUp( *rEvt.GetMouseEvent() ); + break; + case EVENT_MOUSEMOVE: + pWindow->MouseMove( *rEvt.GetMouseEvent() ); + break; + case EVENT_KEYINPUT: + pWindow->KeyInput( *rEvt.GetKeyEvent() ); + break; + case EVENT_KEYUP: + pWindow->KeyUp( *rEvt.GetKeyEvent() ); + break; + case EVENT_GETFOCUS: + pWindow->GetFocus(); + break; + case EVENT_LOSEFOCUS: + pWindow->LoseFocus(); + break; + case EVENT_COMMAND: + pWindow->Command( *rEvt.GetCommandEvent() ); + break; + } + } + + return nRet; +} + +// ======================================================================= + +static BOOL ImplHandleMouseFloatMode( Window* pChild, const Point& rMousePos, + USHORT nCode, USHORT nSVEvent, + BOOL bMouseLeave ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpFirstFloat && !pSVData->maWinData.mpCaptureWin && + !pSVData->maWinData.mpFirstFloat->ImplIsFloatPopupModeWindow( pChild ) ) + { + /* + * #93895# since floats are system windows, coordinates have + * to be converted to float relative for the hittest + */ + USHORT nHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE; + FloatingWindow* pFloat = pSVData->maWinData.mpFirstFloat->ImplFloatHitTest( pChild, rMousePos, nHitTest ); + FloatingWindow* pLastLevelFloat; + ULONG nPopupFlags; + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + if ( bMouseLeave ) + return TRUE; + + if ( !pFloat || (nHitTest & IMPL_FLOATWIN_HITTEST_RECT) ) + { + if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp ) + ImplDestroyHelpWindow( true ); + pChild->ImplGetFrame()->SetPointer( POINTER_ARROW ); + return TRUE; + } + } + else + { + if ( nCode & MOUSE_LEFT ) + { + if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + if ( !pFloat ) + { + pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + nPopupFlags = pLastLevelFloat->GetPopupModeFlags(); + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); +// Erstmal ausgebaut als Hack fuer Bug 53378 +// if ( nPopupFlags & FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK ) +// return FALSE; +// else + return TRUE; + } + else if ( nHitTest & IMPL_FLOATWIN_HITTEST_RECT ) + { + if ( !(pFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOMOUSERECTCLOSE) ) + pFloat->ImplSetMouseDown(); + return TRUE; + } + } + else + { + if ( pFloat ) + { + if ( nHitTest & IMPL_FLOATWIN_HITTEST_RECT ) + { + if ( pFloat->ImplIsMouseDown() ) + pFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL ); + return TRUE; + } + } + else + { + pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + nPopupFlags = pLastLevelFloat->GetPopupModeFlags(); + if ( !(nPopupFlags & FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE) ) + { + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + return TRUE; + } + } + } + } + else + { + if ( !pFloat ) + { + pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + nPopupFlags = pLastLevelFloat->GetPopupModeFlags(); + if ( nPopupFlags & FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE ) + { + if ( (nPopupFlags & FLOATWIN_POPUPMODE_NOMOUSEUPCLOSE) && + (nSVEvent == EVENT_MOUSEBUTTONUP) ) + return TRUE; + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + if ( nPopupFlags & FLOATWIN_POPUPMODE_PATHMOUSECANCELCLICK ) + return FALSE; + else + return TRUE; + } + else + return TRUE; + } + } + } + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleMouseHelpRequest( Window* pChild, const Point& rMousePos ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maHelpData.mpHelpWin || + !( pSVData->maHelpData.mpHelpWin->IsWindowOrChild( pChild ) || + pChild->IsWindowOrChild( pSVData->maHelpData.mpHelpWin ) ) ) + { + USHORT nHelpMode = 0; + if ( pSVData->maHelpData.mbQuickHelp ) + nHelpMode = HELPMODE_QUICK; + if ( pSVData->maHelpData.mbBalloonHelp ) + nHelpMode |= HELPMODE_BALLOON; + if ( nHelpMode ) + { + if ( pChild->IsInputEnabled() && ! pChild->IsInModalMode() ) + { + HelpEvent aHelpEvent( rMousePos, nHelpMode ); + pSVData->maHelpData.mbRequestingHelp = TRUE; + pChild->RequestHelp( aHelpEvent ); + pSVData->maHelpData.mbRequestingHelp = FALSE; + } + // #104172# do not kill keyboard activated tooltips + else if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp) + { + ImplDestroyHelpWindow( true ); + } + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplSetMousePointer( Window* pChild ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maHelpData.mbExtHelpMode ) + pChild->ImplGetFrame()->SetPointer( POINTER_HELP ); + else + pChild->ImplGetFrame()->SetPointer( pChild->ImplGetMousePointer() ); +} + +// ----------------------------------------------------------------------- + +static BOOL ImplCallCommand( Window* pChild, USHORT nEvt, void* pData = NULL, + BOOL bMouse = FALSE, Point* pPos = NULL ) +{ + Point aPos; + if ( pPos ) + aPos = *pPos; + else + { + if( bMouse ) + aPos = pChild->GetPointerPosPixel(); + else + { + // simulate mouseposition at center of window + Size aSize( pChild->GetOutputSizePixel() ); + aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 ); + } + } + + CommandEvent aCEvt( aPos, nEvt, bMouse, pData ); + NotifyEvent aNCmdEvt( EVENT_COMMAND, pChild, &aCEvt ); + ImplDelData aDelData( pChild ); + BOOL bPreNotify = (ImplCallPreNotify( aNCmdEvt ) != 0); + if ( aDelData.IsDelete() ) + return FALSE; + if ( !bPreNotify ) + { + pChild->ImplGetWindowImpl()->mbCommand = FALSE; + pChild->Command( aCEvt ); + + if( aDelData.IsDelete() ) + return FALSE; + pChild->ImplNotifyKeyMouseCommandEventListeners( aNCmdEvt ); + if ( aDelData.IsDelete() ) + return FALSE; + if ( pChild->ImplGetWindowImpl()->mbCommand ) + return TRUE; + } + + return FALSE; +} + +// ----------------------------------------------------------------------- + +/* #i34277# delayed context menu activation; +* necessary if there already was a popup menu running. +*/ + +struct ContextMenuEvent +{ + Window* pWindow; + ImplDelData aDelData; + Point aChildPos; +}; + +static long ContextMenuEventLink( void* pCEvent, void* ) +{ + ContextMenuEvent* pEv = (ContextMenuEvent*)pCEvent; + + if( ! pEv->aDelData.IsDelete() ) + { + pEv->pWindow->ImplRemoveDel( &pEv->aDelData ); + ImplCallCommand( pEv->pWindow, COMMAND_CONTEXTMENU, NULL, TRUE, &pEv->aChildPos ); + } + delete pEv; + + return 0; +} + +long ImplHandleMouseEvent( Window* pWindow, USHORT nSVEvent, BOOL bMouseLeave, + long nX, long nY, ULONG nMsgTime, + USHORT nCode, USHORT nMode ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Point aMousePos( nX, nY ); + Window* pChild; + long nRet; + USHORT nClicks; + ImplFrameData* pWinFrameData = pWindow->ImplGetFrameData(); + USHORT nOldCode = pWinFrameData->mnMouseCode; + + // we need a mousemove event, befor we get a mousebuttondown or a + // mousebuttonup event + if ( (nSVEvent == EVENT_MOUSEBUTTONDOWN) || + (nSVEvent == EVENT_MOUSEBUTTONUP) ) + { + if ( (nSVEvent == EVENT_MOUSEBUTTONUP) && pSVData->maHelpData.mbExtHelpMode ) + Help::EndExtHelp(); + if ( pSVData->maHelpData.mpHelpWin ) + { + if( pWindow->ImplGetWindow() == pSVData->maHelpData.mpHelpWin ) + { + ImplDestroyHelpWindow( false ); + return 1; // pWindow is dead now - avoid crash! + } + else + ImplDestroyHelpWindow( true ); + } + + if ( (pWinFrameData->mnLastMouseX != nX) || + (pWinFrameData->mnLastMouseY != nY) ) + { + ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, FALSE, nX, nY, nMsgTime, nCode, nMode ); + } + } + + // update frame data + pWinFrameData->mnBeforeLastMouseX = pWinFrameData->mnLastMouseX; + pWinFrameData->mnBeforeLastMouseY = pWinFrameData->mnLastMouseY; + pWinFrameData->mnLastMouseX = nX; + pWinFrameData->mnLastMouseY = nY; + pWinFrameData->mnMouseCode = nCode; + pWinFrameData->mnMouseMode = nMode & ~(MOUSE_SYNTHETIC | MOUSE_MODIFIERCHANGED); + if ( bMouseLeave ) + { + pWinFrameData->mbMouseIn = FALSE; + if ( pSVData->maHelpData.mpHelpWin && !pSVData->maHelpData.mbKeyboardHelp ) + { + ImplDelData aDelData( pWindow ); + + ImplDestroyHelpWindow( true ); + + if ( aDelData.IsDelete() ) + return 1; // pWindow is dead now - avoid crash! (#122045#) + } + } + else + pWinFrameData->mbMouseIn = TRUE; + + DBG_ASSERT( !pSVData->maWinData.mpTrackWin || + (pSVData->maWinData.mpTrackWin == pSVData->maWinData.mpCaptureWin), + "ImplHandleMouseEvent: TrackWin != CaptureWin" ); + + // AutoScrollMode + if ( pSVData->maWinData.mpAutoScrollWin && (nSVEvent == EVENT_MOUSEBUTTONDOWN) ) + { + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + return 1; + } + + // find mouse window + if ( pSVData->maWinData.mpCaptureWin ) + { + pChild = pSVData->maWinData.mpCaptureWin; + + DBG_ASSERT( pWindow == pChild->ImplGetFrameWindow(), + "ImplHandleMouseEvent: mouse event is not sent to capture window" ); + + // java client cannot capture mouse correctly + if ( pWindow != pChild->ImplGetFrameWindow() ) + return 0; + + if ( bMouseLeave ) + return 0; + } + else + { + if ( bMouseLeave ) + pChild = NULL; + else + pChild = pWindow->ImplFindWindow( aMousePos ); + } + + // test this because mouse events are buffered in the remote version + // and size may not be in sync + if ( !pChild && !bMouseLeave ) + return 0; + + // Ein paar Test ausfuehren und Message abfangen oder Status umsetzen + if ( pChild ) + { + if( pChild->ImplIsAntiparallel() ) + { + // - RTL - re-mirror frame pos at pChild + pChild->ImplReMirror( aMousePos ); + } + // no mouse messages to system object windows ? + // !!!KA: Is it OK to comment this out? !!! +// if ( pChild->ImplGetWindowImpl()->mpSysObj ) +// return 0; + + // no mouse messages to disabled windows + // #106845# if the window was disabed during capturing we have to pass the mouse events to release capturing + if ( pSVData->maWinData.mpCaptureWin != pChild && (!pChild->IsEnabled() || !pChild->IsInputEnabled() || pChild->IsInModalMode() ) ) + { + ImplHandleMouseFloatMode( pChild, aMousePos, nCode, nSVEvent, bMouseLeave ); + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + ImplHandleMouseHelpRequest( pChild, aMousePos ); + if( pWinFrameData->mpMouseMoveWin != pChild ) + nMode |= MOUSE_ENTERWINDOW; + } + + // Call the hook also, if Window is disabled + Point aChildPos = pChild->ImplFrameToOutput( aMousePos ); + MouseEvent aMEvt( aChildPos, pWinFrameData->mnClickCount, nMode, nCode, nCode ); + NotifyEvent aNEvt( nSVEvent, pChild, &aMEvt ); + Application::CallEventHooks( aNEvt ); + + if( pChild->IsCallHandlersOnInputDisabled() ) + { + pWinFrameData->mpMouseMoveWin = pChild; + pChild->ImplNotifyKeyMouseCommandEventListeners( aNEvt ); + } + + if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + Sound::Beep( SOUND_DISABLE, pChild ); + return 1; + } + else + { + // Set normal MousePointer for disabled windows + if ( nSVEvent == EVENT_MOUSEMOVE ) + ImplSetMousePointer( pChild ); + + return 0; + } + } + + // End ExtTextInput-Mode, if the user click in the same TopLevel Window + if ( pSVData->maWinData.mpExtTextInputWin && + ((nSVEvent == EVENT_MOUSEBUTTONDOWN) || + (nSVEvent == EVENT_MOUSEBUTTONUP)) ) + pSVData->maWinData.mpExtTextInputWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE ); + } + + // determine mouse event data + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + // Testen, ob MouseMove an das gleiche Fenster geht und sich der + // Status nicht geaendert hat + if ( pChild ) + { + Point aChildMousePos = pChild->ImplFrameToOutput( aMousePos ); + if ( !bMouseLeave && + (pChild == pWinFrameData->mpMouseMoveWin) && + (aChildMousePos.X() == pWinFrameData->mnLastMouseWinX) && + (aChildMousePos.Y() == pWinFrameData->mnLastMouseWinY) && + (nOldCode == pWinFrameData->mnMouseCode) ) + { + // Mouse-Pointer neu setzen, da er sich geaendet haben + // koennte, da ein Modus umgesetzt wurde + ImplSetMousePointer( pChild ); + return 0; + } + + pWinFrameData->mnLastMouseWinX = aChildMousePos.X(); + pWinFrameData->mnLastMouseWinY = aChildMousePos.Y(); + } + + // mouse click + nClicks = pWinFrameData->mnClickCount; + + // Gegebenenfalls den Start-Drag-Handler rufen. + // Achtung: Muss vor Move gerufen werden, da sonst bei schnellen + // Mausbewegungen die Applikationen in den Selektionszustand gehen. + Window* pMouseDownWin = pWinFrameData->mpMouseDownWin; + if ( pMouseDownWin ) + { + // Testen, ob StartDrag-Modus uebereinstimmt. Wir vergleichen nur + // den Status der Maustasten, damit man mit Mod1 z.B. sofort + // in den Kopiermodus gehen kann. + const MouseSettings& rMSettings = pMouseDownWin->GetSettings().GetMouseSettings(); + if ( (nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) == + (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) ) + { + if ( !pMouseDownWin->ImplGetFrameData()->mbStartDragCalled ) + { + long nDragW = rMSettings.GetStartDragWidth(); + long nDragH = rMSettings.GetStartDragWidth(); + //long nMouseX = nX; + //long nMouseY = nY; + long nMouseX = aMousePos.X(); // #106074# use the possibly re-mirrored coordinates (RTL) ! nX,nY are unmodified ! + long nMouseY = aMousePos.Y(); + if ( !(((nMouseX-nDragW) <= pMouseDownWin->ImplGetFrameData()->mnFirstMouseX) && + ((nMouseX+nDragW) >= pMouseDownWin->ImplGetFrameData()->mnFirstMouseX)) || + !(((nMouseY-nDragH) <= pMouseDownWin->ImplGetFrameData()->mnFirstMouseY) && + ((nMouseY+nDragH) >= pMouseDownWin->ImplGetFrameData()->mnFirstMouseY)) ) + { + pMouseDownWin->ImplGetFrameData()->mbStartDragCalled = TRUE; + + // Check if drag source provides it's own recognizer + if( pMouseDownWin->ImplGetFrameData()->mbInternalDragGestureRecognizer ) + { + // query DropTarget from child window + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer > xDragGestureRecognizer = + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragGestureRecognizer > ( pMouseDownWin->ImplGetWindowImpl()->mxDNDListenerContainer, + ::com::sun::star::uno::UNO_QUERY ); + + if( xDragGestureRecognizer.is() ) + { + // retrieve mouse position relative to mouse down window + Point relLoc = pMouseDownWin->ImplFrameToOutput( Point( + pMouseDownWin->ImplGetFrameData()->mnFirstMouseX, + pMouseDownWin->ImplGetFrameData()->mnFirstMouseY ) ); + + // create a uno mouse event out of the available data + ::com::sun::star::awt::MouseEvent aMouseEvent( + static_cast < ::com::sun::star::uno::XInterface * > ( 0 ), +#ifdef MACOSX + nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3), +#else + nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2), +#endif + nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE), + nMouseX, + nMouseY, + nClicks, + sal_False ); + + ULONG nCount = Application::ReleaseSolarMutex(); + + // FIXME: where do I get Action from ? + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSource > xDragSource = pMouseDownWin->GetDragSource(); + + if( xDragSource.is() ) + { + static_cast < DNDListenerContainer * > ( xDragGestureRecognizer.get() )->fireDragGestureEvent( 0, + relLoc.X(), relLoc.Y(), xDragSource, ::com::sun::star::uno::makeAny( aMouseEvent ) ); + } + + Application::AcquireSolarMutex( nCount ); + } + } + } + } + } + else + pMouseDownWin->ImplGetFrameData()->mbStartDragCalled = TRUE; + } + + // test for mouseleave and mouseenter + Window* pMouseMoveWin = pWinFrameData->mpMouseMoveWin; + if ( pChild != pMouseMoveWin ) + { + if ( pMouseMoveWin ) + { + Point aLeaveMousePos = pMouseMoveWin->ImplFrameToOutput( aMousePos ); + MouseEvent aMLeaveEvt( aLeaveMousePos, nClicks, nMode | MOUSE_LEAVEWINDOW, nCode, nCode ); + NotifyEvent aNLeaveEvt( EVENT_MOUSEMOVE, pMouseMoveWin, &aMLeaveEvt ); + ImplDelData aDelData; + ImplDelData aDelData2; + pWinFrameData->mbInMouseMove = TRUE; + pMouseMoveWin->ImplGetWinData()->mbMouseOver = FALSE; + pMouseMoveWin->ImplAddDel( &aDelData ); + // Durch MouseLeave kann auch dieses Fenster zerstoert + // werden + if ( pChild ) + pChild->ImplAddDel( &aDelData2 ); + if ( !ImplCallPreNotify( aNLeaveEvt ) ) + { + pMouseMoveWin->MouseMove( aMLeaveEvt ); + // #82968# + if( !aDelData.IsDelete() ) + aNLeaveEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNLeaveEvt ); + } + + pWinFrameData->mpMouseMoveWin = NULL; + pWinFrameData->mbInMouseMove = FALSE; + + if ( pChild ) + { + if ( aDelData2.IsDelete() ) + pChild = NULL; + else + pChild->ImplRemoveDel( &aDelData2 ); + } + if ( aDelData.IsDelete() ) + return 1; + pMouseMoveWin->ImplRemoveDel( &aDelData ); + } + + nMode |= MOUSE_ENTERWINDOW; + } + pWinFrameData->mpMouseMoveWin = pChild; + if( pChild ) + pChild->ImplGetWinData()->mbMouseOver = TRUE; + + // MouseLeave + if ( !pChild ) + return 0; + } + else + { + // mouse click + if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + const MouseSettings& rMSettings = pChild->GetSettings().GetMouseSettings(); + ULONG nDblClkTime = rMSettings.GetDoubleClickTime(); + long nDblClkW = rMSettings.GetDoubleClickWidth(); + long nDblClkH = rMSettings.GetDoubleClickHeight(); + //long nMouseX = nX; + //long nMouseY = nY; + long nMouseX = aMousePos.X(); // #106074# use the possibly re-mirrored coordinates (RTL) ! nX,nY are unmodified ! + long nMouseY = aMousePos.Y(); + + if ( (pChild == pChild->ImplGetFrameData()->mpMouseDownWin) && + (nCode == pChild->ImplGetFrameData()->mnFirstMouseCode) && + ((nMsgTime-pChild->ImplGetFrameData()->mnMouseDownTime) < nDblClkTime) && + ((nMouseX-nDblClkW) <= pChild->ImplGetFrameData()->mnFirstMouseX) && + ((nMouseX+nDblClkW) >= pChild->ImplGetFrameData()->mnFirstMouseX) && + ((nMouseY-nDblClkH) <= pChild->ImplGetFrameData()->mnFirstMouseY) && + ((nMouseY+nDblClkH) >= pChild->ImplGetFrameData()->mnFirstMouseY) ) + { + pChild->ImplGetFrameData()->mnClickCount++; + pChild->ImplGetFrameData()->mbStartDragCalled = TRUE; + } + else + { + pChild->ImplGetFrameData()->mpMouseDownWin = pChild; + pChild->ImplGetFrameData()->mnClickCount = 1; + pChild->ImplGetFrameData()->mnFirstMouseX = nMouseX; + pChild->ImplGetFrameData()->mnFirstMouseY = nMouseY; + pChild->ImplGetFrameData()->mnFirstMouseCode = nCode; + pChild->ImplGetFrameData()->mbStartDragCalled = !((nCode & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE)) == + (rMSettings.GetStartDragCode() & (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE))); + } + pChild->ImplGetFrameData()->mnMouseDownTime = nMsgTime; + } + nClicks = pChild->ImplGetFrameData()->mnClickCount; + + pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks(); + } + + DBG_ASSERT( pChild, "ImplHandleMouseEvent: pChild == NULL" ); + + // create mouse event + Point aChildPos = pChild->ImplFrameToOutput( aMousePos ); + MouseEvent aMEvt( aChildPos, nClicks, nMode, nCode, nCode ); + + // tracking window gets the mouse events + if ( pSVData->maWinData.mpTrackWin ) + pChild = pSVData->maWinData.mpTrackWin; + + // handle FloatingMode + if ( !pSVData->maWinData.mpTrackWin && pSVData->maWinData.mpFirstFloat ) + { + ImplDelData aDelData; + pChild->ImplAddDel( &aDelData ); + if ( ImplHandleMouseFloatMode( pChild, aMousePos, nCode, nSVEvent, bMouseLeave ) ) + { + if ( !aDelData.IsDelete() ) + { + pChild->ImplRemoveDel( &aDelData ); + pChild->ImplGetFrameData()->mbStartDragCalled = TRUE; + } + return 1; + } + else + pChild->ImplRemoveDel( &aDelData ); + } + + // call handler + BOOL bDrag = FALSE; + BOOL bCallHelpRequest = TRUE; + DBG_ASSERT( pChild, "ImplHandleMouseEvent: pChild is NULL" ); + + ImplDelData aDelData; + NotifyEvent aNEvt( nSVEvent, pChild, &aMEvt ); + pChild->ImplAddDel( &aDelData ); + if ( nSVEvent == EVENT_MOUSEMOVE ) + pChild->ImplGetFrameData()->mbInMouseMove = TRUE; + + // bring window into foreground on mouseclick + if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + if( !pSVData->maWinData.mpFirstFloat && // totop for floating windows in popup would change the focus and would close them immediately + !(pChild->ImplGetFrameWindow()->GetStyle() & WB_OWNERDRAWDECORATION) ) // ownerdrawdecorated windows must never grab focus + pChild->ToTop(); + if ( aDelData.IsDelete() ) + return 1; + } + + if ( ImplCallPreNotify( aNEvt ) || aDelData.IsDelete() ) + nRet = 1; + else + { + nRet = 0; + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + if ( pSVData->maWinData.mpTrackWin ) + { + TrackingEvent aTEvt( aMEvt ); + pChild->Tracking( aTEvt ); + if ( !aDelData.IsDelete() ) + { + // When ScrollRepeat, we restart the timer + if ( pSVData->maWinData.mpTrackTimer && + (pSVData->maWinData.mnTrackFlags & STARTTRACK_SCROLLREPEAT) ) + pSVData->maWinData.mpTrackTimer->Start(); + } + bCallHelpRequest = FALSE; + nRet = 1; + } + else + { + // Auto-ToTop + if ( !pSVData->maWinData.mpCaptureWin && + (pChild->GetSettings().GetMouseSettings().GetOptions() & MOUSE_OPTION_AUTOFOCUS) ) + pChild->ToTop( TOTOP_NOGRABFOCUS ); + + if( aDelData.IsDelete() ) + bCallHelpRequest = FALSE; + else + { + // if the MouseMove handler changes the help window's visibility + // the HelpRequest handler should not be called anymore + Window* pOldHelpTextWin = pSVData->maHelpData.mpHelpWin; + pChild->ImplGetWindowImpl()->mbMouseMove = FALSE; + pChild->MouseMove( aMEvt ); + if ( pOldHelpTextWin != pSVData->maHelpData.mpHelpWin ) + bCallHelpRequest = FALSE; + } + } + } + else if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + if ( pSVData->maWinData.mpTrackWin && + !(pSVData->maWinData.mnTrackFlags & STARTTRACK_MOUSEBUTTONDOWN) ) + nRet = 1; + else + { + pChild->ImplGetWindowImpl()->mbMouseButtonDown = FALSE; + pChild->MouseButtonDown( aMEvt ); + } + } + else + { + if ( pSVData->maWinData.mpTrackWin ) + { + pChild->EndTracking(); + nRet = 1; + } + else + { + pChild->ImplGetWindowImpl()->mbMouseButtonUp = FALSE; + pChild->MouseButtonUp( aMEvt ); + } + } + + // #82968# + if ( !aDelData.IsDelete() ) + aNEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNEvt ); + } + + if ( aDelData.IsDelete() ) + return 1; + + + if ( nSVEvent == EVENT_MOUSEMOVE ) + pChild->ImplGetWindowImpl()->mpFrameData->mbInMouseMove = FALSE; + + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + if ( bCallHelpRequest && !pSVData->maHelpData.mbKeyboardHelp ) + ImplHandleMouseHelpRequest( pChild, pChild->OutputToScreenPixel( aMEvt.GetPosPixel() ) ); + nRet = 1; + } + else if ( !nRet ) + { + if ( nSVEvent == EVENT_MOUSEBUTTONDOWN ) + { + if ( !pChild->ImplGetWindowImpl()->mbMouseButtonDown ) + nRet = 1; + } + else + { + if ( !pChild->ImplGetWindowImpl()->mbMouseButtonUp ) + nRet = 1; + } + } + + pChild->ImplRemoveDel( &aDelData ); + + if ( nSVEvent == EVENT_MOUSEMOVE ) + { + // set new mouse pointer + if ( !bMouseLeave ) + ImplSetMousePointer( pChild ); + } + else if ( (nSVEvent == EVENT_MOUSEBUTTONDOWN) || (nSVEvent == EVENT_MOUSEBUTTONUP) ) + { + if ( !bDrag ) + { + // Command-Events + if ( /*(nRet == 0) &&*/ (nClicks == 1) && (nSVEvent == EVENT_MOUSEBUTTONDOWN) && + (nCode == MOUSE_MIDDLE) ) + { + USHORT nMiddleAction = pChild->GetSettings().GetMouseSettings().GetMiddleButtonAction(); + if ( nMiddleAction == MOUSE_MIDDLE_AUTOSCROLL ) + nRet = !ImplCallCommand( pChild, COMMAND_STARTAUTOSCROLL, NULL, TRUE, &aChildPos ); + else if ( nMiddleAction == MOUSE_MIDDLE_PASTESELECTION ) + nRet = !ImplCallCommand( pChild, COMMAND_PASTESELECTION, NULL, TRUE, &aChildPos ); + } + else + { + // ContextMenu + const MouseSettings& rMSettings = pChild->GetSettings().GetMouseSettings(); + if ( (nCode == rMSettings.GetContextMenuCode()) && + (nClicks == rMSettings.GetContextMenuClicks()) ) + { + BOOL bContextMenu; + if ( rMSettings.GetContextMenuDown() ) + bContextMenu = (nSVEvent == EVENT_MOUSEBUTTONDOWN); + else + bContextMenu = (nSVEvent == EVENT_MOUSEBUTTONUP); + if ( bContextMenu ) + { + if( pSVData->maAppData.mpActivePopupMenu ) + { + /* #i34277# there already is a context menu open + * that was probably just closed with EndPopupMode. + * We need to give the eventual corresponding + * PopupMenu::Execute a chance to end properly. + * Therefore delay context menu command and + * issue only after popping one frame of the + * Yield stack. + */ + ContextMenuEvent* pEv = new ContextMenuEvent; + pEv->pWindow = pChild; + pEv->aChildPos = aChildPos; + pChild->ImplAddDel( &pEv->aDelData ); + Application::PostUserEvent( Link( pEv, ContextMenuEventLink ) ); + } + else + nRet = ! ImplCallCommand( pChild, COMMAND_CONTEXTMENU, NULL, TRUE, &aChildPos ); + } + } + } + } + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +static Window* ImplGetKeyInputWindow( Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + // determine last input time + pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks(); + + // #127104# workaround for destroyed windows + if( pWindow->ImplGetWindowImpl() == NULL ) + return 0; + + // find window - is every time the window which has currently the + // focus or the last time the focus. + // the first floating window always has the focus + Window* pChild = pSVData->maWinData.mpFirstFloat; + if( !pChild || ( pChild->ImplGetWindowImpl()->mbFloatWin && !((FloatingWindow *)pChild)->GrabsFocus() ) ) + pChild = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin; + else + { + // allow floaters to forward keyinput to some member + pChild = pChild->GetPreferredKeyInputWindow(); + } + + // no child - than no input + if ( !pChild ) + return 0; + + // We call also KeyInput if we haven't the focus, because on Unix + // system this is often the case when a Lookup Choise Window has + // the focus - because this windows send the KeyInput directly to + // the window without resetting the focus + DBG_ASSERTWARNING( pChild == pSVData->maWinData.mpFocusWin, + "ImplHandleKey: Keyboard-Input is sent to a frame without focus" ); + + // no keyinput to disabled windows + if ( !pChild->IsEnabled() || !pChild->IsInputEnabled() || pChild->IsInModalMode() ) + return 0; + + return pChild; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleKey( Window* pWindow, USHORT nSVEvent, + USHORT nKeyCode, USHORT nCharCode, USHORT nRepeat, BOOL bForward ) +{ + ImplSVData* pSVData = ImplGetSVData(); + KeyCode aKeyCode( nKeyCode, nKeyCode ); + USHORT nEvCode = aKeyCode.GetCode(); + + // allow application key listeners to remove the key event + // but make sure we're not forwarding external KeyEvents, (ie where bForward is FALSE) + // becasue those are coming back from the listener itself and MUST be processed + KeyEvent aKeyEvent( (xub_Unicode)nCharCode, aKeyCode, nRepeat ); + if( bForward ) + { + USHORT nVCLEvent; + switch( nSVEvent ) + { + case EVENT_KEYINPUT: + nVCLEvent = VCLEVENT_WINDOW_KEYINPUT; + break; + case EVENT_KEYUP: + nVCLEvent = VCLEVENT_WINDOW_KEYUP; + break; + default: + nVCLEvent = 0; + break; + } + if( nVCLEvent && pSVData->mpApp->HandleKey( nVCLEvent, pWindow, &aKeyEvent ) ) + return 1; + } + + // #i1820# use locale specific decimal separator + if( nEvCode == KEY_DECIMAL ) + { + if( Application::GetSettings().GetMiscSettings().GetEnableLocalizedDecimalSep() ) + { + String aSep( pWindow->GetSettings().GetLocaleDataWrapper().getNumDecimalSep() ); + nCharCode = (USHORT) aSep.GetChar(0); + } + } + + BOOL bCtrlF6 = (aKeyCode.GetCode() == KEY_F6) && aKeyCode.IsMod1(); + + // determine last input time + pSVData->maAppData.mnLastInputTime = Time::GetSystemTicks(); + + // handle tracking window + if ( nSVEvent == EVENT_KEYINPUT ) + { +#ifdef DBG_UTIL + // #105224# use Ctrl-Alt-Shift-D, Ctrl-Shift-D must be useable by app + if ( aKeyCode.IsShift() && aKeyCode.IsMod1() && (aKeyCode.IsMod2() || aKeyCode.IsMod3()) && (aKeyCode.GetCode() == KEY_D) ) + { + DBGGUI_START(); + return 1; + } +#endif + + if ( pSVData->maHelpData.mbExtHelpMode ) + { + Help::EndExtHelp(); + if ( nEvCode == KEY_ESCAPE ) + return 1; + } + if ( pSVData->maHelpData.mpHelpWin ) + ImplDestroyHelpWindow( false ); + + // AutoScrollMode + if ( pSVData->maWinData.mpAutoScrollWin ) + { + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + if ( nEvCode == KEY_ESCAPE ) + return 1; + } + + if ( pSVData->maWinData.mpTrackWin ) + { + USHORT nOrigCode = aKeyCode.GetCode(); + + if ( (nOrigCode == KEY_ESCAPE) && !(pSVData->maWinData.mnTrackFlags & STARTTRACK_NOKEYCANCEL) ) + { + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL | ENDTRACK_KEY ); + if ( pSVData->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + if ( !(pLastLevelFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOKEYCLOSE) ) + { + USHORT nEscCode = aKeyCode.GetCode(); + + if ( nEscCode == KEY_ESCAPE ) + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + } + return 1; + } + else if ( nOrigCode == KEY_RETURN ) + { + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_KEY ); + return 1; + } + else if ( !(pSVData->maWinData.mnTrackFlags & STARTTRACK_KEYINPUT) ) + return 1; + } + + // handle FloatingMode + if ( pSVData->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + if ( !(pLastLevelFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOKEYCLOSE) ) + { + USHORT nCode = aKeyCode.GetCode(); + + if ( (nCode == KEY_ESCAPE) || bCtrlF6) + { + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + if( !bCtrlF6 ) + return 1; + } + } + } + + // test for accel + if ( pSVData->maAppData.mpAccelMgr ) + { + if ( pSVData->maAppData.mpAccelMgr->IsAccelKey( aKeyCode, nRepeat ) ) + return 1; + } + } + + // find window + Window* pChild = ImplGetKeyInputWindow( pWindow ); + if ( !pChild ) + return 0; + + // --- RTL --- mirror cursor keys + if( (aKeyCode.GetCode() == KEY_LEFT || aKeyCode.GetCode() == KEY_RIGHT) && + pChild->ImplHasMirroredGraphics() && pChild->IsRTLEnabled() ) + aKeyCode = KeyCode( aKeyCode.GetCode() == KEY_LEFT ? KEY_RIGHT : KEY_LEFT, aKeyCode.GetModifier() ); + + // call handler + ImplDelData aDelData; + pChild->ImplAddDel( &aDelData ); + + KeyEvent aKeyEvt( (xub_Unicode)nCharCode, aKeyCode, nRepeat ); + NotifyEvent aNotifyEvt( nSVEvent, pChild, &aKeyEvt ); + BOOL bKeyPreNotify = (ImplCallPreNotify( aNotifyEvt ) != 0); + long nRet = 1; + + if ( !bKeyPreNotify && !aDelData.IsDelete() ) + { + if ( nSVEvent == EVENT_KEYINPUT ) + { + pChild->ImplGetWindowImpl()->mbKeyInput = FALSE; + pChild->KeyInput( aKeyEvt ); + } + else + { + pChild->ImplGetWindowImpl()->mbKeyUp = FALSE; + pChild->KeyUp( aKeyEvt ); + } + // #82968# + if( !aDelData.IsDelete() ) + aNotifyEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNotifyEvt ); + } + + if ( aDelData.IsDelete() ) + return 1; + + pChild->ImplRemoveDel( &aDelData ); + + if ( nSVEvent == EVENT_KEYINPUT ) + { + if ( !bKeyPreNotify && pChild->ImplGetWindowImpl()->mbKeyInput ) + { + USHORT nCode = aKeyCode.GetCode(); + + // #101999# is focus in or below toolbox + BOOL bToolboxFocus=FALSE; + if( (nCode == KEY_F1) && aKeyCode.IsShift() ) + { + Window *pWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin; + while( pWin ) + { + if( pWin->ImplGetWindowImpl()->mbToolBox ) + { + bToolboxFocus = TRUE; + break; + } + else + pWin = pWin->GetParent(); + } + } + + // ContextMenu + if ( (nCode == KEY_CONTEXTMENU) || ((nCode == KEY_F10) && aKeyCode.IsShift() && !aKeyCode.IsMod1() && !aKeyCode.IsMod2() ) ) + nRet = !ImplCallCommand( pChild, COMMAND_CONTEXTMENU, NULL, FALSE ); + else if ( ( (nCode == KEY_F2) && aKeyCode.IsShift() ) || ( (nCode == KEY_F1) && aKeyCode.IsMod1() ) || + // #101999# no active help when focus in toolbox, simulate BallonHelp instead + ( (nCode == KEY_F1) && aKeyCode.IsShift() && bToolboxFocus ) ) + { + // TipHelp via Keyboard (Shift-F2 or Ctrl-F1) + // simulate mouseposition at center of window + + Size aSize = pChild->GetOutputSize(); + Point aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 ); + aPos = pChild->OutputToScreenPixel( aPos ); + + HelpEvent aHelpEvent( aPos, HELPMODE_BALLOON ); + aHelpEvent.SetKeyboardActivated( TRUE ); + pSVData->maHelpData.mbSetKeyboardHelp = TRUE; + pChild->RequestHelp( aHelpEvent ); + pSVData->maHelpData.mbSetKeyboardHelp = FALSE; + } + else if ( (nCode == KEY_F1) || (nCode == KEY_HELP) ) + { + if ( !aKeyCode.GetModifier() ) + { + if ( pSVData->maHelpData.mbContextHelp ) + { + Point aMousePos = pChild->OutputToScreenPixel( pChild->GetPointerPosPixel() ); + HelpEvent aHelpEvent( aMousePos, HELPMODE_CONTEXT ); + pChild->RequestHelp( aHelpEvent ); + } + else + nRet = 0; + } + else if ( aKeyCode.IsShift() ) + { + if ( pSVData->maHelpData.mbExtHelp ) + Help::StartExtHelp(); + else + nRet = 0; + } + } + else + { + if ( ImplCallHotKey( aKeyCode ) ) + nRet = 1; + else + nRet = 0; + } + } + } + else + { + if ( !bKeyPreNotify && pChild->ImplGetWindowImpl()->mbKeyUp ) + nRet = 0; + } + + // #105591# send keyinput to parent if we are a floating window and the key was not pocessed yet + if( !nRet && pWindow->ImplGetWindowImpl()->mbFloatWin && pWindow->GetParent() && (pWindow->ImplGetWindowImpl()->mpFrame != pWindow->GetParent()->ImplGetWindowImpl()->mpFrame) ) + { + pChild = pWindow->GetParent(); + + // call handler + ImplDelData aChildDelData( pChild ); + KeyEvent aKEvt( (xub_Unicode)nCharCode, aKeyCode, nRepeat ); + NotifyEvent aNEvt( nSVEvent, pChild, &aKEvt ); + BOOL bPreNotify = (ImplCallPreNotify( aNEvt ) != 0); + if ( aChildDelData.IsDelete() ) + return 1; + + if ( !bPreNotify ) + { + if ( nSVEvent == EVENT_KEYINPUT ) + { + pChild->ImplGetWindowImpl()->mbKeyInput = FALSE; + pChild->KeyInput( aKEvt ); + } + else + { + pChild->ImplGetWindowImpl()->mbKeyUp = FALSE; + pChild->KeyUp( aKEvt ); + } + // #82968# + if( !aChildDelData.IsDelete() ) + aNEvt.GetWindow()->ImplNotifyKeyMouseCommandEventListeners( aNEvt ); + if ( aChildDelData.IsDelete() ) + return 1; + } + + if( bPreNotify || !pChild->ImplGetWindowImpl()->mbKeyInput ) + nRet = 1; + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleExtTextInput( Window* pWindow, + const XubString& rText, + const USHORT* pTextAttr, + ULONG nCursorPos, USHORT nCursorFlags ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pChild = NULL; + + int nTries = 200; + while( nTries-- ) + { + pChild = pSVData->maWinData.mpExtTextInputWin; + if ( !pChild ) + { + pChild = ImplGetKeyInputWindow( pWindow ); + if ( !pChild ) + return 0; + } + if( !pChild->ImplGetWindowImpl()->mpFrameData->mnFocusId ) + break; + Application::Yield(); + } + + // If it is the first ExtTextInput call, we inform the information + // and allocate the data, which we must store in this mode + ImplWinData* pWinData = pChild->ImplGetWinData(); + if ( !pChild->ImplGetWindowImpl()->mbExtTextInput ) + { + pChild->ImplGetWindowImpl()->mbExtTextInput = TRUE; + if ( !pWinData->mpExtOldText ) + pWinData->mpExtOldText = new UniString; + else + pWinData->mpExtOldText->Erase(); + if ( pWinData->mpExtOldAttrAry ) + { + delete [] pWinData->mpExtOldAttrAry; + pWinData->mpExtOldAttrAry = NULL; + } + pSVData->maWinData.mpExtTextInputWin = pChild; + ImplCallCommand( pChild, COMMAND_STARTEXTTEXTINPUT ); + } + + // be aware of being recursively called in StartExtTextInput + if ( !pChild->ImplGetWindowImpl()->mbExtTextInput ) + return 0; + + // Test for changes + BOOL bOnlyCursor = FALSE; + xub_StrLen nMinLen = Min( pWinData->mpExtOldText->Len(), rText.Len() ); + xub_StrLen nDeltaStart = 0; + while ( nDeltaStart < nMinLen ) + { + if ( pWinData->mpExtOldText->GetChar( nDeltaStart ) != rText.GetChar( nDeltaStart ) ) + break; + nDeltaStart++; + } + if ( pWinData->mpExtOldAttrAry || pTextAttr ) + { + if ( !pWinData->mpExtOldAttrAry || !pTextAttr ) + nDeltaStart = 0; + else + { + xub_StrLen i = 0; + while ( i < nDeltaStart ) + { + if ( pWinData->mpExtOldAttrAry[i] != pTextAttr[i] ) + { + nDeltaStart = i; + break; + } + i++; + } + } + } + if ( (nDeltaStart >= nMinLen) && + (pWinData->mpExtOldText->Len() == rText.Len()) ) + bOnlyCursor = TRUE; + + // Call Event and store the information + CommandExtTextInputData aData( rText, pTextAttr, + (xub_StrLen)nCursorPos, nCursorFlags, + nDeltaStart, pWinData->mpExtOldText->Len(), + bOnlyCursor ); + *pWinData->mpExtOldText = rText; + if ( pWinData->mpExtOldAttrAry ) + { + delete [] pWinData->mpExtOldAttrAry; + pWinData->mpExtOldAttrAry = NULL; + } + if ( pTextAttr ) + { + pWinData->mpExtOldAttrAry = new USHORT[rText.Len()]; + memcpy( pWinData->mpExtOldAttrAry, pTextAttr, rText.Len()*sizeof( USHORT ) ); + } + return !ImplCallCommand( pChild, COMMAND_EXTTEXTINPUT, &aData ); +} + +// ----------------------------------------------------------------------- + +static long ImplHandleEndExtTextInput( Window* /* pWindow */ ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pChild = pSVData->maWinData.mpExtTextInputWin; + long nRet = 0; + + if ( pChild ) + { + pChild->ImplGetWindowImpl()->mbExtTextInput = FALSE; + pSVData->maWinData.mpExtTextInputWin = NULL; + ImplWinData* pWinData = pChild->ImplGetWinData(); + if ( pWinData->mpExtOldText ) + { + delete pWinData->mpExtOldText; + pWinData->mpExtOldText = NULL; + } + if ( pWinData->mpExtOldAttrAry ) + { + delete [] pWinData->mpExtOldAttrAry; + pWinData->mpExtOldAttrAry = NULL; + } + nRet = !ImplCallCommand( pChild, COMMAND_ENDEXTTEXTINPUT ); + } + + return nRet; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleExtTextInputPos( Window* pWindow, + Rectangle& rRect, long& rInputWidth, + bool * pVertical ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pChild = pSVData->maWinData.mpExtTextInputWin; + + if ( !pChild ) + pChild = ImplGetKeyInputWindow( pWindow ); + else + { + // Test, if the Window is related to the frame + if ( !pWindow->ImplIsWindowOrChild( pChild ) ) + pChild = ImplGetKeyInputWindow( pWindow ); + } + + if ( pChild ) + { + ImplCallCommand( pChild, COMMAND_CURSORPOS ); + const Rectangle* pRect = pChild->GetCursorRect(); + if ( pRect ) + rRect = pChild->ImplLogicToDevicePixel( *pRect ); + else + { + Cursor* pCursor = pChild->GetCursor(); + if ( pCursor ) + { + Point aPos = pChild->ImplLogicToDevicePixel( pCursor->GetPos() ); + Size aSize = pChild->LogicToPixel( pCursor->GetSize() ); + if ( !aSize.Width() ) + aSize.Width() = pChild->GetSettings().GetStyleSettings().GetCursorSize(); + rRect = Rectangle( aPos, aSize ); + } + else + rRect = Rectangle( Point( pChild->GetOutOffXPixel(), pChild->GetOutOffYPixel() ), Size() ); + } + rInputWidth = pChild->ImplLogicWidthToDevicePixel( pChild->GetCursorExtTextInputWidth() ); + if ( !rInputWidth ) + rInputWidth = rRect.GetWidth(); + } + if (pVertical != 0) + *pVertical + = pChild != 0 && pChild->GetInputContext().GetFont().IsVertical(); +} + +// ----------------------------------------------------------------------- + +static long ImplHandleInputContextChange( Window* pWindow, LanguageType eNewLang ) +{ + Window* pChild = ImplGetKeyInputWindow( pWindow ); + CommandInputContextData aData( eNewLang ); + return !ImplCallCommand( pChild, COMMAND_INPUTCONTEXTCHANGE, &aData ); +} + +// ----------------------------------------------------------------------- + +static BOOL ImplCallWheelCommand( Window* pWindow, const Point& rPos, + const CommandWheelData* pWheelData ) +{ + Point aCmdMousePos = pWindow->ImplFrameToOutput( rPos ); + CommandEvent aCEvt( aCmdMousePos, COMMAND_WHEEL, TRUE, pWheelData ); + NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); + ImplDelData aDelData( pWindow ); + BOOL bPreNotify = (ImplCallPreNotify( aNCmdEvt ) != 0); + if ( aDelData.IsDelete() ) + return FALSE; + if ( !bPreNotify ) + { + pWindow->ImplGetWindowImpl()->mbCommand = FALSE; + pWindow->Command( aCEvt ); + if ( aDelData.IsDelete() ) + return FALSE; + if ( pWindow->ImplGetWindowImpl()->mbCommand ) + return TRUE; + } + return FALSE; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleWheelEvent( Window* pWindow, const SalWheelMouseEvent& rEvt ) +{ + ImplDelData aDogTag( pWindow ); + + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maWinData.mpAutoScrollWin ) + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + if ( pSVData->maHelpData.mpHelpWin ) + ImplDestroyHelpWindow( true ); + if( aDogTag.IsDelete() ) + return 0; + + USHORT nMode; + USHORT nCode = rEvt.mnCode; + bool bHorz = rEvt.mbHorz; + bool bPixel = rEvt.mbDeltaIsPixel; + if ( nCode & KEY_MOD1 ) + nMode = COMMAND_WHEEL_ZOOM; + else if ( nCode & KEY_MOD2 ) + nMode = COMMAND_WHEEL_DATAZOOM; + else + { + nMode = COMMAND_WHEEL_SCROLL; + // #i85450# interpret shift-wheel as horizontal wheel action + if( (nCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)) == KEY_SHIFT ) + bHorz = true; + } + + CommandWheelData aWheelData( rEvt.mnDelta, rEvt.mnNotchDelta, rEvt.mnScrollLines, nMode, nCode, bHorz, bPixel ); + Point aMousePos( rEvt.mnX, rEvt.mnY ); + BOOL bRet = TRUE; + + // first check any floating window ( eg. drop down listboxes) + bool bIsFloat = false; + Window *pMouseWindow = NULL; + if ( pSVData->maWinData.mpFirstFloat && !pSVData->maWinData.mpCaptureWin && + !pSVData->maWinData.mpFirstFloat->ImplIsFloatPopupModeWindow( pWindow ) ) + { + USHORT nHitTest = IMPL_FLOATWIN_HITTEST_OUTSIDE; + pMouseWindow = pSVData->maWinData.mpFirstFloat->ImplFloatHitTest( pWindow, aMousePos, nHitTest ); + } + // then try the window directly beneath the mouse + if( !pMouseWindow ) + pMouseWindow = pWindow->ImplFindWindow( aMousePos ); + else + { + // transform coordinates to float window frame coordinates + pMouseWindow = pMouseWindow->ImplFindWindow( + pMouseWindow->OutputToScreenPixel( + pMouseWindow->AbsoluteScreenToOutputPixel( + pWindow->OutputToAbsoluteScreenPixel( + pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) ); + bIsFloat = true; + } + + if ( pMouseWindow && + pMouseWindow->IsEnabled() && pMouseWindow->IsInputEnabled() && ! pMouseWindow->IsInModalMode() ) + { + // transform coordinates to float window frame coordinates + Point aRelMousePos( pMouseWindow->OutputToScreenPixel( + pMouseWindow->AbsoluteScreenToOutputPixel( + pWindow->OutputToAbsoluteScreenPixel( + pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) ); + bRet = ImplCallWheelCommand( pMouseWindow, aRelMousePos, &aWheelData ); + } + + // if the commad was not handled try the focus window + if ( bRet ) + { + Window* pFocusWindow = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin; + if ( pFocusWindow && (pFocusWindow != pMouseWindow) && + (pFocusWindow == pSVData->maWinData.mpFocusWin) ) + { + // no wheel-messages to disabled windows + if ( pFocusWindow->IsEnabled() && pFocusWindow->IsInputEnabled() && ! pFocusWindow->IsInModalMode() ) + { + // transform coordinates to focus window frame coordinates + Point aRelMousePos( pFocusWindow->OutputToScreenPixel( + pFocusWindow->AbsoluteScreenToOutputPixel( + pWindow->OutputToAbsoluteScreenPixel( + pWindow->ScreenToOutputPixel( aMousePos ) ) ) ) ); + bRet = ImplCallWheelCommand( pFocusWindow, aRelMousePos, &aWheelData ); + } + } + } + + // close floaters + if( ! bIsFloat && pSVData->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + if( pLastLevelFloat ) + { + ULONG nPopupFlags = pLastLevelFloat->GetPopupModeFlags(); + if ( nPopupFlags & FLOATWIN_POPUPMODE_ALLMOUSEBUTTONCLOSE ) + { + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + } + } + + return !bRet; +} + +// ----------------------------------------------------------------------- +#define IMPL_PAINT_CHECKRTL ((USHORT)0x0020) + +static void ImplHandlePaint( Window* pWindow, const Rectangle& rBoundRect, bool bImmediateUpdate ) +{ + // give up background save when sytem paints arrive + Window* pSaveBackWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFirstBackWin; + while ( pSaveBackWin ) + { + Window* pNext = pSaveBackWin->ImplGetWindowImpl()->mpOverlapData->mpNextBackWin; + Rectangle aRect( Point( pSaveBackWin->GetOutOffXPixel(), pSaveBackWin->GetOutOffYPixel() ), + Size( pSaveBackWin->GetOutputWidthPixel(), pSaveBackWin->GetOutputHeightPixel() ) ); + if ( aRect.IsOver( rBoundRect ) ) + pSaveBackWin->ImplDeleteOverlapBackground(); + pSaveBackWin = pNext; + } + + // system paint events must be checked for re-mirroring + pWindow->ImplGetWindowImpl()->mnPaintFlags |= IMPL_PAINT_CHECKRTL; + + // trigger paint for all windows that live in the new paint region + Region aRegion( rBoundRect ); + pWindow->ImplInvalidateOverlapFrameRegion( aRegion ); + if( bImmediateUpdate ) + { + // #i87663# trigger possible pending resize notifications + // (GetSizePixel does that for us) + pWindow->GetSizePixel(); + // force drawing inmmediately + pWindow->Update(); + } +} + +// ----------------------------------------------------------------------- + +static void KillOwnPopups( Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window *pParent = pWindow->ImplGetWindowImpl()->mpFrameWindow; + Window *pChild = pSVData->maWinData.mpFirstFloat; + if ( pChild && pParent->ImplIsWindowOrChild( pChild, TRUE ) ) + { + if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) ) + pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } +} + +// ----------------------------------------------------------------------- + +void ImplHandleResize( Window* pWindow, long nNewWidth, long nNewHeight ) +{ + if( pWindow->GetStyle() & (WB_MOVEABLE|WB_SIZEABLE) ) + { + KillOwnPopups( pWindow ); + if( pWindow->ImplGetWindow() != ImplGetSVData()->maHelpData.mpHelpWin ) + ImplDestroyHelpWindow( true ); + } + + if ( + (nNewWidth > 0 && nNewHeight > 0) || + pWindow->ImplGetWindow()->ImplGetWindowImpl()->mbAllResize + ) + { + if ( (nNewWidth != pWindow->GetOutputWidthPixel()) || (nNewHeight != pWindow->GetOutputHeightPixel()) ) + { + pWindow->mnOutWidth = nNewWidth; + pWindow->mnOutHeight = nNewHeight; + pWindow->ImplGetWindowImpl()->mbWaitSystemResize = FALSE; + if ( pWindow->IsReallyVisible() ) + pWindow->ImplSetClipFlag(); + if ( pWindow->IsVisible() || pWindow->ImplGetWindow()->ImplGetWindowImpl()->mbAllResize || + ( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplGetWindowImpl()->mpClientWindow ) ) // propagate resize for system border windows + { + bool bStartTimer = true; + // use resize buffering for user resizes + // ownerdraw decorated windows and floating windows can be resized immediately (i.e. synchronously) + if( pWindow->ImplGetWindowImpl()->mbFrame && (pWindow->GetStyle() & WB_SIZEABLE) + && !(pWindow->GetStyle() & WB_OWNERDRAWDECORATION) // synchronous resize for ownerdraw decorated windows (toolbars) + && !pWindow->ImplGetWindowImpl()->mbFloatWin ) // synchronous resize for floating windows, #i43799# + { + if( pWindow->ImplGetWindowImpl()->mpClientWindow ) + { + // #i42750# presentation wants to be informed about resize + // as early as possible + WorkWindow* pWorkWindow = dynamic_cast<WorkWindow*>(pWindow->ImplGetWindowImpl()->mpClientWindow); + if( pWorkWindow && pWorkWindow->IsPresentationMode() ) + bStartTimer = false; + } + } + else + bStartTimer = false; + + if( bStartTimer ) + pWindow->ImplGetWindowImpl()->mpFrameData->maResizeTimer.Start(); + else + pWindow->ImplCallResize(); // otherwise menues cannot be positioned + } + else + pWindow->ImplGetWindowImpl()->mbCallResize = TRUE; + } + } + + pWindow->ImplGetWindowImpl()->mpFrameData->mbNeedSysWindow = (nNewWidth < IMPL_MIN_NEEDSYSWIN) || + (nNewHeight < IMPL_MIN_NEEDSYSWIN); + BOOL bMinimized = (nNewWidth <= 0) || (nNewHeight <= 0); + if( bMinimized != pWindow->ImplGetWindowImpl()->mpFrameData->mbMinimized ) + pWindow->ImplGetWindowImpl()->mpFrameWindow->ImplNotifyIconifiedState( bMinimized ); + pWindow->ImplGetWindowImpl()->mpFrameData->mbMinimized = bMinimized; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleMove( Window* pWindow ) +{ + if( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplIsFloatingWindow() && pWindow->IsReallyVisible() ) + { + static_cast<FloatingWindow*>(pWindow)->EndPopupMode( FLOATWIN_POPUPMODEEND_TEAROFF ); + pWindow->ImplCallMove(); + } + + if( pWindow->GetStyle() & (WB_MOVEABLE|WB_SIZEABLE) ) + { + KillOwnPopups( pWindow ); + if( pWindow->ImplGetWindow() != ImplGetSVData()->maHelpData.mpHelpWin ) + ImplDestroyHelpWindow( true ); + } + + if ( pWindow->IsVisible() ) + pWindow->ImplCallMove(); + else + pWindow->ImplGetWindowImpl()->mbCallMove = TRUE; // make sure the framepos will be updated on the next Show() + + if ( pWindow->ImplGetWindowImpl()->mbFrame && pWindow->ImplGetWindowImpl()->mpClientWindow ) + pWindow->ImplGetWindowImpl()->mpClientWindow->ImplCallMove(); // notify client to update geometry + +} + +// ----------------------------------------------------------------------- + +static void ImplHandleMoveResize( Window* pWindow, long nNewWidth, long nNewHeight ) +{ + ImplHandleMove( pWindow ); + ImplHandleResize( pWindow, nNewWidth, nNewHeight ); +} + +// ----------------------------------------------------------------------- + +static void ImplActivateFloatingWindows( Window* pWindow, BOOL bActive ) +{ + // Zuerst alle ueberlappenden Fenster ueberpruefen + Window* pTempWindow = pWindow->ImplGetWindowImpl()->mpFirstOverlap; + while ( pTempWindow ) + { + if ( !pTempWindow->GetActivateMode() ) + { + if ( (pTempWindow->GetType() == WINDOW_BORDERWINDOW) && + (pTempWindow->ImplGetWindow()->GetType() == WINDOW_FLOATINGWINDOW) ) + ((ImplBorderWindow*)pTempWindow)->SetDisplayActive( bActive ); + } + + ImplActivateFloatingWindows( pTempWindow, bActive ); + pTempWindow = pTempWindow->ImplGetWindowImpl()->mpNext; + } +} + + +// ----------------------------------------------------------------------- + +IMPL_LINK( Window, ImplAsyncFocusHdl, void*, EMPTYARG ) +{ + ImplGetWindowImpl()->mpFrameData->mnFocusId = 0; + + // Wenn Status erhalten geblieben ist, weil wir den Focus in der + // zwischenzeit schon wiederbekommen haben, brauchen wir auch + // nichts machen + BOOL bHasFocus = ImplGetWindowImpl()->mpFrameData->mbHasFocus || ImplGetWindowImpl()->mpFrameData->mbSysObjFocus; + + // Dann die zeitverzoegerten Funktionen ausfuehren + if ( bHasFocus ) + { + // Alle FloatingFenster deaktiv zeichnen + if ( ImplGetWindowImpl()->mpFrameData->mbStartFocusState != bHasFocus ) + ImplActivateFloatingWindows( this, bHasFocus ); + + if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin ) + { + BOOL bHandled = FALSE; + if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsInputEnabled() && + ! ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsInModalMode() ) + { + if ( ImplGetWindowImpl()->mpFrameData->mpFocusWin->IsEnabled() ) + { + ImplGetWindowImpl()->mpFrameData->mpFocusWin->GrabFocus(); + bHandled = TRUE; + } + else if( ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplHasDlgCtrl() ) + { + // #109094# if the focus is restored to a disabled dialog control (was disabled meanwhile) + // try to move it to the next control + ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplDlgCtrlNextWindow(); + bHandled = TRUE; + } + } + if ( !bHandled ) + { + ImplSVData* pSVData = ImplGetSVData(); + Window* pTopLevelWindow = ImplGetWindowImpl()->mpFrameData->mpFocusWin->ImplGetFirstOverlapWindow(); + if ( ( ! pTopLevelWindow->IsInputEnabled() || pTopLevelWindow->IsInModalMode() ) + && pSVData->maWinData.mpLastExecuteDlg ) + pSVData->maWinData.mpLastExecuteDlg->ToTop( TOTOP_RESTOREWHENMIN | TOTOP_GRABFOCUSONLY); + else + pTopLevelWindow->GrabFocus(); + } + } + else + GrabFocus(); + } + else + { + Window* pFocusWin = ImplGetWindowImpl()->mpFrameData->mpFocusWin; + if ( pFocusWin ) + { + ImplSVData* pSVData = ImplGetSVData(); + + if ( pSVData->maWinData.mpFocusWin == pFocusWin ) + { + // FocusWindow umsetzen + Window* pOverlapWindow = pFocusWin->ImplGetFirstOverlapWindow(); + pOverlapWindow->ImplGetWindowImpl()->mpLastFocusWindow = pFocusWin; + pSVData->maWinData.mpFocusWin = NULL; + + if ( pFocusWin->ImplGetWindowImpl()->mpCursor ) + pFocusWin->ImplGetWindowImpl()->mpCursor->ImplHide(); + + // Deaktivate rufen + Window* pOldFocusWindow = pFocusWin; + if ( pOldFocusWindow ) + { + Window* pOldOverlapWindow = pOldFocusWindow->ImplGetFirstOverlapWindow(); + Window* pOldRealWindow = pOldOverlapWindow->ImplGetWindow(); + + pOldOverlapWindow->ImplGetWindowImpl()->mbActive = FALSE; + pOldOverlapWindow->Deactivate(); + if ( pOldRealWindow != pOldOverlapWindow ) + { + pOldRealWindow->ImplGetWindowImpl()->mbActive = FALSE; + pOldRealWindow->Deactivate(); + } + } + + // TrackingMode is ended in ImplHandleLoseFocus +// To avoid problems with the Unix IME +// pFocusWin->EndExtTextInput( EXTTEXTINPUT_END_COMPLETE ); + + // XXX #102010# hack for accessibility: do not close the menu, + // even after focus lost + static const char* pEnv = getenv("SAL_FLOATWIN_NOAPPFOCUSCLOSE"); + if( !(pEnv && *pEnv) ) + { + NotifyEvent aNEvt( EVENT_LOSEFOCUS, pFocusWin ); + if ( !ImplCallPreNotify( aNEvt ) ) + pFocusWin->LoseFocus(); + pFocusWin->ImplCallDeactivateListeners( NULL ); + GetpApp()->FocusChanged(); + } + // XXX + } + } + + // Alle FloatingFenster deaktiv zeichnen + if ( ImplGetWindowImpl()->mpFrameData->mbStartFocusState != bHasFocus ) + ImplActivateFloatingWindows( this, bHasFocus ); + } + + return 0; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleGetFocus( Window* pWindow ) +{ + pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus = TRUE; + + // Focus-Events zeitverzoegert ausfuehren, damit bei SystemChildFenstern + // nicht alles flackert, wenn diese den Focus bekommen + if ( !pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId ) + { + bool bCallDirect = ImplGetSVData()->mbIsTestTool; + pWindow->ImplGetWindowImpl()->mpFrameData->mbStartFocusState = !pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus; + if( ! bCallDirect ) + Application::PostUserEvent( pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId, LINK( pWindow, Window, ImplAsyncFocusHdl ) ); + Window* pFocusWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin; + if ( pFocusWin && pFocusWin->ImplGetWindowImpl()->mpCursor ) + pFocusWin->ImplGetWindowImpl()->mpCursor->ImplShow(); + if( bCallDirect ) + pWindow->ImplAsyncFocusHdl( NULL ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleLoseFocus( Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + // Wenn Frame den Focus verliert, brechen wir auch ein AutoScroll ab + if ( pSVData->maWinData.mpAutoScrollWin ) + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + + // Wenn Frame den Focus verliert, brechen wir auch ein Tracking ab + if ( pSVData->maWinData.mpTrackWin ) + { + if ( pSVData->maWinData.mpTrackWin->ImplGetWindowImpl()->mpFrameWindow == pWindow ) + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL ); + } + + // handle FloatingMode + // hier beenden wir immer den PopupModus, auch dann, wenn NOFOCUSCLOSE + // gesetzt ist, damit wir nicht beim Wechsel noch Fenster stehen lassen + if ( pSVData->maWinData.mpFirstFloat ) + { + if ( !(pSVData->maWinData.mpFirstFloat->GetPopupModeFlags() & FLOATWIN_POPUPMODE_NOAPPFOCUSCLOSE) ) + pSVData->maWinData.mpFirstFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + + pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus = FALSE; + + // Focus-Events zeitverzoegert ausfuehren, damit bei SystemChildFenstern + // nicht alles flackert, wenn diese den Focus bekommen + bool bCallDirect = ImplGetSVData()->mbIsTestTool; + if ( !pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId ) + { + pWindow->ImplGetWindowImpl()->mpFrameData->mbStartFocusState = !pWindow->ImplGetWindowImpl()->mpFrameData->mbHasFocus; + if( ! bCallDirect ) + Application::PostUserEvent( pWindow->ImplGetWindowImpl()->mpFrameData->mnFocusId, LINK( pWindow, Window, ImplAsyncFocusHdl ) ); + } + + Window* pFocusWin = pWindow->ImplGetWindowImpl()->mpFrameData->mpFocusWin; + if ( pFocusWin && pFocusWin->ImplGetWindowImpl()->mpCursor ) + pFocusWin->ImplGetWindowImpl()->mpCursor->ImplHide(); + if( bCallDirect ) + pWindow->ImplAsyncFocusHdl( NULL ); +} + +// ----------------------------------------------------------------------- +struct DelayedCloseEvent +{ + Window* pWindow; + ImplDelData aDelData; +}; + +static long DelayedCloseEventLink( void* pCEvent, void* ) +{ + DelayedCloseEvent* pEv = (DelayedCloseEvent*)pCEvent; + + if( ! pEv->aDelData.IsDelete() ) + { + pEv->pWindow->ImplRemoveDel( &pEv->aDelData ); + // dispatch to correct window type + if( pEv->pWindow->IsSystemWindow() ) + ((SystemWindow*)pEv->pWindow)->Close(); + else if( pEv->pWindow->ImplIsDockingWindow() ) + ((DockingWindow*)pEv->pWindow)->Close(); + } + delete pEv; + + return 0; +} + +void ImplHandleClose( Window* pWindow ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + bool bWasPopup = false; + if( pWindow->ImplIsFloatingWindow() && + static_cast<FloatingWindow*>(pWindow)->ImplIsInPrivatePopupMode() ) + { + bWasPopup = true; + } + + // on Close stop all floating modes and end popups + if ( pSVData->maWinData.mpFirstFloat ) + { + FloatingWindow* pLastLevelFloat; + pLastLevelFloat = pSVData->maWinData.mpFirstFloat->ImplFindLastLevelFloat(); + pLastLevelFloat->EndPopupMode( FLOATWIN_POPUPMODEEND_CANCEL | FLOATWIN_POPUPMODEEND_CLOSEALL ); + } + if ( pSVData->maHelpData.mbExtHelpMode ) + Help::EndExtHelp(); + if ( pSVData->maHelpData.mpHelpWin ) + ImplDestroyHelpWindow( false ); + // AutoScrollMode + if ( pSVData->maWinData.mpAutoScrollWin ) + pSVData->maWinData.mpAutoScrollWin->EndAutoScroll(); + + if ( pSVData->maWinData.mpTrackWin ) + pSVData->maWinData.mpTrackWin->EndTracking( ENDTRACK_CANCEL | ENDTRACK_KEY ); + + if( ! bWasPopup ) + { + Window *pWin = pWindow->ImplGetWindow(); + // check whether close is allowed + if ( !pWin->IsEnabled() || !pWin->IsInputEnabled() || pWin->IsInModalMode() ) + Sound::Beep( SOUND_DISABLE, pWin ); + else + { + DelayedCloseEvent* pEv = new DelayedCloseEvent; + pEv->pWindow = pWin; + pWin->ImplAddDel( &pEv->aDelData ); + Application::PostUserEvent( Link( pEv, DelayedCloseEventLink ) ); + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleUserEvent( ImplSVEvent* pSVEvent ) +{ + if ( pSVEvent ) + { + if ( pSVEvent->mbCall && !pSVEvent->maDelData.IsDelete() ) + { + if ( pSVEvent->mpWindow ) + { + pSVEvent->mpWindow->ImplRemoveDel( &(pSVEvent->maDelData) ); + if ( pSVEvent->mpLink ) + pSVEvent->mpLink->Call( pSVEvent->mpData ); + else + pSVEvent->mpWindow->UserEvent( pSVEvent->mnEvent, pSVEvent->mpData ); + } + else + { + if ( pSVEvent->mpLink ) + pSVEvent->mpLink->Call( pSVEvent->mpData ); + else + GetpApp()->UserEvent( pSVEvent->mnEvent, pSVEvent->mpData ); + } + } + + delete pSVEvent->mpLink; + delete pSVEvent; + } +} + +// ======================================================================= + +static USHORT ImplGetMouseMoveMode( SalMouseEvent* pEvent ) +{ + USHORT nMode = 0; + if ( !pEvent->mnCode ) + nMode |= MOUSE_SIMPLEMOVE; + if ( (pEvent->mnCode & MOUSE_LEFT) && !(pEvent->mnCode & KEY_MOD1) ) + nMode |= MOUSE_DRAGMOVE; + if ( (pEvent->mnCode & MOUSE_LEFT) && (pEvent->mnCode & KEY_MOD1) ) + nMode |= MOUSE_DRAGCOPY; + return nMode; +} + +// ----------------------------------------------------------------------- + +static USHORT ImplGetMouseButtonMode( SalMouseEvent* pEvent ) +{ + USHORT nMode = 0; + if ( pEvent->mnButton == MOUSE_LEFT ) + nMode |= MOUSE_SIMPLECLICK; + if ( (pEvent->mnButton == MOUSE_LEFT) && !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT)) ) + nMode |= MOUSE_SELECT; + if ( (pEvent->mnButton == MOUSE_LEFT) && (pEvent->mnCode & KEY_MOD1) && + !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT | KEY_SHIFT)) ) + nMode |= MOUSE_MULTISELECT; + if ( (pEvent->mnButton == MOUSE_LEFT) && (pEvent->mnCode & KEY_SHIFT) && + !(pEvent->mnCode & (MOUSE_MIDDLE | MOUSE_RIGHT | KEY_MOD1)) ) + nMode |= MOUSE_RANGESELECT; + return nMode; +} + +// ----------------------------------------------------------------------- + +inline long ImplHandleSalMouseLeave( Window* pWindow, SalMouseEvent* pEvent ) +{ + return ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, TRUE, + pEvent->mnX, pEvent->mnY, + pEvent->mnTime, pEvent->mnCode, + ImplGetMouseMoveMode( pEvent ) ); +} + +// ----------------------------------------------------------------------- + +inline long ImplHandleSalMouseMove( Window* pWindow, SalMouseEvent* pEvent ) +{ + return ImplHandleMouseEvent( pWindow, EVENT_MOUSEMOVE, FALSE, + pEvent->mnX, pEvent->mnY, + pEvent->mnTime, pEvent->mnCode, + ImplGetMouseMoveMode( pEvent ) ); +} + +// ----------------------------------------------------------------------- + +inline long ImplHandleSalMouseButtonDown( Window* pWindow, SalMouseEvent* pEvent ) +{ + return ImplHandleMouseEvent( pWindow, EVENT_MOUSEBUTTONDOWN, FALSE, + pEvent->mnX, pEvent->mnY, + pEvent->mnTime, +#ifdef MACOSX + pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)), +#else + pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)), +#endif + ImplGetMouseButtonMode( pEvent ) ); +} + +// ----------------------------------------------------------------------- + +inline long ImplHandleSalMouseButtonUp( Window* pWindow, SalMouseEvent* pEvent ) +{ + return ImplHandleMouseEvent( pWindow, EVENT_MOUSEBUTTONUP, FALSE, + pEvent->mnX, pEvent->mnY, + pEvent->mnTime, +#ifdef MACOSX + pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3)), +#else + pEvent->mnButton | (pEvent->mnCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2)), +#endif + ImplGetMouseButtonMode( pEvent ) ); +} + +// ----------------------------------------------------------------------- + +static long ImplHandleSalMouseActivate( Window* /*pWindow*/, SalMouseActivateEvent* /*pEvent*/ ) +{ + return FALSE; +} + +// ----------------------------------------------------------------------- + +static long ImplHandleMenuEvent( Window* pWindow, SalMenuEvent* pEvent, USHORT nEvent ) +{ + // Find SystemWindow and its Menubar and let it dispatch the command + long nRet = 0; + Window *pWin = pWindow->ImplGetWindowImpl()->mpFirstChild; + while ( pWin ) + { + if ( pWin->ImplGetWindowImpl()->mbSysWin ) + break; + pWin = pWin->ImplGetWindowImpl()->mpNext; + } + if( pWin ) + { + MenuBar *pMenuBar = ((SystemWindow*) pWin)->GetMenuBar(); + if( pMenuBar ) + { + switch( nEvent ) + { + case SALEVENT_MENUACTIVATE: + nRet = pMenuBar->HandleMenuActivateEvent( (Menu*) pEvent->mpMenu ) ? 1 : 0; + break; + case SALEVENT_MENUDEACTIVATE: + nRet = pMenuBar->HandleMenuDeActivateEvent( (Menu*) pEvent->mpMenu ) ? 1 : 0; + break; + case SALEVENT_MENUHIGHLIGHT: + nRet = pMenuBar->HandleMenuHighlightEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0; + break; + case SALEVENT_MENUBUTTONCOMMAND: + nRet = pMenuBar->HandleMenuButtonEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0; + break; + case SALEVENT_MENUCOMMAND: + nRet = pMenuBar->HandleMenuCommandEvent( (Menu*) pEvent->mpMenu, pEvent->mnId ) ? 1 : 0; + break; + default: + break; + } + } + } + return nRet; +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSalKeyMod( Window* pWindow, SalKeyModEvent* pEvent ) +{ + ImplSVData* pSVData = ImplGetSVData(); + Window* pTrackWin = pSVData->maWinData.mpTrackWin; + if ( pTrackWin ) + pWindow = pTrackWin; +#ifdef MACOSX + USHORT nOldCode = pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3); +#else + USHORT nOldCode = pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & (KEY_SHIFT | KEY_MOD1 | KEY_MOD2); +#endif + USHORT nNewCode = pEvent->mnCode; + if ( nOldCode != nNewCode ) + { +#ifdef MACOSX + nNewCode |= pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & ~(KEY_SHIFT | KEY_MOD1 | KEY_MOD2 | KEY_MOD3); +#else + nNewCode |= pWindow->ImplGetWindowImpl()->mpFrameData->mnMouseCode & ~(KEY_SHIFT | KEY_MOD1 | KEY_MOD2); +#endif + pWindow->ImplGetWindowImpl()->mpFrameWindow->ImplCallMouseMove( nNewCode, TRUE ); + } + + // #105224# send commandevent to allow special treatment of Ctrl-LeftShift/Ctrl-RightShift etc. + + // find window + Window* pChild = ImplGetKeyInputWindow( pWindow ); + if ( !pChild ) + return; + + // send modkey events only if useful data is available + if( pEvent->mnModKeyCode != 0 ) + { + CommandModKeyData data( pEvent->mnModKeyCode ); + ImplCallCommand( pChild, COMMAND_MODKEYCHANGE, &data ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleInputLanguageChange( Window* pWindow ) +{ + // find window + Window* pChild = ImplGetKeyInputWindow( pWindow ); + if ( !pChild ) + return; + + ImplCallCommand( pChild, COMMAND_INPUTLANGUAGECHANGE ); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSalSettings( Window* pWindow, USHORT nEvent ) +{ + // Application Notification werden nur fuer das erste Window ausgeloest + ImplSVData* pSVData = ImplGetSVData(); + if ( pWindow != pSVData->maWinData.mpFirstFrame ) + return; + + Application* pApp = GetpApp(); + if ( !pApp ) + return; + + if ( nEvent == SALEVENT_SETTINGSCHANGED ) + { + AllSettings aSettings = pApp->GetSettings(); + pApp->MergeSystemSettings( aSettings ); + pApp->SystemSettingsChanging( aSettings, pWindow ); + pApp->SetSettings( aSettings ); + } + else + { + USHORT nType; + switch ( nEvent ) + { + case SALEVENT_VOLUMECHANGED: + nType = 0; + break; + case SALEVENT_PRINTERCHANGED: + ImplDeletePrnQueueList(); + nType = DATACHANGED_PRINTER; + break; + case SALEVENT_DISPLAYCHANGED: + nType = DATACHANGED_DISPLAY; + break; + case SALEVENT_FONTCHANGED: + OutputDevice::ImplUpdateAllFontData( TRUE ); + nType = DATACHANGED_FONTS; + break; + case SALEVENT_DATETIMECHANGED: + nType = DATACHANGED_DATETIME; + break; + case SALEVENT_KEYBOARDCHANGED: + nType = 0; + break; + default: + nType = 0; + break; + } + + if ( nType ) + { + DataChangedEvent aDCEvt( nType ); + pApp->DataChanged( aDCEvt ); + pApp->NotifyAllWindows( aDCEvt ); + } + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSalExtTextInputPos( Window* pWindow, SalExtTextInputPosEvent* pEvt ) +{ + Rectangle aCursorRect; + ImplHandleExtTextInputPos( pWindow, aCursorRect, pEvt->mnExtWidth, &pEvt->mbVertical ); + if ( aCursorRect.IsEmpty() ) + { + pEvt->mnX = -1; + pEvt->mnY = -1; + pEvt->mnWidth = -1; + pEvt->mnHeight = -1; + } + else + { + pEvt->mnX = aCursorRect.Left(); + pEvt->mnY = aCursorRect.Top(); + pEvt->mnWidth = aCursorRect.GetWidth(); + pEvt->mnHeight = aCursorRect.GetHeight(); + } +} + +// ----------------------------------------------------------------------- + +static long ImplHandleShowDialog( Window* pWindow, int nDialogId ) +{ + if( ! pWindow ) + return FALSE; + + if( pWindow->GetType() == WINDOW_BORDERWINDOW ) + { + Window* pWrkWin = pWindow->GetWindow( WINDOW_CLIENT ); + if( pWrkWin ) + pWindow = pWrkWin; + } + CommandDialogData aCmdData( nDialogId ); + return ImplCallCommand( pWindow, COMMAND_SHOWDIALOG, &aCmdData ); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSurroundingTextRequest( Window *pWindow, + XubString& rText, + Selection &rSelRange ) +{ + Window* pChild = ImplGetKeyInputWindow( pWindow ); + + if ( !pChild ) + { + rText = XubString::EmptyString(); + rSelRange.setMin( 0 ); + rSelRange.setMax( 0 ); + } + else + { + + rText = pChild->GetSurroundingText(); + Selection aSel = pChild->GetSurroundingTextSelection(); + rSelRange.setMin( aSel.Min() ); + rSelRange.setMax( aSel.Max() ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSalSurroundingTextRequest( Window *pWindow, + SalSurroundingTextRequestEvent *pEvt ) +{ + Selection aSelRange; + ImplHandleSurroundingTextRequest( pWindow, pEvt->maText, aSelRange ); + + aSelRange.Justify(); + + if( aSelRange.Min() < 0 ) + pEvt->mnStart = 0; + else if( aSelRange.Min() > pEvt->maText.Len() ) + pEvt->mnStart = pEvt->maText.Len(); + else + pEvt->mnStart = aSelRange.Min(); + + if( aSelRange.Max() < 0 ) + pEvt->mnStart = 0; + else if( aSelRange.Max() > pEvt->maText.Len() ) + pEvt->mnEnd = pEvt->maText.Len(); + else + pEvt->mnEnd = aSelRange.Max(); +} + +// ----------------------------------------------------------------------- + +static void ImplHandleSurroundingTextSelectionChange( Window *pWindow, + ULONG nStart, + ULONG nEnd ) +{ + Window* pChild = ImplGetKeyInputWindow( pWindow ); + if( pChild ) + { + CommandSelectionChangeData data( nStart, nEnd ); + ImplCallCommand( pChild, COMMAND_SELECTIONCHANGE, &data ); + } +} + +// ----------------------------------------------------------------------- + +static void ImplHandleStartReconversion( Window *pWindow ) +{ + Window* pChild = ImplGetKeyInputWindow( pWindow ); + if( pChild ) + ImplCallCommand( pChild, COMMAND_PREPARERECONVERSION ); +} + +// ----------------------------------------------------------------------- + +long ImplWindowFrameProc( Window* pWindow, SalFrame* /*pFrame*/, + USHORT nEvent, const void* pEvent ) +{ + DBG_TESTSOLARMUTEX(); + + long nRet = 0; + + // #119709# for some unknown reason it is possible to receive events (in this case key events) + // although the corresponding VCL window must have been destroyed already + // at least ImplGetWindowImpl() was NULL in these cases, so check this here + if( pWindow->ImplGetWindowImpl() == NULL ) + return 0; + + switch ( nEvent ) + { + case SALEVENT_MOUSEMOVE: + nRet = ImplHandleSalMouseMove( pWindow, (SalMouseEvent*)pEvent ); + break; + case SALEVENT_EXTERNALMOUSEMOVE: + { + MouseEvent* pMouseEvt = (MouseEvent*) pEvent; + SalMouseEvent aSalMouseEvent; + + aSalMouseEvent.mnTime = Time::GetSystemTicks(); + aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X(); + aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y(); + aSalMouseEvent.mnButton = 0; + aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier(); + + nRet = ImplHandleSalMouseMove( pWindow, &aSalMouseEvent ); + } + break; + case SALEVENT_MOUSELEAVE: + nRet = ImplHandleSalMouseLeave( pWindow, (SalMouseEvent*)pEvent ); + break; + case SALEVENT_MOUSEBUTTONDOWN: + nRet = ImplHandleSalMouseButtonDown( pWindow, (SalMouseEvent*)pEvent ); + break; + case SALEVENT_EXTERNALMOUSEBUTTONDOWN: + { + MouseEvent* pMouseEvt = (MouseEvent*) pEvent; + SalMouseEvent aSalMouseEvent; + + aSalMouseEvent.mnTime = Time::GetSystemTicks(); + aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X(); + aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y(); + aSalMouseEvent.mnButton = pMouseEvt->GetButtons(); + aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier(); + + nRet = ImplHandleSalMouseButtonDown( pWindow, &aSalMouseEvent ); + } + break; + case SALEVENT_MOUSEBUTTONUP: + nRet = ImplHandleSalMouseButtonUp( pWindow, (SalMouseEvent*)pEvent ); + break; + case SALEVENT_EXTERNALMOUSEBUTTONUP: + { + MouseEvent* pMouseEvt = (MouseEvent*) pEvent; + SalMouseEvent aSalMouseEvent; + + aSalMouseEvent.mnTime = Time::GetSystemTicks(); + aSalMouseEvent.mnX = pMouseEvt->GetPosPixel().X(); + aSalMouseEvent.mnY = pMouseEvt->GetPosPixel().Y(); + aSalMouseEvent.mnButton = pMouseEvt->GetButtons(); + aSalMouseEvent.mnCode = pMouseEvt->GetButtons() | pMouseEvt->GetModifier(); + + nRet = ImplHandleSalMouseButtonUp( pWindow, &aSalMouseEvent ); + } + break; + case SALEVENT_MOUSEACTIVATE: + nRet = ImplHandleSalMouseActivate( pWindow, (SalMouseActivateEvent*)pEvent ); + break; + case SALEVENT_KEYINPUT: + { + SalKeyEvent* pKeyEvt = (SalKeyEvent*)pEvent; + nRet = ImplHandleKey( pWindow, EVENT_KEYINPUT, + pKeyEvt->mnCode, pKeyEvt->mnCharCode, pKeyEvt->mnRepeat, TRUE ); + } + break; + case SALEVENT_EXTERNALKEYINPUT: + { + KeyEvent* pKeyEvt = (KeyEvent*) pEvent; + nRet = ImplHandleKey( pWindow, EVENT_KEYINPUT, + pKeyEvt->GetKeyCode().GetFullCode(), pKeyEvt->GetCharCode(), pKeyEvt->GetRepeat(), FALSE ); + } + break; + case SALEVENT_KEYUP: + { + SalKeyEvent* pKeyEvt = (SalKeyEvent*)pEvent; + nRet = ImplHandleKey( pWindow, EVENT_KEYUP, + pKeyEvt->mnCode, pKeyEvt->mnCharCode, pKeyEvt->mnRepeat, TRUE ); + } + break; + case SALEVENT_EXTERNALKEYUP: + { + KeyEvent* pKeyEvt = (KeyEvent*) pEvent; + nRet = ImplHandleKey( pWindow, EVENT_KEYUP, + pKeyEvt->GetKeyCode().GetFullCode(), pKeyEvt->GetCharCode(), pKeyEvt->GetRepeat(), FALSE ); + } + break; + case SALEVENT_KEYMODCHANGE: + ImplHandleSalKeyMod( pWindow, (SalKeyModEvent*)pEvent ); + break; + + case SALEVENT_INPUTLANGUAGECHANGE: + ImplHandleInputLanguageChange( pWindow ); + break; + + case SALEVENT_MENUACTIVATE: + case SALEVENT_MENUDEACTIVATE: + case SALEVENT_MENUHIGHLIGHT: + case SALEVENT_MENUCOMMAND: + case SALEVENT_MENUBUTTONCOMMAND: + nRet = ImplHandleMenuEvent( pWindow, (SalMenuEvent*)pEvent, nEvent ); + break; + + case SALEVENT_WHEELMOUSE: + nRet = ImplHandleWheelEvent( pWindow, *(const SalWheelMouseEvent*)pEvent); + break; + + case SALEVENT_PAINT: + { + SalPaintEvent* pPaintEvt = (SalPaintEvent*)pEvent; + + if( Application::GetSettings().GetLayoutRTL() ) + { + // --- RTL --- (mirror paint rect) + SalFrame* pSalFrame = pWindow->ImplGetWindowImpl()->mpFrame; + pPaintEvt->mnBoundX = pSalFrame->maGeometry.nWidth-pPaintEvt->mnBoundWidth-pPaintEvt->mnBoundX; + } + + Rectangle aBoundRect( Point( pPaintEvt->mnBoundX, pPaintEvt->mnBoundY ), + Size( pPaintEvt->mnBoundWidth, pPaintEvt->mnBoundHeight ) ); + ImplHandlePaint( pWindow, aBoundRect, pPaintEvt->mbImmediateUpdate ); + } + break; + + case SALEVENT_MOVE: + ImplHandleMove( pWindow ); + break; + + case SALEVENT_RESIZE: + { + long nNewWidth; + long nNewHeight; + pWindow->ImplGetWindowImpl()->mpFrame->GetClientSize( nNewWidth, nNewHeight ); + ImplHandleResize( pWindow, nNewWidth, nNewHeight ); + } + break; + + case SALEVENT_MOVERESIZE: + { + SalFrameGeometry g = pWindow->ImplGetWindowImpl()->mpFrame->GetGeometry(); + ImplHandleMoveResize( pWindow, g.nWidth, g.nHeight ); + } + break; + + case SALEVENT_CLOSEPOPUPS: + { + KillOwnPopups( pWindow ); + } + break; + + case SALEVENT_GETFOCUS: + ImplHandleGetFocus( pWindow ); + break; + case SALEVENT_LOSEFOCUS: + ImplHandleLoseFocus( pWindow ); + break; + + case SALEVENT_CLOSE: + ImplHandleClose( pWindow ); + break; + + case SALEVENT_SHUTDOWN: + { + static bool bInQueryExit = false; + if( !bInQueryExit ) + { + bInQueryExit = true; + if ( GetpApp()->QueryExit() ) + { + // Message-Schleife beenden + Application::Quit(); + return FALSE; + } + else + { + bInQueryExit = false; + return TRUE; + } + } + return FALSE; + } + + case SALEVENT_SETTINGSCHANGED: + case SALEVENT_VOLUMECHANGED: + case SALEVENT_PRINTERCHANGED: + case SALEVENT_DISPLAYCHANGED: + case SALEVENT_FONTCHANGED: + case SALEVENT_DATETIMECHANGED: + case SALEVENT_KEYBOARDCHANGED: + ImplHandleSalSettings( pWindow, nEvent ); + break; + + case SALEVENT_USEREVENT: + ImplHandleUserEvent( (ImplSVEvent*)pEvent ); + break; + + case SALEVENT_EXTTEXTINPUT: + { + SalExtTextInputEvent* pEvt = (SalExtTextInputEvent*)pEvent; + nRet = ImplHandleExtTextInput( pWindow, + pEvt->maText, pEvt->mpTextAttr, + pEvt->mnCursorPos, pEvt->mnCursorFlags ); + } + break; + case SALEVENT_ENDEXTTEXTINPUT: + nRet = ImplHandleEndExtTextInput( pWindow ); + break; + case SALEVENT_EXTTEXTINPUTPOS: + ImplHandleSalExtTextInputPos( pWindow, (SalExtTextInputPosEvent*)pEvent ); + break; + case SALEVENT_INPUTCONTEXTCHANGE: + nRet = ImplHandleInputContextChange( pWindow, ((SalInputContextChangeEvent*)pEvent)->meLanguage ); + break; + case SALEVENT_SHOWDIALOG: + { + int nDialogID = static_cast<int>(reinterpret_cast<sal_IntPtr>(pEvent)); + nRet = ImplHandleShowDialog( pWindow, nDialogID ); + } + break; + case SALEVENT_SURROUNDINGTEXTREQUEST: + ImplHandleSalSurroundingTextRequest( pWindow, (SalSurroundingTextRequestEvent*)pEvent ); + break; + case SALEVENT_SURROUNDINGTEXTSELECTIONCHANGE: + { + SalSurroundingTextSelectionChangeEvent* pEvt + = (SalSurroundingTextSelectionChangeEvent*)pEvent; + ImplHandleSurroundingTextSelectionChange( pWindow, + pEvt->mnStart, + pEvt->mnEnd ); + } + case SALEVENT_STARTRECONVERSION: + ImplHandleStartReconversion( pWindow ); + break; +#ifdef DBG_UTIL + default: + DBG_ERROR1( "ImplWindowFrameProc(): unknown event (%lu)", (ULONG)nEvent ); + break; +#endif + } + + return nRet; +} diff --git a/vcl/source/window/wpropset.cxx b/vcl/source/window/wpropset.cxx new file mode 100644 index 000000000000..4aaa3f987b77 --- /dev/null +++ b/vcl/source/window/wpropset.cxx @@ -0,0 +1,346 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/wpropset.hxx" +#include "vcl/window.hxx" +#include "vcl/vclevent.hxx" +#include "vcl/svdata.hxx" + +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/beans/PropertyAttribute.hpp" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/beans/XPropertyContainer.hpp" +#include "com/sun/star/beans/XPropertyAccess.hpp" + +#include "cppuhelper/basemutex.hxx" +#include "cppuhelper/compbase1.hxx" + +#include <map> + +using namespace vcl; +using namespace com::sun::star; + +/* + +TODO: +- release solarmutex during outside UNO calls +- in ChildEventListener protect against reentry by using PostUserEvent + +*/ + +class vcl::WindowPropertySetListener : + public cppu::BaseMutex, + public cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >, + private boost::noncopyable +{ + WindowPropertySet* mpParent; + bool mbSuspended; +public: + WindowPropertySetListener( WindowPropertySet* pParent ) + : cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >( m_aMutex ) + , mpParent( pParent ) + , mbSuspended( false ) + {} + + virtual ~WindowPropertySetListener() + { + } + + using cppu::WeakComponentImplHelperBase::disposing; + virtual void SAL_CALL disposing( const lang::EventObject& ) throw() + { + } + + virtual void SAL_CALL propertyChange( const beans::PropertyChangeEvent& i_rEvent ) throw() + { + if( ! mbSuspended ) + mpParent->propertyChange( i_rEvent ); + } + + void suspend( bool i_bSuspended ) + { + mbSuspended = i_bSuspended; + } +}; + +class vcl::WindowPropertySetData +{ +public: + + struct PropertyMapEntry + { + Window* mpWindow; + boost::shared_ptr<WindowArranger> mpLayout; + uno::Sequence< beans::PropertyValue > maSavedValues; + + PropertyMapEntry( Window* i_pWindow = NULL, + const boost::shared_ptr<WindowArranger>& i_pLayout = boost::shared_ptr<WindowArranger>() ) + : mpWindow( i_pWindow ) + , mpLayout( i_pLayout ) + {} + + uno::Sequence< beans::PropertyValue > getProperties() const + { + if( mpWindow ) + return mpWindow->getProperties(); + else if( mpLayout.get() ) + return mpLayout->getProperties(); + return uno::Sequence< beans::PropertyValue >(); + } + + void setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) const + { + if( mpWindow ) + mpWindow->setProperties( i_rProps ); + else if( mpLayout.get() ) + mpLayout->setProperties( i_rProps ); + } + }; + + Window* mpTopWindow; + bool mbOwner; + std::map< rtl::OUString, PropertyMapEntry > maProperties; + uno::Reference< beans::XPropertySet > mxPropSet; + uno::Reference< beans::XPropertyAccess > mxPropSetAccess; + uno::Reference< beans::XPropertyChangeListener > mxListener; + vcl::WindowPropertySetListener* mpListener; + + WindowPropertySetData() + : mpTopWindow( NULL ) + , mbOwner( false ) + , mpListener( NULL ) + {} + + ~WindowPropertySetData() + { + // release layouters, possibly interface properties before destroying + // the involved parent to be on the safe side + maProperties.clear(); + if( mbOwner ) + delete mpTopWindow; + } +}; + +static rtl::OUString getIdentifiedPropertyName( const rtl::OUString& i_rIdentifier, const rtl::OUString& i_rName ) +{ + rtl::OUStringBuffer aBuf( i_rIdentifier.getLength() + 1 + i_rName.getLength() ); + aBuf.append( i_rIdentifier ); + aBuf.append( sal_Unicode( '#' ) ); + aBuf.append( i_rName ); + return aBuf.makeStringAndClear(); +} + +static void spliceIdentifiedPropertyName( const rtl::OUString& i_rIdentifiedPropName, + rtl::OUString& o_rIdentifier, + rtl::OUString& o_rPropName ) +{ + sal_Int32 nIndex = 0; + o_rIdentifier = i_rIdentifiedPropName.getToken( 0, sal_Unicode( '#' ), nIndex ); + if( nIndex != -1 ) + o_rPropName = i_rIdentifiedPropName.copy( nIndex ); + else + o_rPropName = rtl::OUString(); +} + +WindowPropertySet::WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ) +: mpImpl( new vcl::WindowPropertySetData ) +{ + mpImpl->mpTopWindow = i_pTopWindow; + mpImpl->mbOwner = i_bTakeOwnership; + + mpImpl->mpTopWindow->AddChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + mpImpl->mxPropSet = uno::Reference< beans::XPropertySet >( + ImplGetSVData()->maAppData.mxMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.PropertyBag" ) ) ), + uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not create instance of com.sun.star.beans.PropertyBag" ); + mpImpl->mxPropSetAccess = uno::Reference< beans::XPropertyAccess >( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not query XPropertyAccess interface" ); + if( ! mpImpl->mxPropSetAccess.is() ) + mpImpl->mxPropSet.clear(); + + addWindowToSet( i_pTopWindow ); + + setupProperties(); + + if( mpImpl->mxPropSet.is() ) + { + mpImpl->mxListener.set( mpImpl->mpListener = new WindowPropertySetListener( this ) ); + } +} + +WindowPropertySet::~WindowPropertySet() +{ + mpImpl->mpTopWindow->RemoveChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + delete mpImpl; + mpImpl = NULL; +} + +uno::Reference< beans::XPropertySet > WindowPropertySet::getPropertySet() const +{ + return mpImpl->mxPropSet; +} + +void WindowPropertySet::addLayoutToSet( const boost::shared_ptr< WindowArranger >& i_pLayout ) +{ + if( i_pLayout.get() ) + { + if( i_pLayout->getIdentifier().getLength() ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pLayout->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted layout has duplicate name" ); + rEntry.mpWindow = NULL; + rEntry.mpLayout = i_pLayout; + rEntry.maSavedValues = i_pLayout->getProperties(); + } + // insert child layouts + size_t nChildren = i_pLayout->countElements(); + for( size_t i = 0; i < nChildren; i++ ) + addLayoutToSet( i_pLayout->getChild( i ) ); + } +} + +void WindowPropertySet::addWindowToSet( Window* i_pWindow ) +{ + if( i_pWindow->getIdentifier().getLength() ) // no name, no properties + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pWindow->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted window has duplicate name" ); + rEntry.mpWindow = i_pWindow; + rEntry.mpLayout.reset(); + rEntry.maSavedValues = i_pWindow->getProperties(); + } + addLayoutToSet( i_pWindow->getLayout() ); + + Window* pWin = i_pWindow->GetWindow( WINDOW_FIRSTCHILD ); + while( pWin ) + { + addWindowToSet( pWin ); + pWin = pWin->GetWindow( WINDOW_NEXT ); + } +} + +void WindowPropertySet::setupProperties() +{ + uno::Reference< beans::XPropertyContainer > xCont( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( xCont.is(), "could not get XPropertyContainer interface" ); + if( ! xCont.is() ) + return; + + for( std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.begin(); it != mpImpl->maProperties.end(); ++it ) + { + uno::Sequence< beans::PropertyValue > aOutsideValues( it->second.maSavedValues ); + beans::PropertyValue* pVal = aOutsideValues.getArray(); + for( sal_Int32 i = 0; i < aOutsideValues.getLength(); i++ ) + { + pVal[i].Name = getIdentifiedPropertyName( it->first, pVal[i].Name ); + xCont->addProperty( pVal[i].Name, + beans::PropertyAttribute::BOUND | beans:: PropertyAttribute::CONSTRAINED, + pVal[i].Value + ); + } + } +} + +void WindowPropertySet::propertyChange( const beans::PropertyChangeEvent& i_rEvent ) +{ + rtl::OUString aIdentifier, aProperty; + spliceIdentifiedPropertyName( i_rEvent.PropertyName, aIdentifier, aProperty ); + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it = + mpImpl->maProperties.find( aIdentifier ); + if( it != mpImpl->maProperties.end() ) + { + uno::Sequence< beans::PropertyValue > aSet( 1 ); + aSet[0].Name = aProperty; + aSet[0].Value = i_rEvent.NewValue; + it->second.setProperties( aSet ); + } +} + +IMPL_LINK( vcl::WindowPropertySet, ChildEventListener, VclWindowEvent*, pEvent ) +{ + // find window in our properties + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.find( pEvent->GetWindow()->getIdentifier() ); + if( it != mpImpl->maProperties.end() ) // this is valid, some unnamed child may have sent an event + { + ULONG nId = pEvent->GetId(); + // check if anything interesting happened + if( + // general windowy things + nId == VCLEVENT_WINDOW_SHOW || + nId == VCLEVENT_WINDOW_HIDE || + nId == VCLEVENT_WINDOW_ENABLED || + nId == VCLEVENT_WINDOW_DISABLED || + // button thingies + nId == VCLEVENT_BUTTON_CLICK || + nId == VCLEVENT_PUSHBUTTON_TOGGLE || + nId == VCLEVENT_RADIOBUTTON_TOGGLE || + nId == VCLEVENT_CHECKBOX_TOGGLE || + // listbox + nId == VCLEVENT_LISTBOX_SELECT || + // edit + nId == VCLEVENT_EDIT_MODIFY + ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = it->second; + // collect changes + uno::Sequence< beans::PropertyValue > aNewProps( rEntry.getProperties() ); + uno::Sequence< beans::PropertyValue > aNewPropsOut( aNewProps ); + + // translate to identified properties + beans::PropertyValue* pValues = aNewPropsOut.getArray(); + for( sal_Int32 i = 0; i < aNewPropsOut.getLength(); i++ ) + pValues[i].Name = getIdentifiedPropertyName( it->first, pValues[i].Name ); + + // broadcast changes + bool bWasVeto = false; + mpImpl->mpListener->suspend( true ); + try + { + mpImpl->mxPropSetAccess->setPropertyValues( aNewPropsOut ); + } + catch( beans::PropertyVetoException& ) + { + bWasVeto = true; + } + mpImpl->mpListener->suspend( false ); + + if( ! bWasVeto ) // changes accepted ? + rEntry.maSavedValues = rEntry.getProperties(); + else // no, reset + rEntry.setProperties( rEntry.maSavedValues ); + } + } + + return 0; +} diff --git a/vcl/source/window/wrkwin.cxx b/vcl/source/window/wrkwin.cxx new file mode 100644 index 000000000000..8fb2f2f8346a --- /dev/null +++ b/vcl/source/window/wrkwin.cxx @@ -0,0 +1,323 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#ifndef _SV_SVSYS_HXX +#include <svsys.h> +#endif +#include <vcl/salframe.hxx> +#include <tools/debug.hxx> + +#ifndef _SV_RC_H +#include <tools/rc.h> +#endif +#include <vcl/svdata.hxx> +#include <vcl/svapp.hxx> +#include <vcl/brdwin.hxx> +#include <vcl/window.h> +#include <vcl/wrkwin.hxx> +#include <vcl/sysdata.hxx> + +// ======================================================================= + +#define WORKWIN_WINDOWSTATE_FULLSCREEN ((ULONG)0x00010000) +#define WORKWIN_WINDOWSTATE_ALL ((ULONG)0x00FF0000) + +// ======================================================================= + +void WorkWindow::ImplInitWorkWindowData() +{ + mnIcon = 0; // Should be removed in the next top level update - now in SystemWindow + + mnPresentationFlags = 0; + mbPresentationMode = FALSE; + mbPresentationVisible = FALSE; + mbPresentationFull = FALSE; + mbFullScreenMode = FALSE; +} + +// ----------------------------------------------------------------------- + +void WorkWindow::ImplInit( Window* pParent, WinBits nStyle, SystemParentData* pSystemParentData ) +{ + USHORT nFrameStyle = BORDERWINDOW_STYLE_FRAME; + if ( nStyle & WB_APP ) + nFrameStyle |= BORDERWINDOW_STYLE_APP; + + ImplBorderWindow* pBorderWin = new ImplBorderWindow( pParent, pSystemParentData, nStyle, nFrameStyle ); + Window::ImplInit( pBorderWin, nStyle & (WB_3DLOOK | WB_CLIPCHILDREN | WB_DIALOGCONTROL | WB_SYSTEMFLOATWIN), NULL ); + pBorderWin->mpWindowImpl->mpClientWindow = this; + pBorderWin->GetBorder( mpWindowImpl->mnLeftBorder, mpWindowImpl->mnTopBorder, mpWindowImpl->mnRightBorder, mpWindowImpl->mnBottomBorder ); + mpWindowImpl->mpBorderWindow = pBorderWin; +// mpWindowImpl->mpRealParent = pParent; // !!! Muesste eigentlich gesetzt werden, aber wegen Fehlern mit dem MenuBar erstmal nicht gesetzt !!! + + if ( nStyle & WB_APP ) + { + ImplSVData* pSVData = ImplGetSVData(); + DBG_ASSERT( !pSVData->maWinData.mpAppWin, "WorkWindow::WorkWindow(): More than one window with style WB_APP" ); + pSVData->maWinData.mpAppWin = this; + } + + SetActivateMode( ACTIVATE_MODE_GRABFOCUS ); +} + +// ----------------------------------------------------------------------- + +void WorkWindow::ImplInit( Window* pParent, WinBits nStyle, const ::com::sun::star::uno::Any& aSystemWorkWindowToken ) +{ + if( aSystemWorkWindowToken.hasValue() ) + { + ::com::sun::star::uno::Sequence< sal_Int8 > aSeq; + aSystemWorkWindowToken >>= aSeq; + SystemParentData* pData = (SystemParentData*)aSeq.getArray(); + DBG_ASSERT( aSeq.getLength() == sizeof( SystemParentData ) && pData->nSize == sizeof( SystemParentData ), "WorkWindow::WorkWindow( Window*, const Any&, WinBits ) called with invalid Any" ); + // init with style 0 as does WorkWindow::WorkWindow( SystemParentData* ); + ImplInit( pParent, 0, pData ); + } + else + ImplInit( pParent, nStyle, NULL ); +} + +// ----------------------------------------------------------------------- + +WorkWindow::WorkWindow( WindowType nType ) : + SystemWindow( nType ) +{ + ImplInitWorkWindowData(); +} + +// ----------------------------------------------------------------------- + +WorkWindow::WorkWindow( Window* pParent, WinBits nStyle ) : + SystemWindow( WINDOW_WORKWINDOW ) +{ + ImplInitWorkWindowData(); + ImplInit( pParent, nStyle, NULL ); +} + +// ----------------------------------------------------------------------- + +WorkWindow::WorkWindow( Window* pParent, const ResId& rResId ) : + SystemWindow( WINDOW_WORKWINDOW ) +{ + ImplInitWorkWindowData(); + rResId.SetRT( RSC_WORKWIN ); + WinBits nStyle = ImplInitRes( rResId ); + ImplInit( pParent, nStyle ); + ImplLoadRes( rResId ); +} + +// ----------------------------------------------------------------------- + +WorkWindow::WorkWindow( Window* pParent, const ::com::sun::star::uno::Any& aSystemWorkWindowToken, WinBits nStyle ) : + SystemWindow( WINDOW_WORKWINDOW ) +{ + ImplInitWorkWindowData(); + mbSysChild = TRUE; + ImplInit( pParent, nStyle, aSystemWorkWindowToken ); +} + +// ----------------------------------------------------------------------- + +WorkWindow::WorkWindow( SystemParentData* pParent ) : + SystemWindow( WINDOW_WORKWINDOW ) +{ + ImplInitWorkWindowData(); + mbSysChild = TRUE; + ImplInit( NULL, 0, pParent ); +} + +// ----------------------------------------------------------------------- + +void WorkWindow::ImplLoadRes( const ResId& rResId ) +{ + SystemWindow::ImplLoadRes( rResId ); + + ReadLongRes(); + if ( !(rResId.GetWinBits() & WB_HIDE) && (RSC_WORKWIN == rResId.GetRT()) ) + Show(); +} + +// ----------------------------------------------------------------------- + +WorkWindow::~WorkWindow() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( pSVData->maWinData.mpAppWin == this ) + { + pSVData->maWinData.mpAppWin = NULL; + Application::Quit(); + } +} + +// ----------------------------------------------------------------------- + +void WorkWindow::ShowFullScreenMode( BOOL bFullScreenMode, sal_Int32 nDisplay ) +{ + if ( !mbFullScreenMode == !bFullScreenMode ) + return; + + if( (nDisplay < 0) + || (nDisplay >= static_cast<sal_Int32>(Application::GetScreenCount()) ) ) + { + nDisplay = GetScreenNumber(); + } + + mbFullScreenMode = bFullScreenMode != 0; + if ( !mbSysChild ) + { + mpWindowImpl->mpFrameWindow->mpWindowImpl->mbWaitSystemResize = TRUE; + ImplGetFrame()->ShowFullScreen( bFullScreenMode, nDisplay ); + } +} + +// ----------------------------------------------------------------------- + +void WorkWindow::StartPresentationMode( BOOL bPresentation, USHORT nFlags, sal_Int32 nDisplay ) +{ + if ( !bPresentation == !mbPresentationMode ) + return; + + if ( bPresentation ) + { + mbPresentationMode = TRUE; + mbPresentationVisible = IsVisible(); + mbPresentationFull = mbFullScreenMode; + mnPresentationFlags = nFlags; + + if ( !(mnPresentationFlags & PRESENTATION_NOFULLSCREEN) ) + ShowFullScreenMode( TRUE, nDisplay ); + if ( !mbSysChild ) + { + if ( mnPresentationFlags & PRESENTATION_HIDEALLAPPS ) + mpWindowImpl->mpFrame->SetAlwaysOnTop( TRUE ); + if ( !(mnPresentationFlags & PRESENTATION_NOAUTOSHOW) ) + ToTop(); + mpWindowImpl->mpFrame->StartPresentation( TRUE ); + } + + if ( !(mnPresentationFlags & PRESENTATION_NOAUTOSHOW) ) + Show(); + } + else + { + Show( mbPresentationVisible ); + if ( !mbSysChild ) + { + mpWindowImpl->mpFrame->StartPresentation( FALSE ); + if ( mnPresentationFlags & PRESENTATION_HIDEALLAPPS ) + mpWindowImpl->mpFrame->SetAlwaysOnTop( FALSE ); + } + ShowFullScreenMode( mbPresentationFull, nDisplay ); + + mbPresentationMode = FALSE; + mbPresentationVisible = FALSE; + mbPresentationFull = FALSE; + mnPresentationFlags = 0; + } +} + +// ----------------------------------------------------------------------- + +BOOL WorkWindow::IsMinimized() const +{ + //return mpWindowImpl->mpFrameData->mbMinimized; + SalFrameState aState; + mpWindowImpl->mpFrame->GetWindowState(&aState); + return (( aState.mnState & SAL_FRAMESTATE_MINIMIZED ) != 0); +} + +// ----------------------------------------------------------------------- + +BOOL WorkWindow::SetPluginParent( SystemParentData* pParent ) +{ + DBG_ASSERT( ! mbPresentationMode && ! mbFullScreenMode, "SetPluginParent in fullscreen or presentation mode !" ); + + bool bWasDnd = Window::ImplStopDnd(); + + BOOL bShown = IsVisible(); + Show( FALSE ); + BOOL bRet = mpWindowImpl->mpFrame->SetPluginParent( pParent ); + Show( bShown ); + + if( bWasDnd ) + Window::ImplStartDnd(); + + return bRet; +} + +void WorkWindow::ImplSetFrameState( ULONG aFrameState ) +{ + SalFrameState aState; + aState.mnMask = SAL_FRAMESTATE_MASK_STATE; + aState.mnState = aFrameState; + mpWindowImpl->mpFrame->SetWindowState( &aState ); +} + + +void WorkWindow::Minimize() +{ + ImplSetFrameState( SAL_FRAMESTATE_MINIMIZED ); +} + +void WorkWindow::Restore() +{ + ImplSetFrameState( SAL_FRAMESTATE_NORMAL ); +} + +BOOL WorkWindow::Close() +{ + BOOL bCanClose = SystemWindow::Close(); + + // Ist es das Applikationsfenster, dann beende die Applikation + if ( bCanClose && ( ImplGetSVData()->maWinData.mpAppWin == this ) ) + GetpApp()->Quit(); + + return bCanClose; +} + +void WorkWindow::Maximize( BOOL bMaximize ) +{ + ImplSetFrameState( bMaximize ? SAL_FRAMESTATE_MAXIMIZED : SAL_FRAMESTATE_NORMAL ); +} + +BOOL WorkWindow::IsMaximized() const +{ + BOOL bRet = FALSE; + + SalFrameState aState; + if( mpWindowImpl->mpFrame->GetWindowState( &aState ) ) + { + if( aState.mnState & (SAL_FRAMESTATE_MAXIMIZED | + SAL_FRAMESTATE_MAXIMIZED_HORZ | + SAL_FRAMESTATE_MAXIMIZED_VERT ) ) + bRet = TRUE; + } + return bRet; +} |