X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0e320a79f187558effb04d92020b470372bbe456..4952771da3299869bfdb805edb2906ca6551637e:/src/os2/treectrl.cpp diff --git a/src/os2/treectrl.cpp b/src/os2/treectrl.cpp index 137a885dbf..d54a567d25 100644 --- a/src/os2/treectrl.cpp +++ b/src/os2/treectrl.cpp @@ -1,418 +1,2127 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: treectrl.cpp -// Purpose: wxTreeCtrl. See also Robert's generic wxTreeCtrl. -// Author: AUTHOR -// Modified by: -// Created: ??/??/98 +// Name: src/msw/treectrl.cpp +// Purpose: wxTreeCtrl +// Author: Julian Smart +// Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98 +// Created: 1997 // RCS-ID: $Id$ -// Copyright: (c) AUTHOR -// Licence: wxWindows licence +// Copyright: (c) Julian Smart +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "treectrl.h" -#endif +// ============================================================================ +// declarations +// ============================================================================ -#include "wx/stubs/textctrl.h" -#include "wx/stubs/treectrl.h" +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl) -IMPLEMENT_DYNAMIC_CLASS(wxTreeItem, wxObject) +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" +#ifdef __BORLANDC__ + #pragma hdrstop #endif -wxTreeCtrl::wxTreeCtrl() +#if wxUSE_TREECTRL + +#include "wx/os2/private.h" + +#include "wx/app.h" +#include "wx/log.h" +#include "wx/dynarray.h" +#include "wx/imaglist.h" +#include "wx/settings.h" +#include "wx/os2/treectrl.h" + +// a macro to hide the ugliness of nested casts +#define HITEM(item) (HTREEITEM)(WXHTREEITEM)(item) + +// the native control doesn't support multiple selections under MSW and we +// have 2 ways to emulate them: either using TVS_CHECKBOXES style and let +// checkboxes be the selection status (checked == selected) or by really +// emulating everything, i.e. intercepting mouse and key events &c. The first +// approach is much easier but doesn't work with comctl32.dll < 4.71 and also +// looks quite ugly. +#define wxUSE_CHECKBOXES_IN_MULTI_SEL_TREE 0 + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +typedef struct _MYRECORD { - m_imageListNormal = NULL; - m_imageListState = NULL; - m_textCtrl = NULL; -} + RECORDCORE m_vRecord; + ULONG m_ulItemId; + ULONG m_ulUserData; +} MYRECORD, *PMYRECORD; -bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, - long style, const wxValidator& validator, const wxString& name) +struct wxTreeViewItem : public MYRECORD { - SetName(name); - SetValidator(validator); + wxTreeViewItem(const wxTreeItemId& rItem) + { + m_ulItemId = (ULONG)rItem.m_pItem; + } +}; // end of STRUCT wxTreeViewItem - m_imageListNormal = NULL; - m_imageListState = NULL; - m_textCtrl = NULL; +class wxTreeItemInternalData +{ +public: - m_windowStyle = style; + wxTreeItemInternalData() {} + ~wxTreeItemInternalData() + { + if(m_pAttr) + { + delete m_pAttr; + m_pAttr = NULL; + } + } - SetParent(parent); + wxTreeItemAttr* m_pAttr; + WXLPARAM m_lParam; // user data +#if defined(C_CM_COS232) + PMYRECORD m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted +#endif +}; // end of CLASS wxTreeItemInternalData - m_windowId = (id == -1) ? NewControlId() : id; +void BumpTreeRecordIds ( + HWND hWnd +, PMYRECORD pRecord +) +{ + while(pRecord) + { + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (pRecord) + pRecord->m_ulItemId++; + } +} // end of BumpTreeRecordIds - if (parent) parent->AddChild(this); +PMYRECORD FindOS2TreeRecordByID ( + HWND hWnd +, long lItemId +) +{ + PMYRECORD pRecord = NULL; + CNRINFO vCnrInfo; + unsigned long i; + + if (!::WinSendMsg( hWnd + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + )) + return NULL; + for (i = 0; i < vCnrInfo.cRecords; i++) + { + if (i == 0) + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER) + )); + else + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (!pRecord) + return NULL; + if (pRecord->m_ulItemId == (ULONG)lItemId) + break; + } + return pRecord; +} // end of FindOS2ListRecordByID - // TODO create tree control - return FALSE; -} -wxTreeCtrl::~wxTreeCtrl() +class wxTreeTraversal { - if (m_textCtrl) +public: + wxTreeTraversal(const wxTreeCtrl* pTree) { - delete m_textCtrl; + m_pTree = pTree; } -} -// Attributes -int wxTreeCtrl::GetCount() const + // + // Do traverse the tree: visit all items (recursively by default) under the + // given one; return true if all items were traversed or false if the + // traversal was aborted because OnVisit returned false + // + bool DoTraverse( const wxTreeItemId& rRoot + ,bool bRecursively = true + ); + + // + // Override this function to do whatever is needed for each item, return + // false to stop traversing + // + virtual bool OnVisit(const wxTreeItemId& rItem) = 0; + +protected: + const wxTreeCtrl* GetTree(void) const { return m_pTree; } + +private: + bool Traverse( const wxTreeItemId& rRoot + ,bool bRecursively + ); + + const wxTreeCtrl* m_pTree; + DECLARE_NO_COPY_CLASS(wxTreeTraversal) +}; // end of CLASS wxTreeTraversal + +// +// Internal class for getting the selected items +// +class TraverseSelections : public wxTreeTraversal { - // TODO - return 0; -} +public: + TraverseSelections( const wxTreeCtrl* pTree + ,wxArrayTreeItemIds& raSelections + ) + : wxTreeTraversal(pTree) + , m_aSelections(raSelections) + { + m_aSelections.Empty(); + DoTraverse(pTree->GetRootItem()); + } -int wxTreeCtrl::GetIndent() const + virtual bool OnVisit(const wxTreeItemId& rItem) + { + // + // Can't visit a virtual node. + // + if ((GetTree()->GetRootItem() == rItem) && (GetTree()->GetWindowStyle() & wxTR_HIDE_ROOT)) + { + return true; + } + PMYRECORD pRecord = FindOS2TreeRecordByID( (HWND)GetTree()->GetHWND() + ,rItem.m_pItem + ); + if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED) + { + m_aSelections.Add(rItem); + } + return true; + } + + size_t GetCount(void) const { return m_aSelections.GetCount(); } + +private: + wxArrayTreeItemIds& m_aSelections; +}; // end of CLASS TraverseSelections + +// +// Internal class for counting tree items +// +class TraverseCounter : public wxTreeTraversal { - // TODO - return 0; -} +public: + TraverseCounter( const wxTreeCtrl* pTree + ,const wxTreeItemId& rRoot + ,bool bRecursively + ) + : wxTreeTraversal(pTree) + { + m_nCount = 0; + DoTraverse(rRoot, bRecursively); + } + + virtual bool OnVisit(const wxTreeItemId& WXUNUSED(rItem)) + { + m_nCount++; + return true; + } + + size_t GetCount(void) const { return m_nCount; } + +private: + size_t m_nCount; +}; // end of CLASS TraverseCounter + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl) + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- -void wxTreeCtrl::SetIndent(int indent) +// indices in gs_expandEvents table below +enum { - // TODO -} + IDX_COLLAPSE, + IDX_EXPAND, + IDX_WHAT_MAX +}; -wxImageList *wxTreeCtrl::GetImageList(int which) const +enum { - if ( which == wxIMAGE_LIST_NORMAL ) - { - return m_imageListNormal; - } - else if ( which == wxIMAGE_LIST_STATE ) + IDX_DONE, + IDX_DOING, + IDX_HOW_MAX +}; + +// handy table for sending events - it has to be initialized during run-time +// now so can't be const any more +static /* const */ wxEventType gs_expandEvents[IDX_WHAT_MAX][IDX_HOW_MAX]; + +/* + but logically it's a const table with the following entries: += +{ + { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING }, + { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING } +}; +*/ + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// tree traversal +// ---------------------------------------------------------------------------- + +bool wxTreeTraversal::DoTraverse ( + const wxTreeItemId& rRoot +, bool bRecursively +) +{ + if (!OnVisit(rRoot)) + return false; + + return Traverse( rRoot + ,bRecursively + ); +} // end of wxTreeTraversal::DoTraverse + +bool wxTreeTraversal::Traverse ( + const wxTreeItemId& rRoot +, bool bRecursively +) +{ + long lCookie; + wxTreeItemId vChild = m_pTree->GetFirstChild( rRoot + ,lCookie + ); + while (vChild.IsOk()) { - return m_imageListState; - } - return NULL; -} + // + // Depth first traversal + // + if (bRecursively && !Traverse(vChild, true)) + return false; + if (!OnVisit(vChild)) + return false; + vChild = m_pTree->GetNextChild( rRoot + ,lCookie + ); + } + return true; +} // end of wxTreeTraversal::Traverse -void wxTreeCtrl::SetImageList(wxImageList *imageList, int which) +// ---------------------------------------------------------------------------- +// construction and destruction +// ---------------------------------------------------------------------------- + +void wxTreeCtrl::Init () +{ + m_pImageListNormal = NULL; + m_pImageListState = NULL; + m_bOwnsImageListNormal = false; + m_bOwnsImageListState = false; + m_bHasAnyAttr = false; + m_pDragImage = NULL; + + // + // Initialize the global array of events now as it can't be done statically + // with the wxEVT_XXX values being allocated during run-time only + // + gs_expandEvents[IDX_COLLAPSE][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_COLLAPSED; + gs_expandEvents[IDX_COLLAPSE][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_COLLAPSING; + gs_expandEvents[IDX_EXPAND][IDX_DONE] = wxEVT_COMMAND_TREE_ITEM_EXPANDED; + gs_expandEvents[IDX_EXPAND][IDX_DOING] = wxEVT_COMMAND_TREE_ITEM_EXPANDING; +} // end of wxTreeCtrl::Init + +bool wxTreeCtrl::Create ( + wxWindow* pParent +, wxWindowID vId +, const wxPoint& rPos +, const wxSize& rSize +, long lStyle +, const wxValidator& rValidator +, const wxString& rsName +) { - if ( which == wxIMAGE_LIST_NORMAL ) + CNRINFO vCnrInfo; + + Init(); + if (!CreateControl( pParent + ,vId + ,rPos + ,rSize + ,lStyle + ,rValidator + ,rsName + )) + return false; + + DWORD dwStyle = WS_VISIBLE | WS_TABSTOP; + + if (m_windowStyle & wxCLIP_SIBLINGS) + dwStyle |= WS_CLIPSIBLINGS; + + // Create the tree control. + if (!OS2CreateControl( "CONTAINER" + ,dwStyle + )) + return false; + + // + // Now set the display attributes to show a TREE/ICON view of the + // OS/2 Container + // + if (!::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + )) + + vCnrInfo.flWindowAttr = CV_TREE|CV_ICON; + vCnrInfo.flWindowAttr |= CA_DRAWBITMAP; + if (m_windowStyle & wxTR_NO_LINES) + vCnrInfo.flWindowAttr |= CA_TREELINE; + + ::WinSendMsg( GetHWND() + ,CM_SETCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)CMA_FLWINDOWATTR + ); + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); + SetForegroundColour(wxWindow::GetParent()->GetForegroundColour()); + SetFont(*wxSMALL_FONT); + SetXComp(0); + SetYComp(0); + SetSize( rPos.x + ,rPos.y + ,rSize.x + ,rSize.y + ); + return true; +} // end of wxTreeCtrl::Create + +wxTreeCtrl::~wxTreeCtrl () +{ + // + // Delete any attributes + // + if (m_bHasAnyAttr) { - m_imageListNormal = imageList; + for (wxNode* pNode = m_vAttrs.Next(); pNode; pNode = m_vAttrs.Next()) + { + delete (wxTreeItemAttr *)pNode->Data(); + } + m_bHasAnyAttr = false; } - else if ( which == wxIMAGE_LIST_STATE ) + DeleteTextCtrl(); + + // + // Delete user data to prevent memory leaks + // also deletes hidden root node storage. + // + DeleteAllItems(); + if (m_bOwnsImageListNormal) + delete m_pImageListNormal; + if (m_bOwnsImageListState) + delete m_pImageListState; +} // end of wxTreeCtrl::~wxTreeCtrl + +// ---------------------------------------------------------------------------- +// accessors +// ---------------------------------------------------------------------------- + +// +// simple wrappers which add error checking in debug mode. These methods +// assume the items are properly filled out already. If not, you get errors +// +bool wxTreeCtrl::DoGetItem ( + wxTreeViewItem* pTvItem +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND() + ,pTvItem->m_ulItemId + ); + + if (!pRecord) { - m_imageListState = imageList; + wxLogLastError(wxT("Item not obtained")); + return false; } - // TODO -} + return true; +} // end of wxTreeCtrl::DoGetItem -long wxTreeCtrl::GetNextItem(long item, int code) const +void wxTreeCtrl::DoSetItem ( + wxTreeViewItem* pTvItem +) { - // TODO - return 0; -} + // + // Just invalidate the record to redisplay it + // + if (!::WinSendMsg( GetHWND() + ,CM_INVALIDATERECORD + ,MPFROMP(pTvItem) + ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED) + )); + { + wxLogLastError(wxT("CM_INVALIDATERECORD")); + } +} // end of wxTreeCtrl::DoSetItem -bool wxTreeCtrl::ItemHasChildren(long item) const +size_t wxTreeCtrl::GetCount () const { - // TODO - return FALSE; -} + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + return (size_t)vCnrInfo.cRecords; +} // end of wxTreeCtrl::GetCount -long wxTreeCtrl::GetChild(long item) const +unsigned int wxTreeCtrl::GetIndent () const { - // TODO - return 0; -} + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + return (unsigned int)vCnrInfo.cxTreeIndent; +} // end of wxTreeCtrl::GetIndent + +void wxTreeCtrl::SetIndent ( + unsigned int uIndent +) +{ + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + vCnrInfo.cxTreeIndent = (LONG)uIndent; + ::WinSendMsg( GetHWND() + ,CM_SETCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)CMA_CXTREEINDENT + ); +} // end of wxTreeCtrl::SetIndent + +wxImageList* wxTreeCtrl::GetImageList () const +{ + return m_pImageListNormal; +} // end of wxTreeCtrl::GetImageList + +#if WXWIN_COMPATIBILITY_2_4 -long wxTreeCtrl::GetParent(long item) const +wxImageList* wxTreeCtrl::GetImageList(int nVal) const { - // TODO - return 0; + return GetImageList(); } -long wxTreeCtrl::GetFirstVisibleItem() const +void wxTreeCtrl::SetImageList(wxImageList* pImageList, int nVal) { - // TODO - return 0; + SetImageList(pImageList); } -long wxTreeCtrl::GetNextVisibleItem(long item) const +int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& rItem) const { - // TODO - return 0; + return GetItemImage(rItem, wxTreeItemIcon_Selected); } -long wxTreeCtrl::GetSelection() const +void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& rItem, int nImage) { - // TODO - return 0; + SetItemImage(rItem, nImage, wxTreeItemIcon_Selected); } -long wxTreeCtrl::GetRootItem() const +#endif // WXWIN_COMPATIBILITY_2_4 + +wxImageList* wxTreeCtrl::GetStateImageList () const { - // TODO - return 0; -} + return m_pImageListNormal; +} // end of wxTreeCtrl::GetStateImageList + +// +// The SETS of imagelists really do nothing under OS2 as a RECORDCORE +// struct has the icon imbedded in it that it uses for the icon being +// displayed via the TREEITEMDESC member. Provided for interface +// compatibility only +// +void wxTreeCtrl::SetAnyImageList ( + wxImageList* WXUNUSED(pImageList) +, int WXUNUSED(nWhich) +) +{ +} // end of wxTreeCtrl::SetAnyImageList -bool wxTreeCtrl::GetItem(wxTreeItem& info) const +void wxTreeCtrl::SetImageList ( + wxImageList* WXUNUSED(pImageList) +) { - // TODO - return FALSE; -} + if (m_bOwnsImageListNormal) + delete m_pImageListNormal; + m_bOwnsImageListNormal = false; +} // end of wxTreeCtrl::SetImageList + +void wxTreeCtrl::SetStateImageList ( + wxImageList* WXUNUSED(pImageList) +) +{ + if (m_bOwnsImageListState) + delete m_pImageListState; + m_bOwnsImageListState = false; +} // end of wxTreeCtrl::SetStateImageList + +void wxTreeCtrl::AssignImageList ( + wxImageList* WXUNUSED(pImageList) +) +{ + m_bOwnsImageListNormal = true; +} // end of wxTreeCtrl::AssignImageList -bool wxTreeCtrl::SetItem(wxTreeItem& info) +void wxTreeCtrl::AssignStateImageList ( + wxImageList* WXUNUSED(pImageList) +) { - // TODO - return FALSE; -} + m_bOwnsImageListState = true; +} // end of wxTreeCtrl::AssignStateImageList -int wxTreeCtrl::GetItemState(long item, long stateMask) const +size_t wxTreeCtrl::GetChildrenCount ( + const wxTreeItemId& rItem +, bool bRecursively +) const { - wxTreeItem info; + TraverseCounter vCounter( this + ,rItem + ,bRecursively + ); + return vCounter.GetCount() - 1; +} // end of wxTreeCtrl::GetChildrenCount + +// ---------------------------------------------------------------------------- +// control colours +// ---------------------------------------------------------------------------- + +bool wxTreeCtrl::SetBackgroundColour ( + const wxColour& rColour +) +{ + ULONG ulColor = wxColourToRGB(rColour); + + if ( !wxWindowBase::SetBackgroundColour(rColour) ) + return false; + ::WinSetPresParam( GetHWND() + ,PP_BACKGROUNDCOLOR + ,sizeof(ULONG) + ,&ulColor + ); + return true; +} // end of wxTreeCtrl::SetBackgroundColour + +bool wxTreeCtrl::SetForegroundColour ( + const wxColour& rColour +) +{ + ULONG ulColor = wxColourToRGB(rColour); + + if (!wxWindowBase::SetForegroundColour(rColour)) + return false; + ::WinSetPresParam( GetHWND() + ,PP_FOREGROUNDCOLOR + ,sizeof(ULONG) + ,&ulColor + ); + return true; +} // end of wxTreeCtrl::SetForegroundColour + +// ---------------------------------------------------------------------------- +// Item access +// ---------------------------------------------------------------------------- + +wxString wxTreeCtrl::GetItemText ( + const wxTreeItemId& rItem +) const +{ + wxChar zBuf[512]; // the size is arbitrary... + wxTreeViewItem vTvItem(rItem); - info.m_mask = wxTREE_MASK_STATE ; - info.m_stateMask = stateMask; - info.m_itemId = item; + if (!DoGetItem(&vTvItem)) + { + // + // Don't return some garbage which was on stack, but an empty string + // + zBuf[0] = wxT('\0'); + } + else + strcpy(zBuf, vTvItem.m_vRecord.pszTree); + return wxString(zBuf); +} // end of wxTreeCtrl::GetItemText + +void wxTreeCtrl::SetItemText ( + const wxTreeItemId& rItem +, const wxString& rsText +) +{ + wxTreeViewItem vTvItem(rItem); + + vTvItem.m_vRecord.pszTree = (wxChar *)rsText.c_str(); // conversion is ok + DoSetItem(&vTvItem); +} // end of wxTreeCtrl::SetItemText + +// +// These functions under OS/2 PM are not needed. OS/2 containers in tree view +// provide for storing a custom expanded and collapsed icons and selected +// and non selected icons, natively. For instance, by default, a disk display +// will display a tree list of folder icons with "+" icons (collapsed) beside +// those folder which contain child members. Double clicking a folder changes +// the closed folder icon to an open folder icon with hatched selection +// highlighting indicating an ICON view container of the folder is open +// elsewhere on the desktop. So the below is not really needed, but we will +// simply return the appropriate icon requested out of OS/2's native PM +// data structures. +// +int wxTreeCtrl::DoGetItemImageFromData ( + const wxTreeItemId& WXUNUSED(rItem) +, wxTreeItemIcon nWhich +) const +{ + // + // Image handles stored in CNRINFO. + // + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + + // + // We really only have two to chose from. If not custom (set in CNRINFO + // then return the handle to system bitmap). OS/2 automatically provides + // in_use and selected bitmaps/icons + // + switch(nWhich) + { + case wxTreeItemIcon_Normal: + if (vCnrInfo.hbmCollapsed == NULLHANDLE) + return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS); + return vCnrInfo.hbmCollapsed; - if (!GetItem(info)) - return 0; - return info.m_state; + case wxTreeItemIcon_Expanded: + if (vCnrInfo.hbmExpanded == NULLHANDLE) + return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS); + return vCnrInfo.hbmExpanded; + + default: + return vCnrInfo.hbmCollapsed; + } } -bool wxTreeCtrl::SetItemState(long item, long state, long stateMask) +void wxTreeCtrl::DoSetItemImageFromData ( + const wxTreeItemId& WXUNUSED(rItem) +, int nImage +, wxTreeItemIcon nWhich +) const { - wxTreeItem info; + // + // Image handles stored in CNRINFO. + // + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + if (nWhich == wxTreeItemIcon_Normal) + vCnrInfo.hbmCollapsed = (HBITMAP)nImage; + if (nWhich == wxTreeItemIcon_Expanded) + vCnrInfo.hbmExpanded = (HBITMAP)nImage; + ::WinSendMsg( GetHWND() + ,CM_SETCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)CMA_TREEBITMAP + ); +} // end of wxTreeCtrl::DoSetItemImageFromData + +// Useless for OS/2 +void wxTreeCtrl::DoSetItemImages ( + const wxTreeItemId& rItem +, int nImage +, int nImageSel +) +{ +} // end of wxTreeCtrl::DoSetItemImages + +int wxTreeCtrl::GetItemImage ( + const wxTreeItemId& rItem +, wxTreeItemIcon nWhich +) const +{ + if (HasIndirectData(rItem)) + { + return DoGetItemImageFromData( rItem + ,nWhich + ); + } - info.m_mask = wxTREE_MASK_STATE ; - info.m_state = state; - info.m_stateMask = stateMask; - info.m_itemId = item; + CNRINFO vCnrInfo; - return SetItem(info); + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + switch (nWhich) + { + default: + wxFAIL_MSG( wxT("unknown tree item image type") ); + + case wxTreeItemIcon_Normal: + if (vCnrInfo.hbmCollapsed == NULLHANDLE) + return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEPLUS); + return vCnrInfo.hbmCollapsed; + + + case wxTreeItemIcon_Expanded: + if (vCnrInfo.hbmExpanded == NULLHANDLE) + return (int)::WinGetSysBitmap(HWND_DESKTOP, SBMP_TREEMINUS); + return vCnrInfo.hbmExpanded; + + case wxTreeItemIcon_Selected: + case wxTreeItemIcon_SelectedExpanded: + return -1; + } } -bool wxTreeCtrl::SetItemImage(long item, int image, int selImage) +void wxTreeCtrl::SetItemImage ( + const wxTreeItemId& WXUNUSED(rItem) +, int nImage +, wxTreeItemIcon nWhich +) { - wxTreeItem info; + CNRINFO vCnrInfo; + + ::WinSendMsg( GetHWND() + ,CM_QUERYCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)(USHORT)sizeof(CNRINFO) + ); + switch (nWhich) + { + case wxTreeItemIcon_Normal: + vCnrInfo.hbmCollapsed = (HBITMAP)nImage; + break; + + case wxTreeItemIcon_Expanded: + vCnrInfo.hbmExpanded = (HBITMAP)nImage; + break; - info.m_mask = wxTREE_MASK_IMAGE ; - info.m_image = image; - if ( selImage > -1) + default: + wxFAIL_MSG( wxT("unknown tree item image type") ); + } + ::WinSendMsg( GetHWND() + ,CM_SETCNRINFO + ,MPFROMP(&vCnrInfo) + ,(MPARAM)CMA_TREEBITMAP + ); +} // end of wxTreeCtrl::SetItemImage + +wxTreeItemData* wxTreeCtrl::GetItemData ( + const wxTreeItemId& rItem +) const +{ + wxTreeViewItem vTvItem(rItem); + + if (!DoGetItem(&vTvItem)) { - info.m_selectedImage = selImage; - info.m_mask |= wxTREE_MASK_SELECTED_IMAGE; + return NULL; } - info.m_itemId = item; - return SetItem(info); -} + return (wxTreeItemData *)vTvItem.m_ulUserData; +} // end of wxTreeCtrl::GetItemData -wxString wxTreeCtrl::GetItemText(long item) const +void wxTreeCtrl::SetItemData ( + const wxTreeItemId& rItem +, wxTreeItemData* pData +) { - wxTreeItem info; + // + // first, associate this piece of data with this item + if (pData) + { + pData->SetId(rItem); + } - info.m_mask = wxTREE_MASK_TEXT ; - info.m_itemId = item; + wxTreeViewItem vTvItem(rItem); - if (!GetItem(info)) - return wxString(""); - return info.m_text; -} + vTvItem.m_ulUserData = (ULONG)pData; + DoSetItem(&vTvItem); +} // end of wxTreeCtrl::SetItemData -void wxTreeCtrl::SetItemText(long item, const wxString& str) +// The following two do nothing under OS/2 +void wxTreeCtrl::SetIndirectItemData ( + const wxTreeItemId& WXUNUSED(rItem) +, wxTreeItemIndirectData* WXUNUSED(pData) +) { - wxTreeItem info; +} // end of wxTreeCtrl::SetIndirectItemData - info.m_mask = wxTREE_MASK_TEXT ; - info.m_itemId = item; - info.m_text = str; +bool wxTreeCtrl::HasIndirectData ( + const wxTreeItemId& WXUNUSED(rItem) +) const +{ + return false; +} // end of wxTreeCtrl::HasIndirectData + +// Irreleveant under OS/2 --- item either has child records or it doesn't. +void wxTreeCtrl::SetItemHasChildren ( + const wxTreeItemId& WXUNUSED(rItem) +, bool WXUNUSED(bHas) +) +{ +} // end of wxTreeCtrl::SetItemHasChildren - SetItem(info); -} +// Irreleveant under OS/2 --- function of the font in PM +void wxTreeCtrl::SetItemBold ( + const wxTreeItemId& WXUNUSED(rItem) +, bool WXUNUSED(bBold) +) +{ +} // end of wxTreeCtrl::SetItemBold -long wxTreeCtrl::GetItemData(long item) const +void wxTreeCtrl::SetItemDropHighlight ( + const wxTreeItemId& rItem +, bool bHighlight +) { - wxTreeItem info; + wxTreeViewItem vTvItem(rItem); + + ::WinSendMsg( GetHWND() + ,CM_SETRECORDEMPHASIS + ,MPFROMP(&vTvItem) + ,MPFROM2SHORT(bHighlight, CRA_SELECTED) + ); + DoSetItem(&vTvItem); +} // end of wxTreeCtrl::SetItemDropHighlight + +void wxTreeCtrl::RefreshItem ( + const wxTreeItemId& rItem +) +{ + wxTreeViewItem vTvItem(rItem); - info.m_mask = wxTREE_MASK_DATA ; - info.m_itemId = item; + // + // This just does a record invalidate causing it to be re-displayed + // + DoSetItem(&vTvItem); +} // end of wxTreeCtrl::RefreshItem - if (!GetItem(info)) - return 0; - return info.m_data; -} +wxColour wxTreeCtrl::GetItemTextColour ( + const wxTreeItemId& rItem +) const +{ + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); -bool wxTreeCtrl::SetItemData(long item, long data) + if (!pAttr) + { + return wxNullColour; + } + return pAttr->GetTextColour(); +} // end of wxTreeCtrl::GetItemTextColour + +wxColour wxTreeCtrl::GetItemBackgroundColour ( + const wxTreeItemId& rItem +) const { - wxTreeItem info; + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); - info.m_mask = wxTREE_MASK_DATA ; - info.m_itemId = item; - info.m_data = data; + if (!pAttr) + { + return wxNullColour; + } + return pAttr->GetBackgroundColour(); +} // end of wxTreeCtrl::GetItemBackgroundColour - return SetItem(info); -} +wxFont wxTreeCtrl::GetItemFont ( + const wxTreeItemId& rItem +) const +{ + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); -bool wxTreeCtrl::GetItemRect(long item, wxRect& rect, bool textOnly) const + if (!pAttr) + { + return wxNullFont; + } + return pAttr->GetFont(); +} // end of wxTreeCtrl::GetItemFont + +void wxTreeCtrl::SetItemTextColour ( + const wxTreeItemId& rItem +, const wxColour& rCol +) { - // TODO - return FALSE; -} + m_bHasAnyAttr = true; -wxTextCtrl* wxTreeCtrl::GetEditControl() const + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); + + if (!pAttr) + { + pAttr = new wxTreeItemAttr; + m_vAttrs.Put(lId, (wxObject *)pAttr); + } + pAttr->SetTextColour(rCol); + RefreshItem(rItem); +} // end of wxTreeCtrl::SetItemTextColour + +void wxTreeCtrl::SetItemBackgroundColour ( + const wxTreeItemId& rItem +, const wxColour& rCol +) { - return m_textCtrl; -} + m_bHasAnyAttr = true; + + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); + + if (!pAttr) + { + pAttr = new wxTreeItemAttr; + m_vAttrs.Put(lId, (wxObject *)pAttr); + } + pAttr->SetBackgroundColour(rCol); + RefreshItem(rItem); +} // end of wxTreeCtrl::SetItemBackgroundColour + +void wxTreeCtrl::SetItemFont ( + const wxTreeItemId& rItem +, const wxFont& rFont +) +{ + m_bHasAnyAttr = true; + + long lId = (long)rItem.m_pItem; + wxTreeItemAttr* pAttr = (wxTreeItemAttr *)m_vAttrs.Get(lId); + + if (!pAttr) + { + pAttr = new wxTreeItemAttr; + m_vAttrs.Put(lId, (wxObject *)pAttr); + } + pAttr->SetFont(rFont); + RefreshItem(rItem); +} // end of wxTreeCtrl::SetItemFont -// Operations -bool wxTreeCtrl::DeleteItem(long item) +// ---------------------------------------------------------------------------- +// Item status +// ---------------------------------------------------------------------------- + +bool wxTreeCtrl::IsVisible ( + const wxTreeItemId& rItem +) const +{ + // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect + RECTL vRectRecord; + RECTL vRectContainer; + wxRect vWxRectRecord; + wxRect vWxRectContainer; + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + QUERYRECORDRECT vQuery; + + vQuery.cb = sizeof(QUERYRECORDRECT); + vQuery.pRecord = (PRECORDCORE)pRecord; + vQuery.fRightSplitWindow = FALSE; + vQuery.fsExtent = CMA_TREEICON; + + ::WinSendMsg( GetHWND() + ,CM_QUERYVIEWPORTRECT + ,MPFROMP(&vRectContainer) + ,MPFROM2SHORT(CMA_WINDOW, FALSE) + ); + ::WinSendMsg( GetHWND() + ,CM_QUERYRECORDRECT + ,MPFROMP(&vRectRecord) + ,MPFROMP(&vQuery) + ); + vWxRectRecord.SetLeft(vRectRecord.xLeft); + vWxRectRecord.SetTop(vRectRecord.yTop); + vWxRectRecord.SetRight(vRectRecord.xRight); + vWxRectRecord.SetBottom(vRectRecord.yBottom); + + vWxRectContainer.SetLeft(vRectContainer.xLeft); + vWxRectContainer.SetTop(vRectContainer.yTop); + vWxRectContainer.SetRight(vRectContainer.xRight); + vWxRectContainer.SetBottom(vRectContainer.yBottom); + return (vWxRectContainer.Inside(wxPoint(vWxRectRecord.x, vWxRectRecord.y))); +} // end of wxTreeCtrl::IsVisible + +bool wxTreeCtrl::ItemHasChildren ( + const wxTreeItemId& rItem +) const { - // TODO - return FALSE; + wxTreeViewItem vTvItem(rItem); + DoGetItem(&vTvItem); + + // + // A tree record with children will have one of these attributes + // + return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED || + vTvItem.m_vRecord.flRecordAttr & CRA_COLLAPSED) != 0; } -bool wxTreeCtrl::ExpandItem(long item, int action) +bool wxTreeCtrl::IsExpanded ( + const wxTreeItemId& rItem +) const { - // TODO - switch ( action ) - { - case wxTREE_EXPAND_EXPAND: - break; + wxTreeViewItem vTvItem(rItem); + DoGetItem(&vTvItem); - case wxTREE_EXPAND_COLLAPSE: - break; + return (vTvItem.m_vRecord.flRecordAttr & CRA_EXPANDED) != 0; +} // end of wxTreeCtrl::IsExpanded - case wxTREE_EXPAND_COLLAPSE_RESET: - break; +bool wxTreeCtrl::IsSelected ( + const wxTreeItemId& rItem +) const +{ + wxTreeViewItem vTvItem(rItem); + DoGetItem(&vTvItem); - case wxTREE_EXPAND_TOGGLE: - break; + return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED) != 0; +} // end of wxTreeCtrl::IsSelected - default: - wxFAIL_MSG("unknown action in wxTreeCtrl::ExpandItem"); - } +// Not supported +bool wxTreeCtrl::IsBold ( + const wxTreeItemId& rItem +) const +{ + return false; +} // end of wxTreeCtrl::IsBold - bool bOk = FALSE; // TODO expand item +// ---------------------------------------------------------------------------- +// navigation +// ---------------------------------------------------------------------------- - // May not send messages, so emulate them - if ( bOk ) { - wxTreeEvent event(wxEVT_NULL, m_windowId); - event.m_item.m_itemId = item; - event.m_item.m_mask = - event.m_item.m_stateMask = 0xffff; // get all - GetItem(event.m_item); +wxTreeItemId wxTreeCtrl::GetRootItem () const +{ + PMYRECORD pRecord = NULL; - bool bIsExpanded = (event.m_item.m_state & wxTREE_STATE_EXPANDED) != 0; + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER) + )); - event.m_code = action; - event.SetEventObject(this); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetRootItem - // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded - event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDING - : wxEVT_COMMAND_TREE_ITEM_COLLAPSING); - GetEventHandler()->ProcessEvent(event); +wxTreeItemId wxTreeCtrl::GetSelection () const +{ + wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (long)(WXHTREEITEM)0, + wxT("this only works with single selection controls") ); + + PMYRECORD pRecord = NULL; + + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORDEMPHASIS + ,MPARAM(CMA_FIRST) + ,MPARAM(CRA_SELECTED) + )); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetSelection + +wxTreeItemId wxTreeCtrl::GetItemParent ( + const wxTreeItemId& rItem +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_PARENT, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetItemParent + +wxTreeItemId wxTreeCtrl::GetFirstChild ( + const wxTreeItemId& rItem +, long& rCookie +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_FIRSTCHILD, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + // + // Remember the last child returned in 'cookie' + // + rCookie = (long)pRecord->m_ulItemId; + return wxTreeItemId(rCookie); +} // end of wxTreeCtrl::GetFirstChild + +wxTreeItemId wxTreeCtrl::GetNextChild ( + const wxTreeItemId& WXUNUSED(rItem) +, long& rCookie +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rCookie + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + rCookie = (long)pRecord->m_ulItemId; + return wxTreeItemId(rCookie); +} // end of wxTreeCtrl::GetNextChild + +wxTreeItemId wxTreeCtrl::GetLastChild ( + const wxTreeItemId& rItem +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_LASTCHILD, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetLastChild + +wxTreeItemId wxTreeCtrl::GetNextSibling ( + const wxTreeItemId& rItem +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetNextSibling + +wxTreeItemId wxTreeCtrl::GetPrevSibling ( + const wxTreeItemId& rItem +) const +{ + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::GetPrevSibling + +wxTreeItemId wxTreeCtrl::GetFirstVisibleItem () const +{ + PMYRECORD pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + + if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId))) + return wxTreeItemId((long)pRecord->m_ulItemId); + while(pRecord) + { + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId))) + return wxTreeItemId((long)pRecord->m_ulItemId); + } + return wxTreeItemId(-1L); +} // end of wxTreeCtrl::GetFirstVisibleItem - event.SetEventType(bIsExpanded ? wxEVT_COMMAND_TREE_ITEM_EXPANDED - : wxEVT_COMMAND_TREE_ITEM_COLLAPSED); - GetEventHandler()->ProcessEvent(event); - } +wxTreeItemId wxTreeCtrl::GetNextVisible ( + const wxTreeItemId& rItem +) const +{ + wxASSERT_MSG(IsVisible(rItem), wxT("The item you call GetNextVisible() for must be visible itself!")); - return bOk; -} + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); -long wxTreeCtrl::InsertItem(long parent, wxTreeItem& info, long insertAfter) + if (!pRecord) + return wxTreeItemId(-1L); + while(pRecord) + { + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId))) + return wxTreeItemId((long)pRecord->m_ulItemId); + } + return wxTreeItemId(-1L); +} // end of wxTreeCtrl::GetNextVisible + +wxTreeItemId wxTreeCtrl::GetPrevVisible ( + const wxTreeItemId& rItem +) const { - // TODO - return 0; -} + wxASSERT_MSG( IsVisible(rItem), wxT("The item you call GetPrevVisible() for must be visible itself!")); -long wxTreeCtrl::InsertItem(long parent, const wxString& label, int image, int selImage, - long insertAfter) + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + + if (!pRecord) + return wxTreeItemId(-1L); + while(pRecord) + { + pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND() + ,CM_QUERYRECORD + ,MPFROMP(pRecord) + ,MPFROM2SHORT(CMA_PREV, CMA_ITEMORDER) + )); + if (!pRecord) + return wxTreeItemId(-1L); + if (IsVisible(wxTreeItemId((long)pRecord->m_ulItemId))) + return wxTreeItemId((long)pRecord->m_ulItemId); + } + return wxTreeItemId(-1L); +} // end of wxTreeCtrl::GetPrevVisible + +// ---------------------------------------------------------------------------- +// multiple selections emulation -- under OS/2 checked tree items is not +// supported, but multisel is. So we'll just check for selections here. +// ---------------------------------------------------------------------------- + +bool wxTreeCtrl::IsItemChecked ( + const wxTreeItemId& rItem +) const { - wxTreeItem info; - info.m_text = label; - info.m_mask = wxTREE_MASK_TEXT; - if ( image > -1 ) + wxTreeViewItem vTvItem(rItem); + + DoGetItem(&vTvItem); + return (vTvItem.m_vRecord.flRecordAttr & CRA_SELECTED); +} // end of wxTreeCtrl::IsItemChecked + +void wxTreeCtrl::SetItemCheck ( + const wxTreeItemId& rItem +, bool bCheck +) +{ + wxTreeViewItem vTvItem(rItem); + + DoGetItem(&vTvItem); + ::WinSendMsg( GetHWND() + ,CM_SETRECORDEMPHASIS + ,MPFROMP(&vTvItem) + ,MPFROM2SHORT(TRUE, CRA_SELECTED) + ); + DoSetItem(&vTvItem); +} // end of wxTreeCtrl::SetItemCheck + +size_t wxTreeCtrl::GetSelections ( + wxArrayTreeItemIds& raSelections +) const +{ + TraverseSelections vSelector( this + ,raSelections + ); + return vSelector.GetCount(); +} // end of wxTreeCtrl::GetSelections + +// ---------------------------------------------------------------------------- +// Usual operations +// ---------------------------------------------------------------------------- + +wxTreeItemId wxTreeCtrl::DoInsertItem ( + const wxTreeItemId& rParent +, wxTreeItemId vInsertAfter +, const wxString& rsText +, int nImage +, int selectedImage +, wxTreeItemData* pData +) +{ + PMYRECORD pRecordAfter = FindOS2TreeRecordByID( GetHWND() + ,vInsertAfter.m_pItem + ); + + PMYRECORD pRecordParent = FindOS2TreeRecordByID( GetHWND() + ,rParent.m_pItem + ); + + PMYRECORD pRecord = (PMYRECORD)::WinSendMsg( GetHWND() + ,CM_ALLOCRECORD + ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE)) + ,MPFROMLONG(1) + ); + RECORDINSERT vInsert; + + vInsert.cb = sizeof(RECORDINSERT); + if (rParent.m_pItem == 0L) { - info.m_mask |= wxTREE_MASK_IMAGE | wxTREE_MASK_SELECTED_IMAGE; - info.m_image = image; - if ( selImage == -1 ) - info.m_selectedImage = image; + if (vInsertAfter.m_pItem == -1) + vInsert.pRecordOrder = (PRECORDCORE)CMA_END; else - info.m_selectedImage = selImage; + vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST; + vInsert.pRecordParent = NULL; } - - return InsertItem(parent, info, insertAfter); + else + { + if (vInsertAfter.m_pItem == 0) + vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST; + else if (vInsertAfter.m_pItem == -1) + vInsert.pRecordOrder = (PRECORDCORE)CMA_END; + else + vInsert.pRecordOrder = (PRECORDCORE)pRecordAfter; + vInsert.pRecordParent = (PRECORDCORE)pRecordParent; + } + vInsert.fInvalidateRecord = TRUE; + vInsert.zOrder = CMA_TOP; + vInsert.cRecordsInsert = 1; + + pRecord->m_vRecord.pszTree = (wxChar*)rsText.c_str(); + pRecord->m_vRecord.hbmBitmap = nImage; + pRecord->m_ulItemId = pRecordAfter->m_ulItemId + 1; + if (pData != NULL) + { + pRecord->m_ulUserData = (ULONG)pData; + } + ::WinSendMsg( GetHWND() + ,CM_INSERTRECORD + ,MPFROMP(pRecord) + ,MPFROMP(&vInsert) + ); + + // + // OS/2 must mannually bump the index's of following records + // + BumpTreeRecordIds( GetHWND() + ,pRecord + ); + if (pData != NULL) + { + // + // Associate the application tree item with PM tree item handle + // + pData->SetId((long)pRecord->m_ulItemId); + } + return wxTreeItemId((long)pRecord->m_ulItemId); } -bool wxTreeCtrl::SelectItem(long item) +#if WXWIN_COMPATIBILITY_2_4 + +// for compatibility only +wxTreeItemId wxTreeCtrl::InsertItem ( + const wxTreeItemId& rParent +, const wxString& rsText +, int nImage +, int nSelImage +, long lInsertAfter +) +{ + return DoInsertItem( rParent + ,wxTreeItemId(lInsertAfter) + ,rsText + ,nImage + ,nSelImage + ,NULL + ); +} // end of wxTreeCtrl::InsertItem + +#endif // WXWIN_COMPATIBILITY_2_4 + +wxTreeItemId wxTreeCtrl::AddRoot ( + const wxString& rsText +, int nImage +, int nSelectedImage +, wxTreeItemData* pData) { - // TODO - return FALSE; -} -bool wxTreeCtrl::ScrollTo(long item) + return DoInsertItem( wxTreeItemId((long)0) + ,wxTreeItemId((long)-1) + ,rsText + ,nImage + ,nSelectedImage + ,pData + ); +} // end of wxTreeCtrl::AddRoot + +wxTreeItemId wxTreeCtrl::PrependItem ( + const wxTreeItemId& rParent +, const wxString& rsText +, int nImage +, int nSelectedImage +, wxTreeItemData* pData +) { - // TODO - return FALSE; -} + return DoInsertItem( rParent + ,wxTreeItemId((long)0) + ,rsText + ,nImage + ,nSelectedImage + ,pData + ); +} // end of wxTreeCtrl::PrependItem + +wxTreeItemId wxTreeCtrl::InsertItem ( + const wxTreeItemId& rParent +, const wxTreeItemId& rIdPrevious +, const wxString& rsText +, int nImage +, int nSelectedImage +, wxTreeItemData* pData +) +{ + return DoInsertItem( rParent + ,rIdPrevious + ,rsText + ,nImage + ,nSelectedImage + ,pData + ); +} // end of wxTreeCtrl::InsertItem + +wxTreeItemId wxTreeCtrl::InsertItem ( + const wxTreeItemId& rParent +, size_t nIndex +, const wxString& rsText +, int nImage +, int nSelectedImage +, wxTreeItemData* pData +) +{ + return DoInsertItem( rParent + ,wxTreeItemId((long)nIndex) + ,rsText + ,nImage + ,nSelectedImage + ,pData + ); +} // end of wxTreeCtrl::InsertItem + +wxTreeItemId wxTreeCtrl::AppendItem ( + const wxTreeItemId& rParent +, const wxString& rsText +, int nImage +, int nSelectedImage +, wxTreeItemData* pData +) +{ + return DoInsertItem( rParent + ,wxTreeItemId((long)-1) + ,rsText + ,nImage + ,nSelectedImage + ,pData + ); +} // end of wxTreeCtrl::AppendItem + +void wxTreeCtrl::Delete ( + const wxTreeItemId& rItem +) +{ + // + // OS/2 does not generate DELETEITEM events so do it here + // + wxEventType vEventType = wxEVT_NULL; + wxTreeEvent vEvent( wxEVT_NULL + ,m_windowId + ); + PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND() + ,rItem.m_pItem + ); + vEvent.SetEventObject(this); + ::WinSendMsg( GetHWND() + ,CM_REMOVERECORD + ,MPFROMP(pRecord) + ,(MPARAM)(CMA_FREE | CMA_INVALIDATE) + ); + vEvent.m_item = rItem.m_pItem; + if (m_bHasAnyAttr) + { + delete (wxTreeItemAttr *)m_vAttrs.Delete((long)rItem.m_pItem); + } + vEvent.SetEventType(vEventType); + GetEventHandler()->ProcessEvent(vEvent); +} // end of wxTreeCtrl::Delete + +// delete all children (but don't delete the item itself) +void wxTreeCtrl::DeleteChildren ( + const wxTreeItemId& rItem +) +{ + long lCookie; + wxArrayLong aChildren; + wxTreeItemId vChild = GetFirstChild( rItem + ,lCookie + ); + + while (vChild.IsOk()) + { + aChildren.Add((long)(WXHTREEITEM)vChild); + vChild = GetNextChild( rItem + ,lCookie + ); + } + + size_t nCount = aChildren.Count(); + + for (size_t n = 0; n < nCount; n++) + { + Delete(aChildren[n]); + } +} // end of wxTreeCtrl::DeleteChildren -bool wxTreeCtrl::DeleteAllItems() +void wxTreeCtrl::DeleteAllItems () { - // TODO - return FALSE; -} + ::WinSendMsg( GetHWND() + ,CM_REMOVERECORD + ,NULL // Remove all + ,(MPARAM)(CMA_FREE | CMA_INVALIDATE) + ); +} // end of wxTreeCtrl::DeleteAllItems + +void wxTreeCtrl::DoExpand ( + const wxTreeItemId& rItem +, int nFlag +) +{ + PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND() + ,rItem.m_pItem + ); + switch(nFlag) + { + case wxTREE_EXPAND_EXPAND: + ::WinSendMsg( GetHWND() + ,CM_EXPANDTREE + ,MPFROMP(pRecord) + ,NULL + ); + break; + + case wxTREE_EXPAND_COLLAPSE: + ::WinSendMsg( GetHWND() + ,CM_COLLAPSETREE + ,MPFROMP(pRecord) + ,NULL + ); + break; + + case wxTREE_EXPAND_COLLAPSE_RESET: + ::WinSendMsg( GetHWND() + ,CM_COLLAPSETREE + ,MPFROMP(pRecord) + ,NULL + ); + DeleteChildren(rItem); + break; + + case wxTREE_EXPAND_TOGGLE: + if (pRecord->m_vRecord.flRecordAttr & CRA_COLLAPSED) + ::WinSendMsg( GetHWND() + ,CM_EXPANDTREE + ,MPFROMP(pRecord) + ,NULL + ); + else if (pRecord->m_vRecord.flRecordAttr & CRA_EXPANDED) + ::WinSendMsg( GetHWND() + ,CM_COLLAPSETREE + ,MPFROMP(pRecord) + ,NULL + ); + break; + + } +} // end of wxTreeCtrl::DoExpand -wxTextCtrl* wxTreeCtrl::EditLabel(long item, wxClassInfo* textControlClass) +void wxTreeCtrl::Expand ( + const wxTreeItemId& rItem +) { - // TODO - return NULL; -} + DoExpand( rItem + ,wxTREE_EXPAND_EXPAND + ); +} // end of wxTreeCtrl::Expand + +void wxTreeCtrl::Collapse ( + const wxTreeItemId& rItem +) +{ + DoExpand( rItem + ,wxTREE_EXPAND_COLLAPSE + ); +} // end of wxTreeCtrl::Collapse + +void wxTreeCtrl::CollapseAndReset ( + const wxTreeItemId& rItem +) +{ + DoExpand( rItem + ,wxTREE_EXPAND_COLLAPSE_RESET + ); +} // end of wxTreeCtrl::CollapseAndReset + +void wxTreeCtrl::Toggle ( + const wxTreeItemId& rItem +) +{ + DoExpand( rItem + ,wxTREE_EXPAND_TOGGLE + ); +} // end of wxTreeCtrl::Toggle -// End label editing, optionally cancelling the edit -bool wxTreeCtrl::EndEditLabel(bool cancel) +#if WXWIN_COMPATIBILITY_2_4 + +void wxTreeCtrl::ExpandItem ( + const wxTreeItemId& rItem +, int nAction +) { - // TODO - return FALSE; -} + DoExpand( rItem + ,nAction + ); +} // end of wxTreeCtrl::ExpandItem + +#endif // WXWIN_COMPATIBILITY_2_4 -long wxTreeCtrl::HitTest(const wxPoint& point, int& flags) +void wxTreeCtrl::Unselect () { - // TODO - return 0; -} + wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), + wxT("doesn't make sense, may be you want UnselectAll()?") ); -bool wxTreeCtrl::SortChildren(long item) + // + // Just remove the selection + // + SelectItem(wxTreeItemId((long)0)); +} // end of wxTreeCtrl::Unselect + +void wxTreeCtrl::UnselectAll () { - // TODO - return FALSE; -} + if (m_windowStyle & wxTR_MULTIPLE) + { + wxArrayTreeItemIds aSelections; + size_t nCount = GetSelections(aSelections); + + for (size_t n = 0; n < nCount; n++) + { + SetItemCheck( aSelections[n] + ,false + ); + } + } + else + { + // + // Just remove the selection + // + Unselect(); + } +} // end of wxTreeCtrl::UnselectAll -bool wxTreeCtrl::EnsureVisible(long item) +void wxTreeCtrl::SelectItem ( + const wxTreeItemId& rItem +) { - // TODO - return FALSE; -} + SetItemCheck(rItem); +} // end of wxTreeCtrl::SelectItem -// Tree item structure -wxTreeItem::wxTreeItem() -{ - m_mask = 0; - m_itemId = 0; - m_state = 0; - m_stateMask = 0; - m_image = -1; - m_selectedImage = -1; - m_children = 0; - m_data = 0; +void wxTreeCtrl::EnsureVisible ( + const wxTreeItemId& rItem +) +{ + wxTreeViewItem vTvItem(rItem); + + DoGetItem(&vTvItem); + if (!::WinSendMsg( GetHWND() + ,CM_INVALIDATERECORD + ,MPFROMP(&vTvItem) + ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED) + )); +} // end of wxTreeCtrl::EnsureVisible + +void wxTreeCtrl::ScrollTo ( + const wxTreeItemId& rItem +) +{ + wxTreeViewItem vTvItem(rItem); + + DoGetItem(&vTvItem); + if (!::WinSendMsg( GetHWND() + ,CM_INVALIDATERECORD + ,MPFROMP(&vTvItem) + ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED) + )); } -// Tree event -IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent) +wxTextCtrl* wxTreeCtrl::EditLabel ( + const wxTreeItemId& rItem +, wxClassInfo* WXUNUSED(pTextControlClass) +) +{ + CNREDITDATA vEdit; + PMYRECORD pRecord = FindOS2TreeRecordByID( GetHWND() + ,rItem.m_pItem + ); + + vEdit.cb = sizeof(CNREDITDATA); + vEdit.hwndCnr = GetHWND(); + vEdit.pRecord = &pRecord->m_vRecord; + vEdit.pFieldInfo = NULL; + vEdit.ppszText = NULL; + vEdit.cbText = 0; + vEdit.id = 0; + + ::WinSendMsg( GetHWND() + ,CM_OPENEDIT + ,MPFROMP(&vEdit) + ,(MPARAM)0 + ); + return NULL; +} // end of wxTreeCtrl::EditLabel -wxTreeEvent::wxTreeEvent(wxEventType commandType, int id): - wxCommandEvent(commandType, id) +// End label editing, optionally cancelling the edit +void wxTreeCtrl::EndEditLabel ( + const wxTreeItemId& WXUNUSED(rItem) +, bool WXUNUSED(bDiscardChanges) +) { - m_code = 0; - m_oldItem = 0; -} + ::WinSendMsg( GetHWND() + ,CM_CLOSEEDIT + ,(MPARAM)0 + ,(MPARAM)0 + ); +} // end of wxTreeCtrl::EndEditLabel + +wxTreeItemId wxTreeCtrl::HitTest ( + const wxPoint& rPoint +, int& WXUNUSED(rFlags) +) +{ + PMYRECORD pRecord = NULL; + QUERYRECFROMRECT vQueryRect; + RECTL vRect; + long lHeight; + + // + // Get height for OS/2 point conversion + // + ::WinSendMsg( GetHWND() + ,CM_QUERYVIEWPORTRECT + ,MPFROMP(&vRect) + ,MPFROM2SHORT(CMA_WINDOW, TRUE) + ); + lHeight = vRect.yTop - vRect.yBottom; + + // + // For now just try and get a record in the general vicinity and forget + // the flag + // + vRect.xLeft = rPoint.x - 2; + vRect.xRight = rPoint.x + 2; + vRect.yTop = (lHeight - rPoint.y) + 2; + vRect.yBottom = (lHeight - rPoint.y) - 2; + + vQueryRect.cb = sizeof(QUERYRECFROMRECT); + vQueryRect.rect = vRect; + vQueryRect.fsSearch = CMA_PARTIAL; + + pRecord = (PMYRECORD)::WinSendMsg( GetHWND() + ,CM_QUERYRECORDFROMRECT + ,(MPARAM)CMA_FIRST + ,MPFROMP(&vQueryRect) + ); + + if (!pRecord) + return -1L; + return wxTreeItemId((long)pRecord->m_ulItemId); +} // end of wxTreeCtrl::HitTest + +bool wxTreeCtrl::GetBoundingRect ( + const wxTreeItemId& rItem +, wxRect& rRect +, bool bTextOnly +) const +{ + RECTL vRectRecord; + PMYRECORD pRecord = FindOS2TreeRecordByID ( GetHWND() + ,rItem.m_pItem + ); + QUERYRECORDRECT vQuery; + + vQuery.cb = sizeof(QUERYRECORDRECT); + vQuery.pRecord = (PRECORDCORE)pRecord; + vQuery.fRightSplitWindow = FALSE; + if (bTextOnly) + vQuery.fsExtent = CMA_TEXT; + else + vQuery.fsExtent = CMA_TREEICON | CMA_TEXT; + + if (!::WinSendMsg( GetHWND() + ,CM_QUERYRECORDRECT + ,MPFROMP(&vRectRecord) + ,MPFROMP(&vQuery) + )) + return false; + rRect.SetLeft(vRectRecord.xLeft); + rRect.SetTop(vRectRecord.yTop); + rRect.SetRight(vRectRecord.xRight); + rRect.SetBottom(vRectRecord.yBottom); + return true; +} // end of wxTreeCtrl::GetBoundingRect + +// ---------------------------------------------------------------------------- +// sorting stuff +// ---------------------------------------------------------------------------- + +SHORT EXPENTRY InternalDataCompareTreeFunc ( + PMYRECORD p1 +, PMYRECORD p2 +, PVOID pStorage +) +{ + wxCHECK_MSG( p1 && p2, 0, + wxT("sorting tree without data doesn't make sense") ); + + wxTreeCtrl* pTree = (wxTreeCtrl*)pStorage; + + return pTree->OnCompareItems( p1->m_ulItemId + ,p2->m_ulItemId + ); +} // end of wxTreeSortHelper::Compare + +int wxTreeCtrl::OnCompareItems ( + const wxTreeItemId& rItem1 +, const wxTreeItemId& rItem2 +) +{ + return wxStrcmp( GetItemText(rItem1) + ,GetItemText(rItem2) + ); +} // end of wxTreeCtrl::OnCompareItems + +void wxTreeCtrl::SortChildren ( + const wxTreeItemId& rItem +) +{ + ::WinSendMsg( GetHWND() + ,CM_SORTRECORD + ,(PFN)InternalDataCompareTreeFunc + ,NULL + ); +} // end of wxTreeCtrl::SortChildren + +// ---------------------------------------------------------------------------- +// implementation +// ---------------------------------------------------------------------------- + +bool wxTreeCtrl::OS2Command ( + WXUINT uCmd +, WXWORD wId +) +{ + if (uCmd == CN_ENDEDIT) + { + wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED + ,wId + ); + vEvent.SetEventObject( this ); + ProcessCommand(vEvent); + return true; + } + else if (uCmd == CN_KILLFOCUS) + { + wxCommandEvent vEvent( wxEVT_KILL_FOCUS + ,wId + ); + vEvent.SetEventObject( this ); + ProcessCommand(vEvent); + return true; + } + else + return false; +} // end of wxTreeCtrl::OS2Command + +// +// TODO: Fully implement direct manipulation when I figure it out +// +MRESULT wxTreeCtrl::OS2WindowProc ( + WXUINT uMsg +, WXWPARAM wParam +, WXLPARAM lParam +) +{ + bool bProcessed = false; + MRESULT mRc = 0; + wxTreeEvent vEvent( wxEVT_NULL + ,m_windowId + ); + wxEventType vEventType = wxEVT_NULL; + PCNRDRAGINIT pDragInit = NULL; + PCNREDITDATA pEditData = NULL; + PNOTIFYRECORDENTER pNotifyEnter = NULL; + + vEvent.SetEventObject(this); + switch (uMsg) + { + case WM_CONTROL: + switch(SHORT2FROMMP(wParam)) + { + case CN_INITDRAG: + pDragInit = (PCNRDRAGINIT)lParam; + if (pDragInit) + { + PMYRECORD pRecord = (PMYRECORD)pDragInit->pRecord; + + vEventType = wxEVT_COMMAND_TREE_BEGIN_DRAG; + vEvent.m_item = pRecord->m_ulItemId; + vEvent.m_pointDrag.x = pDragInit->x; + vEvent.m_pointDrag.y = pDragInit->y; + } + break; + + case CN_BEGINEDIT: + pEditData = (PCNREDITDATA)lParam; + if (pEditData) + { + PMYRECORD pRecord = (PMYRECORD)pEditData->pRecord; + + vEventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT; + vEvent.m_item = pRecord->m_ulItemId; + vEvent.m_label = pRecord->m_vRecord.pszTree; + vEvent.m_editCancelled = false; + } + break; + + case CN_ENDEDIT: + pEditData = (PCNREDITDATA)lParam; + if (pEditData) + { + PMYRECORD pRecord = (PMYRECORD)pEditData->pRecord; + + vEventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT; + vEvent.m_item = pRecord->m_ulItemId; + vEvent.m_label = pRecord->m_vRecord.pszTree; + if (pRecord->m_vRecord.pszTree == NULL) + { + vEvent.m_editCancelled = true; + } + else + { + vEvent.m_editCancelled = false; + } + } + break; + + case CN_EXPANDTREE: + { + PMYRECORD pRecord = (PMYRECORD)lParam; + + vEventType = gs_expandEvents[IDX_EXPAND][IDX_DONE]; + vEvent.m_item = pRecord->m_ulItemId; + } + break; + } + vEvent.SetEventType(vEventType); + bProcessed = GetEventHandler()->ProcessEvent(vEvent); + break; + } + if (!bProcessed) + mRc = wxControl::OS2WindowProc( uMsg + ,wParam + ,lParam + ); + return mRc; +} // end of wxTreeCtrl::OS2WindowProc + +#endif // wxUSE_TREECTRL