2010-01-23 19:44:49 +00:00
/**********************************************************************
Audacity : A Digital Audio Editor
TimerRecordDialog . cpp
Copyright 2006 - 2009 by Vaughan Johnson
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /**
\ class TimerRecordDialog
\ brief Dialog for Timer Record , i . e . , timed or long recording .
*/ /*******************************************************************/
2021-05-09 15:16:56 +00:00
2015-06-18 14:24:36 +00:00
# include "TimerRecordDialog.h"
2018-11-11 02:40:37 +00:00
2016-02-25 13:47:48 +00:00
# include "FileNames.h"
2010-01-23 19:44:49 +00:00
2019-03-23 18:28:37 +00:00
# include <wx/setup.h> // for wxUSE_* macros
2019-03-28 17:23:26 +00:00
# include <wx/wxcrtvararg.h>
2018-11-14 20:01:44 +00:00
# include <wx/button.h>
2018-11-16 16:02:39 +00:00
# include <wx/calctrl.h>
2018-11-11 22:30:55 +00:00
# include <wx/checkbox.h>
2018-11-14 16:07:06 +00:00
# include <wx/choice.h>
2010-01-23 19:44:49 +00:00
# include <wx/defs.h>
2016-11-22 18:16:03 +00:00
# include <wx/dir.h>
2018-11-16 15:26:39 +00:00
# include <wx/datectrl.h>
2010-01-23 19:44:49 +00:00
# include <wx/datetime.h>
# include <wx/intl.h>
# include <wx/sizer.h>
# include <wx/string.h>
# include <wx/timer.h>
# include <wx/dynlib.h> //<! For windows.h
2015-06-18 14:24:36 +00:00
# include "ShuttleGui.h"
2019-06-25 04:00:09 +00:00
# include "ProjectAudioManager.h"
2020-07-01 05:45:17 +00:00
# include "ProjectFileIO.h"
2019-06-09 14:25:01 +00:00
# include "ProjectFileManager.h"
2019-05-29 15:42:31 +00:00
# include "ProjectManager.h"
2010-02-20 21:31:01 +00:00
# include "Prefs.h"
2019-05-06 23:00:10 +00:00
# include "Track.h"
2014-11-08 15:18:43 +00:00
# include "widgets/NumericTextCtrl.h"
2016-04-07 11:50:25 +00:00
# include "widgets/HelpSystem.h"
2019-05-20 18:27:11 +00:00
# include "widgets/AudacityMessageBox.h"
2017-09-06 21:39:33 +00:00
# include "widgets/ErrorDialog.h"
2019-03-31 20:12:07 +00:00
# include "widgets/ProgressDialog.h"
2020-07-29 05:08:48 +00:00
# include "widgets/wxTextCtrlWrapper.h"
2010-01-23 19:44:49 +00:00
2018-04-03 12:45:30 +00:00
# if wxUSE_ACCESSIBILITY
# include "widgets/WindowAccessible.h"
# endif
2010-02-08 21:00:17 +00:00
# define TIMER_ID 7000
2010-01-23 19:44:49 +00:00
enum { // control IDs
2014-06-03 20:30:19 +00:00
ID_DATEPICKER_START = 10000 ,
ID_TIMETEXT_START ,
ID_DATEPICKER_END ,
ID_TIMETEXT_END ,
2016-02-25 13:47:48 +00:00
ID_TIMETEXT_DURATION ,
ID_AUTOSAVEPATH_BUTTON ,
ID_AUTOSAVEPATH_TEXT ,
ID_AUTOEXPORTPATH_BUTTON ,
ID_AUTOEXPORTPATH_TEXT ,
ID_AUTOSAVE_CHECKBOX ,
ID_AUTOEXPORT_CHECKBOX
} ;
enum {
CONTROL_GROUP_SAVE ,
CONTROL_GROUP_EXPORT
} ;
2018-09-17 14:31:55 +00:00
// The slow timer interval is used to update the start and end times, which only show
// time to the nearest second. So we only need an update once a second.
const int kSlowTimerInterval = 1000 ; // ms
// This timer interval is used in some busy-wait loops and is much shorter.
2020-05-27 15:07:49 +00:00
const int kTimerInterval = 50 ; // ms
2010-01-23 19:44:49 +00:00
static double wxDateTime_to_AudacityTime ( wxDateTime & dateTime )
{
return ( dateTime . GetHour ( ) * 3600.0 ) + ( dateTime . GetMinute ( ) * 60.0 ) + dateTime . GetSecond ( ) ;
} ;
2016-04-02 13:54:32 +00:00
// The purpose of the DatePickerCtrlAx class is to make to wxDatePickerCtrl more accessible for
// the NVDA screen reader.
// By default the msaa state of wxDatePickerCtrl is always normal (0x0), and this causes nvda not
// to read the control when the user tabs to it. This class
// modifies the state to be focusable + focused (when it's the focus).
2016-08-08 13:50:55 +00:00
// Note that even with this class NVDA still doesn't read the NEW selected part of the control when left/right
2016-04-02 13:54:32 +00:00
// arrow keys are used.
# if wxUSE_ACCESSIBILITY
2018-04-03 12:45:30 +00:00
class DatePickerCtrlAx final : public WindowAccessible
2016-04-02 13:54:32 +00:00
{
public :
2018-04-03 12:45:30 +00:00
DatePickerCtrlAx ( wxDatePickerCtrl * ctrl ) : WindowAccessible ( ctrl ) , mCtrl ( ctrl ) { } ;
2016-04-02 13:54:32 +00:00
virtual ~ DatePickerCtrlAx ( ) { } ;
// Returns a state constant.
wxAccStatus GetState ( int childId , long * state ) override ;
private :
wxDatePickerCtrl * mCtrl ;
} ;
// Returns a state constant.
wxAccStatus DatePickerCtrlAx : : GetState ( int WXUNUSED ( childId ) , long * state )
{
* state = wxACC_STATE_SYSTEM_FOCUSABLE ;
* state | = ( mCtrl = = wxWindow : : FindFocus ( ) ? wxACC_STATE_SYSTEM_FOCUSED : 0 ) ;
return wxACC_OK ;
}
# endif // wxUSE_ACCESSIBILITY
2016-07-10 21:10:50 +00:00
BEGIN_EVENT_TABLE ( TimerRecordDialog , wxDialogWrapper )
2010-01-23 19:44:49 +00:00
EVT_DATE_CHANGED ( ID_DATEPICKER_START , TimerRecordDialog : : OnDatePicker_Start )
EVT_TEXT ( ID_TIMETEXT_START , TimerRecordDialog : : OnTimeText_Start )
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
EVT_DATE_CHANGED ( ID_DATEPICKER_END , TimerRecordDialog : : OnDatePicker_End )
EVT_TEXT ( ID_TIMETEXT_END , TimerRecordDialog : : OnTimeText_End )
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
EVT_TEXT ( ID_TIMETEXT_DURATION , TimerRecordDialog : : OnTimeText_Duration )
EVT_BUTTON ( wxID_OK , TimerRecordDialog : : OnOK )
2016-04-06 12:20:36 +00:00
EVT_BUTTON ( wxID_HELP , TimerRecordDialog : : OnHelpButtonClick )
2010-01-23 19:44:49 +00:00
2010-02-08 21:00:17 +00:00
EVT_TIMER ( TIMER_ID , TimerRecordDialog : : OnTimer )
2016-02-25 13:47:48 +00:00
EVT_BUTTON ( ID_AUTOSAVEPATH_BUTTON , TimerRecordDialog : : OnAutoSavePathButton_Click )
EVT_BUTTON ( ID_AUTOEXPORTPATH_BUTTON , TimerRecordDialog : : OnAutoExportPathButton_Click )
EVT_CHECKBOX ( ID_AUTOSAVE_CHECKBOX , TimerRecordDialog : : OnAutoSaveCheckBox_Change )
EVT_CHECKBOX ( ID_AUTOEXPORT_CHECKBOX , TimerRecordDialog : : OnAutoExportCheckBox_Change )
2010-01-23 19:44:49 +00:00
END_EVENT_TABLE ( )
2020-01-02 04:41:04 +00:00
TimerRecordDialog : : TimerRecordDialog (
wxWindow * parent , AudacityProject & project , bool bAlreadySaved )
2019-12-08 05:25:47 +00:00
: wxDialogWrapper ( parent , - 1 , XO ( " Audacity Timer Record " ) , wxDefaultPosition ,
2010-01-23 19:44:49 +00:00
wxDefaultSize , wxCAPTION )
2020-01-02 04:41:04 +00:00
, mProject { project }
2010-01-23 19:44:49 +00:00
{
2019-12-08 05:25:47 +00:00
SetName ( ) ;
2015-05-12 13:29:27 +00:00
2010-02-20 21:31:01 +00:00
m_DateTime_Start = wxDateTime : : UNow ( ) ;
long seconds ; // default duration is 1 hour = 3600 seconds
gPrefs - > Read ( wxT ( " /TimerRecord/LastDuration " ) , & seconds , 3600 ) ;
2014-06-03 20:30:19 +00:00
m_TimeSpan_Duration = wxTimeSpan : : Seconds ( seconds ) ;
2010-01-23 19:44:49 +00:00
m_DateTime_End = m_DateTime_Start + m_TimeSpan_Duration ;
m_pDatePickerCtrl_Start = NULL ;
m_pTimeTextCtrl_Start = NULL ;
m_pDatePickerCtrl_End = NULL ;
m_pTimeTextCtrl_End = NULL ;
2014-06-03 20:30:19 +00:00
2010-01-23 19:44:49 +00:00
m_pTimeTextCtrl_Duration = NULL ;
2016-02-25 13:47:48 +00:00
// Do we allow the user to change the Automatic Save file?
m_bProjectAlreadySaved = bAlreadySaved ;
2010-01-23 19:44:49 +00:00
ShuttleGui S ( this , eIsCreating ) ;
this - > PopulateOrExchange ( S ) ;
2014-11-08 15:18:43 +00:00
// Set initial focus to "1" of "01h" in Duration NumericTextCtrl,
// instead of OK button (default).
2010-01-23 19:44:49 +00:00
m_pTimeTextCtrl_Duration - > SetFocus ( ) ;
m_pTimeTextCtrl_Duration - > SetFieldFocus ( 3 ) ;
2010-02-08 21:00:17 +00:00
m_timer . SetOwner ( this , TIMER_ID ) ;
2018-09-17 14:31:55 +00:00
m_timer . Start ( kSlowTimerInterval ) ;
2010-01-23 19:44:49 +00:00
}
TimerRecordDialog : : ~ TimerRecordDialog ( )
{
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnTimer ( wxTimerEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
wxDateTime dateTime_UNow = wxDateTime : : UNow ( ) ;
if ( m_DateTime_Start < dateTime_UNow ) {
m_DateTime_Start = dateTime_UNow ;
m_pDatePickerCtrl_Start - > SetValue ( m_DateTime_Start ) ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_Start - > SetValue ( wxDateTime_to_AudacityTime ( m_DateTime_Start ) ) ;
2010-01-23 19:44:49 +00:00
this - > UpdateEnd ( ) ; // Keep Duration constant and update End for changed Start.
}
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnDatePicker_Start ( wxDateEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
m_DateTime_Start = m_pDatePickerCtrl_Start - > GetValue ( ) ;
2014-11-08 15:18:43 +00:00
double dTime = m_pTimeTextCtrl_Start - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
long hr = ( long ) ( dTime / 3600.0 ) ;
long min = ( long ) ( ( dTime - ( hr * 3600.0 ) ) / 60.0 ) ;
long sec = ( long ) ( dTime - ( hr * 3600.0 ) - ( min * 60.0 ) ) ;
m_DateTime_Start . SetHour ( hr ) ;
m_DateTime_Start . SetMinute ( min ) ;
m_DateTime_Start . SetSecond ( sec ) ;
2014-06-03 20:30:19 +00:00
// User might have had the dialog up for a while, or
2010-01-23 19:44:49 +00:00
// had a future day, set hour of day less than now's, then changed day to today.
wxTimerEvent dummyTimerEvent ;
this - > OnTimer ( dummyTimerEvent ) ;
// Always update End for changed Start, keeping Duration constant.
2014-06-03 20:30:19 +00:00
// Note that OnTimer sometimes calls UpdateEnd, so sometimes this is redundant,
2010-01-23 19:44:49 +00:00
// but OnTimer doesn't need to always call UpdateEnd, but we must here.
2014-06-03 20:30:19 +00:00
this - > UpdateEnd ( ) ;
2010-01-23 19:44:49 +00:00
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnTimeText_Start ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
2014-11-08 15:18:43 +00:00
//v NumericTextCtrl doesn't implement upper ranges, i.e.,
// if I tell it "024 h 060 m 060 s", then
// user increments the hours past 23, it rolls over to 0
// (although if you increment below 0, it stays at 0).
2010-01-23 19:44:49 +00:00
// So instead, set the max to 99 and just catch hours > 24 and fix the ctrls.
2014-11-08 15:18:43 +00:00
double dTime = m_pTimeTextCtrl_Start - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
long days = ( long ) ( dTime / ( 24.0 * 3600.0 ) ) ;
if ( days > 0 ) {
dTime - = ( double ) days * 24.0 * 3600.0 ;
m_DateTime_Start + = wxTimeSpan : : Days ( days ) ;
m_pDatePickerCtrl_Start - > SetValue ( m_DateTime_Start ) ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_Start - > SetValue ( dTime ) ;
2010-01-23 19:44:49 +00:00
}
wxDateEvent dummyDateEvent ;
this - > OnDatePicker_Start ( dummyDateEvent ) ;
}
2014-06-03 20:30:19 +00:00
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnDatePicker_End ( wxDateEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
m_DateTime_End = m_pDatePickerCtrl_End - > GetValue ( ) ;
2014-11-08 15:18:43 +00:00
double dTime = m_pTimeTextCtrl_End - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
long hr = ( long ) ( dTime / 3600.0 ) ;
long min = ( long ) ( ( dTime - ( hr * 3600.0 ) ) / 60.0 ) ;
long sec = ( long ) ( dTime - ( hr * 3600.0 ) - ( min * 60.0 ) ) ;
m_DateTime_End . SetHour ( hr ) ;
m_DateTime_End . SetMinute ( min ) ;
m_DateTime_End . SetSecond ( sec ) ;
2014-06-03 20:30:19 +00:00
// DatePickerCtrls use SetRange to make sure End is never less than Start, but
2010-01-23 19:44:49 +00:00
// need to implement it for the TimeTextCtrls.
if ( m_DateTime_End < m_DateTime_Start ) {
m_DateTime_End = m_DateTime_Start ;
2012-07-27 23:37:50 +00:00
m_pDatePickerCtrl_End - > SetValue ( m_DateTime_End ) ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_End - > SetValue ( wxDateTime_to_AudacityTime ( m_DateTime_End ) ) ;
2010-01-23 19:44:49 +00:00
}
this - > UpdateDuration ( ) ; // Keep Start constant and update Duration for changed End.
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnTimeText_End ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
2014-11-08 15:18:43 +00:00
//v NumericTextCtrl doesn't implement upper ranges, i.e.,
// if I tell it "024 h 060 m 060 s", then
// user increments the hours past 23, it rolls over to 0
// (although if you increment below 0, it stays at 0).
2010-01-23 19:44:49 +00:00
// So instead, set the max to 99 and just catch hours > 24 and fix the ctrls.
2014-11-08 15:18:43 +00:00
double dTime = m_pTimeTextCtrl_End - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
long days = ( long ) ( dTime / ( 24.0 * 3600.0 ) ) ;
if ( days > 0 ) {
dTime - = ( double ) days * 24.0 * 3600.0 ;
m_DateTime_End + = wxTimeSpan : : Days ( days ) ;
m_pDatePickerCtrl_End - > SetValue ( m_DateTime_End ) ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_End - > SetValue ( dTime ) ;
2010-01-23 19:44:49 +00:00
}
wxDateEvent dummyDateEvent ;
this - > OnDatePicker_End ( dummyDateEvent ) ;
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnTimeText_Duration ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
2014-11-08 15:18:43 +00:00
double dTime = m_pTimeTextCtrl_Duration - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
long hr = ( long ) ( dTime / 3600.0 ) ;
long min = ( long ) ( ( dTime - ( hr * 3600.0 ) ) / 60.0 ) ;
long sec = ( long ) ( dTime - ( hr * 3600.0 ) - ( min * 60.0 ) ) ;
m_TimeSpan_Duration = wxTimeSpan ( hr , min , sec ) ; //v milliseconds?
this - > UpdateEnd ( ) ; // Keep Start constant and update End for changed Duration.
}
2016-02-25 13:47:48 +00:00
// New events for timer recording automation
void TimerRecordDialog : : OnAutoSavePathButton_Click ( wxCommandEvent & WXUNUSED ( event ) )
{
2020-07-01 05:45:17 +00:00
auto & projectFileIO = ProjectFileIO : : Get ( mProject ) ;
2017-08-02 16:41:29 +00:00
wxString fName = FileNames : : SelectFile ( FileNames : : Operation : : Export ,
2019-12-18 21:32:21 +00:00
XO ( " Save Timer Recording As " ) ,
2016-02-25 13:47:48 +00:00
m_fnAutoSaveFile . GetPath ( ) ,
m_fnAutoSaveFile . GetFullName ( ) ,
2020-07-01 05:45:17 +00:00
wxT ( " aup3 " ) ,
2019-12-27 03:48:00 +00:00
{ FileNames : : AudacityProjects } ,
2016-02-25 13:47:48 +00:00
wxFD_SAVE | wxRESIZE_BORDER ,
this ) ;
2019-03-14 17:04:37 +00:00
if ( fName . empty ( ) )
2016-02-25 13:47:48 +00:00
return ;
2016-09-18 17:56:34 +00:00
// If project already exists then abort - we do not allow users to overwrite an existing project
2016-09-17 14:52:52 +00:00
// unless it is the current project.
2020-07-01 05:45:17 +00:00
if ( wxFileExists ( fName ) & & ( projectFileIO . GetFileName ( ) ! = fName ) ) {
2017-10-12 16:21:52 +00:00
AudacityMessageDialog m (
2019-12-18 00:40:32 +00:00
nullptr ,
XO ( " The selected file name could not be used \n for Timer Recording because it \
2016-09-17 14:52:52 +00:00
would overwrite another project . \ nPlease try again and select an original name . " ),
2019-12-18 00:40:32 +00:00
XO ( " Error Saving Timer Recording Project " ) ,
wxOK | wxICON_ERROR ) ;
2016-02-25 13:47:48 +00:00
m . ShowModal ( ) ;
return ;
}
2016-09-17 14:52:52 +00:00
// Set this boolean to false so we now do a SaveAs at the end of the recording
// unless we're saving the current project.
2020-07-01 05:45:17 +00:00
m_bProjectAlreadySaved = projectFileIO . GetFileName ( ) = = fName ? true : false ;
2016-02-25 13:47:48 +00:00
m_fnAutoSaveFile = fName ;
2020-07-01 05:45:17 +00:00
m_fnAutoSaveFile . SetExt ( wxT ( " aup3 " ) ) ;
2016-02-25 13:47:48 +00:00
this - > UpdateTextBoxControls ( ) ;
}
void TimerRecordDialog : : OnAutoExportPathButton_Click ( wxCommandEvent & WXUNUSED ( event ) )
{
2019-05-22 00:16:20 +00:00
Exporter eExporter { mProject } ;
2016-02-25 13:47:48 +00:00
// Call the Exporter to set the options required
2019-05-22 00:16:20 +00:00
if ( eExporter . SetAutoExportOptions ( ) ) {
2016-02-25 13:47:48 +00:00
// Populate the options so that we can destroy this instance of the Exporter
m_fnAutoExportFile = eExporter . GetAutoExportFileName ( ) ;
m_iAutoExportFormat = eExporter . GetAutoExportFormat ( ) ;
m_iAutoExportSubFormat = eExporter . GetAutoExportSubFormat ( ) ;
m_iAutoExportFilterIndex = eExporter . GetAutoExportFilterIndex ( ) ;
// Update the text controls
this - > UpdateTextBoxControls ( ) ;
}
}
void TimerRecordDialog : : OnAutoSaveCheckBox_Change ( wxCommandEvent & WXUNUSED ( event ) ) {
EnableDisableAutoControls ( m_pTimerAutoSaveCheckBoxCtrl - > GetValue ( ) , CONTROL_GROUP_SAVE ) ;
}
void TimerRecordDialog : : OnAutoExportCheckBox_Change ( wxCommandEvent & WXUNUSED ( event ) ) {
EnableDisableAutoControls ( m_pTimerAutoExportCheckBoxCtrl - > GetValue ( ) , CONTROL_GROUP_EXPORT ) ;
}
2016-04-06 12:20:36 +00:00
void TimerRecordDialog : : OnHelpButtonClick ( wxCommandEvent & WXUNUSED ( event ) )
{
2021-06-06 19:40:11 +00:00
HelpSystem : : ShowHelp ( this , L " Timer_Record " , true ) ;
2016-04-06 12:20:36 +00:00
}
2013-08-25 21:51:26 +00:00
void TimerRecordDialog : : OnOK ( wxCommandEvent & WXUNUSED ( event ) )
2010-01-23 19:44:49 +00:00
{
this - > TransferDataFromWindow ( ) ;
if ( ! m_TimeSpan_Duration . IsPositive ( ) )
{
2019-12-07 19:30:07 +00:00
AudacityMessageBox (
XO ( " Duration is zero. Nothing will be recorded. " ) ,
XO ( " Error in Duration " ) ,
wxICON_EXCLAMATION | wxOK ) ;
2010-01-23 19:44:49 +00:00
return ;
}
2016-02-25 13:47:48 +00:00
// Validate that we have a Save and/or Export path setup if the appropriate check box is ticked
wxString sTemp = m_fnAutoSaveFile . GetFullPath ( ) ;
if ( m_pTimerAutoSaveCheckBoxCtrl - > IsChecked ( ) ) {
if ( ! m_fnAutoSaveFile . IsOk ( ) | | m_fnAutoSaveFile . IsDir ( ) ) {
2019-12-07 19:30:07 +00:00
AudacityMessageBox (
XO ( " Automatic Save path is invalid. " ) ,
XO ( " Error in Automatic Save " ) ,
wxICON_EXCLAMATION | wxOK ) ;
2016-02-25 13:47:48 +00:00
return ;
}
}
if ( m_pTimerAutoExportCheckBoxCtrl - > IsChecked ( ) ) {
if ( ! m_fnAutoExportFile . IsOk ( ) | | m_fnAutoExportFile . IsDir ( ) ) {
2019-12-07 19:30:07 +00:00
AudacityMessageBox (
XO ( " Automatic Export path is invalid. " ) ,
XO ( " Error in Automatic Export " ) ,
wxICON_EXCLAMATION | wxOK ) ;
2016-02-25 13:47:48 +00:00
return ;
}
}
2016-03-30 22:46:15 +00:00
// MY: Estimate here if we have enough disk space to
// complete this Timer Recording.
// If we dont think there is enough space then ask the user
// if they want to continue.
// We don't stop the user from starting the recording
// as its possible that they plan to free up some
// space before the recording begins
2020-07-01 05:45:17 +00:00
auto & projectManager = ProjectManager : : Get ( mProject ) ;
2016-03-30 22:46:15 +00:00
2016-04-06 12:20:36 +00:00
// How many minutes do we have left on the disc?
2019-04-29 06:22:08 +00:00
int iMinsLeft = projectManager . GetEstimatedRecordingMinsLeftOnDisk ( ) ;
2016-03-30 22:46:15 +00:00
// How many minutes will this recording require?
int iMinsRecording = m_TimeSpan_Duration . GetMinutes ( ) ;
// Do we have enough space?
if ( iMinsRecording > = iMinsLeft ) {
2016-04-06 12:20:36 +00:00
// Format the strings
2019-12-25 19:33:18 +00:00
auto sRemainingTime = projectManager . GetHoursMinsString ( iMinsLeft ) ;
auto sPlannedTime = projectManager . GetHoursMinsString ( iMinsRecording ) ;
2016-04-06 12:20:36 +00:00
// Create the message string
2019-12-18 00:40:32 +00:00
auto sMessage = XO (
" You may not have enough free disk space to complete this Timer Recording, based on your current settings. \n \n Do you wish to continue? \n \n Planned recording duration: %s \n Recording time remaining on disk: %s " )
. Format ( sPlannedTime , sRemainingTime ) ;
2016-04-06 12:20:36 +00:00
2019-12-18 00:40:32 +00:00
AudacityMessageDialog dlgMessage (
nullptr ,
2016-04-06 12:20:36 +00:00
sMessage ,
2019-12-18 00:40:32 +00:00
XO ( " Timer Recording Disk Space Warning " ) ,
2016-03-30 22:46:15 +00:00
wxYES_NO | wxNO_DEFAULT | wxICON_WARNING ) ;
2019-12-18 00:40:32 +00:00
if ( dlgMessage . ShowModal ( ) ! = wxID_YES ) {
2016-03-30 22:46:15 +00:00
// User decided not to continue - bail out!
return ;
}
}
2010-01-23 19:44:49 +00:00
m_timer . Stop ( ) ; // Don't need to keep updating m_DateTime_Start to prevent backdating.
this - > EndModal ( wxID_OK ) ;
2010-02-20 21:31:01 +00:00
wxLongLong duration = m_TimeSpan_Duration . GetSeconds ( ) ;
// this will assert if the duration won't fit in a long
gPrefs - > Write ( wxT ( " /TimerRecord/LastDuration " ) , duration . ToLong ( ) ) ;
2012-08-02 06:03:19 +00:00
gPrefs - > Flush ( ) ;
2010-01-23 19:44:49 +00:00
}
2016-02-25 13:47:48 +00:00
void TimerRecordDialog : : EnableDisableAutoControls ( bool bEnable , int iControlGoup ) {
2016-04-01 10:13:32 +00:00
2016-02-25 13:47:48 +00:00
if ( iControlGoup = = CONTROL_GROUP_EXPORT ) {
2016-04-01 10:13:32 +00:00
m_pTimerExportPathTextCtrl - > Enable ( bEnable ) ;
m_pTimerExportPathButtonCtrl - > Enable ( bEnable ) ;
} else if ( iControlGoup = = CONTROL_GROUP_SAVE ) {
m_pTimerSavePathTextCtrl - > Enable ( bEnable ) ;
m_pTimerSavePathButtonCtrl - > Enable ( bEnable ) ;
2016-02-25 13:47:48 +00:00
}
// Enable or disable the Choice box - if there is no Save or Export then this will be disabled
if ( m_pTimerAutoSaveCheckBoxCtrl - > GetValue ( ) | | m_pTimerAutoExportCheckBoxCtrl - > GetValue ( ) ) {
m_pTimerAfterCompleteChoiceCtrl - > Enable ( ) ;
2016-04-01 10:13:32 +00:00
} else {
2016-02-25 13:47:48 +00:00
m_pTimerAfterCompleteChoiceCtrl - > SetSelection ( POST_TIMER_RECORD_NOTHING ) ;
m_pTimerAfterCompleteChoiceCtrl - > Disable ( ) ;
}
}
void TimerRecordDialog : : UpdateTextBoxControls ( ) {
// Will update the text box controls
m_pTimerSavePathTextCtrl - > SetValue ( m_fnAutoSaveFile . GetFullPath ( ) ) ;
m_pTimerExportPathTextCtrl - > SetValue ( m_fnAutoExportFile . GetFullPath ( ) ) ;
// MY: Ensure we still display "Current Project" if this has already been saved
if ( m_bProjectAlreadySaved ) {
m_pTimerSavePathTextCtrl - > SetValue ( _ ( " Current Project " ) ) ;
}
}
/// Runs the wait for start dialog. Returns -1 if the user clicks stop while we are recording
/// or if the post recording actions fail.
int TimerRecordDialog : : RunWaitDialog ( )
2010-01-23 19:44:49 +00:00
{
2016-12-24 15:43:25 +00:00
auto updateResult = ProgressResult : : Success ;
2014-11-25 04:11:46 +00:00
2014-06-03 20:30:19 +00:00
if ( m_DateTime_Start > wxDateTime : : UNow ( ) )
updateResult = this - > WaitForStart ( ) ;
2010-01-23 19:44:49 +00:00
2016-12-24 15:43:25 +00:00
if ( updateResult ! = ProgressResult : : Success ) {
2014-06-03 20:30:19 +00:00
// Don't proceed, but don't treat it as canceled recording. User just canceled waiting.
2016-02-25 13:47:48 +00:00
return POST_TIMER_RECORD_CANCEL_WAIT ;
2016-04-01 10:13:32 +00:00
} else {
2010-01-23 19:44:49 +00:00
// Record for specified time.
2020-07-01 05:45:17 +00:00
ProjectAudioManager : : Get ( mProject ) . OnRecord ( false ) ;
2010-01-23 19:44:49 +00:00
bool bIsRecording = true ;
2019-12-19 21:20:41 +00:00
auto sPostAction = Verbatim (
m_pTimerAfterCompleteChoiceCtrl - > GetStringSelection ( ) ) ;
2016-08-30 19:29:10 +00:00
2018-01-05 20:41:36 +00:00
// Two column layout.
2019-02-12 22:54:52 +00:00
TimerProgressDialog : : MessageTable columns {
{
2019-12-08 03:37:02 +00:00
XO ( " Recording start: " ) ,
XO ( " Duration: " ) ,
XO ( " Recording end: " ) ,
2019-02-12 22:54:52 +00:00
{ } ,
2019-12-08 03:37:02 +00:00
XO ( " Automatic Save enabled: " ) ,
XO ( " Automatic Export enabled: " ) ,
XO ( " Action after Timer Recording: " ) ,
2019-02-12 22:54:52 +00:00
} ,
{
GetDisplayDate ( m_DateTime_Start ) ,
2019-12-19 21:20:41 +00:00
Verbatim ( m_TimeSpan_Duration . Format ( ) ) ,
2019-02-12 22:54:52 +00:00
GetDisplayDate ( m_DateTime_End ) ,
{ } ,
2019-12-08 03:37:02 +00:00
( m_bAutoSaveEnabled ? XO ( " Yes " ) : XO ( " No " ) ) ,
( m_bAutoExportEnabled ? XO ( " Yes " ) : XO ( " No " ) ) ,
2019-02-12 22:54:52 +00:00
sPostAction ,
}
} ;
2010-01-23 19:44:49 +00:00
2014-06-03 20:30:19 +00:00
TimerProgressDialog
progress ( m_TimeSpan_Duration . GetMilliseconds ( ) . GetValue ( ) ,
2019-12-08 03:37:02 +00:00
XO ( " Audacity Timer Record Progress " ) ,
2018-01-05 20:41:36 +00:00
columns ,
2016-03-30 22:46:15 +00:00
pdlgHideCancelButton | pdlgConfirmStopCancel ) ;
2010-01-23 19:44:49 +00:00
2014-06-03 20:30:19 +00:00
// Make sure that start and end time are updated, so we always get the full
2010-01-23 19:44:49 +00:00
// duration, even if there's some delay getting here.
wxTimerEvent dummyTimerEvent ;
this - > OnTimer ( dummyTimerEvent ) ;
// Loop for progress display during recording.
2016-12-24 15:43:25 +00:00
while ( bIsRecording & & ( updateResult = = ProgressResult : : Success ) ) {
2018-01-05 20:41:36 +00:00
updateResult = progress . UpdateProgress ( ) ;
2016-04-01 14:17:39 +00:00
wxMilliSleep ( kTimerInterval ) ;
2010-01-23 19:44:49 +00:00
bIsRecording = ( wxDateTime : : UNow ( ) < = m_DateTime_End ) ; // Call UNow() again for extra accuracy...
}
}
2015-01-07 00:48:14 +00:00
// Must do this AFTER the timer project dialog has been deleted to ensure the application
// responds to the AUDIOIO events...see not about bug #334 in the ProgressDialog constructor.
2020-07-01 05:45:17 +00:00
ProjectAudioManager : : Get ( mProject ) . Stop ( ) ;
2015-01-07 00:48:14 +00:00
2014-06-03 20:30:19 +00:00
// Let the caller handle cancellation or failure from recording progress.
2016-12-24 15:43:25 +00:00
if ( updateResult = = ProgressResult : : Cancelled | | updateResult = = ProgressResult : : Failed )
2016-02-25 13:47:48 +00:00
return POST_TIMER_RECORD_CANCEL ;
2014-11-25 04:11:46 +00:00
2016-12-24 15:43:25 +00:00
return ExecutePostRecordActions ( ( updateResult = = ProgressResult : : Stopped ) ) ;
2016-02-25 13:47:48 +00:00
}
2014-11-25 04:11:46 +00:00
2016-02-25 13:47:48 +00:00
int TimerRecordDialog : : ExecutePostRecordActions ( bool bWasStopped ) {
2016-04-01 10:13:32 +00:00
// MY: We no longer automatically (and silently) call ->Save() when the
// timer recording is completed. We can now Save and/or Export depending
// on the options selected by the user.
2016-02-25 13:47:48 +00:00
// Once completed, we can also close Audacity, restart the system or
// shutdown the system.
// If there was any error with the auto save or export then we will not do
// the actions requested and instead present an error mesasge to the user.
2016-04-01 10:13:32 +00:00
// Finally, if there is no post-record action selected then we output
2016-02-25 13:47:48 +00:00
// a dialog detailing what has been carried out instead.
bool bSaveOK = false ;
bool bExportOK = false ;
int iPostRecordAction = m_pTimerAfterCompleteChoiceCtrl - > GetSelection ( ) ;
int iOverriddenAction = iPostRecordAction ;
bool bErrorOverride = false ;
// Do Automatic Save?
if ( m_bAutoSaveEnabled ) {
2020-07-01 05:45:17 +00:00
auto & projectFileManager = ProjectFileManager : : Get ( mProject ) ;
2016-02-25 13:47:48 +00:00
// MY: If this project has already been saved then simply execute a Save here
if ( m_bProjectAlreadySaved ) {
2019-06-07 17:24:38 +00:00
bSaveOK = projectFileManager . Save ( ) ;
2016-04-01 10:13:32 +00:00
} else {
2019-06-07 17:24:38 +00:00
bSaveOK = projectFileManager . SaveFromTimerRecording ( m_fnAutoSaveFile ) ;
2016-02-25 13:47:48 +00:00
}
}
// Do Automatic Export?
if ( m_bAutoExportEnabled ) {
2019-05-22 00:16:20 +00:00
Exporter e { mProject } ;
2019-04-24 01:49:30 +00:00
bExportOK = e . ProcessFromTimerRecording (
2020-07-01 05:45:17 +00:00
false , 0.0 , TrackList : : Get ( mProject ) . GetEndTime ( ) ,
2019-04-24 01:49:30 +00:00
m_fnAutoExportFile , m_iAutoExportFormat ,
m_iAutoExportSubFormat , m_iAutoExportFilterIndex ) ;
2016-02-25 13:47:48 +00:00
}
// Check if we need to override the post recording action
bErrorOverride = ( ( m_bAutoSaveEnabled & & ! bSaveOK ) | | ( m_bAutoExportEnabled & & ! bExportOK ) ) ;
if ( bErrorOverride | | bWasStopped ) {
iPostRecordAction = POST_TIMER_RECORD_NOTHING ;
}
if ( iPostRecordAction = = POST_TIMER_RECORD_NOTHING ) {
// If there is no post-record action then we can show a message indicating what has been done
2019-12-07 19:30:07 +00:00
auto sMessage = ( bWasStopped ? XO ( " Timer Recording stopped. " ) :
XO ( " Timer Recording completed. " ) ) ;
2016-02-25 13:47:48 +00:00
if ( m_bAutoSaveEnabled ) {
if ( bSaveOK ) {
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n Recording saved: %s " ) . Format (
2016-02-25 13:47:48 +00:00
sMessage , m_fnAutoSaveFile . GetFullPath ( ) ) ;
2016-04-01 10:13:32 +00:00
} else {
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n Error saving recording. " ) . Format ( sMessage ) ;
2016-02-25 13:47:48 +00:00
}
}
if ( m_bAutoExportEnabled ) {
if ( bExportOK ) {
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n Recording exported: %s " ) . Format (
2016-02-25 13:47:48 +00:00
sMessage , m_fnAutoExportFile . GetFullPath ( ) ) ;
2016-04-01 10:13:32 +00:00
} else {
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n Error exporting recording. " ) . Format ( sMessage ) ;
2016-02-25 13:47:48 +00:00
}
}
if ( bErrorOverride ) {
if ( ( iOverriddenAction ! = iPostRecordAction ) & &
( iOverriddenAction ! = POST_TIMER_RECORD_NOTHING ) ) {
// Inform the user that we have overridden the selected action
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n '%s' has been canceled due to the error(s) noted above. " ) . Format (
2016-02-25 13:47:48 +00:00
sMessage ,
m_pTimerAfterCompleteChoiceCtrl - > GetString ( iOverriddenAction ) ) ;
}
// Show Error Message Box
2019-12-07 19:30:07 +00:00
AudacityMessageBox (
sMessage ,
XO ( " Error " ) ,
wxICON_EXCLAMATION | wxOK ) ;
2016-04-01 10:13:32 +00:00
} else {
2016-02-25 13:47:48 +00:00
if ( bWasStopped & & ( iOverriddenAction ! = POST_TIMER_RECORD_NOTHING ) ) {
2019-12-07 19:30:07 +00:00
sMessage = XO ( " %s \n \n '%s' has been canceled as the recording was stopped. " ) . Format (
2016-02-25 13:47:48 +00:00
sMessage ,
m_pTimerAfterCompleteChoiceCtrl - > GetString ( iOverriddenAction ) ) ;
}
2019-12-07 19:30:07 +00:00
AudacityMessageBox (
sMessage ,
XO ( " Timer Recording " ) ,
wxICON_INFORMATION | wxOK ) ;
2016-02-25 13:47:48 +00:00
}
}
// MY: Lets do some actions that only apply to Exit/Restart/Shutdown
if ( iPostRecordAction > = POST_TIMER_RECORD_CLOSE ) {
do {
2016-03-30 22:46:15 +00:00
// Set the flags as appropriate based on what we have done
wxUint32 eActionFlags = TR_ACTION_NOTHING ;
if ( m_bAutoSaveEnabled & & bSaveOK ) {
eActionFlags | = TR_ACTION_SAVED ;
}
if ( m_bAutoExportEnabled & & bExportOK ) {
eActionFlags | = TR_ACTION_EXPORTED ;
}
2016-02-25 13:47:48 +00:00
// Lets show a warning dialog telling the user what is about to happen.
// If the user no longer wants to carry out this action then they can click
// Cancel and we will do POST_TIMER_RECORD_NOTHING instead.
2016-12-24 15:43:25 +00:00
auto iDelayOutcome = PreActionDelay ( iPostRecordAction , ( TimerRecordCompletedActions ) eActionFlags ) ;
if ( iDelayOutcome ! = ProgressResult : : Success ) {
2016-02-25 13:47:48 +00:00
// Cancel the action!
iPostRecordAction = POST_TIMER_RECORD_NOTHING ;
break ;
}
} while ( false ) ;
}
// Return the action as required
return iPostRecordAction ;
2010-01-23 19:44:49 +00:00
}
2019-12-08 03:37:02 +00:00
TranslatableString TimerRecordDialog : : GetDisplayDate ( wxDateTime & dt )
2010-01-23 19:44:49 +00:00
{
# if defined(__WXMSW__)
// On Windows, wxWidgets uses the system date control and it displays the
// date based on the Windows locale selected by the user. But, wxDateTime
// using the strftime function to return the formatted date. Since the
// default locale for the Windows CRT environment is "C", the dates come
// back in a different format.
//
// So, we make direct Windows calls to format the date like it the date
// control.
//
// (Most of this taken from src/msw/datectrl.cpp)
const wxDateTime : : Tm tm ( dt . GetTm ( ) ) ;
SYSTEMTIME st ;
wxString s ;
int len ;
st . wYear = ( WXWORD ) tm . year ;
st . wMonth = ( WXWORD ) ( tm . mon - wxDateTime : : Jan + 1 ) ;
st . wDay = tm . mday ;
2014-06-03 20:30:19 +00:00
st . wDayOfWeek = st . wMinute = st . wSecond = st . wMilliseconds = 0 ;
2010-01-23 19:44:49 +00:00
len = : : GetDateFormat ( LOCALE_USER_DEFAULT ,
DATE_SHORTDATE ,
& st ,
NULL ,
NULL ,
0 ) ;
if ( len > 0 ) {
len = : : GetDateFormat ( LOCALE_USER_DEFAULT ,
DATE_SHORTDATE ,
& st ,
NULL ,
wxStringBuffer ( s , len ) ,
len ) ;
if ( len > 0 ) {
s + = wxT ( " " ) + dt . FormatTime ( ) ;
2019-12-21 16:21:34 +00:00
return Verbatim ( s ) ;
2010-01-23 19:44:49 +00:00
}
}
# endif
// Use default formatting
2017-10-09 05:03:14 +00:00
wxPrintf ( wxT ( " %s \n " ) , dt . Format ( ) ) ;
2019-12-19 21:20:41 +00:00
return Verbatim ( dt . FormatDate ( ) + wxT ( " " ) + dt . FormatTime ( ) ) ;
2010-01-23 19:44:49 +00:00
}
2020-07-29 05:08:48 +00:00
wxTextCtrlWrapper * TimerRecordDialog : : NewPathControl (
2019-12-28 03:44:44 +00:00
wxWindow * wParent , const int iID ,
const TranslatableString & sCaption , const TranslatableString & sValue )
2016-02-25 13:47:48 +00:00
{
2020-07-29 05:08:48 +00:00
wxTextCtrlWrapper * pTextCtrl ;
2016-08-14 03:16:05 +00:00
wxASSERT ( wParent ) ; // to justify safenew
2020-07-29 05:08:48 +00:00
pTextCtrl = safenew wxTextCtrlWrapper ( wParent , iID , sValue . Translation ( ) ) ;
2019-12-28 03:44:44 +00:00
pTextCtrl - > SetName ( sCaption . Translation ( ) ) ;
2016-02-25 13:47:48 +00:00
return pTextCtrl ;
}
2010-01-23 19:44:49 +00:00
void TimerRecordDialog : : PopulateOrExchange ( ShuttleGui & S )
{
2016-02-25 13:47:48 +00:00
bool bAutoSave = gPrefs - > ReadBool ( " /TimerRecord/AutoSave " , false ) ;
bool bAutoExport = gPrefs - > ReadBool ( " /TimerRecord/AutoExport " , false ) ;
int iPostTimerRecordAction = gPrefs - > ReadLong ( " /TimerRecord/PostAction " , 0 ) ;
2010-01-23 19:44:49 +00:00
S . SetBorder ( 5 ) ;
2019-02-22 20:15:19 +00:00
using Options = NumericTextCtrl : : Options ;
/* i18n-hint a format string for hours, minutes, and seconds */
2019-12-01 16:05:29 +00:00
auto strFormat = XO ( " 099 h 060 m 060 s " ) ;
2019-02-22 20:15:19 +00:00
/* i18n-hint a format string for days, hours, minutes, and seconds */
2019-12-01 16:05:29 +00:00
auto strFormat1 = XO ( " 099 days 024 h 060 m 060 s " ) ;
2019-02-22 20:15:19 +00:00
2016-02-25 13:47:48 +00:00
S . StartMultiColumn ( 2 , wxCENTER ) ;
2010-01-23 19:44:49 +00:00
{
2016-02-25 13:47:48 +00:00
S . StartVerticalLay ( true ) ;
2010-01-23 19:44:49 +00:00
{
2016-02-25 13:47:48 +00:00
/* i18n-hint: This string is used to configure the controls for times when the recording is
* started and stopped . As such it is important that only the alphabetic parts of the string
* are translated , with the numbers left exactly as they are .
* The ' h ' indicates the first number displayed is hours , the ' m ' indicates the second number
* displayed is minutes , and the ' s ' indicates that the third number displayed is seconds .
*/
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " Start Date and Time " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
m_pDatePickerCtrl_Start =
2017-10-20 16:43:20 +00:00
safenew wxDatePickerCtrl ( S . GetParent ( ) , // wxWindow *parent,
2016-02-25 13:47:48 +00:00
ID_DATEPICKER_START , // wxWindowID id,
m_DateTime_Start ) ; // const wxDateTime& dt = wxDefaultDateTime,
// const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDP_DEFAULT | wxDP_SHOWCENTURY, const wxValidator& validator = wxDefaultValidator, const wxString& name = "datectrl")
m_pDatePickerCtrl_Start - > SetRange ( wxDateTime : : Today ( ) , wxInvalidDateTime ) ; // No backdating.
2016-04-02 13:54:32 +00:00
# if wxUSE_ACCESSIBILITY
2016-05-07 01:03:37 +00:00
m_pDatePickerCtrl_Start - > SetAccessible ( safenew DatePickerCtrlAx ( m_pDatePickerCtrl_Start ) ) ;
2016-04-02 13:54:32 +00:00
# endif
2017-10-29 14:27:23 +00:00
S . Name ( XO ( " Start Date " ) )
. AddWindow ( m_pDatePickerCtrl_Start ) ;
2016-02-25 13:47:48 +00:00
2016-08-08 13:54:53 +00:00
m_pTimeTextCtrl_Start = safenew NumericTextCtrl (
2017-10-20 16:43:20 +00:00
S . GetParent ( ) , ID_TIMETEXT_START , NumericConverter : : TIME ,
2017-10-06 15:05:15 +00:00
{ } , 0 , 44100 ,
2018-01-30 23:44:44 +00:00
Options { }
. MenuEnabled ( false )
. Format ( strFormat )
. Value ( true , wxDateTime_to_AudacityTime ( m_DateTime_Start ) ) ) ;
2017-10-29 14:27:23 +00:00
S . Name ( XO ( " Start Time " ) )
. AddWindow ( m_pTimeTextCtrl_Start ) ;
2016-02-25 13:47:48 +00:00
}
S . EndStatic ( ) ;
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " End Date and Time " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
m_pDatePickerCtrl_End =
2017-10-20 16:43:20 +00:00
safenew wxDatePickerCtrl ( S . GetParent ( ) , // wxWindow *parent,
2016-02-25 13:47:48 +00:00
ID_DATEPICKER_END , // wxWindowID id,
m_DateTime_End ) ; // const wxDateTime& dt = wxDefaultDateTime,
2016-08-30 19:29:10 +00:00
// const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
// long style = wxDP_DEFAULT | wxDP_SHOWCENTURY,
// const wxValidator& validator = wxDefaultValidator,
// const wxString& name = "datectrl")
2016-02-25 13:47:48 +00:00
m_pDatePickerCtrl_End - > SetRange ( m_DateTime_Start , wxInvalidDateTime ) ; // No backdating.
2016-04-02 13:54:32 +00:00
# if wxUSE_ACCESSIBILITY
2016-05-07 01:03:37 +00:00
m_pDatePickerCtrl_End - > SetAccessible ( safenew DatePickerCtrlAx ( m_pDatePickerCtrl_End ) ) ;
2016-04-02 13:54:32 +00:00
# endif
2017-10-29 14:27:23 +00:00
S . Name ( XO ( " End Date " ) )
. AddWindow ( m_pDatePickerCtrl_End ) ;
2016-02-25 13:47:48 +00:00
2016-08-08 13:54:53 +00:00
m_pTimeTextCtrl_End = safenew NumericTextCtrl (
2017-10-20 16:43:20 +00:00
S . GetParent ( ) , ID_TIMETEXT_END , NumericConverter : : TIME ,
2017-10-06 15:05:15 +00:00
{ } , 0 , 44100 ,
2018-01-30 23:44:44 +00:00
Options { }
. MenuEnabled ( false )
. Format ( strFormat )
. Value ( true , wxDateTime_to_AudacityTime ( m_DateTime_End ) ) ) ;
2017-10-29 14:27:23 +00:00
S . Name ( XO ( " End Time " ) )
. AddWindow ( m_pTimeTextCtrl_End ) ;
2016-02-25 13:47:48 +00:00
}
S . EndStatic ( ) ;
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " Duration " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
2020-04-05 12:40:15 +00:00
m_pTimeTextCtrl_Duration = safenew NumericTextCtrl (
S . GetParent ( ) , ID_TIMETEXT_DURATION , NumericConverter : : TIME ,
{ } , 0 , 44100 ,
Options { }
. MenuEnabled ( false )
. Format ( strFormat1 )
. Value ( true , m_TimeSpan_Duration . GetSeconds ( ) . ToDouble ( ) ) ) ;
2016-02-25 13:47:48 +00:00
/* i18n-hint: This string is used to configure the controls which shows the recording
* duration . As such it is important that only the alphabetic parts of the string
* are translated , with the numbers left exactly as they are .
* The string ' days ' indicates that the first number in the control will be the number of days ,
* then the ' h ' indicates the second number displayed is hours , the ' m ' indicates the third
* number displayed is minutes , and the ' s ' indicates that the fourth number displayed is
* seconds .
*/
2017-10-29 14:27:23 +00:00
S . Name ( XO ( " Duration " ) )
. AddWindow ( m_pTimeTextCtrl_Duration ) ;
2016-02-25 13:47:48 +00:00
}
S . EndStatic ( ) ;
2010-01-23 19:44:49 +00:00
}
2016-02-25 13:47:48 +00:00
S . EndVerticalLay ( ) ;
2010-01-23 19:44:49 +00:00
2016-02-25 13:47:48 +00:00
S . StartVerticalLay ( true ) ;
2010-01-23 19:44:49 +00:00
{
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " Automatic Save " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
// If checked, the project will be saved when the recording is completed
2020-05-11 15:28:14 +00:00
m_pTimerAutoSaveCheckBoxCtrl = S . Id ( ID_AUTOSAVE_CHECKBOX ) . AddCheckBox ( XXO ( " Enable &Automatic Save? " ) ,
2018-02-02 02:37:34 +00:00
bAutoSave ) ;
2016-02-25 13:47:48 +00:00
S . StartMultiColumn ( 3 , wxEXPAND ) ;
{
2019-12-28 03:44:44 +00:00
TranslatableString sInitialValue ;
2020-07-01 05:45:17 +00:00
auto sSaveValue = ProjectFileIO : : Get ( mProject ) . GetFileName ( ) ;
2019-03-14 20:20:18 +00:00
if ( ! sSaveValue . empty ( ) ) {
2016-02-25 13:47:48 +00:00
m_fnAutoSaveFile . Assign ( sSaveValue ) ;
2019-12-28 03:44:44 +00:00
sInitialValue = XO ( " Current Project " ) ;
2016-02-25 13:47:48 +00:00
}
2020-05-11 15:28:14 +00:00
S . AddPrompt ( XXO ( " Save Project As: " ) ) ;
2017-10-20 16:43:20 +00:00
m_pTimerSavePathTextCtrl = NewPathControl (
2019-12-28 03:44:44 +00:00
S . GetParent ( ) , ID_AUTOSAVEPATH_TEXT ,
XO ( " Save Project As: " ) , sInitialValue ) ;
2021-04-02 01:00:12 +00:00
m_pTimerSavePathTextCtrl - > SetReadOnly ( true ) ;
2016-02-25 13:47:48 +00:00
S . AddWindow ( m_pTimerSavePathTextCtrl ) ;
2020-05-11 15:28:14 +00:00
m_pTimerSavePathButtonCtrl = S . Id ( ID_AUTOSAVEPATH_BUTTON ) . AddButton ( XXO ( " Select... " ) ) ;
2016-02-25 13:47:48 +00:00
}
S . EndMultiColumn ( ) ;
}
S . EndStatic ( ) ;
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " Automatic Export " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
2020-05-11 15:28:14 +00:00
m_pTimerAutoExportCheckBoxCtrl = S . Id ( ID_AUTOEXPORT_CHECKBOX ) . AddCheckBox ( XXO ( " Enable Automatic &Export? " ) , bAutoExport ) ;
2016-02-25 13:47:48 +00:00
S . StartMultiColumn ( 3 , wxEXPAND ) ;
{
2020-05-11 15:28:14 +00:00
S . AddPrompt ( XXO ( " Export Project As: " ) ) ;
2017-10-20 16:43:20 +00:00
m_pTimerExportPathTextCtrl = NewPathControl (
2019-12-28 03:44:44 +00:00
S . GetParent ( ) , ID_AUTOEXPORTPATH_TEXT ,
XO ( " Export Project As: " ) , { } ) ;
2021-04-02 01:00:12 +00:00
m_pTimerExportPathTextCtrl - > SetReadOnly ( true ) ;
2016-02-25 13:47:48 +00:00
S . AddWindow ( m_pTimerExportPathTextCtrl ) ;
2020-05-11 15:28:14 +00:00
m_pTimerExportPathButtonCtrl = S . Id ( ID_AUTOEXPORTPATH_BUTTON ) . AddButton ( XXO ( " Select... " ) ) ;
2016-02-25 13:47:48 +00:00
}
S . EndMultiColumn ( ) ;
}
S . EndStatic ( ) ;
2019-12-22 19:58:36 +00:00
S . StartStatic ( XO ( " Options " ) , true ) ;
2016-02-25 13:47:48 +00:00
{
2018-04-22 17:08:52 +00:00
S . StartMultiColumn ( 1 , wxEXPAND ) ;
{
S . SetStretchyCol ( 0 ) ;
2020-05-11 15:28:14 +00:00
m_pTimerAfterCompleteChoiceCtrl = S . AddChoice ( XXO ( " After Recording completes: " ) ,
2019-02-22 20:15:19 +00:00
{
2019-12-18 03:52:42 +00:00
XO ( " Do nothing " ) ,
XO ( " Exit Audacity " ) ,
2019-02-22 20:15:19 +00:00
# ifdef __WINDOWS__
2019-12-18 03:52:42 +00:00
XO ( " Restart system " ) ,
XO ( " Shutdown system " ) ,
2019-02-22 20:15:19 +00:00
# endif
} ,
iPostTimerRecordAction
) ;
2018-04-22 17:08:52 +00:00
}
S . EndMultiColumn ( ) ;
2016-02-25 13:47:48 +00:00
}
S . EndStatic ( ) ;
2010-01-23 19:44:49 +00:00
}
2016-02-25 13:47:48 +00:00
S . EndVerticalLay ( ) ;
2010-01-23 19:44:49 +00:00
}
2016-02-25 13:47:48 +00:00
S . EndMultiColumn ( ) ;
2014-06-03 20:30:19 +00:00
2016-04-06 12:20:36 +00:00
// MY: Added the help button here
S . AddStandardButtons ( eOkButton | eCancelButton | eHelpButton ) ;
2010-01-23 19:44:49 +00:00
Layout ( ) ;
Fit ( ) ;
SetMinSize ( GetSize ( ) ) ;
Center ( ) ;
2016-02-25 13:47:48 +00:00
EnableDisableAutoControls ( bAutoSave , CONTROL_GROUP_SAVE ) ;
EnableDisableAutoControls ( bAutoExport , CONTROL_GROUP_EXPORT ) ;
2010-01-23 19:44:49 +00:00
}
bool TimerRecordDialog : : TransferDataFromWindow ( )
{
double dTime ;
long hr ;
long min ;
long sec ;
m_DateTime_Start = m_pDatePickerCtrl_Start - > GetValue ( ) ;
2014-11-08 15:18:43 +00:00
dTime = m_pTimeTextCtrl_Start - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
hr = ( long ) ( dTime / 3600.0 ) ;
min = ( long ) ( ( dTime - ( hr * 3600.0 ) ) / 60.0 ) ;
sec = ( long ) ( dTime - ( hr * 3600.0 ) - ( min * 60.0 ) ) ;
m_DateTime_Start . SetHour ( hr ) ;
m_DateTime_Start . SetMinute ( min ) ;
m_DateTime_Start . SetSecond ( sec ) ;
m_DateTime_End = m_pDatePickerCtrl_End - > GetValue ( ) ;
2014-11-08 15:18:43 +00:00
dTime = m_pTimeTextCtrl_End - > GetValue ( ) ;
2010-01-23 19:44:49 +00:00
hr = ( long ) ( dTime / 3600.0 ) ;
min = ( long ) ( ( dTime - ( hr * 3600.0 ) ) / 60.0 ) ;
sec = ( long ) ( dTime - ( hr * 3600.0 ) - ( min * 60.0 ) ) ;
m_DateTime_End . SetHour ( hr ) ;
m_DateTime_End . SetMinute ( min ) ;
m_DateTime_End . SetSecond ( sec ) ;
m_TimeSpan_Duration = m_DateTime_End - m_DateTime_Start ;
2016-02-25 13:47:48 +00:00
// Pull the settings from the auto save/export controls and write to the pref file
m_bAutoSaveEnabled = m_pTimerAutoSaveCheckBoxCtrl - > GetValue ( ) ;
m_bAutoExportEnabled = m_pTimerAutoExportCheckBoxCtrl - > GetValue ( ) ;
// MY: Obtain the index from the choice control so we can save to the prefs file
int iPostRecordAction = m_pTimerAfterCompleteChoiceCtrl - > GetSelection ( ) ;
// Save the options back to the prefs file
gPrefs - > Write ( " /TimerRecord/AutoSave " , m_bAutoSaveEnabled ) ;
gPrefs - > Write ( " /TimerRecord/AutoExport " , m_bAutoExportEnabled ) ;
gPrefs - > Write ( " /TimerRecord/PostAction " , iPostRecordAction ) ;
2010-01-23 19:44:49 +00:00
return true ;
}
// Update m_TimeSpan_Duration and ctrl based on m_DateTime_Start and m_DateTime_End.
2014-06-03 20:30:19 +00:00
void TimerRecordDialog : : UpdateDuration ( )
2010-01-23 19:44:49 +00:00
{
m_TimeSpan_Duration = m_DateTime_End - m_DateTime_Start ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_Duration - > SetValue ( m_TimeSpan_Duration . GetSeconds ( ) . ToDouble ( ) ) ;
2010-01-23 19:44:49 +00:00
}
// Update m_DateTime_End and ctrls based on m_DateTime_Start and m_TimeSpan_Duration.
void TimerRecordDialog : : UpdateEnd ( )
{
//v Use remaining disk -> record time calcs from AudacityProject::OnTimer to set range?
m_DateTime_End = m_DateTime_Start + m_TimeSpan_Duration ;
2018-09-17 14:31:55 +00:00
//wxLogDebug( "Time start %s end %s",
// m_DateTime_Start.FormatISOCombined(' '),
// m_DateTime_End.FormatISOCombined(' ') );
// Disable the range limitation (to fix Bug 1749 and 1978)
// Otherwise SetVallue asserts when going back in time.
m_pDatePickerCtrl_End - > SetRange ( wxInvalidDateTime , wxInvalidDateTime ) ;
2010-01-23 19:44:49 +00:00
m_pDatePickerCtrl_End - > SetValue ( m_DateTime_End ) ;
2018-09-17 14:31:55 +00:00
// Re-enable range limitation to constrain user input.
2010-01-23 19:44:49 +00:00
m_pDatePickerCtrl_End - > SetRange ( m_DateTime_Start , wxInvalidDateTime ) ; // No backdating.
m_pDatePickerCtrl_End - > Refresh ( ) ;
2014-11-08 15:18:43 +00:00
m_pTimeTextCtrl_End - > SetValue ( wxDateTime_to_AudacityTime ( m_DateTime_End ) ) ;
2010-01-23 19:44:49 +00:00
}
2016-12-24 15:43:25 +00:00
ProgressResult TimerRecordDialog : : WaitForStart ( )
2010-01-23 19:44:49 +00:00
{
2016-03-30 22:46:15 +00:00
// MY: The Waiting For Start dialog now shows what actions will occur after recording has completed
2019-12-19 21:20:41 +00:00
auto sPostAction = Verbatim (
m_pTimerAfterCompleteChoiceCtrl - > GetStringSelection ( ) ) ;
2016-03-30 22:46:15 +00:00
2018-01-05 20:41:36 +00:00
// Two column layout.
2019-02-12 22:54:52 +00:00
TimerProgressDialog : : MessageTable columns {
{
2019-12-08 03:37:02 +00:00
XO ( " Waiting to start recording at: " ) ,
XO ( " Recording duration: " ) ,
XO ( " Scheduled to stop at: " ) ,
2019-02-12 22:54:52 +00:00
{ } ,
2019-12-08 03:37:02 +00:00
XO ( " Automatic Save enabled: " ) ,
XO ( " Automatic Export enabled: " ) ,
XO ( " Action after Timer Recording: " ) ,
2019-02-12 22:54:52 +00:00
} ,
{
2019-12-08 03:37:02 +00:00
GetDisplayDate ( m_DateTime_Start ) ,
2019-12-19 21:20:41 +00:00
Verbatim ( m_TimeSpan_Duration . Format ( ) ) ,
2019-02-12 22:54:52 +00:00
GetDisplayDate ( m_DateTime_End ) ,
{ } ,
2019-12-08 03:37:02 +00:00
( m_bAutoSaveEnabled ? XO ( " Yes " ) : XO ( " No " ) ) ,
( m_bAutoExportEnabled ? XO ( " Yes " ) : XO ( " No " ) ) ,
2019-02-12 22:54:52 +00:00
sPostAction ,
} ,
} ;
2016-03-30 22:46:15 +00:00
2010-01-23 19:44:49 +00:00
wxDateTime startWait_DateTime = wxDateTime : : UNow ( ) ;
wxTimeSpan waitDuration = m_DateTime_Start - startWait_DateTime ;
2016-03-30 22:46:15 +00:00
TimerProgressDialog progress ( waitDuration . GetMilliseconds ( ) . GetValue ( ) ,
2019-12-08 03:37:02 +00:00
XO ( " Audacity Timer Record - Waiting for Start " ) ,
2018-01-05 20:41:36 +00:00
columns ,
2016-03-30 22:46:15 +00:00
pdlgHideStopButton | pdlgConfirmStopCancel | pdlgHideElapsedTime ,
2018-10-25 08:14:40 +00:00
/* i18n-hint: "in" means after a duration of time,
which is shown below this string */
2019-12-08 03:37:02 +00:00
XO ( " Recording will commence in: " ) ) ;
2010-01-23 19:44:49 +00:00
2016-12-24 15:43:25 +00:00
auto updateResult = ProgressResult : : Success ;
2010-01-23 19:44:49 +00:00
bool bIsRecording = false ;
2016-12-24 15:43:25 +00:00
while ( updateResult = = ProgressResult : : Success & & ! bIsRecording )
2010-01-23 19:44:49 +00:00
{
2018-01-05 20:41:36 +00:00
updateResult = progress . UpdateProgress ( ) ;
2018-04-22 11:30:44 +00:00
wxMilliSleep ( kTimerInterval ) ;
2010-01-23 19:44:49 +00:00
bIsRecording = ( m_DateTime_Start < = wxDateTime : : UNow ( ) ) ;
}
return updateResult ;
}
2016-02-25 13:47:48 +00:00
2016-12-24 15:43:25 +00:00
ProgressResult TimerRecordDialog : : PreActionDelay ( int iActionIndex , TimerRecordCompletedActions eCompletedActions )
2016-02-25 13:47:48 +00:00
{
2019-12-19 21:20:41 +00:00
auto sAction = Verbatim ( m_pTimerAfterCompleteChoiceCtrl
- > GetString ( iActionIndex ) ) ;
2019-12-08 03:37:02 +00:00
2018-10-25 08:14:40 +00:00
/* i18n-hint: %s is one of "Do nothing", "Exit Audacity", "Restart system",
or " Shutdown system " , and
" in " means after a duration of time , shown below this string */
2019-12-08 03:37:02 +00:00
auto sCountdownLabel = XO ( " %s in: " ) . Format ( sAction ) ;
2016-03-30 22:46:15 +00:00
2018-01-05 20:41:36 +00:00
// Two column layout.
2019-02-12 22:54:52 +00:00
TimerProgressDialog : : MessageTable columns {
{
2019-12-08 03:37:02 +00:00
XO ( " Timer Recording completed. " ) ,
2019-02-12 22:54:52 +00:00
{ } ,
2019-12-08 03:37:02 +00:00
XO ( " Recording Saved: " ) ,
XO ( " Recording Exported: " ) ,
XO ( " Action after Timer Recording: " ) ,
2019-02-12 22:54:52 +00:00
} ,
{
{ } ,
{ } ,
2019-12-08 03:37:02 +00:00
( ( eCompletedActions & TR_ACTION_SAVED ) ? XO ( " Yes " ) : XO ( " No " ) ) ,
( ( eCompletedActions & TR_ACTION_EXPORTED ) ? XO ( " Yes " ) : XO ( " No " ) ) ,
2019-02-12 22:54:52 +00:00
sAction ,
} ,
} ;
2016-08-30 19:29:10 +00:00
2016-02-25 13:47:48 +00:00
wxDateTime dtNow = wxDateTime : : UNow ( ) ;
wxTimeSpan tsWait = wxTimeSpan ( 0 , 1 , 0 , 0 ) ;
wxDateTime dtActionTime = dtNow . Add ( tsWait ) ;
TimerProgressDialog dlgAction ( tsWait . GetMilliseconds ( ) . GetValue ( ) ,
2019-12-08 03:37:02 +00:00
XO ( " Audacity Timer Record - Waiting " ) ,
2018-01-05 20:41:36 +00:00
columns ,
2016-03-30 22:46:15 +00:00
pdlgHideStopButton | pdlgHideElapsedTime ,
sCountdownLabel ) ;
2016-02-25 13:47:48 +00:00
2016-12-24 15:43:25 +00:00
auto iUpdateResult = ProgressResult : : Success ;
2016-02-25 13:47:48 +00:00
bool bIsTime = false ;
2016-12-24 15:43:25 +00:00
while ( iUpdateResult = = ProgressResult : : Success & & ! bIsTime )
2016-02-25 13:47:48 +00:00
{
2018-01-05 20:41:36 +00:00
iUpdateResult = dlgAction . UpdateProgress ( ) ;
2018-04-22 11:30:44 +00:00
wxMilliSleep ( kTimerInterval ) ;
2016-02-25 13:47:48 +00:00
bIsTime = ( dtActionTime < = wxDateTime : : UNow ( ) ) ;
}
return iUpdateResult ;
}