Make sounds for indicating a warning or error work
[TortoiseGit.git] / src / TortoiseProc / ProgressDlg.cpp
blobe1de8c6bab60abb230c0cbeb1baade753238459a
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - TortoiseGit
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.
19 // ProgressDlg.cpp : implementation file
22 #include "stdafx.h"
23 #include "TortoiseProc.h"
24 #include "ProgressDlg.h"
25 #include "Git.h"
26 #include "atlconv.h"
27 #include "UnicodeUtils.h"
28 #include "IconMenu.h"
29 #include "LoglistCommonResource.h"
30 #include "Tlhelp32.h"
31 #include "AppUtils.h"
32 #include "SmartHandle.h"
33 #include "../TGitCache/CacheInterface.h"
34 #include "LoglistUtils.h"
35 #include "SoundUtils.h"
37 // CProgressDlg dialog
39 IMPLEMENT_DYNAMIC(CProgressDlg, CResizableStandAloneDialog)
41 CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)
42 : CResizableStandAloneDialog(CProgressDlg::IDD, pParent), m_bShowCommand(true), m_bAutoCloseOnSuccess(false), m_bAbort(false), m_bDone(false), m_startTick(GetTickCount())
44 m_pThread = NULL;
45 m_PostCmdCallback = NULL;
46 m_caller = NULL;
47 m_bAltAbortPress=false;
48 m_bBufferAll=false;
49 m_GitStatus = (DWORD)-1;
52 CProgressDlg::~CProgressDlg()
54 if(m_pThread != NULL)
56 delete m_pThread;
60 void CProgressDlg::DoDataExchange(CDataExchange* pDX)
62 CDialog::DoDataExchange(pDX);
63 DDX_Control(pDX, IDC_CURRENT, this->m_CurrentWork);
64 DDX_Control(pDX, IDC_TITLE_ANIMATE, this->m_Animate);
65 DDX_Control(pDX, IDC_RUN_PROGRESS, this->m_Progress);
66 DDX_Control(pDX, IDC_LOG, this->m_Log);
67 DDX_Control(pDX, IDC_PROGRESS_BUTTON1, this->m_ctrlPostCmd);
70 BEGIN_MESSAGE_MAP(CProgressDlg, CResizableStandAloneDialog)
71 ON_WM_CLOSE()
72 ON_MESSAGE(MSG_PROGRESSDLG_UPDATE_UI, OnProgressUpdateUI)
73 ON_BN_CLICKED(IDOK, &CProgressDlg::OnBnClickedOk)
74 ON_BN_CLICKED(IDC_PROGRESS_BUTTON1,&CProgressDlg::OnBnClickedButton1)
75 ON_REGISTERED_MESSAGE(WM_TASKBARBTNCREATED, OnTaskbarBtnCreated)
76 END_MESSAGE_MAP()
78 BOOL CProgressDlg::OnInitDialog()
80 CResizableStandAloneDialog::OnInitDialog();
82 // Let the TaskbarButtonCreated message through the UIPI filter. If we don't
83 // do this, Explorer would be unable to send that message to our window if we
84 // were running elevated. It's OK to make the call all the time, since if we're
85 // not elevated, this is a no-op.
86 CHANGEFILTERSTRUCT cfs = { sizeof(CHANGEFILTERSTRUCT) };
87 typedef BOOL STDAPICALLTYPE ChangeWindowMessageFilterExDFN(HWND hWnd, UINT message, DWORD action, PCHANGEFILTERSTRUCT pChangeFilterStruct);
88 CAutoLibrary hUser = AtlLoadSystemLibraryUsingFullPath(_T("user32.dll"));
89 if (hUser)
91 ChangeWindowMessageFilterExDFN *pfnChangeWindowMessageFilterEx = (ChangeWindowMessageFilterExDFN*)GetProcAddress(hUser, "ChangeWindowMessageFilterEx");
92 if (pfnChangeWindowMessageFilterEx)
94 pfnChangeWindowMessageFilterEx(m_hWnd, WM_TASKBARBTNCREATED, MSGFLT_ALLOW, &cfs);
97 m_pTaskbarList.Release();
98 if (FAILED(m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList)))
99 m_pTaskbarList = nullptr;
101 AddAnchor(IDC_TITLE_ANIMATE, TOP_LEFT, TOP_RIGHT);
102 AddAnchor(IDC_RUN_PROGRESS, TOP_LEFT,TOP_RIGHT);
103 AddAnchor(IDC_LOG, TOP_LEFT,BOTTOM_RIGHT);
105 AddAnchor(IDOK,BOTTOM_RIGHT);
106 AddAnchor(IDCANCEL,BOTTOM_RIGHT);
107 AddAnchor(IDC_PROGRESS_BUTTON1,BOTTOM_LEFT);
108 AddAnchor(IDC_CURRENT,TOP_LEFT);
110 this->GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_HIDE);
111 m_Animate.Open(IDR_DOWNLOAD);
113 CFont m_logFont;
114 CAppUtils::CreateFontForLogs(m_logFont);
115 //GetDlgItem(IDC_CMD_LOG)->SetFont(&m_logFont);
116 m_Log.SetFont(&m_logFont);
118 CString InitialText;
119 if ( !m_PreText.IsEmpty() )
121 InitialText = m_PreText + _T("\r\n");
123 #if 0
124 if (m_bShowCommand && (!m_GitCmd.IsEmpty() ))
126 InitialText += m_GitCmd+_T("\r\n\r\n");
128 #endif
129 m_Log.SetWindowTextW(InitialText);
130 m_CurrentWork.SetWindowTextW(_T(""));
132 EnableSaveRestore(_T("ProgressDlg"));
134 m_pThread = AfxBeginThread(ProgressThreadEntry, this, THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
135 if (m_pThread==NULL)
137 // ReportError(CString(MAKEINTRESOURCE(IDS_ERR_THREADSTARTFAILED)));
139 else
141 m_pThread->m_bAutoDelete = FALSE;
142 m_pThread->ResumeThread();
145 if(!m_Title.IsEmpty())
146 this->SetWindowText(m_Title);
148 CString sWindowTitle;
149 GetWindowText(sWindowTitle);
150 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
152 // Make sure this dialog is shown in foreground (see issue #1536)
153 SetForegroundWindow();
155 return TRUE;
158 UINT CProgressDlg::ProgressThreadEntry(LPVOID pVoid)
160 return ((CProgressDlg*)pVoid)->ProgressThread();
163 //static function, Share with SyncDialog
164 UINT CProgressDlg::RunCmdList(CWnd *pWnd,std::vector<CString> &cmdlist,bool bShowCommand,CString *pfilename,bool *bAbort,CGitByteArray *pdata)
166 UINT ret=0;
168 PROCESS_INFORMATION pi;
169 HANDLE hRead = 0;
171 memset(&pi,0,sizeof(PROCESS_INFORMATION));
173 CBlockCacheForPath cacheBlock(g_Git.m_CurrentDir);
175 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_START,0);
177 if(pdata)
178 pdata->clear();
180 for (int i = 0; i < cmdlist.size(); ++i)
182 if(cmdlist[i].IsEmpty())
183 continue;
185 if (bShowCommand)
187 CStringA str = CUnicodeUtils::GetMulti(cmdlist[i].Trim() + _T("\r\n\r\n"), CP_UTF8);
188 for (int j = 0; j < str.GetLength(); ++j)
190 if(pdata)
192 pdata->m_critSec.Lock();
193 pdata->push_back(str[j]);
194 pdata->m_critSec.Unlock();
196 else
197 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,str[j]);
199 if(pdata)
200 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
203 g_Git.RunAsync(cmdlist[i].Trim(),&pi, &hRead, NULL, pfilename);
205 DWORD readnumber;
206 char lastByte = '\0';
207 char byte;
208 CString output;
209 while(ReadFile(hRead,&byte,1,&readnumber,NULL))
211 if(pdata)
213 if(byte == 0)
214 byte = '\n';
216 pdata->m_critSec.Lock();
217 if (byte == '\n' && lastByte != '\r')
218 pdata->push_back('\r');
219 pdata->push_back( byte);
220 lastByte = byte;
221 pdata->m_critSec.Unlock();
223 if(byte == '\r' || byte == '\n')
224 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,0);
226 else
227 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI,MSG_PROGRESSDLG_RUN,byte);
230 CloseHandle(pi.hThread);
232 WaitForSingleObject(pi.hProcess, INFINITE);
234 DWORD status=0;
235 if(!GetExitCodeProcess(pi.hProcess,&status) || *bAbort)
237 CloseHandle(pi.hProcess);
239 CloseHandle(hRead);
241 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_FAILED, status);
242 return TGIT_GIT_ERROR_GET_EXIT_CODE;
244 ret |= status;
247 CloseHandle(pi.hProcess);
249 CloseHandle(hRead);
251 pWnd->PostMessage(MSG_PROGRESSDLG_UPDATE_UI, MSG_PROGRESSDLG_END, ret);
253 return ret;
257 UINT CProgressDlg::ProgressThread()
260 m_GitCmdList.push_back(m_GitCmd);
262 CString *pfilename;
264 if(m_LogFile.IsEmpty())
265 pfilename=NULL;
266 else
267 pfilename=&m_LogFile;
269 m_startTick = GetTickCount();
270 m_GitStatus = RunCmdList(this,m_GitCmdList,m_bShowCommand,pfilename,&m_bAbort,&this->m_Databuf);;
271 return 0;
274 LRESULT CProgressDlg::OnProgressUpdateUI(WPARAM wParam,LPARAM lParam)
276 if(wParam == MSG_PROGRESSDLG_START)
278 m_BufStart = 0 ;
279 m_Animate.Play(0, INT_MAX, INT_MAX);
280 this->DialogEnableWindow(IDOK,FALSE);
281 if (m_pTaskbarList)
283 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
284 m_pTaskbarList->SetProgressValue(m_hWnd, 0, 100);
287 if(wParam == MSG_PROGRESSDLG_END || wParam == MSG_PROGRESSDLG_FAILED)
289 DWORD tickSpent = GetTickCount() - m_startTick;
290 CString strEndTime = CLoglistUtils::FormatDateAndTime(CTime::GetCurrentTime(), DATE_SHORTDATE, true, false);
292 if(m_bBufferAll)
294 m_Databuf.m_critSec.Lock();
295 m_Databuf.push_back(0);
296 m_Log.SetWindowText(Convert2UnionCode((char*)&m_Databuf[0]));
297 m_Databuf.m_critSec.Unlock();
298 m_Log.LineScroll(m_Log.GetLineCount() - m_Log.GetFirstVisibleLine() - 4);
300 m_BufStart=0;
301 m_Databuf.m_critSec.Lock();
302 this->m_Databuf.clear();
303 m_Databuf.m_critSec.Unlock();
305 m_bDone = true;
306 m_Animate.Stop();
307 m_Progress.SetPos(100);
308 this->DialogEnableWindow(IDOK,TRUE);
310 m_GitStatus = (DWORD)lParam;
312 // detect crashes of perl when performing git svn actions
313 if (m_GitStatus == 0 && m_GitCmd.Find(_T(" svn ")) > 1)
315 CString log;
316 m_Log.GetWindowText(log);
317 if (log.GetLength() > 18 && log.Mid(log.GetLength() - 18) == _T("perl.exe.stackdump"))
318 m_GitStatus = (DWORD)-1;
321 if(this->m_GitStatus)
323 if (m_pTaskbarList)
325 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_ERROR);
326 m_pTaskbarList->SetProgressValue(m_hWnd, 100, 100);
328 CString log;
329 log.Format(IDS_PROC_PROGRESS_GITUNCLEANEXIT, m_GitStatus);
330 CString err;
331 err.Format(_T("\r\n\r\n%s (%d ms @ %s)\r\n"), log, tickSpent, strEndTime);
332 InsertColorText(this->m_Log, err, RGB(255,0,0));
333 CSoundUtils::PlayTGitError();
335 else {
336 if (m_pTaskbarList)
337 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
338 CString temp;
339 temp.LoadString(IDS_SUCCESS);
340 CString log;
341 log.Format(_T("\r\n%s (%d ms @ %s)\r\n"), temp, tickSpent, strEndTime);
342 InsertColorText(this->m_Log, log, RGB(0,0,255));
343 this->DialogEnableWindow(IDCANCEL,FALSE);
346 if (wParam == MSG_PROGRESSDLG_END)
348 if (m_PostCmdCallback) // new handling method using callback
350 m_PostCmdCallback(this, m_caller, m_GitStatus);
352 if (m_PostCmdList.GetCount() > 0)
354 m_ctrlPostCmd.AddEntries(m_PostCmdList);
355 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
358 else if (m_GitStatus == 0) // default old behaviour on success
360 if (m_PostCmdList.GetCount() > 0)
362 m_ctrlPostCmd.AddEntries(m_PostCmdList);
363 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
366 else // simple method to show buttons on failed
368 if (m_PostFailCmdList.GetCount() > 0)
370 m_ctrlPostCmd.AddEntries(m_PostFailCmdList);
371 GetDlgItem(IDC_PROGRESS_BUTTON1)->ShowWindow(SW_SHOW);
376 if(wParam == MSG_PROGRESSDLG_END && m_GitStatus == 0)
378 if(m_bAutoCloseOnSuccess)
380 m_Log.GetWindowText(this->m_LogText);
381 EndDialog(IDOK);
386 if(!m_bBufferAll)
388 if(lParam == 0)
390 m_Databuf.m_critSec.Lock();
391 for (int i = this->m_BufStart; i < this->m_Databuf.size(); ++i)
393 char c = this->m_Databuf[m_BufStart];
394 ++m_BufStart;
395 m_Databuf.m_critSec.Unlock();
396 ParserCmdOutput(c);
398 m_Databuf.m_critSec.Lock();
401 if(m_BufStart>1000)
403 m_Databuf.erase(m_Databuf.begin(), m_Databuf.begin()+m_BufStart);
404 m_BufStart =0;
406 m_Databuf.m_critSec.Unlock();
409 else
410 ParserCmdOutput((char)lParam);
412 return 0;
415 //static function, Share with SyncDialog
416 int CProgressDlg::FindPercentage(CString &log)
418 int s1=log.Find(_T('%'));
419 if(s1<0)
420 return -1;
422 int s2=s1-1;
423 for(int i=s1-1;i>=0;i--)
425 if(log[i]>=_T('0') && log[i]<=_T('9'))
426 s2=i;
427 else
428 break;
430 return _ttol(log.Mid(s2,s1-s2));
433 void CProgressDlg::ParserCmdOutput(char ch)
435 ParserCmdOutput(this->m_Log,this->m_Progress,this->m_hWnd,this->m_pTaskbarList,this->m_LogTextA,ch,&this->m_CurrentWork);
437 void CProgressDlg::ClearESC(CString &str)
439 // see http://ascii-table.com/ansi-escape-sequences.php and http://tldp.org/HOWTO/Bash-Prompt-HOWTO/c327.html
440 str.Replace(_T("\033[K"), _T("")); // erase until end of line; no need to care for this, because we always clear the whole line
442 // drop colors
443 while (true)
445 int escapePosition = str.Find(_T('\033'));
446 if (escapePosition >= 0 && str.GetLength() >= escapePosition + 3)
448 if (str.Mid(escapePosition, 2) == _T("\033["))
450 int colorEnd = str.Find(_T('m'), escapePosition + 2);
451 if (colorEnd > 0)
453 bool found = true;
454 for (int i = escapePosition + 2; i < colorEnd; ++i)
456 if (str[i] != _T(';') && (str[i] < _T('0') && str[i] > _T('9')))
458 found = false;
459 break;
462 if (found)
464 if (escapePosition > 0)
465 str = str.Left(escapePosition) + str.Mid(colorEnd + 1);
466 else
467 str = str.Mid(colorEnd);
468 continue;
473 break;
476 void CProgressDlg::ParserCmdOutput(CRichEditCtrl &log,CProgressCtrl &progressctrl,HWND m_hWnd,CComPtr<ITaskbarList3> m_pTaskbarList,CStringA &oneline, char ch, CWnd *CurrentWork)
478 //TRACE(_T("%c"),ch);
479 if( ch == ('\r') || ch == ('\n'))
481 CString str;
483 // TRACE(_T("End Char %s \r\n"),ch==_T('\r')?_T("lf"):_T(""));
484 // TRACE(_T("End Char %s \r\n"),ch==_T('\n')?_T("cr"):_T(""));
486 int lines = log.GetLineCount();
487 g_Git.StringAppend(&str, (BYTE*)oneline.GetBuffer(), CP_UTF8);
488 str.Trim();
489 // TRACE(_T("%s"), str);
491 ClearESC(str);
493 if(ch == ('\r'))
495 int start=log.LineIndex(lines-1);
496 log.SetSel(start, log.GetTextLength());
497 log.ReplaceSel(str);
499 else
501 int length = log.GetWindowTextLength();
502 log.SetSel(length, length);
503 if (length > 0)
504 log.ReplaceSel(_T("\r\n") + str);
505 else
506 log.ReplaceSel(str);
509 if (lines > 500) //limited log length
511 int end=log.LineIndex(1);
512 log.SetSel(0,end);
513 log.ReplaceSel(_T(""));
515 log.LineScroll(log.GetLineCount() - log.GetFirstVisibleLine() - 4);
517 int s1=oneline.ReverseFind(_T(':'));
518 int s2=oneline.Find(_T('%'));
519 if (s1 > 0 && s2 > 0)
521 if(CurrentWork)
522 CurrentWork->SetWindowTextW(str.Left(s1));
524 int pos=FindPercentage(str);
525 TRACE(_T("Pos %d\r\n"),pos);
526 if(pos>0)
528 progressctrl.SetPos(pos);
529 if (m_pTaskbarList)
531 m_pTaskbarList->SetProgressState(m_hWnd, TBPF_NORMAL);
532 m_pTaskbarList->SetProgressValue(m_hWnd, pos, 100);
537 oneline="";
540 else
542 oneline+=ch;
545 void CProgressDlg::RemoveLastLine(CString &str)
547 int start;
548 start=str.ReverseFind(_T('\n'));
549 if(start>0)
550 str=str.Left(start);
551 return;
553 // CProgressDlg message handlers
555 void CProgressDlg::OnBnClickedOk()
557 m_Log.GetWindowText(this->m_LogText);
558 OnOK();
561 void CProgressDlg::OnBnClickedButton1()
563 this->EndDialog((int)(IDC_PROGRESS_BUTTON1 + this->m_ctrlPostCmd.GetCurrentEntry()));
566 void CProgressDlg::OnClose()
568 DialogEnableWindow(IDCANCEL, TRUE);
569 __super::OnClose();
572 void CProgressDlg::OnCancel()
574 m_bAbort = true;
575 if(m_bDone)
577 CResizableStandAloneDialog::OnCancel();
578 return;
581 if( g_Git.m_CurrentGitPi.hProcess )
583 if(::GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))
585 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
587 else
589 GetLastError();
592 KillProcessTree(g_Git.m_CurrentGitPi.dwProcessId);
595 ::WaitForSingleObject(g_Git.m_CurrentGitPi.hProcess ,10000);
596 CResizableStandAloneDialog::OnCancel();
599 void CProgressDlg::KillProcessTree(DWORD dwProcessId, unsigned int depth)
601 // recursively kills a process tree
602 // This is not optimized, but works and isn't called very often ;)
604 if (!dwProcessId || depth > 20)
605 return;
607 PROCESSENTRY32 pe;
608 memset(&pe, 0, sizeof(PROCESSENTRY32));
609 pe.dwSize = sizeof(PROCESSENTRY32);
611 CAutoGeneralHandle hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
613 if (::Process32First(hSnap, &pe))
617 if (pe.th32ParentProcessID == dwProcessId)
618 KillProcessTree(pe.th32ProcessID, depth + 1);
619 } while (::Process32Next(hSnap, &pe));
621 HANDLE hProc = ::OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId);
622 if (hProc)
623 ::TerminateProcess(hProc, 1);
627 void CProgressDlg::InsertColorText(CRichEditCtrl &edit,CString text,COLORREF rgb)
629 CHARFORMAT old,cf;
630 edit.GetDefaultCharFormat(cf);
631 old=cf;
632 cf.dwMask|=CFM_COLOR;
633 cf.crTextColor=rgb;
634 cf.dwEffects|=CFE_BOLD;
635 cf.dwEffects &= ~CFE_AUTOCOLOR ;
636 edit.SetSel(edit.GetTextLength()-1,edit.GetTextLength());
637 edit.ReplaceSel(text);
638 edit.SetSel(edit.LineIndex(edit.GetLineCount()-2),edit.GetTextLength());
639 edit.SetSelectionCharFormat(cf);
640 edit.SetSel(edit.GetTextLength(),edit.GetTextLength());
641 edit.SetDefaultCharFormat(old);
642 edit.LineScroll(edit.GetLineCount() - edit.GetFirstVisibleLine() - 4);
645 CString CCommitProgressDlg::Convert2UnionCode(char *buff, int size)
647 CString str;
649 CString cmd, output;
650 int cp=CP_UTF8;
652 cmd=_T("git.exe config i18n.logOutputEncoding");
653 if (g_Git.Run(cmd, &output, NULL, CP_UTF8))
654 cp=CP_UTF8;
656 int start=0;
657 output=output.Tokenize(_T("\n"),start);
658 cp=CUnicodeUtils::GetCPCode(output);
660 start =0;
661 if(size == -1)
662 size = (int)strlen(buff);
664 for (int i = 0; i < size; ++i)
666 if(buff[i] == ']')
667 start = i;
668 if( start >0 && buff[i] =='\n' )
670 start =i;
671 break;
675 str.Empty();
676 g_Git.StringAppend(&str, (BYTE*)buff, cp, start);
677 g_Git.StringAppend(&str, (BYTE*)buff + start, CP_UTF8, size - start);
679 ClearESC(str);
681 return str;
684 LRESULT CProgressDlg::OnTaskbarBtnCreated(WPARAM /*wParam*/, LPARAM /*lParam*/)
686 m_pTaskbarList.Release();
687 m_pTaskbarList.CoCreateInstance(CLSID_TaskbarList);
688 SetUUIDOverlayIcon(m_hWnd);
689 return 0;
692 BOOL CProgressDlg::PreTranslateMessage(MSG* pMsg)
694 if (pMsg->message == WM_KEYDOWN)
696 if (pMsg->wParam == VK_ESCAPE)
698 // pressing the ESC key should close the dialog. But since we disabled the escape
699 // key (so the user doesn't get the idea that he could simply undo an e.g. update)
700 // this won't work.
701 // So if the user presses the ESC key, change it to VK_RETURN so the dialog gets
702 // the impression that the OK button was pressed.
703 if ((!GetDlgItem(IDCANCEL)->IsWindowEnabled())
704 &&(GetDlgItem(IDOK)->IsWindowEnabled())&&(GetDlgItem(IDOK)->IsWindowVisible()))
706 // since we convert ESC to RETURN, make sure the OK button has the focus.
707 GetDlgItem(IDOK)->SetFocus();
708 pMsg->wParam = VK_RETURN;
712 else if (pMsg->message == WM_CONTEXTMENU || pMsg->message == WM_RBUTTONDOWN)
714 CWnd * pWnd = (CWnd*) GetDlgItem(IDC_LOG);
715 if (pWnd == GetFocus())
717 CIconMenu popup;
718 if (popup.CreatePopupMenu())
720 popup.AppendMenuIcon(WM_COPY, IDS_SCIEDIT_COPY, IDI_COPYCLIP);
721 if (m_Log.GetSelText().IsEmpty())
722 popup.EnableMenuItem(WM_COPY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
723 popup.AppendMenu(MF_SEPARATOR);
724 popup.AppendMenuIcon(EM_SETSEL, IDS_SCIEDIT_SELECTALL);
725 int cmd = popup.TrackPopupMenu(TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NONOTIFY, pMsg->pt.x, pMsg->pt.y, this);
726 switch (cmd)
728 case 0: // no command selected
729 break;
730 case EM_SETSEL:
731 case WM_COPY:
732 ::SendMessage(GetDlgItem(IDC_LOG)->GetSafeHwnd(), cmd, 0, -1);
733 break;
735 return TRUE;
739 return __super::PreTranslateMessage(pMsg);