support for checkboxes added


2008-02-12 08:08:12 PM
cppbuilder97
1. set VCL listview checkboxes property to true
2. provide StateImageList and SmStateImageIndex to ClBaseVirtualListViewFeed
3. connect ClBaseVirtualListViewFeed to listview (connectTo)
#ifndef __ClBaseVirtualListViewFeed_H__
#define __ClBaseVirtualListViewFeed_H__
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
// BEGIN OF USER LICENSE TERMS.
// You must not alter or remove the user license terms.
// You are not allowed to bring any kind of restriction to this user
licence.
// Copyright Eric Britz (I keep ownership and all rights).
// Provided "as is" without express or implied warranty nor support.
// Free of use for any kind of application (use it if you want don't ask).
//
// If you are fair, I suppose you will share any improvement or
correction you might make.
// If you are not fair, well, do not worry there are a lot of people
like you in the world
// you may still find friends.
// END OF USER LICENSE TERMS
//------------------------------------------------------------------------------
template <class _data_class_>class ClBaseVirtualListViewFeed;
//------------------------------------------------------------------------------
template <class _data_class_>
struct tRegexpSortFunctor
{
static std::vector<std::string>* regexps;
static
std::vector<ClBaseVirtualListViewFeed<_data_class_>::tSmColumnDefinitionMth>
* coldefs;
static int __stdcall order(
ClBaseVirtualListViewFeed<_data_class_>::tUserDataRef o1
, ClBaseVirtualListViewFeed<_data_class_>::tUserDataRef o2
)
{
if (!o1 || !o2)
{
return memcmp((void*)o1,(void*)o2,sizeof(ClNodeObject*)) ;
}
std::vector<std::string>str1;
std::vector<std::string>str2;
// get columns content for each object
for
(std::vector<ClBaseVirtualListViewFeed<_data_class_>::tSmColumnDefinitionMth>::iterator
col = coldefs->begin()
, stopcol = coldefs->end()
; col != stopcol
; ++col)
{
std::string t1 = (*col)(o1);
std::string t2 = (*col)(o2);
str1.push_back( t1 );
str2.push_back( t2 );
}
// apply filter
int r1 = 0;
int r2 = 0;
for ( std::vector<std::string>::iterator reg = regexps->begin(),
st1 = str1.begin(), st2 = str2.begin()
, stopreg = regexps->end(), stopst1 = str1.end(), stopst2 = str2.end()
; (reg != stopreg) && (st1 != stopst1) && (st2 != stopst2)
; ++reg, ++st1, ++st2)
{
if ( !reg->size() ) continue;
if ( ClRegexp::contains(
st1->c_str()
, reg->c_str()
, true //ignoreCase
)
)
++ r1;
if ( ClRegexp::contains(
st2->c_str()
, reg->c_str()
, true //ignoreCase
)
)
++ r2;
}
return r2 - r1;
}
}
;
//------------------------------------------------------------------------------
template <class _data_class_>
class ClBaseVirtualListViewFeed
{
// --
//
// -- Attribut
//
// --
protected:
TListView * FListView;
std::vector<_data_class_>& FData;
void __fastcall (__closure * FOldColumnClick)(
System::TObject* Sender
, TListColumn* c
);
void __fastcall (__closure * FOldCustomDrawSubItem)(
TCustomListView* Sender
, TListItem* Item
, int SubItem
, TCustomDrawState State
, bool &DefaultDraw
);
void __fastcall (__closure * FOldCustomDrawItem)(
TCustomListView* Sender
, TListItem* Item
, TCustomDrawState State
, bool &DefaultDraw
);
private:
int FCurrentSort;
std::vector<std::string>FColumnsFilters;
public:
// Typedefs for external use
bool AllColumnsSort;
// Typedefs for external use
typedef _data_class_ & tUserDataRef;
// Image
static TImageList * ImageList;
static TImageList * StateImageList;
typedef int (*tSmImageIndexMth)(
tUserDataRef
) ;
static tSmImageIndexMth SmImageIndex;
typedef int (__closure *tSmStateImageIndexMth)(
tUserDataRef
) ;
tSmStateImageIndexMth SmStateImageIndex;
// Columns definition
typedef std::string (*tSmColumnDefinitionMth)(
tUserDataRef
) ;
std::vector<tSmColumnDefinitionMth>SmColumnDefinition;
// Columns sort
typedef int (__stdcall * tSmColumnSortMth)(
tUserDataRef o1
, tUserDataRef o2
) ;
std::vector<tSmColumnSortMth>SmColumnSort;
tSmColumnSortMth SmDefaultSort;
// Hint
static tSmColumnDefinitionMth SmInfoTypeDefinition;
// Sort sequence
struct tSortSequence
{
std::vector<ClBaseVirtualListViewFeed<_data_class_>::tSmColumnSortMth>
criterias;
bool operator()(
ClBaseVirtualListViewFeed<_data_class_>::tUserDataRef o1
, ClBaseVirtualListViewFeed<_data_class_>::tUserDataRef o2
)
{
for
(std::vector<ClBaseVirtualListViewFeed<_data_class_>::tSmColumnSortMth>::iterator
mth = criterias.begin()
, stopmth = criterias.end()
; mth != stopmth
; ++ mth)
{
int res = (*mth)(o1,o2) ;
if ( res < 0 ) return true;
if ( res>0 ) return false;
// continue if ==
}
return
memcmp((void*)&o1,(void*)&o2,sizeof(ClBaseVirtualListViewFeed<_data_class_>::tUserDataRef))
< 0; // pour etre sur d'avoir un < strict
}
} ;
// --
//
// -- Constructor / destructors
//
// --
public:
// -----------------------------------------------------
ClBaseVirtualListViewFeed(std::vector<_data_class_>& data)
: FData(data)
, FListView(0)
, FCurrentSort(-1)
, FOldColumnClick(0)
, FOldCustomDrawItem(0)
, FOldCustomDrawSubItem(0)
, SmDefaultSort(0)
, AllColumnsSort(true)
, SmStateImageIndex(&noImage2)
{};
// -----------------------------------------------------
~ClBaseVirtualListViewFeed(void)
{
if ( FListView )
{
FListView->OnData = 0;
FListView->OnInfoTip = 0;
FListView->OnColumnClick = 0;
}
};
// --
//
// -- Methods
//
// --
private:
// -----------------------------------------------------
static int noImage1(tUserDataRef)
{ return -1; };
int noImage2(tUserDataRef)
{ return -1; };
// -----------------------------------------------------
void sortOnColumn(int col_idx)
{
if ( col_idx < 0 ) return;
if ( col_idx>SmColumnSort.size() ) return;
// sort data
tSortSequence sort_sequence ;
sort_sequence.criterias.clear();
if ( SmDefaultSort )
sort_sequence.criterias.push_back(SmDefaultSort);
if ( AllColumnsSort )
{
for ( std::vector<tSmColumnSortMth>::iterator colsort =
SmColumnSort.begin()+col_idx
, stopcolsort = SmColumnSort.end()
; colsort != stopcolsort
; ++ colsort)
{
sort_sequence.criterias.push_back(*colsort);
}
for ( std::vector<tSmColumnSortMth>::iterator colsort =
SmColumnSort.begin()
, stopcolsort = SmColumnSort.begin()+col_idx
; colsort != stopcolsort
; ++ colsort)
{
sort_sequence.criterias.push_back(*colsort);
}
}
else
{
std::vector<tSmColumnSortMth>::iterator colsort =
SmColumnSort.begin()+col_idx;
sort_sequence.criterias.push_back(*colsort);
}
std::sort(
FData.begin()
, FData.end()
, sort_sequence
);
};
public:
// -----------------------------------------------------
// Listview event to handle for virtual list view
// -----------------------------------------------------
void __fastcall lvData(
TObject *Sender
,TListItem *Item
)
{
// must sets the items characteristics according to the data
(caption, subitems, imageindex, ...)
const int idx = Item->Index;
if ( idx>= FData.size() ) return;
// retrieve associated object
tUserDataRef data = *(FData.begin() + idx);
// reset item informations
{
Item->Caption = " ---- ";
Item->SubItems->Clear();
}
// set image index
Item->ImageIndex = SmImageIndex(data);
// set caption and sub items
int nbCol = SmColumnDefinition.size();
if ( nbCol>0 )
{
// caption
std::vector<tSmColumnDefinitionMth>::iterator curs
= SmColumnDefinition.begin();
std::vector<tSmColumnDefinitionMth>::iterator stopcurs
= SmColumnDefinition.end();
Item->Caption = (*curs)(data).c_str();
// sub items
Item->SubItems->Clear();
for ( ++curs
; curs != stopcurs
; ++curs
)
{
Item->SubItems->AddObject(
(*curs)(data).c_str()
, 0
);
}
}
};
void __fastcall lvInfoTip(
System::TObject* Sender
, TListItem* Item
, AnsiString &InfoTip
)
{
// must provide individual item's hint
const int idx = Item->Index;
if ( idx>= FData.size() ) return;
// retrieve associated object
tUserDataRef data = *(FData.begin() + idx);
InfoTip = (
SmInfoTypeDefinition
? SmInfoTypeDefinition(data).c_str()
: ""
);
};
// -----------------------------------------------------
// Listview event to handle column sort
// -----------------------------------------------------
void __fastcall lvColumnClick(
System::TObject* Sender
, TListColumn* c
)
{
if ( FOldColumnClick )
FOldColumnClick (
Sender
, c
);
if ( FListView->ComponentState.Contains(csDestroying) )
return ;
TCursor prev_cursor = Screen->Cursor;
Screen->Cursor = crHourGlass;
try {
// must sort local data and invalidate listview to force redrawing
if ( c->Index < (int)SmColumnSort.size() )
{
// remember column index for later sort
FCurrentSort = c->Index;
sortOnColumn(FCurrentSort);
// invalidate list view to force redraw
FListView->Invalidate();
}
} __finally { Screen->Cursor = prev_cursor; }
};
// -----------------------------------------------------
// Listview event to customize items' drawing
// -----------------------------------------------------
void __fastcall lvCustomDrawSubItem(
TCustomListView* Sender
, TListItem* Item
, int SubItem
, TCustomDrawState State
, bool &DefaultDraw
)
{
const int idx = Item->Index;
if ( idx>= FData.size() ) return;
if ( FOldCustomDrawSubItem )
FOldCustomDrawSubItem (
Sender
, Item
, SubItem
, State
, DefaultDraw
);
Sender->Canvas->Brush->Style = bsClear;
const int col_idx = SubItem;
// if currently sorting from column val
if ( col_idx == FCurrentSort )
{
Sender->Canvas->Brush->Style = bsSolid;
Sender->Canvas->Brush->Color = (TColor)RGB(254,255,183);
}
else
{
Sender->Canvas->Brush->Style = bsClear;
}
// if currently sorting from list af regexps
if ( (FCurrentSort == - 2)
&& (FColumnsFilters[col_idx].size()>0)
&& (col_idx < FColumnsFilters.size())
&& (FColumnsFilters[col_idx].size()>0) ) //regexp filter
{
std::string val = SmColumnDefinition[col_idx](*(FData.begin() +
idx));
if ( ClRegexp::contains(
val.c_str()
, FColumnsFilters[col_idx].c_str()
, true //ignoreCase
)
)
{
Sender->Canvas->Brush->Style = bsSolid;
Sender->Canvas->Brush->Color = (TColor)RGB(254,255,183);
}
else
{
Sender->Canvas->Brush->Style = bsClear;
}
}
};
// -----------------------------------------------------
void __fastcall lvCustomDrawItem(
TCustomListView* Sender
, TListItem* Item
, TCustomDrawState State
, bool &DefaultDraw
)
{
const int idx = Item->Index;
if ( idx>= FData.size() ) return;
if ( FOldCustomDrawItem )
FOldCustomDrawItem (
Sender
, Item
, State
, DefaultDraw
);
Sender->Canvas->Brush->Style = bsClear;
// if currently sorting from 1st column val
if ( FCurrentSort == 0 )
{
Sender->Canvas->Brush->Style = bsSolid;
Sender->Canvas->Brush->Color = (TColor)RGB(254,255,183);
}
else
{
Sender->Canvas->Brush->Style = bsClear;
}
// if currently sorting from list of regexps
if ( (FCurrentSort == - 2) && (FColumnsFilters[0].size()>0) )
//regexp filter
{
std::string val = SmColumnDefinition[0](*(FData.begin() + idx));
if ( ClRegexp::contains(
val.c_str()
, FColumnsFilters[0].c_str()
, true //ignoreCase
)
)
{
Sender->Canvas->Brush->Style = bsSolid;
Sender->Canvas->Brush->Color = (TColor)RGB(254,255,183);
}
else
{
Sender->Canvas->Brush->Style = bsClear;
}
}
// CB custom drawing
if ( FListView->Checkboxes && StateImageList )
{
TRect rectIcon = Item->DisplayRect(drIcon);
HDC Hdc = FListView->Canvas->Handle;
HIMAGELIST Himl =
reinterpret_cast<HIMAGELIST>(StateImageList->Handle);
tUserDataRef data = *(FData.begin() + idx);
ImageList_DrawEx(
Himl
, SmStateImageIndex(data) /* Item->ImageIndex */
, Hdc
, rectIcon.Left-StateImageList->Width
, rectIcon.Top
, 0
, 0
, CLR_NONE
, RGB(255,255,255)
, ILD_TRANSPARENT
);
}
};
public:
void connectTo(TListView * lv)
{
if ( FListView ) return;
FListView = lv;
FListView->Items->Clear();
FListView->SmallImages = ImageList;
FListView->OwnerData = true;
FListView->OnData = &lvData;
FListView->OnInfoTip = &lvInfoTip;
FOldColumnClick = FListView->OnColumnClick;
FListView->OnColumnClick = &lvColumnClick;
FOldCustomDrawSubItem = FListView->OnCustomDrawSubItem ;
FListView->OnCustomDrawSubItem = &lvCustomDrawSubItem;
FOldCustomDrawItem = FListView->OnCustomDrawItem ;
FListView->OnCustomDrawItem = &lvCustomDrawItem;
};
void updateList(void) const
{
if ( !FListView ) return;
FListView->Items->Count = FData.size();
FListView->Invalidate();
};
void sortAgain(void)
{
sortOnColumn(FCurrentSort);
};
void sort(std::vector<std::string>& regexps)
{
FColumnsFilters.clear();
FColumnsFilters = regexps;
// sort data
tRegexpSortFunctor<_data_class_>::regexps = &FColumnsFilters;
tRegexpSortFunctor<_data_class_>::coldefs = &SmColumnDefinition;
tSortSequence sort_sequence ;
sort_sequence.criterias.clear();
if ( SmDefaultSort )
sort_sequence.criterias.push_back(SmDefaultSort);
sort_sequence.criterias.push_back(tRegexpSortFunctor<_data_class_>::order);
FCurrentSort = -2;
std::sort(
FData.begin()
, FData.end()
, sort_sequence
);
// invalidate list view to force redraw
updateList();
};
};
//------------------------------------------------------------------------------
#ifndef ClBaseVirtualListViewFeed_statics
#define ClBaseVirtualListViewFeed_statics
template <class _data_class_>
TImageList *
ClBaseVirtualListViewFeed<_data_class_>::ImageList = 0;
template <class _data_class_>
TImageList *
ClBaseVirtualListViewFeed<_data_class_>::StateImageList = 0;
template <class _data_class_>
ClBaseVirtualListViewFeed<_data_class_>::tSmImageIndexMth
ClBaseVirtualListViewFeed<_data_class_>::SmImageIndex
= ClBaseVirtualListViewFeed<_data_class_>::noImage1;
template <class _data_class_>
std::vector<std::string>*
tRegexpSortFunctor<_data_class_>::regexps
= 0;
template <class _data_class_>
std::vector<ClBaseVirtualListViewFeed<_data_class_>::tSmColumnDefinitionMth>
*
tRegexpSortFunctor<_data_class_>::coldefs
= 0;
template <class _data_class_>
ClBaseVirtualListViewFeed<_data_class_>::tSmColumnDefinitionMth
ClBaseVirtualListViewFeed<_data_class_>::SmInfoTypeDefinition = 0;
#endif
#endif