mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-09 21:40:34 +01:00
Add treectrl
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@71046 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
3
TODO.txt
3
TODO.txt
@@ -145,10 +145,9 @@ other dev stuff
|
||||
* all missing common dialogs
|
||||
* print (as in print framework classes)
|
||||
* mdi (die mdi! die!)
|
||||
* treectrl
|
||||
* dirctrl
|
||||
* cshelp
|
||||
* dragimag
|
||||
* dragimag
|
||||
* datectrl
|
||||
* hyperlink
|
||||
* pickerbase, clrpicker, filepicker, fontpicker
|
||||
|
||||
@@ -148,6 +148,7 @@ INCLUDES = [ # core
|
||||
'toolbar',
|
||||
'infobar',
|
||||
'listctrl',
|
||||
'treectrl',
|
||||
|
||||
# toplevel and dialogs
|
||||
'nonownedwnd',
|
||||
|
||||
237
etg/treectrl.py
Normal file
237
etg/treectrl.py
Normal file
@@ -0,0 +1,237 @@
|
||||
#---------------------------------------------------------------------------
|
||||
# Name: etg/treectrl.py
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 26-Mar-2012
|
||||
# Copyright: (c) 2012 by Total Control Software
|
||||
# License: wxWindows License
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
import etgtools
|
||||
import etgtools.tweaker_tools as tools
|
||||
|
||||
PACKAGE = "wx"
|
||||
MODULE = "_core"
|
||||
NAME = "treectrl" # Base name of the file to generate to for this script
|
||||
DOCSTRING = ""
|
||||
|
||||
# The classes and/or the basename of the Doxygen XML files to be processed by
|
||||
# this script.
|
||||
ITEMS = [ "wxTreeItemId",
|
||||
##"wxTreeItemData",
|
||||
"wxTreeCtrl",
|
||||
"wxTreeEvent",
|
||||
]
|
||||
|
||||
DEPENDS = [ 'src/treeitemdata.h' ]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
def run():
|
||||
# Parse the XML file(s) building a collection of Extractor objects
|
||||
module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING)
|
||||
etgtools.parseDoxyXML(module, ITEMS)
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
# Tweak the parsed meta objects in the module object as needed for
|
||||
# customizing the generated code and docstrings.
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
c = module.find('wxTreeItemId')
|
||||
assert isinstance(c, etgtools.ClassDef)
|
||||
c.addCppMethod('int', '__nonzero__', '()', """\
|
||||
return self->IsOk();
|
||||
""")
|
||||
|
||||
td = etgtools.TypedefDef(name='wxTreeItemIdValue', type='void*')
|
||||
module.insertItemBefore(c, td)
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
# Instead of using the wxTreeItemData defined in the dox file we'll
|
||||
# create our own subclass that knows about dealing with PyObjects
|
||||
# properly and then tweak the wxTreeCtrl methods below to define the use
|
||||
# of this new class instead.
|
||||
|
||||
# TODO: build this with ClassDef, etc. extractor objects instead of WigCode.
|
||||
|
||||
# OR maybe just assume that nobody uses the Set/GetId and make it a %MappedType?
|
||||
# Then Set/GetItemPyData can just be aliases.
|
||||
tid = etgtools.WigCode("""\
|
||||
class TreeItemData {
|
||||
%TypeHeaderCode
|
||||
#include "treeitemdata.h"
|
||||
%End
|
||||
|
||||
public:
|
||||
TreeItemData(PyObject* obj = NULL);
|
||||
~TreeItemData();
|
||||
|
||||
const wxTreeItemId& GetId() const;
|
||||
void SetId(const wxTreeItemId& id);
|
||||
|
||||
PyObject* GetData();
|
||||
void SetData(PyObject* obj);
|
||||
|
||||
%Property(name=Id, get=GetId, set=SetId)
|
||||
%Property(name=Data, get=GetData, set=SetData)
|
||||
};
|
||||
""")
|
||||
module.insertItemAfter(c, tid)
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
c = module.find('wxTreeCtrl')
|
||||
tools.fixWindowClass(c)
|
||||
module.addGlobalStr('wxTreeCtrlNameStr', before=c)
|
||||
|
||||
|
||||
# Switch all wxTreeItemData parameters to our TreeItemData class.
|
||||
for item in c.allItems():
|
||||
if hasattr(item, 'type') and item.type == 'wxTreeItemData *':
|
||||
item.type = 'TreeItemData *'
|
||||
if isinstance(item, etgtools.ParamDef):
|
||||
item.transfer = True
|
||||
|
||||
# Typecast the return value to our data item type
|
||||
c.find('GetItemData').setCppCode(
|
||||
'return dynamic_cast<TreeItemData*>(self->GetItemData(*item));')
|
||||
|
||||
# The setter takes ownership of the data object
|
||||
c.find('SetItemData.data').transfer = True
|
||||
|
||||
# Add methods that allow direct setting/getting of the PyObject without
|
||||
# requiring the programmer to use our TreeItemData class themselves.
|
||||
c.addCppMethod('PyObject*', 'GetItemPyData', '(const wxTreeItemId& item)',
|
||||
doc='Get the Python object associated with the tree item.',
|
||||
body="""\
|
||||
TreeItemData* data = (TreeItemData*)self->GetItemData(*item);
|
||||
if (data == NULL) {
|
||||
RETURN_NONE();
|
||||
}
|
||||
return data->GetData();
|
||||
""")
|
||||
c.addCppMethod('void', 'SetItemPyData', '(const wxTreeItemId& item, PyObject* obj)',
|
||||
doc='Associate a Python object with an item in the treectrl.',
|
||||
body="""\
|
||||
TreeItemData* data = (TreeItemData*)self->GetItemData(*item);
|
||||
if (data == NULL) {
|
||||
data = new TreeItemData(obj);
|
||||
self->SetItemData(*item, data);
|
||||
} else {
|
||||
data->SetData(obj);
|
||||
}
|
||||
""")
|
||||
c.addPyCode("""\
|
||||
TreeCtrl.GetPyData = wx.deprecated(TreeCtrl.GetItemPyData)
|
||||
TreeCtrl.SetPyData = wx.deprecated(TreeCtrl.SetItemPyData)
|
||||
""")
|
||||
|
||||
|
||||
# We can't use wxClassInfo
|
||||
c.find('EditLabel.textCtrlClass').ignore()
|
||||
|
||||
# Replace GetSelections with a method that returns a Python list
|
||||
# size_t GetSelections(wxArrayTreeItemIds& selection) const;
|
||||
c.find('GetSelections').ignore()
|
||||
c.addCppMethod('PyObject*', 'GetSelections', '()',
|
||||
doc='Returns a list of currently selected items in the tree. This function '
|
||||
'can be called only if the control has the wx.TR_MULTIPLE style.',
|
||||
body="""\
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
PyObject* rval = PyList_New(0);
|
||||
wxArrayTreeItemIds array;
|
||||
size_t num, x;
|
||||
num = self->GetSelections(array);
|
||||
for (x=0; x < num; x++) {
|
||||
wxTreeItemId *tii = new wxTreeItemId(array.Item(x));
|
||||
PyObject* item = wxPyConstructObject((void*)tii, wxT("wxTreeItemId"), true);
|
||||
PyList_Append(rval, item);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
wxPyEndBlockThreads(blocked);
|
||||
return rval;
|
||||
""")
|
||||
|
||||
# Change GetBoundingRect to return the rectangle instead of modifying the parameter.
|
||||
#bool GetBoundingRect(const wxTreeItemId& item, wxRect& rect, bool textOnly = false) const;
|
||||
c.find('GetBoundingRect').ignore()
|
||||
c.addCppMethod('PyObject*', 'GetBoundingRect', '(const wxTreeItemId& item, bool textOnly=false)',
|
||||
doc="""\
|
||||
Returns the rectangle bounding the item. If textOnly is true,
|
||||
only the rectangle around the item's label will be returned, otherwise
|
||||
the item's image is also taken into account. The return value may be None
|
||||
if the rectangle was not successfully retrieved, such as if the item is
|
||||
currently not visible.
|
||||
""",
|
||||
isFactory=True,
|
||||
body="""\
|
||||
wxRect rect;
|
||||
if (self->GetBoundingRect(*item, rect, textOnly)) {
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
wxRect* r = new wxRect(rect);
|
||||
PyObject* val = wxPyConstructObject((void*)r, wxT("wxRect"), true);
|
||||
wxPyEndBlockThreads(blocked);
|
||||
return val;
|
||||
}
|
||||
else
|
||||
RETURN_NONE();
|
||||
""")
|
||||
|
||||
|
||||
# switch the virtualness back on for those methods that need to have it.
|
||||
c.find('OnCompareItems').isVirtual = True
|
||||
|
||||
|
||||
# transfer imagelist ownership
|
||||
c.find('AssignImageList.imageList').transfer = True
|
||||
c.find('AssignStateImageList.imageList').transfer = True
|
||||
c.find('AssignButtonsImageList.imageList').transfer = True
|
||||
|
||||
|
||||
# Make the cookie values be returned, instead of setting it through the parameter
|
||||
c.find('GetFirstChild.cookie').out = True
|
||||
c.find('GetFirstChild.cookie').inOut = True
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------
|
||||
c = module.find('wxTreeEvent')
|
||||
tools.fixEventClass(c)
|
||||
|
||||
c.addPyCode("""\
|
||||
EVT_TREE_BEGIN_DRAG = PyEventBinder(wxEVT_COMMAND_TREE_BEGIN_DRAG , 1)
|
||||
EVT_TREE_BEGIN_RDRAG = PyEventBinder(wxEVT_COMMAND_TREE_BEGIN_RDRAG , 1)
|
||||
EVT_TREE_BEGIN_LABEL_EDIT = PyEventBinder(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT , 1)
|
||||
EVT_TREE_END_LABEL_EDIT = PyEventBinder(wxEVT_COMMAND_TREE_END_LABEL_EDIT , 1)
|
||||
EVT_TREE_DELETE_ITEM = PyEventBinder(wxEVT_COMMAND_TREE_DELETE_ITEM , 1)
|
||||
EVT_TREE_GET_INFO = PyEventBinder(wxEVT_COMMAND_TREE_GET_INFO , 1)
|
||||
EVT_TREE_SET_INFO = PyEventBinder(wxEVT_COMMAND_TREE_SET_INFO , 1)
|
||||
EVT_TREE_ITEM_EXPANDED = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_EXPANDED , 1)
|
||||
EVT_TREE_ITEM_EXPANDING = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_EXPANDING , 1)
|
||||
EVT_TREE_ITEM_COLLAPSED = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_COLLAPSED , 1)
|
||||
EVT_TREE_ITEM_COLLAPSING = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_COLLAPSING , 1)
|
||||
EVT_TREE_SEL_CHANGED = PyEventBinder(wxEVT_COMMAND_TREE_SEL_CHANGED , 1)
|
||||
EVT_TREE_SEL_CHANGING = PyEventBinder(wxEVT_COMMAND_TREE_SEL_CHANGING , 1)
|
||||
EVT_TREE_KEY_DOWN = PyEventBinder(wxEVT_COMMAND_TREE_KEY_DOWN , 1)
|
||||
EVT_TREE_ITEM_ACTIVATED = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_ACTIVATED , 1)
|
||||
EVT_TREE_ITEM_RIGHT_CLICK = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK , 1)
|
||||
EVT_TREE_ITEM_MIDDLE_CLICK = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 1)
|
||||
EVT_TREE_END_DRAG = PyEventBinder(wxEVT_COMMAND_TREE_END_DRAG , 1)
|
||||
EVT_TREE_STATE_IMAGE_CLICK = PyEventBinder(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 1)
|
||||
EVT_TREE_ITEM_GETTOOLTIP = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 1)
|
||||
EVT_TREE_ITEM_MENU = PyEventBinder(wxEVT_COMMAND_TREE_ITEM_MENU, 1)
|
||||
""")
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
tools.doCommonTweaks(module)
|
||||
tools.runGenerators(module)
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
48
src/treeitemdata.h
Normal file
48
src/treeitemdata.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//--------------------------------------------------------------------------
|
||||
// Name: treeitemdata.h
|
||||
// Purpose: This class is used to associate a PyObject with a tree item.
|
||||
//
|
||||
// Author: Robin Dunn
|
||||
//
|
||||
// Created: 26-Mar-2012
|
||||
// Copyright: (c) 2012 by Total Control Software
|
||||
// Licence: wxWindows license
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#ifndef TREEITEMDATA_H
|
||||
#define TREEITEMDATA_H
|
||||
|
||||
#include <wx/treebase.h>
|
||||
|
||||
// A wxTreeItemData that knows what to do with PyObjects for maintianing the refcount
|
||||
class TreeItemData : public wxTreeItemData {
|
||||
public:
|
||||
TreeItemData(PyObject* obj = NULL) {
|
||||
if (obj == NULL)
|
||||
obj = Py_None;
|
||||
wxPyBLOCK_THREADS( Py_INCREF(obj) );
|
||||
m_obj = obj;
|
||||
}
|
||||
|
||||
~TreeItemData() {
|
||||
wxPyBLOCK_THREADS( Py_DECREF(m_obj) );
|
||||
}
|
||||
|
||||
PyObject* GetData() {
|
||||
wxPyBLOCK_THREADS( Py_INCREF(m_obj) );
|
||||
return m_obj;
|
||||
}
|
||||
|
||||
void SetData(PyObject* obj) {
|
||||
wxPyBlock_t blocked = wxPyBeginBlockThreads();
|
||||
Py_DECREF(m_obj);
|
||||
m_obj = obj;
|
||||
Py_INCREF(obj);
|
||||
wxPyEndBlockThreads(blocked);
|
||||
}
|
||||
|
||||
private:
|
||||
PyObject* m_obj;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -88,6 +88,9 @@ inline void wxPyEndAllowThreads(PyThreadState* saved) {
|
||||
wxPyBLOCK_THREADS( PyErr_SetString(PyExc_NotImplementedError, msg) );
|
||||
|
||||
|
||||
// A convenience macro for properly returning Py_None
|
||||
//#define RETURN_NONE() { Py_INCREF(Py_None); return Py_None; }
|
||||
#define RETURN_NONE() { wxPyBLOCK_THREADS(Py_INCREF(Py_None)); return Py_None; }
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// The API items whose implementation can not or should not be inline
|
||||
|
||||
141
unittests/test_treectrl.py
Normal file
141
unittests/test_treectrl.py
Normal file
@@ -0,0 +1,141 @@
|
||||
import imp_unittest, unittest
|
||||
import wtc
|
||||
import wx
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
class treectrl_Tests(wtc.WidgetTestCase):
|
||||
|
||||
def test_treectrlCtor(self):
|
||||
t = wx.TreeCtrl(self.frame)
|
||||
|
||||
def test_treectrlDefaultCtor(self):
|
||||
t = wx.TreeCtrl()
|
||||
t.Create(self.frame)
|
||||
|
||||
|
||||
def test_treectrlTreeItemId(self):
|
||||
tree = wx.TreeCtrl(self.frame)
|
||||
root = tree.AddRoot('root item')
|
||||
self.assertTrue( isinstance(root, wx.TreeItemId) )
|
||||
self.assertTrue( root.IsOk() )
|
||||
|
||||
r = tree.GetRootItem()
|
||||
self.assertTrue( r is not root )
|
||||
self.assertTrue( r == root )
|
||||
|
||||
child = tree.AppendItem(root, 'child item')
|
||||
self.assertTrue( child is not root )
|
||||
self.assertTrue( child != root )
|
||||
|
||||
|
||||
def test_treectrlTreeItemData(self):
|
||||
value = 'Some Python Object'
|
||||
tree = wx.TreeCtrl(self.frame)
|
||||
data = wx.TreeItemData(value)
|
||||
root = tree.AddRoot('root item', data=data)
|
||||
d = tree.GetItemData(root)
|
||||
self.assertTrue(d.GetData() == value)
|
||||
self.assertTrue(d.Data == value)
|
||||
self.assertTrue(d.Id == root)
|
||||
tree.SetItemData(root, None)
|
||||
self.assertTrue(tree.GetItemData(root) is None)
|
||||
|
||||
|
||||
def test_treectrlTreeItemPyData(self):
|
||||
value = 'Some Python Object'
|
||||
tree = wx.TreeCtrl(self.frame)
|
||||
root = tree.AddRoot('root item')
|
||||
tree.SetItemPyData(root, value)
|
||||
self.assertTrue(tree.GetItemPyData(root) == value)
|
||||
self.assertTrue(tree.GetItemData(root).GetData() == value)
|
||||
tree.SetItemPyData(root, None)
|
||||
self.assertTrue(tree.GetItemPyData(root) is None)
|
||||
|
||||
|
||||
|
||||
def test_treectrlConstantsExist(self):
|
||||
wx.TR_NO_BUTTONS
|
||||
wx.TR_HAS_BUTTONS
|
||||
wx.TR_NO_LINES
|
||||
wx.TR_LINES_AT_ROOT
|
||||
wx.TR_SINGLE
|
||||
wx.TR_MULTIPLE
|
||||
wx.TR_HAS_VARIABLE_ROW_HEIGHT
|
||||
wx.TR_EDIT_LABELS
|
||||
wx.TR_HIDE_ROOT
|
||||
wx.TR_ROW_LINES
|
||||
wx.TR_FULL_ROW_HIGHLIGHT
|
||||
wx.TR_DEFAULT_STYLE
|
||||
wx.TR_TWIST_BUTTONS
|
||||
wx.TreeItemIcon_Normal
|
||||
wx.TreeItemIcon_Selected
|
||||
wx.TreeItemIcon_Expanded
|
||||
wx.TreeItemIcon_SelectedExpanded
|
||||
wx.TREE_ITEMSTATE_NONE
|
||||
wx.TREE_ITEMSTATE_NEXT
|
||||
wx.TREE_ITEMSTATE_PREV
|
||||
wx.TREE_HITTEST_ABOVE
|
||||
wx.TREE_HITTEST_BELOW
|
||||
wx.TREE_HITTEST_NOWHERE
|
||||
wx.TREE_HITTEST_ONITEMBUTTON
|
||||
wx.TREE_HITTEST_ONITEMICON
|
||||
wx.TREE_HITTEST_ONITEMINDENT
|
||||
wx.TREE_HITTEST_ONITEMLABEL
|
||||
wx.TREE_HITTEST_ONITEMRIGHT
|
||||
wx.TREE_HITTEST_ONITEMSTATEICON
|
||||
wx.TREE_HITTEST_TOLEFT
|
||||
wx.TREE_HITTEST_TORIGHT
|
||||
wx.TREE_HITTEST_ONITEMUPPERPART
|
||||
wx.TREE_HITTEST_ONITEMLOWERPART
|
||||
wx.TREE_HITTEST_ONITEM
|
||||
|
||||
def test_treeEventsExist(self):
|
||||
wx.wxEVT_COMMAND_TREE_BEGIN_DRAG
|
||||
wx.wxEVT_COMMAND_TREE_BEGIN_RDRAG
|
||||
wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
|
||||
wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT
|
||||
wx.wxEVT_COMMAND_TREE_DELETE_ITEM
|
||||
wx.wxEVT_COMMAND_TREE_GET_INFO
|
||||
wx.wxEVT_COMMAND_TREE_SET_INFO
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_EXPANDED
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSING
|
||||
wx.wxEVT_COMMAND_TREE_SEL_CHANGED
|
||||
wx.wxEVT_COMMAND_TREE_SEL_CHANGING
|
||||
wx.wxEVT_COMMAND_TREE_KEY_DOWN
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_ACTIVATED
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK
|
||||
wx.wxEVT_COMMAND_TREE_END_DRAG
|
||||
wx.wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP
|
||||
wx.wxEVT_COMMAND_TREE_ITEM_MENU
|
||||
|
||||
wx.EVT_TREE_BEGIN_DRAG
|
||||
wx.EVT_TREE_BEGIN_RDRAG
|
||||
wx.EVT_TREE_BEGIN_LABEL_EDIT
|
||||
wx.EVT_TREE_END_LABEL_EDIT
|
||||
wx.EVT_TREE_DELETE_ITEM
|
||||
wx.EVT_TREE_GET_INFO
|
||||
wx.EVT_TREE_SET_INFO
|
||||
wx.EVT_TREE_ITEM_EXPANDED
|
||||
wx.EVT_TREE_ITEM_EXPANDING
|
||||
wx.EVT_TREE_ITEM_COLLAPSED
|
||||
wx.EVT_TREE_ITEM_COLLAPSING
|
||||
wx.EVT_TREE_SEL_CHANGED
|
||||
wx.EVT_TREE_SEL_CHANGING
|
||||
wx.EVT_TREE_KEY_DOWN
|
||||
wx.EVT_TREE_ITEM_ACTIVATED
|
||||
wx.EVT_TREE_ITEM_RIGHT_CLICK
|
||||
wx.EVT_TREE_ITEM_MIDDLE_CLICK
|
||||
wx.EVT_TREE_END_DRAG
|
||||
wx.EVT_TREE_STATE_IMAGE_CLICK
|
||||
wx.EVT_TREE_ITEM_GETTOOLTIP
|
||||
wx.EVT_TREE_ITEM_MENU
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user