[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
|