mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
Fixed/hacked 'no parameter' for 0.2.7 keyword compatability;
Added 'just_header' flag to make stylesheet list load faster; Added versioning and dependency support to packages git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@320 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -60,6 +60,9 @@ void read_compat(Reader& tag, Keyword* k) {
|
||||
if (start != String::npos && end != String::npos) {
|
||||
k->match += separator.substr(start + 1, end - start - 1);
|
||||
}
|
||||
if (parameter == _("no parameter")) {
|
||||
parameter.clear(); // was used for magic to indicate absence of parameter
|
||||
}
|
||||
if (!parameter.empty()) {
|
||||
k->match += _("<atom-param>") + parameter + _("</atom-param>");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ void PackageList::showData(const String& pattern) {
|
||||
while (!f.empty()) {
|
||||
// try to open the package
|
||||
// try {
|
||||
PackagedP package = ::packages.openAny(f);
|
||||
PackagedP package = ::packages.openAny(f, true);
|
||||
// open image
|
||||
InputStreamP stream = package->openIconFile();
|
||||
Image img;
|
||||
|
||||
@@ -41,6 +41,7 @@ class PackageList : public GalleryList {
|
||||
shared_ptr<T> getSelection() const {
|
||||
shared_ptr<T> ret = dynamic_pointer_cast<T>(packages.at(selection).package);
|
||||
if (!ret) throw InternalError(_("PackageList: Selected package has the wrong type"));
|
||||
ret->loadFully();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,22 +8,38 @@
|
||||
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <util/version.hpp>
|
||||
#include <script/value.hpp> // for some strange reason the profile build needs this :(
|
||||
#include <wx/dialup.h>
|
||||
#include <wx/url.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
|
||||
DECLARE_POINTER_TYPE(PackageVersionData);
|
||||
DECLARE_POINTER_TYPE(VersionData);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Update data
|
||||
|
||||
/// Information on available packages
|
||||
class PackageVersionData {
|
||||
public:
|
||||
PackageVersionData() : is_installer(true) {}
|
||||
|
||||
String name; ///< Name of the package
|
||||
String description; ///< html description
|
||||
String url; ///< Where can the package be downloaded?
|
||||
bool is_installer; ///< Download url refers to a .mse-installer
|
||||
Version version; ///< Version number of the download
|
||||
vector<PackageDependencyP> depends; ///< Packages this depends on
|
||||
};
|
||||
|
||||
/// Information on the latest availible version
|
||||
class VersionData {
|
||||
public:
|
||||
Version version; ///< Latest version number
|
||||
String description; ///< html description
|
||||
Version version; ///< Latest version number of MSE
|
||||
String description; ///< html description of the latest MSE release
|
||||
String new_updates_url; ///< updates url has moved?
|
||||
vector<PackageVersionDataP> packages; ///< Available packages
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
+46
-3
@@ -9,12 +9,14 @@
|
||||
#include <util/io/package.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <script/to_value.hpp> // for reflection
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/zipstrm.h>
|
||||
#include <wx/dir.h>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
DECLARE_TYPEOF(Package::FileInfos);
|
||||
DECLARE_TYPEOF_COLLECTION(PackageDependencyP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Package : outside
|
||||
|
||||
@@ -400,15 +402,23 @@ String Package::toStandardName(const String& name) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Packaged
|
||||
|
||||
IMPLEMENT_REFLECTION(PackageDependency) {
|
||||
REFLECT(package);
|
||||
REFLECT(version);
|
||||
}
|
||||
|
||||
// note: reflection must be declared before it is used
|
||||
IMPLEMENT_REFLECTION(Packaged) {
|
||||
REFLECT(short_name);
|
||||
REFLECT(full_name);
|
||||
REFLECT_N("icon", icon_filename);
|
||||
REFLECT(version);
|
||||
REFLECT_N("depends ons", dependencies); // hack for singular_form
|
||||
}
|
||||
|
||||
Packaged::Packaged() {
|
||||
}
|
||||
Packaged::Packaged()
|
||||
: fully_loaded(true)
|
||||
{}
|
||||
|
||||
InputStreamP Packaged::openIconFile() {
|
||||
if (!icon_filename.empty()) {
|
||||
@@ -417,8 +427,36 @@ InputStreamP Packaged::openIconFile() {
|
||||
return InputStreamP();
|
||||
}
|
||||
}
|
||||
void Packaged::open(const String& package) {
|
||||
|
||||
// proxy object, that reads just WITHOUT using the overloaded behaviour
|
||||
struct JustAsPackageProxy {
|
||||
JustAsPackageProxy(Packaged* that) : that(that) {}
|
||||
Packaged* that;
|
||||
};
|
||||
template <> void Reader::handle(JustAsPackageProxy& object) {
|
||||
object.that->Packaged::reflect_impl(*this);
|
||||
}
|
||||
|
||||
void Packaged::open(const String& package, bool just_header) {
|
||||
Package::open(package);
|
||||
fully_loaded = false;
|
||||
if (just_header) {
|
||||
// Read just the header (the part common to all Packageds)
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName(), true);
|
||||
try {
|
||||
JustAsPackageProxy proxy(this);
|
||||
reader.handle_greedy(proxy);
|
||||
Packaged::validate(reader.file_app_version);
|
||||
} catch (const ParseError& err) {
|
||||
throw FileParseError(err.what(), absoluteFilename() + _("/") + typeName()); // more detailed message
|
||||
}
|
||||
} else {
|
||||
loadFully();
|
||||
}
|
||||
}
|
||||
void Packaged::loadFully() {
|
||||
if (fully_loaded) return;
|
||||
fully_loaded = true;
|
||||
Reader reader(openIn(typeName()), absoluteFilename() + _("/") + typeName());
|
||||
try {
|
||||
reader.handle_greedy(*this);
|
||||
@@ -427,6 +465,7 @@ void Packaged::open(const String& package) {
|
||||
throw FileParseError(err.what(), absoluteFilename() + _("/") + typeName()); // more detailed message
|
||||
}
|
||||
}
|
||||
|
||||
void Packaged::save() {
|
||||
WITH_DYNAMIC_ARG(writing_package, this);
|
||||
writeFile(typeName(), *this);
|
||||
@@ -443,4 +482,8 @@ void Packaged::saveAs(const String& package) {
|
||||
void Packaged::validate(Version) {
|
||||
// a default for the short name
|
||||
if (short_name.empty()) short_name = name();
|
||||
// check dependencies
|
||||
FOR_EACH(dep, dependencies) {
|
||||
packages.checkDependency(*dep, true);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-1
@@ -17,6 +17,7 @@ class Package;
|
||||
class wxFileInputStream;
|
||||
class wxZipInputStream;
|
||||
class wxZipEntry;
|
||||
DECLARE_POINTER_TYPE(PackageDependency);
|
||||
|
||||
/// The package that is currently being written to
|
||||
DECLARE_DYNAMIC_ARG(Package*, writing_package);
|
||||
@@ -175,6 +176,15 @@ class Package {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Packaged
|
||||
|
||||
/// Dependencies of a package
|
||||
class PackageDependency {
|
||||
public:
|
||||
String package; ///< Name of the package someone depends on
|
||||
Version version; ///< Minimal required version of that package
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
/// Utility class for data types that are always stored in a package.
|
||||
/** When the package is opened/saved a file describing the data object is read/written
|
||||
*/
|
||||
@@ -183,15 +193,21 @@ class Packaged : public Package {
|
||||
Packaged();
|
||||
virtual ~Packaged() {}
|
||||
|
||||
Version version; ///< Version number of this package
|
||||
String short_name; ///< Short name of this package
|
||||
String full_name; ///< Name of this package, for menus etc.
|
||||
String icon_filename; ///< Filename of icon to use in package lists
|
||||
vector<PackageDependencyP> dependencies; ///< Dependencies of this package
|
||||
|
||||
/// Get an input stream for the package icon, if there is any
|
||||
InputStreamP openIconFile();
|
||||
|
||||
/// Open a package, and read the data
|
||||
void open(const String& package);
|
||||
/** if just_header is true, then the package is not fully parsed.
|
||||
*/
|
||||
void open(const String& package, bool just_header = false);
|
||||
/// Ensure the package is fully loaded.
|
||||
void loadFully();
|
||||
void save();
|
||||
void saveAs(const String& package);
|
||||
|
||||
@@ -202,6 +218,10 @@ class Packaged : public Package {
|
||||
virtual void validate(Version file_app_version);
|
||||
|
||||
DECLARE_REFLECTION_VIRTUAL();
|
||||
|
||||
private:
|
||||
bool fully_loaded; ///< Is the package fully loaded?
|
||||
friend struct JustAsPackageProxy;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
@@ -58,7 +58,7 @@ void PackageManager::init() {
|
||||
data_directory += _("/data");
|
||||
}
|
||||
|
||||
PackagedP PackageManager::openAny(const String& name) {
|
||||
PackagedP PackageManager::openAny(const String& name, bool just_header) {
|
||||
wxFileName fn(
|
||||
(wxFileName(name).IsRelative() ? data_directory + _("/") : wxString(wxEmptyString))
|
||||
+ name);
|
||||
@@ -79,7 +79,7 @@ PackagedP PackageManager::openAny(const String& name) {
|
||||
else {
|
||||
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
|
||||
}
|
||||
p->open(filename);
|
||||
p->open(filename, just_header);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,20 @@ InputStreamP PackageManager::openFileFromPackage(const String& name) {
|
||||
return p->openIn(n.substr(pos+1));
|
||||
}
|
||||
|
||||
bool PackageManager::checkDependency(const PackageDependency& dep, bool report_errors) {
|
||||
String name = 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) {
|
||||
handle_warning(_ERROR_3_("package out of date", dep.package, package->version.toString(), dep.version.toString()),false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PackageManager::destroy() {
|
||||
loaded_packages.clear();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wx/filename.h>
|
||||
|
||||
DECLARE_POINTER_TYPE(Packaged);
|
||||
class PackageDependency;
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackageManager
|
||||
|
||||
@@ -40,9 +41,10 @@ class PackageManager {
|
||||
PackagedP& p = loaded_packages[filename];
|
||||
shared_ptr<T> typedP = dynamic_pointer_cast<T>(p);
|
||||
if (typedP) {
|
||||
typedP->loadFully();
|
||||
return typedP;
|
||||
} else {
|
||||
// not loaded, or loaded with wrong type
|
||||
// not loaded, or loaded with wrong type (i.e. with just_header)
|
||||
p = typedP = new_shared<T>();
|
||||
typedP->open(filename);
|
||||
return typedP;
|
||||
@@ -50,7 +52,9 @@ class PackageManager {
|
||||
}
|
||||
|
||||
/// Open a package with the specified name, the type of package is determined by its extension!
|
||||
PackagedP openAny(const String& name);
|
||||
/** @param if just_header is true, then the package is not fully parsed.
|
||||
*/
|
||||
PackagedP openAny(const String& name, bool just_header = false);
|
||||
|
||||
/// Find a package whos name matches a pattern
|
||||
/** Find more using wxFindNextFile().
|
||||
@@ -58,9 +62,12 @@ class PackageManager {
|
||||
*/
|
||||
String findFirst(const String& pattern);
|
||||
|
||||
// Open a file from a package, with a name encoded as "package/file"
|
||||
/// Open a file from a package, with a name encoded as "package/file"
|
||||
InputStreamP openFileFromPackage(const String& name);
|
||||
|
||||
|
||||
/// Check if the given dependency is currently installed
|
||||
bool checkDependency(const PackageDependency& dep, bool report_errors = false);
|
||||
|
||||
private:
|
||||
map<String, PackagedP> loaded_packages;
|
||||
String data_directory;
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reader
|
||||
|
||||
Reader::Reader(const InputStreamP& input, const String& filename)
|
||||
Reader::Reader(const InputStreamP& input, const String& filename, bool ignore_invalid)
|
||||
: indent(0), expected_indent(0), just_opened(false)
|
||||
, filename(filename), line_number(0)
|
||||
, ignore_invalid(ignore_invalid)
|
||||
, input(input), stream(*input)
|
||||
{
|
||||
moveNext();
|
||||
@@ -125,6 +126,13 @@ void Reader::readLine() {
|
||||
}
|
||||
|
||||
void Reader::unknownKey() {
|
||||
// ignore?
|
||||
if (ignore_invalid) {
|
||||
do {
|
||||
moveNext();
|
||||
} while (indent > expected_indent);
|
||||
return;
|
||||
}
|
||||
// aliasses?
|
||||
map<String,Alias>::const_iterator it = aliasses.find(key);
|
||||
if (it != aliasses.end()) {
|
||||
|
||||
@@ -36,7 +36,7 @@ class Reader {
|
||||
/// Construct a reader that reads from the given input stream
|
||||
/** filename is used only for error messages
|
||||
*/
|
||||
Reader(const InputStreamP& input, const String& filename = wxEmptyString);
|
||||
Reader(const InputStreamP& input, const String& filename = wxEmptyString, bool ignore_invalid = false);
|
||||
|
||||
/// Construct a reader that reads a file in a package
|
||||
/** Used for "include file" keys. */
|
||||
@@ -127,6 +127,8 @@ class Reader {
|
||||
};
|
||||
/// Aliasses for compatability
|
||||
map<String, Alias> aliasses;
|
||||
/// Should all invalid keys be ignored?
|
||||
bool ignore_invalid;
|
||||
|
||||
/// Filename for error messages
|
||||
String filename;
|
||||
|
||||
+17
-7
@@ -14,15 +14,24 @@
|
||||
UInt Version::toNumber() const { return version; }
|
||||
|
||||
String Version::toString() const {
|
||||
return String() <<
|
||||
((version / 10000) % 100) <<
|
||||
_(".") << ((version / 100) % 100) <<
|
||||
_(".") << ((version / 1) % 100);
|
||||
if (version > 20000000) {
|
||||
// major > 2000, the version is a date, use ISO notation
|
||||
return String::Format(_("%04d-%02d-%02d"),
|
||||
(version / 10000) ,
|
||||
(version / 100) % 100,
|
||||
(version / 1) % 100);
|
||||
} else {
|
||||
return String::Format(_("%d.%d.%d"),
|
||||
(version / 10000) ,
|
||||
(version / 100) % 100,
|
||||
(version / 1) % 100);
|
||||
}
|
||||
}
|
||||
|
||||
Version Version::fromString(const String& version) {
|
||||
UInt major = 0, minor = 0, build = 0;
|
||||
wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build);
|
||||
if (wxSscanf(version, _("%u.%u.%u"), &major, &minor, &build)<=1) // a.b.c style
|
||||
wxSscanf(version, _("%u-%u-%u"), &major, &minor, &build); // date style
|
||||
return Version(major * 10000 + minor * 100 + build);
|
||||
}
|
||||
|
||||
@@ -40,7 +49,7 @@ template <> void GetDefaultMember::handle(const Version& v) {
|
||||
// ----------------------------------------------------------------------------- : Versions
|
||||
|
||||
// NOTE: Don't use leading zeroes, they mean octal
|
||||
const Version app_version = 301; // 0.3.1
|
||||
const Version app_version = 302; // 0.3.2
|
||||
const Char* version_suffix = _(" (beta)");
|
||||
|
||||
/* Changes:
|
||||
@@ -50,5 +59,6 @@ const Char* version_suffix = _(" (beta)");
|
||||
* 0.2.7 : new tag system, different style of close tags
|
||||
* 0.3.0 : port of code to C++
|
||||
* 0.3.1 : new keyword system, some new style options
|
||||
* 0.3.2 : package dependencies
|
||||
*/
|
||||
const Version file_version = 301; // 0.3.1
|
||||
const Version file_version = 302; // 0.3.2
|
||||
|
||||
Reference in New Issue
Block a user