mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
fix "referencing nonexistant file" bug
improve internal error message
This commit is contained in:
@@ -7,17 +7,10 @@
|
|||||||
// ----------------------------------------------------------------------------- : Includes
|
// ----------------------------------------------------------------------------- : Includes
|
||||||
|
|
||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
|
#include <util/tagged_string.hpp>
|
||||||
#include <data/action/value.hpp>
|
#include <data/action/value.hpp>
|
||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
#include <data/field/text.hpp>
|
|
||||||
#include <data/field/choice.hpp>
|
|
||||||
#include <data/field/multiple_choice.hpp>
|
|
||||||
#include <data/field/color.hpp>
|
|
||||||
#include <data/field/image.hpp>
|
|
||||||
#include <data/field/symbol.hpp>
|
|
||||||
#include <data/field/package_choice.hpp>
|
|
||||||
#include <data/card.hpp>
|
#include <data/card.hpp>
|
||||||
#include <util/tagged_string.hpp>
|
|
||||||
#include <data/set.hpp> // for ValueActionPerformer
|
#include <data/set.hpp> // for ValueActionPerformer
|
||||||
#include <wx/imaglist.h>
|
#include <wx/imaglist.h>
|
||||||
|
|
||||||
@@ -44,48 +37,6 @@ void ValueAction::setCard(CardP const& card) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Simple
|
// ----------------------------------------------------------------------------- : Simple
|
||||||
|
|
||||||
/// Swap the value in a Value object with a new one
|
|
||||||
inline void swap_value(ChoiceValue& a, ChoiceValue ::ValueType& b) { swap(a.value, b); }
|
|
||||||
inline void swap_value(ColorValue& a, ColorValue ::ValueType& b) { swap(a.value, b); }
|
|
||||||
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
|
||||||
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
|
||||||
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); a.last_update.update(); }
|
|
||||||
inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); }
|
|
||||||
inline void swap_value(MultipleChoiceValue& a, MultipleChoiceValue::ValueType& b) {
|
|
||||||
swap(a.value, b.value);
|
|
||||||
swap(a.last_change, b.last_change);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A ValueAction that swaps between old and new values
|
|
||||||
template <typename T, bool ALLOW_MERGE>
|
|
||||||
class SimpleValueAction : public ValueAction {
|
|
||||||
public:
|
|
||||||
inline SimpleValueAction(const intrusive_ptr<T>& value, const typename T::ValueType& new_value)
|
|
||||||
: ValueAction(value), new_value(new_value)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void perform(bool to_undo) override {
|
|
||||||
ValueAction::perform(to_undo);
|
|
||||||
swap_value(static_cast<T&>(*valueP), new_value);
|
|
||||||
valueP->onAction(*this, to_undo); // notify value
|
|
||||||
}
|
|
||||||
|
|
||||||
bool merge(const Action& action) override {
|
|
||||||
if (!ALLOW_MERGE) return false;
|
|
||||||
TYPE_CASE(action, SimpleValueAction) {
|
|
||||||
if (action.valueP == valueP) {
|
|
||||||
// adjacent actions on the same value, discard the other one,
|
|
||||||
// because it only keeps an intermediate value
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typename T::ValueType new_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
unique_ptr<ValueAction> value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) {
|
unique_ptr<ValueAction> value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) {
|
||||||
return make_unique<SimpleValueAction<ChoiceValue, true>>(value, new_value);
|
return make_unique<SimpleValueAction<ChoiceValue, true>>(value, new_value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
#include <util/action_stack.hpp>
|
#include <util/action_stack.hpp>
|
||||||
#include <util/defaultable.hpp>
|
#include <util/defaultable.hpp>
|
||||||
|
#include <data/field/text.hpp>
|
||||||
|
#include <data/field/choice.hpp>
|
||||||
|
#include <data/field/multiple_choice.hpp>
|
||||||
|
#include <data/field/color.hpp>
|
||||||
|
#include <data/field/image.hpp>
|
||||||
|
#include <data/field/symbol.hpp>
|
||||||
|
#include <data/field/package_choice.hpp>
|
||||||
|
|
||||||
class StyleSheet;
|
class StyleSheet;
|
||||||
class LocalFileName;
|
class LocalFileName;
|
||||||
@@ -53,6 +60,47 @@ private:
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Simple
|
// ----------------------------------------------------------------------------- : Simple
|
||||||
|
|
||||||
|
/// Swap the value in a Value object with a new one
|
||||||
|
inline void swap_value(ChoiceValue& a, ChoiceValue ::ValueType& b) { swap(a.value, b); }
|
||||||
|
inline void swap_value(ColorValue& a, ColorValue ::ValueType& b) { swap(a.value, b); }
|
||||||
|
inline void swap_value(ImageValue& a, ImageValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
||||||
|
inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b) { swap(a.filename, b); a.last_update.update(); }
|
||||||
|
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); a.last_update.update(); }
|
||||||
|
inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); }
|
||||||
|
inline void swap_value(MultipleChoiceValue& a, MultipleChoiceValue::ValueType& b) {
|
||||||
|
swap(a.value, b.value);
|
||||||
|
swap(a.last_change, b.last_change);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A ValueAction that swaps between old and new values
|
||||||
|
template <typename T, bool ALLOW_MERGE>
|
||||||
|
class SimpleValueAction : public ValueAction {
|
||||||
|
public:
|
||||||
|
inline SimpleValueAction(const intrusive_ptr<T>& value, const typename T::ValueType& new_value)
|
||||||
|
: ValueAction(value), new_value(new_value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void perform(bool to_undo) override {
|
||||||
|
ValueAction::perform(to_undo);
|
||||||
|
swap_value(static_cast<T&>(*valueP), new_value);
|
||||||
|
valueP->onAction(*this, to_undo); // notify value
|
||||||
|
}
|
||||||
|
|
||||||
|
bool merge(const Action& action) override {
|
||||||
|
if (!ALLOW_MERGE) return false;
|
||||||
|
TYPE_CASE(action, SimpleValueAction) {
|
||||||
|
if (action.valueP == valueP) {
|
||||||
|
// adjacent actions on the same value, discard the other one,
|
||||||
|
// because it only keeps an intermediate value
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename T::ValueType new_value;
|
||||||
|
};
|
||||||
|
|
||||||
/// Action that updates a Value to a new value
|
/// Action that updates a Value to a new value
|
||||||
unique_ptr<ValueAction> value_action(const ChoiceValueP& value, const Defaultable<String>& new_value);
|
unique_ptr<ValueAction> value_action(const ChoiceValueP& value, const Defaultable<String>& new_value);
|
||||||
unique_ptr<ValueAction> value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change);
|
unique_ptr<ValueAction> value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change);
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
#include <data/field.hpp>
|
#include <data/field.hpp>
|
||||||
#include <data/field/text.hpp> // for 0.2.7 fix
|
#include <data/field/text.hpp> // for 0.2.7 fix
|
||||||
#include <data/field/information.hpp>
|
#include <data/field/information.hpp>
|
||||||
|
#include <data/field/image.hpp>
|
||||||
|
#include <data/field/symbol.hpp>
|
||||||
|
#include <data/action/value.hpp>
|
||||||
#include <util/tagged_string.hpp> // for 0.2.7 fix
|
#include <util/tagged_string.hpp> // for 0.2.7 fix
|
||||||
#include <util/order_cache.hpp>
|
#include <util/order_cache.hpp>
|
||||||
#include <util/delayed_index_maps.hpp>
|
#include <util/delayed_index_maps.hpp>
|
||||||
@@ -104,6 +107,28 @@ IndexMap<FieldP, ValueP>& Set::stylingDataFor(const CardP& card) {
|
|||||||
else return stylingDataFor(stylesheetFor(card));
|
else return stylingDataFor(stylesheetFor(card));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Set::referenceActionStackFiles() {
|
||||||
|
referenceActionStackFiles(true);
|
||||||
|
referenceActionStackFiles(false);
|
||||||
|
}
|
||||||
|
void Set::referenceActionStackFiles(bool undo) {
|
||||||
|
for (auto&& action : undo ? actions.undo_actions : actions.redo_actions) {
|
||||||
|
try {
|
||||||
|
SimpleValueAction<ImageValue, false>& v = dynamic_cast<SimpleValueAction<ImageValue, false>&>(*action);
|
||||||
|
if (ImageValue* v2 = dynamic_cast<ImageValue*>(v.valueP.get())) {
|
||||||
|
referenceFile(v.new_value.toStringForWriting());
|
||||||
|
referenceFile(v2->filename.toStringForWriting());
|
||||||
|
}
|
||||||
|
} catch (...) { try {
|
||||||
|
SimpleValueAction<SymbolValue, false>& v = dynamic_cast<SimpleValueAction<SymbolValue, false>&>(*action);
|
||||||
|
if (SymbolValue* v2 = dynamic_cast<SymbolValue*>(v.valueP.get())) {
|
||||||
|
referenceFile(v.new_value.toStringForWriting());
|
||||||
|
referenceFile(v2->filename.toStringForWriting());
|
||||||
|
}
|
||||||
|
} catch (...) {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String Set::identification() const {
|
String Set::identification() const {
|
||||||
// an identifying field
|
// an identifying field
|
||||||
FOR_EACH_CONST(v, data) {
|
FOR_EACH_CONST(v, data) {
|
||||||
|
|||||||
+7
-2
@@ -89,8 +89,13 @@ public:
|
|||||||
/// Styling information for a particular stylesheet
|
/// Styling information for a particular stylesheet
|
||||||
IndexMap<FieldP, ValueP>& stylingDataFor(const StyleSheet&);
|
IndexMap<FieldP, ValueP>& stylingDataFor(const StyleSheet&);
|
||||||
/// Styling information for a particular card
|
/// Styling information for a particular card
|
||||||
IndexMap<FieldP, ValueP>& stylingDataFor(const CardP& card);
|
IndexMap<FieldP, ValueP>& stylingDataFor(const CardP& card);
|
||||||
|
|
||||||
|
/// Make sure the image and symbol files from
|
||||||
|
/// the ActionStack are saved so we can undo
|
||||||
|
void referenceActionStackFiles();
|
||||||
|
void referenceActionStackFiles(bool undo);
|
||||||
|
|
||||||
/// Get the identification of this set, an identification is something like a name, title, etc.
|
/// Get the identification of this set, an identification is something like a name, title, etc.
|
||||||
/** May return "" */
|
/** May return "" */
|
||||||
String identification() const;
|
String identification() const;
|
||||||
|
|||||||
@@ -103,11 +103,12 @@ public:
|
|||||||
/// Tell all listeners about an action
|
/// Tell all listeners about an action
|
||||||
void tellListeners(const Action&, bool undone);
|
void tellListeners(const Action&, bool undone);
|
||||||
|
|
||||||
private:
|
|
||||||
/// Actions to be undone.
|
/// Actions to be undone.
|
||||||
vector<unique_ptr<Action>> undo_actions;
|
vector<unique_ptr<Action>> undo_actions;
|
||||||
/// Actions to be redone
|
/// Actions to be redone
|
||||||
vector<unique_ptr<Action>> redo_actions;
|
vector<unique_ptr<Action>> redo_actions;
|
||||||
|
|
||||||
|
private:
|
||||||
/// Point at which the file was saved, corresponds to the top of the undo stack at that point
|
/// Point at which the file was saved, corresponds to the top of the undo stack at that point
|
||||||
const Action* save_point;
|
const Action* save_point;
|
||||||
/// Was the last thing the user did addAction? (as opposed to undo/redo)
|
/// Was the last thing the user did addAction? (as opposed to undo/redo)
|
||||||
|
|||||||
+6
-4
@@ -110,10 +110,12 @@ String Error::what() const {
|
|||||||
|
|
||||||
InternalError::InternalError(const String& str)
|
InternalError::InternalError(const String& str)
|
||||||
: Error(
|
: Error(
|
||||||
_("An internal error occured:\n\n") +
|
_("An internal error occurred:\n\n") +
|
||||||
str + _("\n")
|
str + _("\n\n")
|
||||||
_("Please save your work (use 'save as' to so you don't overwrite things)\n")
|
_("Please save your work (use 'save as' so you don't overwrite things)\n")
|
||||||
_("and restart Magic Set Editor.\n\n")
|
_("and restart Magic Set Editor.\n")
|
||||||
|
_("You can also find a backup of your set in the same folder as your set file\n")
|
||||||
|
_("called 'SETNAME.mse-set.bak'. Rename it to 'SETNAME-backup.mse-set' to open it.\n")
|
||||||
_("You should leave a bug report on https://github.com/twanvl/MagicSetEditor2/issues/\n")
|
_("You should leave a bug report on https://github.com/twanvl/MagicSetEditor2/issues/\n")
|
||||||
_("Press Ctrl+C to copy this message to the clipboard.")
|
_("Press Ctrl+C to copy this message to the clipboard.")
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <util/error.hpp>
|
#include <util/error.hpp>
|
||||||
#include <script/to_value.hpp> // for reflection
|
#include <script/to_value.hpp> // for reflection
|
||||||
#include <script/profiler.hpp> // for PROFILER
|
#include <script/profiler.hpp> // for PROFILER
|
||||||
|
#include <data/set.hpp>
|
||||||
#include <wx/wfstream.h>
|
#include <wx/wfstream.h>
|
||||||
#include <wx/zipstrm.h>
|
#include <wx/zipstrm.h>
|
||||||
#include <wx/dir.h>
|
#include <wx/dir.h>
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
// ----------------------------------------------------------------------------- : Package : outside
|
// ----------------------------------------------------------------------------- : Package : outside
|
||||||
|
|
||||||
IMPLEMENT_DYNAMIC_ARG(Package*, writing_package, nullptr);
|
IMPLEMENT_DYNAMIC_ARG(Package*, writing_package, nullptr);
|
||||||
IMPLEMENT_DYNAMIC_ARG(Package*, clipboard_package, nullptr);
|
IMPLEMENT_DYNAMIC_ARG(Package*, clipboard_package, nullptr);
|
||||||
|
|
||||||
Package::Package()
|
Package::Package()
|
||||||
: zipStream (nullptr)
|
: zipStream (nullptr)
|
||||||
@@ -97,7 +98,8 @@ void Package::save(bool remove_unused) {
|
|||||||
saveAs(filename, remove_unused);
|
saveAs(filename, remove_unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::saveAs(const String& name, bool remove_unused, bool as_directory) {
|
void Package::saveAs(const String& name, bool remove_unused, bool as_directory) {
|
||||||
|
if (Set* s = dynamic_cast<Set*>(this)) s->referenceActionStackFiles();
|
||||||
// type of package
|
// type of package
|
||||||
if (wxDirExists(name) || as_directory) {
|
if (wxDirExists(name) || as_directory) {
|
||||||
saveToDirectory(name, remove_unused, false);
|
saveToDirectory(name, remove_unused, false);
|
||||||
@@ -109,7 +111,8 @@ void Package::saveAs(const String& name, bool remove_unused, bool as_directory)
|
|||||||
reopen();
|
reopen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Package::saveCopy(const String& name) {
|
void Package::saveCopy(const String& name) {
|
||||||
|
if (Set* s = dynamic_cast<Set*>(this)) s->referenceActionStackFiles();
|
||||||
saveToZipfile(name, true, true);
|
saveToZipfile(name, true, true);
|
||||||
clearKeepFlag();
|
clearKeepFlag();
|
||||||
}
|
}
|
||||||
@@ -298,7 +301,7 @@ LocalFileName Package::newFileName(const String& prefix, const String& suffix) {
|
|||||||
void Package::referenceFile(const String& file) {
|
void Package::referenceFile(const String& file) {
|
||||||
if (file.empty()) return;
|
if (file.empty()) return;
|
||||||
FileInfos::iterator it = files.find(file);
|
FileInfos::iterator it = files.find(file);
|
||||||
if (it == files.end()) throw InternalError(_("referencing a nonexistant file"));
|
if (it == files.end()) throw InternalError(_("Referencing an inexistant file!"));
|
||||||
it->second.keep = true;
|
it->second.keep = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user