Commit 5fb8cafb authored by twanvl's avatar twanvl

Big change set:

* Use ScriptValueP for all Value types.
  All Value types now inherit from AnyValue, all Fields inherit from AnyField.
  Common properties, in particular scripting, are done by AnyValue/AnyField

* Repurposed ImageValueToImage as the representation for image values.

* Added LocalSymbolFile as the representation for symbol values.

* Moved FileName to package.hpp, and renamed it to LocalFileName.
  The notification of packages that was previously done by Reader/Writer is now done by LocalFileName.

* Added toFriendlyString to ScriptValue, it is used (primarily) for the card list.
  The idea is that this function strips tags and always returns something, for example "<image>" for images.

* Removed backwards compatibility with 0.2.7 style tags, since I was too lazy to update it.

Code is a bit messy right now, since cleanup will come in separate commits.
parent 70f7be2b
...@@ -6,8 +6,16 @@ ...@@ -6,8 +6,16 @@
-- trunk: new items added as changes are made -- trunk: new items added as changes are made
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Program:
* Changed the way values are saved to files.
Instead of the representation depending on the type, all values now use script syntax, e.g. "strings" in quotes.
Older files can still be opened, but sets saved with 2.0.1 can not be opened with older versions of mse.
Templates:
* many changes
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- 2.0.0 -- 2.0.0, 2011-??-??
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
Program: Program:
......
...@@ -25,7 +25,21 @@ The type of a value depends on the corresponding field: ...@@ -25,7 +25,21 @@ The type of a value depends on the corresponding field:
| @"color"@ opaque [[type:color]] A color. | @"color"@ opaque [[type:color]] A color.
| @"info"@ [[type:string]] A label for the information box. | @"info"@ [[type:string]] A label for the information box.
--Example-- --File syntax--
DOC_MSE_VERSION: since 2.0.1
Values are stored using script syntax. This makes means that a value can be parsed without knowing the field type.
Here are some examples
>some_text_value: "This is a string\nNext line."
>some_choice_value: "uncommon"
>some_image_value: local_image_file("image1.png")
>some_symbol_value: local_symbol_file("symbol1.mse-symbol")
--Example (old syntax)--
DOC_MSE_VERSION: before 2.0.1
For the field: For the field:
>field: >field:
> type: choice > type: choice
......
...@@ -64,7 +64,7 @@ void KeywordReminderTextValue::store() { ...@@ -64,7 +64,7 @@ void KeywordReminderTextValue::store() {
return; return;
} }
// new value // new value
String new_value = untag(value); String new_value = untag(value->toString());
// Try to parse the script // Try to parse the script
vector<ScriptParseError> parse_errors; vector<ScriptParseError> parse_errors;
ScriptP new_script = parse(new_value, nullptr, true, parse_errors); ScriptP new_script = parse(new_value, nullptr, true, parse_errors);
...@@ -173,7 +173,7 @@ void KeywordReminderTextValue::highlight(const String& code, const vector<Script ...@@ -173,7 +173,7 @@ void KeywordReminderTextValue::highlight(const String& code, const vector<Script
} }
} }
// set // set
value = new_value; value = to_script(new_value);
} }
bool KeywordReminderTextValue::checkScript(const ScriptP& script) { bool KeywordReminderTextValue::checkScript(const ScriptP& script) {
......
...@@ -48,10 +48,18 @@ inline void swap_value(ColorValue& a, ColorValue ::ValueType& b ...@@ -48,10 +48,18 @@ inline void swap_value(ColorValue& a, ColorValue ::ValueType& b
#if USE_SCRIPT_VALUE_VALUE #if USE_SCRIPT_VALUE_VALUE
inline void swap_value(AnyValue& a, AnyValue ::ValueType& b) { swap(a.value, b); } inline void swap_value(AnyValue& a, AnyValue ::ValueType& b) { swap(a.value, b); }
#endif #endif
#if !USE_SCRIPT_VALUE_IMAGE
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); } inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); }
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); } inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); }
#endif
#if !USE_SCRIPT_VALUE_TEXT
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); } inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); }
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); } inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); }
#endif
/// A ValueAction that swaps between old and new values /// A ValueAction that swaps between old and new values
template <typename T, bool ALLOW_MERGE> template <typename T, bool ALLOW_MERGE>
...@@ -92,9 +100,15 @@ ValueAction* value_action(const ColorValueP& value, const Defaultable<C ...@@ -92,9 +100,15 @@ ValueAction* value_action(const ColorValueP& value, const Defaultable<C
#if USE_SCRIPT_VALUE_VALUE #if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value) { return new SimpleValueAction<AnyValue, false>(value, new_value); } ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value) { return new SimpleValueAction<AnyValue, false>(value, new_value); }
#endif #endif
#if !USE_SCRIPT_VALUE_IMAGE
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value); } ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); } ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); }
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction<PackageChoiceValue, false>(value, new_value); } ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction<PackageChoiceValue, false>(value, new_value); }
#endif
// ----------------------------------------------------------------------------- : MultipleChoice // ----------------------------------------------------------------------------- : MultipleChoice
...@@ -119,7 +133,11 @@ void MultipleChoiceValueAction::perform(bool to_undo) { ...@@ -119,7 +133,11 @@ void MultipleChoiceValueAction::perform(bool to_undo) {
// ----------------------------------------------------------------------------- : Text // ----------------------------------------------------------------------------- : Text
#if USE_SCRIPT_VALUE_TEXT
TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const ScriptValueP& new_value, const String& name)
#else
TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name) TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name)
#endif
: ValueAction(value) : ValueAction(value)
, selection_start(start), selection_end(end), new_selection_end(new_end) , selection_start(start), selection_end(end), new_selection_end(new_end)
, new_value(new_value) , new_value(new_value)
...@@ -164,22 +182,22 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag ...@@ -164,22 +182,22 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag
swap(start_i, end_i); swap(start_i, end_i);
} }
String new_value; String new_value;
const String& str = value->value(); String old_value = value->value->toString();
// Are we inside the tag we are toggling? // Are we inside the tag we are toggling?
if (!is_in_tag(str, _("<") + tag, start_i, end_i)) { if (!is_in_tag(old_value, _("<") + tag, start_i, end_i)) {
// we are not inside this tag, add it // we are not inside this tag, add it
new_value = str.substr(0, start_i); new_value = old_value.substr(0, start_i);
new_value += _("<") + tag + _(">"); new_value += _("<") + tag + _(">");
new_value += str.substr(start_i, end_i - start_i); new_value += old_value.substr(start_i, end_i - start_i);
new_value += _("</") + tag + _(">"); new_value += _("</") + tag + _(">");
new_value += str.substr(end_i); new_value += old_value.substr(end_i);
} else { } else {
// we are inside this tag, 'remove' it // we are inside this tag, 'remove' it
new_value = str.substr(0, start_i); new_value = old_value.substr(0, start_i);
new_value += _("</") + tag + _(">"); new_value += _("</") + tag + _(">");
new_value += str.substr(start_i, end_i - start_i); new_value += old_value.substr(start_i, end_i - start_i);
new_value += _("<") + tag + _(">"); new_value += _("<") + tag + _(">");
new_value += str.substr(end_i); new_value += old_value.substr(end_i);
} }
// Build action // Build action
if (start != end) { if (start != end) {
...@@ -187,10 +205,10 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag ...@@ -187,10 +205,10 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag
// user to press Ctrl+B and start typing bold text // user to press Ctrl+B and start typing bold text
new_value = simplify_tagged(new_value); new_value = simplify_tagged(new_value);
} }
if (value->value() == new_value) { if (new_value == old_value) {
return nullptr; // no changes return nullptr; // no changes
} else { } else {
return new TextValueAction(value, start, end, end, new_value, action_name); return new TextValueAction(value, start, end, end, to_script(new_value), action_name);
} }
} }
...@@ -200,15 +218,16 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e ...@@ -200,15 +218,16 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e
swap(start, end); swap(start, end);
swap(start_i, end_i); swap(start_i, end_i);
} }
String new_value = tagged_substr_replace(value->value(), start_i, end_i, replacement); String old_value = value->value->toString();
if (value->value() == new_value) { String new_value = tagged_substr_replace(old_value, start_i, end_i, replacement);
if (new_value == old_value) {
// no change // no change
return nullptr; return nullptr;
} else { } else {
if (reverse) { if (reverse) {
return new TextValueAction(value, end, start, start+untag(replacement).size(), new_value, action_name); return new TextValueAction(value, end, start, start+untag(replacement).size(), to_script(new_value), action_name);
} else { } else {
return new TextValueAction(value, start, end, start+untag(replacement).size(), new_value, action_name); return new TextValueAction(value, start, end, start+untag(replacement).size(), to_script(new_value), action_name);
} }
} }
} }
...@@ -218,11 +237,12 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e ...@@ -218,11 +237,12 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e
TextToggleReminderAction::TextToggleReminderAction(const TextValueP& value, size_t pos_in) TextToggleReminderAction::TextToggleReminderAction(const TextValueP& value, size_t pos_in)
: ValueAction(value) : ValueAction(value)
{ {
pos = in_tag(value->value(), _("<kw-"), pos_in, pos_in); String old_value = value->value->toString();
pos = in_tag(old_value, _("<kw-"), pos_in, pos_in);
if (pos == String::npos) { if (pos == String::npos) {
throw InternalError(_("TextToggleReminderAction: not in <kw- tag")); throw InternalError(_("TextToggleReminderAction: not in <kw- tag"));
} }
Char c = value->value().GetChar(pos + 4); Char c = old_value.GetChar(pos + 4);
enable = !(c == _('1') || c == _('A')); // if it was not enabled, then enable it enable = !(c == _('1') || c == _('A')); // if it was not enabled, then enable it
old = enable ? _('1') : _('0'); old = enable ? _('1') : _('0');
} }
...@@ -233,7 +253,7 @@ String TextToggleReminderAction::getName(bool to_undo) const { ...@@ -233,7 +253,7 @@ String TextToggleReminderAction::getName(bool to_undo) const {
void TextToggleReminderAction::perform(bool to_undo) { void TextToggleReminderAction::perform(bool to_undo) {
ValueAction::perform(to_undo); ValueAction::perform(to_undo);
TextValue& value = static_cast<TextValue&>(*valueP); TextValue& value = static_cast<TextValue&>(*valueP);
String& val = value.value.mutate(); String val = value.value->toString();
assert(pos + 4 < val.size()); assert(pos + 4 < val.size());
size_t end = match_close_tag(val, pos); size_t end = match_close_tag(val, pos);
Char& c = val[pos + 4]; Char& c = val[pos + 4];
...@@ -241,6 +261,7 @@ void TextToggleReminderAction::perform(bool to_undo) { ...@@ -241,6 +261,7 @@ void TextToggleReminderAction::perform(bool to_undo) {
if (end != String::npos && end + 5 < val.size()) { if (end != String::npos && end + 5 < val.size()) {
val[end + 5] = c; // </kw-c> val[end + 5] = c; // </kw-c>
} }
value.value = to_script(val);
value.onAction(*this, to_undo); // notify value value.onAction(*this, to_undo); // notify value
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
class Card; class Card;
class StyleSheet; class StyleSheet;
class LocalFileName;
DECLARE_POINTER_TYPE(Set); DECLARE_POINTER_TYPE(Set);
DECLARE_POINTER_TYPE(Value); DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(Style); DECLARE_POINTER_TYPE(Style);
...@@ -81,9 +82,15 @@ ValueAction* value_action(const MultipleChoiceValueP& value, const ScriptValueP& ...@@ -81,9 +82,15 @@ ValueAction* value_action(const MultipleChoiceValueP& value, const ScriptValueP&
#if !USE_SCRIPT_VALUE_COLOR #if !USE_SCRIPT_VALUE_COLOR
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value); ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value);
#endif #endif
ValueAction* value_action(const ImageValueP& value, const FileName& new_value); #if !USE_SCRIPT_VALUE_IMAGE
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value); ValueAction* value_action(const ImageValueP& value, const LocalFileName& new_value);
#endif
#if !USE_SCRIPT_VALUE_SYMBOL
ValueAction* value_action(const SymbolValueP& value, const LocalFileName& new_value);
#endif
#if !USE_SCRIPT_VALUE_PACKAGE
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value); ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value);
#endif
#if USE_SCRIPT_VALUE_VALUE #if USE_SCRIPT_VALUE_VALUE
ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value); ValueAction* value_action(const AnyValueP& value, const ScriptValueP& new_value);
#endif #endif
...@@ -116,13 +123,21 @@ class MultipleChoiceValueAction : public ValueAction { ...@@ -116,13 +123,21 @@ class MultipleChoiceValueAction : public ValueAction {
/// An action that changes a TextValue /// An action that changes a TextValue
class TextValueAction : public ValueAction { class TextValueAction : public ValueAction {
public: public:
#if USE_SCRIPT_VALUE_TEXT
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const ScriptValueP& new_value, const String& name);
#else
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name); TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name);
#endif
virtual String getName(bool to_undo) const; virtual String getName(bool to_undo) const;
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
virtual bool merge(const Action& action); virtual bool merge(const Action& action);
#if USE_SCRIPT_VALUE_TEXT
inline String newValue() const { return new_value->toString(); }
#else
inline const String& newValue() const { return new_value(); } inline const String& newValue() const { return new_value(); }
#endif
/// The modified selection /// The modified selection
size_t selection_start, selection_end; size_t selection_start, selection_end;
...@@ -130,7 +145,11 @@ class TextValueAction : public ValueAction { ...@@ -130,7 +145,11 @@ class TextValueAction : public ValueAction {
inline TextValue& value() const; inline TextValue& value() const;
size_t new_selection_end; size_t new_selection_end;
#if USE_SCRIPT_VALUE_TEXT
ScriptValueP new_value;
#else
Defaultable<String> new_value; Defaultable<String> new_value;
#endif
String name; String name;
}; };
......
...@@ -44,12 +44,12 @@ String Card::identification() const { ...@@ -44,12 +44,12 @@ String Card::identification() const {
// an identifying field // an identifying field
FOR_EACH_CONST(v, data) { FOR_EACH_CONST(v, data) {
if (v->fieldP->identifying) { if (v->fieldP->identifying) {
return v->toString(); return v->toFriendlyString();
} }
} }
// otherwise the first field // otherwise the first field
if (!data.empty()) { if (!data.empty()) {
return data.at(0)->toString(); return data.at(0)->toFriendlyString();
} else { } else {
return wxEmptyString; return wxEmptyString;
} }
...@@ -57,7 +57,7 @@ String Card::identification() const { ...@@ -57,7 +57,7 @@ String Card::identification() const {
bool Card::contains(String const& query) const { bool Card::contains(String const& query) const {
FOR_EACH_CONST(v, data) { FOR_EACH_CONST(v, data) {
if (find_i(v->toString(),query) != String::npos) return true; if (find_i(v->toFriendlyString(),query) != String::npos) return true;
} }
if (find_i(notes,query) != String::npos) return true; if (find_i(notes,query) != String::npos) return true;
return false; return false;
......
...@@ -321,6 +321,8 @@ IMPLEMENT_DYNAMIC_ARG(Field const*, field_for_reading, nullptr); ...@@ -321,6 +321,8 @@ IMPLEMENT_DYNAMIC_ARG(Field const*, field_for_reading, nullptr);
// * mark_default(value) # a value marked as being default // * mark_default(value) # a value marked as being default
void parse_errors_to_reader_warnings(Reader& reader, vector<ScriptParseError> const& errors); void parse_errors_to_reader_warnings(Reader& reader, vector<ScriptParseError> const& errors);
ScriptValueP script_local_image_file(LocalFileName const& filename);
ScriptValueP script_local_symbol_file(LocalFileName const& filename);
void Reader::handle(ScriptValueP& value) { void Reader::handle(ScriptValueP& value) {
Field const* field = field_for_reading(); Field const* field = field_for_reading();
...@@ -331,7 +333,7 @@ void Reader::handle(ScriptValueP& value) { ...@@ -331,7 +333,7 @@ void Reader::handle(ScriptValueP& value) {
bool x; bool x;
handle(x); handle(x);
value = to_script(x); value = to_script(x);
} else if (dynamic_cast<TextField const*>(field) || dynamic_cast<ChoiceField const*>(field)) { } else if (dynamic_cast<TextField const*>(field) || dynamic_cast<ChoiceField const*>(field) || dynamic_cast<PackageChoiceField const*>(field)) {
// text, choice fields: string // text, choice fields: string
String str; String str;
handle(str); handle(str);
...@@ -345,25 +347,33 @@ void Reader::handle(ScriptValueP& value) { ...@@ -345,25 +347,33 @@ void Reader::handle(ScriptValueP& value) {
// image, symbol fields: string that is a filename in the set // image, symbol fields: string that is a filename in the set
String str; String str;
handle(str); handle(str);
//Packaged* package = package_for_reading(); value = script_local_image_file(LocalFileName::fromReadString(str));
Packaged* package = nullptr; // TODO } else if (dynamic_cast<SymbolField const*>(field)) {
value = intrusive(new ScriptLocalFileName(package,str)); // image, symbol fields: string that is a filename in the set
throw "TODO"; String str;
handle(str);
value = script_local_symbol_file(LocalFileName::fromReadString(str));
} else if (dynamic_cast<InfoField const*>(field)) { } else if (dynamic_cast<InfoField const*>(field)) {
// this should never happen, since info fields were not saved // this should never happen, since info fields were not saved
String str; String str;
handle(str); handle(str);
} else {
throw InternalError(_("Reader::handle(ScriptValueP)"));
} }
} else { } else {
// in the new system, the type is stored in the file. // in the new system, the type is stored in the file.
String unparsed; String unparsed;
vector<ScriptParseError> errors;
handle(unparsed); handle(unparsed);
value = parse_value(unparsed, this->getPackage(), errors); if (unparsed.empty()) {
if (!value) {
value = script_default_nil; value = script_default_nil;
} else {
vector<ScriptParseError> errors;
value = parse_value(unparsed, this->getPackage(), errors);
if (!value) {
value = script_default_nil;
}
parse_errors_to_reader_warnings(*this, errors);
} }
parse_errors_to_reader_warnings(*this, errors);
} }
} }
void Writer::handle(ScriptValueP const& value) { void Writer::handle(ScriptValueP const& value) {
...@@ -411,11 +421,17 @@ AnyValue::AnyValue(AnyFieldP const& field, ScriptValueP const& value) ...@@ -411,11 +421,17 @@ AnyValue::AnyValue(AnyFieldP const& field, ScriptValueP const& value)
ValueP AnyValue::clone() const { ValueP AnyValue::clone() const {
return intrusive(new AnyValue(*this)); return intrusive(new AnyValue(*this));
} }
String AnyValue::toString() const { String AnyValue::toFriendlyString() const {
return value->toString(); try {
return value->toFriendlyString();
} catch (...) {
return _("<") + value->typeName() + _(">");
}
} }
bool AnyValue::update(Context& ctx, const Action* act) { bool AnyValue::update(Context& ctx, const Action* act) {
WITH_DYNAMIC_ARG(last_update_age, last_modified.get()); // TODO: this is redundant, since it can be got from value_being_updated
WITH_DYNAMIC_ARG(value_being_updated, this);
bool change = false; bool change = false;
if (ScriptDefault const* dv = dynamic_cast<ScriptDefault*>(value.get())) { if (ScriptDefault const* dv = dynamic_cast<ScriptDefault*>(value.get())) {
ScriptValueP dvv = dv->un_default; ScriptValueP dvv = dv->un_default;
......
...@@ -37,14 +37,14 @@ DECLARE_DYNAMIC_ARG(Value*, value_being_updated); ...@@ -37,14 +37,14 @@ DECLARE_DYNAMIC_ARG(Value*, value_being_updated);
// experimental: use ScriptValue to store any kind of value // experimental: use ScriptValue to store any kind of value
// TODO: get rid of the conditional stuff // TODO: get rid of the conditional stuff
// TODO2: mergre Any{Field,Value} into {Field,Value} // TODO2: mergre Any{Field,Value} into {Field,Value}
#define USE_SCRIPT_VALUE_VALUE 0 #define USE_SCRIPT_VALUE_VALUE 1
#define USE_SCRIPT_VALUE_COLOR 0 #define USE_SCRIPT_VALUE_COLOR 1
#define USE_SCRIPT_VALUE_CHOICE 0 #define USE_SCRIPT_VALUE_CHOICE 1
#define USE_SCRIPT_VALUE_INFO 0 #define USE_SCRIPT_VALUE_INFO 1
#define USE_SCRIPT_VALUE_TEXT 0 #define USE_SCRIPT_VALUE_TEXT 1
#define USE_SCRIPT_VALUE_SYMBOL 0 #define USE_SCRIPT_VALUE_SYMBOL 1
#define USE_SCRIPT_VALUE_IMAGE 0 #define USE_SCRIPT_VALUE_IMAGE 1
#define USE_SCRIPT_VALUE_PACKAGE 0 #define USE_SCRIPT_VALUE_PACKAGE 1
// ----------------------------------------------------------------------------- : Field // ----------------------------------------------------------------------------- : Field
...@@ -83,9 +83,10 @@ class Field : public IntrusivePtrVirtualBase { ...@@ -83,9 +83,10 @@ class Field : public IntrusivePtrVirtualBase {
/// Add the given dependency to the dependet_scripts list for the variables this field depends on /// Add the given dependency to the dependet_scripts list for the variables this field depends on
virtual void initDependencies(Context& ctx, const Dependency& dep) const; virtual void initDependencies(Context& ctx, const Dependency& dep) const;
virtual void after_reading(Version ver);
private: private:
DECLARE_REFLECTION_VIRTUAL(); DECLARE_REFLECTION_VIRTUAL();
virtual void after_reading(Version ver);
friend void after_reading(Field& s, Version ver);
}; };
template <> template <>
...@@ -176,6 +177,8 @@ class Style : public IntrusivePtrVirtualBase { ...@@ -176,6 +177,8 @@ class Style : public IntrusivePtrVirtualBase {
private: private:
DECLARE_REFLECTION_VIRTUAL(); DECLARE_REFLECTION_VIRTUAL();
virtual void after_reading(Version ver) {}
friend void after_reading(Style& s, Version ver);
/// Things that are listening to changes in this style /// Things that are listening to changes in this style
vector<StyleListener*> listeners; vector<StyleListener*> listeners;
}; };
...@@ -199,6 +202,10 @@ inline String type_name(const Style&) { ...@@ -199,6 +202,10 @@ inline String type_name(const Style&) {
return _TYPE_("style"); return _TYPE_("style");
} }
inline void after_reading(Style& s, Version ver) {
s.after_reading(ver);
}
void mark_dependency_member(const Style& style, const String& name, const Dependency& dep); void mark_dependency_member(const Style& style, const String& name, const Dependency& dep);
// ----------------------------------------------------------------------------- : StyleListener // ----------------------------------------------------------------------------- : StyleListener
...@@ -232,8 +239,8 @@ class Value : public IntrusivePtrVirtualBase { ...@@ -232,8 +239,8 @@ class Value : public IntrusivePtrVirtualBase {
/// Get a copy of this value /// Get a copy of this value
virtual ValueP clone() const = 0; virtual ValueP clone() const = 0;
/// Convert this value to a string for use in tables /// Convert this value to a string, should be human readable, so no <tags>
virtual String toString() const = 0; virtual String toFriendlyString() const = 0;
/// Apply scripts to this value, return true if the value has changed /// Apply scripts to this value, return true if the value has changed
/** Optionally, the action that causes the update is also passed. /** Optionally, the action that causes the update is also passed.
*/ */
...@@ -250,7 +257,7 @@ class Value : public IntrusivePtrVirtualBase { ...@@ -250,7 +257,7 @@ class Value : public IntrusivePtrVirtualBase {
/// Get the key to use for sorting this value /// Get the key to use for sorting this value
inline String getSortKey() const { inline String getSortKey() const {
return fieldP->sort_script ? sort_value : toString(); return fieldP->sort_script ? sort_value : toFriendlyString();
} }
protected: protected:
...@@ -309,7 +316,7 @@ inline String type_name(const Value&) { ...@@ -309,7 +316,7 @@ inline String type_name(const Value&) {
DECLARE_REFLECTION(); public: \ DECLARE_REFLECTION(); public: \
DECLARE_HAS_FIELD(Type) \ DECLARE_HAS_FIELD(Type) \
virtual ValueP clone() const; \ virtual ValueP clone() const; \
virtual String toString() const; \ virtual String toFriendlyString() const; \
typedef ValueType_ ValueType typedef ValueType_ ValueType
// implement field() which returns a field with the right (derived) type // implement field() which returns a field with the right (derived) type
...@@ -346,12 +353,17 @@ class AnyValue : public Value { ...@@ -346,12 +353,17 @@ class AnyValue : public Value {
/// The actual value /// The actual value
typedef ScriptValueP ValueType; typedef ScriptValueP ValueType;
ScriptValueP value; ScriptValueP value; // never null
virtual ValueP clone() const; virtual ValueP clone() const;
virtual String toString() const; virtual String toFriendlyString() const;
virtual bool update(Context& ctx, const Action* = nullptr); virtual bool update(Context& ctx, const Action* = nullptr);
// Convenience functions
inline void operator = (ScriptValueP const& value) {
this->value = value;
}
DECLARE_HAS_FIELD(Any) DECLARE_HAS_FIELD(Any)
DECLARE_REFLECTION_VIRTUAL(); DECLARE_REFLECTION_VIRTUAL();
}; };
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
// ----------------------------------------------------------------------------- : BooleanField // ----------------------------------------------------------------------------- : BooleanField
BooleanField::BooleanField() { BooleanField::BooleanField() {
choices->choices.push_back(intrusive(new Choice(_("yes")))); choices->choices.push_back(intrusive(new Choice(_("true"),_("yes"))));
choices->choices.push_back(intrusive(new Choice(_("no")))); choices->choices.push_back(intrusive(new Choice(_("false"),_("no"))));
choices->initIds(); choices->initIds();
#if USE_SCRIPT_VALUE_CHOICE #if USE_SCRIPT_VALUE_CHOICE
initial = script_true; initial = script_true;
...@@ -39,12 +39,21 @@ BooleanStyle::BooleanStyle(const ChoiceFieldP& field) ...@@ -39,12 +39,21 @@ BooleanStyle::BooleanStyle(const ChoiceFieldP& field)
: ChoiceStyle(field) : ChoiceStyle(field)
{ {
render_style = RENDER_BOTH; render_style = RENDER_BOTH;
//choice_images[_("yes")] = ScriptableImage(_("buildin_image(\"bool_yes\")")); choice_images[_("true")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_yes"))));
//choice_images[_("no")] = ScriptableImage(_("buildin_image(\"bool_no\")")); choice_images[_("false")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_no"))));
choice_images[_("yes")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_yes"))));
choice_images[_("no")] = ScriptableImage(intrusive(new BuiltInImage(_("bool_no"))));
} }
IMPLEMENT_REFLECTION(BooleanStyle) { IMPLEMENT_REFLECTION(BooleanStyle) {
REFLECT_BASE(ChoiceStyle); REFLECT_BASE(ChoiceStyle);
} }
void BooleanStyle::after_reading(Version ver) {
// Prior to 2.0.1, the choices were called "yes" and "no"
if (!choice_images[_("true")].isScripted() && choice_images.find(_("yes")) != choice_images.end()) {
choice_images[_("true")] = choice_images[_("yes")];
}
if (!choice_images[_("false")].isScripted() && choice_images.find(_("no")) != choice_images.end()) {
choice_images[_("false")] = choice_images[_("no")];
}
}
...@@ -39,6 +39,7 @@ class BooleanStyle : public ChoiceStyle { ...@@ -39,6 +39,7 @@ class BooleanStyle : public ChoiceStyle {
private: private:
DECLARE_REFLECTION(); DECLARE_REFLECTION();
virtual void after_reading(Version ver);
}; };
// ----------------------------------------------------------------------------- : BooleanValue // ----------------------------------------------------------------------------- : BooleanValue
......
...@@ -70,8 +70,8 @@ ChoiceField::Choice::Choice() ...@@ -70,8 +70,8 @@ ChoiceField::Choice::Choice()
: line_below(false), enabled(true), type(CHOICE_TYPE_CHECK) : line_below(false), enabled(true), type(CHOICE_TYPE_CHECK)
, first_id(0) , first_id(0)
{} {}
ChoiceField::Choice::Choice(const String& name) ChoiceField::Choice::Choice(const String& name, const String& caption)
: name(name) : name(name), caption(caption)
, line_below(false), enabled(true), type(CHOICE_TYPE_CHECK) , line_below(false), enabled(true), type(CHOICE_TYPE_CHECK)
, first_id(0) , first_id(0)
{} {}
...@@ -316,7 +316,7 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice) ...@@ -316,7 +316,7 @@ ChoiceValue::ChoiceValue(const ChoiceFieldP& field, bool initial_first_choice)
, true) , true)
{} {}
String ChoiceValue::toString() const { String ChoiceValue::toFriendlyString() const {
return value(); return value();
} }
bool ChoiceValue::update(Context& ctx, const Action*) { bool ChoiceValue::update(Context& ctx, const Action*) {
......
...@@ -64,9 +64,10 @@ enum ChoiceChoiceType { ...@@ -64,9 +64,10 @@ enum ChoiceChoiceType {
class ChoiceField::Choice : public IntrusivePtrBase<ChoiceField::Choice> { class ChoiceField::Choice : public IntrusivePtrBase<ChoiceField::Choice> {
public: public:
Choice(); Choice();
Choice(const String& name); Choice(const String& name, const String& caption);
String name; ///< Name/value of the item String name; ///< Name/value of the item
String caption; ///< Caption that is shown in menus etc.
String default_name; ///< A default item, if this is a group and default_name.empty() there is no default String default_name; ///< A default item, if this is a group and default_name.empty() there is no default
vector<ChoiceP> choices; ///< Choices and sub groups in this group vector<ChoiceP> choices; ///< Choices and sub groups in this group
bool line_below; ///< Show a line after this item? bool line_below; ///< Show a line after this item?
......
...@@ -95,7 +95,7 @@ ColorValue::ColorValue(const ColorFieldP& field) ...@@ -95,7 +95,7 @@ ColorValue::ColorValue(const ColorFieldP& field)
, true) , true)
{} {}
String ColorValue::toString() const { String ColorValue::toFriendlyString() const {
if (value.isDefault()) return field().default_name; if (value.isDefault()) return field().default_name;
// is this a named color? // is this a named color?
FOR_EACH(c, field().choices) { FOR_EACH(c, field().choices) {
......
...@@ -33,9 +33,11 @@ int ImageStyle::update(Context& ctx) { ...@@ -33,9 +33,11 @@ int ImageStyle::update(Context& ctx) {
// ----------------------------------------------------------------------------- : ImageValue // ----------------------------------------------------------------------------- : ImageValue
#if !USE_SCRIPT_VALUE_IMAGE
IMPLEMENT_VALUE_CLONE(Image); IMPLEMENT_VALUE_CLONE(Image);
String ImageValue::toString() const { String ImageValue::toFriendlyString() const {
return filename.empty() ? wxEmptyString : _("<image>"); return filename.empty() ? wxEmptyString : _("<image>");
} }
...@@ -52,3 +54,4 @@ void ImageValue::reflect(GetDefaultMember& reflector) { ...@@ -52,3 +54,4 @@ void ImageValue::reflect(GetDefaultMember& reflector) {
// convert to ScriptImageP for scripting // convert to ScriptImageP for scripting
reflector.handle( (ScriptValueP)intrusive(new ImageValueToImage(filename)) ); reflector.handle( (ScriptValueP)intrusive(new ImageValueToImage(filename)) );
} }
#endif
...@@ -17,7 +17,11 @@ IMPLEMENT_FIELD_TYPE(Info, "info"); ...@@ -17,7 +17,11 @@ IMPLEMENT_FIELD_TYPE(Info, "info");
#if USE_SCRIPT_VALUE_INFO #if USE_SCRIPT_VALUE_INFO
IMPLEMENT_REFLECTION(InfoField) { IMPLEMENT_REFLECTION(InfoField) {
REFLECT_BASE(AnyField); REFLECT_BASE(AnyField);
REFLECT_IF_READING if(initial == script_default_nil) initial = to_script(caption); }
void InfoField::after_reading(Version ver) {
AnyField::after_reading(ver);
if (initial == script_default_nil) initial = to_script(caption);
initial = make_default(initial);
} }
#else #else
void InfoField::initDependencies(Context& ctx, const Dependency& dep) const { void InfoField::initDependencies(Context& ctx, const Dependency& dep) const {
...@@ -69,7 +73,7 @@ IMPLEMENT_REFLECTION(InfoStyle) { ...@@ -69,7 +73,7 @@ IMPLEMENT_REFLECTION(InfoStyle) {
IMPLEMENT_VALUE_CLONE(Info); IMPLEMENT_VALUE_CLONE(Info);
String InfoValue::toString() const { String InfoValue::toFriendlyString() const {
return value; return value;
} }
bool InfoValue::update(Context& ctx, const Action*) { bool InfoValue::update(Context& ctx, const Action*) {
......
...@@ -31,6 +31,7 @@ class InfoField : public AnyField { ...@@ -31,6 +31,7 @@ class InfoField : public AnyField {
public: public:
InfoField() { editable = false; } InfoField() { editable = false; }
DECLARE_FIELD_TYPE(); DECLARE_FIELD_TYPE();
virtual void after_reading(Version ver);
}; };
#else #else
class InfoField : public Field { class InfoField : public Field {
......
...@@ -55,20 +55,20 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) { ...@@ -55,20 +55,20 @@ IMPLEMENT_REFLECTION_NAMELESS(MultipleChoiceValue) {
} }
bool MultipleChoiceValue::update(Context& ctx, const Action* act) { bool MultipleChoiceValue::update(Context& ctx, const Action* act) {
String old_value = toString(); String old_value = value->toString();
if (const MultipleChoiceValueAction* mvca = dynamic_cast<const MultipleChoiceValueAction*>(act)) { if (const MultipleChoiceValueAction* mvca = dynamic_cast<const MultipleChoiceValueAction*>(act)) {
ctx.setVariable(_("last_change"), to_script(mvca->changed_choice)); ctx.setVariable(_("last_change"), to_script(mvca->changed_choice));
} }
ChoiceValue::update(ctx,act); ChoiceValue::update(ctx,act);
normalForm(); normalForm();
return toString() != old_value; return value->toString() != old_value;
} }
void MultipleChoiceValue::get(vector<String>& out) const { void MultipleChoiceValue::get(vector<String>& out) const {
// split the value // split the value
out.clear(); out.clear();
bool is_new = true; bool is_new = true;
String val = toString(); String val = value->toString();
FOR_EACH_CONST(c, val) { FOR_EACH_CONST(c, val) {
if (c == _(',')) { if (c == _(',')) {
is_new = true; is_new = true;
...@@ -85,7 +85,7 @@ void MultipleChoiceValue::get(vector<String>& out) const { ...@@ -85,7 +85,7 @@ void MultipleChoiceValue::get(vector<String>& out) const {
} }
void MultipleChoiceValue::normalForm() { void MultipleChoiceValue::normalForm() {
String val = toString(); String val = value->toString();
// which choices are active? // which choices are active?
vector<bool> seen(field().choices->lastId()); vector<bool> seen(field().choices->lastId());
for (size_t pos = 0 ; pos < val.size() ; ) { for (size_t pos = 0 ; pos < val.size() ; ) {
......
...@@ -14,16 +14,22 @@ ...@@ -14,16 +14,22 @@
IMPLEMENT_FIELD_TYPE(PackageChoice, "package choice"); IMPLEMENT_FIELD_TYPE(PackageChoice, "package choice");
#if !USE_SCRIPT_VALUE_PACKAGE
void PackageChoiceField::initDependencies(Context& ctx, const Dependency& dep) const { void PackageChoiceField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep); Field ::initDependencies(ctx, dep);
script. initDependencies(ctx, dep); script. initDependencies(ctx, dep);
} }
#endif
IMPLEMENT_REFLECTION(PackageChoiceField) { IMPLEMENT_REFLECTION(PackageChoiceField) {
#if USE_SCRIPT_VALUE_CHOICE
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field); REFLECT_BASE(Field);
REFLECT(script); REFLECT(script);
REFLECT(match);
REFLECT(initial); REFLECT(initial);
#endif
REFLECT(match);
REFLECT(required); REFLECT(required);
REFLECT(empty_name); REFLECT(empty_name);
} }
...@@ -49,13 +55,14 @@ IMPLEMENT_REFLECTION(PackageChoiceStyle) { ...@@ -49,13 +55,14 @@ IMPLEMENT_REFLECTION(PackageChoiceStyle) {
} }
// ----------------------------------------------------------------------------- : PackageChoiceValue // ----------------------------------------------------------------------------- : PackageChoiceValue
#if !USE_SCRIPT_VALUE_PACKAGE
IMPLEMENT_VALUE_CLONE(PackageChoice); IMPLEMENT_VALUE_CLONE(PackageChoice);
String PackageChoiceValue::toString() const { String PackageChoiceValue::toFriendlyString() const {
PackagedP pack = getPackage(); PackagedP pack = getPackage();
if (pack.get()) return pack->short_name; if (pack.get()) return pack->short_name;
else return _(""); else return _("");
} }
PackagedP PackageChoiceValue::getPackage() const { PackagedP PackageChoiceValue::getPackage() const {
...@@ -87,3 +94,4 @@ void PackageChoiceValue::reflect(GetDefaultMember& reflector) { ...@@ -87,3 +94,4 @@ void PackageChoiceValue::reflect(GetDefaultMember& reflector) {
} }
} }
void PackageChoiceValue::reflect(GetMember& reflector) {} void PackageChoiceValue::reflect(GetMember& reflector) {}
#endif
...@@ -47,12 +47,39 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(SymbolVariation) { ...@@ -47,12 +47,39 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(SymbolVariation) {
// ----------------------------------------------------------------------------- : SymbolValue // ----------------------------------------------------------------------------- : SymbolValue
#if USE_SCRIPT_VALUE_SYMBOL
ScriptValueP script_local_symbol_file(LocalFileName const& filename) {
return intrusive(new LocalSymbolFile(filename));
}
String quote_string(String const& str);
String LocalSymbolFile::toCode() const {
return _("local_symbol_file(") + quote_string(filename.toStringForWriting()) + _(")");
}
String LocalSymbolFile::typeName() const {
return _("symbol");
}
GeneratedImageP LocalSymbolFile::toImage() const {
SymbolVariationP variation(new SymbolVariation);
variation->filter = intrusive(new SolidFillSymbolFilter);
return intrusive(new SymbolToImage(true, filename, variation));
}
String LocalSymbolFile::toFriendlyString() const {
return _("<") + _TYPE_("symbol") + _(">");
}
#else
IMPLEMENT_VALUE_CLONE(Symbol); IMPLEMENT_VALUE_CLONE(Symbol);
String SymbolValue::toString() const { String SymbolValue::toFriendlyString() const {
return filename.empty() ? wxEmptyString : _("<symbol>"); return filename.empty() ? wxEmptyString : _("<symbol>");
} }
IMPLEMENT_REFLECTION_NAMELESS(SymbolValue) { IMPLEMENT_REFLECTION_NO_GET_MEMBER(SymbolValue) {
if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(filename); if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(filename);
} }
void SymbolValue::reflect(GetMember&) {}
void SymbolValue::reflect(GetDefaultMember&) {}
#endif
...@@ -20,7 +20,9 @@ DECLARE_POINTER_TYPE(SymbolVariation); ...@@ -20,7 +20,9 @@ DECLARE_POINTER_TYPE(SymbolVariation);
DECLARE_POINTER_TYPE(SymbolField); DECLARE_POINTER_TYPE(SymbolField);
DECLARE_POINTER_TYPE(SymbolStyle); DECLARE_POINTER_TYPE(SymbolStyle);
#if !USE_SCRIPT_VALUE_SYMBOL #if USE_SCRIPT_VALUE_SYMBOL
DECLARE_POINTER_TYPE(LocalSymbolFile);
#else
DECLARE_POINTER_TYPE(SymbolValue); DECLARE_POINTER_TYPE(SymbolValue);
#endif #endif
...@@ -71,6 +73,21 @@ class SymbolVariation : public IntrusivePtrBase<SymbolVariation> { ...@@ -71,6 +73,21 @@ class SymbolVariation : public IntrusivePtrBase<SymbolVariation> {
#if USE_SCRIPT_VALUE_SYMBOL #if USE_SCRIPT_VALUE_SYMBOL
typedef AnyValue SymbolValue; typedef AnyValue SymbolValue;
typedef AnyValueP SymbolValueP; typedef AnyValueP SymbolValueP;
// A file that refers to a symbol
class LocalSymbolFile : public ScriptValue {
public:
LocalSymbolFile(LocalFileName const& filename) : filename(filename) {}
virtual String toCode() const;
virtual String typeName() const;
virtual ScriptType type() const { return SCRIPT_FILENAME; }
virtual GeneratedImageP toImage() const;
virtual String toFriendlyString() const;
LocalFileName filename; // not empty
};
#else #else
/// The Value in a SymbolField, i.e. a symbol /// The Value in a SymbolField, i.e. a symbol
class SymbolValue : public Value { class SymbolValue : public Value {
......
...@@ -15,24 +15,32 @@ ...@@ -15,24 +15,32 @@
TextField::TextField() TextField::TextField()
: multi_line(false) : multi_line(false)
#if !USE_SCRIPT_VALUE_TEXT
, default_name(_("Default")) , default_name(_("Default"))
#endif
{} {}
IMPLEMENT_FIELD_TYPE(Text, "text"); IMPLEMENT_FIELD_TYPE(Text, "text");
#if !USE_SCRIPT_VALUE_TEXT
void TextField::initDependencies(Context& ctx, const Dependency& dep) const { void TextField::initDependencies(Context& ctx, const Dependency& dep) const {
Field ::initDependencies(ctx, dep); Field ::initDependencies(ctx, dep);
script .initDependencies(ctx, dep); script .initDependencies(ctx, dep);
default_script.initDependencies(ctx, dep); default_script.initDependencies(ctx, dep);
} }
#endif
IMPLEMENT_REFLECTION(TextField) { IMPLEMENT_REFLECTION(TextField) {
#if USE_SCRIPT_VALUE_TEXT
REFLECT_BASE(AnyField);
#else
REFLECT_BASE(Field); REFLECT_BASE(Field);
REFLECT(multi_line);
REFLECT(script); REFLECT(script);
REFLECT_N("default", default_script); REFLECT_N("default", default_script);
REFLECT(default_name); REFLECT(default_name);
#endif
REFLECT(multi_line);
} }
// ----------------------------------------------------------------------------- : TextStyle // ----------------------------------------------------------------------------- : TextStyle
...@@ -132,9 +140,11 @@ IMPLEMENT_REFLECTION(TextStyle) { ...@@ -132,9 +140,11 @@ IMPLEMENT_REFLECTION(TextStyle) {
// ----------------------------------------------------------------------------- : TextValue // ----------------------------------------------------------------------------- : TextValue
#if !USE_SCRIPT_VALUE_TEXT
IMPLEMENT_VALUE_CLONE(Text); IMPLEMENT_VALUE_CLONE(Text);
String TextValue::toString() const { String TextValue::toFriendlyString() const {
return untag_hide_sep(value()); return untag_hide_sep(value());
} }
bool TextValue::update(Context& ctx, const Action*) { bool TextValue::update(Context& ctx, const Action*) {
...@@ -150,6 +160,8 @@ IMPLEMENT_REFLECTION_NAMELESS(TextValue) { ...@@ -150,6 +160,8 @@ IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(value); if (fieldP->save_value || !reflector.isWriting()) REFLECT_NAMELESS(value);
} }
#endif
// ----------------------------------------------------------------------------- : FakeTextValue // ----------------------------------------------------------------------------- : FakeTextValue
FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool editable, bool untagged) FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool editable, bool untagged)
...@@ -160,7 +172,7 @@ FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool e ...@@ -160,7 +172,7 @@ FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool e
void FakeTextValue::store() { void FakeTextValue::store() {
if (underlying) { if (underlying) {
if (editable) { if (editable) {
*underlying = untagged ? untag(value) : value(); *underlying = untagged ? untag(value->toString()) : value->toString();
} else { } else {
retrieve(); retrieve();
} }
...@@ -168,9 +180,9 @@ void FakeTextValue::store() { ...@@ -168,9 +180,9 @@ void FakeTextValue::store() {
} }
void FakeTextValue::retrieve() { void FakeTextValue::retrieve() {
if (underlying) { if (underlying) {
value.assign(untagged ? escape(*underlying) : *underlying); value = to_script(untagged ? escape(*underlying) : *underlying);
} else { } else {
value.assign(wxEmptyString); value = script_default_nil;
} }
} }
......
...@@ -42,8 +42,6 @@ class TextField : public Field { ...@@ -42,8 +42,6 @@ class TextField : public Field {
#if !USE_SCRIPT_VALUE_TEXT #if !USE_SCRIPT_VALUE_TEXT
OptionalScript script; ///< Script to apply to all values OptionalScript script; ///< Script to apply to all values
OptionalScript default_script; ///< Script that generates the default value OptionalScript default_script; ///< Script that generates the default value
//%OptionalScript view_script; ///< Script to apply before viewing
//%OptionalScript unview_script; ///< Script to apply after changes to the view
String default_name; ///< Name of "default" value String default_name; ///< Name of "default" value
virtual void initDependencies(Context&, const Dependency&) const; virtual void initDependencies(Context&, const Dependency&) const;
......
...@@ -360,6 +360,9 @@ void ApprDistro::writeD(wxTextOutputStream& tout, const String& name, int c, int ...@@ -360,6 +360,9 @@ void ApprDistro::writeD(wxTextOutputStream& tout, const String& name, int c, int
String untag_appr(const String& s) { String untag_appr(const String& s) {
return replace_all(untag(curly_quotes(s,false)), _("\n"), _("\r\n")); return replace_all(untag(curly_quotes(s,false)), _("\n"), _("\r\n"));
} }
inline String untag_appr(const ScriptValueP& str) {
return untag_appr(str->toString());
}
DECLARE_POINTER_TYPE(ApprCardRecord); DECLARE_POINTER_TYPE(ApprCardRecord);
DECLARE_TYPEOF_COLLECTION(ApprCardRecordP); DECLARE_TYPEOF_COLLECTION(ApprCardRecordP);
...@@ -422,10 +425,10 @@ class ApprCardRecord : public IntrusivePtrBase<ApprCardRecord> { ...@@ -422,10 +425,10 @@ class ApprCardRecord : public IntrusivePtrBase<ApprCardRecord> {
// conversion from MSE2 card // conversion from MSE2 card
ApprCardRecord::ApprCardRecord(const Card& card, const String& sets_) { ApprCardRecord::ApprCardRecord(const Card& card, const String& sets_) {
name = untag_appr(card.value<TextValue>(_("name")).value); name = untag_appr(card.value<TextValue>(_("name")).value);
sets = sets_ + _("-") + card_rarity_code(card.value<ChoiceValue>(_("rarity")).value); sets = sets_ + _("-") + card_rarity_code(card.value<ChoiceValue>(_("rarity")).value->toString());
cc = untag_appr(card.value<TextValue>(_("casting_cost")).value); cc = untag_appr(card.value<TextValue>(_("casting_cost")).value);
type = untag_appr(card.value<TextValue>(_("super_type")).value); type = untag_appr(card.value<TextValue>(_("super_type")).value);
String subType = untag(card.value<TextValue>(_("sub_type")).value); String subType = untag_appr(card.value<TextValue>(_("sub_type")).value);
if (!subType.empty()) type += _(" - ") + subType; if (!subType.empty()) type += _(" - ") + subType;
text = untag_appr(card.value<TextValue>(_("rule_text")).value); text = untag_appr(card.value<TextValue>(_("rule_text")).value);
flavor = untag_appr(card.value<TextValue>(_("flavor_text")).value); flavor = untag_appr(card.value<TextValue>(_("flavor_text")).value);
...@@ -725,7 +728,7 @@ bool ApprenticeExportWindow::exportSet() { ...@@ -725,7 +728,7 @@ bool ApprenticeExportWindow::exportSet() {
if (res == wxNO) return false; // abort export if (res == wxNO) return false; // abort export
} }
// add our set // add our set
expan.expansions[set->apprentice_code] = set->value<TextValue>(_("title")).value; expan.expansions[set->apprentice_code] = set->value<TextValue>(_("title")).value->toString();
expan.write(); expan.write();
// Format database // Format database
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <data/field/image.hpp> #include <data/field/image.hpp>
#include <wx/wfstream.h> #include <wx/wfstream.h>
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : MSE1FileFormat // ----------------------------------------------------------------------------- : MSE1FileFormat
/// The file format of MSE1 files /// The file format of MSE1 files
...@@ -54,9 +56,9 @@ SetP MSE1FileFormat::importSet(const String& filename) { ...@@ -54,9 +56,9 @@ SetP MSE1FileFormat::importSet(const String& filename) {
throw ParseError(_("Expected MSE format version 8\nTo convert files made with older versions of Magic Set Editor:\n 1. Download the latest version 1 from http:;//magicsetedtitor.sourceforge.net\n 2. Open the set, then save the set\n 3. Try to open them again in this program.")); throw ParseError(_("Expected MSE format version 8\nTo convert files made with older versions of Magic Set Editor:\n 1. Download the latest version 1 from http:;//magicsetedtitor.sourceforge.net\n 2. Open the set, then save the set\n 3. Try to open them again in this program."));
} }
// read general info // read general info
set->value<TextValue>(_("title")) .value = file.ReadLine(); set->value<TextValue>(_("title")) .value = to_script(file.ReadLine());
set->value<TextValue>(_("artist")) .value = file.ReadLine(); set->value<TextValue>(_("artist")) .value = to_script(file.ReadLine());
set->value<TextValue>(_("copyright")).value = file.ReadLine(); set->value<TextValue>(_("copyright")).value = to_script(file.ReadLine());
file.ReadLine(); // border color, ignored file.ReadLine(); // border color, ignored
String stylesheet = file.ReadLine(); String stylesheet = file.ReadLine();
set->apprentice_code = file.ReadLine(); // apprentice prefix set->apprentice_code = file.ReadLine(); // apprentice prefix
...@@ -70,7 +72,7 @@ SetP MSE1FileFormat::importSet(const String& filename) { ...@@ -70,7 +72,7 @@ SetP MSE1FileFormat::importSet(const String& filename) {
if (line == _("\xFF")) break; if (line == _("\xFF")) break;
desc += line; desc += line;
} }
set->value<TextValue>(_("description")).value = desc; set->value<TextValue>(_("description")).value = to_script(desc);
// load stylesheet // load stylesheet
if (stylesheet.substr(0,3) == _("old")) { if (stylesheet.substr(0,3) == _("old")) {
...@@ -95,6 +97,13 @@ SetP MSE1FileFormat::importSet(const String& filename) { ...@@ -95,6 +97,13 @@ SetP MSE1FileFormat::importSet(const String& filename) {
return set; return set;
} }
// append a line to a ScriptString, this is a bit inefficient, since we keep copying the string
void append_line(ScriptValueP& target, String const& line) {
String old_value = target->toString();
if (!is_default(target)) old_value += _("\n");
target = to_script(old_value + line);
}
void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) { void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
CardP card(new Card(*set.game)); CardP card(new Card(*set.game));
while (!f.Eof()) { while (!f.Eof()) {
...@@ -109,46 +118,42 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) { ...@@ -109,46 +118,42 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
set.cards.push_back(card); set.cards.push_back(card);
return; return;
} case 'B': { // name } case 'B': { // name
card->value<TextValue>(_("name")) .value.assign(line); card->value<TextValue>(_("name")) .value = to_script(line);
break; break;
} case 'C': case 'D': { // image filename } case 'C': case 'D': { // image filename
String image_file = set.newFileName(_("image"),_("")); // a new unique name in the package LocalFileName image_file = set.newFileName(_("image"),_("")); // a new unique name in the package
if (wxCopyFile(line, set.nameOut(image_file), true)) { if (wxCopyFile(line, set.nameOut(image_file), true)) {
card->value<ImageValue>(_("image")) .filename = image_file; card->value<ImageValue>(_("image")) = script_local_image_file(image_file);
} }
break; break;
} case 'E': { // super type } case 'E': { // super type
card->value<TextValue>(_("super type")) .value.assign(line); card->value<TextValue>(_("super type")) .value = to_script(line);
break; break;
} case 'F': { // sub type } case 'F': { // sub type
card->value<TextValue>(_("sub type")) .value.assign(line); card->value<TextValue>(_("sub type")) .value = to_script(line);
break; break;
} case 'G': { // casting cost } case 'G': { // casting cost
card->value<TextValue>(_("casting cost")).value.assign(line); card->value<TextValue>(_("casting cost")).value = to_script(line);
break; break;
} case 'H': { // rarity } case 'H': { // rarity
String rarity; String rarity;
if (line == _("(U)")) rarity = _("uncommon"); if (line == _("(U)")) rarity = _("uncommon");
else if (line == _("(R)")) rarity = _("rare"); else if (line == _("(R)")) rarity = _("rare");
else rarity = _("common"); else rarity = _("common");
card->value<ChoiceValue>(_("rarity")) .value.assign(rarity); card->value<ChoiceValue>(_("rarity")) .value = to_script(rarity);
break; break;
} case 'I': { // power/thoughness } case 'I': { // power/thoughness
size_t pos = line.find_first_of(_('/')); size_t pos = line.find_first_of(_('/'));
if (pos != String::npos) { if (pos != String::npos) {
card->value<TextValue>(_("power")) .value.assign(line.substr(0, pos)); card->value<TextValue>(_("power")) .value = to_script(line.substr(0, pos));
card->value<TextValue>(_("toughness")) .value.assign(line.substr(pos+1)); card->value<TextValue>(_("toughness")) .value = to_script(line.substr(pos+1));
} }
break; break;
} case 'J': { // rule text or part of text } case 'J': { // rule text or part of text
Defaultable<String>& text = card->value<TextValue>(_("rule text")).value; append_line(card->value<TextValue>(_("rule text")).value, line);
if (!text().empty()) text.mutate() += _('\n');
text.mutate() += line;
break; break;
} case 'K': { // flavor text or part of text } case 'K': { // flavor text or part of text
Defaultable<String>& text = card->value<TextValue>(_("flavor text")).value; append_line(card->value<TextValue>(_("flavor text")).value, line);
if (!text().empty()) text.mutate() += _('\n');
text.mutate() += line;
break; break;
} case 'L': { // card color (if not default) } case 'L': { // card color (if not default)
// decode color // decode color
...@@ -162,7 +167,7 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) { ...@@ -162,7 +167,7 @@ void read_mse1_card(Set& set, wxFileInputStream& f, wxTextInputStream& file) {
else if (line == _("7")) color = _("land"); else if (line == _("7")) color = _("land");
else if (line == _("9")) color = _("multicolor"); else if (line == _("9")) color = _("multicolor");
else color = _("colorless"); else color = _("colorless");
card->value<ChoiceValue>(_("card color")).value.assign(color); card->value<ChoiceValue>(_("card color")).value = to_script(color);
break; break;
} default: { } default: {
throw ParseError(_("Not a valid MSE1 file")); throw ParseError(_("Not a valid MSE1 file"));
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <wx/wfstream.h> #include <wx/wfstream.h>
DECLARE_TYPEOF_COLLECTION(CardP); DECLARE_TYPEOF_COLLECTION(CardP);
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : MtgEditorFileFormat // ----------------------------------------------------------------------------- : MtgEditorFileFormat
...@@ -31,7 +32,7 @@ class MtgEditorFileFormat : public FileFormat { ...@@ -31,7 +32,7 @@ class MtgEditorFileFormat : public FileFormat {
virtual bool canExport(const Game&) { return false; } virtual bool canExport(const Game&) { return false; }
virtual SetP importSet(const String& filename); virtual SetP importSet(const String& filename);
private: private:
// Filter: se filename -> image directory // Filter: set filename -> image directory
// based on MtgEditor's: CardSet.getImageFolder // based on MtgEditor's: CardSet.getImageFolder
String filter1(const String& str); String filter1(const String& str);
// Filter: card name -> image name // Filter: card name -> image name
...@@ -41,6 +42,7 @@ class MtgEditorFileFormat : public FileFormat { ...@@ -41,6 +42,7 @@ class MtgEditorFileFormat : public FileFormat {
void untag(const CardP& card, const String& field); void untag(const CardP& card, const String& field);
// Translate all tags, mana tags get converted to <sym>, other tags are removed // Translate all tags, mana tags get converted to <sym>, other tags are removed
void translateTags(String& value); void translateTags(String& value);
void translateTags(ScriptValueP& value);
}; };
FileFormatP mtg_editor_file_format() { FileFormatP mtg_editor_file_format() {
...@@ -49,6 +51,8 @@ FileFormatP mtg_editor_file_format() { ...@@ -49,6 +51,8 @@ FileFormatP mtg_editor_file_format() {
// ----------------------------------------------------------------------------- : Importing // ----------------------------------------------------------------------------- : Importing
void append_line(ScriptValueP& target, String const& line);
SetP MtgEditorFileFormat::importSet(const String& filename) { SetP MtgEditorFileFormat::importSet(const String& filename) {
wxFileInputStream f(filename); wxFileInputStream f(filename);
#ifdef UNICODE #ifdef UNICODE
...@@ -61,7 +65,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) { ...@@ -61,7 +65,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
// parsing state // parsing state
CardP current_card; CardP current_card;
Defaultable<String>* target = nullptr; // value we are currently reading ScriptValueP* target = nullptr; // value we are currently reading
String layout = _("8e"); String layout = _("8e");
String set_date, card_date; String set_date, card_date;
bool first = true; bool first = true;
...@@ -99,7 +103,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) { ...@@ -99,7 +103,7 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
untag(current_card, _("power")); untag(current_card, _("power"));
untag(current_card, _("toughness")); untag(current_card, _("toughness"));
// translate mtg editor tags to mse2 tags // translate mtg editor tags to mse2 tags
translateTags(current_card->value<TextValue>(_("rule text")).value.mutate()); translateTags(current_card->value<TextValue>(_("rule text")).value);
// add the card to the set // add the card to the set
set->cards.push_back(current_card); set->cards.push_back(current_card);
} }
...@@ -119,18 +123,18 @@ SetP MtgEditorFileFormat::importSet(const String& filename) { ...@@ -119,18 +123,18 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
} else if (line == _("#RARITY########") || line == _("#FREQUENCY#####")) { // rarity } else if (line == _("#RARITY########") || line == _("#FREQUENCY#####")) { // rarity
target = 0; target = 0;
line = file.ReadLine(); line = file.ReadLine();
if (line == _("0")) current_card->value<ChoiceValue>(_("rarity")).value.assign(_("common")); if (line == _("0")) current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("common"));
else if (line == _("1")) current_card->value<ChoiceValue>(_("rarity")).value.assign(_("uncommon")); else if (line == _("1")) current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("uncommon"));
else current_card->value<ChoiceValue>(_("rarity")).value.assign(_("rare")); else current_card->value<ChoiceValue>(_("rarity")).value = to_script(_("rare"));
} else if (line == _("#COLOR#########")) { // card color } else if (line == _("#COLOR#########")) { // card color
target = 0; target = 0;
line = file.ReadLine(); line = file.ReadLine();
current_card->value<ChoiceValue>(_("card color")).value.assign(line); current_card->value<ChoiceValue>(_("card color")).value = to_script(line);
} else if (line == _("#AUTOBG########")) { // card color.isDefault } else if (line == _("#AUTOBG########")) { // card color.isDefault
target = 0; target = 0;
line = file.ReadLine(); line = file.ReadLine();
if (line == _("TRUE")) { if (line == _("TRUE")) {
current_card->value<ChoiceValue>(_("card color")).value.makeDefault(); current_card->value<ChoiceValue>(_("card color")).value = script_default_nil;
} }
} else if (line == _("#RULETEXT######")) { // rule text } else if (line == _("#RULETEXT######")) { // rule text
target = &current_card->value<TextValue>(_("rule text")).value; target = &current_card->value<TextValue>(_("rule text")).value;
...@@ -150,26 +154,25 @@ SetP MtgEditorFileFormat::importSet(const String& filename) { ...@@ -150,26 +154,25 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
if (!wxFileExists(line)) { if (!wxFileExists(line)) {
// based on card name and date // based on card name and date
line = filter1(filename) + set_date + _("/") + line = filter1(filename) + set_date + _("/") +
filter2(current_card->value<TextValue>(_("name")).value) + card_date + _(".jpg"); filter2(current_card->value<TextValue>(_("name")).value->toString()) + card_date + _(".jpg");
} }
// copy image into set // copy image into set
if (wxFileExists(line)) { if (wxFileExists(line)) {
String image_file = set->newFileName(_("image"),_("")); FileName image_file = set->newFileName(_("image"),_(""));
if (wxCopyFile(line, set->nameOut(image_file), true)) { if (wxCopyFile(line, set->nameOut(image_file), true)) {
current_card->value<ImageValue>(_("image")).filename = image_file; current_card->value<ImageValue>(_("image")).value = script_local_image_file(image_file);
} }
} }
} else if (line == _("#TOMBSTONE#####")) { // tombstone } else if (line == _("#TOMBSTONE#####")) { // tombstone
target = 0; target = 0;
line = file.ReadLine(); line = file.ReadLine();
current_card->value<ChoiceValue>(_("card symbol")).value.assign( current_card->value<ChoiceValue>(_("card symbol")).value = to_script(
line==_("TRUE") ? _("tombstone") : _("none") line==_("TRUE") ? _("tombstone") : _("none")
); );
} else { } else {
// normal text // normal text
if (target != 0) { // value of a text field if (target != 0) { // value of a text field
if (!target->isDefault()) target->mutate() += _("\n"); append_line(*target, line);
target->mutate() += line;
} else { } else {
throw ParseError(_("Error in Mtg Editor file, unexpected text:\n") + line); throw ParseError(_("Error in Mtg Editor file, unexpected text:\n") + line);
} }
...@@ -178,16 +181,16 @@ SetP MtgEditorFileFormat::importSet(const String& filename) { ...@@ -178,16 +181,16 @@ SetP MtgEditorFileFormat::importSet(const String& filename) {
// set defaults for artist and copyright to that of the first card // set defaults for artist and copyright to that of the first card
if (!set->cards.empty()) { if (!set->cards.empty()) {
String artist = set->cards[0]->value<TextValue>(_("illustrator")).value; ScriptValueP& artist = set->cards[0]->value<TextValue>(_("illustrator")).value;
String copyright = set->cards[0]->value<TextValue>(_("copyright")) .value; ScriptValueP& copyright = set->cards[0]->value<TextValue>(_("copyright")) .value;
set->value<TextValue>(_("artist")) .value.assign(artist); set->value<TextValue>(_("artist")) .value = artist;
set->value<TextValue>(_("copyright")).value.assign(copyright); set->value<TextValue>(_("copyright")).value = copyright;
// which cards have this value? // which cards have this value?
FOR_EACH(card, set->cards) { FOR_EACH(card, set->cards) {
Defaultable<String>& card_artist = card->value<TextValue>(_("illustrator")).value; ScriptValueP& card_artist = card->value<TextValue>(_("illustrator")).value;
Defaultable<String>& card_copyright = card->value<TextValue>(_("copyright")) .value; ScriptValueP& card_copyright = card->value<TextValue>(_("copyright")) .value;
if (card_artist == artist) card_artist.makeDefault(); if (equal(card_artist , artist)) card_artist = make_default(artist);
if (card_copyright == copyright) card_copyright.makeDefault(); if (equal(card_copyright, copyright)) card_copyright = make_default(card_copyright);
} }
} }
...@@ -237,8 +240,8 @@ String MtgEditorFileFormat::filter2(const String& str) { ...@@ -237,8 +240,8 @@ String MtgEditorFileFormat::filter2(const String& str) {
} }
void MtgEditorFileFormat::untag(const CardP& card, const String& field) { void MtgEditorFileFormat::untag(const CardP& card, const String& field) {
Defaultable<String>& value = card->value<TextValue>(field).value; ScriptValueP& value = card->value<TextValue>(field).value;
value.assignDontChangeDefault(untag_no_escape(value)); value = with_defaultness_of(value, to_script(untag_no_escape(value->toString())));
} }
...@@ -275,3 +278,8 @@ void MtgEditorFileFormat::translateTags(String& value) { ...@@ -275,3 +278,8 @@ void MtgEditorFileFormat::translateTags(String& value) {
// Join adjecent symbol sections // Join adjecent symbol sections
value = replace_all(ret, _("</sym><sym>"), _("")); value = replace_all(ret, _("</sym><sym>"), _(""));
} }
void MtgEditorFileFormat::translateTags(ScriptValueP& value) {
String val = value->toString();
translateTags(val);
value = to_script(val);
}
...@@ -26,6 +26,9 @@ String untag_mws(const String& str) { ...@@ -26,6 +26,9 @@ String untag_mws(const String& str) {
// TODO : em dashes? // TODO : em dashes?
return replace_all(untag(curly_quotes(str,false)), _("\n"), _("\n\t\t") ); return replace_all(untag(curly_quotes(str,false)), _("\n"), _("\n\t\t") );
} }
inline String untag_mws(const ScriptValueP& str) {
return untag_mws(str->toString());
}
//String untag_mws(const Defaultable<String>& str) { //String untag_mws(const Defaultable<String>& str) {
// str. // str.
//} //}
...@@ -72,7 +75,7 @@ void export_mws(Window* parent, const SetP& set) { ...@@ -72,7 +75,7 @@ void export_mws(Window* parent, const SetP& set) {
wxTextOutputStream file(f, wxEOL_DOS); wxTextOutputStream file(f, wxEOL_DOS);
// Write header // Write header
file.WriteString(set->value<TextValue>(_("title")).value + _(" Spoiler List\n")); file.WriteString(set->value<TextValue>(_("title")).value->toString() + _(" Spoiler List\n"));
file.WriteString(_("Set exported using Magic Set Editor 2, version ") + app_version.toString() + _("\n\n")); file.WriteString(_("Set exported using Magic Set Editor 2, version ") + app_version.toString() + _("\n\n"));
wxDateTime now = wxDateTime::Now(); wxDateTime now = wxDateTime::Now();
file.WriteString(_("Spoiler List created on ") + now.FormatISODate() + _(" ") + now.FormatISOTime()); file.WriteString(_("Spoiler List created on ") + now.FormatISODate() + _(" ") + now.FormatISOTime());
...@@ -83,7 +86,7 @@ void export_mws(Window* parent, const SetP& set) { ...@@ -83,7 +86,7 @@ void export_mws(Window* parent, const SetP& set) {
file.WriteString(_("Card Name:\t")); file.WriteString(_("Card Name:\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("name")).value)); file.WriteString(untag_mws(card->value<TextValue>(_("name")).value));
file.WriteString(_("\nCard Color:\t")); file.WriteString(_("\nCard Color:\t"));
file.WriteString(card_color_mws(card->value<ChoiceValue>(_("card color")).value)); file.WriteString(card_color_mws(card->value<ChoiceValue>(_("card color")).value->toString()));
file.WriteString(_("\nMana Cost:\t")); file.WriteString(_("\nMana Cost:\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("casting cost")).value)); file.WriteString(untag_mws(card->value<TextValue>(_("casting cost")).value));
file.WriteString(_("\nType & Class:\t")); file.WriteString(_("\nType & Class:\t"));
...@@ -103,7 +106,7 @@ void export_mws(Window* parent, const SetP& set) { ...@@ -103,7 +106,7 @@ void export_mws(Window* parent, const SetP& set) {
file.WriteString(_("\nArtist:\t\t")); file.WriteString(_("\nArtist:\t\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("illustrator")).value)); file.WriteString(untag_mws(card->value<TextValue>(_("illustrator")).value));
file.WriteString(_("\nRarity:\t\t")); file.WriteString(_("\nRarity:\t\t"));
file.WriteString(card_rarity_code(card->value<ChoiceValue>(_("rarity")).value)); file.WriteString(card_rarity_code(card->value<ChoiceValue>(_("rarity")).value->toString()));
file.WriteString(_("\nCard #:\t\t")); file.WriteString(_("\nCard #:\t\t"));
file.WriteString(untag_mws(card->value<TextValue>(_("card number")).value)); file.WriteString(untag_mws(card->value<TextValue>(_("card number")).value));
file.WriteString(_("\n\n")); file.WriteString(_("\n\n"));
......
...@@ -111,13 +111,13 @@ String Set::identification() const { ...@@ -111,13 +111,13 @@ String Set::identification() const {
// an identifying field // an identifying field
FOR_EACH_CONST(v, data) { FOR_EACH_CONST(v, data) {
if (v->fieldP->identifying) { if (v->fieldP->identifying) {
return v->toString(); return v->toFriendlyString();
} }
} }
// otherwise the first non-information field // otherwise the first non-information field
FOR_EACH_CONST(v, data) { FOR_EACH_CONST(v, data) {
if (!dynamic_pointer_cast<InfoValue>(v)) { if (!dynamic_pointer_cast<InfoValue>(v)) {
return v->toString(); return v->toFriendlyString();
} }
} }
return wxEmptyString; return wxEmptyString;
...@@ -127,16 +127,6 @@ String Set::identification() const { ...@@ -127,16 +127,6 @@ String Set::identification() const {
String Set::typeName() const { return _("set"); } String Set::typeName() const { return _("set"); }
Version Set::fileVersion() const { return file_version_set; } Version Set::fileVersion() const { return file_version_set; }
// fix values for versions < 0.2.7
void fix_value_207(const ValueP& value) {
if (TextValue* v = dynamic_cast<TextValue*>(value.get())) {
// text value -> fix it
v->value.assignDontChangeDefault( // don't change defaultness
fix_old_tags(v->value()) // remove tags
);
}
}
void Set::validate(Version file_app_version) { void Set::validate(Version file_app_version) {
Packaged::validate(file_app_version); Packaged::validate(file_app_version);
// are the // are the
...@@ -150,19 +140,7 @@ void Set::validate(Version file_app_version) { ...@@ -150,19 +140,7 @@ void Set::validate(Version file_app_version) {
if (stylesheet->game != game) { if (stylesheet->game != game) {
throw Error(_ERROR_("stylesheet and set refer to different game")); throw Error(_ERROR_("stylesheet and set refer to different game"));
} }
// This is our chance to fix version incompatabilities
if (file_app_version < 207) {
// Since 0.2.7 we use </tag> style close tags, in older versions it was </>
// Walk over all fields and fix...
FOR_EACH(c, cards) {
FOR_EACH(v, c->data) fix_value_207(v);
}
FOR_EACH(v, data) fix_value_207(v);
/* FOR_EACH(s, styleData) {
FOR_EACH(v, s.second->data) fix_value_207(v);
}
*/ }
// we want at least one card // we want at least one card
if (cards.empty()) cards.push_back(intrusive(new Card(*game))); if (cards.empty()) cards.push_back(intrusive(new Card(*game)));
// update scripts // update scripts
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
ScriptType GeneratedImage::type() const { return SCRIPT_IMAGE; } ScriptType GeneratedImage::type() const { return SCRIPT_IMAGE; }
String GeneratedImage::typeName() const { return _TYPE_("image"); } String GeneratedImage::typeName() const { return _TYPE_("image"); }
String GeneratedImage::toFriendlyString() const { return _("<") + _TYPE_("image") + _(">"); }
GeneratedImageP GeneratedImage::toImage() const { GeneratedImageP GeneratedImage::toImage() const {
return intrusive_from_existing(const_cast<GeneratedImage*>(this)); return intrusive_from_existing(const_cast<GeneratedImage*>(this));
} }
...@@ -448,9 +449,12 @@ bool BuiltInImage::operator == (const GeneratedImage& that) const { ...@@ -448,9 +449,12 @@ bool BuiltInImage::operator == (const GeneratedImage& that) const {
// ----------------------------------------------------------------------------- : SymbolToImage // ----------------------------------------------------------------------------- : SymbolToImage
SymbolToImage::SymbolToImage(bool is_local, const String& filename, Age age, const SymbolVariationP& variation) SymbolToImage::SymbolToImage(bool is_local, const LocalFileName& filename, const SymbolVariationP& variation)
: is_local(is_local), filename(filename), age(age), variation(variation) : is_local(is_local), filename(filename), variation(variation)
{} {
assert(variation);
assert(variation->filter);
}
SymbolToImage::~SymbolToImage() {} SymbolToImage::~SymbolToImage() {}
Image SymbolToImage::generate(const Options& opt) const { Image SymbolToImage::generate(const Options& opt) const {
...@@ -464,27 +468,32 @@ Image SymbolToImage::generate(const Options& opt) const { ...@@ -464,27 +468,32 @@ Image SymbolToImage::generate(const Options& opt) const {
the_symbol = package->readFile<SymbolP>(filename); the_symbol = package->readFile<SymbolP>(filename);
} }
int size = max(100, 3*max(opt.width,opt.height)); int size = max(100, 3*max(opt.width,opt.height));
int width = size * opt.width / max(opt.width,opt.height);
int height = size * opt.height / max(opt.width,opt.height);
bool allow_smaller = true;
if (opt.width <= 1 || opt.height <= 1) { if (opt.width <= 1 || opt.height <= 1) {
return render_symbol(the_symbol, *variation->filter, variation->border_radius, size, size); allow_smaller = false;
} else { width = height = size;
int width = size * opt.width / max(opt.width,opt.height);
int height = size * opt.height / max(opt.width,opt.height);
return render_symbol(the_symbol, *variation->filter, variation->border_radius, width, height, false, true);
} }
return render_symbol(the_symbol, *variation->filter, variation->border_radius, width, height, false, allow_smaller);
} }
bool SymbolToImage::operator == (const GeneratedImage& that) const { bool SymbolToImage::operator == (const GeneratedImage& that) const {
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that); const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
return that2 && is_local == that2->is_local return that2 && is_local == that2->is_local
&& filename == that2->filename && filename == that2->filename
&& age == that2->age
&& (variation == that2->variation || && (variation == that2->variation ||
*variation == *that2->variation // custom variation *variation == *that2->variation // custom variation
); );
} }
// ----------------------------------------------------------------------------- : ImageValueToImage // ----------------------------------------------------------------------------- : ImageValueToImage
ImageValueToImage::ImageValueToImage(const String& filename) ScriptValueP script_local_image_file(LocalFileName const& filename) {
return intrusive(new ImageValueToImage(filename));
}
ImageValueToImage::ImageValueToImage(const LocalFileName& filename)
: filename(filename) : filename(filename)
{} {}
ImageValueToImage::~ImageValueToImage() {} ImageValueToImage::~ImageValueToImage() {}
...@@ -506,3 +515,8 @@ bool ImageValueToImage::operator == (const GeneratedImage& that) const { ...@@ -506,3 +515,8 @@ bool ImageValueToImage::operator == (const GeneratedImage& that) const {
const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that); const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that);
return that2 && filename == that2->filename; return that2 && filename == that2->filename;
} }
String quote_string(String const& str);
String ImageValueToImage::toCode() const {
return _("local_image_file(") + quote_string(filename.toStringForWriting()) + _(")");
}
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/age.hpp> #include <util/age.hpp>
#include <util/io/package.hpp>
#include <gfx/gfx.hpp> #include <gfx/gfx.hpp>
#include <script/value.hpp> #include <script/value.hpp>
...@@ -63,6 +64,7 @@ class GeneratedImage : public ScriptValue { ...@@ -63,6 +64,7 @@ class GeneratedImage : public ScriptValue {
virtual ScriptType type() const; virtual ScriptType type() const;
virtual String typeName() const; virtual String typeName() const;
virtual GeneratedImageP toImage() const; virtual GeneratedImageP toImage() const;
virtual String toFriendlyString() const;
}; };
/// Resize an image to conform to the options /// Resize an image to conform to the options
...@@ -353,7 +355,8 @@ class BuiltInImage : public GeneratedImage { ...@@ -353,7 +355,8 @@ class BuiltInImage : public GeneratedImage {
/// Use a symbol as an image /// Use a symbol as an image
class SymbolToImage : public GeneratedImage { class SymbolToImage : public GeneratedImage {
public: public:
SymbolToImage(bool is_local, const String& filename, Age age, const SymbolVariationP& variation); SymbolToImage(const SymbolToImage& symbol, const SymbolVariationP& variation);
SymbolToImage(bool is_local, const LocalFileName& filename, const SymbolVariationP& variation = SymbolVariationP());
~SymbolToImage(); ~SymbolToImage();
virtual Image generate(const Options& opt) const; virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const; virtual bool operator == (const GeneratedImage& that) const;
...@@ -365,24 +368,28 @@ class SymbolToImage : public GeneratedImage { ...@@ -365,24 +368,28 @@ class SymbolToImage : public GeneratedImage {
private: private:
SymbolToImage(const SymbolToImage&); // copy ctor SymbolToImage(const SymbolToImage&); // copy ctor
bool is_local; ///< Use local package? bool is_local; ///< Use local package?
String filename; LocalFileName filename;
Age age; ///< Age the symbol was last updated
SymbolVariationP variation; SymbolVariationP variation;
}; };
// ----------------------------------------------------------------------------- : ImageValueToImage // ----------------------------------------------------------------------------- : ImageValueToImage
/// Use an image from an ImageValue as an image /// Use an image from an ImageValue as an image
// Also used as representation for script_local_image_file
// TODO: rename this
class ImageValueToImage : public GeneratedImage { class ImageValueToImage : public GeneratedImage {
public: public:
ImageValueToImage(const String& filename); ImageValueToImage(const LocalFileName& filename);
~ImageValueToImage(); ~ImageValueToImage();
virtual Image generate(const Options& opt) const; virtual Image generate(const Options& opt) const;
virtual bool operator == (const GeneratedImage& that) const; virtual bool operator == (const GeneratedImage& that) const;
virtual bool local() const { return true; } virtual bool local() const { return true; }
virtual String toCode() const;
private: private:
ImageValueToImage(const ImageValueToImage&); // copy ctor ImageValueToImage(const ImageValueToImage&); // copy ctor
String filename; LocalFileName filename;
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
...@@ -312,7 +312,7 @@ String CardListBase::OnGetItemText(long pos, long col) const { ...@@ -312,7 +312,7 @@ String CardListBase::OnGetItemText(long pos, long col) const {
return wxEmptyString; return wxEmptyString;
} }
ValueP val = getCard(pos)->data[column_fields[col]]; ValueP val = getCard(pos)->data[column_fields[col]];
if (val) return val->toString(); if (val) return val->toFriendlyString();
else return wxEmptyString; else return wxEmptyString;
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <data/field/image.hpp> #include <data/field/image.hpp>
#include <data/game.hpp> #include <data/game.hpp>
#include <data/card.hpp> #include <data/card.hpp>
#include <script/image.hpp>
#include <gfx/generated_image.hpp>
#include <gfx/gfx.hpp> #include <gfx/gfx.hpp>
#include <wx/imaglist.h> #include <wx/imaglist.h>
...@@ -51,24 +53,23 @@ ImageFieldP ImageCardList::findImageField() { ...@@ -51,24 +53,23 @@ ImageFieldP ImageCardList::findImageField() {
/// A request for a thumbnail of a card image /// A request for a thumbnail of a card image
class CardThumbnailRequest : public ThumbnailRequest { class CardThumbnailRequest : public ThumbnailRequest {
public: public:
CardThumbnailRequest(ImageCardList* parent, const String& filename) CardThumbnailRequest(ImageCardList* parent, const String& key, const GeneratedImageP& imgen)
: ThumbnailRequest( : ThumbnailRequest(
parent, parent,
_("card") + parent->set->absoluteFilename() + _("-") + filename, _("card") + parent->set->absoluteFilename() + _("-") + key,
wxDateTime::Now()) // TODO: Find mofication time of card image wxDateTime::Now()) // TODO: Find mofication time of card image
, filename(filename) , key(key)
, imgen(imgen)
{} {}
virtual Image generate() { virtual Image generate() {
try { try {
ImageCardList* parent = (ImageCardList*)owner; ImageCardList* parent = (ImageCardList*)owner;
Image image; GeneratedImage::Options opts;
if (image.LoadFile(*parent->set->openIn(filename))) { opts.local_package = parent->set.get();
// two step anti aliased resampling Image image = imgen->generate(opts);
image.Rescale(36, 28); // step 1: no anti aliassing // two step anti aliased resampling
return resample(image, 18, 14); // step 2: with anti aliassing image.Rescale(36, 28); // step 1: no anti aliassing
} else { return resample(image, 18, 14); // step 2: with anti aliassing
return Image();
}
} catch (...) { } catch (...) {
return Image(); return Image();
} }
...@@ -79,28 +80,36 @@ class CardThumbnailRequest : public ThumbnailRequest { ...@@ -79,28 +80,36 @@ class CardThumbnailRequest : public ThumbnailRequest {
if (img.Ok()) { if (img.Ok()) {
wxImageList* il = parent->GetImageList(wxIMAGE_LIST_SMALL); wxImageList* il = parent->GetImageList(wxIMAGE_LIST_SMALL);
int id = il->Add(wxBitmap(img)); int id = il->Add(wxBitmap(img));
parent->thumbnails.insert(make_pair(filename, id)); parent->thumbnails.insert(make_pair(key, id));
parent->Refresh(false); parent->Refresh(false);
} }
} }
virtual bool threadSafe() const {return true;} virtual bool threadSafe() const {return true;}
private: private:
String filename; String key;
GeneratedImageP imgen;
}; };
int ImageCardList::OnGetItemImage(long pos) const { int ImageCardList::OnGetItemImage(long pos) const {
if (image_field) { if (image_field) {
// Image = thumbnail of first image field of card // Image = thumbnail of first image field of card
ImageValue& val = static_cast<ImageValue&>(*getCard(pos)->data[image_field]); const ImageValue& val = static_cast<const ImageValue&>(*getCard(pos)->data[image_field]);
if (!val.filename) return -1; // no image if (val.value->isNil()) return -1;
GeneratedImageP image = val.value->toImage();
// is there already a thumbnail? // is there already a thumbnail?
map<String,int>::const_iterator it = thumbnails.find(val.filename); String key;
try {
key = image->toCode();
} catch (...) {
return -1; // nothing that can be used as a key
}
map<String,int>::const_iterator it = thumbnails.find(key);
if (it != thumbnails.end()) { if (it != thumbnails.end()) {
return it->second; return it->second;
} else { } else {
// request a thumbnail // request a thumbnail
thumbnail_thread.request(intrusive(new CardThumbnailRequest(const_cast<ImageCardList*>(this), val.filename))); thumbnail_thread.request(intrusive(new CardThumbnailRequest(const_cast<ImageCardList*>(this), key, image)));
} }
} }
return -1; return -1;
......
...@@ -48,11 +48,12 @@ SymbolWindow::SymbolWindow(Window* parent, ValueActionPerformer* performer) ...@@ -48,11 +48,12 @@ SymbolWindow::SymbolWindow(Window* parent, ValueActionPerformer* performer)
// attempt to load symbol // attempt to load symbol
SymbolP symbol; SymbolP symbol;
SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value); SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value);
if (!value->filename.empty()) { LocalSymbolFileP symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value->value);
if (symbol_file) {
try { try {
// load symbol // load symbol
Package& package = performer->getLocalPackage(); Package& package = performer->getLocalPackage();
symbol = package.readFile<SymbolP>(value->filename); symbol = package.readFile<SymbolP>(symbol_file->filename);
} catch (const Error& e) { } catch (const Error& e) {
handle_error(e); handle_error(e);
} }
...@@ -251,11 +252,11 @@ void SymbolWindow::onFileStore(wxCommandEvent& ev) { ...@@ -251,11 +252,11 @@ void SymbolWindow::onFileStore(wxCommandEvent& ev) {
if (performer) { if (performer) {
SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value); SymbolValueP value = static_pointer_cast<SymbolValue>(performer->value);
Package& package = performer->getLocalPackage(); Package& package = performer->getLocalPackage();
FileName new_filename = package.newFileName(value->field().name,_(".mse-symbol")); // a new unique name in the package LocalFileName new_filename = package.newFileName(value->field().name,_(".mse-symbol")); // a new unique name in the package
OutputStreamP stream = package.openOut(new_filename); OutputStreamP stream = package.openOut(new_filename);
Writer writer(*stream, file_version_symbol); Writer writer(*stream, file_version_symbol);
writer.handle(control->getSymbol()); writer.handle(control->getSymbol());
performer->addAction(value_action(value, new_filename)); performer->addAction(value_action(value, intrusive(new LocalSymbolFile(new_filename))));
} }
} }
......
...@@ -236,7 +236,7 @@ void DropDownChoiceList::onShow() { ...@@ -236,7 +236,7 @@ void DropDownChoiceList::onShow() {
void DropDownChoiceList::select(size_t item) { void DropDownChoiceList::select(size_t item) {
if (isFieldDefault(item)) { if (isFieldDefault(item)) {
dynamic_cast<ChoiceValueEditor&>(cve).change( Defaultable<String>() ); dynamic_cast<ChoiceValueEditor&>(cve).change( script_default_nil );
} else { } else {
ChoiceField::ChoiceP choice = getChoice(item); ChoiceField::ChoiceP choice = getChoice(item);
dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) ); dynamic_cast<ChoiceValueEditor&>(cve).change( field().choices->choiceName(choice->first_id) );
...@@ -245,11 +245,11 @@ void DropDownChoiceList::select(size_t item) { ...@@ -245,11 +245,11 @@ void DropDownChoiceList::select(size_t item) {
size_t DropDownChoiceList::selection() const { size_t DropDownChoiceList::selection() const {
// selected item // selected item
const Defaultable<String>& value = dynamic_cast<ChoiceValueEditor&>(cve).value().value(); ScriptValueP value = dynamic_cast<ChoiceValueEditor&>(cve).value().value;
int id = field().choices->choiceId(value); int id = field().choices->choiceId(value->toString());
// id of default item // id of default item
if (hasFieldDefault()) { if (hasFieldDefault()) {
if (value.isDefault()) { if (is_default(value)) {
// default is selected // default is selected
default_id = id; default_id = id;
return 0; return 0;
...@@ -304,6 +304,9 @@ void ChoiceValueEditor::determineSize(bool) { ...@@ -304,6 +304,9 @@ void ChoiceValueEditor::determineSize(bool) {
style().height = max(style().height(), 16.); style().height = max(style().height(), 16.);
} }
void ChoiceValueEditor::change(const Defaultable<String>& c) { void ChoiceValueEditor::change(ScriptValueP const& v) {
addAction(value_action(valueP(), c)); addAction(value_action(valueP(), v));
}
void ChoiceValueEditor::change(const String& c) {
change(to_script(c));
} }
...@@ -37,7 +37,8 @@ class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor { ...@@ -37,7 +37,8 @@ class ChoiceValueEditor : public ChoiceValueViewer, public ValueEditor {
DropDownListP drop_down; DropDownListP drop_down;
friend class DropDownChoiceList; friend class DropDownChoiceList;
/// Change the choice /// Change the choice
void change(const Defaultable<String>& c); void change(const ScriptValueP& c);
void change(const String& c);
}; };
// ----------------------------------------------------------------------------- : DropDownChoiceList // ----------------------------------------------------------------------------- : DropDownChoiceList
......
...@@ -80,7 +80,7 @@ void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selecte ...@@ -80,7 +80,7 @@ void DropDownColorList::drawIcon(DC& dc, int x, int y, size_t item, bool selecte
if (isDefault(item)) { if (isDefault(item)) {
col = default_color; col = default_color;
} else if (isCustom(item)) { } else if (isCustom(item)) {
col = cve.value().value(); col = cve.value().value->toColor();
} else { } else {
col = field().choices[item - hasDefault()]->color; col = field().choices[item - hasDefault()]->color;
} }
...@@ -96,16 +96,16 @@ size_t DropDownColorList::selection() const { ...@@ -96,16 +96,16 @@ size_t DropDownColorList::selection() const {
size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION; size_t selection = hasCustom() ? itemCount() - 1 : NO_SELECTION;
size_t i = 0; size_t i = 0;
FOR_EACH_CONST(c, field().choices) { FOR_EACH_CONST(c, field().choices) {
if (c->color == cve.value().value()) { if (c->color == cve.value().value->toColor()) {
selection = i + hasDefault(); selection = i + hasDefault();
break; break;
} }
i++; i++;
} }
// has default item? // has default item?
if (hasDefault() && cve.value().value.isDefault()) { if (hasDefault() && is_default(cve.value().value)) {
// default is selected // default is selected
default_color = cve.value().value(); default_color = cve.value().value->toColor();
return 0; return 0;
} else if (hasDefault()) { } else if (hasDefault()) {
// evaluate script to find default color // evaluate script to find default color
...@@ -115,7 +115,7 @@ size_t DropDownColorList::selection() const { ...@@ -115,7 +115,7 @@ size_t DropDownColorList::selection() const {
} }
void DropDownColorList::select(size_t item) { void DropDownColorList::select(size_t item) {
if (isDefault(item)) { if (isDefault(item)) {
cve.change( Defaultable<Color>()); cve.change(script_default_nil);
} else if (isCustom(item)) { } else if (isCustom(item)) {
cve.changeCustom(); cve.changeCustom();
} else { } else {
...@@ -149,10 +149,13 @@ void ColorValueEditor::determineSize(bool) { ...@@ -149,10 +149,13 @@ void ColorValueEditor::determineSize(bool) {
style().height = 20; style().height = 20;
} }
void ColorValueEditor::change(const Defaultable<Color>& c) { void ColorValueEditor::change(Color c) {
change(to_script(c));
}
void ColorValueEditor::change(ScriptValueP const& c) {
addAction(value_action(valueP(), c)); addAction(value_action(valueP(), c));
} }
void ColorValueEditor::changeCustom() { void ColorValueEditor::changeCustom() {
Color c = wxGetColourFromUser(0, value().value()); Color c = wxGetColourFromUser(0, value().value->toColor());
if (c.Ok()) change(c); if (c.Ok()) change(c);
} }
...@@ -34,7 +34,8 @@ class ColorValueEditor : public ColorValueViewer, public ValueEditor { ...@@ -34,7 +34,8 @@ class ColorValueEditor : public ColorValueViewer, public ValueEditor {
DropDownListP drop_down; DropDownListP drop_down;
friend class DropDownColorList; friend class DropDownColorList;
/// Change the color /// Change the color
void change(const Defaultable<Color>& c); void change(const ScriptValueP& c);
void change(Color c);
/// Change to a custom color /// Change to a custom color
void changeCustom(); void changeCustom();
}; };
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <data/action/value.hpp> #include <data/action/value.hpp>
#include <wx/clipbrd.h> #include <wx/clipbrd.h>
ScriptValueP script_local_image_file(LocalFileName const& filename);
// ----------------------------------------------------------------------------- : ImageValueEditor // ----------------------------------------------------------------------------- : ImageValueEditor
IMPLEMENT_VALUE_EDITOR(Image) {} IMPLEMENT_VALUE_EDITOR(Image) {}
...@@ -39,17 +41,17 @@ void ImageValueEditor::sliceImage(const Image& image) { ...@@ -39,17 +41,17 @@ void ImageValueEditor::sliceImage(const Image& image) {
// clicked ok? // clicked ok?
if (s.ShowModal() == wxID_OK) { if (s.ShowModal() == wxID_OK) {
// store the image into the set // store the image into the set
FileName new_image_file = getLocalPackage().newFileName(field().name,_("")); // a new unique name in the package LocalFileName new_image_file = getLocalPackage().newFileName(field().name,_("")); // a new unique name in the package
Image img = s.getImage(); Image img = s.getImage();
img.SaveFile(getLocalPackage().nameOut(new_image_file), wxBITMAP_TYPE_PNG); // always use PNG images, see #69. Disk space is cheap anyway. img.SaveFile(getLocalPackage().nameOut(new_image_file), wxBITMAP_TYPE_PNG); // always use PNG images, see #69. Disk space is cheap anyway.
addAction(value_action(valueP(), new_image_file)); addAction(value_action(valueP(), script_local_image_file(new_image_file)));
} }
} }
// ----------------------------------------------------------------------------- : Clipboard // ----------------------------------------------------------------------------- : Clipboard
bool ImageValueEditor::canCopy() const { bool ImageValueEditor::canCopy() const {
return !value().filename.empty(); return !value().value->isNil();
} }
bool ImageValueEditor::canPaste() const { bool ImageValueEditor::canPaste() const {
...@@ -58,10 +60,12 @@ bool ImageValueEditor::canPaste() const { ...@@ -58,10 +60,12 @@ bool ImageValueEditor::canPaste() const {
} }
bool ImageValueEditor::doCopy() { bool ImageValueEditor::doCopy() {
// load image // load/generate image
InputStreamP image_file = getLocalPackage().openIn(value().filename); GeneratedImage::Options opts;
Image image; opts.package = &getStylePackage();
if (!image.LoadFile(*image_file)) return false; opts.local_package = &getLocalPackage();
Image image = value().value->toImage()->generate(opts);
if (!image.Ok()) return false;
// set data // set data
if (!wxTheClipboard->Open()) return false; if (!wxTheClipboard->Open()) return false;
bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image)); bool ok = wxTheClipboard->SetData(new wxBitmapDataObject(image));
...@@ -82,7 +86,7 @@ bool ImageValueEditor::doPaste() { ...@@ -82,7 +86,7 @@ bool ImageValueEditor::doPaste() {
} }
bool ImageValueEditor::doDelete() { bool ImageValueEditor::doDelete() {
addAction(value_action(valueP(), FileName())); addAction(value_action(valueP(), script_nil));
return true; return true;
} }
......
...@@ -56,7 +56,7 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo ...@@ -56,7 +56,7 @@ void DropDownMultipleChoiceList::drawIcon(DC& dc, int x, int y, size_t item, boo
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).active[choice->first_id]; active = dynamic_cast<MultipleChoiceValueEditor&>(cve).active[choice->first_id];
radio = choice->type == CHOICE_TYPE_RADIO; radio = choice->type == CHOICE_TYPE_RADIO;
} else { } else {
active = dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value.isDefault(); active = is_default(dynamic_cast<MultipleChoiceValueEditor&>(cve).value().value);
} }
// draw checkbox // draw checkbox
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
...@@ -177,9 +177,13 @@ void MultipleChoiceValueEditor::toggle(int id) { ...@@ -177,9 +177,13 @@ void MultipleChoiceValueEditor::toggle(int id) {
if (i == id) toggled_choice = choice; if (i == id) toggled_choice = choice;
} }
// store value // store value
addAction(value_action(valueP(), new_value, toggled_choice)); addAction(value_action(valueP(), to_script(new_value), toggled_choice));
} }
void MultipleChoiceValueEditor::toggleDefault() { void MultipleChoiceValueEditor::toggleDefault() {
addAction(value_action(valueP(), Defaultable<String>(value().value(), !value().value.isDefault()), _(""))); if (ScriptDefault const* dv = is_default(value().value)) {
addAction(value_action(valueP(), dv->un_default));
} else {
addAction(value_action(valueP(), make_default(value().value)));
}
} }
...@@ -75,8 +75,9 @@ void DropDownPackageChoiceList::select(size_t item) { ...@@ -75,8 +75,9 @@ void DropDownPackageChoiceList::select(size_t item) {
size_t DropDownPackageChoiceList::selection() const { size_t DropDownPackageChoiceList::selection() const {
size_t n = 0; size_t n = 0;
String package_name = editor.value().value->toString();
FOR_EACH(i, editor.items) { FOR_EACH(i, editor.items) {
if (editor.value().package_name == i.package_name) { if (package_name == i.package_name) {
return n + !editor.field().required; return n + !editor.field().required;
} }
++n; ++n;
...@@ -111,7 +112,7 @@ void PackageChoiceValueEditor::determineSize(bool) { ...@@ -111,7 +112,7 @@ void PackageChoiceValueEditor::determineSize(bool) {
} }
void PackageChoiceValueEditor::change(const String& c) { void PackageChoiceValueEditor::change(const String& c) {
addAction(value_action(valueP(), c)); addAction(value_action(valueP(), to_script(c)));
} }
void PackageChoiceValueEditor::initDropDown() { void PackageChoiceValueEditor::initDropDown() {
......
This diff is collapsed.
...@@ -59,7 +59,9 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader); ...@@ -59,7 +59,9 @@ intrusive_ptr<SymbolFilter> read_new<SymbolFilter>(Reader& reader);
/// Symbol filter that returns solid colors /// Symbol filter that returns solid colors
class SolidFillSymbolFilter : public SymbolFilter { class SolidFillSymbolFilter : public SymbolFilter {
public: public:
inline SolidFillSymbolFilter() {} inline SolidFillSymbolFilter()
: fill_color(AColor(0,0,0,255)), border_color(AColor(255,255,255,255))
{}
inline SolidFillSymbolFilter(const AColor& fill_color, const AColor& border_color) inline SolidFillSymbolFilter(const AColor& fill_color, const AColor& border_color)
: fill_color(fill_color), border_color(border_color) : fill_color(fill_color), border_color(border_color)
{} {}
......
...@@ -17,12 +17,12 @@ IMPLEMENT_VALUE_VIEWER(Choice); ...@@ -17,12 +17,12 @@ IMPLEMENT_VALUE_VIEWER(Choice);
void get_options(Rotation& rot, ValueViewer& viewer, const ChoiceStyle& style, GeneratedImage::Options& opts); void get_options(Rotation& rot, ValueViewer& viewer, const ChoiceStyle& style, GeneratedImage::Options& opts);
bool ChoiceValueViewer::prepare(RotatedDC& dc) { bool ChoiceValueViewer::prepare(RotatedDC& dc) {
return prepare_choice_viewer(dc, *this, style(), value().value()); return prepare_choice_viewer(dc, *this, style(), value().value->toString());
} }
void ChoiceValueViewer::draw(RotatedDC& dc) { void ChoiceValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc); drawFieldBorder(dc);
if (style().render_style & RENDER_HIDDEN) return; if (style().render_style & RENDER_HIDDEN) return;
draw_choice_viewer(dc, *this, style(), value().value()); draw_choice_viewer(dc, *this, style(), value().value->toString());
} }
void ChoiceValueViewer::onStyleChange(int changes) { void ChoiceValueViewer::onStyleChange(int changes) {
......
...@@ -19,16 +19,16 @@ IMPLEMENT_VALUE_VIEWER(Color); ...@@ -19,16 +19,16 @@ IMPLEMENT_VALUE_VIEWER(Color);
void ColorValueViewer::draw(RotatedDC& dc) { void ColorValueViewer::draw(RotatedDC& dc) {
// draw in the value color // draw in the value color
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(value().value()); dc.SetBrush(value().value->toColor());
if (nativeLook()) { if (nativeLook()) {
// native look // native look
// find name of color // find name of color
String color_name = _("Custom"); String color_name = _("Custom");
if (field().default_script && value().value.isDefault()) { if (field().default_script && is_default(value().value)) {
color_name = field().default_name; color_name = field().default_name;
} else { } else {
FOR_EACH_CONST(c, field().choices) { FOR_EACH_CONST(c, field().choices) {
if (value().value() == c->color) { if (value().value->toColor() == c->color) {
color_name = capitalize(c->name); color_name = capitalize(c->name);
break; break;
} }
...@@ -45,7 +45,7 @@ void ColorValueViewer::draw(RotatedDC& dc) { ...@@ -45,7 +45,7 @@ void ColorValueViewer::draw(RotatedDC& dc) {
// is there a mask? // is there a mask?
const AlphaMask& alpha_mask = getMask(dc); const AlphaMask& alpha_mask = getMask(dc);
if (alpha_mask.isLoaded()) { if (alpha_mask.isLoaded()) {
dc.DrawImage(alpha_mask.colorImage(value().value()), RealPoint(0,0), style().combine); dc.DrawImage(alpha_mask.colorImage(value().value->toColor()), RealPoint(0,0), style().combine);
} else { } else {
// do we need clipping? // do we need clipping?
bool clip = style().left_width < style().width && style().right_width < style().width && bool clip = style().left_width < style().width && style().right_width < style().width &&
......
...@@ -28,8 +28,22 @@ void ImageValueViewer::draw(RotatedDC& dc) { ...@@ -28,8 +28,22 @@ void ImageValueViewer::draw(RotatedDC& dc) {
if (!bitmap.Ok()) { if (!bitmap.Ok()) {
angle = a; angle = a;
is_default = false; is_default = false;
// load/generate image
GeneratedImage::Options opts;
opts.package = &getStylePackage();
opts.local_package = &getLocalPackage();
opts.angle = a;
opts.width = (int)dc.trX(style().width);
opts.height = (int)dc.trY(style().height);
opts.preserve_aspect = ASPECT_STRETCH;
// TODO: use CachecScriptableImage
Image image; Image image;
// load from file try {
if (!value().value->isNil()) {
image = value().value->toImage()->generate(opts);
}
} CATCH_ALL_ERRORS(false);
/*
if (!value().filename.empty()) { if (!value().filename.empty()) {
try { try {
InputStreamP image_file = getLocalPackage().openIn(value().filename); InputStreamP image_file = getLocalPackage().openIn(value().filename);
...@@ -37,7 +51,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { ...@@ -37,7 +51,7 @@ void ImageValueViewer::draw(RotatedDC& dc) {
image.Rescale(w, h); image.Rescale(w, h);
} }
} CATCH_ALL_ERRORS(false); } CATCH_ALL_ERRORS(false);
} }*/
// nice placeholder // nice placeholder
if (!image.Ok() && style().default_image.isReady()) { if (!image.Ok() && style().default_image.isReady()) {
image = style().default_image.generate(GeneratedImage::Options(w, h, &getStylePackage(), &getLocalPackage())); image = style().default_image.generate(GeneratedImage::Options(w, h, &getStylePackage(), &getLocalPackage()));
......
...@@ -35,6 +35,7 @@ void InfoValueViewer::draw(RotatedDC& dc) { ...@@ -35,6 +35,7 @@ void InfoValueViewer::draw(RotatedDC& dc) {
-style().padding_left - style().padding_right, -style().padding_left - style().padding_right,
-style().padding_top - style().padding_bottom -style().padding_top - style().padding_bottom
); );
RealSize size = dc.GetTextExtent(value().value); String val = value().value->toString();
dc.DrawText(value().value, align_in_rect(style().alignment, size, rect)); RealSize size = dc.GetTextExtent(val);
dc.DrawText(val, align_in_rect(style().alignment, size, rect));
} }
...@@ -20,7 +20,7 @@ IMPLEMENT_VALUE_VIEWER(MultipleChoice); ...@@ -20,7 +20,7 @@ IMPLEMENT_VALUE_VIEWER(MultipleChoice);
bool MultipleChoiceValueViewer::prepare(RotatedDC& dc) { bool MultipleChoiceValueViewer::prepare(RotatedDC& dc) {
if (style().render_style & (RENDER_CHECKLIST | RENDER_LIST)) return false; if (style().render_style & (RENDER_CHECKLIST | RENDER_LIST)) return false;
return prepare_choice_viewer(dc, *this, style(), value().value()); return prepare_choice_viewer(dc, *this, style(), value().value->toString());
} }
void MultipleChoiceValueViewer::draw(RotatedDC& dc) { void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
...@@ -46,7 +46,7 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) { ...@@ -46,7 +46,7 @@ void MultipleChoiceValueViewer::draw(RotatedDC& dc) {
drawChoice(dc, pos, choice); drawChoice(dc, pos, choice);
} }
} else { } else {
draw_choice_viewer(dc, *this, style(), value().value()); draw_choice_viewer(dc, *this, style(), value().value->toString());
} }
} }
......
...@@ -47,15 +47,16 @@ void PackageChoiceValueViewer::initItems() { ...@@ -47,15 +47,16 @@ void PackageChoiceValueViewer::initItems() {
void PackageChoiceValueViewer::draw(RotatedDC& dc) { void PackageChoiceValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc); drawFieldBorder(dc);
// find item // find item
String text = value().package_name; String text = value().value->toString();
Bitmap image; Bitmap image;
if (value().package_name.empty()) { if (text.empty()) {
text = field().empty_name; text = field().empty_name;
} else { } else {
FOR_EACH(i, items) { FOR_EACH(i, items) {
if (i.package_name == value().package_name) { if (i.package_name == text) {
text = i.name; text = i.name;
image = i.image; image = i.image;
break;
} }
} }
} }
......
...@@ -26,10 +26,11 @@ void SymbolValueViewer::draw(RotatedDC& dc) { ...@@ -26,10 +26,11 @@ void SymbolValueViewer::draw(RotatedDC& dc) {
draw_checker(dc, style().getInternalRect()); draw_checker(dc, style().getInternalRect());
double wh = min(dc.getWidth(), dc.getHeight()); double wh = min(dc.getWidth(), dc.getHeight());
// try to load symbol // try to load symbol
if (symbols.empty() && !value().filename.empty()) { LocalSymbolFileP symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value().value);
if (symbols.empty() && symbol_file) {
try { try {
// load symbol // load symbol
SymbolP symbol = getLocalPackage().readFile<SymbolP>(value().filename); SymbolP symbol = getLocalPackage().readFile<SymbolP>(symbol_file->filename);
// aspect ratio // aspect ratio
double ar = symbol->aspectRatio(); double ar = symbol->aspectRatio();
ar = min(style().max_aspect_ratio, max(style().min_aspect_ratio, ar)); ar = min(style().max_aspect_ratio, max(style().min_aspect_ratio, ar));
......
...@@ -16,13 +16,13 @@ IMPLEMENT_VALUE_VIEWER(Text); ...@@ -16,13 +16,13 @@ IMPLEMENT_VALUE_VIEWER(Text);
bool TextValueViewer::prepare(RotatedDC& dc) { bool TextValueViewer::prepare(RotatedDC& dc) {
getMask(dc); // ensure alpha/contour mask is loaded getMask(dc); // ensure alpha/contour mask is loaded
return v.prepare(dc, value().value(), style(), viewer.getContext()); return v.prepare(dc, value().value->toString(), style(), viewer.getContext());
} }
void TextValueViewer::draw(RotatedDC& dc) { void TextValueViewer::draw(RotatedDC& dc) {
drawFieldBorder(dc); drawFieldBorder(dc);
if (!v.prepared()) { if (!v.prepared()) {
v.prepare(dc, value().value(), style(), viewer.getContext()); v.prepare(dc, value().value->toString(), style(), viewer.getContext());
dc.setStretch(getStretch()); dc.setStretch(getStretch());
} }
DrawWhat what = viewer.drawWhat(this); DrawWhat what = viewer.drawWhat(this);
......
...@@ -37,23 +37,32 @@ SCRIPT_FUNCTION(new_card) { ...@@ -37,23 +37,32 @@ SCRIPT_FUNCTION(new_card) {
} }
Value* value = value_it->get(); Value* value = value_it->get();
// set the value // set the value
#if !USE_SCRIPT_VALUE_TEXT
if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) { if (TextValue* tvalue = dynamic_cast<TextValue*>(value)) {
tvalue->value = v->toString(); tvalue->value = v->toString();
} else
#endif
#if !USE_SCRIPT_VALUE_CHOICE #if !USE_SCRIPT_VALUE_CHOICE
} else if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) { if (ChoiceValue* cvalue = dynamic_cast<ChoiceValue*>(value)) {
cvalue->value = v->toString(); cvalue->value = v->toString();
} else
#endif #endif
} else if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) { #if !USE_SCRIPT_VALUE_PACKAGE
if (PackageChoiceValue* pvalue = dynamic_cast<PackageChoiceValue*>(value)) {
pvalue->package_name = v->toString(); pvalue->package_name = v->toString();
} else
#endif
#if !USE_SCRIPT_VALUE_COLOR #if !USE_SCRIPT_VALUE_COLOR
} else if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) { if (ColorValue* cvalue = dynamic_cast<ColorValue*>(value)) {
cvalue->value = v->toColor(); cvalue->value = v->toColor();
} else
#endif #endif
#if USE_SCRIPT_VALUE_VALUE #if USE_SCRIPT_VALUE_VALUE
} else if (AnyValue* avalue = dynamic_cast<AnyValue*>(value)) { if (AnyValue* avalue = dynamic_cast<AnyValue*>(value)) {
avalue->value = v; avalue->value = v;
} else
#endif #endif
} else { {
throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name)); throw ScriptError(format_string(_("Can not set value '%s', it is not of the right type"),name));
} }
} }
......
...@@ -83,8 +83,8 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) { ...@@ -83,8 +83,8 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
Age new_value_update = last_update_age(); Age new_value_update = last_update_age();
FOR_EACH_2(v, values, nv, value_parts) { FOR_EACH_2(v, values, nv, value_parts) {
if (v->last_modified < new_value_update) { if (v->last_modified < new_value_update) {
bool changed = v->value() != nv.first; bool changed = v->value->toString() != nv.first;
v->value.assign(nv.first); if (changed) v->value = to_script(nv.first);
v->last_modified = new_value_update; v->last_modified = new_value_update;
changed |= v->update(ctx); changed |= v->update(ctx);
if (changed) { // notify of change if (changed) { // notify of change
...@@ -94,7 +94,7 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) { ...@@ -94,7 +94,7 @@ SCRIPT_FUNCTION_WITH_DEP(combined_editor) {
set->actions.tellListeners(change, false); set->actions.tellListeners(change, false);
} }
} }
nv.first = v->value(); nv.first = v->value->toString();
nv.second = index_to_untagged(nv.first, nv.first.size()) == 0; nv.second = index_to_untagged(nv.first, nv.first.size()) == 0;
} }
// options // options
...@@ -208,7 +208,7 @@ SCRIPT_FUNCTION(primary_choice) { ...@@ -208,7 +208,7 @@ SCRIPT_FUNCTION(primary_choice) {
throw ScriptError(_("Argument to 'primary_choice' should be a choice value")); throw ScriptError(_("Argument to 'primary_choice' should be a choice value"));
} }
// determine choice // determine choice
int id = field->choices->choiceId(value->toString()); int id = field->choices->choiceId(value->value->toString());
// find the last group that still contains id // find the last group that still contains id
const vector<ChoiceField::ChoiceP>& choices = field->choices->choices; const vector<ChoiceField::ChoiceP>& choices = field->choices->choices;
FOR_EACH_CONST_REVERSE(c, choices) { FOR_EACH_CONST_REVERSE(c, choices) {
......
...@@ -146,13 +146,16 @@ SCRIPT_FUNCTION(symbol_variation) { ...@@ -146,13 +146,16 @@ SCRIPT_FUNCTION(symbol_variation) {
SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input? SCRIPT_PARAM(ScriptValueP, symbol); // TODO: change to input?
ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get()); ScriptObject<ValueP>* valueO = dynamic_cast<ScriptObject<ValueP>*>(symbol.get());
SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr; SymbolValue* value = valueO ? dynamic_cast<SymbolValue*>(valueO->getValue().get()) : nullptr;
String filename; LocalSymbolFileP symbol_file;
if (value) { LocalFileName filename;
filename = value->filename; if (value && value->value->isNil()) {
} else if (valueO) { // empty filename
throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol" )); } else if(value && (symbol_file = dynamic_pointer_cast<LocalSymbolFile>(value->value))) {
filename = symbol_file->filename;
} else if (!valueO) {
filename = LocalFileName::fromReadString(symbol->toString());
} else { } else {
filename = symbol->toString(); throw ScriptErrorConversion(valueO->typeName(), _TYPE_("symbol"));
} }
// known variation? // known variation?
SCRIPT_OPTIONAL_PARAM_(String, variation) SCRIPT_OPTIONAL_PARAM_(String, variation)
...@@ -166,7 +169,7 @@ SCRIPT_FUNCTION(symbol_variation) { ...@@ -166,7 +169,7 @@ SCRIPT_FUNCTION(symbol_variation) {
FOR_EACH(v, style->variations) { FOR_EACH(v, style->variations) {
if (v->name == variation) { if (v->name == variation) {
// found it // found it
return intrusive(new SymbolToImage(value, filename, value->last_modified, v)); return intrusive(new SymbolToImage(value, filename, v));
} }
} }
throw ScriptError(_("Variation of symbol not found ('") + variation + _("')")); throw ScriptError(_("Variation of symbol not found ('") + variation + _("')"));
...@@ -200,7 +203,7 @@ SCRIPT_FUNCTION(symbol_variation) { ...@@ -200,7 +203,7 @@ SCRIPT_FUNCTION(symbol_variation) {
} else { } else {
throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type); throw ScriptError(_("Unknown fill type for symbol_variation: ") + fill_type);
} }
return intrusive(new SymbolToImage(value, filename, value ? value->last_modified : Age(), var)); return intrusive(new SymbolToImage(value, filename, var));
} }
} }
......
...@@ -448,8 +448,9 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) { ...@@ -448,8 +448,9 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
Token token = input.read(); Token token = input.read();
if (token == _("(")) { if (token == _("(")) {
// Parentheses = grouping for precedence of expressions // Parentheses = grouping for precedence of expressions
parseOper(input, script, PREC_ALL); ExprType type = parseOper(input, script, PREC_ALL);
expectToken(input, _(")"), &token); expectToken(input, _(")"), &token);
return type;
} else if (token == _("{")) { } else if (token == _("{")) {
// {} = function block. Parse a new Script // {} = function block. Parse a new Script
intrusive_ptr<Script> subScript(new Script); intrusive_ptr<Script> subScript(new Script);
...@@ -500,19 +501,19 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) { ...@@ -500,19 +501,19 @@ ExprType parseExpr(TokenIterator& input, Script& script, Precedence minPrec) {
parseOper(input, script, PREC_AND); // AAA parseOper(input, script, PREC_AND); // AAA
unsigned jmpElse = script.addInstruction(I_JUMP_IF_NOT); // jnz lbl_else unsigned jmpElse = script.addInstruction(I_JUMP_IF_NOT); // jnz lbl_else
expectToken(input, _("then")); // then expectToken(input, _("then")); // then
parseOper(input, script, PREC_SET); // BBB ExprType type1 = parseOper(input, script, PREC_SET); // BBB
unsigned jmpEnd = script.addInstruction(I_JUMP); // jump lbl_end unsigned jmpEnd = script.addInstruction(I_JUMP); // jump lbl_end
script.comeFrom(jmpElse); // lbl_else: script.comeFrom(jmpElse); // lbl_else:
bool has_else = input.peek() == _("else"); //else bool has_else = input.peek() == _("else"); //else
ExprType type = EXPR_STATEMENT; ExprType type2 = EXPR_STATEMENT;
if (has_else) { if (has_else) {
input.read(); input.read();
type = parseOper(input, script, PREC_SET); // CCC type2 = parseOper(input, script, PREC_SET); // CCC
} else { } else {
script.addInstruction(I_PUSH_CONST, script_nil); script.addInstruction(I_PUSH_CONST, script_nil);
} }
script.comeFrom(jmpEnd); // lbl_end: script.comeFrom(jmpEnd); // lbl_end:
return type == EXPR_STATEMENT ? EXPR_STATEMENT : EXPR_OTHER; return type1 == EXPR_STATEMENT || type2 == EXPR_STATEMENT ? EXPR_STATEMENT : EXPR_OTHER;
} else if (token == _("for")) { } else if (token == _("for")) {
// the loop body should have a net stack effect of 0, but the entire expression of +1 // the loop body should have a net stack effect of 0, but the entire expression of +1
// solution: add all results from the body, start with nil // solution: add all results from the body, start with nil
...@@ -724,7 +725,7 @@ ExprType parseOper(TokenIterator& input, Script& script, Precedence minPrec, Ins ...@@ -724,7 +725,7 @@ ExprType parseOper(TokenIterator& input, Script& script, Precedence minPrec, Ins
else if (minPrec <= PREC_AND && token==_("xor")) parseOper(input, script, PREC_CMP, I_BINARY, I_XOR); else if (minPrec <= PREC_AND && token==_("xor")) parseOper(input, script, PREC_CMP, I_BINARY, I_XOR);
else if (minPrec <= PREC_CMP && token==_("=")) { else if (minPrec <= PREC_CMP && token==_("=")) {
if (minPrec <= PREC_SET) { if (minPrec <= PREC_SET) {
input.add_error(_("Use of '=', did you mean ':=' or '=='?")); input.add_error(_("Use of '=', did you mean ':=' or '=='? I will assume '=='"));
} }
parseOper(input, script, PREC_ADD, I_BINARY, I_EQ); parseOper(input, script, PREC_ADD, I_BINARY, I_EQ);
} }
...@@ -851,6 +852,9 @@ void parseCallArguments(TokenIterator& input, Script& script, vector<Variable>& ...@@ -851,6 +852,9 @@ void parseCallArguments(TokenIterator& input, Script& script, vector<Variable>&
// ----------------------------------------------------------------------------- : Parsing values // ----------------------------------------------------------------------------- : Parsing values
ScriptValueP script_local_image_file(LocalFileName const& filename);
ScriptValueP script_local_symbol_file(LocalFileName const& filename);
ScriptValueP parse_value(TokenIterator& input, Packaged* package) { ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
Token token = input.read(); Token token = input.read();
if (token == _("(")) { if (token == _("(")) {
...@@ -884,9 +888,6 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) { ...@@ -884,9 +888,6 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
} }
expectToken(input, _("]"), &token); expectToken(input, _("]"), &token);
return col; return col;
} else if (token == _("-")) {
// TODO?
throw "TODO";
} else if (token == TOK_NAME) { } else if (token == TOK_NAME) {
if (token == _("true")) { if (token == _("true")) {
return script_true; return script_true;
...@@ -920,16 +921,22 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) { ...@@ -920,16 +921,22 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
return to_script(AColor(r->toInt(),g->toInt(),b->toInt(),a->toInt())); return to_script(AColor(r->toInt(),g->toInt(),b->toInt(),a->toInt()));
} else if (token == _("mark_default")) { } else if (token == _("mark_default")) {
expectToken(input, _("(")); expectToken(input, _("("));
ScriptValueP a = parse_value(input, package); ScriptValueP x = parse_value(input, package);
expectToken(input, _(")")); expectToken(input, _(")"));
if (!a) return ScriptValueP(); if (!x) return ScriptValueP();
return intrusive(new ScriptDefault(a)); return intrusive(new ScriptDefault(x));
} else if (token == _("local_filename")) { } else if (token == _("local_image_file")) {
expectToken(input, _("(")); expectToken(input, _("("));
ScriptValueP a = parse_value(input, package); ScriptValueP x = parse_value(input, package);
expectToken(input, _(")")); expectToken(input, _(")"));
if (!a) return ScriptValueP(); if (!x) return ScriptValueP();
return intrusive(new ScriptLocalFileName(package,a->toString())); return script_local_image_file(LocalFileName::fromReadString(x->toString()));
} else if (token == _("local_symbol_file")) {
expectToken(input, _("("));
ScriptValueP x = parse_value(input, package);
expectToken(input, _(")"));
if (!x) return ScriptValueP();
return script_local_symbol_file(LocalFileName::fromReadString(x->toString()));
} }
} else if (token == TOK_INT) { } else if (token == TOK_INT) {
long l = 0; long l = 0;
...@@ -941,6 +948,9 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) { ...@@ -941,6 +948,9 @@ ScriptValueP parse_value(TokenIterator& input, Packaged* package) {
return to_script(d); return to_script(d);
} else if (token == TOK_STRING) { } else if (token == TOK_STRING) {
return to_script(token.value); return to_script(token.value);
/*} else if (token == _("-")) {
// TODO?
throw InternalError("TODO");*/
} }
// parse error // parse error
input.expected(_("value (string/number/boolean/color/list)")); input.expected(_("value (string/number/boolean/color/list)"));
......
...@@ -111,6 +111,7 @@ class ScriptDefault : public ScriptValue { ...@@ -111,6 +111,7 @@ class ScriptDefault : public ScriptValue {
virtual ScriptType type() const { return un_default->type(); } virtual ScriptType type() const { return un_default->type(); }
virtual String typeName() const { return un_default->typeName(); } virtual String typeName() const { return un_default->typeName(); }
virtual String toString() const { return un_default->toString(); } virtual String toString() const { return un_default->toString(); }
virtual String toFriendlyString() const { return un_default->toFriendlyString(); }
virtual String toCode() const { return _("mark_default(") + un_default->toCode() + _(")"); } virtual String toCode() const { return _("mark_default(") + un_default->toCode() + _(")"); }
virtual double toDouble() const { return un_default->toDouble(); } virtual double toDouble() const { return un_default->toDouble(); }
virtual int toInt() const { return un_default->toInt(); } virtual int toInt() const { return un_default->toInt(); }
...@@ -130,13 +131,14 @@ inline ScriptDefault const* is_default(ScriptValueP const& x) { ...@@ -130,13 +131,14 @@ inline ScriptDefault const* is_default(ScriptValueP const& x) {
return is_default(x.get()); return is_default(x.get());
} }
inline ScriptValueP make_default(ScriptValueP const& x) { inline ScriptValueP make_default(ScriptValueP const& x) {
return intrusive(new ScriptDefault(x)); return is_default(x) ? x : intrusive(new ScriptDefault(x));
} }
inline ScriptValueP with_defaultness_of(ScriptValueP const& of, ScriptValueP const& x) { inline ScriptValueP with_defaultness_of(ScriptValueP const& of, ScriptValueP const& x) {
return is_default(of) ? make_default(x) : x; return is_default(of) ? make_default(x) : x;
} }
extern ScriptValueP script_default_nil; extern ScriptValueP script_default_nil;
/*
// ----------------------------------------------------------------------------- : File names // ----------------------------------------------------------------------------- : File names
class Packaged; class Packaged;
...@@ -156,6 +158,7 @@ class ScriptLocalFileName : public ScriptValue { ...@@ -156,6 +158,7 @@ class ScriptLocalFileName : public ScriptValue {
String fn; //< The filename String fn; //< The filename
Type file_type; Type file_type;
}; };
*/
// ----------------------------------------------------------------------------- : Iterators // ----------------------------------------------------------------------------- : Iterators
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <script/context.hpp> #include <script/context.hpp>
#include <gfx/generated_image.hpp> #include <gfx/generated_image.hpp>
#include <util/error.hpp> #include <util/error.hpp>
#include <util/tagged_string.hpp>
#include <boost/pool/singleton_pool.hpp> #include <boost/pool/singleton_pool.hpp>
DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>); DECLARE_TYPEOF_COLLECTION(pair<Variable COMMA ScriptValueP>);
...@@ -27,6 +28,7 @@ AColor ScriptValue::toColor() const { throw Script ...@@ -27,6 +28,7 @@ AColor ScriptValue::toColor() const { throw Script
wxDateTime ScriptValue::toDateTime() const { throw ScriptErrorConversion(typeName(), _TYPE_("date" )); } wxDateTime ScriptValue::toDateTime() const { throw ScriptErrorConversion(typeName(), _TYPE_("date" )); }
GeneratedImageP ScriptValue::toImage() const { throw ScriptErrorConversion(typeName(), _TYPE_("image" )); } GeneratedImageP ScriptValue::toImage() const { throw ScriptErrorConversion(typeName(), _TYPE_("image" )); }
String ScriptValue::toCode() const { return toString(); } String ScriptValue::toCode() const { return toString(); }
String ScriptValue::toFriendlyString() const { return toString(); }
ScriptValueP ScriptValue::do_eval(Context&, bool) const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("function"))); } ScriptValueP ScriptValue::do_eval(Context&, bool) const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("function"))); }
ScriptValueP ScriptValue::next(ScriptValueP* key_out) { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); } ScriptValueP ScriptValue::next(ScriptValueP* key_out) { throw InternalError(_("Can't convert from ")+typeName()+_(" to iterator")); }
ScriptValueP ScriptValue::makeIterator() const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("collection"))); } ScriptValueP ScriptValue::makeIterator() const { return delay_error(ScriptErrorConversion(typeName(), _TYPE_("collection"))); }
...@@ -250,6 +252,11 @@ class ScriptString : public ScriptValue { ...@@ -250,6 +252,11 @@ class ScriptString : public ScriptValue {
virtual String toCode() const { virtual String toCode() const {
return quote_string(value); return quote_string(value);
} }
virtual String toFriendlyString() const {
// assume that the string can contain tags
// TODO: distinguish between strings with tags and strings without
return untag(value);
}
virtual double toDouble() const { virtual double toDouble() const {
double d; double d;
if (value.ToDouble(&d)) { if (value.ToDouble(&d)) {
......
...@@ -63,6 +63,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete { ...@@ -63,6 +63,8 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
virtual String toString() const; virtual String toString() const;
/// Script code to generate this value /// Script code to generate this value
virtual String toCode() const; virtual String toCode() const;
/// A string that can be shown to a user (i.e. not a template developer), should not contains tags
virtual String toFriendlyString() const;
/// Convert this value to a double /// Convert this value to a double
virtual double toDouble() const; virtual double toDouble() const;
/// Convert this value to an integer /// Convert this value to an integer
...@@ -75,7 +77,9 @@ class ScriptValue : public IntrusivePtrBaseWithDelete { ...@@ -75,7 +77,9 @@ class ScriptValue : public IntrusivePtrBaseWithDelete {
virtual wxDateTime toDateTime() const; virtual wxDateTime toDateTime() const;
/// Convert this value to an image /// Convert this value to an image
virtual GeneratedImageP toImage() const; virtual GeneratedImageP toImage() const;
/// Is the value equal to script_nil?
inline bool isNil() const { return type() == SCRIPT_NIL; }
/// Get a member variable from this value /// Get a member variable from this value
virtual ScriptValueP getMember(const String& name) const; virtual ScriptValueP getMember(const String& name) const;
......
...@@ -33,8 +33,10 @@ class Age { ...@@ -33,8 +33,10 @@ class Age {
} }
/// Compare two ages, smaller means earlier /// Compare two ages, smaller means earlier
inline bool operator < (Age a) const { return age < a.age; } inline bool operator < (Age a) const { return age < a.age; }
/// Compare two ages inline bool operator <= (Age a) const { return age <= a.age; }
inline bool operator > (Age a) const { return age > a.age; }
inline bool operator >= (Age a) const { return age >= a.age; }
inline bool operator == (Age a) const { return age == a.age; } inline bool operator == (Age a) const { return age == a.age; }
/// A number corresponding to the age /// A number corresponding to the age
......
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <data/field/text.hpp>
#include <wx/fdrepdlg.h> #include <wx/fdrepdlg.h>
DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(Card);
DECLARE_POINTER_TYPE(TextValue);
// ----------------------------------------------------------------------------- : Search/replace // ----------------------------------------------------------------------------- : Search/replace
......
...@@ -18,7 +18,7 @@ using boost::tribool; ...@@ -18,7 +18,7 @@ using boost::tribool;
void GetDefaultMember::handle(const Char* v) { value = to_script(v); } void GetDefaultMember::handle(const Char* v) { value = to_script(v); }
template <> void GetDefaultMember::handle(const String& v) { value = to_script(v); } template <> void GetDefaultMember::handle(const String& v) { value = to_script(v); }
template <> void GetDefaultMember::handle(const FileName& v) { value = to_script(v); } //template <> void GetDefaultMember::handle(const FileName& v) { value = to_script(v); }
template <> void GetDefaultMember::handle(const int& v) { value = to_script(v); } template <> void GetDefaultMember::handle(const int& v) { value = to_script(v); }
template <> void GetDefaultMember::handle(const unsigned int& v) { value = to_script((int)v); } template <> void GetDefaultMember::handle(const unsigned int& v) { value = to_script((int)v); }
template <> void GetDefaultMember::handle(const double& v) { value = to_script(v); } template <> void GetDefaultMember::handle(const double& v) { value = to_script(v); }
......
...@@ -259,7 +259,7 @@ String Package::nameOut(const String& file) { ...@@ -259,7 +259,7 @@ String Package::nameOut(const String& file) {
} }
} }
FileName Package::newFileName(const String& prefix, const String& suffix) { LocalFileName Package::newFileName(const String& prefix, const String& suffix) {
assert(wxThread::IsMain()); // Writing should only be done from the main thread assert(wxThread::IsMain()); // Writing should only be done from the main thread
String name; String name;
UInt infix = 0; UInt infix = 0;
...@@ -287,6 +287,8 @@ void Package::referenceFile(const String& file) { ...@@ -287,6 +287,8 @@ void Package::referenceFile(const String& file) {
it->second.keep = true; it->second.keep = true;
} }
// ----------------------------------------------------------------------------- : LocalFileNames and absolute file references
String Package::absoluteName(const String& file) { String Package::absoluteName(const String& file) {
assert(wxThread::IsMain()); assert(wxThread::IsMain());
FileInfos::iterator it = files.find(normalize_internal_filename(file)); FileInfos::iterator it = files.find(normalize_internal_filename(file));
...@@ -301,9 +303,10 @@ String Package::absoluteName(const String& file) { ...@@ -301,9 +303,10 @@ String Package::absoluteName(const String& file) {
return filename+_("/")+file; return filename+_("/")+file;
} else { } else {
// assume zip package // assume zip package
return filename+_("\1")+file; return filename + _("\1") + file;
} }
} }
// Open a file that is in some package // Open a file that is in some package
InputStreamP Package::openAbsoluteFile(const String& name) { InputStreamP Package::openAbsoluteFile(const String& name) {
size_t pos = name.find_first_of(_('\1')); size_t pos = name.find_first_of(_('\1'));
...@@ -320,6 +323,42 @@ InputStreamP Package::openAbsoluteFile(const String& name) { ...@@ -320,6 +323,42 @@ InputStreamP Package::openAbsoluteFile(const String& name) {
} }
} }
String LocalFileName::toStringForWriting() const {
if (!fn.empty() && clipboard_package()) {
// use absolute names on clipboard
try {
return clipboard_package()->absoluteName(fn);
} catch (const Error&) {
// ignore errors
return _("");
}
} else if (!fn.empty() && writing_package()) {
writing_package()->referenceFile(fn);
return fn;
} else {
return fn;
}
}
LocalFileName LocalFileName::fromReadString(String const& fn, String const& prefix, String const& suffix) {
if (!fn.empty() && clipboard_package()) {
// copy file into current package
try {
LocalFileName local_name = clipboard_package()->newFileName(prefix,_("")); // a new unique name in the package, assume it's an image
OutputStreamP out = clipboard_package()->openOut(local_name);
InputStreamP in = Package::openAbsoluteFile(fn);
out->Write(*in); // copy
return local_name;
} catch (Error) {
// ignore errors
return _("");
}
} else {
return LocalFileName(fn);
}
}
// ----------------------------------------------------------------------------- : Package : private // ----------------------------------------------------------------------------- : Package : private
Package::FileInfo::FileInfo() Package::FileInfo::FileInfo()
......
...@@ -21,15 +21,51 @@ class wxZipInputStream; ...@@ -21,15 +21,51 @@ class wxZipInputStream;
class wxZipEntry; class wxZipEntry;
DECLARE_POINTER_TYPE(PackageDependency); DECLARE_POINTER_TYPE(PackageDependency);
/// The package that is currently being written to /// The package that is currently being written to.
/// When writing a filename, the writing_package should be notified that this file is still in use.
DECLARE_DYNAMIC_ARG(Package*, writing_package); DECLARE_DYNAMIC_ARG(Package*, writing_package);
/// The package that is being put onto/read from the clipboard /// The package that contains the thing being written to the clipboard, or the package that will contain the thing being read from the clipboard.
/// When writing a filename, it should be converted to a global name referencing clipboard_package.
/// When reading a global name, the file should be copied into the clipboard_package.
DECLARE_DYNAMIC_ARG(Package*, clipboard_package); DECLARE_DYNAMIC_ARG(Package*, clipboard_package);
typedef shared_ptr<wxOutputStream> OutputStreamP; typedef shared_ptr<wxOutputStream> OutputStreamP;
// ----------------------------------------------------------------------------- : FileName
/// A string standing for a filename, has different behaviour when reading/writing
/// Behaviour is controled by dynamic args:
/// * clipboard_package
/// * writing_package
class LocalFileName {
public:
LocalFileName() {}
// Convert to a string that can be written to a package.
// notifies the package that the underlying file is in use.
// when writing to the clipboard, instead returns a global file reference.
String toStringForWriting() const;
// Construct a LocalFileName based on a string read from a package.
// when reading from the clipboard, this will instead be a global file reference, and it is converted at this point.
static LocalFileName fromReadString(const String&, const String& prefix = _("image"), String const& suffix = _(""));
inline bool empty() const {
return fn.empty();
}
inline bool operator == (LocalFileName const& that) const {
return this->fn == that.fn;
}
private:
LocalFileName(const wxString& fn) : fn(fn) {}
String fn;
friend class Package;
};
// TODO: rename to LocalFileName
typedef LocalFileName FileName;
// ----------------------------------------------------------------------------- : Package // ----------------------------------------------------------------------------- : Package
/// A package is a container for files. On disk it is either a directory or a zip file. /// A package is a container for files. On disk it is either a directory or a zip file.
...@@ -105,14 +141,23 @@ class Package : public IntrusivePtrVirtualBase { ...@@ -105,14 +141,23 @@ class Package : public IntrusivePtrVirtualBase {
/// Open an input stream for a file in the package. /// Open an input stream for a file in the package.
InputStreamP openIn(const String& file); InputStreamP openIn(const String& file);
inline InputStreamP openIn(const LocalFileName& file) {
return openIn(file.fn);
}
/// Open an output stream for a file in the package. /// Open an output stream for a file in the package.
/// (changes are only committed with save()) /// (changes are only committed with save())
OutputStreamP openOut(const String& file); OutputStreamP openOut(const String& file);
inline OutputStreamP openOut(const LocalFileName& file) {
return openOut(file.fn);
}
/// Get a filename that can be written to to modfify a file in the package /// Get a filename that can be written to to modfify a file in the package
/// (changes are only committed with save()) /// (changes are only committed with save())
String nameOut(const String& file); String nameOut(const String& file);
inline String nameOut(const LocalFileName& file) {
return nameOut(file.fn);
}
/// Creates a new, unique, filename with the specified prefix and suffix /// Creates a new, unique, filename with the specified prefix and suffix
/// for example newFileName("image/",".jpg") -> "image/1.jpg" /// for example newFileName("image/",".jpg") -> "image/1.jpg"
...@@ -124,13 +169,6 @@ class Package : public IntrusivePtrVirtualBase { ...@@ -124,13 +169,6 @@ class Package : public IntrusivePtrVirtualBase {
/// If they are to be kept in the package. /// If they are to be kept in the package.
void referenceFile(const String& file); void referenceFile(const String& file);
/// Get an 'absolute filename' for a file in the package.
/// This file can later be opened from anywhere (other process) using openAbsoluteFile()
String absoluteName(const String& file);
/// Open a file given an absolute filename
static InputStreamP openAbsoluteFile(const String& name);
// --------------------------------------------------- : Managing the inside of the package : Reader/writer // --------------------------------------------------- : Managing the inside of the package : Reader/writer
template <typename T> template <typename T>
...@@ -142,6 +180,10 @@ class Package : public IntrusivePtrVirtualBase { ...@@ -142,6 +180,10 @@ class Package : public IntrusivePtrVirtualBase {
readFile(file, obj); readFile(file, obj);
return obj; return obj;
} }
template <typename T>
inline T readFile(const LocalFileName& file) {
return readFile<T>(file.fn);
}
template <typename T> template <typename T>
void writeFile(const String& file, const T& obj, Version file_version) { void writeFile(const String& file, const T& obj, Version file_version) {
...@@ -149,6 +191,10 @@ class Package : public IntrusivePtrVirtualBase { ...@@ -149,6 +191,10 @@ class Package : public IntrusivePtrVirtualBase {
Writer writer(*stream, file_version); Writer writer(*stream, file_version);
writer.handle(obj); writer.handle(obj);
} }
template <typename T>
inline void writeFile(const LocalFileName& file, const T& obj, Version file_version) {
return readFile(file.fn, obj, file_version);
}
protected: protected:
// TODO: I dislike putting this here very much. There ought to be a better way. // TODO: I dislike putting this here very much. There ought to be a better way.
...@@ -202,6 +248,13 @@ class Package : public IntrusivePtrVirtualBase { ...@@ -202,6 +248,13 @@ class Package : public IntrusivePtrVirtualBase {
void saveToZipfile(const String&, bool remove_unused, bool is_copy); void saveToZipfile(const String&, bool remove_unused, bool is_copy);
void saveToDirectory(const String&, bool remove_unused, bool is_copy); void saveToDirectory(const String&, bool remove_unused, bool is_copy);
FileInfos::iterator addFile(const String& file); FileInfos::iterator addFile(const String& file);
/// Get an 'absolute filename' for a file in the package.
/// This file can later be opened from anywhere (other process) using openAbsoluteFile()
String absoluteName(const String& file);
/// Open a file given an absolute filename
static InputStreamP openAbsoluteFile(const String& name);
friend class LocalFileName;
}; };
// ----------------------------------------------------------------------------- : Packaged // ----------------------------------------------------------------------------- : Packaged
......
...@@ -56,6 +56,9 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) { ...@@ -56,6 +56,9 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
// global data dir // global data dir
filename = normalize_filename(global.name(name)); filename = normalize_filename(global.name(name));
} }
if (!wxFileExists(filename) && !wxDirExists(filename)) {
throw PackageNotFoundError(_("Package not found: '") + name + _("'"));
}
} else { // Absolute filename } else { // Absolute filename
filename = normalize_filename(name); filename = normalize_filename(name);
} }
......
...@@ -371,26 +371,8 @@ template <> void Reader::handle(Vector2D& vec) { ...@@ -371,26 +371,8 @@ template <> void Reader::handle(Vector2D& vec) {
} }
} }
template <> void Reader::handle(FileName& f) { template <> void Reader::handle(LocalFileName& f) {
if (clipboard_package()) { f = LocalFileName::fromReadString(this->getValue());
String str = getValue();
if (!str.empty()) {
// copy file into current package
try {
String packaged_name = clipboard_package()->newFileName(_("image"),_("")); // a new unique name in the package, assume it's an image
OutputStreamP out = clipboard_package()->openOut(packaged_name);
InputStreamP in = Package::openAbsoluteFile(str);
out->Write(*in); // copy
f.assign(packaged_name);
} catch (Error) {
// ignore errors
}
} else {
f.assign(str);
}
} else {
handle(static_cast<String&>(f));
}
} }
// ----------------------------------------------------------------------------- : EnumReader // ----------------------------------------------------------------------------- : EnumReader
......
...@@ -133,18 +133,6 @@ template <> void Writer::handle(const Color& col) { ...@@ -133,18 +133,6 @@ template <> void Writer::handle(const Color& col) {
handle(String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue())); handle(String::Format(_("rgb(%u,%u,%u)"), col.Red(), col.Green(), col.Blue()));
} }
template <> void Writer::handle(const FileName& value) { template <> void Writer::handle(const LocalFileName& value) {
if (clipboard_package() && !value.empty()) { handle(value.toStringForWriting());
// use absolute names on clipboard
try {
handle(clipboard_package()->absoluteName(value));
} catch (const Error&) {
// ignore errors
}
} else {
handle(static_cast<const String&>(value));
if (writing_package()) {
writing_package()->referenceFile(value);
}
}
} }
...@@ -89,13 +89,6 @@ typedef unsigned int UInt; ...@@ -89,13 +89,6 @@ typedef unsigned int UInt;
/// Null pointer /// Null pointer
#define nullptr 0 #define nullptr 0
/// A string standing for a filename, has different behaviour when reading/writing
class FileName : public wxString {
public:
FileName() {}
FileName(const wxString& s) : wxString(s) {}
};
// ----------------------------------------------------------------------------- : MSE Headers // ----------------------------------------------------------------------------- : MSE Headers
// MSE utility headers (ones unlikely to change and used everywhere) // MSE utility headers (ones unlikely to change and used everywhere)
......
...@@ -89,8 +89,8 @@ const Version file_version_set = 20001; // 2.0.1 ...@@ -89,8 +89,8 @@ const Version file_version_set = 20001; // 2.0.1
const Version file_version_game = 20001; // 2.0.1 const Version file_version_game = 20001; // 2.0.1
const Version file_version_stylesheet = 20001; // 2.0.1 const Version file_version_stylesheet = 20001; // 2.0.1
const Version file_version_symbol_font = 20001; // 2.0.1 const Version file_version_symbol_font = 20001; // 2.0.1
const Version file_version_export_template = 307; // 0.3.7 const Version file_version_export_template = 20001; // 2.0.1
const Version file_version_installer = 307; // 0.3.7 const Version file_version_installer = 307; // 0.3.7
const Version file_version_symbol = 305; // 0.3.5 const Version file_version_symbol = 305; // 0.3.5
const Version file_version_clipboard = 308; // 0.3.8 const Version file_version_clipboard = 20001; // 2.0.1
const Version file_version_script = 20001; // 2.0.1 const Version file_version_script = 20001; // 2.0.1
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