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 "MainWindow.h"
\r
21 #include "UnicodeUtils.h"
\r
23 CMainWindow::CMainWindow(HINSTANCE hInst, const WNDCLASSEX* wcx /* = NULL*/)
\r
24 : CWindow(hInst, wcx)
\r
25 , m_bShowFindBar(false)
\r
27 SetWindowTitle(_T("TortoiseUDiff"));
\r
30 CMainWindow::~CMainWindow(void)
\r
34 bool CMainWindow::RegisterAndCreateWindow()
\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
44 wcx.hInstance = hResource;
\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
53 if (Create(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN, NULL))
\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
65 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
\r
77 return DoCommand(LOWORD(wParam));
\r
82 if (GET_KEYSTATE_WPARAM(wParam) == MK_SHIFT)
\r
85 SendEditor(SCI_LINESCROLL, -GET_WHEEL_DELTA_WPARAM(wParam)/40, 0);
\r
88 return DefWindowProc(hwnd, uMsg, wParam, lParam);
\r
94 GetClientRect(*this, &rect);
\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
101 ::SetWindowPos(m_FindBar, HWND_TOP,
\r
102 rect.left, rect.bottom-30,
\r
103 rect.right-rect.left, 30,
\r
108 ::SetWindowPos(m_hWndEdit, HWND_TOP,
\r
109 rect.left, rect.top,
\r
110 rect.right-rect.left, rect.bottom-rect.top,
\r
112 ::ShowWindow(m_FindBar, SW_HIDE);
\r
116 case WM_GETMINMAXINFO:
\r
118 MINMAXINFO * mmi = (MINMAXINFO*)lParam;
\r
119 mmi->ptMinTrackSize.x = 100;
\r
120 mmi->ptMinTrackSize.y = 100;
\r
125 PostQuitMessage(0);
\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
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
139 ::DestroyWindow(m_hwnd);
\r
142 SetFocus(m_hWndEdit);
\r
144 case COMMITMONITOR_FINDMSGNEXT:
\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
154 case COMMITMONITOR_FINDMSGPREV:
\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
163 case COMMITMONITOR_FINDEXIT:
\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
175 case COMMITMONITOR_FINDRESET:
\r
176 SendEditor(SCI_SETSELECTIONSTART, 0);
\r
177 SendEditor(SCI_SETSELECTIONEND, 0);
\r
178 SendEditor(SCI_SEARCHANCHOR);
\r
181 return DefWindowProc(hwnd, uMsg, wParam, lParam);
\r
187 LRESULT CMainWindow::DoCommand(int id)
\r
192 ::PostQuitMessage(0);
\r
194 case IDM_SHOWFINDBAR:
\r
196 m_bShowFindBar = true;
\r
197 ::ShowWindow(m_FindBar, SW_SHOW);
\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
204 ::SetWindowPos(m_FindBar, HWND_TOP,
\r
205 rect.left, rect.bottom-30,
\r
206 rect.right-rect.left, 30,
\r
208 ::SetFocus(m_FindBar);
\r
209 SendEditor(SCI_SETSELECTIONSTART, 0);
\r
210 SendEditor(SCI_SETSELECTIONEND, 0);
\r
211 SendEditor(SCI_SEARCHANCHOR);
\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
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
227 if (IsWindowVisible(m_FindBar))
\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
239 PostQuitMessage(0);
\r
249 LRESULT CMainWindow::SendEditor(UINT Msg, WPARAM wParam, LPARAM lParam)
\r
251 if (m_directFunction)
\r
253 return ((SciFnDirect) m_directFunction)(m_directPointer, Msg, wParam, lParam);
\r
255 return ::SendMessage(m_hWndEdit, Msg, wParam, lParam);
\r
258 bool CMainWindow::Initialize()
\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
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
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
279 m_hWndEdit = ::CreateWindow(
\r
282 WS_CHILD | WS_VSCROLL | WS_HSCROLL | WS_CLIPCHILDREN,
\r
283 CW_USEDEFAULT, CW_USEDEFAULT,
\r
284 CW_USEDEFAULT, CW_USEDEFAULT,
\r
289 if (m_hWndEdit == NULL)
\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
299 m_directFunction = SendMessage(m_hWndEdit, SCI_GETDIRECTFUNCTION, 0, 0);
\r
300 m_directPointer = SendMessage(m_hWndEdit, SCI_GETDIRECTPOINTER, 0, 0);
\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
325 bool CMainWindow::LoadFile(LPCTSTR filename)
\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
335 _tfopen_s(&fp, filename, _T("rb"));
\r
340 int lenFile = fread(data, 1, sizeof(data), fp);
\r
341 bool bUTF8 = IsUTF8(data, lenFile);
\r
342 while (lenFile > 0)
\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
349 SendEditor(SCI_SETCODEPAGE, bUTF8 ? SC_CP_UTF8 : GetACP());
\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
363 SendEditor(SCI_CLEARDOCUMENTSTYLE, 0, 0);
\r
364 SendEditor(SCI_SETSTYLEBITS, 5, 0);
\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
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
382 void CMainWindow::SetTitle(LPCTSTR title)
\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
391 void CMainWindow::SetAStyle(int style, COLORREF fore, COLORREF back, int size, const char *face)
\r
393 SendEditor(SCI_STYLESETFORE, style, fore);
\r
394 SendEditor(SCI_STYLESETBACK, style, back);
\r
396 SendEditor(SCI_STYLESETSIZE, style, size);
\r
398 SendEditor(SCI_STYLESETFONT, style, reinterpret_cast<LPARAM>(face));
\r
401 bool CMainWindow::IsUTF8(LPVOID pBuffer, int cb)
\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
411 if (0x0000 == *pVal++)
\r
414 pVal = (UINT16 *)pBuffer;
\r
415 if (*pVal == 0xFEFF)
\r
419 if (*pVal == 0xBBEF)
\r
421 if (*pVal2 == 0xBF)
\r
424 // check for illegal UTF8 chars
\r
425 pVal2 = (UINT8 *)pBuffer;
\r
426 for (int i=0; i<cb; ++i)
\r
428 if ((*pVal2 == 0xC0)||(*pVal2 == 0xC1)||(*pVal2 >= 0xF5))
\r
432 pVal2 = (UINT8 *)pBuffer;
\r
433 bool bUTF8 = false;
\r
434 for (int i=0; i<(cb-3); ++i)
\r
436 if ((*pVal2 & 0xE0)==0xC0)
\r
439 if ((*pVal2 & 0xC0)!=0x80)
\r
443 if ((*pVal2 & 0xF0)==0xE0)
\r
446 if ((*pVal2 & 0xC0)!=0x80)
\r
449 if ((*pVal2 & 0xC0)!=0x80)
\r
453 if ((*pVal2 & 0xF8)==0xF0)
\r
456 if ((*pVal2 & 0xC0)!=0x80)
\r
459 if ((*pVal2 & 0xC0)!=0x80)
\r
462 if ((*pVal2 & 0xC0)!=0x80)
\r