1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2018 - 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 "TortoiseUDiff.h"
22 #include "MainWindow.h"
23 #include "UnicodeUtils.h"
24 #include "StringUtils.h"
25 #include "TaskbarUUID.h"
26 #include "CreateProcessHelper.h"
27 #include "UDiffColors.h"
30 #include "LoadIconEx.h"
32 const UINT TaskBarButtonCreated
= RegisterWindowMessage(L
"TaskbarButtonCreated");
34 CMainWindow::CMainWindow(HINSTANCE hInst
, const WNDCLASSEX
* wcx
/* = nullptr*/)
36 , m_bShowFindBar(false)
42 SetWindowTitle(L
"TortoiseGitUDiff");
45 CMainWindow::~CMainWindow(void)
49 bool CMainWindow::RegisterAndCreateWindow()
53 // Fill in the window class structure with default parameters
54 wcx
.cbSize
= sizeof(WNDCLASSEX
);
55 wcx
.style
= CS_HREDRAW
| CS_VREDRAW
;
56 wcx
.lpfnWndProc
= CWindow::stWinMsgHandler
;
59 wcx
.hInstance
= hResource
;
60 wcx
.hCursor
= nullptr;
61 ResString
clsname(hResource
, IDS_APP_TITLE
);
62 wcx
.lpszClassName
= clsname
;
63 wcx
.hIcon
= LoadIconEx(hResource
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
), GetSystemMetrics(SM_CXICON
), GetSystemMetrics(SM_CYICON
));
64 wcx
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+1);
65 wcx
.lpszMenuName
= MAKEINTRESOURCE(IDC_TORTOISEUDIFF
);
66 wcx
.hIconSm
= LoadIconEx(wcx
.hInstance
, MAKEINTRESOURCE(IDI_TORTOISEUDIFF
));
67 if (RegisterWindow(&wcx
))
69 if (Create(WS_CAPTION
| WS_MAXIMIZEBOX
| WS_MINIMIZEBOX
| WS_SIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
, nullptr))
71 m_FindBar
.SetParent(*this);
72 m_FindBar
.Create(::hResource
, IDD_FINDBAR
, *this);
80 LRESULT CALLBACK
CMainWindow::WinMsgHandler(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
82 if (uMsg
== TaskBarButtonCreated
)
84 SetUUIDOverlayIcon(hwnd
);
96 return DoCommand(LOWORD(wParam
));
101 if (GET_KEYSTATE_WPARAM(wParam
) == MK_SHIFT
)
104 SendEditor(SCI_LINESCROLL
, -GET_WHEEL_DELTA_WPARAM(wParam
)/40, 0);
107 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
113 GetClientRect(*this, &rect
);
116 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
118 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
- int(30 * CDPIAware::Instance().ScaleFactorY()),
120 ::SetWindowPos(m_FindBar
, HWND_TOP
,
121 rect
.left
, rect
.bottom
- int(30 * CDPIAware::Instance().ScaleFactorY()),
122 rect
.right
- rect
.left
, int(30 * CDPIAware::Instance().ScaleFactorY()),
127 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
129 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
131 ::ShowWindow(m_FindBar
, SW_HIDE
);
135 case WM_GETMINMAXINFO
:
137 MINMAXINFO
* mmi
= (MINMAXINFO
*)lParam
;
138 mmi
->ptMinTrackSize
.x
= 100;
139 mmi
->ptMinTrackSize
.y
= 100;
147 ::DestroyWindow(m_hwnd
);
150 SetFocus(m_hWndEdit
);
152 case WM_SYSCOLORCHANGE
:
155 case COMMITMONITOR_FINDMSGNEXT
:
157 SendEditor(SCI_CHARRIGHT
);
158 SendEditor(SCI_SEARCHANCHOR
);
159 m_bMatchCase
= !!wParam
;
160 m_findtext
= (LPCTSTR
)lParam
;
161 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
162 SendEditor(SCI_SCROLLCARET
);
165 case COMMITMONITOR_FINDMSGPREV
:
167 SendEditor(SCI_SEARCHANCHOR
);
168 m_bMatchCase
= !!wParam
;
169 m_findtext
= (LPCTSTR
)lParam
;
170 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
171 SendEditor(SCI_SCROLLCARET
);
174 case COMMITMONITOR_FINDEXIT
:
177 GetClientRect(*this, &rect
);
178 m_bShowFindBar
= false;
179 ::ShowWindow(m_FindBar
, SW_HIDE
);
180 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
182 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
186 case COMMITMONITOR_FINDRESET
:
187 SendEditor(SCI_SETSELECTIONSTART
, 0);
188 SendEditor(SCI_SETSELECTIONEND
, 0);
189 SendEditor(SCI_SEARCHANCHOR
);
192 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
198 LRESULT
CMainWindow::DoCommand(int id
)
203 loadOrSaveFile(true);
206 loadOrSaveFile(false);
209 loadOrSaveFile(false, m_filename
);
212 ::PostQuitMessage(0);
214 case IDM_SHOWFINDBAR
:
216 m_bShowFindBar
= true;
217 ::ShowWindow(m_FindBar
, SW_SHOW
);
219 GetClientRect(*this, &rect
);
220 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
222 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
- int(30 * CDPIAware::Instance().ScaleFactorY()),
224 ::SetWindowPos(m_FindBar
, HWND_TOP
,
225 rect
.left
, rect
.bottom
- int(30 * CDPIAware::Instance().ScaleFactorY()),
226 rect
.right
- rect
.left
, int(30 * CDPIAware::Instance().ScaleFactorY()),
228 ::SetFocus(m_FindBar
);
229 SendEditor(SCI_SETSELECTIONSTART
, 0);
230 SendEditor(SCI_SETSELECTIONEND
, 0);
231 SendEditor(SCI_SEARCHANCHOR
);
235 SendEditor(SCI_SEARCHANCHOR
);
236 SendEditor(SCI_SEARCHNEXT
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
237 SendEditor(SCI_SCROLLCARET
);
240 SendEditor(SCI_SEARCHANCHOR
);
241 SendEditor(SCI_SEARCHPREV
, m_bMatchCase
? SCFIND_MATCHCASE
: 0, (LPARAM
)CUnicodeUtils::StdGetUTF8(m_findtext
).c_str());
242 SendEditor(SCI_SCROLLCARET
);
245 if (IsWindowVisible(m_FindBar
))
248 GetClientRect(*this, &rect
);
249 m_bShowFindBar
= false;
250 ::ShowWindow(m_FindBar
, SW_HIDE
);
251 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
253 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
259 case ID_FILE_SETTINGS
:
261 tstring gitCmd
= L
" /command:settings /page:udiff";
265 case ID_FILE_APPLYPATCH
:
267 std::wstring command
= L
" /diff:\"";
268 command
+= m_filename
;
270 std::wstring tortoiseMergePath
= GetAppDirectory() + L
"TortoiseGitMerge.exe";
271 CCreateProcessHelper::CreateProcessDetached(tortoiseMergePath
.c_str(), command
.c_str());
274 case ID_FILE_PAGESETUP
:
276 TCHAR localeInfo
[3] = { 0 };
277 GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_IMEASURE
, localeInfo
, 3);
278 // Metric system. '1' is US System
279 int defaultMargin
= localeInfo
[0] == '0' ? 2540 : 1000;
281 PAGESETUPDLG pdlg
= {0};
282 pdlg
.lStructSize
= sizeof(PAGESETUPDLG
);
283 pdlg
.hwndOwner
= *this;
284 pdlg
.hInstance
= nullptr;
285 pdlg
.Flags
= PSD_DEFAULTMINMARGINS
|PSD_MARGINS
|PSD_DISABLEPAPER
|PSD_DISABLEORIENTATION
;
286 if (localeInfo
[0] == '0')
287 pdlg
.Flags
|= PSD_INHUNDREDTHSOFMILLIMETERS
;
289 CRegStdDWORD m_regMargLeft
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginleft", defaultMargin
);
290 CRegStdDWORD m_regMargTop
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmargintop", defaultMargin
);
291 CRegStdDWORD m_regMargRight
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginright", defaultMargin
);
292 CRegStdDWORD m_regMargBottom
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginbottom", defaultMargin
);
294 pdlg
.rtMargin
.left
= (long)(DWORD
)m_regMargLeft
;
295 pdlg
.rtMargin
.top
= (long)(DWORD
)m_regMargTop
;
296 pdlg
.rtMargin
.right
= (long)(DWORD
)m_regMargRight
;
297 pdlg
.rtMargin
.bottom
= (long)(DWORD
)m_regMargBottom
;
299 if (!PageSetupDlg(&pdlg
))
302 m_regMargLeft
= pdlg
.rtMargin
.left
;
303 m_regMargTop
= pdlg
.rtMargin
.top
;
304 m_regMargRight
= pdlg
.rtMargin
.right
;
305 m_regMargBottom
= pdlg
.rtMargin
.bottom
;
310 PRINTDLGEX pdlg
= {0};
311 pdlg
.lStructSize
= sizeof(PRINTDLGEX
);
312 pdlg
.hwndOwner
= *this;
313 pdlg
.hInstance
= nullptr;
314 pdlg
.Flags
= PD_USEDEVMODECOPIESANDCOLLATE
| PD_ALLPAGES
| PD_RETURNDC
| PD_NOCURRENTPAGE
| PD_NOPAGENUMS
;
316 pdlg
.nMaxPage
= 0xffffU
; // We do not know how many pages in the document
319 pdlg
.nStartPage
= START_PAGE_GENERAL
;
321 // See if a range has been selected
322 auto startPos
= (Sci_Position
)SendEditor(SCI_GETSELECTIONSTART
);
323 auto endPos
= (Sci_Position
)SendEditor(SCI_GETSELECTIONEND
);
325 if (startPos
== endPos
)
326 pdlg
.Flags
|= PD_NOSELECTION
;
328 pdlg
.Flags
|= PD_SELECTION
;
330 HRESULT hResult
= PrintDlgEx(&pdlg
);
331 if ((hResult
!= S_OK
) || (pdlg
.dwResultAction
!= PD_RESULT_PRINT
))
334 // reset all indicators
335 auto endpos
= (int)SendEditor(SCI_GETLENGTH
);
336 for (int i
= INDIC_CONTAINER
; i
<= INDIC_MAX
; ++i
)
338 SendEditor(SCI_SETINDICATORCURRENT
, i
);
339 SendEditor(SCI_INDICATORCLEARRANGE
, 0, endpos
);
341 // store and reset UI settings
342 auto viewws
= (int)SendEditor(SCI_GETVIEWWS
);
343 SendEditor(SCI_SETVIEWWS
, 0);
344 auto edgemode
= (int)SendEditor(SCI_GETEDGEMODE
);
345 SendEditor(SCI_SETEDGEMODE
, EDGE_NONE
);
346 SendEditor(SCI_SETWRAPVISUALFLAGS
, SC_WRAPVISUALFLAG_END
);
350 RECT rectMargins
, rectPhysMargins
;
354 // Get printer resolution
355 ptDpi
.x
= GetDeviceCaps(hdc
, LOGPIXELSX
); // dpi in X direction
356 ptDpi
.y
= GetDeviceCaps(hdc
, LOGPIXELSY
); // dpi in Y direction
358 // Start by getting the physical page size (in device units).
359 ptPage
.x
= GetDeviceCaps(hdc
, PHYSICALWIDTH
); // device units
360 ptPage
.y
= GetDeviceCaps(hdc
, PHYSICALHEIGHT
); // device units
362 // Get the dimensions of the unprintable
363 // part of the page (in device units).
364 rectPhysMargins
.left
= GetDeviceCaps(hdc
, PHYSICALOFFSETX
);
365 rectPhysMargins
.top
= GetDeviceCaps(hdc
, PHYSICALOFFSETY
);
367 // To get the right and lower unprintable area,
368 // we take the entire width and height of the paper and
369 // subtract everything else.
370 rectPhysMargins
.right
= ptPage
.x
// total paper width
371 - GetDeviceCaps(hdc
, HORZRES
) // printable width
372 - rectPhysMargins
.left
; // left unprintable margin
374 rectPhysMargins
.bottom
= ptPage
.y
// total paper height
375 - GetDeviceCaps(hdc
, VERTRES
) // printable height
376 - rectPhysMargins
.top
; // right unprintable margin
378 TCHAR localeInfo
[3] = { 0 };
379 GetLocaleInfo(LOCALE_USER_DEFAULT
, LOCALE_IMEASURE
, localeInfo
, 3);
380 // Metric system. '1' is US System
381 int defaultMargin
= localeInfo
[0] == '0' ? 2540 : 1000;
382 RECT pagesetupMargin
;
383 CRegStdDWORD m_regMargLeft
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginleft", defaultMargin
);
384 CRegStdDWORD m_regMargTop
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmargintop", defaultMargin
);
385 CRegStdDWORD m_regMargRight
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginright", defaultMargin
);
386 CRegStdDWORD m_regMargBottom
= CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffpagesetupmarginbottom", defaultMargin
);
388 pagesetupMargin
.left
= (long)(DWORD
)m_regMargLeft
;
389 pagesetupMargin
.top
= (long)(DWORD
)m_regMargTop
;
390 pagesetupMargin
.right
= (long)(DWORD
)m_regMargRight
;
391 pagesetupMargin
.bottom
= (long)(DWORD
)m_regMargBottom
;
393 if (pagesetupMargin
.left
!= 0 || pagesetupMargin
.right
!= 0 ||
394 pagesetupMargin
.top
!= 0 || pagesetupMargin
.bottom
!= 0)
398 // Convert the hundredths of millimeters (HiMetric) or
399 // thousandths of inches (HiEnglish) margin values
400 // from the Page Setup dialog to device units.
401 // (There are 2540 hundredths of a mm in an inch.)
402 if (localeInfo
[0] == '0')
404 // Metric system. '1' is US System
405 rectSetup
.left
= MulDiv (pagesetupMargin
.left
, ptDpi
.x
, 2540);
406 rectSetup
.top
= MulDiv (pagesetupMargin
.top
, ptDpi
.y
, 2540);
407 rectSetup
.right
= MulDiv(pagesetupMargin
.right
, ptDpi
.x
, 2540);
408 rectSetup
.bottom
= MulDiv(pagesetupMargin
.bottom
, ptDpi
.y
, 2540);
412 rectSetup
.left
= MulDiv(pagesetupMargin
.left
, ptDpi
.x
, 1000);
413 rectSetup
.top
= MulDiv(pagesetupMargin
.top
, ptDpi
.y
, 1000);
414 rectSetup
.right
= MulDiv(pagesetupMargin
.right
, ptDpi
.x
, 1000);
415 rectSetup
.bottom
= MulDiv(pagesetupMargin
.bottom
, ptDpi
.y
, 1000);
418 // Don't reduce margins below the minimum printable area
419 rectMargins
.left
= max(rectPhysMargins
.left
, rectSetup
.left
);
420 rectMargins
.top
= max(rectPhysMargins
.top
, rectSetup
.top
);
421 rectMargins
.right
= max(rectPhysMargins
.right
, rectSetup
.right
);
422 rectMargins
.bottom
= max(rectPhysMargins
.bottom
, rectSetup
.bottom
);
426 rectMargins
.left
= rectPhysMargins
.left
;
427 rectMargins
.top
= rectPhysMargins
.top
;
428 rectMargins
.right
= rectPhysMargins
.right
;
429 rectMargins
.bottom
= rectPhysMargins
.bottom
;
432 // rectMargins now contains the values used to shrink the printable
435 // Convert device coordinates into logical coordinates
436 DPtoLP(hdc
, (LPPOINT
) &rectMargins
, 2);
437 DPtoLP(hdc
, (LPPOINT
)&rectPhysMargins
, 2);
439 // Convert page size to logical units and we're done!
440 DPtoLP(hdc
, (LPPOINT
) &ptPage
, 1);
443 DOCINFO di
= {sizeof(DOCINFO
), 0, 0, 0, 0};
444 di
.lpszDocName
= m_filename
.c_str();
448 if (::StartDoc(hdc
, &di
) < 0)
454 size_t lengthDoc
= (int)SendEditor(SCI_GETLENGTH
);
455 size_t lengthDocMax
= lengthDoc
;
456 size_t lengthPrinted
= 0;
458 // Requested to print selection
459 if (pdlg
.Flags
& PD_SELECTION
)
461 if (startPos
> endPos
)
463 lengthPrinted
= endPos
;
464 lengthDoc
= startPos
;
468 lengthPrinted
= startPos
;
472 if (lengthDoc
> lengthDocMax
)
473 lengthDoc
= lengthDocMax
;
476 // We must subtract the physical margins from the printable area
477 Sci_RangeToFormat frPrint
;
479 frPrint
.hdcTarget
= hdc
;
480 frPrint
.rc
.left
= rectMargins
.left
- rectPhysMargins
.left
;
481 frPrint
.rc
.top
= rectMargins
.top
- rectPhysMargins
.top
;
482 frPrint
.rc
.right
= ptPage
.x
- rectMargins
.right
- rectPhysMargins
.left
;
483 frPrint
.rc
.bottom
= ptPage
.y
- rectMargins
.bottom
- rectPhysMargins
.top
;
484 frPrint
.rcPage
.left
= 0;
485 frPrint
.rcPage
.top
= 0;
486 frPrint
.rcPage
.right
= ptPage
.x
- rectPhysMargins
.left
- rectPhysMargins
.right
- 1;
487 frPrint
.rcPage
.bottom
= ptPage
.y
- rectPhysMargins
.top
- rectPhysMargins
.bottom
- 1;
490 while (lengthPrinted
< lengthDoc
)
494 frPrint
.chrg
.cpMin
= (long)lengthPrinted
;
495 frPrint
.chrg
.cpMax
= (long)lengthDoc
;
497 lengthPrinted
= SendEditor(SCI_FORMATRANGE
, true, reinterpret_cast<LPARAM
>(&frPrint
));
502 SendEditor(SCI_FORMATRANGE
, FALSE
, 0);
508 GlobalFree(pdlg
.hDevMode
);
510 GlobalFree(pdlg
.hDevNames
);
511 if (pdlg
.lpPageRanges
)
512 GlobalFree(pdlg
.lpPageRanges
);
515 SendEditor(SCI_SETVIEWWS
, viewws
);
516 SendEditor(SCI_SETEDGEMODE
, edgemode
);
517 SendEditor(SCI_SETWRAPVISUALFLAGS
, SC_WRAPVISUALFLAG_NONE
);
526 std::wstring
CMainWindow::GetAppDirectory()
530 DWORD bufferlen
= MAX_PATH
; // MAX_PATH is not the limit here!
533 bufferlen
+= MAX_PATH
; // MAX_PATH is not the limit here!
534 auto pBuf
= std::make_unique
<TCHAR
[]>(bufferlen
);
535 len
= GetModuleFileName(nullptr, pBuf
.get(), bufferlen
);
536 path
= std::wstring(pBuf
.get(), len
);
537 } while(len
== bufferlen
);
538 path
= path
.substr(0, path
.rfind('\\') + 1);
543 void CMainWindow::RunCommand(const std::wstring
& command
)
545 tstring tortoiseProcPath
= GetAppDirectory() + L
"TortoiseGitProc.exe";
546 CCreateProcessHelper::CreateProcessDetached(tortoiseProcPath
.c_str(), command
.c_str());
549 LRESULT
CMainWindow::SendEditor(UINT Msg
, WPARAM wParam
, LPARAM lParam
)
551 if (m_directFunction
)
553 return ((SciFnDirect
) m_directFunction
)(m_directPointer
, Msg
, wParam
, lParam
);
555 return ::SendMessage(m_hWndEdit
, Msg
, wParam
, lParam
);
558 bool CMainWindow::Initialize()
560 m_hWndEdit
= ::CreateWindow(
563 WS_CHILD
| WS_VSCROLL
| WS_HSCROLL
| WS_CLIPCHILDREN
,
564 CW_USEDEFAULT
, CW_USEDEFAULT
,
565 CW_USEDEFAULT
, CW_USEDEFAULT
,
574 GetClientRect(*this, &rect
);
575 ::SetWindowPos(m_hWndEdit
, HWND_TOP
,
577 rect
.right
-rect
.left
, rect
.bottom
-rect
.top
,
580 m_directFunction
= SendMessage(m_hWndEdit
, SCI_GETDIRECTFUNCTION
, 0, 0);
581 m_directPointer
= SendMessage(m_hWndEdit
, SCI_GETDIRECTPOINTER
, 0, 0);
583 // Set up the global default style. These attributes are used wherever no explicit choices are made.
584 SetAStyle(STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
), ::GetSysColor(COLOR_WINDOW
),
585 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffFontSize", 10),
586 CUnicodeUtils::StdGetUTF8(CRegStdString(L
"Software\\TortoiseGit\\UDiffFontName", L
"Consolas")).c_str());
587 SendEditor(SCI_SETTABWIDTH
, CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffTabSize", 4));
588 SendEditor(SCI_SETREADONLY
, TRUE
);
589 LRESULT pix
= SendEditor(SCI_TEXTWIDTH
, STYLE_LINENUMBER
, (LPARAM
)"_99999");
590 SendEditor(SCI_SETMARGINWIDTHN
, 0, pix
);
591 SendEditor(SCI_SETMARGINWIDTHN
, 1);
592 SendEditor(SCI_SETMARGINWIDTHN
, 2);
593 //Set the default windows colors for edit controls
595 if (CRegStdDWORD(L
"Software\\TortoiseGit\\ScintillaDirect2D", FALSE
) != FALSE
)
597 SendEditor(SCI_SETTECHNOLOGY
, SC_TECHNOLOGY_DIRECTWRITERETAIN
);
598 SendEditor(SCI_SETBUFFEREDDRAW
, 0);
600 SendEditor(SCI_SETVIEWWS
, 1);
601 SendEditor(SCI_SETWHITESPACESIZE
, 2);
602 SendEditor(SCI_STYLESETVISIBLE
, STYLE_CONTROLCHAR
, TRUE
);
607 bool CMainWindow::LoadFile(HANDLE hFile
)
610 char data
[4096] = { 0 };
613 BOOL bRet
= ReadFile(hFile
, data
, sizeof(data
), &dwRead
, nullptr);
614 bool bUTF8
= IsUTF8(data
, dwRead
);
615 while ((dwRead
> 0) && (bRet
))
617 SendEditor(SCI_ADDTEXT
, dwRead
,
618 reinterpret_cast<LPARAM
>(static_cast<char *>(data
)));
619 bRet
= ReadFile(hFile
, data
, sizeof(data
), &dwRead
, nullptr);
625 bool CMainWindow::LoadFile(LPCTSTR filename
)
629 _wfopen_s(&fp
, filename
, L
"rb");
634 char data
[4096] = { 0 };
635 size_t lenFile
= fread(data
, 1, sizeof(data
), fp
);
636 bool bUTF8
= IsUTF8(data
, lenFile
);
639 SendEditor(SCI_ADDTEXT
, lenFile
,
640 reinterpret_cast<LPARAM
>(static_cast<char *>(data
)));
641 lenFile
= fread(data
, 1, sizeof(data
), fp
);
645 m_filename
= filename
;
649 void CMainWindow::InitEditor()
651 SendEditor(SCI_SETREADONLY
, FALSE
);
652 SendEditor(SCI_CLEARALL
);
653 SendEditor(EM_EMPTYUNDOBUFFER
);
654 SendEditor(SCI_SETSAVEPOINT
);
655 SendEditor(SCI_CANCEL
);
656 SendEditor(SCI_SETUNDOCOLLECTION
, 0);
659 void CMainWindow::SetupWindow(bool bUTF8
)
661 SendEditor(SCI_SETCODEPAGE
, bUTF8
? SC_CP_UTF8
: GetACP());
663 SendEditor(SCI_SETUNDOCOLLECTION
, 1);
664 ::SetFocus(m_hWndEdit
);
665 SendEditor(EM_EMPTYUNDOBUFFER
);
666 SendEditor(SCI_SETSAVEPOINT
);
667 SendEditor(SCI_GOTOPOS
, 0);
671 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
674 void CMainWindow::SetupColors(bool recolorize
)
676 SendEditor(SCI_STYLESETFORE
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOWTEXT
));
677 SendEditor(SCI_STYLESETBACK
, STYLE_DEFAULT
, ::GetSysColor(COLOR_WINDOW
));
678 SendEditor(SCI_SETSELFORE
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHTTEXT
));
679 SendEditor(SCI_SETSELBACK
, TRUE
, ::GetSysColor(COLOR_HIGHLIGHT
));
680 SendEditor(SCI_SETCARETFORE
, ::GetSysColor(COLOR_WINDOWTEXT
));
682 SendEditor(SCI_SETWHITESPACEFORE
, true, ::GetSysColor(COLOR_3DSHADOW
));
684 SendEditor(SCI_CLEARDOCUMENTSTYLE
, 0, 0);
686 HIGHCONTRAST highContrast
= { 0 };
687 highContrast
.cbSize
= sizeof(HIGHCONTRAST
);
688 if (SystemParametersInfo(SPI_GETHIGHCONTRAST
, 0, &highContrast
, 0) == TRUE
&& (highContrast
.dwFlags
& HCF_HIGHCONTRASTON
))
690 SendEditor(SCI_SETLEXER
, SCLEX_NULL
);
694 //SetAStyle(SCE_DIFF_DEFAULT, RGB(0, 0, 0));
695 SetAStyle(SCE_DIFF_COMMAND
,
696 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForeCommandColor", UDIFF_COLORFORECOMMAND
),
697 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackCommandColor", UDIFF_COLORBACKCOMMAND
));
698 SetAStyle(SCE_DIFF_POSITION
,
699 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForePositionColor", UDIFF_COLORFOREPOSITION
),
700 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackPositionColor", UDIFF_COLORBACKPOSITION
));
701 SetAStyle(SCE_DIFF_HEADER
,
702 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForeHeaderColor", UDIFF_COLORFOREHEADER
),
703 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackHeaderColor", UDIFF_COLORBACKHEADER
));
704 SetAStyle(SCE_DIFF_COMMENT
,
705 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForeCommentColor", UDIFF_COLORFORECOMMENT
),
706 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackCommentColor", UDIFF_COLORBACKCOMMENT
));
707 SendEditor(SCI_STYLESETBOLD
, SCE_DIFF_COMMENT
, TRUE
);
709 SetAStyle(SCE_DIFF_ADDED
,
710 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForeAddedColor", UDIFF_COLORFOREADDED
),
711 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackAddedColor", UDIFF_COLORBACKADDED
));
712 SetAStyle(SCE_DIFF_DELETED
,
713 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffForeRemovedColor", UDIFF_COLORFOREREMOVED
),
714 CRegStdDWORD(L
"Software\\TortoiseGit\\UDiffBackRemovedColor", UDIFF_COLORBACKREMOVED
));
716 SendEditor(SCI_SETLEXER
, SCLEX_DIFF
);
717 SendEditor(SCI_SETKEYWORDS
, 0, (LPARAM
)"revision");
720 SendEditor(SCI_COLOURISE
, 0, -1);
723 bool CMainWindow::SaveFile(LPCTSTR filename
)
726 _wfopen_s(&fp
, filename
, L
"w+b");
730 auto len
= (int)SendEditor(SCI_GETTEXT
, 0, 0);
731 auto data
= std::make_unique
<char[]>(len
+ 1);
732 SendEditor(SCI_GETTEXT
, len
, reinterpret_cast<LPARAM
>(static_cast<char *>(data
.get())));
733 fwrite(data
.get(), sizeof(char), len
-1, fp
);
736 SendEditor(SCI_SETSAVEPOINT
);
737 ::ShowWindow(m_hWndEdit
, SW_SHOW
);
741 void CMainWindow::SetTitle(LPCTSTR title
)
743 size_t len
= wcslen(title
);
744 auto pBuf
= std::make_unique
<TCHAR
[]>(len
+ 40);
745 swprintf_s(pBuf
.get(), len
+ 40, L
"%s - TortoiseGitUDiff", title
);
746 SetWindowTitle(std::wstring(pBuf
.get()));
749 void CMainWindow::SetAStyle(int style
, COLORREF fore
, COLORREF back
, int size
, const char *face
)
751 SendEditor(SCI_STYLESETFORE
, style
, fore
);
752 SendEditor(SCI_STYLESETBACK
, style
, back
);
754 SendEditor(SCI_STYLESETSIZE
, style
, size
);
756 SendEditor(SCI_STYLESETFONT
, style
, reinterpret_cast<LPARAM
>(face
));
759 bool CMainWindow::IsUTF8(LPVOID pBuffer
, size_t cb
)
763 UINT16
* pVal16
= (UINT16
*)pBuffer
;
764 UINT8
* pVal8
= (UINT8
*)(pVal16
+1);
765 // scan the whole buffer for a 0x0000 sequence
766 // if found, we assume a binary file
767 for (size_t i
=0; i
<(cb
-2); i
=i
+2)
769 if (0x0000 == *pVal16
++)
772 pVal16
= (UINT16
*)pBuffer
;
773 if (*pVal16
== 0xFEFF)
777 if (*pVal16
== 0xBBEF)
782 // check for illegal UTF8 chars
783 pVal8
= (UINT8
*)pBuffer
;
784 for (size_t i
=0; i
<cb
; ++i
)
786 if ((*pVal8
== 0xC0)||(*pVal8
== 0xC1)||(*pVal8
>= 0xF5))
790 pVal8
= (UINT8
*)pBuffer
;
792 for (size_t i
=0; i
<(cb
-3); ++i
)
794 if ((*pVal8
& 0xE0)==0xC0)
797 if ((*pVal8
& 0xC0)!=0x80)
801 else if ((*pVal8
& 0xF0)==0xE0)
804 if ((*pVal8
& 0xC0)!=0x80)
807 if ((*pVal8
& 0xC0)!=0x80)
811 else if ((*pVal8
& 0xF8)==0xF0)
814 if ((*pVal8
& 0xC0)!=0x80)
817 if ((*pVal8
& 0xC0)!=0x80)
820 if ((*pVal8
& 0xC0)!=0x80)
824 else if (*pVal8
>= 0x80)
834 void CMainWindow::loadOrSaveFile(bool doLoad
, const std::wstring
& filename
/* = L"" */)
836 OPENFILENAME ofn
= {0}; // common dialog box structure
837 TCHAR szFile
[MAX_PATH
] = {0}; // buffer for file name
838 // Initialize OPENFILENAME
839 ofn
.lStructSize
= sizeof(OPENFILENAME
);
840 ofn
.hwndOwner
= *this;
841 ofn
.lpstrFile
= szFile
;
842 ofn
.nMaxFile
= sizeof(szFile
)/sizeof(TCHAR
);
843 TCHAR filter
[1024] = { 0 };
844 LoadString(::hResource
, IDS_PATCHFILEFILTER
, filter
, sizeof(filter
)/sizeof(TCHAR
));
845 CStringUtils::PipesToNulls(filter
);
846 ofn
.lpstrFilter
= filter
;
847 ofn
.nFilterIndex
= 1;
848 ofn
.lpstrFileTitle
= nullptr;
849 ofn
.lpstrDefExt
= L
"diff";
850 ofn
.nMaxFileTitle
= 0;
851 ofn
.lpstrInitialDir
= nullptr;
852 TCHAR fileTitle
[1024] = { 0 };
853 LoadString(::hResource
, doLoad
? IDS_OPENPATCH
: IDS_SAVEPATCH
, fileTitle
, sizeof(fileTitle
)/sizeof(TCHAR
));
854 ofn
.lpstrTitle
= fileTitle
;
855 ofn
.Flags
= OFN_ENABLESIZING
| OFN_EXPLORER
;
857 ofn
.Flags
|= OFN_PATHMUSTEXIST
| OFN_FILEMUSTEXIST
;
859 ofn
.Flags
|= OFN_OVERWRITEPROMPT
;
860 // Display the Open dialog box.
863 if (GetOpenFileName(&ofn
)==TRUE
)
865 LoadFile(ofn
.lpstrFile
);
870 if (filename
.empty())
872 if (GetSaveFileName(&ofn
)==TRUE
)
874 SaveFile(ofn
.lpstrFile
);
878 SaveFile(filename
.c_str());