OSDN Git Service

Merge from feature_merge branch. Build TortoiseMerge successfully.
[tortoisegit/TortoiseGitJp.git] / src / TortoiseUDiff / MainWindow.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // Copyright (C) 2003-2008 - 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 "MainWindow.h"\r
21 #include "UnicodeUtils.h"\r
22 \r
23 CMainWindow::CMainWindow(HINSTANCE hInst, const WNDCLASSEX* wcx /* = NULL*/) \r
24         : CWindow(hInst, wcx)\r
25         , m_bShowFindBar(false)\r
26 {\r
27         SetWindowTitle(_T("TortoiseUDiff"));\r
28 }\r
29 \r
30 CMainWindow::~CMainWindow(void)\r
31 {\r
32 }\r
33 \r
34 bool CMainWindow::RegisterAndCreateWindow()\r
35 {\r
36         WNDCLASSEX wcx; \r
37 \r
38         // Fill in the window class structure with default parameters \r
39         wcx.cbSize = sizeof(WNDCLASSEX);\r
40         wcx.style = CS_HREDRAW | CS_VREDRAW;\r
41         wcx.lpfnWndProc = CWindow::stWinMsgHandler;\r
42         wcx.cbClsExtra = 0;\r
43         wcx.cbWndExtra = 0;\r
44         wcx.hInstance = hResource;\r
45         wcx.hCursor = NULL;\r
46         wcx.lpszClassName = ResString(hResource, IDS_APP_TITLE);\r
47         wcx.hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_TORTOISEUDIFF));\r
48         wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);\r
49         wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEUDIFF);\r
50         wcx.hIconSm     = LoadIcon(wcx.hInstance, MAKEINTRESOURCE(IDI_TORTOISEUDIFF));\r
51         if (RegisterWindow(&wcx))\r
52         {\r
53                 if (Create(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN, NULL))\r
54                 {\r
55                         m_FindBar.SetParent(*this);\r
56                         m_FindBar.Create(hResource, IDD_FINDBAR, *this);\r
57                         ShowWindow(*this, SW_SHOW);\r
58                         UpdateWindow(*this);\r
59                         return true;\r
60                 }\r
61         }\r
62         return false;\r
63 }\r
64 \r
65 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
66 {\r
67         switch (uMsg)\r
68         {\r
69         case WM_CREATE:\r
70                 {\r
71                         m_hwnd = hwnd;\r
72                         Initialize();\r
73                 }\r
74                 break;\r
75         case WM_COMMAND:\r
76                 {\r
77                         return DoCommand(LOWORD(wParam));\r
78                 }\r
79                 break;\r
80         case WM_MOUSEWHEEL:\r
81                 {\r
82                         if (GET_KEYSTATE_WPARAM(wParam) == MK_SHIFT)\r
83                         {\r
84                                 // scroll sideways\r
85                                 SendEditor(SCI_LINESCROLL, -GET_WHEEL_DELTA_WPARAM(wParam)/40, 0);\r
86                         }\r
87                         else\r
88                                 return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
89                 }\r
90                 break;\r
91         case WM_SIZE:\r
92                 {\r
93                         RECT rect;\r
94                         GetClientRect(*this, &rect);\r
95                         if (m_bShowFindBar)\r
96                         {\r
97                                 ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
98                                         rect.left, rect.top,\r
99                                         rect.right-rect.left, rect.bottom-rect.top-30,\r
100                                         SWP_SHOWWINDOW);\r
101                                 ::SetWindowPos(m_FindBar, HWND_TOP,\r
102                                         rect.left, rect.bottom-30,\r
103                                         rect.right-rect.left, 30,\r
104                                         SWP_SHOWWINDOW);\r
105                         }\r
106                         else\r
107                         {\r
108                                 ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
109                                         rect.left, rect.top,\r
110                                         rect.right-rect.left, rect.bottom-rect.top,\r
111                                         SWP_SHOWWINDOW);\r
112                                 ::ShowWindow(m_FindBar, SW_HIDE);\r
113                         }\r
114                 }\r
115                 break;\r
116         case WM_GETMINMAXINFO:\r
117                 {\r
118                         MINMAXINFO * mmi = (MINMAXINFO*)lParam;\r
119                         mmi->ptMinTrackSize.x = 100;\r
120                         mmi->ptMinTrackSize.y = 100;\r
121                         return 0;\r
122                 }\r
123                 break;\r
124         case WM_DESTROY:\r
125                 PostQuitMessage(0);\r
126                 break;\r
127         case WM_CLOSE:\r
128                 {\r
129                         CRegStdWORD w = CRegStdWORD(_T("Software\\TortoiseGit\\UDiffViewerWidth"), (DWORD)CW_USEDEFAULT);\r
130                         CRegStdWORD h = CRegStdWORD(_T("Software\\TortoiseGit\\UDiffViewerHeight"), (DWORD)CW_USEDEFAULT);\r
131                         CRegStdWORD p = CRegStdWORD(_T("Software\\TortoiseGit\\UDiffViewerPos"), 0);\r
132 \r
133                         RECT rect;\r
134                         ::GetWindowRect(*this, &rect);\r
135                         w = rect.right-rect.left;\r
136                         h = rect.bottom-rect.top;\r
137                         p = MAKELONG(rect.left, rect.top);\r
138                 }\r
139                 ::DestroyWindow(m_hwnd);\r
140                 break;\r
141         case WM_SETFOCUS:\r
142                 SetFocus(m_hWndEdit);\r
143                 break;\r
144         case COMMITMONITOR_FINDMSGNEXT:\r
145                 {\r
146                         SendEditor(SCI_CHARRIGHT);\r
147                         SendEditor(SCI_SEARCHANCHOR);\r
148                         m_bMatchCase = !!wParam;\r
149                         m_findtext = (LPCTSTR)lParam;\r
150                         SendEditor(SCI_SEARCHNEXT, m_bMatchCase ? SCFIND_MATCHCASE : 0, (LPARAM)CUnicodeUtils::StdGetUTF8(m_findtext).c_str());\r
151                         SendEditor(SCI_SCROLLCARET);\r
152                 }\r
153                 break;\r
154         case COMMITMONITOR_FINDMSGPREV:\r
155                 {\r
156                         SendEditor(SCI_SEARCHANCHOR);\r
157                         m_bMatchCase = !!wParam;\r
158                         m_findtext = (LPCTSTR)lParam;\r
159                         SendEditor(SCI_SEARCHPREV, m_bMatchCase ? SCFIND_MATCHCASE : 0, (LPARAM)CUnicodeUtils::StdGetUTF8(m_findtext).c_str());\r
160                         SendEditor(SCI_SCROLLCARET);\r
161                 }\r
162                 break;\r
163         case COMMITMONITOR_FINDEXIT:\r
164                 {\r
165                         RECT rect;\r
166                         GetClientRect(*this, &rect);\r
167                         m_bShowFindBar = false;\r
168                         ::ShowWindow(m_FindBar, SW_HIDE);\r
169                         ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
170                                 rect.left, rect.top,\r
171                                 rect.right-rect.left, rect.bottom-rect.top,\r
172                                 SWP_SHOWWINDOW);\r
173                 }\r
174                 break;\r
175         case COMMITMONITOR_FINDRESET:\r
176                 SendEditor(SCI_SETSELECTIONSTART, 0);\r
177                 SendEditor(SCI_SETSELECTIONEND, 0);\r
178                 SendEditor(SCI_SEARCHANCHOR);\r
179                 break;\r
180         default:\r
181                 return DefWindowProc(hwnd, uMsg, wParam, lParam);\r
182         }\r
183 \r
184         return 0;\r
185 };\r
186 \r
187 LRESULT CMainWindow::DoCommand(int id)\r
188 {\r
189         switch (id) \r
190         {\r
191         case ID_FILE_EXIT:\r
192                 ::PostQuitMessage(0);\r
193                 return 0;\r
194         case IDM_SHOWFINDBAR:\r
195                 {\r
196                         m_bShowFindBar = true;\r
197                         ::ShowWindow(m_FindBar, SW_SHOW);\r
198                         RECT rect;\r
199                         GetClientRect(*this, &rect);\r
200                         ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
201                                 rect.left, rect.top,\r
202                                 rect.right-rect.left, rect.bottom-rect.top-30,\r
203                                 SWP_SHOWWINDOW);\r
204                         ::SetWindowPos(m_FindBar, HWND_TOP,\r
205                                 rect.left, rect.bottom-30,\r
206                                 rect.right-rect.left, 30,\r
207                                 SWP_SHOWWINDOW);\r
208                         ::SetFocus(m_FindBar);\r
209                         SendEditor(SCI_SETSELECTIONSTART, 0);\r
210                         SendEditor(SCI_SETSELECTIONEND, 0);\r
211                         SendEditor(SCI_SEARCHANCHOR);\r
212                 }\r
213                 break;\r
214         case IDM_FINDNEXT:\r
215                 SendEditor(SCI_CHARRIGHT);\r
216                 SendEditor(SCI_SEARCHANCHOR);\r
217                 SendEditor(SCI_SEARCHNEXT, m_bMatchCase ? SCFIND_MATCHCASE : 0, (LPARAM)CUnicodeUtils::StdGetUTF8(m_findtext).c_str());\r
218                 SendEditor(SCI_SCROLLCARET);\r
219                 break;\r
220         case IDM_FINDPREV:\r
221                 SendEditor(SCI_SEARCHANCHOR);\r
222                 SendEditor(SCI_SEARCHPREV, m_bMatchCase ? SCFIND_MATCHCASE : 0, (LPARAM)CUnicodeUtils::StdGetUTF8(m_findtext).c_str());\r
223                 SendEditor(SCI_SCROLLCARET);\r
224                 break;\r
225         case IDM_FINDEXIT:\r
226                 {\r
227                         if (IsWindowVisible(m_FindBar))\r
228                         {\r
229                                 RECT rect;\r
230                                 GetClientRect(*this, &rect);\r
231                                 m_bShowFindBar = false;\r
232                                 ::ShowWindow(m_FindBar, SW_HIDE);\r
233                                 ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
234                                         rect.left, rect.top,\r
235                                         rect.right-rect.left, rect.bottom-rect.top,\r
236                                         SWP_SHOWWINDOW);\r
237                         }\r
238                         else\r
239                                 PostQuitMessage(0);\r
240                 }\r
241                 break;\r
242         default:\r
243                 break;\r
244         };\r
245         return 1;\r
246 }\r
247 \r
248 \r
249 LRESULT CMainWindow::SendEditor(UINT Msg, WPARAM wParam, LPARAM lParam)\r
250 {\r
251         if (m_directFunction)\r
252         {\r
253                 return ((SciFnDirect) m_directFunction)(m_directPointer, Msg, wParam, lParam);\r
254         }\r
255         return ::SendMessage(m_hWndEdit, Msg, wParam, lParam);  \r
256 }\r
257 \r
258 bool CMainWindow::Initialize()\r
259 {\r
260         CRegStdWORD pos(_T("Software\\TortoiseGit\\UDiffViewerPos"), 0);\r
261         CRegStdWORD width(_T("Software\\TortoiseGit\\UDiffViewerWidth"), (DWORD)640);\r
262         CRegStdWORD height(_T("Software\\TortoiseGit\\UDiffViewerHeight"), (DWORD)480);\r
263         if (DWORD(pos) && DWORD(width) && DWORD(height))\r
264         {\r
265                 RECT rc;\r
266                 rc.left = LOWORD(DWORD(pos));\r
267                 rc.top = HIWORD(DWORD(pos));\r
268                 rc.right = rc.left + DWORD(width);\r
269                 rc.bottom = rc.top + DWORD(height);\r
270                 HMONITOR hMon = MonitorFromRect(&rc, MONITOR_DEFAULTTONULL);\r
271                 if (hMon)\r
272                 {\r
273                         // only restore the window position if the monitor is valid\r
274                         MoveWindow(*this, LOWORD(DWORD(pos)), HIWORD(DWORD(pos)),\r
275                                 DWORD(width), DWORD(height), FALSE);\r
276                 }\r
277         }\r
278 \r
279         m_hWndEdit = ::CreateWindow(\r
280                 _T("Scintilla"),\r
281                 _T("Source"),\r
282                 WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN,\r
283                 CW_USEDEFAULT, CW_USEDEFAULT,\r
284                 CW_USEDEFAULT, CW_USEDEFAULT,\r
285                 *this,\r
286                 0,\r
287                 hResource,\r
288                 0);\r
289         if (m_hWndEdit == NULL)\r
290                 return false;\r
291 \r
292         RECT rect;\r
293         GetClientRect(*this, &rect);\r
294         ::SetWindowPos(m_hWndEdit, HWND_TOP, \r
295                 rect.left, rect.top,\r
296                 rect.right-rect.left, rect.bottom-rect.top,\r
297                 SWP_SHOWWINDOW);\r
298 \r
299         m_directFunction = SendMessage(m_hWndEdit, SCI_GETDIRECTFUNCTION, 0, 0);\r
300         m_directPointer = SendMessage(m_hWndEdit, SCI_GETDIRECTPOINTER, 0, 0);\r
301 \r
302         // Set up the global default style. These attributes are used wherever no explicit choices are made.\r
303         SetAStyle(STYLE_DEFAULT, ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOW),\r
304                 // Reusing TortoiseBlame's setting which already have an user friendly\r
305                 // pane in TortoiseSVN's Settings dialog, while there is no such\r
306                 // pane for TortoiseUDiff.\r
307                 CRegStdWORD(_T("Software\\TortoiseGit\\BlameFontSize"), 10),\r
308                 WideToMultibyte(CRegStdString(_T("Software\\TortoiseGit\\BlameFontName"), _T("Courier New"))).c_str());\r
309         SendEditor(SCI_SETTABWIDTH, 4);\r
310         SendEditor(SCI_SETREADONLY, TRUE);\r
311         LRESULT pix = SendEditor(SCI_TEXTWIDTH, STYLE_LINENUMBER, (LPARAM)"_99999");\r
312         SendEditor(SCI_SETMARGINWIDTHN, 0, pix);\r
313         SendEditor(SCI_SETMARGINWIDTHN, 1);\r
314         SendEditor(SCI_SETMARGINWIDTHN, 2);\r
315         //Set the default windows colors for edit controls\r
316         SendEditor(SCI_STYLESETFORE, STYLE_DEFAULT, ::GetSysColor(COLOR_WINDOWTEXT));\r
317         SendEditor(SCI_STYLESETBACK, STYLE_DEFAULT, ::GetSysColor(COLOR_WINDOW));\r
318         SendEditor(SCI_SETSELFORE, TRUE, ::GetSysColor(COLOR_HIGHLIGHTTEXT));\r
319         SendEditor(SCI_SETSELBACK, TRUE, ::GetSysColor(COLOR_HIGHLIGHT));\r
320         SendEditor(SCI_SETCARETFORE, ::GetSysColor(COLOR_WINDOWTEXT));\r
321 \r
322         return true;\r
323 }\r
324 \r
325 bool CMainWindow::LoadFile(LPCTSTR filename)\r
326 {\r
327         SendEditor(SCI_SETREADONLY, FALSE);\r
328         SendEditor(SCI_CLEARALL);\r
329         SendEditor(EM_EMPTYUNDOBUFFER);\r
330         SendEditor(SCI_SETSAVEPOINT);\r
331         SendEditor(SCI_CANCEL);\r
332         SendEditor(SCI_SETUNDOCOLLECTION, 0);\r
333 \r
334         FILE *fp = NULL;\r
335         _tfopen_s(&fp, filename, _T("rb"));\r
336         if (fp) \r
337         {\r
338                 //SetTitle();\r
339                 char data[4096];\r
340                 int lenFile = fread(data, 1, sizeof(data), fp);\r
341                 bool bUTF8 = IsUTF8(data, lenFile);\r
342                 while (lenFile > 0) \r
343                 {\r
344                         SendEditor(SCI_ADDTEXT, lenFile,\r
345                                 reinterpret_cast<LPARAM>(static_cast<char *>(data)));\r
346                         lenFile = fread(data, 1, sizeof(data), fp);\r
347                 }\r
348                 fclose(fp);\r
349                 SendEditor(SCI_SETCODEPAGE, bUTF8 ? SC_CP_UTF8 : GetACP());\r
350         }\r
351         else \r
352         {\r
353                 return false;\r
354         }\r
355 \r
356         SendEditor(SCI_SETUNDOCOLLECTION, 1);\r
357         ::SetFocus(m_hWndEdit);\r
358         SendEditor(EM_EMPTYUNDOBUFFER);\r
359         SendEditor(SCI_SETSAVEPOINT);\r
360         SendEditor(SCI_GOTOPOS, 0);\r
361         SendEditor(SCI_SETREADONLY, TRUE);\r
362 \r
363         SendEditor(SCI_CLEARDOCUMENTSTYLE, 0, 0);\r
364         SendEditor(SCI_SETSTYLEBITS, 5, 0);\r
365 \r
366         //SetAStyle(SCE_DIFF_DEFAULT, RGB(0, 0, 0));\r
367         SetAStyle(SCE_DIFF_COMMAND, RGB(0x0A, 0x24, 0x36));\r
368         SetAStyle(SCE_DIFF_POSITION, RGB(0xFF, 0, 0));\r
369         SetAStyle(SCE_DIFF_HEADER, RGB(0x80, 0, 0), RGB(0xFF, 0xFF, 0x80));\r
370         SetAStyle(SCE_DIFF_COMMENT, RGB(0, 0x80, 0));\r
371         SendEditor(SCI_STYLESETBOLD, SCE_DIFF_COMMENT, TRUE);\r
372         SetAStyle(SCE_DIFF_DELETED, ::GetSysColor(COLOR_WINDOWTEXT), RGB(0xFF, 0x80, 0x80));\r
373         SetAStyle(SCE_DIFF_ADDED, ::GetSysColor(COLOR_WINDOWTEXT), RGB(0x80, 0xFF, 0x80));\r
374 \r
375         SendEditor(SCI_SETLEXER, SCLEX_DIFF);\r
376         SendEditor(SCI_SETKEYWORDS, 0, (LPARAM)"revision");\r
377         SendEditor(SCI_COLOURISE, 0, -1);\r
378         ::ShowWindow(m_hWndEdit, SW_SHOW);\r
379         return true;\r
380 }\r
381 \r
382 void CMainWindow::SetTitle(LPCTSTR title)\r
383 {\r
384         int len = _tcslen(title);\r
385         TCHAR * pBuf = new TCHAR[len+40];\r
386         _stprintf_s(pBuf, len+40, _T("%s - TortoiseUDiff"), title);\r
387         SetWindowTitle(std::wstring(pBuf));\r
388         delete [] pBuf;\r
389 }\r
390 \r
391 void CMainWindow::SetAStyle(int style, COLORREF fore, COLORREF back, int size, const char *face) \r
392 {\r
393         SendEditor(SCI_STYLESETFORE, style, fore);\r
394         SendEditor(SCI_STYLESETBACK, style, back);\r
395         if (size >= 1)\r
396                 SendEditor(SCI_STYLESETSIZE, style, size);\r
397         if (face) \r
398                 SendEditor(SCI_STYLESETFONT, style, reinterpret_cast<LPARAM>(face));\r
399 }\r
400 \r
401 bool CMainWindow::IsUTF8(LPVOID pBuffer, int cb)\r
402 {\r
403         if (cb < 2)\r
404                 return true;\r
405         UINT16 * pVal = (UINT16 *)pBuffer;\r
406         UINT8 * pVal2 = (UINT8 *)(pVal+1);\r
407         // scan the whole buffer for a 0x0000 sequence\r
408         // if found, we assume a binary file\r
409         for (int i=0; i<(cb-2); i=i+2)\r
410         {\r
411                 if (0x0000 == *pVal++)\r
412                         return false;\r
413         }\r
414         pVal = (UINT16 *)pBuffer;\r
415         if (*pVal == 0xFEFF)\r
416                 return false;\r
417         if (cb < 3)\r
418                 return false;\r
419         if (*pVal == 0xBBEF)\r
420         {\r
421                 if (*pVal2 == 0xBF)\r
422                         return true;\r
423         }\r
424         // check for illegal UTF8 chars\r
425         pVal2 = (UINT8 *)pBuffer;\r
426         for (int i=0; i<cb; ++i)\r
427         {\r
428                 if ((*pVal2 == 0xC0)||(*pVal2 == 0xC1)||(*pVal2 >= 0xF5))\r
429                         return false;\r
430                 pVal2++;\r
431         }\r
432         pVal2 = (UINT8 *)pBuffer;\r
433         bool bUTF8 = false;\r
434         for (int i=0; i<(cb-3); ++i)\r
435         {\r
436                 if ((*pVal2 & 0xE0)==0xC0)\r
437                 {\r
438                         pVal2++;i++;\r
439                         if ((*pVal2 & 0xC0)!=0x80)\r
440                                 return false;\r
441                         bUTF8 = true;\r
442                 }\r
443                 if ((*pVal2 & 0xF0)==0xE0)\r
444                 {\r
445                         pVal2++;i++;\r
446                         if ((*pVal2 & 0xC0)!=0x80)\r
447                                 return false;\r
448                         pVal2++;i++;\r
449                         if ((*pVal2 & 0xC0)!=0x80)\r
450                                 return false;\r
451                         bUTF8 = true;\r
452                 }\r
453                 if ((*pVal2 & 0xF8)==0xF0)\r
454                 {\r
455                         pVal2++;i++;\r
456                         if ((*pVal2 & 0xC0)!=0x80)\r
457                                 return false;\r
458                         pVal2++;i++;\r
459                         if ((*pVal2 & 0xC0)!=0x80)\r
460                                 return false;\r
461                         pVal2++;i++;\r
462                         if ((*pVal2 & 0xC0)!=0x80)\r
463                                 return false;\r
464                         bUTF8 = true;\r
465                 }\r
466                 pVal2++;\r
467         }\r
468         if (bUTF8)\r
469                 return true;\r
470         return false;\r
471 }\r