From 62ff837352e41938ffebdd9b1ee88e994b043dd7 Mon Sep 17 00:00:00 2001 From: coppro Date: Mon, 21 May 2007 16:11:38 +0000 Subject: [PATCH] Added thread-safety to thumbnail request system. Marked symbol requests as not being thread-safe. Added icon to symbol editor Made *.* actually register on * git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@407 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/format/formats.cpp | 2 +- src/data/format/mws.cpp | 2 +- src/gfx/generated_image.hpp | 19 +++++++++++++ src/gui/control/image_card_list.cpp | 2 ++ src/gui/control/package_list.hpp | 2 +- src/gui/images_export_window.cpp | 2 +- src/gui/symbol/window.cpp | 1 + src/gui/thumbnail_thread.cpp | 44 ++++++++++++++++++++++------- src/gui/thumbnail_thread.hpp | 3 ++ src/gui/value/choice.cpp | 10 ++++++- src/script/image.hpp | 3 ++ 11 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/data/format/formats.cpp b/src/data/format/formats.cpp index 3e9399f0..d9a07a52 100644 --- a/src/data/format/formats.cpp +++ b/src/data/format/formats.cpp @@ -33,7 +33,7 @@ String import_formats() { type_strings += _("|") + f->name() + _("|*.") + f->extension(); } } - return _("Set files|") + all_extensions + type_strings + _("|All files (*.*)|*.*"); + return _("Set files|") + all_extensions + type_strings + _("|All files (*.*)|*"); } String export_formats(const Game& game) { diff --git a/src/data/format/mws.cpp b/src/data/format/mws.cpp index e8922c4e..16557ca8 100644 --- a/src/data/format/mws.cpp +++ b/src/data/format/mws.cpp @@ -59,7 +59,7 @@ void export_mws(Window* parent, const SetP& set) { // Select filename String name = wxFileSelector(_("Export to file"),_(""),_(""),_(""), - _("Text files (*.txt)|*.txt|All Files|*.*"), + _("Text files (*.txt)|*.txt|All Files|*"), wxSAVE | wxOVERWRITE_PROMPT, parent); if (name.empty()) return; wxBusyCursor busy; diff --git a/src/gfx/generated_image.hpp b/src/gfx/generated_image.hpp index d2422751..a28c3174 100644 --- a/src/gfx/generated_image.hpp +++ b/src/gfx/generated_image.hpp @@ -45,6 +45,9 @@ class GeneratedImage : public ScriptValue { /// Equality should mean that every pixel in the generated images is the same if the same options are used virtual bool operator == (const GeneratedImage& that) const = 0; inline bool operator != (const GeneratedImage& that) const { return !(*this == that); } + + /// Can this image be generated safely from another thread? + virtual bool threadSafe() const = 0; virtual ScriptType type() const; virtual String typeName() const; @@ -61,6 +64,8 @@ class LinearBlendImage : public GeneratedImage { virtual Image generate(const Options& opt) const; virtual ImageCombine combine() const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: GeneratedImageP image1, image2; double x1, y1, x2, y2; @@ -77,6 +82,8 @@ class MaskedBlendImage : public GeneratedImage { virtual Image generate(const Options& opt) const; virtual ImageCombine combine() const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: GeneratedImageP light, dark, mask; }; @@ -92,6 +99,8 @@ class CombineBlendImage : public GeneratedImage { virtual Image generate(const Options& opt) const; virtual ImageCombine combine() const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: GeneratedImageP image1, image2; ImageCombine image_combine; @@ -108,6 +117,8 @@ class SetMaskImage : public GeneratedImage { virtual Image generate(const Options& opt) const; virtual ImageCombine combine() const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: GeneratedImageP image, mask; }; @@ -123,6 +134,8 @@ class SetCombineImage : public GeneratedImage { virtual Image generate(const Options& opt) const; virtual ImageCombine combine() const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: GeneratedImageP image; ImageCombine image_combine; @@ -138,6 +151,8 @@ class PackagedImage : public GeneratedImage { {} virtual Image generate(const Options& opt) const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: String filename; }; @@ -152,6 +167,8 @@ class BuiltInImage : public GeneratedImage { {} virtual Image generate(const Options& opt) const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return true;} private: String name; }; @@ -165,6 +182,8 @@ class SymbolToImage : public GeneratedImage { ~SymbolToImage(); virtual Image generate(const Options& opt) const; virtual bool operator == (const GeneratedImage& that) const; + + virtual bool threadSafe() const {return false;} private: SymbolToImage(const SymbolToImage&); // copy ctor String filename; diff --git a/src/gui/control/image_card_list.cpp b/src/gui/control/image_card_list.cpp index 76c9de55..cbc0929f 100644 --- a/src/gui/control/image_card_list.cpp +++ b/src/gui/control/image_card_list.cpp @@ -84,6 +84,8 @@ class CardThumbnailRequest : public ThumbnailRequest { parent->Refresh(false); } } + + virtual bool threadSafe() const {return true;} private: String filename; }; diff --git a/src/gui/control/package_list.hpp b/src/gui/control/package_list.hpp index 19479691..12e43499 100644 --- a/src/gui/control/package_list.hpp +++ b/src/gui/control/package_list.hpp @@ -29,7 +29,7 @@ class PackageList : public GalleryList { } /// Shows packages that match a specific patern - void showData(const String& pattern = _("*.*")); + void showData(const String& pattern = _("*")); /// Clears this list void clear(); diff --git a/src/gui/images_export_window.cpp b/src/gui/images_export_window.cpp index 27402003..517c1e9f 100644 --- a/src/gui/images_export_window.cpp +++ b/src/gui/images_export_window.cpp @@ -73,7 +73,7 @@ void ImagesExportWindow::onOk(wxCommandEvent&) { ScriptP filename_script = parse(gs.images_export_filename, true); // Select filename String name = wxFileSelector(_TITLE_("export images"),_(""), _LABEL_("filename is ignored"),_(""), - _LABEL_("filename is ignored")+_("|*.*"), wxSAVE, this); + _LABEL_("filename is ignored")+_("|*"), wxSAVE, this); if (name.empty()) return; wxFileName fn(name); // Export diff --git a/src/gui/symbol/window.cpp b/src/gui/symbol/window.cpp index 619dcd9a..1652dedd 100644 --- a/src/gui/symbol/window.cpp +++ b/src/gui/symbol/window.cpp @@ -54,6 +54,7 @@ SymbolWindow::SymbolWindow(Window* parent, const SymbolValueP& value, const SetP void SymbolWindow::init(Window* parent, SymbolP symbol) { Create(parent, wxID_ANY, _TITLE_("symbol editor"), wxDefaultPosition, wxSize(600,600), wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE); + SetIcon(load_resource_icon(_("app"))); inSelectionEvent = false; // Menu bar diff --git a/src/gui/thumbnail_thread.cpp b/src/gui/thumbnail_thread.cpp index c7bdb98f..eed080c5 100644 --- a/src/gui/thumbnail_thread.cpp +++ b/src/gui/thumbnail_thread.cpp @@ -130,17 +130,41 @@ void ThumbnailThread::request(const ThumbnailRequestP& request) { return; } } - request_names.insert(request); - // request generation - { - wxMutexLocker lock(mutex); - open_requests.push_back(request); + if (request->threadSafe()) { + request_names.insert(request); + // request generation + { + wxMutexLocker lock(mutex); + open_requests.push_back(request); + } + // is there a worker? + if (!worker) { + worker = new ThumbnailThreadWorker(this); + worker->Create(); + worker->Run(); + } } - // is there a worker? - if (!worker) { - worker = new ThumbnailThreadWorker(this); - worker->Create(); - worker->Run(); + else { + Image img; + try { + img = request->generate(); + } catch (const Error& e) { + handle_error(e, false, false); + } catch (...) { + } + // store in cache + if (img.Ok()) { + String filename = image_cache_dir() + safe_filename(request->cache_name) + _(".png"); + img.SaveFile(filename, wxBITMAP_TYPE_PNG); + // set modification time + wxFileName fn(filename); + fn.SetTimes(0, &request->modified, 0); + } + { + wxMutexLocker lock(mutex); + closed_requests.push_back(make_pair(request,img)); + completed.Signal(); + } } } diff --git a/src/gui/thumbnail_thread.hpp b/src/gui/thumbnail_thread.hpp index 479179ca..7e63926a 100644 --- a/src/gui/thumbnail_thread.hpp +++ b/src/gui/thumbnail_thread.hpp @@ -31,6 +31,9 @@ class ThumbnailRequest : public IntrusivePtrVirtualBase { virtual Image generate() = 0; /// Store the thumbnail, called from the main thread virtual void store(const Image&) = 0; + + /// Can the thumbnail safely be generated from another thread? + virtual bool threadSafe() const = 0; /// Object that requested the thumbnail void* const owner; diff --git a/src/gui/value/choice.cpp b/src/gui/value/choice.cpp index 7c6712b5..46b0aea1 100644 --- a/src/gui/value/choice.cpp +++ b/src/gui/value/choice.cpp @@ -23,6 +23,9 @@ class ChoiceThumbnailRequest : public ThumbnailRequest { ChoiceThumbnailRequest(ValueViewer* cve, int id, bool from_disk); virtual Image generate(); virtual void store(const Image&); + + bool isThreadSafe; + virtual bool threadSafe() const {return isThreadSafe;} private: StyleSheetP stylesheet; int id; @@ -37,7 +40,12 @@ ChoiceThumbnailRequest::ChoiceThumbnailRequest(ValueViewer* cve, int id, bool fr ) , stylesheet(cve->viewer.stylesheet) , id(id) -{} +{ + ChoiceValueEditor& e = *(ChoiceValueEditor*)cve; + String name = cannocial_name_form(e.field().choices->choiceName(id)); + ScriptableImage& img = e.style().choice_images[name]; + isThreadSafe = img.threadSafe(); +} Image ChoiceThumbnailRequest::generate() { ChoiceValueEditor& cve = *(ChoiceValueEditor*)owner; diff --git a/src/script/image.hpp b/src/script/image.hpp index 3cb891b0..98dc1c9b 100644 --- a/src/script/image.hpp +++ b/src/script/image.hpp @@ -45,6 +45,9 @@ class ScriptableImage { inline void initDependencies(Context& ctx, const Dependency& dep) const { script.initDependencies(ctx, dep); } + + /// Can this be safely generated from another thread? + bool threadSafe() const {return value->threadSafe();} private: OptionalScript script; ///< The script, not really optional