From 0d328b750e2bc0a818e8224134ca753c236d858d Mon Sep 17 00:00:00 2001 From: twanvl Date: Thu, 19 Apr 2007 16:30:51 +0000 Subject: [PATCH] implemented apprentice export git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@267 0fc631ac-6414-0410-93d0-97cfa31319b6 --- data/en.mse-locale/locale | 10 +- src/data/card.hpp | 10 + src/data/format/apprentice.cpp | 778 ++++++++++++++++++++++++++++++++- src/data/format/formats.hpp | 3 + src/gui/set/window.cpp | 3 +- 5 files changed, 800 insertions(+), 4 deletions(-) diff --git a/data/en.mse-locale/locale b/data/en.mse-locale/locale index cd558502..e745c528 100644 --- a/data/en.mse-locale/locale +++ b/data/en.mse-locale/locale @@ -47,7 +47,7 @@ menu: add keyword: &Add Keyword Ctrl++ remove keyword: &Remove Select Keyword Del - format: &Format + format: F&ormat bold: &Bold Ctrl+B italic: &Italic Ctrl+I symbols: &Symbols Ctrl+M @@ -161,6 +161,9 @@ help: (When off, the cards are exported and copied at 100% size and normal rotation) + # apprentice export + set code: A set code is a two character code that is used by Apprentice to refer to a set. + # Symbol editor new symbol: Create a new symbol open symbol: Open a symbol @@ -366,6 +369,10 @@ label: cards to export: Cards to export filename is ignored: (filename is ignored) + # apprentice export + set code: Set &Code: + apprentice export cancled: Export to Apprentice is cancled + # Image slicer original: Original: result: Result: @@ -443,6 +450,7 @@ title: print preview: Print Preview # export export images: Export Images + export cancled: Export Cancled ############################################################## Action (undo/redo) names action: diff --git a/src/data/card.hpp b/src/data/card.hpp index dc5e76da..f619d134 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -55,6 +55,16 @@ class Card { } throw InternalError(_("Expected a card field with name '")+name+_("'")); } + template const T& value(const String& name) const { + for(IndexMap::const_iterator it = data.begin() ; it != data.end() ; ++it) { + if ((*it)->fieldP->name == name) { + const T* ret = dynamic_cast(it->get()); + if (!ret) throw InternalError(_("Card field with name '")+name+_("' doesn't have the right type")); + return *ret; + } + } + throw InternalError(_("Expected a card field with name '")+name+_("'")); + } DECLARE_REFLECTION(); }; diff --git a/src/data/format/apprentice.cpp b/src/data/format/apprentice.cpp index 5e85f472..0361fd16 100644 --- a/src/data/format/apprentice.cpp +++ b/src/data/format/apprentice.cpp @@ -7,5 +7,781 @@ // ----------------------------------------------------------------------------- : Includes #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -// ----------------------------------------------------------------------------- : +DECLARE_TYPEOF_COLLECTION(String); +DECLARE_TYPEOF_COLLECTION(CardP); +DECLARE_TYPEOF(map); + +String card_rarity_code(const String& rarity); + +// ----------------------------------------------------------------------------- : Generic export dialog + +/// Callback for updating a progress bar +class WithProgress { + public: + virtual void onProgress(float progress, const String& message) = 0; +}; + +/// Exception thrown to indicate exporting should be aborted +class AbortException {}; + +/// A dialog to show the progress of exporting +class ExportProgressDialog : public wxProgressDialog, public WithProgress { + public: + ExportProgressDialog(Window* parent, const String& title, const String& message); + + /// Update the progress bar + /** if the operation should be aborted, throws an AbortException + */ + virtual void onProgress(float progress, const String& message); +}; + +ExportProgressDialog::ExportProgressDialog(Window* parent, const String& title, const String& message) + : wxProgressDialog(title, message, 1000, parent, wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_CAN_ABORT) +{} + +void ExportProgressDialog::onProgress(float progress, const String& message) { + if (!Update(int(progress * 1000), message)) { + throw AbortException(); + } +} + +// ----------------------------------------------------------------------------- : Generic apprentice database + +/// An Apprentice database file, has read() and write() functions +class ApprDatabase { + public: + ApprDatabase(WithProgress* progress_target, const String& name); + ~ApprDatabase(); + + /// Read the database + void read(); + /// Write to a temporary file + void write(); + /// Finalize the writing, swap the actual and the temporary file + void commit(); + + protected: + virtual void doRead(wxInputStream&) = 0; + virtual void doWrite(wxOutputStream&) = 0; + + WithProgress* progress_target; ///< Write progress information to here + + private: + bool in_progress; ///< Is writing in progress? + String filename; ///< Filename of database file +}; + + +ApprDatabase::ApprDatabase(WithProgress* progress_target, const String& name) + : progress_target(progress_target) + , in_progress(false) + , filename(settings.apprentice_location + _("\\") + name) +{} +ApprDatabase::~ApprDatabase() { + // An exception is thrown while we were writing, clean up the temporary files + if (in_progress) { + // abort 'transaction' + wxRemoveFile(filename + _(".new")); + } +} + +void ApprDatabase::read() { + wxFileInputStream in(filename); + if (!in.Ok()) { + throw Error(_("Can not open apprentice file for input\n'") + filename + _("'")); + } + doRead(in); +} +void ApprDatabase::write() { + // write to a .new file, doesn't commit yet + if (wxFileExists(filename + _(".new"))) { + wxRemoveFile(filename + _(".new")); + } + wxFileOutputStream out(filename + _(".new")); + in_progress = true; + if (!out.Ok()) { + throw Error(_("Can not open apprentice file for output\n'") + filename + _(".new'")); + } + doWrite(out); +} +void ApprDatabase::commit() { + // commit : rename .new to real filename + if (in_progress) { + wxRenameFile(filename, filename + _(".bak")); + wxRenameFile(filename + _(".new"), filename); + in_progress = false; + } +} + +// ----------------------------------------------------------------------------- : Expansion database + +/// An Apprentice expansion database (Expan.dat) +class ApprExpansionDatabase : public ApprDatabase { + public: + inline ApprExpansionDatabase(WithProgress* progress_target) + : ApprDatabase(progress_target, _("Expan.dat")) + {} + protected: + virtual void doRead(wxInputStream& in); + virtual void doWrite(wxOutputStream& out); + + public: + map expansions; ///< code -> name + vector order; ///< order of codes +}; + +void ApprExpansionDatabase::doRead(wxInputStream& in) { + wxTextInputStream tin(in); + while (!in.Eof()) { + String l = tin.ReadLine(); + if (l.size() < 3) continue; + order.push_back(l.substr(0,2)); + expansions[l.substr(0,2)] = l.substr(3); + } +} + +void ApprExpansionDatabase::doWrite(wxOutputStream& out) { + wxTextOutputStream tout(out, wxEOL_DOS); + // write in order first + FOR_EACH(c, order) { + String code = c; + if (code.GetChar(0) != _('-')) { + // but not the rarities + tout << code << _("-") << expansions[c] << _("\n"); + expansions.erase(c); + } + } + // the remaing expansions (our new set) + FOR_EACH(e, expansions) { + String code = e.first; + if (code.GetChar(0) != _('-')) { + tout << code << _("-") << e.second << _("\n"); + } + } + // and at last the rarities + FOR_EACH(c, order) { + String code = c; + if (code.GetChar(0) == _('-')) { + tout << c << _("-") << expansions[c] << _("\n"); + } + } +} + +// ----------------------------------------------------------------------------- : Format database + +class ApprFormat { + public: + ApprFormat(const String& name) : name(name) {} + String name, sets; +}; + +DECLARE_TYPEOF_COLLECTION(ApprFormat); + +/// An Apprentice format database (Format.dat) +class ApprFormatDatabase : public ApprDatabase { + public: + inline ApprFormatDatabase(WithProgress* progress_target) + : ApprDatabase(progress_target, _("Format.dat")) + {} + /// Remove a set code from all formats + void removeSet(const String& code); + + protected: + virtual void doRead(wxInputStream& in); + virtual void doWrite(wxOutputStream& out); + + private: + vector formats; +}; + +void ApprFormatDatabase::removeSet(const String& code) { + // TODO? +} + +void ApprFormatDatabase::doRead(wxInputStream& in) { + wxTextInputStream tin(in); + // read titles + while (!in.Eof()) { + String l = trim(tin.ReadLine()); + if (l == _("")) { + // ignore header + } else if (l == _("")) { + break; // to formatting step + } else { + size_t pos = l.find_first_of(_('=')); + if (pos == String::npos) continue; + // assume formats are in order + formats.push_back( ApprFormat(l.substr(pos + 1)) ); + } + } + // read formats + size_t i = 0; + while (!in.Eof() && i < formats.size()) { + String l = trim(tin.ReadLine()); + size_t pos = l.find_first_of(_('=')); + if (pos == String::npos) continue; + formats[i].sets = l.substr(pos + 1); + i += 1; + } +} + +void ApprFormatDatabase::doWrite(wxOutputStream& out) { + wxTextOutputStream tout(out, wxEOL_DOS); + tout << _("\n"); + int i = 1; + FOR_EACH(f, formats) { + tout << i++ << _("=") << f.name << _("\n"); + } + tout << _("\n\n"); + i = 1; + FOR_EACH(f, formats) { + tout << i++ << _("=") << f.sets << _("\n"); + } +} + + +// ----------------------------------------------------------------------------- : Distro database + +// An entry in the Distro database +class ApprDistro { + public: + inline ApprDistro(int bc = 0, int bu = 0, int br = 0, int sc = 0, int su = 0, int sr = 0) + : bc(bc), bu(bu), br(br) + , sc(sc), su(su), sr(sr) + {} + + int bc, bu, br; ///< # of cards in booster of each rarity + int sc, su, sr; ///< .. in starter + + String scode, bcode; ///< alternative : numbers as a string (if numbers == 0) + + void write(const String& code, wxTextOutputStream& tout); + + private: + void writeD(wxTextOutputStream& tout, const String& name, int c, int u, int r); +}; + +DECLARE_TYPEOF(map); + +/// An Apprentice distribution database (Distro.dat) +class ApprDistroDatabase : public ApprDatabase { + public: + inline ApprDistroDatabase(WithProgress* progress_target) + : ApprDatabase(progress_target, _("Distro.dat")) + {} + /// Remove a set code + void removeSet(const String& code); + + protected: + virtual void doRead(wxInputStream& in); + virtual void doWrite(wxOutputStream& out); + + public: + map distros; + vector order; // order of codes +}; + + +void ApprDistroDatabase::removeSet(const String& code) { + // TODO ? +} + +void ApprDistroDatabase::doRead(InputStream& in) { + wxTextInputStream tin(in); + ApprDistro* last = 0; + while (!in.Eof()) { + String l = trim(tin.ReadLine()); + if (l.size() > 2 && l.GetChar(0) == _('<')) { + // new code + l = l.substr(1, l.size() - 2); + order.push_back(l); + last = &distros[l]; + } else if (last && starts_with(l, _("Starter"))) { + // no need to read the actual code, only to write it out later + // keep it as a string + last->scode = l; + } else if (last && starts_with(l, _("Booster"))) { + last->bcode = l; + } + } +} + +void ApprDistroDatabase::doWrite(OutputStream& out) { + wxTextOutputStream tout(out, wxEOL_DOS); + // write in order + FOR_EACH(c, order) { + distros[c].write(c, tout); + distros.erase(c); + } + // remaining distros (the newly added one) + FOR_EACH(d, distros) { + d.second.write(d.first, tout); + } +} + +void ApprDistro::write(const String& code, wxTextOutputStream& tout) { + tout.WriteString(_("<") + code + _(">\n")); + // starter + if (sc || su || sr) { + writeD(tout, _("Starter"), sc, su, sr); + } else if (!scode.empty()) { + tout.WriteString(_(" ") + scode + _("\n")); + } + // booster + if (bc || bu || br) { + writeD(tout, _("Booster"), bc, bu, br); + } else if (!bcode.empty()) { + tout.WriteString(_(" ") + bcode + _("\n")); + } +} + +void ApprDistro::writeD(wxTextOutputStream& tout, const String& name, int c, int u, int r) { + tout.WriteString(_(" ")+name+_("=R") << r << _(",U") << u << _(",C") << c << _("\n")); +} + +// ----------------------------------------------------------------------------- : Card database + +/// Untag function for apprentice, replaces newlines with \r\n +String untag_appr(const String& s) { + return replace_all(untag(s), _("\n"), _("\r\n")); +} + +DECLARE_POINTER_TYPE(ApprCardRecord); +DECLARE_TYPEOF_COLLECTION(ApprCardRecordP); + +/// An Apprentice card database (cardinfo.dat) +class ApprCardDatabase : public ApprDatabase { + public: + inline ApprCardDatabase(WithProgress* progress_target) + : ApprDatabase(progress_target, _("sets\\cardinfo.dat")) + {} + /// Remove a set code + void removeSet(const String& code); + + protected: + virtual void doRead(wxInputStream& in); + virtual void doWrite(wxOutputStream& out); + + public: + vector cards; +}; + +/// A single record in the apprentice card database +/** Each card has two records, a data record at the top of the file + * and a head record at the bottom + */ +class ApprCardRecord { + public: + String name, sets; + String type, cc, pt, text, flavor; + UInt data_pos; + Byte color; // bitmask: + enum Color { + white = 0x01, + blue = 0x02, + black = 0x04, + red = 0x08, + green = 0x10, + gold = 0x20, + arti = 0x40, + land = 0x80, + }; + + ApprCardRecord() {} + ApprCardRecord(const Card& card, const String& sets_); + + void readHead(wxDataInputStream& strm); + void readCard(wxDataInputStream& strm); + void writeHead(wxDataOutputStream& strm); + void writeCard(wxDataOutputStream& strm); + + /// Reads a string in apprentice format + String readString(wxDataInputStream& strm); + /// Writes a string in apprentice format + void writeString(wxDataOutputStream& strm, const String& out); + + // Remove a code from the list of set codes + void removeSet(const String& code); +}; + +// conversion from MSE2 card +ApprCardRecord::ApprCardRecord(const Card& card, const String& sets_) { + name = untag_appr(card.value(_("name")).value); + sets = sets_ + _("-") + card_rarity_code(card.value(_("rarity")).value); + cc = untag_appr(card.value(_("casting cost")).value); + type = untag_appr(card.value(_("super type")).value); + String subType = untag(card.value(_("sub type")).value); + if (!subType.empty()) type += _(" - ") + subType; + text = untag_appr(card.value(_("rule text")).value); + flavor = untag_appr(card.value(_("flavor text")).value); + pt = untag_appr(card.value(_("pt")).value); +} + + +void ApprCardRecord::readHead(wxDataInputStream& strm) { + name = readString(strm); + data_pos = strm.Read32(); + color = strm.Read8(); + sets = readString(strm); + strm.Read16(); // 00 00 +} +void ApprCardRecord::readCard(wxDataInputStream& strm) { + type = readString(strm); + cc = readString(strm); + pt = readString(strm); + text = readString(strm); + flavor = readString(strm); +} + +void ApprCardRecord::writeHead(wxDataOutputStream& strm) { + name = name.substr(0, 27); // max length + // determine color + color = 0; + int cnt = 0; + if (cc.find_first_of(_('W')) != String::npos) { cnt +=1; color |= white; } + if (cc.find_first_of(_('U')) != String::npos) { cnt +=1; color |= blue; } + if (cc.find_first_of(_('B')) != String::npos) { cnt +=1; color |= black; } + if (cc.find_first_of(_('R')) != String::npos) { cnt +=1; color |= red; } + if (cc.find_first_of(_('G')) != String::npos) { cnt +=1; color |= green; } + if (cnt > 1) color |= gold; + if (cnt == 0) { + if (type.find(_("Land")) != String::npos) color = land; + else color = arti; + } + // write + writeString(strm, name); + strm.Write32(data_pos); + strm.Write8(color); + writeString(strm, sets); + strm.Write16(0x0000); +} +void ApprCardRecord::writeCard(wxDataOutputStream& strm) { + writeString(strm, type); + writeString(strm, cc); + writeString(strm, pt); + writeString(strm, text); + writeString(strm, flavor); +} + +String ApprCardRecord::readString(wxDataInputStream& strm) { + size_t size = strm.Read16(); + if (size > 1000) size = 1000; // sanity check + String ret; + ret.reserve(size); + for (size_t i = 0 ; i < size ; ++i) { + ret += (Char) strm.Read8(); + } + return ret; +} + +void ApprCardRecord::writeString(wxDataOutputStream& strm, const String& out) { + strm.Write16(UInt(out.size())); + FOR_EACH_CONST(c, out) { + strm.Write8(c); + } +} + +void ApprCardRecord::removeSet(const String& code) { + size_t pos = sets.find(code); + if (pos == String::npos) return; + String before = sets.substr(0, pos); + String after = sets.substr(pos + code.size()); + if (!before.empty() && before.GetChar(before.size()-1) == _(',')) { + // remove comma + before.resize(before.size() - 1); + } + sets = before + after; +} + +// Is a card record unused, i.e. no sets refer to it? +bool unused_appr_card_record(const ApprCardRecordP& rec) { + return rec->sets.size() < 2 || // nothing + (rec->sets.size() < 4 && rec->sets.find_first_of(_('-')) != String::npos); // only a rarity code +} + + + +void ApprCardDatabase::removeSet(const String& code) { + FOR_EACH(c, cards) { + c->removeSet(code); + } + // cleanup + cards.erase(remove_if(cards.begin(), cards.end(), unused_appr_card_record), cards.end()); +} + +void ApprCardDatabase::doRead(wxInputStream& in) { + wxDataInputStream data(in); + size_t head_pos = data.Read32(); + in.SeekI(head_pos); + size_t card_count = data.Read32(); + cards.resize(card_count); + // read cards + int i = 0; + FOR_EACH(card, cards) { + if (++i % 100 == 0) { + // report progress sometimes + progress_target->onProgress(0.4f * float(i) / cards.size(), + String(_("reading card ")) << i << _(" of ") << (int)cards.size()); + } + card = new_shared(); + card->readHead(data); + head_pos = in.TellI(); + in.SeekI(card->data_pos); + card->readCard(data); + in.SeekI(head_pos); + } +} + +void ApprCardDatabase::doWrite(wxOutputStream& out) { + wxDataOutputStream data(out); + data.Write32(0); // replaced with header pos + // write card data + int i = 0; + FOR_EACH(card, cards) { + if (++i % 100 == 0) { + // report progress sometimes + progress_target->onProgress(0.4f + 0.4f * float(i) / cards.size(), + String(_("writing card ")) << i << _(" of ") << (int)cards.size()); + } + card->data_pos = out.TellO(); + card->writeCard(data); + } + // write header location + UInt head_start = out.TellO(); + out.SeekO(0); + data.Write32(head_start); + // card count + out.SeekO(head_start); + data.Write32((UInt)cards.size()); + // write card heads + i = 0; + FOR_EACH(card, cards) { + if (++i % 100 == 0) { + // report progress sometimes + progress_target->onProgress(0.8f + 0.2f * float(i) / cards.size(), + String(_("writing header ")) << i << _(" of ") << (int)cards.size()); + } + card->writeHead(data); + } +} + + + + + +// ----------------------------------------------------------------------------- : Export dialog + +/// Dialog for exporting a set to Apprentice +class ApprenticeExportWindow : public wxDialog, public WithProgress { + public: + ApprenticeExportWindow(Window* parent, const SetP& set); + + virtual void onProgress(float p, const String& message); + void doStep(const String& s, float size); + + private: + DECLARE_EVENT_TABLE(); + SetP set; + + // Gui controls + wxTextCtrl *apprentice, *set_code; + + // In what step of the export process are we? + String step; + float step_begin, step_end; + ExportProgressDialog* progress_target; + + void onApprenticeBrowse(wxCommandEvent& ev); + void onOk(wxCommandEvent& ev); + + /// Export the set + bool export(); +}; + + +void export_apprentice(Window* parent, const SetP& set) { + ApprenticeExportWindow wnd(parent, set); + wnd.ShowModal(); +} + + +ApprenticeExportWindow::ApprenticeExportWindow(Window* parent, const SetP& set) + : wxDialog(parent, wxID_ANY, _("Export to Apprentice"), wxDefaultPosition) + , set(set) + , step_begin(0), step_end(0) +{ + if (!set->game->isMagic()) throw Error(_("Can only export Magic sets to Apprentice")); + + // create controls + apprentice = new wxTextCtrl(this, wxID_ANY); + set_code = new wxTextCtrl(this, wxID_ANY); + wxButton* browse = new wxButton(this, ID_APPRENTICE_BROWSE , _BUTTON_("browse")); + // set values + apprentice->SetValue(settings.apprentice_location); + set_code->SetValue(set->apprentice_code); + // init sizer + wxSizer* s = new wxBoxSizer(wxVERTICAL); + // Apprentice location + s->Add(new wxStaticText(this, wxID_ANY, _TITLE_("locate apprentice")), 0, wxALL, 4); + wxSizer* s2 = new wxBoxSizer(wxHORIZONTAL); + s2->Add(apprentice, 1, wxEXPAND | wxRIGHT, 4); + s2->Add(browse, 0, wxEXPAND); + s->Add(s2, 0, wxEXPAND | wxALL & ~wxTOP, 4); + s->AddSpacer(8); + // Set code + s->Add(new wxStaticText(this, -1, _LABEL_("set code")), 0, wxALL, 4); + s->Add(set_code, 0, wxEXPAND | wxLEFT | wxRIGHT, 4); + s->Add(new wxStaticText(this, -1, _HELP_( "set code")), 0, wxALL, 4); + s->AddSpacer(4); + s->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxALL & ~wxTOP, 8); + s->SetSizeHints(this); + SetSizer(s); +} + +void ApprenticeExportWindow::onApprenticeBrowse(wxCommandEvent& ev) { + // browse for appr.exe + // same as in DirsPreferencesPage + wxFileDialog dlg(this, _TITLE_("locate apprentice"), apprentice->GetValue(), _(""), _LABEL_("apprentice exe") + _("|appr.exe"), wxOPEN); + if (dlg.ShowModal() == wxID_OK) { + wxFileName fn(dlg.GetPath()); + apprentice->SetValue(fn.GetPath()); + } +} + +void ApprenticeExportWindow::onOk(wxCommandEvent& ev) { + // store settings + settings.apprentice_location = apprentice->GetValue(); + // store new code + String new_set_code = set_code->GetValue(); + if (new_set_code.size() != 2) { + wxMessageBox(_("The set code must be 2 characters long"), + _("Invalid set code"), wxOK | wxICON_ERROR); + return; + } + new_set_code.MakeUpper(); + set->apprentice_code.MakeUpper(); + if (set->apprentice_code != new_set_code) { + // changed something in the set + set->apprentice_code = new_set_code; + //%%set->actions.atSavePoint = false; // tell the user he needs to save + } + // Check if apprentice exists + if (!wxFileExists(settings.apprentice_location + _("\\appr.exe"))) { + wxMessageBox(_("Apprentice is not found in the specified location\n") + settings.apprentice_location, + _("Apprentice Not Found"), wxOK | wxICON_ERROR); + return; + } + // create progress dialog + progress_target = new ExportProgressDialog(this, _("Export to Apprentice"), _("Exporting to Apprentice, please wait")); + progress_target->Show(); + // export! + try { + if (!export()) { + // canceled, but allow to try again + progress_target->Hide(); + progress_target->Close(); + return; + } + } catch (const AbortException&) { + // aborted, cleanup is already handled by dtors + wxMessageBox(_LABEL_("apprentice export cancled"), _TITLE_("export canceled"), wxOK | wxICON_INFORMATION); + } + // Done, close progress window + progress_target->Hide(); + progress_target->Close(); + // Close this window + EndModal(wxID_OK); +} + +bool ApprenticeExportWindow::export() { + // Expan database + doStep(_("Exporting expansion"), 0.01f); + ApprExpansionDatabase expan(this); + expan.read(); + // Is there already a set with the desired code? + map::iterator expan_it = expan.expansions.find(set->apprentice_code); + if (expan_it != expan.expansions.end()) { + int res = wxMessageBox( + _("There is already a set with the code '")+ expan_it->first +_("' in the Apprentice database.\n") + + _("This set has the name '")+ expan_it->second +_("'\n") + + _("Do you want to continue, and overwrite that set?"), + _("Overwrite Set?"), wxYES_NO | wxICON_EXCLAMATION + ); + if (res == wxNO) return false; // abort export + } + // add our set + expan.expansions[set->apprentice_code] = set->value(_("title")).value; + expan.write(); + + // Format database + doStep(_("Exporting format"), 0.01f); + ApprFormatDatabase format(this); + format.read(); + // remove old with code, TODO add new? + format.removeSet(set->apprentice_code); + format.write(); + + // Distro database + doStep(_("Exporting distribution"), 0.01f); + ApprDistroDatabase distro(this); + distro.read(); + // remove old with code, add new + distro.removeSet(set->apprentice_code); + distro.distros[set->apprentice_code] = ApprDistro(11,3,1); // booster size + distro.write(); + + // Card database + doStep(_("Exporting cards"), 0.96f); + ApprCardDatabase cardlist(this); + cardlist.read(); + // remove old cards with same code + cardlist.removeSet(set->apprentice_code); + // add cards from set + FOR_EACH(card, set->cards) { + ApprCardRecordP rec = new_shared2(*card, set->apprentice_code); + cardlist.cards.push_back(rec); + } + cardlist.write(); + + // Commit everything + doStep(_("Committing"), 0.01f); + expan.commit(); + format.commit(); + distro.commit(); + cardlist.commit(); + + return true; // all went well +} + +void ApprenticeExportWindow::onProgress(float p, const String& m) { + progress_target->onProgress( + p * (step_end - step_begin) + step_begin, + m.empty() ? step : step + _(": ") + m + ); +} +void ApprenticeExportWindow::doStep(const String& s, float size) { + step = s; + step_begin = step_end; + step_end += size; + onProgress(0.0f, _("")); +} + + + +BEGIN_EVENT_TABLE(ApprenticeExportWindow, wxDialog) + EVT_BUTTON (wxID_OK, ApprenticeExportWindow::onOk) + EVT_BUTTON (ID_APPRENTICE_BROWSE, ApprenticeExportWindow::onApprenticeBrowse) +END_EVENT_TABLE () diff --git a/src/data/format/formats.hpp b/src/data/format/formats.hpp index e2b84dbf..5e23827b 100644 --- a/src/data/format/formats.hpp +++ b/src/data/format/formats.hpp @@ -94,5 +94,8 @@ Bitmap export_bitmap(const SetP& set, const CardP& card); /// Export a set to Magic Workstation format void export_mws(Window* parent, const SetP& set); +/// Export a set to Apprentice +void export_apprentice(Window* parent, const SetP& set); + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/gui/set/window.cpp b/src/gui/set/window.cpp index 5ba5128a..fa431d7d 100644 --- a/src/gui/set/window.cpp +++ b/src/gui/set/window.cpp @@ -458,8 +458,7 @@ void SetWindow::onFileExportHTML(wxCommandEvent&) { } void SetWindow::onFileExportApprentice(wxCommandEvent&) { -// ApprenticeExportWindow wnd(&this, set); -// wnd.ShowModal(); + export_apprentice(this, set); } void SetWindow::onFileExportMWS(wxCommandEvent&) {