|
|
// Folder.cpp: implementation of the CFolder class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#define __FILE_ID__ 21
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW
#endif
IMPLEMENT_DYNAMIC(CFolder, CTreeNode)
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
void CFolder::PreDestruct () { DBG_ENTER(TEXT("CFolder::PreDestruct"), TEXT("Type=%d"), m_Type); //
// Stop the build thread - and wait for its death
//
DWORD dwRes = StopBuildThread (); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CFolder::StopBuildThread"), dwRes); } //
// Clear the map of items
//
dwRes = InvalidateContents(FALSE); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CFolder::InvalidateContents"), dwRes); } } // CFolder::PreDestruct
CFolder::~CFolder() { DBG_ENTER(TEXT("CFolder::~CFolder"), TEXT("Type=%d"), m_Type); //
// Destroy data critical section
//
if (m_bCsDataInitialized) { DeleteCriticalSection (&m_CsData); } } // CFolder::~CFolder
CFaxMsg* CFolder::FindMessage ( DWORDLONG dwlMsgId ) { DBG_ENTER(TEXT("CFolder::FindMessage"));
MSGS_MAP::iterator it = m_Msgs.find (dwlMsgId); if (m_Msgs.end() == it) { //
// Not found
//
return NULL; } else { return (*it).second; } } // CFolder::FindMessage
void CFolder::AssertValid() const { CTreeNode::AssertValid(); }
void CFolder::SetServer ( CServerNode *pServer ) { DBG_ENTER(TEXT("CFolder::SetServer")); ASSERTION (NULL != pServer); m_pServer = pServer;
VERBOSE (DBG_MSG, TEXT ("Folder on server %s, Type=%d"), m_pServer->Machine(), m_Type); }
DWORD CFolder::Init () /*++
Routine name : CFolder::Init
Routine description:
Init a folder
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::Init"), dwRes);
//
// Init the build thread critical section
//
try { InitializeCriticalSection (&m_CsData); } catch (...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT ("InitializeCriticalSection"), dwRes); return dwRes; } m_bCsDataInitialized = TRUE;
return dwRes; } // CFolder::Init
void CFolder::AttachView() { DBG_ENTER(TEXT("CFolder::AttachView"));
m_pAssignedView = NULL;
CMainFrame *pFrm = GetFrm(); if (!pFrm) { //
// Shutdown in progress
//
return; }
//
// Attach the right view to the folder
//
switch (m_Type) { case FOLDER_TYPE_INBOX: m_pAssignedView = pFrm->GetInboxView (); break;
case FOLDER_TYPE_INCOMING: m_pAssignedView = pFrm->GetIncomingView (); break;
case FOLDER_TYPE_OUTBOX: m_pAssignedView = pFrm->GetOutboxView (); break;
case FOLDER_TYPE_SENT_ITEMS: m_pAssignedView = pFrm->GetSentItemsView (); break;
default: ASSERTION_FAILURE; } ASSERTION(m_pAssignedView);
} //CFolder::AttachView
void CFolder::SetVisible() /*++
Routine name : CFolder::SetVisible
Routine description:
Sets the visiblity of a folder
Author:
Eran Yariv (EranY), Jan, 2000
Return Value:
None.
--*/ { DBG_ENTER(TEXT("CFolder::SetVisible"), TEXT("Server = %s, Type=%d"), m_pServer ? m_pServer->Machine() : TEXT("None"), m_Type);
//
// This folder's tree node was just selected
//
m_bVisible = TRUE;
if (!m_bValidList && !m_bRefreshing) { //
// The items list is invalid and there's not thread currently creating it.
//
// This is the 1st time this node is being selected for display
// (since its creation) - build the list of jobs / messages now
//
// NOTICE: RebuildContents() calls StopBuildThread() which waits for
// the previous thread to die WHILE DEQUEUEING WINDOWS MESSAGES.
// This may causes a seconds call to this function BEFORE
// RebuildContents() returned.
//
DWORD dwRes = RebuildContents (); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT ("CFolder::RebuildContents"), dwRes); } }
} // CFolder::SetVisible
DWORD CFolder::InvalidateContents ( BOOL bClearView ) /*++
Routine name : CFolder::InvalidateContents
Routine description:
Clears the contents of a folder (and the view if attached)
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
bClearView [in] - Should we clear attached view ?
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::InvalidateContents"), dwRes, TEXT("Type=%d"), m_Type);
CFaxMsg* pMsg;
EnterData (); for (MSGS_MAP::iterator it = m_Msgs.begin(); it != m_Msgs.end(); ++it) { pMsg = (*it).second;
if(bClearView && m_pAssignedView) { m_pAssignedView->OnUpdate (NULL, UPDATE_HINT_REMOVE_ITEM, pMsg); }
SAFE_DELETE (pMsg); } m_Msgs.clear(); LeaveData ();
//
// Mark list as invalid
//
m_bValidList = FALSE; return dwRes; } // CFolder::InvalidateContents
DWORD CFolder::RebuildContents () /*++
Routine name : CFolder::RebuildContents
Routine description:
Rebuilds the contents of a folder (by creating a worker thread)
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::RebuildContents"), dwRes, TEXT("Type=%d"), m_Type);
ASSERTION(!m_bRefreshing);
m_bRefreshing = TRUE;
//
// Stop the current (if any) build thread and make sure it's dead
//
m_bRefreshFailed = FALSE; DWORD dwThreadId;
dwRes = StopBuildThread (); EnterCriticalSection (&m_CsData); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (RESOURCE_ERR, TEXT("CFolder::StopBuildThread"), dwRes); m_bRefreshing = FALSE; goto exit; } //
// Lock the folder, so that notifications will not add jobs / messages
// to the map and list view.
//
m_bLocked = TRUE; //
// Clear our list and our view (list control)
//
dwRes = InvalidateContents(FALSE); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (RPC_ERR, TEXT("CFolder::InvalidateContents"), dwRes); m_bLocked = FALSE; m_bRefreshing = FALSE; goto exit; } //
// Start the thread that will fill the data (in the background)
//
m_bStopRefresh = FALSE; m_hBuildThread = CreateThread ( NULL, // No security
0, // Default stack size
BuildThreadProc,// Thread procedure
(LPVOID)this, // Parameter
0, // Normal creation
&dwThreadId // We must have a thread id for win9x
); if (NULL == m_hBuildThread) { dwRes = GetLastError (); CALL_FAIL (RESOURCE_ERR, TEXT("CreateThread"), dwRes); PopupError (dwRes); m_bLocked = FALSE; m_bRefreshing = FALSE; } exit: LeaveCriticalSection (&m_CsData); return dwRes; } // CFolder::RebuildContents
DWORD CFolder::StopBuildThread (BOOL bWaitForDeath) /*++
Routine name : CFolder::StopBuildThread
Routine description:
Stops the contents-building worker thread.
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
bWaitForDeath [in] - Should we wait until the therad actually dies?
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::StopBuildThread"), dwRes, TEXT("Type=%d"), m_Type);
m_bStopRefresh = TRUE; if (!bWaitForDeath) { return dwRes; } if (NULL == m_hBuildThread) { //
// Background build thread is already dead
//
return dwRes; } dwRes = WaitForThreadDeathOrShutdown (m_hBuildThread); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("WaitForThreadDeathOrShutdown"), dwRes); } CloseHandle (m_hBuildThread); m_hBuildThread = NULL; return dwRes; } // CFolder::StopBuildThread
DWORD WINAPI CFolder::BuildThreadProc ( LPVOID lpParameter ) /*++
Routine name : CFolder::BuildThreadProc
Routine description:
Static thread entry point.
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
lpParameter [in] - Pointer to the CFolder instance that created the thread.
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::BuildThreadProc"), dwRes);
CFolder *pFolder = (CFolder *)lpParameter; ASSERT (pFolder);
const CServerNode* pServer = pFolder->GetServer(); if(NULL != pServer) { VERBOSE (DBG_MSG, TEXT ("Folder on server %s"), pServer->Machine()); } //
// Call the refresh function for the right folder
//
dwRes = pFolder->Refresh (); if (ERROR_SUCCESS != dwRes) { CALL_FAIL (GENERAL_ERR, TEXT("CFolder::Refresh"), dwRes);
//
// Check if the view still alive
//
pFolder->AttachView(); if(pFolder->m_pAssignedView) { //
// Invalidate contents
//
pFolder->m_pAssignedView->SendMessage ( WM_FOLDER_INVALIDATE, WPARAM (0), LPARAM (pFolder)); } pFolder->m_bRefreshFailed = TRUE; } else { //
// Refresh thread succeeded, there's a point in updating the view
//
pFolder->m_bValidList = TRUE;
//
// Check if the view still alive
//
pFolder->AttachView(); if (pFolder->m_pAssignedView) { //
// Folder has a view attached
//
pFolder->m_pAssignedView->SendMessage ( WM_FOLDER_REFRESH_ENDED, WPARAM (dwRes), LPARAM (pFolder)); } } pFolder->EnterData (); //
// Unlock the folder - notifications can now be processed
//
pFolder->m_bLocked = FALSE; pFolder->LeaveData (); pFolder->m_bRefreshing = FALSE; CMainFrame *pFrm = GetFrm(); if (!pFrm) { //
// Shutdown in progress
//
} else { pFrm->RefreshStatusBar (); }
//
// That's it, return the result
//
return dwRes; } // CFolder::BuildThreadProc
int CFolder::GetActivityStringResource() const /*++
Routine name : CFolder::GetActivityStringResource
Routine description:
Returns the resource id of a string identifying the activity of the folder
Author:
Eran Yariv (EranY), Jan, 2000
Arguments:
Return Value:
Activity string resource id
--*/ { if (m_bRefreshFailed) { //
// Last refresh failed
//
return IDS_FOLDER_REFRESH_FAILED; } if (m_pAssignedView && m_pAssignedView->Sorting()) { //
// Folder has a view and the view is currently sorting
//
return IDS_FOLDER_SORTING; } if (IsRefreshing()) { //
// Folder is busy building up its data
//
return IDS_FOLDER_REFRESHING; } //
// Folder is doing nothing
//
return IDS_FOLDER_IDLE; } // CFolder::GetActivityStringResource
DWORD CFolder::OnJobRemoved ( DWORDLONG dwlMsgId, CFaxMsg* pMsg /* = NULL */ ) /*++
Routine name : CFolder::OnJobRemoved
Routine description:
Handles notification of a message removed from the archive
Author:
Eran Yariv (EranY), Feb, 2000
Arguments:
dwlMsgId [in] - Message unique id pMsg [in] - Optional pointer to message to remove (for optimization)
Return Value:
Standard Win32 error code
--*/ { DWORD dwRes = ERROR_SUCCESS; DBG_ENTER(TEXT("CFolder::OnJobRemoved"), dwRes, TEXT("MsgId=0x%016I64x, Type=%d"), dwlMsgId, Type());
EnterData (); if (!pMsg) { //
// No message pointer was supplied - search for it
//
pMsg = FindMessage (dwlMsgId); } if (!pMsg) { //
// This message is already not in the archive
//
VERBOSE (DBG_MSG, TEXT("Message is already gone")); goto exit; }
if (m_pAssignedView) { //
// If this folder is alive - tell our view to remove the message
//
m_pAssignedView->OnUpdate (NULL, UPDATE_HINT_REMOVE_ITEM, pMsg); }
//
// Remove the message from the map
//
try { m_Msgs.erase (dwlMsgId); } catch (...) { dwRes = ERROR_NOT_ENOUGH_MEMORY; CALL_FAIL (MEM_ERR, TEXT("map::erase"), dwRes); delete pMsg; goto exit; } //
// Delete message
//
delete pMsg;
ASSERTION (ERROR_SUCCESS == dwRes);
exit: LeaveData (); return dwRes;
} // CFolder::OnJobRemoved
|