• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • plugins
  • runner
  • openrouteservice
OpenRouteServiceRunner.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2010 Dennis Nienhüser <earthwings@gentoo.org>
9 //
10 
11 #include "OpenRouteServiceRunner.h"
12 
13 #include "MarbleDebug.h"
14 #include "GeoDataDocument.h"
15 #include "GeoDataPlacemark.h"
16 #include "TinyWebBrowser.h"
17 #include "GeoDataData.h"
18 #include "GeoDataExtendedData.h"
19 #include "routing/RouteRequest.h"
20 
21 #include <QString>
22 #include <QVector>
23 #include <QUrl>
24 #include <QTime>
25 #include <QTimer>
26 #include <QNetworkReply>
27 #include <QDomDocument>
28 
29 namespace Marble
30 {
31 
32 OpenRouteServiceRunner::OpenRouteServiceRunner( QObject *parent ) :
33  RoutingRunner( parent ),
34  m_networkAccessManager()
35 {
36  connect( &m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
37  this, SLOT(retrieveData(QNetworkReply*)));
38 }
39 
40 OpenRouteServiceRunner::~OpenRouteServiceRunner()
41 {
42  // nothing to do
43 }
44 
45 void OpenRouteServiceRunner::retrieveRoute( const RouteRequest *route )
46 {
47  if ( route->size() < 2 ) {
48  return;
49  }
50 
51  GeoDataCoordinates source = route->source();
52  GeoDataCoordinates destination = route->destination();
53 
54  QHash<QString, QVariant> settings = route->routingProfile().pluginSettings()["openrouteservice"];
55 
56  QString request = xmlHeader();
57  QString unit = "KM";
58  QString preference = "Fastest";
59  if ( settings.contains( "preference" ) ) {
60  preference = settings["preference"].toString();
61  }
62  if ( preference == "Pedestrian" ) {
63  unit = 'M';
64  }
65 
66  request += requestHeader( unit, preference );
67  request += requestPoint( StartPoint, source );
68 
69  if ( route->size() > 2 ) {
70  for ( int i = 1; i < route->size() - 1; ++i ) {
71  request += requestPoint( ViaPoint, route->at( i ) );
72  }
73  }
74 
75  request += requestPoint( EndPoint, destination );
76  request += requestFooter( settings );
77  request += xmlFooter();
78  //mDebug() << "POST: " << request;
79 
80  // Please refrain from making this URI public. To use it outside the scope
81  // of marble you need permission from the openrouteservice.org team.
82  QUrl url = QUrl( "http://openls.geog.uni-heidelberg.de/osm/eu/routing" );
83  m_request = QNetworkRequest( url );
84  m_request.setHeader( QNetworkRequest::ContentTypeHeader, "application/xml" );
85  m_requestData = request.toLatin1();
86 
87  QEventLoop eventLoop;
88  QTimer timer;
89  timer.setSingleShot( true );
90  timer.setInterval( 15000 );
91 
92  connect( &timer, SIGNAL(timeout()),
93  &eventLoop, SLOT(quit()));
94  connect( this, SIGNAL(routeCalculated(GeoDataDocument*)),
95  &eventLoop, SLOT(quit()));
96 
97  // @todo FIXME Must currently be done in the main thread, see bug 257376
98  QTimer::singleShot( 0, this, SLOT(get()));
99  timer.start();
100 
101  eventLoop.exec();
102 }
103 
104 void OpenRouteServiceRunner::get()
105 {
106  QNetworkReply *reply = m_networkAccessManager.post( m_request, m_requestData );
107  connect( reply, SIGNAL(error(QNetworkReply::NetworkError)),
108  this, SLOT(handleError(QNetworkReply::NetworkError)), Qt::DirectConnection);
109 }
110 
111 void OpenRouteServiceRunner::retrieveData( QNetworkReply *reply )
112 {
113  if ( reply->isFinished() ) {
114  QByteArray data = reply->readAll();
115  reply->deleteLater();
116  //mDebug() << "Download completed: " << data;
117  GeoDataDocument* document = parse( data );
118 
119  if ( !document ) {
120  mDebug() << "Failed to parse the downloaded route data" << data;
121  }
122 
123  emit routeCalculated( document );
124  }
125 }
126 
127 void OpenRouteServiceRunner::handleError( QNetworkReply::NetworkError error )
128 {
129  mDebug() << " Error when retrieving openrouteservice.org route: " << error;
130 }
131 
132 QString OpenRouteServiceRunner::xmlHeader()
133 {
134  QString result = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
135  result += "<xls:XLS xmlns:xls=\"http://www.opengis.net/xls\" xmlns:sch=\"http://www.ascc.net/xml/schematron\" ";
136  result += "xmlns:gml=\"http://www.opengis.net/gml\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" ";
137  result += "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ";
138  result += "xsi:schemaLocation=\"http://www.opengis.net/xls ";
139  result += "http://schemas.opengis.net/ols/1.1.0/RouteService.xsd\" version=\"1.1\" xls:lang=\"en\">\n";
140  result += "<xls:RequestHeader/>\n";
141  return result;
142 }
143 
144 QString OpenRouteServiceRunner::requestHeader( const QString &unit, const QString &routePreference )
145 {
146  QString result = "<xls:Request methodName=\"RouteRequest\" requestID=\"123456789\" version=\"1.1\">\n";
147  result += "<xls:DetermineRouteRequest distanceUnit=\"%1\">\n";
148  result += "<xls:RoutePlan>\n";
149  result += "<xls:RoutePreference>%2</xls:RoutePreference>\n";
150  result += "<xls:WayPointList>\n";
151  return result.arg( unit ).arg( routePreference );
152 }
153 
154 QString OpenRouteServiceRunner::requestPoint( PointType pointType, const GeoDataCoordinates &coordinates )
155 {
156  QString result = "<xls:%1>\n";
157  result += "<xls:Position>\n";
158  result += "<gml:Point srsName=\"EPSG:4326\">\n";
159  result += "<gml:pos>%2 %3</gml:pos>\n";
160  result += "</gml:Point>\n";
161  result += "</xls:Position>\n";
162  result += "</xls:%1>\n";
163 
164  result = result.arg( pointType == StartPoint ? "StartPoint" : ( pointType == ViaPoint ? "ViaPoint" : "EndPoint" ) );
165  result = result.arg( coordinates.longitude( GeoDataCoordinates::Degree ), 0, 'f', 14 );
166  result = result.arg( coordinates.latitude( GeoDataCoordinates::Degree ), 0, 'f', 14 );
167  return result;
168 }
169 
170 QString OpenRouteServiceRunner::requestFooter( const QHash<QString, QVariant>& settings )
171 {
172  QString result = "</xls:WayPointList>\n";
173 
174  if (settings["noMotorways"].toInt() || settings["noTollways"].toInt() ) {
175  result += "<xls:AvoidList>\n";
176  if ( settings["noTollways"].toInt() ) {
177  result += "<xls:AvoidFeature>Tollway</xls:AvoidFeature>";
178  }
179  if ( settings["noMotorways"].toInt() ) {
180  result += "<xls:AvoidFeature>Highway</xls:AvoidFeature>";
181  }
182  result += "</xls:AvoidList>\n";
183  }
184 
185  result += "</xls:RoutePlan>\n";
186  result += "<xls:RouteInstructionsRequest provideGeometry=\"true\" />\n";
187  result += "<xls:RouteGeometryRequest/>\n";
188  result += "</xls:DetermineRouteRequest>\n";
189  result += "</xls:Request>\n";
190  return result;
191 }
192 
193 QString OpenRouteServiceRunner::xmlFooter()
194 {
195  return "</xls:XLS>\n";
196 }
197 
198 GeoDataDocument* OpenRouteServiceRunner::parse( const QByteArray &content ) const
199 {
200  QDomDocument xml;
201  if ( !xml.setContent( content ) ) {
202  mDebug() << "Cannot parse xml file with routing instructions.";
203  return 0;
204  }
205 
206  QDomElement root = xml.documentElement();
207 
208  GeoDataDocument* result = new GeoDataDocument();
209  result->setName( "OpenRouteService" );
210 
211  QDomNodeList errors = root.elementsByTagName( "xls:Error" );
212  if ( errors.size() > 0 ) {
213  return 0;
214  // Returning early because fallback routing providers are used now
215  // The code below can be used to parse OpenGis errors reported by ORS
216  // and may be useful in the future
217 
218 #if QT_VERSION < 0x050000
219  unsigned int i=0;
220 #else
221  int i=0;
222 #endif
223  for ( ; i < errors.length(); ++i ) {
224  QDomNode node = errors.item( i );
225  QString errorMessage = node.attributes().namedItem( "message" ).nodeValue();
226  QRegExp regexp = QRegExp( "^(.*) Please Check your Position: (-?[0-9]+.[0-9]+) (-?[0-9]+.[0-9]+) !" );
227  if ( regexp.indexIn( errorMessage ) == 0 ) {
228  if ( regexp.capturedTexts().size() == 4 ) {
229  GeoDataPlacemark* placemark = new GeoDataPlacemark;
230  placemark->setName( regexp.capturedTexts().at( 1 ) );
231  GeoDataCoordinates position;
232  position.setLongitude( regexp.capturedTexts().at( 2 ).toDouble(), GeoDataCoordinates::Degree );
233  position.setLatitude( regexp.capturedTexts().at( 3 ).toDouble(), GeoDataCoordinates::Degree );
234  placemark->setCoordinate( position );
235  result->append( placemark );
236  }
237  } else {
238  mDebug() << "Error message " << errorMessage << " not parsable.";
240 // QString message = tr( "Sorry, a problem occurred when calculating the route. Try adjusting start and destination points." );
241 // QPointer<QMessageBox> messageBox = new QMessageBox( QMessageBox::Warning, "Route Error", message );
242 // messageBox->setDetailedText( errorMessage );
243 // messageBox->exec();
244 // delete messageBox;
245  }
246  }
247  }
248 
249  GeoDataPlacemark* routePlacemark = new GeoDataPlacemark;
250  routePlacemark->setName( "Route" );
251  QTime time;
252  QDomNodeList summary = root.elementsByTagName( "xls:RouteSummary" );
253  if ( summary.size() > 0 ) {
254  QDomNodeList timeNodeList = summary.item( 0 ).toElement().elementsByTagName( "xls:TotalTime" );
255  QDomNodeList distance = summary.item( 0 ).toElement().elementsByTagName( "xls:TotalDistance" );
256  if ( timeNodeList.size() == 1 && distance.size() == 1 ) {
257  QRegExp regexp = QRegExp( "^P(?:(\\d+)D)?T(?:(\\d+)H)?(?:(\\d+)M)?(\\d+)S" );
258  if ( regexp.indexIn( timeNodeList.item( 0 ).toElement().text() ) == 0 ) {
259  QStringList matches = regexp.capturedTexts();
260  unsigned int hours( 0 ), minutes( 0 ), seconds( 0 );
261  switch ( matches.size() ) {
262  case 5:
263  // days = regexp.cap( matches.size() - 4 ).toInt();
264  // Intentionally no break
265  case 4:
266  hours = regexp.cap( matches.size() - 3 ).toInt();
267  // Intentionally no break
268  case 3:
269  minutes = regexp.cap( matches.size() - 2 ).toInt();
270  // Intentionally no break
271  case 2:
272  seconds = regexp.cap( matches.size() - 1 ).toInt();
273  break;
274  default:
275  mDebug() << "Unable to parse time string " << timeNodeList.item( 0 ).toElement().text();
276  }
277 
278  time = QTime( hours, minutes, seconds, 0 );
279  qreal totalDistance = distance.item( 0 ).attributes().namedItem( "value" ).nodeValue().toDouble();
280  QString unit = distance.item( 0 ).attributes().namedItem( "uom" ).nodeValue();
281  if ( unit == "M" ) {
282  totalDistance *= METER2KM;
283  }
284  else if ( unit != "KM" ) {
285  mDebug() << "Cannot parse distance unit " << unit << ", treated as km.";
286  }
287 
288  QString description = "";
289  routePlacemark->setDescription( description );
290  }
291  }
292  }
293 
294  GeoDataLineString* routeWaypoints = new GeoDataLineString;
295  QDomNodeList geometry = root.elementsByTagName( "xls:RouteGeometry" );
296  if ( geometry.size() > 0 ) {
297  QDomNodeList waypoints = geometry.item( 0 ).toElement().elementsByTagName( "gml:pos" );
298 #if QT_VERSION < 0x050000
299  unsigned int i=0;
300 #else
301  int i=0;
302 #endif
303  for ( ; i < waypoints.length(); ++i ) {
304  QDomNode node = waypoints.item( i );
305  QStringList content = node.toElement().text().split( ' ' );
306  if ( content.length() == 2 ) {
307  GeoDataCoordinates position;
308  position.setLongitude( content.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
309  position.setLatitude( content.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
310  routeWaypoints->append( position );
311  }
312  }
313  }
314  routePlacemark->setGeometry( routeWaypoints );
315 
316  qreal length = routeWaypoints->length( EARTH_RADIUS );
317  const QString name = nameString( "ORS", length, time );
318  const GeoDataExtendedData data = routeData( length, time );
319  routePlacemark->setExtendedData( data );
320  result->setName( name );
321 
322  result->append( routePlacemark );
323 
324  QDomNodeList instructionList = root.elementsByTagName( "xls:RouteInstructionsList" );
325  if ( instructionList.size() > 0 ) {
326  QDomNodeList instructions = instructionList.item( 0 ).toElement().elementsByTagName( "xls:RouteInstruction" );
327 #if QT_VERSION < 0x050000
328  unsigned int i=0;
329 #else
330  int i=0;
331 #endif
332  for ( ; i < instructions.length(); ++i ) {
333  QDomElement node = instructions.item( i ).toElement();
334 
335  QDomNodeList textNodes = node.elementsByTagName( "xls:Instruction" );
336  QDomNodeList positions = node.elementsByTagName( "gml:pos" );
337 
338  if ( textNodes.size() > 0 && positions.size() > 0 ) {
339  QStringList content = positions.at( 0 ).toElement().text().split( ' ' );
340  if ( content.length() == 2 ) {
341  GeoDataLineString *lineString = new GeoDataLineString;
342 
343  for( int i = 0; i < positions.count(); ++i ) {
344  QStringList pointList = positions.at( i ).toElement().text().split( ' ' );
345  GeoDataCoordinates position;
346  position.setLongitude( pointList.at( 0 ).toDouble(), GeoDataCoordinates::Degree );
347  position.setLatitude( pointList.at( 1 ).toDouble(), GeoDataCoordinates::Degree );
348  lineString->append( position );
349  }
350 
351  GeoDataPlacemark* instruction = new GeoDataPlacemark;
352 
353  QString const text = textNodes.item( 0 ).toElement().text();
354  GeoDataExtendedData extendedData;
355  GeoDataData turnTypeData;
356  turnTypeData.setName( "turnType" );
357  QString road;
358  RoutingInstruction::TurnType turnType = parseTurnType( text, &road );
359  turnTypeData.setValue( turnType );
360  extendedData.addValue( turnTypeData );
361  if ( !road.isEmpty() ) {
362  GeoDataData roadName;
363  roadName.setName( "roadName" );
364  roadName.setValue( road );
365  extendedData.addValue( roadName );
366  }
367 
368  QString const instructionText = turnType == RoutingInstruction::Unknown ? text : RoutingInstruction::generateRoadInstruction( turnType, road );
369  instruction->setName( instructionText );
370  instruction->setExtendedData( extendedData );
371  instruction->setGeometry( lineString );
372  result->append( instruction );
373  }
374  }
375  }
376  }
377 
378  return result;
379 }
380 
381 RoutingInstruction::TurnType OpenRouteServiceRunner::parseTurnType( const QString &text, QString *road )
382 {
383  QRegExp syntax( "^(Go|Drive) (half left|left|sharp left|straight forward|half right|right|sharp right)( on )?(.*)?$", Qt::CaseSensitive, QRegExp::RegExp2 );
384  QString instruction;
385  if ( syntax.indexIn( text ) == 0 ) {
386  if ( syntax.captureCount() > 1 ) {
387  instruction = syntax.cap( 2 );
388  if ( syntax.captureCount() == 4 ) {
389  *road = syntax.cap( 4 ).remove(QLatin1String( " - Arrived at destination!"));
390  }
391  }
392  }
393 
394  if ( instruction == "Continue" ) {
395  return RoutingInstruction::Straight;
396  } else if ( instruction == "half right" ) {
397  return RoutingInstruction::SlightRight;
398  } else if ( instruction == "right" ) {
399  return RoutingInstruction::Right;
400  } else if ( instruction == "sharp right" ) {
401  return RoutingInstruction::SharpRight;
402  } else if ( instruction == "straight forward" ) {
403  return RoutingInstruction::Straight;
404  } else if ( instruction == "turn" ) {
405  return RoutingInstruction::TurnAround;
406  } else if ( instruction == "sharp left" ) {
407  return RoutingInstruction::SharpLeft;
408  } else if ( instruction == "left" ) {
409  return RoutingInstruction::Left;
410  } else if ( instruction == "half left" ) {
411  return RoutingInstruction::SlightLeft;
412  }
413 
414  return RoutingInstruction::Unknown;
415 }
416 
417 } // namespace Marble
418 
419 #include "OpenRouteServiceRunner.moc"
Marble::OpenRouteServiceRunner::OpenRouteServiceRunner
OpenRouteServiceRunner(QObject *parent=0)
Definition: OpenRouteServiceRunner.cpp:32
GeoDataDocument.h
QTimer::setInterval
void setInterval(int msec)
Marble::RouteRequest::size
int size() const
Number of points in the route.
Definition: RouteRequest.cpp:126
QDomElement::elementsByTagName
QDomNodeList elementsByTagName(const QString &tagname) const
Marble::GeoDataCoordinates
A 3d point representation.
Definition: GeoDataCoordinates.h:52
QRegExp::cap
QString cap(int nth) const
TinyWebBrowser.h
QDomNodeList::item
QDomNode item(int index) const
Marble::GeoDataDocument
A container for Features, Styles and in the future Schemas.
Definition: GeoDataDocument.h:65
QEventLoop
Marble::RoutingInstruction::TurnAround
Definition: RoutingInstruction.h:40
Marble::RoutingInstruction::Right
Definition: RoutingInstruction.h:38
QByteArray
Marble::RoutingInstruction::Left
Definition: RoutingInstruction.h:42
QList::length
int length() const
QDomNode::nodeValue
QString nodeValue() const
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QNetworkReply
QDomNodeList
QList::at
const T & at(int i) const
Marble::RouteRequest::destination
GeoDataCoordinates destination() const
The last point, or a default constructed if empty.
Definition: RouteRequest.cpp:140
QDomDocument::documentElement
QDomElement documentElement() const
QDomNode
GeoDataExtendedData.h
QString::remove
QString & remove(int position, int n)
Marble::RoutingInstruction::TurnType
TurnType
Definition: RoutingInstruction.h:32
QString::toDouble
double toDouble(bool *ok) const
QTime
MarbleDebug.h
Marble::GeoDataCoordinates::Degree
Definition: GeoDataCoordinates.h:66
QList::size
int size() const
Marble::RoutingRunner::nameString
const QString nameString(const QString &name, qreal length, const QTime &duration) const
Definition: RoutingRunner.cpp:55
Marble::RoutingInstruction::SharpLeft
Definition: RoutingInstruction.h:41
Marble::RoutingInstruction::generateRoadInstruction
static QString generateRoadInstruction(TurnType turnType, const QString &roadName)
Definition: RoutingInstruction.cpp:357
QDomNode::toElement
QDomElement toElement() const
QRegExp::indexIn
int indexIn(const QString &str, int offset, CaretMode caretMode) const
Marble::RouteRequest
Points to be included in a route.
Definition: RouteRequest.h:31
Marble::OpenRouteServiceRunner::~OpenRouteServiceRunner
~OpenRouteServiceRunner()
Definition: OpenRouteServiceRunner.cpp:40
QRegExp
QObject::name
const char * name() const
Marble::RouteRequest::routingProfile
RoutingProfile routingProfile() const
Definition: RouteRequest.cpp:321
QNetworkRequest
QDomNodeList::count
int count() const
QList::append
void append(const T &value)
Marble::EARTH_RADIUS
const qreal EARTH_RADIUS
Definition: MarbleGlobal.h:257
QDomElement::text
QString text() const
QTimer
QHash< QString, QVariant >
QEventLoop::exec
int exec(QFlags< QEventLoop::ProcessEventsFlag > flags)
QObject
QRegExp::capturedTexts
QStringList capturedTexts() const
OpenRouteServiceRunner.h
QNetworkAccessManager::post
QNetworkReply * post(const QNetworkRequest &request, QIODevice *data)
QNetworkReply::isFinished
bool isFinished() const
QString::isEmpty
bool isEmpty() const
QIODevice::readAll
QByteArray readAll()
Marble::RoutingRunner::routeData
const GeoDataExtendedData routeData(qreal length, const QTime &duration) const
Definition: RoutingRunner.cpp:61
QObject::deleteLater
void deleteLater()
QString
GeoDataPlacemark.h
Marble::METER2KM
const qreal METER2KM
Definition: MarbleGlobal.h:224
Marble::OpenRouteServiceRunner::retrieveRoute
virtual void retrieveRoute(const RouteRequest *request)
Start a route download orw calculation.
Definition: OpenRouteServiceRunner.cpp:45
QStringList
Marble::RoutingInstruction::SlightRight
Definition: RoutingInstruction.h:37
QDomNamedNodeMap::namedItem
QDomNode namedItem(const QString &name) const
Marble::RoutingInstruction::SharpRight
Definition: RoutingInstruction.h:39
QUrl
QDomDocument
QNetworkRequest::setHeader
void setHeader(KnownHeaders header, const QVariant &value)
Marble::RoutingProfile::pluginSettings
const QHash< QString, QHash< QString, QVariant > > & pluginSettings() const
Definition: RoutingProfile.cpp:33
Marble::RoutingRunner::routeCalculated
void routeCalculated(GeoDataDocument *route)
Route download/calculation is finished, result in the given route object.
GeoDataData.h
QString::toLatin1
QByteArray toLatin1() const
Marble::RoutingInstruction::Straight
Definition: RoutingInstruction.h:36
Marble::RoutingRunner
Definition: RoutingRunner.h:28
QLatin1String
Marble::RoutingInstruction::SlightLeft
Definition: RoutingInstruction.h:43
QTimer::start
void start(int msec)
RouteRequest.h
QHash::contains
bool contains(const Key &key) const
QDomNodeList::size
int size() const
QDomNodeList::length
uint length() const
Marble::RoutingInstruction::Unknown
Definition: RoutingInstruction.h:33
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QDomElement
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
QDomNode::attributes
QDomNamedNodeMap attributes() const
Marble::RouteRequest::source
GeoDataCoordinates source() const
The first point, or a default constructed if empty.
Definition: RouteRequest.cpp:131
QDomNodeList::at
QDomNode at(int index) const
QDomDocument::setContent
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QTimer::setSingleShot
void setSingleShot(bool singleShot)
Marble::RouteRequest::at
GeoDataCoordinates at(int index) const
Accessor for the n-th position.
Definition: RouteRequest.cpp:149
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:41 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal