Board index » cppbuilder » support for checkboxes added
E B
![]() CBuilder Developer |
support for checkboxes added2008-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 |