Index: src/ch/CfgProperties.cpp =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/CfgProperties.cpp (.../CfgProperties.cpp) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/CfgProperties.cpp (.../CfgProperties.cpp) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -33,7 +33,7 @@ pManager->register_bool(_t("Program/Enabled clipboard monitoring"), false); pManager->register_signed_num(_t("Program/Monitor scan interval"), 1000, 0, llHour); pManager->register_bool(_t("Program/Reload after restart"), false); - pManager->register_bool(_t("Program/Check for updates at startup"), true); + pManager->register_unsigned_num(_t("Program/Check for updates frequency"), eFreq_Weekly, eFreq_Never, eFreq_Max - 1); pManager->register_bool(_t("Program/Updater checks for beta"), true); pManager->register_bool(_t("Program/Shutdown system after finished"), false); @@ -111,5 +111,8 @@ pManager->register_string(_t("Shortcuts/Shortcut"), _t(""), icpf::property::flag_array); pManager->register_string(_t("Recent paths/Path"), _t(""), icpf::property::flag_array); + // invisible options + pManager->register_unsigned_num(_t("Runtime state/Last checked for updates"), 0, 0, ULLONG_MAX); + return true; } Index: src/ch/CfgProperties.h =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/CfgProperties.h (.../CfgProperties.h) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/CfgProperties.h (.../CfgProperties.h) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -29,7 +29,7 @@ PP_PCLIPBOARDMONITORING = 0, PP_PMONITORSCANINTERVAL, PP_PRELOADAFTERRESTART, - PP_PCHECK_FOR_UPDATES_AT_STARTUP, + PP_PCHECK_FOR_UPDATES_FREQUENCY, PP_PUPDATE_CHECK_FOR_BETA, PP_PSHUTDOWNAFTREFINISHED, PP_PTIMEBEFORESHUTDOWN, @@ -104,9 +104,24 @@ PP_SNDFINISHEDSOUNDPATH, PP_SHORTCUTS, - PP_RECENTPATHS + PP_RECENTPATHS, + + // invisible options + PP_LAST_UPDATE_TIMESTAMP }; +enum EUpdatesFrequency +{ + eFreq_Never, + eFreq_EveryStartup, + eFreq_Daily, + eFreq_Weekly, + eFreq_OnceEvery2Weeks, + eFreq_Monthly, + eFreq_Quarterly, + eFreq_Max +}; + // register function bool RegisterProperties(icpf::config* pManager); Index: src/ch/MainWnd.cpp =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/MainWnd.cpp (.../MainWnd.cpp) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -177,12 +177,54 @@ // start clipboard monitoring CClipboardMonitor::StartMonitor(&m_tasks); - if(GetConfig().get_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP)) + EUpdatesFrequency eFrequency = (EUpdatesFrequency)GetConfig().get_unsigned_num(PP_PCHECK_FOR_UPDATES_FREQUENCY); + if(eFrequency != eFreq_Never) { - CUpdaterDlg* pDlg = new CUpdaterDlg(true); - pDlg->m_bAutoDelete = true; + unsigned long long ullMinInterval = 0; + switch(eFrequency) + { + case eFreq_Daily: + ullMinInterval = 1*24*60*60; + break; + case eFreq_Weekly: + ullMinInterval = 7*24*60*60; + break; + case eFreq_OnceEvery2Weeks: + ullMinInterval = 14*24*60*60; + break; + case eFreq_Monthly: + ullMinInterval = 30*24*60*60; // we don't really care if it is a day less or more + break; + case eFreq_Quarterly: + ullMinInterval = 90*24*60*60; + break; + case eFreq_EveryStartup: + default: + ullMinInterval = 0; + } - pDlg->Create(); + // get last check time stored in configuration + unsigned long long ullCurrentStamp = _time64(NULL); + unsigned long long ullTimestamp = GetConfig().get_unsigned_num(PP_LAST_UPDATE_TIMESTAMP); + + // perform checking for updates only when the minimal interval has passed + if(ullCurrentStamp - ullTimestamp >= ullMinInterval) + { + CUpdaterDlg* pDlg = new CUpdaterDlg(true); + pDlg->m_bAutoDelete = true; + + pDlg->Create(); + chcore::TCoreConfig& rConfig = GetConfig(); + try + { + rConfig.set_unsigned_num(PP_LAST_UPDATE_TIMESTAMP, _time64(NULL)); + rConfig.write(NULL); + } + catch(icpf::exception& /*e*/) + { + LOG_ERROR(_T("Storing last update check timestamp in configuration failed")); + } + } } // start saving timer Index: src/ch/OptionsDlg.cpp =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/OptionsDlg.cpp (.../OptionsDlg.cpp) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -236,7 +236,7 @@ PROP_BOOL(IDS_CLIPBOARDMONITORING_STRING, GetConfig().get_bool(PP_PCLIPBOARDMONITORING)); PROP_UINT(IDS_CLIPBOARDINTERVAL_STRING, GetConfig().get_signed_num(PP_PMONITORSCANINTERVAL)); PROP_BOOL(IDS_AUTORUNPROGRAM_STRING, GetConfig().get_bool(PP_PRELOADAFTERRESTART)); - PROP_BOOL(IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP, GetConfig().get_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP)); + PROP_COMBO(IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY, IDS_UPDATE_FREQUENCIES, GetConfig().get_unsigned_num(PP_PCHECK_FOR_UPDATES_FREQUENCY)); PROP_BOOL(IDS_CFG_UPDATE_CHECK_FOR_BETA, GetConfig().get_bool(PP_PUPDATE_CHECK_FOR_BETA)); PROP_BOOL(IDS_AUTOSHUTDOWN_STRING, GetConfig().get_bool(PP_PSHUTDOWNAFTREFINISHED)); PROP_UINT(IDS_SHUTDOWNTIME_STRING, GetConfig().get_signed_num(PP_PTIMEBEFORESHUTDOWN)); @@ -356,7 +356,7 @@ rConfig.set_bool(PP_PCLIPBOARDMONITORING, GetBoolProp(iPosition++)); rConfig.set_signed_num(PP_PMONITORSCANINTERVAL, GetUintProp(iPosition++)); rConfig.set_bool(PP_PRELOADAFTERRESTART, GetBoolProp(iPosition++)); - rConfig.set_bool(PP_PCHECK_FOR_UPDATES_AT_STARTUP, GetBoolProp(iPosition++)); + rConfig.set_unsigned_num(PP_PCHECK_FOR_UPDATES_FREQUENCY, GetIndexProp(iPosition++)); rConfig.set_bool(PP_PUPDATE_CHECK_FOR_BETA, GetBoolProp(iPosition++)); rConfig.set_bool(PP_PSHUTDOWNAFTREFINISHED, GetBoolProp(iPosition++)); rConfig.set_signed_num(PP_PTIMEBEFORESHUTDOWN, GetUintProp(iPosition++)); Index: src/ch/UpdaterDlg.cpp =================================================================== diff -u -N -rb82ebc5caf998dbfd61370968f0438d8fb74897a -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision b82ebc5caf998dbfd61370968f0438d8fb74897a) +++ src/ch/UpdaterDlg.cpp (.../UpdaterDlg.cpp) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -45,6 +45,11 @@ fmt.SetParam(_t("%site"), _T(PRODUCT_SITE)); m_ctlText.SetWindowText(fmt); + // disable button initially + CWnd* pWnd = GetDlgItem(IDC_OPEN_WEBPAGE_BUTTON); + if(pWnd) + pWnd->EnableWindow(FALSE); + if(!m_bBackgroundMode) ShowWindow(SW_SHOW); @@ -60,19 +65,23 @@ void CUpdaterDlg::OnBnClickedOpenWebpageButton() { - CString str; - str.Format(_T("Opening a browser with address %s..."), (PCTSTR)m_ucChecker.GetDownloadAddress()); - LOG_DEBUG(str); + CString strDownloadAddr = m_ucChecker.GetDownloadAddress(); + if(!strDownloadAddr.IsEmpty()) + { + CString str; + str.Format(_T("Opening a browser with address %s..."), (PCTSTR)strDownloadAddr); + LOG_DEBUG(str); - str.Format(_T("url.dll,FileProtocolHandler %s"), (PCTSTR)m_ucChecker.GetDownloadAddress()); - ulong_t ulRes = (ulong_t)ShellExecute(NULL, _T("open"), _T("rundll32.exe"), str, NULL, SW_SHOW); + str.Format(_T("url.dll,FileProtocolHandler %s"), (PCTSTR)strDownloadAddr); + ulong_t ulRes = (ulong_t)ShellExecute(NULL, _T("open"), _T("rundll32.exe"), str, NULL, SW_SHOW); - str.Format(_T("ShellExecute returned %lu"), ulRes); - LOG_DEBUG(str); + str.Format(_T("ShellExecute returned %lu"), ulRes); + LOG_DEBUG(str); - // close the dialog if succeeded; 32 is some arbitrary value from ms docs - if(ulRes > 32) - CUpdaterDlg::OnOK(); + // close the dialog if succeeded; 32 is some arbitrary value from ms docs + if(ulRes > 32) + CUpdaterDlg::OnOK(); + } } void CUpdaterDlg::OnTimer(UINT_PTR nIDEvent) @@ -84,6 +93,7 @@ CUpdateChecker::ECheckResult eResult = m_ucChecker.GetResult(); CString strFmt; EBkModeResult eBkMode = eRes_None; + bool bEnableButton = false; if(eResult != m_eLastState) { @@ -111,17 +121,20 @@ case CUpdateChecker::eResult_RemoteVersionOlder: TRACE(_T("CUpdateChecker::eResult_RemoteVersionOlder\n")); eBkMode = eRes_Exit; + bEnableButton = true; // eBkMode = eRes_Show; // for debugging purposes only strFmt = rResManager.LoadString(IDS_UPDATER_OLD_VERSION_STRING); break; case CUpdateChecker::eResult_VersionCurrent: TRACE(_T("CUpdateChecker::eResult_VersionCurrent\n")); eBkMode = eRes_Exit; + bEnableButton = true; strFmt = rResManager.LoadString(IDS_UPDATER_EQUAL_VERSION_STRING); break; case CUpdateChecker::eResult_RemoteVersionNewer: TRACE(_T("CUpdateChecker::eResult_RemoteVersionNewer\n")); eBkMode = eRes_Show; + bEnableButton = true; strFmt = rResManager.LoadString(IDS_UPDATER_NEW_VERSION_STRING); break; default: @@ -138,6 +151,11 @@ m_ctlText.SetWindowText(fmt); + // Update button state + CWnd* pWnd = GetDlgItem(IDC_OPEN_WEBPAGE_BUTTON); + if(pWnd) + pWnd->EnableWindow(bEnableButton); + m_eLastState = eResult; // handle background mode Index: src/ch/ch.rc =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/ch.rc (.../ch.rc) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/ch.rc (.../ch.rc) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -769,9 +769,10 @@ BEGIN IDS_CFGINTERCEPTCONTEXTMENU_STRING "Intercept standard Windows operations (experimental/not recommended)" - IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP - "Automatically check for program updates at startup" + IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY + "Check for program updates" IDS_CFG_UPDATE_CHECK_FOR_BETA "Check for updates - include beta versions" + IDS_UPDATE_FREQUENCIES "Never!Every startup!Daily!Weekly!Once every 2 weeks!Monthly!Quarterly" END STRINGTABLE Index: src/ch/resource.h =================================================================== diff -u -N -r2457755b4084e3d1c80a8e7c77c9f0996312941b -r07a3be49b0c7e5599eb89c2f9da9a9272cc1558a --- src/ch/resource.h (.../resource.h) (revision 2457755b4084e3d1c80a8e7c77c9f0996312941b) +++ src/ch/resource.h (.../resource.h) (revision 07a3be49b0c7e5599eb89c2f9da9a9272cc1558a) @@ -421,10 +421,11 @@ #define IDS_LANGSFOLDERCHOOSE_STRING 8094 #define IDS_ABOUT_LANGUAGE_STRING 8095 #define IDS_CFGINTERCEPTCONTEXTMENU_STRING 8096 -#define IDS_CFG_CHECK_FOR_UPDATES_AT_STARTUP 8097 +#define IDS_CFG_CHECK_FOR_UPDATES_FREQUENCY 8097 #define IDS_CFG_UPDATE_CHECK_FOR_BETA 8098 #define IDS_CFGLOGLEVEL 8099 #define IDS_CFGLOGLEVEL_VALUES 8100 +#define IDS_UPDATE_FREQUENCIES 8101 #define IDS_MENUCOPY_STRING 9000 #define IDS_MENUMOVE_STRING 9001 #define IDS_MENUCOPYMOVESPECIAL_STRING 9002