diff --git a/CMakeLists.txt b/CMakeLists.txt index 36183216..66a258d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.13) project(magicseteditor) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) find_package(wxWidgets 3 REQUIRED COMPONENTS core base net html) diff --git a/src/data/action/symbol_part.cpp b/src/data/action/symbol_part.cpp index 85f1d4b4..2ad832df 100644 --- a/src/data/action/symbol_part.cpp +++ b/src/data/action/symbol_part.cpp @@ -97,6 +97,7 @@ ControlPointMoveAction::ControlPointMoveAction(const set& points) FOR_EACH(p, points) { oldValues.push_back(p->pos); } + perform(false); } String ControlPointMoveAction::getName(bool to_undo) const { @@ -104,12 +105,15 @@ String ControlPointMoveAction::getName(bool to_undo) const { } void ControlPointMoveAction::perform(bool to_undo) { + if (to_undo != done) return; + done = !to_undo; FOR_EACH_2(p,points, op,oldValues) { swap(p->pos, op); } } -void ControlPointMoveAction::move (const Vector2D& deltaDelta) { +void ControlPointMoveAction::move(const Vector2D& deltaDelta) { + assert(done); delta += deltaDelta; // Move each point by delta, possibly constrained set::const_iterator it = points.begin(); @@ -128,18 +132,23 @@ HandleMoveAction::HandleMoveAction(const SelectedHandle& handle) , old_other (handle.getOther()) , constrain(false) , snap(0) -{} +{ + perform(false); +} String HandleMoveAction::getName(bool to_undo) const { return _ACTION_("move handle"); } void HandleMoveAction::perform(bool to_undo) { + if (to_undo != done) return; + done = !to_undo; swap(old_handle, handle.getHandle()); swap(old_other, handle.getOther()); } void HandleMoveAction::move(const Vector2D& deltaDelta) { + assert(done); delta += deltaDelta; handle.getHandle() = constrain_snap_vector_offset(handle.point->pos, old_handle + delta, constrain, snap); handle.getOther() = old_other; @@ -246,7 +255,7 @@ void CurveDragAction::move(const Vector2D& delta, double t) { ControlPointAddAction::ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t) : shape(shape) - , new_point(new ControlPoint()) + , new_point(make_shared()) , insert_after(insert_after) , point1(shape->getPoint(insert_after)) , point2(shape->getPoint(insert_after + 1)) @@ -419,13 +428,13 @@ void ControlPointRemoveAction::perform(bool to_undo) { } -Action* control_point_remove_action(const SymbolShapeP& shape, const set& to_delete) { +unique_ptr control_point_remove_action(const SymbolShapeP& shape, const set& to_delete) { if (shape->points.size() - to_delete.size() < 2) { // TODO : remove part? //make_intrusive(part); - return 0; // no action + return unique_ptr(); // no action } else { - return new ControlPointRemoveAction(shape, to_delete); + return make_unique(shape, to_delete); } } diff --git a/src/data/action/symbol_part.hpp b/src/data/action/symbol_part.hpp index 632b1acd..d59e752b 100644 --- a/src/data/action/symbol_part.hpp +++ b/src/data/action/symbol_part.hpp @@ -40,10 +40,18 @@ Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& d, b /** Takes the closest snap */ Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& off2, const Vector2D& d, bool constrain, int steps); +// ----------------------------------------------------------------------------- : Base class + +/// An action that by itself doesn't do anything, but can later be extended after it is performed +class ExtendableAction : public Action { +protected: + bool done = false; +}; + // ----------------------------------------------------------------------------- : Move control point /// Moving a control point in a symbol -class ControlPointMoveAction : public Action { +class ControlPointMoveAction : public ExtendableAction { public: ControlPointMoveAction(const set& points); @@ -65,7 +73,7 @@ class ControlPointMoveAction : public Action { // ----------------------------------------------------------------------------- : Move handle /// Moving a handle(before/after) of a control point in a symbol -class HandleMoveAction : public Action { +class HandleMoveAction : public ExtendableAction { public: HandleMoveAction(const SelectedHandle& handle); @@ -169,7 +177,7 @@ class ControlPointAddAction : public Action { /// Action that removes any number of points from a symbol shape /// TODO: If less then 3 points are left removes the entire shape? -Action* control_point_remove_action(const SymbolShapeP& shape, const set& to_delete); +unique_ptr control_point_remove_action(const SymbolShapeP& shape, const set& to_delete); diff --git a/src/data/action/value.cpp b/src/data/action/value.cpp index 75303d50..e1c60a2f 100644 --- a/src/data/action/value.cpp +++ b/src/data/action/value.cpp @@ -81,14 +81,24 @@ class SimpleValueAction : public ValueAction { typename T::ValueType new_value; }; -ValueAction* value_action(const ChoiceValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value); } -ValueAction* value_action(const ColorValueP& value, const Defaultable& new_value) { return new SimpleValueAction (value, new_value); } -ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction(value, new_value); } -ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction(value, new_value); } -ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction(value, new_value); } -ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change) { +unique_ptr value_action(const ChoiceValueP& value, const Defaultable& new_value) { + return make_unique>(value, new_value); +} +unique_ptr value_action(const ColorValueP& value, const Defaultable& new_value) { + return make_unique>(value, new_value); +} +unique_ptr value_action(const ImageValueP& value, const FileName& new_value) { + return make_unique>(value, new_value); +} +unique_ptr value_action(const SymbolValueP& value, const FileName& new_value) { + return make_unique>(value, new_value); +} +unique_ptr value_action(const PackageChoiceValueP& value, const String& new_value) { + return make_unique>(value, new_value); +} +unique_ptr value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change) { MultipleChoiceValue::ValueType v = { new_value, last_change }; - return new SimpleValueAction(value, v); + return make_unique>(value, v); } @@ -133,7 +143,7 @@ TextValue& TextValueAction::value() const { } -TextValueAction* toggle_format_action(const TextValueP& value, const String& tag, size_t start_i, size_t end_i, size_t start, size_t end, const String& action_name) { +unique_ptr toggle_format_action(const TextValueP& value, const String& tag, size_t start_i, size_t end_i, size_t start, size_t end, const String& action_name) { if (start > end) { swap(start, end); swap(start_i, end_i); @@ -165,11 +175,11 @@ TextValueAction* toggle_format_action(const TextValueP& value, const String& tag if (value->value() == new_value) { return nullptr; // no changes } else { - return new TextValueAction(value, start, end, end, new_value, action_name); + return make_unique(value, start, end, end, new_value, action_name); } } -TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t end_i, size_t start, size_t end, const String& replacement, const String& action_name) { +unique_ptr typing_action(const TextValueP& value, size_t start_i, size_t end_i, size_t start, size_t end, const String& replacement, const String& action_name) { bool reverse = start > end; if (reverse) { swap(start, end); @@ -181,9 +191,9 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e return nullptr; } else { if (reverse) { - return new TextValueAction(value, end, start, start+untag(replacement).size(), new_value, action_name); + return make_unique(value, end, start, start+untag(replacement).size(), new_value, action_name); } else { - return new TextValueAction(value, start, end, start+untag(replacement).size(), new_value, action_name); + return make_unique(value, start, end, start+untag(replacement).size(), new_value, action_name); } } } @@ -248,9 +258,9 @@ ValueActionPerformer::ValueActionPerformer(const ValueP& value, Card* card, cons {} ValueActionPerformer::~ValueActionPerformer() {} -void ValueActionPerformer::addAction(ValueAction* action) { +void ValueActionPerformer::addAction(unique_ptr&& action) { action->isOnCard(card); - set->actions.addAction(action); + set->actions.addAction(move(action)); } Package& ValueActionPerformer::getLocalPackage() { diff --git a/src/data/action/value.hpp b/src/data/action/value.hpp index 3dae9609..85099eef 100644 --- a/src/data/action/value.hpp +++ b/src/data/action/value.hpp @@ -55,12 +55,12 @@ class ValueAction : public Action { // ----------------------------------------------------------------------------- : Simple /// Action that updates a Value to a new value -ValueAction* value_action(const ChoiceValueP& value, const Defaultable& new_value); -ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change); -ValueAction* value_action(const ColorValueP& value, const Defaultable& new_value); -ValueAction* value_action(const ImageValueP& value, const FileName& new_value); -ValueAction* value_action(const SymbolValueP& value, const FileName& new_value); -ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value); +unique_ptr value_action(const ChoiceValueP& value, const Defaultable& new_value); +unique_ptr value_action(const MultipleChoiceValueP& value, const Defaultable& new_value, const String& last_change); +unique_ptr value_action(const ColorValueP& value, const Defaultable& new_value); +unique_ptr value_action(const ImageValueP& value, const FileName& new_value); +unique_ptr value_action(const SymbolValueP& value, const FileName& new_value); +unique_ptr value_action(const PackageChoiceValueP& value, const String& new_value); // ----------------------------------------------------------------------------- : Text @@ -86,11 +86,11 @@ class TextValueAction : public ValueAction { }; /// Action for toggling some formating tag on or off in some range -TextValueAction* toggle_format_action(const TextValueP& value, const String& tag, size_t start_i, size_t end_i, size_t start, size_t end, const String& action_name); +unique_ptr toggle_format_action(const TextValueP& value, const String& tag, size_t start_i, size_t end_i, size_t start, size_t end, const String& action_name); /// Typing in a TextValue, replace the selection [start...end) with replacement /** start and end are cursor positions, start_i and end_i are indices*/ -TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t end_i, size_t start, size_t end, const String& replacement, const String& action_name); +unique_ptr typing_action(const TextValueP& value, size_t start_i, size_t end_i, size_t start, size_t end, const String& replacement, const String& action_name); // ----------------------------------------------------------------------------- : Reminder text @@ -169,7 +169,7 @@ class ValueActionPerformer { ValueActionPerformer(const ValueP& value, Card* card, const SetP& set); ~ValueActionPerformer(); /// Perform an action. The performer takes ownerwhip of the action. - void addAction(ValueAction* action); + void addAction(unique_ptr&& action); const ValueP value; ///< The value Package& getLocalPackage(); diff --git a/src/data/add_cards_script.cpp b/src/data/add_cards_script.cpp index 9099d833..3c026905 100644 --- a/src/data/add_cards_script.cpp +++ b/src/data/add_cards_script.cpp @@ -47,6 +47,6 @@ void AddCardsScript::perform(Set& set) { // Add to set if (!cards.empty()) { // TODO: change the name of the action somehow - set.actions.addAction(new AddCardAction(ADD, set, cards)); + set.actions.addAction(make_unique(ADD, set, cards)); } } diff --git a/src/data/field.hpp b/src/data/field.hpp index e77255ad..3d116006 100644 --- a/src/data/field.hpp +++ b/src/data/field.hpp @@ -284,11 +284,11 @@ inline String type_name(const Value&) { return _(NAME); \ } -#define DECLARE_STYLE_TYPE(Type) \ - DECLARE_REFLECTION(); public: \ - DECLARE_HAS_FIELD(Type) \ - virtual StyleP clone() const; \ - virtual ValueViewerP makeViewer(DataViewer& parent, const StyleP& thisP); \ +#define DECLARE_STYLE_TYPE(Type) \ + DECLARE_REFLECTION(); public: \ + DECLARE_HAS_FIELD(Type) \ + virtual StyleP clone() const; \ + virtual ValueViewerP makeViewer(DataViewer& parent, const StyleP& thisP); \ virtual ValueViewerP makeEditor(DataEditor& parent, const StyleP& thisP) #define DECLARE_VALUE_TYPE(Type,ValueType_) \ diff --git a/src/data/field/choice.cpp b/src/data/field/choice.cpp index 12ee814f..b9a52955 100644 --- a/src/data/field/choice.cpp +++ b/src/data/field/choice.cpp @@ -190,7 +190,7 @@ void ChoiceStyle::initImage() { // CALL 0 // PUSH_CONST nil // OR_ELSE - ScriptCustomCollectionP lookup(new ScriptCustomCollection()); + ScriptCustomCollectionP lookup = make_intrusive(); FOR_EACH(ci, choice_images) { lookup->key_value[uncanonical_name_form(ci.first)] = lookup->key_value[ci.first] = ci.second.getValidScriptP(); diff --git a/src/data/format/apprentice.cpp b/src/data/format/apprentice.cpp index cb3962c3..9e5c2ee1 100644 --- a/src/data/format/apprentice.cpp +++ b/src/data/format/apprentice.cpp @@ -301,7 +301,7 @@ void ApprDistroDatabase::removeSet(const String& code) { // TODO ? } -void ApprDistroDatabase::doRead(InputStream& in) { +void ApprDistroDatabase::doRead(wxInputStream& in) { wxTextInputStream tin(in); ApprDistro* last = 0; while (!in.Eof()) { diff --git a/src/data/format/clipboard.cpp b/src/data/format/clipboard.cpp index 141b6a10..2bf56c97 100644 --- a/src/data/format/clipboard.cpp +++ b/src/data/format/clipboard.cpp @@ -23,16 +23,16 @@ /// Serialize an object to a string, clipboard_package will be set to the given package. template String serialize_for_clipboard(Package& package, T& object) { - shared_ptr stream( new wxStringOutputStream ); + wxStringOutputStream stream; Writer writer(stream, file_version_clipboard); WITH_DYNAMIC_ARG(clipboard_package, &package); writer.handle(object); - return stream->GetString(); + return stream.GetString(); } template void deserialize_from_clipboard(T& object, Package& package, const String& data) { - shared_ptr stream( new wxStringInputStream(data) ); + wxStringInputStream stream = {data}; Reader reader(stream, nullptr, _("clipboard")); WITH_DYNAMIC_ARG(clipboard_package, &package); reader.handle_greedy(object); diff --git a/src/data/installer.cpp b/src/data/installer.cpp index 536304fd..587b3684 100644 --- a/src/data/installer.cpp +++ b/src/data/installer.cpp @@ -21,14 +21,6 @@ #include #include -DECLARE_TYPEOF_COLLECTION(String); -DECLARE_TYPEOF_COLLECTION(PackagedP); -DECLARE_TYPEOF_COLLECTION(PackageDependencyP); -DECLARE_TYPEOF_COLLECTION(PackageDescriptionP); -DECLARE_TYPEOF_COLLECTION(InstallablePackageP); -DECLARE_POINTER_TYPE(wxFileInputStream); -DECLARE_POINTER_TYPE(wxZipInputStream); - // Don't do this check for now, because we can't bless packages #define USE_MODIFIED_CHECK 0 @@ -50,8 +42,8 @@ void Installer::validate(Version file_app_version) { // TODO: support absolute icon names try{ String filename = p->name + _("/") + p->icon_url; - InputStreamP img = openIn(p->name + _("/") + p->icon_url); - image_load_file(p->icon, *img); + auto img_stream = openIn(p->name + _("/") + p->icon_url); + image_load_file(p->icon, *img_stream); } catch (...) { // ignore errors, it's just an image p->icon_url.clear(); @@ -195,9 +187,9 @@ void Installer::addPackage(Packaged& package) { const FileInfos& file_infos = package.getFileInfos(); for (FileInfos::const_iterator it = file_infos.begin() ; it != file_infos.end() ; ++it) { String file = it->first; - InputStreamP is = package.openIn(file); - OutputStreamP os = openOut(name + _("/") + file); - os->Write(*is); + auto in_stream = package.openIn(file); + auto out_stream = openOut(name + _("/") + file); + out_stream->Write(*in_stream); } } @@ -235,8 +227,8 @@ PackageDescription::PackageDescription(const Packaged& package) } } // icon - InputStreamP file = const_cast(package).openIconFile(); - if (file) image_load_file(icon, *file); + auto file_stream = const_cast(package).openIconFile(); + if (file_stream) image_load_file(icon, *file_stream); } IMPLEMENT_REFLECTION_NO_SCRIPT(PackageDescription) { diff --git a/src/data/keyword.cpp b/src/data/keyword.cpp index 8b9324b4..01f539eb 100644 --- a/src/data/keyword.cpp +++ b/src/data/keyword.cpp @@ -256,13 +256,13 @@ class KeywordTrie { KeywordTrie(); ~KeywordTrie(); - map children; ///< children after a given character (owned) - KeywordTrie* on_any_star; ///< children on /.*/ (owned or this) - vector finished; ///< keywordss that end in this node + map> children; ///< children after a given character + KeywordTrie* on_any_star; ///< children on /.*/ (owned or this) + vector finished; ///< keywords that end in this node /// Insert nodes representing the given character /** return the node where the evaluation will be after matching the character */ - KeywordTrie* insert(Char match); + KeywordTrie* insert(wxUniChar match); /// Insert nodes representing the given string /** return the node where the evaluation will be after matching the string */ KeywordTrie* insert(const String& match); @@ -276,32 +276,28 @@ class KeywordTrie { KeywordTrie::KeywordTrie() : on_any_star(nullptr) {} - KeywordTrie::~KeywordTrie() { - FOR_EACH(c, children) { - delete c.second; - } if (on_any_star != this) delete on_any_star; } -KeywordTrie* KeywordTrie::insert(Char c) { +KeywordTrie* KeywordTrie::insert(wxUniChar c) { #if USE_CASE_INSENSITIVE_KEYWORDS c = toLower(c); // case insensitive matching #endif - KeywordTrie*& child = children[c]; - if (!child) child = new KeywordTrie; - return child; + unique_ptr& child = children[c]; + if (!child) child.reset(new KeywordTrie); + return child.get(); } KeywordTrie* KeywordTrie::insert(const String& match) { KeywordTrie* cur = this; - FOR_EACH_CONST(c, match) { - cur = cur->insert(static_cast(c)); + for (wxUniChar c : match) { + cur = cur->insert(c); } return cur; } KeywordTrie* KeywordTrie::insertAnyStar() { - if (!on_any_star) on_any_star = new KeywordTrie; + if (!on_any_star) on_any_star = new KeywordTrie(); on_any_star->on_any_star = on_any_star; // circular reference to itself return on_any_star; } @@ -314,14 +310,11 @@ IMPLEMENT_DYNAMIC_ARG(KeywordUsageStatistics*, keyword_usage_statistics, nullptr KeywordDatabase::KeywordDatabase() : root(nullptr) {} - -KeywordDatabase::~KeywordDatabase() { - clear(); -} +// Note: has to be here because in the header KeywordTrie is not defined +KeywordDatabase::~KeywordDatabase() {} void KeywordDatabase::clear() { - delete root; - root = nullptr; + root.reset(); } void KeywordDatabase::add(const vector& kws) { @@ -334,8 +327,8 @@ void KeywordDatabase::add(const Keyword& kw) { if (kw.match.empty() || !kw.valid) return; // can't handle empty keywords // Create root if (!root) { - root = new KeywordTrie; - root->on_any_star = root; + root = make_unique(); + root->on_any_star = root.get(); } KeywordTrie* cur = root->insertAnyStar(); // Add to trie @@ -384,7 +377,7 @@ void KeywordDatabase::prepare_parameters(const vector& ps, const // ----------------------------------------------------------------------------- : KeywordDatabase : matching // transitive closure of a state, follow all on_any_star links -void closure(vector& state) { +void closure(vector& state) { for (size_t j = 0 ; j < state.size() ; ++j) { if (state[j]->on_any_star && state[j]->on_any_star != state[j]) { state.push_back(state[j]->on_any_star); @@ -393,10 +386,10 @@ void closure(vector& state) { } #ifdef _DEBUG -void dump(int i, KeywordTrie* t) { +void dump(int i, const KeywordTrie* t) { FOR_EACH(c, t->children) { - wxLogDebug(String(i,_(' ')) + c.first + _(" ") + String::Format(_("%p"),c.second)); - dump(i+2, c.second); + wxLogDebug(String(i,_(' ')) + c.first + _(" ") + String::Format(_("%p"),c.second.get())); + dump(i+2, c.second.get()); } if (t->on_any_star) { wxLogDebug(String(i,_(' ')) + _(".*") + _(" ") + String::Format(_("%p"),t->on_any_star)); @@ -438,10 +431,10 @@ String KeywordDatabase::expand(const String& text, // Find keywords while (!tagged.empty()) { - vector current; // current location(s) in the trie - vector next; // location(s) after this step - set used; // keywords already investigated - current.push_back(root); + vector current; // current location(s) in the trie + vector next; // location(s) after this step + set used; // keywords already investigated + current.push_back(root.get()); closure(current); // is the keyword expanded? From tag // Possible values are: @@ -453,7 +446,7 @@ String KeywordDatabase::expand(const String& text, char expand_type = default_expand_type; for (size_t i = 0 ; i < tagged.size() ;) { - Char c = tagged.GetChar(i); + wxUniChar c = tagged.GetChar(i); // tag? if (c == _('<')) { if (is_substr(tagged, i, _("::const_iterator it = kt->children.find(c); + auto it = kt->children.find(c); if (it != kt->children.end()) { - next.push_back(it->second); + next.push_back(it->second.get()); } // TODO: on any star first or last? if (kt->on_any_star) { diff --git a/src/data/keyword.hpp b/src/data/keyword.hpp index 9ea82131..c254a7d3 100644 --- a/src/data/keyword.hpp +++ b/src/data/keyword.hpp @@ -140,7 +140,7 @@ DECLARE_DYNAMIC_ARG(KeywordUsageStatistics*, keyword_usage_statistics); * The database should be rebuild. */ class KeywordDatabase { - public: +public: KeywordDatabase(); ~KeywordDatabase(); @@ -165,8 +165,8 @@ class KeywordDatabase { */ String expand(const String& text, const ScriptValueP& match_condition, const ScriptValueP& expand_default, const ScriptValueP& combine_script, Context& ctx) const; - private: - KeywordTrie* root; ///< Data structure for finding keywords +private: + unique_ptr root; ///< Data structure for finding keywords /// (try to) expand a single keyword /** If the keyword matches: diff --git a/src/data/set.cpp b/src/data/set.cpp index 9baa8903..4d711954 100644 --- a/src/data/set.cpp +++ b/src/data/set.cpp @@ -223,7 +223,8 @@ void Set::reflect_cards (Writer& tag) { // writeFile won't quite work because we'd need // include file: card: filename // to do that - Writer writer(openOut(full_name), app_version); + auto stream = openOut(full_name); + Writer writer(*stream, app_version); writer.handle(_("card"), card); referenceFile(full_name); REFLECT_N("include_file", full_name); diff --git a/src/data/settings.cpp b/src/data/settings.cpp index 89f46f32..02f327e0 100644 --- a/src/data/settings.cpp +++ b/src/data/settings.cpp @@ -295,14 +295,15 @@ void Settings::read() { String filename = settingsFile(); if (wxFileExists(filename)) { // settings file not existing is not an error - shared_ptr file = make_shared(filename); - if (!file->Ok()) return; // failure is not an error + wxFileInputStream file(filename); + if (!file.Ok()) return; // failure is not an error Reader reader(file, nullptr, filename); reader.handle_greedy(*this); } } void Settings::write() { - Writer writer(make_shared(settingsFile()), app_version); + wxFileOutputStream file(settingsFile()); + Writer writer(file, app_version); writer.handle(*this); } diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index a1ab0226..d03a4a1b 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -321,8 +321,8 @@ bool CropImage::operator == (const GeneratedImage& that) const { /** out is scaled some scaling, this is the return value */ UInt gaussian_blur(Byte* in, UInt* out, int w, int h, double radius) { // blur horizontally - UInt* blur_x = new UInt[w*h]; // scaled by total_x, so in [0..255*total_x] - memset(blur_x, 0, w*h*sizeof(UInt)); + auto blur_x = make_unique(w*h); // scaled by total_x, so in [0..255*total_x] + memset(blur_x.get(), 0, w*h*sizeof(UInt)); UInt total_x = 0; { double sigma = radius * w; @@ -363,7 +363,6 @@ UInt gaussian_blur(Byte* in, UInt* out, int w, int h, double radius) { } } } - delete[] blur_x; return total_x * total_y; } @@ -377,8 +376,8 @@ Image DropShadowImage::generate(const Options& opt) const { int w = img.GetWidth(), h = img.GetHeight(); Byte* alpha = img.GetAlpha(); // blur - UInt* shadow = new UInt[w*h]; - UInt total = 255 * gaussian_blur(alpha, shadow, w, h, shadow_blur_radius); + auto shadow = make_unique(w*h); + UInt total = 255 * gaussian_blur(alpha, shadow.get(), w, h, shadow_blur_radius); // combine Byte* data = img.GetData(); int dw = int(w * offset_x), dh = int(h * offset_y); @@ -398,9 +397,6 @@ Image DropShadowImage::generate(const Options& opt) const { alpha[p] = a + shad; } } - //memset(data,0,3*w*h); - // cleanup - delete[] shadow; return img; } bool DropShadowImage::operator == (const GeneratedImage& that) const { @@ -417,9 +413,9 @@ Image PackagedImage::generate(const Options& opt) const { // TODO : use opt.width and opt.height? // open file from package if (!opt.package) throw ScriptError(_("Can only load images in a context where an image is expected")); - InputStreamP file = opt.package->openIn(filename); + auto file_stream = opt.package->openIn(filename); Image img; - if (image_load_file(img, *file)) { + if (image_load_file(img, *file_stream)) { if (img.HasMask()) img.InitAlpha(); // we can't handle masks return img; } else { @@ -494,8 +490,8 @@ Image ImageValueToImage::generate(const Options& opt) const { if (!opt.local_package) throw ScriptError(_("Can only load images in a context where an image is expected")); Image image; if (!filename.empty()) { - InputStreamP image_file = opt.local_package->openIn(filename); - image_load_file(image, *image_file); + auto image_file_stream = opt.local_package->openIn(filename); + image_load_file(image, *image_file_stream); } if (!image.Ok()) { image = Image(max(1,opt.width), max(1,opt.height)); diff --git a/src/gui/control/card_editor.cpp b/src/gui/control/card_editor.cpp index 9fddae44..26d93e4e 100644 --- a/src/gui/control/card_editor.cpp +++ b/src/gui/control/card_editor.cpp @@ -58,8 +58,8 @@ bool DataEditor::viewerIsCurrent(const ValueViewer* viewer) const { } -void DataEditor::addAction(Action* action) { - set->actions.addAction(action); +void DataEditor::addAction(unique_ptr action) { + set->actions.addAction(move(action)); } // ----------------------------------------------------------------------------- : Selection diff --git a/src/gui/control/card_editor.hpp b/src/gui/control/card_editor.hpp index 92f29820..7441d6ab 100644 --- a/src/gui/control/card_editor.hpp +++ b/src/gui/control/card_editor.hpp @@ -27,7 +27,7 @@ class DataEditor : public CardViewer { virtual DrawWhat drawWhat(const ValueViewer*) const; virtual bool viewerIsCurrent(const ValueViewer*) const; - virtual void addAction(Action* action); + virtual void addAction(unique_ptr action); inline SetP getSetForActions() { return set; } // --------------------------------------------------- : Selection diff --git a/src/gui/control/card_list.cpp b/src/gui/control/card_list.cpp index cfb8edf3..6e66296b 100644 --- a/src/gui/control/card_list.cpp +++ b/src/gui/control/card_list.cpp @@ -179,7 +179,7 @@ bool CardListBase::doPaste() { ok = data.getCards(set, new_cards); if (!ok) return false; // add card to set - set->actions.addAction(new AddCardAction(ADD, *set, new_cards)); + set->actions.addAction(make_unique(ADD, *set, new_cards)); return true; } bool CardListBase::doDelete() { @@ -188,7 +188,7 @@ bool CardListBase::doDelete() { getSelection(cards_to_delete); if (cards_to_delete.empty()) return false; // delete cards - set->actions.addAction(new AddCardAction(REMOVE, *set, cards_to_delete)); + set->actions.addAction(make_unique(REMOVE, *set, cards_to_delete)); return true; } @@ -378,7 +378,7 @@ void CardListBase::onDrag(wxMouseEvent& ev) { findSelectedItemPos(); if (item != selected_item_pos) { // move card in the set - set->actions.addAction(new ReorderCardsAction(*set, item, selected_item_pos)); + set->actions.addAction(make_unique(*set, item, selected_item_pos)); } ev.Skip(false); } diff --git a/src/gui/control/keyword_list.cpp b/src/gui/control/keyword_list.cpp index 01c19c14..b8befe56 100644 --- a/src/gui/control/keyword_list.cpp +++ b/src/gui/control/keyword_list.cpp @@ -132,14 +132,14 @@ bool KeywordList::doPaste() { // add keyword to set KeywordP keyword = data.getKeyword(set); if (keyword) { - set->actions.addAction(new AddKeywordAction(ADD, *set, keyword)); + set->actions.addAction(make_unique(ADD, *set, keyword)); return true; } else { return false; } } bool KeywordList::doDelete() { - set->actions.addAction(new AddKeywordAction(REMOVE, *set, getKeyword())); + set->actions.addAction(make_unique(REMOVE, *set, getKeyword())); return true; } diff --git a/src/gui/control/package_list.cpp b/src/gui/control/package_list.cpp index 34abb10b..0fae34a4 100644 --- a/src/gui/control/package_list.cpp +++ b/src/gui/control/package_list.cpp @@ -73,7 +73,7 @@ void PackageList::showData(const String& pattern) { FOR_EACH(p, matching) { // open image PROFILER(_("load package image")); - InputStreamP stream = p->openIconFile(); + auto stream = p->openIconFile(); Image img; Bitmap bmp; if (stream && image_load_file(img, *stream)) { diff --git a/src/gui/packages_window.cpp b/src/gui/packages_window.cpp index 8121af90..7cec19eb 100644 --- a/src/gui/packages_window.cpp +++ b/src/gui/packages_window.cpp @@ -82,15 +82,14 @@ bool DownloadableInstallerList::download() { wxThread::ExitCode DownloadableInstallerList::Thread::Entry() { // open url wxURL url(settings.installer_list_url); - wxInputStream* isP = url.GetInputStream(); - if (!isP) { + unique_ptr stream(url.GetInputStream()); + if (!stream) { wxMutexLocker l(downloadable_installers.lock); downloadable_installers.status = DONE; return 0; } - InputStreamP is(isP); // Read installer list - Reader reader(is, nullptr, _("installers"), true); + Reader reader(*stream, nullptr, _("installers"), true); vector installers; reader.handle(_("installers"),installers); // done @@ -344,7 +343,7 @@ void PackagesWindow::onOk(wxCommandEvent& ev) { } // download installer wxURL url(ip->installer->installer_url); - wxInputStream* is = url.GetInputStream(); + unique_ptr is(url.GetInputStream()); if (!is) { throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url)); } diff --git a/src/gui/set/cards_panel.cpp b/src/gui/set/cards_panel.cpp index f58338c3..a4c448db 100644 --- a/src/gui/set/cards_panel.cpp +++ b/src/gui/set/cards_panel.cpp @@ -325,7 +325,7 @@ void CardsPanel::onCommand(int id) { if (card_list->canSelectNext()) card_list->selectNext(); break; case ID_CARD_ADD: - set->actions.addAction(new AddCardAction(*set)); + set->actions.addAction(make_unique(*set)); break; case ID_CARD_REMOVE: card_list->doDelete(); diff --git a/src/gui/set/keywords_panel.cpp b/src/gui/set/keywords_panel.cpp index 1ecccd9d..8e2ce14e 100644 --- a/src/gui/set/keywords_panel.cpp +++ b/src/gui/set/keywords_panel.cpp @@ -180,7 +180,7 @@ void KeywordsPanel::onCommand(int id) { list->selectNext(); break; case ID_KEYWORD_ADD: - set->actions.addAction(new AddKeywordAction(*set)); + set->actions.addAction(make_unique(*set)); break; case ID_KEYWORD_REMOVE: if (list->canDelete()) { @@ -370,7 +370,7 @@ void KeywordsPanel::onModeChange(wxCommandEvent& ev) { if (!list->getKeyword()) return; int sel = mode->GetSelection(); if (sel >= 0 && (size_t)sel < set->game->keyword_modes.size()) { - set->actions.addAction(new ChangeKeywordModeAction(*list->getKeyword(), set->game->keyword_modes[sel]->name)); + set->actions.addAction(make_unique(*list->getKeyword(), set->game->keyword_modes[sel]->name)); } } diff --git a/src/gui/set/random_pack_panel.cpp b/src/gui/set/random_pack_panel.cpp index 5288797d..22e5565d 100644 --- a/src/gui/set/random_pack_panel.cpp +++ b/src/gui/set/random_pack_panel.cpp @@ -528,7 +528,7 @@ void RandomPackPanel::onCommand(int id) { case ID_CUSTOM_PACK: { CustomPackDialog dlg(this, set, PackTypeP(), false); if (dlg.ShowModal() == wxID_OK) { - set->actions.addAction( new AddPackAction(ADD,*set,dlg.get()) ); + set->actions.addAction(make_unique(ADD,*set,dlg.get())); } break; } @@ -544,12 +544,12 @@ void RandomPackPanel::onPackTypeClick(wxCommandEvent& ev) { // update pack for (size_t i = 0 ; i < set->pack_types.size() ; ++i) { if (set->pack_types[i] == pick.pack) { - set->actions.addAction( new ChangePackAction(*set,i,dlg.get()) ); + set->actions.addAction(make_unique(*set,i,dlg.get())); } } } else { // delete pack - set->actions.addAction( new AddPackAction(REMOVE,*set,pick.pack) ); + set->actions.addAction(make_unique(REMOVE,*set,pick.pack)); } } break; diff --git a/src/gui/set/stats_panel.cpp b/src/gui/set/stats_panel.cpp index 9152a89f..78e38386 100644 --- a/src/gui/set/stats_panel.cpp +++ b/src/gui/set/stats_panel.cpp @@ -238,7 +238,7 @@ void StatDimensionList::drawItem(DC& dc, int x, int y, size_t item) { StatsDimension& dim = *dimensions.at(item - show_empty); // draw icon if (!dim.icon_filename.empty() && !dim.icon.Ok()) { - InputStreamP file = game->openIn(dim.icon_filename); + auto file = game->openIn(dim.icon_filename); Image img(*file); if (img.HasMask()) img.InitAlpha(); // we can't handle masks Image resampled(21, 21); diff --git a/src/gui/set/style_panel.cpp b/src/gui/set/style_panel.cpp index d2f3a374..0764c383 100644 --- a/src/gui/set/style_panel.cpp +++ b/src/gui/set/style_panel.cpp @@ -171,18 +171,18 @@ void StylePanel::onStyleSelect(wxCommandEvent&) { // select no special style when selecting the same style as the set default stylesheet = StyleSheetP(); } - set->actions.addAction(new ChangeCardStyleAction(card, stylesheet)); + set->actions.addAction(make_unique(card, stylesheet)); Layout(); } } void StylePanel::onUseForAll(wxCommandEvent&) { - set->actions.addAction(new ChangeSetStyleAction(*set, card)); + set->actions.addAction(make_unique(*set, card)); Layout(); } void StylePanel::onUseCustom(wxCommandEvent&) { - set->actions.addAction(new ChangeCardHasStylingAction(*set, card)); + set->actions.addAction(make_unique(*set, card)); } BEGIN_EVENT_TABLE(StylePanel, wxPanel) diff --git a/src/gui/symbol/basic_shape_editor.cpp b/src/gui/symbol/basic_shape_editor.cpp index 01a8b877..fdd784ed 100644 --- a/src/gui/symbol/basic_shape_editor.cpp +++ b/src/gui/symbol/basic_shape_editor.cpp @@ -100,7 +100,7 @@ void SymbolBasicShapeEditor::onLeftDown (const Vector2D& pos, wxMouseEvent& ev void SymbolBasicShapeEditor::onLeftUp (const Vector2D& pos, wxMouseEvent& ev) { if (drawing && shape) { // Finalize the shape - addAction(new AddSymbolPartAction(*getSymbol(), shape)); + addAction(make_unique(*getSymbol(), shape)); // Select the part control.selectPart(shape); // no need to clean up, this editor is replaced diff --git a/src/gui/symbol/editor.cpp b/src/gui/symbol/editor.cpp index 0c2bd0a3..1edec1d4 100644 --- a/src/gui/symbol/editor.cpp +++ b/src/gui/symbol/editor.cpp @@ -16,6 +16,6 @@ void SymbolEditorBase::SetStatusText(const String& text) { control.parent->SetStatusText(text); } -void SymbolEditorBase::addAction(Action* action, bool allow_merge) { - getSymbol()->actions.addAction(action, allow_merge); +void SymbolEditorBase::addAction(unique_ptr action, bool allow_merge) { + getSymbol()->actions.addAction(move(action), allow_merge); } diff --git a/src/gui/symbol/editor.hpp b/src/gui/symbol/editor.hpp index a0adef1b..2533c155 100644 --- a/src/gui/symbol/editor.hpp +++ b/src/gui/symbol/editor.hpp @@ -30,7 +30,7 @@ class SymbolEditorBase : public IntrusivePtrVirtualBase { inline SymbolP getSymbol() { return control.getSymbol(); } /// Perform an action - void addAction(Action* action, bool allow_merge = true); + void addAction(unique_ptr action, bool allow_merge = true); void SetStatusText(const String& text); diff --git a/src/gui/symbol/part_list.cpp b/src/gui/symbol/part_list.cpp index c4b028d6..77ee3239 100644 --- a/src/gui/symbol/part_list.cpp +++ b/src/gui/symbol/part_list.cpp @@ -166,9 +166,9 @@ void SymbolPartList::onLeftUp(wxMouseEvent& ev) { if (par != drop_parent && par->parts.size() == 1 && !par->isSymbolSymmetry()) { // this leaves a group without elements, remove it findParent(*par, par, drag_position); // parent of the group - symbol->actions.addAction(new UngroupReorderSymbolPartsAction(*par, drag_position, *drop_parent, drop_position)); + symbol->actions.addAction(make_unique(*par, drag_position, *drop_parent, drop_position)); } else { - symbol->actions.addAction(new ReorderSymbolPartsAction(*par, drag_position, *drop_parent, drop_position)); + symbol->actions.addAction(make_unique(*par, drag_position, *drop_parent, drop_position)); } } else { Refresh(false); @@ -257,14 +257,14 @@ void SymbolPartList::onChar(wxKeyEvent& ev) { if (cursor > 0 && cursor <= typing_in->name.size()) { String new_name = typing_in->name; new_name.erase(cursor - 1, 1); - symbol->actions.addAction(new SymbolPartNameAction(typing_in, new_name, cursor, cursor - 1)); + symbol->actions.addAction(make_unique(typing_in, new_name, cursor, cursor - 1)); } break; case WXK_DELETE: if (cursor < typing_in->name.size()) { String new_name = typing_in->name; new_name.erase(cursor, 1); - symbol->actions.addAction(new SymbolPartNameAction(typing_in, new_name, cursor, cursor)); + symbol->actions.addAction(make_unique(typing_in, new_name, cursor, cursor)); } break; default: @@ -281,7 +281,7 @@ void SymbolPartList::onChar(wxKeyEvent& ev) { #endif String new_name = typing_in->name; new_name.insert(cursor, 1, key); - symbol->actions.addAction(new SymbolPartNameAction(typing_in, new_name, cursor, cursor + 1)); + symbol->actions.addAction(make_unique(typing_in, new_name, cursor, cursor + 1)); } } } diff --git a/src/gui/symbol/point_editor.cpp b/src/gui/symbol/point_editor.cpp index 01c1f9ea..85a902dd 100644 --- a/src/gui/symbol/point_editor.cpp +++ b/src/gui/symbol/point_editor.cpp @@ -253,10 +253,11 @@ void SymbolPointEditor::onLeftDClick(const Vector2D& pos, wxMouseEvent& ev) { findHoveredItem(pos, false); if (hovering == SELECTED_NEW_POINT) { // Add point - ControlPointAddAction* act = new ControlPointAddAction(part, hover_line_1_idx, hover_line_t); - addAction(act); + auto act = make_unique(part, hover_line_1_idx, hover_line_t); + ControlPointP new_point = act->getNewPoint(); + addAction(move(act)); // select the new point - selectPoint(act->getNewPoint(), false); + selectPoint(new_point, false); selection = SELECTED_POINTS; } else if (hovering == SELECTED_HANDLE && hover_handle.handle == HANDLE_MAIN) { // Delete point @@ -287,8 +288,9 @@ void SymbolPointEditor::onMouseDrag(const Vector2D& from, const Vector2D& to, wx // Drag the curve if (controlPointMoveAction) controlPointMoveAction = 0; if (!curveDragAction) { - curveDragAction = new CurveDragAction(selected_line1, selected_line2); - addAction(curveDragAction); + auto action = make_unique(selected_line1, selected_line2); + curveDragAction = action.get(); + addAction(std::move(action)); } curveDragAction->move(delta, selected_line_t); control.Refresh(false); @@ -297,8 +299,9 @@ void SymbolPointEditor::onMouseDrag(const Vector2D& from, const Vector2D& to, wx if (curveDragAction) curveDragAction = 0; if (!controlPointMoveAction) { // create action we can add this movement to - controlPointMoveAction = new ControlPointMoveAction(selected_points); - addAction(controlPointMoveAction); + auto action = make_unique(selected_points); + controlPointMoveAction = action.get(); + addAction(std::move(action)); } controlPointMoveAction->constrain = ev.ControlDown(); // ctrl constrains controlPointMoveAction->snap = snap(ev); @@ -308,8 +311,9 @@ void SymbolPointEditor::onMouseDrag(const Vector2D& from, const Vector2D& to, wx } else if (selection == SELECTED_HANDLE) { // Move the selected handle if (!handleMoveAction) { - handleMoveAction = new HandleMoveAction(selected_handle); - addAction(handleMoveAction); + auto action = make_unique(selected_handle); + handleMoveAction = action.get(); + addAction(std::move(action)); } handleMoveAction->constrain = ev.ControlDown(); // ctrl constrains handleMoveAction->snap = snap(ev); @@ -353,6 +357,7 @@ void SymbolPointEditor::onChar(wxKeyEvent& ev) { if (ev.GetKeyCode() == WXK_DELETE) { deleteSelection(); } else { + resetActions(); // move selection using arrow keys double step = 1.0 / settings.symbol_grid_size; Vector2D delta; @@ -367,19 +372,18 @@ void SymbolPointEditor::onChar(wxKeyEvent& ev) { // what to move if (selection == SELECTED_POINTS || selection == SELECTED_LINE) { // Move all selected points - controlPointMoveAction = new ControlPointMoveAction(selected_points); - addAction(controlPointMoveAction); - controlPointMoveAction->move(delta); + auto action = make_unique(selected_points); + action->move(delta); + addAction(std::move(action)); new_point += delta; control.Refresh(false); } else if (selection == SELECTED_HANDLE) { // Move the selected handle - handleMoveAction = new HandleMoveAction(selected_handle); - addAction(handleMoveAction); - handleMoveAction->move(delta); + auto action = make_unique(selected_handle); + action->move(delta); + addAction(std::move(action)); control.Refresh(false); } - resetActions(); } } @@ -477,12 +481,12 @@ void SymbolPointEditor::onChangeSegment(SegmentMode mode) { assert(selected_line1); assert(selected_line2); if (selected_line1->segment_after == mode) return; - addAction(new SegmentModeAction(selected_line1, selected_line2, mode)); + addAction(make_unique(selected_line1, selected_line2, mode)); control.Refresh(false); } void SymbolPointEditor::onChangeLock(LockMode mode) { - addAction(new LockModeAction(*selected_points.begin(), mode)); + addAction(make_unique(*selected_points.begin(), mode)); control.Refresh(false); } diff --git a/src/gui/symbol/select_editor.cpp b/src/gui/symbol/select_editor.cpp index 6753a9a2..615dbd86 100644 --- a/src/gui/symbol/select_editor.cpp +++ b/src/gui/symbol/select_editor.cpp @@ -173,22 +173,22 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) { void SymbolSelectEditor::onCommand(int id) { if (id >= ID_SYMBOL_COMBINE && id < ID_SYMBOL_COMBINE_MAX) { // change combine mode - addAction(new CombiningModeAction( + addAction(make_unique( control.selected_parts.get(), static_cast(id - ID_SYMBOL_COMBINE) )); control.Refresh(false); } else if (id == ID_EDIT_DUPLICATE && !isEditing()) { // duplicate selection, not when dragging - addAction(new DuplicateSymbolPartsAction(*getSymbol(), control.selected_parts.get())); + addAction(make_unique(*getSymbol(), control.selected_parts.get())); control.Refresh(false); } else if (id == ID_EDIT_GROUP && !isEditing()) { // group selection, not when dragging - addAction(new GroupSymbolPartsAction(*getSymbol(), control.selected_parts.get(), make_intrusive())); + addAction(make_unique(*getSymbol(), control.selected_parts.get(), make_intrusive())); control.Refresh(false); } else if (id == ID_EDIT_UNGROUP && !isEditing()) { // ungroup selection, not when dragging - addAction(new UngroupSymbolPartsAction(*getSymbol(), control.selected_parts.get())); + addAction(make_unique(*getSymbol(), control.selected_parts.get())); control.Refresh(false); } } @@ -312,24 +312,28 @@ void SymbolSelectEditor::onMouseDrag (const Vector2D& from, const Vector2D& to, if (rotate) { if (scaleX == 0 || scaleY == 0) { // shear, center/fixed point on the opposite side - shearAction = new SymbolPartShearAction(control.selected_parts.get(), bounds.corner(-scaleX, -scaleY)); - addAction(shearAction); + auto action = make_unique(control.selected_parts.get(), bounds.corner(-scaleX, -scaleY)); + shearAction = action.get(); + addAction(std::move(action)); } else { // rotate - rotateAction = new SymbolPartRotateAction(control.selected_parts.get(), center); - addAction(rotateAction); + auto action = make_unique(control.selected_parts.get(), center); + rotateAction = action.get(); + addAction(std::move(action)); startAngle = angleTo(to); } } else { // we are on a handle; start scaling - scaleAction = new SymbolPartScaleAction(control.selected_parts.get(), scaleX, scaleY); - addAction(scaleAction); + auto action = make_unique(control.selected_parts.get(), scaleX, scaleY); + scaleAction = action.get(); + addAction(std::move(action)); } } else { // move click_mode = CLICK_MOVE; - moveAction = new SymbolPartMoveAction(control.selected_parts.get()); - addAction(moveAction); + auto action = make_unique(control.selected_parts.get()); + moveAction = action.get(); + addAction(std::move(action)); } } @@ -399,7 +403,7 @@ void SymbolSelectEditor::onKeyChange (wxKeyEvent& ev) { void SymbolSelectEditor::onChar(wxKeyEvent& ev) { if (ev.GetKeyCode() == WXK_DELETE) { // delete selected parts - addAction(new RemoveSymbolPartsAction(*getSymbol(), control.selected_parts.get())); + addAction(make_unique(*getSymbol(), control.selected_parts.get())); if (control.selected_parts.selected(highlightPart)) highlightPart = SymbolPartP(); // deleted it control.selected_parts.clear(); resetActions(); @@ -416,7 +420,7 @@ void SymbolSelectEditor::onChar(wxKeyEvent& ev) { ev.Skip(); return; } - addAction(new SymbolPartMoveAction(control.selected_parts.get(), delta)); + addAction(make_unique(control.selected_parts.get(), delta)); } } diff --git a/src/gui/symbol/symmetry_editor.cpp b/src/gui/symbol/symmetry_editor.cpp index 60df5354..0bda56fb 100644 --- a/src/gui/symbol/symmetry_editor.cpp +++ b/src/gui/symbol/symmetry_editor.cpp @@ -107,13 +107,13 @@ void SymbolSymmetryEditor::onCommand(int id) { if (id >= ID_SYMMETRY && id < ID_SYMMETRY_MAX) { SymbolSymmetryType kind = id == ID_SYMMETRY_ROTATION ? SYMMETRY_ROTATION : SYMMETRY_REFLECTION; if (symmetry && symmetry->kind != kind) { - addAction(new SymmetryTypeAction(*symmetry, kind)); + addAction(make_unique(*symmetry, kind)); control.Refresh(false); } resetActions(); } else if (id == ID_COPIES) { if (symmetry && symmetry->copies != copies->GetValue()) { - addAction(new SymmetryCopiesAction(*symmetry, copies->GetValue())); + addAction(make_unique(*symmetry, copies->GetValue())); control.Refresh(false); } resetActions(); @@ -124,11 +124,11 @@ void SymbolSymmetryEditor::onCommand(int id) { symmetry->center = Vector2D(0.5,0.5); symmetry->handle = Vector2D(0.2,0); symmetry->name = symmetry->expectedName(); - addAction(new GroupSymbolPartsAction(*getSymbol(), control.selected_parts.get(), symmetry)); + addAction(make_unique(*getSymbol(), control.selected_parts.get(), symmetry)); control.selected_parts.select(symmetry); control.Refresh(false); } else if (id == ID_REMOVE_SYMMETRY) { - addAction(new UngroupSymbolPartsAction(*getSymbol(), control.selected_parts.get())); + addAction(make_unique(*getSymbol(), control.selected_parts.get())); symmetry = SymbolSymmetryP(); control.Refresh(false); } @@ -155,10 +155,11 @@ void SymbolSymmetryEditor::onMouseDrag (const Vector2D& from, const Vector2D& t // Resize the object if (selection == SELECTION_NONE) return; if (!symmetryMoveAction) { - symmetryMoveAction = new SymmetryMoveAction(*symmetry, selection == SELECTION_HANDLE); + auto action = make_unique(*symmetry, selection == SELECTION_HANDLE); + symmetryMoveAction = action.get(); symmetryMoveAction->constrain = ev.ControlDown(); symmetryMoveAction->snap = ev.ShiftDown() != settings.symbol_grid_snap ? settings.symbol_grid_size : 0; - addAction(symmetryMoveAction); + addAction(std::move(action)); } symmetryMoveAction->move(to - from); control.Refresh(false); diff --git a/src/gui/symbol/window.cpp b/src/gui/symbol/window.cpp index 58ca2f3f..5482f68e 100644 --- a/src/gui/symbol/window.cpp +++ b/src/gui/symbol/window.cpp @@ -36,7 +36,8 @@ SymbolWindow::SymbolWindow(Window* parent, const String& filename) : performer(nullptr) { // open file - Reader reader(make_shared(filename), nullptr, filename); + wxFileInputStream stream(filename); + Reader reader(stream, nullptr, filename); SymbolP symbol; reader.handle_greedy(symbol); init(parent, symbol); @@ -217,7 +218,8 @@ void SymbolWindow::onFileOpen(wxCommandEvent& ev) { String ext = n.GetExt(); SymbolP symbol; if (ext.Lower() == _("mse-symbol")) { - Reader reader(make_shared(name), nullptr, name); + wxFileInputStream stream(name); + Reader reader(stream, nullptr, name); reader.handle_greedy(symbol); } else { wxBusyCursor busy; @@ -240,7 +242,8 @@ void SymbolWindow::onFileSaveAs(wxCommandEvent& ev) { String name = wxFileSelector(_("Save symbol"),settings.default_set_dir,_(""),_(""),_("Symbol files (*.mse-symbol)|*.mse-symbol"),wxFD_SAVE, this); if (!name.empty()) { settings.default_set_dir = wxPathOnly(name); - Writer writer(make_shared(name), file_version_symbol); + wxFileOutputStream stream(name); + Writer writer(stream, file_version_symbol); writer.handle(control->getSymbol()); } } @@ -250,7 +253,8 @@ void SymbolWindow::onFileStore(wxCommandEvent& ev) { SymbolValueP value = static_pointer_cast(performer->value); Package& package = performer->getLocalPackage(); FileName new_filename = package.newFileName(value->field().name,_(".mse-symbol")); // a new unique name in the package - Writer writer(package.openOut(new_filename), file_version_symbol); + auto stream = package.openOut(new_filename); + Writer writer(*stream, file_version_symbol); writer.handle(control->getSymbol()); performer->addAction(value_action(value, new_filename)); } diff --git a/src/gui/update_checker.cpp b/src/gui/update_checker.cpp index 63cda179..91d817cb 100644 --- a/src/gui/update_checker.cpp +++ b/src/gui/update_checker.cpp @@ -107,13 +107,12 @@ class CheckUpdateThread : public wxThread { String& the_url = settings.updates_url; #endif wxURL url(the_url); - wxInputStream* isP = url.GetInputStream(); + unique_ptr isP(url.GetInputStream()); if (!isP) return; // failed to get data - InputStreamP is(isP); // Read version data // ignore errors for forwards compatability VersionDataP version_data; - Reader reader(is, nullptr, _("updates"), true); + Reader reader(*isP, nullptr, _("updates"), true); reader.handle(version_data); // has the updates url changed? if (!version_data->new_updates_url.empty()) { diff --git a/src/gui/value/editor.cpp b/src/gui/value/editor.cpp index ce54d757..1fecb1df 100644 --- a/src/gui/value/editor.cpp +++ b/src/gui/value/editor.cpp @@ -12,9 +12,9 @@ // ----------------------------------------------------------------------------- : ValueEditor -void ValueEditor::addAction(ValueAction* a) { +void ValueEditor::addAction(unique_ptr a) { if (a) { a->isOnCard(editor().getCard().get()); - editor().addAction(a); + editor().addAction(move(a)); } } diff --git a/src/gui/value/editor.hpp b/src/gui/value/editor.hpp index e61cdbf8..2bc7dd85 100644 --- a/src/gui/value/editor.hpp +++ b/src/gui/value/editor.hpp @@ -130,7 +130,7 @@ class ValueEditor { virtual DataEditor& editor() const = 0; /// Perform an action - void addAction(ValueAction* a); + void addAction(unique_ptr a); }; // ----------------------------------------------------------------------------- : Utility diff --git a/src/gui/value/image.cpp b/src/gui/value/image.cpp index 78ad79c0..ca013c86 100644 --- a/src/gui/value/image.cpp +++ b/src/gui/value/image.cpp @@ -65,7 +65,7 @@ bool ImageValueEditor::canPaste() const { bool ImageValueEditor::doCopy() { // load image - InputStreamP image_file = getLocalPackage().openIn(value().filename); + auto image_file = getLocalPackage().openIn(value().filename); Image image; if (!image_load_file(image, *image_file)) return false; // set data diff --git a/src/gui/value/text.cpp b/src/gui/value/text.cpp index b9c8dade..136553d8 100644 --- a/src/gui/value/text.cpp +++ b/src/gui/value/text.cpp @@ -856,7 +856,7 @@ void TextValueEditor::doFormat(int type) { break; } case ID_FORMAT_REMINDER: { - addAction(new TextToggleReminderAction(valueP(), selection_start_i)); + addAction(make_unique(valueP(), selection_start_i)); break; } } @@ -983,7 +983,7 @@ void TextValueEditor::replaceSelection(const String& replacement, const String& fixSelection(); // execute the action before adding it to the stack, // because we want to run scripts before action listeners see the action - TextValueAction* action = typing_action(valueP(), selection_start_i, selection_end_i, select_on_undo ? selection_start : selection_end, selection_end, replacement, name); + auto action = typing_action(valueP(), selection_start_i, selection_end_i, select_on_undo ? selection_start : selection_end, selection_end, replacement, name); if (!action) { // nothing changes, but move the selection anyway moveSelection(TYPE_CURSOR, selection_end); @@ -994,7 +994,7 @@ void TextValueEditor::replaceSelection(const String& replacement, const String& size_t expected_cursor = min(selection_start, selection_end) + untag_for_cursor(replacement).size(); // perform the action // NOTE: this calls our onAction, invalidating the text viewer and moving the selection around the new text - addAction(action); + addAction(std::move(action)); // move cursor { String real_value = untag_for_cursor(value().value()); diff --git a/src/render/value/image.cpp b/src/render/value/image.cpp index 12c57a19..93cb1108 100644 --- a/src/render/value/image.cpp +++ b/src/render/value/image.cpp @@ -32,7 +32,7 @@ void ImageValueViewer::draw(RotatedDC& dc) { // load from file if (!value().filename.empty()) { try { - InputStreamP image_file = getLocalPackage().openIn(value().filename); + auto image_file = getLocalPackage().openIn(value().filename); if (image_load_file(image, *image_file)) { image.Rescale(w, h); } diff --git a/src/render/value/package_choice.cpp b/src/render/value/package_choice.cpp index e0eb9e71..74fabe2a 100644 --- a/src/render/value/package_choice.cpp +++ b/src/render/value/package_choice.cpp @@ -37,7 +37,7 @@ void PackageChoiceValueViewer::initItems() { i.package_name = p->relativeFilename(); i.name = capitalize_sentence(p->short_name); Image image; - InputStreamP stream = p->openIconFile(); + auto stream = p->openIconFile(); if (stream && image_load_file(image, *stream)) { i.image = Bitmap(resample(image, 16,16)); } diff --git a/src/script/functions/export.cpp b/src/script/functions/export.cpp index cfdccb2d..594c8cd1 100644 --- a/src/script/functions/export.cpp +++ b/src/script/functions/export.cpp @@ -378,7 +378,7 @@ SCRIPT_FUNCTION(copy_file) { String out_path = get_export_full_path(out_name); // copy ExportInfo& ei = *export_info(); - InputStreamP in = ei.export_template->openIn(input); + auto in = ei.export_template->openIn(input); wxFileOutputStream out(out_path); if (!out.Ok()) throw Error(_("Unable to open file '") + out_path + _("' for output")); out.Write(*in); diff --git a/src/script/parser.cpp b/src/script/parser.cpp index e5c1696d..a70242c5 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -213,9 +213,9 @@ void TokenIterator::readToken() { // read the entire file, and start at the beginning of it pos = 0; filename = include_file; - InputStreamP is = package_manager.openFileFromPackage(package, include_file); - eat_utf8_bom(*is); - input = read_utf8_line(*is, true); + auto stream = package_manager.openFileFromPackage(package, include_file); + eat_utf8_bom(*stream); + input = read_utf8_line(*stream, true); } else if (isAlpha(c) || isUnicodeAlpha(c) || c == _('_') || (isDigit(c) && !buffer.empty() && buffer.back() == _("."))) { // name, or a number after a . token, as in array.0 size_t start = pos - 1; diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index 12357817..30889dc2 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -21,57 +21,37 @@ #include #include -typedef map Contexts; -DECLARE_TYPEOF(Contexts); -DECLARE_TYPEOF_COLLECTION(CardP); -DECLARE_TYPEOF_COLLECTION(FieldP); -DECLARE_TYPEOF_COLLECTION(Dependency); -DECLARE_TYPEOF_NO_REV(IndexMap); -DECLARE_TYPEOF_NO_REV(IndexMap); - -//#define LOG_UPDATES - // ----------------------------------------------------------------------------- : SetScriptContext : initialization SetScriptContext::SetScriptContext(Set& set) : set(set) {} -SetScriptContext::~SetScriptContext() { - // destroy contexts - FOR_EACH(sc, contexts) { - delete sc.second; - } -} - Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) { - Contexts::iterator it = contexts.find(stylesheet.get()); - if (it != contexts.end()) { - return *it->second; // we already have a context - } else { - // create a new context - Context* ctx = new Context(); - contexts.insert(make_pair(stylesheet.get(), ctx)); + auto it = contexts.try_emplace(stylesheet.get()); + Context& ctx = it.first->second; + if (it.second) { + // we created a new context // variables // NOTE: do not use a smart pointer for the pointer to the set, because the set owns this // which would lead to a reference cycle. - init_script_functions(*ctx); - ctx->setVariable(SCRIPT_VAR_set, make_intrusive>(&set)); - ctx->setVariable(SCRIPT_VAR_game, to_script(set.game)); - ctx->setVariable(SCRIPT_VAR_stylesheet, to_script(stylesheet)); - ctx->setVariable(SCRIPT_VAR_card_style, to_script(&stylesheet->card_style)); - ctx->setVariable(SCRIPT_VAR_card, set.cards.empty() ? script_nil : to_script(set.cards.front())); // dummy value - ctx->setVariable(SCRIPT_VAR_styling, to_script(&set.stylingDataFor(*stylesheet))); + init_script_functions(ctx); + ctx.setVariable(SCRIPT_VAR_set, make_intrusive>(&set)); + ctx.setVariable(SCRIPT_VAR_game, to_script(set.game)); + ctx.setVariable(SCRIPT_VAR_stylesheet, to_script(stylesheet)); + ctx.setVariable(SCRIPT_VAR_card_style, to_script(&stylesheet->card_style)); + ctx.setVariable(SCRIPT_VAR_card, set.cards.empty() ? script_nil : to_script(set.cards.front())); // dummy value + ctx.setVariable(SCRIPT_VAR_styling, to_script(&set.stylingDataFor(*stylesheet))); try { // perform init scripts, don't use a scope, variables stay bound in the context - set.game ->init_script.invoke(*ctx, false); - stylesheet->init_script.invoke(*ctx, false); + set.game ->init_script.invoke(ctx, false); + stylesheet->init_script.invoke(ctx, false); } catch (const Error& e) { handle_error(e); } onInit(stylesheet, ctx); - return *ctx; } + return ctx; } Context& SetScriptContext::getContext(const CardP& card) { StyleSheetP stylesheet = set.stylesheetForP(card); @@ -100,13 +80,13 @@ SetScriptManager::~SetScriptManager() { set.actions.removeListener(this); } -void SetScriptManager::onInit(const StyleSheetP& stylesheet, Context* ctx) { +void SetScriptManager::onInit(const StyleSheetP& stylesheet, Context& ctx) { assert(wxThread::IsMain()); // initialize dependencies try { // find script dependencies - initDependencies(*ctx, *set.game); - initDependencies(*ctx, *stylesheet); + initDependencies(ctx, *set.game); + initDependencies(ctx, *stylesheet); } catch (const Error& e) { handle_error(e); } diff --git a/src/script/script_manager.hpp b/src/script/script_manager.hpp index 951a1b89..3dd8f8b0 100644 --- a/src/script/script_manager.hpp +++ b/src/script/script_manager.hpp @@ -28,21 +28,20 @@ DECLARE_POINTER_TYPE(Style); /// Manager of the script context for a set class SetScriptContext { - public: +public: SetScriptContext(Set& set); - virtual ~SetScriptContext(); /// Get a context to use for the set, for a given stylesheet Context& getContext(const StyleSheetP&); /// Get a context to use for the set, for a given card Context& getContext(const CardP&); - protected: - Set& set; ///< Set for which we are managing scripts - map contexts; ///< Context for evaluating scripts that use a given stylesheet +protected: + Set& set; ///< Set for which we are managing scripts + map contexts; ///< Context for evaluating scripts that use a given stylesheet /// Called when a new context for a stylesheet is initialized - virtual void onInit(const StyleSheetP& stylesheet, Context* ctx) {} + virtual void onInit(const StyleSheetP& stylesheet, Context& ctx) {} }; @@ -73,7 +72,7 @@ class SetScriptManager : public SetScriptContext, public ActionListener { void updateAll(); private: - virtual void onInit(const StyleSheetP& stylesheet, Context* ctx); + void onInit(const StyleSheetP& stylesheet, Context& ctx) override; void initDependencies(Context&, Game&); void initDependencies(Context&, StyleSheet&); diff --git a/src/util/action_stack.cpp b/src/util/action_stack.cpp index 9800cfa0..61977f3d 100644 --- a/src/util/action_stack.cpp +++ b/src/util/action_stack.cpp @@ -21,29 +21,22 @@ ActionStack::ActionStack() , last_was_add(false) {} -ActionStack::~ActionStack() { - // we own the actions, delete them - FOR_EACH(a, undo_actions) delete a; - FOR_EACH(a, redo_actions) delete a; -} - -void ActionStack::addAction(Action* action, bool allow_merge) { +void ActionStack::addAction(unique_ptr action, bool allow_merge) { if (!action) return; // no action action->perform(false); // TODO: delete action if perform throws tellListeners(*action, false); // clear redo list if (!redo_actions.empty()) allow_merge = false; // don't merge after undo - FOR_EACH(a, redo_actions) delete a; redo_actions.clear(); // try to merge? if (allow_merge && !undo_actions.empty() && - last_was_add && // never merge with something that was redone once already - undo_actions.back() != save_point && // never merge with the save point + last_was_add && // never merge with something that was redone once already + undo_actions.back().get() != save_point && // never merge with the save point undo_actions.back()->merge(*action) // merged with top undo action ) { - delete action; + // don't add } else { - undo_actions.push_back(action); + undo_actions.push_back(move(action)); } last_was_add = true; } @@ -51,23 +44,23 @@ void ActionStack::addAction(Action* action, bool allow_merge) { void ActionStack::undo() { assert(canUndo()); if (!canUndo()) return; - Action* action = undo_actions.back(); + unique_ptr action = move(undo_actions.back()); + undo_actions.pop_back(); action->perform(true); tellListeners(*action, true); // move to redo stack - undo_actions.pop_back(); - redo_actions.push_back(action); + redo_actions.emplace_back(move(action)); last_was_add = false; } void ActionStack::redo() { assert(canRedo()); if (!canRedo()) return; - Action* action = redo_actions.back(); + unique_ptr action = move(redo_actions.back()); + redo_actions.pop_back(); action->perform(false); tellListeners(*action, false); // move to undo stack - redo_actions.pop_back(); - undo_actions.push_back(action); + undo_actions.emplace_back(move(action)); last_was_add = false; } @@ -95,13 +88,13 @@ String ActionStack::redoName() const { bool ActionStack::atSavePoint() const { return (undo_actions.empty() && save_point == nullptr) - || (undo_actions.back() == save_point); + || (undo_actions.back().get() == save_point); } void ActionStack::setSavePoint() { if (undo_actions.empty()) { save_point = nullptr; } else { - save_point = undo_actions.back(); + save_point = undo_actions.back().get(); } } diff --git a/src/util/action_stack.hpp b/src/util/action_stack.hpp index 5427ec34..9a5c1a27 100644 --- a/src/util/action_stack.hpp +++ b/src/util/action_stack.hpp @@ -64,14 +64,13 @@ class ActionListener { class ActionStack { public: ActionStack(); - ~ActionStack(); /// Add an action to the stack, and perform that action. /** Tells all listeners about the action. * The ActionStack takes ownership of the action. * If allow_merge == true then we attempt to merge this action with previous ones */ - void addAction(Action* action, bool allow_merge = true); + void addAction(unique_ptr action, bool allow_merge = true); /// Undoes the last action that was (re)done /** @pre canUndo() */ @@ -107,13 +106,11 @@ class ActionStack { private: /// Actions to be undone. - /** Owns the action objects! */ - vector undo_actions; + vector> undo_actions; /// Actions to be redone - /** Owns the action objects! */ - vector redo_actions; + vector> redo_actions; /// Point at which the file was saved, corresponds to the top of the undo stack at that point - Action* save_point; + const Action* save_point; /// Was the last thing the user did addAction? (as opposed to undo/redo) bool last_was_add; /// Objects that are listening to actions diff --git a/src/util/delayed_index_maps.hpp b/src/util/delayed_index_maps.hpp index 2aec56fd..13641603 100644 --- a/src/util/delayed_index_maps.hpp +++ b/src/util/delayed_index_maps.hpp @@ -25,7 +25,8 @@ IndexMap& DelayedIndexMaps::get(const String& name, const item->read_data.init(init_with); } else if (!item->unread_data.empty()) { // not read, read now item->read_data.init(init_with); - Reader reader(make_shared(item->unread_data), nullptr, _("delayed data for ") + name); + wxStringInputStream input(item->unread_data); + Reader reader(input, nullptr, _("delayed data for ") + name); reader.handle_greedy(item->read_data); item->unread_data.clear(); } diff --git a/src/util/io/package.cpp b/src/util/io/package.cpp index e5a57f47..093130e6 100644 --- a/src/util/io/package.cpp +++ b/src/util/io/package.cpp @@ -26,13 +26,10 @@ IMPLEMENT_DYNAMIC_ARG(Package*, writing_package, nullptr); IMPLEMENT_DYNAMIC_ARG(Package*, clipboard_package, nullptr); Package::Package() - : fileStream(nullptr) - , zipStream (nullptr) + : zipStream (nullptr) {} Package::~Package() { - delete zipStream; - delete fileStream; // remove any remaining temporary files FOR_EACH(f, files) { if (f.second.wasWritten()) { @@ -91,8 +88,7 @@ void Package::open(const String& n, bool fast) { void Package::reopen() { if (wxDirExists(filename)) { // make sure we have no zip open - delete zipStream; zipStream = nullptr; - delete fileStream; fileStream = nullptr; + zipStream.reset(); } else { // reopen only needed for zipfile openZipfile(); @@ -154,40 +150,45 @@ void Package::clearKeepFlag() { // ----------------------------------------------------------------------------- : Package : inside +class FileInputStream_aux { +protected: + wxFileInputStream file_stream; + inline FileInputStream_aux(const String& filename) + : file_stream(filename) + {} +}; + /// Class that is a wxZipInputStream over a wxFileInput stream /** Note that wxFileInputStream is also a base class, because it must be constructed first */ -class ZipFileInputStream : private wxFileInputStream, public wxZipInputStream { - public: +class ZipFileInputStream : private FileInputStream_aux, public wxZipInputStream { +public: + ZipFileInputStream(const String& filename) + : FileInputStream_aux(filename) + , wxZipInputStream(file_stream) + {} ZipFileInputStream(const String& filename, wxZipEntry* entry) - : wxFileInputStream(filename) - , wxZipInputStream(static_cast(*this)) + : FileInputStream_aux(filename) + , wxZipInputStream(file_stream) { OpenEntry(*entry); } }; -class BufferedFileInputStream_aux { - protected: - wxFileInputStream file_stream; - inline BufferedFileInputStream_aux(const String& filename) - : file_stream(filename) - {} -}; /// A buffered version of wxFileInputStream /** 2007-08-24: * According to profiling this gives a significant speedup * Bringing the avarage run time of read_utf8_line from 186k to 54k (in cpu time units) */ -class BufferedFileInputStream : private BufferedFileInputStream_aux, public wxBufferedInputStream { - public: +class BufferedFileInputStream : private FileInputStream_aux, public wxBufferedInputStream { +public: inline BufferedFileInputStream(const String& filename) - : BufferedFileInputStream_aux(filename) + : FileInputStream_aux(filename) , wxBufferedInputStream(file_stream) {} }; -InputStreamP Package::openIn(const String& file) { +unique_ptr Package::openIn(const String& file) { if (!file.empty() && file.GetChar(0) == _('/')) { // absolute path, open file from another package Packaged* p = dynamic_cast(this); @@ -200,16 +201,16 @@ InputStreamP Package::openIn(const String& file) { throw PackageError(_ERROR_2_("file not found package like", file, filename)); } } - InputStreamP stream; + unique_ptr stream; if (it != files.end() && it->second.wasWritten()) { // written to this file, open the temp file - stream = make_shared(it->second.tempName); + stream = make_unique(it->second.tempName); } else if (wxFileExists(filename+_("/")+file)) { // a file in directory package - stream = make_shared(filename+_("/")+file); + stream = make_unique(filename+_("/")+file); } else if (wxFileExists(filename) && it != files.end() && it->second.zipEntry) { // a file in a zip archive - stream = static_pointer_cast(make_shared(filename, it->second.zipEntry)); + stream = make_unique(filename, it->second.zipEntry); } else { // shouldn't happen, packaged changed by someone else since opening it throw FileNotFoundError(file, filename); @@ -221,8 +222,8 @@ InputStreamP Package::openIn(const String& file) { } } -OutputStreamP Package::openOut(const String& file) { - return make_shared(nameOut(file)); +unique_ptr Package::openOut(const String& file) { + return make_unique(nameOut(file)); } String Package::nameOut(const String& file) { @@ -292,13 +293,13 @@ String Package::absoluteName(const String& file) { } } // Open a file that is in some package -InputStreamP Package::openAbsoluteFile(const String& name) { +unique_ptr Package::openAbsoluteFile(const String& name) { size_t pos = name.find_first_of(_('\1')); if (pos == String::npos) { // temp or dir file - shared_ptr f = make_shared(name); - if (!f->IsOk()) throw FileNotFoundError(_(""), name); - return f; + auto stream = make_unique(name); + if (!stream->IsOk()) throw FileNotFoundError(_(""), name); + return stream; } else { // packaged file, always in zip format Package p; @@ -355,12 +356,9 @@ void Package::openSubdir(const String& name) { void Package::openZipfile() { // close old streams - delete fileStream; fileStream = nullptr; - delete zipStream; zipStream = nullptr; + zipStream.reset(); // open streams - fileStream = new wxFileInputStream(filename); - if (!fileStream->IsOk()) throw PackageError(_ERROR_1_("package not found", filename)); - zipStream = new wxZipInputStream(*fileStream); + zipStream = make_unique(filename); if (!zipStream->IsOk()) throw PackageError(_ERROR_1_("package not found", filename)); // read zip entries loadZipStream(); @@ -421,14 +419,13 @@ void Package::saveToZipfile(const String& saveAs, bool remove_unused, bool is_co } else { // changed file, or the old package was not a zipfile newZip->PutNextEntry(f.first); - InputStreamP temp = openIn(f.first); - newZip->Write(*temp); + auto temp_stream = openIn(f.first); + newZip->Write(*temp_stream); } } // close the old file if (!is_copy) { - delete zipStream; zipStream = nullptr; - delete fileStream; fileStream = nullptr; + zipStream.reset(); } } catch (Error e) { // when things go wrong delete the temp file @@ -503,11 +500,11 @@ Packaged::Packaged() , fully_loaded(true) {} -InputStreamP Packaged::openIconFile() { +unique_ptr Packaged::openIconFile() { if (!icon_filename.empty()) { return openIn(icon_filename); } else { - return InputStreamP(); + return unique_ptr(); } } @@ -526,7 +523,8 @@ void Packaged::open(const String& package, bool just_header) { PROFILER(just_header ? _("open package header") : _("open package fully")); if (just_header) { // Read just the header (the part common to all Packageds) - Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName(), true); + auto stream = openIn(typeName()); + Reader reader(*stream, this, absoluteFilename() + _("/") + typeName(), true); try { JustAsPackageProxy proxy(this); reader.handle_greedy(proxy); @@ -538,9 +536,11 @@ void Packaged::open(const String& package, bool just_header) { loadFully(); } } + void Packaged::loadFully() { if (fully_loaded) return; - Reader reader(openIn(typeName()), this, absoluteFilename() + _("/") + typeName()); + auto stream = openIn(typeName()); + Reader reader(*stream, this, absoluteFilename() + _("/") + typeName()); try { reader.handle_greedy(*this); validate(reader.file_app_version); diff --git a/src/util/io/package.hpp b/src/util/io/package.hpp index b8f3eae6..c5c6668f 100644 --- a/src/util/io/package.hpp +++ b/src/util/io/package.hpp @@ -100,11 +100,11 @@ class Package : public IntrusivePtrVirtualBase { // --------------------------------------------------- : Managing the inside of the package /// Open an input stream for a file in the package. - InputStreamP openIn(const String& file); + unique_ptr openIn(const String& file); /// Open an output stream for a file in the package. /// (changes are only committed with save()) - OutputStreamP openOut(const String& file); + unique_ptr openOut(const String& file); /// Get a filename that can be written to to modfify a file in the package /// (changes are only committed with save()) @@ -125,7 +125,7 @@ class Package : public IntrusivePtrVirtualBase { String absoluteName(const String& file); /// Open a file given an absolute filename - static InputStreamP openAbsoluteFile(const String& name); + static unique_ptr openAbsoluteFile(const String& name); // --------------------------------------------------- : Managing the inside of the package : Reader/writer @@ -141,7 +141,8 @@ class Package : public IntrusivePtrVirtualBase { template void writeFile(const String& file, const T& obj, Version file_version) { - Writer writer(openOut(file), file_version); + auto stream = openOut(file); + Writer writer(*stream, file_version); writer.handle(obj); } @@ -182,10 +183,8 @@ class Package : public IntrusivePtrVirtualBase { private: /// All files in the package FileInfos files; - /// Filestream for reading zip files - wxFileInputStream* fileStream; - /// Filestream for reading zip files - wxZipInputStream* zipStream; + /// Filestream/zipstream for reading zip files + unique_ptr zipStream; void loadZipStream(); void openDirectory(bool fast = false); @@ -229,7 +228,7 @@ class Packaged : public Package { int position_hint; ///< A hint for the package list /// Get an input stream for the package icon, if there is any - InputStreamP openIconFile(); + unique_ptr openIconFile(); /// Open a package, and read the data /** if just_header is true, then the package is not fully parsed. @@ -289,9 +288,9 @@ intrusive_ptr open_package(const String& filename) { // This is here because it uses dynamic_cast and must be to a complete type. template -inline void Package::readFile(const String& file, T& obj) -{ - Reader reader(openIn(file), dynamic_cast(this), absoluteFilename() + _("/") + file); +inline void Package::readFile(const String& file, T& obj) { + auto stream = openIn(file); + Reader reader(*stream, dynamic_cast(this), absoluteFilename() + _("/") + file); try { reader.handle_greedy(obj); } catch (const ParseError& err) { diff --git a/src/util/io/package_manager.cpp b/src/util/io/package_manager.cpp index 645977f4..d9ce42b8 100644 --- a/src/util/io/package_manager.cpp +++ b/src/util/io/package_manager.cpp @@ -99,7 +99,7 @@ void PackageManager::findMatching(const String& pattern, vector& out) } } -InputStreamP PackageManager::openFileFromPackage(Packaged*& package, const String& name) { +unique_ptr PackageManager::openFileFromPackage(Packaged*& package, const String& name) { if (!name.empty() && name.GetChar(0) == _('/')) { // absolute name; break name size_t start = name.find_first_not_of(_("/\\"), 1); // allow "//package/name" from incorrect scripts @@ -339,16 +339,17 @@ void PackageDirectory::loadDatabase() { String filename = databaseFile(); if (wxFileExists(filename)) { // packages file not existing is not an error - shared_ptr file = make_shared(filename); - if (!file->Ok()) return; // failure is not an error - Reader reader(file, nullptr, filename); + wxFileInputStream file_stream = {filename}; + if (!file_stream.Ok()) return; // failure is not an error + Reader reader(file_stream, nullptr, filename); reader.handle_greedy(*this); sort(packages.begin(), packages.end(), compare_name); } } void PackageDirectory::saveDatabase() { - Writer writer(make_shared(databaseFile()), app_version); + wxFileOutputStream stream(databaseFile()); + Writer writer(stream, app_version); writer.handle(*this); } String PackageDirectory::databaseFile() { @@ -391,13 +392,13 @@ bool PackageDirectory::actual_install(const InstallablePackage& package, const S String local_file = install_dir + file.substr(name.length()); create_parent_dirs(local_file); // copy file - InputStreamP is = installer.openIn(file); - wxFileOutputStream os (local_file); - if (!os.IsOk()) { + auto in_stream = installer.openIn(file); + wxFileOutputStream out_stream(local_file); + if (!out_stream.IsOk()) { int act = wxMessageBox(_ERROR_1_("cannot create file", file), _TITLE_("cannot create file"), wxICON_ERROR | wxYES_NO); if (act == wxNO) return false; } - os.Write(*is); + out_stream.Write(*in_stream); } // update package database // TODO: bless the package? diff --git a/src/util/io/package_manager.hpp b/src/util/io/package_manager.hpp index ee316b09..377f744f 100644 --- a/src/util/io/package_manager.hpp +++ b/src/util/io/package_manager.hpp @@ -148,7 +148,7 @@ class PackageManager { * this is to force people to fill in the dependencies * Afterwards, package will be set to the package the file is opened from */ - InputStreamP openFileFromPackage(Packaged*& package, const String& name); + unique_ptr openFileFromPackage(Packaged*& package, const String& name); /// Get a filename to open from a package /** WARNING: this is a bit of a hack, since not all package types support names in this way. diff --git a/src/util/io/reader.cpp b/src/util/io/reader.cpp index 0ad6f92d..42fa0570 100644 --- a/src/util/io/reader.cpp +++ b/src/util/io/reader.cpp @@ -21,33 +21,20 @@ IMPLEMENT_DYNAMIC_ARG(ReaderPragmaHandler,reader_pragma_handler,nullptr); // ----------------------------------------------------------------------------- : Reader -Reader::Reader(const InputStreamP& input, Packaged* package, const String& filename, bool ignore_invalid) +Reader::Reader(wxInputStream& input, Packaged* package, const String& filename, bool ignore_invalid) : indent(0), expected_indent(0), state(OUTSIDE) , ignore_invalid(ignore_invalid) , filename(filename), package(package), line_number(0), previous_line_number(0) , input(input) { - assert(input); - assert(input->IsOk()); - eat_utf8_bom(*input); + assert(input.IsOk()); + eat_utf8_bom(input); moveNext(); handleAppVersion(); } -Reader::Reader(Reader* parent, Packaged* pkg, const String& filename, bool ignore_invalid) - : indent(0), expected_indent(0), state(OUTSIDE) - , ignore_invalid(ignore_invalid) - , filename(filename), package(pkg), line_number(0), previous_line_number(0) - , input(package_manager.openFileFromPackage(package, filename)) -{ - assert(input); - eat_utf8_bom(*input); - moveNext(); - // in an included file, use the app version of the parent if we have none - handleAppVersion(); - if (file_app_version == 0) { - file_app_version = parent->file_app_version; - } +unique_ptr Reader::openIncludedFile() { + return package_manager.openFileFromPackage(package, value); } void Reader::addAlias(Version end_version, const Char* a, const Char* b) { @@ -125,11 +112,11 @@ void Reader::moveNext() { key.clear(); indent = -1; // if no line is read it never has the expected indentation // repeat until we have a good line - while (key.empty() && !input->Eof()) { + while (key.empty() && !input.Eof()) { readLine(); } // did we reach the end of the file? - if (key.empty() && input->Eof()) { + if (key.empty() && input.Eof()) { line_number += 1; indent = -1; } @@ -216,7 +203,7 @@ void Reader::readLine(bool in_string) { line_number += 1; // We have to do our own line reading, because wxTextInputStream is insane try { - line = read_utf8_line(*input); + line = read_utf8_line(input); } catch (const ParseError& e) { throw ParseError(e.what() + String(_(" on line ")) << line_number); } @@ -304,7 +291,7 @@ const String& Reader::getValue() { // read all lines that are indented enough readLine(true); previous_line_number = line_number; - while (indent >= expected_indent && !input->Eof()) { + while (indent >= expected_indent && !input.Eof()) { previous_value.resize(previous_value.size() + pending_newlines, _('\n')); pending_newlines = 0; previous_value += line.substr(expected_indent); // strip expected indent @@ -312,15 +299,15 @@ const String& Reader::getValue() { readLine(true); pending_newlines++; // skip empty lines that are not indented enough - } while(trim(line).empty() && indent < expected_indent && !input->Eof()); + } while(trim(line).empty() && indent < expected_indent && !input.Eof()); } // moveNext(), but without the initial readLine() state = HANDLED; - while (key.empty() && !input->Eof()) { + while (key.empty() && !input.Eof()) { readLine(); } // did we reach the end of the file? - if (key.empty() && input->Eof()) { + if (key.empty() && input.Eof()) { line_number += 1; indent = -1; } @@ -400,9 +387,9 @@ template <> void Reader::handle(FileName& f) { // 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 + auto out_stream = clipboard_package()->openOut(packaged_name); + auto in_stream = Package::openAbsoluteFile(str); + out_stream->Write(*in_stream); // copy f.assign(packaged_name); } catch (Error const&) { // ignore errors diff --git a/src/util/io/reader.hpp b/src/util/io/reader.hpp index 900fd563..b29f52e0 100644 --- a/src/util/io/reader.hpp +++ b/src/util/io/reader.hpp @@ -20,9 +20,6 @@ class Packaged; // ----------------------------------------------------------------------------- : Reader -typedef wxInputStream InputStream; -typedef shared_ptr InputStreamP; - /// The Reader can be used for reading (deserializing) objects /** This class makes use of the reflection functionality, in effect * an object tells the Reader what fields it would like to read. @@ -37,12 +34,12 @@ class Reader { /** Used for "include file" keys. * package can be nullptr */ - Reader(Reader* parent, Packaged* package, const String& filename, bool ignore_invalid = false); + //Reader(Reader* parent, Packaged* package, const String& filename, bool ignore_invalid = false); public: /// Construct a reader that reads from the given input stream /** filename is used only for error messages */ - Reader(const InputStreamP& input, Packaged* package = nullptr, const String& filename = wxEmptyString, bool ignore_invalid = false); + Reader(wxInputStream& input, Packaged* package = nullptr, const String& filename = wxEmptyString, bool ignore_invalid = false); ~Reader() { showWarnings(); } @@ -119,7 +116,7 @@ class Reader { // --------------------------------------------------- : Data /// App version this file was made with Version file_app_version; - private: +private: /// The line we read String line; /// The key and value of the last line we read @@ -156,7 +153,7 @@ class Reader { /// Line number of the previous_line int previous_line_number; /// Input stream we are reading from - InputStreamP input; + wxInputStream& input; /// Accumulated warning messages String warnings; @@ -182,14 +179,20 @@ class Reader { template void unknownKey(T& v) { if (key == _("include_file")) { - Reader reader(this, package, value, ignore_invalid); - reader.handle_greedy(v); + auto stream = openIncludedFile(); + Reader sub_reader(*stream, package, value, ignore_invalid); + if (sub_reader.file_app_version == 0) { + // in an included file, use the app version of the parent if there is none + sub_reader.file_app_version = file_app_version; + } + sub_reader.handle_greedy(v); moveNext(); } else { unknownKey(); } } void unknownKey(); + unique_ptr openIncludedFile(); }; // ----------------------------------------------------------------------------- : Container types diff --git a/src/util/io/writer.cpp b/src/util/io/writer.cpp index 2600dfcc..0b628d50 100644 --- a/src/util/io/writer.cpp +++ b/src/util/io/writer.cpp @@ -17,10 +17,10 @@ using boost::tribool; // ----------------------------------------------------------------------------- : Writer -Writer::Writer(const OutputStreamP& output, Version file_app_version) +Writer::Writer(OutputStream& output, Version file_app_version) : indentation(0) , output(output) - , stream(*output, wxEOL_UNIX, wxMBConvUTF8()) + , stream(output, wxEOL_UNIX, wxMBConvUTF8()) { stream.WriteString(BYTE_ORDER_MARK); handle(_("mse_version"), file_app_version); diff --git a/src/util/io/writer.hpp b/src/util/io/writer.hpp index 2d916c5c..43877f35 100644 --- a/src/util/io/writer.hpp +++ b/src/util/io/writer.hpp @@ -19,14 +19,11 @@ DECLARE_POINTER_TYPE(StyleSheet); // ----------------------------------------------------------------------------- : Writer -typedef wxOutputStream OutputStream; -typedef shared_ptr OutputStreamP; - /// The Writer can be used for writing (serializing) objects class Writer { public: /// Construct a writer that writes to the given output stream - Writer(const OutputStreamP& output, Version file_app_version); + Writer(OutputStream& output, Version file_app_version); /// Tell the reflection code we are not reading inline bool reading() const { return false; } @@ -81,7 +78,7 @@ class Writer { vector pending_opened; /// Output stream we are writing to - OutputStreamP output; + OutputStream& output; /// Text stream wrapping the output stream wxTextOutputStream stream;