OSDN Git Service

Enable Abort Button at git progress dialog by terminate process.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / RebaseDlg.cpp
1 // RebaseDlg.cpp : implementation file\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "TortoiseProc.h"\r
6 #include "RebaseDlg.h"\r
7 #include "AppUtils.h"\r
8 #include "MessageBox.h"\r
9 #include "UnicodeUtils.h"\r
10 #include "BrowseRefsDlg.h"\r
11 #include "ProgressDlg.h"\r
12 // CRebaseDlg dialog\r
13 \r
14 IMPLEMENT_DYNAMIC(CRebaseDlg, CResizableStandAloneDialog)\r
15 \r
16 CRebaseDlg::CRebaseDlg(CWnd* pParent /*=NULL*/)\r
17         : CResizableStandAloneDialog(CRebaseDlg::IDD, pParent)\r
18     , m_bPickAll(FALSE)\r
19     , m_bSquashAll(FALSE)\r
20     , m_bEditAll(FALSE)\r
21 {\r
22         m_RebaseStage=CHOOSE_BRANCH;\r
23         m_CurrentRebaseIndex=-1;\r
24         m_bThreadRunning =FALSE;\r
25         this->m_IsCherryPick = FALSE;\r
26         m_bForce=FALSE;\r
27         m_IsFastForward=FALSE;\r
28 }\r
29 \r
30 CRebaseDlg::~CRebaseDlg()\r
31 {\r
32 }\r
33 \r
34 void CRebaseDlg::DoDataExchange(CDataExchange* pDX)\r
35 {\r
36     CDialog::DoDataExchange(pDX);\r
37     DDX_Control(pDX, IDC_REBASE_PROGRESS, m_ProgressBar);\r
38     DDX_Control(pDX, IDC_STATUS_STATIC, m_CtrlStatusText);\r
39     DDX_Check(pDX, IDC_PICK_ALL, m_bPickAll);\r
40     DDX_Check(pDX, IDC_SQUASH_ALL, m_bSquashAll);\r
41     DDX_Check(pDX, IDC_EDIT_ALL, m_bEditAll);\r
42         DDX_Control(pDX, IDC_REBASE_SPLIT, m_wndSplitter);\r
43         DDX_Control(pDX,IDC_COMMIT_LIST,m_CommitList);\r
44         DDX_Control(pDX,IDC_REBASE_COMBOXEX_BRANCH, this->m_BranchCtrl);\r
45         DDX_Control(pDX,IDC_REBASE_COMBOXEX_UPSTREAM,   this->m_UpstreamCtrl);\r
46         DDX_Check(pDX, IDC_REBASE_CHECK_FORCE,m_bForce);\r
47 \r
48 }\r
49 \r
50 \r
51 BEGIN_MESSAGE_MAP(CRebaseDlg, CResizableStandAloneDialog)\r
52     ON_BN_CLICKED(IDC_PICK_ALL, &CRebaseDlg::OnBnClickedPickAll)\r
53     ON_BN_CLICKED(IDC_SQUASH_ALL, &CRebaseDlg::OnBnClickedSquashAll)\r
54     ON_BN_CLICKED(IDC_EDIT_ALL, &CRebaseDlg::OnBnClickedEditAll)\r
55     ON_BN_CLICKED(IDC_REBASE_SPLIT, &CRebaseDlg::OnBnClickedRebaseSplit)\r
56         ON_BN_CLICKED(IDC_REBASE_CONTINUE,OnBnClickedContinue)\r
57         ON_BN_CLICKED(IDC_REBASE_ABORT,  OnBnClickedAbort)\r
58         ON_WM_SIZE()\r
59         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH,   &CRebaseDlg::OnCbnSelchangeBranch)\r
60         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM, &CRebaseDlg::OnCbnSelchangeUpstream)\r
61         ON_MESSAGE(MSG_REBASE_UPDATE_UI, OnRebaseUpdateUI)\r
62         ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CRebaseDlg::OnBnClickedButtonBrowse)\r
63         ON_BN_CLICKED(IDC_REBASE_CHECK_FORCE, &CRebaseDlg::OnBnClickedRebaseCheckForce)\r
64         ON_STN_CLICKED(IDC_STATUS_STATIC, &CRebaseDlg::OnStnClickedStatusStatic)\r
65         ON_BN_CLICKED(IDC_REBASE_POST_BUTTON, &CRebaseDlg::OnBnClickedRebasePostButton)\r
66 END_MESSAGE_MAP()\r
67 \r
68 void CRebaseDlg::AddRebaseAnchor()\r
69 {\r
70         AddAnchor(IDC_REBASE_TAB,TOP_LEFT,BOTTOM_RIGHT);\r
71         AddAnchor(IDC_COMMIT_LIST,TOP_LEFT, TOP_RIGHT);\r
72         AddAnchor(IDC_REBASE_SPLIT,TOP_LEFT, TOP_RIGHT);\r
73         AddAnchor(IDC_STATUS_STATIC, BOTTOM_LEFT,BOTTOM_RIGHT);\r
74         AddAnchor(IDC_REBASE_CONTINUE,BOTTOM_RIGHT);\r
75         AddAnchor(IDC_REBASE_ABORT, BOTTOM_RIGHT);\r
76         AddAnchor(IDC_REBASE_PROGRESS,BOTTOM_LEFT, BOTTOM_RIGHT);\r
77         AddAnchor(IDC_PICK_ALL,TOP_LEFT);\r
78         AddAnchor(IDC_SQUASH_ALL,TOP_LEFT);\r
79         AddAnchor(IDC_EDIT_ALL,TOP_LEFT);       \r
80         AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM,TOP_LEFT);\r
81         AddAnchor(IDC_REBASE_COMBOXEX_BRANCH,TOP_LEFT);\r
82         AddAnchor(IDC_REBASE_STATIC_UPSTREAM,TOP_LEFT);\r
83         AddAnchor(IDC_REBASE_STATIC_BRANCH,TOP_LEFT);\r
84         AddAnchor(IDHELP, BOTTOM_RIGHT);\r
85         AddAnchor(IDC_REBASE_CHECK_FORCE,TOP_RIGHT);\r
86         AddAnchor(IDC_REBASE_POST_BUTTON,BOTTOM_LEFT);\r
87         \r
88         this->AddOthersToAnchor();\r
89 }\r
90 \r
91 BOOL CRebaseDlg::OnInitDialog()\r
92 {\r
93         CResizableStandAloneDialog::OnInitDialog();\r
94 \r
95         CRect rectDummy;\r
96         //IDC_REBASE_DUMY_TAB\r
97         \r
98         GetClientRect(m_DlgOrigRect);\r
99         m_CommitList.GetClientRect(m_CommitListOrigRect);\r
100 \r
101         CWnd *pwnd=this->GetDlgItem(IDC_REBASE_DUMY_TAB);\r
102         pwnd->GetWindowRect(&rectDummy);\r
103         this->ScreenToClient(rectDummy);\r
104 \r
105         if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_REBASE_TAB))\r
106         {\r
107                 TRACE0("Failed to create output tab window\n");\r
108                 return FALSE;      // fail to create\r
109         }\r
110         m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);\r
111         // Create output panes:\r
112         //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
113         DWORD dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;\r
114 \r
115         if (! this->m_FileListCtrl.Create(dwStyle,rectDummy,&this->m_ctrlTabCtrl,0) )\r
116         {\r
117                 TRACE0("Failed to create output windows\n");\r
118                 return FALSE;      // fail to create\r
119         }\r
120 \r
121         if( ! this->m_LogMessageCtrl.Create(_T("Scintilla"),_T("source"),0,rectDummy,&m_ctrlTabCtrl,0,0) )\r
122         {\r
123                 TRACE0("Failed to create log message control");\r
124                 return FALSE;\r
125         }\r
126         m_LogMessageCtrl.Init(0);\r
127 \r
128         dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
129 \r
130         if (!m_wndOutputRebase.Create(_T("Scintilla"),_T("source"),0,rectDummy, &m_ctrlTabCtrl, 0,0) )\r
131         {\r
132                 TRACE0("Failed to create output windows\n");\r
133                 return -1;      // fail to create\r
134         }\r
135         m_wndOutputRebase.Init(0);\r
136         m_wndOutputRebase.Call(SCI_SETREADONLY, TRUE);\r
137         \r
138         m_tooltips.Create(this);\r
139         \r
140         m_tooltips.AddTool(IDC_REBASE_CHECK_FORCE,IDS_REBASE_FORCE_TT);\r
141         m_tooltips.AddTool(IDC_REBASE_ABORT,IDS_REBASE_ABORT_TT);\r
142         \r
143 \r
144 \r
145         m_FileListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLSTATUS |SVNSLC_COLADD|SVNSLC_COLDEL , _T("RebaseDlg"),(SVNSLC_POPALL ^ SVNSLC_POPCOMMIT),false);\r
146 \r
147         m_ctrlTabCtrl.AddTab(&m_FileListCtrl,_T("Conflict File"));\r
148         m_ctrlTabCtrl.AddTab(&m_LogMessageCtrl,_T("Commit Message"),1);\r
149         m_ctrlTabCtrl.AddTab(&m_wndOutputRebase,_T("Log"),2);\r
150         AddRebaseAnchor();\r
151 \r
152 \r
153         EnableSaveRestore(_T("RebaseDlg"));\r
154 \r
155         DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
156         RECT rcDlg, rcLogMsg, rcFileList;\r
157         GetClientRect(&rcDlg);\r
158         m_CommitList.GetWindowRect(&rcLogMsg);\r
159         ScreenToClient(&rcLogMsg);\r
160         this->m_ctrlTabCtrl.GetWindowRect(&rcFileList);\r
161         ScreenToClient(&rcFileList);\r
162         if (yPos)\r
163         {\r
164                 RECT rectSplitter;\r
165                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
166                 ScreenToClient(&rectSplitter);\r
167                 int delta = yPos - rectSplitter.top;\r
168                 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))\r
169                 {\r
170                         m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);\r
171                         DoSize(delta);\r
172                 }\r
173         }\r
174 \r
175         if( this->m_RebaseStage == CHOOSE_BRANCH)\r
176         {\r
177                 this->LoadBranchInfo();\r
178 \r
179         }else\r
180         {\r
181                 this->m_BranchCtrl.EnableWindow(FALSE);\r
182                 this->m_UpstreamCtrl.EnableWindow(FALSE);\r
183         }\r
184 \r
185         m_CommitList.m_IsIDReplaceAction = TRUE;\r
186 //      m_CommitList.m_IsOldFirst = TRUE;\r
187         m_CommitList.m_IsRebaseReplaceGraph = TRUE;\r
188 \r
189         m_CommitList.InsertGitColumn();\r
190 \r
191         this->SetControlEnable();\r
192 \r
193         if(!this->m_PreCmd.IsEmpty())\r
194         {\r
195                 CProgressDlg progress;\r
196                 progress.m_GitCmd=m_PreCmd;\r
197                 progress.m_bAutoCloseOnSuccess=true;\r
198                 progress.DoModal();\r
199         }\r
200 \r
201         if(m_IsCherryPick)\r
202         {\r
203                 this->m_BranchCtrl.SetCurSel(-1);\r
204                 this->m_BranchCtrl.EnableWindow(FALSE);\r
205                 this->m_UpstreamCtrl.EnableWindow(FALSE);\r
206                 this->SetWindowText(_T("Cherry Pick"));\r
207                 this->m_CommitList.StartFilter();\r
208 \r
209         }else\r
210         {\r
211                 SetContinueButtonText();\r
212                 m_CommitList.DeleteAllItems();\r
213                 FetchLogList();\r
214         }\r
215 \r
216         m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK)|\r
217                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV)|\r
218                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_RESET)|\r
219                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTREV)|\r
220                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION)|\r
221                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV)|\r
222                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT));\r
223 \r
224         if(m_CommitList.m_IsOldFirst)\r
225                 this->m_CurrentRebaseIndex = -1;\r
226         else\r
227                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
228 \r
229 \r
230         return TRUE;\r
231 }\r
232 // CRebaseDlg message handlers\r
233 \r
234 void CRebaseDlg::OnBnClickedPickAll()\r
235 {\r
236     // TODO: Add your control notification handler code here\r
237         this->UpdateData();\r
238         if(this->m_bPickAll)\r
239                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK);\r
240 \r
241         this->m_bEditAll=FALSE;\r
242         this->m_bSquashAll=FALSE;\r
243         this->UpdateData(FALSE);\r
244         \r
245 }\r
246 \r
247 void CRebaseDlg::OnBnClickedSquashAll()\r
248 {\r
249     // TODO: Add your control notification handler code here\r
250         this->UpdateData();\r
251         if(this->m_bSquashAll)\r
252                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);\r
253 \r
254         this->m_bEditAll=FALSE;\r
255         this->m_bPickAll=FALSE;\r
256         this->UpdateData(FALSE);\r
257 \r
258 }\r
259 \r
260 void CRebaseDlg::OnBnClickedEditAll()\r
261 {\r
262     // TODO: Add your control notification handler code here\r
263         this->UpdateData();\r
264         if( this->m_bEditAll )\r
265                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT);\r
266 \r
267         this->m_bPickAll=FALSE;\r
268         this->m_bSquashAll=FALSE;\r
269         this->UpdateData(FALSE);\r
270 \r
271 }\r
272 \r
273 void CRebaseDlg::SetAllRebaseAction(int action)\r
274 {\r
275         for(int i=0;i<this->m_CommitList.m_logEntries.size();i++)\r
276         {\r
277                 m_CommitList.m_logEntries[i].m_Action=action;\r
278         }\r
279         m_CommitList.Invalidate();\r
280 }\r
281 \r
282 void CRebaseDlg::OnBnClickedRebaseSplit()\r
283 {\r
284         this->UpdateData();\r
285     // TODO: Add your control notification handler code here\r
286 }\r
287 \r
288 LRESULT CRebaseDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)\r
289 {\r
290         switch (message) {\r
291         case WM_NOTIFY:\r
292                 if (wParam == IDC_REBASE_SPLIT)\r
293                 { \r
294                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
295                         DoSize(pHdr->delta);\r
296                 }\r
297                 break;\r
298         }\r
299 \r
300         return __super::DefWindowProc(message, wParam, lParam);\r
301 }\r
302 \r
303 void CRebaseDlg::DoSize(int delta)\r
304 {\r
305         \r
306         this->RemoveAllAnchors();\r
307 \r
308         CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST), delta, CW_TOPALIGN);\r
309         //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);\r
310         CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB), -delta, CW_BOTTOMALIGN);\r
311         //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);\r
312         CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL),0,delta);\r
313         CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL),0,delta);\r
314         CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL),0,delta);\r
315         CSplitterControl::ChangePos(GetDlgItem(IDC_REBASE_CHECK_FORCE),0,delta);\r
316         \r
317         this->AddRebaseAnchor();\r
318         // adjust the minimum size of the dialog to prevent the resizing from\r
319         // moving the list control too far down.\r
320         CRect rcLogMsg;\r
321         m_CommitList.GetClientRect(rcLogMsg);\r
322         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));\r
323 \r
324         SetSplitterRange();\r
325 //      m_CommitList.Invalidate();\r
326 \r
327 //      GetDlgItem(IDC_LOGMESSAGE)->Invalidate();\r
328 \r
329         this->m_ctrlTabCtrl.Invalidate();\r
330         this->m_CommitList.Invalidate();\r
331         this->m_FileListCtrl.Invalidate();\r
332         this->m_LogMessageCtrl.Invalidate();\r
333 \r
334 }\r
335 \r
336 void CRebaseDlg::SetSplitterRange()\r
337 {\r
338         if ((m_CommitList)&&(m_ctrlTabCtrl))\r
339         {\r
340                 CRect rcTop;\r
341                 m_CommitList.GetWindowRect(rcTop);\r
342                 ScreenToClient(rcTop);\r
343                 CRect rcMiddle;\r
344                 m_ctrlTabCtrl.GetWindowRect(rcMiddle);\r
345                 ScreenToClient(rcMiddle);\r
346                 if (rcMiddle.Height() && rcMiddle.Width())\r
347                         m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);\r
348         }\r
349 }\r
350 \r
351 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)\r
352 {\r
353          // first, let the resizing take place\r
354     __super::OnSize(nType, cx, cy);\r
355 \r
356     //set range\r
357     SetSplitterRange();\r
358 }\r
359 \r
360 void CRebaseDlg::SaveSplitterPos()\r
361 {\r
362         if (!IsIconic())\r
363         {\r
364                 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
365                 RECT rectSplitter;\r
366                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
367                 ScreenToClient(&rectSplitter);\r
368                 regPos = rectSplitter.top;\r
369         }\r
370 }\r
371 \r
372 void CRebaseDlg::LoadBranchInfo()\r
373 {\r
374         m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
375         m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
376 \r
377         STRING_VECTOR list;\r
378         list.clear();\r
379         int current;\r
380         g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);\r
381         m_BranchCtrl.AddString(list);\r
382         m_UpstreamCtrl.AddString(list);\r
383 \r
384         m_BranchCtrl.SetCurSel(current);\r
385 \r
386         AddBranchToolTips(&m_BranchCtrl);\r
387         AddBranchToolTips(&m_UpstreamCtrl);\r
388 \r
389         if(!m_Upstream.IsEmpty())\r
390         {\r
391                 m_UpstreamCtrl.AddString(m_Upstream);\r
392                 m_UpstreamCtrl.SetCurSel(m_UpstreamCtrl.GetCount()-1);\r
393         }\r
394         else\r
395         {\r
396                 //Select pull-remote from current branch\r
397                 CString currentBranch = g_Git.GetSymbolicRef();\r
398                 CString configName;\r
399                 configName.Format(L"branch.%s.remote", currentBranch);\r
400                 CString pullRemote = g_Git.GetConfigValue(configName);\r
401 \r
402                 //Select pull-branch from current branch\r
403                 configName.Format(L"branch.%s.merge", currentBranch);\r
404                 CString pullBranch = CGit::StripRefName(g_Git.GetConfigValue(configName));\r
405 \r
406                 CString defaultUpstream;\r
407                 defaultUpstream.Format(L"remotes/%s/%s", pullRemote, pullBranch);\r
408                 int found = m_UpstreamCtrl.FindStringExact(0, defaultUpstream);\r
409                 if(found >= 0)\r
410                         m_UpstreamCtrl.SetCurSel(found);\r
411         }\r
412 }\r
413 \r
414 void CRebaseDlg::OnCbnSelchangeBranch()\r
415 {\r
416         FetchLogList();\r
417 }\r
418 \r
419 void CRebaseDlg::OnCbnSelchangeUpstream()\r
420 {\r
421         FetchLogList();\r
422 }\r
423 \r
424 void CRebaseDlg::FetchLogList()\r
425 {\r
426         CString base,hash;\r
427         CString cmd;\r
428         m_IsFastForward=FALSE;\r
429         cmd.Format(_T("git.exe merge-base %s %s"), m_UpstreamCtrl.GetString(),m_BranchCtrl.GetString());\r
430         if(g_Git.Run(cmd,&base,CP_ACP))\r
431         {\r
432                 CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
433                 return;\r
434         }\r
435         base=base.Left(40);\r
436 \r
437         hash=g_Git.GetHash(m_BranchCtrl.GetString());\r
438 \r
439         if(hash == g_Git.GetHash(this->m_UpstreamCtrl.GetString()))\r
440         {\r
441                 m_CommitList.Clear();\r
442                 CString text,fmt;\r
443                 fmt.LoadString(IDS_REBASE_EQUAL_FMT);\r
444                 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());\r
445 \r
446                 m_CommitList.ShowText(text);\r
447                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(false);\r
448                 return;\r
449         }\r
450 \r
451         hash=hash.Left(40);\r
452         \r
453         if(hash == base )\r
454         {\r
455                 //fast forword\r
456                 this->m_IsFastForward=TRUE;\r
457 \r
458                 m_CommitList.Clear();\r
459                 CString text,fmt;\r
460                 fmt.LoadString(IDS_REBASE_FASTFORWARD_FMT);\r
461                 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString(),\r
462                                                 m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());\r
463 \r
464                 m_CommitList.ShowText(text);\r
465                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(true);\r
466                 SetContinueButtonText();\r
467                 \r
468                 return ;\r
469         }\r
470 \r
471         hash.Empty();\r
472 \r
473         if(!this->m_bForce)\r
474         {\r
475                 cmd.Format(_T("git.exe rev-parse %s"), m_UpstreamCtrl.GetString());\r
476                 if( g_Git.Run(cmd,&hash,CP_ACP))\r
477                 {\r
478                         CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
479                         return;\r
480                 }\r
481                 hash=hash.Left(40);\r
482                 \r
483                 if( base == hash )\r
484                 {\r
485                         m_CommitList.Clear();\r
486                         CString text,fmt;\r
487                         fmt.LoadString(IDS_REBASE_UPTODATE_FMT);\r
488                         text.Format(fmt,m_BranchCtrl.GetString());\r
489                         m_CommitList.ShowText(text);\r
490                         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
491                         SetContinueButtonText();\r
492                         return;\r
493                 }\r
494         }\r
495 \r
496         m_CommitList.Clear();\r
497         this->m_CommitList.FillGitLog(NULL,0,&m_UpstreamCtrl.GetString(),&m_BranchCtrl.GetString());\r
498         if( m_CommitList.GetItemCount() == 0 )\r
499                 m_CommitList.ShowText(_T("Nothing to Rebase"));\r
500 \r
501         hash=g_Git.GetHash(m_UpstreamCtrl.GetString());\r
502         \r
503 #if 0\r
504         if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )\r
505         {\r
506                 if(hash ==  m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])\r
507                 {\r
508                         m_CommitList.Clear();\r
509                         m_CommitList.ShowText(_T("Nothing Rebase"));\r
510                 }\r
511         }\r
512 #endif\r
513 \r
514         m_tooltips.Pop();\r
515         AddBranchToolTips(&this->m_BranchCtrl);\r
516         AddBranchToolTips(&this->m_UpstreamCtrl);\r
517         \r
518         for(int i=0;i<m_CommitList.m_logEntries.size();i++)\r
519         {\r
520                 m_CommitList.m_logEntries[i].m_Action = CTGitPath::LOGACTIONS_REBASE_PICK;\r
521         }\r
522 \r
523         m_CommitList.Invalidate();\r
524 \r
525         if(m_CommitList.m_IsOldFirst)\r
526                 this->m_CurrentRebaseIndex = -1;\r
527         else\r
528                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
529         \r
530         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
531         SetContinueButtonText();\r
532 }\r
533 \r
534 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)\r
535 {\r
536         if(pBranch)\r
537         {\r
538                 CString text=pBranch->GetString();\r
539                 CString tooltip;\r
540                 BYTE_VECTOR data;\r
541                 g_Git.GetLog(data,text,NULL,1,0);\r
542                 GitRev rev;\r
543                 rev.ParserFromLog(data);\r
544                 tooltip.Format(_T("CommitHash:%s\nCommit by: %s  %s\n <b>%s</b> \n %s"),\r
545                         rev.m_CommitHash,\r
546                         rev.m_AuthorName,\r
547                         CAppUtils::FormatDateAndTime(rev.m_AuthorDate,DATE_LONGDATE),\r
548                         rev.m_Subject,\r
549                         rev.m_Body);\r
550 \r
551                 pBranch->DisableTooltip();\r
552                 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);\r
553         }\r
554 }\r
555 \r
556 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)\r
557 {\r
558         m_tooltips.RelayEvent(pMsg);\r
559         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
560 }\r
561 int CRebaseDlg::CheckRebaseCondition()\r
562 {\r
563         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
564 \r
565         if( !g_Git.CheckCleanWorkTree()  )\r
566         {\r
567                 CMessageBox::Show(NULL,_T("Rebase Need Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
568                 return -1;\r
569         }\r
570         //Todo Check $REBASE_ROOT\r
571         //Todo Check $DOTEST\r
572 \r
573         CString cmd;\r
574         cmd=_T("git.exe var GIT_COMMITTER_IDENT");\r
575         if(g_Git.Run(cmd,NULL,CP_UTF8))\r
576                 return -1;\r
577 \r
578         //Todo call pre_rebase_hook\r
579         return 0;\r
580 }\r
581 int CRebaseDlg::StartRebase()\r
582 {\r
583         CString cmd,out;\r
584         m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;\r
585         if(!this->m_IsCherryPick)\r
586         {\r
587                 //Todo call comment_for_reflog\r
588                 cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());\r
589                 this->AddLogString(cmd);\r
590 \r
591                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
592                         return -1;\r
593 \r
594                 this->AddLogString(out);\r
595         }\r
596 \r
597         cmd=_T("git.exe rev-parse --verify HEAD");\r
598         if(g_Git.Run(cmd,&out,CP_UTF8))\r
599         {\r
600                 AddLogString(_T("No Head"));\r
601                 return -1;\r
602         }\r
603         //Todo \r
604         //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||\r
605         //              echo "detached HEAD" > "$DOTEST"/head-name\r
606 \r
607         cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));\r
608         if(g_Git.Run(cmd,&out,CP_UTF8))\r
609         {\r
610                 AddLogString(_T("update ORIG_HEAD Fail"));\r
611                 return -1;\r
612         }\r
613         \r
614         if( !this->m_IsCherryPick )\r
615         {\r
616                 cmd.Format(_T("git.exe checkout %s"),this->m_UpstreamCtrl.GetString());\r
617                 this->AddLogString(cmd);\r
618 \r
619                 out.Empty();\r
620                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
621                 {\r
622                         return -1;\r
623                 }\r
624         }\r
625         \r
626         m_OrigUpstreamHash.Empty();\r
627         m_OrigUpstreamHash= g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
628         if(m_OrigUpstreamHash.IsEmpty())\r
629         {\r
630                 this->AddLogString(m_OrigUpstreamHash);\r
631                 return -1;\r
632         }\r
633 \r
634         if( !this->m_IsCherryPick )\r
635         {\r
636                 cmd.Format(_T("git.exe rev-parse %s"),this->m_BranchCtrl.GetString());\r
637                 if(g_Git.Run(cmd,&this->m_OrigBranchHash,CP_UTF8))\r
638                 {\r
639                         this->AddLogString(m_OrigBranchHash);\r
640                         return -1;\r
641                 }\r
642                 this->AddLogString(_T("Start Rebase\r\n"));\r
643 \r
644         }else\r
645                 this->AddLogString(_T("Start Cherry-pick\r\n"));\r
646         \r
647         return 0;\r
648 }\r
649 int  CRebaseDlg::VerifyNoConflict()\r
650 {\r
651         CTGitPathList list;\r
652         if(g_Git.ListConflictFile(list))\r
653         {\r
654                 AddLogString(_T("Get conflict files fail"));\r
655                 return -1;\r
656         }\r
657         if( list.GetCount() != 0 )\r
658         {\r
659                 CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);\r
660                 return -1;\r
661         }\r
662         return 0;\r
663 \r
664 }\r
665 int CRebaseDlg::FinishRebase()\r
666 {\r
667         if(this->m_IsCherryPick) //cherry pick mode no "branch", working at upstream branch\r
668                 return 0;\r
669 \r
670         CString cmd,out;\r
671         cmd.Format(_T("git.exe branch -f %s"),this->m_BranchCtrl.GetString());\r
672         if(g_Git.Run(cmd,&out,CP_UTF8))\r
673         {\r
674                 AddLogString(out);\r
675                 return -1;\r
676         }\r
677         out.Empty();\r
678         cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash);\r
679         if(g_Git.Run(cmd,&out,CP_UTF8))\r
680         {\r
681                 AddLogString(out);\r
682                 return -1;\r
683         }\r
684         out.Empty();\r
685         cmd.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl.GetString());\r
686         if(g_Git.Run(cmd,&out,CP_UTF8))\r
687         {\r
688                 AddLogString(out);\r
689                 return -1;\r
690         }\r
691         return 0;\r
692 }\r
693 void CRebaseDlg::OnBnClickedContinue()\r
694 {\r
695         if( m_RebaseStage == REBASE_DONE)\r
696         {\r
697                 OnOK();\r
698                 return;\r
699         }\r
700 \r
701         if( this->m_IsFastForward )\r
702         {\r
703                 CString cmd,out;\r
704                 CString oldbranch = g_Git.GetCurrentBranch();\r
705                 if( oldbranch != m_BranchCtrl.GetString() )\r
706                 {\r
707                         cmd.Format(_T("git.exe checkout %s"),m_BranchCtrl.GetString());\r
708                         AddLogString(cmd);\r
709                         if( g_Git.Run(cmd,&out,CP_ACP) )\r
710                         {\r
711                                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
712                                 AddLogString(out);\r
713                                 return;\r
714                         }\r
715                 }\r
716                 AddLogString(out);\r
717                 out.Empty();\r
718                 m_OrigBranchHash = g_Git.GetHash(m_BranchCtrl.GetString());\r
719                 m_OrigUpstreamHash = g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
720                         \r
721                 if(!g_Git.IsFastForward(this->m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString()))\r
722                 {\r
723                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
724                         AddLogString(_T("No fast forward\r\nMaybe repository changed"));\r
725                         return;\r
726                 }\r
727                 \r
728                 cmd.Format(_T("git.exe reset --hard %s"),this->m_UpstreamCtrl.GetString());\r
729                 this->AddLogString(CString(_T("Fast forward to "))+m_UpstreamCtrl.GetString());\r
730 \r
731                 AddLogString(cmd);\r
732                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
733                 if(g_Git.Run(cmd,&out,CP_ACP))\r
734                 {\r
735                         AddLogString(_T("Fail"));\r
736                         AddLogString(out);\r
737                         return;\r
738                 }\r
739                 AddLogString(out);\r
740                 AddLogString(_T("Done"));\r
741                 m_RebaseStage = REBASE_DONE;\r
742                 UpdateCurrentStatus();\r
743                 return;\r
744 \r
745         }\r
746         if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )\r
747         {\r
748                 if(CheckRebaseCondition())\r
749                         return ;\r
750                 m_RebaseStage = REBASE_START;\r
751         }\r
752 \r
753 \r
754         if( m_RebaseStage == REBASE_FINISH )\r
755         {\r
756                 if(FinishRebase())\r
757                         return ;\r
758 \r
759                 OnOK();\r
760         }\r
761 \r
762         if( m_RebaseStage == REBASE_SQUASH_CONFLICT)\r
763         {\r
764                 if(VerifyNoConflict())\r
765                         return;\r
766                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
767                 if(this->CheckNextCommitIsSquash())\r
768                 {//next commit is not squash;\r
769                         m_RebaseStage = REBASE_SQUASH_EDIT;\r
770                         this->OnRebaseUpdateUI(0,0);\r
771                         this->UpdateCurrentStatus();\r
772                         return ;\r
773 \r
774                 }\r
775                 m_RebaseStage=REBASE_CONTINUE;\r
776                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
777                 this->UpdateCurrentStatus();\r
778 \r
779         }\r
780 \r
781         if( m_RebaseStage == REBASE_CONFLICT )\r
782         {\r
783                 if(VerifyNoConflict())\r
784                         return;\r
785 \r
786                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
787                 \r
788                 CString out =_T("");\r
789                 CString cmd;\r
790                 cmd.Format(_T("git.exe commit -C %s"), curRev->m_CommitHash);\r
791 \r
792                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
793                 {\r
794                         if(!g_Git.CheckCleanWorkTree())\r
795                         {\r
796                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
797                                 return;\r
798                         }\r
799                 }\r
800 \r
801                 AddLogString(out);\r
802                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
803                 if( curRev->m_Action & CTGitPath::LOGACTIONS_REBASE_EDIT)\r
804                 {\r
805                         m_RebaseStage=REBASE_EDIT;\r
806                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
807                         this->UpdateCurrentStatus();\r
808                         return;\r
809                 }\r
810                 else\r
811                 {\r
812                         m_RebaseStage=REBASE_CONTINUE;\r
813                         curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
814                         this->UpdateCurrentStatus();\r
815                 }\r
816                 \r
817         }\r
818 \r
819         if( m_RebaseStage == REBASE_EDIT ||  m_RebaseStage == REBASE_SQUASH_EDIT )\r
820         {\r
821                 CString str;\r
822                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
823         \r
824                 str=this->m_LogMessageCtrl.GetText();\r
825                 if(str.Trim().IsEmpty())\r
826                 {\r
827                         CMessageBox::Show(NULL,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
828                                 return;\r
829                 }\r
830 \r
831                 CString tempfile=::GetTempFile();\r
832                 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );\r
833                 CStringA log=CUnicodeUtils::GetUTF8( str);\r
834                 file.Write(log,log.GetLength());\r
835                 //file.WriteString(m_sLogMessage);\r
836                 file.Close();\r
837         \r
838                 CString out,cmd;\r
839                 \r
840                 if(  m_RebaseStage == REBASE_SQUASH_EDIT )\r
841                         cmd.Format(_T("git.exe commit -F \"%s\""), tempfile);\r
842                 else\r
843                         cmd.Format(_T("git.exe commit --amend -F \"%s\""), tempfile);\r
844 \r
845                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
846                 {\r
847                         if(!g_Git.CheckCleanWorkTree())\r
848                         {\r
849                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
850                                 return;\r
851                         }\r
852                 }\r
853 \r
854                 CFile::Remove(tempfile);\r
855                 AddLogString(out);\r
856                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
857                 m_RebaseStage=REBASE_CONTINUE;\r
858                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
859                 this->UpdateCurrentStatus();\r
860         }\r
861 \r
862 \r
863         InterlockedExchange(&m_bThreadRunning, TRUE);\r
864         SetControlEnable();\r
865         \r
866         if (AfxBeginThread(RebaseThreadEntry, this)==NULL)\r
867         {\r
868                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
869                 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);\r
870                 SetControlEnable();\r
871         }\r
872 }\r
873 int CRebaseDlg::CheckNextCommitIsSquash()\r
874 {\r
875         int index;\r
876         if(m_CommitList.m_IsOldFirst)\r
877                 index=m_CurrentRebaseIndex+1;\r
878         else\r
879                 index=m_CurrentRebaseIndex-1;\r
880 \r
881         GitRev *curRev;\r
882         do\r
883         {\r
884                 if(index<0)\r
885                         return -1;\r
886                 if(index>= m_CommitList.GetItemCount())\r
887                         return -1;\r
888 \r
889                 curRev=(GitRev*)m_CommitList.m_arShownList[index];\r
890                 \r
891                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH )\r
892                         return 0;\r
893                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP)\r
894                 {\r
895                         if(m_CommitList.m_IsOldFirst)\r
896                                 index++;\r
897                         else\r
898                                 index--;\r
899                 }else\r
900                         return -1;              \r
901 \r
902         }while(curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP);\r
903         \r
904         return -1;\r
905 \r
906 }\r
907 int CRebaseDlg::GoNext()\r
908 {\r
909         if(m_CommitList.m_IsOldFirst)\r
910                 m_CurrentRebaseIndex++;\r
911         else\r
912                 m_CurrentRebaseIndex--; \r
913         return 0;\r
914 \r
915 }\r
916 int CRebaseDlg::StateAction()\r
917 {\r
918         switch(this->m_RebaseStage)\r
919         {\r
920         case CHOOSE_BRANCH:\r
921         case CHOOSE_COMMIT_PICK_MODE:\r
922                 if(StartRebase())\r
923                         return -1;\r
924                 m_RebaseStage = REBASE_START;\r
925                 GoNext();\r
926                 break;\r
927         }\r
928 \r
929         return 0;       \r
930 }\r
931 void CRebaseDlg::SetContinueButtonText()\r
932 {\r
933         CString Text;\r
934         switch(this->m_RebaseStage)\r
935         {\r
936         case CHOOSE_BRANCH:\r
937         case CHOOSE_COMMIT_PICK_MODE:\r
938                 if(this->m_IsFastForward)\r
939                         Text = _T("Start(FastFwd)");\r
940                 else\r
941                         Text = _T("Start");\r
942                 break;\r
943 \r
944         case REBASE_START:\r
945         case REBASE_CONTINUE:\r
946         case REBASE_SQUASH_CONFLICT:\r
947                 Text = _T("Continue");\r
948                 break;\r
949 \r
950         case REBASE_CONFLICT:\r
951                 Text = _T("Commit");\r
952                 break;\r
953         case REBASE_EDIT:\r
954                 Text = _T("Amend");\r
955                 break;\r
956 \r
957         case REBASE_SQUASH_EDIT:\r
958                 Text = _T("Commit");\r
959                 break;\r
960 \r
961         case REBASE_ABORT:\r
962         case REBASE_FINISH:\r
963                 Text = _T("Finish");\r
964                 break;\r
965 \r
966         case REBASE_DONE:\r
967                 Text = _T("Done");\r
968                 break;\r
969         }\r
970         this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);\r
971 }\r
972 \r
973 void CRebaseDlg::SetControlEnable()\r
974 {\r
975         switch(this->m_RebaseStage)\r
976         {\r
977         case CHOOSE_BRANCH:\r
978         case CHOOSE_COMMIT_PICK_MODE:\r
979                 \r
980                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);\r
981                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);\r
982                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);\r
983                 if(!m_IsCherryPick)\r
984                 {\r
985                         this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);\r
986                         this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);\r
987                 }\r
988                 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;\r
989                 this->m_CommitList.m_ContextMenuMask |= m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
990                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
991                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
992                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP);\r
993                 break;\r
994 \r
995         case REBASE_START:\r
996         case REBASE_CONTINUE:\r
997         case REBASE_ABORT:\r
998         case REBASE_FINISH:\r
999         case REBASE_CONFLICT:\r
1000         case REBASE_EDIT:\r
1001         case REBASE_SQUASH_CONFLICT:\r
1002         case REBASE_DONE:\r
1003                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);\r
1004                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);\r
1005                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);\r
1006                 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);\r
1007                 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);\r
1008                 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;\r
1009                 this->m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
1010                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
1011                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
1012                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP));\r
1013 \r
1014                 if( m_RebaseStage == REBASE_DONE && (!this->m_PostButtonText.IsEmpty()) )\r
1015                 {\r
1016                         this->GetDlgItem(IDC_STATUS_STATIC)->ShowWindow(SW_HIDE);\r
1017                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->ShowWindow(SW_SHOWNORMAL);\r
1018                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);\r
1019                 }\r
1020                 break;\r
1021         }\r
1022 \r
1023         if(m_bThreadRunning)\r
1024         {\r
1025                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);\r
1026                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(FALSE);\r
1027 \r
1028         }else\r
1029         {\r
1030                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);\r
1031                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(TRUE);\r
1032         }\r
1033 }\r
1034 \r
1035 void CRebaseDlg::UpdateProgress()\r
1036 {\r
1037         int index;\r
1038         CRect rect;\r
1039 \r
1040         if(m_CommitList.m_IsOldFirst)\r
1041                 index = m_CurrentRebaseIndex+1;\r
1042         else\r
1043                 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1044 \r
1045         m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());\r
1046         m_ProgressBar.SetPos(index);\r
1047 \r
1048         if(m_CurrentRebaseIndex>=0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())\r
1049         {\r
1050                 CString text;\r
1051                 text.Format(_T("Rebasing...(%d/%d)"),index,m_CommitList.GetItemCount());\r
1052                 m_CtrlStatusText.SetWindowText(text);\r
1053 \r
1054         }\r
1055 \r
1056         GitRev *prevRev=NULL, *curRev=NULL;\r
1057 \r
1058         if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())\r
1059         {\r
1060                 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1061         }\r
1062         \r
1063         for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)\r
1064         {\r
1065                 prevRev=(GitRev*)m_CommitList.m_arShownList[i];\r
1066                 if(prevRev->m_Action & CTGitPath::LOGACTIONS_REBASE_CURRENT)\r
1067                 {       \r
1068                         prevRev->m_Action &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1069                         m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);\r
1070                         m_CommitList.InvalidateRect(rect);\r
1071                 }\r
1072         }\r
1073 \r
1074         if(curRev)\r
1075         {\r
1076                 curRev->m_Action |= CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1077                 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);\r
1078                 m_CommitList.InvalidateRect(rect);\r
1079         }\r
1080         m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);\r
1081 \r
1082 }\r
1083 \r
1084 void CRebaseDlg::UpdateCurrentStatus()\r
1085 {\r
1086         if( m_CurrentRebaseIndex < 0 && m_RebaseStage!= REBASE_DONE)\r
1087         {\r
1088                 if(m_CommitList.m_IsOldFirst)\r
1089                         m_RebaseStage = CRebaseDlg::REBASE_START;\r
1090                 else\r
1091                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1092         }\r
1093 \r
1094         if( m_CurrentRebaseIndex == m_CommitList.m_arShownList.GetSize() && m_RebaseStage!= REBASE_DONE)\r
1095         {\r
1096                 if(m_CommitList.m_IsOldFirst)\r
1097                         m_RebaseStage = CRebaseDlg::REBASE_DONE;\r
1098                 else\r
1099                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1100         }\r
1101 \r
1102         SetContinueButtonText();\r
1103         SetControlEnable();\r
1104         UpdateProgress();\r
1105 }\r
1106 \r
1107 void CRebaseDlg::AddLogString(CString str)\r
1108 {\r
1109         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);\r
1110         CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);\r
1111         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);\r
1112         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");\r
1113         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);\r
1114 }\r
1115 \r
1116 int CRebaseDlg::GetCurrentCommitID()\r
1117 {\r
1118         if(m_CommitList.m_IsOldFirst)\r
1119         {\r
1120                 return this->m_CurrentRebaseIndex+1;\r
1121 \r
1122         }else\r
1123         {\r
1124                 return m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1125         }\r
1126 }\r
1127 \r
1128 int CRebaseDlg::DoRebase()\r
1129 {       \r
1130         CString cmd,out;\r
1131         if(m_CurrentRebaseIndex <0)\r
1132                 return 0;\r
1133         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1134                 return 0;\r
1135 \r
1136         GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1137         int mode=pRev->m_Action & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;\r
1138         CString nocommit;\r
1139 \r
1140         if( mode== CTGitPath::LOGACTIONS_REBASE_SKIP)\r
1141         {\r
1142                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1143                 return 0;\r
1144         }\r
1145         \r
1146         if( mode != CTGitPath::LOGACTIONS_REBASE_PICK )\r
1147         {\r
1148                 this->m_SquashMessage+= pRev->m_Subject;\r
1149                 this->m_SquashMessage+= _T("\n");\r
1150                 this->m_SquashMessage+= pRev->m_Body;\r
1151         }\r
1152         else\r
1153                 this->m_SquashMessage.Empty();\r
1154 \r
1155         if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1156                 nocommit=_T(" --no-commit ");\r
1157 \r
1158         CString log;\r
1159         log.Format(_T("%s %d:%s"),CTGitPath::GetActionName(mode),this->GetCurrentCommitID(),pRev->m_CommitHash);\r
1160         AddLogString(log);\r
1161         AddLogString(pRev->m_Subject);\r
1162         cmd.Format(_T("git.exe cherry-pick %s %s"),nocommit,pRev->m_CommitHash);\r
1163 \r
1164         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1165         {\r
1166                 AddLogString(out);\r
1167                 CTGitPathList list;\r
1168                 if(g_Git.ListConflictFile(list))\r
1169                 {\r
1170                         AddLogString(_T("Get conflict files fail"));\r
1171                         return -1;\r
1172                 }\r
1173                 if(list.GetCount() == 0 )\r
1174                 {\r
1175                         if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1176                         {\r
1177                                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1178                                 return 0;\r
1179                         }\r
1180                         if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1181                         {\r
1182                                 this->m_RebaseStage = REBASE_EDIT ;\r
1183                                 return -1; // Edit return -1 to stop rebase. \r
1184                         }\r
1185                         // Squash Case\r
1186                         if(CheckNextCommitIsSquash())\r
1187                         {   // no squash\r
1188                                 // let user edit last commmit message\r
1189                                 this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1190                                 return -1;\r
1191                         }\r
1192                 }\r
1193                 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1194                         m_RebaseStage = REBASE_SQUASH_CONFLICT;\r
1195                 else\r
1196                         m_RebaseStage = REBASE_CONFLICT;\r
1197                 return -1;      \r
1198 \r
1199         }else\r
1200         {\r
1201                 AddLogString(out);\r
1202                 if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1203                 {\r
1204                         pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1205                         return 0;\r
1206                 }\r
1207                 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1208                 {\r
1209                         this->m_RebaseStage = REBASE_EDIT ;\r
1210                         return -1; // Edit return -1 to stop rebase. \r
1211                 }\r
1212 \r
1213                 // Squash Case\r
1214                 if(CheckNextCommitIsSquash())\r
1215                 {   // no squash\r
1216                         // let user edit last commmit message\r
1217                         this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1218                         return -1;\r
1219                 }\r
1220         }\r
1221         \r
1222         return 0;\r
1223 }\r
1224 \r
1225 BOOL CRebaseDlg::IsEnd()\r
1226 {\r
1227         if(m_CommitList.m_IsOldFirst)\r
1228                 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();\r
1229         else\r
1230                 return m_CurrentRebaseIndex<0;\r
1231 }\r
1232 \r
1233 int CRebaseDlg::RebaseThread()\r
1234 {\r
1235         int ret=0;\r
1236         while(1)\r
1237         {\r
1238                 if( m_RebaseStage == REBASE_START )\r
1239                 {\r
1240                         if( this->StartRebase() )\r
1241                         {\r
1242                                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
1243                                 ret = -1;\r
1244                                 break;\r
1245                         }\r
1246                         m_RebaseStage = REBASE_CONTINUE;\r
1247 \r
1248                 }else if( m_RebaseStage == REBASE_CONTINUE )\r
1249                 {\r
1250                         this->GoNext(); \r
1251                         if(IsEnd())\r
1252                         {\r
1253                                 ret = 0;\r
1254                                 m_RebaseStage = REBASE_FINISH;\r
1255                                 \r
1256                         }else\r
1257                         {\r
1258                                 ret = DoRebase();\r
1259 \r
1260                                 if( ret )\r
1261                                 {       \r
1262                                         break;\r
1263                                 }\r
1264                         }\r
1265 \r
1266                 }else if( m_RebaseStage == REBASE_FINISH )\r
1267                 {                       \r
1268                         FinishRebase();\r
1269                         m_RebaseStage = REBASE_DONE;\r
1270                         break;\r
1271                         \r
1272                 }else\r
1273                 {\r
1274                         break;\r
1275                 }\r
1276                 this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1277                 //this->UpdateCurrentStatus();\r
1278         }\r
1279 \r
1280         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1281         this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1282         return ret;\r
1283 }\r
1284 \r
1285 void CRebaseDlg::ListConflictFile()\r
1286 {\r
1287         this->m_FileListCtrl.Clear();   \r
1288         CTGitPathList list;\r
1289         CTGitPath path;\r
1290         list.AddPath(path);\r
1291 \r
1292         m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;\r
1293 \r
1294         this->m_FileListCtrl.GetStatus(&list,true);\r
1295         this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED|CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_DELETED,\r
1296                                                            CTGitPath::LOGACTIONS_UNMERGED);\r
1297         if( this->m_FileListCtrl.GetItemCount() == 0 )\r
1298         {\r
1299                 \r
1300         }\r
1301 }\r
1302 \r
1303 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)\r
1304 {\r
1305         UpdateCurrentStatus();\r
1306         if(m_CurrentRebaseIndex <0)\r
1307                 return 0;\r
1308         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1309                 return 0;\r
1310         GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1311         \r
1312         switch(m_RebaseStage)\r
1313         {\r
1314         case REBASE_CONFLICT:\r
1315         case REBASE_SQUASH_CONFLICT:\r
1316                 ListConflictFile();                     \r
1317                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);\r
1318                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1319                 break;\r
1320         case REBASE_EDIT:\r
1321                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1322                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1323                 break;\r
1324         case REBASE_SQUASH_EDIT:\r
1325                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1326                 this->m_LogMessageCtrl.SetText(this->m_SquashMessage);\r
1327                 break;\r
1328         default:\r
1329                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
1330         }       \r
1331         return 0;\r
1332 }\r
1333 void CRebaseDlg::OnCancel()\r
1334 {\r
1335         OnBnClickedAbort();\r
1336 }\r
1337 void CRebaseDlg::OnBnClickedAbort()\r
1338 {\r
1339         CString cmd,out;\r
1340         if(m_OrigUpstreamHash.IsEmpty())\r
1341         {\r
1342                 __super::OnCancel();\r
1343         }\r
1344         \r
1345         if(m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage== CHOOSE_COMMIT_PICK_MODE)\r
1346         {\r
1347                 return;\r
1348         }\r
1349 \r
1350         if(CMessageBox::Show(NULL,_T("Are you sure you want to abort the rebase process?"),_T("TortoiseGit"),MB_YESNO) != IDYES)\r
1351                 return;\r
1352 \r
1353         if(this->m_IsFastForward)\r
1354         {\r
1355                 cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1356                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
1357                 {\r
1358                         AddLogString(out);\r
1359                         return ;\r
1360                 }\r
1361                 __super::OnCancel();\r
1362                 return;\r
1363         }\r
1364         cmd.Format(_T("git.exe checkout -f %s"),this->m_UpstreamCtrl.GetString());\r
1365         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1366         {\r
1367                 AddLogString(out);\r
1368                 return ;\r
1369         }\r
1370 \r
1371         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigUpstreamHash.Left(40));\r
1372         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1373         {\r
1374                 AddLogString(out);\r
1375                 return ;\r
1376         }\r
1377         \r
1378         if(this->m_IsCherryPick) //there are not "branch" at cherry pick mode\r
1379                 return;\r
1380 \r
1381         cmd.Format(_T("git checkout -f %s"),this->m_BranchCtrl.GetString());\r
1382         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1383         {\r
1384                 AddLogString(out);\r
1385                 return ;\r
1386         }\r
1387         \r
1388         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1389         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1390         {\r
1391                 AddLogString(out);\r
1392                 return ;\r
1393         }\r
1394         __super::OnCancel();\r
1395 }\r
1396 \r
1397 void CRebaseDlg::OnBnClickedButtonBrowse()\r
1398 {\r
1399         if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl, gPickRef_NoTag))\r
1400                 OnCbnSelchangeUpstream();\r
1401 }\r
1402 \r
1403 void CRebaseDlg::OnBnClickedRebaseCheckForce()\r
1404 {\r
1405         // TODO: Add your control notification handler code here\r
1406         this->UpdateData();\r
1407         this->FetchLogList();\r
1408 }\r
1409 \r
1410 void CRebaseDlg::OnStnClickedStatusStatic()\r
1411 {\r
1412         // TODO: Add your control notification handler code here\r
1413 }\r
1414 \r
1415 void CRebaseDlg::OnBnClickedRebasePostButton()\r
1416 {\r
1417         // TODO: Add your control notification handler code here\r
1418         this->m_Upstream=this->m_UpstreamCtrl.GetString();\r
1419         this->m_Branch=this->m_BranchCtrl.GetString();\r
1420 \r
1421         this->EndDialog(IDC_REBASE_POST_BUTTON);\r
1422 }\r