gusucode.com > VC_C++源码,界面编程,网页爬虫源码程序 > VC_C++源码,界面编程,网页爬虫源码程序/code/webpageloader_SourceCode/SessionView.cpp

    // ItemView.cpp : implementation of the CSessionView class
//

#include "stdafx.h"
#include "WebPageLoader.h"

#include <atlbase.h>

#include "Doc.h"
#include "MainFrm.h"
#include "SessionView.h"

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

#define TIMER_ID 55

static LPCTSTR szSection = _T("Settings");


LPCTSTR GetSizeNumber(long n)
{
   static TCHAR szResult[64] = { 0 };
   USES_CONVERSION;
   WCHAR szwTemp[64];
   LONGLONG longlong = (DWORD) n;
   ::StrFormatByteSizeW(longlong, szwTemp, 63);
   _tcscpy(szResult, W2CT(szwTemp));
   return szResult;
}

LPCTSTR GetFormattedNumber(long n)
// Returns a string formatted using locale rules (thousand separators etc).
// Returns a STATIC string buffer.
{
   static TCHAR szResult[64] = { 0 };

   // Get the decimal character(s)
   static TCHAR szDecimal[8] = { 0 };
   if( szDecimal[0] == _T('\0') ) {
      int size = ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, NULL, 0);
      if( size==0 ) return NULL;
      HLOCAL hlocal = ::LocalAlloc(LPTR, size);
      LPTSTR lpBuf = (LPTSTR)::LocalLock(hlocal);
      ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, lpBuf, size);
      _tcscpy( szDecimal, lpBuf );
      ::LocalUnlock(hlocal);
      ::LocalFree(hlocal);
   }

   TCHAR szStr[64] = { 0 };
   wsprintf(szStr, _T("%d"), n);
   ::GetNumberFormat(LOCALE_USER_DEFAULT, 0, szStr, NULL, szResult, 63);

   // HACK: Remove possible decimals
   LPTSTR p = _tcsstr( szResult, szDecimal );
   if( p!=NULL ) {
      while( _tcsstr( p+1, szDecimal )!=NULL ) p = _tcsstr( p+1, szDecimal );
      if( p!=NULL ) *p = _T('\0');
   }

   return szResult;
};


/////////////////////////////////////////////////////////////////////////////
// CSessionView

IMPLEMENT_DYNCREATE(CSessionView, CListView)

BEGIN_MESSAGE_MAP(CSessionView, CListView)
   //{{AFX_MSG_MAP(CSessionView)
   ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, OnItemChanged)
   ON_COMMAND(ID_EDIT_REFRESH, OnEditRefresh)
   ON_COMMAND(ID_EDIT_DELETE, OnDelete)
   ON_UPDATE_COMMAND_UI(ID_EDIT_DELETE, OnUpdateDelete)
   ON_WM_DESTROY()
   ON_WM_TIMER()
   ON_NOTIFY_REFLECT(NM_DBLCLK, OnDblclk)
   ON_WM_CONTEXTMENU()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CSessionView construction/destruction

CSessionView::CSessionView()
{
}

CSessionView::~CSessionView()
{
}

BOOL CSessionView::PreCreateWindow(CREATESTRUCT& cs)
{
   cs.style |= LVS_NOSORTHEADER;
   return CListView::PreCreateWindow(cs);
}


/////////////////////////////////////////////////////////////////////////////
// CSessionView drawing

void CSessionView::OnTimer(UINT nIDEvent) 
{
   if( nIDEvent == TIMER_ID ) RefreshItems(FALSE);
   CListView::OnTimer(nIDEvent);
}

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

void CSessionView::OnInitialUpdate()
{
   CListView::OnInitialUpdate();

   CListCtrl& ctlList = GetListCtrl();

   // Create the image list for the tree control
   m_ImageList.Create(IDR_IMAGES, 16, 1, RGB(0,0,255));
   ctlList.SetImageList(&m_ImageList, LVSIL_SMALL);

   // Set style and add columns
   ctlList.ModifyStyle(LVS_TYPEMASK, LVS_REPORT|LVS_SINGLESEL|LVS_SHOWSELALWAYS);
   CString s;
   s.LoadString(IDS_COL_ITEM);
   ctlList.InsertColumn(0, s, LVCFMT_LEFT);
   s.LoadString(IDS_COL_FILES);
   ctlList.InsertColumn(1, s, LVCFMT_CENTER);
   s.LoadString(IDS_COL_DOWNLOADED);
   ctlList.InsertColumn(2, s, LVCFMT_CENTER);

   // Set reasonable widths for our columns
   int w1, w2, w3;
   s = ::AfxGetApp()->GetProfileString(szSection, _T("Columns"), _T("300,100,100"));
   ::sscanf( s, _T("%d,%d,%d"), &w1, &w2, &w3 );
   ctlList.SetColumnWidth(0, w1);
   ctlList.SetColumnWidth(1, w2);
   ctlList.SetColumnWidth(2, w3);
}

void CSessionView::OnDestroy() 
{
   CString s;
   CListCtrl& ctlList = GetListCtrl();
   s.Format(_T("%d,%d,%d"),
      ctlList.GetColumnWidth(0), 
      ctlList.GetColumnWidth(1), 
      ctlList.GetColumnWidth(2) );
   ::AfxGetApp()->WriteProfileString(szSection, _T("Columns"), s);

   CListView::OnDestroy();   
}


/////////////////////////////////////////////////////////////////////////////
// CSessionView diagnostics

#ifdef _DEBUG
void CSessionView::AssertValid() const
{
   CListView::AssertValid();
}

void CSessionView::Dump(CDumpContext& dc) const
{
   CListView::Dump(dc);
}

CDoc* CSessionView::GetDocument() // non-debug version is inline
{
   ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDoc)));
   return (CDoc*)m_pDocument;
}
#endif //_DEBUG


/////////////////////////////////////////////////////////////////////////////
// CSessionView helpers

int CSessionView::StateToImage(CSession *pSession)
{
   ASSERT_VALID(pSession);
   switch( pSession->m_State ) {
   case STATE_UNSCHEDULED: return 0;
   case STATE_QUEUED:      return 1;
   case STATE_CONNECTING:  return 2;
   case STATE_RUNNING:     return 3;
   case STATE_SLEEPING:    return 5;
   case STATE_DONE:;
   case STATE_STOPPED:
      // Download complete image: 
      // * Show GREEN image if all files were reported OK
      // * Show YELLOW image if all files were not downloaded (warnings, skipped files)
      // * Show RED image if any errors have been reported
      if( pSession->m_Info.m_nFilesDownloaded==pSession->m_Files.GetCount() ) return 4;
      if( pSession->m_Info.m_nFilesFailed>0 ) return 16;
      return 15;
   default:
      return 0;
   };
};


/////////////////////////////////////////////////////////////////////////////
// Implementation

int CSessionView::GetSelectedItem()
{
   CListCtrl& ctlList = GetListCtrl();
   return ctlList.GetNextItem(-1, LVIS_SELECTED);
};

LONG CSessionView::GetSelectedSessionID()
{
   int idx = GetSelectedItem();
   if( idx<0 ) return -1;
   CListCtrl& ctlList = GetListCtrl();
   return ctlList.GetItemData(idx);   
};

void CSessionView::CreateItems()
{
   CListCtrl& ctlList = GetListCtrl();
   ctlList.DeleteAllItems();
   RefreshItems(TRUE); 
};

void CSessionView::RefreshItems(BOOL bAll/*=FALSE*/)
{
   CDoc *pDoc = GetDocument();
   if( pDoc==NULL ) return;
   ASSERT_KINDOF(CDoc,pDoc);

   CSingleLock lock( pDoc->m_ThreadManager, TRUE );

   CListCtrl& ctlList = GetListCtrl();

   // Update all existing items if nessecary
   int max = ctlList.GetItemCount();
   for( int i=0; i<max; i++ ) {
      LVITEM itm = { 0 };
      itm.iItem = i;
      itm.mask = LVIF_PARAM;
      BOOL bFound = ctlList.GetItem(&itm);
      if( !bFound ) continue;

      CSession *pSession = pDoc->m_ThreadManager.FindSession(itm.lParam);
      if( pSession==NULL ) {
         // Session is no longer to be found in lists... must
         // have been deleted...
         ctlList.DeleteItem(itm.iItem);
         // Force glorious loop to repeat since deleting
         // usually screws things up in control indexes.
         i=0;
         continue;
      };
      ASSERT_VALID(pSession);

      // Ok, we may wish to update the item!
      // We only select the stuff that really needs updating
      // since this is called for all items.
      {
         CSingleLock lock( *pSession, TRUE );
         UpdateListItem(ctlList, pSession, i, bAll);
         pSession->m_OldState = pSession->m_State;
      }
   };

   // Find and add any new items
   CSessionList List;
   pDoc->m_ThreadManager.GetSessions(List);
   POSITION pos = List.GetHeadPosition();
   while( pos != NULL ) {
      CSession *pSession = List.GetNext(pos);
      ASSERT_VALID(pSession);
      LVFINDINFO find = { 0 };
      find.flags = LVFI_PARAM;
      find.lParam = pSession->m_iUniqueID;
      int idx = ctlList.FindItem(&find);
      if( idx >= 0 ) continue;
      
      // Ok, found a new one. Insert it...
      {
         CSingleLock lock( *pSession, TRUE );
         LV_ITEM itm = { 0 };
         itm.iItem = 0;
         itm.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
         itm.pszText = (LPTSTR)(LPCTSTR)pSession->m_sURL;
         itm.cchTextMax = pSession->m_sURL.GetLength();
         itm.iImage = 0;
         itm.lParam = pSession->m_iUniqueID;
         int newidx = ctlList.InsertItem(&itm);
         UpdateListItem(ctlList,pSession,newidx,TRUE);
         //
         ctlList.SetItemState(newidx, LVIS_SELECTED, LVIS_SELECTED);
      };
   };

   CMainFrame *frm = ((CMainFrame *)::AfxGetMainWnd());
   ASSERT_KINDOF(CMainFrame,frm);
   if( frm==NULL ) return;

   // Update statusbar (download statistics)
   CString files = GetFormattedNumber(pDoc->m_Preferences.m_nFilesDownloaded);
   CString bytes = GetSizeNumber(pDoc->m_Preferences.m_lBytesDownloaded);
   CString s;
   s.Format(IDS_STATUSTEXT, 
      (LPCTSTR)files,
      (LPCTSTR)bytes);
   frm->m_wndStatusBar.SetPaneText(2,s,TRUE);

   // Refresh view periodically
   if( IsWindowVisible() ) SetTimer(TIMER_ID, 2000, NULL);
   else KillTimer(TIMER_ID);
};

void CSessionView::UpdateListItem(CListCtrl &ctlList, CSession *pSession, int idx, BOOL bForce)
// NOT LOCKING
{
   LV_ITEM itm = { 0 };
   itm.iItem = idx;
   itm.mask = 0;
   int iImage;
   if( (iImage = StateToImage(pSession)) != itm.iImage ) {
      itm.mask |= LVIF_IMAGE;
      itm.iImage = iImage;
   };
   if( itm.mask!=0 ) ctlList.SetItem(&itm);
   if( bForce || 
       (pSession->m_State == STATE_RUNNING) || 
       (pSession->m_OldState != pSession->m_State) ) {
      //
      CString s;
      s.Format(_T("%d / %d"), 
         pSession->m_Info.m_nFilesDownloaded + pSession->m_Info.m_nFilesSkipped + pSession->m_Info.m_nFilesFailed, 
         pSession->m_Files.GetCount());
      ctlList.SetItemText(idx, 1, (LPCTSTR)s);
      s = GetFormattedNumber(pSession->m_Info.m_lBytesDownloaded);
      ctlList.SetItemText(idx, 2, (LPCTSTR)s);
   };
};


/////////////////////////////////////////////////////////////////////////////
// CSessionView message handlers

void CSessionView::OnItemChanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
   NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
   
   CDoc *pDoc = GetDocument();
   ASSERT_KINDOF(CDoc,pDoc);
   if( pDoc==NULL ) return;

   CMainFrame *frm = ((CMainFrame *)::AfxGetMainWnd());
   ASSERT_KINDOF(CMainFrame,frm);

   CSession *pSession = pDoc->GetSelectedSession();
   if( pSession==NULL ) {
      frm->OnCreateNodes(0,0);
      frm->m_wndStatusBar.SetPaneText( 0, _T(""), TRUE );
      return;
   }
   CSingleLock lock( *pSession, TRUE );
   frm->OnCreateNodes(0,0);
   frm->m_wndStatusBar.SetPaneText( 0, pSession->m_Settings.m_sDownloadPath, TRUE );

   *pResult = 0;
}

void CSessionView::OnEditRefresh() 
{
   CreateItems();
}

void CSessionView::OnDelete() 
{
   CDoc *pDoc = GetDocument();
   ASSERT_KINDOF(CDoc,pDoc);
   if( pDoc==NULL ) return;
   CSession *pSession = pDoc->GetSelectedSession();
   ASSERT_VALID(pSession);
   if( pSession==NULL ) return;
   CSingleLock lock( *pSession, TRUE );
   pSession->m_bKillRequest = true;
   ::AfxGetMainWnd()->PostMessage(WM_SCHEDULE);
}

void CSessionView::OnUpdateDelete(CCmdUI* pCmdUI) 
{
   CListCtrl& ctlList = GetListCtrl();
   pCmdUI->Enable( ctlList.GetSelectedCount()>0);
}


void CSessionView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
   CDoc *pDoc = GetDocument();
   ASSERT_KINDOF(CDoc,pDoc);
   pDoc->OnEditProperties();
   *pResult = 0;
}

void CSessionView::OnContextMenu(CWnd* pWnd, CPoint point)
{
   if( GetSelectedItem()<0 ) return;

   CMainFrame *frm = (CMainFrame *)::AfxGetMainWnd();
   ASSERT_VALID(frm);
   if( frm==NULL ) return;
   CMenu *menu = frm->GetMenu();
   if( menu==NULL ) return;
   CMenu *editmenu = menu->GetSubMenu(1);
   if( editmenu==NULL ) return;
   editmenu->TrackPopupMenu(TPM_LEFTALIGN, 
      point.x, point.y,
      frm,
      NULL);

}