+ // choice first' and 'last' between item1 and item2
+ if (item1->GetY()<item2->GetY())
+ {
+ first=item1;
+ last=item2;
+ }
+ else
+ {
+ first=item2;
+ last=item1;
+ }
+
+ bool select = m_current->IsSelected();
+
+ if ( TagAllChildrenUntilLast(first,last,select) )
+ return;
+
+ TagNextChildren(first,last,select);
+}
+
+void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId,
+ bool unselect_others,
+ bool extended_select)
+{
+ wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
+
+ bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
+ wxGenericTreeItem *item = itemId.m_pItem;
+
+ //wxCHECK_RET( ( (!unselect_others) && is_single),
+ // wxT("this is a single selection tree") );
+
+ // to keep going anyhow !!!
+ if (is_single)
+ {
+ if (item->IsSelected())
+ return; // nothing to do
+ unselect_others = TRUE;
+ extended_select = FALSE;
+ }
+ else if ( unselect_others && item->IsSelected() )
+ {
+ // selection change if there is more than one item currently selected
+ wxArrayTreeItemIds selected_items;
+ if ( GetSelections(selected_items) == 1 )
+ return;
+ }
+
+ wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
+ event.m_item = item;
+ event.m_itemOld = m_current;
+ event.SetEventObject( this );
+ // TODO : Here we don't send any selection mode yet !
+
+ if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+ return;
+
+ // ctrl press
+ if (unselect_others)
+ {
+ if (is_single) Unselect(); // to speed up thing
+ else UnselectAll();
+ }
+
+ // shift press
+ if (extended_select)
+ {
+ if (m_current == NULL) m_current=m_key_current=GetRootItem().m_pItem;
+ // don't change the mark (m_current)
+ SelectItemRange(m_current, item);
+ }
+ else
+ {
+ bool select=TRUE; // the default
+
+ // Check if we need to toggle hilight (ctrl mode)
+ if (!unselect_others)
+ select=!item->IsSelected();
+
+ m_current = m_key_current = item;
+ m_current->SetHilight(select);
+ RefreshLine( m_current );
+ }
+
+ event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+ GetEventHandler()->ProcessEvent( event );
+}
+
+void wxTreeCtrl::FillArray(wxGenericTreeItem *item,
+ wxArrayTreeItemIds &array) const
+{
+ if ( item->IsSelected() )
+ array.Add(wxTreeItemId(item));
+
+ if ( item->HasChildren() )
+ {
+ wxArrayGenericTreeItems& children = item->GetChildren();
+ size_t count = children.GetCount();
+ for ( size_t n = 0; n < count; ++n )
+ FillArray(children[n],array);
+ }
+}
+
+size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
+{
+ array.Empty();
+ FillArray(GetRootItem().m_pItem, array);
+
+ return array.Count();
+}
+
+void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
+{
+ if (!item.IsOk()) return;
+
+ wxGenericTreeItem *gitem = item.m_pItem;
+
+ // first expand all parent branches
+ wxGenericTreeItem *parent = gitem->GetParent();
+ while ( parent )
+ {
+ Expand(parent);
+ parent = parent->GetParent();
+ }
+
+ //if (parent) CalculatePositions();
+
+ ScrollTo(item);
+}
+
+void wxTreeCtrl::ScrollTo(const wxTreeItemId &item)
+{
+ if (!item.IsOk()) return;
+
+ // We have to call this here because the label in
+ // question might just have been added and no screen
+ // update taken place.
+ if (m_dirty) wxYield();
+
+ wxGenericTreeItem *gitem = item.m_pItem;
+
+ // now scroll to the item
+ int item_y = gitem->GetY();
+
+ int start_x = 0;
+ int start_y = 0;
+ ViewStart( &start_x, &start_y );
+ start_y *= PIXELS_PER_UNIT;
+
+ int client_h = 0;
+ int client_w = 0;
+ GetClientSize( &client_w, &client_h );
+
+ if (item_y < start_y+3)
+ {
+ // going down
+ int x = 0;
+ int y = 0;
+ m_anchor->GetSize( x, y, this );
+ y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+ x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+ int x_pos = GetScrollPos( wxHORIZONTAL );
+ // Item should appear at top
+ SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT );
+ }
+ else if (item_y+GetLineHeight(gitem) > start_y+client_h)
+ {
+ // going up
+ int x = 0;
+ int y = 0;
+ m_anchor->GetSize( x, y, this );
+ y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+ x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
+ item_y += PIXELS_PER_UNIT+2;
+ int x_pos = GetScrollPos( wxHORIZONTAL );
+ // Item should appear at bottom
+ SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT );
+ }
+}
+
+// FIXME: tree sorting functions are not reentrant and not MT-safe!
+static wxTreeCtrl *s_treeBeingSorted = NULL;
+
+static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1,
+ wxGenericTreeItem **item2)
+{
+ wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxTreeCtrl::SortChildren()") );
+
+ return s_treeBeingSorted->OnCompareItems(*item1, *item2);
+}
+
+int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
+ const wxTreeItemId& item2)
+{
+ return wxStrcmp(GetItemText(item1), GetItemText(item2));
+}
+
+void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId)
+{
+ wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
+
+ wxGenericTreeItem *item = itemId.m_pItem;
+
+ wxCHECK_RET( !s_treeBeingSorted,
+ wxT("wxTreeCtrl::SortChildren is not reentrant") );
+
+ wxArrayGenericTreeItems& children = item->GetChildren();
+ if ( children.Count() > 1 )
+ {
+ s_treeBeingSorted = this;
+ children.Sort(tree_ctrl_compare_func);
+ s_treeBeingSorted = NULL;
+
+ m_dirty = TRUE;
+ }
+ //else: don't make the tree dirty as nothing changed
+}