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