OSDN Git Service

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