From b21192646b20707e5e75dcb4772609506d63a0a0 Mon Sep 17 00:00:00 2001 From: coppro Date: Thu, 12 Jul 2007 01:10:45 +0000 Subject: [PATCH] Added new feature allowing data files in the user's settings directory to override those in the default directory It's for systems where the main data is not writable by everyone. (Unices, mainly, and potentially Windows Vista) The Windows default directory is a little out-of-the-way, in %HOME%\Application Data\Magic Set Editor\Data Maybe they should be configurable. But it also paves the way for the installer being capable of putting packages into the user's local directory. That way, users don't all have to have all the packages that the other users want. git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@557 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/util/error.cpp | 42 ++++++++++--------- src/util/io/package_manager.cpp | 74 +++++++++++++++++++++------------ src/util/io/package_manager.hpp | 14 +++++-- 3 files changed, 80 insertions(+), 50 deletions(-) diff --git a/src/util/error.cpp b/src/util/error.cpp index 6250272f..343c6fa9 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -25,12 +25,12 @@ String Error::what() const { // ----------------------------------------------------------------------------- : Parse errors ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& error) - : start(pos), end(pos), line(line), filename(filename) - , ParseError(error) + : ParseError(error) + , start(pos), end(pos), line(line), filename(filename) {} ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& exp, const String& found) - : start(pos), end(pos + found.size()), line(line), filename(filename) - , ParseError(_("Expected '") + exp + _("' instead of '") + found + _("'")) + : ParseError(_("Expected '") + exp + _("' instead of '") + found + _("'")) + , start(pos), end(pos + found.size()), line(line), filename(filename) {} String ScriptParseError::what() const { return String(_("(")) << (int)start << _("): ") << Error::what(); @@ -61,18 +61,20 @@ void show_pending_errors(); void show_pending_warnings(); void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { - // Thread safety - wxCriticalSectionLocker lock(crit_error_handling); - // Check duplicates - if (!allow_duplicate) { - FOR_EACH(pe, previous_errors) { - if (e == pe) return; + { + // Thread safety + wxCriticalSectionLocker lock(crit_error_handling); + // Check duplicates + if (!allow_duplicate) { + FOR_EACH(pe, previous_errors) { + if (e == pe) return; + } + previous_errors.push_back(e); } - previous_errors.push_back(e); + // Only show errors in the main thread + if (!pending_errors.empty()) pending_errors += _("\n\n"); + pending_errors += e; } - // Only show errors in the main thread - if (!pending_errors.empty()) pending_errors += _("\n\n"); - pending_errors += e; // show messages if (now && wxThread::IsMain()) { show_pending_warnings(); // warnings are older, show them first @@ -85,11 +87,13 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) { } void handle_warning(const String& w, bool now) { - // Check duplicates - wxCriticalSectionLocker lock(crit_error_handling); - // Only show errors in the main thread - if (!pending_warnings.empty()) pending_warnings += _("\n\n"); - pending_warnings += w; + { + // Check duplicates + wxCriticalSectionLocker lock(crit_error_handling); + // Only show errors in the main thread + if (!pending_warnings.empty()) pending_warnings += _("\n\n"); + pending_warnings += w; + } // show messages if (now && wxThread::IsMain()) { show_pending_errors(); diff --git a/src/util/io/package_manager.cpp b/src/util/io/package_manager.cpp index 17ff7c1b..b1d1f556 100644 --- a/src/util/io/package_manager.cpp +++ b/src/util/io/package_manager.cpp @@ -37,50 +37,67 @@ PackageManager packages; void PackageManager::init() { // determine data directory - data_directory = wxStandardPaths::Get().GetDataDir(); + global_data_directory = wxStandardPaths::Get().GetDataDir(); + local_data_directory = wxStandardPaths::Get().GetUserDataDir(); // check if this is the actual data directory, especially during debugging, // the data may be higher up: // exe path = mse/build/debug/mse.exe // data path = mse/data - while (!wxDirExists(data_directory + _("/data"))) { - String d = data_directory; - data_directory = wxPathOnly(data_directory); - if (d == data_directory) { + while (!wxDirExists(global_data_directory + _("/data"))) { + String d = global_data_directory; + global_data_directory = wxPathOnly(global_data_directory); + if (d == global_data_directory) { // we are at the root -> 'data' not found anywhere in the path -> fatal error - throw Error(_("The MSE data files can not be found, there should be a directory called 'data' with these files. The expected directory to find it in was ") + wxStandardPaths::Get().GetDataDir()); + throw Error(_("The global MSE data files can not be found, there should be a directory called 'data' with these files. The expected directory to find it in was ") + wxStandardPaths::Get().GetDataDir()); } } - data_directory += _("/data"); + global_data_directory += _("/data"); + // It's not an error for the local directory not to exist. + local_data_directory += _("/data"); } PackagedP PackageManager::openAny(const String& name, bool just_header) { - wxFileName fn( - (wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString)) - + name); - fn.Normalize(); - String filename = fn.GetFullPath(); + // Attempt to load local data first. + String filename; + wxFileName* fn; + if (wxFileName(name).IsRelative()) { + fn = new wxFileName(local_data_directory + _("/") + name); + fn->Normalize(); + filename = fn->GetFullPath(); + if (!wxFileExists(filename) && !wxDirExists(filename)) { + delete fn; + fn = new wxFileName(global_data_directory + _("/") + name); + fn->Normalize(); + filename = fn->GetFullPath(); + } + } else { // Absolute filename + fn = new wxFileName(name); + fn->Normalize(); + filename = fn->GetFullPath(); + } + // Is this package already loaded? PackagedP& p = loaded_packages[filename]; - if (p) { - return p; - } else { + if (!p) { // load with the right type, based on extension - if (fn.GetExt() == _("mse-game")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-style")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-locale")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-include")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-symbol-font")) p = new_intrusive(); - else if (fn.GetExt() == _("mse-export-template")) p = new_intrusive(); + if (fn->GetExt() == _("mse-game")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-style")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-locale")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-include")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-symbol-font")) p = new_intrusive(); + else if (fn->GetExt() == _("mse-export-template")) p = new_intrusive(); else { - throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name); + throw PackageError(_("Unrecognized package type: '") + fn->GetExt() + _("'\nwhile trying to open: ") + name); } p->open(filename, just_header); - return p; } + delete fn; + return p; } String PackageManager::findFirst(const String& pattern) { - return wxFindFirstFile(data_directory + _("/") + pattern, 0); + String file = wxFindFirstFile(local_data_directory + _("/") + pattern, 0); + return file.IsEmpty() ? wxFindFirstFile(global_data_directory + _("/") + pattern, 0) : file; } InputStreamP PackageManager::openFileFromPackage(const String& name) { @@ -97,10 +114,13 @@ InputStreamP PackageManager::openFileFromPackage(const String& name) { } bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) { - String name = data_directory + _("/") + dep.package; + String name = local_data_directory + _("/") + dep.package; if (!wxFileExists(name) && !wxDirExists(name)) { - handle_warning(_ERROR_1_("package not found", dep.package),false); - return false; + name = global_data_directory + _("/") + dep.package; + if (!wxFileExists(name) && !wxDirExists(name)) { + handle_warning(_ERROR_1_("package not found", dep.package),false); + return false; + } } PackagedP package = openAny(dep.package, true); if (package->version < dep.version) { diff --git a/src/util/io/package_manager.hpp b/src/util/io/package_manager.hpp index ec8dae2a..7c39f083 100644 --- a/src/util/io/package_manager.hpp +++ b/src/util/io/package_manager.hpp @@ -34,9 +34,14 @@ class PackageManager { /// Open a package with the specified name (including extension) template intrusive_ptr open(const String& name) { - wxFileName fn(data_directory + _("/") + name); - fn.Normalize(); - String filename = fn.GetFullPath(); + wxFileName loc(local_data_directory + _("/") + name); + loc.Normalize(); + String filename = loc.GetFullPath(); + if (!wxFileExists(filename) && !wxDirExists(filename)) { + wxFileName glob(global_data_directory + _("/") + name); + glob.Normalize(); + filename = glob.GetFullPath(); + } // Is this package already loaded? PackagedP& p = loaded_packages[filename]; intrusive_ptr typedP = dynamic_pointer_cast(p); @@ -70,7 +75,8 @@ class PackageManager { private: map loaded_packages; - String data_directory; + String global_data_directory; + String local_data_directory; }; /// The global PackageManager instance