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 {
// ----------------------------------------------------------------------------- : 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();
......
......@@ -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<Game>();
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-include")) p = new_intrusive<IncludePackage>();
else if (fn.GetExt() == _("mse-symbol-font")) p = new_intrusive<SymbolFont>();
else if (fn.GetExt() == _("mse-export-template")) p = new_intrusive<ExportTemplate>();
if (fn->GetExt() == _("mse-game")) p = new_intrusive<Game>();
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-include")) p = new_intrusive<IncludePackage>();
else if (fn->GetExt() == _("mse-symbol-font")) p = new_intrusive<SymbolFont>();
else if (fn->GetExt() == _("mse-export-template")) p = new_intrusive<ExportTemplate>();
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) {
......
......@@ -34,9 +34,14 @@ class PackageManager {
/// Open a package with the specified name (including extension)
template <typename T>
intrusive_ptr<T> 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<T> typedP = dynamic_pointer_cast<T>(p);
......@@ -70,7 +75,8 @@ class PackageManager {
private:
map<String, PackagedP> loaded_packages;
String data_directory;
String global_data_directory;
String local_data_directory;
};
/// 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