1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2009 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "MainWindow.h"
21 #include "UnicodeUtils.h"
24 CMainWindow::CMainWindow(HINSTANCE hInst
, const WNDCLASSEX
* wcx
/* = NULL*/)
26 , m_bShowFindBar(false)
28 SetWindowTitle(_T("TortoiseUDiff"));
31 CMainWindow::~CMainWindow(void)
35 bool CMainWindow::RegisterAndCreateWindow()
39 // Fill in the window class structure with default parameters
40 wcx
.cbSize
= sizeof(WNDCLASSEX
);
41 wcx
.style
= CS_HREDRAW
| CS_VREDRAW
;
42 wcx
.lpfnWndProc
= CWindow::stWinMsgHandler
;
45 wcx
.hInstance
= hResource
;
47 wcx
.lpszClassName
= ResString(hResource
, IDS_APP_TITLE
);
48 wcx
.hIcon
= LoadIcon(hResource
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
));
49 wcx
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+1);
50 wcx
.lpszMenuName
= MAKEINTRESOURCE(IDC_TORTOISEUDIFF
);
51 wcx
.hIconSm
= LoadIcon(wcx
.hInstance
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
));
52 if (RegisterWindow(&wcx
))
54 if (Create(WS_CAPTION
| WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
, NULL
))
56 m_FindBar
.SetParent(*this);
57 m_FindBar
.Create(hResource
, IDD_FINDBAR
, *this);
58 ShowWindow(*this, SW_SHOW
);
66 LRESULT CALLBACK
CMainWindow::WinMsgHandler(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
78 return DoCommand(LOWORD(wParam
));
83 if (GET_KEYSTATE_WPARAM(wParam
) == MK_SHIFT
)
86 SendEditor(SCI_LINESCROLL
, -GET_WHEEL_DELTA_WPARAM(wParam
)/40, 0);
89 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
95 GetClientRect(*this, &rect
);
98 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
100 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
-30,
102 ::SetWindowPos(m_FindBar
, HWND_TOP
,
103 rect
.left
, rect
.bottom
-30,
104 rect
.right
-rect
.left
, 30,
109 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
111 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
113 ::ShowWindow(m_FindBar
, SW_HIDE
);
117 case WM_GETMINMAXINFO
:
119 MINMAXINFO
* mmi
= (MINMAXINFO
*)lParam
;
120 mmi
->ptMinTrackSize
.x
= 100;
121 mmi
->ptMinTrackSize
.y
= 100;
130 CRegStdDWORD w
= CRegStdDWORD(_T("Software\\TortoiseGit\\UDiffViewerWidth"), (DWORD
)CW_USEDEFAULT
);
131 CRegStdDWORD h
= CRegStdDWORD(_T("Software\\TortoiseGit\\UDiffViewerHeight"), (DWORD
)CW_USEDEFAULT
);
132 CRegStdDWORD p
= CRegStdDWORD(_T("Software\\TortoiseGit\\UDiffViewerPos"), 0);
135 ::GetWindowRect(*this, &rect
);
136 w
= rect
.right
-rect
.left
;
137 h
= rect
.bottom
-rect
.top
;
138 p
= MAKELONG(rect
.left
, rect
.top
);
140 ::DestroyWindow(m_hwnd
);
143 SetFocus(m_hWndEdit
);
145 case COMMITMONITOR_FINDMSGNEXT
:
147 SendEditor(SCI_CHARRIGHT
);
148 SendEditor(SCI_SEARCHANCHOR
);
149 m_bMatchCase
= !!wParam
;
150 m_findtext
= (LPCTSTR
)lParam
;
151 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
152 SendEditor(SCI_SCROLLCARET
);
155 case COMMITMONITOR_FINDMSGPREV
:
157 SendEditor(SCI_SEARCHANCHOR
);
158 m_bMatchCase
= !!wParam
;
159 m_findtext
= (LPCTSTR
)lParam
;
160 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
161 SendEditor(SCI_SCROLLCARET
);
164 case COMMITMONITOR_FINDEXIT
:
167 GetClientRect(*this, &rect
);
168 m_bShowFindBar
= false;
169 ::ShowWindow(m_FindBar
, SW_HIDE
);
170 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
172 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
176 case COMMITMONITOR_FINDRESET
:
177 SendEditor(SCI_SETSELECTIONSTART
, 0);
178 SendEditor(SCI_SETSELECTIONEND
, 0);
179 SendEditor(SCI_SEARCHANCHOR
);
182 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
188 LRESULT
CMainWindow::DoCommand(int id
)
194 OPENFILENAME ofn
= {0}; // common dialog box structure
195 TCHAR szFile
[MAX_PATH
] = {0}; // buffer for file name
196 // Initialize OPENFILENAME
197 ofn
.lStructSize
= sizeof(OPENFILENAME
);
198 ofn
.hwndOwner
= *this;
199 ofn
.lpstrFile
= szFile
;
200 ofn
.nMaxFile
= _countof(szFile
);
202 LoadString(hResource
, IDS_PATCHFILEFILTER
, filter
, _countof(filter
));
203 TCHAR
* pszFilters
= filter
;
204 // Replace '|' delimiters with '\0's
205 TCHAR
*ptr
= pszFilters
+ _tcslen(pszFilters
); //set ptr at the NULL
206 while (ptr
!= pszFilters
)
212 ofn
.lpstrFilter
= pszFilters
;
213 ofn
.nFilterIndex
= 1;
214 ofn
.lpstrFileTitle
= NULL
;
215 ofn
.nMaxFileTitle
= 0;
216 ofn
.lpstrInitialDir
= NULL
;
217 TCHAR opentitle
[1024];
218 LoadString(hResource
, IDS_OPENPATCH
, opentitle
, _countof(opentitle
));
219 ofn
.lpstrTitle
= opentitle
;
220 ofn
.Flags
= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
| OFN_ENABLESIZING
| OFN_EXPLORER
;
221 // Display the Open dialog box.
222 if (GetOpenFileName(&ofn
)==TRUE
)
224 LoadFile(ofn
.lpstrFile
);
230 OPENFILENAME ofn
= {0}; // common dialog box structure
231 TCHAR szFile
[MAX_PATH
] = {0}; // buffer for file name
232 // Initialize OPENFILENAME
233 ofn
.lStructSize
= sizeof(OPENFILENAME
);
234 ofn
.hwndOwner
= *this;
235 ofn
.lpstrFile
= szFile
;
236 ofn
.nMaxFile
= _countof(szFile
);
238 LoadString(hResource
, IDS_PATCHFILEFILTER
, filter
, _countof(filter
));
239 TCHAR
* pszFilters
= filter
;
240 // Replace '|' delimiters with '\0's
241 TCHAR
*ptr
= pszFilters
+ _tcslen(pszFilters
); //set ptr at the NULL
242 while (ptr
!= pszFilters
)
248 ofn
.lpstrFilter
= pszFilters
;
249 ofn
.nFilterIndex
= 1;
250 ofn
.lpstrFileTitle
= NULL
;
251 ofn
.nMaxFileTitle
= 0;
252 ofn
.lpstrInitialDir
= NULL
;
253 TCHAR savetitle
[1024];
254 LoadString(hResource
, IDS_SAVEPATCH
, savetitle
, _countof(savetitle
));
255 ofn
.lpstrTitle
= savetitle
;
256 ofn
.Flags
= OFN_OVERWRITEPROMPT
| OFN_ENABLESIZING
| OFN_EXPLORER
;
257 // Display the Open dialog box.
258 if (GetSaveFileName(&ofn
)==TRUE
)
260 SaveFile(ofn
.lpstrFile
);
265 ::PostQuitMessage(0);
267 case IDM_SHOWFINDBAR
:
269 m_bShowFindBar
= true;
270 ::ShowWindow(m_FindBar
, SW_SHOW
);
272 GetClientRect(*this, &rect
);
273 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
275 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
-30,
277 ::SetWindowPos(m_FindBar
, HWND_TOP
,
278 rect
.left
, rect
.bottom
-30,
279 rect
.right
-rect
.left
, 30,
281 ::SetFocus(m_FindBar
);
282 SendEditor(SCI_SETSELECTIONSTART
, 0);
283 SendEditor(SCI_SETSELECTIONEND
, 0);
284 SendEditor(SCI_SEARCHANCHOR
);
288 SendEditor(SCI_CHARRIGHT
);
289 SendEditor(SCI_SEARCHANCHOR
);
290 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
291 SendEditor(SCI_SCROLLCARET
);
294 SendEditor(SCI_SEARCHANCHOR
);
295 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
296 SendEditor(SCI_SCROLLCARET
);
300 if (IsWindowVisible(m_FindBar
))
303 GetClientRect(*this, &rect
);
304 m_bShowFindBar
= false;
305 ::ShowWindow(m_FindBar
, SW_HIDE
);
306 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
308 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
322 LRESULT
CMainWindow::SendEditor(UINT Msg
, WPARAM wParam
, LPARAM lParam
)
324 if (m_directFunction
)
326 return ((SciFnDirect
) m_directFunction
)(m_directPointer
, Msg
, wParam
, lParam
);
328 return ::SendMessage(m_hWndEdit
, Msg
, wParam
, lParam
);
331 bool CMainWindow::Initialize()
333 CRegStdDWORD
pos(_T("Software\\TortoiseGit\\UDiffViewerPos"), 0);
334 CRegStdDWORD
width(_T("Software\\TortoiseGit\\UDiffViewerWidth"), (DWORD
)640);
335 CRegStdDWORD
height(_T("Software\\TortoiseGit\\UDiffViewerHeight"), (DWORD
)480);
336 if (DWORD(pos
) && DWORD(width
) && DWORD(height
))
339 rc
.left
= LOWORD(DWORD(pos
));
340 rc
.top
= HIWORD(DWORD(pos
));
341 rc
.right
= rc
.left
+ DWORD(width
);
342 rc
.bottom
= rc
.top
+ DWORD(height
);
343 HMONITOR hMon
= MonitorFromRect(&rc
, MONITOR_DEFAULTTONULL
);
346 // only restore the window position if the monitor is valid
347 MoveWindow(*this, LOWORD(DWORD(pos
)), HIWORD(DWORD(pos
)),
348 DWORD(width
), DWORD(height
), FALSE
);
352 m_hWndEdit
= ::CreateWindow(
355 WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
| WS_CLIPCHILDREN
,
356 CW_USEDEFAULT
, CW_USEDEFAULT
,
357 CW_USEDEFAULT
, CW_USEDEFAULT
,
362 if (m_hWndEdit
== NULL
)
366 GetClientRect(*this, &rect
);
367 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
369 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
372 m_directFunction
= SendMessage(m_hWndEdit
, SCI_GETDIRECTFUNCTION
, 0, 0);
373 m_directPointer
= SendMessage(m_hWndEdit
, SCI_GETDIRECTPOINTER
, 0, 0);
375 // Set up the global default style. These attributes are used wherever no explicit choices are made.
376 SetAStyle(STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
), ::GetSysColor(COLOR_WINDOW
),
377 // Reusing TortoiseBlame's setting which already have an user friendly
378 // pane in TortoiseSVN's Settings dialog, while there is no such
379 // pane for TortoiseUDiff.
380 CRegStdDWORD(_T("Software\\TortoiseGit\\BlameFontSize"), 10),
381 WideToMultibyte(CRegStdString(_T("Software\\TortoiseGit\\BlameFontName"), _T("Courier New"))).c_str());
382 SendEditor(SCI_SETTABWIDTH
, 4);
383 SendEditor(SCI_SETREADONLY
, TRUE
);
384 LRESULT pix
= SendEditor(SCI_TEXTWIDTH
, STYLE_LINENUMBER
, (LPARAM
)"_99999");
385 SendEditor(SCI_SETMARGINWIDTHN
, 0, pix
);
386 SendEditor(SCI_SETMARGINWIDTHN
, 1);
387 SendEditor(SCI_SETMARGINWIDTHN
, 2);
388 //Set the default windows colors for edit controls
389 SendEditor(SCI_STYLESETFORE
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
));
390 SendEditor(SCI_STYLESETBACK
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOW
));
391 SendEditor(SCI_SETSELFORE
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHTTEXT
));
392 SendEditor(SCI_SETSELBACK
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHT
));
393 SendEditor(SCI_SETCARETFORE
, ::GetSysColor(COLOR_WINDOWTEXT
));
394 if (SysInfo::Instance().IsWin7OrLater())
396 SendEditor(SCI_SETTECHNOLOGY
, SC_TECHNOLOGY_DIRECTWRITE
);
397 SendEditor(SCI_SETBUFFEREDDRAW
, 0);
399 SendEditor(SCI_SETFONTQUALITY
, SC_EFF_QUALITY_LCD_OPTIMIZED
);
404 bool CMainWindow::LoadFile(LPCTSTR filename
)
406 SendEditor(SCI_SETREADONLY
, FALSE
);
407 SendEditor(SCI_CLEARALL
);
408 SendEditor(EM_EMPTYUNDOBUFFER
);
409 SendEditor(SCI_SETSAVEPOINT
);
410 SendEditor(SCI_CANCEL
);
411 SendEditor(SCI_SETUNDOCOLLECTION
, 0);
414 _tfopen_s(&fp
, filename
, _T("rb"));
419 size_t lenFile
= fread(data
, 1, sizeof(data
), fp
);
420 bool bUTF8
= IsUTF8(data
, lenFile
);
423 SendEditor(SCI_ADDTEXT
, lenFile
,
424 reinterpret_cast<LPARAM
>(static_cast<char *>(data
)));
425 lenFile
= fread(data
, 1, sizeof(data
), fp
);
428 SendEditor(SCI_SETCODEPAGE
, bUTF8
? SC_CP_UTF8
: GetACP());
435 SendEditor(SCI_SETUNDOCOLLECTION
, 1);
436 ::SetFocus(m_hWndEdit
);
437 SendEditor(EM_EMPTYUNDOBUFFER
);
438 SendEditor(SCI_SETSAVEPOINT
);
439 SendEditor(SCI_GOTOPOS
, 0);
441 SendEditor(SCI_CLEARDOCUMENTSTYLE
, 0, 0);
442 SendEditor(SCI_SETSTYLEBITS
, 5, 0);
444 //SetAStyle(SCE_DIFF_DEFAULT, RGB(0, 0, 0));
445 SetAStyle(SCE_DIFF_COMMAND
, RGB(0x0A, 0x24, 0x36));
446 SetAStyle(SCE_DIFF_POSITION
, RGB(0xFF, 0, 0));
447 SetAStyle(SCE_DIFF_HEADER
, RGB(0x80, 0, 0), RGB(0xFF, 0xFF, 0x80));
448 SetAStyle(SCE_DIFF_COMMENT
, RGB(0, 0x80, 0));
449 SendEditor(SCI_STYLESETBOLD
, SCE_DIFF_COMMENT
, TRUE
);
450 SetAStyle(SCE_DIFF_DELETED
, ::GetSysColor(COLOR_WINDOWTEXT
), RGB(0xFF, 0x80, 0x80));
451 SetAStyle(SCE_DIFF_ADDED
, ::GetSysColor(COLOR_WINDOWTEXT
), RGB(0x80, 0xFF, 0x80));
453 SendEditor(SCI_SETLEXER
, SCLEX_DIFF
);
454 SendEditor(SCI_SETKEYWORDS
, 0, (LPARAM
)"revision");
455 SendEditor(SCI_COLOURISE
, 0, -1);
456 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
460 bool CMainWindow::SaveFile(LPCTSTR filename
)
463 _tfopen_s(&fp
, filename
, _T("w+b"));
466 int len
= SendEditor(SCI_GETTEXT
, 0, 0);
467 char * data
= new char[len
+1];
468 SendEditor(SCI_GETTEXT
, len
, (LPARAM
)data
);
469 fwrite(data
, sizeof(char), len
-1, fp
);
477 SendEditor(SCI_SETSAVEPOINT
);
478 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
482 void CMainWindow::SetTitle(LPCTSTR title
)
484 size_t len
= _tcslen(title
);
485 TCHAR
* pBuf
= new TCHAR
[len
+40];
486 _stprintf_s(pBuf
, len
+40, _T("%s - TortoiseUDiff"), title
);
487 SetWindowTitle(std::wstring(pBuf
));
491 void CMainWindow::SetAStyle(int style
, COLORREF fore
, COLORREF back
, int size
, const char *face
)
493 SendEditor(SCI_STYLESETFORE
, style
, fore
);
494 SendEditor(SCI_STYLESETBACK
, style
, back
);
496 SendEditor(SCI_STYLESETSIZE
, style
, size
);
498 SendEditor(SCI_STYLESETFONT
, style
, reinterpret_cast<LPARAM
>(face
));
501 bool CMainWindow::IsUTF8(LPVOID pBuffer
, size_t cb
)
505 UINT16
* pVal
= (UINT16
*)pBuffer
;
506 UINT8
* pVal2
= (UINT8
*)(pVal
+1);
507 // scan the whole buffer for a 0x0000 sequence
508 // if found, we assume a binary file
509 for (size_t i
=0; i
<(cb
-2); i
=i
+2)
511 if (0x0000 == *pVal
++)
514 pVal
= (UINT16
*)pBuffer
;
524 // check for illegal UTF8 chars
525 pVal2
= (UINT8
*)pBuffer
;
526 for (size_t i
=0; i
<cb
; ++i
)
528 if ((*pVal2
== 0xC0)||(*pVal2
== 0xC1)||(*pVal2
>= 0xF5))
532 pVal2
= (UINT8
*)pBuffer
;
534 for (size_t i
=0; i
<(cb
-3); ++i
)
536 if ((*pVal2
& 0xE0)==0xC0)
539 if ((*pVal2
& 0xC0)!=0x80)
543 if ((*pVal2
& 0xF0)==0xE0)
546 if ((*pVal2
& 0xC0)!=0x80)
549 if ((*pVal2
& 0xC0)!=0x80)
553 if ((*pVal2
& 0xF8)==0xF0)
556 if ((*pVal2
& 0xC0)!=0x80)
559 if ((*pVal2
& 0xC0)!=0x80)
562 if ((*pVal2
& 0xC0)!=0x80)