[litwindow-users] Re: Conditional lists/filters
Status: Alpha
Brought to you by:
hajokirchhoff
From: Hajo K. <mai...@ha...> - 2005-05-19 10:39:43
|
Hi, yrs90 wrote: > I am at the point where I need to the ability to filter a list. I considered I have experimented this morning and I think your easiest route will be implementing your own iterators. It looks much more complicated than it actually is. Here is what you need to do: First I'd, typedef your container so that it gets its own unique name. IMPLEMENT_CONTAINER_ADAPTER(MyContainer) instantiates the entire container adapter mechanism. A container is really nothing more than a container iterator factory providing access to begin() and end() and ++. Step 1: Write your own iterator adapter. Derive it from container_iterator_imp_base for non-const, from const_container_iterator_imp_base for const container access. You need to implement the following functions: virtual (const_)container_iterator_imp_base *clone() create a copy of self on the heap and return it virtual (const_)accessor get() const return an accessor pointing to the current location virtual void inc() advance the iterator one element virtual void advance(size_t off) advance the iterator 'off' elements Example: typedef map<wxString, obj*> MyContainer; class MyContainerIterator:public container_iterator_imp_base { MyContainer::iterator m_iterator; // the real iterator public: MyContainerIterator(const MyContainer::iterator &i) :m_iterator(i) { } container_iterator_imp_base *clone() const { return new MyContainerIterator(*this); } accessor get() const { return make_accessor(*m_iterator); } void inc() { ++m_iterator; } void advance(size_t off) { while (off--) inc(); } }; Step 2: You have to use template specialization to override the default iterator factory. Add template<> container_iterator_imp_base *container_converter<MyContainer>::get_begin(const schema_entry *se, const_prop_ptr member_ptr) const { return new MyContainerIterator(member(member_ptr).begin()); } in front (!) of the IMPLEMENT_CONTAINER_ADAPTER statement. It needs to go in front so the compiler sees the specialization before it instantiates the template. 'new MyContainerIterator...' creates a new MyContainerIterator object on the heap and returns a pointer to it. member(member_ptr) returns a reference to the container itself. member(member_ptr).begin() makes sense only if the container actually has a 'begin' method. The STL containers do, but if you where using a different container, you'd be calling a different method. container_converter is a class defined in dataadaptercontainerimp.h. It has four relevant functions: get_begin(), get_end(), get_const_begin() and get_const_end(). These functions return a pointer to a container_iterator_imp_base for non-const container and const_container_iterator_imp_base for const container. You need to override all these methods. Step 3: Add filtering. In Step 1 you defined MyContainerIterator::inc. Modify it so that it skips elements you want filtered out. You will also have to modify the container_converter::get_(const_)begin methods so they will return an iterator to the first element that matches the filter criteria instead of just the first element. > overriding iterators, but it looks pretty complicated. I considered > avoiding the problem by simply creating new underlying data, a new string > vector, to populate the filtered list, but I can't create a rule that allows > me to connect an item selected from the filtered list back to the original > list. For example the following rule won't work: > > RULE("xrcTextCtrl.Text", > make_expr<wxString>("m_FullData[xrcFilteredList.Current].Details")) But you could write your own property here. Assuming that m_FullData is part of a struct MyData, write a FullDataCurrent property with get/set methods that reflect m_FullData[xrcFilteredList.Current]. But its a cludge. > I am considering creating a Condition property in the lwListAdapterBase. The > idea is that an item is inserted in the list only if the Condition evaluates > true. > > Currently there isn't any rule syntax that would allow me to refer to the > current item such that I could evaluate a Boolean rule for each list item. > Also, I am not sure how to cause a rule to be reevaluated. Hm, intriguing. You are suggesting a property that is itself an expression or rule. So that I could pass an expression to the property and it would be evaluated when needed. I'll have to keep that in mind. This is possible and I like the idea. > Any suggestions on the easiest way to add this functionality? Try writing your own iterators. Its not very hard to do, it just looks this way since its still undocumented. Regards Hajo |