📄 sortlistviewctrlex.hpp
字号:
// Copyright E骾n O'Callaghan 2008 - 2008.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef SORTLISTVIEWCTRLEX_HPP_INCLUDED
#define SORTLISTVIEWCTRLEX_HPP_INCLUDED
#include <boost/ptr_container/ptr_map.hpp>
#include "SettingsIni.hpp"
#include "UpdateLock.hpp"
#define LVS_EX_DOUBLEBUFFER 0x00010000
#define ID_LVM_AUTOSORT 0
namespace WTLx
{
template <class TBase, typename adapterType=void*>
class SortListViewCtrlEx :
public WTL::CSortListViewCtrlImpl<SortListViewCtrlEx<TBase, adapterType> >,
public WTLx::update_lockable<SortListViewCtrlEx<TBase, adapterType> >
{
public:
typedef SortListViewCtrlEx<TBase, adapterType> thisClass;
typedef CSortListViewCtrlImpl<thisClass> parentClass;
class SortHeaderCtrl : public CWindowImpl<SortHeaderCtrl, WTL::CHeaderCtrl>
{
public:
enum { COL_MENU_NAMES_ID_START = 123, COL_MAX_NAMES = 256};
SortHeaderCtrl(thisClass& listView) :
listView_(listView)
{}
DECLARE_WND_SUPERCLASS(NULL, parentClass::GetWndClassName())
BEGIN_MSG_MAP(SortHeaderCtrl)
REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
COMMAND_RANGE_HANDLER(COL_MENU_NAMES_ID_START,
COL_MENU_NAMES_ID_START+COL_MAX_NAMES, OnMenuNames)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
{
WTL::CPoint point;
GetCursorPos(&point);
menu_.TrackPopupMenu(0, point.x, point.y, m_hWnd);
return 0;
}
LRESULT OnMenuNames(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
ATLASSERT(wID-COL_MENU_NAMES_ID_START <= GetItemCount());
bool visible = listView_.OnNameChecked(wID-COL_MENU_NAMES_ID_START);
return 0;
}
WTL::CMenu& Menu()
{
return menu_;
}
private:
WTL::CMenu menu_;
thisClass& listView_;
};
struct ColumnAdapter
{
virtual int compare(adapterType& l, adapterType& r) = 0;
virtual std::wstring print(adapterType& t) = 0;
};
public:
SortListViewCtrlEx() :
header_(*this),
auto_sort_(false),
descending_(false),
sort_col_(-1)
{}
BEGIN_MSG_MAP_EX(thisClass)
COMMAND_ID_HANDLER(ID_LVM_AUTOSORT, OnAutoSort)
REFLECTED_NOTIFY_CODE_HANDLER(NM_RCLICK, OnRClick)
DEFAULT_REFLECTION_HANDLER()
CHAIN_MSG_MAP(parentClass)
END_MSG_MAP()
HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
{
HWND hwnd = parentClass::Create(hWndParent,
(RECT &)rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)MenuOrID.m_hMenu, lpCreateParam);
return hwnd;
}
bool SubclassWindow(HWND hwnd)
{
if(!parentClass::SubclassWindow(hwnd))
return false;
InitialSetup();
return true;
}
void InitialSetup(WTL::CMenuHandle menu=WTL::CMenuHandle())
{
SetExtendedListViewStyle(LVS_EX_HEADERDRAGDROP|LVS_EX_DOUBLEBUFFER);
SetSortListViewExtendedStyle(SORTLV_USESHELLBITMAPS,SORTLV_USESHELLBITMAPS);
MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
if (!menu)
{
// menu_.CreatePopupMenu();
}
else
{
menu_.Attach(menu.GetSubMenu(0));
// minfo.fMask = MIIM_SUBMENU;
// minfo.fType = MFT_SEPARATOR;
// menu_.InsertMenuItem(menu_.GetMenuItemCount(), true, &minfo);
}
//minfo.fMask = MIIM_STRING|MIIM_ID|MIIM_FTYPE|MIIM_STATE;
//minfo.fType = MFT_STRING;
//minfo.fState = auto_sort_ ? MFS_CHECKED : MFS_UNCHECKED;
//minfo.wID = ID_LVM_AUTOSORT;
//std::wstring autoarrange = aux::app.res_wstr(IDS_AUTOSORT);
//minfo.dwTypeData = (LPWSTR)autoarrange.c_str();
//menu_.InsertMenuItem(menu_.GetMenuItemCount(), true, &minfo);
header_.SubclassWindow(this->GetHeader());
header_.ModifyStyle(0, HDS_DRAGDROP|HDS_FULLDRAG);
if (header_.Menu().IsNull())
header_.Menu().CreatePopupMenu();
}
int AddColumn(LPCTSTR strItem, int nItem, bool visible, int width=-1)
{
return AddColumn(strItem, nItem, -1,
LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
LVCFMT_LEFT, visible, width);
}
int AddColumn(LPCTSTR strItem, int nItem, int nSubItem = -1,
int nMask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM,
int nFmt = LVCFMT_LEFT, bool visible=true, int width=-1)
{
int i = parentClass::AddColumn(strItem, nItem, nSubItem, nMask, nFmt);
if (i == -1) return i;
if (width != -1) SetColumnWidth(i, width);
if (header_.Menu().IsNull())
header_.Menu().CreatePopupMenu();
WTL::CMenuHandle menu = header_.Menu();
MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
minfo.fMask = MIIM_STRING|MIIM_ID|MIIM_FTYPE|MIIM_STATE;
minfo.fType = MFT_STRING;
minfo.dwTypeData = (LPTSTR)strItem;
minfo.wID = SortHeaderCtrl::COL_MENU_NAMES_ID_START+i;
if (visible)
minfo.fState = MFS_CHECKED;
else
{
minfo.fState = MFS_UNCHECKED;
SetColumnWidth(i, 0);
}
int w = GetColumnWidth(i);
visible_.push_back(visible);
widths_.push_back(w);
order_.push_back(i);
menu.InsertMenuItem(menu.GetMenuItemCount(), false, &minfo);
return i;
}
void SetSort(bool auto_sort=false)
{
auto_sort_ = auto_sort;
//MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
//minfo.fMask = MIIM_STATE;
//minfo.fState = auto_sort_ ? MFS_CHECKED : MFS_UNCHECKED;
//menu_.SetMenuItemInfo(ID_LVM_AUTOSORT, false, &minfo);
m_bSortDescending = descending_;
if (sort_col_ >= 0 && sort_col_ < m_arrColSortType.GetSize())
SetSortColumn(sort_col_);
}
void SetColumnOrderState()
{
while ((int)order_.size() < header_.GetItemCount())
order_.push_back(header_.GetItemCount());
GetColumnOrderArray(order_.size(), &order_[0]);
}
void SetSortState()
{
MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
minfo.fMask = MIIM_STATE;
minfo.fState = auto_sort_ ? MFS_CHECKED : MFS_UNCHECKED;
// menu_.SetMenuItemInfo(ID_LVM_AUTOSORT, false, &minfo);
if (sort_col_ >= 0 && sort_col_ < m_arrColSortType.GetSize())
SetSortColumn(sort_col_);
}
bool OnNameChecked(int i)
{
// try_update_lock<thisClass> lock(*this);
while ((int)order_.size() < header_.GetItemCount())
order_.push_back(header_.GetItemCount());
if (!visible_[i])
{
GetColumnOrderArray(order_.size(), &order_[0]);
SetColumnWidth(i, widths_[i]);
order_.erase(std::find(order_.begin(), order_.end(), i));
int index = i + std::count(visible_.begin()+i, visible_.end(), false) - 1;
order_.insert(order_.begin()+index, i);
SetColumnOrderArray(order_.size(), &order_[0]);
visible_[i] = true;
}
else
{
widths_[i] = GetColumnWidth(i);
GetColumnOrderArray(order_.size(), &order_[0]);
SetColumnWidth(i, 0);
order_.erase(std::find(order_.begin(), order_.end(), i));
order_.insert(order_.begin(), i);
SetColumnOrderArray(order_.size(), &order_[0]);
visible_[i] = false;
}
MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
minfo.fMask = MIIM_STATE;
minfo.fState = visible_[i] ? MFS_CHECKED : MFS_UNCHECKED;
header_.Menu().SetMenuItemInfo(i+SortHeaderCtrl::COL_MENU_NAMES_ID_START, false, &minfo);
InvalidateRect(NULL, true);
return visible_[i];
}
LRESULT OnAutoSort(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
auto_sort_ = !auto_sort_;
MENUITEMINFO minfo = {sizeof(MENUITEMINFO)};
minfo.fMask = MIIM_STATE;
minfo.fState = auto_sort_ ? MFS_CHECKED : MFS_UNCHECKED;
menu_.SetMenuItemInfo(ID_LVM_AUTOSORT, false, &minfo);
return 0;
}
LRESULT OnRClick(int i, LPNMHDR pnmh, BOOL&)
{
LPNMITEMACTIVATE pia = (LPNMITEMACTIVATE)pnmh;
if (menu_)
{
assert (menu_.IsMenu());
POINT ptPoint;
GetCursorPos(&ptPoint);
menu_.TrackPopupMenu(0, ptPoint.x, ptPoint.y, m_hWnd);
}
return 0;
}
friend class boost::serialization::access;
template<class Archive>
void save(Archive & ar, const unsigned int version) const
{
for (size_t i=0; i<widths_.size(); ++i)
{
if (visible_[i])
widths_[i] = GetColumnWidth(i);
}
GetColumnOrderArray(order_.size(), &order_[0]);
sort_col_ = GetSortColumn();
descending_ = IsSortDescending();
using boost::serialization::make_nvp;
ar & make_nvp("widths", widths_);
ar & make_nvp("order", order_);
ar & make_nvp("visible", visible_);
ar & make_nvp("auto_sort", auto_sort_);
ar & make_nvp("descending", descending_);
ar & make_nvp("sort_col", sort_col_);
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
using boost::serialization::make_nvp;
ar & make_nvp("widths", widths_);
ar & make_nvp("order", order_);
ar & make_nvp("visible", visible_);
ar & make_nvp("auto_sort", auto_sort_);
ar & make_nvp("descending", descending_);
ar & make_nvp("sort_col", sort_col_);
SetColumnOrderArray(order_.size(), &order_[0]);
m_bSortDescending = descending_;
if (sort_col_ >= 0 && sort_col_ < m_arrColSortType.GetSize())
SetSortColumn(sort_col_);
for (size_t i=0; i<widths_.size(); ++i)
{
SetColumnWidth(i, widths_[i]);
if (!visible_[i])
{
visible_[i] = true;
OnNameChecked(i);
}
}
SetColumnOrderState();
SetSortState();
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
bool autoSort() { return auto_sort_; }
void ConditionallyDoAutoSort()
{
int iCol = GetSortColumn();
if (autoSort() && iCol >= 0 && iCol < m_arrColSortType.GetSize())
DoSortItems(iCol, IsSortDescending());
}
protected:
WTL::CMenu menu_;
SortHeaderCtrl header_;
mutable std::vector<int> widths_;
mutable std::vector<int> order_;
mutable std::vector<bool> visible_;
mutable bool auto_sort_;
mutable bool descending_;
mutable int sort_col_;
};
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -