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