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, &region);
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