⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 todaypluginwnd.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
/**
 *  TodayPluginWnd.cpp
 *
 *  Copyright (C) 2008  David Andrs <pda@jasnapaka.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


#include "StdAfx.h"
#include "prssrtoday.h"
#include "TodayPluginWnd.h"

#include "todaycmn.h"
#include "Config.h"
#include "../prssr/ctrls/CePropertySheet.h"
#include "OptChannelsPg.h"
#include "OptAppearancePg.h"
#include "OptModePg.h"

#include "../prssr/xml/FeedFile.h"
#include "../share/helpers.h"

#include "../share/defs.h"
#include "../share/reg.h"
#include "../share/wnd.h"
#include "../share/date.h"
#include "../share/fs.h"

#ifdef MYDEBUG
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#include "../prssr/debug/crtdbg.h"
#define new MYDEBUG_NEW
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define FILE_CHANGE_NOT_EXISTS              0
#define FILE_CHANGE_NO_CHANGE				1
#define FILE_CHANGE_UDPATED					2

#define CONFIG_DEFAULT_FONT_SIZE			9
#define LINE_SPACING						2

//int CyclingSpeed[] = { 1000, 2500, 5000, 7500, 10000 };


UINT				WM_SH_UIMETRIC_CHANGE;
UINT				ReadConfigMessage;
UINT				CheckFeedsMessage;
UINT				UpdateFeedFlagsMessage;
UINT				ReloadSubscriptionsMessage;

CTodayPluginWnd		TodayPluginWnd;

BOOL APIENTRY CustomItemOptionsDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam);

DWORD WINAPI ThreadStubProc(LPVOID lpPar) {
	CTodayPluginWnd *plugin = (CTodayPluginWnd *) lpPar;
	return plugin->Thread();
}

/////////////////////////////////////////////////////////////////////////////
// CTodayPluginWnd

CTodayPluginWnd::CTodayPluginWnd() {
	ItemIdx = 0;
	SiteIdx = -1;

	HThread = NULL;

	CycleTimer = 1;
	TapAndHoldTimer = 2;

	FileCheckIdx = 0;

	InitializeCriticalSection(&CSSiteList);
	HTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
	HReloadSubscriptions = CreateEvent(NULL, FALSE, FALSE, NULL);
	HCheckFeeds = CreateEvent(NULL, FALSE, FALSE, NULL);
	HUpdateFeedFlags = CreateEvent(NULL, FALSE, FALSE, NULL);
}

CTodayPluginWnd::~CTodayPluginWnd() {
	SiteList.Destroy();

	DeleteCriticalSection(&CSSiteList);
	CloseHandle(HTerminate);
	CloseHandle(HReloadSubscriptions);
	CloseHandle(HCheckFeeds);
	CloseHandle(HUpdateFeedFlags);
}


BEGIN_MESSAGE_MAP(CTodayPluginWnd, CWnd)
	//{{AFX_MSG_MAP(CTodayPluginWnd)
	ON_WM_ERASEBKGND()
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_COMMAND(ID_TODAY_BRIEF, OnTodayBrief)
	ON_COMMAND(ID_TODAY_CYCLING, OnTodayCycling)
	ON_COMMAND(ID_TODAY_UPDATEALL, OnTodayUpdateall)
	ON_COMMAND(ID_TODAY_SETTINGS, OnTodaySettings)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CTodayPluginWnd message handlers

BOOL CTodayPluginWnd::Register() {
	Unregister();

	WNDCLASS wc;
	memset(&wc, 0, sizeof(wc));

	wc.style		 = 0;
	wc.lpfnWndProc	 = (WNDPROC) ::DefWindowProc;
	wc.hInstance	 = AfxGetInstanceHandle();
	wc.hIcon		 = 0;
	wc.hCursor		 = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
	wc.lpszClassName = TODAY_CLASS_NAME;

	// register our window
	if (!AfxRegisterClass(&wc)) {
		TRACE(_T("Class Registration Failed\n"));
		return FALSE;
	}


	WM_SH_UIMETRIC_CHANGE = RegisterWindowMessage(SH_UIMETRIC_CHANGE);
	ReadConfigMessage = RegisterWindowMessage(READ_CONFIG_MESSAGE);
	ReloadSubscriptionsMessage = RegisterWindowMessage(RELOAD_SUBSCRIPTIONS_MESSAGE);
	CheckFeedsMessage = RegisterWindowMessage(CHECK_FEEDS_MESSAGE);
	UpdateFeedFlagsMessage = RegisterWindowMessage(UPDATE_FEED_FLAGS_MESSAGE);

	return TRUE;
}

BOOL CTodayPluginWnd::Unregister() {
	UnregisterClass(TODAY_CLASS_NAME, AfxGetInstanceHandle());
	return TRUE;
}


void CTodayPluginWnd::LoadFonts() {
	LOG0(5, "CTodayPluginWnd::LoadFonts()");

	m_fntNormal.DeleteObject();
	m_fntBold.DeleteObject();

	LONG dwFontSize;
	if (Config.FontSize == -1) {
		dwFontSize = SCALEY(CONFIG_DEFAULT_FONT_SIZE);
		CDC *pDC = GetDC();
		SHGetUIMetrics(SHUIM_FONTSIZE_PIXEL, &dwFontSize, sizeof(dwFontSize), NULL);
		ReleaseDC(pDC);
	}
	else {
		dwFontSize = SCALEY(Config.FontSize);
	}

	HGDIOBJ hObj = ::GetStockObject(SYSTEM_FONT);
	LOGFONT lf;
	::GetObject(hObj, sizeof(LOGFONT), (LPVOID) &lf);
	lf.lfHeight = -dwFontSize;
	m_fntNormal.CreateFontIndirect(&lf);

	RowHeight = (int) (1.2 * dwFontSize);

	lf.lfWeight = FW_BOLD;
	m_fntBold.CreateFontIndirect(&lf);
}

BOOL CTodayPluginWnd::Create(HWND hwndParent) {
	LOG1(5, "CTodayPluginWnd::Create(%x)", hwndParent);

	m_hWndParent = hwndParent;
	BOOL ret = CreateEx(0, TODAY_CLASS_NAME, TODAY_WINDOW_NAME, WS_VISIBLE | WS_CHILD,
		0, 0, GetSystemMetrics(SM_CXSCREEN), 0, hwndParent, (HMENU) 0x1234);

	// load the font
	LoadFonts();

	HIcon = (HICON) ::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_DISPLAYICON), IMAGE_ICON, SCALEX(16), SCALEX(16), 0);

	EnterCriticalSection(&CSSiteList);
//	LoadSiteList(SiteList);
	if (SiteList.GetCount() > 0)
		SiteIdx = 0;
	else
		SiteIdx = -1;
	LeaveCriticalSection(&CSSiteList);

//	SetTimer(CycleTimer, CyclingSpeed[Config.CyclingSpeedIdx], NULL);
	SetTimer(CycleTimer, Config.CyclingSpeed * 1000, NULL);

	return TRUE;
}

void CTodayPluginWnd::OnDestroy() {
	LOG0(5, "CTodayPluginWnd::OnDestroy()");

	SetEvent(HTerminate);
	if (WaitForSingleObject(HThread, 4000) == WAIT_OBJECT_0) {
	}

	CWnd::OnDestroy();

	KillTimer(CycleTimer);
	KillTimer(TapAndHoldTimer);

	DestroyIcon(HIcon); HIcon = NULL;
	m_fntNormal.DeleteObject();
	m_fntBold.DeleteObject();
}

BOOL CTodayPluginWnd::OnEraseBkgnd(CDC* pDC) {
	LOG1(5, "CTodayPluginWnd::OnEraseBkgnd(%x)", pDC);

	TODAYDRAWWATERMARKINFO dwi;
	dwi.hwnd = GetSafeHwnd();
	dwi.hdc = pDC->GetSafeHdc();
	GetClientRect(&dwi.rc);
	::SendMessage(m_hWndParent, TODAYM_DRAWWATERMARK, 0, (LPARAM) &dwi);

	return TRUE;
}


int CTodayPluginWnd::DrawSiteTitle(CDC &dc, CSiteItem *si, CRect *rc, UINT uFormat) {
	LOG2(5, "CTodayPluginWnd::DrawSiteTitle(, %p, , %d)", si, uFormat);

	int nNewCount = si->GetUnreadCount();
	CString strTitle = si->Name;
	ReplaceHTMLEntities(strTitle);

	CString buffer;
	if (nNewCount > 0)
		buffer.Format(_T("%s (%d)"), strTitle, nNewCount);
	else
		buffer.Format(_T("%s"), strTitle);

	int nWidth = rc->Width();

	CRect rcTemp = *rc;
	dc.DrawText(buffer, &rcTemp, uFormat | DT_CALCRECT);
	if (rcTemp.Width() > nWidth) {
		// Text doesn't fit in rect. We have to truncate it and add ellipsis to the end.
		for (int i = strTitle.GetLength(); i >= 0; i--) {
			CString strName = strTitle.Left(i);

			if (nNewCount > 0)
				buffer.Format(_T("%s... (%d)"), strName, nNewCount);
			else
				buffer.Format(_T("%s..."), strName);

			rcTemp = *rc;
			dc.DrawText(buffer, &rcTemp, uFormat | DT_CALCRECT);
			if (rcTemp.Width() < nWidth) {
				// Gotcha!
				break;
			}
		}
		return dc.DrawText(buffer, rc, uFormat);
	}
	return dc.DrawText(buffer, rc, uFormat);
}

void CTodayPluginWnd::DrawMessage(CDC &dc, CRect &rect, UINT nID) {
	// no news
	CString strNoNews;
	strNoNews.LoadString(nID);

	dc.SelectObject(m_fntNormal);
	dc.DrawText(strNoNews, &rect, DT_LEFT | DT_TOP);
}

void CTodayPluginWnd::DrawBrief(CDC &dc, CRect &rcLabel) {
	LOG0(5, "CTodayPluginWnd::DrawBrief()");

	// only brief view
	if (NewItems == 0 && UnreadItems == 0) {
		DrawMessage(dc, rcLabel, IDS_NO_NEWS);
	}
	else {
		CString strText;
		if (NewItems > 0) {
			if (UnreadItems > 0)
				strText.Format(IDS_NEW_UNREAD_ITEMS, NewItems, UnreadItems);
			else
				strText.Format(IDS_NEW_ITEMS, NewItems);
		}
		else
			strText.Format(IDS_UNREAD_ITEMS, UnreadItems);
		dc.SelectObject(m_fntBold);
		dc.DrawText(strText, &rcLabel, DT_LEFT | DT_TOP);
	}
}

void CTodayPluginWnd::DrawCycling(CDC &dc, CRect &rcLabel) {
	dc.SelectObject(m_fntBold);
	CSiteItem *si = SiteList.GetAt(SiteIdx);

	switch (Config.CyclingSubMode) {
		case CYCLING_SUBMODE_SITES:
			DrawSiteTitle(dc, si, &rcLabel, DT_LEFT | DT_TOP);
			break;

		case CYCLING_SUBMODE_FEED_ITEMS:
			// show site name
			if (Config.ShowSiteName) {
				DrawSiteTitle(dc, si, &rcLabel, DT_LEFT | DT_TOP);

				CPen pen(PS_SOLID, 1, RGB(255, 255, 255));
				dc.SelectObject(pen);
				POINT ln[2] = {
					{ rcLabel.left, rcLabel.top + RowHeight + SCALEY(2) },
					{ rcLabel.right, rcLabel.top + RowHeight + SCALEY(2) }
				};
				dc.Polyline(ln, 2);

				rcLabel.top += RowHeight + SCALEY(2) + SCALEY(2);
				rcLabel.bottom += RowHeight + SCALEY(2) + SCALEY(2);
			}
			dc.SelectObject(m_fntNormal);

			// show feed item
			if (si->Feed != NULL &&
				ItemIdx >= 0 && ItemIdx < si->Feed->GetItemCount())
			{
				CFeedItem *fi = si->Feed->GetItem(ItemIdx);

				dc.SelectObject(m_fntNormal);

				CString sFeedTitle = fi->Title;
				ReplaceHTMLEntities(sFeedTitle);
				DrawTextEndEllipsis(dc, sFeedTitle, rcLabel, DT_LEFT | DT_TOP | DT_NOPREFIX);

				if (Config.ShowDateTime) {
					rcLabel.top += RowHeight;
					rcLabel.bottom += RowHeight;

					CString strDateTime;
					SYSTEMTIME st = { 0 };
					if (fi->PubDate.wYear != 0) {
//						if (Config.GMTTimes)
//							st = fi->PubDate;		// leave at GMT
//						else
							st = TimeToTimeZone(&fi->PubDate);		// convert to local time zone
					}
					if (!FormatDateTime(strDateTime, st, Config.ShowRelativeDates))
						strDateTime.Empty();
					dc.DrawText(strDateTime, &rcLabel, DT_LEFT | DT_TOP);
				}
			}
			else {
				DrawMessage(dc, rcLabel, IDS_NO_NEWS);
			}
			break;

		default:
			DrawMessage(dc, rcLabel, IDS_NO_NEWS);
			break;
	}
}

void CTodayPluginWnd::OnPaint() {
	LOG0(5, "CTodayPluginWnd::OnPaint()");

	CPaintDC dc(this); // device context for painting

	int saveDC = dc.SaveDC();

	CRect rcClient;
	GetClientRect(&rcClient);

	// Get appropriate text color from shell
	COLORREF crText;

	if (Selected) {
		COLORREF clrBkgnd = GetParent()->SendMessage(TODAYM_GETCOLOR, (WPARAM) TODAYCOLOR_HIGHLIGHT, NULL);
		CBrush brush(clrBkgnd);
		dc.FillRect(&rcClient, &brush);

		crText = GetParent()->SendMessage(TODAYM_GETCOLOR, (WPARAM) TODAYCOLOR_HIGHLIGHTEDTEXT, NULL);
	}
	else {
		crText = GetParent()->SendMessage(TODAYM_GETCOLOR, (WPARAM) TODAYCOLOR_TEXT, NULL);
	}

	// Important if you want the watermark behind the text
	dc.SetBkMode(TRANSPARENT);
	dc.SetTextColor(crText);

	CRect rcLabel = rcClient;
	rcLabel.top += SCALEY(Config.VOffset);
	rcLabel.left += SCALEX(4);
	rcLabel.right -= SCALEX(4);

	if (Loading) {
		if (Config.DisplayIcon) {
			DrawIconEx(dc.GetSafeHdc(), SCALEX(2), SCALEY(2), HIcon, SCALEX(16), SCALEY(16), 0, NULL, DI_NORMAL);
			rcLabel.left += SCALEX(24);
		}

		DrawMessage(dc, rcLabel, IDS_LOADING);
	}
	else {
		BOOL bNewsAvailable = NewsAvailable();
		if (bNewsAvailable || !Config.HidePlugin) {
			if (Config.DisplayIcon) {
				DrawIconEx(dc.GetSafeHdc(), SCALEX(2), SCALEY(2), HIcon, SCALEX(16), SCALEY(16), 0, NULL, DI_NORMAL);
				rcLabel.left += SCALEX(24);
			}

			if (Config.Mode == MODE_BRIEF)
				DrawBrief(dc, rcLabel);
			else if (Config.Mode == MODE_CYCLING) {
				if (SiteIdx != -1 && bNewsAvailable)
					DrawCycling(dc, rcLabel);
				else
					DrawMessage(dc, rcLabel, IDS_NO_NEWS);
			}
		}
	}

	ValidateRect(rcClient);

	dc.RestoreDC(saveDC);
	// Do not call CWnd::OnPaint() for painting messages
}

void CTodayPluginWnd::OnAction() {
	LOG0(1, "CTodayPluginWnd::OnAction()");

	switch (Config.Mode) {
		case MODE_BRIEF:
			OpenReader();
			break;

		case MODE_CYCLING:
			if (SiteIdx != -1) {
				if (Config.CyclingSubMode == CYCLING_SUBMODE_FEED_ITEMS)
					OpenReaderFeedItem(SiteIdx, ItemIdx);
				else
					OpenReaderSite(SiteIdx);
			}
			else
				OpenReader();
			break;
	}
}

BOOL CTodayPluginWnd::OnQueryRefreshCache(TODAYLISTITEM *ptli) {
	LOG1(5, "CTodayPluginWnd::OnQueryRefreshCache(%p)", ptli);

	if (ptli == NULL)
		return FALSE;

	Config.LoadSharedConfig();

	if (HThread == NULL) {
		HThread = CreateThread(NULL, 0, ThreadStubProc, this, 0, NULL);
	}

	BOOL fRet = FALSE;

	// calc height
	RECT rcClient;
	GetClientRect(&rcClient);

	UINT nMinHeight = (UINT) SCALEY(20);

	UINT nHeight = nMinHeight;
	BOOL bNewsAvailable = NewsAvailable();
	switch (Config.Mode) {
		case MODE_BRIEF:
			nHeight = (UINT) SCALEY(2 * Config.VOffset) + RowHeight;
			break;

		case MODE_CYCLING:
			nHeight = (UINT) SCALEY(2 * Config.VOffset) + RowHeight;
			if (bNewsAvailable) {
				if (Config.CyclingSubMode == CYCLING_SUBMODE_FEED_ITEMS) {
					if (Config.ShowSiteName)
						nHeight += RowHeight + SCALEY(2) + SCALEY(2) + SCALEY(1);

					if (Config.ShowDateTime)
						nHeight += RowHeight;
				}
			}
			break;
	}

	// ensure minimal height
	if (nHeight < nMinHeight)
		nHeight = nMinHeight;

	// don't show the plugin if there are no news items
	if (!bNewsAvailable && Config.HidePlugin)
		nHeight = -1;

	if (nHeight != ptli->cyp) {
		ptli->cyp = nHeight;
		fRet = TRUE;
	}

	return fRet;
}

void CTodayPluginWnd::OnClearCache(TODAYLISTITEM *ptli) {
	LOG1(5, "CTodayPluginWnd::OnClearCache(%p)", ptli);

	InvalidateRect(NULL, TRUE);
}

LRESULT CTodayPluginWnd::OnUIMetricChange(WPARAM wParam, LPARAM lParam) {
	LOG0(5, "CTodayPluginWnd::OnUIMetricChange()");

	LoadFonts();
	InvalidateRect(NULL, TRUE);
	return 0;
}

void CTodayPluginWnd::OnReadConfig() {
	LOG0(5, "CTodayPluginWnd::OnReadConfig()");

	Config.LoadSharedConfig();
}

void CTodayPluginWnd::OnLButtonDown(UINT nFlags, CPoint point) {
	LOG0(5, "CTodayPluginWnd::OnLButtonDown()");

	SetCapture();
	// only on VGA displays
	CDC *pDC = GetDC();
	if (pDC->GetDeviceCaps(LOGPIXELSX) > 130)
		Selected = TRUE;
	ReleaseDC(pDC);
	GetParent()->PostMessage(TODAYM_TOOKSELECTION, (WPARAM) GetSafeHwnd(), 0);

	LastCursorPos = point;

	KillTimer(TapAndHoldTimer);	// for sure
	SetTimer(TapAndHoldTimer, 100, NULL);

//	CWnd::OnLButtonDown(nFlags, point);
}

void CTodayPluginWnd::OnLButtonUp(UINT nFlags, CPoint point) {
	LOG0(5, "CTodayPluginWnd::OnLButtonUp()");

	Selected = FALSE;
	ReleaseCapture();
	KillTimer(TapAndHoldTimer);

	CRect rc;
	GetClientRect(&rc);
	if (rc.PtInRect(point)) {
		// if user taps icon -> open config

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -