39#include <wx/progdlg.h>
41#include <wx/statline.h>
42#include <wx/textwrapper.h>
44#include "catalog_mgr.h"
45#include "update_mgr.h"
46#include "plugin_loader.h"
47#include "downloader.h"
48#include "OCPNPlatform.h"
49#include "plugin_handler.h"
50#include "pluginmanager.h"
51#include "semantic_vers.h"
68 Wrap(win, text, widthMax);
70 wxString
const& GetWrapped()
const {
return m_wrapped; }
71 int const GetLineCount()
const {
return m_lineCount; }
74 virtual void OnOutputLine(
const wxString& line) { m_wrapped += line; }
75 virtual void OnNewLine() {
94static ssize_t PlugInIxByName(
const std::string name, ArrayOfPlugIns* plugins) {
95 for (
unsigned i = 0; i < plugins->GetCount(); i += 1) {
96 if (name == plugins->Item(i)->m_common_name.Lower().ToStdString()) {
105 ArrayOfPlugIns* plugins) {
106 auto ix = PlugInIxByName(name, plugins);
107 return ix == -1 ? 0 : plugins->Item(ix);
111static void LoadPNGIcon(
const char* path,
int size, wxBitmap& bitmap) {
112 wxPNGHandler handler;
113 if (!wxImage::FindHandler(handler.GetName())) {
114 wxImage::AddHandler(
new wxPNGHandler());
116 auto img =
new wxImage();
117 bool ok = img->LoadFile(path, wxBITMAP_TYPE_PNG);
122 img->Rescale(size, size);
123 bitmap = wxBitmap(*img);
135 : wxPanel(parent), m_plugin_name(plugin_name) {
136 auto size = GetClientSize();
137 auto minsize = GetTextExtent(
"OpenCPN");
138 SetMinClientSize(wxSize(minsize.GetWidth(), size.GetHeight()));
140 Bind(wxEVT_PAINT, &PluginIconPanel::OnPaint,
this);
143 void OnPaint(wxPaintEvent& event) {
144 auto size = GetClientSize();
145 int minsize = wxMin(size.GetHeight(), size.GetWidth());
146 auto offset = minsize / 10;
148 LoadIcon(
"packageBox.svg", m_bitmap, 2 * minsize / 3);
150 if (!m_bitmap.IsOk()) {
151 wxLogMessage(
"AddPluginPanel: bitmap is not OK!");
154 dc.DrawBitmap(m_bitmap, offset, offset,
true);
159 const std::string m_plugin_name;
161 void LoadIcon(
const char* plugin_name, wxBitmap& bitmap,
int size = 32) {
162 wxFileName path(g_Platform->GetSharedDataDir(), plugin_name);
163 path.AppendDir(
"uidata");
164 path.AppendDir(
"traditional");
167 if (path.IsFileReadable()) {
168 bitmap = LoadSVG(path.GetFullPath(), size, size);
173 auto style = g_StyleManager->GetCurrentStyle();
174 bitmap = wxBitmap(style->GetIcon(_T(
"default_pi"), size, size));
175 wxLogMessage(
"Icon: %s not found.", path.GetFullPath());
199 : wxPanel(parent), m_metadata(metadata), m_remove(
false) {
200 auto loader = PluginLoader::getInstance();
202 PlugInByName(metadata.name, loader->GetPlugInArray());
203 std::string label(_(
"Install"));
205 ((found->m_version_major > 0) || (found->m_version_minor > 0))) {
206 label = getUpdateLabel(found, metadata);
209 auto button =
new wxButton(
this, wxID_ANY, label);
210 auto pluginHandler = PluginHandler::getInstance();
211 auto box =
new wxBoxSizer(wxHORIZONTAL);
214 Bind(wxEVT_COMMAND_BUTTON_CLICKED, &InstallButton::OnClick,
this);
217 void OnClick(wxCommandEvent& event) {
218 wxLogMessage(
"Selected update: %s", m_metadata.name.c_str());
219 auto top_parent = GetParent()->GetParent()->GetParent();
221 wxASSERT(dialog != 0);
222 dialog->SetUpdate(m_metadata);
223 dialog->EndModal(wxID_OK);
231 SemanticVersion currentVersion(pic->m_version_major, pic->m_version_minor);
232 if (pic->m_version_str !=
"") {
236 if (newVersion > currentVersion) {
238 }
else if (newVersion == currentVersion) {
239 return _(
"Reinstall");
241 return _(
"Downgrade");
250 : wxPanel(parent), m_url(url) {
251 auto vbox =
new wxBoxSizer(wxVERTICAL);
252 auto button =
new wxButton(
this, wxID_ANY, _(
"Website"));
253 button->Enable(strlen(url) > 0);
256 Bind(wxEVT_COMMAND_BUTTON_CLICKED,
257 [=](wxCommandEvent&) { wxLaunchDefaultBrowser(m_url); });
261 const std::string m_url;
269 auto flags = wxSizerFlags().Border();
271 auto vbox =
new wxBoxSizer(wxVERTICAL);
273 flags.DoubleBorder().Top().Right());
274 vbox->Add(1, 1, 1, wxEXPAND);
277 vbox->Add(m_info_btn, flags.DoubleBorder().Right());
282 void HideDetails(
bool hide) {
283 m_info_btn->Show(!hide);
284 GetParent()->Layout();
296 : wxPanel(parent), m_descr(0), m_buttons(buttons) {
297 auto flags = wxSizerFlags().Border();
300 MORE =
"<span foreground=\'blue\'>";
302 MORE +=
"...</span>";
303 LESS =
"<span foreground=\'blue\'>";
305 LESS +=
"...</span>";
307 auto sum_hbox =
new wxBoxSizer(wxHORIZONTAL);
308 m_widthDescription = g_options->GetSize().x / 2;
311 m_summary =
new wxStaticText(
312 this, wxID_ANY, _T(
""), wxDefaultPosition,
313 wxSize(m_widthDescription, -1) );
314 m_summaryText = wxString(plugin->summary.c_str());
315 m_summary->SetLabel(m_summaryText);
316 m_summary->Wrap(m_widthDescription);
319 m_summaryLineCount = wrapper.GetLineCount() + 1;
321 sum_hbox->Add(m_summary);
322 sum_hbox->AddSpacer(10);
323 m_more = staticText(
"");
324 m_more->SetLabelMarkup(MORE);
325 sum_hbox->Add(m_more, wxSizerFlags());
327 auto vbox =
new wxBoxSizer(wxVERTICAL);
330 wxString nameText(plugin->name +
" " + plugin->version);
331 if (bshowTuple) nameText +=
" " + plugin->target;
333 auto name = staticText(nameText);
335 m_descr =
new wxStaticText(
336 this, wxID_ANY, _T(
""), wxDefaultPosition,
337 wxSize(m_widthDescription, -1) );
338 m_descText = wxString(plugin->description.c_str());
339 m_descr->SetLabel(m_descText);
340 m_descr->Wrap(m_widthDescription);
342 vbox->Add(name, flags);
343 vbox->Add(sum_hbox, flags);
344 vbox->Add(m_descr, 0);
347 m_more->Bind(wxEVT_LEFT_DOWN, &PluginTextPanel::OnClick,
this);
348 m_descr->Bind(wxEVT_LEFT_DOWN, &PluginTextPanel::OnClick,
this);
351 void OnClick(wxMouseEvent& event) {
352 m_descr->Show(!m_descr->IsShown());
353 m_descr->SetLabel(_T(
""));
354 m_descr->SetLabel(m_descText);
355 m_descr->Wrap(m_widthDescription);
357 wxSize asize = GetEffectiveMinSize();
359 m_more->SetLabelMarkup(m_descr->IsShown() ? LESS : MORE);
360 m_buttons->HideDetails(!m_descr->IsShown());
364 swin->RecalculateSize();
368 int m_summaryLineCount;
374 wxStaticText* staticText(
const wxString& text) {
375 return new wxStaticText(
this, wxID_ANY, text, wxDefaultPosition,
376 wxDefaultSize, wxALIGN_LEFT);
379 wxStaticText* m_descr;
380 wxStaticText* m_more;
381 wxStaticText* m_summary;
383 int m_widthDescription;
385 wxString m_summaryText;
395 const std::vector<PluginMetadata>& updates)
396 : wxScrolledWindow(parent),
398 m_grid(
new wxFlexGridSizer(3, 0, 0)) {
399 auto box =
new wxBoxSizer(wxVERTICAL);
401 box->Add(m_grid, wxSizerFlags().Proportion(0).Expand());
402 auto butt_box =
new wxBoxSizer(wxHORIZONTAL);
403 auto cancel_btn =
new wxButton(
this, wxID_CANCEL, _(
"Dismiss"));
404 butt_box->Add(1, 1, 1, wxEXPAND);
405 butt_box->Add(cancel_btn, wxSizerFlags().Border());
406 box->Add(butt_box, wxSizerFlags().Proportion(0).Expand());
409 SetMinSize(GetEffectiveMinSize());
415 struct metadata_compare {
418 return lhs.key() < rhs.key();
422 auto flags = wxSizerFlags();
424 grid->AddGrowableCol(2);
425 for (
auto plugin : m_updates) {
430 tpanel->m_isDesc =
true;
431 grid->Add(tpanel, flags.Proportion(1).Right());
432 grid->Add(buttons, flags.DoubleBorder());
433 grid->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
434 grid->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
435 grid->Add(
new wxStaticLine(
this), wxSizerFlags(0).Expand());
440 const std::vector<PluginMetadata> m_updates;
441 wxFlexGridSizer* m_grid;
448 const std::vector<PluginMetadata>& updates)
449 : wxDialog(parent, wxID_ANY, _(
"Plugin Manager"), wxDefaultPosition,
450 wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {
451 auto vbox =
new wxBoxSizer(wxVERTICAL);
455 vbox->Add(m_scrwin, wxSizerFlags(1).Expand());
462void UpdateDialog::RecalculateSize() {
465 wxWindowList& kids = m_scrwin->GetChildren();
466 for (
unsigned int i = 0; i < kids.GetCount(); i++) {
467 wxWindowListNode* node = kids.Item(i);
468 wxWindow* win = node->GetData();
472 if (panel->m_isDesc) {
473 wxSize tsize = win->GetEffectiveMinSize();
474 calcHeight += tsize.y + GetCharHeight();
475 calcWidth = tsize.x * 2;
480 calcHeight += 3 * GetCharHeight();
481 calcWidth = wxMin(calcWidth, g_Platform->getDisplaySize().x);
483 m_scrwin->SetMinSize(wxSize(calcWidth, calcHeight));
485#ifdef __OCPN__ANDROID__
486 SetMinSize(g_Platform->getDisplaySize());
489 SetMaxSize(g_Platform->getDisplaySize());
A plugin icon, scaled to about 2/3 of available space.
Plugin name, version, summary + an optionally shown description.
Modal dialog, displays available updates (possibly just one) and lets user select and eventually conf...
UpdateDialog(wxWindow *parent, const std::vector< PluginMetadata > &updates)
Top-level install plugins dialog.
Versions uses a modified semantic versioning scheme: major.minor.revision.post-tag+build.
static SemanticVersion parse(std::string s)
Parse a version string, sets major == -1 on errors.