OSDN Git Service

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