1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2008 - 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
39 #define new DEBUG_NEW
\r
41 static char THIS_FILE[] = __FILE__;
\r
44 using namespace Gdiplus;
\r
46 void CRevisionGraphWnd::InitView()
\r
48 m_bIsRubberBand = false;
\r
50 CRect viewRect = GetViewRect();
\r
51 SetScrollbars (0,0,viewRect.Width(),viewRect.Height());
\r
54 void CRevisionGraphWnd::BuildPreview()
\r
56 m_Preview.DeleteObject();
\r
57 if (!m_bShowOverview)
\r
60 // is there a point in drawing this at all?
\r
62 int nodeCount = GetNodeCount();
\r
63 if ((nodeCount > REVGRAPH_PREVIEW_MAX_NODES) || (nodeCount == 0))
\r
66 float origZoom = m_fZoomFactor;
\r
69 GetClientRect (&clientRect);
\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)max (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
107 GetClientRect(&clientrect);
\r
108 const CRect& pRect = GetGraphRect();
\r
110 SCROLLINFO ScrollInfo = {sizeof(SCROLLINFO), SIF_ALL};
\r
111 GetScrollInfo(SB_VERT, &ScrollInfo);
\r
113 if ((nVert)||(oldheight==0))
\r
114 ScrollInfo.nPos = nVert;
\r
116 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Height() / oldheight;
\r
118 ScrollInfo.nMin = 0;
\r
119 ScrollInfo.nMax = static_cast<int>(pRect.bottom * m_fZoomFactor);
\r
120 ScrollInfo.nPage = clientrect.Height();
\r
121 ScrollInfo.nTrackPos = 0;
\r
122 SetScrollInfo(SB_VERT, &ScrollInfo);
\r
124 GetScrollInfo(SB_HORZ, &ScrollInfo);
\r
125 if ((nHorz)||(oldwidth==0))
\r
126 ScrollInfo.nPos = nHorz;
\r
128 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Width() / oldwidth;
\r
130 ScrollInfo.nMax = static_cast<int>(pRect.right * m_fZoomFactor);
\r
131 ScrollInfo.nPage = clientrect.Width();
\r
132 SetScrollInfo(SB_HORZ, &ScrollInfo);
\r
135 CRect CRevisionGraphWnd::GetGraphRect()
\r
137 return m_layout.get() != NULL
\r
138 ? m_layout->GetRect()
\r
142 CRect CRevisionGraphWnd::GetViewRect()
\r
145 GetClientRect (&clientRect);
\r
148 result.UnionRect (clientRect, GetGraphRect());
\r
152 int CRevisionGraphWnd::GetNodeCount()
\r
154 return m_visibleGraph.get() != NULL
\r
155 ? static_cast<int>(m_visibleGraph->GetNodeCount())
\r
159 svn_revnum_t CRevisionGraphWnd::GetHeadRevision() const
\r
161 return m_fullHistory.get() != NULL
\r
162 ? m_fullHistory->GetHeadRevision()
\r
166 CString CRevisionGraphWnd::GetRepositoryRoot() const
\r
168 return m_fullHistory.get() != NULL
\r
169 ? m_fullHistory->GetRepositoryRoot()
\r
173 CString CRevisionGraphWnd::GetRepositoryUUID() const
\r
175 return m_fullHistory.get() != NULL
\r
176 ? m_fullHistory->GetRepositoryUUID()
\r
180 int CRevisionGraphWnd::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
\r
182 UINT num = 0; // number of image encoders
\r
183 UINT size = 0; // size of the image encoder array in bytes
\r
185 ImageCodecInfo* pImageCodecInfo = NULL;
\r
187 if (GetImageEncodersSize(&num, &size)!=Ok)
\r
190 return -1; // Failure
\r
192 pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
\r
193 if(pImageCodecInfo == NULL)
\r
194 return -1; // Failure
\r
196 if (GetImageEncoders(num, size, pImageCodecInfo)==Ok)
\r
198 for(UINT j = 0; j < num; ++j)
\r
200 if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
\r
202 *pClsid = pImageCodecInfo[j].Clsid;
\r
203 free(pImageCodecInfo);
\r
204 return j; // Success
\r
209 free(pImageCodecInfo);
\r
210 return -1; // Failure
\r
213 void CRevisionGraphWnd::Compare (TDiffFunc diffFunc, TStartDiffFunc startDiffFunc, bool bHead)
\r
215 ASSERT(m_SelectedEntry1 != NULL);
\r
216 ASSERT(m_SelectedEntry2 != NULL);
\r
218 CString sRepoRoot = m_fullHistory.get() != NULL
\r
219 ? m_fullHistory->GetRepositoryRoot()
\r
224 url1.SetFromSVN (sRepoRoot + CUnicodeUtils::GetUnicode (m_SelectedEntry1->GetPath().GetPath().c_str()));
\r
225 url2.SetFromSVN (sRepoRoot + CUnicodeUtils::GetUnicode (m_SelectedEntry2->GetPath().GetPath().c_str()));
\r
227 SVNRev rev1 (bHead ? SVNRev::REV_HEAD : m_SelectedEntry1->GetRevision());
\r
228 SVNRev rev2 (bHead ? SVNRev::REV_HEAD : m_SelectedEntry2->GetRevision());
\r
229 SVNRev peg (bHead ? m_SelectedEntry1->GetRevision() : SVNRev());
\r
233 SVNDiff diff (&m_fullHistory->GetSVN(), this->m_hWnd);
\r
234 diff.SetAlternativeTool(!!(GetAsyncKeyState(VK_SHIFT) & 0x8000));
\r
235 (diff.*diffFunc)(url1, rev1,
\r
237 peg, false, false);
\r
241 (*startDiffFunc)(m_hWnd, url1, rev1,
\r
243 SVNRev(), !!(GetAsyncKeyState(VK_SHIFT) & 0x8000), false, false);
\r
247 bool CRevisionGraphWnd::PromptShown() const
\r
249 return m_fullHistory.get() != NULL
\r
250 ? m_fullHistory->GetSVN().PromptShown()
\r
254 bool CRevisionGraphWnd::FetchRevisionData
\r
255 ( const CString& path
\r
256 , SVNRev pegRevision
\r
257 , const CAllRevisionGraphOptions& options)
\r
259 // (re-)fetch the data
\r
261 m_fullHistory.reset (new CFullHistory());
\r
263 bool showWCRev = options.GetOption<CShowWC>()->IsActive();
\r
264 bool result = m_fullHistory->FetchRevisionData (path, pegRevision, showWCRev, m_pProgress);
\r
267 m_fullGraph.reset (new CFullGraph());
\r
268 m_visibleGraph.reset();
\r
271 CFullGraphBuilder builder (*m_fullHistory, *m_fullGraph);
\r
274 CFullGraphFinalizer finalizer (*m_fullHistory, *m_fullGraph);
\r
281 bool CRevisionGraphWnd::AnalyzeRevisionData
\r
282 (const CAllRevisionGraphOptions& options)
\r
285 if ((m_fullGraph.get() != NULL) && (m_fullGraph->GetNodeCount() > 0))
\r
289 m_visibleGraph.reset (new CVisibleGraph());
\r
290 CVisibleGraphBuilder builder ( *m_fullGraph
\r
292 , options.GetCopyFilterOptions());
\r
294 options.GetModificationOptions().Apply (m_visibleGraph.get());
\r
297 for (size_t i = 0, count = m_visibleGraph->GetRootCount(); i < count; ++i)
\r
298 index = m_visibleGraph->GetRoot (i)->InitIndex (index);
\r
302 std::auto_ptr<CStandardLayout> newLayout
\r
303 ( new CStandardLayout ( m_fullHistory->GetCache()
\r
304 , m_visibleGraph.get()));
\r
305 options.GetLayoutOptions().Apply (newLayout.get());
\r
306 newLayout->Finalize();
\r
308 m_layout = newLayout;
\r
311 return m_layout.get() != NULL;
\r
314 CString CRevisionGraphWnd::GetLastErrorMessage() const
\r
316 return m_fullHistory->GetLastErrorMessage();
\r
319 bool CRevisionGraphWnd::GetShowOverview() const
\r
321 return m_bShowOverview != FALSE;
\r
324 void CRevisionGraphWnd::SetShowOverview (bool value)
\r
326 m_bShowOverview = value;
\r
327 if (m_bShowOverview)
\r
331 void CRevisionGraphWnd::CompareRevs(bool bHead)
\r
333 Compare (&SVNDiff::ShowCompare, &CAppUtils::StartShowCompare, bHead);
\r
336 void CRevisionGraphWnd::UnifiedDiffRevs(bool bHead)
\r
338 Compare (&SVNDiff::ShowUnifiedDiff, &CAppUtils::StartShowUnifiedDiff, bHead);
\r
341 void CRevisionGraphWnd::DoZoom(float fZoomFactor)
\r
343 float oldzoom = m_fZoomFactor;
\r
344 m_fZoomFactor = fZoomFactor;
\r
346 m_nFontSize = max(1, int(12.0f * fZoomFactor));
\r
347 if (m_nFontSize < 7)
\r
348 m_nFontSize = min (7, int(15.0f * fZoomFactor));
\r
350 for (int i=0; i<MAXFONTS; i++)
\r
352 if (m_apFonts[i] != NULL)
\r
354 m_apFonts[i]->DeleteObject();
\r
355 delete m_apFonts[i];
\r
357 m_apFonts[i] = NULL;
\r
360 SCROLLINFO si1 = {sizeof(SCROLLINFO), SIF_ALL};
\r
361 GetScrollInfo(SB_VERT, &si1);
\r
362 SCROLLINFO si2 = {sizeof(SCROLLINFO), SIF_ALL};
\r
363 GetScrollInfo(SB_HORZ, &si2);
\r
367 si1.nPos = int(float(si1.nPos)*m_fZoomFactor/oldzoom);
\r
368 si2.nPos = int(float(si2.nPos)*m_fZoomFactor/oldzoom);
\r
369 SetScrollPos (SB_VERT, si1.nPos);
\r
370 SetScrollPos (SB_HORZ, si2.nPos);
\r