OSDN Git Service

BrowseRefs: Added option to delete branch or tag.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseProc / RevisionGraph / RevisionGraphDlgFunc.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 <gdiplus.h>\r
22 #include "Revisiongraphdlg.h"\r
23 #include "MessageBox.h"\r
24 #include "SVN.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
38 \r
39 #ifdef _DEBUG\r
40 #define new DEBUG_NEW\r
41 #undef THIS_FILE\r
42 static char THIS_FILE[] = __FILE__;\r
43 #endif\r
44 \r
45 using namespace Gdiplus;\r
46 \r
47 void CRevisionGraphWnd::InitView()\r
48 {\r
49         m_bIsRubberBand = false;\r
50 \r
51     CRect viewRect = GetViewRect();\r
52         SetScrollbars (0,0,viewRect.Width(),viewRect.Height());\r
53 }\r
54 \r
55 void CRevisionGraphWnd::BuildPreview()\r
56 {\r
57         m_Preview.DeleteObject();\r
58         if (!m_bShowOverview)\r
59                 return;\r
60 \r
61         // is there a point in drawing this at all?\r
62 \r
63     int nodeCount = m_state.GetNodeCount();\r
64         if ((nodeCount > REVGRAPH_PREVIEW_MAX_NODES) || (nodeCount == 0))\r
65                 return;\r
66 \r
67         float origZoom = m_fZoomFactor;\r
68 \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
72 \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
78 \r
79     // make sure the preview window has a minimal size\r
80 \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
83 \r
84         CClientDC ddc(this);\r
85         CDC dc;\r
86         if (!dc.CreateCompatibleDC(&ddc))\r
87                 return;\r
88 \r
89         m_Preview.CreateCompatibleBitmap(&ddc, m_previewWidth, m_previewHeight);\r
90         HBITMAP oldbm = (HBITMAP)dc.SelectObject (m_Preview);\r
91 \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
96 \r
97         // now we have a bitmap the size of the preview window\r
98         dc.SelectObject(oldbm);\r
99         dc.DeleteDC();\r
100 \r
101         DoZoom (origZoom);\r
102 }\r
103 \r
104 void CRevisionGraphWnd::SetScrollbars(int nVert, int nHorz, int oldwidth, int oldheight)\r
105 {\r
106         CRect clientrect = GetClientRect();\r
107         const CRect& pRect = GetGraphRect();\r
108 \r
109     SCROLLINFO ScrollInfo = {sizeof(SCROLLINFO), SIF_ALL};\r
110         GetScrollInfo(SB_VERT, &ScrollInfo);\r
111 \r
112         if ((nVert)||(oldheight==0))\r
113                 ScrollInfo.nPos = nVert;\r
114         else\r
115                 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Height() / oldheight;\r
116 \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
122 \r
123         GetScrollInfo(SB_HORZ, &ScrollInfo);\r
124         if ((nHorz)||(oldwidth==0))\r
125                 ScrollInfo.nPos = nHorz;\r
126         else\r
127                 ScrollInfo.nPos = ScrollInfo.nPos * pRect.Width() / oldwidth;\r
128 \r
129         ScrollInfo.nMax = static_cast<int>(pRect.right * m_fZoomFactor);\r
130         ScrollInfo.nPage = clientrect.Width();\r
131         SetScrollInfo(SB_HORZ, &ScrollInfo);\r
132 }\r
133 \r
134 CRect CRevisionGraphWnd::GetGraphRect()\r
135 {\r
136     return m_state.GetGraphRect();\r
137 }\r
138 \r
139 CRect CRevisionGraphWnd::GetClientRect()\r
140 {\r
141         CRect clientRect;\r
142     CWnd::GetClientRect (&clientRect);\r
143     return clientRect;\r
144 }\r
145 \r
146 CRect CRevisionGraphWnd::GetWindowRect()\r
147 {\r
148         CRect windowRect;\r
149     CWnd::GetWindowRect (&windowRect);\r
150     return windowRect;\r
151 }\r
152 \r
153 CRect CRevisionGraphWnd::GetViewRect()\r
154 {\r
155     CRect result;\r
156     result.UnionRect (GetClientRect(), GetGraphRect()); \r
157     return result;\r
158 }\r
159 \r
160 int CRevisionGraphWnd::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)\r
161 {\r
162         UINT  num = 0;          // number of image encoders\r
163         UINT  size = 0;         // size of the image encoder array in bytes\r
164 \r
165         ImageCodecInfo* pImageCodecInfo = NULL;\r
166 \r
167         if (GetImageEncodersSize(&num, &size)!=Ok)\r
168                 return -1;\r
169         if(size == 0)\r
170                 return -1;  // Failure\r
171 \r
172         pImageCodecInfo = (ImageCodecInfo*)(malloc(size));\r
173         if(pImageCodecInfo == NULL)\r
174                 return -1;  // Failure\r
175 \r
176         if (GetImageEncoders(num, size, pImageCodecInfo)==Ok)\r
177         {\r
178                 for(UINT j = 0; j < num; ++j)\r
179                 {\r
180                         if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )\r
181                         {\r
182                                 *pClsid = pImageCodecInfo[j].Clsid;\r
183                                 free(pImageCodecInfo);\r
184                                 return j;  // Success\r
185                         }\r
186                 }\r
187 \r
188         }\r
189         free(pImageCodecInfo);\r
190         return -1;  // Failure\r
191 }\r
192 \r
193 bool CRevisionGraphWnd::FetchRevisionData \r
194     ( const CString& path\r
195     , SVNRev pegRevision)\r
196 {\r
197     // (re-)fetch the data\r
198 \r
199     std::auto_ptr<CFullHistory> newFullHistory (new CFullHistory());\r
200 \r
201     bool showWCRev \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
206                                                     , pegRevision\r
207                                                     , showWCRev\r
208                                                     , showWCModification\r
209                                                     , m_pProgress);\r
210 \r
211     m_state.SetLastErrorMessage (newFullHistory->GetLastErrorMessage());\r
212 \r
213     if (result)\r
214     {\r
215         std::auto_ptr<CFullGraph> newFullGraph (new CFullGraph());\r
216 \r
217         CFullGraphBuilder builder (*newFullHistory, *newFullGraph);\r
218         builder.Run();\r
219 \r
220         CFullGraphFinalizer finalizer (*newFullHistory, *newFullGraph);\r
221         finalizer.Run();\r
222 \r
223         m_state.SetQueryResult ( newFullHistory\r
224                                , newFullGraph\r
225                                , showWCRev || showWCModification);\r
226     }\r
227 \r
228     return result;\r
229 }\r
230 \r
231 bool CRevisionGraphWnd::AnalyzeRevisionData()\r
232 {\r
233     CSyncPointer<const CFullGraph> fullGraph (m_state.GetFullGraph());\r
234     if ((fullGraph.get() != NULL) && (fullGraph->GetNodeCount() > 0))\r
235     {\r
236         // filter graph\r
237 \r
238         CSyncPointer<CAllRevisionGraphOptions> options (m_state.GetOptions());\r
239         options->Prepare();\r
240 \r
241         std::auto_ptr<CVisibleGraph> visibleGraph (new CVisibleGraph());\r
242         CVisibleGraphBuilder builder ( *fullGraph\r
243                                      , *visibleGraph\r
244                                      , options->GetCopyFilterOptions());\r
245         builder.Run();\r
246         options->GetModificationOptions().Apply (visibleGraph.get());\r
247 \r
248         index_t index = 0;\r
249         for (size_t i = 0, count = visibleGraph->GetRootCount(); i < count; ++i)\r
250             index = visibleGraph->GetRoot (i)->InitIndex (index);\r
251 \r
252         // layout nodes\r
253 \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
259 \r
260         // switch state\r
261 \r
262         m_state.SetAnalysisResult (visibleGraph, newLayout);\r
263     }\r
264 \r
265     return m_state.GetNodes().get() != NULL;\r
266 }\r
267 \r
268 bool CRevisionGraphWnd::GetShowOverview() const\r
269 {\r
270     return m_bShowOverview;\r
271 }\r
272 \r
273 void CRevisionGraphWnd::SetShowOverview (bool value)\r
274 {\r
275     m_bShowOverview = value;\r
276         if (m_bShowOverview)\r
277                 BuildPreview();\r
278 }\r
279 \r
280 void CRevisionGraphWnd::GetSelected \r
281     ( const CVisibleGraphNode* node\r
282     , bool head\r
283     , CTSVNPath& path\r
284     , SVNRev& rev\r
285     , SVNRev& peg)\r
286 {\r
287         CString repoRoot = m_state.GetRepositoryRoot();\r
288 \r
289     // get path and revision\r
290 \r
291         path.SetFromSVN (repoRoot + CUnicodeUtils::GetUnicode (node->GetPath().GetPath().c_str()));\r
292         rev = head ? SVNRev::REV_HEAD : node->GetRevision();\r
293 \r
294     // handle 'modified WC' node\r
295 \r
296     if (node->GetClassification().Is (CNodeClassification::IS_MODIFIED_WC))\r
297     {\r
298         path.SetFromWin (m_sPath);\r
299         rev = SVNRev::REV_WC;\r
300 \r
301         // don't set peg, if we aren't the first node \r
302         // (i.e. would not be valid for node1)\r
303 \r
304         if (node == m_SelectedEntry1)\r
305             peg = SVNRev::REV_WC;\r
306     }\r
307     else\r
308     {\r
309         // set head, if still necessary\r
310 \r
311         if (head && !peg.IsValid())\r
312             peg = node->GetRevision();\r
313     }\r
314 }\r
315 \r
316 void CRevisionGraphWnd::CompareRevs(bool bHead)\r
317 {\r
318         ASSERT(m_SelectedEntry1 != NULL);\r
319         ASSERT(m_SelectedEntry2 != NULL);\r
320 \r
321         CSyncPointer<SVN> svn (m_state.GetSVN());\r
322 \r
323         CTSVNPath url1;\r
324         CTSVNPath url2;\r
325         SVNRev rev1;\r
326         SVNRev rev2;\r
327         SVNRev peg;\r
328 \r
329     GetSelected (m_SelectedEntry1, bHead, url1, rev1, peg);\r
330     GetSelected (m_SelectedEntry2, bHead, url2, rev2, peg);\r
331 \r
332     bool alternativeTool = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
333         if (m_state.PromptShown())\r
334         {\r
335                 SVNDiff diff (svn.get(), this->m_hWnd);\r
336                 diff.SetAlternativeTool (alternativeTool);\r
337                 diff.ShowCompare (url1, rev1, url2, rev2, peg); \r
338         }\r
339         else\r
340         {\r
341                 CAppUtils::StartShowCompare (m_hWnd, url1, rev1,\r
342                         url2, rev2, peg, SVNRev(), alternativeTool);\r
343         }\r
344 }\r
345 \r
346 void CRevisionGraphWnd::UnifiedDiffRevs(bool bHead)\r
347 {\r
348         ASSERT(m_SelectedEntry1 != NULL);\r
349         ASSERT(m_SelectedEntry2 != NULL);\r
350 \r
351         CSyncPointer<SVN> svn (m_state.GetSVN());\r
352 \r
353         CTSVNPath url1;\r
354         CTSVNPath url2;\r
355         SVNRev rev1;\r
356         SVNRev rev2;\r
357         SVNRev peg;\r
358 \r
359     GetSelected (m_SelectedEntry1, bHead, url1, rev1, peg);\r
360     GetSelected (m_SelectedEntry2, bHead, url2, rev2, peg);\r
361 \r
362     bool alternativeTool = !!(GetAsyncKeyState(VK_SHIFT) & 0x8000);\r
363         if (m_state.PromptShown())\r
364         {\r
365                 SVNDiff diff (svn.get(), this->m_hWnd);\r
366                 diff.SetAlternativeTool (alternativeTool);\r
367                 diff.ShowUnifiedDiff (url1, rev1, url2, rev2, peg);\r
368         }\r
369         else\r
370         {\r
371                 CAppUtils::StartShowUnifiedDiff(m_hWnd, url1, rev1,\r
372                         url2, rev2, peg, \r
373                         SVNRev(), alternativeTool);\r
374         }\r
375 }\r
376 \r
377 void CRevisionGraphWnd::DoZoom(float fZoomFactor)\r
378 {\r
379         float oldzoom = m_fZoomFactor;\r
380         m_fZoomFactor = fZoomFactor;\r
381 \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
385 \r
386         for (int i=0; i<MAXFONTS; i++)\r
387         {\r
388                 if (m_apFonts[i] != NULL)\r
389                 {\r
390                         m_apFonts[i]->DeleteObject();\r
391                         delete m_apFonts[i];\r
392                 }\r
393                 m_apFonts[i] = NULL;\r
394         }\r
395 \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
400 \r
401         InitView();\r
402 \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
407 \r
408         Invalidate();\r
409 }\r
410 \r