home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / listctrl.cpp < prev    next >
C/C++ Source or Header  |  2002-11-09  |  154KB  |  5,366 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        generic/listctrl.cpp
  3. // Purpose:     generic implementation of wxListCtrl
  4. // Author:      Robert Roebling
  5. //              Vadim Zeitlin (virtual list control support)
  6. // Id:          $Id: listctrl.cpp,v 1.269.2.9 2002/11/05 00:57:38 VZ Exp $
  7. // Copyright:   (c) 1998 Robert Roebling
  8. // Licence:     wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10.  
  11. /*
  12.    TODO
  13.  
  14.    1. we need to implement searching/sorting for virtual controls somehow
  15.   ?2. when changing selection the lines are refreshed twice
  16.  */
  17.  
  18. // ============================================================================
  19. // declarations
  20. // ============================================================================
  21.  
  22. // ----------------------------------------------------------------------------
  23. // headers
  24. // ----------------------------------------------------------------------------
  25.  
  26. #ifdef __GNUG__
  27.     #pragma implementation "listctrl.h"
  28.     #pragma implementation "listctrlbase.h"
  29. #endif
  30.  
  31. // For compilers that support precompilation, includes "wx.h".
  32. #include "wx/wxprec.h"
  33.  
  34. #ifdef __BORLANDC__
  35. #pragma hdrstop
  36. #endif
  37.  
  38. #if wxUSE_LISTCTRL
  39.  
  40. #ifndef WX_PRECOMP
  41.     #include "wx/app.h"
  42.  
  43.     #include "wx/dynarray.h"
  44.  
  45.     #include "wx/dcscreen.h"
  46.  
  47.     #include "wx/textctrl.h"
  48. #endif
  49.  
  50. // under Win32 we always use the native version and also may use the generic
  51. // one, however some things should be done only if we use only the generic
  52. // version
  53. #if defined(__WIN32__) && !defined(__WXUNIVERSAL__)
  54.     #define HAVE_NATIVE_LISTCTRL
  55. #endif
  56.  
  57. // if we have the native control, wx/listctrl.h declares it and not this one
  58. #ifdef HAVE_NATIVE_LISTCTRL
  59.     #include "wx/generic/listctrl.h"
  60. #else // !HAVE_NATIVE_LISTCTRL
  61.     #include "wx/listctrl.h"
  62.  
  63.     // if we have a native version, its implementation file does all this
  64.     IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
  65.     IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
  66.     IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
  67.  
  68.     IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl)
  69. #endif // HAVE_NATIVE_LISTCTRL/!HAVE_NATIVE_LISTCTRL
  70.  
  71. #if defined(__WXGTK__)
  72.     #include <gtk/gtk.h>
  73.     #include "wx/gtk/win_gtk.h"
  74. #endif
  75.  
  76. // ----------------------------------------------------------------------------
  77. // events
  78. // ----------------------------------------------------------------------------
  79.  
  80. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
  81. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
  82. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
  83. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
  84. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
  85. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
  86. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
  87. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
  88. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
  89. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
  90. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
  91. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
  92. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
  93. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK)
  94. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG)
  95. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING)
  96. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
  97. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
  98. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
  99. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
  100. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
  101. DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
  102.  
  103. // ----------------------------------------------------------------------------
  104. // constants
  105. // ----------------------------------------------------------------------------
  106.  
  107. // the height of the header window (FIXME: should depend on its font!)
  108. static const int HEADER_HEIGHT = 23;
  109.  
  110. // the scrollbar units
  111. static const int SCROLL_UNIT_X = 15;
  112. static const int SCROLL_UNIT_Y = 15;
  113.  
  114. // the spacing between the lines (in report mode)
  115. static const int LINE_SPACING = 0;
  116.  
  117. // extra margins around the text label
  118. static const int EXTRA_WIDTH = 3;
  119. static const int EXTRA_HEIGHT = 4;
  120.  
  121. // offset for the header window
  122. static const int HEADER_OFFSET_X = 1;
  123. static const int HEADER_OFFSET_Y = 1;
  124.  
  125. // when autosizing the columns, add some slack
  126. static const int AUTOSIZE_COL_MARGIN = 10;
  127.  
  128. // default and minimal widths for the header columns
  129. static const int WIDTH_COL_DEFAULT = 80;
  130. static const int WIDTH_COL_MIN = 10;
  131.  
  132. // the space between the image and the text in the report mode
  133. static const int IMAGE_MARGIN_IN_REPORT_MODE = 5;
  134.  
  135. // ============================================================================
  136. // private classes
  137. // ============================================================================
  138.  
  139. // ----------------------------------------------------------------------------
  140. // wxSelectionStore
  141. // ----------------------------------------------------------------------------
  142.  
  143. int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; }
  144.  
  145. WX_DEFINE_SORTED_EXPORTED_ARRAY_LONG(size_t, wxIndexArray);
  146.  
  147. // this class is used to store the selected items in the virtual list control
  148. // (but it is not tied to list control and so can be used with other controls
  149. // such as wxListBox in wxUniv)
  150. //
  151. // the idea is to make it really smart later (i.e. store the selections as an
  152. // array of ranes + individual items) but, as I don't have time to do it now
  153. // (this would require writing code to merge/break ranges and much more) keep
  154. // it simple but define a clean interface to it which allows it to be made
  155. // smarter later
  156. class WXDLLEXPORT wxSelectionStore
  157. {
  158. public:
  159.     wxSelectionStore() : m_itemsSel(wxSizeTCmpFn) { Init(); }
  160.  
  161.     // set the total number of items we handle
  162.     void SetItemCount(size_t count) { m_count = count; }
  163.  
  164.     // special case of SetItemCount(0)
  165.     void Clear() { m_itemsSel.Clear(); m_count = 0; m_defaultState = FALSE; }
  166.  
  167.     // must be called when a new item is inserted/added
  168.     void OnItemAdd(size_t item) { wxFAIL_MSG( _T("TODO") ); }
  169.  
  170.     // must be called when an item is deleted
  171.     void OnItemDelete(size_t item);
  172.  
  173.     // select one item, use SelectRange() insted if possible!
  174.     //
  175.     // returns true if the items selection really changed
  176.     bool SelectItem(size_t item, bool select = TRUE);
  177.  
  178.     // select the range of items
  179.     //
  180.     // return true and fill the itemsChanged array with the indices of items
  181.     // which have changed state if "few" of them did, otherwise return false
  182.     // (meaning that too many items changed state to bother counting them
  183.     // individually)
  184.     bool SelectRange(size_t itemFrom, size_t itemTo,
  185.                      bool select = TRUE,
  186.                      wxArrayInt *itemsChanged = NULL);
  187.  
  188.     // return true if the given item is selected
  189.     bool IsSelected(size_t item) const;
  190.  
  191.     // return the total number of selected items
  192.     size_t GetSelectedCount() const
  193.     {
  194.         return m_defaultState ? m_count - m_itemsSel.GetCount()
  195.                               : m_itemsSel.GetCount();
  196.     }
  197.  
  198. private:
  199.     // (re)init
  200.     void Init() { m_defaultState = FALSE; }
  201.  
  202.     // the total number of items we handle
  203.     size_t m_count;
  204.  
  205.     // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
  206.     // there are more selected items than non selected ones - this allows to
  207.     // handle selection of all items efficiently
  208.     bool m_defaultState;
  209.  
  210.     // the array of items whose selection state is different from default
  211.     wxIndexArray m_itemsSel;
  212.  
  213.     DECLARE_NO_COPY_CLASS(wxSelectionStore)
  214. };
  215.  
  216. //-----------------------------------------------------------------------------
  217. //  wxListItemData (internal)
  218. //-----------------------------------------------------------------------------
  219.  
  220. class WXDLLEXPORT wxListItemData
  221. {
  222. public:
  223.     wxListItemData(wxListMainWindow *owner);
  224.     ~wxListItemData();
  225.  
  226.     void SetItem( const wxListItem &info );
  227.     void SetImage( int image ) { m_image = image; }
  228.     void SetData( long data ) { m_data = data; }
  229.     void SetPosition( int x, int y );
  230.     void SetSize( int width, int height );
  231.  
  232.     bool HasText() const { return !m_text.empty(); }
  233.     const wxString& GetText() const { return m_text; }
  234.     void SetText(const wxString& text) { m_text = text; }
  235.  
  236.     // we can't use empty string for measuring the string width/height, so
  237.     // always return something
  238.     wxString GetTextForMeasuring() const
  239.     {
  240.         wxString s = GetText();
  241.         if ( s.empty() )
  242.             s = _T('H');
  243.  
  244.         return s;
  245.     }
  246.  
  247.     bool IsHit( int x, int y ) const;
  248.  
  249.     int GetX() const;
  250.     int GetY() const;
  251.     int GetWidth() const;
  252.     int GetHeight() const;
  253.  
  254.     int GetImage() const { return m_image; }
  255.     bool HasImage() const { return GetImage() != -1; }
  256.  
  257.     void GetItem( wxListItem &info ) const;
  258.  
  259.     void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
  260.     wxListItemAttr *GetAttr() const { return m_attr; }
  261.  
  262. public:
  263.     // the item image or -1
  264.     int m_image;
  265.  
  266.     // user data associated with the item
  267.     long m_data;
  268.  
  269.     // the item coordinates are not used in report mode, instead this pointer
  270.     // is NULL and the owner window is used to retrieve the item position and
  271.     // size
  272.     wxRect *m_rect;
  273.  
  274.     // the list ctrl we are in
  275.     wxListMainWindow *m_owner;
  276.  
  277.     // custom attributes or NULL
  278.     wxListItemAttr *m_attr;
  279.  
  280. protected:
  281.     // common part of all ctors
  282.     void Init();
  283.  
  284.     wxString m_text;
  285. };
  286.  
  287. //-----------------------------------------------------------------------------
  288. //  wxListHeaderData (internal)
  289. //-----------------------------------------------------------------------------
  290.  
  291. class WXDLLEXPORT wxListHeaderData : public wxObject
  292. {
  293. public:
  294.     wxListHeaderData();
  295.     wxListHeaderData( const wxListItem &info );
  296.     void SetItem( const wxListItem &item );
  297.     void SetPosition( int x, int y );
  298.     void SetWidth( int w );
  299.     void SetFormat( int format );
  300.     void SetHeight( int h );
  301.     bool HasImage() const;
  302.  
  303.     bool HasText() const { return !m_text.empty(); }
  304.     const wxString& GetText() const { return m_text; }
  305.     void SetText(const wxString& text) { m_text = text; }
  306.  
  307.     void GetItem( wxListItem &item );
  308.  
  309.     bool IsHit( int x, int y ) const;
  310.     int GetImage() const;
  311.     int GetWidth() const;
  312.     int GetFormat() const;
  313.  
  314. protected:
  315.     long      m_mask;
  316.     int       m_image;
  317.     wxString  m_text;
  318.     int       m_format;
  319.     int       m_width;
  320.     int       m_xpos,
  321.               m_ypos;
  322.     int       m_height;
  323.  
  324. private:
  325.     void Init();
  326. };
  327.  
  328. //-----------------------------------------------------------------------------
  329. //  wxListLineData (internal)
  330. //-----------------------------------------------------------------------------
  331.  
  332. WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
  333. #include "wx/listimpl.cpp"
  334. WX_DEFINE_LIST(wxListItemDataList);
  335.  
  336. class WXDLLEXPORT wxListLineData
  337. {
  338. public:
  339.     // the list of subitems: only may have more than one item in report mode
  340.     wxListItemDataList m_items;
  341.  
  342.     // this is not used in report view
  343.     struct GeometryInfo
  344.     {
  345.         // total item rect
  346.         wxRect m_rectAll;
  347.  
  348.         // label only
  349.         wxRect m_rectLabel;
  350.  
  351.         // icon only
  352.         wxRect m_rectIcon;
  353.  
  354.         // the part to be highlighted
  355.         wxRect m_rectHighlight;
  356.     } *m_gi;
  357.  
  358.     // is this item selected? [NB: not used in virtual mode]
  359.     bool m_highlighted;
  360.  
  361.     // back pointer to the list ctrl
  362.     wxListMainWindow *m_owner;
  363.  
  364. public:
  365.     wxListLineData(wxListMainWindow *owner);
  366.  
  367.     ~wxListLineData() { delete m_gi; }
  368.  
  369.     // are we in report mode?
  370.     inline bool InReportView() const;
  371.  
  372.     // are we in virtual report mode?
  373.     inline bool IsVirtual() const;
  374.  
  375.     // these 2 methods shouldn't be called for report view controls, in that
  376.     // case we determine our position/size ourselves
  377.  
  378.     // calculate the size of the line
  379.     void CalculateSize( wxDC *dc, int spacing );
  380.  
  381.     // remember the position this line appears at
  382.     void SetPosition( int x, int y,  int window_width, int spacing );
  383.  
  384.     // wxListCtrl API
  385.  
  386.     void SetImage( int image ) { SetImage(0, image); }
  387.     int GetImage() const { return GetImage(0); }
  388.     bool HasImage() const { return GetImage() != -1; }
  389.     bool HasText() const { return !GetText(0).empty(); }
  390.  
  391.     void SetItem( int index, const wxListItem &info );
  392.     void GetItem( int index, wxListItem &info );
  393.  
  394.     wxString GetText(int index) const;
  395.     void SetText( int index, const wxString s );
  396.  
  397.     wxListItemAttr *GetAttr() const;
  398.     void SetAttr(wxListItemAttr *attr);
  399.  
  400.     // return true if the highlighting really changed
  401.     bool Highlight( bool on );
  402.  
  403.     void ReverseHighlight();
  404.  
  405.     bool IsHighlighted() const
  406.     {
  407.         wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
  408.  
  409.         return m_highlighted;
  410.     }
  411.  
  412.     // draw the line on the given DC in icon/list mode
  413.     void Draw( wxDC *dc );
  414.  
  415.     // the same in report mode
  416.     void DrawInReportMode( wxDC *dc,
  417.                            const wxRect& rect,
  418.                            const wxRect& rectHL,
  419.                            bool highlighted );
  420.  
  421. private:
  422.     // set the line to contain num items (only can be > 1 in report mode)
  423.     void InitItems( int num );
  424.  
  425.     // get the mode (i.e. style)  of the list control
  426.     inline int GetMode() const;
  427.  
  428.     // prepare the DC for drawing with these item's attributes, return true if
  429.     // we need to draw the items background to highlight it, false otherwise
  430.     bool SetAttributes(wxDC *dc,
  431.                        const wxListItemAttr *attr,
  432.                        bool highlight);
  433.  
  434.     // draw the text on the DC with the correct justification; also add an
  435.     // ellipsis if the text is too large to fit in the current width
  436.     void DrawTextFormatted(wxDC *dc, const wxString &text, int col, int x, int y, int width);
  437.  
  438.     // these are only used by GetImage/SetImage above, we don't support images
  439.     // with subitems at the public API level yet
  440.     void SetImage( int index, int image );
  441.     int GetImage( int index ) const;
  442. };
  443.  
  444. WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
  445. #include "wx/arrimpl.cpp"
  446. WX_DEFINE_OBJARRAY(wxListLineDataArray);
  447.  
  448. //-----------------------------------------------------------------------------
  449. //  wxListHeaderWindow (internal)
  450. //-----------------------------------------------------------------------------
  451.  
  452. class WXDLLEXPORT wxListHeaderWindow : public wxWindow
  453. {
  454. protected:
  455.     wxListMainWindow  *m_owner;
  456.     wxCursor          *m_currentCursor;
  457.     wxCursor          *m_resizeCursor;
  458.     bool               m_isDragging;
  459.  
  460.     // column being resized or -1
  461.     int m_column;
  462.  
  463.     // divider line position in logical (unscrolled) coords
  464.     int m_currentX;
  465.  
  466.     // minimal position beyond which the divider line can't be dragged in
  467.     // logical coords
  468.     int m_minX;
  469.  
  470. public:
  471.     wxListHeaderWindow();
  472.  
  473.     wxListHeaderWindow( wxWindow *win,
  474.                         wxWindowID id,
  475.                         wxListMainWindow *owner,
  476.                         const wxPoint &pos = wxDefaultPosition,
  477.                         const wxSize &size = wxDefaultSize,
  478.                         long style = 0,
  479.                         const wxString &name = wxT("wxlistctrlcolumntitles") );
  480.  
  481.     virtual ~wxListHeaderWindow();
  482.  
  483.     void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
  484.     void DrawCurrent();
  485.     void AdjustDC(wxDC& dc);
  486.  
  487.     void OnPaint( wxPaintEvent &event );
  488.     void OnMouse( wxMouseEvent &event );
  489.     void OnSetFocus( wxFocusEvent &event );
  490.  
  491.     // needs refresh
  492.     bool m_dirty;
  493.  
  494. private:
  495.     // common part of all ctors
  496.     void Init();
  497.  
  498.     void SendListEvent(wxEventType type, wxPoint pos);
  499.  
  500.     DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
  501.     DECLARE_EVENT_TABLE()
  502. };
  503.  
  504. //-----------------------------------------------------------------------------
  505. // wxListRenameTimer (internal)
  506. //-----------------------------------------------------------------------------
  507.  
  508. class WXDLLEXPORT wxListRenameTimer: public wxTimer
  509. {
  510. private:
  511.     wxListMainWindow *m_owner;
  512.  
  513. public:
  514.     wxListRenameTimer( wxListMainWindow *owner );
  515.     void Notify();
  516. };
  517.  
  518. //-----------------------------------------------------------------------------
  519. //  wxListTextCtrl (internal)
  520. //-----------------------------------------------------------------------------
  521.  
  522. class WXDLLEXPORT wxListTextCtrl: public wxTextCtrl
  523. {
  524. public:
  525.     wxListTextCtrl(wxListMainWindow *owner, size_t itemEdit);
  526.  
  527. protected:
  528.     void OnChar( wxKeyEvent &event );
  529.     void OnKeyUp( wxKeyEvent &event );
  530.     void OnKillFocus( wxFocusEvent &event );
  531.  
  532.     bool AcceptChanges();
  533.     void Finish();
  534.  
  535. private:
  536.     wxListMainWindow   *m_owner;
  537.     wxString            m_startValue;
  538.     size_t              m_itemEdited;
  539.     bool                m_finished;
  540.  
  541.     DECLARE_EVENT_TABLE()
  542. };
  543.  
  544. //-----------------------------------------------------------------------------
  545. //  wxListMainWindow (internal)
  546. //-----------------------------------------------------------------------------
  547.  
  548. WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
  549. #include "wx/listimpl.cpp"
  550. WX_DEFINE_LIST(wxListHeaderDataList);
  551.  
  552. class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow
  553. {
  554. public:
  555.     wxListMainWindow();
  556.     wxListMainWindow( wxWindow *parent,
  557.                       wxWindowID id,
  558.                       const wxPoint& pos = wxDefaultPosition,
  559.                       const wxSize& size = wxDefaultSize,
  560.                       long style = 0,
  561.                       const wxString &name = _T("listctrlmainwindow") );
  562.  
  563.     virtual ~wxListMainWindow();
  564.  
  565.     bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
  566.  
  567.     // return true if this is a virtual list control
  568.     bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
  569.  
  570.     // return true if the control is in report mode
  571.     bool InReportView() const { return HasFlag(wxLC_REPORT); }
  572.  
  573.     // return true if we are in single selection mode, false if multi sel
  574.     bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
  575.  
  576.     // do we have a header window?
  577.     bool HasHeader() const
  578.         { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
  579.  
  580.     void HighlightAll( bool on );
  581.  
  582.     // all these functions only do something if the line is currently visible
  583.  
  584.     // change the line "selected" state, return TRUE if it really changed
  585.     bool HighlightLine( size_t line, bool highlight = TRUE);
  586.  
  587.     // as HighlightLine() but do it for the range of lines: this is incredibly
  588.     // more efficient for virtual list controls!
  589.     //
  590.     // NB: unlike HighlightLine() this one does refresh the lines on screen
  591.     void HighlightLines( size_t lineFrom, size_t lineTo, bool on = TRUE );
  592.  
  593.     // toggle the line state and refresh it
  594.     void ReverseHighlight( size_t line )
  595.         { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
  596.  
  597.     // return true if the line is highlighted
  598.     bool IsHighlighted(size_t line) const;
  599.  
  600.     // refresh one or several lines at once
  601.     void RefreshLine( size_t line );
  602.     void RefreshLines( size_t lineFrom, size_t lineTo );
  603.  
  604.     // refresh all selected items
  605.     void RefreshSelected();
  606.  
  607.     // refresh all lines below the given one: the difference with
  608.     // RefreshLines() is that the index here might not be a valid one (happens
  609.     // when the last line is deleted)
  610.     void RefreshAfter( size_t lineFrom );
  611.  
  612.     // the methods which are forwarded to wxListLineData itself in list/icon
  613.     // modes but are here because the lines don't store their positions in the
  614.     // report mode
  615.  
  616.     // get the bound rect for the entire line
  617.     wxRect GetLineRect(size_t line) const;
  618.  
  619.     // get the bound rect of the label
  620.     wxRect GetLineLabelRect(size_t line) const;
  621.  
  622.     // get the bound rect of the items icon (only may be called if we do have
  623.     // an icon!)
  624.     wxRect GetLineIconRect(size_t line) const;
  625.  
  626.     // get the rect to be highlighted when the item has focus
  627.     wxRect GetLineHighlightRect(size_t line) const;
  628.  
  629.     // get the size of the total line rect
  630.     wxSize GetLineSize(size_t line) const
  631.         { return GetLineRect(line).GetSize(); }
  632.  
  633.     // return the hit code for the corresponding position (in this line)
  634.     long HitTestLine(size_t line, int x, int y) const;
  635.  
  636.     // bring the selected item into view, scrolling to it if necessary
  637.     void MoveToItem(size_t item);
  638.  
  639.     // bring the current item into view
  640.     void MoveToFocus() { MoveToItem(m_current); }
  641.  
  642.     // start editing the label of the given item
  643.     void EditLabel( long item );
  644.  
  645.     // suspend/resume redrawing the control
  646.     void Freeze();
  647.     void Thaw();
  648.  
  649.     void SetFocus();
  650.  
  651.     void OnRenameTimer();
  652.     bool OnRenameAccept(size_t itemEdit, const wxString& value);
  653.  
  654.     void OnMouse( wxMouseEvent &event );
  655.  
  656.     // called to switch the selection from the current item to newCurrent,
  657.     void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
  658.  
  659.     void OnChar( wxKeyEvent &event );
  660.     void OnKeyDown( wxKeyEvent &event );
  661.     void OnSetFocus( wxFocusEvent &event );
  662.     void OnKillFocus( wxFocusEvent &event );
  663.     void OnScroll(wxScrollWinEvent& event) ;
  664.  
  665.     void OnPaint( wxPaintEvent &event );
  666.  
  667.     void DrawImage( int index, wxDC *dc, int x, int y );
  668.     void GetImageSize( int index, int &width, int &height ) const;
  669.     int GetTextLength( const wxString &s ) const;
  670.  
  671.     void SetImageList( wxImageListType *imageList, int which );
  672.     void SetItemSpacing( int spacing, bool isSmall = FALSE );
  673.     int GetItemSpacing( bool isSmall = FALSE );
  674.  
  675.     void SetColumn( int col, wxListItem &item );
  676.     void SetColumnWidth( int col, int width );
  677.     void GetColumn( int col, wxListItem &item ) const;
  678.     int GetColumnWidth( int col ) const;
  679.     int GetColumnCount() const { return m_columns.GetCount(); }
  680.  
  681.     // returns the sum of the heights of all columns
  682.     int GetHeaderWidth() const;
  683.  
  684.     int GetCountPerPage() const;
  685.  
  686.     void SetItem( wxListItem &item );
  687.     void GetItem( wxListItem &item ) const;
  688.     void SetItemState( long item, long state, long stateMask );
  689.     int GetItemState( long item, long stateMask ) const;
  690.     void GetItemRect( long index, wxRect &rect ) const;
  691.     bool GetItemPosition( long item, wxPoint& pos ) const;
  692.     int GetSelectedItemCount() const;
  693.  
  694.     wxString GetItemText(long item) const
  695.     {
  696.         wxListItem info;
  697.         info.m_itemId = item;
  698.         GetItem( info );
  699.         return info.m_text;
  700.     }
  701.  
  702.     void SetItemText(long item, const wxString& value)
  703.     {
  704.         wxListItem info;
  705.         info.m_mask = wxLIST_MASK_TEXT;
  706.         info.m_itemId = item;
  707.         info.m_text = value;
  708.         SetItem( info );
  709.     }
  710.  
  711.     // set the scrollbars and update the positions of the items
  712.     void RecalculatePositions(bool noRefresh = FALSE);
  713.  
  714.     // refresh the window and the header
  715.     void RefreshAll();
  716.  
  717.     long GetNextItem( long item, int geometry, int state ) const;
  718.     void DeleteItem( long index );
  719.     void DeleteAllItems();
  720.     void DeleteColumn( int col );
  721.     void DeleteEverything();
  722.     void EnsureVisible( long index );
  723.     long FindItem( long start, const wxString& str, bool partial = FALSE );
  724.     long FindItem( long start, long data);
  725.     long HitTest( int x, int y, int &flags );
  726.     void InsertItem( wxListItem &item );
  727.     void InsertColumn( long col, wxListItem &item );
  728.     void SortItems( wxListCtrlCompare fn, long data );
  729.  
  730.     size_t GetItemCount() const;
  731.     bool IsEmpty() const { return GetItemCount() == 0; }
  732.     void SetItemCount(long count);
  733.  
  734.     // change the current (== focused) item, send a notification event
  735.     void ChangeCurrent(size_t current);
  736.     void ResetCurrent() { ChangeCurrent((size_t)-1); }
  737.     bool HasCurrent() const { return m_current != (size_t)-1; }
  738.  
  739.     // send out a wxListEvent
  740.     void SendNotify( size_t line,
  741.                      wxEventType command,
  742.                      wxPoint point = wxDefaultPosition );
  743.  
  744.     // override base class virtual to reset m_lineHeight when the font changes
  745.     virtual bool SetFont(const wxFont& font)
  746.     {
  747.         if ( !wxScrolledWindow::SetFont(font) )
  748.             return FALSE;
  749.  
  750.         m_lineHeight = 0;
  751.  
  752.         return TRUE;
  753.     }
  754.  
  755.     // these are for wxListLineData usage only
  756.  
  757.     // get the backpointer to the list ctrl
  758.     wxGenericListCtrl *GetListCtrl() const
  759.     {
  760.         return wxStaticCast(GetParent(), wxGenericListCtrl);
  761.     }
  762.  
  763.     // get the height of all lines (assuming they all do have the same height)
  764.     wxCoord GetLineHeight() const;
  765.  
  766.     // get the y position of the given line (only for report view)
  767.     wxCoord GetLineY(size_t line) const;
  768.  
  769.     // get the brush to use for the item highlighting
  770.     wxBrush *GetHighlightBrush() const
  771.     {
  772.         return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
  773.     }
  774.  
  775. //protected:
  776.     // the array of all line objects for a non virtual list control (for the
  777.     // virtual list control we only ever use m_lines[0])
  778.     wxListLineDataArray  m_lines;
  779.  
  780.     // the list of column objects
  781.     wxListHeaderDataList m_columns;
  782.  
  783.     // currently focused item or -1
  784.     size_t               m_current;
  785.  
  786.     // the number of lines per page
  787.     int                  m_linesPerPage;
  788.  
  789.     // this flag is set when something which should result in the window
  790.     // redrawing happens (i.e. an item was added or deleted, or its appearance
  791.     // changed) and OnPaint() doesn't redraw the window while it is set which
  792.     // allows to minimize the number of repaintings when a lot of items are
  793.     // being added. The real repainting occurs only after the next OnIdle()
  794.     // call
  795.     bool                 m_dirty;
  796.  
  797.     wxColour            *m_highlightColour;
  798.     int                  m_xScroll,
  799.                          m_yScroll;
  800.     wxImageListType         *m_small_image_list;
  801.     wxImageListType         *m_normal_image_list;
  802.     int                  m_small_spacing;
  803.     int                  m_normal_spacing;
  804.     bool                 m_hasFocus;
  805.  
  806.     bool                 m_lastOnSame;
  807.     wxTimer             *m_renameTimer;
  808.     bool                 m_isCreated;
  809.     int                  m_dragCount;
  810.     wxPoint              m_dragStart;
  811.  
  812.     // for double click logic
  813.     size_t m_lineLastClicked,
  814.            m_lineBeforeLastClicked;
  815.  
  816. protected:
  817.     // the total count of items in a virtual list control
  818.     size_t m_countVirt;
  819.  
  820.     // the object maintaining the items selection state, only used in virtual
  821.     // controls
  822.     wxSelectionStore m_selStore;
  823.  
  824.     // common part of all ctors
  825.     void Init();
  826.  
  827.     // intiialize m_[xy]Scroll
  828.     void InitScrolling();
  829.  
  830.     // get the line data for the given index
  831.     wxListLineData *GetLine(size_t n) const
  832.     {
  833.         wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") );
  834.  
  835.         if ( IsVirtual() )
  836.         {
  837.             wxConstCast(this, wxListMainWindow)->CacheLineData(n);
  838.  
  839.             n = 0;
  840.         }
  841.  
  842.         return &m_lines[n];
  843.     }
  844.  
  845.     // get a dummy line which can be used for geometry calculations and such:
  846.     // you must use GetLine() if you want to really draw the line
  847.     wxListLineData *GetDummyLine() const;
  848.  
  849.     // cache the line data of the n-th line in m_lines[0]
  850.     void CacheLineData(size_t line);
  851.  
  852.     // get the range of visible lines
  853.     void GetVisibleLinesRange(size_t *from, size_t *to);
  854.  
  855.     // force us to recalculate the range of visible lines
  856.     void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
  857.  
  858.     // get the colour to be used for drawing the rules
  859.     wxColour GetRuleColour() const
  860.     {
  861. #ifdef __WXMAC__
  862.         return *wxWHITE;
  863. #else
  864.         return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
  865. #endif
  866.     }
  867.  
  868. private:
  869.     // initialize the current item if needed
  870.     void UpdateCurrent();
  871.  
  872.     // delete all items but don't refresh: called from dtor
  873.     void DoDeleteAllItems();
  874.  
  875.     // the height of one line using the current font
  876.     wxCoord m_lineHeight;
  877.  
  878.     // the total header width or 0 if not calculated yet
  879.     wxCoord m_headerWidth;
  880.  
  881.     // the first and last lines being shown on screen right now (inclusive),
  882.     // both may be -1 if they must be calculated so never access them directly:
  883.     // use GetVisibleLinesRange() above instead
  884.     size_t m_lineFrom,
  885.            m_lineTo;
  886.  
  887.     // the brushes to use for item highlighting when we do/don't have focus
  888.     wxBrush *m_highlightBrush,
  889.             *m_highlightUnfocusedBrush;
  890.  
  891.     // if this is > 0, the control is frozen and doesn't redraw itself
  892.     size_t m_freezeCount;
  893.  
  894.     DECLARE_DYNAMIC_CLASS(wxListMainWindow)
  895.     DECLARE_EVENT_TABLE()
  896.  
  897.     friend class wxGenericListCtrl;
  898. };
  899.  
  900. // ============================================================================
  901. // implementation
  902. // ============================================================================
  903.  
  904. // ----------------------------------------------------------------------------
  905. // wxSelectionStore
  906. // ----------------------------------------------------------------------------
  907.  
  908. bool wxSelectionStore::IsSelected(size_t item) const
  909. {
  910.     bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
  911.  
  912.     // if the default state is to be selected, being in m_itemsSel means that
  913.     // the item is not selected, so we have to inverse the logic
  914.     return m_defaultState ? !isSel : isSel;
  915. }
  916.  
  917. bool wxSelectionStore::SelectItem(size_t item, bool select)
  918. {
  919.     // search for the item ourselves as like this we get the index where to
  920.     // insert it later if needed, so we do only one search in the array instead
  921.     // of two (adding item to a sorted array requires a search)
  922.     size_t index = m_itemsSel.IndexForInsert(item);
  923.     bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
  924.  
  925.     if ( select != m_defaultState )
  926.     {
  927.         if ( !isSel )
  928.         {
  929.             m_itemsSel.AddAt(item, index);
  930.  
  931.             return TRUE;
  932.         }
  933.     }
  934.     else // reset to default state
  935.     {
  936.         if ( isSel )
  937.         {
  938.             m_itemsSel.RemoveAt(index);
  939.             return TRUE;
  940.         }
  941.     }
  942.  
  943.     return FALSE;
  944. }
  945.  
  946. bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo,
  947.                                    bool select,
  948.                                    wxArrayInt *itemsChanged)
  949. {
  950.     // 100 is hardcoded but it shouldn't matter much: the important thing is
  951.     // that we don't refresh everything when really few (e.g. 1 or 2) items
  952.     // change state
  953.     static const size_t MANY_ITEMS = 100;
  954.  
  955.     wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") );
  956.  
  957.     // are we going to have more [un]selected items than the other ones?
  958.     if ( itemTo - itemFrom > m_count/2 )
  959.     {
  960.         if ( select != m_defaultState )
  961.         {
  962.             // the default state now becomes the same as 'select'
  963.             m_defaultState = select;
  964.  
  965.             // so all the old selections (which had state select) shouldn't be
  966.             // selected any more, but all the other ones should
  967.             wxIndexArray selOld = m_itemsSel;
  968.             m_itemsSel.Empty();
  969.  
  970.             // TODO: it should be possible to optimize the searches a bit
  971.             //       knowing the possible range
  972.  
  973.             size_t item;
  974.             for ( item = 0; item < itemFrom; item++ )
  975.             {
  976.                 if ( selOld.Index(item) == wxNOT_FOUND )
  977.                     m_itemsSel.Add(item);
  978.             }
  979.  
  980.             for ( item = itemTo + 1; item < m_count; item++ )
  981.             {
  982.                 if ( selOld.Index(item) == wxNOT_FOUND )
  983.                     m_itemsSel.Add(item);
  984.             }
  985.  
  986.             // many items (> half) changed state
  987.             itemsChanged = NULL;
  988.         }
  989.         else // select == m_defaultState
  990.         {
  991.             // get the inclusive range of items between itemFrom and itemTo
  992.             size_t count = m_itemsSel.GetCount(),
  993.                    start = m_itemsSel.IndexForInsert(itemFrom),
  994.                    end = m_itemsSel.IndexForInsert(itemTo);
  995.  
  996.             if ( start == count || m_itemsSel[start] < itemFrom )
  997.             {
  998.                 start++;
  999.             }
  1000.  
  1001.             if ( end == count || m_itemsSel[end] > itemTo )
  1002.             {
  1003.                 end--;
  1004.             }
  1005.  
  1006.             if ( start <= end )
  1007.             {
  1008.                 // delete all of them (from end to avoid changing indices)
  1009.                 for ( int i = end; i >= (int)start; i-- )
  1010.                 {
  1011.                     if ( itemsChanged )
  1012.                     {
  1013.                         if ( itemsChanged->GetCount() > MANY_ITEMS )
  1014.                         {
  1015.                             // stop counting (see comment below)
  1016.                             itemsChanged = NULL;
  1017.                         }
  1018.                         else
  1019.                         {
  1020.                             itemsChanged->Add(m_itemsSel[i]);
  1021.                         }
  1022.                     }
  1023.  
  1024.                     m_itemsSel.RemoveAt(i);
  1025.                 }
  1026.             }
  1027.         }
  1028.     }
  1029.     else // "few" items change state
  1030.     {
  1031.         if ( itemsChanged )
  1032.         {
  1033.             itemsChanged->Empty();
  1034.         }
  1035.  
  1036.         // just add the items to the selection
  1037.         for ( size_t item = itemFrom; item <= itemTo; item++ )
  1038.         {
  1039.             if ( SelectItem(item, select) && itemsChanged )
  1040.             {
  1041.                 itemsChanged->Add(item);
  1042.  
  1043.                 if ( itemsChanged->GetCount() > MANY_ITEMS )
  1044.                 {
  1045.                     // stop counting them, we'll just eat gobs of memory
  1046.                     // for nothing at all - faster to refresh everything in
  1047.                     // this case
  1048.                     itemsChanged = NULL;
  1049.                 }
  1050.             }
  1051.         }
  1052.     }
  1053.  
  1054.     // we set it to NULL if there are many items changing state
  1055.     return itemsChanged != NULL;
  1056. }
  1057.  
  1058. void wxSelectionStore::OnItemDelete(size_t item)
  1059. {
  1060.     size_t count = m_itemsSel.GetCount(),
  1061.            i = m_itemsSel.IndexForInsert(item);
  1062.  
  1063.     if ( i < count && m_itemsSel[i] == item )
  1064.     {
  1065.         // this item itself was in m_itemsSel, remove it from there
  1066.         m_itemsSel.RemoveAt(i);
  1067.  
  1068.         count--;
  1069.     }
  1070.  
  1071.     // and adjust the index of all which follow it
  1072.     while ( i < count )
  1073.     {
  1074.         // all following elements must be greater than the one we deleted
  1075.         wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") );
  1076.  
  1077.         m_itemsSel[i++]--;
  1078.     }
  1079. }
  1080.  
  1081. //-----------------------------------------------------------------------------
  1082. //  wxListItemData
  1083. //-----------------------------------------------------------------------------
  1084.  
  1085. wxListItemData::~wxListItemData()
  1086. {
  1087.     // in the virtual list control the attributes are managed by the main
  1088.     // program, so don't delete them
  1089.     if ( !m_owner->IsVirtual() )
  1090.     {
  1091.         delete m_attr;
  1092.     }
  1093.  
  1094.     delete m_rect;
  1095. }
  1096.  
  1097. void wxListItemData::Init()
  1098. {
  1099.     m_image = -1;
  1100.     m_data = 0;
  1101.  
  1102.     m_attr = NULL;
  1103. }
  1104.  
  1105. wxListItemData::wxListItemData(wxListMainWindow *owner)
  1106. {
  1107.     Init();
  1108.  
  1109.     m_owner = owner;
  1110.  
  1111.     if ( owner->InReportView() )
  1112.     {
  1113.         m_rect = NULL;
  1114.     }
  1115.     else
  1116.     {
  1117.         m_rect = new wxRect;
  1118.     }
  1119. }
  1120.  
  1121. void wxListItemData::SetItem( const wxListItem &info )
  1122. {
  1123.     if ( info.m_mask & wxLIST_MASK_TEXT )
  1124.         SetText(info.m_text);
  1125.     if ( info.m_mask & wxLIST_MASK_IMAGE )
  1126.         m_image = info.m_image;
  1127.     if ( info.m_mask & wxLIST_MASK_DATA )
  1128.         m_data = info.m_data;
  1129.  
  1130.     if ( info.HasAttributes() )
  1131.     {
  1132.         if ( m_attr )
  1133.             *m_attr = *info.GetAttributes();
  1134.         else
  1135.             m_attr = new wxListItemAttr(*info.GetAttributes());
  1136.     }
  1137.  
  1138.     if ( m_rect )
  1139.     {
  1140.         m_rect->x =
  1141.         m_rect->y =
  1142.         m_rect->height = 0;
  1143.         m_rect->width = info.m_width;
  1144.     }
  1145. }
  1146.  
  1147. void wxListItemData::SetPosition( int x, int y )
  1148. {
  1149.     wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") );
  1150.  
  1151.     m_rect->x = x;
  1152.     m_rect->y = y;
  1153. }
  1154.  
  1155. void wxListItemData::SetSize( int width, int height )
  1156. {
  1157.     wxCHECK_RET( m_rect, _T("unexpected SetSize() call") );
  1158.  
  1159.     if ( width != -1 )
  1160.         m_rect->width = width;
  1161.     if ( height != -1 )
  1162.         m_rect->height = height;
  1163. }
  1164.  
  1165. bool wxListItemData::IsHit( int x, int y ) const
  1166. {
  1167.     wxCHECK_MSG( m_rect, FALSE, _T("can't be called in this mode") );
  1168.  
  1169.     return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x, y);
  1170. }
  1171.  
  1172. int wxListItemData::GetX() const
  1173. {
  1174.     wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
  1175.  
  1176.     return m_rect->x;
  1177. }
  1178.  
  1179. int wxListItemData::GetY() const
  1180. {
  1181.     wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
  1182.  
  1183.     return m_rect->y;
  1184. }
  1185.  
  1186. int wxListItemData::GetWidth() const
  1187. {
  1188.     wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
  1189.  
  1190.     return m_rect->width;
  1191. }
  1192.  
  1193. int wxListItemData::GetHeight() const
  1194. {
  1195.     wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
  1196.  
  1197.     return m_rect->height;
  1198. }
  1199.  
  1200. void wxListItemData::GetItem( wxListItem &info ) const
  1201. {
  1202.     info.m_text = m_text;
  1203.     info.m_image = m_image;
  1204.     info.m_data = m_data;
  1205.  
  1206.     if ( m_attr )
  1207.     {
  1208.         if ( m_attr->HasTextColour() )
  1209.             info.SetTextColour(m_attr->GetTextColour());
  1210.         if ( m_attr->HasBackgroundColour() )
  1211.             info.SetBackgroundColour(m_attr->GetBackgroundColour());
  1212.         if ( m_attr->HasFont() )
  1213.             info.SetFont(m_attr->GetFont());
  1214.     }
  1215. }
  1216.  
  1217. //-----------------------------------------------------------------------------
  1218. //  wxListHeaderData
  1219. //-----------------------------------------------------------------------------
  1220.  
  1221. void wxListHeaderData::Init()
  1222. {
  1223.     m_mask = 0;
  1224.     m_image = -1;
  1225.     m_format = 0;
  1226.     m_width = 0;
  1227.     m_xpos = 0;
  1228.     m_ypos = 0;
  1229.     m_height = 0;
  1230. }
  1231.  
  1232. wxListHeaderData::wxListHeaderData()
  1233. {
  1234.     Init();
  1235. }
  1236.  
  1237. wxListHeaderData::wxListHeaderData( const wxListItem &item )
  1238. {
  1239.     Init();
  1240.  
  1241.     SetItem( item );
  1242. }
  1243.  
  1244. void wxListHeaderData::SetItem( const wxListItem &item )
  1245. {
  1246.     m_mask = item.m_mask;
  1247.  
  1248.     if ( m_mask & wxLIST_MASK_TEXT )
  1249.         m_text = item.m_text;
  1250.  
  1251.     if ( m_mask & wxLIST_MASK_IMAGE )
  1252.         m_image = item.m_image;
  1253.  
  1254.     if ( m_mask & wxLIST_MASK_FORMAT )
  1255.         m_format = item.m_format;
  1256.  
  1257.     if ( m_mask & wxLIST_MASK_WIDTH )
  1258.         SetWidth(item.m_width);
  1259. }
  1260.  
  1261. void wxListHeaderData::SetPosition( int x, int y )
  1262. {
  1263.     m_xpos = x;
  1264.     m_ypos = y;
  1265. }
  1266.  
  1267. void wxListHeaderData::SetHeight( int h )
  1268. {
  1269.     m_height = h;
  1270. }
  1271.  
  1272. void wxListHeaderData::SetWidth( int w )
  1273. {
  1274.     m_width = w;
  1275.     if (m_width < 0)
  1276.         m_width = WIDTH_COL_DEFAULT;
  1277.     else if (m_width < WIDTH_COL_MIN)
  1278.         m_width = WIDTH_COL_MIN;
  1279. }
  1280.  
  1281. void wxListHeaderData::SetFormat( int format )
  1282. {
  1283.     m_format = format;
  1284. }
  1285.  
  1286. bool wxListHeaderData::HasImage() const
  1287. {
  1288.     return m_image != -1;
  1289. }
  1290.  
  1291. bool wxListHeaderData::IsHit( int x, int y ) const
  1292. {
  1293.     return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
  1294. }
  1295.  
  1296. void wxListHeaderData::GetItem( wxListItem& item )
  1297. {
  1298.     item.m_mask = m_mask;
  1299.     item.m_text = m_text;
  1300.     item.m_image = m_image;
  1301.     item.m_format = m_format;
  1302.     item.m_width = m_width;
  1303. }
  1304.  
  1305. int wxListHeaderData::GetImage() const
  1306. {
  1307.     return m_image;
  1308. }
  1309.  
  1310. int wxListHeaderData::GetWidth() const
  1311. {
  1312.     return m_width;
  1313. }
  1314.  
  1315. int wxListHeaderData::GetFormat() const
  1316. {
  1317.     return m_format;
  1318. }
  1319.  
  1320. //-----------------------------------------------------------------------------
  1321. //  wxListLineData
  1322. //-----------------------------------------------------------------------------
  1323.  
  1324. inline int wxListLineData::GetMode() const
  1325. {
  1326.     return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE;
  1327. }
  1328.  
  1329. inline bool wxListLineData::InReportView() const
  1330. {
  1331.     return m_owner->HasFlag(wxLC_REPORT);
  1332. }
  1333.  
  1334. inline bool wxListLineData::IsVirtual() const
  1335. {
  1336.     return m_owner->IsVirtual();
  1337. }
  1338.  
  1339. wxListLineData::wxListLineData( wxListMainWindow *owner )
  1340. {
  1341.     m_owner = owner;
  1342.     m_items.DeleteContents( TRUE );
  1343.  
  1344.     if ( InReportView() )
  1345.     {
  1346.         m_gi = NULL;
  1347.     }
  1348.     else // !report
  1349.     {
  1350.         m_gi = new GeometryInfo;
  1351.     }
  1352.  
  1353.     m_highlighted = FALSE;
  1354.  
  1355.     InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 );
  1356. }
  1357.  
  1358. void wxListLineData::CalculateSize( wxDC *dc, int spacing )
  1359. {
  1360.     wxListItemDataList::Node *node = m_items.GetFirst();
  1361.     wxCHECK_RET( node, _T("no subitems at all??") );
  1362.  
  1363.     wxListItemData *item = node->GetData();
  1364.  
  1365.     switch ( GetMode() )
  1366.     {
  1367.         case wxLC_ICON:
  1368.         case wxLC_SMALL_ICON:
  1369.             {
  1370.                 m_gi->m_rectAll.width = spacing;
  1371.  
  1372.                 wxString s = item->GetText();
  1373.  
  1374.                 wxCoord lw, lh;
  1375.                 if ( s.empty() )
  1376.                 {
  1377.                     lh =
  1378.                     m_gi->m_rectLabel.width =
  1379.                     m_gi->m_rectLabel.height = 0;
  1380.                 }
  1381.                 else // has label
  1382.                 {
  1383.                     dc->GetTextExtent( s, &lw, &lh );
  1384.                     if (lh < SCROLL_UNIT_Y)
  1385.                         lh = SCROLL_UNIT_Y;
  1386.                     lw += EXTRA_WIDTH;
  1387.                     lh += EXTRA_HEIGHT;
  1388.  
  1389.                     m_gi->m_rectAll.height = spacing + lh;
  1390.                     if (lw > spacing)
  1391.                         m_gi->m_rectAll.width = lw;
  1392.  
  1393.                     m_gi->m_rectLabel.width = lw;
  1394.                     m_gi->m_rectLabel.height = lh;
  1395.                 }
  1396.  
  1397.                 if (item->HasImage())
  1398.                 {
  1399.                     int w, h;
  1400.                     m_owner->GetImageSize( item->GetImage(), w, h );
  1401.                     m_gi->m_rectIcon.width = w + 8;
  1402.                     m_gi->m_rectIcon.height = h + 8;
  1403.  
  1404.                     if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
  1405.                         m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
  1406.                     if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
  1407.                         m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
  1408.                 }
  1409.  
  1410.                 if ( item->HasText() )
  1411.                 {
  1412.                     m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
  1413.                     m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
  1414.                 }
  1415.                 else // no text, highlight the icon
  1416.                 {
  1417.                     m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
  1418.                     m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
  1419.                 }
  1420.             }
  1421.             break;
  1422.  
  1423.         case wxLC_LIST:
  1424.             {
  1425.                 wxString s = item->GetTextForMeasuring();
  1426.  
  1427.                 wxCoord lw,lh;
  1428.                 dc->GetTextExtent( s, &lw, &lh );
  1429.                 if (lh < SCROLL_UNIT_Y)
  1430.                     lh = SCROLL_UNIT_Y;
  1431.                 lw += EXTRA_WIDTH;
  1432.                 lh += EXTRA_HEIGHT;
  1433.  
  1434.                 m_gi->m_rectLabel.width = lw;
  1435.                 m_gi->m_rectLabel.height = lh;
  1436.  
  1437.                 m_gi->m_rectAll.width = lw;
  1438.                 m_gi->m_rectAll.height = lh;
  1439.  
  1440.                 if (item->HasImage())
  1441.                 {
  1442.                     int w, h;
  1443.                     m_owner->GetImageSize( item->GetImage(), w, h );
  1444.                     m_gi->m_rectIcon.width = w;
  1445.                     m_gi->m_rectIcon.height = h;
  1446.  
  1447.                     m_gi->m_rectAll.width += 4 + w;
  1448.                     if (h > m_gi->m_rectAll.height)
  1449.                         m_gi->m_rectAll.height = h;
  1450.                 }
  1451.  
  1452.                 m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
  1453.                 m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
  1454.             }
  1455.             break;
  1456.  
  1457.         case wxLC_REPORT:
  1458.             wxFAIL_MSG( _T("unexpected call to SetSize") );
  1459.             break;
  1460.  
  1461.         default:
  1462.             wxFAIL_MSG( _T("unknown mode") );
  1463.     }
  1464. }
  1465.  
  1466. void wxListLineData::SetPosition( int x, int y,
  1467.                                   int window_width,
  1468.                                   int spacing )
  1469. {
  1470.     wxListItemDataList::Node *node = m_items.GetFirst();
  1471.     wxCHECK_RET( node, _T("no subitems at all??") );
  1472.  
  1473.     wxListItemData *item = node->GetData();
  1474.  
  1475.     switch ( GetMode() )
  1476.     {
  1477.         case wxLC_ICON:
  1478.         case wxLC_SMALL_ICON:
  1479.             m_gi->m_rectAll.x = x;
  1480.             m_gi->m_rectAll.y = y;
  1481.  
  1482.             if ( item->HasImage() )
  1483.             {
  1484.                 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4 +
  1485.                     (m_gi->m_rectAll.width - m_gi->m_rectIcon.width) / 2;
  1486.                 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4;
  1487.             }
  1488.  
  1489.             if ( item->HasText() )
  1490.             {
  1491.                 if (m_gi->m_rectAll.width > spacing)
  1492.                     m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
  1493.                 else
  1494.                     m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2 + (spacing/2) - (m_gi->m_rectLabel.width/2);
  1495.                 m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height;
  1496.                 m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2;
  1497.                 m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2;
  1498.             }
  1499.             else // no text, highlight the icon
  1500.             {
  1501.                 m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4;
  1502.                 m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4;
  1503.             }
  1504.             break;
  1505.  
  1506.         case wxLC_LIST:
  1507.             m_gi->m_rectAll.x = x;
  1508.             m_gi->m_rectAll.y = y;
  1509.  
  1510.             m_gi->m_rectHighlight.x = m_gi->m_rectAll.x;
  1511.             m_gi->m_rectHighlight.y = m_gi->m_rectAll.y;
  1512.             m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2;
  1513.  
  1514.             if (item->HasImage())
  1515.             {
  1516.                 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2;
  1517.                 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2;
  1518.                 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 6 + m_gi->m_rectIcon.width;
  1519.             }
  1520.             else
  1521.             {
  1522.                 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
  1523.             }
  1524.             break;
  1525.  
  1526.         case wxLC_REPORT:
  1527.             wxFAIL_MSG( _T("unexpected call to SetPosition") );
  1528.             break;
  1529.  
  1530.         default:
  1531.             wxFAIL_MSG( _T("unknown mode") );
  1532.     }
  1533. }
  1534.  
  1535. void wxListLineData::InitItems( int num )
  1536. {
  1537.     for (int i = 0; i < num; i++)
  1538.         m_items.Append( new wxListItemData(m_owner) );
  1539. }
  1540.  
  1541. void wxListLineData::SetItem( int index, const wxListItem &info )
  1542. {
  1543.     wxListItemDataList::Node *node = m_items.Item( index );
  1544.     wxCHECK_RET( node, _T("invalid column index in SetItem") );
  1545.  
  1546.     wxListItemData *item = node->GetData();
  1547.     item->SetItem( info );
  1548. }
  1549.  
  1550. void wxListLineData::GetItem( int index, wxListItem &info )
  1551. {
  1552.     wxListItemDataList::Node *node = m_items.Item( index );
  1553.     if (node)
  1554.     {
  1555.         wxListItemData *item = node->GetData();
  1556.         item->GetItem( info );
  1557.     }
  1558. }
  1559.  
  1560. wxString wxListLineData::GetText(int index) const
  1561. {
  1562.     wxString s;
  1563.  
  1564.     wxListItemDataList::Node *node = m_items.Item( index );
  1565.     if (node)
  1566.     {
  1567.         wxListItemData *item = node->GetData();
  1568.         s = item->GetText();
  1569.     }
  1570.  
  1571.     return s;
  1572. }
  1573.  
  1574. void wxListLineData::SetText( int index, const wxString s )
  1575. {
  1576.     wxListItemDataList::Node *node = m_items.Item( index );
  1577.     if (node)
  1578.     {
  1579.         wxListItemData *item = node->GetData();
  1580.         item->SetText( s );
  1581.     }
  1582. }
  1583.  
  1584. void wxListLineData::SetImage( int index, int image )
  1585. {
  1586.     wxListItemDataList::Node *node = m_items.Item( index );
  1587.     wxCHECK_RET( node, _T("invalid column index in SetImage()") );
  1588.  
  1589.     wxListItemData *item = node->GetData();
  1590.     item->SetImage(image);
  1591. }
  1592.  
  1593. int wxListLineData::GetImage( int index ) const
  1594. {
  1595.     wxListItemDataList::Node *node = m_items.Item( index );
  1596.     wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") );
  1597.  
  1598.     wxListItemData *item = node->GetData();
  1599.     return item->GetImage();
  1600. }
  1601.  
  1602. wxListItemAttr *wxListLineData::GetAttr() const
  1603. {
  1604.     wxListItemDataList::Node *node = m_items.GetFirst();
  1605.     wxCHECK_MSG( node, NULL, _T("invalid column index in GetAttr()") );
  1606.  
  1607.     wxListItemData *item = node->GetData();
  1608.     return item->GetAttr();
  1609. }
  1610.  
  1611. void wxListLineData::SetAttr(wxListItemAttr *attr)
  1612. {
  1613.     wxListItemDataList::Node *node = m_items.GetFirst();
  1614.     wxCHECK_RET( node, _T("invalid column index in SetAttr()") );
  1615.  
  1616.     wxListItemData *item = node->GetData();
  1617.     item->SetAttr(attr);
  1618. }
  1619.  
  1620. bool wxListLineData::SetAttributes(wxDC *dc,
  1621.                                    const wxListItemAttr *attr,
  1622.                                    bool highlighted)
  1623. {
  1624.     wxWindow *listctrl = m_owner->GetParent();
  1625.  
  1626.     // fg colour
  1627.  
  1628.     // don't use foreground colour for drawing highlighted items - this might
  1629.     // make them completely invisible (and there is no way to do bit
  1630.     // arithmetics on wxColour, unfortunately)
  1631.     wxColour colText;
  1632.     if ( highlighted )
  1633.     {
  1634.         colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
  1635.     }
  1636.     else
  1637.     {
  1638.         if ( attr && attr->HasTextColour() )
  1639.         {
  1640.             colText = attr->GetTextColour();
  1641.         }
  1642.         else
  1643.         {
  1644.             colText = listctrl->GetForegroundColour();
  1645.         }
  1646.     }
  1647.  
  1648.     dc->SetTextForeground(colText);
  1649.  
  1650.     // font
  1651.     wxFont font;
  1652.     if ( attr && attr->HasFont() )
  1653.     {
  1654.         font = attr->GetFont();
  1655.     }
  1656.     else
  1657.     {
  1658.         font = listctrl->GetFont();
  1659.     }
  1660.  
  1661.     dc->SetFont(font);
  1662.  
  1663.     // bg colour
  1664.     bool hasBgCol = attr && attr->HasBackgroundColour();
  1665.     if ( highlighted || hasBgCol )
  1666.     {
  1667.         if ( highlighted )
  1668.         {
  1669.             dc->SetBrush( *m_owner->GetHighlightBrush() );
  1670.         }
  1671.         else
  1672.         {
  1673.             dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
  1674.         }
  1675.  
  1676.         dc->SetPen( *wxTRANSPARENT_PEN );
  1677.  
  1678.         return TRUE;
  1679.     }
  1680.  
  1681.     return FALSE;
  1682. }
  1683.  
  1684. void wxListLineData::Draw( wxDC *dc )
  1685. {
  1686.     wxListItemDataList::Node *node = m_items.GetFirst();
  1687.     wxCHECK_RET( node, _T("no subitems at all??") );
  1688.  
  1689.     bool highlighted = IsHighlighted();
  1690.  
  1691.     wxListItemAttr *attr = GetAttr();
  1692.  
  1693.     if ( SetAttributes(dc, attr, highlighted) )
  1694.     {
  1695.         dc->DrawRectangle( m_gi->m_rectHighlight );
  1696.     }
  1697.  
  1698.     wxListItemData *item = node->GetData();
  1699.     if (item->HasImage())
  1700.     {
  1701.         wxRect rectIcon = m_gi->m_rectIcon;
  1702.         m_owner->DrawImage( item->GetImage(), dc,
  1703.                             rectIcon.x, rectIcon.y );
  1704.     }
  1705.  
  1706.     if (item->HasText())
  1707.     {
  1708.         wxRect rectLabel = m_gi->m_rectLabel;
  1709.  
  1710.         wxDCClipper clipper(*dc, rectLabel);
  1711.         dc->DrawText( item->GetText(), rectLabel.x, rectLabel.y );
  1712.     }
  1713. }
  1714.  
  1715. void wxListLineData::DrawInReportMode( wxDC *dc,
  1716.                                        const wxRect& rect,
  1717.                                        const wxRect& rectHL,
  1718.                                        bool highlighted )
  1719. {
  1720.     // TODO: later we should support setting different attributes for
  1721.     //       different columns - to do it, just add "col" argument to
  1722.     //       GetAttr() and move these lines into the loop below
  1723.     wxListItemAttr *attr = GetAttr();
  1724.     if ( SetAttributes(dc, attr, highlighted) )
  1725.     {
  1726.         dc->DrawRectangle( rectHL );
  1727.     }
  1728.  
  1729.     wxCoord x = rect.x + HEADER_OFFSET_X,
  1730.             y = rect.y + (LINE_SPACING + EXTRA_HEIGHT) / 2;
  1731.  
  1732.     size_t col = 0;
  1733.     for ( wxListItemDataList::Node *node = m_items.GetFirst();
  1734.           node;
  1735.           node = node->GetNext(), col++ )
  1736.     {
  1737.         wxListItemData *item = node->GetData();
  1738.  
  1739.         int width = m_owner->GetColumnWidth(col);
  1740.         int xOld = x;
  1741.         x += width;
  1742.  
  1743.         if ( item->HasImage() )
  1744.         {
  1745.             int ix, iy;
  1746.             m_owner->DrawImage( item->GetImage(), dc, xOld, y );
  1747.             m_owner->GetImageSize( item->GetImage(), ix, iy );
  1748.  
  1749.             ix += IMAGE_MARGIN_IN_REPORT_MODE;
  1750.  
  1751.             xOld += ix;
  1752.             width -= ix;
  1753.         }
  1754.  
  1755.         wxDCClipper clipper(*dc, xOld, y, width - 8, rect.height);
  1756.  
  1757.         if ( item->HasText() )
  1758.         {
  1759.             DrawTextFormatted(dc, item->GetText(), col, xOld, y, width - 8);
  1760.         }
  1761.     }
  1762. }
  1763.  
  1764. void wxListLineData::DrawTextFormatted(wxDC *dc,
  1765.                                        const wxString &text,
  1766.                                        int col,
  1767.                                        int x,
  1768.                                        int y,
  1769.                                        int width)
  1770. {
  1771.     wxString drawntext, ellipsis;
  1772.     wxCoord w, h, base_w;
  1773.     wxListItem item;
  1774.  
  1775.     // determine if the string can fit inside the current width
  1776.     dc->GetTextExtent(text, &w, &h);
  1777.  
  1778.     // if it can, draw it
  1779.     if (w <= width)
  1780.     {
  1781.         m_owner->GetColumn(col, item);
  1782.         if (item.m_format == wxLIST_FORMAT_LEFT)
  1783.             dc->DrawText(text, x, y);
  1784.         else if (item.m_format == wxLIST_FORMAT_RIGHT)
  1785.             dc->DrawText(text, x + width - w, y);
  1786.         else if (item.m_format == wxLIST_FORMAT_CENTER)
  1787.             dc->DrawText(text, x + ((width - w) / 2), y);
  1788.     }
  1789.     else // otherwise, truncate and add an ellipsis if possible
  1790.     {
  1791.         // determine the base width
  1792.         ellipsis = wxString(wxT("..."));
  1793.         dc->GetTextExtent(ellipsis, &base_w, &h);
  1794.  
  1795.         // continue until we have enough space or only one character left
  1796.         drawntext = text.Left(text.Length() - 1);
  1797.         while (drawntext.Length() > 1)
  1798.         {
  1799.             dc->GetTextExtent(drawntext, &w, &h);
  1800.             if (w + base_w <= width)
  1801.                 break;
  1802.             drawntext = drawntext.Left(drawntext.Length() - 1);
  1803.         }
  1804.  
  1805.         // if still not enough space, remove ellipsis characters
  1806.         while (ellipsis.Length() > 0 && w + base_w > width)
  1807.         {
  1808.             ellipsis = ellipsis.Left(ellipsis.Length() - 1);
  1809.             dc->GetTextExtent(ellipsis, &base_w, &h);
  1810.         }
  1811.  
  1812.         // now draw the text
  1813.         dc->DrawText(drawntext, x, y);
  1814.         dc->DrawText(ellipsis, x + w, y);
  1815.     }
  1816. }
  1817.  
  1818. bool wxListLineData::Highlight( bool on )
  1819. {
  1820.     wxCHECK_MSG( !m_owner->IsVirtual(), FALSE, _T("unexpected call to Highlight") );
  1821.  
  1822.     if ( on == m_highlighted )
  1823.         return FALSE;
  1824.  
  1825.     m_highlighted = on;
  1826.  
  1827.     return TRUE;
  1828. }
  1829.  
  1830. void wxListLineData::ReverseHighlight( void )
  1831. {
  1832.     Highlight(!IsHighlighted());
  1833. }
  1834.  
  1835. //-----------------------------------------------------------------------------
  1836. //  wxListHeaderWindow
  1837. //-----------------------------------------------------------------------------
  1838.  
  1839. IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow)
  1840.  
  1841. BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
  1842.     EVT_PAINT         (wxListHeaderWindow::OnPaint)
  1843.     EVT_MOUSE_EVENTS  (wxListHeaderWindow::OnMouse)
  1844.     EVT_SET_FOCUS     (wxListHeaderWindow::OnSetFocus)
  1845. END_EVENT_TABLE()
  1846.  
  1847. void wxListHeaderWindow::Init()
  1848. {
  1849.     m_currentCursor = (wxCursor *) NULL;
  1850.     m_isDragging = FALSE;
  1851.     m_dirty = FALSE;
  1852. }
  1853.  
  1854. wxListHeaderWindow::wxListHeaderWindow()
  1855. {
  1856.     Init();
  1857.  
  1858.     m_owner = (wxListMainWindow *) NULL;
  1859.     m_resizeCursor = (wxCursor *) NULL;
  1860. }
  1861.  
  1862. wxListHeaderWindow::wxListHeaderWindow( wxWindow *win,
  1863.                                         wxWindowID id,
  1864.                                         wxListMainWindow *owner,
  1865.                                         const wxPoint& pos,
  1866.                                         const wxSize& size,
  1867.                                         long style,
  1868.                                         const wxString &name )
  1869.                   : wxWindow( win, id, pos, size, style, name )
  1870. {
  1871.     Init();
  1872.  
  1873.     m_owner = owner;
  1874.     m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
  1875.  
  1876.     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
  1877. }
  1878.  
  1879. wxListHeaderWindow::~wxListHeaderWindow()
  1880. {
  1881.     delete m_resizeCursor;
  1882. }
  1883.  
  1884. #ifdef __WXUNIVERSAL__
  1885. #include "wx/univ/renderer.h"
  1886. #include "wx/univ/theme.h"
  1887. #endif
  1888.  
  1889. void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
  1890. {
  1891. #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
  1892.     GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL
  1893.                                                : GTK_STATE_INSENSITIVE;
  1894.  
  1895.     x = dc->XLOG2DEV( x );
  1896.  
  1897.     gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window,
  1898.                    state, GTK_SHADOW_OUT,
  1899.                    (GdkRectangle*) NULL, m_wxwindow,
  1900.                    (char *)"button", // const_cast
  1901.                    x-1, y-1, w+2, h+2);
  1902. #elif defined(__WXUNIVERSAL__)
  1903.     wxTheme *theme = wxTheme::Get();
  1904.     wxRenderer *renderer = theme->GetRenderer();
  1905.     renderer->DrawBorder( *dc, wxBORDER_RAISED, wxRect(x,y,w,h), 0 );
  1906. #elif defined(__WXMAC__)
  1907.     const int m_corner = 1;
  1908.  
  1909.     dc->SetBrush( *wxTRANSPARENT_BRUSH );
  1910.  
  1911.     dc->SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
  1912.     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
  1913.     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
  1914.  
  1915.     wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
  1916.  
  1917.     dc->SetPen( pen );
  1918.     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
  1919.     dc->DrawRectangle( x+1, y+h-1, w-2, 1 );      // bottom (inner)
  1920.  
  1921.     dc->SetPen( *wxWHITE_PEN );
  1922.     dc->DrawRectangle( x, y, w-m_corner+1, 1 );   // top (outer)
  1923.     dc->DrawRectangle( x, y, 1, h );              // left (outer)
  1924.     dc->DrawLine( x, y+h-1, x+1, y+h-1 );
  1925.     dc->DrawLine( x+w-1, y, x+w-1, y+1 );
  1926. #else // !GTK, !Mac
  1927.     const int m_corner = 1;
  1928.  
  1929.     dc->SetBrush( *wxTRANSPARENT_BRUSH );
  1930.  
  1931.     dc->SetPen( *wxBLACK_PEN );
  1932.     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
  1933.     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
  1934.  
  1935.     wxPen pen( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
  1936.  
  1937.     dc->SetPen( pen );
  1938.     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
  1939.     dc->DrawRectangle( x+1, y+h-1, w-2, 1 );      // bottom (inner)
  1940.  
  1941.     dc->SetPen( *wxWHITE_PEN );
  1942.     dc->DrawRectangle( x, y, w-m_corner+1, 1 );   // top (outer)
  1943.     dc->DrawRectangle( x, y, 1, h );              // left (outer)
  1944.     dc->DrawLine( x, y+h-1, x+1, y+h-1 );
  1945.     dc->DrawLine( x+w-1, y, x+w-1, y+1 );
  1946. #endif
  1947. }
  1948.  
  1949. // shift the DC origin to match the position of the main window horz
  1950. // scrollbar: this allows us to always use logical coords
  1951. void wxListHeaderWindow::AdjustDC(wxDC& dc)
  1952. {
  1953.     int xpix;
  1954.     m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
  1955.  
  1956.     int x;
  1957.     m_owner->GetViewStart( &x, NULL );
  1958.  
  1959.     // account for the horz scrollbar offset
  1960.     dc.SetDeviceOrigin( -x * xpix, 0 );
  1961. }
  1962.  
  1963. void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
  1964. {
  1965. #if defined(__WXGTK__)
  1966.     wxClientDC dc( this );
  1967. #else
  1968.     wxPaintDC dc( this );
  1969. #endif
  1970.  
  1971.     PrepareDC( dc );
  1972.     AdjustDC( dc );
  1973.  
  1974.     dc.BeginDrawing();
  1975.  
  1976.     dc.SetFont( GetFont() );
  1977.  
  1978.     // width and height of the entire header window
  1979.     int w, h;
  1980.     GetClientSize( &w, &h );
  1981.     m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
  1982.  
  1983.     dc.SetBackgroundMode(wxTRANSPARENT);
  1984.  
  1985.     // do *not* use the listctrl colour for headers - one day we will have a
  1986.     // function to set it separately
  1987.     //dc.SetTextForeground( *wxBLACK );
  1988.     dc.SetTextForeground(wxSystemSettings::
  1989.                             GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
  1990.  
  1991.     int x = HEADER_OFFSET_X;
  1992.  
  1993.     int numColumns = m_owner->GetColumnCount();
  1994.     wxListItem item;
  1995.     for ( int i = 0; i < numColumns && x < w; i++ )
  1996.     {
  1997.         m_owner->GetColumn( i, item );
  1998.         int wCol = item.m_width;
  1999.  
  2000.         // the width of the rect to draw: make it smaller to fit entirely
  2001.         // inside the column rect
  2002.         int cw = wCol - 2;
  2003.  
  2004.         dc.SetPen( *wxWHITE_PEN );
  2005.  
  2006.         DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
  2007.  
  2008.         // if we have an image, draw it on the right of the label
  2009.         int image = item.m_image;
  2010.         if ( image != -1 )
  2011.         {
  2012.             wxImageListType *imageList = m_owner->m_small_image_list;
  2013.             if ( imageList )
  2014.             {
  2015.                 int ix, iy;
  2016.                 imageList->GetSize(image, ix, iy);
  2017.  
  2018.                 imageList->Draw
  2019.                            (
  2020.                             image,
  2021.                             dc,
  2022.                             x + cw - ix - 1,
  2023.                             HEADER_OFFSET_Y + (h - 4 - iy)/2,
  2024.                             wxIMAGELIST_DRAW_TRANSPARENT
  2025.                            );
  2026.  
  2027.                 cw -= ix + 2;
  2028.             }
  2029.             //else: ignore the column image
  2030.         }
  2031.  
  2032.         // draw the text clipping it so that it doesn't overwrite the column
  2033.         // boundary
  2034.         wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
  2035.  
  2036.         dc.DrawText( item.GetText(),
  2037.                      x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
  2038.  
  2039.         x += wCol;
  2040.     }
  2041.  
  2042.     dc.EndDrawing();
  2043. }
  2044.  
  2045. void wxListHeaderWindow::DrawCurrent()
  2046. {
  2047.     int x1 = m_currentX;
  2048.     int y1 = 0;
  2049.     m_owner->ClientToScreen( &x1, &y1 );
  2050.  
  2051.     int x2 = m_currentX;
  2052.     int y2 = 0;
  2053.     m_owner->GetClientSize( NULL, &y2 );
  2054.     m_owner->ClientToScreen( &x2, &y2 );
  2055.  
  2056.     wxScreenDC dc;
  2057.     dc.SetLogicalFunction( wxINVERT );
  2058.     dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) );
  2059.     dc.SetBrush( *wxTRANSPARENT_BRUSH );
  2060.  
  2061.     AdjustDC(dc);
  2062.  
  2063.     dc.DrawLine( x1, y1, x2, y2 );
  2064.  
  2065.     dc.SetLogicalFunction( wxCOPY );
  2066.  
  2067.     dc.SetPen( wxNullPen );
  2068.     dc.SetBrush( wxNullBrush );
  2069. }
  2070.  
  2071. void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
  2072. {
  2073.     // we want to work with logical coords
  2074.     int x;
  2075.     m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
  2076.     int y = event.GetY();
  2077.  
  2078.     if (m_isDragging)
  2079.     {
  2080.         SendListEvent(wxEVT_COMMAND_LIST_COL_DRAGGING,
  2081.                       event.GetPosition());
  2082.  
  2083.         // we don't draw the line beyond our window, but we allow dragging it
  2084.         // there
  2085.         int w = 0;
  2086.         GetClientSize( &w, NULL );
  2087.         m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
  2088.         w -= 6;
  2089.  
  2090.         // erase the line if it was drawn
  2091.         if ( m_currentX < w )
  2092.             DrawCurrent();
  2093.  
  2094.         if (event.ButtonUp())
  2095.         {
  2096.             ReleaseMouse();
  2097.             m_isDragging = FALSE;
  2098.             m_dirty = TRUE;
  2099.             m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
  2100.             SendListEvent(wxEVT_COMMAND_LIST_COL_END_DRAG,
  2101.                           event.GetPosition());
  2102.         }
  2103.         else
  2104.         {
  2105.             if (x > m_minX + 7)
  2106.                 m_currentX = x;
  2107.             else
  2108.                 m_currentX = m_minX + 7;
  2109.  
  2110.             // draw in the new location
  2111.             if ( m_currentX < w )
  2112.                 DrawCurrent();
  2113.         }
  2114.     }
  2115.     else // not dragging
  2116.     {
  2117.         m_minX = 0;
  2118.         bool hit_border = FALSE;
  2119.  
  2120.         // end of the current column
  2121.         int xpos = 0;
  2122.  
  2123.         // find the column where this event occured
  2124.         int col,
  2125.             countCol = m_owner->GetColumnCount();
  2126.         for (col = 0; col < countCol; col++)
  2127.         {
  2128.             xpos += m_owner->GetColumnWidth( col );
  2129.             m_column = col;
  2130.  
  2131.             if ( (abs(x-xpos) < 3) && (y < 22) )
  2132.             {
  2133.                 // near the column border
  2134.                 hit_border = TRUE;
  2135.                 break;
  2136.             }
  2137.  
  2138.             if ( x < xpos )
  2139.             {
  2140.                 // inside the column
  2141.                 break;
  2142.             }
  2143.  
  2144.             m_minX = xpos;
  2145.         }
  2146.  
  2147.         if ( col == countCol )
  2148.             m_column = -1;
  2149.  
  2150.         if (event.LeftDown() || event.RightUp())
  2151.         {
  2152.             if (hit_border && event.LeftDown())
  2153.             {
  2154.                 m_isDragging = TRUE;
  2155.                 m_currentX = x;
  2156.                 DrawCurrent();
  2157.                 CaptureMouse();
  2158.                 SendListEvent(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG,
  2159.                               event.GetPosition());
  2160.             }
  2161.             else // click on a column
  2162.             {
  2163.                 SendListEvent( event.LeftDown()
  2164.                                     ? wxEVT_COMMAND_LIST_COL_CLICK
  2165.                                     : wxEVT_COMMAND_LIST_COL_RIGHT_CLICK,
  2166.                                 event.GetPosition());
  2167.             }
  2168.         }
  2169.         else if (event.Moving())
  2170.         {
  2171.             bool setCursor;
  2172.             if (hit_border)
  2173.             {
  2174.                 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
  2175.                 m_currentCursor = m_resizeCursor;
  2176.             }
  2177.             else
  2178.             {
  2179.                 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
  2180.                 m_currentCursor = wxSTANDARD_CURSOR;
  2181.             }
  2182.  
  2183.             if ( setCursor )
  2184.                 SetCursor(*m_currentCursor);
  2185.         }
  2186.     }
  2187. }
  2188.  
  2189. void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
  2190. {
  2191.     m_owner->SetFocus();
  2192. }
  2193.  
  2194. void wxListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos)
  2195. {
  2196.     wxWindow *parent = GetParent();
  2197.     wxListEvent le( type, parent->GetId() );
  2198.     le.SetEventObject( parent );
  2199.     le.m_pointDrag = pos;
  2200.  
  2201.     // the position should be relative to the parent window, not
  2202.     // this one for compatibility with MSW and common sense: the
  2203.     // user code doesn't know anything at all about this header
  2204.     // window, so why should it get positions relative to it?
  2205.     le.m_pointDrag.y -= GetSize().y;
  2206.  
  2207.     le.m_col = m_column;
  2208.     parent->GetEventHandler()->ProcessEvent( le );
  2209. }
  2210.  
  2211. //-----------------------------------------------------------------------------
  2212. // wxListRenameTimer (internal)
  2213. //-----------------------------------------------------------------------------
  2214.  
  2215. wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner )
  2216. {
  2217.     m_owner = owner;
  2218. }
  2219.  
  2220. void wxListRenameTimer::Notify()
  2221. {
  2222.     m_owner->OnRenameTimer();
  2223. }
  2224.  
  2225. //-----------------------------------------------------------------------------
  2226. // wxListTextCtrl (internal)
  2227. //-----------------------------------------------------------------------------
  2228.  
  2229. BEGIN_EVENT_TABLE(wxListTextCtrl,wxTextCtrl)
  2230.     EVT_CHAR           (wxListTextCtrl::OnChar)
  2231.     EVT_KEY_UP         (wxListTextCtrl::OnKeyUp)
  2232.     EVT_KILL_FOCUS     (wxListTextCtrl::OnKillFocus)
  2233. END_EVENT_TABLE()
  2234.  
  2235. wxListTextCtrl::wxListTextCtrl(wxListMainWindow *owner, size_t itemEdit)
  2236.               : m_startValue(owner->GetItemText(itemEdit)),
  2237.                 m_itemEdited(itemEdit)
  2238. {
  2239.     m_owner = owner;
  2240.     m_finished = FALSE;
  2241.  
  2242.     wxRect rectLabel = owner->GetLineLabelRect(itemEdit);
  2243.  
  2244.     m_owner->CalcScrolledPosition(rectLabel.x, rectLabel.y,
  2245.                                   &rectLabel.x, &rectLabel.y);
  2246.  
  2247.     (void)Create(owner, wxID_ANY, m_startValue,
  2248.                  wxPoint(rectLabel.x-4,rectLabel.y-4),
  2249.                  wxSize(rectLabel.width+11,rectLabel.height+8));
  2250. }
  2251.  
  2252. void wxListTextCtrl::Finish()
  2253. {
  2254.     if ( !m_finished )
  2255.     {
  2256.         wxPendingDelete.Append(this);
  2257.  
  2258.         m_finished = TRUE;
  2259.  
  2260.         m_owner->SetFocus();
  2261.     }
  2262. }
  2263.  
  2264. bool wxListTextCtrl::AcceptChanges()
  2265. {
  2266.     const wxString value = GetValue();
  2267.  
  2268.     if ( value == m_startValue )
  2269.     {
  2270.         // nothing changed, always accept
  2271.         return TRUE;
  2272.     }
  2273.  
  2274.     if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
  2275.     {
  2276.         // vetoed by the user
  2277.         return FALSE;
  2278.     }
  2279.  
  2280.     // accepted, do rename the item
  2281.     m_owner->SetItemText(m_itemEdited, value);
  2282.  
  2283.     return TRUE;
  2284. }
  2285.  
  2286. void wxListTextCtrl::OnChar( wxKeyEvent &event )
  2287. {
  2288.     switch ( event.m_keyCode )
  2289.     {
  2290.         case WXK_RETURN:
  2291.             if ( !AcceptChanges() )
  2292.             {
  2293.                 // vetoed by the user code
  2294.                 break;
  2295.             }
  2296.             //else: fall through
  2297.  
  2298.         case WXK_ESCAPE:
  2299.             Finish();
  2300.             break;
  2301.  
  2302.         default:
  2303.             event.Skip();
  2304.     }
  2305. }
  2306.  
  2307. void wxListTextCtrl::OnKeyUp( wxKeyEvent &event )
  2308. {
  2309.     if (m_finished)
  2310.     {
  2311.         event.Skip();
  2312.         return;
  2313.     }
  2314.  
  2315.     // auto-grow the textctrl:
  2316.     wxSize parentSize = m_owner->GetSize();
  2317.     wxPoint myPos = GetPosition();
  2318.     wxSize mySize = GetSize();
  2319.     int sx, sy;
  2320.     GetTextExtent(GetValue() + _T("MM"), &sx, &sy);
  2321.     if (myPos.x + sx > parentSize.x)
  2322.         sx = parentSize.x - myPos.x;
  2323.     if (mySize.x > sx)
  2324.         sx = mySize.x;
  2325.     SetSize(sx, -1);
  2326.  
  2327.     event.Skip();
  2328. }
  2329.  
  2330. void wxListTextCtrl::OnKillFocus( wxFocusEvent &event )
  2331. {
  2332.     if ( !m_finished )
  2333.     {
  2334.         (void)AcceptChanges();
  2335.  
  2336.         Finish();
  2337.     }
  2338.  
  2339.     event.Skip();
  2340. }
  2341.  
  2342. //-----------------------------------------------------------------------------
  2343. //  wxListMainWindow
  2344. //-----------------------------------------------------------------------------
  2345.  
  2346. IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow)
  2347.  
  2348. BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
  2349.   EVT_PAINT          (wxListMainWindow::OnPaint)
  2350.   EVT_MOUSE_EVENTS   (wxListMainWindow::OnMouse)
  2351.   EVT_CHAR           (wxListMainWindow::OnChar)
  2352.   EVT_KEY_DOWN       (wxListMainWindow::OnKeyDown)
  2353.   EVT_SET_FOCUS      (wxListMainWindow::OnSetFocus)
  2354.   EVT_KILL_FOCUS     (wxListMainWindow::OnKillFocus)
  2355.   EVT_SCROLLWIN      (wxListMainWindow::OnScroll)
  2356. END_EVENT_TABLE()
  2357.  
  2358. void wxListMainWindow::Init()
  2359. {
  2360.     m_columns.DeleteContents( TRUE );
  2361.     m_dirty = TRUE;
  2362.     m_countVirt = 0;
  2363.     m_lineFrom =
  2364.     m_lineTo = (size_t)-1;
  2365.     m_linesPerPage = 0;
  2366.  
  2367.     m_headerWidth =
  2368.     m_lineHeight = 0;
  2369.  
  2370.     m_small_image_list = (wxImageListType *) NULL;
  2371.     m_normal_image_list = (wxImageListType *) NULL;
  2372.  
  2373.     m_small_spacing = 30;
  2374.     m_normal_spacing = 40;
  2375.  
  2376.     m_hasFocus = FALSE;
  2377.     m_dragCount = 0;
  2378.     m_isCreated = FALSE;
  2379.  
  2380.     m_lastOnSame = FALSE;
  2381.     m_renameTimer = new wxListRenameTimer( this );
  2382.  
  2383.     m_current =
  2384.     m_lineLastClicked =
  2385.     m_lineBeforeLastClicked = (size_t)-1;
  2386.  
  2387.     m_freezeCount = 0;
  2388. }
  2389.  
  2390. void wxListMainWindow::InitScrolling()
  2391. {
  2392.     if ( HasFlag(wxLC_REPORT) )
  2393.     {
  2394.         m_xScroll = SCROLL_UNIT_X;
  2395.         m_yScroll = SCROLL_UNIT_Y;
  2396.     }
  2397.     else
  2398.     {
  2399.         m_xScroll = SCROLL_UNIT_Y;
  2400.         m_yScroll = 0;
  2401.     }
  2402. }
  2403.  
  2404. wxListMainWindow::wxListMainWindow()
  2405. {
  2406.     Init();
  2407.  
  2408.     m_highlightBrush =
  2409.     m_highlightUnfocusedBrush = (wxBrush *) NULL;
  2410.  
  2411.     m_xScroll =
  2412.     m_yScroll = 0;
  2413. }
  2414.  
  2415. wxListMainWindow::wxListMainWindow( wxWindow *parent,
  2416.                                     wxWindowID id,
  2417.                                     const wxPoint& pos,
  2418.                                     const wxSize& size,
  2419.                                     long style,
  2420.                                     const wxString &name )
  2421.                 : wxScrolledWindow( parent, id, pos, size,
  2422.                                     style | wxHSCROLL | wxVSCROLL, name )
  2423. {
  2424.     Init();
  2425.  
  2426.     m_highlightBrush = new wxBrush
  2427.                            (
  2428.                             wxSystemSettings::GetColour
  2429.                             (
  2430.                                 wxSYS_COLOUR_HIGHLIGHT
  2431.                             ),
  2432.                             wxSOLID
  2433.                            );
  2434.  
  2435.     m_highlightUnfocusedBrush = new wxBrush
  2436.                                     (
  2437.                                        wxSystemSettings::GetColour
  2438.                                        (
  2439.                                            wxSYS_COLOUR_BTNSHADOW
  2440.                                        ),
  2441.                                        wxSOLID
  2442.                                     );
  2443.  
  2444.     wxSize sz = size;
  2445.     sz.y = 25;
  2446.  
  2447.     InitScrolling();
  2448.     SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
  2449.  
  2450.     SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) );
  2451. }
  2452.  
  2453. wxListMainWindow::~wxListMainWindow()
  2454. {
  2455.     DoDeleteAllItems();
  2456.  
  2457.     delete m_highlightBrush;
  2458.     delete m_highlightUnfocusedBrush;
  2459.  
  2460.     delete m_renameTimer;
  2461. }
  2462.  
  2463. void wxListMainWindow::CacheLineData(size_t line)
  2464. {
  2465.     wxGenericListCtrl *listctrl = GetListCtrl();
  2466.  
  2467.     wxListLineData *ld = GetDummyLine();
  2468.  
  2469.     size_t countCol = GetColumnCount();
  2470.     for ( size_t col = 0; col < countCol; col++ )
  2471.     {
  2472.         ld->SetText(col, listctrl->OnGetItemText(line, col));
  2473.     }
  2474.  
  2475.     ld->SetImage(listctrl->OnGetItemImage(line));
  2476.     ld->SetAttr(listctrl->OnGetItemAttr(line));
  2477. }
  2478.  
  2479. wxListLineData *wxListMainWindow::GetDummyLine() const
  2480. {
  2481.     wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
  2482.  
  2483.     wxASSERT_MSG( IsVirtual(), _T("GetDummyLine() shouldn't be called") );
  2484.  
  2485.     wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
  2486.  
  2487.     // we need to recreate the dummy line if the number of columns in the
  2488.     // control changed as it would have the incorrect number of fields
  2489.     // otherwise
  2490.     if ( !m_lines.IsEmpty() &&
  2491.             m_lines[0].m_items.GetCount() != (size_t)GetColumnCount() )
  2492.     {
  2493.         self->m_lines.Clear();
  2494.     }
  2495.  
  2496.     if ( m_lines.IsEmpty() )
  2497.     {
  2498.         wxListLineData *line = new wxListLineData(self);
  2499.         self->m_lines.Add(line);
  2500.  
  2501.         // don't waste extra memory -- there never going to be anything
  2502.         // else/more in this array
  2503.         self->m_lines.Shrink();
  2504.     }
  2505.  
  2506.     return &m_lines[0];
  2507. }
  2508.  
  2509. // ----------------------------------------------------------------------------
  2510. // line geometry (report mode only)
  2511. // ----------------------------------------------------------------------------
  2512.  
  2513. wxCoord wxListMainWindow::GetLineHeight() const
  2514. {
  2515.     wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
  2516.  
  2517.     // we cache the line height as calling GetTextExtent() is slow
  2518.     if ( !m_lineHeight )
  2519.     {
  2520.         wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
  2521.  
  2522.         wxClientDC dc( self );
  2523.         dc.SetFont( GetFont() );
  2524.  
  2525.         wxCoord y;
  2526.         dc.GetTextExtent(_T("H"), NULL, &y);
  2527.  
  2528.         if ( y < SCROLL_UNIT_Y )
  2529.             y = SCROLL_UNIT_Y;
  2530.         y += EXTRA_HEIGHT;
  2531.  
  2532.         self->m_lineHeight = y + LINE_SPACING;
  2533.     }
  2534.  
  2535.     return m_lineHeight;
  2536. }
  2537.  
  2538. wxCoord wxListMainWindow::GetLineY(size_t line) const
  2539. {
  2540.     wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
  2541.  
  2542.     return LINE_SPACING + line*GetLineHeight();
  2543. }
  2544.  
  2545. wxRect wxListMainWindow::GetLineRect(size_t line) const
  2546. {
  2547.     if ( !InReportView() )
  2548.         return GetLine(line)->m_gi->m_rectAll;
  2549.  
  2550.     wxRect rect;
  2551.     rect.x = HEADER_OFFSET_X;
  2552.     rect.y = GetLineY(line);
  2553.     rect.width = GetHeaderWidth();
  2554.     rect.height = GetLineHeight();
  2555.  
  2556.     return rect;
  2557. }
  2558.  
  2559. wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
  2560. {
  2561.     if ( !InReportView() )
  2562.         return GetLine(line)->m_gi->m_rectLabel;
  2563.  
  2564.     wxRect rect;
  2565.     rect.x = HEADER_OFFSET_X;
  2566.     rect.y = GetLineY(line);
  2567.     rect.width = GetColumnWidth(0);
  2568.     rect.height = GetLineHeight();
  2569.  
  2570.     return rect;
  2571. }
  2572.  
  2573. wxRect wxListMainWindow::GetLineIconRect(size_t line) const
  2574. {
  2575.     if ( !InReportView() )
  2576.         return GetLine(line)->m_gi->m_rectIcon;
  2577.  
  2578.     wxListLineData *ld = GetLine(line);
  2579.     wxASSERT_MSG( ld->HasImage(), _T("should have an image") );
  2580.  
  2581.     wxRect rect;
  2582.     rect.x = HEADER_OFFSET_X;
  2583.     rect.y = GetLineY(line);
  2584.     GetImageSize(ld->GetImage(), rect.width, rect.height);
  2585.  
  2586.     return rect;
  2587. }
  2588.  
  2589. wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const
  2590. {
  2591.     return InReportView() ? GetLineRect(line)
  2592.                           : GetLine(line)->m_gi->m_rectHighlight;
  2593. }
  2594.  
  2595. long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
  2596. {
  2597.     wxASSERT_MSG( line < GetItemCount(), _T("invalid line in HitTestLine") );
  2598.  
  2599.     wxListLineData *ld = GetLine(line);
  2600.  
  2601.     if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
  2602.         return wxLIST_HITTEST_ONITEMICON;
  2603.  
  2604.     // VS: Testing for "ld->HasText() || InReportView()" instead of
  2605.     //     "ld->HasText()" is needed to make empty lines in report view
  2606.     //     possible
  2607.     if ( ld->HasText() || InReportView() )
  2608.     {
  2609.         wxRect rect = InReportView() ? GetLineRect(line)
  2610.                                      : GetLineLabelRect(line);
  2611.  
  2612.         if ( rect.Inside(x, y) )
  2613.             return wxLIST_HITTEST_ONITEMLABEL;
  2614.     }
  2615.  
  2616.     return 0;
  2617. }
  2618.  
  2619. // ----------------------------------------------------------------------------
  2620. // highlight (selection) handling
  2621. // ----------------------------------------------------------------------------
  2622.  
  2623. bool wxListMainWindow::IsHighlighted(size_t line) const
  2624. {
  2625.     if ( IsVirtual() )
  2626.     {
  2627.         return m_selStore.IsSelected(line);
  2628.     }
  2629.     else // !virtual
  2630.     {
  2631.         wxListLineData *ld = GetLine(line);
  2632.         wxCHECK_MSG( ld, FALSE, _T("invalid index in IsHighlighted") );
  2633.  
  2634.         return ld->IsHighlighted();
  2635.     }
  2636. }
  2637.  
  2638. void wxListMainWindow::HighlightLines( size_t lineFrom,
  2639.                                        size_t lineTo,
  2640.                                        bool highlight )
  2641. {
  2642.     if ( IsVirtual() )
  2643.     {
  2644.         wxArrayInt linesChanged;
  2645.         if ( !m_selStore.SelectRange(lineFrom, lineTo, highlight,
  2646.                                      &linesChanged) )
  2647.         {
  2648.             // meny items changed state, refresh everything
  2649.             RefreshLines(lineFrom, lineTo);
  2650.         }
  2651.         else // only a few items changed state, refresh only them
  2652.         {
  2653.             size_t count = linesChanged.GetCount();
  2654.             for ( size_t n = 0; n < count; n++ )
  2655.             {
  2656.                 RefreshLine(linesChanged[n]);
  2657.             }
  2658.         }
  2659.     }
  2660.     else // iterate over all items in non report view
  2661.     {
  2662.         for ( size_t line = lineFrom; line <= lineTo; line++ )
  2663.         {
  2664.             if ( HighlightLine(line, highlight) )
  2665.             {
  2666.                 RefreshLine(line);
  2667.             }
  2668.         }
  2669.     }
  2670. }
  2671.  
  2672. bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
  2673. {
  2674.     bool changed;
  2675.  
  2676.     if ( IsVirtual() )
  2677.     {
  2678.         changed = m_selStore.SelectItem(line, highlight);
  2679.     }
  2680.     else // !virtual
  2681.     {
  2682.         wxListLineData *ld = GetLine(line);
  2683.         wxCHECK_MSG( ld, FALSE, _T("invalid index in HighlightLine") );
  2684.  
  2685.         changed = ld->Highlight(highlight);
  2686.     }
  2687.  
  2688.     if ( changed )
  2689.     {
  2690.         SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED
  2691.                                     : wxEVT_COMMAND_LIST_ITEM_DESELECTED );
  2692.     }
  2693.  
  2694.     return changed;
  2695. }
  2696.  
  2697. void wxListMainWindow::RefreshLine( size_t line )
  2698. {
  2699.     if ( HasFlag(wxLC_REPORT) )
  2700.     {
  2701.         size_t visibleFrom, visibleTo;
  2702.         GetVisibleLinesRange(&visibleFrom, &visibleTo);
  2703.  
  2704.         if ( line < visibleFrom || line > visibleTo )
  2705.             return;
  2706.     }
  2707.  
  2708.     wxRect rect = GetLineRect(line);
  2709.  
  2710.     CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  2711.     RefreshRect( rect );
  2712. }
  2713.  
  2714. void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
  2715. {
  2716.     // we suppose that they are ordered by caller
  2717.     wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") );
  2718.  
  2719.     wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") );
  2720.  
  2721.     if ( HasFlag(wxLC_REPORT) )
  2722.     {
  2723.         size_t visibleFrom, visibleTo;
  2724.         GetVisibleLinesRange(&visibleFrom, &visibleTo);
  2725.  
  2726.         if ( lineFrom < visibleFrom )
  2727.             lineFrom = visibleFrom;
  2728.         if ( lineTo > visibleTo )
  2729.             lineTo = visibleTo;
  2730.  
  2731.         wxRect rect;
  2732.         rect.x = 0;
  2733.         rect.y = GetLineY(lineFrom);
  2734.         rect.width = GetClientSize().x;
  2735.         rect.height = GetLineY(lineTo) - rect.y + GetLineHeight();
  2736.  
  2737.         CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  2738.         RefreshRect( rect );
  2739.     }
  2740.     else // !report
  2741.     {
  2742.         // TODO: this should be optimized...
  2743.         for ( size_t line = lineFrom; line <= lineTo; line++ )
  2744.         {
  2745.             RefreshLine(line);
  2746.         }
  2747.     }
  2748. }
  2749.  
  2750. void wxListMainWindow::RefreshAfter( size_t lineFrom )
  2751. {
  2752.     if ( HasFlag(wxLC_REPORT) )
  2753.     {
  2754.         size_t visibleFrom, visibleTo;
  2755.         GetVisibleLinesRange(&visibleFrom, &visibleTo);
  2756.  
  2757.         if ( lineFrom < visibleFrom )
  2758.             lineFrom = visibleFrom;
  2759.         else if ( lineFrom > visibleTo )
  2760.             return;
  2761.  
  2762.         wxRect rect;
  2763.         rect.x = 0;
  2764.         rect.y = GetLineY(lineFrom);
  2765.         CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
  2766.  
  2767.         wxSize size = GetClientSize();
  2768.         rect.width = size.x;
  2769.         // refresh till the bottom of the window
  2770.         rect.height = size.y - rect.y;
  2771.  
  2772.         RefreshRect( rect );
  2773.     }
  2774.     else // !report
  2775.     {
  2776.         // TODO: how to do it more efficiently?
  2777.         m_dirty = TRUE;
  2778.     }
  2779. }
  2780.  
  2781. void wxListMainWindow::RefreshSelected()
  2782. {
  2783.     if ( IsEmpty() )
  2784.         return;
  2785.  
  2786.     size_t from, to;
  2787.     if ( InReportView() )
  2788.     {
  2789.         GetVisibleLinesRange(&from, &to);
  2790.     }
  2791.     else // !virtual
  2792.     {
  2793.         from = 0;
  2794.         to = GetItemCount() - 1;
  2795.     }
  2796.  
  2797.     if ( HasCurrent() && m_current >= from && m_current <= to )
  2798.     {
  2799.         RefreshLine(m_current);
  2800.     }
  2801.  
  2802.     for ( size_t line = from; line <= to; line++ )
  2803.     {
  2804.         // NB: the test works as expected even if m_current == -1
  2805.         if ( line != m_current && IsHighlighted(line) )
  2806.         {
  2807.             RefreshLine(line);
  2808.         }
  2809.     }
  2810. }
  2811.  
  2812. void wxListMainWindow::Freeze()
  2813. {
  2814.     m_freezeCount++;
  2815. }
  2816.  
  2817. void wxListMainWindow::Thaw()
  2818. {
  2819.     wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen list control?") );
  2820.  
  2821.     if ( !--m_freezeCount )
  2822.     {
  2823.         Refresh();
  2824.     }
  2825. }
  2826.  
  2827. void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
  2828. {
  2829.     // Note: a wxPaintDC must be constructed even if no drawing is
  2830.     // done (a Windows requirement).
  2831.     wxPaintDC dc( this );
  2832.  
  2833.     if ( IsEmpty() || m_freezeCount )
  2834.     {
  2835.         // nothing to draw or not the moment to draw it
  2836.         return;
  2837.     }
  2838.  
  2839.     if ( m_dirty )
  2840.     {
  2841.         // delay the repainting until we calculate all the items positions
  2842.         return;
  2843.     }
  2844.  
  2845.     PrepareDC( dc );
  2846.  
  2847.     int dev_x, dev_y;
  2848.     CalcScrolledPosition( 0, 0, &dev_x, &dev_y );
  2849.  
  2850.     dc.BeginDrawing();
  2851.  
  2852.     dc.SetFont( GetFont() );
  2853.  
  2854.     if ( HasFlag(wxLC_REPORT) )
  2855.     {
  2856.         int lineHeight = GetLineHeight();
  2857.  
  2858.         size_t visibleFrom, visibleTo;
  2859.         GetVisibleLinesRange(&visibleFrom, &visibleTo);
  2860.  
  2861.         wxRect rectLine;
  2862.         wxCoord xOrig, yOrig;
  2863.         CalcUnscrolledPosition(0, 0, &xOrig, &yOrig);
  2864.  
  2865.         // tell the caller cache to cache the data
  2866.         if ( IsVirtual() )
  2867.         {
  2868.             wxListEvent evCache(wxEVT_COMMAND_LIST_CACHE_HINT,
  2869.                                 GetParent()->GetId());
  2870.             evCache.SetEventObject( GetParent() );
  2871.             evCache.m_oldItemIndex = visibleFrom;
  2872.             evCache.m_itemIndex = visibleTo;
  2873.             GetParent()->GetEventHandler()->ProcessEvent( evCache );
  2874.         }
  2875.  
  2876.         for ( size_t line = visibleFrom; line <= visibleTo; line++ )
  2877.         {
  2878.             rectLine = GetLineRect(line);
  2879.  
  2880.             if ( !IsExposed(rectLine.x - xOrig, rectLine.y - yOrig,
  2881.                             rectLine.width, rectLine.height) )
  2882.             {
  2883.                 // don't redraw unaffected lines to avoid flicker
  2884.                 continue;
  2885.             }
  2886.  
  2887.             GetLine(line)->DrawInReportMode( &dc,
  2888.                                              rectLine,
  2889.                                              GetLineHighlightRect(line),
  2890.                                              IsHighlighted(line) );
  2891.         }
  2892.  
  2893.         if ( HasFlag(wxLC_HRULES) )
  2894.         {
  2895.             wxPen pen(GetRuleColour(), 1, wxSOLID);
  2896.             wxSize clientSize = GetClientSize();
  2897.  
  2898.             // Don't draw the first one
  2899.             for ( size_t i = visibleFrom+1; i <= visibleTo; i++ )
  2900.             {
  2901.                 dc.SetPen(pen);
  2902.                 dc.SetBrush( *wxTRANSPARENT_BRUSH );
  2903.                 dc.DrawLine(0 - dev_x, i*lineHeight,
  2904.                             clientSize.x - dev_x, i*lineHeight);
  2905.             }
  2906.  
  2907.             // Draw last horizontal rule
  2908.             if ( visibleTo == GetItemCount() - 1 )
  2909.             {
  2910.                 dc.SetPen(pen);
  2911.                 dc.SetBrush( *wxTRANSPARENT_BRUSH );
  2912.                 dc.DrawLine(0 - dev_x, (m_lineTo+1)*lineHeight,
  2913.                             clientSize.x - dev_x , (m_lineTo+1)*lineHeight );
  2914.             }
  2915.         }
  2916.  
  2917.         // Draw vertical rules if required
  2918.         if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
  2919.         {
  2920.             wxPen pen(GetRuleColour(), 1, wxSOLID);
  2921.  
  2922.             int col = 0;
  2923.             wxRect firstItemRect;
  2924.             wxRect lastItemRect;
  2925.             GetItemRect(visibleFrom, firstItemRect);
  2926.             GetItemRect(visibleTo, lastItemRect);
  2927.             int x = firstItemRect.GetX();
  2928.             dc.SetPen(pen);
  2929.             dc.SetBrush(* wxTRANSPARENT_BRUSH);
  2930.             for (col = 0; col < GetColumnCount(); col++)
  2931.             {
  2932.                 int colWidth = GetColumnWidth(col);
  2933.                 x += colWidth;
  2934.                 dc.DrawLine(x - dev_x - 2, firstItemRect.GetY() - 1 - dev_y,
  2935.                             x - dev_x - 2, lastItemRect.GetBottom() + 1 - dev_y);
  2936.             }
  2937.         }
  2938.     }
  2939.     else // !report
  2940.     {
  2941.         size_t count = GetItemCount();
  2942.         for ( size_t i = 0; i < count; i++ )
  2943.         {
  2944.             GetLine(i)->Draw( &dc );
  2945.         }
  2946.     }
  2947.  
  2948.     if ( HasCurrent() )
  2949.     {
  2950.         // don't draw rect outline under Max if we already have the background
  2951.         // color but under other platforms only draw it if we do: it is a bit
  2952.         // silly to draw "focus rect" if we don't have focus!
  2953. #ifdef __WXMAC__
  2954.         if ( !m_hasFocus )
  2955. #else // !__WXMAC__
  2956.         if ( m_hasFocus )
  2957. #endif // __WXMAC__/!__WXMAC__
  2958.         {
  2959.             dc.SetPen( *wxBLACK_PEN );
  2960.             dc.SetBrush( *wxTRANSPARENT_BRUSH );
  2961.             dc.DrawRectangle( GetLineHighlightRect(m_current) );
  2962.         }
  2963.     }
  2964.  
  2965.     dc.EndDrawing();
  2966. }
  2967.  
  2968. void wxListMainWindow::HighlightAll( bool on )
  2969. {
  2970.     if ( IsSingleSel() )
  2971.     {
  2972.         wxASSERT_MSG( !on, _T("can't do this in a single sel control") );
  2973.  
  2974.         // we just have one item to turn off
  2975.         if ( HasCurrent() && IsHighlighted(m_current) )
  2976.         {
  2977.             HighlightLine(m_current, FALSE);
  2978.             RefreshLine(m_current);
  2979.         }
  2980.     }
  2981.     else // multi sel
  2982.     {
  2983.         HighlightLines(0, GetItemCount() - 1, on);
  2984.     }
  2985. }
  2986.  
  2987. void wxListMainWindow::SendNotify( size_t line,
  2988.                                    wxEventType command,
  2989.                                    wxPoint point )
  2990. {
  2991.     wxListEvent le( command, GetParent()->GetId() );
  2992.     le.SetEventObject( GetParent() );
  2993.     le.m_itemIndex = line;
  2994.  
  2995.     // set only for events which have position
  2996.     if ( point != wxDefaultPosition )
  2997.         le.m_pointDrag = point;
  2998.  
  2999.     // don't try to get the line info for virtual list controls: the main
  3000.     // program has it anyhow and if we did it would result in accessing all
  3001.     // the lines, even those which are not visible now and this is precisely
  3002.     // what we're trying to avoid
  3003.     if ( !IsVirtual() && (command != wxEVT_COMMAND_LIST_DELETE_ITEM) )
  3004.     {
  3005.         if ( line != (size_t)-1 )
  3006.         {
  3007.             GetLine(line)->GetItem( 0, le.m_item );
  3008.         }
  3009.         //else: this happens for wxEVT_COMMAND_LIST_ITEM_FOCUSED event
  3010.     }
  3011.     //else: there may be no more such item
  3012.  
  3013.     GetParent()->GetEventHandler()->ProcessEvent( le );
  3014. }
  3015.  
  3016. void wxListMainWindow::ChangeCurrent(size_t current)
  3017. {
  3018.     m_current = current;
  3019.  
  3020.     SendNotify(current, wxEVT_COMMAND_LIST_ITEM_FOCUSED);
  3021. }
  3022.  
  3023. void wxListMainWindow::EditLabel( long item )
  3024. {
  3025.     wxCHECK_RET( (item >= 0) && ((size_t)item < GetItemCount()),
  3026.                  wxT("wrong index in wxGenericListCtrl::EditLabel()") );
  3027.  
  3028.     size_t itemEdit = (size_t)item;
  3029.  
  3030.     wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
  3031.     le.SetEventObject( GetParent() );
  3032.     le.m_itemIndex = item;
  3033.     wxListLineData *data = GetLine(itemEdit);
  3034.     wxCHECK_RET( data, _T("invalid index in EditLabel()") );
  3035.     data->GetItem( 0, le.m_item );
  3036.     if ( GetParent()->GetEventHandler()->ProcessEvent( le ) && !le.IsAllowed() )
  3037.     {
  3038.         // vetoed by user code
  3039.         return;
  3040.     }
  3041.  
  3042.     // We have to call this here because the label in question might just have
  3043.     // been added and no screen update taken place.
  3044.     if ( m_dirty )
  3045.         wxSafeYield();
  3046.  
  3047.     wxListTextCtrl *text = new wxListTextCtrl(this, itemEdit);
  3048.  
  3049.     text->SetFocus();
  3050. }
  3051.  
  3052. void wxListMainWindow::OnRenameTimer()
  3053. {
  3054.     wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
  3055.  
  3056.     EditLabel( m_current );
  3057. }
  3058.  
  3059. bool wxListMainWindow::OnRenameAccept(size_t itemEdit, const wxString& value)
  3060. {
  3061.     wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
  3062.     le.SetEventObject( GetParent() );
  3063.     le.m_itemIndex = itemEdit;
  3064.  
  3065.     wxListLineData *data = GetLine(itemEdit);
  3066.     wxCHECK_MSG( data, FALSE, _T("invalid index in OnRenameAccept()") );
  3067.  
  3068.     data->GetItem( 0, le.m_item );
  3069.     le.m_item.m_text = value;
  3070.     return !GetParent()->GetEventHandler()->ProcessEvent( le ) ||
  3071.                 le.IsAllowed();
  3072. }
  3073.  
  3074. void wxListMainWindow::OnMouse( wxMouseEvent &event )
  3075. {
  3076.     event.SetEventObject( GetParent() );
  3077.     if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
  3078.         return;
  3079.  
  3080.     if ( !HasCurrent() || IsEmpty() )
  3081.         return;
  3082.  
  3083.     if (m_dirty)
  3084.         return;
  3085.  
  3086.     if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() ||
  3087.         event.ButtonDClick()) )
  3088.         return;
  3089.  
  3090.     int x = event.GetX();
  3091.     int y = event.GetY();
  3092.     CalcUnscrolledPosition( x, y, &x, &y );
  3093.  
  3094.     // where did we hit it (if we did)?
  3095.     long hitResult = 0;
  3096.  
  3097.     size_t count = GetItemCount(),
  3098.            current;
  3099.  
  3100.     if ( HasFlag(wxLC_REPORT) )
  3101.     {
  3102.         current = y / GetLineHeight();
  3103.         if ( current < count )
  3104.             hitResult = HitTestLine(current, x, y);
  3105.     }
  3106.     else // !report
  3107.     {
  3108.         // TODO: optimize it too! this is less simple than for report view but
  3109.         //       enumerating all items is still not a way to do it!!
  3110.         for ( current = 0; current < count; current++ )
  3111.         {
  3112.             hitResult = HitTestLine(current, x, y);
  3113.             if ( hitResult )
  3114.                 break;
  3115.         }
  3116.     }
  3117.  
  3118.     if (event.Dragging())
  3119.     {
  3120.         if (m_dragCount == 0)
  3121.         {
  3122.             // we have to report the raw, physical coords as we want to be
  3123.             // able to call HitTest(event.m_pointDrag) from the user code to
  3124.             // get the item being dragged
  3125.             m_dragStart = event.GetPosition();
  3126.         }
  3127.  
  3128.         m_dragCount++;
  3129.  
  3130.         if (m_dragCount != 3)
  3131.             return;
  3132.  
  3133.         int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
  3134.                                           : wxEVT_COMMAND_LIST_BEGIN_DRAG;
  3135.  
  3136.         wxListEvent le( command, GetParent()->GetId() );
  3137.         le.SetEventObject( GetParent() );
  3138.         le.m_pointDrag = m_dragStart;
  3139.         GetParent()->GetEventHandler()->ProcessEvent( le );
  3140.  
  3141.         return;
  3142.     }
  3143.     else
  3144.     {
  3145.         m_dragCount = 0;
  3146.     }
  3147.  
  3148.     if ( !hitResult )
  3149.     {
  3150.         // outside of any item
  3151.         return;
  3152.     }
  3153.  
  3154.     bool forceClick = FALSE;
  3155.     if (event.ButtonDClick())
  3156.     {
  3157.         m_renameTimer->Stop();
  3158.         m_lastOnSame = FALSE;
  3159.  
  3160.         if ( current == m_lineLastClicked )
  3161.         {
  3162.             SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
  3163.  
  3164.             return;
  3165.         }
  3166.         else
  3167.         {
  3168.             // the first click was on another item, so don't interpret this as
  3169.             // a double click, but as a simple click instead
  3170.             forceClick = TRUE;
  3171.         }
  3172.     }
  3173.  
  3174.     if (event.LeftUp() && m_lastOnSame)
  3175.     {
  3176.         if ((current == m_current) &&
  3177.             (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
  3178.             HasFlag(wxLC_EDIT_LABELS)  )
  3179.         {
  3180.             m_renameTimer->Start( 100, TRUE );
  3181.         }
  3182.         m_lastOnSame = FALSE;
  3183.     }
  3184.     else if (event.RightDown())
  3185.     {
  3186.         SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK,
  3187.                     event.GetPosition() );
  3188.     }
  3189.     else if (event.MiddleDown())
  3190.     {
  3191.         SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK );
  3192.     }
  3193.     else if ( event.LeftDown() || forceClick )
  3194.     {
  3195.         m_lineBeforeLastClicked = m_lineLastClicked;
  3196.         m_lineLastClicked = current;
  3197.  
  3198.         size_t oldCurrent = m_current;
  3199.  
  3200.         if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
  3201.         {
  3202.             HighlightAll( FALSE );
  3203.  
  3204.             ChangeCurrent(current);
  3205.  
  3206.             ReverseHighlight(m_current);
  3207.         }
  3208.         else // multi sel & either ctrl or shift is down
  3209.         {
  3210.             if (event.ControlDown())
  3211.             {
  3212.                 ChangeCurrent(current);
  3213.  
  3214.                 ReverseHighlight(m_current);
  3215.             }
  3216.             else if (event.ShiftDown())
  3217.             {
  3218.                 ChangeCurrent(current);
  3219.  
  3220.                 size_t lineFrom = oldCurrent,
  3221.                        lineTo = current;
  3222.  
  3223.                 if ( lineTo < lineFrom )
  3224.                 {
  3225.                     lineTo = lineFrom;
  3226.                     lineFrom = m_current;
  3227.                 }
  3228.  
  3229.                 HighlightLines(lineFrom, lineTo);
  3230.             }
  3231.             else // !ctrl, !shift
  3232.             {
  3233.                 // test in the enclosing if should make it impossible
  3234.                 wxFAIL_MSG( _T("how did we get here?") );
  3235.             }
  3236.         }
  3237.  
  3238.         if (m_current != oldCurrent)
  3239.         {
  3240.             RefreshLine( oldCurrent );
  3241.         }
  3242.  
  3243.         // forceClick is only set if the previous click was on another item
  3244.         m_lastOnSame = !forceClick && (m_current == oldCurrent);
  3245.     }
  3246. }
  3247.  
  3248. void wxListMainWindow::MoveToItem(size_t item)
  3249. {
  3250.     if ( item == (size_t)-1 )
  3251.         return;
  3252.  
  3253.     wxRect rect = GetLineRect(item);
  3254.  
  3255.     int client_w, client_h;
  3256.     GetClientSize( &client_w, &client_h );
  3257.  
  3258.     int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
  3259.     int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
  3260.  
  3261.     if ( HasFlag(wxLC_REPORT) )
  3262.     {
  3263.         // the next we need the range of lines shown it might be different, so
  3264.         // recalculate it
  3265.         ResetVisibleLinesRange();
  3266.  
  3267.         if (rect.y < view_y )
  3268.             Scroll( -1, rect.y/m_yScroll );
  3269.         if (rect.y+rect.height+5 > view_y+client_h)
  3270.             Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
  3271.     }
  3272.     else // !report
  3273.     {
  3274.         if (rect.x-view_x < 5)
  3275.             Scroll( (rect.x-5)/m_xScroll, -1 );
  3276.         if (rect.x+rect.width-5 > view_x+client_w)
  3277.             Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
  3278.     }
  3279. }
  3280.  
  3281. // ----------------------------------------------------------------------------
  3282. // keyboard handling
  3283. // ----------------------------------------------------------------------------
  3284.  
  3285. void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
  3286. {
  3287.     wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
  3288.                  _T("invalid item index in OnArrowChar()") );
  3289.  
  3290.     size_t oldCurrent = m_current;
  3291.  
  3292.     // in single selection we just ignore Shift as we can't select several
  3293.     // items anyhow
  3294.     if ( event.ShiftDown() && !IsSingleSel() )
  3295.     {
  3296.         ChangeCurrent(newCurrent);
  3297.  
  3298.         // select all the items between the old and the new one
  3299.         if ( oldCurrent > newCurrent )
  3300.         {
  3301.             newCurrent = oldCurrent;
  3302.             oldCurrent = m_current;
  3303.         }
  3304.  
  3305.         HighlightLines(oldCurrent, newCurrent);
  3306.     }
  3307.     else // !shift
  3308.     {
  3309.         // all previously selected items are unselected unless ctrl is held
  3310.         if ( !event.ControlDown() )
  3311.             HighlightAll(FALSE);
  3312.  
  3313.         ChangeCurrent(newCurrent);
  3314.  
  3315.         // refresh the old focus to remove it
  3316.         RefreshLine( oldCurrent );
  3317.  
  3318.         if ( !event.ControlDown() )
  3319.         {
  3320.             HighlightLine( m_current, TRUE );
  3321.         }
  3322.     }
  3323.  
  3324.     RefreshLine( m_current );
  3325.  
  3326.     MoveToFocus();
  3327. }
  3328.  
  3329. void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
  3330. {
  3331.     wxWindow *parent = GetParent();
  3332.  
  3333.     /* we propagate the key event up */
  3334.     wxKeyEvent ke( wxEVT_KEY_DOWN );
  3335.     ke.m_shiftDown = event.m_shiftDown;
  3336.     ke.m_controlDown = event.m_controlDown;
  3337.     ke.m_altDown = event.m_altDown;
  3338.     ke.m_metaDown = event.m_metaDown;
  3339.     ke.m_keyCode = event.m_keyCode;
  3340.     ke.m_x = event.m_x;
  3341.     ke.m_y = event.m_y;
  3342.     ke.SetEventObject( parent );
  3343.     if (parent->GetEventHandler()->ProcessEvent( ke )) return;
  3344.  
  3345.     event.Skip();
  3346. }
  3347.  
  3348. void wxListMainWindow::OnChar( wxKeyEvent &event )
  3349. {
  3350.     wxWindow *parent = GetParent();
  3351.  
  3352.     /* we send a list_key event up */
  3353.     if ( HasCurrent() )
  3354.     {
  3355.         wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
  3356.         le.m_itemIndex = m_current;
  3357.         GetLine(m_current)->GetItem( 0, le.m_item );
  3358.         le.m_code = (int)event.KeyCode();
  3359.         le.SetEventObject( parent );
  3360.         parent->GetEventHandler()->ProcessEvent( le );
  3361.     }
  3362.  
  3363.     /* we propagate the char event up */
  3364.     wxKeyEvent ke( wxEVT_CHAR );
  3365.     ke.m_shiftDown = event.m_shiftDown;
  3366.     ke.m_controlDown = event.m_controlDown;
  3367.     ke.m_altDown = event.m_altDown;
  3368.     ke.m_metaDown = event.m_metaDown;
  3369.     ke.m_keyCode = event.m_keyCode;
  3370.     ke.m_x = event.m_x;
  3371.     ke.m_y = event.m_y;
  3372.     ke.SetEventObject( parent );
  3373.     if (parent->GetEventHandler()->ProcessEvent( ke )) return;
  3374.  
  3375.     if (event.KeyCode() == WXK_TAB)
  3376.     {
  3377.         wxNavigationKeyEvent nevent;
  3378.         nevent.SetWindowChange( event.ControlDown() );
  3379.         nevent.SetDirection( !event.ShiftDown() );
  3380.         nevent.SetEventObject( GetParent()->GetParent() );
  3381.         nevent.SetCurrentFocus( m_parent );
  3382.         if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
  3383.             return;
  3384.     }
  3385.  
  3386.     /* no item -> nothing to do */
  3387.     if (!HasCurrent())
  3388.     {
  3389.         event.Skip();
  3390.         return;
  3391.     }
  3392.  
  3393.     switch (event.KeyCode())
  3394.     {
  3395.         case WXK_UP:
  3396.             if ( m_current > 0 )
  3397.                 OnArrowChar( m_current - 1, event );
  3398.             break;
  3399.  
  3400.         case WXK_DOWN:
  3401.             if ( m_current < (size_t)GetItemCount() - 1 )
  3402.                 OnArrowChar( m_current + 1, event );
  3403.             break;
  3404.  
  3405.         case WXK_END:
  3406.             if (!IsEmpty())
  3407.                 OnArrowChar( GetItemCount() - 1, event );
  3408.             break;
  3409.  
  3410.         case WXK_HOME:
  3411.             if (!IsEmpty())
  3412.                 OnArrowChar( 0, event );
  3413.             break;
  3414.  
  3415.         case WXK_PRIOR:
  3416.             {
  3417.                 int steps = 0;
  3418.                 if ( HasFlag(wxLC_REPORT) )
  3419.                 {
  3420.                     steps = m_linesPerPage - 1;
  3421.                 }
  3422.                 else
  3423.                 {
  3424.                     steps = m_current % m_linesPerPage;
  3425.                 }
  3426.  
  3427.                 int index = m_current - steps;
  3428.                 if (index < 0)
  3429.                     index = 0;
  3430.  
  3431.                 OnArrowChar( index, event );
  3432.             }
  3433.             break;
  3434.  
  3435.         case WXK_NEXT:
  3436.             {
  3437.                 int steps = 0;
  3438.                 if ( HasFlag(wxLC_REPORT) )
  3439.                 {
  3440.                     steps = m_linesPerPage - 1;
  3441.                 }
  3442.                 else
  3443.                 {
  3444.                     steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
  3445.                 }
  3446.  
  3447.                 size_t index = m_current + steps;
  3448.                 size_t count = GetItemCount();
  3449.                 if ( index >= count )
  3450.                     index = count - 1;
  3451.  
  3452.                 OnArrowChar( index, event );
  3453.             }
  3454.             break;
  3455.  
  3456.         case WXK_LEFT:
  3457.             if ( !HasFlag(wxLC_REPORT) )
  3458.             {
  3459.                 int index = m_current - m_linesPerPage;
  3460.                 if (index < 0)
  3461.                     index = 0;
  3462.  
  3463.                 OnArrowChar( index, event );
  3464.             }
  3465.             break;
  3466.  
  3467.         case WXK_RIGHT:
  3468.             if ( !HasFlag(wxLC_REPORT) )
  3469.             {
  3470.                 size_t index = m_current + m_linesPerPage;
  3471.  
  3472.                 size_t count = GetItemCount();
  3473.                 if ( index >= count )
  3474.                     index = count - 1;
  3475.  
  3476.                 OnArrowChar( index, event );
  3477.             }
  3478.             break;
  3479.  
  3480.         case WXK_SPACE:
  3481.             if ( IsSingleSel() )
  3482.             {
  3483.                 SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
  3484.  
  3485.                 if ( IsHighlighted(m_current) )
  3486.                 {
  3487.                     // don't unselect the item in single selection mode
  3488.                     break;
  3489.                 }
  3490.                 //else: select it in ReverseHighlight() below if unselected
  3491.             }
  3492.  
  3493.             ReverseHighlight(m_current);
  3494.             break;
  3495.  
  3496.         case WXK_RETURN:
  3497.         case WXK_EXECUTE:
  3498.             SendNotify( m_current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
  3499.             break;
  3500.  
  3501.         default:
  3502.             event.Skip();
  3503.     }
  3504. }
  3505.  
  3506. // ----------------------------------------------------------------------------
  3507. // focus handling
  3508. // ----------------------------------------------------------------------------
  3509.  
  3510. void wxListMainWindow::SetFocus()
  3511. {
  3512.     // VS: wxListMainWindow derives from wxPanel (via wxScrolledWindow) and wxPanel
  3513.     //     overrides SetFocus in such way that it does never change focus from
  3514.     //     panel's child to the panel itself. Unfortunately, we must be able to change
  3515.     //     focus to the panel from wxListTextCtrl because the text control should
  3516.     //     disappear when the user clicks outside it.
  3517.  
  3518.     wxWindow *oldFocus = FindFocus();
  3519.  
  3520.     if ( oldFocus && oldFocus->GetParent() == this )
  3521.     {
  3522.         wxWindow::SetFocus();
  3523.     }
  3524.     else
  3525.     {
  3526.         wxScrolledWindow::SetFocus();
  3527.     }
  3528. }
  3529.  
  3530. void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
  3531. {
  3532.     // wxGTK sends us EVT_SET_FOCUS events even if we had never got
  3533.     // EVT_KILL_FOCUS before which means that we finish by redrawing the items
  3534.     // which are already drawn correctly resulting in horrible flicker - avoid
  3535.     // it
  3536.     if ( !m_hasFocus )
  3537.     {
  3538.         m_hasFocus = TRUE;
  3539.  
  3540.         RefreshSelected();
  3541.     }
  3542.  
  3543.     if ( !GetParent() )
  3544.         return;
  3545.  
  3546.     wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
  3547.     event.SetEventObject( GetParent() );
  3548.     GetParent()->GetEventHandler()->ProcessEvent( event );
  3549. }
  3550.  
  3551. void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
  3552. {
  3553.     m_hasFocus = FALSE;
  3554.  
  3555.     RefreshSelected();
  3556. }
  3557.  
  3558. void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
  3559. {
  3560.     if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
  3561.     {
  3562.         m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
  3563.     }
  3564.     else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
  3565.     {
  3566.         m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
  3567.     }
  3568.     else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
  3569.     {
  3570.         m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
  3571.     }
  3572.     else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
  3573.     {
  3574.         m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
  3575.     }
  3576. }
  3577.  
  3578. void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
  3579. {
  3580.     if ( HasFlag(wxLC_ICON) && m_normal_image_list )
  3581.     {
  3582.         m_normal_image_list->GetSize( index, width, height );
  3583.     }
  3584.     else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
  3585.     {
  3586.         m_small_image_list->GetSize( index, width, height );
  3587.     }
  3588.     else if ( HasFlag(wxLC_LIST) && m_small_image_list )
  3589.     {
  3590.         m_small_image_list->GetSize( index, width, height );
  3591.     }
  3592.     else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
  3593.     {
  3594.         m_small_image_list->GetSize( index, width, height );
  3595.     }
  3596.     else
  3597.     {
  3598.         width =
  3599.         height = 0;
  3600.     }
  3601. }
  3602.  
  3603. int wxListMainWindow::GetTextLength( const wxString &s ) const
  3604. {
  3605.     wxClientDC dc( wxConstCast(this, wxListMainWindow) );
  3606.     dc.SetFont( GetFont() );
  3607.  
  3608.     wxCoord lw;
  3609.     dc.GetTextExtent( s, &lw, NULL );
  3610.  
  3611.     return lw + AUTOSIZE_COL_MARGIN;
  3612. }
  3613.  
  3614. void wxListMainWindow::SetImageList( wxImageListType *imageList, int which )
  3615. {
  3616.     m_dirty = TRUE;
  3617.  
  3618.     // calc the spacing from the icon size
  3619.     int width = 0,
  3620.         height = 0;
  3621.     if ((imageList) && (imageList->GetImageCount()) )
  3622.     {
  3623.         imageList->GetSize(0, width, height);
  3624.     }
  3625.  
  3626.     if (which == wxIMAGE_LIST_NORMAL)
  3627.     {
  3628.         m_normal_image_list = imageList;
  3629.         m_normal_spacing = width + 8;
  3630.     }
  3631.  
  3632.     if (which == wxIMAGE_LIST_SMALL)
  3633.     {
  3634.         m_small_image_list = imageList;
  3635.         m_small_spacing = width + 14;
  3636.     }
  3637. }
  3638.  
  3639. void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall )
  3640. {
  3641.     m_dirty = TRUE;
  3642.     if (isSmall)
  3643.     {
  3644.         m_small_spacing = spacing;
  3645.     }
  3646.     else
  3647.     {
  3648.         m_normal_spacing = spacing;
  3649.     }
  3650. }
  3651.  
  3652. int wxListMainWindow::GetItemSpacing( bool isSmall )
  3653. {
  3654.     return isSmall ? m_small_spacing : m_normal_spacing;
  3655. }
  3656.  
  3657. // ----------------------------------------------------------------------------
  3658. // columns
  3659. // ----------------------------------------------------------------------------
  3660.  
  3661. void wxListMainWindow::SetColumn( int col, wxListItem &item )
  3662. {
  3663.     wxListHeaderDataList::Node *node = m_columns.Item( col );
  3664.  
  3665.     wxCHECK_RET( node, _T("invalid column index in SetColumn") );
  3666.  
  3667.     if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER )
  3668.         item.m_width = GetTextLength( item.m_text );
  3669.  
  3670.     wxListHeaderData *column = node->GetData();
  3671.     column->SetItem( item );
  3672.  
  3673.     wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
  3674.     if ( headerWin )
  3675.         headerWin->m_dirty = TRUE;
  3676.  
  3677.     m_dirty = TRUE;
  3678.  
  3679.     // invalidate it as it has to be recalculated
  3680.     m_headerWidth = 0;
  3681. }
  3682.  
  3683. void wxListMainWindow::SetColumnWidth( int col, int width )
  3684. {
  3685.     wxCHECK_RET( col >= 0 && col < GetColumnCount(),
  3686.                  _T("invalid column index") );
  3687.  
  3688.     wxCHECK_RET( HasFlag(wxLC_REPORT),
  3689.                  _T("SetColumnWidth() can only be called in report mode.") );
  3690.  
  3691.     m_dirty = TRUE;
  3692.     wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
  3693.     if ( headerWin )
  3694.         headerWin->m_dirty = TRUE;
  3695.  
  3696.     wxListHeaderDataList::Node *node = m_columns.Item( col );
  3697.     wxCHECK_RET( node, _T("no column?") );
  3698.  
  3699.     wxListHeaderData *column = node->GetData();
  3700.  
  3701.     size_t count = GetItemCount();
  3702.  
  3703.     if (width == wxLIST_AUTOSIZE_USEHEADER)
  3704.     {
  3705.         width = GetTextLength(column->GetText());
  3706.     }
  3707.     else if ( width == wxLIST_AUTOSIZE )
  3708.     {
  3709.         if ( IsVirtual() )
  3710.         {
  3711.             // TODO: determine the max width somehow...
  3712.             width = WIDTH_COL_DEFAULT;
  3713.         }
  3714.         else // !virtual
  3715.         {
  3716.             wxClientDC dc(this);
  3717.             dc.SetFont( GetFont() );
  3718.  
  3719.             int max = AUTOSIZE_COL_MARGIN;
  3720.  
  3721.             for ( size_t i = 0; i < count; i++ )
  3722.             {
  3723.                 wxListLineData *line = GetLine(i);
  3724.                 wxListItemDataList::Node *n = line->m_items.Item( col );
  3725.  
  3726.                 wxCHECK_RET( n, _T("no subitem?") );
  3727.  
  3728.                 wxListItemData *item = n->GetData();
  3729.                 int current = 0;
  3730.  
  3731.                 if (item->HasImage())
  3732.                 {
  3733.                     int ix, iy;
  3734.                     GetImageSize( item->GetImage(), ix, iy );
  3735.                     current += ix + 5;
  3736.                 }
  3737.  
  3738.                 if (item->HasText())
  3739.                 {
  3740.                     wxCoord w;
  3741.                     dc.GetTextExtent( item->GetText(), &w, NULL );
  3742.                     current += w;
  3743.                 }
  3744.  
  3745.                 if (current > max)
  3746.                     max = current;
  3747.             }
  3748.  
  3749.             width = max + AUTOSIZE_COL_MARGIN;
  3750.         }
  3751.     }
  3752.  
  3753.     column->SetWidth( width );
  3754.  
  3755.     // invalidate it as it has to be recalculated
  3756.     m_headerWidth = 0;
  3757. }
  3758.  
  3759. int wxListMainWindow::GetHeaderWidth() const
  3760. {
  3761.     if ( !m_headerWidth )
  3762.     {
  3763.         wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
  3764.  
  3765.         size_t count = GetColumnCount();
  3766.         for ( size_t col = 0; col < count; col++ )
  3767.         {
  3768.             self->m_headerWidth += GetColumnWidth(col);
  3769.         }
  3770.     }
  3771.  
  3772.     return m_headerWidth;
  3773. }
  3774.  
  3775. void wxListMainWindow::GetColumn( int col, wxListItem &item ) const
  3776. {
  3777.     wxListHeaderDataList::Node *node = m_columns.Item( col );
  3778.     wxCHECK_RET( node, _T("invalid column index in GetColumn") );
  3779.  
  3780.     wxListHeaderData *column = node->GetData();
  3781.     column->GetItem( item );
  3782. }
  3783.  
  3784. int wxListMainWindow::GetColumnWidth( int col ) const
  3785. {
  3786.     wxListHeaderDataList::Node *node = m_columns.Item( col );
  3787.     wxCHECK_MSG( node, 0, _T("invalid column index") );
  3788.  
  3789.     wxListHeaderData *column = node->GetData();
  3790.     return column->GetWidth();
  3791. }
  3792.  
  3793. // ----------------------------------------------------------------------------
  3794. // item state
  3795. // ----------------------------------------------------------------------------
  3796.  
  3797. void wxListMainWindow::SetItem( wxListItem &item )
  3798. {
  3799.     long id = item.m_itemId;
  3800.     wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(),
  3801.                  _T("invalid item index in SetItem") );
  3802.  
  3803.     if ( !IsVirtual() )
  3804.     {
  3805.         wxListLineData *line = GetLine((size_t)id);
  3806.         line->SetItem( item.m_col, item );
  3807.     }
  3808.  
  3809.     if ( InReportView() )
  3810.     {
  3811.         // just refresh the line to show the new value of the text/image
  3812.         RefreshLine((size_t)id);
  3813.     }
  3814.     else // !report
  3815.     {
  3816.         // refresh everything (resulting in horrible flicker - FIXME!)
  3817.         m_dirty = TRUE;
  3818.     }
  3819. }
  3820.  
  3821. void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
  3822. {
  3823.      wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(),
  3824.                   _T("invalid list ctrl item index in SetItem") );
  3825.  
  3826.     size_t oldCurrent = m_current;
  3827.     size_t item = (size_t)litem;    // safe because of the check above
  3828.  
  3829.     // do we need to change the focus?
  3830.     if ( stateMask & wxLIST_STATE_FOCUSED )
  3831.     {
  3832.         if ( state & wxLIST_STATE_FOCUSED )
  3833.         {
  3834.             // don't do anything if this item is already focused
  3835.             if ( item != m_current )
  3836.             {
  3837.                 ChangeCurrent(item);
  3838.  
  3839.                 if ( oldCurrent != (size_t)-1 )
  3840.                 {
  3841.                     if ( IsSingleSel() )
  3842.                     {
  3843.                         HighlightLine(oldCurrent, FALSE);
  3844.                     }
  3845.  
  3846.                     RefreshLine(oldCurrent);
  3847.                 }
  3848.  
  3849.                 RefreshLine( m_current );
  3850.             }
  3851.         }
  3852.         else // unfocus
  3853.         {
  3854.             // don't do anything if this item is not focused
  3855.             if ( item == m_current )
  3856.             {
  3857.                 ResetCurrent();
  3858.  
  3859.                 if ( IsSingleSel() )
  3860.                 {
  3861.                     // we must unselect the old current item as well or we
  3862.                     // might end up with more than one selected item in a
  3863.                     // single selection control
  3864.                     HighlightLine(oldCurrent, FALSE);
  3865.                 }
  3866.  
  3867.                 RefreshLine( oldCurrent );
  3868.             }
  3869.         }
  3870.     }
  3871.  
  3872.     // do we need to change the selection state?
  3873.     if ( stateMask & wxLIST_STATE_SELECTED )
  3874.     {
  3875.         bool on = (state & wxLIST_STATE_SELECTED) != 0;
  3876.  
  3877.         if ( IsSingleSel() )
  3878.         {
  3879.             if ( on )
  3880.             {
  3881.                 // selecting the item also makes it the focused one in the
  3882.                 // single sel mode
  3883.                 if ( m_current != item )
  3884.                 {
  3885.                     ChangeCurrent(item);
  3886.  
  3887.                     if ( oldCurrent != (size_t)-1 )
  3888.                     {
  3889.                         HighlightLine( oldCurrent, FALSE );
  3890.                         RefreshLine( oldCurrent );
  3891.                     }
  3892.                 }
  3893.             }
  3894.             else // off
  3895.             {
  3896.                 // only the current item may be selected anyhow
  3897.                 if ( item != m_current )
  3898.                     return;
  3899.             }
  3900.         }
  3901.  
  3902.         if ( HighlightLine(item, on) )
  3903.         {
  3904.             RefreshLine(item);
  3905.         }
  3906.     }
  3907. }
  3908.  
  3909. int wxListMainWindow::GetItemState( long item, long stateMask ) const
  3910. {
  3911.     wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0,
  3912.                  _T("invalid list ctrl item index in GetItemState()") );
  3913.  
  3914.     int ret = wxLIST_STATE_DONTCARE;
  3915.  
  3916.     if ( stateMask & wxLIST_STATE_FOCUSED )
  3917.     {
  3918.         if ( (size_t)item == m_current )
  3919.             ret |= wxLIST_STATE_FOCUSED;
  3920.     }
  3921.  
  3922.     if ( stateMask & wxLIST_STATE_SELECTED )
  3923.     {
  3924.         if ( IsHighlighted(item) )
  3925.             ret |= wxLIST_STATE_SELECTED;
  3926.     }
  3927.  
  3928.     return ret;
  3929. }
  3930.  
  3931. void wxListMainWindow::GetItem( wxListItem &item ) const
  3932. {
  3933.     wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(),
  3934.                  _T("invalid item index in GetItem") );
  3935.  
  3936.     wxListLineData *line = GetLine((size_t)item.m_itemId);
  3937.     line->GetItem( item.m_col, item );
  3938. }
  3939.  
  3940. // ----------------------------------------------------------------------------
  3941. // item count
  3942. // ----------------------------------------------------------------------------
  3943.  
  3944. size_t wxListMainWindow::GetItemCount() const
  3945. {
  3946.     return IsVirtual() ? m_countVirt : m_lines.GetCount();
  3947. }
  3948.  
  3949. void wxListMainWindow::SetItemCount(long count)
  3950. {
  3951.     m_selStore.SetItemCount(count);
  3952.     m_countVirt = count;
  3953.  
  3954.     ResetVisibleLinesRange();
  3955.  
  3956.     // scrollbars must be reset
  3957.     m_dirty = TRUE;
  3958. }
  3959.  
  3960. int wxListMainWindow::GetSelectedItemCount() const
  3961. {
  3962.     // deal with the quick case first
  3963.     if ( IsSingleSel() )
  3964.     {
  3965.         return HasCurrent() ? IsHighlighted(m_current) : FALSE;
  3966.     }
  3967.  
  3968.     // virtual controls remmebers all its selections itself
  3969.     if ( IsVirtual() )
  3970.         return m_selStore.GetSelectedCount();
  3971.  
  3972.     // TODO: we probably should maintain the number of items selected even for
  3973.     //       non virtual controls as enumerating all lines is really slow...
  3974.     size_t countSel = 0;
  3975.     size_t count = GetItemCount();
  3976.     for ( size_t line = 0; line < count; line++ )
  3977.     {
  3978.         if ( GetLine(line)->IsHighlighted() )
  3979.             countSel++;
  3980.     }
  3981.  
  3982.     return countSel;
  3983. }
  3984.  
  3985. // ----------------------------------------------------------------------------
  3986. // item position/size
  3987. // ----------------------------------------------------------------------------
  3988.  
  3989. void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const
  3990. {
  3991.     wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
  3992.                  _T("invalid index in GetItemRect") );
  3993.  
  3994.     rect = GetLineRect((size_t)index);
  3995.  
  3996.     CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
  3997. }
  3998.  
  3999. bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos) const
  4000. {
  4001.     wxRect rect;
  4002.     GetItemRect(item, rect);
  4003.  
  4004.     pos.x = rect.x;
  4005.     pos.y = rect.y;
  4006.  
  4007.     return TRUE;
  4008. }
  4009.  
  4010. // ----------------------------------------------------------------------------
  4011. // geometry calculation
  4012. // ----------------------------------------------------------------------------
  4013.  
  4014. void wxListMainWindow::RecalculatePositions(bool noRefresh)
  4015. {
  4016.     wxClientDC dc( this );
  4017.     dc.SetFont( GetFont() );
  4018.  
  4019.     int iconSpacing;
  4020.     if ( HasFlag(wxLC_ICON) )
  4021.         iconSpacing = m_normal_spacing;
  4022.     else if ( HasFlag(wxLC_SMALL_ICON) )
  4023.         iconSpacing = m_small_spacing;
  4024.     else
  4025.         iconSpacing = 0;
  4026.  
  4027.     // Note that we do not call GetClientSize() here but
  4028.     // GetSize() and substract the border size for sunken
  4029.     // borders manually. This is technically incorrect,
  4030.     // but we need to know the client area's size WITHOUT
  4031.     // scrollbars here. Since we don't know if there are
  4032.     // any scrollbars, we use GetSize() instead. Another
  4033.     // solution would be to call SetScrollbars() here to
  4034.     // remove the scrollbars and call GetClientSize() then,
  4035.     // but this might result in flicker and - worse - will
  4036.     // reset the scrollbars to 0 which is not good at all
  4037.     // if you resize a dialog/window, but don't want to
  4038.     // reset the window scrolling. RR.
  4039.     // Furthermore, we actually do NOT subtract the border
  4040.     // width as 2 pixels is just the extra space which we
  4041.     // need around the actual content in the window. Other-
  4042.     // wise the text would e.g. touch the upper border. RR.
  4043.     int clientWidth,
  4044.         clientHeight;
  4045.     GetSize( &clientWidth, &clientHeight );
  4046.  
  4047.     if ( HasFlag(wxLC_REPORT) )
  4048.     {
  4049.         // all lines have the same height
  4050.         int lineHeight = GetLineHeight();
  4051.  
  4052.         // scroll one line per step
  4053.         m_yScroll = lineHeight;
  4054.  
  4055.         size_t lineCount = GetItemCount();
  4056.         int entireHeight = lineCount*lineHeight + LINE_SPACING;
  4057.  
  4058.         m_linesPerPage = clientHeight / lineHeight;
  4059.  
  4060.         ResetVisibleLinesRange();
  4061.  
  4062.         SetScrollbars( m_xScroll, m_yScroll,
  4063.                        GetHeaderWidth() / m_xScroll,
  4064.                        (entireHeight + m_yScroll - 1)/m_yScroll,
  4065.                        GetScrollPos(wxHORIZONTAL),
  4066.                        GetScrollPos(wxVERTICAL),
  4067.                        TRUE );
  4068.     }
  4069.     else // !report
  4070.     {
  4071.         // at first we try without any scrollbar. if the items don't
  4072.         // fit into the window, we recalculate after subtracting an
  4073.         // approximated 15 pt for the horizontal scrollbar
  4074.  
  4075.         int entireWidth = 0;
  4076.  
  4077.         for (int tries = 0; tries < 2; tries++)
  4078.         {
  4079.             // We start with 4 for the border around all items
  4080.             entireWidth = 4;
  4081.  
  4082.             if (tries == 1)
  4083.             {
  4084.                 // Now we have decided that the items do not fit into the
  4085.                 // client area. Unfortunately, wxWindows sometimes thinks
  4086.                 // that it does fit and therefore NO horizontal scrollbar
  4087.                 // is inserted. This looks ugly, so we fudge here and make
  4088.                 // the calculated width bigger than was actually has been
  4089.                 // calculated. This ensures that wxScrolledWindows puts
  4090.                 // a scrollbar at the bottom of its client area.
  4091.                 entireWidth += SCROLL_UNIT_X;
  4092.             }
  4093.  
  4094.             // Start at 2,2 so the text does not touch the border
  4095.             int x = 2;
  4096.             int y = 2;
  4097.             int maxWidth = 0;
  4098.             m_linesPerPage = 0;
  4099.             int currentlyVisibleLines = 0;
  4100.  
  4101.             size_t count = GetItemCount();
  4102.             for (size_t i = 0; i < count; i++)
  4103.             {
  4104.                 currentlyVisibleLines++;
  4105.                 wxListLineData *line = GetLine(i);
  4106.                 line->CalculateSize( &dc, iconSpacing );
  4107.                 line->SetPosition( x, y, clientWidth, iconSpacing );  // Why clientWidth? (FIXME)
  4108.  
  4109.                 wxSize sizeLine = GetLineSize(i);
  4110.  
  4111.                 if ( maxWidth < sizeLine.x )
  4112.                     maxWidth = sizeLine.x;
  4113.  
  4114.                 y += sizeLine.y;
  4115.                 if (currentlyVisibleLines > m_linesPerPage)
  4116.                     m_linesPerPage = currentlyVisibleLines;
  4117.  
  4118.                 // Assume that the size of the next one is the same... (FIXME)
  4119.                 if ( y + sizeLine.y >= clientHeight )
  4120.                 {
  4121.                     currentlyVisibleLines = 0;
  4122.                     y = 2;
  4123.                     x += maxWidth+6;
  4124.                     entireWidth += maxWidth+6;
  4125.                     maxWidth = 0;
  4126.                 }
  4127.  
  4128.                 // We have reached the last item.
  4129.                 if ( i == count - 1 )
  4130.                     entireWidth += maxWidth;
  4131.  
  4132.                 if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) )
  4133.                 {
  4134.                     clientHeight -= 15; // We guess the scrollbar height. (FIXME)
  4135.                     m_linesPerPage = 0;
  4136.                     currentlyVisibleLines = 0;
  4137.                     break;
  4138.                 }
  4139.  
  4140.                 if ( i == count - 1 )
  4141.                     tries = 1;  // Everything fits, no second try required.
  4142.             }
  4143.         }
  4144.  
  4145.         int scroll_pos = GetScrollPos( wxHORIZONTAL );
  4146.         SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
  4147.     }
  4148.  
  4149.     if ( !noRefresh )
  4150.     {
  4151.         // FIXME: why should we call it from here?
  4152.         UpdateCurrent();
  4153.  
  4154.         RefreshAll();
  4155.     }
  4156. }
  4157.  
  4158. void wxListMainWindow::RefreshAll()
  4159. {
  4160.     m_dirty = FALSE;
  4161.     Refresh();
  4162.  
  4163.     wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
  4164.     if ( headerWin && headerWin->m_dirty )
  4165.     {
  4166.         headerWin->m_dirty = FALSE;
  4167.         headerWin->Refresh();
  4168.     }
  4169. }
  4170.  
  4171. void wxListMainWindow::UpdateCurrent()
  4172. {
  4173.     if ( !HasCurrent() && !IsEmpty() )
  4174.     {
  4175.         ChangeCurrent(0);
  4176.     }
  4177. }
  4178.  
  4179. long wxListMainWindow::GetNextItem( long item,
  4180.                                     int WXUNUSED(geometry),
  4181.                                     int state ) const
  4182. {
  4183.     long ret = item,
  4184.          max = GetItemCount();
  4185.     wxCHECK_MSG( (ret == -1) || (ret < max), -1,
  4186.                  _T("invalid listctrl index in GetNextItem()") );
  4187.  
  4188.     // notice that we start with the next item (or the first one if item == -1)
  4189.     // and this is intentional to allow writing a simple loop to iterate over
  4190.     // all selected items
  4191.     ret++;
  4192.     if ( ret == max )
  4193.     {
  4194.         // this is not an error because the index was ok initially, just no
  4195.         // such item
  4196.         return -1;
  4197.     }
  4198.  
  4199.     if ( !state )
  4200.     {
  4201.         // any will do
  4202.         return (size_t)ret;
  4203.     }
  4204.  
  4205.     size_t count = GetItemCount();
  4206.     for ( size_t line = (size_t)ret; line < count; line++ )
  4207.     {
  4208.         if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) )
  4209.             return line;
  4210.  
  4211.         if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) )
  4212.             return line;
  4213.     }
  4214.  
  4215.     return -1;
  4216. }
  4217.  
  4218. // ----------------------------------------------------------------------------
  4219. // deleting stuff
  4220. // ----------------------------------------------------------------------------
  4221.  
  4222. void wxListMainWindow::DeleteItem( long lindex )
  4223. {
  4224.     size_t count = GetItemCount();
  4225.  
  4226.     wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count),
  4227.                  _T("invalid item index in DeleteItem") );
  4228.  
  4229.     size_t index = (size_t)lindex;
  4230.  
  4231.     // we don't need to adjust the index for the previous items
  4232.     if ( HasCurrent() && m_current >= index )
  4233.     {
  4234.         // if the current item is being deleted, we want the next one to
  4235.         // become selected - unless there is no next one - so don't adjust
  4236.         // m_current in this case
  4237.         if ( m_current != index || m_current == count - 1 )
  4238.         {
  4239.             m_current--;
  4240.         }
  4241.     }
  4242.  
  4243.     if ( InReportView() )
  4244.     {
  4245.         ResetVisibleLinesRange();
  4246.     }
  4247.  
  4248.     if ( IsVirtual() )
  4249.     {
  4250.         m_countVirt--;
  4251.  
  4252.         m_selStore.OnItemDelete(index);
  4253.     }
  4254.     else
  4255.     {
  4256.         m_lines.RemoveAt( index );
  4257.     }
  4258.  
  4259.     // we need to refresh the (vert) scrollbar as the number of items changed
  4260.     m_dirty = TRUE;
  4261.  
  4262.     SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM );
  4263.  
  4264.     RefreshAfter(index);
  4265. }
  4266.  
  4267. void wxListMainWindow::DeleteColumn( int col )
  4268. {
  4269.     wxListHeaderDataList::Node *node = m_columns.Item( col );
  4270.  
  4271.     wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") );
  4272.  
  4273.     m_dirty = TRUE;
  4274.     m_columns.DeleteNode( node );
  4275.  
  4276.     // invalidate it as it has to be recalculated
  4277.     m_headerWidth = 0;
  4278. }
  4279.  
  4280. void wxListMainWindow::DoDeleteAllItems()
  4281. {
  4282.     if ( IsEmpty() )
  4283.     {
  4284.         // nothing to do - in particular, don't send the event
  4285.         return;
  4286.     }
  4287.  
  4288.     ResetCurrent();
  4289.  
  4290.     // to make the deletion of all items faster, we don't send the
  4291.     // notifications for each item deletion in this case but only one event
  4292.     // for all of them: this is compatible with wxMSW and documented in
  4293.     // DeleteAllItems() description
  4294.  
  4295.     wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() );
  4296.     event.SetEventObject( GetParent() );
  4297.     GetParent()->GetEventHandler()->ProcessEvent( event );
  4298.  
  4299.     if ( IsVirtual() )
  4300.     {
  4301.         m_countVirt = 0;
  4302.  
  4303.         m_selStore.Clear();
  4304.     }
  4305.  
  4306.     if ( InReportView() )
  4307.     {
  4308.         ResetVisibleLinesRange();
  4309.     }
  4310.  
  4311.     m_lines.Clear();
  4312. }
  4313.  
  4314. void wxListMainWindow::DeleteAllItems()
  4315. {
  4316.     DoDeleteAllItems();
  4317.  
  4318.     RecalculatePositions();
  4319. }
  4320.  
  4321. void wxListMainWindow::DeleteEverything()
  4322. {
  4323.     m_columns.Clear();
  4324.  
  4325.     DeleteAllItems();
  4326. }
  4327.  
  4328. // ----------------------------------------------------------------------------
  4329. // scanning for an item
  4330. // ----------------------------------------------------------------------------
  4331.  
  4332. void wxListMainWindow::EnsureVisible( long index )
  4333. {
  4334.     wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
  4335.                  _T("invalid index in EnsureVisible") );
  4336.  
  4337.     // We have to call this here because the label in question might just have
  4338.     // been added and its position is not known yet
  4339.     if ( m_dirty )
  4340.     {
  4341.         RecalculatePositions(TRUE /* no refresh */);
  4342.     }
  4343.  
  4344.     MoveToItem((size_t)index);
  4345. }
  4346.  
  4347. long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(partial) )
  4348. {
  4349.     long pos = start;
  4350.     wxString tmp = str;
  4351.     if (pos < 0)
  4352.         pos = 0;
  4353.  
  4354.     size_t count = GetItemCount();
  4355.     for ( size_t i = (size_t)pos; i < count; i++ )
  4356.     {
  4357.         wxListLineData *line = GetLine(i);
  4358.         if ( line->GetText(0) == tmp )
  4359.             return i;
  4360.     }
  4361.  
  4362.     return wxNOT_FOUND;
  4363. }
  4364.  
  4365. long wxListMainWindow::FindItem(long start, long data)
  4366. {
  4367.     long pos = start;
  4368.     if (pos < 0)
  4369.         pos = 0;
  4370.  
  4371.     size_t count = GetItemCount();
  4372.     for (size_t i = (size_t)pos; i < count; i++)
  4373.     {
  4374.         wxListLineData *line = GetLine(i);
  4375.         wxListItem item;
  4376.         line->GetItem( 0, item );
  4377.         if (item.m_data == data)
  4378.             return i;
  4379.     }
  4380.  
  4381.     return wxNOT_FOUND;
  4382. }
  4383.  
  4384. long wxListMainWindow::HitTest( int x, int y, int &flags )
  4385. {
  4386.     CalcUnscrolledPosition( x, y, &x, &y );
  4387.  
  4388.     size_t count = GetItemCount();
  4389.  
  4390.     if ( HasFlag(wxLC_REPORT) )
  4391.     {
  4392.         size_t current = y / GetLineHeight();
  4393.         if ( current < count )
  4394.         {
  4395.             flags = HitTestLine(current, x, y);
  4396.             if ( flags )
  4397.                 return current;
  4398.         }
  4399.     }
  4400.     else // !report
  4401.     {
  4402.         // TODO: optimize it too! this is less simple than for report view but
  4403.         //       enumerating all items is still not a way to do it!!
  4404.         for ( size_t current = 0; current < count; current++ )
  4405.         {
  4406.             flags = HitTestLine(current, x, y);
  4407.             if ( flags )
  4408.                 return current;
  4409.         }
  4410.     }
  4411.  
  4412.     return wxNOT_FOUND;
  4413. }
  4414.  
  4415. // ----------------------------------------------------------------------------
  4416. // adding stuff
  4417. // ----------------------------------------------------------------------------
  4418.  
  4419. void wxListMainWindow::InsertItem( wxListItem &item )
  4420. {
  4421.     wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
  4422.  
  4423.     size_t count = GetItemCount();
  4424.     wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId <= count,
  4425.                  _T("invalid item index") );
  4426.  
  4427.     size_t id = item.m_itemId;
  4428.  
  4429.     m_dirty = TRUE;
  4430.  
  4431.     int mode = 0;
  4432.     if ( HasFlag(wxLC_REPORT) )
  4433.     {
  4434.         mode = wxLC_REPORT;
  4435.         ResetVisibleLinesRange();
  4436.     }
  4437.     else if ( HasFlag(wxLC_LIST) )
  4438.         mode = wxLC_LIST;
  4439.     else if ( HasFlag(wxLC_ICON) )
  4440.         mode = wxLC_ICON;
  4441.     else if ( HasFlag(wxLC_SMALL_ICON) )
  4442.         mode = wxLC_ICON;  // no typo
  4443.     else
  4444.     {
  4445.         wxFAIL_MSG( _T("unknown mode") );
  4446.     }
  4447.  
  4448.     wxListLineData *line = new wxListLineData(this);
  4449.  
  4450.     line->SetItem( 0, item );
  4451.  
  4452.     m_lines.Insert( line, id );
  4453.  
  4454.     m_dirty = TRUE;
  4455.     RefreshLines(id, GetItemCount() - 1);
  4456. }
  4457.  
  4458. void wxListMainWindow::InsertColumn( long col, wxListItem &item )
  4459. {
  4460.     m_dirty = TRUE;
  4461.     if ( HasFlag(wxLC_REPORT) )
  4462.     {
  4463.         if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
  4464.             item.m_width = GetTextLength( item.m_text );
  4465.         wxListHeaderData *column = new wxListHeaderData( item );
  4466.         if ((col >= 0) && (col < (int)m_columns.GetCount()))
  4467.         {
  4468.             wxListHeaderDataList::Node *node = m_columns.Item( col );
  4469.             m_columns.Insert( node, column );
  4470.         }
  4471.         else
  4472.         {
  4473.             m_columns.Append( column );
  4474.         }
  4475.  
  4476.         // invalidate it as it has to be recalculated
  4477.         m_headerWidth = 0;
  4478.     }
  4479. }
  4480.  
  4481. // ----------------------------------------------------------------------------
  4482. // sorting
  4483. // ----------------------------------------------------------------------------
  4484.  
  4485. wxListCtrlCompare list_ctrl_compare_func_2;
  4486. long              list_ctrl_compare_data;
  4487.  
  4488. int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 )
  4489. {
  4490.     wxListLineData *line1 = *arg1;
  4491.     wxListLineData *line2 = *arg2;
  4492.     wxListItem item;
  4493.     line1->GetItem( 0, item );
  4494.     long data1 = item.m_data;
  4495.     line2->GetItem( 0, item );
  4496.     long data2 = item.m_data;
  4497.     return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data );
  4498. }
  4499.  
  4500. void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
  4501. {
  4502.     list_ctrl_compare_func_2 = fn;
  4503.     list_ctrl_compare_data = data;
  4504.     m_lines.Sort( list_ctrl_compare_func_1 );
  4505.     m_dirty = TRUE;
  4506. }
  4507.  
  4508. // ----------------------------------------------------------------------------
  4509. // scrolling
  4510. // ----------------------------------------------------------------------------
  4511.  
  4512. void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
  4513. {
  4514.     // update our idea of which lines are shown when we redraw the window the
  4515.     // next time
  4516.     ResetVisibleLinesRange();
  4517.  
  4518.     // FIXME
  4519. #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
  4520.     wxScrolledWindow::OnScroll(event);
  4521. #else
  4522.     HandleOnScroll( event );
  4523. #endif
  4524.  
  4525.     if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
  4526.     {
  4527.         wxGenericListCtrl* lc = GetListCtrl();
  4528.         wxCHECK_RET( lc, _T("no listctrl window?") );
  4529.  
  4530.         lc->m_headerWin->Refresh();
  4531.         lc->m_headerWin->Update();
  4532.     }
  4533. }
  4534.  
  4535. int wxListMainWindow::GetCountPerPage() const
  4536. {
  4537.     if ( !m_linesPerPage )
  4538.     {
  4539.         wxConstCast(this, wxListMainWindow)->
  4540.             m_linesPerPage = GetClientSize().y / GetLineHeight();
  4541.     }
  4542.  
  4543.     return m_linesPerPage;
  4544. }
  4545.  
  4546. void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
  4547. {
  4548.     wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
  4549.  
  4550.     if ( m_lineFrom == (size_t)-1 )
  4551.     {
  4552.         size_t count = GetItemCount();
  4553.         if ( count )
  4554.         {
  4555.             m_lineFrom = GetScrollPos(wxVERTICAL);
  4556.  
  4557.             // this may happen if SetScrollbars() hadn't been called yet
  4558.             if ( m_lineFrom >= count )
  4559.                 m_lineFrom = count - 1;
  4560.  
  4561.             // we redraw one extra line but this is needed to make the redrawing
  4562.             // logic work when there is a fractional number of lines on screen
  4563.             m_lineTo = m_lineFrom + m_linesPerPage;
  4564.             if ( m_lineTo >= count )
  4565.                 m_lineTo = count - 1;
  4566.         }
  4567.         else // empty control
  4568.         {
  4569.             m_lineFrom = 0;
  4570.             m_lineTo = (size_t)-1;
  4571.         }
  4572.     }
  4573.  
  4574.     wxASSERT_MSG( IsEmpty() ||
  4575.                   (m_lineFrom <= m_lineTo && m_lineTo < GetItemCount()),
  4576.                   _T("GetVisibleLinesRange() returns incorrect result") );
  4577.  
  4578.     if ( from )
  4579.         *from = m_lineFrom;
  4580.     if ( to )
  4581.         *to = m_lineTo;
  4582. }
  4583.  
  4584. // -------------------------------------------------------------------------------------
  4585. // wxGenericListCtrl
  4586. // -------------------------------------------------------------------------------------
  4587.  
  4588. IMPLEMENT_DYNAMIC_CLASS(wxGenericListCtrl, wxControl)
  4589.  
  4590. BEGIN_EVENT_TABLE(wxGenericListCtrl,wxControl)
  4591.   EVT_SIZE(wxGenericListCtrl::OnSize)
  4592.   EVT_IDLE(wxGenericListCtrl::OnIdle)
  4593. END_EVENT_TABLE()
  4594.  
  4595. wxGenericListCtrl::wxGenericListCtrl()
  4596. {
  4597.     m_imageListNormal = (wxImageListType *) NULL;
  4598.     m_imageListSmall = (wxImageListType *) NULL;
  4599.     m_imageListState = (wxImageListType *) NULL;
  4600.  
  4601.     m_ownsImageListNormal =
  4602.     m_ownsImageListSmall =
  4603.     m_ownsImageListState = FALSE;
  4604.  
  4605.     m_mainWin = (wxListMainWindow*) NULL;
  4606.     m_headerWin = (wxListHeaderWindow*) NULL;
  4607. }
  4608.  
  4609. wxGenericListCtrl::~wxGenericListCtrl()
  4610. {
  4611.     if (m_ownsImageListNormal)
  4612.         delete m_imageListNormal;
  4613.     if (m_ownsImageListSmall)
  4614.         delete m_imageListSmall;
  4615.     if (m_ownsImageListState)
  4616.         delete m_imageListState;
  4617. }
  4618.  
  4619. void wxGenericListCtrl::CreateHeaderWindow()
  4620. {
  4621.     m_headerWin = new wxListHeaderWindow
  4622.                       (
  4623.                         this, -1, m_mainWin,
  4624.                         wxPoint(0, 0),
  4625.                         wxSize(GetClientSize().x, HEADER_HEIGHT),
  4626.                         wxTAB_TRAVERSAL
  4627.                       );
  4628. }
  4629.  
  4630. bool wxGenericListCtrl::Create(wxWindow *parent,
  4631.                         wxWindowID id,
  4632.                         const wxPoint &pos,
  4633.                         const wxSize &size,
  4634.                         long style,
  4635.                         const wxValidator &validator,
  4636.                         const wxString &name)
  4637. {
  4638.     m_imageListNormal =
  4639.     m_imageListSmall =
  4640.     m_imageListState = (wxImageListType *) NULL;
  4641.     m_ownsImageListNormal =
  4642.     m_ownsImageListSmall =
  4643.     m_ownsImageListState = FALSE;
  4644.  
  4645.     m_mainWin = (wxListMainWindow*) NULL;
  4646.     m_headerWin = (wxListHeaderWindow*) NULL;
  4647.  
  4648.     if ( !(style & wxLC_MASK_TYPE) )
  4649.     {
  4650.         style = style | wxLC_LIST;
  4651.     }
  4652.  
  4653.     if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
  4654.         return FALSE;
  4655.  
  4656.     // don't create the inner window with the border
  4657.     style &= ~wxSUNKEN_BORDER;
  4658.  
  4659.     m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
  4660.  
  4661.     if ( HasFlag(wxLC_REPORT) )
  4662.     {
  4663.         CreateHeaderWindow();
  4664.  
  4665.         if ( HasFlag(wxLC_NO_HEADER) )
  4666.         {
  4667.             // VZ: why do we create it at all then?
  4668.             m_headerWin->Show( FALSE );
  4669.         }
  4670.     }
  4671.  
  4672.     return TRUE;
  4673. }
  4674.  
  4675. void wxGenericListCtrl::SetSingleStyle( long style, bool add )
  4676. {
  4677.     wxASSERT_MSG( !(style & wxLC_VIRTUAL),
  4678.                   _T("wxLC_VIRTUAL can't be [un]set") );
  4679.  
  4680.     long flag = GetWindowStyle();
  4681.  
  4682.     if (add)
  4683.     {
  4684.         if (style & wxLC_MASK_TYPE)
  4685.             flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL);
  4686.         if (style & wxLC_MASK_ALIGN)
  4687.             flag &= ~wxLC_MASK_ALIGN;
  4688.         if (style & wxLC_MASK_SORT)
  4689.             flag &= ~wxLC_MASK_SORT;
  4690.     }
  4691.  
  4692.     if (add)
  4693.     {
  4694.         flag |= style;
  4695.     }
  4696.     else
  4697.     {
  4698.         flag &= ~style;
  4699.     }
  4700.  
  4701.     SetWindowStyleFlag( flag );
  4702. }
  4703.  
  4704. void wxGenericListCtrl::SetWindowStyleFlag( long flag )
  4705. {
  4706.     if (m_mainWin)
  4707.     {
  4708.         m_mainWin->DeleteEverything();
  4709.  
  4710.         // has the header visibility changed?
  4711.         bool hasHeader = HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER),
  4712.              willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
  4713.  
  4714.         if ( hasHeader != willHaveHeader )
  4715.         {
  4716.             // toggle it
  4717.             if ( hasHeader )
  4718.             {
  4719.                 if ( m_headerWin )
  4720.                 {
  4721.                     // don't delete, just hide, as we can reuse it later
  4722.                     m_headerWin->Show(FALSE);
  4723.                 }
  4724.                 //else: nothing to do
  4725.             }
  4726.             else // must show header
  4727.             {
  4728.                 if (!m_headerWin)
  4729.                 {
  4730.                     CreateHeaderWindow();
  4731.                 }
  4732.                 else // already have it, just show
  4733.                 {
  4734.                     m_headerWin->Show( TRUE );
  4735.                 }
  4736.             }
  4737.  
  4738.             ResizeReportView(willHaveHeader);
  4739.         }
  4740.     }
  4741.  
  4742.     wxWindow::SetWindowStyleFlag( flag );
  4743. }
  4744.  
  4745. bool wxGenericListCtrl::GetColumn(int col, wxListItem &item) const
  4746. {
  4747.     m_mainWin->GetColumn( col, item );
  4748.     return TRUE;
  4749. }
  4750.  
  4751. bool wxGenericListCtrl::SetColumn( int col, wxListItem& item )
  4752. {
  4753.     m_mainWin->SetColumn( col, item );
  4754.     return TRUE;
  4755. }
  4756.  
  4757. int wxGenericListCtrl::GetColumnWidth( int col ) const
  4758. {
  4759.     return m_mainWin->GetColumnWidth( col );
  4760. }
  4761.  
  4762. bool wxGenericListCtrl::SetColumnWidth( int col, int width )
  4763. {
  4764.     m_mainWin->SetColumnWidth( col, width );
  4765.     return TRUE;
  4766. }
  4767.  
  4768. int wxGenericListCtrl::GetCountPerPage() const
  4769. {
  4770.   return m_mainWin->GetCountPerPage();  // different from Windows ?
  4771. }
  4772.  
  4773. bool wxGenericListCtrl::GetItem( wxListItem &info ) const
  4774. {
  4775.     m_mainWin->GetItem( info );
  4776.     return TRUE;
  4777. }
  4778.  
  4779. bool wxGenericListCtrl::SetItem( wxListItem &info )
  4780. {
  4781.     m_mainWin->SetItem( info );
  4782.     return TRUE;
  4783. }
  4784.  
  4785. long wxGenericListCtrl::SetItem( long index, int col, const wxString& label, int imageId )
  4786. {
  4787.     wxListItem info;
  4788.     info.m_text = label;
  4789.     info.m_mask = wxLIST_MASK_TEXT;
  4790.     info.m_itemId = index;
  4791.     info.m_col = col;
  4792.     if ( imageId > -1 )
  4793.     {
  4794.         info.m_image = imageId;
  4795.         info.m_mask |= wxLIST_MASK_IMAGE;
  4796.     };
  4797.     m_mainWin->SetItem(info);
  4798.     return TRUE;
  4799. }
  4800.  
  4801. int wxGenericListCtrl::GetItemState( long item, long stateMask ) const
  4802. {
  4803.     return m_mainWin->GetItemState( item, stateMask );
  4804. }
  4805.  
  4806. bool wxGenericListCtrl::SetItemState( long item, long state, long stateMask )
  4807. {
  4808.     m_mainWin->SetItemState( item, state, stateMask );
  4809.     return TRUE;
  4810. }
  4811.  
  4812. bool wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
  4813. {
  4814.     wxListItem info;
  4815.     info.m_image = image;
  4816.     info.m_mask = wxLIST_MASK_IMAGE;
  4817.     info.m_itemId = item;
  4818.     m_mainWin->SetItem( info );
  4819.     return TRUE;
  4820. }
  4821.  
  4822. wxString wxGenericListCtrl::GetItemText( long item ) const
  4823. {
  4824.     return m_mainWin->GetItemText(item);
  4825. }
  4826.  
  4827. void wxGenericListCtrl::SetItemText( long item, const wxString& str )
  4828. {
  4829.     m_mainWin->SetItemText(item, str);
  4830. }
  4831.  
  4832. long wxGenericListCtrl::GetItemData( long item ) const
  4833. {
  4834.     wxListItem info;
  4835.     info.m_itemId = item;
  4836.     m_mainWin->GetItem( info );
  4837.     return info.m_data;
  4838. }
  4839.  
  4840. bool wxGenericListCtrl::SetItemData( long item, long data )
  4841. {
  4842.     wxListItem info;
  4843.     info.m_mask = wxLIST_MASK_DATA;
  4844.     info.m_itemId = item;
  4845.     info.m_data = data;
  4846.     m_mainWin->SetItem( info );
  4847.     return TRUE;
  4848. }
  4849.  
  4850. bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect,  int WXUNUSED(code) ) const
  4851. {
  4852.     m_mainWin->GetItemRect( item, rect );
  4853.     return TRUE;
  4854. }
  4855.  
  4856. bool wxGenericListCtrl::GetItemPosition( long item, wxPoint& pos ) const
  4857. {
  4858.     m_mainWin->GetItemPosition( item, pos );
  4859.     return TRUE;
  4860. }
  4861.  
  4862. bool wxGenericListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
  4863. {
  4864.     return 0;
  4865. }
  4866.  
  4867. int wxGenericListCtrl::GetItemCount() const
  4868. {
  4869.     return m_mainWin->GetItemCount();
  4870. }
  4871.  
  4872. int wxGenericListCtrl::GetColumnCount() const
  4873. {
  4874.     return m_mainWin->GetColumnCount();
  4875. }
  4876.  
  4877. void wxGenericListCtrl::SetItemSpacing( int spacing, bool isSmall )
  4878. {
  4879.     m_mainWin->SetItemSpacing( spacing, isSmall );
  4880. }
  4881.  
  4882. int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const
  4883. {
  4884.     return m_mainWin->GetItemSpacing( isSmall );
  4885. }
  4886.  
  4887. void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col )
  4888. {
  4889.     wxListItem info;
  4890.     info.m_itemId = item;
  4891.     info.SetTextColour( col );
  4892.     m_mainWin->SetItem( info );
  4893. }
  4894.  
  4895. wxColour wxGenericListCtrl::GetItemTextColour( long item ) const
  4896. {
  4897.     wxListItem info;
  4898.     info.m_itemId = item;
  4899.     m_mainWin->GetItem( info );
  4900.     return info.GetTextColour();
  4901. }
  4902.  
  4903. void wxGenericListCtrl::SetItemBackgroundColour( long item, const wxColour &col )
  4904. {
  4905.     wxListItem info;
  4906.     info.m_itemId = item;
  4907.     info.SetBackgroundColour( col );
  4908.     m_mainWin->SetItem( info );
  4909. }
  4910.  
  4911. wxColour wxGenericListCtrl::GetItemBackgroundColour( long item ) const
  4912. {
  4913.     wxListItem info;
  4914.     info.m_itemId = item;
  4915.     m_mainWin->GetItem( info );
  4916.     return info.GetBackgroundColour();
  4917. }
  4918.  
  4919. int wxGenericListCtrl::GetSelectedItemCount() const
  4920. {
  4921.     return m_mainWin->GetSelectedItemCount();
  4922. }
  4923.  
  4924. wxColour wxGenericListCtrl::GetTextColour() const
  4925. {
  4926.     return GetForegroundColour();
  4927. }
  4928.  
  4929. void wxGenericListCtrl::SetTextColour(const wxColour& col)
  4930. {
  4931.     SetForegroundColour(col);
  4932. }
  4933.  
  4934. long wxGenericListCtrl::GetTopItem() const
  4935. {
  4936.     size_t top;
  4937.     m_mainWin->GetVisibleLinesRange(&top, NULL);
  4938.     return (long)top;
  4939. }
  4940.  
  4941. long wxGenericListCtrl::GetNextItem( long item, int geom, int state ) const
  4942. {
  4943.     return m_mainWin->GetNextItem( item, geom, state );
  4944. }
  4945.  
  4946. wxImageListType *wxGenericListCtrl::GetImageList(int which) const
  4947. {
  4948.     if (which == wxIMAGE_LIST_NORMAL)
  4949.     {
  4950.         return m_imageListNormal;
  4951.     }
  4952.     else if (which == wxIMAGE_LIST_SMALL)
  4953.     {
  4954.         return m_imageListSmall;
  4955.     }
  4956.     else if (which == wxIMAGE_LIST_STATE)
  4957.     {
  4958.         return m_imageListState;
  4959.     }
  4960.     return (wxImageListType *) NULL;
  4961. }
  4962.  
  4963. void wxGenericListCtrl::SetImageList( wxImageListType *imageList, int which )
  4964. {
  4965.     if ( which == wxIMAGE_LIST_NORMAL )
  4966.     {
  4967.         if (m_ownsImageListNormal) delete m_imageListNormal;
  4968.         m_imageListNormal = imageList;
  4969.         m_ownsImageListNormal = FALSE;
  4970.     }
  4971.     else if ( which == wxIMAGE_LIST_SMALL )
  4972.     {
  4973.         if (m_ownsImageListSmall) delete m_imageListSmall;
  4974.         m_imageListSmall = imageList;
  4975.         m_ownsImageListSmall = FALSE;
  4976.     }
  4977.     else if ( which == wxIMAGE_LIST_STATE )
  4978.     {
  4979.         if (m_ownsImageListState) delete m_imageListState;
  4980.         m_imageListState = imageList;
  4981.         m_ownsImageListState = FALSE;
  4982.     }
  4983.  
  4984.     m_mainWin->SetImageList( imageList, which );
  4985. }
  4986.  
  4987. void wxGenericListCtrl::AssignImageList(wxImageListType *imageList, int which)
  4988. {
  4989.     SetImageList(imageList, which);
  4990.     if ( which == wxIMAGE_LIST_NORMAL )
  4991.         m_ownsImageListNormal = TRUE;
  4992.     else if ( which == wxIMAGE_LIST_SMALL )
  4993.         m_ownsImageListSmall = TRUE;
  4994.     else if ( which == wxIMAGE_LIST_STATE )
  4995.         m_ownsImageListState = TRUE;
  4996. }
  4997.  
  4998. bool wxGenericListCtrl::Arrange( int WXUNUSED(flag) )
  4999. {
  5000.     return 0;
  5001. }
  5002.  
  5003. bool wxGenericListCtrl::DeleteItem( long item )
  5004. {
  5005.     m_mainWin->DeleteItem( item );
  5006.     return TRUE;
  5007. }
  5008.  
  5009. bool wxGenericListCtrl::DeleteAllItems()
  5010. {
  5011.     m_mainWin->DeleteAllItems();
  5012.     return TRUE;
  5013. }
  5014.  
  5015. bool wxGenericListCtrl::DeleteAllColumns()
  5016. {
  5017.     size_t count = m_mainWin->m_columns.GetCount();
  5018.     for ( size_t n = 0; n < count; n++ )
  5019.         DeleteColumn(0);
  5020.  
  5021.     return TRUE;
  5022. }
  5023.  
  5024. void wxGenericListCtrl::ClearAll()
  5025. {
  5026.     m_mainWin->DeleteEverything();
  5027. }
  5028.  
  5029. bool wxGenericListCtrl::DeleteColumn( int col )
  5030. {
  5031.     m_mainWin->DeleteColumn( col );
  5032.  
  5033.     // if we don't have the header any longer, we need to relayout the window
  5034.     if ( !GetColumnCount() )
  5035.     {
  5036.         ResizeReportView(FALSE /* no header */);
  5037.     }
  5038.  
  5039.     return TRUE;
  5040. }
  5041.  
  5042. void wxGenericListCtrl::Edit( long item )
  5043. {
  5044.     m_mainWin->EditLabel( item );
  5045. }
  5046.  
  5047. bool wxGenericListCtrl::EnsureVisible( long item )
  5048. {
  5049.     m_mainWin->EnsureVisible( item );
  5050.     return TRUE;
  5051. }
  5052.  
  5053. long wxGenericListCtrl::FindItem( long start, const wxString& str,  bool partial )
  5054. {
  5055.     return m_mainWin->FindItem( start, str, partial );
  5056. }
  5057.  
  5058. long wxGenericListCtrl::FindItem( long start, long data )
  5059. {
  5060.     return m_mainWin->FindItem( start, data );
  5061. }
  5062.  
  5063. long wxGenericListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt),
  5064.                            int WXUNUSED(direction))
  5065. {
  5066.     return 0;
  5067. }
  5068.  
  5069. long wxGenericListCtrl::HitTest( const wxPoint &point, int &flags )
  5070. {
  5071.     return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
  5072. }
  5073.  
  5074. long wxGenericListCtrl::InsertItem( wxListItem& info )
  5075. {
  5076.     m_mainWin->InsertItem( info );
  5077.     return info.m_itemId;
  5078. }
  5079.  
  5080. long wxGenericListCtrl::InsertItem( long index, const wxString &label )
  5081. {
  5082.     wxListItem info;
  5083.     info.m_text = label;
  5084.     info.m_mask = wxLIST_MASK_TEXT;
  5085.     info.m_itemId = index;
  5086.     return InsertItem( info );
  5087. }
  5088.  
  5089. long wxGenericListCtrl::InsertItem( long index, int imageIndex )
  5090. {
  5091.     wxListItem info;
  5092.     info.m_mask = wxLIST_MASK_IMAGE;
  5093.     info.m_image = imageIndex;
  5094.     info.m_itemId = index;
  5095.     return InsertItem( info );
  5096. }
  5097.  
  5098. long wxGenericListCtrl::InsertItem( long index, const wxString &label, int imageIndex )
  5099. {
  5100.     wxListItem info;
  5101.     info.m_text = label;
  5102.     info.m_image = imageIndex;
  5103.     info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
  5104.     info.m_itemId = index;
  5105.     return InsertItem( info );
  5106. }
  5107.  
  5108. long wxGenericListCtrl::InsertColumn( long col, wxListItem &item )
  5109. {
  5110.     wxCHECK_MSG( m_headerWin, -1, _T("can't add column in non report mode") );
  5111.  
  5112.     m_mainWin->InsertColumn( col, item );
  5113.  
  5114.     // if we hadn't had header before and have it now we need to relayout the
  5115.     // window
  5116.     if ( GetColumnCount() == 1 )
  5117.     {
  5118.         ResizeReportView(TRUE /* have header */);
  5119.     }
  5120.  
  5121.     m_headerWin->Refresh();
  5122.  
  5123.     return 0;
  5124. }
  5125.  
  5126. long wxGenericListCtrl::InsertColumn( long col, const wxString &heading,
  5127.                                int format, int width )
  5128. {
  5129.     wxListItem item;
  5130.     item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
  5131.     item.m_text = heading;
  5132.     if (width >= -2)
  5133.     {
  5134.         item.m_mask |= wxLIST_MASK_WIDTH;
  5135.         item.m_width = width;
  5136.     }
  5137.     item.m_format = format;
  5138.  
  5139.     return InsertColumn( col, item );
  5140. }
  5141.  
  5142. bool wxGenericListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
  5143. {
  5144.     return 0;
  5145. }
  5146.  
  5147. // Sort items.
  5148. // fn is a function which takes 3 long arguments: item1, item2, data.
  5149. // item1 is the long data associated with a first item (NOT the index).
  5150. // item2 is the long data associated with a second item (NOT the index).
  5151. // data is the same value as passed to SortItems.
  5152. // The return value is a negative number if the first item should precede the second
  5153. // item, a positive number of the second item should precede the first,
  5154. // or zero if the two items are equivalent.
  5155. // data is arbitrary data to be passed to the sort function.
  5156.  
  5157. bool wxGenericListCtrl::SortItems( wxListCtrlCompare fn, long data )
  5158. {
  5159.     m_mainWin->SortItems( fn, data );
  5160.     return TRUE;
  5161. }
  5162.  
  5163. // ----------------------------------------------------------------------------
  5164. // event handlers
  5165. // ----------------------------------------------------------------------------
  5166.  
  5167. void wxGenericListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
  5168. {
  5169.     if ( !m_mainWin )
  5170.         return;
  5171.  
  5172.     ResizeReportView(m_mainWin->HasHeader());
  5173.  
  5174.     m_mainWin->RecalculatePositions();
  5175. }
  5176.  
  5177. void wxGenericListCtrl::ResizeReportView(bool showHeader)
  5178. {
  5179.     int cw, ch;
  5180.     GetClientSize( &cw, &ch );
  5181.  
  5182.     if ( showHeader )
  5183.     {
  5184.         m_headerWin->SetSize( 0, 0, cw, HEADER_HEIGHT );
  5185.         m_mainWin->SetSize( 0, HEADER_HEIGHT + 1, cw, ch - HEADER_HEIGHT - 1 );
  5186.     }
  5187.     else // no header window
  5188.     {
  5189.         m_mainWin->SetSize( 0, 0, cw, ch );
  5190.     }
  5191. }
  5192.  
  5193. void wxGenericListCtrl::OnIdle( wxIdleEvent & event )
  5194. {
  5195.     event.Skip();
  5196.  
  5197.     // do it only if needed
  5198.     if ( !m_mainWin->m_dirty )
  5199.         return;
  5200.  
  5201.     m_mainWin->RecalculatePositions();
  5202. }
  5203.  
  5204. // ----------------------------------------------------------------------------
  5205. // font/colours
  5206. // ----------------------------------------------------------------------------
  5207.  
  5208. bool wxGenericListCtrl::SetBackgroundColour( const wxColour &colour )
  5209. {
  5210.     if (m_mainWin)
  5211.     {
  5212.         m_mainWin->SetBackgroundColour( colour );
  5213.         m_mainWin->m_dirty = TRUE;
  5214.     }
  5215.  
  5216.     return TRUE;
  5217. }
  5218.  
  5219. bool wxGenericListCtrl::SetForegroundColour( const wxColour &colour )
  5220. {
  5221.     if ( !wxWindow::SetForegroundColour( colour ) )
  5222.         return FALSE;
  5223.  
  5224.     if (m_mainWin)
  5225.     {
  5226.         m_mainWin->SetForegroundColour( colour );
  5227.         m_mainWin->m_dirty = TRUE;
  5228.     }
  5229.  
  5230.     if (m_headerWin)
  5231.     {
  5232.         m_headerWin->SetForegroundColour( colour );
  5233.     }
  5234.  
  5235.     return TRUE;
  5236. }
  5237.  
  5238. bool wxGenericListCtrl::SetFont( const wxFont &font )
  5239. {
  5240.     if ( !wxWindow::SetFont( font ) )
  5241.         return FALSE;
  5242.  
  5243.     if (m_mainWin)
  5244.     {
  5245.         m_mainWin->SetFont( font );
  5246.         m_mainWin->m_dirty = TRUE;
  5247.     }
  5248.  
  5249.     if (m_headerWin)
  5250.     {
  5251.         m_headerWin->SetFont( font );
  5252.     }
  5253.  
  5254.     return TRUE;
  5255. }
  5256.  
  5257. // ----------------------------------------------------------------------------
  5258. // methods forwarded to m_mainWin
  5259. // ----------------------------------------------------------------------------
  5260.  
  5261. #if wxUSE_DRAG_AND_DROP
  5262.  
  5263. void wxGenericListCtrl::SetDropTarget( wxDropTarget *dropTarget )
  5264. {
  5265.     m_mainWin->SetDropTarget( dropTarget );
  5266. }
  5267.  
  5268. wxDropTarget *wxGenericListCtrl::GetDropTarget() const
  5269. {
  5270.     return m_mainWin->GetDropTarget();
  5271. }
  5272.  
  5273. #endif // wxUSE_DRAG_AND_DROP
  5274.  
  5275. bool wxGenericListCtrl::SetCursor( const wxCursor &cursor )
  5276. {
  5277.     return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : FALSE;
  5278. }
  5279.  
  5280. wxColour wxGenericListCtrl::GetBackgroundColour() const
  5281. {
  5282.     return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour();
  5283. }
  5284.  
  5285. wxColour wxGenericListCtrl::GetForegroundColour() const
  5286. {
  5287.     return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour();
  5288. }
  5289.  
  5290. bool wxGenericListCtrl::DoPopupMenu( wxMenu *menu, int x, int y )
  5291. {
  5292. #if wxUSE_MENUS
  5293.     return m_mainWin->PopupMenu( menu, x, y );
  5294. #else
  5295.     return FALSE;
  5296. #endif // wxUSE_MENUS
  5297. }
  5298.  
  5299. void wxGenericListCtrl::SetFocus()
  5300. {
  5301.     /* The test in window.cpp fails as we are a composite
  5302.        window, so it checks against "this", but not m_mainWin. */
  5303.     if ( FindFocus() != this )
  5304.         m_mainWin->SetFocus();
  5305. }
  5306.  
  5307. // ----------------------------------------------------------------------------
  5308. // virtual list control support
  5309. // ----------------------------------------------------------------------------
  5310.  
  5311. wxString wxGenericListCtrl::OnGetItemText(long WXUNUSED(item), long WXUNUSED(col)) const
  5312. {
  5313.     // this is a pure virtual function, in fact - which is not really pure
  5314.     // because the controls which are not virtual don't need to implement it
  5315.     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemText not supposed to be called") );
  5316.  
  5317.     return wxEmptyString;
  5318. }
  5319.  
  5320. int wxGenericListCtrl::OnGetItemImage(long WXUNUSED(item)) const
  5321. {
  5322.     // same as above
  5323.     wxFAIL_MSG( _T("wxGenericListCtrl::OnGetItemImage not supposed to be called") );
  5324.  
  5325.     return -1;
  5326. }
  5327.  
  5328. wxListItemAttr *wxGenericListCtrl::OnGetItemAttr(long item) const
  5329. {
  5330.     wxASSERT_MSG( item >= 0 && item < GetItemCount(),
  5331.                   _T("invalid item index in OnGetItemAttr()") );
  5332.  
  5333.     // no attributes by default
  5334.     return NULL;
  5335. }
  5336.  
  5337. void wxGenericListCtrl::SetItemCount(long count)
  5338. {
  5339.     wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
  5340.  
  5341.     m_mainWin->SetItemCount(count);
  5342. }
  5343.  
  5344. void wxGenericListCtrl::RefreshItem(long item)
  5345. {
  5346.     m_mainWin->RefreshLine(item);
  5347. }
  5348.  
  5349. void wxGenericListCtrl::RefreshItems(long itemFrom, long itemTo)
  5350. {
  5351.     m_mainWin->RefreshLines(itemFrom, itemTo);
  5352. }
  5353.  
  5354. void wxGenericListCtrl::Freeze()
  5355. {
  5356.     m_mainWin->Freeze();
  5357. }
  5358.  
  5359. void wxGenericListCtrl::Thaw()
  5360. {
  5361.     m_mainWin->Thaw();
  5362. }
  5363.  
  5364. #endif // wxUSE_LISTCTRL
  5365.  
  5366.