OSDN Git Service

Merge pull request #93 from GreyMerlin/master
[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
23 #include "DiffThread.h"
24 #include <cassert>
25 #include <climits>
26 #include <Poco/Thread.h>
27 #include <Poco/Semaphore.h>
28 #include "UnicodeString.h"
29 #include "DiffContext.h"
30 #include "DirScan.h"
31 #include "DiffItemList.h"
32 #include "PathContext.h"
33 #include "CompareStats.h"
34 #include "IAbortable.h"
35
36 using Poco::Thread;
37 using Poco::Semaphore;
38
39 // Thread functions
40 static void DiffThreadCollect(void *lpParam);
41 static void DiffThreadCompare(void *lpParam);
42
43 /** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
44 class DiffThreadAbortable : public IAbortable
45 {
46 // Implement DirScan's IAbortable
47 public:
48         virtual bool ShouldAbort() const { return m_diffthread->ShouldAbort(); }
49
50 // All this object does is forward ShouldAbort calls to its containing CDiffThread
51
52         explicit DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
53         CDiffThread * m_diffthread;
54 };
55
56 /**
57  * @brief Default constructor.
58  */
59 CDiffThread::CDiffThread()
60 : m_pDiffContext(NULL)
61 , m_bAborting(false)
62 , m_bPaused(false)
63 , m_pDiffParm(new DiffFuncStruct)
64 {
65         m_pAbortgate.reset(new DiffThreadAbortable(this));
66 }
67
68 /**
69  * @brief Destructor, release resources.
70  */
71 CDiffThread::~CDiffThread()
72 {
73         delete m_pDiffParm->pSemaphore;
74 }
75
76 /**
77  * @brief Sets context pointer forwarded to thread.
78  * @param [in] pCtx Pointer to compare context.
79  */
80 void CDiffThread::SetContext(CDiffContext * pCtx)
81 {
82         m_pDiffContext = pCtx;
83 }
84
85 /**
86  * @brief runtime interface for child thread, called on child thread
87  */
88 bool CDiffThread::ShouldAbort() const
89 {
90         while (m_bPaused && !m_bAborting)
91                 Poco::Thread::sleep(100);
92         return m_bAborting;
93 }
94
95 /**
96  * @brief Start and run directory compare thread.
97  * @return Success (1) or error for thread. Currently always 1.
98  */
99 unsigned CDiffThread::CompareDirectories()
100 {
101         assert(m_pDiffParm->nThreadState != THREAD_COMPARING);
102
103         m_pDiffParm->context = m_pDiffContext;
104         m_pDiffParm->m_pAbortgate = m_pAbortgate.get();
105         m_pDiffParm->bOnlyRequested = m_bOnlyRequested;
106         m_bAborting = false;
107         m_bPaused = false;
108
109         m_pDiffParm->nThreadState = THREAD_COMPARING;
110
111         delete m_pDiffParm->pSemaphore;
112         m_pDiffParm->pSemaphore = new Semaphore(0, LONG_MAX);
113
114         m_pDiffParm->context->m_pCompareStats->SetCompareState(CompareStats::STATE_START);
115
116         if (m_bOnlyRequested == false)
117                 m_threads[0].start(DiffThreadCollect, m_pDiffParm.get());
118         else
119         {
120                 int nItems = DirScan_UpdateMarkedItems(m_pDiffParm.get(), 0);
121                 // Send message to UI to update
122                 int event = CDiffThread::EVENT_COLLECT_COMPLETED;
123                 m_pDiffParm->m_listeners.notify(m_pDiffParm.get(), event);
124                 m_pDiffParm->context->m_pCompareStats->IncreaseTotalItems(nItems - m_pDiffParm->context->m_pCompareStats->GetTotalItems());
125         }
126         m_threads[1].start(DiffThreadCompare, m_pDiffParm.get());
127
128         return 1;
129 }
130
131 /**
132  * @brief Selects to compare all or only selected items.
133  * @param [in] bSelected If true only selected items are compared.
134  */
135 void CDiffThread::SetCompareSelected(bool bSelected /*=false*/)
136 {
137         m_bOnlyRequested = bSelected;
138 }
139
140 /**
141  * @brief Returns thread's current state
142  */
143 unsigned CDiffThread::GetThreadState() const
144 {
145         return m_pDiffParm->nThreadState;
146 }
147
148 /**
149  * @brief Item collection thread function.
150  *
151  * This thread is responsible for finding and collecting all items to compare
152  * to the item list.
153  * @param [in] lpParam Pointer to parameter structure.
154  * @return Thread's return value.
155  */
156 static void DiffThreadCollect(void *pParam)
157 {
158         PathContext paths;
159         DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
160
161         assert(myStruct->bOnlyRequested == false);
162
163         // Stash abortable interface into context
164         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
165
166         bool casesensitive = false;
167         int depth = myStruct->context->m_bRecursive ? -1 : 0;
168
169         paths = myStruct->context->GetNormalizedPaths();
170
171         String subdir[3] = {_T(""), _T(""), _T("")}; // blank to start at roots specified in diff context
172
173         // Build results list (except delaying file comparisons until below)
174         DirScan_GetItems(paths, subdir, myStruct,
175                         casesensitive, depth, NULL, myStruct->context->m_bWalkUniques);
176
177         // ReleaseSemaphore() once again to signal that collect phase is ready
178         myStruct->pSemaphore->set();
179
180         // Send message to UI to update
181         int event = CDiffThread::EVENT_COLLECT_COMPLETED;
182         myStruct->m_listeners.notify(myStruct, event);
183 };
184
185 /**
186  * @brief Folder compare thread function.
187  *
188  * Compares items in item list. After compare is ready
189  * sends message to UI so UI can update itself.
190  * @param [in] lpParam Pointer to parameter structure.
191  * @return Thread's return value.
192  */
193 static void DiffThreadCompare(void *pParam)
194 {
195         DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
196
197         // Stash abortable interface into context
198         myStruct->context->SetAbortable(myStruct->m_pAbortgate);
199
200         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE);
201
202         // Now do all pending file comparisons
203         if (myStruct->bOnlyRequested)
204                 DirScan_CompareRequestedItems(myStruct, 0);
205         else
206                 DirScan_CompareItems(myStruct, 0);
207
208         myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_IDLE);
209
210         // Send message to UI to update
211         myStruct->nThreadState = CDiffThread::THREAD_COMPLETED;
212         int event = CDiffThread::EVENT_COMPARE_COMPLETED;
213         myStruct->m_listeners.notify(myStruct, event);
214 }