QGIS API Documentation  2.8.2-Wien
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsapplication.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsapplication.cpp - Accessors for application-wide data
3  --------------------------------------
4  Date : 02-Jan-2006
5  Copyright : (C) 2006 by Tom Elwertowski
6  Email : telwertowski at users dot sourceforge dot net
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsapplication.h"
17 #include "qgscrscache.h"
18 #include "qgsexception.h"
19 #include "qgsgeometry.h"
20 #include "qgslogger.h"
21 #include "qgsmaplayerregistry.h"
23 #include "qgsproviderregistry.h"
24 
25 #include <QDir>
26 #include <QFile>
27 #include <QFileOpenEvent>
28 #include <QMessageBox>
29 #include <QPalette>
30 #include <QProcess>
31 #include <QSettings>
32 #include <QIcon>
33 #include <QPixmap>
34 #include <QThreadPool>
35 
36 #ifndef Q_OS_WIN
37 #include <netinet/in.h>
38 #else
39 #include <winsock.h>
40 #endif
41 
42 #include "qgsconfig.h"
43 
44 #include <gdal.h>
45 #include <ogr_api.h>
46 #include <cpl_conv.h> // for setting gdal options
47 #include <sqlite3.h>
48 
49 QObject * ABISYM( QgsApplication::mFileOpenEventReceiver );
50 QStringList ABISYM( QgsApplication::mFileOpenEventList );
51 QString ABISYM( QgsApplication::mPrefixPath );
52 QString ABISYM( QgsApplication::mPluginPath );
53 QString ABISYM( QgsApplication::mPkgDataPath );
54 QString ABISYM( QgsApplication::mLibraryPath );
55 QString ABISYM( QgsApplication::mLibexecPath );
56 QString ABISYM( QgsApplication::mThemeName );
57 QStringList ABISYM( QgsApplication::mDefaultSvgPaths );
58 QMap<QString, QString> ABISYM( QgsApplication::mSystemEnvVars );
59 QString ABISYM( QgsApplication::mConfigPath );
60 bool ABISYM( QgsApplication::mRunningFromBuildDir ) = false;
61 QString ABISYM( QgsApplication::mBuildSourcePath );
62 #ifdef _MSC_VER
63 QString ABISYM( QgsApplication::mCfgIntDir );
64 #endif
65 QString ABISYM( QgsApplication::mBuildOutputPath );
66 QStringList ABISYM( QgsApplication::mGdalSkipList );
67 int ABISYM( QgsApplication::mMaxThreads );
68 
69 const char* QgsApplication::QGIS_ORGANIZATION_NAME = "QGIS";
70 const char* QgsApplication::QGIS_ORGANIZATION_DOMAIN = "qgis.org";
71 const char* QgsApplication::QGIS_APPLICATION_NAME = "QGIS2";
72 
86 QgsApplication::QgsApplication( int & argc, char ** argv, bool GUIenabled, QString customConfigPath )
87  : QApplication( argc, argv, GUIenabled )
88 {
89  init( customConfigPath ); // init can also be called directly by e.g. unit tests that don't inherit QApplication.
90 }
91 
92 void QgsApplication::init( QString customConfigPath )
93 {
94  if ( customConfigPath.isEmpty() )
95  {
96  if ( getenv( "QGIS_CUSTOM_CONFIG_PATH" ) )
97  {
98  customConfigPath = getenv( "QGIS_CUSTOM_CONFIG_PATH" );
99  }
100  else
101  {
102  customConfigPath = QString( "%1/.qgis%2/" ).arg( QDir::homePath() ).arg( QGis::QGIS_VERSION_INT / 10000 );
103  }
104  }
105 
106  qRegisterMetaType<QgsGeometry::Error>( "QgsGeometry::Error" );
107 
108  QString prefixPath( getenv( "QGIS_PREFIX_PATH" ) ? getenv( "QGIS_PREFIX_PATH" ) : applicationDirPath() );
109  // QgsDebugMsg( QString( "prefixPath(): %1" ).arg( prefixPath ) );
110 
111  // check if QGIS is run from build directory (not the install directory)
112  QFile f;
113  // "/../../.." is for Mac bundled app in build directory
114  foreach ( QString path, QStringList() << "" << "/.." << "/bin" << "/../../.." )
115  {
116  f.setFileName( prefixPath + path + "/qgisbuildpath.txt" );
117  if ( f.exists() )
118  break;
119  }
120  if ( f.exists() && f.open( QIODevice::ReadOnly ) )
121  {
122  ABISYM( mRunningFromBuildDir ) = true;
123  ABISYM( mBuildSourcePath ) = f.readLine().trimmed();
124  ABISYM( mBuildOutputPath ) = f.readLine().trimmed();
125  qDebug( "Running from build directory!" );
126  qDebug( "- source directory: %s", ABISYM( mBuildSourcePath ).toUtf8().data() );
127  qDebug( "- output directory of the build: %s", ABISYM( mBuildOutputPath ).toUtf8().data() );
128 #ifdef _MSC_VER
129  ABISYM( mCfgIntDir ) = prefixPath.split( "/", QString::SkipEmptyParts ).last();
130  qDebug( "- cfg: %s", ABISYM( mCfgIntDir ).toUtf8().data() );
131 #endif
132  }
133 
134  if ( ABISYM( mRunningFromBuildDir ) )
135  {
136  // we run from source directory - not installed to destination (specified prefix)
137  ABISYM( mPrefixPath ) = QString(); // set invalid path
138 #if defined(_MSC_VER) && !defined(USING_NMAKE)
139  setPluginPath( ABISYM( mBuildOutputPath ) + "/" + QString( QGIS_PLUGIN_SUBDIR ) + "/" + ABISYM( mCfgIntDir ) );
140 #else
141  setPluginPath( ABISYM( mBuildOutputPath ) + "/" + QString( QGIS_PLUGIN_SUBDIR ) );
142 #endif
143  setPkgDataPath( ABISYM( mBuildSourcePath ) ); // directly source path - used for: doc, resources, svg
144  ABISYM( mLibraryPath ) = ABISYM( mBuildOutputPath ) + "/" + QGIS_LIB_SUBDIR + "/";
145 #if defined(_MSC_VER) && !defined(USING_NMAKE)
146  ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + "/" + QGIS_LIBEXEC_SUBDIR + "/" + ABISYM( mCfgIntDir ) + "/";
147 #else
148  ABISYM( mLibexecPath ) = ABISYM( mBuildOutputPath ) + "/" + QGIS_LIBEXEC_SUBDIR + "/";
149 #endif
150  }
151  else
152  {
153  char *prefixPath = getenv( "QGIS_PREFIX_PATH" );
154  if ( !prefixPath )
155  {
156 #if defined(Q_OS_MACX) || defined(Q_OS_WIN32) || defined(WIN32)
157  setPrefixPath( applicationDirPath(), true );
158 #elif defined(ANDROID)
159  // this is "/data/data/org.qgis.qgis" in android
160  QDir myDir( QDir::homePath() );
161  myDir.cdUp();
162  QString myPrefix = myDir.absolutePath();
163  setPrefixPath( myPrefix, true );
164 #else
165  QDir myDir( applicationDirPath() );
166  myDir.cdUp();
167  QString myPrefix = myDir.absolutePath();
168  setPrefixPath( myPrefix, true );
169 #endif
170  }
171  else
172  {
173  setPrefixPath( prefixPath, true );
174  }
175  }
176 
177  if ( !customConfigPath.isEmpty() )
178  {
179  ABISYM( mConfigPath ) = customConfigPath + "/"; // make sure trailing slash is included
180  }
181 
182  ABISYM( mDefaultSvgPaths ) << qgisSettingsDirPath() + QString( "svg/" );
183 
184  // store system environment variables passed to application, before they are adjusted
185  QMap<QString, QString> systemEnvVarMap;
186  foreach ( const QString &varStr, QProcess::systemEnvironment() )
187  {
188  int pos = varStr.indexOf( QLatin1Char( '=' ) );
189  if ( pos == -1 )
190  continue;
191  QString varStrName = varStr.left( pos );
192  QString varStrValue = varStr.mid( pos + 1 );
193  systemEnvVarMap.insert( varStrName, varStrValue );
194  }
195  ABISYM( mSystemEnvVars ) = systemEnvVarMap;
196 
197  // allow Qt to search for Qt plugins (e.g. sqldrivers) in our plugin directory
198  QCoreApplication::addLibraryPath( pluginPath() );
199 
200  // set max. thread count to -1
201  // this should be read from QSettings but we don't know where they are at this point
202  // so we read actual value in main.cpp
203  ABISYM( mMaxThreads ) = -1;
204 }
205 
207 {
208 }
209 
210 bool QgsApplication::event( QEvent * event )
211 {
212  bool done = false;
213  if ( event->type() == QEvent::FileOpen )
214  {
215  // handle FileOpen event (double clicking a file icon in Mac OS X Finder)
216  if ( ABISYM( mFileOpenEventReceiver ) )
217  {
218  // Forward event to main window.
219  done = notify( ABISYM( mFileOpenEventReceiver ), event );
220  }
221  else
222  {
223  // Store filename because receiver has not registered yet.
224  // If QGIS has been launched by double clicking a file icon, FileOpen will be
225  // the first event; the main window is not yet ready to handle the event.
226  ABISYM( mFileOpenEventList ).append( static_cast<QFileOpenEvent *>( event )->file() );
227  done = true;
228  }
229  }
230  else
231  {
232  // pass other events to base class
233  done = QApplication::event( event );
234  }
235  return done;
236 }
237 
238 bool QgsApplication::notify( QObject * receiver, QEvent * event )
239 {
240  bool done = false;
241  // Crashes in customization (especially on Mac), if we're not in the main/UI thread, see #5597
242  if ( thread() == receiver->thread() )
243  emit preNotify( receiver, event, &done );
244 
245  if ( done )
246  return true;
247 
248  // Send event to receiver and catch unhandled exceptions
249  done = true;
250  try
251  {
252  done = QApplication::notify( receiver, event );
253  }
254  catch ( QgsException & e )
255  {
256  QgsDebugMsg( "Caught unhandled QgsException: " + e.what() );
257  if ( qApp->thread() == QThread::currentThread() )
258  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
259  }
260  catch ( std::exception & e )
261  {
262  QgsDebugMsg( "Caught unhandled std::exception: " + QString::fromAscii( e.what() ) );
263  if ( qApp->thread() == QThread::currentThread() )
264  QMessageBox::critical( activeWindow(), tr( "Exception" ), e.what() );
265  }
266  catch ( ... )
267  {
268  QgsDebugMsg( "Caught unhandled unknown exception" );
269  if ( qApp->thread() == QThread::currentThread() )
270  QMessageBox::critical( activeWindow(), tr( "Exception" ), tr( "unknown exception" ) );
271  }
272 
273  return done;
274 }
275 
277 {
278  // Set receiver for FileOpen events
279  ABISYM( mFileOpenEventReceiver ) = receiver;
280  // Propagate any events collected before the receiver has registered.
281  if ( ABISYM( mFileOpenEventList ).count() > 0 )
282  {
283  QStringListIterator i( ABISYM( mFileOpenEventList ) );
284  while ( i.hasNext() )
285  {
286  QFileOpenEvent foe( i.next() );
287  QgsApplication::sendEvent( ABISYM( mFileOpenEventReceiver ), &foe );
288  }
289  ABISYM( mFileOpenEventList ).clear();
290  }
291 }
292 
293 void QgsApplication::setPrefixPath( const QString &thePrefixPath, bool useDefaultPaths )
294 {
295  ABISYM( mPrefixPath ) = thePrefixPath;
296 #if defined(_MSC_VER)
297  if ( ABISYM( mPrefixPath ).endsWith( "/bin" ) )
298  {
299  ABISYM( mPrefixPath ).chop( 4 );
300  }
301 #endif
302  if ( useDefaultPaths && !ABISYM( mRunningFromBuildDir ) )
303  {
304  setPluginPath( ABISYM( mPrefixPath ) + "/" + QString( QGIS_PLUGIN_SUBDIR ) );
305  setPkgDataPath( ABISYM( mPrefixPath ) + "/" + QString( QGIS_DATA_SUBDIR ) );
306  }
307  ABISYM( mLibraryPath ) = ABISYM( mPrefixPath ) + "/" + QGIS_LIB_SUBDIR + "/";
308  ABISYM( mLibexecPath ) = ABISYM( mPrefixPath ) + "/" + QGIS_LIBEXEC_SUBDIR + "/";
309 }
310 
311 void QgsApplication::setPluginPath( const QString &thePluginPath )
312 {
313  ABISYM( mPluginPath ) = thePluginPath;
314 }
315 
316 void QgsApplication::setPkgDataPath( const QString &thePkgDataPath )
317 {
318  ABISYM( mPkgDataPath ) = thePkgDataPath;
319  QString mySvgPath = thePkgDataPath + ( ABISYM( mRunningFromBuildDir ) ? "/images/svg/" : "/svg/" );
320  // avoid duplicate entries
321  if ( !ABISYM( mDefaultSvgPaths ).contains( mySvgPath ) )
322  ABISYM( mDefaultSvgPaths ) << mySvgPath;
323 }
324 
325 void QgsApplication::setDefaultSvgPaths( const QStringList& pathList )
326 {
327  ABISYM( mDefaultSvgPaths ) = pathList;
328 }
329 
331 {
332  if ( ABISYM( mRunningFromBuildDir ) )
333  {
334  static bool once = true;
335  if ( once )
336  qWarning( "!!! prefix path was requested, but it is not valid - we do not run from installed path !!!" );
337  once = false;
338  }
339 
340  return ABISYM( mPrefixPath );
341 }
343 {
344  return ABISYM( mPluginPath );
345 }
347 {
348  return ABISYM( mPkgDataPath );
349 }
351 {
352  return ":/images/themes/default/";
353 }
355 {
356  return ":/images/themes/" + themeName() + "/";
357 }
358 
359 
360 QString QgsApplication::iconPath( QString iconFile )
361 {
362  // try active theme
363  QString path = activeThemePath();
364  if ( QFile::exists( path + iconFile ) )
365  return path + iconFile;
366 
367  // use default theme
368  return defaultThemePath() + iconFile;
369 }
370 
371 QIcon QgsApplication::getThemeIcon( const QString &theName )
372 {
373  QString myPreferredPath = activeThemePath() + QDir::separator() + theName;
374  QString myDefaultPath = defaultThemePath() + QDir::separator() + theName;
375  if ( QFile::exists( myPreferredPath ) )
376  {
377  return QIcon( myPreferredPath );
378  }
379  else if ( QFile::exists( myDefaultPath ) )
380  {
381  //could still return an empty icon if it
382  //doesnt exist in the default theme either!
383  return QIcon( myDefaultPath );
384  }
385  else
386  {
387  return QIcon();
388  }
389 }
390 
391 // TODO: add some caching mechanism ?
392 QPixmap QgsApplication::getThemePixmap( const QString &theName )
393 {
394  QString myPreferredPath = activeThemePath() + QDir::separator() + theName;
395  QString myDefaultPath = defaultThemePath() + QDir::separator() + theName;
396  if ( QFile::exists( myPreferredPath ) )
397  {
398  return QPixmap( myPreferredPath );
399  }
400  else
401  {
402  //could still return an empty icon if it
403  //doesnt exist in the default theme either!
404  return QPixmap( myDefaultPath );
405  }
406 }
407 
411 void QgsApplication::setThemeName( const QString &theThemeName )
412 {
413  QString myPath = ":/images/themes/" + theThemeName + "/";
414  //check it exists and if not roll back to default theme
415  if ( QFile::exists( myPath ) )
416  {
417  ABISYM( mThemeName ) = theThemeName;
418  }
419  else
420  {
421  ABISYM( mThemeName ) = "default";
422  }
423 }
428 {
429  return ABISYM( mThemeName );
430 }
435 {
436  return ABISYM( mPkgDataPath ) + QString( "/doc/AUTHORS" );
437 }
442 {
443  return ABISYM( mPkgDataPath ) + QString( "/doc/CONTRIBUTORS" );
444 }
446 {
447  return ABISYM( mPkgDataPath ) + QString( "/doc/developersmap.html" );
448 }
453 {
454  return ABISYM( mPkgDataPath ) + QString( "/doc/SPONSORS" );
455 }
456 
461 {
462  return ABISYM( mPkgDataPath ) + QString( "/doc/DONORS" );
463 }
464 
467 {
468  return ABISYM( mPkgDataPath ) + QString( "/doc/TRANSLATORS" );
469 }
470 
473 {
474  return ABISYM( mPkgDataPath ) + QString( "/doc/LICENSE" );
475 }
476 
481 {
482  QString helpAppPath;
483 #ifdef Q_OS_MACX
484  helpAppPath = applicationDirPath() + "/bin/qgis_help.app/Contents/MacOS";
485 #else
486  helpAppPath = libexecPath();
487 #endif
488  helpAppPath += "/qgis_help";
489 #ifdef Q_OS_WIN
490  helpAppPath += ".exe";
491 #endif
492  return helpAppPath;
493 }
498 {
499  if ( ABISYM( mRunningFromBuildDir ) )
500  return ABISYM( mBuildOutputPath ) + QString( "/i18n" );
501  else
502  return ABISYM( mPkgDataPath ) + QString( "/i18n/" );
503 }
504 
509 {
510  return ABISYM( mPkgDataPath ) + QString( "/resources/qgis.db" );
511 }
512 
517 {
518  return ABISYM( mConfigPath );
519 }
520 
525 {
526  return qgisSettingsDirPath() + QString( "qgis.db" );
527 }
528 
533 {
534  return QString( ":/images/splash/" );
535 }
536 
541 {
542  return ABISYM( mPkgDataPath ) + QString( "/images/icons/" );
543 }
548 {
549  if ( ABISYM( mRunningFromBuildDir ) )
550  {
551  QString tempCopy = QDir::tempPath() + "/srs.db";
552 
553  if ( !QFile( tempCopy ).exists() )
554  {
555  QFile f( ABISYM( mPkgDataPath ) + "/resources/srs.db" );
556  if ( !f.copy( tempCopy ) )
557  {
558  qFatal( "Could not create temporary copy" );
559  }
560  }
561 
562  return tempCopy;
563  }
564  else
565  {
566  return ABISYM( mPkgDataPath ) + QString( "/resources/srs.db" );
567  }
568 }
569 
573 const QStringList QgsApplication::svgPaths()
574 {
575  //local directories to search when looking for an SVG with a given basename
576  //defined by user in options dialog
577  QSettings settings;
578  QStringList myPathList;
579  QString myPaths = settings.value( "svg/searchPathsForSVG", "" ).toString();
580  if ( !myPaths.isEmpty() )
581  {
582  myPathList = myPaths.split( "|" );
583  }
584 
585  myPathList << ABISYM( mDefaultSvgPaths );
586  return myPathList;
587 }
588 
590 {
591  return qgisSettingsDirPath() + QString( "symbology-ng-style.db" );
592 }
593 
595 {
596  return ABISYM( mPkgDataPath ) + QString( "/resources/symbology-ng-style.db" );
597 }
598 
600 {
601  return ABISYM( mLibraryPath );
602 }
603 
605 {
606  return ABISYM( mLibexecPath );
607 }
608 
610 {
611  return ( htonl( 1 ) == 1 ) ? XDR : NDR;
612 }
613 
615 {
616  // set the provider plugin path (this creates provider registry)
618 
619  // create map layer registry if doesn't exist
621 }
622 
624 {
625  // Cleanup known singletons
629 
630  // Cleanup providers
632 }
633 
635 {
636  QString myEnvironmentVar( getenv( "QGIS_PREFIX_PATH" ) );
637  QString myState = tr( "Application state:\n"
638  "QGIS_PREFIX_PATH env var:\t\t%1\n"
639  "Prefix:\t\t%2\n"
640  "Plugin Path:\t\t%3\n"
641  "Package Data Path:\t%4\n"
642  "Active Theme Name:\t%5\n"
643  "Active Theme Path:\t%6\n"
644  "Default Theme Path:\t%7\n"
645  "SVG Search Paths:\t%8\n"
646  "User DB Path:\t%9\n" )
647  .arg( myEnvironmentVar )
648  .arg( prefixPath() )
649  .arg( pluginPath() )
650  .arg( pkgDataPath() )
651  .arg( themeName() )
652  .arg( activeThemePath() )
653  .arg( defaultThemePath() )
654  .arg( svgPaths().join( tr( "\n\t\t", "match indentation of application state" ) ) )
655  .arg( qgisMasterDbFilePath() );
656  return myState;
657 }
658 
660 {
661  //
662  // Make the style sheet desktop preferences aware by using qappliation
663  // palette as a basis for colors where appropriate
664  //
665 // QColor myColor1 = palette().highlight().color();
666  QColor myColor1( Qt::lightGray );
667  QColor myColor2 = myColor1;
668  myColor2 = myColor2.lighter( 110 ); //10% lighter
669  QString myStyle;
670  myStyle = "p.glossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
671  " stop: 0 " + myColor1.name() + ","
672  " stop: 0.1 " + myColor2.name() + ","
673  " stop: 0.5 " + myColor1.name() + ","
674  " stop: 0.9 " + myColor2.name() + ","
675  " stop: 1 " + myColor1.name() + ");"
676  " color: black;"
677  " padding-left: 4px;"
678  " padding-top: 20px;"
679  " padding-bottom: 8px;"
680  " border: 1px solid #6c6c6c;"
681  "}"
682  "p.subheaderglossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
683  " stop: 0 " + myColor1.name() + ","
684  " stop: 0.1 " + myColor2.name() + ","
685  " stop: 0.5 " + myColor1.name() + ","
686  " stop: 0.9 " + myColor2.name() + ","
687  " stop: 1 " + myColor1.name() + ");"
688  " font-weight: bold;"
689  " font-size: medium;"
690  " line-height: 1.1em;"
691  " width: 100%;"
692  " color: black;"
693  " padding-left: 4px;"
694  " padding-right: 4px;"
695  " padding-top: 20px;"
696  " padding-bottom: 8px;"
697  " border: 1px solid #6c6c6c;"
698  "}"
699  "th.glossy{ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
700  " stop: 0 " + myColor1.name() + ","
701  " stop: 0.1 " + myColor2.name() + ","
702  " stop: 0.5 " + myColor1.name() + ","
703  " stop: 0.9 " + myColor2.name() + ","
704  " stop: 1 " + myColor1.name() + ");"
705  " color: black;"
706  " border: 1px solid #6c6c6c;"
707  "}"
708  ".overview{ font: 1.82em; font-weight: bold;}"
709  "body{ background: white;"
710  " color: black;"
711  " font-family: arial,sans-serif;"
712  "}"
713  "h1{ background-color: #F6F6F6;"
714  " color: #8FB171; "
715  " font-size: x-large; "
716  " font-weight: normal;"
717  " font-family: luxi serif, georgia, times new roman, times, serif;"
718  " background: none;"
719  " padding: 0.75em 0 0;"
720  " margin: 0;"
721  " line-height: 3em;"
722  "}"
723  "h2{ background-color: #F6F6F6;"
724  " color: #8FB171; "
725  " font-size: medium; "
726  " font-weight: normal;"
727  " font-family: luxi serif, georgia, times new roman, times, serif;"
728  " background: none;"
729  " padding: 0.75em 0 0;"
730  " margin: 0;"
731  " line-height: 1.1em;"
732  "}"
733  "h3{ background-color: #F6F6F6;"
734  " color: #729FCF;"
735  " font-family: luxi serif, georgia, times new roman, times, serif;"
736  " font-weight: bold;"
737  " font-size: large;"
738  " text-align: right;"
739  " border-bottom: 5px solid #DCEB5C;"
740  "}"
741  "h4{ background-color: #F6F6F6;"
742  " color: #729FCF;"
743  " font-family: luxi serif, georgia, times new roman, times, serif;"
744  " font-weight: bold;"
745  " font-size: medium;"
746  " text-align: right;"
747  "}"
748  "h5{ background-color: #F6F6F6;"
749  " color: #729FCF;"
750  " font-family: luxi serif, georgia, times new roman, times, serif;"
751  " font-weight: bold;"
752  " font-size: small;"
753  " text-align: right;"
754  "}"
755  "a{ color: #729FCF;"
756  " font-family: arial,sans-serif;"
757  " font-size: small;"
758  "}"
759  "label{ background-color: #FFFFCC;"
760  " border: 1px solid black;"
761  " margin: 1px;"
762  " padding: 0px 3px; "
763  " font-size: small;"
764  "}";
765  return myStyle;
766 }
767 
769 {
770  if ( 0 >= OGRGetDriverCount() )
771  {
772  OGRRegisterAll();
773  }
774 }
775 
776 QString QgsApplication::absolutePathToRelativePath( QString aPath, QString targetPath )
777 {
778 #if defined( Q_OS_WIN )
779  const Qt::CaseSensitivity cs = Qt::CaseInsensitive;
780 
781  aPath.replace( "\\", "/" );
782  if ( aPath.startsWith( "//" ) )
783  {
784  // keep UNC prefix
785  aPath = "\\\\" + aPath.mid( 2 );
786  }
787 
788  targetPath.replace( "\\", "/" );
789  if ( targetPath.startsWith( "//" ) )
790  {
791  // keep UNC prefix
792  targetPath = "\\\\" + targetPath.mid( 2 );
793  }
794 #else
795  const Qt::CaseSensitivity cs = Qt::CaseSensitive;
796 #endif
797 
798  QStringList targetElems = targetPath.split( "/", QString::SkipEmptyParts );
799  QStringList aPathElems = aPath.split( "/", QString::SkipEmptyParts );
800 
801  targetElems.removeAll( "." );
802  aPathElems.removeAll( "." );
803 
804  // remove common part
805  int n = 0;
806  while ( aPathElems.size() > 0 &&
807  targetElems.size() > 0 &&
808  aPathElems[0].compare( targetElems[0], cs ) == 0 )
809  {
810  aPathElems.removeFirst();
811  targetElems.removeFirst();
812  n++;
813  }
814 
815  if ( n == 0 )
816  {
817  // no common parts; might not even be a file
818  return aPath;
819  }
820 
821  if ( targetElems.size() > 0 )
822  {
823  // go up to the common directory
824  for ( int i = 0; i < targetElems.size(); i++ )
825  {
826  aPathElems.insert( 0, ".." );
827  }
828  }
829  else
830  {
831  // let it start with . nevertheless,
832  // so relative path always start with either ./ or ../
833  aPathElems.insert( 0, "." );
834  }
835 
836  return aPathElems.join( "/" );
837 }
838 
839 QString QgsApplication::relativePathToAbsolutePath( QString rpath, QString targetPath )
840 {
841  // relative path should always start with ./ or ../
842  if ( !rpath.startsWith( "./" ) && !rpath.startsWith( "../" ) )
843  {
844  return rpath;
845  }
846 
847 #if defined(Q_OS_WIN)
848  rpath.replace( "\\", "/" );
849  targetPath.replace( "\\", "/" );
850 
851  bool uncPath = targetPath.startsWith( "//" );
852 #endif
853 
854  QStringList srcElems = rpath.split( "/", QString::SkipEmptyParts );
855  QStringList targetElems = targetPath.split( "/", QString::SkipEmptyParts );
856 
857 #if defined(Q_OS_WIN)
858  if ( uncPath )
859  {
860  targetElems.insert( 0, "" );
861  targetElems.insert( 0, "" );
862  }
863 #endif
864 
865  // append source path elements
866  targetElems << srcElems;
867  targetElems.removeAll( "." );
868 
869  // resolve ..
870  int pos;
871  while (( pos = targetElems.indexOf( ".." ) ) > 0 )
872  {
873  // remove preceding element and ..
874  targetElems.removeAt( pos - 1 );
875  targetElems.removeAt( pos - 1 );
876  }
877 
878 #if !defined(Q_OS_WIN)
879  // make path absolute
880  targetElems.prepend( "" );
881 #endif
882 
883  return targetElems.join( "/" );
884 }
885 
886 void QgsApplication::skipGdalDriver( QString theDriver )
887 {
888  if ( ABISYM( mGdalSkipList ).contains( theDriver ) || theDriver.isEmpty() )
889  {
890  return;
891  }
892  ABISYM( mGdalSkipList ) << theDriver;
894 }
895 
896 void QgsApplication::restoreGdalDriver( QString theDriver )
897 {
898  if ( !ABISYM( mGdalSkipList ).contains( theDriver ) )
899  {
900  return;
901  }
902  int myPos = ABISYM( mGdalSkipList ).indexOf( theDriver );
903  if ( myPos >= 0 )
904  {
905  ABISYM( mGdalSkipList ).removeAt( myPos );
906  }
908 }
909 
911 {
912  ABISYM( mGdalSkipList ).removeDuplicates();
913  QString myDriverList = ABISYM( mGdalSkipList ).join( " " );
914  QgsDebugMsg( "Gdal Skipped driver list set to:" );
915  QgsDebugMsg( myDriverList );
916  CPLSetConfigOption( "GDAL_SKIP", myDriverList.toUtf8() );
917  GDALAllRegister(); //to update driver list and skip missing ones
918 }
919 
920 bool QgsApplication::createDB( QString *errorMessage )
921 {
922  // set a working directory up for gdal to write .aux.xml files into
923  // for cases where the raster dir is read only to the user
924  // if the env var is already set it will be used preferentially
925  QString myPamPath = qgisSettingsDirPath() + QString( "gdal_pam/" );
926  QDir myDir( myPamPath );
927  if ( !myDir.exists() )
928  {
929  myDir.mkpath( myPamPath ); //fail silently
930  }
931 
932 #if defined(Q_OS_WIN32) || defined(WIN32)
933  CPLSetConfigOption( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8() );
934 #else
935  //under other OS's we use an environment var so the user can
936  //override the path if he likes
937  int myChangeFlag = 0; //whether we want to force the env var to change
938  setenv( "GDAL_PAM_PROXY_DIR", myPamPath.toUtf8(), myChangeFlag );
939 #endif
940 
941  // Check qgis.db and make private copy if necessary
942  QFile qgisPrivateDbFile( QgsApplication::qgisUserDbFilePath() );
943 
944  // first we look for ~/.qgis/qgis.db
945  if ( !qgisPrivateDbFile.exists() )
946  {
947  // if it doesnt exist we copy it in from the global resources dir
948  QString qgisMasterDbFileName = QgsApplication::qgisMasterDbFilePath();
949  QFile masterFile( qgisMasterDbFileName );
950 
951  // Must be sure there is destination directory ~/.qgis
952  QDir().mkpath( QgsApplication::qgisSettingsDirPath() );
953 
954  //now copy the master file into the users .qgis dir
955  bool isDbFileCopied = masterFile.copy( qgisPrivateDbFile.fileName() );
956 
957  if ( !isDbFileCopied )
958  {
959  if ( errorMessage )
960  {
961  *errorMessage = tr( "[ERROR] Can not make qgis.db private copy" );
962  }
963  return false;
964  }
965  }
966  else
967  {
968  // migrate if necessary
969  sqlite3 *db;
970  if ( sqlite3_open( QgsApplication::qgisUserDbFilePath().toUtf8().constData(), &db ) != SQLITE_OK )
971  {
972  if ( errorMessage )
973  {
974  *errorMessage = tr( "Could not open qgis.db" );
975  }
976  return false;
977  }
978 
979  char *errmsg;
980  int res = sqlite3_exec( db, "SELECT epsg FROM tbl_srs LIMIT 0", 0, 0, &errmsg );
981  if ( res == SQLITE_OK )
982  {
983  // epsg column exists => need migration
984  if ( sqlite3_exec( db,
985  "ALTER TABLE tbl_srs RENAME TO tbl_srs_bak;"
986  "CREATE TABLE tbl_srs ("
987  "srs_id INTEGER PRIMARY KEY,"
988  "description text NOT NULL,"
989  "projection_acronym text NOT NULL,"
990  "ellipsoid_acronym NOT NULL,"
991  "parameters text NOT NULL,"
992  "srid integer,"
993  "auth_name varchar,"
994  "auth_id varchar,"
995  "is_geo integer NOT NULL,"
996  "deprecated boolean);"
997  "CREATE INDEX idx_srsauthid on tbl_srs(auth_name,auth_id);"
998  "INSERT INTO tbl_srs(srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) SELECT srs_id,description,projection_acronym,ellipsoid_acronym,parameters,srid,'','',is_geo,0 FROM tbl_srs_bak;"
999  "DROP TABLE tbl_srs_bak", 0, 0, &errmsg ) != SQLITE_OK
1000  )
1001  {
1002  if ( errorMessage )
1003  {
1004  *errorMessage = tr( "Migration of private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1005  }
1006  sqlite3_free( errmsg );
1007  sqlite3_close( db );
1008  return false;
1009  }
1010  }
1011  else
1012  {
1013  sqlite3_free( errmsg );
1014  }
1015 
1016  if ( sqlite3_exec( db, "DROP VIEW vw_srs", 0, 0, &errmsg ) != SQLITE_OK )
1017  {
1018  QgsDebugMsg( QString( "vw_srs didn't exists in private qgis.db: %1" ).arg( errmsg ) );
1019  }
1020 
1021  if ( sqlite3_exec( db,
1022  "CREATE VIEW vw_srs AS"
1023  " SELECT"
1024  " a.description AS description"
1025  ",a.srs_id AS srs_id"
1026  ",a.is_geo AS is_geo"
1027  ",coalesce(b.name,a.projection_acronym) AS name"
1028  ",a.parameters AS parameters"
1029  ",a.auth_name AS auth_name"
1030  ",a.auth_id AS auth_id"
1031  ",a.deprecated AS deprecated"
1032  " FROM tbl_srs a"
1033  " LEFT OUTER JOIN tbl_projection b ON a.projection_acronym=b.acronym"
1034  " ORDER BY coalesce(b.name,a.projection_acronym),a.description", 0, 0, &errmsg ) != SQLITE_OK
1035  )
1036  {
1037  if ( errorMessage )
1038  {
1039  *errorMessage = tr( "Update of view in private qgis.db failed.\n%1" ).arg( QString::fromUtf8( errmsg ) );
1040  }
1041  sqlite3_free( errmsg );
1042  sqlite3_close( db );
1043  return false;
1044  }
1045 
1046  sqlite3_close( db );
1047  }
1048  return true;
1049 }
1050 
1051 void QgsApplication::setMaxThreads( int maxThreads )
1052 {
1053  QgsDebugMsg( QString( "maxThreads: %1" ).arg( maxThreads ) );
1054 
1055  // make sure value is between 1 and #cores, if not set to -1 (use #cores)
1056  // 0 could be used to disable any parallel processing
1057  if ( maxThreads < 1 || maxThreads > QThread::idealThreadCount() )
1058  maxThreads = -1;
1059 
1060  // save value
1061  ABISYM( mMaxThreads ) = maxThreads;
1062 
1063  // if -1 use #cores
1064  if ( maxThreads == -1 )
1065  maxThreads = QThread::idealThreadCount();
1066 
1067  // set max thread count in QThreadPool
1068  QThreadPool::globalInstance()->setMaxThreadCount( maxThreads );
1069  QgsDebugMsg( QString( "set QThreadPool max thread count to %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
1070 }
1071