Audacity  3.0.3
Classes | Public Types | Public Member Functions | Static Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
ProjectFileIO Class Referencefinal

Object associated with a project that manages reading and writing of Audacity project file formats, and autosave. More...

#include <ProjectFileIO.h>

Inheritance diagram for ProjectFileIO:
[legend]
Collaboration diagram for ProjectFileIO:
[legend]

Classes

class  BackupProject
 

Public Types

using ExecCB = std::function< int(int cols, char **vals, char **names)>
 

Public Member Functions

 ProjectFileIO (AudacityProject &project)
 
 ProjectFileIO (const ProjectFileIO &) PROHIBITED
 
ProjectFileIOoperator= (const ProjectFileIO &) PROHIBITED
 
 ~ProjectFileIO ()
 
void SetProjectTitle (int number=-1)
 
const FilePathGetFileName () const
 
void SetFileName (const FilePath &fileName)
 
bool IsModified () const
 
bool IsTemporary () const
 
bool IsRecovered () const
 
bool AutoSave (bool recording=false)
 
bool AutoSaveDelete (sqlite3 *db=nullptr)
 
bool OpenProject ()
 
bool CloseProject ()
 
bool ReopenProject ()
 
bool LoadProject (const FilePath &fileName, bool ignoreAutosave)
 
bool UpdateSaved (const TrackList *tracks=nullptr)
 
bool SaveProject (const FilePath &fileName, const TrackList *lastSaved)
 
bool SaveCopy (const FilePath &fileName)
 
wxLongLong GetFreeDiskSpace () const
 
int64_t GetBlockUsage (SampleBlockID blockid)
 
int64_t GetCurrentUsage (const std::vector< const TrackList * > &trackLists) const
 
int64_t GetTotalUsage ()
 
void ShowError (const BasicUI::WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage)
 Displays an error dialog with a button that offers help. More...
 
const TranslatableStringGetLastError () const
 
const TranslatableStringGetLibraryError () const
 
int GetLastErrorCode () const
 
const wxString & GetLastLog () const
 
void SetBypass ()
 
void Compact (const std::vector< const TrackList * > &tracks, bool force=false)
 
bool WasCompacted ()
 
bool HadUnused ()
 
bool DeleteBlocks (const BlockIDs &blockids, bool complement)
 
bool HasConnection () const
 Return true if a connection is now open. More...
 
DBConnectionGetConnection ()
 Return a reference to a connection, creating it as needed on demand; throw on failure. More...
 
wxString GenerateDoc ()
 Return a strings representation of the active project XML doc. More...
 
- Public Member Functions inherited from ClientData::Base
virtual ~Base ()
 
- Public Member Functions inherited from XMLTagHandler
 XMLTagHandler ()
 
virtual ~XMLTagHandler ()
 
virtual void HandleXMLEndTag (const wxChar *WXUNUSED(tag))
 
virtual void HandleXMLContent (const wxString &WXUNUSED(content))
 
bool ReadXMLTag (const char *tag, const char **attrs)
 
void ReadXMLEndTag (const char *tag)
 
void ReadXMLContent (const char *s, int len)
 
XMLTagHandlerReadXMLChild (const char *tag)
 

Static Public Member Functions

static bool InitializeSQL ()
 
static ProjectFileIOGet (AudacityProject &project)
 
static const ProjectFileIOGet (const AudacityProject &project)
 
static int64_t GetDiskUsage (DBConnection &conn, SampleBlockID blockid)
 
static bool RemoveProject (const FilePath &filename)
 Remove any files associated with a project at given path; return true if successful. More...
 

Private Member Functions

bool RenameOrWarn (const FilePath &src, const FilePath &dst)
 Rename a file or put up appropriate warning message. More...
 
bool MoveProject (const FilePath &src, const FilePath &dst)
 
void OnCheckpointFailure ()
 
void WriteXMLHeader (XMLWriter &xmlFile) const
 
void WriteXML (XMLWriter &xmlFile, bool recording=false, const TrackList *tracks=nullptr)
 
bool HandleXMLTag (const wxChar *tag, const wxChar **attrs) override
 
XMLTagHandlerHandleXMLChild (const wxChar *tag) override
 
void UpdatePrefs () override
 
int Exec (const char *query, const ExecCB &callback)
 
sqlite3 * DB ()
 
bool OpenConnection (FilePath fileName={})
 
bool CloseConnection ()
 
void SaveConnection ()
 
void DiscardConnection ()
 
void RestoreConnection ()
 
void UseConnection (Connection &&conn, const FilePath &filePath)
 
bool Query (const char *sql, const ExecCB &callback)
 
bool GetValue (const char *sql, wxString &value)
 
bool GetBlob (const char *sql, wxMemoryBuffer &buffer)
 
bool CheckVersion ()
 
bool InstallSchema (sqlite3 *db, const char *schema="main")
 
bool UpgradeSchema ()
 
bool WriteDoc (const char *table, const ProjectSerializer &autosave, const char *schema="main")
 
bool CopyTo (const FilePath &destpath, const TranslatableString &msg, bool isTemporary, bool prune=false, const std::vector< const TrackList * > &tracks={})
 
void SetError (const TranslatableString &msg, const TranslatableString &libraryError={}, int errorCode={})
 Just set stored errors. More...
 
void SetDBError (const TranslatableString &msg, const TranslatableString &libraryError={}, int errorCode=-1)
 Set stored errors and write to log; and default libraryError to what database library reports. More...
 
bool ShouldCompact (const std::vector< const TrackList * > &tracks)
 
ConnectionCurrConn ()
 
- Private Member Functions inherited from PrefsListener
 PrefsListener ()
 
virtual ~PrefsListener ()
 
virtual void UpdateSelectedPrefs (int id)
 

Static Private Member Functions

static const std::vector< wxString > & AuxiliaryFileSuffixes ()
 
static FilePath SafetyFileName (const FilePath &src)
 Generate a name for short-lived backup project files from an existing project. More...
 
static void InSet (sqlite3_context *context, int argc, sqlite3_value **argv)
 
static unsigned int get2 (const unsigned char *ptr)
 
static unsigned int get4 (const unsigned char *ptr)
 
static int get_varint (const unsigned char *ptr, int64_t *out)
 
- Static Private Member Functions inherited from PrefsListener
static void Broadcast (int id=0)
 Call this static function to notify all PrefsListener objects. More...
 

Private Attributes

AudacityProjectmProject
 
std::shared_ptr< DBConnectionErrorsmpErrors
 
FilePath mFileName
 
bool mRecovered
 
bool mModified
 
bool mTemporary
 
bool mWasCompacted
 
bool mHadUnused
 
Connection mPrevConn
 
FilePath mPrevFileName
 
bool mPrevTemporary
 

Detailed Description

Object associated with a project that manages reading and writing of Audacity project file formats, and autosave.

Definition at line 57 of file ProjectFileIO.h.

Member Typedef Documentation

◆ ExecCB

using ProjectFileIO::ExecCB = std::function<int(int cols, char **vals, char **names)>

Definition at line 193 of file ProjectFileIO.h.

Constructor & Destructor Documentation

◆ ProjectFileIO() [1/2]

ProjectFileIO::ProjectFileIO ( AudacityProject project)
explicit

Definition at line 277 of file ProjectFileIO.cpp.

278  : mProject{ project }
279  , mpErrors{ std::make_shared<DBConnectionErrors>() }
280 {
281  mPrevConn = nullptr;
282 
283  mRecovered = false;
284  mModified = false;
285  mTemporary = true;
286 
287  UpdatePrefs();
288 
289  // Make sure there is plenty of space for Sqlite files
290  wxLongLong freeSpace = 0;
291 
292  auto path = TempDirectory::TempDir();
293  if (wxGetDiskSpace(path, NULL, &freeSpace)) {
294  if (freeSpace < wxLongLong(wxLL(100 * 1048576))) {
295  auto volume = FileNames::AbbreviatePath( path );
296  /* i18n-hint: %s will be replaced by the drive letter (on Windows) */
298  XO("Warning"),
299  XO("There is very little free disk space left on %s\n"
300  "Please select a bigger temporary directory location in\n"
301  "Directories Preferences.").Format( volume ),
302  "Error:_Disk_full_or_not_writable"
303  );
304  }
305  }
306 }

◆ ProjectFileIO() [2/2]

ProjectFileIO::ProjectFileIO ( const ProjectFileIO )

◆ ~ProjectFileIO()

ProjectFileIO::~ProjectFileIO ( )

Definition at line 308 of file ProjectFileIO.cpp.

309 {
310 }

Member Function Documentation

◆ AutoSave()

bool ProjectFileIO::AutoSave ( bool  recording = false)

Definition at line 1689 of file ProjectFileIO.cpp.

1690 {
1691  ProjectSerializer autosave;
1692  WriteXMLHeader(autosave);
1693  WriteXML(autosave, recording);
1694 
1695  if (WriteDoc("autosave", autosave))
1696  {
1697  mModified = true;
1698  return true;
1699  }
1700 
1701  return false;
1702 }

References mModified, WriteDoc(), WriteXML(), and WriteXMLHeader().

Referenced by anonymous_namespace{ProjectHistory.cpp}::AutoSaveOrThrow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AutoSaveDelete()

bool ProjectFileIO::AutoSaveDelete ( sqlite3 *  db = nullptr)

Definition at line 1704 of file ProjectFileIO.cpp.

1705 {
1706  int rc;
1707 
1708  if (!db)
1709  {
1710  db = DB();
1711  }
1712 
1713  rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
1714  if (rc != SQLITE_OK)
1715  {
1716  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1717  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::AutoSaveDelete");
1718 
1719  SetDBError(
1720  XO("Failed to remove the autosave information from the project file.")
1721  );
1722  return false;
1723  }
1724 
1725  mModified = false;
1726 
1727  return true;
1728 }

References ADD_EXCEPTION_CONTEXT, DB(), mModified, SetDBError(), and XO.

Referenced by Compact(), SaveProject(), and UpdateSaved().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AuxiliaryFileSuffixes()

const std::vector< wxString > & ProjectFileIO::AuxiliaryFileSuffixes ( )
staticprivate

Strings like -wal that may be appended to main project name to get other files created by the database system

Definition at line 1133 of file ProjectFileIO.cpp.

1134 {
1135  static const std::vector<wxString> strings {
1136  "-wal",
1137 #ifndef NO_SHM
1138  "-shm",
1139 #endif
1140  };
1141  return strings;
1142 }

Referenced by MoveProject(), RemoveProject(), SafetyFileName(), and ProjectFileIO::BackupProject::~BackupProject().

Here is the caller graph for this function:

◆ CheckVersion()

bool ProjectFileIO::CheckVersion ( )
private

Definition at line 633 of file ProjectFileIO.cpp.

634 {
635  auto db = DB();
636  int rc;
637 
638  // Install our schema if this is an empty DB
639  wxString result;
640  if (!GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';", result))
641  {
642  // Bug 2718 workaround for a better error message:
643  // If at this point we get SQLITE_CANTOPEN, then the directory is read-only
644  if (GetLastErrorCode() == SQLITE_CANTOPEN)
645  {
646  SetError(
647  /* i18n-hint: An error message. */
648  XO("Project is in a read only directory\n(Unable to create the required temporary files)"),
650  );
651  }
652 
653  return false;
654  }
655 
656  // If the return count is zero, then there are no tables defined, so this
657  // must be a new project file.
658  if (wxStrtol<char **>(result, nullptr, 10) == 0)
659  {
660  return InstallSchema(db);
661  }
662 
663  // Check for our application ID
664  if (!GetValue("PRAGMA application_ID;", result))
665  {
666  return false;
667  }
668 
669  // It's a database that SQLite recognizes, but it's not one of ours
670  if (wxStrtoul<char **>(result, nullptr, 10) != ProjectFileID)
671  {
672  SetError(XO("This is not an Audacity project file"));
673  return false;
674  }
675 
676  // Get the project file version
677  if (!GetValue("PRAGMA user_version;", result))
678  {
679  return false;
680  }
681 
682  long version = wxStrtol<char **>(result, nullptr, 10);
683 
684  // Project file version is higher than ours. We will refuse to
685  // process it since we can't trust anything about it.
686  if (version > ProjectFileVersion)
687  {
688  SetError(
689  XO("This project was created with a newer version of Audacity.\n\nYou will need to upgrade to open it.")
690  );
691  return false;
692  }
693 
694  // Project file is older than ours, ask the user if it's okay to
695  // upgrade.
696  if (version < ProjectFileVersion)
697  {
698  return UpgradeSchema();
699  }
700 
701  return true;
702 }

References DB(), GetLastErrorCode(), GetLibraryError(), GetValue(), InstallSchema(), ProjectFileID, ProjectFileVersion, SetError(), UpgradeSchema(), and XO.

Referenced by OpenConnection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CloseConnection()

bool ProjectFileIO::CloseConnection ( )
private

Definition at line 415 of file ProjectFileIO.cpp.

416 {
417  auto &curConn = CurrConn();
418  if (!curConn)
419  return false;
420 
421  if (!curConn->Close())
422  {
423  return false;
424  }
425  curConn.reset();
426 
427  SetFileName({});
428 
429  return true;
430 }

References CurrConn(), and SetFileName().

Referenced by CloseProject(), Compact(), OpenConnection(), ReopenProject(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CloseProject()

bool ProjectFileIO::CloseProject ( )

Definition at line 2168 of file ProjectFileIO.cpp.

2169 {
2170  auto &currConn = CurrConn();
2171  if (!currConn)
2172  {
2173  wxLogDebug("Closing project with no database connection");
2174  return true;
2175  }
2176 
2177  // Save the filename since CloseConnection() will clear it
2178  wxString filename = mFileName;
2179 
2180  // Not much we can do if this fails. The user will simply get
2181  // the recovery dialog upon next restart.
2182  if (CloseConnection())
2183  {
2184  // If this is a temporary project, we no longer want to keep the
2185  // project file.
2186  if (IsTemporary())
2187  {
2188  // This is just a safety check.
2189  wxFileName temp(TempDirectory::TempDir(), wxT(""));
2190  wxFileName file(filename);
2191  file.SetFullName(wxT(""));
2192  if (file == temp)
2193  RemoveProject(filename);
2194  }
2195  }
2196 
2197  return true;
2198 }

References CloseConnection(), CurrConn(), IsTemporary(), mFileName, RemoveProject(), and TempDirectory::TempDir().

Referenced by SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Compact()

void ProjectFileIO::Compact ( const std::vector< const TrackList * > &  tracks,
bool  force = false 
)

Definition at line 1308 of file ProjectFileIO.cpp.

1310 {
1311  // Haven't compacted yet
1312  mWasCompacted = false;
1313 
1314  // Assume we have unused blocks until we find out otherwise. That way cleanup
1315  // at project close time will still occur.
1316  mHadUnused = true;
1317 
1318  // If forcing compaction, bypass inspection.
1319  if (!force)
1320  {
1321  // Don't compact if this is a temporary project or if it's determined there are not
1322  // enough unused blocks to make it worthwhile.
1323  if (IsTemporary() || !ShouldCompact(tracks))
1324  {
1325  // Delete the AutoSave doc it if exists
1326  if (IsModified())
1327  {
1328  // PRL: not clear what to do if the following fails, but the worst should
1329  // be, the project may reopen in its present state as a recovery file, not
1330  // at the last saved state.
1331  // REVIEW: Could the autosave file be corrupt though at that point, and so
1332  // prevent recovery?
1333  // LLL: I believe Paul is correct since it's deleted with a single SQLite
1334  // transaction. The next time the file opens will just invoke recovery.
1335  (void) AutoSaveDelete();
1336  }
1337 
1338  return;
1339  }
1340  }
1341 
1342  wxString origName = mFileName;
1343  wxString backName = origName + "_compact_back";
1344  wxString tempName = origName + "_compact_temp";
1345 
1346  // Copy the original database to a new database. Only prune sample blocks if
1347  // we have a tracklist.
1348  // REVIEW: Compact can fail on the CopyTo with no error messages. That's OK?
1349  // LLL: We could display an error message or just ignore the failure and allow
1350  // the file to be compacted the next time it's saved.
1351  if (CopyTo(tempName, XO("Compacting project"), IsTemporary(), !tracks.empty(), tracks))
1352  {
1353  // Must close the database to rename it
1354  if (CloseConnection())
1355  {
1356  // Only use the new file if it is actually smaller than the original.
1357  //
1358  // If the original file doesn't have anything to compact (original and new
1359  // are basically identical), the file could grow by a few pages because of
1360  // differences in how SQLite constructs the b-tree.
1361  //
1362  // In this case, just toss the new file and continue to use the original.
1363  //
1364  // Also, do this after closing the connection so that the -wal file
1365  // gets cleaned up.
1366  if (wxFileName::GetSize(tempName) < wxFileName::GetSize(origName))
1367  {
1368  // Rename the original to backup
1369  if (wxRenameFile(origName, backName))
1370  {
1371  // Rename the temporary to original
1372  if (wxRenameFile(tempName, origName))
1373  {
1374  // Open the newly compacted original file
1375  if (OpenConnection(origName))
1376  {
1377  // Remove the old original file
1378  if (!wxRemoveFile(backName))
1379  {
1380  // Just log the error, nothing can be done to correct it
1381  // and WX should have logged another message showing the
1382  // system error code.
1383  wxLogWarning(wxT("Compaction failed to delete backup %s"), backName);
1384  }
1385 
1386  // Remember that we compacted
1387  mWasCompacted = true;
1388 
1389  return;
1390  }
1391  else
1392  {
1393  wxLogWarning(wxT("Compaction failed to open new project %s"), origName);
1394  }
1395 
1396  if (!wxRenameFile(origName, tempName))
1397  {
1398  wxLogWarning(wxT("Compaction failed to rename orignal %s to temp %s"),
1399  origName, tempName);
1400  }
1401  }
1402  else
1403  {
1404  wxLogWarning(wxT("Compaction failed to rename temp %s to orig %s"),
1405  origName, tempName);
1406  }
1407 
1408  if (!wxRenameFile(backName, origName))
1409  {
1410  wxLogWarning(wxT("Compaction failed to rename back %s to orig %s"),
1411  backName, origName);
1412  }
1413  }
1414  else
1415  {
1416  wxLogWarning(wxT("Compaction failed to rename orig %s to back %s"),
1417  backName, origName);
1418  }
1419  }
1420 
1421  if (!OpenConnection(origName))
1422  {
1423  wxLogWarning(wxT("Compaction failed to reopen %s"), origName);
1424  }
1425  }
1426 
1427  // Did not achieve any real compaction
1428  // RemoveProject not needed for what was an attached database
1429  if (!wxRemoveFile(tempName))
1430  {
1431  // Just log the error, nothing can be done to correct it
1432  // and WX should have logged another message showing the
1433  // system error code.
1434  wxLogWarning(wxT("Failed to delete temporary file...ignoring"));
1435  }
1436  }
1437 
1438  return;
1439 }

References AutoSaveDelete(), CloseConnection(), CopyTo(), IsModified(), IsTemporary(), mFileName, mHadUnused, mWasCompacted, OpenConnection(), ShouldCompact(), and XO.

Referenced by SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CopyTo()

bool ProjectFileIO::CopyTo ( const FilePath destpath,
const TranslatableString msg,
bool  isTemporary,
bool  prune = false,
const std::vector< const TrackList * > &  tracks = {} 
)
private
Parameters
tracksFirst track list (or if none, then the project's track list) are tracks to write into document blob; That list, plus any others, contain tracks whose sample blocks must be kept

Definition at line 820 of file ProjectFileIO.cpp.

825 {
826  auto pConn = CurrConn().get();
827  if (!pConn)
828  return false;
829 
830  // Get access to the active tracklist
831  auto pProject = &mProject;
832 
833  SampleBlockIDSet blockids;
834 
835  // Collect all active blockids
836  if (prune)
837  {
838  for (auto trackList : tracks)
839  if (trackList)
840  InspectBlocks( *trackList, {}, &blockids );
841  }
842  // Collect ALL blockids
843  else
844  {
845  auto cb = [&blockids](int cols, char **vals, char **){
846  SampleBlockID blockid;
847  wxString{ vals[0] }.ToLongLong(&blockid);
848  blockids.insert(blockid);
849  return 0;
850  };
851 
852  if (!Query("SELECT blockid FROM sampleblocks;", cb))
853  {
854  // Error message already captured.
855  return false;
856  }
857  }
858 
859  // Create the project doc
860  ProjectSerializer doc;
861  WriteXMLHeader(doc);
862  WriteXML(doc, false, tracks.empty() ? nullptr : tracks[0]);
863 
864  auto db = DB();
865  Connection destConn = nullptr;
866  bool success = false;
867  int rc = SQLITE_OK;
869 
870  // Cleanup in case things go awry
871  auto cleanup = finally([&]
872  {
873  if (!success)
874  {
875  if (destConn)
876  {
877  destConn->Close();
878  destConn = nullptr;
879  }
880 
881  // Rollback transaction in case one was active.
882  // If this fails (probably due to memory or disk space), the transaction will
883  // (presumably) stil be active, so further updates to the project file will
884  // fail as well. Not really much we can do about it except tell the user.
885  auto result = sqlite3_exec(db, "ROLLBACK;", nullptr, nullptr, nullptr);
886 
887  // Only capture the error if there wasn't a previous error
888  if (result != SQLITE_OK && (rc == SQLITE_DONE || rc == SQLITE_OK))
889  {
890  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
892  "sqlite3.context", "ProjectGileIO::CopyTo.cleanup");
893 
894  SetDBError(
895  XO("Failed to rollback transaction during import")
896  );
897  }
898 
899  // And detach the outbound DB in case (if it's attached). Don't check for
900  // errors since it may not be attached. But, if it is and the DETACH fails,
901  // subsequent CopyTo() actions will fail until Audacity is relaunched.
902  sqlite3_exec(db, "DETACH DATABASE outbound;", nullptr, nullptr, nullptr);
903 
904  // RemoveProject not necessary to clean up attached database
905  wxRemoveFile(destpath);
906  }
907  });
908 
909  // Attach the destination database
910  wxString sql;
911  wxString dbName = destpath;
912  // Bug 2793: Quotes in name need escaping for sqlite3.
913  dbName.Replace( "'", "''");
914  sql.Printf("ATTACH DATABASE '%s' AS outbound;", dbName.ToUTF8());
915 
916  rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
917  if (rc != SQLITE_OK)
918  {
919  SetDBError(
920  XO("Unable to attach destination database")
921  );
922  return false;
923  }
924 
925  // Ensure attached DB connection gets configured
926  //
927  // NOTE: Between the above attach and setting the mode here, a normal DELETE
928  // mode journal will be used and will briefly appear in the filesystem.
929  if ( pConn->FastMode("outbound") != SQLITE_OK)
930  {
931  SetDBError(
932  XO("Unable to switch to fast journaling mode")
933  );
934 
935  return false;
936  }
937 
938  // Install our schema into the new database
939  if (!InstallSchema(db, "outbound"))
940  {
941  // Message already set
942  return false;
943  }
944 
945  {
946  // Ensure statement gets cleaned up
947  sqlite3_stmt *stmt = nullptr;
948  auto cleanup = finally([&]
949  {
950  if (stmt)
951  {
952  // No need to check return code
953  sqlite3_finalize(stmt);
954  }
955  });
956 
957  // Prepare the statement only once
958  rc = sqlite3_prepare_v2(db,
959  "INSERT INTO outbound.sampleblocks"
960  " SELECT * FROM main.sampleblocks"
961  " WHERE blockid = ?;",
962  -1,
963  &stmt,
964  nullptr);
965  if (rc != SQLITE_OK)
966  {
967  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
969  "sqlite3.context", "ProjectGileIO::CopyTo.prepare");
970 
971  SetDBError(
972  XO("Unable to prepare project file command:\n\n%s").Format(sql)
973  );
974  return false;
975  }
976 
977  /* i18n-hint: This title appears on a dialog that indicates the progress
978  in doing something.*/
979  ProgressDialog progress(XO("Progress"), msg, pdlgHideStopButton);
981 
982  wxLongLong_t count = 0;
983  wxLongLong_t total = blockids.size();
984 
985  // Start a transaction. Since we're running without a journal,
986  // this really doesn't provide rollback. It just prevents SQLite
987  // from auto committing after each step through the loop.
988  //
989  // Also note that we will have an open transaction if we fail
990  // while copying the blocks. This is fine since we're just going
991  // to delete the database anyway.
992  sqlite3_exec(db, "BEGIN;", nullptr, nullptr, nullptr);
993 
994  // Copy sample blocks from the main DB to the outbound DB
995  for (auto blockid : blockids)
996  {
997  // Bind statement parameters
998  rc = sqlite3_bind_int64(stmt, 1, blockid);
999  if (rc != SQLITE_OK)
1000  {
1001  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1003  "sqlite3.context", "ProjectGileIO::CopyTo.bind");
1004 
1005  SetDBError(
1006  XO("Failed to bind SQL parameter")
1007  );
1008 
1009  return false;
1010  }
1011 
1012  // Process it
1013  rc = sqlite3_step(stmt);
1014  if (rc != SQLITE_DONE)
1015  {
1016  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1018  "sqlite3.context", "ProjectGileIO::CopyTo.step");
1019 
1020  SetDBError(
1021  XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql)
1022  );
1023  return false;
1024  }
1025 
1026  // Reset statement to beginning
1027  if (sqlite3_reset(stmt) != SQLITE_OK)
1028  {
1029  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1031  "sqlite3.context", "ProjectGileIO::CopyTo.reset");
1032 
1034  }
1035 
1036  result = progress.Update(++count, total);
1037  if (result != ProgressResult::Success)
1038  {
1039  // Note that we're not setting success, so the finally
1040  // block above will take care of cleaning up
1041  return false;
1042  }
1043  }
1044 
1045  // Write the doc.
1046  //
1047  // If we're compacting a temporary project (user initiated from the File
1048  // menu), then write the doc to the "autosave" table since temporary
1049  // projects do not have a "project" doc.
1050  if (!WriteDoc(isTemporary ? "autosave" : "project", doc, "outbound"))
1051  {
1052  return false;
1053  }
1054 
1055  // See BEGIN above...
1056  sqlite3_exec(db, "COMMIT;", nullptr, nullptr, nullptr);
1057  }
1058 
1059  // Detach the destination database
1060  rc = sqlite3_exec(db, "DETACH DATABASE outbound;", nullptr, nullptr, nullptr);
1061  if (rc != SQLITE_OK)
1062  {
1063  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1064  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::CopyTo::detach");
1065 
1066  SetDBError(
1067  XO("Destination project could not be detached")
1068  );
1069 
1070  return false;
1071  }
1072 
1073  // Tell cleanup everything is good to go
1074  success = true;
1075 
1076  return true;
1077 }

References ADD_EXCEPTION_CONTEXT, CurrConn(), DB(), InspectBlocks(), InstallSchema(), mProject, pdlgHideStopButton, Query(), SetDBError(), BasicUI::Success, THROW_INCONSISTENCY_EXCEPTION, ProgressDialog::Update(), WriteDoc(), WriteXML(), WriteXMLHeader(), and XO.

Referenced by Compact(), SaveCopy(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CurrConn()

Connection & ProjectFileIO::CurrConn ( )
private

Definition at line 1127 of file ProjectFileIO.cpp.

1128 {
1129  auto &connectionPtr = ConnectionPtr::Get( mProject );
1130  return connectionPtr.mpConnection;
1131 }

References ConnectionPtr::Get(), and mProject.

Referenced by CloseConnection(), CloseProject(), CopyTo(), GetBlockUsage(), GetConnection(), GetTotalUsage(), OpenConnection(), RestoreConnection(), SaveConnection(), SetBypass(), SetDBError(), SetError(), and UseConnection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DB()

sqlite3 * ProjectFileIO::DB ( )
private

Definition at line 348 of file ProjectFileIO.cpp.

349 {
350  return GetConnection().DB();
351 }

References DBConnection::DB(), and GetConnection().

Referenced by AutoSaveDelete(), CheckVersion(), CopyTo(), DeleteBlocks(), Exec(), GetBlob(), and WriteDoc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DeleteBlocks()

bool ProjectFileIO::DeleteBlocks ( const BlockIDs blockids,
bool  complement 
)

Definition at line 744 of file ProjectFileIO.cpp.

745 {
746  auto db = DB();
747  int rc;
748 
749  auto cleanup = finally([&]
750  {
751  // Remove our function, whether it was successfully defined or not.
752  sqlite3_create_function(db, "inset", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, nullptr, nullptr, nullptr);
753  });
754 
755  // Add the function used to verify each row's blockid against the set of active blockids
756  const void *p = &blockids;
757  rc = sqlite3_create_function(db, "inset", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, const_cast<void*>(p), InSet, nullptr, nullptr);
758  if (rc != SQLITE_OK)
759  {
760  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
761  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::DeleteBlocks::create_function");
762 
763  /* i18n-hint: An error message. Don't translate inset or blockids.*/
764  SetDBError(XO("Unable to add 'inset' function (can't verify blockids)"));
765  return false;
766  }
767 
768  // Delete all rows in the set, or not in it
769  // This is the first command that writes to the database, and so we
770  // do more informative error reporting than usual, if it fails.
771  auto sql = wxString::Format(
772  "DELETE FROM sampleblocks WHERE %sinset(blockid);",
773  complement ? "NOT " : "" );
774  rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
775  if (rc != SQLITE_OK)
776  {
777  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql.ToStdString());
778  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
779  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob");
780 
781  if( rc==SQLITE_READONLY)
782  /* i18n-hint: An error message. Don't translate blockfiles.*/
783  SetDBError(XO("Project is read only\n(Unable to work with the blockfiles)"));
784  else if( rc==SQLITE_LOCKED)
785  /* i18n-hint: An error message. Don't translate blockfiles.*/
786  SetDBError(XO("Project is locked\n(Unable to work with the blockfiles)"));
787  else if( rc==SQLITE_BUSY)
788  /* i18n-hint: An error message. Don't translate blockfiles.*/
789  SetDBError(XO("Project is busy\n(Unable to work with the blockfiles)"));
790  else if( rc==SQLITE_CORRUPT)
791  /* i18n-hint: An error message. Don't translate blockfiles.*/
792  SetDBError(XO("Project is corrupt\n(Unable to work with the blockfiles)"));
793  else if( rc==SQLITE_PERM)
794  /* i18n-hint: An error message. Don't translate blockfiles.*/
795  SetDBError(XO("Some permissions issue\n(Unable to work with the blockfiles)"));
796  else if( rc==SQLITE_IOERR)
797  /* i18n-hint: An error message. Don't translate blockfiles.*/
798  SetDBError(XO("A disk I/O error\n(Unable to work with the blockfiles)"));
799  else if( rc==SQLITE_AUTH)
800  /* i18n-hint: An error message. Don't translate blockfiles.*/
801  SetDBError(XO("Not authorized\n(Unable to work with the blockfiles)"));
802  else
803  /* i18n-hint: An error message. Don't translate blockfiles.*/
804  SetDBError(XO("Unable to work with the blockfiles"));
805 
806  return false;
807  }
808 
809  // Mark the project recovered if we deleted any rows
810  int changes = sqlite3_changes(db);
811  if (changes > 0)
812  {
813  wxLogInfo(XO("Total orphan blocks deleted %d").Translation(), changes);
814  mRecovered = true;
815  }
816 
817  return true;
818 }

References ADD_EXCEPTION_CONTEXT, DB(), InSet(), mRecovered, SetDBError(), and XO.

Referenced by LoadProject(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ DiscardConnection()

void ProjectFileIO::DiscardConnection ( )
private

Definition at line 447 of file ProjectFileIO.cpp.

448 {
449  if (mPrevConn)
450  {
451  if (!mPrevConn->Close())
452  {
453  // Store an error message
454  SetDBError(
455  XO("Failed to discard connection")
456  );
457  }
458 
459  // If this is a temporary project, we no longer want to keep the
460  // project file.
461  if (mPrevTemporary)
462  {
463  // This is just a safety check.
464  wxFileName temp(TempDirectory::TempDir(), wxT(""));
465  wxFileName file(mPrevFileName);
466  file.SetFullName(wxT(""));
467  if (file == temp)
468  {
470  {
471  wxLogMessage("Failed to remove temporary project %s", mPrevFileName);
472  }
473  }
474  }
475  mPrevConn = nullptr;
476  mPrevFileName.clear();
477  }
478 }

References mPrevConn, mPrevFileName, mPrevTemporary, RemoveProject(), SetDBError(), TempDirectory::TempDir(), and XO.

Referenced by LoadProject(), and SaveConnection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Exec()

int ProjectFileIO::Exec ( const char *  query,
const ExecCB callback 
)
private

Definition at line 521 of file ProjectFileIO.cpp.

522 {
523  char *errmsg = nullptr;
524 
525  const void *ptr = &callback;
526  int rc = sqlite3_exec(DB(), query, ExecCallback,
527  const_cast<void*>(ptr), &errmsg);
528 
529  if (rc != SQLITE_ABORT && errmsg)
530  {
531  ADD_EXCEPTION_CONTEXT("sqlite3.query", query);
532  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
533 
534  SetDBError(
535  XO("Failed to execute a project file command:\n\n%s").Format(query),
536  Verbatim(errmsg),
537  rc
538  );
539  }
540  if (errmsg)
541  {
542  sqlite3_free(errmsg);
543  }
544 
545  return rc;
546 }

References ADD_EXCEPTION_CONTEXT, DB(), ExecCallback(), SetDBError(), Verbatim(), and XO.

Referenced by Query().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GenerateDoc()

wxString ProjectFileIO::GenerateDoc ( )

Return a strings representation of the active project XML doc.

Definition at line 338 of file ProjectFileIO.cpp.

339 {
340  auto &trackList = TrackList::Get( mProject );
341 
342  XMLStringWriter doc;
343  WriteXMLHeader(doc);
344  WriteXML(doc, false, trackList.empty() ? nullptr : &trackList);
345  return doc;
346 }

References TrackList::Get(), mProject, WriteXML(), and WriteXMLHeader().

Here is the call graph for this function:

◆ Get() [1/2]

ProjectFileIO & ProjectFileIO::Get ( AudacityProject project)
static

Definition at line 266 of file ProjectFileIO.cpp.

267 {
268  auto &result = project.AttachedObjects::Get< ProjectFileIO >( sFileIOKey );
269  return result;
270 }

References sFileIOKey.

Referenced by ProjectFileManager::AddImportedTracks(), OpenProjectCommand::Apply(), ProjectFileManager::CloseProject(), ProjectFileManager::Compact(), ProjectFileManager::CompactProjectOnClose(), Effect::DoEffect(), anonymous_namespace{FileMenus.cpp}::DoExport(), DoImportMIDI(), ProjectFileManager::DoSave(), AudioIO::DrainRecordBuffers(), Get(), ProjectManager::GetEstimatedRecordingMinsLeftOnDisk(), ProjectFileManager::Import(), anonymous_namespace{ProjectFileManager.cpp}::ImportProject(), ProjectFileManager::IsAlreadyOpen(), ProjectHistory::ModifyState(), ProjectAudioManager::OnAudioIONewBlocks(), ProjectAudioManager::OnAudioIOStopRecording(), TimerRecordDialog::OnAutoSavePathButton_Click(), ProjectManager::OnCloseWindow(), HistoryDialog::OnCompact(), ContrastDialog::OnExport(), ProjectManager::OnTimer(), TransportActions::Handler::OnTimerRecord(), ProjectFileManager::OpenNewProject(), ProjectFileManager::OpenProject(), ProjectManager::OpenProject(), ProjectFileManager::OpenProjectFile(), ProjectHistory::PopState(), AutoRecoveryDialog::PopulateList(), TimerRecordDialog::PopulateOrExchange(), ProjectHistory::PushState(), ProjectFileManager::ReadProjectFile(), RefreshAllTitles(), ProjectManager::ResetProjectToEmpty(), ProjectFileManager::Save(), ProjectFileManager::SaveAs(), ProjectFileManager::SaveCopy(), ProjectFileManager::SaveFromTimerRecording(), AudioIO::StopStream(), and UnsavedChangesFlag().

Here is the caller graph for this function:

◆ Get() [2/2]

const ProjectFileIO & ProjectFileIO::Get ( const AudacityProject project)
static

Definition at line 272 of file ProjectFileIO.cpp.

273 {
274  return Get( const_cast< AudacityProject & >( project ) );
275 }

References Get().

Here is the call graph for this function:

◆ get2()

static unsigned int ProjectFileIO::get2 ( const unsigned char *  ptr)
staticprivate

◆ get4()

static unsigned int ProjectFileIO::get4 ( const unsigned char *  ptr)
staticprivate

◆ get_varint()

static int ProjectFileIO::get_varint ( const unsigned char *  ptr,
int64_t *  out 
)
staticprivate

◆ GetBlob()

bool ProjectFileIO::GetBlob ( const char *  sql,
wxMemoryBuffer &  buffer 
)
private

Definition at line 575 of file ProjectFileIO.cpp.

576 {
577  auto db = DB();
578  int rc;
579 
580  buffer.Clear();
581 
582  sqlite3_stmt *stmt = nullptr;
583  auto cleanup = finally([&]
584  {
585  if (stmt)
586  {
587  sqlite3_finalize(stmt);
588  }
589  });
590 
591  rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
592  if (rc != SQLITE_OK)
593  {
594  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql);
595  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
596  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob::prepare");
597 
598  SetDBError(
599  XO("Unable to prepare project file command:\n\n%s").Format(sql)
600  );
601  return false;
602  }
603 
604  rc = sqlite3_step(stmt);
605 
606  // A row wasn't found...not an error
607  if (rc == SQLITE_DONE)
608  {
609  return true;
610  }
611 
612  if (rc != SQLITE_ROW)
613  {
614  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql);
615  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
616  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::GetBlob::step");
617 
618  SetDBError(
619  XO("Failed to retrieve data from the project file.\nThe following command failed:\n\n%s").Format(sql)
620  );
621  // AUD TODO handle error
622  return false;
623  }
624 
625  const void *blob = sqlite3_column_blob(stmt, 0);
626  int size = sqlite3_column_bytes(stmt, 0);
627 
628  buffer.AppendData(blob, size);
629 
630  return true;
631 }

References ADD_EXCEPTION_CONTEXT, DB(), SetDBError(), size, and XO.

Referenced by LoadProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetBlockUsage()

int64_t ProjectFileIO::GetBlockUsage ( SampleBlockID  blockid)

Definition at line 2335 of file ProjectFileIO.cpp.

2336 {
2337  auto pConn = CurrConn().get();
2338  if (!pConn)
2339  return 0;
2340  return GetDiskUsage(*pConn, blockid);
2341 }

References CurrConn(), and GetDiskUsage().

Here is the call graph for this function:

◆ GetConnection()

DBConnection & ProjectFileIO::GetConnection ( )

Return a reference to a connection, creating it as needed on demand; throw on failure.

Definition at line 318 of file ProjectFileIO.cpp.

319 {
320  auto &curConn = CurrConn();
321  if (!curConn)
322  {
323  if (!OpenConnection())
324  {
326  {
328  XO("Failed to open the project's database"),
329  XO("Warning"),
330  "Error:_Disk_full_or_not_writable"
331  };
332  }
333  }
334 
335  return *curConn;
336 }

References CurrConn(), Internal, OpenConnection(), and XO.

Referenced by DB().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetCurrentUsage()

int64_t ProjectFileIO::GetCurrentUsage ( const std::vector< const TrackList * > &  trackLists) const

Definition at line 2343 of file ProjectFileIO.cpp.

2345 {
2346  unsigned long long current = 0;
2347  const auto fn = BlockSpaceUsageAccumulator(current);
2348 
2349  // Must pass address of this set, even if not otherwise used, to avoid
2350  // possible multiple count of shared blocks
2351  SampleBlockIDSet seen;
2352  for (auto pTracks: trackLists)
2353  if (pTracks)
2354  InspectBlocks(*pTracks, fn, &seen);
2355 
2356  return current;
2357 }

References BlockSpaceUsageAccumulator(), fn, and InspectBlocks().

Here is the call graph for this function:

◆ GetDiskUsage()

int64_t ProjectFileIO::GetDiskUsage ( DBConnection conn,
SampleBlockID  blockid 
)
static

Definition at line 2372 of file ProjectFileIO.cpp.

2373 {
2374  sqlite3_stmt* stmt = nullptr;
2375 
2376  if (blockid == 0)
2377  {
2378  static const char* statement =
2379 R"(SELECT
2380  sum(length(blockid) + length(sampleformat) +
2381  length(summin) + length(summax) + length(sumrms) +
2382  length(summary256) + length(summary64k) +
2383  length(samples))
2384 FROM sampleblocks;)";
2385 
2386  stmt = conn.Prepare(DBConnection::GetAllSampleBlocksSize, statement);
2387  }
2388  else
2389  {
2390  static const char* statement =
2391 R"(SELECT
2392  length(blockid) + length(sampleformat) +
2393  length(summin) + length(summax) + length(sumrms) +
2394  length(summary256) + length(summary64k) +
2395  length(samples)
2396 FROM sampleblocks WHERE blockid = ?1;)";
2397 
2398  stmt = conn.Prepare(DBConnection::GetSampleBlockSize, statement);
2399  }
2400 
2401  auto cleanup = finally(
2402  [stmt]() {
2403  // Clear statement bindings and rewind statement
2404  if (stmt != nullptr)
2405  {
2406  sqlite3_clear_bindings(stmt);
2407  sqlite3_reset(stmt);
2408  }
2409  });
2410 
2411  if (blockid != 0)
2412  {
2413  int rc = sqlite3_bind_int64(stmt, 1, blockid);
2414 
2415  if (rc != SQLITE_OK)
2416  {
2418  "sqlite3.rc", std::to_string(rc));
2419 
2421  "sqlite3.context", "ProjectFileIO::GetDiskUsage::bind");
2422 
2423  conn.ThrowException(false);
2424  }
2425  }
2426 
2427  int rc = sqlite3_step(stmt);
2428 
2429  if (rc != SQLITE_ROW)
2430  {
2431  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
2432 

References ADD_EXCEPTION_CONTEXT, DBConnection::GetAllSampleBlocksSize, DBConnection::GetSampleBlockSize, DBConnection::Prepare(), and DBConnection::ThrowException().

Referenced by GetBlockUsage(), SqliteSampleBlock::GetSpaceUsage(), and GetTotalUsage().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetFileName()

const FilePath & ProjectFileIO::GetFileName ( ) const

Definition at line 1502 of file ProjectFileIO.cpp.

1503 {
1504  return mFileName;
1505 }

References mFileName.

Referenced by ProjectFileManager::IsAlreadyOpen(), ContrastDialog::OnExport(), OpenConnection(), TimerRecordDialog::PopulateOrExchange(), and ProjectFileManager::SaveAs().

Here is the caller graph for this function:

◆ GetFreeDiskSpace()

wxLongLong ProjectFileIO::GetFreeDiskSpace ( ) const

Definition at line 2226 of file ProjectFileIO.cpp.

2227 {
2228  wxLongLong freeSpace;
2229  if (wxGetDiskSpace(wxPathOnly(mFileName), NULL, &freeSpace))
2230  {
2232  // 4 GiB per-file maximum
2233  constexpr auto limit = 1ll << 32;
2234 
2235  // Opening a file only to find its length looks wasteful but
2236  // seems to be necessary at least on Windows with FAT filesystems.
2237  // I don't know if that is only a wxWidgets bug.
2238  auto length = wxFile{mFileName}.Length();
2239  // auto length = wxFileName::GetSize(mFileName);
2240 
2241  if (length == wxInvalidSize)
2242  length = 0;
2243  auto free = std::max<wxLongLong>(0, limit - length);
2244  freeSpace = std::min(freeSpace, free);
2245  }
2246  return freeSpace;
2247  }
2248 
2249  return -1;
2250 }

References FileNames::IsOnFATFileSystem(), mFileName, and min().

Referenced by ProjectManager::GetEstimatedRecordingMinsLeftOnDisk(), and ProjectManager::OnTimer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetLastError()

const TranslatableString & ProjectFileIO::GetLastError ( ) const

Definition at line 2265 of file ProjectFileIO.cpp.

2266 {
2267  return mpErrors->mLastError;
2268 }

References mpErrors.

Referenced by SaveProject().

Here is the caller graph for this function:

◆ GetLastErrorCode()

int ProjectFileIO::GetLastErrorCode ( ) const

Definition at line 2275 of file ProjectFileIO.cpp.

2276 {
2277  return mpErrors->mErrorCode;
2278 }

References mpErrors.

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ GetLastLog()

const wxString & ProjectFileIO::GetLastLog ( ) const

Definition at line 2280 of file ProjectFileIO.cpp.

2281 {
2282  return mpErrors->mLog;
2283 }

References mpErrors.

Referenced by ShowError().

Here is the caller graph for this function:

◆ GetLibraryError()

const TranslatableString & ProjectFileIO::GetLibraryError ( ) const

Definition at line 2270 of file ProjectFileIO.cpp.

2271 {
2272  return mpErrors->mLibraryError;
2273 }

References mpErrors.

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ GetTotalUsage()

int64_t ProjectFileIO::GetTotalUsage ( )

Definition at line 2359 of file ProjectFileIO.cpp.

2360 {
2361  auto pConn = CurrConn().get();
2362  if (!pConn)
2363  return 0;
2364  return GetDiskUsage(*pConn, 0);
2365 }

References CurrConn(), and GetDiskUsage().

Referenced by ShouldCompact().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetValue()

bool ProjectFileIO::GetValue ( const char *  sql,
wxString &  value 
)
private

Definition at line 561 of file ProjectFileIO.cpp.

562 {
563  // Retrieve the first column in the first row, if any
564  result.clear();
565  auto cb = [&result](int cols, char **vals, char **){
566  if (cols > 0)
567  result = vals[0];
568  // Stop after one row
569  return 1;
570  };
571 
572  return Query(sql, cb);
573 }

References Query().

Referenced by CheckVersion(), and LoadProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ HadUnused()

bool ProjectFileIO::HadUnused ( )

Definition at line 1446 of file ProjectFileIO.cpp.

1447 {
1448  return mHadUnused;
1449 }

References mHadUnused.

Referenced by SetBypass().

Here is the caller graph for this function:

◆ HandleXMLChild()

XMLTagHandler * ProjectFileIO::HandleXMLChild ( const wxChar *  tag)
overrideprivatevirtual

Implements XMLTagHandler.

Definition at line 1619 of file ProjectFileIO.cpp.

1620 {
1621  auto &project = mProject;
1622  return ProjectFileIORegistry::Get().CallObjectAccessor(tag, project);
1623 }

References XMLMethodRegistry< Host >::CallObjectAccessor(), XMLMethodRegistry< Host >::Get(), and mProject.

Here is the call graph for this function:

◆ HandleXMLTag()

bool ProjectFileIO::HandleXMLTag ( const wxChar *  tag,
const wxChar **  attrs 
)
overrideprivatevirtual

Implements XMLTagHandler.

Definition at line 1535 of file ProjectFileIO.cpp.

1536 {
1537  auto &project = mProject;
1538 
1539  wxString fileVersion;
1540  wxString audacityVersion;
1541  int requiredTags = 0;
1542 
1543  // loop through attrs, which is a null-terminated list of
1544  // attribute-value pairs
1545  while (*attrs)
1546  {
1547  const wxChar *attr = *attrs++;
1548  const wxChar *value = *attrs++;
1549 
1550  if (!value || !XMLValueChecker::IsGoodString(value))
1551  {
1552  break;
1553  }
1554 
1556  .CallAttributeHandler( attr, project, value ) )
1557  continue;
1558 
1559  else if (!wxStrcmp(attr, wxT("version")))
1560  {
1561  fileVersion = value;
1562  requiredTags++;
1563  }
1564 
1565  else if (!wxStrcmp(attr, wxT("audacityversion")))
1566  {
1567  audacityVersion = value;
1568  requiredTags++;
1569  }
1570  } // while
1571 
1572  if (requiredTags < 2)
1573  {
1574  return false;
1575  }
1576 
1577  // Parse the file version from the project
1578  int fver;
1579  int frel;
1580  int frev;
1581  if (!wxSscanf(fileVersion, wxT("%i.%i.%i"), &fver, &frel, &frev))
1582  {
1583  return false;
1584  }
1585 
1586  // Parse the file version Audacity was build with
1587  int cver;
1588  int crel;
1589  int crev;
1590  wxSscanf(wxT(AUDACITY_FILE_FORMAT_VERSION), wxT("%i.%i.%i"), &cver, &crel, &crev);
1591 
1592  int fileVer = ((fver *100)+frel)*100+frev;
1593  int codeVer = ((cver *100)+crel)*100+crev;
1594 
1595  if (codeVer<fileVer)
1596  {
1597  /* i18n-hint: %s will be replaced by the version number.*/
1598  auto msg = XO("This file was saved using Audacity %s.\nYou are using Audacity %s. You may need to upgrade to a newer version to open this file.")
1599  .Format(audacityVersion, AUDACITY_VERSION_STRING);
1600 
1601  ShowError( *ProjectFramePlacement(&project),
1602  XO("Can't open project file"),
1603  msg,
1604  "FAQ:Errors_opening_an_Audacity_project"
1605  );
1606 
1607  return false;
1608  }
1609 
1610  if (wxStrcmp(tag, wxT("project")))
1611  {
1612  return false;
1613  }
1614 
1615  // All other tests passed, so we succeed
1616  return true;
1617 }

References AUDACITY_FILE_FORMAT_VERSION, XMLMethodRegistry< Host >::Get(), XMLValueChecker::IsGoodString(), mProject, ProjectFramePlacement(), ShowError(), and XO.

Here is the call graph for this function:

◆ HasConnection()

bool ProjectFileIO::HasConnection ( ) const

Return true if a connection is now open.

Definition at line 312 of file ProjectFileIO.cpp.

313 {
314  auto &connectionPtr = ConnectionPtr::Get( mProject );
315  return connectionPtr.mpConnection != nullptr;
316 }

References ConnectionPtr::Get(), and mProject.

Here is the call graph for this function:

◆ InitializeSQL()

bool ProjectFileIO::InitializeSQL ( )
static

Definition at line 211 of file ProjectFileIO.cpp.

212 {
213  static SQLiteIniter sqliteIniter;
214  return sqliteIniter.mRc == SQLITE_OK;
215 }

References SQLiteIniter::mRc.

Referenced by AudacityApp::OnInit().

Here is the caller graph for this function:

◆ InSet()

void ProjectFileIO::InSet ( sqlite3_context *  context,
int  argc,
sqlite3_value **  argv 
)
staticprivate

Definition at line 736 of file ProjectFileIO.cpp.

737 {
738  BlockIDs *blockids = (BlockIDs *) sqlite3_user_data(context);
739  SampleBlockID blockid = sqlite3_value_int64(argv[0]);
740 
741  sqlite3_result_int(context, blockids->find(blockid) != blockids->end());
742 }

Referenced by DeleteBlocks().

Here is the caller graph for this function:

◆ InstallSchema()

bool ProjectFileIO::InstallSchema ( sqlite3 *  db,
const char *  schema = "main" 
)
private

Definition at line 704 of file ProjectFileIO.cpp.

705 {
706  int rc;
707 
708  wxString sql;
710  sql.Replace("<schema>", schema);
711 
712  rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
713  if (rc != SQLITE_OK)
714  {
715  SetDBError(
716  XO("Unable to initialize the project file")
717  );
718  return false;
719  }
720 
721  return true;
722 }

References ProjectFileID, ProjectFileSchema, ProjectFileVersion, SetDBError(), and XO.

Referenced by CheckVersion(), and CopyTo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsModified()

bool ProjectFileIO::IsModified ( ) const

Definition at line 2211 of file ProjectFileIO.cpp.

2212 {
2213  return mModified;
2214 }

References mModified.

Referenced by Compact(), TransportActions::Handler::OnTimerRecord(), and UnsavedChangesFlag().

Here is the caller graph for this function:

◆ IsRecovered()

bool ProjectFileIO::IsRecovered ( ) const

Definition at line 2221 of file ProjectFileIO.cpp.

2222 {
2223  return mRecovered;
2224 }

References mRecovered.

◆ IsTemporary()

bool ProjectFileIO::IsTemporary ( ) const

Definition at line 2216 of file ProjectFileIO.cpp.

2217 {
2218  return mTemporary;
2219 }

References mTemporary.

Referenced by CloseProject(), Compact(), SaveProject(), SetBypass(), and SetFileName().

Here is the caller graph for this function:

◆ LoadProject()

bool ProjectFileIO::LoadProject ( const FilePath fileName,
bool  ignoreAutosave 
)

Definition at line 1804 of file ProjectFileIO.cpp.

1805 {
1806  bool success = false;
1807 
1808  auto cleanup = finally([&]
1809  {
1810  if (!success)
1811  {
1813  }
1814  });
1815 
1816  SaveConnection();
1817 
1818  // Open the project file
1819  if (!OpenConnection(fileName))
1820  {
1821  return false;
1822  }
1823 
1824  wxString project;
1825  wxMemoryBuffer buffer;
1826  bool usedAutosave = true;
1827 
1828  // Get the autosave doc, if any
1829  if (!ignoreAutosave &&
1830  !GetBlob("SELECT dict || doc FROM autosave WHERE id = 1;", buffer))
1831  {
1832  // Error already set
1833  return false;
1834  }
1835 
1836  // If we didn't have an autosave doc, load the project doc instead
1837  if (buffer.GetDataLen() == 0)
1838  {
1839  usedAutosave = false;
1840 
1841  if (!GetBlob("SELECT dict || doc FROM project WHERE id = 1;", buffer))
1842  {
1843  // Error already set
1844  return false;
1845  }
1846  }
1847 
1848  // Missing both the autosave and project docs. This can happen if the
1849  // system were to crash before the first autosave into a temporary file.
1850  // This should be a recoverable scenario.
1851  if (buffer.GetDataLen() == 0)
1852  {
1853  mRecovered = true;
1854  }
1855  else
1856  {
1857  project = ProjectSerializer::Decode(buffer);
1858  if (project.empty())
1859  {
1860  SetError(XO("Unable to decode project document"));
1861 
1862  return false;
1863  }
1864 
1865  XMLFileReader xmlFile;
1866 
1867  // Load 'er up
1868  success = xmlFile.ParseString(this, project);
1869  if (!success)
1870  {
1871  SetError(
1872  XO("Unable to parse project information."),
1873  xmlFile.GetErrorStr()
1874  );
1875  return false;
1876  }
1877 
1878  // Check for orphans blocks...sets mRecovered if any were deleted
1879 
1880  auto blockids = WaveTrackFactory::Get( mProject )
1882  ->GetActiveBlockIDs();
1883  if (blockids.size() > 0)
1884  {
1885  success = DeleteBlocks(blockids, true);
1886  if (!success)
1887  {
1888  return false;
1889  }
1890  }
1891 
1892  // Remember if we used autosave or not
1893  if (usedAutosave)
1894  {
1895  mRecovered = true;
1896  }
1897  }
1898 
1899  // Mark the project modified if we recovered it
1900  if (mRecovered)
1901  {
1902  mModified = true;
1903  }
1904 
1905  // A previously saved project will have a document in the project table, so
1906  // we use that knowledge to determine if this file is an unsaved/temporary
1907  // file or a permanent project file
1908  wxString result;
1909  success = GetValue("SELECT Count(*) FROM project;", result);
1910  if (!success)
1911  {
1912  return false;
1913  }
1914 
1915  mTemporary = !result.IsSameAs(wxT("1"));
1916 
1917  SetFileName(fileName);
1918 
1920 
1921  success = true;
1922 
1923  return true;
1924 }

References ProjectSerializer::Decode(), DeleteBlocks(), DiscardConnection(), WaveTrackFactory::Get(), GetBlob(), XMLFileReader::GetErrorStr(), WaveTrackFactory::GetSampleBlockFactory(), GetValue(), mModified, mProject, mRecovered, mTemporary, OpenConnection(), XMLFileReader::ParseString(), RestoreConnection(), SaveConnection(), SetError(), SetFileName(), and XO.

Here is the call graph for this function:

◆ MoveProject()

bool ProjectFileIO::MoveProject ( const FilePath src,
const FilePath dst 
)
private

Definition at line 1219 of file ProjectFileIO.cpp.

1220 {
1221  // Assume the src database file is not busy.
1222  if (!RenameOrWarn(src, dst))
1223  return false;
1224 
1225  // So far so good, but the separate -wal and -shm files might yet exist,
1226  // as when checkpointing failed for limited space on the drive.
1227  // If so move them too or else lose data.
1228 
1229  std::vector< std::pair<FilePath, FilePath> > pairs{ { src, dst } };
1230  bool success = false;
1231  auto cleanup = finally([&]{
1232  if (!success) {
1233  // If any one of the renames failed, back out the previous ones.
1234  // This should be a no-fail recovery! Not clear what to do if any
1235  // of these renames fails.
1236  for (auto &pair : pairs) {
1237  if (!(pair.first.empty() && pair.second.empty()))
1238  wxRenameFile(pair.second, pair.first);
1239  }
1240  }
1241  });
1242 
1243  for (const auto &suffix : AuxiliaryFileSuffixes()) {
1244  auto srcName = src + suffix;
1245  if (wxFileExists(srcName)) {
1246  auto dstName = dst + suffix;
1247  if (!RenameOrWarn(srcName, dstName))
1248  return false;
1249  pairs.push_back({ srcName, dstName });
1250  }
1251  }
1252 
1253  return (success = true);
1254 }

References AuxiliaryFileSuffixes(), and RenameOrWarn().

Referenced by ProjectFileIO::BackupProject::BackupProject(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnCheckpointFailure()

void ProjectFileIO::OnCheckpointFailure ( )
private

Definition at line 1625 of file ProjectFileIO.cpp.

1626 {
1627  wxCommandEvent evt{ EVT_CHECKPOINT_FAILURE };
1628  mProject.ProcessEvent(evt);
1629 }

References mProject.

◆ OpenConnection()

bool ProjectFileIO::OpenConnection ( FilePath  fileName = {})
private
Precondition
*CurConn() does not exist
Postcondition
*CurConn() exists or return value is false

Definition at line 357 of file ProjectFileIO.cpp.

358 {
359  auto &curConn = CurrConn();
360  wxASSERT(!curConn);
361  bool isTemp = false;
362 
363  if (fileName.empty())
364  {
365  fileName = GetFileName();
366  if (fileName.empty())
367  {
369  isTemp = true;
370  }
371  }
372  else
373  {
374  // If this project resides in the temporary directory, then we'll mark it
375  // as temporary.
376  wxFileName temp(TempDirectory::TempDir(), wxT(""));
377  wxFileName file(fileName);
378  file.SetFullName(wxT(""));
379  if (file == temp)
380  {
381  isTemp = true;
382  }
383  }
384 
385  // Pass weak_ptr to project into DBConnection constructor
386  curConn = std::make_unique<DBConnection>(
387  mProject.shared_from_this(), mpErrors, [this]{ OnCheckpointFailure(); } );
388  auto rc = curConn->Open(fileName);
389  if (rc != SQLITE_OK)
390  {
391  // Must use SetError() here since we do not have an active DB
392  SetError(
393  XO("Failed to open database file:\n\n%s").Format(fileName),
394  {},
395  rc
396  );
397  curConn.reset();
398  return false;
399  }
400 
401  if (!CheckVersion())
402  {
403  CloseConnection();
404  curConn.reset();
405  return false;
406  }
407 
408  mTemporary = isTemp;
409 
410  SetFileName(fileName);
411 
412  return true;
413 }

References CheckVersion(), CloseConnection(), CurrConn(), GetFileName(), mpErrors, mProject, mTemporary, SetError(), SetFileName(), TempDirectory::TempDir(), TempDirectory::UnsavedProjectFileName(), and XO.

Referenced by Compact(), GetConnection(), LoadProject(), OpenProject(), ReopenProject(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OpenProject()

bool ProjectFileIO::OpenProject ( )

Definition at line 2163 of file ProjectFileIO.cpp.

2164 {
2165  return OpenConnection();
2166 }

References OpenConnection().

Here is the call graph for this function:

◆ operator=()

ProjectFileIO& ProjectFileIO::operator= ( const ProjectFileIO )

◆ Query()

bool ProjectFileIO::Query ( const char *  sql,
const ExecCB callback 
)
private

Definition at line 548 of file ProjectFileIO.cpp.

549 {
550  int rc = Exec(sql, callback);
551  // SQLITE_ABORT is a non-error return only meaning the callback
552  // stopped the iteration of rows early
553  if ( !(rc == SQLITE_OK || rc == SQLITE_ABORT) )
554  {
555  return false;
556  }
557 
558  return true;
559 }

References Exec().

Referenced by CopyTo(), GetValue(), and ShouldCompact().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RemoveProject()

bool ProjectFileIO::RemoveProject ( const FilePath filename)
static

Remove any files associated with a project at given path; return true if successful.

Definition at line 1256 of file ProjectFileIO.cpp.

1257 {
1258  if (!wxFileExists(filename))
1259  return false;
1260 
1261  bool success = wxRemoveFile(filename);
1262  auto &suffixes = AuxiliaryFileSuffixes();
1263  for (const auto &suffix : suffixes) {
1264  auto file = filename + suffix;
1265  if (wxFileExists(file))
1266  success = wxRemoveFile(file) && success;
1267  }
1268  return success;
1269 }

References AuxiliaryFileSuffixes().

Referenced by CloseProject(), ProjectFileIO::BackupProject::Discard(), DiscardConnection(), and AutoRecoveryDialog::OnDiscardSelected().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RenameOrWarn()

bool ProjectFileIO::RenameOrWarn ( const FilePath src,
const FilePath dst 
)
private

Rename a file or put up appropriate warning message.

Failure might happen when renaming onto another device, doing copy of contents

Definition at line 1179 of file ProjectFileIO.cpp.

1180 {
1181  std::atomic_bool done = {false};
1182  bool success = false;
1183  auto thread = std::thread([&]
1184  {
1185  success = wxRenameFile(src, dst);
1186  done = true;
1187  });
1188 
1189  // Provides a progress dialog with indeterminate mode
1190  using namespace BasicUI;
1192  XO("Copying Project"), XO("This may take several seconds"));
1193  wxASSERT(pd);
1194 
1195  // Wait for the checkpoints to end
1196  while (!done)
1197  {
1198  wxMilliSleep(50);
1199  pd->Pulse();
1200  }
1201  thread.join();
1202 
1203  if (!success)
1204  {
1206  XO("Error Writing to File"),
1207  XO("Audacity failed to write file %s.\n"
1208  "Perhaps disk is full or not writable.\n"
1209  "For tips on freeing up space, click the help button.")
1210  .Format(dst),
1211  "Error:_Disk_full_or_not_writable"
1212  );
1213  return false;
1214  }
1215 
1216  return true;
1217 }

References BasicUI::MakeGenericProgress(), mProject, ProjectFramePlacement(), ShowError(), and XO.

Referenced by MoveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ReopenProject()

bool ProjectFileIO::ReopenProject ( )

Definition at line 2200 of file ProjectFileIO.cpp.

2201 {
2202  FilePath fileName = mFileName;
2203  if (!CloseConnection())
2204  {
2205  return false;
2206  }
2207 
2208  return OpenConnection(fileName);
2209 }

References CloseConnection(), mFileName, and OpenConnection().

Here is the call graph for this function:

◆ RestoreConnection()

void ProjectFileIO::RestoreConnection ( )
private

Definition at line 481 of file ProjectFileIO.cpp.

482 {
483  auto &curConn = CurrConn();
484  if (curConn)
485  {
486  if (!curConn->Close())
487  {
488  // Store an error message
489  SetDBError(
490  XO("Failed to restore connection")
491  );
492  }
493  }
494 
495  curConn = std::move(mPrevConn);
498 
499  mPrevFileName.clear();
500 }

References CurrConn(), mPrevConn, mPrevFileName, mPrevTemporary, mTemporary, SetDBError(), SetFileName(), and XO.

Referenced by LoadProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SafetyFileName()

FilePath ProjectFileIO::SafetyFileName ( const FilePath src)
staticprivate

Generate a name for short-lived backup project files from an existing project.

Definition at line 1144 of file ProjectFileIO.cpp.

1145 {
1146  wxFileNameWrapper fn{ src };
1147 
1148  // Extra characters inserted into filename before extension
1149  wxString extra =
1150 #ifdef __WXGTK__
1151  wxT("~")
1152 #else
1153  wxT(".bak")
1154 #endif
1155  ;
1156 
1157  int nn = 1;
1158  auto numberString = [](int num) -> wxString {
1159  return num == 1 ? wxString{} : wxString::Format(".%d", num);
1160  };
1161 
1162  auto suffixes = AuxiliaryFileSuffixes();
1163  suffixes.push_back({});
1164 
1165  // Find backup paths not already occupied; check all auxiliary suffixes
1166  const auto name = fn.GetName();
1167  FilePath result;
1168  do {
1169  fn.SetName( name + numberString(nn++) + extra );
1170  result = fn.GetFullPath();
1171  }
1172  while( std::any_of(suffixes.begin(), suffixes.end(), [&](auto &suffix){
1173  return wxFileExists(result + suffix);
1174  }) );
1175 
1176  return result;
1177 }

References AuxiliaryFileSuffixes(), fn, and name.

Referenced by ProjectFileIO::BackupProject::BackupProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SaveConnection()

void ProjectFileIO::SaveConnection ( )
private

Definition at line 434 of file ProjectFileIO.cpp.

435 {
436  // Should do nothing in proper usage, but be sure not to leak a connection:
438 
439  mPrevConn = std::move(CurrConn());
442 
443  SetFileName({});
444 }

References CurrConn(), DiscardConnection(), mFileName, mPrevConn, mPrevFileName, mPrevTemporary, mTemporary, and SetFileName().

Referenced by LoadProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SaveCopy()

bool ProjectFileIO::SaveCopy ( const FilePath fileName)

Definition at line 2157 of file ProjectFileIO.cpp.

2158 {
2159  return CopyTo(fileName, XO("Backing up project"), false, true,
2160  {&TrackList::Get(mProject)});
2161 }

References CopyTo(), TrackList::Get(), mProject, and XO.

Here is the call graph for this function:

◆ SaveProject()

bool ProjectFileIO::SaveProject ( const FilePath fileName,
const TrackList lastSaved 
)

Definition at line 1949 of file ProjectFileIO.cpp.

1951 {
1952  // In the case where we're saving a temporary project to a permanent project,
1953  // we'll try to simply rename the project to save a bit of time. We then fall
1954  // through to the normal Save (not SaveAs) processing.
1955  if (IsTemporary() && mFileName != fileName)
1956  {
1957  FilePath savedName = mFileName;
1958  if (CloseConnection())
1959  {
1960  bool reopened = false;
1961  bool moved = false;
1962  if (true == (moved = MoveProject(savedName, fileName)))
1963  {
1964  if (OpenConnection(fileName))
1965  reopened = true;
1966  else {
1967  MoveProject(fileName, savedName);
1968  moved = false; // No longer moved
1969 
1970  reopened = OpenConnection(savedName);
1971  }
1972  }
1973  else {
1974  // Rename can fail -- if it's to a different device, requiring
1975  // real copy of contents, which might exhaust space
1976  reopened = OpenConnection(savedName);
1977  }
1978 
1979  // Warning issued in MoveProject()
1980  if (reopened && !moved) {
1981  return false;
1982  }
1983 
1984  if (!reopened) {
1985  wxTheApp->CallAfter([this]{
1986  ShowError( {},
1987  XO("Warning"),
1988  XO(
1989 "The project's database failed to reopen, "
1990 "possibly because of limited space on the storage device."),
1991  "Error:_Disk_full_or_not_writable"
1992  );
1993  wxCommandEvent evt{ EVT_RECONNECTION_FAILURE };
1994  mProject.ProcessEvent(evt);
1995  });
1996 
1997  return false;
1998  }
1999  }
2000  }
2001 
2002  // If we're saving to a different file than the current one, then copy the
2003  // current to the new file and make it the active file.
2004  if (mFileName != fileName)
2005  {
2006  // Do NOT prune here since we need to retain the Undo history
2007  // after we switch to the new file.
2008  if (!CopyTo(fileName, XO("Saving project"), false))
2009  {
2010  ShowError( {},
2011  XO("Error Saving Project"),
2013  "Error:_Disk_full_or_not_writable"
2014  );
2015  return false;
2016  }
2017 
2018  // Open the newly created database
2019  Connection newConn = std::make_unique<DBConnection>(
2020  mProject.shared_from_this(), mpErrors,
2021  [this]{ OnCheckpointFailure(); });
2022 
2023  // NOTE: There is a noticeable delay here when dealing with large multi-hour
2024  // projects that we just created. The delay occurs in Open() when it
2025  // calls SafeMode() and is due to the switch from the NONE journal mode
2026  // to the WAL journal mode.
2027  //
2028  // So, we do the Open() in a thread and display a progress dialog. Since
2029  // this is currently the only known instance where this occurs, we do the
2030  // threading here. If more instances are identified, then the threading
2031  // should be moved to DBConnection::Open(), wrapping the SafeMode() call
2032  // there.
2033  {
2034  std::atomic_bool done = {false};
2035  bool success = true;
2036  auto thread = std::thread([&]
2037  {
2038  auto rc = newConn->Open(fileName);
2039  if (rc != SQLITE_OK)
2040  {
2041  // Capture the error string
2042  SetError(Verbatim(sqlite3_errstr(rc)));
2043  success = false;
2044  }
2045  done = true;
2046  });
2047 
2048  // Provides a progress dialog with indeterminate mode
2049  using namespace BasicUI;
2050  auto pd = MakeGenericProgress({},
2051  XO("Syncing"), XO("This may take several seconds"));
2052  wxASSERT(pd);
2053 
2054  // Wait for the checkpoints to end
2055  while (!done)
2056  {
2057  wxMilliSleep(50);
2058  pd->Pulse();
2059  }
2060  thread.join();
2061 
2062  if (!success)
2063  {
2064  // Additional help via a Help button links to the manual.
2065  ShowError( {},
2066  XO("Error Saving Project"),
2067  XO("The project failed to open, possibly due to limited space\n"
2068  "on the storage device.\n\n%s").Format(GetLastError()),
2069  "Error:_Disk_full_or_not_writable");
2070 
2071  newConn = nullptr;
2072 
2073  // Clean up the destination project
2074  if (!wxRemoveFile(fileName))
2075  {
2076  wxLogMessage("Failed to remove destination project after open failure: %s", fileName);
2077  }
2078 
2079  return false;
2080  }
2081  }
2082 
2083  // Autosave no longer needed in original project file.
2084  if (!AutoSaveDelete())
2085  {
2086  // Additional help via a Help button links to the manual.
2087  ShowError( {},
2088  XO("Error Saving Project"),
2089  XO("Unable to remove autosave information, possibly due to limited space\n"
2090  "on the storage device.\n\n%s").Format(GetLastError()),
2091  "Error:_Disk_full_or_not_writable");
2092 
2093  newConn = nullptr;
2094 
2095  // Clean up the destination project
2096  if (!wxRemoveFile(fileName))
2097  {
2098  wxLogMessage("Failed to remove destination project after AutoSaveDelete failure: %s", fileName);
2099  }
2100 
2101  return false;
2102  }
2103 
2104  if (lastSaved) {
2105  // Bug2605: Be sure not to save orphan blocks
2106  bool recovered = mRecovered;
2107  SampleBlockIDSet blockids;
2108  InspectBlocks( *lastSaved, {}, &blockids );
2109  // TODO: Not sure what to do if the deletion fails
2110  DeleteBlocks(blockids, true);
2111  // Don't set mRecovered if any were deleted
2112  mRecovered = recovered;
2113  }
2114 
2115  // Try to compact the original project file.
2116  auto empty = TrackList::Create(&mProject);
2117  Compact( { lastSaved ? lastSaved : empty.get() }, true );
2118 
2119  // Safe to close the original project file now. Not much we can do if this fails,
2120  // but we should still be in good shape since we'll be switching to the newly
2121  // saved database below.
2122  CloseProject();
2123 
2124  // And make it the active project file
2125  UseConnection(std::move(newConn), fileName);
2126  }
2127  else
2128  {
2129  if ( !UpdateSaved( nullptr ) ) {
2130  ShowError( {},
2131  XO("Error Saving Project"),
2133  "Error:_Disk_full_or_not_writable"
2134  );
2135  return false;
2136  }
2137  }
2138 
2139  // Reaching this point defines success and all the rest are no-fail
2140  // operations:
2141 
2142  // No longer modified
2143  mModified = false;
2144 
2145  // No longer recovered
2146  mRecovered = false;
2147 
2148  // No longer a temporary project
2149  mTemporary = false;
2150 
2151  // Adjust the title
2152  SetProjectTitle();
2153 
2154  return true;
2155 }

References AutoSaveDelete(), CloseConnection(), CloseProject(), Compact(), CopyTo(), TrackList::Create(), DeleteBlocks(), GetLastError(), InspectBlocks(), IsTemporary(), BasicUI::MakeGenericProgress(), mFileName, mModified, MoveProject(), mpErrors, mProject, mRecovered, mTemporary, OpenConnection(), SetError(), SetProjectTitle(), ShowError(), UpdateSaved(), UseConnection(), Verbatim(), FileException::WriteFailureMessage(), and XO.

Here is the call graph for this function:

◆ SetBypass()

void ProjectFileIO::SetBypass ( )

Definition at line 2301 of file ProjectFileIO.cpp.

2302 {
2303  auto &currConn = CurrConn();
2304  if (!currConn)
2305  return;
2306 
2307  // Determine if we can bypass sample block deletes during shutdown.
2308  //
2309  // IMPORTANT:
2310  // If the project was compacted, then we MUST bypass further
2311  // deletions since the new file doesn't have the blocks that the
2312  // Sequences expect to be there.
2313 
2314  currConn->SetBypass( true );
2315 
2316  // Only permanent project files need cleaning at shutdown
2317  if (!IsTemporary() && !WasCompacted())
2318  {
2319  // If we still have unused blocks, then we must not bypass deletions
2320  // during shutdown. Otherwise, we would have orphaned blocks the next time
2321  // the project is opened.
2322  //
2323  // An example of when dead blocks will exist is when a user opens a permanent
2324  // project, adds a track (with samples) to it, and chooses not to save the
2325  // changes.
2326  if (HadUnused())
2327  {
2328  currConn->SetBypass( false );
2329  }
2330  }
2331 
2332  return;
2333 }

References CurrConn(), HadUnused(), IsTemporary(), and WasCompacted().

Here is the call graph for this function:

◆ SetDBError()

void ProjectFileIO::SetDBError ( const TranslatableString msg,
const TranslatableString libraryError = {},
int  errorCode = -1 
)
private

Set stored errors and write to log; and default libraryError to what database library reports.

Definition at line 2293 of file ProjectFileIO.cpp.

2295 {
2296  auto &currConn = CurrConn();
2297  if (currConn)
2298  currConn->SetDBError(msg, libraryError, errorCode);
2299 }

References CurrConn().

Referenced by AutoSaveDelete(), CopyTo(), DeleteBlocks(), DiscardConnection(), Exec(), GetBlob(), InstallSchema(), RestoreConnection(), and WriteDoc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetError()

void ProjectFileIO::SetError ( const TranslatableString msg,
const TranslatableString libraryError = {},
int  errorCode = {} 
)
private

Just set stored errors.

Definition at line 2285 of file ProjectFileIO.cpp.

2287 {
2288  auto &currConn = CurrConn();
2289  if (currConn)
2290  currConn->SetError(msg, libraryError, errorCode);
2291 }

References CurrConn().

Referenced by CheckVersion(), LoadProject(), OpenConnection(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetFileName()

void ProjectFileIO::SetFileName ( const FilePath fileName)

Definition at line 1507 of file ProjectFileIO.cpp.

1508 {
1509  auto &project = mProject;
1510 
1511  if (!mFileName.empty())
1512  {
1514  }
1515 
1516  mFileName = fileName;
1517 
1518  if (!mFileName.empty())
1519  {
1521  }
1522 
1523  if (IsTemporary())
1524  {
1525  project.SetProjectName({});
1526  }
1527  else
1528  {
1529  project.SetProjectName(wxFileName(mFileName).GetName());
1530  }
1531 
1532  SetProjectTitle();
1533 }

References ActiveProjects::Add(), IsTemporary(), mFileName, mProject, ActiveProjects::Remove(), and SetProjectTitle().

Referenced by CloseConnection(), LoadProject(), OpenConnection(), RestoreConnection(), SaveConnection(), and UseConnection().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetProjectTitle()

void ProjectFileIO::SetProjectTitle ( int  number = -1)

Definition at line 1457 of file ProjectFileIO.cpp.

1458 {
1459  auto &project = mProject;
1460  auto pWindow = FindProjectFrame(&project);
1461  if (!pWindow)
1462  {
1463  return;
1464  }
1465  auto &window = *pWindow;
1466  wxString name = project.GetProjectName();
1467 
1468  // If we are showing project numbers, then we also explicitly show "<untitled>" if there
1469  // is none.
1470  if (number >= 0)
1471  {
1472  name =
1473  /* i18n-hint: The %02i is the project number, the %s is the project name.*/
1474  XO("[Project %02i] Audacity \"%s\"")
1475  .Format( number + 1,
1476  name.empty() ? XO("<untitled>") : Verbatim((const char *)name))
1477  .Translation();
1478  }
1479  // If we are not showing numbers, then <untitled> shows as 'Audacity'.
1480  else if (name.empty())
1481  {
1482  name = _TS("Audacity");
1483  }
1484 
1485  if (mRecovered)
1486  {
1487  name += wxT(" ");
1488  /* i18n-hint: E.g this is recovered audio that had been lost.*/
1489  name += _("(Recovered)");
1490  }
1491 
1492  if (name != window.GetTitle())
1493  {
1494  window.SetTitle( name );
1495  window.SetName(name); // to make the nvda screen reader read the correct title
1496 
1497  project.QueueEvent(
1498  safenew wxCommandEvent{ EVT_PROJECT_TITLE_CHANGE } );
1499  }
1500 }

References _, _TS, TranslatableString::empty(), FindProjectFrame(), mProject, mRecovered, name, safenew, Verbatim(), and XO.

Referenced by RefreshAllTitles(), SaveProject(), SetFileName(), and UpdatePrefs().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ShouldCompact()

bool ProjectFileIO::ShouldCompact ( const std::vector< const TrackList * > &  tracks)
private

Definition at line 1079 of file ProjectFileIO.cpp.

1080 {
1081  SampleBlockIDSet active;
1082  unsigned long long current = 0;
1083 
1084  {
1085  auto fn = BlockSpaceUsageAccumulator( current );
1086  for (auto pTracks : tracks)
1087  if (pTracks)
1088  InspectBlocks( *pTracks, fn,
1089  &active // Visit unique blocks only
1090  );
1091  }
1092 
1093  // Get the number of blocks and total length from the project file.
1094  unsigned long long total = GetTotalUsage();
1095  unsigned long long blockcount = 0;
1096 
1097  auto cb = [&blockcount](int cols, char **vals, char **)
1098  {
1099  // Convert
1100  wxString(vals[0]).ToULongLong(&blockcount);
1101  return 0;
1102  };
1103 
1104  if (!Query("SELECT Count(*) FROM sampleblocks;", cb) || blockcount == 0)
1105  {
1106  // Shouldn't compact since we don't have the full picture
1107  return false;
1108  }
1109 
1110  // Remember if we had unused blocks in the project file
1111  mHadUnused = (blockcount > active.size());
1112 
1113  // Let's make a percentage...should be plenty of head room
1114  current *= 100;
1115 
1116  wxLogDebug(wxT("used = %lld total = %lld %lld"), current, total, total ? current / total : 0);
1117  if (!total || current / total > 80)
1118  {
1119  wxLogDebug(wxT("not compacting"));
1120  return false;
1121  }
1122  wxLogDebug(wxT("compacting"));
1123 
1124  return true;
1125 }

References BlockSpaceUsageAccumulator(), fn, GetTotalUsage(), InspectBlocks(), mHadUnused, and Query().

Referenced by Compact().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ShowError()

void ProjectFileIO::ShowError ( const BasicUI::WindowPlacement placement,
const TranslatableString dlogTitle,
const TranslatableString message,
const wxString &  helpPage 
)

Displays an error dialog with a button that offers help.

Definition at line 2253 of file ProjectFileIO.cpp.

2257 {
2258  using namespace audacity;
2259  using namespace BasicUI;
2260  ShowErrorDialog( placement, dlogTitle, message, helpPage,
2261  ErrorDialogOptions{ ErrorDialogType::ModalErrorReport }
2262  .Log(ToWString(GetLastLog())));
2263 }

References GetLastLog(), BasicUI::ErrorDialogOptions::Log(), BasicUI::ShowErrorDialog(), and audacity::ToWString().

Referenced by HandleXMLTag(), RenameOrWarn(), and SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdatePrefs()

void ProjectFileIO::UpdatePrefs ( )
overrideprivatevirtual

Implements PrefsListener.

Definition at line 1451 of file ProjectFileIO.cpp.

1452 {
1453  SetProjectTitle();
1454 }

References SetProjectTitle().

Here is the call graph for this function:

◆ UpdateSaved()

bool ProjectFileIO::UpdateSaved ( const TrackList tracks = nullptr)

Definition at line 1926 of file ProjectFileIO.cpp.

1927 {
1928  ProjectSerializer doc;
1929  WriteXMLHeader(doc);
1930  WriteXML(doc, false, tracks);
1931 
1932  if (!WriteDoc("project", doc))
1933  {
1934  return false;
1935  }
1936 
1937  // Autosave no longer needed
1938  if (!AutoSaveDelete())
1939  {
1940  return false;
1941  }
1942 
1943  return true;
1944 }

References AutoSaveDelete(), WriteDoc(), WriteXML(), and WriteXMLHeader().

Referenced by SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpgradeSchema()

bool ProjectFileIO::UpgradeSchema ( )
private

Definition at line 724 of file ProjectFileIO.cpp.

725 {
726  // To do
727  return true;
728 }

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ UseConnection()

void ProjectFileIO::UseConnection ( Connection &&  conn,
const FilePath filePath 
)
private

Definition at line 502 of file ProjectFileIO.cpp.

503 {
504  auto &curConn = CurrConn();
505  wxASSERT(!curConn);
506 
507  curConn = std::move(conn);
508  SetFileName(filePath);
509 }

References CurrConn(), and SetFileName().

Referenced by SaveProject().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WasCompacted()

bool ProjectFileIO::WasCompacted ( )

Definition at line 1441 of file ProjectFileIO.cpp.

1442 {
1443  return mWasCompacted;
1444 }

References mWasCompacted.

Referenced by SetBypass().

Here is the caller graph for this function:

◆ WriteDoc()

bool ProjectFileIO::WriteDoc ( const char *  table,
const ProjectSerializer autosave,
const char *  schema = "main" 
)
private

Definition at line 1730 of file ProjectFileIO.cpp.

1733 {
1734  auto db = DB();
1735  int rc;
1736 
1737  // For now, we always use an ID of 1. This will replace the previously
1738  // written row every time.
1739  char sql[256];
1740  sqlite3_snprintf(sizeof(sql),
1741  sql,
1742  "INSERT INTO %s.%s(id, dict, doc) VALUES(1, ?1, ?2)"
1743  " ON CONFLICT(id) DO UPDATE SET dict = ?1, doc = ?2;",
1744  schema,
1745  table);
1746 
1747  sqlite3_stmt *stmt = nullptr;
1748  auto cleanup = finally([&]
1749  {
1750  if (stmt)
1751  {
1752  sqlite3_finalize(stmt);
1753  }
1754  });
1755 
1756  rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
1757  if (rc != SQLITE_OK)
1758  {
1759  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql);
1760  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1761  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::prepare");
1762 
1763  SetDBError(
1764  XO("Unable to prepare project file command:\n\n%s").Format(sql)
1765  );
1766  return false;
1767  }
1768 
1769  const wxMemoryBuffer &dict = autosave.GetDict();
1770  const wxMemoryBuffer &data = autosave.GetData();
1771 
1772  // Bind statement parameters
1773  // Might return SQL_MISUSE which means it's our mistake that we violated
1774  // preconditions; should return SQL_OK which is 0
1775  if (sqlite3_bind_blob(stmt, 1, dict.GetData(), dict.GetDataLen(), SQLITE_STATIC) ||
1776  sqlite3_bind_blob(stmt, 2, data.GetData(), data.GetDataLen(), SQLITE_STATIC))
1777  {
1778  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql);
1779  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1780  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::bind");
1781 
1782  SetDBError(
1783  XO("Unable to bind to blob")
1784  );
1785  return false;
1786  }
1787 
1788  rc = sqlite3_step(stmt);
1789  if (rc != SQLITE_DONE)
1790  {
1791  ADD_EXCEPTION_CONTEXT("sqlite3.query", sql);
1792  ADD_EXCEPTION_CONTEXT("sqlite3.rc", std::to_string(rc));
1793  ADD_EXCEPTION_CONTEXT("sqlite3.context", "ProjectGileIO::WriteDoc::step");
1794 
1795  SetDBError(
1796  XO("Failed to update the project file.\nThe following command failed:\n\n%s").Format(sql)
1797  );
1798  return false;
1799  }
1800 
1801  return true;
1802 }

References ADD_EXCEPTION_CONTEXT, DB(), ProjectSerializer::GetData(), ProjectSerializer::GetDict(), SetDBError(), and XO.

Referenced by AutoSave(), CopyTo(), and UpdateSaved().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteXML()

void ProjectFileIO::WriteXML ( XMLWriter xmlFile,
bool  recording = false,
const TrackList tracks = nullptr 
)
private

Definition at line 1646 of file ProjectFileIO.cpp.

1650 {
1651  auto &proj = mProject;
1652  auto &tracklist = tracks ? *tracks : TrackList::Get(proj);
1653 
1654  //TIMER_START( "AudacityProject::WriteXML", xml_writer_timer );
1655 
1656  xmlFile.StartTag(wxT("project"));
1657  xmlFile.WriteAttr(wxT("xmlns"), wxT("http://audacity.sourceforge.net/xml/"));
1658 
1659  xmlFile.WriteAttr(wxT("version"), wxT(AUDACITY_FILE_FORMAT_VERSION));
1660  xmlFile.WriteAttr(wxT("audacityversion"), AUDACITY_VERSION_STRING);
1661 
1662  ProjectFileIORegistry::Get().CallWriters(proj, xmlFile);
1663 
1664  tracklist.Any().Visit([&](const Track *t)
1665  {
1666  auto useTrack = t;
1667  if ( recording ) {
1668  // When append-recording, there is a temporary "shadow" track accumulating
1669  // changes and displayed on the screen but it is not yet part of the
1670  // regular track list. That is the one that we want to back up.
1671  // SubstitutePendingChangedTrack() fetches the shadow, if the track has
1672  // one, else it gives the same track back.
1673  useTrack = t->SubstitutePendingChangedTrack().get();
1674  }
1675  else if ( useTrack->GetId() == TrackId{} ) {
1676  // This is a track added during a non-appending recording that is
1677  // not yet in the undo history. The UndoManager skips backing it up
1678  // when pushing. Don't auto-save it.
1679  return;
1680  }
1681  useTrack->WriteXML(xmlFile);
1682  });
1683 
1684  xmlFile.EndTag(wxT("project"));
1685 
1686  //TIMER_STOP( xml_writer_timer );
1687 }

References AUDACITY_FILE_FORMAT_VERSION, XMLMethodRegistry< Host >::CallWriters(), XMLWriter::EndTag(), XMLMethodRegistry< Host >::Get(), TrackList::Get(), mProject, XMLWriter::StartTag(), Track::SubstitutePendingChangedTrack(), and XMLWriter::WriteAttr().

Referenced by AutoSave(), CopyTo(), GenerateDoc(), and UpdateSaved().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteXMLHeader()

void ProjectFileIO::WriteXMLHeader ( XMLWriter xmlFile) const
private

Definition at line 1631 of file ProjectFileIO.cpp.

1632 {
1633  xmlFile.Write(wxT("<?xml "));
1634  xmlFile.Write(wxT("version=\"1.0\" "));
1635  xmlFile.Write(wxT("standalone=\"no\" "));
1636  xmlFile.Write(wxT("?>\n"));
1637 
1638  xmlFile.Write(wxT("<!DOCTYPE "));
1639  xmlFile.Write(wxT("project "));
1640  xmlFile.Write(wxT("PUBLIC "));
1641  xmlFile.Write(wxT("\"-//audacityproject-1.3.0//DTD//EN\" "));
1642  xmlFile.Write(wxT("\"http://audacity.sourceforge.net/xml/audacityproject-1.3.0.dtd\" "));
1643  xmlFile.Write(wxT(">\n"));
1644 }

References XMLWriter::Write().

Referenced by AutoSave(), CopyTo(), GenerateDoc(), and UpdateSaved().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ mFileName

FilePath ProjectFileIO::mFileName
private

◆ mHadUnused

bool ProjectFileIO::mHadUnused
private

Definition at line 307 of file ProjectFileIO.h.

Referenced by Compact(), HadUnused(), and ShouldCompact().

◆ mModified

bool ProjectFileIO::mModified
private

Definition at line 298 of file ProjectFileIO.h.

Referenced by AutoSave(), AutoSaveDelete(), IsModified(), LoadProject(), and SaveProject().

◆ mpErrors

std::shared_ptr<DBConnectionErrors> ProjectFileIO::mpErrors
private

◆ mPrevConn

Connection ProjectFileIO::mPrevConn
private

Definition at line 309 of file ProjectFileIO.h.

Referenced by DiscardConnection(), RestoreConnection(), and SaveConnection().

◆ mPrevFileName

FilePath ProjectFileIO::mPrevFileName
private

Definition at line 310 of file ProjectFileIO.h.

Referenced by DiscardConnection(), RestoreConnection(), and SaveConnection().

◆ mPrevTemporary

bool ProjectFileIO::mPrevTemporary
private

Definition at line 311 of file ProjectFileIO.h.

Referenced by DiscardConnection(), RestoreConnection(), and SaveConnection().

◆ mProject

AudacityProject& ProjectFileIO::mProject
private

◆ mRecovered

bool ProjectFileIO::mRecovered
private

Definition at line 295 of file ProjectFileIO.h.

Referenced by DeleteBlocks(), IsRecovered(), LoadProject(), SaveProject(), and SetProjectTitle().

◆ mTemporary

bool ProjectFileIO::mTemporary
private

◆ mWasCompacted

bool ProjectFileIO::mWasCompacted
private

Definition at line 304 of file ProjectFileIO.h.

Referenced by Compact(), and WasCompacted().


The documentation for this class was generated from the following files:
ProjectFileIO::CopyTo
bool CopyTo(const FilePath &destpath, const TranslatableString &msg, bool isTemporary, bool prune=false, const std::vector< const TrackList * > &tracks={})
Definition: ProjectFileIO.cpp:820
size
size_t size
Definition: ffmpeg-2.3.6-single-header.h:412
XMLWriter::EndTag
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:99
ProjectFileIO::HadUnused
bool HadUnused()
Definition: ProjectFileIO.cpp:1446
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
BasicUI::ErrorDialogOptions::Log
ErrorDialogOptions && Log(std::wstring log_) &&
Definition: BasicUI.h:61
ProjectFramePlacement
std::unique_ptr< const BasicUI::WindowPlacement > ProjectFramePlacement(AudacityProject *project)
Make a WindowPlacement object suitable for project (which may be null)
Definition: ProjectWindows.cpp:101
WaveTrackFactory::Get
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2890
ProjectFileIO::GetFileName
const FilePath & GetFileName() const
Definition: ProjectFileIO.cpp:1502
ProjectSerializer::Decode
static wxString Decode(const wxMemoryBuffer &buffer)
Definition: ProjectSerializer.cpp:386
ProjectFileIO::GetConnection
DBConnection & GetConnection()
Return a reference to a connection, creating it as needed on demand; throw on failure.
Definition: ProjectFileIO.cpp:318
BasicUI::ProgressResult::Success
@ Success
ProjectFileIO::GetLibraryError
const TranslatableString & GetLibraryError() const
Definition: ProjectFileIO.cpp:2270
ProjectFileIO::SetFileName
void SetFileName(const FilePath &fileName)
Definition: ProjectFileIO.cpp:1507
SampleBlockIDSet
std::unordered_set< SampleBlockID > SampleBlockIDSet
Definition: WaveTrack.h:693
fn
static const auto fn
Definition: WaveformView.cpp:1108
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
FileNames::AbbreviatePath
FILES_API wxString AbbreviatePath(const wxFileName &fileName)
Give enough of the path to identify the device. (On Windows, drive letter plus ':')
ProjectFileIO::UpgradeSchema
bool UpgradeSchema()
Definition: ProjectFileIO.cpp:724
BasicUI::ShowErrorDialog
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:233
ProjectFileIO::WriteDoc
bool WriteDoc(const char *table, const ProjectSerializer &autosave, const char *schema="main")
Definition: ProjectFileIO.cpp:1730
ProjectFileIO::CurrConn
Connection & CurrConn()
Definition: ProjectFileIO.cpp:1127
pdlgHideStopButton
@ pdlgHideStopButton
Definition: ProgressDialog.h:38
ProjectFileVersion
static const int ProjectFileVersion
Definition: ProjectFileIO.cpp:76
Format
Abstract base class used in importing a file.
ProjectFileIO::AuxiliaryFileSuffixes
static const std::vector< wxString > & AuxiliaryFileSuffixes()
Definition: ProjectFileIO.cpp:1133
BasicUI::ProgressResult
ProgressResult
Definition: BasicUI.h:145
ProjectFileIO::RemoveProject
static bool RemoveProject(const FilePath &filename)
Remove any files associated with a project at given path; return true if successful.
Definition: ProjectFileIO.cpp:1256
ProjectFileIO::GetLastErrorCode
int GetLastErrorCode() const
Definition: ProjectFileIO.cpp:2275
Connection
std::unique_ptr< DBConnection > Connection
Definition: DBConnection.h:154
XO
#define XO(s)
Definition: Internat.h:31
XMLStringWriter
Wrapper to output XML data to strings.
Definition: XMLWriter.h:136
ProjectFileIO::IsTemporary
bool IsTemporary() const
Definition: ProjectFileIO.cpp:2216
ProjectFileIO::Get
static ProjectFileIO & Get(AudacityProject &project)
Definition: ProjectFileIO.cpp:266
ProjectFileIO::CloseConnection
bool CloseConnection()
Definition: ProjectFileIO.cpp:415
audacity
Definition: ErrorReportDialog.h:22
ProjectFileIO::DB
sqlite3 * DB()
Definition: ProjectFileIO.cpp:348
ProjectFileIO::InstallSchema
bool InstallSchema(sqlite3 *db, const char *schema="main")
Definition: ProjectFileIO.cpp:704
SQLiteIniter::mRc
int mRc
Definition: ProjectFileIO.cpp:208
ExecCallback
static int ExecCallback(void *data, int cols, char **vals, char **names)
Definition: ProjectFileIO.cpp:511
ProjectFileSchema
static const char * ProjectFileSchema
Definition: ProjectFileIO.cpp:86
ProjectFileIO::SaveConnection
void SaveConnection()
Definition: ProjectFileIO.cpp:434
InspectBlocks
void InspectBlocks(const TrackList &tracks, BlockInspector inspector, SampleBlockIDSet *pIDs)
Definition: WaveTrack.cpp:2871
ProjectFileIO::mFileName
FilePath mFileName
Definition: ProjectFileIO.h:292
DBConnection::GetAllSampleBlocksSize
@ GetAllSampleBlocksSize
Definition: DBConnection.h:81
ProjectFileID
static const int ProjectFileID
Definition: ProjectFileIO.cpp:61
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:38
SampleBlockID
long long SampleBlockID
Definition: ProjectFileIO.h:39
ProjectFileIO::ShouldCompact
bool ShouldCompact(const std::vector< const TrackList * > &tracks)
Definition: ProjectFileIO.cpp:1079
ProjectFileIO::WriteXML
void WriteXML(XMLWriter &xmlFile, bool recording=false, const TrackList *tracks=nullptr)
Definition: ProjectFileIO.cpp:1646
_TS
#define _TS(s)
Definition: Internat.h:27
DBConnection::DB
sqlite3 * DB()
Definition: DBConnection.cpp:410
ProjectFileIO::Compact
void Compact(const std::vector< const TrackList * > &tracks, bool force=false)
Definition: ProjectFileIO.cpp:1308
ProjectFileIO::mModified
bool mModified
Definition: ProjectFileIO.h:298
ProjectFileIO::mPrevTemporary
bool mPrevTemporary
Definition: ProjectFileIO.h:311
FileNames::IsOnFATFileSystem
FILES_API bool IsOnFATFileSystem(const FilePath &path)
ProjectFileIO::mRecovered
bool mRecovered
Definition: ProjectFileIO.h:295
Track::SubstitutePendingChangedTrack
std::shared_ptr< Track > SubstitutePendingChangedTrack()
Definition: Track.cpp:1198
ProjectFileIO::SetError
void SetError(const TranslatableString &msg, const TranslatableString &libraryError={}, int errorCode={})
Just set stored errors.
Definition: ProjectFileIO.cpp:2285
XMLFileReader::GetErrorStr
const TranslatableString & GetErrorStr() const
Definition: XMLFileReader.cpp:178
FilePath
wxString FilePath
Definition: Project.h:20
ProjectSerializer::GetDict
const wxMemoryBuffer & GetDict() const
Definition: ProjectSerializer.cpp:365
ProjectFileIO::UpdatePrefs
void UpdatePrefs() override
Definition: ProjectFileIO.cpp:1451
ProjectFileIO::CheckVersion
bool CheckVersion()
Definition: ProjectFileIO.cpp:633
ProjectFileIO::InSet
static void InSet(sqlite3_context *context, int argc, sqlite3_value **argv)
Definition: ProjectFileIO.cpp:736
ProjectFileIO::UseConnection
void UseConnection(Connection &&conn, const FilePath &filePath)
Definition: ProjectFileIO.cpp:502
ProjectFileIO::DeleteBlocks
bool DeleteBlocks(const BlockIDs &blockids, bool complement)
Definition: ProjectFileIO.cpp:744
ProjectFileIO::AutoSaveDelete
bool AutoSaveDelete(sqlite3 *db=nullptr)
Definition: ProjectFileIO.cpp:1704
AUDACITY_FILE_FORMAT_VERSION
#define AUDACITY_FILE_FORMAT_VERSION
Definition: ProjectFileIO.cpp:40
ProjectFileIO::DiscardConnection
void DiscardConnection()
Definition: ProjectFileIO.cpp:447
XMLFileReader::ParseString
bool ParseString(XMLTagHandler *baseHandler, const wxString &xmldata)
Definition: XMLFileReader.cpp:136
name
const TranslatableString name
Definition: Distortion.cpp:98
ProjectFileIO::WriteXMLHeader
void WriteXMLHeader(XMLWriter &xmlFile) const
Definition: ProjectFileIO.cpp:1631
ProjectFileIO::WasCompacted
bool WasCompacted()
Definition: ProjectFileIO.cpp:1441
ProjectFileIO::OpenConnection
bool OpenConnection(FilePath fileName={})
Definition: ProjectFileIO.cpp:357
THROW_INCONSISTENCY_EXCEPTION
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Definition: InconsistencyException.h:79
sFileIOKey
static const AudacityProject::AttachedObjects::RegisteredFactory sFileIOKey
Definition: ProjectFileIO.cpp:259
ProjectFileIO::GetTotalUsage
int64_t GetTotalUsage()
Definition: ProjectFileIO.cpp:2359
ProjectFileIO::UpdateSaved
bool UpdateSaved(const TrackList *tracks=nullptr)
Definition: ProjectFileIO.cpp:1926
ProjectFileIO::mPrevFileName
FilePath mPrevFileName
Definition: ProjectFileIO.h:310
XMLMethodRegistry::CallObjectAccessor
XMLTagHandler * CallObjectAccessor(const wxString &tag, Host &host)
Definition: XMLMethodRegistry.h:102
ProjectFileIO::GetLastError
const TranslatableString & GetLastError() const
Definition: ProjectFileIO.cpp:2265
BasicUI::ErrorDialogOptions
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
DBConnection::ThrowException
void ThrowException(bool write) const
throw and show appropriate message box
Definition: DBConnection.cpp:340
ProjectFileIO::GetValue
bool GetValue(const char *sql, wxString &value)
Definition: ProjectFileIO.cpp:561
BlockIDs
std::unordered_set< SampleBlockID > BlockIDs
Definition: ProjectFileIO.h:43
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
ProjectSerializer::GetData
const wxMemoryBuffer & GetData() const
Definition: ProjectSerializer.cpp:370
XMLMethodRegistry::Get
static XMLMethodRegistry & Get()
Get the unique instance.
TrackId
An in-session identifier of track objects across undo states. It does not persist between sessions.
Definition: Track.h:165
BasicUI
Definition: Export.h:39
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
XMLFileReader
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:18
BasicUI::MakeGenericProgress
std::unique_ptr< GenericProgressDialog > MakeGenericProgress(const WindowPlacement &placement, const TranslatableString &title, const TranslatableString &message)
Create and display a progress dialog (return nullptr if Services not installed)
Definition: BasicUI.h:281
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:239
XMLWriter::Write
virtual void Write(const wxString &data)=0
_
#define _(s)
Definition: Internat.h:75
ConnectionPtr::Get
static ConnectionPtr & Get(AudacityProject &project)
Definition: DBConnection.cpp:728
BasicUI::ProgressDialog
Abstraction of a progress dialog with well defined time-to-completion estimate.
Definition: BasicUI.h:154
WaveTrackFactory::GetSampleBlockFactory
const SampleBlockFactoryPtr & GetSampleBlockFactory() const
Definition: WaveTrack.h:729
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
TempDirectory::UnsavedProjectFileName
FILES_API wxString UnsavedProjectFileName()
Definition: TempDirectory.cpp:107
ProjectFileIO::ShowError
void ShowError(const BasicUI::WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage)
Displays an error dialog with a button that offers help.
Definition: ProjectFileIO.cpp:2253
ProjectFileIO::mWasCompacted
bool mWasCompacted
Definition: ProjectFileIO.h:304
ProjectFileIO::Query
bool Query(const char *sql, const ExecCB &callback)
Definition: ProjectFileIO.cpp:548
ProjectFileIO::RenameOrWarn
bool RenameOrWarn(const FilePath &src, const FilePath &dst)
Rename a file or put up appropriate warning message.
Definition: ProjectFileIO.cpp:1179
XMLWriter::WriteAttr
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:34
Verbatim
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
Definition: TranslatableString.h:321
ExceptionType::Internal
@ Internal
Indicates internal failure from Audacity.
TrackList::Create
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:523
ProjectFileIO::GetLastLog
const wxString & GetLastLog() const
Definition: ProjectFileIO.cpp:2280
XMLMethodRegistry::CallWriters
void CallWriters(const Host &host, XMLWriter &writer)
Definition: XMLMethodRegistry.h:173
ProjectFileIO::MoveProject
bool MoveProject(const FilePath &src, const FilePath &dst)
Definition: ProjectFileIO.cpp:1219
FindProjectFrame
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
Definition: ProjectWindows.cpp:88
FileException::WriteFailureMessage
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
Definition: FileException.cpp:60
ProjectFileIO::GetBlob
bool GetBlob(const char *sql, wxMemoryBuffer &buffer)
Definition: ProjectFileIO.cpp:575
audacity::ToWString
std::wstring ToWString(const std::string &str)
Definition: CodeConversions.cpp:34
SQLiteIniter
Definition: ProjectFileIO.cpp:166
ProjectFileIO::IsModified
bool IsModified() const
Definition: ProjectFileIO.cpp:2211
ProjectFileIO::GetDiskUsage
static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid)
Definition: ProjectFileIO.cpp:2372
ActiveProjects::Remove
void Remove(const FilePath &path)
ProjectFileIO::mPrevConn
Connection mPrevConn
Definition: ProjectFileIO.h:309
safenew
#define safenew
Definition: MemoryX.h:10
ADD_EXCEPTION_CONTEXT
#define ADD_EXCEPTION_CONTEXT(name, value)
Definition: SentryHelper.h:21
ActiveProjects::Add
void Add(const FilePath &path)
BlockSpaceUsageAccumulator
std::function< void(const SampleBlock &) > BlockSpaceUsageAccumulator(unsigned long long &total)
Definition: SampleBlock.h:97
ProjectSerializer
a class used to (de)serialize the project catalog
Definition: ProjectSerializer.h:34
SimpleMessageBoxException
A MessageBoxException that shows a given, unvarying string.
Definition: AudacityException.h:95
ProjectFileIO::SetDBError
void SetDBError(const TranslatableString &msg, const TranslatableString &libraryError={}, int errorCode=-1)
Set stored errors and write to log; and default libraryError to what database library reports.
Definition: ProjectFileIO.cpp:2293
DBConnection::GetSampleBlockSize
@ GetSampleBlockSize
Definition: DBConnection.h:80
ProjectFileIO::Exec
int Exec(const char *query, const ExecCB &callback)
Definition: ProjectFileIO.cpp:521
ProjectFileIO::mpErrors
std::shared_ptr< DBConnectionErrors > mpErrors
Definition: ProjectFileIO.h:289
ProjectFileIO::SetProjectTitle
void SetProjectTitle(int number=-1)
Definition: ProjectFileIO.cpp:1457
DBConnection::Prepare
sqlite3_stmt * Prepare(enum StatementID id, const char *sql)
Definition: DBConnection.cpp:427
ProjectFileIO::mProject
AudacityProject & mProject
Definition: ProjectFileIO.h:287
XMLWriter::StartTag
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:76
ProjectFileIO::mHadUnused
bool mHadUnused
Definition: ProjectFileIO.h:307
ProjectFileIO::mTemporary
bool mTemporary
Definition: ProjectFileIO.h:301
ProjectFileIO::CloseProject
bool CloseProject()
Definition: ProjectFileIO.cpp:2168
ProjectFileIO
Object associated with a project that manages reading and writing of Audacity project file formats,...
Definition: ProjectFileIO.h:62
TempDirectory::TempDir
FILES_API wxString TempDir()
Definition: TempDirectory.cpp:26
ProjectFileIO::RestoreConnection
void RestoreConnection()
Definition: ProjectFileIO.cpp:481