#include "DirScan.h"
#include "Plugins.h"
+
/**
- * @brief Static structure for sharing data with thread
+ * @brief Data sent to diff thread
*/
-static DiffFuncStruct diffParam;
+struct DiffFuncStruct
+{
+ CString path1;
+ CString path2;
+ CDiffContext * context;
+ UINT msgUIUpdate;
+ UINT msgStatusUpdate;
+ HWND hWindow;
+ UINT nThreadState;
+ BOOL bRecursive;
+ DiffThreadAbortable * m_pAbortgate;
+ DiffFuncStruct()
+ : context(0)
+ , msgUIUpdate(0)
+ , msgStatusUpdate(0)
+ , hWindow(0)
+ , nThreadState(THREAD_NOTSTARTED)
+ , bRecursive(FALSE)
+ , m_pAbortgate(0)
+ {}
+};
+
+
+/** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
+class DiffThreadAbortable : public IAbortable
+{
+// Implement DirScan's IAbortable
+public:
+ virtual bool ShouldAbort() { return m_diffthread->ShouldAbort(); }
+
+// All this object does is forward ShouldAbort calls to its containing CDiffThread
+
+ DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
+ CDiffThread * m_diffthread;
+};
/**
* @brief Default constructor
{
m_pDiffContext = NULL;
m_thread = NULL;
- diffParam.nThreadState = THREAD_NOTSTARTED;
+ m_pDiffParm = new DiffFuncStruct;
+ m_pAbortgate = new DiffThreadAbortable(this);
+ m_msgUpdateUI = 0;
+ m_msgUpdateStatus = 0;
+ m_hWnd = 0;
+ m_bAborting = FALSE;
}
CDiffThread::~CDiffThread()
{
+ delete m_pDiffParm;
+ delete m_pAbortgate;
}
*/
UINT CDiffThread::CompareDirectories(CString dir1, CString dir2, BOOL bRecursive)
{
- diffParam.path1 = dir1;
- diffParam.path2 = dir2;
- diffParam.bRecursive = bRecursive;
- diffParam.context = m_pDiffContext;
- diffParam.msgUIUpdate = m_msgUpdateUI;
- diffParam.hWindow = m_hWnd;
-
- diffParam.nThreadState = THREAD_COMPARING;
- m_thread = AfxBeginThread(DiffThread, (LPVOID)&diffParam);
+ ASSERT(m_pDiffParm->nThreadState != THREAD_COMPARING);
+
+ m_pDiffParm->path1 = dir1;
+ m_pDiffParm->path2 = dir2;
+ m_pDiffParm->bRecursive = bRecursive;
+ m_pDiffParm->context = m_pDiffContext;
+ m_pDiffParm->msgUIUpdate = m_msgUpdateUI;
+ m_pDiffParm->hWindow = m_hWnd;
+ m_pDiffParm->m_pAbortgate = m_pAbortgate;
+
+ m_pDiffParm->nThreadState = THREAD_COMPARING;
+ m_thread = AfxBeginThread(DiffThread, m_pDiffParm);
return 1;
}
/**
* @brief Returns thread's current state
*/
-UINT CDiffThread::GetThreadState()
+UINT CDiffThread::GetThreadState() const
{
- return diffParam.nThreadState;
+ return m_pDiffParm->nThreadState;
}
/**
bool casesensitive = false;
int depth = myStruct->bRecursive ? -1 : 0;
CString subdir; // blank to start at roots specified in diff context
- DirScan(subdir, myStruct->context, casesensitive, depth);
+ DirScan(subdir, myStruct->context, casesensitive, depth, myStruct->m_pAbortgate);
// Send message to UI to update
- diffParam.nThreadState = THREAD_COMPLETED;
+ myStruct->nThreadState = THREAD_COMPLETED;
PostMessage(hWnd, msgID, NULL, NULL);
return 1;
}
#include "diffcontext.h"
+struct DiffFuncStruct;
+class DiffThreadAbortable;
+
/**
* @brief Thread's statuses
*/
THREAD_COMPLETED
};
-/**
- * @brief Data sent to diff thread
- */
-struct DiffFuncStruct
-{
- CString path1;
- CString path2;
- CDiffContext * context;
- UINT msgUIUpdate;
- UINT msgStatusUpdate;
- HWND hWindow;
- UINT nThreadState;
- BOOL bRecursive;
-};
/**
* @brief Class for threaded directory compare
class CDiffThread
{
public:
+// creation and use, called on main thread
CDiffThread();
~CDiffThread();
CDiffContext * SetContext(CDiffContext * pCtx);
UINT CompareDirectories(CString dir1, CString dir2, BOOL bRecursive);
void SetHwnd(HWND hWnd);
void SetMessageIDs(UINT updateMsg, UINT statusMsg);
- UINT GetThreadState();
+
+// runtime interface for main thread, called on main thread
+ UINT GetThreadState() const;
+ void Abort() { m_bAborting = true; }
+ bool IsAborting() const { return m_bAborting; }
+
+// runtime interface for child thread, called on child thread
+ bool ShouldAbort() const { return m_bAborting; }
+
private:
CDiffContext * m_pDiffContext;
CWinThread * m_thread;
+ DiffFuncStruct * m_pDiffParm;
+ DiffThreadAbortable * m_pAbortgate;
UINT m_msgUpdateUI;
UINT m_msgUpdateStatus;
HWND m_hWnd;
+ bool m_bAborting;
};
UINT DiffThread(LPVOID lpParam);
return FALSE;
return CDocument::SaveModified();
-}
\ No newline at end of file
+}
+
+/**
+ * @brief Send signal to thread to stop current scan
+ *
+ * @todo: Call this from somewhere in GUI, eg, <escape> button
+ */
+void CDirDoc::AbortCurrentScan()
+{
+ m_diffThread.Abort();
+}
+
+/**
+ * @brief Returns true if there is an active scan that hasn't been aborted.
+ *
+ * @todo: This is for Update command handler of menu item or toolbar button to cancel scan
+ */
+bool CDirDoc::IsCurrentScanAbortable() const
+{
+ return (m_diffThread.GetThreadState() == THREAD_COMPARING
+ && !m_diffThread.IsAborting());
+}
void SetDiffStatus(UINT diffcode, UINT mask, int idx);
void SetDiffContext(CDiffContext *pCtxt);
void UpdateHeaderPath(BOOL bLeft);
+ void AbortCurrentScan();
+ bool IsCurrentScanAbortable() const;
#ifdef _DEBUG
virtual void AssertValid() const;
// base directories to compare are in the CDiffContext
// and this call is responsible for diff'ing just the subdir specified
// (ie, if subdir is empty, this is the base call)
-int DirScan(const CString & subdir, CDiffContext * pCtxt, bool casesensitive, int depth)
+// return 1 normally, return -1 if aborting
+int DirScan(const CString & subdir, CDiffContext * pCtxt, bool casesensitive,
+ int depth, IAbortable * piAbortable)
{
CString sLeftDir = pCtxt->m_strNormalizedLeft;
CString sRightDir = pCtxt->m_strNormalizedRight;
sRightDir += _T("\\") + subdir;
subprefix = subdir + _T("\\");
}
+
cmpmth mthptr = (casesensitive ? &CString::Collate : &CString::CollateNoCase);
fentryArray leftDirs, leftFiles, rightDirs, rightFiles;
LoadAndSortFiles(sLeftDir, &leftDirs, &leftFiles, casesensitive);
LoadAndSortFiles(sRightDir, &rightDirs, &rightFiles, casesensitive);
+ if (piAbortable && piAbortable->ShouldAbort()) return -1;
+
// Handle directories
// i points to current directory in left list (leftDirs)
// j points to current directory in right list (rightDirs)
int i=0, j=0;
while (1)
{
+ if (piAbortable && piAbortable->ShouldAbort()) return -1;
+
// In debug mode, send current status to debug window
if (i<leftDirs.GetSize())
TRACE(_T("Candidate left: leftDirs[i]=%s\n"), leftDirs[i]);
}
else
{
- DirScan(newsub, pCtxt, casesensitive, depth-1);
+ if (DirScan(newsub, pCtxt, casesensitive, depth-1, piAbortable) == -1)
+ return -1;
}
++i;
++j;
i=0, j=0;
while (1)
{
+ if (piAbortable && piAbortable->ShouldAbort()) return -1;
+
// In debug mode, send current status to debug window
if (i<leftFiles.GetSize())
TRACE(_T("Candidate left: leftFiles[i]=%s\n"), leftFiles[i]);
#define DirScan_h_included
class CDiffContext;
-int DirScan(const CString & subdir, CDiffContext * pCtxt, bool casesensitive, int depth=-1);
+
+/** @brief callback to check if dirscan needs to abort */
+class IAbortable
+{
+public:
+ virtual bool ShouldAbort() = 0;
+};
+
+int DirScan(const CString & subdir, CDiffContext * pCtxt, bool casesensitive,
+ int depth, IAbortable * piAbortable);
+
#endif // DirScan_h_included
+2003-10-25 Perry
+ PATCH: [ 828633 ] Abort running scan
+ WinMerge: DiffThread.cpp DiffThread.h DirDoc.cpp DirDoc.h
+ DirScan.cpp DirScan.h
+
2003-10-24 Perry
PATCH: [ 814832 ] Timing traces for loading file
WinMerge: MergeDoc.cpp