1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2009 - TortoiseSVN
\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
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
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
20 #include "TortoiseProc.h"
\r
21 #include <gdiplus.h>
\r
22 #include "Revisiongraphdlg.h"
\r
23 #include "MessageBox.h"
\r
25 #include "TempFile.h"
\r
26 #include "UnicodeUtils.h"
\r
27 #include "TSVNPath.h"
\r
28 #include "SVNInfo.h"
\r
29 #include ".\revisiongraphwnd.h"
\r
30 #include "CachedLogInfo.h"
\r
31 #include "RevisionGraph/IRevisionGraphLayout.h"
\r
32 #include "RevisionGraph/FullGraphBuilder.h"
\r
33 #include "RevisionGraph/FullGraphFinalizer.h"
\r
34 #include "RevisionGraph/VisibleGraphBuilder.h"
\r
35 #include "RevisionGraph/StandardLayout.h"
\r
36 #include "RevisionGraph/ShowWC.h"
\r
37 #include "RevisionGraph/ShowWCModification.h"
\r
40 #define new DEBUG_NEW
\r
42 static char THIS_FILE[] = __FILE__;
\r
45 using namespace Gdiplus;
\r
47 void CRevisionGraphWnd::InitView()
\r
49 m_bIsRubberBand = false;
\r
51 CRect viewRect = GetViewRect();
\r
52 SetScrollbars (0,0,viewRect.Width(),viewRect.Height());
\r
55 void CRevisionGraphWnd::BuildPreview()
\r
57 m_Preview.DeleteObject();
\r
58 if (!m_bShowOverview)
\r
61 // is there a point in drawing this at all?
\r
63 int nodeCount = m_state.GetNodeCount();
\r
64 if ((nodeCount > REVGRAPH_PREVIEW_MAX_NODES) || (nodeCount == 0))
\r
67 float origZoom = m_fZoomFactor;
\r
69 CRect clientRect = GetClientRect();
\r
70 CSize preViewSize (max (REVGRAPH_PREVIEW_WIDTH, clientRect.Width() / 4)
\r
71 ,max (REVGRAPH_PREVIEW_HEIGHT, clientRect.Height() / 4));
\r
73 // zoom the graph so that it is completely visible in the window
\r
74 CRect graphRect = GetGraphRect();
\r
75 float horzfact = float(graphRect.Width())/float(preViewSize.cx);
\r
76 float vertfact = float(graphRect.Height())/float(preViewSize.cy);
\r
77 m_previewZoom = min (1.0f, 1.0f/(max(horzfact, vertfact)));
\r
79 // make sure the preview window has a minimal size
\r
81 m_previewWidth = (int)min (max (graphRect.Width() * m_previewZoom, 30), preViewSize.cx);
\r
82 m_previewHeight = (int)min (max (graphRect.Height() * m_previewZoom, 30), preViewSize.cy);
\r
84 CClientDC ddc(this);
\r
86 if (!dc.CreateCompatibleDC(&ddc))
\r
89 m_Preview.CreateCompatibleBitmap(&ddc, m_previewWidth, m_previewHeight);
\r
90 HBITMAP oldbm = (HBITMAP)dc.SelectObject (m_Preview);
\r
92 // paint the whole graph
\r
93 DoZoom (m_previewZoom);
\r
94 CRect rect (0, 0, m_previewWidth, m_previewHeight);
\r
95 DrawGraph(&dc, rect, 0, 0, true);
\r
97 // now we have a bitmap the size of the preview window
\r
98 dc.SelectObject(oldbm);
\r
104 void CRevisionGraphWnd::SetScrollbars(int nVert, int nHorz, int oldwidth, int oldheight)
\r
106 CRect clientrect = GetClientRect();
\r
107 const CRect& pRect = GetGraphRect();
\r
109 SCROLLINFO ScrollInfo = {sizeof(SCROLLINFO), SIF_ALL};
\r
110 GetScrollInfo(SB_VERT, &ScrollInfo);
\r
112 if ((nVert)||(oldheight==0))
\r
113 ScrollInfo.nPos = nVert;
\r
115 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Height() / oldheight;
\r
117 ScrollInfo.nMin = 0;
\r
118 ScrollInfo.nMax = static_cast<int>(pRect.bottom * m_fZoomFactor);
\r
119 ScrollInfo.nPage = clientrect.Height();
\r
120 ScrollInfo.nTrackPos = 0;
\r
121 SetScrollInfo(SB_VERT, &ScrollInfo);
\r
123 GetScrollInfo(SB_HORZ, &ScrollInfo);
\r
124 if ((nHorz)||(oldwidth==0))
\r
125 ScrollInfo.nPos = nHorz;
\r
127 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Width() / oldwidth;
\r
129 ScrollInfo.nMax = static_cast<int>(pRect.right * m_fZoomFactor);
\r
130 ScrollInfo.nPage = clientrect.Width();
\r
131 SetScrollInfo(SB_HORZ, &ScrollInfo);
\r
134 CRect CRevisionGraphWnd::GetGraphRect()
\r
136 return m_state.GetGraphRect();
\r
139 CRect CRevisionGraphWnd::GetClientRect()
\r
142 CWnd::GetClientRect (&clientRect);
\r
146 CRect CRevisionGraphWnd::GetWindowRect()
\r
149 CWnd::GetWindowRect (&windowRect);
\r
153 CRect CRevisionGraphWnd::GetViewRect()
\r
156 result.UnionRect (GetClientRect(), GetGraphRect());
\r
160 int CRevisionGraphWnd::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
\r
162 UINT num = 0; // number of image encoders
\r
163 UINT size = 0; // size of the image encoder array in bytes
\r
165 ImageCodecInfo* pImageCodecInfo = NULL;
\r
167 if (GetImageEncodersSize(&num, &size)!=Ok)
\r
170 return -1; // Failure
\r
172 pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
\r
173 if(pImageCodecInfo == NULL)
\r
174 return -1; // Failure
\r
176 if (GetImageEncoders(num, size, pImageCodecInfo)==Ok)
\r
178 for(UINT j = 0; j < num; ++j)
\r
180 if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
\r
182 *pClsid = pImageCodecInfo[j].Clsid;
\r
183 free(pImageCodecInfo);
\r
184 return j; // Success
\r
189 free(pImageCodecInfo);
\r
190 return -1; // Failure
\r
193 bool CRevisionGraphWnd::FetchRevisionData
\r
194 ( const CString& path
\r
195 , SVNRev pegRevision)
\r
197 // (re-)fetch the data
\r
199 std::auto_ptr<CFullHistory> newFullHistory (new CFullHistory());
\r
202 = m_state.GetOptions()->GetOption<CShowWC>()->IsSelected();
\r
203 bool showWCModification
\r
204 = m_state.GetOptions()->GetOption<CShowWCModification>()->IsSelected();
\r
205 bool result = newFullHistory->FetchRevisionData ( path
\r
208 , showWCModification
\r
211 m_state.SetLastErrorMessage (newFullHistory->GetLastErrorMessage());
\r
215 std::auto_ptr<CFullGraph> newFullGraph (new CFullGraph());
\r
217 CFullGraphBuilder builder (*newFullHistory, *newFullGraph);
\r
220 CFullGraphFinalizer finalizer (*newFullHistory, *newFullGraph);
\r
223 m_state.SetQueryResult ( newFullHistory
\r
225 , showWCRev || showWCModification);
\r
231 bool CRevisionGraphWnd::AnalyzeRevisionData()
\r
233 CSyncPointer<const CFullGraph> fullGraph (m_state.GetFullGraph());
\r
234 if ((fullGraph.get() != NULL) && (fullGraph->GetNodeCount() > 0))
\r
238 CSyncPointer<CAllRevisionGraphOptions> options (m_state.GetOptions());
\r
239 options->Prepare();
\r
241 std::auto_ptr<CVisibleGraph> visibleGraph (new CVisibleGraph());
\r
242 CVisibleGraphBuilder builder ( *fullGraph
\r
244 , options->GetCopyFilterOptions());
\r
246 options->GetModificationOptions().Apply (visibleGraph.get());
\r
249 for (size_t i = 0, count = visibleGraph->GetRootCount(); i < count; ++i)
\r
250 index = visibleGraph->GetRoot (i)->InitIndex (index);
\r
254 std::auto_ptr<CStandardLayout> newLayout
\r
255 ( new CStandardLayout ( m_state.GetFullHistory()->GetCache()
\r
256 , visibleGraph.get()));
\r
257 options->GetLayoutOptions().Apply (newLayout.get());
\r
258 newLayout->Finalize();
\r
262 m_state.SetAnalysisResult (visibleGraph, newLayout);
\r
265 return m_state.GetNodes().get() != NULL;
\r
268 bool CRevisionGraphWnd::GetShowOverview() const
\r
270 return m_bShowOverview;
\r
273 void CRevisionGraphWnd::SetShowOverview (bool value)
\r
275 m_bShowOverview = value;
\r
276 if (m_bShowOverview)
\r
280 void CRevisionGraphWnd::GetSelected
\r
281 ( const CVisibleGraphNode* node
\r
287 CString repoRoot = m_state.GetRepositoryRoot();
\r
289 // get path and revision
\r
291 path.SetFromSVN (repoRoot + CUnicodeUtils::GetUnicode (node->GetPath().GetPath().c_str()));
\r
292 rev = head ? SVNRev::REV_HEAD : node->GetRevision();
\r
294 // handle 'modified WC' node
\r
296 if (node->GetClassification().Is (CNodeClassification::IS_MODIFIED_WC))
\r
298 path.SetFromWin (m_sPath);
\r
299 rev = SVNRev::REV_WC;
\r
301 // don't set peg, if we aren't the first node
\r
302 // (i.e. would not be valid for node1)
\r
304 if (node == m_SelectedEntry1)
\r
305 peg = SVNRev::REV_WC;
\r
309 // set head, if still necessary
\r
311 if (head && !peg.IsValid())
\r
312 peg = node->GetRevision();
\r
316 void CRevisionGraphWnd::CompareRevs(bool bHead)
\r
318 ASSERT(m_SelectedEntry1 != NULL);
\r
319 ASSERT(m_SelectedEntry2 != NULL);
\r
321 CSyncPointer<SVN> svn (m_state.GetSVN());
\r
329 GetSelected (m_SelectedEntry1, bHead, url1, rev1, peg);
\r
330 GetSelected (m_SelectedEntry2, bHead, url2, rev2, peg);
\r
332 bool alternativeTool = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);
\r
333 if (m_state.PromptShown())
\r
335 SVNDiff diff (svn.get(), this->m_hWnd);
\r
336 diff.SetAlternativeTool (alternativeTool);
\r
337 diff.ShowCompare (url1, rev1, url2, rev2, peg);
\r
341 CAppUtils::StartShowCompare (m_hWnd, url1, rev1,
\r
342 url2, rev2, peg, SVNRev(), alternativeTool);
\r
346 void CRevisionGraphWnd::UnifiedDiffRevs(bool bHead)
\r
348 ASSERT(m_SelectedEntry1 != NULL);
\r
349 ASSERT(m_SelectedEntry2 != NULL);
\r
351 CSyncPointer<SVN> svn (m_state.GetSVN());
\r
359 GetSelected (m_SelectedEntry1, bHead, url1, rev1, peg);
\r
360 GetSelected (m_SelectedEntry2, bHead, url2, rev2, peg);
\r
362 bool alternativeTool = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);
\r
363 if (m_state.PromptShown())
\r
365 SVNDiff diff (svn.get(), this->m_hWnd);
\r
366 diff.SetAlternativeTool (alternativeTool);
\r
367 diff.ShowUnifiedDiff (url1, rev1, url2, rev2, peg);
\r
371 CAppUtils::StartShowUnifiedDiff(m_hWnd, url1, rev1,
\r
373 SVNRev(), alternativeTool);
\r
377 void CRevisionGraphWnd::DoZoom(float fZoomFactor)
\r
379 float oldzoom = m_fZoomFactor;
\r
380 m_fZoomFactor = fZoomFactor;
\r
382 m_nFontSize = max(1, int(12.0f * fZoomFactor));
\r
383 if (m_nFontSize < 7)
\r
384 m_nFontSize = min (7, int(15.0f * fZoomFactor));
\r
386 for (int i=0; i<MAXFONTS; i++)
\r
388 if (m_apFonts[i] != NULL)
\r
390 m_apFonts[i]->DeleteObject();
\r
391 delete m_apFonts[i];
\r
393 m_apFonts[i] = NULL;
\r
396 SCROLLINFO si1 = {sizeof(SCROLLINFO), SIF_ALL};
\r
397 GetScrollInfo(SB_VERT, &si1);
\r
398 SCROLLINFO si2 = {sizeof(SCROLLINFO), SIF_ALL};
\r
399 GetScrollInfo(SB_HORZ, &si2);
\r
403 si1.nPos = int(float(si1.nPos)*m_fZoomFactor/oldzoom);
\r
404 si2.nPos = int(float(si2.nPos)*m_fZoomFactor/oldzoom);
\r
405 SetScrollPos (SB_VERT, si1.nPos);
\r
406 SetScrollPos (SB_HORZ, si2.nPos);
\r