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

📄 feedview.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
📖 第 1 页 / 共 3 页
字号:
/**
 *  FeedView.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 "prssr.h"
#include "FeedView.h"

#include "Appearance.h"
#include "Feed.h"
#include "Site.h"
#include "Config.h"
#include "misc.h"
#include "MainFrm.h"
#include "../share/date.h"

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

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

#define CLASS_NAME						_T("FeedViewClass")

#define SCROLL_SLEEP					10
#define SCROLL_SPEED					1
#define SCROLL_MAXSPEED					60

const int CFeedView::LEFT_SKIP = 20;
const int CFeedView::PADDING_TOP = 2;
const int CFeedView::PADDING_RIGHT = 4;
const int CFeedView::PADDING_BOTTOM = 1;
const int CFeedView::ITEM_MARGIN = 22;
const int CFeedView::DATE_HEIGHT = 18;

BOOL CFeedView::Register() {
	// Register your unique class name that you wish to use
	WNDCLASS wndcls;

	memset(&wndcls, 0, sizeof(WNDCLASS));   // start with NULL
											// defaults

	wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;

	//you can specify your own window procedure
	wndcls.lpfnWndProc = ::DefWindowProc;
	wndcls.hInstance = AfxGetInstanceHandle();
	wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
	wndcls.lpszMenuName = NULL;

	// Specify your own class name for using FindWindow later
	wndcls.lpszClassName = CLASS_NAME;

	// Register the new class and exit if it fails
	if (!AfxRegisterClass(&wndcls)) {
		TRACE(_T("Class Registration Failed\n"));
		return FALSE;
	}

	return TRUE;
}

void CFeedView::Unregister() {
}

/////////////////////////////////////////////////////////////////////////////
// CFeedView

CFeedView::CFeedView() {
	m_nTotalHeight = 0;
	m_nViewTop = 0;
	m_nClientHeight = 0;
	m_nClientWidth = 0;

	m_nSelectStart = m_nSelectEnd = -1;		// none
	m_nSelectFirst = -1;
	m_bSelecting = FALSE;

	m_bScrolling = FALSE;

	CtxMenuTimer = 1;
	m_bOpenCtxMenu = FALSE;

	SiteItem = NULL;
}

CFeedView::~CFeedView() {
}


BEGIN_MESSAGE_MAP(CFeedView, CWnd)
	//{{AFX_MSG_MAP(CFeedView)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_VSCROLL()
	ON_WM_SIZE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_WM_KEYDOWN()
	ON_WM_KEYUP()
	//}}AFX_MSG_MAP

	ON_COMMAND(ID_ITEM_OPEN, OnItemOpen)
	ON_COMMAND(ID_ITEM_MARKASREAD, OnItemMarkRead)
	ON_COMMAND(ID_ITEM_MARKASUNREAD, OnItemMarkUnread)
	ON_COMMAND(ID_ITEM_MARKASNEW, OnItemMarkNew)
	ON_COMMAND(ID_ITEM_DELETE, OnItemDelete)

	ON_UPDATE_COMMAND_UI(ID_ITEM_DELETE, OnUpdateItemSelected)
	ON_UPDATE_COMMAND_UI(ID_ITEM_MARKASREAD, OnUpdateItemSelected)
	ON_UPDATE_COMMAND_UI(ID_ITEM_MARKASUNREAD, OnUpdateItemSelected)
	ON_UPDATE_COMMAND_UI(ID_ITEM_MARKASNEW, OnUpdateItemSelected)

	ON_COMMAND(ID_SELECT_ALL, OnSelectAll)

	ON_COMMAND(ID_ITEM_FLAG, OnItemFlag)
	ON_UPDATE_COMMAND_UI(ID_ITEM_FLAG, OnUpdateItemFlag)

	ON_COMMAND(ID_COPY_URL, OnCopyUrl)
	ON_COMMAND(ID_SEND_BY_EMAIL, OnSendByEmail)

	ON_COMMAND(ID_VIEW_HIDEREADITEMS, OnViewHideReadItems)
	ON_UPDATE_COMMAND_UI(ID_VIEW_HIDEREADITEMS, OnUpdateViewHideReadItems)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CFeedView message handlers

void CFeedView::CreateFonts() {
	m_fntSmall.DeleteObject();
	m_fntBase.DeleteObject();
	m_fntBold.DeleteObject();

	HGDIOBJ hSysFont = ::GetStockObject(SYSTEM_FONT);
	LOGFONT lf;
	::GetObject(hSysFont, sizeof(LOGFONT), (LPVOID) &lf);
	lf.lfHeight = SCALEY(11) + 1;
	m_fntSmall.CreateFontIndirect(&lf);

	wcscpy(lf.lfFaceName, Appearance.FeedViewFontCfg.FontFace);
	CDC *pDC = GetDC();
	lf.lfHeight = ((Appearance.FeedViewFontCfg.Size * pDC->GetDeviceCaps(LOGPIXELSY)) / 72) + 1;
	m_fntBase.CreateFontIndirect(&lf);

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

	ReleaseDC(pDC);
}

int CFeedView::OnCreate(LPCREATESTRUCT lpCreateStruct) {
	LOG1(3, "CFeedView::OnCreate(%p)", lpCreateStruct);

	BOOL ret = CWnd::OnCreate(lpCreateStruct);
	if (ret == -1)
		return -1;

	CreateFonts();

	// icons
	AfxSetResourceHandle(theApp.GetDPISpecificInstanceHandle());
	m_oIcons.Create(IDB_NEWS_ITEMS, SCALEX(16), 0, RGB(255, 0, 255));
	AfxSetResourceHandle(AfxGetInstanceHandle());

	// scroll bar
	CRect rcVert;
	m_oVScrollBar.Create(SBS_VERT | WS_CHILD, rcVert, this, 1);

	UpdateScrollBars();

	return ret;
}

void CFeedView::SelectAll() {
	LOG0(3, "CFeedView::SelectAll()");

	m_nSelectFirst = m_nSelectStart = 0;
	m_nSelectEnd = m_oItems.GetSize();
	Invalidate(FALSE);
}

void CFeedView::SelectItem(int item) {
	if (item >= 0 && item < m_oItems.GetSize()) {
		m_nSelectFirst = m_nSelectStart = m_nSelectEnd = item;
		Invalidate(FALSE);
	}
}

void CFeedView::DeleteItem(int idx) {
	LOG1(1, "CFeedView::DeleteItem(%d)", idx);

	if (idx >= 0  && idx < m_oItems.GetSize()) {
		m_oItems.RemoveAt(idx);

		if (idx <= m_nSelectStart) m_nSelectStart--;
		if (idx <= m_nSelectEnd) m_nSelectEnd--;
		if (idx <= m_nSelectFirst) m_nSelectFirst--;

		AdjustViewTop();
		UpdateItemHeights();
		UpdateScrollBars();
		Invalidate();
	}
}

void CFeedView::DeleteAllItems() {
	LOG0(1, "CFeedView::DeleteAllItems()");

	m_oItems.RemoveAll();
	m_oItemHeight.RemoveAll();
	Invalidate();

	m_nTotalHeight = 0;
	m_nViewTop = 0;
	m_nSelectStart = m_nSelectEnd = m_nSelectFirst = -1;
}

BOOL CFeedView::InsertItem(int i, CFeedItem *item) {
	LOG2(1, "CFeedView::InsertItem(%d, %p)", i, item);

	if (item->IsDeleted())
		return FALSE;
	else {
		m_oItems.SetAtGrow(i, item);
		int ht = CalcItemHeight(i);
		m_nTotalHeight += ht;
		m_oItemHeight.SetAtGrow(i, m_nTotalHeight);
		return TRUE;
	}
}

void CFeedView::EnsureVisible(int item) {
	LOG1(1, "CFeedView::EnsureVisible(%d)", item);

	int y;
	if (item > 0) y = m_oItemHeight[item - 1];
	else y = 0;

	if (m_nViewTop <= y && m_oItemHeight[item] <= m_nViewTop + m_nClientHeight) {
	}
	else {
		m_nViewTop = y;
		AdjustViewTop();
		UpdateScrollBars();
	}
}

void CFeedView::DeselectAllItems() {
	LOG0(1, "CFeedView::DeselectAllItems()");

	m_nSelectStart = m_nSelectEnd = m_nSelectFirst = -1;
	Invalidate();
}

void CFeedView::MarkItem(int item, DWORD mask) {
	CFeedItem *fi = m_oItems.GetAt(item);
	fi->SetFlags(mask, MESSAGE_READ_STATE);

	CMainFrame *frame = (CMainFrame *) AfxGetMainWnd();
	frame->SyncItem(fi);
}

void CFeedView::MarkAllRead() {
	LOG0(1, "CFeedView::MarkAllRead()");

	for (int i = 0; i < m_oItems.GetSize(); i++)
		MarkItem(i, MESSAGE_READ);

	if (SiteItem != NULL) {
		if (SiteItem->Type == CSiteItem::VFolder && SiteItem->FlagMask == MESSAGE_READ_STATE)
			DeleteAllItems();
		else if (SiteItem->Type != CSiteItem::VFolder && Config.HideReadItems)
			DeleteAllItems();
	}

	AdjustViewTop();

	DeselectAllItems();
	SortItems();
	UpdateScrollBars();
	Invalidate(TRUE);
}

void CFeedView::MarkAllUnread() {
	LOG0(1, "CFeedView::MarkAllUnread()");

	for (int i = 0; i < m_oItems.GetSize(); i++)
		MarkItem(i, MESSAGE_UNREAD);

	AdjustViewTop();

	DeselectAllItems();
	SortItems();
	UpdateScrollBars();
	Invalidate(TRUE);
}


void CFeedView::MarkAllUnflagged() {
	LOG0(1, "CFeedView::MarkAllUnflagged()");

	for (int i = 0; i < m_oItems.GetSize(); i++)
		UnflagItem(i);

	AdjustViewTop();

	DeselectAllItems();
	SortItems();
	UpdateScrollBars();
	Invalidate(TRUE);
}

//
//
//

void CFeedView::AdjustViewTop() {
	if (m_nViewTop < 0 || m_nTotalHeight < m_nClientHeight)
		m_nViewTop = 0;
	else if (m_nTotalHeight > m_nClientHeight) {
		int max = m_nTotalHeight - m_nClientHeight;
		if (m_nViewTop > max)
			m_nViewTop = max;
	}
}

void CFeedView::DrawIcon(CDC &dc, int icon, BOOL selected, int xofs/* = 0*/, int yofs/* = 0*/) {
	IMAGELISTDRAWPARAMS drawing;
	drawing.cbSize = sizeof(IMAGELISTDRAWPARAMS);
	drawing.himl = m_oIcons.GetSafeHandle();
	drawing.i = icon;
	drawing.hdcDst = dc.GetSafeHdc();
	drawing.x = SCALEX(1) + SCALEX(xofs);
	drawing.y = SCALEY(2) + SCALEX(yofs);
	drawing.cx = SCALEX(16);
	drawing.cy = SCALEY(16);
	drawing.xBitmap = 0;
	drawing.yBitmap = 0;
	drawing.rgbBk = CLR_NONE;
	drawing.rgbFg = CLR_DEFAULT;
	if (selected)
		drawing.fStyle = ILD_BLEND50;
	else
		drawing.fStyle = ILD_NORMAL;
	drawing.dwRop = SRCCOPY;
	ImageList_DrawIndirect(&drawing);
}

void CFeedView::DrawItem(CDC &dc, CRect &rc, int idx) {
	CFeedItem *item = m_oItems[idx];

	BOOL selected = (m_nSelectStart <= idx) && (idx <= m_nSelectEnd);

	COLORREF clrBg, clrFg, clrOld;
	if (selected) {
		clrBg = ::GetSysColor(COLOR_HIGHLIGHT);
		clrFg = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
	}
	else {
		clrBg = Appearance.ClrFeedViewBg;

		if (item->IsNew() || item->IsUnread())
			clrFg = Appearance.ClrFeedViewFg;
		else
			clrFg = ::GetSysColor(COLOR_3DSHADOW);
	}

	// background
	dc.FillSolidRect(rc, clrBg);

	int oldBkMode = dc.SetBkMode(TRANSPARENT);

	// icon
	if (item->IsNew())
		DrawIcon(dc, NEW_FEED_ICON, selected);
	else if (item->IsUnread())
		DrawIcon(dc, UNREAD_FEED_ICON, selected);
	else
		DrawIcon(dc, READ_FEED_ICON, selected);

	// has html cached
	if (IsHTMLCached(item->Link, TRUE)) {
		if (item->IsNew() || item->IsUnread())
			DrawIcon(dc, CACHED_ITEM_ICON, selected);
		else
			DrawIcon(dc, NOT_CACHED_ITEM_ICON, selected);
	}

	if (item->HasEnclosure()) {
		CEnclosureItem *ei = item->Enclosures.GetHead();
		if (IsEnclosureCached(ei->URL))
			DrawIcon(dc, CACHED_ITEM_ICON, selected);
		else
			DrawIcon(dc, NOT_CACHED_ITEM_ICON, selected);
	}

	// keyword
	if (item->HasKeywordMatch())
		DrawIcon(dc, KEYWORD_ICON, selected);

	// flagged?
	if (item->IsFlagged())
		DrawIcon(dc, FLAG_ICON, selected);

	// title
	CFont *pOldFont;
	pOldFont = dc.SelectObject(&m_fntBold);
	clrOld = dc.SetTextColor(clrFg);
	CRect rcTitle = rc;
	rcTitle.DeflateRect(SCALEX(LEFT_SKIP), SCALEY(PADDING_TOP), SCALEX(PADDING_RIGHT), SCALEY(PADDING_BOTTOM));

	CString strTitle = item->Title;
	ReplaceHTMLEntities(strTitle);
	if (m_bWrapTitles) {
		dc.DrawText(strTitle, &rcTitle, DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK);

	}
	else
		DrawTextEndEllipsis(dc, strTitle, rcTitle, DT_LEFT | DT_TOP | DT_NOPREFIX);
	dc.SetTextColor(clrOld);
	dc.SelectObject(pOldFont);

	// date
	if (item->PubDate.wYear != 0) {
		pOldFont = dc.SelectObject(&m_fntSmall);

		CString sTime;
		SYSTEMTIME st = TimeToTimeZone(&item->PubDate);		// convert to local time zone
		FormatDateTime(sTime, st, Config.ShowRelativeDates);

		CRect rcTime = rc;
		rcTime.left = rcTitle.left;
		rcTime.bottom -= SCALEY(3);
		rcTime.right -= SCALEX(3);
		if (selected)
			clrOld = dc.SetTextColor(clrFg);
		else
			clrOld = dc.SetTextColor(Appearance.ClrDate);
		dc.DrawText(sTime, &rcTime, DT_LEFT | DT_BOTTOM | DT_NOPREFIX);
		dc.SetTextColor(clrOld);

		dc.SelectObject(pOldFont);
	}

	// draw separator
	CPen pen(PS_SOLID, 1, ::GetSysColor(COLOR_3DSHADOW));
	CPen *oldPen = dc.SelectObject(&pen);
	dc.MoveTo(rc.left, rc.bottom - 1);
	dc.LineTo(rc.right, rc.bottom - 1);
	dc.SelectObject(oldPen);

	dc.SetBkMode(oldBkMode);
}

void CFeedView::InvalidateItem(int idx, BOOL erase/* = TRUE*/) {
	if (idx >= 0 && idx < m_oItems.GetSize()) {
		CRect rcClient;
		GetClientRect(rcClient);

		int top;
		if (idx > 0) top = m_oItemHeight[idx - 1];
		else top = 0;
		CRect rc(rcClient.left, top - m_nViewTop, rcClient.right, m_oItemHeight[idx] - m_nViewTop);
		InvalidateRect(rc, erase);
	}
}

void CFeedView::OnDraw(CDC *pDC) {
}

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

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

	int nSavedDC = dc.SaveDC();

	CRect rc;
	GetClientRect(rc);

	if (m_oItems.GetSize() > 0) {
		CRect rcClip;
		dc.GetClipBox(rcClip);

		if (m_oVScrollBar.IsWindowVisible()) {
			CRect rcVScroll;
			m_oVScrollBar.GetWindowRect(rcVScroll);
			rc.right -= rcVScroll.Width() - SCALEX(1);
		}

		int y = rc.top;

		int first = 0;
		for (; first < m_oItems.GetSize(); first++)
			if (m_oItemHeight[first] > m_nViewTop)
				break;
		int ofsY;
		if (first > 0) ofsY = m_nViewTop - m_oItemHeight[first - 1];
		else ofsY = m_nViewTop;

		for (int idx = first; idx < m_oItems.GetSize() && y < rc.bottom; idx++) {
			int wd = rc.Width();
			int ht;
			if (idx > 0) ht = m_oItemHeight[idx] - m_oItemHeight[idx - 1];
			else ht = m_oItemHeight[idx];

			CBitmap bmp;
			bmp.CreateCompatibleBitmap(&dc, wd, ht);

			CDC memDC;
			memDC.CreateCompatibleDC(&dc);
			CBitmap *saveBmp = memDC.SelectObject(&bmp);

			CRect rcPhys(rc.left, y, rc.right, y + ht);
			CRect rcDraw;
			if (rcDraw.IntersectRect(rcClip, rcPhys)) {
				CRect rcMsg(rc.left, 0, rc.right, ht);
				DrawItem(memDC, rcMsg, idx);

				// copy to screen
				dc.BitBlt(0, y, wd, ht - ofsY, &memDC, 0, ofsY, SRCCOPY);
			}

⌨️ 快捷键说明

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