Qt Virtual Chart Table (QVCT)
CVesselOverlay.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 <QByteArray>
21 #include <QDataStream>
22 #include <QDomDocument> // QtXml module
23 #include <QFileInfo>
24 #include <QList>
25 #include <QMimeData>
26 #include <QPainter>
27 #include <QPointF>
28 #include <QStringList>
29 #include <QTreeWidget>
30 #include <QTreeWidgetItem>
31 #include <QWidget>
32 #include <QXmlStreamWriter>
33 
34 // QVCT
35 #include "QVCTRuntime.hpp"
41 
42 
43 //------------------------------------------------------------------------------
44 // CONSTRUCTORS / DESTRUCTOR
45 //------------------------------------------------------------------------------
46 
47 CVesselOverlay::CVesselOverlay( QWidget* _pqParent )
48  : COverlayBaseTree( _pqParent, tr("Vessels") )
49 {
51 
52  // Tree widget
53  // ... columns
54  QTreeWidget::setColumnCount( 3 );
55  QTreeWidget::setColumnWidth( NAME, 184 );
56  // ... header
57  QTreeWidgetItem* __pqTreeWidgetItem = new QTreeWidgetItem();
58  __pqTreeWidgetItem->setText( NAME, tr("Name") );
59  __pqTreeWidgetItem->setIcon( VISIBLE, QIcon( ":icons/16x16/visible.png" ) );
60  __pqTreeWidgetItem->setIcon( SELECT, QIcon( ":icons/16x16/select.png" ) );
61  QTreeWidget::setHeaderItem( __pqTreeWidgetItem );
62  QTreeWidget::resizeColumnToContents( VISIBLE );
63  QTreeWidget::resizeColumnToContents( SELECT );
64  // ... top-level item
65  QTreeWidgetItem::setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable );
66  QTreeWidgetItem::setText( NAME, COverlay::qsName );
67  QTreeWidgetItem::setCheckState( VISIBLE, Qt::Checked );
68  // ... drag 'n drop
69  QTreeWidget::setDragDropMode( QAbstractItemView::InternalMove );
70 }
71 
73 {
75  clear();
76 }
77 
78 
79 //------------------------------------------------------------------------------
80 // METHODS: QTreeWidget (implement/override)
81 //------------------------------------------------------------------------------
82 
83 QStringList CVesselOverlay::mimeTypes() const
84 {
85  static const QStringList __qStringList( "application/qvct.vesselpoint" );
86  return __qStringList;
87 }
88 
89 QMimeData* CVesselOverlay::mimeData( const QList<QTreeWidgetItem*> _qListTreeWidgetItems ) const
90 {
91  QByteArray __qByteArray;
92  QDataStream __qDataStream( &__qByteArray, QIODevice::WriteOnly );
93  for( int __i=0; __i < _qListTreeWidgetItems.count(); __i++ )
94  {
95  QTreeWidgetItem* __pqTreeWidgetItem = _qListTreeWidgetItems.at( __i );
96  if( __pqTreeWidgetItem->type() != COverlayObject::ITEM ) continue;
97  CVesselPoint* __poVesselPoint = (CVesselPoint*)__pqTreeWidgetItem;
98  __poVesselPoint->serialize( __qDataStream );
99  }
100  QMimeData* __pqMimeData = new QMimeData();
101  __pqMimeData->setData( "application/qvct.vesselpoint", __qByteArray );
102  return __pqMimeData;
103 }
104 
105 bool CVesselOverlay::dropMimeData ( QTreeWidgetItem* _pqTreeWidgetItem, int _iIndex, const QMimeData* _pqMimeData, Qt::DropAction eAction )
106 {
107  if( !_pqTreeWidgetItem ) return false;
108  QByteArray __qByteArray = _pqMimeData->data( "application/qvct.vesselpoint" );
109  QDataStream __qDataStream( &__qByteArray, QIODevice::ReadOnly );
110  CVesselPoint* __poVesselPoint = 0;
111  while( !__qDataStream.atEnd() )
112  {
113  __poVesselPoint = new CVesselPoint( "#MIMEDATA#" );
114  __poVesselPoint->unserialize( __qDataStream );
115  _pqTreeWidgetItem->insertChild( _iIndex, __poVesselPoint );
116  }
117  if( __poVesselPoint ) QTreeWidget::setCurrentItem( __poVesselPoint );
118  return true;
119 }
120 
121 void CVesselOverlay::dropEvent( QDropEvent* _pqDropEvent )
122 {
123  QTreeWidget::dropEvent( _pqDropEvent );
126 }
127 
128 //------------------------------------------------------------------------------
129 // METHODS: COverlay (implement/override)
130 //------------------------------------------------------------------------------
131 
132 void CVesselOverlay::drawContent( const CChart* _poChart, QPainter* _pqPainter ) const
133 {
134  if( !bVisible ) return;
135  int __iCount = QTreeWidgetItem::childCount();
136  for( int __i = 0; __i < __iCount; __i++ )
137  ((CVesselContainer*)QTreeWidgetItem::child( __i ))->draw( _poChart, _pqPainter );
138 }
139 
140 void CVesselOverlay::showDetail( const QTreeWidgetItem* _pqTreeWidgetItem ) const
141 {
142  if( !_pqTreeWidgetItem ) return;
143  switch( _pqTreeWidgetItem->type() )
144  {
145 
147  {
148  CVesselContainer* __poVesselContainer = (CVesselContainer*)_pqTreeWidgetItem;
149  __poVesselContainer->showDetail();
150  }
151  break;
152 
154  {
155  CVesselPoint* __poVesselPoint = (CVesselPoint*)_pqTreeWidgetItem;
156  CChartTable* __poChartTable = QVCTRuntime::useChartTable();
157  if( __poVesselPoint->CDataPosition::operator!=( CDataPosition::UNDEFINED )
158  && ( __poChartTable->setPointerTarget( *__poVesselPoint )
159  || __poChartTable->extendPointerPath( *__poVesselPoint ) ) )
160  __poChartTable->showGeoPosition( *__poVesselPoint );
161  else
162  __poVesselPoint->showDetail();
163  }
164  break;
165 
167  {
168  CVesselContainerDevice* __poVesselContainerDevice = (CVesselContainerDevice*)_pqTreeWidgetItem;
169  __poVesselContainerDevice->showDetail();
170  }
171  break;
172 
174  {
175  CVesselPointDevice* __poVesselPointDevice = (CVesselPointDevice*)_pqTreeWidgetItem;
176  __poVesselPointDevice->showDetail();
177  }
178  break;
179 
180  default:;
181 
182  }
183 }
184 
185 void CVesselOverlay::setPosition( const QTreeWidgetItem* _pqTreeWidgetItem ) const
186 {
187  switch( _pqTreeWidgetItem->type() )
188  {
189 
191  if( _pqTreeWidgetItem->isExpanded() ) return; // NOTE: Expansion switch is handled *AFTER* this method is called
192  {
193  CDataPosition __oDataPositionLower, __oDataPositionUpper;
194  int __iCount = COverlayPoint::getPositionBox( (CVesselContainer*)_pqTreeWidgetItem, &__oDataPositionLower, &__oDataPositionUpper );
195  if( __iCount > 1 ) QVCTRuntime::useChartTable()->setScaleArea( __oDataPositionLower, __oDataPositionUpper, 0.9 );
196  else if( __iCount == 1 ) QVCTRuntime::useChartTable()->setGeoPosition( __oDataPositionLower );
197  }
198  break;
199 
201  {
202  CVesselPoint* __poVesselPoint = (CVesselPoint*)_pqTreeWidgetItem;
203  if( __poVesselPoint->CDataPosition::operator==( CDataPosition::UNDEFINED ) ) return;
204  QVCTRuntime::useChartTable()->setGeoPosition( *__poVesselPoint );
205  }
206  break;
207 
208  default:;
209 
210  }
211 }
212 
213 COverlayPoint* CVesselOverlay::matchScrPosition( const CChart* _poChart, const QPointF& _rqPointFScrPosition ) const
214 {
215  if( !bVisible ) return 0;
216  int __iCount = QTreeWidgetItem::childCount();
217  for( int __i = __iCount-1 ; __i >= 0; __i-- ) // we must go in the reverse order of CVesselOverlay::draw() to pick the correct (overlapping) item
218  {
219  CVesselContainer* __poVesselContainer = (CVesselContainer*)QTreeWidgetItem::child( __i );
220  COverlayPoint* __poOverlayPoint = __poVesselContainer->matchScrPosition( _poChart, _rqPointFScrPosition );
221  if( __poOverlayPoint ) return __poOverlayPoint;
222  }
223  return 0;
224 }
225 
226 
227 //------------------------------------------------------------------------------
228 // METHODS: COverlayBaseTree (implement/override)
229 //------------------------------------------------------------------------------
230 
231 void CVesselOverlay::onChange( QTreeWidgetItem* _pqTreeWidgetItem, int _iColumn )
232 {
233  bool bRedraw = false;
234  switch( _pqTreeWidgetItem->type() )
235  {
236 
238  {
239  switch( _iColumn )
240  {
241  case VISIBLE:
242  COverlay::setVisible( _pqTreeWidgetItem->checkState( VISIBLE ) == Qt::Checked );
243  bRedraw = true;
244  break;
245  default:;
246  }
247  }
248  break;
249 
251  {
252  CVesselContainer* __poVesselContainer = (CVesselContainer*)_pqTreeWidgetItem;
253  switch( _iColumn )
254  {
255  case NAME:
256  __poVesselContainer->setName( _pqTreeWidgetItem->text( NAME ) );
257  break;
258  case VISIBLE:
259  __poVesselContainer->setVisible( _pqTreeWidgetItem->checkState( VISIBLE ) == Qt::Checked );
260  bRedraw = true;
261  break;
262  default:;
263  }
264  }
265  break;
266 
268  {
269  CVesselPoint* __poVesselPoint = (CVesselPoint*)_pqTreeWidgetItem;
270  switch( _iColumn )
271  {
272  case NAME:
273  __poVesselPoint->setName( _pqTreeWidgetItem->text( NAME ) );
274  bRedraw = true;
275  break;
276  case VISIBLE:
277  __poVesselPoint->setVisible( _pqTreeWidgetItem->checkState( VISIBLE ) == Qt::Checked );
278  bRedraw = true;
279  break;
280  case SELECT:
281  __poVesselPoint->setMultiSelected( _pqTreeWidgetItem->checkState( SELECT ) == Qt::Checked );
282  bRedraw = true;
283  break;
284  default:;
285  }
286  }
287  break;
288 
289  default:;
290 
291  }
292 
293  // Redraw
294  if( bRedraw )
295  {
298  }
299 }
300 
301 
302 //------------------------------------------------------------------------------
303 // METHODS
304 //------------------------------------------------------------------------------
305 
306 //
307 // OTHER
308 //
309 
311 {
312  QColor __qColor = QVCTRuntime::useSettings()->getColorVessel();
313  __qColor.setAlpha( 128 );
314  qBrushMarker.setColor( __qColor );
315  __qColor.setAlpha( 192 );
316  qPenText.setColor( QColor::fromHsv( __qColor.hue(), __qColor.saturation(), std::min( 128, __qColor.value() ), 192 ) );
317  qPenMarker.setColor( __qColor );
318  qPenLine.setColor( __qColor );
319  qPenVector.setColor( __qColor );
320 }
321 
323 {
324  CVesselContainer* __poVesselContainer = new CVesselContainer( _rqsName );
325  QTreeWidgetItem::addChild( __poVesselContainer );
326  QTreeWidgetItem::setExpanded( true );
327  return __poVesselContainer;
328 }
329 
331 {
332  int __iCount = 0;
333  for( int __i = QTreeWidgetItem::childCount()-1; __i >= 0; __i-- )
334  __iCount += ((CVesselContainer*)QTreeWidgetItem::child( __i ))->deleteSelection();
335  return __iCount;
336 }
337 
339 {
340  QTreeWidgetItem* __pqTreeWidgetItem = QTreeWidgetItem::takeChild( 0 );
341  while( __pqTreeWidgetItem )
342  {
343  delete (CVesselContainer*)__pqTreeWidgetItem;
344  __pqTreeWidgetItem = QTreeWidgetItem::takeChild( 0 );
345  }
346 }
347 
348 CVesselContainer* CVesselOverlay::load( const QString& _rqsFilename )
349 {
350  QFileInfo __qFileInfo( _rqsFilename );
351  CVesselContainer* __poVesselContainer = 0;
352  QString __qsError;
353  do // error-catching context [begin]
354  {
355  // File
356  QFileInfo __qFileInfo( _rqsFilename );
357  QFile __qFile( __qFileInfo.absoluteFilePath() );
358  if( !__qFile.open( QIODevice::ReadOnly ) )
359  {
360  __qsError = QString( "Failed to open file (%1)" ).arg( __qFile.fileName() );
361  break;
362  }
363  QDomDocument __qDocDocument;
364  if( !__qDocDocument.setContent( &__qFile ) )
365  {
366  __qsError = QString( "Failed to parse XML (%1)" ).arg( __qFile.fileName() );
367  __qFile.close();
368  break;
369  }
370  __qFile.close();
371 
372  // XML
373  QDomElement __qDomElement = __qDocDocument.documentElement();
374  QString __qDocType = __qDomElement.nodeName();
375  if( __qDomElement.isNull() || __qDocType != "QVCT" )
376  {
377  __qsError = QString( "Invalid XML document type (%1); expected: 'QVCT'" ).arg( __qFile.fileName() );
378  break;
379  }
380  parseQVCT( __qDomElement, &__poVesselContainer );
381  }
382  while( false ); // error-catching context [end]
383  if( !__qsError.isEmpty() )
384  {
385  qCritical( "ERROR[%s]: %s", Q_FUNC_INFO, qPrintable( __qsError ) );
386  QVCTRuntime::useMainWindow()->fileError( QVCT::OPEN, _rqsFilename );
387  return 0;
388  }
389  QTreeWidgetItem::setExpanded( true );
390  return __poVesselContainer;
391 }
392 
393 int CVesselOverlay::parseQVCT( const QDomElement& _rqDomElement, CVesselContainer** _ppoVesselContainer )
394 {
395  CVesselContainer* __poVesselContainer = 0;
396  int __iCount = 0;
397  for( QDomElement __qDomElement = _rqDomElement.firstChildElement( "Flotilla" );
398  !__qDomElement.isNull();
399  __qDomElement = __qDomElement.nextSiblingElement( "Flotilla" ) )
400  {
401  __iCount++;
402  QString __qsName = __qDomElement.attribute( "name" );
403  if( !__qsName.isEmpty() ) __qsName = COverlay::newChildName( __qsName );
404  else __qsName = COverlay::newChildName( tr("Flotilla"), 1, true );
405  __poVesselContainer = new CVesselContainer( __qsName );
406  __poVesselContainer->parseQVCT( __qDomElement );
407  QTreeWidgetItem::addChild( __poVesselContainer );
408  }
409  if( _ppoVesselContainer ) *_ppoVesselContainer = __poVesselContainer;
410  return __iCount;
411 }
412 
413 void CVesselOverlay::save( const QString& _rqsFilename, CVesselContainer* _poVesselContainer ) const
414 {
415  QFileInfo __qFileInfo( _rqsFilename );
416  QString __qsFormat = __qFileInfo.suffix();
417  if( __qsFormat != "qvct" )
418  {
419  qCritical( "ERROR[%s]: Invalid file format/extention (%s); expected: 'qvct'", Q_FUNC_INFO, qPrintable( __qsFormat ) );
420  return;
421  }
422 
423  // File [open]
424  QFile __qFile( __qFileInfo.absoluteFilePath() );
425  if( !__qFile.open( QIODevice::WriteOnly ) )
426  {
427  qCritical( "ERROR[%s]: Failed to open file (%s)", Q_FUNC_INFO, qPrintable( __qFile.fileName() ) );
428  return;
429  }
430 
431  // XML [start]
432  QXmlStreamWriter __qXmlStreamWriter( &__qFile );
433  __qXmlStreamWriter.setAutoFormatting( true );
434  __qXmlStreamWriter.writeStartDocument();
435 
436  // Data
437  dumpQVCT( __qXmlStreamWriter, _poVesselContainer );
438 
439  // XML [end]
440  __qXmlStreamWriter.writeEndDocument();
441 
442  // File [close]
443  __qFile.close();
444 }
445 
446 void CVesselOverlay::dumpQVCT( QXmlStreamWriter & _rqXmlStreamWriter, CVesselContainer* _poVesselContainer, bool _bProjectDump ) const
447 {
448  // Data
449  if( !_bProjectDump ) _rqXmlStreamWriter.writeStartElement( "QVCT" );
450  // ... containers
451  if( _poVesselContainer )
452  {
453  _poVesselContainer->dumpQVCT( _rqXmlStreamWriter, false );
454  }
455  else // no container given; assume selection dump or full dump
456  {
457  int __iCount = QTreeWidgetItem::childCount();
458  for( int __i = 0; __i < __iCount; __i++ )
459  ((CVesselContainer*)QTreeWidgetItem::child( __i ))->dumpQVCT( _rqXmlStreamWriter, !_bProjectDump );
460  }
461  // ... [end]
462  if( !_bProjectDump ) _rqXmlStreamWriter.writeEndElement(); // QVCT
463 }
[UI] Virtual "chart table" (view)
Definition: CChartTable.hpp:55
bool extendPointerPath(const CDataPosition &_roGeoPosition)
Extends the pointer path; returns true if is was actually extended, false otherwise.
void setScaleArea(const CDataPosition &_roGeoPosition1, const CDataPosition &_roGeoPosition2, double _fdScaleCorrection=1.0)
Sets the reference scale factor to display the given (geographical) area (defined by its opposite cor...
void updateChart()
Update the (current) chart content (on screen)
bool setPointerTarget(const CDataPosition &_roGeoPosition)
Sets the pointer target's position; returns true if is was actually set, false otherwise.
void showGeoPosition(const CDataPosition &_roGeoPosition)
Shows the given (geographical) position on chart.
void setGeoPosition(const CDataPosition &_roGeoPosition, bool _bSkipCurrent=false)
Sets the reference chart (geographical) position.
[UI] Chart (view)
Definition: CChart.hpp:44
(Geographical) Position data [long,lat,elev]
static const CDataPosition UNDEFINED
Specific value for an undefined position.
void fileError(QVCT::EFileOperation _eFileOperation, const QString &_rqsFilename)
Displays a generic error message for an invalid file name and operation (open/save)
Generic overlay base (tree widget)
void destroy()
Prepare the underlying QTreeWidget for destruction.
void setMultiSelected(bool _bMultiSelected)
Sets this item's selection status.
@ SUBITEM1
Sub-item (type 1)
@ CONTAINER
Container.
@ SUBITEM2
Sub-item (type 2)
@ OVERLAY
(Base) overlay
void setName(const QString &_rqsName)
Sets this object's name.
Generic overlay point.
static int getPositionBox(const QTreeWidgetItem *_pqTreeWidgetItem, CDataPosition *_poDataPositionLower, CDataPosition *_poDataPositionUpper, int _iIndexMin=0, int _iIndexMax=-1)
Returns the minimal geographical positions box containing the points in the given overlay/container.
void setVisible(bool _bVisible)
Sets the point's (marker) visibility status.
void setVisible(bool _bVisible)
Sets this overlay items' global visibility status.
Definition: COverlay.hpp:113
QString newChildName(const QString &_rqsName, int __iZeroPrefix=0, bool __bForceSuffix=false) const
Returns a valid name for a new sibling of this object.
Definition: COverlay.cpp:123
QPen qPenLine
QPen used to draw lines on this overlay.
Definition: COverlay.hpp:91
QPen qPenVector
QPen used to draw vectors on this overlay.
Definition: COverlay.hpp:94
QPen qPenText
QPen used to draw text on this overlay.
Definition: COverlay.hpp:76
bool bVisible
Overlay items' global visibility status.
Definition: COverlay.hpp:56
void forceRedraw()
Forces this overlay's rendering (not matter its cache content)
Definition: COverlay.hpp:115
QString qsName
Overlay name.
Definition: COverlay.hpp:52
QBrush qBrushMarker
QBrush used to draw markers on this overlay.
Definition: COverlay.hpp:79
QPen qPenMarker
QPen used to draw markers on this overlay.
Definition: COverlay.hpp:82
QColor getColorVessel()
[Color] Returns the vessel overlay's base color
Definition: CSettings.hpp:420
virtual void showDetail()
Displays this object's details (in the appropriate widget/view)
[UI] Vessel overlay container / flotilla
virtual void showDetail()
Displays this object's details (in the appropriate widget/view)
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...
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)
virtual void onChange(QTreeWidgetItem *_pqTreeWidgetItem, int __iColumn)
Handles item (content) changes in the underlying QTreeWidget.
CVesselOverlay(QWidget *_pqParent=0)
virtual COverlayPoint * matchScrPosition(const CChart *_poChart, const QPointF &_rqPointFScrPosition) const
Returns the overlay's point that (first) matches the given screen position (0 if none is found)
virtual QStringList mimeTypes() const
void save(const QString &_rqsFilename, CVesselContainer *_poVesselContainer=0) const
Save this object's content (container) to the given file (all selected items if no container is given...
void importSettings()
Imports settings from the application's global settings.
void clear()
Clear the entire content of this overlay.
virtual void drawContent(const CChart *_poChart, QPainter *_pqPainter) const
Draws this overlay's content.
virtual void dropEvent(QDropEvent *_pqDropEvent)
int deleteSelection()
Deletes selected items within this overlay's containers.
virtual bool dropMimeData(QTreeWidgetItem *_pqTreeWidgetItem, int _iIndex, const QMimeData *_pqMimeData, Qt::DropAction eAction)
@ NAME
Vessel name.
@ SELECT
Vessel selection status.
@ VISIBLE
Vessel visibility status.
CVesselContainer * addContainer(const QString &_rqsName)
Add a new vessel (container) to this overlay.
virtual void showDetail(const QTreeWidgetItem *_pqTreeWidgetItem) const
Displays the given overlay object's details (in the appropriate widget/view)
int parseQVCT(const QDomElement &_rqDomElement, CVesselContainer **_ppoVesselContainer=0)
Retrieves this object's content from the given QVCT source (file)
virtual void setPosition(const QTreeWidgetItem *_pqTreeWidgetItem) const
Centers the chart on the given overlay object's position.
virtual ~CVesselOverlay()
void dumpQVCT(QXmlStreamWriter &_rqXmlStreamWriter, CVesselContainer *_poVesselContainer=0, bool _bProjectDump=false) const
Stores this object's content to the given QVCT destination (file)
CVesselContainer * load(const QString &_rqsFilename)
Load this object's content from the given file and returns the last loaded container (0 if none)
virtual QMimeData * mimeData(const QList< QTreeWidgetItem * > _qListTreeWidgetItems) const
[UI] Vessel device
virtual void showDetail()
Displays this object's details (in the appropriate widget/view)
[UI] Vessel overlay point (item) / vessel
virtual void unserialize(QDataStream &_rqDataStream)
Unserializes (restore) this object's data from binary format.
virtual void showDetail()
Displays this object's details (in the appropriate widget/view)
virtual void serialize(QDataStream &_rqDataStream) const
Serializes (store) this object's data to binary format.
static CMainWindow * useMainWindow()
static CChartTable * useChartTable()
static CSettings * useSettings()
@ OPEN
Definition: QVCT.hpp:42