|
|
|
@@ -11,14 +11,11 @@
|
|
|
|
|
#include <gui/control/tree_list.hpp>
|
|
|
|
|
//%#include <gui/update_checker.hpp>
|
|
|
|
|
#include <gui/util.hpp>
|
|
|
|
|
#include <util/io/package_repository.hpp>
|
|
|
|
|
#include <util/io/package_manager.hpp>
|
|
|
|
|
#include <util/window_id.hpp>
|
|
|
|
|
#include <data/installer.hpp>
|
|
|
|
|
#include <data/settings.hpp>
|
|
|
|
|
#include <gfx/gfx.hpp>
|
|
|
|
|
//%#include <list>
|
|
|
|
|
//%#include <set>
|
|
|
|
|
#include <wx/wfstream.h>
|
|
|
|
|
#include <wx/html/htmlwin.h>
|
|
|
|
|
#include <wx/dialup.h>
|
|
|
|
@@ -26,49 +23,16 @@
|
|
|
|
|
#include <wx/dcbuffer.h>
|
|
|
|
|
#include <wx/progdlg.h>
|
|
|
|
|
|
|
|
|
|
//%DECLARE_POINTER_TYPE(VersionData); //%% TODO
|
|
|
|
|
DECLARE_POINTER_TYPE(Installer);
|
|
|
|
|
//%DECLARE_POINTER_TYPE(PackageVersionData);
|
|
|
|
|
|
|
|
|
|
DECLARE_TYPEOF_COLLECTION(PackageVersionDataP);
|
|
|
|
|
DECLARE_TYPEOF_COLLECTION(PackageDependencyP);
|
|
|
|
|
DECLARE_TYPEOF_COLLECTION(InstallablePackageP);
|
|
|
|
|
DECLARE_TYPEOF_COLLECTION(DownloadableInstallerP);
|
|
|
|
|
DECLARE_TYPEOF_COLLECTION(TreeList::ItemP);
|
|
|
|
|
//%DECLARE_TYPEOF(list<PackageVersionDataP>);
|
|
|
|
|
//%DECLARE_TYPEOF(set<String>);
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : TODO: MOVE
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
/// Information on available packages
|
|
|
|
|
class PackageVersionData : public IntrusivePtrVirtualBase {
|
|
|
|
|
public:
|
|
|
|
|
PackageVersionData() {}
|
|
|
|
|
|
|
|
|
|
String name; ///< Name of the package
|
|
|
|
|
String type; ///< Type of package ("magic style" or "game")
|
|
|
|
|
String display_name; ///< Name to show on package list.
|
|
|
|
|
String description; ///< html description
|
|
|
|
|
String url; ///< Where can the package be downloaded?
|
|
|
|
|
Version version; ///< Version number of the download
|
|
|
|
|
Version app_version; ///< The minimium version of MSE required
|
|
|
|
|
vector<PackageDependencyP> depends; ///< Packages this depends on
|
|
|
|
|
|
|
|
|
|
DECLARE_REFLECTION();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Information on the latest available version
|
|
|
|
|
class VersionData : public IntrusivePtrBase<VersionData> {
|
|
|
|
|
public:
|
|
|
|
|
Version version; ///< Latest version number of MSE
|
|
|
|
|
String description; ///< html description of the latest MSE release
|
|
|
|
|
String new_updates_url; ///< updates url has moved?
|
|
|
|
|
vector<PackageVersionDataP> packages; ///< Available packages
|
|
|
|
|
|
|
|
|
|
DECLARE_REFLECTION();
|
|
|
|
|
};
|
|
|
|
|
extern VersionDataP update_version_data;
|
|
|
|
|
|
|
|
|
|
// A HTML control that opens all pages in an actual browser
|
|
|
|
|
struct HtmlWindowToBrowser : public wxHtmlWindow {
|
|
|
|
|
HtmlWindowToBrowser(Window* parent, int id, const wxPoint& pos, const wxSize& size, long flags)
|
|
|
|
@@ -79,134 +43,61 @@ struct HtmlWindowToBrowser : public wxHtmlWindow {
|
|
|
|
|
wxLaunchDefaultBrowser( info.GetHref() );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : PackageUpdateList
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
class PackageUpdateList : public wxVListBox {
|
|
|
|
|
public:
|
|
|
|
|
PackageUpdateList(UpdatesWindow* parent)
|
|
|
|
|
: wxVListBox (parent, ID_PACKAGE_LIST, wxDefaultPosition, wxSize(540,210), wxNO_BORDER | wxVSCROLL)
|
|
|
|
|
, parent(parent)
|
|
|
|
|
{
|
|
|
|
|
if (!checking_updates && !update_version_data) {
|
|
|
|
|
check_updates_now(true);
|
|
|
|
|
}
|
|
|
|
|
SetItemCount(update_version_data ? update_version_data->packages.size() : 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void OnDrawItem(wxDC& dc, const wxRect& rect, size_t n) const {
|
|
|
|
|
static wxBrush greyBrush(Color(224,224,224));
|
|
|
|
|
if (checking_updates) {
|
|
|
|
|
String text = _ERROR_("checking updates");
|
|
|
|
|
|
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
|
dc.SetBrush(greyBrush);
|
|
|
|
|
dc.DrawRectangle(rect);
|
|
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
|
dc.GetTextExtent(text, &w, &h);
|
|
|
|
|
dc.DrawText(text, rect.GetLeft() + (rect.GetWidth() - w) / 2, rect.GetTop() + (rect.GetHeight() - h) / 2);
|
|
|
|
|
} else if (!update_version_data || update_version_data->packages.empty()) {
|
|
|
|
|
String text = _ERROR_("no packages");
|
|
|
|
|
|
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
|
dc.SetBrush(greyBrush);
|
|
|
|
|
dc.DrawRectangle(rect);
|
|
|
|
|
|
|
|
|
|
int w, h;
|
|
|
|
|
dc.GetTextExtent(text, &w, &h);
|
|
|
|
|
dc.DrawText(text, rect.GetLeft() + (rect.GetWidth() - w) / 2, rect.GetTop() + (rect.GetHeight() - h) / 2);
|
|
|
|
|
} else {
|
|
|
|
|
static wxBrush darkBrush(Color(192,224,255));
|
|
|
|
|
static wxBrush selectBrush(Color(96,96,192));
|
|
|
|
|
|
|
|
|
|
PackageVersionDataP pack = update_version_data->packages[n];
|
|
|
|
|
UpdatesWindow::PackageStatus status = parent->package_data[pack].first;
|
|
|
|
|
UpdatesWindow::PackageAction action = parent->package_data[pack].second;
|
|
|
|
|
|
|
|
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
|
dc.SetBrush(IsSelected(n) ? selectBrush : (n % 2 ? *wxWHITE_BRUSH : darkBrush));
|
|
|
|
|
|
|
|
|
|
dc.DrawRectangle(rect);
|
|
|
|
|
|
|
|
|
|
// These two arrays correspond to PackageStatus and PackageAction, respectively
|
|
|
|
|
static Color status_colors [] = {
|
|
|
|
|
Color(32,160,32)
|
|
|
|
|
,Color(32,32,255)
|
|
|
|
|
,Color(192,32,32)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static Color action_colors [] = {
|
|
|
|
|
Color(32,160,32)
|
|
|
|
|
,Color(192,32,32)
|
|
|
|
|
,Color(192,192,32)
|
|
|
|
|
,Color(32,32,255)
|
|
|
|
|
,Color(32,32,32)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Ditto here (these are the locale names)
|
|
|
|
|
static String status_texts [] = {
|
|
|
|
|
_TYPE_("installed")
|
|
|
|
|
,_TYPE_("uninstalled")
|
|
|
|
|
,_TYPE_("upgradeable")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static String action_texts [] = {
|
|
|
|
|
_TYPE_("install")
|
|
|
|
|
,_TYPE_("uninstall")
|
|
|
|
|
,_TYPE_("upgrade")
|
|
|
|
|
,_TYPE_("do nothing")
|
|
|
|
|
,_TYPE_("new mse")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static Color packageFront(64,64,64);
|
|
|
|
|
|
|
|
|
|
#define SELECT_WHITE(color) (IsSelected(n) ? *wxWHITE : color)
|
|
|
|
|
|
|
|
|
|
dc.SetClippingRegion(wxRect(rect.x, rect.y, 180, rect.height));
|
|
|
|
|
dc.SetTextForeground(SELECT_WHITE(packageFront));
|
|
|
|
|
dc.DrawText(pack->display_name, rect.GetLeft() + 1, rect.GetTop());
|
|
|
|
|
dc.DestroyClippingRegion();
|
|
|
|
|
|
|
|
|
|
dc.SetClippingRegion(wxRect(rect.x + 180, rect.y, 120, rect.height));
|
|
|
|
|
dc.DrawText(pack->type, rect.GetLeft() + 180, rect.GetTop());
|
|
|
|
|
dc.DestroyClippingRegion();
|
|
|
|
|
|
|
|
|
|
dc.SetTextForeground(SELECT_WHITE(status_colors[status]));
|
|
|
|
|
dc.DrawText(status_texts[status], rect.GetLeft() + 300, rect.GetTop());
|
|
|
|
|
|
|
|
|
|
dc.SetTextForeground(SELECT_WHITE(action_colors[action]));
|
|
|
|
|
dc.DrawText(action_texts[action], rect.GetLeft() + 420, rect.GetTop());
|
|
|
|
|
|
|
|
|
|
#undef SELECT_WHITE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual wxCoord OnMeasureItem(size_t) const {
|
|
|
|
|
return (update_version_data && !update_version_data->packages.empty()) ? 15 : 210;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onUpdateCheckingFinished(wxEvent& event) {
|
|
|
|
|
SetItemCount(update_version_data ? update_version_data->packages.size() : 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual wxCoord EstimateTotalHeight() const {
|
|
|
|
|
return (update_version_data && !update_version_data->packages.empty())
|
|
|
|
|
? 15 * (int)update_version_data->packages.size()
|
|
|
|
|
: 210;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
DECLARE_EVENT_TABLE()
|
|
|
|
|
|
|
|
|
|
UpdatesWindow* parent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BEGIN_EVENT_TABLE(PackageUpdateList, wxVListBox)
|
|
|
|
|
EVT_CUSTOM(UPDATE_CHECK_FINISHED_EVT, wxID_ANY, PackageUpdateList::onUpdateCheckingFinished)
|
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : DownloadableInstallers
|
|
|
|
|
|
|
|
|
|
class DownloadableInstallerList {
|
|
|
|
|
public:
|
|
|
|
|
DownloadableInstallerList() : status(NONE) {}
|
|
|
|
|
|
|
|
|
|
/// are we done? if not, start downloading
|
|
|
|
|
bool done();
|
|
|
|
|
|
|
|
|
|
vector<DownloadableInstallerP> installers;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
enum Status { NONE, DOWNLOADING, DONE } status;
|
|
|
|
|
wxMutex lock;
|
|
|
|
|
|
|
|
|
|
struct Thread : public wxThread {
|
|
|
|
|
virtual ExitCode Entry();
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DownloadableInstallerList downloadable_installers;
|
|
|
|
|
|
|
|
|
|
bool DownloadableInstallerList::done() {
|
|
|
|
|
if (status == DONE) return true;
|
|
|
|
|
if (status == NONE) {
|
|
|
|
|
status = DOWNLOADING;
|
|
|
|
|
Thread* thread = new Thread();
|
|
|
|
|
thread->Create();
|
|
|
|
|
thread->Run();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wxThread::ExitCode DownloadableInstallerList::Thread::Entry() {
|
|
|
|
|
// open url
|
|
|
|
|
wxURL url(settings.installer_list_url);
|
|
|
|
|
wxInputStream* isP = url.GetInputStream();
|
|
|
|
|
if (!isP) {
|
|
|
|
|
wxMutexLocker l(downloadable_installers.lock);
|
|
|
|
|
downloadable_installers.status = DONE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
InputStreamP is(isP);
|
|
|
|
|
// Read installer list
|
|
|
|
|
Reader reader(is, nullptr, _("installers"), true);
|
|
|
|
|
vector<DownloadableInstallerP> installers;
|
|
|
|
|
reader.handle(_("installers"),installers);
|
|
|
|
|
// done
|
|
|
|
|
wxMutexLocker l(downloadable_installers.lock);
|
|
|
|
|
swap(installers, downloadable_installers.installers);
|
|
|
|
|
downloadable_installers.status = DONE;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------- : PackageUpdateList
|
|
|
|
|
|
|
|
|
@@ -216,7 +107,6 @@ class PackageUpdateList : public TreeList {
|
|
|
|
|
PackageUpdateList(PackagesWindow* parent, int id = wxID_ANY)
|
|
|
|
|
: TreeList(parent, id)
|
|
|
|
|
, parent(parent)
|
|
|
|
|
, images(16,16)
|
|
|
|
|
{
|
|
|
|
|
item_height = max(item_height,17);
|
|
|
|
|
rebuild();
|
|
|
|
@@ -240,7 +130,6 @@ class PackageUpdateList : public TreeList {
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
PackagesWindow* parent;
|
|
|
|
|
mutable wxImageList images;
|
|
|
|
|
class TreeItem;
|
|
|
|
|
public:
|
|
|
|
|
typedef intrusive_ptr<TreeItem> TreeItemP;
|
|
|
|
@@ -250,9 +139,11 @@ class PackageUpdateList : public TreeList {
|
|
|
|
|
String label;
|
|
|
|
|
vector<TreeItemP> children;
|
|
|
|
|
InstallablePackageP package;
|
|
|
|
|
Bitmap icon, icon_grey;
|
|
|
|
|
|
|
|
|
|
void add(const InstallablePackageP& package, const String& path, int level = -1);
|
|
|
|
|
void toItems(vector<TreeList::ItemP>& items);
|
|
|
|
|
bool highlight() const;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -312,14 +203,21 @@ void PackageUpdateList::TreeItem::toItems(vector<TreeList::ItemP>& items) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool PackageUpdateList::TreeItem::highlight() const {
|
|
|
|
|
if (package && ((package->installed && !(package->action & PACKAGE_REMOVE))
|
|
|
|
|
|| package->action & (PACKAGE_INSTALL | PACKAGE_UPGRADE))) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
FOR_EACH_CONST(c,children) if (c->highlight()) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
//% group += _("/");
|
|
|
|
|
if (!group.empty()) group += _("/");
|
|
|
|
|
group += ip->description->short_name;
|
|
|
|
|
root.add(ip, group);
|
|
|
|
@@ -328,21 +226,25 @@ void PackageUpdateList::initItems() {
|
|
|
|
|
items.clear();
|
|
|
|
|
root.toItems(items);
|
|
|
|
|
// init image list
|
|
|
|
|
images.RemoveAll();
|
|
|
|
|
Image resampled(16,16,false);
|
|
|
|
|
FOR_EACH(i,items) {
|
|
|
|
|
const TreeItem& ti = static_cast<const TreeItem&>(*i);
|
|
|
|
|
TreeItem& ti = static_cast<TreeItem&>(*i);
|
|
|
|
|
const InstallablePackageP& p = ti.package;
|
|
|
|
|
Image image;
|
|
|
|
|
if (p && p->description->icon.Ok()) {
|
|
|
|
|
Image resampled(16,16,false);
|
|
|
|
|
resample_preserve_aspect(p->description->icon, resampled);
|
|
|
|
|
images.Add(resampled);
|
|
|
|
|
image = resampled;
|
|
|
|
|
} else if (p) {
|
|
|
|
|
images.Add(load_resource_image(_("installer_package")));
|
|
|
|
|
image = load_resource_image(_("installer_package"));
|
|
|
|
|
} else if (ti.label == _("locales")) {
|
|
|
|
|
images.Add(load_resource_image(_("installer_locales")));
|
|
|
|
|
image = load_resource_image(_("installer_locales"));
|
|
|
|
|
} else {
|
|
|
|
|
images.Add(load_resource_image(_("installer_group")));
|
|
|
|
|
image = load_resource_image(_("installer_group"));
|
|
|
|
|
}
|
|
|
|
|
ti.icon = Bitmap(image);
|
|
|
|
|
desaturate(image);
|
|
|
|
|
set_alpha(image, 0.5);
|
|
|
|
|
ti.icon_grey = Bitmap(image);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -351,31 +253,41 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
|
|
|
|
|
Color color = wxSystemSettings::GetColour(selected ? wxSYS_COLOUR_HIGHLIGHTTEXT : wxSYS_COLOUR_WINDOWTEXT);
|
|
|
|
|
if (column == 0) {
|
|
|
|
|
// Name
|
|
|
|
|
images.Draw((int)index, dc, x, y);
|
|
|
|
|
const Bitmap& bmp = ti.highlight() ? ti.icon : ti.icon_grey;
|
|
|
|
|
if (bmp.Ok()) dc.DrawBitmap(bmp,x,y);
|
|
|
|
|
dc.SetTextForeground(color);
|
|
|
|
|
dc.DrawText(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) {
|
|
|
|
|
dc.SetTextForeground(lerp(color,Color(0,255,0),0.5));
|
|
|
|
|
dc.DrawText(_LABEL_("install package"), x+1,y+2);
|
|
|
|
|
} else if (act & PACKAGE_UPGRADE) {
|
|
|
|
|
dc.SetTextForeground(lerp(color,Color(0,0,255),0.5));
|
|
|
|
|
dc.DrawText(_LABEL_("upgrade 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -457,11 +369,16 @@ END_EVENT_TABLE()
|
|
|
|
|
PackagesWindow::PackagesWindow(Window* parent, bool download_package_list)
|
|
|
|
|
: wxDialog(parent, wxID_ANY, _TITLE_("package list"), wxDefaultPosition, wxSize(640,480), wxDEFAULT_DIALOG_STYLE | wxCLIP_CHILDREN | wxRESIZE_BORDER)
|
|
|
|
|
, where(is_install_local(settings.install_type) ? PACKAGE_LOCAL : PACKAGE_GLOBAL)
|
|
|
|
|
, waiting_for_list(download_package_list)
|
|
|
|
|
{
|
|
|
|
|
// request download before searching disk so we do two things at once
|
|
|
|
|
if (download_package_list) downloadable_installers.done();
|
|
|
|
|
// get packages
|
|
|
|
|
wxBusyCursor busy;
|
|
|
|
|
packages.installedPackages(installable_packages);
|
|
|
|
|
FOR_EACH(p, installable_packages) p->determineStatus();
|
|
|
|
|
checkInstallerList();
|
|
|
|
|
|
|
|
|
|
// ui elements
|
|
|
|
|
SetIcon(wxIcon());
|
|
|
|
|
package_list = new PackageUpdateList(this, ID_PACKAGE_LIST);
|
|
|
|
@@ -471,38 +388,8 @@ PackagesWindow::PackagesWindow(Window* parent, bool download_package_list)
|
|
|
|
|
wxButton* install_button = new wxButton(this, ID_INSTALL, _BUTTON_("install package"));
|
|
|
|
|
wxButton* upgrade_button = new wxButton(this, ID_UPGRADE, _BUTTON_("upgrade package"));
|
|
|
|
|
wxButton* remove_button = new wxButton(this, ID_REMOVE, _BUTTON_("remove package"));
|
|
|
|
|
/*
|
|
|
|
|
description_window = new HtmlWindowToBrowser(this, wxID_ANY, wxDefaultPosition, wxSize(540,100), wxHW_SCROLLBAR_AUTO | wxSUNKEN_BORDER);
|
|
|
|
|
setDefaultPackageStatus();
|
|
|
|
|
|
|
|
|
|
(install_button = new wxButton(this, ID_INSTALL, _MENU_("install package")))->Disable();
|
|
|
|
|
(upgrade_button = new wxButton(this, ID_UPGRADE, _MENU_("upgrade package")))->Disable();
|
|
|
|
|
(remove_button = new wxButton(this, ID_REMOVE, _MENU_("remove package")))->Disable();
|
|
|
|
|
(cancel_button = new wxButton(this, ID_CANCEL, _MENU_("cancel changes")))->Disable();
|
|
|
|
|
|
|
|
|
|
apply_button = new wxButton(this, ID_APPLY, _MENU_("apply changes"));
|
|
|
|
|
|
|
|
|
|
// Init sizer
|
|
|
|
|
|
|
|
|
|
h2->AddStretchSpacer();
|
|
|
|
|
h2->Add(install_button);
|
|
|
|
|
h2->AddStretchSpacer();
|
|
|
|
|
h2->Add(upgrade_button);
|
|
|
|
|
h2->AddStretchSpacer();
|
|
|
|
|
h2->Add(remove_button);
|
|
|
|
|
h2->AddStretchSpacer();
|
|
|
|
|
h2->Add(cancel_button);
|
|
|
|
|
h2->AddStretchSpacer();
|
|
|
|
|
*/
|
|
|
|
|
/* wxBoxSizer *h2 = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
|
wxBoxSizer *h3 = new wxBoxSizer(wxHORIZONTAL);
|
|
|
|
|
|
|
|
|
|
h3->AddStretchSpacer();
|
|
|
|
|
h3->Add(apply_button);
|
|
|
|
|
h3->AddStretchSpacer();
|
|
|
|
|
// v->Add(h2);
|
|
|
|
|
// v->Add(h3);*/
|
|
|
|
|
|
|
|
|
|
wxBoxSizer* v = new wxBoxSizer(wxVERTICAL);
|
|
|
|
|
v->Add(package_list, 1, wxEXPAND | wxALL & ~wxBOTTOM, 8);
|
|
|
|
|
v->AddSpacer(4);
|
|
|
|
@@ -522,16 +409,10 @@ PackagesWindow::PackagesWindow(Window* parent, bool download_package_list)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PackagesWindow::~PackagesWindow() {
|
|
|
|
|
//(new WelcomeWindow)->Show();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
void PackagesWindow::onUpdateCheckFinished(wxCommandEvent&) {
|
|
|
|
|
setDefaultPackageStatus();
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
void PackagesWindow::onPackageSelect(wxCommandEvent& ev) {
|
|
|
|
|
// updateButtons(package_list->getSelection());
|
|
|
|
|
package_info->setPackage(package = package_list->getSelection());
|
|
|
|
|
UpdateWindowUI(wxUPDATE_UI_RECURSE);
|
|
|
|
|
}
|
|
|
|
@@ -620,265 +501,32 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
void PackagesWindow::onActionChange(wxCommandEvent& ev) {
|
|
|
|
|
PackageVersionDataP pack = package_list->getSelection();
|
|
|
|
|
if (!pack) return;
|
|
|
|
|
PackageAction& action = package_data[pack].second;
|
|
|
|
|
switch (ev.GetId()) {
|
|
|
|
|
case ID_INSTALL:
|
|
|
|
|
action = ACTION_INSTALL;
|
|
|
|
|
SelectPackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
case ID_REMOVE:
|
|
|
|
|
action = ACTION_UNINSTALL;
|
|
|
|
|
RemovePackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
case ID_UPGRADE:
|
|
|
|
|
action = ACTION_UPGRADE;
|
|
|
|
|
SelectPackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
case ID_CANCEL:
|
|
|
|
|
switch (package_data[pack].first) {
|
|
|
|
|
case STATUS_INSTALLED:
|
|
|
|
|
SelectPackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
case STATUS_NOT_INSTALLED:
|
|
|
|
|
RemovePackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
case STATUS_UPGRADEABLE:
|
|
|
|
|
if (action == ACTION_UPGRADE)
|
|
|
|
|
DowngradePackageDependencies(pack);
|
|
|
|
|
else
|
|
|
|
|
SelectPackageDependencies(pack);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
action = (pack->app_version > file_version) ? ACTION_NEW_MSE : ACTION_NOTHING;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
updateButtons(package_list->getSelection());
|
|
|
|
|
package_list->Refresh();
|
|
|
|
|
void PackagesWindow::onIdle(wxIdleEvent& ev) {
|
|
|
|
|
ev.RequestMore(!checkInstallerList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PackagesWindow::onApplyChanges(wxCommandEvent& ev) {
|
|
|
|
|
list<PackageVersionDataP> to_install, to_remove;
|
|
|
|
|
|
|
|
|
|
FOR_EACH(pack, update_version_data->packages) {
|
|
|
|
|
switch (package_data[pack].second) {
|
|
|
|
|
case ACTION_INSTALL:
|
|
|
|
|
to_install.push_back(pack);
|
|
|
|
|
break;
|
|
|
|
|
case ACTION_UPGRADE:
|
|
|
|
|
to_install.push_back(pack);
|
|
|
|
|
case ACTION_UNINSTALL:
|
|
|
|
|
to_remove.push_back(pack);
|
|
|
|
|
default:;
|
|
|
|
|
}
|
|
|
|
|
bool PackagesWindow::checkInstallerList() {
|
|
|
|
|
if (!waiting_for_list) return true;
|
|
|
|
|
if (!downloadable_installers.done()) return false;
|
|
|
|
|
waiting_for_list = false;
|
|
|
|
|
// merge installer lists
|
|
|
|
|
FOR_EACH(inst, downloadable_installers.installers) {
|
|
|
|
|
merge(installable_packages, inst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOR_EACH(pack, to_remove) {
|
|
|
|
|
String filename = packages.openAny(pack->name, true)->absoluteFilename();
|
|
|
|
|
if (!remove_file_or_dir(filename)) {
|
|
|
|
|
handle_error(_("Cannot delete ") + filename + _(" to remove package ") + pack->name + _(". ")
|
|
|
|
|
_("Other packages may have been removed, including packages that this on is dependent on. Please remove manually."));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOR_EACH(pack, to_install) {
|
|
|
|
|
wxURL url(pack->url);
|
|
|
|
|
wxInputStream* is = url.GetInputStream();
|
|
|
|
|
if (!is) {
|
|
|
|
|
handle_error(_("Cannot fetch file ") + pack->url + _(" to install package ") + pack->name + _(". ")
|
|
|
|
|
_("Other packages may have been installed, including packages that depend on this one. ")
|
|
|
|
|
_("Please remove those packages manually or install this one manually."));
|
|
|
|
|
}
|
|
|
|
|
wxString filename = wxFileName::CreateTempFileName(_(""));
|
|
|
|
|
wxFileOutputStream os (filename);
|
|
|
|
|
|
|
|
|
|
os.Write(*is);
|
|
|
|
|
os.Close();
|
|
|
|
|
|
|
|
|
|
InstallerP inst(new Installer);
|
|
|
|
|
inst->open(filename);
|
|
|
|
|
inst->install(isInstallLocal(settings.install_type), false);
|
|
|
|
|
|
|
|
|
|
delete is;
|
|
|
|
|
wxRemoveFile(filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setDefaultPackageStatus();
|
|
|
|
|
updateButtons(package_list->getSelection());
|
|
|
|
|
package_list->Refresh();
|
|
|
|
|
|
|
|
|
|
handle_pending_errors();
|
|
|
|
|
|
|
|
|
|
packages.clearPackageCache();
|
|
|
|
|
FOR_EACH(p, installable_packages) p->determineStatus();
|
|
|
|
|
// refresh
|
|
|
|
|
package_list->rebuild();
|
|
|
|
|
package_info->setPackage(package = package_list->getSelection());
|
|
|
|
|
UpdateWindowUI(wxUPDATE_UI_RECURSE);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PackagesWindow::updateButtons(const PackageVersionDataP& pack) {
|
|
|
|
|
|
|
|
|
|
description_window->SetPage(pack->description);
|
|
|
|
|
|
|
|
|
|
PackageStatus status = package_data[pack].first;
|
|
|
|
|
PackageAction action = package_data[pack].second;
|
|
|
|
|
|
|
|
|
|
if (action == ACTION_NEW_MSE) {
|
|
|
|
|
install_button->Disable();
|
|
|
|
|
remove_button->Enable(status != STATUS_NOT_INSTALLED);
|
|
|
|
|
upgrade_button->Disable();
|
|
|
|
|
cancel_button->Disable();
|
|
|
|
|
} else if (status == STATUS_INSTALLED) {
|
|
|
|
|
install_button->Disable();
|
|
|
|
|
remove_button->Enable(action != ACTION_UNINSTALL);
|
|
|
|
|
upgrade_button->Disable();
|
|
|
|
|
cancel_button->Enable(action == ACTION_UNINSTALL);
|
|
|
|
|
} else if (status == STATUS_NOT_INSTALLED) {
|
|
|
|
|
install_button->Enable(action != ACTION_INSTALL);
|
|
|
|
|
remove_button->Disable();
|
|
|
|
|
upgrade_button->Disable();
|
|
|
|
|
cancel_button->Enable(action == ACTION_INSTALL);
|
|
|
|
|
} else /* status == STATUS_UPGRADEABLE * / {
|
|
|
|
|
install_button->Disable();
|
|
|
|
|
remove_button->Enable(action != ACTION_UNINSTALL);
|
|
|
|
|
upgrade_button->Enable(action != ACTION_UPGRADE);
|
|
|
|
|
cancel_button->Enable(action != ACTION_NOTHING);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PackagesWindow::setDefaultPackageStatus() {
|
|
|
|
|
if (!update_version_data) return;
|
|
|
|
|
FOR_EACH(p, update_version_data->packages) {
|
|
|
|
|
PackagedP pack;
|
|
|
|
|
try { pack = packages.openAny(p->name, true); }
|
|
|
|
|
catch (PackageNotFoundError&) { } // We couldn't open a package... no cause for alarm
|
|
|
|
|
|
|
|
|
|
if (!pack || !(wxFileExists(pack->absoluteFilename()) || wxDirExists(pack->absoluteFilename()))) {
|
|
|
|
|
// not installed
|
|
|
|
|
if (p->app_version > file_version) {
|
|
|
|
|
package_data[p] = PackageData(STATUS_NOT_INSTALLED, ACTION_NEW_MSE);
|
|
|
|
|
} else {
|
|
|
|
|
package_data[p] = PackageData(STATUS_NOT_INSTALLED, ACTION_NOTHING);
|
|
|
|
|
}
|
|
|
|
|
} else if (pack->version < p->version) {
|
|
|
|
|
// newer version
|
|
|
|
|
if (p->app_version > file_version) {
|
|
|
|
|
package_data[p] = PackageData(STATUS_UPGRADEABLE, ACTION_NEW_MSE);
|
|
|
|
|
} else {
|
|
|
|
|
package_data[p] = PackageData(STATUS_UPGRADEABLE, ACTION_UPGRADE);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
package_data[p] = PackageData(STATUS_INSTALLED, ACTION_NOTHING);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Select the dependencies for a package
|
|
|
|
|
/**
|
|
|
|
|
* \param pack The package data to check dependencies for.
|
|
|
|
|
*
|
|
|
|
|
* This function will select all the dependencies for the package, to ensure
|
|
|
|
|
* that the user can't install a package without it's dependencies.
|
|
|
|
|
* /
|
|
|
|
|
void PackagesWindow::SelectPackageDependencies (PackageVersionDataP pack) {
|
|
|
|
|
FOR_EACH(dep, pack->depends) {
|
|
|
|
|
if (packages.checkDependency(*dep, false)) //It's already installed.
|
|
|
|
|
continue;
|
|
|
|
|
FOR_EACH(p, update_version_data->packages) {
|
|
|
|
|
if (p->name == dep->package) { //We have a match.
|
|
|
|
|
if (p->version >= dep->version) { //Versions line up
|
|
|
|
|
|
|
|
|
|
PackageStatus& status = package_data[p].first;
|
|
|
|
|
PackageAction& action = package_data[p].second;
|
|
|
|
|
if (status == STATUS_NOT_INSTALLED)
|
|
|
|
|
action = ACTION_INSTALL;
|
|
|
|
|
else if (status == STATUS_UPGRADEABLE)
|
|
|
|
|
action = ACTION_UPGRADE;
|
|
|
|
|
else //status == STATUS_INSTALLED
|
|
|
|
|
action = ACTION_NOTHING;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// TODO: Decide what to do if a dependency can't be met.
|
|
|
|
|
// It shouldn't happen with a decently maintained updates list.
|
|
|
|
|
// But it could, and we need to decide what to do in this situation.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This finds all packages that depend on the one provided and marks them for removal.
|
|
|
|
|
void PackagesWindow::RemovePackageDependencies (PackageVersionDataP pack) {
|
|
|
|
|
FOR_EACH(p, update_version_data->packages) {
|
|
|
|
|
FOR_EACH(dep, p->depends) {
|
|
|
|
|
if (pack->name == dep->package) {
|
|
|
|
|
PackageStatus& status = package_data[p].first;
|
|
|
|
|
PackageAction& action = package_data[p].second;
|
|
|
|
|
|
|
|
|
|
if (status != STATUS_NOT_INSTALLED)
|
|
|
|
|
action = ACTION_UNINSTALL;
|
|
|
|
|
else // status == STATUS_NOT_INSTALLED
|
|
|
|
|
action = p->app_version > file_version ? ACTION_NEW_MSE : ACTION_NOTHING;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// This deals with the complexities of a downgrade and its dependencies.
|
|
|
|
|
void PackagesWindow::DowngradePackageDependencies (PackageVersionDataP pack) {
|
|
|
|
|
PackagedP old_pack = packages.openAny(pack->name, true);
|
|
|
|
|
FOR_EACH(dep, old_pack->dependencies) {
|
|
|
|
|
// dependencies the old version has, but the new one might not.
|
|
|
|
|
if (packages.checkDependency(*dep, false)) //It's already installed.
|
|
|
|
|
continue;
|
|
|
|
|
FOR_EACH(p, update_version_data->packages) {
|
|
|
|
|
if (p->name == dep->package) { //We have a match.
|
|
|
|
|
if (p->version >= dep->version) { //Versions line up
|
|
|
|
|
if (p->app_version > file_version) //We can't install this
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
PackageStatus& status = package_data[p].first;
|
|
|
|
|
PackageAction& action = package_data[p].second;
|
|
|
|
|
if (status == STATUS_NOT_INSTALLED)
|
|
|
|
|
action = ACTION_INSTALL;
|
|
|
|
|
else if (status == STATUS_UPGRADEABLE)
|
|
|
|
|
action = ACTION_UPGRADE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// TODO: Decide what to do if a dependency can't be met.
|
|
|
|
|
// It shouldn't happen with a decently maintained updates list.
|
|
|
|
|
// But it could, and we need to decide what to do in this situation.
|
|
|
|
|
// Ideally, some sort of error should occur, such that we don't have packages
|
|
|
|
|
// with unmet dependencies.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FOR_EACH(p, update_version_data->packages) {
|
|
|
|
|
// dependencies that can no longer be met.
|
|
|
|
|
FOR_EACH(dep, p->depends) {
|
|
|
|
|
if (pack->name == dep->package) {
|
|
|
|
|
if (old_pack->version > dep->version) {
|
|
|
|
|
PackageStatus& status = package_data[p].first;
|
|
|
|
|
PackageAction& action = package_data[p].second;
|
|
|
|
|
|
|
|
|
|
if (status != STATUS_NOT_INSTALLED)
|
|
|
|
|
action = ACTION_UNINSTALL;
|
|
|
|
|
else // status == STATUS_NOT_INSTALLED
|
|
|
|
|
action = p->app_version > file_version ? ACTION_NEW_MSE : ACTION_NOTHING;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
|
|
|
|
|
// EVT_COMMAND(wxID_ANY, UPDATE_CHECK_FINISHED_EVT, PackagesWindow::onUpdateCheckFinished)
|
|
|
|
|
EVT_LISTBOX(ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
|
|
|
|
|
EVT_BUTTON(ID_INSTALL, PackagesWindow::onActionChange)
|
|
|
|
|
EVT_BUTTON(ID_REMOVE, PackagesWindow::onActionChange)
|
|
|
|
|
EVT_BUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
|
|
|
|
|
EVT_BUTTON(wxID_OK, PackagesWindow::onOk)
|
|
|
|
|
EVT_UPDATE_UI(wxID_ANY, PackagesWindow::onUpdateUI)
|
|
|
|
|
EVT_IDLE ( PackagesWindow::onIdle)
|
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|