OSDN Git Service

Change Dir Structure to be same as TortoiseSVN'
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / SVNProgressDlg.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "messagebox.h"\r
22 #include "SVNProgressDlg.h"\r
23 #include "LogDlg.h"\r
24 #include "TSVNPath.h"\r
25 #include "Registry.h"\r
26 #include "SVNStatus.h"\r
27 #include "AppUtils.h"\r
28 #include "PathUtils.h"\r
29 #include "StringUtils.h"\r
30 #include "TempFile.h"\r
31 #include "UnicodeUtils.h"\r
32 #include "SoundUtils.h"\r
33 #include "SVNDiff.h"\r
34 #include "Hooks.h"\r
35 #include "DropFiles.h"\r
36 #include "SVNLogHelper.h"\r
37 #include "RegHistory.h"\r
38 #include "ConflictResolveDlg.h"\r
39 #include "LogFile.h"\r
40 #include "ShellUpdater.h"\r
41 #include "IconMenu.h"\r
42 #include "BugTraqAssociations.h"\r
43 \r
44 \r
45 BOOL    CSVNProgressDlg::m_bAscending = FALSE;\r
46 int             CSVNProgressDlg::m_nSortedColumn = -1;\r
47 \r
48 #define TRANSFERTIMER   100\r
49 #define VISIBLETIMER    101\r
50 \r
51 enum SVNProgressDlgContextMenuCommands\r
52 {\r
53         // needs to start with 1, since 0 is the return value if *nothing* is clicked on in the context menu\r
54         ID_COMPARE = 1,\r
55         ID_EDITCONFLICT,\r
56         ID_CONFLICTRESOLVE,\r
57         ID_CONFLICTUSETHEIRS,\r
58         ID_CONFLICTUSEMINE,\r
59         ID_LOG,\r
60         ID_OPEN,\r
61         ID_OPENWITH,\r
62         ID_EXPLORE,\r
63         ID_COPY\r
64 };\r
65 \r
66 IMPLEMENT_DYNAMIC(CSVNProgressDlg, CResizableStandAloneDialog)\r
67 CSVNProgressDlg::CSVNProgressDlg(CWnd* pParent /*=NULL*/)\r
68         : CResizableStandAloneDialog(CSVNProgressDlg::IDD, pParent)\r
69         , m_Revision(_T("HEAD"))\r
70         , m_RevisionEnd(0)\r
71         , m_bLockWarning(false)\r
72         , m_bLockExists(false)\r
73         , m_bCancelled(FALSE)\r
74         , m_bThreadRunning(FALSE)\r
75         , m_nConflicts(0)\r
76         , m_bErrorsOccurred(FALSE)\r
77         , m_bMergesAddsDeletesOccurred(FALSE)\r
78         , m_pThread(NULL)\r
79         , m_options(ProgOptNone)\r
80         , m_dwCloseOnEnd((DWORD)-1)\r
81         , m_bFinishedItemAdded(false)\r
82         , m_bLastVisible(false)\r
83         , m_depth(svn_depth_unknown)\r
84         , m_itemCount(-1)\r
85         , m_itemCountTotal(-1)\r
86         , m_AlwaysConflicted(false)\r
87         , m_BugTraqProvider(NULL)\r
88         , sIgnoredIncluded(MAKEINTRESOURCE(IDS_PROGRS_IGNOREDINCLUDED))\r
89         , sExtExcluded(MAKEINTRESOURCE(IDS_PROGRS_EXTERNALSEXCLUDED))\r
90         , sExtIncluded(MAKEINTRESOURCE(IDS_PROGRS_EXTERNALSINCLUDED))\r
91         , sIgnoreAncestry(MAKEINTRESOURCE(IDS_PROGRS_IGNOREANCESTRY))\r
92         , sRespectAncestry(MAKEINTRESOURCE(IDS_PROGRS_RESPECTANCESTRY))\r
93         , sDryRun(MAKEINTRESOURCE(IDS_PROGRS_DRYRUN))\r
94         , sRecordOnly(MAKEINTRESOURCE(IDS_MERGE_RECORDONLY))\r
95 {\r
96 }\r
97 \r
98 CSVNProgressDlg::~CSVNProgressDlg()\r
99 {\r
100         for (size_t i=0; i<m_arData.size(); i++)\r
101         {\r
102                 delete m_arData[i];\r
103         } \r
104         if(m_pThread != NULL)\r
105         {\r
106                 delete m_pThread;\r
107         }\r
108 }\r
109 \r
110 void CSVNProgressDlg::DoDataExchange(CDataExchange* pDX)\r
111 {\r
112         CResizableStandAloneDialog::DoDataExchange(pDX);\r
113         DDX_Control(pDX, IDC_SVNPROGRESS, m_ProgList);\r
114 }\r
115 \r
116 BEGIN_MESSAGE_MAP(CSVNProgressDlg, CResizableStandAloneDialog)\r
117         ON_BN_CLICKED(IDC_LOGBUTTON, OnBnClickedLogbutton)\r
118         ON_NOTIFY(NM_CUSTOMDRAW, IDC_SVNPROGRESS, OnNMCustomdrawSvnprogress)\r
119         ON_WM_CLOSE()\r
120         ON_NOTIFY(NM_DBLCLK, IDC_SVNPROGRESS, OnNMDblclkSvnprogress)\r
121         ON_NOTIFY(HDN_ITEMCLICK, 0, OnHdnItemclickSvnprogress)\r
122         ON_WM_SETCURSOR()\r
123         ON_WM_CONTEXTMENU()\r
124         ON_REGISTERED_MESSAGE(WM_SVNPROGRESS, OnSVNProgress)\r
125         ON_WM_TIMER()\r
126         ON_EN_SETFOCUS(IDC_INFOTEXT, &CSVNProgressDlg::OnEnSetfocusInfotext)\r
127         ON_NOTIFY(LVN_BEGINDRAG, IDC_SVNPROGRESS, &CSVNProgressDlg::OnLvnBegindragSvnprogress)\r
128         ON_WM_SIZE()\r
129         ON_NOTIFY(LVN_GETDISPINFO, IDC_SVNPROGRESS, &CSVNProgressDlg::OnLvnGetdispinfoSvnprogress)\r
130         ON_BN_CLICKED(IDC_NONINTERACTIVE, &CSVNProgressDlg::OnBnClickedNoninteractive)\r
131         ON_MESSAGE(WM_SHOWCONFLICTRESOLVER, OnShowConflictResolver)\r
132 END_MESSAGE_MAP()\r
133 \r
134 BOOL CSVNProgressDlg::Cancel()\r
135 {\r
136         return m_bCancelled;\r
137 }\r
138 \r
139 LRESULT CSVNProgressDlg::OnShowConflictResolver(WPARAM /*wParam*/, LPARAM lParam)\r
140 {\r
141         CConflictResolveDlg dlg(this);\r
142         const svn_wc_conflict_description_t *description = (svn_wc_conflict_description_t *)lParam;\r
143         if (description)\r
144         {\r
145                 dlg.SetConflictDescription(description);\r
146                 if (dlg.DoModal() == IDOK)\r
147                 {\r
148                         if (dlg.GetResult() == svn_wc_conflict_choose_postpone)\r
149                         {\r
150                                 // if the result is conflicted and the dialog returned IDOK,\r
151                                 // that means we should not ask again in case of a conflict\r
152                                 m_AlwaysConflicted = true;\r
153                                 ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE)->GetSafeHwnd(), BM_SETCHECK, BST_CHECKED, 0);\r
154                         }\r
155                 }\r
156                 m_mergedfile = dlg.GetMergedFile();\r
157                 m_bCancelled = dlg.IsCancelled();\r
158                 return dlg.GetResult();\r
159         }\r
160         return svn_wc_conflict_choose_postpone;\r
161 }\r
162 \r
163 svn_wc_conflict_choice_t CSVNProgressDlg::ConflictResolveCallback(const svn_wc_conflict_description_t *description, CString& mergedfile)\r
164 {\r
165         // we only bother the user when merging\r
166         if (((m_Command == SVNProgress_Merge)||(m_Command == SVNProgress_MergeAll)||(m_Command == SVNProgress_MergeReintegrate))&&(!m_AlwaysConflicted)&&(description))\r
167         {\r
168                 // we're in a worker thread here. That means we must not show a dialog from the thread\r
169                 // but let the UI thread do it.\r
170                 // To do that, we send a message to the UI thread and let it show the conflict resolver dialog.\r
171                 LRESULT dlgResult = ::SendMessage(GetSafeHwnd(), WM_SHOWCONFLICTRESOLVER, 0, (LPARAM)description);\r
172                 mergedfile = m_mergedfile;\r
173                 return (svn_wc_conflict_choice_t)dlgResult;\r
174         }\r
175 \r
176         return svn_wc_conflict_choose_postpone;\r
177 }\r
178 \r
179 void CSVNProgressDlg::AddItemToList()\r
180 {\r
181         int totalcount = m_ProgList.GetItemCount();\r
182 \r
183         m_ProgList.SetItemCountEx(totalcount+1, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);\r
184         // make columns width fit\r
185         if (iFirstResized < 30)\r
186         {\r
187                 // only resize the columns for the first 30 or so entries.\r
188                 // after that, don't resize them anymore because that's an\r
189                 // expensive function call and the columns will be sized\r
190                 // close enough already.\r
191                 ResizeColumns();\r
192                 iFirstResized++;\r
193         }\r
194 \r
195         // Make sure the item is *entirely* visible even if the horizontal\r
196         // scroll bar is visible.\r
197         int count = m_ProgList.GetCountPerPage();\r
198         if (totalcount <= (m_ProgList.GetTopIndex() + count + nEnsureVisibleCount + 2))\r
199         {\r
200                 nEnsureVisibleCount++;\r
201                 m_bLastVisible = true;\r
202         }\r
203         else\r
204         {\r
205                 nEnsureVisibleCount = 0;\r
206                 if (IsIconic() == 0)\r
207                         m_bLastVisible = false;\r
208         }\r
209 }\r
210 \r
211 BOOL CSVNProgressDlg::Notify(const CTSVNPath& path, svn_wc_notify_action_t action, \r
212                                                          svn_node_kind_t kind, const CString& mime_type, \r
213                                                          svn_wc_notify_state_t content_state, \r
214                                                          svn_wc_notify_state_t prop_state, LONG rev,\r
215                                                          const svn_lock_t * lock, svn_wc_notify_lock_state_t lock_state,\r
216                                                          const CString& changelistname,\r
217                                                          svn_merge_range_t * range,\r
218                                                          svn_error_t * err, apr_pool_t * pool)\r
219 {\r
220         bool bNoNotify = false;\r
221         bool bDoAddData = true;\r
222         NotificationData * data = new NotificationData();\r
223         data->path = path;\r
224         data->action = action;\r
225         data->kind = kind;\r
226         data->mime_type = mime_type;\r
227         data->content_state = content_state;\r
228         data->prop_state = prop_state;\r
229         data->rev = rev;\r
230         data->lock_state = lock_state;\r
231         data->changelistname = changelistname;\r
232         if ((lock)&&(lock->owner))\r
233                 data->owner = CUnicodeUtils::GetUnicode(lock->owner);\r
234         data->sPathColumnText = path.GetUIPathString();\r
235         if (!m_basePath.IsEmpty())\r
236                 data->basepath = m_basePath;\r
237         if (range)\r
238                 data->merge_range = *range;\r
239         switch (data->action)\r
240         {\r
241         case svn_wc_notify_add:\r
242         case svn_wc_notify_update_add:\r
243                 if ((data->content_state == svn_wc_notify_state_conflicted) || (data->prop_state == svn_wc_notify_state_conflicted))\r
244                 {\r
245                         data->color = m_Colors.GetColor(CColors::Conflict);\r
246                         data->bConflictedActionItem = true;\r
247                         data->sActionColumnText.LoadString(IDS_SVNACTION_CONFLICTED);\r
248                         m_nConflicts++;\r
249                 }\r
250                 else\r
251                 {\r
252                         m_bMergesAddsDeletesOccurred = true;\r
253                         data->sActionColumnText.LoadString(IDS_SVNACTION_ADD);\r
254                         data->color = m_Colors.GetColor(CColors::Added);\r
255                 }\r
256                 break;\r
257         case svn_wc_notify_commit_added:\r
258                 data->sActionColumnText.LoadString(IDS_SVNACTION_ADDING);\r
259                 data->color = m_Colors.GetColor(CColors::Added);\r
260                 break;\r
261         case svn_wc_notify_copy:\r
262                 data->sActionColumnText.LoadString(IDS_SVNACTION_COPY);\r
263                 break;\r
264         case svn_wc_notify_commit_modified:\r
265                 data->sActionColumnText.LoadString(IDS_SVNACTION_MODIFIED);\r
266                 data->color = m_Colors.GetColor(CColors::Modified);\r
267                 break;\r
268         case svn_wc_notify_delete:\r
269         case svn_wc_notify_update_delete:\r
270                 data->sActionColumnText.LoadString(IDS_SVNACTION_DELETE);\r
271                 m_bMergesAddsDeletesOccurred = true;\r
272                 data->color = m_Colors.GetColor(CColors::Deleted);\r
273                 break;\r
274         case svn_wc_notify_commit_deleted:\r
275                 data->sActionColumnText.LoadString(IDS_SVNACTION_DELETING);\r
276                 data->color = m_Colors.GetColor(CColors::Deleted);\r
277                 break;\r
278         case svn_wc_notify_restore:\r
279                 data->sActionColumnText.LoadString(IDS_SVNACTION_RESTORE);\r
280                 break;\r
281         case svn_wc_notify_revert:\r
282                 data->sActionColumnText.LoadString(IDS_SVNACTION_REVERT);\r
283                 break;\r
284         case svn_wc_notify_resolved:\r
285                 data->sActionColumnText.LoadString(IDS_SVNACTION_RESOLVE);\r
286                 break;\r
287         case svn_wc_notify_update_replace:\r
288         case svn_wc_notify_commit_replaced:\r
289                 data->sActionColumnText.LoadString(IDS_SVNACTION_REPLACED);\r
290                 data->color = m_Colors.GetColor(CColors::Deleted);\r
291                 break;\r
292         case svn_wc_notify_exists:\r
293                 if ((data->content_state == svn_wc_notify_state_conflicted) || (data->prop_state == svn_wc_notify_state_conflicted))\r
294                 {\r
295                         data->color = m_Colors.GetColor(CColors::Conflict);\r
296                         data->bConflictedActionItem = true;\r
297                         m_nConflicts++;\r
298                         data->sActionColumnText.LoadString(IDS_SVNACTION_CONFLICTED);\r
299                 }\r
300                 else if ((data->content_state == svn_wc_notify_state_merged) || (data->prop_state == svn_wc_notify_state_merged))\r
301                 {\r
302                         data->color = m_Colors.GetColor(CColors::Merged);\r
303                         m_bMergesAddsDeletesOccurred = true;\r
304                         data->sActionColumnText.LoadString(IDS_SVNACTION_MERGED);\r
305                 }\r
306                 else\r
307                         data->sActionColumnText.LoadString(IDS_SVNACTION_EXISTS);\r
308                 break;\r
309         case svn_wc_notify_update_update:\r
310                 // if this is an inoperative dir change, don't show the notification.\r
311                 // an inoperative dir change is when a directory gets updated without\r
312                 // any real change in either text or properties.\r
313                 if ((kind == svn_node_dir)\r
314                         && ((prop_state == svn_wc_notify_state_inapplicable)\r
315                         || (prop_state == svn_wc_notify_state_unknown)\r
316                         || (prop_state == svn_wc_notify_state_unchanged)))\r
317                 {\r
318                         bNoNotify = true;\r
319                         break;\r
320                 }\r
321                 if ((data->content_state == svn_wc_notify_state_conflicted) || (data->prop_state == svn_wc_notify_state_conflicted))\r
322                 {\r
323                         data->color = m_Colors.GetColor(CColors::Conflict);\r
324                         data->bConflictedActionItem = true;\r
325                         m_nConflicts++;\r
326                         data->sActionColumnText.LoadString(IDS_SVNACTION_CONFLICTED);\r
327                 }\r
328                 else if ((data->content_state == svn_wc_notify_state_merged) || (data->prop_state == svn_wc_notify_state_merged))\r
329                 {\r
330                         data->color = m_Colors.GetColor(CColors::Merged);\r
331                         m_bMergesAddsDeletesOccurred = true;\r
332                         data->sActionColumnText.LoadString(IDS_SVNACTION_MERGED);\r
333                 }\r
334                 else if (((data->content_state != svn_wc_notify_state_unchanged)&&(data->content_state != svn_wc_notify_state_unknown)) || \r
335                         ((data->prop_state != svn_wc_notify_state_unchanged)&&(data->prop_state != svn_wc_notify_state_unknown)))\r
336                 {\r
337                         data->sActionColumnText.LoadString(IDS_SVNACTION_UPDATE);\r
338                 }\r
339                 else\r
340                 {\r
341                         bNoNotify = true;\r
342                         break;\r
343                 }\r
344                 if (lock_state == svn_wc_notify_lock_state_unlocked)\r
345                 {\r
346                         CString temp(MAKEINTRESOURCE(IDS_SVNACTION_UNLOCKED));\r
347                         data->sActionColumnText += _T(", ") + temp;\r
348                 }\r
349                 break;\r
350 \r
351         case svn_wc_notify_update_external:\r
352                 // For some reason we build a list of externals...\r
353                 m_ExtStack.AddHead(path.GetUIPathString());\r
354                 data->sActionColumnText.LoadString(IDS_SVNACTION_EXTERNAL);\r
355                 data->bAuxItem = true;\r
356                 break;\r
357 \r
358         case svn_wc_notify_update_completed:\r
359                 {\r
360                         data->sActionColumnText.LoadString(IDS_SVNACTION_COMPLETED);\r
361                         data->bAuxItem = true;\r
362                         bool bEmpty = !!m_ExtStack.IsEmpty();\r
363                         if (!bEmpty)\r
364                                 data->sPathColumnText.Format(IDS_PROGRS_PATHATREV, (LPCTSTR)m_ExtStack.RemoveHead(), rev);\r
365                         else\r
366                                 data->sPathColumnText.Format(IDS_PROGRS_ATREV, rev);\r
367 \r
368                         if ((m_nConflicts>0)&&(bEmpty))\r
369                         {\r
370                                 // We're going to add another aux item - let's shove this current onto the list first\r
371                                 // I don't really like this, but it will do for the moment.\r
372                                 m_arData.push_back(data);\r
373                                 AddItemToList();\r
374 \r
375                                 data = new NotificationData();\r
376                                 data->bAuxItem = true;\r
377                                 data->sActionColumnText.LoadString(IDS_PROGRS_CONFLICTSOCCURED_WARNING);\r
378                                 data->sPathColumnText.LoadString(IDS_PROGRS_CONFLICTSOCCURED);\r
379                                 data->color = m_Colors.GetColor(CColors::Conflict);\r
380                                 CSoundUtils::PlayTSVNWarning();\r
381                                 // This item will now be added after the switch statement\r
382                         }\r
383                         if (!m_basePath.IsEmpty())\r
384                                 m_FinishedRevMap[m_basePath.GetSVNApiPath(pool)] = rev;\r
385                         m_RevisionEnd = rev;\r
386                         m_bFinishedItemAdded = true;\r
387                 }\r
388                 break;\r
389         case svn_wc_notify_commit_postfix_txdelta:\r
390                 data->sActionColumnText.LoadString(IDS_SVNACTION_POSTFIX);\r
391                 break;\r
392         case svn_wc_notify_failed_revert:\r
393                 data->sActionColumnText.LoadString(IDS_SVNACTION_FAILEDREVERT);\r
394                 break;\r
395         case svn_wc_notify_status_completed:\r
396         case svn_wc_notify_status_external:\r
397                 data->sActionColumnText.LoadString(IDS_SVNACTION_STATUS);\r
398                 break;\r
399         case svn_wc_notify_skip:\r
400                 if ((content_state == svn_wc_notify_state_missing)||(content_state == svn_wc_notify_state_obstructed)||(content_state == svn_wc_notify_state_conflicted))\r
401                 {\r
402                         data->sActionColumnText.LoadString(IDS_SVNACTION_SKIPMISSING);\r
403 \r
404                         // The color settings dialog describes the red color with\r
405                         // "possible or real conflict / obstructed" which also applies to\r
406                         // skipped targets during a merge. So we just use the same color.\r
407                         data->color = m_Colors.GetColor(CColors::Conflict);\r
408                 }\r
409                 else\r
410                         data->sActionColumnText.LoadString(IDS_SVNACTION_SKIP);\r
411                 break;\r
412         case svn_wc_notify_locked:\r
413                 if ((lock)&&(lock->owner))\r
414                         data->sActionColumnText.Format(IDS_SVNACTION_LOCKEDBY, (LPCTSTR)CUnicodeUtils::GetUnicode(lock->owner));\r
415                 break;\r
416         case svn_wc_notify_unlocked:\r
417                 data->sActionColumnText.LoadString(IDS_SVNACTION_UNLOCKED);\r
418                 break;\r
419         case svn_wc_notify_failed_lock:\r
420                 data->sActionColumnText.LoadString(IDS_SVNACTION_FAILEDLOCK);\r
421                 m_arData.push_back(data);\r
422                 AddItemToList();\r
423                 ReportError(SVN::GetErrorString(err));\r
424                 bDoAddData = false;\r
425                 if (err->apr_err == SVN_ERR_FS_OUT_OF_DATE)\r
426                         m_bLockWarning = true;\r
427                 if (err->apr_err == SVN_ERR_FS_PATH_ALREADY_LOCKED)\r
428                         m_bLockExists = true;\r
429                 break;\r
430         case svn_wc_notify_failed_unlock:\r
431                 data->sActionColumnText.LoadString(IDS_SVNACTION_FAILEDUNLOCK);\r
432                 m_arData.push_back(data);\r
433                 AddItemToList();\r
434                 ReportError(SVN::GetErrorString(err));\r
435                 bDoAddData = false;\r
436                 if (err->apr_err == SVN_ERR_FS_OUT_OF_DATE)\r
437                         m_bLockWarning = true;\r
438                 break;\r
439         case svn_wc_notify_changelist_set:\r
440                 data->sActionColumnText.Format(IDS_SVNACTION_CHANGELISTSET, (LPCTSTR)data->changelistname);\r
441                 break;\r
442         case svn_wc_notify_changelist_clear:\r
443                 data->sActionColumnText.LoadString(IDS_SVNACTION_CHANGELISTCLEAR);\r
444                 break;\r
445         case svn_wc_notify_changelist_moved:\r
446                 data->sActionColumnText.Format(IDS_SVNACTION_CHANGELISTMOVED, (LPCTSTR)data->changelistname);\r
447                 break;\r
448         case svn_wc_notify_foreign_merge_begin:\r
449         case svn_wc_notify_merge_begin:\r
450                 if (range == NULL)\r
451                         data->sActionColumnText.LoadString(IDS_SVNACTION_MERGEBEGINNONE);\r
452                 else if ((data->merge_range.start == data->merge_range.end) || (data->merge_range.start == data->merge_range.end - 1))\r
453                         data->sActionColumnText.Format(IDS_SVNACTION_MERGEBEGINSINGLE, data->merge_range.end);\r
454                 else if (data->merge_range.start - 1 == data->merge_range.end)\r
455                         data->sActionColumnText.Format(IDS_SVNACTION_MERGEBEGINSINGLEREVERSE, data->merge_range.start);\r
456                 else if (data->merge_range.start < data->merge_range.end)\r
457                         data->sActionColumnText.Format(IDS_SVNACTION_MERGEBEGINMULTIPLE, data->merge_range.start + 1, data->merge_range.end);\r
458                 else\r
459                         data->sActionColumnText.Format(IDS_SVNACTION_MERGEBEGINMULTIPLEREVERSE, data->merge_range.start, data->merge_range.end + 1);\r
460                 data->bAuxItem = true;\r
461                 break;\r
462         default:\r
463                 break;\r
464         } // switch (data->action)\r
465 \r
466         if (bNoNotify)\r
467                 delete data;\r
468         else\r
469         {\r
470                 if (bDoAddData)\r
471                 {\r
472                         m_arData.push_back(data);\r
473                         AddItemToList();\r
474                         if ((!data->bAuxItem)&&(m_itemCount > 0))\r
475                         {\r
476                                 m_itemCount--;\r
477 \r
478                                 CProgressCtrl * progControl = (CProgressCtrl *)GetDlgItem(IDC_PROGRESSBAR);\r
479                                 progControl->ShowWindow(SW_SHOW);\r
480                                 progControl->SetPos(m_itemCountTotal - m_itemCount);\r
481                                 progControl->SetRange32(0, m_itemCountTotal);\r
482                         }\r
483                 }\r
484                 if ((action == svn_wc_notify_commit_postfix_txdelta)&&(bSecondResized == FALSE))\r
485                 {\r
486                         ResizeColumns();\r
487                         bSecondResized = TRUE;\r
488                 }\r
489         }\r
490 \r
491         return TRUE;\r
492 }\r
493 \r
494 CString CSVNProgressDlg::BuildInfoString()\r
495 {\r
496         CString infotext;\r
497         CString temp;\r
498         int added = 0;\r
499         int copied = 0;\r
500         int deleted = 0;\r
501         int restored = 0;\r
502         int reverted = 0;\r
503         int resolved = 0;\r
504         int conflicted = 0;\r
505         int updated = 0;\r
506         int merged = 0;\r
507         int modified = 0;\r
508         int skipped = 0;\r
509         int replaced = 0;\r
510 \r
511         for (size_t i=0; i<m_arData.size(); ++i)\r
512         {\r
513                 const NotificationData * dat = m_arData[i];\r
514                 switch (dat->action)\r
515                 {\r
516                 case svn_wc_notify_add:\r
517                 case svn_wc_notify_update_add:\r
518                 case svn_wc_notify_commit_added:\r
519                         if (dat->bConflictedActionItem)\r
520                                 conflicted++;\r
521                         else\r
522                                 added++;\r
523                         break;\r
524                 case svn_wc_notify_copy:\r
525                         copied++;\r
526                         break;\r
527                 case svn_wc_notify_delete:\r
528                 case svn_wc_notify_update_delete:\r
529                 case svn_wc_notify_commit_deleted:\r
530                         deleted++;\r
531                         break;\r
532                 case svn_wc_notify_restore:\r
533                         restored++;\r
534                         break;\r
535                 case svn_wc_notify_revert:\r
536                         reverted++;\r
537                         break;\r
538                 case svn_wc_notify_resolved:\r
539                         resolved++;\r
540                         break;\r
541                 case svn_wc_notify_update_update:\r
542                         if (dat->bConflictedActionItem)\r
543                                 conflicted++;\r
544                         else if ((dat->content_state == svn_wc_notify_state_merged) || (dat->prop_state == svn_wc_notify_state_merged))\r
545                                 merged++;\r
546                         else\r
547                                 updated++;\r
548                         break;\r
549                 case svn_wc_notify_commit_modified:\r
550                         modified++;\r
551                         break;\r
552                 case svn_wc_notify_skip:\r
553                         skipped++;\r
554                         break;\r
555                 case svn_wc_notify_commit_replaced:\r
556                         replaced++;\r
557                         break;\r
558                 }\r
559         }\r
560         if (conflicted)\r
561         {\r
562                 temp.LoadString(IDS_SVNACTION_CONFLICTED);\r
563                 infotext += temp;\r
564                 temp.Format(_T(":%d "), conflicted);\r
565                 infotext += temp;\r
566         }\r
567         if (skipped)\r
568         {\r
569                 temp.LoadString(IDS_SVNACTION_SKIP);\r
570                 infotext += temp;\r
571                 infotext.AppendFormat(_T(":%d "), skipped);\r
572         }\r
573         if (merged)\r
574         {\r
575                 temp.LoadString(IDS_SVNACTION_MERGED);\r
576                 infotext += temp;\r
577                 infotext.AppendFormat(_T(":%d "), merged);\r
578         }\r
579         if (added)\r
580         {\r
581                 temp.LoadString(IDS_SVNACTION_ADD);\r
582                 infotext += temp;\r
583                 infotext.AppendFormat(_T(":%d "), added);\r
584         }\r
585         if (deleted)\r
586         {\r
587                 temp.LoadString(IDS_SVNACTION_DELETE);\r
588                 infotext += temp;\r
589                 infotext.AppendFormat(_T(":%d "), deleted);\r
590         }\r
591         if (modified)\r
592         {\r
593                 temp.LoadString(IDS_SVNACTION_MODIFIED);\r
594                 infotext += temp;\r
595                 infotext.AppendFormat(_T(":%d "), modified);\r
596         }\r
597         if (copied)\r
598         {\r
599                 temp.LoadString(IDS_SVNACTION_COPY);\r
600                 infotext += temp;\r
601                 infotext.AppendFormat(_T(":%d "), copied);\r
602         }\r
603         if (replaced)\r
604         {\r
605                 temp.LoadString(IDS_SVNACTION_REPLACED);\r
606                 infotext += temp;\r
607                 infotext.AppendFormat(_T(":%d "), replaced);\r
608         }\r
609         if (updated)\r
610         {\r
611                 temp.LoadString(IDS_SVNACTION_UPDATE);\r
612                 infotext += temp;\r
613                 infotext.AppendFormat(_T(":%d "), updated);\r
614         }\r
615         if (restored)\r
616         {\r
617                 temp.LoadString(IDS_SVNACTION_RESTORE);\r
618                 infotext += temp;\r
619                 infotext.AppendFormat(_T(":%d "), restored);\r
620         }\r
621         if (reverted)\r
622         {\r
623                 temp.LoadString(IDS_SVNACTION_REVERT);\r
624                 infotext += temp;\r
625                 infotext.AppendFormat(_T(":%d "), reverted);\r
626         }\r
627         if (resolved)\r
628         {\r
629                 temp.LoadString(IDS_SVNACTION_RESOLVE);\r
630                 infotext += temp;\r
631                 infotext.AppendFormat(_T(":%d "), resolved);\r
632         }\r
633         return infotext;\r
634 }\r
635 \r
636 void CSVNProgressDlg::SetSelectedList(const CTSVNPathList& selPaths)\r
637 {\r
638         m_selectedPaths = selPaths;\r
639 }\r
640 \r
641 void CSVNProgressDlg::ResizeColumns()\r
642 {\r
643         m_ProgList.SetRedraw(FALSE);\r
644 \r
645         TCHAR textbuf[MAX_PATH];\r
646 \r
647         int maxcol = ((CHeaderCtrl*)(m_ProgList.GetDlgItem(0)))->GetItemCount()-1;\r
648         for (int col = 0; col <= maxcol; col++)\r
649         {\r
650                 // find the longest width of all items\r
651                 int count = m_ProgList.GetItemCount();\r
652                 HDITEM hdi = {0};\r
653                 hdi.mask = HDI_TEXT;\r
654                 hdi.pszText = textbuf;\r
655                 hdi.cchTextMax = sizeof(textbuf);\r
656                 ((CHeaderCtrl*)(m_ProgList.GetDlgItem(0)))->GetItem(col, &hdi);\r
657                 int cx = m_ProgList.GetStringWidth(hdi.pszText)+20; // 20 pixels for col separator and margin\r
658 \r
659                 for (int index = 0; index<count; ++index)\r
660                 {\r
661                         // get the width of the string and add 12 pixels for the column separator and margins\r
662                         int linewidth = cx;\r
663                         switch (col)\r
664                         {\r
665                         case 0:\r
666                                 linewidth = m_ProgList.GetStringWidth(m_arData[index]->sActionColumnText) + 12;\r
667                                 break;\r
668                         case 1:\r
669                                 linewidth = m_ProgList.GetStringWidth(m_arData[index]->sPathColumnText) + 12;\r
670                                 break;\r
671                         case 2:\r
672                                 linewidth = m_ProgList.GetStringWidth(m_arData[index]->mime_type) + 12;\r
673                                 break;\r
674                         }\r
675                         if (cx < linewidth)\r
676                                 cx = linewidth;\r
677                 }\r
678                 m_ProgList.SetColumnWidth(col, cx);\r
679         }\r
680 \r
681         m_ProgList.SetRedraw(TRUE);     \r
682 }\r
683 \r
684 BOOL CSVNProgressDlg::OnInitDialog()\r
685 {\r
686         __super::OnInitDialog();\r
687 \r
688         m_ProgList.SetExtendedStyle (LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);\r
689 \r
690         m_ProgList.DeleteAllItems();\r
691         int c = ((CHeaderCtrl*)(m_ProgList.GetDlgItem(0)))->GetItemCount()-1;\r
692         while (c>=0)\r
693                 m_ProgList.DeleteColumn(c--);\r
694         CString temp;\r
695         temp.LoadString(IDS_PROGRS_ACTION);\r
696         m_ProgList.InsertColumn(0, temp);\r
697         temp.LoadString(IDS_PROGRS_PATH);\r
698         m_ProgList.InsertColumn(1, temp);\r
699         temp.LoadString(IDS_PROGRS_MIMETYPE);\r
700         m_ProgList.InsertColumn(2, temp);\r
701 \r
702         m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);\r
703         if (m_pThread==NULL)\r
704         {\r
705                 ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));\r
706         }\r
707         else\r
708         {\r
709                 m_pThread->m_bAutoDelete = FALSE;\r
710                 m_pThread->ResumeThread();\r
711         }\r
712 \r
713         UpdateData(FALSE);\r
714 \r
715         // Call this early so that the column headings aren't hidden before any\r
716         // text gets added.\r
717         ResizeColumns();\r
718 \r
719         SetTimer(VISIBLETIMER, 300, NULL);\r
720 \r
721         AddAnchor(IDC_SVNPROGRESS, TOP_LEFT, BOTTOM_RIGHT);\r
722         AddAnchor(IDC_PROGRESSLABEL, BOTTOM_LEFT, BOTTOM_CENTER);\r
723         AddAnchor(IDC_PROGRESSBAR, BOTTOM_CENTER, BOTTOM_RIGHT);\r
724         AddAnchor(IDC_INFOTEXT, BOTTOM_LEFT, BOTTOM_RIGHT);\r
725         AddAnchor(IDC_NONINTERACTIVE, BOTTOM_LEFT, BOTTOM_RIGHT);\r
726         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
727         AddAnchor(IDOK, BOTTOM_RIGHT);\r
728         AddAnchor(IDC_LOGBUTTON, BOTTOM_RIGHT);\r
729         SetPromptParentWindow(this->m_hWnd);\r
730         if (hWndExplorer)\r
731                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
732         EnableSaveRestore(_T("SVNProgressDlg"));\r
733         return TRUE;\r
734 }\r
735 \r
736 bool CSVNProgressDlg::SetBackgroundImage(UINT nID)\r
737 {\r
738         return CAppUtils::SetListCtrlBackgroundImage(m_ProgList.GetSafeHwnd(), nID);\r
739 }\r
740 \r
741 void CSVNProgressDlg::ReportSVNError()\r
742 {\r
743         ReportError(GetLastErrorMessage());\r
744 }\r
745 \r
746 void CSVNProgressDlg::ReportError(const CString& sError)\r
747 {\r
748         CSoundUtils::PlayTSVNError();\r
749         ReportString(sError, CString(MAKEINTRESOURCE(IDS_ERR_ERROR)), m_Colors.GetColor(CColors::Conflict));\r
750         m_bErrorsOccurred = true;\r
751 }\r
752 \r
753 void CSVNProgressDlg::ReportWarning(const CString& sWarning)\r
754 {\r
755         CSoundUtils::PlayTSVNWarning();\r
756         ReportString(sWarning, CString(MAKEINTRESOURCE(IDS_WARN_WARNING)), m_Colors.GetColor(CColors::Conflict));\r
757 }\r
758 \r
759 void CSVNProgressDlg::ReportNotification(const CString& sNotification)\r
760 {\r
761         CSoundUtils::PlayTSVNNotification();\r
762         ReportString(sNotification, CString(MAKEINTRESOURCE(IDS_WARN_NOTE)));\r
763 }\r
764 \r
765 void CSVNProgressDlg::ReportCmd(const CString& sCmd)\r
766 {\r
767         ReportString(sCmd, CString(MAKEINTRESOURCE(IDS_PROGRS_CMDINFO)), m_Colors.GetColor(CColors::Cmd));\r
768 }\r
769 \r
770 void CSVNProgressDlg::ReportString(CString sMessage, const CString& sMsgKind, COLORREF color)\r
771 {\r
772         // instead of showing a dialog box with the error message or notification,\r
773         // just insert the error text into the list control.\r
774         // that way the user isn't 'interrupted' by a dialog box popping up!\r
775 \r
776         // the message may be split up into different lines\r
777         // so add a new entry for each line of the message\r
778         while (!sMessage.IsEmpty())\r
779         {\r
780                 NotificationData * data = new NotificationData();\r
781                 data->bAuxItem = true;\r
782                 data->sActionColumnText = sMsgKind;\r
783                 if (sMessage.Find('\n')>=0)\r
784                         data->sPathColumnText = sMessage.Left(sMessage.Find('\n'));\r
785                 else\r
786                         data->sPathColumnText = sMessage;               \r
787                 data->sPathColumnText.Trim(_T("\n\r"));\r
788                 data->color = color;\r
789                 if (sMessage.Find('\n')>=0)\r
790                 {\r
791                         sMessage = sMessage.Mid(sMessage.Find('\n'));\r
792                         sMessage.Trim(_T("\n\r"));\r
793                 }\r
794                 else\r
795                         sMessage.Empty();\r
796                 m_arData.push_back(data);\r
797                 AddItemToList();\r
798         }\r
799 }\r
800 \r
801 UINT CSVNProgressDlg::ProgressThreadEntry(LPVOID pVoid)\r
802 {\r
803         return ((CSVNProgressDlg*)pVoid)->ProgressThread();\r
804 }\r
805 \r
806 UINT CSVNProgressDlg::ProgressThread()\r
807 {\r
808         // The SetParams function should have loaded something for us\r
809 \r
810         CString temp;\r
811         CString sWindowTitle;\r
812         bool localoperation = false;\r
813         bool bSuccess = false;\r
814         m_AlwaysConflicted = false;\r
815 \r
816         DialogEnableWindow(IDOK, FALSE);\r
817         DialogEnableWindow(IDCANCEL, TRUE);\r
818         SetAndClearProgressInfo(m_hWnd);\r
819         m_itemCount = m_itemCountTotal;\r
820 \r
821         InterlockedExchange(&m_bThreadRunning, TRUE);\r
822         iFirstResized = 0;\r
823         bSecondResized = FALSE;\r
824         m_bFinishedItemAdded = false;\r
825         CTime startTime = CTime::GetCurrentTime();\r
826         switch (m_Command)\r
827         {\r
828         case SVNProgress_Add:\r
829                 bSuccess = CmdAdd(sWindowTitle, localoperation);\r
830                 break;\r
831         case SVNProgress_Checkout:\r
832                 bSuccess = CmdCheckout(sWindowTitle, localoperation);\r
833                 break;\r
834         case SVNProgress_Commit:\r
835                 bSuccess = CmdCommit(sWindowTitle, localoperation);\r
836                 break;\r
837         case SVNProgress_Copy:\r
838                 bSuccess = CmdCopy(sWindowTitle, localoperation);\r
839                 break;\r
840         case SVNProgress_Export:\r
841                 bSuccess = CmdExport(sWindowTitle, localoperation);\r
842                 break;\r
843         case SVNProgress_Import:\r
844                 bSuccess = CmdImport(sWindowTitle, localoperation);\r
845                 break;\r
846         case SVNProgress_Lock:\r
847                 bSuccess = CmdLock(sWindowTitle, localoperation);\r
848                 break;\r
849         case SVNProgress_Merge:\r
850                 bSuccess = CmdMerge(sWindowTitle, localoperation);\r
851                 break;\r
852         case SVNProgress_MergeAll:\r
853                 bSuccess = CmdMergeAll(sWindowTitle, localoperation);\r
854                 break;\r
855         case SVNProgress_MergeReintegrate:\r
856                 bSuccess = CmdMergeReintegrate(sWindowTitle, localoperation);\r
857                 break;\r
858         case SVNProgress_Rename:\r
859                 bSuccess = CmdRename(sWindowTitle, localoperation);\r
860                 break;\r
861         case SVNProgress_Resolve:\r
862                 bSuccess = CmdResolve(sWindowTitle, localoperation);\r
863                 break;\r
864         case SVNProgress_Revert:\r
865                 bSuccess = CmdRevert(sWindowTitle, localoperation);\r
866                 break;\r
867         case SVNProgress_Switch:\r
868                 bSuccess = CmdSwitch(sWindowTitle, localoperation);\r
869                 break;\r
870         case SVNProgress_Unlock:\r
871                 bSuccess = CmdUnlock(sWindowTitle, localoperation);\r
872                 break;\r
873         case SVNProgress_Update:\r
874                 bSuccess = CmdUpdate(sWindowTitle, localoperation);\r
875                 break;\r
876         }\r
877         if (!bSuccess)\r
878                 temp.LoadString(IDS_PROGRS_TITLEFAILED);\r
879         else\r
880                 temp.LoadString(IDS_PROGRS_TITLEFIN);\r
881         sWindowTitle = sWindowTitle + _T(" ") + temp;\r
882         SetWindowText(sWindowTitle);\r
883 \r
884         KillTimer(TRANSFERTIMER);\r
885         KillTimer(VISIBLETIMER);\r
886 \r
887         DialogEnableWindow(IDCANCEL, FALSE);\r
888         DialogEnableWindow(IDOK, TRUE);\r
889 \r
890         CString info = BuildInfoString();\r
891         if (!bSuccess)\r
892                 info.LoadString(IDS_PROGRS_INFOFAILED);\r
893         SetDlgItemText(IDC_INFOTEXT, info);\r
894         ResizeColumns();\r
895         SendMessage(DM_SETDEFID, IDOK);\r
896         GetDlgItem(IDOK)->SetFocus();   \r
897 \r
898         CString sFinalInfo;\r
899         if (!m_sTotalBytesTransferred.IsEmpty())\r
900         {\r
901                 CTimeSpan time = CTime::GetCurrentTime() - startTime;\r
902                 temp.Format(IDS_PROGRS_TIME, (LONG)time.GetTotalMinutes(), (LONG)time.GetSeconds());\r
903                 sFinalInfo.Format(IDS_PROGRS_FINALINFO, m_sTotalBytesTransferred, (LPCTSTR)temp);\r
904                 SetDlgItemText(IDC_PROGRESSLABEL, sFinalInfo);\r
905         }\r
906         else\r
907                 GetDlgItem(IDC_PROGRESSLABEL)->ShowWindow(SW_HIDE);\r
908 \r
909         GetDlgItem(IDC_PROGRESSBAR)->ShowWindow(SW_HIDE);\r
910 \r
911         if (!m_bFinishedItemAdded)\r
912         {\r
913                 // there's no "finished: xxx" line at the end. We add one here to make\r
914                 // sure the user sees that the command is actually finished.\r
915                 NotificationData * data = new NotificationData();\r
916                 data->bAuxItem = true;\r
917                 data->sActionColumnText.LoadString(IDS_PROGRS_FINISHED);\r
918                 m_arData.push_back(data);\r
919                 AddItemToList();\r
920         }\r
921 \r
922         int count = m_ProgList.GetItemCount();\r
923         if ((count > 0)&&(m_bLastVisible))\r
924                 m_ProgList.EnsureVisible(count-1, FALSE);\r
925 \r
926         CLogFile logfile;\r
927         if (logfile.Open())\r
928         {\r
929                 logfile.AddTimeLine();\r
930                 for (size_t i=0; i<m_arData.size(); i++)\r
931                 {\r
932                         NotificationData * data = m_arData[i];\r
933                         temp.Format(_T("%-20s : %s"), (LPCTSTR)data->sActionColumnText, (LPCTSTR)data->sPathColumnText);\r
934                         logfile.AddLine(temp);\r
935                 }\r
936                 if (!sFinalInfo.IsEmpty())\r
937                         logfile.AddLine(sFinalInfo);\r
938                 logfile.Close();\r
939         }\r
940 \r
941         m_bCancelled = TRUE;\r
942         InterlockedExchange(&m_bThreadRunning, FALSE);\r
943         RefreshCursor();\r
944 \r
945         DWORD dwAutoClose = CRegStdWORD(_T("Software\\TortoiseSVN\\AutoClose"));\r
946         if (m_options & ProgOptDryRun)\r
947                 dwAutoClose = 0;                // dry run means progress dialog doesn't auto close at all\r
948         if (!m_bLastVisible)\r
949                 dwAutoClose = 0;\r
950         if (m_dwCloseOnEnd != (DWORD)-1)\r
951                 dwAutoClose = m_dwCloseOnEnd;           // command line value has priority over setting value\r
952         if ((dwAutoClose == CLOSE_NOERRORS)&&(!m_bErrorsOccurred))\r
953                 PostMessage(WM_COMMAND, 1, (LPARAM)GetDlgItem(IDOK)->m_hWnd);\r
954         if ((dwAutoClose == CLOSE_NOCONFLICTS)&&(!m_bErrorsOccurred)&&(m_nConflicts==0))\r
955                 PostMessage(WM_COMMAND, 1, (LPARAM)GetDlgItem(IDOK)->m_hWnd);\r
956         if ((dwAutoClose == CLOSE_NOMERGES)&&(!m_bErrorsOccurred)&&(m_nConflicts==0)&&(!m_bMergesAddsDeletesOccurred))\r
957                 PostMessage(WM_COMMAND, 1, (LPARAM)GetDlgItem(IDOK)->m_hWnd);\r
958         if ((dwAutoClose == CLOSE_LOCAL)&&(!m_bErrorsOccurred)&&(m_nConflicts==0)&&(localoperation))\r
959                 PostMessage(WM_COMMAND, 1, (LPARAM)GetDlgItem(IDOK)->m_hWnd);\r
960 \r
961         //Don't do anything here which might cause messages to be sent to the window\r
962         //The window thread is probably now blocked in OnOK if we've done an auto close\r
963         return 0;\r
964 }\r
965 \r
966 void CSVNProgressDlg::OnBnClickedLogbutton()\r
967 {\r
968         if (m_targetPathList.GetCount() != 1)\r
969                 return;\r
970         StringRevMap::iterator it = m_UpdateStartRevMap.begin();\r
971         svn_revnum_t rev = -1;\r
972         if (it != m_UpdateStartRevMap.end())\r
973         {\r
974                 rev = it->second;\r
975         }\r
976         CLogDlg dlg;\r
977         dlg.SetParams(m_targetPathList[0], m_RevisionEnd, m_RevisionEnd, rev, 0, TRUE);\r
978         dlg.DoModal();\r
979 }\r
980 \r
981 \r
982 void CSVNProgressDlg::OnClose()\r
983 {\r
984         if (m_bCancelled)\r
985         {\r
986                 TerminateThread(m_pThread->m_hThread, (DWORD)-1);\r
987                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
988         }\r
989         else\r
990         {\r
991                 m_bCancelled = TRUE;\r
992                 return;\r
993         }\r
994         DialogEnableWindow(IDCANCEL, TRUE);\r
995         __super::OnClose();\r
996 }\r
997 \r
998 void CSVNProgressDlg::OnOK()\r
999 {\r
1000         if ((m_bCancelled)&&(!m_bThreadRunning))\r
1001         {\r
1002                 // I have made this wait a sensible amount of time (10 seconds) for the thread to finish\r
1003                 // You must be careful in the thread that after posting the WM_COMMAND/IDOK message, you \r
1004                 // don't do any more operations on the window which might require message passing\r
1005                 // If you try to send windows messages once we're waiting here, then the thread can't finished\r
1006                 // because the Window's message loop is blocked at this wait\r
1007                 WaitForSingleObject(m_pThread->m_hThread, 10000);\r
1008                 __super::OnOK();\r
1009         }\r
1010         m_bCancelled = TRUE;\r
1011 }\r
1012 \r
1013 void CSVNProgressDlg::OnCancel()\r
1014 {\r
1015         if ((m_bCancelled)&&(!m_bThreadRunning))\r
1016                 __super::OnCancel();\r
1017         m_bCancelled = TRUE;\r
1018 }\r
1019 \r
1020 void CSVNProgressDlg::OnLvnGetdispinfoSvnprogress(NMHDR *pNMHDR, LRESULT *pResult)\r
1021 {\r
1022         NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);\r
1023 \r
1024         if (pDispInfo)\r
1025         {\r
1026                 if (pDispInfo->item.mask & LVIF_TEXT)\r
1027                 {\r
1028                         if (pDispInfo->item.iItem < (int)m_arData.size())\r
1029                         {\r
1030                                 const NotificationData * data = m_arData[pDispInfo->item.iItem];\r
1031                                 switch (pDispInfo->item.iSubItem)\r
1032                                 {\r
1033                                 case 0:\r
1034                                         lstrcpyn(m_columnbuf, data->sActionColumnText, MAX_PATH);\r
1035                                         break;\r
1036                                 case 1:\r
1037                                         lstrcpyn(m_columnbuf, data->sPathColumnText, pDispInfo->item.cchTextMax);\r
1038                                         if (!data->bAuxItem)\r
1039                                         {\r
1040                                                 int cWidth = m_ProgList.GetColumnWidth(1);\r
1041                                                 cWidth = max(12, cWidth-12);\r
1042                                                 CDC * pDC = m_ProgList.GetDC();\r
1043                         if (pDC != NULL)\r
1044                         {\r
1045                                                     CFont * pFont = pDC->SelectObject(m_ProgList.GetFont());\r
1046                                                     PathCompactPath(pDC->GetSafeHdc(), m_columnbuf, cWidth);\r
1047                                                     pDC->SelectObject(pFont);\r
1048                                                         ReleaseDC(pDC);\r
1049                         }\r
1050                                         }\r
1051                                         break;\r
1052                                 case 2:\r
1053                                         lstrcpyn(m_columnbuf, data->mime_type, MAX_PATH);\r
1054                                         break;\r
1055                                 default:\r
1056                                         m_columnbuf[0] = 0;\r
1057                                 }\r
1058                                 pDispInfo->item.pszText = m_columnbuf;\r
1059                         }\r
1060                 }\r
1061         }\r
1062         *pResult = 0;\r
1063 }\r
1064 \r
1065 void CSVNProgressDlg::OnNMCustomdrawSvnprogress(NMHDR *pNMHDR, LRESULT *pResult)\r
1066 {\r
1067         NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );\r
1068 \r
1069         // Take the default processing unless we set this to something else below.\r
1070         *pResult = CDRF_DODEFAULT;\r
1071 \r
1072         // First thing - check the draw stage. If it's the control's prepaint\r
1073         // stage, then tell Windows we want messages for every item.\r
1074 \r
1075         if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )\r
1076         {\r
1077                 *pResult = CDRF_NOTIFYITEMDRAW;\r
1078         }\r
1079         else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )\r
1080         {\r
1081                 // This is the prepaint stage for an item. Here's where we set the\r
1082                 // item's text color. Our return value will tell Windows to draw the\r
1083                 // item itself, but it will use the new color we set here.\r
1084 \r
1085                 // Tell Windows to paint the control itself.\r
1086                 *pResult = CDRF_DODEFAULT;\r
1087 \r
1088                 ASSERT(pLVCD->nmcd.dwItemSpec <  m_arData.size());\r
1089                 if(pLVCD->nmcd.dwItemSpec >= m_arData.size())\r
1090                 {\r
1091                         return;\r
1092                 }\r
1093                 const NotificationData * data = m_arData[pLVCD->nmcd.dwItemSpec];\r
1094                 ASSERT(data != NULL);\r
1095                 if (data == NULL)\r
1096                         return;\r
1097 \r
1098                 // Store the color back in the NMLVCUSTOMDRAW struct.\r
1099                 pLVCD->clrText = data->color;\r
1100         }\r
1101 }\r
1102 \r
1103 void CSVNProgressDlg::OnNMDblclkSvnprogress(NMHDR *pNMHDR, LRESULT *pResult)\r
1104 {\r
1105         LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1106         *pResult = 0;\r
1107         if (pNMLV->iItem < 0)\r
1108                 return;\r
1109         if (m_options & ProgOptDryRun)\r
1110                 return; //don't do anything in a dry-run.\r
1111 \r
1112         const NotificationData * data = m_arData[pNMLV->iItem];\r
1113         if (data == NULL)\r
1114                 return;\r
1115 \r
1116         if (data->bConflictedActionItem)\r
1117         {\r
1118                 // We've double-clicked on a conflicted item - do a three-way merge on it\r
1119                 SVNDiff::StartConflictEditor(data->path);\r
1120         }\r
1121         else if ((data->action == svn_wc_notify_update_update) && ((data->content_state == svn_wc_notify_state_merged)||(SVNProgress_Merge == m_Command)) || (data->action == svn_wc_notify_resolved))\r
1122         {\r
1123                 // This is a modified file which has been merged on update. Diff it against base\r
1124                 CTSVNPath temporaryFile;\r
1125                 SVNDiff diff(this, this->m_hWnd, true);\r
1126                 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));\r
1127                 svn_revnum_t baseRev = 0;\r
1128                 diff.DiffFileAgainstBase(data->path, baseRev);\r
1129         }\r
1130         else if ((!data->bAuxItem)&&(data->path.Exists())&&(!data->path.IsDirectory()))\r
1131         {\r
1132                 bool bOpenWith = false;\r
1133                 int ret = (int)ShellExecute(m_hWnd, NULL, data->path.GetWinPath(), NULL, NULL, SW_SHOWNORMAL);\r
1134                 if (ret <= HINSTANCE_ERROR)\r
1135                         bOpenWith = true;\r
1136                 if (bOpenWith)\r
1137                 {\r
1138                         CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
1139                         cmd += data->path.GetWinPathString() + _T(" ");\r
1140                         CAppUtils::LaunchApplication(cmd, NULL, false);\r
1141                 }\r
1142         }\r
1143 }\r
1144 \r
1145 void CSVNProgressDlg::OnHdnItemclickSvnprogress(NMHDR *pNMHDR, LRESULT *pResult)\r
1146 {\r
1147         LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);\r
1148         if (m_bThreadRunning)\r
1149                 return;\r
1150         if (m_nSortedColumn == phdr->iItem)\r
1151                 m_bAscending = !m_bAscending;\r
1152         else\r
1153                 m_bAscending = TRUE;\r
1154         m_nSortedColumn = phdr->iItem;\r
1155         Sort();\r
1156 \r
1157         CString temp;\r
1158         m_ProgList.SetRedraw(FALSE);\r
1159         m_ProgList.DeleteAllItems();\r
1160         m_ProgList.SetItemCountEx (static_cast<int>(m_arData.size()));\r
1161 \r
1162         m_ProgList.SetRedraw(TRUE);\r
1163 \r
1164         *pResult = 0;\r
1165 }\r
1166 \r
1167 bool CSVNProgressDlg::NotificationDataIsAux(const NotificationData* pData)\r
1168 {\r
1169         return pData->bAuxItem;\r
1170 }\r
1171 \r
1172 LRESULT CSVNProgressDlg::OnSVNProgress(WPARAM /*wParam*/, LPARAM lParam)\r
1173 {\r
1174         SVNProgress * pProgressData = (SVNProgress *)lParam;\r
1175         CProgressCtrl * progControl = (CProgressCtrl *)GetDlgItem(IDC_PROGRESSBAR);\r
1176         if ((pProgressData->total > 1000)&&(!progControl->IsWindowVisible()))\r
1177         {\r
1178                 progControl->ShowWindow(SW_SHOW);\r
1179         }\r
1180         if (((pProgressData->total < 0)&&(pProgressData->progress > 1000)&&(progControl->IsWindowVisible()))&&(m_itemCountTotal<0))\r
1181         {\r
1182                 progControl->ShowWindow(SW_HIDE);\r
1183         }\r
1184         if (!GetDlgItem(IDC_PROGRESSLABEL)->IsWindowVisible())\r
1185                 GetDlgItem(IDC_PROGRESSLABEL)->ShowWindow(SW_SHOW);\r
1186         SetTimer(TRANSFERTIMER, 2000, NULL);\r
1187         if ((pProgressData->total > 0)&&(pProgressData->progress > 1000))\r
1188         {\r
1189                 progControl->SetPos((int)pProgressData->progress);\r
1190                 progControl->SetRange32(0, (int)pProgressData->total);\r
1191         }\r
1192         CString progText;\r
1193         if (pProgressData->overall_total < 1024)\r
1194                 m_sTotalBytesTransferred.Format(IDS_SVN_PROGRESS_TOTALBYTESTRANSFERRED, pProgressData->overall_total);  \r
1195         else if (pProgressData->overall_total < 1200000)\r
1196                 m_sTotalBytesTransferred.Format(IDS_SVN_PROGRESS_TOTALTRANSFERRED, pProgressData->overall_total / 1024);\r
1197         else\r
1198                 m_sTotalBytesTransferred.Format(IDS_SVN_PROGRESS_TOTALMBTRANSFERRED, (double)((double)pProgressData->overall_total / 1024000.0));\r
1199         progText.Format(IDS_SVN_PROGRESS_TOTALANDSPEED, (LPCTSTR)m_sTotalBytesTransferred, (LPCTSTR)pProgressData->SpeedString);\r
1200         SetDlgItemText(IDC_PROGRESSLABEL, progText);\r
1201         return 0;\r
1202 }\r
1203 \r
1204 void CSVNProgressDlg::OnTimer(UINT_PTR nIDEvent)\r
1205 {\r
1206         if (nIDEvent == TRANSFERTIMER)\r
1207         {\r
1208                 CString progText;\r
1209                 CString progSpeed;\r
1210                 progSpeed.Format(IDS_SVN_PROGRESS_BYTES_SEC, 0);\r
1211                 progText.Format(IDS_SVN_PROGRESS_TOTALANDSPEED, (LPCTSTR)m_sTotalBytesTransferred, (LPCTSTR)progSpeed);\r
1212                 SetDlgItemText(IDC_PROGRESSLABEL, progText);\r
1213                 KillTimer(TRANSFERTIMER);\r
1214         }\r
1215         if (nIDEvent == VISIBLETIMER)\r
1216         {\r
1217                 if (nEnsureVisibleCount)\r
1218                         m_ProgList.EnsureVisible(m_ProgList.GetItemCount()-1, false);\r
1219                 nEnsureVisibleCount = 0;\r
1220         }\r
1221 }\r
1222 \r
1223 void CSVNProgressDlg::Sort()\r
1224 {\r
1225         if(m_arData.size() < 2)\r
1226         {\r
1227                 return;\r
1228         }\r
1229 \r
1230         // We need to sort the blocks which lie between the auxiliary entries\r
1231         // This is so that any aux data stays where it was\r
1232         NotificationDataVect::iterator actionBlockBegin;\r
1233         NotificationDataVect::iterator actionBlockEnd = m_arData.begin();       // We start searching from here\r
1234 \r
1235         for(;;)\r
1236         {\r
1237                 // Search to the start of the non-aux entry in the next block\r
1238                 actionBlockBegin = std::find_if(actionBlockEnd, m_arData.end(), std::not1(std::ptr_fun(&CSVNProgressDlg::NotificationDataIsAux)));\r
1239                 if(actionBlockBegin == m_arData.end())\r
1240                 {\r
1241                         // There are no more actions\r
1242                         break;\r
1243                 }\r
1244                 // Now search to find the end of the block\r
1245                 actionBlockEnd = std::find_if(actionBlockBegin+1, m_arData.end(), std::ptr_fun(&CSVNProgressDlg::NotificationDataIsAux));\r
1246                 // Now sort the block\r
1247                 std::sort(actionBlockBegin, actionBlockEnd, &CSVNProgressDlg::SortCompare);\r
1248         }\r
1249 }\r
1250 \r
1251 bool CSVNProgressDlg::SortCompare(const NotificationData * pData1, const NotificationData * pData2)\r
1252 {\r
1253         int result = 0;\r
1254         switch (m_nSortedColumn)\r
1255         {\r
1256         case 0:         //action column\r
1257                 result = pData1->sActionColumnText.Compare(pData2->sActionColumnText);\r
1258                 break;\r
1259         case 1:         //path column\r
1260                 // Compare happens after switch()\r
1261                 break;\r
1262         case 2:         //mime-type column\r
1263                 result = pData1->mime_type.Compare(pData2->mime_type);\r
1264                 break;\r
1265         default:\r
1266                 break;\r
1267         }\r
1268 \r
1269         // Sort by path if everything else is equal\r
1270         if (result == 0)\r
1271         {\r
1272                 result = CTSVNPath::Compare(pData1->path, pData2->path);\r
1273         }\r
1274 \r
1275         if (!m_bAscending)\r
1276                 result = -result;\r
1277         return result < 0;\r
1278 }\r
1279 \r
1280 BOOL CSVNProgressDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)\r
1281 {\r
1282         if (!GetDlgItem(IDOK)->IsWindowEnabled())\r
1283         {\r
1284                 // only show the wait cursor over the list control\r
1285                 if ((pWnd)&&(pWnd == GetDlgItem(IDC_SVNPROGRESS)))\r
1286                 {\r
1287                         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));\r
1288                         SetCursor(hCur);\r
1289                         return TRUE;\r
1290                 }\r
1291         }\r
1292         HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));\r
1293         SetCursor(hCur);\r
1294         return CResizableStandAloneDialog::OnSetCursor(pWnd, nHitTest, message);\r
1295 }\r
1296 \r
1297 BOOL CSVNProgressDlg::PreTranslateMessage(MSG* pMsg)\r
1298 {\r
1299         if (pMsg->message == WM_KEYDOWN)\r
1300         {\r
1301                 if (pMsg->wParam == VK_ESCAPE)\r
1302                 {\r
1303                         // pressing the ESC key should close the dialog. But since we disabled the escape\r
1304                         // key (so the user doesn't get the idea that he could simply undo an e.g. update)\r
1305                         // this won't work.\r
1306                         // So if the user presses the ESC key, change it to VK_RETURN so the dialog gets\r
1307                         // the impression that the OK button was pressed.\r
1308                         if ((!m_bThreadRunning)&&(!GetDlgItem(IDCANCEL)->IsWindowEnabled())\r
1309                                 &&(GetDlgItem(IDOK)->IsWindowEnabled())&&(GetDlgItem(IDOK)->IsWindowVisible()))\r
1310                         {\r
1311                                 // since we convert ESC to RETURN, make sure the OK button has the focus.\r
1312                                 GetDlgItem(IDOK)->SetFocus();\r
1313                                 pMsg->wParam = VK_RETURN;\r
1314                         }\r
1315                 }\r
1316                 if (pMsg->wParam == 'A')\r
1317                 {\r
1318                         if (GetKeyState(VK_CONTROL)&0x8000)\r
1319                         {\r
1320                                 // Ctrl-A -> select all\r
1321                                 m_ProgList.SetSelectionMark(0);\r
1322                                 for (int i=0; i<m_ProgList.GetItemCount(); ++i)\r
1323                                 {\r
1324                                         m_ProgList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);\r
1325                                 }\r
1326                         }\r
1327                 }\r
1328                 if ((pMsg->wParam == 'C')||(pMsg->wParam == VK_INSERT))\r
1329                 {\r
1330                         int selIndex = m_ProgList.GetSelectionMark();\r
1331                         if (selIndex >= 0)\r
1332                         {\r
1333                                 if (GetKeyState(VK_CONTROL)&0x8000)\r
1334                                 {\r
1335                                         //Ctrl-C -> copy to clipboard\r
1336                                         CString sClipdata;\r
1337                                         POSITION pos = m_ProgList.GetFirstSelectedItemPosition();\r
1338                                         if (pos != NULL)\r
1339                                         {\r
1340                                                 while (pos)\r
1341                                                 {\r
1342                                                         int nItem = m_ProgList.GetNextSelectedItem(pos);\r
1343                                                         CString sAction = m_ProgList.GetItemText(nItem, 0);\r
1344                                                         CString sPath = m_ProgList.GetItemText(nItem, 1);\r
1345                                                         CString sMime = m_ProgList.GetItemText(nItem, 2);\r
1346                                                         CString sLogCopyText;\r
1347                                                         sLogCopyText.Format(_T("%s: %s  %s\r\n"),\r
1348                                                                 (LPCTSTR)sAction, (LPCTSTR)sPath, (LPCTSTR)sMime);\r
1349                                                         sClipdata +=  sLogCopyText;\r
1350                                                 }\r
1351                                                 CStringUtils::WriteAsciiStringToClipboard(sClipdata);\r
1352                                         }\r
1353                                 }\r
1354                         }\r
1355                 } \r
1356         } // if (pMsg->message == WM_KEYDOWN)\r
1357         return __super::PreTranslateMessage(pMsg);\r
1358 }\r
1359 \r
1360 void CSVNProgressDlg::OnContextMenu(CWnd* pWnd, CPoint point)\r
1361 {\r
1362         if (m_options & ProgOptDryRun)\r
1363                 return; // don't do anything in a dry-run.\r
1364 \r
1365         if (pWnd == &m_ProgList)\r
1366         {\r
1367                 int selIndex = m_ProgList.GetSelectionMark();\r
1368                 if ((point.x == -1) && (point.y == -1))\r
1369                 {\r
1370                         // Menu was invoked from the keyboard rather than by right-clicking\r
1371                         CRect rect;\r
1372                         m_ProgList.GetItemRect(selIndex, &rect, LVIR_LABEL);\r
1373                         m_ProgList.ClientToScreen(&rect);\r
1374                         point = rect.CenterPoint();\r
1375                 }\r
1376 \r
1377                 if ((selIndex >= 0)&&(!m_bThreadRunning))\r
1378                 {\r
1379                         // entry is selected, thread has finished with updating so show the popup menu\r
1380                         CIconMenu popup;\r
1381                         if (popup.CreatePopupMenu())\r
1382                         {\r
1383                                 bool bAdded = false;\r
1384                                 NotificationData * data = m_arData[selIndex];\r
1385                                 if ((data)&&(!data->path.IsDirectory()))\r
1386                                 {\r
1387                                         if (data->action == svn_wc_notify_update_update || data->action == svn_wc_notify_resolved)\r
1388                                         {\r
1389                                                 if (m_ProgList.GetSelectedCount() == 1)\r
1390                                                 {\r
1391                                                         popup.AppendMenuIcon(ID_COMPARE, IDS_LOG_POPUP_COMPARE, IDI_DIFF);\r
1392                                                         bAdded = true;\r
1393                                                 }\r
1394                                         }\r
1395                                                 if (data->bConflictedActionItem)\r
1396                                                 {\r
1397                                                         if (m_ProgList.GetSelectedCount() == 1)\r
1398                                                         {\r
1399                                                                 popup.AppendMenuIcon(ID_EDITCONFLICT, IDS_MENUCONFLICT,IDI_CONFLICT);\r
1400                                                                 popup.SetDefaultItem(ID_EDITCONFLICT, FALSE);\r
1401                                                                 popup.AppendMenuIcon(ID_CONFLICTRESOLVE, IDS_SVNPROGRESS_MENUMARKASRESOLVED,IDI_RESOLVE);\r
1402                                                         }\r
1403                                                         popup.AppendMenuIcon(ID_CONFLICTUSETHEIRS, IDS_SVNPROGRESS_MENUUSETHEIRS,IDI_RESOLVE);\r
1404                                                         popup.AppendMenuIcon(ID_CONFLICTUSEMINE, IDS_SVNPROGRESS_MENUUSEMINE,IDI_RESOLVE);\r
1405                                                 }\r
1406                                                 else if ((data->content_state == svn_wc_notify_state_merged)||(SVNProgress_Merge == m_Command)||(data->action == svn_wc_notify_resolved))\r
1407                                                         popup.SetDefaultItem(ID_COMPARE, FALSE);\r
1408                                         \r
1409                                         if (m_ProgList.GetSelectedCount() == 1)\r
1410                                         {\r
1411                                                 if ((data->action == svn_wc_notify_add)||\r
1412                                                         (data->action == svn_wc_notify_update_add)||\r
1413                                                         (data->action == svn_wc_notify_commit_added)||\r
1414                                                         (data->action == svn_wc_notify_commit_modified)||\r
1415                                                         (data->action == svn_wc_notify_restore)||\r
1416                                                         (data->action == svn_wc_notify_revert)||\r
1417                                                         (data->action == svn_wc_notify_resolved)||\r
1418                                                         (data->action == svn_wc_notify_commit_replaced)||\r
1419                                                         (data->action == svn_wc_notify_commit_modified)||\r
1420                                                         (data->action == svn_wc_notify_commit_postfix_txdelta)||\r
1421                                                         (data->action == svn_wc_notify_update_update))\r
1422                                                 {\r
1423                                                         popup.AppendMenuIcon(ID_LOG, IDS_MENULOG,IDI_LOG);\r
1424                                                         if (data->action == svn_wc_notify_update_update)\r
1425                                                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
1426                                                         popup.AppendMenuIcon(ID_OPEN, IDS_LOG_POPUP_OPEN, IDI_OPEN);\r
1427                                                         popup.AppendMenuIcon(ID_OPENWITH, IDS_LOG_POPUP_OPENWITH, IDI_OPEN);\r
1428                                                         bAdded = true;\r
1429                                                 }\r
1430                                         }\r
1431                                 } // if ((data)&&(!data->path.IsDirectory()))\r
1432                                 if (m_ProgList.GetSelectedCount() == 1)\r
1433                                 {\r
1434                                         if (data)\r
1435                                         {\r
1436                                                 CString sPath = GetPathFromColumnText(data->sPathColumnText);\r
1437                                                 if ((!sPath.IsEmpty())&&(!SVN::PathIsURL(CTSVNPath(sPath))))\r
1438                                                 {\r
1439                                                         CTSVNPath path = CTSVNPath(sPath);\r
1440                                                         if (path.GetDirectory().Exists())\r
1441                                                         {\r
1442                                                                 popup.AppendMenuIcon(ID_EXPLORE, IDS_SVNPROGRESS_MENUOPENPARENT, IDI_EXPLORER);\r
1443                                                                 bAdded = true;\r
1444                                                         }\r
1445                                                 }\r
1446                                         }\r
1447                                 }\r
1448                                 if (m_ProgList.GetSelectedCount() > 0)\r
1449                                 {\r
1450                                         if (bAdded)\r
1451                                                 popup.AppendMenu(MF_SEPARATOR, NULL);\r
1452                                         popup.AppendMenuIcon(ID_COPY, IDS_LOG_POPUP_COPYTOCLIPBOARD,IDI_COPYCLIP);\r
1453                                         bAdded = true;\r
1454                                 }\r
1455                                 if (bAdded)\r
1456                                 {\r
1457                                         int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, point.x, point.y, this, 0);\r
1458                                         DialogEnableWindow(IDOK, FALSE);\r
1459                                         this->SetPromptApp(&theApp);\r
1460                                         theApp.DoWaitCursor(1);\r
1461                                         bool bOpenWith = false;\r
1462                                         switch (cmd)\r
1463                                         {\r
1464                                         case ID_COPY:\r
1465                                                 {\r
1466                                                         CString sLines;\r
1467                                                         POSITION pos = m_ProgList.GetFirstSelectedItemPosition();\r
1468                                                         while (pos)\r
1469                                                         {\r
1470                                                                 int nItem = m_ProgList.GetNextSelectedItem(pos);\r
1471                                                                 NotificationData * data = m_arData[nItem];\r
1472                                                                 if (data)\r
1473                                                                 {\r
1474                                                                         sLines += data->sPathColumnText;\r
1475                                                                         sLines += _T("\r\n");\r
1476                                                                 }\r
1477                                                         }\r
1478                                                         sLines.TrimRight();\r
1479                                                         if (!sLines.IsEmpty())\r
1480                                                         {\r
1481                                                                 CStringUtils::WriteAsciiStringToClipboard(sLines, GetSafeHwnd());\r
1482                                                         }\r
1483                                                 }\r
1484                                                 break;\r
1485                                         case ID_EXPLORE:\r
1486                                                 {\r
1487                                                         CString sPath = GetPathFromColumnText(data->sPathColumnText);\r
1488 \r
1489                                                         CTSVNPath path = CTSVNPath(sPath);\r
1490                                                         ShellExecute(m_hWnd, _T("explore"), path.GetDirectory().GetWinPath(), NULL, path.GetDirectory().GetWinPath(), SW_SHOW);\r
1491                                                 }\r
1492                                                 break;\r
1493                                         case ID_COMPARE:\r
1494                                                 {\r
1495                                                         svn_revnum_t rev = -1;\r
1496                                                         StringRevMap::iterator it = m_UpdateStartRevMap.end();\r
1497                                                         if (data->basepath.IsEmpty())\r
1498                                                                 it = m_UpdateStartRevMap.begin();\r
1499                                                         else\r
1500                                                                 it = m_UpdateStartRevMap.find(data->basepath.GetSVNApiPath(pool));\r
1501                                                         if (it != m_UpdateStartRevMap.end())\r
1502                                                                 rev = it->second;\r
1503                                                         // if the file was merged during update, do a three way diff between OLD, MINE, THEIRS\r
1504                                                         if (data->content_state == svn_wc_notify_state_merged)\r
1505                                                         {\r
1506                                                                 CTSVNPath basefile = CTempFiles::Instance().GetTempFilePath(false, data->path, rev);\r
1507                                                                 CTSVNPath newfile = CTempFiles::Instance().GetTempFilePath(false, data->path, SVNRev::REV_HEAD);\r
1508                                                                 SVN svn;\r
1509                                                                 if (!svn.Cat(data->path, SVNRev(SVNRev::REV_WC), rev, basefile))\r
1510                                                                 {\r
1511                                                                         CMessageBox::Show(m_hWnd, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
1512                                                                         DialogEnableWindow(IDOK, TRUE);\r
1513                                                                         break;\r
1514                                                                 }\r
1515                                                                 // If necessary, convert the line-endings on the file before diffing\r
1516                                                                 if ((DWORD)CRegDWORD(_T("Software\\TortoiseSVN\\ConvertBase"), TRUE))\r
1517                                                                 {\r
1518                                                                         CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(false, data->path, SVNRev::REV_BASE);\r
1519                                                                         if (!svn.Cat(data->path, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE), temporaryFile))\r
1520                                                                         {\r
1521                                                                                 temporaryFile.Reset();\r
1522                                                                                 break;\r
1523                                                                         }\r
1524                                                                         else\r
1525                                                                         {\r
1526                                                                                 newfile = temporaryFile;\r
1527                                                                         }\r
1528                                                                 }\r
1529 \r
1530                                                                 SetFileAttributes(newfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
1531                                                                 SetFileAttributes(basefile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
1532                                                                 CString revname, wcname, basename;\r
1533                                                                 revname.Format(_T("%s Revision %ld"), (LPCTSTR)data->path.GetUIFileOrDirectoryName(), rev);\r
1534                                                                 wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)data->path.GetUIFileOrDirectoryName());\r
1535                                                                 basename.Format(IDS_DIFF_BASENAME, (LPCTSTR)data->path.GetUIFileOrDirectoryName());\r
1536                                                                 CAppUtils::StartExtMerge(basefile, newfile, data->path, data->path, basename, revname, wcname, CString(), true);\r
1537                                                         }\r
1538                                                         else\r
1539                                                         {\r
1540                                                                 CTSVNPath tempfile = CTempFiles::Instance().GetTempFilePath(false, data->path, rev);\r
1541                                                                 SVN svn;\r
1542                                                                 if (!svn.Cat(data->path, SVNRev(SVNRev::REV_WC), rev, tempfile))\r
1543                                                                 {\r
1544                                                                         CMessageBox::Show(m_hWnd, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
1545                                                                         DialogEnableWindow(IDOK, TRUE);\r
1546                                                                         break;\r
1547                                                                 }\r
1548                                                                 else\r
1549                                                                 {\r
1550                                                                         SetFileAttributes(tempfile.GetWinPath(), FILE_ATTRIBUTE_READONLY);\r
1551                                                                         CString revname, wcname;\r
1552                                                                         revname.Format(_T("%s Revision %ld"), (LPCTSTR)data->path.GetUIFileOrDirectoryName(), rev);\r
1553                                                                         wcname.Format(IDS_DIFF_WCNAME, (LPCTSTR)data->path.GetUIFileOrDirectoryName());\r
1554                                                                         CAppUtils::StartExtDiff(\r
1555                                                                                 tempfile, data->path, revname, wcname,\r
1556                                                                                 CAppUtils::DiffFlags().AlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000)));\r
1557                                                                 }\r
1558                                                         }\r
1559                                                 }\r
1560                                                 break;\r
1561                                         case ID_EDITCONFLICT:\r
1562                                                 {\r
1563                                                         CString sPath = GetPathFromColumnText(data->sPathColumnText);\r
1564                                                         SVNDiff::StartConflictEditor(CTSVNPath(sPath));\r
1565                                                 }\r
1566                                                 break;\r
1567                                         case ID_CONFLICTUSETHEIRS:\r
1568                                         case ID_CONFLICTUSEMINE:\r
1569                                         case ID_CONFLICTRESOLVE:\r
1570                                                 {\r
1571                                                         svn_wc_conflict_choice_t result = svn_wc_conflict_choose_merged;\r
1572                                                         switch (cmd)\r
1573                                                         {\r
1574                                                         case ID_CONFLICTUSETHEIRS:\r
1575                                                                 result = svn_wc_conflict_choose_theirs_full;\r
1576                                                                 break;\r
1577                                                         case ID_CONFLICTUSEMINE:\r
1578                                                                 result = svn_wc_conflict_choose_mine_full;\r
1579                                                                 break;\r
1580                                                         case ID_CONFLICTRESOLVE:\r
1581                                                                 result = svn_wc_conflict_choose_merged;\r
1582                                                                 break;\r
1583                                                         }\r
1584                                                         SVN svn;\r
1585                                                         POSITION pos = m_ProgList.GetFirstSelectedItemPosition();\r
1586                                                         CString sResolvedPaths;\r
1587                                                         while (pos)\r
1588                                                         {\r
1589                                                                 int nItem = m_ProgList.GetNextSelectedItem(pos);\r
1590                                                                 NotificationData * data = m_arData[nItem];\r
1591                                                                 if (data)\r
1592                                                                 {\r
1593                                                                         if (data->bConflictedActionItem)\r
1594                                                                         {\r
1595                                                                                 if (!svn.Resolve(data->path, result, FALSE))\r
1596                                                                                 {\r
1597                                                                                         CMessageBox::Show(m_hWnd, svn.GetLastErrorMessage(), _T("TortoiseSVN"), MB_ICONERROR);\r
1598                                                                                         DialogEnableWindow(IDOK, TRUE);\r
1599                                                                                         break;\r
1600                                                                                 }\r
1601                                                                                 else\r
1602                                                                                 {\r
1603                                                                                         data->color = ::GetSysColor(COLOR_WINDOWTEXT);\r
1604                                                                                         data->action = svn_wc_notify_resolved;\r
1605                                                                                         data->sActionColumnText.LoadString(IDS_SVNACTION_RESOLVE);\r
1606                                                                                         data->bConflictedActionItem = false;\r
1607                                                                                         m_nConflicts--;\r
1608 \r
1609                                                                                         if (m_nConflicts==0)\r
1610                                                                                         {\r
1611                                                                                                 // When the last conflict is resolved we remove\r
1612                                                                                                 // the warning which we assume is in the last line.\r
1613                                                                                                 int nIndex = m_ProgList.GetItemCount()-1;\r
1614                                                                                                 VERIFY(m_ProgList.DeleteItem(nIndex));\r
1615 \r
1616                                                                                                 delete m_arData[nIndex];\r
1617                                                                                                 m_arData.pop_back();\r
1618                                                                                         }\r
1619                                                                                         sResolvedPaths += data->path.GetWinPathString() + _T("\n");\r
1620                                                                                 }\r
1621                                                                         }\r
1622                                                                 }\r
1623                                                         }\r
1624                                                         m_ProgList.Invalidate();\r
1625                                                         CString info = BuildInfoString();\r
1626                                                         SetDlgItemText(IDC_INFOTEXT, info);\r
1627 \r
1628                                                         if (!sResolvedPaths.IsEmpty())\r
1629                                                         {\r
1630                                                                 CString msg;\r
1631                                                                 msg.Format(IDS_SVNPROGRESS_RESOLVED, (LPCTSTR)sResolvedPaths);\r
1632                                                                 CMessageBox::Show(m_hWnd, msg, _T("TortoiseSVN"), MB_OK | MB_ICONINFORMATION);\r
1633                                                         }\r
1634                                                 }\r
1635                                                 break;\r
1636                                         case ID_LOG:\r
1637                                                 {\r
1638                                                         CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseSVN\\NumberOfLogs"), 100);\r
1639                                                         int limit = (int)(DWORD)reg;\r
1640                                                         svn_revnum_t rev = m_RevisionEnd;\r
1641                                                         if (!data->basepath.IsEmpty())\r
1642                                                         {\r
1643                                                                 StringRevMap::iterator it = m_FinishedRevMap.find(data->basepath.GetSVNApiPath(pool));\r
1644                                                                 if (it != m_FinishedRevMap.end())\r
1645                                                                         rev = it->second;\r
1646                                                         }\r
1647                                                         CLogDlg dlg;\r
1648                                                         // fetch the log from HEAD, not the revision we updated to:\r
1649                                                         // the path might be inside an external folder which has its own\r
1650                                                         // revisions.\r
1651                                                         CString sPath = GetPathFromColumnText(data->sPathColumnText);\r
1652                                                         dlg.SetParams(CTSVNPath(sPath), SVNRev(), SVNRev::REV_HEAD, 1, limit, TRUE);\r
1653                                                         dlg.DoModal();\r
1654                                                 }\r
1655                                                 break;\r
1656                                         case ID_OPENWITH:\r
1657                                                 bOpenWith = true;\r
1658                                         case ID_OPEN:\r
1659                                                 {\r
1660                                                         int ret = 0;\r
1661                                                         CString sWinPath = GetPathFromColumnText(data->sPathColumnText);\r
1662                                                         if (!bOpenWith)\r
1663                                                                 ret = (int)ShellExecute(this->m_hWnd, NULL, (LPCTSTR)sWinPath, NULL, NULL, SW_SHOWNORMAL);\r
1664                                                         if ((ret <= HINSTANCE_ERROR)||bOpenWith)\r
1665                                                         {\r
1666                                                                 CString cmd = _T("RUNDLL32 Shell32,OpenAs_RunDLL ");\r
1667                                                                 cmd += sWinPath + _T(" ");\r
1668                                                                 CAppUtils::LaunchApplication(cmd, NULL, false);\r
1669                                                         }\r
1670                                                 }\r
1671                                         }\r
1672                                         DialogEnableWindow(IDOK, TRUE);\r
1673                                         theApp.DoWaitCursor(-1);\r
1674                                 } // if (bAdded)\r
1675                         }\r
1676                 }\r
1677         }\r
1678 }\r
1679 \r
1680 void CSVNProgressDlg::OnEnSetfocusInfotext()\r
1681 {\r
1682         CString sTemp;\r
1683         GetDlgItemText(IDC_INFOTEXT, sTemp);\r
1684         if (sTemp.IsEmpty())\r
1685                 GetDlgItem(IDC_INFOTEXT)->HideCaret();\r
1686 }\r
1687 \r
1688 void CSVNProgressDlg::OnLvnBegindragSvnprogress(NMHDR* , LRESULT *pResult)\r
1689 {\r
1690         //LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);\r
1691 \r
1692         int selIndex = m_ProgList.GetSelectionMark();\r
1693         if (selIndex < 0)\r
1694                 return;\r
1695 \r
1696         CDropFiles dropFiles; // class for creating DROPFILES struct\r
1697 \r
1698         int index;\r
1699         POSITION pos = m_ProgList.GetFirstSelectedItemPosition();\r
1700         while ( (index = m_ProgList.GetNextSelectedItem(pos)) >= 0 )\r
1701         {\r
1702                 NotificationData * data = m_arData[index];\r
1703 \r
1704                 if ( data->kind==svn_node_file || data->kind==svn_node_dir )\r
1705                 {\r
1706                         CString sPath = GetPathFromColumnText(data->sPathColumnText);\r
1707 \r
1708                         dropFiles.AddFile( sPath );\r
1709                 }\r
1710         }\r
1711 \r
1712         if ( dropFiles.GetCount()>0 )\r
1713         {\r
1714                 dropFiles.CreateStructure();\r
1715         }\r
1716 \r
1717         *pResult = 0;\r
1718 }\r
1719 \r
1720 void CSVNProgressDlg::OnSize(UINT nType, int cx, int cy)\r
1721 {\r
1722         CResizableStandAloneDialog::OnSize(nType, cx, cy);\r
1723         if ((nType == SIZE_RESTORED)&&(m_bLastVisible))\r
1724         {\r
1725                 int count = m_ProgList.GetItemCount();\r
1726                 if (count > 0)\r
1727                         m_ProgList.EnsureVisible(count-1, false);\r
1728         }\r
1729 }\r
1730 \r
1731 //////////////////////////////////////////////////////////////////////////\r
1732 /// commands\r
1733 //////////////////////////////////////////////////////////////////////////\r
1734 bool CSVNProgressDlg::CmdAdd(CString& sWindowTitle, bool& localoperation)\r
1735 {\r
1736         localoperation = true;\r
1737         sWindowTitle.LoadString(IDS_PROGRS_TITLE_ADD);\r
1738         SetWindowText(sWindowTitle);\r
1739         SetBackgroundImage(IDI_ADD_BKG);\r
1740         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_ADD)));\r
1741         if (!Add(m_targetPathList, &m_ProjectProperties, svn_depth_empty, FALSE, TRUE, TRUE))\r
1742         {\r
1743                 ReportSVNError();\r
1744                 return false;\r
1745         }\r
1746         CShellUpdater::Instance().AddPathsForUpdate(m_targetPathList);\r
1747         return true;\r
1748 }\r
1749 \r
1750 bool CSVNProgressDlg::CmdCheckout(CString& sWindowTitle, bool& /*localoperation*/)\r
1751 {\r
1752         ASSERT(m_targetPathList.GetCount() == 1);\r
1753         sWindowTitle.LoadString(IDS_PROGRS_TITLE_CHECKOUT);\r
1754         SetBackgroundImage(IDI_CHECKOUT_BKG);\r
1755         CTSVNPathList urls;\r
1756         urls.LoadFromAsteriskSeparatedString(m_url.GetSVNPathString());\r
1757         CTSVNPath checkoutdir = m_targetPathList[0];\r
1758         for (int i=0; i<urls.GetCount(); ++i)\r
1759         {\r
1760                 sWindowTitle = urls[i].GetUIFileOrDirectoryName()+_T(" - ")+sWindowTitle;\r
1761                 SetWindowText(sWindowTitle);\r
1762                 checkoutdir = m_targetPathList[0];\r
1763                 if (urls.GetCount() > 1)\r
1764                 {\r
1765                         CString fileordir = urls[i].GetFileOrDirectoryName();\r
1766                         fileordir = CPathUtils::PathUnescape(fileordir);\r
1767                         checkoutdir.AppendPathString(fileordir);\r
1768                 }\r
1769                 CString sCmdInfo;\r
1770                 sCmdInfo.Format(IDS_PROGRS_CMD_CHECKOUT, \r
1771                         (LPCTSTR)urls[i].GetSVNPathString(), (LPCTSTR)m_Revision.ToString(), \r
1772                         (LPCTSTR)SVNStatus::GetDepthString(m_depth), \r
1773                         m_options & ProgOptIgnoreExternals ? (LPCTSTR)sExtExcluded : (LPCTSTR)sExtIncluded);\r
1774                 ReportCmd(sCmdInfo);\r
1775 \r
1776                 if (!Checkout(urls[i], checkoutdir, m_Revision, m_Revision, m_depth, m_options & ProgOptIgnoreExternals))\r
1777                 {\r
1778                         if (m_ProgList.GetItemCount()!=0)\r
1779                         {\r
1780                                 ReportSVNError();\r
1781                                 return false;\r
1782                         }\r
1783                         // if the checkout fails with the peg revision set to the checkout revision,\r
1784                         // try again with HEAD as the peg revision.\r
1785                         else\r
1786                         {\r
1787                                 if (!Checkout(urls[i], checkoutdir, SVNRev::REV_HEAD, m_Revision, m_depth, m_options & ProgOptIgnoreExternals))\r
1788                                 {\r
1789                                         ReportSVNError();\r
1790                                         return false;\r
1791                                 }\r
1792                         }\r
1793                 }\r
1794         }\r
1795         return true;\r
1796 }\r
1797 \r
1798 bool CSVNProgressDlg::CmdCommit(CString& sWindowTitle, bool& /*localoperation*/)\r
1799 {\r
1800         sWindowTitle.LoadString(IDS_PROGRS_TITLE_COMMIT);\r
1801         SetWindowText(sWindowTitle);\r
1802         SetBackgroundImage(IDI_COMMIT_BKG);\r
1803         if (m_targetPathList.GetCount()==0)\r
1804         {\r
1805                 SetWindowText(sWindowTitle);\r
1806 \r
1807                 DialogEnableWindow(IDCANCEL, FALSE);\r
1808                 DialogEnableWindow(IDOK, TRUE);\r
1809 \r
1810                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
1811                 return true;\r
1812         }\r
1813         if (m_targetPathList.GetCount()==1)\r
1814         {\r
1815                 sWindowTitle = m_targetPathList[0].GetUIFileOrDirectoryName()+_T(" - ")+sWindowTitle;\r
1816                 SetWindowText(sWindowTitle);\r
1817         }\r
1818         BOOL isTag = FALSE;\r
1819         BOOL bURLFetched = FALSE;\r
1820         CString url;\r
1821         for (int i=0; i<m_targetPathList.GetCount(); ++i)\r
1822         {\r
1823                 if (bURLFetched == FALSE)\r
1824                 {\r
1825                         url = GetURLFromPath(m_targetPathList[i]);\r
1826                         if (!url.IsEmpty())\r
1827                                 bURLFetched = TRUE;\r
1828                         CString urllower = url;\r
1829                         urllower.MakeLower();\r
1830                         // test if the commit goes to a tag.\r
1831                         // now since Subversion doesn't force users to\r
1832                         // create tags in the recommended /tags/ folder\r
1833                         // only a warning is shown. This won't work if the tags\r
1834                         // are stored in a non-recommended place, but the check\r
1835                         // still helps those who do.\r
1836                         if (urllower.Find(_T("/tags/"))>=0)\r
1837                                 isTag = TRUE;\r
1838                         break;\r
1839                 }\r
1840         }\r
1841         if (isTag)\r
1842         {\r
1843                 if (CMessageBox::Show(m_hWnd, IDS_PROGRS_COMMITT_TRUNK, IDS_APPNAME, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION)==IDNO)\r
1844                         return false;\r
1845         }\r
1846         DWORD exitcode = 0;\r
1847         CString error;\r
1848         if (CHooks::Instance().PreCommit(m_selectedPaths, m_depth, m_sMessage, exitcode, error))\r
1849         {\r
1850                 if (exitcode)\r
1851                 {\r
1852                         CString temp;\r
1853                         temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);\r
1854                         ReportError(temp);\r
1855                         return false;\r
1856                 }\r
1857         }\r
1858 \r
1859         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_COMMIT)));\r
1860         CStringArray changelists;\r
1861     if (!m_changelist.IsEmpty())\r
1862             changelists.Add(m_changelist);\r
1863         bool commitSuccessful = true;\r
1864         if (!Commit(m_targetPathList, m_sMessage, changelists, m_keepchangelist, \r
1865                 m_depth, m_options & ProgOptKeeplocks))\r
1866         {\r
1867                 ReportSVNError();\r
1868                 error = GetLastErrorMessage();\r
1869                 // if a non-recursive commit failed with SVN_ERR_UNSUPPORTED_FEATURE,\r
1870                 // that means a folder deletion couldn't be committed.\r
1871                 if ((m_Revision != 0)&&(Err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))\r
1872                 {\r
1873                         ReportError(CString(MAKEINTRESOURCE(IDS_PROGRS_NONRECURSIVEHINT)));\r
1874                 }\r
1875                 commitSuccessful = false;\r
1876                 return false;\r
1877         }\r
1878         if (!PostCommitErr.IsEmpty())\r
1879         {\r
1880                 ReportWarning(PostCommitErr);\r
1881         }\r
1882         if (commitSuccessful)\r
1883         {\r
1884                 if (m_BugTraqProvider)\r
1885                 {\r
1886                         CComPtr<IBugTraqProvider2> pProvider = NULL;\r
1887                         HRESULT hr = m_BugTraqProvider.QueryInterface(&pProvider);\r
1888                         if (SUCCEEDED(hr))\r
1889                         {\r
1890                                 BSTR commonRoot = SysAllocString(m_targetPathList.GetCommonRoot().GetDirectory().GetWinPath());\r
1891                                 SAFEARRAY *pathList = SafeArrayCreateVector(VT_BSTR, 0, m_targetPathList.GetCount());\r
1892 \r
1893                                 for (LONG index = 0; index < m_targetPathList.GetCount(); ++index)\r
1894                                         SafeArrayPutElement(pathList, &index, m_targetPathList[index].GetSVNPathString().AllocSysString());\r
1895 \r
1896                                 BSTR logMessage = m_sMessage.AllocSysString();\r
1897 \r
1898                                 BSTR temp = NULL;\r
1899                                 if (FAILED(hr = pProvider->OnCommitFinished(GetSafeHwnd(), \r
1900                                         commonRoot,\r
1901                                         pathList,\r
1902                                         logMessage,\r
1903                                         (LONG)m_RevisionEnd,\r
1904                                         &temp)))\r
1905                                 {\r
1906                                         CString sErr = temp;\r
1907                                         if (!sErr.IsEmpty())\r
1908                                                 ReportError(temp);\r
1909                                 }\r
1910 \r
1911                                 SysFreeString(temp);\r
1912                         }\r
1913                 }\r
1914         }\r
1915         if (CHooks::Instance().PostCommit(m_selectedPaths, m_depth, m_RevisionEnd, m_sMessage, exitcode, error))\r
1916         {\r
1917                 if (exitcode)\r
1918                 {\r
1919                         CString temp;\r
1920                         temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);\r
1921                         ReportError(temp);\r
1922                         return false;\r
1923                 }\r
1924         }\r
1925         return true;\r
1926 }\r
1927 \r
1928 bool CSVNProgressDlg::CmdCopy(CString& sWindowTitle, bool& /*localoperation*/)\r
1929 {\r
1930         ASSERT(m_targetPathList.GetCount() == 1);\r
1931         sWindowTitle.LoadString(IDS_PROGRS_TITLE_COPY);\r
1932         SetWindowText(sWindowTitle);\r
1933         SetBackgroundImage(IDI_COPY_BKG);\r
1934 \r
1935         CString sCmdInfo;\r
1936         sCmdInfo.Format(IDS_PROGRS_CMD_COPY, \r
1937                 m_targetPathList[0].IsUrl() ? (LPCTSTR)m_targetPathList[0].GetSVNPathString() : m_targetPathList[0].GetWinPath(),\r
1938                 (LPCTSTR)m_url.GetSVNPathString(), (LPCTSTR)m_Revision.ToString());\r
1939         ReportCmd(sCmdInfo);\r
1940 \r
1941         if (!Copy(m_targetPathList, m_url, m_Revision, m_pegRev, m_sMessage))\r
1942         {\r
1943                 ReportSVNError();\r
1944                 return false;\r
1945         }\r
1946         if (m_options & ProgOptSwitchAfterCopy)\r
1947         {\r
1948                 sCmdInfo.Format(IDS_PROGRS_CMD_SWITCH, \r
1949                         m_targetPathList[0].GetWinPath(),\r
1950                         (LPCTSTR)m_url.GetSVNPathString(), (LPCTSTR)m_Revision.ToString());\r
1951                 ReportCmd(sCmdInfo);\r
1952                 if (!Switch(m_targetPathList[0], m_url, SVNRev::REV_HEAD, SVNRev::REV_HEAD, m_depth, TRUE, m_options & ProgOptIgnoreExternals))\r
1953                 {\r
1954                         if (!Switch(m_targetPathList[0], m_url, SVNRev::REV_HEAD, m_Revision, m_depth, TRUE, m_options & ProgOptIgnoreExternals))\r
1955                         {\r
1956                                 ReportSVNError();\r
1957                                 return false;\r
1958                         }\r
1959                 }\r
1960         }\r
1961         else\r
1962         {\r
1963                 if (SVN::PathIsURL(m_url))\r
1964                 {\r
1965                         CString sMsg(MAKEINTRESOURCE(IDS_PROGRS_COPY_WARNING));\r
1966                         ReportNotification(sMsg);\r
1967                 }\r
1968         }\r
1969         return true;\r
1970 }\r
1971 \r
1972 bool CSVNProgressDlg::CmdExport(CString& sWindowTitle, bool& /*localoperation*/)\r
1973 {\r
1974         ASSERT(m_targetPathList.GetCount() == 1);\r
1975         sWindowTitle.LoadString(IDS_PROGRS_TITLE_EXPORT);\r
1976         sWindowTitle = m_url.GetUIFileOrDirectoryName()+_T(" - ")+sWindowTitle;\r
1977         SetWindowText(sWindowTitle);\r
1978         SetBackgroundImage(IDI_EXPORT_BKG);\r
1979         CString eol;\r
1980         if (m_options & ProgOptEolCRLF)\r
1981                 eol = _T("CRLF");\r
1982         if (m_options & ProgOptEolLF)\r
1983                 eol = _T("LF");\r
1984         if (m_options & ProgOptEolCR)\r
1985                 eol = _T("CR");\r
1986         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_EXPORT)));\r
1987         if (!Export(m_url, m_targetPathList[0], m_Revision, m_Revision, TRUE, m_options & ProgOptIgnoreExternals, m_depth, NULL, FALSE, eol))\r
1988         {\r
1989                 ReportSVNError();\r
1990                 return false;\r
1991         }\r
1992         return true;\r
1993 }\r
1994 \r
1995 bool CSVNProgressDlg::CmdImport(CString& sWindowTitle, bool& /*localoperation*/)\r
1996 {\r
1997         ASSERT(m_targetPathList.GetCount() == 1);\r
1998         sWindowTitle.LoadString(IDS_PROGRS_TITLE_IMPORT);\r
1999         sWindowTitle = m_targetPathList[0].GetUIFileOrDirectoryName()+_T(" - ")+sWindowTitle;\r
2000         SetWindowText(sWindowTitle);\r
2001         SetBackgroundImage(IDI_IMPORT_BKG);\r
2002         CString sCmdInfo;\r
2003         sCmdInfo.Format(IDS_PROGRS_CMD_IMPORT, \r
2004                 m_targetPathList[0].GetWinPath(), (LPCTSTR)m_url.GetSVNPathString(), \r
2005                 m_options & ProgOptIncludeIgnored ? (LPCTSTR)(_T(", ") + sIgnoredIncluded) : _T(""));\r
2006         ReportCmd(sCmdInfo);\r
2007         if (!Import(m_targetPathList[0], m_url, m_sMessage, &m_ProjectProperties, svn_depth_infinity, m_options & ProgOptIncludeIgnored ? true : false, false))\r
2008         {\r
2009                 ReportSVNError();\r
2010                 return false;\r
2011         }\r
2012         return true;\r
2013 }\r
2014 \r
2015 bool CSVNProgressDlg::CmdLock(CString& sWindowTitle, bool& /*localoperation*/)\r
2016 {\r
2017         sWindowTitle.LoadString(IDS_PROGRS_TITLE_LOCK);\r
2018         SetWindowText(sWindowTitle);\r
2019         SetBackgroundImage(IDI_LOCK_BKG);\r
2020         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_LOCK)));\r
2021         if (!Lock(m_targetPathList, m_options & ProgOptLockForce, m_sMessage))\r
2022         {\r
2023                 ReportSVNError();\r
2024                 return false;\r
2025         }\r
2026         CShellUpdater::Instance().AddPathsForUpdate(m_targetPathList);\r
2027         if (m_bLockWarning)\r
2028         {\r
2029                 // the lock failed, because the file was outdated.\r
2030                 // ask the user whether to update the file and try again\r
2031                 if (CMessageBox::Show(m_hWnd, IDS_WARN_LOCKOUTDATED, IDS_APPNAME, MB_ICONQUESTION|MB_YESNO)==IDYES)\r
2032                 {\r
2033                         ReportString(CString(MAKEINTRESOURCE(IDS_SVNPROGRESS_UPDATEANDRETRY)), CString(MAKEINTRESOURCE(IDS_WARN_NOTE)));\r
2034                         if (!Update(m_targetPathList, SVNRev::REV_HEAD, svn_depth_files, false, true))\r
2035                         {\r
2036                                 ReportSVNError();\r
2037                                 return false;\r
2038                         }\r
2039                         if (!Lock(m_targetPathList, m_options & ProgOptLockForce, m_sMessage))\r
2040                         {\r
2041                                 ReportSVNError();\r
2042                                 return false;\r
2043                         }\r
2044                 }\r
2045         }\r
2046         if (m_bLockExists)\r
2047         {\r
2048                 // the locking failed because there already is a lock.\r
2049                 // if the locking-dialog is skipped in the settings, tell the\r
2050                 // user how to steal the lock anyway (i.e., how to get the lock\r
2051                 // dialog back without changing the settings)\r
2052                 if (!DWORD(CRegDWORD(_T("Software\\TortoiseSVN\\ShowLockDlg"), TRUE)))\r
2053                 {\r
2054                         ReportString(CString(MAKEINTRESOURCE(IDS_SVNPROGRESS_LOCKHINT)), CString(MAKEINTRESOURCE(IDS_WARN_NOTE)));\r
2055                 }\r
2056                 return false;\r
2057         }\r
2058         return true;\r
2059 }\r
2060 \r
2061 bool CSVNProgressDlg::CmdMerge(CString& sWindowTitle, bool& /*localoperation*/)\r
2062 {\r
2063         bool bFailed = false;\r
2064         ASSERT(m_targetPathList.GetCount() == 1);\r
2065         sWindowTitle.LoadString(IDS_PROGRS_TITLE_MERGE);\r
2066         SetBackgroundImage(IDI_MERGE_BKG);\r
2067         if (m_options & ProgOptDryRun)\r
2068         {\r
2069                 sWindowTitle += _T(" ") + sDryRun;\r
2070         }\r
2071         if (m_options & ProgOptRecordOnly)\r
2072         {\r
2073                 sWindowTitle += _T(" ") + sRecordOnly;\r
2074         }\r
2075         SetWindowText(sWindowTitle);\r
2076 \r
2077         GetDlgItem(IDC_INFOTEXT)->ShowWindow(SW_HIDE);\r
2078         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_SHOW);\r
2079         CRegDWORD nonint = CRegDWORD(_T("Software\\TortoiseSVN\\MergeNonInteractive"), FALSE);\r
2080         if (DWORD(nonint))\r
2081         {\r
2082                 ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE)->GetSafeHwnd(), BM_SETCHECK, BST_CHECKED, 0);\r
2083                 m_AlwaysConflicted = true;\r
2084         }\r
2085         // we only accept a revision list to merge for peg merges\r
2086         ATLASSERT((m_revisionArray.GetCount()==0) || (m_revisionArray.GetCount() && (m_url.IsEquivalentTo(m_url2))));\r
2087 \r
2088         if (m_url.IsEquivalentTo(m_url2))\r
2089         {\r
2090                 CString sSuggestedMessage;\r
2091                 CString sMergedLogMessage;\r
2092                 CString sSeparator = CRegString(_T("Software\\TortoiseSVN\\MergeLogSeparator"), _T("........"));\r
2093                 CString temp;\r
2094 \r
2095                 // Merging revisions %s of %s to %s into %s, %s%s\r
2096                 CString sCmdInfo;\r
2097                 sCmdInfo.Format(IDS_PROGRS_CMD_MERGEPEG, \r
2098                         (LPCTSTR)m_revisionArray.ToListString(),\r
2099                         (LPCTSTR)m_url.GetSVNPathString(),\r
2100                         m_targetPathList[0].GetWinPath(),\r
2101                         m_options & ProgOptIgnoreAncestry ? (LPCTSTR)sIgnoreAncestry : (LPCTSTR)sRespectAncestry,\r
2102                         m_options & ProgOptDryRun ? ((LPCTSTR)_T(", ") + sDryRun) : _T(""));\r
2103                 ReportCmd(sCmdInfo);\r
2104 \r
2105                 if (!PegMerge(m_url, m_revisionArray, \r
2106                         m_pegRev.IsValid() ? m_pegRev : (m_url.IsUrl() ? SVNRev::REV_HEAD : SVNRev(SVNRev::REV_WC)),\r
2107                         m_targetPathList[0], true, m_depth, m_diffoptions, !!(m_options & ProgOptIgnoreAncestry), !!(m_options & ProgOptDryRun), !!(m_options & ProgOptRecordOnly)))\r
2108                 {\r
2109                         // if the merge fails with the peg revision set,\r
2110                         // try again with HEAD as the peg revision.\r
2111                         if (!PegMerge(m_url, m_revisionArray, SVNRev::REV_HEAD,\r
2112                                 m_targetPathList[0], true, m_depth, m_diffoptions, !!(m_options & ProgOptIgnoreAncestry), !!(m_options & ProgOptDryRun), !!(m_options & ProgOptRecordOnly)))\r
2113                         {\r
2114                                 ReportSVNError();\r
2115                                 bFailed = true;\r
2116                         }\r
2117                 }\r
2118         }\r
2119         else\r
2120         {\r
2121                 CString sCmdInfo;\r
2122                 sCmdInfo.Format(IDS_PROGRS_CMD_MERGEURL, \r
2123                         (LPCTSTR)m_url.GetSVNPathString(), (LPCTSTR)m_Revision.ToString(), \r
2124                         (LPCTSTR)m_url2.GetSVNPathString(), (LPCTSTR)m_RevisionEnd.ToString(),\r
2125                         m_targetPathList[0].GetWinPath(),\r
2126                         m_options & ProgOptIgnoreAncestry ? (LPCTSTR)sIgnoreAncestry : (LPCTSTR)sRespectAncestry,\r
2127                         m_options & ProgOptDryRun ? ((LPCTSTR)_T(", ") + sDryRun) : _T(""));\r
2128                 ReportCmd(sCmdInfo);\r
2129 \r
2130                 if (!Merge(m_url, m_Revision, m_url2, m_RevisionEnd, m_targetPathList[0], \r
2131                         true, m_depth, m_diffoptions, !!(m_options & ProgOptIgnoreAncestry), !!(m_options & ProgOptDryRun), !!(m_options & ProgOptRecordOnly)))\r
2132                 {\r
2133                         ReportSVNError();\r
2134                         bFailed = true;\r
2135                 }\r
2136         }\r
2137         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_HIDE);\r
2138         GetDlgItem(IDC_INFOTEXT)->ShowWindow(SW_SHOW);\r
2139         return !bFailed;\r
2140 }\r
2141 \r
2142 bool CSVNProgressDlg::CmdMergeAll(CString& sWindowTitle, bool& /*localoperation*/)\r
2143 {\r
2144         ASSERT(m_targetPathList.GetCount() == 1);\r
2145         sWindowTitle.LoadString(IDS_PROGRS_TITLE_MERGE);\r
2146         SetBackgroundImage(IDI_MERGE_BKG);\r
2147         SetWindowText(sWindowTitle);\r
2148 \r
2149         ATLASSERT(m_targetPathList.GetCount() == 1);\r
2150 \r
2151         CString sCmdInfo;\r
2152         sCmdInfo.LoadString(IDS_PROGRS_INFOGETTINGINFO);\r
2153         ReportCmd(sCmdInfo);\r
2154         CTSVNPathList suggestedSources;\r
2155         if (!SuggestMergeSources(m_targetPathList[0], m_Revision, suggestedSources))\r
2156         {\r
2157                 ReportSVNError();\r
2158                 return false;\r
2159         }\r
2160 \r
2161         if (suggestedSources.GetCount() == 0)\r
2162         {\r
2163                 CString sErr;\r
2164                 sErr.Format(IDS_PROGRS_MERGEALLNOSOURCES, m_targetPathList[0].GetWinPath());\r
2165                 ReportError(sErr);\r
2166                 return false;\r
2167         }\r
2168         sCmdInfo.Format(IDS_PROGRS_CMD_MERGEALL, \r
2169                 (LPCTSTR)suggestedSources[0].GetSVNPathString(),\r
2170                 m_targetPathList[0].GetWinPath(),\r
2171                 m_options & ProgOptIgnoreAncestry ? (LPCTSTR)sIgnoreAncestry : (LPCTSTR)sRespectAncestry);\r
2172         ReportCmd(sCmdInfo);\r
2173 \r
2174         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_SHOW);\r
2175         CRegDWORD nonint = CRegDWORD(_T("Software\\TortoiseSVN\\MergeNonInteractive"), FALSE);\r
2176         if (DWORD(nonint))\r
2177         {\r
2178                 ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE)->GetSafeHwnd(), BM_SETCHECK, BST_CHECKED, 0);\r
2179                 m_AlwaysConflicted = true;\r
2180         }\r
2181 \r
2182         SVNRevRangeArray revarray;\r
2183         if (!PegMerge(suggestedSources[0], revarray, \r
2184                 SVNRev::REV_HEAD,\r
2185                 m_targetPathList[0], true, m_depth, m_diffoptions, !!(m_options & ProgOptIgnoreAncestry), FALSE))\r
2186         {\r
2187                 GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_HIDE);\r
2188                 ReportSVNError();\r
2189                 return false;\r
2190         }\r
2191 \r
2192         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_HIDE);\r
2193         return true;\r
2194 }\r
2195 \r
2196 bool CSVNProgressDlg::CmdMergeReintegrate(CString& sWindowTitle, bool& /*localoperation*/)\r
2197 {\r
2198         ASSERT(m_targetPathList.GetCount() == 1);\r
2199         sWindowTitle.LoadString(IDS_PROGRS_TITLE_MERGEREINTEGRATE);\r
2200         SetBackgroundImage(IDI_MERGE_BKG);\r
2201         SetWindowText(sWindowTitle);\r
2202 \r
2203         CString sCmdInfo;\r
2204         sCmdInfo.Format(IDS_PROGRS_CMD_MERGEREINTEGRATE, \r
2205                 (LPCTSTR)m_url.GetSVNPathString(),\r
2206                 m_targetPathList[0].GetWinPath());\r
2207         ReportCmd(sCmdInfo);\r
2208 \r
2209         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_SHOW);\r
2210         CRegDWORD nonint = CRegDWORD(_T("Software\\TortoiseSVN\\MergeNonInteractive"), FALSE);\r
2211         if (DWORD(nonint))\r
2212         {\r
2213                 ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE)->GetSafeHwnd(), BM_SETCHECK, BST_CHECKED, 0);\r
2214                 m_AlwaysConflicted = true;\r
2215         }\r
2216 \r
2217         if (!MergeReintegrate(m_url, SVNRev::REV_HEAD, m_targetPathList[0], !!(m_options & ProgOptDryRun), m_diffoptions))\r
2218         {\r
2219                 ReportSVNError();\r
2220                 GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_HIDE);\r
2221                 return false;\r
2222         }\r
2223 \r
2224         GetDlgItem(IDC_NONINTERACTIVE)->ShowWindow(SW_HIDE);\r
2225         return true;\r
2226 }\r
2227 \r
2228 bool CSVNProgressDlg::CmdRename(CString& sWindowTitle, bool& localoperation)\r
2229 {\r
2230         ASSERT(m_targetPathList.GetCount() == 1);\r
2231         if ((!m_targetPathList[0].IsUrl())&&(!m_url.IsUrl()))\r
2232                 localoperation = true;\r
2233         sWindowTitle.LoadString(IDS_PROGRS_TITLE_RENAME);\r
2234         SetWindowText(sWindowTitle);\r
2235         SetBackgroundImage(IDI_RENAME_BKG);\r
2236         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_RENAME)));\r
2237         if (!Move(m_targetPathList, m_url, m_Revision, m_sMessage))\r
2238         {\r
2239                 ReportSVNError();\r
2240                 return false;\r
2241         }\r
2242         return true;\r
2243 }\r
2244 \r
2245 bool CSVNProgressDlg::CmdResolve(CString& sWindowTitle, bool& localoperation)\r
2246 {\r
2247         localoperation = true;\r
2248         ASSERT(m_targetPathList.GetCount() == 1);\r
2249         sWindowTitle.LoadString(IDS_PROGRS_TITLE_RESOLVE);\r
2250         SetWindowText(sWindowTitle);\r
2251         SetBackgroundImage(IDI_RESOLVE_BKG);\r
2252         // check if the file may still have conflict markers in it.\r
2253         BOOL bMarkers = FALSE;\r
2254         if ((m_options & ProgOptSkipConflictCheck) == 0)\r
2255         {\r
2256                 try\r
2257                 {\r
2258                         for (INT_PTR fileindex=0; (fileindex<m_targetPathList.GetCount()) && (bMarkers==FALSE); ++fileindex)\r
2259                         {\r
2260                                 if (!m_targetPathList[fileindex].IsDirectory())\r
2261                                 {\r
2262                                         CStdioFile file(m_targetPathList[fileindex].GetWinPath(), CFile::typeBinary | CFile::modeRead);\r
2263                                         CString strLine = _T("");\r
2264                                         while (file.ReadString(strLine))\r
2265                                         {\r
2266                                                 if (strLine.Find(_T("<<<<<<<"))==0)\r
2267                                                 {\r
2268                                                         bMarkers = TRUE;\r
2269                                                         break;\r
2270                                                 }\r
2271                                         }\r
2272                                         file.Close();\r
2273                                 }\r
2274                         }\r
2275                 } \r
2276                 catch (CFileException* pE)\r
2277                 {\r
2278                         TRACE(_T("CFileException in Resolve!\n"));\r
2279                         TCHAR error[10000] = {0};\r
2280                         pE->GetErrorMessage(error, 10000);\r
2281                         ReportError(error);\r
2282                         pE->Delete();\r
2283                         return false;\r
2284                 }\r
2285         }\r
2286         if (bMarkers)\r
2287         {\r
2288                 if (CMessageBox::Show(m_hWnd, IDS_PROGRS_REVERTMARKERS, IDS_APPNAME, MB_YESNO | MB_ICONQUESTION)==IDYES)\r
2289                 {\r
2290                         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_RESOLVE)));\r
2291                         for (INT_PTR fileindex=0; fileindex<m_targetPathList.GetCount(); ++fileindex)\r
2292                                 Resolve(m_targetPathList[fileindex], svn_wc_conflict_choose_merged, true);\r
2293                 }\r
2294         }\r
2295         else\r
2296         {\r
2297                 ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_RESOLVE)));\r
2298                 for (INT_PTR fileindex=0; fileindex<m_targetPathList.GetCount(); ++fileindex)\r
2299                         Resolve(m_targetPathList[fileindex], svn_wc_conflict_choose_merged, true);\r
2300         }\r
2301         CShellUpdater::Instance().AddPathsForUpdate(m_targetPathList);\r
2302         return true;\r
2303 }\r
2304 \r
2305 bool CSVNProgressDlg::CmdRevert(CString& sWindowTitle, bool& localoperation)\r
2306 {\r
2307         localoperation = true;\r
2308         sWindowTitle.LoadString(IDS_PROGRS_TITLE_REVERT);\r
2309         SetWindowText(sWindowTitle);\r
2310         SetBackgroundImage(IDI_REVERT_BKG);\r
2311 \r
2312         CTSVNPathList delList = m_selectedPaths;\r
2313         if (DWORD(CRegDWORD(_T("Software\\TortoiseSVN\\RevertWithRecycleBin"), TRUE)))\r
2314                 delList.DeleteAllFiles(true);\r
2315 \r
2316         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_REVERT)));\r
2317         if (!Revert(m_targetPathList, CStringArray(), !!(m_options & ProgOptRecursive)))\r
2318         {\r
2319                 ReportSVNError();\r
2320                 return false;\r
2321         }\r
2322         CShellUpdater::Instance().AddPathsForUpdate(m_targetPathList);\r
2323         return true;\r
2324 }\r
2325 \r
2326 bool CSVNProgressDlg::CmdSwitch(CString& sWindowTitle, bool& /*localoperation*/)\r
2327 {\r
2328         ASSERT(m_targetPathList.GetCount() == 1);\r
2329         SVNStatus st;\r
2330         sWindowTitle.LoadString(IDS_PROGRS_TITLE_SWITCH);\r
2331         SetWindowText(sWindowTitle);\r
2332         SetBackgroundImage(IDI_SWITCH_BKG);\r
2333         LONG rev = 0;\r
2334         if (st.GetStatus(m_targetPathList[0]) != (-2))\r
2335         {\r
2336                 if (st.status->entry != NULL)\r
2337                 {\r
2338                         rev = st.status->entry->revision;\r
2339                 }\r
2340         }\r
2341 \r
2342         CString sCmdInfo;\r
2343         sCmdInfo.Format(IDS_PROGRS_CMD_SWITCH, \r
2344                 m_targetPathList[0].GetWinPath(), (LPCTSTR)m_url.GetSVNPathString(),\r
2345                 (LPCTSTR)m_Revision.ToString());\r
2346         ReportCmd(sCmdInfo);\r
2347 \r
2348         bool depthIsSticky = true;\r
2349         if (m_depth == svn_depth_unknown)\r
2350                 depthIsSticky = false;\r
2351         if (!Switch(m_targetPathList[0], m_url, m_Revision, m_Revision, m_depth, depthIsSticky, m_options & ProgOptIgnoreExternals))\r
2352         {\r
2353                 ReportSVNError();\r
2354                 return false;\r
2355         }\r
2356         m_UpdateStartRevMap[m_targetPathList[0].GetSVNApiPath(pool)] = rev;\r
2357         if ((m_RevisionEnd >= 0)&&(rev >= 0)\r
2358                 &&((LONG)m_RevisionEnd > (LONG)rev))\r
2359         {\r
2360                 GetDlgItem(IDC_LOGBUTTON)->ShowWindow(SW_SHOW);\r
2361         }\r
2362         return true;\r
2363 }\r
2364 \r
2365 bool CSVNProgressDlg::CmdUnlock(CString& sWindowTitle, bool& /*localoperation*/)\r
2366 {\r
2367         sWindowTitle.LoadString(IDS_PROGRS_TITLE_UNLOCK);\r
2368         SetWindowText(sWindowTitle);\r
2369         SetBackgroundImage(IDI_UNLOCK_BKG);\r
2370         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_UNLOCK)));\r
2371         if (!Unlock(m_targetPathList, m_options & ProgOptLockForce))\r
2372         {\r
2373                 ReportSVNError();\r
2374                 return false;\r
2375         }\r
2376         CShellUpdater::Instance().AddPathsForUpdate(m_targetPathList);\r
2377         return true;\r
2378 }\r
2379 \r
2380 bool CSVNProgressDlg::CmdUpdate(CString& sWindowTitle, bool& /*localoperation*/)\r
2381 {\r
2382         sWindowTitle.LoadString(IDS_PROGRS_TITLE_UPDATE);\r
2383         SetWindowText(sWindowTitle);\r
2384         SetBackgroundImage(IDI_UPDATE_BKG);\r
2385 \r
2386         int targetcount = m_targetPathList.GetCount();\r
2387         CString sfile;\r
2388         CStringA uuid;\r
2389         StringRevMap uuidmap;\r
2390         SVNRev revstore = m_Revision;\r
2391         int nUUIDs = 0;\r
2392         for(int nItem = 0; nItem < targetcount; nItem++)\r
2393         {\r
2394                 const CTSVNPath& targetPath = m_targetPathList[nItem];\r
2395                 SVNStatus st;\r
2396                 LONG headrev = -1;\r
2397                 m_Revision = revstore;\r
2398                 if (m_Revision.IsHead())\r
2399                 {\r
2400                         if ((targetcount > 1)&&((headrev = st.GetStatus(targetPath, true)) != (-2)))\r
2401                         {\r
2402                                 if (st.status->entry != NULL)\r
2403                                 {\r
2404 \r
2405                                         m_UpdateStartRevMap[targetPath.GetSVNApiPath(pool)] = st.status->entry->cmt_rev;\r
2406                                         if (st.status->entry->uuid)\r
2407                                         {\r
2408                                                 uuid = st.status->entry->uuid;\r
2409                                                 StringRevMap::iterator iter = uuidmap.lower_bound(uuid);\r
2410                                                 if (iter == uuidmap.end() || iter->first != uuid)\r
2411                                                 {\r
2412                                                         uuidmap.insert(iter, std::make_pair(uuid, headrev));\r
2413                                                         nUUIDs++;\r
2414                                                 }\r
2415                                                 else\r
2416                                                         headrev = iter->second;\r
2417                                                 m_Revision = headrev;\r
2418                                         }\r
2419                                         else\r
2420                                                 m_Revision = headrev;\r
2421                                 }\r
2422                         }\r
2423                         else\r
2424                         {\r
2425                                 if ((headrev = st.GetStatus(targetPath, FALSE)) != (-2))\r
2426                                 {\r
2427                                         if (st.status->entry != NULL)\r
2428                                                 m_UpdateStartRevMap[targetPath.GetSVNApiPath(pool)] = st.status->entry->cmt_rev;\r
2429                                 }\r
2430                         }\r
2431                         if (uuidmap.size() > 1)\r
2432                                 m_Revision = SVNRev::REV_HEAD;\r
2433                 } // if (m_Revision.IsHead()) \r
2434         } // for(int nItem = 0; nItem < targetcount; nItem++) \r
2435         sWindowTitle = m_targetPathList.GetCommonRoot().GetWinPathString()+_T(" - ")+sWindowTitle;\r
2436         SetWindowText(sWindowTitle);\r
2437 \r
2438         DWORD exitcode = 0;\r
2439         CString error;\r
2440         if (CHooks::Instance().PreUpdate(m_targetPathList, m_depth, nUUIDs > 1 ? revstore : m_Revision, exitcode, error))\r
2441         {\r
2442                 if (exitcode)\r
2443                 {\r
2444                         CString temp;\r
2445                         temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);\r
2446                         ReportError(temp);\r
2447                         return false;\r
2448                 }\r
2449         }\r
2450         ReportCmd(CString(MAKEINTRESOURCE(IDS_PROGRS_CMD_UPDATE)));\r
2451         if (nUUIDs > 1)\r
2452         {\r
2453                 // the selected items are from different repositories,\r
2454                 // so we have to update them separately\r
2455                 for(int nItem = 0; nItem < targetcount; nItem++)\r
2456                 {\r
2457                         const CTSVNPath& targetPath = m_targetPathList[nItem];\r
2458                         m_basePath = targetPath;\r
2459                         CString sNotify;\r
2460                         sNotify.Format(IDS_PROGRS_UPDATEPATH, m_basePath.GetWinPath());\r
2461                         ReportString(sNotify, CString(MAKEINTRESOURCE(IDS_WARN_NOTE)));\r
2462                         if (!Update(CTSVNPathList(targetPath), revstore, m_depth, TRUE, m_options & ProgOptIgnoreExternals))\r
2463                         {\r
2464                                 ReportSVNError();\r
2465                                 return false;\r
2466                         }\r
2467                 }\r
2468         }\r
2469         else \r
2470         {\r
2471                 // if we have only one target path, but that target path does not exist,\r
2472                 // we have to check whether at least the parent path exists. If not,\r
2473                 // then we have to update all paths in between the first path that exists and the\r
2474                 // parent path of the one we want to update\r
2475                 // This is required so a user can create a sparse checkout without having\r
2476                 // to update all intermediate folders manually\r
2477                 if ((m_targetPathList.GetCount() == 1) && (!m_targetPathList[0].Exists()))\r
2478                 {\r
2479                         CTSVNPath wcPath = m_targetPathList[0].GetContainingDirectory();\r
2480                         CTSVNPath existingParentPath = wcPath.GetContainingDirectory();\r
2481                         while (!existingParentPath.Exists() && (existingParentPath.GetWinPathString().GetLength() > 2))\r
2482                         {\r
2483                                 existingParentPath = existingParentPath.GetContainingDirectory();\r
2484                         }\r
2485                         if (existingParentPath.GetWinPathString().GetLength() && !existingParentPath.IsEquivalentTo(wcPath))\r
2486                         {\r
2487                                 // update all intermediate directories with depth 'empty'\r
2488                                 CTSVNPath intermediatepath = existingParentPath;\r
2489                                 bool bSuccess = true;\r
2490                                 while (bSuccess && intermediatepath.IsAncestorOf(wcPath) && !intermediatepath.IsEquivalentTo(wcPath))\r
2491                                 {\r
2492                                         CString childname = wcPath.GetWinPathString().Mid(intermediatepath.GetWinPathString().GetLength(),\r
2493                                                 wcPath.GetWinPathString().Find('\\', intermediatepath.GetWinPathString().GetLength()+1)-intermediatepath.GetWinPathString().GetLength());\r
2494                                         if (childname.IsEmpty())\r
2495                                                 intermediatepath = wcPath;\r
2496                                         else\r
2497                                                 intermediatepath.AppendPathString(childname);\r
2498                                         bSuccess = !!Update(CTSVNPathList(intermediatepath), m_Revision, svn_depth_empty, false, true);\r
2499                                 }\r
2500 \r
2501                                 if (!bSuccess)\r
2502                                 {\r
2503                                         ReportSVNError();\r
2504                                         return false;\r
2505                                 }\r
2506                         }\r
2507                 }\r
2508                 if (!Update(m_targetPathList, m_Revision, m_depth, TRUE, m_options & ProgOptIgnoreExternals))\r
2509                 {\r
2510                         ReportSVNError();\r
2511                         return false;\r
2512                 }\r
2513         }\r
2514         if (CHooks::Instance().PostUpdate(m_targetPathList, m_depth, m_RevisionEnd, exitcode, error))\r
2515         {\r
2516                 if (exitcode)\r
2517                 {\r
2518                         CString temp;\r
2519                         temp.Format(IDS_ERR_HOOKFAILED, (LPCTSTR)error);\r
2520                         ReportError(temp);\r
2521                         return false;\r
2522                 }\r
2523         }\r
2524 \r
2525         // after an update, show the user the log button, but only if only one single item was updated\r
2526         // (either a file or a directory)\r
2527         if ((m_targetPathList.GetCount() == 1)&&(m_UpdateStartRevMap.size()>0))\r
2528                 GetDlgItem(IDC_LOGBUTTON)->ShowWindow(SW_SHOW);\r
2529 \r
2530         return true;\r
2531 }\r
2532 \r
2533 void CSVNProgressDlg::OnBnClickedNoninteractive()\r
2534 {\r
2535         LRESULT res = ::SendMessage(GetDlgItem(IDC_NONINTERACTIVE)->GetSafeHwnd(), BM_GETCHECK, 0, 0);\r
2536         m_AlwaysConflicted = (res == BST_CHECKED);\r
2537         CRegDWORD nonint = CRegDWORD(_T("Software\\TortoiseSVN\\MergeNonInteractive"), FALSE);\r
2538         nonint = m_AlwaysConflicted;\r
2539 }\r
2540 \r
2541 CString CSVNProgressDlg::GetPathFromColumnText(const CString& sColumnText)\r
2542 {\r
2543         CString sPath = CPathUtils::ParsePathInString(sColumnText);\r
2544         if (sPath.Find(':')<0)\r
2545         {\r
2546                 // the path is not absolute: add the common root of all paths to it\r
2547                 sPath = m_targetPathList.GetCommonRoot().GetDirectory().GetWinPathString() + _T("\\") + CPathUtils::ParsePathInString(sColumnText);\r
2548         }\r
2549         return sPath;\r
2550 }\r