1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2013 - TortoiseGit
4 // Copyright (C) 2003-2014 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "MainWindow.h"
22 #include "UnicodeUtils.h"
23 #include "StringUtils.h"
24 #include "TaskbarUUID.h"
25 #include "CreateProcessHelper.h"
28 const UINT TaskBarButtonCreated
= RegisterWindowMessage(L
"TaskbarButtonCreated");
30 CMainWindow::CMainWindow(HINSTANCE hInst
, const WNDCLASSEX
* wcx
/* = NULL*/)
32 , m_bShowFindBar(false)
38 SetWindowTitle(_T("TortoiseGitUDiff"));
41 CMainWindow::~CMainWindow(void)
45 bool CMainWindow::RegisterAndCreateWindow()
49 // Fill in the window class structure with default parameters
50 wcx
.cbSize
= sizeof(WNDCLASSEX
);
51 wcx
.style
= CS_HREDRAW
| CS_VREDRAW
;
52 wcx
.lpfnWndProc
= CWindow::stWinMsgHandler
;
55 wcx
.hInstance
= hResource
;
57 ResString
clsname(hResource
, IDS_APP_TITLE
);
58 wcx
.lpszClassName
= clsname
;
59 wcx
.hIcon
= LoadIcon(hResource
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
));
60 wcx
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+1);
61 wcx
.lpszMenuName
= MAKEINTRESOURCE(IDC_TORTOISEUDIFF
);
62 wcx
.hIconSm
= LoadIcon(wcx
.hInstance
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
));
63 if (RegisterWindow(&wcx
))
65 if (Create(WS_CAPTION
| WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
, NULL
))
67 m_FindBar
.SetParent(*this);
68 m_FindBar
.Create(hResource
, IDD_FINDBAR
, *this);
76 LRESULT CALLBACK
CMainWindow::WinMsgHandler(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
78 if (uMsg
== TaskBarButtonCreated
)
80 SetUUIDOverlayIcon(hwnd
);
92 return DoCommand(LOWORD(wParam
));
97 if (GET_KEYSTATE_WPARAM(wParam
) == MK_SHIFT
)
100 SendEditor(SCI_LINESCROLL
, -GET_WHEEL_DELTA_WPARAM(wParam
)/40, 0);
103 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
109 GetClientRect(*this, &rect
);
112 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
114 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
-30,
116 ::SetWindowPos(m_FindBar
, HWND_TOP
,
117 rect
.left
, rect
.bottom
-30,
118 rect
.right
-rect
.left
, 30,
123 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
125 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
127 ::ShowWindow(m_FindBar
, SW_HIDE
);
131 case WM_GETMINMAXINFO
:
133 MINMAXINFO
* mmi
= (MINMAXINFO
*)lParam
;
134 mmi
->ptMinTrackSize
.x
= 100;
135 mmi
->ptMinTrackSize
.y
= 100;
143 ::DestroyWindow(m_hwnd
);
146 SetFocus(m_hWndEdit
);
148 case COMMITMONITOR_FINDMSGNEXT
:
150 SendEditor(SCI_CHARRIGHT
);
151 SendEditor(SCI_SEARCHANCHOR
);
152 m_bMatchCase
= !!wParam
;
153 m_findtext
= (LPCTSTR
)lParam
;
154 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
155 SendEditor(SCI_SCROLLCARET
);
158 case COMMITMONITOR_FINDMSGPREV
:
160 SendEditor(SCI_SEARCHANCHOR
);
161 m_bMatchCase
= !!wParam
;
162 m_findtext
= (LPCTSTR
)lParam
;
163 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
164 SendEditor(SCI_SCROLLCARET
);
167 case COMMITMONITOR_FINDEXIT
:
170 GetClientRect(*this, &rect
);
171 m_bShowFindBar
= false;
172 ::ShowWindow(m_FindBar
, SW_HIDE
);
173 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
175 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
179 case COMMITMONITOR_FINDRESET
:
180 SendEditor(SCI_SETSELECTIONSTART
, 0);
181 SendEditor(SCI_SETSELECTIONEND
, 0);
182 SendEditor(SCI_SEARCHANCHOR
);
185 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
191 LRESULT
CMainWindow::DoCommand(int id
)
196 loadOrSaveFile(true);
199 loadOrSaveFile(false);
202 loadOrSaveFile(false, m_filename
);
205 ::PostQuitMessage(0);
207 case IDM_SHOWFINDBAR
:
209 m_bShowFindBar
= true;
210 ::ShowWindow(m_FindBar
, SW_SHOW
);
212 GetClientRect(*this, &rect
);
213 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
215 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
-30,
217 ::SetWindowPos(m_FindBar
, HWND_TOP
,
218 rect
.left
, rect
.bottom
-30,
219 rect
.right
-rect
.left
, 30,
221 ::SetFocus(m_FindBar
);
222 SendEditor(SCI_SETSELECTIONSTART
, 0);
223 SendEditor(SCI_SETSELECTIONEND
, 0);
224 SendEditor(SCI_SEARCHANCHOR
);
228 SendEditor(SCI_SEARCHANCHOR
);
229 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
230 SendEditor(SCI_SCROLLCARET
);
233 SendEditor(SCI_SEARCHANCHOR
);
234 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
235 SendEditor(SCI_SCROLLCARET
);
238 if (IsWindowVisible(m_FindBar
))
241 GetClientRect(*this, &rect
);
242 m_bShowFindBar
= false;
243 ::ShowWindow(m_FindBar
, SW_HIDE
);
244 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
246 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
252 case ID_FILE_SETTINGS
:
254 tstring gitCmd
= _T(" /command:settings /page:blame");
258 case ID_FILE_APPLYPATCH
:
260 std::wstring command
= L
" /diff:\"";
261 command
+= m_filename
;
263 std::wstring tortoiseMergePath
= GetAppDirectory() + _T("TortoiseGitMerge.exe");
264 CCreateProcessHelper::CreateProcessDetached(tortoiseMergePath
.c_str(), const_cast<TCHAR
*>(command
.c_str()));
267 case ID_FILE_PAGESETUP
:
269 TCHAR localeInfo
[3] = { 0 };
270 GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_IMEASURE
, localeInfo
, 3);
271 // Metric system. '1' is US System
272 int defaultMargin
= localeInfo
[0] == '0' ? 2540 : 1000;
274 PAGESETUPDLG pdlg
= {0};
275 pdlg
.lStructSize
= sizeof(PAGESETUPDLG
);
276 pdlg
.hwndOwner
= *this;
277 pdlg
.hInstance
= NULL
;
278 pdlg
.Flags
= PSD_DEFAULTMINMARGINS
|PSD_MARGINS
|PSD_DISABLEPAPER
|PSD_DISABLEORIENTATION
;
279 if (localeInfo
[0] == '0')
280 pdlg
.Flags
|= PSD_INHUNDREDTHSOFMILLIMETERS
;
282 CRegStdDWORD m_regMargLeft
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginleft", defaultMargin
);
283 CRegStdDWORD m_regMargTop
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmargintop", defaultMargin
);
284 CRegStdDWORD m_regMargRight
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginright", defaultMargin
);
285 CRegStdDWORD m_regMargBottom
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginbottom", defaultMargin
);
287 pdlg
.rtMargin
.left
= (long)(DWORD
)m_regMargLeft
;
288 pdlg
.rtMargin
.top
= (long)(DWORD
)m_regMargTop
;
289 pdlg
.rtMargin
.right
= (long)(DWORD
)m_regMargRight
;
290 pdlg
.rtMargin
.bottom
= (long)(DWORD
)m_regMargBottom
;
292 if (!PageSetupDlg(&pdlg
))
295 m_regMargLeft
= pdlg
.rtMargin
.left
;
296 m_regMargTop
= pdlg
.rtMargin
.top
;
297 m_regMargRight
= pdlg
.rtMargin
.right
;
298 m_regMargBottom
= pdlg
.rtMargin
.bottom
;
303 PRINTDLGEX pdlg
= {0};
304 pdlg
.lStructSize
= sizeof(PRINTDLGEX
);
305 pdlg
.hwndOwner
= *this;
306 pdlg
.hInstance
= NULL
;
307 pdlg
.Flags
= PD_USEDEVMODECOPIESANDCOLLATE
| PD_ALLPAGES
| PD_RETURNDC
| PD_NOCURRENTPAGE
| PD_NOPAGENUMS
;
309 pdlg
.nMaxPage
= 0xffffU
; // We do not know how many pages in the document
312 pdlg
.nStartPage
= START_PAGE_GENERAL
;
314 // See if a range has been selected
315 size_t startPos
= SendEditor(SCI_GETSELECTIONSTART
);
316 size_t endPos
= SendEditor(SCI_GETSELECTIONEND
);
318 if (startPos
== endPos
)
319 pdlg
.Flags
|= PD_NOSELECTION
;
321 pdlg
.Flags
|= PD_SELECTION
;
323 HRESULT hResult
= PrintDlgEx(&pdlg
);
324 if ((hResult
!= S_OK
) || (pdlg
.dwResultAction
!= PD_RESULT_PRINT
))
327 // reset all indicators
328 size_t endpos
= SendEditor(SCI_GETLENGTH
);
329 for (int i
= INDIC_CONTAINER
; i
<= INDIC_MAX
; ++i
)
331 SendEditor(SCI_SETINDICATORCURRENT
, i
);
332 SendEditor(SCI_INDICATORCLEARRANGE
, 0, endpos
);
334 // store and reset UI settings
335 int viewws
= (int)SendEditor(SCI_GETVIEWWS
);
336 SendEditor(SCI_SETVIEWWS
, 0);
337 int edgemode
= (int)SendEditor(SCI_GETEDGEMODE
);
338 SendEditor(SCI_SETEDGEMODE
, EDGE_NONE
);
339 SendEditor(SCI_SETWRAPVISUALFLAGS
, SC_WRAPVISUALFLAG_END
);
343 RECT rectMargins
, rectPhysMargins
;
347 // Get printer resolution
348 ptDpi
.x
= GetDeviceCaps(hdc
, LOGPIXELSX
); // dpi in X direction
349 ptDpi
.y
= GetDeviceCaps(hdc
, LOGPIXELSY
); // dpi in Y direction
351 // Start by getting the physical page size (in device units).
352 ptPage
.x
= GetDeviceCaps(hdc
, PHYSICALWIDTH
); // device units
353 ptPage
.y
= GetDeviceCaps(hdc
, PHYSICALHEIGHT
); // device units
355 // Get the dimensions of the unprintable
356 // part of the page (in device units).
357 rectPhysMargins
.left
= GetDeviceCaps(hdc
, PHYSICALOFFSETX
);
358 rectPhysMargins
.top
= GetDeviceCaps(hdc
, PHYSICALOFFSETY
);
360 // To get the right and lower unprintable area,
361 // we take the entire width and height of the paper and
362 // subtract everything else.
363 rectPhysMargins
.right
= ptPage
.x
// total paper width
364 - GetDeviceCaps(hdc
, HORZRES
) // printable width
365 - rectPhysMargins
.left
; // left unprintable margin
367 rectPhysMargins
.bottom
= ptPage
.y
// total paper height
368 - GetDeviceCaps(hdc
, VERTRES
) // printable height
369 - rectPhysMargins
.top
; // right unprintable margin
371 TCHAR localeInfo
[3] = { 0 };
372 GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_IMEASURE
, localeInfo
, 3);
373 // Metric system. '1' is US System
374 int defaultMargin
= localeInfo
[0] == '0' ? 2540 : 1000;
375 RECT pagesetupMargin
;
376 CRegStdDWORD m_regMargLeft
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginleft", defaultMargin
);
377 CRegStdDWORD m_regMargTop
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmargintop", defaultMargin
);
378 CRegStdDWORD m_regMargRight
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginright", defaultMargin
);
379 CRegStdDWORD m_regMargBottom
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginbottom", defaultMargin
);
381 pagesetupMargin
.left
= (long)(DWORD
)m_regMargLeft
;
382 pagesetupMargin
.top
= (long)(DWORD
)m_regMargTop
;
383 pagesetupMargin
.right
= (long)(DWORD
)m_regMargRight
;
384 pagesetupMargin
.bottom
= (long)(DWORD
)m_regMargBottom
;
386 if (pagesetupMargin
.left
!= 0 || pagesetupMargin
.right
!= 0 ||
387 pagesetupMargin
.top
!= 0 || pagesetupMargin
.bottom
!= 0)
391 // Convert the hundredths of millimeters (HiMetric) or
392 // thousandths of inches (HiEnglish) margin values
393 // from the Page Setup dialog to device units.
394 // (There are 2540 hundredths of a mm in an inch.)
395 if (localeInfo
[0] == '0')
397 // Metric system. '1' is US System
398 rectSetup
.left
= MulDiv (pagesetupMargin
.left
, ptDpi
.x
, 2540);
399 rectSetup
.top
= MulDiv (pagesetupMargin
.top
, ptDpi
.y
, 2540);
400 rectSetup
.right
= MulDiv(pagesetupMargin
.right
, ptDpi
.x
, 2540);
401 rectSetup
.bottom
= MulDiv(pagesetupMargin
.bottom
, ptDpi
.y
, 2540);
405 rectSetup
.left
= MulDiv(pagesetupMargin
.left
, ptDpi
.x
, 1000);
406 rectSetup
.top
= MulDiv(pagesetupMargin
.top
, ptDpi
.y
, 1000);
407 rectSetup
.right
= MulDiv(pagesetupMargin
.right
, ptDpi
.x
, 1000);
408 rectSetup
.bottom
= MulDiv(pagesetupMargin
.bottom
, ptDpi
.y
, 1000);
411 // Don't reduce margins below the minimum printable area
412 rectMargins
.left
= max(rectPhysMargins
.left
, rectSetup
.left
);
413 rectMargins
.top
= max(rectPhysMargins
.top
, rectSetup
.top
);
414 rectMargins
.right
= max(rectPhysMargins
.right
, rectSetup
.right
);
415 rectMargins
.bottom
= max(rectPhysMargins
.bottom
, rectSetup
.bottom
);
419 rectMargins
.left
= rectPhysMargins
.left
;
420 rectMargins
.top
= rectPhysMargins
.top
;
421 rectMargins
.right
= rectPhysMargins
.right
;
422 rectMargins
.bottom
= rectPhysMargins
.bottom
;
425 // rectMargins now contains the values used to shrink the printable
428 // Convert device coordinates into logical coordinates
429 DPtoLP(hdc
, (LPPOINT
) &rectMargins
, 2);
430 DPtoLP(hdc
, (LPPOINT
)&rectPhysMargins
, 2);
432 // Convert page size to logical units and we're done!
433 DPtoLP(hdc
, (LPPOINT
) &ptPage
, 1);
436 DOCINFO di
= {sizeof(DOCINFO
), 0, 0, 0, 0};
437 di
.lpszDocName
= m_filename
.c_str();
441 if (::StartDoc(hdc
, &di
) < 0)
447 size_t lengthDoc
= SendEditor(SCI_GETLENGTH
);
448 size_t lengthDocMax
= lengthDoc
;
449 size_t lengthPrinted
= 0;
451 // Requested to print selection
452 if (pdlg
.Flags
& PD_SELECTION
)
454 if (startPos
> endPos
)
456 lengthPrinted
= endPos
;
457 lengthDoc
= startPos
;
461 lengthPrinted
= startPos
;
465 if (lengthDoc
> lengthDocMax
)
466 lengthDoc
= lengthDocMax
;
469 // We must subtract the physical margins from the printable area
470 Sci_RangeToFormat frPrint
;
472 frPrint
.hdcTarget
= hdc
;
473 frPrint
.rc
.left
= rectMargins
.left
- rectPhysMargins
.left
;
474 frPrint
.rc
.top
= rectMargins
.top
- rectPhysMargins
.top
;
475 frPrint
.rc
.right
= ptPage
.x
- rectMargins
.right
- rectPhysMargins
.left
;
476 frPrint
.rc
.bottom
= ptPage
.y
- rectMargins
.bottom
- rectPhysMargins
.top
;
477 frPrint
.rcPage
.left
= 0;
478 frPrint
.rcPage
.top
= 0;
479 frPrint
.rcPage
.right
= ptPage
.x
- rectPhysMargins
.left
- rectPhysMargins
.right
- 1;
480 frPrint
.rcPage
.bottom
= ptPage
.y
- rectPhysMargins
.top
- rectPhysMargins
.bottom
- 1;
483 while (lengthPrinted
< lengthDoc
)
487 frPrint
.chrg
.cpMin
= (long)lengthPrinted
;
488 frPrint
.chrg
.cpMax
= (long)lengthDoc
;
490 lengthPrinted
= SendEditor(SCI_FORMATRANGE
, true, reinterpret_cast<LPARAM
>(&frPrint
));
495 SendEditor(SCI_FORMATRANGE
, FALSE
, 0);
500 if (pdlg
.hDevMode
!= NULL
)
501 GlobalFree(pdlg
.hDevMode
);
502 if (pdlg
.hDevNames
!= NULL
)
503 GlobalFree(pdlg
.hDevNames
);
504 if (pdlg
.lpPageRanges
!= NULL
)
505 GlobalFree(pdlg
.lpPageRanges
);
508 SendEditor(SCI_SETVIEWWS
, viewws
);
509 SendEditor(SCI_SETEDGEMODE
, edgemode
);
510 SendEditor(SCI_SETWRAPVISUALFLAGS
, SC_WRAPVISUALFLAG_NONE
);
519 std::wstring
CMainWindow::GetAppDirectory()
523 DWORD bufferlen
= MAX_PATH
; // MAX_PATH is not the limit here!
526 bufferlen
+= MAX_PATH
; // MAX_PATH is not the limit here!
527 std::unique_ptr
<TCHAR
[]> pBuf(new TCHAR
[bufferlen
]);
528 len
= GetModuleFileName(NULL
, pBuf
.get(), bufferlen
);
530 } while(len
== bufferlen
);
531 path
= path
.substr(0, path
.rfind('\\') + 1);
536 void CMainWindow::RunCommand(const std::wstring
& command
)
538 tstring tortoiseProcPath
= GetAppDirectory() + _T("TortoiseGitProc.exe");
539 CCreateProcessHelper::CreateProcessDetached(tortoiseProcPath
.c_str(), const_cast<TCHAR
*>(command
.c_str()));
542 LRESULT
CMainWindow::SendEditor(UINT Msg
, WPARAM wParam
, LPARAM lParam
)
544 if (m_directFunction
)
546 return ((SciFnDirect
) m_directFunction
)(m_directPointer
, Msg
, wParam
, lParam
);
548 return ::SendMessage(m_hWndEdit
, Msg
, wParam
, lParam
);
551 bool CMainWindow::Initialize()
553 m_hWndEdit
= ::CreateWindow(
556 WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
| WS_CLIPCHILDREN
,
557 CW_USEDEFAULT
, CW_USEDEFAULT
,
558 CW_USEDEFAULT
, CW_USEDEFAULT
,
563 if (m_hWndEdit
== NULL
)
567 GetClientRect(*this, &rect
);
568 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
570 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
573 m_directFunction
= SendMessage(m_hWndEdit
, SCI_GETDIRECTFUNCTION
, 0, 0);
574 m_directPointer
= SendMessage(m_hWndEdit
, SCI_GETDIRECTPOINTER
, 0, 0);
576 // Set up the global default style. These attributes are used wherever no explicit choices are made.
577 SetAStyle(STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
), ::GetSysColor(COLOR_WINDOW
),
578 // Reusing TortoiseBlame's setting which already have an user friendly
579 // pane in TortoiseSVN's Settings dialog, while there is no such
580 // pane for TortoiseUDiff.
581 CRegStdDWORD(_T("Software\\TortoiseGit\\BlameFontSize"), 10),
582 CUnicodeUtils::StdGetUTF8(CRegStdString(_T("Software\\TortoiseGit\\BlameFontName"), _T("Courier New"))).c_str());
583 SendEditor(SCI_SETTABWIDTH
, 4);
584 SendEditor(SCI_SETREADONLY
, TRUE
);
585 LRESULT pix
= SendEditor(SCI_TEXTWIDTH
, STYLE_LINENUMBER
, (LPARAM
)"_99999");
586 SendEditor(SCI_SETMARGINWIDTHN
, 0, pix
);
587 SendEditor(SCI_SETMARGINWIDTHN
, 1);
588 SendEditor(SCI_SETMARGINWIDTHN
, 2);
589 //Set the default windows colors for edit controls
590 SendEditor(SCI_STYLESETFORE
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
));
591 SendEditor(SCI_STYLESETBACK
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOW
));
592 SendEditor(SCI_SETSELFORE
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHTTEXT
));
593 SendEditor(SCI_SETSELBACK
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHT
));
594 SendEditor(SCI_SETCARETFORE
, ::GetSysColor(COLOR_WINDOWTEXT
));
595 CRegStdDWORD
used2d(L
"Software\\TortoiseGit\\ScintillaDirect2D", FALSE
);
596 if (SysInfo::Instance().IsWin7OrLater() && DWORD(used2d
))
598 SendEditor(SCI_SETTECHNOLOGY
, SC_TECHNOLOGY_DIRECTWRITE
);
599 SendEditor(SCI_SETBUFFEREDDRAW
, 0);
601 SendEditor(SCI_SETVIEWWS
, 1);
602 SendEditor(SCI_SETWHITESPACESIZE
, 2);
603 SendEditor(SCI_SETWHITESPACEFORE
, true, ::GetSysColor(COLOR_3DSHADOW
));
604 SendEditor(SCI_STYLESETVISIBLE
, STYLE_CONTROLCHAR
, TRUE
);
609 bool CMainWindow::LoadFile(HANDLE hFile
)
612 char data
[4096] = { 0 };
615 BOOL bRet
= ReadFile(hFile
, data
, sizeof(data
), &dwRead
, NULL
);
616 bool bUTF8
= IsUTF8(data
, dwRead
);
617 while ((dwRead
> 0) && (bRet
))
619 SendEditor(SCI_ADDTEXT
, dwRead
,
620 reinterpret_cast<LPARAM
>(static_cast<char *>(data
)));
621 bRet
= ReadFile(hFile
, data
, sizeof(data
), &dwRead
, NULL
);
627 bool CMainWindow::LoadFile(LPCTSTR filename
)
631 _tfopen_s(&fp
, filename
, _T("rb"));
636 char data
[4096] = { 0 };
637 size_t lenFile
= fread(data
, 1, sizeof(data
), fp
);
638 bool bUTF8
= IsUTF8(data
, lenFile
);
641 SendEditor(SCI_ADDTEXT
, lenFile
,
642 reinterpret_cast<LPARAM
>(static_cast<char *>(data
)));
643 lenFile
= fread(data
, 1, sizeof(data
), fp
);
647 m_filename
= filename
;
651 void CMainWindow::InitEditor()
653 SendEditor(SCI_SETREADONLY
, FALSE
);
654 SendEditor(SCI_CLEARALL
);
655 SendEditor(EM_EMPTYUNDOBUFFER
);
656 SendEditor(SCI_SETSAVEPOINT
);
657 SendEditor(SCI_CANCEL
);
658 SendEditor(SCI_SETUNDOCOLLECTION
, 0);
661 void CMainWindow::SetupWindow(bool bUTF8
)
663 SendEditor(SCI_SETCODEPAGE
, bUTF8
? SC_CP_UTF8
: GetACP());
665 SendEditor(SCI_SETUNDOCOLLECTION
, 1);
666 ::SetFocus(m_hWndEdit
);
667 SendEditor(EM_EMPTYUNDOBUFFER
);
668 SendEditor(SCI_SETSAVEPOINT
);
669 SendEditor(SCI_GOTOPOS
, 0);
671 SendEditor(SCI_CLEARDOCUMENTSTYLE
, 0, 0);
672 SendEditor(SCI_SETSTYLEBITS
, 5, 0);
674 //SetAStyle(SCE_DIFF_DEFAULT, RGB(0, 0, 0));
675 SetAStyle(SCE_DIFF_COMMAND
, RGB(0x0A, 0x24, 0x36));
676 SetAStyle(SCE_DIFF_POSITION
, RGB(0xFF, 0, 0));
677 SetAStyle(SCE_DIFF_HEADER
, RGB(0x80, 0, 0), RGB(0xFF, 0xFF, 0x80));
678 SetAStyle(SCE_DIFF_COMMENT
, RGB(0, 0x80, 0));
679 SendEditor(SCI_STYLESETBOLD
, SCE_DIFF_COMMENT
, TRUE
);
680 SetAStyle(SCE_DIFF_DELETED
, ::GetSysColor(COLOR_WINDOWTEXT
), RGB(0xFF, 0x80, 0x80));
681 SetAStyle(SCE_DIFF_ADDED
, ::GetSysColor(COLOR_WINDOWTEXT
), RGB(0x80, 0xFF, 0x80));
683 SendEditor(SCI_SETLEXER
, SCLEX_DIFF
);
684 SendEditor(SCI_SETKEYWORDS
, 0, (LPARAM
)"revision");
685 SendEditor(SCI_COLOURISE
, 0, -1);
686 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
689 bool CMainWindow::SaveFile(LPCTSTR filename
)
692 _tfopen_s(&fp
, filename
, _T("w+b"));
696 LRESULT len
= SendEditor(SCI_GETTEXT
, 0, 0);
697 std::unique_ptr
<char[]> data (new char[len
+1]);
698 SendEditor(SCI_GETTEXT
, len
, reinterpret_cast<LPARAM
>(static_cast<char *>(data
.get())));
699 fwrite(data
.get(), sizeof(char), len
-1, fp
);
702 SendEditor(SCI_SETSAVEPOINT
);
703 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
707 void CMainWindow::SetTitle(LPCTSTR title
)
709 size_t len
= _tcslen(title
);
710 std::unique_ptr
<TCHAR
[]> pBuf(new TCHAR
[len
+ 40]);
711 _stprintf_s(pBuf
.get(), len
+ 40, _T("%s - TortoiseGitUDiff"), title
);
712 SetWindowTitle(std::wstring(pBuf
.get()));
715 void CMainWindow::SetAStyle(int style
, COLORREF fore
, COLORREF back
, int size
, const char *face
)
717 SendEditor(SCI_STYLESETFORE
, style
, fore
);
718 SendEditor(SCI_STYLESETBACK
, style
, back
);
720 SendEditor(SCI_STYLESETSIZE
, style
, size
);
722 SendEditor(SCI_STYLESETFONT
, style
, reinterpret_cast<LPARAM
>(face
));
725 bool CMainWindow::IsUTF8(LPVOID pBuffer
, size_t cb
)
729 UINT16
* pVal16
= (UINT16
*)pBuffer
;
730 UINT8
* pVal8
= (UINT8
*)(pVal16
+1);
731 // scan the whole buffer for a 0x0000 sequence
732 // if found, we assume a binary file
733 for (size_t i
=0; i
<(cb
-2); i
=i
+2)
735 if (0x0000 == *pVal16
++)
738 pVal16
= (UINT16
*)pBuffer
;
739 if (*pVal16
== 0xFEFF)
743 if (*pVal16
== 0xBBEF)
748 // check for illegal UTF8 chars
749 pVal8
= (UINT8
*)pBuffer
;
750 for (size_t i
=0; i
<cb
; ++i
)
752 if ((*pVal8
== 0xC0)||(*pVal8
== 0xC1)||(*pVal8
>= 0xF5))
756 pVal8
= (UINT8
*)pBuffer
;
758 for (size_t i
=0; i
<(cb
-3); ++i
)
760 if ((*pVal8
& 0xE0)==0xC0)
763 if ((*pVal8
& 0xC0)!=0x80)
767 else if ((*pVal8
& 0xF0)==0xE0)
770 if ((*pVal8
& 0xC0)!=0x80)
773 if ((*pVal8
& 0xC0)!=0x80)
777 else if ((*pVal8
& 0xF8)==0xF0)
780 if ((*pVal8
& 0xC0)!=0x80)
783 if ((*pVal8
& 0xC0)!=0x80)
786 if ((*pVal8
& 0xC0)!=0x80)
790 else if (*pVal8
>= 0x80)
800 void CMainWindow::loadOrSaveFile(bool doLoad
, const std::wstring
& filename
/* = L"" */)
802 OPENFILENAME ofn
= {0}; // common dialog box structure
803 TCHAR szFile
[MAX_PATH
] = {0}; // buffer for file name
804 // Initialize OPENFILENAME
805 ofn
.lStructSize
= sizeof(OPENFILENAME
);
806 ofn
.hwndOwner
= *this;
807 ofn
.lpstrFile
= szFile
;
808 ofn
.nMaxFile
= sizeof(szFile
)/sizeof(TCHAR
);
809 TCHAR filter
[1024] = { 0 };
810 LoadString(hResource
, IDS_PATCHFILEFILTER
, filter
, sizeof(filter
)/sizeof(TCHAR
));
811 CStringUtils::PipesToNulls(filter
);
812 ofn
.lpstrFilter
= filter
;
813 ofn
.nFilterIndex
= 1;
814 ofn
.lpstrFileTitle
= NULL
;
815 ofn
.nMaxFileTitle
= 0;
816 ofn
.lpstrInitialDir
= NULL
;
817 TCHAR fileTitle
[1024] = { 0 };
818 LoadString(hResource
, doLoad
? IDS_OPENPATCH
: IDS_SAVEPATCH
, fileTitle
, sizeof(fileTitle
)/sizeof(TCHAR
));
819 ofn
.lpstrTitle
= fileTitle
;
820 ofn
.Flags
= OFN_ENABLESIZING
| OFN_EXPLORER
;
822 ofn
.Flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
824 ofn
.Flags
|= OFN_OVERWRITEPROMPT
;
825 // Display the Open dialog box.
828 if (GetOpenFileName(&ofn
)==TRUE
)
830 LoadFile(ofn
.lpstrFile
);
835 if (filename
.empty())
837 if (GetSaveFileName(&ofn
)==TRUE
)
839 SaveFile(ofn
.lpstrFile
);
843 SaveFile(filename
.c_str());