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