OSDN Git Service

RebaseDlg: Pick Basic Working
[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 // CRebaseDlg dialog\r
11 \r
12 IMPLEMENT_DYNAMIC(CRebaseDlg, CResizableStandAloneDialog)\r
13 \r
14 CRebaseDlg::CRebaseDlg(CWnd* pParent /*=NULL*/)\r
15         : CResizableStandAloneDialog(CRebaseDlg::IDD, pParent)\r
16     , m_bPickAll(FALSE)\r
17     , m_bSquashAll(FALSE)\r
18     , m_bEditAll(FALSE)\r
19 {\r
20         m_RebaseStage=CHOOSE_BRANCH;\r
21         m_CurrentRebaseIndex=-1;\r
22         m_bThreadRunning =FALSE;\r
23 }\r
24 \r
25 CRebaseDlg::~CRebaseDlg()\r
26 {\r
27 }\r
28 \r
29 void CRebaseDlg::DoDataExchange(CDataExchange* pDX)\r
30 {\r
31     CDialog::DoDataExchange(pDX);\r
32     DDX_Control(pDX, IDC_REBASE_PROGRESS, m_ProgressBar);\r
33     DDX_Control(pDX, IDC_STATUS_STATIC, m_CtrlStatusText);\r
34     DDX_Check(pDX, IDC_PICK_ALL, m_bPickAll);\r
35     DDX_Check(pDX, IDC_SQUASH_ALL, m_bSquashAll);\r
36     DDX_Check(pDX, IDC_EDIT_ALL, m_bEditAll);\r
37         DDX_Control(pDX, IDC_REBASE_SPLIT, m_wndSplitter);\r
38         DDX_Control(pDX,IDC_COMMIT_LIST,m_CommitList);\r
39         DDX_Control(pDX,IDC_REBASE_COMBOXEX_BRANCH, this->m_BranchCtrl);\r
40         DDX_Control(pDX,IDC_REBASE_COMBOXEX_UPSTREAM,   this->m_UpstreamCtrl);\r
41 \r
42 }\r
43 \r
44 \r
45 BEGIN_MESSAGE_MAP(CRebaseDlg, CResizableStandAloneDialog)\r
46     ON_BN_CLICKED(IDC_PICK_ALL, &CRebaseDlg::OnBnClickedPickAll)\r
47     ON_BN_CLICKED(IDC_SQUASH_ALL, &CRebaseDlg::OnBnClickedSquashAll)\r
48     ON_BN_CLICKED(IDC_EDIT_ALL, &CRebaseDlg::OnBnClickedEditAll)\r
49     ON_BN_CLICKED(IDC_REBASE_SPLIT, &CRebaseDlg::OnBnClickedRebaseSplit)\r
50         ON_BN_CLICKED(IDC_REBASE_CONTINUE,OnBnClickedContinue)\r
51         ON_WM_SIZE()\r
52         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH,   &CRebaseDlg::OnCbnSelchangeBranch)\r
53         ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM, &CRebaseDlg::OnCbnSelchangeUpstream)\r
54         ON_MESSAGE(MSG_REBASE_UPDATE_UI, OnRebaseUpdateUI)\r
55 END_MESSAGE_MAP()\r
56 \r
57 void CRebaseDlg::AddRebaseAnchor()\r
58 {\r
59         AddAnchor(IDC_REBASE_TAB,TOP_LEFT,BOTTOM_RIGHT);\r
60         AddAnchor(IDC_COMMIT_LIST,TOP_LEFT, TOP_RIGHT);\r
61         AddAnchor(IDC_REBASE_SPLIT,TOP_LEFT, TOP_RIGHT);\r
62         AddAnchor(IDC_STATUS_STATIC, BOTTOM_LEFT,BOTTOM_RIGHT);\r
63         AddAnchor(IDC_REBASE_CONTINUE,BOTTOM_RIGHT);\r
64         AddAnchor(IDC_REBASE_ABORT, BOTTOM_RIGHT);\r
65         AddAnchor(IDC_REBASE_PROGRESS,BOTTOM_LEFT, BOTTOM_RIGHT);\r
66         AddAnchor(IDC_PICK_ALL,TOP_LEFT);\r
67         AddAnchor(IDC_SQUASH_ALL,TOP_LEFT);\r
68         AddAnchor(IDC_EDIT_ALL,TOP_LEFT);       \r
69         AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM,TOP_LEFT);\r
70         AddAnchor(IDC_REBASE_COMBOXEX_BRANCH,TOP_LEFT);\r
71         AddAnchor(IDC_REBASE_STATIC_UPSTREAM,TOP_LEFT);\r
72         AddAnchor(IDC_REBASE_STATIC_BRANCH,TOP_LEFT);\r
73         \r
74 }\r
75 \r
76 BOOL CRebaseDlg::OnInitDialog()\r
77 {\r
78         CResizableStandAloneDialog::OnInitDialog();\r
79 \r
80         CRect rectDummy;\r
81         //IDC_REBASE_DUMY_TAB\r
82         \r
83         GetClientRect(m_DlgOrigRect);\r
84         m_CommitList.GetClientRect(m_CommitListOrigRect);\r
85 \r
86         CWnd *pwnd=this->GetDlgItem(IDC_REBASE_DUMY_TAB);\r
87         pwnd->GetWindowRect(&rectDummy);\r
88 \r
89         rectDummy.top-=20;\r
90         rectDummy.bottom-=20;\r
91 \r
92         rectDummy.left-=5;\r
93         rectDummy.right-=5;\r
94         \r
95         if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_REBASE_TAB))\r
96         {\r
97                 TRACE0("Failed to create output tab window\n");\r
98                 return FALSE;      // fail to create\r
99         }\r
100         m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);\r
101         // Create output panes:\r
102         //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
103         DWORD dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP |LVS_SINGLESEL |WS_CHILD | WS_VISIBLE;\r
104 \r
105         if (! this->m_FileListCtrl.Create(dwStyle,rectDummy,&this->m_ctrlTabCtrl,0) )\r
106         {\r
107                 TRACE0("Failed to create output windows\n");\r
108                 return FALSE;      // fail to create\r
109         }\r
110 \r
111         if( ! this->m_LogMessageCtrl.Create(_T("Scintilla"),_T("source"),0,rectDummy,&m_ctrlTabCtrl,0,0) )\r
112         {\r
113                 TRACE0("Failed to create log message control");\r
114                 return FALSE;\r
115         }\r
116         m_LogMessageCtrl.Init(0);\r
117 \r
118         dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;\r
119 \r
120         if (!m_wndOutputRebase.Create(_T("Scintilla"),_T("source"),0,rectDummy, &m_ctrlTabCtrl, 0,0) )\r
121         {\r
122                 TRACE0("Failed to create output windows\n");\r
123                 return -1;      // fail to create\r
124         }\r
125         m_wndOutputRebase.Init(0);\r
126         m_wndOutputRebase.Call(SCI_SETREADONLY, TRUE);\r
127         \r
128         m_tooltips.Create(this);\r
129 \r
130         m_FileListCtrl.Init(SVNSLC_COLEXT | SVNSLC_COLSTATUS |IDS_STATUSLIST_COLADD|IDS_STATUSLIST_COLDEL , _T("RebaseDlg"),(SVNSLC_POPALL ^ SVNSLC_POPCOMMIT),false);\r
131 \r
132         m_ctrlTabCtrl.AddTab(&m_FileListCtrl,_T("Conflict File"));\r
133         m_ctrlTabCtrl.AddTab(&m_LogMessageCtrl,_T("Commit Message"),1);\r
134         m_ctrlTabCtrl.AddTab(&m_wndOutputRebase,_T("Log"),2);\r
135         AddRebaseAnchor();\r
136 \r
137 \r
138         EnableSaveRestore(_T("RebaseDlg"));\r
139 \r
140         DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
141         RECT rcDlg, rcLogMsg, rcFileList;\r
142         GetClientRect(&rcDlg);\r
143         m_CommitList.GetWindowRect(&rcLogMsg);\r
144         ScreenToClient(&rcLogMsg);\r
145         this->m_ctrlTabCtrl.GetWindowRect(&rcFileList);\r
146         ScreenToClient(&rcFileList);\r
147         if (yPos)\r
148         {\r
149                 RECT rectSplitter;\r
150                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
151                 ScreenToClient(&rectSplitter);\r
152                 int delta = yPos - rectSplitter.top;\r
153                 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))\r
154                 {\r
155                         m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);\r
156                         DoSize(delta);\r
157                 }\r
158         }\r
159 \r
160         if( this->m_RebaseStage == CHOOSE_BRANCH)\r
161         {\r
162                 this->LoadBranchInfo();\r
163 \r
164         }else\r
165         {\r
166                 this->m_BranchCtrl.EnableWindow(FALSE);\r
167                 this->m_UpstreamCtrl.EnableWindow(FALSE);\r
168         }\r
169 \r
170         m_CommitList.m_IsIDReplaceAction = TRUE;\r
171 //      m_CommitList.m_IsOldFirst = TRUE;\r
172         m_CommitList.m_IsRebaseReplaceGraph = TRUE;\r
173 \r
174         m_CommitList.DeleteAllItems();\r
175         m_CommitList.InsertGitColumn();\r
176 \r
177         FetchLogList();\r
178         SetContinueButtonText();\r
179         return TRUE;\r
180 }\r
181 // CRebaseDlg message handlers\r
182 \r
183 void CRebaseDlg::OnBnClickedPickAll()\r
184 {\r
185     // TODO: Add your control notification handler code here\r
186         this->UpdateData();\r
187         if(this->m_bPickAll)\r
188                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK);\r
189 \r
190         this->m_bEditAll=FALSE;\r
191         this->m_bSquashAll=FALSE;\r
192         this->UpdateData(FALSE);\r
193         \r
194 }\r
195 \r
196 void CRebaseDlg::OnBnClickedSquashAll()\r
197 {\r
198     // TODO: Add your control notification handler code here\r
199         this->UpdateData();\r
200         if(this->m_bSquashAll)\r
201                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);\r
202 \r
203         this->m_bEditAll=FALSE;\r
204         this->m_bPickAll=FALSE;\r
205         this->UpdateData(FALSE);\r
206 \r
207 }\r
208 \r
209 void CRebaseDlg::OnBnClickedEditAll()\r
210 {\r
211     // TODO: Add your control notification handler code here\r
212         this->UpdateData();\r
213         if( this->m_bEditAll )\r
214                 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT);\r
215 \r
216         this->m_bPickAll=FALSE;\r
217         this->m_bSquashAll=FALSE;\r
218         this->UpdateData(FALSE);\r
219 \r
220 }\r
221 \r
222 void CRebaseDlg::SetAllRebaseAction(int action)\r
223 {\r
224         for(int i=0;i<this->m_CommitList.m_logEntries.size();i++)\r
225         {\r
226                 m_CommitList.m_logEntries[i].m_Action=action;\r
227         }\r
228         m_CommitList.Invalidate();\r
229 }\r
230 \r
231 void CRebaseDlg::OnBnClickedRebaseSplit()\r
232 {\r
233         this->UpdateData();\r
234     // TODO: Add your control notification handler code here\r
235 }\r
236 \r
237 LRESULT CRebaseDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)\r
238 {\r
239         switch (message) {\r
240         case WM_NOTIFY:\r
241                 if (wParam == IDC_REBASE_SPLIT)\r
242                 { \r
243                         SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;\r
244                         DoSize(pHdr->delta);\r
245                 }\r
246                 break;\r
247         }\r
248 \r
249         return __super::DefWindowProc(message, wParam, lParam);\r
250 }\r
251 \r
252 void CRebaseDlg::DoSize(int delta)\r
253 {\r
254         \r
255         this->RemoveAllAnchors();\r
256 \r
257         CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST), delta, CW_TOPALIGN);\r
258         //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);\r
259         CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB), -delta, CW_BOTTOMALIGN);\r
260         //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);\r
261         CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL),0,delta);\r
262         CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL),0,delta);\r
263         CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL),0,delta);\r
264         \r
265         this->AddRebaseAnchor();\r
266         // adjust the minimum size of the dialog to prevent the resizing from\r
267         // moving the list control too far down.\r
268         CRect rcLogMsg;\r
269         m_CommitList.GetClientRect(rcLogMsg);\r
270         SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));\r
271 \r
272         SetSplitterRange();\r
273 //      m_CommitList.Invalidate();\r
274 \r
275 //      GetDlgItem(IDC_LOGMESSAGE)->Invalidate();\r
276 \r
277         this->m_ctrlTabCtrl.Invalidate();\r
278         this->m_CommitList.Invalidate();\r
279         this->m_FileListCtrl.Invalidate();\r
280         this->m_LogMessageCtrl.Invalidate();\r
281 \r
282 }\r
283 \r
284 void CRebaseDlg::SetSplitterRange()\r
285 {\r
286         if ((m_CommitList)&&(m_ctrlTabCtrl))\r
287         {\r
288                 CRect rcTop;\r
289                 m_CommitList.GetWindowRect(rcTop);\r
290                 ScreenToClient(rcTop);\r
291                 CRect rcMiddle;\r
292                 m_ctrlTabCtrl.GetWindowRect(rcMiddle);\r
293                 ScreenToClient(rcMiddle);\r
294                 if (rcMiddle.Height() && rcMiddle.Width())\r
295                         m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);\r
296         }\r
297 }\r
298 \r
299 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)\r
300 {\r
301          // first, let the resizing take place\r
302     __super::OnSize(nType, cx, cy);\r
303 \r
304     //set range\r
305     SetSplitterRange();\r
306 }\r
307 \r
308 void CRebaseDlg::SaveSplitterPos()\r
309 {\r
310         if (!IsIconic())\r
311         {\r
312                 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));\r
313                 RECT rectSplitter;\r
314                 m_wndSplitter.GetWindowRect(&rectSplitter);\r
315                 ScreenToClient(&rectSplitter);\r
316                 regPos = rectSplitter.top;\r
317         }\r
318 }\r
319 \r
320 void CRebaseDlg::LoadBranchInfo()\r
321 {\r
322         m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
323         m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);\r
324 \r
325         STRING_VECTOR list;\r
326         list.clear();\r
327         int current;\r
328         g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);\r
329         m_BranchCtrl.AddString(list);\r
330         m_UpstreamCtrl.AddString(list);\r
331 \r
332         m_BranchCtrl.SetCurSel(current);\r
333 \r
334         AddBranchToolTips(&m_BranchCtrl);\r
335         AddBranchToolTips(&m_UpstreamCtrl);\r
336 \r
337 }\r
338 \r
339 void CRebaseDlg::OnCbnSelchangeBranch()\r
340 {\r
341         FetchLogList();\r
342 }\r
343 \r
344 void CRebaseDlg::OnCbnSelchangeUpstream()\r
345 {\r
346         FetchLogList();\r
347 }\r
348 \r
349 void CRebaseDlg::FetchLogList()\r
350 {\r
351         m_CommitList.Clear();\r
352         this->m_CommitList.FillGitLog(NULL,0,&m_UpstreamCtrl.GetString(),&m_BranchCtrl.GetString());\r
353         if( m_CommitList.GetItemCount() == 0 )\r
354                 m_CommitList.ShowText(_T("Nothing Rebase"));\r
355 \r
356         CString hash=g_Git.GetHash(m_UpstreamCtrl.GetString());\r
357         \r
358 #if 0\r
359         if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )\r
360         {\r
361                 if(hash ==  m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])\r
362                 {\r
363                         m_CommitList.Clear();\r
364                         m_CommitList.ShowText(_T("Nothing Rebase"));\r
365                 }\r
366         }\r
367 #endif\r
368 \r
369         m_tooltips.Pop();\r
370         AddBranchToolTips(&this->m_BranchCtrl);\r
371         AddBranchToolTips(&this->m_UpstreamCtrl);\r
372         \r
373         for(int i=0;i<m_CommitList.m_logEntries.size();i++)\r
374         {\r
375                 m_CommitList.m_logEntries[i].m_Action = CTGitPath::LOGACTIONS_REBASE_PICK;\r
376         }\r
377         \r
378         m_CommitList.Invalidate();\r
379 \r
380         if(m_CommitList.m_IsOldFirst)\r
381                 this->m_CurrentRebaseIndex = -1;\r
382         else\r
383                 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();\r
384         \r
385 }\r
386 \r
387 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)\r
388 {\r
389         if(pBranch)\r
390         {\r
391                 CString text=pBranch->GetString();\r
392                 CString tooltip;\r
393                 BYTE_VECTOR data;\r
394                 g_Git.GetLog(data,text,NULL,1,0);\r
395                 GitRev rev;\r
396                 rev.ParserFromLog(data);\r
397                 tooltip.Format(_T("CommitHash:%s\nCommit by: %s  %s\n <b>%s</b> \n %s"),\r
398                         rev.m_CommitHash,\r
399                         rev.m_AuthorName,\r
400                         CAppUtils::FormatDateAndTime(rev.m_AuthorDate,DATE_LONGDATE),\r
401                         rev.m_Subject,\r
402                         rev.m_Body);\r
403 \r
404                 pBranch->DisableTooltip();\r
405                 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);\r
406         }\r
407 }\r
408 \r
409 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)\r
410 {\r
411         m_tooltips.RelayEvent(pMsg);\r
412         return CResizableStandAloneDialog::PreTranslateMessage(pMsg);\r
413 }\r
414 int CRebaseDlg::CheckRebaseCondition()\r
415 {\r
416         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
417 \r
418         if( !g_Git.CheckCleanWorkTree()  )\r
419         {\r
420                 CMessageBox::Show(NULL,_T("Rebase Need Clean Working Tree"),_T("TortoiseGit"),MB_OK);\r
421                 return -1;\r
422         }\r
423         //Todo Check $REBASE_ROOT\r
424         //Todo Check $DOTEST\r
425 \r
426         CString cmd;\r
427         cmd=_T("git.exe var GIT_COMMITTER_IDENT");\r
428         if(g_Git.Run(cmd,NULL,CP_UTF8))\r
429                 return -1;\r
430 \r
431         //Todo call pre_rebase_hook\r
432 }\r
433 int CRebaseDlg::StartRebase()\r
434 {\r
435         CString cmd,out;\r
436         //Todo call comment_for_reflog\r
437         cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());\r
438         this->AddLogString(cmd);\r
439 \r
440         if(g_Git.Run(cmd,&out,CP_UTF8))\r
441                 return -1;\r
442 \r
443         this->AddLogString(out);\r
444 \r
445         cmd=_T("git.exe rev-parse --verify HEAD");\r
446         if(g_Git.Run(cmd,&out,CP_UTF8))\r
447         {\r
448                 AddLogString(_T("No Head"));\r
449                 return -1;\r
450         }\r
451         //Todo \r
452         //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||\r
453         //              echo "detached HEAD" > "$DOTEST"/head-name\r
454 \r
455         cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));\r
456         if(g_Git.Run(cmd,&out,CP_UTF8))\r
457         {\r
458                 AddLogString(_T("update ORIG_HEAD Fail"));\r
459                 return -1;\r
460         }\r
461         \r
462         cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));\r
463 \r
464         cmd.Format(_T("git.exe checkout %s"),this->m_UpstreamCtrl.GetString());\r
465         this->AddLogString(cmd);\r
466 \r
467         out.Empty();\r
468         if(g_Git.Run(cmd,&out,CP_UTF8))\r
469         {\r
470                 return -1;\r
471         }\r
472 \r
473         this->AddLogString(_T("Start Rebase\r\n"));\r
474         return 0;\r
475 }\r
476 void CRebaseDlg::OnBnClickedContinue()\r
477 {\r
478         if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )\r
479         {\r
480                 if(CheckRebaseCondition())\r
481                         return ;\r
482                 m_RebaseStage = REBASE_START;\r
483         }\r
484 \r
485         if( m_RebaseStage == REBASE_CONFLICT )\r
486         {\r
487                 CTGitPathList list;\r
488                 if(g_Git.ListConflictFile(list))\r
489                 {\r
490                         AddLogString(_T("Get conflict files fail"));\r
491                         return ;\r
492                 }\r
493                 if( list.GetCount() != 0 )\r
494                 {\r
495                         CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);\r
496                         return;\r
497                 }\r
498 \r
499                 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
500 \r
501                 CString out =_T("");\r
502                 CString cmd;\r
503                 cmd.Format(_T("git.exe commit -C \"%s\""), curRev->m_CommitHash);\r
504                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
505                 {\r
506                         if(!g_Git.CheckCleanWorkTree())\r
507                         {\r
508                                 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);\r
509                                 return;\r
510                         }\r
511                 }\r
512                 AddLogString(out);\r
513                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
514                 m_RebaseStage=REBASE_CONTINUE;\r
515                 curRev->m_Action|=CTGitPath::LOGACTIONS_REBASE_DONE;\r
516                 this->UpdateCurrentStatus();\r
517         }\r
518 \r
519         InterlockedExchange(&m_bThreadRunning, TRUE);\r
520         SetControlEnable();\r
521         \r
522         if (AfxBeginThread(RebaseThreadEntry, this)==NULL)\r
523         {\r
524                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
525                 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);\r
526                 SetControlEnable();\r
527         }\r
528 }\r
529 int CRebaseDlg::GoNext()\r
530 {\r
531         if(m_CommitList.m_IsOldFirst)\r
532                 m_CurrentRebaseIndex++;\r
533         else\r
534                 m_CurrentRebaseIndex--; \r
535         return 0;\r
536 \r
537 }\r
538 int CRebaseDlg::StateAction()\r
539 {\r
540         switch(this->m_RebaseStage)\r
541         {\r
542         case CHOOSE_BRANCH:\r
543         case CHOOSE_COMMIT_PICK_MODE:\r
544                 if(StartRebase())\r
545                         return -1;\r
546                 m_RebaseStage = REBASE_START;\r
547                 GoNext();\r
548                 break;\r
549         }\r
550 \r
551         return 0;       \r
552 }\r
553 void CRebaseDlg::SetContinueButtonText()\r
554 {\r
555         CString Text;\r
556         switch(this->m_RebaseStage)\r
557         {\r
558         case CHOOSE_BRANCH:\r
559         case CHOOSE_COMMIT_PICK_MODE:\r
560                 Text = _T("Start");\r
561                 break;\r
562 \r
563         case REBASE_START:\r
564         case REBASE_CONTINUE:\r
565                 Text = _T("Continue");\r
566                 break;\r
567 \r
568         case REBASE_CONFLICT:\r
569                 Text = _T("Commit");\r
570                 break;\r
571 \r
572         case REBASE_ABORT:\r
573         case REBASE_FINISH:\r
574                 Text = _T("Finish");\r
575                 break;\r
576         }\r
577         this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);\r
578 }\r
579 \r
580 void CRebaseDlg::SetControlEnable()\r
581 {\r
582         switch(this->m_RebaseStage)\r
583         {\r
584         case CHOOSE_BRANCH:\r
585         case CHOOSE_COMMIT_PICK_MODE:\r
586                 \r
587                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);\r
588                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);\r
589                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);\r
590                 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);\r
591                 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);\r
592                 this->m_CommitList.m_IsEnableRebaseMenu=TRUE;\r
593                 break;\r
594 \r
595         case REBASE_START:\r
596         case REBASE_CONTINUE:\r
597         case REBASE_ABORT:\r
598         case REBASE_FINISH:\r
599         case REBASE_CONFLICT:\r
600                 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);\r
601                 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);\r
602                 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);\r
603                 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);\r
604                 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);\r
605                 this->m_CommitList.m_IsEnableRebaseMenu=FALSE;\r
606                 break;\r
607         }\r
608 \r
609         if(m_bThreadRunning)\r
610         {\r
611                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);\r
612                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(FALSE);\r
613 \r
614         }else\r
615         {\r
616                 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);\r
617                 this->GetDlgItem(IDC_REBASE_ABORT)->EnableWindow(TRUE);\r
618         }\r
619 }\r
620 \r
621 void CRebaseDlg::UpdateProgress()\r
622 {\r
623         int index;\r
624         CRect rect;\r
625 \r
626         if(m_CommitList.m_IsOldFirst)\r
627                 index = m_CurrentRebaseIndex+1;\r
628         else\r
629                 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;\r
630 \r
631         m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());\r
632         m_ProgressBar.SetPos(index);\r
633 \r
634         if(m_CurrentRebaseIndex>0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())\r
635         {\r
636                 CString text;\r
637                 text.Format(_T("Rebasing...(%d/%d)"),index,m_CommitList.GetItemCount());\r
638                 m_CtrlStatusText.SetWindowText(text);\r
639 \r
640         }\r
641 \r
642         GitRev *prevRev=NULL, *curRev=NULL;\r
643         int prevIndex;\r
644 \r
645         if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())\r
646         {\r
647                 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
648         }\r
649         \r
650         for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)\r
651         {\r
652                 prevRev=(GitRev*)m_CommitList.m_arShownList[i];\r
653                 if(prevRev->m_Action & CTGitPath::LOGACTIONS_REBASE_CURRENT)\r
654                 {       \r
655                         prevRev->m_Action &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
656                         m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);\r
657                         m_CommitList.InvalidateRect(rect);\r
658                 }\r
659         }\r
660 \r
661         if(curRev)\r
662         {\r
663                 curRev->m_Action |= CTGitPath::LOGACTIONS_REBASE_CURRENT;\r
664                 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);\r
665                 m_CommitList.InvalidateRect(rect);\r
666         }\r
667         m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);\r
668 \r
669 }\r
670 \r
671 void CRebaseDlg::UpdateCurrentStatus()\r
672 {\r
673         if( m_CurrentRebaseIndex < 0)\r
674         {\r
675                 if(m_CommitList.m_IsOldFirst)\r
676                         m_RebaseStage = CRebaseDlg::REBASE_START;\r
677                 else\r
678                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
679         }\r
680 \r
681         if( m_CurrentRebaseIndex == m_CommitList.m_arShownList.GetSize())\r
682         {\r
683                 if(m_CommitList.m_IsOldFirst)\r
684                         m_RebaseStage = CRebaseDlg::REBASE_FINISH;\r
685                 else\r
686                         m_RebaseStage = CRebaseDlg::REBASE_START;\r
687         }\r
688 \r
689         SetContinueButtonText();\r
690         SetControlEnable();\r
691         UpdateProgress();\r
692 }\r
693 \r
694 void CRebaseDlg::AddLogString(CString str)\r
695 {\r
696         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);\r
697         CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);\r
698         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);\r
699         this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");\r
700         this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);\r
701 }\r
702 \r
703 int CRebaseDlg::DoRebase()\r
704 {       \r
705         CString cmd,out;\r
706         if(m_CurrentRebaseIndex <0)\r
707                 return 0;\r
708         if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )\r
709                 return 0;\r
710 \r
711         this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
712 \r
713         GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];\r
714         int mode=pRev->m_Action & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;\r
715         switch(mode)\r
716         {\r
717         case CTGitPath::LOGACTIONS_REBASE_PICK:\r
718                 AddLogString(CString(_T("Pick "))+pRev->m_CommitHash);\r
719                 AddLogString(pRev->m_Subject);\r
720                 cmd.Format(_T("git.exe cherry-pick %s"),pRev->m_CommitHash);\r
721                 if(g_Git.Run(cmd,&out,CP_UTF8))\r
722                 {\r
723                         AddLogString(out);\r
724                         CTGitPathList list;\r
725                         if(g_Git.ListConflictFile(list))\r
726                         {\r
727                                 AddLogString(_T("Get conflict files fail"));\r
728                                 return -1;\r
729                         }\r
730                         if(list.GetCount() == 0 )\r
731                         {\r
732                                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
733                                 break;\r
734                         }\r
735 \r
736                         this->m_RebaseStage = REBASE_CONFLICT;\r
737                         return -1;      \r
738                 }else\r
739                 {\r
740                         AddLogString(out);\r
741                         pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
742                 }\r
743                 break;\r
744         case CTGitPath::LOGACTIONS_REBASE_SQUASH:\r
745                 break;\r
746         case CTGitPath::LOGACTIONS_REBASE_EDIT:\r
747                 break;\r
748         case CTGitPath::LOGACTIONS_REBASE_SKIP:\r
749                 pRev->m_Action|= CTGitPath::LOGACTIONS_REBASE_DONE;\r
750                 return 0;\r
751                 break;\r
752         default:\r
753                 AddLogString(CString(_T("Unknow Action for "))+pRev->m_CommitHash);\r
754                 break;\r
755         }\r
756         return 0;\r
757 }\r
758 \r
759 BOOL CRebaseDlg::IsEnd()\r
760 {\r
761         if(m_CommitList.m_IsOldFirst)\r
762                 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();\r
763         else\r
764                 return m_CurrentRebaseIndex<0;\r
765 }\r
766 \r
767 int CRebaseDlg::RebaseThread()\r
768 {\r
769         int ret=0;\r
770         while(1)\r
771         {\r
772                 if( m_RebaseStage == REBASE_START )\r
773                 {\r
774                         if( this->StartRebase() )\r
775                         {\r
776                                 InterlockedExchange(&m_bThreadRunning, FALSE);\r
777                                 ret = -1;\r
778                                 break;\r
779                         }\r
780                         m_RebaseStage = REBASE_CONTINUE;\r
781 \r
782                 }else if( m_RebaseStage == REBASE_CONTINUE )\r
783                 {\r
784                         this->GoNext(); \r
785                         if(IsEnd())\r
786                         {\r
787                                 ret = 0;\r
788                                 m_RebaseStage = REBASE_FINISH;\r
789                                 break;\r
790                         }\r
791 \r
792                         ret = DoRebase();\r
793 \r
794                         if( ret )\r
795                         {       \r
796                                 break;\r
797                         }\r
798 \r
799                 }else\r
800                         break;\r
801                 this->PostMessage(MSG_REBASE_UPDATE_UI);\r
802                 //this->UpdateCurrentStatus();\r
803         }\r
804 \r
805         InterlockedExchange(&m_bThreadRunning, FALSE);\r
806         this->PostMessage(MSG_REBASE_UPDATE_UI);\r
807         return ret;\r
808 }\r
809 \r
810 void CRebaseDlg::ListConflictFile()\r
811 {\r
812         this->m_FileListCtrl.Clear();   \r
813         CTGitPathList list;\r
814         CTGitPath path;\r
815         list.AddPath(path);\r
816 \r
817         this->m_FileListCtrl.GetStatus(list,true);\r
818         this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED,CTGitPath::LOGACTIONS_UNMERGED);\r
819         if( this->m_FileListCtrl.GetItemCount() == 0 )\r
820         {\r
821                 \r
822         }\r
823 }\r
824 \r
825 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)\r
826 {\r
827         UpdateCurrentStatus();\r
828         switch(m_RebaseStage)\r
829         {\r
830         case REBASE_CONFLICT:\r
831                 ListConflictFile();                     \r
832                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);\r
833                 break;\r
834         default:\r
835                 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);\r
836         }       \r
837         return 0;\r
838 }