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 (wxWindow *parent, 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)
 

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 55 of file ProjectFileIO.h.

Member Typedef Documentation

◆ ExecCB

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

Definition at line 191 of file ProjectFileIO.h.

Constructor & Destructor Documentation

◆ ProjectFileIO() [1/2]

ProjectFileIO::ProjectFileIO ( AudacityProject project)
explicit

Definition at line 278 of file ProjectFileIO.cpp.

279  : mProject{ project }
280  , mpErrors{ std::make_shared<DBConnectionErrors>() }
281 {
282  mPrevConn = nullptr;
283 
284  mRecovered = false;
285  mModified = false;
286  mTemporary = true;
287 
288  UpdatePrefs();
289 }

◆ ProjectFileIO() [2/2]

ProjectFileIO::ProjectFileIO ( const ProjectFileIO )

◆ ~ProjectFileIO()

ProjectFileIO::~ProjectFileIO ( )

Definition at line 291 of file ProjectFileIO.cpp.

292 {
293 }

Member Function Documentation

◆ AutoSave()

bool ProjectFileIO::AutoSave ( bool  recording = false)

Definition at line 1701 of file ProjectFileIO.cpp.

1702 {
1703  ProjectSerializer autosave;
1704  WriteXMLHeader(autosave);
1705  WriteXML(autosave, recording);
1706 
1707  if (WriteDoc("autosave", autosave))
1708  {
1709  mModified = true;
1710  return true;
1711  }
1712 
1713  return false;
1714 }

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 1716 of file ProjectFileIO.cpp.

1717 {
1718  int rc;
1719 
1720  if (!db)
1721  {
1722  db = DB();
1723  }
1724 
1725  rc = sqlite3_exec(db, "DELETE FROM autosave;", nullptr, nullptr, nullptr);
1726  if (rc != SQLITE_OK)
1727  {
1728  SetDBError(
1729  XO("Failed to remove the autosave information from the project file.")
1730  );
1731  return false;
1732  }
1733 
1734  mModified = false;
1735 
1736  return true;
1737 }

References 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 1071 of file ProjectFileIO.cpp.

1072 {
1073  static const std::vector<wxString> strings {
1074  "-wal",
1075 #ifndef NO_SHM
1076  "-shm",
1077 #endif
1078  };
1079  return strings;
1080 }

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 604 of file ProjectFileIO.cpp.

605 {
606  auto db = DB();
607  int rc;
608 
609  // Install our schema if this is an empty DB
610  wxString result;
611  if (!GetValue("SELECT Count(*) FROM sqlite_master WHERE type='table';", result))
612  {
613  // Bug 2718 workaround for a better error message:
614  // If at this point we get SQLITE_CANTOPEN, then the directory is read-only
615  if (GetLastErrorCode() == SQLITE_CANTOPEN)
616  {
617  SetError(
618  /* i18n-hint: An error message. */
619  XO("Project is in a read only directory\n(Unable to create the required temporary files)"),
621  );
622  }
623 
624  return false;
625  }
626 
627  // If the return count is zero, then there are no tables defined, so this
628  // must be a new project file.
629  if (wxStrtol<char **>(result, nullptr, 10) == 0)
630  {
631  return InstallSchema(db);
632  }
633 
634  // Check for our application ID
635  if (!GetValue("PRAGMA application_ID;", result))
636  {
637  return false;
638  }
639 
640  // It's a database that SQLite recognizes, but it's not one of ours
641  if (wxStrtoul<char **>(result, nullptr, 10) != ProjectFileID)
642  {
643  SetError(XO("This is not an Audacity project file"));
644  return false;
645  }
646 
647  // Get the project file version
648  if (!GetValue("PRAGMA user_version;", result))
649  {
650  return false;
651  }
652 
653  long version = wxStrtol<char **>(result, nullptr, 10);
654 
655  // Project file version is higher than ours. We will refuse to
656  // process it since we can't trust anything about it.
657  if (version > ProjectFileVersion)
658  {
659  SetError(
660  XO("This project was created with a newer version of Audacity.\n\nYou will need to upgrade to open it.")
661  );
662  return false;
663  }
664 
665  // Project file is older than ours, ask the user if it's okay to
666  // upgrade.
667  if (version < ProjectFileVersion)
668  {
669  return UpgradeSchema();
670  }
671 
672  return true;
673 }

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 397 of file ProjectFileIO.cpp.

398 {
399  auto &curConn = CurrConn();
400  if (!curConn)
401  return false;
402 
403  if (!curConn->Close())
404  {
405  return false;
406  }
407  curConn.reset();
408 
409  SetFileName({});
410 
411  return true;
412 }

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 1250 of file ProjectFileIO.cpp.

1252 {
1253  // Haven't compacted yet
1254  mWasCompacted = false;
1255 
1256  // Assume we have unused blocks until we find out otherwise. That way cleanup
1257  // at project close time will still occur.
1258  mHadUnused = true;
1259 
1260  // If forcing compaction, bypass inspection.
1261  if (!force)
1262  {
1263  // Don't compact if this is a temporary project or if it's determined there are not
1264  // enough unused blocks to make it worthwhile.
1265  if (IsTemporary() || !ShouldCompact(tracks))
1266  {
1267  // Delete the AutoSave doc it if exists
1268  if (IsModified())
1269  {
1270  // PRL: not clear what to do if the following fails, but the worst should
1271  // be, the project may reopen in its present state as a recovery file, not
1272  // at the last saved state.
1273  // REVIEW: Could the autosave file be corrupt though at that point, and so
1274  // prevent recovery?
1275  // LLL: I believe Paul is correct since it's deleted with a single SQLite
1276  // transaction. The next time the file opens will just invoke recovery.
1277  (void) AutoSaveDelete();
1278  }
1279 
1280  return;
1281  }
1282  }
1283 
1284  wxString origName = mFileName;
1285  wxString backName = origName + "_compact_back";
1286  wxString tempName = origName + "_compact_temp";
1287 
1288  // Copy the original database to a new database. Only prune sample blocks if
1289  // we have a tracklist.
1290  // REVIEW: Compact can fail on the CopyTo with no error messages. That's OK?
1291  // LLL: We could display an error message or just ignore the failure and allow
1292  // the file to be compacted the next time it's saved.
1293  if (CopyTo(tempName, XO("Compacting project"), IsTemporary(), !tracks.empty(), tracks))
1294  {
1295  // Must close the database to rename it
1296  if (CloseConnection())
1297  {
1298  // Only use the new file if it is actually smaller than the original.
1299  //
1300  // If the original file doesn't have anything to compact (original and new
1301  // are basically identical), the file could grow by a few pages because of
1302  // differences in how SQLite constructs the b-tree.
1303  //
1304  // In this case, just toss the new file and continue to use the original.
1305  //
1306  // Also, do this after closing the connection so that the -wal file
1307  // gets cleaned up.
1308  if (wxFileName::GetSize(tempName) < wxFileName::GetSize(origName))
1309  {
1310  // Rename the original to backup
1311  if (wxRenameFile(origName, backName))
1312  {
1313  // Rename the temporary to original
1314  if (wxRenameFile(tempName, origName))
1315  {
1316  // Open the newly compacted original file
1317  if (OpenConnection(origName))
1318  {
1319  // Remove the old original file
1320  if (!wxRemoveFile(backName))
1321  {
1322  // Just log the error, nothing can be done to correct it
1323  // and WX should have logged another message showing the
1324  // system error code.
1325  wxLogWarning(wxT("Compaction failed to delete backup %s"), backName);
1326  }
1327 
1328  // Remember that we compacted
1329  mWasCompacted = true;
1330 
1331  return;
1332  }
1333  else
1334  {
1335  wxLogWarning(wxT("Compaction failed to open new project %s"), origName);
1336  }
1337 
1338  if (!wxRenameFile(origName, tempName))
1339  {
1340  wxLogWarning(wxT("Compaction failed to rename orignal %s to temp %s"),
1341  origName, tempName);
1342  }
1343  }
1344  else
1345  {
1346  wxLogWarning(wxT("Compaction failed to rename temp %s to orig %s"),
1347  origName, tempName);
1348  }
1349 
1350  if (!wxRenameFile(backName, origName))
1351  {
1352  wxLogWarning(wxT("Compaction failed to rename back %s to orig %s"),
1353  backName, origName);
1354  }
1355  }
1356  else
1357  {
1358  wxLogWarning(wxT("Compaction failed to rename orig %s to back %s"),
1359  backName, origName);
1360  }
1361  }
1362 
1363  if (!OpenConnection(origName))
1364  {
1365  wxLogWarning(wxT("Compaction failed to reopen %s"), origName);
1366  }
1367  }
1368 
1369  // Did not achieve any real compaction
1370  // RemoveProject not needed for what was an attached database
1371  if (!wxRemoveFile(tempName))
1372  {
1373  // Just log the error, nothing can be done to correct it
1374  // and WX should have logged another message showing the
1375  // system error code.
1376  wxLogWarning(wxT("Failed to delete temporary file...ignoring"));
1377  }
1378  }
1379 
1380  return;
1381 }

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 784 of file ProjectFileIO.cpp.

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

References CurrConn(), DB(), InspectBlocks(), InstallSchema(), mProject, pdlgHideStopButton, Query(), SetDBError(), 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 1065 of file ProjectFileIO.cpp.

1066 {
1067  auto &connectionPtr = ConnectionPtr::Get( mProject );
1068  return connectionPtr.mpConnection;
1069 }

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 330 of file ProjectFileIO.cpp.

331 {
332  return GetConnection().DB();
333 }

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 715 of file ProjectFileIO.cpp.

716 {
717  auto db = DB();
718  int rc;
719 
720  auto cleanup = finally([&]
721  {
722  // Remove our function, whether it was successfully defined or not.
723  sqlite3_create_function(db, "inset", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr, nullptr, nullptr, nullptr);
724  });
725 
726  // Add the function used to verify each row's blockid against the set of active blockids
727  const void *p = &blockids;
728  rc = sqlite3_create_function(db, "inset", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, const_cast<void*>(p), InSet, nullptr, nullptr);
729  if (rc != SQLITE_OK)
730  {
731  /* i18n-hint: An error message. Don't translate inset or blockids.*/
732  SetDBError(XO("Unable to add 'inset' function (can't verify blockids)"));
733  return false;
734  }
735 
736  // Delete all rows in the set, or not in it
737  // This is the first command that writes to the database, and so we
738  // do more informative error reporting than usual, if it fails.
739  auto sql = wxString::Format(
740  "DELETE FROM sampleblocks WHERE %sinset(blockid);",
741  complement ? "NOT " : "" );
742  rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
743  if (rc != SQLITE_OK)
744  {
745  if( rc==SQLITE_READONLY)
746  /* i18n-hint: An error message. Don't translate blockfiles.*/
747  SetDBError(XO("Project is read only\n(Unable to work with the blockfiles)"));
748  else if( rc==SQLITE_LOCKED)
749  /* i18n-hint: An error message. Don't translate blockfiles.*/
750  SetDBError(XO("Project is locked\n(Unable to work with the blockfiles)"));
751  else if( rc==SQLITE_BUSY)
752  /* i18n-hint: An error message. Don't translate blockfiles.*/
753  SetDBError(XO("Project is busy\n(Unable to work with the blockfiles)"));
754  else if( rc==SQLITE_CORRUPT)
755  /* i18n-hint: An error message. Don't translate blockfiles.*/
756  SetDBError(XO("Project is corrupt\n(Unable to work with the blockfiles)"));
757  else if( rc==SQLITE_PERM)
758  /* i18n-hint: An error message. Don't translate blockfiles.*/
759  SetDBError(XO("Some permissions issue\n(Unable to work with the blockfiles)"));
760  else if( rc==SQLITE_IOERR)
761  /* i18n-hint: An error message. Don't translate blockfiles.*/
762  SetDBError(XO("A disk I/O error\n(Unable to work with the blockfiles)"));
763  else if( rc==SQLITE_AUTH)
764  /* i18n-hint: An error message. Don't translate blockfiles.*/
765  SetDBError(XO("Not authorized\n(Unable to work with the blockfiles)"));
766  else
767  /* i18n-hint: An error message. Don't translate blockfiles.*/
768  SetDBError(XO("Unable to work with the blockfiles"));
769 
770  return false;
771  }
772 
773  // Mark the project recovered if we deleted any rows
774  int changes = sqlite3_changes(db);
775  if (changes > 0)
776  {
777  wxLogInfo(XO("Total orphan blocks deleted %d").Translation(), changes);
778  mRecovered = true;
779  }
780 
781  return true;
782 }

References 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 429 of file ProjectFileIO.cpp.

430 {
431  if (mPrevConn)
432  {
433  if (!mPrevConn->Close())
434  {
435  // Store an error message
436  SetDBError(
437  XO("Failed to discard connection")
438  );
439  }
440 
441  // If this is a temporary project, we no longer want to keep the
442  // project file.
443  if (mPrevTemporary)
444  {
445  // This is just a safety check.
446  wxFileName temp(TempDirectory::TempDir(), wxT(""));
447  wxFileName file(mPrevFileName);
448  file.SetFullName(wxT(""));
449  if (file == temp)
450  {
452  {
453  wxLogMessage("Failed to remove temporary project %s", mPrevFileName);
454  }
455  }
456  }
457  mPrevConn = nullptr;
458  mPrevFileName.clear();
459  }
460 }

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 503 of file ProjectFileIO.cpp.

504 {
505  char *errmsg = nullptr;
506 
507  const void *ptr = &callback;
508  int rc = sqlite3_exec(DB(), query, ExecCallback,
509  const_cast<void*>(ptr), &errmsg);
510 
511  if (rc != SQLITE_ABORT && errmsg)
512  {
513  SetDBError(
514  XO("Failed to execute a project file command:\n\n%s").Format(query),
515  Verbatim(errmsg),
516  rc
517  );
518  }
519  if (errmsg)
520  {
521  sqlite3_free(errmsg);
522  }
523 
524  return rc;
525 }

References 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 320 of file ProjectFileIO.cpp.

321 {
322  auto &trackList = TrackList::Get( mProject );
323 
324  XMLStringWriter doc;
325  WriteXMLHeader(doc);
326  WriteXML(doc, false, trackList.empty() ? nullptr : &trackList);
327  return doc;
328 }

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 267 of file ProjectFileIO.cpp.

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

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::FillBuffers(), 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::OpenFile(), ProjectFileManager::OpenNewProject(), ProjectFileManager::OpenProject(), ProjectManager::OpenProject(), ProjectHistory::PopState(), AutoRecoveryDialog::PopulateList(), TimerRecordDialog::PopulateOrExchange(), ProjectHistory::PushState(), ProjectFileManager::ReadProjectFile(), RefreshAllTitles(), ProjectManager::ResetProjectToEmpty(), ProjectFileManager::Save(), ProjectFileManager::SaveAs(), ProjectFileManager::SaveCopy(), ProjectFileManager::SaveFromTimerRecording(), AudioIO::StopStream(), UnsavedChangesFlag(), and InvisibleTemporaryProject::~InvisibleTemporaryProject().

Here is the caller graph for this function:

◆ Get() [2/2]

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

Definition at line 273 of file ProjectFileIO.cpp.

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

References Get().

Here is the call graph for this function:

◆ get2()

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

Definition at line 2577 of file ProjectFileIO.cpp.

2578 {
2579  return (ptr[0] << 8) | ptr[1];
2580 }

Referenced by GetDiskUsage().

Here is the caller graph for this function:

◆ get4()

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

Definition at line 2583 of file ProjectFileIO.cpp.

2584 {
2585  return ((unsigned int) ptr[0] << 24) |
2586  ((unsigned int) ptr[1] << 16) |
2587  ((unsigned int) ptr[2] << 8) |
2588  ((unsigned int) ptr[3]);
2589 }

Referenced by GetDiskUsage().

Here is the caller graph for this function:

◆ get_varint()

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

Definition at line 2594 of file ProjectFileIO.cpp.

2595 {
2596  int64_t val = 0;
2597  int i;
2598 
2599  for (i = 0; i < 8; ++i)
2600  {
2601  val = (val << 7) + (ptr[i] & 0x7f);
2602  if ((ptr[i] & 0x80) == 0)
2603  {
2604  *out = val;
2605  return i + 1;
2606  }
2607  }
2608 
2609  val = (val << 8) + (ptr[i] & 0xff);
2610  *out = val;
2611 
2612  return 9;
2613 }

Referenced by GetDiskUsage().

Here is the caller graph for this function:

◆ GetBlob()

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

Definition at line 554 of file ProjectFileIO.cpp.

555 {
556  auto db = DB();
557  int rc;
558 
559  buffer.Clear();
560 
561  sqlite3_stmt *stmt = nullptr;
562  auto cleanup = finally([&]
563  {
564  if (stmt)
565  {
566  sqlite3_finalize(stmt);
567  }
568  });
569 
570  rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
571  if (rc != SQLITE_OK)
572  {
573  SetDBError(
574  XO("Unable to prepare project file command:\n\n%s").Format(sql)
575  );
576  return false;
577  }
578 
579  rc = sqlite3_step(stmt);
580 
581  // A row wasn't found...not an error
582  if (rc == SQLITE_DONE)
583  {
584  return true;
585  }
586 
587  if (rc != SQLITE_ROW)
588  {
589  SetDBError(
590  XO("Failed to retrieve data from the project file.\nThe following command failed:\n\n%s").Format(sql)
591  );
592  // AUD TODO handle error
593  return false;
594  }
595 
596  const void *blob = sqlite3_column_blob(stmt, 0);
597  int size = sqlite3_column_bytes(stmt, 0);
598 
599  buffer.AppendData(blob, size);
600 
601  return true;
602 }

References DB(), SetDBError(), 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 2331 of file ProjectFileIO.cpp.

2332 {
2333  auto pConn = CurrConn().get();
2334  if (!pConn)
2335  return 0;
2336  return GetDiskUsage(*pConn, blockid);
2337 }

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 301 of file ProjectFileIO.cpp.

302 {
303  auto &curConn = CurrConn();
304  if (!curConn)
305  {
306  if (!OpenConnection())
307  {
309  {
310  XO("Failed to open the project's database"),
311  XO("Warning"),
312  "Error:_Disk_full_or_not_writable"
313  };
314  }
315  }
316 
317  return *curConn;
318 }

References CurrConn(), 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 2339 of file ProjectFileIO.cpp.

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

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 2369 of file ProjectFileIO.cpp.

2370 {
2371  // Information we need to track our travels through the b-tree
2372  typedef struct
2373  {
2374  int64_t pgno;
2375  int currentCell;
2376  int numCells;
2377  unsigned char data[65536];
2378  } page;
2379  std::vector<page> stack;
2380 
2381  int64_t total = 0;
2382  int64_t found = 0;
2383  int64_t right = 0;
2384  int rc;
2385 
2386  // Get the rootpage for the sampleblocks table.
2387  sqlite3_stmt *stmt =
2389  "SELECT rootpage FROM sqlite_master WHERE tbl_name = 'sampleblocks';");
2390  if (stmt == nullptr || sqlite3_step(stmt) != SQLITE_ROW)
2391  {
2392  return 0;
2393  }
2394 
2395  // And store it in our first stack frame
2396  stack.push_back({sqlite3_column_int64(stmt, 0)});
2397 
2398  // All done with the statement
2399  sqlite3_clear_bindings(stmt);
2400  sqlite3_reset(stmt);
2401 
2402  // Prepare/retrieve statement to read raw database page
2403  stmt = conn.Prepare(DBConnection::GetDBPage,
2404  "SELECT data FROM sqlite_dbpage WHERE pgno = ?1;");
2405  if (stmt == nullptr)
2406  {
2407  return 0;
2408  }
2409 
2410  // Traverse the b-tree until we've visited all of the leaf pages or until
2411  // we find the one corresponding to the passed in sample blockid. Because we
2412  // use an integer primary key for the sampleblocks table, the traversal will
2413  // be in ascending blockid sequence.
2414  do
2415  {
2416  // Acces the top stack frame
2417  page &pg = stack.back();
2418 
2419  // Read the page from the sqlite_dbpage table if it hasn't yet been loaded
2420  if (pg.numCells == 0)
2421  {
2422  // Bind the page number
2423  sqlite3_bind_int64(stmt, 1, pg.pgno);
2424 
2425  // And retrieve the page
2426  if (sqlite3_step(stmt) != SQLITE_ROW)
2427  {
2428  // REVIEW: Likely harmless failure - says size is zero on
2429  // this error.
2430  // LLL: Yea, but not much else we can do.
2431  return 0;
2432  }
2433 
2434  // Copy the page content to the stack frame
2435  memcpy(&pg.data,
2436  sqlite3_column_blob(stmt, 0),
2437  sqlite3_column_bytes(stmt, 0));
2438 
2439  // And retrieve the total number of cells within it
2440  pg.numCells = get2(&pg.data[3]);
2441 
2442  // Reset statement for next usage
2443  sqlite3_clear_bindings(stmt);
2444  sqlite3_reset(stmt);
2445  }
2446 
2447  //wxLogDebug("%*.*spgno %lld currentCell %d numCells %d", (stack.size() - 1) * 2, (stack.size() - 1) * 2, "", pg.pgno, pg.currentCell, pg.numCells);
2448 
2449  // Process an interior table b-tree page
2450  if (pg.data[0] == 0x05)
2451  {
2452  // Process the next cell if we haven't examined all of them yet
2453  if (pg.currentCell < pg.numCells)
2454  {
2455  // Remember the right-most leaf page number.
2456  right = get4(&pg.data[8]);
2457 
2458  // Iterate over the cells.
2459  //
2460  // If we're not looking for a specific blockid, then we always push the
2461  // target page onto the stack and leave the loop after a single iteration.
2462  //
2463  // Otherwise, we match the blockid against the highest integer key contained
2464  // within the cell and if the blockid falls within the cell, we stack the
2465  // page and stop the iteration.
2466  //
2467  // In theory, we could do a binary search for a specific blockid here, but
2468  // because our sample blocks are always large, we will get very few cells
2469  // per page...usually 6 or less.
2470  //
2471  // In both cases, the stacked page can be either an internal or leaf page.
2472  bool stacked = false;
2473  while (pg.currentCell < pg.numCells)
2474  {
2475  // Get the offset to this cell using the offset in the cell pointer
2476  // array.
2477  //
2478  // The cell pointer array starts immediately after the page header
2479  // at offset 12 and the retrieved offset is from the beginning of
2480  // the page.
2481  int celloff = get2(&pg.data[12 + (pg.currentCell * 2)]);
2482 
2483  // Bump to the next cell for the next iteration.
2484  pg.currentCell++;
2485 
2486  // Get the page number this cell describes
2487  int pagenum = get4(&pg.data[celloff]);
2488 
2489  // And the highest integer key, which starts at offset 4 within the cell.
2490  int64_t intkey = 0;
2491  get_varint(&pg.data[celloff + 4], &intkey);
2492 
2493  //wxLogDebug("%*.*sinternal - right %lld celloff %d pagenum %d intkey %lld", (stack.size() - 1) * 2, (stack.size() - 1) * 2, " ", right, celloff, pagenum, intkey);
2494 
2495  // Stack the described page if we're not looking for a specific blockid
2496  // or if this page contains the given blockid.
2497  if (!blockid || blockid <= intkey)
2498  {
2499  stack.push_back({pagenum, 0, 0});
2500  stacked = true;
2501  break;
2502  }
2503  }
2504 
2505  // If we pushed a new page onto the stack, we need to jump back up
2506  // to read the page
2507  if (stacked)
2508  {
2509  continue;
2510  }
2511  }
2512 
2513  // We've exhausted all the cells with this page, so we stack the right-most
2514  // leaf page. Ensure we only process it once.
2515  if (right)
2516  {
2517  stack.push_back({right, 0, 0});
2518  right = 0;
2519  continue;
2520  }
2521  }
2522  // Process a leaf table b-tree page
2523  else if (pg.data[0] == 0x0d)
2524  {
2525  // Iterate over the cells
2526  //
2527  // If we're not looking for a specific blockid, then just accumulate the
2528  // payload sizes. We will be reading every leaf page in the sampleblocks
2529  // table.
2530  //
2531  // Otherwise we break out when we find the matching blockid. In this case,
2532  // we only ever look at 1 leaf page.
2533  bool stop = false;
2534  for (int i = 0; i < pg.numCells; i++)
2535  {
2536  // Get the offset to this cell using the offset in the cell pointer
2537  // array.
2538  //
2539  // The cell pointer array starts immediately after the page header
2540  // at offset 8 and the retrieved offset is from the beginning of
2541  // the page.
2542  int celloff = get2(&pg.data[8 + (i * 2)]);
2543 
2544  // Get the total payload size in bytes of the described row.
2545  int64_t payload = 0;
2546  int digits = get_varint(&pg.data[celloff], &payload);
2547 
2548  // Get the integer key for this row.
2549  int64_t intkey = 0;
2550  get_varint(&pg.data[celloff + digits], &intkey);
2551 
2552  //wxLogDebug("%*.*sleaf - celloff %4d intkey %lld payload %lld", (stack.size() - 1) * 2, (stack.size() - 1) * 2, " ", celloff, intkey, payload);
2553 
2554  // Add this payload size to the total if we're not looking for a specific
2555  // blockid
2556  if (!blockid)
2557  {
2558  total += payload;
2559  }
2560  // Otherwise, return the payload size for a matching row
2561  else if (blockid == intkey)
2562  {
2563  return payload;
2564  }
2565  }
2566  }
2567 
2568  // Done with the current branch, so pop back up to the previous one (if any)
2569  stack.pop_back();
2570  } while (!stack.empty());
2571 
2572  // Return the total used for all sample blocks
2573  return total;
2574 }

References get2(), get4(), get_varint(), DBConnection::GetDBPage, DBConnection::GetRootPage, and DBConnection::Prepare().

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 1444 of file ProjectFileIO.cpp.

1445 {
1446  return mFileName;
1447 }

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 2261 of file ProjectFileIO.cpp.

2262 {
2263  return mpErrors->mLastError;
2264 }

References mpErrors.

Referenced by SaveProject().

Here is the caller graph for this function:

◆ GetLastErrorCode()

int ProjectFileIO::GetLastErrorCode ( ) const

Definition at line 2271 of file ProjectFileIO.cpp.

2272 {
2273  return mpErrors->mErrorCode;
2274 }

References mpErrors.

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ GetLastLog()

const wxString & ProjectFileIO::GetLastLog ( ) const

Definition at line 2276 of file ProjectFileIO.cpp.

2277 {
2278  return mpErrors->mLog;
2279 }

References mpErrors.

Referenced by ShowError().

Here is the caller graph for this function:

◆ GetLibraryError()

const TranslatableString & ProjectFileIO::GetLibraryError ( ) const

Definition at line 2266 of file ProjectFileIO.cpp.

2267 {
2268  return mpErrors->mLibraryError;
2269 }

References mpErrors.

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ GetTotalUsage()

int64_t ProjectFileIO::GetTotalUsage ( )

Definition at line 2355 of file ProjectFileIO.cpp.

2356 {
2357  auto pConn = CurrConn().get();
2358  if (!pConn)
2359  return 0;
2360  return GetDiskUsage(*pConn, 0);
2361 }

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 540 of file ProjectFileIO.cpp.

541 {
542  // Retrieve the first column in the first row, if any
543  result.clear();
544  auto cb = [&result](int cols, char **vals, char **){
545  if (cols > 0)
546  result = vals[0];
547  // Stop after one row
548  return 1;
549  };
550 
551  return Query(sql, cb);
552 }

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 1388 of file ProjectFileIO.cpp.

1389 {
1390  return mHadUnused;
1391 }

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 1611 of file ProjectFileIO.cpp.

1612 {
1613  auto &project = mProject;
1614  auto fn = ProjectFileIORegistry::Lookup(tag);
1615  if (fn)
1616  {
1617  return fn(project);
1618  }
1619 
1620  return nullptr;
1621 }

References fn, ProjectFileIORegistry::Lookup(), 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 1477 of file ProjectFileIO.cpp.

1478 {
1479  auto &project = mProject;
1480  auto &window = GetProjectFrame(project);
1481  auto &viewInfo = ViewInfo::Get(project);
1482  auto &settings = ProjectSettings::Get(project);
1483 
1484  wxString fileVersion;
1485  wxString audacityVersion;
1486  int requiredTags = 0;
1487  long longVpos = 0;
1488 
1489  // loop through attrs, which is a null-terminated list of
1490  // attribute-value pairs
1491  while (*attrs)
1492  {
1493  const wxChar *attr = *attrs++;
1494  const wxChar *value = *attrs++;
1495 
1496  if (!value || !XMLValueChecker::IsGoodString(value))
1497  {
1498  break;
1499  }
1500 
1501  if (viewInfo.ReadXMLAttribute(attr, value))
1502  {
1503  // We need to save vpos now and restore it below
1504  longVpos = std::max(longVpos, long(viewInfo.vpos));
1505  continue;
1506  }
1507 
1508  else if (!wxStrcmp(attr, wxT("version")))
1509  {
1510  fileVersion = value;
1511  requiredTags++;
1512  }
1513 
1514  else if (!wxStrcmp(attr, wxT("audacityversion")))
1515  {
1516  audacityVersion = value;
1517  requiredTags++;
1518  }
1519 
1520  else if (!wxStrcmp(attr, wxT("rate")))
1521  {
1522  double rate;
1523  Internat::CompatibleToDouble(value, &rate);
1524  settings.SetRate( rate );
1525  }
1526 
1527  else if (!wxStrcmp(attr, wxT("snapto")))
1528  {
1529  settings.SetSnapTo(wxString(value) == wxT("on") ? true : false);
1530  }
1531 
1532  else if (!wxStrcmp(attr, wxT("selectionformat")))
1533  {
1534  settings.SetSelectionFormat(
1536  }
1537 
1538  else if (!wxStrcmp(attr, wxT("audiotimeformat")))
1539  {
1540  settings.SetAudioTimeFormat(
1542  }
1543 
1544  else if (!wxStrcmp(attr, wxT("frequencyformat")))
1545  {
1546  settings.SetFrequencySelectionFormatName(
1548  }
1549 
1550  else if (!wxStrcmp(attr, wxT("bandwidthformat")))
1551  {
1552  settings.SetBandwidthSelectionFormatName(
1554  }
1555  } // while
1556 
1557  if (longVpos != 0)
1558  {
1559  // PRL: It seems this must happen after SetSnapTo
1560  viewInfo.vpos = longVpos;
1561  }
1562 
1563  if (requiredTags < 2)
1564  {
1565  return false;
1566  }
1567 
1568  // Parse the file version from the project
1569  int fver;
1570  int frel;
1571  int frev;
1572  if (!wxSscanf(fileVersion, wxT("%i.%i.%i"), &fver, &frel, &frev))
1573  {
1574  return false;
1575  }
1576 
1577  // Parse the file version Audacity was build with
1578  int cver;
1579  int crel;
1580  int crev;
1581  wxSscanf(wxT(AUDACITY_FILE_FORMAT_VERSION), wxT("%i.%i.%i"), &cver, &crel, &crev);
1582 
1583  int fileVer = ((fver *100)+frel)*100+frev;
1584  int codeVer = ((cver *100)+crel)*100+crev;
1585 
1586  if (codeVer<fileVer)
1587  {
1588  /* i18n-hint: %s will be replaced by the version number.*/
1589  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.")
1590  .Format(audacityVersion, AUDACITY_VERSION_STRING);
1591 
1592  ShowError(
1593  &window,
1594  XO("Can't open project file"),
1595  msg,
1596  "FAQ:Errors_opening_an_Audacity_project"
1597  );
1598 
1599  return false;
1600  }
1601 
1602  if (wxStrcmp(tag, wxT("project")))
1603  {
1604  return false;
1605  }
1606 
1607  // All other tests passed, so we succeed
1608  return true;
1609 }

References AUDACITY_FILE_FORMAT_VERSION, NumericConverter::BANDWIDTH, Internat::CompatibleToDouble(), NumericConverter::FREQUENCY, ProjectSettings::Get(), ViewInfo::Get(), GetProjectFrame(), XMLValueChecker::IsGoodString(), NumericConverter::LookupFormat(), mProject, settings(), ShowError(), NumericConverter::TIME, 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 295 of file ProjectFileIO.cpp.

296 {
297  auto &connectionPtr = ConnectionPtr::Get( mProject );
298  return connectionPtr.mpConnection != nullptr;
299 }

References ConnectionPtr::Get(), and mProject.

Here is the call graph for this function:

◆ InitializeSQL()

bool ProjectFileIO::InitializeSQL ( )
static

Definition at line 212 of file ProjectFileIO.cpp.

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

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 707 of file ProjectFileIO.cpp.

708 {
709  BlockIDs *blockids = (BlockIDs *) sqlite3_user_data(context);
710  SampleBlockID blockid = sqlite3_value_int64(argv[0]);
711 
712  sqlite3_result_int(context, blockids->find(blockid) != blockids->end());
713 }

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 675 of file ProjectFileIO.cpp.

676 {
677  int rc;
678 
679  wxString sql;
681  sql.Replace("<schema>", schema);
682 
683  rc = sqlite3_exec(db, sql, nullptr, nullptr, nullptr);
684  if (rc != SQLITE_OK)
685  {
686  SetDBError(
687  XO("Unable to initialize the project file")
688  );
689  return false;
690  }
691 
692  return true;
693 }

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 1801 of file ProjectFileIO.cpp.

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

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 1161 of file ProjectFileIO.cpp.

1162 {
1163  // Assume the src database file is not busy.
1164  if (!RenameOrWarn(src, dst))
1165  return false;
1166 
1167  // So far so good, but the separate -wal and -shm files might yet exist,
1168  // as when checkpointing failed for limited space on the drive.
1169  // If so move them too or else lose data.
1170 
1171  std::vector< std::pair<FilePath, FilePath> > pairs{ { src, dst } };
1172  bool success = false;
1173  auto cleanup = finally([&]{
1174  if (!success) {
1175  // If any one of the renames failed, back out the previous ones.
1176  // This should be a no-fail recovery! Not clear what to do if any
1177  // of these renames fails.
1178  for (auto &pair : pairs) {
1179  if (!(pair.first.empty() && pair.second.empty()))
1180  wxRenameFile(pair.second, pair.first);
1181  }
1182  }
1183  });
1184 
1185  for (const auto &suffix : AuxiliaryFileSuffixes()) {
1186  auto srcName = src + suffix;
1187  if (wxFileExists(srcName)) {
1188  auto dstName = dst + suffix;
1189  if (!RenameOrWarn(srcName, dstName))
1190  return false;
1191  pairs.push_back({ srcName, dstName });
1192  }
1193  }
1194 
1195  return (success = true);
1196 }

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 1623 of file ProjectFileIO.cpp.

1624 {
1625  wxCommandEvent evt{ EVT_CHECKPOINT_FAILURE };
1626  mProject.ProcessEvent(evt);
1627 }

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 339 of file ProjectFileIO.cpp.

340 {
341  auto &curConn = CurrConn();
342  wxASSERT(!curConn);
343  bool isTemp = false;
344 
345  if (fileName.empty())
346  {
347  fileName = GetFileName();
348  if (fileName.empty())
349  {
351  isTemp = true;
352  }
353  }
354  else
355  {
356  // If this project resides in the temporary directory, then we'll mark it
357  // as temporary.
358  wxFileName temp(TempDirectory::TempDir(), wxT(""));
359  wxFileName file(fileName);
360  file.SetFullName(wxT(""));
361  if (file == temp)
362  {
363  isTemp = true;
364  }
365  }
366 
367  // Pass weak_ptr to project into DBConnection constructor
368  curConn = std::make_unique<DBConnection>(
369  mProject.shared_from_this(), mpErrors, [this]{ OnCheckpointFailure(); } );
370  auto rc = curConn->Open(fileName);
371  if (rc != SQLITE_OK)
372  {
373  // Must use SetError() here since we do not have an active DB
374  SetError(
375  XO("Failed to open database file:\n\n%s").Format(fileName),
376  {},
377  rc
378  );
379  curConn.reset();
380  return false;
381  }
382 
383  if (!CheckVersion())
384  {
385  CloseConnection();
386  curConn.reset();
387  return false;
388  }
389 
390  mTemporary = isTemp;
391 
392  SetFileName(fileName);
393 
394  return true;
395 }

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 527 of file ProjectFileIO.cpp.

528 {
529  int rc = Exec(sql, callback);
530  // SQLITE_ABORT is a non-error return only meaning the callback
531  // stopped the iteration of rows early
532  if ( !(rc == SQLITE_OK || rc == SQLITE_ABORT) )
533  {
534  return false;
535  }
536 
537  return true;
538 }

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 1198 of file ProjectFileIO.cpp.

1199 {
1200  if (!wxFileExists(filename))
1201  return false;
1202 
1203  bool success = wxRemoveFile(filename);
1204  auto &suffixes = AuxiliaryFileSuffixes();
1205  for (const auto &suffix : suffixes) {
1206  auto file = filename + suffix;
1207  if (wxFileExists(file))
1208  success = wxRemoveFile(file) && success;
1209  }
1210  return success;
1211 }

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 1117 of file ProjectFileIO.cpp.

1118 {
1119  std::atomic_bool done = {false};
1120  bool success = false;
1121  auto thread = std::thread([&]
1122  {
1123  success = wxRenameFile(src, dst);
1124  done = true;
1125  });
1126 
1127  auto &window = GetProjectFrame( mProject );
1128 
1129  // Provides a progress dialog with indeterminate mode
1130  wxGenericProgressDialog pd(XO("Copying Project").Translation(),
1131  XO("This may take several seconds").Translation(),
1132  300000, // range
1133  &window, // parent
1134  wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH);
1135 
1136  // Wait for the checkpoints to end
1137  while (!done)
1138  {
1139  wxMilliSleep(50);
1140  pd.Pulse();
1141  }
1142  thread.join();
1143 
1144  if (!success)
1145  {
1146  ShowError(
1147  &window,
1148  XO("Error Writing to File"),
1149  XO("Audacity failed to write file %s.\n"
1150  "Perhaps disk is full or not writable.\n"
1151  "For tips on freeing up space, click the help button.")
1152  .Format(dst),
1153  "Error:_Disk_full_or_not_writable"
1154  );
1155  return false;
1156  }
1157 
1158  return true;
1159 }

References GetProjectFrame(), mProject, 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 463 of file ProjectFileIO.cpp.

464 {
465  auto &curConn = CurrConn();
466  if (curConn)
467  {
468  if (!curConn->Close())
469  {
470  // Store an error message
471  SetDBError(
472  XO("Failed to restore connection")
473  );
474  }
475  }
476 
477  curConn = std::move(mPrevConn);
480 
481  mPrevFileName.clear();
482 }

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 1082 of file ProjectFileIO.cpp.

1083 {
1084  wxFileNameWrapper fn{ src };
1085 
1086  // Extra characters inserted into filename before extension
1087  wxString extra =
1088 #ifdef __WXGTK__
1089  wxT("~")
1090 #else
1091  wxT(".bak")
1092 #endif
1093  ;
1094 
1095  int nn = 1;
1096  auto numberString = [](int num) -> wxString {
1097  return num == 1 ? "" : wxString::Format(".%d", num);
1098  };
1099 
1100  auto suffixes = AuxiliaryFileSuffixes();
1101  suffixes.push_back({});
1102 
1103  // Find backup paths not already occupied; check all auxiliary suffixes
1104  const auto name = fn.GetName();
1105  FilePath result;
1106  do {
1107  fn.SetName( name + numberString(nn++) + extra );
1108  result = fn.GetFullPath();
1109  }
1110  while( std::any_of(suffixes.begin(), suffixes.end(), [&](auto &suffix){
1111  return wxFileExists(result + suffix);
1112  }) );
1113 
1114  return result;
1115 }

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 416 of file ProjectFileIO.cpp.

417 {
418  // Should do nothing in proper usage, but be sure not to leak a connection:
420 
421  mPrevConn = std::move(CurrConn());
424 
425  SetFileName({});
426 }

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 1946 of file ProjectFileIO.cpp.

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

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

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 2289 of file ProjectFileIO.cpp.

2291 {
2292  auto &currConn = CurrConn();
2293  if (currConn)
2294  currConn->SetDBError(msg, libraryError, errorCode);
2295 }

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 2281 of file ProjectFileIO.cpp.

2283 {
2284  auto &currConn = CurrConn();
2285  if (currConn)
2286  currConn->SetError(msg, libraryError, errorCode);
2287 }

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 1449 of file ProjectFileIO.cpp.

1450 {
1451  auto &project = mProject;
1452 
1453  if (!mFileName.empty())
1454  {
1456  }
1457 
1458  mFileName = fileName;
1459 
1460  if (!mFileName.empty())
1461  {
1463  }
1464 
1465  if (IsTemporary())
1466  {
1467  project.SetProjectName({});
1468  }
1469  else
1470  {
1471  project.SetProjectName(wxFileName(mFileName).GetName());
1472  }
1473 
1474  SetProjectTitle();
1475 }

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 1399 of file ProjectFileIO.cpp.

1400 {
1401  auto &project = mProject;
1402  auto pWindow = project.GetFrame();
1403  if (!pWindow)
1404  {
1405  return;
1406  }
1407  auto &window = *pWindow;
1408  wxString name = project.GetProjectName();
1409 
1410  // If we are showing project numbers, then we also explicitly show "<untitled>" if there
1411  // is none.
1412  if (number >= 0)
1413  {
1414  name =
1415  /* i18n-hint: The %02i is the project number, the %s is the project name.*/
1416  XO("[Project %02i] Audacity \"%s\"")
1417  .Format( number + 1,
1418  name.empty() ? XO("<untitled>") : Verbatim((const char *)name))
1419  .Translation();
1420  }
1421  // If we are not showing numbers, then <untitled> shows as 'Audacity'.
1422  else if (name.empty())
1423  {
1424  name = _TS("Audacity");
1425  }
1426 
1427  if (mRecovered)
1428  {
1429  name += wxT(" ");
1430  /* i18n-hint: E.g this is recovered audio that had been lost.*/
1431  name += _("(Recovered)");
1432  }
1433 
1434  if (name != window.GetTitle())
1435  {
1436  window.SetTitle( name );
1437  window.SetName(name); // to make the nvda screen reader read the correct title
1438 
1439  project.QueueEvent(
1440  safenew wxCommandEvent{ EVT_PROJECT_TITLE_CHANGE } );
1441  }
1442 }

References _, _TS, TranslatableString::empty(), AudacityProject::GetFrame(), 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 1017 of file ProjectFileIO.cpp.

1018 {
1019  SampleBlockIDSet active;
1020  unsigned long long current = 0;
1021 
1022  {
1023  auto fn = BlockSpaceUsageAccumulator( current );
1024  for (auto pTracks : tracks)
1025  if (pTracks)
1026  InspectBlocks( *pTracks, fn,
1027  &active // Visit unique blocks only
1028  );
1029  }
1030 
1031  // Get the number of blocks and total length from the project file.
1032  unsigned long long total = GetTotalUsage();
1033  unsigned long long blockcount = 0;
1034 
1035  auto cb = [&blockcount](int cols, char **vals, char **)
1036  {
1037  // Convert
1038  wxString(vals[0]).ToULongLong(&blockcount);
1039  return 0;
1040  };
1041 
1042  if (!Query("SELECT Count(*) FROM sampleblocks;", cb) || blockcount == 0)
1043  {
1044  // Shouldn't compact since we don't have the full picture
1045  return false;
1046  }
1047 
1048  // Remember if we had unused blocks in the project file
1049  mHadUnused = (blockcount > active.size());
1050 
1051  // Let's make a percentage...should be plenty of head room
1052  current *= 100;
1053 
1054  wxLogDebug(wxT("used = %lld total = %lld %lld"), current, total, total ? current / total : 0);
1055  if (!total || current / total > 80)
1056  {
1057  wxLogDebug(wxT("not compacting"));
1058  return false;
1059  }
1060  wxLogDebug(wxT("compacting"));
1061 
1062  return true;
1063 }

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 ( wxWindow *  parent,
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  ShowErrorDialog(parent, dlogTitle, message, helpPage, true, GetLastLog());
2259 }

References GetLastLog(), and ShowErrorDialog().

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 1393 of file ProjectFileIO.cpp.

1394 {
1395  SetProjectTitle();
1396 }

References SetProjectTitle().

Here is the call graph for this function:

◆ UpdateSaved()

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

Definition at line 1923 of file ProjectFileIO.cpp.

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

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 695 of file ProjectFileIO.cpp.

696 {
697  // To do
698  return true;
699 }

Referenced by CheckVersion().

Here is the caller graph for this function:

◆ UseConnection()

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

Definition at line 484 of file ProjectFileIO.cpp.

485 {
486  auto &curConn = CurrConn();
487  wxASSERT(!curConn);
488 
489  curConn = std::move(conn);
490  SetFileName(filePath);
491 }

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 1383 of file ProjectFileIO.cpp.

1384 {
1385  return mWasCompacted;
1386 }

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 1739 of file ProjectFileIO.cpp.

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

References 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 1644 of file ProjectFileIO.cpp.

1648 {
1649  auto &proj = mProject;
1650  auto &tracklist = tracks ? *tracks : TrackList::Get(proj);
1651  auto &viewInfo = ViewInfo::Get(proj);
1652  auto &tags = Tags::Get(proj);
1653  const auto &settings = ProjectSettings::Get(proj);
1654 
1655  //TIMER_START( "AudacityProject::WriteXML", xml_writer_timer );
1656 
1657  xmlFile.StartTag(wxT("project"));
1658  xmlFile.WriteAttr(wxT("xmlns"), wxT("http://audacity.sourceforge.net/xml/"));
1659 
1660  xmlFile.WriteAttr(wxT("version"), wxT(AUDACITY_FILE_FORMAT_VERSION));
1661  xmlFile.WriteAttr(wxT("audacityversion"), AUDACITY_VERSION_STRING);
1662 
1663  viewInfo.WriteXMLAttributes(xmlFile);
1664  xmlFile.WriteAttr(wxT("rate"), settings.GetRate());
1665  xmlFile.WriteAttr(wxT("snapto"), settings.GetSnapTo() ? wxT("on") : wxT("off"));
1666  xmlFile.WriteAttr(wxT("selectionformat"),
1667  settings.GetSelectionFormat().Internal());
1668  xmlFile.WriteAttr(wxT("frequencyformat"),
1669  settings.GetFrequencySelectionFormatName().Internal());
1670  xmlFile.WriteAttr(wxT("bandwidthformat"),
1671  settings.GetBandwidthSelectionFormatName().Internal());
1672 
1673  tags.WriteXML(xmlFile);
1674 
1675  unsigned int ndx = 0;
1676  tracklist.Any().Visit([&](const Track *t)
1677  {
1678  auto useTrack = t;
1679  if ( recording ) {
1680  // When append-recording, there is a temporary "shadow" track accumulating
1681  // changes and displayed on the screen but it is not yet part of the
1682  // regular track list. That is the one that we want to back up.
1683  // SubstitutePendingChangedTrack() fetches the shadow, if the track has
1684  // one, else it gives the same track back.
1685  useTrack = t->SubstitutePendingChangedTrack().get();
1686  }
1687  else if ( useTrack->GetId() == TrackId{} ) {
1688  // This is a track added during a non-appending recording that is
1689  // not yet in the undo history. The UndoManager skips backing it up
1690  // when pushing. Don't auto-save it.
1691  return;
1692  }
1693  useTrack->WriteXML(xmlFile);
1694  });
1695 
1696  xmlFile.EndTag(wxT("project"));
1697 
1698  //TIMER_STOP( xml_writer_timer );
1699 }

References AUDACITY_FILE_FORMAT_VERSION, XMLWriter::EndTag(), ProjectSettings::Get(), Tags::Get(), TrackList::Get(), ViewInfo::Get(), mProject, settings(), 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 1629 of file ProjectFileIO.cpp.

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

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 305 of file ProjectFileIO.h.

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

◆ mModified

bool ProjectFileIO::mModified
private

Definition at line 296 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 307 of file ProjectFileIO.h.

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

◆ mPrevFileName

FilePath ProjectFileIO::mPrevFileName
private

Definition at line 308 of file ProjectFileIO.h.

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

◆ mPrevTemporary

bool ProjectFileIO::mPrevTemporary
private

Definition at line 309 of file ProjectFileIO.h.

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

◆ mProject

AudacityProject& ProjectFileIO::mProject
private

◆ mRecovered

bool ProjectFileIO::mRecovered
private

Definition at line 293 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 302 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:784
XMLWriter::EndTag
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:100
ProjectFileIO::HadUnused
bool HadUnused()
Definition: ProjectFileIO.cpp:1388
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:162
TranslatableString::empty
bool empty() const
Definition: Types.h:329
WaveTrackFactory::Get
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:2786
ProjectFileIO::GetFileName
const FilePath & GetFileName() const
Definition: ProjectFileIO.cpp:1444
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:301
ProjectFileIO::GetLibraryError
const TranslatableString & GetLibraryError() const
Definition: ProjectFileIO.cpp:2266
ProjectFileIO::SetFileName
void SetFileName(const FilePath &fileName)
Definition: ProjectFileIO.cpp:1449
SampleBlockIDSet
std::unordered_set< SampleBlockID > SampleBlockIDSet
Definition: WaveTrack.h:657
fn
static const auto fn
Definition: WaveformView.cpp:1102
wxFileNameWrapper
Definition: wxFileNameWrapper.h:21
ProjectFileIO::UpgradeSchema
bool UpgradeSchema()
Definition: ProjectFileIO.cpp:695
AudacityProject::GetFrame
wxFrame * GetFrame()
Definition: Project.h:120
ProjectFileIO::WriteDoc
bool WriteDoc(const char *table, const ProjectSerializer &autosave, const char *schema="main")
Definition: ProjectFileIO.cpp:1739
ProjectFileIO::CurrConn
Connection & CurrConn()
Definition: ProjectFileIO.cpp:1065
pdlgHideStopButton
@ pdlgHideStopButton
Definition: ProgressDialog.h:43
ProjectFileVersion
static const int ProjectFileVersion
Definition: ProjectFileIO.cpp:77
Format
Abstract base class used in importing a file.
ProjectFileIO::AuxiliaryFileSuffixes
static const std::vector< wxString > & AuxiliaryFileSuffixes()
Definition: ProjectFileIO.cpp:1071
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:1198
ProjectFileIO::GetLastErrorCode
int GetLastErrorCode() const
Definition: ProjectFileIO.cpp:2271
Connection
std::unique_ptr< DBConnection > Connection
Definition: DBConnection.h:152
XO
#define XO(s)
Definition: Internat.h:32
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:267
ProjectFileIO::CloseConnection
bool CloseConnection()
Definition: ProjectFileIO.cpp:397
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:39
ProjectFileIO::DB
sqlite3 * DB()
Definition: ProjectFileIO.cpp:330
ProjectFileIO::InstallSchema
bool InstallSchema(sqlite3 *db, const char *schema="main")
Definition: ProjectFileIO.cpp:675
SQLiteIniter::mRc
int mRc
Definition: ProjectFileIO.cpp:209
ExecCallback
static int ExecCallback(void *data, int cols, char **vals, char **names)
Definition: ProjectFileIO.cpp:493
ProjectFileSchema
static const char * ProjectFileSchema
Definition: ProjectFileIO.cpp:87
ProjectFileIO::SaveConnection
void SaveConnection()
Definition: ProjectFileIO.cpp:416
InspectBlocks
void InspectBlocks(const TrackList &tracks, BlockInspector inspector, SampleBlockIDSet *pIDs)
Definition: WaveTrack.cpp:2767
ProjectFileIO::mFileName
FilePath mFileName
Definition: ProjectFileIO.h:290
ProjectFileID
static const int ProjectFileID
Definition: ProjectFileIO.cpp:62
XMLValueChecker::IsGoodString
static bool IsGoodString(const wxString &str)
Definition: XMLTagHandler.cpp:39
Tags::Get
static Tags & Get(AudacityProject &project)
Definition: Tags.cpp:236
SampleBlockID
long long SampleBlockID
Definition: ProjectFileIO.h:37
NumericConverter::BANDWIDTH
@ BANDWIDTH
Definition: NumericTextCtrl.h:54
ProjectFileIO::ShouldCompact
bool ShouldCompact(const std::vector< const TrackList * > &tracks)
Definition: ProjectFileIO.cpp:1017
ProjectFileIO::WriteXML
void WriteXML(XMLWriter &xmlFile, bool recording=false, const TrackList *tracks=nullptr)
Definition: ProjectFileIO.cpp:1644
_TS
#define _TS(s)
Definition: Internat.h:28
DBConnection::DB
sqlite3 * DB()
Definition: DBConnection.cpp:356
ProjectFileIO::Compact
void Compact(const std::vector< const TrackList * > &tracks, bool force=false)
Definition: ProjectFileIO.cpp:1250
ProjectFileIO::mModified
bool mModified
Definition: ProjectFileIO.h:296
ProjectFileIO::mPrevTemporary
bool mPrevTemporary
Definition: ProjectFileIO.h:309
ProjectFileIO::mRecovered
bool mRecovered
Definition: ProjectFileIO.h:293
DBConnection::GetDBPage
@ GetDBPage
Definition: DBConnection.h:79
NumericConverter::LookupFormat
static NumericFormatSymbol LookupFormat(Type type, const wxString &id)
Definition: NumericTextCtrl.cpp:702
ProjectFileIORegistry::Lookup
TagHandlerFactory Lookup(const wxString &tag)
Definition: ProjectFileIORegistry.cpp:35
Track::SubstitutePendingChangedTrack
std::shared_ptr< Track > SubstitutePendingChangedTrack()
Definition: Track.cpp:1186
ProjectFileIO::SetError
void SetError(const TranslatableString &msg, const TranslatableString &libraryError={}, int errorCode={})
Just set stored errors.
Definition: ProjectFileIO.cpp:2281
XMLFileReader::GetErrorStr
const TranslatableString & GetErrorStr() const
Definition: XMLFileReader.cpp:177
ProgressDialog
ProgressDialog Class.
Definition: ProgressDialog.h:56
ProjectSerializer::GetDict
const wxMemoryBuffer & GetDict() const
Definition: ProjectSerializer.cpp:365
ProjectFileIO::UpdatePrefs
void UpdatePrefs() override
Definition: ProjectFileIO.cpp:1393
ProgressResult
ProgressResult
Definition: ProgressDialog.h:33
ProjectFileIO::CheckVersion
bool CheckVersion()
Definition: ProjectFileIO.cpp:604
ProjectFileIO::InSet
static void InSet(sqlite3_context *context, int argc, sqlite3_value **argv)
Definition: ProjectFileIO.cpp:707
ProgressResult::Success
@ Success
ProjectFileIO::UseConnection
void UseConnection(Connection &&conn, const FilePath &filePath)
Definition: ProjectFileIO.cpp:484
ProjectFileIO::DeleteBlocks
bool DeleteBlocks(const BlockIDs &blockids, bool complement)
Definition: ProjectFileIO.cpp:715
ProjectFileIO::AutoSaveDelete
bool AutoSaveDelete(sqlite3 *db=nullptr)
Definition: ProjectFileIO.cpp:1716
GetProjectFrame
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
Definition: Project.cpp:186
AUDACITY_FILE_FORMAT_VERSION
#define AUDACITY_FILE_FORMAT_VERSION
Definition: ProjectFileIO.cpp:41
ProjectFileIO::DiscardConnection
void DiscardConnection()
Definition: ProjectFileIO.cpp:429
XMLFileReader::ParseString
bool ParseString(XMLTagHandler *baseHandler, const wxString &xmldata)
Definition: XMLFileReader.cpp:135
name
const TranslatableString name
Definition: Distortion.cpp:98
ProjectFileIO::WriteXMLHeader
void WriteXMLHeader(XMLWriter &xmlFile) const
Definition: ProjectFileIO.cpp:1629
NumericConverter::TIME
@ TIME
Definition: NumericTextCtrl.h:51
ProjectFileIO::WasCompacted
bool WasCompacted()
Definition: ProjectFileIO.cpp:1383
DBConnection::GetRootPage
@ GetRootPage
Definition: DBConnection.h:78
ProjectFileIO::OpenConnection
bool OpenConnection(FilePath fileName={})
Definition: ProjectFileIO.cpp:339
THROW_INCONSISTENCY_EXCEPTION
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Definition: InconsistencyException.h:77
sFileIOKey
static const AudacityProject::AttachedObjects::RegisteredFactory sFileIOKey
Definition: ProjectFileIO.cpp:260
ProjectFileIO::GetTotalUsage
int64_t GetTotalUsage()
Definition: ProjectFileIO.cpp:2355
ProjectFileIO::UpdateSaved
bool UpdateSaved(const TrackList *tracks=nullptr)
Definition: ProjectFileIO.cpp:1923
ProjectFileIO::mPrevFileName
FilePath mPrevFileName
Definition: ProjectFileIO.h:308
ProjectFileIO::GetLastError
const TranslatableString & GetLastError() const
Definition: ProjectFileIO.cpp:2261
FileNames::IsOnFATFileSystem
AUDACITY_DLL_API bool IsOnFATFileSystem(const FilePath &path)
NumericConverter::FREQUENCY
@ FREQUENCY
Definition: NumericTextCtrl.h:53
ProjectFileIO::GetValue
bool GetValue(const char *sql, wxString &value)
Definition: ProjectFileIO.cpp:540
ShowErrorDialog
void ShowErrorDialog(wxWindow *parent, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage, const bool Close, const wxString &log)
Displays an error dialog with a button that offers help.
Definition: ErrorDialog.cpp:148
BlockIDs
std::unordered_set< SampleBlockID > BlockIDs
Definition: ProjectFileIO.h:41
ProjectFileIO::get2
static unsigned int get2(const unsigned char *ptr)
Definition: ProjectFileIO.cpp:2577
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
ProjectSerializer::GetData
const wxMemoryBuffer & GetData() const
Definition: ProjectSerializer.cpp:370
FilePath
wxString FilePath
Definition: Types.h:270
TrackId
An in-session identifier of track objects across undo states. It does not persist between sessions.
Definition: Track.h:164
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:495
XMLFileReader
Reads a file and passes the results through an XMLTagHandler.
Definition: XMLFileReader.h:20
Track
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:238
XMLWriter::Write
virtual void Write(const wxString &data)=0
_
#define _(s)
Definition: Internat.h:76
ConnectionPtr::Get
static ConnectionPtr & Get(AudacityProject &project)
Definition: DBConnection.cpp:658
WaveTrackFactory::GetSampleBlockFactory
const SampleBlockFactoryPtr & GetSampleBlockFactory() const
Definition: WaveTrack.h:691
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:112
TempDirectory::UnsavedProjectFileName
wxString UnsavedProjectFileName()
Definition: TempDirectory.cpp:108
Verbatim
TranslatableString Verbatim(wxString str)
Definition: Types.h:573
ProjectFileIO::mWasCompacted
bool mWasCompacted
Definition: ProjectFileIO.h:302
ProjectFileIO::Query
bool Query(const char *sql, const ExecCB &callback)
Definition: ProjectFileIO.cpp:527
ProjectFileIO::RenameOrWarn
bool RenameOrWarn(const FilePath &src, const FilePath &dst)
Rename a file or put up appropriate warning message.
Definition: ProjectFileIO.cpp:1117
XMLWriter::WriteAttr
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:34
TrackList::Create
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:512
ProjectFileIO::GetLastLog
const wxString & GetLastLog() const
Definition: ProjectFileIO.cpp:2276
ProjectFileIO::MoveProject
bool MoveProject(const FilePath &src, const FilePath &dst)
Definition: ProjectFileIO.cpp:1161
FileException::WriteFailureMessage
static TranslatableString WriteFailureMessage(const wxFileName &fileName)
Definition: FileException.cpp:61
ProjectFileIO::GetBlob
bool GetBlob(const char *sql, wxMemoryBuffer &buffer)
Definition: ProjectFileIO.cpp:554
ProjectFileIO::get4
static unsigned int get4(const unsigned char *ptr)
Definition: ProjectFileIO.cpp:2583
ProjectFileIO::ShowError
void ShowError(wxWindow *parent, const TranslatableString &dlogTitle, const TranslatableString &message, const wxString &helpPage)
Displays an error dialog with a button that offers help.
Definition: ProjectFileIO.cpp:2253
SQLiteIniter
Definition: ProjectFileIO.cpp:167
ProjectFileIO::IsModified
bool IsModified() const
Definition: ProjectFileIO.cpp:2211
ProjectFileIO::GetDiskUsage
static int64_t GetDiskUsage(DBConnection &conn, SampleBlockID blockid)
Definition: ProjectFileIO.cpp:2369
ActiveProjects::Remove
void Remove(const FilePath &path)
ProjectFileIO::get_varint
static int get_varint(const unsigned char *ptr, int64_t *out)
Definition: ProjectFileIO.cpp:2594
ProjectFileIO::mPrevConn
Connection mPrevConn
Definition: ProjectFileIO.h:307
safenew
#define safenew
Definition: MemoryX.h:8
settings
static Settings & settings()
Definition: TrackInfo.cpp:87
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:78
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:2289
ProjectFileIO::Exec
int Exec(const char *query, const ExecCB &callback)
Definition: ProjectFileIO.cpp:503
ProjectFileIO::mpErrors
std::shared_ptr< DBConnectionErrors > mpErrors
Definition: ProjectFileIO.h:287
ProjectFileIO::SetProjectTitle
void SetProjectTitle(int number=-1)
Definition: ProjectFileIO.cpp:1399
DBConnection::Prepare
sqlite3_stmt * Prepare(enum StatementID id, const char *sql)
Definition: DBConnection.cpp:373
ProjectFileIO::mProject
AudacityProject & mProject
Definition: ProjectFileIO.h:285
XMLWriter::StartTag
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:77
ProjectFileIO::mHadUnused
bool mHadUnused
Definition: ProjectFileIO.h:305
ProjectFileIO::mTemporary
bool mTemporary
Definition: ProjectFileIO.h:299
Internat::CompatibleToDouble
static bool CompatibleToDouble(const wxString &stringToConvert, double *result)
Convert a string to a number.
Definition: Internat.cpp:139
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:60
TempDirectory::TempDir
wxString TempDir()
Definition: TempDirectory.cpp:26
ProjectFileIO::RestoreConnection
void RestoreConnection()
Definition: ProjectFileIO.cpp:463