30#include <wx/wxcrtvararg.h>
32#include <wx/calctrl.h>
33#include <wx/checkbox.h>
37#include <wx/datectrl.h>
38#include <wx/datetime.h>
57#if wxUSE_ACCESSIBILITY
91 return (dateTime.GetHour() * 3600.0) + (dateTime.GetMinute() * 60.0) + dateTime.GetSecond();
103#if wxUSE_ACCESSIBILITY
108 DatePickerCtrlAx(wxDatePickerCtrl * ctrl) :
WindowAccessible(ctrl), mCtrl(ctrl) {};
110 virtual ~ DatePickerCtrlAx() {};
113 wxAccStatus GetState(
int childId,
long *state)
override;
116 wxDatePickerCtrl *mCtrl;
120wxAccStatus DatePickerCtrlAx::GetState(
int WXUNUSED(childId),
long *state)
122 *state = wxACC_STATE_SYSTEM_FOCUSABLE;
156 wxDefaultSize, wxCAPTION)
161 m_DateTime_Start = wxDateTime::UNow();
163 gPrefs->Read(
wxT(
"/TimerRecord/LastDuration"), &seconds, 3600);
164 m_TimeSpan_Duration = wxTimeSpan::Seconds(seconds);
165 m_DateTime_End = m_DateTime_Start + m_TimeSpan_Duration;
167 m_pDatePickerCtrl_Start = NULL;
168 m_pTimeTextCtrl_Start = NULL;
170 m_pDatePickerCtrl_End = NULL;
171 m_pTimeTextCtrl_End = NULL;
173 m_pTimeTextCtrl_Duration = NULL;
176 m_bProjectAlreadySaved = bAlreadySaved;
179 this->PopulateOrExchange(
S);
183 m_pTimeTextCtrl_Duration->SetFocus();
184 m_pTimeTextCtrl_Duration->SetFieldFocus(3);
196 wxDateTime dateTime_UNow = wxDateTime::UNow();
209 long hr = (long)(dTime / 3600.0);
210 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
211 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
218 wxTimerEvent dummyTimerEvent;
219 this->
OnTimer(dummyTimerEvent);
235 long days = (long)(dTime / (24.0 * 3600.0));
237 dTime -= (double)days * 24.0 * 3600.0;
243 wxDateEvent dummyDateEvent;
251 long hr = (long)(dTime / 3600.0);
252 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
253 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
277 long days = (long)(dTime / (24.0 * 3600.0));
279 dTime -= (double)days * 24.0 * 3600.0;
285 wxDateEvent dummyDateEvent;
292 long hr = (long)(dTime / 3600.0);
293 long min = (long)((dTime - (hr * 3600.0)) / 60.0);
294 long sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
305 wxString fName =
SelectFile(FileNames::Operation::Export,
306 XO(
"Save Timer Recording As"),
311 wxFD_SAVE | wxRESIZE_BORDER,
319 if (wxFileExists(fName) && (projectFileIO.GetFileName() != fName)) {
322 XO(
"The selected file name could not be used\nfor Timer Recording because it \
323would overwrite another project.\nPlease try again and select an original name."),
324 XO(
"Error Saving Timer Recording Project"),
344 if (eExporter.SetAutoExportOptions()) {
372 if (!m_TimeSpan_Duration.IsPositive())
375 XO(
"Duration is zero. Nothing will be recorded."),
376 XO(
"Error in Duration"),
377 wxICON_EXCLAMATION | wxOK);
386 XO(
"Automatic Save path is invalid."),
387 XO(
"Error in Automatic Save"),
388 wxICON_EXCLAMATION | wxOK);
395 XO(
"Automatic Export path is invalid."),
396 XO(
"Error in Automatic Export"),
397 wxICON_EXCLAMATION | wxOK);
412 int iMinsLeft = projectManager.GetEstimatedRecordingMinsLeftOnDisk();
418 if (iMinsRecording >= iMinsLeft) {
421 auto sRemainingTime = projectManager.GetHoursMinsString(iMinsLeft);
422 auto sPlannedTime = projectManager.GetHoursMinsString(iMinsRecording);
426"You may not have enough free disk space to complete this Timer Recording, based on your current settings.\n\nDo you wish to continue?\n\nPlanned recording duration: %s\nRecording time remaining on disk: %s")
427 .Format( sPlannedTime, sRemainingTime );
432 XO(
"Timer Recording Disk Space Warning"),
433 wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
434 if (dlgMessage.ShowModal() != wxID_YES ) {
441 this->EndModal(wxID_OK);
444 gPrefs->Write(
wxT(
"/TimerRecord/LastDuration"), duration.ToLong());
485 gAudioIO->DelayActions(
true);
487 auto cleanup =
finally([gAudioIO]{ gAudioIO->DelayActions(
false); });
498 bool bIsRecording =
true;
506 XO(
"Recording start:") ,
508 XO(
"Recording end:") ,
510 XO(
"Automatic Save enabled:") ,
511 XO(
"Automatic Export enabled:") ,
512 XO(
"Action after Timer Recording:") ,
527 XO(
"Audacity Timer Record Progress"),
533 wxTimerEvent dummyTimerEvent;
534 this->
OnTimer(dummyTimerEvent);
539 using namespace std::chrono;
568 bool bSaveOK =
false;
569 bool bExportOK =
false;
571 int iOverriddenAction = iPostRecordAction;
572 bool bErrorOverride =
false;
580 bSaveOK = projectFileManager.Save();
589 bExportOK = e.ProcessFromTimerRecording(
597 if (bErrorOverride || bWasStopped) {
604 auto sMessage = (bWasStopped ?
XO(
"Timer Recording stopped.") :
605 XO(
"Timer Recording completed."));
609 sMessage =
XO(
"%s\n\nRecording saved: %s").Format(
612 sMessage =
XO(
"%s\n\nError saving recording.").Format( sMessage );
617 sMessage =
XO(
"%s\n\nRecording exported: %s").Format(
620 sMessage =
XO(
"%s\n\nError exporting recording.").Format( sMessage );
624 if (bErrorOverride) {
626 if ((iOverriddenAction != iPostRecordAction) &&
629 sMessage =
XO(
"%s\n\n'%s' has been canceled due to the error(s) noted above.").Format(
638 wxICON_EXCLAMATION | wxOK);
642 sMessage =
XO(
"%s\n\n'%s' has been canceled as the recording was stopped.").Format(
649 XO(
"Timer Recording"),
650 wxICON_INFORMATION | wxOK);
680 return iPostRecordAction;
685#if defined(__WXMSW__)
697 const wxDateTime::Tm tm(dt.GetTm());
702 st.wYear = (WXWORD)tm.year;
703 st.wMonth = (WXWORD)(tm.mon - wxDateTime::Jan + 1);
705 st.wDayOfWeek = st.wMinute = st.wSecond = st.wMilliseconds = 0;
707 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
714 len = ::GetDateFormat(LOCALE_USER_DEFAULT,
718 wxStringBuffer(s, len),
721 s +=
wxT(
" ") + dt.FormatTime();
728wxPrintf(
wxT(
"%s\n"), dt.Format());
729 return Verbatim( dt.FormatDate() +
wxT(
" ") + dt.FormatTime() );
733 wxWindow *wParent,
const int iID,
745 bool bAutoSave =
gPrefs->ReadBool(
"/TimerRecord/AutoSave",
false);
746 bool bAutoExport =
gPrefs->ReadBool(
"/TimerRecord/AutoExport",
false);
747 int iPostTimerRecordAction =
gPrefs->ReadLong(
"/TimerRecord/PostAction", 0);
752 auto strFormat =
XO(
"099 h 060 m 060 s");
754 auto strFormat1 =
XO(
"099 days 024 h 060 m 060 s");
756 S.StartMultiColumn(2, wxCENTER);
758 S.StartVerticalLay(
true);
766 S.StartStatic(
XO(
"Start Date and Time"),
true);
769 safenew wxDatePickerCtrl(
S.GetParent(),
774#if wxUSE_ACCESSIBILITY
777 S.Name(
XO(
"Start Date"))
785 .CustomFormat(strFormat)
787 S.Name(
XO(
"Start Time"))
792 S.StartStatic(
XO(
"End Date and Time"),
true);
795 safenew wxDatePickerCtrl(
S.GetParent(),
803#if wxUSE_ACCESSIBILITY
806 S.Name(
XO(
"End Date"))
814 .CustomFormat(strFormat)
816 S.Name(
XO(
"End Time"))
821 S.StartStatic(
XO(
"Duration"),
true);
828 .CustomFormat(strFormat1)
838 S.Name(
XO(
"Duration"))
845 S.StartVerticalLay(
true);
847 S.StartStatic(
XO(
"Automatic Save"),
true);
852 S.StartMultiColumn(3, wxEXPAND);
856 if (!sSaveValue.empty()) {
858 sInitialValue =
XO(
"Current Project");
860 S.AddPrompt(
XXO(
"Save Project As:"));
863 XO(
"Save Project As:"), sInitialValue);
872 S.StartStatic(
XO(
"Automatic Export"),
true);
875 S.StartMultiColumn(3, wxEXPAND);
877 S.AddPrompt(
XXO(
"Export Project As:"));
880 XO(
"Export Project As:"), {});
889 S.StartStatic(
XO(
"Options"),
true);
892 S.StartMultiColumn(1, wxEXPAND);
894 S.SetStretchyCol( 0 );
898 XO(
"Exit Audacity") ,
900 XO(
"Restart system") ,
901 XO(
"Shutdown system") ,
904 iPostTimerRecordAction
921 SetMinSize(GetSize());
937 hr = (long)(dTime / 3600.0);
938 min = (long)((dTime - (hr * 3600.0)) / 60.0);
939 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
946 hr = (long)(dTime / 3600.0);
947 min = (long)((dTime - (hr * 3600.0)) / 60.0);
948 sec = (long)(dTime - (hr * 3600.0) - (
min * 60.0));
965 gPrefs->Write(
"/TimerRecord/PostAction", iPostRecordAction);
1005 XO(
"Waiting to start recording at:") ,
1006 XO(
"Recording duration:") ,
1007 XO(
"Scheduled to stop at:") ,
1009 XO(
"Automatic Save enabled:") ,
1010 XO(
"Automatic Export enabled:") ,
1011 XO(
"Action after Timer Recording:") ,
1024 wxDateTime startWait_DateTime = wxDateTime::UNow();
1027 XO(
"Audacity Timer Record - Waiting for Start"),
1032 XO(
"Recording will commence in:"));
1035 bool bIsRecording =
false;
1039 using namespace std::chrono;
1043 return updateResult;
1049 ->GetString(iActionIndex) );
1054 auto sCountdownLabel =
XO(
"%s in:").Format( sAction );
1059 XO(
"Timer Recording completed.") ,
1061 XO(
"Recording Saved:") ,
1062 XO(
"Recording Exported:") ,
1063 XO(
"Action after Timer Recording:") ,
1075 wxDateTime dtNow = wxDateTime::UNow();
1076 wxTimeSpan tsWait = wxTimeSpan(0, 1, 0, 0);
1077 wxDateTime dtActionTime = dtNow.Add(tsWait);
1080 XO(
"Audacity Timer Record - Waiting"),
1086 bool bIsTime =
false;
1090 using namespace std::chrono;
1092 bIsTime = (dtActionTime <= wxDateTime::UNow());
1094 return iUpdateResult;
1111 auto &project = context.
project;
1122"Timer Recording cannot be used with more than one open project.\n\nPlease close any additional projects and try again."),
1123 XO(
"Timer Recording"),
1124 wxICON_INFORMATION | wxOK);
1132 if ((undoManager.UnsavedChanges()) &&
1136"Timer Recording cannot be used while you have unsaved changes.\n\nPlease save or close this project and try again."),
1137 XO(
"Timer Recording"),
1138 wxICON_INFORMATION | wxOK);
1148 const int numberOfSelected{ selectedTracks.numberOfSelected };
1149 const bool allSameRate{ selectedTracks.allSameRate };
1153 "for recording must all have the same sampling rate"),
1154 XO(
"Mismatched Sampling Rates"),
1155 wxICON_ERROR | wxCENTRE);
1161 if (existingTracks.empty()) {
1162 if (numberOfSelected > 0 && rateOfSelected !=
1165 "Too few tracks are selected for recording at this sample rate.\n"
1166 "(Audacity requires two channels at the same sample rate for\n"
1167 "each stereo track)"),
1168 XO(
"Too Few Compatible Tracks Selected"),
1169 wxICON_ERROR | wxCENTRE);
1184 &window, project, bProjectSaved);
1185 int modalResult = dialog.ShowModal();
1186 if (modalResult == wxID_CANCEL)
1196 bool bPreferNewTrack;
1197 gPrefs->Read(
"/GUI/PreferNewTrackRecord",&bPreferNewTrack,
false);
1198 if (bPreferNewTrack) {
1199 window.Rewind(
false);
1201 window.SkipEnd(
false);
1206 switch (iTimerRecordingOutcome) {
1224 wxTheApp->CallAfter( []{
1226 wxCommandEvent evt{ wxEVT_MENU, wxID_EXIT };
1227 wxTheApp->AddPendingEvent( evt );
1233 case POST_TIMER_RECORD_RESTART:
1236 system(
"shutdown /r /f /t 30");
1238 case POST_TIMER_RECORD_SHUTDOWN:
1241 system(
"shutdown /s /f /t 30");
1252 {
wxT(
"Transport/Basic/Record"),
1253 { OrderingHint::After,
wxT(
"Record2ndChoice") } },
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
const ReservedCommandFlag & AudioIONotBusyFlag()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
XXO("&Cut/Copy/Paste Toolbar")
const NumericConverterType & NumericConverterType_TIME()
const ReservedCommandFlag & CanStopAudioStreamFlag()
PropertiesOfSelected GetPropertiesOfSelected(const AudacityProject &proj)
an object holding per-project preferred sample rate
FilePath SelectFile(FileNames::Operation op, const TranslatableString &message, const FilePath &default_path, const FilePath &default_filename, const FileExtension &default_extension, const FileTypes &fileTypes, int flags, wxWindow *parent)
@ ID_AUTOEXPORTPATH_BUTTON
const int kSlowTimerInterval
constexpr auto kTimerInterval
static double wxDateTime_to_AudacityTime(wxDateTime &dateTime)
@ POST_TIMER_RECORD_CLOSE
@ POST_TIMER_RECORD_CANCEL
@ POST_TIMER_RECORD_CANCEL_WAIT
@ POST_TIMER_RECORD_NOTHING
TimerRecordCompletedActions
declares abstract base class Track, TrackList, and iterators over TrackList
static Settings & settings()
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Wrap wxMessageDialog so that caption IS translatable.
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
AudacityProject & project
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
FILES_API const FileType AudacityProjects
static FormatterContext EmptyContext()
static void ShowHelp(wxWindow *parent, const FilePath &localFileName, const URLString &remoteURL, bool bModal=false, bool alwaysDefaultBrowser=false)
void SetValue(double newValue)
std::vector< MessageColumn > MessageTable
void Stop(bool stopStream=true)
static WritableSampleTrackArray ChooseExistingRecordingTracks(AudacityProject &proj, bool selectedOnly, double targetRate=RATE_NOT_SELECTED)
static ProjectAudioManager & Get(AudacityProject &project)
void SetTimerRecordCancelled()
void OnRecord(bool altAppearance)
static ProjectFileIO & Get(AudacityProject &project)
const FilePath & GetFileName() const
static ProjectFileManager & Get(AudacityProject &project)
static ProjectHistory & Get(AudacityProject &project)
static ProjectManager & Get(AudacityProject &project)
void SetSkipSavePrompt(bool bSkip)
static ProjectRate & Get(AudacityProject &project)
static ProjectSettings & Get(AudacityProject &project)
static ProjectWindow & Get(AudacityProject &project)
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
ProgressResult UpdateProgress()
Dialog for Timer Record, i.e., timed or long recording.
void OnAutoSaveCheckBox_Change(wxCommandEvent &event)
wxDatePickerCtrl * m_pDatePickerCtrl_Start
NumericTextCtrl * m_pTimeTextCtrl_Duration
wxDateTime m_DateTime_End
void OnHelpButtonClick(wxCommandEvent &event)
void OnTimeText_Duration(wxCommandEvent &event)
NumericTextCtrl * m_pTimeTextCtrl_End
AudacityProject & mProject
TranslatableString GetDisplayDate(wxDateTime &dt)
wxButton * m_pTimerSavePathButtonCtrl
void EnableDisableAutoControls(bool bEnable, int iControlGoup)
wxCheckBox * m_pTimerAutoSaveCheckBoxCtrl
int ExecutePostRecordActions(bool bWasStopped)
void OnOK(wxCommandEvent &event)
void PopulateOrExchange(ShuttleGui &S)
NumericTextCtrl * m_pTimeTextCtrl_Start
wxTextCtrlWrapper * m_pTimerExportPathTextCtrl
wxDateTime m_DateTime_Start
bool m_bAutoExportEnabled
void OnAutoExportPathButton_Click(wxCommandEvent &event)
bool m_bProjectAlreadySaved
void OnAutoExportCheckBox_Change(wxCommandEvent &event)
void UpdateTextBoxControls()
bool TransferDataFromWindow() override
wxChoice * m_pTimerAfterCompleteChoiceCtrl
wxFileName m_fnAutoSaveFile
void OnDatePicker_End(wxDateEvent &event)
ProgressResult WaitForStart()
wxTextCtrlWrapper * NewPathControl(wxWindow *wParent, const int iID, const TranslatableString &sCaption, const TranslatableString &sValue)
int m_iAutoExportSubFormat
wxCheckBox * m_pTimerAutoExportCheckBoxCtrl
wxFileName m_fnAutoExportFile
void OnTimeText_Start(wxCommandEvent &event)
int m_iAutoExportFilterIndex
wxTimeSpan m_TimeSpan_Duration
wxDatePickerCtrl * m_pDatePickerCtrl_End
void OnAutoSavePathButton_Click(wxCommandEvent &event)
wxTextCtrlWrapper * m_pTimerSavePathTextCtrl
void OnTimeText_End(wxCommandEvent &event)
wxButton * m_pTimerExportPathButtonCtrl
void OnTimer(wxTimerEvent &event)
int RunWaitDialog()
Runs the wait for start dialog. Returns false if the user clicks stop.
void OnDatePicker_Start(wxDateEvent &event)
ProgressResult PreActionDelay(int iActionIndex, TimerRecordCompletedActions eCompletedActions)
auto Any() -> TrackIterRange< TrackType >
static TrackList & Get(AudacityProject &project)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
static UndoManager & Get(AudacityProject &project)
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void SetReadOnly(bool readonly=true)
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
CommandManager::Options Options
double GetRate(const Track &track)
void OnTimerRecord(const CommandContext &context)