OSDN Git Service

Fix 'Explore To' in context menu in Commit Dialog
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / ResolveDlg.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 "ResolveDlg.h"\r
23 \r
24 #define REFRESHTIMER   100\r
25 \r
26 IMPLEMENT_DYNAMIC(CResolveDlg, CResizableStandAloneDialog)\r
27 CResolveDlg::CResolveDlg(CWnd* pParent /*=NULL*/)\r
28         : CResizableStandAloneDialog(CResolveDlg::IDD, pParent)\r
29         , m_bThreadRunning(FALSE)\r
30         , m_bCancelled(false)\r
31 {\r
32 }\r
33 \r
34 CResolveDlg::~CResolveDlg()\r
35 {\r
36 }\r
37 \r
38 void CResolveDlg::DoDataExchange(CDataExchange* pDX)\r
39 {\r
40         CResizableStandAloneDialog::DoDataExchange(pDX);\r
41         DDX_Control(pDX, IDC_RESOLVELIST, m_resolveListCtrl);\r
42         DDX_Control(pDX, IDC_SELECTALL, m_SelectAll);\r
43 }\r
44 \r
45 \r
46 BEGIN_MESSAGE_MAP(CResolveDlg, CResizableStandAloneDialog)\r
47         ON_BN_CLICKED(IDC_SELECTALL, OnBnClickedSelectall)\r
48         ON_BN_CLICKED(IDHELP, OnBnClickedHelp)\r
49         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_NEEDSREFRESH, OnSVNStatusListCtrlNeedsRefresh)\r
50         ON_REGISTERED_MESSAGE(CSVNStatusListCtrl::SVNSLNM_ADDFILE, OnFileDropped)\r
51         ON_WM_TIMER()\r
52 END_MESSAGE_MAP()\r
53 \r
54 BOOL CResolveDlg::OnInitDialog()\r
55 {\r
56         CResizableStandAloneDialog::OnInitDialog();\r
57 \r
58         m_resolveListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLTEXTSTATUS | SVNSLC_COLPROPSTATUS, _T("ResolveDlg"), SVNSLC_POPALL ^ (SVNSLC_POPIGNORE|SVNSLC_POPADD|SVNSLC_POPCOMMIT));\r
59         m_resolveListCtrl.SetConfirmButton((CButton*)GetDlgItem(IDOK));\r
60         m_resolveListCtrl.SetSelectButton(&m_SelectAll);\r
61         m_resolveListCtrl.SetCancelBool(&m_bCancelled);\r
62         m_resolveListCtrl.SetBackgroundImage(IDI_RESOLVE_BKG);\r
63         m_resolveListCtrl.EnableFileDrop();\r
64 \r
65         AdjustControlSize(IDC_SELECTALL);\r
66 \r
67         AddAnchor(IDC_RESOLVELIST, TOP_LEFT, BOTTOM_RIGHT);\r
68         AddAnchor(IDC_SELECTALL, BOTTOM_LEFT);\r
69         AddAnchor(IDOK, BOTTOM_RIGHT);\r
70         AddAnchor(IDCANCEL, BOTTOM_RIGHT);\r
71         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
72         if (hWndExplorer)\r
73                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
74         EnableSaveRestore(_T("ResolveDlg"));\r
75 \r
76         // first start a thread to obtain the file list with the status without\r
77         // blocking the dialog\r
78         if(AfxBeginThread(ResolveThreadEntry, this) == NULL)\r
79         {\r
80                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
81         }\r
82         InterlockedExchange(&m_bThreadRunning, TRUE);\r
83 \r
84         return TRUE;\r
85 }\r
86 \r
87 void CResolveDlg::OnOK()\r
88 {\r
89         if (m_bThreadRunning)\r
90                 return;\r
91 \r
92         //save only the files the user has selected into the path list\r
93         m_resolveListCtrl.WriteCheckedNamesToPathList(m_pathList);\r
94 \r
95         CResizableStandAloneDialog::OnOK();\r
96 }\r
97 \r
98 void CResolveDlg::OnCancel()\r
99 {\r
100         m_bCancelled = true;\r
101         if (m_bThreadRunning)\r
102                 return;\r
103 \r
104         CResizableStandAloneDialog::OnCancel();\r
105 }\r
106 \r
107 void CResolveDlg::OnBnClickedSelectall()\r
108 {\r
109         UINT state = (m_SelectAll.GetState() & 0x0003);\r
110         if (state == BST_INDETERMINATE)\r
111         {\r
112                 // It is not at all useful to manually place the checkbox into the indeterminate state...\r
113                 // We will force this on to the unchecked state\r
114                 state = BST_UNCHECKED;\r
115                 m_SelectAll.SetCheck(state);\r
116         }\r
117         theApp.DoWaitCursor(1);\r
118         m_resolveListCtrl.SelectAll(state == BST_CHECKED);\r
119         theApp.DoWaitCursor(-1);\r
120 }\r
121 \r
122 UINT CResolveDlg::ResolveThreadEntry(LPVOID pVoid)\r
123 {\r
124         return ((CResolveDlg*)pVoid)->ResolveThread();\r
125 }\r
126 UINT CResolveDlg::ResolveThread()\r
127 {\r
128         // get the status of all selected file/folders recursively\r
129         // and show the ones which are in conflict\r
130         DialogEnableWindow(IDOK, false);\r
131 \r
132         m_bCancelled = false;\r
133 \r
134         if (!m_resolveListCtrl.GetStatus(m_pathList))\r
135         {\r
136                 m_resolveListCtrl.SetEmptyString(m_resolveListCtrl.GetLastErrorMessage());\r
137         }\r
138         m_resolveListCtrl.Show(SVNSLC_SHOWCONFLICTED|SVNSLC_SHOWINEXTERNALS, SVNSLC_SHOWCONFLICTED);\r
139 \r
140         InterlockedExchange(&m_bThreadRunning, FALSE);\r
141         return 0;\r
142 }\r
143 \r
144 void CResolveDlg::OnBnClickedHelp()\r
145 {\r
146         OnHelp();\r
147 }\r
148 \r
149 BOOL CResolveDlg::PreTranslateMessage(MSG* pMsg)\r
150 {\r
151         if (pMsg->message == WM_KEYDOWN)\r
152         {\r
153                 switch (pMsg->wParam)\r
154                 {\r
155                 case VK_RETURN:\r
156                         {\r
157                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
158                                 {\r
159                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
160                                         {\r
161                                                 PostMessage(WM_COMMAND, IDOK);\r
162                                         }\r
163                                         return TRUE;\r
164                                 }\r
165                         }\r
166                         break;\r
167                 case VK_F5:\r
168                         {\r
169                                 if (!m_bThreadRunning)\r
170                                 {\r
171                                         if(AfxBeginThread(ResolveThreadEntry, this) == NULL)\r
172                                         {\r
173                                                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
174                                         }\r
175                                         else\r
176                                                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
177                                 }\r
178                         }\r
179                         break;\r
180                 }\r
181         }\r
182 \r
183         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
184 }\r
185 \r
186 LRESULT CResolveDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
187 {\r
188         if(AfxBeginThread(ResolveThreadEntry, this) == NULL)\r
189         {\r
190                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
191         }\r
192         return 0;\r
193 }\r
194 \r
195 LRESULT CResolveDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
196 {\r
197         BringWindowToTop();\r
198         SetForegroundWindow();\r
199         SetActiveWindow();\r
200         // if multiple files/folders are dropped\r
201         // this handler is called for every single item\r
202         // separately.\r
203         // To avoid creating multiple refresh threads and\r
204         // causing crashes, we only add the items to the\r
205         // list control and start a timer.\r
206         // When the timer expires, we start the refresh thread,\r
207         // but only if it isn't already running - otherwise we\r
208         // restart the timer.\r
209         CTSVNPath path;\r
210         path.SetFromWin((LPCTSTR)lParam);\r
211 \r
212         if (!m_resolveListCtrl.HasPath(path))\r
213         {\r
214                 if (m_pathList.AreAllPathsFiles())\r
215                 {\r
216                         m_pathList.AddPath(path);\r
217                         m_pathList.RemoveDuplicates();\r
218                 }\r
219                 else\r
220                 {\r
221                         // if the path list contains folders, we have to check whether\r
222                         // our just (maybe) added path is a child of one of those. If it is\r
223                         // a child of a folder already in the list, we must not add it. Otherwise\r
224                         // that path could show up twice in the list.\r
225                         bool bHasParentInList = false;\r
226                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
227                         {\r
228                                 if (m_pathList[i].IsAncestorOf(path))\r
229                                 {\r
230                                         bHasParentInList = true;\r
231                                         break;\r
232                                 }\r
233                         }\r
234                         if (!bHasParentInList)\r
235                         {\r
236                                 m_pathList.AddPath(path);\r
237                                 m_pathList.RemoveDuplicates();\r
238                         }\r
239                 }\r
240         }\r
241 \r
242         // Always start the timer, since the status of an existing item might have changed\r
243         SetTimer(REFRESHTIMER, 200, NULL);\r
244         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
245         return 0;\r
246 }\r
247 \r
248 void CResolveDlg::OnTimer(UINT_PTR nIDEvent)\r
249 {\r
250         switch (nIDEvent)\r
251         {\r
252         case REFRESHTIMER:\r
253                 if (m_bThreadRunning)\r
254                 {\r
255                         SetTimer(REFRESHTIMER, 200, NULL);\r
256                         ATLTRACE("Wait some more before refreshing\n");\r
257                 }\r
258                 else\r
259                 {\r
260                         KillTimer(REFRESHTIMER);\r
261                         ATLTRACE("Refreshing after items dropped\n");\r
262                         OnSVNStatusListCtrlNeedsRefresh(0, 0);\r
263                 }\r
264                 break;\r
265         }\r
266         __super::OnTimer(nIDEvent);\r
267 }\r