Qt Virtual Chart Table (QVCT)
CRouteContainer.cpp
Go to the documentation of this file.
1 // INDENTING (emacs/vi): -*- mode:c++; tab-width:2; c-basic-offset:2; intent-tabs-mode:nil; -*- ex: set tabstop=2 expandtab:
2 
3 /*
4  * Qt Virtual Chart Table (QVCT)
5  * Copyright (C) 2012 Cedric Dufour <http://cedric.dufour.name>
6  * Author: Cedric Dufour <http://cedric.dufour.name>
7  *
8  * The Qt Virtual Chart Table (QVCT) is free software:
9  * you can redistribute it and/or modify it under the terms of the GNU General
10  * Public License as published by the Free Software Foundation, Version 3.
11  *
12  * The Qt Virtual Chart Table (QVCT) is distributed in the hope
13  * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
14  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * See the GNU General Public License for more details.
17  */
18 
19 // QT
20 #include <QDomElement> // QtXml module
21 #include <QFileInfo>
22 #include <QFileDialog>
23 #include <QPainter>
24 #include <QPointF>
25 #include <QTreeWidgetItem>
26 
27 // QVCT
28 #include "QVCTRuntime.hpp"
32 
33 
34 //------------------------------------------------------------------------------
35 // CONSTRUCTORS / DESTRUCTOR
36 //------------------------------------------------------------------------------
37 
38 CRouteContainer::CRouteContainer( const QString& _rqsName )
39  : COverlayContainer( COverlayObject::CONTAINER, _rqsName )
40  , qsType()
41  , qsDescription()
42  , qsComment()
43  , qsUrl()
44 {
45  QTreeWidgetItem::setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled );
46  QTreeWidgetItem::setText( CRouteOverlay::NAME, qsName );
47  QTreeWidgetItem::setCheckState( CRouteOverlay::VISIBLE, Qt::Checked );
48  bVisibleRouting = true;
49 }
50 
52 {
53  QTreeWidgetItem* __pqTreeWidgetItem = QTreeWidgetItem::takeChild( 0 );
54  while( __pqTreeWidgetItem )
55  {
56  delete (CRoutePoint*)__pqTreeWidgetItem;
57  __pqTreeWidgetItem = QTreeWidgetItem::takeChild( 0 );
58  }
59 }
60 
61 
62 //------------------------------------------------------------------------------
63 // METHODS: COverlayObject (implement/override)
64 //------------------------------------------------------------------------------
65 
66 void CRouteContainer::serialize( QDataStream& _rqDataStream ) const
67 {
68  COverlayObject::serialize( _rqDataStream );
69  _rqDataStream << qsType << qsDescription << qsComment << qsUrl;
70 }
71 
72 void CRouteContainer::unserialize( QDataStream& _rqDataStream )
73 {
74  COverlayObject::unserialize( _rqDataStream );
75  _rqDataStream >> qsType >> qsDescription >> qsComment >> qsUrl;
76  QTreeWidgetItem::setText( CRouteOverlay::NAME, qsName );
77 }
78 
79 void CRouteContainer::draw( const CChart* _poChart, QPainter* _pqPainter )
80 {
81  if( !bVisible ) return;
82  int __iCount = QTreeWidgetItem::childCount();
83  if( !__iCount ) return;
84  CRoutePoint* __poRoutePointFrom = (CRoutePoint*)QTreeWidgetItem::child( 0 );
85  if( __iCount == 1 )
86  {
87  __poRoutePointFrom->draw( _poChart, _pqPainter );
88  return;
89  }
90  CRoutePoint* __poRoutePointTo = 0;
91  for( int __i = 1; __i < __iCount; __i++ )
92  {
93  __poRoutePointTo = (CRoutePoint*)QTreeWidgetItem::child( __i );
94  __poRoutePointFrom->drawLine( _poChart, _pqPainter, __poRoutePointTo );
95  __poRoutePointFrom->draw( _poChart, _pqPainter );
96  __poRoutePointFrom = __poRoutePointTo;
97  }
98  __poRoutePointTo->draw( _poChart, _pqPainter );
99 }
100 
102 {
108 }
109 
111 {
112  CRouteContainerEditView* __poRouteContainerEditView = new CRouteContainerEditView( this );
113  if( __poRouteContainerEditView->exec() == QDialog::Accepted ) showDetail();
114  delete __poRouteContainerEditView;
115 }
116 
117 
118 //------------------------------------------------------------------------------
119 // METHODS: COverlayContainer (implement/override)
120 //------------------------------------------------------------------------------
121 
122 COverlayPoint* CRouteContainer::matchScrPosition( const CChart* _poChart, const QPointF& _rqPointFScrPosition ) const
123 {
124  if( !bVisible ) return 0;
125  int __iCount = QTreeWidgetItem::childCount();
126  for( int __i = __iCount-1 ; __i >= 0; __i-- ) // we must go in the reverse order of CRouteContainer::draw() to pick the correct (overlapping) item
127  {
128  COverlayPoint* __poOverlayPoint = (COverlayPoint*)QTreeWidgetItem::child( __i );
129  if( __poOverlayPoint->matchScrPosition( _poChart, _rqPointFScrPosition ) )
130  return __poOverlayPoint;
131  }
132  return 0;
133 }
134 
135 
136 //------------------------------------------------------------------------------
137 // METHODS: COverlayVisibility (override)
138 //------------------------------------------------------------------------------
139 
140 void CRouteContainer::setVisibleName( bool _bVisibleName )
141 {
142  bVisibleName = _bVisibleName;
143  int __iCount = QTreeWidgetItem::childCount();
144  for( int __i = 0; __i < __iCount; __i++ )
145  ((CRoutePoint*)QTreeWidgetItem::child( __i ))->setVisibleName( bVisibleName );
146 }
147 
148 void CRouteContainer::setVisiblePosition( bool _bVisiblePosition )
149 {
150  bVisiblePosition = _bVisiblePosition;
151  int __iCount = QTreeWidgetItem::childCount();
152  for( int __i = 0; __i < __iCount; __i++ )
153  ((CRoutePoint*)QTreeWidgetItem::child( __i ))->setVisiblePosition( bVisiblePosition );
154 }
155 
156 void CRouteContainer::setVisibleRouting( bool _bVisibleRouting )
157 {
158  bVisibleRouting = _bVisibleRouting;
159  int __iCount = QTreeWidgetItem::childCount();
160  for( int __i = 0; __i < __iCount; __i++ )
161  ((CRoutePoint*)QTreeWidgetItem::child( __i ))->setVisibleRouting( bVisibleRouting );
162 }
163 
165 {
166  // Toggle global visibility
168  // Set points visibility
169  int __iCount = QTreeWidgetItem::childCount();
170  for( int __i = 0; __i < __iCount; __i++ )
171  {
172  CRoutePoint* __poRoutePoint = (CRoutePoint*)QTreeWidgetItem::child( __i );
173  __poRoutePoint->setVisibleName( bVisibleName );
174  __poRoutePoint->setVisiblePosition( bVisiblePosition );
175  __poRoutePoint->setVisibleRouting( bVisibleRouting );
176  }
177 }
178 
179 
180 //------------------------------------------------------------------------------
181 // METHODS
182 //------------------------------------------------------------------------------
183 
184 //
185 // OTHER
186 //
187 
188 CRoutePoint* CRouteContainer::addPoint( const QString& _rqsName, const CDataPosition& _roDataPosition, bool _bMinimizeLength )
189 {
190  CRoutePoint* __poRoutePoint = new CRoutePoint( _rqsName, _roDataPosition );
191  __poRoutePoint->setVisibility( this->getVisibility() | 1 );
192  int __iCount = QTreeWidgetItem::childCount();
193  int __iIndex = __iCount;
194  if( _bMinimizeLength && __iCount > 1 )
195  __iIndex = this->getInsertIndexMinLength( *__poRoutePoint );
196  QTreeWidgetItem::insertChild( __iIndex, __poRoutePoint );
197  return __poRoutePoint;
198 }
199 
201 {
202  int __iCount = QTreeWidgetItem::childCount();
203  if( __iCount < 2 ) return 0.0;
204  CRoutePoint* __poRoutePathFrom = (CRoutePoint*)QTreeWidgetItem::child( 0 );
205  CRoutePoint* __poRoutePathTo = 0;
206  double __fdLength = 0;
207  for( int __i = 1; __i < __iCount; __i++ )
208  {
209  __poRoutePathTo = (CRoutePoint*)QTreeWidgetItem::child( __i );
210  __fdLength += CDataPosition::distanceRL( *__poRoutePathFrom, *__poRoutePathTo );
211  __poRoutePathFrom = __poRoutePathTo;
212  }
213  return __fdLength;
214 }
215 
217 {
218  int __iCount = QTreeWidgetItem::childCount();
219  if( __iCount < 2 ) return __iCount;
220 
221  // Compute current overall length (and detect overlapping waypoint)
222  CRoutePoint* __poRoutePathFrom = (CRoutePoint*)QTreeWidgetItem::child( 0 );
223  if( CDataPosition::length( *__poRoutePathFrom, _roDataPosition ) < 10.0 )
224  return __iCount; // best to append overlapping (nonsensical) waypoint
225  CRoutePoint* __poRoutePathTo = 0;
226  double __fdLengthCurrent = 0;
227  for( int __i = 1; __i < __iCount; __i++ )
228  {
229  __poRoutePathTo = (CRoutePoint*)QTreeWidgetItem::child( __i );
230  if( CDataPosition::length( _roDataPosition, *__poRoutePathTo ) < 10.0 )
231  return __iCount; // best to append overlapping (nonsensical) waypoint
232  __fdLengthCurrent += CDataPosition::length( *__poRoutePathFrom, *__poRoutePathTo );
233  __poRoutePathFrom = __poRoutePathTo;
234  }
235 
236  // Find index that minimizes length
237  int __iIndexBest = __iCount;
238  double __fdLengthBest = __fdLengthCurrent + CDataPosition::length( *__poRoutePathFrom, _roDataPosition );
239  for( int __iIndexCandidate = 1; __iIndexCandidate < __iCount; __iIndexCandidate++ )
240  {
241  double __fdLengthCandidate = __fdLengthCurrent;
242  for( int __i = 1; __i < __iCount; __i++ )
243  {
244  if( __i == __iIndexCandidate )
245  {
246  __poRoutePathFrom = (CRoutePoint*)QTreeWidgetItem::child( __i-1 );
247  __poRoutePathTo = (CRoutePoint*)QTreeWidgetItem::child( __i );
248  __fdLengthCandidate -= CDataPosition::length( *__poRoutePathFrom, *__poRoutePathTo );
249  __fdLengthCandidate += CDataPosition::length( *__poRoutePathFrom, _roDataPosition );
250  __fdLengthCandidate += CDataPosition::length( _roDataPosition, *__poRoutePathTo );
251  }
252  }
253  if( __fdLengthCandidate <= __fdLengthBest || __fdLengthBest < 0 )
254  {
255  __iIndexBest = __iIndexCandidate;
256  __fdLengthBest = __fdLengthCandidate;
257  }
258  }
259  return __iIndexBest;
260 }
261 
262 int CRouteContainer::parseQVCT( const QDomElement& _rqDomElement )
263 {
264  COverlayVisibility::setVisibility( _rqDomElement.attribute( "visibility", "19" ).toInt() );
265  QTreeWidgetItem::setCheckState( CRouteOverlay::VISIBLE, bVisible ? Qt::Checked : Qt::Unchecked );
266  qsType = _rqDomElement.attribute( "type" );
267  qsUrl = _rqDomElement.attribute( "url" );
268  qsDescription = _rqDomElement.firstChildElement( "Description" ).text();
269  qsComment = _rqDomElement.firstChildElement( "Comment" ).text();
270  int __iCount = 0;
271  for( QDomElement __qDomElement = _rqDomElement.firstChildElement( "Point" );
272  !__qDomElement.isNull();
273  __qDomElement = __qDomElement.nextSiblingElement( "Point" ) )
274  {
275  __iCount++;
276  QString __qsName = __qDomElement.attribute( "name" );
277  if( __qsName.isEmpty() ) COverlayObject::newChildName( tr("Waypoint"), 1, __iCount );
278  CRoutePoint* __poRoutePoint = new CRoutePoint( __qsName );
279  __poRoutePoint->parseQVCT( __qDomElement );
280  addChild( __poRoutePoint );
281  }
282  return __iCount;
283 }
284 
285 int CRouteContainer::parseGPX( const QDomElement& _rqDomElement )
286 {
287  // GPX format reference: see http://www.topografix.com/GPX/1/1/
288  qsType = _rqDomElement.firstChildElement( "type" ).text();
289  qsDescription = _rqDomElement.firstChildElement( "desc" ).text();
290  qsComment = _rqDomElement.firstChildElement( "cmt" ).text();
291  qsUrl = _rqDomElement.firstChildElement( "link" ).attribute( "href" );
292  int __iCount = 0;
293  for( QDomElement __qDomElement = _rqDomElement.firstChildElement( "rtept" );
294  !__qDomElement.isNull();
295  __qDomElement = __qDomElement.nextSiblingElement( "rtept" ) )
296  {
297  __iCount++;
298  QString __qsName = __qDomElement.firstChildElement( "name" ).text();
299  if( __qsName.isEmpty() ) COverlayObject::newChildName( tr("Waypoint"), 1, __iCount );
300  CRoutePoint* __poRoutePoint = new CRoutePoint( __qsName );
301  __poRoutePoint->parseGPX( __qDomElement );
302  addChild( __poRoutePoint );
303  }
304  return __iCount;
305 }
306 
307 void CRouteContainer::dumpQVCT( QXmlStreamWriter & _rqXmlStreamWriter, bool bOnlySelected ) const
308 {
309  // Data
310  _rqXmlStreamWriter.writeStartElement( "Route" );
311  // ... name
312  if( !qsName.isEmpty() ) _rqXmlStreamWriter.writeAttribute( "name", qsName );
313  // ... visibility
314  _rqXmlStreamWriter.writeAttribute( "visibility", QString::number( COverlayVisibility::getVisibility() ) );
315  // ... type
316  if( !qsType.isEmpty() ) _rqXmlStreamWriter.writeAttribute( "type", qsType );
317  // ... url
318  if( !qsUrl.isEmpty() ) _rqXmlStreamWriter.writeAttribute( "url", qsUrl );
319  // ... description
320  if( !qsDescription.isEmpty() )
321  {
322  _rqXmlStreamWriter.writeStartElement( "Description" );
323  _rqXmlStreamWriter.writeCDATA( qsDescription );
324  _rqXmlStreamWriter.writeEndElement(); // Description
325  }
326  // ... comment
327  if( !qsComment.isEmpty() )
328  {
329  _rqXmlStreamWriter.writeStartElement( "Comment" );
330  _rqXmlStreamWriter.writeCDATA( qsComment );
331  _rqXmlStreamWriter.writeEndElement(); // Comment
332  }
333  // ... points
334  int __iCount = QTreeWidgetItem::childCount();
335  for( int __i = 0; __i < __iCount; __i++ )
336  {
337  CRoutePoint* __poRoutePoint = (CRoutePoint*)QTreeWidgetItem::child( __i );
338  if( bOnlySelected && !__poRoutePoint->isMultiSelected() ) continue;
339  __poRoutePoint->dumpQVCT( _rqXmlStreamWriter );
340  }
341  // ... [end]
342  _rqXmlStreamWriter.writeEndElement(); // Route
343 }
344 
345 void CRouteContainer::dumpGPX( QXmlStreamWriter & _rqXmlStreamWriter, bool bOnlySelected ) const
346 {
347  // GPX format reference: see http://www.topografix.com/GPX/1/1/
348 
349  // Data
350  _rqXmlStreamWriter.writeStartElement( "rte" );
351  // ... name
352  if( !qsName.isEmpty() )
353  {
354  _rqXmlStreamWriter.writeStartElement( "name" );
355  _rqXmlStreamWriter.writeCharacters( qsName );
356  _rqXmlStreamWriter.writeEndElement(); // name
357  }
358  // ... type
359  if( !qsType.isEmpty() )
360  {
361  _rqXmlStreamWriter.writeStartElement( "type" );
362  _rqXmlStreamWriter.writeCharacters( qsType );
363  _rqXmlStreamWriter.writeEndElement(); // type
364  }
365  // ... description
366  if( !qsDescription.isEmpty() )
367  {
368  _rqXmlStreamWriter.writeStartElement( "desc" );
369  _rqXmlStreamWriter.writeCDATA( qsDescription );
370  _rqXmlStreamWriter.writeEndElement(); // desc
371  }
372  // ... comment
373  if( !qsComment.isEmpty() )
374  {
375  _rqXmlStreamWriter.writeStartElement( "cmt" );
376  _rqXmlStreamWriter.writeCDATA( qsComment );
377  _rqXmlStreamWriter.writeEndElement(); // cmt
378  }
379  // ... url
380  if( !qsUrl.isEmpty() )
381  {
382  _rqXmlStreamWriter.writeStartElement( "link" );
383  _rqXmlStreamWriter.writeAttribute( "href", qsUrl );
384  _rqXmlStreamWriter.writeEndElement(); // link
385  }
386  // ... points
387  int __iCount = QTreeWidgetItem::childCount();
388  for( int __i = 0; __i < __iCount; __i++ )
389  {
390  CRoutePoint* __poRoutePoint = (CRoutePoint*)QTreeWidgetItem::child( __i );
391  if( bOnlySelected && !__poRoutePoint->isMultiSelected() ) continue;
392  __poRoutePoint->dumpGPX( _rqXmlStreamWriter );
393  }
394  // ... [end]
395  _rqXmlStreamWriter.writeEndElement(); // rte
396 }
397 
399 {
400  int __iCount = 0;
401  for( int __i = QTreeWidgetItem::childCount()-1; __i >= 0; __i-- )
402  {
403  CRoutePoint* __poRoutePoint = (CRoutePoint*)QTreeWidgetItem::child( __i );
404  if( __poRoutePoint->isMultiSelected() )
405  {
406  __iCount++;
407  QTreeWidgetItem::removeChild( __poRoutePoint );
408  delete __poRoutePoint;
409  }
410  }
411  return __iCount;
412 }
void setOverlayObjectSelected(COverlayObject *_poOverlayObject)
Sets the currently selected overlay object.
[UI] Chart (view)
Definition: CChart.hpp:44
(Geographical) Position data [long,lat,elev]
static double distanceRL(const CDataPosition &_roPosition1, const CDataPosition &_roPosition2)
Returns the rhumb-line distance between two points, in meters.
static double length(const CDataPosition &_roPosition1, const CDataPosition &_roPosition2)
Returns the length (rhumb-line distance and elevation delta) between two points, in meters.
Generic overlay container.
void switchView(EView eView)
Displays the requested container/item details (switching to the appropriate widget)
@ ROUTE_CONTAINER
Route container.
bool isMultiSelected() const
Returns this item's selection status.
@ ROUTE
Route overlay.
void switchView(EView eView)
Displays the requested overlay (switching to the appropriate tab)
void setOverlayObject(COverlayObject *_poOverlayObject)
Sets the overlay object to be displayed (and refreshes the underlying widget)
Generic overlay object.
virtual void serialize(QDataStream &_rqDataStream) const
Serializes (store) this object's data to binary format.
virtual void unserialize(QDataStream &_rqDataStream)
Unserializes (restore) this object's data from binary format.
QString newChildName(const QString &_rqsName, int _iZeroPrefix=0, bool _bForceSuffix=false) const
Returns a valid (non-duplicate) name for a new sibling of this object.
QString qsName
Object name.
Generic overlay point.
virtual bool matchScrPosition(const CChart *_poChart, const QPointF &_rqPointFScrPosition) const
Returns whether this point matches the given screen position.
virtual void drawLine(const CChart *_poChart, QPainter *_pqPainter, const COverlayPoint *_poOverlayPoint)
Draws a line (between this and the other specified point), including distance/bearing data.
bool bVisibleRouting
Routing's (data) visibility status.
virtual void setVisiblePosition(bool _bVisiblePosition)
Sets the position's visibility status.
void setVisibility(int _iVisibilityCode)
Sets the global (coded) visibility status.
virtual void setVisibleRouting(bool _bVisibleRouting)
Sets the routing's (data) visibility status.
virtual void toggleVisibility(bool _bIncludeCourse, bool _bIncludeRouting)
Toggle the visibility status.
bool bVisible
Global (marker) visibility status.
bool bVisiblePosition
Position's visibility status.
bool bVisibleName
Name's (tag) visibility status.
int getVisibility() const
Returns the global (coded) visibility status.
virtual void setVisibleName(bool _bVisibleName)
Sets the name's (tag) visibility status.
virtual void refreshContent()
Refreshes the content of the underlying widget.
[UI] Route container's edit view
virtual void setVisiblePosition(bool _bVisiblePosition)
Sets the position's visibility status.
QString qsComment
Route's comment.
virtual void setVisibleRouting(bool _bVisibleRouting)
Sets the routing's (data) visibility status.
virtual void toggleVisibility()
virtual ~CRouteContainer()
virtual void setVisibleName(bool _bVisibleName)
Sets the name's (tag) visibility status.
virtual void serialize(QDataStream &_rqDataStream) const
Serializes (store) this object's data to binary format.
CRoutePoint * addPoint(const QString &_rqsName, const CDataPosition &_roDataPosition=CDataPosition::UNDEFINED, bool _bMinimizeLength=false)
Add a new route (item/point) to this container.
virtual void draw(const CChart *_poChart, QPainter *_pqPainter)
Draws this object (itself or its content)
int deleteSelection()
Deletes selected items within this container.
double getLengthRL()
Returns the route's (rhumb-line) length.
QString qsUrl
Route's URL.
int getInsertIndexMinLength(const CDataPosition &_roDataPosition)
Returns the given point insertion index that minimizes the route's (rhumb-line) length.
virtual void showDetail()
Displays this object's details (in the appropriate widget/view)
virtual void unserialize(QDataStream &_rqDataStream)
Unserializes (restore) this object's data from binary format.
QString qsDescription
Route's description.
virtual COverlayPoint * matchScrPosition(const CChart *_poChart, const QPointF &_rqPointFScrPosition) const
Returns the overlay container's point that (first) matches the given screen position (0 if none is fo...
CRouteContainer(const QString &_rqsName)
int parseGPX(const QDomElement &_rqDomElement)
Retrieves this object's content from the given GPX source (file)
virtual void showEdit()
Displays this object's edit widget/view.
QString qsType
Route's type.
void dumpQVCT(QXmlStreamWriter &_rqXmlStreamWriter, bool bOnlySelected=false) const
Stores this object's content to the given QVCT destination (file)
int parseQVCT(const QDomElement &_rqDomElement)
Retrieves this object's content from the given QVCT source (file)
void dumpGPX(QXmlStreamWriter &_rqXmlStreamWriter, bool bOnlySelected=false) const
Stores this object's content to the given GPX destination (file)
@ VISIBLE
Route visibility status.
@ NAME
Route name.
[UI] Route overlay point (item) / waypoint
Definition: CRoutePoint.hpp:40
void dumpQVCT(QXmlStreamWriter &_rqXmlStreamWriter) const
Stores this object's content to the given QVCT destination (file)
void dumpGPX(QXmlStreamWriter &_rqXmlStreamWriter) const
Stores this object's content to the given GPX destination (file)
void parseQVCT(const QDomElement &_rqDomElement)
Retrieves this object's content from the given QVCT source (file)
virtual void draw(const CChart *_poChart, QPainter *_pqPainter)
Draws this object (itself or its content)
Definition: CRoutePoint.cpp:82
void parseGPX(const QDomElement &_rqDomElement)
Retrieves this object's content from the given GPX source (file)
static COverlayDetailView * useOverlayDetailView()
static COverlayListView * useOverlayListView()
static CChartTable * useChartTable()
static CRouteContainerDetailView * useRouteContainerDetailView()