Commit c8636d46 authored by coppro's avatar coppro

Added new feature allowing data files in the user's settings directory to...

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.
parent bcc26f1a
...@@ -25,12 +25,12 @@ String Error::what() const { ...@@ -25,12 +25,12 @@ String Error::what() const {
// ----------------------------------------------------------------------------- : Parse errors // ----------------------------------------------------------------------------- : Parse errors
ScriptParseError::ScriptParseError(size_t pos, int line, const String& filename, const String& error) 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) 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 { String ScriptParseError::what() const {
return String(_("(")) << (int)start << _("): ") << Error::what(); return String(_("(")) << (int)start << _("): ") << Error::what();
...@@ -61,18 +61,20 @@ void show_pending_errors(); ...@@ -61,18 +61,20 @@ void show_pending_errors();
void show_pending_warnings(); void show_pending_warnings();
void handle_error(const String& e, bool allow_duplicate = true, bool now = true) { void handle_error(const String& e, bool allow_duplicate = true, bool now = true) {
// Thread safety {
wxCriticalSectionLocker lock(crit_error_handling); // Thread safety
// Check duplicates wxCriticalSectionLocker lock(crit_error_handling);
if (!allow_duplicate) { // Check duplicates
FOR_EACH(pe, previous_errors) { if (!allow_duplicate) {
if (e == pe) return; 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 // show messages
if (now && wxThread::IsMain()) { if (now && wxThread::IsMain()) {
show_pending_warnings(); // warnings are older, show them first show_pending_warnings(); // warnings are older, show them first
...@@ -85,11 +87,13 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) { ...@@ -85,11 +87,13 @@ void handle_error(const Error& e, bool allow_duplicate, bool now) {
} }
void handle_warning(const String& w, bool now) { void handle_warning(const String& w, bool now) {
// Check duplicates {
wxCriticalSectionLocker lock(crit_error_handling); // Check duplicates
// Only show errors in the main thread wxCriticalSectionLocker lock(crit_error_handling);
if (!pending_warnings.empty()) pending_warnings += _("\n\n"); // Only show errors in the main thread
pending_warnings += w; if (!pending_warnings.empty()) pending_warnings += _("\n\n");
pending_warnings += w;
}
// show messages // show messages
if (now && wxThread::IsMain()) { if (now && wxThread::IsMain()) {
show_pending_errors(); show_pending_errors();
......
...@@ -37,50 +37,67 @@ PackageManager packages; ...@@ -37,50 +37,67 @@ PackageManager packages;
void PackageManager::init() { void PackageManager::init() {
// determine data directory // 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, // check if this is the actual data directory, especially during debugging,
// the data may be higher up: // the data may be higher up:
// exe path = mse/build/debug/mse.exe // exe path = mse/build/debug/mse.exe
// data path = mse/data // data path = mse/data
while (!wxDirExists(data_directory + _("/data"))) { while (!wxDirExists(global_data_directory + _("/data"))) {
String d = data_directory; String d = global_data_directory;
data_directory = wxPathOnly(data_directory); global_data_directory = wxPathOnly(global_data_directory);
if (d == data_directory) { if (d == global_data_directory) {
// we are at the root -> 'data' not found anywhere in the path -> fatal error // 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) { PackagedP PackageManager::openAny(const String& name, bool just_header) {
wxFileName fn( // Attempt to load local data first.
(wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString)) String filename;
+ name); wxFileName* fn;
fn.Normalize(); if (wxFileName(name).IsRelative()) {
String filename = fn.GetFullPath(); 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? // Is this package already loaded?
PackagedP& p = loaded_packages[filename]; PackagedP& p = loaded_packages[filename];
if (p) { if (!p) {
return p;
} else {
// load with the right type, based on extension // load with the right type, based on extension
if (fn.GetExt() == _("mse-game")) p = new_intrusive<Game>(); if (fn->GetExt() == _("mse-game")) p = new_intrusive<Game>();
else if (fn.GetExt() == _("mse-style")) p = new_intrusive<StyleSheet>(); else if (fn->GetExt() == _("mse-style")) p = new_intrusive<StyleSheet>();
else if (fn.GetExt() == _("mse-locale")) p = new_intrusive<Locale>(); else if (fn->GetExt() == _("mse-locale")) p = new_intrusive<Locale>();
else if (fn.GetExt() == _("mse-include")) p = new_intrusive<IncludePackage>(); else if (fn->GetExt() == _("mse-include")) p = new_intrusive<IncludePackage>();
else if (fn.GetExt() == _("mse-symbol-font")) p = new_intrusive<SymbolFont>(); else if (fn->GetExt() == _("mse-symbol-font")) p = new_intrusive<SymbolFont>();
else if (fn.GetExt() == _("mse-export-template")) p = new_intrusive<ExportTemplate>(); else if (fn->GetExt() == _("mse-export-template")) p = new_intrusive<ExportTemplate>();
else { 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); p->open(filename, just_header);
return p;
} }
delete fn;
return p;
} }
String PackageManager::findFirst(const String& pattern) { 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) { InputStreamP PackageManager::openFileFromPackage(const String& name) {
...@@ -97,10 +114,13 @@ 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) { 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)) { if (!wxFileExists(name) && !wxDirExists(name)) {
handle_warning(_ERROR_1_("package not found", dep.package),false); name = global_data_directory + _("/") + dep.package;
return false; if (!wxFileExists(name) && !wxDirExists(name)) {
handle_warning(_ERROR_1_("package not found", dep.package),false);
return false;
}
} }
PackagedP package = openAny(dep.package, true); PackagedP package = openAny(dep.package, true);
if (package->version < dep.version) { if (package->version < dep.version) {
......
...@@ -34,9 +34,14 @@ class PackageManager { ...@@ -34,9 +34,14 @@ class PackageManager {
/// Open a package with the specified name (including extension) /// Open a package with the specified name (including extension)
template <typename T> template <typename T>
intrusive_ptr<T> open(const String& name) { intrusive_ptr<T> open(const String& name) {
wxFileName fn(data_directory + _("/") + name); wxFileName loc(local_data_directory + _("/") + name);
fn.Normalize(); loc.Normalize();
String filename = fn.GetFullPath(); 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? // Is this package already loaded?
PackagedP& p = loaded_packages[filename]; PackagedP& p = loaded_packages[filename];
intrusive_ptr<T> typedP = dynamic_pointer_cast<T>(p); intrusive_ptr<T> typedP = dynamic_pointer_cast<T>(p);
...@@ -70,7 +75,8 @@ class PackageManager { ...@@ -70,7 +75,8 @@ class PackageManager {
private: private:
map<String, PackagedP> loaded_packages; map<String, PackagedP> loaded_packages;
String data_directory; String global_data_directory;
String local_data_directory;
}; };
/// The global PackageManager instance /// The global PackageManager instance
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment