wxGrid class extended

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
Post Reply
seb_seb0
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Mar 29, 2009 11:33 am

wxGrid class extended

Post by seb_seb0 » Mon Mar 30, 2009 8:14 pm

Hello,

I have programmed a class derived from wxGrid. It does the following:
- basic sorting (1 column only for now, only one algorithm)
- basic filtering (based on Regular Expression) - only text filtering is supported for now (no "<" or ">" operators for numeric types or dates supported yet).
- it can be used by simply replacing all occurences of wxGrid by wxEGrid, and adding the wxEGrid.h and wxEGrid.cpp in the project (no lib compilation necessary). I have successfully compiled griddemo.cpp (wxWidgets sample) with this method.

I will make it available on wxCode later - the procedure is a bit complex for now - and I have just 10 minutes before my wife screams on me for being too much on the computer...

My questions are:
- are there plans to support sorting and/or filtering in wxWidgets ?
- I have seen some advanced Table widgets (closed source) in .NET application with very performant filters (RegEx also, and fast...) and with a hierarchical organisation feature (possible to groups data based on values in a tree control style - this hierarchy can be multileveled). Are there some plans similar to that in wxWidgets ? (I suspect it is a huge piece of work).
- I have found a small bug in wxGridWindow class. The mouse capture is sometimes not released (try selecting some cells while scrolling to the top or the bottom). Is it a known bug ? It could be solved in a few lines I guess (processing a mouse button left up event). I will post a solution later on the bug tracking list.

I post the code in the next posts.

Sebastien
Last edited by seb_seb0 on Mon Mar 30, 2009 8:27 pm, edited 2 times in total.

seb_seb0
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Mar 29, 2009 11:33 am

Post by seb_seb0 » Mon Mar 30, 2009 8:16 pm

Here is the code. There are 2 files (wxEGrid.h and wxEGrid.cpp)

wxEGrid.h:

Code: Select all

#ifndef EGRID_H
#define EGRID_H

#include <wx/grid.h>
#include <wx/dc.h>
#include <wx/dcclient.h>
#include <wx/settings.h>
#include <wx/gdicmn.h>
#include <wx/renderer.h>
#include <wx/combobox.h>
#include <wx/dynarray.h>
#include <wx/regex.h>
#include <wx/checklst.h>
#include <wx/textctrl.h>
#include <wx/dialog.h>
#include <wx/button.h>

#include <wx/msgdlg.h>

#define WX_EGRID_MERGE_SORT     1
#define WX_EGRID_QUICK_SORT     2
#define WX_EGRID_SHELL_SORT     3
#define WX_EGRID_INSERTION_SORT 4

#define WX_EGRID_ASCENDING      0
#define WX_EGRID_DESCENDING     1

#define WX_STRING_ARRAY_SIZE   100
#define WX_ROW_ARRAY_SIZE      100
#define WX_ROWCOL_ARRAY_SIZE   100
#define WX_VALUENOTFOUND        -1

/**
 the wxGridTableBase must implement the following methods:
    - GetValue()
    - InsertCols()
    - GetNumberCols()
 for working
**/

class wxEGrid; //derived from wxGrid. Implement built-in filters & sorting
class wxPopupFilter; //for the combobox filter

class wxPopupFilter : public wxDialog
{
 public:
  wxPopupFilter(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size); //constructor
  ~wxPopupFilter(void); //destructor
  void Clear(void); //clear the list box
  int Append(wxString sValue); //append the value to the listbox
  void InsertItems(const wxArrayString &items, unsigned int pos); //insert the value to the listbox
  bool SetBackgroundColour(const wxColour &  colour);  //set the background colour
  void Popup(void);
  void SetGrid(wxEGrid *g); //set the grid member
  wxEGrid* GetGrid(void); //get the grid member
  void SetTextCtrl(wxTextCtrl *p); //set the pointer to the text control
  void SetBackgroundColour(wxColour& colour); //override
  void GetVirtualSize(int *width, int *height) const; //override

 protected:
  wxCheckListBox* ListBox;
  wxScrolledWindow* Panel;
  wxEGrid *grid;
  wxTextCtrl *pTextCtrl;
  void OnResize(wxSizeEvent& event); //process a size event
  void OnKillFocus(wxFocusEvent &event);
  void OnActivateWin(wxActivateEvent& event);
  void OnItemSelected(wxCommandEvent& event); //the selection in the CheckListBox changed

};

class wxEGrid : public wxGrid
{
 public:
  /** constructors and Destructors  **/
  wxEGrid(wxWindow* parent,
          wxWindowID id = wxID_ANY,
          const wxPoint& pos = wxDefaultPosition,
          const wxSize& size = wxSize( 500,300 ),
          long style = wxTAB_TRAVERSAL,
          const wxString& name = wxPanelNameStr);
  ~wxEGrid();

  /** OVERRIDEN FUNCTIONS FROM wxGrid **/
  virtual void DrawColLabels(wxDC& dc, const wxArrayInt& cols); //Draw a range of column labels, including filters
  virtual void DrawColLabel(wxDC& dc, int col); //draw one column label + filter
  virtual void DrawRowLabels(wxDC& dc, const wxArrayInt& rows); //draw a range of row labels
  virtual void DrawRowLabel(wxDC& dc, int row);//draw 1 row label
  virtual void DrawCornerLabel(wxDC& dc); //draw the corner window
  void UseNativeColHeader(bool native = true); //indicate if wxRendererNative should be used for drawing col labels
  void SetUseNativeColLabels(bool native); //indicate if wxRendererNative should be used for drawing col labels
  bool AppendCols(int  numCols = 1, bool  updateLabels = true); //add numCols column at the end of the table
  bool DeleteCols(int  pos = 0,int  numCols = 1, bool  updateLabels = true); //Delete numCols in the table at the position "pos"
  bool InsertCols(int  pos = 0,int  numCols = 1, bool  updateLabels = true); //Add numCols in the table at the position "pos"
  bool AppendRows(int numRows=1, bool updateLabels=true); //add numRows rows at the end of the table
  bool DeleteRows(int pos=0, int numRows=1, bool updateLabels=true); //delete numRows rows in the table at the position "pos"
  bool InsertRows(int pos=0, int numRows=1, bool updateLabels=true); //insert numRows rows in the table at the position "pos"
  bool CreateGrid(int numRows, int numCols, wxGridSelectionModes selmode=wxGridSelectCells); //Create the grid table
  bool SetTable(wxGridTableBase *table, bool takeOwnership=false, wxGridSelectionModes selmode=wxGridSelectCells); //add a data table to the grid
  void HideRow(int row); //Hide a row
  void ShowRow(int row); //show a hidden row
  bool IsRowShown(int  row) const; //returns true if a row is shown

  /** FILTER API **/
  bool IsFilter(void);  //return the current filter status
  void SetFilter(bool enable=true); //set the filter (true = filters are activated and displayed)
  void SetFactor(double factor); //Set the multiplicating factor for the displaying the filters
  double GetFactor(void); //Get the multiplicating factor for the displaying the filters
  wxString GetFilterValue(int col); //returns the current value of the filter
  int GetFilterState(int col); //returns wxCONTROL_CURRENT or wxCONTROL_PRESSED
  void ResetFilterState(void); //reset the filter arrow state
  void SetCurrentFilterValue(wxString value); //Set the value of the current filter
  void ClearFilter(int col); //reset the value of a specific filter
  void ClearAllFilter(void); //reset the value of all filters
  void ApplyFilter(int col, bool bRecompute = false,
                   bool bListFilteredValue = false); //apply the filter for a specific column
  void ApplyAllFilter(bool bRecompute = false,
                      bool bListFilteredValue = false); //apply all filters to each column
  wxWindow* GetFilterWindow(void); //return a pointer to the filter band
  void SetRegExFlag(int flag);  //Set the RegEx type
  int GetRegExFlag(void);       //return the RegEx type
  bool AreFilteredApplied(void); //indicate if one or more filters are applied

 /** SORTING API **/
 bool IsSortingBy(int col = 0) const; //return true if the column sorts
 int GetSortingColumn(void) const; //return the 1st column used for sorting
 bool IsSortOrderAscending(int col = 0) const; //get the sort order of the column
 void SetSortingColumn(int col, bool ascending = true, int key = 1); //set the sorting order of the column
 void UnsetSortingColumn(void); //resets the sorting columns
 void Sort(int algo = WX_EGRID_INSERTION_SORT); //sort the table
 void SwapRows(int row1, int row2); //invert the content from row1 and row2
 void CopyRow(int row1, int row2); //copy row2 in row1

 /** VISUAL ATTRIBUTE API **/
 void GetFilterArrowDim(int *width, int *height); //get the filter arrow Dimension
 void SetFilterArrowDim(int width, int height);   //set the filter arrow Dimension
 wxColour GetFilterArrowColourOn(void);          //get the filter arrow color ON
 void SetFilterArrowColourOn(wxColour colour);    //set the filter arrow color ON
 wxColour GetFilterArrowColourOff(void);          //get the filter arrow color OFF
 void SetFilterArrowColourOff(wxColour colour);    //set the filter arrow color OFF
 wxColour GetFilterBkColourOn(void);                   //get the filter background color ON
 void SetFilterBkColourOn(wxColour colour);       //set the filter background color ON
 wxColour GetFilterBkColourOff(void);          //get the filter background color OFF
 void SetFilterBkColourOff(wxColour colour);     //set the filter background color OFF
 wxColour GetSortingArrowColour(void);          //get the sorting arrow color
 void SetSortingArrowColour(wxColour colour);     //set the sorting arrow color OFF

 protected:
  wxEGrid* Grid;
  void OnLabelClick(wxGridEvent& event); //process click on a filter
  void OnFilterTextLoseFocus(wxFocusEvent& event); //Text Field of filter lose focus
  void OnFilterTextCharEvent(wxKeyEvent& event); //Text Field process a WXK_RETURN char event
  void OnTextChangedEvent(wxCommandEvent& event); //process a text change in the filter text control
  void SetColSizeEvent(wxGridSizeEvent& event); //resize the filters after column resize when needed
  void OnClearFilter(wxCommandEvent& event); //the button "CLEAR" was clicked - clear all filters
  void OnLeftUp(wxMouseEvent& event); //Release mouse capture

  /**Protected filter API **/
  wxArrayString ListValues(int col); //returns the content of the filter for a specific column
  void Add_Filter(int pos); //insert a new filter (wxString) at pos
  void Remove_Filter(int pos);  //remove an existing filter (wxString) at pos
  void Empty_Filters(void); //delete the wxString created
  void Add_FRows(int pos); //add one row to the filtered row array
  void Remove_FRows(int pos);  //remove one row from the filtered row array
  void Empty_FRows(void); //delete the filtered row arrays
  bool IsAppliedFilter(int row,int col); //indicate if a row is filtered according to a column  different from col
  void ResetFilter(int col); //remove the filter from a specific column
  void SetFilteredRow(int row); //set the IsRowFiltered flag for a row

  /** PROTECTED SORTING API **/
  void InsertionSort(); //sort the table

 private:
  //private members
  int LabelHeight; //Label Heigth
  double f;        //multiplicating factor, for drawing the filters
  bool bFilterOn;  //true if filters are ON (displayed), false otherwise
  int ArrowHeight; //height of the Filter Arrow
  int ArrowWidth;  //width of the Filter Arrow
  wxColour FilterArrowColourOn; //Colour of the Filter arrow when ON
  wxColour FilterArrowColourOff; //Colour of the Filter arrow when OFF
  wxColour FilterBkColourOn; //Colour of the Filter text when ON
  wxColour FilterBkColourOff;//Colour of the Filter text when OFF
  wxColour SortArrowColor; //Colour of the sorting arrow
  wxTextCtrl *FilterTextCtrl;  //the text field that receives the RegEx for filtering
  wxPopupFilter *FilterListCtrl; //The CheckListBox which shows the differents value available
  wxButton *ClearFilterButton; //Button to disable filter
  int iCurrentCol; //the column impacted by a filter focus (text control of listbox)
  int FilterState; //>0: the corresponding column filter button is pressed. -1: no buttons pressed
  int iMinimalHeight; //Minimal Acceptable Height for the rows
  int iRegExType; //wxRE_ADVANCED, wxRE_EXTENDED, wxRE_BASIC
  //filters data
  wxString **Values;    //List of Current filter values
  int iFilterNumber;   //amount of filter really allocated (nb of wxString pointers of "Values")
  int iFilterMaxNumber; //amount of filters that can be allocated (size of "Values")
  bool *IsRowFiltered; //indicate if a row is hidden due to a filter (size = iRealSize)
  int **AppliedFilter; //indicate which filters (col index) applies on the row (size = iRealSize * iSize[i])
  int *iSize;          //size of the arrays in AppliedFilter
  int iUsedSize;       //used size of the dynamic arrays
  int iRealSize;       //real (allocated) size of the dynamic arrays
  bool bFilterApplied; //indicate if filtering is applied
  int *iSorting;       //indicate if a column is a sorting column, and in which direction
  int iSortSize;       //size of the array iSortSize

};

#endif // EGRID_H

seb_seb0
In need of some credit
In need of some credit
Posts: 8
Joined: Sun Mar 29, 2009 11:33 am

Post by seb_seb0 » Mon Mar 30, 2009 8:19 pm

wxEGrid.cpp:

Code: Select all

#include "wxegrid.h"

/***********************************************************/
/*************** wxPopupFilter CLASS ***********************/
/******************  POPUP CLASS  **************************/
/***********************************************************/
wxPopupFilter::wxPopupFilter(wxWindow* parent,wxWindowID id,const wxPoint& pos,const wxSize& size)
{
 //constructor
 wxWindowID idList;

 //wxWS_EX_TRANSIENT style can maybe be used
 Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxRESIZE_BORDER, _T("id"));
 ListBox = NULL;
 Panel = NULL;
 grid = NULL;

 Panel = new wxScrolledWindow(this, wxID_ANY);
 ListBox = new wxCheckListBox(Panel, wxID_ANY, wxPoint(0,0), wxDefaultSize, 0, 0,
                              wxLB_SINGLE | wxBORDER_NONE |wxLB_HSCROLL,
                              //wxLB_MULTIPLE | wxBORDER_NONE |wxLB_HSCROLL,
                              wxDefaultValidator, _T("ID_CHECKLISTBOX1"));
 idList = ListBox->GetId();
 pTextCtrl = NULL;
 Connect(wxEVT_SIZE, (wxObjectEventFunction)&wxPopupFilter::OnResize);
 Connect(wxEVT_ACTIVATE, (wxObjectEventFunction)&wxPopupFilter::OnActivateWin);
 Connect(wxEVT_KILL_FOCUS, (wxObjectEventFunction)&wxPopupFilter::OnKillFocus);
 Connect(idList,wxEVT_COMMAND_CHECKLISTBOX_TOGGLED,(wxObjectEventFunction) &wxPopupFilter::OnItemSelected);

}

wxPopupFilter::~wxPopupFilter(void)
{
 //destructor
 if (HasCapture()) ReleaseMouse();
}

void wxPopupFilter::SetBackgroundColour(wxColour& colour)
{
 if (ListBox != NULL) ListBox->SetBackgroundColour(colour);
 wxWindow::SetBackgroundColour(colour);
}

void wxPopupFilter::OnActivateWin(wxActivateEvent& event)
{
 //activate or diactivate window

 if (!event.GetActive())
 {
  Show(false);
  if (grid != NULL)
  {
   grid->ApplyAllFilter();
   grid->ResetFilterState();
   grid->ForceRefresh();
  }
 }

 event.Skip();
}

void wxPopupFilter::OnItemSelected(wxCommandEvent& event)
{
 //the selection in the CheckListBox changed
 int i, iMax;
 wxString s, sFilter;

 //Get the list of all checked element
 if (pTextCtrl == NULL) return;
 i = event.GetInt();
 s = event.GetString();

 if (ListBox->IsChecked(i))
 {
  if (s == "<ALL>")
  {
   //pTextCtrl->SetValue(".*");
   pTextCtrl->SetValue("");
   return;
  }

  if (s == "<BLANK>")
  {
   pTextCtrl->SetValue("^$");
   return;
  }

  if (s == "<NON BLANK>")
  {
   pTextCtrl->SetValue(".+");
   return;
  }
 }

 //scan all texts
 iMax = ListBox->GetCount();
 sFilter = wxEmptyString;
 for(i=0;i<iMax;i++)
 {
  if (ListBox->IsChecked(i))
  {
   if (sFilter != wxEmptyString) sFilter += "|";
   sFilter += "^";
   sFilter += ListBox->GetString(i);
   sFilter += "$";
  }
 }
 pTextCtrl->SetValue(sFilter);

}

void wxPopupFilter::SetGrid(wxEGrid *g)
{
 //set the grid member
 grid = g;
}

wxEGrid* wxPopupFilter::GetGrid(void)
{
 //get the grid member
 return(grid);
}

bool wxPopupFilter::SetBackgroundColour(const wxColour &  colour)
{
 //set the background colour
 bool bResult;
 bResult = wxWindow::SetBackgroundColour(colour);
 if (ListBox != NULL) ListBox->SetBackgroundColour(colour);
 return(bResult);
}

void wxPopupFilter::Popup(void)
{
 Show(true);
}

void wxPopupFilter::OnResize(wxSizeEvent& event)
{
 //process a size event
 wxSize cs;

 cs = GetClientSize();

 if (Panel != NULL)
 {
  //cs.SetHeight(50);
  Panel->SetSize(cs);
 }


 if (ListBox != NULL)
 {
  //cs.SetHeight(50);
  ListBox->SetSize(cs);
 }
}

void wxPopupFilter::Clear(void)
{
 //clear the list box
 if (ListBox != NULL) ListBox->Clear();
}

int wxPopupFilter::Append(wxString sValue)
{
 //append the value to the listbox
 if (ListBox != NULL)
 {
  return(ListBox->Append(sValue));
 }
 return(-1);
}

void wxPopupFilter::InsertItems(const wxArrayString &items, unsigned int pos)
{
 //insert the value to the listbox
 if (ListBox != NULL)
 {
  ListBox->Append(items);
 }
 return;
}

void wxPopupFilter::OnKillFocus(wxFocusEvent &event)
{
 wxWindow *LabelWin;
 if (HasCapture())
 {
  ReleaseMouse();
  Show(false);
  if (grid != NULL)
  {
   LabelWin = (wxWindow *) grid->GetFilterWindow();
   if (LabelWin != NULL)
   {
    LabelWin->Refresh(true,NULL);
    LabelWin->Update();
   }
   grid->ResetFilterState();
   grid->ForceRefresh();
   grid->Update();
  }
 }
 event.Skip();
}

void wxPopupFilter::SetTextCtrl(wxTextCtrl *p)
{
 //set the pointer to the text control
 pTextCtrl = p;
}

void wxPopupFilter::GetVirtualSize(int *width, int *height) const
{
 //override
 if (ListBox != NULL)
 {
  ListBox->GetVirtualSize(width,height);
 }
 else
 {
  wxWindow::GetVirtualSize(width,height);
 }
}

/***********************************************************/
/*********************** EGRID CLASS ***********************/
/******************  THE MAIN CLASS  ***********************/
/***********************************************************/

wxEGrid::wxEGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
: wxGrid(parent, id, pos, size, style)
{
 //CONSTRUTOR
 wxColourDatabase wxColourDB;
 wxWindow *gWindow, *GridWindow;
 wxWindowID TextCtrlID, ButttonID;
 int iHeight1, iHeight2;

 iHeight1 = GetRowMinimalAcceptableHeight();
 iHeight2 = GetDefaultRowSize();
 iMinimalHeight = wxMax(iHeight1, iHeight2);
 SetRowMinimalAcceptableHeight(0);

 ArrowWidth = 8;
 ArrowHeight = 4;

 //Constructor
 Grid = this;
 bFilterOn = true;
 LabelHeight = GetColLabelSize();
 gWindow = GetGridColLabelWindow();
 //gWindow = this;

 //increase the LabelHeight by f for the place for the Filters
 f = 1.7;
 LabelHeight = LabelHeight * f;
 SetColLabelSize(LabelHeight);

 //Filters colour
 FilterArrowColourOn = *wxRED;
 FilterArrowColourOff = *wxBLACK;
 FilterBkColourOn = wxColourDB.Find("LIGHT BLUE"); //STEEL BLUE
 FilterBkColourOff = *wxWHITE;


 iRegExType = wxRE_ADVANCED;

 //filters data
 iCurrentCol = -1;
 FilterState = -1;
 FilterTextCtrl = NULL;
 FilterListCtrl = NULL;
 Values = NULL;
 IsRowFiltered = NULL;
 AppliedFilter = NULL;
 iSize = NULL;
 iFilterNumber = 0;
 iFilterMaxNumber = 0;
 iUsedSize = 0;
 iRealSize = 0;
 bFilterApplied = false;

 //sorting
 iSorting = NULL;
 iSortSize = 0;

 //Bug Correction
 GridWindow = GetGridWindow();
 if (GridWindow != NULL)
 {
  //GridWindow->Connect(wxEVT_LEFT_UP,(wxObjectEventFunction)&wxEGrid::OnLeftUp);
 }

 //clear filter button
 ClearFilterButton = new wxButton(this, wxID_ANY, "CLEAR", wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON"));
 if (ClearFilterButton != NULL)
 {
  ClearFilterButton->Show(true);
  ButttonID = ClearFilterButton->GetId();
  Connect(ButttonID, wxEVT_COMMAND_BUTTON_CLICKED ,(wxObjectEventFunction)&wxEGrid::OnClearFilter);
 }

 //filter widgets
 FilterTextCtrl = new wxTextCtrl(gWindow, wxID_ANY, _("Text"), wxPoint(96,288), wxDefaultSize, wxTE_CENTRE | wxTE_PROCESS_ENTER, wxDefaultValidator, _T("ID_TEXTCTRL1"));
 if (FilterTextCtrl != NULL)
 {
  FilterTextCtrl->Show(false);
 }

 FilterListCtrl = new wxPopupFilter(gWindow, wxID_ANY, wxDefaultPosition, wxDefaultSize);
 if (FilterListCtrl != NULL)
 {
  FilterListCtrl->Show(false);
  FilterListCtrl->SetGrid(this);
  FilterListCtrl->SetBackgroundColour(FilterBkColourOff);
  FilterListCtrl->SetTextCtrl(FilterTextCtrl);
 }

 //sort arrow color
 SortArrowColor = *wxBLACK; //Colour of the sorting arrow

 //events for filter click
 Connect(wxEVT_GRID_LABEL_LEFT_CLICK,(wxObjectEventFunction)&wxEGrid::OnLabelClick);
 Connect(wxEVT_GRID_COL_SIZE,(wxObjectEventFunction)&wxEGrid::SetColSizeEvent);

 //connects events for the filters
 if (FilterTextCtrl != NULL)
 {
  FilterTextCtrl->Connect(wxEVT_KILL_FOCUS, (wxObjectEventFunction)&wxEGrid::OnFilterTextLoseFocus, NULL, this);
  FilterTextCtrl->Connect(wxEVT_CHAR, (wxObjectEventFunction)&wxEGrid::OnFilterTextCharEvent, NULL, this);
  TextCtrlID = FilterTextCtrl->GetId();
  Connect(TextCtrlID, wxEVT_COMMAND_TEXT_UPDATED,(wxObjectEventFunction)&wxEGrid::OnTextChangedEvent);
 }
}

wxEGrid::~wxEGrid()
{
 //DESTRUCTOR
 int i, iMax;

 //delete objects
 if (FilterTextCtrl != NULL) FilterTextCtrl->Destroy();
 if (FilterListCtrl != NULL) FilterListCtrl->Destroy();

 if (Values != NULL)
 {
  for(i=0; i<iFilterNumber; i++) delete Values[i];
  free(Values);
 }

 if (iSorting != NULL) free(iSorting);

 if (IsRowFiltered != NULL) free(IsRowFiltered);

 if (AppliedFilter != NULL)
 {
  iMax = iUsedSize;
  for(i=0; i<iMax; i++)
  {
   if (AppliedFilter[i] != NULL) free(AppliedFilter[i]);
  }
  free(AppliedFilter);
 }
 if (iSize != NULL) free(iSize);


 // Disconnect Events
 Disconnect(wxEVT_GRID_LABEL_LEFT_CLICK,(wxObjectEventFunction)&wxEGrid::OnLabelClick);
 Disconnect(wxEVT_GRID_COL_SIZE,(wxObjectEventFunction)&wxEGrid::SetColSizeEvent);

}

/** EVENTS HANDLERS **/
void wxEGrid::OnLeftUp(wxMouseEvent& event)
{
 //release mouse capture
 wxWindow *GridWindow;


 if (HasCapture())
 {
  ReleaseMouse();
 }
 else
 {
  GridWindow = GetGridWindow();
  if (GridWindow != NULL)
  {
   if (GridWindow->HasCapture())
   {
    GridWindow->ReleaseMouse();
   }
  }
 }

}


void wxEGrid::OnClearFilter(wxCommandEvent& event)
{
 //the button "CLEAR" was clicked - clear all filters
 BeginBatch();
 ClearAllFilter();
 EndBatch();
}

void wxEGrid::OnFilterTextLoseFocus(wxFocusEvent& event)
{
 //Text Field of filter lose focus
 if (FilterTextCtrl != NULL)
 {
  SetCurrentFilterValue(FilterTextCtrl->GetValue());
  ApplyFilter(iCurrentCol);
  FilterTextCtrl->Show(false);
  iCurrentCol = -1;
 }
 event.Skip();
}

void wxEGrid::OnTextChangedEvent(wxCommandEvent& event)
{
 //process a text change in the filter text control
 wxWindow *LabelWindow;
 wxRect InvalideArea;
 int iRight, iLeft, x, y;
 wxString sValue;

 sValue = FilterTextCtrl->GetValue();
 SetCurrentFilterValue(sValue);
 //change the Background color of the text control
 if (sValue == wxEmptyString)
 {
  FilterTextCtrl->SetBackgroundColour(FilterBkColourOff);
  FilterListCtrl->SetBackgroundColour(FilterBkColourOff);
 }
 else
 {
  FilterTextCtrl->SetBackgroundColour(FilterBkColourOn);
  FilterListCtrl->SetBackgroundColour(FilterBkColourOn);
 }

 //repaint the filter arrow to get the correct color
 LabelWindow = GetGridColLabelWindow();
 iLeft = GetColLeft(iCurrentCol);
 iRight = GetColRight(iCurrentCol);
 CalcUnscrolledPosition(0,0,&x,&y);
 InvalideArea = wxRect(iLeft-x,0,iRight - iLeft,LabelHeight);
 if (LabelWindow != NULL)
 {
  LabelWindow->Refresh(true,&InvalideArea);
  LabelWindow->Update();
 }
}

void wxEGrid::OnFilterTextCharEvent(wxKeyEvent& event)
{
 //Text Field process a WXK_RETURN char event

 if (FilterTextCtrl != NULL)
 {
  if (event.GetKeyCode() == WXK_RETURN)
  {
   SetCurrentFilterValue(FilterTextCtrl->GetValue());
   ApplyFilter(iCurrentCol);
   FilterTextCtrl->Show(false);
   iCurrentCol = -1;
  }
  else
  {
   SetCurrentFilterValue(FilterTextCtrl->GetValue());
  }
 }
 event.Skip();
}

/** OVERRIDEN FUNCTIONS FROM wxGrid **/

void wxEGrid::DrawColLabels(wxDC& dc, const wxArrayInt& cols)
{
 //Draw a range of column labels, including filters
 int i,  numLabels;
 wxCoord width,height;
 int iLeft, iWidth,x,y;
 wxRect r;

 numLabels = GetNumberCols();
 dc.GetSize(&width, &height);
 CalcScrolledPosition(0,0,&x,&y);

 for(i = 0; i < numLabels; i++ )
 {
  r = CellToRect(0,i);
  iLeft = r.GetX() + x;
  iWidth = r.GetWidth();
  if ((iLeft+iWidth > 0) && (iLeft<width)) DrawColLabel(dc,i);
 }

}



void wxEGrid::DrawColLabel(wxDC& dc, int col)
{
 //draw one column label + filter
 //wxGrid::DrawColLabel(dc,col);
 int colLeft,colRight;
 int hAlign, vAlign;
 int orient;
 int lh, lh2, lh3, iColWidth;
 wxRect rect,rect3,rect4;
 wxFont ft;
 wxString FilterValue;
 wxBrush FilterBkBrush, ArrowBkBrush;
 wxPoint Pt[3];
 int iActivated;

 if ( GetColWidth(col) <= 0 || LabelHeight <= 0 ) return;

 colLeft = GetColLeft(col);
 if (bFilterOn) lh = LabelHeight / f; else lh = LabelHeight;
 lh2 = lh + (LabelHeight - lh) / 2;
 lh3 = ArrowHeight / 2;

 iColWidth = GetColWidth(col);
 rect = wxRect(colLeft, 0, iColWidth, lh);

 if ( m_nativeColumnLabels )
 {
  wxRendererNative::Get().DrawHeaderButton((wxWindow*)GetColLabelWindow(),
                                           dc,
                                           rect,
                                           0,
                                           IsSortingBy(col)
                                           ? IsSortOrderAscending(col)
                                             ? wxHDR_SORT_ICON_UP
                                             : wxHDR_SORT_ICON_DOWN
                                           : wxHDR_SORT_ICON_NONE
                                          );
  //draw vertical lines for filters
  colRight = GetColRight(col) - 1;
  dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
  dc.DrawLine(colRight, lh,
              colRight, LabelHeight - 1);
  dc.DrawLine(colLeft, lh - 1,
              colRight , lh - 1);
  dc.SetPen(*wxWHITE_PEN);
  dc.DrawLine(colLeft, lh, colLeft,LabelHeight - 1);
  dc.DrawLine(colLeft, lh ,
              colRight , lh );

 }
 else
 {
  colRight = GetColRight(col) - 1;

  dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
  dc.DrawLine(colRight, 0,
              colRight, LabelHeight - 1);
  dc.DrawLine(colLeft, 0,
              colRight, 0);
  dc.DrawLine(colLeft, LabelHeight - 1,
              colRight + 1, LabelHeight - 1);

  //Filter
  dc.DrawLine(colLeft, lh - 1,
              colRight , lh - 1);


  dc.SetPen(*wxWHITE_PEN);
  dc.DrawLine(colLeft, 1, colLeft,LabelHeight - 1);
  dc.DrawLine(colLeft, 1, colRight, 1);
  //Filter
  dc.DrawLine(colLeft, lh ,
              colRight , lh );

  //sorting arrow
  if (IsSortingBy(col))
  {
   dc.SetBrush(wxBrush(SortArrowColor));
   dc.SetPen(*wxTRANSPARENT_PEN);

   if (IsSortOrderAscending(col))
   {
    Pt[0] = wxPoint(colLeft + iColWidth - 4, lh - 5);
    Pt[1] = wxPoint(colLeft + iColWidth - 15, lh - 5);
    Pt[2] = wxPoint(colLeft + iColWidth - 10, lh - 11);
   }
   else
   {
    Pt[0] = wxPoint(colLeft + iColWidth - 4, lh - 11);
    Pt[1] = wxPoint(colLeft + iColWidth - 15, lh - 11);
    Pt[2] = wxPoint(colLeft + iColWidth - 10, lh - 5);
   }

   dc.DrawPolygon(3,Pt);
   dc.SetBrush(wxNullBrush);
  };

 }

 dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
 dc.SetTextForeground(GetLabelTextColour());
 dc.SetFont(GetLabelFont());

 GetColLabelAlignment(&hAlign, &vAlign);
 orient = GetColLabelTextOrientation();

 rect.Deflate(2);
 DrawTextRectangle(dc, GetColLabelValue(col), rect, hAlign, vAlign, orient);

 if (bFilterOn)
 {
  //draw the filter

  ft = GetLabelFont();
  ft.SetWeight(wxFONTWEIGHT_NORMAL);
  dc.SetFont(ft);

  rect3 = wxRect(colLeft+3, lh + 2,
                 iColWidth - ArrowWidth - 8, LabelHeight - lh - 4);//rectangle for text
  rect4 = wxRect(colLeft +iColWidth - ArrowWidth - 6, lh + 3,
                 ArrowWidth + 5, LabelHeight - lh - 6);//outline rectangle for the button

  FilterValue = GetFilterValue(col);

  Pt[0] = wxPoint(colLeft + iColWidth - ArrowWidth/2 - 4, lh2 + lh3);
  Pt[1] = wxPoint(colLeft + iColWidth - 4, lh2 - lh3);
  Pt[2] = wxPoint(colLeft + iColWidth - 4 - ArrowWidth, lh2 - lh3);


  if (FilterValue == wxEmptyString)
  {
   //Filter not activated
   ArrowBkBrush = wxBrush(FilterArrowColourOff);
   FilterBkBrush = wxBrush(FilterBkColourOff);

  }
  else
  {
   //Filter activated
   ArrowBkBrush = wxBrush(FilterArrowColourOn);
   FilterBkBrush = wxBrush(FilterBkColourOn);
  }
   //draw the Push button
   iActivated = GetFilterState(col); //wxCONTROL_CURRENT or wxCONTROL_PRESSED
   wxRendererNative::Get().DrawPushButton(this,dc,rect4, iActivated);
   //draw the dropdown arrow
   dc.SetBrush(ArrowBkBrush);
   dc.SetPen(*wxTRANSPARENT_PEN);
   dc.DrawPolygon(3,Pt);

   //Draw the text
   dc.SetBrush(FilterBkBrush);
   dc.SetBackgroundMode(wxTRANSPARENT);
   dc.DrawRectangle(colLeft+2, lh + 2, iColWidth - ArrowWidth - 8,LabelHeight - lh - 4);
   dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
   dc.DrawLine(colLeft+2,lh + 2,colLeft + iColWidth - ArrowWidth - 6,lh + 2);
   dc.DrawLine(colLeft+2,lh + 2,colLeft + 2, LabelHeight - 3);
   dc.SetPen(*wxWHITE_PEN);
   dc.DrawLine(colLeft+2,LabelHeight - 3,colLeft + iColWidth - ArrowWidth - 6,LabelHeight - 3);
   dc.DrawLine(colLeft + iColWidth - ArrowWidth - 6,lh + 2,colLeft + iColWidth - ArrowWidth - 6, LabelHeight - 3);
   DrawTextRectangle(dc, FilterValue, rect3, wxALIGN_CENTRE, wxALIGN_CENTRE, wxHORIZONTAL);
   dc.SetBrush(wxNullBrush);
   dc.SetPen(wxNullPen);
 }

}

void wxEGrid::DrawCornerLabel(wxDC& dc)
{
 //draws the corner window
 int lh, w, h;
 wxWindow *pCornerWindow;

 if ( m_nativeColumnLabels )
 {
  wxRect rect(wxSize(m_rowLabelWidth, m_colLabelHeight));
  rect.Deflate(1);
  wxRendererNative::Get().DrawHeaderButton((wxWindow*) GetGridCornerLabelWindow(), dc, rect, 0);
 }
 else
 {
  dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
  dc.DrawLine( m_rowLabelWidth - 1, m_colLabelHeight - 1, m_rowLabelWidth - 1, 0 );
  dc.DrawLine( m_rowLabelWidth - 1, m_colLabelHeight - 1, 0, m_colLabelHeight - 1 );
  dc.DrawLine( 0, 0, m_rowLabelWidth, 0 );
  dc.DrawLine( 0, 0, 0, m_colLabelHeight );

  dc.SetPen( *wxWHITE_PEN );
  dc.DrawLine( 1, 1, m_rowLabelWidth - 1, 1 );
  dc.DrawLine( 1, 1, 1, m_colLabelHeight - 1 );
 }

 if (bFilterOn)
 {
  if (ClearFilterButton != NULL)
  {
   lh = LabelHeight / f;
   pCornerWindow = GetGridCornerLabelWindow();
   if (pCornerWindow != NULL)
   {
    pCornerWindow->GetSize(&w,&h);
    pCornerWindow->SetSize(0,0,w,lh);
    ClearFilterButton->SetSize(1,lh,w-2,LabelHeight-lh);
   }
  }
 }
}

void wxEGrid::DrawRowLabels(wxDC& dc, const wxArrayInt& rows)
{
 //draw a range of row labels
 const size_t numLabels = rows.GetCount();

 for(size_t i = 0; i < numLabels; i++)
 {
  DrawRowLabel(dc, rows[i]);
 }
}

void wxEGrid::DrawRowLabel(wxDC& dc, int row)
{
 //draw 1 row label
  if ( GetRowHeight(row) <= 0 || m_rowLabelWidth <= 0 )
        return;

    wxRect rect;

    int rowTop = GetRowTop(row),
        rowBottom = GetRowBottom(row) - 1;

    dc.SetPen( wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW)));
    dc.DrawLine( m_rowLabelWidth - 1, rowTop, m_rowLabelWidth - 1, rowBottom );
    dc.DrawLine( 0, rowTop, 0, rowBottom );
    dc.DrawLine( 0, rowBottom, m_rowLabelWidth, rowBottom );

    dc.SetPen( *wxWHITE_PEN );
    dc.DrawLine( 1, rowTop, 1, rowBottom );
    dc.DrawLine( 1, rowTop, m_rowLabelWidth - 1, rowTop );

    dc.SetBackgroundMode( wxBRUSHSTYLE_TRANSPARENT );
    if (bFilterApplied)
    {
     dc.SetTextForeground(FilterArrowColourOn);
    }
    else
    {
     dc.SetTextForeground(GetLabelTextColour());
    }
    dc.SetFont( GetLabelFont() );

    int hAlign, vAlign;
    GetRowLabelAlignment( &hAlign, &vAlign );

    rect.SetX( 2 );
    rect.SetY( GetRowTop(row) + 2 );
    rect.SetWidth( m_rowLabelWidth - 4 );
    rect.SetHeight( GetRowHeight(row) - 4 );
    DrawTextRectangle( dc, GetRowLabelValue( row ), rect, hAlign, vAlign );
}

void wxEGrid::UseNativeColHeader(bool native)
{
 //indicate if wxRendererNative should be used for drawing col labels
 return(SetUseNativeColLabels(native));
}

void wxEGrid::SetUseNativeColLabels(bool native)
{
 //indicate if wxRendererNative should be used for drawing col labels
 int iHeight;

 BeginBatch();
 wxGrid::SetUseNativeColLabels(native);
 //label size is modified if native == true
 //therefore we must modify it back to display filter correctly
 if (native)
 {
  iHeight = GetColLabelSize(); //get the new label size
  SetColLabelSize(iHeight * f);
  LabelHeight = iHeight * f;
 }
 EndBatch();
 Refresh();
}

bool wxEGrid::AppendCols(int numCols, bool updateLabels)
{
 //add numCols column at the end of the table
 bool bResult;
 int i;

 //Append the columns
 bResult = wxGrid::AppendCols(numCols, updateLabels);


 //Create the filters
 if (bResult)
 {
  for(i = 0; i<numCols;i++) Add_Filter(iFilterNumber + i);
 }

 return(bResult);
}

bool wxEGrid::DeleteCols(int pos, int numCols, bool updateLabels)
{
 //Delete numCols in the table at the position "pos"
 bool bResult;
 int i;

 //Delete the columns
 bResult = wxGrid::DeleteCols(pos, numCols, updateLabels);

 //Delete the filters
 if (bResult)
 {
  for(i = 0; i<numCols;i++) Remove_Filter(pos);
 }

 return(bResult);
}

bool wxEGrid::InsertCols(int pos, int numCols, bool updateLabels)
{
 //Add numCols in the table at the position "pos"
 bool bResult;
 int i;

 //add the columns
 bResult = wxGrid::InsertCols(pos, numCols, updateLabels);

 //add the filters
 if (bResult)
 {
  for(i = 0; i<numCols;i++) Add_Filter(pos);
 }

 return(bResult);
}

bool wxEGrid::AppendRows(int numRows, bool updateLabels)
{
 //add numRows rows at the end of the table
 bool bResult;
 int i;

 bResult = wxGrid::AppendRows(numRows, updateLabels);

 //Filtered rows table update
 if (bResult)
 {
  for(i = 0; i<numRows;i++) Add_FRows(iFilterNumber + i);
 }


 return(bResult);
}

bool wxEGrid::DeleteRows(int pos, int numRows, bool updateLabels)
{
 //delete numRows rows in the table at the position "pos"
 bool bResult;
 int i;

 bResult = wxGrid::DeleteRows(pos, numRows, updateLabels);

 //Filtered rows table update
 if (bResult)
 {
  for(i = 0; i<numRows;i++) Remove_FRows(pos);
 }

 return(bResult);
}

bool wxEGrid::InsertRows(int pos, int numRows, bool updateLabels)
{
 //insert numRows rows in the table at the position "pos"
 bool bResult;
 int i;

 bResult = wxGrid::InsertRows(pos, numRows, updateLabels);

 //Filtered rows table update
 if (bResult)
 {
  for(i = 0; i<numRows;i++) Add_FRows(pos);
 }

 return(bResult);
}

void wxEGrid::Add_Filter(int pos)
{
 //insert a new filter (wxString) at pos
 int i, iPos, j, jMin;


 iPos = pos;
 if (pos <0 ) iPos = 0;
 if (pos > iFilterNumber) iPos = iFilterNumber;

 //allocate new memory if necessary
 if (iFilterMaxNumber <= iFilterNumber)
 {
  iFilterMaxNumber = iFilterMaxNumber + WX_STRING_ARRAY_SIZE;
  iSortSize = iSortSize + WX_STRING_ARRAY_SIZE;
  Values = (wxString **) realloc(Values,iFilterMaxNumber * sizeof(wxString*));
  iSorting = (int *) realloc(iSorting, iSortSize * sizeof(int));

  //initialisation
  jMin = iSortSize - WX_STRING_ARRAY_SIZE;
  for(j=jMin;j<iSortSize;j++) iSorting[j] = 0;

 }
 if (Values == NULL) return;
 if (iSorting == NULL) return;
 //shift the existing wxString to the right
 for(i=iFilterNumber-1; i>=iPos; i--)
 {
  Values[i+1] = Values[i];
  iSorting[i+1] = iSorting[i];
 }

 //allocate the new wxString
 Values[iPos] = new wxString();
 iSorting[iPos] = 0;
 iFilterNumber++;
}

void wxEGrid::Remove_Filter(int pos)
{
 //remove an existing filter (wxString) at pos

 int i, iPos;

 iPos = pos;
 if (pos <0 ) iPos = 0;
 if (pos > iFilterNumber-1) iPos = iFilterNumber-1;

 //delete the wxString
 if (Values == NULL) return;
 delete Values[iPos];

 //shift the values to the left
 for(i=iPos; i<iFilterNumber-1; i++)
 {
  Values[i] = Values[i+1];
  iSorting[i] = iSorting[i+1];
 }
 iFilterNumber--;
}

void wxEGrid::Empty_Filters(void)
{
 //delete the wxString created
 int i;

 if (Values == NULL) return;
 for(i=0; i<iFilterNumber;i++) delete Values[i];
 iFilterNumber = 0;
}

void wxEGrid::Add_FRows(int pos)
{
 //add one row to the filtered row array

 /*
  bool *IsRowFiltered; //indicate if a row is hidden due to a filter (size = iRealSize)
  int **AppliedFilter; //indicate which filters (col index) applies on the row (size = iRealSize * iSize[i])
  int *iSize;          //size of the arrays in AppliedFilter
  int iUsedSize;       //used size of the dynamic arrays
  int iRealSize;       //real (allocated) size of the dynamic arrays
  WX_ROWCOL_ARRAY_SIZE
 */

 int iPos, i, j;

 iPos = pos;
 if (pos < 0) iPos = 0;
 if (pos > iUsedSize) iPos = iUsedSize;

 //allocate memory when necessary
 if (iUsedSize >= iRealSize)
 {
  iRealSize = iRealSize + WX_ROW_ARRAY_SIZE;
  IsRowFiltered = (bool *) realloc(IsRowFiltered, iRealSize * sizeof(bool));
  iSize =         (int *)  realloc(iSize, iRealSize * sizeof(int));
  AppliedFilter = (int **) realloc(AppliedFilter, iRealSize * sizeof(int*));

 }
 if (AppliedFilter == NULL) return;
 if (IsRowFiltered == NULL) return;
 if (iSize == NULL) return;

 //shift the values to the right
 for(i=iUsedSize-1; i>=iPos; i--)
 {
  AppliedFilter[i+1] = AppliedFilter[i];
  iSize[i+1] = iSize[i];
  IsRowFiltered[i+1] = IsRowFiltered[i];
 }

 //give standard values
 AppliedFilter[iPos] = (int*) malloc(WX_ROWCOL_ARRAY_SIZE * sizeof(int));
 if (AppliedFilter[iPos] == NULL)
 {
  iSize[iPos] = 0;
  return;
 }
 iSize[iPos] = WX_ROWCOL_ARRAY_SIZE;
 for(j=0; j<WX_ROWCOL_ARRAY_SIZE; j++) AppliedFilter[iPos][j] = -1;
 IsRowFiltered[iPos] = false;

 iUsedSize++;
}

void wxEGrid::Remove_FRows(int pos)
{
 //remove one row from the filtered row array
 int iPos, i;

 iPos = pos;
 if (pos < 0) iPos = 0;
 if (pos > iUsedSize) iPos = iUsedSize;

 if (AppliedFilter == NULL) return;
 if (IsRowFiltered == NULL) return;
 if (iSize == NULL) return;

 //free some memory
 if (iSize[iPos] > 0) free(AppliedFilter[iPos]);
 //shift the values to the left
 for(i=iPos; i<iUsedSize-1; i++)
 {
  AppliedFilter[i] = AppliedFilter[i+1];
  iSize[i] = iSize[i+1];
  IsRowFiltered[i] = IsRowFiltered[i+1];
 }
 iUsedSize--;
}

void wxEGrid::Empty_FRows(void)
{
 //delete the filtered row arrays
 int i;

 if (AppliedFilter == NULL) return;
 if (IsRowFiltered == NULL) return;
 if (iSize == NULL) return;

 for(i=0;i<iUsedSize;i++)
 {
  IsRowFiltered[i] = false;
  if (AppliedFilter[i] != NULL)
  {
   free(AppliedFilter[i]);
   AppliedFilter[i] = NULL;
   iSize[i] = 0;
  }
 }
}

bool wxEGrid::CreateGrid(int numRows, int numCols, wxGridSelectionModes selmode)
{
 //Create the grid table
 bool bResult;
 int i;

 //create the grid
 bResult = wxGrid::CreateGrid(numRows, numCols, selmode);

 //create the filters
 if (bResult)
 {
  Empty_Filters();
  for(i = 0; i<numCols;i++) Add_Filter(i);
  Empty_FRows();
  for(i = 0; i<numRows;i++) Add_FRows(i);
 }

 return(bResult);
}

bool wxEGrid::SetTable(wxGridTableBase *table, bool takeOwnership, wxGridSelectionModes selmode)
{
 //add a data table to the grid
 bool bResult;
 int i, numCols, numRows;

 bResult = wxGrid::SetTable(table, takeOwnership, selmode);

 if ((bResult) && (table != NULL))
 {
  Empty_Filters();
  numCols = table->GetNumberCols();
  for(i = 0; i<numCols;i++) Add_Filter(i);
  Empty_FRows();
  numRows = table->GetNumberRows();
  for(i = 0; i<numRows;i++) Add_FRows(i);
 }

 return(bResult);
}

void wxEGrid::HideRow(int row)
{
 //Hide a row
 int iSize;

 if (row < 0) return;
 if (row >= GetNumberRows()) return;
 iSize = GetRowSize(row);

 if (iSize <= 0) return; //already hidden
 SetRowSize(row, 0); //hide the row by setting its size to a negative value
}

void wxEGrid::ShowRow(int row)
{
 //show a hidden row
 int iSize;

 if (row < 0) return;
 if (row >= GetNumberRows()) return;

 if (IsRowFiltered != NULL)
 {
  //do not show because it is filtered
  //it should stay hidden
  if (IsRowFiltered[row]) return;
 }

 iSize = GetRowSize(row);

 if (iSize > 0) return; //already shown
  //show the row by setting its size to a strictly positive value
 if (iSize == 0) SetRowSize(row, iMinimalHeight); else SetRowSize(row, -iSize);
}

bool wxEGrid::IsRowShown(int  row) const
{
 //returns true if a row is shown3
 int iSize;

 if (row < 0) return(false);
 if (row >= GetNumberRows()) return(false);
 iSize = GetRowSize(row);
 if (iSize > 0) return(true);
 return(false);
}

void wxEGrid::SetColSizeEvent(wxGridSizeEvent& event)
{
 //hide filters window after col resizing
 int col, iLeft, iRight, iButton,x, y;

 col = event.GetRowOrCol();
 if (col == iCurrentCol)
 {
  if (FilterTextCtrl != NULL)
  {
   iLeft = GetColLeft(col);
   iRight = GetColRight(col);
   iButton = iRight - ArrowWidth - 5; // X coordinate of the Push button
   CalcScrolledPosition(0,0,&x,&y);

   FilterTextCtrl->SetSize(iLeft+3 + x, LabelHeight / f + 2,
                           iButton - iLeft-3, LabelHeight -LabelHeight / f - 4);
  }
 }

 if (col + 1 == iCurrentCol)
 {
  if (FilterTextCtrl != NULL)
  {
   iLeft = GetColLeft(iCurrentCol);
   iRight = GetColRight(iCurrentCol);
   iButton = iRight - ArrowWidth - 5; // X coordinate of the Push button
   CalcScrolledPosition(0,0,&x,&y);

   FilterTextCtrl->SetSize(iLeft+3 + x, LabelHeight / f + 2,
                           iButton - iLeft-3, LabelHeight -LabelHeight / f - 4);
  }
 }
}

/** FILTERS API **/

bool wxEGrid::IsFilter(void)
{
 //return the current filter status
 return(bFilterOn);
}

void wxEGrid::SetFilter(bool enable)
{
 //set the filter (true = filters are activated and displayed)
 if (bFilterOn == enable) return;
 bFilterOn = enable;
 if (bFilterOn)
 {
  LabelHeight = LabelHeight * f;
  SetColLabelSize(LabelHeight);
  if (ClearFilterButton!=NULL) ClearFilterButton->Show(true);
 }
 else
 {
  LabelHeight = LabelHeight / f;
  SetColLabelSize(LabelHeight);
  if (ClearFilterButton!=NULL) ClearFilterButton->Show(false);
  if (FilterListCtrl!=NULL) FilterListCtrl->Show(false);
  if (FilterTextCtrl!=NULL) FilterTextCtrl->Show(false);
 }
 ForceRefresh();
}

void wxEGrid::SetFactor(double factor)
{
 //Set the multiplicating factor for the displaying the filters
 //ColLabelSize = LabelHeight = f * size of column header = size of label + size of filter
 if (factor < 1) return;
 LabelHeight = LabelHeight / f;
 f = factor;
 LabelHeight = LabelHeight * f;
 SetColLabelSize(LabelHeight);
 ForceRefresh();
}

double wxEGrid::GetFactor(void)
{
 //Get the multiplicating factor for the displaying the filters
 return(f);
}

wxString wxEGrid::GetFilterValue(int col)
{
 //returns the current value of the filter

 //Get the value of the current filter
 if ((col >= 0) && (col < GetNumberCols()))
 {
  return(*Values[col]);
 }
 return(wxEmptyString);
}

wxArrayString wxEGrid::ListValues(int col)
{
 //returns the content of the filter for a specific column

 wxSortedArrayString sArray;
 wxString s;
 int i, iMax;
 bool bBlank, bNonBlank;

 if (col < 0) return(wxArrayString());
 if (col >= GetNumberCols()) return(wxArrayString());

 iMax = GetNumberRows();
 bBlank = false;
 bNonBlank = false;

 for(i=0; i<iMax ; i++)
 {
  if (IsRowShown(i))
  {
   s = GetCellValue(i,col);
   if (s == wxEmptyString)
   {
    bBlank = true;
   }
   else
   {
    bNonBlank = true;
    if (sArray.Index(s) == wxNOT_FOUND) sArray.Add(s);
   }

  }
  else if ((!IsAppliedFilter(i,col)) && (IsRowFiltered[i]))
  {
   //the row is hidden due to a filter on another column
   s = GetCellValue(i,col);
   if (s == wxEmptyString)
   {
    bBlank = true;
   }
   else
   {
    bNonBlank = true;
    if (sArray.Index(s) == wxNOT_FOUND) sArray.Add(s);
   }

  }
 }
 if (bBlank) sArray.Add("<BLANK>");
 if (bNonBlank) sArray.Add("<NON BLANK>");

 return(sArray);

}

bool wxEGrid::IsAppliedFilter(int row,int col)
{
 //indicate if a row is filtered according to the column different from col
 int i, iMax;

 if (row < 0) return(false);
 if (row > GetNumberRows()) return(false);
 if (AppliedFilter == NULL) return(false);
 if (iSize == NULL) return(false);

 if (AppliedFilter[row] == NULL) return(false);
 iMax = iSize[row];

 for(i=0;i<iMax;i++)
 {
  if ((AppliedFilter[row][i] != col) && (AppliedFilter[row][i] != -1)) return(true);
 }
 return(false);
}

int wxEGrid::GetFilterState(int col)
{
 //returns wxCONTROL_CURRENT or wxCONTROL_PRESSED
 if (FilterState == col) return(wxCONTROL_PRESSED);

 return(wxCONTROL_CURRENT);
}

void wxEGrid::ResetFilterState(void)
{
 //reset the filter arrows state
 FilterState = -1;

}


void wxEGrid::ClearFilter(int col)
{
 //reset the value of a specific filter
 wxWindow *LabelWin;

 if (col < 0) return;
 if (col >= GetNumberCols()) return;

 *Values[col] = wxEmptyString;

 LabelWin = (wxWindow *) GetColLabelWindow();
 if (GetBatchCount() == 0 )
 {
  if (LabelWin != NULL)
  {
   LabelWin->Refresh(true,NULL);
   LabelWin->Update();
  }
 }
 ApplyFilter(col);
}

void wxEGrid::ClearAllFilter(void)
{
 //reset the value of all filters
 int i, iMax;

 iMax = GetNumberCols();

 for(i=0;i<iMax;i++) ClearFilter(i);

}

void wxEGrid::ApplyFilter(int col, bool bRecompute, bool bListFilteredValue)
{
 //apply the filter for a specific column
 wxString s;
 int i, iMax, j, jMax, k;
 wxRegEx *r;
 bool bAllocate;

 if (col < 0) return;
 if (col >= GetNumberCols()) return;
 if (Values == NULL) return;

 s = *Values[col];
 r = new wxRegEx(s,iRegExType);
 if (r == NULL) return;

 BeginBatch();

 //remove the previous filter from this column
 ResetFilter(col);

 //apply the new filter
 if (r->IsValid())
 {
  iMax = GetNumberRows();
  for(i=0;i<iMax;i++)
  {
   //apply the filter only on specific rows
   //case 1: the row is visible: apply the filter
   //case 2: the row was hidden by a filter on another column: apply the filter
   //case 3: the row was hidden by the user : do not apply the filter
   //
   //flags
   //case 1: (IsRowShown(i) == true)
   //case 2: ((IsRowFiltered[i] = true)&&(IsRowShown(i) == false))
   //case 3: ((IsRowFiltered[i] = false)&&(IsRowShown(i) == false))

   if ((IsRowShown(i) == true) || ((IsRowFiltered[i] = true)&&(IsRowShown(i) == false)))
   {
    //case 1 OR case 2
    //test the filter
    s = GetCellValue(i,col);
    if (!r->Matches(s))
    {
     //there is a match - set the filter flags
     jMax = iSize[i];
     bAllocate = true;
     for(j=0;j<jMax;j++)
     {
      if (AppliedFilter[i][j] == -1) AppliedFilter[i][j] = col;
      bAllocate = false;
      break;
     }
     if (bAllocate)
     {
      AppliedFilter[i] = (int *) realloc(AppliedFilter[i], (iSize[i]+WX_ROWCOL_ARRAY_SIZE) * sizeof(int));
      if (AppliedFilter[i] == NULL) return;
      iSize[i] = iSize[i] +  WX_ROWCOL_ARRAY_SIZE;
      //initialisation
      for(k=iSize[i] - WX_ROWCOL_ARRAY_SIZE; k < iSize[i]; k++) AppliedFilter[i][k] = -1;
     }
     SetFilteredRow(i);
    }
    //check if the row needs to be hidden or not
    if (IsRowFiltered[i] == true) HideRow(i); else ShowRow(i);
   }

  }
 }

 bFilterApplied = AreFilteredApplied();

 EndBatch();
 ForceRefresh();

 delete r;

}

bool wxEGrid::AreFilteredApplied(void)
{
 //indicate if one or more filters are applied
 int i, iMax;

 iMax = GetNumberCols();
 if (Values == NULL) return(false);

 for(i=0;i<iMax;i++)
 {
  if (*Values[i] != wxEmptyString) return(true);
 }

 return(false);
}

void wxEGrid::ResetFilter(int col)
{
 //remove the filter from a specific column
 int i, iMax, j, jMax;

 if (col < 0) return;
 if (col > GetNumberCols()) return;
 if (IsRowFiltered == NULL) return;
 if (AppliedFilter == NULL) return;
 if (iSize == NULL) return;

 iMax = GetNumberRows();
 for(i=0;i<iMax;i++)
 {
  //check 1st if a filter is applied on the row
  if (IsRowFiltered[i])
  {
   //if a filter is applied on it, look up if it is due to the filter from column "col"
   jMax = iSize[i];
   for(j=0;j<jMax;j++)
   {
    if (AppliedFilter[i][j] == col) AppliedFilter[i][j]=-1;
   }
   SetFilteredRow(i);
   if (!IsRowFiltered[i]) ShowRow(i);
  }
 }
}

void  wxEGrid::SetFilteredRow(int row)
{
 //set the IsRowFiltered flag for a row
 int j, jMax;

 jMax = iSize[row];
 IsRowFiltered[row] = false;

 for(j=0;j<jMax;j++)
 {
  if (AppliedFilter[row][j] != -1)
  {
   IsRowFiltered[row] = true;
   return;
  }
 }
}

void wxEGrid::ApplyAllFilter(bool bRecompute, bool bListFilteredValue)
{
 //apply all filters to each column
 int i, iMax;

 iMax = GetNumberCols();

 for(i=0;i<iMax;i++) ApplyFilter(i, bRecompute, bListFilteredValue);
}

void wxEGrid::OnLabelClick(wxGridEvent& event)
{
 //process click on a filter
 wxPoint Pos, wPos;
 int col, iLeft, iRight, iButton, iRowLabelSize, x, y, w, h, k, kMax;
 wxString FilterValue;
 wxArrayString sArray;
 int iPreviousCol;

 Pos = event.GetPosition();
 iRowLabelSize = GetRowLabelSize();
 CalcScrolledPosition(0,0,&x,&y);

 if ((Pos.y > LabelHeight / f)&&(Pos.x > iRowLabelSize))
 {
  //event occured in the Filter area - therefore we process it
  col = event.GetCol();
  iLeft = GetColLeft(col);
  iRight = GetColRight(col);
  iButton = iRight - ArrowWidth - 5; // X coordinate of the Push button


  if ((Pos.x - iRowLabelSize - x > iButton) && (Pos.x - iRowLabelSize - x < iRight))
  {
   if (FilterListCtrl != NULL)
   {
    iPreviousCol = iCurrentCol;
    iCurrentCol = col;
    if (FilterTextCtrl != NULL)
    {
     if (FilterTextCtrl->IsShown())
     {
      *Values[iPreviousCol] = FilterTextCtrl->GetValue();
      ApplyFilter(iPreviousCol);
      FilterTextCtrl->Show(false);
     }
    }

    //add the values
     FilterListCtrl->Clear();
    //fill the ListBox with the String values of the filter
     sArray = ListValues(col);
     FilterListCtrl->Append("<ALL>");
     //FilterListCtrl->Append("<CUSTOM>");
     FilterListCtrl->InsertItems(sArray, 2);

    wPos = ClientToScreen(wxPoint(0,0));
    FilterListCtrl->Refresh(true,NULL);
    FilterListCtrl->Update();
    FilterListCtrl->GetVirtualSize(&w,&h);
    if (w > iRight - iLeft)
    {
     if (iCurrentCol > 0)
     {
      iLeft = GetColLeft(iCurrentCol - 1);
     }
     else
     {
      iLeft = 0;
     }
     w = iRight - iLeft;
    }
    else
    {
     w = iRight - iLeft;
    };

    FilterListCtrl->SetSize(iLeft + x + wPos.x + iRowLabelSize, LabelHeight - 4 + wPos.y,
                            w, 100);

    if ((col >= 0) && (col < GetNumberCols())) FilterValue = *Values[col]; else FilterValue = wxEmptyString;

    iPreviousCol = iCurrentCol;
    iCurrentCol = col;
    FilterState = col;
    if (FilterValue == wxEmptyString)
    {
     FilterListCtrl->SetBackgroundColour(FilterBkColourOff);
    }
    else
    {
     FilterListCtrl->SetBackgroundColour(FilterBkColourOn);
    }

    FilterListCtrl->Popup();
    ForceRefresh();
    Update();
    FilterListCtrl->SetFocus();
   }
  }
  else if ((Pos.x - iRowLabelSize - x > iLeft) && (Pos.x - iRowLabelSize - x < iButton))
  {

   //display the text control
   if (FilterTextCtrl != NULL)
   {
    //(colLeft+2, lh + 2, iColWidth - ArrowWidth - 8,LabelHeight - lh - 4);
    //lh = LabelHeight / f
    iPreviousCol = iCurrentCol;
    iCurrentCol = col;
    if (FilterTextCtrl->IsShown())
    {
     *Values[iPreviousCol] = FilterTextCtrl->GetValue();
     ApplyFilter(iPreviousCol);
    }

    FilterTextCtrl->SetSize(iLeft+3 + x, LabelHeight / f + 2,
                            iButton - iLeft-3, LabelHeight -LabelHeight / f - 4);
    FilterValue = wxEmptyString;
    if ((col >= 0) && (col < GetNumberCols())) FilterValue = *Values[col]; else FilterValue = wxEmptyString;

    FilterTextCtrl->SetValue(FilterValue);

    if (FilterTextCtrl->GetValue() == wxEmptyString)
    {
     FilterTextCtrl->SetBackgroundColour(FilterBkColourOff);
    }
    else
    {
     FilterTextCtrl->SetBackgroundColour(FilterBkColourOn);
    }

     FilterTextCtrl->Show(true);
     FilterTextCtrl->SetFocus();
   }

  }
  else
  {
   //skip the event to allow parent window to process them when needed
   event.Skip();
  }
 }
 else if (Pos.x > iRowLabelSize)
 {
   //event occured in the label area. Update the sort indicator
   col = event.GetCol();
   if (iSorting != NULL)
   {
    if (iSorting[col] == 0)
    {
     kMax = GetNumberCols();
     for(k=0; k<kMax; k++) iSorting[k] = 0;
     iSorting[col] = 1;
     Sort(WX_EGRID_INSERTION_SORT);
    }
    else if (iSorting[col] > 0)
    {
     iSorting[col] = -iSorting[col];
     Sort(WX_EGRID_INSERTION_SORT);
    }
    else
    {
     iSorting[col] = 0;
    }
   }
   ForceRefresh();

   //skip the event to allow parent window to process them when needed
   event.Skip();
 }
 else
 {
  //skip the event to allow parent window to process them when needed

  event.Skip();
 }

}

wxWindow* wxEGrid::GetFilterWindow(void)
{
 //return a pointer to the filter band
 return((wxWindow *) GetColLabelWindow());
}

void wxEGrid::SetRegExFlag(int flag)
{
 //Set the RegEx type
 iRegExType = flag;
}

int wxEGrid::GetRegExFlag(void)
{
 //return the RegEx type
 return(iRegExType);
}

void wxEGrid::SetCurrentFilterValue(wxString value)
{
 //Set the value of the current filter
 if ((iCurrentCol >= 0) && (iCurrentCol < GetNumberCols()))
 {
  *Values[iCurrentCol] = value;
 }
}

/** VISUAL ATTRIBUTE API **/
void wxEGrid::GetFilterArrowDim(int *width, int *height)
{
  //get the filter arrow Dimension
  *width = ArrowWidth;
  *height = ArrowHeight;
}

void wxEGrid::SetFilterArrowDim(int width, int height)
{
 //set the filter arrow Dimension
 if (width > 0) ArrowWidth = width;
 if (height > 0) ArrowHeight = height;
 Refresh(true,NULL);
 Update();
}

wxColour wxEGrid::GetFilterArrowColourOn(void)
{
 //get the filter arrow color ON
 return(FilterArrowColourOn);
}

void wxEGrid::SetFilterArrowColourOn(wxColour colour)
{
 //set the filter arrow color ON
 FilterArrowColourOn = colour;
}

wxColour wxEGrid::GetFilterArrowColourOff(void)
{
 //get the filter arrow color OFF
 return(FilterArrowColourOff);
}


void wxEGrid::SetFilterArrowColourOff(wxColour colour)
{
 //set the filter arrow color OFF
 FilterArrowColourOff = colour;
}

wxColour wxEGrid::GetFilterBkColourOn(void)
{
 //get the filter background color ON
 return(FilterBkColourOn);
}


void wxEGrid::SetFilterBkColourOn(wxColour colour)
{
 //set the filter arrow color ON
 FilterBkColourOn = colour;
}

wxColour wxEGrid::GetFilterBkColourOff(void)
{
 //get the filter background color ON
 return(FilterBkColourOff);
}

void wxEGrid::SetFilterBkColourOff(wxColour colour)
{
 //set the filter arrow color OFF
 FilterBkColourOff = colour;
}

wxColour wxEGrid::GetSortingArrowColour(void)
{
 //get the sorting arrow color
 return(SortArrowColor);
}

void wxEGrid::SetSortingArrowColour(wxColour colour)
{
 //set the sorting arrow color OFF
 SortArrowColor = colour;
}
/** Sorting API ***/
bool wxEGrid::IsSortingBy(int col) const
{
 //return true if the column sorts
 if (iSorting == NULL) return(false);
 if (col < 0) return(false);
 if (col >= iSortSize) return(false);

 if (iSorting[col] == 0) return(false);
 return(true);
}

int wxEGrid::GetSortingColumn(void) const
{
 //return the 1st column used for sorting
 int i;

 if (iSorting == NULL) return(-1);

 for(i=0;i<iSortSize;i++)
 {
  if ((iSorting[i] == 1)||(iSorting[i] == -1)) return(i);
 }
 return(0);
}

bool wxEGrid::IsSortOrderAscending(int col) const
{
 //get the sort order of the column
 if (iSorting == NULL) return(false);
 if (col < 0) return(false);
 if (col >= iSortSize) return(false);

 if (iSorting[col] > 0) return(true);
 return(false);
}

void wxEGrid::SetSortingColumn(int col, bool ascending, int key)
{
 //set the sorting order of the column
 //col : the column number used for sorting
 //ascending: true if ascending sorting is used, false otherwise
 //key: 1 if used for primary sorting, 2 for secondary,...
 int iKey;

 if (iSorting == NULL) return;
 if (col < 0) return;
 if (col >= iSortSize) return;

 if (key <0) iKey = -key; else iKey = key;

 if (ascending) iSorting[col] = iKey; else  iSorting[col] = -iKey;
}

void wxEGrid::UnsetSortingColumn(void)
{
 //reset the sorting columns
 int i;

 if (iSorting == NULL) return;
 for(i=0; i<iSortSize; i++) iSorting[i] = 0;
}

void wxEGrid::Sort(int algo)
{
 //sort the table
 InsertionSort();
}

void wxEGrid::SwapRows(int row1, int row2)
{
 //invert the content from row1 and row2
 int i, iMax;
 wxString s;

 iMax = GetNumberCols();

 for(i=0;i<iMax;i++)
 {
  s = GetCellValue(row1,i);
  SetCellValue(row1,i,GetCellValue(row2,i));
  SetCellValue(row2,i,s);
 }
}

void wxEGrid::CopyRow(int row1, int row2)
{
 //copy row2 in row1
 int i, iMax;

 iMax = GetNumberCols();

 for(i=0;i<iMax;i++)
 {
  SetCellValue(row1,i,GetCellValue(row2,i));
 }
}

void wxEGrid::InsertionSort()
{
 //sort the table
 int col, row;
 int i, j;
 wxString s, s2;
 bool bAscending;

 BeginBatch();


 col = GetSortingColumn();
 bAscending = true;
 if (iSorting == NULL) return;
 if (iSorting[col] < 0) bAscending = false;

 row = GetNumberRows();
 AppendRows(1);

 if (bAscending)
 {
  for (i=1; i < row; i++)
  {
   s = GetCellValue(i,col);
   CopyRow(row,i);
   j = i;

   s2 = GetCellValue(j-1,col);
   while ((j > 0) && (s2.Cmp(s)>0))
   {
    CopyRow(j,j-1);
    j = j - 1;
   }
   CopyRow(j,row);
  }
 }
 else
 {
  for (i=1; i < row; i++)
  {
   s = GetCellValue(i,col);
   CopyRow(row,i);
   j = i;

   s2 = GetCellValue(j-1,col);
   while ((j > 0) && (s.Cmp(s2)>0))
   {
    CopyRow(j,j-1);
    j = j - 1;
   }
   CopyRow(j,row);
  }
 }
 DeleteRows(row,1);
 EndBatch();
 ForceRefresh();

}

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Re: wxGrid class extended

Post by Auria » Mon Mar 30, 2009 9:27 pm

seb_seb0 wrote: My questions are:
- are there plans to support sorting and/or filtering in wxWidgets ?
...
- I have found a small bug in wxGridWindow class. The mouse capture is sometimes not released (try selecting some cells while scrolling to the top or the bottom). Is it a known bug ? It could be solved in a few lines I guess (processing a mouse button left up event). I will post a solution later on the bug tracking list.
Hi,

since this is mostly a user forum, such questions about the development of wx may not be answered; for such matters the mailing list usually gets you better answers

BTW: thanks for the nice contrib :)

orbitcowboy
I live to help wx-kind
I live to help wx-kind
Posts: 178
Joined: Mon Jul 23, 2007 9:01 am

Post by orbitcowboy » Sat Jun 27, 2009 1:11 pm

Hello,

i have tested the wxEgrid class on Ubuntu Linux with wxGTK-2.8.9 (svn-head). It made some little adjustment, because g++ raised a lots of warnings. These are fixed now.
I have attached a linux makefile an the modified source.

Best regards

Orbitcowboy
Attachments
wxEGrid.tar.gz
tar -xpvzf wxEGrid.tar.gz
cd wxEGrid/make
make depend
make
../bin/GridDemo
(26.75 KiB) Downloaded 355 times
Screenshot-wxWidgets grid class demo.png
screenshot of the griddemo application realised with wxEGrid class
OS: Ubuntu 9.04 (32/64-Bit), Debian Lenny (32-Bit)
Compiler: gcc/g++-4.3.3 , gcc/g++-4.4.0
wxWidgets: 2.8.10,2.9.0

Ankit
In need of some credit
In need of some credit
Posts: 1
Joined: Thu Sep 19, 2013 7:19 am

Re: wxGrid class extended

Post by Ankit » Thu Sep 19, 2013 7:22 am

I have few query:-

1) How to Incorporate these 2 file (wxEgrid.cpp, wxEgrid.h) in the source code ( I am new to python and wxpython).

Post Reply