1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2012, 2018 - TortoiseSVN
4 // Copyright (C) 2012-2016, 2018 - TortoiseGit
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 #include "TortoiseProc.h"
22 #include "RevisionGraphDlg.h"
25 #include "StringUtils.h"
27 #include "UnicodeUtils.h"
29 //#include "SVNInfo.h"
30 //#include "SVNDiff.h"
31 #include "RevGraphFilterDlg.h"
32 //#include "RepositoryInfo.h"
33 //#include "RevisionInRange.h"
34 //#include "RemovePathsBySubString.h"
40 static char THIS_FILE
[] = __FILE__
;
43 using namespace Gdiplus
;
51 //WORD aItems[wItemCount]
55 return (WORD
*)(this + 1);
59 IMPLEMENT_DYNAMIC(CRevisionGraphDlg
, CResizableStandAloneDialog
)
60 CRevisionGraphDlg::CRevisionGraphDlg(CWnd
* pParent
/*=nullptr*/)
61 : CResizableStandAloneDialog(CRevisionGraphDlg::IDD
, pParent
)
64 , m_fZoomFactor(DEFAULT_ZOOM
)
67 // GDI+ initialization
69 GdiplusStartupInput input
;
70 GdiplusStartup(&m_gdiPlusToken
, &input
, nullptr);
72 // restore option state
74 // DWORD dwOpts = CRegStdDWORD(L"Software\\TortoiseGit\\RevisionGraphOptions", 0x1ff199);
75 // m_Graph.m_state.GetOptions()->SetRegistryFlags (dwOpts, 0x407fbf);
81 CRevisionGraphDlg::~CRevisionGraphDlg()
85 CRegStdDWORD regOpts
= CRegStdDWORD(L
"Software\\TortoiseGit\\RevisionGraphOptions", 1);
86 // regOpts = m_Graph.m_state.GetOptions()->GetRegistryFlags();
90 GdiplusShutdown (m_gdiPlusToken
);
93 void CRevisionGraphDlg::DoDataExchange(CDataExchange
* pDX
)
95 CResizableStandAloneDialog::DoDataExchange(pDX
);
99 BEGIN_MESSAGE_MAP(CRevisionGraphDlg
, CResizableStandAloneDialog
)
103 ON_COMMAND(ID_VIEW_ZOOMIN
, OnViewZoomin
)
104 ON_COMMAND(ID_VIEW_ZOOMOUT
, OnViewZoomout
)
105 ON_COMMAND(ID_VIEW_ZOOM100
, OnViewZoom100
)
106 ON_COMMAND(ID_VIEW_ZOOMHEIGHT
, OnViewZoomHeight
)
107 ON_COMMAND(ID_VIEW_ZOOMWIDTH
, OnViewZoomWidth
)
108 ON_COMMAND(ID_VIEW_ZOOMALL
, OnViewZoomAll
)
109 ON_CBN_SELCHANGE(ID_REVGRAPH_ZOOMCOMBO
, OnChangeZoom
)
110 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW
, 0, 0xFFFF, OnToolTipNotify
)
111 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA
, 0, 0xFFFF, OnToolTipNotify
)
112 ON_COMMAND(ID_MENUEXIT
, OnMenuexit
)
113 ON_COMMAND(ID_MENUHELP
, OnMenuhelp
)
114 ON_COMMAND(ID_FILE_SAVEGRAPHAS
, OnFileSavegraphas
)
115 ON_COMMAND(ID_VIEW_SHOWOVERVIEW
, OnViewShowoverview
)
116 ON_COMMAND(ID_VIEW_FILTER
, OnViewFilter
)
117 ON_COMMAND(ID_VIEW_COMPAREHEADREVISIONS
, OnViewCompareheadrevisions
)
118 ON_COMMAND(ID_VIEW_COMPAREREVISIONS
, OnViewComparerevisions
)
119 ON_COMMAND(ID_VIEW_UNIFIEDDIFF
, OnViewUnifieddiff
)
120 ON_COMMAND(ID_VIEW_UNIFIEDDIFFOFHEADREVISIONS
, OnViewUnifieddiffofheadrevisions
)
123 ON_COMMAND_EX(ID_VIEW_SHOWALLREVISIONS
, OnToggleOption
)
124 ON_COMMAND_EX(ID_VIEW_GROUPBRANCHES
, OnToggleOption
)
125 ON_COMMAND_EX(ID_VIEW_TOPDOWN
, OnToggleOption
)
126 ON_COMMAND_EX(ID_VIEW_TOPALIGNTREES
, OnToggleOption
)
127 ON_COMMAND_EX(ID_VIEW_SHOWHEAD
, OnToggleOption
)
128 ON_COMMAND_EX(ID_VIEW_EXACTCOPYSOURCE
, OnToggleOption
)
129 ON_COMMAND_EX(ID_VIEW_FOLDTAGS
, OnToggleOption
)
130 ON_COMMAND_EX(ID_VIEW_REDUCECROSSLINES
, OnToggleOption
)
131 ON_COMMAND_EX(ID_VIEW_REMOVEDELETEDONES
, OnToggleOption
)
132 ON_COMMAND_EX(ID_VIEW_SHOWWCREV
, OnToggleReloadOption
)
133 ON_COMMAND_EX(ID_VIEW_REMOVEUNCHANGEDBRANCHES
, OnToggleOption
)
134 ON_COMMAND_EX(ID_VIEW_REMOVETAGS
, OnToggleOption
)
135 ON_COMMAND_EX(ID_VIEW_SHOWWCMODIFICATION
, OnToggleReloadOption
)
136 ON_COMMAND_EX(ID_VIEW_SHOWDIFFPATHS
, OnToggleOption
)
137 ON_COMMAND_EX(ID_VIEW_SHOWTREESTRIPES
, OnToggleRedrawOption
)
139 ON_WM_WINDOWPOSCHANGING()
143 BOOL
CRevisionGraphDlg::InitializeToolbar()
145 // set up the toolbar
146 // add the tool bar to the dialog
147 m_ToolBar
.CreateEx(this, TBSTYLE_FLAT
| TBSTYLE_WRAPABLE
| TBSTYLE_TRANSPARENT
| CBRS_SIZE_DYNAMIC
);
149 // LoadToolBar() asserts in debug mode because the bitmap
150 // fails to load. That's not a problem because we load the bitmap
151 // further down manually.
152 // but the assertion is ugly, so we load the button resource here
153 // manually as well and call SetButtons().
154 HINSTANCE hInst
= AfxFindResourceHandle(MAKEINTRESOURCE(IDR_REVGRAPHBAR
), RT_TOOLBAR
);
155 HRSRC hRsrc
= ::FindResource(hInst
, MAKEINTRESOURCE(IDR_REVGRAPHBAR
), RT_TOOLBAR
);
159 HGLOBAL hGlobal
= LoadResource(hInst
, hRsrc
);
163 auto pData
= reinterpret_cast<CToolBarData
*>(LockResource(hGlobal
));
166 ASSERT(pData
->wVersion
== 1);
168 auto pItems
= std::make_unique
<UINT
[]>(pData
->wItemCount
);
169 for (int i
= 0; i
< pData
->wItemCount
; ++i
)
170 pItems
[i
] = pData
->items()[i
];
171 m_ToolBar
.SetButtons(pItems
.get(), pData
->wItemCount
);
173 UnlockResource(hGlobal
);
174 FreeResource(hGlobal
);
176 m_ToolBar
.ShowWindow(SW_SHOW
);
177 m_ToolBar
.SetBarStyle(CBRS_ALIGN_TOP
| CBRS_TOOLTIPS
| CBRS_FLYBY
);
179 // toolbars aren't true-color without some tweaking:
181 CImageList cImageList
;
185 // load the toolbar with the dimensions of the bitmap itself
186 cBitmap
.Attach(LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_REVGRAPHBAR
),
188 LR_DEFAULTSIZE
| LR_CREATEDIBSECTION
));
189 cBitmap
.GetBitmap(&bmBitmap
);
190 cBitmap
.DeleteObject();
191 // now load the toolbar again, but this time with the dpi-scaled dimensions
192 // note: we could just load it once and then resize the bitmap, but
193 // that's not faster. So loading it again is what we do.
194 cBitmap
.Attach(LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_REVGRAPHBAR
),
196 CDPIAware::Instance().ScaleX(bmBitmap
.bmWidth
),
197 CDPIAware::Instance().ScaleY(bmBitmap
.bmHeight
),
198 LR_CREATEDIBSECTION
));
199 cBitmap
.GetBitmap(&bmBitmap
);
202 CSize
cSize(bmBitmap
.bmWidth
, bmBitmap
.bmHeight
);
203 int nNbBtn
= cSize
.cx
/ CDPIAware::Instance().ScaleX(20);
204 RGBTRIPLE
* rgb
= (RGBTRIPLE
*)(bmBitmap
.bmBits
);
205 COLORREF rgbMask
= RGB(rgb
[0].rgbtRed
, rgb
[0].rgbtGreen
, rgb
[0].rgbtBlue
);
207 cImageList
.Create(CDPIAware::Instance().ScaleX(20), cSize
.cy
, ILC_COLOR32
| ILC_MASK
, nNbBtn
, 0);
208 cImageList
.Add(&cBitmap
, rgbMask
);
209 // set the sizes of the button and images:
210 // note: buttonX must be 7 pixels more than imageX, and buttonY must be 6 pixels more than imageY.
211 // See the source of SetSizes().
212 m_ToolBar
.SetSizes(CSize(CDPIAware::Instance().ScaleX(27), CDPIAware::Instance().ScaleY(26)),
213 CSize(CDPIAware::Instance().ScaleX(20), CDPIAware::Instance().ScaleY(20)));
214 m_ToolBar
.SendMessage(TB_SETIMAGELIST
, 0, (LPARAM
)cImageList
.m_hImageList
);
219 RepositionBars(AFX_IDW_CONTROLBAR_FIRST
, AFX_IDW_CONTROLBAR_LAST
, 0);
221 #define SNAP_WIDTH CDPIAware::Instance().ScaleX(60) //the width of the combo box
222 // set up the ComboBox control as a snap mode select box
223 // First get the index of the placeholders position in the toolbar
224 int zoomComboIndex
= 0;
225 while (m_ToolBar
.GetItemID(zoomComboIndex
) != ID_REVGRAPH_ZOOMCOMBO
) ++zoomComboIndex
;
227 // next convert that button to a separator and get its position
228 m_ToolBar
.SetButtonInfo(zoomComboIndex
, ID_REVGRAPH_ZOOMCOMBO
, TBBS_SEPARATOR
,
231 m_ToolBar
.GetItemRect(zoomComboIndex
, &rect
);
233 // expand the rectangle to allow the combo box room to drop down
234 rect
.top
+= CDPIAware::Instance().ScaleY(3);
235 rect
.bottom
+= CDPIAware::Instance().ScaleY(200);
237 // then create the combo box and show it
238 if (!m_ToolBar
.m_ZoomCombo
.CreateEx(WS_EX_RIGHT
, WS_CHILD
|WS_VISIBLE
|CBS_AUTOHSCROLL
|CBS_DROPDOWN
,
239 rect
, &m_ToolBar
, ID_REVGRAPH_ZOOMCOMBO
))
241 CTraceToOutputDebugString::Instance()(__FUNCTION__
": Failed to create combo-box\n");
244 m_ToolBar
.m_ZoomCombo
.ShowWindow(SW_SHOW
);
246 // fill the combo box
248 TCHAR
* texts
[] = { L
"5%"
258 COMBOBOXEXITEM cbei
= { 0 };
259 cbei
.mask
= CBEIF_TEXT
;
261 for (TCHAR
** text
= texts
; *text
; ++text
)
263 cbei
.pszText
= *text
;
264 m_ToolBar
.m_ZoomCombo
.InsertItem(&cbei
);
267 m_ToolBar
.m_ZoomCombo
.SetCurSel(1);
269 UpdateOptionAvailability();
274 BOOL
CRevisionGraphDlg::OnInitDialog()
276 CResizableStandAloneDialog::OnInitDialog();
277 CAppUtils::MarkWindowAsUnpinnable(m_hWnd
);
281 CString sWindowTitle
;
282 GetWindowText(sWindowTitle
);
283 CAppUtils::SetWindowTitle(m_hWnd
, g_Git
.m_CurrentDir
, sWindowTitle
);
286 // set up the status bar
287 m_StatusBar
.Create(WS_CHILD
|WS_VISIBLE
|SBT_OWNERDRAW
,
288 CRect(0,0,0,0), this, 1);
289 int strPartDim
[2]= {120, -1};
290 m_StatusBar
.SetParts(2, strPartDim
);
292 if (InitializeToolbar() != TRUE
)
295 m_pTaskbarList
.Release();
296 if (FAILED(m_pTaskbarList
.CoCreateInstance(CLSID_TaskbarList
)))
297 m_pTaskbarList
= nullptr;
299 // CSyncPointer<CAllRevisionGraphOptions>
300 // options (m_Graph.m_state.GetOptions());
302 // for (size_t i = 0; i < options->count(); ++i)
303 // if ((*options)[i]->CommandID() != 0)
304 // SetOption ((*options)[i]->CommandID());
307 CMenu
* pMenu
= GetMenu();
310 CRegDWORD
reg(L
"Software\\TortoiseGit\\ShowRevGraphOverview", FALSE
);
311 m_Graph
.SetShowOverview ((DWORD
)reg
!= FALSE
);
312 pMenu
->CheckMenuItem(ID_VIEW_SHOWOVERVIEW
, MF_BYCOMMAND
| (DWORD(reg
) ? MF_CHECKED
: 0));
313 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(ID_VIEW_SHOWOVERVIEW
);
314 m_ToolBar
.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW
, tbstate
| (DWORD(reg
) ? TBSTATE_CHECKED
: 0));
318 // m_hAccel = LoadAccelerators(AfxGetResourceHandle(),MAKEINTRESOURCE(IDR_ACC_REVISIONGRAPH));
321 CRect graphrect
= GetGraphRect();
322 m_Graph
.Init(this, &graphrect
);
323 m_Graph
.SetOwner(this);
324 m_Graph
.UpdateWindow();
325 DoZoom (DEFAULT_ZOOM
);
327 // begin background operation
330 EnableSaveRestore(L
"RevisionGraphDlg");
331 // if (GetExplorerHWND())
332 // CenterWindow(CWnd::FromHandle(GetExplorerHWND()));
334 return TRUE
; // return TRUE unless you set the focus to a control
337 bool CRevisionGraphDlg::UpdateData()
339 CoInitialize(nullptr);
341 if (!m_Graph
.FetchRevisionData (m_Graph
.m_sPath
, nullptr, m_pTaskbarList
, m_hWnd
))
343 // only show the error dialog if we're not in hidden mode
346 // TGitMessageBox( m_hWnd
347 // , // m_Graph.m_state.GetLastErrorMessage()
356 CProgressDlg progress
;
357 progress
.SetTitle(IDS_REVGRAPH_PROGTITLE
);
358 progress
.SetCancelMsg(IDS_REVGRAPH_PROGCANCEL
);
360 progress
.SetProgress(0, 100);
363 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NORMAL
);
364 m_pTaskbarList
->SetProgressValue(m_hWnd
, 0, 100);
367 svn_revnum_t pegRev
= m_Graph
.m_pegRev
.IsNumber()
368 ? (svn_revnum_t
)m_Graph
.m_pegRev
371 if (!m_Graph
.FetchRevisionData (m_Graph
.m_sPath
, pegRev
, &progress
, m_pTaskbarList
, m_hWnd
))
373 // only show the error dialog if we're not in hidden mode
376 TSVNMessageBox( m_hWnd
377 , m_Graph
.m_state
.GetLastErrorMessage()
386 m_pTaskbarList
->SetProgressState(m_hWnd
, TBPF_NOPROGRESS
);
389 m_bFetchLogs
= false; // we've got the logs, no need to fetch them a second time
392 // standard plus user settings
395 if (m_Graph
.AnalyzeRevisionData())
398 UpdateOptionAvailability();
403 m_Graph
.PostMessage (CRevisionGraphWnd::WM_WORKERTHREADDONE
, 0, 0);
408 void CRevisionGraphDlg::OnSize(UINT nType
, int cx
, int cy
)
410 __super::OnSize(nType
, cx
, cy
);
412 GetClientRect(&rect
);
413 if (IsWindow(m_ToolBar
))
415 RepositionBars(AFX_IDW_CONTROLBAR_FIRST
, AFX_IDW_CONTROLBAR_LAST
, 0);
417 if (IsWindow(m_StatusBar
))
420 m_StatusBar
.GetClientRect(&statusbarrect
);
421 statusbarrect
.top
= rect
.bottom
- statusbarrect
.top
+ statusbarrect
.bottom
;
422 m_StatusBar
.MoveWindow(&statusbarrect
);
424 if (IsWindow(m_Graph
))
426 m_Graph
.MoveWindow (GetGraphRect());
430 BOOL
CRevisionGraphDlg::PreTranslateMessage(MSG
* pMsg
)
432 #define SCROLL_STEP 20
433 if (pMsg
->message
== WM_KEYDOWN
)
436 switch (pMsg
->wParam
)
439 pos
= m_Graph
.GetScrollPos(SB_VERT
);
440 m_Graph
.SetScrollPos(SB_VERT
, pos
- SCROLL_STEP
);
441 m_Graph
.Invalidate();
444 pos
= m_Graph
.GetScrollPos(SB_VERT
);
445 m_Graph
.SetScrollPos(SB_VERT
, pos
+ SCROLL_STEP
);
446 m_Graph
.Invalidate();
449 pos
= m_Graph
.GetScrollPos(SB_HORZ
);
450 m_Graph
.SetScrollPos(SB_HORZ
, pos
- SCROLL_STEP
);
451 m_Graph
.Invalidate();
454 pos
= m_Graph
.GetScrollPos(SB_HORZ
);
455 m_Graph
.SetScrollPos(SB_HORZ
, pos
+ SCROLL_STEP
);
456 m_Graph
.Invalidate();
459 pos
= m_Graph
.GetScrollPos(SB_VERT
);
460 m_Graph
.SetScrollPos(SB_VERT
, pos
- GetGraphRect().Height() / 2);
461 m_Graph
.Invalidate();
464 pos
= m_Graph
.GetScrollPos(SB_VERT
);
465 m_Graph
.SetScrollPos(SB_VERT
, pos
+ GetGraphRect().Height() / 2);
466 m_Graph
.Invalidate();
473 if ((m_hAccel
)&&(pMsg
->message
>= WM_KEYFIRST
&& pMsg
->message
<= WM_KEYLAST
))
475 if (pMsg
->wParam
== VK_ESCAPE
)
476 if (m_Graph
.CancelMouseZoom())
478 return TranslateAccelerator(m_hWnd
,m_hAccel
,pMsg
);
480 return __super::PreTranslateMessage(pMsg
);
483 void CRevisionGraphDlg::DoZoom (float zoom
)
485 m_fZoomFactor
= zoom
;
486 m_Graph
.DoZoom (zoom
);
490 void CRevisionGraphDlg::OnViewZoomin()
492 DoZoom (min (MAX_ZOOM
, m_fZoomFactor
/ ZOOM_STEP
));
495 void CRevisionGraphDlg::OnViewZoomout()
497 DoZoom (max (MIN_ZOOM
, m_fZoomFactor
* ZOOM_STEP
));
500 void CRevisionGraphDlg::OnViewZoom100()
502 DoZoom (DEFAULT_ZOOM
);
505 void CRevisionGraphDlg::OnViewZoomHeight()
507 CRect graphRect
= m_Graph
.GetGraphRect();
508 CRect windowRect
= m_Graph
.GetWindowRect();
510 float horzfact
= (windowRect
.Width() - 4.0f
)/(4.0f
+ graphRect
.Width());
511 float vertfact
= (windowRect
.Height() - 4.0f
)/(4.0f
+ graphRect
.Height());
512 if ((horzfact
< vertfact
) && (horzfact
< MAX_ZOOM
))
513 vertfact
= (windowRect
.Height() - CDPIAware::Instance().ScaleY(20)) / (4.0f
+ graphRect
.Height());
515 DoZoom (min (MAX_ZOOM
, vertfact
));
518 void CRevisionGraphDlg::OnViewZoomWidth()
520 // zoom the graph so that it is completely visible in the window
521 CRect graphRect
= m_Graph
.GetGraphRect();
522 CRect windowRect
= m_Graph
.GetWindowRect();
524 float horzfact
= (windowRect
.Width() - 4.0f
)/(4.0f
+ graphRect
.Width());
525 float vertfact
= (windowRect
.Height() - 4.0f
)/(4.0f
+ graphRect
.Height());
526 if ((vertfact
< horzfact
) && (vertfact
< MAX_ZOOM
))
527 horzfact
= (windowRect
.Width() - CDPIAware::Instance().ScaleX(20)) / (4.0f
+ graphRect
.Width());
529 DoZoom (min (MAX_ZOOM
, horzfact
));
532 void CRevisionGraphDlg::OnViewZoomAll()
534 // zoom the graph so that it is completely visible in the window
535 CRect graphRect
= m_Graph
.GetGraphRect();
536 CRect windowRect
= m_Graph
.GetWindowRect();
538 float horzfact
= (windowRect
.Width() - 4.0f
)/(4.0f
+ graphRect
.Width());
539 float vertfact
= (windowRect
.Height() - 4.0f
)/(4.0f
+ graphRect
.Height());
541 DoZoom (min (MAX_ZOOM
, min(horzfact
, vertfact
)));
544 void CRevisionGraphDlg::OnMenuexit()
546 if (!m_Graph
.IsUpdateJobRunning())
550 void CRevisionGraphDlg::OnMenuhelp()
555 void CRevisionGraphDlg::OnViewCompareheadrevisions()
557 m_Graph
.CompareRevs(L
"HEAD");
560 void CRevisionGraphDlg::OnViewComparerevisions()
562 m_Graph
.CompareRevs(false);
565 void CRevisionGraphDlg::OnViewUnifieddiff()
567 m_Graph
.UnifiedDiffRevs(false);
570 void CRevisionGraphDlg::OnViewUnifieddiffofheadrevisions()
572 m_Graph
.UnifiedDiffRevs(true);
575 void CRevisionGraphDlg::UpdateFullHistory()
577 m_Graph
.SetDlgTitle (false);
583 m_Graph
.SetDlgTitle (false);
586 LogCache::CRepositoryInfo
& cachedProperties
587 = svn
.GetLogCachePool()->GetRepositoryInfo();
588 CString root
= m_Graph
.m_state
.GetRepositoryRoot();
589 CString uuid
= m_Graph
.m_state
.GetRepositoryUUID();
591 cachedProperties
.ResetHeadRevision (uuid
, root
);
598 void CRevisionGraphDlg::SetOption (UINT
/*controlID*/)
601 CMenu
* pMenu
= GetMenu();
605 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(controlID
);
608 if (m_Graph
.m_state
.GetOptions()->IsSelected (controlID
))
610 pMenu
->CheckMenuItem(controlID
, MF_BYCOMMAND
| MF_CHECKED
);
611 m_ToolBar
.GetToolBarCtrl().SetState(controlID
, tbstate
| TBSTATE_CHECKED
);
615 pMenu
->CheckMenuItem(controlID
, MF_BYCOMMAND
| MF_UNCHECKED
);
616 m_ToolBar
.GetToolBarCtrl().SetState(controlID
, tbstate
& (~TBSTATE_CHECKED
));
622 BOOL
CRevisionGraphDlg::ToggleOption (UINT controlID
)
624 // check request for validity
626 if (m_Graph
.IsUpdateJobRunning())
628 // restore previous state
630 int state
= m_ToolBar
.GetToolBarCtrl().GetState(controlID
);
631 if (state
& TBSTATE_CHECKED
)
632 state
&= ~TBSTATE_CHECKED
;
634 state
|= TBSTATE_CHECKED
;
635 m_ToolBar
.GetToolBarCtrl().SetState (controlID
, state
);
640 CMenu
* pMenu
= GetMenu();
644 // actually toggle the option
646 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(controlID
);
647 UINT state
= pMenu
->GetMenuState(controlID
, MF_BYCOMMAND
);
648 if (state
& MF_CHECKED
)
650 pMenu
->CheckMenuItem(controlID
, MF_BYCOMMAND
| MF_UNCHECKED
);
651 m_ToolBar
.GetToolBarCtrl().SetState(controlID
, tbstate
& (~TBSTATE_CHECKED
));
655 pMenu
->CheckMenuItem(controlID
, MF_BYCOMMAND
| MF_CHECKED
);
656 m_ToolBar
.GetToolBarCtrl().SetState(controlID
, tbstate
| TBSTATE_CHECKED
);
659 // CSyncPointer<CAllRevisionGraphOptions>
660 // options (m_Graph.m_state.GetOptions());
661 // if (((state & MF_CHECKED) != 0) == options->IsSelected (controlID))
662 // options->ToggleSelection (controlID);
667 BOOL
CRevisionGraphDlg::OnToggleOption (UINT controlID
)
669 if (!ToggleOption (controlID
))
672 // re-process the data
679 BOOL
CRevisionGraphDlg::OnToggleReloadOption (UINT controlID
)
682 if (!m_Graph
.m_state
.GetFetchedWCState())
685 return OnToggleOption (controlID
);
688 BOOL
CRevisionGraphDlg::OnToggleRedrawOption (UINT controlID
)
690 if (!ToggleOption (controlID
))
693 m_Graph
.BuildPreview();
699 void CRevisionGraphDlg::StartWorkerThread()
701 if (!m_Graph
.IsUpdateJobRunning())
702 m_Graph
.updateJob
= std::make_unique
<CFuture
<bool>>(this, &CRevisionGraphDlg::UpdateData
);
705 void CRevisionGraphDlg::OnCancel()
707 if (!m_Graph
.IsUpdateJobRunning())
711 void CRevisionGraphDlg::OnOK()
716 void CRevisionGraphDlg::OnFileSavegraphas()
720 if (CAppUtils::FileOpenSave(tempfile
, &filterindex
, IDS_REVGRAPH_SAVEPIC
, IDS_PICTUREFILEFILTER
, false, m_hWnd
))
722 // if the user doesn't specify a file extension, default to
723 // svg and add that extension to the filename. But only if the
724 // user chose the 'pictures' filter. The filename isn't changed
725 // if the 'All files' filter was chosen.
727 int dotPos
= tempfile
.ReverseFind('.');
728 int slashPos
= tempfile
.ReverseFind('\\');
729 if (dotPos
> slashPos
)
730 extension
= tempfile
.Mid(dotPos
);
731 if ((filterindex
== 1)&&(extension
.IsEmpty()))
734 tempfile
+= extension
;
736 if ((filterindex
== 2)&&(extension
.IsEmpty()))
739 tempfile
+= extension
;
741 m_Graph
.SaveGraphAs(tempfile
);
745 CRect
CRevisionGraphDlg::GetGraphRect()
748 GetClientRect(&rect
);
751 m_StatusBar
.GetClientRect(&statusbarrect
);
752 rect
.bottom
-= statusbarrect
.Height();
755 m_ToolBar
.GetClientRect(&toolbarrect
);
756 rect
.top
+= toolbarrect
.Height();
761 void CRevisionGraphDlg::UpdateStatusBar()
764 // sFormat.Format(IDS_REVGRAPH_STATUSBARURL, (LPCTSTR)m_Graph.m_sPath);
765 // m_StatusBar.SetText(sFormat,1,0);
766 // sFormat.Format(IDS_REVGRAPH_STATUSBARNUMNODES, m_Graph.m_state.GetNodeCount());
767 // m_StatusBar.SetText(sFormat,0,0);
770 void CRevisionGraphDlg::OnChangeZoom()
772 if (!IsWindow(m_Graph
.GetSafeHwnd()))
775 CComboBoxEx
* pCBox
= (CComboBoxEx
*)m_ToolBar
.GetDlgItem(ID_REVGRAPH_ZOOMCOMBO
);
776 pCBox
->GetWindowText(strItem
);
777 if (strItem
.IsEmpty())
780 DoZoom ((float)(_wtof(strItem
) / 100.0));
783 void CRevisionGraphDlg::UpdateZoomBox()
787 CComboBoxEx
* pCBox
= (CComboBoxEx
*)m_ToolBar
.GetDlgItem(ID_REVGRAPH_ZOOMCOMBO
);
788 pCBox
->GetWindowText(strItem
);
789 strText
.Format(L
"%.0f%%", (m_fZoomFactor
* 100.0));
790 if (strText
.Compare(strItem
) != 0)
791 pCBox
->SetWindowText(strText
);
794 BOOL
CRevisionGraphDlg::OnToolTipNotify(UINT
/*id*/, NMHDR
*pNMHDR
, LRESULT
*pResult
)
796 // need to handle both ANSI and UNICODE versions of the message
797 TOOLTIPTEXTA
* pTTTA
= (TOOLTIPTEXTA
*)pNMHDR
;
798 TOOLTIPTEXTW
* pTTTW
= (TOOLTIPTEXTW
*)pNMHDR
;
801 UINT_PTR nID
= pNMHDR
->idFrom
;
803 if (pNMHDR
->code
== TTN_NEEDTEXTA
&& (pTTTA
->uFlags
& TTF_IDISHWND
) ||
804 pNMHDR
->code
== TTN_NEEDTEXTW
&& (pTTTW
->uFlags
& TTF_IDISHWND
))
806 // idFrom is actually the HWND of the tool
807 nID
= ::GetDlgCtrlID((HWND
)nID
);
810 if (nID
!= 0) // will be zero on a separator
811 strTipText
.LoadString (static_cast<UINT
>(nID
));
814 if (strTipText
.IsEmpty())
817 if (strTipText
.GetLength() >= MAX_TT_LENGTH
)
818 strTipText
= strTipText
.Left(MAX_TT_LENGTH
);
820 if (pNMHDR
->code
== TTN_NEEDTEXTA
)
822 ::SendMessage(pNMHDR
->hwndFrom
, TTM_SETMAXTIPWIDTH
, 0, 600);
823 pTTTA
->lpszText
= m_szTip
;
824 WideCharToMultiByte(CP_ACP
, 0, strTipText
, -1, m_szTip
, strTipText
.GetLength()+1, 0, 0);
828 ::SendMessage(pNMHDR
->hwndFrom
, TTM_SETMAXTIPWIDTH
, 0, 600);
829 lstrcpyn(m_wszTip
, strTipText
, strTipText
.GetLength()+1);
830 pTTTW
->lpszText
= m_wszTip
;
832 // bring the tooltip window above other pop up windows
833 ::SetWindowPos(pNMHDR
->hwndFrom
, HWND_TOP
, 0, 0, 0, 0,
834 SWP_NOACTIVATE
|SWP_NOSIZE
|SWP_NOMOVE
|SWP_NOOWNERZORDER
);
835 return TRUE
; // message was handled
838 void CRevisionGraphDlg::OnViewFilter()
840 /* CSyncPointer<CAllRevisionGraphOptions>
841 options (m_Graph.m_state.GetOptions());
843 CRevisionInRange* revisionRange = options->GetOption<CRevisionInRange>();
844 svn_revnum_t head = m_Graph.m_state.GetHeadRevision();
845 svn_revnum_t lowerLimit = revisionRange->GetLowerLimit();
846 svn_revnum_t upperLimit = revisionRange->GetUpperLimit();
848 CRemovePathsBySubString* pathFilter = options->GetOption<CRemovePathsBySubString>();
850 CRevGraphFilterDlg dlg
;
852 dlg
.m_bCurrentBranch
= this->m_Graph
.m_bCurrentBranch
;
853 dlg
.m_bLocalBranches
= m_Graph
.m_bLocalBranches
;
854 dlg
.SetRevisionRange(m_Graph
.m_FromRev
, m_Graph
.m_ToRev
);
856 if (dlg
.DoModal()==IDOK
)
858 // user pressed OK to dismiss the dialog, which means
859 // we have to accept the new filter settings and apply them
861 dlg
.GetRevisionRange(m_Graph
.m_FromRev
, m_Graph
.m_ToRev
);
862 // update menu & toolbar
864 this->m_Graph
.m_bCurrentBranch
= dlg
.m_bCurrentBranch
;
865 m_Graph
.m_bLocalBranches
= dlg
.m_bLocalBranches
;
867 CMenu
* pMenu
= GetMenu();
868 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(ID_VIEW_FILTER
);
869 if (m_Graph
.m_bCurrentBranch
|| m_Graph
.m_bLocalBranches
|| !m_Graph
.m_FromRev
.IsEmpty() || !m_Graph
.m_ToRev
.IsEmpty())
872 pMenu
->CheckMenuItem(ID_VIEW_FILTER
, MF_BYCOMMAND
| MF_CHECKED
);
873 m_ToolBar
.GetToolBarCtrl().SetState(ID_VIEW_FILTER
, tbstate
| TBSTATE_CHECKED
);
878 pMenu
->CheckMenuItem(ID_VIEW_FILTER
, MF_BYCOMMAND
| MF_UNCHECKED
);
879 m_ToolBar
.GetToolBarCtrl().SetState(ID_VIEW_FILTER
, tbstate
& (~TBSTATE_CHECKED
));
888 void CRevisionGraphDlg::OnViewShowoverview()
890 CMenu
* pMenu
= GetMenu();
893 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(ID_VIEW_SHOWOVERVIEW
);
894 UINT state
= pMenu
->GetMenuState(ID_VIEW_SHOWOVERVIEW
, MF_BYCOMMAND
);
895 if (state
& MF_CHECKED
)
897 pMenu
->CheckMenuItem(ID_VIEW_SHOWOVERVIEW
, MF_BYCOMMAND
| MF_UNCHECKED
);
898 m_ToolBar
.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW
, tbstate
& (~TBSTATE_CHECKED
));
899 m_Graph
.SetShowOverview (false);
903 pMenu
->CheckMenuItem(ID_VIEW_SHOWOVERVIEW
, MF_BYCOMMAND
| MF_CHECKED
);
904 m_ToolBar
.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW
, tbstate
| TBSTATE_CHECKED
);
905 m_Graph
.SetShowOverview (true);
908 CRegDWORD
reg(L
"Software\\TortoiseGit\\ShowRevGraphOverview", FALSE
);
909 reg
= m_Graph
.GetShowOverview();
910 m_Graph
.Invalidate(FALSE
);
913 void CRevisionGraphDlg::UpdateOptionAvailability (UINT id
, bool available
)
915 CMenu
* pMenu
= GetMenu();
919 pMenu
->EnableMenuItem (id
, available
? MF_ENABLED
: MF_GRAYED
);
921 int tbstate
= m_ToolBar
.GetToolBarCtrl().GetState(id
);
922 int newTbstate
= available
923 ? tbstate
| TBSTATE_ENABLED
924 : tbstate
& ~TBSTATE_ENABLED
;
926 if (tbstate
!= newTbstate
)
927 m_ToolBar
.GetToolBarCtrl().SetState(id
, newTbstate
);
930 void CRevisionGraphDlg::UpdateOptionAvailability()
933 bool multipleTrees
= m_Graph
.m_state
.GetTreeCount() > 1;
934 bool isWCPath
= !CTGitPath (m_Graph
.m_sPath
).IsUrl();
936 UpdateOptionAvailability (ID_VIEW_TOPALIGNTREES
, multipleTrees
);
937 UpdateOptionAvailability (ID_VIEW_SHOWTREESTRIPES
, multipleTrees
);
938 UpdateOptionAvailability (ID_VIEW_SHOWWCREV
, isWCPath
);
939 UpdateOptionAvailability (ID_VIEW_SHOWWCMODIFICATION
, isWCPath
);
945 void CRevisionGraphDlg::OnWindowPosChanging(WINDOWPOS
* lpwndpos
)
948 lpwndpos
->flags
&= ~SWP_SHOWWINDOW
;
949 CResizableStandAloneDialog::OnWindowPosChanging(lpwndpos
);