diff options
Diffstat (limited to 'svtools/source/contnr')
-rw-r--r-- | svtools/source/contnr/cont_pch.cxx | 73 | ||||
-rw-r--r-- | svtools/source/contnr/ctrdll.cxx | 113 | ||||
-rw-r--r-- | svtools/source/contnr/makefile.mk | 134 | ||||
-rw-r--r-- | svtools/source/contnr/svicnvw.cxx | 855 | ||||
-rw-r--r-- | svtools/source/contnr/svimpbox.cxx | 3171 | ||||
-rw-r--r-- | svtools/source/contnr/svimpicn.cxx | 4222 | ||||
-rw-r--r-- | svtools/source/contnr/svlbitm.cxx | 449 | ||||
-rw-r--r-- | svtools/source/contnr/svlbox.cxx | 1691 | ||||
-rw-r--r-- | svtools/source/contnr/svtabbx.cxx | 639 | ||||
-rw-r--r-- | svtools/source/contnr/svtreebx.cxx | 2355 | ||||
-rw-r--r-- | svtools/source/contnr/treelist.cxx | 2146 |
11 files changed, 15848 insertions, 0 deletions
diff --git a/svtools/source/contnr/cont_pch.cxx b/svtools/source/contnr/cont_pch.cxx new file mode 100644 index 000000000000..4753a03158dc --- /dev/null +++ b/svtools/source/contnr/cont_pch.cxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * $RCSfile: cont_pch.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <sv.hxx> +#include "treelist.hxx" +#include "svtabbx.hxx" +#include "svtreebx.hxx" +#include "svicnvw.hxx" +#include "svimpbox.hxx" +#include "svimpicn.hxx" +#include "svlbox.hxx" +#include "svlbitm.hxx" + +#pragma hdrstop + diff --git a/svtools/source/contnr/ctrdll.cxx b/svtools/source/contnr/ctrdll.cxx new file mode 100644 index 000000000000..20729e743e5b --- /dev/null +++ b/svtools/source/contnr/ctrdll.cxx @@ -0,0 +1,113 @@ +/************************************************************************* + * + * $RCSfile: ctrdll.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef WIN + +#ifndef _SVWIN_H +#include <svwin.h> +#endif + +#ifndef _SYSDEP_HXX +#include <sysdep.hxx> +#endif + +// Statische DLL-Verwaltungs-Variablen +static HINSTANCE hDLLInst = 0; // HANDLE der DLL + + +/*************************************************************************** +|* +|* LibMain() +|* +|* Beschreibung Initialisierungsfunktion der DLL +|* Ersterstellung TH 05.05.93 +|* Letzte Aenderung TH 05.05.93 +|* +***************************************************************************/ + +extern "C" int CALLBACK LibMain( HINSTANCE hDLL, WORD, WORD nHeap, LPSTR ) +{ +#ifndef WNT + if ( nHeap ) + UnlockData( 0 ); +#endif + + hDLLInst = hDLL; + + return TRUE; +} + +/*************************************************************************** +|* +|* WEP() +|* +|* Beschreibung DLL-Deinitialisierung +|* Ersterstellung TH 05.05.93 +|* Letzte Aenderung TH 05.05.93 +|* +***************************************************************************/ + +extern "C" int CALLBACK WEP( int ) +{ + return 1; +} + +#endif diff --git a/svtools/source/contnr/makefile.mk b/svtools/source/contnr/makefile.mk new file mode 100644 index 000000000000..cddb84f1bc6c --- /dev/null +++ b/svtools/source/contnr/makefile.mk @@ -0,0 +1,134 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1.1.1 $ +# +# last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library 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 for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (the "License"); You may not use this file +# except in compliance with the License. You may obtain a copy of the +# License at http://www.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=SVTOOLS +TARGET=svcontnr + +PROJECTPCH4DLL=TRUE +PROJECTPCH=cont_pch +PROJECTPCHSOURCE=cont_pch + +# --- Settings ----------------------------------------------------- + +.INCLUDE : svpre.mk +.INCLUDE : settings.mk +.INCLUDE : sv.mk + +# --- Files -------------------------------------------------------- + +.IF "$(COM)"=="WTC" +CFLAGS=$(CFLAGS) -od -3r +.ENDIF + +.IF "$(header)" == "" + +CXXFILES= svtabbx.cxx \ + svicnvw.cxx \ + svimpicn.cxx \ + treelist.cxx \ + svlbox.cxx \ + svimpbox.cxx \ + svlbitm.cxx \ + svtreebx.cxx \ + cont_pch.cxx \ + ctrdll.cxx + +SLOFILES= $(SLO)$/svtabbx.obj \ + $(SLO)$/svicnvw.obj \ + $(SLO)$/svimpicn.obj \ + $(SLO)$/treelist.obj \ + $(SLO)$/svlbox.obj \ + $(SLO)$/svimpbox.obj \ + $(SLO)$/svlbitm.obj \ + $(SLO)$/svtreebx.obj + +# Fuer das Setup bauen wir noch mal statisch +.IF "$(VCSID)" != "OV" + +OBJFILES= $(OBJ)$/svtabbx.obj \ + $(OBJ)$/svicnvw.obj \ + $(OBJ)$/svimpicn.obj \ + $(OBJ)$/treelist.obj \ + $(OBJ)$/svlbox.obj \ + $(OBJ)$/svimpbox.obj \ + $(OBJ)$/svlbitm.obj \ + $(OBJ)$/svtreebx.obj + +.ENDIF + +.ENDIF + +HXX1TARGET= svcontnr +HXX1EXT= hxx +HXX1FILES= $(PRJ)$/inc$/svlbox.hxx \ + $(PRJ)$/inc$/svlbitm.hxx \ + $(PRJ)$/inc$/svtreebx.hxx \ + $(PRJ)$/inc$/svicnvw.hxx \ + $(PRJ)$/inc$/svtabbx.hxx \ + $(PRJ)$/inc$/treelist.hxx +HXX1EXCL= -E:*include* + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/svtools/source/contnr/svicnvw.cxx b/svtools/source/contnr/svicnvw.cxx new file mode 100644 index 000000000000..e2948c69e60a --- /dev/null +++ b/svtools/source/contnr/svicnvw.cxx @@ -0,0 +1,855 @@ +/************************************************************************* + * + * $RCSfile: svicnvw.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <svlbox.hxx> +#include <svicnvw.hxx> +#include <svimpicn.hxx> +#include <svlbitm.hxx> + +#pragma hdrstop + +#define ICNVW_BLOCK_ENTRYINS 0x0001 + +SvIcnVwDataEntry::SvIcnVwDataEntry() + : nIcnVwFlags(0),eTextMode(ShowTextDontKnow) +{ +} + +SvIcnVwDataEntry::~SvIcnVwDataEntry() +{ +} + +SvIconView::SvIconView( Window* pParent, WinBits nWinStyle ) : + SvLBox( pParent, nWinStyle | WB_BORDER ) +{ + nWinBits = nWinStyle; + nIcnVwFlags = 0; + pImp = new SvImpIconView( this, GetModel(), nWinStyle | WB_ICON ); + pImp->pViewData = 0; + SetSelectionMode( SINGLE_SELECTION ); + SetLineColor(); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + SetDefaultFont(); +} + +SvIconView::SvIconView( Window* pParent , const ResId& rResId ) : + SvLBox( pParent, rResId ) +{ + pImp = new SvImpIconView( this, GetModel(), WB_BORDER | WB_ICON ); + nIcnVwFlags = 0; + pImp->pViewData = 0; + SetLineColor(); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + SetDefaultFont(); + pImp->SetSelectionMode( GetSelectionMode() ); + pImp->SetWindowBits( nWindowStyle ); + nWinBits = nWindowStyle; +} + +SvIconView::~SvIconView() +{ + delete pImp; +} + +void SvIconView::SetDefaultFont() +{ + SetFont( GetFont() ); +} + +SvLBoxEntry* SvIconView::CreateEntry( const XubString& rStr, + const Image& rCollEntryBmp, const Image& rExpEntryBmp ) +{ + SvLBoxEntry* pEntry = new SvLBoxEntry; + + SvLBoxContextBmp* pContextBmp = + new SvLBoxContextBmp( pEntry,0, rCollEntryBmp,rExpEntryBmp, 0xffff ); + pEntry->AddItem( pContextBmp ); + + SvLBoxString* pString = new SvLBoxString( pEntry, 0, rStr ); + pEntry->AddItem( pString ); + + return pEntry; +} + +void SvIconView::DisconnectFromModel() +{ + SvLBox::DisconnectFromModel(); + pImp->SetModel( GetModel(), 0 ); +} + + +SvLBoxEntry* SvIconView::InsertEntry( const XubString& rText, + SvLBoxEntry* pParent, BOOL bChildsOnDemand, ULONG nPos ) +{ + SvLBoxEntry* pEntry = CreateEntry( + rText, aCollapsedEntryBmp, aExpandedEntryBmp ); + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + if ( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + return pEntry; +} + +SvLBoxEntry* SvIconView::InsertEntry( const XubString& rText, + const Image& rExpEntryBmp, + const Image& rCollEntryBmp, + SvLBoxEntry* pParent, BOOL bChildsOnDemand, ULONG nPos) +{ + SvLBoxEntry* pEntry = CreateEntry( + rText, rCollEntryBmp, rExpEntryBmp ); + + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + if ( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + return pEntry; +} + + +void SvIconView::SetEntryText(SvLBoxEntry* pEntry, const XubString& rStr) +{ + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pItem ) + { + pItem->SetText( pEntry, rStr ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +void SvIconView::SetExpandedEntryBmp(SvLBoxEntry* pEntry, const Image& rBmp) +{ + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + { + pItem->SetBitmap2( pEntry, rBmp ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +void SvIconView::SetCollapsedEntryBmp(SvLBoxEntry* pEntry, + const Image& rBmp ) +{ + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + { + pItem->SetBitmap1( pEntry, rBmp ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +XubString SvIconView::GetEntryText(SvLBoxEntry* pEntry ) const +{ + XubString aStr; + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pItem ) + aStr = pItem->GetText(); + return aStr; +} + +Image SvIconView::GetExpandedEntryBmp(SvLBoxEntry* pEntry) const +{ + Image aBmp; + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + aBmp = pItem->GetBitmap2(); + return aBmp; +} + +Image SvIconView::GetCollapsedEntryBmp(SvLBoxEntry* pEntry) const +{ + Image aBmp; + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + aBmp = pItem->GetBitmap1(); + return aBmp; +} + + +SvLBoxEntry* SvIconView::CloneEntry( SvLBoxEntry* pSource ) +{ + XubString aStr; + Image aCollEntryBmp; + Image aExpEntryBmp; + + SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pStringItem ) + aStr = pStringItem->GetText(); + SvLBoxContextBmp* pBmpItem =(SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pBmpItem ) + { + aCollEntryBmp = pBmpItem->GetBitmap1(); + aExpEntryBmp = pBmpItem->GetBitmap2(); + } + SvLBoxEntry* pEntry = CreateEntry( aStr, aCollEntryBmp, aExpEntryBmp ); + pEntry->SvListEntry::Clone( pSource ); + pEntry->EnableChildsOnDemand( pSource->HasChildsOnDemand() ); + pEntry->SetUserData( pSource->GetUserData() ); + return pEntry; +} + + +USHORT SvIconView::IsA() +{ + return SV_LISTBOX_ID_ICONVIEW; +} + +void SvIconView::RequestingChilds( SvLBoxEntry* pParent ) +{ + if ( !pParent->HasChilds() ) + InsertEntry( String::CreateFromAscii("<dummy>"), pParent, FALSE, LIST_APPEND ); +} + +void __EXPORT SvIconView::Paint( const Rectangle& rRect ) +{ + pImp->Paint( rRect ); +} + +void __EXPORT SvIconView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + pImp->MouseButtonDown( rMEvt ); +} + +void __EXPORT SvIconView::MouseButtonUp( const MouseEvent& rMEvt ) +{ + pImp->MouseButtonUp( rMEvt ); +} + +void __EXPORT SvIconView::MouseMove( const MouseEvent& rMEvt ) +{ + pImp->MouseMove( rMEvt ); +} + +void __EXPORT SvIconView::KeyInput( const KeyEvent& rKEvt ) +{ + // unter OS/2 bekommen wir auch beim Editieren Key-Up/Down + if( IsEditingActive() ) + return; + + nImpFlags |= SVLBOX_IS_TRAVELSELECT; + BOOL bKeyUsed = pImp->KeyInput( rKEvt ); + if ( !bKeyUsed ) + SvLBox::KeyInput( rKEvt ); + nImpFlags &= ~SVLBOX_IS_TRAVELSELECT; +} + +void __EXPORT SvIconView::Resize() +{ + pImp->Resize(); + SvLBox::Resize(); +} + +void __EXPORT SvIconView::GetFocus() +{ + pImp->GetFocus(); + SvLBox::GetFocus(); +} + +void __EXPORT SvIconView::LoseFocus() +{ + pImp->LoseFocus(); + SvLBox::LoseFocus(); +} + +void SvIconView::SetUpdateMode( BOOL bUpdate ) +{ + Control::SetUpdateMode( bUpdate ); + if ( bUpdate ) + pImp->UpdateAll(); +} + +void SvIconView::SetModel( SvLBoxTreeList* pNewModel ) +{ +} + +void SvIconView::SetModel( SvLBoxTreeList* pNewModel, SvLBoxEntry* pParent ) +{ + nIcnVwFlags |= ICNVW_BLOCK_ENTRYINS; + SvLBox::SetModel( pNewModel ); + nIcnVwFlags &= (~ICNVW_BLOCK_ENTRYINS); + if ( pParent && pParent->HasChildsOnDemand() ) + RequestingChilds( pParent ); + pImp->SetModel( pNewModel, pParent ); +} + +void __EXPORT SvIconView::ModelHasCleared() +{ + SvLBox::ModelHasCleared(); + pImp->Clear(); +} + +void __EXPORT SvIconView::ModelHasInserted( SvListEntry* pEntry ) +{ + if( !(nIcnVwFlags & ICNVW_BLOCK_ENTRYINS ) ) + pImp->EntryInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelHasInsertedTree( SvListEntry* pEntry ) +{ + pImp->TreeInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelIsMoving(SvListEntry* pSource, + SvListEntry* /* pTargetParent */ , ULONG /* nChildPos */ ) +{ + pImp->MovingEntry( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvIconView::ModelHasMoved(SvListEntry* pSource ) +{ + pImp->EntryMoved( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvIconView::ModelIsRemoving( SvListEntry* pEntry ) +{ + pImp->RemovingEntry( (SvLBoxEntry*)pEntry ); + NotifyRemoving( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelHasRemoved( SvListEntry* /* pEntry */ ) +{ + pImp->EntryRemoved(); +} + +void __EXPORT SvIconView::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + // die einzelnen Items des Entries reinitialisieren + SvLBox::ModelHasEntryInvalidated( pEntry ); + // painten + pImp->ModelHasEntryInvalidated( pEntry ); +} + +void SvIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, BOOL bShow ) +{ + pImp->ShowTargetEmphasis( pEntry, bShow ); +} + +Point SvIconView::GetEntryPos( SvLBoxEntry* pEntry ) const +{ + return ((SvIconView*)this)->pImp->GetEntryPos( pEntry ); +} + +void SvIconView::SetEntryPos( SvLBoxEntry* pEntry, const Point& rPos) +{ + pImp->SetEntryPos( pEntry, rPos, FALSE, TRUE ); +} + +void SvIconView::SetEntryPos( SvLBoxEntry* pEntry, const Point& rPos, BOOL bAdjustAtGrid ) +{ + pImp->SetEntryPos( pEntry, rPos, bAdjustAtGrid ); +} + +void SvIconView::SetFont( const Font& rFont ) +{ + Font aTempFont( rFont ); + aTempFont.SetTransparent( TRUE ); + SvLBox::SetFont( aTempFont ); + RecalcViewData(); + pImp->ChangedFont(); +} + +void SvIconView::ViewDataInitialized( SvLBoxEntry* pEntry ) +{ + pImp->ViewDataInitialized( pEntry ); +} + +SvLBoxEntry* SvIconView::GetCurEntry() const +{ + return pImp->GetCurEntry(); +} + +SvLBoxEntry* SvIconView::GetDropTarget( const Point& rPos ) +{ + return pImp->GetDropTarget( rPos ); +} + +SvLBoxEntry* SvIconView::GetEntry( const Point& rPixPos, BOOL ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetEntry( aPos ); +} + +SvLBoxEntry* SvIconView::GetEntryFromLogicPos( const Point& rDocPos ) const +{ + return ((SvIconView*)this)->pImp->GetEntry( rDocPos ); +} + + +void SvIconView::SetWindowBits( WinBits nWinStyle ) +{ + nWinBits = nWinStyle; + pImp->SetWindowBits( nWinStyle ); +} + +void SvIconView::PaintEntry( SvLBoxEntry* pEntry ) +{ + pImp->PaintEntry( pEntry ); +} + + +void SvIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos ) +{ + pImp->PaintEntry( pEntry, rPos ); +} + +Rectangle SvIconView::GetFocusRect( SvLBoxEntry* pEntry ) +{ + return pImp->CalcFocusRect( pEntry ); +} + +void SvIconView::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + pImp->InvalidateEntry( pEntry ); +} + +void SvIconView::SetDragDropMode( DragDropMode nDDMode ) +{ + SvLBox::SetDragDropMode( nDDMode ); + pImp->SetDragDropMode( nDDMode ); +} + +void SvIconView::SetSelectionMode( SelectionMode eSelMode ) +{ + SvLBox::SetSelectionMode( eSelMode ); + pImp->SetSelectionMode( eSelMode ); +} + +BOOL SvIconView::Select( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + EndEditing(); + BOOL bRetVal = SvListView::Select( pEntry, bSelect ); + if( bRetVal ) + { + pImp->EntrySelected( pEntry, bSelect ); + pHdlEntry = pEntry; + SelectHdl(); + } + return bRetVal; +} + +void SvIconView::SelectAll( BOOL bSelect, BOOL bPaint ) +{ + SvLBoxEntry* pEntry = pImp->GetCurParent(); + pEntry = FirstChild( pEntry ); + while( pEntry ) + { + Select( pEntry, bSelect ); + pEntry = NextSibling( pEntry ); + } +} + +void SvIconView::Arrange() +{ +#ifdef DBG_UTIL + USHORT n=1; + if( n == 1 && n-1 == 0 ) + { + pImp->Arrange(); + } + else + { + pImp->AdjustAtGrid(); + } +#else + pImp->Arrange(); +#endif +} + + +void SvIconView::SetSpaceBetweenEntries( long nX, long nY ) +{ + pImp->SetSpaceBetweenEntries( nX, nY ); +} + +BOOL SvIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos ) +{ + return pImp->NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos); +} + +BOOL SvIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos ) +{ + return pImp->NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos); +} + + +void SvIconView::EnableInplaceEditing( BOOL bEnable ) +{ + SvLBox::EnableInplaceEditing( bEnable ); +} + +void SvIconView::EditingRequest( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Point& ) +{ + if ( pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if ( EditingEntry( pEntry, aSel ) ) + { + SelectAll( FALSE ); + EditItemText( pEntry, (SvLBoxString*)pItem, aSel ); + } + } +} + + +void SvIconView::EditItemText( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Selection& rSel ) +{ + DBG_ASSERT(pEntry&&pItem,"EditItemText:Params?") + pCurEdEntry = pEntry; + pCurEdItem = pItem; + Rectangle aRect( pImp->CalcTextRect( pEntry, (SvLBoxString*)pItem,0,TRUE )); + + aRect.Bottom() += 4; + pImp->MakeVisible( aRect ); // vor der Umrechnung in Pixel-Koord. rufen! + aRect.Bottom() -= 4; + + Point aPos( aRect.TopLeft() ); + aPos += GetMapMode().GetOrigin(); // Dok-Koord. -> Window-Koord. + aRect.SetPos( aPos ); + + aRect.Bottom() += 2; // sieht huebscher aus + +#ifdef WIN + aRect.Bottom() += 4; +#endif +#ifdef OS2 + +#if OS2_SINGLE_LINE_EDIT + aRect.Left() -= 3; + aRect.Right() += 3; + aRect.Top() -= 3; + aRect.Bottom() += 3; +#else + aRect.Left() -= 10; + aRect.Right() += 10; + aRect.Top() -= 5; + aRect.Bottom() += 5; +#endif + +#endif // OS2 + EditText( ((SvLBoxString*)pItem)->GetText(), aRect, rSel, TRUE ); +} + +void SvIconView::EditEntry( SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + pEntry = pImp->GetCurEntry(); + if( pEntry ) + { + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pItem ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( EditingEntry( pEntry, aSel ) ) + { + SelectAll( FALSE ); + EditItemText( pEntry, pItem, aSel ); + } + } + } +} + +void SvIconView::EditedText( const XubString& rStr ) +{ + XubString aRefStr( ((SvLBoxString*)pCurEdItem)->GetText() ); + if ( EditedEntry( pCurEdEntry, rStr ) ) + { + ((SvLBoxString*)pCurEdItem)->SetText( pCurEdEntry, rStr ); + pModel->InvalidateEntry( pCurEdEntry ); + } + if( GetSelectionMode()==SINGLE_SELECTION && !GetSelectionCount()) + Select( pCurEdEntry ); +} + + +BOOL SvIconView::EditingEntry( SvLBoxEntry*, Selection& ) +{ + return TRUE; +} + +BOOL SvIconView::EditedEntry( SvLBoxEntry*, const XubString& ) +{ + return TRUE; +} + + +void SvIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo) +{ + pImp->WriteDragServerInfo( rPos, pInfo ); +} + +void SvIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo ) +{ + pImp->ReadDragServerInfo( rPos, pInfo ); +} + +void SvIconView::Command( const CommandEvent& rCEvt ) +{ + pImp->Command( rCEvt ); +} + +void SvIconView::SetCurParent( SvLBoxEntry* pNewParent ) +{ + if ( pNewParent && pNewParent->HasChildsOnDemand() ) + RequestingChilds( pNewParent ); + pImp->SetCurParent( pNewParent ); +} + +SvLBoxEntry* SvIconView::GetCurParent() const +{ + return pImp->GetCurParent(); +} + +SvViewData* SvIconView::CreateViewData( SvListEntry* pEntry ) +{ + SvIcnVwDataEntry* pEntryData = new SvIcnVwDataEntry; + return (SvViewData*)pEntryData; +} + +void SvIconView::InitViewData( SvViewData* pData, SvListEntry* pEntry ) +{ + SvLBox::InitViewData( pData, pEntry ); + pImp->InvalidateBoundingRect( ((SvIcnVwDataEntry*)pData)->aRect ); +} + +Region SvIconView::GetDragRegion() const +{ + Rectangle aRect; + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + aRect = pImp->GetBoundingRect( pEntry ); + Region aRegion( aRect ); + return aRegion; +} + +ULONG SvIconView::GetSelectionCount() const +{ + return (ULONG)(pImp->GetSelectionCount()); +} + +void SvIconView::SetGrid( long nDX, long nDY ) +{ + pImp->SetGrid( nDX, nDY ); +} + +void SvIconView::ModelNotification( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, ULONG nPos ) +{ + SvLBox::ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + switch( nActionId ) + { + case LISTACTION_RESORTING: + SetUpdateMode( FALSE ); + break; + + case LISTACTION_RESORTED: + SetUpdateMode( TRUE ); + Arrange(); + break; + + case LISTACTION_CLEARED: + if( IsUpdateMode() ) + Update(); + break; + } +} + + +void SvIconView::Scroll( long nDeltaX, long nDeltaY ) +{ + pImp->Scroll( nDeltaX, nDeltaY, FALSE ); +} + +void SvIconView::PrepareCommandEvent( const CommandEvent& rCEvt ) +{ + pImp->PrepareCommandEvent( rCEvt ); +} + +void SvIconView::BeginDrag( const Point& rPos ) +{ + SvLBoxEntry* pEntry = GetEntry( rPos, TRUE ); + pImp->pViewData = pEntry; + SvLBox::BeginDrag( rPos ); +} + +BOOL __EXPORT SvIconView::QueryDrop( DropEvent& rDEvt ) +{ + if( pImp->pViewData ) + { + pImp->HideDDIcon(); + } + BOOL bResult = SvLBox::QueryDrop( rDEvt ); + if( bResult ) + { + pImp->ShowDDIcon( pImp->pViewData, rDEvt.GetPosPixel() ); + } + return bResult; +} + +BOOL SvIconView::Drop( const DropEvent& rDEvt ) +{ + if( pImp->pViewData ) + { + pImp->HideDDIcon(); + pImp->pViewData = 0; + } + return SvLBox::Drop( rDEvt ); +} + +void SvIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPos ) +{ + pImp->ShowDDIcon( pRefEntry, rPos ); +} + +void SvIconView::HideDDIcon() +{ + pImp->HideDDIcon(); +} + +void SvIconView::HideShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPos ) +{ + pImp->HideShowDDIcon( pRefEntry, rPos ); +} + +void SvIconView::SelectRect( const Rectangle& rRect, BOOL bAdd, + SvPtrarr* pRects, short nOffs ) +{ + pImp->SelectRect( rRect, bAdd, pRects, nOffs ); +} + +void SvIconView::CalcScrollOffsets( const Point& rRefPosPixel, long& rX, long& rY, + BOOL b, USHORT nBorderWidth ) +{ + pImp->CalcScrollOffsets( rRefPosPixel, rX, rY, b, nBorderWidth ); +} + +void SvIconView::EndTracking() +{ + pImp->EndTracking(); +} + +void SvIconView::MakeVisible( SvLBoxEntry* pEntry ) +{ + pImp->MakeVisible( pEntry ); +} + +void SvIconView::PreparePaint( SvLBoxEntry* ) +{ +} + +void SvIconView::AdjustAtGrid( SvLBoxEntry* pEntry ) +{ + pImp->AdjustAtGrid( pEntry ); +} + +void SvIconView::LockEntryPos( SvLBoxEntry* pEntry, BOOL bLock ) +{ + SvIcnVwDataEntry* pViewData = (SvIcnVwDataEntry*)GetViewData( pEntry ); + if( bLock ) + pViewData->SetVwFlags( ICNVW_FLAG_POS_LOCKED ); + else + pViewData->ClearVwFlags( ICNVW_FLAG_POS_LOCKED ); +} + +BOOL SvIconView::IsEntryPosLocked( const SvLBoxEntry* pEntry ) const +{ + const SvIcnVwDataEntry* pViewData = (const SvIcnVwDataEntry*)GetViewData( (SvListEntry*)pEntry ); + return pViewData->IsEntryPosLocked(); +} + +void SvIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry ) +{ + pImp->SetTextMode( eMode, pEntry ); +} + +SvIconViewTextMode SvIconView::GetTextMode( const SvLBoxEntry* pEntry ) const +{ + return pImp->GetTextMode( pEntry ); +} + +SvLBoxEntry* SvIconView::GetNextEntry( const Point& rPixPos, SvLBoxEntry* pCurEntry, BOOL ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetNextEntry( aPos, pCurEntry ); +} + +SvLBoxEntry* SvIconView::GetPrevEntry( const Point& rPixPos, SvLBoxEntry* pCurEntry, BOOL ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetPrevEntry( aPos, pCurEntry ); +} + +void SvIconView::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + pImp->ShowFocusRect( pEntry ); +} + + diff --git a/svtools/source/contnr/svimpbox.cxx b/svtools/source/contnr/svimpbox.cxx new file mode 100644 index 000000000000..ebdc765651cf --- /dev/null +++ b/svtools/source/contnr/svimpbox.cxx @@ -0,0 +1,3171 @@ +/************************************************************************* + * + * $RCSfile: svimpbox.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifndef _SV_SVAPP_HXX //autogen +#include <vcl/svapp.hxx> +#endif + +#ifndef _HELP_HXX +#include <vcl/help.hxx> +#endif +#ifndef _TABBAR_HXX +#include <tabbar.hxx> +#endif + +#pragma hdrstop + +#define _SVTREEBX_CXX +#include <svtreebx.hxx> +#ifndef _SVLBOX_HXX +#include <svlbox.hxx> +#endif +#include <svimpbox.hxx> + + +#define NODE_BMP_TABDIST_NOTVALID -2000000 + +SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvLBoxTreeList* pLBTree, WinBits nWinStyle) : + aVerSBar( pLBView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pLBView, WB_DRAG | WB_HSCROLL ), + aScrBarBox( pLBView ), + aOutputSize( 0,0 ), + aSelEng( pLBView, (FunctionSet*)0 ), + aFctSet( this, &aSelEng, pLBView ), + pTabBar(0) +{ + pView = pLBView; + pTree = pLBTree; + aSelEng.SetFunctionSet( (FunctionSet*)&aFctSet ); + aSelEng.ExpandSelectionOnMouseMove( FALSE ); + SetWindowBits( nWinStyle ); + SetSelectionMode( SINGLE_SELECTION ); + SetDragDropMode( 0 ); + + aVerSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl ) ); + aHorSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl ) ); + aHorSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) ); + aVerSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) ); +#if SUPD > 358 + aVerSBar.SetRange( Range(0,0) ); + aVerSBar.Hide(); +#endif + aHorSBar.SetRange( Range(0,0) ); + aHorSBar.SetPageSize( 24 ); // Pixel + aHorSBar.SetLineSize( 8 ); // Pixel + + nHorSBarHeight = (short)aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = (short)aVerSBar.GetSizePixel().Width(); + + pStartEntry = 0; + pCursor = 0; + pAnchor = 0; + nVisibleCount = 0; // Anzahl Daten-Zeilen im Control + nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID; + nYoffsNodeBmp = 0; + nNodeBmpWidth = 0; + + bAsyncBeginDrag = FALSE; + aAsyncBeginDragTimer.SetTimeout( 0 ); + aAsyncBeginDragTimer.SetTimeoutHdl( LINK(this,SvImpLBox,BeginDragHdl)); + // Button-Animation in Listbox + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nFlags = 0; + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl( LINK(this,SvImpLBox,EditTimerCall) ); + + nMostRight = -1; + pMostRightEntry = 0; + nCurUserEvent = 0xffffffff; + + bUpdateMode = TRUE; + bInVScrollHdl = FALSE; + nFlags |= F_FILLING; +} + +SvImpLBox::~SvImpLBox() +{ + aEditTimer.Stop(); + StopUserEvent(); +} + +void SvImpLBox::SetWindowBits( WinBits nWinStyle ) +{ + nWinBits = nWinStyle; + if((nWinStyle & WB_SIMPLEMODE) && aSelEng.GetSelectionMode()==MULTIPLE_SELECTION) + aSelEng.AddAlways( TRUE ); +} + +// Das Model darf hier nicht mehr angefasst werden +void SvImpLBox::Clear() +{ + StopUserEvent(); + pStartEntry = 0; + pAnchor = 0; + + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nMostRight = -1; + pMostRightEntry = 0; + + // Der Cursor darf hier nicht mehr angefasst werden! + if( pCursor ) + { + if( pView->HasFocus() ) + pView->HideFocus(); + pCursor = 0; + } + aVerSBar.Hide(); + aVerSBar.SetThumbPos( 0 ); + Range aRange( 0, 0 ); + aVerSBar.SetRange( aRange ); + aOutputSize = pView->Control::GetOutputSizePixel(); + nFlags &= ~(F_VER_SBARSIZE_WITH_HBAR | F_HOR_SBARSIZE_WITH_VBAR ); + if( pTabBar ) + { + aOutputSize.Height() -= nHorSBarHeight; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + if( !pTabBar ) + aHorSBar.Hide(); + aHorSBar.SetThumbPos( 0 ); + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point(0,0) ); + pView->Control::SetMapMode( aMapMode ); + aHorSBar.SetRange( aRange ); + aHorSBar.SetSizePixel(Size(aOutputSize.Width(),nHorSBarHeight)); + pView->SetClipRegion(); + if( GetUpdateMode() ) + pView->Invalidate( GetVisibleArea() ); + nFlags |= F_FILLING; + if( !aHorSBar.IsVisible() && !aVerSBar.IsVisible() ) + aScrBarBox.Hide(); +} + +// ********************************************************************* +// Painten, Navigieren, Scrollen +// ********************************************************************* + +IMPL_LINK_INLINE_START( SvImpLBox, EndScrollHdl, ScrollBar *, pScrollBar ) +{ + if( nFlags & F_ENDSCROLL_SET_VIS_SIZE ) + { + aVerSBar.SetVisibleSize( nNextVerVisSize ); + nFlags &= ~F_ENDSCROLL_SET_VIS_SIZE; + } + EndScroll(); + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, EndScrollHdl, ScrollBar *, pScrollBar ) + + +// Handler vertikale ScrollBar + +IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar ) +{ + DBG_ASSERT(!bInVScrollHdl,"Scroll-Handler ueberholt sich!"); + long nDelta = pScrollBar->GetDelta(); + if( !nDelta ) + return 0; + + nFlags &= (~F_FILLING); + + bInVScrollHdl = TRUE; + + if( pView->IsEditingActive() ) + { + pView->EndEditing( TRUE ); // Cancel + pView->Update(); + } + BeginScroll(); + + if( nDelta > 0 ) + { + if( nDelta == 1 ) + CursorDown(); + else + PageDown( (USHORT) nDelta ); + } + else + { + nDelta *= (-1); + if( nDelta == 1 ) + CursorUp(); + else + PageUp( (USHORT) nDelta ); + } + bInVScrollHdl = FALSE; + return 0; +} + + +void SvImpLBox::CursorDown() +{ + SvLBoxEntry* pNextFirstToDraw = (SvLBoxEntry*)(pView->NextVisible( pStartEntry)); + if( pNextFirstToDraw ) + { + nFlags &= (~F_FILLING); + pView->NotifyScrolling( -1 ); + ShowCursor( FALSE ); + pView->Update(); + pStartEntry = pNextFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + pView->Scroll( 0, -(pView->GetEntryHeight()), aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::CursorUp() +{ + SvLBoxEntry* pPrevFirstToDraw = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry)); + if( pPrevFirstToDraw ) + { + nFlags &= (~F_FILLING); + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( 1 ); + ShowCursor( FALSE ); + pView->Update(); + pStartEntry = pPrevFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + aArea.Bottom() -= nEntryHeight; + pView->Scroll( 0, nEntryHeight, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::PageDown( USHORT nDelta ) +{ + USHORT nRealDelta = nDelta; + + if( !nDelta ) + return; + + SvLBoxEntry* pNext; + pNext = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nRealDelta )); + if( (ULONG)pNext == (ULONG)pStartEntry ) + return; + + ShowCursor( FALSE ); + + nFlags &= (~F_FILLING); + pView->Update(); + pStartEntry = pNext; + + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nScroll = nRealDelta * (-1); + pView->NotifyScrolling( nScroll ); + Rectangle aArea( GetVisibleArea() ); + nScroll = pView->GetEntryHeight()*nRealDelta; + nScroll = -nScroll; + pView->Update(); + pView->Scroll( 0, nScroll, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( TRUE ); +} + +void SvImpLBox::PageUp( USHORT nDelta ) +{ + USHORT nRealDelta = nDelta; + if( !nDelta ) + return; + + SvLBoxEntry* pPrev = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry, nRealDelta )); + if( (ULONG)pPrev == (ULONG)pStartEntry ) + return; + + nFlags &= (~F_FILLING); + ShowCursor( FALSE ); + + pView->Update(); + pStartEntry = pPrev; + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( (long)nRealDelta ); + Rectangle aArea( GetVisibleArea() ); + pView->Update(); + pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( TRUE ); +} + +void SvImpLBox::KeyUp( BOOL bPageUp, BOOL bNotifyScroll ) +{ + if( !aVerSBar.IsVisible() ) + return; + + long nDelta; + if( bPageUp ) + nDelta = aVerSBar.GetPageSize(); + else + nDelta = 1; + + long nThumbPos = aVerSBar.GetThumbPos(); + + if( nThumbPos < nDelta ) + nDelta = nThumbPos; + + if( nDelta <= 0 ) + return; + + nFlags &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos - nDelta ); + if( bPageUp ) + PageUp( (short)nDelta ); + else + CursorUp(); + + if( bNotifyScroll ) + EndScroll(); +} + + +void SvImpLBox::KeyDown( BOOL bPageDown, BOOL bNotifyScroll ) +{ + if( !aVerSBar.IsVisible() ) + return; + + long nDelta; + if( bPageDown ) + nDelta = aVerSBar.GetPageSize(); + else + nDelta = 1; + + long nThumbPos = aVerSBar.GetThumbPos(); + long nVisibleSize = aVerSBar.GetVisibleSize(); + long nRange = aVerSBar.GetRange().Len(); + + long nTmp = nThumbPos+nVisibleSize; + while( (nDelta > 0) && (nTmp+nDelta) >= nRange ) + nDelta--; + + if( nDelta <= 0 ) + return; + + nFlags &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos+nDelta ); + if( bPageDown ) + PageDown( (short)nDelta ); + else + CursorDown(); + + if( bNotifyScroll ) + EndScroll(); +} + + + +void SvImpLBox::InvalidateEntriesFrom( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + aRect.Top() = nY; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + long nMaxBottom = aRect.Bottom(); + aRect.Top() = nY; + aRect.Bottom() = nY; aRect.Bottom() += pView->GetEntryHeight(); + if( aRect.Top() > nMaxBottom ) + return; + if( aRect.Bottom() > nMaxBottom ) + aRect.Bottom() = nMaxBottom; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + long nPrev = nMostRight; + SetMostRight( pEntry ); + if( nPrev < nMostRight ) + ShowVerSBar(); + } + if( !(nFlags & F_IN_PAINT )) + { + BOOL bHasFocusRect = FALSE; + if( pEntry==pCursor && pView->HasFocus() ) + { + bHasFocusRect = TRUE; + ShowCursor( FALSE ); + } + InvalidateEntry( GetEntryLine( pEntry ) ); + if( bHasFocusRect ) + ShowCursor( TRUE ); + } +} + + +void SvImpLBox::RecalcFocusRect() +{ + if( pView->HasFocus() && pCursor ) + { + pView->HideFocus(); + long nY = GetEntryLine( pCursor ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + +// +// Setzt Cursor. Passt bei SingleSelection die Selektion an +// + +void SvImpLBox::SetCursor( SvLBoxEntry* pEntry, BOOL bForceNoSelect ) +{ + SvViewDataEntry* pViewDataNewCur = 0; + if( pEntry ) + pViewDataNewCur= pView->GetViewDataEntry(pEntry); + if( pEntry && + pEntry == pCursor && + pViewDataNewCur->HasFocus() && + pViewDataNewCur->IsSelected()) + { + return; + } + SvLBoxEntry* pOldCursor = pCursor; + if( pCursor && pEntry != pCursor ) + { + pView->SetEntryFocus( pCursor, FALSE ); + if( bSimpleTravel ) + pView->Select( pCursor, FALSE ); + pView->HideFocus(); + } + pCursor = pEntry; + if( pCursor ) + { + pViewDataNewCur->SetFocus( TRUE ); + if(!bForceNoSelect && bSimpleTravel && !(nFlags & F_DESEL_ALL) && GetUpdateMode()) + { + pView->Select( pCursor, TRUE ); + } + // Mehrfachselektion: Im Cursor-Move selektieren, wenn + // nicht im Add-Mode (Ctrl-F8) + else if( GetUpdateMode() && + pView->GetSelectionMode() == MULTIPLE_SELECTION && + !(nFlags & F_DESEL_ALL) && !aSelEng.IsAddMode() && + !bForceNoSelect ) + { + pView->Select( pCursor, TRUE ); + } + else + { + ShowCursor( TRUE ); + } + + if( pAnchor ) + { + DBG_ASSERT(aSelEng.GetSelectionMode() != SINGLE_SELECTION,"Mode?") + SetAnchorSelection( pOldCursor, pCursor ); + } + } + nFlags &= (~F_DESEL_ALL); +} + +void SvImpLBox::ShowCursor( BOOL bShow ) +{ + if( !bShow || !pCursor || !pView->HasFocus() ) + pView->HideFocus(); + else + { + long nY = GetEntryLine( pCursor ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + + + +void SvImpLBox::UpdateAll( BOOL bInvalidateCompleteView, + BOOL bUpdateVerScrollBar ) +{ + if( bUpdateVerScrollBar ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + SyncVerThumb(); + FillView(); + ShowVerSBar(); + if( bSimpleTravel && pCursor && pView->HasFocus() ) + pView->Select( pCursor, TRUE ); + ShowCursor( TRUE ); + if( bInvalidateCompleteView ) + pView->Invalidate(); + else + pView->Invalidate( GetVisibleArea() ); +} + +IMPL_LINK_INLINE_START( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) +{ + long nDelta = pScrollBar->GetDelta(); + if( nDelta ) + { + if( pView->IsEditingActive() ) + { + pView->EndEditing( TRUE ); // Cancel + pView->Update(); + } + pView->nFocusWidth = -1; + KeyLeftRight( nDelta ); + } + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) + +void SvImpLBox::KeyLeftRight( long nDelta ) +{ + if( !(nFlags & F_IN_RESIZE) ) + pView->Update(); + BeginScroll(); + nFlags &= (~F_FILLING); + pView->NotifyScrolling( 0 ); // 0 == horizontales Scrolling + ShowCursor( FALSE ); + + // neuen Origin berechnen + long nPos = aHorSBar.GetThumbPos(); + Point aOrigin( -nPos, 0 ); + + MapMode aMapMode( pView->GetMapMode() ); + aMapMode.SetOrigin( aOrigin ); + pView->SetMapMode( aMapMode ); + + if( !(nFlags & F_IN_RESIZE) ) + { + Rectangle aRect( GetVisibleArea() ); + pView->Scroll( -nDelta, 0, aRect, SCROLL_NOCHILDREN ); + } + else + pView->Invalidate(); + RecalcFocusRect(); + ShowCursor( TRUE ); + pView->NotifyScrolled(); +} + + +// gibt letzten Eintrag zurueck, wenn Position unter +// dem letzten Eintrag ist +SvLBoxEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const +{ + if( pView->GetEntryCount() == 0 || !pStartEntry) + return 0; + + USHORT nClickedEntry = (USHORT)(rPoint.Y() / pView->GetEntryHeight() ); + USHORT nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + return pEntry; +} + +// +// prueft, ob der Eintrag "richtig" getroffen wurde +// (Focusrect+ ContextBitmap bei TreeListBox) +// +BOOL SvImpLBox::EntryReallyHit(SvLBoxEntry* pEntry,const Point& rPosPixel,long nLine) +{ + BOOL bRet; + // bei "besonderen" Entries (mit CheckButtons usw.) sind wir + // nicht so pingelig + if( pEntry->ItemCount() >= 3 ) + return TRUE; + + Rectangle aRect( pView->GetFocusRect( pEntry, nLine )); + if( pView->IsA() == SV_LISTBOX_ID_TREEBOX ) + { + SvLBoxContextBmp* pBmp = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + aRect.Left() -= pBmp->GetSize(pView,pEntry).Width(); + aRect.Left() -= 4; // etwas Speilraum lassen + } + Point aPos( rPosPixel ); + aPos -= pView->GetMapMode().GetOrigin(); + if( aRect.IsInside( aPos ) ) + bRet = TRUE; + else + bRet = FALSE; + return bRet; +} + + +// gibt 0 zurueck, wenn Position unter dem letzten Eintrag ist +SvLBoxEntry* SvImpLBox::GetEntry( const Point& rPoint ) const +{ + if( (pView->GetEntryCount() == 0) || !pStartEntry || + (rPoint.Y() > aOutputSize.Height()) ) + return 0; + + USHORT nClickedEntry = (USHORT)(rPoint.Y() / pView->GetEntryHeight() ); + USHORT nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + if( nTemp != nClickedEntry ) + pEntry = 0; + return pEntry; +} + + +SvLBoxEntry* SvImpLBox::MakePointVisible(const Point& rPoint,BOOL bNotifyScroll) +{ + if( !pCursor ) + return 0; + long nY = rPoint.Y(); + SvLBoxEntry* pEntry = 0; + long nMax = aOutputSize.Height(); + if( nY < 0 || nY >= nMax ) // aOutputSize.Height() ) + { + if( nY < 0 ) + pEntry = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + else + pEntry = (SvLBoxEntry*)(pView->NextVisible( pCursor )); + + if( pEntry && pEntry != pCursor ) + pView->SetEntryFocus( pCursor, FALSE ); + + if( nY < 0 ) + KeyUp( FALSE, bNotifyScroll ); + else + KeyDown( FALSE, bNotifyScroll ); + } + else + { + pEntry = GetClickedEntry( rPoint ); + if( !pEntry ) + { + USHORT nSteps = 0xFFFF; + // LastVisible ist noch nicht implementiert! + pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nSteps )); + } + if( pEntry ) + { + if( pEntry != pCursor && + aSelEng.GetSelectionMode() == SINGLE_SELECTION + ) + pView->Select( pCursor, FALSE ); + } + } + return pEntry; +} + +Rectangle SvImpLBox::GetClipRegionRect() const +{ + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin.X() *= -1; // Umrechnung Dokumentkoord. + Rectangle aClipRect( aOrigin, aOutputSize ); + aClipRect.Bottom()++; + return aClipRect; +} + + +void SvImpLBox::Paint( const Rectangle& rRect ) +{ + if( !pView->GetVisibleCount() ) + return; + + nFlags |= F_IN_PAINT; + +//#if SUPD > 364 + if( nFlags & F_FILLING ) + { + SvLBoxEntry* pFirst = pView->First(); + if( pFirst != pStartEntry ) + { + ShowCursor( FALSE ); + pStartEntry = pView->First(); + aVerSBar.SetThumbPos( 0 ); + StopUserEvent(); + ShowCursor( TRUE ); + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)1); + return; + } + } +//#endif + + if( !pStartEntry ) + { + pStartEntry = pView->First(); + } + +#ifdef XX_OV + ULONG nXAbsPos = (USHORT)pTree->GetAbsPos( pStartEntry ); + ULONG nXVisPos = pView->GetVisiblePos( pStartEntry ); + SvLBoxString* pXStr = (SvLBoxString*)pStartEntry->GetFirstItem( SV_ITEM_ID_LBOXSTRING); +#endif + + + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + long nRectHeight = rRect.GetHeight(); + long nEntryHeight = pView->GetEntryHeight(); + + int bHorSBar; + if( (pView->nWindowStyle) & WB_HSCROLL ) + bHorSBar = TRUE; + else + bHorSBar = FALSE; + + // Bereich der zu zeichnenden Entries berechnen + USHORT nStartLine = (USHORT)( rRect.Top() / nEntryHeight ); + USHORT nCount = (USHORT)( nRectHeight / nEntryHeight ); + nCount += 2; // keine Zeile vergessen + + long nY = nStartLine * nEntryHeight; + SvLBoxEntry* pEntry = pStartEntry; + while( nStartLine && pEntry ) + { + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + nStartLine--; + } + + Region aClipRegion( GetClipRegionRect() ); + + // erst die Linien Zeichnen, dann clippen! + pView->SetClipRegion(); + if( nWinBits & ( WB_HASLINES | WB_HASLINESATROOT ) ) + DrawNet(); + + pView->SetClipRegion( aClipRegion ); + + for( USHORT n=0; n< nCount && pEntry; n++ ) + { + /*long nMaxRight=*/ + pView->PaintEntry1( pEntry, nY, 0xffff, TRUE ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + if( !pCursor ) + { + if( aSelEng.GetSelectionMode()==SINGLE_SELECTION ) + { + if( nWinBits & WB_NOINITIALSELECTION ) + { + // nicht selektieren + SetCursor( pStartEntry, TRUE ); + } + else + SetCursor( pStartEntry ); + } + else + // nicht selektieren + SetCursor( pStartEntry, TRUE ); + //OV, 16.7.97, warum HideFocus?? (siehe Bugid 41404) + //pView->HideFocus(); + } + nFlags &= (~F_DESEL_ALL); + + pView->SetClipRegion(); + Rectangle aRect; + if( !(nFlags & F_PAINTED) ) + { + nFlags |= F_PAINTED; + RepaintScrollBars(); + } + nFlags &= (~F_IN_PAINT); +} + +void SvImpLBox::MakeVisible( SvLBoxEntry* pEntry, BOOL bMoveToTop ) +{ + if( !pEntry ) + return; + + BOOL bInView = IsEntryInView( pEntry ); + + if( bInView && (!bMoveToTop || pStartEntry == pEntry) ) + return; // ist schon sichtbar + + if( pStartEntry || (nWinBits & WB_FORCE_MAKEVISIBLE) ) + nFlags &= (~F_FILLING); + if( !bInView ) + { + if( !pView->IsEntryVisible(pEntry) ) // Parent(s) zugeklappt ? + { + SvLBoxEntry* pParent = pView->GetParent( pEntry ); + while( pParent ) + { + if( !pView->IsExpanded( pParent ) ) + { + BOOL bRet = pView->Expand( pParent ); + DBG_ASSERT(bRet,"Not expanded!"); + } + pParent = pView->GetParent( pParent ); + } + // Passen Childs der Parents in View oder muessen wir scrollen ? + if( IsEntryInView( pEntry ) && !bMoveToTop ) + return; // Scrollen nicht noetig -> tschuess + } + } + + pStartEntry = pEntry; + ShowCursor( FALSE ); + FillView(); + aVerSBar.SetThumbPos( (long)(pView->GetVisiblePos( pStartEntry )) ); + ShowCursor( TRUE ); + pView->Invalidate(); +} + + +void SvImpLBox::RepaintSelectionItems() +{ + if( !pView->GetVisibleCount() ) + return; + + if( !pStartEntry ) + pStartEntry = pView->First(); + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + ShowCursor( FALSE ); + + long nEntryHeight = pView->GetEntryHeight(); + + USHORT nCount = nVisibleCount; + long nY = 0; + SvLBoxEntry* pEntry = pStartEntry; + for( USHORT n=0; n< nCount && pEntry; n++ ) + { + pView->PaintEntry1( pEntry, nY, 0xffff ); //wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + ShowCursor( TRUE ); +} + + +void SvImpLBox::DrawNet() +{ + if( pView->GetVisibleCount() < 2 && !pStartEntry->HasChildsOnDemand() && + !pStartEntry->HasChilds() ) + return; + long nEntryHeight = pView->GetEntryHeight(); + long nEntryHeightDIV2 = nEntryHeight / 2; + if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001)) + nEntryHeightDIV2--; + + SvLBoxEntry* pChild; + SvLBoxEntry* pEntry = pStartEntry; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + while( pTree->GetDepth( pEntry ) > 0 ) + pEntry = pView->GetParent( pEntry ); + USHORT nOffs = (USHORT)(pView->GetVisiblePos( pStartEntry ) - + pView->GetVisiblePos( pEntry )); + long nY = 0; + nY -= ( nOffs * nEntryHeight ); + + DBG_ASSERT(pFirstDynamicTab,"No Tree!") + + Color aOldLineColor = pView->GetLineColor(); + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + Color aCol= rStyleSettings.GetFaceColor(); + + if( aCol.IsRGBEqual( pView->GetBackground().GetColor()) ) + aCol = rStyleSettings.GetShadowColor(); + pView->SetLineColor( aCol ); + Point aPos1, aPos2; + USHORT nDistance; + USHORT nMax = nVisibleCount + nOffs + 1; + for( USHORT n=0; n< nMax && pEntry; n++ ) + { + if( pView->IsExpanded(pEntry) ) + { + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += aExpNodeBmp.GetSizePixel().Width() / 2; + + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + + pChild = pView->FirstChild( pEntry ); + DBG_ASSERT(pChild,"Child?") + pChild = pTree->LastSibling( pChild ); + nDistance = (USHORT)(pView->GetVisiblePos(pChild) - + pView->GetVisiblePos(pEntry)); + aPos2 = aPos1; + aPos2.Y() += nDistance * nEntryHeight; + pView->DrawLine( aPos1, aPos2 ); + } + // Sichtbar im Control ? + if( n>= nOffs && ((nWinBits & WB_HASLINESATROOT) || !pTree->IsAtRootDepth(pEntry))) + { + // kann aPos1 recyclet werden ? + if( !pView->IsExpanded(pEntry) ) + { + // njet + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += aExpNodeBmp.GetSizePixel().Width() / 2; + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + aPos2.X() = aPos1.X(); + } + aPos2.Y() = aPos1.Y(); + aPos2.X() -= pView->GetIndent(); + pView->DrawLine( aPos1, aPos2 ); + } + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( nWinBits & WB_HASLINESATROOT ) + { + pEntry = pView->First(); + aPos1.X() = pView->GetTabPos( pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += aExpNodeBmp.GetSizePixel().Width() / 2; + aPos1.X() -= pView->GetIndent(); + aPos1.Y() = GetEntryLine( pEntry ); + aPos1.Y() += nEntryHeightDIV2; + pChild = pTree->LastSibling( pEntry ); + aPos2.X() = aPos1.X(); + aPos2.Y() = GetEntryLine( pChild ); + aPos2.Y() += nEntryHeightDIV2; + pView->DrawLine( aPos1, aPos2 ); + } + pView->SetLineColor( aOldLineColor ); +} + + +static long GetOptSize( TabBar* pTabBar ) +{ +#if SUPD > 373 + return pTabBar->CalcWindowSizePixel().Width(); +#else + long nWidth = 0; + USHORT nCount = pTabBar->GetPageCount(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + USHORT nId = pTabBar->GetPageId( nCur ); + nWidth+= pTabBar->GetTextSize(pTabBar->GetPageText(nId)).Width(); + nWidth += 18; + } + return nWidth; +#endif +} + +void SvImpLBox::PositionScrollBars( Size& rSize, USHORT nMask ) +{ + long nOverlap = 0; + + Size aVerSize( nVerSBarWidth, rSize.Height() ); + Size aHorSize( rSize.Width(), nHorSBarHeight ); + long nTabBarWidth = 0; + if( pTabBar ) + { + nTabBarWidth = GetOptSize( pTabBar ); + long nMaxWidth = (rSize.Width() * 700) / 1000; + if( nTabBarWidth > nMaxWidth ) + { + nTabBarWidth = nMaxWidth; + pTabBar->SetStyle( pTabBar->GetStyle() | WB_MINSCROLL ); + } + else + { + WinBits nStyle = pTabBar->GetStyle(); + nStyle &= ~(WB_MINSCROLL); + pTabBar->SetStyle( nStyle ); + } + aHorSize.Width() -= nTabBarWidth; + Size aTabSize( pTabBar->GetSizePixel() ); + aTabSize.Width() = nTabBarWidth; + pTabBar->SetSizePixel( aTabSize ); + } + if( nMask & 0x0001 ) + aHorSize.Width() -= nVerSBarWidth; + if( nMask & 0x0002 ) + aVerSize.Height() -= nHorSBarHeight; + + aVerSize.Height() += 2 * nOverlap; + Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap ); + aVerSBar.SetPosSizePixel( aVerPos, aVerSize ); + + aHorSize.Width() += 2 * nOverlap; + Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap ); + if( pTabBar ) + pTabBar->SetPosPixel( aHorPos ); + aHorPos.X() += nTabBarWidth; + aHorSBar.SetPosSizePixel( aHorPos, aHorSize ); + + if( nMask & 0x0001 ) + rSize.Width() = aVerPos.X(); + if( nMask & 0x0002 ) + rSize.Height() = aHorPos.Y(); + if( pTabBar ) + pTabBar->Show(); + + if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) ) + aScrBarBox.Show(); + else + aScrBarBox.Hide(); + +} + +// nResult: Bit0 == VerSBar Bit1 == HorSBar +USHORT SvImpLBox::AdjustScrollBars( Size& rSize ) +{ + long nEntryHeight = pView->GetEntryHeight(); + if( !nEntryHeight ) + return 0; + + USHORT nResult = 0; + + Size aOSize( pView->Control::GetOutputSizePixel() ); + + int bVerSBar = pView->nWindowStyle & WB_VSCROLL; + int bHorBar = 0; + long nMaxRight = aOSize.Width(); //GetOutputSize().Width(); + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin.X() *= -1; + nMaxRight += aOrigin.X() - 1; + long nVis = nMostRight - aOrigin.X(); + if( pTabBar || ( + (pView->nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) )) + bHorBar = 1; + + // Anzahl aller nicht eingeklappten Eintraege + ULONG nTotalCount = pView->GetVisibleCount(); + + // Anzahl in der View sichtbarer Eintraege + nVisibleCount = aOSize.Height() / nEntryHeight; + + // muessen wir eine vertikale Scrollbar einblenden? + if( bVerSBar || nTotalCount > nVisibleCount - 1 ) + { + nResult = 1; + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + nMaxRight -= nVerSBarWidth; + if( !bHorBar ) + { + if( (pView->nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) ) + bHorBar = 1; + } + } + + // muessen wir eine horizontale Scrollbar einblenden? + if( bHorBar ) + { + nResult |= 0x0002; + // die Anzahl der in der View sichtbaren Eintraege + // muss neu berechnet werden, da die horizontale + // ScrollBar eingeblendet wird + nVisibleCount = (aOSize.Height() - nHorSBarHeight) / nEntryHeight; + // eventuell brauchen wir jetzt doch eine vertikale ScrollBar + if( !(nResult & 0x0001) && + ((nTotalCount > nVisibleCount - 1) || bVerSBar) ) + { + nResult = 3; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + + PositionScrollBars( aOSize, nResult ); + + // Range, VisibleRange usw. anpassen + + // Output-Size aktualisieren, falls wir scrollen muessen + Rectangle aRect; + aRect.SetSize( aOSize ); + aSelEng.SetVisibleArea( aRect ); + + // Vertikale ScrollBar + long nTemp = (long)nVisibleCount; + nTemp--; + if( nTemp != aVerSBar.GetVisibleSize() ) + { + if( !bInVScrollHdl ) + { + aVerSBar.SetPageSize( nTemp - 1 ); + aVerSBar.SetVisibleSize( nTemp ); + } + else + { + nFlags |= F_ENDSCROLL_SET_VIS_SIZE; + nNextVerVisSize = nTemp; + } + } + + // Horizontale ScrollBar + nTemp = aHorSBar.GetThumbPos(); + aHorSBar.SetVisibleSize( aOSize.Width() ); + long nNewThumbPos = aHorSBar.GetThumbPos(); + Range aRange( aHorSBar.GetRange() ); + if( aRange.Max() < nMostRight+25 ) + { + aRange.Max() = nMostRight+25; + aHorSBar.SetRange( aRange ); + } + + if( nTemp != nNewThumbPos ) + { + nTemp = nNewThumbPos - nTemp; + if( pView->IsEditingActive() ) + { + pView->EndEditing( TRUE ); // Cancel + pView->Update(); + } + pView->nFocusWidth = -1; + KeyLeftRight( nTemp ); + } + + if( nResult & 0x0001 ) + aVerSBar.Show(); + else + aVerSBar.Hide(); + + if( nResult & 0x0002 ) + aHorSBar.Show(); + else + { + if( !pTabBar ) + aHorSBar.Hide(); + } + rSize = aOSize; + return nResult; +} + +void SvImpLBox::InitScrollBarBox() +{ + aScrBarBox.SetSizePixel( Size(nVerSBarWidth, nHorSBarHeight) ); + Size aSize( pView->Control::GetOutputSizePixel() ); + aScrBarBox.SetPosPixel( Point(aSize.Width()-nVerSBarWidth, aSize.Height()-nHorSBarHeight)); +} + +void SvImpLBox::Resize() +{ + Size aSize( pView->Control::GetOutputSizePixel()); + if( aSize.Width() <= 0 || aSize.Height() <= 0 ) + return; + nFlags |= F_IN_RESIZE; + InitScrollBarBox(); + + if( pView->GetEntryHeight()) + { + AdjustScrollBars( aOutputSize ); + FillView(); + } + // !!!HACK, da in Floating- & Docking-Windows nach Resizes + // die Scrollbars nicht richtig, bzw. ueberhaupt nicht gezeichnet werden + if( aHorSBar.IsVisible()) + aHorSBar.Invalidate(); + if( aVerSBar.IsVisible()) + aVerSBar.Invalidate(); + nFlags &= (~(F_IN_RESIZE | F_PAINTED)); +} + +void SvImpLBox::FillView() +{ + if( !pStartEntry ) + { + USHORT nVisibleCount = (USHORT)(pView->GetVisibleCount()); + USHORT nTempThumb = (USHORT)aVerSBar.GetThumbPos(); + if( nTempThumb >= nVisibleCount ) + nTempThumb = nVisibleCount - 1; + pStartEntry = (SvLBoxEntry*)(pView->GetEntryAtVisPos(nTempThumb)); + } + if( pStartEntry ) + { + USHORT nLast = (USHORT)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + USHORT nThumb = (USHORT)(pView->GetVisiblePos( pStartEntry )); + USHORT nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + ShowCursor( FALSE ); + // Fenster fuellen, indem der Thumb schrittweise + // nach oben bewegt wird + BOOL bFound = FALSE; + SvLBoxEntry* pTemp = pStartEntry; + while( nCurDispEntries < nVisibleCount && pTemp ) + { + pTemp = (SvLBoxEntry*)(pView->PrevVisible(pStartEntry)); + if( pTemp ) + { + nThumb--; + pStartEntry = pTemp; + nCurDispEntries++; + bFound = TRUE; + } + } + if( bFound ) + { + aVerSBar.SetThumbPos( nThumb ); + ShowCursor( TRUE ); // Focusrect neu berechnen + pView->Invalidate(); + } + } + } +} + + + + +void SvImpLBox::ShowVerSBar() +{ + USHORT bVerBar = pView->nWindowStyle & WB_VSCROLL; + ULONG nVis; + if( !bVerBar ) + nVis = pView->GetVisibleCount(); + if( bVerBar || (nVisibleCount && nVis > (ULONG)(nVisibleCount-1)) ) + { + if( !aVerSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + if( GetUpdateMode() ) + aVerSBar.Update(); + } + } + else + { + if( aVerSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } + + long nMaxRight = GetOutputSize().Width(); + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + nMaxRight = nMaxRight + aPos.X() - 1; + if( nMaxRight < nMostRight ) + { + if( !aHorSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + if( GetUpdateMode() ) + aHorSBar.Update(); + } + else + { + Range aRange( aHorSBar.GetRange() ); + if( aRange.Max() < nMostRight+25 ) + { + aRange.Max() = nMostRight+25; + aHorSBar.SetRange( aRange ); + } + else + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } + } + else + { + if( aHorSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } +} + + +void SvImpLBox::SyncVerThumb() +{ + if( pStartEntry ) + { + long nEntryPos = pView->GetVisiblePos( pStartEntry ); + aVerSBar.SetThumbPos( nEntryPos ); + } + else + aVerSBar.SetThumbPos( 0 ); +} + +BOOL SvImpLBox::IsEntryInView( SvLBoxEntry* pEntry ) const +{ + // Parent eingeklappt + if( !pView->IsEntryVisible(pEntry) ) + return FALSE; + long nY = GetEntryLine( pEntry ); + if( nY < 0 ) + return FALSE; + long nMax = nVisibleCount * pView->GetEntryHeight(); + if( nY >= nMax ) + return FALSE; + return TRUE; +} + + +long SvImpLBox::GetEntryLine( SvLBoxEntry* pEntry ) const +{ + if(!pStartEntry ) + return -1; // unsichtbare Position + + long nFirstVisPos = pView->GetVisiblePos( pStartEntry ); + long nEntryVisPos = pView->GetVisiblePos( pEntry ); + nFirstVisPos = nEntryVisPos - nFirstVisPos; + nFirstVisPos *= pView->GetEntryHeight(); + return nFirstVisPos; +} + +void SvImpLBox::SetEntryHeight( short /* nHeight */ ) +{ + SetNodeBmpYOffset( aExpNodeBmp ); + SetNodeBmpYOffset( aCollNodeBmp ); + if(!pView->HasViewData()) // stehen wir im Clear? + { + Size aSize = pView->Control::GetOutputSizePixel(); + AdjustScrollBars( aSize ); + } + else + { + Resize(); + if( GetUpdateMode() ) + pView->Invalidate(); + } +} + + + +// *********************************************************************** +// Callback-Functions +// *********************************************************************** + +void SvImpLBox::IndentChanged( short /* nIndentPixel */ ) {} + +void SvImpLBox::EntryExpanded( SvLBoxEntry* pEntry ) +{ + // SelAllDestrAnch( FALSE, TRUE ); //DeselectAll(); + if( GetUpdateMode() ) + { + ShowCursor( FALSE ); + long nY = GetEntryLine( pEntry ); + if( IsLineVisible(nY) ) + { + InvalidateEntriesFrom( nY ); + FindMostRight( pEntry, 0 ); + } + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + // falls vor dem Thumb expandiert wurde, muss + // die Thumb-Position korrigiert werden. + SyncVerThumb(); + ShowVerSBar(); + ShowCursor( TRUE ); + } +} + +void SvImpLBox::EntryCollapsed( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) ) + return; + + ShowCursor( FALSE ); + + if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) ) + { + FindMostRight(0); + } + + if( pStartEntry ) + { + long nOldThumbPos = aVerSBar.GetThumbPos(); + ULONG nVisList = pView->GetVisibleCount(); + aVerSBar.SetRange( Range(0, nVisList-1) ); + long nNewThumbPos = aVerSBar.GetThumbPos(); + if( nNewThumbPos != nOldThumbPos ) + { + pStartEntry = pView->First(); + USHORT nDistance = (USHORT)nNewThumbPos; + if( nDistance ) + pStartEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, + nDistance)); + if( GetUpdateMode() ) + pView->Invalidate(); + } + else + SyncVerThumb(); + ShowVerSBar(); + } + // wurde Cursor eingeklappt ? + if( pTree->IsChild( pEntry, pCursor ) ) + SetCursor( pEntry ); + if( GetUpdateMode() ) + ShowVerSBar(); + ShowCursor( TRUE ); + if( GetUpdateMode() ) + pView->Select( pCursor, TRUE ); +} + +void SvImpLBox::CollapsingEntry( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) || !pStartEntry ) + return; + + SelAllDestrAnch( FALSE, TRUE ); // deselectall + + // ist der eingeklappte Parent sichtbar ? + long nY = GetEntryLine( pEntry ); + if( IsLineVisible(nY) ) + { + if( GetUpdateMode() ) + InvalidateEntriesFrom( nY ); + } + else + { + if( pTree->IsChild(pEntry, pStartEntry) ) + { + pStartEntry = pEntry; + if( GetUpdateMode() ) + pView->Invalidate(); + } + } +} + + +void SvImpLBox::SetNodeBmpYOffset( const Image& rBmp ) +{ + Size aSize; + nYoffsNodeBmp = pView->GetHeightOffset( rBmp, aSize ); + nNodeBmpWidth = aSize.Width(); +} + +void SvImpLBox::SetNodeBmpTabDistance() +{ + nNodeBmpTabDistance = -pView->GetIndent(); + if( pView->nContextBmpWidthMax ) + { + // nur, wenn der erste dynamische Tab zentriert ist + // (setze ich momentan voraus) + Size aSize = aExpNodeBmp.GetSizePixel(); + nNodeBmpTabDistance -= aSize.Width() / 2; + } +} + +// +// korrigiert bei SingleSelection den Cursor +// +void SvImpLBox::EntrySelected( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + if( nFlags & F_IGNORE_SELECT ) + return; + + /* + if( (nWinBits & WB_HIDESELECTION) && pEntry && !pView->HasFocus() ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->SetCursored( bSelect ); + } + */ + + nFlags &= (~F_DESEL_ALL); + if( bSelect && + aSelEng.GetSelectionMode() == SINGLE_SELECTION && + pEntry != pCursor ) + { + SetCursor( pEntry ); + DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?") + } + + if( GetUpdateMode() && pView->IsEntryVisible(pEntry) ) + { + long nY = GetEntryLine( pEntry ); + if( IsLineVisible( nY ) ) + { + ShowCursor( FALSE ); + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + ShowCursor( TRUE ); + } + } +} + + +void SvImpLBox::RemovingEntry( SvLBoxEntry* pEntry ) +{ + DestroyAnchor(); + + if( !pView->IsEntryVisible( pEntry ) ) + { + // wenn Parent eingeklappt, dann tschuess + nFlags |= F_REMOVED_ENTRY_INVISIBLE; + return; + } + + if( pEntry == pMostRightEntry || ( + pEntry->HasChilds() && pView->IsExpanded(pEntry) && + pTree->IsChild(pEntry, pMostRightEntry))) + { + nFlags |= F_REMOVED_RECALC_MOST_RIGHT; + } + + SvLBoxEntry* pOldStartEntry = pStartEntry; + + SvLBoxEntry* pParent = (SvLBoxEntry*)(pView->GetModel()->GetParent(pEntry)); + + if( pParent && pView->GetModel()->GetChildList(pParent)->Count() == 1 ) + { + DBG_ASSERT( pView->IsExpanded( pParent ), "Parent not expanded"); + pParent->SetFlags( pParent->GetFlags() | SV_ENTRYFLAG_NO_NODEBMP); + InvalidateEntry( pParent ); + } + + if( pCursor && pTree->IsChild( pEntry, pCursor) ) + pCursor = pEntry; + if( pStartEntry && pTree->IsChild(pEntry,pStartEntry) ) + pStartEntry = pEntry; + + SvLBoxEntry* pTemp; + if( pCursor && pCursor == pEntry ) + { + if( bSimpleTravel ) + pView->Select( pCursor, FALSE ); + ShowCursor( FALSE ); // Focus-Rect weg + // NextSibling, weil auch Childs des Cursors geloescht werden + pTemp = pView->NextSibling( pCursor ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + + SetCursor( pTemp, TRUE ); + } + if( pStartEntry && pStartEntry == pEntry ) + { + pTemp = pView->NextSibling( pStartEntry ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + pStartEntry = pTemp; + } + if( GetUpdateMode()) + { + // wenns der letzte ist, muss invalidiert werden, damit die Linien + // richtig gezeichnet (in diesem Fall geloescht) werden. + if( pStartEntry && (pStartEntry != pOldStartEntry || pEntry == (SvLBoxEntry*)pView->GetModel()->Last()) ) + { + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry )); + pView->Invalidate( GetVisibleArea() ); + } + else + InvalidateEntriesFrom( GetEntryLine( pEntry ) ); + } +} + +void SvImpLBox::EntryRemoved() +{ + if( nFlags & F_REMOVED_ENTRY_INVISIBLE ) + { + nFlags &= (~F_REMOVED_ENTRY_INVISIBLE); + return; + } + if( !pStartEntry ) + pStartEntry = pTree->First(); + if( !pCursor ) + SetCursor( pStartEntry, TRUE ); + + if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() )) + pView->Select( pCursor, TRUE ); + + if( GetUpdateMode()) + { + if( nFlags & F_REMOVED_RECALC_MOST_RIGHT ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + FillView(); + if( pStartEntry ) + // falls ueber dem Thumb geloescht wurde + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry) ); + + ShowVerSBar(); + if( pCursor && pView->HasFocus() && !pView->IsSelected(pCursor) ) + { + if( pView->GetSelectionCount() ) + { + // ist ein benachbarter Eintrag selektiert? + SvLBoxEntry* pNextCursor = (SvLBoxEntry*)pView->PrevVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + pNextCursor = (SvLBoxEntry*)pView->NextVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + // kein Nachbar selektiert: Ersten selektierten nehmen + pNextCursor = pView->FirstSelected(); + SetCursor( pNextCursor ); + MakeVisible( pCursor ); + } + else + pView->Select( pCursor, TRUE ); + } + ShowCursor( TRUE ); + } + nFlags &= (~F_REMOVED_RECALC_MOST_RIGHT); +} + + +void SvImpLBox::MovingEntry( SvLBoxEntry* pEntry ) +{ + int bDeselAll = nFlags & F_DESEL_ALL; + SelAllDestrAnch( FALSE, TRUE ); // DeselectAll(); + if( !bDeselAll ) + nFlags &= (~F_DESEL_ALL); + + if( pEntry == pCursor ) + ShowCursor( FALSE ); + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); + if( pEntry == pStartEntry ) + { + SvLBoxEntry* pNew = 0; + if( !pEntry->HasChilds() ) + { + pNew = (SvLBoxEntry*)(pView->NextVisible( pStartEntry )); + if( !pNew ) + pNew = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + } + else + { + pNew = pTree->NextSibling( pEntry ); + if( !pNew ) + pNew = pTree->PrevSibling( pEntry ); + } + pStartEntry = pNew; + } +} + +void SvImpLBox::EntryMoved( SvLBoxEntry* pEntry ) +{ + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1)); + USHORT nFirstPos = (USHORT)pTree->GetAbsPos( pStartEntry ); + USHORT nNewPos = (USHORT)pTree->GetAbsPos( pEntry ); + FindMostRight(0); + if( nNewPos < nFirstPos ) + { + //!!!Notloesung + pStartEntry = pEntry; + SyncVerThumb(); + } + if( pEntry == pCursor ) + { + if( pView->IsEntryVisible( pCursor ) ) + ShowCursor( TRUE ); + else + { + SvLBoxEntry* pParent = pEntry; + do { + pParent = pTree->GetParent( pParent ); + } + while( !pView->IsEntryVisible( pParent ) ); + SetCursor( pParent ); + } + } + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); +} + + + +void SvImpLBox::EntryInserted( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + SvLBoxEntry* pParent = (SvLBoxEntry*)pTree->GetParent(pEntry); + if( pParent && pTree->GetChildList(pParent)->Count() == 1 ) + // Pluszeichen zeichnen + pTree->InvalidateEntry( pParent ); + + if( !pView->IsEntryVisible( pEntry ) ) + return; + int bDeselAll = nFlags & F_DESEL_ALL; + if( bDeselAll ) + SelAllDestrAnch( FALSE, TRUE ); + else + DestroyAnchor(); + // nFlags &= (~F_DESEL_ALL); +// ShowCursor( FALSE ); // falls sich Cursor nach unten verschiebt + long nY = GetEntryLine( pEntry ); + BOOL bEntryVisible = IsLineVisible( nY ); + BOOL bPrevEntryVisible = IsLineVisible(nY-pView->GetEntryHeight()); + if( bEntryVisible ) + { + ShowCursor( FALSE ); // falls sich Cursor nach unten verschiebt + nY -= pView->GetEntryHeight(); // wg. Linien + InvalidateEntriesFrom( nY ); + } + else if( pStartEntry && nY < GetEntryLine(pStartEntry) ) + { + // pruefen, ob die View komplett gefuellt ist. Wenn + // nicht, dann pStartEntry und den Cursor anpassen + // (automatisches scrollen) + USHORT nLast = (USHORT)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + USHORT nThumb = (USHORT)(pView->GetVisiblePos( pStartEntry )); + USHORT nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + // beim naechsten Paint-Event setzen + pStartEntry = 0; + SetCursor( 0 ); + pView->Invalidate(); + } + } + else if( !pStartEntry ) + pView->Invalidate(); + + // die Linien invalidieren + /* + if( (bEntryVisible || bPrevEntryVisible) && + (nWinBits & ( WB_HASLINES | WB_HASLINESATROOT )) ) + { + SvLBoxTab* pTab = pView->GetFirstDynamicTab(); + if( pTab ) + { + long nDX = pView->GetTabPos( pEntry, pTab ); + Point aTmpPoint; + Size aSize( nDX, nY ); + Rectangle aRect( aTmpPoint, aSize ); + pView->Invalidate( aRect ); + } + } + */ + + SetMostRight( pEntry ); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1)); + SyncVerThumb(); // falls vor Thumb eingefuegt wurde + ShowVerSBar(); + ShowCursor( TRUE ); +//#if SUPD > 364 + if( pStartEntry != pView->First() && (nFlags & F_FILLING) ) + pView->Update(); +//#endif + } +} + + + +// ******************************************************************** +// Eventhandler +// ******************************************************************** + + +// ****** Steuerung der Controlanimation + +BOOL SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvLBoxEntry* pEntry, + long nY ) +{ + SvLBoxItem* pItem = pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&pActiveTab); + if( pItem && (pItem->IsA()==SV_ITEM_ID_LBOXBUTTON)) + { + pActiveButton = (SvLBoxButton*)pItem; + pActiveEntry = pEntry; + if( pCursor == pActiveEntry ) + pView->HideFocus(); + pView->CaptureMouse(); + pActiveButton->SetStateHilighted( TRUE ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + return TRUE; + } + else + pActiveButton = 0; + return FALSE; +} + +BOOL SvImpLBox::MouseMoveCheckCtrl( const MouseEvent& rMEvt, SvLBoxEntry* pEntry) +{ + if( pActiveButton ) + { + long nY; + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem(pActiveEntry, nMouseX) == pActiveButton ) + { + if( !pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(TRUE ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + } + } + else + { + if( pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(FALSE ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, SV_LBOXTAB_PUSHABLE ); + } + } + return TRUE; + } + return FALSE; +} + +BOOL SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt ) +{ + if( pActiveButton ) + { + pView->ReleaseMouse(); + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + long nY = GetEntryLine( pActiveEntry ); + pActiveButton->SetStateHilighted( FALSE ); + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem( pActiveEntry, nMouseX ) == pActiveButton ) + pActiveButton->ClickHdl( pView, pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + if( pCursor == pActiveEntry ) + ShowCursor( TRUE ); + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + return TRUE; + } + return FALSE; +} + +// ******* Steuerung Plus/Minus-Button zum Expandieren/Kollabieren + +// FALSE == kein Expand/Collapse-Button getroffen +BOOL SvImpLBox::IsNodeButton( const Point& rPosPixel, SvLBoxEntry* pEntry ) const +{ + if( !pEntry->HasChilds() && !pEntry->HasChildsOnDemand() ) + return FALSE; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + if( !pFirstDynamicTab ) + return FALSE; + + long nMouseX = rPosPixel.X(); + // in Doc-Koords umrechnen + Point aOrigin( pView->GetMapMode().GetOrigin() ); + nMouseX -= aOrigin.X(); + + long nX = pView->GetTabPos( pEntry, pFirstDynamicTab); + nX += nNodeBmpTabDistance; + if( nMouseX < nX ) + return FALSE; + nX += nNodeBmpWidth; + if( nMouseX > nX ) + return FALSE; + return TRUE; +} + +// FALSE == kein Expand/Collapse-Button getroffen +BOOL SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, + SvLBoxEntry* pEntry, long /* nY */ ) +{ + // beim Inplace-Ed. gunnix machen + if( pView->IsEditingActive() && pEntry == pView->pEdEntry ) + return TRUE; + + if( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) ) + { + if( rMEvt.GetClicks() == 1 ) + { + if( pView->IsExpanded(pEntry) ) + { + pView->EndEditing( TRUE ); + pView->Collapse( pEntry ); + } + else + { + //einen Entry, der editiert wird, darf man aufklappen + pView->Expand( pEntry ); + } + } + return TRUE; + } + return FALSE; +} + +void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( !rMEvt.IsLeft() && !rMEvt.IsRight()) + return; + +#ifdef OS2 + // unter OS/2 kommt zwischen MouseButtonDown und + // MouseButtonUp ein MouseMove + nFlags |= F_IGNORE_NEXT_MOUSEMOVE; +#endif + aEditTimer.Stop(); + Point aPos( rMEvt.GetPosPixel()); + + if( aPos.X() > aOutputSize.Width() || aPos.Y() > aOutputSize.Height() ) + return; + + nFlags &= (~F_FILLING); + pView->GrabFocus(); + SvLBoxEntry* pEntry = GetEntry( aPos ); + if( !pEntry ) + return; + + long nY = GetEntryLine( pEntry ); + // Node-Button? + if( ButtonDownCheckExpand( rMEvt, pEntry, nY ) ) + return; + + if( !EntryReallyHit(pEntry,aPos,nY)) + return; + +//#if defined(MAC) || defined(OV_DEBUG) + SvLBoxItem* pXItem = pView->GetItem( pEntry, aPos.X() ); + if( pXItem ) + { + SvLBoxTab* pXTab = pView->GetTab( pEntry, pXItem ); + if( !rMEvt.IsMod1() && !rMEvt.IsMod2() &&pXTab->IsEditable() ) + nFlags |= F_START_EDITTIMER; +#ifndef MAC + if( !pView->IsSelected( pEntry )) + nFlags &= ~F_START_EDITTIMER; +#endif + } +//#endif + + + if( (rMEvt.GetClicks() % 2) == 0 ) + { +//#ifdef MAC + nFlags &= (~F_START_EDITTIMER); +//#endif + pView->pHdlEntry = pEntry; + if( pView->DoubleClickHdl() ) + { + // falls im Handler der Eintrag geloescht wurde + pEntry = GetClickedEntry( aPos ); + if( !pEntry ) + return; + if( pEntry != pView->pHdlEntry ) + { + // neu selektieren & tschuess + if( !bSimpleTravel && !aSelEng.IsAlwaysAdding()) + SelAllDestrAnch( FALSE, TRUE ); // DeselectAll(); + SetCursor( pEntry ); + return; + } + if( pEntry->HasChilds() || pEntry->HasChildsOnDemand() ) + { + if( pView->IsExpanded(pEntry) ) + pView->Collapse( pEntry ); + else + pView->Expand( pEntry ); + if( pEntry == pCursor ) // nur wenn Entryitem angeklickt wurde + // (Nodebutton ist kein Entryitem!) + pView->Select( pCursor, TRUE ); + return; + } + } + } + else + { + // CheckButton? (TreeListBox: Check + Info) + if( ButtonDownCheckCtrl(rMEvt, pEntry, nY) == TRUE) + return; + // Inplace-Editing? +//#ifndef MAC +#if 0 + if( rMEvt.IsMod2() && pView->IsInplaceEditingEnabled() ) + { + SvLBoxItem* pItem = pView->GetItem( pEntry, aPos.X() ); + if( pItem ) + pView->EditingRequest( pEntry, pItem, aPos ); + return; + } +#endif + } + aSelEng.SelMouseButtonDown( rMEvt ); +} + +void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt) +{ +#ifdef OS2 + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); +#endif + if(!ButtonUpCheckCtrl( rMEvt ) ) + aSelEng.SelMouseButtonUp( rMEvt ); + EndScroll(); +//#if defined(MAC) || defined(OV_DEBUG) + if( nFlags & F_START_EDITTIMER ) + { + nFlags &= (~F_START_EDITTIMER); + aEditTimer.Start(); + } +//#endif + + return; +} + +void SvImpLBox::MouseMove( const MouseEvent& rMEvt) +{ +#ifdef OS2 + if( nFlags & F_IGNORE_NEXT_MOUSEMOVE ) + { + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); + return; + } +#endif + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + if(!MouseMoveCheckCtrl( rMEvt, pEntry ) ) + aSelEng.SelMouseMove( rMEvt ); + return; +} + +BOOL SvImpLBox::KeyInput( const KeyEvent& rKEvt) +{ +//#if defined(MAC) || defined(OV_DEBUG) + aEditTimer.Stop(); +//#endif + + if( rKEvt.GetKeyCode().IsMod2() ) + return FALSE; // Alt-Taste nicht auswerten + + nFlags &= (~F_FILLING); + + if( !pCursor ) + pCursor = pStartEntry; + if( !pCursor ) + return FALSE; + + BOOL bKeyUsed = TRUE; + + USHORT nDelta = (USHORT)aVerSBar.GetPageSize(); + USHORT aCode = rKEvt.GetKeyCode().GetCode(); + + BOOL bShift = rKEvt.GetKeyCode().IsShift(); + BOOL bMod1 = rKEvt.GetKeyCode().IsMod1(); + + SvLBoxEntry* pNewCursor; + long nThumb; + + switch( aCode ) + { + case KEY_UP: + if( !IsEntryInView( pCursor ) ) + MakeVisible( pCursor ); + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + if( pNewCursor ) + { + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyUp( FALSE ); + } + } + break; + + case KEY_DOWN: + if( !IsEntryInView( pCursor ) ) + MakeVisible( pCursor ); + pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pCursor )); + if( pNewCursor ) + { + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + if( pCursor ) + pView->Select( pCursor, FALSE ); + KeyDown( FALSE ); + SetCursor( pNewCursor ); + } + } + else + KeyDown( FALSE ); // weil ScrollBar-Range evtl. noch + // scrollen erlaubt + break; + + case KEY_RIGHT: + if( pView->nWindowStyle & WB_HSCROLL ) + { + nThumb = aHorSBar.GetThumbPos(); + nThumb += aHorSBar.GetLineSize(); + long nOldThumb = aHorSBar.GetThumbPos(); + aHorSBar.SetThumbPos( nThumb ); + nThumb = nOldThumb; + nThumb -= aHorSBar.GetThumbPos(); + nThumb *= -1; + if( nThumb ) + { + KeyLeftRight( nThumb ); + EndScroll(); + } + } + else + bKeyUsed = FALSE; + break; + + case KEY_LEFT: + if( pView->nWindowStyle & WB_HSCROLL ) + { + nThumb = aHorSBar.GetThumbPos(); + nThumb -= aHorSBar.GetLineSize(); + long nOldThumb = aHorSBar.GetThumbPos(); + aHorSBar.SetThumbPos( nThumb ); + nThumb = nOldThumb; + nThumb -= aHorSBar.GetThumbPos(); + if( nThumb ) + { + KeyLeftRight( -nThumb ); + EndScroll(); + } + } + else + bKeyUsed = FALSE; + break; + + case KEY_PAGEUP: + if( !bMod1 ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pCursor, nDelta )); + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(ULONG)pNewCursor!=(ULONG)pCursor,"Cursor?") + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyUp( TRUE ); + } + } + } + else + bKeyUsed = FALSE; + break; + + case KEY_PAGEDOWN: + if( !bMod1 ) + { + pNewCursor= (SvLBoxEntry*)(pView->NextVisible( pCursor, nDelta )); + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(ULONG)pNewCursor!=(ULONG)pCursor,"Cursor?") + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyDown( TRUE ); + } + } + else + KeyDown( FALSE ); // siehe KEY_DOWN + } + else + bKeyUsed = FALSE; + break; + + case KEY_SPACE: + if( pView->GetSelectionMode() >= MULTIPLE_SELECTION ) + { + if( !bShift && !bMod1 ) + { + if( aSelEng.IsAddMode() ) + { + // toggle selection + BOOL bSel = TRUE; + if( pView->IsSelected( pCursor )) + bSel = FALSE; + pView->Select( pCursor, bSel ); + } + else + { + SelAllDestrAnch( FALSE ); + pView->Select( pCursor, TRUE ); + } + } + } + break; + +#if 0 + // Probleme mit Default-OK-Button! + case KEY_RETURN: + if( pCursor->HasChilds() || pCursor->HasChildsOnDemand() ) + { + if( pView->IsExpanded(pCursor) ) + pView->Collapse( pCursor ); + else + pView->Expand( pCursor ); + } +#endif + + case KEY_F2: + if( !bShift && !bMod1 ) + EditTimerCall( 0 ); + break; + + case KEY_F8: + if( bShift && pView->GetSelectionMode()==MULTIPLE_SELECTION && + !(nWinBits & WB_SIMPLEMODE)) + { + if( aSelEng.IsAlwaysAdding() ) + aSelEng.AddAlways( FALSE ); + else + aSelEng.AddAlways( TRUE ); + } + break; + + +#ifdef OV_DEBUG + case KEY_F9: + MakeVisible( pCursor ); + break; + case KEY_F10: + pView->RemoveSelection(); + break; + case KEY_DELETE: + pView->RemoveEntry( pCursor ); + break; +#endif + + case KEY_ADD: + if( pCursor ) + { + if( !pView->IsExpanded(pCursor)) + pView->Expand( pCursor ); + if( bMod1 ) + { + USHORT nRefDepth = pTree->GetDepth( pCursor ); + SvLBoxEntry* pCur = pTree->Next( pCursor ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && !pView->IsExpanded(pCur)) + pView->Expand( pCur ); + pCur = pTree->Next( pCur ); + } + } + } + break; + + case KEY_A: + if( bMod1 ) + SelAllDestrAnch( TRUE ); + break; + + case KEY_SUBTRACT: + if( pCursor ) + { + if( pView->IsExpanded(pCursor)) + pView->Collapse( pCursor ); + if( bMod1 ) + { + // bis zur Root alle Parents einklappen + SvLBoxEntry* pParentToCollapse = (SvLBoxEntry*)pTree->GetRootLevelParent(pCursor); + if( pParentToCollapse ) + { + USHORT nRefDepth; + // Sonderbehandlung Explorer: Befindet sich auf der + // Root nur ein Eintrag,dann den Root-Entry nicht + // einklappen + if( pTree->GetChildList(0)->Count() < 2 ) + { + nRefDepth = 1; + pParentToCollapse = pCursor; + while( pTree->GetParent(pParentToCollapse) && + pTree->GetDepth( pTree->GetParent(pParentToCollapse)) > 0) + { + pParentToCollapse = pTree->GetParent(pParentToCollapse); + } + } + else + nRefDepth = 0; + + if( pView->IsExpanded(pParentToCollapse) ) + pView->Collapse( pParentToCollapse ); + SvLBoxEntry* pCur = pTree->Next( pParentToCollapse ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && pView->IsExpanded(pCur) ) + pView->Collapse( pCur ); + pCur = pTree->Next( pCur ); + } + } + } + } + break; + + case KEY_DIVIDE : + if( bMod1 ) + SelAllDestrAnch( TRUE ); + break; + + case KEY_COMMA : + if( bMod1 ) + SelAllDestrAnch( FALSE ); + break; + + case KEY_HOME : + pNewCursor = pView->GetModel()->First(); + if( pNewCursor && pNewCursor != pCursor ) + { +// SelAllDestrAnch( FALSE ); + aSelEng.CursorPosChanging( bShift, bMod1 ); + SetCursor( pNewCursor ); + if( !IsEntryInView( pNewCursor ) ) + MakeVisible( pNewCursor ); + } + break; + + case KEY_END : + pNewCursor = pView->GetModel()->Last(); + if( pNewCursor && pNewCursor != pCursor) + { +// SelAllDestrAnch( FALSE ); + aSelEng.CursorPosChanging( bShift, bMod1 ); + SetCursor( pNewCursor ); + if( !IsEntryInView( pNewCursor ) ) + MakeVisible( pNewCursor ); + } + break; + + + + default: + bKeyUsed = FALSE; + } + return bKeyUsed; +} + +void __EXPORT SvImpLBox::GetFocus() +{ + if( pCursor ) + { + pView->SetEntryFocus( pCursor, TRUE ); + ShowCursor( TRUE ); +// auskommentiert wg. deselectall +// if( bSimpleTravel && !pView->IsSelected(pCursor) ) +// pView->Select( pCursor, TRUE ); + } + if( nWinBits & WB_HIDESELECTION ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + /* + SvLBoxEntry* pEntry = pView->GetModel()->First(); + while( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + if( pViewData->IsCursored() ) + { + pViewData->SetCursored( FALSE ); + InvalidateEntry( pEntry ); + } + pEntry = pView->GetModel()->Next( pEntry ); + } + */ + + + } +} + +void __EXPORT SvImpLBox::LoseFocus() +{ +//#if defined(MAC) || defined(OV_DEBUG) + aEditTimer.Stop(); +//#endif + if( pCursor ) + pView->SetEntryFocus( pCursor,FALSE ); + ShowCursor( FALSE ); + + if( nWinBits & WB_HIDESELECTION ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + //pViewData->SetCursored( TRUE ); + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + } +} + + +// ******************************************************************** +// SelectionEngine +// ******************************************************************** + +inline void SvImpLBox::SelectEntry( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + pView->Select( pEntry, bSelect ); +} + +__EXPORT ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SelectionEngine* pSEng, + SvTreeListBox* pV ) +{ + pImp = pImpl; + pSelEng = pSEng; + pView = pV; +} + +__EXPORT ImpLBSelEng::~ImpLBSelEng() +{ +} + +void __EXPORT ImpLBSelEng::BeginDrag() +{ + pImp->BeginDrag(); +} + +/* +void __EXPORT ImpLBSelEng::EndDrag( const Point& ) +{ +} +*/ + +void __EXPORT ImpLBSelEng::CreateAnchor() +{ + pImp->pAnchor = pImp->pCursor; +} + +void __EXPORT ImpLBSelEng::DestroyAnchor() +{ + pImp->pAnchor = 0; +} + +/* +void __EXPORT ImpLBSelEng::CreateCursor() +{ + pImp->pAnchor = 0; +} +*/ + + +BOOL __EXPORT ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, BOOL bDontSelectAtCursor) +{ + SvLBoxEntry* pNewCursor = pImp->MakePointVisible( rPoint ); + if( pNewCursor != pImp->pCursor ) + pImp->BeginScroll(); + + if( pNewCursor ) + { + // bei SimpleTravel wird in SetCursor selektiert und + // der Select-Handler gerufen + //if( !bDontSelectAtCursor && !pImp->bSimpleTravel ) + // pImp->SelectEntry( pNewCursor, TRUE ); + pImp->SetCursor( pNewCursor, bDontSelectAtCursor ); + return TRUE; + } + return FALSE; +} + +BOOL __EXPORT ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( pEntry ) + return pView->IsSelected(pEntry); + return FALSE; +} + +void __EXPORT ImpLBSelEng::DeselectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, FALSE ); +} + +/* +void __EXPORT ImpLBSelEng::SelectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, TRUE ); +} +*/ + +void __EXPORT ImpLBSelEng::DeselectAll() +{ + pImp->SelAllDestrAnch( FALSE, FALSE ); // SelectionEngine nicht resetten! + pImp->nFlags &= (~F_DESEL_ALL); +} + +// *********************************************************************** +// Selektion +// *********************************************************************** + +void SvImpLBox::SetAnchorSelection(SvLBoxEntry* pOldCursor,SvLBoxEntry* pNewCursor) +{ + SvLBoxEntry* pEntry; + ULONG nAnchorVisPos = pView->GetVisiblePos( pAnchor ); + ULONG nOldVisPos = pView->GetVisiblePos( pOldCursor ); + ULONG nNewVisPos = pView->GetVisiblePos( pNewCursor ); + + if( nOldVisPos > nAnchorVisPos || + ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) ) + { + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos < nAnchorVisPos ) + { + pEntry = pAnchor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + + pEntry = pNewCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos < nOldVisPos ) + { + pEntry = pNewCursor; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + return; + } + } + else + { + if( nNewVisPos < nOldVisPos ) // Vergroessern der Selektion + { + pEntry = pNewCursor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos > nAnchorVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, FALSE ); + pEntry = pAnchor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, TRUE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, TRUE ); + return; + } + + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, FALSE ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + return; + } + } +} + +void SvImpLBox::SelAllDestrAnch( BOOL bSelect, BOOL bDestroyAnchor, + BOOL bSingleSelToo ) +{ + SvLBoxEntry* pEntry; + nFlags &= (~F_DESEL_ALL); + if( bSelect && bSimpleTravel ) + { + if( pCursor && !pView->IsSelected( pCursor )) + { + pView->Select( pCursor, TRUE ); + } + return; + } + if( !bSelect && pView->GetSelectionCount() == 0 ) + { + if( bSimpleTravel && ( !GetUpdateMode() || !pCursor) ) + nFlags |= F_DESEL_ALL; + return; + } + if( bSelect && pView->GetSelectionCount() == pView->GetEntryCount()) + return; + if( !bSingleSelToo && bSimpleTravel ) + return; + + if( !bSelect && pView->GetSelectionCount()==1 && pCursor && + pView->IsSelected( pCursor )) + { + pView->Select( pCursor, FALSE ); + if( bDestroyAnchor ) + DestroyAnchor(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + return; + } + + if( bSimpleTravel && !pCursor && !GetUpdateMode() ) + nFlags |= F_DESEL_ALL; + + ShowCursor( FALSE ); + BOOL bUpdate = GetUpdateMode(); + + nFlags |= F_IGNORE_SELECT; // EntryInserted soll nix tun + pEntry = pTree->First(); + while( pEntry ) + { + if( pView->Select( pEntry, bSelect ) ) + { + if( bUpdate && pView->IsEntryVisible(pEntry) ) + { + long nY = GetEntryLine( pEntry ); + if( IsLineVisible( nY ) ) + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + } + } + pEntry = pTree->Next( pEntry ); + } + nFlags &= ~F_IGNORE_SELECT; + + if( bDestroyAnchor ) + DestroyAnchor(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + ShowCursor( TRUE ); +} + +void SvImpLBox::SetSelectionMode( SelectionMode eSelMode ) +{ + aSelEng.SetSelectionMode( eSelMode); + if( eSelMode == SINGLE_SELECTION ) + bSimpleTravel = TRUE; + else + bSimpleTravel = FALSE; + if( (nWinBits & WB_SIMPLEMODE) && (eSelMode == MULTIPLE_SELECTION) ) + aSelEng.AddAlways( TRUE ); +} + +// *********************************************************************** +// Drag & Drop +// *********************************************************************** + +void SvImpLBox::SetDragDropMode( DragDropMode eDDMode ) +{ + if( eDDMode && eDDMode != SV_DRAGDROP_APP_DROP ) + { + aSelEng.ExpandSelectionOnMouseMove( FALSE ); + aSelEng.EnableDrag( TRUE ); + } + else + { + aSelEng.ExpandSelectionOnMouseMove( TRUE ); + aSelEng.EnableDrag( FALSE ); + } +} + +void SvImpLBox::BeginDrag() +{ + nFlags &= (~F_FILLING); + if( !bAsyncBeginDrag ) + { + BeginScroll(); + pView->BeginDrag( aSelEng.GetMousePosPixel() ); + EndScroll(); + } + else + { + aAsyncBeginDragPos = aSelEng.GetMousePosPixel(); + aAsyncBeginDragTimer.Start(); + } +} + +IMPL_LINK( SvImpLBox, BeginDragHdl, void*, EMPTYARG ) +{ + pView->BeginDrag( aAsyncBeginDragPos ); + return 0; +} + +void SvImpLBox::PaintDDCursor( SvLBoxEntry* pInsertionPos ) +{ + long nY; + if( pInsertionPos ) + { + nY = GetEntryLine( pInsertionPos ); + nY += pView->GetEntryHeight(); + } + else + nY = 1; + RasterOp eOldOp = pView->GetRasterOp(); + pView->SetRasterOp( ROP_INVERT ); + Color aOldLineColor = pView->GetLineColor(); + pView->SetLineColor( Color( COL_BLACK ) ); + pView->DrawLine( Point( 0, nY ), Point( aOutputSize.Width(), nY ) ); + pView->SetLineColor( aOldLineColor ); + pView->SetRasterOp( eOldOp ); +} + +void SvImpLBox::Command( const CommandEvent& rCEvt ) +{ + // Rollmaus-Event? + if( (rCEvt.GetCommand() == COMMAND_WHEEL) || + (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || + (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) + { + if( pView->HandleScrollCommand( rCEvt, &aHorSBar, &aVerSBar ) ) + return; + } +#ifndef NOCOMMAND + const Point& rPos = rCEvt.GetMousePosPixel(); + if( rPos.X() < aOutputSize.Width() && rPos.Y() < aOutputSize.Height() ) + aSelEng.Command( rCEvt ); +#endif +} + +void SvImpLBox::BeginScroll() +{ + if( !(nFlags & F_IN_SCROLLING)) + { + pView->NotifyBeginScroll(); + nFlags |= F_IN_SCROLLING; + } +} + +void SvImpLBox::EndScroll() +{ + if( nFlags & F_IN_SCROLLING) + { + pView->NotifyEndScroll(); + nFlags &= (~F_IN_SCROLLING); + } +} + + +Rectangle SvImpLBox::GetVisibleArea() const +{ + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; + Rectangle aRect( aPos, aOutputSize ); + return aRect; +} + +void SvImpLBox::Invalidate() +{ + pView->SetClipRegion(); +} + +void SvImpLBox::SetCurEntry( SvLBoxEntry* pEntry ) +{ + if( aSelEng.GetSelectionMode() != SINGLE_SELECTION ) + SelAllDestrAnch( FALSE, TRUE, FALSE ); + MakeVisible( pEntry ); + SetCursor( pEntry ); +// if( bSimpleTravel ) + pView->Select( pEntry, TRUE ); +} + +//#if defined(MAC) || defined(OV_DEBUG) +IMPL_LINK( SvImpLBox, EditTimerCall, Timer *, pTimer ) +{ + if( pView->IsInplaceEditingEnabled() ) + { + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + { + ShowCursor( FALSE ); + pView->EditEntry( pEntry ); + ShowCursor( TRUE ); + } + } + return 0; +} +//#endif + + +BOOL SvImpLBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if( rHEvt.GetMode() & HELPMODE_QUICK ) + { + Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); + if( !GetVisibleArea().IsInside( aPos )) + return FALSE; + + SvLBoxEntry* pEntry = GetEntry( aPos ); + if( pEntry ) + { + // Rechteck des Textes berechnen + SvLBoxTab* pTab; + SvLBoxString* pItem = (SvLBoxString*)(pView->GetItem( pEntry, aPos.X(), &pTab )); + if( !pItem || pItem->IsA() != SV_ITEM_ID_LBOXSTRING ) + return FALSE; + + aPos = GetEntryPos( pEntry ); + aPos.X() = pView->GetTabPos( pEntry, pTab ); //pTab->GetPos(); + Size aSize( pItem->GetSize( pView, pEntry ) ); + SvLBoxTab* pNextTab = NextTab( pTab ); + BOOL bItemClipped = FALSE; + // wurde das Item von seinem rechten Nachbarn abgeschnitten? + if( pNextTab && pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() ) + { + aSize.Width() = pNextTab->GetPos() - pTab->GetPos(); + bItemClipped = TRUE; + } + Rectangle aItemRect( aPos, aSize ); + + Rectangle aViewRect( GetVisibleArea() ); + + if( bItemClipped || !aViewRect.IsInside( aItemRect ) ) + { + // rechten Item-Rand am View-Rand clippen + //if( aItemRect.Right() > aViewRect.Right() ) + // aItemRect.Right() = aViewRect.Right(); + + Point aPt = pView->OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = pView->OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + + Help::ShowQuickHelp( pView, aItemRect, + pItem->GetText(), QUICKHELP_LEFT | QUICKHELP_VCENTER ); + return TRUE; + } + } + } + return FALSE; +} + +SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab* pTab ) +{ + USHORT nTabCount = pView->TabCount(); + if( nTabCount <= 1 ) + return 0; + for( USHORT nTab=0; nTab < (nTabCount-1); nTab++) + { + if( pView->aTabs[nTab]==pTab ) + return (SvLBoxTab*)(pView->aTabs[nTab+1]); + } + return 0; +} + +void SvImpLBox::EndSelection() +{ + DestroyAnchor(); + nFlags &= ~F_START_EDITTIMER; +} + +void SvImpLBox::RepaintScrollBars() +{ +#ifndef VCL + aHorSBar.Invalidate(); + aHorSBar.Update(); + aVerSBar.Invalidate(); + aVerSBar.Update(); +#endif +} + +void SvImpLBox::SetUpdateMode( BOOL bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( FALSE ); + } +} + +void SvImpLBox::SetUpdateModeFast( BOOL bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( FALSE, FALSE ); + } +} + + +BOOL SvImpLBox::SetMostRight( SvLBoxEntry* pEntry ) +{ + if( pView->nTreeFlags & TREEFLAG_RECALCTABS ) + { + nFlags |= F_IGNORE_CHANGED_TABS; + pView->SetTabs(); + nFlags &= ~F_IGNORE_CHANGED_TABS; + } + + USHORT nLastTab = pView->aTabs.Count() - 1; + USHORT nLastItem = pEntry->ItemCount() - 1; + if( nLastTab != USHRT_MAX && nLastItem != USHRT_MAX ) + { + if( nLastItem < nLastTab ) + nLastTab = nLastItem; + + SvLBoxTab* pTab = (SvLBoxTab*)pView->aTabs[ nLastTab ]; + SvLBoxItem* pItem = pEntry->GetItem( nLastTab ); + + long nTabPos = pView->GetTabPos( pEntry, pTab ); + + long nMaxRight = GetOutputSize().Width(); + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + nMaxRight = nMaxRight + aPos.X() - 1; + + long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50; + long nTabWidth = nNextTab - nTabPos + 1; + long nItemSize = pItem->GetSize(pView,pEntry).Width(); + long nOffset = pTab->CalcOffset( nItemSize, nTabWidth ); + + long nRight = nTabPos + nOffset + nItemSize; + if( nRight > nMostRight ) + { + nMostRight = nRight; + pMostRightEntry = pEntry; + return TRUE; + } + } + return FALSE; +} + +void SvImpLBox::FindMostRight( SvLBoxEntry* pEntryToIgnore ) +{ + nMostRight = -1; + pMostRightEntry = 0; + if( !pView->GetModel() ) + return; + + SvLBoxEntry* pEntry = (SvLBoxEntry*)pView->FirstVisible(); + while( pEntry ) + { + if( pEntry != pEntryToIgnore ) + SetMostRight( pEntry ); + pEntry = (SvLBoxEntry*)pView->NextVisible( pEntry ); + } +} + +void SvImpLBox::FindMostRight( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + if( !pParent ) + FindMostRight( pEntryToIgnore ); + else + FindMostRight_Impl( pParent, pEntryToIgnore ); +} + +void SvImpLBox::FindMostRight_Impl( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + SvTreeEntryList* pList = pTree->GetChildList( pParent ); + + if( !pList ) + return; + + ULONG nCount = pList->Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pChild = (SvLBoxEntry*)pList->GetObject( nCur ); + if( pChild != pEntryToIgnore ) + { + SetMostRight( pChild ); + if( pChild->HasChilds() && pView->IsExpanded( pChild )) + FindMostRight_Impl( pChild, pEntryToIgnore ); + } + } +} + +void SvImpLBox::NotifyTabsChanged() +{ + if( GetUpdateMode() && !(nFlags & F_IGNORE_CHANGED_TABS ) && + nCurUserEvent == 0xffffffff ) + { + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)0); + } +} + +IMPL_LINK(SvImpLBox,MyUserEvent,void*, pArg ) +{ + nCurUserEvent = 0xffffffff; + if( !pArg ) + { + pView->Invalidate(); + pView->Update(); + } + else + { + FindMostRight( 0 ); + ShowVerSBar(); + pView->Invalidate( GetVisibleArea() ); + } + return 0; +} + + +void SvImpLBox::StopUserEvent() +{ + if( nCurUserEvent != 0xffffffff ) + { + Application::RemoveUserEvent( nCurUserEvent ); + nCurUserEvent = 0xffffffff; + } +} + +void SvImpLBox::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + if( pEntry ) + { + long nY = GetEntryLine( (SvLBoxEntry*)pEntry ); + Rectangle aRect = pView->GetFocusRect( (SvLBoxEntry*)pEntry, nY ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + + } + else + { + pView->HideFocus(); + } +} + +void SvImpLBox::SetTabBar( TabBar* _pTabBar ) +{ + pTabBar = _pTabBar; +} + + diff --git a/svtools/source/contnr/svimpicn.cxx b/svtools/source/contnr/svimpicn.cxx new file mode 100644 index 000000000000..5d0f83c01d78 --- /dev/null +++ b/svtools/source/contnr/svimpicn.cxx @@ -0,0 +1,4222 @@ +/************************************************************************* + * + * $RCSfile: svimpicn.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:56 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <limits.h> +#ifndef _METRIC_HXX +#include <vcl/metric.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <vcl/svapp.hxx> +#endif +#ifdef DBG_UTIL +#include <vcl/sound.hxx> +#endif + +#pragma hdrstop + +#include <svlbox.hxx> +#include <svicnvw.hxx> +#ifndef _SVIMPICN_HXX +#include <svimpicn.hxx> +#endif +#ifndef _SVLBITM_HXX +#include <svlbitm.hxx> +#endif +#ifndef _SVARRAY_HXX +#include "svarray.hxx" +#endif + + + +#define VIEWMODE_ICON 0x0001 // Text unter Bitmap +#define VIEWMODE_NAME 0x0002 // Text rechts neben Bitmap +#define VIEWMODE_TEXT 0x0004 // Text ohne Bitmap + +#define DD_SCROLL_PIXEL 10 + +// alle Angaben in Pixel + +#define ICONVIEW_OFFS_BMP_STRING 3 + +// fuer das Bounding-Rectangle +#define LROFFS_BOUND 2 +#define TBOFFS_BOUND 2 + +// fuer das Focus-Rectangle um Icons +#define LROFFS_ICON 2 +#define TBOFFS_ICON 2 + +#define NAMEVIEW_OFFS_BMP_STRING 3 + +// Abstaende von Fensterraendern +#define LROFFS_WINBORDER 4 +#define TBOFFS_WINBORDER 4 + +// Breitenoffset Highlight-Rect bei Text +#define LROFFS_TEXT 2 + + +#define ICNVIEWDATA(xPtr) (SvIcnVwDataEntry*)(pView->GetViewDataEntry(xPtr)) +#define ICNVIEWDATA2(xPtr) (SvIcnVwDataEntry*)(pView->pView->GetViewDataEntry(xPtr)) + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// ------------------------------------------------------------------------- +// Hilfsfunktionen von Thomas Hosemann zur mehrzeiligen Ausgabe von +// Strings. Die Funktionen werden spaeter in StarView integriert. +// ------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + +// keine doppelten Defines +#ifdef TEXT_DRAW_CLIP +#undef TEXT_DRAW_CLIP +#endif +#ifdef TEXT_DRAW_MULTILINE +#undef TEXT_DRAW_MULTILINE +#endif +#ifdef TEXT_DRAW_WORDBREAK +#undef TEXT_DRAW_WORDBREAK +#endif + +// #define TEXT_DRAW_DISABLE ((USHORT)0x0001) +// #define TEXT_DRAW_3DLOOK ((USHORT)0x0002) +// #define TEXT_DRAW_MNEMONIC ((USHORT)0x0004) +#define TEXT_DRAW_LEFT ((USHORT)0x0010) +#define TEXT_DRAW_CENTER ((USHORT)0x0020) +#define TEXT_DRAW_RIGHT ((USHORT)0x0040) +#define TEXT_DRAW_TOP ((USHORT)0x0080) +#define TEXT_DRAW_VCENTER ((USHORT)0x0100) +#define TEXT_DRAW_BOTTOM ((USHORT)0x0200) +#define TEXT_DRAW_ENDELLIPSIS ((USHORT)0x0400) +#define TEXT_DRAW_PATHELLIPSIS ((USHORT)0x0800) +#define TEXT_DRAW_CLIP ((USHORT)0x1000) +#define TEXT_DRAW_MULTILINE ((USHORT)0x2000) +#define TEXT_DRAW_WORDBREAK ((USHORT)0x4000) + +XubString GetEllipsisString( OutputDevice* pDev, + const XubString& rStr, long nMaxWidth, + USHORT nStyle = TEXT_DRAW_ENDELLIPSIS ) +{ + XubString aStr = rStr; + + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + USHORT nIndex = pDev->GetTextBreak( rStr, nMaxWidth ); + if ( nIndex != STRING_LEN ) + { + aStr.Erase( nIndex ); + if ( nIndex > 1 ) + { + aStr.AppendAscii("..."); + while ( aStr.Len() && + (pDev->GetTextWidth( aStr ) > nMaxWidth) ) + { + if ( (nIndex > 1) || (nIndex == aStr.Len()) ) + nIndex--; + aStr.Erase( nIndex, 1 ); + } + } + + if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) ) + aStr += rStr.GetChar( 0 ); + } + } + + return aStr; +} + +class TextLineInfo +{ +private: + long mnWidth; + USHORT mnIndex; + USHORT mnLen; + +public: + TextLineInfo( long nWidth, USHORT nIndex, USHORT nLen ) + { + mnWidth = nWidth; + mnIndex = nIndex; + mnLen = nLen; + } + + long GetWidth() const { return mnWidth; } + USHORT GetIndex() const { return mnIndex; } + USHORT GetLen() const { return mnLen; } +}; + +#define MULTITEXTLINEINFO_RESIZE 16 +typedef TextLineInfo* PTextLineInfo; + +class MultiTextLineInfo +{ +private: + PTextLineInfo* mpLines; + USHORT mnLines; + USHORT mnSize; + +public: + MultiTextLineInfo(); + ~MultiTextLineInfo(); + + void AddLine( TextLineInfo* pLine ); + void Clear(); + + TextLineInfo* GetLine( USHORT nLine ) const + { return mpLines[nLine]; } + USHORT Count() const { return mnLines; } + +private: + MultiTextLineInfo( const MultiTextLineInfo& ); + MultiTextLineInfo& operator=( const MultiTextLineInfo& ); +}; + +MultiTextLineInfo::MultiTextLineInfo() +{ + mpLines = new PTextLineInfo[MULTITEXTLINEINFO_RESIZE]; + mnLines = 0; + mnSize = MULTITEXTLINEINFO_RESIZE; +} + +MultiTextLineInfo::~MultiTextLineInfo() +{ + for ( USHORT i = 0; i < mnLines; i++ ) + delete mpLines[i]; + delete mpLines; +} + +void MultiTextLineInfo::AddLine( TextLineInfo* pLine ) +{ + if ( mnSize == mnLines ) + { + mnSize += MULTITEXTLINEINFO_RESIZE; + PTextLineInfo* pNewLines = new PTextLineInfo[mnSize]; + memcpy( pNewLines, mpLines, mnLines*sizeof(PTextLineInfo) ); + mpLines = pNewLines; + } + + mpLines[mnLines] = pLine; + mnLines++; +} + +void MultiTextLineInfo::Clear() +{ + for ( USHORT i = 0; i < mnLines; i++ ) + delete mpLines[i]; + mnLines = 0; +} + +// ----------------------------------------------------------------------- + +long GetTextLines( OutputDevice* pDev, MultiTextLineInfo& rLineInfo, + long nWidth, const XubString& rStr, + USHORT nStyle = TEXT_DRAW_WORDBREAK ) +{ + rLineInfo.Clear(); + if ( !rStr.Len() ) + return 0; + if ( nWidth <= 0 ) + nWidth = 1; + + USHORT nStartPos = 0; // Start-Position der Zeile + USHORT nLastLineLen = 0; // Zeilenlaenge bis zum vorherigen Wort + USHORT nLastWordPos = 0; // Position des letzten Wortanfangs + USHORT i = 0; + USHORT nPos; // StartPositon der Zeile (nur Temp) + USHORT nLen; // Laenge der Zeile (nur Temp) + USHORT nStrLen = rStr.Len(); + long nMaxLineWidth = 0; // Maximale Zeilenlaenge + long nLineWidth; // Aktuelle Zeilenlaenge + long nLastLineWidth = 0; // Zeilenlaenge der letzten Zeile + xub_Unicode c; + xub_Unicode c2; + const xub_Unicode* pStr = rStr.GetBuffer(); + BOOL bHardBreak = FALSE; + + do + { + c = pStr[i]; + + // Auf Zeilenende ermitteln + if ( (c == _CR) || (c == _LF) ) + bHardBreak = TRUE; + else + bHardBreak = FALSE; + + // Testen, ob ein Wortende erreicht ist + if ( bHardBreak || (i == nStrLen) || + (((c == ' ') || (c == '-')) && (nStyle & TEXT_DRAW_WORDBREAK)) ) + { + nLen = i-nStartPos; + if ( c == '-' ) + nLen++; + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); + + // Findet ein Zeilenumbruch statt + if ( bHardBreak || (i == nStrLen) || + ((nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK)) ) + { + nPos = nStartPos; + + if ( (nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK) ) + { + nLineWidth = nLastLineWidth; + nLen = nLastLineLen; + nStartPos = nLastWordPos; + nLastLineLen = i-nStartPos; + nLastWordPos = nStartPos+nLastLineLen+1; + if ( c == '-' ) + nLastLineLen++; + else if ( bHardBreak && (i > nStartPos) ) + i--; + } + else + { + nStartPos = i; + // Zeilenende-Zeichen und '-' beruecksichtigen + if ( bHardBreak ) + { + nStartPos++; + c2 = pStr[i+1]; + if ( (c != c2) && ((c2 == _CR) || (c2 == _LF)) ) + { + nStartPos++; + i++; + } + } + else if ( c != '-' ) + nStartPos++; + nLastWordPos = nStartPos; + nLastLineLen = 0; + } + + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + if ( nLen || bHardBreak ) + rLineInfo.AddLine( new TextLineInfo( nLineWidth, nPos, nLen ) ); + + // Testen, ob aktuelles Wort noch auf die Zeile passt, + // denn ansonsten mueessen wir es auftrennen + if ( nLastLineLen ) + { + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); + if ( nLineWidth > nWidth ) + { + // Wenn ein Wortumbruch in einem Wort stattfindet, + // ist die maximale Zeilenlaenge die Laenge + // des laengsten Wortes + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + // Solange Wort auftrennen, bis es auf eine Zeile passt + do + { + nPos = pDev->GetTextBreak( rStr, nWidth, nStartPos, nLastLineLen ); + nLen = nPos-nStartPos; + if ( !nLen ) + { + nPos++; + nLen++; + } + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); + rLineInfo.AddLine( new TextLineInfo( nLineWidth, nStartPos, nLen ) ); + nStartPos = nPos; + nLastLineLen -= nLen; + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); + } + while ( nLineWidth > nWidth ); + } + nLastLineWidth = nLineWidth; + + // Bei Stringende muessen wir die letzte Zeile auch noch + // dranhaengen + if ( (i == nStrLen) && nLastLineLen ) + rLineInfo.AddLine( new TextLineInfo( nLastLineWidth, nStartPos, nLastLineLen ) ); + } + else + nLastLineWidth = 0; + } + else + { + nLastLineWidth = nLineWidth; + nLastLineLen = nLen; + nLastWordPos = nStartPos+nLastLineLen; + if ( c != '-' ) + nLastWordPos++; + } + } + + i++; + } + while ( i <= nStrLen ); + + return nMaxLineWidth; +} + +// ----------------------------------------------------------------------- + +USHORT GetTextLines( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, + USHORT nStyle = TEXT_DRAW_WORDBREAK, + long* pMaxWidth = NULL ) +{ + MultiTextLineInfo aMultiLineInfo; + long nMaxWidth = GetTextLines( pDev, aMultiLineInfo, + rRect.GetWidth(), rStr, nStyle ); + if ( pMaxWidth ) + *pMaxWidth = nMaxWidth; + return aMultiLineInfo.Count(); +} + +// ----------------------------------------------------------------------- + +Rectangle GetTextRect( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, + USHORT nStyle = TEXT_DRAW_WORDBREAK ) +{ + Rectangle aRect = rRect; + USHORT nLines; + long nWidth = rRect.GetWidth(); + long nMaxWidth; + long nTextHeight; + + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + MultiTextLineInfo aMultiLineInfo; + TextLineInfo* pLineInfo; + USHORT nFormatLines; + + nMaxWidth = 0; + GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); + nFormatLines = aMultiLineInfo.Count(); + nTextHeight = pDev->GetTextHeight(); + nLines = (USHORT)(aRect.GetHeight()/nTextHeight); + if ( nFormatLines <= nLines ) + nLines = nFormatLines; + else + { + if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) ) + nLines = nFormatLines; + else + nMaxWidth = nWidth; + } + for ( USHORT i = 0; i < nLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( pLineInfo->GetWidth() > nMaxWidth ) + nMaxWidth = pLineInfo->GetWidth(); + } + } + else + { + nLines = 1; + nMaxWidth = pDev->GetTextWidth( rStr ); + nTextHeight = pDev->GetTextHeight(); + if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ENDELLIPSIS) ) + nMaxWidth = nWidth; + } + + if ( nStyle & TEXT_DRAW_RIGHT ) + aRect.Left() = aRect.Right()-nMaxWidth+1; + else if ( nStyle & TEXT_DRAW_CENTER ) + { + aRect.Left() += (nWidth-nMaxWidth)/2; + aRect.Right() = aRect.Left()+nMaxWidth-1; + } + else + aRect.Right() = aRect.Left()+nMaxWidth-1; + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1; + else if ( nStyle & TEXT_DRAW_VCENTER ) + { + aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2; + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + } + else + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + + return aRect; +} + +// ----------------------------------------------------------------------- + +void DrawText( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, USHORT nStyle = 0 ) +{ + if ( !rStr.Len() || rRect.IsEmpty() ) + return; + + Point aPos = rRect.TopLeft(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + FontAlign eAlign = pDev->GetFont().GetAlign(); + + if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) ) + return; + + // Mehrzeiligen Text behandeln wir anders + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + String aLastLine; + Region aOldRegion; + MultiTextLineInfo aMultiLineInfo; + TextLineInfo* pLineInfo; + long nTextHeight = pDev->GetTextHeight(); + long nMaxTextWidth; + USHORT i; + USHORT nLines = (USHORT)(nHeight/nTextHeight); + USHORT nFormatLines; + BOOL bIsClipRegion; + nMaxTextWidth = GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); + + nFormatLines = aMultiLineInfo.Count(); + if ( nFormatLines > nLines ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + // Letzte Zeile zusammenbauen und kuerzen + nFormatLines = nLines-1; + pLineInfo = aMultiLineInfo.GetLine( nFormatLines ); + aLastLine = rStr.Copy( pLineInfo->GetIndex() ); + aLastLine.ConvertLineEnd( LINEEND_LF ); + aLastLine.SearchAndReplace( _LF, ' ' ); + aLastLine = GetEllipsisString( pDev, aLastLine, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM); + nStyle |= TEXT_DRAW_TOP; + } + } + else + { + if ( nMaxTextWidth <= nWidth ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Clipping setzen + if ( nStyle & TEXT_DRAW_CLIP ) + { + bIsClipRegion = pDev->IsClipRegion(); + if ( bIsClipRegion ) + { + aOldRegion = pDev->GetClipRegion(); + pDev->IntersectClipRegion( rRect ); + } + else + { + Region aRegion( rRect ); + pDev->SetClipRegion( aRegion ); + } + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-(nFormatLines*nTextHeight); + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += nTextHeight; + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += pDev->GetFontMetric().GetAscent(); + + // Alle Zeilen ausgeben, bis auf die letzte + for ( i = 0; i < nFormatLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-pLineInfo->GetWidth(); + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-pLineInfo->GetWidth())/2; + pDev->DrawText( aPos, rStr, pLineInfo->GetIndex(), pLineInfo->GetLen() ); + aPos.Y() += nTextHeight; + aPos.X() = rRect.Left(); + } + + // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben, + // da die Zeile gekuerzt wurde + if ( aLastLine.Len() ) + pDev->DrawText( aPos, aLastLine ); + + // Clipping zuruecksetzen + if ( nStyle & TEXT_DRAW_CLIP ) + { + if ( bIsClipRegion ) + pDev->SetClipRegion( aOldRegion ); + else + pDev->SetClipRegion(); + } + } + else + { + XubString aStr = rStr; + Size aTextSize(pDev->GetTextWidth( aStr ), pDev->GetTextHeight()); + + // Evt. Text kuerzen + if ( aTextSize.Width() > nWidth ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + aStr = GetEllipsisString( pDev, rStr, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT); + nStyle |= TEXT_DRAW_LEFT; + aTextSize.Width() = pDev->GetTextWidth(aStr); + } + } + else + { + if ( aTextSize.Height() <= nHeight ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-aTextSize.Width(); + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-aTextSize.Width())/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += aTextSize.Height(); + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += pDev->GetFontMetric().GetAscent(); + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-aTextSize.Height(); + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-aTextSize.Height())/2; + + if ( nStyle & TEXT_DRAW_CLIP ) + { + BOOL bIsClipRegion = pDev->IsClipRegion(); + if ( bIsClipRegion ) + { + Region aOldRegion = pDev->GetClipRegion(); + pDev->IntersectClipRegion( rRect ); + pDev->DrawText( aPos, aStr ); + pDev->SetClipRegion( aOldRegion ); + } + else + { + Region aRegion( rRect ); + pDev->SetClipRegion( aRegion ); + pDev->DrawText( aPos, aStr ); + pDev->SetClipRegion(); + } + } + else + pDev->DrawText( aPos, aStr ); + } +} + +// ----------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + + +#define DRAWTEXT_FLAGS (TEXT_DRAW_CENTER|TEXT_DRAW_TOP|TEXT_DRAW_ENDELLIPSIS|\ + TEXT_DRAW_CLIP|TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK) + + +class ImpIcnCursor +{ + SvImpIconView* pView; + SvPtrarr* pColumns; + SvPtrarr* pRows; + BOOL* pGridMap; + long nGridDX, nGridDY; + long nGridCols, nGridRows; + long nCols; + long nRows; + short nDeltaWidth; + short nDeltaHeight; + SvLBoxEntry* pCurEntry; + void SetDeltas(); + void ImplCreate(); + void Create() { if( !pColumns ) ImplCreate(); } + + USHORT GetSortListPos( SvPtrarr* pList, long nValue, int bVertical); + SvLBoxEntry* SearchCol(USHORT nCol,USHORT nTop,USHORT nBottom,USHORT nPref, + BOOL bDown, BOOL bSimple ); + SvLBoxEntry* SearchRow(USHORT nRow,USHORT nRight,USHORT nLeft,USHORT nPref, + BOOL bRight, BOOL bSimple ); + + void ExpandGrid(); + void CreateGridMap(); + // Rueckgabe FALSE: Eintrag liegt nicht in der GridMap. rGridx,y werden + // dann an nGridCols, nGridRows geclippt + BOOL GetGrid( const Point& rDocPos, USHORT& rGridX, USHORT& rGridY ) const; + void SetGridUsed( USHORT nDX, USHORT nDY, BOOL bUsed ) + { + pGridMap[ (nDY * nGridCols) + nDX ] = bUsed; + } + BOOL IsGridUsed( USHORT nDX, USHORT nDY ) + { + return pGridMap[ (nDY * nGridCols) + nDX ]; + } +public: + ImpIcnCursor( SvImpIconView* pOwner ); + ~ImpIcnCursor(); + void Clear( BOOL bGridToo = TRUE ); + + // fuer Cursortravelling usw. + SvLBoxEntry* GoLeftRight( SvLBoxEntry*, BOOL bRight ); + SvLBoxEntry* GoUpDown( SvLBoxEntry*, BOOL bDown ); + + // Rueckgaebe: FALSE == Das leere Rect steht hinter dem letzten + // Eintrag; d.h. beim naechsten Einfuegen ergibt sich das naechste + // leere Rechteck durch Addition. Hinweis: Das Rechteck kann dann + // ausserhalb des View-Space liegen + BOOL FindEmptyGridRect( Rectangle& rRect ); + + // Erzeugt fuer jede Zeile (Hoehe=nGridDY) eine nach BoundRect.Left() + // sortierte Liste der Eintraege, die in ihr stehen. Eine Liste kann + // leer sein. Die Listen gehen in das Eigentum des Rufenden ueber und + // muessen mit DestroyGridAdjustData geloescht werden + void CreateGridAjustData( SvPtrarr& pLists, SvLBoxEntry* pRow=0); + static void DestroyGridAdjustData( SvPtrarr& rLists ); + void SetGridUsed( const Rectangle&, BOOL bUsed = TRUE ); +}; + + + + +SvImpIconView::SvImpIconView( SvIconView* pCurView, SvLBoxTreeList* pTree, + WinBits nWinStyle ) : + aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pCurView, WB_DRAG | WB_HSCROLL ) +{ + pView = pCurView; + pModel = pTree; + pCurParent = 0; + pZOrderList = new SvPtrarr; + SetWindowBits( nWinStyle ); + nHorDist = 0; + nVerDist = 0; + nFlags = 0; + nCurUserEvent = 0; + nMaxVirtWidth = 200; + pDDRefEntry = 0; + pDDDev = 0; + pDDBufDev = 0; + pDDTempDev = 0; + eTextMode = ShowTextShort; + pImpCursor = new ImpIcnCursor( this ); + + aVerSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollUpDownHdl ) ); + aHorSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollLeftRightHdl ) ); + nHorSBarHeight = aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = aVerSBar.GetSizePixel().Width(); + + aMouseMoveTimer.SetTimeout( 20 ); + aMouseMoveTimer.SetTimeoutHdl(LINK(this,SvImpIconView,MouseMoveTimeoutHdl)); + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl(LINK(this,SvImpIconView,EditTimeoutHdl)); + + Clear( TRUE ); +} + +SvImpIconView::~SvImpIconView() +{ + StopEditTimer(); + CancelUserEvent(); + delete pZOrderList; + delete pImpCursor; + delete pDDDev; + delete pDDBufDev; + delete pDDTempDev; + ClearSelectedRectList(); +} + +void SvImpIconView::Clear( BOOL bInCtor ) +{ + StopEditTimer(); + CancelUserEvent(); + nMaxBmpWidth = 0; + nMaxBmpHeight = 0; + nMaxTextWidth = 0; + bMustRecalcBoundingRects = FALSE; + nMaxBoundHeight = 0; + + //XXX + nFlags |= F_GRID_INSERT; + nFlags &= ~F_PAINTED; + SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); + pCursor = 0; + if( !bInCtor ) + { + pImpCursor->Clear(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + pZOrderList->Remove(0,pZOrderList->Count()); + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point() ); + pView->SetMapMode( aMapMode ); + if( pView->IsUpdateMode() ) + pView->Invalidate(); + } + AdjustScrollBars(); +} + +void SvImpIconView::SetWindowBits( WinBits nWinStyle ) +{ + nWinBits = nWinStyle; + nViewMode = VIEWMODE_TEXT; + if( nWinStyle & WB_NAME ) + nViewMode = VIEWMODE_NAME; + if( nWinStyle & WB_ICON ) + nViewMode = VIEWMODE_ICON; +} + + +IMPL_LINK( SvImpIconView, ScrollUpDownHdl, ScrollBar *, pScrollBar ) +{ + pView->EndEditing( TRUE ); + // Pfeil hoch: delta=-1; Pfeil runter: delta=+1 + Scroll( 0, pScrollBar->GetDelta(), TRUE ); + return 0; +} + +IMPL_LINK( SvImpIconView, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) +{ + pView->EndEditing( TRUE ); + // Pfeil links: delta=-1; Pfeil rechts: delta=+1 + Scroll( pScrollBar->GetDelta(), 0, TRUE ); + return 0; +} + +void SvImpIconView::ChangedFont() +{ + StopEditTimer(); + ImpArrange(); +} + + +void SvImpIconView::CheckAllSizes() +{ + nMaxTextWidth = 0; + nMaxBmpWidth = 0; + nMaxBmpHeight = 0; + SvLBoxEntry* pEntry = pModel->First(); + while( pEntry ) + { + CheckSizes( pEntry ); + pEntry = pModel->Next( pEntry ); + } +} + +void SvImpIconView::CheckSizes( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) +{ + Size aSize; + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + { + aSize = GetItemSize( pView, pEntry, pStringItem, pViewData ); + if( aSize.Width() > nMaxTextWidth ) + { + nMaxTextWidth = aSize.Width(); + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = TRUE; + } + } + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aSize = GetItemSize( pView, pEntry, pBmpItem, pViewData ); + if( aSize.Width() > nMaxBmpWidth ) + { + nMaxBmpWidth = aSize.Width(); + nMaxBmpWidth += (2*LROFFS_ICON); + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = TRUE; + } + if( aSize.Height() > nMaxBmpHeight ) + { + nMaxBmpHeight = aSize.Height(); + nMaxBmpHeight += (2*TBOFFS_ICON);; + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = TRUE; + } + } +} + +void SvImpIconView::EntryInserted( SvLBoxEntry* pEntry ) +{ + if( pModel->GetParent(pEntry) == pCurParent ) + { + StopEditTimer(); + DBG_ASSERT(pZOrderList->GetPos(pEntry)==0xffff,"EntryInserted:ZOrder?"); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + if( nFlags & F_GRIDMODE ) + pImpCursor->Clear( FALSE ); + else + pImpCursor->Clear( TRUE ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + CheckSizes( pEntry, pViewData ); + if( pView->IsUpdateMode() ) + { + FindBoundingRect( pEntry, pViewData ); + PaintEntry( pEntry, pViewData ); + } + else + InvalidateBoundingRect( pViewData->aRect ); + } +} + +void SvImpIconView::RemovingEntry( SvLBoxEntry* pEntry ) +{ + if( pModel->GetParent(pEntry) == pCurParent) + { + StopEditTimer(); + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"RemovingEntry:ZOrder?"); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect ) ) + { + // bei gueltigem Bounding-Rect muss in EntryRemoved eine + // Sonderbehandlung erfolgen + nFlags |= F_ENTRY_REMOVED; + pView->Invalidate( pViewData->aRect ); + } + if( pEntry == pCursor ) + { + SvLBoxEntry* pNewCursor = GetNewCursor(); + ShowCursor( FALSE ); + pCursor = 0; // damit er nicht deselektiert wird + SetCursor( pNewCursor ); + } + USHORT nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pImpCursor->Clear(); + } +} + +void SvImpIconView::EntryRemoved() +{ + if( (nFlags & (F_ENTRY_REMOVED | F_PAINTED)) == (F_ENTRY_REMOVED | F_PAINTED)) + { + // Ein Eintrag mit gueltigem BoundRect wurde geloescht und wir + // haben schon mal gepaintet. In diesem Fall muessen wir die + // Position des naechsten Eintrags, der eingefuegt wird oder noch + // kein gueltiges BoundRect hat, "suchen" d.h. ein "Loch" in + // der View auffuellen. + nFlags &= ~( F_ENTRY_REMOVED | F_GRID_INSERT ); + } +} + + +void SvImpIconView::MovingEntry( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"MovingEntry: 0!"); + pNextCursor = 0; + StopEditTimer(); + if( pModel->GetParent(pEntry) == pCurParent ) + { + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"MovingEntry:ZOrder?"); + nFlags |= F_MOVING_SIBLING; + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect ) ) + pView->Invalidate( pViewData->aRect ); + // falls Eintrag seinen Parent wechselt vorsichtshalber + // die neue Cursorposition berechnen + if( pEntry == pCursor ) + pNextCursor = GetNewCursor(); + pImpCursor->Clear(); + } +} + + +void SvImpIconView::EntryMoved( SvLBoxEntry* pEntry ) +{ + ShowCursor( FALSE ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pModel->GetParent(pEntry)==pCurParent ) + { + if( nFlags & F_MOVING_SIBLING ) + { + // die Neu-Positionierung eines Eintrags bei D&D innerhalb + // einer IconView findet bereits in NotifyMoving statt + // (MovingEntry/EntryMoved wird dann nicht mehr gerufen) + ToTop( pEntry ); + } + else + { + pImpCursor->Clear(); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + DBG_ASSERT(pZOrderList->Count()==pModel->GetChildCount(pCurParent),"EntryMoved:Bad zorder count"); + FindBoundingRect( pEntry, pViewData ); + } + PaintEntry( pEntry, pViewData ); + } + else + { + if( pEntry == pCursor ) + { + DBG_ASSERT(pNextCursor,"EntryMoved: Next cursor bad"); + SetCursor( pNextCursor ); + } + pImpCursor->Clear(); + USHORT nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pView->Select( pEntry, FALSE ); + // wenn er nochmal in dieser View auftaucht, muss sein + // Bounding-Rect neu berechnet werden + InvalidateBoundingRect( pViewData->aRect ); + } + nFlags &= (~F_MOVING_SIBLING); +} + +void SvImpIconView::TreeInserted( SvLBoxEntry* pEntry ) +{ + EntryMoved( pEntry ); // vorlaeufig +} + +void SvImpIconView::EntryExpanded( SvLBoxEntry* ) +{ +} + +void SvImpIconView::EntryCollapsed( SvLBoxEntry*) +{ +} + +void SvImpIconView::CollapsingEntry( SvLBoxEntry* ) +{ +} + +void SvImpIconView::EntrySelected( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + if( pModel->GetParent(pEntry) != pCurParent ) + return; + + // bei SingleSelection dafuer sorgen, dass der Cursor immer + // auf dem (einzigen) selektierten Eintrag steht + if( bSelect && pCursor && + pView->GetSelectionMode() == SINGLE_SELECTION && + pEntry != pCursor ) + { + SetCursor( pEntry ); + DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?") + } + // bei Gummibandselektion ist uns das zu teuer + if( !(nFlags & F_RUBBERING )) + ToTop( pEntry ); + if( pView->IsUpdateMode() ) + { + if( pEntry == pCursor ) + ShowCursor( FALSE ); + if( nFlags & F_RUBBERING ) + PaintEntry( pEntry ); + else + pView->Invalidate( GetBoundingRect( pEntry ) ); + if( pEntry == pCursor ) + ShowCursor( TRUE ); + } +} + +void SvImpIconView::SetNextEntryPos(const Point& rPos) +{ + aPrevBoundRect.SetPos( rPos ); + aPrevBoundRect.Right() = LONG_MAX; // dont know +} + +Point SvImpIconView::FindNextEntryPos( const Size& rBoundSize ) +{ + if( nFlags & F_GRIDMODE ) + { + if( nFlags & F_GRID_INSERT ) + { + if( aPrevBoundRect.Right() != LONG_MAX ) + { + // passt der naechste Entry noch in die Zeile ? + long nNextWidth = aPrevBoundRect.Right() + nGridDX + LROFFS_WINBORDER; + if( nNextWidth > aVirtOutputSize.Width() ) + { + // darf aVirtOutputSize verbreitert werden ? + if( nNextWidth < nMaxVirtWidth ) + { + // verbreitern & in Zeile aufnehmen + aPrevBoundRect.Left() += nGridDX; + } + else + { + // erhoehen & neue Zeile beginnen + aPrevBoundRect.Top() += nGridDY; + aPrevBoundRect.Left() = LROFFS_WINBORDER; + } + } + else + { + // in die Zeile aufnehmen + aPrevBoundRect.Left() += nGridDX; + } + } + aPrevBoundRect.SetSize( Size( nGridDX, nGridDY ) ); + } + else + { + if( !pImpCursor->FindEmptyGridRect( aPrevBoundRect ) ) + { + // mitten in den Entries gibts keine Loecher mehr, + // wir koennen also wieder ins "Fast Insert" springen + nFlags |= F_GRID_INSERT; + } + } + } + else + { + if( aPrevBoundRect.Right() != LONG_MAX ) + { + // passt der naechste Entry noch in die Zeile ? + long nNextWidth=aPrevBoundRect.Right()+rBoundSize.Width()+LROFFS_BOUND+nHorDist; + if( nNextWidth > aVirtOutputSize.Width() ) + { + // darf aVirtOutputSize verbreitert werden ? + if( nNextWidth < nMaxVirtWidth ) + { + // verbreitern & in Zeile aufnehmen + aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); + aPrevBoundRect.Left() += nHorDist; + } + else + { + // erhoehen & neue Zeile beginnen + aPrevBoundRect.Top() += nMaxBoundHeight + nVerDist + TBOFFS_BOUND; + aPrevBoundRect.Left() = LROFFS_WINBORDER; + } + } + else + { + // in die Zeile aufnehmen + aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); + aPrevBoundRect.Left() += nHorDist; + } + } + aPrevBoundRect.SetSize( rBoundSize ); + } + return aPrevBoundRect.TopLeft(); +} + +void SvImpIconView::ResetVirtSize() +{ + StopEditTimer(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + BOOL bLockedEntryFound = FALSE; + nFlags &= (~F_GRID_INSERT); + SvLBoxEntry* pCur = pModel->FirstChild( pCurParent ); + while( pCur ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); + if( pViewData->IsEntryPosLocked() ) + { + // VirtSize u.a. anpassen + if( !IsBoundingRectValid( pViewData->aRect ) ) + FindBoundingRect( pCur, pViewData ); + else + AdjustVirtSize( pViewData->aRect ); + bLockedEntryFound = TRUE; + } + else + InvalidateBoundingRect( pViewData->aRect ); + + pCur = pModel->NextSibling( pCur ); + } + if( !bLockedEntryFound ) + { + //XXX + nFlags |= F_GRID_INSERT; + } + + SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); + pImpCursor->Clear(); +} + + +void SvImpIconView::AdjustVirtSize( const Rectangle& rRect ) +{ + long nHeightOffs = 0; + long nWidthOffs = 0; + + if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) ) + nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width(); + + if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) ) + nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height(); + + if( nWidthOffs || nHeightOffs ) + { + Range aRange; + aVirtOutputSize.Width() += nWidthOffs; + aRange.Max() = aVirtOutputSize.Width(); + aHorSBar.SetRange( aRange ); + + aVirtOutputSize.Height() += nHeightOffs; + aRange.Max() = aVirtOutputSize.Height(); + aVerSBar.SetRange( aRange ); + + pImpCursor->Clear(); + AdjustScrollBars(); + } +} + +void SvImpIconView::Arrange() +{ + nMaxVirtWidth = aOutputSize.Width(); + ImpArrange(); +} + +void SvImpIconView::ImpArrange() +{ + StopEditTimer(); + ShowCursor( FALSE ); + ResetVirtSize(); + bMustRecalcBoundingRects = FALSE; + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point() ); + pView->SetMapMode( aMapMode ); + CheckAllSizes(); + RecalcAllBoundingRectsSmart(); + pView->Invalidate(); + ShowCursor( TRUE ); +} + +void SvImpIconView::Paint( const Rectangle& rRect ) +{ + if( !pView->IsUpdateMode() ) + return; + +#if defined(DBG_UTIL) && defined(OV_DRAWGRID) + if( nFlags & F_GRIDMODE ) + { + Color aOldColor = pView->GetLineColor(); + Color aNewColor( COL_BLACK ); + pView->SetLineColor( aNewColor ); + Point aOffs( pView->GetMapMode().GetOrigin()); + Size aXSize( pView->GetOutputSizePixel() ); + for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX ) + { + Point aStart( nDX+LROFFS_BOUND, 0 ); + Point aEnd( nDX+LROFFS_BOUND, aXSize.Height()); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY ) + { + Point aStart( 0, nDY+TBOFFS_BOUND ); + Point aEnd( aXSize.Width(), nDY+TBOFFS_BOUND ); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + pView->SetLineColor( aOldColor ); + } +#endif + nFlags |= F_PAINTED; + + if( !(pModel->HasChilds( pCurParent ) )) + return; + if( !pCursor ) + pCursor = pModel->FirstChild( pCurParent ); + + USHORT nCount = pZOrderList->Count(); + if( !nCount ) + return; + + SvPtrarr* pNewZOrderList = new SvPtrarr; + SvPtrarr* pPaintedEntries = new SvPtrarr; + + USHORT nPos = 0; + while( nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + const Rectangle& rBoundRect = GetBoundingRect( pEntry, pViewData ); + if( rRect.IsOver( rBoundRect ) ) + { + PaintEntry( pEntry, rBoundRect.TopLeft(), pViewData ); + // Eintraege, die neu gezeichnet werden, auf Top setzen + pPaintedEntries->Insert( pEntry, pPaintedEntries->Count() ); + } + else + pNewZOrderList->Insert( pEntry, pNewZOrderList->Count() ); + + nCount--; + nPos++; + } + delete pZOrderList; + pZOrderList = pNewZOrderList; + nCount = pPaintedEntries->Count(); + if( nCount ) + { + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + pZOrderList->Insert( pPaintedEntries->GetObject( nCur ),pZOrderList->Count()); + } + delete pPaintedEntries; + + Rectangle aRect; + if( GetResizeRect( aRect )) + PaintResizeRect( aRect ); +} + +BOOL SvImpIconView::GetResizeRect( Rectangle& rRect ) +{ + if( aHorSBar.IsVisible() && aVerSBar.IsVisible() ) + { + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin()); + aOrigin *= -1; + aOrigin.X() += aOutputSize.Width(); + aOrigin.Y() += aOutputSize.Height(); + rRect.SetPos( aOrigin ); + rRect.SetSize( Size( nVerSBarWidth, nHorSBarHeight)); + return TRUE; + } + return FALSE; +} + +void SvImpIconView::PaintResizeRect( const Rectangle& rRect ) +{ + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + Color aNewColor = rStyleSettings.GetFaceColor(); + Color aOldColor = pView->GetFillColor(); + pView->SetFillColor( aNewColor ); + pView->DrawRect( rRect ); + pView->SetFillColor( aOldColor ); +} + +void SvImpIconView::RepaintSelectionItems() +{ + DBG_ERROR("RepaintSelectionItems"); + pView->Invalidate(); // vorlaeufig +} + +SvLBoxItem* SvImpIconView::GetItem( SvLBoxEntry* pEntry, + const Point& rAbsPos ) +{ + Rectangle aRect; + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + { + aRect = CalcTextRect( pEntry, pStringItem ); + if( aRect.IsInside( rAbsPos ) ) + return pStringItem; + } + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aRect = CalcBmpRect( pEntry ); + if( aRect.IsInside( rAbsPos ) ) + return pBmpItem; + } + return 0; +} + +void SvImpIconView::CalcDocPos( Point& aMaeuschenPos ) +{ + aMaeuschenPos -= pView->GetMapMode().GetOrigin(); +} + +void SvImpIconView::MouseButtonDown( const MouseEvent& rMEvt) +{ + StopEditTimer(); + pView->GrabFocus(); + Point aDocPos( rMEvt.GetPosPixel() ); + if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height()) + return; + CalcDocPos( aDocPos ); + SvLBoxEntry* pEntry = GetEntry( aDocPos ); + if( !pEntry ) + { + if( pView->GetSelectionMode() != SINGLE_SELECTION ) + { + if( !rMEvt.IsMod1() ) // Ctrl + { + pView->SelectAll( FALSE ); + ClearSelectedRectList(); + } + else + nFlags |= F_ADD_MODE; + nFlags |= F_RUBBERING; + aCurSelectionRect.SetPos( aDocPos ); + pView->CaptureMouse(); + } + return; + } + + BOOL bSelected = pView->IsSelected( pEntry ); + BOOL bEditingEnabled = pView->IsInplaceEditingEnabled(); + + if( rMEvt.GetClicks() == 2 ) + { + DeselectAllBut( pEntry ); + pView->pHdlEntry = pEntry; + pView->DoubleClickHdl(); + } + else + { + // Inplace-Editing ? + if( rMEvt.IsMod2() ) // Alt? + { + if( bEditingEnabled ) + { + SvLBoxItem* pItem = GetItem(pEntry,aDocPos); + if( pItem ) + pView->EditingRequest( pEntry, pItem, aDocPos); + } + } + else if( pView->GetSelectionMode() == SINGLE_SELECTION ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, TRUE ); + if( bEditingEnabled && bSelected && !rMEvt.GetModifier() && + rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) ) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + else + { + if( !rMEvt.GetModifier() ) + { + if( !bSelected ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, TRUE ); + } + else + { + // erst im Up deselektieren, falls Move per D&D! + nFlags |= F_DOWN_DESELECT; + if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) && + rMEvt.IsLeft()) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + } + else if( rMEvt.IsMod1() ) + nFlags |= F_DOWN_CTRL; + } + } +} + +void SvImpIconView::MouseButtonUp( const MouseEvent& rMEvt ) +{ + aMouseMoveTimer.Stop(); + pView->ReleaseMouse(); + // HACK, da Einar noch nicht PrepareCommandEvent aufruft + if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) )) + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + + if( nFlags & F_RUBBERING ) + { + aMouseMoveTimer.Stop(); + AddSelectedRect( aCurSelectionRect ); + HideSelectionRect(); + nFlags &= ~(F_RUBBERING | F_ADD_MODE); + } + + SvLBoxEntry* pEntry = pView->GetEntry( rMEvt.GetPosPixel(), TRUE ); + if( pEntry ) + { + if( nFlags & F_DOWN_CTRL ) + { + // Ctrl & MultiSelection + ToggleSelection( pEntry ); + SetCursor( pEntry ); + } + else if( nFlags & F_DOWN_DESELECT ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, TRUE ); + } + } + + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + if( nFlags & F_START_EDITTIMER_IN_MOUSEUP ) + { + StartEditTimer(); + nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP; + } +} + +void SvImpIconView::MouseMove( const MouseEvent& rMEvt ) +{ + if( nFlags & F_RUBBERING ) + { + const Point& rPosPixel = rMEvt.GetPosPixel(); + if( !aMouseMoveTimer.IsActive() ) + { + aMouseMoveEvent = rMEvt; + aMouseMoveTimer.Start(); + // ausserhalb des Fensters liegende Move-Events muessen + // vom Timer kommen, damit die Scrollgeschwindigkeit + // unabhaengig von Mausbewegungen ist. + if( rPosPixel.X() < 0 || rPosPixel.Y() < 0 ) + return; + const Size& rSize = pView->GetOutputSizePixel(); + if( rPosPixel.X() > rSize.Width() || rPosPixel.Y() > rSize.Height()) + return; + } + + if( &rMEvt != &aMouseMoveEvent ) + aMouseMoveEvent = rMEvt; + + long nScrollDX, nScrollDY; + + CalcScrollOffsets(rMEvt.GetPosPixel(),nScrollDX,nScrollDY,FALSE ); + BOOL bSelRectHidden = FALSE; + if( nScrollDX || nScrollDY ) + { + HideSelectionRect(); + bSelRectHidden = TRUE; + pView->Scroll( nScrollDX, nScrollDY ); + } + Point aDocPos( rMEvt.GetPosPixel() ); + aDocPos = pView->PixelToLogic( aDocPos ); + Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos ); + if( aRect != aCurSelectionRect ) + { + HideSelectionRect(); + bSelRectHidden = TRUE; + BOOL bAdd = (nFlags & F_ADD_MODE) ? TRUE : FALSE; + SelectRect( aRect, bAdd, &aSelectedRectList ); + } + if( bSelRectHidden ) + DrawSelectionRect( aRect ); + } +} + +BOOL SvImpIconView::KeyInput( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + BOOL bKeyUsed = TRUE; + BOOL bMod1 = rKEvt.GetKeyCode().IsMod1(); + BOOL bInAddMode = (BOOL)((nFlags & F_ADD_MODE) != 0); + int bDeselAll = (pView->GetSelectionMode() != SINGLE_SELECTION) && + !bInAddMode; + SvLBoxEntry* pNewCursor; + USHORT nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case KEY_UP: + if( pCursor ) + { + MakeVisible( pCursor ); + pNewCursor = pImpCursor->GoUpDown(pCursor,FALSE); + if( pNewCursor ) + { + if( bDeselAll ) + pView->SelectAll( FALSE ); + ShowCursor( FALSE ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, TRUE ); + } + else + { + Rectangle aRect( GetBoundingRect( pCursor ) ); + if( aRect.Top()) + { + aRect.Bottom() -= aRect.Top(); + aRect.Top() = 0; + MakeVisible( aRect ); + } + } + } + break; + + case KEY_DOWN: + if( pCursor ) + { + pNewCursor=pImpCursor->GoUpDown( pCursor,TRUE ); + if( pNewCursor ) + { + MakeVisible( pCursor ); + if( bDeselAll ) + pView->SelectAll( FALSE ); + ShowCursor( FALSE ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, TRUE ); + } + } + break; + + case KEY_RIGHT: + if( pCursor ) + { + pNewCursor=pImpCursor->GoLeftRight(pCursor,TRUE ); + if( pNewCursor ) + { + MakeVisible( pCursor ); + if( bDeselAll ) + pView->SelectAll( FALSE ); + ShowCursor( FALSE ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, TRUE ); + } + } + break; + + case KEY_LEFT: + if( pCursor ) + { + MakeVisible( pCursor ); + pNewCursor = pImpCursor->GoLeftRight(pCursor,FALSE ); + if( pNewCursor ) + { + if( bDeselAll ) + pView->SelectAll( FALSE ); + ShowCursor( FALSE ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, TRUE ); + } + else + { + Rectangle aRect( GetBoundingRect(pCursor)); + if( aRect.Left() ) + { + aRect.Right() -= aRect.Left(); + aRect.Left() = 0; + MakeVisible( aRect ); + } + } + } + break; + + case KEY_ESCAPE: + if( nFlags & F_RUBBERING ) + { + HideSelectionRect(); + pView->SelectAll( FALSE ); + nFlags &= ~F_RUBBERING; + } + break; + + case KEY_F8: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( nFlags & F_ADD_MODE ) + nFlags &= (~F_ADD_MODE); + else + nFlags |= F_ADD_MODE; + } + break; + +#ifdef OS2 + case KEY_F9: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( pCursor && pView->IsInplaceEditingEnabled() ) + pView->EditEntry( pCursor ); + } + break; +#endif + + case KEY_SPACE: + if( pCursor ) + { + ToggleSelection( pCursor ); + } + break; + + + case KEY_PAGEDOWN: + break; + case KEY_PAGEUP: + break; + + case KEY_ADD: + case KEY_DIVIDE : + if( bMod1 ) + pView->SelectAll( TRUE ); + break; + + case KEY_SUBTRACT: + case KEY_COMMA : + if( bMod1 ) + pView->SelectAll( FALSE ); + break; + + case KEY_RETURN: + if( bMod1 ) + { + if( pCursor && pView->IsInplaceEditingEnabled() ) + pView->EditEntry( pCursor ); + } + break; + + default: + bKeyUsed = FALSE; + + } + return bKeyUsed; +} + + +void SvImpIconView::PositionScrollBars( long nRealWidth, long nRealHeight ) +{ + // hor scrollbar + Point aPos( 0, nRealHeight ); + aPos.Y() -= nHorSBarHeight; + +#ifdef WIN + // vom linken und unteren Rand ein Pixel abschneiden + aPos.Y()++; + aPos.X()--; +#endif +#ifdef OS2 + aPos.Y()++; +#endif + if( aHorSBar.GetPosPixel() != aPos ) + aHorSBar.SetPosPixel( aPos ); + + // ver scrollbar + aPos.X() = nRealWidth; aPos.Y() = 0; + aPos.X() -= nVerSBarWidth; + +#if defined(WIN) || defined(WNT) + aPos.X()++; + aPos.Y()--; +#endif + +#ifdef OS2 + aPos.Y()--; + aPos.X()++; +#endif + +#ifdef MAC + aPos.Y()--; + aPos.X()++; +#endif + if( aVerSBar.GetPosPixel() != aPos ) + aVerSBar.SetPosPixel( aPos ); +} + + + +void SvImpIconView::AdjustScrollBars( BOOL bVirtSizeGrowedOnly ) +{ + long nVirtHeight = aVirtOutputSize.Height(); + long nVirtWidth = aVirtOutputSize.Width(); + + Size aOSize( pView->Control::GetOutputSizePixel() ); + long nRealHeight = aOSize.Height(); + long nRealWidth = aOSize.Width(); + + PositionScrollBars( nRealWidth, nRealHeight ); + + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + + long nVisibleWidth; + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + long nVisibleHeight; + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + int bVerSBar = pView->nWindowStyle & WB_VSCROLL; + int bHorSBar = pView->nWindowStyle & WB_HSCROLL; + + USHORT nResult = 0; + if( nVirtHeight ) + { + // activate ver scrollbar ? + if( bVerSBar || ( nVirtHeight > nVisibleHeight) ) + { + nResult = 0x0001; + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + } + // activate hor scrollbar ? + if( bHorSBar || (nVirtWidth > nVisibleWidth) ) + { + nResult |= 0x0002; + nRealHeight -= nHorSBarHeight; + + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + // brauchen wir jetzt doch eine senkrechte Scrollbar ? + if( !(nResult & 0x0001) && // nur wenn nicht schon da + ( (nVirtHeight > nVisibleHeight) || bVerSBar) ) + { + nResult = 3; // both are active + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + } + + // size ver scrollbar + long nThumb = aVerSBar.GetThumbPos(); + Size aSize( nVerSBarWidth, nRealHeight ); +#if defined(WIN) || defined(WNT) + aSize.Height() += 2; +#endif +#ifdef OS2 + aSize.Height() += 3; +#endif +#ifdef MAC + aSize.Height() += 2; +#endif + if( aSize != aVerSBar.GetSizePixel() ) + aVerSBar.SetSizePixel( aSize ); + aVerSBar.SetVisibleSize( nVisibleHeight ); + aVerSBar.SetPageSize( (nVisibleHeight*75)/100 ); + if( nResult & 0x0001 ) + { + aVerSBar.SetThumbPos( nThumb ); + aVerSBar.Show(); + } + else + { + aVerSBar.SetThumbPos( 0 ); + aVerSBar.Hide(); + } + + // size hor scrollbar + nThumb = aHorSBar.GetThumbPos(); + aSize.Width() = nRealWidth; + aSize.Height() = nHorSBarHeight; +#if defined(WIN) || defined(WNT) + aSize.Width()++; +#endif +#ifdef OS2 + aSize.Width() += 3; + if( nResult & 0x0001 ) // vertikale Scrollbar ? + aSize.Width()--; +#endif +#if defined(WIN) || defined(WNT) + if( nResult & 0x0001 ) // vertikale Scrollbar ? + { + aSize.Width()++; + nRealWidth++; + } +#endif + if( aSize != aHorSBar.GetSizePixel() ) + aHorSBar.SetSizePixel( aSize ); + aHorSBar.SetVisibleSize( nVisibleWidth ); //nRealWidth ); + aHorSBar.SetPageSize( (nVisibleWidth*75)/100 ); + if( nResult & 0x0002 ) + { + aHorSBar.SetThumbPos( nThumb ); + aHorSBar.Show(); + } + else + { + aHorSBar.SetThumbPos( 0 ); + aHorSBar.Hide(); + } + +#ifdef OS2 + nRealWidth++; +#endif + aOutputSize.Width() = nRealWidth; +#if defined(WIN) || defined(WNT) + if( nResult & 0x0002 ) // hor scrollbar ? + nRealHeight++; // weil unterer Rand geclippt wird +#endif +#ifdef OS2 + if( nResult & 0x0002 ) // hor scrollbar ? + nRealHeight++; +#endif + aOutputSize.Height() = nRealHeight; +} + +void __EXPORT SvImpIconView::Resize() +{ + StopEditTimer(); + Rectangle aRect; + if( GetResizeRect(aRect) ) + pView->Invalidate( aRect ); + aOutputSize = pView->GetOutputSizePixel(); + pImpCursor->Clear(); + +#if 1 + const Size& rSize = pView->Control::GetOutputSizePixel(); + PositionScrollBars( rSize.Width(), rSize.Height() ); + // Die ScrollBars werden asynchron ein/ausgeblendet, damit abgeleitete + // Klassen im Resize ein Arrange durchfuehren koennen, ohne dass + // die ScrollBars aufblitzen (SfxExplorerIconView!) + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpIconView,UserEventHdl),0); +#else + AdjustScrollBars(); + if( GetResizeRect(aRect) ) + PaintResizeRect( aRect ); +#endif +} + +BOOL SvImpIconView::CheckHorScrollBar() +{ + if( !pZOrderList || !aHorSBar.IsVisible() ) + return FALSE; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!(pView->nWindowStyle & WB_HSCROLL) && !aOrigin.X() ) + { + long nWidth = aOutputSize.Width(); + USHORT nCount = pZOrderList->Count(); + long nMostRight = 0; + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); + long nRight = GetBoundingRect(pEntry).Right(); + if( nRight > nWidth ) + return FALSE; + if( nRight > nMostRight ) + nMostRight = nRight; + } + aHorSBar.Hide(); + aOutputSize.Height() += nHorSBarHeight; + aVirtOutputSize.Width() = nMostRight; + aHorSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nMostRight - 1; + aHorSBar.SetRange( aRange ); + if( aVerSBar.IsVisible() ) + { + Size aSize( aVerSBar.GetSizePixel()); + aSize.Height() += nHorSBarHeight; + aVerSBar.SetSizePixel( aSize ); + } + return TRUE; + } + return FALSE; +} + +BOOL SvImpIconView::CheckVerScrollBar() +{ + if( !pZOrderList || !aVerSBar.IsVisible() ) + return FALSE; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!(pView->nWindowStyle & WB_VSCROLL) && !aOrigin.Y() ) + { + long nDeepest = 0; + long nHeight = aOutputSize.Height(); + USHORT nCount = pZOrderList->Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); + long nBottom = GetBoundingRect(pEntry).Bottom(); + if( nBottom > nHeight ) + return FALSE; + if( nBottom > nDeepest ) + nDeepest = nBottom; + } + aVerSBar.Hide(); + aOutputSize.Width() += nVerSBarWidth; + aVirtOutputSize.Height() = nDeepest; + aVerSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nDeepest - 1; + aVerSBar.SetRange( aRange ); + if( aHorSBar.IsVisible() ) + { + Size aSize( aHorSBar.GetSizePixel()); + aSize.Width() += nVerSBarWidth; + aHorSBar.SetSizePixel( aSize ); + } + return TRUE; + } + return FALSE; +} + + +// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden +void SvImpIconView::CheckScrollBars() +{ + CheckVerScrollBar(); + if( CheckHorScrollBar() ) + CheckVerScrollBar(); +} + + +void __EXPORT SvImpIconView::GetFocus() +{ + if( pCursor ) + { + pView->SetEntryFocus( pCursor, TRUE ); + ShowCursor( TRUE ); + } +} + +void __EXPORT SvImpIconView::LoseFocus() +{ + StopEditTimer(); + if( pCursor ) + pView->SetEntryFocus( pCursor,FALSE ); + ShowCursor( FALSE ); +} + +void SvImpIconView::UpdateAll() +{ + AdjustScrollBars(); + pImpCursor->Clear(); + pView->Invalidate(); +} + +void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) +{ + Point aPos( GetEntryPos( pEntry ) ); + PaintEntry( pEntry, aPos, pViewData ); +} + +void SvImpIconView::PaintEmphasis( const Rectangle& rRect, BOOL bSelected, + BOOL bInUse, BOOL bCursored, + OutputDevice* pOut ) +{ + // HACK fuer D&D + if( nFlags & F_NO_EMPHASIS ) + return; + + if( !pOut ) + pOut = pView; + + // Selektion painten + Color aOldFillColor = pOut->GetFillColor(); + Color aOldLineColor = pOut->GetLineColor(); + Color aNewColor; + const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); + if( bSelected ) + { + aNewColor = rStyleSettings.GetHighlightColor(); + } + else + { +#ifndef OS2 + aNewColor =rStyleSettings.GetFieldColor(); +#else + aNewColor = pOut->GetBackground().GetColor(); +#endif + } + + if( bCursored ) + { + pOut->SetLineColor( Color( COL_BLACK ) ); + } + pOut->SetFillColor( aNewColor ); + pOut->DrawRect( rRect ); + pOut->SetFillColor( aOldFillColor ); + pOut->SetLineColor( aOldLineColor ); +} + +void SvImpIconView::PaintItem( const Rectangle& rRect, + SvLBoxItem* pItem, SvLBoxEntry* pEntry, USHORT nPaintFlags, + OutputDevice* pOut ) +{ + if( nViewMode == VIEWMODE_ICON && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + const String& rStr = ((SvLBoxString*)pItem)->GetText(); + DrawText( pOut, rRect, rStr, DRAWTEXT_FLAGS ); + } + else + { + Point aPos( rRect.TopLeft() ); + const Size& rSize = GetItemSize( pView, pEntry, pItem ); + if( nPaintFlags & PAINTFLAG_HOR_CENTERED ) + aPos.X() += (rRect.GetWidth() - rSize.Width() ) / 2; + if( nPaintFlags & PAINTFLAG_VER_CENTERED ) + aPos.Y() += (rRect.GetHeight() - rSize.Height() ) / 2; + pItem->Paint( aPos, *(SvLBox*)pOut, 0, pEntry ); + } +} + +void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos, + SvIcnVwDataEntry* pViewData, OutputDevice* pOut ) +{ + if( !pView->IsUpdateMode() ) + return; + + if( !pOut ) + pOut = pView; + + SvLBoxContextBmp* pBmpItem; + + pView->PreparePaint( pEntry ); + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + + BOOL bSelected = pViewData->IsSelected(); + BOOL bCursored = pViewData->IsCursored(); + BOOL bInUse = pEntry->HasInUseEmphasis(); + + Font aTempFont( pOut->GetFont() ); + // waehrend D&D nicht die Fontfarbe wechseln, da sonst auch die + // Emphasis gezeichnet werden muss! (weisser Adler auf weissem Grund) + if( bSelected && !(nFlags & F_NO_EMPHASIS) ) + { + const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); + Font aNewFont( aTempFont ); + aNewFont.SetColor( rStyleSettings.GetHighlightTextColor() ); + pOut->SetFont( aNewFont ); + } + Rectangle aTextRect( CalcTextRect(pEntry,pStringItem,&rPos,FALSE,pViewData)); + Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos, pViewData ) ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + PaintEmphasis( aBmpRect, bSelected, bInUse, bCursored, pOut ); + PaintItem( aBmpRect, pBmpItem, pEntry, + PAINTFLAG_HOR_CENTERED | PAINTFLAG_VER_CENTERED, pOut ); + PaintEmphasis( aTextRect, bSelected, FALSE, FALSE, pOut ); + PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_HOR_CENTERED, pOut ); + break; + + case VIEWMODE_NAME: + pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + PaintEmphasis( aBmpRect, bSelected, bInUse, bCursored, pOut ); + PaintItem( aBmpRect, pBmpItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); + PaintEmphasis( aTextRect, bSelected, FALSE, FALSE, pOut ); + PaintItem( aTextRect, pStringItem, pEntry,PAINTFLAG_VER_CENTERED, pOut ); + break; + + case VIEWMODE_TEXT: + PaintEmphasis( aTextRect, bSelected, FALSE, bCursored, pOut ); + PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); + break; + } + pOut->SetFont( aTempFont ); +} + +void SvImpIconView::SetEntryPos( SvLBoxEntry* pEntry, const Point& rPos, + BOOL bAdjustAtGrid, BOOL bCheckScrollBars ) +{ + if( pModel->GetParent(pEntry) == pCurParent ) + { + ShowCursor( FALSE ); + long nVirtHeightOffs = 0; + long nVirtWidthOffs = 0; + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + Rectangle aBoundRect( GetBoundingRect( pEntry, pViewData )); + pView->Invalidate( aBoundRect ); + ToTop( pEntry ); + if( rPos != aBoundRect.TopLeft() ) + { + Point aGridOffs = pViewData->aGridRect.TopLeft() - + pViewData->aRect.TopLeft(); + pImpCursor->Clear(); + nFlags &= ~F_GRID_INSERT; + aBoundRect.SetPos( rPos ); + pViewData->aRect = aBoundRect; + pViewData->aGridRect.SetPos( rPos + aGridOffs ); + AdjustVirtSize( aBoundRect ); + } + //HACK(Billigloesung, die noch verbessert werden muss) + if( bAdjustAtGrid ) + { + AdjustAtGrid( pEntry ); + ToTop( pEntry ); + } + if( bCheckScrollBars && pView->IsUpdateMode() ) + CheckScrollBars(); + + PaintEntry( pEntry, pViewData ); + ShowCursor( TRUE ); + } +} + +void SvImpIconView::ViewDataInitialized( SvLBoxEntry*) +{ +} + +void SvImpIconView::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + if( pEntry == pCursor ) + ShowCursor( FALSE ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + pView->Invalidate( pViewData->aRect ); + + if( nFlags & F_GRIDMODE ) + Center( (SvLBoxEntry*)pEntry, pViewData ); + else + pViewData->aRect.SetSize( CalcBoundingSize( + (SvLBoxEntry*)pEntry, pViewData ) ); + + ViewDataInitialized( (SvLBoxEntry*)pEntry ); + pView->Invalidate( pViewData->aRect ); + if( pEntry == pCursor ) + ShowCursor( TRUE ); +} + + +void SvImpIconView::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + const Rectangle& rRect = GetBoundingRect( pEntry ); + pView->Invalidate( rRect ); +} + +void SvImpIconView::SetNoSelection() +{ +} + +void SvImpIconView::SetDragDropMode( DragDropMode ) +{ +} + +void SvImpIconView::SetSelectionMode( SelectionMode ) +{ +} + +BOOL SvImpIconView::IsEntryInView( SvLBoxEntry* ) +{ + return FALSE; +} + +SvLBoxEntry* SvImpIconView::GetDropTarget( const Point& rPos ) +{ + Point aDocPos( rPos ); + CalcDocPos( aDocPos ); + SvLBoxEntry* pTarget = GetEntry( aDocPos ); + if( !pTarget || !pTarget->HasChilds() ) + pTarget = pCurParent; + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetEntry( const Point& rDocPos ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + // Z-Order-Liste vom Ende her absuchen + USHORT nCount = pZOrderList->Count(); + while( nCount ) + { + nCount--; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCount)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetNextEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + USHORT nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != USHRT_MAX ) + { + USHORT nCount = pZOrderList->Count(); + for( USHORT nCur = nStartPos+1; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCur)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } + } + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetPrevEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + USHORT nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != USHRT_MAX && nStartPos != 0 ) + { + nStartPos--; + do + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nStartPos)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } while( nStartPos > 0 ); + } + return pTarget; +} + + +Point SvImpIconView::GetEntryPos( SvLBoxEntry* pEntry ) +{ + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model") + return pViewData->aRect.TopLeft(); +} + +const Rectangle& SvImpIconView::GetBoundingRect( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model") + if( !IsBoundingRectValid( pViewData->aRect )) + FindBoundingRect( pEntry, pViewData ); + return pViewData->aRect; +} + +void SvImpIconView::SetSpaceBetweenEntries( long nHor, long nVer ) +{ + nHorDist = nHor; + nVerDist = nVer; +} + +Rectangle SvImpIconView::CalcBmpRect( SvLBoxEntry* pEntry, const Point* pPos, + SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Rectangle aBound = GetBoundingRect( pEntry, pViewData ); + if( pPos ) + aBound.SetPos( *pPos ); + Point aPos( aBound.TopLeft() ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + { + aPos.X() += ( aBound.GetWidth() - nMaxBmpWidth ) / 2; + Size aSize( nMaxBmpWidth, nMaxBmpHeight ); + // das Bitmap-Rechteck soll nicht das TextRect beruehren + aSize.Height() -= 3; + return Rectangle( aPos, aSize ); + } + + case VIEWMODE_NAME: + return Rectangle( aPos, + Size( nMaxBmpWidth, aBound.GetHeight() )); + + case VIEWMODE_TEXT: + return Rectangle( aPos, aBound.GetSize() ); + + default: + { + Rectangle aRect; + return aRect; + } + } +} + +Rectangle SvImpIconView::CalcTextRect( SvLBoxEntry* pEntry, + SvLBoxString* pItem, const Point* pPos, BOOL bForInplaceEdit, + SvIcnVwDataEntry* pViewData ) +{ + long nBmpHeight, nBmpWidth; + + if( !pItem ) + pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Size aTextSize( GetItemSize( pView, pEntry, pItem, pViewData )); + aTextSize.Width() += 2*LROFFS_TEXT; + + Size aContextBmpSize(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry)); + Rectangle aBound = GetBoundingRect( pEntry, pViewData ); + if( pPos ) + aBound.SetPos( *pPos ); + Point aPos( aBound.TopLeft() ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nBmpHeight = aContextBmpSize.Height(); + if( nBmpHeight < nMaxBmpHeight ) + nBmpHeight = nMaxBmpHeight; + aPos.Y() += nBmpHeight; + + // beim Inplace-Editieren, spendieren wir ein bisschen mehr Platz + if( bForInplaceEdit ) + { + // 20% rauf + long nMinWidth = (( (aContextBmpSize.Width()*10) / 100 ) * 2 ) + + aContextBmpSize.Width(); + if( nMinWidth > aBound.GetWidth() ) + nMinWidth = aBound.GetWidth(); + + if( aTextSize.Width() < nMinWidth ) + aTextSize.Width() = nMinWidth; + + // beim Inplace-Ed. darfs auch untere Eintraege ueberlappen + Rectangle aMaxGridTextRect = CalcMaxTextRect(pEntry, pViewData); +#ifndef VCL + aMaxGridTextRect.Bottom() = LONG_MAX - 1; + aMaxGridTextRect = GetTextRect( pView, aMaxGridTextRect,pItem->GetText(), DRAWTEXT_FLAGS ); +#endif + Size aOptSize = aMaxGridTextRect.GetSize(); + if( aOptSize.Height() > aTextSize.Height() ) + aTextSize.Height() = aOptSize.Height(); + } + + + aPos.X() += ( aBound.GetWidth() - aTextSize.Width() ) / 2; + break; + + case VIEWMODE_NAME: + nBmpWidth = aContextBmpSize.Width(); + if( nBmpWidth < nMaxBmpWidth ) + nBmpWidth = nMaxBmpWidth; + aPos.X() += nBmpWidth; + // vertikal ausrichten + aPos.Y() += ( nBmpWidth - aTextSize.Height() ) / 2; + break; + } + + Rectangle aRect( aPos, aTextSize ); +// KNALLT BEIM D&D, WENN GECLIPPT WIRD (In DrawText von Thomas) +// ClipAtVirtOutRect( aRect ); + return aRect; +} + + +long SvImpIconView::CalcBoundingWidth( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps") + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text") + long nStringWidth = GetItemSize( pView, pEntry, pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Width(); + nStringWidth += 2*LROFFS_TEXT; + long nBmpWidth = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Width(); + long nWidth = 0; + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nWidth = Max( nStringWidth, nBmpWidth ); + nWidth = Max( nWidth, nMaxBmpWidth ); + break; + + case VIEWMODE_NAME: + nWidth = Max( nBmpWidth, nMaxBmpWidth ); + nWidth += NAMEVIEW_OFFS_BMP_STRING; // Abstand Bitmap String + nWidth += nStringWidth; + break; + + case VIEWMODE_TEXT: + nWidth = nStringWidth; + break; + } + return nWidth; +} + +long SvImpIconView::CalcBoundingHeight( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps") + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text") + long nStringHeight = GetItemSize(pView,pEntry,pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Height(); + long nBmpHeight = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Height(); + long nHeight = 0; + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nHeight = Max( nBmpHeight, nMaxBmpHeight ); + nHeight += ICONVIEW_OFFS_BMP_STRING; // Abstand Bitmap String + nHeight += nStringHeight; + break; + + case VIEWMODE_NAME: + nHeight = Max( nBmpHeight, nMaxBmpHeight ); + nHeight = Max( nHeight, nStringHeight ); + break; + + case VIEWMODE_TEXT: + nHeight = nStringHeight; + break; + } + if( nHeight > nMaxBoundHeight ) + { + ((SvImpIconView*)this)->nMaxBoundHeight = nHeight; + ((SvImpIconView*)this)->aHorSBar.SetLineSize( nHeight / 2 ); + ((SvImpIconView*)this)->aVerSBar.SetLineSize( nHeight / 2 ); + } + return nHeight; +} + +Size SvImpIconView::CalcBoundingSize( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) const +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + return Size( CalcBoundingWidth(pEntry,pViewData), + CalcBoundingHeight(pEntry,pViewData) ); +} + +void SvImpIconView::RecalcAllBoundingRects() +{ + nMaxBoundHeight = 0; + pZOrderList->Remove(0, pZOrderList->Count() ); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + pEntry = pModel->NextSibling( pEntry ); + } + bMustRecalcBoundingRects = FALSE; + AdjustScrollBars(); +} + +void SvImpIconView::RecalcAllBoundingRectsSmart() +{ + nMaxBoundHeight = 0; + pZOrderList->Remove(0, pZOrderList->Count() ); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect )) + { + Size aBoundSize( pViewData->aRect.GetSize() ); + if( aBoundSize.Height() > nMaxBoundHeight ) + nMaxBoundHeight = aBoundSize.Height(); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + } + else + { + FindBoundingRect( pEntry, pViewData ); + } + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + pEntry = pModel->NextSibling( pEntry ); + } + AdjustScrollBars(); +} + +void SvImpIconView::UpdateBoundingRects() +{ + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + GetBoundingRect( pEntry ); + pEntry = pModel->NextSibling( pEntry ); + } +} + +void SvImpIconView::FindBoundingRect( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Size aSize( CalcBoundingSize( pEntry, pViewData ) ); + Point aPos; + + DBG_ASSERT(!pViewData->IsEntryPosLocked(),"Locked entry pos in FindBoundingRect"); + // damits in der IconView nicht drunter & drueber geht + if( pViewData->IsEntryPosLocked() && IsBoundingRectValid(pViewData->aRect) ) + { + AdjustVirtSize( pViewData->aRect ); + return; + } + + aPos = FindNextEntryPos( aSize ); + + if( nFlags & F_GRIDMODE ) + { + Rectangle aGridRect( aPos, Size(nGridDX, nGridDY) ); + pViewData->aGridRect = aGridRect; + Center( pEntry, pViewData ); + AdjustVirtSize( pViewData->aRect ); + pImpCursor->SetGridUsed( pViewData->aRect ); + } + else + { + pViewData->aRect = Rectangle( aPos, aSize ); + AdjustVirtSize( pViewData->aRect ); + } +} + + +void SvImpIconView::SetCursor( SvLBoxEntry* pEntry ) +{ + if( pEntry == pCursor ) + return; + + ShowCursor( FALSE ); + if( pCursor ) + { + pView->SetEntryFocus( pCursor, FALSE ); + if( pView->GetSelectionMode() == SINGLE_SELECTION ) + pView->Select( pCursor, FALSE ); + } + pCursor = pEntry; + ToTop( pCursor ); + if( pCursor ) + { + pView->SetEntryFocus(pCursor, TRUE ); + if( pView->GetSelectionMode() == SINGLE_SELECTION ) + pView->Select( pCursor, TRUE ); + ShowCursor( TRUE ); + } +} + + +void SvImpIconView::ShowCursor( BOOL bShow ) +{ + if( !pCursor || !bShow || !pView->HasFocus() ) + { + pView->HideFocus(); + return; + } + Rectangle aRect ( CalcFocusRect( pCursor ) ); + pView->ShowFocus( aRect ); +} + + +void SvImpIconView::HideDDIcon() +{ + pView->Update(); + ImpHideDDIcon(); + pDDBufDev = pDDDev; + pDDDev = 0; +} + +void SvImpIconView::ImpHideDDIcon() +{ + if( pDDDev ) + { + Size aSize( pDDDev->GetOutputSizePixel() ); + // pView restaurieren + pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev ); + } +} + + +void SvImpIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) +{ + pView->Update(); + if( pRefEntry != pDDRefEntry ) + { + DELETEZ(pDDDev); + DELETEZ(pDDBufDev); + } + BOOL bSelected = pView->SvListView::Select( pRefEntry, FALSE ); + if( !pDDDev ) + { + if( pDDBufDev ) + { + // nicht bei jedem Move ein Device anlegen, da dies besonders + // auf Remote-Clients zu langsam ist + pDDDev = pDDBufDev; + pDDBufDev = 0; + } + else + { + pDDDev = new VirtualDevice( *pView ); + pDDDev->SetFont( pView->GetFont() ); + } + } + else + { + ImpHideDDIcon(); + } + const Rectangle& rRect = GetBoundingRect( pRefEntry ); + pDDDev->SetOutputSizePixel( rRect.GetSize() ); + + Point aPos( rPosPix ); + CalcDocPos( aPos ); + + Size aSize( pDDDev->GetOutputSizePixel() ); + pDDRefEntry = pRefEntry; + aDDLastEntryPos = aPos; + aDDLastRectPos = aPos; + + // Hintergrund sichern + pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView ); + // Icon in pView malen + nFlags |= F_NO_EMPHASIS; + PaintEntry( pRefEntry, aPos ); + nFlags &= ~F_NO_EMPHASIS; + if( bSelected ) + pView->SvListView::Select( pRefEntry, TRUE ); +} + +void SvImpIconView::HideShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) +{ +/* In Notfaellen folgenden flackernden Code aktivieren: + + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; +*/ + if( !pDDDev ) + { + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + if( pRefEntry != pDDRefEntry ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + Point aEmptyPoint; + + Point aCurEntryPos( rPosPix ); + CalcDocPos( aCurEntryPos ); + + const Rectangle& rRect = GetBoundingRect( pRefEntry ); + Size aEntrySize( rRect.GetSize() ); + Rectangle aPrevEntryRect( aDDLastEntryPos, aEntrySize ); + Rectangle aCurEntryRect( aCurEntryPos, aEntrySize ); + + if( !aPrevEntryRect.IsOver( aCurEntryRect ) ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + // Ueberlappung des neuen und alten D&D-Pointers! + + Rectangle aFullRect( aPrevEntryRect.Union( aCurEntryRect ) ); + if( !pDDTempDev ) + { + pDDTempDev = new VirtualDevice( *pView ); + pDDTempDev->SetFont( pView->GetFont() ); + } + + Size aFullSize( aFullRect.GetSize() ); + Point aFullPos( aFullRect.TopLeft() ); + + pDDTempDev->SetOutputSizePixel( aFullSize ); + + // Hintergrund (mit dem alten D&D-Pointer!) sichern + pDDTempDev->DrawOutDev( aEmptyPoint, aFullSize, aFullPos, aFullSize, *pView ); + // den alten Buffer in den neuen Buffer pasten + aDDLastRectPos = aDDLastRectPos - aFullPos; + + pDDTempDev->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDDev ); + + // Swap + VirtualDevice* pTemp = pDDDev; + pDDDev = pDDTempDev; + pDDTempDev = pTemp; + + // in den restaurierten Hintergrund den neuen D&D-Pointer zeichnen + pDDTempDev->SetOutputSizePixel( pDDDev->GetOutputSizePixel() ); + pDDTempDev->DrawOutDev( + aEmptyPoint, aFullSize, aEmptyPoint, aFullSize, *pDDDev ); + Point aRelPos = aCurEntryPos - aFullPos; + nFlags |= F_NO_EMPHASIS; + PaintEntry( pRefEntry, aRelPos, 0, pDDTempDev ); + nFlags &= ~F_NO_EMPHASIS; + + aDDLastRectPos = aFullPos; + aDDLastEntryPos = aCurEntryPos; + + pView->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDTempDev ); + + BOOL bSelected = pView->SvListView::Select( pRefEntry, FALSE ); + if( bSelected ) + pView->SvListView::Select( pRefEntry, TRUE ); +} + +void SvImpIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, BOOL bShow ) +{ + CheckBoundingRects(); + Rectangle aRect; + if( pEntry != pCurParent && + (pEntry->HasChilds() || pEntry->HasChildsOnDemand()) ) + aRect = CalcBmpRect( pEntry ); + else + { + aRect.SetSize( aOutputSize ); + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin()); + aOrigin *= -1; // in Doc-Koord wandeln + aRect.SetPos( aOrigin ); + aRect.Left()++; aRect.Top()++; + aRect.Right()--; aRect.Bottom()--; + } + ImpDrawXORRect( aRect ); +} + +BOOL SvImpIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewPar, ULONG& rNewChildPos ) +{ + if( pTarget == pCurParent && pModel->GetParent(pEntry) == pCurParent ) + { + // D&D innerhalb einer Childlist + StopEditTimer(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + Size aSize( pViewData->aRect.GetSize() ); + Point aNewPos = FindNextEntryPos( aSize ); + AdjustVirtSize( Rectangle( aNewPos, aSize ) ); + SetEntryPos( pEntry, aNewPos, FALSE, TRUE ); + return FALSE; + } + return pView->SvLBox::NotifyMoving(pTarget,pEntry,rpNewPar,rNewChildPos); +} + +BOOL SvImpIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, ULONG& rNewChildPos ) +{ + return pView->SvLBox::NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos); +} + +void SvImpIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo) +{ + SvLBoxEntry* pCurEntry = GetCurEntry(); + Point aEntryPos; + if( pCurEntry ) + { + aEntryPos = rPos; + aEntryPos -= GetEntryPos( pCurEntry ); + } + pInfo->nMouseRelX = aEntryPos.X(); + pInfo->nMouseRelY = aEntryPos.Y(); +} + +void SvImpIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo ) +{ + Point aDropPos( rPos ); + aDropPos.X() -= pInfo->nMouseRelX; + aDropPos.Y() -= pInfo->nMouseRelY; + SetNextEntryPos( aDropPos ); +} + +void SvImpIconView::InvalidateBoundingRect( SvLBoxEntry* pEntry ) +{ + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + InvalidateBoundingRect( pViewData->aRect ); +} + +void SvImpIconView::PrepareCommandEvent( const CommandEvent& rCEvt ) +{ + aMouseMoveTimer.Stop(); + StopEditTimer(); + nFlags |= F_CMD_ARRIVED; + SvLBoxEntry* pEntry = pView->GetEntry( rCEvt.GetMousePosPixel(), TRUE ); + if( (nFlags & F_DOWN_CTRL) && pEntry && !pView->IsSelected(pEntry) ) + pView->Select( pEntry, TRUE ); + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); +} + +void SvImpIconView::Command( const CommandEvent& rCEvt ) +{ + PrepareCommandEvent( rCEvt ); + if( rCEvt.GetCommand() == COMMAND_STARTDRAG ) + { + nFlags |= F_DRAG_SOURCE; + if( GetSelectionCount() ) + { + ShowCursor( FALSE ); + pView->BeginDrag( rCEvt.GetMousePosPixel() ); + ShowCursor( TRUE ); + } + nFlags &= (~F_DRAG_SOURCE); + } +} + +void SvImpIconView::ToTop( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"ToTop:ZOrder?"); + if( pZOrderList->GetObject( pZOrderList->Count() -1 ) != pEntry ) + { + USHORT nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + } +} + +void SvImpIconView::SetCurParent( SvLBoxEntry* pNewParent ) +{ + Clear(); + pCurParent = pNewParent; + ImpArrange(); +} + +void SvImpIconView::ClipAtVirtOutRect( Rectangle& rRect ) const +{ + if( rRect.Bottom() >= aVirtOutputSize.Height() ) + rRect.Bottom() = aVirtOutputSize.Height() - 1; + if( rRect.Right() >= aVirtOutputSize.Width() ) + rRect.Right() = aVirtOutputSize.Width() - 1; + if( rRect.Top() < 0 ) + rRect.Top() = 0; + if( rRect.Left() < 0 ) + rRect.Left() = 0; +} + +// rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der +// sichtbar gemacht werden soll. +// bScrBar == TRUE: Das Rect wurde aufgrund eines ScrollBar-Events berechnet + +void SvImpIconView::MakeVisible( const Rectangle& rRect, BOOL bScrBar ) +{ + Rectangle aRect( rRect ); + ClipAtVirtOutRect( aRect ); + MapMode aMapMode( pView->GetMapMode() ); + Point aOrigin( aMapMode.GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + + Rectangle aOutputArea( aOrigin, aOutputSize ); + if( aOutputArea.IsInside( aRect ) ) + return; // ist schon sichtbar + + long nDy; + if( aRect.Top() < aOutputArea.Top() ) + { + // nach oben scrollen (nDy < 0) + nDy = aRect.Top() - aOutputArea.Top(); + } + else if( aRect.Bottom() > aOutputArea.Bottom() ) + { + // nach unten scrollen (nDy > 0) + nDy = aRect.Bottom() - aOutputArea.Bottom(); + } + else + nDy = 0; + + long nDx; + if( aRect.Left() < aOutputArea.Left() ) + { + // nach links scrollen (nDx < 0) + nDx = aRect.Left() - aOutputArea.Left(); + } + else if( aRect.Right() > aOutputArea.Right() ) + { + // nach rechts scrollen (nDx > 0) + nDx = aRect.Right() - aOutputArea.Right(); + } + else + nDx = 0; + + aOrigin.X() += nDx; + aOrigin.Y() += nDy; + aOutputArea.SetPos( aOrigin ); + + pView->Update(); + + // Origin fuer SV invertieren (damit wir in + // Dokumentkoordinaten scrollen/painten koennen) + aOrigin *= -1; + aMapMode.SetOrigin( aOrigin ); + pView->SetMapMode( aMapMode ); + + // in umgekehrte Richtung scrollen! + pView->Control::Scroll( -nDx, -nDy, aOutputArea, TRUE ); + if( aHorSBar.IsVisible() || aVerSBar.IsVisible() ) + { + if( !bScrBar ) + { + aOrigin *= -1; + // Thumbs korrigieren + if(aHorSBar.IsVisible() && aHorSBar.GetThumbPos() != aOrigin.X()) + aHorSBar.SetThumbPos( aOrigin.X() ); + if(aVerSBar.IsVisible() && aVerSBar.GetThumbPos() != aOrigin.Y()) + aVerSBar.SetThumbPos( aOrigin.Y() ); + } + } + // pruefen, ob ScrollBars noch benoetigt werden + CheckScrollBars(); + pView->Update(); +} + + +SvLBoxEntry* SvImpIconView::GetNewCursor() +{ + SvLBoxEntry* pNewCursor; + if( pCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, FALSE ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, TRUE ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoUpDown( pCursor, FALSE ); + if( !pNewCursor ) + pNewCursor = pImpCursor->GoUpDown( pCursor, TRUE ); + } + } + } + else + pNewCursor = pModel->FirstChild( pCurParent ); + DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"GetNewCursor failed"); + return pNewCursor; +} + + +USHORT SvImpIconView:: GetSelectionCount() const +{ + USHORT nSelected = 0; + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent); + while( pEntry ) + { + if( pView->IsSelected( pEntry ) ) + nSelected++; + pEntry = pModel->NextSibling( pEntry ); + } + return nSelected; +} + + +void SvImpIconView::ToggleSelection( SvLBoxEntry* pEntry ) +{ + BOOL bSel; + if( pView->IsSelected( pEntry ) ) + bSel = FALSE; + else + bSel = TRUE; + pView->Select( pEntry, bSel ); +} + +void SvImpIconView::DeselectAllBut( SvLBoxEntry* pThisEntryNot ) +{ + ClearSelectedRectList(); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + if( pEntry != pThisEntryNot && pView->IsSelected( pEntry )) + pView->Select( pEntry, FALSE ); + pEntry = pModel->NextSibling( pEntry ); + } +} + +#define ICN_ROWS 50 +#define ICN_COLS 30 + +ImpIcnCursor::ImpIcnCursor( SvImpIconView* pOwner ) +{ + pView = pOwner; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight= 0; + nCols = 0; + nRows = 0; + nGridCols = 0; + nGridRows = 0; + pGridMap = 0; +} + +ImpIcnCursor::~ImpIcnCursor() +{ + delete[] pColumns; + delete[] pRows; + delete pGridMap; +} + +USHORT ImpIcnCursor::GetSortListPos( SvPtrarr* pList, long nValue, + int bVertical ) +{ + USHORT nCount = (USHORT)pList->Count(); + if( !nCount ) + return 0; + + USHORT nCurPos = 0; + long nPrevValue = LONG_MIN; + while( nCount ) + { + const Rectangle& rRect= + pView->GetBoundingRect((SvLBoxEntry*)(pList->GetObject(nCurPos))); + long nCurValue; + if( bVertical ) + nCurValue = rRect.Top(); + else + nCurValue = rRect.Left(); + if( nValue >= nPrevValue && nValue <= nCurValue ) + return (USHORT)nCurPos; + nPrevValue = nCurValue; + nCount--; + nCurPos++; + } + return pList->Count(); +} + +void ImpIcnCursor::ImplCreate() +{ + pView->CheckBoundingRects(); + DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared"); + + SetDeltas(); + + pColumns = new SvPtrarr[ nCols ]; + pRows = new SvPtrarr[ nRows ]; + + DELETEZ(pGridMap); + + SvLBoxTreeList* pModel = pView->pModel; + SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + // const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + Rectangle rRect( pView->CalcBmpRect( pEntry,0,pViewData ) ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight ); + short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth ); + + // Rundungsfehler abfangen + if( nY >= nRows ) + nY = nRows - 1; + if( nX >= nCols ) + nX = nCols - 1; + + USHORT nIns = GetSortListPos( &pColumns[nX], rRect.Top(), TRUE ); + pColumns[ nX ].Insert( pEntry, nIns ); + + nIns = GetSortListPos( &pRows[nY], rRect.Left(), FALSE ); + pRows[ nY ].Insert( pEntry, nIns ); + + pViewData->nX = nX; + pViewData->nY = nY; + + pEntry = pModel->NextSibling( pEntry ); + } +} + +void ImpIcnCursor::CreateGridMap() +{ + if( pGridMap ) + return; + + const Size& rSize = pView->aVirtOutputSize; + long nWidth = rSize.Width(); + if( nWidth < pView->nMaxVirtWidth ) + nWidth = pView->nMaxVirtWidth; + nWidth -= 2*LROFFS_WINBORDER; + if( nWidth <= 0 ) + nWidth = 1; + + nGridDX = pView->nGridDX; + nGridDY = pView->nGridDY; + + // Hinweis: Wegen der Abrundung bei Berechnung von nGridCols + // ist es moeglich, dass Eintrage nicht im Grid liegen. Diese + // wurden typischerweise manuell verschoben und gelockt + nGridCols = nWidth / nGridDX; + if( !nGridCols ) nGridCols = 1; + + nGridRows = rSize.Height() / nGridDY; + // nRows nicht abrunden, da zur Vermeidung von Ueberlappungen + // das gesamte BoundingRect des Eintrags zur Markierung im Grid + // herangezogen wird. + if( (nGridRows * nGridDY) < rSize.Height() ) + nGridRows++; + else if( !nGridRows ) + nGridRows = 1; + + //XXX + //nGridRows += 50; // in fuenfziger-Schritten + + pGridMap = new BOOL[ nGridRows*nGridCols]; + memset( (void*)pGridMap, 0, nGridRows*nGridCols ); + + SvLBoxTreeList* pModel = pView->pModel; + SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + const Rectangle& rRect = pViewData->aRect; + // nur, wenn der Entry schon plaziert ist + if( pView->IsBoundingRectValid( rRect )) + { + // Alle vom Eintrag beruehrten Grids kennzeichnen + SetGridUsed( pView->GetBoundingRect( pEntry, pViewData ) ); + } + pEntry = pModel->NextSibling( pEntry ); + } +} + +BOOL ImpIcnCursor::GetGrid( const Point& rDocPos, USHORT& rGridX, USHORT& rGridY ) const +{ + Point aPos( rDocPos ); + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + rGridX = (USHORT)(aPos.X() / nGridDX); + rGridY = (USHORT)(aPos.Y() / nGridDY); + BOOL bInGrid = TRUE; + if( rGridX >= nGridCols ) + { + rGridX = nGridCols - 1; + bInGrid = FALSE; + } + if( rGridY >= nGridRows ) + { + rGridY = nGridRows - 1; + if( !bInGrid ) + return FALSE; // beide Koordinaten nicht im Grid + } + return TRUE; +} + +void ImpIcnCursor::SetGridUsed( const Rectangle& rRect, BOOL bUsed ) +{ + CreateGridMap(); + USHORT nTLX, nTLY, nBRX, nBRY; + + BOOL bTLInGrid = GetGrid( rRect.TopLeft(), nTLX, nTLY ); + BOOL bBRInGrid = GetGrid( rRect.BottomRight(), nBRX, nBRY ); + + if( !bTLInGrid && !bBRInGrid ) + return; + + for( USHORT nCurY = nTLY; nCurY <= nBRY; nCurY++ ) + { + for( USHORT nCurX = nTLX; nCurX <= nBRX; nCurX++ ) + { + SetGridUsed( nCurX, nCurY, bUsed ); + } + } +} + +void ImpIcnCursor::Clear( BOOL bGridToo ) +{ + if( pColumns ) + { + delete[] pColumns; + delete[] pRows; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight = 0; + } + if( bGridToo && pGridMap ) + { + DELETEZ(pGridMap); + nGridRows = 0; + nGridCols = 0; + } +} + +SvLBoxEntry* ImpIcnCursor::SearchCol(USHORT nCol,USHORT nTop,USHORT nBottom, + USHORT nPref, BOOL bDown, BOOL bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchCol: No reference entry"); + SvPtrarr* pList = &(pColumns[ nCol ]); + USHORT nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); + + if( bSimple ) + { + USHORT nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List"); + if( bDown ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Top() > rRefRect.Top() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Top() < rRefRect.Top() ) + return pEntry; + } + } + return 0; + } + } + + if( nTop > nBottom ) + { + USHORT nTemp = nTop; + nTop = nBottom; + nBottom = nTemp; + } + long nMinDistance = LONG_MAX; + SvLBoxEntry* pResult = 0; + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + USHORT nY = pViewData->nY; + if( nY >= nTop && nY <= nBottom ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + long nDistance = rRect.Top() - rRefRect.Top(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + +SvLBoxEntry* ImpIcnCursor::SearchRow(USHORT nRow,USHORT nLeft,USHORT nRight, + USHORT nPref, BOOL bRight, BOOL bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchRow: No reference entry"); + SvPtrarr* pList = &(pRows[ nRow ]); + USHORT nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); + + if( bSimple ) + { + USHORT nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List"); + if( bRight ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Left() > rRefRect.Left() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Left() < rRefRect.Left() ) + return pEntry; + } + } + return 0; + } + + } + if( nRight < nLeft ) + { + USHORT nTemp = nRight; + nRight = nLeft; + nLeft = nTemp; + } + long nMinDistance = LONG_MAX; + SvLBoxEntry* pResult = 0; + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + USHORT nX = pViewData->nX; + if( nX >= nLeft && nX <= nRight ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + long nDistance = rRect.Left() - rRefRect.Left(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + + + +/* + Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw. + linksstehenden. Suchverfahren am Beispiel bRight = TRUE: + + c + b c + a b c + S 1 1 1 ====> Suchrichtung + a b c + b c + c + + S : Startposition + 1 : erstes Suchrechteck + a,b,c : 2., 3., 4. Suchrechteck +*/ + +SvLBoxEntry* ImpIcnCursor::GoLeftRight( SvLBoxEntry* pEntry, BOOL bRight ) +{ + SvLBoxEntry* pResult; + pCurEntry = pEntry; + Create(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + USHORT nY = pViewData->nY; + USHORT nX = pViewData->nX; + DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column"); + DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row"); + // Nachbar auf gleicher Zeile ? + if( bRight ) + pResult = SearchRow( nY, nX ,nCols-1, nX, TRUE, TRUE ); + else + pResult = SearchRow( nY, nX ,0, nX, FALSE, TRUE ); + if( pResult ) + return pResult; + + long nCurCol = nX; + + long nColOffs, nLastCol; + if( bRight ) + { + nColOffs = 1; + nLastCol = nCols; + } + else + { + nColOffs = -1; + nLastCol = -1; // 0-1 + } + + USHORT nRowMin = nY; + USHORT nRowMax = nY; + do + { + SvLBoxEntry* pEntry = SearchCol((USHORT)nCurCol,nRowMin,nRowMax,nY,TRUE, FALSE); + if( pEntry ) + return pEntry; + if( nRowMin ) + nRowMin--; + if( nRowMax < (nRows-1)) + nRowMax++; + nCurCol += nColOffs; + } while( nCurCol != nLastCol ); + return 0; +} + +SvLBoxEntry* ImpIcnCursor::GoUpDown( SvLBoxEntry* pEntry, BOOL bDown) +{ + SvLBoxEntry* pResult; + pCurEntry = pEntry; + Create(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + USHORT nY = pViewData->nY; + USHORT nX = pViewData->nX; + DBG_ASSERT(nY<nRows,"GoUpDown:Bad column"); + DBG_ASSERT(nX<nCols,"GoUpDown:Bad row"); + + // Nachbar in gleicher Spalte ? + if( bDown ) + pResult = SearchCol( nX, nY ,nRows-1, nY, TRUE, TRUE ); + else + pResult = SearchCol( nX, nY ,0, nY, FALSE, TRUE ); + if( pResult ) + return pResult; + + long nCurRow = nY; + + long nRowOffs, nLastRow; + if( bDown ) + { + nRowOffs = 1; + nLastRow = nRows; + } + else + { + nRowOffs = -1; + nLastRow = -1; // 0-1 + } + + USHORT nColMin = nX; + USHORT nColMax = nX; + do + { + SvLBoxEntry* pEntry = SearchRow((USHORT)nCurRow,nColMin,nColMax,nX,TRUE, FALSE); + if( pEntry ) + return pEntry; + if( nColMin ) + nColMin--; + if( nColMax < (nCols-1)) + nColMax++; + nCurRow += nRowOffs; + } while( nCurRow != nLastRow ); + return 0; +} + +void ImpIcnCursor::SetDeltas() +{ + const Size& rSize = pView->aVirtOutputSize; + if( pView->nFlags & F_GRIDMODE ) + { + nGridDX = pView->nGridDX; + nGridDY = pView->nGridDY; + } + else + { + nGridDX = 20; + nGridDY = 20; + } + nCols = rSize.Width() / nGridDX; + if( !nCols ) + nCols = 1; + nRows = rSize.Height() / nGridDY; + if( (nRows * nGridDY) < rSize.Height() ) + nRows++; + if( !nRows ) + nRows = 1; + + nDeltaWidth = (short)(rSize.Width() / nCols); + nDeltaHeight = (short)(rSize.Height() / nRows); + if( !nDeltaHeight ) + { + nDeltaHeight = 1; + DBG_WARNING("SetDeltas:Bad height"); + } + if( !nDeltaWidth ) + { + nDeltaWidth = 1; + DBG_WARNING("SetDeltas:Bad width"); + } +} + + +void ImpIcnCursor::ExpandGrid() +{ + if( pGridMap ) + { + long nNewGridRows = nGridRows + 20; + unsigned char* pTempMap = new unsigned char[ nNewGridRows * nGridCols ]; + memset( pTempMap, nNewGridRows * nGridCols, 0 ); + memcpy( pTempMap, pGridMap, nGridRows * nGridCols ); + delete pGridMap; + pGridMap = pTempMap; + nGridRows = nNewGridRows; + } +} + +BOOL ImpIcnCursor::FindEmptyGridRect( Rectangle& rRect ) +{ + CreateGridMap(); + USHORT nCount = (USHORT)(nGridCols * nGridRows); + if( !nCount ) + return FALSE; + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + if( !pGridMap[ nCur ] ) + { + USHORT nCol = (USHORT)(nCur % nGridCols); + USHORT nRow = (USHORT)(nCur / nGridCols); + rRect.Top() = nRow * nGridDY + TBOFFS_WINBORDER; + rRect.Bottom() = rRect.Top() + nGridDY; + rRect.Left() = nCol * nGridDX+ LROFFS_WINBORDER; + rRect.Right() = rRect.Left() + nGridDX; + SetGridUsed( nCol, nRow, TRUE ); + + //XXX + //if( nRow + 5 > nGridRows ) + // ExpandGrid(); + DBG_ASSERT(pGridMap[nCur],"SetGridUsed failed"); + return TRUE; + } + } + // Gridmap ist voll: Um eine Zeile erweitern + rRect.Top() = nGridRows * nGridDY + TBOFFS_WINBORDER; + rRect.Bottom() = rRect.Top() + nGridDY; + rRect.Left() = LROFFS_WINBORDER; + rRect.Right() = rRect.Left() + nGridDX; + return FALSE; + //XXX + //ExpandGrid(); + //return TRUE; +} + +void ImpIcnCursor::CreateGridAjustData( SvPtrarr& rLists, SvLBoxEntry* pRefEntry) +{ + if( !pRefEntry ) + { + USHORT nRows = (USHORT)(pView->aVirtOutputSize.Height() / pView->nGridDY); + nRows++; // wg. Abrundung! + + if( !nRows ) + return; + for( USHORT nCurList = 0; nCurList < nRows; nCurList++ ) + { + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, nCurList ); + } + SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + USHORT nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),FALSE); + ((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns ); + pEntry = pView->pModel->NextSibling( pEntry ); + } + } + else + { + // Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile + + // UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen??? + + Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) ); + //const Rectangle& rRefRect = pView->GetBoundingRect( pRefEntry ); + short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY ); + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, 0 ); + SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + Rectangle rRect( pView->CalcBmpRect(pEntry) ); + //const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + if( nY == nRefRow ) + { + USHORT nIns = GetSortListPos( pRow, rRect.Left(), FALSE ); + pRow->Insert( pEntry, nIns ); + } + pEntry = pView->pModel->NextSibling( pEntry ); + } + } +} + +//static +void ImpIcnCursor::DestroyGridAdjustData( SvPtrarr& rLists ) +{ + USHORT nCount = rLists.Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ]; + delete pArr; + } + rLists.Remove( 0, rLists.Count() ); +} + +void SvImpIconView::SetGrid( long nDX, long nDY ) +{ + nGridDX = nDX; + nGridDY = nDY; + nFlags |= F_GRIDMODE; +} + +Rectangle SvImpIconView::CalcMaxTextRect( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + Rectangle aRect = pViewData->aGridRect; + long nBmpHeight = ((SvLBoxEntry*)pEntry)->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,(SvLBoxEntry*)pEntry).Height(); + aRect.Top() += nBmpHeight; + aRect.Top() += ICONVIEW_OFFS_BMP_STRING; + if( aRect.Top() > aRect.Bottom()) + aRect.Top() = aRect.Bottom(); + aRect.Left() += LROFFS_BOUND; + aRect.Left()++; + aRect.Right() -= LROFFS_BOUND; + aRect.Right()--; + if( aRect.Left() > aRect.Right()) + aRect.Left() = aRect.Right(); + if( GetTextMode( pEntry, pViewData ) == ShowTextFull ) + aRect.Bottom() = LONG_MAX; + return aRect; +} + +void SvImpIconView::Center( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) const +{ + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + const String& rEntryText = pStringItem->GetText(); + + Rectangle aTextRect = CalcMaxTextRect(pEntry,pViewData); + aTextRect = GetTextRect( pView, aTextRect, rEntryText, DRAWTEXT_FLAGS ); + pViewData->aTextSize = aTextRect.GetSize(); + + pViewData->aRect = pViewData->aGridRect; + Size aSize( CalcBoundingSize( pEntry, pViewData ) ); + long nBorder = pViewData->aGridRect.GetWidth() - aSize.Width(); + pViewData->aRect.Left() += nBorder / 2; + pViewData->aRect.Right() -= nBorder / 2; + pViewData->aRect.Bottom() = pViewData->aRect.Top() + aSize.Height(); +} + + +// Die Deltas entsprechen Offsets, um die die View auf dem Doc verschoben wird +// links, hoch: Offsets < 0 +// rechts, runter: Offsets > 0 +void SvImpIconView::Scroll( long nDeltaX, long nDeltaY, BOOL bScrollBar ) +{ + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + aOrigin.Y() += nDeltaY; + aOrigin.X() += nDeltaX; + Rectangle aRect( aOrigin, aOutputSize ); + MakeVisible( aRect, bScrollBar ); +} + + +const Size& SvImpIconView::GetItemSize( SvIconView* pView, + SvLBoxEntry* pEntry, SvLBoxItem* pItem, const SvIcnVwDataEntry* pViewData) const +{ + if( (nFlags & F_GRIDMODE) && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + return pViewData->aTextSize; + } + else + return pItem->GetSize( pView, pEntry ); +} + +Rectangle SvImpIconView::CalcFocusRect( SvLBoxEntry* pEntry ) +{ +#if !defined(OS2) + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT(pStringItem,"Text not set"); + return CalcTextRect( pEntry, pStringItem ); +#else + return CalcBmpRect( pEntry ); +#endif +} + + +void SvImpIconView::SelectRect( const Rectangle& rRect, BOOL bAdd, + SvPtrarr* pOtherRects, short nBorderOffs ) +{ + if( !pZOrderList || !pZOrderList->Count() ) + return; + + CheckBoundingRects(); + pView->Update(); + USHORT nCount = pZOrderList->Count(); + + Rectangle aRect( rRect ); + aRect.Justify(); + if( nBorderOffs ) + { + aRect.Left() -= nBorderOffs; + aRect.Right() += nBorderOffs; + aRect.Top() -= nBorderOffs; + aRect.Bottom() += nBorderOffs; + } + BOOL bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? TRUE : FALSE; + + for( USHORT nPos = 0; nPos < nCount; nPos++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); + + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model") + if( !IsBoundingRectValid( pViewData->aRect )) + FindBoundingRect( pEntry, pViewData ); + const Rectangle& rBoundRect = pViewData->aRect; + BOOL bSelected = pViewData->IsSelected(); + + BOOL bOverlaps; + if( bCalcOverlap ) + bOverlaps = IsOver( pOtherRects, rBoundRect ); + else + bOverlaps = FALSE; + BOOL bOver = aRect.IsOver( rBoundRect ); + + if( bOver && !bOverlaps ) + { + // Ist im neuen Selektionsrechteck und in keinem alten + // => selektieren + if( !bSelected ) + pView->Select( pEntry, TRUE ); + } + else if( !bAdd ) + { + // ist ausserhalb des Selektionsrechtecks + // => Selektion entfernen + if( bSelected ) + pView->Select( pEntry, FALSE ); + } + else if( bAdd && bOverlaps ) + { + // Der Eintrag befindet sich in einem alten (=>Aufspannen + // mehrerer Rechtecke mit Ctrl!) Selektionsrechteck + + // Hier ist noch ein Bug! Der Selektionsstatus eines Eintrags + // in einem vorherigen Rechteck, muss restauriert werden, wenn + // er vom aktuellen Selektionsrechteck beruehrt wurde, jetzt aber + // nicht mehr in ihm liegt. Ich gehe hier der Einfachheit halber + // pauschal davon aus, dass die Eintraege in den alten Rechtecken + // alle selektiert sind. Ebenso ist es falsch, die Schnittmenge + // nur zu deselektieren. + // Loesungsmoeglichkeit: Snapshot der Selektion vor dem Auf- + // spannen des Rechtecks merken + if( rBoundRect.IsOver( rRect)) + { + // Schnittmenge zwischen alten Rects & aktuellem Rect desel. + if( bSelected ) + pView->Select( pEntry, FALSE ); + } + else + { + // Eintrag eines alten Rects selektieren + if( !bSelected ) + pView->Select( pEntry, TRUE ); + } + } + else if( !bOver && bSelected ) + { + // Der Eintrag liegt voellig ausserhalb und wird deshalb desel. + pView->Select( pEntry, FALSE ); + } + } + pView->Update(); +} + +BOOL SvImpIconView::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const +{ + USHORT nCount = pRectList->Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur ); + if( rBoundRect.IsOver( *pRect )) + return TRUE; + } + return FALSE; +} + +void SvImpIconView::AddSelectedRect( const Rectangle& rRect, short nBorderOffs ) +{ + Rectangle* pRect = new Rectangle( rRect ); + pRect->Justify(); + if( nBorderOffs ) + { + pRect->Left() -= nBorderOffs; + pRect->Right() += nBorderOffs; + pRect->Top() -= nBorderOffs; + pRect->Bottom() += nBorderOffs; + } + aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() ); +} + +void SvImpIconView::ClearSelectedRectList() +{ + USHORT nCount = aSelectedRectList.Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur ); + delete pRect; + } + aSelectedRectList.Remove( 0, aSelectedRectList.Count() ); +} + + +void SvImpIconView::DrawSelectionRect( const Rectangle& rRect ) +{ + pView->HideTracking(); + nFlags |= F_SELRECT_VISIBLE; + pView->ShowTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); + aCurSelectionRect = rRect; +} + +void SvImpIconView::HideSelectionRect() +{ + if( nFlags & F_SELRECT_VISIBLE ) + { + pView->HideTracking(); + nFlags &= ~F_SELRECT_VISIBLE; + } +} + +void SvImpIconView::ImpDrawXORRect( const Rectangle& rRect ) +{ + RasterOp eOldOp = pView->GetRasterOp(); + pView->SetRasterOp( ROP_XOR ); + Color aOldColor = pView->GetFillColor(); + pView->SetFillColor(); + pView->DrawRect( rRect ); + pView->SetFillColor( aOldColor ); + pView->SetRasterOp( eOldOp ); +} + +void SvImpIconView::CalcScrollOffsets( const Point& rPosPixel, + long& rX, long& rY, BOOL bInDragDrop, USHORT nBorderWidth) +{ + // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des + // Fensters befindet + long nPixelToScrollX = 0; + long nPixelToScrollY = 0; + Size aWndSize = aOutputSize; + + nBorderWidth = (USHORT)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth )); + nBorderWidth = (USHORT)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth )); + + if ( rPosPixel.X() < nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollX = -DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X()- nBorderWidth; + } + else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollX = DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth); + } + if ( rPosPixel.Y() < nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollY = -DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - nBorderWidth; + } + else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollY = DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth); + } + + rX = nPixelToScrollX; + rY = nPixelToScrollY; +} + +IMPL_LINK(SvImpIconView, MouseMoveTimeoutHdl, Timer*, pTimer ) +{ + pTimer->Start(); + MouseMove( aMouseMoveEvent ); + return 0; +} + +void SvImpIconView::EndTracking() +{ + pView->ReleaseMouse(); + if( nFlags & F_RUBBERING ) + { + aMouseMoveTimer.Stop(); + nFlags &= ~(F_RUBBERING | F_ADD_MODE); + } +} + +BOOL SvImpIconView::IsTextHit( SvLBoxEntry* pEntry, const Point& rDocPos ) +{ + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pItem ) + { + Rectangle aRect( CalcTextRect( pEntry, pItem )); + if( aRect.IsInside( rDocPos ) ) + return TRUE; + } + return FALSE; +} + +IMPL_LINK(SvImpIconView, EditTimeoutHdl, Timer*, pTimer ) +{ + SvLBoxEntry* pEntry = GetCurEntry(); + if( pView->IsInplaceEditingEnabled() && pEntry && + pView->IsSelected( pEntry )) + { + pView->EditEntry( pEntry ); + } + return 0; +} + + +// +// Funktionen zum Ausrichten der Eintraege am Grid +// + +// pStart == 0: Alle Eintraege werden ausgerichtet +// sonst: Alle Eintraege der Zeile ab einschliesslich pStart werden ausgerichtet +void SvImpIconView::AdjustAtGrid( SvLBoxEntry* pStart ) +{ + SvPtrarr aLists; + pImpCursor->CreateGridAjustData( aLists, pStart ); + USHORT nCount = aLists.Count(); + for( USHORT nCur = 0; nCur < nCount; nCur++ ) + { + AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart ); + } + ImpIcnCursor::DestroyGridAdjustData( aLists ); + CheckScrollBars(); +} + +// Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um +void SvImpIconView::AdjustAtGrid( const SvPtrarr& rRow, SvLBoxEntry* pStart ) +{ + if( !rRow.Count() ) + return; + + BOOL bGo; + if( !pStart ) + bGo = TRUE; + else + bGo = FALSE; + + long nCurRight = 0; + for( USHORT nCur = 0; nCur < rRow.Count(); nCur++ ) + { + SvLBoxEntry* pCur = (SvLBoxEntry*)rRow[ nCur ]; + if( !bGo && pCur == pStart ) + bGo = TRUE; + + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); + // Massgebend (fuer das menschliche Auge) ist die Bitmap, da sonst + // durch lange Texte der Eintrag stark springen kann + const Rectangle& rBoundRect = GetBoundingRect( pCur, pViewData ); + Rectangle aCenterRect( CalcBmpRect( pCur, 0, pViewData )); + if( bGo && !pViewData->IsEntryPosLocked() ) + { + long nWidth = aCenterRect.GetSize().Width(); + Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) ); + while( aNewPos.X() < nCurRight ) + aNewPos.X() += nGridDX; + if( aNewPos != rBoundRect.TopLeft() ) + SetEntryPos( pCur, aNewPos ); + nCurRight = aNewPos.X() + nWidth; + } + else + { + nCurRight = rBoundRect.Right(); + } + } +} + +// Richtet Rect am Grid aus, garantiert jedoch nicht, dass die +// neue Pos. frei ist. Die Pos. kann fuer SetEntryPos verwendet werden. +// Das CenterRect beschreibt den Teil des BoundRects, der fuer +// die Berechnung des Ziel-Rechtecks verwendet wird. +Point SvImpIconView::AdjustAtGrid( const Rectangle& rCenterRect, + const Rectangle& rBoundRect ) const +{ + Point aPos( rCenterRect.TopLeft() ); + Size aSize( rCenterRect.GetSize() ); + + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + + // align (ref ist mitte des rects) + short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX); + short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY); + aPos.X() = nGridX * nGridDX; + aPos.Y() = nGridY * nGridDY; + // hor. center + aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2; + + aPos.X() += LROFFS_WINBORDER; + aPos.Y() += TBOFFS_WINBORDER; + + return aPos; +} + + +void SvImpIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + { + if( eTextMode != eMode ) + { + if( eTextMode == ShowTextDontKnow ) + eTextMode = ShowTextShort; + eTextMode = eMode; + pView->Arrange(); + } + } + else + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->eTextMode != eMode ) + { + pViewData->eTextMode = eMode; + pModel->InvalidateEntry( pEntry ); + AdjustVirtSize( pViewData->aRect ); + } + } +} + +SvIconViewTextMode SvImpIconView::GetTextMode( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + if( !pEntry ) + return eTextMode; + else + { + if( !pViewData ) + pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); + return pViewData->GetTextMode(); + } +} + +SvIconViewTextMode SvImpIconView::GetEntryTextModeSmart( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set"); + if( !pViewData ) + pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); + SvIconViewTextMode eMode = pViewData->GetTextMode(); + if( eMode == ShowTextDontKnow ) + return eTextMode; + return eMode; +} + +void SvImpIconView::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + pView->HideFocus(); + else + { + Rectangle aRect ( CalcFocusRect( (SvLBoxEntry*)pEntry ) ); + pView->ShowFocus( aRect ); + } +} + +IMPL_LINK(SvImpIconView, UserEventHdl, void*, EMPTYARG ) +{ + nCurUserEvent = 0; + AdjustScrollBars(); + Rectangle aRect; + if( GetResizeRect(aRect) ) + PaintResizeRect( aRect ); + return 0; +} + +void SvImpIconView::CancelUserEvent() +{ + if( nCurUserEvent ) + { + Application::RemoveUserEvent( nCurUserEvent ); + nCurUserEvent = 0; + } +} + + diff --git a/svtools/source/contnr/svlbitm.cxx b/svtools/source/contnr/svlbitm.cxx new file mode 100644 index 000000000000..fc6cd0c85cf8 --- /dev/null +++ b/svtools/source/contnr/svlbitm.cxx @@ -0,0 +1,449 @@ +/************************************************************************* + * + * $RCSfile: svlbitm.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + + +#include <svlbox.hxx> +#include <svlbitm.hxx> + +#pragma hdrstop + +#define TABOFFS_NOT_VALID -2000000 + +DBG_NAME(SvLBoxButtonData); + +SvLBoxButtonData::SvLBoxButtonData() +{ + DBG_CTOR(SvLBoxButtonData,0); + bDataOk = FALSE; + pEntry = 0; + eState = SV_BUTTON_UNCHECKED; +} + +SvLBoxButtonData::~SvLBoxButtonData() +{ + DBG_DTOR(SvLBoxButtonData,0); +} + + +void SvLBoxButtonData::CallLink() +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + aLink.Call( this ); +} + + +USHORT SvLBoxButtonData::GetIndex( USHORT nItemState ) +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + nItemState &= 0x000F; + USHORT nIdx; + switch( nItemState ) + { + case SV_ITEMSTATE_UNCHECKED: + nIdx = SV_BMP_UNCHECKED; break; + case SV_ITEMSTATE_CHECKED: + nIdx = SV_BMP_CHECKED; break; + case SV_ITEMSTATE_TRISTATE: + nIdx = SV_BMP_TRISTATE; break; + case SV_ITEMSTATE_UNCHECKED | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HIUNCHECKED; break; + case SV_ITEMSTATE_CHECKED | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HICHECKED; break; + case SV_ITEMSTATE_TRISTATE | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HITRISTATE; break; + default: + nIdx = SV_BMP_UNCHECKED; + } + return nIdx; +} + +void SvLBoxButtonData::SetWidthAndHeight() +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + Size aSize = aBmps[0].GetSizePixel(); + nWidth = aSize.Width(); + nHeight = aSize.Height(); + bDataOk = TRUE; +} + + +void SvLBoxButtonData::StoreButtonState( SvLBoxEntry* pActEntry, USHORT nItemFlags ) +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + pEntry = pActEntry; + eState = ConvertToButtonState( nItemFlags ); +} + +SvButtonState SvLBoxButtonData::ConvertToButtonState( USHORT nItemFlags ) const +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + nItemFlags &= (SV_ITEMSTATE_UNCHECKED | + SV_ITEMSTATE_CHECKED | + SV_ITEMSTATE_TRISTATE); + switch( nItemFlags ) + { + case SV_ITEMSTATE_UNCHECKED: + return SV_BUTTON_UNCHECKED; + + case SV_ITEMSTATE_CHECKED: + return SV_BUTTON_CHECKED; + + case SV_ITEMSTATE_TRISTATE: + return SV_BUTTON_TRISTATE; + default: + return SV_BUTTON_UNCHECKED; + } +} + + +// *************************************************************** +// class SvLBoxString +// *************************************************************** + +DBG_NAME(SvLBoxString); + +SvLBoxString::SvLBoxString( SvLBoxEntry* pEntry,USHORT nFlags,const XubString& rStr) : + SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxString,0); + SetText( pEntry, rStr ); +} + +SvLBoxString::SvLBoxString() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxString,0); +} + +SvLBoxString::~SvLBoxString() +{ + DBG_DTOR(SvLBoxString,0); +} + +USHORT SvLBoxString::IsA() +{ + DBG_CHKTHIS(SvLBoxString,0); + return SV_ITEM_ID_LBOXSTRING; +} + +void SvLBoxString::Paint( const Point& rPos, SvLBox& rDev, USHORT /* nFlags */, + SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBoxString,0); + rDev.DrawText( rPos, aStr ); +} + +SvLBoxItem* SvLBoxString::Create() const +{ + DBG_CHKTHIS(SvLBoxString,0); + return new SvLBoxString; +} + +void SvLBoxString::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxString,0); + aStr = ((SvLBoxString*)pSource)->aStr; +} + +void SvLBoxString::SetText( SvLBoxEntry*, const XubString& rStr ) +{ + DBG_CHKTHIS(SvLBoxString,0); + aStr = rStr; +} + +void SvLBoxString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxString,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = Size(pView->GetTextWidth( aStr ), pView->GetTextHeight()); +} + +// *************************************************************** +// class SvLBoxBmp +// *************************************************************** + +DBG_NAME(SvLBoxBmp); + +SvLBoxBmp::SvLBoxBmp( SvLBoxEntry* pEntry, USHORT nFlags, Image aBitmap ) : + SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxBmp,0); + SetBitmap( pEntry, aBitmap); +} + +SvLBoxBmp::SvLBoxBmp() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxBmp,0); +} + +SvLBoxBmp::~SvLBoxBmp() +{ + DBG_DTOR(SvLBoxBmp,0); +} + +USHORT SvLBoxBmp::IsA() +{ + DBG_CHKTHIS(SvLBoxBmp,0); + return SV_ITEM_ID_LBOXBMP; +} + +void SvLBoxBmp::SetBitmap( SvLBoxEntry*, Image aBitmap) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + aBmp = aBitmap; +} + +void SvLBoxBmp::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = aBmp.GetSizePixel(); +} + +void SvLBoxBmp::Paint( const Point& rPos, SvLBox& rDev, USHORT /* nFlags */, + SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + rDev.DrawImage( rPos, aBmp ); +} + +SvLBoxItem* SvLBoxBmp::Create() const +{ + DBG_CHKTHIS(SvLBoxBmp,0); + return new SvLBoxBmp; +} + +void SvLBoxBmp::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + aBmp = ((SvLBoxBmp*)pSource)->aBmp; +} + +// *************************************************************** +// class SvLBoxButton +// *************************************************************** + +DBG_NAME(SvLBoxButton); + +SvLBoxButton::SvLBoxButton( SvLBoxEntry* pEntry,USHORT nFlags,SvLBoxButtonData* pBData) + : SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxButton,0); + nBaseOffs = 0; + nItemFlags = 0; + SetStateUnchecked(); + pData = pBData; +} + +SvLBoxButton::SvLBoxButton() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxButton,0); + nItemFlags = 0; + SetStateUnchecked(); +} + +SvLBoxButton::~SvLBoxButton() +{ + DBG_DTOR(SvLBoxButton,0); +} + +USHORT SvLBoxButton::IsA() +{ + DBG_CHKTHIS(SvLBoxButton,0); + return SV_ITEM_ID_LBOXBUTTON; +} + +void SvLBoxButton::Check(SvLBox*, SvLBoxEntry*, BOOL bOn) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if ( bOn != IsStateChecked() ) + { + if ( bOn ) + SetStateChecked(); + else + SetStateUnchecked(); + } +} + +BOOL SvLBoxButton::ClickHdl( SvLBox*, SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if ( IsStateChecked() ) + SetStateUnchecked(); + else + SetStateChecked(); + pData->StoreButtonState( pEntry, nItemFlags ); + pData->CallLink(); + return FALSE; +} + +void SvLBoxButton::Paint( const Point& rPos, SvLBox& rDev, USHORT /* nFlags */, + SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + USHORT nIndex = pData->GetIndex( nItemFlags ); + rDev.DrawImage( rPos, pData->aBmps[nIndex + nBaseOffs] ); +} + +SvLBoxItem* SvLBoxButton::Create() const +{ + DBG_CHKTHIS(SvLBoxButton,0); + return new SvLBoxButton; +} + +void SvLBoxButton::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + pData = ((SvLBoxButton*)pSource)->pData; +} + +void SvLBoxButton::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = Size( pData->Width(), pData->Height() ); +} + + + +// *************************************************************** +// class SvLBoxContextBmp +// *************************************************************** + +DBG_NAME(SvLBoxContextBmp); + +SvLBoxContextBmp::SvLBoxContextBmp( SvLBoxEntry* pEntry, USHORT nItemFlags, + Image aBmp1, Image aBmp2, USHORT nEntryFlags ) + : SvLBoxItem( pEntry, nItemFlags ) +{ + DBG_CTOR(SvLBoxContextBmp,0); + nEntryFlagsBmp1 = nEntryFlags; + SetBitmap1( pEntry, aBmp1 ); + SetBitmap2( pEntry, aBmp2 ); +} + +SvLBoxContextBmp::SvLBoxContextBmp() +{ + DBG_CTOR(SvLBoxContextBmp,0); +} + +SvLBoxContextBmp::~SvLBoxContextBmp() +{ + DBG_DTOR(SvLBoxContextBmp,0); +} + +USHORT SvLBoxContextBmp::IsA() +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + return SV_ITEM_ID_LBOXCONTEXTBMP; +} + +void SvLBoxContextBmp::SetBitmap1( SvLBoxEntry*, Image aBmp ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + aBmp1 = aBmp; +} + +void SvLBoxContextBmp::SetBitmap2( SvLBoxEntry*, Image aBmp) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + aBmp2 = aBmp; +} + +void SvLBoxContextBmp::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = aBmp1.GetSizePixel(); +} + +void SvLBoxContextBmp::Paint( const Point& rPos, SvLBox& rDev, + USHORT nViewDataEntryFlags, SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + Image* pBmp = &aBmp1; + if( nViewDataEntryFlags & nEntryFlagsBmp1 ) + pBmp = &aBmp2; + rDev.DrawImage( rPos, *pBmp); +} + +SvLBoxItem* SvLBoxContextBmp::Create() const +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + return new SvLBoxContextBmp; +} + +void SvLBoxContextBmp::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + aBmp1 = ((SvLBoxContextBmp*)pSource)->aBmp1; + aBmp2 = ((SvLBoxContextBmp*)pSource)->aBmp2; + nEntryFlagsBmp1 = ((SvLBoxContextBmp*)pSource)->nEntryFlagsBmp1; +} + + diff --git a/svtools/source/contnr/svlbox.cxx b/svtools/source/contnr/svlbox.cxx new file mode 100644 index 000000000000..2d7b9b333e99 --- /dev/null +++ b/svtools/source/contnr/svlbox.cxx @@ -0,0 +1,1691 @@ +/************************************************************************* + * + * $RCSfile: svlbox.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +/* + Todo: + - Anker loeschen in SelectionEngine bei manuellem Selektieren + - SelectAll( FALSE ), nur die deselektierten Entries repainten +*/ + + +#include <string.h> +#ifndef _SVEDI_HXX +#include <svmedit.hxx> +#endif +#ifndef _SV_SVAPP_HXX +#include <vcl/svapp.hxx> +#endif +#ifndef _SV_ACCEL_HXX +#include <vcl/accel.hxx> +#endif +#ifndef _SV_DRAG_HXX +#include <vcl/drag.hxx> +#endif +#ifndef _SOT_FORMATS_HXX +#include <sot/formats.hxx> +#endif + +#pragma hdrstop + +#include <svlbox.hxx> +#include <svlbitm.hxx> + +// fuer Drag&Drop +static SvLBox* pDDSource = 0; +static SvLBox* pDDTarget = 0; + +DBG_NAME(SvInplaceEdit); +DBG_NAME(SvInplaceEdit2); + +#define SVLBOX_ACC_RETURN 1 +#define SVLBOX_ACC_ESCAPE 2 + +SvInplaceEdit::SvInplaceEdit( Window* pParent, const Point& rPos, + const Size& rSize, const XubString& rData, const Link& rNotifyEditEnd, + const Selection& rSelection) : +#ifndef OS2 + Edit( pParent, WB_LEFT ), +#else + Edit( pParent, WB_LEFT | WB_BORDER ), +#endif + aCallBackHdl( rNotifyEditEnd ), + bCanceled( FALSE ), + bAlreadyInCallBack( FALSE ) +{ + DBG_CTOR(SvInplaceEdit,0); + Font aFont( pParent->GetFont() ); + aFont.SetTransparent( FALSE ); + Color aColor( pParent->GetBackground().GetColor() ); + aFont.SetFillColor(aColor ); + SetFont( aFont ); + SetBackground( pParent->GetBackground() ); + SetPosPixel( rPos ); + SetSizePixel( rSize ); + SetText( rData ); + SetSelection( rSelection ); + SaveValue(); + + aAccReturn.InsertItem( SVLBOX_ACC_RETURN, KeyCode(KEY_RETURN) ); + aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, KeyCode(KEY_ESCAPE) ); + + aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit, ReturnHdl_Impl) ); + aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit, EscapeHdl_Impl) ); + GetpApp()->InsertAccel( &aAccReturn ); + GetpApp()->InsertAccel( &aAccEscape ); + + Show(); + GrabFocus(); +} + +__EXPORT SvInplaceEdit::~SvInplaceEdit() +{ + DBG_DTOR(SvInplaceEdit,0); + if( !bAlreadyInCallBack ) + { + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + } +} + + + +IMPL_LINK_INLINE_START( SvInplaceEdit, ReturnHdl_Impl, Accelerator *, pAccelerator ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + bCanceled = FALSE; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, ReturnHdl_Impl, Accelerator *, pAccelerator ) + +IMPL_LINK_INLINE_START( SvInplaceEdit, EscapeHdl_Impl, Accelerator *, pAccelerator ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + bCanceled = TRUE; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, EscapeHdl_Impl, Accelerator *, pAccelerator ) + + +void __EXPORT SvInplaceEdit::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + USHORT nCode = rKEvt.GetKeyCode().GetCode(); + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = TRUE; + CallCallBackHdl_Impl(); + break; + + case KEY_RETURN: + bCanceled = FALSE; + CallCallBackHdl_Impl(); + break; + + default: + Edit::KeyInput( rKEvt ); + } +} + +void SvInplaceEdit::StopEditing( BOOL bCancel ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +void __EXPORT SvInplaceEdit::LoseFocus() +{ + DBG_CHKTHIS(SvInplaceEdit,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = FALSE; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit,Timeout_Impl)); + aTimer.Start(); + } +} + +IMPL_LINK_INLINE_START( SvInplaceEdit, Timeout_Impl, Timer *, pTimer ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + CallCallBackHdl_Impl(); + return 0; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, Timeout_Impl, Timer *, pTimer ) + +void SvInplaceEdit::CallCallBackHdl_Impl() +{ + DBG_CHKTHIS(SvInplaceEdit,0); + aTimer.Stop(); + if ( !bAlreadyInCallBack ) + { + bAlreadyInCallBack = TRUE; + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + Hide(); + aCallBackHdl.Call( this ); + // bAlreadyInCallBack = FALSE; + } +} + + +// *************************************************************** + +class MyEdit_Impl : public Edit +{ + SvInplaceEdit2* pOwner; +public: + MyEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner ); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual void LoseFocus(); +}; + +class MyMultiEdit_Impl : public MultiLineEdit +{ + SvInplaceEdit2* pOwner; +public: + MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner ); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual void LoseFocus(); +}; + +MyEdit_Impl::MyEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner ) + : +#ifndef OS2 + Edit( pParent, WB_LEFT ), +#else + Edit( pParent, WB_LEFT | WB_BORDER ), +#endif + pOwner(_pOwner) +{ +} + +void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + if( !pOwner->KeyInput( rKEvt )) + Edit::KeyInput( rKEvt ); +} + +void MyEdit_Impl::LoseFocus() +{ + pOwner->LoseFocus(); +} + +MyMultiEdit_Impl::MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner ) + : MultiLineEdit( pParent, +#if !defined(VCL) +#if defined(WIN) || defined(WNT) + WB_CENTER +#else + WB_LEFT +#endif +#else + WB_CENTER +#endif + ), pOwner(_pOwner) +{ +} + +void MyMultiEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + if( !pOwner->KeyInput( rKEvt )) + MultiLineEdit::KeyInput( rKEvt ); +} + +void MyMultiEdit_Impl::LoseFocus() +{ + pOwner->LoseFocus(); +} + + +SvInplaceEdit2::SvInplaceEdit2( Window* pParent, const Point& rPos, + const Size& rSize, const XubString& rData, const Link& rNotifyEditEnd, + const Selection& rSelection, BOOL bMulti) : + aCallBackHdl( rNotifyEditEnd ), + bCanceled( FALSE ), + bAlreadyInCallBack( FALSE ), + bMultiLine( bMulti ) +{ + DBG_CTOR(SvInplaceEdit2,0); + if( bMulti ) + pEdit = new MyMultiEdit_Impl( pParent, this ); + else + pEdit = new MyEdit_Impl( pParent, this ); + + Font aFont( pParent->GetFont() ); + aFont.SetTransparent( FALSE ); + Color aColor( pParent->GetBackground().GetColor() ); + aFont.SetFillColor(aColor ); + pEdit->SetFont( aFont ); + pEdit->SetBackground( pParent->GetBackground() ); + pEdit->SetPosPixel( rPos ); + pEdit->SetSizePixel( rSize ); + pEdit->SetText( rData ); +#ifndef OS2 + pEdit->SetSelection( rSelection ); +#else + if( !bMulti ) + pEdit->SetSelection( rSelection ); +#endif + pEdit->SaveValue(); + + aAccReturn.InsertItem( SVLBOX_ACC_RETURN, KeyCode(KEY_RETURN) ); + aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, KeyCode(KEY_ESCAPE) ); + + aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) ); + aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) ); + GetpApp()->InsertAccel( &aAccReturn ); + GetpApp()->InsertAccel( &aAccEscape ); + + pEdit->Show(); + pEdit->GrabFocus(); +} + +SvInplaceEdit2::~SvInplaceEdit2() +{ + DBG_DTOR(SvInplaceEdit2,0); + if( !bAlreadyInCallBack ) + { + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + } + delete pEdit; +} + +XubString SvInplaceEdit2::GetSavedValue() const +{ + return pEdit->GetSavedValue(); +} + +void SvInplaceEdit2::Hide() +{ + pEdit->Hide(); +} + + +IMPL_LINK_INLINE_START( SvInplaceEdit2, ReturnHdl_Impl, Accelerator *, pAccelerator ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + bCanceled = FALSE; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, ReturnHdl_Impl, Accelerator *, pAccelerator ) + +IMPL_LINK_INLINE_START( SvInplaceEdit2, EscapeHdl_Impl, Accelerator *, pAccelerator ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + bCanceled = TRUE; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, EscapeHdl_Impl, Accelerator *, pAccelerator ) + + +BOOL SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + KeyCode aCode = rKEvt.GetKeyCode(); + USHORT nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = TRUE; + CallCallBackHdl_Impl(); + return TRUE; + + case KEY_RETURN: +// if( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() ) + { + bCanceled = FALSE; + CallCallBackHdl_Impl(); + return TRUE; + } + break; + } + return FALSE; +} + +void SvInplaceEdit2::StopEditing( BOOL bCancel ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +void SvInplaceEdit2::LoseFocus() +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + if ( !bAlreadyInCallBack +#ifdef VCL + && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) ) +#endif + ) + { + bCanceled = FALSE; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit2,Timeout_Impl)); + aTimer.Start(); + } +} + +IMPL_LINK_INLINE_START( SvInplaceEdit2, Timeout_Impl, Timer *, pTimer ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + CallCallBackHdl_Impl(); + return 0; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, Timeout_Impl, Timer *, pTimer ) + +void SvInplaceEdit2::CallCallBackHdl_Impl() +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + aTimer.Stop(); + if ( !bAlreadyInCallBack ) + { + bAlreadyInCallBack = TRUE; + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + pEdit->Hide(); + aCallBackHdl.Call( this ); + } +} + +XubString SvInplaceEdit2::GetText() const +{ + return pEdit->GetText(); +} + +// *************************************************************** +// class SvLBoxTab +// *************************************************************** + +DBG_NAME(SvLBoxTab); + +SvLBoxTab::SvLBoxTab() +{ + DBG_CTOR(SvLBoxTab,0); + nPos = 0; + pUserData = 0; + nFlags = 0; +} + +SvLBoxTab::SvLBoxTab( long nPosition, USHORT nTabFlags ) +{ + DBG_CTOR(SvLBoxTab,0); + nPos = nPosition; + pUserData = 0; + nFlags = nTabFlags; +} + +SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab ) +{ + DBG_CTOR(SvLBoxTab,0); + nPos = rTab.nPos; + pUserData = rTab.pUserData; + nFlags = rTab.nFlags; +} + +SvLBoxTab::~SvLBoxTab() +{ + DBG_DTOR(SvLBoxTab,0); +} + + +long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth ) +{ + DBG_CHKTHIS(SvLBoxTab,0); + long nOffset = 0; + if ( nFlags & SV_LBOXTAB_ADJUST_RIGHT ) + { + nOffset = nTabWidth - nItemWidth; + if( nOffset < 0 ) + nOffset = 0; + } + else if ( nFlags & SV_LBOXTAB_ADJUST_CENTER ) + { + if( nFlags & SV_LBOXTAB_FORCE ) + { + //richtige Implementierung der Zentrierung + nOffset = ( nTabWidth - nItemWidth ) / 2; + if( nOffset < 0 ) + nOffset = 0; + } + else + { + // historisch gewachsene falsche Berechnung des Tabs, auf die sich + // Abo-Tabbox, Extras/Optionen/Anpassen etc. verlassen + nItemWidth++; + nOffset = -( nItemWidth / 2 ); + } + } + return nOffset; +} + +/* +long SvLBoxTab::CalcOffset( const XubString& rStr, const OutputDevice& rOutDev ) +{ + DBG_CHKTHIS(SvLBoxTab,0); + long nWidth; + if ( nFlags & SV_LBOXTAB_ADJUST_NUMERIC ) + { + USHORT nPos = rStr.Search( '.' ); + if ( nPos == STRING_NOTFOUND ) + nPos = rStr.Search( ',' ); + if ( nPos == STRING_NOTFOUND ) + nPos = STRING_LEN; + + nWidth = rOutDev.GetTextSize( rStr, 0, nPos ).Width(); + nWidth *= -1; + } + else + { + nWidth = rOutDev.GetTextSize( rStr ).Width(); + nWidth = CalcOffset( nWidth ); + } + return nWidth; +} +*/ + +// *************************************************************** +// class SvLBoxItem +// *************************************************************** + +DBG_NAME(SvLBoxItem); + +SvLBoxItem::SvLBoxItem( SvLBoxEntry*, USHORT ) +{ + DBG_CTOR(SvLBoxItem,0); +} + +SvLBoxItem::SvLBoxItem() +{ + DBG_CTOR(SvLBoxItem,0); +} + +SvLBoxItem::~SvLBoxItem() +{ + DBG_DTOR(SvLBoxItem,0); +} + +const Size& SvLBoxItem::GetSize( SvLBox* pView,SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBoxItem,0); + SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this ); + return pViewData->aSize; +} + +const Size& SvLBoxItem::GetSize( SvLBoxEntry* pEntry, SvViewDataEntry* pViewData) +{ + DBG_CHKTHIS(SvLBoxItem,0); + USHORT nItemPos = pEntry->GetPos( this ); + SvViewDataItem* pItemData = pViewData->pItemData+nItemPos; + return pItemData->aSize; +} + +DBG_NAME(SvViewDataItem); + +SvViewDataItem::SvViewDataItem() +{ + DBG_CTOR(SvViewDataItem,0); +} + +SvViewDataItem::~SvViewDataItem() +{ + DBG_DTOR(SvViewDataItem,0); +} + + + +// *************************************************************** +// class SvLBoxEntry +// *************************************************************** + +DBG_NAME(SvLBoxEntry); + +SvLBoxEntry::SvLBoxEntry() : aItems() +{ + DBG_CTOR(SvLBoxEntry,0); + nEntryFlags = 0; + pUserData = 0; +} + +SvLBoxEntry::~SvLBoxEntry() +{ + DBG_DTOR(SvLBoxEntry,0); + DeleteItems_Impl(); +} + +void SvLBoxEntry::DeleteItems_Impl() +{ + DBG_CHKTHIS(SvLBoxEntry,0); + USHORT nCount = aItems.Count(); + while( nCount ) + { + nCount--; + SvLBoxItem* pItem = (SvLBoxItem*)aItems.GetObject( nCount ); + delete pItem; + } + aItems.Remove(0, aItems.Count() ); +} + + +void SvLBoxEntry::AddItem( SvLBoxItem* pItem ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + aItems.Insert( pItem, aItems.Count() ); +} + +void SvLBoxEntry::Clone( SvListEntry* pSource ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + SvListEntry::Clone( pSource ); + SvLBoxItem* pNewItem; + DeleteItems_Impl(); + USHORT nCount = ((SvLBoxEntry*)pSource)->ItemCount(); + USHORT nCurPos = 0; + while( nCurPos < nCount ) + { + SvLBoxItem* pItem = ((SvLBoxEntry*)pSource)->GetItem( nCurPos ); + pNewItem = pItem->Create(); + pNewItem->Clone( pItem ); + AddItem( pNewItem ); + nCurPos++; + } + pUserData = ((SvLBoxEntry*)pSource)->GetUserData(); + nEntryFlags = ((SvLBoxEntry*)pSource)->nEntryFlags; +} + +void SvLBoxEntry::EnableChildsOnDemand( BOOL bEnable ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + if ( bEnable ) + nEntryFlags |= SV_ENTRYFLAG_CHILDS_ON_DEMAND; + else + nEntryFlags &= (~SV_ENTRYFLAG_CHILDS_ON_DEMAND); +} + +void SvLBoxEntry::ReplaceItem( SvLBoxItem* pNewItem, USHORT nPos ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + DBG_ASSERT(pNewItem,"ReplaceItem:No Item") + SvLBoxItem* pOld = GetItem( nPos ); + if ( pOld ) + { + aItems.Remove( nPos ); + aItems.Insert( pNewItem, nPos ); + delete pOld; + } +} + +SvLBoxItem* SvLBoxEntry::GetFirstItem( USHORT nId ) +{ + USHORT nCount = aItems.Count(); + USHORT nCur = 0; + SvLBoxItem* pItem; + while( nCur < nCount ) + { + pItem = GetItem( nCur ); + if( pItem->IsA() == nId ) + return pItem; + nCur++; + } + return 0; +} + +// *************************************************************** +// class SvLBoxViewData +// *************************************************************** + +DBG_NAME(SvViewDataEntry); + +SvViewDataEntry::SvViewDataEntry() + : SvViewData() +{ + DBG_CTOR(SvViewDataEntry,0); + pItemData = 0; +} + +SvViewDataEntry::~SvViewDataEntry() +{ + DBG_DTOR(SvViewDataEntry,0); + __DELETE(nItmCnt) pItemData; +} + +// *************************************************************** +// class SvLBox +// *************************************************************** + +DBG_NAME(SvLBox); + + +__EXPORT SvLBox::SvLBox( Window* pParent, WinBits nWinStyle ) : + Control( pParent, nWinStyle | WB_CLIPCHILDREN ) +{ + DBG_CTOR(SvLBox,0); + nWindowStyle = nWinStyle; + nDragOptions = DRAG_ALL; + nImpFlags = 0; + pTargetEntry = 0; + nDragDropMode = 0; + pReserved = 0; + nReserved = 0; + SvLBoxTreeList* pTempModel = new SvLBoxTreeList; + pTempModel->SetRefCount( 0 ); + SetModel( pTempModel ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + pModel->InsertView( this ); + pHdlEntry = 0; + pEdCtrl = 0; + aMovePtr = Pointer( POINTER_MOVEDATA ); + aCopyPtr = Pointer( POINTER_COPYDATA ); + SetSelectionMode( SINGLE_SELECTION ); // pruefen ob TreeListBox gecallt wird + SetDragDropMode( SV_DRAGDROP_NONE ); +#ifdef MAC + Font aFont( "Geneva", Size( 0, 10 ) ); + SetFont( aFont ); +#endif +} + +__EXPORT SvLBox::SvLBox( Window* pParent, const ResId& rResId ) : + Control( pParent, rResId ) +{ + DBG_CTOR(SvLBox,0); + pTargetEntry = 0; + nImpFlags = 0; + nWindowStyle = 0; + pReserved = 0; + nReserved = 0; + nDragOptions = DRAG_ALL; + nDragDropMode = 0; + SvLBoxTreeList* pTempModel = new SvLBoxTreeList; + pTempModel->SetRefCount( 0 ); + SetModel( pTempModel ); + pModel->InsertView( this ); + pHdlEntry = 0; + pEdCtrl = 0; + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + aMovePtr = Pointer( POINTER_MOVEDATA ); + aCopyPtr = Pointer( POINTER_COPYDATA ); +#ifdef MAC + Font aFont( "Geneva", Size( 0, 10 ) ); + SetFont( aFont ); +#endif +} + + +__EXPORT SvLBox::~SvLBox() +{ + DBG_DTOR(SvLBox,0); + delete pEdCtrl; + pEdCtrl = 0; + pModel->RemoveView( this ); + if ( pModel->GetRefCount() == 0 ) + { + pModel->Clear(); + delete pModel; + } + if( nReserved ) + { + *((BOOL*)nReserved) = TRUE; + } +} + +void SvLBox::SetModel( SvLBoxTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvLBox,0); + // erledigt das ganz CleanUp + SvListView::SetModel( pNewModel ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + ModelHasInserted( pEntry ); + pEntry = Next( pEntry ); + } +} + +void SvLBox::DisconnectFromModel() +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxTreeList* pNewModel = new SvLBoxTreeList; + SvListView::SetModel( pNewModel ); +} + +void SvLBox::Clear() +{ + DBG_CHKTHIS(SvLBox,0); + pModel->Clear(); // Model ruft SvLBox::ModelHasCleared() auf +} + + +USHORT SvLBox::IsA() +{ + DBG_CHKTHIS(SvLBox,0); + return SVLISTBOX_ID_LBOX; +} + +IMPL_LINK_INLINE_START( SvLBox, CloneHdl_Impl, SvListEntry*, pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + return (long)(CloneEntry((SvLBoxEntry*)pEntry)); +} +IMPL_LINK_INLINE_END( SvLBox, CloneHdl_Impl, SvListEntry*, pEntry ) + +ULONG SvLBox::Insert( SvLBoxEntry* pEntry, SvLBoxEntry* pParent, ULONG nPos ) +{ + DBG_CHKTHIS(SvLBox,0); + ULONG nInsPos = pModel->Insert( pEntry, pParent, nPos ); + return nInsPos; +} + +ULONG SvLBox::Insert( SvLBoxEntry* pEntry,ULONG nRootPos ) +{ + DBG_CHKTHIS(SvLBox,0); + ULONG nInsPos = pModel->Insert( pEntry, nRootPos ); + return nInsPos; +} + +long SvLBox::ExpandingHdl() +{ + DBG_CHKTHIS(SvLBox,0); + return aExpandingHdl.IsSet() ? aExpandingHdl.Call( this ) : 1; +} + +void SvLBox::ExpandedHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aExpandedHdl.Call( this ); +} + +void SvLBox::SelectHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aSelectHdl.Call( this ); +} + +void SvLBox::DeselectHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aDeselectHdl.Call( this ); +} + +BOOL SvLBox::DoubleClickHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aDoubleClickHdl.Call( this ); + return TRUE; +} + +void __EXPORT SvLBox::BeginDrag( const Point& rPos ) +{ + DBG_CHKTHIS(SvLBox,0); + BOOL bDeleted = FALSE; + + ReleaseMouse(); + SvLBoxDDInfo aDDInfo; + SvLBoxEntry* pEntry = GetEntry( rPos ); // GetDropTarget( rPos ); + if ( !pEntry ) + { + EndDrag(); + return; + } + + DragServer::Clear(); + + DragDropMode nTemp = GetDragDropMode(); + nDragDropMode = NotifyBeginDrag(pEntry); + if( !nDragDropMode || GetSelectionCount() == 0 ) + { + nDragDropMode = nTemp; + EndDrag(); + return; + } + + ULONG nDDFormatId = SOT_FORMATSTR_ID_TREELISTBOX; + memset(&aDDInfo,0,sizeof(SvLBoxDDInfo)); + aDDInfo.pApp = GetpApp(); + aDDInfo.pSource = this; + aDDInfo.pDDStartEntry = pEntry; + // abgeleitete Views zum Zuge kommen lassen + WriteDragServerInfo( rPos, &aDDInfo ); + DragServer::CopyData( &aDDInfo, sizeof(SvLBoxDDInfo), nDDFormatId ); + pDDSource = this; + pDDTarget = 0; + DropAction eAction; + + BOOL bOldUpdateMode = Control::IsUpdateMode(); + Control::SetUpdateMode( TRUE ); + Update(); + Control::SetUpdateMode( bOldUpdateMode ); + + // Selektion & deren Childs im Model als DropTargets sperren + // Wichtig: Wenn im DropHandler die Selektion der + // SourceListBox veraendert wird, muessen vorher die Eintraege + // als DropTargets wieder freigeschaltet werden: + // (GetSourceListBox()->EnableSelectionAsDropTarget( TRUE, TRUE );) + EnableSelectionAsDropTarget( FALSE, TRUE /* with Childs */ ); + + Region aRegion( GetDragRegion() ); // fuer die Mac-Leute + nReserved = (ULONG)&bDeleted; + eAction = ExecuteDrag( aMovePtr, aCopyPtr, nDragOptions, &aRegion ); + nReserved = 0; + if( bDeleted ) + { + EndDrag(); + return; + } + + EnableSelectionAsDropTarget( TRUE, TRUE ); + + if( (eAction == DROP_MOVE) && + ( + (pDDTarget && ((ULONG)(pDDTarget->GetModel())!=(ULONG)(this->GetModel()))) || + !pDDTarget )) + { + RemoveSelection(); + } + + ImplShowTargetEmphasis( pTargetEntry, FALSE ); + EndDrag(); + nDragDropMode = nTemp; +} + + +void SvLBox::EndDrag() +{ + DBG_CHKTHIS(SvLBox,0); + pDDSource = 0; + pDDTarget = 0; + pTargetEntry = 0; +} + +BOOL SvLBox::CheckDragAndDropMode( SvLBox* pSource, DropAction eAction ) +{ + DBG_CHKTHIS(SvLBox,0); + if ( pSource == this ) + { + if ( !(nDragDropMode & (SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY) ) ) + return FALSE; // D&D innerhalb der Liste gesperrt + if ( eAction == DROP_MOVE ) + { + if ( !(nDragDropMode & SV_DRAGDROP_CTRL_MOVE) ) + return FALSE; // kein lokales Move + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_CTRL_COPY)) + return FALSE; // kein lokales Copy + } + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_DROP ) ) + return FALSE; // kein Drop + if ( eAction == DROP_MOVE ) + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_MOVE) ) + return FALSE; // kein globales Move + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_COPY)) + return FALSE; // kein globales Copy + } + } + return TRUE; +} + + +BOOL __EXPORT SvLBox::QueryDrop( DropEvent& rDEvt ) +{ + DBG_CHKTHIS(SvLBox,0); + + if ( rDEvt.IsLeaveWindow() || !CheckDragAndDropMode( pDDSource, rDEvt.GetAction() ) ) + { + ImplShowTargetEmphasis( pTargetEntry, FALSE ); + return FALSE; + } + + if ( !nDragDropMode ) + { + DBG_ERRORFILE( "SvLBox::QueryDrop(): no target" ); + return FALSE; + } + + BOOL bAllowDrop = TRUE; + + ULONG nDDFormatId = SOT_FORMATSTR_ID_TREELISTBOX; + if ( !DragServer::HasFormat( 0, nDDFormatId ) ) + { + DBG_ERRORFILE( "SvLBox::QueryDrop(): no format" ); + bAllowDrop = FALSE; + } + + SvLBoxEntry* pEntry = GetDropTarget( rDEvt.GetPosPixel() ); + + if ( bAllowDrop ) + { + DBG_ASSERT( pDDSource, "SvLBox::QueryDrop(): SourceBox == 0 (__EXPORT?)" ); + if ( pEntry && pDDSource->GetModel() == this->GetModel() + && rDEvt.GetAction()==DROP_MOVE + && ( pEntry->nEntryFlags & SV_ENTRYFLAG_DISABLE_DROP ) ) + { + bAllowDrop = FALSE; // nicht auf sich selbst moven + } + } + if ( bAllowDrop ) + bAllowDrop = NotifyQueryDrop( pEntry ); + + + // **** Emphasis zeichnen **** + + if ( bAllowDrop ) + { + if ( pEntry != pTargetEntry || !(nImpFlags & SVLBOX_TARGEMPH_VIS) ) + { + ImplShowTargetEmphasis( pTargetEntry, FALSE ); + pTargetEntry = pEntry; + ImplShowTargetEmphasis( pTargetEntry, TRUE ); + } + } + else + ImplShowTargetEmphasis( pTargetEntry, FALSE ); + + return bAllowDrop; +} + +BOOL __EXPORT SvLBox::Drop( const DropEvent& rDEvt ) +{ + DBG_CHKTHIS(SvLBox,0); + GetSourceView()->EnableSelectionAsDropTarget( TRUE, TRUE ); + + ImplShowTargetEmphasis( pTargetEntry, FALSE ); + pDDTarget = this; + ULONG nDDFormatId = SOT_FORMATSTR_ID_TREELISTBOX; + + SvLBoxDDInfo aDDInfo; + if( !DragServer::PasteData(0, &aDDInfo, sizeof(SvLBoxDDInfo),nDDFormatId )) + return FALSE; + ReadDragServerInfo( rDEvt.GetPosPixel(), &aDDInfo ); + + SvLBoxEntry* pTarget = pTargetEntry; // !!! kann 0 sein !!! + BOOL bDataAccepted; + if ( rDEvt.GetAction() == DROP_COPY ) + bDataAccepted = CopySelection( aDDInfo.pSource, pTarget ); + else + bDataAccepted = MoveSelection( aDDInfo.pSource, pTarget ); + return bDataAccepted; +} + +DragDropMode SvLBox::NotifyBeginDrag( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return (DragDropMode)0xffff; +} + +BOOL SvLBox::NotifyQueryDrop( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return TRUE; +} + +void SvLBox::NotifyRemoving( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +/* + NotifyMoving/Copying + ==================== + + Standard-Verhalten: + + 1. Target hat keine Childs + - Entry wird Sibling des Targets. Entry steht hinter dem + Target (->Fenster: Unter dem Target) + 2. Target ist ein aufgeklappter Parent + - Entry wird an den Anfang der Target-Childlist gehaengt + 3. Target ist ein zugeklappter Parent + - Entry wird an das Ende der Target-Childlist gehaengt +*/ + +BOOL SvLBox::NotifyMoving( + SvLBoxEntry* pTarget, // D&D-Drop-Position in this->GetModel() + SvLBoxEntry* pEntry, // Zu verschiebender Entry aus + // GetSourceListBox()->GetModel() + SvLBoxEntry*& rpNewParent, // Neuer Target-Parent + ULONG& rNewChildPos) // Position in Childlist des Target-Parents +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?") + if( !pTarget ) + { + rpNewParent = 0; + rNewChildPos = 0; + return TRUE; + } + if ( !pTarget->HasChilds() && !pTarget->HasChildsOnDemand() ) + { + // Fall 1 + rpNewParent = GetParent( pTarget ); + rNewChildPos = pModel->GetRelPos( pTarget ) + 1; + rNewChildPos += nCurEntrySelPos; + nCurEntrySelPos++; + } + else + { + // Faelle 2 & 3 + rpNewParent = pTarget; + if( IsExpanded(pTarget)) + rNewChildPos = 0; + else + rNewChildPos = LIST_APPEND; + } + return TRUE; +} + +BOOL SvLBox::NotifyCopying( + SvLBoxEntry* pTarget, // D&D-Drop-Position in this->GetModel() + SvLBoxEntry* pEntry, // Zu kopierender Entry aus + // GetSourceListBox()->GetModel() + SvLBoxEntry*& rpNewParent, // Neuer Target-Parent + ULONG& rNewChildPos) // Position in Childlist des Target-Parents +{ + DBG_CHKTHIS(SvLBox,0); + return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos); + /* + DBG_ASSERT(pEntry,"NotifyCopying:SourceEntry?") + if( !pTarget ) + { + rpNewParent = 0; + rNewChildPos = 0; + return TRUE; + } + if ( !pTarget->HasChilds() && !pTarget->HasChildsOnDemand() ) + { + // Fall 1 + rpNewParent = GetParent( pTarget ); + rNewChildPos = GetRelPos( pTarget ) + 1; + } + else + { + // Faelle 2 & 3 + rpNewParent = pTarget; + if( IsExpanded(pTarget)) + rNewChildPos = 0; + else + rNewChildPos = LIST_APPEND; + } + return TRUE; + */ +} + +SvLBoxEntry* __EXPORT SvLBox::CloneEntry( SvLBoxEntry* pSource ) +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pEntry = (SvLBoxEntry*)CreateEntry(); // new SvLBoxEntry; + pEntry->Clone( (SvListEntry*)pSource ); + return pEntry; +} + + +// Rueckgabe: Alle Entries wurden kopiert +BOOL SvLBox::CopySelection( SvLBox* pSource, SvLBoxEntry* pTarget ) +{ + DBG_CHKTHIS(SvLBox,0); + nCurEntrySelPos = 0; // Selektionszaehler fuer NotifyMoving/Copying + BOOL bSuccess = TRUE; + SvTreeEntryList aList; + BOOL bClone = (BOOL)( (ULONG)(pSource->GetModel()) != (ULONG)GetModel() ); + Link aCloneLink( pModel->GetCloneLink() ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + + // Selektion zwischenspeichern, um bei D&D-Austausch + // innerhalb der gleichen Listbox das Iterieren ueber + // die Selektion zu vereinfachen + SvLBoxEntry* pSourceEntry = pSource->FirstSelected(); + while ( pSourceEntry ) + { + // Childs werden automatisch mitkopiert + pSource->SelectChilds( pSourceEntry, FALSE ); + aList.Insert( pSourceEntry, LIST_APPEND ); + pSourceEntry = pSource->NextSelected( pSourceEntry ); + } + + pSourceEntry = (SvLBoxEntry*)aList.First(); + while ( pSourceEntry ) + { + SvLBoxEntry* pNewParent = 0; + ULONG nInsertionPos = LIST_APPEND; + BOOL bOk=NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos); + if ( bOk ) + { + if ( bClone ) + { + ULONG nCloneCount = 0; + pSourceEntry = (SvLBoxEntry*) + pModel->Clone( (SvListEntry*)pSourceEntry, nCloneCount ); + pModel->InsertTree( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + else + { + ULONG nListPos = pModel->Copy( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + pSourceEntry = GetEntry( pNewParent, nListPos ); + } + } + else + bSuccess = FALSE; + + if( bOk == (BOOL)2 ) // !!!HACK verschobenen Entry sichtbar machen? + MakeVisible( pSourceEntry ); + + pSourceEntry = (SvLBoxEntry*)aList.Next(); + } + pModel->SetCloneLink( aCloneLink ); + return bSuccess; +} + +// Rueckgabe: Alle Entries wurden verschoben +BOOL SvLBox::MoveSelection( SvLBox* pSource, SvLBoxEntry* pTarget ) +{ + DBG_CHKTHIS(SvLBox,0); + nCurEntrySelPos = 0; // Selektionszaehler fuer NotifyMoving/Copying + BOOL bSuccess = TRUE; + SvTreeEntryList aList; + BOOL bClone = (BOOL)( (ULONG)(pSource->GetModel()) != (ULONG)GetModel() ); + Link aCloneLink( pModel->GetCloneLink() ); + if ( bClone ) + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + + SvLBoxEntry* pSourceEntry = pSource->FirstSelected(); + while ( pSourceEntry ) + { + // Childs werden automatisch mitbewegt + pSource->SelectChilds( pSourceEntry, FALSE ); + aList.Insert( pSourceEntry, LIST_APPEND ); + pSourceEntry = pSource->NextSelected( pSourceEntry ); + } + + pSourceEntry = (SvLBoxEntry*)aList.First(); + while ( pSourceEntry ) + { + SvLBoxEntry* pNewParent = 0; + ULONG nInsertionPos = LIST_APPEND; + BOOL bOk= NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos); + if ( bOk ) + { + if ( bClone ) + { + ULONG nCloneCount = 0; + pSourceEntry = (SvLBoxEntry*) + pModel->Clone( (SvListEntry*)pSourceEntry, nCloneCount ); + pModel->InsertTree( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + else + pModel->Move( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + else + bSuccess = FALSE; + + if( bOk == (BOOL)2 ) // !!!HACK verschobenen Entry sichtbar machen? + MakeVisible( pSourceEntry ); + + pSourceEntry = (SvLBoxEntry*)aList.Next(); + } + pModel->SetCloneLink( aCloneLink ); + return bSuccess; +} + +void SvLBox::RemoveSelection() +{ + DBG_CHKTHIS(SvLBox,0); + SvTreeEntryList aList; + // Selektion zwischenspeichern, da die Impl bei + // dem ersten Remove alles deselektiert! + SvLBoxEntry* pEntry = FirstSelected(); + while ( pEntry ) + { + aList.Insert( pEntry ); + if ( pEntry->HasChilds() ) + // Remove loescht Childs automatisch + SelectChilds( pEntry, FALSE ); + pEntry = NextSelected( pEntry ); + } + pEntry = (SvLBoxEntry*)aList.First(); + while ( pEntry ) + { + pModel->Remove( pEntry ); + pEntry = (SvLBoxEntry*)aList.Next(); + } +} + + +SvLBox* __EXPORT SvLBox::GetSourceView() const + { return pDDSource; } + +SvLBox* __EXPORT SvLBox::GetTargetView() const + { return pDDTarget; } + +void SvLBox::RequestingChilds( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ERROR("Child-Request-Hdl not implemented!") +} + +void SvLBox::RecalcViewData() +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + USHORT nCount = pEntry->ItemCount(); + USHORT nCurPos = 0; + while ( nCurPos < nCount ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCurPos ); + pItem->InitViewData( this, pEntry ); + nCurPos++; + } + ViewDataInitialized( pEntry ); + pEntry = Next( pEntry ); + } +} + +void SvLBox::ViewDataInitialized( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + + +void SvLBox::ImplShowTargetEmphasis( SvLBoxEntry* pEntry, BOOL bShow) +{ + DBG_CHKTHIS(SvLBox,0); + if ( bShow && (nImpFlags & SVLBOX_TARGEMPH_VIS) ) + return; + if ( !bShow && !(nImpFlags & SVLBOX_TARGEMPH_VIS) ) + return; + ShowTargetEmphasis( pEntry, bShow ); + if( bShow ) + nImpFlags |= SVLBOX_TARGEMPH_VIS; + else + nImpFlags &= ~SVLBOX_TARGEMPH_VIS; +} + +void SvLBox::ShowTargetEmphasis( SvLBoxEntry*, BOOL /* bShow */ ) +{ + DBG_CHKTHIS(SvLBox,0); +} + + +BOOL SvLBox::Expand( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return TRUE; +} + +BOOL SvLBox::Collapse( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return TRUE; +} + +BOOL SvLBox::Select( SvLBoxEntry*, BOOL ) +{ + DBG_CHKTHIS(SvLBox,0); + return FALSE; +} + +ULONG SvLBox::SelectChilds( SvLBoxEntry* , BOOL ) +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +void SvLBox::SelectAll( BOOL /* bSelect */ , BOOL /* bPaint */ ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::SetSelectionMode( SelectionMode eSelectMode ) +{ + DBG_CHKTHIS(SvLBox,0); + eSelMode = eSelectMode; +} + +void SvLBox::SetDragDropMode( DragDropMode nDDMode ) +{ + DBG_CHKTHIS(SvLBox,0); + if( nDDMode && !nDragDropMode ) + EnableDrop(); + nDragDropMode = nDDMode; +} + +SvViewData* SvLBox::CreateViewData( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + SvViewDataEntry* pEntryData = new SvViewDataEntry; + return (SvViewData*)pEntryData; +} + +void SvLBox::InitViewData( SvViewData* pData, SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pInhEntry = (SvLBoxEntry*)pEntry; + SvViewDataEntry* pEntryData = (SvViewDataEntry*)pData; + + pEntryData->pItemData = new SvViewDataItem[ pInhEntry->ItemCount() ]; + SvViewDataItem* pItemData = pEntryData->pItemData; + pEntryData->nItmCnt = pInhEntry->ItemCount(); // Anzahl Items fuer delete + USHORT nCount = pInhEntry->ItemCount(); + USHORT nCurPos = 0; + while( nCurPos < nCount ) + { + SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos ); + pItem->InitViewData( this, pInhEntry, pItemData ); + pItemData++; + nCurPos++; + } +} + + + +void SvLBox::EnableSelectionAsDropTarget( BOOL bEnable, BOOL bWithChilds ) +{ + DBG_CHKTHIS(SvLBox,0); + USHORT nRefDepth; + SvLBoxEntry* pTemp; + + SvLBoxEntry* pSelEntry = FirstSelected(); + while( pSelEntry ) + { + if ( !bEnable ) + { + pSelEntry->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP; + if ( bWithChilds ) + { + nRefDepth = pModel->GetDepth( pSelEntry ); + pTemp = Next( pSelEntry ); + while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth ) + { + pTemp->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP; + pTemp = Next( pTemp ); + } + } + } + else + { + pSelEntry->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP); + if ( bWithChilds ) + { + nRefDepth = pModel->GetDepth( pSelEntry ); + pTemp = Next( pSelEntry ); + while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth ) + { + pTemp->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP); + pTemp = Next( pTemp ); + } + } + } + pSelEntry = NextSelected( pSelEntry ); + } +} + +SvLBoxEntry* SvLBox::GetDropTarget( const Point& ) +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +// ****************************************************************** +// InplaceEditing +// ****************************************************************** + +void SvLBox::EditText( const XubString& rStr, const Rectangle& rRect, + const Selection& rSel ) +{ + EditText( rStr, rRect, rSel, FALSE ); +} + +void SvLBox::EditText( const XubString& rStr, const Rectangle& rRect, + const Selection& rSel, BOOL bMulti ) +{ + DBG_CHKTHIS(SvLBox,0); + if( pEdCtrl ) + delete pEdCtrl; + nImpFlags |= SVLBOX_IN_EDT; + nImpFlags &= ~SVLBOX_EDTEND_CALLED; + HideFocus(); + pEdCtrl = new SvInplaceEdit2( + this, rRect.TopLeft(), rRect.GetSize(), rStr, + LINK( this, SvLBox, TextEditEndedHdl_Impl ), + rSel, bMulti ); +} + +IMPL_LINK( SvLBox, TextEditEndedHdl_Impl, SvInplaceEdit2 *, pSvInplaceEdit ) +{ + DBG_CHKTHIS(SvLBox,0); + if ( nImpFlags & SVLBOX_EDTEND_CALLED ) // Nesting verhindern + return 0; + nImpFlags |= SVLBOX_EDTEND_CALLED; + XubString aStr; + if ( !pEdCtrl->EditingCanceled() ) + aStr = pEdCtrl->GetText(); + else + aStr = pEdCtrl->GetSavedValue(); + EditedText( aStr ); + // Hide darf erst gerufen werden, nachdem der neue Text in den + // Entry gesetzt wurde, damit im GetFocus der ListBox nicht + // der Selecthandler mit dem alten EntryText gerufen wird. + pEdCtrl->Hide(); + // delete pEdCtrl; + // pEdCtrl = 0; + nImpFlags &= (~SVLBOX_IN_EDT); +// GrabFocus(); + return 0; +} + +void SvLBox::CancelTextEditing() +{ + DBG_CHKTHIS(SvLBox,0); + if ( pEdCtrl ) + pEdCtrl->StopEditing( TRUE ); + nImpFlags &= (~SVLBOX_IN_EDT); +} + +void SvLBox::EndEditing( BOOL bCancel ) +{ + DBG_CHKTHIS(SvLBox,0); + if( pEdCtrl ) + pEdCtrl->StopEditing( bCancel ); + nImpFlags &= (~SVLBOX_IN_EDT); +} + + +void SvLBox::EditedText( const XubString& ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::EditingRequest( SvLBoxEntry*, SvLBoxItem*,const Point& ) +{ + DBG_CHKTHIS(SvLBox,0); +} + + +SvLBoxEntry* SvLBox::CreateEntry() const +{ + DBG_CHKTHIS(SvLBox,0); + return new SvLBoxEntry; +} + +void SvLBox::MakeVisible( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +Region SvLBox::GetDragRegion() const +{ + DBG_CHKTHIS(SvLBox,0); + Region aRegion; + return aRegion; +} + +void SvLBox::Command( const CommandEvent& ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +SvLBoxEntry* SvLBox::GetEntry( const Point& rPos, BOOL ) const +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +void __EXPORT SvLBox::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + USHORT nCount = ((SvLBoxEntry*)pEntry)->ItemCount(); + for( USHORT nIdx = 0; nIdx < nCount; nIdx++ ) + { + SvLBoxItem* pItem = ((SvLBoxEntry*)pEntry)->GetItem( nIdx ); + pItem->InitViewData( this, (SvLBoxEntry*)pEntry, 0 ); + } +} + +void SvLBox::SetInUseEmphasis( SvLBoxEntry* pEntry, BOOL bInUse ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + if( bInUse ) + { + if( !pEntry->HasInUseEmphasis() ) + { + pEntry->nEntryFlags |= SV_ENTRYFLAG_IN_USE; + pModel->InvalidateEntry( pEntry ); + } + } + else + { + if( pEntry->HasInUseEmphasis() ) + { + pEntry->nEntryFlags &= (~SV_ENTRYFLAG_IN_USE); + pModel->InvalidateEntry( pEntry ); + } + } +} + +void SvLBox::SetCursorEmphasis( SvLBoxEntry* pEntry, BOOL bCursored ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + if( pViewData && (bCursored != pViewData->IsCursored()) ) + { + pViewData->SetCursored( bCursored ); + // paintet in allen Views + // pModel->InvalidateEntry( pEntry ); + // invalidiert nur in dieser View + ModelHasEntryInvalidated( pEntry ); + } +} + +BOOL SvLBox::HasCursorEmphasis( SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + DBG_ASSERT(pViewData,"Entry not in View"); + return pViewData->IsCursored(); +} + +void SvLBox::WriteDragServerInfo( const Point&, SvLBoxDDInfo* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::ReadDragServerInfo(const Point&, SvLBoxDDInfo* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +BOOL SvLBox::EditingCanceled() const +{ + if( pEdCtrl && pEdCtrl->EditingCanceled() ) + return TRUE; + return FALSE; +} + + diff --git a/svtools/source/contnr/svtabbx.cxx b/svtools/source/contnr/svtabbx.cxx new file mode 100644 index 000000000000..2ab576bc2d54 --- /dev/null +++ b/svtools/source/contnr/svtabbx.cxx @@ -0,0 +1,639 @@ +/************************************************************************* + * + * $RCSfile: svtabbx.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +/* + Todo + - Tokenparsing optimieren + - Optimierungsfehler Microsoft/Win3.1 Funktion suchen +*/ + +// !!!HACK +#ifdef _MSC_VER +#pragma optimize( "", off ) +#endif +#pragma hdrstop + +#include "svtabbx.hxx" +#include "headbar.hxx" + +#define MYTABMASK (SV_LBOXTAB_ADJUST_RIGHT | SV_LBOXTAB_ADJUST_LEFT |\ + SV_LBOXTAB_ADJUST_CENTER | SV_LBOXTAB_ADJUST_NUMERIC) + +// SvTreeListBox-Callback + +void SvTabListBox::SetTabs() +{ + SvTreeListBox::SetTabs(); + if( nTabCount ) + { + DBG_ASSERT(pTabList,"TabList ?"); + + // die TreeListBox hat jetzt ihre Tabulatoren in die Liste eingefuegt. + // jetzt plustern wir die Liste mit zusaetzlichen Tabulatoren auf, + // und passen den ganz rechten Tab der Treelistbox an. + + // den ganz rechten Tab nehmen + // HACK fuer den Explorer! Wenn der ViewParent != 0 ist, dann wird + // der erste Tab der TreeListBox von der TreelistBox berechnet! + // Dies wird fuer ButtonsOnRoot benoetigt, da der Explorer nicht + // weiss, welchen zusaetzlichen Offset er in diesem Modus auf + // den Tabulator addieren muss. Die TreeListBox weiss es! + /* + if( !pViewParent ) + { + SvLBoxTab* pFirstTab = (SvLBoxTab*)aTabs.GetObject( aTabs.Count()-1 ); + pFirstTab->SetPos( pTabList[0].GetPos() ); + pFirstTab->nFlags &= ~MYTABMASK; + pFirstTab->nFlags |= pTabList[0].nFlags; + } + */ + + // alle anderen Tabs an Liste haengen + for( USHORT nCurTab = 1; nCurTab < nTabCount; nCurTab++ ) + { + SvLBoxTab* pTab = pTabList+nCurTab; + AddTab( pTab->GetPos(), pTab->nFlags ); + } + } +} + +void SvTabListBox::InitEntry( SvLBoxEntry* pEntry, const XubString& rStr, + const Image& rColl, const Image& rExp ) +{ + SvTreeListBox::InitEntry( pEntry, rStr, rColl, rExp); + XubString aToken; + + const xub_Unicode* pCurToken = aCurEntry.GetBuffer(); + USHORT nCurTokenLen; + const xub_Unicode* pNextToken = GetToken( pCurToken, nCurTokenLen ); + USHORT nCount = nTabCount; nCount--; + for( USHORT nToken = 0; nToken < nCount; nToken++ ) + { + if( pCurToken && nCurTokenLen ) + // aToken.Assign( pCurToken, nCurTokenLen ); + aToken = XubString( pCurToken, nCurTokenLen ); + else + aToken.Erase(); + SvLBoxString* pStr = new SvLBoxString( pEntry, 0, aToken ); + pEntry->AddItem( pStr ); + pCurToken = pNextToken; + if( pCurToken ) + pNextToken = GetToken( pCurToken, nCurTokenLen ); + else + nCurTokenLen = 0; + } +} + + +SvTabListBox::SvTabListBox( Window* pParent, WinBits nBits ) + : SvTreeListBox( pParent, nBits ) +{ + pTabList = 0; + nTabCount = 0; + pViewParent = 0; + SetHighlightRange(); // ueber volle Breite selektieren +} + +SvTabListBox::SvTabListBox( Window* pParent, const ResId& rResId ) + : SvTreeListBox( pParent, rResId ) +{ + pTabList = 0; + nTabCount = 0; + pViewParent = 0; + SvTabListBox::Resize(); + SetHighlightRange(); +} + +SvTabListBox::~SvTabListBox() +{ + // array-delete + __DELETE(nTabCount) pTabList; +#ifdef DBG_UTIL + pTabList = 0; + nTabCount = 0; +#endif +} + +void SvTabListBox::SetTabs( long* pTabs, MapUnit eMapUnit ) +{ + DBG_ASSERT(pTabs,"SetTabs:NULL-Ptr"); + if( !pTabs ) + return; + + __DELETE(nTabCount) pTabList; + USHORT nCount = (USHORT)(*pTabs); + pTabList = new SvLBoxTab[ nCount ]; + nTabCount = nCount; + + MapMode aMMSource( eMapUnit ); + MapMode aMMDest( MAP_PIXEL ); + + pTabs++; + for( USHORT nIdx = 0; nIdx < nCount; nIdx++, pTabs++ ) + { + Size aSize( *pTabs, 0 ); + aSize = LogicToLogic( aSize, &aMMSource, &aMMDest ); + long nNewTab = aSize.Width(); + pTabList[nIdx].SetPos( nNewTab ); + pTabList[nIdx].nFlags=(SV_LBOXTAB_ADJUST_LEFT| SV_LBOXTAB_INV_ALWAYS); + } + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); +} + +void SvTabListBox::SetTab( USHORT nTab,long nValue,MapUnit eMapUnit ) +{ + DBG_ASSERT(nTab<nTabCount,"Invalid Tab-Pos"); + if( nTab < nTabCount ) + { + DBG_ASSERT(pTabList,"TabList?"); + MapMode aMMSource( eMapUnit ); + MapMode aMMDest( MAP_PIXEL ); + Size aSize( nValue, 0 ); + aSize = LogicToLogic( aSize, &aMMSource, &aMMDest ); + nValue = aSize.Width(); + pTabList[ nTab ].SetPos( nValue ); + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); + } +} + +#if SUPD < 375 + +SvLBoxEntry* SvTabListBox::InsertEntry(const XubString& rStr,SvLBoxEntry* pParent,ULONG nPos,USHORT nCol ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Cut( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + return SvTreeListBox::InsertEntry( aFirstStr, pParent, FALSE, nPos ); +} + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, + const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent,ULONG nPos,USHORT nCol ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Cut( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + + return SvTreeListBox::InsertEntry( + aFirstStr, + rExpandedEntryBmp, rCollapsedEntryBmp, + pParent, FALSE, nPos ); +} + + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, ULONG nPos, + USHORT nCol ) +{ + return InsertEntry( rStr,0,nPos, nCol ); +} + +SvLBoxEntry* SvTabListBox::InsertEntry(const XubString& rStr,SvLBoxEntry* pParent,ULONG nPos,USHORT nCol, + void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Cut( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + return SvTreeListBox::InsertEntry( aFirstStr, pParent, FALSE, nPos, pUser ); +} + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, + const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent,ULONG nPos,USHORT nCol, void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Cut( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + + return SvTreeListBox::InsertEntry( + aFirstStr, + rExpandedEntryBmp, rCollapsedEntryBmp, + pParent, FALSE, nPos, pUser ); +} + + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, ULONG nPos, + USHORT nCol, void* pUser ) +{ + return InsertEntry( rStr,0,nPos, nCol, pUser ); +} + +#else + +SvLBoxEntry* SvTabListBox::InsertEntry(const XubString& rStr,SvLBoxEntry* pParent,ULONG nPos,USHORT nCol, + void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Erase( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + return SvTreeListBox::InsertEntry( aFirstStr, pParent, FALSE, nPos, pUser ); +} + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, + const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent,ULONG nPos,USHORT nCol, void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + USHORT nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Erase( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + + return SvTreeListBox::InsertEntry( + aFirstStr, + rExpandedEntryBmp, rCollapsedEntryBmp, + pParent, FALSE, nPos, pUser ); +} + + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rStr, ULONG nPos, + USHORT nCol, void* pUser ) +{ + return InsertEntry( rStr,0,nPos, nCol, pUser ); +} + +#endif + +XubString SvTabListBox::GetEntryText( ULONG nPos, USHORT nCol ) const +{ + SvLBoxEntry* pEntry = SvTreeListBox::GetEntry( nPos ); + return GetEntryText( pEntry, nCol ); +} + +XubString SvTabListBox::GetEntryText( SvLBoxEntry* pEntry, USHORT nCol ) const +{ + DBG_ASSERT(pEntry,"GetEntryText:Invalid Entry"); + XubString aResult; + if( pEntry ) + { + USHORT nCount = pEntry->ItemCount(); + USHORT nCur = 0; + while( nCur < nCount ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCur ); + if( pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( nCol == 0xffff ) + { + if( aResult.Len() ) + aResult += '\t'; + aResult += ((SvLBoxString*)pStr)->GetText(); + } + else + { + if( nCol == 0 ) + return ((SvLBoxString*)pStr)->GetText(); + nCol--; + } + } + nCur++; + } + } + return aResult; +} + +void SvTabListBox::SetEntryText( const XubString& rStr, ULONG nPos, + USHORT nCol ) +{ + SvLBoxEntry* pEntry = SvTreeListBox::GetEntry( nPos ); + SetEntryText( rStr, pEntry, nCol ); +} + +void SvTabListBox::SetEntryText( const XubString& rStr, SvLBoxEntry* pEntry, + USHORT nCol ) +{ + DBG_ASSERT(pEntry,"SetEntryText:Invalid Entry"); + if( !pEntry ) + return; + + const xub_Unicode* pCurToken = rStr.GetBuffer(); + USHORT nCurTokenLen; + const xub_Unicode* pNextToken = GetToken( pCurToken, nCurTokenLen ); + + XubString aTemp; + USHORT nCount = pEntry->ItemCount(); + USHORT nCur = 0; + while( nCur < nCount ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCur ); + if( pStr && pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( nCol == 0xffff ) + { + if( pCurToken ) + aTemp = XubString( pCurToken, nCurTokenLen ); + else + aTemp.Erase(); // alle Spalten ohne Token loeschen + ((SvLBoxString*)pStr)->SetText( pEntry, aTemp ); + pCurToken = pNextToken; + pNextToken = GetToken( pCurToken, nCurTokenLen ); + } + else + { + if( !nCol ) + { + aTemp = XubString( pCurToken, nCurTokenLen ); + ((SvLBoxString*)pStr)->SetText( pEntry, aTemp ); + if( !pNextToken ) + break; + pCurToken = pNextToken; + pNextToken = GetToken( pCurToken, nCurTokenLen ); + } + else + nCol--; + } + } + nCur++; + } + GetModel()->InvalidateEntry( pEntry ); +} + + + +ULONG SvTabListBox::GetEntryPos( const XubString& rStr, USHORT nCol ) +{ + ULONG nPos = 0; + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + XubString aStr( GetEntryText( pEntry, nCol )); + if( aStr == rStr ) + return nPos; + pEntry = Next( pEntry ); + nPos++; + } + return 0xffffffff; +} + +void __EXPORT SvTabListBox::Resize() +{ + SvTreeListBox::Resize(); +} + +// static +const xub_Unicode* SvTabListBox::GetToken( const xub_Unicode* pPtr, USHORT& rLen ) +{ + if( !pPtr || *pPtr == 0 ) + { + rLen = 0; + return 0; + } + xub_Unicode c = *pPtr; + USHORT nLen = 0; + while( c != '\t' && c != 0 ) + { + pPtr++; + nLen++; + c = *pPtr; + } + if( c ) + pPtr++; // Tab ueberspringen + else + pPtr = 0; + rLen = nLen; + return pPtr; +} + + +void SvTabListBox::SetTabJustify( USHORT nTab, SvTabJustify eJustify) +{ + if( nTab >= nTabCount ) + return; + SvLBoxTab* pTab = &(pTabList[ nTab ]); + USHORT nFlags = pTab->nFlags; + nFlags &= (~MYTABMASK); + nFlags |= (USHORT)eJustify; + pTab->nFlags = nFlags; + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); +} + +SvTabJustify SvTabListBox::GetTabJustify( USHORT nTab ) const +{ + SvTabJustify eResult = AdjustLeft; + if( nTab >= nTabCount ) + return eResult; + SvLBoxTab* pTab = &(pTabList[ nTab ]); + USHORT nFlags = pTab->nFlags; + nFlags &= MYTABMASK; + eResult = (SvTabJustify)nFlags; + return eResult; +} + +long SvTabListBox::GetLogicTab( USHORT nTab ) +{ + if( SvTreeListBox::nTreeFlags & TREEFLAG_RECALCTABS ) + ((SvTabListBox*)this)->SetTabs(); + + DBG_ASSERT(nTab<nTabCount,"GetTabPos:Invalid Tab"); + return ((SvLBoxTab*)aTabs.GetObject( nTab ))->GetPos(); +} + +// class SvHeaderTabListBox ---------------------------------------------- + +SvHeaderTabListBox::SvHeaderTabListBox( Window* pParent, WinBits nWinStyle ) : + + SvTabListBox( pParent, nWinStyle ), + + mbFirstPaint( TRUE ) + +{ +} + +// ----------------------------------------------------------------------- + +SvHeaderTabListBox::~SvHeaderTabListBox() +{ +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::Paint( const Rectangle& rRect ) +{ + if ( mbFirstPaint ) + { + mbFirstPaint = FALSE; + RepaintScrollBars(); + } + SvTabListBox::Paint( rRect ); +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::InitHeaderBar( HeaderBar* pHeaderBar ) +{ + mpHeaderBar = pHeaderBar; + SetScrolledHdl( LINK( this, SvHeaderTabListBox, ScrollHdl_Impl ) ); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( SvHeaderTabListBox, ScrollHdl_Impl, SvTabListBox*, pList ) +{ + mpHeaderBar->SetOffset( -GetXOffset() ); + return 0; +} + + diff --git a/svtools/source/contnr/svtreebx.cxx b/svtools/source/contnr/svtreebx.cxx new file mode 100644 index 000000000000..bc7f6de0ab05 --- /dev/null +++ b/svtools/source/contnr/svtreebx.cxx @@ -0,0 +1,2355 @@ +/************************************************************************* + * + * $RCSfile: svtreebx.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _SVTREEBX_CXX + +#ifndef _SV_SVAPP_HXX //autogen wg. Application +#include <vcl/svapp.hxx> +#endif +#pragma hdrstop + +class TabBar; + +#include <svlbox.hxx> +#include <svlbitm.hxx> +#include <svtreebx.hxx> +#ifndef _SVIMPLBOX_HXX +#include <svimpbox.hxx> +#endif + +/* + Bugs/ToDo + + - Berechnung Rectangle beim Inplace-Editing (Bug bei manchen Fonts) + - SetSpaceBetweenEntries: Offset wird in SetEntryHeight nicht + beruecksichtigt +*/ + +#define TREEFLAG_FIXEDHEIGHT 0x0010 + + +DBG_NAME(SvTreeListBox); + +#define SV_LBOX_DEFAULT_INDENT_PIXEL 20 + +__EXPORT SvTreeListBox::SvTreeListBox( Window* pParent, WinBits nWinStyle ) + : SvLBox(pParent,nWinStyle ) +{ + DBG_CTOR(SvTreeListBox,0); + InitTreeView( nWinStyle ); +} + +__EXPORT SvTreeListBox::SvTreeListBox( Window* pParent , const ResId& rResId ) + : SvLBox( pParent,rResId ) +{ + DBG_CTOR(SvTreeListBox,0); + InitTreeView( 0 ); + Resize(); +} + +void SvTreeListBox::InitTreeView( WinBits nWinStyle ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pCheckButtonData = 0; + nEntryHeight = 0; + pEdCtrl = 0; + nFirstSelTab = 0; + nLastSelTab = 0; + nFocusWidth = -1; + + Link* pLink = new Link( LINK(this,SvTreeListBox, DefaultCompare) ); + pReserved = pLink; + + nTreeFlags = TREEFLAG_RECALCTABS; + nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL; + nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL; + pImp = new SvImpLBox( this, GetModel(), nWinStyle ); + + aContextBmpMode = SVLISTENTRYFLAG_EXPANDED; + nContextBmpWidthMax = 0; + SetFont( GetFont() ); + SetSpaceBetweenEntries( 0 ); + SetLineColor(); + InitSettings( TRUE, TRUE, TRUE ); + SetWindowBits( nWinStyle ); + SetTabs(); + InitAcc(); +} + + +__EXPORT SvTreeListBox::~SvTreeListBox() +{ + DBG_DTOR(SvTreeListBox,0); + if( IsInplaceEditingEnabled() ) + Application::RemoveAccel( &aInpEditAcc ); + delete pImp; + delete (Link*)pReserved; + ClearTabList(); +} + +void SvTreeListBox::SetModel( SvLBoxTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetModel( pNewModel ); + SvLBox::SetModel( pNewModel ); +} + +void SvTreeListBox::DisconnectFromModel() +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::DisconnectFromModel(); + pImp->SetModel( GetModel() ); +} + + +USHORT SvTreeListBox::IsA() +{ + DBG_CHKTHIS(SvTreeListBox,0); + return SV_LISTBOX_ID_TREEBOX; +} + +void SvTreeListBox::InitAcc() +{ + DBG_CHKTHIS(SvTreeListBox,0); +#ifdef OS2 + aInpEditAcc.InsertItem( 1, KeyCode(KEY_F9,KEY_SHIFT) ); +#else + aInpEditAcc.InsertItem( 1, KeyCode(KEY_RETURN,KEY_MOD2) ); +#endif + aInpEditAcc.SetActivateHdl( LINK( this, SvTreeListBox, InpEdActivateHdl) ); +} + +IMPL_LINK_INLINE_START( SvTreeListBox, InpEdActivateHdl, Accelerator *, pAccelerator ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + EditEntry(); + return 1; +} +IMPL_LINK_INLINE_END( SvTreeListBox, InpEdActivateHdl, Accelerator *, pAccelerator ) + + +void __EXPORT SvTreeListBox::Resize() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing( TRUE ); + SvLBox::Resize(); + pImp->Resize(); + nFocusWidth = -1; + pImp->ShowCursor( FALSE ); + pImp->ShowCursor( TRUE ); +} + +/* Faelle: + + A) Entries haben Bitmaps + 0. Keine Buttons + 1. Node-Buttons (optional auch an Root-Items) + 2. Node-Buttons (optional auch an Root-Items) + CheckButton + 3. CheckButton + B) Entries haben keine Bitmaps (->ueber WindowBits wg. D&D !!!!!!) + 0. Keine Buttons + 1. Node-Buttons (optional auch an Root-Items) + 2. Node-Buttons (optional auch an Root-Items) + CheckButton + 3. CheckButton +*/ + +#define NO_BUTTONS 0 +#define NODE_BUTTONS 1 +#define NODE_AND_CHECK_BUTTONS 2 +#define CHECK_BUTTONS 3 + +#define TABFLAGS_TEXT (SV_LBOXTAB_DYNAMIC | \ + SV_LBOXTAB_ADJUST_LEFT | \ + SV_LBOXTAB_EDITABLE | \ + SV_LBOXTAB_SHOW_SELECTION) + +#define TABFLAGS_CONTEXTBMP (SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER) + +#define TABFLAGS_CHECKBTN (SV_LBOXTAB_DYNAMIC | \ + SV_LBOXTAB_ADJUST_CENTER | \ + SV_LBOXTAB_PUSHABLE) + +#define TAB_STARTPOS 2 + +// bei Aenderungen GetTextOffset beruecksichtigen +void SvTreeListBox::SetTabs() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing( TRUE ); + nTreeFlags &= (~TREEFLAG_RECALCTABS); + nFocusWidth = -1; + BOOL bHasButtons = (nWindowStyle & WB_HASBUTTONS)!=0; + BOOL bHasButtonsAtRoot = (nWindowStyle & (WB_HASLINESATROOT | + WB_HASBUTTONSATROOT))!=0; + long nStartPos = TAB_STARTPOS; + long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width(); + + long nCheckWidth = 0; + if( nTreeFlags & TREEFLAG_CHKBTN ) + nCheckWidth = pCheckButtonData->aBmps[0].GetSizePixel().Width(); + long nCheckWidthDIV2 = nCheckWidth / 2; + + long nContextWidth = nContextBmpWidthMax; + long nContextWidthDIV2 = nContextWidth / 2; + + ClearTabList(); + + int nCase = NO_BUTTONS; + if( !(nTreeFlags & TREEFLAG_CHKBTN) ) + { + if( bHasButtons ) + nCase = NODE_BUTTONS; + } + else + { + if( bHasButtons ) + nCase = NODE_AND_CHECK_BUTTONS; + else + nCase = CHECK_BUTTONS; + } + + switch( nCase ) + { + case NO_BUTTONS : + nStartPos += nContextWidthDIV2; // wg. Zentrierung + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case NODE_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + (nNodeWidthPixel/2) ); + else + nStartPos += nContextWidthDIV2; + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case NODE_AND_CHECK_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + nNodeWidthPixel ); + else + nStartPos += nCheckWidthDIV2; + AddTab( nStartPos, TABFLAGS_CHECKBTN ); + nStartPos += nCheckWidthDIV2; // rechter Rand des CheckButtons + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case CHECK_BUTTONS : + nStartPos += nCheckWidthDIV2; + AddTab( nStartPos, TABFLAGS_CHECKBTN ); + nStartPos += nCheckWidthDIV2; // rechter Rand CheckButton + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + } + pImp->NotifyTabsChanged(); +} + +void SvTreeListBox::InitEntry( SvLBoxEntry* pEntry, + const XubString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxButton* pButton; + SvLBoxString* pString; + SvLBoxContextBmp* pContextBmp; + + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + pButton= new SvLBoxButton( pEntry,0,pCheckButtonData ); + pEntry->AddItem( pButton ); + } + + pContextBmp= new SvLBoxContextBmp( pEntry,0, aCollEntryBmp,aExpEntryBmp, + aContextBmpMode ); + pEntry->AddItem( pContextBmp ); + + pString = new SvLBoxString( pEntry, 0, aStr ); + pEntry->AddItem( pString ); +} + +XubString SvTreeListBox::GetEntryText(SvLBoxEntry* pEntry) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Entry?") + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT(pItem,"GetEntryText:Item not found") + return pItem->GetText(); +} + +const Image& SvTreeListBox::GetExpandedEntryBmp(SvLBoxEntry* pEntry) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Entry?") + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"GetContextBmp:Item not found") + return pItem->GetBitmap2(); +} + +const Image& SvTreeListBox::GetCollapsedEntryBmp(SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Entry?") + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"GetContextBmp:Item not found") + return pItem->GetBitmap1(); +} + +IMPL_LINK_INLINE_START( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pHdlEntry = pData->GetActEntry(); + CheckButtonHdl(); + return 0; +} +IMPL_LINK_INLINE_END( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData ) + +SvLBoxEntry* SvTreeListBox::InsertEntry( const XubString& aText,SvLBoxEntry* pParent, + BOOL bChildsOnDemand, ULONG nPos, void* pUser ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags |= TREEFLAG_MANINS; + + aCurInsertedExpBmp = aExpandedEntryBmp; + aCurInsertedColBmp = aCollapsedEntryBmp; + + SvLBoxEntry* pEntry = CreateEntry(); + pEntry->SetUserData( pUser ); + InitEntry( pEntry, aText, aCollapsedEntryBmp, aExpandedEntryBmp ); + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + if( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + + aPrevInsertedExpBmp = aExpandedEntryBmp; + aPrevInsertedColBmp = aCollapsedEntryBmp; + + nTreeFlags &= (~TREEFLAG_MANINS); + + return pEntry; +} + +SvLBoxEntry* SvTreeListBox::InsertEntry( const XubString& aText, + const Image& aExpEntryBmp, const Image& aCollEntryBmp, + SvLBoxEntry* pParent, BOOL bChildsOnDemand, ULONG nPos, void* pUser ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags |= TREEFLAG_MANINS; + + aCurInsertedExpBmp = aExpEntryBmp; + aCurInsertedColBmp = aCollEntryBmp; + + short nExpWidth = (short)aExpEntryBmp.GetSizePixel().Width(); + short nColWidth = (short)aCollEntryBmp.GetSizePixel().Width(); + short nMax = Max(nExpWidth, nColWidth); + if( nMax > nContextBmpWidthMax ) + { + nContextBmpWidthMax = nMax; + SetTabs(); + } + + SvLBoxEntry* pEntry = CreateEntry(); + pEntry->SetUserData( pUser ); + InitEntry( pEntry, aText, aCollEntryBmp, aExpEntryBmp ); + + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + if( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + + aPrevInsertedExpBmp = aExpEntryBmp; + aPrevInsertedColBmp = aCollEntryBmp; + + nTreeFlags &= (~TREEFLAG_MANINS); + + return pEntry; +} + +void SvTreeListBox::SetEntryText( SvLBoxEntry* pEntry, const XubString& aStr) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT(pItem,"SetText:Item not found") + pItem->SetText( pEntry, aStr ); + pItem->InitViewData( this, pEntry, 0 ); + GetModel()->InvalidateEntry( pEntry ); +} + +void SvTreeListBox::SetExpandedEntryBmp(SvLBoxEntry* pEntry, const Image& aBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"SetExpBmp:Item not found") + pItem->SetBitmap2( pEntry, aBmp ); + GetModel()->InvalidateEntry( pEntry ); + SetEntryHeight( pEntry ); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + } +} + +void SvTreeListBox::SetCollapsedEntryBmp(SvLBoxEntry* pEntry,const Image& aBmp ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"SetExpBmp:Item not found") + pItem->SetBitmap1( pEntry, aBmp ); + GetModel()->InvalidateEntry( pEntry ); + SetEntryHeight( pEntry ); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + } +} + +void SvTreeListBox::ImpEntryInserted( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + SvLBoxEntry* pParent = (SvLBoxEntry*)pModel->GetParent( pEntry ); + if( pParent ) + { + USHORT nFlags = pParent->GetFlags(); + nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP; + pParent->SetFlags( nFlags ); + } + + if(!((nTreeFlags & TREEFLAG_MANINS) && + (aPrevInsertedExpBmp == aCurInsertedExpBmp) && + (aPrevInsertedColBmp == aCurInsertedColBmp) )) + { + Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + nTreeFlags |= TREEFLAG_RECALCTABS; + } + aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + nTreeFlags |= TREEFLAG_RECALCTABS; + } + } + SetEntryHeight( (SvLBoxEntry*)pEntry ); +} + + + +void SvTreeListBox::SetCheckButtonState( SvLBoxEntry* pEntry, SvButtonState eState) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON)); + DBG_ASSERT(pItem,"SetCheckButton:Item not found") + switch( eState ) + { + case SV_BUTTON_CHECKED: + pItem->SetStateChecked(); + break; + + case SV_BUTTON_UNCHECKED: + pItem->SetStateUnchecked(); + break; + + case SV_BUTTON_TRISTATE: + pItem->SetStateTristate(); + break; + } + InvalidateEntry( pEntry ); + } +} + +SvButtonState SvTreeListBox::GetCheckButtonState( SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvButtonState eState = SV_BUTTON_UNCHECKED; + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON)); + DBG_ASSERT(pItem,"GetChButnState:Item not found") + USHORT nButtonFlags = pItem->GetButtonFlags(); + eState = pCheckButtonData->ConvertToButtonState( nButtonFlags ); + } + return eState; +} + + +void __EXPORT SvTreeListBox::CheckButtonHdl() +{ + DBG_CHKTHIS(SvTreeListBox,0); + aCheckButtonHdl.Call( this ); +} + +BOOL __EXPORT SvTreeListBox::QueryDrop( DropEvent& rDEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return SvLBox::QueryDrop( rDEvt ); // Basisklasse rufen +} + + + +// ********************************************************************* +// ********************************************************************* + +// +// TODO: Momentan werden die Daten so geklont, dass sie dem +// Standard-TreeView-Format entsprechen. Hier sollte eigentlich +// das Model als Referenz dienen. Dies fuehrt dazu, dass +// SvLBoxEntry::Clone _nicht_ gerufen wird, sondern nur dessen +// Basisklasse SvListEntry +// + +SvLBoxEntry* __EXPORT SvTreeListBox::CloneEntry( SvLBoxEntry* pSource ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + XubString aStr; + Image aCollEntryBmp; + Image aExpEntryBmp; + + SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + aStr = pStringItem->GetText(); + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aCollEntryBmp = pBmpItem->GetBitmap1(); + aExpEntryBmp = pBmpItem->GetBitmap2(); + } + SvLBoxEntry* pEntry = CreateEntry(); + InitEntry( pEntry, aStr, aCollEntryBmp, aExpEntryBmp ); + pEntry->SvListEntry::Clone( pSource ); + pEntry->EnableChildsOnDemand( pSource->HasChildsOnDemand() ); + pEntry->SetUserData( pSource->GetUserData() ); + return pEntry; +} + +// ********************************************************************* +// ********************************************************************* + + +void SvTreeListBox::ShowExpandBitmapOnCursor( BOOL bYes ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( bYes ) + aContextBmpMode = SVLISTENTRYFLAG_FOCUSED; + else + aContextBmpMode = SVLISTENTRYFLAG_EXPANDED; +} + +void SvTreeListBox::SetIndent( short nNewIndent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nIndent = nNewIndent; + SetTabs(); + if( IsUpdateMode() ) + Invalidate(); +} + +void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + aExpandedEntryBmp = aBmp; +} + +void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + aCollapsedEntryBmp = aBmp; +} + +void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0"); + if( !pData ) + nTreeFlags &= (~TREEFLAG_CHKBTN); + else + { + pCheckButtonData = pData; + nTreeFlags |= TREEFLAG_CHKBTN; + pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick)); + } + + SetTabs(); + if( IsUpdateMode() ) + Invalidate(); +} + +void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, + const Image& rExpandedNodeBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SetExpandedNodeBmp( rExpandedNodeBmp ); + SetCollapsedNodeBmp( rCollapsedNodeBmp ); + SetTabs(); +} + +BOOL SvTreeListBox::EditingEntry( SvLBoxEntry*, Selection& ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return TRUE; +} + +BOOL SvTreeListBox::EditedEntry( SvLBoxEntry* /*pEntry*/,const XubString& /*rNewText*/) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return TRUE; +} + +void SvTreeListBox::EnableInplaceEditing( BOOL bOn ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::EnableInplaceEditing( bOn ); + if( Control::HasFocus() ) + Application::InsertAccel( &aInpEditAcc ); +} + +void __EXPORT SvTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // unter OS/2 bekommen wir auch beim Editieren Key-Up/Down + if( IsEditingActive() ) + return; + + nImpFlags |= SVLBOX_IS_TRAVELSELECT; + USHORT nCode = rKEvt.GetKeyCode().GetCode(); + +#ifdef OVDEBUG + switch ( nCode ) + { + case KEY_F1: + { + SvLBoxEntry* pEntry = First(); + pEntry = NextVisible( pEntry ); + SetEntryText( pEntry, "SetEntryText" ); + Sound::Beep(); + } + break; + } +#endif + + if( IsInplaceEditingEnabled() && + nCode == KEY_RETURN && + rKEvt.GetKeyCode().IsMod2() ) + { + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + EditEntry( pEntry ); + nImpFlags &= ~SVLBOX_IS_TRAVELSELECT; + } + else + { + BOOL bKeyUsed = pImp->KeyInput( rKEvt ); + nImpFlags &= ~SVLBOX_IS_TRAVELSELECT; + if( !bKeyUsed ) + SvLBox::KeyInput( rKEvt ); + } +} + +void SvTreeListBox::RequestingChilds( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( !pParent->HasChilds() ) + InsertEntry( String::CreateFromAscii("<dummy>"), pParent, FALSE, LIST_APPEND ); +} + +void __EXPORT SvTreeListBox::GetFocus() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsInplaceEditingEnabled() ) + Application::InsertAccel( &aInpEditAcc ); + pImp->GetFocus(); + SvLBox::GetFocus(); +} + +void __EXPORT SvTreeListBox::LoseFocus() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsInplaceEditingEnabled() ) + Application::RemoveAccel( &aInpEditAcc ); + pImp->LoseFocus(); + SvLBox::LoseFocus(); +} + +void __EXPORT SvTreeListBox::ModelHasCleared() +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->pCursor = 0; //sonst Absturz beim Inplace-Editieren im GetFocus + delete pEdCtrl; + pEdCtrl = 0; + pImp->Clear(); + nFocusWidth = -1; + + nContextBmpWidthMax = 0; + SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() ); + SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() ); + + if( !(nTreeFlags & TREEFLAG_FIXEDHEIGHT )) + nEntryHeight = 0; + AdjustEntryHeight( GetFont() ); + AdjustEntryHeight( GetDefaultExpandedEntryBmp() ); + AdjustEntryHeight( GetDefaultCollapsedEntryBmp() ); + + SvLBox::ModelHasCleared(); +// if( IsUpdateMode() ) +// Invalidate(); +} + +void SvTreeListBox::ShowTargetEmphasis( SvLBoxEntry* pEntry, BOOL /* bShow */ ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->PaintDDCursor( pEntry ); +} + +void SvTreeListBox::ScrollOutputArea( short nDeltaEntries ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( !nDeltaEntries || !pImp->aVerSBar.IsVisible() ) + return; + + long nThumb = pImp->aVerSBar.GetThumbPos(); + long nMax = pImp->aVerSBar.GetRange().Max(); + + NotifyBeginScroll(); + if( nDeltaEntries < 0 ) + { + // das Fenster nach oben verschieben + nDeltaEntries *= -1; + long nVis = pImp->aVerSBar.GetVisibleSize(); + long nTemp = nThumb + nVis; + if( nDeltaEntries > (nMax - nTemp) ) + nDeltaEntries = (short)(nMax - nTemp); + pImp->PageDown( (USHORT)nDeltaEntries ); + } + else + { + if( nDeltaEntries > nThumb ) + nDeltaEntries = (short)nThumb; + pImp->PageUp( (USHORT)nDeltaEntries ); + } + pImp->SyncVerThumb(); + NotifyEndScroll(); +} + +void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::SetSelectionMode( eSelectMode ); + pImp->SetSelectionMode( eSelectMode ); +} + +void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::SetDragDropMode( nDDMode ); + pImp->SetDragDropMode( nDDMode ); +} + +short SvTreeListBox::GetHeightOffset(const Image& rBmp, Size& aSizeLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nOffset = 0; + aSizeLogic = rBmp.GetSizePixel(); + if( GetEntryHeight() > aSizeLogic.Height() ) + nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2; + return nOffset; +} + +short SvTreeListBox::GetHeightOffset(const Font& /* rFont */, Size& aSizeLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nOffset = 0; + aSizeLogic = Size(GetTextWidth('X'), GetTextHeight()); + if( GetEntryHeight() > aSizeLogic.Height() ) + nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2; + return nOffset; +} + +void SvTreeListBox::SetEntryHeight( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nHeight, nHeightMax=0; + USHORT nCount = pEntry->ItemCount(); + USHORT nCur = 0; + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + while( nCur < nCount ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCur ); + nHeight = (short)(pItem->GetSize( pViewData, nCur ).Height()); + if( nHeight > nHeightMax ) + nHeightMax = nHeight; + nCur++; + } + + if( nHeightMax > nEntryHeight ) + { + nEntryHeight = nHeightMax; + SvLBox::SetFont( GetFont() ); + pImp->SetEntryHeight( nHeightMax ); + } +} + +void SvTreeListBox::SetEntryHeight( short nHeight, BOOL bAlways ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + if( bAlways || nHeight > nEntryHeight ) + { + nEntryHeight = nHeight; + if( nEntryHeight ) + nTreeFlags |= TREEFLAG_FIXEDHEIGHT; + else + nTreeFlags &= ~TREEFLAG_FIXEDHEIGHT; + SvLBox::SetFont( GetFont() ); + pImp->SetEntryHeight( nHeight ); + } +} + + +void SvTreeListBox::AdjustEntryHeight( const Image& rBmp ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + GetHeightOffset( rBmp, aSize ); + if( aSize.Height() > nEntryHeight ) + { + nEntryHeight = (short)aSize.Height() + nEntryHeightOffs; + pImp->SetEntryHeight( nEntryHeight ); + } +} + +void SvTreeListBox::AdjustEntryHeight( const Font& rFont ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + GetHeightOffset( rFont, aSize ); + if( aSize.Height() > nEntryHeight ) + { + nEntryHeight = (short)aSize.Height() + nEntryHeightOffs; + pImp->SetEntryHeight( nEntryHeight ); + } +} + +BOOL SvTreeListBox::Expand( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pHdlEntry = pParent; + BOOL bExpanded = FALSE; + USHORT nFlags; + + if( pParent->HasChildsOnDemand() ) + RequestingChilds( pParent ); + if( pParent->HasChilds() ) + { + nImpFlags |= SVLBOX_IS_EXPANDING; + if( ExpandingHdl() ) + { + bExpanded = TRUE; + SvListView::Expand( pParent ); + pImp->EntryExpanded( pParent ); + ExpandedHdl(); + } + nFlags = pParent->GetFlags(); + nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP; + nFlags |= SV_ENTRYFLAG_HAD_CHILDREN; + pParent->SetFlags( nFlags ); + } + else + { + nFlags = pParent->GetFlags(); + nFlags |= SV_ENTRYFLAG_NO_NODEBMP; + pParent->SetFlags( nFlags ); + GetModel()->InvalidateEntry( pParent ); // neu zeichnen + } + return bExpanded; +} + +BOOL SvTreeListBox::Collapse( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nImpFlags &= ~SVLBOX_IS_EXPANDING; + pHdlEntry = pParent; + BOOL bCollapsed = FALSE; + + if( ExpandingHdl() ) + { + bCollapsed = TRUE; + pImp->CollapsingEntry( pParent ); + SvListView::Collapse( pParent ); + pImp->EntryCollapsed( pParent ); + ExpandedHdl(); + } + return bCollapsed; +} + +BOOL SvTreeListBox::Select( SvLBoxEntry* pEntry, BOOL bSelect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Select: Null-Ptr") + BOOL bRetVal = SvListView::Select( pEntry, bSelect ); + DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed"); + if( bRetVal ) + { + pImp->EntrySelected( pEntry, bSelect ); + pHdlEntry = pEntry; + if( bSelect ) + SelectHdl(); + else + DeselectHdl(); + } + return bRetVal; +} + +ULONG SvTreeListBox::SelectChilds( SvLBoxEntry* pParent, BOOL bSelect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->DestroyAnchor(); + ULONG nRet = 0; + if( !pParent->HasChilds() ) + return 0; + USHORT nRefDepth = pModel->GetDepth( pParent ); + SvLBoxEntry* pChild = FirstChild( pParent ); + do { + nRet++; + Select( pChild, bSelect ); + pChild = Next( pChild ); + } while( pChild && pModel->GetDepth( pChild ) > nRefDepth ); + return nRet; +} + +void SvTreeListBox::SelectAll( BOOL bSelect, BOOL bPaint ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SelAllDestrAnch( + bSelect, + TRUE, // Anker loeschen, + TRUE ); // auch bei SINGLE_SELECTION den Cursor deselektieren +} + +void __EXPORT SvTreeListBox::ModelHasInsertedTree( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + USHORT nRefDepth = pModel->GetDepth( (SvLBoxEntry*)pEntry ); + SvLBoxEntry* pTmp = (SvLBoxEntry*)pEntry; + do + { + ImpEntryInserted( pTmp ); + pTmp = Next( pTmp ); + } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) ); + pImp->TreeInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvTreeListBox::ModelHasInserted( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + ImpEntryInserted( (SvLBoxEntry*)pEntry ); + pImp->EntryInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvTreeListBox::ModelIsMoving(SvListEntry* pSource, + SvListEntry* /* pTargetParent */, + ULONG /* nChildPos */ ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MovingEntry( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvTreeListBox::ModelHasMoved( SvListEntry* pSource ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->EntryMoved( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvTreeListBox::ModelIsRemoving( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->RemovingEntry( (SvLBoxEntry*)pEntry ); + NotifyRemoving( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvTreeListBox::ModelHasRemoved( SvListEntry* /* pEntry */ ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->EntryRemoved(); +} + +void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + AdjustEntryHeight( rBmp ); + pImp->SetCollapsedNodeBmp( rBmp ); +} + +void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp) +{ + DBG_CHKTHIS(SvTreeListBox,0); + AdjustEntryHeight( rBmp ); + pImp->SetExpandedNodeBmp( rBmp ); +} + + +void SvTreeListBox::SetFont( const Font& rFont ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Font aTempFont( rFont ); + aTempFont.SetTransparent( TRUE ); +#ifndef VCL + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + aTempFont.SetColor( rStyleSettings.GetFieldTextColor() ); +#endif + Control::SetFont( aTempFont ); + AdjustEntryHeight( aTempFont ); + // immer Invalidieren, sonst fallen wir + // bei SetEntryHeight auf die Nase + RecalcViewData(); +} + + +void __EXPORT SvTreeListBox::Paint( const Rectangle& rRect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::Paint( rRect ); + if( nTreeFlags & TREEFLAG_RECALCTABS ) + SetTabs(); + pImp->Paint( rRect ); +} + +void __EXPORT SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseButtonDown( rMEvt ); +} + +void __EXPORT SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseButtonUp( rMEvt ); +} + +void __EXPORT SvTreeListBox::MouseMove( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseMove( rMEvt ); +} + + +void __EXPORT SvTreeListBox::SetUpdateMode( BOOL bUpdate ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetUpdateMode( bUpdate ); +} + +void SvTreeListBox::SetUpdateModeFast( BOOL bUpdate ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetUpdateModeFast( bUpdate ); +} + +void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nOffsLogic != nEntryHeightOffs ) + { + nEntryHeight -= nEntryHeightOffs; + nEntryHeightOffs = (short)nOffsLogic; + nEntryHeight += nOffsLogic; + AdjustEntryHeight( GetFont() ); + RecalcViewData(); + pImp->SetEntryHeight( nEntryHeight ); + } +} + +void SvTreeListBox::SetCursor( SvLBoxEntry* pEntry, BOOL bForceNoSelect ) +{ + pImp->SetCursor(pEntry, bForceNoSelect); +} + +void SvTreeListBox::SetCurEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( pEntry ) + pImp->SetCurEntry( pEntry ); +} + +Image SvTreeListBox::GetCollapsedNodeBmp() const +{ + return pImp->GetCollapsedNodeBmp(); +} + +Image SvTreeListBox::GetExpandedNodeBmp() const +{ + return pImp->GetExpandedNodeBmp(); +} + +Point SvTreeListBox::GetEntryPos( SvLBoxEntry* pEntry ) const +{ + return pImp->GetEntryPos( pEntry ); +} + +void SvTreeListBox::ShowEntry( SvLBoxEntry* pEntry ) +{ + MakeVisible( pEntry ); +} + +void SvTreeListBox::MakeVisible( SvLBoxEntry* pEntry ) +{ + pImp->MakeVisible(pEntry); +} + +void SvTreeListBox::MakeVisible( SvLBoxEntry* pEntry, BOOL bMoveToTop ) +{ + pImp->MakeVisible( pEntry, bMoveToTop ); +} + +void __EXPORT SvTreeListBox::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // die einzelnen Items des Entries reinitialisieren + SvLBox::ModelHasEntryInvalidated( pEntry ); + // repainten + pImp->InvalidateEntry( (SvLBoxEntry*)pEntry ); +} + +void SvTreeListBox::EditItemText( SvLBoxEntry* pEntry, SvLBoxString* pItem, + const Selection& rSelection ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params"); + if( IsSelected( pEntry )) + { + pImp->ShowCursor( FALSE ); + SvListView::Select( pEntry, FALSE ); + PaintEntry( pEntry ); + SvListView::Select( pEntry, TRUE ); + pImp->ShowCursor( TRUE ); + } + pEdEntry = pEntry; + pEdItem = pItem; + SvLBoxTab* pTab = GetTab( pEntry, pItem ); + DBG_ASSERT(pTab,"EditItemText:Tab not found"); + + Size aItemSize( pItem->GetSize(this, pEntry) ); + Point aPos = GetEntryPos( pEntry ); + aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2; + aPos.X() = GetTabPos( pEntry, pTab ); + long nOutputWidth = pImp->GetOutputSize().Width(); + Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() ); + USHORT nPos = aTabs.GetPos( pTab ); + if( nPos+1 < aTabs.Count() ) + { + SvLBoxTab* pRightTab = (SvLBoxTab*)aTabs.GetObject( nPos + 1 ); + long nRight = GetTabPos( pEntry, pRightTab ); + if( nRight <= nOutputWidth ) + aSize.Width() = nRight - aPos.X(); + } + Point aOrigin( GetMapMode().GetOrigin() ); + aPos += aOrigin; // in Win-Koord umrechnen + aSize.Width() -= aOrigin.X(); + Rectangle aRect( aPos, aSize ); +#ifdef OS2 + // Platz lassen fuer WB_BORDER + aRect.Left() -= 2; + aRect.Top() -= 3; + aRect.Bottom() += 3; +#endif + EditText( pItem->GetText(), aRect, rSelection ); +} + +void SvTreeListBox::CancelEditing() +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::CancelTextEditing(); +} + +void SvTreeListBox::EditEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing(); + if( !pEntry ) + pEntry = GetCurEntry(); + if( pEntry ) + { + SvLBoxString* pItem = (SvLBoxString* )pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING); + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( pItem && EditingEntry( pEntry, aSel ) ) + { + SelectAll( FALSE ); + MakeVisible( pEntry ); + EditItemText( pEntry, pItem, aSel ); + } + } +} + +void SvTreeListBox::EditedText( const XubString& rStr ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Point aPos = GetEntryPos( pEdEntry ); + if( EditedEntry( pEdEntry, rStr ) ) + { + ((SvLBoxString*)pEdItem)->SetText( pEdEntry, rStr ); + pModel->InvalidateEntry( pEdEntry ); + } + //if( GetSelectionMode() == SINGLE_SELECTION ) + //{ + if( GetSelectionCount() == 0 ) + Select( pEdEntry ); + if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() ) + SetCurEntry( pEdEntry ); + //} +} + +void SvTreeListBox::EditingRequest( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Point& ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing(); + if( pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( EditingEntry( pEntry, aSel ) ) + { + SelectAll( FALSE ); + EditItemText( pEntry, (SvLBoxString*)pItem, aSel ); + } + } +} + + + +SvLBoxEntry* SvTreeListBox::GetDropTarget( const Point& rPos ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // Scrollen + if( rPos.Y() < 12 ) + { + SvLBox::ImplShowTargetEmphasis( SvLBox::pTargetEntry, FALSE ); + ScrollOutputArea( +1 ); + } + else + { + Size aSize( pImp->GetOutputSize() ); + if( rPos.Y() > aSize.Height() - 12 ) + { + SvLBox::ImplShowTargetEmphasis( SvLBox::pTargetEntry, FALSE ); + ScrollOutputArea( -1 ); + } + } + + SvLBoxEntry* pTarget = pImp->GetEntry( rPos ); + // bei Droppen in leere Flaeche -> den letzten Eintrag nehmen + if( !pTarget ) + return (SvLBoxEntry*)LastVisible(); + else if( (GetDragDropMode() & SV_DRAGDROP_ENABLE_TOP) && + pTarget == First() && rPos.Y() < 6 ) + return 0; + + return pTarget; +} + + +SvLBoxEntry* SvTreeListBox::GetEntry( const Point& rPos, BOOL bHit ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxEntry* pEntry = pImp->GetEntry( rPos ); + if( pEntry && bHit ) + { + long nLine = pImp->GetEntryLine( pEntry ); + if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) ) + return 0; + } + return pEntry; +} + +SvLBoxEntry* SvTreeListBox::GetCurEntry() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + return pImp->GetCurEntry(); +} + +void SvTreeListBox::SetWindowBits( WinBits nWinStyle ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nWindowStyle = nWinStyle; + nTreeFlags |= TREEFLAG_RECALCTABS; + if( nWinStyle & WB_SORT ) + { + GetModel()->SetSortMode( SortAscending ); + GetModel()->SetCompareHdl( LINK(this,SvTreeListBox,DefaultCompare)); + } + else + { + GetModel()->SetSortMode( SortNone ); + GetModel()->SetCompareHdl( Link() ); + } +#ifdef OS2 + nWinStyle |= WB_VSCROLL; +#endif + pImp->SetWindowBits( nWinStyle ); + pImp->Resize(); + Invalidate(); +} + +void SvTreeListBox::PaintEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"PaintEntry:No Entry") + if( pEntry ) + pImp->PaintEntry( pEntry ); +} + +void SvTreeListBox::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"InvalidateEntry:No Entry") + if( pEntry ) + { + GetModel()->InvalidateEntry( pEntry ); + // pImp->InvalidateEntry( pEntry ); + } +} + + +long SvTreeListBox::PaintEntry(SvLBoxEntry* pEntry,long nLine,USHORT nTabFlags) +{ + return PaintEntry1(pEntry,nLine,nTabFlags); +} + +#define SV_TAB_BORDER 8 + +long SvTreeListBox::PaintEntry1(SvLBoxEntry* pEntry,long nLine,USHORT nTabFlags, + BOOL bHasClipRegion ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + Rectangle aRect; // multi purpose + + BOOL bHorSBar = pImp->HasHorScrollBar(); + PreparePaint( pEntry ); + + if( nTreeFlags & TREEFLAG_RECALCTABS ) + SetTabs(); + + short nTempEntryHeight = GetEntryHeight(); + long nWidth = pImp->GetOutputSize().Width(); + + // wurde innerhalb des PreparePaints die horizontale ScrollBar + // angeschaltet? Wenn ja, muss die ClipRegion neu gesetzt werden + if( !bHorSBar && pImp->HasHorScrollBar() ) + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + + Point aPos( GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + long nMaxRight = nWidth + aPos.X() - 1; + + Font aBackupFont( GetFont() ); + Color aBackupColor = GetFillColor(); + + int bCurFontIsSel = FALSE; + BOOL bInUse = pEntry->HasInUseEmphasis(); + // wenn eine ClipRegion von aussen gesetzt wird, dann + // diese nicht zuruecksetzen + BOOL bResetClipRegion = !bHasClipRegion; + BOOL bHideSelection = ((nWindowStyle & WB_HIDESELECTION) && !HasFocus())!=0; + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + Font aHiliteFont( GetFont() ); + aHiliteFont.SetColor( rSettings.GetHighlightTextColor() ); + + Size aRectSize( 0, nTempEntryHeight ); + + if( !bHasClipRegion && nWindowStyle & WB_HSCROLL ) + { + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + bHasClipRegion = TRUE; + } + + SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry ); + + USHORT nTabCount = aTabs.Count(); + USHORT nItemCount = pEntry->ItemCount(); + USHORT nCurTab = 0; + USHORT nCurItem = 0; + + while( nCurTab < nTabCount && nCurItem < nItemCount ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( nCurTab ); + USHORT nNextTab = nCurTab + 1; + SvLBoxTab* pNextTab = nNextTab < nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextTab) : 0; + SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0; + + USHORT nFlags = pTab->nFlags; + Size aSize( pItem->GetSize( pViewDataEntry, nCurItem )); + long nTabPos = GetTabPos( pEntry, pTab ); + + long nNextTabPos; + if( pNextTab ) + nNextTabPos = GetTabPos( pEntry, pNextTab ); + else + { + nNextTabPos = nMaxRight; + if( nTabPos > nMaxRight ) + nNextTabPos += 50; + } + + long nX; + if( pTab->nFlags & SV_LBOXTAB_ADJUST_RIGHT ) + //verhindern, das rechter Rand von der Tabtrennung abgeschnitten wird + nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos-SV_TAB_BORDER-1) -nTabPos); + else + nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos-nTabPos); + + if( nFlags & nTabFlags ) + { + if( !bHasClipRegion && nX + aSize.Width() >= nMaxRight ) + { + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + bHasClipRegion = TRUE; + } + aPos.X() = nX; + aPos.Y() = nLine; + + // Hintergrund-Muster & Farbe bestimmen + + Wallpaper aWallpaper = GetBackground(); + + int bSelTab = nFlags & SV_LBOXTAB_SHOW_SELECTION; + USHORT nItemType = pItem->IsA(); + + if( pViewDataEntry->IsSelected() && bSelTab && + !pViewDataEntry->IsCursored() ) + { + if( !bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP ) + { + if( bHideSelection ) + aWallpaper.SetColor( rSettings.GetDeactiveColor() ); + else + aWallpaper.SetColor( rSettings.GetHighlightColor() ); + // Font auf Hilite-Farbe setzen ? + if( !bCurFontIsSel && nItemType == SV_ITEM_ID_LBOXSTRING ) + { + Control::SetFont( aHiliteFont ); + bCurFontIsSel = TRUE; + } + } + else // ContextBitmap + InUse-Emphasis + Selektiert + aWallpaper.SetColor( rSettings.GetHighlightColor() ); + } + else // keine Selektion + { + if( bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP ) + aWallpaper.SetColor( rSettings.GetFieldColor() ); + else if( bCurFontIsSel && nItemType == SV_ITEM_ID_LBOXSTRING ) + { + bCurFontIsSel = FALSE; + Control::SetFont( aBackupFont ); + } + } + + // Hintergrund zeichnen + if( !(nTreeFlags & TREEFLAG_USESEL)) + { + // nur den Bereich zeichnen, den das Item einnimmt + aRectSize.Width() = aSize.Width(); + aRect.SetPos( aPos ); + aRect.SetSize( aRectSize ); + } + else + { + // vom aktuellen bis zum naechsten Tab zeichnen + if( nCurTab != 0 ) + aRect.Left() = nTabPos; + else + // beim nullten Tab immer ab Spalte 0 zeichnen + // (sonst Probleme bei Tabs mit Zentrierung) + aRect.Left() = 0; + aRect.Top() = nLine; + aRect.Bottom() = nLine + nTempEntryHeight - 1; + if( pNextTab ) + { + long nRight; + nRight = GetTabPos(pEntry,pNextTab)-1; + if( nRight > nMaxRight ) + nRight = nMaxRight; + aRect.Right() = nRight; + } + else + aRect.Right() = nMaxRight; + } + // bei anwenderdefinierter Selektion, die bei einer Tabposition + // groesser 0 beginnt den Hintergrund des 0.ten Items nicht + // fuellen, da sonst z.B. TablistBoxen mit Linien nicht + // realisiert werden koennen. + if( !(nCurTab==0 && (nTreeFlags & TREEFLAG_USESEL) && nFirstSelTab) ) + { + SetFillColor( aWallpaper.GetColor() ); + // Bei kleinen hor. Resizes tritt dieser Fall auf + if( aRect.Left() < aRect.Right() ) + DrawRect( aRect ); + } + // Item zeichnen + // vertikal zentrieren + aPos.Y() += ( nTempEntryHeight - aSize.Height() ) / 2; + pItem->Paint( aPos, *this, pViewDataEntry->GetFlags(), pEntry ); + + // Trennungslinie zwischen Tabs + if( pNextTab && pItem->IsA() == SV_ITEM_ID_LBOXSTRING && + // nicht am rechten Fensterrand! + aRect.Right() < nMaxRight ) + { + aRect.Left() = aRect.Right() - SV_TAB_BORDER; + DrawRect( aRect ); + } + + SetFillColor( aBackupColor ); + } + nCurItem++; + nCurTab++; + } + if( pViewDataEntry->IsCursored() && !HasFocus() ) + { + // Cursor-Emphasis + SetFillColor(); + Color aOldLineColor = GetLineColor(); + SetLineColor( Color( COL_BLACK ) ); + aRect = GetFocusRect( pEntry, nLine ); + aRect.Top()++; + aRect.Bottom()--; + DrawRect( aRect ); + SetLineColor( aOldLineColor ); + SetFillColor( aBackupColor ); + } + + if( bCurFontIsSel ) + Control::SetFont( aBackupFont ); + + USHORT nFirstDynTabPos; + SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab( nFirstDynTabPos ); + long nDynTabPos = GetTabPos( pEntry, pFirstDynamicTab ); + nDynTabPos += pImp->nNodeBmpTabDistance; + nDynTabPos += pImp->nNodeBmpWidth / 2; + nDynTabPos += 4; // 4 Pixel Reserve, damit die Node-Bitmap + // nicht zu nah am naechsten Tab steht + + if( (!(pEntry->GetFlags() & SV_ENTRYFLAG_NO_NODEBMP)) && + (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab && + ( pEntry->HasChilds() || pEntry->HasChildsOnDemand() ) ) + { + // ersten festen Tab suchen, und pruefen ob die Node-Bitmap + // in ihn hineinragt + USHORT nNextTab = nFirstDynTabPos; + SvLBoxTab* pNextTab; + do + { + nNextTab++; + pNextTab = nNextTab < nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextTab) : 0; + } while( pNextTab && pNextTab->IsDynamic() ); + + if( !pNextTab || (GetTabPos( pEntry, pNextTab ) > nDynTabPos) ) + { + if((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(pEntry) > 0) + { + Point aPos( GetTabPos(pEntry,pFirstDynamicTab), nLine ); + aPos.X() += pImp->nNodeBmpTabDistance; + const Image* pImg = 0; + if( IsExpanded(pEntry) ) + pImg = &pImp->GetExpandedNodeBmp(); + else + { + if( (!pEntry->HasChilds()) && pEntry->HasChildsOnDemand() && + (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) && + pImp->GetDontKnowNodeBmp().GetSizePixel().Width() ) + pImg = &pImp->GetDontKnowNodeBmp(); + else + pImg = &pImp->GetCollapsedNodeBmp(); + } + aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2; + DrawImage( aPos, *pImg ); + } + } + } + + + if( bHasClipRegion && bResetClipRegion ) + SetClipRegion(); + return 0; // nRowLen; +} + +void SvTreeListBox::PreparePaint( SvLBoxEntry* ) +{ +} + +Rectangle SvTreeListBox::GetFocusRect( SvLBoxEntry* pEntry, long nLine ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + Rectangle aRect; + aRect.Top() = nLine; + aSize.Height() = GetEntryHeight(); + + long nRealWidth = pImp->GetOutputSize().Width(); + nRealWidth -= GetMapMode().GetOrigin().X(); + + USHORT nCurTab; + SvLBoxTab* pTab = GetFirstTab( SV_LBOXTAB_SHOW_SELECTION, nCurTab ); + long nTabPos = 0; + if( pTab ) + nTabPos = GetTabPos( pEntry, pTab ); + long nNextTabPos; + if( pTab && nCurTab < aTabs.Count() - 1 ) + { + SvLBoxTab* pNextTab = (SvLBoxTab*)aTabs.GetObject( nCurTab + 1 ); + nNextTabPos = GetTabPos( pEntry, pNextTab ); + } + else + { + nNextTabPos = nRealWidth; + if( nTabPos > nRealWidth ) + nNextTabPos += 50; + } + + BOOL bUserSelection = (BOOL)( nTreeFlags & TREEFLAG_USESEL ) != 0; + if( !bUserSelection ) + { + if( pTab && nCurTab < pEntry->ItemCount() ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCurTab ); + aSize.Width() = pItem->GetSize( this, pEntry ).Width(); + if( !aSize.Width() ) + aSize.Width() = 15; + long nX = nTabPos; //GetTabPos( pEntry, pTab ); + // Ausrichtung + nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos ); + aRect.Left() = nX; + // damit erster & letzter Buchstabe nicht angeknabbert werden + aRect.SetSize( aSize ); + if( aRect.Left() > 0 ) + aRect.Left()--; + aRect.Right()++; + } + } + else + { + // wenn erster SelTab != 0, dann muessen wir auch rechnen + if( nFocusWidth == -1 || nFirstSelTab ) + { + USHORT nLastTab; + SvLBoxTab* pLastTab = GetLastTab(SV_LBOXTAB_SHOW_SELECTION,nLastTab); + nLastTab++; + if( nLastTab < aTabs.Count() ) // gibts noch einen ? + pLastTab = (SvLBoxTab*)aTabs.GetObject( nLastTab ); + else + pLastTab = 0; // ueber gesamte Breite selektieren + aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff; + nFocusWidth = (short)aSize.Width(); + if( pTab ) + nFocusWidth -= (short)nTabPos; //pTab->GetPos(); + } + else + { + aSize.Width() = nFocusWidth; + if( pTab ) + { + if( nCurTab ) + aSize.Width() += nTabPos; + else + aSize.Width() += pTab->GetPos(); // Tab0 immer ab ganz links + } + } + // wenn Sel. beim nullten Tab anfaengt, dann ab Spalte 0 sel. zeichnen + if( nCurTab != 0 ) + { + aRect.Left() = nTabPos; + aSize.Width() -= nTabPos; + } + aRect.SetSize( aSize ); + } + // rechten Rand anpassen wg. Clipping + if( aRect.Right() >= nRealWidth ) + { + aRect.Right() = nRealWidth-1; + nFocusWidth = (short)aRect.GetWidth(); + } + return aRect; +} + + +long SvTreeListBox::GetTabPos( SvLBoxEntry* pEntry, SvLBoxTab* pTab) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pTab,"No Tab") + long nPos = pTab->GetPos(); + if( pTab->IsDynamic() ) + { + USHORT nDepth = pModel->GetDepth( pEntry ); + nDepth *= (USHORT)nIndent; + nPos += (long)nDepth; + } + return nPos; +} + +SvLBoxItem* SvTreeListBox::GetItem_Impl( SvLBoxEntry* pEntry, long nX, + SvLBoxTab** ppTab, USHORT nEmptyWidth ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxItem* pItemClicked = 0; + USHORT nTabCount = aTabs.Count(); + USHORT nItemCount = pEntry->ItemCount(); + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(0); + SvLBoxItem* pItem = pEntry->GetItem(0); + USHORT nNextItem = 1; + nX -= GetMapMode().GetOrigin().X(); + long nRealWidth = pImp->GetOutputSize().Width(); + nRealWidth -= GetMapMode().GetOrigin().X(); + + while( 1 ) + { + SvLBoxTab* pNextTab=nNextItem<nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextItem) : 0; + long nStart = GetTabPos( pEntry, pTab ); + + long nNextTabPos; + if( pNextTab ) + nNextTabPos = GetTabPos( pEntry, pNextTab ); + else + { + nNextTabPos = nRealWidth; + if( nStart > nRealWidth ) + nNextTabPos += 50; + } + + Size aItemSize( pItem->GetSize(this, pEntry)); + nStart += pTab->CalcOffset( aItemSize.Width(), nNextTabPos - nStart ); + long nLen = aItemSize.Width(); + if( pNextTab ) + { + long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart; + if( nTabWidth < nLen ) + nLen = nTabWidth; + } + + if( !nLen ) + nLen = nEmptyWidth; + + if( nX >= nStart && nX < (nStart+nLen ) ) + { + pItemClicked = pItem; + if( ppTab ) + { + *ppTab = pTab; + break; + } + } + if( nNextItem >= nItemCount || nNextItem >= nTabCount) + break; + pTab = (SvLBoxTab*)aTabs.GetObject( nNextItem ); + pItem = pEntry->GetItem( nNextItem ); + nNextItem++; + } + return pItemClicked; +} + +SvLBoxItem* SvTreeListBox::GetItem(SvLBoxEntry* pEntry,long nX,SvLBoxTab** ppTab) +{ + return GetItem_Impl( pEntry, nX, ppTab, 0 ); +} + +SvLBoxItem* SvTreeListBox::GetItem(SvLBoxEntry* pEntry,long nX ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxTab* pDummyTab; + return GetItem_Impl( pEntry, nX, &pDummyTab, 0 ); +} + +SvLBoxItem* SvTreeListBox::GetFirstDynamicItem( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(0); + SvLBoxItem* pItem = pEntry->GetItem(0); + USHORT nTabCount = aTabs.Count(); + + USHORT nNext = 1; + while ( !pTab->IsDynamic() && nNext < nTabCount ) + { + pItem = pEntry->GetItem( nNext ); + pTab = (SvLBoxTab*)aTabs.GetObject( nNext ); + nNext++; + } + return pItem; +} + +void SvTreeListBox::AddTab(long nPos,USHORT nFlags,void* pUserData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nFocusWidth = -1; + SvLBoxTab* pTab = new SvLBoxTab( nPos, nFlags ); + pTab->SetUserData( pUserData ); + aTabs.Insert( pTab, aTabs.Count() ); + if( nTreeFlags & TREEFLAG_USESEL ) + { + USHORT nPos = aTabs.Count() - 1; + if( nPos >= nFirstSelTab && nPos <= nLastSelTab ) + pTab->nFlags |= SV_LBOXTAB_SHOW_SELECTION; + else + // String-Items werden normalerweise immer selektiert + // deshalb explizit ausschalten + pTab->nFlags &= ~SV_LBOXTAB_SHOW_SELECTION; + } +} + + + +SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( USHORT& rPos ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + USHORT nCurTab = 0; + USHORT nTabCount = aTabs.Count(); + while( nCurTab < nTabCount ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(nCurTab); + if( pTab->nFlags & SV_LBOXTAB_DYNAMIC ) + { + rPos = nCurTab; + return pTab; + } + nCurTab++; + } + return 0; +} + +SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const +{ + USHORT nDummy; + return GetFirstDynamicTab( nDummy ); +} + +SvLBoxTab* SvTreeListBox::GetTab( SvLBoxEntry* pEntry, SvLBoxItem* pItem) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + USHORT nPos = pEntry->GetPos( pItem ); + return (SvLBoxTab*)aTabs.GetObject( nPos ); +} + +void SvTreeListBox::ClearTabList() +{ + DBG_CHKTHIS(SvTreeListBox,0); + USHORT nTabCount = aTabs.Count(); + while( nTabCount ) + { + nTabCount--; + SvLBoxTab* pDelTab = (SvLBoxTab*)aTabs.GetObject( nTabCount ); + delete pDelTab; + } + aTabs.Remove(0,aTabs.Count()); +} + + +Size SvTreeListBox::GetOutputSizePixel() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = pImp->GetOutputSize(); + return aSize; +} + +void SvTreeListBox::NotifyBeginScroll() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyEndScroll() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyScrolling( long nCount ) +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyScrolled() +{ + DBG_CHKTHIS(SvTreeListBox,0); + aScrolledHdl.Call( this ); +} + +void SvTreeListBox::NotifyInvalidating() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::Invalidate() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nFocusWidth == -1 ) + // damit Control nicht nach dem Paint ein falsches FocusRect anzeigt + pImp->RecalcFocusRect(); + NotifyInvalidating(); + SvLBox::Invalidate(); + pImp->Invalidate(); +} + +void SvTreeListBox::Invalidate( const Rectangle& rRect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nFocusWidth == -1 ) + // damit Control nicht nach dem Paint ein falsches FocusRect anzeigt + pImp->RecalcFocusRect(); + NotifyInvalidating(); + SvLBox::Invalidate( rRect ); +} + + +void SvTreeListBox::SetHighlightRange( USHORT nStart, USHORT nEnd) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + USHORT nTemp; + nTreeFlags |= TREEFLAG_USESEL; + if( nStart > nEnd ) + { + nTemp = nStart; + nStart = nEnd; + nEnd = nTemp; + } + // alle Tabs markieren, die im Bereich liegen + nTreeFlags |= TREEFLAG_RECALCTABS; + nFirstSelTab = nStart; + nLastSelTab = nEnd; + pImp->RecalcFocusRect(); +} + +void SvTreeListBox::RemoveHighlightRange() +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags &= (~TREEFLAG_USESEL); + if( IsUpdateMode() ) + Invalidate(); +} + +ULONG SvTreeListBox::GetAscInsertionPos(SvLBoxEntry* pEntry,SvLBoxEntry* pParent) +{ + return LIST_APPEND; +} + +ULONG SvTreeListBox::GetDescInsertionPos(SvLBoxEntry* pEntry,SvLBoxEntry* pParent) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return LIST_APPEND; +} + +Region SvTreeListBox::GetDragRegion() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + Rectangle aRect; + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + { + Point aPos = GetEntryPos( pEntry ); + aRect = ((SvTreeListBox*)this)->GetFocusRect( pEntry, aPos.Y() ); + } + Region aRegion( aRect ); + return aRegion; +} + + +void SvTreeListBox::Command( const CommandEvent& rCEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->Command( rCEvt ); +} + + +void SvTreeListBox::RemoveParentKeepChilds( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pParent,"RemoveParentKeepChilds:No Parent"); + SvLBoxEntry* pNewParent = GetParent( pParent ); + if( pParent->HasChilds()) + { + SvLBoxEntry* pChild = FirstChild( pParent ); + while( pChild ) + { + pModel->Move( pChild, pNewParent, LIST_APPEND ); + pChild = FirstChild( pParent ); + } + } + pModel->Remove( pParent ); +} + +SvLBoxTab* SvTreeListBox::GetFirstTab( USHORT nFlagMask, USHORT& rPos ) +{ + USHORT nTabCount = aTabs.Count(); + for( USHORT nPos = 0; nPos < nTabCount; nPos++ ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( nPos ); + if( (pTab->nFlags & nFlagMask) ) + { + rPos = nPos; + return pTab; + } + } + rPos = 0xffff; + return 0; +} + +SvLBoxTab* SvTreeListBox::GetLastTab( USHORT nFlagMask, USHORT& rTabPos ) +{ + short nTabCount = (short)aTabs.Count(); + if( nTabCount ) + { + for( short nPos = nTabCount-1; nPos >= 0; nPos-- ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( (USHORT)nPos ); + if( (pTab->nFlags & nFlagMask) ) + { + rTabPos = (USHORT)nPos; + return pTab; + } + } + } + rTabPos = 0xffff; + return 0; +} + +void SvTreeListBox::SetAddMode( BOOL bAdd ) +{ + pImp->SetAddMode( bAdd ); +} + +BOOL SvTreeListBox::IsAddMode() const +{ + return pImp->IsAddMode(); +} + +void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if( !pImp->RequestHelp( rHEvt ) ) + SvLBox::RequestHelp( rHEvt ); +} + +void SvTreeListBox::CursorMoved( SvLBoxEntry* ) +{ +} + +IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData ) +{ + SvLBoxEntry* pLeft = (SvLBoxEntry*)(pData->pLeft ); + SvLBoxEntry* pRight = (SvLBoxEntry*)(pData->pRight ); + String aLeft( ((SvLBoxString*)(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText()); + String aRight( ((SvLBoxString*)(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText()); + // Intntl: Compare(a,b) ==> b.Compare(a) ==> strcmp(a,b) + const International& rInter = Application::GetAppInternational(); + StringCompare eCompare = rInter.Compare( aLeft, aRight ); + return (long)eCompare; +} + +void SvTreeListBox::ModelNotification( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, ULONG nPos ) +{ + if( nActionId == LISTACTION_CLEARING ) + CancelTextEditing(); + + SvLBox::ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + switch( nActionId ) + { + case LISTACTION_RESORTING: + SetUpdateMode( FALSE ); + break; + + case LISTACTION_RESORTED: + // nach Sortierung den ersten Eintrag anzeigen, dabei die + // Selektion erhalten. + MakeVisible( (SvLBoxEntry*)pModel->First(), TRUE ); + SetUpdateMode( TRUE ); + break; + + case LISTACTION_CLEARED: + if( IsUpdateMode() ) + Update(); + break; + } +} + +// bei Aenderungen SetTabs beruecksichtigen +long SvTreeListBox::GetTextOffset() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + BOOL bHasButtons = (nWindowStyle & WB_HASBUTTONS)!=0; + BOOL bHasButtonsAtRoot = (nWindowStyle & (WB_HASLINESATROOT | + WB_HASBUTTONSATROOT))!=0; + long nStartPos = TAB_STARTPOS; + long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width(); + + long nCheckWidth = 0; + if( nTreeFlags & TREEFLAG_CHKBTN ) + nCheckWidth = pCheckButtonData->aBmps[0].GetSizePixel().Width(); + long nCheckWidthDIV2 = nCheckWidth / 2; + + long nContextWidth = nContextBmpWidthMax; + long nContextWidthDIV2 = nContextWidth / 2; + + int nCase = NO_BUTTONS; + if( !(nTreeFlags & TREEFLAG_CHKBTN) ) + { + if( bHasButtons ) + nCase = NODE_BUTTONS; + } + else + { + if( bHasButtons ) + nCase = NODE_AND_CHECK_BUTTONS; + else + nCase = CHECK_BUTTONS; + } + + switch( nCase ) + { + case NO_BUTTONS : + nStartPos += nContextWidthDIV2; // wg. Zentrierung + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case NODE_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + (nNodeWidthPixel/2) ); + else + nStartPos += nContextWidthDIV2; + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case NODE_AND_CHECK_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + nNodeWidthPixel ); + else + nStartPos += nCheckWidthDIV2; + nStartPos += nCheckWidthDIV2; // rechter Rand des CheckButtons + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case CHECK_BUTTONS : + nStartPos += nCheckWidthDIV2; + nStartPos += nCheckWidthDIV2; // rechter Rand CheckButton + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + } + return nStartPos; +} + +void SvTreeListBox::EndSelection() +{ + pImp->EndSelection(); +} + +BOOL SvTreeListBox::IsNodeButton( const Point& rPos ) const +{ + SvLBoxEntry* pEntry = GetEntry( rPos ); + if( pEntry ) + return pImp->IsNodeButton( rPos, pEntry ); + return FALSE; +} + +void SvTreeListBox::RepaintScrollBars() const +{ + ((SvTreeListBox*)this)->pImp->RepaintScrollBars(); +} + +ScrollBar *SvTreeListBox::GetVScroll() +{ + return &((SvTreeListBox*)this)->pImp->aVerSBar; +} + +ScrollBar *SvTreeListBox::GetHScroll() +{ + return &((SvTreeListBox*)this)->pImp->aHorSBar; +} + +void SvTreeListBox::EnableAsyncDrag( BOOL b ) +{ + pImp->EnableAsyncDrag( b ); +} + +void SvTreeListBox::SetDontKnowNodeBitmap( const Image& rCollapsedNodeBmp ) +{ + pImp->SetDontKnowNodeBmp( rCollapsedNodeBmp ); +} + +SvLBoxEntry* SvTreeListBox::GetFirstEntryInView() const +{ + Point aPos; + return GetEntry( aPos ); +} + +SvLBoxEntry* SvTreeListBox::GetNextEntryInView(SvLBoxEntry* pEntry ) const +{ + SvLBoxEntry* pNext = (SvLBoxEntry*)NextVisible( pEntry ); + if( pNext ) + { + Point aPos( GetEntryPos(pNext) ); + const Size& rSize = pImp->GetOutputSize(); + if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() ) + return 0; + } + return pNext; +} + +void SvTreeListBox::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + pImp->ShowFocusRect( pEntry ); +} + +void SvTreeListBox::SetTabBar( TabBar* pTabBar ) +{ + pImp->SetTabBar( pTabBar ); +} + +void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if( (rDCEvt.GetType()==DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + InitSettings( TRUE, TRUE, TRUE ); + Invalidate(); + } + else + Control::DataChanged( rDCEvt ); +} + +void SvTreeListBox::InitSettings(BOOL bFont,BOOL bForeground,BOOL bBackground) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetFieldFont(); + SetPointFont( aFont ); + } + + if( bForeground || bFont ) + { + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + } + + if( bBackground ) + SetBackground( rStyleSettings.GetFieldColor() ); +} + +void SvTreeListBox::InitStartEntry() +{ + if( !pImp->pStartEntry ) + pImp->pStartEntry = GetModel()->First(); +} + + diff --git a/svtools/source/contnr/treelist.cxx b/svtools/source/contnr/treelist.cxx new file mode 100644 index 000000000000..04255804df22 --- /dev/null +++ b/svtools/source/contnr/treelist.cxx @@ -0,0 +1,2146 @@ +/************************************************************************* + * + * $RCSfile: treelist.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:58:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#define _TREELIST_CXX + +#pragma hdrstop + +#include <treelist.hxx> + +#ifndef PRODUCT +// Prueft Integritaet der Liste nach jeder Operation +//#define CHECK_INTEGRITY +#endif + + +DBG_NAME(SvListEntry); + +SvListEntry::SvListEntry() +{ + DBG_CTOR(SvListEntry,0); + pChilds = 0; + pParent = 0; + nListPos = 0; + nAbsPos = 0; +} + +SvListEntry::SvListEntry( const SvListEntry& rEntry ) +{ + DBG_CTOR(SvListEntry,0); + pChilds = 0; + pParent = 0; + nListPos &= 0x80000000; + nListPos |= ( rEntry.nListPos & 0x7fffffff); + nAbsPos = rEntry.nAbsPos; +} + +SvListEntry::~SvListEntry() +{ + DBG_DTOR(SvListEntry,0); + if ( pChilds ) + { + pChilds->DestroyAll(); + delete pChilds; + } +#ifdef DBG_UTIL + pChilds = 0; + pParent = 0; +#endif +} + +void SvListEntry::Clone( SvListEntry* pSource) +{ + DBG_CHKTHIS(SvListEntry,0); + nListPos &= 0x80000000; + nListPos |= ( pSource->nListPos & 0x7fffffff); + nAbsPos = pSource->nAbsPos; +} + +void SvListEntry::SetListPositions() +{ + if( pChilds ) + { + SvListEntry *pEntry = (SvListEntry*)pChilds->First(); + ULONG nCur = 0; + while ( pEntry ) + { + pEntry->nListPos &= 0x80000000; + pEntry->nListPos |= nCur; + nCur++; + pEntry = (SvListEntry*)pChilds->Next(); + } + } + nListPos &= (~0x80000000); +} + + +DBG_NAME(SvViewData); + +SvViewData::SvViewData() +{ + DBG_CTOR(SvViewData,0); + nFlags = 0; + nVisPos = 0; +} + +SvViewData::SvViewData( const SvViewData& rData ) +{ + DBG_CTOR(SvViewData,0); + nFlags = rData.nFlags; + nFlags &= ~( SVLISTENTRYFLAG_SELECTED | SVLISTENTRYFLAG_FOCUSED ); + nVisPos = rData.nVisPos; +} + +SvViewData::~SvViewData() +{ + DBG_DTOR(SvViewData,0); +#ifdef DBG_UTIL + nVisPos = 0x12345678; + nFlags = 0x1234; +#endif +} + +void SvTreeEntryList::DestroyAll() +{ + SvListEntry* pPtr = (SvListEntry*)First(); + while( pPtr ) + { + delete pPtr; + pPtr = (SvListEntry*)Next(); + } +} + + + + +#if defined (WIN) && defined (MSC) +// siehe BugId 42896: Die Funktionen Prev, PrevVisible, Next, NextVisible +// (andere?) funktionieren nicht mit Optimierung. +#pragma optimize ("", off) +#endif + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::SvTreeList() +{ + nEntryCount = 0; + bAbsPositionsValid = FALSE; + nRefCount = 1; + pRootItem = new SvListEntry; + eSortMode = SortNone; +} + + +/************************************************************************* +|* +|* SvTreeList::~SvTreeList +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::~SvTreeList() +{ + Clear(); + delete pRootItem; +#ifdef DBG_UTIL + pRootItem = 0; +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Broadcast +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Broadcast( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, ULONG nPos ) +{ + ULONG nViewCount = aViewList.Count(); + for( ULONG nCurView = 0; nCurView < nViewCount; nCurView++ ) + { + SvListView* pView = (SvListView*)aViewList.GetObject( nCurView ); + if( pView ) + pView->ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + } +} + +void SvTreeList::InsertView( SvListView* pView) +{ + ULONG nPos = aViewList.GetPos( pView ); + if ( nPos == LIST_ENTRY_NOTFOUND ) + { + aViewList.Insert( pView, LIST_APPEND ); + nRefCount++; + } +} + +void SvTreeList::RemoveView( SvListView* pView ) +{ + ULONG nPos = aViewList.GetPos( pView ); + if ( nPos != LIST_ENTRY_NOTFOUND ) + { + aViewList.Remove( pView ); + nRefCount--; + } +} + + +// Ein Entry ist sichtbar, wenn alle Parents expandiert sind +BOOL SvTreeList::IsEntryVisible( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"IsVisible:Invalid Params") + BOOL bRetVal=FALSE; + do + { + if ( pEntry == pRootItem ) + { + bRetVal=TRUE; + break; + } + pEntry = pEntry->pParent; + } while( pView->IsExpanded( pEntry ) ); + return bRetVal; +} + +USHORT SvTreeList::GetDepth( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry&&pEntry!=pRootItem,"GetDepth:Bad Entry") + USHORT nDepth = 0; + while( pEntry->pParent != pRootItem ) + { + nDepth++; + pEntry = pEntry->pParent; + } + return nDepth; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Clear() +{ + Broadcast( LISTACTION_CLEARING ); + SvTreeEntryList* pRootList = pRootItem->pChilds; + if ( pRootList ) + { + SvListEntry* pEntry = (SvListEntry*)(pRootList->First()); + while( pEntry ) + { + delete pEntry; + pEntry = (SvListEntry*)(pRootList->Next()); + } + delete pRootItem->pChilds; + pRootItem->pChilds = 0; + } + nEntryCount = 0; + Broadcast( LISTACTION_CLEARED ); +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +BOOL SvTreeList::IsChild( SvListEntry* pParent, SvListEntry* pChild ) const +{ + if ( !pParent ) + pParent = pRootItem; + + BOOL bIsChild = FALSE; + SvTreeEntryList* pList = pParent->pChilds; + if ( !pList ) + return FALSE; + SvListEntry* pActualChild = (SvListEntry*)(pList->First()); + while( !bIsChild && pActualChild ) + { + if ( pActualChild == pChild ) + bIsChild = TRUE; + else + { + if ( pActualChild->pChilds ) + bIsChild = IsChild( pActualChild, pChild ); + pActualChild = (SvListEntry*)(pList->Next()); + } + } + return bIsChild; +} + +ULONG SvTreeList::Move(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,ULONG nListPos) +{ + // pDest darf Null sein! + DBG_ASSERT(pSrcEntry,"Entry?") + if ( !pTargetParent ) + pTargetParent = pRootItem; + DBG_ASSERT(pSrcEntry!=pTargetParent,"Move:Source=Target") + + Broadcast( LISTACTION_MOVING, pSrcEntry, pTargetParent, nListPos ); + + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + if ( pSrcEntry == pTargetParent ) + return pSrcEntry->GetChildListPos(); + + bAbsPositionsValid = FALSE; + + SvTreeEntryList* pDstList = pTargetParent->pChilds; + SvTreeEntryList* pSrcList = pSrcEntry->pParent->pChilds; + + // Dummy-Ptr einfuegen, weil nListPos durch das + // folgende Remove ungueltig werden koennte + SvListEntry* pDummy = 0; pDstList->Insert( pDummy, nListPos ); + + // loeschen + pSrcList->Remove( pSrcEntry ); + // Hat Parent noch Childs ? + if ( pSrcList->Count() == 0 ) + { + // Keine Childs, deshalb Child-List loeschen + SvListEntry* pParent = pSrcEntry->pParent; + pParent->pChilds = 0; + delete pSrcList; + pSrcList = 0; + } + + // Parent umsetzen (erst hier, weil wir zum Loeschen + // der ChildList den alten Parent noch benoetigen!) + pSrcEntry->pParent = pTargetParent; + + pDstList->Replace( pSrcEntry, pDummy ); + + // Listenpositionen in Zielliste korrigieren + SetListPositions( pDstList ); + if ( pSrcList && (ULONG)pSrcList != (ULONG)pDstList ) + SetListPositions( pSrcList ); + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + + ULONG nRetVal = pDstList->GetPos( pSrcEntry ); + DBG_ASSERT(nRetVal==pSrcEntry->GetChildListPos(),"ListPos not valid") + Broadcast( LISTACTION_MOVED,pSrcEntry,pTargetParent,nRetVal); + return nRetVal; +} + +ULONG SvTreeList::Copy(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,ULONG nListPos) +{ + // pDest darf Null sein! + DBG_ASSERT(pSrcEntry,"Entry?") + if ( !pTargetParent ) + pTargetParent = pRootItem; + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + + bAbsPositionsValid = FALSE; + + ULONG nCloneCount = 0; + SvListEntry* pClonedEntry = Clone( pSrcEntry, nCloneCount ); + nEntryCount += nCloneCount; + + SvTreeEntryList* pDstList = pTargetParent->pChilds; + pClonedEntry->pParent = pTargetParent; // Parent umsetzen + pDstList->Insert( pClonedEntry, nListPos ); // Einfuegen + SetListPositions( pDstList ); // Listenpositionen in Zielliste korrigieren + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_INSERTED_TREE, pClonedEntry ); + ULONG nRetVal = pDstList->GetPos( pClonedEntry ); + return nRetVal; +} + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Move( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos(); + nPos++; // UNTER (Bildschirm) pDstEntry einfuegen + } + Move( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Copy( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + Copy( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +void SvTreeList::InsertTree( SvListEntry* pSrcEntry, SvListEntry* pDstEntry) +{ + SvListEntry* pParent; + ULONG nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + InsertTree( pSrcEntry, pParent, nPos ); +} + + +void SvTreeList::InsertTree(SvListEntry* pSrcEntry, + SvListEntry* pTargetParent,ULONG nListPos) +{ + DBG_ASSERT(pSrcEntry,"InsertTree:Entry?") + if ( !pSrcEntry ) + return; + + if ( !pTargetParent ) + pTargetParent = pRootItem; + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + + // Sortierung beruecksichtigen + GetInsertionPos( pSrcEntry, pTargetParent, nListPos ); + + bAbsPositionsValid = FALSE; + + pSrcEntry->pParent = pTargetParent; // Parent umsetzen + SvTreeEntryList* pDstList = pTargetParent->pChilds; + pDstList->Insert( pSrcEntry, nListPos ); // einfuegen + SetListPositions(pDstList); // Listenpositionen in Zielliste korrigieren + nEntryCount += GetChildCount( pSrcEntry ); + nEntryCount++; // der Parent ist ja auch neu + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast(LISTACTION_INSERTED_TREE, pSrcEntry ); +} + +SvListEntry* SvTreeList::CloneEntry( SvListEntry* pSource ) const +{ + if( aCloneLink.IsSet() ) + return (SvListEntry*)aCloneLink.Call( pSource ); + SvListEntry* pEntry = CreateEntry(); + pSource->Clone( pEntry ); + return pSource; +} + +SvListEntry* SvTreeList::CreateEntry() const +{ + return new SvListEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Clone( SvListEntry* pEntry, ULONG& nCloneCount ) const +{ + SvListEntry* pClonedEntry = CloneEntry( pEntry ); + nCloneCount = 1; + SvTreeEntryList* pChilds = pEntry->pChilds; + if ( pChilds ) + pClonedEntry->pChilds=CloneChilds(pChilds,pClonedEntry,nCloneCount); + return pClonedEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeEntryList* SvTreeList::CloneChilds( SvTreeEntryList* pChilds, + SvListEntry* pNewParent, + ULONG& nCloneCount ) const +{ + DBG_ASSERT(pChilds->Count(),"Childs?") + SvTreeEntryList* pClonedChilds = new SvTreeEntryList; + SvListEntry* pChild = (SvListEntry*)pChilds->First(); + while ( pChild ) + { + SvListEntry* pNewChild = CloneEntry( pChild ); + nCloneCount++; + pNewChild->pParent = pNewParent; + SvTreeEntryList* pSubChilds = pChild->pChilds; + if ( pSubChilds ) + { + pSubChilds = CloneChilds( pSubChilds, pNewChild, nCloneCount ); + pNewChild->pChilds = pSubChilds; + } + + pClonedChilds->Insert( pNewChild, LIST_APPEND ); + pChild = (SvListEntry*)pChilds->Next(); + } + return pClonedChilds; +} + + +/************************************************************************* +|* +|* SvTreeList::GetChildCount +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetChildCount( SvListEntry* pParent ) const +{ + if ( !pParent ) + return GetEntryCount(); + + if ( !pParent || !pParent->pChilds) + return 0; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetVisibleChildCount(const SvListView* pView, SvListEntry* pParent) const +{ + DBG_ASSERT(pView,"GetVisChildCount:No View") + if ( !pParent ) + pParent = pRootItem; + if ( !pParent || !pView->IsExpanded(pParent) || !pParent->pChilds ) + return 0; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = NextVisible( pView, pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +ULONG SvTreeList::GetChildSelectionCount(const SvListView* pView,SvListEntry* pParent) const +{ + DBG_ASSERT(pView,"GetChildSelCount:No View") + if ( !pParent ) + pParent = pRootItem; + if ( !pParent || !pParent->pChilds) + return 0; + ULONG nCount = 0; + USHORT nRefDepth = GetDepth( pParent ); + USHORT nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + if( pParent && pView->IsSelected( pParent ) && nRefDepth < nActDepth) + nCount++; + } while( pParent && nRefDepth < nActDepth ); +// nCount--; + return nCount; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::First() const +{ + if ( nEntryCount ) + return (SvListEntry*)(pRootItem->pChilds->GetObject(0)); + else + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Next +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Next( SvListEntry* pActEntry, USHORT* pDepth ) const +{ + DBG_ASSERT(pActEntry,"Entry?") + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + + if ( pActualList->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos + 1 )); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + + SvListEntry* pParent = pActEntry->pParent; + nDepth--; + while( pParent != pRootItem && pParent != 0 ) + { + DBG_ASSERT(pParent!=0,"TreeData corrupt!"); + pActualList = pParent->pParent->pChilds; + DBG_ASSERT(pActualList,"TreeData corrupt!") + nActualPos = pParent->GetChildListPos(); + if ( pActualList->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos + 1 )); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Prev +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Prev( SvListEntry* pActEntry, USHORT* pDepth ) const +{ + DBG_ASSERT(pActEntry!=0,"Entry?") + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos - 1 )); + while( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + pActualList = pActEntry->pChilds; + nDepth++; + pActEntry = (SvListEntry*)(pActualList->Last()); + } + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + if ( pActEntry->pParent == pRootItem ) + return 0; + + pActEntry = pActEntry->pParent; + + if ( pActEntry ) + { + nDepth--; + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Last( USHORT* /* nDepth */ ) const +{ + SvTreeEntryList* pActList = pRootItem->pChilds; +// if ( pActList->Count() == 0 ) +// return 0; + SvListEntry* pEntry = 0; + while( pActList ) + { + pEntry = (SvListEntry*)(pActList->Last()); + pActList = pEntry->pChilds; +// if ( pActList->Count() == 0 ) +// pActList = 0; + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetVisiblePos( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"View/Entry?") + + if ( !pView->bVisPositionsValid ) + { + // damit GetVisibleCount die Positionen aktualisiert + ((SvListView*)pView)->nVisibleCount = 0; + GetVisibleCount( pView ); + } + SvViewData* pViewData = pView->GetViewData( pEntry ); + return pViewData->nVisPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetVisibleCount( const SvListView* pView ) const +{ + DBG_ASSERT(pView,"GetVisCount:No View") + if( !pView->HasViewData() ) + return 0; + if ( pView->nVisibleCount ) + return pView->nVisibleCount; + + ULONG nPos = 0; + SvListEntry* pEntry = First(); // erster Eintrag immer sichtbar + while ( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->nVisPos = nPos; + nPos++; + pEntry = NextVisible( pView, pEntry ); + } +#ifdef DBG_UTIL + if( nPos > 10000000 ) + { + DBG_ERROR("nVisibleCount bad"); + } +#endif + ((SvListView*)pView)->nVisibleCount = nPos; + ((SvListView*)pView)->bVisPositionsValid = TRUE; + return nPos; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pActEntry,USHORT* pActDepth) const +{ + DBG_ASSERT(pView,"NextVisible:No View") + if ( !pActEntry ) + return 0; + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( pView->IsExpanded(pActEntry) ) + { + DBG_ASSERT(pActEntry->pChilds,"Childs?") + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + nActualPos++; + if ( pActualList->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos )); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + SvListEntry* pParent = pActEntry->pParent; + nDepth--; + while( pParent != pRootItem ) + { + pActualList = pParent->pParent->pChilds; + nActualPos = pParent->GetChildListPos(); + nActualPos++; + if ( pActualList->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos )); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::PrevVisible(const SvListView* pView, SvListEntry* pActEntry, USHORT* pActDepth) const +{ + DBG_ASSERT(pView&&pActEntry,"PrevVis:View/Entry?") + + USHORT nDepth = 0; + int bWithDepth = FALSE; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = TRUE; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + ULONG nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos - 1 )); + while( pView->IsExpanded(pActEntry) ) + { + pActualList = pActEntry->pChilds; + nDepth++; + pActEntry = (SvListEntry*)(pActualList->Last()); + } + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + if ( pActEntry->pParent == pRootItem ) + return 0; + + pActEntry = pActEntry->pParent; + if ( pActEntry ) + { + nDepth--; + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::LastVisible( const SvListView* pView, USHORT* pDepth) const +{ + DBG_ASSERT(pView,"LastVis:No View") + SvListEntry* pEntry = Last(); + while( pEntry && !IsEntryVisible( pView, pEntry ) ) + pEntry = PrevVisible( pView, pEntry ); + if ( pEntry && pDepth ) + *pDepth = GetDepth( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pEntry,USHORT& nDelta) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"NextVis:Wrong Prms/!Vis") + + ULONG nVisPos = GetVisiblePos( pView, pEntry ); + // nDelta Eintraege vorhanden ? + // Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=5 nDelta=7 + // nNewDelta = 10-nVisPos-1 == 4 + if ( nVisPos+nDelta >= pView->nVisibleCount ) + { + nDelta = (USHORT)(pView->nVisibleCount-nVisPos); + nDelta--; + } + USHORT nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = NextVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?") + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::PrevVisible( const SvListView* pView, SvListEntry* pEntry, USHORT& nDelta ) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"PrevVis:Parms/!Vis") + + ULONG nVisPos = GetVisiblePos( pView, pEntry ); + // nDelta Eintraege vorhanden ? + // Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=8 nDelta=20 + // nNewDelta = nNewVisPos + if ( nDelta > nVisPos ) + nDelta = (USHORT)nVisPos; + USHORT nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = PrevVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?") + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::FirstSelected( const SvListView* pView) const +{ + DBG_ASSERT(pView,"FirstSel:No View") + if( !pView ) + return 0; + SvListEntry* pActSelEntry = First(); + while( pActSelEntry && !pView->IsSelected(pActSelEntry) ) + pActSelEntry = NextVisible( pView, pActSelEntry ); + return pActSelEntry; +} + + +SvListEntry* SvTreeList::FirstChild( SvListEntry* pParent ) const +{ + if ( !pParent ) + pParent = pRootItem; + SvListEntry* pResult; + if ( pParent->pChilds ) + pResult = (SvListEntry*)(pParent->pChilds->GetObject( 0 )); + else + pResult = 0; + return pResult; +} + +SvListEntry* SvTreeList::NextSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"Entry?") + if( !pEntry ) + return 0; + SvTreeEntryList* pList = pEntry->pParent->pChilds; +// ULONG nPos = pList->GetPos( pEntry ); + ULONG nPos = pEntry->GetChildListPos(); + nPos++; + pEntry = (SvListEntry*)(pList->GetObject( nPos )); + return pEntry; +} + +SvListEntry* SvTreeList::PrevSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"Entry?") + if( !pEntry ) + return 0; + + SvTreeEntryList* pList = pEntry->pParent->pChilds; + // ULONG nPos = pList->GetPos( pEntry ); + ULONG nPos = pEntry->GetChildListPos(); + if ( nPos == 0 ) + return 0; + nPos--; + pEntry = (SvListEntry*)(pList->GetObject( nPos )); + return pEntry; +} + + +SvListEntry* SvTreeList::LastSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"LastSibling:Entry?"); + if( !pEntry ) + return 0; + SvListEntry* pSib = 0; + SvTreeEntryList* pSibs = pEntry->pParent->pChilds; + if ( pSibs ) + pSib = (SvListEntry*)(pSibs->Last()); + return pSib; +} + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::NextSelected( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"NextSel:View/Entry?") + pEntry = Next( pEntry ); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Next( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::PrevSelected( const SvListView* pView, SvListEntry* pEntry) const +{ + DBG_ASSERT(pView&&pEntry,"PrevSel:View/Entry?") + pEntry = Prev( pEntry ); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Prev( pEntry ); + + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::LastSelected( const SvListView* pView ) const +{ + DBG_ASSERT(pView,"LastSel:No View") + SvListEntry* pEntry = Last(); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Prev( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList::Insert +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +ULONG SvTreeList::Insert( SvListEntry* pEntry,SvListEntry* pParent,ULONG nPos ) +{ + DBG_ASSERT( pEntry,"Entry?") + + if ( !pParent ) + pParent = pRootItem; + + + SvTreeEntryList* pList = pParent->pChilds; + if ( !pList ) + { + // Parent bekommt zum erstenmal ein Kind + pList = new SvTreeEntryList; + pParent->pChilds = pList; + } + + // Sortierung beruecksichtigen + GetInsertionPos( pEntry, pParent, nPos ); + + bAbsPositionsValid = FALSE; + pEntry->pParent = pParent; + + pList->Insert( pEntry, nPos ); + nEntryCount++; + if( nPos != LIST_APPEND && (nPos != (pList->Count()-1)) ) + SetListPositions( pList ); + else + pEntry->nListPos = pList->Count()-1; + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_INSERTED, pEntry ); + return nPos; // pEntry->nListPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::GetAbsPos( SvListEntry* pEntry) const +{ + if ( !bAbsPositionsValid ) + ((SvTreeList*)this)->SetAbsolutePositions(); + return pEntry->nAbsPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::SetAbsolutePositions() +{ + ULONG nPos = 0; + SvListEntry* pEntry = First(); + while ( pEntry ) + { + pEntry->nAbsPos = nPos; + nPos++; + pEntry = Next( pEntry ); + } + bAbsPositionsValid = TRUE; +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList::Expand +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Expand( SvListView* pView, SvListEntry* pEntry ) +{ + DBG_ASSERT(pEntry&&pView,"Expand:View/Entry?") + if ( pView->IsExpanded(pEntry) ) + return; + + DBG_ASSERT(pEntry->pChilds,"Expand:No Childs!") + + SvViewData* pViewData = pView->GetViewData(pEntry); + pViewData->nFlags |= SVLISTENTRYFLAG_EXPANDED; + SvListEntry* pParent = pEntry->pParent; + // wenn Parent sichtbar dann Statusdaten invalidieren + if ( pView->IsExpanded( pParent ) ) + { + pView->bVisPositionsValid = FALSE; + pView->nVisibleCount = 0; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Collapse +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Collapse( SvListView* pView, SvListEntry* pEntry ) +{ + DBG_ASSERT(pView&&pEntry,"Collapse:View/Entry?") + if ( !pView->IsExpanded(pEntry) ) + return; + + DBG_ASSERT(pEntry->pChilds,"Collapse:No Childs!") + + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->nFlags &=(~SVLISTENTRYFLAG_EXPANDED); + + SvListEntry* pParent = pEntry->pParent; + if ( pView->IsExpanded(pParent) ) + { + pView->nVisibleCount = 0; + pView->bVisPositionsValid = FALSE; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +BOOL SvTreeList::Select( SvListView* pView, SvListEntry* pEntry, BOOL bSelect ) +{ + DBG_ASSERT(pView&&pEntry,"Select:View/Entry?") + SvViewData* pViewData = pView->GetViewData( pEntry ); + if ( bSelect ) + { + if ( pViewData->IsSelected() ) + return FALSE; + else + { + pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED; + pView->nSelectionCount++; + } + } + else + { + if ( !pViewData->IsSelected() ) + return FALSE; + else + { + pViewData->nFlags &= ~( SVLISTENTRYFLAG_SELECTED ); + pView->nSelectionCount--; + } + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return TRUE; +} + +/************************************************************************* +|* +|* SvTreeList::Remove +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 24.06.97 +|* +*************************************************************************/ +BOOL SvTreeList::Remove( SvListEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"Cannot remove root, use clear") + + if( !pEntry->pParent ) + { + DBG_ERROR("Removing entry not in model!"); + // unter gewissen Umstaenden (welche?) loescht der + // Explorer aus der View Eintraege, die er nicht in die View + // eingefuegt hat. Da sich der Kunde fuer ein platzendes + // Office nichts kaufen kann, fange ich diesen Fall ab. + return FALSE; + } + + Broadcast( LISTACTION_REMOVING, pEntry ); + ULONG nRemoved = 1 + GetChildCount(pEntry); + bAbsPositionsValid = FALSE; + + SvListEntry* pParent = pEntry->pParent; + SvTreeEntryList* pList = pParent->pChilds; + DBG_ASSERT(pList,"Remove:No Childlist") + BOOL bLastEntry = FALSE; + + if ( pEntry->HasChildListPos() ) + { + ULONG nListPos = pEntry->GetChildListPos(); + bLastEntry = (nListPos == (pList->Count()-1) ) ? TRUE : FALSE; + pList->Remove( nListPos ); + } + else + { + pList->Remove( (void*) pEntry ); + } + + delete pEntry; // loescht auch alle Childs + + if ( pList->Count() == 0 ) + { + pParent->pChilds = 0; + delete pList; + } + else + { + if( !bLastEntry ) + SetListPositions( pList ); + } + nEntryCount -= nRemoved; + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_REMOVED, pEntry ); + return TRUE; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +ULONG SvTreeList::SelectChilds(SvListView* pView, SvListEntry* pParent,BOOL bSelect ) +{ + DBG_ASSERT(pView&&pParent,"SelChilds:View/Parent?") + if ( !pParent->pChilds ) + return 0; + if ( pParent->pChilds->Count() == 0 ) + return 0; + + USHORT nRefDepth = GetDepth( pParent ); + USHORT nDepth = nRefDepth; + ULONG nCount = 0; + pParent = Next( pParent ); + do + { + if ( Select( pView, pParent, bSelect ) ) + nCount++; // nur die tatsaechlichen Selektierungen zaehlen + pParent = Next( pParent, &nDepth ); + } + while( pParent && nDepth > nRefDepth ); +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return nCount; +} + +void SvTreeList::SelectAll( SvListView* pView, BOOL bSelect ) +{ + DBG_ASSERT(pView,"SelectAll:NoView") + SvListEntry* pEntry = First(); + while ( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + if ( bSelect ) + pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED; + else + pViewData->nFlags &= (~SVLISTENTRYFLAG_SELECTED); + + pEntry = Next( pEntry ); + } + if ( bSelect ) + pView->nSelectionCount = nEntryCount; + else + pView->nSelectionCount = 0; +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +SvListEntry* SvTreeList::GetEntryAtAbsPos( ULONG nAbsPos ) const +{ + SvListEntry* pEntry = First(); + while ( nAbsPos && pEntry ) + { + pEntry = Next( pEntry ); + nAbsPos--; + } + return pEntry; +} + +SvListEntry* SvTreeList::GetEntryAtVisPos( const SvListView* pView, ULONG nVisPos ) const +{ + DBG_ASSERT(pView,"GetEntryAtVisPos:No View") + SvListEntry* pEntry = First(); + while ( nVisPos && pEntry ) + { + pEntry = NextVisible( pView, pEntry ); + nVisPos--; + } + return pEntry; +} + +void SvTreeList::SetListPositions( SvTreeEntryList* pList ) +{ + if( pList->Count() ) + { + SvListEntry* pEntry = (SvListEntry*)(pList->GetObject(0)); + if( pEntry->pParent ) + pEntry->pParent->InvalidateChildrensListPositions(); + } + /* + ULONG nListPos = 0; + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + while( pEntry ) + { + pEntry->nListPos = nListPos; + nListPos++; + pEntry = (SvListEntry*)(pList->Next()); + } + */ +} + + +void SvTreeList::InvalidateEntry( SvListEntry* pEntry ) +{ + Broadcast( LISTACTION_INVALIDATE_ENTRY, pEntry ); +} + +BOOL SvTreeList::IsInChildList( SvListEntry* pParent, SvListEntry* pChild) const +{ + if ( !pParent ) + pParent = pRootItem; + BOOL bIsChild = FALSE; + if ( pParent->pChilds ) + bIsChild = (BOOL)(pParent->pChilds->GetPos(pChild) != LIST_ENTRY_NOTFOUND); + return bIsChild; +} + + +void lcl_CheckList( SvTreeEntryList* pList ) +{ + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + ULONG nPos = 0; + while ( pEntry ) + { + DBG_ASSERT(pEntry->GetChildListPos()==nPos,"Wrong ListPos") + pEntry = (SvListEntry*)(pList->Next()); + nPos++; + } +} + +void SvTreeList::CheckIntegrity() const +{ + ULONG nMyEntryCount = 0; + if ( pRootItem->pChilds ) + { + lcl_CheckList( pRootItem->pChilds ); + SvListEntry* pEntry = First(); + while( pEntry ) + { + nMyEntryCount++; + if ( pEntry->pChilds ) + lcl_CheckList( pEntry->pChilds ); + pEntry = Next( pEntry ); + } + } + DBG_ASSERT(nMyEntryCount==GetEntryCount(),"Entry count invalid") +} + +SvListEntry* SvTreeList::GetRootLevelParent( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"GetRootLevelParent:No Entry") + SvListEntry* pCurParent = 0; + if ( pEntry ) + { + pCurParent = pEntry->pParent; + if ( pCurParent == pRootItem ) + return pEntry; // ist sein eigener Parent + while( pCurParent->pParent != pRootItem ) + pCurParent = pCurParent->pParent; + } + return pCurParent; +} + + + + +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* + +DBG_NAME(SvListView); + +SvListView::SvListView( SvTreeList* pModell ) +{ + DBG_CTOR(SvListView,0); + pModel = 0; + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = FALSE; + SetModel( pModell ); +} + +SvListView::SvListView() +{ + DBG_CTOR(SvListView,0); + pModel = 0; + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = FALSE; +} + + +SvListView::~SvListView() +{ + DBG_DTOR(SvListView,0); + ClearTable(); +} + +void SvListView::InitTable() +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pModel,"InitTable:No Model") + DBG_ASSERT(!nSelectionCount&&!nVisibleCount&&!bVisPositionsValid,"InitTable: Not cleared!"); + + if( aDataTable.Count() ) + { + DBG_ASSERT(aDataTable.Count()==1,"InitTable: TableCount != 1"); + // die im Clear fuer die Root allozierten View-Daten loeschen + // Achtung: Das zu dem RootEntry (und damit auch der Entry) + // gehoerende Model kann bereits geloescht sein! + SvViewData* pViewData = (SvViewData*)aDataTable.GetObject( 0 ); + delete pViewData; + aDataTable.Clear(); + } + + SvListEntry* pEntry; + SvViewData* pViewData; + + // RootEntry einfuegen + pEntry = pModel->pRootItem; + pViewData = new SvViewData; + pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED; + aDataTable.Insert( (ULONG)pEntry, pViewData ); + // Jetzt alle anderen Entries + pEntry = pModel->First(); + while( pEntry ) + { + pViewData = CreateViewData( pEntry ); + DBG_ASSERT(pViewData,"InitTable:No ViewData") + InitViewData( pViewData, pEntry ); + aDataTable.Insert( (ULONG)pEntry, pViewData ); + pEntry = pModel->Next( pEntry ); + } +} + +SvViewData* SvListView::CreateViewData( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); + return new SvViewData; +} + +void SvListView::ClearTable() +{ + DBG_CHKTHIS(SvListView,0); + SvViewData* pViewData = (SvViewData*)aDataTable.First(); + while( pViewData ) + { + delete pViewData; + pViewData = (SvViewData*)aDataTable.Next(); + } + aDataTable.Clear(); +} + +void SvListView::Clear() +{ + ClearTable(); + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = FALSE; + if( pModel ) + { + // RootEntry einfuegen + SvListEntry* pEntry = pModel->pRootItem; + SvViewData* pViewData = new SvViewData; + pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED; + aDataTable.Insert( (ULONG)pEntry, pViewData ); + } +} + +void SvListView::SetModel( SvTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvListView,0); + BOOL bBroadcastCleared = FALSE; + if ( pModel ) + { + pModel->RemoveView( this ); + bBroadcastCleared = TRUE; + ModelNotification( LISTACTION_CLEARING,0,0,0 ); + if ( pModel->GetRefCount() == 0 ) + delete pModel; + } + pModel = pNewModel; + InitTable(); + pNewModel->InsertView( this ); + if( bBroadcastCleared ) + ModelNotification( LISTACTION_CLEARED,0,0,0 ); +} + + +void SvListView::ModelHasCleared() +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasInserted( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasInsertedTree( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelIsMoving( SvListEntry* /* pSource */ , + SvListEntry* /* pTargetParent */ , ULONG /* nPos */ ) +{ + DBG_CHKTHIS(SvListView,0); +} + + +void SvListView::ModelHasMoved( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelIsRemoving( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasRemoved( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasEntryInvalidated( SvListEntry*) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ActionMoving( SvListEntry* pEntry,SvListEntry* pTargetPrnt,ULONG nChildPos) +{ + DBG_CHKTHIS(SvListView,0); + SvListEntry* pParent = pEntry->pParent; + DBG_ASSERT(pParent,"Model not consistent") + if( pParent != pModel->pRootItem && pParent->pChilds->Count() == 1 ) + { + SvViewData* pViewData = (SvViewData*)aDataTable.Get( (ULONG)pParent ); + pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED); + } + // vorlaeufig + nVisibleCount = 0; + bVisPositionsValid = FALSE; +} + +void SvListView::ActionMoved( SvListEntry* /* pEntry */ , + SvListEntry* /* pTargetPrnt */ , + ULONG /* nChildPos */ ) +{ + DBG_CHKTHIS(SvListView,0); + nVisibleCount = 0; + bVisPositionsValid = FALSE; +} + +void SvListView::ActionInserted( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pEntry,"Insert:No Entry") + SvViewData* pData = CreateViewData( pEntry ); + InitViewData( pData, pEntry ); + BOOL bSuccess = aDataTable.Insert( (ULONG)pEntry, pData ); + DBG_ASSERT(bSuccess,"Entry already in View") + if ( nVisibleCount && pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = FALSE; + } +} + +void SvListView::ActionInsertedTree( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + if ( pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = FALSE; + } + // ueber Entry und seine Childs iterieren + SvListEntry* pCurEntry = pEntry; + USHORT nRefDepth = pModel->GetDepth( pCurEntry ); + while( pCurEntry ) + { + DBG_ASSERT(aDataTable.Get((ULONG)pCurEntry)==0,"Entry already in Table") + SvViewData* pViewData = CreateViewData( pCurEntry ); + DBG_ASSERT(pViewData,"No ViewData") + InitViewData( pViewData, pEntry ); + aDataTable.Insert( (ULONG)pCurEntry, pViewData ); + pCurEntry = pModel->Next( pCurEntry ); + if ( pCurEntry && pModel->GetDepth(pCurEntry) <= nRefDepth) + pCurEntry = 0; + } +} + +void SvListView::RemoveViewData( SvListEntry* pParent ) +{ + SvTreeEntryList* pChilds = pParent->pChilds; + if( pChilds ) + { + SvListEntry* pCur = (SvListEntry*)pChilds->First(); + while( pCur ) + { + SvViewData* pViewData = (SvViewData*)aDataTable.Get((ULONG)pCur); + delete pViewData; + aDataTable.Remove( (ULONG)pCur ); + if( pCur->HasChilds()) + RemoveViewData( pCur ); + pCur = (SvListEntry*)pChilds->Next(); + } + } +} + + + +void SvListView::ActionRemoving( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pEntry,"Remove:No Entry") + + SvViewData* pViewData = (SvViewData*)aDataTable.Get( (ULONG)pEntry ); + ULONG nSelRemoved = 0; + if ( pViewData->IsSelected() ) + nSelRemoved = 1 + pModel->GetChildSelectionCount( this, pEntry ); + nSelectionCount -= nSelRemoved; + ULONG nVisibleRemoved = 0; + if ( pModel->IsEntryVisible( this, pEntry ) ) + nVisibleRemoved = 1 + pModel->GetVisibleChildCount( this, pEntry ); + if( nVisibleCount ) + { +#ifdef DBG_UTIL + if( nVisibleCount < nVisibleRemoved ) + { + DBG_ERROR("nVisibleRemoved bad"); + } +#endif + nVisibleCount -= nVisibleRemoved; + } + bVisPositionsValid = FALSE; + + pViewData = (SvViewData*)aDataTable.Get((ULONG)pEntry); + delete pViewData; + aDataTable.Remove( (ULONG)pEntry ); + RemoveViewData( pEntry ); + + SvListEntry* pCurEntry = pEntry->pParent; + if ( pCurEntry && pCurEntry != pModel->pRootItem && + pCurEntry->pChilds->Count() == 1 ) + { + pViewData = (SvViewData*)aDataTable.Get((ULONG)pCurEntry); + pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED); + } +} + +void SvListView::ActionRemoved( SvListEntry* /* pEntry */ ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ActionClear() +{ + DBG_CHKTHIS(SvListView,0); + Clear(); +} + +void SvListView::ModelNotification( USHORT nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, ULONG nPos ) +{ + DBG_CHKTHIS(SvListView,0); + switch( nActionId ) + { + case LISTACTION_INSERTED: + ActionInserted( pEntry1 ); + ModelHasInserted( pEntry1 ); + break; + case LISTACTION_INSERTED_TREE: + ActionInsertedTree( pEntry1 ); + ModelHasInsertedTree( pEntry1 ); + break; + case LISTACTION_REMOVING: + ModelIsRemoving( pEntry1 ); + ActionRemoving( pEntry1 ); + break; + case LISTACTION_REMOVED: + ActionRemoved( pEntry1 ); + ModelHasRemoved( pEntry1 ); + break; + case LISTACTION_MOVING: + ModelIsMoving( pEntry1, pEntry2, nPos ); + ActionMoving( pEntry1, pEntry2, nPos ); + break; + case LISTACTION_MOVED: + ActionMoved( pEntry1, pEntry2, nPos ); + ModelHasMoved( pEntry1 ); + break; + case LISTACTION_CLEARING: + ActionClear(); + ModelHasCleared(); //sic! wg. Kompatibilitaet! + break; + case LISTACTION_CLEARED: + break; + case LISTACTION_INVALIDATE_ENTRY: + // keine Action fuer die Basisklasse + ModelHasEntryInvalidated( pEntry1 ); + break; + case LISTACTION_RESORTED: + bVisPositionsValid = FALSE; + break; + case LISTACTION_RESORTING: + break; + default: + DBG_ERROR("unknown ActionId"); + } +} + +void SvListView::InitViewData( SvViewData*, SvListEntry* ) +{ +} + +StringCompare SvTreeList::Compare( SvListEntry* pLeft, SvListEntry* pRight) const +{ + if( aCompareLink.IsSet()) + { + SvSortData aSortData; + aSortData.pLeft = pLeft; + aSortData.pRight = pRight; + return (StringCompare)aCompareLink.Call( &aSortData ); + } + return COMPARE_EQUAL; +} + +void SvTreeList::Resort() +{ + Broadcast( LISTACTION_RESORTING ); + bAbsPositionsValid = FALSE; + ResortChilds( pRootItem ); + Broadcast( LISTACTION_RESORTED ); +} + +void SvTreeList::ResortChilds( SvListEntry* pParent ) +{ + DBG_ASSERT(pParent,"Parent not set"); + List* pChildList = pParent->pChilds; + if( !pChildList ) + return; + List aList( *pChildList ); + pChildList->Clear(); + + ULONG nCount = aList.Count(); + for( ULONG nCur = 0; nCur < nCount; nCur++ ) + { + SvListEntry* pCurEntry = (SvListEntry*)aList.GetObject( nCur ); + ULONG nListPos = LIST_APPEND; + GetInsertionPos( pCurEntry, pParent, nListPos ); + pChildList->Insert( pCurEntry, nListPos ); + if( pCurEntry->pChilds ) + ResortChilds( pCurEntry ); + } + SetListPositions( (SvTreeEntryList*)pChildList ); +} + +void SvTreeList::GetInsertionPos( SvListEntry* pEntry, SvListEntry* pParent, + ULONG& rPos ) +{ + DBG_ASSERT(pEntry,"No Entry") + + if( eSortMode == SortNone ) + return; + + rPos = LIST_APPEND; + SvTreeEntryList* pChildList = GetChildList( pParent ); + + if( pChildList && pChildList->Count() ) + { + long i = 0; + long j = pChildList->Count()-1; + long k; + StringCompare eCompare = COMPARE_GREATER; + + do + { + k = (i+j)/2; + SvListEntry* pTempEntry = (SvListEntry*)(pChildList->GetObject(k)); + eCompare = Compare( pEntry, pTempEntry ); + if( eSortMode == SortDescending && eCompare != COMPARE_EQUAL ) + { + if( eCompare == COMPARE_LESS ) + eCompare = COMPARE_GREATER; + else + eCompare = COMPARE_LESS; + } + if( eCompare == COMPARE_GREATER ) + i = k + 1; + else + j = k - 1; + } while( (eCompare != COMPARE_EQUAL) && (i <= j) ); + + if( eCompare != COMPARE_EQUAL ) + { + if(i > ((long)pChildList->Count() - 1)) // nicht gefunden, Ende der Liste + rPos = LIST_APPEND; + else + rPos = i; // nicht gefunden, Mitte + } + else + rPos = k; + } +} + + |