OSDN Git Service

034221d2e1b3605a72b82c0a9c507d82c2570dbf
[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         \r
316         this->AddRebaseAnchor();\r
317         // adjust the minimum size of the dialog to prevent the resizing from\r
318         // moving the list control too far down.\r
319         CRect rcLogMsg;\r
320         m_CommitList.GetClientRect(rcLogMsg);\r
321         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));\r
322 \r
323         SetSplitterRange();\r
324 //      m_CommitList.Invalidate();\r
325 \r
326 //      GetDlgItem(IDC_LOGMESSAGE)->Invalidate();\r
327 \r
328         this->m_ctrlTabCtrl.Invalidate();\r
329         this->m_CommitList.Invalidate();\r
330         this->m_FileListCtrl.Invalidate();\r
331         this->m_LogMessageCtrl.Invalidate();\r
332 \r
333 }\r
334 \r
335 void CRebaseDlg::SetSplitterRange()\r
336 {\r
337         if ((m_CommitList)&&(m_ctrlTabCtrl))\r
338         {\r
339                 CRect rcTop;\r
340                 m_CommitList.GetWindowRect(rcTop);\r
341                 ScreenToClient(rcTop);\r
342                 CRect rcMiddle;\r
343                 m_ctrlTabCtrl.GetWindowRect(rcMiddle);\r
344                 ScreenToClient(rcMiddle);\r
345                 if (rcMiddle.Height() && rcMiddle.Width())\r
346                         m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);\r
347         }\r
348 }\r
349 \r
350 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)\r
351 {\r
352          // first, let the resizing take place\r
353     __super::OnSize(nType, cx, cy);\r
354 \r
355     //set range\r
356     SetSplitterRange();\r
357 }\r
358 \r
359 void CRebaseDlg::SaveSplitterPos()\r
360 {\r
361         if (!IsIconic())\r
362         {\r
363                 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
364                 RECT rectSplitter;\r
365                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
366                 ScreenToClient(&rectSplitter);\r
367                 regPos = rectSplitter.top;\r
368         }\r
369 }\r
370 \r
371 void CRebaseDlg::LoadBranchInfo()\r
372 {\r
373         m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
374         m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
375 \r
376         STRING_VECTOR list;\r
377         list.clear();\r
378         int current;\r
379         g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);\r
380         m_BranchCtrl.AddString(list);\r
381         m_UpstreamCtrl.AddString(list);\r
382 \r
383         m_BranchCtrl.SetCurSel(current);\r
384 \r
385         AddBranchToolTips(&m_BranchCtrl);\r
386         AddBranchToolTips(&m_UpstreamCtrl);\r
387 \r
388         if(!m_Upstream.IsEmpty())\r
389         {\r
390                 m_UpstreamCtrl.AddString(m_Upstream);\r
391                 m_UpstreamCtrl.SetCurSel(m_UpstreamCtrl.GetCount()-1);\r
392         }\r
393         else\r
394         {\r
395                 //Select pull-remote from current branch\r
396                 CString currentBranch = g_Git.GetSymbolicRef();\r
397                 CString configName;\r
398                 configName.Format(L"branch.%s.remote", currentBranch);\r
399                 CString pullRemote = g_Git.GetConfigValue(configName);\r
400 \r
401                 //Select pull-branch from current branch\r
402                 configName.Format(L"branch.%s.merge", currentBranch);\r
403                 CString pullBranch = CGit::StripRefName(g_Git.GetConfigValue(configName));\r
404 \r
405                 CString defaultUpstream;\r
406                 defaultUpstream.Format(L"remotes/%s/%s", pullRemote, pullBranch);\r
407                 int found = m_UpstreamCtrl.FindStringExact(0, defaultUpstream);\r
408                 if(found >= 0)\r
409                         m_UpstreamCtrl.SetCurSel(found);\r
410         }\r
411 }\r
412 \r
413 void CRebaseDlg::OnCbnSelchangeBranch()\r
414 {\r
415         FetchLogList();\r
416 }\r
417 \r
418 void CRebaseDlg::OnCbnSelchangeUpstream()\r
419 {\r
420         FetchLogList();\r
421 }\r
422 \r
423 void CRebaseDlg::FetchLogList()\r
424 {\r
425         CString base,hash;\r
426         CString cmd;\r
427         m_IsFastForward=FALSE;\r
428         cmd.Format(_T("git.exe merge-base %s %s"), m_UpstreamCtrl.GetString(),m_BranchCtrl.GetString());\r
429         if(g_Git.Run(cmd,&base,CP_ACP))\r
430         {\r
431                 CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
432                 return;\r
433         }\r
434         base=base.Left(40);\r
435 \r
436         hash=g_Git.GetHash(m_BranchCtrl.GetString());\r
437 \r
438         if(hash == g_Git.GetHash(this->m_UpstreamCtrl.GetString()))\r
439         {\r
440                 m_CommitList.Clear();\r
441                 CString text,fmt;\r
442                 fmt.LoadString(IDS_REBASE_EQUAL_FMT);\r
443                 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());\r
444 \r
445                 m_CommitList.ShowText(text);\r
446                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(false);\r
447                 return;\r
448         }\r
449 \r
450         hash=hash.Left(40);\r
451         \r
452         if(hash == base )\r
453         {\r
454                 //fast forword\r
455                 this->m_IsFastForward=TRUE;\r
456 \r
457                 m_CommitList.Clear();\r
458                 CString text,fmt;\r
459                 fmt.LoadString(IDS_REBASE_FASTFORWARD_FMT);\r
460                 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString(),\r
461                                                 m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());\r
462 \r
463                 m_CommitList.ShowText(text);\r
464                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(true);\r
465                 SetContinueButtonText();\r
466                 \r
467                 return ;\r
468         }\r
469 \r
470         hash.Empty();\r
471 \r
472         if(!this->m_bForce)\r
473         {\r
474                 cmd.Format(_T("git.exe rev-parse %s"), m_UpstreamCtrl.GetString());\r
475                 if( g_Git.Run(cmd,&hash,CP_ACP))\r
476                 {\r
477                         CMessageBox::Show(NULL,base,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
478                         return;\r
479                 }\r
480                 hash=hash.Left(40);\r
481                 \r
482                 if( base == hash )\r
483                 {\r
484                         m_CommitList.Clear();\r
485                         CString text,fmt;\r
486                         fmt.LoadString(IDS_REBASE_UPTODATE_FMT);\r
487                         text.Format(fmt,m_BranchCtrl.GetString());\r
488                         m_CommitList.ShowText(text);\r
489                         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
490                         SetContinueButtonText();\r
491                         return;\r
492                 }\r
493         }\r
494 \r
495         m_CommitList.Clear();\r
496         this->m_CommitList.FillGitLog(NULL,0,&m_UpstreamCtrl.GetString(),&m_BranchCtrl.GetString());\r
497         if( m_CommitList.GetItemCount() == 0 )\r
498                 m_CommitList.ShowText(_T("Nothing to Rebase"));\r
499 \r
500         hash=g_Git.GetHash(m_UpstreamCtrl.GetString());\r
501         \r
502 #if 0\r
503         if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )\r
504         {\r
505                 if(hash ==  m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])\r
506                 {\r
507                         m_CommitList.Clear();\r
508                         m_CommitList.ShowText(_T("Nothing Rebase"));\r
509                 }\r
510         }\r
511 #endif\r
512 \r
513         m_tooltips.Pop();\r
514         AddBranchToolTips(&this->m_BranchCtrl);\r
515         AddBranchToolTips(&this->m_UpstreamCtrl);\r
516         \r
517         for(int i=0;i<m_CommitList.m_logEntries.size();i++)\r
518         {\r
519                 m_CommitList.m_logEntries[i].m_Action = CTGitPath::LOGACTIONS_REBASE_PICK;\r
520         }\r
521 \r
522         m_CommitList.Invalidate();\r
523 \r
524         if(m_CommitList.m_IsOldFirst)\r
525                 this->m_CurrentRebaseIndex = -1;\r
526         else\r
527                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
528         \r
529         this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());\r
530         SetContinueButtonText();\r
531 }\r
532 \r
533 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)\r
534 {\r
535         if(pBranch)\r
536         {\r
537                 CString text=pBranch->GetString();\r
538                 CString tooltip;\r
539                 BYTE_VECTOR data;\r
540                 g_Git.GetLog(data,text,NULL,1,0);\r
541                 GitRev rev;\r
542                 rev.ParserFromLog(data);\r
543                 tooltip.Format(_T("CommitHash:%s\nCommit by: %s  %s\n <b>%s</b> \n %s"),\r
544                         rev.m_CommitHash,\r
545                         rev.m_AuthorName,\r
546                         CAppUtils::FormatDateAndTime(rev.m_AuthorDate,DATE_LONGDATE),\r
547                         rev.m_Subject,\r
548                         rev.m_Body);\r
549 \r
550                 pBranch->DisableTooltip();\r
551                 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);\r
552         }\r
553 }\r
554 \r
555 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)\r
556 {\r
557         m_tooltips.RelayEvent(pMsg);\r
558         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
559 }\r
560 int CRebaseDlg::CheckRebaseCondition()\r
561 {\r
562         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
563 \r
564         if( !g_Git.CheckCleanWorkTree()  )\r
565         {\r
566                 CMessageBox::Show(NULL,_T("Rebase Need Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
567                 return -1;\r
568         }\r
569         //Todo Check $REBASE_ROOT\r
570         //Todo Check $DOTEST\r
571 \r
572         CString cmd;\r
573         cmd=_T("git.exe var GIT_COMMITTER_IDENT");\r
574         if(g_Git.Run(cmd,NULL,CP_UTF8))\r
575                 return -1;\r
576 \r
577         //Todo call pre_rebase_hook\r
578         return 0;\r
579 }\r
580 int CRebaseDlg::StartRebase()\r
581 {\r
582         CString cmd,out;\r
583 \r
584         if(!this->m_IsCherryPick)\r
585         {\r
586                 //Todo call comment_for_reflog\r
587                 cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());\r
588                 this->AddLogString(cmd);\r
589 \r
590                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
591                         return -1;\r
592 \r
593                 this->AddLogString(out);\r
594         }\r
595 \r
596         cmd=_T("git.exe rev-parse --verify HEAD");\r
597         if(g_Git.Run(cmd,&out,CP_UTF8))\r
598         {\r
599                 AddLogString(_T("No Head"));\r
600                 return -1;\r
601         }\r
602         //Todo \r
603         //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||\r
604         //              echo "detached HEAD" > "$DOTEST"/head-name\r
605 \r
606         cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));\r
607         if(g_Git.Run(cmd,&out,CP_UTF8))\r
608         {\r
609                 AddLogString(_T("update ORIG_HEAD Fail"));\r
610                 return -1;\r
611         }\r
612         \r
613         if( !this->m_IsCherryPick )\r
614         {\r
615                 cmd.Format(_T("git.exe checkout %s"),this->m_UpstreamCtrl.GetString());\r
616                 this->AddLogString(cmd);\r
617 \r
618                 out.Empty();\r
619                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
620                 {\r
621                         return -1;\r
622                 }\r
623         }\r
624         \r
625         m_OrigUpstreamHash.Empty();\r
626         m_OrigUpstreamHash= g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
627         if(m_OrigUpstreamHash.IsEmpty())\r
628         {\r
629                 this->AddLogString(m_OrigUpstreamHash);\r
630                 return -1;\r
631         }\r
632 \r
633         if( !this->m_IsCherryPick )\r
634         {\r
635                 cmd.Format(_T("git.exe rev-parse %s"),this->m_BranchCtrl.GetString());\r
636                 if(g_Git.Run(cmd,&this->m_OrigBranchHash,CP_UTF8))\r
637                 {\r
638                         this->AddLogString(m_OrigBranchHash);\r
639                         return -1;\r
640                 }\r
641                 this->AddLogString(_T("Start Rebase\r\n"));\r
642 \r
643         }else\r
644                 this->AddLogString(_T("Start Cherry-pick\r\n"));\r
645         \r
646         return 0;\r
647 }\r
648 int  CRebaseDlg::VerifyNoConflict()\r
649 {\r
650         CTGitPathList list;\r
651         if(g_Git.ListConflictFile(list))\r
652         {\r
653                 AddLogString(_T("Get conflict files fail"));\r
654                 return -1;\r
655         }\r
656         if( list.GetCount() != 0 )\r
657         {\r
658                 CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);\r
659                 return -1;\r
660         }\r
661         return 0;\r
662 \r
663 }\r
664 int CRebaseDlg::FinishRebase()\r
665 {\r
666         if(this->m_IsCherryPick) //cherry pick mode no "branch", working at upstream branch\r
667                 return 0;\r
668 \r
669         CString cmd,out;\r
670         cmd.Format(_T("git.exe branch -f %s"),this->m_BranchCtrl.GetString());\r
671         if(g_Git.Run(cmd,&out,CP_UTF8))\r
672         {\r
673                 AddLogString(out);\r
674                 return -1;\r
675         }\r
676         out.Empty();\r
677         cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash);\r
678         if(g_Git.Run(cmd,&out,CP_UTF8))\r
679         {\r
680                 AddLogString(out);\r
681                 return -1;\r
682         }\r
683         out.Empty();\r
684         cmd.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl.GetString());\r
685         if(g_Git.Run(cmd,&out,CP_UTF8))\r
686         {\r
687                 AddLogString(out);\r
688                 return -1;\r
689         }\r
690         return 0;\r
691 }\r
692 void CRebaseDlg::OnBnClickedContinue()\r
693 {\r
694         if( m_RebaseStage == REBASE_DONE)\r
695         {\r
696                 OnOK();\r
697                 return;\r
698         }\r
699 \r
700         if( this->m_IsFastForward )\r
701         {\r
702                 CString cmd,out;\r
703                 CString oldbranch = g_Git.GetCurrentBranch();\r
704                 if( oldbranch != m_BranchCtrl.GetString() )\r
705                 {\r
706                         cmd.Format(_T("git.exe checkout %s"),m_BranchCtrl.GetString());\r
707                         AddLogString(cmd);\r
708                         if( g_Git.Run(cmd,&out,CP_ACP) )\r
709                         {\r
710                                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
711                                 AddLogString(out);\r
712                                 return;\r
713                         }\r
714                 }\r
715                 AddLogString(out);\r
716                 out.Empty();\r
717                 m_OrigBranchHash = g_Git.GetHash(m_BranchCtrl.GetString());\r
718                 m_OrigUpstreamHash = g_Git.GetHash(this->m_UpstreamCtrl.GetString());\r
719                         \r
720                 if(!g_Git.IsFastForward(this->m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString()))\r
721                 {\r
722                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
723                         AddLogString(_T("No fast forward\r\nMaybe repository changed"));\r
724                         return;\r
725                 }\r
726                 \r
727                 cmd.Format(_T("git.exe reset --hard %s"),this->m_UpstreamCtrl.GetString());\r
728                 this->AddLogString(CString(_T("Fast forward to "))+m_UpstreamCtrl.GetString());\r
729 \r
730                 AddLogString(cmd);\r
731                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
732                 if(g_Git.Run(cmd,&out,CP_ACP))\r
733                 {\r
734                         AddLogString(_T("Fail"));\r
735                         AddLogString(out);\r
736                         return;\r
737                 }\r
738                 AddLogString(out);\r
739                 AddLogString(_T("Done"));\r
740                 m_RebaseStage = REBASE_DONE;\r
741                 UpdateCurrentStatus();\r
742                 return;\r
743 \r
744         }\r
745         if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )\r
746         {\r
747                 if(CheckRebaseCondition())\r
748                         return ;\r
749                 m_RebaseStage = REBASE_START;\r
750         }\r
751 \r
752 \r
753         if( m_RebaseStage == REBASE_FINISH )\r
754         {\r
755                 if(FinishRebase())\r
756                         return ;\r
757 \r
758                 OnOK();\r
759         }\r
760 \r
761         if( m_RebaseStage == REBASE_SQUASH_CONFLICT)\r
762         {\r
763                 if(VerifyNoConflict())\r
764                         return;\r
765                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
766                 if(this->CheckNextCommitIsSquash())\r
767                 {//next commit is not squash;\r
768                         m_RebaseStage = REBASE_SQUASH_EDIT;\r
769                         this->OnRebaseUpdateUI(0,0);\r
770                         this->UpdateCurrentStatus();\r
771                         return ;\r
772 \r
773                 }\r
774                 m_RebaseStage=REBASE_CONTINUE;\r
775                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
776                 this->UpdateCurrentStatus();\r
777 \r
778         }\r
779 \r
780         if( m_RebaseStage == REBASE_CONFLICT )\r
781         {\r
782                 if(VerifyNoConflict())\r
783                         return;\r
784 \r
785                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
786                 \r
787                 CString out =_T("");\r
788                 CString cmd;\r
789                 cmd.Format(_T("git.exe commit -C %s"), curRev->m_CommitHash);\r
790 \r
791                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
792                 {\r
793                         if(!g_Git.CheckCleanWorkTree())\r
794                         {\r
795                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
796                                 return;\r
797                         }\r
798                 }\r
799 \r
800                 AddLogString(out);\r
801                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
802                 if( curRev->m_Action & CTGitPath::LOGACTIONS_REBASE_EDIT)\r
803                 {\r
804                         m_RebaseStage=REBASE_EDIT;\r
805                         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
806                         this->UpdateCurrentStatus();\r
807                         return;\r
808                 }\r
809                 else\r
810                 {\r
811                         m_RebaseStage=REBASE_CONTINUE;\r
812                         curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
813                         this->UpdateCurrentStatus();\r
814                 }\r
815                 \r
816         }\r
817 \r
818         if( m_RebaseStage == REBASE_EDIT ||  m_RebaseStage == REBASE_SQUASH_EDIT )\r
819         {\r
820                 CString str;\r
821                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
822         \r
823                 str=this->m_LogMessageCtrl.GetText();\r
824                 if(str.Trim().IsEmpty())\r
825                 {\r
826                         CMessageBox::Show(NULL,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
827                                 return;\r
828                 }\r
829 \r
830                 CString tempfile=::GetTempFile();\r
831                 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );\r
832                 CStringA log=CUnicodeUtils::GetUTF8( str);\r
833                 file.Write(log,log.GetLength());\r
834                 //file.WriteString(m_sLogMessage);\r
835                 file.Close();\r
836         \r
837                 CString out,cmd;\r
838                 \r
839                 if(  m_RebaseStage == REBASE_SQUASH_EDIT )\r
840                         cmd.Format(_T("git.exe commit -F \"%s\""), tempfile);\r
841                 else\r
842                         cmd.Format(_T("git.exe commit --amend -F \"%s\""), tempfile);\r
843 \r
844                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
845                 {\r
846                         if(!g_Git.CheckCleanWorkTree())\r
847                         {\r
848                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
849                                 return;\r
850                         }\r
851                 }\r
852 \r
853                 CFile::Remove(tempfile);\r
854                 AddLogString(out);\r
855                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
856                 m_RebaseStage=REBASE_CONTINUE;\r
857                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
858                 this->UpdateCurrentStatus();\r
859         }\r
860 \r
861 \r
862         InterlockedExchange(&m_bThreadRunning, TRUE);\r
863         SetControlEnable();\r
864         \r
865         if (AfxBeginThread(RebaseThreadEntry, this)==NULL)\r
866         {\r
867                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
868                 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);\r
869                 SetControlEnable();\r
870         }\r
871 }\r
872 int CRebaseDlg::CheckNextCommitIsSquash()\r
873 {\r
874         int index;\r
875         if(m_CommitList.m_IsOldFirst)\r
876                 index=m_CurrentRebaseIndex+1;\r
877         else\r
878                 index=m_CurrentRebaseIndex-1;\r
879 \r
880         GitRev *curRev;\r
881         do\r
882         {\r
883                 if(index<0)\r
884                         return -1;\r
885                 if(index>= m_CommitList.GetItemCount())\r
886                         return -1;\r
887 \r
888                 curRev=(GitRev*)m_CommitList.m_arShownList[index];\r
889                 \r
890                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SQUASH )\r
891                         return 0;\r
892                 if( curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP)\r
893                 {\r
894                         if(m_CommitList.m_IsOldFirst)\r
895                                 index++;\r
896                         else\r
897                                 index--;\r
898                 }else\r
899                         return -1;              \r
900 \r
901         }while(curRev->m_Action&CTGitPath::LOGACTIONS_REBASE_SKIP);\r
902         \r
903         return -1;\r
904 \r
905 }\r
906 int CRebaseDlg::GoNext()\r
907 {\r
908         if(m_CommitList.m_IsOldFirst)\r
909                 m_CurrentRebaseIndex++;\r
910         else\r
911                 m_CurrentRebaseIndex--; \r
912         return 0;\r
913 \r
914 }\r
915 int CRebaseDlg::StateAction()\r
916 {\r
917         switch(this->m_RebaseStage)\r
918         {\r
919         case CHOOSE_BRANCH:\r
920         case CHOOSE_COMMIT_PICK_MODE:\r
921                 if(StartRebase())\r
922                         return -1;\r
923                 m_RebaseStage = REBASE_START;\r
924                 GoNext();\r
925                 break;\r
926         }\r
927 \r
928         return 0;       \r
929 }\r
930 void CRebaseDlg::SetContinueButtonText()\r
931 {\r
932         CString Text;\r
933         switch(this->m_RebaseStage)\r
934         {\r
935         case CHOOSE_BRANCH:\r
936         case CHOOSE_COMMIT_PICK_MODE:\r
937                 if(this->m_IsFastForward)\r
938                         Text = _T("Start(FastFwd)");\r
939                 else\r
940                         Text = _T("Start");\r
941                 break;\r
942 \r
943         case REBASE_START:\r
944         case REBASE_CONTINUE:\r
945         case REBASE_SQUASH_CONFLICT:\r
946                 Text = _T("Continue");\r
947                 break;\r
948 \r
949         case REBASE_CONFLICT:\r
950                 Text = _T("Commit");\r
951                 break;\r
952         case REBASE_EDIT:\r
953                 Text = _T("Amend");\r
954                 break;\r
955 \r
956         case REBASE_SQUASH_EDIT:\r
957                 Text = _T("Commit");\r
958                 break;\r
959 \r
960         case REBASE_ABORT:\r
961         case REBASE_FINISH:\r
962                 Text = _T("Finish");\r
963                 break;\r
964 \r
965         case REBASE_DONE:\r
966                 Text = _T("Done");\r
967                 break;\r
968         }\r
969         this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);\r
970 }\r
971 \r
972 void CRebaseDlg::SetControlEnable()\r
973 {\r
974         switch(this->m_RebaseStage)\r
975         {\r
976         case CHOOSE_BRANCH:\r
977         case CHOOSE_COMMIT_PICK_MODE:\r
978                 \r
979                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);\r
980                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);\r
981                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);\r
982                 if(!m_IsCherryPick)\r
983                 {\r
984                         this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);\r
985                         this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);\r
986                 }\r
987                 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;\r
988                 this->m_CommitList.m_ContextMenuMask |= m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
989                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
990                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
991                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP);\r
992                 break;\r
993 \r
994         case REBASE_START:\r
995         case REBASE_CONTINUE:\r
996         case REBASE_ABORT:\r
997         case REBASE_FINISH:\r
998         case REBASE_CONFLICT:\r
999         case REBASE_EDIT:\r
1000         case REBASE_SQUASH_CONFLICT:\r
1001         case REBASE_DONE:\r
1002                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);\r
1003                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);\r
1004                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);\r
1005                 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);\r
1006                 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);\r
1007                 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;\r
1008                 this->m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|\r
1009                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|\r
1010                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|\r
1011                                                                                                 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP));\r
1012 \r
1013                 if( m_RebaseStage == REBASE_DONE && (!this->m_PostButtonText.IsEmpty()) )\r
1014                 {\r
1015                         this->GetDlgItem(IDC_STATUS_STATIC)->ShowWindow(SW_HIDE);\r
1016                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->ShowWindow(SW_SHOWNORMAL);\r
1017                         this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);\r
1018                 }\r
1019                 break;\r
1020         }\r
1021 \r
1022         if(m_bThreadRunning)\r
1023         {\r
1024                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);\r
1025                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(FALSE);\r
1026 \r
1027         }else\r
1028         {\r
1029                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);\r
1030                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(TRUE);\r
1031         }\r
1032 }\r
1033 \r
1034 void CRebaseDlg::UpdateProgress()\r
1035 {\r
1036         int index;\r
1037         CRect rect;\r
1038 \r
1039         if(m_CommitList.m_IsOldFirst)\r
1040                 index = m_CurrentRebaseIndex+1;\r
1041         else\r
1042                 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1043 \r
1044         m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());\r
1045         m_ProgressBar.SetPos(index);\r
1046 \r
1047         if(m_CurrentRebaseIndex>=0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())\r
1048         {\r
1049                 CString text;\r
1050                 text.Format(_T("Rebasing...(%d/%d)"),index,m_CommitList.GetItemCount());\r
1051                 m_CtrlStatusText.SetWindowText(text);\r
1052 \r
1053         }\r
1054 \r
1055         GitRev *prevRev=NULL, *curRev=NULL;\r
1056 \r
1057         if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())\r
1058         {\r
1059                 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1060         }\r
1061         \r
1062         for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)\r
1063         {\r
1064                 prevRev=(GitRev*)m_CommitList.m_arShownList[i];\r
1065                 if(prevRev->m_Action & CTGitPath::LOGACTIONS_REBASE_CURRENT)\r
1066                 {       \r
1067                         prevRev->m_Action &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1068                         m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);\r
1069                         m_CommitList.InvalidateRect(rect);\r
1070                 }\r
1071         }\r
1072 \r
1073         if(curRev)\r
1074         {\r
1075                 curRev->m_Action |= CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
1076                 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);\r
1077                 m_CommitList.InvalidateRect(rect);\r
1078         }\r
1079         m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);\r
1080 \r
1081 }\r
1082 \r
1083 void CRebaseDlg::UpdateCurrentStatus()\r
1084 {\r
1085         if( m_CurrentRebaseIndex < 0 && m_RebaseStage!= REBASE_DONE)\r
1086         {\r
1087                 if(m_CommitList.m_IsOldFirst)\r
1088                         m_RebaseStage = CRebaseDlg::REBASE_START;\r
1089                 else\r
1090                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1091         }\r
1092 \r
1093         if( m_CurrentRebaseIndex == m_CommitList.m_arShownList.GetSize() && m_RebaseStage!= REBASE_DONE)\r
1094         {\r
1095                 if(m_CommitList.m_IsOldFirst)\r
1096                         m_RebaseStage = CRebaseDlg::REBASE_DONE;\r
1097                 else\r
1098                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
1099         }\r
1100 \r
1101         SetContinueButtonText();\r
1102         SetControlEnable();\r
1103         UpdateProgress();\r
1104 }\r
1105 \r
1106 void CRebaseDlg::AddLogString(CString str)\r
1107 {\r
1108         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);\r
1109         CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);\r
1110         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);\r
1111         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");\r
1112         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);\r
1113 }\r
1114 \r
1115 int CRebaseDlg::GetCurrentCommitID()\r
1116 {\r
1117         if(m_CommitList.m_IsOldFirst)\r
1118         {\r
1119                 return this->m_CurrentRebaseIndex+1;\r
1120 \r
1121         }else\r
1122         {\r
1123                 return m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
1124         }\r
1125 }\r
1126 \r
1127 int CRebaseDlg::DoRebase()\r
1128 {       \r
1129         CString cmd,out;\r
1130         if(m_CurrentRebaseIndex <0)\r
1131                 return 0;\r
1132         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1133                 return 0;\r
1134 \r
1135         GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1136         int mode=pRev->m_Action & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;\r
1137         CString nocommit;\r
1138 \r
1139         if( mode== CTGitPath::LOGACTIONS_REBASE_SKIP)\r
1140         {\r
1141                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1142                 return 0;\r
1143         }\r
1144         \r
1145         if( mode != CTGitPath::LOGACTIONS_REBASE_PICK )\r
1146         {\r
1147                 this->m_SquashMessage+= pRev->m_Subject;\r
1148                 this->m_SquashMessage+= _T("\n");\r
1149                 this->m_SquashMessage+= pRev->m_Body;\r
1150         }\r
1151         else\r
1152                 this->m_SquashMessage.Empty();\r
1153 \r
1154         if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1155                 nocommit=_T(" --no-commit ");\r
1156 \r
1157         CString log;\r
1158         log.Format(_T("%s %d:%s"),CTGitPath::GetActionName(mode),this->GetCurrentCommitID(),pRev->m_CommitHash);\r
1159         AddLogString(log);\r
1160         AddLogString(pRev->m_Subject);\r
1161         cmd.Format(_T("git.exe cherry-pick %s %s"),nocommit,pRev->m_CommitHash);\r
1162 \r
1163         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1164         {\r
1165                 AddLogString(out);\r
1166                 CTGitPathList list;\r
1167                 if(g_Git.ListConflictFile(list))\r
1168                 {\r
1169                         AddLogString(_T("Get conflict files fail"));\r
1170                         return -1;\r
1171                 }\r
1172                 if(list.GetCount() == 0 )\r
1173                 {\r
1174                         if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1175                         {\r
1176                                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1177                                 return 0;\r
1178                         }\r
1179                         if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1180                         {\r
1181                                 this->m_RebaseStage = REBASE_EDIT ;\r
1182                                 return -1; // Edit return -1 to stop rebase. \r
1183                         }\r
1184                         // Squash Case\r
1185                         if(CheckNextCommitIsSquash())\r
1186                         {   // no squash\r
1187                                 // let user edit last commmit message\r
1188                                 this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1189                                 return -1;\r
1190                         }\r
1191                 }\r
1192                 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)\r
1193                         m_RebaseStage = REBASE_SQUASH_CONFLICT;\r
1194                 else\r
1195                         m_RebaseStage = REBASE_CONFLICT;\r
1196                 return -1;      \r
1197 \r
1198         }else\r
1199         {\r
1200                 AddLogString(out);\r
1201                 if(mode ==  CTGitPath::LOGACTIONS_REBASE_PICK)\r
1202                 {\r
1203                         pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
1204                         return 0;\r
1205                 }\r
1206                 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)\r
1207                 {\r
1208                         this->m_RebaseStage = REBASE_EDIT ;\r
1209                         return -1; // Edit return -1 to stop rebase. \r
1210                 }\r
1211 \r
1212                 // Squash Case\r
1213                 if(CheckNextCommitIsSquash())\r
1214                 {   // no squash\r
1215                         // let user edit last commmit message\r
1216                         this->m_RebaseStage = REBASE_SQUASH_EDIT;\r
1217                         return -1;\r
1218                 }\r
1219         }\r
1220         \r
1221         return 0;\r
1222 }\r
1223 \r
1224 BOOL CRebaseDlg::IsEnd()\r
1225 {\r
1226         if(m_CommitList.m_IsOldFirst)\r
1227                 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();\r
1228         else\r
1229                 return m_CurrentRebaseIndex<0;\r
1230 }\r
1231 \r
1232 int CRebaseDlg::RebaseThread()\r
1233 {\r
1234         int ret=0;\r
1235         while(1)\r
1236         {\r
1237                 if( m_RebaseStage == REBASE_START )\r
1238                 {\r
1239                         if( this->StartRebase() )\r
1240                         {\r
1241                                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
1242                                 ret = -1;\r
1243                                 break;\r
1244                         }\r
1245                         m_RebaseStage = REBASE_CONTINUE;\r
1246 \r
1247                 }else if( m_RebaseStage == REBASE_CONTINUE )\r
1248                 {\r
1249                         this->GoNext(); \r
1250                         if(IsEnd())\r
1251                         {\r
1252                                 ret = 0;\r
1253                                 m_RebaseStage = REBASE_FINISH;\r
1254                                 \r
1255                         }else\r
1256                         {\r
1257                                 ret = DoRebase();\r
1258 \r
1259                                 if( ret )\r
1260                                 {       \r
1261                                         break;\r
1262                                 }\r
1263                         }\r
1264 \r
1265                 }else if( m_RebaseStage == REBASE_FINISH )\r
1266                 {                       \r
1267                         FinishRebase();\r
1268                         m_RebaseStage = REBASE_DONE;\r
1269                         break;\r
1270                         \r
1271                 }else\r
1272                 {\r
1273                         break;\r
1274                 }\r
1275                 this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1276                 //this->UpdateCurrentStatus();\r
1277         }\r
1278 \r
1279         InterlockedExchange(&m_bThreadRunning, FALSE);\r
1280         this->PostMessage(MSG_REBASE_UPDATE_UI);\r
1281         return ret;\r
1282 }\r
1283 \r
1284 void CRebaseDlg::ListConflictFile()\r
1285 {\r
1286         this->m_FileListCtrl.Clear();   \r
1287         CTGitPathList list;\r
1288         CTGitPath path;\r
1289         list.AddPath(path);\r
1290 \r
1291         this->m_FileListCtrl.GetStatus(&list,true);\r
1292         this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED|CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_DELETED,\r
1293                                                            CTGitPath::LOGACTIONS_UNMERGED);\r
1294         if( this->m_FileListCtrl.GetItemCount() == 0 )\r
1295         {\r
1296                 \r
1297         }\r
1298 }\r
1299 \r
1300 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)\r
1301 {\r
1302         UpdateCurrentStatus();\r
1303         if(m_CurrentRebaseIndex <0)\r
1304                 return 0;\r
1305         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
1306                 return 0;\r
1307         GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
1308         \r
1309         switch(m_RebaseStage)\r
1310         {\r
1311         case REBASE_CONFLICT:\r
1312         case REBASE_SQUASH_CONFLICT:\r
1313                 ListConflictFile();                     \r
1314                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);\r
1315                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1316                 break;\r
1317         case REBASE_EDIT:\r
1318                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1319                 this->m_LogMessageCtrl.SetText(curRev->m_Subject+_T("\n")+curRev->m_Body);\r
1320                 break;\r
1321         case REBASE_SQUASH_EDIT:\r
1322                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);\r
1323                 this->m_LogMessageCtrl.SetText(this->m_SquashMessage);\r
1324                 break;\r
1325         default:\r
1326                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
1327         }       \r
1328         return 0;\r
1329 }\r
1330 void CRebaseDlg::OnCancel()\r
1331 {\r
1332         OnBnClickedAbort();\r
1333 }\r
1334 void CRebaseDlg::OnBnClickedAbort()\r
1335 {\r
1336         CString cmd,out;\r
1337         if(m_OrigUpstreamHash.IsEmpty())\r
1338         {\r
1339                 __super::OnCancel();\r
1340         }\r
1341         \r
1342         if(m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage== CHOOSE_COMMIT_PICK_MODE)\r
1343         {\r
1344                 return;\r
1345         }\r
1346 \r
1347         if(CMessageBox::Show(NULL,_T("Are you sure you want to abort the rebase process?"),_T("TortoiseGit"),MB_YESNO) != IDYES)\r
1348                 return;\r
1349 \r
1350         if(this->m_IsFastForward)\r
1351         {\r
1352                 cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1353                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
1354                 {\r
1355                         AddLogString(out);\r
1356                         return ;\r
1357                 }\r
1358                 __super::OnCancel();\r
1359                 return;\r
1360         }\r
1361         cmd.Format(_T("git.exe checkout -f %s"),this->m_UpstreamCtrl.GetString());\r
1362         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1363         {\r
1364                 AddLogString(out);\r
1365                 return ;\r
1366         }\r
1367 \r
1368         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigUpstreamHash.Left(40));\r
1369         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1370         {\r
1371                 AddLogString(out);\r
1372                 return ;\r
1373         }\r
1374         \r
1375         if(this->m_IsCherryPick) //there are not "branch" at cherry pick mode\r
1376                 return;\r
1377 \r
1378         cmd.Format(_T("git checkout -f %s"),this->m_BranchCtrl.GetString());\r
1379         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1380         {\r
1381                 AddLogString(out);\r
1382                 return ;\r
1383         }\r
1384         \r
1385         cmd.Format(_T("git.exe reset --hard  %s"),this->m_OrigBranchHash.Left(40));\r
1386         if(g_Git.Run(cmd,&out,CP_UTF8))\r
1387         {\r
1388                 AddLogString(out);\r
1389                 return ;\r
1390         }\r
1391         __super::OnCancel();\r
1392 }\r
1393 \r
1394 void CRebaseDlg::OnBnClickedButtonBrowse()\r
1395 {\r
1396         if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl, gPickRef_NoTag))\r
1397                 OnCbnSelchangeUpstream();\r
1398 }\r
1399 \r
1400 void CRebaseDlg::OnBnClickedRebaseCheckForce()\r
1401 {\r
1402         // TODO: Add your control notification handler code here\r
1403         this->UpdateData();\r
1404         this->FetchLogList();\r
1405 }\r
1406 \r
1407 void CRebaseDlg::OnStnClickedStatusStatic()\r
1408 {\r
1409         // TODO: Add your control notification handler code here\r
1410 }\r
1411 \r
1412 void CRebaseDlg::OnBnClickedRebasePostButton()\r
1413 {\r
1414         // TODO: Add your control notification handler code here\r
1415         this->m_Upstream=this->m_UpstreamCtrl.GetString();\r
1416         this->m_Branch=this->m_BranchCtrl.GetString();\r
1417 \r
1418         this->EndDialog(IDC_REBASE_POST_BUTTON);\r
1419 }\r