Index: src/ch/UpdaterDlg.cpp =================================================================== diff -u -rd5c3edd0d167db9b5d47d04248820fda49499a5e -r3921d82d9605d98b2281f3f42d9f9c8385b89a3e --- src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision d5c3edd0d167db9b5d47d04248820fda49499a5e) +++ src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision 3921d82d9605d98b2281f3f42d9f9c8385b89a3e) @@ -6,97 +6,394 @@ #include "UpdaterDlg.h" #include "UpdateChecker.h" #include "../common/version.h" -#include +#include "StaticEx.h" +#include +#include +#include "WindowsVersion.h" +#include "resource.h" +#include "CfgProperties.h" +#include "../liblogger/TLogger.h" +#include "../libchengine/TConfigSerializers.h" #define UPDATER_TIMER 639 BEGIN_MESSAGE_MAP(CUpdaterDlg, ictranslate::CLanguageDialog) ON_BN_CLICKED(IDC_OPEN_WEBPAGE_BUTTON, &CUpdaterDlg::OnBnClickedOpenWebpageButton) + ON_CBN_SELCHANGE(IDC_UPDATESFREQ_COMBO, OnSelchangeFreqCombo) + ON_CBN_SELCHANGE(IDC_UPDATECHANNEL_COMBO, OnSelchangeChannelCombo) ON_WM_TIMER() END_MESSAGE_MAP() - // CUpdaterDlg dialog - IMPLEMENT_DYNAMIC(CUpdaterDlg, ictranslate::CLanguageDialog) -CUpdaterDlg::CUpdaterDlg(CWnd* pParent /*=NULL*/) -: ictranslate::CLanguageDialog(CUpdaterDlg::IDD, pParent) +CUpdaterDlg::CUpdaterDlg(bool bBackgroundMode, CWnd* pParent /*=nullptr*/) : + ictranslate::CLanguageDialog(IDD_UPDATER_DIALOG, pParent), + m_eLastState(CUpdateChecker::eResult_Undefined), + m_bBackgroundMode(bBackgroundMode), + m_spLog(logger::MakeLogger(GetLogFileData(), L"UpdaterDlg")) { + RegisterStaticExControl(AfxGetInstanceHandle()); } CUpdaterDlg::~CUpdaterDlg() { + m_ucChecker.Cleanup(); } void CUpdaterDlg::DoDataExchange(CDataExchange* pDX) { ictranslate::CLanguageDialog::DoDataExchange(pDX); - DDX_Control(pDX, IDC_INFO_STATIC, m_ctlText); + DDX_Control(pDX, IDC_ICON_STATIC, m_ctlImage); + DDX_Control(pDX, IDC_MAINUPDATEINFO_CUSTOM, m_ctlMainText); + DDX_Control(pDX, IDC_CHANGELOG_RICHEDIT, m_ctlRichEdit); + DDX_Control(pDX, IDC_UPDATESFREQ_COMBO, m_ctlUpdateFreq); + DDX_Control(pDX, IDC_UPDATECHANNEL_COMBO, m_ctlUpdateChannel); + } BOOL CUpdaterDlg::OnInitDialog() { ictranslate::CLanguageDialog::OnInitDialog(); - ictranslate::CFormat fmt(GetResManager()->LoadString(IDS_UPDATER_WAITING_STRING)); - fmt.SetParam(_t("%site"), _T(PRODUCT_SITE)); - m_ctlText.SetWindowText(fmt); + // set dialog icon + HICON hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); + SetIcon(hIcon, FALSE); - SetTimer(UPDATER_TIMER, 10, NULL); + InitRichEdit(); + InitUpdateFreqCombo(); + InitUpdateChannelCombo(); + // disable button initially + EnableOpenWebPageButton(false); + + if(!m_bBackgroundMode) + ShowWindow(SW_SHOW); + + // start the updater + CheckForUpdates(); + + // start a timer to display progress + SetTimer(UPDATER_TIMER, 50, nullptr); + return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } -void CUpdaterDlg::StartChecking() +void CUpdaterDlg::OnBnClickedOpenWebpageButton() { - m_ucChecker.CheckForUpdates(_T(PRODUCT_SITE), false); + CString strDownloadAddr = m_ucChecker.GetDownloadAddress(); + if(!strDownloadAddr.IsEmpty()) + { + CString str; + str.Format(_T("Opening a browser with address %s..."), (PCTSTR)strDownloadAddr); + LOG_DEBUG(m_spLog) << str; - ictranslate::CResourceManager* pResManager = GetResManager(); - BOOST_ASSERT(pResManager); - if(!pResManager) - return; + str.Format(_T("url.dll,FileProtocolHandler %s"), (PCTSTR)strDownloadAddr); + ULONG_PTR ulRes = (ULONG_PTR)ShellExecute(nullptr, _T("open"), _T("rundll32.exe"), str, nullptr, SW_SHOW); - ictranslate::CFormat fmt; + str.Format(_T("ShellExecute returned %I64u"), (unsigned long long)ulRes); + LOG_DEBUG(m_spLog) << str; - CString strFmt; - switch(m_ucChecker.GetResult()) + // close the dialog if succeeded; 32 is some arbitrary value from ms docs + if(ulRes > 32) + CUpdaterDlg::OnOK(); + } +} + +void CUpdaterDlg::OnTimer(UINT_PTR nIDEvent) +{ + if(nIDEvent == UPDATER_TIMER) { - case CUpdateChecker::eResult_Error: - strFmt = pResManager->LoadString(IDS_UPDATER_ERROR_STRING); + ictranslate::CResourceManager& rResManager = GetResManager(); + ictranslate::CFormat fmt; + CUpdateChecker::ECheckResult eResult = m_ucChecker.GetResult(); + CString strFmt; + EBkModeResult eBkMode = eRes_None; + + if(eResult != m_eLastState) + { + bool bEnableButton = false; + m_eLastState = eResult; + + switch(eResult) + { + case CUpdateChecker::eResult_Undefined: + TRACE(_T("CUpdateChecker::eResult_Undefined\n")); + eBkMode = eRes_Exit; + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_CHECKINGFORUPDATES)); + strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); + break; + + case CUpdateChecker::eResult_Pending: + TRACE(_T("CUpdateChecker::eResult_Pending\n")); + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_CHECKINGFORUPDATES)); + strFmt = rResManager.LoadString(IDS_UPDATER_WAITING_STRING); + break; + + case CUpdateChecker::eResult_Killed: + TRACE(_T("CUpdateChecker::eResult_Killed\n")); + eBkMode = eRes_Exit; + UpdateIcon(eIcon_Error); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ERROR_STRING)); + strFmt = rResManager.LoadString(IDS_UPDATER_KILLEDERROR); + break; + + case CUpdateChecker::eResult_Error: + TRACE(_T("CUpdateChecker::eResult_Error\n")); + eBkMode = eRes_Exit; + UpdateIcon(eIcon_Error); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ERROR_STRING)); + strFmt = m_ucChecker.GetLastError(); + break; + + case CUpdateChecker::eResult_VersionCurrent: + TRACE(_T("CUpdateChecker::eResult_VersionCurrent\n")); + eBkMode = eRes_Exit; + bEnableButton = false; + UpdateIcon(eIcon_Info); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_ALREADYNEWESTVERSION)); + strFmt = rResManager.LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); + break; + + case CUpdateChecker::eResult_RemoteVersionNewer: + TRACE(_T("CUpdateChecker::eResult_RemoteVersionNewer\n")); + eBkMode = eRes_Show; + bEnableButton = true; + UpdateIcon(eIcon_Warning); + UpdateMainText(rResManager.LoadString(IDS_UPDATER_NEWVERSIONEXISTS)); + strFmt = rResManager.LoadString(IDS_UPDATER_NEW_VERSION_STRING); + break; + + default: + _ASSERTE(FALSE); + return; + } + + fmt.SetFormat(strFmt); + fmt.SetParam(_T("%site"), _T(PRODUCT_SITE)); + fmt.SetParam(_T("%thisver"), _T(PRODUCT_VERSION)); + fmt.SetParam(L"%thisnumericver", PRODUCT_NUMERIC_VERSION); + fmt.SetParam(L"%numericver", m_ucChecker.GetNumericVersion()); + fmt.SetParam(_T("%officialver"), m_ucChecker.GetReadableVersion()); + fmt.SetParam(L"%reldate", m_ucChecker.GetReleaseDate()); + + CString strEntireText = fmt.ToString(); + CString strReleaseNotes = m_ucChecker.GetReleaseNotes(); + strReleaseNotes = strReleaseNotes.Trim(); + if(!strReleaseNotes.IsEmpty()) + { + fmt.SetFormat(L"\n\n%relnoteshdr\n%relnotestxt"); + fmt.SetParam(L"%relnoteshdr", rResManager.LoadString(IDS_UPDATER_RELEASENOTES)); + fmt.SetParam(L"%relnotestxt", m_ucChecker.GetReleaseNotes()); + strEntireText += fmt.ToString(); + } + + UpdateSecondaryText(strEntireText); + + // Update button state + EnableOpenWebPageButton(bEnableButton); + EnableUpdateRelatedControls(eResult > CUpdateChecker::eResult_Pending); + + // handle background mode + if(m_bBackgroundMode) + { + switch(eBkMode) + { + case eRes_None: + break; + case eRes_Exit: + KillTimer(UPDATER_TIMER); + EndDialog(IDCANCEL); + return; + case eRes_Show: + ShowWindow(SW_SHOW); + m_bBackgroundMode = false; // when we show this window for the first time the user is responsible for closing the dialog; + // otherwise window might close by itself when checking for updates from within the open window + break; + default: + BOOST_ASSERT(FALSE); + } + } + } + } + + CLanguageDialog::OnTimer(nIDEvent); +} + +void CUpdaterDlg::UpdateIcon(EUpdateType eType) +{ + HICON hIcon = nullptr; + switch(eType) + { + case eIcon_Warning: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_WARNING); break; - case CUpdateChecker::eResult_VersionNewer: - strFmt = pResManager->LoadString(IDS_UPDATER_NEW_VERSION_STRING); + + case eIcon_Error: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_ERROR); break; - case CUpdateChecker::eResult_VersionCurrent: - strFmt = pResManager->LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); + + case eIcon_Info: + default: + hIcon = AfxGetApp()->LoadStandardIcon(IDI_INFORMATION); break; - case CUpdateChecker::eResult_VersionOlder: - strFmt = pResManager->LoadString(IDS_UPDATER_OLD_VERSION_STRING); - break; } - fmt.SetFormat(strFmt); - fmt.SetParam(_t("%errdesc"), m_ucChecker.GetLastError()); - fmt.SetParam(_t("%thisver"), _T(PRODUCT_VERSION)); - fmt.SetParam(_t("%officialver"), m_ucChecker.GetReadableVersion()); + m_ctlImage.SetIcon(hIcon); +} - m_ctlText.SetWindowText(fmt); +void CUpdaterDlg::UpdateMainText(const wchar_t* pszText) +{ + m_ctlMainText.SetWindowText(pszText); } -void CUpdaterDlg::OnBnClickedOpenWebpageButton() +void CUpdaterDlg::UpdateSecondaryText(const wchar_t* pszText) { - ShellExecute(NULL, _T("open"), m_ucChecker.GetDownloadAddress(), NULL, NULL, SW_SHOW); + m_ctlRichEdit.SetWindowText(pszText); } -void CUpdaterDlg::OnTimer(UINT_PTR nIDEvent) +void CUpdaterDlg::InitRichEdit() { - if(nIDEvent == UPDATER_TIMER) + COLORREF crTextColor = GetSysColor(COLOR_BTNTEXT); + CHARFORMAT2 cf; + cf.cbSize = sizeof(CHARFORMAT2); + + m_ctlRichEdit.GetDefaultCharFormat(cf); + cf.dwMask |= CFM_COLOR; + cf.dwEffects &= ~CFE_AUTOCOLOR; + cf.crTextColor = crTextColor; + m_ctlRichEdit.SetDefaultCharFormat(cf); +} + +void CUpdaterDlg::InitUpdateChannelCombo() +{ + ictranslate::CResourceManager& rResManager = GetResManager(); + + std::wstring strText = rResManager.LoadString(IDS_CFGUPDATECHANNELITEMS_STRING); + std::vector vItems; + for(std::wstring strItem : boost::split(vItems, strText, boost::is_any_of(L"!"))) { - KillTimer(UPDATER_TIMER); - StartChecking(); + m_ctlUpdateChannel.AddString(strItem.c_str()); } - CLanguageDialog::OnTimer(nIDEvent); + UpdateVersionInfo::EVersionType eUpdateChannel = (UpdateVersionInfo::EVersionType)GetPropValue(GetConfig()); + if(eUpdateChannel < vItems.size()) + m_ctlUpdateChannel.SetCurSel(eUpdateChannel); + else + m_ctlUpdateChannel.SetCurSel(0); } + +void CUpdaterDlg::InitUpdateFreqCombo() +{ + ictranslate::CResourceManager& rResManager = GetResManager(); + + std::wstring strText = rResManager.LoadString(IDS_UPDATE_FREQUENCIES); + std::vector vItems; + for(std::wstring strItem : boost::split(vItems, strText, boost::is_any_of(L"!"))) + { + m_ctlUpdateFreq.AddString(strItem.c_str()); + } + + EUpdatesFrequency eFrequency = (EUpdatesFrequency)GetPropValue(GetConfig()); + if(eFrequency < vItems.size()) + m_ctlUpdateFreq.SetCurSel(eFrequency); + else + m_ctlUpdateFreq.SetCurSel(0); +} + +void CUpdaterDlg::OnSelchangeFreqCombo() +{ + int iCurSel = m_ctlUpdateFreq.GetCurSel(); + if(iCurSel == CB_ERR) + return; + + EUpdatesFrequency eFrequency = eFreq_Weekly; + if(iCurSel < EUpdatesFrequency::eFreq_Max) + eFrequency = (EUpdatesFrequency)iCurSel; + + SetPropValue(GetConfig(), eFrequency); + GetConfig().Write(); +} + +void CUpdaterDlg::OnSelchangeChannelCombo() +{ + int iCurSel = m_ctlUpdateChannel.GetCurSel(); + if(iCurSel == CB_ERR) + return; + + UpdateVersionInfo::EVersionType eVersionType = UpdateVersionInfo::eReleaseCandidate; + if(iCurSel < UpdateVersionInfo::EVersionType::eMax) + eVersionType = (UpdateVersionInfo::EVersionType)iCurSel; + + SetPropValue(GetConfig(), eVersionType); + GetConfig().Write(); + + CheckForUpdates(); +} + +void CUpdaterDlg::EnableOpenWebPageButton(bool bEnable) +{ + CWnd* pWnd = GetDlgItem(IDC_OPEN_WEBPAGE_BUTTON); + if(pWnd) + pWnd->EnableWindow(bEnable ? TRUE : FALSE); +} + +void CUpdaterDlg::CheckForUpdates() +{ + EnableUpdateRelatedControls(false); + m_eLastState = CUpdateChecker::eResult_Undefined; + + CString strSite; + + EUseSecureConnection eUseSecureConnection = (EUseSecureConnection)GetPropValue(GetConfig()); + switch(eUseSecureConnection) + { + case eSecure_No: + strSite = _T(UPDATE_CHECK_LINK_NONSECURE); + break; + + case eSecure_Yes: + strSite = _T(UPDATE_CHECK_LINK_SECURE); + break; + + case eSecure_Auto: + default: + { + bool bUseSecureConnection = WindowsVersion::IsWindows7Or2008R2OrGreater(); + if(bUseSecureConnection) + strSite = _T(UPDATE_CHECK_LINK_SECURE); + else + strSite = _T(UPDATE_CHECK_LINK_NONSECURE); + + break; + } + } + + CString strError; + try + { + m_ucChecker.AsyncCheckForUpdates(strSite, + GetPropValue(GetConfig()), + (UpdateVersionInfo::EVersionType)GetPropValue(GetConfig()), + m_bBackgroundMode, + false // disabled sending headers as it is causing issues with WinInet on WinXP and Win Vista + ); + } + catch (const std::exception& e) + { + strError = e.what(); + } + + if(!strError.IsEmpty()) + { + LOG_ERROR(m_spLog) << strError; + } +} + +void CUpdaterDlg::EnableUpdateRelatedControls(bool bEnable) +{ + m_ctlUpdateChannel.EnableWindow(bEnable ? TRUE : FALSE); +}