OSDN Git Service

Update RevisionGraph to 15570
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / RevisionGraph / RevisionGraphDlg.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2009 - TortoiseSVN\r
4 \r
5 // This program is free software; you can redistribute it and/or\r
6 // modify it under the terms of the GNU General Public License\r
7 // as published by the Free Software Foundation; either version 2\r
8 // of the License, or (at your option) any later version.\r
9 \r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 \r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, write to the Free Software Foundation,\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
18 //\r
19 #include "stdafx.h"\r
20 #include "TortoiseProc.h"\r
21 #include "Revisiongraphdlg.h"\r
22 #include "MessageBox.h"\r
23 #include "SVN.h"\r
24 #include "AppUtils.h"\r
25 #include "StringUtils.h"\r
26 #include "TempFile.h"\r
27 #include "UnicodeUtils.h"\r
28 #include "TSVNPath.h"\r
29 #include "SVNInfo.h"\r
30 #include "SVNDiff.h"\r
31 #include "RevGraphFilterDlg.h"\r
32 #include ".\revisiongraphdlg.h"\r
33 #include "RepositoryInfo.h"\r
34 #include "RevisionInRange.h"\r
35 #include "RemovePathsBySubString.h"\r
36 \r
37 #ifdef _DEBUG\r
38 #define new DEBUG_NEW\r
39 #undef THIS_FILE\r
40 static char THIS_FILE[] = __FILE__;\r
41 #endif\r
42 \r
43 using namespace Gdiplus;\r
44 \r
45 IMPLEMENT_DYNAMIC(CRevisionGraphDlg, CResizableStandAloneDialog)\r
46 CRevisionGraphDlg::CRevisionGraphDlg(CWnd* pParent /*=NULL*/)\r
47         : CResizableStandAloneDialog(CRevisionGraphDlg::IDD, pParent)\r
48         , m_hAccel(NULL)\r
49         , m_bFetchLogs(true)\r
50         , m_fZoomFactor(0.5)\r
51 {\r
52     // GDI+ initialization\r
53 \r
54     GdiplusStartupInput input;\r
55     GdiplusStartup (&m_gdiPlusToken, &input, NULL);\r
56 \r
57     // restore option state\r
58 \r
59         DWORD dwOpts = CRegStdDWORD(_T("Software\\TortoiseSVN\\RevisionGraphOptions"), 0x1ff199);\r
60     m_Graph.m_state.GetOptions()->SetRegistryFlags (dwOpts, 0x7fbf);\r
61 }\r
62 \r
63 CRevisionGraphDlg::~CRevisionGraphDlg()\r
64 {\r
65     // save option state\r
66 \r
67         CRegStdDWORD regOpts = CRegStdDWORD(_T("Software\\TortoiseSVN\\RevisionGraphOptions"), 1);\r
68     regOpts = m_Graph.m_state.GetOptions()->GetRegistryFlags();\r
69 \r
70     // GDI+ cleanup\r
71 \r
72     GdiplusShutdown (m_gdiPlusToken);\r
73 }\r
74 \r
75 void CRevisionGraphDlg::DoDataExchange(CDataExchange* pDX)\r
76 {\r
77         CResizableStandAloneDialog::DoDataExchange(pDX);\r
78 }\r
79 \r
80 \r
81 BEGIN_MESSAGE_MAP(CRevisionGraphDlg, CResizableStandAloneDialog)\r
82         ON_WM_SIZE()\r
83         ON_WM_LBUTTONDOWN()\r
84         ON_COMMAND(ID_VIEW_ZOOMIN, OnViewZoomin)\r
85         ON_COMMAND(ID_VIEW_ZOOMOUT, OnViewZoomout)\r
86         ON_COMMAND(ID_VIEW_ZOOM100, OnViewZoom100)\r
87         ON_COMMAND(ID_VIEW_ZOOMHEIGHT, OnViewZoomHeight)\r
88         ON_COMMAND(ID_VIEW_ZOOMWIDTH, OnViewZoomWidth)\r
89         ON_COMMAND(ID_VIEW_ZOOMALL, OnViewZoomAll)\r
90         ON_COMMAND(ID_MENUEXIT, OnMenuexit)\r
91         ON_COMMAND(ID_MENUHELP, OnMenuhelp)\r
92         ON_COMMAND(ID_VIEW_COMPAREHEADREVISIONS, OnViewCompareheadrevisions)\r
93         ON_COMMAND(ID_VIEW_COMPAREREVISIONS, OnViewComparerevisions)\r
94         ON_COMMAND(ID_VIEW_UNIFIEDDIFF, OnViewUnifieddiff)\r
95         ON_COMMAND(ID_VIEW_UNIFIEDDIFFOFHEADREVISIONS, OnViewUnifieddiffofheadrevisions)\r
96         ON_COMMAND(ID_FILE_SAVEGRAPHAS, OnFileSavegraphas)\r
97         ON_COMMAND_EX(ID_VIEW_SHOWALLREVISIONS, OnToggleOption)\r
98         ON_COMMAND_EX(ID_VIEW_GROUPBRANCHES, OnToggleOption)\r
99         ON_COMMAND_EX(ID_VIEW_TOPDOWN, OnToggleOption)\r
100     ON_COMMAND_EX(ID_VIEW_TOPALIGNTREES, OnToggleOption)\r
101         ON_COMMAND_EX(ID_VIEW_SHOWHEAD, OnToggleOption)\r
102         ON_COMMAND_EX(ID_VIEW_EXACTCOPYSOURCE, OnToggleOption)\r
103         ON_COMMAND_EX(ID_VIEW_FOLDTAGS, OnToggleOption)\r
104         ON_COMMAND_EX(ID_VIEW_REDUCECROSSLINES, OnToggleOption)\r
105         ON_COMMAND_EX(ID_VIEW_REMOVEDELETEDONES, OnToggleOption)\r
106         ON_COMMAND_EX(ID_VIEW_SHOWWCREV, OnToggleReloadOption)\r
107         ON_COMMAND_EX(ID_VIEW_REMOVEUNCHANGEDBRANCHES, OnToggleOption)\r
108     ON_COMMAND_EX(ID_VIEW_SHOWWCMODIFICATION, OnToggleReloadOption)\r
109     ON_COMMAND_EX(ID_VIEW_SHOWDIFFPATHS, OnToggleOption)\r
110     ON_COMMAND_EX(ID_VIEW_SHOWTREESTRIPES, OnToggleRedrawOption)\r
111         ON_CBN_SELCHANGE(ID_REVGRAPH_ZOOMCOMBO, OnChangeZoom)\r
112         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipNotify)\r
113         ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipNotify)\r
114         ON_COMMAND(ID_VIEW_FILTER, OnViewFilter)\r
115         ON_COMMAND(ID_VIEW_SHOWOVERVIEW, OnViewShowoverview)\r
116 END_MESSAGE_MAP()\r
117 \r
118 BOOL CRevisionGraphDlg::InitializeToolbar()\r
119 {\r
120         // set up the toolbar\r
121         // add the tool bar to the dialog\r
122         m_ToolBar.CreateEx(this, TBSTYLE_FLAT | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT | CBRS_SIZE_DYNAMIC);\r
123         m_ToolBar.LoadToolBar(IDR_REVGRAPHBAR);\r
124         m_ToolBar.ShowWindow(SW_SHOW);\r
125         m_ToolBar.SetBarStyle(CBRS_ALIGN_TOP | CBRS_TOOLTIPS | CBRS_FLYBY);\r
126 \r
127         // toolbars aren't true-color without some tweaking:\r
128         {\r
129                 CImageList      cImageList;\r
130                 CBitmap         cBitmap;\r
131                 BITMAP          bmBitmap;\r
132 \r
133                 cBitmap.Attach(LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_REVGRAPHBAR),\r
134                         IMAGE_BITMAP, 0, 0,\r
135                         LR_DEFAULTSIZE|LR_CREATEDIBSECTION));\r
136                 cBitmap.GetBitmap(&bmBitmap);\r
137 \r
138                 CSize           cSize(bmBitmap.bmWidth, bmBitmap.bmHeight); \r
139                 int                     nNbBtn = cSize.cx/20;\r
140                 RGBTRIPLE *     rgb     = (RGBTRIPLE*)(bmBitmap.bmBits);\r
141                 COLORREF        rgbMask = RGB(rgb[0].rgbtRed, rgb[0].rgbtGreen, rgb[0].rgbtBlue);\r
142 \r
143                 cImageList.Create(20, cSize.cy, ILC_COLOR32|ILC_MASK, nNbBtn, 0);\r
144                 cImageList.Add(&cBitmap, rgbMask);\r
145                 m_ToolBar.SendMessage(TB_SETIMAGELIST, 0, (LPARAM)cImageList.m_hImageList);\r
146                 cImageList.Detach(); \r
147                 cBitmap.Detach();\r
148         }\r
149         RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);\r
150 \r
151 #define SNAP_WIDTH 60 //the width of the combo box\r
152         // set up the ComboBox control as a snap mode select box\r
153         // First get the index of the placeholders position in the toolbar\r
154         int zoomComboIndex = 0;\r
155         while (m_ToolBar.GetItemID(zoomComboIndex) != ID_REVGRAPH_ZOOMCOMBO) zoomComboIndex++;\r
156 \r
157         // next convert that button to a separator and get its position\r
158         m_ToolBar.SetButtonInfo(zoomComboIndex, ID_REVGRAPH_ZOOMCOMBO, TBBS_SEPARATOR,\r
159                 SNAP_WIDTH);\r
160         RECT rect;\r
161         m_ToolBar.GetItemRect(zoomComboIndex, &rect);\r
162 \r
163         // expand the rectangle to allow the combo box room to drop down\r
164         rect.top+=3;\r
165         rect.bottom += 200;\r
166 \r
167         // then create the combo box and show it\r
168         if (!m_ToolBar.m_ZoomCombo.CreateEx(WS_EX_RIGHT, WS_CHILD|WS_VISIBLE|CBS_AUTOHSCROLL|CBS_DROPDOWN,\r
169                 rect, &m_ToolBar, ID_REVGRAPH_ZOOMCOMBO))\r
170         {\r
171                 TRACE0("Failed to create combo-box\n");\r
172                 return FALSE;\r
173         }\r
174         m_ToolBar.m_ZoomCombo.ShowWindow(SW_SHOW);\r
175 \r
176         // fill the combo box\r
177 \r
178         TCHAR* texts[] = { _T("5%")\r
179                                          , _T("10%")\r
180                                          , _T("20%")\r
181                                          , _T("40%")\r
182                                          , _T("50%")\r
183                                          , _T("75%")\r
184                                          , _T("100%")\r
185                                          , _T("200%")\r
186                                          , NULL};\r
187 \r
188         COMBOBOXEXITEM cbei;\r
189         SecureZeroMemory(&cbei, sizeof cbei);\r
190         cbei.mask = CBEIF_TEXT;\r
191 \r
192         for (TCHAR** text = texts; *text != NULL; ++text)\r
193         {\r
194                 cbei.pszText = *text;\r
195                 m_ToolBar.m_ZoomCombo.InsertItem(&cbei);\r
196         }\r
197 \r
198         m_ToolBar.m_ZoomCombo.SetCurSel(1);\r
199 \r
200     UpdateOptionAvailability();\r
201 \r
202         return TRUE;\r
203 }\r
204 \r
205 BOOL CRevisionGraphDlg::OnInitDialog()\r
206 {\r
207         CResizableStandAloneDialog::OnInitDialog();\r
208 \r
209         EnableToolTips();\r
210 \r
211         // set up the status bar\r
212         m_StatusBar.Create(WS_CHILD|WS_VISIBLE|SBT_OWNERDRAW,\r
213                 CRect(0,0,0,0), this, 1);\r
214         int strPartDim[2]= {120, -1};\r
215         m_StatusBar.SetParts(2, strPartDim);\r
216 \r
217         if (InitializeToolbar() != TRUE)\r
218                 return FALSE;\r
219 \r
220     CSyncPointer<CAllRevisionGraphOptions> \r
221         options (m_Graph.m_state.GetOptions());\r
222 \r
223     for (size_t i = 0; i < options->count(); ++i)\r
224         if ((*options)[i]->CommandID() != 0)\r
225                 SetOption ((*options)[i]->CommandID());\r
226 \r
227         CMenu * pMenu = GetMenu();\r
228         if (pMenu)\r
229         {\r
230                 CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseSVN\\ShowRevGraphOverview"), FALSE);\r
231                 m_Graph.SetShowOverview ((DWORD)reg != FALSE);\r
232                 pMenu->CheckMenuItem(ID_VIEW_SHOWOVERVIEW, MF_BYCOMMAND | (DWORD(reg) ? MF_CHECKED : 0));\r
233                 int tbstate = m_ToolBar.GetToolBarCtrl().GetState(ID_VIEW_SHOWOVERVIEW);\r
234                 m_ToolBar.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW, tbstate | (DWORD(reg) ? TBSTATE_CHECKED : 0));\r
235         }\r
236 \r
237         m_hAccel = LoadAccelerators(AfxGetResourceHandle(),MAKEINTRESOURCE(IDR_ACC_REVISIONGRAPH));\r
238 \r
239         CRect graphrect = GetGraphRect();\r
240         m_Graph.Init(this, &graphrect);\r
241         m_Graph.SetOwner(this);\r
242         m_Graph.UpdateWindow();\r
243     DoZoom (0.75);\r
244 \r
245         EnableSaveRestore(_T("RevisionGraphDlg"));\r
246 \r
247     assert (m_Graph.m_bThreadRunning == TRUE);\r
248         if (AfxBeginThread(WorkerThread, this)== NULL)\r
249         {\r
250         InterlockedExchange (&m_Graph.m_bThreadRunning, FALSE);\r
251                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
252         }\r
253         if (hWndExplorer)\r
254                 CenterWindow(CWnd::FromHandle(hWndExplorer));\r
255         return TRUE;  // return TRUE unless you set the focus to a control\r
256 }\r
257 \r
258 UINT CRevisionGraphDlg::WorkerThread(LPVOID pVoid)\r
259 {\r
260         CRevisionGraphDlg*      pDlg;\r
261         pDlg = (CRevisionGraphDlg*)pVoid;\r
262         assert (pDlg->m_Graph.m_bThreadRunning == TRUE);\r
263         CoInitialize(NULL);\r
264 \r
265     if (pDlg->m_bFetchLogs)\r
266     {\r
267             pDlg->m_Graph.m_pProgress = new CProgressDlg();\r
268             pDlg->m_Graph.m_pProgress->SetTitle(IDS_REVGRAPH_PROGTITLE);\r
269             pDlg->m_Graph.m_pProgress->SetCancelMsg(IDS_REVGRAPH_PROGCANCEL);\r
270             pDlg->m_Graph.m_pProgress->SetTime();\r
271             pDlg->m_Graph.m_pProgress->SetProgress(0, 100);\r
272 \r
273         svn_revnum_t pegRev = pDlg->m_Graph.m_pegRev.IsNumber()\r
274                             ? (svn_revnum_t)pDlg->m_Graph.m_pegRev\r
275                             : (svn_revnum_t)-1;\r
276 \r
277             if (!pDlg->m_Graph.FetchRevisionData (pDlg->m_Graph.m_sPath, pegRev))\r
278                     CMessageBox::Show ( pDlg->m_hWnd\r
279                               , pDlg->m_Graph.m_state.GetLastErrorMessage()\r
280                               , _T("TortoiseSVN")\r
281                               , MB_ICONERROR);\r
282 \r
283         pDlg->m_Graph.m_pProgress->Stop();\r
284         delete pDlg->m_Graph.m_pProgress;\r
285         pDlg->m_Graph.m_pProgress = NULL;\r
286 \r
287         pDlg->m_bFetchLogs = false;     // we've got the logs, no need to fetch them a second time\r
288     }\r
289 \r
290     // standard plus user settings\r
291 \r
292     if (pDlg->m_Graph.AnalyzeRevisionData())\r
293     {\r
294         pDlg->UpdateStatusBar();\r
295         pDlg->UpdateOptionAvailability();\r
296     }\r
297 \r
298         CoUninitialize();\r
299         InterlockedExchange(&pDlg->m_Graph.m_bThreadRunning, FALSE);\r
300 \r
301     pDlg->m_Graph.SendMessage (CRevisionGraphWnd::WM_WORKERTHREADDONE, 0, 0);\r
302         return 0;\r
303 }\r
304 \r
305 void CRevisionGraphDlg::OnSize(UINT nType, int cx, int cy)\r
306 {\r
307         __super::OnSize(nType, cx, cy);\r
308         CRect rect;\r
309         GetClientRect(&rect);\r
310         if (IsWindow(m_ToolBar))\r
311         {\r
312                 RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0);\r
313         }\r
314         if (IsWindow(m_StatusBar))\r
315         {\r
316                 CRect statusbarrect;\r
317                 m_StatusBar.GetClientRect(&statusbarrect);\r
318                 statusbarrect.top = rect.bottom - statusbarrect.top + statusbarrect.bottom;\r
319                 m_StatusBar.MoveWindow(&statusbarrect);\r
320         }\r
321         if (IsWindow(m_Graph))\r
322         {\r
323                 m_Graph.MoveWindow (GetGraphRect());\r
324         }\r
325 }\r
326 \r
327 BOOL CRevisionGraphDlg::PreTranslateMessage(MSG* pMsg)\r
328 {\r
329 #define SCROLL_STEP  20\r
330         if (pMsg->message == WM_KEYDOWN)\r
331         {\r
332                 int pos = 0;\r
333                 switch (pMsg->wParam)\r
334                 {\r
335                 case VK_UP:\r
336                         pos = m_Graph.GetScrollPos(SB_VERT);\r
337                         m_Graph.SetScrollPos(SB_VERT, pos - SCROLL_STEP);\r
338                         m_Graph.Invalidate();\r
339                         break;\r
340                 case VK_DOWN:\r
341                         pos = m_Graph.GetScrollPos(SB_VERT);\r
342                         m_Graph.SetScrollPos(SB_VERT, pos + SCROLL_STEP);\r
343                         m_Graph.Invalidate();\r
344                         break;\r
345                 case VK_LEFT:\r
346                         pos = m_Graph.GetScrollPos(SB_HORZ);\r
347                         m_Graph.SetScrollPos(SB_HORZ, pos - SCROLL_STEP);\r
348                         m_Graph.Invalidate();\r
349                         break;\r
350                 case VK_RIGHT:\r
351                         pos = m_Graph.GetScrollPos(SB_HORZ);\r
352                         m_Graph.SetScrollPos(SB_HORZ, pos + SCROLL_STEP);\r
353                         m_Graph.Invalidate();\r
354                         break;\r
355                 case VK_PRIOR:\r
356                         pos = m_Graph.GetScrollPos(SB_VERT);\r
357                         m_Graph.SetScrollPos(SB_VERT, pos - GetGraphRect().Height() / 2);\r
358                         m_Graph.Invalidate();\r
359                         break;\r
360                 case VK_NEXT:\r
361                         pos = m_Graph.GetScrollPos(SB_VERT);\r
362                         m_Graph.SetScrollPos(SB_VERT, pos + GetGraphRect().Height() / 2);\r
363                         m_Graph.Invalidate();\r
364                         break;\r
365                 case VK_F5:\r
366             UpdateFullHistory();\r
367                         break;\r
368                 }\r
369         }\r
370         if ((m_hAccel)&&(pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST))\r
371         {\r
372                 if (pMsg->wParam == VK_ESCAPE)\r
373                         if (m_Graph.CancelMouseZoom())\r
374                                 return TRUE;\r
375                 return TranslateAccelerator(m_hWnd,m_hAccel,pMsg);\r
376         }\r
377         return __super::PreTranslateMessage(pMsg);\r
378 }\r
379 \r
380 void CRevisionGraphDlg::DoZoom (float zoom)\r
381 {\r
382     m_fZoomFactor = zoom;\r
383     m_Graph.DoZoom (zoom);\r
384     UpdateZoomBox();\r
385 }\r
386 \r
387 void CRevisionGraphDlg::OnViewZoomin()\r
388 {\r
389     DoZoom (min (2.0f, m_fZoomFactor / .9f));\r
390 }\r
391 \r
392 void CRevisionGraphDlg::OnViewZoomout()\r
393 {\r
394     DoZoom (max (0.01f, m_fZoomFactor * .9f));\r
395 }\r
396 \r
397 void CRevisionGraphDlg::OnViewZoom100()\r
398 {\r
399         DoZoom (1.0);\r
400 }\r
401 \r
402 void CRevisionGraphDlg::OnViewZoomHeight()\r
403 {\r
404         CRect graphRect = m_Graph.GetGraphRect();\r
405     CRect windowRect = m_Graph.GetWindowRect();\r
406 \r
407         float horzfact = (windowRect.Width() - 4.0f)/(4.0f + graphRect.Width());\r
408         float vertfact = (windowRect.Height() - 4.0f)/(4.0f + graphRect.Height());\r
409     if ((horzfact < vertfact) && (horzfact < 2.0f))\r
410         vertfact = (windowRect.Height() - 20.0f)/(4.0f + graphRect.Height());\r
411 \r
412     DoZoom (min (2.0f, vertfact));\r
413 }\r
414 \r
415 void CRevisionGraphDlg::OnViewZoomWidth()\r
416 {\r
417         // zoom the graph so that it is completely visible in the window\r
418         CRect graphRect = m_Graph.GetGraphRect();\r
419     CRect windowRect = m_Graph.GetWindowRect();\r
420 \r
421         float horzfact = (windowRect.Width() - 4.0f)/(4.0f + graphRect.Width());\r
422         float vertfact = (windowRect.Height() - 4.0f)/(4.0f + graphRect.Height());\r
423     if ((vertfact < horzfact) && (vertfact < 2.0f))\r
424         horzfact = (windowRect.Width() - 20.0f)/(4.0f + graphRect.Width());\r
425 \r
426     DoZoom (min (2.0f, horzfact));\r
427 }\r
428 \r
429 void CRevisionGraphDlg::OnViewZoomAll()\r
430 {\r
431         // zoom the graph so that it is completely visible in the window\r
432         CRect graphRect = m_Graph.GetGraphRect();\r
433     CRect windowRect = m_Graph.GetWindowRect();\r
434 \r
435         float horzfact = (windowRect.Width() - 4.0f)/(4.0f + graphRect.Width());\r
436         float vertfact = (windowRect.Height() - 4.0f)/(4.0f + graphRect.Height());\r
437 \r
438     DoZoom (min (2.0f, min(horzfact, vertfact)));\r
439 }\r
440 \r
441 void CRevisionGraphDlg::OnMenuexit()\r
442 {\r
443         if (!m_Graph.m_bThreadRunning)\r
444                 EndDialog(IDOK);\r
445 }\r
446 \r
447 void CRevisionGraphDlg::OnMenuhelp()\r
448 {\r
449         OnHelp();\r
450 }\r
451 \r
452 void CRevisionGraphDlg::OnViewCompareheadrevisions()\r
453 {\r
454         m_Graph.CompareRevs(true);\r
455 }\r
456 \r
457 void CRevisionGraphDlg::OnViewComparerevisions()\r
458 {\r
459         m_Graph.CompareRevs(false);\r
460 }\r
461 \r
462 void CRevisionGraphDlg::OnViewUnifieddiff()\r
463 {\r
464         m_Graph.UnifiedDiffRevs(false);\r
465 }\r
466 \r
467 void CRevisionGraphDlg::OnViewUnifieddiffofheadrevisions()\r
468 {\r
469         m_Graph.UnifiedDiffRevs(true);\r
470 }\r
471 \r
472 void CRevisionGraphDlg::UpdateFullHistory()\r
473 {\r
474     m_Graph.SetDlgTitle (false);\r
475 \r
476     SVN svn;\r
477         LogCache::CRepositoryInfo& cachedProperties \r
478         = svn.GetLogCachePool()->GetRepositoryInfo();\r
479     CString root = m_Graph.m_state.GetRepositoryRoot();\r
480     CString uuid = m_Graph.m_state.GetRepositoryUUID();\r
481 \r
482     cachedProperties.ResetHeadRevision (uuid, root);\r
483 \r
484     m_bFetchLogs = true;\r
485     StartWorkerThread();\r
486 }\r
487 \r
488 void CRevisionGraphDlg::SetOption (UINT controlID)\r
489 {\r
490         CMenu * pMenu = GetMenu();\r
491         if (pMenu == NULL)\r
492                 return;\r
493 \r
494         int tbstate = m_ToolBar.GetToolBarCtrl().GetState(controlID);\r
495     if (tbstate != -1)\r
496     {\r
497         if (m_Graph.m_state.GetOptions()->IsSelected (controlID))\r
498             {\r
499                     pMenu->CheckMenuItem(controlID, MF_BYCOMMAND | MF_CHECKED);\r
500                     m_ToolBar.GetToolBarCtrl().SetState(controlID, tbstate | TBSTATE_CHECKED);\r
501             }\r
502             else\r
503             {\r
504                     pMenu->CheckMenuItem(controlID, MF_BYCOMMAND | MF_UNCHECKED);\r
505                     m_ToolBar.GetToolBarCtrl().SetState(controlID, tbstate & (~TBSTATE_CHECKED));\r
506             }\r
507     }\r
508 }\r
509 \r
510 BOOL CRevisionGraphDlg::ToggleOption (UINT controlID)\r
511 {\r
512     // check request for validity\r
513 \r
514         if (m_Graph.m_bThreadRunning)\r
515         {\r
516                 int state = m_ToolBar.GetToolBarCtrl().GetState(controlID);\r
517                 if (state & TBSTATE_CHECKED)\r
518                         state &= ~TBSTATE_CHECKED;\r
519                 else\r
520                         state |= TBSTATE_CHECKED;\r
521                 m_ToolBar.GetToolBarCtrl().SetState (controlID, state);\r
522                 return FALSE;\r
523         }\r
524 \r
525         CMenu * pMenu = GetMenu();\r
526         if (pMenu == NULL)\r
527                 return FALSE;\r
528 \r
529     // actually toggle the option\r
530 \r
531         int tbstate = m_ToolBar.GetToolBarCtrl().GetState(controlID);\r
532         UINT state = pMenu->GetMenuState(controlID, MF_BYCOMMAND);\r
533         if (state & MF_CHECKED)\r
534         {\r
535                 pMenu->CheckMenuItem(controlID, MF_BYCOMMAND | MF_UNCHECKED);\r
536                 m_ToolBar.GetToolBarCtrl().SetState(controlID, tbstate & (~TBSTATE_CHECKED));\r
537         }\r
538         else\r
539         {\r
540                 pMenu->CheckMenuItem(controlID, MF_BYCOMMAND | MF_CHECKED);\r
541                 m_ToolBar.GetToolBarCtrl().SetState(controlID, tbstate | TBSTATE_CHECKED);\r
542         }\r
543 \r
544     CSyncPointer<CAllRevisionGraphOptions> \r
545         options (m_Graph.m_state.GetOptions());\r
546     if (((state & MF_CHECKED) != 0) == options->IsSelected (controlID))\r
547         options->ToggleSelection (controlID);\r
548 \r
549     return TRUE;\r
550 }\r
551 \r
552 BOOL CRevisionGraphDlg::OnToggleOption (UINT controlID)\r
553 {\r
554     if (!ToggleOption (controlID))\r
555         return FALSE;\r
556 \r
557     // re-process the data\r
558 \r
559     StartWorkerThread();\r
560 \r
561     return TRUE;\r
562 }\r
563 \r
564 BOOL CRevisionGraphDlg::OnToggleReloadOption (UINT controlID)\r
565 {\r
566     if (!m_Graph.m_state.GetFetchedWCState())\r
567         m_bFetchLogs = true;\r
568 \r
569     return OnToggleOption (controlID);\r
570 }\r
571 \r
572 BOOL CRevisionGraphDlg::OnToggleRedrawOption (UINT controlID)\r
573 {\r
574     if (!ToggleOption (controlID))\r
575         return FALSE;\r
576 \r
577     m_Graph.BuildPreview();\r
578     Invalidate();\r
579 \r
580     return TRUE;\r
581 }\r
582 \r
583 void CRevisionGraphDlg::StartWorkerThread()\r
584 {\r
585         if (InterlockedExchange(&m_Graph.m_bThreadRunning, TRUE) == TRUE)\r
586         return;\r
587 \r
588         if (AfxBeginThread(WorkerThread, this)==NULL)\r
589         {\r
590                 CMessageBox::Show(this->m_hWnd, IDS_ERR_THREADSTARTFAILED, IDS_APPNAME, MB_OK | MB_ICONERROR);\r
591             InterlockedExchange(&m_Graph.m_bThreadRunning, FALSE);\r
592         }\r
593 }\r
594 \r
595 void CRevisionGraphDlg::OnCancel()\r
596 {\r
597         if (!m_Graph.m_bThreadRunning)\r
598                 __super::OnCancel();\r
599 }\r
600 \r
601 void CRevisionGraphDlg::OnOK()\r
602 {\r
603         OnChangeZoom();\r
604 }\r
605 \r
606 void CRevisionGraphDlg::OnFileSavegraphas()\r
607 {\r
608         CString tempfile;\r
609         int filterindex = 0;\r
610         if (CAppUtils::FileOpenSave(tempfile, &filterindex, IDS_REVGRAPH_SAVEPIC, IDS_PICTUREFILEFILTER, false, m_hWnd))\r
611         {\r
612                 // if the user doesn't specify a file extension, default to\r
613                 // wmf and add that extension to the filename. But only if the\r
614                 // user chose the 'pictures' filter. The filename isn't changed\r
615                 // if the 'All files' filter was chosen.\r
616                 CString extension;\r
617                 int dotPos = tempfile.ReverseFind('.');\r
618                 int slashPos = tempfile.ReverseFind('\\');\r
619                 if (dotPos > slashPos)\r
620                         extension = tempfile.Mid(dotPos);\r
621                 if ((filterindex == 1)&&(extension.IsEmpty()))\r
622                 {\r
623                         extension = _T(".wmf");\r
624                         tempfile += extension;\r
625                 }\r
626                 m_Graph.SaveGraphAs(tempfile);\r
627         }\r
628 }\r
629 \r
630 CRect CRevisionGraphDlg::GetGraphRect()\r
631 {\r
632     CRect rect;\r
633     GetClientRect(&rect);\r
634 \r
635     CRect statusbarrect;\r
636     m_StatusBar.GetClientRect(&statusbarrect);\r
637     rect.bottom -= statusbarrect.Height();\r
638 \r
639     CRect toolbarrect;\r
640     m_ToolBar.GetClientRect(&toolbarrect);\r
641     rect.top += toolbarrect.Height();\r
642 \r
643     return rect;\r
644 }\r
645 \r
646 void CRevisionGraphDlg::UpdateStatusBar()\r
647 {\r
648         CString sFormat;\r
649         sFormat.Format(IDS_REVGRAPH_STATUSBARURL, (LPCTSTR)m_Graph.m_sPath);\r
650         m_StatusBar.SetText(sFormat,1,0);\r
651         sFormat.Format(IDS_REVGRAPH_STATUSBARNUMNODES, m_Graph.m_state.GetNodeCount());\r
652         m_StatusBar.SetText(sFormat,0,0);\r
653 }\r
654 \r
655 void CRevisionGraphDlg::OnChangeZoom()\r
656 {\r
657         if (!IsWindow(m_Graph.GetSafeHwnd()))\r
658                 return;\r
659         CString strText;\r
660         CString strItem;\r
661         CComboBoxEx* pCBox = (CComboBoxEx*)m_ToolBar.GetDlgItem(ID_REVGRAPH_ZOOMCOMBO);\r
662         pCBox->GetWindowText(strItem);\r
663         if (strItem.IsEmpty())\r
664                 return;\r
665         ATLTRACE(_T("OnChangeZoom to %s\n"), strItem);\r
666 \r
667     DoZoom ((float)(_tstof(strItem)/100.0));\r
668 }\r
669 \r
670 void CRevisionGraphDlg::UpdateZoomBox()\r
671 {\r
672         CString strText;\r
673         CString strItem;\r
674         CComboBoxEx* pCBox = (CComboBoxEx*)m_ToolBar.GetDlgItem(ID_REVGRAPH_ZOOMCOMBO);\r
675         pCBox->GetWindowText(strItem);\r
676         strText.Format(_T("%.0f%%"), (m_fZoomFactor*100.0));\r
677         if (strText.Compare(strItem) != 0)\r
678                 pCBox->SetWindowText(strText);\r
679 }\r
680 \r
681 BOOL CRevisionGraphDlg::OnToolTipNotify(UINT /*id*/, NMHDR *pNMHDR, LRESULT *pResult)\r
682 {\r
683         // need to handle both ANSI and UNICODE versions of the message\r
684         TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;\r
685         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;\r
686         CString strTipText;\r
687 \r
688         UINT_PTR nID = pNMHDR->idFrom;\r
689 \r
690         if (pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||\r
691                 pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))\r
692         {\r
693                 // idFrom is actually the HWND of the tool \r
694                 nID = ::GetDlgCtrlID((HWND)nID);\r
695         }\r
696 \r
697         if (nID != 0) // will be zero on a separator\r
698         {\r
699                 strTipText.LoadString (static_cast<UINT>(nID));\r
700         }\r
701 \r
702         *pResult = 0;\r
703         if (strTipText.IsEmpty())\r
704                 return TRUE;\r
705 \r
706         if (strTipText.GetLength() >= MAX_TT_LENGTH)\r
707                 strTipText = strTipText.Left(MAX_TT_LENGTH);\r
708 \r
709         if (pNMHDR->code == TTN_NEEDTEXTA)\r
710         {\r
711                 ::SendMessage(pNMHDR->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 600);\r
712                 pTTTA->lpszText = m_szTip;\r
713                 WideCharToMultiByte(CP_ACP, 0, strTipText, -1, m_szTip, strTipText.GetLength()+1, 0, 0);\r
714         }\r
715         else\r
716         {\r
717                 ::SendMessage(pNMHDR->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 600);\r
718                 lstrcpyn(m_wszTip, strTipText, strTipText.GetLength()+1);\r
719                 pTTTW->lpszText = m_wszTip;\r
720         }\r
721         // bring the tooltip window above other pop up windows\r
722         ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,\r
723                 SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOOWNERZORDER);\r
724         return TRUE;    // message was handled\r
725 }\r
726 \r
727 void CRevisionGraphDlg::OnViewFilter()\r
728 {\r
729     CSyncPointer<CAllRevisionGraphOptions> \r
730         options (m_Graph.m_state.GetOptions());\r
731 \r
732     CRevisionInRange* revisionRange = options->GetOption<CRevisionInRange>();\r
733     svn_revnum_t head = m_Graph.m_state.GetHeadRevision();\r
734     svn_revnum_t lowerLimit = revisionRange->GetLowerLimit();\r
735     svn_revnum_t upperLimit = revisionRange->GetUpperLimit();\r
736 \r
737     CRemovePathsBySubString* pathFilter = options->GetOption<CRemovePathsBySubString>();\r
738 \r
739         CRevGraphFilterDlg dlg;\r
740         dlg.SetMaxRevision (head);\r
741         dlg.SetFilterString (m_sFilter);\r
742     dlg.SetRemoveSubTrees (pathFilter->GetRemoveSubTrees());\r
743     dlg.SetRevisionRange ( min (head, lowerLimit == -1 ? 1 : lowerLimit)\r
744                          , min (head, upperLimit == -1 ? head : upperLimit));\r
745 \r
746     if (dlg.DoModal()==IDOK)\r
747         {\r
748                 // user pressed OK to dismiss the dialog, which means\r
749                 // we have to accept the new filter settings and apply them\r
750                 svn_revnum_t minrev, maxrev;\r
751                 dlg.GetRevisionRange(minrev, maxrev);\r
752                 m_sFilter = dlg.GetFilterString();\r
753 \r
754         revisionRange->SetLowerLimit (minrev);\r
755         revisionRange->SetUpperLimit (maxrev == head ? revision_t (NO_REVISION) : maxrev);\r
756 \r
757         pathFilter->SetRemoveSubTrees (dlg.GetRemoveSubTrees());\r
758         std::set<std::string>& filterPaths = pathFilter->GetFilterPaths();\r
759         int index = 0;\r
760         filterPaths.clear();\r
761 \r
762         CString path = m_sFilter.Tokenize (_T("*"),  index);\r
763         while (!path.IsEmpty())\r
764         {\r
765             filterPaths.insert (CUnicodeUtils::StdGetUTF8 ((LPCTSTR)path));\r
766             path = m_sFilter.Tokenize (_T("*"),  index);\r
767         }\r
768 \r
769         // update menu & toolbar\r
770 \r
771             CMenu * pMenu = GetMenu();\r
772         int tbstate = m_ToolBar.GetToolBarCtrl().GetState(ID_VIEW_FILTER);\r
773         if (revisionRange->IsActive() || pathFilter->IsActive())\r
774             {\r
775             if (pMenu != NULL)\r
776                     pMenu->CheckMenuItem(ID_VIEW_FILTER, MF_BYCOMMAND | MF_CHECKED);\r
777                     m_ToolBar.GetToolBarCtrl().SetState(ID_VIEW_FILTER, tbstate | TBSTATE_CHECKED);\r
778             }\r
779             else\r
780             {\r
781             if (pMenu != NULL)\r
782                         pMenu->CheckMenuItem(ID_VIEW_FILTER, MF_BYCOMMAND | MF_UNCHECKED);\r
783                     m_ToolBar.GetToolBarCtrl().SetState(ID_VIEW_FILTER, tbstate & (~TBSTATE_CHECKED));\r
784             }\r
785 \r
786         // re-run query\r
787 \r
788         StartWorkerThread();\r
789         }\r
790 }\r
791 \r
792 void CRevisionGraphDlg::OnViewShowoverview()\r
793 {\r
794         CMenu * pMenu = GetMenu();\r
795         if (pMenu == NULL)\r
796                 return;\r
797         int tbstate = m_ToolBar.GetToolBarCtrl().GetState(ID_VIEW_SHOWOVERVIEW);\r
798         UINT state = pMenu->GetMenuState(ID_VIEW_SHOWOVERVIEW, MF_BYCOMMAND);\r
799         if (state & MF_CHECKED)\r
800         {\r
801                 pMenu->CheckMenuItem(ID_VIEW_SHOWOVERVIEW, MF_BYCOMMAND | MF_UNCHECKED);\r
802                 m_ToolBar.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW, tbstate & (~TBSTATE_CHECKED));\r
803                 m_Graph.SetShowOverview (false);\r
804         }\r
805         else\r
806         {\r
807                 pMenu->CheckMenuItem(ID_VIEW_SHOWOVERVIEW, MF_BYCOMMAND | MF_CHECKED);\r
808                 m_ToolBar.GetToolBarCtrl().SetState(ID_VIEW_SHOWOVERVIEW, tbstate | TBSTATE_CHECKED);\r
809                 m_Graph.SetShowOverview (true);\r
810         }\r
811 \r
812         CRegDWORD reg = CRegDWORD(_T("Software\\TortoiseSVN\\ShowRevGraphOverview"), FALSE);\r
813         reg = m_Graph.GetShowOverview();\r
814         m_Graph.Invalidate(FALSE);\r
815 }\r
816 \r
817 void CRevisionGraphDlg::UpdateOptionAvailability (UINT id, bool available)\r
818 {\r
819         CMenu * pMenu = GetMenu();\r
820         if (pMenu == NULL)\r
821                 return;\r
822 \r
823     pMenu->EnableMenuItem (id, available ? MF_ENABLED : MF_GRAYED);\r
824 \r
825     int tbstate = m_ToolBar.GetToolBarCtrl().GetState(id);\r
826     int newTbstate = available\r
827         ? tbstate | TBSTATE_ENABLED\r
828         : tbstate & ~TBSTATE_ENABLED;\r
829 \r
830     if (tbstate != newTbstate)\r
831         m_ToolBar.GetToolBarCtrl().SetState(id, newTbstate);\r
832 }\r
833 \r
834 void CRevisionGraphDlg::UpdateOptionAvailability()\r
835 {\r
836     bool multipleTrees = m_Graph.m_state.GetTreeCount() > 1;\r
837     bool isWCPath = !CTSVNPath (m_Graph.m_sPath).IsUrl();\r
838 \r
839     UpdateOptionAvailability (ID_VIEW_TOPALIGNTREES, multipleTrees);\r
840     UpdateOptionAvailability (ID_VIEW_SHOWTREESTRIPES, multipleTrees);\r
841     UpdateOptionAvailability (ID_VIEW_SHOWWCREV, isWCPath);\r
842     UpdateOptionAvailability (ID_VIEW_SHOWWCMODIFICATION, isWCPath);\r
843 }\r
844 \r