?? articleview.cpp.svn-base
字號:
/**
* ArticleView.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 "../share/UIHelper.h"
#include "ArticleView.h"
#include "../share/date.h"
#include "../share/fs.h"
#include "../share/str.h"
#include "misc.h"
#include "Config.h"
#include "Feed.h"
#include "MainFrm.h"
#include "Appearance.h"
#include "Errors.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
static DWORD MakeRGBVal(COLORREF clr) {
return (GetRValue(clr) << 16) | (GetGValue(clr) << 8) | GetBValue(clr);
}
///
void OpenOnlineMessage(const CString &link, CSiteItem *si) {
LOG1(1, "OpenOnlineMessage('%S')", link);
CString url = SanitizeUrl(link);
if (IsHTMLCached(url, TRUE)) {
CString fileName = UrlToFileName(MakeAbsoluteUrl(url, _T(""), _T("")), TRUE);
CString path = GetCachePath(FILE_TYPE_HTML, Config.CacheLocation);
url = MakeOfflineUrl(path, fileName);
}
else {
// first try to rewrite the URL
if (Config.UseHtmlOptimizer && Config.OpenMsgWithHtmlOptimizer) url = MakeHtmlOptimizerUrl(url, Config.HtmlOptimizerURL);
else url = RewriteUrl(url, Config.RewriteRules);
}
OpenUrlExt(url);
}
///////
/////////////////////////////////////////////////////////////////////////////
// CArticleView dialog
CArticleView::CArticleView() {
//{{AFX_DATA_INIT(CArticleView)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
HotSpot = FALSE;
m_pArticle = NULL;
InFullScreen = FALSE;
}
CArticleView::~CArticleView() {
delete m_pArticle;
}
BEGIN_MESSAGE_MAP(CArticleView, CHTMLCtrl)
//{{AFX_MSG_MAP(CArticleView)
ON_WM_INITMENUPOPUP()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_HOTKEY, OnHotKey)
ON_COMMAND(ID_ITEM_FLAG, OnItemFlag)
ON_UPDATE_COMMAND_UI(ID_ITEM_FLAG, OnUpdateItemFlag)
ON_COMMAND(ID_ITEM_OPEN, OnItemOpen)
ON_COMMAND(ID_REFRESH, OnRefresh)
ON_COMMAND(ID_COPY_URL, OnCopyUrl)
ON_COMMAND(ID_EDIT_COPY, OnCopy)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateCopy)
ON_COMMAND(ID_ENCLOSURE_OPEN, OnEnclosureOpen)
ON_UPDATE_COMMAND_UI(ID_ENCLOSURE_OPEN, OnUpdateEnclosureOpen)
ON_COMMAND(ID_ENCLOSURE_GET, OnEnclosureGet)
ON_UPDATE_COMMAND_UI(ID_ENCLOSURE_GET, OnUpdateEnclosureGet)
ON_COMMAND(ID_ENCLOSURE_DELETE, OnEnclosureDelete)
ON_UPDATE_COMMAND_UI(ID_ENCLOSURE_DELETE, OnUpdateEnclosureDelete)
ON_COMMAND(ID_OPEN_LINK, OnLinkOpen)
ON_COMMAND(ID_DOWNLOAD_LINK, OnLinkDownload)
ON_COMMAND_RANGE(ID_SOCIAL_BOOKMARK_BASE, ID_SOCIAL_BOOKMARK_BASE + 100, OnBookmarkLink)
ON_COMMAND(ID_SEND_BY_EMAIL, OnSendByEmail)
ON_COMMAND(ID_FULLSCREEN, OnFullscreen)
ON_UPDATE_COMMAND_UI(ID_FULLSCREEN, OnUpdateFullscreen)
ON_COMMAND(ID_VIEW_IMAGE, OnViewImage)
ON_COMMAND(ID_COPY_IMAGE_LOCATION, OnCopyImageLocation)
END_MESSAGE_MAP()
void CArticleView::SetFeedItem(CFeedItem *fi) {
delete m_pArticle;
m_pArticle = new CFeedItem(*fi);
}
void CArticleView::ShowArticle() {
LOG0(1, "CArticleView::ShowFeedItem()");
// // reposition controls before displaying the article (enclosure bar may get hidden or visible)
// ResizeControls();
CString sText, sTemp;
::SendMessage(GetSafeHwnd(), WM_SETTEXT, 0, (LPARAM) (LPCTSTR) _T(""));
Clear();
EnableContextMenu(TRUE);
EnableClearType(Appearance.ClearType);
EnableScripting(FALSE);
ZoomLevel(1);
AddText(L"<html>");
AddText(L"<head>");
CString strCSS;
strCSS.Format(
L"<style type=\"text/css\"><!-- "
L"body { font-family: \"%s\"; font-size: %dpt; } "
L"--></style>",
Appearance.ArticleFontCfg.FontFace, Appearance.ArticleFontCfg.Size
);
AddText(strCSS);
AddText(L"</head>");
sText.Format(_T("<body bgcolor=#%x text=#%x>"),
MakeRGBVal(Appearance.ClrArticleBg), MakeRGBVal(Appearance.ClrArticleFg));
AddText(sText);
sText.Format(_T("<font face=\"%s\">"), Appearance.ArticleFontCfg.FontFace);
AddText(sText);
// FIXME: critical section
if (m_pArticle != NULL) {
AddText(L"<p><strong>");
AddText(m_pArticle->Title);
AddText(L"</strong></p>");
BOOL cached = IsHTMLCached(m_pArticle->Link, TRUE);
if (cached && Config.AdvancedHtmlOptimizer) {
HANDLE file;
CString fileName = GetCacheFile(FILE_TYPE_HTML, Config.CacheLocation, m_pArticle->Link);
if ((file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) {
do {
char buffer[1024] = { 0 };
DWORD read;
BOOL res = ReadFile(file, buffer, 1023, &read, NULL);
if (res && (read == 0)) break;
CString text = CharToWChar(buffer, CP_UTF8);
AddText(text);
} while (TRUE);
CloseHandle(file);
}
else {
CString text;
text.Format(_T("Could not open the cached HTML file: %s"), fileName);
AddText(text);
}
}
else {
// translate
CString description;
description.Format(_T("<div>%s</div>"), m_pArticle->Description); // workaround for libsgml
AddText(L"<p>");
AddText(description);
AddText(L"</p>");
// author
sText.Empty();
if (!m_pArticle->Author.IsEmpty())
sText += m_pArticle->Author + _T(" | ");
// date/time
CString sDateTime;
SYSTEMTIME st = TimeToTimeZone(&m_pArticle->PubDate); // convert to local time zone
FormatDateTime(sDateTime, st, Config.ShowRelativeDates);
sText += sDateTime;
// keywords
if (m_pArticle->HasKeywordMatch()) {
AddText(L"<p>Keywords: ");
for (int i = 0; i < m_pArticle->KeywordPos.GetSize(); i++) {
if (i > 0) AddText(L", ");
AddText(Config.Keywords.GetAt(i));
}
AddText(L"</p>");
}
AddText(L"<p><font color=\"#aaa\">");
AddText(sText);
AddText(L"</font></p>");
// horz divider
AddText(L"<hr/>");
sTemp.LoadString(IDS_LINK_TO_ARTICLE);
if (cached)
sText.Format(_T("<a href=\"%s\"><strong>%s</strong></a>"), m_pArticle->Link, sTemp);
else
sText.Format(_T("<a href=\"%s\">%s</a>"), m_pArticle->Link, sTemp);
AddText(L"<p>");
AddText(sText);
AddText(L"</p>");
}
}
else {
sTemp.Format(IDS_NOTHING_TO_DISPLAY);
AddText(L"<p>");
AddText(sTemp);
AddText(L"</p>");
}
AddText(L"</font>");
AddText(L"</body>");
AddText(L"</html>");
EndOfSource();
}
void CArticleView::CreateMenu(HWND hwndCmdBar) {
// create menu for the right Softkey
TBBUTTON tb;
::SendMessage(hwndCmdBar, TB_GETBUTTON, 1, (LPARAM) &tb);
CMenu mnu;
mnu.Attach((HMENU) tb.dwData);
while (mnu.GetMenuItemCount() > 0)
mnu.DeleteMenu(0, MF_BYPOSITION);
AppendMenuFromResource(&mnu, IDR_OPEN);
if (m_pArticle != NULL && m_pArticle->HasEnclosure()) {
AppendMenuFromResource(&mnu, IDR_ENCLOSURES);
}
mnu.AppendMenu(MF_SEPARATOR);
AppendMenuFromResource(&mnu, IDR_ITEM_FLAG);
AppendMenuFromResource(&mnu, IDR_COPY_URL);
// bookmark
AppendBookmarkMenu(&mnu);
AppendMenuFromResource(&mnu, IDR_SEND_BY_EMAIL);
AppendMenuFromResource(&mnu, IDR_FULLSCREEN);
mnu.AppendMenu(MF_SEPARATOR);
// AppendMenuFromResource(&mnu, IDR_REFRESH);
AppendMenuFromResource(&mnu, IDR_EXIT);
mnu.Detach();
}
void CArticleView::OnScrollUp() {
LOG0(1, "CArticleView::OnScrollUp()");
SCROLLINFO si;
HWND hSB = ::GetWindow(GetSafeHwnd(), GW_CHILD);
if (hSB == NULL)
hSB = GetSafeHwnd();
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
::GetScrollInfo(hSB, SB_VERT, &si);
if (si.nPos == 0) {
// at the top of the message move to the previous one
OnItemPrev();
}
else {
// scroll the message up
::SendMessage(hSB, WM_VSCROLL, SB_LINEUP, NULL);
}
}
void CArticleView::OnScrollDown() {
LOG0(1, "CArticleView::OnScrollDown()");
SCROLLINFO si;
HWND hSB = ::GetWindow(GetSafeHwnd(), GW_CHILD);
if (hSB == NULL)
hSB = GetSafeHwnd();
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS;
::GetScrollInfo(hSB, SB_VERT, &si);
if (si.nPos + (int) si.nPage > si.nMax) {
// at the top of the message move to the previous one
OnItemNext();
}
else {
// scroll the message up
::SendMessage(hSB, WM_VSCROLL, SB_LINEDOWN, NULL);
}
}
BOOL CArticleView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) {
LOG0(5, "CArticleView::OnNotify()");
NMHDR *pnmh = (LPNMHDR) lParam;
if (pnmh != NULL) {
NM_HTMLVIEW *pnmHTML = (NM_HTMLVIEW *) lParam;
if (pnmh->code == NM_HOTSPOT) {
HotSpot = TRUE;
OpenOnlineMessage(pnmHTML->szTarget, m_pArticle->SiteItem);
*pResult = 1;
return 1;
}
else if (pnmh->code == NM_CONTEXTMENU) {
OnContextMenu((NM_HTMLCONTEXT *) lParam);
*pResult = 1;
return 1;
}
else if (pnmh->code == NM_INLINE_IMAGE) {
if (IsHTMLCached(pnmHTML->szTarget, FALSE)) {
// rewrite the source of the image to the cache
m_strImageLoc = MakeOfflineUrl(GetCacheFile(FILE_TYPE_IMAGE, Config.CacheLocation, pnmHTML->szTarget));
pnmHTML->szTarget = m_strImageLoc;
*pResult = 0; // use default handling of an image
return 0;
}
else {
// not cached -> show empty box
CSiteItem *si= m_pArticle->SiteItem;
BOOL cacheImgs;
if (si->Info->UseGlobalCacheOptions)
cacheImgs = Config.CacheImages;
else
cacheImgs = si->Info->CacheItemImages;
if (Config.WorkOffline || !cacheImgs) {
::SendMessage(GetSafeHwnd(), DTM_IMAGEFAIL, 0, (LPARAM) (INLINEIMAGEINFO*) pnmHTML->dwCookie);
*pResult = 1;
return 1;
}
else {
*pResult = 0; // use default handling of an image
return 0;
}
}
}
}
return CWnd::OnNotify(wParam, lParam, pResult);
}
void CArticleView::AppendBookmarkMenu(CMenu *menu) {
// bookmarking
if (Config.SocialBookmarkSites.GetSize() > 1) {
// create popup menu
HMENU hSubMenu = CreatePopupMenu();
for (int i = 0; i < Config.SocialBookmarkSites.GetSize(); i++) {
CSocialBookmarkSite *sbs = Config.SocialBookmarkSites[i];
::AppendMenu(hSubMenu, MF_STRING | MF_ENABLED, ID_SOCIAL_BOOKMARK_BASE + i, sbs->Name);
}
CString sText;
sText.Format(IDS_BOOKMARK_AT, _T(""));
menu->AppendMenu(MF_POPUP, (UINT) hSubMenu, sText);
}
else {
CSocialBookmarkSite *sbs = Config.SocialBookmarkSites[0];
CString sText;
sText.Format(IDS_BOOKMARK_AT, sbs->Name);
menu->AppendMenu(MF_STRING, ID_SOCIAL_BOOKMARK_BASE, sText);
}
}
void CArticleView::ContextMenu(CPoint point) {
LOG0(3, "CArticleView::ContextMenu()");
CMenu popup;
popup.CreatePopupMenu();
m_strContextMnuUrl.Empty();
m_strContextMenuLinkName.Empty();
AppendMenuFromResource(&popup, IDR_OPEN);
if (m_pArticle->HasEnclosure()) {
AppendMenuFromResource(&popup, IDR_ENCLOSURES);
}
popup.AppendMenu(MF_SEPARATOR);
AppendBookmarkMenu(&popup);
AppendMenuFromResource(&popup, IDR_SEND_BY_EMAIL);
AppendMenuFromResource(&popup, IDR_COPY_URL);
popup.AppendMenu(MF_SEPARATOR);
AppendMenuFromResource(&popup, IDR_ITEM_FLAG);
AppendMenuFromResource(&popup, IDR_COPY);
AppendMenuFromResource(&popup, IDR_FULLSCREEN);
popup.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, GetParent());
}
void CArticleView::OnContextMenu(NM_HTMLCONTEXT *pnmhc) {
LOG0(3, "CArticleView::OnContextMenu()");
CMenu popup;
popup.CreatePopupMenu();
if (pnmhc->uTypeFlags & HTMLCONTEXT_LINK) {
m_strContextMnuUrl = pnmhc->szLinkHREF;
m_strContextMenuLinkName = pnmhc->szLinkName;
AppendMenuFromResource(&popup, IDR_LINK_CTX);
popup.InsertMenu(1, MF_SEPARATOR | MF_BYPOSITION);
AppendBookmarkMenu(&popup);
AppendMenuFromResource(&popup, IDR_SEND_BY_EMAIL);
AppendMenuFromResource(&popup, IDR_COPY_LINK_URL);
}
else if (pnmhc->uTypeFlags & (HTMLCONTEXT_IMAGE | HTMLCONTEXT_IMAGENOTLOADED)) {
m_strContextMnuUrl = pnmhc->szLinkHREF;
m_strContextMenuLinkName = pnmhc->szLinkName;
AppendMenuFromResource(&popup, IDR_ARTICLE_IMAGE);
AppendMenuFromResource(&popup, IDR_SEND_BY_EMAIL);
}
else {
m_strContextMnuUrl.Empty();
m_strContextMenuLinkName.Empty();
AppendMenuFromResource(&popup, IDR_OPEN);
if (m_pArticle->HasEnclosure()) {
AppendMenuFromResource(&popup, IDR_ENCLOSURES);
}
popup.AppendMenu(MF_SEPARATOR);
AppendBookmarkMenu(&popup);
AppendMenuFromResource(&popup, IDR_SEND_BY_EMAIL);
AppendMenuFromResource(&popup, IDR_COPY_URL);
}
popup.AppendMenu(MF_SEPARATOR);
AppendMenuFromResource(&popup, IDR_ITEM_FLAG);
AppendMenuFromResource(&popup, IDR_COPY);
AppendMenuFromResource(&popup, IDR_FULLSCREEN);
//
CPoint point = pnmhc->pt;
popup.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, GetParent());
}
LRESULT CArticleView::OnHotKey(WPARAM wParam, LPARAM lParam) {
LOG0(3, "CArticleView::OnHotKey()");
return 0;
}
void CArticleView::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu) {
LOG0(3, "CArticleView::OnInitMenuPopup()");
if (bSysMenu)
return; // don't support system menu
ASSERT(pMenu != NULL); // check the enabled state of various menu items
CCmdUI state;
state.m_pMenu = pMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup)
HMENU hParentMenu;
if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
state.m_pParentMenu = pMenu; // parent == child for tracking popup
else if ((hParentMenu = ::WCE_FCTN(GetMenu)(m_hWnd)) != NULL) {
CWnd *pParent = GetTopLevelParent(); // child windows don't have menus -- need to go to the top!
if (pParent != NULL &&
(hParentMenu = ::WCE_FCTN(GetMenu)(pParent->m_hWnd)) != NULL)
{
int nIndexMax = ::WCE_FCTN(GetMenuItemCount)(hParentMenu);
for (int nIndex = 0; nIndex < nIndexMax; nIndex++) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -