OSDN Git Service

Share resource file between TortoiseGitBlame and TortoiseProc
[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         if (!m_addListCtrl.GetStatus(m_pathList))\r
142         {\r
143                 m_addListCtrl.SetEmptyString(m_addListCtrl.GetLastErrorMessage());\r
144         }\r
145         m_addListCtrl.Show(SVNSLC_SHOWUNVERSIONED | SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWREMOVEDANDPRESENT, \r
146                                                 SVNSLC_SHOWUNVERSIONED | SVNSLC_SHOWDIRECTFILES | SVNSLC_SHOWREMOVEDANDPRESENT);\r
147 \r
148         InterlockedExchange(&m_bThreadRunning, FALSE);\r
149         return 0;\r
150 }\r
151 \r
152 void CAddDlg::OnBnClickedHelp()\r
153 {\r
154         OnHelp();\r
155 }\r
156 \r
157 BOOL CAddDlg::PreTranslateMessage(MSG* pMsg)\r
158 {\r
159         if (pMsg->message == WM_KEYDOWN)\r
160         {\r
161                 switch (pMsg->wParam)\r
162                 {\r
163                 case VK_RETURN:\r
164                         {\r
165                                 if (GetAsyncKeyState(VK_CONTROL)&0x8000)\r
166                                 {\r
167                                         if ( GetDlgItem(IDOK)->IsWindowEnabled() )\r
168                                         {\r
169                                                 PostMessage(WM_COMMAND, IDOK);\r
170                                         }\r
171                                         return TRUE;\r
172                                 }\r
173                         }\r
174                         break;\r
175                 case VK_F5:\r
176                         {\r
177                                 if (!m_bThreadRunning)\r
178                                 {\r
179                                         if(AfxBeginThread(AddThreadEntry, this) == NULL)\r
180                                         {\r
181                                                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
182                                         }\r
183                                         else\r
184                                                 InterlockedExchange(&m_bThreadRunning, TRUE);\r
185                                 }\r
186                         }\r
187                         break;\r
188                 }\r
189         }\r
190 \r
191         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
192 }\r
193 \r
194 LRESULT CAddDlg::OnSVNStatusListCtrlNeedsRefresh(WPARAM, LPARAM)\r
195 {\r
196         if(AfxBeginThread(AddThreadEntry, this) == NULL)\r
197         {\r
198                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
199         }\r
200         return 0;\r
201 }\r
202 \r
203 LRESULT CAddDlg::OnFileDropped(WPARAM, LPARAM lParam)\r
204 {\r
205         BringWindowToTop();\r
206         SetForegroundWindow();\r
207         SetActiveWindow();\r
208         // if multiple files/folders are dropped\r
209         // this handler is called for every single item\r
210         // separately.\r
211         // To avoid creating multiple refresh threads and\r
212         // causing crashes, we only add the items to the\r
213         // list control and start a timer.\r
214         // When the timer expires, we start the refresh thread,\r
215         // but only if it isn't already running - otherwise we\r
216         // restart the timer.\r
217         CTGitPath path;\r
218         path.SetFromWin((LPCTSTR)lParam);\r
219 \r
220         if (!m_addListCtrl.HasPath(path))\r
221         {\r
222                 if (m_pathList.AreAllPathsFiles())\r
223                 {\r
224                         m_pathList.AddPath(path);\r
225                         m_pathList.RemoveDuplicates();\r
226                 }\r
227                 else\r
228                 {\r
229                         // if the path list contains folders, we have to check whether\r
230                         // our just (maybe) added path is a child of one of those. If it is\r
231                         // a child of a folder already in the list, we must not add it. Otherwise\r
232                         // that path could show up twice in the list.\r
233                         bool bHasParentInList = false;\r
234                         for (int i=0; i<m_pathList.GetCount(); ++i)\r
235                         {\r
236                                 if (m_pathList[i].IsAncestorOf(path))\r
237                                 {\r
238                                         bHasParentInList = true;\r
239                                         break;\r
240                                 }\r
241                         }\r
242                         if (!bHasParentInList)\r
243                         {\r
244                                 m_pathList.AddPath(path);\r
245                                 m_pathList.RemoveDuplicates();\r
246                         }\r
247                 }\r
248         }\r
249 \r
250         // Always start the timer, since the status of an existing item might have changed\r
251         SetTimer(REFRESHTIMER, 200, NULL);\r
252         ATLTRACE(_T("Item %s dropped, timer started\n"), path.GetWinPath());\r
253         return 0;\r
254 }\r
255 \r
256 void CAddDlg::OnTimer(UINT_PTR nIDEvent)\r
257 {\r
258         switch (nIDEvent)\r
259         {\r
260         case REFRESHTIMER:\r
261                 if (m_bThreadRunning)\r
262                 {\r
263                         SetTimer(REFRESHTIMER, 200, NULL);\r
264                         ATLTRACE("Wait some more before refreshing\n");\r
265                 }\r
266                 else\r
267                 {\r
268                         KillTimer(REFRESHTIMER);\r
269                         ATLTRACE("Refreshing after items dropped\n");\r
270                         OnSVNStatusListCtrlNeedsRefresh(0, 0);\r
271                 }\r
272                 break;\r
273         }\r
274         __super::OnTimer(nIDEvent);\r
275 }\r