Files
libreoffice/svtools/source/contnr/treelistbox.cxx
Stephan Bergmann 01f3186c4b SvTreeListBox::ExpandingHdl should return bool
Change-Id: I39a854910299ab2e7c64beabda381bb9f0bd2891
2014-01-13 18:08:07 +01:00

4131 lines
117 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 .
*/
/*
TODO:
- delete anchor in SelectionEngine when selecting manually
- SelectAll( sal_False ) => only repaint the delselected entries
*/
#include <svtools/treelistbox.hxx>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <vcl/svapp.hxx>
#include <vcl/accel.hxx>
#include <vcl/i18nhelp.hxx>
#include <vcl/builder.hxx>
#include <sot/formats.hxx>
#include <unotools/accessiblestatesethelper.hxx>
#include <rtl/instance.hxx>
#include <comphelper/string.hxx>
#include <svtools/svmedit.hxx>
#include <svtools/svlbitm.hxx>
#include "svtools/treelistentry.hxx"
#include "svtools/viewdataentry.hxx"
#include "svimpbox.hxx"
#include <set>
#include <string.h>
#include <vector>
using namespace ::com::sun::star::accessibility;
// Drag&Drop
static SvTreeListBox* pDDSource = NULL;
static SvTreeListBox* pDDTarget = NULL;
DBG_NAME(SvInplaceEdit2)
#define SVLBOX_ACC_RETURN 1
#define SVLBOX_ACC_ESCAPE 2
// ***************************************************************
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 ) :
Edit( pParent, WB_LEFT ),
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,
WB_CENTER
), 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 OUString& rData,
const Link& rNotifyEditEnd,
const Selection& rSelection,
sal_Bool bMulti
) :
aCallBackHdl ( rNotifyEditEnd ),
bCanceled ( sal_False ),
bAlreadyInCallBack ( sal_False )
{
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( sal_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 );
pEdit->SetSelection( rSelection );
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;
}
OUString SvInplaceEdit2::GetSavedValue() const
{
return pEdit->GetSavedValue();
}
void SvInplaceEdit2::Hide()
{
pEdit->Hide();
}
IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, ReturnHdl_Impl)
{
DBG_CHKTHIS(SvInplaceEdit2,0);
bCanceled = sal_False;
CallCallBackHdl_Impl();
return 1;
}
IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, ReturnHdl_Impl)
IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, EscapeHdl_Impl)
{
DBG_CHKTHIS(SvInplaceEdit2,0);
bCanceled = sal_True;
CallCallBackHdl_Impl();
return 1;
}
IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, EscapeHdl_Impl)
sal_Bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
{
DBG_CHKTHIS(SvInplaceEdit2,0);
KeyCode aCode = rKEvt.GetKeyCode();
sal_uInt16 nCode = aCode.GetCode();
switch ( nCode )
{
case KEY_ESCAPE:
bCanceled = sal_True;
CallCallBackHdl_Impl();
return sal_True;
case KEY_RETURN:
bCanceled = sal_False;
CallCallBackHdl_Impl();
return sal_True;
}
return sal_False;
}
void SvInplaceEdit2::StopEditing( sal_Bool bCancel )
{
DBG_CHKTHIS(SvInplaceEdit2,0);
if ( !bAlreadyInCallBack )
{
bCanceled = bCancel;
CallCallBackHdl_Impl();
}
}
void SvInplaceEdit2::LoseFocus()
{
DBG_CHKTHIS(SvInplaceEdit2,0);
if ( !bAlreadyInCallBack
&& ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) )
)
{
bCanceled = sal_False;
aTimer.SetTimeout(10);
aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit2,Timeout_Impl));
aTimer.Start();
}
}
IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, Timeout_Impl)
{
DBG_CHKTHIS(SvInplaceEdit2,0);
CallCallBackHdl_Impl();
return 0;
}
IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, Timeout_Impl)
void SvInplaceEdit2::CallCallBackHdl_Impl()
{
DBG_CHKTHIS(SvInplaceEdit2,0);
aTimer.Stop();
if ( !bAlreadyInCallBack )
{
bAlreadyInCallBack = sal_True;
GetpApp()->RemoveAccel( &aAccReturn );
GetpApp()->RemoveAccel( &aAccEscape );
pEdit->Hide();
aCallBackHdl.Call( this );
}
}
OUString 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, sal_uInt16 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 )
{
// correct implementation of centering
nOffset = ( nTabWidth - nItemWidth ) / 2;
if( nOffset < 0 )
nOffset = 0;
}
else
{
// historically grown, wrong calculation of tabs which is needed by
// Abo-Tabbox, Tools/Options/Customize etc.
nItemWidth++;
nOffset = -( nItemWidth / 2 );
}
}
return nOffset;
}
// ***************************************************************
// class SvLBoxItem
// ***************************************************************
DBG_NAME(SvLBoxItem);
SvLBoxItem::SvLBoxItem( SvTreeListEntry*, sal_uInt16 )
{
DBG_CTOR(SvLBoxItem,0);
}
SvLBoxItem::SvLBoxItem()
{
DBG_CTOR(SvLBoxItem,0);
}
SvLBoxItem::~SvLBoxItem()
{
DBG_DTOR(SvLBoxItem,0);
}
const Size& SvLBoxItem::GetSize(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
{
DBG_CHKTHIS(SvLBoxItem,0);
const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
return pViewData->maSize;
}
const Size& SvLBoxItem::GetSize(const SvViewDataEntry* pData, sal_uInt16 nItemPos) const
{
const SvViewDataItem* pIData = pData->GetItem(nItemPos);
return pIData->maSize;
}
struct SvTreeListBoxImpl
{
bool m_bIsEmptyTextAllowed:1;
bool m_bEntryMnemonicsEnabled:1;
bool m_bDoingQuickSelection:1;
Link* m_pLink;
vcl::MnemonicEngine m_aMnemonicEngine;
vcl::QuickSelectionEngine m_aQuickSelectionEngine;
SvTreeListBoxImpl(SvTreeListBox& _rBox) :
m_bIsEmptyTextAllowed(true),
m_bEntryMnemonicsEnabled(false),
m_bDoingQuickSelection(false),
m_pLink(NULL),
m_aMnemonicEngine(_rBox),
m_aQuickSelectionEngine(_rBox) {}
};
DBG_NAME(SvTreeListBox);
SvTreeListBox::SvTreeListBox(Window* pParent, WinBits nWinStyle) :
Control(pParent, nWinStyle | WB_CLIPCHILDREN),
DropTargetHelper(this),
DragSourceHelper(this),
mpImpl(new SvTreeListBoxImpl(*this)),
mbContextBmpExpanded(false),
eSelMode(NO_SELECTION),
nMinWidthInChars(0)
{
DBG_CTOR(SvTreeListBox,0);
nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
nImpFlags = 0;
pTargetEntry = 0;
nDragDropMode = 0;
SvTreeList* pTempModel = new SvTreeList;
pTempModel->SetRefCount( 0 );
SetBaseModel(pTempModel);
pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
pModel->InsertView( this );
pHdlEntry = 0;
pEdCtrl = 0;
eSelMode = SINGLE_SELECTION;
nDragDropMode = SV_DRAGDROP_NONE;
SetType(WINDOW_TREELISTBOX);
InitTreeView();
SetSublistOpenWithLeftRight();
}
SvTreeListBox::SvTreeListBox(Window* pParent, const ResId& rResId) :
Control(pParent, rResId),
DropTargetHelper(this),
DragSourceHelper(this),
mpImpl(new SvTreeListBoxImpl(*this)),
mbContextBmpExpanded(false),
eSelMode(NO_SELECTION),
nMinWidthInChars(0)
{
DBG_CTOR(SvTreeListBox,0);
pTargetEntry = 0;
nImpFlags = 0;
nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
nDragDropMode = 0;
SvTreeList* pTempModel = new SvTreeList;
pTempModel->SetRefCount( 0 );
SetBaseModel(pTempModel);
pModel->InsertView( this );
pHdlEntry = 0;
pEdCtrl = 0;
pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
SetType(WINDOW_TREELISTBOX);
InitTreeView();
Resize();
SetSublistOpenWithLeftRight();
}
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSvTreeListBox(Window *pParent, VclBuilder::stringmap &rMap)
{
WinBits nWinStyle = WB_TABSTOP;
OString sBorder = VclBuilder::extractCustomProperty(rMap);
if (!sBorder.isEmpty())
nWinStyle |= WB_BORDER;
return new SvTreeListBox(pParent, nWinStyle);
}
void SvTreeListBox::Clear()
{
DBG_CHKTHIS(SvTreeListBox,0);
pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
}
void SvTreeListBox::EnableEntryMnemonics( bool _bEnable )
{
if ( _bEnable == IsEntryMnemonicsEnabled() )
return;
mpImpl->m_bEntryMnemonicsEnabled = _bEnable;
Invalidate();
}
bool SvTreeListBox::IsEntryMnemonicsEnabled() const
{
return mpImpl->m_bEntryMnemonicsEnabled;
}
IMPL_LINK_INLINE_START( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
return (sal_IntPtr)(CloneEntry((SvTreeListEntry*)pEntry));
}
IMPL_LINK_INLINE_END( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
return nInsPos;
}
sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
return nInsPos;
}
bool SvTreeListBox::ExpandingHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
return !aExpandingHdl.IsSet() || aExpandingHdl.Call( this );
}
void SvTreeListBox::ExpandedHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
aExpandedHdl.Call( this );
}
void SvTreeListBox::SelectHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
aSelectHdl.Call( this );
}
void SvTreeListBox::DeselectHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
aDeselectHdl.Call( this );
}
sal_Bool SvTreeListBox::DoubleClickHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
aDoubleClickHdl.Call( this );
return sal_True;
}
sal_Bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox* pSource, sal_Int8 nAction )
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( pSource == this )
{
if ( !(nDragDropMode & (SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY) ) )
return sal_False; // D&D locked within list
if( DND_ACTION_MOVE == nAction )
{
if ( !(nDragDropMode & SV_DRAGDROP_CTRL_MOVE) )
return sal_False; // no local move
}
else
{
if ( !(nDragDropMode & SV_DRAGDROP_CTRL_COPY))
return sal_False; // no local copy
}
}
else
{
if ( !(nDragDropMode & SV_DRAGDROP_APP_DROP ) )
return sal_False; // no drop
if ( DND_ACTION_MOVE == nAction )
{
if ( !(nDragDropMode & SV_DRAGDROP_APP_MOVE) )
return sal_False; // no global move
}
else
{
if ( !(nDragDropMode & SV_DRAGDROP_APP_COPY))
return sal_False; // no global copy
}
}
return sal_True;
}
void SvTreeListBox::NotifyRemoving( SvTreeListEntry* )
{
DBG_CHKTHIS(SvTreeListBox,0);
}
/*
NotifyMoving/Copying
====================
default behavior:
1. target doesn't have children
- entry becomes sibling of target. entry comes after target
(->Window: below the target)
2. target is an expanded parent
- entry inserted at the beginning of the target childlist
3. target is a collapsed parent
- entry is inserted at the end of the target childlist
*/
#ifdef DBG_UTIL
sal_Bool SvTreeListBox::NotifyMoving(
SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
SvTreeListEntry* pEntry, // entry that we want to move, from
// GetSourceListBox()->GetModel()
SvTreeListEntry*& rpNewParent, // new target parent
sal_uLong& rNewChildPos) // position in childlist of target parent
#else
sal_Bool SvTreeListBox::NotifyMoving(
SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
SvTreeListEntry*, // entry that we want to move, from
// GetSourceListBox()->GetModel()
SvTreeListEntry*& rpNewParent, // new target parent
sal_uLong& rNewChildPos) // position in childlist of target parent
#endif
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?");
if( !pTarget )
{
rpNewParent = 0;
rNewChildPos = 0;
return sal_True;
}
if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
{
// case 1
rpNewParent = GetParent( pTarget );
rNewChildPos = pModel->GetRelPos( pTarget ) + 1;
rNewChildPos += nCurEntrySelPos;
nCurEntrySelPos++;
}
else
{
// cases 2 & 3
rpNewParent = pTarget;
if( IsExpanded(pTarget))
rNewChildPos = 0;
else
rNewChildPos = LIST_APPEND;
}
return sal_True;
}
sal_Bool SvTreeListBox::NotifyCopying(
SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
SvTreeListEntry* pEntry, // entry that we want to move, from
// GetSourceListBox()->GetModel()
SvTreeListEntry*& rpNewParent, // new target parent
sal_uLong& rNewChildPos) // position in childlist of target parent
{
DBG_CHKTHIS(SvTreeListBox,0);
return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
}
SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
{
return pModel->FirstChild(pParent);
}
SvTreeListEntry* SvTreeListBox::NextSibling( SvTreeListEntry* pEntry ) const
{
return pModel->NextSibling(pEntry);
}
SvTreeListEntry* SvTreeListBox::PrevSibling( SvTreeListEntry* pEntry ) const
{
return pModel->PrevSibling(pEntry);
}
// return: all entries copied
sal_Bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
{
DBG_CHKTHIS(SvTreeListBox,0);
nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
sal_Bool bSuccess = sal_True;
std::vector<SvTreeListEntry*> aList;
sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
Link aCloneLink( pModel->GetCloneLink() );
pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
// cache selection to simplify iterating over the selection when doing a D&D
// exchange within the same listbox
SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
while ( pSourceEntry )
{
// children are copied automatically
pSource->SelectChildren( pSourceEntry, sal_False );
aList.push_back( pSourceEntry );
pSourceEntry = pSource->NextSelected( pSourceEntry );
}
std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
for (; it != itEnd; ++it)
{
pSourceEntry = *it;
SvTreeListEntry* pNewParent = 0;
sal_uLong nInsertionPos = ULONG_MAX;
sal_Bool bOk=NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
if ( bOk )
{
if ( bClone )
{
sal_uLong nCloneCount = 0;
pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
}
else
{
sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
pSourceEntry = GetEntry( pNewParent, nListPos );
}
}
else
bSuccess = sal_False;
if( bOk == (sal_Bool)2 ) // HACK: make visible moved entry?
MakeVisible( pSourceEntry );
}
pModel->SetCloneLink( aCloneLink );
return bSuccess;
}
// return: all entries were moved
sal_Bool SvTreeListBox::MoveSelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
{
return MoveSelectionCopyFallbackPossible( pSource, pTarget, sal_False );
}
sal_Bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, sal_Bool bAllowCopyFallback )
{
DBG_CHKTHIS(SvTreeListBox,0);
nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
sal_Bool bSuccess = sal_True;
std::vector<SvTreeListEntry*> aList;
sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
Link aCloneLink( pModel->GetCloneLink() );
if ( bClone )
pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
while ( pSourceEntry )
{
// children are automatically moved
pSource->SelectChildren( pSourceEntry, sal_False );
aList.push_back( pSourceEntry );
pSourceEntry = pSource->NextSelected( pSourceEntry );
}
std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
for (; it != itEnd; ++it)
{
pSourceEntry = *it;
SvTreeListEntry* pNewParent = 0;
sal_uLong nInsertionPos = ULONG_MAX;
sal_Bool bOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
sal_Bool bCopyOk = bOk;
if ( !bOk && bAllowCopyFallback )
{
nInsertionPos = LIST_APPEND;
bCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
}
if ( bOk || bCopyOk )
{
if ( bClone )
{
sal_uLong nCloneCount = 0;
pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
}
else
{
if ( bOk )
pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
else
pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
}
}
else
bSuccess = sal_False;
if( bOk == (sal_Bool)2 ) // HACK: make moved entry visible?
MakeVisible( pSourceEntry );
}
pModel->SetCloneLink( aCloneLink );
return bSuccess;
}
void SvTreeListBox::RemoveSelection()
{
DBG_CHKTHIS(SvTreeListBox,0);
std::vector<const SvTreeListEntry*> aList;
// cache selection, as the implementation deselects everything on the first
// remove
SvTreeListEntry* pEntry = FirstSelected();
while ( pEntry )
{
aList.push_back( pEntry );
if ( pEntry->HasChildren() )
// remove deletes all children automatically
SelectChildren(pEntry, false);
pEntry = NextSelected( pEntry );
}
std::vector<const SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
for (; it != itEnd; ++it)
pModel->Remove(*it);
}
SvTreeListBox* SvTreeListBox::GetSourceView() const
{
return pDDSource;
}
void SvTreeListBox::RecalcViewData()
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeListEntry* pEntry = First();
while( pEntry )
{
sal_uInt16 nCount = pEntry->ItemCount();
sal_uInt16 nCurPos = 0;
while ( nCurPos < nCount )
{
SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
pItem->InitViewData( this, pEntry );
nCurPos++;
}
ViewDataInitialized( pEntry );
pEntry = Next( pEntry );
}
}
void SvTreeListBox::ViewDataInitialized( SvTreeListEntry* )
{
DBG_CHKTHIS(SvTreeListBox,0);
}
void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, sal_Bool bShow)
{
DBG_CHKTHIS(SvTreeListBox,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 SvTreeListBox::OnCurrentEntryChanged()
{
if ( !mpImpl->m_bDoingQuickSelection )
mpImpl->m_aQuickSelectionEngine.Reset();
}
SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
{
return pModel->GetEntry(pParent, nPos);
}
SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
{
return pModel->GetEntry(nRootPos);
}
SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeListEntry* pEntry = NULL;
SvTreeListEntry* pParent = NULL;
for( ::std::deque< sal_Int32 >::const_iterator pItem = _rPath.begin(); pItem != _rPath.end(); ++pItem )
{
pEntry = GetEntry( pParent, *pItem );
if ( !pEntry )
break;
pParent = pEntry;
}
return pEntry;
}
void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( pEntry )
{
SvTreeListEntry* pParentEntry = GetParent( pEntry );
while ( true )
{
sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
for ( i = 0; i < nCount; ++i )
{
SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
DBG_ASSERT( pEntry, "invalid entry" );
if ( pEntry == pTemp )
{
_rPath.push_front( (sal_Int32)i );
break;
}
}
if ( pParentEntry )
{
pEntry = pParentEntry;
pParentEntry = GetParent( pParentEntry );
}
else
break;
}
}
}
const SvTreeListEntry* SvTreeListBox::GetParent( const SvTreeListEntry* pEntry ) const
{
return pModel->GetParent(pEntry);
}
SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
{
return pModel->GetParent(pEntry);
}
SvTreeListEntry* SvTreeListBox::GetRootLevelParent( SvTreeListEntry* pEntry ) const
{
return pModel->GetRootLevelParent(pEntry);
}
sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry* pParent ) const
{
return pModel->GetChildCount(pParent);
}
sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
//if _pParent is 0, then pEntry is the first child of the root.
SvTreeListEntry* pEntry = FirstChild( _pParent );
if( !pEntry )//there is only root, root don't have children
return 0;
if( !_pParent )//root and children of root
return pEntry->pParent->maChildren.size();
return _pParent->maChildren.size();
}
SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry* pEntry ) const
{
return (SvViewDataEntry*)SvListView::GetViewData(pEntry);
}
SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry* pEntry, SvLBoxItem* pItem)
{
return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
}
const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
{
const SvViewDataEntry* pEntryData = (const SvViewDataEntry*)SvListView::GetViewData(pEntry);
DBG_ASSERT(pEntryData,"Entry not in View");
sal_uInt16 nItemPos = pEntry->GetPos(pItem);
return pEntryData->GetItem(nItemPos);
}
SvViewDataEntry* SvTreeListBox::CreateViewData( SvTreeListEntry* )
{
DBG_CHKTHIS(SvTreeListBox,0);
SvViewDataEntry* pEntryData = new SvViewDataEntry;
return (SvViewDataEntry*)pEntryData;
}
void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeListEntry* pInhEntry = (SvTreeListEntry*)pEntry;
SvViewDataEntry* pEntryData = (SvViewDataEntry*)pData;
pEntryData->Init(pInhEntry->ItemCount());
sal_uInt16 nCount = pInhEntry->ItemCount();
sal_uInt16 nCurPos = 0;
while( nCurPos < nCount )
{
SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos );
SvViewDataItem* pItemData = pEntryData->GetItem(nCurPos);
pItem->InitViewData( this, pInhEntry, pItemData );
pItemData++;
nCurPos++;
}
}
void SvTreeListBox::EnableSelectionAsDropTarget( sal_Bool bEnable, sal_Bool bWithChildren )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nRefDepth;
SvTreeListEntry* pTemp;
SvTreeListEntry* pSelEntry = FirstSelected();
while( pSelEntry )
{
if ( !bEnable )
{
pSelEntry->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP;
if ( bWithChildren )
{
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 ( bWithChildren )
{
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 );
}
}
// ******************************************************************
// InplaceEditing
// ******************************************************************
void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
const Selection& rSel )
{
EditText( rStr, rRect, rSel, sal_False );
}
void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
const Selection& rSel, sal_Bool bMulti )
{
DBG_CHKTHIS(SvTreeListBox,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, SvTreeListBox, TextEditEndedHdl_Impl ),
rSel, bMulti );
}
IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl)
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( nImpFlags & SVLBOX_EDTEND_CALLED ) // avoid nesting
return 0;
nImpFlags |= SVLBOX_EDTEND_CALLED;
OUString aStr;
if ( !pEdCtrl->EditingCanceled() )
aStr = pEdCtrl->GetText();
else
aStr = pEdCtrl->GetSavedValue();
if ( IsEmptyTextAllowed() || !aStr.isEmpty() )
EditedText( aStr );
// Hide may only be called after the new text was put into the entry, so
// that we don't call the selection handler in the GetFocus of the listbox
// with the old entry text.
pEdCtrl->Hide();
// delete pEdCtrl;
// pEdCtrl = 0;
nImpFlags &= (~SVLBOX_IN_EDT);
GrabFocus();
return 0;
}
void SvTreeListBox::CancelTextEditing()
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( pEdCtrl )
pEdCtrl->StopEditing( sal_True );
nImpFlags &= (~SVLBOX_IN_EDT);
}
void SvTreeListBox::EndEditing( bool bCancel )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( pEdCtrl )
pEdCtrl->StopEditing( bCancel );
nImpFlags &= (~SVLBOX_IN_EDT);
}
bool SvTreeListBox::IsEmptyTextAllowed() const
{
DBG_CHKTHIS(SvTreeListBox,0);
return mpImpl->m_bIsEmptyTextAllowed;
}
void SvTreeListBox::ForbidEmptyText()
{
DBG_CHKTHIS(SvTreeListBox,0);
mpImpl->m_bIsEmptyTextAllowed = false;
}
SvTreeListEntry* SvTreeListBox::CreateEntry() const
{
DBG_CHKTHIS(SvTreeListBox,0);
return new SvTreeListEntry;
}
const void* SvTreeListBox::FirstSearchEntry( OUString& _rEntryText ) const
{
SvTreeListEntry* pEntry = GetCurEntry();
if ( pEntry )
pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) );
else
{
pEntry = FirstSelected();
if ( !pEntry )
pEntry = First();
}
if ( pEntry )
_rEntryText = GetEntryText( pEntry );
return pEntry;
}
const void* SvTreeListBox::NextSearchEntry( const void* _pCurrentSearchEntry, OUString& _rEntryText ) const
{
SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
if ( ( ( GetChildCount( pEntry ) > 0 )
|| ( pEntry->HasChildrenOnDemand() )
)
&& !IsExpanded( pEntry )
)
{
pEntry = NextSibling( pEntry );
}
else
{
pEntry = Next( pEntry );
}
if ( !pEntry )
pEntry = First();
if ( pEntry )
_rEntryText = GetEntryText( pEntry );
return pEntry;
}
void SvTreeListBox::SelectSearchEntry( const void* _pEntry )
{
SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
if ( !pEntry )
return;
SelectAll( sal_False );
SetCurEntry( pEntry );
Select( pEntry );
}
void SvTreeListBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const
{
// nothing to do here, we have no "execution"
}
::vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
{
// always accept the current entry if there is one
SvTreeListEntry* pCurrentEntry( GetCurEntry() );
if ( pCurrentEntry )
{
_out_entryText = GetEntryText( pCurrentEntry );
return pCurrentEntry;
}
return FirstSearchEntry( _out_entryText );
}
::vcl::StringEntryIdentifier SvTreeListBox::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
{
return NextSearchEntry( _currentEntry, _out_entryText );
}
void SvTreeListBox::SelectEntry( ::vcl::StringEntryIdentifier _entry )
{
SelectSearchEntry( _entry );
}
bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
{
if ( IsEntryMnemonicsEnabled()
&& mpImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt )
)
return true;
if ( ( GetStyle() & WB_QUICK_SEARCH ) != 0 )
{
mpImpl->m_bDoingQuickSelection = true;
const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
mpImpl->m_bDoingQuickSelection = false;
if ( bHandled )
return true;
}
return false;
}
void SvTreeListBox::WriteDragServerInfo( const Point&, SvLBoxDDInfo* )
{
DBG_CHKTHIS(SvTreeListBox,0);
}
void SvTreeListBox::ReadDragServerInfo(const Point&, SvLBoxDDInfo* )
{
DBG_CHKTHIS(SvTreeListBox,0);
}
sal_Bool SvTreeListBox::EditingCanceled() const
{
if( pEdCtrl && pEdCtrl->EditingCanceled() )
return sal_True;
return sal_False;
}
//JP 28.3.2001: new Drag & Drop API
sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_Int8 nRet = DND_ACTION_NONE;
if( rEvt.mbLeaving || !CheckDragAndDropMode( pDDSource, rEvt.mnAction ) )
{
ImplShowTargetEmphasis( pTargetEntry, sal_False );
}
else if( !nDragDropMode )
{
SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" );
}
else
{
SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
if( !IsDropFormatSupported( SOT_FORMATSTR_ID_TREELISTBOX ) )
{
SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" );
}
else
{
DBG_ASSERT( pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0" );
if( !( pEntry && pDDSource->GetModel() == this->GetModel()
&& DND_ACTION_MOVE == rEvt.mnAction
&& ( pEntry->nEntryFlags & SV_ENTRYFLAG_DISABLE_DROP ) ))
{
if( NotifyAcceptDrop( pEntry ))
nRet = rEvt.mnAction;
}
}
// **** draw emphasis ****
if( DND_ACTION_NONE == nRet )
ImplShowTargetEmphasis( pTargetEntry, sal_False );
else if( pEntry != pTargetEntry || !(nImpFlags & SVLBOX_TARGEMPH_VIS) )
{
ImplShowTargetEmphasis( pTargetEntry, sal_False );
pTargetEntry = pEntry;
ImplShowTargetEmphasis( pTargetEntry, sal_True );
}
}
return nRet;
}
sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_Int8 nRet = DND_ACTION_NONE;
DBG_ASSERT( pSourceView, "SvTreeListBox::ExecuteDrop(): no source view" );
pSourceView->EnableSelectionAsDropTarget( sal_True, sal_True );
ImplShowTargetEmphasis( pTargetEntry, sal_False );
pDDTarget = this;
SvLBoxDDInfo aDDInfo;
TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
if( aData.HasFormat( SOT_FORMATSTR_ID_TREELISTBOX ))
{
::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
if( aData.GetSequence( SOT_FORMATSTR_ID_TREELISTBOX, aSeq ) &&
sizeof(SvLBoxDDInfo) == aSeq.getLength() )
{
memcpy( &aDDInfo, aSeq.getConstArray(), sizeof(SvLBoxDDInfo) );
nRet = rEvt.mnAction;
}
}
if( DND_ACTION_NONE != nRet )
{
nRet = DND_ACTION_NONE;
ReadDragServerInfo( rEvt.maPosPixel, &aDDInfo );
SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
if( DND_ACTION_COPY == rEvt.mnAction )
{
if ( CopySelection( aDDInfo.pSource, pTarget ) )
nRet = rEvt.mnAction;
}
else if( DND_ACTION_MOVE == rEvt.mnAction )
{
if ( MoveSelection( aDDInfo.pSource, pTarget ) )
nRet = rEvt.mnAction;
}
else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
{
if ( MoveSelectionCopyFallbackPossible( aDDInfo.pSource, pTarget, sal_True ) )
nRet = rEvt.mnAction;
}
}
return nRet;
}
sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
return ExecuteDrop( rEvt, GetSourceView() );
}
void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
{
DBG_CHKTHIS(SvTreeListBox,0);
Point aEventPos( rPosPixel );
MouseEvent aMouseEvt( aEventPos, 1, MOUSE_SELECT, MOUSE_LEFT );
MouseButtonUp( aMouseEvt );
nOldDragMode = GetDragDropMode();
if ( !nOldDragMode )
return;
ReleaseMouse();
SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
if( !pEntry )
{
DragFinished( DND_ACTION_NONE );
return;
}
TransferDataContainer* pContainer = new TransferDataContainer;
::com::sun::star::uno::Reference<
::com::sun::star::datatransfer::XTransferable > xRef( pContainer );
nDragDropMode = NotifyStartDrag( *pContainer, pEntry );
if( !nDragDropMode || 0 == GetSelectionCount() )
{
nDragDropMode = nOldDragMode;
DragFinished( DND_ACTION_NONE );
return;
}
SvLBoxDDInfo aDDInfo;
memset(&aDDInfo,0,sizeof(SvLBoxDDInfo));
aDDInfo.pApp = GetpApp();
aDDInfo.pSource = this;
aDDInfo.pDDStartEntry = pEntry;
// let derived views do their thing
WriteDragServerInfo( rPosPixel, &aDDInfo );
pContainer->CopyAnyData( SOT_FORMATSTR_ID_TREELISTBOX,
(sal_Char*)&aDDInfo, sizeof(SvLBoxDDInfo) );
pDDSource = this;
pDDTarget = 0;
sal_Bool bOldUpdateMode = Control::IsUpdateMode();
Control::SetUpdateMode( sal_True );
Update();
Control::SetUpdateMode( bOldUpdateMode );
// Disallow using the selection and its children as drop targets.
// Important: If the selection of the SourceListBox is changed in the
// DropHandler, the entries have to be allowed as drop targets again:
// (GetSourceListBox()->EnableSelectionAsDropTarget( sal_True, sal_True );)
EnableSelectionAsDropTarget( sal_False, sal_True /* with children */ );
pContainer->StartDrag( this, nDragOptions, GetDragFinishedHdl() );
}
void SvTreeListBox::DragFinished( sal_Int8
#ifndef UNX
nAction
#endif
)
{
EnableSelectionAsDropTarget( sal_True, sal_True );
#ifndef UNX
if( (nAction == DND_ACTION_MOVE) && ( (pDDTarget &&
((sal_uLong)(pDDTarget->GetModel())!=(sal_uLong)(this->GetModel()))) ||
!pDDTarget ))
{
RemoveSelection();
}
#endif
ImplShowTargetEmphasis( pTargetEntry, sal_False );
pDDSource = 0;
pDDTarget = 0;
pTargetEntry = 0;
nDragDropMode = nOldDragMode;
}
DragDropMode SvTreeListBox::NotifyStartDrag( TransferDataContainer&, SvTreeListEntry* )
{
DBG_CHKTHIS(SvTreeListBox,0);
return (DragDropMode)0xffff;
}
sal_Bool SvTreeListBox::NotifyAcceptDrop( SvTreeListEntry* )
{
DBG_CHKTHIS(SvTreeListBox,0);
return sal_True;
}
// Handler and methods for Drag - finished handler.
// The with get GetDragFinishedHdl() get link can set on the
// TransferDataContainer. This link is a callback for the DragFinished
// call. AddBox method is called from the GetDragFinishedHdl() and the
// remove is called in link callback and in the destructor. So it can't
// called to a deleted object.
namespace
{
struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
}
void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
{
sal_uLong nVal = (sal_uLong)&rB;
SortLBoxes::get().insert( nVal );
}
void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
{
sal_uLong nVal = (sal_uLong)&rB;
SortLBoxes::get().erase( nVal );
}
IMPL_STATIC_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8*, pAction )
{
sal_uLong nVal = (sal_uLong)pThis;
std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
if( it != rSortLBoxes.end() )
{
pThis->DragFinished( *pAction );
rSortLBoxes.erase( it );
}
return 0;
}
Link SvTreeListBox::GetDragFinishedHdl() const
{
AddBoxToDDList_Impl( *this );
return STATIC_LINK( this, SvTreeListBox, DragFinishHdl_Impl );
}
/*
Bugs/TODO
- calculate rectangle when editing in-place (bug with some fonts)
- SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
*/
#define TREEFLAG_FIXEDHEIGHT 0x0010
#define SV_LBOX_DEFAULT_INDENT_PIXEL 20
void SvTreeListBox::InitTreeView()
{
DBG_CHKTHIS(SvTreeListBox,0);
pCheckButtonData = NULL;
pEdEntry = NULL;
pEdItem = NULL;
nEntryHeight = 0;
pEdCtrl = NULL;
nFirstSelTab = 0;
nLastSelTab = 0;
nFocusWidth = -1;
nAllItemAccRoleType = 0;
mnCheckboxItemWidth = 0;
Link* pLink = new Link( LINK(this,SvTreeListBox, DefaultCompare) );
mpImpl->m_pLink = pLink;
nTreeFlags = TREEFLAG_RECALCTABS;
nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
pImp = new SvImpLBox( this, GetModel(), GetStyle() );
mbContextBmpExpanded = true;
nContextBmpWidthMax = 0;
SetFont( GetFont() );
AdjustEntryHeightAndRecalc( GetFont() );
SetSpaceBetweenEntries( 0 );
SetLineColor();
InitSettings( sal_True, sal_True, sal_True );
ImplInitStyle();
SetTabs();
}
OUString SvTreeListBox::GetEntryAltText( SvTreeListEntry* ) const
{
return OUString();
}
OUString SvTreeListBox::GetEntryLongDescription( SvTreeListEntry* ) const
{
return OUString();
}
OUString SvTreeListBox::SearchEntryTextWithHeadTitle( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" );
OUString sRet;
sal_uInt16 nCount = pEntry->ItemCount();
sal_uInt16 nCur = 0;
sal_uInt16 nHeaderCur = 0;
SvLBoxItem* pItem;
while( nCur < nCount )
{
// MT: SV_ITEM_ID_EXTENDRLBOXSTRING / GetExtendText() was in use in IA2 cws, but only used in sc: ScSolverOptionsString. Needed?
pItem = pEntry->GetItem( nCur );
if ( (pItem->GetType() == SV_ITEM_ID_LBOXSTRING ) &&
!static_cast<SvLBoxString*>( pItem )->GetText().isEmpty() )
{
//want the column header
if (!headString.isEmpty())
{
sal_Int32 nEnd = headString.indexOf('\t');
if( nEnd == -1 )
{
if (!sRet.isEmpty())
{
sRet += ",";
}
if (!headString.isEmpty())
{
sRet += headString ;
sRet += ":" ;
}
}
else
{
OUString aString=headString.getToken(nHeaderCur, '\t');
if (!sRet.isEmpty())
{
sRet += ",";
}
if (!aString.isEmpty())
{
sRet += aString ;
sRet += ":" ;
}
nHeaderCur++;
}
sRet += static_cast<SvLBoxString*>( pItem )->GetText();
}
else
{
sRet += static_cast<SvLBoxString*>( pItem )->GetText();
sRet += ",";
}
//end want to the column header
}
nCur++;
}
if (!sRet.isEmpty())
sRet = sRet.copy(0, sRet.getLength() - 1);
return sRet;
}
SvTreeListBox::~SvTreeListBox()
{
DBG_DTOR(SvTreeListBox,0);
pImp->CallEventListeners( VCLEVENT_OBJECT_DYING );
delete pImp;
delete mpImpl->m_pLink;
ClearTabList();
delete pEdCtrl;
pEdCtrl = 0;
pModel->RemoveView( this );
if ( pModel->GetRefCount() == 0 )
{
pModel->Clear();
delete pModel;
pModel = NULL;
}
SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
if( this == pDDSource )
pDDSource = 0;
if( this == pDDTarget )
pDDTarget = 0;
delete mpImpl;
}
void SvTreeListBox::SetExtendedWinBits( ExtendedWinBits _nBits )
{
pImp->SetExtendedWindowBits( _nBits );
}
void SvTreeListBox::SetModel( SvTreeList* pNewModel )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->SetModel( pNewModel );
SetBaseModel(pNewModel);
}
void SvTreeListBox::SetBaseModel( SvTreeList* pNewModel )
{
// does the CleanUp
SvListView::SetModel( pNewModel );
pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
SvTreeListEntry* pEntry = First();
while( pEntry )
{
ModelHasInserted( pEntry );
pEntry = Next( pEntry );
}
}
void SvTreeListBox::DisconnectFromModel()
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeList* pNewModel = new SvTreeList;
pNewModel->SetRefCount( 0 ); // else this will never be deleted
SvListView::SetModel( pNewModel );
pImp->SetModel( GetModel() );
}
void SvTreeListBox::SetSublistOpenWithReturn( sal_Bool b )
{
pImp->bSubLstOpRet = b;
}
void SvTreeListBox::SetSublistOpenWithLeftRight( sal_Bool b )
{
pImp->bSubLstOpLR = b;
}
void SvTreeListBox::Resize()
{
DBG_CHKTHIS(SvTreeListBox,0);
if( IsEditingActive() )
EndEditing( sal_True );
Control::Resize();
pImp->Resize();
nFocusWidth = -1;
pImp->ShowCursor( sal_False );
pImp->ShowCursor( sal_True );
}
/* Cases:
A) entries have bitmaps
0. no buttons
1. node buttons (can optionally also be on root items)
2. node buttons (can optionally also be on root items) + CheckButton
3. CheckButton
B) entries don't have bitmaps (=>via WindowBits because of D&D!)
0. no buttons
1. node buttons (can optionally also be on root items)
2. node buttons (can optionally also be on 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
// take care of GetTextOffset when doing changes
void SvTreeListBox::SetTabs()
{
DBG_CHKTHIS(SvTreeListBox,0);
if( IsEditingActive() )
EndEditing( sal_True );
nTreeFlags &= (~TREEFLAG_RECALCTABS);
nFocusWidth = -1;
const WinBits nStyle( GetStyle() );
sal_Bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
sal_Bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
WB_HASBUTTONSATROOT))!=0;
long nStartPos = TAB_STARTPOS;
long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
// pCheckButtonData->Width() knows nothing about the native checkbox width,
// so we have mnCheckboxItemWidth which becomes valid when something is added.
long nCheckWidth = 0;
if( nTreeFlags & TREEFLAG_CHKBTN )
nCheckWidth = mnCheckboxItemWidth;
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; // because of centering
AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
nStartPos += nContextWidthDIV2; // right edge of context bitmap
// only set a distance if there are bitmaps
if( nContextBmpWidthMax )
nStartPos += 5; // distance context bitmap to text
AddTab( nStartPos, TABFLAGS_TEXT );
break;
case NODE_BUTTONS :
if( bHasButtonsAtRoot )
nStartPos += ( nIndent + (nNodeWidthPixel/2) );
else
nStartPos += nContextWidthDIV2;
AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
nStartPos += nContextWidthDIV2; // right edge of context bitmap
// only set a distance if there are bitmaps
if( nContextBmpWidthMax )
nStartPos += 5; // distance context bitmap to 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; // right edge of CheckButton
nStartPos += 3; // distance CheckButton to context bitmap
nStartPos += nContextWidthDIV2; // center of context bitmap
AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
nStartPos += nContextWidthDIV2; // right edge of context bitmap
// only set a distance if there are bitmaps
if( nContextBmpWidthMax )
nStartPos += 5; // distance context bitmap to text
AddTab( nStartPos, TABFLAGS_TEXT );
break;
case CHECK_BUTTONS :
nStartPos += nCheckWidthDIV2;
AddTab( nStartPos, TABFLAGS_CHECKBTN );
nStartPos += nCheckWidthDIV2; // right edge of CheckButton
nStartPos += 3; // distance CheckButton to context bitmap
nStartPos += nContextWidthDIV2; // center of context bitmap
AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
nStartPos += nContextWidthDIV2; // right edge of context bitmap
// only set a distance if there are bitmaps
if( nContextBmpWidthMax )
nStartPos += 5; // distance context bitmap to text
AddTab( nStartPos, TABFLAGS_TEXT );
break;
}
pImp->NotifyTabsChanged();
}
void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp,
SvLBoxButtonKind eButtonKind)
{
DBG_CHKTHIS(SvTreeListBox,0);
SvLBoxButton* pButton;
SvLBoxString* pString;
SvLBoxContextBmp* pContextBmp;
if( nTreeFlags & TREEFLAG_CHKBTN )
{
pButton= new SvLBoxButton( pEntry,eButtonKind,0,pCheckButtonData );
pEntry->AddItem( pButton );
}
pContextBmp= new SvLBoxContextBmp(
pEntry,0, aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded);
pEntry->AddItem( pContextBmp );
pString = new SvLBoxString( pEntry, 0, aStr );
pEntry->AddItem( pString );
}
OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): no entry" );
SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): item not found" );
return pItem->GetText();
}
OUString SvTreeListBox::SearchEntryText( SvTreeListEntry* pEntry ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" );
OUString sRet;
sal_uInt16 nCount = pEntry->ItemCount();
sal_uInt16 nCur = 0;
SvLBoxItem* pItem;
while( nCur < nCount )
{
pItem = pEntry->GetItem( nCur );
if (pItem->GetType() == SV_ITEM_ID_LBOXSTRING && !static_cast<const SvLBoxString*>(pItem)->GetText().isEmpty())
{
sRet = static_cast<const SvLBoxString*>(pItem)->GetText();
break;
}
nCur++;
}
return sRet;
}
const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry) const
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"Entry?");
const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
DBG_ASSERT(pItem,"GetContextBmp:Item not found");
return pItem->GetBitmap2( );
}
const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"Entry?");
const SvLBoxContextBmp* pItem = static_cast<const 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 )
SvTreeListEntry* SvTreeListBox::InsertEntry(
const OUString& rText,
SvTreeListEntry* pParent,
sal_Bool bChildrenOnDemand, sal_uLong nPos,
void* pUser,
SvLBoxButtonKind eButtonKind
)
{
DBG_CHKTHIS(SvTreeListBox,0);
nTreeFlags |= TREEFLAG_MANINS;
const Image& rDefExpBmp = pImp->GetDefaultEntryExpBmp( );
const Image& rDefColBmp = pImp->GetDefaultEntryColBmp( );
aCurInsertedExpBmp = rDefExpBmp;
aCurInsertedColBmp = rDefColBmp;
SvTreeListEntry* pEntry = CreateEntry();
pEntry->SetUserData( pUser );
InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp, eButtonKind );
pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
if( !pParent )
Insert( pEntry, nPos );
else
Insert( pEntry, pParent, nPos );
aPrevInsertedExpBmp = rDefExpBmp;
aPrevInsertedColBmp = rDefColBmp;
nTreeFlags &= (~TREEFLAG_MANINS);
return pEntry;
}
SvTreeListEntry* SvTreeListBox::InsertEntry( const OUString& rText,
const Image& aExpEntryBmp, const Image& aCollEntryBmp,
SvTreeListEntry* pParent, sal_Bool bChildrenOnDemand, sal_uLong nPos, void* pUser,
SvLBoxButtonKind eButtonKind )
{
DBG_CHKTHIS(SvTreeListBox,0);
nTreeFlags |= TREEFLAG_MANINS;
aCurInsertedExpBmp = aExpEntryBmp;
aCurInsertedColBmp = aCollEntryBmp;
SvTreeListEntry* pEntry = CreateEntry();
pEntry->SetUserData( pUser );
InitEntry( pEntry, rText, aCollEntryBmp, aExpEntryBmp, eButtonKind );
pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
if( !pParent )
Insert( pEntry, nPos );
else
Insert( pEntry, pParent, nPos );
aPrevInsertedExpBmp = aExpEntryBmp;
aPrevInsertedColBmp = aCollEntryBmp;
nTreeFlags &= (~TREEFLAG_MANINS);
return pEntry;
}
void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
{
DBG_CHKTHIS(SvTreeListBox,0);
SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
DBG_ASSERT(pItem,"SetText:Item not found");
pItem->SetText(rStr);
pItem->InitViewData( this, pEntry, 0 );
GetModel()->InvalidateEntry( pEntry );
}
void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* 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( aBmp );
GetModel()->InvalidateEntry( pEntry );
SetEntryHeight( pEntry );
Size aSize = aBmp.GetSizePixel();
short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
if( nWidth > nContextBmpWidthMax )
{
nContextBmpWidthMax = nWidth;
SetTabs();
}
}
void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* 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( aBmp );
GetModel()->InvalidateEntry( pEntry );
SetEntryHeight( pEntry );
Size aSize = aBmp.GetSizePixel();
short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
if( nWidth > nContextBmpWidthMax )
{
nContextBmpWidthMax = nWidth;
SetTabs();
}
}
void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeListEntry* pParent = (SvTreeListEntry*)pModel->GetParent( pEntry );
if( pParent )
{
sal_uInt16 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( (SvTreeListEntry*)pEntry );
if( nTreeFlags & TREEFLAG_CHKBTN )
{
SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
if( pItem )
{
long nWidth = pItem->GetSize(this, pEntry).Width();
if( mnCheckboxItemWidth < nWidth )
{
mnCheckboxItemWidth = nWidth;
nTreeFlags |= TREEFLAG_RECALCTABS;
}
}
}
}
void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
{
DBG_CHKTHIS(SvTreeListBox,0);
if( nTreeFlags & TREEFLAG_CHKBTN )
{
SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
if(!(pItem && pItem->CheckModification()))
return ;
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 );
}
}
void SvTreeListBox::SetCheckButtonInvisible( SvTreeListEntry* pEntry)
{
DBG_CHKTHIS(SvTreeListBox,0);
if( nTreeFlags & TREEFLAG_CHKBTN )
{
SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
pItem->SetStateInvisible();
InvalidateEntry( pEntry );
}
}
SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
SvButtonState eState = SV_BUTTON_UNCHECKED;
if( nTreeFlags & TREEFLAG_CHKBTN )
{
SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
if(!pItem)
return SV_BUTTON_TRISTATE;
sal_uInt16 nButtonFlags = pItem->GetButtonFlags();
eState = pCheckButtonData->ConvertToButtonState( nButtonFlags );
}
return eState;
}
void SvTreeListBox::CheckButtonHdl()
{
DBG_CHKTHIS(SvTreeListBox,0);
aCheckButtonHdl.Call( this );
if ( pCheckButtonData )
pImp->CallEventListeners( VCLEVENT_CHECKBOX_TOGGLE, (void*)pCheckButtonData->GetActEntry() );
}
//
// TODO: Currently all data is cloned so that they conform to the default tree
// view format. Actually, the model should be used as a reference here. This
// leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
// SvTreeListEntry.
//
SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
{
DBG_CHKTHIS(SvTreeListBox,0);
OUString aStr;
Image aCollEntryBmp;
Image aExpEntryBmp;
SvLBoxButtonKind eButtonKind = SvLBoxButtonKind_enabledCheckbox;
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( );
}
SvLBoxButton* pButtonItem = (SvLBoxButton*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
if( pButtonItem )
eButtonKind = pButtonItem->GetKind();
SvTreeListEntry* pClone = CreateEntry();
InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp, eButtonKind );
pClone->SvTreeListEntry::Clone( pSource );
pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
pClone->SetUserData( pSource->GetUserData() );
return pClone;
}
void SvTreeListBox::SetIndent( short nNewIndent )
{
DBG_CHKTHIS(SvTreeListBox,0);
nIndent = nNewIndent;
SetTabs();
if( IsUpdateMode() )
Invalidate();
}
const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
{
return pImp->GetDefaultEntryExpBmp( );
}
const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
{
return pImp->GetDefaultEntryColBmp( );
}
void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
{
DBG_CHKTHIS(SvTreeListBox,0);
Size aSize = aBmp.GetSizePixel();
if( aSize.Width() > nContextBmpWidthMax )
nContextBmpWidthMax = (short)aSize.Width();
SetTabs();
pImp->SetDefaultEntryExpBmp( aBmp );
}
void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
{
DBG_CHKTHIS(SvTreeListBox,0);
Size aSize = aBmp.GetSizePixel();
if( aSize.Width() > nContextBmpWidthMax )
nContextBmpWidthMax = (short)aSize.Width();
SetTabs();
pImp->SetDefaultEntryColBmp( aBmp );
}
void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0");
if( !pData )
nTreeFlags &= (~TREEFLAG_CHKBTN);
else
{
SetCheckButtonData( pData );
nTreeFlags |= TREEFLAG_CHKBTN;
pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick));
}
SetTabs();
if( IsUpdateMode() )
Invalidate();
}
void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( pData )
pCheckButtonData = pData;
}
const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
{
return SvImpLBox::GetDefaultExpandedNodeImage( );
}
const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
{
return SvImpLBox::GetDefaultCollapsedNodeImage( );
}
void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
{
DBG_CHKTHIS(SvTreeListBox,0);
SetExpandedNodeBmp( rExpandedNodeBmp );
SetCollapsedNodeBmp( rCollapsedNodeBmp );
SetTabs();
}
sal_Bool SvTreeListBox::EditingEntry( SvTreeListEntry*, Selection& )
{
DBG_CHKTHIS(SvTreeListBox,0);
return sal_True;
}
sal_Bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
{
DBG_CHKTHIS(SvTreeListBox,0);
return sal_True;
}
void SvTreeListBox::EnableInplaceEditing( bool bOn )
{
DBG_CHKTHIS(SvTreeListBox,0);
if (bOn)
nImpFlags |= SVLBOX_EDT_ENABLED;
else
nImpFlags &= ~SVLBOX_EDT_ENABLED;
}
void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
// under OS/2, we get key up/down even while editing
if( IsEditingActive() )
return;
nImpFlags |= SVLBOX_IS_TRAVELSELECT;
#ifdef OVDEBUG
sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
switch ( nCode )
{
case KEY_F1:
{
SvTreeListEntry* pEntry = First();
pEntry = NextVisible( pEntry );
SetEntryText( pEntry, "SetEntryText" );
}
break;
}
#endif
if( !pImp->KeyInput( rKEvt ) )
{
bool bHandled = HandleKeyInput( rKEvt );
if ( !bHandled )
Control::KeyInput( rKEvt );
}
nImpFlags &= ~SVLBOX_IS_TRAVELSELECT;
}
void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( !pParent->HasChildren() )
InsertEntry( OUString("<dummy>"), pParent, sal_False, LIST_APPEND );
}
void SvTreeListBox::GetFocus()
{
DBG_CHKTHIS(SvTreeListBox,0);
//If there is no item in the tree, draw focus.
if( !First())
{
Invalidate();
}
pImp->GetFocus();
Control::GetFocus();
SvTreeListEntry* pEntry = FirstSelected();
if ( !pEntry )
{
pEntry = pImp->GetCurrentEntry();
}
if (pImp->pCursor)
{
if (pEntry != pImp->pCursor)
pEntry = pImp->pCursor;
}
if ( pEntry )
pImp->CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS, pEntry );
}
void SvTreeListBox::LoseFocus()
{
DBG_CHKTHIS(SvTreeListBox,0);
//If there is no item in the tree, delete visual focus.
if( !First())
{
Invalidate();
}
pImp->LoseFocus();
Control::LoseFocus();
}
void SvTreeListBox::ModelHasCleared()
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->pCursor = 0; // else we crash in GetFocus when editing in-place
delete pEdCtrl;
pEdCtrl = NULL;
pImp->Clear();
nFocusWidth = -1;
nContextBmpWidthMax = 0;
SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
if( !(nTreeFlags & TREEFLAG_FIXEDHEIGHT ))
nEntryHeight = 0;
AdjustEntryHeight( GetFont() );
AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
SvListView::ModelHasCleared();
}
void SvTreeListBox::ShowTargetEmphasis( SvTreeListEntry* pEntry, sal_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 )
{
// move window up
nDeltaEntries *= -1;
long nVis = pImp->aVerSBar.GetVisibleSize();
long nTemp = nThumb + nVis;
if( nDeltaEntries > (nMax - nTemp) )
nDeltaEntries = (short)(nMax - nTemp);
pImp->PageDown( (sal_uInt16)nDeltaEntries );
}
else
{
if( nDeltaEntries > nThumb )
nDeltaEntries = (short)nThumb;
pImp->PageUp( (sal_uInt16)nDeltaEntries );
}
pImp->SyncVerThumb();
NotifyEndScroll();
}
void SvTreeListBox::ScrollToAbsPos( long nPos )
{
pImp->ScrollToAbsPos( nPos );
}
void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
{
DBG_CHKTHIS(SvTreeListBox,0);
eSelMode = eSelectMode;
pImp->SetSelectionMode( eSelectMode );
}
void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
{
DBG_CHKTHIS(SvTreeListBox,0);
nDragDropMode = 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(OUString('X')), GetTextHeight());
if( GetEntryHeight() > aSizeLogic.Height() )
nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
return nOffset;
}
void SvTreeListBox::SetEntryHeight( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
short nHeight, nHeightMax=0;
sal_uInt16 nCount = pEntry->ItemCount();
sal_uInt16 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;
Control::SetFont( GetFont() );
pImp->SetEntryHeight( nHeightMax );
}
}
void SvTreeListBox::SetEntryHeight( short nHeight, sal_Bool bAlways )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( bAlways || nHeight > nEntryHeight )
{
nEntryHeight = nHeight;
if( nEntryHeight )
nTreeFlags |= TREEFLAG_FIXEDHEIGHT;
else
nTreeFlags &= ~TREEFLAG_FIXEDHEIGHT;
Control::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 );
}
}
sal_Bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
{
DBG_CHKTHIS(SvTreeListBox,0);
pHdlEntry = pParent;
sal_Bool bExpanded = sal_False;
sal_uInt16 nFlags;
if( pParent->HasChildrenOnDemand() )
RequestingChildren( pParent );
if( pParent->HasChildren() )
{
nImpFlags |= SVLBOX_IS_EXPANDING;
if( ExpandingHdl() )
{
bExpanded = sal_True;
SvListView::Expand( pParent );
pImp->EntryExpanded( pParent );
pHdlEntry = 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 ); // repaint
}
// #i92103#
if ( bExpanded )
{
pImp->CallEventListeners( VCLEVENT_ITEM_EXPANDED, pParent );
}
return bExpanded;
}
sal_Bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
{
DBG_CHKTHIS(SvTreeListBox,0);
nImpFlags &= ~SVLBOX_IS_EXPANDING;
pHdlEntry = pParent;
sal_Bool bCollapsed = sal_False;
if( ExpandingHdl() )
{
bCollapsed = sal_True;
pImp->CollapsingEntry( pParent );
SvListView::Collapse( pParent );
pImp->EntryCollapsed( pParent );
pHdlEntry = pParent;
ExpandedHdl();
}
// #i92103#
if ( bCollapsed )
{
pImp->CallEventListeners( VCLEVENT_ITEM_COLLAPSED, pParent );
}
return bCollapsed;
}
sal_Bool SvTreeListBox::Select( SvTreeListEntry* pEntry, sal_Bool bSelect )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"Select: Null-Ptr");
sal_Bool bRetVal = SvListView::Select( pEntry, bSelect );
DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
if( bRetVal )
{
pImp->EntrySelected( pEntry, bSelect );
pHdlEntry = pEntry;
if( bSelect )
{
SelectHdl();
CallEventListeners( VCLEVENT_LISTBOX_TREESELECT, pEntry);
}
else
DeselectHdl();
}
return bRetVal;
}
sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, sal_Bool bSelect )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->DestroyAnchor();
sal_uLong nRet = 0;
if( !pParent->HasChildren() )
return 0;
sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
SvTreeListEntry* pChild = FirstChild( pParent );
do {
nRet++;
Select( pChild, bSelect );
pChild = Next( pChild );
} while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
return nRet;
}
void SvTreeListBox::SelectAll( sal_Bool bSelect, sal_Bool )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->SelAllDestrAnch(
bSelect,
sal_True, // delete anchor,
sal_True ); // even when using SINGLE_SELECTION, deselect the cursor
}
void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nRefDepth = pModel->GetDepth( (SvTreeListEntry*)pEntry );
SvTreeListEntry* pTmp = (SvTreeListEntry*)pEntry;
do
{
ImpEntryInserted( pTmp );
pTmp = Next( pTmp );
} while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
pImp->TreeInserted( (SvTreeListEntry*)pEntry );
}
void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
ImpEntryInserted( (SvTreeListEntry*)pEntry );
pImp->EntryInserted( (SvTreeListEntry*)pEntry );
}
void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource,
SvTreeListEntry* /* pTargetParent */,
sal_uLong /* nChildPos */ )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->MovingEntry( (SvTreeListEntry*)pSource );
}
void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->EntryMoved( (SvTreeListEntry*)pSource );
}
void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
if(pEdEntry == pEntry)
pEdEntry = NULL;
pImp->RemovingEntry( (SvTreeListEntry*)pEntry );
NotifyRemoving( (SvTreeListEntry*)pEntry );
}
void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
if ( pEntry == pHdlEntry)
pHdlEntry = NULL;
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 );
Font aOrigFont( GetFont() );
aTempFont.SetTransparent( sal_True );
if (aTempFont == aOrigFont)
return;
Control::SetFont( aTempFont );
aTempFont.SetColor(aOrigFont.GetColor());
aTempFont.SetFillColor(aOrigFont.GetFillColor());
aTempFont.SetTransparent(aOrigFont.IsTransparent());
if (aTempFont == aOrigFont)
return;
AdjustEntryHeightAndRecalc( GetFont() );
}
void SvTreeListBox::AdjustEntryHeightAndRecalc( const Font& rFont )
{
DBG_CHKTHIS(SvTreeListBox,0);
AdjustEntryHeight( rFont );
// always invalidate, else things go wrong in SetEntryHeight
RecalcViewData();
}
void SvTreeListBox::Paint( const Rectangle& rRect )
{
DBG_CHKTHIS(SvTreeListBox,0);
Control::Paint( rRect );
if( nTreeFlags & TREEFLAG_RECALCTABS )
SetTabs();
pImp->Paint( rRect );
//Add visual focus draw
if( !First() )
{
if( HasFocus() )
{
long tempHeight = GetTextHeight();
Rectangle tempRect(
Point(0,0),Size(GetSizePixel().Width(),tempHeight)
);
ShowFocus(tempRect);
}
else{
HideFocus();
}
}
}
void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->MouseButtonDown( rMEvt );
}
void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->MouseButtonUp( rMEvt );
}
void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->MouseMove( rMEvt );
}
void SvTreeListBox::SetUpdateMode( sal_Bool bUpdate )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->SetUpdateMode( bUpdate );
}
void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( nOffsLogic != nEntryHeightOffs )
{
nEntryHeight = nEntryHeight - nEntryHeightOffs;
nEntryHeightOffs = (short)nOffsLogic;
nEntryHeight = nEntryHeight + nOffsLogic;
AdjustEntryHeightAndRecalc( GetFont() );
pImp->SetEntryHeight( nEntryHeight );
}
}
void SvTreeListBox::SetCursor( SvTreeListEntry* pEntry, sal_Bool bForceNoSelect )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->SetCursor(pEntry, bForceNoSelect);
}
void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
pImp->SetCurEntry( pEntry );
}
Image SvTreeListBox::GetExpandedNodeBmp( ) const
{
return pImp->GetExpandedNodeBmp( );
}
Point SvTreeListBox::GetEntryPosition( SvTreeListEntry* pEntry ) const
{
return pImp->GetEntryPosition( pEntry );
}
void SvTreeListBox::ShowEntry( SvTreeListEntry* pEntry )
{
MakeVisible( pEntry );
}
void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
{
pImp->MakeVisible(pEntry);
}
void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, sal_Bool bMoveToTop )
{
pImp->MakeVisible( pEntry, bMoveToTop );
}
void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
// reinitialize the separate items of the entries
sal_uInt16 nCount = ((SvTreeListEntry*)pEntry)->ItemCount();
for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
{
SvLBoxItem* pItem = ((SvTreeListEntry*)pEntry)->GetItem( nIdx );
pItem->InitViewData( this, (SvTreeListEntry*)pEntry, 0 );
}
// repaint
pImp->InvalidateEntry( (SvTreeListEntry*)pEntry );
}
void SvTreeListBox::EditItemText( SvTreeListEntry* pEntry, SvLBoxString* pItem,
const Selection& rSelection )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params");
if( IsSelected( pEntry ))
{
pImp->ShowCursor( sal_False );
SvListView::Select( pEntry, sal_False );
PaintEntry( pEntry );
SvListView::Select( pEntry, sal_True );
pImp->ShowCursor( sal_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 = GetEntryPosition( pEntry );
aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2;
aPos.X() = GetTabPos( pEntry, pTab );
long nOutputWidth = pImp->GetOutputSize().Width();
Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() );
sal_uInt16 nPos = std::find( aTabs.begin(), aTabs.end(), pTab ) - aTabs.begin();
if( nPos+1 < (sal_uInt16)aTabs.size() )
{
SvLBoxTab* pRightTab = aTabs[ nPos + 1 ];
long nRight = GetTabPos( pEntry, pRightTab );
if( nRight <= nOutputWidth )
aSize.Width() = nRight - aPos.X();
}
Point aOrigin( GetMapMode().GetOrigin() );
aPos += aOrigin; // convert to win coordinates
aSize.Width() -= aOrigin.X();
Rectangle aRect( aPos, aSize );
EditText( pItem->GetText(), aRect, rSelection );
}
void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
{
pImp->aEditClickPos = Point( -1, -1 );
ImplEditEntry( pEntry );
}
void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( IsEditingActive() )
EndEditing();
if( !pEntry )
pEntry = GetCurEntry();
if( pEntry )
{
long nClickX = pImp->aEditClickPos.X();
bool bIsMouseTriggered = nClickX >= 0;
SvLBoxString* pItem = NULL;
sal_uInt16 nCount = pEntry->ItemCount();
long nTabPos, nNextTabPos = 0;
for( sal_uInt16 i = 0 ; i < nCount ; i++ )
{
SvLBoxItem* pTmpItem = pEntry->GetItem( i );
if (pTmpItem->GetType() != SV_ITEM_ID_LBOXSTRING)
continue;
SvLBoxTab* pTab = GetTab( pEntry, pTmpItem );
nNextTabPos = -1;
if( i < nCount - 1 )
{
SvLBoxItem* pNextItem = pEntry->GetItem( i + 1 );
SvLBoxTab* pNextTab = GetTab( pEntry, pNextItem );
nNextTabPos = pNextTab->GetPos();
}
if( pTab && pTab->IsEditable() )
{
nTabPos = pTab->GetPos();
if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
{
pItem = static_cast<SvLBoxString*>( pTmpItem );
break;
}
}
}
Selection aSel( SELECTION_MIN, SELECTION_MAX );
if( pItem && EditingEntry( pEntry, aSel ) )
{
SelectAll( sal_False );
MakeVisible( pEntry );
EditItemText( pEntry, pItem, aSel );
}
}
}
sal_Bool SvTreeListBox::AreChildrenTransient() const
{
return pImp->AreChildrenTransient();
}
void SvTreeListBox::SetChildrenNotTransient()
{
pImp->SetChildrenNotTransient();
}
void SvTreeListBox::EditedText( const OUString& rStr )
{
DBG_CHKTHIS(SvTreeListBox,0);
if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
{
if( EditedEntry( pEdEntry, rStr ) )
{
((SvLBoxString*)pEdItem)->SetText( rStr );
pModel->InvalidateEntry( pEdEntry );
}
if( GetSelectionCount() == 0 )
Select( pEdEntry );
if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() )
SetCurEntry( pEdEntry );
}
}
SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
{
DBG_CHKTHIS(SvTreeListBox,0);
// scroll
if( rPos.Y() < 12 )
{
ImplShowTargetEmphasis(pTargetEntry, false);
ScrollOutputArea( +1 );
}
else
{
Size aSize( pImp->GetOutputSize() );
if( rPos.Y() > aSize.Height() - 12 )
{
ImplShowTargetEmphasis(pTargetEntry, false);
ScrollOutputArea( -1 );
}
}
SvTreeListEntry* pTarget = pImp->GetEntry( rPos );
// when dropping in a vacant space, use the last entry
if( !pTarget )
return (SvTreeListEntry*)LastVisible();
else if( (GetDragDropMode() & SV_DRAGDROP_ENABLE_TOP) &&
pTarget == First() && rPos.Y() < 6 )
return 0;
return pTarget;
}
SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, sal_Bool bHit ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
SvTreeListEntry* pEntry = pImp->GetEntry( rPos );
if( pEntry && bHit )
{
long nLine = pImp->GetEntryLine( pEntry );
if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) )
return 0;
}
return pEntry;
}
SvTreeListEntry* SvTreeListBox::GetCurEntry() const
{
DBG_CHKTHIS(SvTreeListBox,0);
return pImp->GetCurEntry();
}
void SvTreeListBox::ImplInitStyle()
{
DBG_CHKTHIS(SvTreeListBox,0);
const WinBits nWindowStyle = GetStyle();
nTreeFlags |= TREEFLAG_RECALCTABS;
if( nWindowStyle & WB_SORT )
{
GetModel()->SetSortMode( SortAscending );
GetModel()->SetCompareHdl( LINK(this,SvTreeListBox,DefaultCompare));
}
else
{
GetModel()->SetSortMode( SortNone );
GetModel()->SetCompareHdl( Link() );
}
pImp->SetStyle( nWindowStyle );
pImp->Resize();
Invalidate();
}
void SvTreeListBox::PaintEntry( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"PaintEntry:No Entry");
if( pEntry )
pImp->PaintEntry( pEntry );
}
void SvTreeListBox::InvalidateEntry( SvTreeListEntry* pEntry )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pEntry,"InvalidateEntry:No Entry");
if( pEntry )
{
GetModel()->InvalidateEntry( pEntry );
}
}
long SvTreeListBox::PaintEntry(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags)
{
return PaintEntry1(pEntry,nLine,nTabFlags);
}
long SvTreeListBox::PaintEntry1(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags,
sal_Bool bHasClipRegion )
{
DBG_CHKTHIS(SvTreeListBox,0);
Rectangle aRect; // multi purpose
sal_Bool bHorSBar = pImp->HasHorScrollBar();
PreparePaint( pEntry );
pImp->UpdateContextBmpWidthMax( pEntry );
if( nTreeFlags & TREEFLAG_RECALCTABS )
SetTabs();
short nTempEntryHeight = GetEntryHeight();
long nWidth = pImp->GetOutputSize().Width();
// Did we turn on the scrollbar within PreparePaints? If yes, we have to set
// the ClipRegion anew.
if( !bHorSBar && pImp->HasHorScrollBar() )
SetClipRegion( Region(pImp->GetClipRegionRect()) );
Point aEntryPos( GetMapMode().GetOrigin() );
aEntryPos.X() *= -1; // conversion document coordinates
long nMaxRight = nWidth + aEntryPos.X() - 1;
Color aBackupTextColor( GetTextColor() );
Font aBackupFont( GetFont() );
Color aBackupColor = GetFillColor();
bool bCurFontIsSel = false;
sal_Bool bInUse = pEntry->HasInUseEmphasis();
// if a ClipRegion was set from outside, we don't have to reset it
const WinBits nWindowStyle = GetStyle();
const bool bResetClipRegion = !bHasClipRegion;
const bool bHideSelection = (nWindowStyle & WB_HIDESELECTION) !=0 && !HasFocus();
const StyleSettings& rSettings = GetSettings().GetStyleSettings();
Font aHighlightFont( GetFont() );
const Color aHighlightTextColor( rSettings.GetHighlightTextColor() );
aHighlightFont.SetColor( aHighlightTextColor );
Size aRectSize( 0, nTempEntryHeight );
if( !bHasClipRegion && nWindowStyle & WB_HSCROLL )
{
SetClipRegion( Region(pImp->GetClipRegionRect()) );
bHasClipRegion = sal_True;
}
SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry );
sal_uInt16 nTabCount = aTabs.size();
sal_uInt16 nItemCount = pEntry->ItemCount();
sal_uInt16 nCurTab = 0;
sal_uInt16 nCurItem = 0;
while( nCurTab < nTabCount && nCurItem < nItemCount )
{
SvLBoxTab* pTab = aTabs[ nCurTab ];
sal_uInt16 nNextTab = nCurTab + 1;
SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0;
sal_uInt16 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 )
// avoid cutting the right edge off the tab separation
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 = sal_True;
}
aEntryPos.X() = nX;
aEntryPos.Y() = nLine;
// set background pattern/color
Wallpaper aWallpaper = GetBackground();
int bSelTab = nFlags & SV_LBOXTAB_SHOW_SELECTION;
sal_uInt16 nItemType = pItem->GetType();
if (pViewDataEntry->IsHighlighted() && bSelTab && !pViewDataEntry->IsCursored())
{
Color aNewWallColor = rSettings.GetHighlightColor();
if ( !bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP )
{
// if the face color is bright then the deactive color is also bright
// -> so you can't see any deactive selection
if ( bHideSelection && !rSettings.GetFaceColor().IsBright() &&
aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright() )
aNewWallColor = rSettings.GetDeactiveColor();
// set font color to highlight
if ( !bCurFontIsSel )
{
SetTextColor( aHighlightTextColor );
Control::SetFont( aHighlightFont );
bCurFontIsSel = true;
}
}
aWallpaper.SetColor( aNewWallColor );
}
else // no selection
{
if( bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP )
aWallpaper.SetColor( rSettings.GetFieldColor() );
else if( bCurFontIsSel )
{
bCurFontIsSel = false;
SetTextColor( aBackupTextColor );
Control::SetFont( aBackupFont );
}
}
// draw background
if( !(nTreeFlags & TREEFLAG_USESEL))
{
// only draw the area that is used by the item
aRectSize.Width() = aSize.Width();
aRect.SetPos( aEntryPos );
aRect.SetSize( aRectSize );
}
else
{
// draw from the current to the next tab
if( nCurTab != 0 )
aRect.Left() = nTabPos;
else
// if we're in the 0th tab, always draw from column 0 --
// else we get problems with centered tabs
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;
}
// A custom selection that starts at a tab position > 0, do not fill
// the background of the 0th item, else e.g. we might not be able to
// realize tab listboxes with lines.
if( !(nCurTab==0 && (nTreeFlags & TREEFLAG_USESEL) && nFirstSelTab) )
{
SetFillColor( aWallpaper.GetColor() );
// this case may occur for smaller horizontal resizes
if( aRect.Left() < aRect.Right() )
DrawRect( aRect );
}
// draw item
// center vertically
aEntryPos.Y() += ( nTempEntryHeight - aSize.Height() ) / 2;
pItem->Paint(aEntryPos, *this, pViewDataEntry, pEntry);
// division line between tabs
if (pNextTab && pItem->GetType() == SV_ITEM_ID_LBOXSTRING &&
// not at the right edge of the window!
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 )
{
SetTextColor( aBackupTextColor );
Control::SetFont( aBackupFont );
}
sal_uInt16 nFirstDynTabPos;
SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab( nFirstDynTabPos );
long nDynTabPos = GetTabPos( pEntry, pFirstDynamicTab );
nDynTabPos += pImp->nNodeBmpTabDistance;
nDynTabPos += pImp->nNodeBmpWidth / 2;
nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
// to the next tab
if( (!(pEntry->GetFlags() & SV_ENTRYFLAG_NO_NODEBMP)) &&
(nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() ) )
{
// find first tab and check if the node bitmap extends into it
sal_uInt16 nNextTab = nFirstDynTabPos;
SvLBoxTab* pNextTab;
do
{
nNextTab++;
pNextTab = nNextTab < nTabCount ? aTabs[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->HasChildren()) && pEntry->HasChildrenOnDemand() &&
(!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
pImp->GetDontKnowNodeBmp().GetSizePixel().Width() )
pImg = &pImp->GetDontKnowNodeBmp( );
else
pImg = &pImp->GetCollapsedNodeBmp( );
}
aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2;
sal_uInt16 nStyle = 0;
if ( !IsEnabled() )
nStyle |= IMAGE_DRAW_DISABLE;
//native
sal_Bool bNativeOK = sal_False;
if ( IsNativeControlSupported( CTRL_LISTNODE, PART_ENTIRE_CONTROL) )
{
ImplControlValue aControlValue;
Rectangle aCtrlRegion( aPos, pImg->GetSizePixel() );
ControlState nState = 0;
if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED;
if ( IsExpanded(pEntry) )
aControlValue.setTristateVal( BUTTONVALUE_ON );//expanded node
else
{
if( (!pEntry->HasChildren() ) &&
pEntry->HasChildrenOnDemand() &&
(!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
pImp->GetDontKnowNodeBmp().GetSizePixel().Width()
)
aControlValue.setTristateVal( BUTTONVALUE_DONTKNOW ); //dont know
else
aControlValue.setTristateVal( BUTTONVALUE_OFF ); //collapsed node
}
bNativeOK = DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL,
aCtrlRegion, nState, aControlValue, OUString() );
}
if( !bNativeOK) {
DrawImage( aPos, *pImg ,nStyle);
}
}
}
}
if( bHasClipRegion && bResetClipRegion )
SetClipRegion();
return 0; // nRowLen;
}
void SvTreeListBox::PreparePaint( SvTreeListEntry* )
{
}
Rectangle SvTreeListBox::GetFocusRect( SvTreeListEntry* 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();
sal_uInt16 nCurTab;
SvLBoxTab* pTab = GetFirstTab( SV_LBOXTAB_SHOW_SELECTION, nCurTab );
long nTabPos = 0;
if( pTab )
nTabPos = GetTabPos( pEntry, pTab );
long nNextTabPos;
if( pTab && nCurTab < aTabs.size() - 1 )
{
SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ];
nNextTabPos = GetTabPos( pEntry, pNextTab );
}
else
{
nNextTabPos = nRealWidth;
if( nTabPos > nRealWidth )
nNextTabPos += 50;
}
sal_Bool bUserSelection = (sal_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 );
// alignment
nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
aRect.Left() = nX;
// make sure that first and last letter aren't cut off slightly
aRect.SetSize( aSize );
if( aRect.Left() > 0 )
aRect.Left()--;
aRect.Right()++;
}
}
else
{
// if SelTab != 0, we have to calculate also
if( nFocusWidth == -1 || nFirstSelTab )
{
sal_uInt16 nLastTab;
SvLBoxTab* pLastTab = GetLastTab(SV_LBOXTAB_SHOW_SELECTION,nLastTab);
nLastTab++;
if( nLastTab < aTabs.size() ) // is there another one?
pLastTab = aTabs[ nLastTab ];
else
pLastTab = 0; // select whole width
aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff;
nFocusWidth = (short)aSize.Width();
if( pTab )
nFocusWidth = nFocusWidth - (short)nTabPos; //pTab->GetPos();
}
else
{
aSize.Width() = nFocusWidth;
if( pTab )
{
if( nCurTab )
aSize.Width() += nTabPos;
else
aSize.Width() += pTab->GetPos(); // Tab0 always from the leftmost position
}
}
// if selection starts with 0th tab, draw from column 0 on
if( nCurTab != 0 )
{
aRect.Left() = nTabPos;
aSize.Width() -= nTabPos;
}
aRect.SetSize( aSize );
}
// adjust right edge because of clipping
if( aRect.Right() >= nRealWidth )
{
aRect.Right() = nRealWidth-1;
nFocusWidth = (short)aRect.GetWidth();
}
return aRect;
}
sal_IntPtr SvTreeListBox::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pTab,"No Tab");
sal_IntPtr nPos = pTab->GetPos();
if( pTab->IsDynamic() )
{
sal_uInt16 nDepth = pModel->GetDepth( pEntry );
nDepth = nDepth * (sal_uInt16)nIndent;
nPos += (sal_IntPtr)nDepth;
}
return nPos;
}
SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
SvLBoxTab** ppTab, sal_uInt16 nEmptyWidth )
{
DBG_CHKTHIS(SvTreeListBox,0);
SvLBoxItem* pItemClicked = 0;
sal_uInt16 nTabCount = aTabs.size();
sal_uInt16 nItemCount = pEntry->ItemCount();
SvLBoxTab* pTab = aTabs.front();
SvLBoxItem* pItem = pEntry->GetItem(0);
sal_uInt16 nNextItem = 1;
nX -= GetMapMode().GetOrigin().X();
long nRealWidth = pImp->GetOutputSize().Width();
nRealWidth -= GetMapMode().GetOrigin().X();
while( 1 )
{
SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[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 = aTabs[ nNextItem ];
pItem = pEntry->GetItem( nNextItem );
nNextItem++;
}
return pItemClicked;
}
long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
{
long nHeight = 0;
rWidths.clear();
SvTreeListEntry* pEntry = First();
while (pEntry)
{
sal_uInt16 nCount = pEntry->ItemCount();
sal_uInt16 nCurPos = 0;
if (nCount > rWidths.size())
rWidths.resize(nCount);
while (nCurPos < nCount)
{
SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
long nWidth = pItem->GetSize(this, pEntry).Width();
if (nWidth)
{
nWidth += SV_TAB_BORDER * 2;
if (nWidth > rWidths[nCurPos])
rWidths[nCurPos] = nWidth;
}
++nCurPos;
}
pEntry = Next( pEntry );
nHeight += GetEntryHeight();
}
return nHeight;
}
Size SvTreeListBox::GetOptimalSize() const
{
std::vector<long> aWidths;
Size aRet(0, getPreferredDimensions(aWidths));
for (size_t i = 0; i < aWidths.size(); ++i)
aRet.Width() += aWidths[i];
if (GetStyle() & WB_BORDER)
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
aRet.Width() += rStyleSettings.GetBorderSize() * 2;
aRet.Height() += rStyleSettings.GetBorderSize() * 2;
}
long nMinWidth = nMinWidthInChars * approximate_char_width();
aRet.Width() = std::max(aRet.Width(), nMinWidth);
return aRet;
}
SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
{
return GetItem_Impl( pEntry, nX, ppTab, 0 );
}
SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
{
DBG_CHKTHIS(SvTreeListBox,0);
SvLBoxTab* pDummyTab;
return GetItem_Impl( pEntry, nX, &pDummyTab, 0 );
}
void SvTreeListBox::AddTab(long nTabPos,sal_uInt16 nFlags,void* pUserData )
{
DBG_CHKTHIS(SvTreeListBox,0);
nFocusWidth = -1;
SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
pTab->SetUserData( pUserData );
aTabs.push_back( pTab );
if( nTreeFlags & TREEFLAG_USESEL )
{
sal_uInt16 nPos = aTabs.size() - 1;
if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
pTab->nFlags |= SV_LBOXTAB_SHOW_SELECTION;
else
// string items usually have to be selected -- turn this off
// explicitly
pTab->nFlags &= ~SV_LBOXTAB_SHOW_SELECTION;
}
}
SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nCurTab = 0;
sal_uInt16 nTabCount = aTabs.size();
while( nCurTab < nTabCount )
{
SvLBoxTab* pTab = aTabs[nCurTab];
if( pTab->nFlags & SV_LBOXTAB_DYNAMIC )
{
rPos = nCurTab;
return pTab;
}
nCurTab++;
}
return 0;
}
SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
{
sal_uInt16 nDummy;
return GetFirstDynamicTab( nDummy );
}
SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry* pEntry, SvLBoxItem* pItem) const
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nPos = pEntry->GetPos( pItem );
return aTabs[ nPos ];
}
void SvTreeListBox::ClearTabList()
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nTabCount = aTabs.size();
while( nTabCount )
{
nTabCount--;
SvLBoxTab* pDelTab = aTabs[ nTabCount ];
delete pDelTab;
}
aTabs.clear();
}
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 )
{
DBG_CHKTHIS(SvTreeListBox,0);
}
void SvTreeListBox::NotifyScrolled()
{
DBG_CHKTHIS(SvTreeListBox,0);
aScrolledHdl.Call( this );
}
void SvTreeListBox::NotifyInvalidating()
{
DBG_CHKTHIS(SvTreeListBox,0);
}
void SvTreeListBox::Invalidate( sal_uInt16 nInvalidateFlags )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( nFocusWidth == -1 )
// to make sure that the control doesn't show the wrong focus rectangle
// after painting
pImp->RecalcFocusRect();
NotifyInvalidating();
Control::Invalidate( nInvalidateFlags );
pImp->Invalidate();
}
void SvTreeListBox::Invalidate( const Rectangle& rRect, sal_uInt16 nInvalidateFlags )
{
DBG_CHKTHIS(SvTreeListBox,0);
if( nFocusWidth == -1 )
// to make sure that the control doesn't show the wrong focus rectangle
// after painting
pImp->RecalcFocusRect();
NotifyInvalidating();
Control::Invalidate( rRect, nInvalidateFlags );
}
void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
{
DBG_CHKTHIS(SvTreeListBox,0);
sal_uInt16 nTemp;
nTreeFlags |= TREEFLAG_USESEL;
if( nStart > nEnd )
{
nTemp = nStart;
nStart = nEnd;
nEnd = nTemp;
}
// select all tabs that lie within the area
nTreeFlags |= TREEFLAG_RECALCTABS;
nFirstSelTab = nStart;
nLastSelTab = nEnd;
pImp->RecalcFocusRect();
}
void SvTreeListBox::Command( const CommandEvent& rCEvt )
{
DBG_CHKTHIS(SvTreeListBox,0);
// FIXME gnumake2 resync to DEV300_m84
pImp->Command( rCEvt );
}
void SvTreeListBox::RemoveParentKeepChildren( SvTreeListEntry* pParent )
{
DBG_CHKTHIS(SvTreeListBox,0);
DBG_ASSERT(pParent,"RemoveParentKeepChildren:No Parent");
SvTreeListEntry* pNewParent = GetParent( pParent );
if( pParent->HasChildren())
{
SvTreeListEntry* pChild = FirstChild( pParent );
while( pChild )
{
pModel->Move( pChild, pNewParent, LIST_APPEND );
pChild = FirstChild( pParent );
}
}
pModel->Remove( pParent );
}
SvLBoxTab* SvTreeListBox::GetFirstTab( sal_uInt16 nFlagMask, sal_uInt16& rPos )
{
sal_uInt16 nTabCount = aTabs.size();
for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
{
SvLBoxTab* pTab = aTabs[ nPos ];
if( (pTab->nFlags & nFlagMask) )
{
rPos = nPos;
return pTab;
}
}
rPos = 0xffff;
return 0;
}
SvLBoxTab* SvTreeListBox::GetLastTab( sal_uInt16 nFlagMask, sal_uInt16& rTabPos )
{
sal_uInt16 nPos = (sal_uInt16)aTabs.size();
while( nPos )
{
--nPos;
SvLBoxTab* pTab = aTabs[ nPos ];
if( (pTab->nFlags & nFlagMask) )
{
rTabPos = nPos;
return pTab;
}
}
rTabPos = 0xffff;
return 0;
}
void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
{
if( !pImp->RequestHelp( rHEvt ) )
Control::RequestHelp( rHEvt );
}
void SvTreeListBox::CursorMoved( SvTreeListEntry* )
{
}
IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData )
{
const SvTreeListEntry* pLeft = pData->pLeft;
const SvTreeListEntry* pRight = pData->pRight;
OUString aLeft( ((SvLBoxString*)(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
OUString aRight( ((SvLBoxString*)(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
pImp->UpdateStringSorter();
return pImp->m_pStringSorter->compare(aLeft, aRight);
}
void SvTreeListBox::ModelNotification( sal_uInt16 nActionId, SvTreeListEntry* pEntry1,
SvTreeListEntry* pEntry2, sal_uLong nPos )
{
SolarMutexGuard aSolarGuard;
if( nActionId == LISTACTION_CLEARING )
CancelTextEditing();
SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
switch( nActionId )
{
case LISTACTION_INSERTED:
{
SvTreeListEntry* pEntry( dynamic_cast< SvTreeListEntry* >( pEntry1 ) );
if ( !pEntry )
{
SAL_WARN( "svtools.contnr", "SvTreeListBox::ModelNotification: invalid entry!" );
break;
}
SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) );
if ( !pBmpItem )
break;
const Image& rBitmap1( pBmpItem->GetBitmap1() );
const Image& rBitmap2( pBmpItem->GetBitmap2() );
short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
nMaxWidth = pImp->UpdateContextBmpWidthVector( pEntry, nMaxWidth );
if( nMaxWidth > nContextBmpWidthMax )
{
nContextBmpWidthMax = nMaxWidth;
SetTabs();
}
if (get_width_request() == -1)
queue_resize();
}
break;
case LISTACTION_RESORTING:
SetUpdateMode( sal_False );
break;
case LISTACTION_RESORTED:
// after a selection: show first entry and also keep the selection
MakeVisible( (SvTreeListEntry*)pModel->First(), sal_True );
SetUpdateMode( sal_True );
break;
case LISTACTION_CLEARED:
if( IsUpdateMode() )
Update();
break;
}
}
void SvTreeListBox::EndSelection()
{
pImp->EndSelection();
}
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( sal_Bool b )
{
pImp->EnableAsyncDrag( b );
}
SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
{
Point aPos;
return GetEntry( aPos );
}
SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
{
SvTreeListEntry* pNext = (SvTreeListEntry*)NextVisible( pEntry );
if( pNext )
{
Point aPos( GetEntryPosition(pNext) );
const Size& rSize = pImp->GetOutputSize();
if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
return 0;
}
return pNext;
}
SvTreeListEntry* SvTreeListBox::GetLastEntryInView() const
{
SvTreeListEntry* pEntry = GetFirstEntryInView();
SvTreeListEntry* pNext = 0;
while( pEntry )
{
pNext = (SvTreeListEntry*)NextVisible( pEntry );
if( pNext )
{
Point aPos( GetEntryPosition(pNext) );
const Size& rSize = pImp->GetOutputSize();
if( aPos.Y() < 0 || aPos.Y() + GetEntryHeight() >= rSize.Height() )
break;
else
pEntry = pNext;
}
else
break;
}
return pEntry;
}
void SvTreeListBox::ShowFocusRect( const SvTreeListEntry* pEntry )
{
pImp->ShowFocusRect( pEntry );
}
void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
{
if( (rDCEvt.GetType()==DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
{
nEntryHeight = 0; // _together_ with sal_True of 1. par (bFont) of InitSettings() a zero-height
// forces complete recalc of heights!
InitSettings( sal_True, sal_True, sal_True );
Invalidate();
}
else
Control::DataChanged( rDCEvt );
}
void SvTreeListBox::StateChanged( StateChangedType eType )
{
if( eType == STATE_CHANGE_ENABLE )
Invalidate( INVALIDATE_CHILDREN );
Control::StateChanged( eType );
if ( eType == STATE_CHANGE_STYLE )
ImplInitStyle();
}
void SvTreeListBox::InitSettings(sal_Bool bFont,sal_Bool bForeground,sal_Bool bBackground)
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
if( bFont )
{
Font aFont;
aFont = rStyleSettings.GetFieldFont();
aFont.SetColor( rStyleSettings.GetWindowTextColor() );
SetPointFont( aFont );
AdjustEntryHeightAndRecalc( aFont );
}
if( bForeground || bFont )
{
SetTextColor( rStyleSettings.GetFieldTextColor() );
SetTextFillColor();
}
if( bBackground )
SetBackground( rStyleSettings.GetFieldColor() );
// always try to re-create default-SvLBoxButtonData
if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
pCheckButtonData->SetDefaultImages( this );
}
sal_Bool SvTreeListBox::IsCellFocusEnabled() const
{
return pImp->IsCellFocusEnabled();
}
bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
{
return pImp->SetCurrentTabPos( _nNewPos );
}
sal_uInt16 SvTreeListBox::GetCurrentTabPos() const
{
return pImp->GetCurrentTabPos();
}
void SvTreeListBox::InitStartEntry()
{
if( !pImp->pStartEntry )
pImp->pStartEntry = GetModel()->First();
}
PopupMenu* SvTreeListBox::CreateContextMenu( void )
{
return NULL;
}
void SvTreeListBox::ExcecuteContextMenuAction( sal_uInt16 )
{
DBG_WARNING( "SvTreeListBox::ExcecuteContextMenuAction(): now there's happening nothing!" );
}
void SvTreeListBox::EnableContextMenuHandling( void )
{
DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
pImp->bContextMenuHandling = sal_True;
}
void SvTreeListBox::EnableContextMenuHandling( sal_Bool b )
{
DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
pImp->bContextMenuHandling = b;
}
sal_Bool SvTreeListBox::IsContextMenuHandlingEnabled( void ) const
{
DBG_ASSERT( pImp, "-SvTreeListBox::IsContextMenuHandlingEnabled(): No implementation!" );
return pImp->bContextMenuHandling;
}
void SvTreeListBox::EnableList( bool _bEnable )
{
// call base class method
Window::Enable( _bEnable != false );
// then paint immediately
Paint( Rectangle( Point(), GetSizePixel() ) );
}
::com::sun::star::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
{
Window* pParent = GetAccessibleParentWindow();
DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
::com::sun::star::uno::Reference< XAccessible > xAccessible;
if ( pParent )
{
::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
if ( xAccParent.is() )
{
// need to be done here to get the vclxwindow later on in the accessbile
::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface());
xAccessible = pImp->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
}
}
return xAccessible;
}
void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
{
DBG_ASSERT( pEntry, "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry" );
if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
{
rStateSet.AddState( AccessibleStateType::EXPANDABLE );
if ( IsExpanded( pEntry ) )
rStateSet.AddState( (sal_Int16)AccessibleStateType::EXPANDED );
}
if ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED )
rStateSet.AddState( AccessibleStateType::CHECKED );
if ( IsEntryVisible( pEntry ) )
rStateSet.AddState( AccessibleStateType::VISIBLE );
if ( IsSelected( pEntry ) )
rStateSet.AddState( AccessibleStateType::SELECTED );
if ( IsEnabled() )
{
rStateSet.AddState( AccessibleStateType::ENABLED );
rStateSet.AddState( AccessibleStateType::FOCUSABLE );
rStateSet.AddState( AccessibleStateType::SELECTABLE );
SvViewDataEntry* pViewDataNewCur = 0;
if( pEntry )
{
pViewDataNewCur = GetViewDataEntry(pEntry);
if (pViewDataNewCur && pViewDataNewCur->HasFocus())
rStateSet.AddState( AccessibleStateType::FOCUSED );
}
}
}
Rectangle SvTreeListBox::GetBoundingRect( SvTreeListEntry* pEntry )
{
Point aPos = GetEntryPosition( pEntry );
Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
return aRect;
}
void SvTreeListBox::EnableCellFocus()
{
pImp->EnableCellFocus();
}
void SvTreeListBox::CallImplEventListeners(sal_uLong nEvent, void* pData)
{
CallEventListeners(nEvent, pData);
}
void SvTreeListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& /*rStateSet*/ ) const
{
}
void SvTreeListBox::set_min_width_in_chars(sal_Int32 nChars)
{
nMinWidthInChars = nChars;
queue_resize();
}
bool SvTreeListBox::set_property(const OString &rKey, const OString &rValue)
{
if (rKey == "min-width-chars")
{
set_min_width_in_chars(rValue.toInt32());
}
else
return Control::set_property(rKey, rValue);
return true;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */