/* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2010, Anders Lund */ #include "config.h" #include "routemanagerdialog.h" // For compilers that support precompilation, includes "wx/wx.h". #include #ifndef WX_PRECOMP #include #endif #include #include #include #include #include #include #include #include "styles.h" #include "dychart.h" #include "navutil.h" #include "MarkInfo.h" #include "RoutePropDlgImpl.h" #include "routeman.h" #include "georef.h" #include "chartbase.h" #include "Layer.h" #include "SendToGpsDlg.h" #include "TrackPropDlg.h" #include "AIS_Decoder.h" #include "OCPNPlatform.h" #include "Track.h" #include "Route.h" #include "chcanv.h" extern wxImage LoadSVGIcon( wxString filename, int width, int height ); #ifdef __OCPN__ANDROID__ #include "androidUTIL.h" #endif #define DIALOG_MARGIN 3 enum { rmVISIBLE = 0, rmROUTENAME, rmROUTEDESC };// RMColumns; enum { colTRKVISIBLE = 0, colTRKNAME, colTRKLENGTH }; enum { colLAYVISIBLE = 0, colLAYNAME, colLAYITEMS, colLAYPERSIST }; enum { colWPTICON = 0, colWPTSCALE, colWPTNAME, colWPTDIST }; // GLOBALS :0 extern RouteList *pRouteList; extern TrackList *pTrackList; extern LayerList *pLayerList; extern wxString GetLayerName(int id); extern RoutePropDlgImpl *pRoutePropDialog; extern TrackPropDlg *pTrackPropDialog; extern Routeman *g_pRouteMan; extern MyConfig *pConfig; extern ActiveTrack *g_pActiveTrack; extern WayPointman *pWayPointMan; extern MarkInfoDlg *g_pMarkInfoDialog; extern MyFrame *gFrame; extern Select *pSelect; extern double gLat, gLon; extern double gCog, gSog; extern bool g_bShowLayers; extern wxString g_default_wp_icon; extern AIS_Decoder *g_pAIS; extern OCPNPlatform *g_Platform; extern bool g_bOverruleScaMin; //Helper for conditional file name separator void appendOSDirSlash(wxString* pString); static int SortRouteTrack(const int order, const wxString &it1, const wxString &it2) { if(order & 1) return it2.CmpNoCase(it1); return it1.CmpNoCase(it2); } // sort callback. Sort by route name. static int sort_route_name_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortRoutesOnName(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortRoutesOnName(long item1, long item2, long list) #endif { return SortRouteTrack(sort_route_name_dir, ((Route*)item1)->GetName(), ((Route*)item2)->GetName()); } // sort callback. Sort by route Destination. static int sort_route_to_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortRoutesOnTo(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortRoutesOnTo(long item1, long item2, long list) #endif { return SortRouteTrack(sort_route_to_dir, ((Route*)item1)->GetTo(), ((Route*)item2)->GetTo()); } // sort callback. Sort by track name. static int sort_track_name_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortTracksOnName(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortTracksOnName(long item1, long item2, long list) #endif { return SortRouteTrack(sort_track_name_dir, ((Track*)item1)->GetName(), ((Track*)item2)->GetName()); } static int SortDouble(const int order, const double &it1, const double &it2) { double l1; double l2; if(order & 1) { l1 = it2; l2 = it1; } else { l1 = it1; l2 = it2; } if( l1 == l2 ) return 0; if (l2 < l1) return 1; return -1; } // sort callback. Sort by track length. static int sort_track_len_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortTracksOnDistance(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortTracksOnDistance(long item1, long item2, long list) #endif { return SortDouble(sort_track_len_dir, ((Track*)item1)->Length(), ((Track*)item2)->Length()); } static int sort_wp_key; static int sort_track_key; // sort callback. Sort by wpt name. static int sort_wp_name_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortWaypointsOnName(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortWaypointsOnName(long item1, long item2, long list) #endif { RoutePoint *pRP1 = (RoutePoint *)item1; RoutePoint *pRP2 = (RoutePoint *)item2; if(pRP1 && pRP2) { if(sort_wp_name_dir & 1) return pRP2->GetName().CmpNoCase(pRP1->GetName()); else return pRP1->GetName().CmpNoCase(pRP2->GetName()); } else return 0; } // sort callback. Sort by wpt distance. static int sort_wp_len_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortWaypointsOnDistance(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortWaypointsOnDistance(long item1, long item2, long list) #endif { double dst1, dst2; DistanceBearingMercator( ((RoutePoint*)item1)->m_lat, ((RoutePoint*)item1)->m_lon, gLat, gLon, NULL, &dst1 ); DistanceBearingMercator( ((RoutePoint*)item2)->m_lat, ((RoutePoint*)item2)->m_lon, gLat, gLon, NULL, &dst2 ); return SortDouble(sort_wp_len_dir, dst1, dst2); } // sort callback. Sort by layer name. static int sort_layer_name_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortLayersOnName(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortLayersOnName(long item1, long item2, long list) #endif { return SortRouteTrack(sort_layer_name_dir, ((Layer*)item1)->m_LayerName, ((Layer*)item2)->m_LayerName); } // sort callback. Sort by layer size. static int sort_layer_len_dir; #if wxCHECK_VERSION(2, 9, 0) static int wxCALLBACK SortLayersOnSize(wxIntPtr item1, wxIntPtr item2, wxIntPtr list) #else int wxCALLBACK SortLayersOnSize(long item1, long item2, long list) #endif { return SortDouble(sort_layer_len_dir, ((Layer*)item1)->m_NoOfItems, ((Layer*)item2)->m_NoOfItems); } // event table. Mostly empty, because I find it much easier to see what is connected to what // using Connect() where possible, so that it is visible in the code. BEGIN_EVENT_TABLE(RouteManagerDialog, wxFrame) EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, RouteManagerDialog::OnTabSwitch) // This should work under Windows :-( EVT_CLOSE(RouteManagerDialog::OnClose) EVT_COMMAND(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED, RouteManagerDialog::OnOK) EVT_CHAR_HOOK(RouteManagerDialog::OnKey) END_EVENT_TABLE() void RouteManagerDialog::OnKey( wxKeyEvent& ke ) { if ( ke.GetKeyCode() == WXK_ESCAPE ) Close( true ); else ke.Skip(); } void RouteManagerDialog::OnTabSwitch( wxNotebookEvent &event ) { if( !m_pNotebook ) return; int current_page = m_pNotebook->GetSelection(); if( current_page == 3 ) { // if( btnImport ) btnImport->Enable( false ); // if( btnExport ) btnExport->Enable( false ); // if( btnExportViz ) btnExportViz->Enable( false ); } else { if( btnImport ) btnImport->Enable( true ); if( btnExport ) btnExport->Enable( true ); if( btnExportViz ) btnExportViz->Enable( true ); } event.Skip(); // remove if using event table... why? } // implementation bool RouteManagerDialog::instanceFlag = false; RouteManagerDialog* RouteManagerDialog::single = NULL; RouteManagerDialog* RouteManagerDialog::getInstance(wxWindow *parent) { if(! instanceFlag) { single = new RouteManagerDialog(parent); instanceFlag = true; return single; } else { return single; } } RouteManagerDialog::RouteManagerDialog( wxWindow *parent ) { long style = wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER | wxFRAME_FLOAT_ON_PARENT; wxFrame::Create( parent, -1, wxString( _("Route & Mark Manager") ), wxDefaultPosition, wxDefaultSize, style ); wxFont *qFont = GetOCPNScaledFont(_("Dialog")); SetFont( *qFont ); m_lastWptItem = -1; m_lastTrkItem = -1; m_lastRteItem = -1; sort_wp_key = SORT_ON_NAME; sort_track_key = SORT_ON_NAME; btnImport = NULL; btnExport = NULL; btnExportViz = NULL; Create(); } void RouteManagerDialog::Create() { // Get a text height metric for reference int char_width, char_height; GetTextExtent(_T("W"), &char_width, &char_height); m_charWidth = char_width; wxBoxSizer* itemBoxSizer1 = new wxBoxSizer( wxVERTICAL ); SetSizer( itemBoxSizer1 ); m_pNotebook = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxSize( -1, -1 ), wxNB_TOP ); itemBoxSizer1->Add( m_pNotebook, 1, wxALL | wxEXPAND, 5 ); // Create "Routes" panel m_pPanelRte = new wxPanel( m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL); wxBoxSizer *sbsRoutes = new wxBoxSizer( wxHORIZONTAL ); m_pPanelRte->SetSizer( sbsRoutes ); m_pNotebook->AddPage( m_pPanelRte, _("Routes") ); sort_wp_len_dir = 1; sort_wp_name_dir = 0; sort_track_len_dir = 1; sort_route_to_dir = 0; sort_track_name_dir = 0; sort_route_name_dir = 0; sort_layer_name_dir = 0; sort_layer_len_dir = 1; m_listIconSize = 2 * GetCharHeight(); // Setup GUI wxBoxSizer* bSizerRteContents; bSizerRteContents = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgSizerFilterRte; fgSizerFilterRte = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizerFilterRte->AddGrowableCol( 1 ); fgSizerFilterRte->SetFlexibleDirection( wxBOTH ); fgSizerFilterRte->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_stFilterRte = new wxStaticText( m_pPanelRte, wxID_ANY, _("Filter"), wxDefaultPosition, wxDefaultSize, 0 ); m_stFilterRte->Wrap( -1 ); fgSizerFilterRte->Add( m_stFilterRte, 0, wxALL, 5 ); m_tFilterRte = new wxTextCtrl( m_pPanelRte, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); fgSizerFilterRte->Add( m_tFilterRte, 1, wxALL|wxEXPAND, 5 ); bSizerRteContents->Add( fgSizerFilterRte, 0, wxEXPAND, 5 ); m_tFilterRte->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( RouteManagerDialog::OnFilterChanged ), NULL, this ); m_pRouteListCtrl = new wxListCtrl( m_pPanelRte, -1, wxDefaultPosition, wxSize(-1, -1), wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES | wxBORDER_SUNKEN/*|wxLC_VRULES*/); #ifdef __OCPN__ANDROID__ m_pRouteListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet()); #endif m_pRouteListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(RouteManagerDialog::OnRteSelected), NULL, this ); m_pRouteListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler(RouteManagerDialog::OnRteSelected), NULL, this ); m_pRouteListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RouteManagerDialog::OnRteDefaultAction), NULL, this ); m_pRouteListCtrl->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnRteToggleVisibility), NULL, this ); m_pRouteListCtrl->Connect( wxEVT_COMMAND_LIST_COL_CLICK, wxListEventHandler(RouteManagerDialog::OnRteColumnClicked), NULL, this ); bSizerRteContents->Add( m_pRouteListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN ); sbsRoutes->Add( bSizerRteContents, 1, wxEXPAND, 5 ); // Columns: visibility ctrl, name // note that under MSW for SetColumnWidth() to work we need to create the // items with images initially even if we specify dummy image id m_pRouteListCtrl->InsertColumn( rmVISIBLE, _("Show"), wxLIST_FORMAT_LEFT, 10 /*4 * char_width*/ ); m_pRouteListCtrl->InsertColumn( rmROUTENAME, _("Route Name"), wxLIST_FORMAT_LEFT, 15 * char_width ); m_pRouteListCtrl->InsertColumn( rmROUTEDESC, _("From <-> To"), wxLIST_FORMAT_LEFT, 10 * char_width ); // Buttons: Delete, Properties... wxBoxSizer *bsRouteButtons = new wxBoxSizer( wxVERTICAL ); sbsRoutes->Add( bsRouteButtons, 0, wxEXPAND ); wxScrolledWindow *winr = new wxScrolledWindow( m_pPanelRte, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL); winr->SetScrollRate(0,5); bsRouteButtons->Add( winr, 1, wxALL | wxEXPAND, DIALOG_MARGIN ); wxBoxSizer *bsRouteButtonsInner = new wxBoxSizer( wxVERTICAL ); winr->SetSizer(bsRouteButtonsInner); btnRteProperties = new wxButton( winr, -1, _("&Properties") + _T("...") ); bsRouteButtonsInner->Add( btnRteProperties, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteProperties->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRtePropertiesClick), NULL, this ); btnRteActivate = new wxButton( winr, -1, _("&Activate") ); bsRouteButtonsInner->Add( btnRteActivate, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteActivate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteActivateClick), NULL, this ); btnRteActivate->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnRteBtnLeftDown), NULL, this ); btnRteZoomto = new wxButton( winr, -1, _("&Center View") ); bsRouteButtonsInner->Add( btnRteZoomto, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteZoomto->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteZoomtoClick), NULL, this ); btnRteZoomto->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnRteBtnLeftDown), NULL, this ); btnRteReverse = new wxButton( winr, -1, _("&Reverse") ); bsRouteButtonsInner->Add( btnRteReverse, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteReverse->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteReverseClick), NULL, this ); btnRteDelete = new wxButton( winr, -1, _("&Delete") ); bsRouteButtonsInner->Add( btnRteDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteDeleteClick), NULL, this ); btnRteExport = new wxButton( winr, -1, _("&Export selected...") ); bsRouteButtonsInner->Add( btnRteExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteExportClick), NULL, this ); btnRteSendToGPS = new wxButton( winr, -1, _("&Send to GPS") ); bsRouteButtonsInner->Add( btnRteSendToGPS, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteSendToGPS->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteSendToGPSClick), NULL, this ); bsRouteButtonsInner->AddSpacer( 10 ); btnRteDeleteAll = new wxButton( winr, -1, _("&Delete All") ); bsRouteButtonsInner->Add( btnRteDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnRteDeleteAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnRteDeleteAllClick), NULL, this ); // Create "Tracks" panel m_pPanelTrk = new wxPanel( m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL ); wxBoxSizer* sbsTracks = new wxBoxSizer( wxHORIZONTAL ); m_pPanelTrk->SetSizer( sbsTracks ); m_pNotebook->AddPage( m_pPanelTrk, _("Tracks") ); wxBoxSizer* bSizerTrkContents; bSizerTrkContents = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgSizerFilterTrk; fgSizerFilterTrk = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizerFilterTrk->AddGrowableCol( 1 ); fgSizerFilterTrk->SetFlexibleDirection( wxBOTH ); fgSizerFilterTrk->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_stFilterTrk = new wxStaticText( m_pPanelTrk, wxID_ANY, _("Filter"), wxDefaultPosition, wxDefaultSize, 0 ); m_stFilterTrk->Wrap( -1 ); fgSizerFilterTrk->Add( m_stFilterTrk, 0, wxALL, 5 ); m_tFilterTrk = new wxTextCtrl( m_pPanelTrk, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); fgSizerFilterTrk->Add( m_tFilterTrk, 1, wxALL|wxEXPAND, 5 ); bSizerTrkContents->Add( fgSizerFilterTrk, 0, wxEXPAND, 5 ); m_tFilterTrk->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( RouteManagerDialog::OnFilterChanged ), NULL, this ); m_pTrkListCtrl = new wxListCtrl( m_pPanelTrk, -1, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES | wxBORDER_SUNKEN/*|wxLC_VRULES*/); #ifdef __OCPN__ANDROID__ m_pTrkListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet()); #endif m_pTrkListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(RouteManagerDialog::OnTrkSelected), NULL, this ); m_pTrkListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler(RouteManagerDialog::OnTrkSelected), NULL, this ); m_pTrkListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RouteManagerDialog::OnTrkDefaultAction), NULL, this ); m_pTrkListCtrl->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnTrkToggleVisibility), NULL, this ); m_pTrkListCtrl->Connect( wxEVT_COMMAND_LIST_COL_CLICK, wxListEventHandler(RouteManagerDialog::OnTrkColumnClicked), NULL, this ); m_pTrkListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, wxListEventHandler(RouteManagerDialog::OnTrkRightClick), NULL, this ); this->Connect( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(RouteManagerDialog::OnTrkMenuSelected), NULL, this ); bSizerTrkContents->Add( m_pTrkListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN ); sbsTracks->Add( bSizerTrkContents, 1, wxEXPAND, 5 ); m_pTrkListCtrl->InsertColumn( colTRKVISIBLE, _("Show"), wxLIST_FORMAT_LEFT, 4 * char_width ); m_pTrkListCtrl->InsertColumn( colTRKNAME, _("Track Name"), wxLIST_FORMAT_LEFT, 20 * char_width ); m_pTrkListCtrl->InsertColumn( colTRKLENGTH, _("Length"), wxLIST_FORMAT_LEFT, 5 * char_width ); wxBoxSizer *bsTrkButtons = new wxBoxSizer( wxVERTICAL ); sbsTracks->Add( bsTrkButtons, 0, wxEXPAND ); wxScrolledWindow *wint = new wxScrolledWindow( m_pPanelTrk, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL); wint->SetScrollRate(0,5); bsTrkButtons->Add( wint, 1, wxALL | wxEXPAND, DIALOG_MARGIN ); wxBoxSizer *bsTrkButtonsInner = new wxBoxSizer( wxVERTICAL ); wint->SetSizer(bsTrkButtonsInner); btnTrkNew = new wxButton( wint, -1, _("&Start Track") ); bsTrkButtonsInner->Add( btnTrkNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkNewClick), NULL, this ); btnTrkProperties = new wxButton( wint, -1, _("&Properties") ); bsTrkButtonsInner->Add( btnTrkProperties, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkProperties->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkPropertiesClick), NULL, this ); btnTrkDelete = new wxButton( wint, -1, _("&Delete") ); bsTrkButtonsInner->Add( btnTrkDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkDeleteClick), NULL, this ); btnTrkExport = new wxButton( wint, -1, _("&Export selected...") ); bsTrkButtonsInner->Add( btnTrkExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkExportClick), NULL, this ); btnTrkRouteFromTrack = new wxButton( wint, -1, _("Route from Track") ); bsTrkButtonsInner->Add( btnTrkRouteFromTrack, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkRouteFromTrack->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkRouteFromTrackClick), NULL, this ); bsTrkButtonsInner->AddSpacer( 10 ); btnTrkDeleteAll = new wxButton( wint, -1, _("&Delete All") ); bsTrkButtonsInner->Add( btnTrkDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnTrkDeleteAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnTrkDeleteAllClick), NULL, this ); // Create "Waypoints" panel m_pPanelWpt = new wxPanel( m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL ); wxBoxSizer* sbsWpts = new wxBoxSizer( wxHORIZONTAL ); m_pPanelWpt->SetSizer( sbsWpts ); m_pNotebook->AddPage( m_pPanelWpt, _("Waypoints") ); wxBoxSizer* bSizerWptContents; bSizerWptContents = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgSizerFilterWpt; fgSizerFilterWpt = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizerFilterWpt->AddGrowableCol( 1 ); fgSizerFilterWpt->SetFlexibleDirection( wxBOTH ); fgSizerFilterWpt->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_stFilterWpt = new wxStaticText( m_pPanelWpt, wxID_ANY, _("Filter"), wxDefaultPosition, wxDefaultSize, 0 ); m_stFilterWpt->Wrap( -1 ); fgSizerFilterWpt->Add( m_stFilterWpt, 0, wxALL, 5 ); m_tFilterWpt = new wxTextCtrl( m_pPanelWpt, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); fgSizerFilterWpt->Add( m_tFilterWpt, 1, wxALL|wxEXPAND, 5 ); bSizerWptContents->Add( fgSizerFilterWpt, 0, wxEXPAND, 5 ); m_tFilterWpt->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( RouteManagerDialog::OnFilterChanged ), NULL, this ); m_pWptListCtrl = new wxListCtrl( m_pPanelWpt, -1, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SORT_ASCENDING | wxLC_HRULES | wxBORDER_SUNKEN/*|wxLC_VRULES*/); #ifdef __OCPN__ANDROID__ m_pWptListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet()); #endif m_pWptListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(RouteManagerDialog::OnWptSelected), NULL, this ); m_pWptListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler(RouteManagerDialog::OnWptSelected), NULL, this ); m_pWptListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RouteManagerDialog::OnWptDefaultAction), NULL, this ); m_pWptListCtrl->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnWptToggleVisibility), NULL, this ); m_pWptListCtrl->Connect( wxEVT_COMMAND_LIST_COL_CLICK, wxListEventHandler(RouteManagerDialog::OnWptColumnClicked), NULL, this ); bSizerWptContents->Add( m_pWptListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN ); sbsWpts->Add( bSizerWptContents, 1, wxEXPAND, 5 ); m_pWptListCtrl->InsertColumn( colWPTICON, _("Icon"), wxLIST_FORMAT_LEFT, 4 * char_width ); m_pWptListCtrl->InsertColumn( colWPTSCALE, _("Scale"), wxLIST_FORMAT_LEFT, 8 * char_width ); m_pWptListCtrl->InsertColumn( colWPTNAME, _("Waypoint Name"), wxLIST_FORMAT_LEFT, 15 * char_width ); m_pWptListCtrl->InsertColumn( colWPTDIST, _("Distance from own ship"), wxLIST_FORMAT_LEFT, 14 * char_width ); wxBoxSizer *bsWptButtons = new wxBoxSizer( wxVERTICAL ); sbsWpts->Add( bsWptButtons, 0, wxEXPAND ); wxScrolledWindow *winw = new wxScrolledWindow( m_pPanelWpt, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL); winw->SetScrollRate(0,5); bsWptButtons->Add( winw, 1, wxALL | wxEXPAND, DIALOG_MARGIN ); wxBoxSizer *bsWptButtonsInner = new wxBoxSizer( wxVERTICAL ); winw->SetSizer(bsWptButtonsInner); btnWptNew = new wxButton( winw, -1, _("&New") ); bsWptButtonsInner->Add( btnWptNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptNewClick), NULL, this ); btnWptProperties = new wxButton( winw, -1, _("&Properties") ); bsWptButtonsInner->Add( btnWptProperties, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptProperties->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptPropertiesClick), NULL, this ); btnWptZoomto = new wxButton( winw, -1, _("&Center View") ); bsWptButtonsInner->Add( btnWptZoomto, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptZoomto->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptZoomtoClick), NULL, this ); btnWptDelete = new wxButton( winw, -1, _("&Delete") ); bsWptButtonsInner->Add( btnWptDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptDeleteClick), NULL, this ); btnWptGoTo = new wxButton( winw, -1, _("&Go To") ); bsWptButtonsInner->Add( btnWptGoTo, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptGoTo->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptGoToClick), NULL, this ); btnWptExport = new wxButton( winw, -1, _("&Export selected...") ); bsWptButtonsInner->Add( btnWptExport, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptExportClick), NULL, this ); btnWptSendToGPS = new wxButton( winw, -1, _("&Send to GPS") ); bsWptButtonsInner->Add( btnWptSendToGPS, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptSendToGPS->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptSendToGPSClick), NULL, this ); bsWptButtonsInner->AddSpacer( 10 ); btnWptDeleteAll = new wxButton( winw, -1, _("Delete All") ); bsWptButtonsInner->Add( btnWptDeleteAll, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnWptDeleteAll->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnWptDeleteAllClick), NULL, this ); wxBoxSizer *itemBoxSizer5 = new wxBoxSizer( wxHORIZONTAL ); itemBoxSizer1->Add( itemBoxSizer5, 0, wxALL | wxEXPAND ); wxBoxSizer *itemBoxSizer6 = new wxBoxSizer( wxHORIZONTAL ); itemBoxSizer5->Add( itemBoxSizer6, 1, wxALL | wxEXPAND ); btnImport = new wxButton( this, -1, _("I&mport GPX...") ); itemBoxSizer6->Add( btnImport, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN ); btnImport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnImportClick), NULL, this ); /* * btnExport = new wxButton( this, -1, _("E&xport All...") ); * itemBoxSizer6->Add( btnExport, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN ); * btnExport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, * wxCommandEventHandler(RouteManagerDialog::OnExportClick), NULL, this ); */ btnExportViz = new wxButton( this, -1, _("Export All Visible...") ); itemBoxSizer6->Add( btnExportViz, 0, wxALL | wxALIGN_LEFT, DIALOG_MARGIN ); btnExportViz->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnExportVizClick), NULL, this ); // Dialog OK button itemBoxSizer6->Add( 0, 0, 1, wxEXPAND, 5 ); // Spacer itemBoxSizer6->Add( new wxButton( this, wxID_OK ), 0, wxALL, DIALOG_MARGIN ); // Create "Layers" panel m_pPanelLay = new wxPanel( m_pNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL ); wxBoxSizer* sbsLayers = new wxBoxSizer( wxHORIZONTAL ); m_pPanelLay->SetSizer( sbsLayers ); m_pNotebook->AddPage( m_pPanelLay, _("Layers") ); wxBoxSizer* bSizerLayContents; bSizerLayContents = new wxBoxSizer( wxVERTICAL ); wxFlexGridSizer* fgSizerFilterLay; fgSizerFilterLay = new wxFlexGridSizer( 0, 2, 0, 0 ); fgSizerFilterLay->AddGrowableCol( 1 ); fgSizerFilterLay->SetFlexibleDirection( wxBOTH ); fgSizerFilterLay->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); m_stFilterLay = new wxStaticText( m_pPanelLay, wxID_ANY, _("Filter"), wxDefaultPosition, wxDefaultSize, 0 ); m_stFilterLay->Wrap( -1 ); fgSizerFilterLay->Add( m_stFilterLay, 0, wxALL, 5 ); m_tFilterLay = new wxTextCtrl( m_pPanelLay, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); fgSizerFilterLay->Add( m_tFilterLay, 1, wxALL|wxEXPAND, 5 ); bSizerLayContents->Add( fgSizerFilterLay, 0, wxEXPAND, 5 ); m_tFilterLay->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( RouteManagerDialog::OnFilterChanged ), NULL, this ); m_pLayListCtrl = new wxListCtrl( m_pPanelLay, -1, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING | wxLC_HRULES | wxBORDER_SUNKEN/*|wxLC_VRULES*/); #ifdef __OCPN__ANDROID__ m_pLayListCtrl->GetHandle()->setStyleSheet(getAdjustedDialogStyleSheet()); #endif m_pLayListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler(RouteManagerDialog::OnLaySelected), NULL, this ); m_pLayListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler(RouteManagerDialog::OnLaySelected), NULL, this ); m_pLayListCtrl->Connect( wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler(RouteManagerDialog::OnLayDefaultAction), NULL, this ); m_pLayListCtrl->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler(RouteManagerDialog::OnLayToggleVisibility), NULL, this ); m_pLayListCtrl->Connect( wxEVT_COMMAND_LIST_COL_CLICK, wxListEventHandler(RouteManagerDialog::OnLayColumnClicked), NULL, this ); bSizerLayContents->Add( m_pLayListCtrl, 1, wxEXPAND | wxALL, DIALOG_MARGIN ); sbsLayers->Add( bSizerLayContents, 1, wxEXPAND, 5 ); m_pLayListCtrl->InsertColumn( colLAYVISIBLE, _T(""), wxLIST_FORMAT_LEFT, 4 * char_width ); m_pLayListCtrl->InsertColumn( colLAYNAME, _("Layer Name"), wxLIST_FORMAT_LEFT, 14 * char_width ); m_pLayListCtrl->InsertColumn( colLAYITEMS, _("No. of items"), wxLIST_FORMAT_LEFT, 10 * char_width ); m_pLayListCtrl->InsertColumn( colLAYPERSIST, _("Layer type"), wxLIST_FORMAT_LEFT, 10 * char_width); wxBoxSizer *bsLayButtons = new wxBoxSizer( wxVERTICAL ); sbsLayers->Add( bsLayButtons, 0, wxEXPAND); wxScrolledWindow *winl = new wxScrolledWindow( m_pPanelLay, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL | wxVSCROLL); winl->SetScrollRate(0,5); bsLayButtons->Add( winl, 1, wxALL | wxEXPAND, DIALOG_MARGIN ); wxBoxSizer *bsLayButtonsInner = new wxBoxSizer( wxVERTICAL ); winl->SetSizer(bsLayButtonsInner); btnLayNew = new wxButton( winl, -1, _("Create Temporary layer") ); bsLayButtonsInner->Add( btnLayNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnLayNew->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnLayNewClick), NULL, this ); btnPerLayNew = new wxButton(winl, -1, _("Create Persistent layer")); bsLayButtonsInner->Add(btnPerLayNew, 0, wxALL | wxEXPAND, DIALOG_MARGIN); btnPerLayNew->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnPerLayNewClick), NULL, this); btnLayDelete = new wxButton( winl, -1, _("&Delete") ); bsLayButtonsInner->Add( btnLayDelete, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); btnLayDelete->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnLayDeleteClick), NULL, this ); cbLayToggleChart = new wxCheckBox( winl, -1, _("Show on chart") ); bsLayButtonsInner->Add( cbLayToggleChart, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); cbLayToggleChart->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnLayToggleChartClick), NULL, this ); cbLayToggleNames = new wxCheckBox( winl, -1, _("Show WPT names"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER ); bsLayButtonsInner->Add( cbLayToggleNames, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); cbLayToggleNames->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnLayToggleNamesClick), NULL, this ); cbLayToggleListing = new wxCheckBox( winl, -1, _("List contents") ); bsLayButtonsInner->Add( cbLayToggleListing, 0, wxALL | wxEXPAND, DIALOG_MARGIN ); cbLayToggleListing->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler(RouteManagerDialog::OnLayToggleListingClick), NULL, this ); RecalculateSize(); int imageRefSize = m_charWidth * 2; //g_Platform->GetDisplayDPmm() * 4; wxImageList *imglist = new wxImageList( imageRefSize, imageRefSize, true, 1 ); // Load eye icons wxString UserIconPath = g_Platform->GetSharedDataDir() + _T("uidata") + wxFileName::GetPathSeparator(); wxImage iconSVG = LoadSVGIcon( UserIconPath + _T("eye.svg"), imageRefSize, imageRefSize ); if(iconSVG.IsOk()){ iconSVG.Resize( wxSize(imageRefSize, imageRefSize), wxPoint(0,0)); // Avoid wxImageList size asserts imglist->Add( wxBitmap( iconSVG ) ); } iconSVG = LoadSVGIcon( UserIconPath + _T("eyex.svg"), imageRefSize, imageRefSize ); if(iconSVG.IsOk()){ iconSVG.Resize( wxSize(imageRefSize, imageRefSize), wxPoint(0,0)); imglist->Add( wxBitmap( iconSVG ) ); } m_pRouteListCtrl->AssignImageList( imglist, wxIMAGE_LIST_SMALL ); #ifdef __OCPN__ANDROID__ m_pRouteListCtrl->GetHandle() ->setIconSize(QSize(imageRefSize, imageRefSize)); #endif // Assign will handle destroy, Set will not. It's OK, that's what we want m_pTrkListCtrl->SetImageList( imglist, wxIMAGE_LIST_SMALL ); m_pWptListCtrl->SetImageList( pWayPointMan->Getpmarkicon_image_list(m_listIconSize), wxIMAGE_LIST_SMALL ); m_pLayListCtrl->SetImageList( imglist, wxIMAGE_LIST_SMALL ); SetColorScheme(); UpdateLists(); // This should work under Linux :-( //m_pNotebook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(RouteManagerDialog::OnTabSwitch), NULL, this); m_bNeedConfigFlush = false; } RouteManagerDialog::~RouteManagerDialog() { delete m_pRouteListCtrl; delete m_pTrkListCtrl; delete m_pWptListCtrl; delete m_pLayListCtrl; delete btnRteDelete; delete btnRteExport; delete btnRteZoomto; delete btnRteProperties; delete btnRteActivate; delete btnRteReverse; delete btnRteSendToGPS; delete btnRteDeleteAll; delete btnTrkNew; delete btnTrkProperties; delete btnTrkDelete; delete btnTrkExport; delete btnTrkRouteFromTrack; delete btnTrkDeleteAll; delete btnWptNew; delete btnWptProperties; delete btnWptZoomto; delete btnWptDelete; delete btnWptGoTo; delete btnWptExport; delete btnWptSendToGPS; delete btnWptDeleteAll; delete btnLayNew; //delete btnLayProperties; delete cbLayToggleChart; delete cbLayToggleListing; delete cbLayToggleNames; delete btnLayDelete; delete btnImport; delete btnExport; delete btnExportViz; btnImport = NULL; btnExport = NULL; btnExportViz = NULL; delete m_pNotebook; instanceFlag = false; } void RouteManagerDialog::RecalculateSize() { // All of this dialog layout is expandable, so we need to set a specific size target // for the onscreen display. // The size will then be adjusted so that it fits within the parent's client area, with some padding // Get a text height metric for reference int char_width, char_height; GetTextExtent(_T("W"), &char_width, &char_height); wxSize sz; sz.x = 60 * char_width; sz.y = 30 * char_height; wxSize dsize = GetParent()->GetClientSize(); sz.y = wxMin(sz.y, dsize.y - (0 * char_height)); sz.x = wxMin(sz.x, dsize.x - (0 * char_height)); SetClientSize(sz); wxSize fsize = GetSize(); fsize.y = wxMin(fsize.y, dsize.y - (0 * char_height)); fsize.x = wxMin(fsize.x, dsize.x - (0 * char_height)); SetSize(fsize); CentreOnParent(); } void RouteManagerDialog::OnClose(wxCloseEvent& event) { #ifdef __WXGTK__ gFrame->Raise(); #endif Hide(); // pRouteManagerDialog = NULL; } void RouteManagerDialog::OnOK(wxCommandEvent& event) { #ifdef __WXGTK__ gFrame->Raise(); #endif Hide(); } void RouteManagerDialog::SetColorScheme() { DimeControl( this ); } void RouteManagerDialog::UpdateRouteListCtrl() { // if an item was selected, make it selected again if it still exist long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); wxUIntPtr selected_id = wxUIntPtr(0); if( item != -1 ) selected_id = m_pRouteListCtrl->GetItemData( item ); // Delete existing items m_pRouteListCtrl->DeleteAllItems(); // then add routes to the listctrl RouteList::iterator it; int index = 0; int list_index = 0; for( it = ( *pRouteList ).begin(); it != ( *pRouteList ).end(); ++it, ++index ) { if( !( *it )->IsListed() ) continue; if( ! ( *it )->GetName().Upper().Contains(m_tFilterRte->GetValue().Upper()) ) { continue; } wxListItem li; li.SetId( list_index ); li.SetImage( ( *it )->IsVisible() ? 0 : 1 ); li.SetData( *it ); li.SetText( _T("") ); li.SetAlign(wxLIST_FORMAT_LEFT); if( ( *it )->m_bRtIsActive ) { wxFont font = *wxNORMAL_FONT; font.SetWeight( wxFONTWEIGHT_BOLD ); li.SetFont( font ); } long idx = m_pRouteListCtrl->InsertItem( li ); wxString name = ( *it )->m_RouteNameString; if( name.IsEmpty() ) name = _("(Unnamed Route)"); m_pRouteListCtrl->SetItem( idx, rmROUTENAME, name ); wxString startend = ( *it )->m_RouteStartString; if( !( *it )->m_RouteEndString.IsEmpty() ) startend.append(_(" - ") + ( *it )->m_RouteEndString ); m_pRouteListCtrl->SetItem( idx, rmROUTEDESC, startend ); wxListItem lic; lic.SetId( list_index ); lic.SetColumn(1); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pRouteListCtrl->SetItem( lic ); lic.SetColumn(2); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pRouteListCtrl->SetItem( lic ); list_index++; } m_pRouteListCtrl->SortItems( SortRoutesOnName, (wxIntPtr)NULL ); m_pRouteListCtrl->SetColumnWidth(0, 4 * m_charWidth); // restore selection if possible // NOTE this will select a different item, if one is deleted // (the next route will get that index). if( selected_id != wxUIntPtr(0) ) { item = m_pRouteListCtrl->FindItem( -1, selected_id ); m_pRouteListCtrl->SetItemState( item, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED ); } if( (m_lastRteItem >= 0) && (m_pRouteListCtrl->GetItemCount()) ) m_pRouteListCtrl->EnsureVisible( m_lastRteItem ); UpdateRteButtons(); } void RouteManagerDialog::UpdateRteButtons() { // enable/disable buttons long selected_index_index = m_pRouteListCtrl->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); bool enable1 = m_pRouteListCtrl->GetSelectedItemCount() == 1; bool enablemultiple = m_pRouteListCtrl->GetSelectedItemCount() >= 1; m_lastRteItem = selected_index_index; btnRteDelete->Enable( m_pRouteListCtrl->GetSelectedItemCount() > 0 ); btnRteZoomto->Enable( enable1 ); btnRteProperties->Enable( enable1 ); btnRteReverse->Enable( enable1 ); btnRteExport->Enable( enablemultiple ); btnRteSendToGPS->Enable( enable1 ); btnRteDeleteAll->Enable( enablemultiple ); // set activate button text Route *route = NULL; if( enable1 ) route = (Route*)m_pRouteListCtrl->GetItemData( selected_index_index ); if( !g_pRouteMan->IsAnyRouteActive() ) { btnRteActivate->Enable( enable1 ); if( enable1 ) btnRteActivate->SetLabel( _("Activate") ); } else { if( enable1 ) { if( route && route->m_bRtIsActive ) { btnRteActivate->Enable( enable1 ); btnRteActivate->SetLabel( _("Deactivate") ); } else btnRteActivate->Enable( false ); } else btnRteActivate->Enable( false ); } } void RouteManagerDialog::MakeAllRoutesInvisible() { RouteList::iterator it; long index = 0; for( it = ( *pRouteList ).begin(); it != ( *pRouteList ).end(); ++it, ++index ) { if( ( *it )->IsVisible() ) { // avoid config updating as much as possible! ( *it )->SetVisible( false ); m_pRouteListCtrl->SetItemImage( m_pRouteListCtrl->FindItem( -1, index ), 1 ); // Likely not same order :0 pConfig->UpdateRoute( *it ); // auch, flushes config to disk. FIXME } } } void RouteManagerDialog::ZoomtoRoute( Route *route ) { // Calculate bbox center LLBBox RBBox = route->GetBBox(); double clat = (RBBox.GetMinLat() + RBBox.GetMaxLat()) / 2; double clon = (RBBox.GetMinLon() + RBBox.GetMaxLon()) / 2; // Calculate ppm double rw, rh, ppm; // route width, height, final ppm scale to use int ww, wh; // chart window width, height // route bbox width in nm DistanceBearingMercator( RBBox.GetMinLat(), RBBox.GetMinLon(), RBBox.GetMinLat(), RBBox.GetMaxLon(), NULL, &rw ); // route bbox height in nm DistanceBearingMercator( RBBox.GetMinLat(), RBBox.GetMinLon(), RBBox.GetMaxLat(), RBBox.GetMinLon(), NULL, &rh ); gFrame->GetPrimaryCanvas()->GetSize( &ww, &wh ); ppm = wxMin(ww/(rw*1852), wh/(rh*1852)) * ( 100 - fabs( clat ) ) / 90; ppm = wxMin(ppm, 1.0); gFrame->JumpToPosition( gFrame->GetPrimaryCanvas(), clat, clon, ppm ); m_bNeedConfigFlush = true; } //BEGIN Event handlers void RouteManagerDialog::OnRteDeleteClick( wxCommandEvent &event ) { RouteList list; int answer = OCPNMessageBox( this, _("Are you sure you want to delete the selected object(s)"), wxString( _("OpenCPN Alert") ), wxYES_NO ); if ( answer != wxID_YES ) return; bool busy = false; if( m_pRouteListCtrl->GetSelectedItemCount() ) { ::wxBeginBusyCursor(); gFrame->CancelAllMouseRoute(); m_bNeedConfigFlush = true; busy = true; } long item = -1; for ( ;; ) { item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; Route *proute_to_delete = (Route*)m_pRouteListCtrl->GetItemData( item ); if( proute_to_delete ) list.Append( proute_to_delete ); } if( busy ) { for(unsigned int i=0 ; i < list.GetCount() ; i++) { Route *route = list.Item(i)->GetData(); if( route ) { pConfig->DeleteConfigRoute( route ); g_pRouteMan->DeleteRoute( route ); } } m_lastRteItem = -1; UpdateRouteListCtrl(); UpdateTrkListCtrl(); gFrame->InvalidateAllCanvasUndo(); gFrame->RefreshAllCanvas(); ::wxEndBusyCursor(); } } void RouteManagerDialog::OnRteDeleteAllClick( wxCommandEvent &event ) { int dialog_ret = OCPNMessageBox( this, _("Are you sure you want to delete routes?"), wxString( _("OpenCPN Alert") ), wxYES_NO ); if( dialog_ret == wxID_YES ) { if( g_pRouteMan->GetpActiveRoute() ) g_pRouteMan->DeactivateRoute(); gFrame->CancelAllMouseRoute(); g_pRouteMan->DeleteAllRoutes(); // TODO Seth // m_pSelectedRoute = NULL; // m_pFoundRoutePoint = NULL; // m_pFoundRoutePointSecond = NULL; m_lastRteItem = -1; UpdateRouteListCtrl(); // Also need to update the track list control, since routes and tracks share a common global list (pRouteList) UpdateTrkListCtrl(); if( pRoutePropDialog ) pRoutePropDialog->Hide(); gFrame->InvalidateAllCanvasUndo(); gFrame->RefreshAllCanvas(); m_bNeedConfigFlush = true; } } void RouteManagerDialog::OnRtePropertiesClick( wxCommandEvent &event ) { // Show routeproperties dialog for selected route long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Route *route = (Route*)m_pRouteListCtrl->GetItemData( item ); if( !route ) return; pRoutePropDialog = RoutePropDlgImpl::getInstance( GetParent() ); pRoutePropDialog->SetRouteAndUpdate( route ); if( !pRoutePropDialog->IsShown() ) pRoutePropDialog->Show(); m_bNeedConfigFlush = true; } void RouteManagerDialog::OnRteZoomtoClick( wxCommandEvent &event ) { // Zoom into the bounding box of the selected route long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; // optionally make this route exclusively visible if( m_bCtrlDown ) MakeAllRoutesInvisible(); Route *route = (Route*)m_pRouteListCtrl->GetItemData( item ); if( !route ) return; // Ensure route is visible if( !route->IsVisible() ) { route->SetVisible( true ); m_pRouteListCtrl->SetItemImage( item, route->IsVisible() ? 0 : 1 ); pConfig->UpdateRoute( route ); } ZoomtoRoute( route ); } void RouteManagerDialog::OnRteReverseClick( wxCommandEvent &event ) { // Reverse selected route long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Route *route = (Route*)m_pRouteListCtrl->GetItemData( item ); if( !route ) return; if( route->m_bIsInLayer ) return; int ask_return = OCPNMessageBox( this, g_pRouteMan->GetRouteReverseMessage(), _("Rename Waypoints?"), wxYES_NO | wxCANCEL ); if( ask_return != wxID_CANCEL ) { bool rename = ( ask_return == wxID_YES ); pSelect->DeleteAllSelectableRouteSegments( route ); route->Reverse( rename ); pSelect->AddAllSelectableRouteSegments( route ); // update column 2 - create a UpdateRouteItem(index) instead? wxString startend = route->m_RouteStartString; if( !route->m_RouteEndString.IsEmpty() ) startend.append( _(" - ") + route->m_RouteEndString ); m_pRouteListCtrl->SetItem( item, 2, startend ); pConfig->UpdateRoute( route ); gFrame->RefreshAllCanvas(); } m_bNeedConfigFlush = true; } void RouteManagerDialog::OnRteExportClick( wxCommandEvent &event ) { RouteList list; wxString suggested_name = _T("routes"); long item = -1; for ( ;; ) { item = m_pRouteListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; Route *proute_to_export = (Route*) m_pRouteListCtrl->GetItemData( item ); if( proute_to_export ) { list.Append( proute_to_export ); if( proute_to_export->m_RouteNameString != wxEmptyString ) suggested_name = proute_to_export->m_RouteNameString; } } ExportGPXRoutes( this, &list, suggested_name ); } void RouteManagerDialog::OnRteActivateClick( wxCommandEvent &event ) { // Activate the selected route, unless it already is long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; if( m_bCtrlDown ) MakeAllRoutesInvisible(); Route *route = (Route*)m_pRouteListCtrl->GetItemData( item ); if( !route ) return; if( !route->m_bRtIsActive ) { if( !route->IsVisible() ) { route->SetVisible( true ); m_pRouteListCtrl->SetItemImage( item, 0, 0 ); } ZoomtoRoute( route ); RoutePoint *best_point = g_pRouteMan->FindBestActivatePoint( route, gLat, gLon, gCog, gSog ); g_pRouteMan->ActivateRoute( route, best_point ); // g_pRouteMan->ActivateRoute(route); } else g_pRouteMan->DeactivateRoute(); UpdateRouteListCtrl(); pConfig->UpdateRoute( route ); gFrame->RefreshAllCanvas(); // btnRteActivate->SetLabel(route->m_bRtIsActive ? _("Deactivate") : _("Activate")); m_bNeedConfigFlush = true; } void RouteManagerDialog::OnRteToggleVisibility( wxMouseEvent &event ) { wxPoint pos = event.GetPosition(); int flags = 0; long clicked_index = m_pRouteListCtrl->HitTest( pos, flags ); // Clicking Visibility column? if( clicked_index > -1 && event.GetX() < m_pRouteListCtrl->GetColumnWidth( rmVISIBLE ) ) { // Process the clicked item Route *route = (Route*)m_pRouteListCtrl->GetItemData( clicked_index ); int wpts_set_viz = wxID_YES; bool invizsharedwpts = true; bool has_shared_wpts = g_pRouteMan->DoesRouteContainSharedPoints(route); if( has_shared_wpts && route->IsVisible() ) { wpts_set_viz = OCPNMessageBox( this, _("Do you also want to make the shared waypoints being part of this route invisible?"), _("Question"), wxYES_NO ); invizsharedwpts = (wpts_set_viz == wxID_YES); } route->SetVisible( !route->IsVisible(), invizsharedwpts ); route->SetSharedWPViz( !invizsharedwpts); m_pRouteListCtrl->SetItemImage( clicked_index, route->IsVisible() ? 0 : 1 ); ::wxBeginBusyCursor(); pConfig->UpdateRoute( route ); gFrame->RefreshAllCanvas(); // We need to update the waypoint list control only if the visibility of shared waypoints might have changed. if( has_shared_wpts ) UpdateWptListCtrlViz(); ::wxEndBusyCursor(); } // Allow wx to process... event.Skip(); } // FIXME add/remove route segments/waypoints from selectable items, so there are no // hidden selectables! This should probably be done outside this class! // The problem is that the current waypoint class does not provide good support // for this, there is a "visible" property, but no means for proper management. // Jan. 28 2010: Ideas: // - Calculate on the fly how many visible routes use a waypoint. // This requires a semidouble loop (routes, waypoints in visible routes). It could // be done by the function getting the selection. Potentially somewhat slow? // - OR keep a property in waypoints telling that // (A number, increased/decreased for each waypoint by Route::SetVisible()). // Immediate result when detecting the selectable object, small overhead in // Route::SetVisible(). I prefer this. // - We also need to know if the waypoint should otherwise be visible, // ie it is a "normal" waypoint used in the route (then it should be visible // in all cases). Is this possible with current code? // - Get rid of the Select objects, they do no good! They should be replaced with a function // in the application, the search would reqire equal amount of looping, but less // dereferencing pointers, and it would remove the overhead of keeping and maintaining // the extra pointer lists. void RouteManagerDialog::OnRteBtnLeftDown( wxMouseEvent &event ) { m_bCtrlDown = event.ControlDown(); event.Skip(); } void RouteManagerDialog::OnRteSelected( wxListEvent &event ) { long clicked_index = event.m_itemIndex; // Process the clicked item Route *route = (Route*)m_pRouteListCtrl->GetItemData( clicked_index ); // route->SetVisible(!route->IsVisible()); m_pRouteListCtrl->SetItemImage( clicked_index, route->IsVisible() ? 0 : 1 ); // pConfig->UpdateRoute(route); gFrame->RefreshAllCanvas(); UpdateRteButtons(); } void RouteManagerDialog::OnRteColumnClicked( wxListEvent &event ) { if( event.m_col == 1 ) { sort_route_name_dir++; m_pRouteListCtrl->SortItems( SortRoutesOnName, (wxIntPtr)NULL ); } else if( event.m_col == 2 ) { sort_route_to_dir++; m_pRouteListCtrl->SortItems( SortRoutesOnTo, (wxIntPtr)NULL ); } } void RouteManagerDialog::OnRteSendToGPSClick( wxCommandEvent &event ) { long item = -1; item = m_pRouteListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Route *route = (Route*)m_pRouteListCtrl->GetItemData( item ); if( !route ) return; SendToGpsDlg *pdlg = new SendToGpsDlg(); pdlg->SetRoute( route ); wxFont fo = GetOCPNGUIScaledFont(_T("Dialog")); pdlg->SetFont(fo); wxString source; pdlg->Create( NULL, -1, _( "Send to GPS" ) + _T( "..." ), source ); #ifdef __WXOSX__ HideWithEffect(wxSHOW_EFFECT_BLEND ); #endif pdlg->ShowModal(); #ifdef __WXOSX__ ShowWithEffect(wxSHOW_EFFECT_BLEND ); #endif pdlg->Destroy(); } void RouteManagerDialog::OnRteDefaultAction( wxListEvent &event ) { wxCommandEvent evt; OnRtePropertiesClick( evt ); } void RouteManagerDialog::OnTrkDefaultAction( wxListEvent &event ) { wxCommandEvent evt; OnTrkPropertiesClick( evt ); } void RouteManagerDialog::OnTrkRightClick( wxListEvent &event ) { wxMenu menu; wxMenuItem* mergeItem = menu.Append( TRACK_MERGE, _("&Merge Selected Tracks") ); mergeItem->Enable( m_pTrkListCtrl->GetSelectedItemCount() > 1 ); wxMenuItem* cleanItem = menu.Append( TRACK_CLEAN, _("Reduce Data...") ); cleanItem->Enable( m_pTrkListCtrl->GetSelectedItemCount() == 1 ); wxMenuItem* copyItem = menu.Append( TRACK_COPY_TEXT, _("&Copy as text") ); copyItem->Enable( m_pTrkListCtrl->GetSelectedItemCount() > 0 ); PopupMenu( &menu ); } static bool CompareTracks( Track* track1, Track* track2 ) { TrackPoint* start1 = track1->GetPoint(0); TrackPoint* start2 = track2->GetPoint(0); return start1->GetCreateTime() < start2->GetCreateTime(); } void RouteManagerDialog::OnTrkMenuSelected( wxCommandEvent &event ) { int item = -1; switch( event.GetId() ) { case TRACK_CLEAN: { item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) break; Track* track = (Track*)m_pTrkListCtrl->GetItemData( item ); if( track->IsRunning() ) { wxBell(); break; } const wxString choices[] = { _T("5.0"), _T("10.0"), _T("20.0"), _T("50.0"), _T("100.0") }; wxSingleChoiceDialog precisionDlg ( this, _("Select the maximum error allowed (in meters)\nafter data reduction:"), _("Reduce Data Precision"), 5, choices ); #ifdef __WXOSX__ precisionDlg.ShowWindowModal(); while ( precisionDlg.IsShown() ) { wxMilliSleep(10); wxYield(); } int result = precisionDlg.GetReturnCode(); #else int result = precisionDlg.ShowModal(); #endif if( result == wxID_CANCEL ) break; double precision = 5.0; switch( precisionDlg.GetSelection() ) { case 0: precision = 5.0; break; case 1: precision = 10.0; break; case 2: precision = 20.0; break; case 3: precision = 50.0; break; case 4: precision = 100.0; break; } int pointsBefore = track->GetnPoints(); int reduction = track->Simplify( precision ); gFrame->Refresh( false ); reduction = 100 * reduction / pointsBefore; wxString msg = wxString::Format( _("The amount of data used by the track\n was reduced by %d%%."), reduction ); OCPNMessageBox( this, msg, _("OpenCPN info"), wxICON_INFORMATION | wxOK ); UpdateTrkListCtrl(); UpdateRouteListCtrl(); break; } case TRACK_COPY_TEXT: { wxString csvString; while( 1 ) { item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) break; Track *track = (Track*)m_pTrkListCtrl->GetItemData( item ); csvString << track->GetName() << _T("\t") << wxString::Format( _T("%.1f"), track->Length() ) << _T("\t") << _T("\n"); } if( wxTheClipboard->Open() ) { wxTextDataObject* data = new wxTextDataObject; data->SetText( csvString ); wxTheClipboard->SetData( data ); wxTheClipboard->Close(); } break; } case TRACK_MERGE: { Track* targetTrack = NULL; TrackPoint* tPoint; TrackPoint* newPoint; TrackPoint* lastPoint; std::vector mergeList; std::vector deleteList; bool runningSkipped = false; ::wxBeginBusyCursor(); while( 1 ) { item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) break; Track* track = (Track*)m_pTrkListCtrl->GetItemData( item ); mergeList.push_back( track ); } std::sort(mergeList.begin(), mergeList.end(), CompareTracks ); targetTrack = mergeList[ 0 ]; lastPoint = targetTrack->GetLastPoint(); for(auto const& mergeTrack: mergeList) { if(mergeTrack == *mergeList.begin()) continue; if( mergeTrack->IsRunning() ) { runningSkipped = true; continue; } for(int i=0; iGetnPoints(); i++) { tPoint = mergeTrack->GetPoint(i); newPoint = new TrackPoint( tPoint->m_lat, tPoint->m_lon, tPoint->GetCreateTime() ); targetTrack->AddPoint( newPoint ); pSelect->AddSelectableTrackSegment( lastPoint->m_lat, lastPoint->m_lon, newPoint->m_lat, newPoint->m_lon, lastPoint, newPoint, targetTrack ); lastPoint = newPoint; } deleteList.push_back( mergeTrack ); } for(auto const& deleteTrack: deleteList) { g_pAIS->DeletePersistentTrack( deleteTrack ); pConfig->DeleteConfigTrack( deleteTrack ); g_pRouteMan->DeleteTrack( deleteTrack ); } mergeList.clear(); deleteList.clear(); ::wxEndBusyCursor(); UpdateTrkListCtrl(); UpdateRouteListCtrl(); gFrame->RefreshAllCanvas(); if( runningSkipped ) { wxMessageDialog skipWarning( this, _("The currently running Track was not merged.\nYou can merge it later when it is completed."), _T("Warning"), wxCANCEL | wxICON_WARNING ); skipWarning.ShowModal(); } break; } } } void RouteManagerDialog::UpdateTrkListCtrl() { // if an item was selected, make it selected again if it still exist long item = -1; item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); wxUIntPtr selected_id = wxUIntPtr(0); if( item != -1 ) selected_id = m_pTrkListCtrl->GetItemData( item ); // Delete existing items m_pTrkListCtrl->DeleteAllItems(); // then add tracks to the listctrl TrackList::iterator it; int index = 0; int list_index = 0; for( it = ( *pTrackList ).begin(); it != ( *pTrackList ).end(); ++it, ++index ) {; Track *trk = *it; if( !trk->IsListed() ) continue; if( !trk->GetName(true).Upper().Contains(m_tFilterTrk->GetValue().Upper()) ) { continue; } wxListItem li; li.SetId( list_index ); li.SetImage( trk->IsVisible() ? 0 : 1 ); li.SetData( trk ); li.SetText( _T("") ); if( g_pActiveTrack == trk ) { wxFont font = *wxNORMAL_FONT; font.SetWeight( wxFONTWEIGHT_BOLD ); li.SetFont( font ); } long idx = m_pTrkListCtrl->InsertItem( li ); m_pTrkListCtrl->SetItem( idx, colTRKNAME, trk->GetName(true) ); wxString len; len.Printf( wxT("%5.2f"), trk->Length() ); m_pTrkListCtrl->SetItem( idx, colTRKLENGTH, len ); wxListItem lic; lic.SetId( list_index ); lic.SetColumn(1); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pTrkListCtrl->SetItem( lic ); lic.SetColumn(2); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pTrkListCtrl->SetItem( lic ); list_index++; } switch( sort_track_key ){ case SORT_ON_DISTANCE: m_pTrkListCtrl->SortItems( SortTracksOnDistance, (wxIntPtr)NULL ); break; case SORT_ON_NAME: default: m_pTrkListCtrl->SortItems( SortTracksOnName, (wxIntPtr)NULL ); break; } m_pTrkListCtrl->SetColumnWidth(0, 4 * m_charWidth); // restore selection if possible // NOTE this will select a different item, if one is deleted // (the next route will get that index). if( selected_id != wxUIntPtr(0) ) { item = m_pTrkListCtrl->FindItem( -1, selected_id ); m_pTrkListCtrl->SetItemState( item, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED ); } if( (m_lastTrkItem >= 0 ) && (m_pTrkListCtrl->GetItemCount()) ) m_pTrkListCtrl->EnsureVisible( m_lastTrkItem ); UpdateTrkButtons(); } void RouteManagerDialog::OnTrkSelected( wxListEvent &event ) { UpdateTrkButtons(); } void RouteManagerDialog::OnTrkColumnClicked( wxListEvent &event ) { if( event.m_col == 1 ) { sort_track_key = SORT_ON_NAME; sort_track_name_dir++; m_pTrkListCtrl->SortItems( SortTracksOnName, (wxIntPtr)NULL ); } else if( event.m_col == 2 ) { sort_track_key = SORT_ON_DISTANCE; sort_track_len_dir++; m_pTrkListCtrl->SortItems( SortTracksOnDistance, (wxIntPtr)NULL ); } } void RouteManagerDialog::UpdateTrkButtons() { long item = -1; item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); int items = m_pTrkListCtrl->GetSelectedItemCount(); m_lastTrkItem = item; btnTrkProperties->Enable( items == 1 ); btnTrkDelete->Enable( items >= 1 ); btnTrkExport->Enable( items >= 1 ); btnTrkRouteFromTrack->Enable( items == 1 ); btnTrkDeleteAll->Enable( items >= 1 ); } void RouteManagerDialog::OnTrkToggleVisibility( wxMouseEvent &event ) { wxPoint pos = event.GetPosition(); int flags = 0; long clicked_index = m_pTrkListCtrl->HitTest( pos, flags ); // Clicking Visibility column? if( clicked_index > -1 && event.GetX() < m_pTrkListCtrl->GetColumnWidth( colTRKVISIBLE ) ) { // Process the clicked item Track *track = (Track*)m_pTrkListCtrl->GetItemData( clicked_index ); if(track) { track->SetVisible( !track->IsVisible() ); m_pTrkListCtrl->SetItemImage( clicked_index, track->IsVisible() ? 0 : 1 ); } gFrame->RefreshAllCanvas(); } // Allow wx to process... event.Skip(); } void RouteManagerDialog::OnTrkNewClick( wxCommandEvent &event ) { gFrame->TrackOff(); gFrame->TrackOn(); UpdateTrkListCtrl(); } void RouteManagerDialog::OnTrkPropertiesClick( wxCommandEvent &event ) { // Show trackproperties dialog for selected track long item = -1; item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Track *track = (Track*)m_pTrkListCtrl->GetItemData( item ); if( !track ) return; pTrackPropDialog = TrackPropDlg::getInstance( GetParent() ); pTrackPropDialog->SetTrackAndUpdate( track ); if( !pTrackPropDialog->IsShown() ) pTrackPropDialog->Show(); UpdateTrkListCtrl(); m_bNeedConfigFlush = true; } void RouteManagerDialog::OnTrkDeleteClick( wxCommandEvent &event ) { TrackList list; int answer = OCPNMessageBox( this, _("Are you sure you want to delete the selected object(s)"), wxString( _("OpenCPN Alert") ), wxYES_NO ); if ( answer != wxID_YES ) return; bool busy = false; if( m_pTrkListCtrl->GetSelectedItemCount() ) { ::wxBeginBusyCursor(); m_bNeedConfigFlush = true; busy = true; } long item = -1; for ( ;; ) { item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; Track *ptrack_to_delete = (Track*)m_pTrkListCtrl->GetItemData( item ); if( ptrack_to_delete ) list.Append( ptrack_to_delete ); } if( busy ) { for(unsigned int i=0 ; i < list.GetCount() ; i++) { Track *track = (list.Item(i)->GetData()); if( track ) { g_pAIS->DeletePersistentTrack( track ); pConfig->DeleteConfigTrack( track ); g_pRouteMan->DeleteTrack( track ); } } m_lastTrkItem = -1; // UpdateRouteListCtrl(); UpdateTrkListCtrl(); gFrame->InvalidateAllCanvasUndo(); gFrame->RefreshAllCanvas(); ::wxEndBusyCursor(); } } void RouteManagerDialog::OnTrkExportClick( wxCommandEvent &event ) { TrackList list; wxString suggested_name = _T("tracks"); long item = -1; for ( ;; ) { item = m_pTrkListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; Track *ptrack_to_export = (Track*)m_pTrkListCtrl->GetItemData( item ); if( ptrack_to_export ) { list.Append( ptrack_to_export ); if( ptrack_to_export->GetName() != wxEmptyString ) suggested_name = ptrack_to_export->GetName(); } } ExportGPXTracks( this, &list, suggested_name ); } void RouteManagerDialog::TrackToRoute( Track *track ) { if( !track ) return; if( track->m_bIsInLayer ) return; wxGenericProgressDialog pprog( _("OpenCPN Converting Track to Route...."), _("Processing Waypoints..."), 101, NULL, wxPD_AUTO_HIDE | wxPD_SMOOTH | wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME ); ::wxBeginBusyCursor(); Route *route = track->RouteFromTrack( &pprog ); pRouteList->Append( route ); pprog.Update( 101, _("Done.") ); gFrame->RefreshAllCanvas(); ::wxEndBusyCursor(); } void RouteManagerDialog::OnTrkRouteFromTrackClick( wxCommandEvent &event ) { long item = -1; item = m_pTrkListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Track *track = (Track*)m_pTrkListCtrl->GetItemData( item ); TrackToRoute( track ); UpdateRouteListCtrl(); } void RouteManagerDialog::OnTrkDeleteAllClick( wxCommandEvent &event ) { int dialog_ret = OCPNMessageBox( this, _("Are you sure you want to delete tracks?"), wxString( _("OpenCPN Alert") ), wxYES_NO ); if( dialog_ret == wxID_YES ) { g_pRouteMan->DeleteAllTracks(); } m_lastTrkItem = -1; m_lastRteItem = -1; UpdateTrkListCtrl(); // Also need to update the route list control, since routes and tracks share a common global list (pRouteList) UpdateRouteListCtrl(); if( pRoutePropDialog ) pRoutePropDialog->Hide(); gFrame->RefreshAllCanvas(); m_bNeedConfigFlush = true; } void RouteManagerDialog::UpdateWptListCtrl( RoutePoint *rp_select, bool b_retain_sort ) { wxIntPtr selected_id = wxUIntPtr(0); long item = -1; if( NULL == rp_select ) { // if an item was selected, make it selected again if it still exists item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item != -1 ) selected_id = m_pWptListCtrl->GetItemData( item ); } // Freshen the image list m_pWptListCtrl->SetImageList( pWayPointMan->Getpmarkicon_image_list(m_listIconSize), wxIMAGE_LIST_SMALL ); m_pWptListCtrl->DeleteAllItems(); wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst(); int index = 0; while( node ) { RoutePoint *rp = node->GetData(); if( rp && rp->IsListed() ) { if( rp->m_bIsInRoute && !rp->m_bKeepXRoute ) { node = node->GetNext(); continue; } if( ! rp->GetName().Upper().Contains(m_tFilterWpt->GetValue().Upper()) ) { node = node->GetNext(); continue; } wxListItem li; li.SetId( index ); li.SetImage( rp->IsVisible() ? pWayPointMan->GetIconImageListIndex( rp->GetIconBitmap() ) : pWayPointMan->GetXIconImageListIndex( rp->GetIconBitmap() ) ); li.SetData( rp ); li.SetText( _T("") ); long idx = m_pWptListCtrl->InsertItem( li ); wxString scamin = wxString::Format( _T("%i"), (int)rp->GetScaMin() ); if ( !rp->GetUseSca()) scamin = _("Always"); if ( g_bOverruleScaMin ) scamin = _("Overruled"); m_pWptListCtrl->SetItem( idx, colWPTSCALE, scamin ); wxString name = rp->GetName(); if( name.IsEmpty() ) name = _("(Unnamed Waypoint)"); m_pWptListCtrl->SetItem( idx, colWPTNAME, name ); double dst; DistanceBearingMercator( rp->m_lat, rp->m_lon, gLat, gLon, NULL, &dst ); wxString dist; dist.Printf( _T("%5.2f ") + getUsrDistanceUnit(), toUsrDistance( dst ) ); m_pWptListCtrl->SetItem( idx, colWPTDIST, dist ); if( rp == rp_select ) selected_id = (wxIntPtr) rp_select; wxListItem lic; lic.SetId( index ); lic.SetColumn(1); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pWptListCtrl->SetItem( lic ); lic.SetColumn(2); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pWptListCtrl->SetItem( lic ); index++; } node = node->GetNext(); } if( !b_retain_sort ) { m_pWptListCtrl->SortItems( SortWaypointsOnName, reinterpret_cast( m_pWptListCtrl )); sort_wp_key = SORT_ON_NAME; } else { switch( sort_wp_key ){ case SORT_ON_NAME: m_pWptListCtrl->SortItems( SortWaypointsOnName, reinterpret_cast( m_pWptListCtrl )); break; case SORT_ON_DISTANCE: m_pWptListCtrl->SortItems( SortWaypointsOnDistance, reinterpret_cast( m_pWptListCtrl )); break; } } if( selected_id != wxUIntPtr(0) ) { item = m_pWptListCtrl->FindItem( -1, selected_id ); m_pWptListCtrl->SetItemState( item, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED ); } if( (m_lastWptItem >= 0) && (m_pWptListCtrl->GetItemCount()) ) m_pWptListCtrl->EnsureVisible( m_lastWptItem ); if(pWayPointMan->Getpmarkicon_image_list(m_listIconSize)->GetImageCount()) { int iwidth, iheight; pWayPointMan->Getpmarkicon_image_list(m_listIconSize)->GetSize(0, iwidth, iheight); m_pWptListCtrl->SetColumnWidth(0, wxMax(iwidth + 4, 4 * m_charWidth)); } UpdateWptButtons(); } void RouteManagerDialog::UpdateWptListCtrlViz( ) { long item = -1; for ( ;; ) { item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_DONTCARE); if ( item == -1 ) break; RoutePoint *pRP = (RoutePoint *)m_pWptListCtrl->GetItemData(item); int image = pRP->IsVisible() ? pWayPointMan->GetIconImageListIndex( pRP->GetIconBitmap() ) : pWayPointMan->GetXIconImageListIndex( pRP->GetIconBitmap() ) ; m_pWptListCtrl->SetItemImage(item, image); } } void RouteManagerDialog::OnWptDefaultAction( wxListEvent &event ) { wxCommandEvent evt; OnWptPropertiesClick( evt ); } void RouteManagerDialog::OnWptSelected( wxListEvent &event ) { UpdateWptButtons(); } void RouteManagerDialog::OnWptColumnClicked( wxListEvent &event ) { if( event.m_col == NAME_COLUMN ) { sort_wp_name_dir++; m_pWptListCtrl->SortItems( SortWaypointsOnName, reinterpret_cast( m_pWptListCtrl )); sort_wp_key = SORT_ON_NAME; } else { if( event.m_col == DISTANCE_COLUMN ) { sort_wp_len_dir++; m_pWptListCtrl->SortItems( SortWaypointsOnDistance, reinterpret_cast( m_pWptListCtrl )); sort_wp_key = SORT_ON_DISTANCE; } } UpdateWptListCtrl(); } void RouteManagerDialog::UpdateWptButtons() { long item = -1; item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); bool enable1 = ( m_pWptListCtrl->GetSelectedItemCount() == 1 ); bool enablemultiple = ( m_pWptListCtrl->GetSelectedItemCount() >= 1 ); if( enable1 ) m_lastWptItem = item; else m_lastWptItem = -1; // Check selection to see if it is in a layer // If so, disable the "delete" button bool b_delete_enable = true; item = -1; for ( ;; ) { item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( wp && wp->m_bIsInLayer) { b_delete_enable = false; break; } } btnWptProperties->Enable( enable1 ); btnWptZoomto->Enable( enable1 ); btnWptDeleteAll->Enable( enablemultiple ); btnWptDelete->Enable( b_delete_enable && enablemultiple ); btnWptGoTo->Enable( enable1 ); btnWptExport->Enable( enablemultiple ); btnWptSendToGPS->Enable( enable1 ); } void RouteManagerDialog::OnWptToggleVisibility( wxMouseEvent &event ) { wxPoint pos = event.GetPosition(); int flags = 0; long clicked_index = m_pWptListCtrl->HitTest( pos, flags ); // Clicking Visibility column? if( clicked_index > -1 && event.GetX() < m_pWptListCtrl->GetColumnWidth( colTRKVISIBLE ) ) { // Process the clicked item RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( clicked_index ); wp->SetVisible( !wp->IsVisible() ); m_pWptListCtrl->SetItemImage( clicked_index, wp->IsVisible() ? pWayPointMan->GetIconImageListIndex( wp->GetIconBitmap() ) : pWayPointMan->GetXIconImageListIndex( wp->GetIconBitmap() ) ); pConfig->UpdateWayPoint( wp ); gFrame->RefreshAllCanvas(); } else // clicked on ScaMin column?? if( clicked_index > -1 && event.GetX() > m_pWptListCtrl->GetColumnWidth( colTRKVISIBLE ) && event.GetX() < ( m_pWptListCtrl->GetColumnWidth( colTRKVISIBLE )+ m_pWptListCtrl->GetColumnWidth( colWPTSCALE ) ) && !g_bOverruleScaMin ){ RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( clicked_index ); wp->SetUseSca( !wp->GetUseSca() ); pConfig->UpdateWayPoint( wp ); gFrame->RefreshAllCanvas(); wxString scamin = wxString::Format( _T("%i"), (int)wp->GetScaMin() ); if ( !wp->GetUseSca()) scamin = _("Always"); m_pWptListCtrl->SetItem( clicked_index, colWPTSCALE, scamin ); } // Allow wx to process... event.Skip(); } void RouteManagerDialog::OnWptNewClick( wxCommandEvent &event ) { RoutePoint *pWP = new RoutePoint( gLat, gLon, g_default_wp_icon, wxEmptyString, wxEmptyString ); pWP->m_bIsolatedMark = true; // This is an isolated mark pSelect->AddSelectableRoutePoint( gLat, gLon, pWP ); pConfig->AddNewWayPoint( pWP, -1 ); // use auto next num gFrame->RefreshAllCanvas(); //g_pMarkInfoDialog = MarkInfoImpl::getInstance( GetParent() ); if ( !g_pMarkInfoDialog ) // There is one global instance of the MarkProp Dialog g_pMarkInfoDialog = new MarkInfoDlg(GetParent()); g_pMarkInfoDialog->SetRoutePoint( pWP ); g_pMarkInfoDialog->UpdateProperties(); WptShowPropertiesDialog( pWP, GetParent() ); } void RouteManagerDialog::OnWptPropertiesClick( wxCommandEvent &event ) { long item = -1; item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( !wp ) return; WptShowPropertiesDialog( wp, GetParent() ); UpdateWptListCtrl(); m_bNeedConfigFlush = true; } void RouteManagerDialog::WptShowPropertiesDialog( RoutePoint* wp, wxWindow* parent ) { if ( !g_pMarkInfoDialog ) // There is one global instance of the MarkProp Dialog g_pMarkInfoDialog = new MarkInfoDlg(parent); g_pMarkInfoDialog->SetRoutePoint( wp ); g_pMarkInfoDialog->UpdateProperties(); if( wp->m_bIsInLayer ) { wxString caption( wxString::Format( _T("%s, %s: %s"), _("Waypoint Properties"), _("Layer"), GetLayerName( wp->m_LayerID ) ) ); g_pMarkInfoDialog->SetDialogTitle( caption ); } else g_pMarkInfoDialog->SetDialogTitle( _("Waypoint Properties") ); if( !g_pMarkInfoDialog->IsShown() ) g_pMarkInfoDialog->Show(); g_pMarkInfoDialog->Raise(); } void RouteManagerDialog::OnWptZoomtoClick( wxCommandEvent &event ) { long item = -1; item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( !wp ) return; gFrame->JumpToPosition( gFrame->GetPrimaryCanvas(), wp->m_lat, wp->m_lon, gFrame->GetPrimaryCanvas()->GetVPScale() ); } void RouteManagerDialog::OnWptDeleteClick( wxCommandEvent &event ) { RoutePointList list; int answer = OCPNMessageBox( this, _("Are you sure you want to delete the selected object(s)"), wxString( _("OpenCPN Alert") ), wxYES_NO ); if ( answer != wxID_YES ) return; bool busy = false; if( m_pWptListCtrl->GetSelectedItemCount() ) { ::wxBeginBusyCursor(); m_bNeedConfigFlush = true; busy = true; } long item = -1; long item_last_selected = -1; for ( ;; ) { item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; item_last_selected = item; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( wp && !wp->m_bIsInLayer) list.Append( wp ); } if( busy ) { for(unsigned int i=0 ; i < list.GetCount() ; i++) { RoutePoint *wp = list.Item(i)->GetData(); if( wp ) { if ( wp->m_bIsInRoute ) { if ( wxID_YES == OCPNMessageBox(this, _( "The waypoint you want to delete is used in a route, do you really want to delete it?" ), _( "OpenCPN Alert" ), wxYES_NO )) pWayPointMan->DestroyWaypoint( wp ); } else pWayPointMan->DestroyWaypoint( wp ); } } long item_next = m_pWptListCtrl->GetNextItem( item_last_selected ); // next in list RoutePoint *wp_next = NULL; if( item_next > -1 ) wp_next = (RoutePoint *) m_pWptListCtrl->GetItemData( item_next ); m_lastWptItem = item_next; UpdateRouteListCtrl(); UpdateTrkListCtrl(); UpdateWptListCtrl( wp_next, true ); if( g_pMarkInfoDialog ) { g_pMarkInfoDialog->SetRoutePoint( NULL ); g_pMarkInfoDialog->UpdateProperties(); } gFrame->InvalidateAllCanvasUndo(); gFrame->RefreshAllCanvas(); ::wxEndBusyCursor(); } } void RouteManagerDialog::OnWptGoToClick( wxCommandEvent &event ) { long item = -1; item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( !wp ) return; RoutePoint *pWP_src = new RoutePoint( gLat, gLon, g_default_wp_icon, wxEmptyString, wxEmptyString ); pSelect->AddSelectableRoutePoint( gLat, gLon, pWP_src ); Route *temp_route = new Route(); pRouteList->Append( temp_route ); temp_route->AddPoint( pWP_src ); temp_route->AddPoint( wp ); pSelect->AddSelectableRouteSegment( gLat, gLon, wp->m_lat, wp->m_lon, pWP_src, wp, temp_route ); wxString name = wp->GetName(); if( name.IsEmpty() ) name = _("(Unnamed Waypoint)"); wxString rteName = _("Go to "); rteName.Append( name ); temp_route->m_RouteNameString = rteName; temp_route->m_RouteStartString = _("Here"); temp_route->m_RouteEndString = name; temp_route->m_bDeleteOnArrival = true; if( g_pRouteMan->GetpActiveRoute() ) g_pRouteMan->DeactivateRoute(); g_pRouteMan->ActivateRoute( temp_route, wp ); UpdateRouteListCtrl(); } void RouteManagerDialog::OnWptExportClick( wxCommandEvent &event ) { RoutePointList list; wxString suggested_name = _T("waypoints"); long item = -1; for ( ;; ) { item = m_pWptListCtrl->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if ( item == -1 ) break; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( wp && !wp->m_bIsInLayer) { list.Append( wp ); if( wp->GetName() != wxEmptyString ) suggested_name = wp->GetName(); } } ExportGPXWaypoints( this, &list, suggested_name ); } void RouteManagerDialog::OnWptSendToGPSClick( wxCommandEvent &event ) { long item = -1; item = m_pWptListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; RoutePoint *wp = (RoutePoint *) m_pWptListCtrl->GetItemData( item ); if( !wp ) return; SendToGpsDlg *pdlg = new SendToGpsDlg(); pdlg->SetWaypoint( wp ); wxString source; pdlg->Create( NULL, -1, _( "Send to GPS" ) + _T( "..." ), source ); #ifdef __WXOSX__ HideWithEffect(wxSHOW_EFFECT_BLEND ); #endif pdlg->ShowModal(); #ifdef __WXOSX__ ShowWithEffect(wxSHOW_EFFECT_BLEND ); #endif delete pdlg; } void RouteManagerDialog::OnWptDeleteAllClick( wxCommandEvent &event ) { wxString prompt; int buttons, type; if ( !pWayPointMan->SharedWptsExist() ) { prompt = _("Are you sure you want to delete waypoints?"); buttons = wxYES_NO; type = 1; } else { prompt = _("There are some waypoints used in routes or anchor alarms.\n Do you want to delete them as well?\n This will change the routes and disable the anchor alarms.\n Answering No keeps the waypoints used in routes or alarms."); buttons = wxYES_NO | wxCANCEL; type = 2; } int answer = OCPNMessageBox( this, prompt, wxString( _("OpenCPN Alert") ), buttons ); if ( answer == wxID_YES ) pWayPointMan->DeleteAllWaypoints( true ); if ( answer == wxID_NO && type == 2 ) pWayPointMan->DeleteAllWaypoints( false ); // only delete unused waypoints if( g_pMarkInfoDialog ) { g_pMarkInfoDialog->SetRoutePoint( NULL ); g_pMarkInfoDialog->UpdateProperties(); } m_lastWptItem = -1; UpdateRouteListCtrl(); UpdateWptListCtrl(); gFrame->InvalidateAllCanvasUndo(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnLaySelected( wxListEvent &event ) { UpdateLayButtons(); } void RouteManagerDialog::OnLayColumnClicked( wxListEvent &event ) { if( event.m_col == 1 ) { sort_layer_name_dir++; m_pLayListCtrl->SortItems( SortLayersOnName, (wxIntPtr)NULL ); } else if( event.m_col == 2 ) { sort_layer_len_dir++; m_pLayListCtrl->SortItems( SortLayersOnSize, (wxIntPtr)NULL ); } } void RouteManagerDialog::UpdateLayButtons() { long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); bool enable = ( item != -1 ); //btnLayProperties->Enable(false); btnLayDelete->Enable( enable ); cbLayToggleChart->Enable( enable ); cbLayToggleListing->Enable( enable ); cbLayToggleNames->Enable( enable ); if( item >= 0 ) { cbLayToggleChart->SetValue(((Layer*)m_pLayListCtrl->GetItemData( item ))->IsVisibleOnChart()); cbLayToggleNames->Set3StateValue( ((Layer*)m_pLayListCtrl->GetItemData( item ))->HasVisibleNames() ); cbLayToggleListing->SetValue( ((Layer*)m_pLayListCtrl->GetItemData( item ))->IsVisibleOnListing() ); } else { cbLayToggleChart->SetValue(true); cbLayToggleNames->Set3StateValue( wxCHK_UNDETERMINED ); cbLayToggleListing->SetValue( true ); } } void RouteManagerDialog::OnLayToggleVisibility( wxMouseEvent &event ) { wxPoint pos = event.GetPosition(); int flags = 0; long clicked_index = m_pLayListCtrl->HitTest( pos, flags ); // Clicking Visibility column? if( clicked_index > -1 && event.GetX() < m_pLayListCtrl->GetColumnWidth( colLAYVISIBLE ) ) { // Process the clicked item Layer *layer = (Layer*)m_pLayListCtrl->GetItemData( clicked_index ); layer->SetVisibleOnChart( !layer->IsVisibleOnChart() ); m_pLayListCtrl->SetItemImage( clicked_index, layer->IsVisibleOnChart() ? 0 : 1 ); ToggleLayerContentsOnChart( layer ); } // Allow wx to process... event.Skip(); } void RouteManagerDialog::UpdateLists() { UpdateRouteListCtrl(); UpdateTrkListCtrl(); UpdateWptListCtrl(); UpdateLayListCtrl(); } void RouteManagerDialog::OnLayNewClick( wxCommandEvent &event ) { AddNewLayer( false ); //Temporary layer } void RouteManagerDialog::OnPerLayNewClick( wxCommandEvent &event ) { AddNewLayer( true ); //Persistent layer } void RouteManagerDialog::AddNewLayer( bool isPersistent ) { bool show_flag = g_bShowLayers; g_bShowLayers = true; UI_ImportGPX(this, true, _T(""), true, isPersistent); g_bShowLayers = show_flag; UpdateLists(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnLayPropertiesClick( wxCommandEvent &event ) { // Show layer properties dialog for selected layer - todo long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; } void RouteManagerDialog::OnLayDeleteClick( wxCommandEvent &event ) { long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Layer *layer = (Layer*)m_pLayListCtrl->GetItemData( item ); if( !layer ) return; // Check if this file is a persistent layer. // If added in this session the listctrl file path is origin dir and not yet /layers bool ispers = false; wxString destf, f, name, ext; f = layer->m_LayerFileName; wxFileName::SplitPath(f, NULL, NULL, &name, &ext); destf = g_Platform->GetPrivateDataDir(); appendOSDirSlash(&destf); destf.Append( _T("layers") ); appendOSDirSlash(&destf); destf << name << _T(".") << ext; wxString prompt = _("Are you sure you want to delete this layer and of its contents?"); if (wxFileExists(destf)) { prompt.Append( _T("\n") ); prompt.Append( _("The file will also be deleted from OpenCPN's layer directory.") ); prompt.Append( _T("\n (") + destf + _T(")" ) ); ispers = true; } int answer = OCPNMessageBox( this, prompt, wxString( _("OpenCPN Alert") ), wxYES_NO ); if ( answer == wxID_NO ) return; // Delete a persistent layer file if present if (ispers) { wxString remMSG; if (wxRemoveFile(destf) ) remMSG.sprintf(_T("Layer file: %s is deleted"), destf); else remMSG.sprintf(_T("Error deleting Layer file: %s"), destf); wxLogMessage(remMSG); } // Process Tracks and Routes in this layer wxRouteListNode *node1 = pRouteList->GetFirst(); while( node1 ) { Route *pRoute = node1->GetData(); wxRouteListNode *next_node = node1->GetNext(); if( pRoute->m_bIsInLayer && ( pRoute->m_LayerID == layer->m_LayerID ) ) { pRoute->m_bIsInLayer = false; pRoute->m_LayerID = 0; g_pRouteMan->DeleteRoute( pRoute ); } node1 = next_node; } wxTrackListNode *node2 = pTrackList->GetFirst(); while( node2 ) { Track *pTrack = node2->GetData(); wxTrackListNode *next_node = node2->GetNext(); if( pTrack->m_bIsInLayer && ( pTrack->m_LayerID == layer->m_LayerID ) ) { pTrack->m_bIsInLayer = false; pTrack->m_LayerID = 0; g_pRouteMan->DeleteTrack( pTrack ); } node2 = next_node; } // Process waypoints in this layer wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst(); wxRoutePointListNode *node3; while( node ) { node3 = node->GetNext(); RoutePoint *rp = node->GetData(); if( rp && ( rp->m_LayerID == layer->m_LayerID ) ) { rp->m_bIsInLayer = false; rp->m_LayerID = 0; pWayPointMan->DestroyWaypoint( rp, false ); // no need to update the change set on layer ops } node = node3; node3 = NULL; } if( g_pMarkInfoDialog ) { g_pMarkInfoDialog->SetRoutePoint( NULL ); g_pMarkInfoDialog->UpdateProperties(); } pLayerList->DeleteObject( layer ); UpdateLists(); gFrame->RefreshAllCanvas(); m_bNeedConfigFlush = false; } void RouteManagerDialog::OnLayToggleChartClick( wxCommandEvent &event ) { // Toggle visibility on chart for selected layer long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Layer *layer = (Layer*)m_pLayListCtrl->GetItemData( item ); if( !layer ) return; layer->SetVisibleOnChart( !layer->IsVisibleOnChart() ); m_pLayListCtrl->SetItemImage( item, layer->IsVisibleOnChart() ? 0 : 1 ); ToggleLayerContentsOnChart( layer ); } void RouteManagerDialog::ToggleLayerContentsOnChart( Layer *layer ) { // Process Tracks and Routes in this layer wxRouteListNode *node1 = pRouteList->GetFirst(); while( node1 ) { Route *pRoute = node1->GetData(); if( pRoute->m_bIsInLayer && ( pRoute->m_LayerID == layer->m_LayerID ) ) { pRoute->SetVisible( layer->IsVisibleOnChart() ); pConfig->UpdateRoute( pRoute ); } node1 = node1->GetNext(); } wxTrackListNode *node2 = pTrackList->GetFirst(); while( node2 ) { Track *pTrack = node2->GetData(); if( pTrack->m_bIsInLayer && ( pTrack->m_LayerID == layer->m_LayerID ) ) pTrack->SetVisible( layer->IsVisibleOnChart() ); node2 = node2->GetNext(); } // Process waypoints in this layer wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst(); while( node ) { RoutePoint *rp = node->GetData(); if( rp && ( rp->m_LayerID == layer->m_LayerID ) ) { rp->SetVisible( layer->IsVisibleOnChart() ); } node = node->GetNext(); } UpdateLists(); UpdateLayButtons(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnLayToggleNamesClick( wxCommandEvent &event ) { // Toggle WPT names visibility on chart for selected layer long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Layer *layer = (Layer*)m_pLayListCtrl->GetItemData( item ); if( !layer ) return; layer->SetVisibleNames( cbLayToggleNames->Get3StateValue() ); ToggleLayerContentsNames( layer ); } void RouteManagerDialog::ToggleLayerContentsNames( Layer *layer ) { // Process Tracks and Routes in this layer wxRouteListNode *node1 = pRouteList->GetFirst(); while( node1 ) { Route *pRoute = node1->GetData(); if( pRoute->m_bIsInLayer && ( pRoute->m_LayerID == layer->m_LayerID ) ) { wxRoutePointListNode *node = pRoute->pRoutePointList->GetFirst(); RoutePoint *prp1 = node->GetData(); while( node ) { if( layer->HasVisibleNames() == wxCHK_UNDETERMINED ) { prp1->m_bShowName = prp1->m_bShowNameData; } else { prp1->m_bShowName = (layer->HasVisibleNames() == wxCHK_CHECKED); } node = node->GetNext(); } } node1 = node1->GetNext(); } // Process waypoints in this layer wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst(); while( node ) { RoutePoint *rp = node->GetData(); if( rp && ( rp->m_LayerID == layer->m_LayerID ) ) { rp->SetNameShown( layer->HasVisibleNames() == wxCHK_CHECKED || (rp->m_bShowNameData && layer->HasVisibleNames() == wxCHK_UNDETERMINED) ); } node = node->GetNext(); } UpdateLayButtons(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnLayToggleListingClick( wxCommandEvent &event ) { // Toggle visibility on listing for selected layer long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); if( item == -1 ) return; Layer *layer = (Layer*)m_pLayListCtrl->GetItemData( item ); if( !layer ) return; layer->SetVisibleOnListing( !layer->IsVisibleOnListing() ); ToggleLayerContentsOnListing( layer ); } void RouteManagerDialog::ToggleLayerContentsOnListing( Layer *layer ) { ::wxBeginBusyCursor(); // Process Tracks and Routes in this layer wxRouteListNode *node1 = pRouteList->GetFirst(); while( node1 ) { Route *pRoute = node1->GetData(); if( pRoute->m_bIsInLayer && ( pRoute->m_LayerID == layer->m_LayerID ) ) { pRoute->SetListed( layer->IsVisibleOnListing() ); } node1 = node1->GetNext(); } wxTrackListNode *node2 = pTrackList->GetFirst(); while( node2 ) { Track *pTrack = node2->GetData(); if( pTrack->m_bIsInLayer && ( pTrack->m_LayerID == layer->m_LayerID ) ) pTrack->SetListed( layer->IsVisibleOnListing() ); node2 = node2->GetNext(); } // Process waypoints in this layer // n.b. If the waypoint belongs to a track, and is not shared, then do not list it. // This is a performance optimization, allowing large track support. wxRoutePointListNode *node = pWayPointMan->GetWaypointList()->GetFirst(); while( node ) { RoutePoint *rp = node->GetData(); if( rp && rp->m_bIsolatedMark && ( rp->m_LayerID == layer->m_LayerID ) ) { rp->SetListed( layer->IsVisibleOnListing() ); } node = node->GetNext(); } UpdateLists(); ::wxEndBusyCursor(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnLayDefaultAction( wxListEvent &event ) { wxCommandEvent evt; OnLayPropertiesClick( evt ); } void RouteManagerDialog::UpdateLayListCtrl() { // if an item was selected, make it selected again if it still exist long item = -1; item = m_pLayListCtrl->GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED ); wxUIntPtr selected_id = wxUIntPtr(0); if( item != -1 ) selected_id = m_pLayListCtrl->GetItemData( item ); // Delete existing items m_pLayListCtrl->DeleteAllItems(); // then add routes to the listctrl LayerList::iterator it; int index = 0; for( it = ( *pLayerList ).begin(); it != ( *pLayerList ).end(); ++it, ++index ) { Layer *lay = (Layer *) ( *it ); if( !lay->m_LayerName.Upper().Contains(m_tFilterLay->GetValue().Upper()) ) { continue; } wxListItem li; li.SetId( index ); li.SetImage( lay->IsVisibleOnChart() ? 0 : 1 ); li.SetData( lay ); li.SetText( _T("") ); long idx = m_pLayListCtrl->InsertItem( li ); wxString name = lay->m_LayerName; if( name.IsEmpty() ) { //RoutePoint *rp = trk->GetPoint(1); //if (rp) // name = rp->m_CreateTime.FormatISODate() + _T(" ") + rp->m_CreateTime.FormatISOTime(); //name = rp->m_CreateTime.Format(); //else name = _("(Unnamed Layer)"); } m_pLayListCtrl->SetItem( idx, colLAYNAME, name ); wxString len; len.Printf( wxT("%d"), (int) lay->m_NoOfItems ); m_pLayListCtrl->SetItem( idx, colLAYITEMS, len ); m_pLayListCtrl->SetItem(idx, colLAYPERSIST, lay->m_LayerType); wxListItem lic; lic.SetId( index ); lic.SetColumn(1); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pLayListCtrl->SetItem( lic ); lic.SetColumn(2); lic.SetAlign(wxLIST_FORMAT_LEFT); m_pLayListCtrl->SetItem( lic ); } m_pLayListCtrl->SortItems( SortLayersOnName, reinterpret_cast( m_pLayListCtrl )); m_pLayListCtrl->SetColumnWidth(0, 4 * m_charWidth); // restore selection if possible // NOTE this will select a different item, if one is deleted // (the next route will get that index). if( selected_id != wxUIntPtr(0) ) { item = m_pLayListCtrl->FindItem( -1, selected_id ); m_pLayListCtrl->SetItemState( item, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED ); } UpdateLayButtons(); } void RouteManagerDialog::OnImportClick( wxCommandEvent &event ) { // Import routes // FIXME there is no way to instruct this function about what to import. // Suggest to add that! UI_ImportGPX( this ); UpdateLists(); gFrame->RefreshAllCanvas(); } void RouteManagerDialog::OnExportClick( wxCommandEvent &event ) { ExportGPX( this ); } void RouteManagerDialog::OnExportVizClick( wxCommandEvent &event ) { ExportGPX( this, true, true ); // only visible objects, layers included } void RouteManagerDialog::OnFilterChanged( wxCommandEvent &event ) { if( event.GetEventObject() == m_tFilterWpt ) { UpdateWptListCtrl( NULL, true ); } else if ( event.GetEventObject() == m_tFilterRte ) { UpdateRouteListCtrl(); } else if ( event.GetEventObject() == m_tFilterTrk ) { UpdateTrkListCtrl(); } else if ( event.GetEventObject() == m_tFilterLay ) { UpdateLayListCtrl(); } } //END Event handlers