From 9c18ed51e2de20b00385be5c1828df56afe0ad76 Mon Sep 17 00:00:00 2001 From: twanvl Date: Sat, 31 May 2008 14:02:53 +0000 Subject: [PATCH] Put PackageUpdateList into its own file git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@904 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/installer.cpp | 8 +- src/data/installer.hpp | 14 +- src/gui/package_update_list.cpp | 298 +++++++++++++++++++++++++++ src/gui/package_update_list.hpp | 80 ++++++++ src/gui/packages_window.cpp | 343 +------------------------------- src/gui/packages_window.hpp | 8 +- src/mse.vcproj | 34 ++-- src/util/io/package_manager.cpp | 4 +- 8 files changed, 427 insertions(+), 362 deletions(-) create mode 100644 src/gui/package_update_list.cpp create mode 100644 src/gui/package_update_list.hpp diff --git a/src/data/installer.cpp b/src/data/installer.cpp index 0ab56bac..3e00eba3 100644 --- a/src/data/installer.cpp +++ b/src/data/installer.cpp @@ -254,9 +254,9 @@ DownloadableInstaller::~DownloadableInstaller() { // ----------------------------------------------------------------------------- : Installable package -InstallablePackage::InstallablePackage(const PackageVersionP& installed, const PackageDescriptionP& description) - : installed(installed) - , description(description) +InstallablePackage::InstallablePackage(const PackageDescriptionP& description, const PackageVersionP& installed) + : description(description) + , installed(installed) , status(PACKAGE_INSTALLED) , action(PACKAGE_NOTHING) {} @@ -586,5 +586,5 @@ InstallablePackageP mse_installable_package() { mse_description->position_hint = -100; mse_description->icon = load_resource_image(_("installer_program")); //mse_description->description = _LABEL_("magic set editor package"); - return new_intrusive2(mse_version,mse_description); + return new_intrusive2(mse_description, mse_version); } diff --git a/src/data/installer.hpp b/src/data/installer.hpp index dffd8640..f60cfd3d 100644 --- a/src/data/installer.hpp +++ b/src/data/installer.hpp @@ -18,6 +18,13 @@ DECLARE_POINTER_TYPE(PackageDescription); DECLARE_POINTER_TYPE(DownloadableInstaller); DECLARE_POINTER_TYPE(InstallablePackage); +// The installer system consists of several layers: +// - Installer = an actual package available in memory, containing packages to be installed +// - DownloadableInstaller = an installar (possibly) not yet available, i.e. just its URL +// - PackageDescription = description of a package version +// - InstallablePackage = the complete status of a package, both local and remote + + // ----------------------------------------------------------------------------- : Installer /// A package that contains other packages that can be installed @@ -125,12 +132,13 @@ inline bool flag(int flags, int flag) { return (flags & flag) == flag; } /// A package that can be installed, or is already installed class InstallablePackage : public IntrusivePtrVirtualBase { public: - //InstallablePackage(); + /// A new package InstallablePackage(const PackageDescriptionP&, const DownloadableInstallerP&); - InstallablePackage(const PackageVersionP&, const PackageDescriptionP&); + /// An installed package + InstallablePackage(const PackageDescriptionP&, const PackageVersionP&); - PackageVersionP installed; ///< The information of the installed package (if installed) PackageDescriptionP description; ///< The details of the package. Either from the installed package or from an installer + PackageVersionP installed; ///< The information of the installed package (if installed) DownloadableInstallerP installer; ///< The installer to install from (if updates are available) PackageStatus status; ///< Status of installation PackageAction action; ///< What to do with this package? diff --git a/src/gui/package_update_list.cpp b/src/gui/package_update_list.cpp new file mode 100644 index 00000000..f4859f1e --- /dev/null +++ b/src/gui/package_update_list.cpp @@ -0,0 +1,298 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_TYPEOF_COLLECTION(InstallablePackageP); +DECLARE_TYPEOF_COLLECTION(PackageUpdateList::TreeItemP); +DECLARE_TYPEOF_COLLECTION(TreeList::ItemP); + + +// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem + +void PackageUpdateList::TreeItem::add(const InstallablePackageP& package, const String& path, int level) { + // this node + this->level = level; + PackageType new_type = package_type(*package->description); + int new_hint = package->description->position_hint; + if (new_type < position_type || (new_type == position_type && new_hint < position_hint)) { + // this is a lower position hint, use it + position_type = new_type; + position_hint = new_hint; + } + // end of the path? + if (path.empty()) { + assert(!this->package); + this->package = package; + return; + } + // split path + size_t pos = path.find_first_of(_('/')); + String name = path.substr(0,pos); + String rest = pos == String::npos ? _("") : path.substr(pos+1); + // find/add child + FOR_EACH(ti, children) { + if (ti->label == name) { + // already have this child + if (pos == String::npos && ti->package) { + // two packages with the same path + TreeItemP ti2(new TreeItem); + ti2->label = name; + children.insert(ti_IT.first, ti2); + ti2->add(package, rest, level + 1); + } else { + ti->add(package, rest, level + 1); + } + return; + } + } + // don't have this child + TreeItemP ti(new TreeItem); + children.push_back(ti); + ti->label = name; + ti->add(package, rest, level + 1); +} + +bool compare_pos_hint(const PackageUpdateList::TreeItemP& a, const PackageUpdateList::TreeItemP& b) { + if (a->position_type < b->position_type) return true; + if (a->position_type > b->position_type) return false; + if (a->position_hint < b->position_hint) return true; + if (a->position_hint > b->position_hint) return false; + return a->label < b->label; +} + +void PackageUpdateList::TreeItem::toItems(vector& items) { + sort(children.begin(), children.end(), compare_pos_hint); + FOR_EACH(c, children) { + items.push_back(c); + c->toItems(items); + } +} + +bool PackageUpdateList::TreeItem::highlight() const { + if (package && package->willBeInstalled()) return true; + FOR_EACH_CONST(c,children) if (c->highlight()) return true; + return false; +} + +PackageUpdateList::TreeItem::PackageType PackageUpdateList::TreeItem::package_type(const PackageDescription& desc) { + if (desc.name == mse_package) return TYPE_PROG; + size_t pos = desc.name.find_last_of(_('.')); + if (pos == String::npos) return TYPE_OTHER; + if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE; + if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME; + if (is_substr(desc.name,pos,_(".mse-style"))) return TYPE_STYLESHEET; + if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE; + if (is_substr(desc.name,pos,_(".mse-symbol-font"))) return TYPE_SYMBOL_FONT; + if (is_substr(desc.name,pos,_(".mse-include"))) return TYPE_INCLUDE; + if (is_substr(desc.name,pos,_(".ttf"))) return TYPE_FONT; + return TYPE_OTHER; +} + +void PackageUpdateList::TreeItem::setIcon(const Image& img) { + Image image = img; + int iw = image.GetWidth(), ih = image.GetHeight(); + if (ih > 107) { + int w = 107 * iw / ih; + image = resample(image, w, 107); + } else if (iw > 107) { + int h = 107 * ih / iw; + image = resample(image, 107, h); + } + if (package) package->description->icon = image; + Image resampled = resample_preserve_aspect(image,16,16); + icon = Bitmap(resampled); + saturate(resampled, -.75); + set_alpha(resampled,0.5); + icon_grey = Bitmap(resampled); +} + + +// ----------------------------------------------------------------------------- : PackageIconRequest + +/// wx doesn't allow seeking on InputStreams from a wxURL +/// The built in buffer class is too stupid to seek, so we must do it ourselfs +class SeekAtStartInputStream : public wxFilterInputStream { + public: + SeekAtStartInputStream(wxInputStream& stream) + : wxFilterInputStream(stream) + , buffer_pos(0) + { + m_parent_i_stream->Read(buffer, 1024); + buffer_size = m_parent_i_stream->LastRead(); + } + + bool IsSeekable() const { return true; } + protected: + virtual size_t OnSysRead(void *buffer, size_t bufsize) { + size_t len = min(buffer_size - buffer_pos, bufsize); + memcpy(buffer, this->buffer + buffer_pos, len); + buffer_pos += len; + m_parent_i_stream->Read((Byte*)buffer + len, bufsize - len); + return m_parent_i_stream->LastRead() + len; + } + virtual wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode) { + if (mode == wxFromStart) buffer_pos = seek; + else if (mode == wxFromCurrent) buffer_pos += seek; + else assert(false); + assert(buffer_pos < buffer_size); + return buffer_pos; + } + virtual wxFileOffset OnSysTell() const { + assert(buffer_pos < buffer_size); + return buffer_pos; + } + private: + size_t buffer_size, buffer_pos; + Byte buffer[1024]; +}; + +class PackageIconRequest : public ThumbnailRequest { + public: + PackageIconRequest(PackageUpdateList* list, PackageUpdateList::TreeItem* ti) + : ThumbnailRequest( + list, + _("package_") + ti->package->description->icon_url + _("_") + ti->package->description->version.toString(), + wxDateTime(1,wxDateTime::Jan,2000)) + , list(list), ti(ti) + {} + + virtual Image generate() { + wxURL url(ti->package->description->icon_url); + scoped_ptr isP(url.GetInputStream()); + if (!isP) return wxImage(); + SeekAtStartInputStream is2(*isP); + Image result(is2); + return result; + } + virtual void store(const Image& image) { + if (!image.Ok()) return; + ti->setIcon(image); + list->Refresh(false); + } + private: + PackageUpdateList* list; + PackageUpdateList::TreeItem* ti; +}; + + +// ----------------------------------------------------------------------------- : PackageUpdateList : implementation + +PackageUpdateList::PackageUpdateList(Window* parent, const InstallablePackages& packages, int id) + : TreeList(parent, id) + , packages(packages) +{ + item_height = max(item_height,17); + rebuild(); +} +PackageUpdateList::~PackageUpdateList() { + thumbnail_thread.abort(this); +} + +void PackageUpdateList::initItems() { + // add packages to tree + TreeItem root; + FOR_EACH_CONST(ip, packages) { + String group = ip->description->installer_group; + if (group.empty()) group = _("custom"); + root.add(ip, group); + } + // tree to treelist items + items.clear(); + root.toItems(items); + // init image list + FOR_EACH(i,items) { + TreeItem& ti = static_cast(*i); + const InstallablePackageP& p = ti.package; + // load icon + Image image; + if (p && p->description->icon.Ok()) { // it has an icon + ti.setIcon(p->description->icon); + } else if (p) { // it doesn't have an icon (yet) + ti.setIcon(load_resource_image(_("installer_package"))); + if (!p->description->icon_url.empty()) { + // download icon + thumbnail_thread.request(new_intrusive2(this,&ti)); + } + } else if (ti.position_type == TreeItem::TYPE_LOCALE) { // locale folder + ti.setIcon(load_resource_image(_("installer_locales"))); + } else { // other folder + ti.setIcon(load_resource_image(_("installer_group"))); + } + } +} + +void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const { + const TreeItem& ti = static_cast(*items[index]); + Color color = wxSystemSettings::GetColour(selected ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT); + if (column == 0) { + // Name + const Bitmap& bmp = ti.highlight() ? ti.icon : ti.icon_grey; + if (bmp.Ok()) dc.DrawBitmap(bmp,x,y); + dc.SetTextForeground(color); + dc.DrawText(capitalize_sentence(ti.label), x+18, y+2); + } else if (column == 1 && ti.package) { + // Status + int stat = ti.package->status; + if ((stat & PACKAGE_CONFLICTS) == PACKAGE_CONFLICTS) { + dc.SetTextForeground(lerp(color,Color(255,0,0),0.8)); + dc.DrawText(_LABEL_("package conflicts"), x+1,y+2); + } else if ((stat & PACKAGE_MODIFIED) == PACKAGE_MODIFIED) { + dc.SetTextForeground(lerp(color,Color(255,255,0),0.5)); + dc.DrawText(_LABEL_("package modified"), x+1,y+2); + } else if ((stat & PACKAGE_UPDATES) == PACKAGE_UPDATES) { + dc.SetTextForeground(lerp(color,Color(0,0,255),0.5)); + dc.DrawText(_LABEL_("package updates"), x+1,y+2); + } else if ((stat & PACKAGE_INSTALLED) == PACKAGE_INSTALLED) { + dc.SetTextForeground(color); + dc.DrawText(_LABEL_("package installed"), x+1,y+2); + } else if ((stat & PACKAGE_INSTALLABLE) == PACKAGE_INSTALLABLE) { + dc.SetTextForeground(lerp(color,Color(128,128,128),0.6)); + dc.SetTextForeground(color); + dc.DrawText(_LABEL_("package installable"), x+1,y+2); + } + } else if (column == 2 && ti.package) { + // Action + int act = ti.package->action; + if (act & PACKAGE_INSTALL) { + if (ti.package->status & PACKAGE_INSTALLED) { + dc.SetTextForeground(lerp(color,Color(0,0,255),0.5)); + dc.DrawText(_LABEL_("upgrade package"), x+1,y+2); + } else { + dc.SetTextForeground(lerp(color,Color(0,255,0),0.5)); + dc.DrawText(_LABEL_("install package"), x+1,y+2); + } + } else if (act & PACKAGE_REMOVE) { + dc.SetTextForeground(lerp(color,Color(255,0,0),0.5)); + dc.DrawText(_LABEL_("remove package"), x+1,y+2); + } + } +} + +String PackageUpdateList::columnText(size_t column) const { + if (column == 0) return _LABEL_("package name"); + else if (column == 1) return _LABEL_("package status"); + else if (column == 2) return _LABEL_("package action"); + else throw InternalError(_("Unknown column")); +} + +int PackageUpdateList::columnWidth(size_t column) const { + if (column == 0) { + wxSize cs = GetClientSize(); + return cs.x - 300; + } else { + return 150; + } +} + diff --git a/src/gui/package_update_list.hpp b/src/gui/package_update_list.hpp new file mode 100644 index 00000000..e9390fa9 --- /dev/null +++ b/src/gui/package_update_list.hpp @@ -0,0 +1,80 @@ +//+----------------------------------------------------------------------------+ +//| Description: Magic Set Editor - Program to make Magic (tm) cards | +//| Copyright: (C) 2001 - 2008 Twan van Laarhoven and "coppro" | +//| License: GNU General Public License 2 or later (see file COPYING) | +//+----------------------------------------------------------------------------+ + +#ifndef HEADER_GUI_PACKAGE_UPDATE_LIST +#define HEADER_GUI_PACKAGE_UPDATE_LIST + +// ----------------------------------------------------------------------------- : Includes + +#include +#include +#include + +// ----------------------------------------------------------------------------- : PackageUpdateList + +/// A list of installed and downloadable packages +class PackageUpdateList : public TreeList { + public: + PackageUpdateList(Window* parent, const InstallablePackages& packages, int id = wxID_ANY); + ~PackageUpdateList(); + + inline InstallablePackageP getSelection() const { + return selection == NOTHING ? InstallablePackageP() : get(selection); + } + + inline InstallablePackageP get(size_t item) const { + return static_pointer_cast(items[item])->package; + } + + protected: + // overridden methods from TreeList + virtual void initItems(); + virtual void drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const; + + virtual size_t columnCount() const { return 3; } + virtual String columnText(size_t column) const; + virtual int columnWidth(size_t column) const; + + private: + const InstallablePackages& packages; + + class TreeItem; + public: + typedef intrusive_ptr TreeItemP; + private: + class TreeItem : public Item { + public: + TreeItem() : position_type(TYPE_OTHER), position_hint(1000000) {} + String label; + vector children; + InstallablePackageP package; + Bitmap icon, icon_grey; + // positioning + enum PackageType { + TYPE_PROG, + TYPE_LOCALE, + TYPE_GAME, + TYPE_STYLESHEET, + TYPE_EXPORT_TEMPLATE, + TYPE_SYMBOL_FONT, + TYPE_INCLUDE, + TYPE_FONT, + TYPE_OTHER, + } position_type; + int position_hint; + + void add(const InstallablePackageP& package, const String& path, int level = -1); + void toItems(vector& items); + void setIcon(const Image& image); + bool highlight() const; + + static PackageType package_type(const PackageDescription& desc); + }; + friend class PackageIconRequest; +}; + +// ----------------------------------------------------------------------------- : EOF +#endif diff --git a/src/gui/packages_window.cpp b/src/gui/packages_window.cpp index 4d79fe4b..8977ed95 100644 --- a/src/gui/packages_window.cpp +++ b/src/gui/packages_window.cpp @@ -8,15 +8,11 @@ #include #include -#include -#include -#include +#include #include #include #include #include -#include -#include #include #include #include @@ -29,7 +25,6 @@ DECLARE_POINTER_TYPE(Installer); DECLARE_TYPEOF_COLLECTION(PackageDependencyP); DECLARE_TYPEOF_COLLECTION(InstallablePackageP); DECLARE_TYPEOF_COLLECTION(DownloadableInstallerP); -DECLARE_TYPEOF_COLLECTION(TreeList::ItemP); // ----------------------------------------------------------------------------- : TODO: MOVE @@ -102,341 +97,9 @@ wxThread::ExitCode DownloadableInstallerList::Thread::Entry() { return 0; } -// ----------------------------------------------------------------------------- : PackageUpdateList - -/// A list of installed and downloadable packages -class PackageUpdateList : public TreeList { - public: - PackageUpdateList(PackagesWindow* parent, int id = wxID_ANY) - : TreeList(parent, id) - , parent(parent) - { - item_height = max(item_height,17); - rebuild(); - } - ~PackageUpdateList() { - thumbnail_thread.abort(this); - } - - InstallablePackageP getSelection() const { - return selection == NOTHING ? InstallablePackageP() : get(selection); - } - - InstallablePackageP get(size_t item) const { - return static_pointer_cast(items[item])->package; - } - - protected: - virtual void initItems(); - virtual void drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const; - - virtual size_t columnCount() const { return 3; } - virtual String columnText(size_t column) const; - virtual int columnWidth(size_t column) const; - - private: - PackagesWindow* parent; - public: - class TreeItem; - typedef intrusive_ptr TreeItemP; - class TreeItem : public Item { - public: - TreeItem() : position_type(TYPE_OTHER), position_hint(1000000) {} - String label; - vector children; - InstallablePackageP package; - Bitmap icon, icon_grey; - // positioning - enum PackageType { - TYPE_PROG, - TYPE_LOCALE, - TYPE_GAME, - TYPE_STYLESHEET, - TYPE_EXPORT_TEMPLATE, - TYPE_SYMBOL_FONT, - TYPE_INCLUDE, - TYPE_FONT, - TYPE_OTHER, - } position_type; - int position_hint; - - void add(const InstallablePackageP& package, const String& path, int level = -1); - void toItems(vector& items); - void setIcon(const Image& image); - bool highlight() const; - - static PackageType package_type(const PackageDescription& desc); - }; -}; - -// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem - -DECLARE_TYPEOF_COLLECTION(PackageUpdateList::TreeItemP); - - -void PackageUpdateList::TreeItem::add(const InstallablePackageP& package, const String& path, int level) { - // this node - this->level = level; - PackageType new_type = package_type(*package->description); - int new_hint = package->description->position_hint; - if (new_type < position_type || (new_type == position_type && new_hint < position_hint)) { - // this is a lower position hint, use it - position_type = new_type; - position_hint = new_hint; - } - // end of the path? - if (path.empty()) { - assert(!this->package); - this->package = package; - return; - } - // split path - size_t pos = path.find_first_of(_('/')); - String name = path.substr(0,pos); - String rest = pos == String::npos ? _("") : path.substr(pos+1); - // find/add child - FOR_EACH(ti, children) { - if (ti->label == name) { - // already have this child - if (pos == String::npos && ti->package) { - // two packages with the same path - TreeItemP ti2(new TreeItem); - ti2->label = name; - children.insert(ti_IT.first, ti2); - ti2->add(package, rest, level + 1); - } else { - ti->add(package, rest, level + 1); - } - return; - } - } - // don't have this child - TreeItemP ti(new TreeItem); - children.push_back(ti); - ti->label = name; - ti->add(package, rest, level + 1); -} - -bool compare_pos_hint(const PackageUpdateList::TreeItemP& a, const PackageUpdateList::TreeItemP& b) { - if (a->position_type < b->position_type) return true; - if (a->position_type > b->position_type) return false; - if (a->position_hint < b->position_hint) return true; - if (a->position_hint > b->position_hint) return false; - return a->label < b->label; -} - -void PackageUpdateList::TreeItem::toItems(vector& items) { - sort(children.begin(), children.end(), compare_pos_hint); - FOR_EACH(c, children) { - items.push_back(c); - c->toItems(items); - } -} - -bool PackageUpdateList::TreeItem::highlight() const { - if (package && package->willBeInstalled()) return true; - FOR_EACH_CONST(c,children) if (c->highlight()) return true; - return false; -} - -PackageUpdateList::TreeItem::PackageType PackageUpdateList::TreeItem::package_type(const PackageDescription& desc) { - if (desc.name == mse_package) return TYPE_PROG; - size_t pos = desc.name.find_last_of(_('.')); - if (pos == String::npos) return TYPE_OTHER; - if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE; - if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME; - if (is_substr(desc.name,pos,_(".mse-style"))) return TYPE_STYLESHEET; - if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE; - if (is_substr(desc.name,pos,_(".mse-symbol-font"))) return TYPE_SYMBOL_FONT; - if (is_substr(desc.name,pos,_(".mse-include"))) return TYPE_INCLUDE; - if (is_substr(desc.name,pos,_(".ttf"))) return TYPE_FONT; - return TYPE_OTHER; -} - -void PackageUpdateList::TreeItem::setIcon(const Image& img) { - Image image = img; - int iw = image.GetWidth(), ih = image.GetHeight(); - if (ih > 107) { - int w = 107 * iw / ih; - image = resample(image, w, 107); - } else if (iw > 107) { - int h = 107 * ih / iw; - image = resample(image, 107, h); - } - if (package) package->description->icon = image; - Image resampled = resample_preserve_aspect(image,16,16); - icon = Bitmap(resampled); - saturate(resampled, -.75); - set_alpha(resampled,0.5); - icon_grey = Bitmap(resampled); -} - -// ----------------------------------------------------------------------------- : PackageIconRequest - -/// wx doesn't allow seeking on InputStreams from a wxURL -/// The built in buffer class is too stupid to seek, so we must do it ourselfs -class SeekAtStartInputStream : public wxFilterInputStream { - public: - SeekAtStartInputStream(wxInputStream& stream) - : wxFilterInputStream(stream) - , buffer_pos(0) - { - m_parent_i_stream->Read(buffer, 1024); - buffer_size = m_parent_i_stream->LastRead(); - } - - bool IsSeekable() const { return true; } - protected: - virtual size_t OnSysRead(void *buffer, size_t bufsize) { - size_t len = min(buffer_size - buffer_pos, bufsize); - memcpy(buffer, this->buffer + buffer_pos, len); - buffer_pos += len; - m_parent_i_stream->Read((Byte*)buffer + len, bufsize - len); - return m_parent_i_stream->LastRead() + len; - } - virtual wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode) { - if (mode == wxFromStart) buffer_pos = seek; - else if (mode == wxFromCurrent) buffer_pos += seek; - else assert(false); - assert(buffer_pos < buffer_size); - return buffer_pos; - } - virtual wxFileOffset OnSysTell() const { - assert(buffer_pos < buffer_size); - return buffer_pos; - } - private: - size_t buffer_size, buffer_pos; - Byte buffer[1024]; -}; - -class PackageIconRequest : public ThumbnailRequest { - public: - PackageIconRequest(PackageUpdateList* list, PackageUpdateList::TreeItem* ti) - : ThumbnailRequest( - list, - _("package_") + ti->package->description->icon_url + _("_") + ti->package->description->version.toString(), - wxDateTime(1,wxDateTime::Jan,2000)) - , list(list), ti(ti) - {} - - virtual Image generate() { - wxURL url(ti->package->description->icon_url); - scoped_ptr isP(url.GetInputStream()); - if (!isP) return wxImage(); - SeekAtStartInputStream is2(*isP); - Image result(is2); - return result; - } - virtual void store(const Image& image) { - if (!image.Ok()) return; - ti->setIcon(image); - list->Refresh(false); - } - private: - PackageUpdateList* list; - PackageUpdateList::TreeItem* ti; -}; - -// ----------------------------------------------------------------------------- : PackageUpdateList : implementation - -void PackageUpdateList::initItems() { - // packages to tree - TreeItem root; - FOR_EACH(ip, parent->installable_packages) { - String group = ip->description->installer_group; - if (group.empty()) group = _("custom"); - root.add(ip, group); - } - // tree to treelist items - items.clear(); - root.toItems(items); - // init image list - FOR_EACH(i,items) { - TreeItem& ti = static_cast(*i); - const InstallablePackageP& p = ti.package; - Image image; - if (p && p->description->icon.Ok()) { - ti.setIcon(p->description->icon); - } else if (p) { - ti.setIcon(load_resource_image(_("installer_package"))); - if (!p->description->icon_url.empty()) { - // download icon - thumbnail_thread.request(new_intrusive2(this,&ti)); - } - } else if (ti.position_type == TreeItem::TYPE_LOCALE) { - ti.setIcon(load_resource_image(_("installer_locales"))); - } else { - ti.setIcon(load_resource_image(_("installer_group"))); - } - } -} - -void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const { - const TreeItem& ti = static_cast(*items[index]); - Color color = wxSystemSettings::GetColour(selected ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT); - if (column == 0) { - // Name - const Bitmap& bmp = ti.highlight() ? ti.icon : ti.icon_grey; - if (bmp.Ok()) dc.DrawBitmap(bmp,x,y); - dc.SetTextForeground(color); - dc.DrawText(capitalize_sentence(ti.label), x+18, y+2); - } else if (column == 1 && ti.package) { - // Status - int stat = ti.package->status; - if ((stat & PACKAGE_CONFLICTS) == PACKAGE_CONFLICTS) { - dc.SetTextForeground(lerp(color,Color(255,0,0),0.8)); - dc.DrawText(_LABEL_("package conflicts"), x+1,y+2); - } else if ((stat & PACKAGE_MODIFIED) == PACKAGE_MODIFIED) { - dc.SetTextForeground(lerp(color,Color(255,255,0),0.5)); - dc.DrawText(_LABEL_("package modified"), x+1,y+2); - } else if ((stat & PACKAGE_UPDATES) == PACKAGE_UPDATES) { - dc.SetTextForeground(lerp(color,Color(0,0,255),0.5)); - dc.DrawText(_LABEL_("package updates"), x+1,y+2); - } else if ((stat & PACKAGE_INSTALLED) == PACKAGE_INSTALLED) { - dc.SetTextForeground(color); - dc.DrawText(_LABEL_("package installed"), x+1,y+2); - } else if ((stat & PACKAGE_INSTALLABLE) == PACKAGE_INSTALLABLE) { - dc.SetTextForeground(lerp(color,Color(128,128,128),0.6)); - dc.SetTextForeground(color); - dc.DrawText(_LABEL_("package installable"), x+1,y+2); - } - } else if (column == 2 && ti.package) { - // Action - int act = ti.package->action; - if (act & PACKAGE_INSTALL) { - if (ti.package->status & PACKAGE_INSTALLED) { - dc.SetTextForeground(lerp(color,Color(0,0,255),0.5)); - dc.DrawText(_LABEL_("upgrade package"), x+1,y+2); - } else { - dc.SetTextForeground(lerp(color,Color(0,255,0),0.5)); - dc.DrawText(_LABEL_("install package"), x+1,y+2); - } - } else if (act & PACKAGE_REMOVE) { - dc.SetTextForeground(lerp(color,Color(255,0,0),0.5)); - dc.DrawText(_LABEL_("remove package"), x+1,y+2); - } - } -} - -String PackageUpdateList::columnText(size_t column) const { - if (column == 0) return _LABEL_("package name"); - else if (column == 1) return _LABEL_("package status"); - else if (column == 2) return _LABEL_("package action"); - else throw InternalError(_("Unknown column")); -} -int PackageUpdateList::columnWidth(size_t column) const { - if (column == 0) { - wxSize cs = GetClientSize(); - return cs.x - 300; - } else { - return 150; - } -} - - // ----------------------------------------------------------------------------- : PackageInfoPanel +/// Information on a package class PackageInfoPanel : public wxPanel { public: PackageInfoPanel(Window* parent); @@ -508,7 +171,7 @@ PackagesWindow::PackagesWindow(Window* parent, bool download_package_list) // ui elements SetIcon(wxIcon()); - package_list = new PackageUpdateList(this, ID_PACKAGE_LIST); + package_list = new PackageUpdateList(this, installable_packages, ID_PACKAGE_LIST); package_info = new PackageInfoPanel(this); //wxToolbar* buttons = new wxToolbar diff --git a/src/gui/packages_window.hpp b/src/gui/packages_window.hpp index 0d13b22a..a3afc306 100644 --- a/src/gui/packages_window.hpp +++ b/src/gui/packages_window.hpp @@ -20,9 +20,13 @@ class PackageInfoPanel; /// A window that displays the installed packages and updates to them class PackagesWindow : public wxDialog { public: + /// Show the packages window, optionally downloading the package database from the website PackagesWindow(Window* parent, bool download_package_list = true); + /// Show the packages window for an installer + PackagesWindow(Window* parent, const InstallerP& installer); ~PackagesWindow(); - + + /// List of the packages shown in this window InstallablePackages installable_packages; private: @@ -42,6 +46,8 @@ class PackagesWindow : public wxDialog { void onUpdateUI(wxUpdateUIEvent&); void onIdle(wxIdleEvent&); + /// Check whether we have downloaded the list of installers + /** If the download is (partially) complete, update the installable_packages list */ bool checkInstallerList(bool refresh = true); }; diff --git a/src/mse.vcproj b/src/mse.vcproj index 1d764557..eb549346 100644 --- a/src/mse.vcproj +++ b/src/mse.vcproj @@ -1000,12 +1000,6 @@ - - - - @@ -1024,18 +1018,34 @@ - - - - + + + + + + + + + + + + + + & packages_o PackageVersionP ver(new PackageVersion( is_local ? PackageVersion::STATUS_LOCAL : PackageVersion::STATUS_GLOBAL)); ver->check_status(*pack); - packages_out.push_back(new_intrusive2(ver, new_intrusive1(*pack))); + packages_out.push_back(new_intrusive2(new_intrusive1(*pack), ver)); } catch (const Error&) {} ++it2; } else if ((*it1)->name < *it2) { @@ -246,7 +246,7 @@ void PackageDirectory::installedPackages(vector& packages_o try { PackagedP pack = ::packages.openAny(*it2, true); (*it1)->check_status(*pack); - packages_out.push_back(new_intrusive2(*it1, new_intrusive1(*pack))); + packages_out.push_back(new_intrusive2(new_intrusive1(*pack), *it1)); } catch (const Error&) { db_changed = true; } ++it1, ++it2; }