1 /******************************************************************************
2  *
3  * Project:  OpenCPN
4  * Purpose:  Read and write KML Format (http://en.wikipedia.org/wiki/Keyhole_Markup_Language)
5  * Author:   Jesper Weissglas
6  *
7  ***************************************************************************
8  *   Copyright (C) 2012 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  *
27  */
28 
29 #include "config.h"
30 
31 #include "wx/wxprec.h"
32 
33 #ifndef  WX_PRECOMP
34 #include "wx/wx.h"
35 #endif
36 
37 #include <vector>
38 
39 #include <wx/file.h>
40 #include <wx/datetime.h>
41 #include <wx/clipbrd.h>
42 
43 #include "ocpn_types.h"
44 #include "navutil.h"
45 #include "tinyxml.h"
46 #include "kml.h"
47 #include "Track.h"
48 #include "Route.h"
49 #include "chart1.h"
50 
51 extern MyFrame *gFrame;
52 extern double gLat;
53 extern double gLon;
54 
55 int Kml::seqCounter = 0;
56 bool Kml::insertQtVlmExtendedData = false;
57 
ParseCoordinates(TiXmlNode * node,dPointList & points)58 int Kml::ParseCoordinates( TiXmlNode* node, dPointList& points ) {
59     TiXmlElement* e = node->FirstChildElement( "coordinates" );
60     if( ! e ) {
61         wxString msg( _T("KML Parser found no <coordinates> for the element: ") );
62         msg << wxString( node->ToElement()->Value(), wxConvUTF8 );
63         wxLogMessage( msg );
64         return 0;
65     }
66 
67     // Parse "long,lat,z" format.
68 
69     dPoint point;
70 
71     std::stringstream ss( e->GetText() );
72     std::string txtCoord;
73 
74 	while(1) {
75         if( ! std::getline( ss, txtCoord, ',' ) ) break;;
76         if( txtCoord.length() == 0 ) break;
77 
78         point.x = atof( txtCoord.c_str() );
79         std::getline( ss, txtCoord, ',' );
80         point.y = atof( txtCoord.c_str() );
81         std::getline( ss, txtCoord, ' ' );
82         point.z = atof( txtCoord.c_str() );
83 
84         points.push_back( point );
85     }
86     return points.size();
87 }
88 
ParseTrack(TiXmlNode * node,wxString & name)89 KmlPastebufferType Kml::ParseTrack( TiXmlNode* node, wxString& name ) {
90     parsedTrack = new Track();
91     parsedTrack->SetName(name);
92 
93     if( 0 == strncmp( node->ToElement()->Value(), "LineString", 10 ) ) {
94         dPointList coordinates;
95         if( ParseCoordinates( node, coordinates ) > 2 ) {
96             TrackPoint* trackpoint = NULL;
97 
98             for( unsigned int i=0; i<coordinates.size(); i++ ) {
99                 trackpoint = new TrackPoint(coordinates[i].y, coordinates[i].x);
100                 parsedTrack->AddPoint( trackpoint );
101             }
102         }
103         return KML_PASTE_TRACK;
104     }
105 
106     if( 0 == strncmp( node->ToElement()->Value(), "gx:Track", 8 ) ) {
107         TrackPoint* trackpoint = NULL;
108         TiXmlElement* point = node->FirstChildElement( "gx:coord" );
109         int pointCounter = 0;
110 
111         for( ; point; point=point->NextSiblingElement( "gx:coord" ) ) {
112             double lat, lon;
113             std::stringstream ss( point->GetText() );
114             std::string txtCoord;
115             std::getline( ss, txtCoord, ' ' );
116             lon = atof( txtCoord.c_str() );
117             std::getline( ss, txtCoord, ' ' );
118             lat = atof( txtCoord.c_str() );
119 
120             parsedTrack->AddPoint( new TrackPoint(lat, lon) );
121             pointCounter++;
122         }
123 
124         TiXmlElement* when = node->FirstChildElement( "when" );
125 
126         wxDateTime whenTime;
127 
128         int i = 0;
129         for( ; when; when=when->NextSiblingElement( "when" ) ) {
130             trackpoint = parsedTrack->GetPoint(i);
131             if( ! trackpoint ) continue;
132             whenTime.ParseFormat( wxString( when->GetText(), wxConvUTF8 ), _T("%Y-%m-%dT%H:%M:%SZ") );
133             trackpoint->SetCreateTime(whenTime);
134             i++;
135         }
136 
137         return KML_PASTE_TRACK;
138     }
139     return KML_PASTE_INVALID;
140 }
141 
ParseOnePlacemarkPoint(TiXmlNode * node,wxString & name)142 KmlPastebufferType Kml::ParseOnePlacemarkPoint( TiXmlNode* node, wxString& name ) {
143     double newLat = 0., newLon = 0.;
144     dPointList coordinates;
145 
146     if( ParseCoordinates( node->ToElement(), coordinates ) ) {
147         newLat = coordinates[0].y;
148         newLon = coordinates[0].x;
149     }
150 
151     if( newLat == 0.0 && newLon == 0.0 ) {
152         wxString msg( _T("KML Parser failed to convert <Point> coordinates.") );
153         wxLogMessage( msg );
154         return KML_PASTE_INVALID;
155     }
156     wxString pointName = wxEmptyString;
157 	TiXmlElement* e = node->Parent()->FirstChild( "name" )->ToElement();
158     if( e ) pointName = wxString( e->GetText(), wxConvUTF8 );
159 
160     wxString pointDescr = wxEmptyString;
161     e = node->Parent()->FirstChildElement( "description" );
162 
163     // If the <description> is an XML element we must convert it to text,
164     // otherwise it gets lost.
165     if( e ) {
166         TiXmlNode* n = e->FirstChild();
167         if( n ) switch( n->Type() ){
168             case TiXmlNode::TINYXML_TEXT:
169                 pointDescr = wxString( e->GetText(), wxConvUTF8 );
170                 break;
171             case TiXmlNode::TINYXML_ELEMENT:
172                 TiXmlPrinter printer;
173                 printer.SetIndent( "\t" );
174                 n->Accept( &printer );
175                 pointDescr = wxString( printer.CStr(), wxConvUTF8 );
176                 break;
177         }
178     }
179 
180     // Extended data will override description.
181     TiXmlNode* n = node->Parent()->FirstChild( "ExtendedData" );
182     if( n ) {
183         TiXmlPrinter printer;
184         printer.SetIndent( "\t" );
185         n->Accept( &printer );
186         pointDescr = wxString( printer.CStr(), wxConvUTF8 );
187     }
188 
189     // XXX leak ?
190     parsedRoutePoint = new RoutePoint();
191     parsedRoutePoint->m_lat = newLat;
192     parsedRoutePoint->m_lon = newLon;
193     parsedRoutePoint->m_bIsolatedMark = true;
194     parsedRoutePoint->m_bPtIsSelected = false;
195     parsedRoutePoint->m_MarkDescription = pointDescr;
196     parsedRoutePoint->SetName( pointName );
197 
198     return KML_PASTE_WAYPOINT;
199 }
200 
ParsePasteBuffer()201 KmlPastebufferType Kml::ParsePasteBuffer() {
202     if( !wxTheClipboard->IsOpened() )
203         if( ! wxTheClipboard->Open() ) return KML_PASTE_INVALID;
204 
205     wxTextDataObject data;
206     wxTheClipboard->GetData( data );
207     kmlText = data.GetText();
208     wxTheClipboard->Close();
209 
210     if( kmlText.Find( _T("<kml") ) == wxNOT_FOUND ) return KML_PASTE_INVALID;
211 
212     TiXmlDocument doc;
213     if( ! doc.Parse( kmlText.mb_str( wxConvUTF8 ), 0, TIXML_ENCODING_UTF8 ) ) {
214 		wxLogError( wxString( doc.ErrorDesc(), wxConvUTF8 ) );
215 		return KML_PASTE_INVALID;
216 	}
217     if( 0 != strncmp( doc.RootElement()->Value(), "kml", 3 ) ) return KML_PASTE_INVALID;
218 
219     TiXmlHandle docHandle( doc.RootElement() );
220 
221 	// We may or may not have a <document> depending on what the user copied.
222     TiXmlElement* placemark = docHandle.FirstChild( "Document" ).FirstChild( "Placemark" ).ToElement();
223     if( ! placemark ) {
224         placemark = docHandle.FirstChild( "Placemark" ).ToElement();
225 	}
226     if( ! placemark ) {
227         wxString msg( _T("KML Parser found no <Placemark> tag in the KML.") );
228         wxLogMessage( msg );
229         return KML_PASTE_INVALID;
230     }
231 
232     int pointCounter = 0;
233     wxString name;
234     for( ; placemark; placemark=placemark->NextSiblingElement() ) {
235         TiXmlElement* e = placemark->FirstChildElement( "name" );
236         if( e ) name = wxString( e->GetText(),wxConvUTF8 );
237         pointCounter++;
238     }
239 
240     if( pointCounter == 1 ) {
241 
242         // Is it a single waypoint?
243         TiXmlNode* element = docHandle.FirstChild( "Document" ).FirstChild( "Placemark" ).FirstChild( "Point" ).ToNode();
244         if( ! element ) element = docHandle.FirstChild( "Placemark" ).FirstChild( "Point" ).ToNode();
245         if( element ) return ParseOnePlacemarkPoint( element, name );
246 
247         // Is it a dumb <LineString> track?
248         element = docHandle.FirstChild( "Document" ).FirstChild( "Placemark" ).FirstChild( "LineString" ).ToNode();
249         if( ! element ) element = docHandle.FirstChild( "Placemark" ).FirstChild( "LineString" ).ToNode();
250         if( element ) return ParseTrack( element, name );
251 
252         // Is it a smart extended <gx:track> track?
253         element = docHandle.FirstChild( "Document" ).FirstChild( "Placemark" ).FirstChild( "gx:Track" ).ToNode();
254         if( ! element ) element = docHandle.FirstChild( "Placemark" ).FirstChild( "gx:Track" ).ToNode();
255         if( element ) return ParseTrack( element, name );
256 
257         wxString msg( _T("KML Parser found a single <Placemark> in the KML, but no useable data in it.") );
258         wxLogMessage( msg );
259         return KML_PASTE_INVALID;
260     }
261 
262     // Here we go with a full route.
263 
264     parsedRoute = new Route();
265     bool foundPoints = false;
266     bool foundTrack = false;
267     TiXmlElement* element = docHandle.FirstChild( "Document" ).FirstChild( "name" ).ToElement();
268     if( element )
269         parsedRoute->m_RouteNameString = wxString( element->GetText(), wxConvUTF8 );
270 
271     placemark = docHandle.FirstChild( "Document" ).FirstChild( "Placemark" ).ToElement();
272     for( ; placemark; placemark=placemark->NextSiblingElement() ) {
273 
274         TiXmlNode* n = placemark->FirstChild( "Point" );
275         if( n ) {
276             if( ParseOnePlacemarkPoint( n->ToElement(), name ) == KML_PASTE_WAYPOINT ) {
277                 parsedRoute->AddPoint( new RoutePoint( parsedRoutePoint ) );
278                 delete parsedRoutePoint;
279                 parsedRoutePoint = 0;
280                 foundPoints = true;
281             }
282         }
283 
284         n = placemark->FirstChild( "LineString" );
285         if( n ) {
286             ParseTrack( n->ToElement(), name );
287             foundTrack = true;
288         }
289         n = placemark->FirstChild( "gx:Track" );
290         if( n ) {
291             ParseTrack( n->ToElement(), name );
292             foundTrack = true;
293         }
294     }
295 
296     if( foundPoints && parsedRoute->GetnPoints() < 2 ) {
297         wxString msg( _T("KML Parser did not find enough <Point>s to make a route.") );
298         wxLogMessage( msg );
299         foundPoints = false;
300     }
301 
302     if( foundPoints && ! foundTrack ) return KML_PASTE_ROUTE;
303     if( foundPoints && foundTrack ) return KML_PASTE_ROUTE_TRACK;
304     if( ! foundPoints && foundTrack ) return KML_PASTE_TRACK;
305     return KML_PASTE_INVALID;
306 }
307 
StandardHead(TiXmlDocument & xmlDoc,wxString name)308 TiXmlElement* Kml::StandardHead( TiXmlDocument& xmlDoc, wxString name ) {
309     TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "UTF-8", "" );
310     xmlDoc.LinkEndChild( decl );
311 
312     TiXmlElement* kml = new TiXmlElement( "kml" );
313     kml->SetAttribute( "xmlns:atom", "http://www.w3.org/2005/Atom" );
314     kml->SetAttribute( "xmlns", "http://www.opengis.net/kml/2.2" );
315     kml->SetAttribute( "xmlns:gx", "http://www.google.com/kml/ext/2.2" );
316     kml->SetAttribute( "xmlns:kml", "http://www.opengis.net/kml/2.2" );
317 
318     if( insertQtVlmExtendedData )
319         kml->SetAttribute( "xmlns:vlm", "http://virtual-loup-de-mer.org" );
320 
321     xmlDoc.LinkEndChild( kml );
322 
323     TiXmlElement* document = new TiXmlElement( "Document" );
324     kml->LinkEndChild( document );
325     TiXmlElement* docName = new TiXmlElement( "name" );
326     document->LinkEndChild( docName );
327     TiXmlText* docNameVal = new TiXmlText( name.mb_str( wxConvUTF8 ) );
328     docName->LinkEndChild( docNameVal );
329     return document;
330 }
331 
PointPlacemark(TiXmlElement * document,RoutePoint * routepoint)332 std::string Kml::PointPlacemark(  TiXmlElement* document, RoutePoint* routepoint ) {
333     TiXmlElement* pmPoint = new TiXmlElement( "Placemark" );
334     document->LinkEndChild( pmPoint );
335     TiXmlElement* pmPointName = new TiXmlElement( "name" );
336     pmPoint->LinkEndChild( pmPointName );
337     TiXmlText* pmPointNameVal = new TiXmlText( routepoint->GetName().mb_str( wxConvUTF8 ) );
338     pmPointName->LinkEndChild( pmPointNameVal );
339 
340     TiXmlElement* pointDescr = new TiXmlElement( "description" );
341     pmPoint->LinkEndChild( pointDescr );
342 
343     bool descrIsPlainText = true;
344     wxCharBuffer descrString = routepoint->m_MarkDescription.mb_str( wxConvUTF8 );
345 
346     if( insertQtVlmExtendedData ) {
347         // Does the RoutePoint description parse as XML with an <ExtendedData> root tag?
348         TiXmlDocument descrDoc;
349         TiXmlElement* extendedData;
350         if( descrDoc.Parse( descrString, 0, TIXML_ENCODING_UTF8 ) ) {
351             if( 0 == strncmp( descrDoc.RootElement()->Value(), "ExtendedData", 12 ) ) {
352                 descrIsPlainText = false;
353                 extendedData = descrDoc.RootElement();
354                 TiXmlHandle docHandle( &descrDoc );
355                 TiXmlElement* seq = docHandle.FirstChild( "ExtendedData" ).FirstChild( "vlm:sequence" ).ToElement();
356                 if( ! seq ) {
357                     seq = new TiXmlElement( "vlm:sequence" );
358                     TiXmlText* snVal = new TiXmlText(
359                             wxString::Format( _T("%04d"), seqCounter ).mb_str( wxConvUTF8 ) );
360                     seq->LinkEndChild( snVal );
361                     descrDoc.RootElement()->LinkEndChild( seq );
362                 }
363                 pmPoint->LinkEndChild( descrDoc.RootElement()->Clone() );
364             }
365         }
366         if( descrIsPlainText ) {
367             // We want Sequence names but there was some non-parsing stuff in the description.
368             // Push that into a sub-tag of an XML formatted description.
369             extendedData = new TiXmlElement( "ExtendedData" );
370             pmPoint->LinkEndChild( extendedData );
371             TiXmlElement* seq = new TiXmlElement( "vlm:sequence" );
372             extendedData->LinkEndChild( seq );
373             TiXmlText* snVal = new TiXmlText(
374                     wxString::Format( _T("%04d"), seqCounter ).mb_str( wxConvUTF8 ) );
375             seq->LinkEndChild( snVal );
376 
377             if( routepoint->m_MarkDescription.Length() ) {
378                 TiXmlElement* data = new TiXmlElement( "Data" );
379                 data->SetAttribute( "name", "Description" );
380                 extendedData->LinkEndChild( data );
381 
382                 TiXmlElement* value = new TiXmlElement( "value" );
383                 data->LinkEndChild( value );
384                 TiXmlText* txtVal = new TiXmlText( descrString );
385                 value->LinkEndChild( txtVal );
386             }
387         }
388         if( extendedData && seqCounter == 0 ) {
389             const wxCharBuffer ownshipPos = wxString::Format( _T("%f %f"), gLon, gLat ).mb_str( wxConvUTF8 );
390             TiXmlHandle h( extendedData );
391             TiXmlElement* route = h.FirstChild( "vlm:route" ).ToElement();
392             TiXmlElement* ownship = h.FirstChild( "vlm:route" ).FirstChild( "ownship" ).ToElement();
393             if( route ) {
394                 if( ownship ) {
395                     TiXmlText* owns = ownship->FirstChild()->ToText();
396                     if( owns ) {
397                         owns->SetValue( ownshipPos );
398                     } else {
399                         owns = new TiXmlText( ownshipPos );
400                         ownship->LinkEndChild( owns );
401                     }
402                 } else {
403                     ownship = new TiXmlElement( "ownship" );
404                     route->LinkEndChild( ownship );
405                     TiXmlText* owns = new TiXmlText( ownshipPos );
406                     ownship->LinkEndChild( owns );
407                 }
408             } else {
409                 route = new TiXmlElement( "vlm:route" );
410                 extendedData->LinkEndChild( route );
411                 ownship = new TiXmlElement( "ownship" );
412                 route->LinkEndChild( ownship );
413                 TiXmlText* owns = new TiXmlText( ownshipPos );
414                 ownship->LinkEndChild( owns );
415             }
416         }
417     }
418 
419     else {
420         // Add description as dumb text.
421         TiXmlText* pointDescrVal = new TiXmlText( descrString );
422         pointDescr->LinkEndChild( pointDescrVal );
423     }
424 
425     TiXmlElement* point = new TiXmlElement( "Point" );
426     pmPoint->LinkEndChild( point );
427 
428     TiXmlElement* pointCoord = new TiXmlElement( "coordinates" );
429     point->LinkEndChild( pointCoord );
430 
431     std::stringstream pointCoordStr;
432     pointCoordStr << routepoint->m_lon << "," << routepoint->m_lat << ",0. ";
433 
434     TiXmlText* pointText = new TiXmlText( pointCoordStr.str() );
435     pointCoord->LinkEndChild( pointText );
436 
437     return pointCoordStr.str();
438 }
439 
MakeKmlFromRoute(Route * route,bool insertSeq)440 wxString Kml::MakeKmlFromRoute( Route* route, bool insertSeq ) {
441     insertQtVlmExtendedData = insertSeq;
442     seqCounter = 0;
443     TiXmlDocument xmlDoc;
444     wxString name = _("OpenCPN Route");
445     if( route->m_RouteNameString.Length() ) name = route->m_RouteNameString;
446     TiXmlElement* document = StandardHead( xmlDoc, name );
447 
448     std::stringstream lineStringCoords;
449 
450     RoutePointList *pointList = route->pRoutePointList;
451     wxRoutePointListNode *pointnode = pointList->GetFirst();
452     RoutePoint *routepoint;
453 
454     while( pointnode ) {
455         routepoint = pointnode->GetData();
456 
457         lineStringCoords << PointPlacemark( document, routepoint );
458         seqCounter++;
459         pointnode = pointnode->GetNext();
460     }
461 
462     TiXmlElement* pmPath = new TiXmlElement( "Placemark" );
463     document->LinkEndChild( pmPath );
464 
465     TiXmlElement* pmName = new TiXmlElement( "name" );
466     pmPath->LinkEndChild( pmName );
467     TiXmlText* pmNameVal = new TiXmlText( "Path" );
468     pmName->LinkEndChild( pmNameVal );
469 
470     TiXmlElement* linestring = new TiXmlElement( "LineString" );
471     pmPath->LinkEndChild( linestring );
472 
473     TiXmlElement* coordinates = new TiXmlElement( "coordinates" );
474     linestring->LinkEndChild( coordinates );
475 
476     TiXmlText* text = new TiXmlText( lineStringCoords.str() );
477     coordinates->LinkEndChild( text );
478 
479     TiXmlPrinter printer;
480     printer.SetIndent( "  " );
481     xmlDoc.Accept( &printer );
482 
483     return wxString( printer.CStr(), wxConvUTF8 );
484 }
485 
486 
MakeKmlFromTrack(Track * track)487 wxString Kml::MakeKmlFromTrack( Track* track ) {
488     TiXmlDocument xmlDoc;
489     wxString name = _("OpenCPN Track");
490     if( track->GetName().Length() ) name = track->GetName();
491     TiXmlElement* document = StandardHead( xmlDoc, name );
492 
493     TiXmlElement* pmTrack = new TiXmlElement( "Placemark" );
494     document->LinkEndChild( pmTrack );
495 
496     TiXmlElement* pmName = new TiXmlElement( "name" );
497     pmTrack->LinkEndChild( pmName );
498     TiXmlText* pmNameVal = new TiXmlText( track->GetName().mb_str( wxConvUTF8 ) );
499     pmName->LinkEndChild( pmNameVal );
500 
501     TiXmlElement* gxTrack = new TiXmlElement( "gx:Track" );
502     pmTrack->LinkEndChild( gxTrack );
503 
504     std::stringstream lineStringCoords;
505 
506     for(int i=0; i<track->GetnPoints(); i++) {
507         TrackPoint *trackpoint = track->GetPoint(i);
508 
509         TiXmlElement* when = new TiXmlElement( "when" );
510         gxTrack->LinkEndChild( when );
511 
512         wxDateTime whenTime( trackpoint->GetCreateTime() );
513         TiXmlText* whenVal = new TiXmlText( whenTime.Format( _T("%Y-%m-%dT%H:%M:%SZ") ).mb_str( wxConvUTF8 ) );
514         when->LinkEndChild( whenVal );
515     }
516 
517     for(int i=0; i<track->GetnPoints(); i++) {
518         TrackPoint *trackpoint = track->GetPoint(i);
519 
520         TiXmlElement* coord = new TiXmlElement( "gx:coord" );
521         gxTrack->LinkEndChild( coord );
522         wxString coordStr = wxString::Format( _T("%f %f 0.0"), trackpoint->m_lon, trackpoint->m_lat );
523         TiXmlText* coordVal = new TiXmlText( coordStr.mb_str( wxConvUTF8 ) );
524         coord->LinkEndChild( coordVal );
525     }
526 
527 
528     TiXmlPrinter printer;
529     printer.SetIndent( "  " );
530     xmlDoc.Accept( &printer );
531 
532     return wxString( printer.CStr(), wxConvUTF8 );
533 }
534 
MakeKmlFromWaypoint(RoutePoint * routepoint)535 wxString Kml::MakeKmlFromWaypoint( RoutePoint* routepoint ) {
536     TiXmlDocument xmlDoc;
537     wxString name = _("OpenCPN Waypoint");
538     if( routepoint->GetName().Length() ) name = routepoint->GetName();
539     TiXmlElement* document = StandardHead( xmlDoc, name );
540 
541     insertQtVlmExtendedData = false;
542     PointPlacemark( document, routepoint );
543 
544     TiXmlPrinter printer;
545     printer.SetIndent( "  " );
546     xmlDoc.Accept( &printer );
547 
548     return wxString( printer.CStr(), wxConvUTF8 );
549 }
550 
CopyRouteToClipboard(Route * route)551 void Kml::CopyRouteToClipboard( Route* route ) {
552     KmlFormatDialog* formatDlg = new KmlFormatDialog( gFrame );
553     int format = formatDlg->ShowModal();
554 
555     if( format != wxID_CANCEL ) {
556         format = formatDlg->GetSelectedFormat();
557         bool extradata = (format == KML_COPY_EXTRADATA);
558 
559         ::wxBeginBusyCursor();
560         if( wxTheClipboard->Open() ) {
561             wxTextDataObject* data = new wxTextDataObject;
562             data->SetText( MakeKmlFromRoute( route, extradata ) );
563             wxTheClipboard->SetData( data );
564         }
565         ::wxEndBusyCursor();
566     }
567         delete formatDlg;
568 }
569 
CopyTrackToClipboard(Track * track)570 void Kml::CopyTrackToClipboard( Track* track ) {
571     ::wxBeginBusyCursor();
572     if( wxTheClipboard->Open() ) {
573         wxTextDataObject* data = new wxTextDataObject;
574         data->SetText( MakeKmlFromTrack( track ) );
575         wxTheClipboard->SetData( data );
576     }
577     ::wxEndBusyCursor();
578 }
579 
CopyWaypointToClipboard(RoutePoint * rp)580 void Kml::CopyWaypointToClipboard( RoutePoint* rp ) {
581     if( wxTheClipboard->Open() ) {
582         wxTextDataObject* data = new wxTextDataObject;
583         data->SetText( MakeKmlFromWaypoint( rp ) );
584         wxTheClipboard->SetData( data );
585     }
586 }
587 
Kml()588 Kml::Kml() {
589     parsedRoute = NULL;
590     parsedTrack = NULL;
591     parsedRoutePoint = NULL;
592 }
593 
~Kml()594 Kml::~Kml() {
595     delete parsedTrack;
596     if( parsedRoute ) {
597         for( int i=1; i<=parsedRoute->GetnPoints(); i++ ) {
598             if( parsedRoute->GetPoint(i) ) delete parsedRoute->GetPoint(i);
599         }
600         delete parsedRoute;
601     }
602     delete parsedRoutePoint;
603 }
604 
605 //----------------------------------------------------------------------------------
606 
KmlFormatDialog(wxWindow * parent)607 KmlFormatDialog::KmlFormatDialog( wxWindow* parent )
608        : wxDialog( parent, wxID_ANY, _("Choose Format for Copy"), wxDefaultPosition, wxSize(250, 230) )
609 {
610     wxBoxSizer* topSizer = new wxBoxSizer( wxVERTICAL );
611 
612     wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
613     topSizer->Add( sizer, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5 );
614 
615     choices.push_back( new wxRadioButton( this, KML_COPY_STANDARD, _("KML Standard (Google Earth and others)"),
616             wxDefaultPosition, wxDefaultSize, wxRB_GROUP ) );
617 
618     choices.push_back( new wxRadioButton( this, KML_COPY_EXTRADATA, _("KML with extended waypoint data (QtVlm)"),
619             wxDefaultPosition) );
620 
621     wxStdDialogButtonSizer* buttonSizer = CreateStdDialogButtonSizer( wxOK | wxCANCEL );
622 
623     sizer->Add( choices[0], 0, wxEXPAND | wxALL, 5 );
624     sizer->Add( choices[1], 0, wxEXPAND | wxALL, 5 );
625     sizer->Add( buttonSizer, 0, wxEXPAND | wxTOP, 5 );
626 
627     topSizer->SetSizeHints(this);
628     SetSizer( topSizer );
629 }
630 
GetSelectedFormat()631 int KmlFormatDialog::GetSelectedFormat() {
632     for( unsigned int i=0; i<choices.size(); i++ ) {
633         if( choices[i]->GetValue() ) return choices[i]->GetId();
634     }
635     return 0;
636 }
637 
638