1 /***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: PlugIn Manager Object
5 * Author: David Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by David S. Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 **************************************************************************/
25
26 #include <config.h>
27
28 #ifdef __MINGW32__
29 #undef IPV6STRICT // mingw FTBS fix: missing struct ip_mreq
30 #include <windows.h>
31 #endif
32
33 #include <typeinfo>
34 #if defined(__linux__) && !defined(__OCPN__ANDROID__)
35 #include <wordexp.h>
36 #endif
37 #include <wx/wx.h>
38 #include <wx/dir.h>
39 #include <wx/event.h>
40 #include <wx/filename.h>
41 #include <wx/aui/aui.h>
42 #include <wx/platinfo.h>
43 #include <wx/popupwin.h>
44 #include <wx/progdlg.h>
45 #include <wx/statline.h>
46 #include <wx/tokenzr.h>
47 #include <wx/tooltip.h>
48 #include <wx/app.h>
49 #include <wx/hashset.h>
50 #include <wx/hashmap.h>
51 #include <wx/uri.h>
52 #include <wx/zipstrm.h>
53 #include <wx/zstream.h>
54 #include <wx/tarstrm.h>
55
56 #ifndef __WXMSW__
57 #include <cxxabi.h>
58 #endif // __WXMSW__
59
60 #include <stdint.h>
61 #include <fcntl.h>
62 #include <errno.h>
63 #include <cstdio>
64 #include <memory>
65 #include <iostream>
66
67 #include <algorithm>
68 #include <cstdio>
69 #include <string>
70 #include <set>
71 #include <iostream>
72
73 #include <archive.h>
74 #include <archive_entry.h>
75 typedef __LA_INT64_T la_int64_t; // "older" libarchive versions support
76
77 #ifdef ocpnUSE_SVG
78 #include <wxSVG/svg.h>
79 #endif // ocpnUSE_SVG
80
81 #ifdef USE_LIBELF
82 #include <elf.h>
83 #include <libelf.h>
84 #include <gelf.h>
85 #endif
86
87 #include <sstream>
88 #include <fstream>
89 #include <unordered_map>
90 #include "config.h"
91 #include "SoundFactory.h"
92 #include "dychart.h"
93 #include "PluginHandler.h"
94 #include "pluginmanager.h"
95 #include "navutil.h"
96 #include "ais.h"
97 #include "chartbase.h" // for ChartPlugInWrapper
98 #include "chartdb.h"
99 #include "chartdbs.h"
100 #include "Downloader.h"
101 #include "ocpndc.h"
102 #include "styles.h"
103 #include "options.h"
104 #include "multiplexer.h"
105 #include "logger.h"
106 #include "ocpn_utils.h"
107 #include "piano.h"
108 #include "safe_mode.h"
109 #include "routeman.h"
110 #include "FontMgr.h"
111 #include "AIS_Decoder.h"
112 #include "AIS_Target_Data.h"
113 #include "OCPN_DataStreamEvent.h"
114 #include "georef.h"
115 #include "routemanagerdialog.h"
116 #include "NavObjectCollection.h"
117 #include "OCPNRegion.h"
118 #include "s52plib.h"
119 #include "ocpn_pixel.h"
120 #include "s52utils.h"
121 #include "gshhs.h"
122 #include "mygeom.h"
123 #include "OCPNPlatform.h"
124 #include "PluginPaths.h"
125 #include "toolbar.h"
126 #include "Track.h"
127 #include "Route.h"
128 #include "OCPN_AUIManager.h"
129 #include "chcanv.h"
130 #include "canvasMenu.h"
131 #include "download_mgr.h"
132 #include "catalog_handler.h"
133 #include "semantic_vers.h"
134 #include "update_mgr.h"
135
136 #ifdef __OCPN__ANDROID__
137 #include "androidUTIL.h"
138 #include <dlfcn.h>
139 #endif
140
141 #ifdef ocpnUSE_GL
142 #include "glChartCanvas.h"
143 #endif
144
145 extern wxImage LoadSVGIcon( wxString filename, int width, int height );
146
147 extern MyConfig *pConfig;
148 extern AIS_Decoder *g_pAIS;
149 extern OCPN_AUIManager *g_pauimgr;
150
151 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3,0,0)
152 extern wxLocale *plocale_def_lang;
153 #endif
154
155 extern OCPNPlatform *g_Platform;
156 extern ChartDB *ChartData;
157 extern MyFrame *gFrame;
158 extern ocpnStyle::StyleManager* g_StyleManager;
159 extern options *g_pOptions;
160 extern Multiplexer *g_pMUX;
161 extern bool g_bShowChartBar;
162 extern Routeman *g_pRouteMan;
163 extern WayPointman *pWayPointMan;
164 extern Select *pSelect;
165 extern RouteManagerDialog *pRouteManagerDialog;
166 extern RouteList *pRouteList;
167 extern TrackList *pTrackList;
168 extern PlugInManager *g_pi_manager;
169 extern s52plib *ps52plib;
170 extern wxString ChartListFileName;
171 extern bool g_boptionsactive;
172 extern options *g_options;
173 extern ColorScheme global_color_scheme;
174 extern wxArrayString g_locale_catalog_array;
175 extern int g_GUIScaleFactor;
176 extern int g_ChartScaleFactor;
177 extern wxString g_locale;
178 extern bool g_btouch;
179 extern ocpnFloatingToolbarDialog *g_MainToolbar;
180
181 extern int g_chart_zoom_modifier;
182 extern int g_chart_zoom_modifier_vector;
183 extern double g_display_size_mm;
184 extern bool g_bopengl;
185
186 extern ChartGroupArray *g_pGroupArray;
187 extern unsigned int g_canvasConfig;
188
189 extern wxString g_CmdSoundString;
190
191 extern int g_iSDMMFormat;
192
193 unsigned int gs_plib_flags;
194 wxString g_lastPluginMessage;
195 extern ChartCanvas *g_focusCanvas;
196 extern ChartCanvas *g_overlayCanvas;
197 extern bool g_bquiting;
198 extern wxString g_ownshipMMSI_SK;
199
200 WX_DEFINE_ARRAY_PTR(ChartCanvas*, arrayofCanvasPtr);
201 extern arrayofCanvasPtr g_canvasArray;
202
203 const char* const LINUX_LOAD_PATH = "~/.local/lib:/usr/local/lib:/usr/lib";
204 const char* const FLATPAK_LOAD_PATH = "~/.var/app/org.opencpn.OpenCPN/lib";
205
206 void NotifySetupOptionsPlugin( PlugInContainer *pic );
207
208 enum
209 {
210 CurlThreadId = wxID_HIGHEST+1
211 };
212
213 #include <wx/listimpl.cpp>
214 WX_DEFINE_LIST(Plugin_WaypointList);
215 WX_DEFINE_LIST(Plugin_HyperlinkList);
216
217 static const std::vector<std::string> SYSTEM_PLUGINS = {
218 "chartdownloader", "wmm", "dashboard", "grib"
219 };
220
221 struct EnumClassHash
222 {
223 template <typename T>
operator ()EnumClassHash224 std::size_t operator()(T t) const
225 {
226 return static_cast<std::size_t>(t);
227 }
228 };
229
230
231 static std::unordered_map<PluginStatus, const char*, EnumClassHash>
232 message_by_status({
233 {PluginStatus::System,
234 _("Plugin is a standard system plugin") },
235 {PluginStatus::Managed,
236 _("Plugin is managed by OpenCPN") },
237 {PluginStatus::Unmanaged,
238 _("Plugin is not managed by OpenCPN") },
239 {PluginStatus::Ghost,
240 _("") },
241 {PluginStatus::Unknown,
242 _("Plugin status unknown") },
243 {PluginStatus::LegacyUpdateAvailable,
244 _("Update to managed Plugin is available") },
245 {PluginStatus::ManagedInstallAvailable,
246 _("New managed Plugin installation available") },
247 {PluginStatus::ManagedInstalledUpdateAvailable,
248 _("Update to installed Plugin is available") },
249 {PluginStatus::ManagedInstalledCurrentVersion,
250 _("Plugin is latest available") },
251 {PluginStatus::ManagedInstalledDowngradeAvailable,
252 _("") },
253 {PluginStatus::PendingListRemoval,
254 _("") }
255
256
257 });
258
259
260 static std::unordered_map<PluginStatus, const char*, EnumClassHash>
261 icon_by_status({
262 {PluginStatus::System, "emblem-system.svg" },
263 {PluginStatus::Managed, "emblem-default.svg" },
264 {PluginStatus::Unmanaged, "emblem-unmanaged.svg" },
265 {PluginStatus::Ghost, "ghost.svg" },
266 {PluginStatus::Unknown, "emblem-default.svg" },
267 {PluginStatus::LegacyUpdateAvailable, "emblem-legacy-update.svg" },
268 {PluginStatus::ManagedInstallAvailable, "emblem-default.svg" },
269 {PluginStatus::ManagedInstalledUpdateAvailable, "emblem-legacy-update.svg" },
270 {PluginStatus::ManagedInstalledCurrentVersion, "emblem-default.svg" },
271 {PluginStatus::ManagedInstalledDowngradeAvailable, "emblem-default.svg" },
272 {PluginStatus::PendingListRemoval, "emblem-default.svg" }
273
274 });
275
276 static std::unordered_map<PluginStatus, const char*, EnumClassHash>
277 literalstatus_by_status({
278 {PluginStatus::System, "System" },
279 {PluginStatus::Managed, "Managed" },
280 {PluginStatus::Unmanaged, "Unmanaged" },
281 {PluginStatus::Ghost, "Ghost" },
282 {PluginStatus::Unknown, "Unknown" },
283 {PluginStatus::LegacyUpdateAvailable, "LegacyUpdateAvailable" },
284 {PluginStatus::ManagedInstallAvailable, "ManagedInstallAvailable" },
285 {PluginStatus::ManagedInstalledUpdateAvailable, "ManagedInstalledUpdateAvailable" },
286 {PluginStatus::ManagedInstalledCurrentVersion, "ManagedInstalledCurrentVersion" },
287 {PluginStatus::ManagedInstalledDowngradeAvailable, "ManagedInstalledDowngradeAvailable" },
288 {PluginStatus::PendingListRemoval, "PendingListRemoval" }
289
290 });
291
292
293
294 /**
295 * Return list of available, unique and compatible plugins from
296 * configured XML catalog.
297 */
getCompatiblePlugins()298 static std::vector<PluginMetadata> getCompatiblePlugins()
299 {
300 /** Compare two PluginMetadata objects, a named c++ requirement. */
301 struct metadata_compare{
302 bool operator() (const PluginMetadata& lhs,
303 const PluginMetadata& rhs) const
304 {
305 return lhs.key() < rhs.key();
306 }
307 };
308
309 std::vector<PluginMetadata> returnArray;
310
311 std::set<PluginMetadata, metadata_compare> unique_plugins;
312 for (auto plugin: PluginHandler::getInstance()->getAvailable()) {
313 unique_plugins.insert(plugin);
314 }
315 for (auto plugin: unique_plugins) {
316 if (PluginHandler::isCompatible(plugin)) {
317 returnArray.push_back(plugin);
318 }
319 }
320 return returnArray;
321 }
322
323
metadata_version(const PluginMetadata pm)324 static SemanticVersion metadata_version(const PluginMetadata pm)
325 {
326 return SemanticVersion::parse(pm.name);
327 }
328
329
330 // Get installed version from manifest for given plugin. For
331 // older plugins this contains more detailed info then the
332 // plugin API. From API level 117 the API should contain the
333 // same info.
334 //
335 // TODO: Get version from API for api level 117+
getInstalledVersion(const std::string name)336 SemanticVersion getInstalledVersion(const std::string name)
337 {
338 std::string installed;
339 std::string path = PluginHandler::versionPath(name);
340 if (path == "" || !wxFileName::IsFileReadable(path)) {
341 return SemanticVersion(-1, -1);
342 }
343 std::ifstream stream;
344 stream.open(path, std::ifstream::in);
345 stream >> installed;
346 return SemanticVersion::parse(installed);
347 }
348
349
350 /**
351 * Return list of all versions of given plugin name besides installed
352 * one.
353 */
getUpdates(const char * name)354 static std::vector<PluginMetadata> getUpdates(const char* name)
355 {
356 auto updates = getCompatiblePlugins();
357 updates.erase(
358 std::remove_if(updates.begin(), updates.end(),
359 [&](const PluginMetadata m) { return m.name != name; }),
360 updates.end());
361
362 auto inst_vers = getInstalledVersion(name);
363 if (inst_vers.major == -1) {
364 return updates;
365 }
366
367 // Drop already installed plugin, it has its own update options.
368 updates.erase(
369 std::remove_if(
370 updates.begin(), updates.end(),
371 [&](const PluginMetadata m) {
372 return metadata_version(m) == inst_vers; }),
373 updates.end());
374 return updates;
375 }
376
377
378 /**
379 * Return number of existing files named filename in the list of
380 * dirs.
381 */
count_files_in_dirs(const char * filename,const std::vector<std::string> dirs)382 static int count_files_in_dirs(const char* filename,
383 const std::vector<std::string> dirs)
384 {
385 int count = 0;
386 for (auto dir: dirs) {
387 const std::string sep(1, wxFileName::GetPathSeparator());
388 auto path = dir + sep + filename;
389 if (ocpn::exists(path)) {
390 count += 1;
391 }
392 }
393 return count;
394 }
395
396
getLatestUpdate()397 static PluginMetadata getLatestUpdate()
398 {
399 auto updates = getCompatiblePlugins();
400 if (updates.size() == 0) {
401 PluginMetadata metadata;
402 return metadata;
403 }
404 std::sort(updates.begin(), updates.end(),
405 [](PluginMetadata m1, PluginMetadata m2) {
406 return !(m1.version < m2.version);
407 }
408 );
409 return updates[0];
410 }
411
412
run_update_dialog(PluginListPanel * parent,PlugInContainer * pic,bool uninstall,const char * name=0)413 static void run_update_dialog(PluginListPanel* parent,
414 PlugInContainer* pic,
415 bool uninstall,
416 const char* name = 0)
417 {
418 wxString pluginName = pic->m_common_name;
419 const char* plugin = name == 0 ? pic->m_common_name.mb_str().data() : name;
420 auto updates = getUpdates(plugin);
421 auto parent_dlg = dynamic_cast<wxScrolledWindow*>(parent->GetParent());
422 wxASSERT(parent_dlg != 0);
423 UpdateDialog dialog(parent_dlg, updates);
424 auto status = dialog.ShowModal();
425 status = dialog.GetReturnCode();
426 if (status != wxID_OK) {
427 return;
428 }
429
430 auto update = dialog.GetUpdate();
431 if (uninstall) {
432 g_Platform->ShowBusySpinner();
433 g_pi_manager->DeactivatePlugIn(pic);
434 pic->m_bEnabled = false;
435 g_pi_manager->UpdatePlugIns();
436
437 wxLogMessage("Uninstalling %s", plugin);
438 PluginHandler::getInstance()->uninstall(plugin);
439 g_pi_manager->UpdatePlugIns();
440 g_Platform->HideBusySpinner();
441
442 }
443
444 wxLogMessage("Installing %s", update.name.c_str());
445
446 auto pluginHandler = PluginHandler::getInstance();
447 bool cacheResult = pluginHandler->installPluginFromCache( update );
448
449 if(!cacheResult){
450 g_Platform->ShowBusySpinner(); // Will be cancelled in downloader->run()
451 wxYield();
452
453 auto downloader = new GuiDownloader(parent_dlg, update);
454 std::string tempTarballPath = downloader->run(parent_dlg);
455
456 // Provisional error check
457 bool bOK = true;
458 std::string manifestPath =
459 PluginHandler::fileListPath(update.name);
460 if(!isRegularFile(manifestPath.c_str())) {
461 wxLogMessage("Installation of %s failed", update.name.c_str());
462 PluginHandler::cleanupFiles(manifestPath, update.name);
463 bOK = false;
464 }
465
466 // On successful installation, copy the temp tarball to the local cache
467 if(bOK){
468 wxLogMessage("Installation of %s successful", update.name.c_str());
469
470 wxURI uri( wxString(update.tarball_url.c_str()));
471 wxFileName fn(uri.GetPath());
472 wxString tarballFile = fn.GetFullName();
473 wxString cacheDir = g_Platform->GetPrivateDataDir() + _T("/") + _T("plugins");
474 wxString sep = _T("/");
475 if( !wxDirExists(cacheDir) )
476 wxMkdir( cacheDir);
477 cacheDir += sep + wxString(_T("cache"));
478 if( !wxDirExists(cacheDir) )
479 wxMkdir( cacheDir);
480 cacheDir += sep + wxString(_T("tarballs"));
481 if( !wxDirExists(cacheDir) )
482 wxMkdir( cacheDir);
483
484 wxString destination = cacheDir + _T("/") + tarballFile;
485 wxLogMessage(" Trying to copy %s ", tempTarballPath.c_str());
486
487 if(wxFileExists(wxString( tempTarballPath.c_str()))){
488 wxLogMessage("Copying %s to local cache", tarballFile.c_str());
489 wxCopyFile( wxString( tempTarballPath.c_str()), destination);
490 remove(tempTarballPath.c_str());
491 }
492 }
493 }
494
495 // Check the library compatibility of the installed plugin
496 // Find the first dll/so/dylib file
497 #ifdef __WXMSW__
498 wxString pispec = _T(".dll");
499 #elif defined(__WXOSX__)
500 wxString pispec = _T(".dylib");
501 #else
502 wxString pispec = _T(".so");
503 #endif
504
505 std::string manifestPath = PluginHandler::fileListPath(update.name);
506 wxTextFile manifest_file(manifestPath);
507 if( manifest_file.Open()){
508 wxString val;
509 for ( wxString str = manifest_file.GetFirstLine(); !manifest_file.Eof() ; str = manifest_file.GetNextLine() ){
510 if(str.Contains(pispec)){
511 if (getenv("OCPN_KEEP_PLUGINS")) {
512 // Undocumented debug hook
513 continue;
514 }
515 if( !g_pi_manager->CheckPluginCompatibility(str)){
516 wxString msg = _("The plugin is not compatible with this version of OpenCPN, and will be uninstalled.");
517 OCPNMessageBox( NULL, msg, wxString(_("OpenCPN Info")), wxICON_INFORMATION | wxOK, 10 );
518
519 PluginHandler::cleanupFiles(manifestPath, update.name);
520 }
521 break;
522 }
523 }
524 }
525
526
527 // Reload all plugins, which will bring in the action results.
528 g_pi_manager->LoadAllPlugIns( false );
529
530 // Check to see if this plugin needs an options instance reload
531 if(g_options){
532 bool b_newOptions = false;
533 for(unsigned int i = 0 ; i < g_pi_manager->GetPlugInArray()->GetCount() ; i++)
534 {
535 PlugInContainer *pic = g_pi_manager->GetPlugInArray()->Item(i);
536 wxString cname = pic->m_common_name;
537 if(pic->m_bInitState && (pluginName == cname)) {
538 if((pic->m_cap_flag & INSTALLS_TOOLBOX_PAGE)){
539 g_options->SetNeedNew( true );
540
541 NotifySetupOptionsPlugin(pic);
542 }
543 }
544 }
545 }
546
547 parent->ReloadPluginPanels(g_pi_manager->GetPlugInArray());
548 //wxString name(plugin);
549 //g_pi_manager->GetListPanelPtr()->SelectByName(name);
550 }
551
552
GetPluginDataDir(const char * plugin_name)553 wxString GetPluginDataDir(const char* plugin_name)
554 {
555 static const wxString sep = wxFileName::GetPathSeparator();
556
557 wxString datadirs = g_Platform->GetPluginDataPath();
558 wxLogMessage(_T("PlugInManager: Using data dirs from: ") + datadirs);
559 wxStringTokenizer dirs(datadirs, ";");
560 while (dirs.HasMoreTokens()) {
561 wxString dir = dirs.GetNextToken();
562 wxFileName tryDirName(dir);
563 wxDir tryDir;
564 if (!tryDir.Open(tryDirName.GetFullPath()))
565 continue;
566 wxString next;
567 bool more = tryDir.GetFirst(&next);
568 while (more) {
569 if (next == plugin_name) {
570 next = next.Prepend(tryDirName.GetFullPath() + sep);
571 wxLogMessage(_T("PlugInManager: using data dir: %s"), next);
572 return next;
573 }
574 more = tryDir.GetNext(&next);
575 }
576 tryDir.Close();
577 }
578 wxLogMessage(_T("Warnińg: no data directory found, using \"\""));
579 return "";
580 }
581
582
583 // Some static helper funtions
584 // Scope is local to this module
585
CreatePlugInViewport(const ViewPort & vp)586 PlugIn_ViewPort CreatePlugInViewport( const ViewPort &vp)
587 {
588 // Create a PlugIn Viewport
589 ViewPort tvp = vp;
590 PlugIn_ViewPort pivp;
591
592 pivp.clat = tvp.clat; // center point
593 pivp.clon = tvp.clon;
594 pivp.view_scale_ppm = tvp.view_scale_ppm;
595 pivp.skew = tvp.skew;
596 pivp.rotation = tvp.rotation;
597 pivp.chart_scale = tvp.chart_scale;
598 pivp.pix_width = tvp.pix_width;
599 pivp.pix_height = tvp.pix_height;
600 pivp.rv_rect = tvp.rv_rect;
601 pivp.b_quilt = tvp.b_quilt;
602 pivp.m_projection_type = tvp.m_projection_type;
603
604 pivp.lat_min = tvp.GetBBox().GetMinLat();
605 pivp.lat_max = tvp.GetBBox().GetMaxLat();
606 pivp.lon_min = tvp.GetBBox().GetMinLon();
607 pivp.lon_max = tvp.GetBBox().GetMaxLon();
608
609 pivp.bValid = tvp.IsValid(); // This VP is valid
610
611 return pivp;
612 }
613
CreateCompatibleViewport(const PlugIn_ViewPort & pivp)614 ViewPort CreateCompatibleViewport( const PlugIn_ViewPort &pivp)
615 {
616 // Create a system ViewPort
617 ViewPort vp;
618
619 vp.clat = pivp.clat; // center point
620 vp.clon = pivp.clon;
621 vp.view_scale_ppm = pivp.view_scale_ppm;
622 vp.skew = pivp.skew;
623 vp.rotation = pivp.rotation;
624 vp.chart_scale = pivp.chart_scale;
625 vp.pix_width = pivp.pix_width;
626 vp.pix_height = pivp.pix_height;
627 vp.rv_rect = pivp.rv_rect;
628 vp.b_quilt = pivp.b_quilt;
629 vp.m_projection_type = pivp.m_projection_type;
630
631 if(gFrame->GetPrimaryCanvas())
632 vp.ref_scale = gFrame->GetPrimaryCanvas()->GetVP().ref_scale;
633 else
634 vp.ref_scale = vp.chart_scale;
635
636 vp.SetBoxes();
637 vp.Validate(); // This VP is valid
638
639 return vp;
640 }
641
PlugInContainer()642 PlugInContainer::PlugInContainer()
643 {
644 m_pplugin = NULL;
645 m_bEnabled = false;
646 m_bInitState = false;
647 m_bToolboxPanel = false;
648 m_bitmap = NULL;
649 m_pluginStatus = PluginStatus::Unknown;
650 m_api_version = 0;
651 }
652
GetVersion()653 SemanticVersion PlugInContainer::GetVersion()
654 {
655 if(!m_pplugin){
656 return SemanticVersion(0,0,0);
657 }
658 auto plugin_117 = dynamic_cast<opencpn_plugin_117*>(m_pplugin);
659 if (plugin_117) {
660 return SemanticVersion(plugin_117->GetPlugInVersionMajor(),
661 plugin_117->GetPlugInVersionMinor(),
662 plugin_117->GetPlugInVersionPatch(),
663 plugin_117->GetPlugInVersionPost(),
664 plugin_117->GetPlugInVersionPre(),
665 plugin_117->GetPlugInVersionBuild());
666 }
667 else {
668 return SemanticVersion(m_pplugin->GetPlugInVersionMajor(),
669 m_pplugin->GetPlugInVersionMinor(),
670 -1); // Don't print .patch. It's unknown
671 }
672
673 }
674
675
676 class pluginUtilHandler : public wxEvtHandler
677 {
678 public:
679 pluginUtilHandler();
~pluginUtilHandler()680 ~pluginUtilHandler() {}
681
682 void OnPluginUtilAction( wxCommandEvent& event );
683
684
685 DECLARE_EVENT_TABLE()
686 };
687
688
BEGIN_EVENT_TABLE(pluginUtilHandler,wxEvtHandler)689 BEGIN_EVENT_TABLE ( pluginUtilHandler, wxEvtHandler )
690 EVT_BUTTON( ID_CMD_BUTTON_PERFORM_ACTION, pluginUtilHandler::OnPluginUtilAction )
691 END_EVENT_TABLE()
692
693 pluginUtilHandler::pluginUtilHandler()
694 {
695 }
696
OnPluginUtilAction(wxCommandEvent & event)697 void pluginUtilHandler::OnPluginUtilAction( wxCommandEvent& event )
698 {
699 auto panel = static_cast<PluginPanel*>(event.GetClientData());
700 PluginListPanel *plugin_list_panel = dynamic_cast<PluginListPanel*>(panel->GetGrandParent());
701 wxASSERT(plugin_list_panel != 0);
702
703 auto actionPIC = panel->GetPlugin();
704 wxString name = actionPIC->m_common_name;
705
706 // Perform the indicated action according to the verb...
707 switch (panel->GetAction()){
708 case ActionVerb::UPGRADE_TO_MANAGED_VERSION:
709 {
710 // capture the plugin name
711 std::string pluginName = actionPIC->m_ManagedMetadata.name;
712
713 wxLogMessage("Installing managed plugin: %s", pluginName.c_str());
714 auto downloader = new GuiDownloader(plugin_list_panel, actionPIC->m_ManagedMetadata);
715 downloader->run(plugin_list_panel);
716
717 // Provisional error check
718 std::string manifestPath = PluginHandler::fileListPath(pluginName);
719 if(isRegularFile(manifestPath.c_str())) {
720
721 // dynamically deactivate the legacy plugin, making way for the upgrade.
722 for (unsigned i = 0; i < g_pi_manager->GetPlugInArray()->GetCount(); i += 1) {
723 if (actionPIC->m_ManagedMetadata.name == g_pi_manager->GetPlugInArray()->Item(i)->m_common_name.ToStdString()) {
724 g_pi_manager->UnLoadPlugIn(i);
725 break;
726 }
727 }
728
729 // Reload all plugins, which will bring in the new, managed version.
730 g_pi_manager->LoadAllPlugIns( false );
731 }
732 else {
733 PluginHandler::cleanupFiles(manifestPath,
734 actionPIC->m_ManagedMetadata.name);
735 }
736 plugin_list_panel->ReloadPluginPanels(g_pi_manager->GetPlugInArray());
737 plugin_list_panel->SelectByName(name);
738
739 break;
740 }
741
742 case ActionVerb::UPGRADE_INSTALLED_MANAGED_VERSION:
743 case ActionVerb::REINSTALL_MANAGED_VERSION:
744 case ActionVerb::DOWNGRADE_INSTALLED_MANAGED_VERSION:
745 {
746 // Grab a copy of the managed metadata
747 auto metaSave = actionPIC->m_ManagedMetadata;
748 run_update_dialog(
749 plugin_list_panel, actionPIC, true, metaSave.name.c_str());
750 break;
751 }
752
753 case ActionVerb::INSTALL_MANAGED_VERSION:
754 {
755 wxLogMessage("Installing new managed plugin.");
756 run_update_dialog(plugin_list_panel, actionPIC, false);
757 break;
758 }
759
760 case ActionVerb::UNINSTALL_MANAGED_VERSION:
761 {
762 g_pi_manager->DeactivatePlugIn(actionPIC);
763
764 // Capture the confirmation dialog contents before the plugin goes away
765 wxString message;
766 message.Printf("%s %s\n", actionPIC->m_ManagedMetadata.name.c_str(),
767 actionPIC->m_ManagedMetadata.version.c_str());
768 message += _("successfully un-installed");
769
770 wxLogMessage("Uninstalling %s", actionPIC->m_ManagedMetadata.name.c_str());
771
772 PluginHandler::getInstance()->uninstall(actionPIC->m_ManagedMetadata.name);
773
774 // Reload all plugins, which will bring in the action results.
775 g_pi_manager->LoadAllPlugIns( false );
776 plugin_list_panel->ReloadPluginPanels(g_pi_manager->GetPlugInArray());
777
778 OCPNMessageBox(gFrame, message, _("Un-Installation complete"), wxICON_INFORMATION | wxOK);
779
780 break;
781 }
782
783 case ActionVerb::NOP:
784 default:
785 break;
786 }
787
788 }
789
790
791
792
793
794 /**
795 * A svg status icon, scaled to about 1/3 of available space
796 *
797 * Load icons from .../uidata/.
798 *
799 * Dont unbind in destructor:
800 * https://forums.wxwidgets.org/viewtopic.php?t=36399
801 */
802 class StatusIconPanel: public wxPanel
803 {
804 public:
StatusIconPanel(wxWindow * parent,const PlugInContainer * pic)805 StatusIconPanel(wxWindow* parent, const PlugInContainer* pic)
806 :wxPanel(parent)
807 {
808 m_parent = wxDynamicCast(parent, PluginPanel);
809
810 m_stat = pic->m_pluginStatus; //::Unknown;
811 SetToolTip(message_by_status[m_stat]);
812 m_icon_name = icon_by_status[m_stat];
813
814 m_penWidthUnselected = g_Platform->GetDisplayDPmm() * .25;
815 m_penWidthSelected = g_Platform->GetDisplayDPmm() * .5;
816
817 //SetBackgroundColour(GetGlobalColor(_T("DILG0")));
818 auto size = GetClientSize();
819 auto minsize = GetTextExtent("OpenCPNOpenCPNOpenCPNOpenCPN");
820 SetMinClientSize(wxSize(minsize.GetWidth(), size.GetHeight()));
821 Layout();
822 Bind(wxEVT_PAINT, &StatusIconPanel::OnPaint, this);
823 Bind(wxEVT_LEFT_DOWN, &StatusIconPanel::OnIconSelected, this);
824
825
826 }
827
OnPaint(wxPaintEvent & event)828 void OnPaint(wxPaintEvent& event)
829 {
830 auto size = GetClientSize();
831 // int minsize = wxMin(size.GetHeight(), size.GetWidth());
832 int minsize = GetCharWidth() * 3;
833 auto offset = minsize / 4;
834
835 LoadIcon(m_icon_name.c_str(), m_bitmap, wxMax(1, minsize));
836 wxPaintDC dc(this);
837 if (!m_bitmap.IsOk()) {
838 wxLogMessage("StatusPluginPanel: bitmap is not OK!");
839 return;
840 }
841
842 wxString color = "DILG0";
843 int penWidth = m_penWidthUnselected;
844
845 if(m_parent->GetSelected()){
846 color = "DILG1";
847 penWidth = m_penWidthSelected;
848 }
849
850 wxBrush b(GetGlobalColor(color), wxSOLID);
851 dc.SetBrush(b);
852 dc.SetPen( wxPen(*wxBLACK, penWidth ));
853
854 dc.DrawRoundedRectangle(-20, 5, GetSize().x-5, GetSize().y-10, 5);
855 dc.DrawBitmap(m_bitmap, offset, offset*2, true);
856
857
858 //dc.DrawText(_T("PluginStatus"), 0, 0);
859 //dc.DrawText(literalstatus_by_status[m_stat], 4 * GetCharWidth(), GetCharHeight());
860 }
861
SetStatus(PluginStatus stat)862 void SetStatus(PluginStatus stat)
863 {
864 m_stat = stat;
865 SetToolTip(message_by_status[m_stat]);
866 m_icon_name = icon_by_status[m_stat];
867 Refresh();
868 }
869
OnIconSelected(wxMouseEvent & event)870 void OnIconSelected( wxMouseEvent &event )
871 {
872 if(m_parent){
873 m_parent->OnPluginSelected(event);
874 }
875 }
876
877
878 protected:
879 wxBitmap m_bitmap;
880 std::string m_icon_name;
881 PluginStatus m_stat;
882 PluginPanel *m_parent;
883 int m_penWidthUnselected;
884 int m_penWidthSelected;
885
LoadIcon(const char * icon_name,wxBitmap & bitmap,int size=32)886 void LoadIcon(const char* icon_name, wxBitmap& bitmap, int size=32)
887 {
888 wxFileName path(g_Platform->GetSharedDataDir(), icon_name);
889 path.AppendDir("uidata");
890 path.AppendDir("traditional");
891 bool ok = false;
892
893
894 if (path.IsFileReadable()) {
895 wxImage img = LoadSVGIcon(path.GetFullPath(), size, size);
896 bitmap = wxBitmap(img);
897 ok = bitmap.IsOk();
898 }
899
900 if (!ok) {
901 auto style = g_StyleManager->GetCurrentStyle();
902 bitmap = wxBitmap(style->GetIcon( _T("default_pi"), size, size));
903 wxLogMessage("Icon: %s not found.", path.GetFullPath());
904 }
905 }
906 };
907
908
909 //------------------------------------------------------------------------------
910 // NMEA Event Implementation
911 // PlugIn Messaging scheme Event
912 //------------------------------------------------------------------------------
913
914 const wxEventType wxEVT_OCPN_MSG = wxNewEventType();
915
OCPN_MsgEvent(wxEventType commandType,int id)916 OCPN_MsgEvent::OCPN_MsgEvent( wxEventType commandType, int id )
917 :wxEvent(id, commandType)
918 {
919 }
920
~OCPN_MsgEvent()921 OCPN_MsgEvent::~OCPN_MsgEvent( )
922 {
923 }
924
Clone() const925 wxEvent* OCPN_MsgEvent::Clone() const
926 {
927 OCPN_MsgEvent *newevent=new OCPN_MsgEvent(*this);
928 newevent->m_MessageID=this->m_MessageID.c_str(); // this enforces a deep copy of the string data
929 newevent->m_MessageText=this->m_MessageText.c_str();
930 return newevent;
931 }
932
933 //------------------------------------------------------------------------------------------------
934 //
935 // The PlugInToolbarToolContainer Implementation
936 //
937 //------------------------------------------------------------------------------------------------
PlugInToolbarToolContainer()938 PlugInToolbarToolContainer::PlugInToolbarToolContainer()
939 {
940 bitmap_dusk = NULL;
941 bitmap_night = NULL;
942 bitmap_day = NULL;
943 bitmap_Rollover_day = NULL;
944 bitmap_Rollover_dusk = NULL;
945 bitmap_Rollover_night = NULL;
946
947 }
948
~PlugInToolbarToolContainer()949 PlugInToolbarToolContainer::~PlugInToolbarToolContainer()
950 {
951 delete bitmap_dusk;
952 delete bitmap_night;
953 delete bitmap_day;
954 delete bitmap_Rollover_day;
955 delete bitmap_Rollover_dusk;
956 delete bitmap_Rollover_night;
957 }
958
959 //-----------------------------------------------------------------------------------------------------
960 //
961 // The PlugIn Manager Implementation
962 //
963 //-----------------------------------------------------------------------------------------------------
964 PlugInManager *s_ppim;
965
BEGIN_EVENT_TABLE(PlugInManager,wxEvtHandler)966 BEGIN_EVENT_TABLE( PlugInManager, wxEvtHandler )
967 #ifndef __OCPN__ANDROID__
968 #ifdef OCPN_USE_CURL
969 EVT_CURL_END_PERFORM( CurlThreadId, PlugInManager::OnEndPerformCurlDownload )
970 EVT_CURL_DOWNLOAD( CurlThreadId, PlugInManager::OnCurlDownload )
971 #endif
972 #endif
973 END_EVENT_TABLE()
974
975 PlugInManager::PlugInManager(MyFrame *parent)
976 {
977 #ifndef __OCPN__ANDROID__
978 #ifdef OCPN_USE_CURL
979 m_pCurlThread = NULL;
980 m_pCurl = 0;
981 #endif
982 #endif
983 pParent = parent;
984 s_ppim = this;
985
986 MyFrame *pFrame = GetParentFrame();
987 if(pFrame)
988 {
989 m_plugin_menu_item_id_next = CanvasMenuHandler::GetNextContextMenuId();
990 m_plugin_tool_id_next = pFrame->GetNextToolbarToolId();
991 }
992
993 #ifdef __OCPN__ANDROID__
994 // Due to the oddball mixed static/dynamic linking model used in the Android architecture,
995 // all classes used in PlugIns must be present in the core, even if stubs.
996 //
997 // Here is where we do that....
998 if(pFrame){
999 wxArrayString as;
1000 as.Add(_T("Item0"));
1001 wxRadioBox *box = new wxRadioBox(pFrame, -1, _T(""), wxPoint(0,0), wxSize(-1, -1), as);
1002 delete box;
1003 }
1004
1005
1006 #endif
1007
1008 #ifdef OCPN_USE_CURL
1009 #ifndef __OCPN__ANDROID__
1010 wxCurlBase::Init();
1011 m_last_online = false;
1012 m_last_online_chk = -1;
1013 #endif
1014 #endif
1015
1016 m_benable_blackdialog_done = false;
1017
1018 m_utilHandler = new pluginUtilHandler();
1019 m_listPanel = NULL;
1020 }
1021
~PlugInManager()1022 PlugInManager::~PlugInManager()
1023 {
1024 #ifdef OCPN_USE_CURL
1025 #ifndef __OCPN__ANDROID__
1026 wxCurlBase::Shutdown();
1027 #endif
1028 #endif
1029 }
1030
1031
1032 /**
1033 *
1034 * For linux, set up LD_LIBRARY_PATH to the same value as the path used
1035 * to load plugins, assuring helper binaries can load libraries installed
1036 * in the same directory as the plugin.mac is handled the same way using
1037 * DYLD_LIBRARY_PATH. For windows, setup PATH in the likewise.
1038 */
setLoadPath()1039 static void setLoadPath()
1040 {
1041 using namespace std;
1042
1043 auto const osSystemId = wxPlatformInfo::Get().GetOperatingSystemId();
1044 vector<string> dirs = PluginPaths::getInstance()->Libdirs();
1045 if (osSystemId & wxOS_UNIX_LINUX) {
1046 string path = ocpn::join(dirs, ':');
1047 wxString envPath;
1048 if (wxGetEnv("LD_LIBRARY_PATH", &envPath)) {
1049 path = path + ":" + envPath.ToStdString();
1050 }
1051 wxLogMessage("Using LD_LIBRARY_PATH: %s", path.c_str());
1052 wxSetEnv("LD_LIBRARY_PATH", path.c_str());
1053 }
1054 else if (osSystemId & wxOS_WINDOWS) {
1055 // On windows, Libdirs() and Bindirs() are the same.
1056 string path = ocpn::join(dirs, ';');
1057 wxString envPath;
1058 if (wxGetEnv("PATH", &envPath)) {
1059 path = path + ";" + envPath.ToStdString();
1060 }
1061 wxLogMessage("Using PATH: %s", path);
1062 wxSetEnv("PATH", path);
1063 }
1064 else if (osSystemId & wxOS_MAC) {
1065 string path = ocpn::join(dirs, ':');
1066 wxString envPath;
1067 if (wxGetEnv("DYLD_LIBRARY_PATH", &envPath)) {
1068 path = path + ":" + envPath.ToStdString();
1069 }
1070 wxLogMessage("Using DYLD_LIBRARY_PATH: %s", path.c_str());
1071 wxSetEnv("DYLD_LIBRARY_PATH", path.c_str());
1072 }
1073 else {
1074 wxString os_name = wxPlatformInfo::Get().GetPortIdName();
1075 if(os_name.Contains(_T("wxQT"))){
1076 wxLogMessage(_T("setLoadPath() using Android library path"));
1077 }
1078 else
1079 wxLogWarning("SetLoadPath: Unsupported platform.");
1080 }
1081 if (osSystemId & wxOS_MAC || osSystemId & wxOS_UNIX_LINUX) {
1082 vector<string> dirs = PluginPaths::getInstance()->Bindirs();
1083 string path = ocpn::join(dirs, ':');
1084 wxString envPath;
1085 wxGetEnv("PATH", &envPath);
1086 path = path + ":" + envPath.ToStdString();
1087 wxLogMessage("Using PATH: %s", path);
1088 wxSetEnv("PATH", path);
1089 }
1090 }
1091
1092
LoadAllPlugIns(bool load_enabled,bool b_enable_blackdialog)1093 bool PlugInManager::LoadAllPlugIns(bool load_enabled, bool b_enable_blackdialog)
1094 {
1095 using namespace std;
1096 static const wxString sep = wxFileName::GetPathSeparator();
1097 vector<string> dirs = PluginPaths::getInstance()->Libdirs();
1098 wxLogMessage(_T("PlugInManager: loading plugins from %s"),
1099 ocpn::join(dirs, ';'));
1100 setLoadPath();
1101 bool any_dir_loaded = false;
1102 for (auto dir: dirs) {
1103 wxString wxdir(dir);
1104 wxLogMessage("Loading plugins from dir: %s", wxdir.mb_str().data());
1105 if (LoadPlugInDirectory(wxdir, load_enabled, b_enable_blackdialog))
1106 any_dir_loaded = true;
1107 }
1108
1109 // Read the default ocpn-plugins.xml, and update/merge the plugin array
1110 // This only needs to happen when the entire universe (enabled and disabled) of plugins are loaded for management.
1111 if(!load_enabled)
1112 UpdateManagedPlugins();
1113 return any_dir_loaded;
1114 }
1115
1116
1117 // Static helper function: loads all plugins from a single directory
LoadPlugInDirectory(const wxString & plugin_dir,bool load_enabled,bool b_enable_blackdialog)1118 bool PlugInManager::LoadPlugInDirectory(const wxString& plugin_dir, bool load_enabled, bool b_enable_blackdialog)
1119 {
1120 pConfig->SetPath( _T("/PlugIns/") );
1121 SetPluginOrder( pConfig->Read( _T("PluginOrder"), wxEmptyString ) );
1122
1123 // Enable the compatibility dialogs if requested, and has not been already done once.
1124 m_benable_blackdialog = b_enable_blackdialog && !m_benable_blackdialog_done;
1125
1126 m_plugin_location = plugin_dir;
1127
1128 wxString msg(_T("PlugInManager searching for PlugIns in location "));
1129 msg += m_plugin_location;
1130 wxLogMessage(msg);
1131
1132 #ifdef __WXMSW__
1133 wxString pispec = _T("*_pi.dll");
1134 #elif defined(__WXOSX__)
1135 wxString pispec = _T("*_pi.dylib");
1136 #else
1137 wxString pispec = _T("*_pi.so");
1138 #endif
1139
1140 if(!::wxDirExists(m_plugin_location))
1141 {
1142 msg = m_plugin_location;
1143 msg.Prepend(_T(" Directory "));
1144 msg.Append(_T(" does not exist."));
1145 wxLogMessage(msg);
1146 return false;
1147 }
1148
1149 if(!g_Platform->isPlatformCapable(PLATFORM_CAP_PLUGINS)) return false;
1150
1151 wxArrayString file_list;
1152
1153 int get_flags = wxDIR_FILES | wxDIR_DIRS;
1154 #ifdef __WXMSW__
1155 #ifdef _DEBUG
1156 get_flags = wxDIR_FILES;
1157 #endif
1158 #endif
1159
1160 #ifdef __OCPN__ANDROID__
1161 get_flags = wxDIR_FILES; // No subdirs, especially "/files" where PlugIns are initially placed in APK
1162 #endif
1163
1164 bool ret = false; // return true if at least one new plugins gets loaded/unloaded
1165 wxDir::GetAllFiles( m_plugin_location, &file_list, pispec, get_flags );
1166
1167 wxLogMessage("Found %d candidates", (int)file_list.GetCount());
1168 for(unsigned int i=0 ; i < file_list.GetCount() ; i++) {
1169 wxString file_name = file_list[i];
1170 if(file_name.Contains(_T("draw")))
1171 int yyp = 3;
1172
1173 wxString plugin_file = wxFileName(file_name).GetFullName();
1174 wxLogMessage("Checking plugin candidate: %s", file_name.mb_str().data());
1175 wxDateTime plugin_modification = wxFileName(file_name).GetModificationTime();
1176
1177 // this gets called every time we switch to the plugins tab.
1178 // this allows plugins to be installed and enabled without restarting opencpn.
1179 // For this reason we must check that we didn't already load this plugin
1180 bool loaded = false;
1181 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1182 {
1183 PlugInContainer *pic = plugin_array[i];
1184
1185 // Checking for dynamically updated plugins
1186 if(pic->m_plugin_filename == plugin_file) {
1187
1188 // Do not re-load same-name plugins from different directories. Certain to crash...
1189 if(pic->m_plugin_file == file_name){
1190 if(pic->m_plugin_modification != plugin_modification) {
1191 // modification times don't match, reload plugin
1192 plugin_array.Remove(pic);
1193 i--;
1194
1195 DeactivatePlugIn(pic);
1196 pic->m_destroy_fn(pic->m_pplugin);
1197
1198 delete pic;
1199 ret = true;
1200 } else {
1201 loaded = true;
1202 break;
1203 }
1204 } else {
1205 loaded = true;
1206 break;
1207 }
1208 }
1209 }
1210
1211 if(loaded)
1212 continue;
1213
1214 // Check the config file to see if this PlugIn is user-enabled
1215 wxString config_section = ( _T ( "/PlugIns/" ) );
1216 config_section += plugin_file;
1217 pConfig->SetPath ( config_section );
1218 bool enabled;
1219 pConfig->Read ( _T ( "bEnabled" ), &enabled, false );
1220
1221 // only loading enabled plugins? check that it is enabled
1222 if(load_enabled && !enabled) {
1223 wxLogMessage("Skipping not enabled candidate.");
1224 continue;
1225 }
1226
1227 bool b_compat = CheckPluginCompatibility(file_name);
1228
1229 if(m_benable_blackdialog && !b_compat)
1230 {
1231 wxLogMessage(wxString::Format(_T(" %s: %s"), _T("Incompatible plugin detected"), file_name.c_str()));
1232 OCPNMessageBox( NULL, wxString::Format(_("The plugin %s is not compatible with this version of OpenCPN, please get an updated version."), plugin_file.c_str()), wxString(_("OpenCPN Info")), wxICON_INFORMATION | wxOK, 10 );
1233 }
1234
1235 // Safe mode? If so, refuse to load.
1236 if (safe_mode::get_mode()) {
1237 continue;
1238 }
1239
1240 PlugInContainer *pic = NULL;
1241 wxStopWatch sw;
1242 if(b_compat)
1243 pic = LoadPlugIn(file_name);
1244
1245 if(pic)
1246 {
1247 if(pic->m_pplugin)
1248 {
1249 plugin_array.Add(pic);
1250
1251 // The common name is available without initialization and startup of the PlugIn
1252 pic->m_common_name = pic->m_pplugin->GetCommonName();
1253 pic->m_plugin_filename = plugin_file;
1254 pic->m_plugin_modification = plugin_modification;
1255 pic->m_bEnabled = enabled;
1256 if(pic->m_bEnabled)
1257 {
1258 wxStopWatch sw;
1259 pic->m_cap_flag = pic->m_pplugin->Init();
1260 pic->m_bInitState = true;
1261 if(g_options){
1262 if((pic->m_cap_flag & INSTALLS_TOOLBOX_PAGE)){
1263 if(!pic->m_bToolboxPanel)
1264 NotifySetupOptionsPlugin( pic );
1265 }
1266 }
1267 #ifdef __WXGTK__ // 10 milliseconds is very slow at least on linux
1268 if(sw.Time() > 10)
1269 wxLogMessage(_T("PlugInManager: ") + pic->m_common_name
1270 + _T(" has loaded very slowly: %ld ms"),
1271 sw.Time());
1272 #endif
1273 }
1274 std::string found_version;
1275 for (auto p: PluginHandler::getInstance()->getInstalled()) {
1276 if (p.name == pic->m_common_name.Lower()) {
1277 found_version = p.readonly ? "" : p.version;
1278 break;
1279 }
1280 }
1281 pic->m_version_str = found_version;
1282 pic->m_short_description = pic->m_pplugin->GetShortDescription();
1283 pic->m_long_description = pic->m_pplugin->GetLongDescription();
1284 pic->m_version_major = pic->m_pplugin->GetPlugInVersionMajor();
1285 pic->m_version_minor = pic->m_pplugin->GetPlugInVersionMinor();
1286 pic->m_bitmap = pic->m_pplugin->GetPlugInBitmap();
1287
1288 ret = true;
1289 }
1290 else // not loaded
1291 {
1292 wxString msg;
1293 msg.Printf(_T(" PlugInManager: Unloading invalid PlugIn, API version %d "), pic->m_api_version );
1294 wxLogMessage(msg);
1295
1296 pic->m_destroy_fn(pic->m_pplugin);
1297
1298 delete pic;
1299 }
1300 }
1301 }
1302
1303 // Scrub the plugin array...
1304 // Here, looking for duplicates caused by new installation of a plugin
1305 // We want to remove the previous entry representing the uninstalled packaged plugin metadata
1306 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++){
1307 PlugInContainer *pic = plugin_array[i];
1308 for(unsigned int j=i+1; j < plugin_array.GetCount() ; j++){
1309 PlugInContainer *pict= plugin_array[j];
1310
1311 if(pic->m_common_name == pict->m_common_name){
1312 if(pic->m_plugin_file.IsEmpty())
1313 plugin_array.Item(i)->m_pluginStatus = PluginStatus::PendingListRemoval;
1314 else
1315 plugin_array.Item(j)->m_pluginStatus = PluginStatus::PendingListRemoval;
1316 }
1317 }
1318 }
1319
1320 // Remove any list items marked
1321 size_t i=0;
1322 while( (i >= 0) && (i < plugin_array.GetCount())){
1323 PlugInContainer *pict = plugin_array.Item(i);
1324 if(pict->m_pluginStatus == PluginStatus::PendingListRemoval){
1325 plugin_array.RemoveAt(i);
1326 i=0;
1327 }
1328 else
1329 i++;
1330 }
1331
1332
1333 /*
1334 std::map<int, PlugInContainer*> ap;
1335 for( unsigned int i = 0; i < plugin_array.GetCount(); i++ )
1336 {
1337 int index = m_plugin_order.Index( plugin_array[i]->m_common_name );
1338 if( index != wxNOT_FOUND )
1339 {
1340 ap[index] = plugin_array[i];
1341 }
1342 else
1343 ap[10000 + i] = plugin_array[i];
1344 }
1345 plugin_array.Empty();
1346 for (std::map<int, PlugInContainer*>::reverse_iterator iter = ap.rbegin(); iter != ap.rend(); ++iter)
1347 {
1348 plugin_array.Insert( iter->second, 0 );
1349 }
1350 ap.clear();
1351 */
1352
1353 UpDateChartDataTypes();
1354
1355 // Inform plugins of the current color scheme
1356 SetColorSchemeForAllPlugIns( global_color_scheme );
1357
1358 // Only allow the PlugIn compatibility dialogs once per instance of application.
1359 if(b_enable_blackdialog)
1360 m_benable_blackdialog_done = true;
1361
1362 // Tell all the PlugIns about the current OCPN configuration
1363 SendBaseConfigToAllPlugIns();
1364 SendS52ConfigToAllPlugIns( true );
1365 SendSKConfigToAllPlugIns();
1366
1367 // Inform Plugins of OpenGL configuration, if enabled
1368 if(g_bopengl){
1369 if(gFrame->GetPrimaryCanvas()->GetglCanvas())
1370 gFrame->GetPrimaryCanvas()->GetglCanvas()->SendJSONConfigMessage();
1371 }
1372
1373 // And then reload all catalogs.
1374 ReloadLocale();
1375
1376 return ret;
1377 }
1378
CallLateInit(void)1379 bool PlugInManager::CallLateInit(void)
1380 {
1381 bool bret = true;
1382
1383 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1384 {
1385 PlugInContainer *pic = plugin_array[i];
1386
1387 switch(pic->m_api_version)
1388 {
1389 case 110:
1390 case 111:
1391 case 112:
1392 case 113:
1393 case 114:
1394 case 115:
1395 case 116:
1396 case 117:
1397 ProcessLateInit(pic);
1398 break;
1399 }
1400 }
1401
1402 return bret;
1403 }
1404
ProcessLateInit(PlugInContainer * pic)1405 void PlugInManager::ProcessLateInit(PlugInContainer *pic)
1406 {
1407 if(pic->m_cap_flag & WANTS_LATE_INIT) {
1408 wxString msg(_T("PlugInManager: Calling LateInit PlugIn: "));
1409 msg += pic->m_plugin_file;
1410 wxLogMessage(msg);
1411
1412 opencpn_plugin_110* ppi = dynamic_cast<opencpn_plugin_110*>(pic->m_pplugin);
1413 if (ppi)
1414 ppi->LateInit();
1415 }
1416
1417 }
1418
SendVectorChartObjectInfo(const wxString & chart,const wxString & feature,const wxString & objname,double & lat,double & lon,double & scale,int & nativescale)1419 void PlugInManager::SendVectorChartObjectInfo(const wxString &chart, const wxString &feature, const wxString &objname, double &lat, double &lon, double &scale, int &nativescale)
1420 {
1421 wxString decouple_chart(chart);
1422 wxString decouple_feature(feature);
1423 wxString decouple_objname(objname);
1424 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1425 {
1426 PlugInContainer *pic = plugin_array[i];
1427 if(pic->m_bEnabled && pic->m_bInitState)
1428 {
1429 if(pic->m_cap_flag & WANTS_VECTOR_CHART_OBJECT_INFO)
1430 {
1431 switch(pic->m_api_version)
1432 {
1433 case 112:
1434 case 113:
1435 case 114:
1436 case 115:
1437 case 116:
1438 case 117:
1439 {
1440 opencpn_plugin_112 *ppi = dynamic_cast<opencpn_plugin_112 *>(pic->m_pplugin);
1441 if(ppi)
1442 ppi->SendVectorChartObjectInfo(decouple_chart, decouple_feature, decouple_objname, lat, lon, scale, nativescale);
1443 break;
1444 }
1445 default:
1446 break;
1447 }
1448 }
1449 }
1450 }
1451 }
1452
1453
IsAnyPlugInChartEnabled()1454 bool PlugInManager::IsAnyPlugInChartEnabled()
1455 {
1456 // Is there a PlugIn installed and active that implements PlugIn Chart type(s)?
1457 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1458 {
1459 PlugInContainer *pic = plugin_array[i];
1460 if(pic->m_bEnabled && pic->m_bInitState)
1461 {
1462 if( (pic->m_cap_flag & INSTALLS_PLUGIN_CHART) || (pic->m_cap_flag & INSTALLS_PLUGIN_CHART_GL) )
1463 return true;
1464 }
1465 }
1466 return false;
1467 }
1468
1469
1470
UpdatePlugIns()1471 bool PlugInManager::UpdatePlugIns()
1472 {
1473 bool bret = false;
1474
1475 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1476 {
1477 PlugInContainer *pic = plugin_array[i];
1478
1479 // Installed and loaded?
1480 if(!pic->m_pplugin)
1481 continue;
1482
1483 if(pic->m_bEnabled && !pic->m_bInitState)
1484 {
1485 wxString msg(_T("PlugInManager: Initializing PlugIn: "));
1486 msg += pic->m_plugin_file;
1487 wxLogMessage(msg);
1488
1489 pic->m_cap_flag = pic->m_pplugin->Init();
1490 pic->m_pplugin->SetDefaults();
1491 pic->m_bInitState = true;
1492 ProcessLateInit(pic);
1493 pic->m_short_description = pic->m_pplugin->GetShortDescription();
1494 pic->m_long_description = pic->m_pplugin->GetLongDescription();
1495 pic->m_version_major = pic->m_pplugin->GetPlugInVersionMajor();
1496 pic->m_version_minor = pic->m_pplugin->GetPlugInVersionMinor();
1497 pic->m_bitmap = pic->m_pplugin->GetPlugInBitmap();
1498 bret = true;
1499 }
1500 else if(!pic->m_bEnabled && pic->m_bInitState)
1501 {
1502 bret = DeactivatePlugIn(pic);
1503
1504 }
1505 }
1506
1507 UpDateChartDataTypes();
1508
1509 return bret;
1510 }
1511
UpdateManagedPlugins()1512 void PlugInManager::UpdateManagedPlugins()
1513 {
1514 PlugInContainer *pict;
1515 // Clear the status (to "unmanaged") on all plugins
1516 for (size_t i = 0; i < plugin_array.GetCount(); i++) {
1517 pict = plugin_array.Item(i);
1518 plugin_array.Item(i)->m_pluginStatus = PluginStatus::Unmanaged;
1519
1520 // Pre-mark the default "system" plugins
1521 auto r = std::find(SYSTEM_PLUGINS.begin(), SYSTEM_PLUGINS.end(), plugin_array.Item(i)->m_common_name.Lower().ToStdString());
1522 if (r != SYSTEM_PLUGINS.end())
1523 plugin_array.Item(i)->m_pluginStatus = PluginStatus::System;
1524 }
1525
1526 std::vector<PluginMetadata> available = getCompatiblePlugins();
1527
1528 // Traverse the list again
1529 // Remove any inactive/uninstalled managed plugins that are no longer available in the current catalog
1530 // Usually due to reverting from Alpha/Beta catalog back to master
1531 for (size_t i = 0; i < plugin_array.GetCount(); i++) {
1532 pict = plugin_array.Item(i);
1533 if(pict->m_ManagedMetadata.name.size()){ // If metadata is good, must be a managed plugin
1534 bool bfound = false;
1535 for (auto plugin: available) {
1536 if(pict->m_common_name.IsSameAs(wxString(plugin.name.c_str()))){
1537 bfound = true;
1538 break;
1539 }
1540 }
1541 if(!bfound){
1542 if(!pict->m_pplugin){ // Only remove inactive plugins
1543 plugin_array.Item(i)->m_pluginStatus = PluginStatus::PendingListRemoval;
1544 }
1545 }
1546 }
1547 }
1548
1549 // Remove any list items marked
1550 size_t i=0;
1551 while( (i >= 0) && (i < plugin_array.GetCount())){
1552 pict = plugin_array.Item(i);
1553 if(pict->m_pluginStatus == PluginStatus::PendingListRemoval){
1554 plugin_array.RemoveAt(i);
1555 i=0;
1556 }
1557 else
1558 i++;
1559 }
1560
1561 for (size_t i = 0; i < plugin_array.GetCount(); i++) {
1562 pict = plugin_array.Item(i);
1563 int yyp = 4;
1564 }
1565
1566 // Now merge and update from the catalog
1567 for (auto plugin: available) {
1568
1569 PlugInContainer *pic = NULL;
1570 // Search for an exact name match in the existing plugin array
1571 bool bfound = false;
1572 for (size_t i = 0; i < plugin_array.GetCount(); i++) {
1573 pic = plugin_array.Item(i);
1574 if(plugin_array.Item(i)->m_common_name.IsSameAs(wxString(plugin.name.c_str()))){
1575 bfound = true;
1576 break;
1577 }
1578 }
1579
1580 // No match found, so add a container, and populate it
1581 if(!bfound){
1582 PlugInContainer *new_pic = new PlugInContainer;
1583 new_pic->m_common_name = wxString(plugin.name.c_str());
1584 new_pic->m_pluginStatus = PluginStatus::ManagedInstallAvailable;
1585 new_pic->m_ManagedMetadata = plugin;
1586 new_pic->m_version_major = 0;
1587 new_pic->m_version_minor = 0;
1588
1589 plugin_array.Add(new_pic);
1590
1591 }
1592 // Match found, so merge the info and determine the plugin status
1593 else{
1594 // If the managed plugin is installed, the fileList (manifest) will be present
1595 if (isRegularFile(PluginHandler::fileListPath(plugin.name).c_str())) {
1596
1597 // Get the installed version from the manifest
1598 std::string installed;
1599 std::string path = PluginHandler::versionPath(plugin.name);
1600 if (path != "" && wxFileName::IsFileReadable(path)) {
1601 std::ifstream stream;
1602 stream.open(path, std::ifstream::in);
1603 stream >> installed;
1604 }
1605 pic->m_InstalledManagedVersion = installed;
1606 auto installedVersion = SemanticVersion::parse(installed);
1607
1608 //Compare to the version reported in metadata
1609 auto metaVersion = SemanticVersion::parse(plugin.version);
1610 if(installedVersion < metaVersion)
1611 pic->m_pluginStatus = PluginStatus::ManagedInstalledUpdateAvailable;
1612 else if(installedVersion == metaVersion)
1613 pic->m_pluginStatus = PluginStatus::ManagedInstalledCurrentVersion;
1614 else if(installedVersion > metaVersion)
1615 pic->m_pluginStatus = PluginStatus::ManagedInstalledDowngradeAvailable;
1616
1617 pic->m_ManagedMetadata = plugin;
1618 }
1619
1620 // If the new plugin is not installed....
1621 else{
1622
1623 // If the plugin is actually loaded, but the new plugin is known not to be installed,
1624 // then there must be a legacy plugin loaded.
1625 // and the new status must be "PluginStatus::LegacyUpdateAvailable"
1626 if(pic->m_api_version){
1627 pic->m_pluginStatus = PluginStatus::LegacyUpdateAvailable;
1628 pic->m_ManagedMetadata = plugin;
1629 }
1630 // Otherwise, this is an uninstalled managed plugin.
1631 else{
1632 pic->m_pluginStatus = PluginStatus::ManagedInstallAvailable;
1633 }
1634 }
1635
1636
1637 }
1638 }
1639
1640 // Sort the list
1641
1642 // Detach and hold the uninstalled, managed plugins
1643 std::map <std::string, PlugInContainer*> sortmap;
1644 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++){
1645 PlugInContainer *pic = plugin_array[i];
1646 if(pic->m_pluginStatus == PluginStatus::ManagedInstallAvailable){
1647 plugin_array.Remove(pic);
1648
1649 // Sort by name, lower cased.
1650 std::string name = pic->m_ManagedMetadata.name;
1651 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
1652 sortmap[name] = pic;
1653 i = 0; // Restart the list
1654 }
1655 }
1656
1657 // Add the detached plugins back at the top of the list.
1658 // Later, the list will be populated in reverse order...Why??
1659 for (std::map<std::string, PlugInContainer*>::iterator i = sortmap.begin(); i != sortmap.end(); i++){
1660 PlugInContainer *pic = i->second;
1661 plugin_array.Insert(pic, 0);
1662 }
1663
1664 if(m_listPanel)
1665 m_listPanel->ReloadPluginPanels( &plugin_array );
1666
1667 g_options->itemBoxSizerPanelPlugins->Layout();
1668
1669
1670 }
1671
UpDateChartDataTypes(void)1672 bool PlugInManager::UpDateChartDataTypes(void)
1673 {
1674 bool bret = false;
1675 if(NULL == ChartData)
1676 return bret;
1677
1678 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1679 {
1680 PlugInContainer *pic = plugin_array[i];
1681
1682 if(pic->m_bInitState) {
1683 if((pic->m_cap_flag & INSTALLS_PLUGIN_CHART) || (pic->m_cap_flag & INSTALLS_PLUGIN_CHART_GL))
1684 bret = true;
1685 }
1686 }
1687
1688 if(bret)
1689 ChartData->UpdateChartClassDescriptorArray();
1690
1691 return bret;
1692 }
1693
1694
DeactivatePlugIn(PlugInContainer * pic)1695 bool PlugInManager::DeactivatePlugIn(PlugInContainer *pic)
1696 {
1697 bool bret = false;
1698
1699 if(pic)
1700 {
1701 wxString msg(_T("PlugInManager: Deactivating PlugIn: "));
1702 msg += pic->m_plugin_file;
1703 wxLogMessage(msg);
1704 if(pic->m_bInitState){
1705
1706 // Unload chart cache if this plugin is responsible for any charts
1707 if((pic->m_cap_flag & INSTALLS_PLUGIN_CHART) || (pic->m_cap_flag & INSTALLS_PLUGIN_CHART_GL)){
1708 ChartData->PurgeCachePlugins();
1709 gFrame->InvalidateAllQuilts();
1710 }
1711
1712 pic->m_bInitState = false;
1713 pic->m_pplugin->DeInit();
1714 }
1715 else {
1716 // Already deactivated
1717 return true;
1718 }
1719
1720 // Deactivate (Remove) any ToolbarTools added by this PlugIn
1721 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
1722 {
1723 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
1724
1725 if(pttc->m_pplugin == pic->m_pplugin)
1726 {
1727 m_PlugInToolbarTools.Remove(pttc);
1728 delete pttc;
1729 }
1730 }
1731
1732 // Deactivate (Remove) any ContextMenu items addded by this PlugIn
1733 for(unsigned int i=0; i < m_PlugInMenuItems.GetCount(); i++)
1734 {
1735 PlugInMenuItemContainer *pimis = m_PlugInMenuItems[i];
1736 if(pimis->m_pplugin == pic->m_pplugin)
1737 {
1738 m_PlugInMenuItems.Remove(pimis);
1739 delete pimis;
1740 }
1741 }
1742
1743
1744 bret = true;
1745 }
1746
1747 return bret;
1748 }
1749
SetPluginOrder(wxString serialized_names)1750 void PlugInManager::SetPluginOrder( wxString serialized_names )
1751 {
1752 m_plugin_order.Empty();
1753 wxStringTokenizer tokenizer( serialized_names, _T(";") );
1754 while( tokenizer.HasMoreTokens() )
1755 {
1756 m_plugin_order.Add( tokenizer.GetNextToken() );
1757 }
1758 }
1759
GetPluginOrder()1760 wxString PlugInManager::GetPluginOrder()
1761 {
1762 wxString plugins = wxEmptyString;
1763 for( unsigned int i = 0; i < plugin_array.GetCount(); i++ )
1764 {
1765 plugins.Append( plugin_array[i]->m_common_name );
1766 if( i < plugin_array.GetCount() - 1 )
1767 plugins.Append(';');
1768 }
1769 return plugins;
1770 }
1771
UpdateConfig()1772 bool PlugInManager::UpdateConfig()
1773 {
1774 // pConfig->SetPath( _T("/PlugIns/") );
1775 // pConfig->Write( _T("PluginOrder"), GetPluginOrder() );
1776
1777 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1778 {
1779 PlugInContainer *pic = plugin_array[i];
1780
1781 if(pic){
1782 wxString config_section = ( _T ( "/PlugIns/" ) );
1783 config_section += pic->m_plugin_filename;
1784 pConfig->SetPath ( config_section );
1785 pConfig->Write ( _T ( "bEnabled" ), pic->m_bEnabled );
1786 }
1787 }
1788
1789 return true;
1790 }
1791
1792
UnLoadPlugIn(size_t ix)1793 bool PlugInManager::UnLoadPlugIn(size_t ix)
1794 {
1795 if (ix >= plugin_array.GetCount()) {
1796 wxLogWarning("Attempt to remove non-existing plugin %d", ix);
1797 return false;
1798 }
1799 PlugInContainer *pic = plugin_array[ix];
1800 if (!DeactivatePlugIn(pic)) {
1801 return false;
1802 }
1803 if(pic->m_pplugin){
1804 pic->m_destroy_fn(pic->m_pplugin);
1805 }
1806
1807 delete pic; // This will unload the PlugIn via DTOR of pic->m_library
1808 plugin_array.RemoveAt(ix);
1809 return true;
1810 }
1811
1812
UnLoadAllPlugIns()1813 bool PlugInManager::UnLoadAllPlugIns()
1814 {
1815 for (size_t i = 0; i < plugin_array.GetCount(); i++) {
1816 if (!UnLoadPlugIn(i)) {
1817 return false;
1818 }
1819 }
1820 return true;
1821 }
1822
1823
DeactivateAllPlugIns()1824 bool PlugInManager::DeactivateAllPlugIns()
1825 {
1826 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
1827 {
1828 PlugInContainer *pic = plugin_array[i];
1829 if(pic && pic->m_bEnabled && pic->m_bInitState)
1830 DeactivatePlugIn(pic);
1831 }
1832 return true;
1833 }
1834
1835 #ifdef __WXMSW__
1836 /*Convert Virtual Address to File Offset */
Rva2Offset(DWORD rva,PIMAGE_SECTION_HEADER psh,PIMAGE_NT_HEADERS pnt)1837 DWORD Rva2Offset(DWORD rva, PIMAGE_SECTION_HEADER psh, PIMAGE_NT_HEADERS pnt)
1838 {
1839 size_t i = 0;
1840 PIMAGE_SECTION_HEADER pSeh;
1841 if (rva == 0)
1842 {
1843 return (rva);
1844 }
1845 pSeh = psh;
1846 for (i = 0; i < pnt->FileHeader.NumberOfSections; i++)
1847 {
1848 if (rva >= pSeh->VirtualAddress && rva < pSeh->VirtualAddress +
1849 pSeh->Misc.VirtualSize)
1850 {
1851 break;
1852 }
1853 pSeh++;
1854 }
1855 return (rva - pSeh->VirtualAddress + pSeh->PointerToRawData);
1856 }
1857 #endif
1858
1859 class ModuleInfo
1860 {
1861 public:
1862 WX_DECLARE_HASH_SET( wxString, wxStringHash, wxStringEqual, DependencySet );
1863 WX_DECLARE_HASH_MAP( wxString, wxString, wxStringHash, wxStringEqual, DependencyMap );
1864
1865 uint64_t type_magic;
1866 DependencyMap dependencies;
1867 };
1868
1869 #ifdef USE_LIBELF
ReadModuleInfoFromELF(const wxString & file,const ModuleInfo::DependencySet & dependencies,ModuleInfo & info)1870 bool ReadModuleInfoFromELF( const wxString& file, const ModuleInfo::DependencySet& dependencies, ModuleInfo& info )
1871 {
1872
1873 static bool b_libelf_initialized = false;
1874 static bool b_libelf_usable = false;
1875
1876 if ( b_libelf_usable )
1877 {
1878 // Nothing to do.
1879 }
1880 else if ( b_libelf_initialized )
1881 {
1882 return false;
1883 }
1884 else if( elf_version(EV_CURRENT) == EV_NONE ) {
1885 b_libelf_initialized = true;
1886 b_libelf_usable = false;
1887 wxLogError( _T("LibELF is outdated.") );
1888 return false;
1889 }
1890 else
1891 {
1892 b_libelf_initialized = true;
1893 b_libelf_usable = true;
1894 }
1895
1896 int file_handle;
1897 Elf *elf_handle = NULL;
1898 GElf_Ehdr elf_file_header;
1899 Elf_Scn *elf_section_handle = NULL;
1900
1901 file_handle = open( file, O_RDONLY );
1902 if( file_handle == -1 )
1903 {
1904 wxLogError( wxString::Format( _T("Could not open file \"%s\" for reading with errno = %i."), file, errno ) );
1905 goto FailureEpilogue;
1906 }
1907
1908 elf_handle = elf_begin( file_handle, ELF_C_READ, NULL );
1909 if( elf_handle == NULL )
1910 {
1911 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("structures"), file ) );
1912 goto FailureEpilogue;
1913 }
1914
1915 if( gelf_getehdr( elf_handle, &elf_file_header ) != &elf_file_header )
1916 {
1917 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("file header"), file ) );
1918 goto FailureEpilogue;
1919 }
1920
1921 switch( elf_file_header.e_type )
1922 {
1923 case ET_EXEC:
1924 case ET_DYN:
1925 break;
1926 default:
1927 wxLogError( wxString::Format( _T("Module \"%s\" is not an executable or shared library."), file ) );
1928 goto FailureEpilogue;
1929 }
1930
1931 info.type_magic =
1932 ( static_cast< uint64_t >( elf_file_header.e_ident[EI_CLASS] ) << 0 ) | // ELF class (32/64).
1933 ( static_cast< uint64_t >( elf_file_header.e_ident[EI_DATA] ) << 8 ) | // Endianness.
1934 ( static_cast< uint64_t >( elf_file_header.e_ident[EI_OSABI] ) << 16 ) | // OS ABI (Linux, FreeBSD, etc.).
1935 ( static_cast< uint64_t >( elf_file_header.e_ident[EI_ABIVERSION] ) << 24 ) | // OS ABI version.
1936 ( static_cast< uint64_t >( elf_file_header.e_machine) << 32 ) | // Instruction set.
1937 0;
1938
1939 while( ( elf_section_handle = elf_nextscn( elf_handle, elf_section_handle ) ) != NULL )
1940 {
1941 GElf_Shdr elf_section_header;
1942 Elf_Data *elf_section_data = NULL;
1943 size_t elf_section_entry_count = 0;
1944
1945 if( gelf_getshdr( elf_section_handle, &elf_section_header ) != &elf_section_header )
1946 {
1947 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("section header"), file ) );
1948 goto FailureEpilogue;
1949 }
1950 else if( elf_section_header.sh_type != SHT_DYNAMIC )
1951 {
1952 continue;
1953 }
1954
1955 elf_section_data = elf_getdata( elf_section_handle, NULL );
1956 if( elf_section_data == NULL )
1957 {
1958 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("section data"), file ) );
1959 goto FailureEpilogue;
1960 }
1961
1962 if( ( elf_section_data->d_size == 0 ) || ( elf_section_header.sh_entsize == 0 ) )
1963 {
1964 wxLogError( wxString::Format( _T("Got malformed %s %s from \"%s\"."), _T("ELF"), _T("section metadata"), file ) );
1965 goto FailureEpilogue;
1966 }
1967
1968 elf_section_entry_count = elf_section_data->d_size / elf_section_header.sh_entsize;
1969 for( size_t elf_section_entry_index = 0; elf_section_entry_index < elf_section_entry_count; ++elf_section_entry_index )
1970 {
1971 GElf_Dyn elf_dynamic_entry;
1972 const char *elf_dynamic_entry_name = NULL;
1973 if( gelf_getdyn( elf_section_data, elf_section_entry_index, &elf_dynamic_entry ) != &elf_dynamic_entry )
1974 {
1975 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("dynamic section entry"), file ) );
1976 goto FailureEpilogue;
1977 }
1978 else if( elf_dynamic_entry.d_tag != DT_NEEDED )
1979 {
1980 continue;
1981 }
1982 elf_dynamic_entry_name = elf_strptr( elf_handle, elf_section_header.sh_link, elf_dynamic_entry.d_un.d_val );
1983 if( elf_dynamic_entry_name == NULL )
1984 {
1985 wxLogError( wxString::Format( _T("Could not get %s %s from \"%s\"."), _T("ELF"), _T("string entry"), file ) );
1986 goto FailureEpilogue;
1987 }
1988 wxString name_full( elf_dynamic_entry_name );
1989 wxString name_part( elf_dynamic_entry_name, strcspn( elf_dynamic_entry_name, "-." ) );
1990 if( dependencies.find( name_part ) != dependencies.end() )
1991 {
1992 info.dependencies.insert( ModuleInfo::DependencyMap::value_type( name_part, name_full ) );
1993 }
1994 }
1995 };
1996
1997 goto SuccessEpilogue;
1998
1999 SuccessEpilogue:
2000 elf_end( elf_handle );
2001 close( file_handle );
2002 return true;
2003
2004 FailureEpilogue:
2005 if( elf_handle != NULL )
2006 elf_end( elf_handle );
2007 if( file_handle >= 0 )
2008 close( file_handle );
2009 return false;
2010 }
2011 #endif // USE_LIBELF
2012
CheckPluginCompatibility(wxString plugin_file)2013 bool PlugInManager::CheckPluginCompatibility(wxString plugin_file)
2014 {
2015 bool b_compat = true;
2016
2017 #ifdef __WXMSW__
2018 char strver[22]; //Enough space even for very big integers...
2019 sprintf(strver, "%i%i", wxMAJOR_VERSION, wxMINOR_VERSION);
2020 LPCWSTR fNmae = plugin_file.wc_str();
2021 HANDLE handle = CreateFile(fNmae, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
2022 DWORD byteread, size = GetFileSize(handle, NULL);
2023 PVOID virtualpointer = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
2024 ReadFile(handle, virtualpointer, size, &byteread, NULL);
2025 CloseHandle(handle);
2026 // Get pointer to NT header
2027 PIMAGE_NT_HEADERS ntheaders = (PIMAGE_NT_HEADERS)(PCHAR(virtualpointer) + PIMAGE_DOS_HEADER(virtualpointer)->e_lfanew);
2028 PIMAGE_SECTION_HEADER pSech = IMAGE_FIRST_SECTION(ntheaders);//Pointer to first section header
2029 PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor; //Pointer to import descriptor
2030 if (ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size != 0)/*if size of the table is 0 - Import Table does not exist */
2031 {
2032 pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)virtualpointer + \
2033 Rva2Offset(ntheaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress, pSech, ntheaders));
2034 LPSTR libname[256];
2035 size_t i = 0;
2036 // Walk until you reached an empty IMAGE_IMPORT_DESCRIPTOR
2037 while (pImportDescriptor->Name != 0)
2038 {
2039 //Get the name of each DLL
2040 libname[i] = (PCHAR)((DWORD_PTR)virtualpointer + Rva2Offset(pImportDescriptor->Name, pSech, ntheaders));
2041 //wxMessageBox(wxString::Format(_T("%s"), libname[i]));
2042 if (strstr(libname[i], "wx") != NULL)
2043 {
2044 if (strstr(libname[i], strver) == NULL)
2045 b_compat = false;
2046 break;
2047 }
2048 pImportDescriptor++; //advance to next IMAGE_IMPORT_DESCRIPTOR
2049 i++;
2050 }
2051 }
2052 else
2053 {
2054 wxLogMessage(wxString::Format(_T("No Import Table! in %s"), plugin_file.c_str()));
2055 }
2056 if (virtualpointer)
2057 VirtualFree(virtualpointer, size, MEM_DECOMMIT);
2058 #endif
2059 #if defined(__WXGTK__) || defined(__WXQT__)
2060 #if defined(USE_LIBELF)
2061
2062 static bool b_own_info_queried = false;
2063 static bool b_own_info_usable = false;
2064 static ModuleInfo own_info;
2065 static ModuleInfo::DependencySet dependencies;
2066
2067 if( !b_own_info_queried )
2068 {
2069 dependencies.insert( _T("libwx_baseu") );
2070 const wxApp& app = *wxTheApp;
2071 if( app.argc && !app.argv[0].IsEmpty())
2072 {
2073 wxString app_path( app.argv[0] );
2074 b_own_info_usable = ReadModuleInfoFromELF( app_path, dependencies, own_info );
2075 }
2076 else
2077 {
2078 wxLogError( _T("Cannot get own executable path.") );
2079 }
2080 b_own_info_queried = true;
2081 }
2082
2083 if( b_own_info_usable )
2084 {
2085 bool b_pi_info_usable = false;
2086 ModuleInfo pi_info;
2087 b_pi_info_usable = ReadModuleInfoFromELF( plugin_file, dependencies, pi_info );
2088 if( b_pi_info_usable )
2089 {
2090 b_compat = ( pi_info.type_magic == own_info.type_magic );
2091 if(g_Platform->isFlatpacked()){ // Ignore specific difference in OSABI field on flatpak builds
2092 if( (pi_info.type_magic ^ own_info.type_magic) == 0x00030000)
2093 b_compat = true;
2094 }
2095 if( !b_compat )
2096 {
2097 pi_info.dependencies.clear();
2098 wxLogError( wxString::Format( _T(" Plugin \"%s\" is of another binary flavor than the main module."), plugin_file ) );
2099 wxLogDebug("host magic: %.8x, plugin magic: %.8x", own_info.type_magic, pi_info.type_magic);
2100 }
2101 for( ModuleInfo::DependencyMap::const_iterator own_dependency = own_info.dependencies.begin(); own_dependency != own_info.dependencies.end(); ++own_dependency )
2102 {
2103 ModuleInfo::DependencyMap::const_iterator pi_dependency = pi_info.dependencies.find( own_dependency->first );
2104 if( ( pi_dependency != pi_info.dependencies.end() ) && ( pi_dependency->second != own_dependency->second ) )
2105 {
2106 b_compat = false;
2107 wxLogError( wxString::Format( _T(" Plugin \"%s\" depends on library \"%s\", but the main module was built for \"%s\"."), plugin_file, pi_dependency->second, own_dependency->second ) );
2108 break;
2109 }
2110 }
2111 }
2112 else
2113 {
2114 b_compat = false;
2115 wxLogMessage( wxString::Format( _T(" Plugin \"%s\" could not be reliably checked for compatibility."), plugin_file ) );
2116 }
2117 }
2118 else
2119 {
2120 // Allow any plugin when own info is not available.
2121 b_compat = true;
2122 }
2123
2124 wxLogMessage("Plugin is compatible by elf library scan: %s", b_compat ? "true" : "false");
2125 return b_compat;
2126
2127 #endif // LIBELF
2128
2129
2130 // But Android Plugins do not include the wxlib specification in their ELF file.
2131 // So we assume Android Plugins are compatible....
2132 #ifdef __OCPN__ANDROID__
2133 return true;
2134 #endif
2135
2136 // If libelf is not available, then we must use a simplistic file scan method.
2137 // This is easily fooled if the wxWidgets version in use is not exactly recognized.
2138 // File scan is 3x faster than the ELF scan method
2139
2140 FILE *f = fopen(plugin_file, "r");
2141 char strver[26]; //Enough space even for very big integers...
2142
2143 sprintf( strver,
2144 #if defined(__WXGTK3__)
2145 "libwx_gtk3u_core-%i.%i"
2146 #elif defined(__WXGTK20__)
2147 "libwx_gtk2u_core-%i.%i"
2148 #elif defined(__WXQT__)
2149 "libwx_qtu_core-%i.%i"
2150 #else
2151 #error undefined plugin platform
2152 #endif
2153 , wxMAJOR_VERSION, wxMINOR_VERSION );
2154 b_compat = false;
2155
2156 int pos = 0, len = strlen(strver), c;
2157 while((c = fgetc(f)) != EOF) {
2158 if(c == strver[pos]) {
2159 if(++pos == len) {
2160 b_compat = true;
2161 break;
2162 }
2163 } else
2164 pos = 0;
2165 }
2166 fclose(f);
2167 #endif // __WXGTK__ or __WXQT__
2168
2169 wxLogMessage("Plugin is compatible: %s", b_compat ? "true" : "false");
2170 return b_compat;
2171 }
2172
ShowDeferredBlacklistMessages()2173 void PlugInManager::ShowDeferredBlacklistMessages()
2174 {
2175 for( unsigned int i=0 ; i < m_deferred_blacklist_messages.GetCount() ; i++){
2176 OCPNMessageBox ( NULL, m_deferred_blacklist_messages[i], wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 5 ); // 5 second timeout
2177 }
2178
2179 }
2180
CheckBlacklistedPlugin(opencpn_plugin * plugin)2181 bool PlugInManager::CheckBlacklistedPlugin(opencpn_plugin* plugin)
2182 {
2183 int len = sizeof(PluginBlacklist) / sizeof(BlackListedPlugin);
2184 int major = plugin->GetPlugInVersionMajor();
2185 int minor = plugin->GetPlugInVersionMinor();
2186
2187 #ifdef __WXMSW__
2188 wxString name = wxString::FromAscii(typeid(*plugin).name());
2189 name.Replace(_T("class "), wxEmptyString);
2190 #else
2191 const std::type_info &ti = typeid(*plugin);
2192 int status;
2193 char *realname = abi::__cxa_demangle(ti.name(), 0, 0, &status);
2194 wxString name = wxString::FromAscii(realname);
2195 free(realname);
2196 #endif // __WXMSW__
2197 for (int i = 0; i < len; i++) {
2198 if( ( PluginBlacklist[i].all_lower && name == PluginBlacklist[i].name && PluginBlacklist[i].version_major >= major && PluginBlacklist[i].version_minor >= minor ) ||
2199 ( !PluginBlacklist[i].all_lower && name == PluginBlacklist[i].name && PluginBlacklist[i].version_major == major && PluginBlacklist[i].version_minor == minor ) )
2200 {
2201 wxString msg;
2202 wxString msg1;
2203 if ( PluginBlacklist[i].hard ){
2204 msg = wxString::Format(_("PlugIn %s (%s), version %i.%i was detected.\n This version is known to be unstable and will not be loaded.\n Please update this PlugIn at the opencpn.org website."),
2205 PluginBlacklist[i].name.c_str(), plugin->GetCommonName().c_str(), major, minor), _("Blacklisted plugin detected...");
2206 msg1= wxString::Format(_T(" PlugIn %s (%s), version %i.%i was detected. Hard blacklisted. Not loaded."),
2207 PluginBlacklist[i].name.c_str(), plugin->GetCommonName().c_str(), major, minor);
2208 }
2209 else{
2210 msg = wxString::Format(_("PlugIn %s (%s), version %i.%i was detected.\n This version is known to be unstable.\n Please update this PlugIn at the opencpn.org website."),
2211 PluginBlacklist[i].name.c_str(), plugin->GetCommonName().c_str(), major, minor), _("Blacklisted plugin detected...");
2212 msg1= wxString::Format(_T(" PlugIn %s (%s), version %i.%i was detected. Soft blacklisted. Loaded."),
2213 PluginBlacklist[i].name.c_str(), plugin->GetCommonName().c_str(), major, minor);
2214 }
2215
2216 wxLogMessage(msg1);
2217 if(m_benable_blackdialog)
2218 OCPNMessageBox ( NULL, msg, wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 5 ); // 5 second timeout
2219 else
2220 m_deferred_blacklist_messages.Add(msg);
2221
2222 return PluginBlacklist[i].hard;
2223 }
2224 }
2225 return false;
2226 }
2227
LoadPlugIn(wxString plugin_file)2228 PlugInContainer *PlugInManager::LoadPlugIn(wxString plugin_file)
2229 {
2230 wxString msg(_T("PlugInManager: Loading PlugIn: "));
2231 msg += plugin_file;
2232 wxLogMessage(msg);
2233
2234 PlugInContainer *pic = new PlugInContainer;
2235 pic->m_plugin_file = plugin_file;
2236 pic->m_pluginStatus = PluginStatus::Unmanaged; // Status is updated later, if necessary
2237
2238 // load the library
2239
2240 pic->m_library.Load(plugin_file);
2241
2242 if( m_benable_blackdialog && !wxIsReadable(plugin_file) )
2243 {
2244 msg = _("Unreadable PlugIn library detected, check the file permissions:\n");
2245 msg += plugin_file;
2246 msg += _T("\n\n");
2247 OCPNMessageBox ( NULL, msg, wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 10 ); // 10 second timeout
2248 }
2249 else if(!pic->m_library.IsLoaded())
2250 {
2251 if( m_benable_blackdialog ){
2252 // Look in the Blacklist, try to match a filename, to give some kind of message
2253 // extract the probable plugin name
2254 wxFileName fn( plugin_file );
2255 wxString prob_pi_name;
2256 wxString name = fn.GetName();
2257 prob_pi_name = name;
2258
2259 #ifdef __WXGTK__
2260 prob_pi_name = name.Mid(3); // lop off "lib"
2261 #endif
2262 #ifdef __WXOSX__
2263 prob_pi_name = name.Mid(3); // lop off "lib"
2264 #endif
2265
2266 int len = sizeof(PluginBlacklist) / sizeof(BlackListedPlugin);
2267 for (int i = 0; i < len; i++) {
2268 wxString candidate = PluginBlacklist[i].name.Lower();
2269 if( prob_pi_name.Lower().EndsWith(candidate)){
2270 wxString msg( wxString::Format( _T("%s:\n%s\n\n"), _("Incompatible plugin detected"), plugin_file ) );
2271
2272 wxString msg1;
2273 msg1 = wxString::Format(_("PlugIn [ %s ] version %i.%i"),
2274 PluginBlacklist[i].name.c_str(),
2275 PluginBlacklist[i].version_major, PluginBlacklist[i].version_minor);
2276 msg += msg1;
2277 if(PluginBlacklist[i].all_lower)
2278 msg += _(", and all previous versions,");
2279 msg += _(" is incompatible with this version of OpenCPN."),
2280
2281 OCPNMessageBox ( NULL, msg, wxString( _("OpenCPN Info") ), wxICON_INFORMATION | wxOK, 10 ); // 10 second timeout
2282 break;
2283 }
2284 }
2285 }
2286
2287
2288 wxString msg(_T(" PlugInManager: Cannot load library: "));
2289 msg += plugin_file;
2290 msg += _T(" ");
2291 wxLogMessage(msg);
2292 delete pic;
2293 return NULL;
2294 }
2295
2296
2297 // load the factory symbols
2298 create_t* create_plugin = (create_t*)pic->m_library.GetSymbol(_T("create_pi"));
2299 if (NULL == create_plugin)
2300 {
2301 wxString msg(_T(" PlugInManager: Cannot load symbol create_pi: "));
2302 msg += plugin_file;
2303 wxLogMessage(msg);
2304 delete pic;
2305 return NULL;
2306 }
2307
2308 destroy_t* destroy_plugin = (destroy_t*) pic->m_library.GetSymbol(_T("destroy_pi"));
2309 pic->m_destroy_fn = destroy_plugin;
2310 if (NULL == destroy_plugin) {
2311 wxString msg(_T(" PlugInManager: Cannot load symbol destroy_pi: "));
2312 msg += plugin_file;
2313 wxLogMessage(msg);
2314 delete pic;
2315 return NULL;
2316 }
2317
2318
2319 // create an instance of the plugin class
2320 opencpn_plugin* plug_in = create_plugin(this);
2321
2322 int api_major = plug_in->GetAPIVersionMajor();
2323 int api_minor = plug_in->GetAPIVersionMinor();
2324 int api_ver = (api_major * 100) + api_minor;
2325 pic->m_api_version = api_ver;
2326
2327 int pi_major = plug_in->GetPlugInVersionMajor();
2328 int pi_minor = plug_in->GetPlugInVersionMinor();
2329 SemanticVersion pi_ver(pi_major, pi_minor, -1);
2330
2331 if ( CheckBlacklistedPlugin(plug_in) ) {
2332 delete pic;
2333 return NULL;
2334 }
2335
2336 switch(api_ver)
2337 {
2338 case 105:
2339 pic->m_pplugin = dynamic_cast<opencpn_plugin*>(plug_in);
2340 break;
2341
2342 case 106:
2343 pic->m_pplugin = dynamic_cast<opencpn_plugin_16*>(plug_in);
2344 break;
2345
2346 case 107:
2347 pic->m_pplugin = dynamic_cast<opencpn_plugin_17*>(plug_in);
2348 break;
2349
2350 case 108:
2351 pic->m_pplugin = dynamic_cast<opencpn_plugin_18*>(plug_in);
2352 break;
2353
2354 case 109:
2355 pic->m_pplugin = dynamic_cast<opencpn_plugin_19*>(plug_in);
2356 break;
2357
2358 case 110:
2359 pic->m_pplugin = dynamic_cast<opencpn_plugin_110*>(plug_in);
2360 break;
2361
2362 case 111:
2363 pic->m_pplugin = dynamic_cast<opencpn_plugin_111*>(plug_in);
2364 break;
2365
2366 case 112:
2367 pic->m_pplugin = dynamic_cast<opencpn_plugin_112*>(plug_in);
2368 break;
2369
2370 case 113:
2371 pic->m_pplugin = dynamic_cast<opencpn_plugin_113*>(plug_in);
2372 break;
2373
2374 case 114:
2375 pic->m_pplugin = dynamic_cast<opencpn_plugin_114*>(plug_in);
2376 break;
2377 case 115:
2378 pic->m_pplugin = dynamic_cast<opencpn_plugin_115*>(plug_in);
2379 break;
2380
2381 case 116:
2382 pic->m_pplugin = dynamic_cast<opencpn_plugin_116*>(plug_in);
2383 break;
2384
2385 case 117:
2386 pic->m_pplugin = dynamic_cast<opencpn_plugin_117*>(plug_in);
2387 do /* force a local scope */ {
2388 auto p = dynamic_cast<opencpn_plugin_117*>(plug_in);
2389 pi_ver = SemanticVersion(pi_major, pi_minor,
2390 p->GetPlugInVersionPatch(),
2391 p->GetPlugInVersionPost(),
2392 p->GetPlugInVersionPre(),
2393 p->GetPlugInVersionBuild());
2394 } while (false);
2395 break;
2396
2397 default:
2398 break;
2399 }
2400
2401 if(pic->m_pplugin)
2402 {
2403 INFO_LOG << "PlugInManager: " << plugin_file;
2404 INFO_LOG << " Plugin common name: "
2405 << pic->m_pplugin->GetCommonName();
2406 INFO_LOG << " API Version detected: " << api_ver;
2407 INFO_LOG << " PlugIn Version detected: " << pi_ver;
2408 }
2409 else
2410 {
2411 wxString msg = _T(" ");
2412 msg += plugin_file;
2413 wxString msg1 = _T(" cannot be loaded");
2414 msg += msg1;
2415 wxLogMessage(msg);
2416 }
2417
2418 return pic;
2419 }
2420
RenderAllCanvasOverlayPlugIns(ocpnDC & dc,const ViewPort & vp,int canvasIndex)2421 bool PlugInManager::RenderAllCanvasOverlayPlugIns( ocpnDC &dc, const ViewPort &vp, int canvasIndex )
2422 {
2423 for(unsigned int i = 0; i < plugin_array.GetCount(); i++)
2424 {
2425 PlugInContainer *pic = plugin_array[i];
2426 if(pic->m_bEnabled && pic->m_bInitState)
2427 {
2428 if(pic->m_cap_flag & WANTS_OVERLAY_CALLBACK)
2429 {
2430 PlugIn_ViewPort pivp = CreatePlugInViewport( vp );
2431
2432 wxDC *pdc = dc.GetDC();
2433 if(pdc) // not in OpenGL mode
2434 {
2435 switch(pic->m_api_version)
2436 {
2437 case 106:
2438 {
2439 opencpn_plugin_16 *ppi = dynamic_cast<opencpn_plugin_16 *>(pic->m_pplugin);
2440 if(ppi)
2441 ppi->RenderOverlay(*pdc, &pivp);
2442 break;
2443 }
2444 case 107:
2445 {
2446 opencpn_plugin_17 *ppi = dynamic_cast<opencpn_plugin_17 *>(pic->m_pplugin);
2447 if(ppi)
2448 ppi->RenderOverlay(*pdc, &pivp);
2449 break;
2450 }
2451 case 108:
2452 case 109:
2453 case 110:
2454 case 111:
2455 case 112:
2456 case 113:
2457 case 114:
2458 case 115:
2459 {
2460 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2461 if (ppi)
2462 ppi->RenderOverlay(*pdc, &pivp);
2463 break;
2464 }
2465 case 116:
2466 case 117:
2467 {
2468 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2469 if (ppi) {
2470 ppi->RenderOverlay(*pdc, &pivp);
2471 }
2472 opencpn_plugin_116 *ppi116 = dynamic_cast<opencpn_plugin_116 *>(pic->m_pplugin);
2473 if (ppi116)
2474 ppi116->RenderOverlayMultiCanvas(*pdc, &pivp, canvasIndex);
2475 break;
2476 }
2477 default:
2478 break;
2479 }
2480 }
2481 else
2482 {
2483 // If in OpenGL mode, and the PlugIn has requested OpenGL render callbacks,
2484 // then there is no need to render by wxDC here.
2485 if(pic->m_cap_flag & WANTS_OPENGL_OVERLAY_CALLBACK)
2486 continue;
2487
2488
2489 if((m_cached_overlay_bm.GetWidth() != vp.pix_width) || (m_cached_overlay_bm.GetHeight() != vp.pix_height))
2490 m_cached_overlay_bm.Create(vp.pix_width, vp.pix_height, -1);
2491
2492 wxMemoryDC mdc;
2493 mdc.SelectObject ( m_cached_overlay_bm );
2494 mdc.SetBackground ( *wxBLACK_BRUSH );
2495 mdc.Clear();
2496
2497
2498 bool b_rendered = false;
2499
2500 switch(pic->m_api_version)
2501 {
2502 case 106:
2503 {
2504 opencpn_plugin_16 *ppi = dynamic_cast<opencpn_plugin_16 *>(pic->m_pplugin);
2505 if(ppi)
2506 b_rendered = ppi->RenderOverlay(mdc, &pivp);
2507 break;
2508 }
2509 case 107:
2510 {
2511 opencpn_plugin_17 *ppi = dynamic_cast<opencpn_plugin_17 *>(pic->m_pplugin);
2512 if(ppi)
2513 b_rendered = ppi->RenderOverlay(mdc, &pivp);
2514 break;
2515 }
2516 case 108:
2517 case 109:
2518 case 110:
2519 case 111:
2520 case 112:
2521 case 113:
2522 case 114:
2523 case 115:
2524 {
2525 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2526 if (ppi)
2527 b_rendered = ppi->RenderOverlay(*pdc, &pivp);
2528 break;
2529 }
2530 case 116:
2531 case 117:
2532 {
2533 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2534 if (ppi) {
2535 b_rendered = ppi->RenderOverlay(*pdc, &pivp);
2536 }
2537 opencpn_plugin_116 *ppi116 = dynamic_cast<opencpn_plugin_116 *>(pic->m_pplugin);
2538 if (ppi116)
2539 b_rendered = ppi116->RenderOverlayMultiCanvas(*pdc, &pivp, g_canvasConfig);
2540 break;
2541 }
2542 default:
2543 {
2544 b_rendered = pic->m_pplugin->RenderOverlay(&mdc, &pivp);
2545 break;
2546 }
2547 }
2548
2549 mdc.SelectObject(wxNullBitmap);
2550
2551 if(b_rendered)
2552 {
2553 wxMask *p_msk = new wxMask(m_cached_overlay_bm, wxColour(0,0,0));
2554 m_cached_overlay_bm.SetMask(p_msk);
2555
2556 dc.DrawBitmap(m_cached_overlay_bm, 0, 0, true);
2557 }
2558 }
2559 }
2560 else if(pic->m_cap_flag & WANTS_OPENGL_OVERLAY_CALLBACK)
2561 {
2562 }
2563
2564 }
2565 }
2566
2567 return true;
2568 }
2569
RenderAllGLCanvasOverlayPlugIns(wxGLContext * pcontext,const ViewPort & vp,int canvasIndex)2570 bool PlugInManager::RenderAllGLCanvasOverlayPlugIns( wxGLContext *pcontext, const ViewPort &vp, int canvasIndex)
2571 {
2572 for(unsigned int i = 0; i < plugin_array.GetCount(); i++)
2573 {
2574 PlugInContainer *pic = plugin_array[i];
2575 if(pic->m_bEnabled && pic->m_bInitState)
2576 {
2577 if(pic->m_cap_flag & WANTS_OPENGL_OVERLAY_CALLBACK)
2578 {
2579 PlugIn_ViewPort pivp = CreatePlugInViewport( vp );
2580
2581 switch(pic->m_api_version)
2582 {
2583 case 107:
2584 {
2585 opencpn_plugin_17 *ppi = dynamic_cast<opencpn_plugin_17 *>(pic->m_pplugin);
2586 if(ppi)
2587 ppi->RenderGLOverlay(pcontext, &pivp);
2588 break;
2589 }
2590
2591 case 108:
2592 case 109:
2593 case 110:
2594 case 111:
2595 case 112:
2596 case 113:
2597 case 114:
2598 case 115:
2599 {
2600 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2601 if (ppi)
2602 ppi->RenderGLOverlay(pcontext, &pivp);
2603 break;
2604 }
2605 case 116:
2606 case 117:
2607 {
2608 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2609 if (ppi) {
2610 ppi->RenderGLOverlay(pcontext, &pivp);
2611 }
2612 opencpn_plugin_116 *ppi116 = dynamic_cast<opencpn_plugin_116 *>(pic->m_pplugin);
2613 if (ppi116) {
2614 ppi116->RenderGLOverlayMultiCanvas(pcontext, &pivp, canvasIndex);
2615 }
2616 break;
2617 }
2618 default:
2619 break;
2620 }
2621 }
2622 }
2623 }
2624
2625 return true;
2626 }
2627
SendMouseEventToPlugins(wxMouseEvent & event)2628 bool PlugInManager::SendMouseEventToPlugins( wxMouseEvent &event)
2629 {
2630 bool bret = false;
2631 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2632 {
2633 PlugInContainer *pic = plugin_array[i];
2634 if(pic->m_bEnabled && pic->m_bInitState)
2635 {
2636 if(pic->m_cap_flag & WANTS_MOUSE_EVENTS)
2637 {
2638 switch(pic->m_api_version)
2639 {
2640 case 112:
2641 case 113:
2642 case 114:
2643 case 115:
2644 case 116:
2645 case 117:
2646 {
2647 opencpn_plugin_112 *ppi = dynamic_cast<opencpn_plugin_112*>(pic->m_pplugin);
2648 if(ppi)
2649 if(ppi->MouseEventHook( event ))
2650 bret = true;
2651 break;
2652 }
2653 default:
2654 break;
2655 }
2656 }
2657 }
2658 }
2659
2660 return bret;
2661 }
2662
SendKeyEventToPlugins(wxKeyEvent & event)2663 bool PlugInManager::SendKeyEventToPlugins( wxKeyEvent &event)
2664 {
2665 bool bret = false;
2666 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2667 {
2668 PlugInContainer *pic = plugin_array[i];
2669 if(pic->m_bEnabled && pic->m_bInitState)
2670 {
2671 if(pic->m_cap_flag & WANTS_KEYBOARD_EVENTS){
2672 {
2673 switch(pic->m_api_version)
2674 {
2675 case 113:
2676 case 114:
2677 case 115:
2678 case 116:
2679 case 117:
2680 {
2681 opencpn_plugin_113 *ppi = dynamic_cast<opencpn_plugin_113*>(pic->m_pplugin);
2682 if(ppi && ppi->KeyboardEventHook( event ))
2683 bret = true;
2684 break;
2685 }
2686 default:
2687 break;
2688 }
2689 }
2690 }
2691 }
2692 }
2693
2694 return bret;;
2695 }
2696
2697
SendViewPortToRequestingPlugIns(ViewPort & vp)2698 void PlugInManager::SendViewPortToRequestingPlugIns( ViewPort &vp )
2699 {
2700 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2701 {
2702 PlugInContainer *pic = plugin_array[i];
2703 if(pic->m_bEnabled && pic->m_bInitState)
2704 {
2705 if(pic->m_cap_flag & WANTS_ONPAINT_VIEWPORT)
2706 {
2707 PlugIn_ViewPort pivp = CreatePlugInViewport( vp );
2708 pic->m_pplugin->SetCurrentViewPort(pivp);
2709 }
2710 }
2711 }
2712 }
2713
SendCursorLatLonToAllPlugIns(double lat,double lon)2714 void PlugInManager::SendCursorLatLonToAllPlugIns( double lat, double lon)
2715 {
2716 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2717 {
2718 PlugInContainer *pic = plugin_array[i];
2719 if(pic->m_bEnabled && pic->m_bInitState)
2720 {
2721 if(pic->m_cap_flag & WANTS_CURSOR_LATLON)
2722 pic->m_pplugin->SetCursorLatLon(lat, lon);
2723 }
2724 }
2725 }
2726
NotifySetupOptionsPlugin(PlugInContainer * pic)2727 void NotifySetupOptionsPlugin( PlugInContainer *pic )
2728 {
2729 if(pic->m_bEnabled && pic->m_bInitState)
2730 {
2731 if(pic->m_cap_flag & INSTALLS_TOOLBOX_PAGE)
2732 {
2733 switch(pic->m_api_version)
2734 {
2735 case 109:
2736 case 110:
2737 case 111:
2738 case 112:
2739 case 113:
2740 case 114:
2741 case 115:
2742 case 116:
2743 case 117:
2744 {
2745 opencpn_plugin_19 *ppi = dynamic_cast<opencpn_plugin_19 *>(pic->m_pplugin);
2746 if(ppi) {
2747 ppi->OnSetupOptions();
2748 pic->m_bToolboxPanel = true;
2749 }
2750 break;
2751 }
2752 default:
2753 break;
2754 }
2755 }
2756 }
2757 }
2758
NotifySetupOptions()2759 void PlugInManager::NotifySetupOptions()
2760 {
2761 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2762 {
2763 PlugInContainer *pic = plugin_array[i];
2764 NotifySetupOptionsPlugin( pic );
2765 }
2766 }
2767
ClosePlugInPanel(PlugInContainer * pic,int ok_apply_cancel)2768 void PlugInManager::ClosePlugInPanel(PlugInContainer* pic, int ok_apply_cancel)
2769 {
2770 if(pic->m_bEnabled && pic->m_bInitState) {
2771 if ((pic->m_cap_flag & INSTALLS_TOOLBOX_PAGE) && pic->m_bToolboxPanel)
2772 {
2773 pic->m_pplugin->OnCloseToolboxPanel(0, ok_apply_cancel);
2774 pic->m_bToolboxPanel = false;
2775 }
2776 }
2777 }
2778
CloseAllPlugInPanels(int ok_apply_cancel)2779 void PlugInManager::CloseAllPlugInPanels(int ok_apply_cancel)
2780 {
2781 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++) {
2782 PlugInContainer *pic = plugin_array[i];
2783 if (pic) {
2784 ClosePlugInPanel(pic, ok_apply_cancel);
2785 }
2786 }
2787 }
2788
AddCanvasContextMenuItem(wxMenuItem * pitem,opencpn_plugin * pplugin,const char * name)2789 int PlugInManager::AddCanvasContextMenuItem(wxMenuItem *pitem, opencpn_plugin *pplugin, const char *name )
2790 {
2791 PlugInMenuItemContainer *pmic = new PlugInMenuItemContainer;
2792 pmic->pmenu_item = pitem;
2793 pmic->m_pplugin = pplugin;
2794 pmic->id = pitem->GetId()==wxID_SEPARATOR?wxID_SEPARATOR:m_plugin_menu_item_id_next;
2795 pmic->b_viz = true;
2796 pmic->b_grey = false;
2797 pmic->m_in_menu = name;
2798
2799 m_PlugInMenuItems.Add(pmic);
2800
2801 m_plugin_menu_item_id_next++;
2802
2803 return pmic->id;
2804 }
2805
2806
2807
2808
RemoveCanvasContextMenuItem(int item,const char * name)2809 void PlugInManager::RemoveCanvasContextMenuItem(int item, const char *name )
2810 {
2811 for(unsigned int i=0; i < m_PlugInMenuItems.GetCount(); i++)
2812 {
2813 PlugInMenuItemContainer *pimis = m_PlugInMenuItems[i];
2814 {
2815 if(pimis->id == item && !strcmp(name, pimis->m_in_menu))
2816 {
2817 m_PlugInMenuItems.Remove(pimis);
2818 delete pimis;
2819 break;
2820 }
2821 }
2822 }
2823 }
2824
SetCanvasContextMenuItemViz(int item,bool viz,const char * name)2825 void PlugInManager::SetCanvasContextMenuItemViz(int item, bool viz, const char *name)
2826 {
2827 for(unsigned int i=0; i < m_PlugInMenuItems.GetCount(); i++)
2828 {
2829 PlugInMenuItemContainer *pimis = m_PlugInMenuItems[i];
2830 {
2831 if(pimis->id == item && !strcmp(name, pimis->m_in_menu))
2832 {
2833 pimis->b_viz = viz;
2834 break;
2835 }
2836 }
2837 }
2838 }
2839
SetCanvasContextMenuItemGrey(int item,bool grey,const char * name)2840 void PlugInManager::SetCanvasContextMenuItemGrey(int item, bool grey, const char *name)
2841 {
2842 for(unsigned int i=0; i < m_PlugInMenuItems.GetCount(); i++)
2843 {
2844 PlugInMenuItemContainer *pimis = m_PlugInMenuItems[i];
2845 {
2846 if(pimis->id == item && !strcmp(name, pimis->m_in_menu))
2847 {
2848 pimis->b_grey = grey;
2849 break;
2850 }
2851 }
2852 }
2853 }
2854
SendNMEASentenceToAllPlugIns(const wxString & sentence)2855 void PlugInManager::SendNMEASentenceToAllPlugIns(const wxString &sentence)
2856 {
2857 wxString decouple_sentence(sentence); // decouples 'const wxString &' and 'wxString &' to keep bin compat for plugins
2858 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2859 {
2860 PlugInContainer *pic = plugin_array[i];
2861 if(pic->m_bEnabled && pic->m_bInitState)
2862 {
2863 if(pic->m_cap_flag & WANTS_NMEA_SENTENCES)
2864 pic->m_pplugin->SetNMEASentence(decouple_sentence);
2865 }
2866 }
2867 }
2868
GetJSONMessageTargetCount()2869 int PlugInManager::GetJSONMessageTargetCount()
2870 {
2871 int rv = 0;
2872 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2873 {
2874 PlugInContainer *pic = plugin_array[i];
2875 if(pic->m_bEnabled && pic->m_bInitState && (pic->m_cap_flag & WANTS_PLUGIN_MESSAGING) )
2876 rv++;
2877 }
2878 return rv;
2879 }
2880
SendJSONMessageToAllPlugins(const wxString & message_id,wxJSONValue v)2881 void PlugInManager::SendJSONMessageToAllPlugins(const wxString &message_id, wxJSONValue v)
2882 {
2883 wxJSONWriter w;
2884 wxString out;
2885 w.Write(v, out);
2886 SendMessageToAllPlugins(message_id,out);
2887 // wxLogMessage(message_id);
2888 // wxLogMessage(out);
2889 }
2890
SendMessageToAllPlugins(const wxString & message_id,const wxString & message_body)2891 void PlugInManager::SendMessageToAllPlugins(const wxString &message_id, const wxString &message_body)
2892 {
2893 g_lastPluginMessage = message_body;
2894
2895 wxString decouple_message_id(message_id); // decouples 'const wxString &' and 'wxString &' to keep bin compat for plugins
2896 wxString decouple_message_body(message_body); // decouples 'const wxString &' and 'wxString &' to keep bin compat for plugins
2897 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2898 {
2899 PlugInContainer *pic = plugin_array[i];
2900 if(pic->m_bEnabled && pic->m_bInitState)
2901 {
2902 if(pic->m_cap_flag & WANTS_PLUGIN_MESSAGING)
2903 {
2904 switch(pic->m_api_version)
2905 {
2906 case 106:
2907 {
2908 opencpn_plugin_16 *ppi = dynamic_cast<opencpn_plugin_16 *>(pic->m_pplugin);
2909 if(ppi)
2910 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
2911 break;
2912 }
2913 case 107:
2914 {
2915 opencpn_plugin_17 *ppi = dynamic_cast<opencpn_plugin_17 *>(pic->m_pplugin);
2916 if(ppi)
2917 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
2918 break;
2919 }
2920 case 108:
2921 case 109:
2922 case 110:
2923 case 111:
2924 case 112:
2925 case 113:
2926 case 114:
2927 case 115:
2928 case 116:
2929 case 117:
2930 {
2931 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
2932 if(ppi)
2933 ppi->SetPluginMessage(decouple_message_id, decouple_message_body);
2934 break;
2935 }
2936 default:
2937 break;
2938 }
2939 }
2940 }
2941 }
2942 }
2943
2944
SendAISSentenceToAllPlugIns(const wxString & sentence)2945 void PlugInManager::SendAISSentenceToAllPlugIns(const wxString &sentence)
2946 {
2947 wxString decouple_sentence(sentence); // decouples 'const wxString &' and 'wxString &' to keep bin compat for plugins
2948 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2949 {
2950 PlugInContainer *pic = plugin_array[i];
2951 if(pic->m_bEnabled && pic->m_bInitState)
2952 {
2953 if(pic->m_cap_flag & WANTS_AIS_SENTENCES)
2954 pic->m_pplugin->SetAISSentence(decouple_sentence);
2955 }
2956 }
2957 }
2958
SendPositionFixToAllPlugIns(GenericPosDatEx * ppos)2959 void PlugInManager::SendPositionFixToAllPlugIns(GenericPosDatEx *ppos)
2960 {
2961 // Send basic position fix
2962 PlugIn_Position_Fix pfix;
2963 pfix.Lat = ppos->kLat;
2964 pfix.Lon = ppos->kLon;
2965 pfix.Cog = ppos->kCog;
2966 pfix.Sog = ppos->kSog;
2967 pfix.Var = ppos->kVar;
2968 pfix.FixTime = ppos->FixTime;
2969 pfix.nSats = ppos->nSats;
2970
2971 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2972 {
2973 PlugInContainer *pic = plugin_array[i];
2974 if(pic->m_bEnabled && pic->m_bInitState)
2975 {
2976 if(pic->m_cap_flag & WANTS_NMEA_EVENTS)
2977 pic->m_pplugin->SetPositionFix(pfix);
2978 }
2979 }
2980
2981 // Send extended position fix to PlugIns at API 108 and later
2982 PlugIn_Position_Fix_Ex pfix_ex;
2983 pfix_ex.Lat = ppos->kLat;
2984 pfix_ex.Lon = ppos->kLon;
2985 pfix_ex.Cog = ppos->kCog;
2986 pfix_ex.Sog = ppos->kSog;
2987 pfix_ex.Var = ppos->kVar;
2988 pfix_ex.FixTime = ppos->FixTime;
2989 pfix_ex.nSats = ppos->nSats;
2990 pfix_ex.Hdt = ppos->kHdt;
2991 pfix_ex.Hdm = ppos->kHdm;
2992
2993 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
2994 {
2995 PlugInContainer *pic = plugin_array[i];
2996 if(pic->m_bEnabled && pic->m_bInitState)
2997 {
2998 if(pic->m_cap_flag & WANTS_NMEA_EVENTS)
2999 {
3000 switch(pic->m_api_version)
3001 {
3002 case 108:
3003 case 109:
3004 case 110:
3005 case 111:
3006 case 112:
3007 case 113:
3008 case 114:
3009 case 115:
3010 case 116:
3011 case 117:
3012 {
3013 opencpn_plugin_18 *ppi = dynamic_cast<opencpn_plugin_18 *>(pic->m_pplugin);
3014 if(ppi)
3015 ppi->SetPositionFixEx(pfix_ex);
3016 break;
3017 }
3018 default:
3019 break;
3020 }
3021 }
3022 }
3023 }
3024 }
3025
SendActiveLegInfoToAllPlugIns(ActiveLegDat * leg_info)3026 void PlugInManager::SendActiveLegInfoToAllPlugIns(ActiveLegDat *leg_info)
3027 {
3028 Plugin_Active_Leg_Info leg;
3029 leg.Btw = leg_info->Btw;
3030 leg.Dtw = leg_info->Dtw;
3031 leg.wp_name = leg_info->wp_name;
3032 leg.Xte = leg_info->Xte;
3033 leg.arrival = leg_info->arrival;
3034 for (unsigned int i = 0; i < plugin_array.GetCount(); i++)
3035 {
3036 PlugInContainer *pic = plugin_array[i];
3037 if (pic->m_bEnabled && pic->m_bInitState)
3038 {
3039 if (pic->m_cap_flag & WANTS_NMEA_EVENTS)
3040 {
3041 switch (pic->m_api_version)
3042 {
3043 case 108:
3044 case 109:
3045 case 110:
3046 case 111:
3047 case 112:
3048 case 113:
3049 case 114:
3050 case 115:
3051 case 116:
3052 break;
3053 case 117:
3054 {
3055 opencpn_plugin_117 *ppi = dynamic_cast<opencpn_plugin_117 *>(pic->m_pplugin);
3056 if (ppi)
3057 ppi->SetActiveLegInfo(leg);
3058 break;
3059 }
3060 default:
3061 break;
3062 }
3063 }
3064 }
3065 }
3066 }
3067
SendResizeEventToAllPlugIns(int x,int y)3068 void PlugInManager::SendResizeEventToAllPlugIns(int x, int y)
3069 {
3070 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
3071 {
3072 PlugInContainer *pic = plugin_array[i];
3073 if(pic->m_bEnabled && pic->m_bInitState)
3074 pic->m_pplugin->ProcessParentResize(x, y);
3075 }
3076 }
3077
SetColorSchemeForAllPlugIns(ColorScheme cs)3078 void PlugInManager::SetColorSchemeForAllPlugIns(ColorScheme cs)
3079 {
3080 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
3081 {
3082 PlugInContainer *pic = plugin_array[i];
3083 if(pic->m_bEnabled && pic->m_bInitState)
3084 pic->m_pplugin->SetColorScheme((PI_ColorScheme)cs);
3085 }
3086 }
3087
PrepareAllPluginContextMenus()3088 void PlugInManager::PrepareAllPluginContextMenus()
3089 {
3090 int canvasIndex = gFrame->GetCanvasIndexUnderMouse();
3091 if(canvasIndex < 0)
3092 return;
3093
3094 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
3095 {
3096 PlugInContainer *pic = plugin_array[i];
3097 if(pic->m_bEnabled && pic->m_bInitState){
3098 if(pic->m_cap_flag & INSTALLS_CONTEXTMENU_ITEMS){
3099 switch(pic->m_api_version)
3100 {
3101 case 116:
3102 case 117:
3103 {
3104 opencpn_plugin_116 *ppi = dynamic_cast<opencpn_plugin_116 *>(pic->m_pplugin);
3105 if(ppi)
3106 ppi->PrepareContextMenu( canvasIndex );
3107 break;
3108 }
3109 default:
3110 break;
3111 }
3112 }
3113 }
3114 }
3115 }
3116
SendSKConfigToAllPlugIns()3117 void PlugInManager::SendSKConfigToAllPlugIns()
3118 {
3119 // Send the current ownship MMSI, encoded as sK, to all PlugIns
3120 wxJSONValue v;
3121 v[_T("self")] = g_ownshipMMSI_SK;
3122
3123 wxJSONWriter w;
3124 wxString out;
3125 w.Write(v, out);
3126 SendMessageToAllPlugins(wxString(_T("OCPN_CORE_SIGNALK")), out);
3127 }
3128
SendBaseConfigToAllPlugIns()3129 void PlugInManager::SendBaseConfigToAllPlugIns()
3130 {
3131 // Send the current run-time configuration to all PlugIns
3132 wxJSONValue v;
3133 v[_T("OpenCPN Version Major")] = VERSION_MAJOR;
3134 v[_T("OpenCPN Version Minor")] = VERSION_MINOR;
3135 v[_T("OpenCPN Version Patch")] = VERSION_PATCH;
3136 v[_T("OpenCPN Version Date")] = VERSION_DATE;
3137 v[_T("OpenCPN Version Full")] = VERSION_FULL;
3138
3139 // Some useful display metrics
3140 if(g_MainToolbar){
3141 v[_T("OpenCPN Toolbar Width")] = g_MainToolbar->GetSize().x;
3142 v[_T("OpenCPN Toolbar Height")] = g_MainToolbar->GetSize().y;
3143 v[_T("OpenCPN Toolbar PosnX")] = g_MainToolbar->GetPosition().x;
3144 v[_T("OpenCPN Toolbar PosnY")] = g_MainToolbar->GetPosition().y;
3145 }
3146
3147 // Some rendering parameters
3148 v[_T("OpenCPN Zoom Mod Vector")] = g_chart_zoom_modifier_vector;
3149 v[_T("OpenCPN Zoom Mod Other")] = g_chart_zoom_modifier;
3150 v[_T("OpenCPN Display Width")] = (int)g_display_size_mm;
3151
3152 wxJSONWriter w;
3153 wxString out;
3154 w.Write(v, out);
3155 SendMessageToAllPlugins(wxString(_T("OpenCPN Config")), out);
3156 }
3157
SendS52ConfigToAllPlugIns(bool bReconfig)3158 void PlugInManager::SendS52ConfigToAllPlugIns( bool bReconfig )
3159 {
3160 // Send the current run-time configuration to all PlugIns
3161 wxJSONValue v;
3162 v[_T("OpenCPN Version Major")] = VERSION_MAJOR;
3163 v[_T("OpenCPN Version Minor")] = VERSION_MINOR;
3164 v[_T("OpenCPN Version Patch")] = VERSION_PATCH;
3165 v[_T("OpenCPN Version Date")] = VERSION_DATE;
3166 v[_T("OpenCPN Version Full")] = VERSION_FULL;
3167
3168 // S52PLIB state
3169 if(ps52plib){
3170 // v[_T("OpenCPN S52PLIB ShowText")] = ps52plib->GetShowS57Text();
3171 // v[_T("OpenCPN S52PLIB ShowSoundings")] = ps52plib->GetShowSoundings();
3172 // v[_T("OpenCPN S52PLIB ShowLights")] = !ps52plib->GetLightsOff();
3173 v[_T("OpenCPN S52PLIB ShowAnchorConditions")] = ps52plib->GetAnchorOn();
3174 v[_T("OpenCPN S52PLIB ShowQualityOfData")] = ps52plib->GetQualityOfData();
3175 // v[_T("OpenCPN S52PLIB DisplayCategory")] = ps52plib->GetDisplayCategory();
3176
3177 // Global parameters
3178 v[_T("OpenCPN S52PLIB MetaDisplay")] = ps52plib->m_bShowMeta;
3179 v[_T("OpenCPN S52PLIB DeclutterText")] = ps52plib->m_bDeClutterText;
3180 v[_T("OpenCPN S52PLIB ShowNationalText")] = ps52plib->m_bShowNationalTexts;
3181 v[_T("OpenCPN S52PLIB ShowImportantTextOnly")] = ps52plib->m_bShowS57ImportantTextOnly;
3182 v[_T("OpenCPN S52PLIB UseSCAMIN")] = ps52plib->m_bUseSCAMIN;
3183 v[_T("OpenCPN S52PLIB SymbolStyle")] = ps52plib->m_nSymbolStyle;
3184 v[_T("OpenCPN S52PLIB BoundaryStyle")] = ps52plib->m_nBoundaryStyle;
3185 v[_T("OpenCPN S52PLIB ColorShades")] = S52_getMarinerParam( S52_MAR_TWO_SHADES );
3186 }
3187
3188 // Notify plugins that S52PLIB may have reconfigured global options
3189 v[_T("OpenCPN S52PLIB GlobalReconfig")] = bReconfig;
3190
3191
3192
3193 wxJSONWriter w;
3194 wxString out;
3195 w.Write(v, out);
3196 SendMessageToAllPlugins(wxString(_T("OpenCPN Config")), out);
3197 }
3198
NotifyAuiPlugIns(void)3199 void PlugInManager::NotifyAuiPlugIns(void)
3200 {
3201 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
3202 {
3203 PlugInContainer *pic = plugin_array[i];
3204 if(pic->m_bEnabled && pic->m_bInitState && (pic->m_cap_flag & USES_AUI_MANAGER))
3205 pic->m_pplugin->UpdateAuiStatus();
3206 }
3207 }
3208
AddToolbarTool(wxString label,wxBitmap * bitmap,wxBitmap * bmpRollover,wxItemKind kind,wxString shortHelp,wxString longHelp,wxObject * clientData,int position,int tool_sel,opencpn_plugin * pplugin)3209 int PlugInManager::AddToolbarTool(wxString label, wxBitmap *bitmap, wxBitmap *bmpRollover, wxItemKind kind,
3210 wxString shortHelp, wxString longHelp, wxObject *clientData, int position,
3211 int tool_sel, opencpn_plugin *pplugin )
3212 {
3213 PlugInToolbarToolContainer *pttc = new PlugInToolbarToolContainer;
3214 pttc->label = label;
3215
3216 if( !bitmap->IsOk() ) {
3217 ocpnStyle::Style*style = g_StyleManager->GetCurrentStyle();
3218 pttc->bitmap_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3219 } else {
3220 // Force a non-reference copy of the bitmap from the PlugIn
3221 pttc->bitmap_day = new wxBitmap(*bitmap);
3222 pttc->bitmap_day->UnShare();
3223 }
3224
3225 if( !bmpRollover->IsOk() ) {
3226 ocpnStyle::Style*style = g_StyleManager->GetCurrentStyle();
3227 pttc->bitmap_Rollover_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3228 } else {
3229 // Force a non-reference copy of the bitmap from the PlugIn
3230 pttc->bitmap_Rollover_day = new wxBitmap(*bmpRollover);
3231 pttc->bitmap_Rollover_day->UnShare();
3232 }
3233
3234 pttc->bitmap_dusk = BuildDimmedToolBitmap(pttc->bitmap_day, 128);
3235 pttc->bitmap_night = BuildDimmedToolBitmap(pttc->bitmap_day, 32);
3236 pttc->bitmap_Rollover_dusk = BuildDimmedToolBitmap(pttc->bitmap_Rollover_day, 128);
3237 pttc->bitmap_Rollover_night = BuildDimmedToolBitmap(pttc->bitmap_Rollover_day, 32);
3238
3239 pttc->kind = kind;
3240 pttc->shortHelp = shortHelp;
3241 pttc->longHelp = longHelp;
3242 pttc->clientData = clientData;
3243 pttc->position = position;
3244 pttc->m_pplugin = pplugin;
3245 pttc->tool_sel = tool_sel;
3246 pttc->b_viz = true;
3247 pttc->b_toggle = false;
3248 pttc->id = m_plugin_tool_id_next;
3249
3250
3251
3252 m_PlugInToolbarTools.Add(pttc);
3253
3254 m_plugin_tool_id_next++;
3255
3256 return pttc->id;
3257 }
3258
AddToolbarTool(wxString label,wxString SVGfile,wxString SVGRolloverfile,wxString SVGToggledfile,wxItemKind kind,wxString shortHelp,wxString longHelp,wxObject * clientData,int position,int tool_sel,opencpn_plugin * pplugin)3259 int PlugInManager::AddToolbarTool(wxString label, wxString SVGfile, wxString SVGRolloverfile, wxString SVGToggledfile,
3260 wxItemKind kind, wxString shortHelp, wxString longHelp,
3261 wxObject *clientData, int position, int tool_sel, opencpn_plugin *pplugin )
3262 {
3263 PlugInToolbarToolContainer *pttc = new PlugInToolbarToolContainer;
3264 pttc->label = label;
3265
3266 pttc->pluginNormalIconSVG = SVGfile;
3267 pttc->pluginRolloverIconSVG = SVGRolloverfile;
3268 pttc->pluginToggledIconSVG = SVGToggledfile;
3269
3270 // Build a set of bitmaps based on the generic "puzzle piece" icon,
3271 // In case there is some problem with the SVG file(s) specified.
3272 ocpnStyle::Style*style = g_StyleManager->GetCurrentStyle();
3273 pttc->bitmap_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3274 pttc->bitmap_Rollover_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3275
3276 pttc->bitmap_dusk = BuildDimmedToolBitmap(pttc->bitmap_day, 128);
3277 pttc->bitmap_night = BuildDimmedToolBitmap(pttc->bitmap_day, 32);
3278 pttc->bitmap_Rollover_day = new wxBitmap(*pttc->bitmap_day);
3279 pttc->bitmap_Rollover_dusk = BuildDimmedToolBitmap(pttc->bitmap_Rollover_day, 128);
3280 pttc->bitmap_Rollover_night = BuildDimmedToolBitmap(pttc->bitmap_Rollover_day, 32);
3281
3282 pttc->kind = kind;
3283 pttc->shortHelp = shortHelp;
3284 pttc->longHelp = longHelp;
3285 pttc->clientData = clientData;
3286 pttc->position = position;
3287 pttc->m_pplugin = pplugin;
3288 pttc->tool_sel = tool_sel;
3289 pttc->b_viz = true;
3290 pttc->b_toggle = false;
3291 pttc->id = m_plugin_tool_id_next;
3292
3293
3294
3295 m_PlugInToolbarTools.Add(pttc);
3296
3297 m_plugin_tool_id_next++;
3298
3299 return pttc->id;
3300 }
3301
RemoveToolbarTool(int tool_id)3302 void PlugInManager::RemoveToolbarTool(int tool_id)
3303 {
3304 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
3305 {
3306 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
3307 {
3308 if(pttc->id == tool_id)
3309 {
3310 m_PlugInToolbarTools.Remove(pttc);
3311 delete pttc;
3312 break;
3313 }
3314 }
3315 }
3316
3317 pParent->RequestNewToolbars();
3318 }
3319
SetToolbarToolViz(int item,bool viz)3320 void PlugInManager::SetToolbarToolViz(int item, bool viz)
3321 {
3322 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
3323 {
3324 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
3325 {
3326 if(pttc->id == item)
3327 {
3328 pttc->b_viz = viz;
3329
3330 // Apply the change
3331 pParent->RequestNewToolbars();
3332
3333 break;
3334 }
3335 }
3336 }
3337 }
3338
SetToolbarItemState(int item,bool toggle)3339 void PlugInManager::SetToolbarItemState(int item, bool toggle)
3340 {
3341 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
3342 {
3343 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
3344 {
3345 if(pttc->id == item)
3346 {
3347 pttc->b_toggle = toggle;
3348 pParent->SetMasterToolbarItemState( item, toggle);
3349 break;
3350 }
3351 }
3352 }
3353 }
3354
SetToolbarItemBitmaps(int item,wxBitmap * bitmap,wxBitmap * bmpRollover)3355 void PlugInManager::SetToolbarItemBitmaps(int item, wxBitmap *bitmap, wxBitmap *bmpRollover)
3356 {
3357 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
3358 {
3359 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
3360 {
3361 if(pttc->id == item)
3362 {
3363 delete pttc->bitmap_day;
3364 delete pttc->bitmap_dusk;
3365 delete pttc->bitmap_night;
3366 delete pttc->bitmap_Rollover_day;
3367
3368 if( !bitmap->IsOk() ) {
3369 ocpnStyle::Style*style = g_StyleManager->GetCurrentStyle();
3370 pttc->bitmap_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3371 } else {
3372 // Force a non-reference copy of the bitmap from the PlugIn
3373 pttc->bitmap_day = new wxBitmap(*bitmap);
3374 pttc->bitmap_day->UnShare();
3375 }
3376
3377 if( !bmpRollover->IsOk() ) {
3378 ocpnStyle::Style*style = g_StyleManager->GetCurrentStyle();
3379 pttc->bitmap_Rollover_day = new wxBitmap( style->GetIcon( _T("default_pi") ));
3380 } else {
3381 // Force a non-reference copy of the bitmap from the PlugIn
3382 pttc->bitmap_Rollover_day = new wxBitmap(*bmpRollover);
3383 pttc->bitmap_Rollover_day->UnShare();
3384 }
3385
3386 pttc->bitmap_dusk = BuildDimmedToolBitmap(pttc->bitmap_day, 128);
3387 pttc->bitmap_night = BuildDimmedToolBitmap(pttc->bitmap_day, 32);
3388
3389 pParent->SetToolbarItemBitmaps(item, pttc->bitmap_day, pttc->bitmap_Rollover_day);
3390 break;
3391 }
3392 }
3393 }
3394
3395 }
3396
SetToolbarItemBitmaps(int item,wxString SVGfile,wxString SVGfileRollover,wxString SVGfileToggled)3397 void PlugInManager::SetToolbarItemBitmaps(int item, wxString SVGfile, wxString SVGfileRollover, wxString SVGfileToggled)
3398 {
3399 for(unsigned int i=0; i < m_PlugInToolbarTools.GetCount(); i++)
3400 {
3401 PlugInToolbarToolContainer *pttc = m_PlugInToolbarTools[i];
3402 {
3403 if(pttc->id == item)
3404 {
3405 pttc->pluginNormalIconSVG = SVGfile;
3406 pttc->pluginRolloverIconSVG = SVGfileRollover;
3407 pttc->pluginToggledIconSVG = SVGfileToggled;
3408 pParent->SetToolbarItemSVG(item, pttc->pluginNormalIconSVG,
3409 pttc->pluginRolloverIconSVG,
3410 pttc->pluginToggledIconSVG);
3411 break;
3412 }
3413 }
3414 }
3415
3416 }
3417
3418
FindToolOwner(const int id)3419 opencpn_plugin *PlugInManager::FindToolOwner(const int id)
3420 {
3421 for(unsigned int i = 0 ; i < m_PlugInToolbarTools.GetCount() ; i++) {
3422 PlugInToolbarToolContainer *pc = m_PlugInToolbarTools[i];
3423 if(id == pc->id)
3424 return pc->m_pplugin;
3425 }
3426
3427 return NULL;
3428 }
3429
GetToolOwnerCommonName(const int id)3430 wxString PlugInManager::GetToolOwnerCommonName(const int id)
3431 {
3432 opencpn_plugin *ppi = FindToolOwner(id);
3433 if(ppi) {
3434 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++) {
3435 PlugInContainer *pic = plugin_array[i];
3436 if(pic && (pic->m_pplugin == ppi)) return pic->m_common_name;
3437 }
3438 }
3439
3440 return wxEmptyString;
3441 }
3442
3443
3444
3445
GetLastError()3446 wxString PlugInManager::GetLastError()
3447 {
3448 return m_last_error_string;
3449 }
3450
BuildDimmedToolBitmap(wxBitmap * pbmp_normal,unsigned char dim_ratio)3451 wxBitmap *PlugInManager::BuildDimmedToolBitmap(wxBitmap *pbmp_normal, unsigned char dim_ratio)
3452 {
3453 wxImage img_dup = pbmp_normal->ConvertToImage();
3454
3455 if( !img_dup.IsOk() ) return NULL;
3456
3457 if(dim_ratio < 200)
3458 {
3459 // Create a dimmed version of the image/bitmap
3460 int gimg_width = img_dup.GetWidth();
3461 int gimg_height = img_dup.GetHeight();
3462
3463 double factor = (double)(dim_ratio) / 256.0;
3464
3465 for(int iy=0 ; iy < gimg_height ; iy++)
3466 {
3467 for(int ix=0 ; ix < gimg_width ; ix++)
3468 {
3469 if(!img_dup.IsTransparent(ix, iy))
3470 {
3471 wxImage::RGBValue rgb(img_dup.GetRed(ix, iy), img_dup.GetGreen(ix, iy), img_dup.GetBlue(ix, iy));
3472 wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
3473 hsv.value = hsv.value * factor;
3474 wxImage::RGBValue nrgb = wxImage::HSVtoRGB(hsv);
3475 img_dup.SetRGB(ix, iy, nrgb.red, nrgb.green, nrgb.blue);
3476 }
3477 }
3478 }
3479 }
3480
3481 // Make a bitmap
3482 wxBitmap *ptoolBarBitmap;
3483
3484 #ifdef __WXMSW__
3485 wxBitmap tbmp(img_dup.GetWidth(),img_dup.GetHeight(),-1);
3486 wxMemoryDC dwxdc;
3487 dwxdc.SelectObject(tbmp);
3488
3489 ptoolBarBitmap = new wxBitmap(img_dup, (wxDC &)dwxdc);
3490 #else
3491 ptoolBarBitmap = new wxBitmap(img_dup);
3492 #endif
3493
3494 // store it
3495 return ptoolBarBitmap;
3496 }
3497
3498
GetPlugInChartClassNameArray(void)3499 wxArrayString PlugInManager::GetPlugInChartClassNameArray(void)
3500 {
3501 wxArrayString array;
3502 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++)
3503 {
3504 PlugInContainer *pic = plugin_array[i];
3505 if(pic->m_bEnabled && pic->m_bInitState &&
3506 ((pic->m_cap_flag & INSTALLS_PLUGIN_CHART) || (pic->m_cap_flag & INSTALLS_PLUGIN_CHART_GL)) )
3507 {
3508 wxArrayString carray = pic->m_pplugin->GetDynamicChartClassNameArray();
3509
3510 for(unsigned int j = 0 ; j < carray.GetCount() ; j++){
3511 array.Add(carray[j]);
3512 }
3513 }
3514 }
3515
3516 // Scrub the list for duplicates
3517 // Corrects a flaw in BSB4 and NVC PlugIns
3518 unsigned int j=0;
3519 while(j < array.GetCount())
3520 {
3521 wxString test = array[j];
3522 unsigned int k = j+1;
3523 while(k < array.GetCount())
3524 {
3525 if(test == array[k])
3526 {
3527 array.RemoveAt(k);
3528 j = -1;
3529 break;
3530 }
3531 else
3532 k++;
3533 }
3534
3535 j++;
3536 }
3537
3538
3539 return array;
3540 }
3541
IsPlugInAvailable(wxString commonName)3542 bool PlugInManager::IsPlugInAvailable(wxString commonName)
3543 {
3544 for(unsigned int i = 0 ; i < plugin_array.GetCount() ; i++) {
3545 PlugInContainer *pic = plugin_array[i];
3546 if(pic && pic->m_bEnabled && (pic->m_common_name == commonName) )
3547 return true;
3548 }
3549
3550 return false;
3551 }
3552
3553
3554
3555 //----------------------------------------------------------------------------------------------------------
3556 // The PlugIn CallBack API Implementation
3557 // The definitions of this API are found in ocpn_plugin.h
3558 //----------------------------------------------------------------------------------------------------------
3559
3560
InsertPlugInTool(wxString label,wxBitmap * bitmap,wxBitmap * bmpRollover,wxItemKind kind,wxString shortHelp,wxString longHelp,wxObject * clientData,int position,int tool_sel,opencpn_plugin * pplugin)3561 int InsertPlugInTool(wxString label, wxBitmap *bitmap, wxBitmap *bmpRollover, wxItemKind kind,
3562 wxString shortHelp, wxString longHelp, wxObject *clientData, int position,
3563 int tool_sel, opencpn_plugin *pplugin)
3564 {
3565 if(s_ppim)
3566 return s_ppim->AddToolbarTool(label, bitmap, bmpRollover, kind,
3567 shortHelp, longHelp, clientData, position,
3568 tool_sel, pplugin );
3569 else
3570 return -1;
3571 }
3572
3573
RemovePlugInTool(int tool_id)3574 void RemovePlugInTool(int tool_id)
3575 {
3576 if(s_ppim)
3577 s_ppim->RemoveToolbarTool(tool_id);
3578 }
3579
SetToolbarToolViz(int item,bool viz)3580 void SetToolbarToolViz(int item, bool viz)
3581 {
3582 if(s_ppim)
3583 s_ppim->SetToolbarToolViz(item, viz);
3584 }
3585
SetToolbarItemState(int item,bool toggle)3586 void SetToolbarItemState(int item, bool toggle)
3587 {
3588 if(s_ppim)
3589 s_ppim->SetToolbarItemState(item, toggle);
3590 }
3591
SetToolbarToolBitmaps(int item,wxBitmap * bitmap,wxBitmap * bmpRollover)3592 void SetToolbarToolBitmaps(int item, wxBitmap *bitmap, wxBitmap *bmpRollover)
3593 {
3594 if(s_ppim)
3595 s_ppim->SetToolbarItemBitmaps(item, bitmap, bmpRollover);
3596 }
3597
InsertPlugInToolSVG(wxString label,wxString SVGfile,wxString SVGfileRollover,wxString SVGfileToggled,wxItemKind kind,wxString shortHelp,wxString longHelp,wxObject * clientData,int position,int tool_sel,opencpn_plugin * pplugin)3598 int InsertPlugInToolSVG(wxString label, wxString SVGfile, wxString SVGfileRollover, wxString SVGfileToggled,
3599 wxItemKind kind, wxString shortHelp, wxString longHelp,
3600 wxObject *clientData, int position, int tool_sel, opencpn_plugin *pplugin)
3601 {
3602 if(s_ppim)
3603 return s_ppim->AddToolbarTool(label, SVGfile, SVGfileRollover, SVGfileToggled, kind,
3604 shortHelp, longHelp, clientData, position,
3605 tool_sel, pplugin );
3606 else
3607 return -1;
3608 }
3609
SetToolbarToolBitmapsSVG(int item,wxString SVGfile,wxString SVGfileRollover,wxString SVGfileToggled)3610 void SetToolbarToolBitmapsSVG(int item, wxString SVGfile, wxString SVGfileRollover, wxString SVGfileToggled)
3611 {
3612 if(s_ppim)
3613 s_ppim->SetToolbarItemBitmaps(item, SVGfile, SVGfileRollover, SVGfileToggled);
3614 }
3615
3616
AddCanvasMenuItem(wxMenuItem * pitem,opencpn_plugin * pplugin,const char * name)3617 int AddCanvasMenuItem(wxMenuItem *pitem, opencpn_plugin *pplugin, const char *name )
3618 {
3619 if(s_ppim)
3620 return s_ppim->AddCanvasContextMenuItem(pitem, pplugin, name );
3621 else
3622 return -1;
3623 }
3624
SetCanvasMenuItemViz(int item,bool viz,const char * name)3625 void SetCanvasMenuItemViz(int item, bool viz, const char *name)
3626 {
3627 if(s_ppim)
3628 s_ppim->SetCanvasContextMenuItemViz(item, viz, name);
3629 }
3630
SetCanvasMenuItemGrey(int item,bool grey,const char * name)3631 void SetCanvasMenuItemGrey(int item, bool grey, const char *name)
3632 {
3633 if(s_ppim)
3634 s_ppim->SetCanvasContextMenuItemGrey(item, grey, name);
3635 }
3636
3637
RemoveCanvasMenuItem(int item,const char * name)3638 void RemoveCanvasMenuItem(int item, const char *name)
3639 {
3640 if(s_ppim)
3641 s_ppim->RemoveCanvasContextMenuItem(item, name);
3642 }
3643
3644
AddCanvasContextMenuItem(wxMenuItem * pitem,opencpn_plugin * pplugin)3645 int AddCanvasContextMenuItem(wxMenuItem *pitem, opencpn_plugin *pplugin )
3646 {
3647 /* main context popup menu */
3648 return AddCanvasMenuItem(pitem, pplugin, "");
3649 }
3650
SetCanvasContextMenuItemViz(int item,bool viz)3651 void SetCanvasContextMenuItemViz(int item, bool viz)
3652 {
3653 SetCanvasMenuItemViz(item, viz);
3654 }
3655
SetCanvasContextMenuItemGrey(int item,bool grey)3656 void SetCanvasContextMenuItemGrey(int item, bool grey)
3657 {
3658 SetCanvasMenuItemGrey(item, grey);
3659 }
3660
3661
RemoveCanvasContextMenuItem(int item)3662 void RemoveCanvasContextMenuItem(int item)
3663 {
3664 RemoveCanvasMenuItem(item);
3665 }
3666
3667
3668
3669
GetOCPNConfigObject(void)3670 wxFileConfig *GetOCPNConfigObject(void)
3671 {
3672 if(s_ppim)
3673 return pConfig; // return the global application config object
3674 else
3675 return NULL;
3676 }
3677
GetOCPNCanvasWindow()3678 wxWindow *GetOCPNCanvasWindow()
3679 {
3680 wxWindow *pret = NULL;
3681 if(s_ppim)
3682 {
3683 MyFrame *pFrame = s_ppim->GetParentFrame();
3684 pret = (wxWindow *)pFrame->GetPrimaryCanvas();
3685 }
3686 return pret;
3687 }
3688
RequestRefresh(wxWindow * win)3689 void RequestRefresh(wxWindow *win)
3690 {
3691 if(win)
3692 win->Refresh();
3693 }
3694
GetCanvasPixLL(PlugIn_ViewPort * vp,wxPoint * pp,double lat,double lon)3695 void GetCanvasPixLL(PlugIn_ViewPort *vp, wxPoint *pp, double lat, double lon)
3696 {
3697 // Make enough of an application viewport to run its method....
3698 ViewPort ocpn_vp;
3699 ocpn_vp.clat = vp->clat;
3700 ocpn_vp.clon = vp->clon;
3701 ocpn_vp.m_projection_type = vp->m_projection_type;
3702 ocpn_vp.view_scale_ppm = vp->view_scale_ppm;
3703 ocpn_vp.skew = vp->skew;
3704 ocpn_vp.rotation = vp->rotation;
3705 ocpn_vp.pix_width = vp->pix_width;
3706 ocpn_vp.pix_height = vp->pix_height;
3707
3708 wxPoint ret = ocpn_vp.GetPixFromLL(lat, lon);
3709 pp->x = ret.x;
3710 pp->y = ret.y;
3711 }
3712
GetDoubleCanvasPixLL(PlugIn_ViewPort * vp,wxPoint2DDouble * pp,double lat,double lon)3713 void GetDoubleCanvasPixLL(PlugIn_ViewPort *vp, wxPoint2DDouble *pp, double lat, double lon)
3714 {
3715 // Make enough of an application viewport to run its method....
3716 ViewPort ocpn_vp;
3717 ocpn_vp.clat = vp->clat;
3718 ocpn_vp.clon = vp->clon;
3719 ocpn_vp.m_projection_type = vp->m_projection_type;
3720 ocpn_vp.view_scale_ppm = vp->view_scale_ppm;
3721 ocpn_vp.skew = vp->skew;
3722 ocpn_vp.rotation = vp->rotation;
3723 ocpn_vp.pix_width = vp->pix_width;
3724 ocpn_vp.pix_height = vp->pix_height;
3725
3726 *pp = ocpn_vp.GetDoublePixFromLL(lat, lon);
3727 }
3728
GetCanvasLLPix(PlugIn_ViewPort * vp,wxPoint p,double * plat,double * plon)3729 void GetCanvasLLPix( PlugIn_ViewPort *vp, wxPoint p, double *plat, double *plon)
3730 {
3731 // Make enough of an application viewport to run its method....
3732 ViewPort ocpn_vp;
3733 ocpn_vp.clat = vp->clat;
3734 ocpn_vp.clon = vp->clon;
3735 ocpn_vp.m_projection_type = vp->m_projection_type;
3736 ocpn_vp.view_scale_ppm = vp->view_scale_ppm;
3737 ocpn_vp.skew = vp->skew;
3738 ocpn_vp.rotation = vp->rotation;
3739 ocpn_vp.pix_width = vp->pix_width;
3740 ocpn_vp.pix_height = vp->pix_height;
3741
3742 return ocpn_vp.GetLLFromPix( p, plat, plon);
3743 }
3744
GetGlobalColor(wxString colorName,wxColour * pcolour)3745 bool GetGlobalColor(wxString colorName, wxColour *pcolour)
3746 {
3747 wxColour c = GetGlobalColor(colorName);
3748 *pcolour = c;
3749
3750 return true;
3751 }
3752
OCPNGetFont(wxString TextElement,int default_size)3753 wxFont *OCPNGetFont(wxString TextElement, int default_size)
3754 {
3755 return FontMgr::Get().GetFont(TextElement, default_size);
3756 }
3757
GetOCPNScaledFont_PlugIn(wxString TextElement,int default_size)3758 wxFont *GetOCPNScaledFont_PlugIn(wxString TextElement, int default_size)
3759 {
3760 return GetOCPNScaledFont( TextElement, default_size );
3761 }
3762
GetOCPNGUIToolScaleFactor_PlugIn(int GUIScaleFactor)3763 double GetOCPNGUIToolScaleFactor_PlugIn(int GUIScaleFactor)
3764 {
3765 return g_Platform->GetToolbarScaleFactor(GUIScaleFactor);
3766 }
3767
GetOCPNGUIToolScaleFactor_PlugIn()3768 double GetOCPNGUIToolScaleFactor_PlugIn()
3769 {
3770 return g_Platform->GetToolbarScaleFactor(g_GUIScaleFactor);
3771 }
3772
GetOCPNChartScaleFactor_Plugin()3773 float GetOCPNChartScaleFactor_Plugin()
3774 {
3775 return g_Platform->getChartScaleFactorExp( g_ChartScaleFactor );
3776 }
3777
GetOCPNGUIScaledFont_PlugIn(wxString item)3778 wxFont GetOCPNGUIScaledFont_PlugIn(wxString item)
3779 {
3780 return GetOCPNGUIScaledFont( item );
3781 }
3782
AddPersistentFontKey(wxString TextElement)3783 bool AddPersistentFontKey(wxString TextElement)
3784 {
3785 return FontMgr::Get().AddAuxKey( TextElement );
3786 }
3787
GetActiveStyleName()3788 wxString GetActiveStyleName()
3789 {
3790 if(g_StyleManager)
3791 return g_StyleManager->GetCurrentStyle()->name;
3792 else
3793 return _T("");
3794 }
3795
GetBitmapFromSVGFile(wxString filename,unsigned int width,unsigned int height)3796 wxBitmap GetBitmapFromSVGFile(wxString filename, unsigned int width, unsigned int height)
3797 {
3798 #ifdef ocpnUSE_SVG
3799 #ifndef __OCPN__ANDROID__
3800 wxSVGDocument svgDoc;
3801 if ( (width > 0) && (height > 0) && svgDoc.Load(filename))
3802 return wxBitmap(svgDoc.Render(width, height, NULL, false, true));
3803 else
3804 return wxBitmap(1, 1);
3805 #else
3806 return loadAndroidSVG( filename, width, height );
3807 #endif
3808 #else
3809 return wxBitmap(width, height);
3810 #endif // ocpnUSE_SVG
3811 }
3812
IsTouchInterface_PlugIn(void)3813 bool IsTouchInterface_PlugIn(void)
3814 {
3815 return g_btouch;
3816 }
3817
GetFontColour_PlugIn(wxString TextElement)3818 wxColour GetFontColour_PlugIn(wxString TextElement)
3819 {
3820 return FontMgr::Get().GetFontColor( TextElement );
3821 }
3822
GetpSharedDataLocation(void)3823 wxString *GetpSharedDataLocation(void)
3824 {
3825 return g_Platform->GetSharedDataDirPtr();
3826 }
3827
GetpPrivateApplicationDataLocation(void)3828 wxString *GetpPrivateApplicationDataLocation(void)
3829 {
3830 return g_Platform->GetPrivateDataDirPtr();
3831 }
3832
3833
3834
GetAISTargetArray(void)3835 ArrayOfPlugIn_AIS_Targets *GetAISTargetArray(void)
3836 {
3837 if ( !g_pAIS )
3838 return NULL;
3839
3840
3841 ArrayOfPlugIn_AIS_Targets *pret = new ArrayOfPlugIn_AIS_Targets;
3842
3843 // Iterate over the AIS Target Hashmap
3844 AIS_Target_Hash::iterator it;
3845
3846 AIS_Target_Hash *current_targets = g_pAIS->GetTargetList();
3847
3848 for ( it = ( *current_targets ).begin(); it != ( *current_targets ).end(); ++it )
3849 {
3850 AIS_Target_Data *td = it->second;
3851 PlugIn_AIS_Target *ptarget = Create_PI_AIS_Target(td);
3852 pret->Add(ptarget);
3853 }
3854
3855 // Test one alarm target
3856 #if 0
3857 AIS_Target_Data td;
3858 td.n_alarm_state = AIS_ALARM_SET;
3859 PlugIn_AIS_Target *ptarget = Create_PI_AIS_Target(&td);
3860 pret->Add(ptarget);
3861 #endif
3862 return pret;
3863 }
3864
3865
GetFrameAuiManager(void)3866 wxAuiManager *GetFrameAuiManager(void)
3867 {
3868 return g_pauimgr;
3869 }
3870
AddLocaleCatalog(wxString catalog)3871 bool AddLocaleCatalog( wxString catalog )
3872 {
3873 #if wxUSE_XLOCALE || !wxCHECK_VERSION(3,0,0)
3874
3875 if(plocale_def_lang){
3876 // Add this catalog to the persistent catalog array
3877 g_locale_catalog_array.Add(catalog);
3878
3879 return plocale_def_lang->AddCatalog( catalog );
3880 }
3881 else
3882 #endif
3883 return false;
3884 }
3885
PushNMEABuffer(wxString buf)3886 void PushNMEABuffer( wxString buf )
3887 {
3888 OCPN_DataStreamEvent event( wxEVT_OCPN_DATASTREAM, 0 );
3889 std::string s = std::string( buf.mb_str() );
3890 event.SetNMEAString( s );
3891 event.SetStream( NULL );
3892
3893 g_pMUX->AddPendingEvent( event );
3894 }
3895
GetChartDatabaseEntryXML(int dbIndex,bool b_getGeom)3896 wxXmlDocument GetChartDatabaseEntryXML(int dbIndex, bool b_getGeom)
3897 {
3898
3899 wxXmlDocument doc = ChartData->GetXMLDescription(dbIndex, b_getGeom);
3900
3901 return doc;
3902 }
3903
UpdateChartDBInplace(wxArrayString dir_array,bool b_force_update,bool b_ProgressDialog)3904 bool UpdateChartDBInplace(wxArrayString dir_array,
3905 bool b_force_update,
3906 bool b_ProgressDialog)
3907 {
3908 // Make an array of CDI
3909 ArrayOfCDI ChartDirArray;
3910 for(unsigned int i=0 ; i < dir_array.GetCount(); i++)
3911 {
3912 wxString dirname = dir_array[i];
3913 ChartDirInfo cdi;
3914 cdi.fullpath = dirname;
3915 cdi.magic_number = _T("");
3916 ChartDirArray.Add ( cdi );
3917 }
3918
3919 bool b_ret =gFrame->UpdateChartDatabaseInplace(ChartDirArray,
3920 b_force_update, b_ProgressDialog,
3921 ChartData->GetDBFileName());
3922
3923 gFrame->ChartsRefresh();
3924
3925 return b_ret;
3926 }
3927
GetChartDBDirArrayString()3928 wxArrayString GetChartDBDirArrayString()
3929 {
3930 return ChartData->GetChartDirArrayString();
3931 }
3932
AddChartToDBInPlace(wxString & full_path,bool b_RefreshCanvas)3933 int AddChartToDBInPlace( wxString &full_path, bool b_RefreshCanvas )
3934 {
3935 // extract the path from the chart name
3936 wxFileName fn(full_path);
3937 wxString fdir = fn.GetPath();
3938
3939 bool bret = false;
3940 if(ChartData){
3941
3942 bret = ChartData->AddSingleChart( full_path );
3943
3944 if(bret){
3945 // Save to disk
3946 pConfig->UpdateChartDirs( ChartData->GetChartDirArray() );
3947 ChartData->SaveBinary(ChartListFileName);
3948
3949
3950 // Completely reload the chart database, for a fresh start
3951 ArrayOfCDI XnewChartDirArray;
3952 pConfig->LoadChartDirArray( XnewChartDirArray );
3953 delete ChartData;
3954 ChartData = new ChartDB();
3955 ChartData->LoadBinary(ChartListFileName, XnewChartDirArray);
3956
3957 // Update group contents
3958 if(g_pGroupArray)
3959 ChartData->ApplyGroupArray(g_pGroupArray);
3960
3961
3962 if(g_boptionsactive){
3963 g_options->UpdateDisplayedChartDirList(ChartData->GetChartDirArray());
3964 }
3965
3966
3967 if(b_RefreshCanvas || !gFrame->GetPrimaryCanvas()->GetQuiltMode()) {
3968 gFrame->ChartsRefresh();
3969 }
3970 }
3971 }
3972 return bret;
3973
3974 }
3975
RemoveChartFromDBInPlace(wxString & full_path)3976 int RemoveChartFromDBInPlace( wxString &full_path )
3977 {
3978 bool bret = false;
3979 if(ChartData){
3980 bret = ChartData->RemoveSingleChart( full_path );
3981
3982 // Save to disk
3983 pConfig->UpdateChartDirs( ChartData->GetChartDirArray() );
3984 ChartData->SaveBinary(ChartListFileName);
3985
3986
3987 // Completely reload the chart database, for a fresh start
3988 ArrayOfCDI XnewChartDirArray;
3989 pConfig->LoadChartDirArray( XnewChartDirArray );
3990 delete ChartData;
3991 ChartData = new ChartDB();
3992 ChartData->LoadBinary(ChartListFileName, XnewChartDirArray);
3993
3994 // Update group contents
3995 if(g_pGroupArray)
3996 ChartData->ApplyGroupArray(g_pGroupArray);
3997
3998 if(g_boptionsactive){
3999 g_options->UpdateDisplayedChartDirList(ChartData->GetChartDirArray());
4000 }
4001
4002 gFrame->ChartsRefresh();
4003 }
4004
4005 return bret;
4006 }
4007
GetLocaleCanonicalName()4008 wxString GetLocaleCanonicalName()
4009 {
4010 return g_locale;
4011 }
4012
4013
SendPluginMessage(wxString message_id,wxString message_body)4014 void SendPluginMessage( wxString message_id, wxString message_body )
4015 {
4016 s_ppim->SendMessageToAllPlugins(message_id, message_body);
4017
4018 // We will send an event to the main application frame (gFrame)
4019 // for informational purposes.
4020 // Of course, gFrame is encouraged to use any or all the
4021 // data flying by if judged useful and dependable....
4022
4023 OCPN_MsgEvent Nevent(wxEVT_OCPN_MSG, 0);
4024 Nevent.SetID(message_id);
4025 Nevent.SetJSONText(message_body);
4026 gFrame->GetEventHandler()->AddPendingEvent( Nevent );
4027
4028 }
4029
DimeWindow(wxWindow * win)4030 void DimeWindow(wxWindow *win)
4031 {
4032 DimeControl(win);
4033 }
4034
JumpToPosition(double lat,double lon,double scale)4035 void JumpToPosition(double lat, double lon, double scale)
4036 {
4037 gFrame->JumpToPosition(gFrame->GetFocusCanvas(), lat, lon, scale);
4038 }
4039
4040 /* API 1.9 */
AddOptionsPage(OptionsParentPI parent,wxString title)4041 wxScrolledWindow *AddOptionsPage( OptionsParentPI parent, wxString title )
4042 {
4043 if (! g_pOptions) return NULL;
4044
4045 size_t parentid;
4046 switch (parent) {
4047 case PI_OPTIONS_PARENT_DISPLAY:
4048 parentid = g_pOptions->m_pageDisplay;
4049 break;
4050 case PI_OPTIONS_PARENT_CONNECTIONS:
4051 parentid = g_pOptions->m_pageConnections;
4052 break;
4053 case PI_OPTIONS_PARENT_CHARTS:
4054 parentid = g_pOptions->m_pageCharts;
4055 break;
4056 case PI_OPTIONS_PARENT_SHIPS:
4057 parentid = g_pOptions->m_pageShips;
4058 break;
4059 case PI_OPTIONS_PARENT_UI:
4060 parentid = g_pOptions->m_pageUI;
4061 break;
4062 case PI_OPTIONS_PARENT_PLUGINS:
4063 parentid = g_pOptions->m_pagePlugins;
4064 break;
4065 default:
4066 wxLogMessage( _T("Error in PluginManager::AddOptionsPage: Unknown parent") );
4067 return NULL;
4068 break;
4069 }
4070
4071 return g_pOptions->AddPage( parentid, title );
4072 }
4073
DeleteOptionsPage(wxScrolledWindow * page)4074 bool DeleteOptionsPage( wxScrolledWindow* page )
4075 {
4076 if (! g_pOptions) return false;
4077 return g_pOptions->DeletePluginPage( page );
4078 }
4079
DecodeSingleVDOMessage(const wxString & str,PlugIn_Position_Fix_Ex * pos,wxString * accumulator)4080 bool DecodeSingleVDOMessage( const wxString& str, PlugIn_Position_Fix_Ex *pos, wxString *accumulator )
4081 {
4082 if(!pos)
4083 return false;
4084
4085 GenericPosDatEx gpd;
4086 AIS_Error nerr = AIS_GENERIC_ERROR;
4087 if(g_pAIS)
4088 nerr = g_pAIS->DecodeSingleVDO(str, &gpd, accumulator);
4089 if(nerr == AIS_NoError){
4090 pos->Lat = gpd.kLat;
4091 pos->Lon = gpd.kLon;
4092 pos->Cog = gpd.kCog;
4093 pos->Sog = gpd.kSog;
4094 pos->Hdt = gpd.kHdt;
4095
4096 // Fill in the dummy values
4097 pos->FixTime = 0;
4098 pos->Hdm = 1000;
4099 pos->Var = 1000;
4100 pos->nSats = 0;
4101
4102 return true;
4103 }
4104
4105 return false;
4106 }
4107
GetChartbarHeight(void)4108 int GetChartbarHeight( void )
4109 {
4110 int val = 0;
4111 if(g_bShowChartBar){
4112 ChartCanvas *cc = gFrame->GetPrimaryCanvas();
4113 if(cc && cc->GetPiano()){
4114 val = cc->GetPiano()->GetHeight();
4115 }
4116 }
4117 return val;
4118 }
4119
4120
GetRoutepointGPX(RoutePoint * pRoutePoint,char * buffer,unsigned int buffer_length)4121 bool GetRoutepointGPX( RoutePoint *pRoutePoint, char *buffer, unsigned int buffer_length)
4122 {
4123 bool ret = false;
4124
4125 NavObjectCollection1 *pgpx = new NavObjectCollection1;
4126 pgpx->AddGPXWaypoint( pRoutePoint);
4127 wxString gpxfilename = wxFileName::CreateTempFileName(wxT("gpx"));
4128 pgpx->SaveFile(gpxfilename);
4129 delete pgpx;
4130
4131 wxFFile gpxfile( gpxfilename );
4132 wxString s;
4133 if( gpxfile.ReadAll( &s ) ) {
4134 if(s.Length() < buffer_length) {
4135 strncpy(buffer, (const char*)s.mb_str(wxConvUTF8), buffer_length -1);
4136 ret = true;
4137 }
4138 }
4139
4140 gpxfile.Close();
4141 ::wxRemoveFile(gpxfilename);
4142
4143 return ret;
4144 }
4145
GetActiveRoutepointGPX(char * buffer,unsigned int buffer_length)4146 bool GetActiveRoutepointGPX( char *buffer, unsigned int buffer_length )
4147 {
4148 if( g_pRouteMan->IsAnyRouteActive() )
4149 return GetRoutepointGPX( g_pRouteMan->GetpActivePoint(), buffer, buffer_length);
4150 else
4151 return false;
4152 }
4153
PositionBearingDistanceMercator_Plugin(double lat,double lon,double brg,double dist,double * dlat,double * dlon)4154 void PositionBearingDistanceMercator_Plugin(double lat, double lon,
4155 double brg, double dist,
4156 double *dlat, double *dlon)
4157 {
4158 PositionBearingDistanceMercator(lat, lon, brg, dist, dlat, dlon);
4159 }
4160
DistanceBearingMercator_Plugin(double lat0,double lon0,double lat1,double lon1,double * brg,double * dist)4161 void DistanceBearingMercator_Plugin(double lat0, double lon0, double lat1, double lon1, double *brg, double *dist)
4162 {
4163 DistanceBearingMercator( lat0, lon0, lat1, lon1, brg, dist);
4164 }
4165
DistGreatCircle_Plugin(double slat,double slon,double dlat,double dlon)4166 double DistGreatCircle_Plugin(double slat, double slon, double dlat, double dlon)
4167 {
4168 return DistGreatCircle(slat, slon, dlat, dlon);
4169 }
4170
toTM_Plugin(float lat,float lon,float lat0,float lon0,double * x,double * y)4171 void toTM_Plugin(float lat, float lon, float lat0, float lon0, double *x, double *y)
4172 {
4173 toTM(lat, lon, lat0, lon0, x, y);
4174 }
4175
fromTM_Plugin(double x,double y,double lat0,double lon0,double * lat,double * lon)4176 void fromTM_Plugin(double x, double y, double lat0, double lon0, double *lat, double *lon)
4177 {
4178 fromTM(x, y, lat0, lon0, lat, lon);
4179 }
4180
toSM_Plugin(double lat,double lon,double lat0,double lon0,double * x,double * y)4181 void toSM_Plugin(double lat, double lon, double lat0, double lon0, double *x, double *y)
4182 {
4183 toSM(lat, lon, lat0, lon0, x, y);
4184 }
4185
fromSM_Plugin(double x,double y,double lat0,double lon0,double * lat,double * lon)4186 void fromSM_Plugin(double x, double y, double lat0, double lon0, double *lat, double *lon)
4187 {
4188 fromSM(x, y, lat0, lon0, lat, lon);
4189 }
4190
toSM_ECC_Plugin(double lat,double lon,double lat0,double lon0,double * x,double * y)4191 void toSM_ECC_Plugin(double lat, double lon, double lat0, double lon0, double *x, double *y)
4192 {
4193 toSM_ECC(lat, lon, lat0, lon0, x, y);
4194 }
4195
fromSM_ECC_Plugin(double x,double y,double lat0,double lon0,double * lat,double * lon)4196 void fromSM_ECC_Plugin(double x, double y, double lat0, double lon0, double *lat, double *lon)
4197 {
4198 fromSM_ECC(x, y, lat0, lon0, lat, lon);
4199 }
4200
toUsrDistance_Plugin(double nm_distance,int unit)4201 double toUsrDistance_Plugin( double nm_distance, int unit )
4202 {
4203 return toUsrDistance( nm_distance, unit );
4204 }
4205
fromUsrDistance_Plugin(double usr_distance,int unit)4206 double fromUsrDistance_Plugin( double usr_distance, int unit )
4207 {
4208 return fromUsrDistance( usr_distance, unit );
4209 }
4210
toUsrSpeed_Plugin(double kts_speed,int unit)4211 double toUsrSpeed_Plugin( double kts_speed, int unit )
4212 {
4213 return toUsrSpeed( kts_speed, unit );
4214 }
4215
fromUsrSpeed_Plugin(double usr_speed,int unit)4216 double fromUsrSpeed_Plugin( double usr_speed, int unit )
4217 {
4218 return fromUsrSpeed( usr_speed, unit );
4219 }
4220
getUsrDistanceUnit_Plugin(int unit)4221 wxString getUsrDistanceUnit_Plugin( int unit )
4222 {
4223 return getUsrDistanceUnit( unit );
4224 }
4225
getUsrSpeedUnit_Plugin(int unit)4226 wxString getUsrSpeedUnit_Plugin( int unit )
4227 {
4228 return getUsrSpeedUnit( unit );
4229 }
4230
PlugIn_GSHHS_CrossesLand(double lat1,double lon1,double lat2,double lon2)4231 bool PlugIn_GSHHS_CrossesLand(double lat1, double lon1, double lat2, double lon2)
4232 {
4233 static bool loaded = false;
4234 if(!loaded) {
4235 gshhsCrossesLandInit();
4236 loaded = true;
4237 }
4238
4239 return gshhsCrossesLand(lat1, lon1, lat2, lon2);
4240 }
4241
4242
PlugInPlaySound(wxString & sound_file)4243 void PlugInPlaySound(wxString& sound_file)
4244 {
4245 PlugInPlaySoundEx(sound_file, -1);
4246 }
4247
4248 // API 1.10 Route and Waypoint Support
4249 //wxBitmap *FindSystemWaypointIcon( wxString& icon_name );
4250
4251 // PlugInWaypoint implementation
PlugIn_Waypoint()4252 PlugIn_Waypoint::PlugIn_Waypoint()
4253 {
4254 m_HyperlinkList = NULL;
4255 }
4256
PlugIn_Waypoint(double lat,double lon,const wxString & icon_ident,const wxString & wp_name,const wxString & GUID)4257 PlugIn_Waypoint::PlugIn_Waypoint(double lat, double lon,
4258 const wxString& icon_ident, const wxString& wp_name,
4259 const wxString& GUID )
4260 {
4261 wxDateTime now = wxDateTime::Now();
4262 m_CreateTime = now.ToUTC();
4263 m_HyperlinkList = NULL;
4264
4265 m_lat = lat;
4266 m_lon = lon;
4267 m_IconName = icon_ident;
4268 m_MarkName = wp_name;
4269 m_GUID = GUID;
4270 }
4271
~PlugIn_Waypoint()4272 PlugIn_Waypoint::~PlugIn_Waypoint()
4273 {
4274 }
4275
4276 // PlugInRoute implementation
PlugIn_Route(void)4277 PlugIn_Route::PlugIn_Route(void )
4278 {
4279 pWaypointList = new Plugin_WaypointList;
4280 }
4281
~PlugIn_Route(void)4282 PlugIn_Route::~PlugIn_Route(void )
4283 {
4284 pWaypointList->DeleteContents( false ); // do not delete Waypoints
4285 pWaypointList->Clear();
4286
4287 delete pWaypointList;
4288 }
4289
4290 // PlugInTrack implementation
PlugIn_Track(void)4291 PlugIn_Track::PlugIn_Track(void )
4292 {
4293 pWaypointList = new Plugin_WaypointList;
4294 }
4295
~PlugIn_Track(void)4296 PlugIn_Track::~PlugIn_Track(void )
4297 {
4298 pWaypointList->DeleteContents( false ); // do not delete Waypoints
4299 pWaypointList->Clear();
4300
4301 delete pWaypointList;
4302 }
4303
4304
4305
GetNewGUID(void)4306 wxString GetNewGUID( void )
4307 {
4308 return GpxDocument::GetUUID();
4309 }
4310
AddCustomWaypointIcon(wxBitmap * pimage,wxString key,wxString description)4311 bool AddCustomWaypointIcon( wxBitmap *pimage, wxString key, wxString description )
4312 {
4313 pWayPointMan->ProcessIcon( *pimage, key, description );
4314 return true;
4315 }
4316
cloneHyperlinkList(RoutePoint * dst,const PlugIn_Waypoint * src)4317 static void cloneHyperlinkList(RoutePoint *dst, const PlugIn_Waypoint *src)
4318 {
4319 // Transcribe (clone) the html HyperLink List, if present
4320 if( src->m_HyperlinkList == nullptr)
4321 return;
4322
4323 if( src->m_HyperlinkList->GetCount() > 0 ) {
4324 wxPlugin_HyperlinkListNode *linknode = src->m_HyperlinkList->GetFirst();
4325 while( linknode ) {
4326 Plugin_Hyperlink *link = linknode->GetData();
4327
4328 Hyperlink* h = new Hyperlink();
4329 h->DescrText = link->DescrText;
4330 h->Link = link->Link;
4331 h->LType = link->Type;
4332
4333 dst->m_HyperlinkList->Append( h );
4334
4335 linknode = linknode->GetNext();
4336 }
4337 }
4338 }
4339
AddSingleWaypoint(PlugIn_Waypoint * pwaypoint,bool b_permanent)4340 bool AddSingleWaypoint( PlugIn_Waypoint *pwaypoint, bool b_permanent)
4341 {
4342 // Validate the waypoint parameters a little bit
4343
4344 // GUID
4345 // Make sure that this GUID is indeed unique in the Routepoint list
4346 bool b_unique = true;
4347 wxRoutePointListNode *prpnode = pWayPointMan->GetWaypointList()->GetFirst();
4348 while( prpnode ) {
4349 RoutePoint *prp = prpnode->GetData();
4350
4351 if( prp->m_GUID == pwaypoint->m_GUID ) {
4352 b_unique = false;
4353 break;
4354 }
4355 prpnode = prpnode->GetNext(); //RoutePoint
4356 }
4357
4358 if( !b_unique )
4359 return false;
4360
4361 RoutePoint *pWP = new RoutePoint( pwaypoint->m_lat, pwaypoint->m_lon,
4362 pwaypoint->m_IconName, pwaypoint->m_MarkName,
4363 pwaypoint->m_GUID );
4364
4365 pWP->m_bIsolatedMark = true; // This is an isolated mark
4366
4367 cloneHyperlinkList(pWP, pwaypoint);
4368
4369 pWP->m_MarkDescription = pwaypoint->m_MarkDescription;
4370 pWP->SetCreateTime(pwaypoint->m_CreateTime);
4371 pWP->m_btemp = (b_permanent == false);
4372
4373 pSelect->AddSelectableRoutePoint( pwaypoint->m_lat, pwaypoint->m_lon, pWP );
4374 if(b_permanent)
4375 pConfig->AddNewWayPoint( pWP, -1 );
4376
4377 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4378 pRouteManagerDialog->UpdateWptListCtrl();
4379
4380 return true;
4381 }
4382
DeleteSingleWaypoint(wxString & GUID)4383 bool DeleteSingleWaypoint( wxString &GUID )
4384 {
4385 // Find the RoutePoint
4386 bool b_found = false;
4387 RoutePoint *prp = pWayPointMan->FindRoutePointByGUID( GUID );
4388
4389 if(prp)
4390 b_found = true;
4391
4392 if( b_found ) {
4393 pWayPointMan->DestroyWaypoint( prp );
4394 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4395 pRouteManagerDialog->UpdateWptListCtrl();
4396 }
4397
4398 return b_found;
4399 }
4400
4401
UpdateSingleWaypoint(PlugIn_Waypoint * pwaypoint)4402 bool UpdateSingleWaypoint( PlugIn_Waypoint *pwaypoint )
4403 {
4404 // Find the RoutePoint
4405 bool b_found = false;
4406 RoutePoint *prp = pWayPointMan->FindRoutePointByGUID( pwaypoint->m_GUID );
4407
4408 if(prp)
4409 b_found = true;
4410
4411 if( b_found ) {
4412 double lat_save = prp->m_lat;
4413 double lon_save = prp->m_lon;
4414
4415 prp->m_lat = pwaypoint->m_lat;
4416 prp->m_lon = pwaypoint->m_lon;
4417 prp->SetIconName( pwaypoint->m_IconName );
4418 prp->SetName( pwaypoint->m_MarkName );
4419 prp->m_MarkDescription = pwaypoint->m_MarkDescription;
4420 prp->SetVisible(pwaypoint->m_IsVisible);
4421 prp->SetCreateTime(pwaypoint->m_CreateTime);
4422
4423 // Transcribe (clone) the html HyperLink List, if present
4424
4425 if( pwaypoint->m_HyperlinkList ) {
4426 prp->m_HyperlinkList->Clear();
4427 if( pwaypoint->m_HyperlinkList->GetCount() > 0 ) {
4428 wxPlugin_HyperlinkListNode *linknode = pwaypoint->m_HyperlinkList->GetFirst();
4429 while( linknode ) {
4430 Plugin_Hyperlink *link = linknode->GetData();
4431
4432 Hyperlink* h = new Hyperlink();
4433 h->DescrText = link->DescrText;
4434 h->Link = link->Link;
4435 h->LType = link->Type;
4436
4437 prp->m_HyperlinkList->Append( h );
4438
4439 linknode = linknode->GetNext();
4440 }
4441 }
4442 }
4443
4444 SelectItem *pFind = pSelect->FindSelection( gFrame->GetPrimaryCanvas(), lat_save, lon_save, SELTYPE_ROUTEPOINT );
4445 if( pFind ) {
4446 pFind->m_slat = pwaypoint->m_lat; // update the SelectList entry
4447 pFind->m_slon = pwaypoint->m_lon;
4448 }
4449
4450 if(!prp->m_btemp)
4451 pConfig->UpdateWayPoint( prp );
4452
4453 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4454 pRouteManagerDialog->UpdateWptListCtrl();
4455 }
4456
4457 return b_found;
4458 }
4459
4460 // translate O route class to Plugin one
PlugInFromRoutePoint(PlugIn_Waypoint * dst,RoutePoint * src)4461 static void PlugInFromRoutePoint(PlugIn_Waypoint *dst, /* const*/ RoutePoint *src)
4462 {
4463 dst->m_lat = src->m_lat;
4464 dst->m_lon = src->m_lon;
4465 dst->m_IconName = src->GetIconName();
4466 dst->m_MarkName = src->GetName( );
4467 dst->m_MarkDescription = src->m_MarkDescription;
4468 dst->m_IsVisible = src->IsVisible();
4469 dst->m_CreateTime = src->GetCreateTime(); // not const
4470 dst->m_GUID = src->m_GUID;
4471
4472 // Transcribe (clone) the html HyperLink List, if present
4473 if( src->m_HyperlinkList == nullptr )
4474 return;
4475
4476 delete dst->m_HyperlinkList;
4477 dst->m_HyperlinkList = nullptr;
4478
4479 if( src->m_HyperlinkList->GetCount() > 0 ) {
4480 dst->m_HyperlinkList = new Plugin_HyperlinkList;
4481
4482 wxHyperlinkListNode *linknode = src->m_HyperlinkList->GetFirst();
4483 while( linknode ) {
4484 Hyperlink *link = linknode->GetData();
4485
4486 Plugin_Hyperlink* h = new Plugin_Hyperlink();
4487 h->DescrText = link->DescrText;
4488 h->Link = link->Link;
4489 h->Type = link->LType;
4490
4491 dst->m_HyperlinkList->Append( h );
4492
4493 linknode = linknode->GetNext();
4494 }
4495 }
4496 }
4497
GetSingleWaypoint(wxString GUID,PlugIn_Waypoint * pwaypoint)4498 bool GetSingleWaypoint(wxString GUID, PlugIn_Waypoint *pwaypoint)
4499 {
4500 // Find the RoutePoint
4501 RoutePoint *prp = pWayPointMan->FindRoutePointByGUID( GUID );
4502
4503 if(!prp)
4504 return false;
4505
4506 PlugInFromRoutePoint(pwaypoint, prp);
4507
4508 return true;
4509 }
4510
GetWaypointGUIDArray(void)4511 wxArrayString GetWaypointGUIDArray( void )
4512 {
4513 wxArrayString result;
4514 RoutePointList *list = pWayPointMan->GetWaypointList();
4515
4516 wxRoutePointListNode *prpnode = list->GetFirst();
4517 while( prpnode ) {
4518 RoutePoint *prp = prpnode->GetData();
4519 result.Add(prp->m_GUID);
4520
4521 prpnode = prpnode->GetNext(); //RoutePoint
4522 }
4523
4524 return result;
4525 }
4526
GetIconNameArray(void)4527 wxArrayString GetIconNameArray(void)
4528 {
4529 wxArrayString result;
4530
4531 for (int i = 0; i < pWayPointMan->GetNumIcons(); i++) {
4532 wxString *ps = pWayPointMan->GetIconKey(i);
4533 result.Add(*ps);
4534 }
4535 return result;
4536 }
4537
AddPlugInRoute(PlugIn_Route * proute,bool b_permanent)4538 bool AddPlugInRoute( PlugIn_Route *proute, bool b_permanent )
4539 {
4540 Route *route = new Route();
4541
4542 PlugIn_Waypoint *pwp;
4543 RoutePoint *pWP_src;
4544 int ip = 0;
4545 wxDateTime plannedDeparture;
4546
4547 wxPlugin_WaypointListNode *pwpnode = proute->pWaypointList->GetFirst();
4548 while( pwpnode ) {
4549 pwp = pwpnode->GetData();
4550
4551 RoutePoint *pWP = new RoutePoint( pwp->m_lat, pwp->m_lon,
4552 pwp->m_IconName, pwp->m_MarkName,
4553 pwp->m_GUID );
4554
4555 // Transcribe (clone) the html HyperLink List, if present
4556 cloneHyperlinkList(pWP, pwp);
4557 pWP->m_MarkDescription = pwp->m_MarkDescription;
4558 pWP->m_bShowName = false;
4559 pWP->SetCreateTime(pwp->m_CreateTime);
4560
4561 route->AddPoint( pWP );
4562
4563
4564 pSelect->AddSelectableRoutePoint( pWP->m_lat, pWP->m_lon, pWP );
4565
4566 if(ip > 0)
4567 pSelect->AddSelectableRouteSegment( pWP_src->m_lat, pWP_src->m_lon, pWP->m_lat,
4568 pWP->m_lon, pWP_src, pWP, route );
4569 else
4570 plannedDeparture = pwp->m_CreateTime;
4571 ip++;
4572 pWP_src = pWP;
4573
4574 pwpnode = pwpnode->GetNext(); //PlugInWaypoint
4575 }
4576
4577 route->m_PlannedDeparture = plannedDeparture;
4578
4579 route->m_RouteNameString = proute->m_NameString;
4580 route->m_RouteStartString = proute->m_StartString;
4581 route->m_RouteEndString = proute->m_EndString;
4582 if (!proute->m_GUID.IsEmpty()) {
4583 route->m_GUID = proute->m_GUID;
4584 }
4585 route->m_btemp = (b_permanent == false);
4586
4587 pRouteList->Append( route );
4588
4589 if(b_permanent)
4590 pConfig->AddNewRoute( route );
4591
4592 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4593 pRouteManagerDialog->UpdateRouteListCtrl();
4594
4595 return true;
4596 }
4597
4598
4599
DeletePlugInRoute(wxString & GUID)4600 bool DeletePlugInRoute( wxString& GUID )
4601 {
4602 bool b_found = false;
4603
4604 // Find the Route
4605 Route *pRoute = g_pRouteMan->FindRouteByGUID( GUID );
4606 if(pRoute) {
4607 g_pRouteMan->DeleteRoute( pRoute );
4608 b_found = true;
4609 }
4610 return b_found;
4611 }
4612
UpdatePlugInRoute(PlugIn_Route * proute)4613 bool UpdatePlugInRoute ( PlugIn_Route *proute )
4614 {
4615 bool b_found = false;
4616
4617 // Find the Route
4618 Route *pRoute = g_pRouteMan->FindRouteByGUID( proute->m_GUID );
4619 if(pRoute)
4620 b_found = true;
4621
4622 if(b_found) {
4623 bool b_permanent = (pRoute->m_btemp == false);
4624 g_pRouteMan->DeleteRoute( pRoute );
4625
4626 b_found = AddPlugInRoute( proute, b_permanent );
4627 }
4628
4629 return b_found;
4630 }
4631
4632
AddPlugInTrack(PlugIn_Track * ptrack,bool b_permanent)4633 bool AddPlugInTrack( PlugIn_Track *ptrack, bool b_permanent )
4634 {
4635 Track *track = new Track();
4636
4637 PlugIn_Waypoint *pwp = 0;
4638 TrackPoint *pWP_src = 0;
4639 int ip = 0;
4640
4641 wxPlugin_WaypointListNode *pwpnode = ptrack->pWaypointList->GetFirst();
4642 while( pwpnode ) {
4643 pwp = pwpnode->GetData();
4644
4645 TrackPoint *pWP = new TrackPoint( pwp->m_lat, pwp->m_lon );
4646 pWP->SetCreateTime( pwp->m_CreateTime );
4647
4648 track->AddPoint( pWP );
4649
4650 if(ip > 0)
4651 pSelect->AddSelectableTrackSegment( pWP_src->m_lat, pWP_src->m_lon, pWP->m_lat,
4652 pWP->m_lon, pWP_src, pWP, track );
4653 ip++;
4654 pWP_src = pWP;
4655
4656 pwpnode = pwpnode->GetNext(); //PlugInWaypoint
4657 }
4658
4659 track->SetName(ptrack->m_NameString);
4660 track->m_TrackStartString = ptrack->m_StartString;
4661 track->m_TrackEndString = ptrack->m_EndString;
4662 track->m_GUID = ptrack->m_GUID;
4663 track->m_btemp = (b_permanent == false);
4664
4665 pTrackList->Append( track );
4666
4667 if(b_permanent)
4668 pConfig->AddNewTrack( track );
4669
4670 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4671 pRouteManagerDialog->UpdateTrkListCtrl();
4672
4673 return true;
4674 }
4675
4676
4677
DeletePluginTrack(wxString & GUID)4678 bool DeletePluginTrack( wxString& GUID )
4679 {
4680 bool b_found = false;
4681
4682 // Find the Route
4683 Track *pTrack = g_pRouteMan->FindTrackByGUID( GUID );
4684 if(pTrack) {
4685 g_pRouteMan->DeleteTrack( pTrack );
4686 b_found = true;
4687 }
4688
4689 if( pRouteManagerDialog && pRouteManagerDialog->IsShown() )
4690 pRouteManagerDialog->UpdateTrkListCtrl();
4691
4692 return b_found;
4693 }
4694
UpdatePlugInTrack(PlugIn_Track * ptrack)4695 bool UpdatePlugInTrack ( PlugIn_Track *ptrack )
4696 {
4697 bool b_found = false;
4698
4699 // Find the Track
4700 Track *pTrack = g_pRouteMan->FindTrackByGUID( ptrack->m_GUID );
4701 if(pTrack)
4702 b_found = true;
4703
4704 if(b_found) {
4705 bool b_permanent = (pTrack->m_btemp == false);
4706 g_pRouteMan->DeleteTrack( pTrack );
4707
4708 b_found = AddPlugInTrack( ptrack, b_permanent );
4709 }
4710
4711 return b_found;
4712 }
4713
PlugInHasNormalizedViewPort(PlugIn_ViewPort * vp)4714 bool PlugInHasNormalizedViewPort( PlugIn_ViewPort *vp )
4715 {
4716 #ifdef ocpnUSE_GL
4717 ViewPort ocpn_vp;
4718 ocpn_vp.m_projection_type = vp->m_projection_type;
4719
4720 return glChartCanvas::HasNormalizedViewPort(ocpn_vp);
4721 #else
4722 return false;
4723 #endif
4724 }
4725
PlugInMultMatrixViewport(PlugIn_ViewPort * vp,float lat,float lon)4726 void PlugInMultMatrixViewport ( PlugIn_ViewPort *vp, float lat, float lon )
4727 {
4728 #ifdef ocpnUSE_GL
4729 ViewPort ocpn_vp;
4730 ocpn_vp.clat = vp->clat;
4731 ocpn_vp.clon = vp->clon;
4732 ocpn_vp.m_projection_type = vp->m_projection_type;
4733 ocpn_vp.view_scale_ppm = vp->view_scale_ppm;
4734 ocpn_vp.skew = vp->skew;
4735 ocpn_vp.rotation = vp->rotation;
4736 ocpn_vp.pix_width = vp->pix_width;
4737 ocpn_vp.pix_height = vp->pix_height;
4738
4739 //TODO fix for multicanvas glChartCanvas::MultMatrixViewPort(ocpn_vp, lat, lon);
4740 #endif
4741 }
4742
PlugInNormalizeViewport(PlugIn_ViewPort * vp,float lat,float lon)4743 void PlugInNormalizeViewport ( PlugIn_ViewPort *vp, float lat, float lon )
4744 {
4745 #ifdef ocpnUSE_GL
4746 ViewPort ocpn_vp;
4747 glChartCanvas::NormalizedViewPort(ocpn_vp, lat, lon);
4748
4749 vp->clat = ocpn_vp.clat;
4750 vp->clon = ocpn_vp.clon;
4751 vp->view_scale_ppm = ocpn_vp.view_scale_ppm;
4752 vp->rotation = ocpn_vp.rotation;
4753 vp->skew = ocpn_vp.skew;
4754 #endif
4755 }
4756
4757
4758 //-----------------------------------------------------------------------------------------
4759 // The opencpn_plugin base class implementation
4760 //-----------------------------------------------------------------------------------------
4761
~opencpn_plugin()4762 opencpn_plugin::~opencpn_plugin()
4763 {}
4764
Init(void)4765 int opencpn_plugin::Init(void)
4766 {
4767 return 0;
4768 }
4769
4770
DeInit(void)4771 bool opencpn_plugin::DeInit(void)
4772 {
4773 return true;
4774 }
4775
GetAPIVersionMajor()4776 int opencpn_plugin::GetAPIVersionMajor()
4777 {
4778 return 1;
4779 }
4780
GetAPIVersionMinor()4781 int opencpn_plugin::GetAPIVersionMinor()
4782 {
4783 return 2;
4784 }
4785
GetPlugInVersionMajor()4786 int opencpn_plugin::GetPlugInVersionMajor()
4787 {
4788 return 1;
4789 }
4790
GetPlugInVersionMinor()4791 int opencpn_plugin::GetPlugInVersionMinor()
4792 {
4793 return 0;
4794 }
4795
GetPlugInBitmap()4796 wxBitmap *opencpn_plugin::GetPlugInBitmap()
4797 {
4798 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
4799 return new wxBitmap(style->GetIcon( _T("default_pi") ) );
4800 }
4801
GetCommonName()4802 wxString opencpn_plugin::GetCommonName()
4803 {
4804 return _T("BaseClassCommonName");
4805 }
4806
GetShortDescription()4807 wxString opencpn_plugin::GetShortDescription()
4808 {
4809 return _T("OpenCPN PlugIn Base Class");
4810 }
4811
GetLongDescription()4812 wxString opencpn_plugin::GetLongDescription()
4813 {
4814 return _T("OpenCPN PlugIn Base Class\n\
4815 PlugInManager created this base class");
4816 }
4817
4818
4819
SetPositionFix(PlugIn_Position_Fix & pfix)4820 void opencpn_plugin::SetPositionFix(PlugIn_Position_Fix &pfix)
4821 {}
4822
SetNMEASentence(wxString & sentence)4823 void opencpn_plugin::SetNMEASentence(wxString &sentence)
4824 {}
4825
SetAISSentence(wxString & sentence)4826 void opencpn_plugin::SetAISSentence(wxString &sentence)
4827 {}
4828
GetToolbarToolCount(void)4829 int opencpn_plugin::GetToolbarToolCount(void)
4830 {
4831 return 0;
4832 }
4833
GetToolboxPanelCount(void)4834 int opencpn_plugin::GetToolboxPanelCount(void)
4835 {
4836 return 0;
4837 }
4838
SetupToolboxPanel(int page_sel,wxNotebook * pnotebook)4839 void opencpn_plugin::SetupToolboxPanel(int page_sel, wxNotebook* pnotebook)
4840 {}
4841
OnCloseToolboxPanel(int page_sel,int ok_apply_cancel)4842 void opencpn_plugin::OnCloseToolboxPanel(int page_sel, int ok_apply_cancel)
4843 {}
4844
ShowPreferencesDialog(wxWindow * parent)4845 void opencpn_plugin::ShowPreferencesDialog( wxWindow* parent )
4846 {}
4847
OnToolbarToolCallback(int id)4848 void opencpn_plugin::OnToolbarToolCallback(int id)
4849 {}
4850
OnContextMenuItemCallback(int id)4851 void opencpn_plugin::OnContextMenuItemCallback(int id)
4852 {}
4853
RenderOverlay(wxMemoryDC * dc,PlugIn_ViewPort * vp)4854 bool opencpn_plugin::RenderOverlay(wxMemoryDC *dc, PlugIn_ViewPort *vp)
4855 {
4856 return false;
4857 }
4858
SetCursorLatLon(double lat,double lon)4859 void opencpn_plugin::SetCursorLatLon(double lat, double lon)
4860 {}
4861
SetCurrentViewPort(PlugIn_ViewPort & vp)4862 void opencpn_plugin::SetCurrentViewPort(PlugIn_ViewPort &vp)
4863 {}
4864
SetDefaults(void)4865 void opencpn_plugin::SetDefaults(void)
4866 {}
4867
ProcessParentResize(int x,int y)4868 void opencpn_plugin::ProcessParentResize(int x, int y)
4869 {}
4870
SetColorScheme(PI_ColorScheme cs)4871 void opencpn_plugin::SetColorScheme(PI_ColorScheme cs)
4872 {}
4873
UpdateAuiStatus(void)4874 void opencpn_plugin::UpdateAuiStatus(void)
4875 {}
4876
4877
GetDynamicChartClassNameArray()4878 wxArrayString opencpn_plugin::GetDynamicChartClassNameArray()
4879 {
4880 wxArrayString array;
4881 return array;
4882 }
4883
4884
4885 // Opencpn_Plugin_16 Implementation
opencpn_plugin_16(void * pmgr)4886 opencpn_plugin_16::opencpn_plugin_16(void *pmgr)
4887 : opencpn_plugin(pmgr)
4888 {
4889 }
4890
~opencpn_plugin_16(void)4891 opencpn_plugin_16::~opencpn_plugin_16(void)
4892 {}
4893
RenderOverlay(wxDC & dc,PlugIn_ViewPort * vp)4894 bool opencpn_plugin_16::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp)
4895 {
4896 return false;
4897 }
4898
SetPluginMessage(wxString & message_id,wxString & message_body)4899 void opencpn_plugin_16::SetPluginMessage(wxString &message_id, wxString &message_body)
4900 {}
4901
4902 // Opencpn_Plugin_17 Implementation
opencpn_plugin_17(void * pmgr)4903 opencpn_plugin_17::opencpn_plugin_17(void *pmgr)
4904 : opencpn_plugin(pmgr)
4905 {
4906 }
4907
~opencpn_plugin_17(void)4908 opencpn_plugin_17::~opencpn_plugin_17(void)
4909 {}
4910
4911
RenderOverlay(wxDC & dc,PlugIn_ViewPort * vp)4912 bool opencpn_plugin_17::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp)
4913 {
4914 return false;
4915 }
4916
RenderGLOverlay(wxGLContext * pcontext,PlugIn_ViewPort * vp)4917 bool opencpn_plugin_17::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp)
4918 {
4919 return false;
4920 }
4921
SetPluginMessage(wxString & message_id,wxString & message_body)4922 void opencpn_plugin_17::SetPluginMessage(wxString &message_id, wxString &message_body)
4923 {}
4924
4925
4926 // Opencpn_Plugin_18 Implementation
opencpn_plugin_18(void * pmgr)4927 opencpn_plugin_18::opencpn_plugin_18(void *pmgr)
4928 : opencpn_plugin(pmgr)
4929 {
4930 }
4931
~opencpn_plugin_18(void)4932 opencpn_plugin_18::~opencpn_plugin_18(void)
4933 {}
4934
4935
RenderOverlay(wxDC & dc,PlugIn_ViewPort * vp)4936 bool opencpn_plugin_18::RenderOverlay(wxDC &dc, PlugIn_ViewPort *vp)
4937 {
4938 return false;
4939 }
4940
RenderGLOverlay(wxGLContext * pcontext,PlugIn_ViewPort * vp)4941 bool opencpn_plugin_18::RenderGLOverlay(wxGLContext *pcontext, PlugIn_ViewPort *vp)
4942 {
4943 return false;
4944 }
4945
SetPluginMessage(wxString & message_id,wxString & message_body)4946 void opencpn_plugin_18::SetPluginMessage(wxString &message_id, wxString &message_body)
4947 {}
4948
SetPositionFixEx(PlugIn_Position_Fix_Ex & pfix)4949 void opencpn_plugin_18::SetPositionFixEx(PlugIn_Position_Fix_Ex &pfix)
4950 {}
4951
4952
4953 // Opencpn_Plugin_19 Implementation
opencpn_plugin_19(void * pmgr)4954 opencpn_plugin_19::opencpn_plugin_19(void *pmgr)
4955 : opencpn_plugin_18(pmgr)
4956 {
4957 }
4958
~opencpn_plugin_19(void)4959 opencpn_plugin_19::~opencpn_plugin_19(void)
4960 {
4961 }
4962
OnSetupOptions(void)4963 void opencpn_plugin_19::OnSetupOptions(void)
4964 {
4965 }
4966
4967 // Opencpn_Plugin_110 Implementation
opencpn_plugin_110(void * pmgr)4968 opencpn_plugin_110::opencpn_plugin_110(void *pmgr)
4969 : opencpn_plugin_19(pmgr)
4970 {
4971 }
4972
~opencpn_plugin_110(void)4973 opencpn_plugin_110::~opencpn_plugin_110(void)
4974 {
4975 }
4976
LateInit(void)4977 void opencpn_plugin_110::LateInit(void)
4978 {
4979 }
4980
4981 // Opencpn_Plugin_111 Implementation
opencpn_plugin_111(void * pmgr)4982 opencpn_plugin_111::opencpn_plugin_111(void *pmgr)
4983 : opencpn_plugin_110(pmgr)
4984 {
4985 }
4986
~opencpn_plugin_111(void)4987 opencpn_plugin_111::~opencpn_plugin_111(void)
4988 {
4989 }
4990
4991
4992 // Opencpn_Plugin_112 Implementation
opencpn_plugin_112(void * pmgr)4993 opencpn_plugin_112::opencpn_plugin_112(void *pmgr)
4994 : opencpn_plugin_111(pmgr)
4995 {
4996 }
4997
~opencpn_plugin_112(void)4998 opencpn_plugin_112::~opencpn_plugin_112(void)
4999 {
5000 }
5001
MouseEventHook(wxMouseEvent & event)5002 bool opencpn_plugin_112::MouseEventHook( wxMouseEvent &event )
5003 {
5004 return false;
5005 }
5006
SendVectorChartObjectInfo(wxString & chart,wxString & feature,wxString & objname,double lat,double lon,double scale,int nativescale)5007 void opencpn_plugin_112::SendVectorChartObjectInfo(wxString &chart, wxString &feature, wxString &objname, double lat, double lon, double scale, int nativescale)
5008 {
5009 }
5010
5011 // Opencpn_Plugin_113 Implementation
opencpn_plugin_113(void * pmgr)5012 opencpn_plugin_113::opencpn_plugin_113(void *pmgr)
5013 : opencpn_plugin_112(pmgr)
5014 {
5015 }
5016
~opencpn_plugin_113(void)5017 opencpn_plugin_113::~opencpn_plugin_113(void)
5018 {
5019 }
5020
KeyboardEventHook(wxKeyEvent & event)5021 bool opencpn_plugin_113::KeyboardEventHook( wxKeyEvent &event )
5022 {
5023 return false;
5024 }
5025
OnToolbarToolDownCallback(int id)5026 void opencpn_plugin_113::OnToolbarToolDownCallback(int id) {}
OnToolbarToolUpCallback(int id)5027 void opencpn_plugin_113::OnToolbarToolUpCallback(int id) {}
5028
5029
5030 // Opencpn_Plugin_114 Implementation
opencpn_plugin_114(void * pmgr)5031 opencpn_plugin_114::opencpn_plugin_114(void *pmgr)
5032 : opencpn_plugin_113(pmgr)
5033 {
5034 }
5035
~opencpn_plugin_114(void)5036 opencpn_plugin_114::~opencpn_plugin_114(void)
5037 {
5038 }
5039
5040 // Opencpn_Plugin_115 Implementation
opencpn_plugin_115(void * pmgr)5041 opencpn_plugin_115::opencpn_plugin_115(void *pmgr)
5042 : opencpn_plugin_114(pmgr)
5043 {
5044 }
5045
~opencpn_plugin_115(void)5046 opencpn_plugin_115::~opencpn_plugin_115(void)
5047 {
5048 }
5049
5050 // Opencpn_Plugin_116 Implementation
opencpn_plugin_116(void * pmgr)5051 opencpn_plugin_116::opencpn_plugin_116(void *pmgr)
5052 : opencpn_plugin_115(pmgr)
5053 {
5054 }
5055
~opencpn_plugin_116(void)5056 opencpn_plugin_116::~opencpn_plugin_116(void)
5057 {
5058 }
5059
RenderGLOverlayMultiCanvas(wxGLContext * pcontext,PlugIn_ViewPort * vp,int max_canvas)5060 bool opencpn_plugin_116::RenderGLOverlayMultiCanvas(wxGLContext *pcontext, PlugIn_ViewPort *vp, int max_canvas)
5061 {
5062 return false;
5063 }
5064
RenderOverlayMultiCanvas(wxDC & dc,PlugIn_ViewPort * vp,int max_canvas)5065 bool opencpn_plugin_116::RenderOverlayMultiCanvas(wxDC &dc, PlugIn_ViewPort *vp, int max_canvas)
5066 {
5067 return false;
5068 }
5069
PrepareContextMenu(int canvasIndex)5070 void opencpn_plugin_116::PrepareContextMenu( int canvasIndex)
5071 {
5072 return;
5073 }
5074
5075 // Opencpn_Plugin_117 Implementation
opencpn_plugin_117(void * pmgr)5076 opencpn_plugin_117::opencpn_plugin_117(void *pmgr)
5077 :opencpn_plugin_116(pmgr)
5078 {}
5079
GetPlugInVersionPatch()5080 int opencpn_plugin_117::GetPlugInVersionPatch() { return 0; };
5081
GetPlugInVersionPost()5082 int opencpn_plugin_117::GetPlugInVersionPost() { return 0; };
5083
GetPlugInVersionPre()5084 const char* opencpn_plugin_117::GetPlugInVersionPre() { return ""; };
5085
GetPlugInVersionBuild()5086 const char* opencpn_plugin_117::GetPlugInVersionBuild() { return ""; };
5087
SetActiveLegInfo(Plugin_Active_Leg_Info & leg_info)5088 void opencpn_plugin_117::SetActiveLegInfo(Plugin_Active_Leg_Info &leg_info)
5089 {}
5090
5091
5092 // Helper and interface classes
5093
5094 //-------------------------------------------------------------------------------
5095 // PlugIn_AIS_Target Implementation
5096 //-------------------------------------------------------------------------------
5097
Create_PI_AIS_Target(AIS_Target_Data * ptarget)5098 PlugIn_AIS_Target *Create_PI_AIS_Target(AIS_Target_Data *ptarget)
5099 {
5100 PlugIn_AIS_Target *pret = new PlugIn_AIS_Target;
5101
5102 pret->MMSI = ptarget->MMSI;
5103 pret->Class = ptarget->Class;
5104 pret->NavStatus = ptarget->NavStatus;
5105 pret->SOG = ptarget->SOG;
5106 pret->COG = ptarget->COG;
5107 pret->HDG = ptarget->HDG;
5108 pret->Lon = ptarget->Lon;
5109 pret->Lat = ptarget->Lat;
5110 pret->ROTAIS = ptarget->ROTAIS;
5111 pret->ShipType = ptarget->ShipType;
5112 pret->IMO = ptarget->IMO;
5113
5114 pret->Range_NM = ptarget->Range_NM;
5115 pret->Brg = ptarget->Brg;
5116
5117 // Per target collision parameters
5118 pret->bCPA_Valid = ptarget->bCPA_Valid;
5119 pret->TCPA = ptarget->TCPA; // Minutes
5120 pret->CPA = ptarget->CPA; // Nautical Miles
5121
5122 pret->alarm_state = (plugin_ais_alarm_type)ptarget->n_alert_state;
5123
5124 memcpy(pret->CallSign, ptarget->CallSign, CALL_SIGN_LEN);
5125 memcpy(pret->ShipName, ptarget->ShipName, SHIP_NAME_LEN);
5126
5127 return pret;
5128 }
5129
5130 //-------------------------------------------------------------------------------
5131 // PluginListPanel & PluginPanel Implementation
5132 //-------------------------------------------------------------------------------
5133
LoadSVGIcon(wxFileName path,int size,wxBitmap & bitmap)5134 static void LoadSVGIcon(wxFileName path, int size, wxBitmap& bitmap)
5135 {
5136 wxImage img = LoadSVGIcon(path.GetFullPath(), size, size);
5137 if (img.IsOk()) {
5138 bitmap = wxBitmap(img);
5139 }
5140 }
5141
5142
5143 /*
5144 * Panel with buttons to control plugin catalog management.
5145 */
CatalogMgrPanel(wxWindow * parent)5146 CatalogMgrPanel::CatalogMgrPanel(wxWindow* parent)
5147 :wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize),
5148 m_parent(parent)
5149 {
5150 wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
5151 SetSizer( topSizer );
5152
5153 topSizer->Add( new wxStaticLine(this), 0, wxGROW|wxLEFT|wxRIGHT, 4);
5154
5155 wxStaticBox* itemStaticBoxSizer4Static = new wxStaticBox( this, wxID_ANY, _("Plugin Catalog") );
5156 wxStaticBoxSizer* itemStaticBoxSizer4 = new wxStaticBoxSizer( itemStaticBoxSizer4Static, wxVERTICAL );
5157 topSizer->Add( itemStaticBoxSizer4, 1, wxEXPAND | wxALL, 2 );
5158 #ifndef __OCPN__ANDROID__
5159 // First line
5160 m_catalogText = new wxStaticText( this, wxID_STATIC, _T(""));
5161 itemStaticBoxSizer4->Add( m_catalogText, 1, wxALIGN_LEFT );
5162 m_catalogText->SetLabel(GetCatalogText(false));
5163
5164 // Next line
5165 wxBoxSizer* rowSizer2 = new wxBoxSizer( wxHORIZONTAL );
5166 itemStaticBoxSizer4->Add( rowSizer2, 1, wxEXPAND | wxALL, 1 );
5167
5168 m_updateButton = new wxButton( this, wxID_ANY, _("Update Plugin Catalog"), wxDefaultPosition, wxDefaultSize, 0 );
5169 rowSizer2->Add( m_updateButton, 0, wxALIGN_LEFT );
5170 m_updateButton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnUpdateButton, this);
5171
5172 rowSizer2->AddSpacer( 4 * GetCharWidth() );
5173
5174 wxStaticText *tchannels = new wxStaticText( this, wxID_STATIC, _("Choose Remote Catalog"));
5175 rowSizer2->Add( tchannels, 0, wxALIGN_RIGHT | wxALL, 5 );
5176
5177 wxArrayString channels;
5178 channels.Add(_T( "Master" ));
5179 channels.Add(_T( "Beta" ));
5180 pConfig->SetPath( _T("/PlugIns/") );
5181 wxString expert = pConfig->Read( "CatalogExpert", "0");
5182 if(expert.IsSameAs(_T("1"))){
5183 channels.Add(_T( "Alpha" ));
5184 channels.Add(_T( "Custom..." ));
5185 }
5186
5187 m_choiceChannel = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, channels);
5188 rowSizer2->Add( m_choiceChannel, 0, wxALIGN_RIGHT );
5189 m_choiceChannel->Bind(wxEVT_CHOICE, &CatalogMgrPanel::OnChannelSelected, this);
5190 int selection = GetChannelIndex(&channels);
5191 if(!expert){
5192 if(selection > 1) selection = 0;
5193 }
5194 m_choiceChannel->SetSelection( selection );
5195
5196 m_tarballButton = new wxButton( this, wxID_ANY, _("Import plugin..."), wxDefaultPosition, wxDefaultSize, 0 );
5197 rowSizer2->Add( m_tarballButton, 0, wxALIGN_LEFT | wxLEFT, 2 * GetCharWidth() );
5198 m_tarballButton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnTarballButton, this);
5199
5200 SetUpdateButtonLabel();
5201
5202 // Next line
5203 wxBoxSizer* rowSizer3 = new wxBoxSizer( wxHORIZONTAL );
5204 itemStaticBoxSizer4->Add( rowSizer3, 0, wxEXPAND | wxALL, 4 );
5205
5206 m_customText = new wxStaticText( this, wxID_STATIC, _T("Custom url"));
5207 rowSizer3->Add( m_customText, 0, wxALIGN_LEFT | wxRIGHT, 2 * GetCharWidth() );
5208 m_tcCustomURL = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, 0 );
5209 rowSizer3->Add( m_tcCustomURL, 1, wxEXPAND );
5210
5211 if(m_choiceChannel->GetString(m_choiceChannel->GetSelection()).StartsWith(_T("Custom"))){
5212 m_tcCustomURL->Show();
5213 m_customText->Show();
5214 }
5215 else{
5216 m_tcCustomURL->Hide();
5217 m_customText->Hide();
5218 }
5219 #else
5220 SetBackgroundColour(wxColour(0x7c, 0xb0, 0xe9)); // light blue
5221 pConfig->SetPath( _T("/PlugIns/") );
5222 wxString expert = pConfig->Read( "CatalogExpert", "0");
5223
5224 // First line
5225 m_catalogText = new wxStaticText( this, wxID_STATIC, GetCatalogText(false));
5226 itemStaticBoxSizer4->Add( m_catalogText, 0, wxALIGN_LEFT );
5227 if(expert.IsSameAs(_T("0")))
5228 m_catalogText->Hide();
5229
5230 // Next line
5231 m_updateButton = new wxButton( this, wxID_ANY, _("Update Plugin Catalog:Master"), wxDefaultPosition, wxDefaultSize, 0 );
5232 itemStaticBoxSizer4->Add( m_updateButton, 1, wxALIGN_LEFT );
5233 m_updateButton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnUpdateButton, this);
5234
5235 // Next line
5236 wxBoxSizer* rowSizer2 = new wxBoxSizer( wxHORIZONTAL );
5237 itemStaticBoxSizer4->Add( rowSizer2, 1, wxEXPAND | wxALL, 1 );
5238
5239 wxStaticText *tchannels = new wxStaticText( this, wxID_STATIC, _("Choose Remote Catalog"));
5240 rowSizer2->Add( tchannels, 1, wxALIGN_RIGHT | wxALL, 5 );
5241 if(expert.IsSameAs(_T("0")))
5242 tchannels->Hide();
5243
5244 wxArrayString channels;
5245 channels.Add(_T( "Master" ));
5246 channels.Add(_T( "Beta" ));
5247 if(expert.IsSameAs(_T("1"))){
5248 channels.Add(_T( "Alpha" ));
5249 channels.Add(_T( "Custom..." ));
5250 }
5251
5252 m_choiceChannel = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, channels);
5253 rowSizer2->Add( m_choiceChannel, 1, wxALIGN_RIGHT );
5254 m_choiceChannel->Bind(wxEVT_CHOICE, &CatalogMgrPanel::OnChannelSelected, this);
5255 int selection = GetChannelIndex(&channels);
5256 if(!expert){
5257 if(selection > 1) selection = 0;
5258 }
5259 m_choiceChannel->SetSelection( selection );
5260 if(expert.IsSameAs(_T("0")))
5261 m_choiceChannel->Hide();
5262
5263 // Next line
5264 m_tarballButton = new wxButton( this, wxID_ANY, _("Import plugin..."), wxDefaultPosition, wxDefaultSize, 0 );
5265 itemStaticBoxSizer4->Add( m_tarballButton, 0, wxALIGN_LEFT );
5266 m_tarballButton->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnTarballButton, this);
5267 if(expert.IsSameAs(_T("0")))
5268 m_tarballButton->Hide();
5269
5270 // Next line
5271 wxBoxSizer* rowSizer3 = new wxBoxSizer( wxHORIZONTAL );
5272 itemStaticBoxSizer4->Add( rowSizer3, 0, wxEXPAND | wxALL, 4 );
5273
5274 m_customText = new wxStaticText( this, wxID_STATIC, _T("Custom url"));
5275 rowSizer3->Add( m_customText, 0, wxALIGN_LEFT | wxRIGHT, 2 * GetCharWidth() );
5276 m_tcCustomURL = new wxTextCtrl(this, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, 0 );
5277 rowSizer3->Add( m_tcCustomURL, 1, wxEXPAND );
5278
5279 if(m_choiceChannel->GetString(m_choiceChannel->GetSelection()).StartsWith(_T("Custom"))){
5280 m_tcCustomURL->Show();
5281 m_customText->Show();
5282 }
5283 else{
5284 m_tcCustomURL->Hide();
5285 m_customText->Hide();
5286 }
5287
5288 SetUpdateButtonLabel();
5289
5290 #endif
5291 SetMinSize(wxSize(m_parent->GetClientSize().x - (4 * GetCharWidth()), -1));
5292 Fit();
5293
5294 }
5295
~CatalogMgrPanel()5296 CatalogMgrPanel::~CatalogMgrPanel()
5297 {
5298 m_updateButton->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnUpdateButton, this);
5299 m_tarballButton->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &CatalogMgrPanel::OnTarballButton, this);
5300
5301 }
5302
5303 static const char* const DOWNLOAD_REPO_PROTO = "https://raw.githubusercontent.com/OpenCPN/plugins/@branch@/ocpn-plugins.xml";
5304
OnUpdateButton(wxCommandEvent & event)5305 void CatalogMgrPanel::OnUpdateButton( wxCommandEvent &event)
5306 {
5307 std::string url;
5308
5309 // Craft the url
5310 if(m_choiceChannel->GetString(m_choiceChannel->GetSelection()).StartsWith(_T("Custom")))
5311 url = m_tcCustomURL->GetValue();
5312 else{
5313 url = std::string(DOWNLOAD_REPO_PROTO);
5314 if(m_choiceChannel->GetSelection() == 0) // Master-->master
5315 ocpn::replace(url, "@branch@", m_choiceChannel->GetString(m_choiceChannel->GetSelection()).Lower().ToStdString());
5316 else
5317 ocpn::replace(url, "@branch@", m_choiceChannel->GetString(m_choiceChannel->GetSelection()).ToStdString());
5318 }
5319
5320 // Download to a temp file
5321 std::string filePath = wxFileName::CreateTempFileName("ocpn_dl").ToStdString();
5322
5323 auto catalogHdlr = CatalogHandler::getInstance();
5324
5325 g_Platform->ShowBusySpinner();
5326 auto status = catalogHdlr->DownloadCatalog( filePath, url);
5327 g_Platform->HideBusySpinner();
5328
5329 std::string message;
5330 if (status != CatalogHandler::ServerStatus::OK) {
5331 message = _("Cannot download data from url");
5332 OCPNMessageBox(this, message, _("OpenCPN Catalog update"), wxICON_ERROR);
5333 return;
5334 }
5335
5336 //TODO Validate xml using xsd here....
5337 #ifdef __OCPN__ANDROID__
5338 if(!AndroidSecureCopyFile (wxString(filePath.c_str()), g_Platform->GetPrivateDataDir() + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml"))){
5339 OCPNMessageBox(this, _("Unable to copy catalog file"), _("OpenCPN Catalog update"), wxICON_ERROR);
5340 return;
5341 }
5342 #else
5343 // Copy the downloaded file to proper local location
5344 if(!wxCopyFile (wxString(filePath.c_str()), g_Platform->GetPrivateDataDir() + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml"))){
5345 OCPNMessageBox(this, _("Unable to copy catalog file"), _("OpenCPN Catalog update"), wxICON_ERROR);
5346 return;
5347 }
5348 #endif
5349
5350 // If this is the "master" catalog, also copy to plugin cache
5351 if(m_choiceChannel->GetString(m_choiceChannel->GetSelection()).StartsWith(_T("Master"))){
5352 wxString metaCache = g_Platform->GetPrivateDataDir() + wxFileName::GetPathSeparator() + _T("plugins");
5353 if(!wxDirExists( metaCache ))
5354 wxMkdir( metaCache );
5355 metaCache += wxFileName::GetPathSeparator();
5356 metaCache += _T("cache");
5357 if(!wxDirExists( metaCache ))
5358 wxMkdir( metaCache );
5359 metaCache += wxFileName::GetPathSeparator();
5360 metaCache += _T("metadata");
5361 if(!wxDirExists( metaCache ))
5362 wxMkdir( metaCache );
5363
5364 #ifdef __OCPN__ANDROID__
5365 if(!AndroidSecureCopyFile (wxString(filePath.c_str()), metaCache + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml"))){
5366 OCPNMessageBox(this, _("Unable to copy catalog file to cache"), _("OpenCPN Catalog update"), wxICON_ERROR);
5367 return;
5368 }
5369 #else
5370 if(!wxCopyFile (wxString(filePath.c_str()), metaCache + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml"))){
5371 OCPNMessageBox(this, _("Unable to copy catalog file to cache"), _("OpenCPN Catalog update"), wxICON_ERROR);
5372 return;
5373 }
5374 #endif
5375 }
5376
5377 // Record in the config file the name of the catalog downloaded
5378 pConfig->SetPath( _T("/PlugIns/") );
5379 pConfig->Write( _T("LatestCatalogDownloaded"), m_choiceChannel->GetString(m_choiceChannel->GetSelection()) );
5380 pConfig->Flush();
5381
5382 // Reset the PluginHandler catalog file source.
5383 // This will case the Handler to find, load, and parse the just-downloaded catalog
5384 // as copied to g_Platform->GetPrivateDataDir()...
5385 auto pluginHandler = PluginHandler::getInstance();
5386 pluginHandler->setMetadata("");
5387
5388 // Reload all plugins, which will also update the status fields
5389 g_pi_manager->LoadAllPlugIns( false );
5390
5391 // Update this Panel, and the entire list.
5392 m_catalogText->SetLabel(GetCatalogText(true));
5393 if(m_PluginListPanel)
5394 m_PluginListPanel->ReloadPluginPanels(g_pi_manager->GetPlugInArray());
5395
5396 OCPNMessageBox(this, _("Catalog update successful"), _("OpenCPN Catalog update"), wxICON_INFORMATION | wxOK);
5397
5398 }
5399
parsePluginNode(pugi::xml_node & pluginRoot,PluginMetadata & plugin)5400 static bool parsePluginNode( pugi::xml_node &pluginRoot, PluginMetadata &plugin)
5401 {
5402 for (pugi::xml_node element = pluginRoot.first_child(); element; element = element.next_sibling()){
5403 if( !strcmp(element.name(), "name") ){
5404 plugin.name = element.first_child().value();
5405 }
5406 else if( !strcmp(element.name(), "version") ){
5407 plugin.version = element.first_child().value();
5408 }
5409 else if( !strcmp(element.name(), "release") ){
5410 plugin.release = element.first_child().value();
5411 }
5412 else if( !strcmp(element.name(), "summary") ){
5413 plugin.summary = element.first_child().value();
5414 }
5415 else if( !strcmp(element.name(), "api-version") ){
5416 plugin.api_version = element.first_child().value();
5417 }
5418 else if( !strcmp(element.name(), "open-source") ){
5419 plugin.openSource = element.first_child().value();
5420 }
5421 else if( !strcmp(element.name(), "author") ){
5422 plugin.author = element.first_child().value();
5423 }
5424 else if( !strcmp(element.name(), "source") ){
5425 plugin.source = element.first_child().value();
5426 }
5427 else if( !strcmp(element.name(), "info-url") ){
5428 plugin.info_url = element.first_child().value();
5429 }
5430 else if( !strcmp(element.name(), "description") ){
5431 plugin.description = element.first_child().value();
5432 }
5433 else if( !strcmp(element.name(), "target") ){
5434 plugin.target = element.first_child().value();
5435 }
5436 else if( !strcmp(element.name(), "target-version") ){
5437 plugin.target_version = element.first_child().value();
5438 }
5439 else if( !strcmp(element.name(), "target-arch") ){
5440 plugin.target_arch = element.first_child().value();
5441 }
5442 else if( !strcmp(element.name(), "tarball-url") ){
5443 plugin.tarball_url = element.first_child().value();
5444 }
5445 }
5446
5447 return true;
5448 }
5449
populatePluginNode(pugi::xml_node & pluginNode,PluginMetadata & workingMetadata)5450 static void populatePluginNode(pugi::xml_node &pluginNode, PluginMetadata &workingMetadata)
5451 {
5452 pugi::xml_node child;
5453
5454 child = pluginNode.append_child("name");
5455 child.append_child(pugi::node_pcdata).set_value(workingMetadata.name.c_str());
5456
5457 child = pluginNode.append_child("version");
5458 child.append_child(pugi::node_pcdata).set_value(workingMetadata.version.c_str());
5459
5460 child = pluginNode.append_child("release");
5461 child.append_child(pugi::node_pcdata).set_value(workingMetadata.release.c_str());
5462
5463 child = pluginNode.append_child("summary");
5464 child.append_child(pugi::node_pcdata).set_value(workingMetadata.summary.c_str());
5465
5466 child = pluginNode.append_child("api-version");
5467 child.append_child(pugi::node_pcdata).set_value(workingMetadata.api_version.c_str());
5468
5469 child = pluginNode.append_child("open-source");
5470 char b[2]; sprintf(b, "%1d", workingMetadata.openSource);
5471 child.append_child(pugi::node_pcdata).set_value(b);
5472
5473 child = pluginNode.append_child("author");
5474 child.append_child(pugi::node_pcdata).set_value(workingMetadata.author.c_str());
5475
5476 child = pluginNode.append_child("source");
5477 child.append_child(pugi::node_pcdata).set_value(workingMetadata.source.c_str());
5478
5479 child = pluginNode.append_child("info-url");
5480 child.append_child(pugi::node_pcdata).set_value(workingMetadata.info_url.c_str());
5481
5482 child = pluginNode.append_child("description");
5483 child.append_child(pugi::node_pcdata).set_value(workingMetadata.description.c_str());
5484
5485 child = pluginNode.append_child("target");
5486 child.append_child(pugi::node_pcdata).set_value(workingMetadata.target.c_str());
5487
5488 child = pluginNode.append_child("target-version");
5489 child.append_child(pugi::node_pcdata).set_value(workingMetadata.target_version.c_str());
5490
5491 child = pluginNode.append_child("target-arch");
5492 child.append_child(pugi::node_pcdata).set_value(workingMetadata.target_arch.c_str());
5493
5494 child = pluginNode.append_child("tarball-url");
5495 child.append_child(pugi::node_pcdata).set_value(workingMetadata.tarball_url.c_str());
5496
5497 }
5498
5499
OnTarballButton(wxCommandEvent & event)5500 void CatalogMgrPanel::OnTarballButton( wxCommandEvent &event)
5501 {
5502 // Present a file selector dialog to get the file name..
5503 wxString tarballPath;
5504 int response = g_Platform->DoFileSelectorDialog( this, &tarballPath, _( "Select tarball file" ),
5505 g_Platform->GetPrivateDataDir(), wxEmptyString, wxT ( "*.tar.gz" ));
5506
5507 if( response == wxID_OK )
5508 {
5509 // Traverse the tarball to find the required "metadata.xml file
5510
5511 // Store the metadata file in temp location
5512 wxString tmpMetadata = wxFileName::CreateTempFileName("meta");
5513
5514 struct archive* src = archive_read_new();
5515 archive_read_support_filter_gzip(src);
5516 archive_read_support_format_tar(src);
5517 int r = archive_read_open_filename(src, tarballPath.ToStdString().c_str(), 10240);
5518 if (r != ARCHIVE_OK) {
5519 std::ostringstream os;
5520 //os << "Cannot read installation tarball: " << path;
5521 wxLogWarning(os.str().c_str());
5522 //last_error_msg = os.str();
5523 return;
5524 }
5525
5526 struct archive* dest = archive_write_disk_new();
5527 archive_write_disk_set_options(dest, ARCHIVE_EXTRACT_TIME);
5528
5529 bool bFoundMetadata = false;
5530 struct archive_entry* entry = 0;
5531 while (true) {
5532 int r = archive_read_next_header(src, &entry);
5533 if (r == ARCHIVE_EOF) {
5534 break;
5535 }
5536 if(r < ARCHIVE_OK){
5537 break;
5538 }
5539
5540 // Find the file "metadata.xml"
5541 std::string path = archive_entry_pathname(entry);
5542 if(std::string::npos != path.find("metadata.xml")){
5543 bFoundMetadata = true;
5544 archive_entry_set_pathname(entry, tmpMetadata.mb_str());
5545
5546
5547 if (r >= ARCHIVE_OK && archive_entry_size(entry) > 0) {
5548 const void* buff;
5549 size_t size;
5550 la_int64_t offset;
5551
5552 r = archive_write_header(dest, entry);
5553 if( r < ARCHIVE_OK){
5554 break;
5555 }
5556
5557 while (true) {
5558 r = archive_read_data_block(src, &buff, &size, &offset);
5559 if (r == ARCHIVE_EOF){
5560 break;
5561 }
5562 if (r < ARCHIVE_OK){
5563 break;
5564 }
5565 r = archive_write_data_block(dest, buff, size, offset);
5566 if (r < ARCHIVE_OK) {
5567 wxLogWarning("Error copying install data: %s",
5568 archive_error_string(dest));
5569
5570 break;
5571 }
5572 }
5573 if (r < ARCHIVE_OK){
5574 break;
5575 }
5576
5577 r = archive_write_finish_entry(dest);
5578 if( r < ARCHIVE_OK){
5579 break;
5580 }
5581 }
5582 }
5583 else{
5584 continue;
5585 }
5586
5587 }
5588 archive_read_free(src);
5589 archive_write_free(dest);
5590
5591
5592 // Any tarball extraction problem?
5593 if( r < ARCHIVE_OK ){
5594 OCPNMessageBox(this,_("Error extracting import plugin tarball."), _("OpenCPN Plugin Import Error"));
5595 return;
5596 }
5597
5598 // Found the metadata?
5599 if(!bFoundMetadata){
5600 OCPNMessageBox(this,_("Error, import plugin tarball does not contain required metadata."), _("OpenCPN Plugin Import Error"));
5601 return;
5602 }
5603
5604 // Parse the import metadata
5605 PluginMetadata importPlugin;
5606
5607 pugi::xml_document doc;
5608 bool ret = doc.load_file( tmpMetadata.mb_str() );
5609 if( ret ){
5610 pugi::xml_node pluginRoot = doc.first_child();
5611
5612 if(!parsePluginNode( pluginRoot, importPlugin)){
5613 OCPNMessageBox(this,_("Error processing import plugin metadata."), _("OpenCPN Plugin Import Error"));
5614 return;
5615 }
5616 }
5617
5618 // TODO Validate the metadata, in some simplistic way...
5619 if (!PluginHandler::isCompatible(importPlugin)) {
5620 OCPNMessageBox(this,_("Incompatible import plugin detected."), _("OpenCPN Plugin Import Error"));
5621 return;
5622 }
5623
5624 // Load and parse a working copy of the currently active catalog...
5625 std::vector<PluginMetadata> pluginArray;
5626
5627 pugi::xml_document catalog;
5628 wxString currentCatalog = g_Platform->GetPrivateDataDir() + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml");
5629 ret = catalog.load_file( currentCatalog.mb_str() );
5630 if( !ret ){
5631 OCPNMessageBox(this,_("Cannot access current catalog."), _("OpenCPN Plugin Import Error"));
5632 return;
5633 }
5634
5635 pugi::xml_node catalogRoot = catalog.first_child();
5636 for (pugi::xml_node element = catalogRoot.first_child(); element; element = element.next_sibling()){
5637 if( !strcmp(element.name(), "plugin") ){
5638 PluginMetadata catalogPlugin;
5639 parsePluginNode( element, catalogPlugin);
5640 pluginArray.push_back( catalogPlugin );
5641 }
5642 }
5643
5644 // Merge the import plugin metadata with the current catalog
5645 // By merge, we mean this:
5646 // 1. If the import metadata does not exist in the catalog, append it
5647 // 2. If the import metadata does exist (name, target, and target-version match), then..
5648 // update the catalog version with the import version
5649 bool bmerge = false;
5650 for(size_t i=0 ; i < pluginArray.size(); i++){
5651 PluginMetadata candidate = pluginArray[i];
5652 if( importPlugin.name == candidate.name){
5653 if(importPlugin.target == candidate.target){
5654 if(importPlugin.target_version == candidate.target_version){
5655 bmerge = true;
5656 pluginArray[i].version = importPlugin.version;
5657 pluginArray[i].release = importPlugin.release;
5658 pluginArray[i].summary = importPlugin.summary;
5659 pluginArray[i].description = importPlugin.description;
5660 pluginArray[i].tarball_url = importPlugin.tarball_url;
5661 break;
5662 }
5663 }
5664 }
5665 }
5666 // If there was no exact merge, then simply add the importPlugin metadata (case 1)
5667 if(!bmerge)
5668 pluginArray.push_back( importPlugin );
5669
5670 // Write out the newly merged catalog, replacing the currently active catalog
5671 pugi::xml_document newCatalog;
5672 pugi::xml_node pluginsNode = newCatalog.append_child("plugins");
5673
5674 pugi::xml_node childT = pluginsNode.append_child("version");
5675 childT.append_child(pugi::node_pcdata).set_value("0.0.0");
5676 childT = pluginsNode.append_child("date");
5677 wxDateTime now = wxDateTime::GetTimeNow();
5678 wxString timeFormat = now.FormatISOCombined(' ');
5679 childT.append_child(pugi::node_pcdata).set_value(timeFormat.mb_str());
5680
5681 for(size_t i=0 ; i < pluginArray.size(); i++){
5682 PluginMetadata workingMetadata = pluginArray[i];
5683
5684 pugi::xml_node pluginNode = pluginsNode.append_child("plugin");
5685 pugi::xml_attribute version = pluginNode.append_attribute( "version" );
5686 version.set_value( "1" );
5687
5688 populatePluginNode(pluginNode, workingMetadata);
5689 }
5690
5691 wxString catalogName = g_Platform->GetPrivateDataDir() + wxFileName::GetPathSeparator() + _T("ocpn-plugins.xml");
5692 newCatalog.save_file( catalogName.mb_str(), " ");
5693
5694 // Copy the metadata to the tarball cache
5695 wxString sep = wxFileName::GetPathSeparator();
5696 wxString cacheDir = g_Platform->GetPrivateDataDir() + sep + _T("plugins");
5697 if( !wxDirExists(cacheDir) )
5698 wxMkdir( cacheDir);
5699 cacheDir += sep + wxString(_T("cache"));
5700 if( !wxDirExists(cacheDir) )
5701 wxMkdir( cacheDir);
5702 cacheDir += sep + wxString(_T("tarballs"));
5703 if( !wxDirExists(cacheDir) )
5704 wxMkdir( cacheDir);
5705
5706 wxFileName fn(tarballPath);
5707 wxString destination = cacheDir + sep + fn.GetFullName();
5708 if(wxFileExists(wxString( tarballPath.c_str()))){
5709 wxLogMessage("Copying %s to local cache", tarballPath.ToStdString().c_str());
5710 #ifdef __OCPN__ANDROID__
5711 AndroidSecureCopyFile (tarballPath, destination);
5712 #else
5713 wxCopyFile( tarballPath, destination);
5714 #endif
5715 }
5716
5717 // Ready to load an process the merged catalog...
5718
5719 // Reset the PluginHandler catalog file source.
5720 // This will cause the Handler to find, load, and parse the just-merged catalog
5721 // as copied to g_Platform->GetPrivateDataDir()...
5722 auto pluginHandler = PluginHandler::getInstance();
5723 pluginHandler->setMetadata("");
5724
5725 // Reload all plugins, which will also update the status fields
5726 g_pi_manager->LoadAllPlugIns( false );
5727
5728 // Update this Panel, and the entire list.
5729 if(m_PluginListPanel)
5730 m_PluginListPanel->ReloadPluginPanels(g_pi_manager->GetPlugInArray());
5731
5732
5733
5734 // Success!
5735 wxString msg = _("Plugin imported successfully");
5736 msg += _T("\n");
5737 msg += _("Active catalog updated.");
5738 msg += _T("\n");
5739 msg += _("Plugin may be installed or updated now.");
5740 OCPNMessageBox(this, msg, _("OpenCPN Plugin Import Successful"));
5741
5742
5743 }
5744 }
5745
5746
GetCatalogText(bool updated)5747 wxString CatalogMgrPanel::GetCatalogText(bool updated)
5748 {
5749 wxString catalog;
5750 catalog = updated ? _("Active Catalog") : _("Last Catalog");
5751 catalog += _T(": ");
5752
5753 // Check the config file to learn what was the last catalog downloaded.
5754 pConfig->SetPath( _T("/PlugIns/") );
5755 wxString latestCatalog = pConfig->Read( _T("LatestCatalogDownloaded"), _T("default") );
5756 catalog += latestCatalog;
5757
5758 // Get the version from the currently active catalog, by which we mean
5759 // the latest catalog parsed.
5760 auto pluginHandler = PluginHandler::getInstance();
5761 std::string version = pluginHandler->GetCatalogData()->version;
5762
5763 catalog += _T(" ");
5764 catalog += _("Version");
5765 catalog += _T(" ");
5766 catalog += wxString(version.c_str());
5767 if (!updated) catalog += _T(" : ") + _("Please Update Plugin Catalog.");
5768
5769 return catalog;
5770 }
5771
OnChannelSelected(wxCommandEvent & event)5772 void CatalogMgrPanel::OnChannelSelected(wxCommandEvent &event)
5773 {
5774 SetUpdateButtonLabel();
5775 if(m_choiceChannel->GetString(m_choiceChannel->GetSelection()).StartsWith(_T("Custom"))){
5776 m_tcCustomURL->Show();
5777 m_customText->Show();
5778 }
5779 else{
5780 m_tcCustomURL->Hide();
5781 m_customText->Hide();
5782 }
5783
5784 Layout();
5785 Fit();
5786 g_options->itemBoxSizerPanelPlugins->Layout();
5787
5788
5789 }
5790
GetChannelIndex(const wxArrayString * channels)5791 unsigned int CatalogMgrPanel::GetChannelIndex(const wxArrayString* channels)
5792 {
5793 wxString current =
5794 pConfig->Read( "LatestCatalogDownloaded", "default");
5795 int ix = channels->Index(current);
5796 return ix == -1 ? 0 : ix;
5797 }
5798
SetUpdateButtonLabel()5799 void CatalogMgrPanel::SetUpdateButtonLabel()
5800 {
5801 wxString label = _("Update Plugin Catalog");
5802 label += _T(": ");
5803 label += m_choiceChannel->GetString(m_choiceChannel->GetSelection());
5804 m_updateButton->SetLabel(label);
5805 Layout();
5806 }
5807
5808
5809
BEGIN_EVENT_TABLE(PluginListPanel,wxScrolledWindow)5810 BEGIN_EVENT_TABLE( PluginListPanel, wxScrolledWindow )
5811 //EVT_BUTTON( ID_CMD_BUTTON_PERFORM_ACTION, PluginListPanel::OnPluginPanelAction )
5812 END_EVENT_TABLE()
5813
5814 PluginListPanel::PluginListPanel(wxWindow *parent, wxWindowID id,
5815 const wxPoint &pos, const wxSize &size,
5816 ArrayOfPlugIns *pPluginArray )
5817 :wxScrolledWindow( parent, id, pos, size, wxTAB_TRAVERSAL|wxVSCROLL ),
5818 m_PluginSelected(0)
5819 {
5820 SetSizer(new wxBoxSizer(wxVERTICAL));
5821 m_panel = 0;
5822 ReloadPluginPanels(pPluginArray);
5823 //SetScrollRate(0, 1);
5824 }
5825
SelectByName(wxString & name)5826 void PluginListPanel::SelectByName(wxString &name)
5827 {
5828 for (auto it = GetChildren().GetFirst(); it; it = it->GetNext()) {
5829 auto pluginPanel = dynamic_cast<PluginPanel*>(it->GetData());
5830 if(pluginPanel){
5831 if(pluginPanel->GetPluginPtr()->m_common_name.IsSameAs(name)){
5832 pluginPanel->SetSelected(true);
5833 pluginPanel->Layout();
5834 SelectPlugin(pluginPanel);
5835 break;
5836 }
5837 }
5838 }
5839 }
5840
ReloadPluginPanels(ArrayOfPlugIns * plugins)5841 void PluginListPanel::ReloadPluginPanels(ArrayOfPlugIns* plugins)
5842 {
5843 m_pPluginArray = plugins;
5844 delete m_panel;
5845 m_PluginItems.Clear();
5846
5847 m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
5848 m_pitemBoxSizer01 = new wxBoxSizer(wxVERTICAL);
5849 m_panel->SetSizer(m_pitemBoxSizer01);
5850
5851 GetSizer()->Add(m_panel, wxSizerFlags().Expand());
5852
5853 m_panel->Hide();
5854 m_PluginSelected = 0;
5855 for (size_t i = m_pPluginArray->GetCount(); i > 0; i -= 1) {
5856 PlugInContainer* pic = m_pPluginArray->Item(i - 1);
5857 AddPlugin(pic);
5858 }
5859 m_panel->Show();
5860 Layout();
5861 Refresh(true);
5862
5863 Scroll(0,0);
5864 }
5865
5866
AddPlugin(PlugInContainer * pic)5867 void PluginListPanel::AddPlugin(PlugInContainer* pic)
5868 {
5869 auto pPluginPanel = new PluginPanel(m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, pic);
5870 pPluginPanel->SetSelected(false);
5871 m_pitemBoxSizer01->Add( pPluginPanel, wxSizerFlags().Expand());
5872 m_PluginItems.Add( pPluginPanel );
5873
5874 m_pluginSpacer = g_Platform->GetDisplayDPmm() * 1.0;
5875 m_pitemBoxSizer01->AddSpacer(m_pluginSpacer);
5876
5877 // wxStaticLine* itemStaticLine = new wxStaticLine( m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
5878 // m_pitemBoxSizer01->Add( itemStaticLine, wxSizerFlags().Expand());
5879 }
5880
5881 // When a child Panel is selected, its size grows to include "Preferences"
5882 // and Enable" buttons. As a consequence, the vertical size of the
5883 // ListPanel grows as well.Calculate and add a spacer to bottom of
5884 // ListPanel so that initial ListPanel minimum size calculations account
5885 // for selected Panel size growth. Sadly, this does not work right on wxQt.
5886 // So, just punt for now...
ComputePluginSpace(ArrayOfPluginPanel plugins,wxBoxSizer * sizer)5887 int PluginListPanel::ComputePluginSpace(ArrayOfPluginPanel plugins, wxBoxSizer* sizer)
5888 {
5889 int max_dy = 0;
5890 for (size_t i = 0; i < plugins.GetCount(); i++) {
5891 auto panel = plugins.Item(i);
5892 bool was_selected = panel->GetSelected();
5893 panel->SetSelected(false);
5894 sizer->Layout();
5895 wxSize unselected = panel->GetSize();
5896
5897 panel->SetSelected(true); // switch to selected, a bit bigger
5898 sizer->Layout();
5899 wxSize selected = panel->GetSize();
5900
5901 int dy = selected.GetHeight() - unselected.GetHeight();
5902 max_dy = wxMax(max_dy, dy);
5903 panel->SetSelected(was_selected);
5904 }
5905 return max_dy;
5906 }
5907
UpdatePluginsOrder()5908 void PluginListPanel::UpdatePluginsOrder()
5909 {
5910 m_pPluginArray->Clear();
5911 for( unsigned int i = 0 ; i < m_PluginItems.GetCount() ; i++ )
5912 {
5913 m_pPluginArray->Insert(m_PluginItems[i]->GetPluginPtr(), 0);
5914 }
5915 }
5916
5917
~PluginListPanel()5918 PluginListPanel::~PluginListPanel()
5919 {
5920 }
5921
UpdateSelections()5922 void PluginListPanel::UpdateSelections()
5923 {
5924 for(unsigned int i=0 ; i < m_PluginItems.GetCount() ; i++) {
5925 PluginPanel *pPluginPanel = m_PluginItems[i];
5926 if( pPluginPanel ){
5927 pPluginPanel->SetSelected( pPluginPanel->GetSelected() );
5928 }
5929 }
5930 }
5931
SelectPlugin(PluginPanel * pi)5932 void PluginListPanel::SelectPlugin( PluginPanel *pi )
5933 {
5934 int xs, ys;
5935 GetViewStart(&xs, &ys);
5936 Scroll(0,0);
5937
5938 if (m_PluginSelected){
5939 m_PluginSelected->SetSelected(false);
5940 m_PluginSelected->Layout();
5941 }
5942
5943 if (pi == NULL)
5944 m_PluginSelected->SetSelected(false);
5945
5946 m_PluginSelected = pi;
5947
5948 m_pitemBoxSizer01->Layout();
5949 Refresh(false);
5950 wxSize size = GetBestVirtualSize();
5951 SetVirtualSize( size );
5952
5953 // Measure, and ensure that the selected item is fully visible in the vertical scroll box.
5954 int htop = 0;
5955 for(unsigned int i=0 ; i < m_PluginItems.GetCount() ; i++) {
5956 PluginPanel *pPluginPanel = m_PluginItems[i];
5957 int yd = pPluginPanel->GetSize().y;
5958 htop += yd;
5959 htop += m_pluginSpacer;
5960 if(pPluginPanel == pi){
5961 int piBottom = htop - (ys*g_options->GetScrollRate());
5962 if(piBottom > GetClientSize().y){
5963 ys += (piBottom - GetClientSize().y)/g_options->GetScrollRate();
5964 }
5965 break;
5966 }
5967 }
5968
5969 Scroll(xs, ys);
5970 }
5971
MoveUp(PluginPanel * pi)5972 void PluginListPanel::MoveUp( PluginPanel *pi )
5973 {
5974 int pos = m_PluginItems.Index( pi );
5975 if( pos == 0 ) //The first one can't be moved further up
5976 return;
5977 m_PluginItems.RemoveAt(pos);
5978 m_pitemBoxSizer01->Remove( pos * 2 + 1 );
5979 m_pitemBoxSizer01->Remove( pos * 2 );
5980 m_PluginItems.Insert( pi, pos - 1 );
5981 wxStaticLine* itemStaticLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
5982 m_pitemBoxSizer01->Insert( (pos - 1) * 2, itemStaticLine, 0, wxEXPAND|wxALL, 0 );
5983 m_pitemBoxSizer01->Insert( (pos - 1) * 2, pi, 0, wxEXPAND|wxALL, 0 );
5984
5985 m_PluginSelected = pi;
5986
5987 GetSizer()->Layout();
5988 m_parent->Layout();
5989 Refresh(true);
5990 }
5991
MoveDown(PluginPanel * pi)5992 void PluginListPanel::MoveDown( PluginPanel *pi )
5993 {
5994 int pos = m_PluginItems.Index( pi );
5995 if( pos == (int)m_PluginItems.Count() - 1 ) //The last one can't be moved further down
5996 return;
5997 m_PluginItems.RemoveAt(pos);
5998 m_pitemBoxSizer01->Remove( pos * 2 + 1 );
5999 m_pitemBoxSizer01->Remove( pos * 2 );
6000 m_PluginItems.Insert( pi, pos + 1 );
6001 wxStaticLine* itemStaticLine = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
6002 m_pitemBoxSizer01->Insert( (pos + 1) * 2 - 1, itemStaticLine, 0, wxEXPAND|wxALL, 0 );
6003 m_pitemBoxSizer01->Insert( (pos + 1) * 2, pi, 0, wxEXPAND|wxALL, 0 );
6004
6005 m_PluginSelected = pi;
6006
6007 GetSizer()->Layout();
6008 m_parent->Layout();
6009 Refresh(false);
6010 }
6011
6012
canUninstall(std::string name)6013 static bool canUninstall(std::string name)
6014 {
6015 PluginHandler* pluginHandler = PluginHandler::getInstance();
6016 //std::transform(name.begin(), name.end(), name.begin(), ::tolower);
6017
6018 for (auto plugin: pluginHandler->getInstalled()) {
6019 if (plugin.name == name) {
6020 return !plugin.readonly;
6021 }
6022 }
6023 return false;
6024 }
6025
BEGIN_EVENT_TABLE(PluginPanel,wxPanel)6026 BEGIN_EVENT_TABLE( PluginPanel, wxPanel )
6027 EVT_PAINT ( PluginPanel::OnPaint )
6028 END_EVENT_TABLE()
6029
6030 PluginPanel::PluginPanel(wxPanel *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, PlugInContainer *p_plugin)
6031 :wxPanel(parent, id, pos, size, wxBORDER_NONE)
6032 {
6033 m_PluginListPanel = (PluginListPanel *)parent->GetParent();
6034 m_PluginListPanel = dynamic_cast<PluginListPanel*>(parent->GetParent());
6035 wxASSERT(m_PluginListPanel != 0);
6036
6037 m_pPlugin = p_plugin;
6038 m_bSelected = false;
6039 m_penWidthUnselected = g_Platform->GetDisplayDPmm() * .25;
6040 m_penWidthSelected = g_Platform->GetDisplayDPmm() * .5;
6041
6042 wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
6043 SetSizer(topSizer);
6044
6045 wxBoxSizer* itemBoxSizer01 = new wxBoxSizer(wxHORIZONTAL);
6046 topSizer->Add(itemBoxSizer01, 0, wxEXPAND);
6047 Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6048 Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6049
6050 double iconSize = GetCharWidth() * 4;
6051 wxImage plugin_icon;
6052 ocpnStyle::Style *style = g_StyleManager->GetCurrentStyle();
6053 if (m_pPlugin->m_bitmap) {
6054 plugin_icon = m_pPlugin->m_bitmap->ConvertToImage();
6055 }
6056 wxBitmap bitmap;
6057 if (plugin_icon.IsOk()) {
6058 int nowSize = plugin_icon.GetWidth();
6059 if( (nowSize > iconSize) || ((iconSize / nowSize) > 1.5) )
6060 plugin_icon.Rescale( iconSize, iconSize, wxIMAGE_QUALITY_HIGH);
6061 bitmap = wxBitmap(plugin_icon);
6062 }
6063 else if (m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstallAvailable)
6064 {
6065 wxFileName path(g_Platform->GetSharedDataDir(), "packageBox.svg");
6066 path.AppendDir("uidata");
6067 path.AppendDir("traditional");
6068 wxImage img = LoadSVGIcon(path.GetFullPath(), iconSize, iconSize);
6069 bitmap = wxBitmap(img);
6070 }
6071 else {
6072 bitmap = wxBitmap(style->GetIcon( _T("default_pi"), iconSize, iconSize));
6073 }
6074 m_itemStaticBitmap = new wxStaticBitmap(this, wxID_ANY, bitmap);
6075
6076 itemBoxSizer01->Add(m_itemStaticBitmap, 0, wxEXPAND|wxALL, 10);
6077 m_itemStaticBitmap->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6078 m_itemStaticBitmap->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6079
6080 wxBoxSizer* itemBoxSizer02 = new wxBoxSizer(wxVERTICAL);
6081 itemBoxSizer01->Add(itemBoxSizer02, 1, wxEXPAND|wxALL, 0);
6082
6083 // Calculate character width available
6084 int nChars = g_options->GetSize().x / GetCharWidth();
6085 bool bCompact = false;
6086 if(nChars < 60) // Arbitrary, detecting mobile devices in portrait mode.
6087 bCompact = true;
6088
6089 if(bCompact){
6090
6091 // Might need to shorten the Plugin name string
6092 wxString nameString = m_pPlugin->m_common_name;
6093 int maxWidth = g_Platform->getDisplaySize().x * 3 / 10;
6094 wxScreenDC dc;
6095 int nameWidth;
6096 dc.GetTextExtent( m_pPlugin->m_common_name, &nameWidth, NULL);
6097 if(nameWidth > maxWidth){
6098 nameString = wxControl::Ellipsize(m_pPlugin->m_common_name, dc, wxELLIPSIZE_END, maxWidth);
6099 }
6100 m_pName = new wxStaticText( this, wxID_ANY, nameString );
6101 m_pName->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6102 m_pName->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6103 itemBoxSizer02->Add(m_pName, 0, /*wxEXPAND|*/wxALL, 5);
6104
6105 wxFlexGridSizer* sl1 = new wxFlexGridSizer(2,0,0);
6106 sl1->AddGrowableCol(1);
6107 itemBoxSizer02->Add(sl1, 0, wxEXPAND);
6108
6109 m_pVersion = new wxStaticText( this, wxID_ANY, _T("X.YY.ZZ.AA") );
6110 sl1->Add(m_pVersion, 0, /*wxEXPAND|*/ wxALL, 5);
6111 if (m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstallAvailable) {
6112 m_pVersion->Hide();
6113 }
6114 m_pVersion->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6115 m_pVersion->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6116
6117 m_cbEnable = new wxCheckBox(this, wxID_ANY, _("Enabled"));
6118 sl1->Add(m_cbEnable, 1, wxALIGN_RIGHT | wxTOP, 5);
6119 m_cbEnable->Bind(wxEVT_CHECKBOX, &PluginPanel::OnPluginEnableToggle, this);
6120
6121 // Might need to shorten the Plugin description string
6122 wxString descriptionString = m_pPlugin->m_short_description;
6123 int maxDescriptionWidth = g_Platform->getDisplaySize().x - (iconSize * 4);
6124 int descriptionWidth;
6125 dc.GetTextExtent( m_pPlugin->m_short_description, &descriptionWidth, NULL);
6126 if(descriptionWidth > maxDescriptionWidth)
6127 descriptionString = wxControl::Ellipsize(m_pPlugin->m_short_description, dc, wxELLIPSIZE_END, maxDescriptionWidth);
6128
6129 // This invocation has the effect of setting the minimum width of the descriptor field.
6130 m_pDescription = new wxStaticText( this, wxID_ANY, descriptionString, wxDefaultPosition, wxSize( maxDescriptionWidth, -1), wxST_NO_AUTORESIZE );
6131 itemBoxSizer02->Add( m_pDescription, 0, wxEXPAND|wxALL, 5 );
6132 m_pDescription->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6133 m_pDescription->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6134
6135 }
6136 else{
6137 wxFlexGridSizer* itemBoxSizer03 = new wxFlexGridSizer(3,0,0);
6138 itemBoxSizer03->AddGrowableCol(2);
6139 itemBoxSizer02->Add(itemBoxSizer03, 0, wxEXPAND);
6140
6141 wxString nameString = m_pPlugin->m_common_name;
6142 m_pName = new wxStaticText( this, wxID_ANY, nameString );
6143 m_pName->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6144 m_pName->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6145
6146 // Avoid known bug in wxGTK3
6147 #ifndef __WXGTK3__
6148 wxFont font = GetFont();
6149 font.SetWeight(wxFONTWEIGHT_BOLD);
6150 m_pName->SetFont(font);
6151 #endif
6152
6153 itemBoxSizer03->Add(m_pName, 0, /*wxEXPAND|*/wxALL, 10);
6154
6155 m_pVersion = new wxStaticText( this, wxID_ANY, _T("X.YY.ZZ.AA") );
6156 itemBoxSizer03->Add(m_pVersion, 0, /*wxEXPAND|*/ wxALL, 10);
6157 if (m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstallAvailable) {
6158 m_pVersion->Hide();
6159 }
6160 m_pVersion->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6161 m_pVersion->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6162
6163 m_cbEnable = new wxCheckBox(this, wxID_ANY, _("Enabled"));
6164 itemBoxSizer03->Add(m_cbEnable, 1, wxALIGN_RIGHT | wxTOP, 10);
6165 m_cbEnable->Bind(wxEVT_CHECKBOX, &PluginPanel::OnPluginEnableToggle, this);
6166
6167 // This invocation has the effect of setting the minimum width of the descriptor field.
6168 m_pDescription = new wxStaticText( this, wxID_ANY, m_pPlugin->m_short_description, wxDefaultPosition, wxSize( 40 * GetCharWidth(), -1), wxST_NO_AUTORESIZE );
6169 itemBoxSizer02->Add( m_pDescription, 0, wxEXPAND|wxALL, 5 );
6170 m_pDescription->Bind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6171 m_pDescription->Bind(wxEVT_LEFT_UP, &PluginPanel::OnPluginSelectedUp, this);
6172
6173 }
6174
6175
6176 if(!bCompact){
6177 m_info_btn = new WebsiteButton(this, "https:\\opencpn.org");
6178 m_info_btn->Hide();
6179 itemBoxSizer02->Add(m_info_btn, 0);
6180
6181 m_pButtons = new wxBoxSizer(wxHORIZONTAL);
6182 itemBoxSizer02->Add( m_pButtons, 0, /*wxEXPAND|*/wxALL, 0 );
6183 m_pButtonPreferences = new wxButton( this, wxID_ANY, _("Preferences"), wxDefaultPosition, wxDefaultSize, 0 );
6184 m_pButtons->Add( m_pButtonPreferences, 0, wxALIGN_LEFT|wxALL, 2);
6185
6186 m_pButtons->AddSpacer(3 * GetCharWidth());
6187
6188 m_pButtonAction = new wxButton( this, wxID_ANY, "Upgrade to Version XX.XX.XX", wxDefaultPosition, wxDefaultSize, 0 );
6189 m_pButtons->Add( m_pButtonAction, 0, wxALIGN_LEFT|wxALL, 2);
6190
6191 m_pButtonUninstall = new wxButton( this, wxID_ANY, _("Uninstall"), wxDefaultPosition, wxDefaultSize, 0 );
6192 m_pButtons->Add( m_pButtonUninstall, 0, wxALIGN_LEFT|wxALL, 2);
6193 }
6194 else{
6195 m_pButtons = new wxBoxSizer(wxVERTICAL);
6196 itemBoxSizer02->Add( m_pButtons, 0, /*wxEXPAND|*/wxALL, 0 );
6197
6198 wxBoxSizer *tline = new wxBoxSizer(wxHORIZONTAL);
6199 m_pButtons->Add( tline, 0,wxALL, 2);
6200
6201 m_pButtonPreferences = new wxButton( this, wxID_ANY, _("Preferences"), wxDefaultPosition, wxDefaultSize, 0 );
6202 tline->Add( m_pButtonPreferences, 0, wxALIGN_LEFT|wxALL, 0);
6203
6204 tline->AddSpacer(3 * GetCharWidth());
6205
6206 m_info_btn = new WebsiteButton(this, "https:\\opencpn.org");
6207 m_info_btn->Hide();
6208 tline->Add(m_info_btn, 0);
6209
6210 m_pButtonAction = new wxButton( this, wxID_ANY, "Upgrade to Version XX.XX.XX", wxDefaultPosition, wxDefaultSize );
6211 m_pButtons->Add( m_pButtonAction, 0, wxALIGN_LEFT|wxALL, 2);
6212
6213 m_pButtonUninstall = new wxButton( this, wxID_ANY, _("Uninstall"), wxDefaultPosition, wxDefaultSize, 0 );
6214 m_pButtons->Add( m_pButtonUninstall, 0, wxALIGN_LEFT|wxALL, 2);
6215
6216 }
6217
6218 m_status_icon = new StatusIconPanel(this, m_pPlugin);
6219 m_status_icon->SetStatus(p_plugin->m_pluginStatus);
6220 itemBoxSizer01->Add(m_status_icon, 0, wxEXPAND);
6221
6222 itemBoxSizer02->AddSpacer( GetCharWidth() );
6223
6224 m_pButtonPreferences->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginPreferences, this);
6225 m_pButtonUninstall->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginUninstall, this);
6226 m_pButtonAction->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginAction, this);
6227
6228
6229 SetSelected( m_bSelected );
6230 SetAutoLayout(true);
6231 //FitInside();
6232 Fit();
6233 }
6234
~PluginPanel()6235 PluginPanel::~PluginPanel()
6236 {
6237 Unbind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6238 m_itemStaticBitmap->Unbind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6239 m_pName->Unbind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6240 m_pVersion->Unbind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6241 m_pDescription->Unbind(wxEVT_LEFT_DOWN, &PluginPanel::OnPluginSelected, this);
6242 if (m_pButtonAction) {
6243 m_pButtonAction->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginAction, this);
6244 }
6245 m_pButtonPreferences->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginPreferences, this);
6246 m_cbEnable->Unbind(wxEVT_COMMAND_BUTTON_CLICKED, &PluginPanel::OnPluginEnableToggle, this);
6247 }
6248
SetActionLabel(wxString & label)6249 void PluginPanel::SetActionLabel( wxString &label)
6250 {
6251 m_pButtonAction->SetLabel( label );
6252 Refresh();
6253 }
6254
6255 static wxStopWatch swclick;
6256 static int downx, downy;
6257
OnPluginSelected(wxMouseEvent & event)6258 void PluginPanel::OnPluginSelected( wxMouseEvent &event )
6259 {
6260 #ifdef __OCPN__ANDROID__
6261 swclick.Start();
6262 event.GetPosition( &downx, &downy );
6263 #else
6264 DoPluginSelect();
6265 #endif
6266 }
6267
OnPluginSelectedUp(wxMouseEvent & event)6268 void PluginPanel::OnPluginSelectedUp( wxMouseEvent &event )
6269 {
6270 #ifdef __OCPN__ANDROID__
6271 qDebug() << swclick.Time();
6272 if(swclick.Time() < 200){
6273 int upx, upy;
6274 event.GetPosition(&upx, &upy);
6275 if( (fabs(upx-downx) < GetCharWidth()) && (fabs(upy-downy) < GetCharWidth()) ){
6276 DoPluginSelect();
6277 }
6278 }
6279 swclick.Start();
6280 #endif
6281 }
6282
DoPluginSelect()6283 void PluginPanel::DoPluginSelect( )
6284 {
6285 if (m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstallAvailable)
6286 {
6287 auto dialog = dynamic_cast<PluginListPanel*>(GetGrandParent());
6288 wxASSERT(dialog != 0);
6289 run_update_dialog(dialog, m_pPlugin, false);
6290 }
6291 else if (m_bSelected){
6292 SetSelected(false);
6293 m_PluginListPanel->SelectPlugin( NULL );
6294 }
6295 else {
6296 SetSelected( true );
6297 m_PluginListPanel->SelectPlugin( this );
6298 }
6299 }
6300
6301
SetSelected(bool selected)6302 void PluginPanel::SetSelected( bool selected )
6303 {
6304 m_bSelected = selected;
6305
6306 m_pVersion->SetLabel( m_pPlugin->GetVersion().to_string() );
6307
6308 if(m_pPlugin->m_ManagedMetadata.version.size()){
6309 // Is this a fully managed and current plugin?
6310 // If so, as a special case...
6311 // We show the version from the metadata, thus handling managed plugins with API < 117
6312
6313 if( m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstalledCurrentVersion )
6314 m_pVersion->SetLabel( m_pPlugin->m_ManagedMetadata.version );
6315
6316 if( m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstalledUpdateAvailable )
6317 m_pVersion->SetLabel( wxString(m_pPlugin->m_InstalledManagedVersion) );
6318
6319 }
6320
6321
6322 if (selected) {
6323 m_status_icon->SetBackgroundColour(GetGlobalColor(_T("DILG1")));
6324 SetBackgroundColour(GetGlobalColor(_T("DILG1")));
6325 m_pButtons->Show(true);
6326 bool unInstallPossible = canUninstall(m_pPlugin->m_common_name.ToStdString());
6327
6328 //Directly mark Legacy and system plugins as "not uninstallable"
6329 if( (m_pPlugin->m_pluginStatus == PluginStatus::LegacyUpdateAvailable) ||
6330 (m_pPlugin->m_pluginStatus == PluginStatus::Unmanaged) ||
6331 (m_pPlugin->m_pluginStatus == PluginStatus::System) )
6332 unInstallPossible = false;
6333
6334 m_pButtonUninstall->Show(unInstallPossible);
6335
6336 if(m_pPlugin->m_ManagedMetadata.info_url.size()){
6337 m_info_btn->SetURL(m_pPlugin->m_ManagedMetadata.info_url.c_str());
6338 m_info_btn->Show();
6339 }
6340
6341 m_cbEnable->Show(true);
6342
6343
6344 // Configure the "Action" button
6345 wxString label;
6346 SemanticVersion newVersion;
6347 switch(m_pPlugin->m_pluginStatus){
6348 case PluginStatus::LegacyUpdateAvailable:
6349 label = _("Upgrade to Version ");
6350 label += wxString(m_pPlugin->m_ManagedMetadata.version.c_str());
6351 m_action = ActionVerb::UPGRADE_TO_MANAGED_VERSION;
6352 m_pButtonAction->Enable();
6353 break;
6354
6355 case PluginStatus::ManagedInstallAvailable:
6356 label = _("Install...");
6357 m_action = ActionVerb::INSTALL_MANAGED_VERSION;
6358 m_pButtonAction->Enable();
6359 break;
6360
6361 case PluginStatus::ManagedInstalledUpdateAvailable:
6362 label = _("Update to ");
6363 label += wxString(m_pPlugin->m_ManagedMetadata.version.c_str());
6364 m_action = ActionVerb::UPGRADE_INSTALLED_MANAGED_VERSION;
6365 m_pButtonAction->Enable();
6366 break;
6367
6368 case PluginStatus::ManagedInstalledCurrentVersion:
6369 label = _("Reinstall");
6370 m_action = ActionVerb::REINSTALL_MANAGED_VERSION;
6371 m_pButtonAction->Enable();
6372 break;
6373
6374 case PluginStatus::ManagedInstalledDowngradeAvailable:
6375 label = _("Downgrade");
6376 m_action = ActionVerb::DOWNGRADE_INSTALLED_MANAGED_VERSION;
6377 m_pButtonAction->Enable();
6378 break;
6379
6380 case PluginStatus::Unmanaged:
6381 m_action = ActionVerb::NOP;
6382 m_pButtonAction->Hide();
6383 break;
6384
6385 case PluginStatus::System:
6386 m_action = ActionVerb::NOP;
6387 m_pButtonAction->Hide();
6388 break;
6389
6390 default:
6391 label = "TBD";
6392 m_action = ActionVerb::NOP;
6393 break;
6394 }
6395 SetActionLabel( label );
6396
6397 Layout();
6398 }
6399 else {
6400 m_status_icon->SetBackgroundColour(GetGlobalColor(_T("DILG0")));
6401 SetBackgroundColour(GetGlobalColor(_T("DILG0")));
6402 //m_pDescription->SetLabel( m_pPlugin->m_short_description );
6403 #ifndef __WXQT__
6404 //m_pButtons->Show(false);
6405 #else
6406 //m_pButtons->Show(true);
6407 #endif
6408 //();
6409
6410 m_pButtons->Show(false);
6411 m_info_btn->Hide();
6412
6413 if (m_pPlugin->m_pluginStatus == PluginStatus::ManagedInstallAvailable)
6414 m_cbEnable->Show(false);
6415
6416 Layout();
6417 }
6418
6419
6420 //m_status_icon->Show(!selected);
6421 //m_pButtons->Show(selected); // For most platforms, show buttons if selected
6422 //m_pButtonsUpDown->Show(selected);
6423 #ifdef __OCPN__ANDROID__
6424 // Some Android devices (e.g. Kyocera) have trouble with wxBitmapButton...
6425 //m_pButtonsUpDown->Show(false);
6426 //m_pButtons->Show(true); // Always enable buttons for Android
6427 #endif
6428
6429 Layout();
6430
6431 bool bUseSysColors = false;
6432 #ifdef __WXOSX__
6433 if( wxPlatformInfo::Get().CheckOSVersion(10, 14) )
6434 bUseSysColors = true;
6435 #endif
6436 #ifdef __WXGTK__
6437 bUseSysColors= true;
6438 #endif
6439
6440 if(bUseSysColors){
6441 wxColour bg = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
6442 if( bg.Red() < 128 ) { // is Dark...
6443 if(selected) {
6444 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
6445 m_status_icon->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
6446 } else {
6447 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
6448 m_status_icon->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE));
6449 }
6450 }
6451 }
6452
6453 SetEnabled( m_pPlugin->m_bEnabled );
6454
6455 #ifdef __OCPN__ANDROID__
6456 // Android (wxQT) sizers have troubles...
6457 // So we set some layout factors to avoid re-sizing on select/deselect.
6458 // m_rgSizer->Show(true);
6459 //m_pButtons->Show(true);
6460 //m_pButtonAction->Hide();
6461 //m_pButtonUninstall->Hide();
6462
6463 Fit();
6464 m_PluginListPanel->m_pitemBoxSizer01->Layout();
6465 #endif
6466
6467
6468 }
6469
OnPaint(wxPaintEvent & event)6470 void PluginPanel::OnPaint(wxPaintEvent &event)
6471 {
6472 wxPaintDC dc( this );
6473
6474 wxString color = "DILG0";
6475
6476 int penWidth = m_penWidthUnselected;
6477 if(m_bSelected){
6478 color = "DILG1";
6479 penWidth = m_penWidthSelected;
6480 }
6481
6482 wxBrush b(GetGlobalColor(color), wxSOLID);
6483 dc.SetBrush(b);
6484 dc.SetPen( wxPen(*wxBLACK, penWidth) );
6485
6486 dc.DrawRoundedRectangle( 5, 5, GetSize().x - 10, GetSize().y - 10, 5);
6487 //dc.DrawLine( 5, 5, 1000, 5 );
6488
6489 }
6490
OnPluginPreferences(wxCommandEvent & event)6491 void PluginPanel::OnPluginPreferences( wxCommandEvent& event )
6492 {
6493 if (m_pPlugin->m_bEnabled && m_pPlugin->m_bInitState && (m_pPlugin->m_cap_flag & WANTS_PREFERENCES) ){
6494 #ifdef __OCPN__ANDROID__
6495 androidDisableRotation();
6496 m_pPlugin->m_pplugin->ShowPreferencesDialog( GetGrandParent() ); // GrandParent will be the entire list panel, not the plugin panel
6497 // Ensures better centering on small screens
6498 #else
6499 m_pPlugin->m_pplugin->ShowPreferencesDialog( this );
6500 #endif
6501 }
6502 }
6503
OnPluginEnableToggle(wxCommandEvent & event)6504 void PluginPanel::OnPluginEnableToggle( wxCommandEvent& event )
6505 {
6506 SetEnabled(!m_pPlugin->m_bEnabled);
6507 }
6508
OnPluginUninstall(wxCommandEvent & event)6509 void PluginPanel::OnPluginUninstall( wxCommandEvent& event )
6510 {
6511 m_action = ActionVerb::UNINSTALL_MANAGED_VERSION;
6512
6513 // Chain up to the utility event handler
6514 wxCommandEvent actionEvent(wxEVT_COMMAND_BUTTON_CLICKED);
6515 actionEvent.SetId( ID_CMD_BUTTON_PERFORM_ACTION );
6516 actionEvent.SetClientData(this);
6517 g_pi_manager->GetUtilHandler()->AddPendingEvent(actionEvent);
6518 }
6519
6520
OnPluginAction(wxCommandEvent & event)6521 void PluginPanel::OnPluginAction( wxCommandEvent& event )
6522 {
6523 // Chain up to the utility event handler
6524 wxCommandEvent actionEvent(wxEVT_COMMAND_BUTTON_CLICKED);
6525 actionEvent.SetId( ID_CMD_BUTTON_PERFORM_ACTION );
6526 actionEvent.SetClientData(this);
6527 g_pi_manager->GetUtilHandler()->AddPendingEvent(actionEvent);
6528
6529 return;
6530 }
6531
6532
SetEnabled(bool enabled)6533 void PluginPanel::SetEnabled( bool enabled )
6534 {
6535 if (m_pPlugin->m_bEnabled != enabled)
6536 {
6537 m_pPlugin->m_bEnabled = enabled;
6538 if(s_ppim)
6539 s_ppim->UpdatePlugIns();
6540 NotifySetupOptionsPlugin( m_pPlugin );
6541 }
6542 if (!enabled && !m_bSelected)
6543 {
6544 m_pName->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
6545 m_pVersion->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
6546 m_pDescription->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
6547 #ifdef x__OCPN__ANDROID__
6548 m_pName->Disable();
6549 m_pVersion->Disable();
6550 m_pDescription->Disable();
6551 #endif
6552 }
6553 else
6554 {
6555 m_pName->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
6556 m_pVersion->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
6557 m_pDescription->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
6558 #ifdef x__OCPN__ANDROID__
6559 m_pName->Enable();
6560 m_pVersion->Enable();
6561 m_pDescription->Enable();
6562 #endif
6563 }
6564
6565 #ifdef __OCPN__ANDROID__
6566 m_pName->Enable( enabled || m_bSelected );
6567 m_pVersion->Enable( enabled || m_bSelected );
6568 m_pDescription->Enable( enabled || m_bSelected );
6569 #endif
6570
6571 if(m_bSelected) {
6572 wxString description = m_pPlugin->m_long_description;
6573 if(description.IsEmpty())
6574 description = wxString(m_pPlugin->m_ManagedMetadata.description.c_str());
6575 m_pDescription->SetLabel( description );
6576 if(m_pPlugin->m_ManagedMetadata.info_url.size()){
6577 m_info_btn->SetURL(m_pPlugin->m_ManagedMetadata.info_url.c_str());
6578 m_info_btn->Show();
6579 }
6580 }
6581 else{
6582 wxString description = m_pPlugin->m_short_description;
6583 if(description.IsEmpty())
6584 description = wxString(m_pPlugin->m_ManagedMetadata.summary.c_str());
6585 m_pDescription->SetLabel( description );
6586
6587 }
6588
6589 m_pButtonPreferences->Enable( enabled && (m_pPlugin->m_cap_flag & WANTS_PREFERENCES) );
6590 m_cbEnable->SetValue(enabled);
6591
6592 }
6593
OnPluginUp(wxCommandEvent & event)6594 void PluginPanel::OnPluginUp( wxCommandEvent& event )
6595 {
6596 m_PluginListPanel->MoveUp( this );
6597 }
6598
OnPluginDown(wxCommandEvent & event)6599 void PluginPanel::OnPluginDown( wxCommandEvent& event )
6600 {
6601 m_PluginListPanel->MoveDown( this );
6602 }
6603
6604
6605 /** Invokes client browser on plugin info_url when clicked. */
WebsiteButton(wxWindow * parent,const char * url)6606 WebsiteButton::WebsiteButton(wxWindow* parent, const char* url)
6607 :wxPanel(parent), m_url(url)
6608 {
6609 auto vbox = new wxBoxSizer(wxVERTICAL);
6610 auto button = new wxButton(this, wxID_ANY, _("Website"));
6611 button->Enable(strlen(url) > 0);
6612 vbox->Add(button);
6613 SetSizer(vbox);
6614 Bind(wxEVT_COMMAND_BUTTON_CLICKED,
6615 [=](wxCommandEvent&) {wxLaunchDefaultBrowser(m_url);});
6616 }
6617
6618
6619 // ----------------------------------------------------------------------------
6620 // PlugInChartBase Implmentation
6621 // This class is the base class for Plug-able chart types
6622 // ----------------------------------------------------------------------------
6623
PlugInChartBase()6624 PlugInChartBase::PlugInChartBase()
6625 {
6626 m_Chart_Error_Factor = 0.;
6627 }
6628
~PlugInChartBase()6629 PlugInChartBase::~PlugInChartBase()
6630 {}
6631
GetFileSearchMask(void)6632 wxString PlugInChartBase::GetFileSearchMask(void)
6633 {
6634 return _T("");
6635 }
6636
Init(const wxString & name,int init_flags)6637 int PlugInChartBase::Init( const wxString& name, int init_flags )
6638 {
6639 return 0;
6640 }
6641
6642 // Accessors
6643
GetNormalScaleMin(double canvas_scale_factor,bool b_allow_overzoom)6644 double PlugInChartBase::GetNormalScaleMin(double canvas_scale_factor, bool b_allow_overzoom)
6645 {
6646 return 1.0;
6647 }
6648
GetNormalScaleMax(double canvas_scale_factor,int canvas_width)6649 double PlugInChartBase::GetNormalScaleMax(double canvas_scale_factor, int canvas_width)
6650 {
6651 return 2.0e7;
6652 }
6653
GetChartExtent(ExtentPI * pext)6654 bool PlugInChartBase::GetChartExtent(ExtentPI *pext)
6655 {
6656 return false;
6657 }
6658
6659
RenderRegionView(const PlugIn_ViewPort & VPoint,const wxRegion & Region)6660 wxBitmap& PlugInChartBase::RenderRegionView(const PlugIn_ViewPort& VPoint,
6661 const wxRegion &Region)
6662 {
6663 return wxNullBitmap;
6664 }
6665
6666
AdjustVP(PlugIn_ViewPort & vp_last,PlugIn_ViewPort & vp_proposed)6667 bool PlugInChartBase::AdjustVP(PlugIn_ViewPort &vp_last, PlugIn_ViewPort &vp_proposed)
6668 {
6669 return false;
6670 }
6671
GetValidCanvasRegion(const PlugIn_ViewPort & VPoint,wxRegion * pValidRegion)6672 void PlugInChartBase::GetValidCanvasRegion(const PlugIn_ViewPort& VPoint, wxRegion *pValidRegion)
6673 {}
6674
SetColorScheme(int cs,bool bApplyImmediate)6675 void PlugInChartBase::SetColorScheme(int cs, bool bApplyImmediate)
6676 {}
6677
GetNearestPreferredScalePPM(double target_scale_ppm)6678 double PlugInChartBase::GetNearestPreferredScalePPM(double target_scale_ppm)
6679 {
6680 return 1.0;
6681 }
6682
GetThumbnail(int tnx,int tny,int cs)6683 wxBitmap *PlugInChartBase::GetThumbnail(int tnx, int tny, int cs)
6684 {
6685 return NULL;
6686 }
6687
ComputeSourceRectangle(const PlugIn_ViewPort & vp,wxRect * pSourceRect)6688 void PlugInChartBase::ComputeSourceRectangle(const PlugIn_ViewPort &vp, wxRect *pSourceRect)
6689 {}
6690
GetRasterScaleFactor()6691 double PlugInChartBase::GetRasterScaleFactor()
6692 {
6693 return 1.0;
6694 }
6695
GetChartBits(wxRect & source,unsigned char * pPix,int sub_samp)6696 bool PlugInChartBase::GetChartBits( wxRect& source, unsigned char *pPix, int sub_samp )
6697 {
6698 return false;
6699 }
6700
GetSize_X()6701 int PlugInChartBase::GetSize_X()
6702 {
6703 return 1;
6704 }
6705
GetSize_Y()6706 int PlugInChartBase::GetSize_Y()
6707 {
6708 return 1;
6709 }
6710
latlong_to_chartpix(double lat,double lon,double & pixx,double & pixy)6711 void PlugInChartBase::latlong_to_chartpix(double lat, double lon, double &pixx, double &pixy)
6712 {}
6713
chartpix_to_latlong(double pixx,double pixy,double * plat,double * plon)6714 void PlugInChartBase::chartpix_to_latlong(double pixx, double pixy, double *plat, double *plon)
6715 {}
6716
6717
6718 // ----------------------------------------------------------------------------
6719 // PlugInChartBaseGL Implementation
6720 //
6721 // ----------------------------------------------------------------------------
6722
PlugInChartBaseGL()6723 PlugInChartBaseGL::PlugInChartBaseGL()
6724 {}
6725
~PlugInChartBaseGL()6726 PlugInChartBaseGL::~PlugInChartBaseGL()
6727 {}
6728
RenderRegionViewOnGL(const wxGLContext & glc,const PlugIn_ViewPort & VPoint,const wxRegion & Region,bool b_use_stencil)6729 int PlugInChartBaseGL::RenderRegionViewOnGL( const wxGLContext &glc, const PlugIn_ViewPort& VPoint,
6730 const wxRegion &Region, bool b_use_stencil )
6731 {
6732 return 0;
6733 }
6734
GetObjRuleListAtLatLon(float lat,float lon,float select_radius,PlugIn_ViewPort * VPoint)6735 ListOfPI_S57Obj *PlugInChartBaseGL::GetObjRuleListAtLatLon(float lat, float lon, float select_radius,
6736 PlugIn_ViewPort *VPoint)
6737 {
6738 return NULL;
6739 }
6740
CreateObjDescriptions(ListOfPI_S57Obj * obj_list)6741 wxString PlugInChartBaseGL::CreateObjDescriptions( ListOfPI_S57Obj* obj_list )
6742 {
6743 return _T("");
6744 }
6745
GetNoCOVREntries()6746 int PlugInChartBaseGL::GetNoCOVREntries()
6747 {
6748 return 0;
6749 }
6750
GetNoCOVRTablePoints(int iTable)6751 int PlugInChartBaseGL::GetNoCOVRTablePoints(int iTable)
6752 {
6753 return 0;
6754 }
6755
GetNoCOVRTablenPoints(int iTable)6756 int PlugInChartBaseGL::GetNoCOVRTablenPoints(int iTable)
6757 {
6758 return 0;
6759 }
6760
GetNoCOVRTableHead(int iTable)6761 float *PlugInChartBaseGL::GetNoCOVRTableHead(int iTable)
6762 {
6763 return 0;
6764 }
6765
6766
6767 // ----------------------------------------------------------------------------
6768 // PlugInChartBaseExtended Implementation
6769 //
6770 // ----------------------------------------------------------------------------
6771
PlugInChartBaseExtended()6772 PlugInChartBaseExtended::PlugInChartBaseExtended()
6773 {}
6774
~PlugInChartBaseExtended()6775 PlugInChartBaseExtended::~PlugInChartBaseExtended()
6776 {}
6777
RenderRegionViewOnGL(const wxGLContext & glc,const PlugIn_ViewPort & VPoint,const wxRegion & Region,bool b_use_stencil)6778 int PlugInChartBaseExtended::RenderRegionViewOnGL( const wxGLContext &glc, const PlugIn_ViewPort& VPoint,
6779 const wxRegion &Region, bool b_use_stencil )
6780 {
6781 return 0;
6782 }
6783
RenderRegionViewOnGLNoText(const wxGLContext & glc,const PlugIn_ViewPort & VPoint,const wxRegion & Region,bool b_use_stencil)6784 int PlugInChartBaseExtended::RenderRegionViewOnGLNoText( const wxGLContext &glc, const PlugIn_ViewPort& VPoint,
6785 const wxRegion &Region, bool b_use_stencil )
6786 {
6787 return 0;
6788 }
6789
RenderRegionViewOnGLTextOnly(const wxGLContext & glc,const PlugIn_ViewPort & VPoint,const wxRegion & Region,bool b_use_stencil)6790 int PlugInChartBaseExtended::RenderRegionViewOnGLTextOnly( const wxGLContext &glc, const PlugIn_ViewPort& VPoint,
6791 const wxRegion &Region, bool b_use_stencil )
6792 {
6793 return 0;
6794 }
6795
6796
RenderRegionViewOnDCNoText(const PlugIn_ViewPort & VPoint,const wxRegion & Region)6797 wxBitmap &PlugInChartBaseExtended::RenderRegionViewOnDCNoText(const PlugIn_ViewPort& VPoint, const wxRegion &Region)
6798 {
6799 return wxNullBitmap;
6800 }
6801
RenderRegionViewOnDCTextOnly(wxMemoryDC & dc,const PlugIn_ViewPort & VPoint,const wxRegion & Region)6802 bool PlugInChartBaseExtended::RenderRegionViewOnDCTextOnly(wxMemoryDC& dc, const PlugIn_ViewPort& VPoint, const wxRegion &Region)
6803 {
6804 return false;
6805 }
6806
GetObjRuleListAtLatLon(float lat,float lon,float select_radius,PlugIn_ViewPort * VPoint)6807 ListOfPI_S57Obj *PlugInChartBaseExtended::GetObjRuleListAtLatLon(float lat, float lon, float select_radius,
6808 PlugIn_ViewPort *VPoint)
6809 {
6810 return NULL;
6811 }
6812
CreateObjDescriptions(ListOfPI_S57Obj * obj_list)6813 wxString PlugInChartBaseExtended::CreateObjDescriptions( ListOfPI_S57Obj* obj_list )
6814 {
6815 return _T("");
6816 }
6817
GetNoCOVREntries()6818 int PlugInChartBaseExtended::GetNoCOVREntries()
6819 {
6820 return 0;
6821 }
6822
GetNoCOVRTablePoints(int iTable)6823 int PlugInChartBaseExtended::GetNoCOVRTablePoints(int iTable)
6824 {
6825 return 0;
6826 }
6827
GetNoCOVRTablenPoints(int iTable)6828 int PlugInChartBaseExtended::GetNoCOVRTablenPoints(int iTable)
6829 {
6830 return 0;
6831 }
6832
GetNoCOVRTableHead(int iTable)6833 float *PlugInChartBaseExtended::GetNoCOVRTableHead(int iTable)
6834 {
6835 return 0;
6836 }
6837
ClearPLIBTextList()6838 void PlugInChartBaseExtended::ClearPLIBTextList()
6839 {
6840 }
6841
6842 // ----------------------------------------------------------------------------
6843 // ChartPlugInWrapper Implementation
6844 // This class is a wrapper/interface to PlugIn charts(PlugInChartBase)
6845 // ----------------------------------------------------------------------------
6846
6847
ChartPlugInWrapper()6848 ChartPlugInWrapper::ChartPlugInWrapper()
6849 {}
6850
ChartPlugInWrapper(const wxString & chart_class)6851 ChartPlugInWrapper::ChartPlugInWrapper(const wxString &chart_class)
6852 {
6853 m_ppo = ::wxCreateDynamicObject(chart_class);
6854 m_ppicb = wxDynamicCast(m_ppo, PlugInChartBase);
6855 }
6856
~ChartPlugInWrapper()6857 ChartPlugInWrapper::~ChartPlugInWrapper()
6858 {
6859 if(m_ppicb)
6860 delete m_ppicb;
6861 }
6862
GetFileSearchMask(void)6863 wxString ChartPlugInWrapper::GetFileSearchMask(void)
6864 {
6865 if(m_ppicb)
6866 return m_ppicb->GetFileSearchMask();
6867 else
6868 return _T("");
6869 }
6870
Init(const wxString & name,ChartInitFlag init_flags)6871 InitReturn ChartPlugInWrapper::Init( const wxString& name, ChartInitFlag init_flags )
6872 {
6873 if(m_ppicb)
6874 {
6875 wxWindow *pa = wxWindow::FindFocus();
6876
6877 InitReturn ret_val = (InitReturn)m_ppicb->Init(name, (int)init_flags);
6878
6879 // Here we transcribe all the required wrapped member elements up into the chartbase object which is the parent of this class
6880 if(ret_val == INIT_OK)
6881 {
6882 m_FullPath = m_ppicb->GetFullPath();
6883 m_ChartType = (ChartTypeEnum)m_ppicb->GetChartType();
6884 m_ChartFamily = (ChartFamilyEnum)m_ppicb->GetChartFamily();
6885 m_projection = (OcpnProjType)m_ppicb->GetChartProjection();
6886 m_EdDate = m_ppicb->GetEditionDate();
6887 m_Name = m_ppicb->GetName();
6888 m_ID = m_ppicb->GetID();
6889 m_DepthUnits = m_ppicb->GetDepthUnits();
6890 m_SoundingsDatum = m_ppicb->GetSoundingsDatum();
6891 m_datum_str = m_ppicb->GetDatumString();
6892 m_SE = m_ppicb->GetSE();
6893 m_EdDate = m_ppicb->GetEditionDate();
6894 m_ExtraInfo = m_ppicb->GetExtraInfo();
6895 Chart_Error_Factor = m_ppicb->GetChartErrorFactor();
6896 m_depth_unit_id = (ChartDepthUnitType)m_ppicb->GetDepthUnitId();
6897 m_Chart_Skew = m_ppicb->GetChartSkew();
6898 m_Chart_Scale = m_ppicb->GetNativeScale();
6899
6900 // We estimate ppm_avg as needed by raster texture cache logic...
6901 // This number works for average BSB charts, scanned with average resolution
6902 m_ppm_avg = 10000./m_ppicb->GetNativeScale(); // fallback value
6903
6904 // Calcuculate a "better" ppm from the chart geo extent and raster size.
6905 if( (fabs(m_Chart_Skew) < .01) && (CHART_FAMILY_RASTER == m_ChartFamily) ){
6906 Extent extent;
6907 if( GetChartExtent(&extent) ){
6908 double lon_range = extent.ELON - extent.WLON;
6909 if( (lon_range > 0) && (lon_range < 90.0) ) // Be safe about IDL crossing and huge charts
6910 m_ppm_avg = GetSize_X() / (lon_range * 1852 * 60);
6911 }
6912 }
6913
6914 m_overlayENC = false;
6915 if(m_ChartFamily == (ChartFamilyEnum)PI_CHART_FAMILY_VECTOR){
6916 wxCharBuffer buf = m_FullPath.ToUTF8();
6917 m_overlayENC = s57chart::IsCellOverlayType( buf.data() );
6918 }
6919
6920 bReadyToRender = m_ppicb->IsReadyToRender();
6921
6922 }
6923
6924
6925 // PlugIn may invoke wxExecute(), which steals the keyboard focus
6926 // So take it back
6927 ChartCanvas *pc = wxDynamicCast(pa, ChartCanvas);
6928 if(pc)
6929 pc->SetFocus();
6930
6931 return ret_val;
6932 }
6933 else
6934 return INIT_FAIL_REMOVE;
6935 }
6936
6937
6938 // Accessors
GetCOVREntries()6939 int ChartPlugInWrapper::GetCOVREntries()
6940 {
6941 if(m_ppicb)
6942 return m_ppicb->GetCOVREntries();
6943 else
6944 return 0;
6945 }
6946
GetCOVRTablePoints(int iTable)6947 int ChartPlugInWrapper::GetCOVRTablePoints(int iTable)
6948 {
6949 if(m_ppicb)
6950 return m_ppicb->GetCOVRTablePoints(iTable);
6951 else
6952 return 0;
6953 }
6954
GetCOVRTablenPoints(int iTable)6955 int ChartPlugInWrapper::GetCOVRTablenPoints(int iTable)
6956 {
6957 if(m_ppicb)
6958 return m_ppicb->GetCOVRTablenPoints(iTable);
6959 else
6960 return 0;
6961 }
6962
GetCOVRTableHead(int iTable)6963 float *ChartPlugInWrapper::GetCOVRTableHead(int iTable)
6964 {
6965 if(m_ppicb)
6966 return m_ppicb->GetCOVRTableHead(iTable);
6967 else
6968 return 0;
6969 }
6970
6971 // TODO
6972 // PlugIn chart types do not properly support NoCovr Regions
6973 // Proper fix is to update PlugIn Chart Type API
6974 // Derive an extended PlugIn chart class from existing class,
6975 // and use some kind of RTTI to figure out which class to call.
GetNoCOVREntries()6976 int ChartPlugInWrapper::GetNoCOVREntries()
6977 {
6978 if(m_ppicb) {
6979 PlugInChartBaseGL *ppicbgl = dynamic_cast<PlugInChartBaseGL *>(m_ppicb);
6980 if(ppicbgl){
6981 return ppicbgl->GetNoCOVREntries();
6982 }
6983 }
6984 return 0;
6985 }
6986
GetNoCOVRTablePoints(int iTable)6987 int ChartPlugInWrapper::GetNoCOVRTablePoints(int iTable)
6988 {
6989 if(m_ppicb) {
6990 PlugInChartBaseGL *ppicbgl = dynamic_cast<PlugInChartBaseGL *>(m_ppicb);
6991 if(ppicbgl){
6992 return ppicbgl->GetNoCOVRTablePoints(iTable);
6993 }
6994 }
6995 return 0;
6996 }
6997
GetNoCOVRTablenPoints(int iTable)6998 int ChartPlugInWrapper::GetNoCOVRTablenPoints(int iTable)
6999 {
7000 if(m_ppicb) {
7001 PlugInChartBaseGL *ppicbgl = dynamic_cast<PlugInChartBaseGL *>(m_ppicb);
7002 if(ppicbgl){
7003 return ppicbgl->GetNoCOVRTablenPoints(iTable);
7004 }
7005 }
7006 return 0;
7007 }
7008
GetNoCOVRTableHead(int iTable)7009 float *ChartPlugInWrapper::GetNoCOVRTableHead(int iTable)
7010 {
7011 if(m_ppicb) {
7012 PlugInChartBaseGL *ppicbgl = dynamic_cast<PlugInChartBaseGL *>(m_ppicb);
7013 if(ppicbgl){
7014 return ppicbgl->GetNoCOVRTableHead(iTable);
7015 }
7016 }
7017 return 0;
7018 }
7019
GetChartExtent(Extent * pext)7020 bool ChartPlugInWrapper::GetChartExtent(Extent *pext)
7021 {
7022 if(m_ppicb)
7023 {
7024 ExtentPI xpi;
7025 if(m_ppicb->GetChartExtent(&xpi))
7026 {
7027 pext->NLAT = xpi.NLAT;
7028 pext->SLAT = xpi.SLAT;
7029 pext->ELON = xpi.ELON;
7030 pext->WLON = xpi.WLON;
7031
7032 return true;
7033 }
7034 else
7035 return false;
7036 }
7037 else
7038 return false;
7039 }
7040
GetThumbData(int tnx,int tny,float lat,float lon)7041 ThumbData *ChartPlugInWrapper::GetThumbData(int tnx, int tny, float lat, float lon)
7042 {
7043 if(m_ppicb)
7044 {
7045
7046 // Create the bitmap if needed, doing a deep copy from the Bitmap owned by the PlugIn Chart
7047 if(!pThumbData->pDIBThumb)
7048 {
7049 wxBitmap *pBMPOwnedByChart = m_ppicb->GetThumbnail(tnx, tny, m_global_color_scheme);
7050 if( pBMPOwnedByChart ) {
7051 wxImage img = pBMPOwnedByChart->ConvertToImage();
7052 pThumbData->pDIBThumb = new wxBitmap(img);
7053 }
7054 else
7055 pThumbData->pDIBThumb = NULL;
7056
7057 }
7058
7059 pThumbData->Thumb_Size_X = tnx;
7060 pThumbData->Thumb_Size_Y = tny;
7061
7062 /*
7063 // Plot the supplied Lat/Lon on the thumbnail
7064 int divx = m_ppicb->Size_X / tnx;
7065 int divy = m_ppicb->Size_Y / tny;
7066
7067 int div_factor = __min(divx, divy);
7068
7069 int pixx, pixy;
7070
7071
7072 // Using a temporary synthetic ViewPort and source rectangle,
7073 // calculate the ships position on the thumbnail
7074 ViewPort tvp;
7075 tvp.pix_width = tnx;
7076 tvp.pix_height = tny;
7077 tvp.view_scale_ppm = GetPPM() / div_factor;
7078 wxRect trex = Rsrc;
7079 Rsrc.x = 0;
7080 Rsrc.y = 0;
7081 latlong_to_pix_vp(lat, lon, pixx, pixy, tvp);
7082 Rsrc = trex;
7083
7084 pThumbData->ShipX = pixx;// / div_factor;
7085 pThumbData->ShipY = pixy;// / div_factor;
7086 */
7087 pThumbData->ShipX = 0;
7088 pThumbData->ShipY = 0;
7089
7090 return pThumbData;
7091 }
7092 else
7093 return NULL;
7094 }
7095
GetThumbData()7096 ThumbData *ChartPlugInWrapper::GetThumbData()
7097 {
7098 return pThumbData;
7099 }
7100
UpdateThumbData(double lat,double lon)7101 bool ChartPlugInWrapper::UpdateThumbData(double lat, double lon)
7102 {
7103 return true;
7104 }
7105
GetNormalScaleMin(double canvas_scale_factor,bool b_allow_overzoom)7106 double ChartPlugInWrapper::GetNormalScaleMin(double canvas_scale_factor, bool b_allow_overzoom)
7107 {
7108 if(m_ppicb)
7109 return m_ppicb->GetNormalScaleMin(canvas_scale_factor, b_allow_overzoom);
7110 else
7111 return 1.0;
7112 }
7113
GetNormalScaleMax(double canvas_scale_factor,int canvas_width)7114 double ChartPlugInWrapper::GetNormalScaleMax(double canvas_scale_factor, int canvas_width)
7115 {
7116 if(m_ppicb)
7117 return m_ppicb->GetNormalScaleMax(canvas_scale_factor, canvas_width);
7118 else
7119 return 2.0e7;
7120 }
7121
7122
7123 /* RectRegion:
7124 * This is the Screen region desired to be updated. Will be either 1 rectangle(full screen)
7125 * or two rectangles (panning with FBO accelerated pan logic)
7126 *
7127 * Region:
7128 * This is the LLRegion describing the quilt active region for this chart.
7129 *
7130 * So, Actual rendering area onscreen should be clipped to the intersection of the two regions.
7131 */
7132
RenderRegionViewOnGL(const wxGLContext & glc,const ViewPort & VPoint,const OCPNRegion & RectRegion,const LLRegion & Region)7133 bool ChartPlugInWrapper::RenderRegionViewOnGL(const wxGLContext &glc, const ViewPort& VPoint,
7134 const OCPNRegion &RectRegion, const LLRegion &Region)
7135 {
7136 #ifdef ocpnUSE_GL
7137 if(m_ppicb)
7138 {
7139 ViewPort vp = VPoint; // non-const copy
7140
7141 gs_plib_flags = 0; // reset the CAPs flag
7142 PlugInChartBaseGL *ppicb_gl = dynamic_cast<PlugInChartBaseGL*>(m_ppicb);
7143 PlugInChartBaseExtended *ppicb_x = dynamic_cast<PlugInChartBaseExtended*>(m_ppicb);
7144 if(!Region.Empty() && (ppicb_gl || ppicb_x))
7145 {
7146 wxRegion *r = RectRegion.GetNew_wxRegion();
7147 for(OCPNRegionIterator upd ( RectRegion ); upd.HaveRects(); upd.NextRect()) {
7148 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
7149 chart_region.Intersect(Region);
7150
7151 if(!chart_region.Empty()) {
7152 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
7153
7154 glChartCanvas::SetClipRect(cvp, upd.GetRect(), false);
7155
7156 ps52plib->m_last_clip_rect = upd.GetRect();
7157
7158 #ifndef USE_ANDROID_GLES2
7159 glPushMatrix(); // Adjust for rotation
7160 #endif
7161 glChartCanvas::RotateToViewPort(VPoint);
7162
7163 PlugIn_ViewPort pivp = CreatePlugInViewport( cvp );
7164 if(ppicb_x)
7165 ppicb_x->RenderRegionViewOnGL( glc, pivp, *r, glChartCanvas::s_b_useStencil);
7166 else if(ppicb_gl)
7167 ppicb_gl->RenderRegionViewOnGL( glc, pivp, *r, glChartCanvas::s_b_useStencil);
7168
7169 #ifndef USE_ANDROID_GLES2
7170 glPopMatrix();
7171 #endif
7172 glChartCanvas::DisableClipRegion();
7173
7174
7175 } //!empty
7176 } //for
7177 delete r;
7178 }
7179 }
7180 else
7181 return false;
7182 #endif
7183 return true;
7184 }
7185
7186 //int indexrr;
7187
RenderRegionViewOnGLNoText(const wxGLContext & glc,const ViewPort & VPoint,const OCPNRegion & RectRegion,const LLRegion & Region)7188 bool ChartPlugInWrapper::RenderRegionViewOnGLNoText(const wxGLContext &glc, const ViewPort& VPoint,
7189 const OCPNRegion &RectRegion, const LLRegion &Region)
7190 {
7191 #ifdef ocpnUSE_GL
7192 if(m_ppicb)
7193 {
7194 // printf("\nCPIW::RRVOGLNT %d %d \n", indexrr++, m_Chart_Scale);
7195
7196 gs_plib_flags = 0; // reset the CAPs flag
7197 PlugInChartBaseExtended *ppicb_x = dynamic_cast<PlugInChartBaseExtended*>(m_ppicb);
7198 PlugInChartBaseGL *ppicb = dynamic_cast<PlugInChartBaseGL*>(m_ppicb);
7199 if(!Region.Empty() && ppicb_x)
7200 {
7201
7202 #ifndef USE_ANDROID_GLES2
7203 glPushMatrix(); // Adjust for rotation
7204 #endif
7205
7206 // Start with a clean slate
7207 glChartCanvas::SetClipRect(VPoint, VPoint.rv_rect, false);
7208 glChartCanvas::DisableClipRegion();
7209
7210 glChartCanvas::RotateToViewPort(VPoint);
7211
7212 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint );
7213 wxRegion *r = RectRegion.GetNew_wxRegion();
7214
7215 ppicb_x->RenderRegionViewOnGLNoText( glc, pivp, *r, glChartCanvas::s_b_useStencil);
7216
7217 #ifndef USE_ANDROID_GLES2
7218 glPopMatrix();
7219 #endif
7220 delete r;
7221
7222 }
7223
7224 else if(!Region.Empty() && ppicb ) // Legacy Vector GL Plugin chart (e.g.S63)
7225 {
7226 ViewPort vp = VPoint; // non-const copy
7227 wxRegion *r = RectRegion.GetNew_wxRegion();
7228 for(OCPNRegionIterator upd ( RectRegion ); upd.HaveRects(); upd.NextRect()) {
7229 LLRegion chart_region = vp.GetLLRegion(upd.GetRect());
7230 chart_region.Intersect(Region);
7231
7232 if(!chart_region.Empty()) {
7233 ViewPort cvp = glChartCanvas::ClippedViewport(VPoint, chart_region);
7234
7235 glChartCanvas::SetClipRect(cvp, upd.GetRect(), false);
7236
7237 ps52plib->m_last_clip_rect = upd.GetRect();
7238 #ifndef USE_ANDROID_GLES2
7239 glPushMatrix(); // Adjust for rotation
7240 #endif
7241 glChartCanvas::RotateToViewPort(VPoint);
7242
7243 PlugIn_ViewPort pivp = CreatePlugInViewport( cvp );
7244 ppicb->RenderRegionViewOnGL( glc, pivp, *r, glChartCanvas::s_b_useStencil);
7245
7246 #ifndef USE_ANDROID_GLES2
7247 glPopMatrix();
7248 #endif
7249 glChartCanvas::DisableClipRegion();
7250
7251
7252 } //!empty
7253 } //for
7254 delete r;
7255 }
7256
7257 }
7258 else
7259 return false;
7260 #endif
7261 return true;
7262 }
7263
RenderRegionViewOnGLTextOnly(const wxGLContext & glc,const ViewPort & VPoint,const OCPNRegion & Region)7264 bool ChartPlugInWrapper::RenderRegionViewOnGLTextOnly( const wxGLContext &glc, const ViewPort& VPoint,
7265 const OCPNRegion &Region )
7266 {
7267 #ifdef ocpnUSE_GL
7268 if(m_ppicb)
7269 {
7270 gs_plib_flags = 0; // reset the CAPs flag
7271 PlugInChartBaseExtended *ppicb_x = dynamic_cast<PlugInChartBaseExtended*>(m_ppicb);
7272 if(!Region.Empty() && ppicb_x)
7273 {
7274 wxRegion *r = Region.GetNew_wxRegion();
7275 for(OCPNRegionIterator upd ( Region ); upd.HaveRects(); upd.NextRect()) {
7276
7277 #ifndef USE_ANDROID_GLES2
7278 glPushMatrix(); // Adjust for rotation
7279 #endif
7280 glChartCanvas::RotateToViewPort(VPoint);
7281
7282 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint );
7283 ppicb_x->RenderRegionViewOnGLTextOnly( glc, pivp, *r, glChartCanvas::s_b_useStencil);
7284
7285 #ifndef USE_ANDROID_GLES2
7286 glPopMatrix();
7287 #endif
7288
7289 } //for
7290 delete r;
7291 }
7292 }
7293 else
7294 return false;
7295 #endif
7296 return true;
7297
7298 }
7299
7300
RenderRegionViewOnDC(wxMemoryDC & dc,const ViewPort & VPoint,const OCPNRegion & Region)7301 bool ChartPlugInWrapper::RenderRegionViewOnDC(wxMemoryDC& dc, const ViewPort& VPoint,
7302 const OCPNRegion &Region)
7303 {
7304 if(m_ppicb)
7305 {
7306 gs_plib_flags = 0; // reset the CAPs flag
7307 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint);
7308 if(Region.IsOk())
7309 {
7310 wxRegion *r = Region.GetNew_wxRegion();
7311 if(!m_overlayENC)
7312 dc.SelectObject(m_ppicb->RenderRegionView( pivp, *r));
7313 else{
7314 wxBitmap &obmp = m_ppicb->RenderRegionView( pivp, *r);
7315
7316 // Create a mask to remove the NODTA areas from overlay cells.
7317 wxColour nodat = GetGlobalColor( _T ( "NODTA" ) );
7318 wxColour nodat_sub = nodat;
7319
7320 #ifdef ocpnUSE_ocpnBitmap
7321 nodat_sub = wxColour( nodat.Blue(), nodat.Green(), nodat.Red() );
7322 #endif
7323 m_pMask = new wxMask( obmp, nodat_sub );
7324 obmp.SetMask( m_pMask );
7325
7326 dc.SelectObject(obmp);
7327 }
7328
7329 delete r;
7330 return true;
7331 }
7332 else
7333 return false;
7334 }
7335 else
7336 return false;
7337 }
7338
RenderRegionViewOnDCNoText(wxMemoryDC & dc,const ViewPort & VPoint,const OCPNRegion & Region)7339 bool ChartPlugInWrapper::RenderRegionViewOnDCNoText(wxMemoryDC& dc, const ViewPort& VPoint,
7340 const OCPNRegion &Region)
7341 {
7342 if(m_ppicb)
7343 {
7344 gs_plib_flags = 0; // reset the CAPs flag
7345 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint);
7346
7347 PlugInChartBaseExtended *pCBx = dynamic_cast<PlugInChartBaseExtended*>( m_ppicb );
7348 PlugInChartBase *ppicb = dynamic_cast<PlugInChartBase*>(m_ppicb);
7349
7350 if(Region.IsOk() && (pCBx || ppicb))
7351 {
7352 wxRegion *r = Region.GetNew_wxRegion();
7353
7354 if(pCBx)
7355 dc.SelectObject(pCBx->RenderRegionViewOnDCNoText( pivp, *r));
7356 else if(ppicb)
7357 dc.SelectObject(ppicb->RenderRegionView( pivp, *r));
7358
7359 delete r;
7360 return true;
7361 }
7362 else
7363 return false;
7364 }
7365 else
7366 return false;
7367 }
7368
RenderRegionViewOnDCTextOnly(wxMemoryDC & dc,const ViewPort & VPoint,const OCPNRegion & Region)7369 bool ChartPlugInWrapper::RenderRegionViewOnDCTextOnly(wxMemoryDC& dc, const ViewPort& VPoint,
7370 const OCPNRegion &Region)
7371 {
7372 if(m_ppicb)
7373 {
7374 bool ret_val = false;
7375 gs_plib_flags = 0; // reset the CAPs flag
7376 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint);
7377 if(Region.IsOk())
7378 {
7379 wxRegion *r = Region.GetNew_wxRegion();
7380
7381 PlugInChartBaseExtended *pCBx = dynamic_cast<PlugInChartBaseExtended*>( m_ppicb );
7382 if(pCBx)
7383 ret_val = pCBx->RenderRegionViewOnDCTextOnly( dc, pivp, *r);
7384
7385 delete r;
7386 return ret_val;
7387 }
7388 else
7389 return false;
7390 }
7391 else
7392 return false;
7393 }
7394
ClearPLIBTextList()7395 void ChartPlugInWrapper::ClearPLIBTextList()
7396 {
7397 if(m_ppicb)
7398 {
7399 PlugInChartBaseExtended *pCBx = dynamic_cast<PlugInChartBaseExtended*>( m_ppicb );
7400 if(pCBx)
7401 pCBx->ClearPLIBTextList();
7402 }
7403 }
7404
AdjustVP(ViewPort & vp_last,ViewPort & vp_proposed)7405 bool ChartPlugInWrapper::AdjustVP(ViewPort &vp_last, ViewPort &vp_proposed)
7406 {
7407 if(m_ppicb)
7408 {
7409 PlugIn_ViewPort pivp_last = CreatePlugInViewport( vp_last);
7410 PlugIn_ViewPort pivp_proposed = CreatePlugInViewport( vp_proposed);
7411 return m_ppicb->AdjustVP(pivp_last, pivp_proposed);
7412 }
7413 else
7414 return false;
7415 }
7416
GetValidCanvasRegion(const ViewPort & VPoint,OCPNRegion * pValidRegion)7417 void ChartPlugInWrapper::GetValidCanvasRegion(const ViewPort& VPoint, OCPNRegion *pValidRegion)
7418 {
7419 if(m_ppicb)
7420 {
7421 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint);
7422 // currently convert using wxRegion,
7423 // this should be changed as wxRegion is proven unstable/buggy on various platforms
7424 wxRegion region;
7425 m_ppicb->GetValidCanvasRegion(pivp, ®ion);
7426 *pValidRegion = OCPNRegion(region);
7427 }
7428
7429 return;
7430 }
7431
7432
SetColorScheme(ColorScheme cs,bool bApplyImmediate)7433 void ChartPlugInWrapper::SetColorScheme(ColorScheme cs, bool bApplyImmediate)
7434 {
7435 if(m_ppicb) {
7436 m_ppicb->SetColorScheme(cs, bApplyImmediate);
7437 }
7438 m_global_color_scheme = cs;
7439 // Force a new thumbnail
7440 if(pThumbData)
7441 pThumbData->pDIBThumb = NULL;
7442 }
7443
7444
GetNearestPreferredScalePPM(double target_scale_ppm)7445 double ChartPlugInWrapper::GetNearestPreferredScalePPM(double target_scale_ppm)
7446 {
7447 if(m_ppicb)
7448 return m_ppicb->GetNearestPreferredScalePPM(target_scale_ppm);
7449 else
7450 return 1.0;
7451 }
7452
7453
ComputeSourceRectangle(const ViewPort & VPoint,wxRect * pSourceRect)7454 void ChartPlugInWrapper::ComputeSourceRectangle(const ViewPort &VPoint, wxRect *pSourceRect)
7455 {
7456 if(m_ppicb)
7457 {
7458 PlugIn_ViewPort pivp = CreatePlugInViewport( VPoint);
7459 m_ppicb->ComputeSourceRectangle(pivp, pSourceRect);
7460 }
7461 }
7462
GetRasterScaleFactor(const ViewPort & vp)7463 double ChartPlugInWrapper::GetRasterScaleFactor(const ViewPort &vp)
7464 {
7465 if(m_ppicb){
7466 return (wxRound(100000 * GetPPM() / vp.view_scale_ppm)) / 100000.;
7467 }
7468 else
7469 return 1.0;
7470 }
7471
GetChartBits(wxRect & source,unsigned char * pPix,int sub_samp)7472 bool ChartPlugInWrapper::GetChartBits( wxRect& source, unsigned char *pPix, int sub_samp )
7473 {
7474 wxCriticalSectionLocker locker(m_critSect);
7475
7476 if(m_ppicb)
7477
7478 return m_ppicb->GetChartBits( source, pPix, sub_samp );
7479 else
7480 return false;
7481 }
7482
GetSize_X()7483 int ChartPlugInWrapper::GetSize_X()
7484 {
7485 if(m_ppicb)
7486 return m_ppicb->GetSize_X();
7487 else
7488 return 1;
7489 }
7490
GetSize_Y()7491 int ChartPlugInWrapper::GetSize_Y()
7492 {
7493 if(m_ppicb)
7494 return m_ppicb->GetSize_Y();
7495 else
7496 return 1;
7497 }
7498
latlong_to_chartpix(double lat,double lon,double & pixx,double & pixy)7499 void ChartPlugInWrapper::latlong_to_chartpix(double lat, double lon, double &pixx, double &pixy)
7500 {
7501 if(m_ppicb)
7502 m_ppicb->latlong_to_chartpix(lat, lon, pixx, pixy);
7503 }
7504
7505
chartpix_to_latlong(double pixx,double pixy,double * plat,double * plon)7506 void ChartPlugInWrapper::chartpix_to_latlong(double pixx, double pixy, double *plat, double *plon)
7507 {
7508 if(m_ppicb)
7509 m_ppicb->chartpix_to_latlong(pixx, pixy, plat, plon);
7510 }
7511
7512
7513 /* API 1.11 */
7514
7515 /* API 1.11 adds some more common functions to avoid unnecessary code duplication */
7516
toSDMM_PlugIn(int NEflag,double a,bool hi_precision)7517 wxString toSDMM_PlugIn(int NEflag, double a, bool hi_precision)
7518 {
7519 return toSDMM(NEflag, a, hi_precision);
7520 }
7521
GetBaseGlobalColor(wxString colorName)7522 wxColour GetBaseGlobalColor(wxString colorName)
7523 {
7524 return GetGlobalColor( colorName );
7525 }
7526
7527
OCPNMessageBox_PlugIn(wxWindow * parent,const wxString & message,const wxString & caption,int style,int x,int y)7528 int OCPNMessageBox_PlugIn(wxWindow *parent,
7529 const wxString& message,
7530 const wxString& caption,
7531 int style, int x, int y)
7532 {
7533 return OCPNMessageBox( parent, message, caption, style, 100, x, y );
7534 }
7535
GetOCPN_ExePath(void)7536 wxString GetOCPN_ExePath( void )
7537 {
7538 return g_Platform->GetExePath();
7539 }
7540
GetpPlugInLocation()7541 wxString *GetpPlugInLocation()
7542 {
7543 return g_Platform->GetPluginDirPtr();
7544 }
7545
GetWritableDocumentsDir(void)7546 wxString GetWritableDocumentsDir( void )
7547 {
7548 return g_Platform->GetWritableDocumentsDir();
7549 }
7550
7551
GetPlugInPath(opencpn_plugin * pplugin)7552 wxString GetPlugInPath(opencpn_plugin *pplugin)
7553 {
7554 wxString ret_val;
7555 ArrayOfPlugIns *pi_array = g_pi_manager->GetPlugInArray();
7556 for(unsigned int i = 0 ; i < pi_array->GetCount() ; i++)
7557 {
7558 PlugInContainer *pic = pi_array->Item(i);
7559 if(pic->m_pplugin == pplugin )
7560 {
7561 ret_val =pic->m_plugin_file;
7562 break;
7563 }
7564 }
7565
7566 return ret_val;
7567 }
7568
7569 // API 1.11 Access to Vector PlugIn charts
7570
GetPlugInObjRuleListAtLatLon(ChartPlugInWrapper * target,float zlat,float zlon,float SelectRadius,const ViewPort & vp)7571 ListOfPI_S57Obj *PlugInManager::GetPlugInObjRuleListAtLatLon( ChartPlugInWrapper *target, float zlat, float zlon,
7572 float SelectRadius, const ViewPort& vp )
7573 {
7574 ListOfPI_S57Obj *list = NULL;
7575 if(target) {
7576 PlugInChartBaseGL *picbgl = dynamic_cast <PlugInChartBaseGL *>(target->GetPlugInChart());
7577 if(picbgl){
7578 PlugIn_ViewPort pi_vp = CreatePlugInViewport( vp );
7579 list = picbgl->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &pi_vp);
7580
7581 return list;
7582 }
7583 PlugInChartBaseExtended *picbx = dynamic_cast <PlugInChartBaseExtended *>(target->GetPlugInChart());
7584 if(picbx){
7585 PlugIn_ViewPort pi_vp = CreatePlugInViewport( vp );
7586 list = picbx->GetObjRuleListAtLatLon(zlat, zlon, SelectRadius, &pi_vp);
7587
7588 return list;
7589 }
7590 else
7591 return list;
7592 }
7593 else
7594 return list;
7595 }
7596
CreateObjDescriptions(ChartPlugInWrapper * target,ListOfPI_S57Obj * rule_list)7597 wxString PlugInManager::CreateObjDescriptions( ChartPlugInWrapper *target, ListOfPI_S57Obj *rule_list )
7598 {
7599 wxString ret_str;
7600 if(target) {
7601 PlugInChartBaseGL *picbgl = dynamic_cast <PlugInChartBaseGL *>(target->GetPlugInChart());
7602 if(picbgl){
7603 ret_str = picbgl->CreateObjDescriptions( rule_list );
7604 }
7605 else{
7606 PlugInChartBaseExtended *picbx = dynamic_cast <PlugInChartBaseExtended *>(target->GetPlugInChart());
7607 if(picbx){
7608 ret_str = picbx->CreateObjDescriptions( rule_list );
7609 }
7610 }
7611 }
7612 return ret_str;
7613 }
7614
7615
7616 // API 1.11 Access to S52 PLIB
PI_GetPLIBColorScheme()7617 wxString PI_GetPLIBColorScheme()
7618 {
7619 return _T(""); //ps52plib->GetPLIBColorScheme()
7620 }
7621
PI_GetPLIBDepthUnitInt()7622 int PI_GetPLIBDepthUnitInt()
7623 {
7624 if(ps52plib)
7625 return ps52plib->m_nDepthUnitDisplay;
7626 else
7627 return 0;
7628 }
7629
PI_GetPLIBSymbolStyle()7630 int PI_GetPLIBSymbolStyle()
7631 {
7632 if(ps52plib)
7633 return ps52plib->m_nSymbolStyle;
7634 else
7635 return 0;
7636 }
7637
PI_GetPLIBBoundaryStyle()7638 int PI_GetPLIBBoundaryStyle()
7639 {
7640 if(ps52plib)
7641 return ps52plib->m_nBoundaryStyle;
7642 else
7643 return 0;
7644 }
7645
PI_PLIBObjectRenderCheck(PI_S57Obj * pObj,PlugIn_ViewPort * vp)7646 bool PI_PLIBObjectRenderCheck( PI_S57Obj *pObj, PlugIn_ViewPort *vp )
7647 {
7648 if(ps52plib) {
7649 // Create and populate a compatible s57 Object
7650 S57Obj cobj;
7651 chart_context ctx;
7652 CreateCompatibleS57Object( pObj, &cobj, &ctx );
7653
7654 ViewPort cvp = CreateCompatibleViewport( *vp );
7655
7656 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7657
7658 // Create and populate a minimally compatible object container
7659 ObjRazRules rzRules;
7660 rzRules.obj = &cobj;
7661 rzRules.LUP = pContext->LUP;
7662 rzRules.sm_transform_parms = 0;
7663 rzRules.child = NULL;
7664 rzRules.next = NULL;
7665
7666 if(pContext->LUP)
7667 return ps52plib->ObjectRenderCheck( &rzRules, &cvp );
7668 else
7669 return false;
7670 }
7671 else
7672 return false;
7673
7674 }
7675
PI_GetPLIBStateHash()7676 int PI_GetPLIBStateHash()
7677 {
7678 if(ps52plib)
7679 return ps52plib->GetStateHash();
7680 else
7681 return 0;
7682 }
7683
CreateCompatibleS57Object(PI_S57Obj * pObj,S57Obj * cobj,chart_context * pctx)7684 void CreateCompatibleS57Object( PI_S57Obj *pObj, S57Obj *cobj, chart_context *pctx )
7685 {
7686 strncpy(cobj->FeatureName, pObj->FeatureName, 8);
7687 cobj->Primitive_type = (GeoPrim_t)pObj->Primitive_type;
7688 cobj->att_array = pObj->att_array;
7689 cobj->attVal = pObj->attVal;
7690 cobj->n_attr = pObj->n_attr;
7691
7692 cobj->x = pObj->x;
7693 cobj->y = pObj->y;
7694 cobj->z = pObj->z;
7695 cobj->npt = pObj->npt;
7696
7697 cobj->iOBJL = pObj->iOBJL;
7698 cobj->Index = pObj->Index;
7699
7700 cobj->geoPt = (pt *)pObj->geoPt;
7701 cobj->geoPtz = pObj->geoPtz;
7702 cobj->geoPtMulti = pObj->geoPtMulti;
7703
7704 cobj->m_lat = pObj->m_lat;
7705 cobj->m_lon = pObj->m_lon;
7706
7707 cobj->m_DisplayCat = (DisCat)pObj->m_DisplayCat;
7708 cobj->x_rate = pObj->x_rate;
7709 cobj->y_rate = pObj->y_rate;
7710 cobj->x_origin = pObj->x_origin;
7711 cobj->y_origin = pObj->y_origin;
7712
7713 cobj->Scamin = pObj->Scamin;
7714 cobj->nRef = pObj->nRef;
7715 cobj->bIsAton = pObj->bIsAton;
7716 cobj->bIsAssociable = pObj->bIsAssociable;
7717
7718 cobj->m_n_lsindex = pObj->m_n_lsindex;
7719 cobj->m_lsindex_array = pObj->m_lsindex_array;
7720 cobj->m_n_edge_max_points = pObj->m_n_edge_max_points;
7721
7722 if(gs_plib_flags & PLIB_CAPS_OBJSEGLIST){
7723 cobj->m_ls_list_legacy = (PI_line_segment_element *)pObj->m_ls_list; // note the cast, assumes in-sync layout
7724 }
7725 else
7726 cobj->m_ls_list_legacy = 0;
7727 cobj->m_ls_list = 0;
7728
7729 if(gs_plib_flags & PLIB_CAPS_OBJCATMUTATE)
7730 cobj->m_bcategory_mutable = pObj->m_bcategory_mutable;
7731 else
7732 cobj->m_bcategory_mutable = true; // assume all objects are mutable
7733
7734 cobj->m_DPRI = -1; // default is unassigned, fixed at render time
7735 if(gs_plib_flags & PLIB_CAPS_OBJCATMUTATE){
7736 if(pObj->m_DPRI == -1){
7737 S52PLIB_Context *pCtx = (S52PLIB_Context *)pObj->S52_Context;
7738 if(pCtx->LUP)
7739 cobj->m_DPRI = pCtx->LUP->DPRI - '0';
7740 }
7741 else
7742 cobj->m_DPRI = pObj->m_DPRI;
7743 }
7744
7745
7746
7747 cobj->pPolyTessGeo = ( PolyTessGeo* )pObj->pPolyTessGeo;
7748 cobj->m_chart_context = (chart_context *)pObj->m_chart_context;
7749
7750 if(pObj->auxParm3 != 1234){
7751 pObj->auxParm3 = 1234;
7752 pObj->auxParm0 = -99;
7753 }
7754
7755 cobj->auxParm0 = pObj->auxParm0;
7756 cobj->auxParm1 = 0;
7757 cobj->auxParm2 = 0;
7758 cobj->auxParm3 = 0;
7759
7760 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7761
7762 if( pContext->bBBObj_valid )
7763 // this is ugly because plugins still use wxBoundingBox
7764 cobj->BBObj.Set(pContext->BBObj.GetMinY(), pContext->BBObj.GetMinX(),
7765 pContext->BBObj.GetMaxY(), pContext->BBObj.GetMaxX());
7766
7767 cobj->CSrules = pContext->CSrules;
7768 cobj->bCS_Added = pContext->bCS_Added;
7769
7770 cobj->FText = pContext->FText;
7771 cobj->bFText_Added = pContext->bFText_Added;
7772 cobj->rText = pContext->rText;
7773
7774 cobj->bIsClone = true; // Protect cloned object pointers in S57Obj dtor
7775
7776 if(pctx){
7777 cobj->m_chart_context = pctx;
7778 chart_context *ppctx = (chart_context *)pObj->m_chart_context;
7779
7780 if( ppctx ){
7781 cobj->m_chart_context->m_pvc_hash = ppctx->m_pvc_hash;
7782 cobj->m_chart_context->m_pve_hash = ppctx->m_pve_hash;
7783 cobj->m_chart_context->ref_lat = ppctx->ref_lat;
7784 cobj->m_chart_context->ref_lon = ppctx->ref_lon;
7785 cobj->m_chart_context->pFloatingATONArray = ppctx->pFloatingATONArray;
7786 cobj->m_chart_context->pRigidATONArray = ppctx->pRigidATONArray;
7787 cobj->m_chart_context->safety_contour = ppctx->safety_contour;
7788 cobj->m_chart_context->vertex_buffer = ppctx->vertex_buffer;
7789 }
7790 cobj->m_chart_context->chart = 0; // note bene, this is always NULL for a PlugIn chart
7791 }
7792 }
7793
7794
PI_PLIBSetContext(PI_S57Obj * pObj)7795 bool PI_PLIBSetContext( PI_S57Obj *pObj )
7796 {
7797 S52PLIB_Context *ctx;
7798 if( !pObj->S52_Context ){
7799 ctx = new S52PLIB_Context;
7800 pObj->S52_Context = ctx;
7801 }
7802
7803 ctx = (S52PLIB_Context *)pObj->S52_Context;
7804
7805 S57Obj cobj;
7806 CreateCompatibleS57Object( pObj, &cobj, NULL );
7807
7808 LUPname LUP_Name = PAPER_CHART;
7809
7810 // Force a re-evaluation of CS rules
7811 ctx->CSrules = NULL;
7812 ctx->bCS_Added = false;
7813
7814 // Clear the rendered text cache
7815 if( ctx->bFText_Added ) {
7816 ctx->bFText_Added = false;
7817 delete ctx->FText;
7818 ctx->FText = NULL;
7819 }
7820
7821 // Reset object selection box
7822 ctx->bBBObj_valid = true;
7823 ctx->BBObj.SetMin( pObj->lon_min, pObj->lat_min );
7824 ctx->BBObj.SetMax( pObj->lon_max, pObj->lat_max );
7825
7826
7827 // This is where Simplified or Paper-Type point features are selected
7828 switch( cobj.Primitive_type ){
7829 case GEO_POINT:
7830 case GEO_META:
7831 case GEO_PRIM:
7832
7833 if( PAPER_CHART == ps52plib->m_nSymbolStyle )
7834 LUP_Name = PAPER_CHART;
7835 else
7836 LUP_Name = SIMPLIFIED;
7837
7838 break;
7839
7840 case GEO_LINE:
7841 LUP_Name = LINES;
7842 break;
7843
7844 case GEO_AREA:
7845 if( PLAIN_BOUNDARIES == ps52plib->m_nBoundaryStyle )
7846 LUP_Name = PLAIN_BOUNDARIES;
7847 else
7848 LUP_Name = SYMBOLIZED_BOUNDARIES;
7849
7850 break;
7851 }
7852
7853 LUPrec *lup = ps52plib->S52_LUPLookup( LUP_Name, cobj.FeatureName, &cobj );
7854 ctx->LUP = lup;
7855
7856 // Convert LUP to rules set
7857 ps52plib->_LUP2rules( lup, &cobj );
7858
7859 ctx->MPSRulesList = NULL;
7860
7861 return true;
7862 }
7863
PI_UpdateContext(PI_S57Obj * pObj)7864 void PI_UpdateContext(PI_S57Obj *pObj)
7865 {
7866 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7867 if(pContext){
7868 pContext->bBBObj_valid = true;
7869 pContext->BBObj.SetMin( pObj->lon_min, pObj->lat_min );
7870 pContext->BBObj.SetMax( pObj->lon_max, pObj->lat_max );
7871 }
7872 }
7873
7874
UpdatePIObjectPlibContext(PI_S57Obj * pObj,S57Obj * cobj,ObjRazRules * rzRules)7875 void UpdatePIObjectPlibContext( PI_S57Obj *pObj, S57Obj *cobj, ObjRazRules *rzRules )
7876 {
7877 // Update the PLIB context after the render operation
7878 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7879
7880 pContext->CSrules = cobj->CSrules;
7881 pContext->bCS_Added = cobj->bCS_Added;
7882
7883 pContext->FText = cobj->FText;
7884 pContext->bFText_Added = cobj->bFText_Added;
7885 pContext->rText = cobj->rText;
7886
7887 if(cobj->BBObj.GetValid()) {
7888 // ugly as plugins still use wxBoundingBox
7889 pContext->BBObj = wxBoundingBox(cobj->BBObj.GetMinLon(), cobj->BBObj.GetMinLat(),
7890 cobj->BBObj.GetMaxLon(), cobj->BBObj.GetMaxLat());
7891 pContext->bBBObj_valid = true;
7892 }
7893
7894 // Render operation may have promoted the object's display category (e.g.WRECKS)
7895 pObj->m_DisplayCat = (PI_DisCat)cobj->m_DisplayCat;
7896
7897 if(gs_plib_flags & PLIB_CAPS_OBJCATMUTATE)
7898 pObj->m_DPRI = cobj->m_DPRI;
7899
7900 pContext->ChildRazRules = rzRules->child;
7901 pContext->MPSRulesList = rzRules->mps;
7902
7903 pObj->auxParm0 = cobj->auxParm0;
7904
7905
7906 }
7907
PI_GetObjectRenderBox(PI_S57Obj * pObj,double * lat_min,double * lat_max,double * lon_min,double * lon_max)7908 bool PI_GetObjectRenderBox( PI_S57Obj *pObj, double *lat_min, double *lat_max, double *lon_min, double *lon_max)
7909 {
7910 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7911 if(pContext){
7912 if(lat_min) *lat_min = pContext->BBObj.GetMinY();
7913 if(lat_max) *lat_max = pContext->BBObj.GetMaxY();
7914 if(lon_min) *lon_min = pContext->BBObj.GetMinX();
7915 if(lon_max) *lon_max = pContext->BBObj.GetMaxX();
7916 return pContext->bBBObj_valid;
7917 }
7918 else
7919 return false;
7920 }
7921
PI_GetObjectLUPName(PI_S57Obj * pObj)7922 PI_LUPname PI_GetObjectLUPName( PI_S57Obj *pObj )
7923 {
7924 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7925 if( pContext ) {
7926 LUPrec *lup = pContext->LUP;
7927 if( lup )
7928 return (PI_LUPname)(lup->TNAM);
7929 }
7930 return (PI_LUPname)(-1);
7931
7932 }
7933
PI_GetObjectDisplayPriority(PI_S57Obj * pObj)7934 PI_DisPrio PI_GetObjectDisplayPriority( PI_S57Obj *pObj )
7935 {
7936 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7937 if( pContext ) {
7938 LUPrec *lup = pContext->LUP;
7939 if( lup )
7940 return (PI_DisPrio)(lup->DPRI);
7941 }
7942
7943 return (PI_DisPrio)(-1);
7944
7945 }
7946
PI_GetObjectDisplayCategory(PI_S57Obj * pObj)7947 PI_DisCat PI_GetObjectDisplayCategory( PI_S57Obj *pObj )
7948 {
7949 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7950 if( pContext ) {
7951 LUPrec *lup = pContext->LUP;
7952 if( lup )
7953 return (PI_DisCat)(lup->DISC);
7954 }
7955 return (PI_DisCat)(-1);
7956
7957 }
PI_GetPLIBMarinerSafetyContour()7958 double PI_GetPLIBMarinerSafetyContour()
7959 {
7960 return S52_getMarinerParam(S52_MAR_SAFETY_CONTOUR);
7961 }
7962
7963
PI_PLIBSetLineFeaturePriority(PI_S57Obj * pObj,int prio)7964 void PI_PLIBSetLineFeaturePriority( PI_S57Obj *pObj, int prio )
7965 {
7966 // Create and populate a compatible s57 Object
7967 S57Obj cobj;
7968 chart_context ctx;
7969 CreateCompatibleS57Object( pObj, &cobj, &ctx );
7970
7971 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
7972
7973 // Create and populate a minimally compatible object container
7974 ObjRazRules rzRules;
7975 rzRules.obj = &cobj;
7976 rzRules.LUP = pContext->LUP;
7977 rzRules.sm_transform_parms = 0;
7978 rzRules.child = NULL;
7979 rzRules.next = NULL;
7980 rzRules.mps = pContext->MPSRulesList;
7981
7982 if(pContext->LUP){
7983 ps52plib->SetLineFeaturePriority( &rzRules, prio );
7984
7985 // Update the PLIB context after the render operation
7986 UpdatePIObjectPlibContext( pObj, &cobj, &rzRules );
7987 }
7988
7989 }
7990
PI_PLIBPrepareForNewRender(void)7991 void PI_PLIBPrepareForNewRender( void )
7992 {
7993 if(ps52plib){
7994 ps52plib->PrepareForRender();
7995 ps52plib->ClearTextList();
7996
7997 if(gs_plib_flags & PLIB_CAPS_LINE_BUFFER)
7998 ps52plib->EnableGLLS(true); // Newer PlugIns can use GLLS
7999 else
8000 ps52plib->EnableGLLS(false); // Older cannot
8001 }
8002 }
8003
PI_PLIBSetRenderCaps(unsigned int flags)8004 void PI_PLIBSetRenderCaps( unsigned int flags )
8005 {
8006 gs_plib_flags = flags;
8007 }
8008
PI_PLIBFreeContext(void * pContext)8009 void PI_PLIBFreeContext( void *pContext )
8010 {
8011
8012 S52PLIB_Context *pctx = (S52PLIB_Context *)pContext;
8013
8014 if( pctx->ChildRazRules ){
8015 ObjRazRules *ctop = pctx->ChildRazRules;
8016 while( ctop ) {
8017 delete ctop->obj;
8018
8019 if( ps52plib )
8020 ps52plib->DestroyLUP( ctop->LUP );
8021 delete ctop->LUP;
8022
8023 ObjRazRules *cnxx = ctop->next;
8024 delete ctop;
8025 ctop = cnxx;
8026 }
8027 }
8028
8029 if(pctx->MPSRulesList){
8030
8031 if( ps52plib && pctx->MPSRulesList->cs_rules ){
8032 for(unsigned int i=0 ; i < pctx->MPSRulesList->cs_rules->GetCount() ; i++){
8033 Rules *top = pctx->MPSRulesList->cs_rules->Item(i);
8034 ps52plib->DestroyRulesChain( top );
8035 }
8036 delete pctx->MPSRulesList->cs_rules;
8037 }
8038 free( pctx->MPSRulesList );
8039
8040 }
8041
8042 delete pctx->FText;
8043
8044 delete pctx;
8045 }
8046
PI_PLIBRenderObjectToDC(wxDC * pdc,PI_S57Obj * pObj,PlugIn_ViewPort * vp)8047 int PI_PLIBRenderObjectToDC( wxDC *pdc, PI_S57Obj *pObj, PlugIn_ViewPort *vp )
8048 {
8049 // Create and populate a compatible s57 Object
8050 S57Obj cobj;
8051 chart_context ctx;
8052 CreateCompatibleS57Object( pObj, &cobj, &ctx );
8053
8054 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
8055
8056 // Set up object SM rendering constants
8057 sm_parms transform;
8058 toSM( vp->clat, vp->clon, pObj->chart_ref_lat, pObj->chart_ref_lon, &transform.easting_vp_center, &transform.northing_vp_center );
8059
8060 // Create and populate a minimally compatible object container
8061 ObjRazRules rzRules;
8062 rzRules.obj = &cobj;
8063 rzRules.LUP = pContext->LUP;
8064 rzRules.sm_transform_parms = &transform;
8065 rzRules.child = pContext->ChildRazRules;
8066 rzRules.next = NULL;
8067 rzRules.mps = pContext->MPSRulesList;
8068
8069 if(pContext->LUP){
8070 ViewPort cvp = CreateCompatibleViewport( *vp );
8071
8072 // Do the render
8073 ps52plib->RenderObjectToDC( pdc, &rzRules, &cvp );
8074
8075 // Update the PLIB context after the render operation
8076 UpdatePIObjectPlibContext( pObj, &cobj, &rzRules );
8077 }
8078
8079 return 1;
8080 }
8081
PI_PLIBRenderAreaToDC(wxDC * pdc,PI_S57Obj * pObj,PlugIn_ViewPort * vp,wxRect rect,unsigned char * pixbuf)8082 int PI_PLIBRenderAreaToDC( wxDC *pdc, PI_S57Obj *pObj, PlugIn_ViewPort *vp, wxRect rect, unsigned char *pixbuf )
8083 {
8084 // Create a compatible render canvas
8085 render_canvas_parms pb_spec;
8086
8087 pb_spec.depth = BPP;
8088 pb_spec.pb_pitch = ( ( rect.width * pb_spec.depth / 8 ) );
8089 pb_spec.lclip = rect.x;
8090 pb_spec.rclip = rect.x + rect.width - 1;
8091 pb_spec.pix_buff = pixbuf; // the passed buffer
8092 pb_spec.width = rect.width;
8093 pb_spec.height = rect.height;
8094 pb_spec.x = rect.x;
8095 pb_spec.y = rect.y;
8096 #ifdef ocpnUSE_ocpnBitmap
8097 pb_spec.b_revrgb = true;
8098 #else
8099 pb_spec.b_revrgb = false;
8100 #endif
8101
8102 pb_spec.b_revrgb = false;
8103
8104 // Create and populate a compatible s57 Object
8105 S57Obj cobj;
8106 chart_context ctx;
8107 CreateCompatibleS57Object( pObj, &cobj, &ctx );
8108
8109 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
8110
8111 // Set up object SM rendering constants
8112 sm_parms transform;
8113 toSM( vp->clat, vp->clon, pObj->chart_ref_lat, pObj->chart_ref_lon, &transform.easting_vp_center, &transform.northing_vp_center );
8114
8115 // Create and populate a minimally compatible object container
8116 ObjRazRules rzRules;
8117 rzRules.obj = &cobj;
8118 rzRules.LUP = pContext->LUP;
8119 rzRules.sm_transform_parms = &transform;
8120 rzRules.child = pContext->ChildRazRules;
8121 rzRules.next = NULL;
8122 rzRules.mps = pContext->MPSRulesList;
8123
8124 ViewPort cvp = CreateCompatibleViewport( *vp );
8125
8126 // If the PlugIn does not support it nativiely, build a fully described Geomoetry
8127 if( !(gs_plib_flags & PLIB_CAPS_SINGLEGEO_BUFFER) ){
8128 if(!pObj->geoPtMulti){ // do this only once
8129 PolyTessGeo *tess = (PolyTessGeo *)pObj->pPolyTessGeo;
8130
8131 if(!tess)
8132 return 1; // bail on empty data
8133
8134 PolyTriGroup *ptg = new PolyTriGroup;
8135 ptg->tri_prim_head = tess->Get_PolyTriGroup_head()->tri_prim_head; //tph;
8136 ptg->bsingle_alloc = false;
8137 ptg->data_type = DATA_TYPE_DOUBLE;
8138 tess->Set_PolyTriGroup_head(ptg);
8139
8140 double *pd = (double *)malloc(sizeof(double));
8141 pObj->geoPtMulti = pd; //Hack hack
8142
8143 }
8144 }
8145
8146 if(pContext->LUP){
8147 // Do the render
8148 ps52plib->RenderAreaToDC( pdc, &rzRules, &cvp, &pb_spec );
8149
8150 // Update the PLIB context after the render operation
8151 UpdatePIObjectPlibContext( pObj, &cobj, &rzRules );
8152 }
8153
8154 return 1;
8155 }
8156
PI_PLIBRenderAreaToGL(const wxGLContext & glcc,PI_S57Obj * pObj,PlugIn_ViewPort * vp,wxRect & render_rect)8157 int PI_PLIBRenderAreaToGL( const wxGLContext &glcc, PI_S57Obj *pObj, PlugIn_ViewPort *vp, wxRect &render_rect )
8158 {
8159 #ifdef ocpnUSE_GL
8160 // Create and populate a compatible s57 Object
8161 S57Obj cobj;
8162 chart_context ctx;
8163 CreateCompatibleS57Object( pObj, &cobj, &ctx );
8164
8165 // chart_context *pct = (chart_context *)pObj->m_chart_context;
8166
8167 // If the PlugIn does not support it nativiely, build a fully described Geomoetry
8168
8169 if( !(gs_plib_flags & PLIB_CAPS_SINGLEGEO_BUFFER) ){
8170 if(!pObj->geoPtMulti ){ // only do this once
8171 PolyTessGeo *tess = (PolyTessGeo *)pObj->pPolyTessGeo;
8172
8173 if(!tess)
8174 return 1; // bail on empty data
8175
8176 PolyTriGroup *ptg = new PolyTriGroup; // this will leak a little, but is POD
8177 ptg->tri_prim_head = tess->Get_PolyTriGroup_head()->tri_prim_head;
8178 ptg->bsingle_alloc = false;
8179 ptg->data_type = DATA_TYPE_DOUBLE;
8180 tess->Set_PolyTriGroup_head(ptg);
8181
8182 // Mark this object using geoPtMulti
8183 // The malloc will get free'ed when the object is deleted.
8184 double *pd = (double *)malloc(sizeof(double));
8185 pObj->geoPtMulti = pd; //Hack hack
8186 }
8187 cobj.auxParm0 = -6; // signal that this object render cannot use VBO
8188 cobj.auxParm1 = -1; // signal that this object render cannot have single buffer conversion done
8189 }
8190 else { // it is a newer PLugIn, so can do single buffer conversion and VBOs
8191 if(pObj->auxParm0 < 1)
8192 cobj.auxParm0 = -7; // signal that this object render can use a persistent VBO for area triangle vertices
8193 }
8194
8195
8196 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
8197
8198 // Set up object SM rendering constants
8199 sm_parms transform;
8200 toSM( vp->clat, vp->clon, pObj->chart_ref_lat, pObj->chart_ref_lon, &transform.easting_vp_center, &transform.northing_vp_center );
8201
8202 // Create and populate a minimally compatible object container
8203 ObjRazRules rzRules;
8204 rzRules.obj = &cobj;
8205 rzRules.LUP = pContext->LUP;
8206 rzRules.sm_transform_parms = &transform;
8207 rzRules.child = pContext->ChildRazRules;
8208 rzRules.next = NULL;
8209 rzRules.mps = pContext->MPSRulesList;
8210
8211 if(pContext->LUP){
8212 ViewPort cvp = CreateCompatibleViewport( *vp );
8213
8214 // Do the render
8215 ps52plib->RenderAreaToGL( glcc, &rzRules, &cvp );
8216
8217
8218 // Update the PLIB context after the render operation
8219 UpdatePIObjectPlibContext( pObj, &cobj, &rzRules );
8220 }
8221
8222 #endif
8223 return 1;
8224
8225 }
8226
PI_PLIBRenderObjectToGL(const wxGLContext & glcc,PI_S57Obj * pObj,PlugIn_ViewPort * vp,wxRect & render_rect)8227 int PI_PLIBRenderObjectToGL( const wxGLContext &glcc, PI_S57Obj *pObj,
8228 PlugIn_ViewPort *vp, wxRect &render_rect )
8229 {
8230 // Create and populate a compatible s57 Object
8231 S57Obj cobj;
8232 chart_context ctx;
8233 CreateCompatibleS57Object( pObj, &cobj, &ctx );
8234
8235 S52PLIB_Context *pContext = (S52PLIB_Context *)pObj->S52_Context;
8236
8237 // Set up object SM rendering constants
8238 sm_parms transform;
8239 toSM( vp->clat, vp->clon, pObj->chart_ref_lat, pObj->chart_ref_lon, &transform.easting_vp_center, &transform.northing_vp_center );
8240
8241 // Create and populate a minimally compatible object container
8242 ObjRazRules rzRules;
8243 rzRules.obj = &cobj;
8244 rzRules.LUP = pContext->LUP;
8245 rzRules.sm_transform_parms = &transform;
8246 rzRules.child = pContext->ChildRazRules;
8247 rzRules.next = NULL;
8248 rzRules.mps = pContext->MPSRulesList;
8249
8250 if(pContext->LUP){
8251 ViewPort cvp = CreateCompatibleViewport( *vp );
8252
8253 // Do the render
8254 ps52plib->RenderObjectToGL( glcc, &rzRules, &cvp );
8255
8256 // Update the PLIB context after the render operation
8257 UpdatePIObjectPlibContext( pObj, &cobj, &rzRules );
8258 }
8259
8260 return 1;
8261
8262 }
8263
8264 /* API 1.13 */
8265
8266 /* API 1.13 adds some more common functions to avoid unnecessary code duplication */
8267
fromDMM_Plugin(wxString sdms)8268 double fromDMM_Plugin( wxString sdms )
8269 {
8270 return fromDMM( sdms );
8271 }
8272
SetCanvasRotation(double rotation)8273 void SetCanvasRotation(double rotation)
8274 {
8275 gFrame->GetPrimaryCanvas()->DoRotateCanvas( rotation );
8276 }
8277
GetCanvasTilt()8278 double GetCanvasTilt()
8279 {
8280 return gFrame->GetPrimaryCanvas()->GetVPTilt();
8281 }
8282
SetCanvasTilt(double tilt)8283 void SetCanvasTilt(double tilt)
8284 {
8285 gFrame->GetPrimaryCanvas()->DoTiltCanvas( tilt );
8286 }
8287
SetCanvasProjection(int projection)8288 void SetCanvasProjection(int projection)
8289 {
8290 gFrame->GetPrimaryCanvas()->SetVPProjection(projection);
8291 }
8292
8293 OcpnSound* g_PluginSound = SoundFactory( );
onPlugInPlaySoundExFinished(void * ptr)8294 static void onPlugInPlaySoundExFinished( void* ptr ) { }
8295
8296 // Start playing a sound to a given device and return status to plugin
PlugInPlaySoundEx(wxString & sound_file,int deviceIndex)8297 bool PlugInPlaySoundEx( wxString &sound_file, int deviceIndex )
8298 {
8299 bool ok = g_PluginSound->Load( sound_file, deviceIndex );
8300 if ( !ok ) {
8301 wxLogWarning( "Cannot load sound file: %s", sound_file );
8302 return false;
8303 }
8304 g_PluginSound->SetCmd( g_CmdSoundString.mb_str( wxConvUTF8 ) );
8305
8306 g_PluginSound->SetFinishedCallback( onPlugInPlaySoundExFinished, NULL );
8307 ok = g_PluginSound->Play( );
8308 if ( !ok ) {
8309 wxLogWarning( "Cannot play sound file: %s", sound_file );
8310 }
8311 return ok;
8312 }
8313
CheckEdgePan_PlugIn(int x,int y,bool dragging,int margin,int delta)8314 bool CheckEdgePan_PlugIn( int x, int y, bool dragging, int margin, int delta )
8315 {
8316 return gFrame->GetPrimaryCanvas()->CheckEdgePan( x, y, dragging, margin, delta );
8317 }
8318
GetIcon_PlugIn(const wxString & name)8319 wxBitmap GetIcon_PlugIn(const wxString & name)
8320 {
8321 ocpnStyle::Style* style = g_StyleManager->GetCurrentStyle();
8322 return style->GetIcon( name );
8323 }
8324
SetCursor_PlugIn(wxCursor * pCursor)8325 void SetCursor_PlugIn( wxCursor *pCursor )
8326 {
8327 gFrame->GetPrimaryCanvas()->pPlugIn_Cursor = pCursor;
8328 }
8329
AddChartDirectory(wxString & path)8330 void AddChartDirectory( wxString &path )
8331 {
8332 if( g_options )
8333 {
8334 g_options->AddChartDir( path );
8335 }
8336 }
8337
ForceChartDBUpdate()8338 void ForceChartDBUpdate()
8339 {
8340 if( g_options )
8341 {
8342 g_options->pScanCheckBox->SetValue(true);
8343 g_options->pUpdateCheckBox->SetValue(true);
8344 }
8345 }
8346
ForceChartDBRebuild()8347 void ForceChartDBRebuild()
8348 {
8349 if( g_options )
8350 {
8351 g_options->pUpdateCheckBox->SetValue(true);
8352 }
8353 }
8354
GetActiveOptionsDialog()8355 wxDialog *GetActiveOptionsDialog()
8356 {
8357 return g_options;
8358 }
8359
8360
PlatformDirSelectorDialog(wxWindow * parent,wxString * file_spec,wxString Title,wxString initDir)8361 int PlatformDirSelectorDialog( wxWindow *parent, wxString *file_spec, wxString Title, wxString initDir)
8362 {
8363 return g_Platform->DoDirSelectorDialog( parent, file_spec, Title, initDir);
8364 }
8365
PlatformFileSelectorDialog(wxWindow * parent,wxString * file_spec,wxString Title,wxString initDir,wxString suggestedName,wxString wildcard)8366 int PlatformFileSelectorDialog( wxWindow *parent, wxString *file_spec, wxString Title, wxString initDir,
8367 wxString suggestedName, wxString wildcard)
8368 {
8369 return g_Platform->DoFileSelectorDialog( parent, file_spec, Title, initDir,
8370 suggestedName, wildcard);
8371 }
8372
8373
8374
8375
8376 // http File Download Support
8377
8378 // OCPN_downloadEvent Implementation
8379
8380
OCPN_downloadEvent(wxEventType commandType,int id)8381 OCPN_downloadEvent::OCPN_downloadEvent(wxEventType commandType, int id)
8382 :wxEvent(id, commandType)
8383 {
8384 m_stat = OCPN_DL_UNKNOWN;
8385 m_condition = OCPN_DL_EVENT_TYPE_UNKNOWN;
8386 m_b_complete = false;
8387 m_sofarBytes = 0;
8388 }
8389
~OCPN_downloadEvent()8390 OCPN_downloadEvent::~OCPN_downloadEvent()
8391 {
8392 }
8393
Clone() const8394 wxEvent* OCPN_downloadEvent::Clone() const
8395 {
8396 OCPN_downloadEvent *newevent=new OCPN_downloadEvent(*this);
8397 newevent->m_stat=this->m_stat;
8398 newevent->m_condition=this->m_condition;
8399
8400 newevent->m_totalBytes=this->m_totalBytes;
8401 newevent->m_sofarBytes=this->m_sofarBytes;
8402 newevent->m_b_complete=this->m_b_complete;
8403
8404 return newevent;
8405 }
8406
8407 //const wxEventType wxEVT_DOWNLOAD_EVENT = wxNewEventType();
8408 DECL_EXP wxEventType wxEVT_DOWNLOAD_EVENT = wxNewEventType();
8409
8410
8411
8412
8413
8414 _OCPN_DLStatus g_download_status;
8415 _OCPN_DLCondition g_download_condition;
8416
8417 #define DL_EVENT_TIMER 4388
8418
8419 class PI_DLEvtHandler : public wxEvtHandler
8420 {
8421 public:
8422 PI_DLEvtHandler();
8423 ~PI_DLEvtHandler();
8424
8425 void onDLEvent( OCPN_downloadEvent &event);
8426 void setBackgroundMode( long ID, wxEvtHandler *handler );
8427 void clearBackgroundMode();
8428 void onTimerEvent(wxTimerEvent &event);
8429
8430 long m_id;
8431 wxTimer m_eventTimer;
8432 wxEvtHandler *m_download_evHandler;
8433
8434 long m_sofarBytes;
8435 long m_totalBytes;
8436
8437
8438 };
8439
8440
8441
8442
PI_DLEvtHandler()8443 PI_DLEvtHandler::PI_DLEvtHandler()
8444 {
8445 g_download_status = OCPN_DL_UNKNOWN;
8446 g_download_condition = OCPN_DL_EVENT_TYPE_UNKNOWN;
8447
8448 m_download_evHandler = NULL;
8449 m_id = -1;
8450 m_sofarBytes = 0;
8451 m_totalBytes = 0;
8452
8453
8454 }
8455
~PI_DLEvtHandler()8456 PI_DLEvtHandler::~PI_DLEvtHandler()
8457 {
8458 m_eventTimer.Stop();
8459 Disconnect(wxEVT_TIMER, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onTimerEvent);
8460
8461 }
8462
8463
onDLEvent(OCPN_downloadEvent & event)8464 void PI_DLEvtHandler::onDLEvent( OCPN_downloadEvent &event)
8465 {
8466 // qDebug() << "Got Event " << (int)event.getDLEventStatus() << (int)event.getDLEventCondition();
8467
8468 g_download_status = event.getDLEventStatus();
8469 g_download_condition = event.getDLEventCondition();
8470
8471 // This is an END event, happening at the end of BACKGROUND file download
8472 if(m_download_evHandler && ( OCPN_DL_EVENT_TYPE_END == event.getDLEventCondition()) ){
8473 OCPN_downloadEvent ev(wxEVT_DOWNLOAD_EVENT, 0);
8474 ev.setComplete(true);
8475 ev.setTransferred(m_sofarBytes);
8476 ev.setTotal(m_totalBytes);
8477
8478 ev.setDLEventStatus( event.getDLEventStatus());
8479 ev.setDLEventCondition( OCPN_DL_EVENT_TYPE_END );
8480
8481 m_download_evHandler->AddPendingEvent(ev);
8482 m_eventTimer.Stop();
8483 #ifdef __OCPN__ANDROID__
8484 finishAndroidFileDownload();
8485 #endif
8486 }
8487
8488 event.Skip();
8489 }
8490
setBackgroundMode(long ID,wxEvtHandler * handler)8491 void PI_DLEvtHandler::setBackgroundMode( long ID, wxEvtHandler *handler)
8492 {
8493 m_id = ID;
8494 m_download_evHandler = handler;
8495
8496 m_eventTimer.SetOwner( this, DL_EVENT_TIMER );
8497
8498 Connect(wxEVT_TIMER, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onTimerEvent);
8499 m_eventTimer.Start(1000, wxTIMER_CONTINUOUS);
8500
8501 }
8502
clearBackgroundMode()8503 void PI_DLEvtHandler::clearBackgroundMode()
8504 {
8505 m_download_evHandler = NULL;
8506 m_eventTimer.Stop();
8507 }
8508
8509
8510
onTimerEvent(wxTimerEvent & event)8511 void PI_DLEvtHandler::onTimerEvent(wxTimerEvent &event)
8512 {
8513 #ifdef __OCPN__ANDROID__
8514 // Query the download status, and post to the original requestor
8515 // This method only happens on Background file downloads
8516
8517 wxString sstat;
8518 int stat = queryAndroidFileDownload( m_id, &sstat );
8519
8520 OCPN_downloadEvent ev(wxEVT_DOWNLOAD_EVENT, 0);
8521 long sofarBytes = 0;
8522 long totalBytes = -1;
8523 long state = -1;
8524
8525 if(stat){ // some error
8526 qDebug() << "Error on queryAndroidFileDownload, ending download";
8527 ev.setComplete(true);
8528 ev.setTransferred(sofarBytes);
8529 ev.setTotal(totalBytes);
8530
8531 ev.setDLEventStatus( OCPN_DL_FAILED);
8532 ev.setDLEventCondition( OCPN_DL_EVENT_TYPE_END );
8533 }
8534 else{
8535 wxStringTokenizer tk(sstat, _T(";"));
8536 if( tk.HasMoreTokens() ){
8537 wxString token = tk.GetNextToken();
8538 token.ToLong(&state);
8539 token = tk.GetNextToken();
8540 token.ToLong(&sofarBytes);
8541 token = tk.GetNextToken();
8542 token.ToLong(&totalBytes);
8543 }
8544
8545 qDebug() << state << sofarBytes << totalBytes;
8546
8547 m_sofarBytes = sofarBytes;
8548 m_totalBytes = totalBytes;
8549
8550 ev.setTransferred(sofarBytes);
8551 ev.setTotal(totalBytes);
8552
8553 if(state == 16){ // error
8554 qDebug() << "Event OCPN_DL_FAILED/OCPN_DL_EVENT_TYPE_END";
8555 ev.setComplete(true);
8556 ev.setDLEventStatus( OCPN_DL_FAILED);
8557 ev.setDLEventCondition( OCPN_DL_EVENT_TYPE_END );
8558 }
8559 else if(state == 8){ // Completed OK
8560 qDebug() << "Event OCPN_DL_NO_ERROR/OCPN_DL_EVENT_TYPE_END";
8561 ev.setComplete(true);
8562 ev.setDLEventStatus( OCPN_DL_NO_ERROR);
8563 ev.setDLEventCondition( OCPN_DL_EVENT_TYPE_END );
8564 }
8565 else{
8566 ev.setComplete(false);
8567 ev.setDLEventStatus( OCPN_DL_UNKNOWN);
8568 ev.setDLEventCondition( OCPN_DL_EVENT_TYPE_PROGRESS );
8569 }
8570
8571
8572 //2;0;148686
8573 }
8574
8575 if(m_download_evHandler){
8576 // qDebug() << "Sending event on timer...";
8577 m_download_evHandler->AddPendingEvent(ev);
8578 }
8579
8580 // Background download is all done.
8581 if(OCPN_DL_EVENT_TYPE_END == ev.getDLEventCondition()){
8582 m_eventTimer.Stop();
8583 finishAndroidFileDownload();
8584 }
8585
8586
8587 #endif
8588 }
8589
8590
8591
8592 PI_DLEvtHandler *g_piEventHandler;
8593
8594
8595
8596
8597 // Blocking download of single file
OCPN_downloadFile(const wxString & url,const wxString & outputFile,const wxString & title,const wxString & message,const wxBitmap & bitmap,wxWindow * parent,long style,int timeout_secs)8598 _OCPN_DLStatus OCPN_downloadFile( const wxString& url, const wxString &outputFile,
8599 const wxString &title, const wxString &message,
8600 const wxBitmap& bitmap,
8601 wxWindow *parent, long style, int timeout_secs)
8602 {
8603 #ifdef __OCPN__ANDROID__
8604
8605 wxString msg = _T("Downloading file synchronously: ");
8606 msg += url; msg += _T(" to: "); msg += outputFile;
8607 wxLogMessage(msg);
8608
8609 // Create a single event handler to receive status events
8610 if(!g_piEventHandler)
8611 g_piEventHandler = new PI_DLEvtHandler;
8612
8613 // Reset global status indicators
8614 g_download_status = OCPN_DL_UNKNOWN;
8615 g_download_condition = OCPN_DL_EVENT_TYPE_UNKNOWN;
8616
8617 // Create a connection for the expected events from Android Activity
8618 g_piEventHandler->Connect(wxEVT_DOWNLOAD_EVENT, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onDLEvent);
8619
8620 long dl_ID = -1;
8621
8622 // Make sure the outputfile is a file URI
8623 wxString fURI = outputFile;
8624 if(!fURI.StartsWith(_T("file://"))){
8625 fURI.Prepend(_T("file://"));
8626 }
8627
8628 int res = startAndroidFileDownload( url, fURI, g_piEventHandler, &dl_ID );
8629 // Started OK?
8630 if(res){
8631 finishAndroidFileDownload();
8632 g_piEventHandler->Disconnect(wxEVT_DOWNLOAD_EVENT, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onDLEvent);
8633 //delete g_piEventHandler;
8634 return OCPN_DL_FAILED;
8635 }
8636
8637
8638 wxDateTime dl_start_time = wxDateTime::Now();
8639
8640 // Spin, waiting for timeout or event from downstream, and checking status
8641 while(1){
8642 wxTimeSpan dt = wxDateTime::Now() - dl_start_time;
8643 qDebug() << "Spin.." << dt.GetSeconds().GetLo();
8644
8645 if(dt.GetSeconds() > timeout_secs){
8646 qDebug() << "USER_TIMOUT";
8647 finishAndroidFileDownload();
8648 g_piEventHandler->Disconnect(wxEVT_DOWNLOAD_EVENT, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onDLEvent);
8649 //delete g_piEventHandler;
8650 return (OCPN_DL_USER_TIMEOUT);
8651 }
8652
8653 if(g_download_condition != OCPN_DL_EVENT_TYPE_UNKNOWN){
8654 if(OCPN_DL_EVENT_TYPE_END == g_download_condition){
8655 _OCPN_DLStatus ss = g_download_status;
8656 finishAndroidFileDownload();
8657 g_piEventHandler->Disconnect(wxEVT_DOWNLOAD_EVENT, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onDLEvent);
8658 //delete g_piEventHandler;
8659 qDebug() << "RETURN DL_END" << (int)ss;
8660 return ss; // The actual return code
8661 }
8662 }
8663
8664 wxString sstat;
8665 int stat = queryAndroidFileDownload( dl_ID, &sstat );
8666 if(stat){ // some error
8667 qDebug() << "Error on queryAndroidFileDownload";
8668 finishAndroidFileDownload();
8669 g_piEventHandler->Disconnect(wxEVT_DOWNLOAD_EVENT, (wxObjectEventFunction)(wxEventFunction)&PI_DLEvtHandler::onDLEvent);
8670 //delete g_piEventHandler;
8671
8672 return OCPN_DL_FAILED; // so abort
8673 }
8674
8675
8676 wxSleep(1);
8677 wxSafeYield();
8678 }
8679
8680 #else
8681 #ifdef OCPN_USE_CURL
8682 wxFileName tfn = wxFileName::CreateTempFileName( outputFile );
8683 wxFileOutputStream output( tfn.GetFullPath() );
8684
8685 wxCurlDownloadDialog ddlg(url, &output, title,
8686 message + url, bitmap, parent,
8687 style);
8688 wxCurlDialogReturnFlag ret = ddlg.RunModal();
8689 output.Close();
8690
8691 _OCPN_DLStatus result = OCPN_DL_UNKNOWN;
8692
8693 switch( ret )
8694 {
8695 case wxCDRF_SUCCESS:
8696 {
8697 if ( wxCopyFile( tfn.GetFullPath(), outputFile ) )
8698 result = OCPN_DL_NO_ERROR;
8699 else
8700 result = OCPN_DL_FAILED;
8701 break;
8702 }
8703 case wxCDRF_FAILED:
8704 {
8705 result = OCPN_DL_FAILED;
8706 break;
8707 }
8708 case wxCDRF_USER_ABORTED:
8709 {
8710 result = OCPN_DL_ABORTED;
8711 break;
8712 }
8713 default:
8714 wxASSERT( false ); // This should never happen because we handle all possible cases of ret
8715 }
8716 if( wxFileExists( tfn.GetFullPath() ) )
8717 wxRemoveFile ( tfn.GetFullPath() );
8718 return result;
8719 #else
8720 return OCPN_DL_FAILED;
8721 #endif
8722 #endif
8723 }
8724
8725
8726 // Non-Blocking download of single file
OCPN_downloadFileBackground(const wxString & url,const wxString & outputFile,wxEvtHandler * handler,long * handle)8727 _OCPN_DLStatus OCPN_downloadFileBackground( const wxString& url, const wxString &outputFile,
8728 wxEvtHandler *handler, long *handle)
8729 {
8730
8731 #ifdef __OCPN__ANDROID__
8732 wxString msg = _T("Downloading file asynchronously: ");
8733 msg += url; msg += _T(" to: "); msg += outputFile;
8734 wxLogMessage(msg);
8735
8736 // Create a single event handler to receive status events
8737
8738 if(!g_piEventHandler)
8739 g_piEventHandler = new PI_DLEvtHandler;
8740
8741
8742
8743 long dl_ID = -1;
8744
8745 int res = startAndroidFileDownload( url, outputFile, NULL/*g_piEventHandler*/, &dl_ID );
8746 // Started OK?
8747 if(res){
8748 finishAndroidFileDownload();
8749 return OCPN_DL_FAILED;
8750 }
8751
8752 // configure the local event handler for background transfer
8753 g_piEventHandler->setBackgroundMode(dl_ID, handler);
8754
8755
8756 if(handle)
8757 *handle = dl_ID;
8758
8759 return OCPN_DL_STARTED;
8760 #else
8761 #ifdef OCPN_USE_CURL
8762
8763 if( g_pi_manager->m_pCurlThread ) //We allow just one download at a time. Do we want more? Or at least return some other status in this case?
8764 return OCPN_DL_FAILED;
8765 g_pi_manager->m_pCurlThread = new wxCurlDownloadThread( g_pi_manager, CurlThreadId );
8766 bool http = (url.StartsWith(wxS("http:")) || url.StartsWith(wxS("https:")));
8767 bool keep = false;
8768 if (http && g_pi_manager->m_pCurl && dynamic_cast<wxCurlHTTP*>(g_pi_manager->m_pCurl.get())) {
8769 keep = true;
8770 }
8771 if (!keep) {
8772 g_pi_manager->m_pCurl = 0;
8773 }
8774
8775 bool failed = false;
8776 if ( !g_pi_manager->HandleCurlThreadError( g_pi_manager->m_pCurlThread->SetURL( url, g_pi_manager->m_pCurl ), g_pi_manager->m_pCurlThread, url ) )
8777 failed = true;
8778 if (!failed)
8779 {
8780 g_pi_manager->m_pCurl = g_pi_manager->m_pCurlThread->GetCurlSharedPtr();
8781 if (!g_pi_manager->HandleCurlThreadError(g_pi_manager->m_pCurlThread->SetOutputStream(new wxFileOutputStream(outputFile)), g_pi_manager->m_pCurlThread))
8782 failed = true;
8783 }
8784 if (!failed)
8785 {
8786 g_pi_manager->m_download_evHandler = handler;
8787 g_pi_manager->m_downloadHandle = handle;
8788
8789 wxCurlThreadError err = g_pi_manager->m_pCurlThread->Download();
8790 if (err != wxCTE_NO_ERROR)
8791 {
8792 g_pi_manager->HandleCurlThreadError(err, g_pi_manager->m_pCurlThread); // shows a message to the user
8793 g_pi_manager->m_pCurlThread->Abort();
8794 failed = true;
8795 }
8796 }
8797
8798 if( !failed )
8799 return OCPN_DL_STARTED;
8800
8801 if( g_pi_manager->m_pCurlThread )
8802 {
8803 if (g_pi_manager->m_pCurlThread->IsAlive())
8804 g_pi_manager->m_pCurlThread->Abort();
8805 if (g_pi_manager->m_pCurlThread->GetOutputStream())
8806 delete (g_pi_manager->m_pCurlThread->GetOutputStream());
8807 wxDELETE(g_pi_manager->m_pCurlThread);
8808 g_pi_manager->m_download_evHandler = NULL;
8809 g_pi_manager->m_downloadHandle = NULL;
8810 }
8811 g_pi_manager->m_pCurl = 0;
8812 #else
8813
8814 return OCPN_DL_FAILED;
8815 #endif
8816 return OCPN_DL_FAILED;
8817 #endif
8818 }
8819
OCPN_cancelDownloadFileBackground(long handle)8820 void OCPN_cancelDownloadFileBackground( long handle )
8821 {
8822 #ifdef OCPN_USE_CURL
8823
8824 #ifdef __OCPN__ANDROID__
8825 cancelAndroidFileDownload( handle );
8826 finishAndroidFileDownload();
8827 if(g_piEventHandler)
8828 g_piEventHandler->clearBackgroundMode();
8829 #else
8830 if( g_pi_manager->m_pCurlThread )
8831 {
8832 g_pi_manager->m_pCurlThread->Abort();
8833 delete (g_pi_manager->m_pCurlThread->GetOutputStream());
8834 wxDELETE(g_pi_manager->m_pCurlThread);
8835 g_pi_manager->m_download_evHandler = NULL;
8836 g_pi_manager->m_downloadHandle = NULL;
8837 }
8838 g_pi_manager->m_pCurl = 0;
8839 #endif
8840 #endif
8841 }
8842
OCPN_postDataHttp(const wxString & url,const wxString & parameters,wxString & result,int timeout_secs)8843 _OCPN_DLStatus OCPN_postDataHttp( const wxString& url, const wxString& parameters, wxString& result, int timeout_secs )
8844 {
8845 #ifndef __OCPN__ANDROID__
8846
8847 #ifdef OCPN_USE_CURL
8848
8849 wxCurlHTTP post;
8850 post.SetOpt(CURLOPT_TIMEOUT, timeout_secs);
8851 size_t res = post.Post( parameters.ToAscii(), parameters.Len(), url );
8852
8853 if( res )
8854 {
8855 result = wxString(post.GetResponseBody().c_str(), wxConvUTF8);
8856 return OCPN_DL_NO_ERROR;
8857 } else
8858 result = wxEmptyString;
8859
8860 return OCPN_DL_FAILED;
8861 #else
8862 return OCPN_DL_FAILED;
8863 #endif
8864 #else
8865
8866 wxString lparms = parameters;
8867 wxString postResult = doAndroidPOST( url, lparms, timeout_secs * 1000);
8868 if(postResult.IsSameAs(_T("NOK")))
8869 return OCPN_DL_FAILED;
8870
8871 result = postResult;
8872 return OCPN_DL_NO_ERROR;
8873
8874 #endif
8875
8876 }
8877
OCPN_isOnline()8878 bool OCPN_isOnline()
8879 {
8880 #ifdef __OCPN__ANDROID__
8881 return androidCheckOnline();
8882 #endif
8883
8884 #ifndef __OCPN__ANDROID__
8885 #ifdef OCPN_USE_CURL
8886
8887 if (wxDateTime::GetTimeNow() > g_pi_manager->m_last_online_chk + ONLINE_CHECK_RETRY)
8888 {
8889 wxCurlHTTP get;
8890 get.Head( _T("http://yahoo.com/") );
8891 g_pi_manager->m_last_online = get.GetResponseCode() > 0;
8892
8893 g_pi_manager->m_last_online_chk = wxDateTime::GetTimeNow();
8894 }
8895 return g_pi_manager->m_last_online;
8896 #else
8897 return false;
8898 #endif
8899 #endif
8900 }
8901
8902 #ifdef OCPN_USE_CURL
8903
8904 #ifndef __OCPN__ANDROID__
OnEndPerformCurlDownload(wxCurlEndPerformEvent & ev)8905 void PlugInManager::OnEndPerformCurlDownload(wxCurlEndPerformEvent &ev)
8906 {
8907 OCPN_downloadEvent event( wxEVT_DOWNLOAD_EVENT, 0 );
8908 if (ev.IsSuccessful()) {
8909 event.setDLEventStatus( OCPN_DL_NO_ERROR );
8910 }
8911 else {
8912 g_pi_manager->m_pCurl = 0;
8913 event.setDLEventStatus( OCPN_DL_FAILED );
8914 }
8915 event.setDLEventCondition( OCPN_DL_EVENT_TYPE_END );
8916 event.setComplete(true);
8917
8918 if(m_download_evHandler){
8919 m_download_evHandler->AddPendingEvent(event);
8920 m_download_evHandler = NULL;
8921 m_downloadHandle = NULL;
8922 }
8923
8924 if( m_pCurlThread )
8925 {
8926 m_pCurlThread->Wait();
8927 if(!m_pCurlThread->IsAborting()){
8928 delete (m_pCurlThread->GetOutputStream());
8929 wxDELETE(m_pCurlThread);
8930 }
8931 }
8932 }
8933
OnCurlDownload(wxCurlDownloadEvent & ev)8934 void PlugInManager::OnCurlDownload(wxCurlDownloadEvent &ev)
8935 {
8936 OCPN_downloadEvent event( wxEVT_DOWNLOAD_EVENT, 0 );
8937 event.setDLEventStatus( OCPN_DL_UNKNOWN );
8938 event.setDLEventCondition( OCPN_DL_EVENT_TYPE_PROGRESS );
8939 event.setTotal( ev.GetTotalBytes() );
8940 event.setTransferred( ev.GetDownloadedBytes() );
8941 event.setComplete(false);
8942
8943 if(m_download_evHandler){
8944 m_download_evHandler->AddPendingEvent(event);
8945 }
8946 }
8947
8948
HandleCurlThreadError(wxCurlThreadError err,wxCurlBaseThread * p,const wxString & url)8949 bool PlugInManager::HandleCurlThreadError(wxCurlThreadError err, wxCurlBaseThread *p, const wxString &url)
8950 {
8951 switch (err)
8952 {
8953 case wxCTE_NO_ERROR:
8954 return true; // ignore this
8955
8956 case wxCTE_NO_RESOURCE:
8957 wxLogError(wxS("Insufficient resources for correct execution of the program."));
8958 break;
8959
8960 case wxCTE_ALREADY_RUNNING:
8961 wxFAIL; // should never happen!
8962 break;
8963
8964 case wxCTE_INVALID_PROTOCOL:
8965 wxLogError(wxS("The URL '%s' uses an unsupported protocol."), url.c_str());
8966 break;
8967
8968 case wxCTE_NO_VALID_STREAM:
8969 wxFAIL; // should never happen - the user streams should always be valid!
8970 break;
8971
8972 case wxCTE_ABORTED:
8973 return true; // ignore this
8974
8975 case wxCTE_CURL_ERROR:
8976 {
8977 wxString err = wxS("unknown");
8978 if (p->GetCurlSession())
8979 err = wxString(p->GetCurlSession()->GetErrorString().c_str(), wxConvUTF8);
8980 wxLogError(wxS("Network error: %s"), err.c_str());
8981 }
8982 break;
8983 }
8984
8985 // stop the thread
8986 if (p->IsAlive()) p->Abort();
8987
8988 // this is an unrecoverable error:
8989 return false;
8990 }
8991 #endif
8992 #endif
8993
8994
LaunchDefaultBrowser_Plugin(wxString url)8995 bool LaunchDefaultBrowser_Plugin( wxString url )
8996 {
8997 if(g_Platform)
8998 g_Platform->platformLaunchDefaultBrowser( url );
8999
9000 return true;
9001 }
9002
9003 /* API 1.14 */
9004
PlugInAISDrawGL(wxGLCanvas * glcanvas,const PlugIn_ViewPort & vp)9005 void PlugInAISDrawGL( wxGLCanvas* glcanvas, const PlugIn_ViewPort &vp )
9006 {
9007 ViewPort ocpn_vp = CreateCompatibleViewport(vp);
9008
9009 ocpnDC dc(*glcanvas);
9010
9011 AISDraw(dc, ocpn_vp, NULL);
9012 }
9013
PlugInSetFontColor(const wxString TextElement,const wxColour color)9014 bool PlugInSetFontColor(const wxString TextElement, const wxColour color)
9015 {
9016 return FontMgr::Get().SetFontColor(TextElement, color);
9017 }
9018
9019 /* API 1.15 */
9020
PlugInGetDisplaySizeMM()9021 double PlugInGetDisplaySizeMM()
9022 {
9023 return g_Platform->GetDisplaySizeMM();
9024 }
9025
FindOrCreateFont_PlugIn(int point_size,wxFontFamily family,wxFontStyle style,wxFontWeight weight,bool underline,const wxString & facename,wxFontEncoding encoding)9026 wxFont* FindOrCreateFont_PlugIn( int point_size, wxFontFamily family,
9027 wxFontStyle style, wxFontWeight weight, bool underline,
9028 const wxString &facename,
9029 wxFontEncoding encoding)
9030 {
9031 return FontMgr::Get().FindOrCreateFont(point_size, family, style, weight, underline, facename, encoding);
9032 }
9033
PluginGetMinAvailableGshhgQuality()9034 int PluginGetMinAvailableGshhgQuality() { return gFrame->GetPrimaryCanvas()->GetMinAvailableGshhgQuality(); }
PluginGetMaxAvailableGshhgQuality()9035 int PluginGetMaxAvailableGshhgQuality() { return gFrame->GetPrimaryCanvas()->GetMaxAvailableGshhgQuality(); }
9036
9037 // disable builtin console canvas, and autopilot nmea sentences
PlugInHandleAutopilotRoute(bool enable)9038 void PlugInHandleAutopilotRoute(bool enable) { g_bPluginHandleAutopilotRoute = enable; }
9039
9040 /* API 1.16 */
GetSelectedWaypointGUID_Plugin()9041 wxString GetSelectedWaypointGUID_Plugin( )
9042 {
9043 ChartCanvas *cc = gFrame->GetFocusCanvas();
9044 if (cc && cc->GetSelectedRoutePoint() ) {
9045 return cc->GetSelectedRoutePoint()->m_GUID;
9046 }
9047 return wxEmptyString;
9048 }
9049
GetSelectedRouteGUID_Plugin()9050 wxString GetSelectedRouteGUID_Plugin( )
9051 {
9052 ChartCanvas *cc = gFrame->GetFocusCanvas();
9053 if (cc && cc->GetSelectedRoute() ) {
9054 return cc->GetSelectedRoute()->m_GUID;
9055 }
9056 return wxEmptyString;
9057 }
9058
GetSelectedTrackGUID_Plugin()9059 wxString GetSelectedTrackGUID_Plugin( )
9060 {
9061 ChartCanvas *cc = gFrame->GetFocusCanvas();
9062 if (cc && cc->GetSelectedTrack() ) {
9063 return cc->GetSelectedTrack()->m_GUID;
9064 }
9065 return wxEmptyString;
9066 }
9067
GetWaypoint_Plugin(const wxString & GUID)9068 std::unique_ptr<PlugIn_Waypoint> GetWaypoint_Plugin( const wxString& GUID)
9069 {
9070 std::unique_ptr<PlugIn_Waypoint> w(new PlugIn_Waypoint);
9071 GetSingleWaypoint(GUID, w.get());
9072 return w;
9073 }
9074
GetRoute_Plugin(const wxString & GUID)9075 std::unique_ptr<PlugIn_Route> GetRoute_Plugin( const wxString& GUID)
9076 {
9077 std::unique_ptr<PlugIn_Route> r;
9078 Route *route = g_pRouteMan->FindRouteByGUID( GUID );
9079 if (route == nullptr)
9080 return r;
9081
9082 r = std::unique_ptr<PlugIn_Route>(new PlugIn_Route);
9083 PlugIn_Route *dst_route = r.get();
9084
9085 // PlugIn_Waypoint *pwp;
9086 RoutePoint *src_wp;
9087 wxRoutePointListNode *node = route->pRoutePointList->GetFirst();
9088
9089 while( node ) {
9090 src_wp = node->GetData();
9091
9092 PlugIn_Waypoint *dst_wp = new PlugIn_Waypoint();
9093 PlugInFromRoutePoint(dst_wp, src_wp);
9094
9095 dst_route->pWaypointList->Append( dst_wp );
9096
9097 node = node->GetNext();
9098 }
9099 dst_route->m_NameString = route->m_RouteNameString;
9100 dst_route->m_StartString = route->m_RouteStartString;
9101 dst_route->m_EndString = route->m_RouteEndString;
9102 dst_route->m_GUID = route->m_GUID;
9103
9104 return r;
9105 }
9106
GetTrack_Plugin(const wxString & GUID)9107 std::unique_ptr<PlugIn_Track> GetTrack_Plugin( const wxString& GUID)
9108 {
9109 std::unique_ptr<PlugIn_Track> t;
9110 return t;
9111 }
9112
PluginGetFocusCanvas()9113 wxWindow* PluginGetFocusCanvas()
9114 {
9115 return g_focusCanvas;
9116 }
9117
PluginGetOverlayRenderCanvas()9118 wxWindow* PluginGetOverlayRenderCanvas()
9119 {
9120 //if(g_overlayCanvas)
9121 return g_overlayCanvas;
9122 //else
9123
9124 }
9125
CanvasJumpToPosition(wxWindow * canvas,double lat,double lon,double scale)9126 void CanvasJumpToPosition( wxWindow *canvas, double lat, double lon, double scale)
9127 {
9128 ChartCanvas *oCanvas = wxDynamicCast( canvas, ChartCanvas );
9129 if(oCanvas)
9130 gFrame->JumpToPosition( oCanvas, lat, lon, scale);
9131
9132 }
9133
ShuttingDown(void)9134 bool ShuttingDown( void )
9135 {
9136 return g_bquiting;
9137 }
9138
GetCanvasUnderMouse(void)9139 wxWindow* GetCanvasUnderMouse( void )
9140 {
9141 return gFrame->GetCanvasUnderMouse();
9142 }
9143
GetCanvasIndexUnderMouse(void)9144 int GetCanvasIndexUnderMouse( void )
9145 {
9146 ChartCanvas *l_canvas = gFrame->GetCanvasUnderMouse();
9147 if(l_canvas) {
9148 for(unsigned int i = 0; i < g_canvasArray.GetCount(); ++i) {
9149 if(l_canvas == g_canvasArray[i])
9150 return i;
9151 }
9152 }
9153 return 0;
9154 }
9155
9156 // std::vector<wxWindow *> GetCanvasArray()
9157 // {
9158 // std::vector<wxWindow *> rv;
9159 // for(unsigned int i=0 ; i < g_canvasArray.GetCount() ; i++){
9160 // ChartCanvas *cc = g_canvasArray.Item(i);
9161 // rv.push_back(cc);
9162 // }
9163 //
9164 // return rv;
9165 // }
9166
GetCanvasByIndex(int canvasIndex)9167 wxWindow *GetCanvasByIndex( int canvasIndex )
9168 {
9169 if(g_canvasConfig == 0)
9170 return gFrame->GetPrimaryCanvas();
9171 else{
9172 if( (canvasIndex >=0) && g_canvasArray[canvasIndex] ){
9173 return g_canvasArray[canvasIndex];
9174 }
9175 }
9176 return NULL;
9177 }
9178
9179
CheckMUIEdgePan_PlugIn(int x,int y,bool dragging,int margin,int delta,int canvasIndex)9180 bool CheckMUIEdgePan_PlugIn( int x, int y, bool dragging, int margin, int delta, int canvasIndex )
9181 {
9182 if(g_canvasConfig == 0)
9183 return gFrame->GetPrimaryCanvas()->CheckEdgePan( x, y, dragging, margin, delta );
9184 else{
9185 if( (canvasIndex >=0) && g_canvasArray[canvasIndex] ){
9186 return g_canvasArray[canvasIndex]->CheckEdgePan( x, y, dragging, margin, delta );
9187 }
9188 }
9189
9190 return false;
9191 }
9192
SetMUICursor_PlugIn(wxCursor * pCursor,int canvasIndex)9193 void SetMUICursor_PlugIn( wxCursor *pCursor, int canvasIndex )
9194 {
9195 if(g_canvasConfig == 0)
9196 gFrame->GetPrimaryCanvas()->pPlugIn_Cursor = pCursor;
9197 else{
9198 if( (canvasIndex >=0) && g_canvasArray[canvasIndex] ){
9199 g_canvasArray[canvasIndex]->pPlugIn_Cursor = pCursor;
9200 }
9201 }
9202 }
9203
GetCanvasCount()9204 int GetCanvasCount( )
9205 {
9206 if(g_canvasConfig == 1)
9207 return 2;
9208 // else
9209 return 1;
9210 }
9211
GetLatLonFormat()9212 int GetLatLonFormat()
9213 {
9214 return g_iSDMMFormat;
9215 }
9216
GetMasterToolbarRect()9217 wxRect GetMasterToolbarRect()
9218 {
9219 if(g_MainToolbar)
9220 return g_MainToolbar->GetRect();
9221 else
9222 return wxRect(0,0,1,1);
9223 }
9224
9225 /* API 1.17 */
9226
ZeroXTE()9227 void ZeroXTE() {
9228 if (g_pRouteMan) {
9229 g_pRouteMan->ZeroCurrentXTEToActivePoint();
9230 }
9231 }
9232