From 8a86778bfbe1b8e4221effca17d887fcb6d8cbfe Mon Sep 17 00:00:00 2001 From: GenevensiS <66968533+G-e-n-e-v-e-n-s-i-S@users.noreply.github.com> Date: Mon, 4 May 2026 11:46:11 +0200 Subject: [PATCH] refactor card copy pasting --- src/data/format/clipboard.cpp | 51 +++++++++++------ src/data/format/clipboard.hpp | 13 +++-- src/gui/control/card_list.cpp | 105 ++++++++++++++++++++-------------- 3 files changed, 103 insertions(+), 66 deletions(-) diff --git a/src/data/format/clipboard.cpp b/src/data/format/clipboard.cpp index 7e2fa930..b0a9a1d7 100644 --- a/src/data/format/clipboard.cpp +++ b/src/data/format/clipboard.cpp @@ -61,9 +61,11 @@ IMPLEMENT_REFLECTION(WrappedCards) { } -wxDataFormat CardsDataObject::format(wxString("application/x-mse-cards")); +wxDataFormat CardsDataObject::format(wxString("application/x-mse-cards")); -CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector& cards) { +CardsDataObject::CardsDataObject(const SetP& set, const String& id, const vector& cards) + : wxCustomDataObject(format) +{ // set the stylesheet, so when deserializing we know whos style options we are reading vector has_styling; for (size_t i = 0 ; i < cards.size() ; ++i) { @@ -72,9 +74,15 @@ CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector< cards[i]->stylesheet = set->stylesheet; } } + + // store as raw bytes WrappedCards data = { set->game.get(), set->game->name(), id, cards }; - SetText(serialize_for_clipboard(*set, data)); - // restore cards + String serialized = serialize_for_clipboard(*set, data); + wxScopedCharBuffer utf8 = serialized.utf8_str(); + buffer.assign(utf8.data(), utf8.length()); + SetData(buffer.size(), buffer.data()); + + // restore styling for (size_t i = 0 ; i < cards.size() ; ++i) { if (has_styling[i]) { cards[i]->stylesheet = StyleSheetP(); @@ -83,22 +91,31 @@ CardsDataObject::CardsDataObject(const SetP& set, const String id, const vector< SetFormat(format); } -CardsDataObject::CardsDataObject() { - SetFormat(format); -} +CardsDataObject::CardsDataObject() + : wxCustomDataObject(format) +{} -bool CardsDataObject::getCards(const SetP& set, const String id, vector& out) { +bool CardsDataObject::getCards(const SetP& set, const String& id, vector& out) { + size_t size = GetSize(); + if (size == 0) return false; + const void* raw = GetData(); + if (!raw) return false; + + String text(wxString::FromUTF8(static_cast(raw), size)); WrappedCards data = { set->game.get(), set->game->name() }; - deserialize_from_clipboard(data, *set, GetText()); + try { + deserialize_from_clipboard(data, *set, text); + } catch (...) { + queue_message(MESSAGE_ERROR, _("DEBUG: Card deserialization failed")); + return false; + } + if (data.cards.empty()) return false; if (!id.empty() && data.id == id) return false; - if (data.game_name == set->game->name()) { - // Cards are from the same game - out = data.cards; - return true; - } else { - return false; - } + if (data.game_name != set->game->name()) return false; + // Cards are from the same game + out = data.cards; + return true; } // ----------------------------------------------------------------------------- : KeywordDataObject @@ -139,7 +156,7 @@ KeywordP KeywordDataObject::getKeyword(const SetP& set) { deserialize_from_clipboard(data, *set, GetText()); if (data.game_name != set->game->name()) return KeywordP(); // Keyword is from a different game else return keyword; -} +} // ----------------------------------------------------------------------------- : Card on clipboard diff --git a/src/data/format/clipboard.hpp b/src/data/format/clipboard.hpp index eef8047d..76cb2ec0 100644 --- a/src/data/format/clipboard.hpp +++ b/src/data/format/clipboard.hpp @@ -18,20 +18,23 @@ DECLARE_POINTER_TYPE(Keyword); // ----------------------------------------------------------------------------- : CardDataObject /// The data format for cards on the clipboard -class CardsDataObject : public wxTextDataObject { +class CardsDataObject : public wxCustomDataObject { public: /// Name of the format of MSE cards static wxDataFormat format; CardsDataObject(); /// Store a card - CardsDataObject(const SetP& set, const String id, const vector& cards); + CardsDataObject(const SetP& set, const String& id, const vector& cards); /// Retrieve the cards, only if this is made with the same game as set /// And if this is NOT of the same id as the given one /** Return true if the cards are correctly retrieved, and there is at least one card */ - bool getCards(const SetP& set, const String id, vector& out); -}; + bool getCards(const SetP& set, const String& id, vector& out); + +private: + std::string buffer; // keep data alive for wx +}; // ----------------------------------------------------------------------------- : KeywordDataObject @@ -44,7 +47,7 @@ public: KeywordDataObject(); /// Store a keyword KeywordDataObject(const SetP& set, const KeywordP& card); - + /// Retrieve a keyword, only if it is made with the same game as set KeywordP getKeyword(const SetP& set); }; diff --git a/src/gui/control/card_list.cpp b/src/gui/control/card_list.cpp index ccf300ee..d0883d2a 100644 --- a/src/gui/control/card_list.cpp +++ b/src/gui/control/card_list.cpp @@ -332,7 +332,11 @@ bool CardListBase::parseFiles(wxArrayString& filenames, vector& out) { // if it's an url, request the data std::ifstream ifs(filenames[i].ToStdString()); if (ifs.bad() || ifs.fail() || !ifs.good() || !ifs.is_open()) continue; - std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + bool looks_like_text = std::all_of(content.begin(), content.end(), [](char c) { + return isprint(c) || isspace(c); + }); + if (!looks_like_text) continue; wxString text(content); if (!parseUrl(text, out)) parseText(text, out); } @@ -356,9 +360,10 @@ bool CardListBase::parseImage(Image& image, vector& out) { } bool CardListBase::parseText(String& text, vector& out) { - size_t j = out.size(); - if (size_t pos = text.find("") != wxString::npos) { - text = text.substr(pos + 14, text.find("") - pos - 14); + size_t j = out.size(); + size_t pos = text.find(""); + if (pos != wxString::npos) { + text = text.substr(pos + 15, text.find("") - pos - 15); } try { ScriptValueP sv = json_to_mse(text, set.get()); @@ -386,54 +391,66 @@ bool CardListBase::parseText(String& text, vector& out) { bool CardListBase::parseData(bool ignore_cards_from_own_card_list) { wxBusyCursor wait; - wxDataFormat format = drop_target->data_object->GetReceivedFormat(); - wxDataObject *data = drop_target->data_object->GetObject(format); + wxDataObjectComposite* composite = drop_target->data_object; + wxDataFormat format = composite->GetReceivedFormat(); vector new_cards; - - if (CardsDataObject* card_data = dynamic_cast(data)) { + + if (format == CardsDataObject::format) { String id = ignore_cards_from_own_card_list ? drop_target->ignored_id : _(""); - card_data->getCards(set, id, new_cards); + size_t size = composite->GetDataSize(format); + if (size > 0) { + std::vector buffer(size); + if (composite->GetDataHere(format, buffer.data())) { + CardsDataObject card_data; + card_data.SetData(size, buffer.data()); + card_data.getCards(set, id, new_cards); + } + } } - else switch (format.GetType()) - { - case wxDF_FILENAME: + else { + wxDataObject *data = composite->GetObject(format); + + switch (format.GetType()) { - wxFileDataObject* file_data = static_cast(data); - wxArrayString filenames = file_data->GetFilenames(); - parseFiles(filenames, new_cards); - } - break; + case wxDF_FILENAME: + { + wxFileDataObject* file_data = static_cast(data); + wxArrayString filenames = file_data->GetFilenames(); + parseFiles(filenames, new_cards); + } + break; - case wxDF_PNG: - { - wxImageDataObject* image_data = static_cast(data); - Image image = image_data->GetImage(); - parseImage(image, new_cards); - } - break; + case wxDF_PNG: + { + wxImageDataObject* image_data = static_cast(data); + Image image = image_data->GetImage(); + parseImage(image, new_cards); + } + break; - case wxDF_BITMAP: - { - wxBitmapDataObject* bitmap_data = static_cast(data); - wxBitmap bitmap = bitmap_data->GetBitmap(); - Image image = bitmap.ConvertToImage(); - parseImage(image, new_cards); - } - break; + case wxDF_BITMAP: + { + wxBitmapDataObject* bitmap_data = static_cast(data); + wxBitmap bitmap = bitmap_data->GetBitmap(); + Image image = bitmap.ConvertToImage(); + parseImage(image, new_cards); + } + break; - case wxDF_UNICODETEXT: - case wxDF_TEXT: - case wxDF_HTML: - { - wxTextDataObject* text_data = static_cast(data); - String text = text_data->GetText(); - if (!parseUrl(text, new_cards)) parseText(text, new_cards); - } - break; + case wxDF_UNICODETEXT: + case wxDF_TEXT: + case wxDF_HTML: + { + wxTextDataObject* text_data = static_cast(data); + String text = text_data->GetText(); + if (!parseUrl(text, new_cards)) parseText(text, new_cards); + } + break; - default: - { - queue_message(MESSAGE_ERROR, _ERROR_("unknown data format")); + default: + { + queue_message(MESSAGE_ERROR, _ERROR_("unknown data format")); + } } }