OSDN Git Service

Merge with stable
[winmerge-jp/winmerge-jp.git] / Src / DiffThread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
3 //    This program is free software; you can redistribute it and/or modify
4 //    it under the terms of the GNU General Public License as published by
5 //    the Free Software Foundation; either version 2 of the License, or (at
6 //    your option) any later version.
7 //    
8 //    This program is distributed in the hope that it will be useful, but
9 //    WITHOUT ANY WARRANTY; without even the implied warranty of
10 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //    GNU General Public License for more details.
12 //
13 //    You should have received a copy of the GNU General Public License
14 //    along with this program; if not, write to the Free Software
15 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  DiffThread.cpp
19  *
20  * @brief Code for DiffThread class
21  */
22 // ID line follows -- this is updated by SVN
23 // $Id: DiffThread.cpp 6910 2009-07-12 09:06:54Z kimmov $
24
25 #include "DiffThread.h"
26 #include <cassert>
27 #include <climits>
28 #include <Poco/Thread.h>
29 #include <Poco/Semaphore.h>
30 #include "UnicodeString.h"
31 #include "DiffContext.h"
32 #include "DirScan.h"
33 #include "DiffItemList.h"
34 #include "PathContext.h"
35 #include "CompareStats.h"
36 #include "IAbortable.h"
37
38 using Poco::Thread;
39 using Poco::Semaphore;
40
41 // Thread functions
42 static void DiffThreadCollect(void *lpParam);
43 static void DiffThreadCompare(void *lpParam);
44
45 /** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
46 class DiffThreadAbortable : public IAbortable
47 {
48 // Implement DirScan's IAbortable
49 public:
50         virtual bool ShouldAbort() const { return m_diffthread->ShouldAbort(); }
51
52 // All this object does is forward ShouldAbort calls to its containing CDiffThread
53
54         DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
55         CDiffThread * m_diffthread;
56 };
57
58 /**
59  * @brief Default constructor.
60  */
61 CDiffThread::CDiffThread()
62 : m_pDiffContext(NULL)
63 , m_bAborting(false)
64 , m_pDiffParm(new DiffFuncStruct)
65 {
66         m_pAbortgate.reset(new DiffThreadAbortable(this));
67 }
68
69 /**
70  * @brief Destructor, release resources.
71  */
72 CDiffThread::~CDiffThread()
73 {
74         delete m_pDiffParm->pSemaphore;
75 }
76
77 /**
78  * @brief Sets context pointer forwarded to thread.
79  * @param [in] pCtx Pointer to compare context.
80  */
81 void CDiffThread::SetContext(CDiffContext * pCtx)
82 {
83         m_pDiffContext = pCtx;
84 }
85
86 /**
87  * @brief runtime interface for child thread, called on child thread
88  */
89 bool CDiffThread::ShouldAbort() const
90 {
91         return m_bAborting;
92 }
93
94 /**
95  * @brief Start and run directory compare thread.
96  * @return Success (1) or error for thread. Currently always 1.
97  */
98 unsigned CDiffThread::CompareDirectories()
99 {
100         assert(m_pDiffParm->nThreadState != THREAD_COMPARING);
101
102         m_pDiffParm->context = m_pDiffContext;
103         m_pDiffParm->m_pAbortgate = m_pAbortgate.get();
104         m_pDiffParm->bOnlyRequested = m_bOnlyRequested;
105         m_bAborting = false;
106
107         m_pDiffParm->nThreadState = THREAD_COMPARING;
108
109         delete m_pDiffParm->pSemaphore;
110         m_pDiffParm->pSemaphore = new Semaphore(0, LONG_MAX);
111
112         m_pDiffParm->context->m_pCompareStats->SetCompareState(CompareStats::STATE_START);
113
114         if (m_bOnlyRequested == false)
115                 m_threads[0].start(DiffThreadCollect, m_pDiffParm.get());
116         m_threads[1].start(DiffThreadCompare, m_pDiffParm.get());
117
118         return 1;
119 }
120
121 /**
122  * @brief Selects to compare all or only selected items.
123  * @param [in] bSelected If true only selected items are compared.
124  */
125 void CDiffThread::SetCompareSelected(bool bSelected /*=false*/)
126 {
127         m_bOnlyRequested = bSelected;
128 }
129
130 /**
131  * @brief Returns thread's current state
132  */
133 unsigned CDiffThread::GetThreadState() const
134 {
135         return m_pDiffParm->nThreadState;
136 }
137
138 /**
139  * @brief Item collection thread function.
140  *
141  * This thread is responsible for finding and collecting all items to compare
142  * to the item list.
143  * @param [in] lpParam Pointer to parameter structure.
144  * @return Thread's return value.
145  */
146 static void DiffThreadCollect(void *pParam)
147 {
148         PathContext paths;
149         DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
150
151         assert(myStruct->bOnlyRequested == false);
152
153         // Stash abortable interface into context
154         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
155
156         bool casesensitive = false;
157         int depth = myStruct->context->m_bRecursive ? -1 : 0;
158
159         paths = myStruct->context->GetNormalizedPaths();
160
161         String subdir[3] = {_T(""), _T(""), _T("")}; // blank to start at roots specified in diff context
162
163         // Build results list (except delaying file comparisons until below)
164         DirScan_GetItems(paths, subdir, myStruct,
165                         casesensitive, depth, NULL, myStruct->context->m_bWalkUniques);
166
167         // ReleaseSemaphore() once again to signal that collect phase is ready
168         myStruct->pSemaphore->set();
169
170         // Send message to UI to update
171         int event = CDiffThread::EVENT_COLLECT_COMPLETED;
172         myStruct->m_listeners.notify(myStruct, event);
173 };
174
175 /**
176  * @brief Folder compare thread function.
177  *
178  * Compares items in item list. After compare is ready
179  * sends message to UI so UI can update itself.
180  * @param [in] lpParam Pointer to parameter structure.
181  * @return Thread's return value.
182  */
183 static void DiffThreadCompare(void *pParam)
184 {
185         DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
186
187         // Stash abortable interface into context
188         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
189
190         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE);
191
192         // Now do all pending file comparisons
193         if (myStruct->bOnlyRequested)
194                 DirScan_CompareRequestedItems(myStruct, 0);
195         else
196                 DirScan_CompareItems(myStruct, 0);
197
198         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_IDLE);
199
200         // Send message to UI to update
201         myStruct->nThreadState = CDiffThread::THREAD_COMPLETED;
202         int event = CDiffThread::EVENT_COMPARE_COMPLETED;
203         myStruct->m_listeners.notify(myStruct, event);
204 }