added new log filter (for subject)
[TortoiseGit.git] / src / TortoiseProc / RebaseDlg.cpp
blob5ae6cb84ec95f9130639d2020892926f7cac08ec
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - TortoiseGit
4 // Copyright (C) 2011 - Sven Strickroth <email@cs-ware.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 // RebaseDlg.cpp : implementation file
24 #include "stdafx.h"
25 #include "TortoiseProc.h"
26 #include "RebaseDlg.h"
27 #include "AppUtils.h"
28 #include "MessageBox.h"
29 #include "UnicodeUtils.h"
30 #include "BrowseRefsDlg.h"
31 #include "ProgressDlg.h"
32 // CRebaseDlg dialog
34 IMPLEMENT_DYNAMIC(CRebaseDlg, CResizableStandAloneDialog)
36 CRebaseDlg::CRebaseDlg(CWnd* pParent /*=NULL*/)
37 : CResizableStandAloneDialog(CRebaseDlg::IDD, pParent)
38 , m_bPickAll(FALSE)
39 , m_bSquashAll(FALSE)
40 , m_bEditAll(FALSE)
42 m_RebaseStage=CHOOSE_BRANCH;
43 m_CurrentRebaseIndex=-1;
44 m_bThreadRunning =FALSE;
45 this->m_IsCherryPick = FALSE;
46 m_bForce=FALSE;
47 m_IsFastForward=FALSE;
50 CRebaseDlg::~CRebaseDlg()
54 void CRebaseDlg::DoDataExchange(CDataExchange* pDX)
56 CDialog::DoDataExchange(pDX);
57 DDX_Control(pDX, IDC_REBASE_PROGRESS, m_ProgressBar);
58 DDX_Control(pDX, IDC_STATUS_STATIC, m_CtrlStatusText);
59 DDX_Check(pDX, IDC_PICK_ALL, m_bPickAll);
60 DDX_Check(pDX, IDC_SQUASH_ALL, m_bSquashAll);
61 DDX_Check(pDX, IDC_EDIT_ALL, m_bEditAll);
62 DDX_Control(pDX, IDC_REBASE_SPLIT, m_wndSplitter);
63 DDX_Control(pDX,IDC_COMMIT_LIST,m_CommitList);
64 DDX_Control(pDX,IDC_REBASE_COMBOXEX_BRANCH, this->m_BranchCtrl);
65 DDX_Control(pDX,IDC_REBASE_COMBOXEX_UPSTREAM, this->m_UpstreamCtrl);
66 DDX_Check(pDX, IDC_REBASE_CHECK_FORCE,m_bForce);
67 DDX_Control(pDX,IDC_REBASE_POST_BUTTON,m_PostButton);
71 BEGIN_MESSAGE_MAP(CRebaseDlg, CResizableStandAloneDialog)
72 ON_BN_CLICKED(IDC_PICK_ALL, &CRebaseDlg::OnBnClickedPickAll)
73 ON_BN_CLICKED(IDC_SQUASH_ALL, &CRebaseDlg::OnBnClickedSquashAll)
74 ON_BN_CLICKED(IDC_EDIT_ALL, &CRebaseDlg::OnBnClickedEditAll)
75 ON_BN_CLICKED(IDC_REBASE_SPLIT, &CRebaseDlg::OnBnClickedRebaseSplit)
76 ON_BN_CLICKED(IDC_REBASE_CONTINUE,OnBnClickedContinue)
77 ON_BN_CLICKED(IDC_REBASE_ABORT, OnBnClickedAbort)
78 ON_WM_SIZE()
79 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_BRANCH, &CRebaseDlg::OnCbnSelchangeBranch)
80 ON_CBN_SELCHANGE(IDC_REBASE_COMBOXEX_UPSTREAM, &CRebaseDlg::OnCbnSelchangeUpstream)
81 ON_MESSAGE(MSG_REBASE_UPDATE_UI, OnRebaseUpdateUI)
82 ON_BN_CLICKED(IDC_BUTTON_BROWSE, &CRebaseDlg::OnBnClickedButtonBrowse)
83 ON_BN_CLICKED(IDC_REBASE_CHECK_FORCE, &CRebaseDlg::OnBnClickedRebaseCheckForce)
84 ON_BN_CLICKED(IDC_REBASE_POST_BUTTON, &CRebaseDlg::OnBnClickedRebasePostButton)
85 ON_BN_CLICKED(IDC_BUTTON_UP2, &CRebaseDlg::OnBnClickedButtonUp2)
86 ON_BN_CLICKED(IDC_BUTTON_DOWN2, &CRebaseDlg::OnBnClickedButtonDown2)
87 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
88 ON_NOTIFY(LVN_ITEMCHANGED, IDC_COMMIT_LIST, OnLvnItemchangedLoglist)
89 END_MESSAGE_MAP()
91 void CRebaseDlg::AddRebaseAnchor()
93 AddAnchor(IDC_REBASE_TAB,TOP_LEFT,BOTTOM_RIGHT);
94 AddAnchor(IDC_COMMIT_LIST,TOP_LEFT, TOP_RIGHT);
95 AddAnchor(IDC_REBASE_SPLIT,TOP_LEFT, TOP_RIGHT);
96 AddAnchor(IDC_STATUS_STATIC, BOTTOM_LEFT,BOTTOM_RIGHT);
97 AddAnchor(IDC_REBASE_CONTINUE,BOTTOM_RIGHT);
98 AddAnchor(IDC_REBASE_ABORT, BOTTOM_RIGHT);
99 AddAnchor(IDC_REBASE_PROGRESS,BOTTOM_LEFT, BOTTOM_RIGHT);
100 AddAnchor(IDC_PICK_ALL,TOP_LEFT);
101 AddAnchor(IDC_SQUASH_ALL,TOP_LEFT);
102 AddAnchor(IDC_EDIT_ALL,TOP_LEFT);
103 AddAnchor(IDC_BUTTON_UP2,TOP_LEFT);
104 AddAnchor(IDC_BUTTON_DOWN2,TOP_LEFT);
105 AddAnchor(IDC_REBASE_COMBOXEX_UPSTREAM,TOP_LEFT);
106 AddAnchor(IDC_REBASE_COMBOXEX_BRANCH,TOP_LEFT);
107 AddAnchor(IDC_REBASE_STATIC_UPSTREAM,TOP_LEFT);
108 AddAnchor(IDC_REBASE_STATIC_BRANCH,TOP_LEFT);
109 AddAnchor(IDHELP, BOTTOM_RIGHT);
110 AddAnchor(IDC_REBASE_CHECK_FORCE,TOP_RIGHT);
111 AddAnchor(IDC_REBASE_POST_BUTTON,BOTTOM_LEFT);
113 this->AddOthersToAnchor();
116 BOOL CRebaseDlg::OnInitDialog()
118 CResizableStandAloneDialog::OnInitDialog();
119 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
121 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
122 // do this, Explorer would be unable to send that message to our window if we
123 // were running elevated. It's OK to make the call all the time, since if we're
124 // not elevated, this is a no-op.
125 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
126 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
127 HMODULE hUser = ::LoadLibrary(_T("user32.dll"));
128 if (hUser)
130 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
131 if (pfnChangeWindowMessageFilterEx)
133 pfnChangeWindowMessageFilterEx(m_hWnd, WM_TASKBARBTNCREATED, MSGFLT_ALLOW, &cfs);
135 FreeLibrary(hUser);
137 m_pTaskbarList.Release();
138 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
140 CRect rectDummy;
141 //IDC_REBASE_DUMY_TAB
143 GetClientRect(m_DlgOrigRect);
144 m_CommitList.GetClientRect(m_CommitListOrigRect);
146 CWnd *pwnd=this->GetDlgItem(IDC_REBASE_DUMY_TAB);
147 pwnd->GetWindowRect(&rectDummy);
148 this->ScreenToClient(rectDummy);
150 if (!m_ctrlTabCtrl.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, IDC_REBASE_TAB))
152 TRACE0("Failed to create output tab window\n");
153 return FALSE; // fail to create
155 m_ctrlTabCtrl.SetResizeMode(CMFCTabCtrl::RESIZE_NO);
156 // Create output panes:
157 //const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
158 DWORD dwStyle =LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | WS_VISIBLE;
160 if (! this->m_FileListCtrl.Create(dwStyle,rectDummy,&this->m_ctrlTabCtrl,0) )
162 TRACE0("Failed to create output windows\n");
163 return FALSE; // fail to create
166 if( ! this->m_LogMessageCtrl.Create(_T("Scintilla"),_T("source"),0,rectDummy,&m_ctrlTabCtrl,0,0) )
168 TRACE0("Failed to create log message control");
169 return FALSE;
171 m_LogMessageCtrl.Init(0);
172 m_LogMessageCtrl.Call(SCI_SETREADONLY, TRUE);
174 dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL;
176 if (!m_wndOutputRebase.Create(_T("Scintilla"),_T("source"),0,rectDummy, &m_ctrlTabCtrl, 0,0) )
178 TRACE0("Failed to create output windows\n");
179 return -1; // fail to create
181 m_wndOutputRebase.Init(0);
182 m_wndOutputRebase.Call(SCI_SETREADONLY, TRUE);
184 m_tooltips.Create(this);
186 m_tooltips.AddTool(IDC_REBASE_CHECK_FORCE,IDS_REBASE_FORCE_TT);
187 m_tooltips.AddTool(IDC_REBASE_ABORT,IDS_REBASE_ABORT_TT);
191 m_FileListCtrl.Init(GITSLC_COLEXT | GITSLC_COLSTATUS |GITSLC_COLADD|GITSLC_COLDEL , _T("RebaseDlg"),(GITSLC_POPALL ^ GITSLC_POPCOMMIT),false);
193 m_ctrlTabCtrl.AddTab(&m_FileListCtrl,_T("Revision Files"));
194 m_ctrlTabCtrl.AddTab(&m_LogMessageCtrl,_T("Commit Message"),1);
195 AddRebaseAnchor();
197 CString sWindowTitle;
198 GetWindowText(sWindowTitle);
199 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
201 EnableSaveRestore(_T("RebaseDlg"));
203 DWORD yPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
204 RECT rcDlg, rcLogMsg, rcFileList;
205 GetClientRect(&rcDlg);
206 m_CommitList.GetWindowRect(&rcLogMsg);
207 ScreenToClient(&rcLogMsg);
208 this->m_ctrlTabCtrl.GetWindowRect(&rcFileList);
209 ScreenToClient(&rcFileList);
210 if (yPos)
212 RECT rectSplitter;
213 m_wndSplitter.GetWindowRect(&rectSplitter);
214 ScreenToClient(&rectSplitter);
215 int delta = yPos - rectSplitter.top;
216 if ((rcLogMsg.bottom + delta > rcLogMsg.top)&&(rcLogMsg.bottom + delta < rcFileList.bottom - 30))
218 m_wndSplitter.SetWindowPos(NULL, 0, yPos, 0, 0, SWP_NOSIZE);
219 DoSize(delta);
223 if( this->m_RebaseStage == CHOOSE_BRANCH)
225 this->LoadBranchInfo();
228 else
230 this->m_BranchCtrl.EnableWindow(FALSE);
231 this->m_UpstreamCtrl.EnableWindow(FALSE);
234 m_CommitList.m_ColumnRegKey = _T("Rebase");
235 m_CommitList.m_IsIDReplaceAction = TRUE;
236 // m_CommitList.m_IsOldFirst = TRUE;
237 m_CommitList.m_IsRebaseReplaceGraph = TRUE;
239 m_CommitList.InsertGitColumn();
241 this->SetControlEnable();
243 if(!this->m_PreCmd.IsEmpty())
245 CProgressDlg progress;
246 progress.m_GitCmd=m_PreCmd;
247 progress.m_bAutoCloseOnSuccess=true;
248 progress.DoModal();
251 if(m_IsCherryPick)
253 this->m_BranchCtrl.SetCurSel(-1);
254 this->m_BranchCtrl.EnableWindow(FALSE);
255 this->m_UpstreamCtrl.AddString(_T("HEAD"));
256 this->m_UpstreamCtrl.EnableWindow(FALSE);
257 this->SetWindowText(_T("Cherry Pick"));
258 this->m_CommitList.StartFilter();
261 else
263 SetContinueButtonText();
264 m_CommitList.DeleteAllItems();
265 FetchLogList();
268 m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_CHERRY_PICK)|
269 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_SWITCHTOREV)|
270 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_RESET)|
271 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTREV)|
272 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_TO_VERSION)|
273 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REVERTTOREV)|
274 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_COMBINE_COMMIT));
276 if(m_CommitList.m_IsOldFirst)
277 this->m_CurrentRebaseIndex = -1;
278 else
279 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();
282 if(this->CheckRebaseCondition())
284 /* Disable Start Rebase */
285 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
288 return TRUE;
290 // CRebaseDlg message handlers
292 void CRebaseDlg::OnBnClickedPickAll()
294 this->UpdateData();
295 if(this->m_bPickAll)
296 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_PICK);
298 this->m_bEditAll=FALSE;
299 this->m_bSquashAll=FALSE;
300 this->UpdateData(FALSE);
303 void CRebaseDlg::OnBnClickedSquashAll()
305 this->UpdateData();
306 if(this->m_bSquashAll)
307 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);
309 this->m_bEditAll=FALSE;
310 this->m_bPickAll=FALSE;
311 this->UpdateData(FALSE);
314 void CRebaseDlg::OnBnClickedEditAll()
316 this->UpdateData();
317 if( this->m_bEditAll )
318 this->SetAllRebaseAction(CTGitPath::LOGACTIONS_REBASE_EDIT);
320 this->m_bPickAll=FALSE;
321 this->m_bSquashAll=FALSE;
322 this->UpdateData(FALSE);
325 void CRebaseDlg::SetAllRebaseAction(int action)
327 for(int i=0;i<this->m_CommitList.m_logEntries.size();i++)
329 m_CommitList.m_logEntries.GetGitRevAt(i).GetAction(&m_CommitList)=action;
331 m_CommitList.Invalidate();
334 void CRebaseDlg::OnBnClickedRebaseSplit()
336 this->UpdateData();
339 LRESULT CRebaseDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
341 switch (message) {
342 case WM_NOTIFY:
343 if (wParam == IDC_REBASE_SPLIT)
345 SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;
346 DoSize(pHdr->delta);
348 break;
351 return __super::DefWindowProc(message, wParam, lParam);
354 void CRebaseDlg::DoSize(int delta)
356 this->RemoveAllAnchors();
358 CSplitterControl::ChangeHeight(GetDlgItem(IDC_COMMIT_LIST), delta, CW_TOPALIGN);
359 //CSplitterControl::ChangeHeight(GetDlgItem(), delta, CW_TOPALIGN);
360 CSplitterControl::ChangeHeight(GetDlgItem(IDC_REBASE_TAB), -delta, CW_BOTTOMALIGN);
361 //CSplitterControl::ChangeHeight(GetDlgItem(), -delta, CW_BOTTOMALIGN);
362 CSplitterControl::ChangePos(GetDlgItem(IDC_SQUASH_ALL),0,delta);
363 CSplitterControl::ChangePos(GetDlgItem(IDC_PICK_ALL),0,delta);
364 CSplitterControl::ChangePos(GetDlgItem(IDC_EDIT_ALL),0,delta);
365 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_UP2),0,delta);
366 CSplitterControl::ChangePos(GetDlgItem(IDC_BUTTON_DOWN2),0,delta);
367 CSplitterControl::ChangePos(GetDlgItem(IDC_REBASE_CHECK_FORCE),0,delta);
369 this->AddRebaseAnchor();
370 // adjust the minimum size of the dialog to prevent the resizing from
371 // moving the list control too far down.
372 CRect rcLogMsg;
373 m_CommitList.GetClientRect(rcLogMsg);
374 SetMinTrackSize(CSize(m_DlgOrigRect.Width(), m_DlgOrigRect.Height()-m_CommitListOrigRect.Height()+rcLogMsg.Height()));
376 SetSplitterRange();
377 // m_CommitList.Invalidate();
379 // GetDlgItem(IDC_LOGMESSAGE)->Invalidate();
381 this->m_ctrlTabCtrl.Invalidate();
382 this->m_CommitList.Invalidate();
383 this->m_FileListCtrl.Invalidate();
384 this->m_LogMessageCtrl.Invalidate();
388 void CRebaseDlg::SetSplitterRange()
390 if ((m_CommitList)&&(m_ctrlTabCtrl))
392 CRect rcTop;
393 m_CommitList.GetWindowRect(rcTop);
394 ScreenToClient(rcTop);
395 CRect rcMiddle;
396 m_ctrlTabCtrl.GetWindowRect(rcMiddle);
397 ScreenToClient(rcMiddle);
398 if (rcMiddle.Height() && rcMiddle.Width())
399 m_wndSplitter.SetRange(rcTop.top+60, rcMiddle.bottom-80);
403 void CRebaseDlg::OnSize(UINT nType,int cx, int cy)
405 // first, let the resizing take place
406 __super::OnSize(nType, cx, cy);
408 //set range
409 SetSplitterRange();
412 void CRebaseDlg::SaveSplitterPos()
414 if (!IsIconic())
416 CRegDWORD regPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RebaseDlgSizer"));
417 RECT rectSplitter;
418 m_wndSplitter.GetWindowRect(&rectSplitter);
419 ScreenToClient(&rectSplitter);
420 regPos = rectSplitter.top;
424 void CRebaseDlg::LoadBranchInfo()
426 m_BranchCtrl.SetMaxHistoryItems(0x7FFFFFFF);
427 m_UpstreamCtrl.SetMaxHistoryItems(0x7FFFFFFF);
429 STRING_VECTOR list;
430 list.clear();
431 int current;
432 g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL);
433 m_BranchCtrl.AddString(list);
434 list.clear();
435 g_Git.GetBranchList(list,&current,CGit::BRANCH_ALL_F);
436 m_UpstreamCtrl.AddString(list);
438 m_BranchCtrl.SetCurSel(current);
440 AddBranchToolTips(&m_BranchCtrl);
441 AddBranchToolTips(&m_UpstreamCtrl);
443 if(!m_Upstream.IsEmpty())
445 m_UpstreamCtrl.AddString(m_Upstream);
446 m_UpstreamCtrl.SetCurSel(m_UpstreamCtrl.GetCount()-1);
448 else
450 //Select pull-remote from current branch
451 CString currentBranch = g_Git.GetSymbolicRef();
452 CString configName;
453 configName.Format(L"branch.%s.remote", currentBranch);
454 CString pullRemote = g_Git.GetConfigValue(configName);
456 //Select pull-branch from current branch
457 configName.Format(L"branch.%s.merge", currentBranch);
458 CString pullBranch = CGit::StripRefName(g_Git.GetConfigValue(configName));
460 CString defaultUpstream;
461 defaultUpstream.Format(L"remotes/%s/%s", pullRemote, pullBranch);
462 int found = m_UpstreamCtrl.FindStringExact(0, defaultUpstream);
463 if(found >= 0)
464 m_UpstreamCtrl.SetCurSel(found);
468 void CRebaseDlg::OnCbnSelchangeBranch()
470 FetchLogList();
473 void CRebaseDlg::OnCbnSelchangeUpstream()
475 FetchLogList();
478 void CRebaseDlg::FetchLogList()
480 CGitHash base,hash;
481 CString basestr, err;
482 CString cmd;
483 m_IsFastForward=FALSE;
484 cmd.Format(_T("git.exe merge-base %s %s"), g_Git.FixBranchName(m_UpstreamCtrl.GetString()),
485 g_Git.FixBranchName(m_BranchCtrl.GetString()));
486 if (g_Git.Run(cmd, &basestr, &err, CP_ACP))
488 CMessageBox::Show(NULL, basestr + L"\n" + err, _T("TortoiseGit"), MB_OK|MB_ICONERROR);
489 return;
491 base=basestr;
493 hash=g_Git.GetHash(m_BranchCtrl.GetString());
495 if(hash == g_Git.GetHash(this->m_UpstreamCtrl.GetString()))
497 m_CommitList.Clear();
498 CString text,fmt;
499 fmt.LoadString(IDS_REBASE_EQUAL_FMT);
500 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());
502 m_CommitList.ShowText(text);
503 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(false);
504 return;
507 if(hash == base )
509 //fast forword
510 this->m_IsFastForward=TRUE;
512 m_CommitList.Clear();
513 CString text,fmt;
514 fmt.LoadString(IDS_REBASE_FASTFORWARD_FMT);
515 text.Format(fmt,m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString(),
516 m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString());
518 m_CommitList.ShowText(text);
519 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(true);
520 SetContinueButtonText();
522 return ;
525 hash.Empty();
527 if(!this->m_bForce)
529 hash=g_Git.GetHash(m_UpstreamCtrl.GetString());
531 if( base == hash )
533 m_CommitList.Clear();
534 CString text,fmt;
535 fmt.LoadString(IDS_REBASE_UPTODATE_FMT);
536 text.Format(fmt,m_BranchCtrl.GetString());
537 m_CommitList.ShowText(text);
538 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());
539 SetContinueButtonText();
540 return;
544 m_CommitList.Clear();
545 CString from,to;
546 from = m_UpstreamCtrl.GetString();
547 to = m_BranchCtrl.GetString();
548 this->m_CommitList.FillGitLog(NULL,0,&from,&to);
550 if( m_CommitList.GetItemCount() == 0 )
551 m_CommitList.ShowText(_T("Nothing to Rebase"));
553 hash=g_Git.GetHash(m_UpstreamCtrl.GetString());
555 #if 0
556 if(m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash.size() >=0 )
558 if(hash == m_CommitList.m_logEntries[m_CommitList.m_logEntries.size()-1].m_ParentHash[0])
560 m_CommitList.Clear();
561 m_CommitList.ShowText(_T("Nothing Rebase"));
564 #endif
566 m_tooltips.Pop();
567 AddBranchToolTips(&this->m_BranchCtrl);
568 AddBranchToolTips(&this->m_UpstreamCtrl);
570 for(int i=0;i<m_CommitList.m_logEntries.size();i++)
572 m_CommitList.m_logEntries.GetGitRevAt(i).GetAction(&m_CommitList) = CTGitPath::LOGACTIONS_REBASE_PICK;
575 m_CommitList.Invalidate();
577 if(m_CommitList.m_IsOldFirst)
578 this->m_CurrentRebaseIndex = -1;
579 else
580 this->m_CurrentRebaseIndex = m_CommitList.m_logEntries.size();
582 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(m_CommitList.GetItemCount());
583 SetContinueButtonText();
586 void CRebaseDlg::AddBranchToolTips(CHistoryCombo *pBranch)
588 if(pBranch)
590 CString text=pBranch->GetString();
591 CString tooltip;
593 GitRev rev;
594 rev.GetCommit(text);
596 tooltip.Format(_T("CommitHash:%s\nCommit by: %s %s\n <b>%s</b> \n %s"),
597 rev.m_CommitHash.ToString(),
598 rev.GetAuthorName(),
599 CAppUtils::FormatDateAndTime(rev.GetAuthorDate(),DATE_LONGDATE),
600 rev.GetSubject(),
601 rev.GetBody());
603 pBranch->DisableTooltip();
604 this->m_tooltips.AddTool(pBranch->GetComboBoxCtrl(),tooltip);
608 BOOL CRebaseDlg::PreTranslateMessage(MSG*pMsg)
610 if (pMsg->message == WM_KEYDOWN)
612 switch (pMsg->wParam)
614 case ' ':
615 if(LogListHasFocus(pMsg->hwnd))
617 m_CommitList.ShiftSelectedAction();
618 return TRUE;
620 break;
621 case 'P':
622 if(LogListHasFocus(pMsg->hwnd))
624 m_CommitList.SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_PICK);
625 return TRUE;
627 break;
628 case 'S':
629 if(LogListHasFocus(pMsg->hwnd))
631 m_CommitList.SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SKIP);
632 return TRUE;
634 break;
635 case 'Q':
636 if(LogListHasFocus(pMsg->hwnd))
638 m_CommitList.SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_SQUASH);
639 return TRUE;
641 break;
642 case 'E':
643 if(LogListHasFocus(pMsg->hwnd))
645 m_CommitList.SetSelectedAction(CTGitPath::LOGACTIONS_REBASE_EDIT);
646 return TRUE;
648 break;
649 case 'A':
650 if(LogListHasFocus(pMsg->hwnd) && GetAsyncKeyState(VK_CONTROL) & 0x8000)
652 // select all entries
653 for (int i = 0; i < m_CommitList.GetItemCount(); ++i)
655 m_CommitList.SetItemState(i, LVIS_SELECTED, LVIS_SELECTED);
657 return TRUE;
659 break;
660 case VK_F5:
662 Refresh();
663 return TRUE;
665 break;
666 /* Avoid TAB control destroy but dialog exist*/
667 case VK_ESCAPE:
668 case VK_CANCEL:
670 TCHAR buff[128];
671 ::GetClassName(pMsg->hwnd,buff,128);
674 if(_tcsnicmp(buff,_T("RichEdit20W"),128)==0 ||
675 _tcsnicmp(buff,_T("Scintilla"),128)==0 ||
676 _tcsnicmp(buff,_T("SysListView32"),128)==0||
677 ::GetParent(pMsg->hwnd) == this->m_ctrlTabCtrl.m_hWnd)
679 this->PostMessage(WM_KEYDOWN,VK_ESCAPE,0);
680 return TRUE;
685 m_tooltips.RelayEvent(pMsg);
686 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
689 bool CRebaseDlg::LogListHasFocus(HWND hwnd)
691 TCHAR buff[128];
692 ::GetClassName(hwnd, buff, 128);
694 if(_tcsnicmp(buff, _T("SysListView32"), 128) == 0)
695 return true;
696 return false;
699 int CRebaseDlg::CheckRebaseCondition()
701 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
703 if( !g_Git.CheckCleanWorkTree() )
705 if(CMessageBox::Show(NULL, IDS_ERROR_NOCLEAN_STASH,IDS_APPNAME,MB_YESNO|MB_ICONINFORMATION)==IDYES)
707 CString cmd,out;
708 cmd=_T("git.exe stash");
709 this->AddLogString(cmd);
710 if(g_Git.Run(cmd,&out,CP_ACP))
712 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK);
713 return -1;
717 else
718 return -1;
720 //Todo Check $REBASE_ROOT
721 //Todo Check $DOTEST
723 CString cmd;
724 cmd=_T("git.exe var GIT_COMMITTER_IDENT");
725 if(g_Git.Run(cmd,NULL,CP_UTF8))
726 return -1;
728 //Todo call pre_rebase_hook
729 return 0;
731 int CRebaseDlg::StartRebase()
733 CString cmd,out;
734 m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;
735 if(!this->m_IsCherryPick)
737 //Todo call comment_for_reflog
738 cmd.Format(_T("git.exe checkout %s"),this->m_BranchCtrl.GetString());
739 this->AddLogString(cmd);
741 if(g_Git.Run(cmd,&out,CP_UTF8))
743 this->AddLogString(out);
744 return -1;
747 this->AddLogString(out);
750 cmd=_T("git.exe rev-parse --verify HEAD");
751 if(g_Git.Run(cmd,&out,CP_UTF8))
753 AddLogString(_T("No Head"));
754 return -1;
756 //Todo
757 //git symbolic-ref HEAD > "$DOTEST"/head-name 2> /dev/null ||
758 // echo "detached HEAD" > "$DOTEST"/head-name
760 cmd.Format(_T("git.exe update-ref ORIG_HEAD HEAD"));
761 if(g_Git.Run(cmd,&out,CP_UTF8))
763 AddLogString(_T("update ORIG_HEAD Fail"));
764 return -1;
767 m_OrigUpstreamHash.Empty();
768 m_OrigUpstreamHash= g_Git.GetHash(this->m_UpstreamCtrl.GetString());
769 if(m_OrigUpstreamHash.IsEmpty())
771 this->AddLogString(m_OrigUpstreamHash);
772 return -1;
775 if( !this->m_IsCherryPick )
777 cmd.Format(_T("git.exe checkout -f %s"), m_OrigUpstreamHash.ToString());
778 this->AddLogString(cmd);
780 out.Empty();
781 if(g_Git.Run(cmd,&out,CP_UTF8))
783 this->AddLogString(out);
784 return -1;
788 if( !this->m_IsCherryPick )
790 m_OrigBranchHash = g_Git.GetHash(this->m_BranchCtrl.GetString());
791 if(m_OrigBranchHash.IsEmpty())
793 this->AddLogString(m_OrigBranchHash.ToString());
794 return -1;
796 this->AddLogString(_T("Start Rebase\r\n"));
799 else
800 this->AddLogString(_T("Start Cherry-pick\r\n"));
802 return 0;
804 int CRebaseDlg::VerifyNoConflict()
806 CTGitPathList list;
807 if(g_Git.ListConflictFile(list))
809 AddLogString(_T("Get conflict files fail"));
810 return -1;
812 if( list.GetCount() != 0 )
814 CMessageBox::Show(NULL,_T("There are conflict file, you should mark it resolve"),_T("TortoiseGit"),MB_OK);
815 return -1;
817 return 0;
820 int CRebaseDlg::FinishRebase()
822 if(this->m_IsCherryPick) //cherry pick mode no "branch", working at upstream branch
823 return 0;
825 git_revnum_t head = g_Git.GetHash(_T("HEAD"));
826 CString out,cmd;
828 out.Empty();
829 cmd.Format(_T("git.exe checkout -f %s"),this->m_BranchCtrl.GetString());
830 AddLogString(cmd);
831 if(g_Git.Run(cmd,&out,CP_UTF8))
833 AddLogString(out);
834 return -1;
836 AddLogString(out);
838 out.Empty();
839 cmd.Format(_T("git.exe reset --hard %s"),head);
840 AddLogString(cmd);
841 if(g_Git.Run(cmd,&out,CP_UTF8))
843 AddLogString(out);
844 return -1;
846 AddLogString(out);
848 m_ctrlTabCtrl.RemoveTab(0);
849 m_ctrlTabCtrl.RemoveTab(0);
850 m_CtrlStatusText.SetWindowText(_T("Finished rebasing."));
852 return 0;
854 void CRebaseDlg::OnBnClickedContinue()
856 if( m_RebaseStage == REBASE_DONE)
858 OnOK();
859 return;
862 if( this->m_IsFastForward )
864 CString cmd,out;
865 CString oldbranch = g_Git.GetCurrentBranch();
866 if( oldbranch != m_BranchCtrl.GetString() )
868 cmd.Format(_T("git.exe checkout %s"),m_BranchCtrl.GetString());
869 AddLogString(cmd);
870 if( g_Git.Run(cmd,&out,CP_ACP) )
872 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
873 AddLogString(out);
874 return;
877 AddLogString(out);
878 out.Empty();
879 m_OrigBranchHash = g_Git.GetHash(m_BranchCtrl.GetString());
880 m_OrigUpstreamHash = g_Git.GetHash(this->m_UpstreamCtrl.GetString());
882 if(!g_Git.IsFastForward(this->m_BranchCtrl.GetString(),this->m_UpstreamCtrl.GetString()))
884 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
885 AddLogString(_T("No fast forward\r\nMaybe repository changed"));
886 return;
889 cmd.Format(_T("git.exe reset --hard %s"),g_Git.FixBranchName(this->m_UpstreamCtrl.GetString()));
890 this->AddLogString(CString(_T("Fast forward to "))+m_UpstreamCtrl.GetString());
892 AddLogString(cmd);
893 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
894 if(g_Git.Run(cmd,&out,CP_ACP))
896 AddLogString(_T("Fail"));
897 AddLogString(out);
898 return;
900 AddLogString(out);
901 AddLogString(_T("Done"));
902 m_RebaseStage = REBASE_DONE;
903 UpdateCurrentStatus();
904 return;
907 if( m_RebaseStage == CHOOSE_BRANCH|| m_RebaseStage == CHOOSE_COMMIT_PICK_MODE )
909 if(CheckRebaseCondition())
910 return ;
911 m_RebaseStage = REBASE_START;
912 m_FileListCtrl.Clear();
913 m_FileListCtrl.m_CurrentVersion = L"";
914 m_ctrlTabCtrl.SetTabLabel(REBASE_TAB_CONFLICT, _T("Conflict Files"));
915 m_ctrlTabCtrl.AddTab(&m_wndOutputRebase,_T("Log"),2);
918 if( m_RebaseStage == REBASE_FINISH )
920 if(FinishRebase())
921 return ;
923 OnOK();
926 if( m_RebaseStage == REBASE_SQUASH_CONFLICT)
928 if(VerifyNoConflict())
929 return;
930 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
931 if(this->CheckNextCommitIsSquash())
932 {//next commit is not squash;
933 m_RebaseStage = REBASE_SQUASH_EDIT;
934 this->OnRebaseUpdateUI(0,0);
935 this->UpdateCurrentStatus();
936 return ;
939 m_RebaseStage=REBASE_CONTINUE;
940 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
941 this->UpdateCurrentStatus();
945 if( m_RebaseStage == REBASE_CONFLICT )
947 if(VerifyNoConflict())
948 return;
950 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
952 CString out =_T("");
953 CString cmd;
954 cmd.Format(_T("git.exe commit -a -C %s"), curRev->m_CommitHash.ToString());
956 AddLogString(cmd);
958 if(g_Git.Run(cmd,&out,CP_UTF8))
960 AddLogString(out);
961 if(!g_Git.CheckCleanWorkTree())
963 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
964 return;
968 AddLogString(out);
969 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
970 if( curRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_EDIT)
972 m_RebaseStage=REBASE_EDIT;
973 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
974 this->UpdateCurrentStatus();
975 return;
977 else
979 m_RebaseStage=REBASE_CONTINUE;
980 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
981 this->UpdateCurrentStatus();
985 if( m_RebaseStage == REBASE_EDIT || m_RebaseStage == REBASE_SQUASH_EDIT )
987 CString str;
988 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
990 str=this->m_LogMessageCtrl.GetText();
991 if(str.Trim().IsEmpty())
993 CMessageBox::Show(NULL,_T("Commit Message Is Empty"),_T("TortoiseGit"),MB_OK|MB_ICONERROR);
994 return;
997 CString tempfile=::GetTempFile();
998 CFile file(tempfile,CFile::modeReadWrite|CFile::modeCreate );
999 CStringA log=CUnicodeUtils::GetUTF8( str);
1000 file.Write(log,log.GetLength());
1001 //file.WriteString(m_sLogMessage);
1002 file.Close();
1004 CString out,cmd;
1006 if( m_RebaseStage == REBASE_SQUASH_EDIT )
1007 cmd.Format(_T("git.exe commit -F \"%s\""), tempfile);
1008 else
1009 cmd.Format(_T("git.exe commit --amend -F \"%s\""), tempfile);
1011 if(g_Git.Run(cmd,&out,CP_UTF8))
1013 if(!g_Git.CheckCleanWorkTree())
1015 CMessageBox::Show(NULL,out,_T("TortoiseGit"),MB_OK|MB_ICONERROR);
1016 return;
1020 CFile::Remove(tempfile);
1021 AddLogString(out);
1022 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
1023 m_RebaseStage=REBASE_CONTINUE;
1024 curRev->GetAction(&m_CommitList)|=CTGitPath::LOGACTIONS_REBASE_DONE;
1025 this->UpdateCurrentStatus();
1029 InterlockedExchange(&m_bThreadRunning, TRUE);
1030 SetControlEnable();
1032 if (AfxBeginThread(RebaseThreadEntry, this)==NULL)
1034 InterlockedExchange(&m_bThreadRunning, FALSE);
1035 CMessageBox::Show(NULL, _T("Create Rebase Thread Fail"), _T("TortoiseGit"), MB_OK | MB_ICONERROR);
1036 SetControlEnable();
1039 int CRebaseDlg::CheckNextCommitIsSquash()
1041 int index;
1042 if(m_CommitList.m_IsOldFirst)
1043 index=m_CurrentRebaseIndex+1;
1044 else
1045 index=m_CurrentRebaseIndex-1;
1047 GitRev *curRev;
1050 if(index<0)
1051 return -1;
1052 if(index>= m_CommitList.GetItemCount())
1053 return -1;
1055 curRev=(GitRev*)m_CommitList.m_arShownList[index];
1057 if( curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SQUASH )
1058 return 0;
1059 if( curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SKIP)
1061 if(m_CommitList.m_IsOldFirst)
1062 index++;
1063 else
1064 index--;
1066 else
1067 return -1;
1069 }while(curRev->GetAction(&m_CommitList)&CTGitPath::LOGACTIONS_REBASE_SKIP);
1071 return -1;
1074 int CRebaseDlg::GoNext()
1076 if(m_CommitList.m_IsOldFirst)
1077 m_CurrentRebaseIndex++;
1078 else
1079 m_CurrentRebaseIndex--;
1080 return 0;
1083 int CRebaseDlg::StateAction()
1085 switch(this->m_RebaseStage)
1087 case CHOOSE_BRANCH:
1088 case CHOOSE_COMMIT_PICK_MODE:
1089 if(StartRebase())
1090 return -1;
1091 m_RebaseStage = REBASE_START;
1092 GoNext();
1093 break;
1096 return 0;
1098 void CRebaseDlg::SetContinueButtonText()
1100 CString Text;
1101 switch(this->m_RebaseStage)
1103 case CHOOSE_BRANCH:
1104 case CHOOSE_COMMIT_PICK_MODE:
1105 if(this->m_IsFastForward)
1106 Text = _T("Start(FastFwd)");
1107 else
1108 Text = _T("Start");
1109 break;
1111 case REBASE_START:
1112 case REBASE_CONTINUE:
1113 case REBASE_SQUASH_CONFLICT:
1114 Text = _T("Continue");
1115 break;
1117 case REBASE_CONFLICT:
1118 Text = _T("Commit");
1119 break;
1120 case REBASE_EDIT:
1121 Text = _T("Amend");
1122 break;
1124 case REBASE_SQUASH_EDIT:
1125 Text = _T("Commit");
1126 break;
1128 case REBASE_ABORT:
1129 case REBASE_FINISH:
1130 Text = _T("Finish");
1131 break;
1133 case REBASE_DONE:
1134 Text = _T("Done");
1135 break;
1137 this->GetDlgItem(IDC_REBASE_CONTINUE)->SetWindowText(Text);
1140 void CRebaseDlg::SetControlEnable()
1142 switch(this->m_RebaseStage)
1144 case CHOOSE_BRANCH:
1145 case CHOOSE_COMMIT_PICK_MODE:
1147 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(TRUE);
1148 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(TRUE);
1149 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(TRUE);
1150 this->GetDlgItem(IDC_BUTTON_UP2)->EnableWindow(TRUE);
1151 this->GetDlgItem(IDC_BUTTON_DOWN2)->EnableWindow(TRUE);
1153 if(!m_IsCherryPick)
1155 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(TRUE);
1156 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(TRUE);
1157 this->GetDlgItem(IDC_REBASE_CHECK_FORCE)->EnableWindow(TRUE);
1159 //this->m_CommitList.m_IsEnableRebaseMenu=TRUE;
1160 this->m_CommitList.m_ContextMenuMask |= m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|
1161 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|
1162 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|
1163 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP);
1164 break;
1166 case REBASE_START:
1167 case REBASE_CONTINUE:
1168 case REBASE_ABORT:
1169 case REBASE_FINISH:
1170 case REBASE_CONFLICT:
1171 case REBASE_EDIT:
1172 case REBASE_SQUASH_CONFLICT:
1173 case REBASE_DONE:
1174 this->GetDlgItem(IDC_PICK_ALL)->EnableWindow(FALSE);
1175 this->GetDlgItem(IDC_EDIT_ALL)->EnableWindow(FALSE);
1176 this->GetDlgItem(IDC_SQUASH_ALL)->EnableWindow(FALSE);
1177 this->GetDlgItem(IDC_REBASE_COMBOXEX_BRANCH)->EnableWindow(FALSE);
1178 this->GetDlgItem(IDC_REBASE_COMBOXEX_UPSTREAM)->EnableWindow(FALSE);
1179 this->GetDlgItem(IDC_REBASE_CHECK_FORCE)->EnableWindow(FALSE);
1180 this->GetDlgItem(IDC_BUTTON_UP2)->EnableWindow(FALSE);
1181 this->GetDlgItem(IDC_BUTTON_DOWN2)->EnableWindow(FALSE);
1182 //this->m_CommitList.m_IsEnableRebaseMenu=FALSE;
1183 this->m_CommitList.m_ContextMenuMask &= ~(m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_PICK)|
1184 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SQUASH)|
1185 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_EDIT)|
1186 m_CommitList.GetContextMenuBit(CGitLogListBase::ID_REBASE_SKIP));
1188 if( m_RebaseStage == REBASE_DONE && (this->m_PostButtonTexts.GetCount() != 0) )
1190 this->GetDlgItem(IDC_STATUS_STATIC)->ShowWindow(SW_HIDE);
1191 this->GetDlgItem(IDC_REBASE_POST_BUTTON)->ShowWindow(SW_SHOWNORMAL);
1192 this->m_PostButton.RemoveAll();
1193 this->m_PostButton.AddEntries(m_PostButtonTexts);
1194 //this->GetDlgItem(IDC_REBASE_POST_BUTTON)->SetWindowText(this->m_PostButtonText);
1196 break;
1199 if(m_bThreadRunning)
1201 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1204 else
1206 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(TRUE);
1210 void CRebaseDlg::UpdateProgress()
1212 int index;
1213 CRect rect;
1215 if(m_CommitList.m_IsOldFirst)
1216 index = m_CurrentRebaseIndex+1;
1217 else
1218 index = m_CommitList.GetItemCount()-m_CurrentRebaseIndex;
1220 m_ProgressBar.SetRange(1,m_CommitList.GetItemCount());
1221 m_ProgressBar.SetPos(index);
1222 if (m_pTaskbarList)
1224 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
1225 m_pTaskbarList->SetProgressValue(m_hWnd, index, m_CommitList.GetItemCount());
1228 if(m_CurrentRebaseIndex>=0 && m_CurrentRebaseIndex< m_CommitList.GetItemCount())
1230 CString text;
1231 text.Format(_T("Rebasing... (%d/%d)"),index,m_CommitList.GetItemCount());
1232 m_CtrlStatusText.SetWindowText(text);
1236 GitRev *prevRev=NULL, *curRev=NULL;
1238 if( m_CurrentRebaseIndex >= 0 && m_CurrentRebaseIndex< m_CommitList.m_arShownList.GetSize())
1240 curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1243 for(int i=0;i<m_CommitList.m_arShownList.GetSize();i++)
1245 prevRev=(GitRev*)m_CommitList.m_arShownList[i];
1246 if(prevRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_CURRENT)
1248 prevRev->GetAction(&m_CommitList) &= ~ CTGitPath::LOGACTIONS_REBASE_CURRENT;
1249 m_CommitList.GetItemRect(i,&rect,LVIR_BOUNDS);
1250 m_CommitList.InvalidateRect(rect);
1254 if(curRev)
1256 curRev->GetAction(&m_CommitList) |= CTGitPath::LOGACTIONS_REBASE_CURRENT;
1257 m_CommitList.GetItemRect(m_CurrentRebaseIndex,&rect,LVIR_BOUNDS);
1258 m_CommitList.InvalidateRect(rect);
1260 m_CommitList.EnsureVisible(m_CurrentRebaseIndex,FALSE);
1263 void CRebaseDlg::UpdateCurrentStatus()
1265 SetContinueButtonText();
1266 SetControlEnable();
1267 UpdateProgress();
1270 void CRebaseDlg::AddLogString(CString str)
1272 this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, FALSE);
1273 CStringA sTextA = m_wndOutputRebase.StringForControl(str);//CUnicodeUtils::GetUTF8(str);
1274 this->m_wndOutputRebase.SendMessage(SCI_DOCUMENTEND);
1275 this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)sTextA);
1276 this->m_wndOutputRebase.SendMessage(SCI_REPLACESEL, 0, (LPARAM)(LPCSTR)"\n");
1277 this->m_wndOutputRebase.SendMessage(SCI_SETREADONLY, TRUE);
1280 int CRebaseDlg::GetCurrentCommitID()
1282 if(m_CommitList.m_IsOldFirst)
1284 return this->m_CurrentRebaseIndex+1;
1287 else
1289 return m_CommitList.GetItemCount()-m_CurrentRebaseIndex;
1293 int CRebaseDlg::DoRebase()
1295 CString cmd,out;
1296 if(m_CurrentRebaseIndex <0)
1297 return 0;
1298 if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )
1299 return 0;
1301 GitRev *pRev = (GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1302 int mode=pRev->GetAction(&m_CommitList) & CTGitPath::LOGACTIONS_REBASE_MODE_MASK;
1303 CString nocommit;
1305 if( mode== CTGitPath::LOGACTIONS_REBASE_SKIP)
1307 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1308 return 0;
1311 if( mode != CTGitPath::LOGACTIONS_REBASE_PICK )
1313 this->m_SquashMessage+= pRev->GetSubject();
1314 this->m_SquashMessage+= _T("\n");
1315 this->m_SquashMessage+= pRev->GetBody();
1317 else
1318 this->m_SquashMessage.Empty();
1320 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)
1321 nocommit=_T(" --no-commit ");
1323 CString log;
1324 log.Format(_T("%s %d: %s"),CTGitPath::GetActionName(mode),this->GetCurrentCommitID(),pRev->m_CommitHash.ToString());
1325 AddLogString(log);
1326 AddLogString(pRev->GetSubject());
1327 if (pRev->GetSubject().IsEmpty())
1329 CMessageBox::Show(m_hWnd, _T("Found an empty commit message. You have to enter one or rebase cannot proceed."), _T("TortoiseGit"), MB_OK | MB_ICONEXCLAMATION);
1330 mode = CTGitPath::LOGACTIONS_REBASE_EDIT;
1333 cmd.Format(_T("git.exe cherry-pick %s %s"),nocommit,pRev->m_CommitHash.ToString());
1335 if(g_Git.Run(cmd,&out,CP_UTF8))
1337 AddLogString(out);
1338 CTGitPathList list;
1339 if(g_Git.ListConflictFile(list))
1341 AddLogString(_T("Get conflict files fail"));
1342 return -1;
1344 if(list.GetCount() == 0 )
1346 if(mode == CTGitPath::LOGACTIONS_REBASE_PICK)
1348 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1349 return 0;
1351 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)
1353 this->m_RebaseStage = REBASE_EDIT ;
1354 return -1; // Edit return -1 to stop rebase.
1356 // Squash Case
1357 if(CheckNextCommitIsSquash())
1358 { // no squash
1359 // let user edit last commmit message
1360 this->m_RebaseStage = REBASE_SQUASH_EDIT;
1361 return -1;
1364 if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)
1365 m_RebaseStage = REBASE_SQUASH_CONFLICT;
1366 else
1367 m_RebaseStage = REBASE_CONFLICT;
1368 return -1;
1371 else
1373 AddLogString(out);
1374 if(mode == CTGitPath::LOGACTIONS_REBASE_PICK)
1376 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1377 return 0;
1379 if(mode == CTGitPath::LOGACTIONS_REBASE_EDIT)
1381 this->m_RebaseStage = REBASE_EDIT ;
1382 return -1; // Edit return -1 to stop rebase.
1385 // Squash Case
1386 if(CheckNextCommitIsSquash())
1387 { // no squash
1388 // let user edit last commmit message
1389 this->m_RebaseStage = REBASE_SQUASH_EDIT;
1390 return -1;
1392 else if(mode == CTGitPath::LOGACTIONS_REBASE_SQUASH)
1393 pRev->GetAction(&m_CommitList)|= CTGitPath::LOGACTIONS_REBASE_DONE;
1396 return 0;
1399 BOOL CRebaseDlg::IsEnd()
1401 if(m_CommitList.m_IsOldFirst)
1402 return m_CurrentRebaseIndex>= this->m_CommitList.GetItemCount();
1403 else
1404 return m_CurrentRebaseIndex<0;
1407 int CRebaseDlg::RebaseThread()
1409 int ret=0;
1410 while(1)
1412 if( m_RebaseStage == REBASE_START )
1414 if( this->StartRebase() )
1416 InterlockedExchange(&m_bThreadRunning, FALSE);
1417 ret = -1;
1418 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
1419 break;
1421 m_RebaseStage = REBASE_CONTINUE;
1424 else if( m_RebaseStage == REBASE_CONTINUE )
1426 this->GoNext();
1427 UpdateCurrentStatus();
1428 if(IsEnd())
1430 ret = 0;
1431 m_RebaseStage = REBASE_FINISH;
1434 else
1436 ret = DoRebase();
1438 if( ret )
1440 break;
1445 else if( m_RebaseStage == REBASE_FINISH )
1447 FinishRebase();
1448 m_RebaseStage = REBASE_DONE;
1449 if (m_pTaskbarList)
1450 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
1451 break;
1454 else
1456 break;
1458 this->PostMessage(MSG_REBASE_UPDATE_UI);
1459 //this->UpdateCurrentStatus();
1462 InterlockedExchange(&m_bThreadRunning, FALSE);
1463 this->PostMessage(MSG_REBASE_UPDATE_UI);
1464 return ret;
1467 void CRebaseDlg::ListConflictFile()
1469 this->m_FileListCtrl.Clear();
1470 CTGitPathList list;
1471 CTGitPath path;
1472 list.AddPath(path);
1474 m_FileListCtrl.m_bIsRevertTheirMy = !m_IsCherryPick;
1476 this->m_FileListCtrl.GetStatus(&list,true);
1477 this->m_FileListCtrl.Show(CTGitPath::LOGACTIONS_UNMERGED|CTGitPath::LOGACTIONS_MODIFIED|CTGitPath::LOGACTIONS_ADDED|CTGitPath::LOGACTIONS_DELETED,
1478 CTGitPath::LOGACTIONS_UNMERGED);
1481 LRESULT CRebaseDlg::OnRebaseUpdateUI(WPARAM,LPARAM)
1483 UpdateCurrentStatus();
1484 if(m_CurrentRebaseIndex <0)
1485 return 0;
1486 if(m_CurrentRebaseIndex >= m_CommitList.GetItemCount() )
1487 return 0;
1488 GitRev *curRev=(GitRev*)m_CommitList.m_arShownList[m_CurrentRebaseIndex];
1490 switch(m_RebaseStage)
1492 case REBASE_CONFLICT:
1493 case REBASE_SQUASH_CONFLICT:
1494 ListConflictFile();
1495 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_CONFLICT);
1496 if (m_pTaskbarList)
1497 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
1498 this->m_LogMessageCtrl.SetText(curRev->GetSubject()+_T("\n")+curRev->GetBody());
1499 this->m_LogMessageCtrl.Call(SCI_SETREADONLY, FALSE);
1500 break;
1501 case REBASE_EDIT:
1502 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
1503 if (m_pTaskbarList)
1504 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_PAUSED);
1505 this->m_LogMessageCtrl.SetText(curRev->GetSubject()+_T("\n")+curRev->GetBody());
1506 this->m_LogMessageCtrl.Call(SCI_SETREADONLY, FALSE);
1507 break;
1508 case REBASE_SQUASH_EDIT:
1509 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_MESSAGE);
1510 this->m_LogMessageCtrl.SetText(this->m_SquashMessage);
1511 this->m_LogMessageCtrl.Call(SCI_SETREADONLY, FALSE);
1512 if (m_pTaskbarList)
1513 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_PAUSED);
1514 break;
1515 default:
1516 this->m_ctrlTabCtrl.SetActiveTab(REBASE_TAB_LOG);
1518 return 0;
1520 void CRebaseDlg::OnCancel()
1522 OnBnClickedAbort();
1524 void CRebaseDlg::OnBnClickedAbort()
1526 if (m_pTaskbarList)
1527 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
1529 CString cmd,out;
1530 CString pron = m_OrigUpstreamHash.ToString();
1531 if(m_OrigUpstreamHash.IsEmpty())
1533 __super::OnCancel();
1536 if(m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage== CHOOSE_COMMIT_PICK_MODE)
1538 return;
1541 if(CMessageBox::Show(NULL,_T("Are you sure you want to abort the rebase process?"),_T("TortoiseGit"),MB_YESNO) != IDYES)
1542 return;
1544 if(this->m_IsFastForward)
1546 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigBranchHash.ToString());
1547 if(g_Git.Run(cmd,&out,CP_UTF8))
1549 AddLogString(out);
1550 return ;
1552 __super::OnCancel();
1553 return;
1555 cmd.Format(_T("git.exe checkout -f %s"),g_Git.FixBranchName(this->m_UpstreamCtrl.GetString()));
1556 if(g_Git.Run(cmd,&out,CP_UTF8))
1558 AddLogString(out);
1559 return ;
1562 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigUpstreamHash.ToString());
1563 if(g_Git.Run(cmd,&out,CP_UTF8))
1565 AddLogString(out);
1566 return ;
1569 if(this->m_IsCherryPick) //there are not "branch" at cherry pick mode
1571 __super::OnCancel();
1572 return;
1575 cmd.Format(_T("git checkout -f %s"),this->m_BranchCtrl.GetString());
1576 if(g_Git.Run(cmd,&out,CP_UTF8))
1578 AddLogString(out);
1579 return ;
1582 cmd.Format(_T("git.exe reset --hard %s"),this->m_OrigBranchHash.ToString());
1583 if(g_Git.Run(cmd,&out,CP_UTF8))
1585 AddLogString(out);
1586 return ;
1588 __super::OnCancel();
1591 void CRebaseDlg::OnBnClickedButtonBrowse()
1593 if(CBrowseRefsDlg::PickRefForCombo(&m_UpstreamCtrl, gPickRef_NoTag))
1594 OnCbnSelchangeUpstream();
1597 void CRebaseDlg::OnBnClickedRebaseCheckForce()
1599 this->UpdateData();
1600 this->FetchLogList();
1601 if(this->CheckRebaseCondition())
1603 /* Disable Start Rebase */
1604 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1608 void CRebaseDlg::OnBnClickedRebasePostButton()
1610 this->m_Upstream=this->m_UpstreamCtrl.GetString();
1611 this->m_Branch=this->m_BranchCtrl.GetString();
1613 this->EndDialog(IDC_REBASE_POST_BUTTON+this->m_PostButton.GetCurrentEntry());
1616 void CRebaseDlg::Refresh()
1618 if(this->m_IsCherryPick)
1619 return ;
1621 if(this->m_RebaseStage == CHOOSE_BRANCH )
1623 this->UpdateData();
1624 this->FetchLogList();
1625 if(this->CheckRebaseCondition())
1627 /* Disable Start Rebase */
1628 this->GetDlgItem(IDC_REBASE_CONTINUE)->EnableWindow(FALSE);
1633 void CRebaseDlg::OnBnClickedButtonUp2()
1635 POSITION pos;
1636 pos = m_CommitList.GetFirstSelectedItemPosition();
1638 // do nothing if the first selected item is the first item in the list
1639 if (m_CommitList.GetNextSelectedItem(pos) == 0)
1640 return;
1642 pos = m_CommitList.GetFirstSelectedItemPosition();
1644 bool changed = false;
1645 while(pos)
1647 int index=m_CommitList.GetNextSelectedItem(pos);
1648 if(index>=1)
1650 CGitHash old = m_CommitList.m_logEntries[index-1];
1651 m_CommitList.m_logEntries[index-1] = m_CommitList.m_logEntries[index];
1652 m_CommitList.m_logEntries[index] = old;
1653 m_CommitList.SetItemState(index-1, LVIS_SELECTED, LVIS_SELECTED);
1654 m_CommitList.SetItemState(index, 0, LVIS_SELECTED);
1655 changed = true;
1658 if (changed)
1660 m_CommitList.RecalculateShownList(&m_CommitList.m_arShownList);
1661 m_CommitList.Invalidate();
1662 m_CommitList.SetFocus();
1666 void CRebaseDlg::OnBnClickedButtonDown2()
1668 if (m_CommitList.GetSelectedCount() == 0)
1669 return;
1671 POSITION pos;
1672 pos = m_CommitList.GetFirstSelectedItemPosition();
1673 bool changed = false;
1674 // use an array to store all selected item indexes; the user won't select too much items
1675 int* indexes = NULL;
1676 indexes = new int[m_CommitList.GetSelectedCount()];
1677 int i = 0;
1678 while(pos)
1680 indexes[i++] = m_CommitList.GetNextSelectedItem(pos);
1682 // don't move any item if the last selected item is the last item in the m_CommitList
1683 // (that would change the order of the selected items)
1684 if(indexes[m_CommitList.GetSelectedCount() - 1] < m_CommitList.GetItemCount() - 1)
1686 // iterate over the indexes backwards in order to correctly move multiselected items
1687 for (i = m_CommitList.GetSelectedCount() - 1; i >= 0; i--)
1689 int index = indexes[i];
1690 CGitHash old = m_CommitList.m_logEntries[index+1];
1691 m_CommitList.m_logEntries[index+1] = m_CommitList.m_logEntries[index];
1692 m_CommitList.m_logEntries[index] = old;
1693 m_CommitList.SetItemState(index, 0, LVIS_SELECTED);
1694 m_CommitList.SetItemState(index+1, LVIS_SELECTED, LVIS_SELECTED);
1695 changed = true;
1698 delete [] indexes;
1699 indexes = NULL;
1700 if (changed)
1702 m_CommitList.RecalculateShownList(&m_CommitList.m_arShownList);
1703 m_CommitList.Invalidate();
1704 m_CommitList.SetFocus();
1708 LRESULT CRebaseDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
1710 m_pTaskbarList.Release();
1711 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
1712 return 0;
1715 void CRebaseDlg::OnLvnItemchangedLoglist(NMHDR *pNMHDR, LRESULT *pResult)
1717 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
1718 *pResult = 0;
1719 if(m_CommitList.m_bNoDispUpdates)
1720 return;
1721 if (pNMLV->iItem >= 0)
1723 this->m_CommitList.m_nSearchIndex = pNMLV->iItem;
1724 if (pNMLV->iSubItem != 0)
1725 return;
1726 if ((pNMLV->iItem == m_CommitList.m_arShownList.GetCount()))
1728 // remove the selected state
1729 if (pNMLV->uChanged & LVIF_STATE)
1731 m_CommitList.SetItemState(pNMLV->iItem, 0, LVIS_SELECTED);
1732 FillLogMessageCtrl();
1734 return;
1736 if (pNMLV->uChanged & LVIF_STATE)
1738 FillLogMessageCtrl();
1741 else
1743 FillLogMessageCtrl();
1747 void CRebaseDlg::FillLogMessageCtrl()
1749 int selCount = m_CommitList.GetSelectedCount();
1750 if (selCount == 1 && (m_RebaseStage == CHOOSE_BRANCH || m_RebaseStage == CHOOSE_COMMIT_PICK_MODE))
1752 POSITION pos = m_CommitList.GetFirstSelectedItemPosition();
1753 int selIndex = m_CommitList.GetNextSelectedItem(pos);
1754 GitRev* pLogEntry = reinterpret_cast<GitRev *>(m_CommitList.m_arShownList.SafeGetAt(selIndex));
1755 m_FileListCtrl.UpdateWithGitPathList(pLogEntry->GetFiles(&m_CommitList));
1756 m_FileListCtrl.m_CurrentVersion = pLogEntry->m_CommitHash;
1757 m_FileListCtrl.Show(GITSLC_SHOWVERSIONED);
1758 m_LogMessageCtrl.Call(SCI_SETREADONLY, FALSE);
1759 m_LogMessageCtrl.SetText(pLogEntry->GetSubject() + _T("\n") + pLogEntry->GetBody());
1760 m_LogMessageCtrl.Call(SCI_SETREADONLY, TRUE);