]> git.saurik.com Git - wxWidgets.git/commitdiff
wxMSW::wxTreeCtrl has multiple selection too (somewhat documented)
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 30 Jul 1999 22:45:55 +0000 (22:45 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 30 Jul 1999 22:45:55 +0000 (22:45 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3220 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/latex/wx/treectrl.tex
include/wx/generic/treectrl.h
include/wx/msw/treectrl.h
samples/treectrl/treetest.cpp
samples/treectrl/treetest.h
src/generic/treectrl.cpp
src/msw/treectrl.cpp

index f150147bfd848d81fb7dd9efb5e3317f2d286429..6e5b52fb27641b0fb8b44d858be1b54158c8d1a0 100644 (file)
@@ -24,6 +24,9 @@ To intercept events from a tree control, use the event table macros described in
 left of parent items.}
 \twocolitem{\windowstyle{wxTR\_EDIT\_LABELS}}{Use this style if you wish the user to be
 able to edit labels in the tree control.}
+\twocolitem{\windowstyle{wxTR\_MULTIPLE}}{Use this style to allow the user to
+select more than one item in the control - by default, only one item may be
+selected.}
 \end{twocollist}
 
 See also \helpref{window styles overview}{windowstyles}.
@@ -385,6 +388,18 @@ Gets the selected item image.
 \constfunc{wxTreeItemId}{GetSelection}{\void}
 
 Returns the selection, or an invalid item if there is no selection.
+This function only works with the controls without wxTR\_MULTIPLE style, use 
+\helpref{GetSelections}{wxtreectrlgetselections} for the controls which do have
+this style.
+
+\membersection{wxTreeCtrl::GetSelections}\label{wxtreectrlgetselections}
+
+\constfunc{size\_t}{GetSelections}{\param{wxArrayTreeItemIds\& }{selection}}
+
+Fills the array of tree items passed in with the currently selected items. This
+function can be called only if the control has the wxTR\_MULTIPLE style.
+
+Returns the number of selected items.
 
 \membersection{wxTreeCtrl::HitTest}\label{wxtreectrlhittest}
 
@@ -572,6 +587,14 @@ Toggles the given item between collapsed and expanded states.
 
 Removes the selection from the currently selected item (if any).
 
+\membersection{wxTreeCtrl::UnselectAll}\label{wxtreectrlunselectall}
+
+\func{void}{UnselectAll}{\void}
+
+This function either behaves the same as \helpref{Unselect}{wxtreectrlunselect} 
+if the control doesn't have wxTR\_MULTIPLE style, or removes the selection from
+all items if it does have this style.
+
 \section{\class{wxTreeItemData}}\label{wxtreeitemdata}
 
 wxTreeItemData is some (arbitrary) user class associated with some item. The
index 7720cddc91923bb519d74e5ef2a071f5f7180110..43718e0469f1e18cb27d0e5c16eefe750a542dfe 100644 (file)
@@ -32,7 +32,7 @@ WXDLLEXPORT_DATA(extern const char*) wxTreeCtrlNameStr;
 #include "wx/dynarray.h"
 #include "wx/timer.h"
 
-//those defines should only be done in generic/treectrl.h, 
+//those defines should only be done in generic/treectrl.h,
 //because wxMSW doesn't allow mutiple selection
 
 #ifndef wxTR_SINGLE
@@ -177,7 +177,7 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
 
   public:
     wxTreeTextCtrl(void) {};
-    wxTreeTextCtrl( wxWindow *parent, const wxWindowID id, 
+    wxTreeTextCtrl( wxWindow *parent, const wxWindowID id,
                     bool *accept, wxString *res, wxTreeCtrl *owner,
                     const wxString &value = "",
                     const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize,
@@ -185,7 +185,7 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
                     const wxString &name = "wxTreeTextCtrlText" );
     void OnChar( wxKeyEvent &event );
     void OnKillFocus( wxFocusEvent &event );
-    
+
   DECLARE_EVENT_TABLE()
 };
 
@@ -231,10 +231,10 @@ public:
     unsigned int GetIndent() const { return m_indent; }
     void SetIndent(unsigned int indent);
 
-       // spacing is the number of pixels between the start and the Text
+        // spacing is the number of pixels between the start and the Text
     unsigned int GetSpacing() const { return m_spacing; }
     void SetSpacing(unsigned int spacing);
-    
+
         // image list: these functions allow to associate an image list with
         // the control and retrieve it. Note that the control does _not_ delete
         // the associated image list when it's deleted in order to allow image
@@ -420,7 +420,7 @@ public:
         // been before.
     void EditLabel( const wxTreeItemId& item ) { Edit( item ); }
     void Edit( const wxTreeItemId& item );
-    
+
     // sorting
         // this function is called to compare 2 items and should return -1, 0
         // or +1 if the first item is less than, equal to or greater than the
@@ -447,7 +447,7 @@ public:
     // Draw Special Information
     void DrawBorder(wxTreeItemId& item);
     void DrawLine(wxTreeItemId& item, bool below);
-    
+
 protected:
     friend class wxGenericTreeItem;
     friend class wxTreeRenameTimer;
@@ -491,7 +491,7 @@ protected:
 
     void RefreshSubtree( wxGenericTreeItem *item );
     void RefreshLine( wxGenericTreeItem *item );
-    
+
     void OnRenameTimer();
     void OnRenameAccept();
 
index 213b4934ff2c9fc75df4132e40e38261addaaccc..66871a4891112ede0857539ca40d7428dcaef8e2 100644 (file)
@@ -121,6 +121,8 @@ protected:
     long m_itemId;
 };
 
+WX_DEFINE_ARRAY(wxTreeItemId, wxArrayTreeItemIds);
+
 // ----------------------------------------------------------------------------
 // wxTreeItemData is some (arbitrary) user class associated with some item. The
 // main advantage of having this class (compared to old untyped interface) is
@@ -275,7 +277,8 @@ public:
 
         // if 'recursively' is FALSE, only immediate children count, otherwise
         // the returned number is the number of all items in this branch
-    size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = TRUE);
+    size_t GetChildrenCount(const wxTreeItemId& item,
+                            bool recursively = TRUE) const;
 
     // navigation
     // ----------
@@ -288,6 +291,12 @@ public:
         // get the item currently selected (may return NULL if no selection)
     wxTreeItemId GetSelection() const;
 
+        // get the items currently selected, return the number of such item
+        //
+        // NB: this operation is expensive and can take a long time for a
+        //     control with a lot of items (~ O(number of items)).
+    size_t GetSelections(wxArrayTreeItemIds& selections) const;
+
         // get the parent of this item (may return NULL if root)
     wxTreeItemId GetParent(const wxTreeItemId& item) const;
 
@@ -365,6 +374,8 @@ public:
 
         // remove the selection from currently selected item (if any)
     void Unselect();
+        // unselect all items (only makes sense for multiple selection control)
+    void UnselectAll();
         // select this item
     void SelectItem(const wxTreeItemId& item);
         // make sure this item is visible (expanding the parent item and/or
@@ -445,6 +456,10 @@ public:
     virtual bool MSWCommand(WXUINT param, WXWORD id);
     virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
 
+    // get/set the check state for the item (only for wxTR_MULTIPLE)
+    bool IsItemChecked(const wxTreeItemId& item) const;
+    void SetItemCheck(const wxTreeItemId& item, bool check = TRUE);
+
 protected:
     // SetImageList helper
     void SetAnyImageList(wxImageList *imageList, int which);
@@ -469,6 +484,8 @@ private:
                               int image, int selectedImage,
                               wxTreeItemData *data);
 
+    void DoSetItemImages(const wxTreeItemId& item, int image, int imageSel);
+
     void DeleteTextCtrl();
 
     DECLARE_DYNAMIC_CLASS(wxTreeCtrl)
index c626ea433fefa2db9fc93921f15b479a17c7843c..6b585f079cefdaf1b3f52bc32d98b724d4d329f7 100644 (file)
 
 #include "math.h"
 
-#include "treetest.h"
-
 #ifdef __WXMSW__
-    #define NO_ADVANCED_FEATURES
+    //#define NO_MULTIPLE_SELECTION
+    #define NO_VARIABLE_HEIGHT
 #endif
 
+#include "treetest.h"
+
 // under Windows the icons are in the .rc file
 #ifndef __WXMSW__
   #include "icon1.xpm"
@@ -59,7 +60,11 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(TreeTest_Quit, MyFrame::OnQuit)
     EVT_MENU(TreeTest_About, MyFrame::OnAbout)
     EVT_MENU(TreeTest_Dump, MyFrame::OnDump)
-    EVT_MENU(TreeTest_Dump_Selected, MyFrame::OnDumpSelected)
+#ifndef NO_MULTIPLE_SELECTION
+    EVT_MENU(TreeTest_DumpSelected, MyFrame::OnDumpSelected)
+    EVT_MENU(TreeTest_Select, MyFrame::OnSelect)
+    EVT_MENU(TreeTest_Unselect, MyFrame::OnUnselect)
+#endif // NO_MULTIPLE_SELECTION
     EVT_MENU(TreeTest_Rename, MyFrame::OnRename)
     EVT_MENU(TreeTest_Sort, MyFrame::OnSort)
     EVT_MENU(TreeTest_SortRev, MyFrame::OnSortRev)
@@ -76,6 +81,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(TreeTest_DecIndent, MyFrame::OnDecIndent)
     EVT_MENU(TreeTest_IncSpacing, MyFrame::OnIncSpacing)
     EVT_MENU(TreeTest_DecSpacing, MyFrame::OnDecSpacing)
+    EVT_MENU(TreeTest_ToggleIcon, MyFrame::OnToggleIcon)
 END_EVENT_TABLE()
 
 BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
@@ -153,14 +159,20 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
     tree_menu->Append(TreeTest_DecSpacing, "Reduce spacing by 5 points\tCtrl-R");
 
     item_menu->Append(TreeTest_Dump, "&Dump item children");
-#ifndef NO_ADVANCED_FEATURES
-    item_menu->Append(TreeTest_Dump_Selected, "Dump selected items\tAlt-S");
-#endif
     item_menu->Append(TreeTest_Rename, "&Rename item...");
 
     item_menu->AppendSeparator();
     item_menu->Append(TreeTest_Bold, "Make item &bold");
     item_menu->Append(TreeTest_UnBold, "Make item &not bold");
+    item_menu->AppendSeparator();
+    item_menu->Append(TreeTest_ToggleIcon, "Toggle the items &icon");
+
+#ifndef NO_MULTIPLE_SELECTION
+    item_menu->AppendSeparator();
+    item_menu->Append(TreeTest_DumpSelected, "Dump selected items\tAlt-D");
+    item_menu->Append(TreeTest_Select, "Select current item\tAlt-S");
+    item_menu->Append(TreeTest_Unselect, "Unselect everything\tAlt-U");
+#endif
 
     wxMenuBar *menu_bar = new wxMenuBar;
     menu_bar->Append(file_menu, "&File");
@@ -172,10 +184,8 @@ MyFrame::MyFrame(const wxString& title, int x, int y, int w, int h)
                                 wxDefaultPosition, wxDefaultSize,
                                 wxTR_HAS_BUTTONS |
                                 wxTR_EDIT_LABELS |
-#ifndef NO_ADVANCED_FEATURES
                                 wxTR_MULTIPLE |
                                 wxTR_HAS_VARIABLE_ROW_HEIGHT |
-#endif
                                 wxSUNKEN_BORDER);
     wxTextCtrl *textCtrl = new wxTextCtrl(this, -1, "",
                                 wxDefaultPosition, wxDefaultSize,
@@ -268,20 +278,33 @@ void MyFrame::OnDump(wxCommandEvent& WXUNUSED(event))
     m_treeCtrl->GetItemsRecursively(root, -1);
 }
 
+#ifndef NO_MULTIPLE_SELECTION
+
 void MyFrame::OnDumpSelected(wxCommandEvent& WXUNUSED(event))
 {
-#ifndef NO_ADVANCED_FEATURES
-   wxArrayTreeItemIds array;
+    wxArrayTreeItemIds array;
 
-    m_treeCtrl->GetSelections(array);
-    size_t nos=array.Count();
-    wxLogMessage(wxString("items selected : ")<< (int)nos);
+    size_t count = m_treeCtrl->GetSelections(array);
+    wxLogMessage(_T("%u items selected"), count);
 
-    for (size_t n=0; n<nos; ++n)
-      wxLogMessage(m_treeCtrl->GetItemText(array.Item(n)));
-#endif
+    for ( size_t n = 0; n < count; n++ )
+    {
+        wxLogMessage("\t%s", m_treeCtrl->GetItemText(array.Item(n)).c_str());
+    }
+}
+
+void MyFrame::OnSelect(wxCommandEvent& event)
+{
+    m_treeCtrl->SelectItem(m_treeCtrl->GetSelection());
+}
+
+void MyFrame::OnUnselect(wxCommandEvent& event)
+{
+    m_treeCtrl->UnselectAll();
 }
 
+#endif // NO_MULTIPLE_SELECTION
+
 void MyFrame::DoSetBold(bool bold)
 {
     wxTreeItemId item = m_treeCtrl->GetSelection();
@@ -370,6 +393,15 @@ void MyFrame::OnDecSpacing(wxCommandEvent& WXUNUSED(event))
         m_treeCtrl->SetSpacing( indent-5 );
 }
 
+void MyFrame::OnToggleIcon(wxCommandEvent& WXUNUSED(event))
+{
+    wxTreeItemId item = m_treeCtrl->GetSelection();
+
+    CHECK_ITEM( item );
+
+    m_treeCtrl->DoToggleIcon(item);
+}
+
 // MyTreeCtrl implementation
 IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)
 
@@ -379,7 +411,7 @@ MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
           : wxTreeCtrl(parent, id, pos, size, style)
 {
 #if (USE_TR_HAS_VARIABLE_ROW_HIGHT && wxUSE_LIBJPEG)
-    wxImage::AddHandler(new wxJPEGHandler); 
+    wxImage::AddHandler(new wxJPEGHandler);
     wxImage image;
 
     image.LoadFile(wxString("horse.jpg"), wxBITMAP_TYPE_JPEG );
@@ -450,8 +482,7 @@ void MyTreeCtrl::AddItemsRecursively(const wxTreeItemId& idParent,
             else
                 str.Printf("%s child %d", "Folder", n + 1);
 
-//            int image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder;
-            int image = depth == 1 ? -1 : TreeCtrlIcon_Folder;
+            int image = depth == 1 ? TreeCtrlIcon_File : TreeCtrlIcon_Folder;
             wxTreeItemId id = AppendItem(idParent, str, image, image,
                                          new MyTreeItemData(str));
 
@@ -489,7 +520,7 @@ void MyTreeCtrl::GetItemsRecursively(const wxTreeItemId& idParent, long cookie)
     if(id <= 0)
         return;
 
-    wxString text=GetItemText(id);
+    wxString text = GetItemText(id);
     wxLogMessage(text);
 
     if (ItemHasChildren(id))
@@ -498,6 +529,14 @@ void MyTreeCtrl::GetItemsRecursively(const wxTreeItemId& idParent, long cookie)
     GetItemsRecursively(idParent, cookie);
 }
 
+void MyTreeCtrl::DoToggleIcon(const wxTreeItemId& item)
+{
+    int image = GetItemImage(item) == TreeCtrlIcon_Folder ? TreeCtrlIcon_File
+                                                          : TreeCtrlIcon_Folder;
+
+    SetItemImage(item, image);
+}
+
 
 // avoid repetition
 #define TREE_EVENT_HANDLER(name)                            \
index 12c6b2245b1791be30a4efacc3f1493df8efc85a..dec33dc30a8434864c1b3d1e152facdf31df8414 100644 (file)
@@ -65,9 +65,11 @@ public:
     void AddTestItemsToTree(size_t numChildren, size_t depth);
 
     void DoSortChildren(const wxTreeItemId& item, bool reverse = FALSE)
-    { m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }
+        { m_reverseSort = reverse; wxTreeCtrl::SortChildren(item); }
     void DoEnsureVisible() { EnsureVisible(m_lastItem); }
 
+    void DoToggleIcon(const wxTreeItemId& item);
+
 protected:
     virtual int OnCompareItems(const wxTreeItemId& i1, const wxTreeItemId& i2);
 
@@ -109,7 +111,11 @@ public:
     void OnAbout(wxCommandEvent& event);
 
     void OnDump(wxCommandEvent& event);
+#ifndef NO_MULTIPLE_SELECTION
     void OnDumpSelected(wxCommandEvent& event);
+    void OnSelect(wxCommandEvent& event);
+    void OnUnselect(wxCommandEvent& event);
+#endif // NO_MULTIPLE_SELECTION
     void OnDelete(wxCommandEvent& event);
     void OnDeleteChildren(wxCommandEvent& event);
     void OnDeleteAll(wxCommandEvent& event);
@@ -126,13 +132,15 @@ public:
     void OnSortRev(wxCommandEvent& event) { DoSort(TRUE); }
 
     void OnAddItem(wxCommandEvent& event);
-    
+
     void OnIncIndent(wxCommandEvent& event);
     void OnDecIndent(wxCommandEvent& event);
 
     void OnIncSpacing(wxCommandEvent& event);
     void OnDecSpacing(wxCommandEvent& event);
 
+    void OnToggleIcon(wxCommandEvent& event);
+
 private:
     void DoSort(bool reverse = FALSE);
 
@@ -149,7 +157,7 @@ enum
     TreeTest_Quit,
     TreeTest_About,
     TreeTest_Dump,
-    TreeTest_Dump_Selected,
+    TreeTest_DumpSelected,
     TreeTest_Sort,
     TreeTest_SortRev,
     TreeTest_Bold,
@@ -166,5 +174,8 @@ enum
     TreeTest_DecIndent,
     TreeTest_IncSpacing,
     TreeTest_DecSpacing,
-    TreeTest_Ctrl = 100
+    TreeTest_ToggleIcon,
+    TreeTest_Select,
+    TreeTest_Unselect,
+    TreeTest_Ctrl = 1000
 };
index cffc64230c80522a59db6a066d8a5f5eb57ebe6c..1e6e00823134b64895205db0f2d339208dae7731 100644 (file)
@@ -203,14 +203,14 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
     {
         (*m_accept) = TRUE;
         (*m_res) = GetValue();
-       m_owner->SetFocus();
+        m_owner->SetFocus();
         return;
     }
     if (event.m_keyCode == WXK_ESCAPE)
     {
         (*m_accept) = FALSE;
         (*m_res) = "";
-       m_owner->SetFocus();
+        m_owner->SetFocus();
         return;
     }
     event.Skip();
@@ -221,7 +221,7 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
     if (wxPendingDelete.Member(this)) return;
 
     wxPendingDelete.Append(this);
-    
+
     if ((*m_accept) && ((*m_res) != m_startValue))
         m_owner->OnRenameAccept();
 }
@@ -232,7 +232,7 @@ void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
 // -----------------------------------------------------------------------------
 
 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
-  
+
 wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
            : wxNotifyEvent( commandType, id )
 {
@@ -463,7 +463,7 @@ void wxTreeCtrl::Init()
   m_imageListState = (wxImageList *) NULL;
 
   m_dragCount = 0;
-  
+
   m_renameTimer = new wxTreeRenameTimer( this );
 }
 
@@ -493,7 +493,7 @@ wxTreeCtrl::~wxTreeCtrl()
   wxDELETE( m_hilightBrush );
 
   DeleteAllItems();
-  
+
   delete m_renameTimer;
 }
 
@@ -1143,16 +1143,18 @@ void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     GetEventHandler()->ProcessEvent( event );
 }
 
-void wxTreeCtrl::FillArray(wxGenericTreeItem *item, wxArrayTreeItemIds &array) const
+void wxTreeCtrl::FillArray(wxGenericTreeItem *item,
+                           wxArrayTreeItemIds &array) const
 {
-  if (item->HasHilight()) array.Add(wxTreeItemId(item));
+    if ( item->HasHilight() )
+        array.Add(wxTreeItemId(item));
 
-  if (item->HasChildren())
+    if ( item->HasChildren() )
     {
-      wxArrayGenericTreeItems& children = item->GetChildren();
-      size_t count = children.Count();
-      for ( size_t n = 0; n < count; ++n )
-        FillArray(children[n],array);
+        wxArrayGenericTreeItems& children = item->GetChildren();
+        size_t count = children.GetCount();
+        for ( size_t n = 0; n < count; ++n )
+            FillArray(children[n],array);
     }
 }
 
@@ -1445,12 +1447,12 @@ void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &
             dc.SetPen( *wxGREY_PEN );
             dc.SetBrush( *wxWHITE_BRUSH );
             dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 );
-            
+
             dc.SetPen( *wxBLACK_PEN );
             dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y );
             if (!item->IsExpanded())
                 dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 );
-                
+
             dc.SetPen( m_dottedPen );
         }
 
@@ -1793,20 +1795,20 @@ void wxTreeCtrl::Edit( const wxTreeItemId& item )
     if (!item.IsOk()) return;
 
     m_currentEdit = item.m_pItem;
-    
+
     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
     te.m_item = m_currentEdit;
     te.SetEventObject( this );
     GetEventHandler()->ProcessEvent( te );
 
     if (!te.IsAllowed()) return;
-    
+
     wxString s = m_currentEdit->GetText();
     int x = m_currentEdit->GetX();
     int y = m_currentEdit->GetY();
     int w = m_currentEdit->GetWidth();
     int h = m_currentEdit->GetHeight();
-    
+
     int image_h = 0;
     int image_w = 0;
     if ((m_currentEdit->IsExpanded()) && (m_currentEdit->GetSelectedImage() != -1))
@@ -1844,12 +1846,12 @@ void wxTreeCtrl::OnRenameAccept()
     le.SetEventObject( this );
     le.m_label = m_renameRes;
     GetEventHandler()->ProcessEvent( le );
-    
+
     if (!le.IsAllowed()) return;
-    
+
     SetItemText( m_currentEdit, m_renameRes );
 }
-    
+
 void wxTreeCtrl::OnMouse( wxMouseEvent &event )
 {
     if (!event.LeftIsDown()) m_dragCount = 0;
@@ -1887,14 +1889,14 @@ void wxTreeCtrl::OnMouse( wxMouseEvent &event )
         return;
     }
 
-    if (event.LeftUp() && (item == m_current) && 
-        (flags & wxTREE_HITTEST_ONITEMLABEL) && 
-       HasFlag(wxTR_EDIT_LABELS) )
+    if (event.LeftUp() && (item == m_current) &&
+        (flags & wxTREE_HITTEST_ONITEMLABEL) &&
+        HasFlag(wxTR_EDIT_LABELS) )
     {
         m_renameTimer->Start( 100, TRUE );
         return;
     }
-    
+
     bool is_multiple=(GetWindowStyleFlag() & wxTR_MULTIPLE);
     bool extended_select=(event.ShiftDown() && is_multiple);
     bool unselect_others=!(extended_select || (event.ControlDown() && is_multiple));
@@ -1937,7 +1939,7 @@ void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
 {
     long text_w = 0;
     long text_h = 0;
-    
+
     wxFont fontOld;
     wxFont fontNew;
     if (item->IsBold())
@@ -1958,14 +1960,14 @@ void wxTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
             wxFAIL_MSG(_T("wxDC::GetFont() failed!"));
         }
     }
-    
+
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
     text_h+=2;
 
     // restore normal font for bold items
     if (fontOld.Ok())
         dc.SetFont( fontOld);
-    
+
     int image_h = 0;
     int image_w = 0;
     if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
index b7a04734283a6c5abefc82aadf024a174bf7fc9a..c3eb0e1d4fb89e6173d0560c59a6afe14e96ab34 100644 (file)
 #include "wx/window.h"
 #include "wx/msw/private.h"
 
-#ifndef WX_PRECOMP
-    #include "wx/settings.h"
-#endif
-
 // Mingw32 is a bit mental even though this is done in winundef
 #ifdef GetFirstChild
     #undef GetFirstChild
 // a convenient wrapper around TV_ITEM struct which adds a ctor
 struct wxTreeViewItem : public TV_ITEM
 {
-    wxTreeViewItem(const wxTreeItemId& item,
-                   UINT mask_, UINT stateMask_ = 0)
+    wxTreeViewItem(const wxTreeItemId& item,    // the item handle
+                   UINT mask_,                  // fields which are valid
+                   UINT stateMask_ = 0)         // for TVIF_STATE only
     {
-        mask = mask_;
+        // hItem member is always valid
+        mask = mask_ | TVIF_HANDLE;
         stateMask = stateMask_;
         hItem = (HTREEITEM) (WXHTREEITEM) item;
     }
 };
 
+// a class which encapsulates the tree traversal logic: it vists all (unless
+// OnVisit() returns FALSE) items under the given one
+class wxTreeTraversal
+{
+public:
+    wxTreeTraversal(const wxTreeCtrl *tree)
+    {
+        m_tree = tree;
+    }
+
+    // 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& root, bool recursively = TRUE);
+
+    // override this function to do whatever is needed for each item, return
+    // FALSE to stop traversing
+    virtual bool OnVisit(const wxTreeItemId& item) = 0;
+
+protected:
+    const wxTreeCtrl *GetTree() const { return m_tree; }
+
+private:
+    bool Traverse(const wxTreeItemId& root, bool recursively);
+
+    const wxTreeCtrl *m_tree;
+};
+
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
@@ -102,6 +128,37 @@ static const wxEventType g_events[2][2] =
 // implementation
 // ============================================================================
 
+// ----------------------------------------------------------------------------
+// tree traversal
+// ----------------------------------------------------------------------------
+
+bool wxTreeTraversal::DoTraverse(const wxTreeItemId& root, bool recursively)
+{
+    if ( !OnVisit(root) )
+        return FALSE;
+
+    return Traverse(root, recursively);
+}
+
+bool wxTreeTraversal::Traverse(const wxTreeItemId& root, bool recursively)
+{
+    long cookie;
+    wxTreeItemId child = m_tree->GetFirstChild(root, cookie);
+    while ( child.IsOk() )
+    {
+        // depth first traversal
+        if ( recursively && !Traverse(child, TRUE) )
+            return FALSE;
+
+        if ( !OnVisit(child) )
+            return FALSE;
+
+        child = m_tree->GetNextChild(root, cookie);
+    }
+
+    return TRUE;
+}
+
 // ----------------------------------------------------------------------------
 // construction and destruction
 // ----------------------------------------------------------------------------
@@ -113,37 +170,22 @@ void wxTreeCtrl::Init()
     m_textCtrl = NULL;
 }
 
-bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
-                        const wxPoint& pos, const wxSize& size,
-                        long style, const wxValidator& validator,
+bool wxTreeCtrl::Create(wxWindow *parent,
+                        wxWindowID id,
+                        const wxPoint& pos,
+                        const wxSize& size,
+                        long style,
+                        const wxValidator& validator,
                         const wxString& name)
 {
     Init();
 
-    wxSystemSettings settings;
-
-    SetName(name);
-    SetValidator(validator);
-
-    m_windowStyle = style;
-
-    SetParent(parent);
-
-    m_windowId = (id == -1) ? NewControlId() : id;
+    if ( !CreateControl(parent, id, pos, size, style, validator, name) )
+        return FALSE;
 
     DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
                    TVS_HASLINES | TVS_SHOWSELALWAYS;
 
-    bool want3D;
-    WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
-
-    // Even with extended styles, need to combine with WS_BORDER
-    // for them to look right.
-    if ( want3D || wxStyleHasBorder(m_windowStyle) )
-    {
-        wstyle |= WS_BORDER;
-    }
-
     if ( m_windowStyle & wxTR_HAS_BUTTONS )
         wstyle |= TVS_HASBUTTONS;
 
@@ -153,26 +195,67 @@ bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
     if ( m_windowStyle & wxTR_LINES_AT_ROOT )
         wstyle |= TVS_LINESATROOT;
 
+    // we emulate the multiple selection tree controls by using checkboxes: set
+    // up the image list we need for this if we do have multiple selections
+    if ( m_windowStyle & wxTR_MULTIPLE )
+        wstyle |= TVS_CHECKBOXES;
+
     // Create the tree control.
-    m_hWnd = (WXHWND)::CreateWindowEx
-                       (
-                        exStyle,
-                        WC_TREEVIEW,
-                        _T(""),
-                        wstyle,
-                        pos.x, pos.y, size.x, size.y,
-                        (HWND)parent->GetHWND(),
-                        (HMENU)m_windowId,
-                        wxGetInstance(),
-                        NULL
-                       );
-
-    wxCHECK_MSG( m_hWnd, FALSE, _T("Failed to create tree ctrl") );
-
-    if ( parent )
-        parent->AddChild(this);
-
-    SubclassWin(m_hWnd);
+    if ( !MSWCreateControl(WC_TREEVIEW, wstyle) )
+        return FALSE;
+
+    // VZ: this is some experimental code which may be used to get the
+    //     TVS_CHECKBOXES style functionality for comctl32.dll < 4.71.
+    //     AFAIK, the standard DLL does about the same thing anyhow.
+#if 0
+    if ( m_windowStyle & wxTR_MULTIPLE )
+    {
+        wxBitmap bmp;
+
+        // create the DC compatible with the current screen
+        HDC hdcMem = CreateCompatibleDC(NULL);
+
+        // create a mono bitmap of the standard size
+        int x = GetSystemMetrics(SM_CXMENUCHECK);
+        int y = GetSystemMetrics(SM_CYMENUCHECK);
+        wxImageList imagelistCheckboxes(x, y, FALSE, 2);
+        HBITMAP hbmpCheck = CreateBitmap(x, y,   // bitmap size
+                                         1,      // # of color planes
+                                         1,      // # bits needed for one pixel
+                                         0);     // array containing colour data
+        SelectObject(hdcMem, hbmpCheck);
+
+        // then draw a check mark into it
+        RECT rect = { 0, 0, x, y };
+        if ( !::DrawFrameControl(hdcMem, &rect,
+                                 DFC_BUTTON,
+                                 DFCS_BUTTONCHECK | DFCS_CHECKED) )
+        {
+            wxLogLastError(_T("DrawFrameControl(check)"));
+        }
+
+        bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
+        imagelistCheckboxes.Add(bmp);
+
+        if ( !::DrawFrameControl(hdcMem, &rect,
+                                 DFC_BUTTON,
+                                 DFCS_BUTTONCHECK) )
+        {
+            wxLogLastError(_T("DrawFrameControl(uncheck)"));
+        }
+
+        bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
+        imagelistCheckboxes.Add(bmp);
+
+        // clean up
+        ::DeleteDC(hdcMem);
+
+        // set the imagelist
+        SetStateImageList(&imagelistCheckboxes);
+    }
+#endif // 0
+
+    SetSize(pos.x, pos.y, size.x, size.y);
 
     return TRUE;
 }
@@ -254,29 +337,36 @@ void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
     SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
 }
 
-size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
+size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
+                                    bool recursively) const
 {
-    long cookie;
+    class TraverseCounter : public wxTreeTraversal
+    {
+    public:
+        TraverseCounter(const wxTreeCtrl *tree,
+                        const wxTreeItemId& root,
+                        bool recursively)
+            : wxTreeTraversal(tree)
+            {
+                m_count = 0;
 
-    size_t result = 0;
+                DoTraverse(root, recursively);
+            }
 
-    wxArrayLong children;
-    wxTreeItemId child = GetFirstChild(item, cookie);
-    while ( child.IsOk() )
-    {
-        if ( recursively )
+        virtual bool OnVisit(const wxTreeItemId& item)
         {
-            // recursive call
-            result += GetChildrenCount(child, TRUE);
+            m_count++;
+
+            return TRUE;
         }
 
-        // add the child to the result in any case
-        result++;
+        size_t GetCount() const { return m_count; }
 
-        child = GetNextChild(item, cookie);
-    }
+    private:
+        size_t m_count;
+    } counter(this, item, recursively);
 
-    return result;
+    return counter.GetCount();
 }
 
 // ----------------------------------------------------------------------------
@@ -306,6 +396,16 @@ void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
     DoSetItem(&tvItem);
 }
 
+void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
+                                 int image,
+                                 int imageSel)
+{
+    wxTreeViewItem tvItem(item, TVIF_IMAGE | TVIF_SELECTEDIMAGE);
+    tvItem.iSelectedImage = imageSel;
+    tvItem.iImage = image;
+    DoSetItem(&tvItem);
+}
+
 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
 {
     wxTreeViewItem tvItem(item, TVIF_IMAGE);
@@ -316,9 +416,10 @@ int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
 
 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
 {
-    wxTreeViewItem tvItem(item, TVIF_IMAGE);
-    tvItem.iImage = image;
-    DoSetItem(&tvItem);
+    // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
+    //     change both normal and selected image - otherwise the change simply
+    //     doesn't take place!
+    DoSetItemImages(item, image, GetItemSelectedImage(item));
 }
 
 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
@@ -331,9 +432,10 @@ int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
 
 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
 {
-    wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
-    tvItem.iSelectedImage = image;
-    DoSetItem(&tvItem);
+    // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
+    //     change both normal and selected image - otherwise the change simply
+    //     doesn't take place!
+    DoSetItemImages(item, GetItemImage(item), image);
 }
 
 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
@@ -433,6 +535,9 @@ wxTreeItemId wxTreeCtrl::GetRootItem() const
 
 wxTreeItemId wxTreeCtrl::GetSelection() const
 {
+    wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0,
+                 _T("this only works with single selection controls") );
+
     return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd()));
 }
 
@@ -507,6 +612,62 @@ wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
     return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
 }
 
+// ----------------------------------------------------------------------------
+// multiple selections emulation
+// ----------------------------------------------------------------------------
+
+bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const
+{
+    // receive the desired information.
+    wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
+    DoGetItem(&tvItem);
+
+    // state image indices are 1 based
+    return ((tvItem.state >> 12) - 1) == 1;
+}
+
+void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
+{
+    // receive the desired information.
+    wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
+
+    // state images are one-based
+    tvItem.state = (check ? 2 : 1) << 12;
+
+    DoSetItem(&tvItem);
+}
+
+size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const
+{
+    class TraverseSelections : public wxTreeTraversal
+    {
+    public:
+        TraverseSelections(const wxTreeCtrl *tree,
+                           wxArrayTreeItemIds& selections)
+            : wxTreeTraversal(tree), m_selections(selections)
+            {
+                m_selections.Empty();
+
+                DoTraverse(tree->GetRootItem());
+            }
+
+        virtual bool OnVisit(const wxTreeItemId& item)
+        {
+            if ( GetTree()->IsItemChecked(item) )
+            {
+                m_selections.Add(item);
+            }
+
+            return TRUE;
+        }
+
+    private:
+        wxArrayTreeItemIds& m_selections;
+    } selector(this, selections);
+
+    return selections.GetCount();
+}
+
 // ----------------------------------------------------------------------------
 // Usual operations
 // ----------------------------------------------------------------------------
@@ -721,38 +882,67 @@ void wxTreeCtrl::Toggle(const wxTreeItemId& item)
 
 void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
 {
-       DoExpand(item, action);
+    DoExpand(item, action);
 }
 
 void wxTreeCtrl::Unselect()
 {
+    wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), _T("doesn't make sense") );
+
+    // just remove the selection
     SelectItem(wxTreeItemId((WXHTREEITEM) 0));
 }
 
-void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
+void wxTreeCtrl::UnselectAll()
 {
-    // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
-    // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
-    // send them ourselves
-
-    wxTreeEvent event(wxEVT_NULL, m_windowId);
-    event.m_item = item;
-    event.SetEventObject(this);
-
-    event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
-    if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
+    if ( m_windowStyle & wxTR_MULTIPLE )
     {
-        if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
+        wxArrayTreeItemIds selections;
+        size_t count = GetSelections(selections);
+        for ( size_t n = 0; n < count; n++ )
         {
-            wxLogLastError("TreeView_SelectItem");
+            SetItemCheck(selections[n], FALSE);
         }
-        else
+    }
+    else
+    {
+        // just remove the selection
+        Unselect();
+    }
+}
+
+void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
+{
+    if ( m_windowStyle & wxTR_MULTIPLE )
+    {
+        // selecting the item means checking it
+        SetItemCheck(item);
+    }
+    else
+    {
+        // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
+        // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
+        // send them ourselves
+
+        wxTreeEvent event(wxEVT_NULL, m_windowId);
+        event.m_item = item;
+        event.SetEventObject(this);
+
+        event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
+        if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
         {
-            event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
-            (void)GetEventHandler()->ProcessEvent(event);
+            if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
+            {
+                wxLogLastError("TreeView_SelectItem");
+            }
+            else
+            {
+                event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+                (void)GetEventHandler()->ProcessEvent(event);
+            }
         }
+        //else: program vetoed the change
     }
-    //else: program vetoed the change
 }
 
 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)