📄 donutclipboardbar.h
字号:
#pragma once
// for debug
#ifdef _DEBUG
const bool _Mtl_ClipboardBar_traceOn = false;
#define clbTRACE if (_Mtl_ClipboardBar_traceOn) ATLTRACE
#else
#define clbTRACE
#endif
// Note. When I made dialogs, I've encountered a strange kernel32 exception.
// If a form view has a check box, kernel32 exception occurs when an app unloaded.
// I can't get the reason.
#define CLPV_EX_ON 0x00000001L
#define CLPV_EX_DIRECT 0x00000002L
#define CLPV_EX_FLUSH 0x00000004L
class CDonutClipboardBar :
public CDialogImpl<CDonutClipboardBar>,
public CDialogResize<CDonutClipboardBar>,
public CClipboardViewer<CDonutClipboardBar>,
public CWinDataExchange<CDonutClipboardBar>
{
public:
enum { IDD = IDD_CLIPBAR_FORM };
// Data members
DWORD m_dwExStyle;
CString m_strExts;
int m_nOn;
int m_nDirect, m_nFlush;
// Windows
CEdit m_edit;
CContainedWindowT<CListBox> m_box;
// Ctor
CDonutClipboardBar() : m_dwExStyle(0), m_box(this, 1)
{
}
// Methods
CString GetExtsList()
{
return MtlGetWindowText(m_edit);
}
void OpenClipboardUrl()
{
CString strText = MtlGetClipboardText();
if (strText.IsEmpty())
return;
CSimpleArray<CString> arrExt;
MtlBuildExtArray(arrExt, GetExtsList());
CSimpleArray<CString> arrUrl;
MtlBuildUrlArray(arrUrl, arrExt, strText);
for (int i = 0; i < arrUrl.GetSize(); ++i) {
DonutOpenFile(m_hWnd, arrUrl[i], 0);
}
}
// Overrides
void OnUpdateClipboard()
{
if (CMainOption::s_bIgnoreUpdateClipboard)
return;
clbTRACE(_T("OnUpdateClipboard\n"));
CString strText = MtlGetClipboardText();
if (strText.IsEmpty())
return;
CWebBrowser2 browser = DonutGetIWebBrowser2(GetTopLevelParent());
if (!browser.IsBrowserNull()) {
CString strUrl = browser.GetLocationURL();
if (strUrl == strText)
return;
}
if (_check_flag(CLPV_EX_FLUSH, m_dwExStyle))
m_box.ResetContent();
CSimpleArray<CString> arrExt;
MtlBuildExtArray(arrExt, MtlGetWindowText(m_edit));
CSimpleArray<CString> arrUrl;
MtlBuildUrlArray(arrUrl, arrExt, strText);
if (arrUrl.GetSize() == 0) {
return;
}
else {
if (_check_flag(CLPV_EX_FLUSH, m_dwExStyle))
m_box.ResetContent();
}
for (int i = 0; i < arrUrl.GetSize(); ++i) {
if (m_box.GetCount() == 0)
m_box.AddString(arrUrl[i]);
else
m_box.InsertString(0, arrUrl[i]);
}
if (_check_flag(CLPV_EX_DIRECT, m_dwExStyle)) {
for (int i = 0; i < arrUrl.GetSize(); ++i) {
DonutOpenFile(m_hWnd, arrUrl[i], 0);
}
}
}
// Methods
BYTE PreTranslateMessage(MSG* pMsg)
{
UINT msg = pMsg->message;
int vKey = pMsg->wParam;
HWND hWnd = pMsg->hwnd;
if (msg == WM_KEYDOWN) {
if (hWnd != m_edit.m_hWnd && ::GetKeyState(VK_CONTROL) < 0) // may be accelerator
return _MTL_TRANSLATE_PASS;
}
else if (msg == WM_SYSKEYDOWN) { // I gave up to add accesskeys to bar
return _MTL_TRANSLATE_PASS;
}
if (IsDialogMessage(pMsg))// is very smart.
return _MTL_TRANSLATE_HANDLE;
return _MTL_TRANSLATE_PASS;
}
// Message map and handlers
BEGIN_MSG_MAP(CDonutClipboardBar)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
COMMAND_ID_HANDLER(IDC_CHECK_CB_ON, OnCheckCommand)
COMMAND_ID_HANDLER(IDC_CHECK_CB_DIRECT, OnCheckCommand)
COMMAND_ID_HANDLER(IDC_CHECK_CB_FLUSH, OnCheckCommand)
COMMAND_ID_HANDLER(IDC_BUTTON_OPEN, OnButtonOpen)
COMMAND_ID_HANDLER(IDC_BUTTON_CB_PASTE, OnButtonPaste)
COMMAND_ID_HANDLER(IDC_BUTTON_DELETE, OnButtonDelete)
COMMAND_ID_HANDLER(IDC_BUTTON_DELETEALL, OnButtonDeleteAll)
COMMAND_ID_HANDLER(IDC_BUTTON_CB_PASTE_DONUT, OnButtonPasteDonut)
COMMAND_ID_HANDLER(IDOK, OnIdOk)
CHAIN_MSG_MAP(CClipboardViewer<CDonutClipboardBar>)
CHAIN_MSG_MAP(CDialogResize<CDonutClipboardBar>)
ALT_MSG_MAP(1) // list box
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLBLButtonDblClk)
END_MSG_MAP()
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
DlgResize_Init(false, true, WS_CLIPCHILDREN);
m_edit.Attach(GetDlgItem(IDC_EDIT_CB_EXT));
m_box.SubclassWindow(GetDlgItem(IDC_LIST_CB_CONT));
_GetProfile();
_SetData();
DoDataExchange(FALSE);
return TRUE;
}
LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
DoDataExchange(TRUE);
_GetData();
_WriteProfile();
return 0;
}
LRESULT OnCheckCommand(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
if (wNotifyCode == BN_CLICKED) {
DoDataExchange(TRUE);
_GetData();
}
return 0;
}
LRESULT OnButtonDelete(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
_MtlForEachListBoxSelectedItem(m_box.m_hWnd, _Function_DeleteString());
return 0;
}
LRESULT OnButtonOpen(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
_MtlForEachListBoxSelectedItem(m_box.m_hWnd, _Function_Open());
return 0;
}
LRESULT OnButtonPaste(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
OnUpdateClipboard();
return 0;
}
LRESULT OnButtonPasteDonut(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
OpenClipboardUrl();
return 0;
}
LRESULT OnButtonDeleteAll(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
m_box.ResetContent();
return 0;
}
LRESULT OnIdOk(WORD wNotifyCode, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
if (::GetFocus() == m_box.m_hWnd)
_MtlForEachListBoxSelectedItem(m_box.m_hWnd, _Function_Open());
return 0;
}
LRESULT OnLBLButtonDblClk(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
{
CPoint pt(LOWORD(lParam), HIWORD(lParam));
BOOL bOutside;
UINT nIndex = m_box.ItemFromPoint(pt, bOutside);
if (!bOutside)
_OnItemOpen(nIndex);
return 0;
}
// Dlg resize map
BEGIN_DLGRESIZE_MAP(CDonutClipboardBar)
DLGRESIZE_CONTROL(IDC_CHECK_CB_ON, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_LIST_CB_CONT, DLSZ_SIZE_X|DLSZ_SIZE_Y)
DLGRESIZE_CONTROL(IDC_BUTTON_OPEN, DLSZ_MOVE_Y|DLSZ_SIZE_X)
BEGIN_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BUTTON_CB_PASTE, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON_DELETE, DLSZ_SIZE_X)
DLGRESIZE_CONTROL(IDC_BUTTON_DELETEALL, DLSZ_SIZE_X)
END_DLGRESIZE_GROUP()
DLGRESIZE_CONTROL(IDC_BUTTON_CB_PASTE_DONUT, DLSZ_SIZE_X|DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_CHECK_CB_DIRECT, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_CHECK_CB_FLUSH, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_STATIC_CB_EXT, DLSZ_MOVE_Y)
DLGRESIZE_CONTROL(IDC_EDIT_CB_EXT, DLSZ_MOVE_Y|DLSZ_SIZE_X)
END_DLGRESIZE_MAP()
// DDX map
BEGIN_DDX_MAP(CDonutClipboardBar)
DDX_TEXT(IDC_EDIT_CB_EXT, m_strExts)
DDX_CHECK(IDC_CHECK_CB_ON, m_nOn)
DDX_CHECK(IDC_CHECK_CB_DIRECT, m_nDirect)
DDX_CHECK(IDC_CHECK_CB_FLUSH, m_nFlush)
END_DDX_MAP()
// Implementation
void _GetData()
{
// update style
m_dwExStyle = 0;
if (m_nOn == 1)
m_dwExStyle |= CLPV_EX_ON;
if (m_nDirect == 1)
m_dwExStyle |= CLPV_EX_DIRECT;
if (m_nFlush == 1)
m_dwExStyle |= CLPV_EX_FLUSH;
if (_check_flag(CLPV_EX_ON, m_dwExStyle))
InstallClipboardViewer();
else
UninstallClipboardViewer();
}
void _SetData()
{
m_nOn = _check_flag(CLPV_EX_ON, m_dwExStyle) ? 1 : 0;
m_nDirect = _check_flag(CLPV_EX_DIRECT, m_dwExStyle) ? 1 : 0;
m_nFlush = _check_flag(CLPV_EX_FLUSH, m_dwExStyle) ? 1 : 0;
}
void _GetProfile()
{
CIniSection pr;
pr.Open(MtlGetChangedExtFromModuleName(_T(".ini")), _T("ClipboardBar"));
pr.QueryValue(m_dwExStyle, _T("Extended_Style"));
DWORD dwCount = 4096;
TCHAR szExts[4096];
if (pr.QueryValue(szExts, _T("Ext_List"), &dwCount) != ERROR_SUCCESS)
::lstrcpyn(szExts, _T("/;html;htm;shtml;cgi;asp;com;net;jp;lnk;url;"), 4096);
m_strExts = szExts;
if (_check_flag(CLPV_EX_ON, m_dwExStyle))
InstallClipboardViewer();
}
void _WriteProfile()
{
CIniSection pr;
pr.Open(MtlGetChangedExtFromModuleName(_T(".ini")), _T("ClipboardBar"));
pr.SetValue(m_dwExStyle, _T("Extended_Style"));
pr.SetValue(m_strExts, _T("Ext_List"));
UninstallClipboardViewer();
}
template <class _Function>
bool _MtlForEachListBoxSelectedItem(CListBox box, _Function __f)
{
int nCount = box.GetSelCount();
if (nCount == 0)
return false;
LPINT rgIndex = (LPINT)_alloca(sizeof(INT)*nCount);
nCount = box.GetSelItems(nCount, rgIndex);
if (nCount == LB_ERR)
return false;
CSimpleArray<int> arrIndex;
for (int i = 0; i < nCount; ++i) {
arrIndex.Add(rgIndex[i]);
}
std::sort(_begin(arrIndex), _end(arrIndex));
for (int j = arrIndex.GetSize() - 1; j >= 0; --j)// from the tail, you can delete it
__f(box.m_hWnd, arrIndex[j], nCount);
return true;
}
struct _Function_DeleteString
{
void operator()(CListBox box, int nIndex, int nCount)
{
box.DeleteString(nIndex);
}
};
struct _Function_Open
{
void operator()(CListBox box, int nIndex, int nCount)
{
CString str;
MtlListBoxGetText(box.m_hWnd, nIndex, str);
if (str.IsEmpty())
return;
DonutOpenFile(box.m_hWnd, str, 0);
}
};
/*
static void _BuildExtArray(CSimpleArray<CString>& arrExt, const CString& strExts)
{
int nFirst = 0;
int nLast = 0;
while (nFirst < strExts.GetLength()) {
nLast = __MtlFindChar(strExts, nFirst, _T(';'));
if (nLast == -1)
nLast = strExts.GetLength();
CString strExt = strExts.Mid(nFirst, nLast - nFirst);
if (!strExt.IsEmpty() && arrExt.Find(strExt) == -1) {
clbTRACE(_T("_BuildExtsArray.Add(%s)\n"), strExt);
arrExt.Add(strExt);
}
nFirst = nLast + 1;
}
}
static void _BuildUrlArray(CSimpleArray<CString>& arrUrl, const CSimpleArray<CString>& arrExt, const CString& strText_)
{
int nFirst = 0;
int nLast = 0;
CString strText = strText_;
strText.Replace(_T("\r"), _T(""));
while (nFirst < strText.GetLength()) {
nLast = __MtlFindChar(strText, nFirst, _T('\n'));
if (nLast == -1)
nLast = strText.GetLength();
CString strPart = strText.Mid(nFirst, nLast - nFirst);
if (!strPart.IsEmpty()) {
CString strExt = _MtlGetExt(strPart, true);
if (_FindExtFromArray(arrExt, strExt)) {
clbTRACE(_T("_BuildUrlArray.Add(%s)\n"), strPart);
arrUrl.Add(strPart);
}
else {
strExt = _MtlGetExt(strPart, false);
if (_FindExtFromArray(arrExt, strExt)) {
clbTRACE(_T("_BuildUrlArray.Add(%s)\n"), strPart);
arrUrl.Add(strPart);
}
else {
strExt = _MtlGetTrailingSeparator(strPart);
if (_FindExtFromArray(arrExt, strExt)) {
clbTRACE(_T("_BuildUrlArray.Add(%s)\n"), strPart);
arrUrl.Add(strPart);
}
}
}
}
nFirst = nLast + 1;
}
}
static bool _FindExtFromArray(const CSimpleArray<CString>& arrExt, const CString& strExt)
{
if (strExt.IsEmpty())
return false;
for (int i = 0; i < arrExt.GetSize(); ++i) {
if (strExt.CompareNoCase(arrExt[i]) == 0)
return true;
}
return false;
}
static CString _MtlGetTrailingSeparator(const CString& strUrl)
{
int nIndex = strUrl.ReverseFind(_T('/'));
if (nIndex == strUrl.GetLength() - 1)
return _T('/');
nIndex = strUrl.ReverseFind(_T('\\'));
if (nIndex == strUrl.GetLength() - 1)
return _T('\\');
return CString();
}
static CString _MtlGetExt(const CString& strUrl, bool bFromLeft)
{
if (strUrl.IsEmpty())
return CString();
int nIndex = -1;
if (bFromLeft) {
int nIndexName = strUrl.ReverseFind(_T('/'));
if (nIndexName == -1)
nIndexName = strUrl.ReverseFind(_T('\\'));
if (nIndexName == -1)
return CString();
nIndex = __MtlFindChar(strUrl, nIndexName, _T('.'));
}
else {
nIndex = strUrl.ReverseFind(_T('.'));
}
if (nIndex == -1)
return CString();
CString str_ = strUrl.Mid(nIndex + 1);
int nLen = str_.GetLength() + 1;
LPTSTR lpsz = (LPTSTR)_alloca(nLen * sizeof(TCHAR));
::lstrcpy(lpsz, str_);
for (LPCTSTR lpszRunner = lpsz; *lpszRunner != _T('\0'); lpszRunner = ::CharNext(lpszRunner)) {
if (!Mtl_isalpha(*lpszRunner))
break;
}
return strUrl.Mid(nIndex + 1, lpszRunner - lpsz);
}
*/
void _OnItemOpen(int nIndex)
{
clbTRACE(_T("_OnItemOpen\n"));
CString str;
MtlListBoxGetText(m_box.m_hWnd, nIndex, str);
if (str.IsEmpty())
return;
DonutOpenFile(m_hWnd, str, 0);
}
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -