QGIS/src/app/qgisapp.cpp
2008-08-23 19:38:17 +00:00

5456 lines
170 KiB
C++

/***************************************************************************
qgisapp.cpp - description
-------------------
begin : Sat Jun 22 2002
copyright : (C) 2002 by Gary E.Sherman
email : sherman at mrcc.com
Romans 3:23=>Romans 6:23=>Romans 10:9,10=>Romans 12
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/* $Id$ */
//
// QT4 includes make sure to use the new <CamelCase> style!
//
#include <QAction>
#include <QApplication>
#include <QBitmap>
#include <QCheckBox>
#include <QClipboard>
#include <QColor>
#include <QCursor>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialog>
#include <QDir>
#include <QDockWidget>
#include <QEvent>
#include <QFile>
#include <QFileInfo>
#include <QInputDialog>
#include <QKeyEvent>
#include <QLabel>
#include <QLibrary>
#include <QMenu>
#include <QMenuBar>
#include <QMenuItem>
#include <QMessageBox>
#include <QNetworkProxy>
#include <QPainter>
#include <QPictureIO>
#include <QPixmap>
#include <QPoint>
#include <QPrinter>
#include <QProcess>
#include <QProgressBar>
#include <QRegExp>
#include <QRegExpValidator>
#include <QSettings>
#include <QSplashScreen>
#include <QStatusBar>
#include <QStringList>
#include <QTcpSocket>
#include <QTextStream>
#include <QTimer>
#include <QToolButton>
#include <QVBoxLayout>
#include <QWhatsThis>
#include <QtGlobal>
//
// Mac OS X Includes
// Must include before GEOS 3 due to unqualified use of 'Point'
//
#ifdef Q_OS_MACX
#include <ApplicationServices/ApplicationServices.h>
// check macro breaks QItemDelegate
#ifdef check
#undef check
#endif
#endif
//
// QGIS Specific Includes
//
#include "../../images/themes/default/qgis.xpm"
#include "qgisapp.h"
#include "qgisappinterface.h"
#include "qgis.h"
#include "qgisplugin.h"
#include "qgsabout.h"
#include "qgsapplication.h"
#include "qgsbookmarkitem.h"
#include "qgsbookmarks.h"
#include "qgsclipboard.h"
#include "qgscomposer.h"
#include "qgscoordinatetransform.h"
#include "qgscursors.h"
#include "qgscustomprojectiondialog.h"
#include "qgsencodingfiledialog.h"
#include "qgsexception.h"
#include "qgsfeature.h"
#include "qgsgeomtypedialog.h"
#include "qgshelpviewer.h"
#include "qgsgenericprojectionselector.h"
#include "qgslegend.h"
#include "qgslegendlayerfile.h"
#include "qgslegendlayer.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerinterface.h"
#include "qgsmaplayerregistry.h"
#include "qgsmapoverviewcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaptip.h"
#include "qgsmessageviewer.h"
#include "qgsoptions.h"
#include "qgspastetransformations.h"
#include "qgspluginitem.h"
#include "qgspluginmanager.h"
#include "qgspluginregistry.h"
#include "qgspoint.h"
#include "qgsproject.h"
#include "qgsprojectproperties.h"
#include "qgsproviderregistry.h"
#include "qgsrasterlayer.h"
#include "qgsrasterlayerproperties.h"
#include "qgsrect.h"
#include "qgsrenderer.h"
#include "qgsserversourceselect.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsattributetabledisplay.h"
//
// Gdal/Ogr includes
//
#include <ogr_api.h>
//
// Other includes
//
#include <algorithm>
#include <cassert>
#include <cmath>
#include <functional>
#include <iomanip>
#include <list>
#include <memory>
#include <vector>
//
// Map tools
//
#include "qgsmaptooladdfeature.h"
#include "qgsmaptooladdisland.h"
#include "qgsmaptooladdring.h"
#include "qgsmaptooladdvertex.h"
#include "qgsmaptooldeletevertex.h"
#include "qgsmaptoolidentify.h"
#include "qgsmaptoolmovefeature.h"
#include "qgsmaptoolmovevertex.h"
#include "qgsmaptoolpan.h"
#include "qgsmaptoolselect.h"
#include "qgsmaptoolsplitfeatures.h"
#include "qgsmaptoolvertexedit.h"
#include "qgsmaptoolzoom.h"
#include "qgsmeasuretool.h"
//
// Conditional Includes
//
#ifdef HAVE_POSTGRESQL
#include "qgsdbsourceselect.h"
#endif
#include "qgspythondialog.h"
#include "qgspythonutils.h"
#ifndef WIN32
#include <dlfcn.h>
#endif
#ifdef WIN32
#include <windows.h>
#endif
using namespace std;
class QTreeWidgetItem;
/* typedefs for plugins */
typedef QgsMapLayerInterface *create_it();
typedef QgisPlugin *create_ui(QgisInterface * qI);
typedef QString name_t();
typedef QString description_t();
typedef int type_t();
// IDs for locating particular menu items
const int BEFORE_RECENT_PATHS = 123;
const int AFTER_RECENT_PATHS = 321;
/// build the vector file filter string for a QFileDialog
/*
called in ctor for initializing mVectorFileFilter
*/
static void buildSupportedVectorFileFilter_(QString & fileFilters);
/** set the application title bar text
If the current project title is null
if the project file is null then
set title text to just application name and version
else
set set title text to the the project file name
else
set the title text to project title
*/
static void setTitleBarText_( QWidget & qgisApp )
{
QString caption = QgisApp::tr("Quantum GIS - ");
caption += QString("%1 ").arg(QGis::qgisVersion) + " ";
if ( QgsProject::instance()->title().isEmpty() )
{
if ( QgsProject::instance()->fileName().isEmpty() )
{
// no project title nor file name, so just leave caption with
// application name and version
}
else
{
QFileInfo projectFileInfo( QgsProject::instance()->fileName() );
caption += projectFileInfo.baseName();
}
}
else
{
caption += QgsProject::instance()->title();
}
qgisApp.setWindowTitle( caption );
} // setTitleBarText_( QWidget * qgisApp )
/**
Creator function for output viewer
*/
static QgsMessageOutput* messageOutputViewer_()
{
return new QgsMessageViewer();
}
/**
* This function contains forced validation of CRS used in QGIS.
* There are 3 options depending on the settings:
* - ask for CRS using projection selecter
* - use project's CRS
* - use predefined global CRS
*/
static void customSrsValidation_(QgsCoordinateReferenceSystem* srs)
{
QString proj4String;
QSettings mySettings;
QString myDefaultProjectionOption =
mySettings.value("/Projections/defaultBehaviour").toString();
if (myDefaultProjectionOption=="prompt")
{
//@note this class is not a descendent of QWidget so we cant pass
//it in the ctor of the layer projection selector
QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector();
mySelector->setMessage(); //shows a generic message
proj4String = QgsProject::instance()->readEntry("SpatialRefSys","//ProjectCRSProj4String",GEOPROJ4);
QgsCoordinateReferenceSystem defaultCRS;
if(defaultCRS.createFromProj4(proj4String))
{
mySelector->setSelectedCRSID(defaultCRS.srsid());
}
if(mySelector->exec())
{
QgsDebugMsg("Layer srs set from dialog: " + QString::number(mySelector->getSelectedCRSID()));
srs->createFromProj4(mySelector->getSelectedProj4String());
srs->debugPrint();
}
else
{
QApplication::restoreOverrideCursor();
}
delete mySelector;
}
else if (myDefaultProjectionOption=="useProject")
{
// XXX TODO: Change project to store selected CS as 'projectCRS' not 'selectedWKT'
proj4String = QgsProject::instance()->readEntry("SpatialRefSys","//ProjectCRSProj4String",GEOPROJ4);
QgsDebugMsg("Layer srs set from project: " + proj4String);
srs->createFromProj4(proj4String);
srs->debugPrint();
}
else ///Projections/defaultBehaviour==useGlobal
{
srs->createFromProj4(mySettings.value("/Projections/defaultProjectionString",GEOPROJ4).toString());
srs->debugPrint();
}
}
QgisApp *QgisApp::smInstance = 0;
// constructor starts here
QgisApp::QgisApp(QSplashScreen *splash, QWidget * parent, Qt::WFlags fl)
: QMainWindow(parent,fl),
mSplash(splash),
mPythonConsole(NULL),
mPythonUtils(NULL)
{
if(smInstance) {
QMessageBox::critical(
this,
tr("Multiple Instances of QgisApp"),
tr("Multiple instances of Quantum GIS application object detected.\nPlease contact the developers.\n"));
abort();
}
smInstance = this;
// setupUi(this);
resize(640, 480);
mSplash->showMessage(tr("Checking database"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
// Do this early on before anyone else opens it and prevents us copying it
createDB();
mSplash->showMessage(tr("Reading settings"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
mSplash->showMessage(tr("Setting up the GUI"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
createActions();
createActionGroups();
createMenus();
createToolBars();
createStatusBar();
createCanvas();
mMapCanvas->freeze();
createLegend();
createOverview();
createMapTips();
setupProxy();
readSettings();
updateRecentProjectPaths();
mComposer = new QgsComposer(this); // Map composer
mInternalClipboard = new QgsClipboard; // create clipboard
mQgisInterface = new QgisAppInterface(this); // create the interfce
// set application's icon
setWindowIcon(QPixmap(qgis_xpm));
// set application's caption
QString caption = tr("Quantum GIS - ");
caption += QString("%1 ('%2')").arg(QGis::qgisVersion).arg(QGis::qgisReleaseName);
setWindowTitle(caption);
// set QGIS specific srs validation
QgsCoordinateReferenceSystem::setCustomSrsValidation(customSrsValidation_);
// set graphical message output
QgsMessageOutput::setMessageOutputCreator(messageOutputViewer_);
fileNew(); // prepare empty project
qApp->processEvents();
// load providers
mSplash->showMessage(tr("Checking provider plugins"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
QgsApplication::initQgis();
mSplash->showMessage(tr("Starting Python"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
loadPythonSupport();
// Create the plugin registry and load plugins
// load any plugins that were running in the last session
mSplash->showMessage(tr("Restoring loaded plugins"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
restoreSessionPlugins(QgsApplication::pluginPath());
mSplash->showMessage(tr("Initializing file filters"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
// now build vector file filter
buildSupportedVectorFileFilter_( mVectorFileFilter );
// now build raster file filter
QgsRasterLayer::buildSupportedRasterFileFilter( mRasterFileFilter );
#if 0
// Set the background colour for toolbox and overview as they default to
// white instead of the window color
QPalette myPalette = toolBox->palette();
myPalette.setColor(QPalette::Button, myPalette.window().color());
toolBox->setPalette(myPalette);
//do the same for legend control
myPalette = toolBox->palette();
myPalette.setColor(QPalette::Button, myPalette.window().color());
mMapLegend->setPalette(myPalette);
//and for overview control this is done in createOverView method
#endif
// Do this last in the ctor to ensure that all members are instantiated properly
setupConnections();
//
// Please make sure this is the last thing the ctor does so that we can ensure the
// widgets are all initialised before trying to restore their state.
//
mSplash->showMessage(tr("Restoring window state"), Qt::AlignHCenter | Qt::AlignBottom);
qApp->processEvents();
restoreWindowState();
mSplash->showMessage(tr("QGIS Ready!"), Qt::AlignHCenter | Qt::AlignBottom);
mMapTipsVisible = false;
// setup drag drop
setAcceptDrops(true);
mFullScreenMode = false;
show();
qApp->processEvents();
//finally show all the application settings as initialised above
QgsApplication::showSettings();
mMapCanvas->freeze(false);
} // QgisApp ctor
QgisApp::~QgisApp()
{
delete mInternalClipboard;
delete mQgisInterface;
delete mMapTools.mZoomIn;
delete mMapTools.mZoomOut;
delete mMapTools.mPan;
delete mMapTools.mIdentify;
delete mMapTools.mMeasureDist;
delete mMapTools.mMeasureArea;
delete mMapTools.mCapturePoint;
delete mMapTools.mCaptureLine;
delete mMapTools.mCapturePolygon;
delete mMapTools.mMoveFeature;
delete mMapTools.mSplitFeatures;
delete mMapTools.mSelect;
delete mMapTools.mVertexAdd;
delete mMapTools.mVertexMove;
delete mMapTools.mVertexDelete;
delete mMapTools.mAddRing;
delete mMapTools.mAddIsland;
delete mPythonConsole;
delete mPythonUtils;
// delete map layer registry and provider registry
QgsApplication::exitQgis();
}
void QgisApp::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls())
{
event->acceptProposedAction();
}
}
void QgisApp::dropEvent(QDropEvent *event)
{
// get the file list
QList<QUrl>::iterator i;
QList<QUrl>urls = event->mimeData()->urls();
for (i = urls.begin(); i != urls.end(); i++)
{
QUrl mUrl = *i;
// seems that some drag and drop operations include an empty url
// so we test for length to make sure we have something
if( mUrl.path().length() > 0)
{
// check to see if we are opening a project file
QFileInfo fi(mUrl.path());
if( fi.completeSuffix() == "qgs" )
{
QgsDebugMsg("Opening project " + mUrl.path());
}
else
{
QgsDebugMsg("Adding " + mUrl.path() + " to the map canvas");
openLayer(mUrl.path());
}
}
}
event->acceptProposedAction();
}
// restore any application settings stored in QSettings
void QgisApp::readSettings()
{
QSettings settings;
// get the users theme preference from the settings
setTheme(settings.value("/Themes","default").toString());
// Add the recently accessed project file paths to the File menu
mRecentProjectPaths = settings.value("/UI/recentProjectsList").toStringList();
}
//////////////////////////////////////////////////////////////////////
// Set Up the gui toolbars, menus, statusbar etc
//////////////////////////////////////////////////////////////////////
void QgisApp::createActions()
{
//
// File Menu Related Items
//
mActionFileNew= new QAction(getThemeIcon("mActionFileNew.png"), tr("&New Project"), this);
mActionFileNew->setShortcut(tr("Ctrl+N","New Project"));
mActionFileNew->setStatusTip(tr("New Project"));
connect(mActionFileNew, SIGNAL(triggered()), this, SLOT(fileNew()));
//
mActionFileOpen= new QAction(getThemeIcon("mActionFileOpen.png"), tr("&Open Project..."), this);
mActionFileOpen->setShortcut(tr("Ctrl+O","Open a Project"));
mActionFileOpen->setStatusTip(tr("Open a Project"));
connect(mActionFileOpen, SIGNAL(triggered()), this, SLOT(fileOpen()));
//
mActionFileSave= new QAction(getThemeIcon("mActionFileSave.png"), tr("&Save Project"), this);
mActionFileSave->setShortcut(tr("Ctrl+S","Save Project"));
mActionFileSave->setStatusTip(tr("Save Project"));
connect(mActionFileSave, SIGNAL(triggered()), this, SLOT(fileSave()));
//
mActionFileSaveAs= new QAction(getThemeIcon("mActionFileSaveAs.png"), tr("Save Project &As..."), this);
mActionFileSaveAs->setShortcut(tr("Ctrl+A","Save Project under a new name"));
mActionFileSaveAs->setStatusTip(tr("Save Project under a new name"));
connect(mActionFileSaveAs, SIGNAL(triggered()), this, SLOT(fileSaveAs()));
//
mActionFilePrint= new QAction(getThemeIcon("mActionFilePrint.png"), tr("&Print..."), this);
mActionFilePrint->setShortcut(tr("Ctrl+P","Print"));
mActionFilePrint->setStatusTip(tr("Print"));
connect(mActionFilePrint, SIGNAL(triggered()), this, SLOT(filePrint()));
//
mActionSaveMapAsImage= new QAction(getThemeIcon("mActionSaveMapAsImage.png"), tr("Save as Image..."), this);
mActionSaveMapAsImage->setShortcut(tr("Ctrl+I","Save map as image"));
mActionSaveMapAsImage->setStatusTip(tr("Save map as image"));
connect(mActionSaveMapAsImage, SIGNAL(triggered()), this, SLOT(saveMapAsImage()));
//
mActionFileExit= new QAction(getThemeIcon("mActionFileExit.png"), tr("Exit"), this);
mActionFileExit->setShortcut(tr("Ctrl+Q","Exit QGIS"));
mActionFileExit->setStatusTip(tr("Exit QGIS"));
connect(mActionFileExit, SIGNAL(triggered()), this, SLOT(fileExit()));
//
// Layer Menu Related Items
//
mActionAddOgrLayer= new QAction(getThemeIcon("mActionAddOgrLayer.png"), tr("Add a Vector Layer..."), this);
mActionAddOgrLayer->setShortcut(tr("V","Add a Vector Layer"));
mActionAddOgrLayer->setStatusTip(tr("Add a Vector Layer"));
connect(mActionAddOgrLayer, SIGNAL(triggered()), this, SLOT(addVectorLayer()));
//
mActionAddRasterLayer= new QAction(getThemeIcon("mActionAddRasterLayer.png"), tr("Add a Raster Layer..."), this);
mActionAddRasterLayer->setShortcut(tr("R","Add a Raster Layer"));
mActionAddRasterLayer->setStatusTip(tr("Add a Raster Layer"));
connect(mActionAddRasterLayer, SIGNAL(triggered()), this, SLOT(addRasterLayer()));
//
mActionAddLayer= new QAction(getThemeIcon("mActionAddLayer.png"), tr("Add a PostGIS Layer..."), this);
mActionAddLayer->setShortcut(tr("D","Add a PostGIS Layer"));
mActionAddLayer->setStatusTip(tr("Add a PostGIS Layer"));
//#ifdef HAVE_POSTGRESQL
// std::cout << "HAVE_POSTGRESQL is defined" << std::endl;
// assert(0);
//#else
// std::cout << "HAVE_POSTGRESQL not defined" << std::endl;
// assert(0);
//#endif
connect(mActionAddLayer, SIGNAL(triggered()), this, SLOT(addDatabaseLayer()));
//
mActionNewVectorLayer= new QAction(getThemeIcon("mActionNewVectorLayer.png"), tr("New Vector Layer..."), this);
mActionNewVectorLayer->setShortcut(tr("N","Create a New Vector Layer"));
mActionNewVectorLayer->setStatusTip(tr("Create a New Vector Layer"));
connect(mActionNewVectorLayer, SIGNAL(triggered()), this, SLOT(newVectorLayer()));
//
mActionRemoveLayer= new QAction(getThemeIcon("mActionRemoveLayer.png"), tr("Remove Layer"), this);
mActionRemoveLayer->setShortcut(tr("Ctrl+D","Remove a Layer"));
mActionRemoveLayer->setStatusTip(tr("Remove a Layer"));
connect(mActionRemoveLayer, SIGNAL(triggered()), this, SLOT(removeLayer()));
mActionRemoveLayer->setEnabled(false);
//
mActionAddAllToOverview= new QAction(getThemeIcon("mActionAddAllToOverview.png"), tr("Add All To Overview"), this);
mActionAddAllToOverview->setShortcut(tr("+","Show all layers in the overview map"));
mActionAddAllToOverview->setStatusTip(tr("Show all layers in the overview map"));
connect(mActionAddAllToOverview, SIGNAL(triggered()), this, SLOT(addAllToOverview()));
//
mActionRemoveAllFromOverview= new QAction(getThemeIcon("mActionRemoveAllFromOverview.png"), tr("Remove All From Overview"), this);
mActionRemoveAllFromOverview->setShortcut(tr("-","Remove all layers from overview map"));
mActionRemoveAllFromOverview->setStatusTip(tr("Remove all layers from overview map"));
connect(mActionRemoveAllFromOverview, SIGNAL(triggered()), this, SLOT(removeAllFromOverview()));
//
mActionToggleFullScreen = new QAction(getThemeIcon("mActionToggleFullScreen.png"), tr("Toggle full screen mode"), this);
mActionToggleFullScreen->setShortcut(tr("Ctrl-F","Toggle fullscreen mode"));
mActionToggleFullScreen->setStatusTip(tr("Toggle fullscreen mode"));
connect(mActionToggleFullScreen, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
//
mActionShowAllLayers= new QAction(getThemeIcon("mActionShowAllLayers.png"), tr("Show All Layers"), this);
mActionShowAllLayers->setShortcut(tr("S","Show all layers"));
mActionShowAllLayers->setStatusTip(tr("Show all layers"));
connect(mActionShowAllLayers, SIGNAL(triggered()), this, SLOT(showAllLayers()));
//
mActionHideAllLayers= new QAction(getThemeIcon("mActionHideAllLayers.png"), tr("Hide All Layers"), this);
mActionHideAllLayers->setShortcut(tr("H","Hide all layers"));
mActionHideAllLayers->setStatusTip(tr("Hide all layers"));
connect(mActionHideAllLayers, SIGNAL(triggered()), this, SLOT(hideAllLayers()));
//
// Settings Menu Related Items
//
mActionProjectProperties= new QAction(getThemeIcon("mActionProjectProperties.png"), tr("Project Properties..."), this);
mActionProjectProperties->setShortcut(tr("P","Set project properties"));
mActionProjectProperties->setStatusTip(tr("Set project properties"));
connect(mActionProjectProperties, SIGNAL(triggered()), this, SLOT(projectProperties()));
//
mActionOptions= new QAction(getThemeIcon("mActionOptions.png"), tr("Options..."), this);
// mActionOptions->setShortcut(tr("Alt+O","Change various QGIS options"));
mActionOptions->setStatusTip(tr("Change various QGIS options"));
connect(mActionOptions, SIGNAL(triggered()), this, SLOT(options()));
//
mActionCustomProjection= new QAction(getThemeIcon("mActionCustomProjection.png"), tr("Custom CRS..."), this);
// mActionCustomProjection->setShortcut(tr("Alt+I","Manage custom projections"));
mActionCustomProjection->setStatusTip(tr("Manage custom coordinate reference systems"));
connect(mActionCustomProjection, SIGNAL(triggered()), this, SLOT(customProjection()));
//
// Help Menu Related items
//
mActionHelpContents= new QAction(getThemeIcon("mActionHelpContents.png"), tr("Help Contents"), this);
#ifdef Q_WS_MAC
mActionHelpContents->setShortcut(tr("Ctrl+?","Help Documentation (Mac)"));
#else
mActionHelpContents->setShortcut(tr("F1","Help Documentation"));
#endif
mActionHelpContents->setStatusTip(tr("Help Documentation"));
connect(mActionHelpContents, SIGNAL(triggered()), this, SLOT(helpContents()));
//
mActionQgisHomePage= new QAction(getThemeIcon("mActionQgisHomePage.png"), tr("QGIS Home Page"), this);
#ifndef Q_WS_MAC
mActionQgisHomePage->setShortcut(tr("Ctrl+H","QGIS Home Page"));
#endif
mActionQgisHomePage->setStatusTip(tr("QGIS Home Page"));
connect(mActionQgisHomePage, SIGNAL(triggered()), this, SLOT(helpQgisHomePage()));
//
mActionHelpAbout= new QAction(getThemeIcon("mActionHelpAbout.png"), tr("About"), this);
mActionHelpAbout->setStatusTip(tr("About QGIS"));
connect(mActionHelpAbout, SIGNAL(triggered()), this, SLOT(about()));
//
mActionCheckQgisVersion= new QAction(getThemeIcon("mActionCheckQgisVersion.png"), tr("Check Qgis Version"), this);
mActionCheckQgisVersion->setStatusTip(tr("Check if your QGIS version is up to date (requires internet access)"));
connect(mActionCheckQgisVersion, SIGNAL(triggered()), this, SLOT(checkQgisVersion()));
//
// View Menu Items
//
mActionDraw= new QAction(getThemeIcon("mActionDraw.png"), tr("Refresh"), this);
mActionDraw->setShortcut(tr("Ctrl+R","Refresh Map"));
mActionDraw->setStatusTip(tr("Refresh Map"));
connect(mActionDraw, SIGNAL(triggered()), this, SLOT(refreshMapCanvas()));
//
mActionZoomIn= new QAction(getThemeIcon("mActionZoomIn.png"), tr("Zoom In"), this);
mActionZoomIn->setShortcut(tr("Ctrl++","Zoom In"));
mActionZoomIn->setStatusTip(tr("Zoom In"));
connect(mActionZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
//
mActionZoomOut= new QAction(getThemeIcon("mActionZoomOut.png"), tr("Zoom Out"), this);
mActionZoomOut->setShortcut(tr("Ctrl+-","Zoom Out"));
mActionZoomOut->setStatusTip(tr("Zoom Out"));
connect(mActionZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
//
mActionZoomFullExtent= new QAction(getThemeIcon("mActionZoomFullExtent.png"), tr("Zoom Full"), this);
mActionZoomFullExtent->setShortcut(tr("F","Zoom to Full Extents"));
mActionZoomFullExtent->setStatusTip(tr("Zoom to Full Extents"));
connect(mActionZoomFullExtent, SIGNAL(triggered()), this, SLOT(zoomFull()));
//
mActionZoomToSelected= new QAction(getThemeIcon("mActionZoomToSelected.png"), tr("Zoom To Selection"), this);
mActionZoomToSelected->setShortcut(tr("Ctrl+F","Zoom to selection"));
mActionZoomToSelected->setStatusTip(tr("Zoom to selection"));
connect(mActionZoomToSelected, SIGNAL(triggered()), this, SLOT(zoomToSelected()));
//
mActionPan= new QAction(getThemeIcon("mActionPan.png"), tr("Pan Map"), this);
mActionPan->setStatusTip(tr("Pan the map"));
connect(mActionPan, SIGNAL(triggered()), this, SLOT(pan()));
//
mActionZoomLast= new QAction(getThemeIcon("mActionZoomLast.png"), tr("Zoom Last"), this);
//mActionZoomLast->setShortcut(tr("Ctrl+O","Zoom to Last Extent"));
mActionZoomLast->setStatusTip(tr("Zoom to Last Extent"));
connect(mActionZoomLast, SIGNAL(triggered()), this, SLOT(zoomPrevious()));
//
mActionZoomToLayer= new QAction(getThemeIcon("mActionZoomToLayer.png"), tr("Zoom To Layer"), this);
//mActionZoomToLayer->setShortcut(tr("Ctrl+O","Zoom to Layer"));
mActionZoomToLayer->setStatusTip(tr("Zoom to Layer"));
connect(mActionZoomToLayer, SIGNAL(triggered()), this, SLOT(zoomToLayerExtent()));
//
mActionIdentify= new QAction(getThemeIcon("mActionIdentify.png"), tr("Identify Features"), this);
mActionIdentify->setShortcut(tr("I","Click on features to identify them"));
mActionIdentify->setStatusTip(tr("Click on features to identify them"));
connect(mActionIdentify, SIGNAL(triggered()), this, SLOT(identify()));
//
mActionSelect= new QAction(getThemeIcon("mActionSelect.png"), tr("Select Features"), this);
mActionSelect->setStatusTip(tr("Select Features"));
connect(mActionSelect, SIGNAL(triggered()), this, SLOT(select()));
mActionSelect->setEnabled(false);
//
mActionOpenTable= new QAction(getThemeIcon("mActionOpenTable.png"), tr("Open Table"), this);
//mActionOpenTable->setShortcut(tr("Ctrl+O","Open Table"));
mActionOpenTable->setStatusTip(tr("Open Table"));
connect(mActionOpenTable, SIGNAL(triggered()), this, SLOT(attributeTable()));
mActionOpenTable->setEnabled(false);
//
mActionMeasure= new QAction(getThemeIcon("mActionMeasure.png"), tr("Measure Line "), this);
mActionMeasure->setShortcut(tr("Ctrl+M","Measure a Line"));
mActionMeasure->setStatusTip(tr("Measure a Line"));
connect(mActionMeasure, SIGNAL(triggered()), this, SLOT(measure()));
//
mActionMeasureArea= new QAction(getThemeIcon("mActionMeasureArea.png"), tr("Measure Area"), this);
mActionMeasureArea->setShortcut(tr("Ctrl+J","Measure an Area"));
mActionMeasureArea->setStatusTip(tr("Measure an Area"));
connect(mActionMeasureArea, SIGNAL(triggered()), this, SLOT(measureArea()));
//
mActionShowBookmarks= new QAction(getThemeIcon("mActionShowBookmarks.png"), tr("Show Bookmarks"), this);
mActionShowBookmarks->setShortcut(tr("B","Show Bookmarks"));
mActionShowBookmarks->setStatusTip(tr("Show Bookmarks"));
connect(mActionShowBookmarks, SIGNAL(triggered()), this, SLOT(showBookmarks()));
//
mActionShowAllToolbars = new QAction(tr("Show most toolbars"), this);
mActionShowAllToolbars->setShortcut(tr("T", "Show most toolbars"));
mActionShowAllToolbars->setStatusTip(tr("Show most toolbars"));
connect(mActionShowAllToolbars, SIGNAL(triggered()), this,
SLOT(showAllToolbars()));
//
mActionHideAllToolbars = new QAction(tr("Hide most toolbars"), this);
mActionHideAllToolbars->setShortcut(tr("Ctrl+T", "Hide most toolbars"));
mActionHideAllToolbars->setStatusTip(tr("Hide most toolbars"));
connect(mActionHideAllToolbars, SIGNAL(triggered()), this,
SLOT(hideAllToolbars()));
//
mActionNewBookmark= new QAction(getThemeIcon("mActionNewBookmark.png"), tr("New Bookmark..."), this);
mActionNewBookmark->setShortcut(tr("Ctrl+B","New Bookmark"));
mActionNewBookmark->setStatusTip(tr("New Bookmark"));
connect(mActionNewBookmark, SIGNAL(triggered()), this, SLOT(newBookmark()));
//
mActionAddWmsLayer= new QAction(getThemeIcon("mActionAddWmsLayer.png"), tr("Add WMS Layer..."), this);
mActionAddWmsLayer->setShortcut(tr("W","Add Web Mapping Server Layer"));
mActionAddWmsLayer->setStatusTip(tr("Add Web Mapping Server Layer"));
connect(mActionAddWmsLayer, SIGNAL(triggered()), this, SLOT(addWmsLayer()));
//
mActionInOverview= new QAction(getThemeIcon("mActionInOverview.png"), tr("In Overview"), this);
mActionInOverview->setShortcut(tr("O","Add current layer to overview map"));
mActionInOverview->setStatusTip(tr("Add current layer to overview map"));
connect(mActionInOverview, SIGNAL(triggered()), this, SLOT(inOverview()));
mActionInOverview->setEnabled(false);
//
// Plugin Menu Related Items
//
mActionShowPluginManager= new QAction(getThemeIcon("mActionShowPluginManager.png"), tr("Plugin Manager..."), this);
// mActionShowPluginManager->setShortcut(tr("Ctrl+P","Open the plugin manager"));
mActionShowPluginManager->setStatusTip(tr("Open the plugin manager"));
connect(mActionShowPluginManager, SIGNAL(triggered()), this, SLOT(showPluginManager()));
//
// Add the whats this toolbar button
// QWhatsThis::whatsThisButton(mHelpToolBar);
//
//
// Digitising Toolbar Items
//
mActionToggleEditing = new QAction(getThemeIcon("mActionToggleEditing.png"),
tr("Toggle editing"), this);
mActionToggleEditing->setStatusTip(tr("Toggles the editing state of the current layer"));
mActionToggleEditing->setCheckable(true);
connect(mActionToggleEditing, SIGNAL(triggered()), this, SLOT(toggleEditing()));
mActionToggleEditing->setEnabled(false);
//
mActionCapturePoint= new QAction(getThemeIcon("mActionCapturePoint.png"), tr("Capture Point"), this);
mActionCapturePoint->setShortcut(tr(".","Capture Points"));
mActionCapturePoint->setStatusTip(tr("Capture Points"));
connect(mActionCapturePoint, SIGNAL(triggered()), this, SLOT(capturePoint()));
mActionCapturePoint->setEnabled(false);
//
mActionCaptureLine= new QAction(getThemeIcon("mActionCaptureLine.png"), tr("Capture Line"), this);
mActionCaptureLine->setShortcut(tr("/","Capture Lines"));
mActionCaptureLine->setStatusTip(tr("Capture Lines"));
connect(mActionCaptureLine, SIGNAL(triggered()), this, SLOT(captureLine()));
mActionCaptureLine->setEnabled(false);
//
mActionCapturePolygon= new QAction(getThemeIcon("mActionCapturePolygon.png"), tr("Capture Polygon"), this);
mActionCapturePolygon->setShortcut(tr("Ctrl+/","Capture Polygons"));
mActionCapturePolygon->setStatusTip(tr("Capture Polygons"));
connect(mActionCapturePolygon, SIGNAL(triggered()), this, SLOT(capturePolygon()));
mActionCapturePolygon->setEnabled(false);
//
mActionDeleteSelected = new QAction(getThemeIcon("mActionDeleteSelected.png"), tr("Delete Selected"), this);
mActionDeleteSelected->setStatusTip(tr("Delete Selected"));
connect(mActionDeleteSelected, SIGNAL(triggered()), this, SLOT(deleteSelected()));
mActionDeleteSelected->setEnabled(false);
//
mActionMoveFeature = new QAction(getThemeIcon("mActionMoveFeature.png"), tr("Move Feature"), this);
mActionMoveFeature->setStatusTip(tr("Move Feature"));
connect(mActionMoveFeature, SIGNAL(triggered()), this, SLOT(moveFeature()));
mActionMoveFeature->setEnabled(false);
//
mActionSplitFeatures = new QAction(getThemeIcon("mActionSplitFeatures.png"), tr("Split Features"), this);
mActionSplitFeatures->setStatusTip(tr("Split Features"));
connect(mActionSplitFeatures, SIGNAL(triggered()), this, SLOT(splitFeatures()));
mActionSplitFeatures->setEnabled(false);
//
mActionAddVertex = new QAction(getThemeIcon("mActionAddVertex.png"), tr("Add Vertex"), this);
mActionAddVertex->setStatusTip(tr("Add Vertex"));
connect(mActionAddVertex, SIGNAL(triggered()), this, SLOT(addVertex()));
mActionAddVertex->setEnabled(false);
//
mActionDeleteVertex = new QAction(getThemeIcon("mActionDeleteVertex.png"), tr("Delete Vertex"), this);
mActionDeleteVertex->setStatusTip(tr("Delete Vertex"));
connect(mActionDeleteVertex, SIGNAL(triggered()), this, SLOT(deleteVertex()));
mActionDeleteVertex->setEnabled(false);
//
mActionMoveVertex = new QAction(getThemeIcon("mActionMoveVertex.png"), tr("Move Vertex"), this);
mActionMoveVertex->setStatusTip(tr("Move Vertex"));
connect(mActionMoveVertex, SIGNAL(triggered()), this, SLOT(moveVertex()));
mActionMoveVertex->setEnabled(false);
mActionAddRing = new QAction(getThemeIcon("mActionAddRing.png"), tr("Add Ring"), this);
mActionAddRing->setStatusTip(tr("Add Ring"));
connect(mActionAddRing, SIGNAL(triggered()), this, SLOT(addRing()));
mActionAddRing->setEnabled(false);
mActionAddIsland = new QAction(getThemeIcon("mActionAddIsland.png"), tr("Add Island"), this);
mActionAddIsland->setStatusTip(tr("Add Island to multipolygon"));
connect(mActionAddIsland, SIGNAL(triggered()), this, SLOT(addIsland()));
mActionAddIsland->setEnabled(false);
mActionEditCut = new QAction(getThemeIcon("mActionEditCut.png"), tr("Cut Features"), this);
mActionEditCut->setStatusTip(tr("Cut selected features"));
connect(mActionEditCut, SIGNAL(triggered()), this, SLOT(editCut()));
mActionEditCut->setEnabled(false);
mActionEditCopy = new QAction(getThemeIcon("mActionEditCopy.png"), tr("Copy Features"), this);
mActionEditCopy->setStatusTip(tr("Copy selected features"));
connect(mActionEditCopy, SIGNAL(triggered()), this, SLOT(editCopy()));
mActionEditCopy->setEnabled(false);
mActionEditPaste = new QAction(getThemeIcon("mActionEditPaste.png"), tr("Paste Features"), this);
mActionEditPaste->setStatusTip(tr("Paste selected features"));
connect(mActionEditPaste, SIGNAL(triggered()), this, SLOT(editPaste()));
mActionEditPaste->setEnabled(false);
// maptips
mActionMapTips = new QAction(getThemeIcon("mActionMapTips.png"), tr("Map Tips"), this);
mActionMapTips->setStatusTip(tr("Show information about a feature when the mouse is hovered over it"));
connect ( mActionMapTips, SIGNAL ( triggered() ), this, SLOT ( toggleMapTips() ) );
mActionMapTips->setCheckable(true);
}
void QgisApp::showPythonDialog()
{
if (!mPythonUtils || !mPythonUtils->isEnabled())
return;
if (mPythonConsole == NULL)
mPythonConsole = new QgsPythonDialog(mQgisInterface, mPythonUtils);
mPythonConsole->show();
}
void QgisApp::createActionGroups()
{
//
// Map Tool Group
mMapToolGroup = new QActionGroup(this);
mActionPan->setCheckable(true);
mMapToolGroup->addAction(mActionPan);
mActionZoomIn->setCheckable(true);
mMapToolGroup->addAction(mActionZoomIn);
mActionZoomOut->setCheckable(true);
mMapToolGroup->addAction(mActionZoomOut);
mActionIdentify->setCheckable(true);
mMapToolGroup->addAction(mActionIdentify);
mActionSelect->setCheckable(true);
mMapToolGroup->addAction(mActionSelect);
mActionMeasure->setCheckable(true);
mMapToolGroup->addAction(mActionMeasure);
mActionMeasureArea->setCheckable(true);
mMapToolGroup->addAction(mActionMeasureArea);
mActionCaptureLine->setCheckable(true);
mMapToolGroup->addAction(mActionCaptureLine);
mActionCapturePoint->setCheckable(true);
mMapToolGroup->addAction(mActionCapturePoint);
mActionCapturePolygon->setCheckable(true);
mMapToolGroup->addAction(mActionCapturePolygon);
mActionMoveFeature->setCheckable(true);
mMapToolGroup->addAction(mActionMoveFeature);
mActionSplitFeatures->setCheckable(true);
mMapToolGroup->addAction(mActionSplitFeatures);
mMapToolGroup->addAction(mActionDeleteSelected);
mActionAddVertex->setCheckable(true);
mMapToolGroup->addAction(mActionAddVertex);
mActionDeleteVertex->setCheckable(true);
mMapToolGroup->addAction(mActionDeleteVertex);
mActionMoveVertex->setCheckable(true);
mMapToolGroup->addAction(mActionMoveVertex);
mActionAddRing->setCheckable(true);
mMapToolGroup->addAction(mActionAddRing);
mActionAddIsland->setCheckable(true);
mMapToolGroup->addAction(mActionAddIsland);
}
void QgisApp::createMenus()
{
//
// File Menu
mFileMenu = menuBar()->addMenu(tr("&File"));
mFileMenu->addAction(mActionFileNew);
mFileMenu->addAction(mActionFileOpen);
mRecentProjectsMenu = mFileMenu->addMenu(tr("&Open Recent Projects"));
// Connect once for the entire submenu.
connect(mRecentProjectsMenu, SIGNAL(triggered(QAction *)),
this, SLOT(openProject(QAction *)));
mFileMenu->addSeparator();
mFileMenu->addAction(mActionFileSave);
mFileMenu->addAction(mActionFileSaveAs);
mFileMenu->addAction(mActionSaveMapAsImage);
mFileMenu->addSeparator();
mFileMenu->addAction(mActionFilePrint);
mFileMenu->addSeparator();
mFileMenu->addAction(mActionFileExit);
//
// View Menu
mViewMenu = menuBar()->addMenu(tr("&View"));
mViewMenu->addAction(mActionZoomFullExtent);
mViewMenu->addAction(mActionZoomToSelected);
mViewMenu->addAction(mActionZoomToLayer);
mViewMenu->addAction(mActionZoomLast);
mViewMenu->addAction(mActionDraw);
mViewMenu->addAction(mActionToggleFullScreen);
mViewMenu->addSeparator();
mViewMenu->addAction(mActionShowBookmarks);
mViewMenu->addAction(mActionNewBookmark);
mViewMenu->addSeparator();
//
// View:toolbars menu
mViewMenu->addAction(mActionShowAllToolbars);
mViewMenu->addAction(mActionHideAllToolbars);
//
// Layers Menu
mLayerMenu = menuBar()->addMenu(tr("&Layer"));
mLayerMenu->addAction(mActionAddOgrLayer);
mLayerMenu->addAction(mActionAddRasterLayer);
#ifdef HAVE_POSTGRESQL
mLayerMenu->addAction(mActionAddLayer);
#endif
mLayerMenu->addAction(mActionAddWmsLayer);
mLayerMenu->addSeparator();
mLayerMenu->addAction(mActionRemoveLayer);
mLayerMenu->addAction(mActionNewVectorLayer);
mLayerMenu->addSeparator();
mLayerMenu->addAction(mActionInOverview);
mLayerMenu->addAction(mActionAddAllToOverview);
mLayerMenu->addAction(mActionRemoveAllFromOverview);
mLayerMenu->addSeparator();
mLayerMenu->addAction(mActionHideAllLayers);
mLayerMenu->addAction(mActionShowAllLayers);
//
// Settings Menu
mSettingsMenu = menuBar()->addMenu(tr("&Settings"));
mSettingsMenu->addAction(mActionProjectProperties);
mSettingsMenu->addAction(mActionCustomProjection);
mSettingsMenu->addAction(mActionOptions);
//
// Plugins Menu
mPluginMenu = menuBar()->addMenu(tr("&Plugins"));
mPluginMenu->addAction(mActionShowPluginManager);
mPluginMenu->addSeparator();
// Add the plugin manager action to it
//actionPluginManager->addTo(mPluginMenu);
// Add separator. Plugins will add their menus to this
// menu when they are loaded by the plugin manager
//mPluginMenu->insertSeparator();
// Add to the menubar
//menuBar()->insertItem(tr("&Plugins"), mPluginMenu, -1, menuBar()->count() - 1);
menuBar()->addSeparator();
mHelpMenu = menuBar()->addMenu(tr("&Help"));
mHelpMenu->addAction(mActionHelpContents);
mHelpMenu->addSeparator();
mHelpMenu->addAction(mActionQgisHomePage);
mHelpMenu->addAction(mActionCheckQgisVersion);
mHelpMenu->addSeparator();
mHelpMenu->addAction(mActionHelpAbout);
}
void QgisApp::createToolBars()
{
QSize myIconSize ( 24,24 );
// QSize myIconSize ( 32,32 ); //large icons
// Note: we need to set each object name to ensure that
// qmainwindow::saveState and qmainwindow::restoreState
// work properly
//
// File Toolbar
mFileToolBar = addToolBar(tr("File"));
mFileToolBar->setIconSize(myIconSize);
mFileToolBar->setObjectName("FileToolBar");
mFileToolBar->addAction(mActionFileNew);
mFileToolBar->addAction(mActionFileNew);
mFileToolBar->addAction(mActionFileSave);
mFileToolBar->addAction(mActionFileSaveAs);
mFileToolBar->addAction(mActionFileOpen);
mFileToolBar->addAction(mActionFilePrint);
mFileToolBar->addAction(mActionAddOgrLayer);
mFileToolBar->addAction(mActionAddRasterLayer);
#ifdef HAVE_POSTGRESQL
mFileToolBar->addAction(mActionAddLayer);
#endif
mFileToolBar->addAction(mActionAddWmsLayer);
//
// Layer Toolbar
mLayerToolBar = addToolBar(tr("Manage Layers"));
mLayerToolBar->setIconSize(myIconSize);
mLayerToolBar->setObjectName("LayerToolBar");
mLayerToolBar->addAction(mActionNewVectorLayer);
mLayerToolBar->addAction(mActionRemoveLayer);
mLayerToolBar->addAction(mActionInOverview);
mLayerToolBar->addAction(mActionShowAllLayers);
mLayerToolBar->addAction(mActionHideAllLayers);
//
// Digitizing Toolbar
mDigitizeToolBar = addToolBar(tr("Digitizing"));
mDigitizeToolBar->setIconSize(myIconSize);
mDigitizeToolBar->setObjectName("Digitizing");
mDigitizeToolBar->addAction(mActionToggleEditing);
mDigitizeToolBar->addAction(mActionCapturePoint);
mDigitizeToolBar->addAction(mActionCaptureLine);
mDigitizeToolBar->addAction(mActionCapturePolygon);
mDigitizeToolBar->addAction(mActionAddRing);
mDigitizeToolBar->addAction(mActionAddIsland);
mDigitizeToolBar->addAction(mActionSplitFeatures);
mDigitizeToolBar->addAction(mActionMoveFeature);
mDigitizeToolBar->addAction(mActionMoveVertex);
mDigitizeToolBar->addAction(mActionAddVertex);
mDigitizeToolBar->addAction(mActionDeleteVertex);
mDigitizeToolBar->addAction(mActionDeleteSelected);
mDigitizeToolBar->addAction(mActionEditCut);
mDigitizeToolBar->addAction(mActionEditCopy);
mDigitizeToolBar->addAction(mActionEditPaste);
//
// Map Navigation Toolbar
mMapNavToolBar = addToolBar(tr("Map Navigation"));
mMapNavToolBar->setIconSize(myIconSize);
mMapNavToolBar->setObjectName("Map Navigation");
mMapNavToolBar->addAction(mActionPan);
mMapNavToolBar->addAction(mActionZoomIn);
mMapNavToolBar->addAction(mActionZoomOut);
mMapNavToolBar->addAction(mActionZoomFullExtent);
mMapNavToolBar->addAction(mActionZoomToSelected);
mMapNavToolBar->addAction(mActionZoomToLayer);
mMapNavToolBar->addAction(mActionZoomLast);
mMapNavToolBar->addAction(mActionDraw);
//
// Attributes Toolbar
mAttributesToolBar = addToolBar(tr("Attributes"));
mAttributesToolBar->setIconSize(myIconSize);
mAttributesToolBar->setObjectName("Attributes");
mAttributesToolBar->addAction(mActionIdentify);
mAttributesToolBar->addAction(mActionSelect);
mAttributesToolBar->addAction(mActionOpenTable);
mAttributesToolBar->addAction(mActionMeasure);
mAttributesToolBar->addAction(mActionMeasureArea);
mAttributesToolBar->addAction(mActionMapTips);
mAttributesToolBar->addAction(mActionShowBookmarks);
mAttributesToolBar->addAction(mActionNewBookmark);
//
// Plugins Toolbar
mPluginToolBar = addToolBar(tr("Plugins"));
mPluginToolBar->setIconSize(myIconSize);
mPluginToolBar->setObjectName("Plugins");
//
// Help Toolbar
mHelpToolBar = addToolBar(tr("Help"));
mHelpToolBar->setIconSize(myIconSize);
mHelpToolBar->setObjectName("Help");
mHelpToolBar->addAction(mActionHelpContents);
mHelpToolBar->addAction(QWhatsThis::createAction());
//Add the menu for toolbar visibility here
//because createPopupMenu() would return 0
//before the toolbars are created
QMenu* toolbarVisibilityMenu = createPopupMenu();
if(toolbarVisibilityMenu)
{
toolbarVisibilityMenu->setTitle(tr("Toolbar Visibility..."));
mViewMenu->addMenu(toolbarVisibilityMenu);
}
}
void QgisApp::createStatusBar()
{
//
// Add a panel to the status bar for the scale, coords and progress
// And also rendering suppression checkbox
//
mProgressBar = new QProgressBar(statusBar());
mProgressBar->setMaximumWidth(100);
mProgressBar->hide();
mProgressBar->setWhatsThis(tr("Progress bar that displays the status "
"of rendering layers and other time-intensive operations"));
statusBar()->addPermanentWidget(mProgressBar, 1);
// Bumped the font up one point size since 8 was too
// small on some platforms. A point size of 9 still provides
// plenty of display space on 1024x768 resolutions
QFont myFont( "Arial", 9 );
statusBar()->setFont(myFont);
//toggle to switch between mouse pos and extents display in status bar widget
mToggleExtentsViewButton = new QToolButton( statusBar() );
mToggleExtentsViewButton->setMaximumWidth(20);
mToggleExtentsViewButton->setMaximumHeight(20);
mToggleExtentsViewButton->setIcon(getThemeIcon("tracking.png"));
mToggleExtentsViewButton->setToolTip(tr("Toggle extents and mouse position display") );
mToggleExtentsViewButton->setCheckable(true);
connect(mToggleExtentsViewButton, SIGNAL(toggled(bool)), this, SLOT(extentsViewToggled(bool)));
statusBar()->addPermanentWidget(mToggleExtentsViewButton, 0);
//coords status bar widget
mCoordsLabel = new QLabel(QString(), statusBar());
mCoordsLabel->setMinimumWidth(10);
mCoordsLabel->setMaximumHeight(20);
mCoordsLabel->setFont(myFont);
mCoordsLabel->setMargin(3);
mCoordsLabel->setAlignment(Qt::AlignCenter);
mCoordsLabel->setWhatsThis(tr("Shows the map coordinates at the "
"current cursor position. The display is continuously updated "
"as the mouse is moved."));
statusBar()->addPermanentWidget(mCoordsLabel, 0);
// add a label to show current scale
mScaleLabel = new QLabel(QString(),statusBar());
mScaleLabel->setFont(myFont);
mScaleLabel->setMinimumWidth(10);
mScaleLabel->setMaximumHeight(20);
mScaleLabel->setMargin(3);
mScaleLabel->setAlignment(Qt::AlignCenter);
mScaleLabel->setFrameStyle(QFrame::NoFrame);
mScaleLabel->setText(tr("Scale "));
mScaleLabel->setToolTip(tr("Current map scale"));
statusBar()->addPermanentWidget(mScaleLabel, 0);
mScaleEdit = new QLineEdit(QString(),statusBar());
mScaleEdit->setFont(myFont);
mScaleEdit->setMinimumWidth(10);
mScaleEdit->setMaximumWidth(100);
mScaleEdit->setMaximumHeight(20);
mScaleEdit->setContentsMargins(0, 0, 0, 0);
mScaleEdit->setAlignment(Qt::AlignLeft);
QRegExp validator("\\d+\\.?\\d*:\\d+\\.?\\d*");
mScaleEditValidator = new QRegExpValidator(validator, mScaleEdit);
mScaleEdit->setValidator(mScaleEditValidator);
mScaleEdit->setWhatsThis(tr("Displays the current map scale"));
mScaleEdit->setToolTip(tr("Current map scale (formatted as x:y)"));
statusBar()->addPermanentWidget(mScaleEdit, 0);
connect(mScaleEdit, SIGNAL(editingFinished()), this, SLOT(userScale()));
//stop rendering status bar widget
mStopRenderButton = new QToolButton( statusBar() );
mStopRenderButton->setMaximumWidth(20);
mStopRenderButton->setMaximumHeight(20);
mStopRenderButton->setIcon(getThemeIcon("mIconDelete.png"));
mStopRenderButton->setToolTip(tr("Stop map rendering") );
statusBar()->addPermanentWidget(mStopRenderButton, 0);
// render suppression status bar widget
mRenderSuppressionCBox = new QCheckBox(tr("Render"),statusBar());
mRenderSuppressionCBox->setChecked(true);
mRenderSuppressionCBox->setFont(myFont);
mRenderSuppressionCBox->setWhatsThis(tr("When checked, the map layers "
"are rendered in response to map navigation commands and other "
"events. When not checked, no rendering is done. This allows you "
"to add a large number of layers and symbolize them before rendering."));
mRenderSuppressionCBox->setToolTip(tr("Toggle map rendering") );
statusBar()->addPermanentWidget(mRenderSuppressionCBox,0);
// On the fly projection status bar icon
// Changed this to a tool button since a QPushButton is
// sculpted on OS X and the icon is never displayed [gsherman]
mOnTheFlyProjectionStatusButton = new QToolButton(statusBar());
mOnTheFlyProjectionStatusButton->setMaximumWidth(20);
// Maintain uniform widget height in status bar by setting button height same as labels
// For Qt/Mac 3.3, the default toolbutton height is 30 and labels were expanding to match
mOnTheFlyProjectionStatusButton->setMaximumHeight(mScaleLabel->height());
mOnTheFlyProjectionStatusButton->setIcon(getThemeIcon("mIconProjectionDisabled.png"));
if (!QFile::exists(QgsApplication::defaultThemePath() + "/mIconProjectionDisabled.png"))
{
QMessageBox::critical(this, tr("Resource Location Error"),
tr("Error reading icon resources from: \n %1\n Quitting...").arg(
QgsApplication::defaultThemePath() + "/mIconProjectionDisabled.png"
));
exit(0);
}
mOnTheFlyProjectionStatusButton->setWhatsThis(tr("This icon shows whether "
"on the fly coordinate reference system transformation is enabled or not. "
"Click the icon to bring up "
"the project properties dialog to alter this behaviour."));
mOnTheFlyProjectionStatusButton->setToolTip(tr("CRS status - Click "
"to open coordinate reference system dialog"));
connect(mOnTheFlyProjectionStatusButton, SIGNAL(clicked()),
this, SLOT(projectPropertiesProjections()));//bring up the project props dialog when clicked
statusBar()->addPermanentWidget(mOnTheFlyProjectionStatusButton,0);
statusBar()->showMessage(tr("Ready"));
}
void QgisApp::setTheme(QString theThemeName)
{
/*****************************************************************
// Init the toolbar icons by setting the icon for each action.
// All toolbar/menu items must be a QAction in order for this
// to work.
//
// When new toolbar/menu QAction objects are added to the interface,
// add an entry below to set the icon
//
// PNG names must match those defined for the default theme. The
// default theme is installed in <prefix>/share/qgis/themes/default.
//
// New core themes can be added by creating a subdirectory under src/themes
// and modifying the appropriate CMakeLists.txt files. User contributed themes
// will be installed directly into <prefix>/share/qgis/themes/<themedir>.
//
// Themes can be selected from the preferences dialog. The dialog parses
// the themes directory and builds a list of themes (ie subdirectories)
// for the user to choose from.
//
*/
QgsApplication::setThemeName(theThemeName);
//QgsDebugMsg("Setting theme to \n" + theThemeName);
mActionFileNew->setIcon(getThemeIcon( "/mActionFileNew.png"));
mActionFileSave->setIcon(getThemeIcon( "/mActionFileSave.png"));
mActionFileSaveAs->setIcon(getThemeIcon( "/mActionFileSaveAs.png"));
mActionFileOpen->setIcon(getThemeIcon( "/mActionFileOpen.png"));
mActionFilePrint->setIcon(getThemeIcon( "/mActionFilePrint.png"));
mActionSaveMapAsImage->setIcon(getThemeIcon( "/mActionSaveMapAsImage.png"));
mActionFileExit->setIcon(getThemeIcon( "/mActionFileExit.png"));
mActionAddOgrLayer->setIcon(getThemeIcon( "/mActionAddOgrLayer.png"));
mActionAddRasterLayer->setIcon(getThemeIcon( "/mActionAddRasterLayer.png"));
mActionAddLayer->setIcon(getThemeIcon( "/mActionAddLayer.png"));
mActionRemoveLayer->setIcon(getThemeIcon( "/mActionRemoveLayer.png"));
mActionNewVectorLayer->setIcon(getThemeIcon( "/mActionNewVectorLayer.png"));
mActionAddAllToOverview->setIcon(getThemeIcon( "/mActionAddAllToOverview.png"));
mActionHideAllLayers->setIcon(getThemeIcon( "/mActionHideAllLayers.png"));
mActionShowAllLayers->setIcon(getThemeIcon( "/mActionShowAllLayers.png"));
mActionRemoveAllFromOverview->setIcon(getThemeIcon( "/mActionRemoveAllFromOverview.png"));
mActionProjectProperties->setIcon(getThemeIcon( "/mActionProjectProperties.png"));
mActionShowPluginManager->setIcon(getThemeIcon( "/mActionShowPluginManager.png"));
mActionCheckQgisVersion->setIcon(getThemeIcon( "/mActionCheckQgisVersion.png"));
mActionOptions->setIcon(getThemeIcon( "/mActionOptions.png"));
mActionHelpContents->setIcon(getThemeIcon( "/mActionHelpContents.png"));
mActionQgisHomePage->setIcon(getThemeIcon( "/mActionQgisHomePage.png"));
mActionHelpAbout->setIcon(getThemeIcon( "/mActionHelpAbout.png"));
mActionDraw->setIcon(getThemeIcon( "/mActionDraw.png"));
mActionCapturePoint->setIcon(getThemeIcon( "/mActionCapturePoint.png"));
mActionCaptureLine->setIcon(getThemeIcon( "/mActionCaptureLine.png"));
mActionCapturePolygon->setIcon(getThemeIcon( "/mActionCapturePolygon.png"));
mActionZoomIn->setIcon(getThemeIcon( "/mActionZoomIn.png"));
mActionZoomOut->setIcon(getThemeIcon( "/mActionZoomOut.png"));
mActionZoomFullExtent->setIcon(getThemeIcon( "/mActionZoomFullExtent.png"));
mActionZoomToSelected->setIcon(getThemeIcon( "/mActionZoomToSelected.png"));
mActionPan->setIcon(getThemeIcon( "/mActionPan.png"));
mActionZoomLast->setIcon(getThemeIcon( "/mActionZoomLast.png"));
mActionZoomToLayer->setIcon(getThemeIcon( "/mActionZoomToLayer.png"));
mActionIdentify->setIcon(getThemeIcon( "/mActionIdentify.png"));
mActionSelect->setIcon(getThemeIcon( "/mActionSelect.png"));
mActionOpenTable->setIcon(getThemeIcon( "/mActionOpenTable.png"));
mActionMeasure->setIcon(getThemeIcon( "/mActionMeasure.png"));
mActionMeasureArea->setIcon(getThemeIcon( "/mActionMeasureArea.png"));
mActionShowBookmarks->setIcon(getThemeIcon( "/mActionShowBookmarks.png"));
mActionNewBookmark->setIcon(getThemeIcon( "/mActionNewBookmark.png"));
mActionCustomProjection->setIcon(getThemeIcon( "/mActionCustomProjection.png"));
mActionAddWmsLayer->setIcon(getThemeIcon( "/mActionAddWmsLayer.png"));
mActionInOverview->setIcon(getThemeIcon( "/mActionInOverview.png"));
}
void QgisApp::setupConnections()
{
// connect the "cleanup" slot
connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(saveWindowState()));
//connect the legend, mapcanvas and overview canvas to the registry
// connect map layer registry signals to legend
connect(QgsMapLayerRegistry::instance(), SIGNAL(layerWillBeRemoved(QString)),
mMapLegend, SLOT(removeLayer(QString)));
connect(QgsMapLayerRegistry::instance(), SIGNAL(removedAll()),
mMapLegend, SLOT(removeAll()));
connect(QgsMapLayerRegistry::instance(), SIGNAL(layerWasAdded(QgsMapLayer*)),
mMapLegend, SLOT(addLayer(QgsMapLayer *)));
connect(mMapLegend, SIGNAL(currentLayerChanged(QgsMapLayer*)),
this, SLOT(activateDeactivateLayerRelatedActions(QgsMapLayer*)));
//signal when mouse moved over window (coords display in status bar)
connect(mMapCanvas, SIGNAL(xyCoordinates(QgsPoint &)), this, SLOT(showMouseCoordinate(QgsPoint &)));
connect(mMapCanvas->mapRenderer(), SIGNAL(drawingProgress(int,int)), this, SLOT(showProgress(int,int)));
connect(mMapCanvas->mapRenderer(), SIGNAL(projectionsEnabled(bool)), this, SLOT(projectionsEnabled(bool)));
connect(mMapCanvas->mapRenderer(), SIGNAL(destinationSrsChanged()), this, SLOT(destinationSrsChanged()));
connect(mMapCanvas, SIGNAL(extentsChanged()),this,SLOT(showExtents()));
connect(mMapCanvas, SIGNAL(scaleChanged(double)), this, SLOT(showScale(double)));
connect(mMapCanvas, SIGNAL(scaleChanged(double)), this, SLOT(updateMouseCoordinatePrecision()));
connect(mMapCanvas, SIGNAL(mapToolSet(QgsMapTool *)), this, SLOT(mapToolChanged(QgsMapTool *)));
connect(mRenderSuppressionCBox, SIGNAL(toggled(bool )), mMapCanvas, SLOT(setRenderFlag(bool)));
//
// Do we really need this ??? - its already connected to the esc key...TS
//
connect(mStopRenderButton, SIGNAL(clicked()), this, SLOT(stopRendering()));
// Connect warning dialog from project reading
connect(QgsProject::instance(), SIGNAL(warnOlderProjectVersion(QString)),
this, SLOT(warnOlderProjectVersion(QString)));
}
void QgisApp::createCanvas()
{
// "theMapCanvas" used to find this canonical instance later
mMapCanvas = new QgsMapCanvas(this, "theMapCanvas" );
mMapCanvas->setWhatsThis(tr("Map canvas. This is where raster and vector "
"layers are displayed when added to the map"));
setCentralWidget(mMapCanvas);
// set the focus to the map canvas
mMapCanvas->setFocus();
// create tools
mMapTools.mZoomIn = new QgsMapToolZoom(mMapCanvas, FALSE /* zoomIn */);
mMapTools.mZoomIn->setAction(mActionZoomIn);
mMapTools.mZoomOut = new QgsMapToolZoom(mMapCanvas, TRUE /* zoomOut */);
mMapTools.mZoomOut->setAction(mActionZoomOut);
mMapTools.mPan = new QgsMapToolPan(mMapCanvas);
mMapTools.mPan->setAction(mActionPan);
mMapTools.mIdentify = new QgsMapToolIdentify(mMapCanvas);
mMapTools.mIdentify->setAction(mActionIdentify);
mMapTools.mMeasureDist = new QgsMeasureTool(mMapCanvas, FALSE /* area */);
mMapTools.mMeasureDist->setAction(mActionMeasure);
mMapTools.mMeasureArea = new QgsMeasureTool(mMapCanvas, TRUE /* area */);
mMapTools.mMeasureArea->setAction(mActionMeasureArea);
mMapTools.mCapturePoint = new QgsMapToolAddFeature(mMapCanvas, QgsMapToolCapture::CapturePoint);
mMapTools.mCapturePoint->setAction(mActionCapturePoint);
mMapTools.mCaptureLine = new QgsMapToolAddFeature(mMapCanvas, QgsMapToolCapture::CaptureLine);
mMapTools.mCaptureLine->setAction(mActionCaptureLine);
mMapTools.mCapturePolygon = new QgsMapToolAddFeature(mMapCanvas, QgsMapToolCapture::CapturePolygon);
mMapTools.mCapturePolygon->setAction(mActionCapturePolygon);
mMapTools.mMoveFeature = new QgsMapToolMoveFeature(mMapCanvas);
mMapTools.mMoveFeature->setAction(mActionMoveFeature);
mMapTools.mSplitFeatures = new QgsMapToolSplitFeatures(mMapCanvas);
mMapTools.mSplitFeatures->setAction(mActionSplitFeatures);
mMapTools.mSelect = new QgsMapToolSelect(mMapCanvas);
mMapTools.mSelect->setAction(mActionSelect);
mMapTools.mVertexAdd = new QgsMapToolAddVertex(mMapCanvas);
mMapTools.mVertexAdd->setAction(mActionAddVertex);
mMapTools.mVertexMove = new QgsMapToolMoveVertex(mMapCanvas);
mMapTools.mVertexMove->setAction(mActionMoveVertex);
mMapTools.mVertexDelete = new QgsMapToolDeleteVertex(mMapCanvas);
mMapTools.mVertexDelete->setAction(mActionDeleteVertex);
mMapTools.mAddRing = new QgsMapToolAddRing(mMapCanvas);
mMapTools.mAddRing->setAction(mActionAddRing);
mMapTools.mAddIsland = new QgsMapToolAddIsland(mMapCanvas);
//ensure that non edit tool is initialised or we will get crashes in some situations
mNonEditMapTool = mMapTools.mPan;
}
void QgisApp::createOverview()
{
// overview canvas
QgsMapOverviewCanvas* overviewCanvas = new QgsMapOverviewCanvas(NULL, mMapCanvas);
overviewCanvas->setWhatsThis(tr("Map overview canvas. This canvas can be used to display a locator map that shows the current extent of the map canvas. The current extent is shown as a red rectangle. Any layer on the map can be added to the overview canvas."));
QBitmap overviewPanBmp = QBitmap::fromData(QSize(16, 16), pan_bits);
QBitmap overviewPanBmpMask = QBitmap::fromData(QSize(16, 16), pan_mask_bits);
mOverviewMapCursor = new QCursor(overviewPanBmp, overviewPanBmpMask, 5, 5);
overviewCanvas->setCursor(*mOverviewMapCursor);
// QVBoxLayout *myOverviewLayout = new QVBoxLayout;
// myOverviewLayout->addWidget(overviewCanvas);
// overviewFrame->setLayout(myOverviewLayout);
mOverviewDock = new QDockWidget(tr("Overview"), this);
mOverviewDock->setObjectName("Overview");
mOverviewDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
mOverviewDock->setWidget(overviewCanvas);
addDockWidget(Qt::LeftDockWidgetArea, mOverviewDock);
mMapCanvas->setOverview(overviewCanvas);
// moved here to set anti aliasing to both map canvas and overview
QSettings mySettings;
mMapCanvas->enableAntiAliasing(mySettings.value("/qgis/enable_anti_aliasing",false).toBool());
mMapCanvas->useQImageToRender(mySettings.value("/qgis/use_qimage_to_render",false).toBool());
int action = mySettings.value("/qgis/wheel_action", 0).toInt();
double zoomFactor = mySettings.value("/qgis/zoom_factor", 2).toDouble();
mMapCanvas->setWheelAction((QgsMapCanvas::WheelAction) action, zoomFactor);
}
void QgisApp::addDockWidget ( Qt::DockWidgetArea theArea, QDockWidget * thepDockWidget )
{
QMainWindow::addDockWidget ( theArea, thepDockWidget );
// Make the right and left docks consume all vertical space and top
// and bottom docks nest between them
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
// add to the view menu
mViewMenu->addAction(thepDockWidget->toggleViewAction());
}
void QgisApp::createLegend()
{
//legend
mMapLegend = new QgsLegend(NULL, "theMapLegend");
mMapLegend->setObjectName("theMapLegend");
mMapLegend->setMapCanvas(mMapCanvas);
//add the toggle editing action also to legend such that right click menu and button show the same state
mMapLegend->setToggleEditingAction(mActionToggleEditing);
mMapLegend->setWhatsThis(tr("Map legend that displays all the layers currently on the map canvas. Click on the check box to turn a layer on or off. Double click on a layer in the legend to customize its appearance and set other properties."));
mLegendDock = new QDockWidget(tr("Legend"), this);
mLegendDock->setObjectName("Legend");
mLegendDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
mLegendDock->setWidget(mMapLegend);
addDockWidget(Qt::LeftDockWidgetArea, mLegendDock);
return;
}
bool QgisApp::createDB()
{
// Check qgis.db and make private copy if necessary
QFile qgisPrivateDbFile(QgsApplication::qgisUserDbFilePath());
// first we look for ~/.qgis/qgis.db
if (!qgisPrivateDbFile.exists())
{
// if it doesnt exist we copy it in from the global resources dir
QString qgisMasterDbFileName = QgsApplication::qgisMasterDbFilePath();
QFile masterFile(qgisMasterDbFileName);
// Must be sure there is destination directory ~/.qgis
QDir().mkpath(QgsApplication::qgisSettingsDirPath());
//now copy the master file into the users .qgis dir
bool isDbFileCopied = masterFile.copy(qgisPrivateDbFile.fileName());
if (!isDbFileCopied)
{
QgsDebugMsg("[ERROR] Can not make qgis.db private copy");
return FALSE;
}
}
return TRUE;
}
void QgisApp::createMapTips()
{
// Set up the timer for maptips. The timer is reset everytime the mouse is moved
mpMapTipsTimer = new QTimer ( mMapCanvas );
// connect the timer to the maptips slot
connect ( mpMapTipsTimer, SIGNAL ( timeout() ), this, SLOT ( showMapTip() ) );
// set the interval to 0.850 seconds - timer will be started next time the mouse moves
mpMapTipsTimer->setInterval ( 850 );
// Create the maptips object
mpMaptip = new QgsMapTip ();
}
// Update file menu with the current list of recently accessed projects
void QgisApp::updateRecentProjectPaths()
{
// Remove existing paths from the recent projects menu
int i;
int menusize = mRecentProjectsMenu->actions().size();
for(i = menusize; i < mRecentProjectPaths.size(); i++)
{
mRecentProjectsMenu->addAction("Dummy text");
}
QList<QAction *> menulist = mRecentProjectsMenu->actions();
assert(menulist.size() == mRecentProjectPaths.size());
for (i = 0; i < mRecentProjectPaths.size(); i++)
{
menulist.at(i)->setText(mRecentProjectPaths.at(i));
// Disable this menu item if the file has been removed, if not enable it
menulist.at(i)->setEnabled(QFile::exists((mRecentProjectPaths.at(i))));
}
} // QgisApp::updateRecentProjectPaths
// add this file to the recently opened/saved projects list
void QgisApp::saveRecentProjectPath(QString projectPath, QSettings & settings)
{
// Get canonical absolute path
QFileInfo myFileInfo(projectPath);
projectPath = myFileInfo.absoluteFilePath();
// If this file is already in the list, remove it
mRecentProjectPaths.removeAll(projectPath);
// Prepend this file to the list
mRecentProjectPaths.prepend(projectPath);
// Keep the list to 8 items by trimming excess off the bottom
while (mRecentProjectPaths.count() > 8)
{
mRecentProjectPaths.pop_back();
}
// Persist the list
settings.setValue("/UI/recentProjectsList", mRecentProjectPaths);
// Update menu list of paths
updateRecentProjectPaths();
} // QgisApp::saveRecentProjectPath
void QgisApp::saveWindowState()
{
// store window and toolbar positions
QSettings settings;
// store the toolbar/dock widget settings using Qt4 settings API
settings.setValue("/UI/state", this->saveState());
// store window geometry
settings.setValue("/UI/geometry", saveGeometry());
}
void QgisApp::restoreWindowState()
{
// restore the toolbar and dock widgets postions using Qt4 settings API
QSettings settings;
QVariant vstate = settings.value("/UI/state");
this->restoreState(vstate.toByteArray());
// restore window geometry
restoreGeometry(settings.value("/UI/geometry").toByteArray());
}
///////////// END OF GUI SETUP ROUTINES ///////////////
void QgisApp::about()
{
static QgsAbout *abt = NULL;
if (!abt) {
QApplication::setOverrideCursor(Qt::WaitCursor);
abt = new QgsAbout();
QString versionString = tr("You are using QGIS version %1 built against code revision %2.")
.arg(QGis::qgisVersion)
.arg(QGis::qgisSvnVersion);
#ifdef HAVE_POSTGRESQL
versionString += tr(" This copy of QGIS has been built with PostgreSQL support.");
#else
versionString += tr(" This copy of QGIS has been built without PostgreSQL support.");
#endif
versionString += tr("\nThis binary was compiled against Qt %1,"
"and is currently running against Qt %2")
.arg(QT_VERSION_STR)
.arg(qVersion());
#ifdef WIN32
// special version stuff for windows (if required)
// versionString += "\nThis is a Windows preview release - not for production use";
#endif
abt->setVersion(versionString);
QString whatsNew = "<html><body>" + tr("Version") + " ";
whatsNew += QGis::qgisVersion;
whatsNew += "<h3>" + tr("New features") + "</h3>" +
tr("This release candidate includes over 60 bug fixes and enchancements "
"over the QGIS 0.10.0 release. In addition we have added "
"the following new features:");
whatsNew += "<ul><li>"
+ tr("Revision of all dialogs for user interface consistancy")
+ "</li>"
+ "<li>"
+ tr("Improvements to unique value renderer vector dialog")
+ "</li>"
+ "<li>"
+ tr("Symbol previews when defining vector classes")
+ "</li>"
+ "<li>"
+ tr("Separation of python support into its own library")
+ "</li>"
+ "<li>"
+ tr("List view and filter for GRASS toolbox to find tools more quickly")
+ "</li>"
+ "<li>"
+ tr("List view and filter for Plugin Manager to find plugins more easily")
+ "</li>"
+ "<li>"
+ tr("Updated Spatial Reference System definitions")
+ "</li>"
+ "<li>"
+ tr("QML Style support for rasters and database layers")
+ "</li>"
//+ "<li>"
//+ tr("X")
//+ "</li>"
+ "</ul></body></html>";
abt->setWhatsNew(whatsNew);
QApplication::restoreOverrideCursor();
}
abt->show();
abt->raise();
abt->activateWindow();
}
/** Load up any plugins used in the last session
*/
void QgisApp::restoreSessionPlugins(QString thePluginDirString)
{
QSettings mySettings;
#ifdef WIN32
QString pluginExt = "*.dll";
#else
QString pluginExt = "*.so*";
#endif
// check all libs in the current plugin directory and get name and descriptions
QDir myPluginDir(thePluginDirString, pluginExt, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);
for (uint i = 0; i < myPluginDir.count(); i++)
{
QString myFullPath = thePluginDirString + "/" + myPluginDir[i];
QLibrary *myLib = new QLibrary(myFullPath);
bool loaded = myLib->load();
if (loaded)
{
name_t * myName =(name_t *) cast_to_fptr(myLib->resolve("name"));
description_t * myDescription = (description_t *) cast_to_fptr(myLib->resolve("description"));
version_t * myVersion = (version_t *) cast_to_fptr(myLib->resolve("version"));
if (myName && myDescription && myVersion )
{
//check if the plugin was active on last session
QString myEntryName = myName();
// Windows stores a "true" value as a 1 in the registry so we
// have to use readBoolEntry in this function
if (mySettings.value("/Plugins/" + myEntryName).toBool())
{
//QgsDebugMsg("Loading plugin: " + myEntryName);
loadPlugin(myName(), myDescription(), myFullPath);
}
else
{
//QgsDebugMsg("Plugin was not active last session, leaving disabled: " + myEntryName);
}
}
else
{
//QgsDebugMsg("Failed to get name, description, or type for " + myLib->fileName());
}
}
else
{
//QgsDebugMsg("Failed to load " + myLib->fileName());
//QgsDebugMsg("Reason: " + myLib->errorString());
}
delete myLib;
}
QString pluginName, description, version;
if (mPythonUtils && mPythonUtils->isEnabled())
{
// check for python plugins system-wide
QStringList pluginList = mPythonUtils->pluginList();
std::cout << "Loading python plugins" << std::endl;
for (int i = 0; i < pluginList.size(); i++)
{
QString packageName = pluginList[i];
// import plugin's package
if (!mPythonUtils->loadPlugin(packageName))
continue;
// get information from the plugin
// if there are some problems, don't continue with metadata retreival
pluginName = mPythonUtils->getPluginMetadata(packageName, "name");
if (pluginName != "__error__")
{
description = mPythonUtils->getPluginMetadata(packageName, "description");
if (description != "__error__")
version = mPythonUtils->getPluginMetadata(packageName, "version");
}
if (pluginName == "__error__" || description == "__error__" || version == "__error__")
{
QMessageBox::warning(this, tr("Python error"), tr("Error when reading metadata of plugin ") + packageName);
continue;
}
if (mySettings.value("/PythonPlugins/" + packageName).toBool())
{
loadPythonPlugin(packageName, pluginName);
}
}
}
std::cout << "Plugin loading completed";
}
/**
Convenience function for readily creating file filters.
Given a long name for a file filter and a regular expression, return
a file filter string suitable for use in a QFileDialog::OpenFiles()
call. The regular express, glob, will have both all lower and upper
case versions added.
*/
static QString createFileFilter_(QString const &longName, QString const &glob)
{
return longName + " (" + glob.toLower() + " " + glob.toUpper() + ");;";
} // createFileFilter_
/**
Builds the list of file filter strings to later be used by
QgisApp::addVectorLayer()
We query OGR for a list of supported vector formats; we then build a list
of file filter strings from that list. We return a string that contains
this list that is suitable for use in a a QFileDialog::getOpenFileNames()
call.
XXX Most of the file name filters need to be filled in; however we
XXX may want to wait until we've tested each format before committing
XXX them permanently instead of blindly relying on OGR to properly
XXX supply all needed spatial data.
*/
static void buildSupportedVectorFileFilter_(QString & fileFilters)
{
#ifdef DEPRECATED
static QString myFileFilters;
// if we've already built the supported vector string, just return what
// we've already built
if ( ! ( myFileFilters.isEmpty() || myFileFilters.isNull() ) )
{
fileFilters = myFileFilters;
return;
}
// then iterate through all of the supported drivers, adding the
// corresponding file filter
OGRSFDriverH driver; // current driver
QString driverName; // current driver name
// Grind through all the drivers and their respective metadata.
// We'll add a file filter for those drivers that have a file
// extension defined for them; the others, welll, even though
// theoreticaly we can open those files because there exists a
// driver for them, the user will have to use the "All Files" to
// open datasets with no explicitly defined file name extension.
QgsDebugMsg("Driver count: " + QString::number(driverRegistrar->GetDriverCount()));
for (int i = 0; i < OGRGetDriverCount(); ++i)
{
driver = OGRGetDriver(i);
Q_CHECK_PTR(driver);
if (!driver)
{
qWarning("unable to get driver %d", i);
continue;
}
driverName = OGR_Dr_GetName(driver);
if (driverName.startsWith("ESRI"))
{
myFileFilters += createFileFilter_("ESRI Shapefiles", "*.shp");
}
else if (driverName.startsWith("UK"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("SDTS"))
{
myFileFilters += createFileFilter_( "Spatial Data Transfer Standard",
"*catd.ddf" );
}
else if (driverName.startsWith("TIGER"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("S57"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("MapInfo"))
{
myFileFilters += createFileFilter_("MapInfo", "*.mif *.tab");
// XXX needs file filter extension
}
else if (driverName.startsWith("DGN"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("VRT"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("AVCBin"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("REC"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("Memory"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("Jis"))
{
// XXX needs file filter extension
}
else if (driverName.startsWith("GML"))
{
// XXX not yet supported; post 0.1 release task
myFileFilters += createFileFilter_( "Geography Markup Language",
"*.gml" );
}
else
{
// NOP, we don't know anything about the current driver
// with regards to a proper file filter string
QgsDebugMsg("unknown driver " + driverName );
}
} // each loaded GDAL driver
std::cout << myFileFilters.toLocal8Bit().data() << std::endl;
// can't forget the default case
myFileFilters += "All files (*.*)";
fileFilters = myFileFilters;
#endif // DEPRECATED
fileFilters = QgsProviderRegistry::instance()->fileVectorFilters();
//QgsDebugMsg("Vector file filters: " + fileFilters);
} // buildSupportedVectorFileFilter_()
/**
Open files, preferring to have the default file selector be the
last one used, if any; also, prefer to start in the last directory
associated with filterName.
@param filterName the name of the filter; used for persistent store
key
@param filters the file filters used for QFileDialog
@param selectedFiles string list of selected files; will be empty
if none selected
@param enc encoding?
@param title the title for the dialog
@note
Stores persistent settings under /UI/. The sub-keys will be
filterName and filterName + "Dir".
Opens dialog on last directory associated with the filter name, or
the current working directory if this is the first time invoked
with the current filter name.
*/
static void openFilesRememberingFilter_(QString const &filterName,
QString const &filters, QStringList & selectedFiles, QString& enc, QString &title)
{
bool haveLastUsedFilter = false; // by default, there is no last
// used filter
QSettings settings; // where we keep last used filter in
// persistant state
haveLastUsedFilter = settings.contains("/UI/" + filterName);
QString lastUsedFilter = settings.value("/UI/" + filterName,
QVariant(QString::null)).toString();
QString lastUsedDir = settings.value("/UI/" + filterName + "Dir",".").toString();
QString lastUsedEncoding = settings.value("/UI/encoding").toString();
QgsDebugMsg("Opening file dialog with filters: " + filters);
QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog(0,
title, lastUsedDir, filters, lastUsedEncoding);
// allow for selection of more than one file
openFileDialog->setFileMode(QFileDialog::ExistingFiles);
if (haveLastUsedFilter) // set the filter to the last one used
{
openFileDialog->selectFilter(lastUsedFilter);
}
if (openFileDialog->exec() == QDialog::Accepted)
{
selectedFiles = openFileDialog->selectedFiles();
enc = openFileDialog->encoding();
// Fix by Tim - getting the dirPath from the dialog
// directly truncates the last node in the dir path.
// This is a workaround for that
QString myFirstFileName = selectedFiles.first();
QFileInfo myFI(myFirstFileName);
QString myPath = myFI.path();
QgsDebugMsg("Writing last used dir: " + myPath);
settings.setValue("/UI/" + filterName, openFileDialog->selectedFilter());
settings.setValue("/UI/" + filterName + "Dir", myPath);
settings.setValue("/UI/encoding", openFileDialog->encoding());
}
delete openFileDialog;
} // openFilesRememberingFilter_
/**
This method prompts the user for a list of vector filenames with a dialog.
*/
void QgisApp::addVectorLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->freeze();
QStringList selectedFiles;
QgsDebugMsg("Vector file filters: " + mVectorFileFilter);
QString enc;
QString title = tr("Open an OGR Supported Vector Layer");
openFilesRememberingFilter_("lastVectorFileFilter", mVectorFileFilter, selectedFiles, enc,
title);
if (selectedFiles.isEmpty())
{
// no files were selected, so just bail
mMapCanvas->freeze(false);
return;
}
addVectorLayers(selectedFiles, enc);
}
bool QgisApp::addVectorLayers(QStringList const & theLayerQStringList, const QString& enc)
{
for ( QStringList::ConstIterator it = theLayerQStringList.begin();
it != theLayerQStringList.end();
++it )
{
QFileInfo fi(*it);
QString base = fi.completeBaseName();
QgsDebugMsg("completeBaseName: "+base);
// create the layer
QgsVectorLayer *layer = new QgsVectorLayer(*it, base, "ogr");
Q_CHECK_PTR( layer );
if ( ! layer )
{
mMapCanvas->freeze(false);
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
// XXX insert meaningful whine to the user here
return false;
}
if (layer->isValid())
{
layer->setProviderEncoding(enc);
// Register this layer with the layers registry
QgsMapLayerRegistry::instance()->addMapLayer(layer);
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
else
{
QString msg = *it + " ";
msg += tr("is not a valid or recognized data source");
QMessageBox::critical(this, tr("Invalid Data Source"), msg);
// since the layer is bad, stomp on it
delete layer;
// XXX should we return false here, or just grind through
// XXX the remaining arguments?
}
}
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze(false);
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
statusBar()->showMessage(mMapCanvas->extent().toString(2));
return true;
} // QgisApp::addVectorLayer()
/** This helper checks to see whether the filename appears to be a valid vector file name */
bool QgisApp::isValidVectorFileName(QString theFileNameQString)
{
return (theFileNameQString.toLower().endsWith(".shp"));
}
/** Overloaded of the above function provided for convenience that takes a qstring pointer */
bool QgisApp::isValidVectorFileName(QString * theFileNameQString)
{
//dereference and delegate
return isValidVectorFileName(*theFileNameQString);
}
#ifndef HAVE_POSTGRESQL
void QgisApp::addDatabaseLayer(){}
#else
void QgisApp::addDatabaseLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// only supports postgis layers at present
// show the postgis dialog
QgsDbSourceSelect *dbs = new QgsDbSourceSelect(this);
mMapCanvas->freeze();
if (dbs->exec())
{
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
// repaint the canvas if it was covered by the dialog
// add files to the map canvas
QStringList tables = dbs->selectedTables();
QApplication::setOverrideCursor(Qt::WaitCursor);
QString connInfo = dbs->connInfo();
// for each selected table, connect to the database, parse the WKT geometry,
// and build a canvasitem for it
// readWKB(connInfo,tables);
QStringList::Iterator it = tables.begin();
while (it != tables.end())
{
// create the layer
//qWarning("creating layer");
QgsVectorLayer *layer = new QgsVectorLayer(connInfo + " table=" + *it, *it, "postgres");
if (layer->isValid())
{
// register this layer with the central layers registry
QgsMapLayerRegistry::instance()->addMapLayer(layer);
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
else
{
QgsDebugMsg( (*it) + " is an invalid layer - not loaded");
QMessageBox::critical(this, tr("Invalid Layer"), tr("%1 is an invalid layer and cannot be loaded.").arg(*it));
delete layer;
}
//qWarning("incrementing iterator");
++it;
}
QApplication::restoreOverrideCursor();
statusBar()->showMessage(mMapCanvas->extent().toString(2));
}
delete dbs;
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze(false);
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
} // QgisApp::addDatabaseLayer()
#endif
void QgisApp::addWmsLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// Fudge for now
QgsDebugMsg("about to addRasterLayer");
QgsServerSourceSelect *wmss = new QgsServerSourceSelect(this);
if (wmss->exec())
{
addRasterLayer(wmss->connInfo(),
wmss->connName(),
"wms",
wmss->selectedLayers(),
wmss->selectedStylesForSelectedLayers(),
wmss->selectedImageEncoding(),
wmss->selectedCrs());
}
}
/// file data representation
enum dataType { IS_VECTOR, IS_RASTER, IS_BOGUS };
/** returns data type associated with the given QgsProject file Dom node
The Dom node should represent the state associated with a specific layer.
*/
static
dataType
dataType_( QDomNode & layerNode )
{
QString type = layerNode.toElement().attribute( "type" );
if ( QString::null == type )
{
QgsDebugMsg("cannot find ``type'' attribute");
return IS_BOGUS;
}
if ( "raster" == type )
{
QgsDebugMsg("is a raster");
return IS_RASTER;
}
else if ( "vector" == type )
{
QgsDebugMsg("is a vector");
return IS_VECTOR;
}
QgsDebugMsg("is unknown type " + type);
return IS_BOGUS;
} // dataType_( QDomNode & layerNode )
/** return the data source for the given layer
The QDomNode is a QgsProject Dom node corresponding to a map layer state.
Essentially dumps <datasource> tag.
*/
static
QString
dataSource_( QDomNode & layerNode )
{
QDomNode dataSourceNode = layerNode.namedItem( "datasource" );
if ( dataSourceNode.isNull() )
{
QgsDebugMsg("cannot find datasource node");
return QString::null;
}
return dataSourceNode.toElement().text();
} // dataSource_( QDomNode & layerNode )
/// the three flavors for data
typedef enum { IS_FILE, IS_DATABASE, IS_URL, IS_UNKNOWN } providerType;
/** return the physical storage type associated with the given layer
The QDomNode is a QgsProject Dom node corresponding to a map layer state.
If the <provider> is "ogr", then it's a file type.
However, if the layer is a raster, then there won't be a <provider> tag. It
will always have an associated file.
If the layer doesn't fall into either of the previous two categories, then
it's either a database or URL. If the <datasource> tag has "url=", then
it's URL based. If the <datasource> tag has "dbname=">, then the layer data
is in a database.
*/
static
providerType
providerType_( QDomNode & layerNode )
{
// XXX but what about rasters that can be URLs? _Can_ they be URLs?
switch( dataType_( layerNode ) )
{
case IS_VECTOR:
{
QString dataSource = dataSource_( layerNode );
QgsDebugMsg("datasource is " + dataSource);
if ( dataSource.contains("host=") )
{
return IS_URL;
}
#ifdef HAVE_POSTGRESQL
else if ( dataSource.contains("dbname=") )
{
return IS_DATABASE;
}
#endif
// be default, then, this should be a file based layer data source
// XXX is this a reasonable assumption?
return IS_FILE;
}
case IS_RASTER: // rasters are currently only accessed as
// physical files
return IS_FILE;
default:
QgsDebugMsg("unknown ``type'' attribute");
}
return IS_UNKNOWN;
} // providerType_
/** set the <datasource> to the new value
*/
static
void
setDataSource_( QDomNode & layerNode, QString const & dataSource )
{
QDomNode dataSourceNode = layerNode.namedItem("datasource");
QDomElement dataSourceElement = dataSourceNode.toElement();
QDomText dataSourceText = dataSourceElement.firstChild().toText();
QgsDebugMsg("datasource changed from " + dataSourceText.data() );
dataSourceText.setData( dataSource );
QgsDebugMsg("to " + dataSourceText.data() );
} // setDataSource_
/** this is used to locate files that have moved or otherwise are missing
*/
static
void
findMissingFile_( QString const & fileFilters, QDomNode & layerNode )
{
// Prepend that file name to the valid file format filter list since it
// makes it easier for the user to not only find the original file, but to
// perhaps find a similar file.
QFileInfo originalDataSource( dataSource_(layerNode) );
QString memoryQualifier; // to differentiate between last raster and
// vector directories
switch( dataType_( layerNode ) )
{
case IS_VECTOR:
{
memoryQualifier = "lastVectorFileFilter";
break;
}
case IS_RASTER:
{
memoryQualifier = "lastRasterFileFilter";
break;
}
default:
QgsDebugMsg("unable to determine data type");
return;
}
// Prepend the original data source base name to make it easier to pick it
// out from a list of other files; however the appropriate filter strings
// for the file type will also be added in case the file name itself has
// changed, too.
QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters;
QStringList selectedFiles;
QString enc;
QString title( QObject::tr("Where is '") + originalDataSource.fileName() + "'? (" + QObject::tr("original location: ") + originalDataSource.absoluteFilePath() + ")");
openFilesRememberingFilter_(memoryQualifier,
myFileFilters,
selectedFiles,
enc,
title);
if (selectedFiles.isEmpty())
{
return;
}
else
{
setDataSource_( layerNode, selectedFiles.first() );
if ( ! QgsProject::instance()->read( layerNode ) )
{
QgsDebugMsg("unable to re-read layer");
}
}
} // findMissingFile_
/** find relocated data source for the given layer
This QDom object represents a QgsProject node that maps to a specific layer.
@param layerNode QDom node containing layer project information
@todo
XXX Only implemented for file based layers. It will need to be extended for
XXX other data source types such as databases.
*/
static
void
findLayer_( QString const & fileFilters, QDomNode const & constLayerNode )
{
// XXX actually we could possibly get away with a copy of the node
QDomNode & layerNode = const_cast<QDomNode&>(constLayerNode);
switch ( providerType_(layerNode) )
{
case IS_FILE:
QgsDebugMsg("layer is file based");
findMissingFile_( fileFilters, layerNode );
break;
case IS_DATABASE:
QgsDebugMsg("layer is database based");
break;
case IS_URL:
QgsDebugMsg("layer is URL based");
break;
case IS_UNKNOWN:
QgsDebugMsg("layer has an unkown type");
break;
}
} // findLayer_
/** find relocated data sources for given layers
These QDom objects represent QgsProject nodes that map to specific layers.
*/
static
void
findLayers_( QString const & fileFilters, list<QDomNode> const & layerNodes )
{
for( list<QDomNode>::const_iterator i = layerNodes.begin();
i != layerNodes.end();
++i )
{
findLayer_( fileFilters, *i );
}
} // findLayers_
void QgisApp::fileExit()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
if (saveDirty())
{
removeAllLayers();
qApp->exit(0);
}
}
void QgisApp::fileNew()
{
fileNew(TRUE); // prompts whether to save project
} // fileNew()
//as file new but accepts flags to indicate whether we should prompt to save
void QgisApp::fileNew(bool thePromptToSaveFlag)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
if (thePromptToSaveFlag)
{
if (!saveDirty())
{
return;
}
}
//QgsDebugMsg("erasing project");
mMapCanvas->freeze(true);
QgsMapLayerRegistry::instance()->removeAllMapLayers();
mMapCanvas->clear();
delete mComposer;
mComposer = new QgsComposer(this);
QgsProject* prj = QgsProject::instance();
prj->title( QString::null );
prj->setFilename( QString::null );
prj->clearProperties(); // why carry over properties from previous projects?
QSettings settings;
//set the colour for selections
//the default can be set in qgisoptions
//use project properties to override the colour on a per project basis
int myRed = settings.value("/qgis/default_selection_color_red",255).toInt();
int myGreen = settings.value("/qgis/default_selection_color_green",255).toInt();
int myBlue = settings.value("/qgis/default_selection_color_blue",0).toInt();
prj->writeEntry("Gui","/SelectionColorRedPart",myRed);
prj->writeEntry("Gui","/SelectionColorGreenPart",myGreen);
prj->writeEntry("Gui","/SelectionColorBluePart",myBlue);
QgsRenderer::setSelectionColor(QColor(myRed,myGreen,myBlue));
//set the canvas to the default background colour
//the default can be set in qgisoptions
//use project properties to override the colour on a per project basis
myRed = settings.value("/qgis/default_canvas_color_red",255).toInt();
myGreen = settings.value("/qgis/default_canvas_color_green",255).toInt();
myBlue = settings.value("/qgis/default_canvas_color_blue",255).toInt();
prj->writeEntry("Gui","/CanvasColorRedPart",myRed);
prj->writeEntry("Gui","/CanvasColorGreenPart",myGreen);
prj->writeEntry("Gui","/CanvasColorBluePart",myBlue);
mMapCanvas->setCanvasColor(QColor(myRed,myGreen,myBlue));
prj->dirty(false);
setTitleBarText_( *this );
//QgsDebugMsg("emiting new project signal");
//emit signal so QgsComposer knows we have a new project
emit newProject();
mMapCanvas->freeze(false);
mMapCanvas->refresh();
mMapCanvas->mapRenderer()->setProjectionsEnabled(FALSE);
// set the initial map tool
mMapCanvas->setMapTool(mMapTools.mPan);
mNonEditMapTool = mMapTools.mPan; // signals are not yet setup to catch this
} // QgisApp::fileNew(bool thePromptToSaveFlag)
void QgisApp::newVectorLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QGis::WKBTYPE geometrytype;
QString fileformat;
QgsGeomTypeDialog geomDialog(this);
if(geomDialog.exec()==QDialog::Rejected)
{
return;
}
geometrytype = geomDialog.selectedType();
fileformat = geomDialog.selectedFileFormat();
std::list<std::pair<QString, QString> > attributes;
geomDialog.attributes(attributes);
bool haveLastUsedFilter = false; // by default, there is no last
// used filter
QString enc;
QString filename;
QSettings settings; // where we keep last used filter in
// persistant state
haveLastUsedFilter = settings.contains("/UI/lastVectorFileFilter");
QString lastUsedFilter = settings.value("/UI/lastVectorFileFilter",
QVariant(QString::null)).toString();
QString lastUsedDir = settings.value("/UI/lastVectorFileFilterDir",
".").toString();
QString lastUsedEncoding = settings.value("/UI/encoding").toString();
QgsDebugMsg("Saving vector file dialog without filters: ");
QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog(this,
tr("Save As"), lastUsedDir, "", lastUsedEncoding);
// allow for selection of more than one file
openFileDialog->setFileMode(QFileDialog::AnyFile);
openFileDialog->setAcceptMode(QFileDialog::AcceptSave);
openFileDialog->setConfirmOverwrite( true );
if (haveLastUsedFilter) // set the filter to the last one used
{
openFileDialog->selectFilter(lastUsedFilter);
}
if (openFileDialog->exec() != QDialog::Accepted)
{
delete openFileDialog;
return;
}
filename = openFileDialog->selectedFiles().first();
enc = openFileDialog->encoding();
// If the file exists, delete it otherwise we'll end up loading that
// file, which can cause problems (e.g., if the file contains
// linestrings, but we're wanting to create points, we'll end up
// with a linestring file).
QFile::remove(filename);
settings.setValue("/UI/lastVectorFileFilter", openFileDialog->selectedFilter());
settings.setValue("/UI/lastVectorFileFilterDir", openFileDialog->directory().absolutePath());
settings.setValue("/UI/encoding", openFileDialog->encoding());
delete openFileDialog;
//try to create the new layer with OGRProvider instead of QgsVectorFileWriter
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
QString ogrlib = pReg->library("ogr");
// load the data provider
QLibrary* myLib = new QLibrary(ogrlib);
bool loaded = myLib->load();
if (loaded)
{
QgsDebugMsg("ogr provider loaded");
typedef bool (*createEmptyDataSourceProc)(const QString&, const QString&, const QString&, QGis::WKBTYPE, \
const std::list<std::pair<QString, QString> >&);
createEmptyDataSourceProc createEmptyDataSource=(createEmptyDataSourceProc) cast_to_fptr(myLib->resolve("createEmptyDataSource"));
if(createEmptyDataSource)
{
#if 0
if(geometrytype == QGis::WKBPoint)
{
createEmptyDataSource(filename,fileformat, enc, QGis::WKBPoint, attributes);
}
else if (geometrytype == QGis::WKBLineString)
{
createEmptyDataSource(filename,fileformat, enc, QGis::WKBLineString, attributes);
}
else if(geometrytype == QGis::WKBPolygon)
{
createEmptyDataSource(filename,fileformat, enc, QGis::WKBPolygon, attributes);
}
#endif
if(geometrytype != QGis::WKBUnknown)
{
createEmptyDataSource(filename,fileformat, enc, geometrytype, attributes);
}
else
{
QgsDebugMsg("geometry type not recognised");
return;
}
}
else
{
QgsDebugMsg("Resolving newEmptyDataSource(...) failed");
}
}
//then add the layer to the view
QStringList filenames;
filenames.append(filename);
addVectorLayers(filenames, enc);
}
void QgisApp::fileOpen()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// possibly save any pending work before opening a new project
if (saveDirty())
{
// Retrieve last used project dir from persistent settings
QSettings settings;
QString lastUsedDir = settings.value("/UI/lastProjectDir", ".").toString();
QFileDialog * openFileDialog = new QFileDialog(this,
tr("Choose a QGIS project file to open"),
lastUsedDir, QObject::tr("QGis files (*.qgs)"));
openFileDialog->setFileMode(QFileDialog::ExistingFile);
QString fullPath;
if (openFileDialog->exec() == QDialog::Accepted)
{
// Fix by Tim - getting the dirPath from the dialog
// directly truncates the last node in the dir path.
// This is a workaround for that
fullPath = openFileDialog->selectedFiles().first();
QFileInfo myFI(fullPath);
QString myPath = myFI.path();
// Persist last used project dir
settings.setValue("/UI/lastProjectDir", myPath);
}
else
{
// if they didn't select anything, just return
delete openFileDialog;
return;
}
delete openFileDialog;
// clear out any stuff from previous project
mMapCanvas->freeze(true);
removeAllLayers();
delete mComposer;
mComposer = new QgsComposer(this);
QgsProject::instance()->setFilename( fullPath );
try
{
if ( QgsProject::instance()->read() )
{
setTitleBarText_( *this );
emit projectRead(); // let plug-ins know that we've read in a new
// project so that they can check any project
// specific plug-in state
// add this to the list of recently used project files
saveRecentProjectPath(fullPath, settings);
}
}
catch ( QgsProjectBadLayerException & e )
{
QMessageBox::critical(this,
tr("QGIS Project Read Error"),
tr("") + "\n" + QString::fromLocal8Bit( e.what() ) );
QgsDebugMsg( QString("%1 bad layers found").arg(e.layers().size()) );
// attempt to find the new locations for missing layers
// XXX vector file hard-coded -- but what if it's raster?
findLayers_( mVectorFileFilter, e.layers() );
}
catch ( std::exception & e )
{
QMessageBox::critical(this,
tr("QGIS Project Read Error"),
tr("") + "\n" + QString::fromLocal8Bit( e.what() ) );
QgsDebugMsg("BAD LAYERS FOUND");
}
mMapCanvas->freeze(false);
mMapCanvas->refresh();
}
} // QgisApp::fileOpen
/**
adds a saved project to qgis, usually called on startup by specifying a
project file on the command line
*/
bool QgisApp::addProject(QString projectFile)
{
mMapCanvas->freeze(true);
// clear the map canvas
removeAllLayers();
try
{
if ( QgsProject::instance()->read( projectFile ) )
{
setTitleBarText_( *this );
int myRedInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorRedPart",255);
int myGreenInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorGreenPart",255);
int myBlueInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorBluePart",255);
QColor myColor = QColor(myRedInt,myGreenInt,myBlueInt);
mMapCanvas->setCanvasColor(myColor); //this is fill colour before rendering starts
QgsDebugMsg("Canvas background color restored...");
emit projectRead(); // let plug-ins know that we've read in a new
// project so that they can check any project
// specific plug-in state
// add this to the list of recently used project files
QSettings settings;
saveRecentProjectPath(projectFile, settings);
}
else
{
mMapCanvas->freeze(false);
mMapCanvas->refresh();
return false;
}
}
catch ( QgsProjectBadLayerException & e )
{
QgsDebugMsg( QString("%1 bad layers found").arg( e.layers().size() ) );
if ( QMessageBox::Ok == QMessageBox::critical( this,
tr("QGIS Project Read Error"),
tr("") + "\n" + QString::fromLocal8Bit( e.what() ) + "\n" +
tr("Try to find missing layers?"),
QMessageBox::Ok | QMessageBox::Cancel ) )
{
QgsDebugMsg("want to find missing layers is true");
// attempt to find the new locations for missing layers
// XXX vector file hard-coded -- but what if it's raster?
findLayers_( mVectorFileFilter, e.layers() );
}
}
catch ( std::exception & e )
{
QgsDebugMsg("BAD LAYERS FOUND");
QMessageBox::critical( this,
tr("Unable to open project"), QString::fromLocal8Bit( e.what() ) );
mMapCanvas->freeze(false);
mMapCanvas->refresh();
return false;
}
mMapCanvas->freeze(false);
mMapCanvas->refresh();
return true;
} // QgisApp::addProject(QString projectFile)
bool QgisApp::fileSave()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return false;
}
// if we don't have a filename, then obviously we need to get one; note
// that the project file name is reset to null in fileNew()
QFileInfo fullPath;
// we need to remember if this is a new project so that we know to later
// update the "last project dir" settings; we know it's a new project if
// the current project file name is empty
bool isNewProject = false;
if ( QgsProject::instance()->fileName().isNull() )
{
isNewProject = true;
// Retrieve last used project dir from persistent settings
QSettings settings;
QString lastUsedDir = settings.value("/UI/lastProjectDir", ".").toString();
std::auto_ptr<QFileDialog> saveFileDialog( new QFileDialog(this,
tr("Choose a QGIS project file"),
lastUsedDir, QObject::tr("QGis files (*.qgs)")) );
saveFileDialog->setFileMode(QFileDialog::AnyFile);
saveFileDialog->setAcceptMode(QFileDialog::AcceptSave);
saveFileDialog->setConfirmOverwrite( true );
if (saveFileDialog->exec() == QDialog::Accepted)
{
fullPath.setFile( saveFileDialog->selectedFiles().first() );
}
else
{
// if they didn't select anything, just return
// delete saveFileDialog; auto_ptr auto destroys
return false;
}
// make sure we have the .qgs extension in the file name
if( "qgs" != fullPath.suffix() )
{
QString newFilePath = fullPath.filePath() + ".qgs";
fullPath.setFile( newFilePath );
}
QgsProject::instance()->setFilename( fullPath.filePath() );
}
try
{
if ( QgsProject::instance()->write() )
{
setTitleBarText_(*this); // update title bar
statusBar()->showMessage(tr("Saved project to:") + " " + QgsProject::instance()->fileName() );
if (isNewProject)
{
// add this to the list of recently used project files
QSettings settings;
saveRecentProjectPath(fullPath.filePath(), settings);
}
}
else
{
QMessageBox::critical(this,
tr("Unable to save project"),
tr("Unable to save project to ") + QgsProject::instance()->fileName() );
}
}
catch ( std::exception & e )
{
QMessageBox::critical( this,
tr("Unable to save project ") + QgsProject::instance()->fileName(),
QString::fromLocal8Bit( e.what() ) );
}
return true;
} // QgisApp::fileSave
void QgisApp::fileSaveAs()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// Retrieve last used project dir from persistent settings
QSettings settings;
QString lastUsedDir = settings.value("/UI/lastProjectDir", ".").toString();
auto_ptr<QFileDialog> saveFileDialog( new QFileDialog(this,
tr("Choose a filename to save the QGIS project file as"),
lastUsedDir, QObject::tr("QGis files (*.qgs)")) );
saveFileDialog->setFileMode(QFileDialog::AnyFile);
saveFileDialog->setAcceptMode(QFileDialog::AcceptSave);
saveFileDialog->setConfirmOverwrite( true );
// if we don't have a filename, then obviously we need to get one; note
// that the project file name is reset to null in fileNew()
QFileInfo fullPath;
if (saveFileDialog->exec() == QDialog::Accepted)
{
// Fix by Tim - getting the dirPath from the dialog
// directly truncates the last node in the dir path.
// This is a workaround for that
fullPath.setFile(saveFileDialog->selectedFiles().first());
QString myPath = fullPath.path();
// Persist last used project dir
settings.setValue("/UI/lastProjectDir", myPath);
}
else
{
// if they didn't select anything, just return
// delete saveFileDialog; auto_ptr auto deletes
return;
}
// make sure the .qgs extension is included in the path name. if not, add it...
if( "qgs" != fullPath.suffix() )
{
QString newFilePath = fullPath.filePath() + ".qgs";
fullPath.setFile( newFilePath );
}
try
{
QgsProject::instance()->setFilename( fullPath.filePath() );
if ( QgsProject::instance()->write() )
{
setTitleBarText_(*this); // update title bar
statusBar()->showMessage(tr("Saved project to:") + " " + QgsProject::instance()->fileName() );
// add this to the list of recently used project files
saveRecentProjectPath(fullPath.filePath(), settings);
}
else
{
QMessageBox::critical(this,
tr("Unable to save project"),
tr("Unable to save project to ") + QgsProject::instance()->fileName() );
}
}
catch ( std::exception & e )
{
QMessageBox::critical( 0x0,
tr("Unable to save project ") + QgsProject::instance()->fileName(),
QString::fromLocal8Bit( e.what() ),
QMessageBox::Ok,
Qt::NoButton );
}
} // QgisApp::fileSaveAs
// Open the project file corresponding to the
// path at the given index in mRecentProjectPaths
void QgisApp::openProject(QAction *action)
{
// possibly save any pending work before opening a different project
QString debugme;
assert(action != NULL);
debugme = action->text();
if (saveDirty())
{
addProject(debugme);
}
//set the projections enabled icon in the status bar
int myProjectionEnabledFlag =
QgsProject::instance()->readNumEntry("SpatialRefSys","/ProjectionsEnabled",0);
mMapCanvas->mapRenderer()->setProjectionsEnabled(myProjectionEnabledFlag);
} // QgisApp::openProject
/**
Open the specified project file; prompt to save previous project if necessary.
Used to process a commandline argument or OpenDocument AppleEvent.
*/
void QgisApp::openProject(const QString & fileName)
{
// possibly save any pending work before opening a different project
if (saveDirty())
{
try
{
if ( ! addProject(fileName) )
{
QgsDebugMsg("unable to load project " + fileName);
}
else
{
}
}
catch ( QgsIOException & io_exception )
{
Q_UNUSED(io_exception);
QMessageBox::critical( this,
tr("QGIS: Unable to load project"),
tr("Unable to load project ") + fileName );
}
}
return ;
}
/**
Open a raster or vector file; ignore other files.
Used to process a commandline argument or OpenDocument AppleEvent.
@returns true if the file is successfully opened
*/
bool QgisApp::openLayer(const QString & fileName)
{
QFileInfo fileInfo(fileName);
// try to load it as raster
QgsMapLayer* ok = NULL;
CPLPushErrorHandler(CPLQuietErrorHandler);
if (QgsRasterLayer::isValidRasterFileName(fileName))
ok = addRasterLayer(fileName, false);
else // nope - try to load it as a shape/ogr
ok = addVectorLayer(fileName, fileName, "ogr");
CPLPopErrorHandler();
if (!ok)
{
// we have no idea what this file is...
QgsDebugMsg("Unable to load " + fileName);
}
return ok;
}
/*
void QgisApp::filePrint()
{
//
// Warn the user first that priting is experimental still
//
QString myHeading = "QGIS Printing Support is Experimental";
QString myMessage = "Please note that printing only works on A4 landscape at the moment.\n";
myMessage += "For other page sizes your mileage may vary.\n";
QMessageBox::information( this, tr(myHeading),tr(myMessage) );
QPrinter myQPrinter;
if(myQPrinter.setup(this))
{
QgsDebugMsg("..............................");
QgsDebugMsg("...........Printing...........");
QgsDebugMsg("..............................");
#endif
// Ithought we could just do this:
//mMapCanvas->render(&myQPrinter);
//but it doesnt work so now we try this....
QPaintDeviceMetrics myMetrics( &myQPrinter ); // need width/height of printer surface
std::cout << "Print device width: " << myMetrics.width() << std::endl;
std::cout << "Print device height: " << myMetrics.height() << std::endl;
QPainter myQPainter;
myQPainter.begin( &myQPrinter );
QPixmap myQPixmap(myMetrics.width(),myMetrics.height());
myQPixmap.fill();
mMapCanvas->freeze(false);
mMapCanvas->setDirty(true);
mMapCanvas->render(&myQPixmap);
myQPainter.drawPixmap(0,0, myQPixmap);
myQPainter.end();
}
}
*/
void QgisApp::filePrint()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mComposer->open();
}
void QgisApp::saveMapAsImage()
{
//create a map to hold the QImageIO names and the filter names
//the QImageIO name must be passed to the mapcanvas saveas image function
typedef QMap<QString, QString> FilterMap;
FilterMap myFilterMap;
//find out the last used filter
QSettings myQSettings; // where we keep last used filter in persistant state
QString myLastUsedFilter = myQSettings.value("/UI/saveAsImageFilter").toString();
QString myLastUsedDir = myQSettings.value("/UI/lastSaveAsImageDir",".").toString();
// get a list of supported output image types
int myCounterInt=0;
QString myFilters;
QList<QByteArray> formats = QPictureIO::outputFormats();
// Workaround for a problem with Qt4 - calls to outputFormats tend
// to return nothing :(
if (formats.count() == 0)
{
formats.append("png");
formats.append("jpg");
}
for ( ; myCounterInt < formats.count(); myCounterInt++ )
{
QString myFormat=QString(formats.at( myCounterInt ));
QString myFilter = createFileFilter_(myFormat + " format", "*."+myFormat);
myFilters += myFilter;
myFilterMap[myFilter] = myFormat;
}
#ifdef QGISDEBUG
QgsDebugMsg("Available Filters Map: ");
FilterMap::Iterator myIterator;
for ( myIterator = myFilterMap.begin(); myIterator != myFilterMap.end(); ++myIterator )
{
QgsDebugMsg( myIterator.key() + " : " + myIterator.value());
}
#endif
//create a file dialog using the the filter list generated above
std::auto_ptr < QFileDialog > myQFileDialog( new QFileDialog(this,
tr("Choose a filename to save the map image as"),
myLastUsedDir, myFilters) );
// allow for selection of more than one file
myQFileDialog->setFileMode(QFileDialog::AnyFile);
myQFileDialog->setAcceptMode(QFileDialog::AcceptSave);
myQFileDialog->setConfirmOverwrite( true );
if (!myLastUsedFilter.isEmpty()) // set the filter to the last one used
{
myQFileDialog->selectFilter(myLastUsedFilter);
}
//prompt the user for a filename
QString myOutputFileNameQString; // = myQFileDialog->getSaveFileName(); //delete this
if (myQFileDialog->exec() == QDialog::Accepted)
{
myOutputFileNameQString = myQFileDialog->selectedFiles().first();
}
QString myFilterString = myQFileDialog->selectedFilter()+";;";
QgsDebugMsg("Selected filter: " + myFilterString);
QgsDebugMsg("Image type to be passed to mapcanvas: " + myFilterMap[myFilterString]);
// Add the file type suffix to the filename if required
if (!myOutputFileNameQString.endsWith(myFilterMap[myFilterString]))
{
myOutputFileNameQString += "." + myFilterMap[myFilterString];
}
myQSettings.setValue("/UI/lastSaveAsImageFilter" , myFilterString);
myQSettings.setValue("/UI/lastSaveAsImageDir", myQFileDialog->directory().absolutePath());
if ( myOutputFileNameQString !="")
{
//save the mapview to the selected file
mMapCanvas->saveAsImage(myOutputFileNameQString,NULL,myFilterMap[myFilterString]);
statusBar()->showMessage(tr("Saved map image to") + " " + myOutputFileNameQString);
}
} // saveMapAsImage
//overloaded version of the above function
void QgisApp::saveMapAsImage(QString theImageFileNameQString, QPixmap * theQPixmap)
{
if ( theImageFileNameQString=="")
{
//no filename chosen
return;
}
else
{
//force the size of the canvase
mMapCanvas->resize(theQPixmap->width(), theQPixmap->height());
//save the mapview to the selected file
mMapCanvas->saveAsImage(theImageFileNameQString,theQPixmap);
}
} // saveMapAsImage
//reimplements method from base (gui) class
void QgisApp::addAllToOverview()
{
if(mMapLegend)
{
mMapLegend->setOverviewAllLayers(true);
}
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
//reimplements method from base (gui) class
void QgisApp::removeAllFromOverview()
{
if(mMapLegend)
{
mMapLegend->setOverviewAllLayers(false);
}
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::toggleFullScreen()
{
if (true == mFullScreenMode)
{
showNormal();
mFullScreenMode = false;
}
else
{
showFullScreen();
mFullScreenMode = true;
}
}
void QgisApp::stopRendering()
{
if(mMapCanvas)
{
QgsMapRenderer* mypMapRenderer = mMapCanvas->mapRenderer();
if(mypMapRenderer)
{
QgsRenderContext* mypRenderContext = mypMapRenderer->rendererContext();
if(mypRenderContext)
{
mypRenderContext->setRenderingStopped(true);
}
}
}
}
QToolBar * QgisApp::fileToolBar()
{
return mFileToolBar;
}
//reimplements method from base (gui) class
void QgisApp::hideAllLayers()
{
QgsDebugMsg("hiding all layers!");
legend()->selectAll(false);
}
// reimplements method from base (gui) class
void QgisApp::showAllLayers()
{
QgsDebugMsg("Showing all layers!");
legend()->selectAll(true);
}
void QgisApp::zoomIn()
{
QgsDebugMsg ("Setting map tool to zoomIn");
mMapCanvas->setMapTool(mMapTools.mZoomIn);
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::zoomOut()
{
mMapCanvas->setMapTool(mMapTools.mZoomOut);
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::zoomToSelected()
{
mMapCanvas->zoomToSelected();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::pan()
{
mMapCanvas->setMapTool(mMapTools.mPan);
}
void QgisApp::zoomFull()
{
mMapCanvas->zoomFullExtent();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::zoomPrevious()
{
mMapCanvas->zoomPreviousExtent();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::identify()
{
mMapCanvas->setMapTool(mMapTools.mIdentify);
}
void QgisApp::measure()
{
mMapCanvas->setMapTool(mMapTools.mMeasureDist);
}
void QgisApp::measureArea()
{
mMapCanvas->setMapTool(mMapTools.mMeasureArea);
}
void QgisApp::attributeTable()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer *>(mMapLegend->currentLayer()) );
}
void QgisApp::deleteSelected()
{
QgsMapLayer *layer = mMapLegend->currentLayer();
if(!layer)
{
QMessageBox::information(this, tr("No Layer Selected"),
tr("To delete features, you must select a vector layer in the legend"));
return;
}
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(layer);
if(!vlayer)
{
QMessageBox::information(this, tr("No Vector Layer Selected"),
tr("Deleting features only works on vector layers"));
return;
}
if(!(vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::DeleteFeatures))
{
QMessageBox::information(this, tr("Provider does not support deletion"),
tr("Data provider does not support deleting features"));
return;
}
if(!vlayer->isEditable())
{
QMessageBox::information(this, tr("Layer not editable"),
tr("The current layer is not editable. Choose 'Start editing' in the digitizing toolbar."));
return;
}
if(!vlayer->deleteSelectedFeatures())
{
QMessageBox::information(this, tr("Problem deleting features"),
tr("A problem occured during deletion of features"));
}
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::moveFeature()
{
mMapCanvas->setMapTool(mMapTools.mMoveFeature);
}
void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool(mMapTools.mSplitFeatures);
}
void QgisApp::capturePoint()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// set current map tool to select
mMapCanvas->setMapTool(mMapTools.mCapturePoint);
}
void QgisApp::captureLine()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mCaptureLine);
}
void QgisApp::capturePolygon()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mCapturePolygon);
}
void QgisApp::select()
{
mMapCanvas->setMapTool(mMapTools.mSelect);
}
void QgisApp::addVertex()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mVertexAdd);
}
void QgisApp::moveVertex()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mVertexMove);
}
void QgisApp::addRing()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mAddRing);
}
void QgisApp::addIsland()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mAddIsland);
}
void QgisApp::deleteVertex()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
mMapCanvas->setMapTool(mMapTools.mVertexDelete);
}
void QgisApp::editCut(QgsMapLayer * layerContainingSelection)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QgsMapLayer * selectionLayer = (layerContainingSelection != 0) ?
(layerContainingSelection) :
(activeLayer());
if (selectionLayer)
{
// Test for feature support in this layer
QgsVectorLayer* selectionVectorLayer = dynamic_cast<QgsVectorLayer*>(selectionLayer);
if (selectionVectorLayer != 0)
{
QgsFeatureList features = selectionVectorLayer->selectedFeatures();
clipboard()->replaceWithCopyOf( selectionVectorLayer->dataProvider()->fields(), features );
selectionVectorLayer->deleteSelectedFeatures();
}
}
}
void QgisApp::editCopy(QgsMapLayer * layerContainingSelection)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QgsMapLayer * selectionLayer = (layerContainingSelection != 0) ?
(layerContainingSelection) :
(activeLayer());
if (selectionLayer)
{
// Test for feature support in this layer
QgsVectorLayer* selectionVectorLayer = dynamic_cast<QgsVectorLayer*>(selectionLayer);
if (selectionVectorLayer != 0)
{
QgsFeatureList features = selectionVectorLayer->selectedFeatures();
clipboard()->replaceWithCopyOf( selectionVectorLayer->dataProvider()->fields(), features );
}
}
}
void QgisApp::editPaste(QgsMapLayer * destinationLayer)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QgsMapLayer * pasteLayer = (destinationLayer != 0) ?
(destinationLayer) :
(activeLayer());
if (pasteLayer)
{
// Test for feature support in this layer
QgsVectorLayer* pasteVectorLayer = dynamic_cast<QgsVectorLayer*>(pasteLayer);
if (pasteVectorLayer != 0)
{
pasteVectorLayer->addFeatures( clipboard()->copyOf() );
mMapCanvas->refresh();
}
}
}
void QgisApp::pasteTransformations()
{
QgsPasteTransformations *pt = new QgsPasteTransformations();
mMapCanvas->freeze();
pt->exec();
}
void QgisApp::refreshMapCanvas()
{
mMapCanvas->refresh();
}
void QgisApp::toggleMapTips()
{
mMapTipsVisible = !mMapTipsVisible;
// if off, stop the timer
if ( !mMapTipsVisible )
{
mpMapTipsTimer->stop();
}
}
void QgisApp::toggleEditing()
{
if( mMapCanvas && mMapCanvas->isDrawing() )
return;
QgsLegendLayerFile* currentLayerFile = mMapLegend->currentLayerFile();
if(currentLayerFile)
{
toggleEditing( mMapLegend->currentLayer() );
}
else
{
mActionToggleEditing->setChecked(false);
}
}
void QgisApp::toggleEditing(QgsMapLayer *layer)
{
if( !layer )
return;
QgsVectorLayer *vlayer = dynamic_cast<QgsVectorLayer*>(layer);
if (!vlayer)
return;
if (!vlayer->isEditable())
{
vlayer->startEditing();
if(!(vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures))
{
QMessageBox::information(0,tr("Start editing failed"), tr("Provider cannot be opened for editing"));
}
}
else if(vlayer->isModified())
{
// commit or roll back?
QMessageBox::StandardButton commit =
QMessageBox::information(this,
tr("Stop editing"),
tr("Do you want to save the changes to layer %1?").arg( vlayer->name() ),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if(commit==QMessageBox::Save)
{
if(!vlayer->commitChanges())
{
QMessageBox::information(this,
tr("Error"),
tr("Could not commit changes to layer %1\n\nErrors: %2\n")
.arg( vlayer->name() )
.arg( vlayer->commitErrors().join("\n ") ) );
// Leave the in-memory editing state alone,
// to give the user a chance to enter different values
// and try the commit again later
}
}
else if(commit==QMessageBox::Discard)
{
if(!vlayer->rollBack())
{
QMessageBox::information(0,tr("Error"), tr("Problems during roll back"));
}
}
else //cancel
{
return;
}
}
else //layer not modified
{
vlayer->rollBack();
}
if( layer==mMapLegend->currentLayer() )
activateDeactivateLayerRelatedActions( layer );
vlayer->triggerRepaint();
}
void QgisApp::showMouseCoordinate(QgsPoint & p)
{
if ( mMapTipsVisible )
{
// store the point, we need it for when the maptips timer fires
mLastMapPosition = p;
// we use this slot to control the timer for maptips since it is fired each time
// the mouse moves.
if ( mMapCanvas->underMouse() )
{
// Clear the maptip (this is done conditionally)
mpMaptip->clear ( mMapCanvas );
// don't start the timer if the mouse is not over the map canvas
mpMapTipsTimer->start();
//QgsDebugMsg("Started maptips timer");
}
}
if (mToggleExtentsViewButton->isChecked())
{
//we are in show extents mode so no need to do anything
return;
}
else
{
mCoordsLabel->setText(p.toString(mMousePrecisionDecimalPlaces));
// Set minimum necessary width
if ( mCoordsLabel->width() > mCoordsLabel->minimumWidth() )
{
mCoordsLabel->setMinimumWidth(mCoordsLabel->width());
}
}
}
void QgisApp::showScale(double theScale)
{
if (theScale >= 1.0)
mScaleEdit->setText("1:" + QString::number(theScale, 'f', 0));
else if (theScale > 0.0)
mScaleEdit->setText(QString::number(1.0/theScale, 'f', 0) + ":1");
else
mScaleEdit->setText(tr("Invalid scale"));
// Set minimum necessary width
if ( mScaleEdit->width() > mScaleEdit->minimumWidth() )
{
mScaleEdit->setMinimumWidth(mScaleEdit->width());
}
}
void QgisApp::userScale()
{
double currentScale = mMapCanvas->getScale();
QStringList parts = mScaleEdit->text().split(':');
if (parts.size() == 2)
{
bool leftOk, rightOk;
double leftSide = parts.at(0).toDouble(&leftOk);
double rightSide = parts.at(1).toDouble(&rightOk);
if (leftSide > 0.0 && leftOk && rightOk)
{
double wantedScale = rightSide / leftSide;
mMapCanvas->zoom(wantedScale/currentScale);
}
}
}
void QgisApp::testButton()
{
}
void QgisApp::menubar_highlighted( int i )
{
// used to save us from re-enabling layer menu items every single time the
// user tweaks the layers drop down menu
static bool enabled;
if ( 6 == i ) // XXX I hate magic numbers; where is '6' defined
// XXX for Layers menu?
{
// first, if there are NO layers, disable everything that assumes we
// have at least one layer loaded
if ( QgsMapLayerRegistry::instance()->mapLayers().empty() )
{
mActionRemoveLayer->setEnabled(false);
mActionRemoveAllFromOverview->setEnabled(false);
mActionInOverview->setEnabled(false);
mActionShowAllLayers->setEnabled(false);
mActionHideAllLayers->setEnabled(false);
mActionOpenTable->setEnabled(false);
mActionLayerProperties->setEnabled(false);
enabled = false;
}
else
{
if ( ! enabled )
{
mActionRemoveLayer->setEnabled(true);
mActionRemoveAllFromOverview->setEnabled(true);
mActionInOverview->setEnabled(true);
mActionShowAllLayers->setEnabled(true);
mActionHideAllLayers->setEnabled(true);
mActionOpenTable->setEnabled(true);
mActionLayerProperties->setEnabled(true);
}
}
}
} // QgisApp::menubar_highlighted( int i )
// toggle overview status
void QgisApp::inOverview()
{
mMapLegend->legendLayerShowInOverview();
}
void QgisApp::removeLayer()
{
QgsLegendLayerFile* currentLayerFile = mMapLegend->currentLayerFile();
if(currentLayerFile && currentLayerFile->isEditing() )
{
toggleEditing( dynamic_cast<QgsVectorLayer *>(currentLayerFile->layer()) );
}
mMapLegend->legendLayerRemove();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
void QgisApp::removeAllLayers()
{
QgsMapLayerRegistry::instance()->removeAllMapLayers();
mMapCanvas->refresh();
// notify the project we've made a change
QgsProject::instance()->dirty(true);
} //remove all layers
void QgisApp::zoomToLayerExtent()
{
mMapLegend->legendLayerZoom();
}
void QgisApp::showPluginManager()
{
QgsPluginManager *pm = new QgsPluginManager(mPythonUtils, this);
pm->resizeColumnsToContents();
if (pm->exec())
{
// load selected plugins
std::vector < QgsPluginItem > pi = pm->getSelectedPlugins();
std::vector < QgsPluginItem >::iterator it = pi.begin();
while (it != pi.end())
{
QgsPluginItem plugin = *it;
if (plugin.isPython())
{
loadPythonPlugin(plugin.fullPath(), plugin.name());
}
else
{
loadPlugin(plugin.name(), plugin.description(), plugin.fullPath());
}
it++;
}
}
}
void QgisApp::loadPythonSupport()
{
QString pythonlibName("qgispython");
#ifdef Q_WS_MAC
pythonlibName.prepend(QgsApplication::prefixPath() + "/lib/");
#endif
#ifdef __MINGW32__
pythonlibName.prepend("lib");
#endif
QLibrary pythonlib(pythonlibName);
// It's necessary to set these two load hints, otherwise Python library won't work correctly
// see http://lists.kde.org/?l=pykde&m=117190116820758&w=2
pythonlib.setLoadHints(QLibrary::ResolveAllSymbolsHint | QLibrary::ExportExternalSymbolsHint);
if (pythonlib.load())
{
//QgsDebugMsg("Python support library loaded successfully.");
typedef QgsPythonUtils* (*inst)();
inst pythonlib_inst = (inst) cast_to_fptr(pythonlib.resolve("instance"));
if (pythonlib_inst)
{
//QgsDebugMsg("Python support library's instance() symbol resolved.");
mPythonUtils = pythonlib_inst();
mPythonUtils->initPython(mQgisInterface);
}
else
{
//using stderr on purpose because we want end users to see this [TS]
std::cerr << "Couldn't resolve python support library's instance() symbol." << std::endl;
}
}
else
{
//using stderr on purpose because we want end users to see this [TS]
std::cerr << "Couldn't load Python support library." << std::endl;
}
if (mPythonUtils && mPythonUtils->isEnabled())
{
mActionShowPythonDialog = new QAction(tr("Python console"), this);
connect(mActionShowPythonDialog, SIGNAL(triggered()), this, SLOT(showPythonDialog()));
mPluginMenu->addAction(mActionShowPythonDialog);
// Purposely using stdout here [TS]
std::cout << "Python support ENABLED :-) " << std::endl;
}
}
void QgisApp::loadPythonPlugin(QString packageName, QString pluginName)
{
if (!mPythonUtils || !mPythonUtils->isEnabled())
{
QgsDebugMsg("Python is not enabled in QGIS.");
return;
}
QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
// is loaded already?
if (pRegistry->library(pluginName).isEmpty())
{
mPythonUtils->loadPlugin(packageName);
mPythonUtils->startPlugin(packageName);
// TODO: test success
// add to plugin registry
pRegistry->addPythonPlugin(packageName, pluginName);
// add to settings
QSettings settings;
settings.setValue("/PythonPlugins/" + packageName, true);
std::cout << "Loaded : " << pluginName.toLocal8Bit().constData() << " (package: "
<< packageName.toLocal8Bit().constData() << ")" << std::endl;
}
}
void QgisApp::loadPlugin(QString name, QString description, QString theFullPathName)
{
QSettings settings;
// first check to see if its already loaded
QgsPluginRegistry *pRegistry = QgsPluginRegistry::instance();
QString lib = pRegistry->library(name);
if (lib.length() > 0)
{
// plugin is loaded
// QMessageBox::warning(this, "Already Loaded", description + " is already loaded");
}
else
{
QLibrary *myLib = new QLibrary(theFullPathName);
QString myError; //we will only show detailed diagnostics if something went wrong
myError +="Library name is " + myLib->fileName() + " " + QString(__LINE__) + " in " + QString(__FUNCTION__) + "\n";
bool loaded = myLib->load();
if (loaded)
{
myError += "Attempting to resolve the classFactory function " + QString (__LINE__) + " in " + QString (__FUNCTION__ ) + "\n";
type_t *pType = (type_t *) cast_to_fptr(myLib->resolve("type"));
switch (pType())
{
case QgisPlugin::RENDERER:
case QgisPlugin::UI:
{
// UI only -- doesn't use mapcanvas
create_ui *cf = (create_ui *) cast_to_fptr(myLib->resolve("classFactory"));
if (cf)
{
QgisPlugin *pl = cf(mQgisInterface);
if (pl)
{
pl->initGui();
// add it to the plugin registry
pRegistry->addPlugin(myLib->fileName(), name, pl);
//add it to the qsettings file [ts]
settings.setValue("/Plugins/" + name, true);
}
else
{
// something went wrong
QMessageBox::warning(this, tr("Error Loading Plugin"), tr("There was an error loading a plugin."
"The following diagnostic information may help the QGIS developers resolve the issue:\n%1.").arg
(myError));
//disable it to the qsettings file [ts]
settings.setValue("/Plugins/" + name, false);
}
}
else
{
QgsDebugMsg("Unable to find the class factory for " + theFullPathName);
}
}
break;
case QgisPlugin::MAPLAYER:
{
// Map layer - requires interaction with the canvas
create_it *cf = (create_it *) cast_to_fptr(myLib->resolve("classFactory"));
if (cf)
{
QgsMapLayerInterface *pl = cf();
if (pl)
{
// set the main window pointer for the plugin
pl->setQgisMainWindow(this);
pl->initGui();
//add it to the qsettings file [ts]
settings.setValue("/Plugins/" + name, true);
}
else
{
// something went wrong
QMessageBox::warning(this, tr("Error Loading Plugin"), tr("There was an error loading %1."));
//add it to the qsettings file [ts]
settings.setValue("/Plugins/" + name, false);
}
}
else
{
QgsDebugMsg("Unable to find the class factory for " + theFullPathName);
}
}
break;
default:
// type is unknown
QgsDebugMsg("Plugin " + theFullPathName + " did not return a valid type and cannot be loaded");
break;
}
}
else
{
QgsDebugMsg("Failed to load " + theFullPathName);
}
delete myLib;
}
}
void QgisApp::checkQgisVersion()
{
QApplication::setOverrideCursor(Qt::WaitCursor);
/* QUrlOperator op = new QUrlOperator( "http://mrcc.com/qgis/version.txt" );
connect(op, SIGNAL(data()), SLOT(urlData()));
connect(op, SIGNAL(finished(QNetworkOperation)), SLOT(urlFinished(QNetworkOperation)));
op.get(); */
mSocket = new QTcpSocket(this);
connect(mSocket, SIGNAL(connected()), SLOT(socketConnected()));
connect(mSocket, SIGNAL(connectionClosed()), SLOT(socketConnectionClosed()));
connect(mSocket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
connect(mSocket, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(socketError(QAbstractSocket::SocketError)));
mSocket->connectToHost("mrcc.com", 80);
}
void QgisApp::socketConnected()
{
QTextStream os(mSocket);
mVersionMessage = "";
// send the qgis version string
// os << qgisVersion << "\r\n";
os << "GET /qgis/version.txt HTTP/1.0\n\n";
}
void QgisApp::socketConnectionClosed()
{
QApplication::restoreOverrideCursor();
// strip the header
QString contentFlag = "#QGIS Version";
int pos = mVersionMessage.indexOf(contentFlag);
if (pos > -1)
{
pos += contentFlag.length();
/* std::cout << mVersionMessage << "\n ";
std::cout << "Pos is " << pos <<"\n"; */
mVersionMessage = mVersionMessage.mid(pos);
QStringList parts = mVersionMessage.split("|", QString::SkipEmptyParts);
// check the version from the server against our version
QString versionInfo;
int currentVersion = parts[0].toInt();
if (currentVersion > QGis::qgisVersionInt)
{
// show version message from server
versionInfo = tr("There is a new version of QGIS available") + "\n";
}
else
{
if (QGis::qgisVersionInt > currentVersion)
{
versionInfo = tr("You are running a development version of QGIS") + "\n";
}
else
{
versionInfo = tr("You are running the current version of QGIS") + "\n";
}
}
if (parts.count() > 1)
{
versionInfo += parts[1] + "\n\n" + tr("Would you like more information?");
;
QMessageBox::StandardButton result = QMessageBox::information(this,
tr("QGIS Version Information"), versionInfo, QMessageBox::Ok |
QMessageBox::Cancel);
if (result == QMessageBox::Ok)
{
// show more info
QgsMessageViewer *mv = new QgsMessageViewer(this);
mv->setWindowTitle(tr("QGIS - Changes in SVN Since Last Release"));
mv->setMessageAsHtml(parts[2]);
mv->exec();
}
}
else
{
QMessageBox::information(this, tr("QGIS Version Information"), versionInfo);
}
}
else
{
QMessageBox::warning(this, tr("QGIS Version Information"), tr("Unable to get current version information from server"));
}
}
void QgisApp::socketError(QAbstractSocket::SocketError e)
{
if (e == QAbstractSocket::RemoteHostClosedError)
return;
QApplication::restoreOverrideCursor();
// get error type
QString detail;
switch (e)
{
case QAbstractSocket::ConnectionRefusedError:
detail = tr("Connection refused - server may be down");
break;
case QAbstractSocket::HostNotFoundError:
detail = tr("QGIS server was not found");
break;
case QAbstractSocket::NetworkError:
detail = tr("Network error while communicating with server");
break;
default:
detail = tr("Unknown network socket error");
break;
}
// show version message from server
QMessageBox::critical(this, tr("QGIS Version Information"), tr("Unable to communicate with QGIS Version server") + "\n" + detail);
}
void QgisApp::socketReadyRead()
{
while (mSocket->bytesAvailable() > 0)
{
char *data = new char[mSocket->bytesAvailable() + 1];
memset(data, '\0', mSocket->bytesAvailable() + 1);
mSocket->read(data, mSocket->bytesAvailable());
mVersionMessage += data;
delete[]data;
}
}
void QgisApp::options()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QgsOptions *optionsDialog = new QgsOptions(this);
if(optionsDialog->exec())
{
// set the theme if it changed
setTheme(optionsDialog->theme());
QSettings mySettings;
mMapCanvas->enableAntiAliasing(mySettings.value("/qgis/enable_anti_aliasing").toBool());
mMapCanvas->useQImageToRender(mySettings.value("/qgis/use_qimage_to_render").toBool());
int action = mySettings.value("/qgis/wheel_action", 0).toInt();
double zoomFactor = mySettings.value("/qgis/zoom_factor", 2).toDouble();
mMapCanvas->setWheelAction((QgsMapCanvas::WheelAction) action, zoomFactor);
setupProxy();
}
}
void QgisApp::helpContents()
{
openURL("index.html");
}
void QgisApp::helpQgisHomePage()
{
openURL("http://qgis.org", false);
}
void QgisApp::openURL(QString url, bool useQgisDocDirectory)
{
// open help in user browser
if (useQgisDocDirectory)
{
url = "file://" + QgsApplication::pkgDataPath() + "/doc/" + url;
}
#ifdef Q_OS_MACX
/* Use Mac OS X Launch Services which uses the user's default browser
* and will just open a new window if that browser is already running.
* QProcess creates a new browser process for each invocation and expects a
* commandline application rather than a bundled application.
*/
CFURLRef urlRef = CFURLCreateWithBytes(kCFAllocatorDefault,
reinterpret_cast<const UInt8*>(url.toUtf8().data()), url.length(),
kCFStringEncodingUTF8, NULL);
OSStatus status = LSOpenCFURLRef(urlRef, NULL);
status = 0; //avoid compiler warning
CFRelease(urlRef);
#elif defined(WIN32)
if(url.startsWith("file://", Qt::CaseInsensitive))
ShellExecute(0, 0, url.mid(7).toLocal8Bit().constData(), 0, 0, SW_SHOWNORMAL);
else
QDesktopServices::openUrl(url);
#else
QDesktopServices::openUrl(url);
#endif
}
/** Get a pointer to the currently selected map layer */
QgsMapLayer *QgisApp::activeLayer()
{
return (mMapLegend->currentLayer());
}
/** Add a vector layer directly without prompting user for location
The caller must provide information compatible with the provider plugin
using the vectorLayerPath and baseName. The provider can use these
parameters in any way necessary to initialize the layer. The baseName
parameter is used in the Map Legend so it should be formed in a meaningful
way.
*/
QgsVectorLayer* QgisApp::addVectorLayer(QString vectorLayerPath, QString baseName, QString providerKey)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return NULL;
}
mMapCanvas->freeze();
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
// create the layer
QgsVectorLayer *layer;
/* Eliminate the need to instantiate the layer based on provider type.
The caller is responsible for cobbling together the needed information to
open the layer
*/
QgsDebugMsg( "Creating new vector layer using " + vectorLayerPath
+ " with baseName of " + baseName
+ " and providerKey of " + providerKey);
layer = new QgsVectorLayer(vectorLayerPath, baseName, providerKey);
if( layer && layer->isValid() )
{
// Register this layer with the layers registry
QgsMapLayerRegistry::instance()->addMapLayer(layer);
// notify the project we've made a change
QgsProject::instance()->dirty(true);
statusBar()->showMessage(mMapCanvas->extent().toString(2));
}
else
{
QMessageBox::critical(this,tr("Layer is not valid"),
tr("The layer is not a valid layer and can not be added to the map"));
delete layer;
mMapCanvas->freeze(false);
return NULL;
}
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze(false);
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
return layer;
} // QgisApp::addVectorLayer
void QgisApp::addMapLayer(QgsMapLayer *theMapLayer)
{
mMapCanvas->freeze();
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
if(theMapLayer->isValid())
{
// Register this layer with the layers registry
QgsMapLayerRegistry::instance()->addMapLayer(theMapLayer);
// add it to the mapcanvas collection
// not necessary since adding to registry adds to canvas mMapCanvas->addLayer(theMapLayer);
statusBar()->showMessage(mMapCanvas->extent().toString(2));
// notify the project we've made a change
QgsProject::instance()->dirty(true);
}
else
{
QMessageBox::critical(this,tr("Layer is not valid"),
tr("The layer is not a valid layer and can not be added to the map"));
}
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze(false);
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
}
void QgisApp::setExtent(QgsRect theRect)
{
mMapCanvas->setExtent(theRect);
}
/**
Prompt and save if project has been modified.
@return true if saved or discarded, false if cancelled
*/
bool QgisApp::saveDirty()
{
QMessageBox::StandardButton answer(QMessageBox::Discard);
mMapCanvas->freeze(true);
//QgsDebugMsg(QString("Layer count is %1").arg(mMapCanvas->layerCount()));
//QgsDebugMsg(QString("Project is %1dirty").arg( QgsProject::instance()->isDirty() ? "" : "not "));
//QgsDebugMsg(QString("Map canvas is %1dirty").arg(mMapCanvas->isDirty() ? "" : "not "));
QSettings settings;
bool askThem = settings.value("qgis/askToSaveProjectChanges", true).toBool();
if (askThem && (QgsProject::instance()->isDirty() || mMapCanvas->isDirty()) && mMapCanvas->layerCount() > 0)
{
// flag project as dirty since dirty state of canvas is reset if "dirty"
// is based on a zoom or pan
QgsProject::instance()->dirty( true );
// old code: mProjectIsDirtyFlag = true;
// prompt user to save
answer = QMessageBox::information(this, tr("Save?"),
tr("Do you want to save the current project?"),
QMessageBox::Save | QMessageBox::Cancel | QMessageBox::Discard);
if (QMessageBox::Save == answer)
{
if (!fileSave())
answer = QMessageBox::Cancel;
}
}
mMapCanvas->freeze(false);
return (answer != QMessageBox::Cancel);
} // QgisApp::saveDirty()
void QgisApp::closeEvent(QCloseEvent* event)
{
// We'll close in our own good time, thank you very much
event->ignore();
// Do the usual checks and ask if they want to save, etc
fileExit();
}
void QgisApp::whatsThis()
{
QWhatsThis::enterWhatsThisMode();
} // QgisApp::whatsThis()
QMenu* QgisApp::getPluginMenu(QString menuName)
{
// This is going to record the menu item that the potentially new
// menu item is going to be inserted before. A value of 0 will a new
// menu item to be appended.
QAction* before = 0;
QList<QAction*> actions = mPluginMenu->actions();
// Avoid 1 because the first item (number 0) is 'Plugin Manager',
// which we want to stay first. Search in reverse order as that
// makes it easier to find out where which item a new menu item
// should go before (since the insertMenu() function requires a
// 'before' argument).
for (unsigned int i = actions.count()-1; i > 0; --i)
{
if (actions.at(i)->text() == menuName)
{
return actions.at(i)->menu();
}
// Find out where to put the menu item, assuming that it is a new one
//
// This bit of code assumes that the menu items are already in
// alphabetical order, which they will be if the menus are all
// created using this function.
if (menuName.localeAwareCompare(actions.at(i)->text()) <= 0)
before = actions.at(i);
}
// It doesn't exist, so create
QMenu* menu = new QMenu(menuName, this);
// Where to put it? - we worked that out above...
mPluginMenu->insertMenu(before, menu);
return menu;
}
void QgisApp::addPluginMenu(QString name, QAction* action)
{
QMenu* menu = getPluginMenu(name);
menu->addAction(action);
}
void QgisApp::removePluginMenu(QString name, QAction* action)
{
QMenu* menu = getPluginMenu(name);
menu->removeAction(action);
if (menu->actions().count() == 0)
{
mPluginMenu->removeAction(menu->menuAction());
}
}
int QgisApp::addPluginToolBarIcon (QAction * qAction)
{
mPluginToolBar->addAction(qAction);
return 0;
}
void QgisApp::removePluginToolBarIcon(QAction *qAction)
{
mPluginToolBar->removeAction(qAction);
}
void QgisApp::destinationSrsChanged()
{
// save this information to project
long srsid = mMapCanvas->mapRenderer()->destinationSrs().srsid();
QgsProject::instance()->writeEntry("SpatialRefSys", "/ProjectCRSID", (int)srsid);
}
void QgisApp::projectionsEnabled(bool theFlag)
{
// save this information to project
QgsProject::instance()->writeEntry("SpatialRefSys","/ProjectionsEnabled", (theFlag?1:0));
// update icon
if (theFlag)
{
mOnTheFlyProjectionStatusButton->setIcon(
getThemeIcon("mIconProjectionEnabled.png"));
}
else
{
mOnTheFlyProjectionStatusButton->setIcon(
getThemeIcon("mIconProjectionDisabled.png"));
}
}
// slot to update the progress bar in the status bar
void QgisApp::showProgress(int theProgress, int theTotalSteps)
{
if (theProgress==theTotalSteps)
{
mProgressBar->reset();
mProgressBar->hide();
}
else
{
//only call show if not already hidden to reduce flicker
if (!mProgressBar->isVisible())
{
mProgressBar->show();
}
mProgressBar->setMaximum(theTotalSteps);
mProgressBar->setValue(theProgress);
}
}
void QgisApp::mapToolChanged(QgsMapTool *tool)
{
if( tool && !tool->isEditTool() )
{
mNonEditMapTool = tool;
}
}
void QgisApp::extentsViewToggled(bool theFlag)
{
if (theFlag)
{
//extents view mode!
mToggleExtentsViewButton->setIcon(getThemeIcon("extents.png"));
mCoordsLabel->setToolTip(tr("Map coordinates for the current view extents"));
showExtents();
}
else
{
//mouse cursor pos view mode!
mToggleExtentsViewButton->setIcon(getThemeIcon("tracking.png"));
mCoordsLabel->setToolTip(tr("Map coordinates at mouse cursor position"));
}
}
void QgisApp::showExtents()
{
if (!mToggleExtentsViewButton->isChecked())
{
//we are in show coords mode so no need to do anything
return;
}
// update the statusbar with the current extents.
QgsRect myExtents = mMapCanvas->extent();
mCoordsLabel->setText(QString(tr("Extents: ")) + myExtents.toString(true));
//ensure the label is big enough
if ( mCoordsLabel->width() > mCoordsLabel->minimumWidth() )
{
mCoordsLabel->setMinimumWidth(mCoordsLabel->width());
}
} // QgisApp::showExtents
void QgisApp::updateMouseCoordinatePrecision()
{
// Work out what mouse display precision to use. This only needs to
// be when the settings change or the zoom level changes. This
// function needs to be called every time one of the above happens.
// Get the display precision from the project settings
bool automatic = QgsProject::instance()->readBoolEntry("PositionPrecision","/Automatic");
int dp = 0;
if (automatic)
{
// Work out a suitable number of decimal places for the mouse
// coordinates with the aim of always having enough decimal places
// to show the difference in position between adjacent pixels.
// Also avoid taking the log of 0.
if (getMapCanvas()->mapUnitsPerPixel() != 0.0)
dp = static_cast<int> (ceil(-1.0*log10(getMapCanvas()->mapUnitsPerPixel())));
}
else
dp = QgsProject::instance()->readNumEntry("PositionPrecision","/DecimalPlaces");
// Keep dp sensible
if (dp < 0) dp = 0;
mMousePrecisionDecimalPlaces = dp;
}
void QgisApp::showStatusMessage(QString theMessage)
{
statusBar()->showMessage(theMessage);
}
void QgisApp::showMapTip()
{
/* Show the maptip using tooltip */
// Stop the timer while we look for a maptip
mpMapTipsTimer->stop();
// Only show tooltip if the mouse is over the canvas
if ( mMapCanvas->underMouse() )
{
QPoint myPointerPos = mMapCanvas->mouseLastXY();
// Make sure there is an active layer before proceeding
QgsMapLayer* mypLayer = mMapCanvas->currentLayer();
if ( mypLayer )
{
//QgsDebugMsg("Current layer for maptip display is: " + mypLayer->source());
// only process vector layers
if ( mypLayer->type() == QgsMapLayer::VECTOR )
{
// Show the maptip if the maptips button is depressed
if(mMapTipsVisible)
{
mpMaptip->showMapTip ( mypLayer, mLastMapPosition, myPointerPos, mMapCanvas );
}
}
}
else
{
showStatusMessage(tr( "Maptips require an active layer" ));
}
}
}
void QgisApp::projectPropertiesProjections()
{
// Driver to display the project props dialog and switch to the
// projections tab
mShowProjectionTab = true;
projectProperties();
}
void QgisApp::projectProperties()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
/* Display the property sheet for the Project */
// set wait cursor since construction of the project properties
// dialog results in the construction of the spatial reference
// system QMap
QApplication::setOverrideCursor(Qt::WaitCursor);
QgsProjectProperties *pp = new QgsProjectProperties(mMapCanvas, this);
// if called from the status bar, show the projection tab
if(mShowProjectionTab)
{
pp->showProjectionsTab();
mShowProjectionTab = false;
}
qApp->processEvents();
// Be told if the mouse display precision may have changed by the user
// changing things in the project properties dialog box
connect(pp, SIGNAL(displayPrecisionChanged()), this,
SLOT(updateMouseCoordinatePrecision()));
QApplication::restoreOverrideCursor();
//pass any refresg signals off to canvases
//connect (pp,SIGNAL(refresh()), mMapCanvas, SLOT(refresh()));
QgsMapRenderer* myRender = mMapCanvas->mapRenderer();
bool wasProjected = myRender->projectionsEnabled();
long oldCRSID = myRender->destinationSrs().srsid();
// Display the modal dialog box.
pp->exec();
long newCRSID = myRender->destinationSrs().srsid();
bool isProjected = myRender->projectionsEnabled();
// projections have been turned on/off or dest CRS has changed while projections are on
if (wasProjected != isProjected || (isProjected && oldCRSID != newCRSID))
{
// TODO: would be better to try to reproject current extent to the new one
mMapCanvas->updateFullExtent();
}
int myRedInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorRedPart",255);
int myGreenInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorGreenPart",255);
int myBlueInt = QgsProject::instance()->readNumEntry("Gui","/CanvasColorBluePart",255);
QColor myColor = QColor(myRedInt,myGreenInt,myBlueInt);
mMapCanvas->setCanvasColor(myColor); // this is fill colour before rendering onto canvas
// Set the window title.
setTitleBarText_( *this );
// delete the property sheet object
delete pp;
} // QgisApp::projectProperties
QgsClipboard * QgisApp::clipboard()
{
return mInternalClipboard;
}
void QgisApp::activateDeactivateLayerRelatedActions(QgsMapLayer* layer)
{
if(!layer)
{
mActionToggleEditing->setEnabled(false);
mActionRemoveLayer->setEnabled(false);
mActionInOverview->setEnabled(false);
mActionEditCopy->setEnabled(false);
return;
}
mActionToggleEditing->setEnabled(true);
mActionRemoveLayer->setEnabled(true);
mActionInOverview->setEnabled(true);
/***********Vector layers****************/
if(layer->type() == QgsMapLayer::VECTOR)
{
mActionSelect->setEnabled(true);
mActionOpenTable->setEnabled(true);
mActionIdentify->setEnabled(true);
mActionEditCopy->setEnabled(true);
const QgsVectorLayer* vlayer = dynamic_cast<const QgsVectorLayer*>(layer);
const QgsVectorDataProvider* dprovider = vlayer->dataProvider();
if( !vlayer->isEditable() && mMapCanvas->mapTool() && mMapCanvas->mapTool()->isEditTool() )
{
mMapCanvas->setMapTool(mNonEditMapTool);
}
if (dprovider)
{
//start editing/stop editing
if(dprovider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
mActionToggleEditing->setEnabled(true);
mActionToggleEditing->setChecked(vlayer->isEditable());
mActionEditPaste->setEnabled(vlayer->isEditable());
}
else
{
mActionToggleEditing->setEnabled(false);
mActionEditPaste->setEnabled(false);
}
//does provider allow deleting of features?
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures)
{
mActionDeleteSelected->setEnabled(true);
mActionEditCut->setEnabled(true);
}
else
{
mActionDeleteSelected->setEnabled(false);
mActionEditCut->setEnabled(false);
}
if(vlayer->vectorType() == QGis::Point)
{
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
mActionCapturePoint->setEnabled(true);
mActionMoveFeature->setEnabled(true);
}
else
{
mActionCapturePoint->setEnabled(false);
mActionMoveFeature->setEnabled(false);
}
mActionCaptureLine->setEnabled(false);
mActionCapturePolygon->setEnabled(false);
mActionAddVertex->setEnabled(false);
mActionDeleteVertex->setEnabled(false);
mActionMoveVertex->setEnabled(false);
mActionAddRing->setEnabled(false);
mActionAddIsland->setEnabled(false);
mActionSplitFeatures->setEnabled(false);
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries)
{
//don't enable vertex move for single point
if(vlayer->geometryType() != QGis::WKBPoint && vlayer->geometryType() != QGis::WKBPoint25D)
{
mActionMoveVertex->setEnabled(true);
}
mActionMoveFeature->setEnabled(true);
}
return;
}
else if(vlayer->vectorType() == QGis::Line)
{
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
mActionCaptureLine->setEnabled(true);
mActionSplitFeatures->setEnabled(true);
mActionMoveFeature->setEnabled(true);
}
else
{
mActionCaptureLine->setEnabled(false);
mActionSplitFeatures->setEnabled(false);
mActionMoveFeature->setEnabled(false);
}
mActionCapturePoint->setEnabled(false);
mActionCapturePolygon->setEnabled(false);
mActionAddRing->setEnabled(false);
mActionAddIsland->setEnabled(false);
}
else if(vlayer->vectorType() == QGis::Polygon)
{
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
mActionCapturePolygon->setEnabled(true);
mActionAddRing->setEnabled(true);
mActionAddIsland->setEnabled(true);
mActionSplitFeatures->setEnabled(true);
mActionMoveFeature->setEnabled(true);
}
else
{
mActionCapturePolygon->setEnabled(false);
mActionAddRing->setEnabled(false);
mActionAddIsland->setEnabled(false);
mActionSplitFeatures->setEnabled(false);
mActionMoveFeature->setEnabled(false);
}
mActionCapturePoint->setEnabled(false);
mActionCaptureLine->setEnabled(false);
}
//are add/delete/move vertex supported?
if(vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries)
{
mActionAddVertex->setEnabled(true);
mActionMoveVertex->setEnabled(true);
mActionDeleteVertex->setEnabled(true);
mActionMoveFeature->setEnabled(true);
if(vlayer->vectorType() == QGis::Polygon)
{
mActionAddRing->setEnabled(true);
//some polygon layers contain also multipolygon features.
//Therefore, the test for multipolygon is done in QgsGeometry
mActionAddIsland->setEnabled(true);
}
}
else
{
mActionAddVertex->setEnabled(false);
mActionMoveVertex->setEnabled(false);
mActionDeleteVertex->setEnabled(false);
mActionMoveFeature->setEnabled(false);
}
return;
}
}
/*************Raster layers*************/
else if(layer->type() == QgsMapLayer::RASTER)
{
mActionSelect->setEnabled(false);
mActionOpenTable->setEnabled(false);
mActionToggleEditing->setEnabled(false);
mActionCapturePoint->setEnabled(false);
mActionCaptureLine->setEnabled(false);
mActionCapturePolygon->setEnabled(false);
mActionDeleteSelected->setEnabled(false);
mActionAddRing->setEnabled(false);
mActionAddIsland->setEnabled(false);
mActionAddVertex->setEnabled(false);
mActionDeleteVertex->setEnabled(false);
mActionMoveVertex->setEnabled(false);
mActionMoveFeature->setEnabled(false);
mActionEditCopy->setEnabled(false);
mActionEditCut->setEnabled(false);
mActionEditPaste->setEnabled(false);
const QgsRasterLayer* vlayer = dynamic_cast<const QgsRasterLayer*> (layer);
const QgsRasterDataProvider* dprovider = vlayer->dataProvider();
if (dprovider)
{
// does provider allow the identify map tool?
if (dprovider->capabilities() & QgsRasterDataProvider::Identify)
{
mActionIdentify->setEnabled(TRUE);
}
else
{
mActionIdentify->setEnabled(FALSE);
}
}
}
}
/////////////////////////////////////////////////////////////////
//
//
// Only functions relating to raster layer management in this
// section (look for a similar comment block to this to find
// the end of this section).
//
// Tim Sutton
//
//
/////////////////////////////////////////////////////////////////
// this is a slot for action from GUI to add raster layer
void QgisApp::addRasterLayer()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
QString fileFilters;
QStringList selectedFiles;
QString e;//only for parameter correctness
QString title = tr("Open a GDAL Supported Raster Data Source");
openFilesRememberingFilter_("lastRasterFileFilter", mRasterFileFilter, selectedFiles,e,
title);
if (selectedFiles.isEmpty())
{
// no files were selected, so just bail
return;
}
addRasterLayers(selectedFiles);
}// QgisApp::addRasterLayer()
//
// This is the method that does the actual work of adding a raster layer - the others
// here simply create a raster layer object and delegate here. It is the responsibility
// of the calling method to manage things such as the frozen state of the mapcanvas and
// using waitcursors etc. - this method wont and SHOULDNT do it
//
bool QgisApp::addRasterLayer(QgsRasterLayer * theRasterLayer)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return false;
}
Q_CHECK_PTR( theRasterLayer );
if ( ! theRasterLayer )
{
// XXX insert meaningful whine to the user here; although be
// XXX mindful that a null layer may mean exhausted memory resources
return false;
}
if (!theRasterLayer->isValid())
{
delete theRasterLayer;
return false;
}
// register this layer with the central layers registry
QgsMapLayerRegistry::instance()->addMapLayer(theRasterLayer);
// connect up any request the raster may make to update the app progress
QObject::connect(theRasterLayer,
SIGNAL(drawingProgress(int,int)),
this,
SLOT(showProgress(int,int)));
// connect up any request the raster may make to update the statusbar message
QObject::connect(theRasterLayer,
SIGNAL(setStatus(QString)),
this,
SLOT(showStatusMessage(QString)));
// notify the project we've made a change
QgsProject::instance()->dirty(true);
return true;
}
//create a raster layer object and delegate to addRasterLayer(QgsRasterLayer *)
QgsRasterLayer* QgisApp::addRasterLayer(QString const & rasterFile, QString const & baseName, bool guiWarning)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return NULL;
}
// let the user know we're going to possibly be taking a while
QApplication::setOverrideCursor(Qt::WaitCursor);
mMapCanvas->freeze(true);
// XXX ya know QgsRasterLayer can snip out the basename on its own;
// XXX why do we have to pass it in for it?
QgsRasterLayer *layer =
new QgsRasterLayer(rasterFile, baseName); // fi.completeBaseName());
if (!addRasterLayer(layer))
{
mMapCanvas->freeze(false);
QApplication::restoreOverrideCursor();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
if(guiWarning)
{
// don't show the gui warning (probably because we are loading from command line)
QString msg(rasterFile
+ tr(" is not a valid or recognized raster data source"));
QMessageBox::critical(this, tr("Invalid Data Source"), msg);
}
return NULL;
}
else
{
statusBar()->showMessage(mMapCanvas->extent().toString(2));
mMapCanvas->freeze(false);
QApplication::restoreOverrideCursor();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
mMapCanvas->refresh();
return layer;
}
} // QgisApp::addRasterLayer
/** Add a raster layer directly without prompting user for location
The caller must provide information compatible with the provider plugin
using the rasterLayerPath and baseName. The provider can use these
parameters in any way necessary to initialize the layer. The baseName
parameter is used in the Map Legend so it should be formed in a meaningful
way.
\note Copied from the equivalent addVectorLayer function in this file
TODO Make it work for rasters specifically.
*/
QgsRasterLayer* QgisApp::addRasterLayer(QString const & rasterLayerPath,
QString const & baseName,
QString const & providerKey,
QStringList const & layers,
QStringList const & styles,
QString const & format,
QString const & crs)
{
QgsDebugMsg("about to get library for " + providerKey);
if(mMapCanvas && mMapCanvas->isDrawing())
{
return 0;
}
mMapCanvas->freeze();
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
// create the layer
QgsRasterLayer *layer;
/* Eliminate the need to instantiate the layer based on provider type.
The caller is responsible for cobbling together the needed information to
open the layer
*/
QgsDebugMsg( "Creating new raster layer using " + rasterLayerPath
+ " with baseName of " + baseName
+ " and layer list of " + layers.join(", ")
+ " and style list of " + styles.join(", ")
+ " and format of " + format
+ " and providerKey of " + providerKey
+ " and CRS of " + crs );
// TODO: Remove the 0 when the raster layer becomes a full provider gateway.
layer = new QgsRasterLayer(0, rasterLayerPath, baseName, providerKey, layers, styles, format, crs);
QgsDebugMsg("Constructed new layer.");
if( layer && layer->isValid() )
{
addRasterLayer(layer);
statusBar()->showMessage(mMapCanvas->extent().toString(2));
}
else
{
QMessageBox::critical(this,tr("Layer is not valid"),
tr("The layer is not a valid layer and can not be added to the map"));
}
// update UI
qApp->processEvents();
// draw the map
mMapCanvas->freeze(false);
mMapCanvas->refresh();
return layer;
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
} // QgisApp::addRasterLayer
//create a raster layer object and delegate to addRasterLayer(QgsRasterLayer *)
bool QgisApp::addRasterLayers(QStringList const &theFileNameQStringList, bool guiWarning)
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return false;
}
if (theFileNameQStringList.empty())
{
// no files selected so bail out, but
// allow mMapCanvas to handle events
// first
mMapCanvas->freeze(false);
return false;
}
mMapCanvas->freeze(true);
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
// this is messy since some files in the list may be rasters and others may
// be ogr layers. We'll set returnValue to false if one or more layers fail
// to load.
bool returnValue = true;
for (QStringList::ConstIterator myIterator = theFileNameQStringList.begin();
myIterator != theFileNameQStringList.end();
++myIterator)
{
QString errMsg;
if (QgsRasterLayer::isValidRasterFileName(*myIterator,errMsg))
{
QFileInfo myFileInfo(*myIterator);
// get the directory the .adf file was in
QString myDirNameQString = myFileInfo.path();
QString myBaseNameQString = myFileInfo.completeBaseName();
//only allow one copy of a ai grid file to be loaded at a
//time to prevent the user selecting all adfs in 1 dir which
//actually represent 1 coverage,
// create the layer
QgsRasterLayer *layer = new QgsRasterLayer(*myIterator, myBaseNameQString);
addRasterLayer(layer);
//only allow one copy of a ai grid file to be loaded at a
//time to prevent the user selecting all adfs in 1 dir which
//actually represent 1 coverate,
if (myBaseNameQString.toLower().endsWith(".adf"))
{
break;
}
}
else
{
// Issue message box warning unless we are loading from cmd line since
// non-rasters are passed to this function first and then sucessfully
// loaded afterwards (see main.cpp)
if(guiWarning)
{
QString msg(*myIterator + tr(" is not a supported raster data source"));
if( errMsg.size() > 0 )
msg += "\n" + errMsg;
QMessageBox::critical(this, tr("Unsupported Data Source"), msg);
}
returnValue = false;
}
}
statusBar()->showMessage(mMapCanvas->extent().toString(2));
mMapCanvas->freeze(false);
mMapCanvas->refresh();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
return returnValue;
}// QgisApp::addRasterLayer()
///////////////////////////////////////////////////////////////////
//
//
//
//
// RASTER ONLY RELATED FUNCTIONS BLOCK ENDS....
//
//
//
//
///////////////////////////////////////////////////////////////////
void QgisApp::keyPressEvent ( QKeyEvent * e )
{
// The following statement causes a crash on WIN32 and should be
// enclosed in an #ifdef QGISDEBUG if its really necessary. Its
// commented out for now. [gsherman]
// std::cout << e->text().toLocal8Bit().data() << " (keypress recevied)" << std::endl;
emit keyPressed (e);
//cancel rendering progress with esc key
if(e->key() == Qt::Key_Escape)
{
stopRendering();
}
else
{
e->ignore();
}
}
// Debug hook - used to output diagnostic messages when evoked (usually from the menu)
/* Temporarily disabled...
void QgisApp::debugHook()
{
std::cout << "Hello from debug hook" << std::endl;
// show the map canvas extent
std::cout << mMapCanvas->extent() << std::endl;
}
*/
void QgisApp::customProjection()
{
if(mMapCanvas && mMapCanvas->isDrawing())
{
return;
}
// Create an instance of the Custom Projection Designer modeless dialog.
// Autodelete the dialog when closing since a pointer is not retained.
QgsCustomProjectionDialog * myDialog = new QgsCustomProjectionDialog(this);
myDialog->setAttribute(Qt::WA_DeleteOnClose);
myDialog->show();
}
void QgisApp::showBookmarks()
{
// Create or show the single instance of the Bookmarks modeless dialog.
// Closing a QWidget only hides it so it can be shown again later.
static QgsBookmarks *bookmarks = NULL;
if (bookmarks == NULL)
{
bookmarks = new QgsBookmarks(this, Qt::WindowMinMaxButtonsHint);
}
bookmarks->restorePosition();
bookmarks->show();
bookmarks->raise();
bookmarks->activateWindow();
}
void QgisApp::newBookmark()
{
// Get the name for the bookmark. Everything else we fetch from
// the mapcanvas
bool ok;
QString bookmarkName = QInputDialog::getText(this, tr("New Bookmark"),
tr("Enter a name for the new bookmark:"), QLineEdit::Normal,
QString::null, &ok);
if( ok && !bookmarkName.isEmpty())
{
if (createDB())
{
// create the bookmark
QgsBookmarkItem *bmi = new QgsBookmarkItem(bookmarkName,
QgsProject::instance()->title(), mMapCanvas->extent(), -1,
QgsApplication::qgisUserDbFilePath());
bmi->store();
delete bmi;
// emit a signal to indicate that the bookmark was added
emit bookmarkAdded();
}
else
{
QMessageBox::warning(this,tr("Error"), tr("Unable to create the bookmark. Your user database may be missing or corrupted"));
}
}
}
void QgisApp::showAllToolbars()
{
setToolbarVisibility(true);
}
void QgisApp::hideAllToolbars()
{
setToolbarVisibility(false);
}
void QgisApp::setToolbarVisibility(bool visibility)
{
mFileToolBar->setVisible(visibility);
mLayerToolBar->setVisible(visibility);
mMapNavToolBar->setVisible(visibility);
mDigitizeToolBar->setVisible(visibility);
mAttributesToolBar->setVisible(visibility);
mPluginToolBar->setVisible(visibility);
mHelpToolBar->setVisible(visibility);
}
// Slot that gets called when the project file was saved with an older
// version of QGIS
void QgisApp::warnOlderProjectVersion(QString oldVersion)
{
QSettings settings;
if ( settings.value("/qgis/warnOldProjectVersion", QVariant(true)).toBool() )
{
QMessageBox::warning(NULL, tr("Project file is older"),
(tr("<p>This project file was saved by an older version of QGIS.") +
tr(" When saving this project file, QGIS will update it to the latest version, "
"possibly rendering it useless for older versions of QGIS.") +
tr("<p>Even though QGIS developers try to maintain backwards "
"compatibility, some of the information from the old project "
"file might be lost.") +
tr(" To improve the quality of QGIS, we appreciate "
"if you file a bug report at %3.") +
tr(" Be sure to include the old project file, and state the version of "
"QGIS you used to discover the error.") +
tr("<p>To remove this warning when opening an older project file, "
"uncheck the box '%5' in the %4 menu.") +
tr("<p>Version of the project file: %1<br>Current version of QGIS: %2"))
.arg(oldVersion)
.arg(QGis::qgisVersion)
.arg("<a href=https://svn.qgis.org/trac/wiki>http://svn.qgis.org/trac/wiki</a> ")
.arg(tr("<tt>Settings:Options:General</tt>", "Menu path to setting options"))
.arg(tr("Warn me when opening a project file saved with an older version of QGIS"))
);
}
return;
}
void QgisApp::setupProxy()
{
QSettings mySettings;
bool myFlag = mySettings.value("proxy/proxyEnabled", "0").toBool();
QNetworkProxy myProxy;
if (myFlag)
{
myProxy.setType(QNetworkProxy::HttpProxy);
myProxy.setHostName(mySettings.value("proxy/proxyHost", "").toString());
myProxy.setPort(mySettings.value("proxy/proxyPort", "").toInt());
myProxy.setUser(mySettings.value("proxy/proxyUser", "").toString());
myProxy.setPassword(mySettings.value("proxy/proxyPassword", "").toString());
}
else
{
// otherwise leave it blank to disable proxy usage
}
QNetworkProxy::setApplicationProxy(myProxy);
}
QIcon QgisApp::getThemeIcon(const QString theName)
{
QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
if (QFile::exists(myPreferredPath))
{
return QIcon(myPreferredPath);
}
else if (QFile::exists(myDefaultPath))
{
//could still return an empty icon if it
//doesnt exist in the default theme either!
return QIcon(myDefaultPath);
}
else
{
return QIcon();
}
}
QPixmap QgisApp::getThemePixmap(const QString theName)
{
QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
if (QFile::exists(myPreferredPath))
{
return QPixmap(myPreferredPath);
}
else
{
//could still return an empty icon if it
//doesnt exist in the default theme either!
return QPixmap(myDefaultPath);
}
}