A Key Associated Category for Listbox

Coordinator
Mar 29, 2014 at 6:56 AM
When a new item is inserted to the listbox, we need to determine which category should be chose. For example, a listbox creates some categories to classify items by country. We should do it like this.
struct T
{
    nana::string country;
    nana::string address;
};

using namespace nana::gui;

std::size_t find_category(listbox & lb, const T& t)
{
    for (std::size_t i = 0; i < lb.size_categ(); ++i)
    {
        if (t.country == lb.at(i).text())
            return i;
    }
    lb.append(t.country);   //Create a new category for new country.
    return lb.size_categ() - 1;
}

void insert(listbox & lb, const T& t)
{
    auto cat_index = find_category(lb, t);
    lb.at(cat_index).push_back(t.address);
}

int main()
{
    form fm;

    listbox lb(fm);
    place plc(fm);
    plc.div("<screen>");
    plc.field("screen") << lb;
    plc.collocate();

    lb.append_header(L"Address", 300);

    T t;
    t.country = L"United States";
    t.address = L"123";
    insert(lb, t);

    t.country = L"China";
    t.address = L"ABC";
    insert(lb, t);

    t.country = L"Germany";
    t.address = L"CDE";
    insert(lb, t);

    t.country = L"Russia";
    t.address = L"DEF";
    insert(lb, t);

    t.country = L"United Kingdom";
    t.address = L"EFG";
    insert(lb, t);

    fm.show();
    exec();
}
Listbox introduced a key associated category feature, which allows the category to be determined by a specified key type. The above example can be rewrite as follows.
//Remove the find_category() function, and modify the insert() as follows.

void insert(listbox & lb, const T& t)
{
    //If the associated category of the key does not exist,
    //It will be created with the empty name. So we need to
    //call text() method to reset the category name.
    auto cat = lb[t.country];
    cat.text(t.country);
    cat.push_back(t.address);
}
There is another feature for the key associated category, that is to create new categories by the order of key. For example.
struct Date
{
    int year;
    int month;

    void set(int y, int m)
    {
        year = y;
        month = m;
    }

    bool operator<(const Date& r) const
    {
        return (year < r.year) || (year == r.year && month < r.month);
    }
};

struct T
{
    Date date;
    nana::string text;
};

using namespace nana::gui;

void insert(listbox & lb, const T& t)
{
    //If the associated category of the key does not exist,
    //It will be created with the empty name. So we need to
    //call text() method to reset the category name.
    auto cat = lb[t.date];
    if (cat.text().empty()) //the text is empty if it is a new category.
    {
        std::wstringstream ss;
        ss << t.date.year << L"-" << t.date.month;
        cat.text(ss.str());
    }
    cat.push_back(t.text);
}

int main()
{
    form fm;

    listbox lb(fm);
    place plc(fm);
    plc.div("<screen>");
    plc.field("screen") << lb;
    plc.collocate();

    lb.append_header(L"Address", 300);

    lb.ordered_categories(true); //Creates a new category by the order of KEY.

    T t;
    t.text = L"example";

    t.date.set(2012, 1);
    insert(lb, t);

    t.date.set(2012, 2);
    insert(lb, t);

    t.date.set(2013, 5);
    insert(lb, t);

    t.date.set(2014, 3);
    insert(lb, t);

    t.date.set(2013, 12);  //This date will be created before the previous one.
    insert(lb, t);
    t.text = L"Hello Nana";
    insert(lb, t);

    fm.show();
    exec();
}
The listbox aslo provides a erase_key() method to remove the category by the specified key.