QGIS/src/app/qgisapp.cpp
2009-10-29 13:17:57 +00:00

6387 lines
215 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 <QProgressDialog>
#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 "qgsconfigureshortcutsdialog.h"
#include "qgscoordinatetransform.h"
#include "qgscursors.h"
#include "qgscustomprojectiondialog.h"
#include "qgsencodingfiledialog.h"
#include "qgsogrsublayersdialog.h"
#include "qgsexception.h"
#include "qgsfeature.h"
#include "qgsnewvectorlayerdialog.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 "qgsmaplayerregistry.h"
#include "qgsmapoverviewcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaptip.h"
#include "qgsmergeattributesdialog.h"
#include "qgsmessageviewer.h"
#include "qgsoptions.h"
#include "qgspastetransformations.h"
#include "qgspluginitem.h"
#include "qgspluginmanager.h"
#include "qgspluginmetadata.h"
#include "qgspluginregistry.h"
#include "qgspoint.h"
#include "qgsproject.h"
#include "qgsprojectproperties.h"
#include "qgsproviderregistry.h"
#include "qgsrasterlayer.h"
#include "qgsrasterlayerproperties.h"
#include "qgsrectangle.h"
#include "qgsrenderer.h"
#include "qgswmssourceselect.h"
#include "qgsshortcutsmanager.h"
#include "qgsundowidget.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "ogr/qgsopenvectorlayerdialog.h"
#include "qgsattributetabledialog.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 "qgsmaptooldeletering.h"
#include "qgsmaptooldeletepart.h"
#include "qgsmaptooldeletevertex.h"
#include "qgsmaptoolidentify.h"
#include "qgsmaptoolmovefeature.h"
#include "qgsmaptoolmovevertex.h"
#include "qgsmaptoolnodetool.h"
#include "qgsmaptoolpan.h"
#include "qgsmaptoolselect.h"
#include "qgsmaptoolreshape.h"
#include "qgsmaptoolrotatepointsymbols.h"
#include "qgsmaptoolsplitfeatures.h"
#include "qgsmaptoolvertexedit.h"
#include "qgsmaptoolzoom.h"
#include "qgsmaptoolsimplify.h"
#include "qgsmeasuretool.h"
//
// Conditional Includes
//
#ifdef HAVE_POSTGRESQL
#include "qgspgsourceselect.h"
#endif
#ifdef HAVE_SPATIALITE
#include "qgsspatialitesourceselect.h"
#endif
#include "qgspythondialog.h"
#include "qgspythonutils.h"
#ifndef WIN32
#include <dlfcn.h>
#endif
#ifdef WIN32
#include <windows.h>
#endif
class QTreeWidgetItem;
// 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 " );
if ( QString( QGis::QGIS_VERSION ).endsWith( "Trunk" ) )
{
caption += QString( "r%1" ).arg( QGis::QGIS_SVN_VERSION );
}
else
{
caption += QGis::QGIS_VERSION;
}
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 toProj4;
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( srs->validationHint() ); //shows a generic message, if not speficied
toProj4 = QgsProject::instance()->readEntry( "SpatialRefSys", "//ProjectCRSProj4String", GEOPROJ4 );
QgsCoordinateReferenceSystem defaultCRS;
if ( defaultCRS.createFromProj4( toProj4 ) )
{
mySelector->setSelectedCrsId( defaultCRS.srsid() );
}
if ( mySelector->exec() )
{
QgsDebugMsg( "Layer srs set from dialog: " + QString::number( mySelector->selectedCrsId() ) );
srs->createFromProj4( mySelector->selectedProj4String() );
}
else
{
QApplication::restoreOverrideCursor();
}
delete mySelector;
}
else if ( myDefaultProjectionOption == "useProject" )
{
// XXX TODO: Change project to store selected CS as 'projectCRS' not 'selectedWkt'
toProj4 = QgsProject::instance()->readEntry( "SpatialRefSys", "//ProjectCRSProj4String", GEOPROJ4 );
QgsDebugMsg( "Layer srs set from project: " + toProj4 );
srs->createFromProj4( toProj4 );
}
else ///Projections/defaultBehaviour==useGlobal
{
srs->createFromProj4( mySettings.value( "/Projections/defaultProjectionString", GEOPROJ4 ).toString() );
}
}
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();
readSettings();
updateRecentProjectPaths();
mInternalClipboard = new QgsClipboard; // create clipboard
mQgisInterface = new QgisAppInterface( this ); // create the interfce
// create undo widget
mUndoWidget = new QgsUndoWidget( NULL, mMapCanvas );
addDockWidget( Qt::LeftDockWidgetArea, mUndoWidget );
mUndoWidget->hide();
// set application's icon
setWindowIcon( QPixmap( qgis_xpm ) );
#ifdef Q_WS_MAC
// action for Window menu (create before generating WindowTitleChange event))
mWindowAction = new QAction( this );
connect( mWindowAction, SIGNAL( triggered() ), this, SLOT( activate() ) );
// add this window to Window menu
addWindow( mWindowAction );
#endif
// set application's caption
QString caption = tr( "Quantum GIS - %1 ('%2')" ).arg( QGis::QGIS_VERSION ).arg( QGis::QGIS_RELEASE_NAME );
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();
QgsPluginRegistry::instance()->setQgisInterface( mQgisInterface );
QgsPluginRegistry::instance()->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;
mPrevScreenModeMaximized = false;
show();
qApp->processEvents();
//finally show all the application settings as initialised above
QgsDebugMsg( "\n\n\nApplication Settings:\n--------------------------\n" );
QgsDebugMsg( QgsApplication::showSettings() );
QgsDebugMsg( "\n--------------------------\n\n\n" );
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.mReshapeFeatures;
delete mMapTools.mSplitFeatures;
delete mMapTools.mSelect;
delete mMapTools.mVertexAdd;
delete mMapTools.mVertexMove;
delete mMapTools.mVertexDelete;
delete mMapTools.mAddRing;
delete mMapTools.mSimplifyFeature;
delete mMapTools.mDeleteRing;
delete mMapTools.mDeletePart;
delete mMapTools.mAddIsland;
delete mMapTools.mNodeTool;
delete mPythonConsole;
delete mPythonUtils;
deletePrintComposers();
// 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++ )
{
QString fileName = i->toLocalFile();
// seems that some drag and drop operations include an empty url
// so we test for length to make sure we have something
if ( !fileName.isEmpty() )
{
// check to see if we are opening a project file
QFileInfo fi( fileName );
if ( fi.completeSuffix() == "qgs" )
{
QgsDebugMsg( "Opening project " + fileName );
}
else
{
QgsDebugMsg( "Adding " + fileName + " to the map canvas" );
openLayer( fileName );
}
}
}
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()
{
QgsShortcutsManager* shortcuts = QgsShortcutsManager::instance();
// File Menu Items
mActionNewProject = new QAction( getThemeIcon( "mActionFileNew.png" ), tr( "&New Project" ), this );
shortcuts->registerAction( mActionNewProject, tr( "Ctrl+N", "New Project" ) );
mActionNewProject->setStatusTip( tr( "New Project" ) );
connect( mActionNewProject, SIGNAL( triggered() ), this, SLOT( fileNew() ) );
mActionOpenProject = new QAction( getThemeIcon( "mActionFileOpen.png" ), tr( "&Open Project..." ), this );
shortcuts->registerAction( mActionOpenProject, tr( "Ctrl+O", "Open a Project" ) );
mActionOpenProject->setStatusTip( tr( "Open a Project" ) );
connect( mActionOpenProject, SIGNAL( triggered() ), this, SLOT( fileOpen() ) );
mActionSaveProject = new QAction( getThemeIcon( "mActionFileSave.png" ), tr( "&Save Project" ), this );
shortcuts->registerAction( mActionSaveProject, tr( "Ctrl+S", "Save Project" ) );
mActionSaveProject->setStatusTip( tr( "Save Project" ) );
connect( mActionSaveProject, SIGNAL( triggered() ), this, SLOT( fileSave() ) );
mActionSaveProjectAs = new QAction( getThemeIcon( "mActionFileSaveAs.png" ), tr( "Save Project &As..." ), this );
shortcuts->registerAction( mActionSaveProjectAs, tr( "Shift+Ctrl+S", "Save Project under a new name" ) );
mActionSaveProjectAs->setStatusTip( tr( "Save Project under a new name" ) );
connect( mActionSaveProjectAs, SIGNAL( triggered() ), this, SLOT( fileSaveAs() ) );
mActionSaveMapAsImage = new QAction( getThemeIcon( "mActionSaveMapAsImage.png" ), tr( "Save as Image..." ), this );
shortcuts->registerAction( mActionSaveMapAsImage ); // tr( "Ctrl+I", "Save map as image" )
mActionSaveMapAsImage->setStatusTip( tr( "Save map as image" ) );
connect( mActionSaveMapAsImage, SIGNAL( triggered() ), this, SLOT( saveMapAsImage() ) );
mActionNewPrintComposer = new QAction( getThemeIcon( "mActionFilePrint.png" ), tr( "&New Print Composer" ), this );
shortcuts->registerAction( mActionNewPrintComposer, tr( "Ctrl+P", "New Print Composer" ) );
mActionNewPrintComposer->setStatusTip( tr( "New Print Composer" ) );
connect( mActionNewPrintComposer, SIGNAL( triggered() ), this, SLOT( newPrintComposer() ) );
mActionExit = new QAction( getThemeIcon( "mActionFileExit.png" ), tr( "Exit" ), this );
shortcuts->registerAction( mActionExit, tr( "Ctrl+Q", "Exit QGIS" ) );
mActionExit->setStatusTip( tr( "Exit QGIS" ) );
mActionExit->setMenuRole( QAction::QuitRole ); // put in Application menu on Mac OS X
connect( mActionExit, SIGNAL( triggered() ), this, SLOT( fileExit() ) );
// Edit Menu Items
#if 0
mActionCut = new QAction( tr( "Cu&t" ), this );
shortcuts->registerAction( mActionCut, tr( "Ctrl+X" ) );
mActionCut->setStatusTip( tr( "Cut the current selection's contents to the clipboard" ) );
connect( mActionCut, SIGNAL( triggered ), this, SLOT( cut() ) );
mActionCopy = new QAction( tr( "&Copy" ), this );
shortcuts->registerAction( mActionCopy, tr( "Ctrl+C" ) );
mActionCopy->setStatusTip( tr( "Copy the current selection's contents to the clipboard" ) );
connect( mActionCopy, SIGNAL( triggered ), this, SLOT( copy() ) );
mActionPaste = new QAction( tr( "&Paste" ), this );
shortcuts->registerAction( mActionPaste, tr( "Ctrl+V" ) );
mActionPaste->setStatusTip( tr( "Paste the clipboard's contents into the current selection" ) );
connect( mActionPaste, SIGNAL( triggered ), this, SLOT( paste() ) );
#endif
mActionUndo = new QAction( getThemeIcon( "mActionUndo.png" ), tr( "&Undo" ), this );
shortcuts->registerAction( mActionUndo, tr( "Ctrl+Z" ) );
mActionUndo->setStatusTip( tr( "Undo the last operation" ) );
mActionUndo->setEnabled( false );
// action connected to mUndoWidget::undo slot in setupConnections()
mActionRedo = new QAction( getThemeIcon( "mActionRedo.png" ), tr( "&Redo" ), this );
shortcuts->registerAction( mActionRedo, tr( "Ctrl+Shift+Z" ) );
mActionRedo->setStatusTip( tr( "Redo the last operation" ) );
mActionRedo->setEnabled( false );
// action connected to mUndoWidget::redo slot in setupConnections()
mActionCutFeatures = new QAction( getThemeIcon( "mActionEditCut.png" ), tr( "Cut Features" ), this );
shortcuts->registerAction( mActionCutFeatures, tr( "Ctrl+X" ) );
mActionCutFeatures->setStatusTip( tr( "Cut selected features" ) );
connect( mActionCutFeatures, SIGNAL( triggered() ), this, SLOT( editCut() ) );
mActionCutFeatures->setEnabled( false );
mActionCopyFeatures = new QAction( getThemeIcon( "mActionEditCopy.png" ), tr( "Copy Features" ), this );
shortcuts->registerAction( mActionCopyFeatures, tr( "Ctrl+C" ) );
mActionCopyFeatures->setStatusTip( tr( "Copy selected features" ) );
connect( mActionCopyFeatures, SIGNAL( triggered() ), this, SLOT( editCopy() ) );
mActionCopyFeatures->setEnabled( false );
mActionPasteFeatures = new QAction( getThemeIcon( "mActionEditPaste.png" ), tr( "Paste Features" ), this );
shortcuts->registerAction( mActionPasteFeatures, tr( "Ctrl+V" ) );
mActionPasteFeatures->setStatusTip( tr( "Paste selected features" ) );
connect( mActionPasteFeatures, SIGNAL( triggered() ), this, SLOT( editPaste() ) );
mActionPasteFeatures->setEnabled( false );
mActionCapturePoint = new QAction( getThemeIcon( "mActionCapturePoint.png" ), tr( "Capture Point" ), this );
shortcuts->registerAction( mActionCapturePoint, tr( "Ctrl+.", "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 );
shortcuts->registerAction( mActionCaptureLine, tr( "Ctrl+/", "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 );
shortcuts->registerAction( mActionCapturePolygon, tr( "Ctrl+Shift+/", "Capture Polygons" ) );
mActionCapturePolygon->setStatusTip( tr( "Capture Polygons" ) );
connect( mActionCapturePolygon, SIGNAL( triggered() ), this, SLOT( capturePolygon() ) );
mActionCapturePolygon->setEnabled( false );
mActionMoveFeature = new QAction( getThemeIcon( "mActionMoveFeature.png" ), tr( "Move Feature" ), this );
shortcuts->registerAction( mActionMoveFeature );
mActionMoveFeature->setStatusTip( tr( "Move Feature" ) );
connect( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) );
mActionMoveFeature->setEnabled( false );
mActionReshapeFeatures = new QAction( getThemeIcon( "mActionReshape.png" ), tr( "Reshape Features" ), this );
shortcuts->registerAction( mActionReshapeFeatures );
mActionReshapeFeatures->setStatusTip( tr( "Reshape Features" ) );
connect( mActionReshapeFeatures, SIGNAL( triggered() ), this, SLOT( reshapeFeatures() ) );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures = new QAction( getThemeIcon( "mActionSplitFeatures.png" ), tr( "Split Features" ), this );
shortcuts->registerAction( mActionSplitFeatures );
mActionSplitFeatures->setStatusTip( tr( "Split Features" ) );
connect( mActionSplitFeatures, SIGNAL( triggered() ), this, SLOT( splitFeatures() ) );
mActionSplitFeatures->setEnabled( false );
mActionDeleteSelected = new QAction( getThemeIcon( "mActionDeleteSelected.png" ), tr( "Delete Selected" ), this );
shortcuts->registerAction( mActionDeleteSelected );
mActionDeleteSelected->setStatusTip( tr( "Delete Selected" ) );
connect( mActionDeleteSelected, SIGNAL( triggered() ), this, SLOT( deleteSelected() ) );
mActionDeleteSelected->setEnabled( false );
mActionAddVertex = new QAction( getThemeIcon( "mActionAddVertex.png" ), tr( "Add Vertex" ), this );
shortcuts->registerAction( mActionAddVertex );
mActionAddVertex->setStatusTip( tr( "Add Vertex" ) );
connect( mActionAddVertex, SIGNAL( triggered() ), this, SLOT( addVertex() ) );
mActionAddVertex->setEnabled( false );
mActionMoveVertex = new QAction( getThemeIcon( "mActionMoveVertex.png" ), tr( "Move Vertex" ), this );
shortcuts->registerAction( mActionMoveVertex );
mActionMoveVertex->setStatusTip( tr( "Move Vertex" ) );
connect( mActionMoveVertex, SIGNAL( triggered() ), this, SLOT( moveVertex() ) );
mActionMoveVertex->setEnabled( false );
mActionDeleteVertex = new QAction( getThemeIcon( "mActionDeleteVertex.png" ), tr( "Delete Vertex" ), this );
shortcuts->registerAction( mActionDeleteVertex );
mActionDeleteVertex->setStatusTip( tr( "Delete Vertex" ) );
connect( mActionDeleteVertex, SIGNAL( triggered() ), this, SLOT( deleteVertex() ) );
mActionDeleteVertex->setEnabled( false );
mActionAddRing = new QAction( getThemeIcon( "mActionAddRing.png" ), tr( "Add Ring" ), this );
shortcuts->registerAction( mActionAddRing );
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 );
shortcuts->registerAction( mActionAddIsland );
mActionAddIsland->setStatusTip( tr( "Add Island to multipolygon" ) );
connect( mActionAddIsland, SIGNAL( triggered() ), this, SLOT( addIsland() ) );
mActionAddIsland->setEnabled( false );
mActionSimplifyFeature = new QAction( getThemeIcon( "mActionSimplify.png" ), tr( "Simplify Feature" ), this );
shortcuts->registerAction( mActionSimplifyFeature );
mActionSimplifyFeature->setStatusTip( tr( "Simplify Feature" ) );
connect( mActionSimplifyFeature, SIGNAL( triggered() ), this, SLOT( simplifyFeature() ) );
mActionSimplifyFeature->setEnabled( false );
mActionDeleteRing = new QAction( getThemeIcon( "mActionDeleteRing.png" ), tr( "Delete Ring" ), this );
shortcuts->registerAction( mActionDeleteRing );
mActionDeleteRing->setStatusTip( tr( "Delete Ring" ) );
connect( mActionDeleteRing, SIGNAL( triggered() ), this, SLOT( deleteRing() ) );
mActionDeleteRing->setEnabled( false );
mActionDeletePart = new QAction( getThemeIcon( "mActionDeletePart.png" ), tr( "Delete Part" ), this );
shortcuts->registerAction( mActionDeletePart );
mActionDeletePart->setStatusTip( tr( "Delete Part" ) );
connect( mActionDeletePart, SIGNAL( triggered() ), this, SLOT( deletePart() ) );
mActionDeletePart->setEnabled( false );
mActionMergeFeatures = new QAction( getThemeIcon( "mActionMergeFeatures.png" ), tr( "Merge selected features" ), this );
shortcuts->registerAction( mActionMergeFeatures );
mActionMergeFeatures->setStatusTip( tr( "Merge selected features" ) );
connect( mActionMergeFeatures, SIGNAL( triggered() ), this, SLOT( mergeSelectedFeatures() ) );
mActionMergeFeatures->setEnabled( false );
mActionNodeTool = new QAction( getThemeIcon( "mActionNodeTool.png" ), tr( "Node Tool" ), this );
shortcuts->registerAction( mActionNodeTool );
mActionNodeTool->setStatusTip( tr( "Node Tool" ) );
connect( mActionNodeTool, SIGNAL( triggered() ), this, SLOT( nodeTool() ) );
mActionNodeTool->setEnabled( false );
mActionRotatePointSymbols = new QAction( getThemeIcon( "mActionRotatePointSymbols.png" ), tr( "Rotate Point Symbols" ), this );
shortcuts->registerAction( mActionRotatePointSymbols );
mActionRotatePointSymbols->setStatusTip( tr( "Rotate Point Symbols" ) );
connect( mActionRotatePointSymbols, SIGNAL( triggered() ), this, SLOT( rotatePointSymbols() ) );
mActionRotatePointSymbols->setEnabled( false );
// View Menu Items
mActionPan = new QAction( getThemeIcon( "mActionPan.png" ), tr( "Pan Map" ), this );
shortcuts->registerAction( mActionPan );
mActionPan->setStatusTip( tr( "Pan the map" ) );
connect( mActionPan, SIGNAL( triggered() ), this, SLOT( pan() ) );
mActionZoomIn = new QAction( getThemeIcon( "mActionZoomIn.png" ), tr( "Zoom In" ), this );
shortcuts->registerAction( mActionZoomIn, 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 );
shortcuts->registerAction( mActionZoomOut, tr( "Ctrl+-", "Zoom Out" ) );
mActionZoomOut->setStatusTip( tr( "Zoom Out" ) );
connect( mActionZoomOut, SIGNAL( triggered() ), this, SLOT( zoomOut() ) );
mActionSelect = new QAction( getThemeIcon( "mActionSelect.png" ), tr( "Select Features" ), this );
shortcuts->registerAction( mActionSelect );
mActionSelect->setStatusTip( tr( "Select Features" ) );
connect( mActionSelect, SIGNAL( triggered() ), this, SLOT( select() ) );
mActionSelect->setEnabled( false );
mActionIdentify = new QAction( getThemeIcon( "mActionIdentify.png" ), tr( "Identify Features" ), this );
shortcuts->registerAction( mActionIdentify, tr( "Ctrl+Shift+I", "Click on features to identify them" ) );
mActionIdentify->setStatusTip( tr( "Click on features to identify them" ) );
connect( mActionIdentify, SIGNAL( triggered() ), this, SLOT( identify() ) );
mActionIdentify->setEnabled( QSettings().value( "/Map/identifyMode", 0 ).toInt() != 0 );
mActionMeasure = new QAction( getThemeIcon( "mActionMeasure.png" ), tr( "Measure Line " ), this );
shortcuts->registerAction( mActionMeasure, tr( "Ctrl+Shift+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 );
shortcuts->registerAction( mActionMeasureArea, tr( "Ctrl+Shift+J", "Measure an Area" ) );
mActionMeasureArea->setStatusTip( tr( "Measure an Area" ) );
connect( mActionMeasureArea, SIGNAL( triggered() ), this, SLOT( measureArea() ) );
mActionZoomFullExtent = new QAction( getThemeIcon( "mActionZoomFullExtent.png" ), tr( "Zoom Full" ), this );
shortcuts->registerAction( mActionZoomFullExtent, tr( "Ctrl+Shift+F", "Zoom to Full Extents" ) );
mActionZoomFullExtent->setStatusTip( tr( "Zoom to Full Extents" ) );
connect( mActionZoomFullExtent, SIGNAL( triggered() ), this, SLOT( zoomFull() ) );
mActionZoomToLayer = new QAction( getThemeIcon( "mActionZoomToLayer.png" ), tr( "Zoom to Layer" ), this );
shortcuts->registerAction( mActionZoomToLayer ); // tr("Ctrl+O","Zoom to Layer")
mActionZoomToLayer->setStatusTip( tr( "Zoom to Layer" ) );
connect( mActionZoomToLayer, SIGNAL( triggered() ), this, SLOT( zoomToLayerExtent() ) );
mActionZoomToSelected = new QAction( getThemeIcon( "mActionZoomToSelected.png" ), tr( "Zoom to Selection" ), this );
shortcuts->registerAction( mActionZoomToSelected, tr( "Ctrl+J", "Zoom to Selection" ) );
mActionZoomToSelected->setStatusTip( tr( "Zoom to Selection" ) );
connect( mActionZoomToSelected, SIGNAL( triggered() ), this, SLOT( zoomToSelected() ) );
mActionZoomLast = new QAction( getThemeIcon( "mActionZoomLast.png" ), tr( "Zoom Last" ), this );
shortcuts->registerAction( mActionZoomLast ); // tr("Ctrl+O","Zoom to Last Extent")
mActionZoomLast->setStatusTip( tr( "Zoom to Last Extent" ) );
connect( mActionZoomLast, SIGNAL( triggered() ), this, SLOT( zoomToPrevious() ) );
mActionZoomNext = new QAction( getThemeIcon( "mActionZoomNext.png" ), tr( "Zoom Next" ), this );
shortcuts->registerAction( mActionZoomNext );
mActionZoomNext->setStatusTip( tr( "Zoom to Forward Extent" ) );
connect( mActionZoomNext, SIGNAL( triggered() ), this, SLOT( zoomToNext() ) );
mActionZoomActualSize = new QAction( tr( "Zoom Actual Size" ), this );
shortcuts->registerAction( mActionZoomActualSize );
mActionZoomActualSize->setStatusTip( tr( "Zoom to Actual Size" ) );
connect( mActionZoomActualSize, SIGNAL( triggered() ), this, SLOT( zoomActualSize() ) );
mActionZoomActualSize->setEnabled( false );
mActionMapTips = new QAction( getThemeIcon( "mActionMapTips.png" ), tr( "Map Tips" ), this );
shortcuts->registerAction( mActionMapTips );
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 );
mActionNewBookmark = new QAction( getThemeIcon( "mActionNewBookmark.png" ), tr( "New Bookmark..." ), this );
shortcuts->registerAction( mActionNewBookmark, tr( "Ctrl+B", "New Bookmark" ) );
mActionNewBookmark->setStatusTip( tr( "New Bookmark" ) );
connect( mActionNewBookmark, SIGNAL( triggered() ), this, SLOT( newBookmark() ) );
mActionShowBookmarks = new QAction( getThemeIcon( "mActionShowBookmarks.png" ), tr( "Show Bookmarks" ), this );
shortcuts->registerAction( mActionShowBookmarks, tr( "Ctrl+Shift+B", "Show Bookmarks" ) );
mActionShowBookmarks->setStatusTip( tr( "Show Bookmarks" ) );
connect( mActionShowBookmarks, SIGNAL( triggered() ), this, SLOT( showBookmarks() ) );
mActionDraw = new QAction( getThemeIcon( "mActionDraw.png" ), tr( "Refresh" ), this );
shortcuts->registerAction( mActionDraw, tr( "Ctrl+R", "Refresh Map" ) );
mActionDraw->setStatusTip( tr( "Refresh Map" ) );
connect( mActionDraw, SIGNAL( triggered() ), this, SLOT( refreshMapCanvas() ) );
// Layer Menu Items
mActionNewVectorLayer = new QAction( getThemeIcon( "mActionNewVectorLayer.png" ), tr( "New Vector Layer..." ), this );
shortcuts->registerAction( mActionNewVectorLayer, tr( "Ctrl+Shift+N", "Create a New Vector Layer" ) );
mActionNewVectorLayer->setStatusTip( tr( "Create a New Vector Layer" ) );
connect( mActionNewVectorLayer, SIGNAL( triggered() ), this, SLOT( newVectorLayer() ) );
mActionAddOgrLayer = new QAction( getThemeIcon( "mActionAddOgrLayer.png" ), tr( "Add Vector Layer..." ), this );
shortcuts->registerAction( mActionAddOgrLayer, tr( "Ctrl+Shift+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 Raster Layer..." ), this );
shortcuts->registerAction( mActionAddRasterLayer, tr( "Ctrl+Shift+R", "Add a Raster Layer" ) );
mActionAddRasterLayer->setStatusTip( tr( "Add a Raster Layer" ) );
connect( mActionAddRasterLayer, SIGNAL( triggered() ), this, SLOT( addRasterLayer() ) );
mActionAddPgLayer = new QAction( getThemeIcon( "mActionAddLayer.png" ), tr( "Add PostGIS Layer..." ), this );
shortcuts->registerAction( mActionAddPgLayer, tr( "Ctrl+Shift+D", "Add a PostGIS Layer" ) );
mActionAddPgLayer->setStatusTip( tr( "Add a PostGIS Layer" ) );
//#ifdef HAVE_POSTGRESQL
// QgsDebugMsg("HAVE_POSTGRESQL is defined");
// assert(0);
//#else
// QgsDebugMsg("HAVE_POSTGRESQL not defined");
// assert(0);
//#endif
connect( mActionAddPgLayer, SIGNAL( triggered() ), this, SLOT( addDatabaseLayer() ) );
mActionAddSpatiaLiteLayer = new QAction( getThemeIcon( "mActionAddSpatiaLiteLayer.png" ), tr( "Add SpatiaLite Layer..." ), this );
shortcuts->registerAction( mActionAddSpatiaLiteLayer, tr( "Ctrl+Shift+L", "Add a SpatiaLite Layer" ) );
mActionAddSpatiaLiteLayer->setStatusTip( tr( "Add a SpatiaLite Layer" ) );
connect( mActionAddSpatiaLiteLayer, SIGNAL( triggered() ), this, SLOT( addSpatiaLiteLayer() ) );
//#ifdef HAVE_SPATIALITE
// QgsDebugMsg("HAVE_SPATIALITE is defined");
// assert(0);
//#else
// QgsDebugMsg("HAVE_SPATIALITE not defined");
// assert(0);
//#endif
mActionAddWmsLayer = new QAction( getThemeIcon( "mActionAddWmsLayer.png" ), tr( "Add WMS Layer..." ), this );
shortcuts->registerAction( mActionAddWmsLayer, tr( "Ctrl+Shift+W", "Add a Web Mapping Server Layer" ) );
mActionAddWmsLayer->setStatusTip( tr( "Add a Web Mapping Server Layer" ) );
connect( mActionAddWmsLayer, SIGNAL( triggered() ), this, SLOT( addWmsLayer() ) );
mActionOpenTable = new QAction( getThemeIcon( "mActionOpenTable.png" ), tr( "Open Attribute Table" ), this );
shortcuts->registerAction( mActionOpenTable ); // tr("Ctrl+O","Open Table")
mActionOpenTable->setStatusTip( tr( "Open Attribute Table" ) );
connect( mActionOpenTable, SIGNAL( triggered() ), this, SLOT( attributeTable() ) );
mActionOpenTable->setEnabled( false );
mActionToggleEditing = new QAction( getThemeIcon( "mActionToggleEditing.png" ), tr( "Toggle editing" ), this );
shortcuts->registerAction( mActionToggleEditing );
mActionToggleEditing->setStatusTip( tr( "Toggles the editing state of the current layer" ) );
mActionToggleEditing->setCheckable( true );
connect( mActionToggleEditing, SIGNAL( triggered() ), this, SLOT( toggleEditing() ) );
mActionToggleEditing->setEnabled( false );
mActionLayerSaveAs = new QAction( tr( "Save as Shapefile..." ), this );
shortcuts->registerAction( mActionLayerSaveAs );
mActionLayerSaveAs->setStatusTip( tr( "Save the current layer as a shapefile" ) );
connect( mActionLayerSaveAs, SIGNAL( triggered() ), this, SLOT( saveAsShapefile() ) );
mActionLayerSaveAs->setEnabled( false );
mActionLayerSelectionSaveAs = new QAction( tr( "Save Selection as Shapefile..." ), this );
shortcuts->registerAction( mActionLayerSelectionSaveAs );
mActionLayerSelectionSaveAs->setStatusTip( tr( "Save the selection as a shapefile" ) );
connect( mActionLayerSelectionSaveAs, SIGNAL( triggered() ), this, SLOT( saveSelectionAsShapefile() ) );
mActionLayerSelectionSaveAs->setEnabled( false );
mActionRemoveLayer = new QAction( getThemeIcon( "mActionRemoveLayer.png" ), tr( "Remove Layer" ), this );
shortcuts->registerAction( mActionRemoveLayer, tr( "Ctrl+D", "Remove a Layer" ) );
mActionRemoveLayer->setStatusTip( tr( "Remove a Layer" ) );
connect( mActionRemoveLayer, SIGNAL( triggered() ), this, SLOT( removeLayer() ) );
mActionRemoveLayer->setEnabled( false );
mActionLayerProperties = new QAction( tr( "Properties..." ), this );
shortcuts->registerAction( mActionLayerProperties );
mActionLayerProperties->setStatusTip( tr( "Set properties of the current layer" ) );
connect( mActionLayerProperties, SIGNAL( triggered() ), this, SLOT( layerProperties() ) );
mActionLayerProperties->setEnabled( false );
mActionAddToOverview = new QAction( getThemeIcon( "mActionInOverview.png" ), tr( "Add to Overview" ), this );
shortcuts->registerAction( mActionAddToOverview, tr( "Ctrl+Shift+O", "Add current layer to overview map" ) );
mActionAddToOverview->setStatusTip( tr( "Add current layer to overview map" ) );
connect( mActionAddToOverview, SIGNAL( triggered() ), this, SLOT( isInOverview() ) );
mActionAddToOverview->setEnabled( false );
mActionAddAllToOverview = new QAction( getThemeIcon( "mActionAddAllToOverview.png" ), tr( "Add All to Overview" ), this );
shortcuts->registerAction( mActionAddAllToOverview ); //, 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 );
shortcuts->registerAction( mActionRemoveAllFromOverview ); //, tr( "-", "Remove all layers from overview map" ) );
mActionRemoveAllFromOverview->setStatusTip( tr( "Remove all layers from overview map" ) );
connect( mActionRemoveAllFromOverview, SIGNAL( triggered() ), this, SLOT( removeAllFromOverview() ) );
mActionShowAllLayers = new QAction( getThemeIcon( "mActionShowAllLayers.png" ), tr( "Show All Layers" ), this );
shortcuts->registerAction( mActionShowAllLayers, tr( "Ctrl+Shift+U", "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 );
shortcuts->registerAction( mActionHideAllLayers, tr( "Ctrl+Shift+H", "Hide all layers" ) );
mActionHideAllLayers->setStatusTip( tr( "Hide all layers" ) );
connect( mActionHideAllLayers, SIGNAL( triggered() ), this, SLOT( hideAllLayers() ) );
// Plugin Menu Items
mActionManagePlugins = new QAction( getThemeIcon( "mActionShowPluginManager.png" ), tr( "Manage Plugins..." ), this );
shortcuts->registerAction( mActionManagePlugins ); // tr("Ctrl+P","Open the plugin manager")
mActionManagePlugins->setStatusTip( tr( "Open the plugin manager" ) );
connect( mActionManagePlugins, SIGNAL( triggered() ), this, SLOT( showPluginManager() ) );
// Settings Menu Items
mActionToggleFullScreen = new QAction( getThemeIcon( "mActionToggleFullScreen.png" ), tr( "Toggle Full Screen Mode" ), this );
shortcuts->registerAction( mActionToggleFullScreen, tr( "Ctrl-F", "Toggle fullscreen mode" ) );
mActionToggleFullScreen->setStatusTip( tr( "Toggle fullscreen mode" ) );
connect( mActionToggleFullScreen, SIGNAL( triggered() ), this, SLOT( toggleFullScreen() ) );
mActionProjectProperties = new QAction( getThemeIcon( "mActionProjectProperties.png" ), tr( "Project Properties..." ), this );
shortcuts->registerAction( mActionProjectProperties, tr( "Ctrl+Shift+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 );
shortcuts->registerAction( mActionOptions ); // tr("Alt+O","Change various QGIS options")
mActionOptions->setStatusTip( tr( "Change various QGIS options" ) );
mActionOptions->setMenuRole( QAction::PreferencesRole ); // put in application menu on Mac OS X
connect( mActionOptions, SIGNAL( triggered() ), this, SLOT( options() ) );
mActionCustomProjection = new QAction( getThemeIcon( "mActionCustomProjection.png" ), tr( "Custom CRS..." ), this );
shortcuts->registerAction( mActionCustomProjection ); // tr("Alt+I","Manage custom projections")
mActionCustomProjection->setStatusTip( tr( "Manage custom coordinate reference systems" ) );
// mActionCustomProjection->setMenuRole( QAction::ApplicationSpecificRole ); // put in application menu on Mac OS X
connect( mActionCustomProjection, SIGNAL( triggered() ), this, SLOT( customProjection() ) );
mActionConfigureShortcuts = new QAction( getThemeIcon( "mActionOptions.png" ), tr( "Configure shortcuts..." ), this );
shortcuts->registerAction( mActionConfigureShortcuts );
mActionConfigureShortcuts->setStatusTip( tr( "Configure shortcuts" ) );
connect( mActionConfigureShortcuts, SIGNAL( triggered() ), this, SLOT( configureShortcuts() ) );
#ifdef Q_WS_MAC
// Window Menu Items
mActionWindowMinimize = new QAction( tr( "Minimize" ), this );
shortcuts->registerAction( mActionWindowMinimize, tr( "Ctrl+M", "Minimize Window" ) );
mActionWindowMinimize->setStatusTip( tr( "Minimizes the active window to the dock" ) );
connect( mActionWindowMinimize, SIGNAL( triggered() ), this, SLOT( showActiveWindowMinimized() ) );
mActionWindowZoom = new QAction( tr( "Zoom" ), this );
shortcuts->registerAction( mActionWindowZoom );
mActionWindowZoom->setStatusTip( tr( "Toggles between a predefined size and the window size set by the user" ) );
connect( mActionWindowZoom, SIGNAL( triggered() ), this, SLOT( toggleActiveWindowMaximized() ) );
mActionWindowAllToFront = new QAction( tr( "Bring All to Front" ), this );
shortcuts->registerAction( mActionWindowAllToFront );
mActionWindowAllToFront->setStatusTip( tr( "Bring forward all open windows" ) );
connect( mActionWindowAllToFront, SIGNAL( triggered() ), this, SLOT( bringAllToFront() ) );
// list of open windows
mWindowActions = new QActionGroup( this );
#endif
// Help Menu Items
mActionHelpContents = new QAction( getThemeIcon( "mActionHelpContents.png" ), tr( "Help Contents" ), this );
#ifdef Q_WS_MAC
shortcuts->registerAction( mActionHelpContents, tr( "Ctrl+?", "Help Documentation (Mac)" ) );
#else
shortcuts->registerAction( mActionHelpContents, 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
shortcuts->registerAction( mActionQgisHomePage, tr( "Ctrl+H", "QGIS Home Page" ) );
#else
shortcuts->registerAction( mActionQgisHomePage );
#endif
mActionQgisHomePage->setStatusTip( tr( "QGIS Home Page" ) );
connect( mActionQgisHomePage, SIGNAL( triggered() ), this, SLOT( helpQgisHomePage() ) );
mActionCheckQgisVersion = new QAction( getThemeIcon( "mActionCheckQgisVersion.png" ), tr( "Check Qgis Version" ), this );
shortcuts->registerAction( mActionCheckQgisVersion );
mActionCheckQgisVersion->setStatusTip( tr( "Check if your QGIS version is up to date (requires internet access)" ) );
connect( mActionCheckQgisVersion, SIGNAL( triggered() ), this, SLOT( checkQgisVersion() ) );
mActionAbout = new QAction( getThemeIcon( "mActionHelpAbout.png" ), tr( "About" ), this );
shortcuts->registerAction( mActionAbout );
mActionAbout->setStatusTip( tr( "About QGIS" ) );
mActionAbout->setMenuRole( QAction::AboutRole ); // put in application menu on Mac OS X
connect( mActionAbout, SIGNAL( triggered() ), this, SLOT( about() ) );
}
void QgisApp::showPythonDialog()
{
if ( !mPythonUtils || !mPythonUtils->isEnabled() )
return;
if ( mPythonConsole == NULL )
mPythonConsole = new QgsPythonDialog( mQgisInterface, mPythonUtils );
mPythonConsole->show();
mPythonConsole->raise();
mPythonConsole->setWindowState( mPythonConsole->windowState() & ~Qt::WindowMinimized );
mPythonConsole->activateWindow();
}
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 );
mActionReshapeFeatures->setCheckable( true );
mMapToolGroup->addAction( mActionReshapeFeatures );
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 );
mActionSimplifyFeature->setCheckable( true );
mMapToolGroup->addAction( mActionSimplifyFeature );
mActionDeleteRing->setCheckable( true );
mMapToolGroup->addAction( mActionDeleteRing );
mActionDeletePart->setCheckable( true );
mMapToolGroup->addAction( mActionDeletePart );
mMapToolGroup->addAction( mActionMergeFeatures );
mActionNodeTool->setCheckable( true );
mMapToolGroup->addAction( mActionNodeTool );
mActionRotatePointSymbols->setCheckable( true );
mMapToolGroup->addAction( mActionRotatePointSymbols );
}
void QgisApp::createMenus()
{
/*
* The User Interface Guidelines for each platform specify different locations
* for the following items.
*
* Project Properties:
* Gnome, Mac - File menu above print commands
* Kde, Win - Settings menu (Win doesn't specify)
*
* Custom CRS, Options:
* Gnome - bottom of Edit menu
* Mac - Application menu (moved automatically by Qt)
* Kde, Win - Settings menu (Win should use Tools menu but we don't have one)
*
* Panel and Toolbar submenus, Toggle Full Screen:
* Gnome, Mac, Win - View menu
* Kde - Settings menu
*
* For Mac, About and Exit are also automatically moved by Qt to the Application menu.
*/
// Get platform for menu layout customization (Gnome, Kde, Mac, Win)
QDialogButtonBox::ButtonLayout layout =
QDialogButtonBox::ButtonLayout( style()->styleHint( QStyle::SH_DialogButtonLayout, 0, this ) );
// File Menu
mFileMenu = menuBar()->addMenu( tr( "&File" ) );
mFileMenu->addAction( mActionNewProject );
mFileMenu->addAction( mActionOpenProject );
mRecentProjectsMenu = mFileMenu->addMenu( tr( "&Open Recent Projects" ) );
// Connect once for the entire submenu.
connect( mRecentProjectsMenu, SIGNAL( triggered( QAction * ) ),
this, SLOT( openProject( QAction * ) ) );
mActionFileSeparator1 = mFileMenu->addSeparator();
mFileMenu->addAction( mActionSaveProject );
mFileMenu->addAction( mActionSaveProjectAs );
mFileMenu->addAction( mActionSaveMapAsImage );
mActionFileSeparator2 = mFileMenu->addSeparator();
if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
mFileMenu->addAction( mActionProjectProperties );
mActionFileSeparator3 = mFileMenu->addSeparator();
}
mFileMenu->addAction( mActionNewPrintComposer );
mActionFileSeparator4 = mFileMenu->addSeparator();
mFileMenu->addAction( mActionExit );
// Edit Menu
mEditMenu = menuBar()->addMenu( tr( "&Edit" ) );
#if 0
mEditMenu->addAction( mActionCut );
mEditMenu->addAction( mActionCopy );
mEditMenu->addAction( mActionPaste );
#endif
mEditMenu->addAction( mActionUndo );
mEditMenu->addAction( mActionRedo );
mActionEditSeparator0 = mEditMenu->addSeparator();
mEditMenu->addAction( mActionCutFeatures );
mEditMenu->addAction( mActionCopyFeatures );
mEditMenu->addAction( mActionPasteFeatures );
mActionEditSeparator1 = mEditMenu->addSeparator();
mEditMenu->addAction( mActionCapturePoint );
mEditMenu->addAction( mActionCaptureLine );
mEditMenu->addAction( mActionCapturePolygon );
mEditMenu->addAction( mActionMoveFeature );
mEditMenu->addAction( mActionDeleteSelected );
mEditMenu->addAction( mActionAddVertex );
mEditMenu->addAction( mActionMoveVertex );
mEditMenu->addAction( mActionDeleteVertex );
mActionEditSeparator2 = mEditMenu->addSeparator();
mEditMenu->addAction( mActionSimplifyFeature );
mEditMenu->addAction( mActionAddRing );
mEditMenu->addAction( mActionAddIsland );
mEditMenu->addAction( mActionDeleteRing );
mEditMenu->addAction( mActionDeletePart );
mEditMenu->addAction( mActionReshapeFeatures );
mEditMenu->addAction( mActionSplitFeatures );
mEditMenu->addAction( mActionMergeFeatures );
mEditMenu->addAction( mActionNodeTool );
mEditMenu->addAction( mActionRotatePointSymbols );
if ( layout == QDialogButtonBox::GnomeLayout || layout == QDialogButtonBox::MacLayout )
{
mActionEditSeparator3 = mEditMenu->addSeparator();
mEditMenu->addAction( mActionOptions );
mEditMenu->addAction( mActionConfigureShortcuts );
mEditMenu->addAction( mActionCustomProjection );
}
// Panel and Toolbar Submenus
mPanelMenu = new QMenu( tr( "Panels" ) );
mToolbarMenu = new QMenu( tr( "Toolbars" ) );
// View Menu
mViewMenu = menuBar()->addMenu( tr( "&View" ) );
mViewMenu->addAction( mActionPan );
mViewMenu->addAction( mActionZoomIn );
mViewMenu->addAction( mActionZoomOut );
mViewMenu->addAction( mActionSelect );
mViewMenu->addAction( mActionIdentify );
mViewMenu->addAction( mActionMeasure );
mViewMenu->addAction( mActionMeasureArea );
mActionViewSeparator1 = mViewMenu->addSeparator();
mViewMenu->addAction( mActionZoomFullExtent );
mViewMenu->addAction( mActionZoomToLayer );
mViewMenu->addAction( mActionZoomToSelected );
mViewMenu->addAction( mActionZoomLast );
mViewMenu->addAction( mActionZoomNext );
mViewMenu->addAction( mActionZoomActualSize );
mActionViewSeparator2 = mViewMenu->addSeparator();
mViewMenu->addAction( mActionMapTips );
mViewMenu->addAction( mActionNewBookmark );
mViewMenu->addAction( mActionShowBookmarks );
mViewMenu->addAction( mActionDraw );
if ( layout != QDialogButtonBox::KdeLayout )
{
mActionViewSeparator3 = mViewMenu->addSeparator();
mViewMenu->addMenu( mPanelMenu );
mViewMenu->addMenu( mToolbarMenu );
mViewMenu->addAction( mActionToggleFullScreen );
}
// Layers Menu
mLayerMenu = menuBar()->addMenu( tr( "&Layer" ) );
mLayerMenu->addAction( mActionNewVectorLayer );
mLayerMenu->addAction( mActionAddOgrLayer );
mLayerMenu->addAction( mActionAddRasterLayer );
#ifdef HAVE_POSTGRESQL
mLayerMenu->addAction( mActionAddPgLayer );
#endif
#ifdef HAVE_SPATIALITE
mLayerMenu->addAction( mActionAddSpatiaLiteLayer );
#endif
mLayerMenu->addAction( mActionAddWmsLayer );
mActionLayerSeparator1 = mLayerMenu->addSeparator();
mLayerMenu->addAction( mActionOpenTable );
mLayerMenu->addAction( mActionToggleEditing );
mLayerMenu->addAction( mActionLayerSaveAs );
mLayerMenu->addAction( mActionLayerSelectionSaveAs );
mLayerMenu->addAction( mActionRemoveLayer );
mLayerMenu->addAction( mActionLayerProperties );
mActionLayerSeparator2 = mLayerMenu->addSeparator();
mLayerMenu->addAction( mActionAddToOverview );
mLayerMenu->addAction( mActionAddAllToOverview );
mLayerMenu->addAction( mActionRemoveAllFromOverview );
mActionLayerSeparator3 = mLayerMenu->addSeparator();
mLayerMenu->addAction( mActionHideAllLayers );
mLayerMenu->addAction( mActionShowAllLayers );
// Settings Menu
#ifndef Q_WS_MAC
if ( layout == QDialogButtonBox::KdeLayout || layout == QDialogButtonBox::WinLayout )
{
mSettingsMenu = menuBar()->addMenu( tr( "&Settings" ) );
#ifndef Q_WS_WIN
mSettingsMenu->addMenu( mPanelMenu );
mSettingsMenu->addMenu( mToolbarMenu );
mSettingsMenu->addAction( mActionToggleFullScreen );
mActionSettingsSeparator1 = mSettingsMenu->addSeparator();
#endif
mSettingsMenu->addAction( mActionProjectProperties );
mSettingsMenu->addAction( mActionCustomProjection );
mSettingsMenu->addAction( mActionConfigureShortcuts );
mSettingsMenu->addAction( mActionOptions );
}
#endif
// Plugins Menu
mPluginMenu = menuBar()->addMenu( tr( "&Plugins" ) );
mPluginMenu->addAction( mActionManagePlugins );
mActionPluginSeparator1 = NULL; // plugin list separator will be created when the first plugin is loaded
mActionPluginSeparator2 = NULL; // python separator will be created only if python is found
#ifdef Q_WS_MAC
// Window Menu
mWindowMenu = menuBar()->addMenu( tr( "&Window" ) );
mWindowMenu->addAction( mActionWindowMinimize );
mWindowMenu->addAction( mActionWindowZoom );
mActionWindowSeparator1 = mWindowMenu->addSeparator();
mWindowMenu->addAction( mActionWindowAllToFront );
mActionWindowSeparator2 = mWindowMenu->addSeparator();
#endif
//Print composers menu
mPrintComposersMenu = menuBar()->addMenu( tr( "Print Composers" ) );
// Help Menu
menuBar()->addSeparator();
mHelpMenu = menuBar()->addMenu( tr( "&Help" ) );
mHelpMenu->addAction( mActionHelpContents );
mActionHelpSeparator1 = mHelpMenu->addSeparator();
mHelpMenu->addAction( mActionQgisHomePage );
mHelpMenu->addAction( mActionCheckQgisVersion );
mActionHelpSeparator2 = mHelpMenu->addSeparator();
mHelpMenu->addAction( mActionAbout );
}
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( mActionNewProject );
mFileToolBar->addAction( mActionOpenProject );
mFileToolBar->addAction( mActionSaveProject );
mFileToolBar->addAction( mActionSaveProjectAs );
mFileToolBar->addAction( mActionNewPrintComposer );
mFileToolBar->addAction( mActionAddOgrLayer );
mFileToolBar->addAction( mActionAddRasterLayer );
#ifdef HAVE_POSTGRESQL
mFileToolBar->addAction( mActionAddPgLayer );
#endif
#ifdef HAVE_SPATIALITE
mFileToolBar->addAction( mActionAddSpatiaLiteLayer );
#endif
mFileToolBar->addAction( mActionAddWmsLayer );
mToolbarMenu->addAction( mFileToolBar->toggleViewAction() );
//
// Layer Toolbar
mLayerToolBar = addToolBar( tr( "Manage Layers" ) );
mLayerToolBar->setIconSize( myIconSize );
mLayerToolBar->setObjectName( "LayerToolBar" );
mLayerToolBar->addAction( mActionNewVectorLayer );
mLayerToolBar->addAction( mActionRemoveLayer );
mLayerToolBar->addAction( mActionAddToOverview );
mLayerToolBar->addAction( mActionShowAllLayers );
mLayerToolBar->addAction( mActionHideAllLayers );
mToolbarMenu->addAction( mLayerToolBar->toggleViewAction() );
//
// 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( mActionMoveFeature );
mDigitizeToolBar->addAction( mActionMoveVertex );
mDigitizeToolBar->addAction( mActionAddVertex );
mDigitizeToolBar->addAction( mActionDeleteVertex );
mDigitizeToolBar->addAction( mActionDeleteSelected );
mDigitizeToolBar->addAction( mActionCutFeatures );
mDigitizeToolBar->addAction( mActionCopyFeatures );
mDigitizeToolBar->addAction( mActionPasteFeatures );
mToolbarMenu->addAction( mDigitizeToolBar->toggleViewAction() );
mAdvancedDigitizeToolBar = addToolBar( tr( "Advanced Digitizing" ) );
mAdvancedDigitizeToolBar->setIconSize( myIconSize );
mAdvancedDigitizeToolBar->setObjectName( "Advanced Digitizing" );
mAdvancedDigitizeToolBar->addAction( mActionUndo );
mAdvancedDigitizeToolBar->addAction( mActionRedo );
mAdvancedDigitizeToolBar->addAction( mActionSimplifyFeature );
mAdvancedDigitizeToolBar->addAction( mActionAddRing );
mAdvancedDigitizeToolBar->addAction( mActionAddIsland );
mAdvancedDigitizeToolBar->addAction( mActionDeleteRing );
mAdvancedDigitizeToolBar->addAction( mActionDeletePart );
mAdvancedDigitizeToolBar->addAction( mActionReshapeFeatures );
mAdvancedDigitizeToolBar->addAction( mActionSplitFeatures );
mAdvancedDigitizeToolBar->addAction( mActionMergeFeatures );
mAdvancedDigitizeToolBar->addAction( mActionNodeTool );
mAdvancedDigitizeToolBar->addAction( mActionRotatePointSymbols );
mToolbarMenu->addAction( mAdvancedDigitizeToolBar->toggleViewAction() );
//
// 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( mActionZoomNext );
mMapNavToolBar->addAction( mActionDraw );
mToolbarMenu->addAction( mMapNavToolBar->toggleViewAction() );
//
// 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 );
mToolbarMenu->addAction( mAttributesToolBar->toggleViewAction() );
//
// Plugins Toolbar
mPluginToolBar = addToolBar( tr( "Plugins" ) );
mPluginToolBar->setIconSize( myIconSize );
mPluginToolBar->setObjectName( "Plugins" );
mToolbarMenu->addAction( mPluginToolBar->toggleViewAction() );
//
// Help Toolbar
mHelpToolBar = addToolBar( tr( "Help" ) );
mHelpToolBar->setIconSize( myIconSize );
mHelpToolBar->setObjectName( "Help" );
mHelpToolBar->addAction( mActionHelpContents );
mHelpToolBar->addAction( QWhatsThis::createAction() );
mToolbarMenu->addAction( mHelpToolBar->toggleViewAction() );
}
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 );
// add a label to show current scale
mCoordsLabel = new QLabel( QString(), statusBar() );
mCoordsLabel->setFont( myFont );
mCoordsLabel->setMinimumWidth( 10 );
mCoordsLabel->setMaximumHeight( 20 );
mCoordsLabel->setMargin( 3 );
mCoordsLabel->setAlignment( Qt::AlignCenter );
mCoordsLabel->setFrameStyle( QFrame::NoFrame );
mCoordsLabel->setText( tr( "Coordinate:" ) );
mCoordsLabel->setToolTip( tr( "Current map coordinate" ) );
statusBar()->addPermanentWidget( mCoordsLabel, 0 );
//coords status bar widget
mCoordsEdit = new QLineEdit( QString(), statusBar() );
mCoordsEdit->setFont( myFont );
mCoordsEdit->setMinimumWidth( 10 );
mCoordsEdit->setMaximumWidth( 200 );
mCoordsEdit->setMaximumHeight( 20 );
mCoordsEdit->setContentsMargins( 0, 0, 0, 0 );
mCoordsEdit->setAlignment( Qt::AlignCenter );
mCoordsEdit->setAlignment( Qt::AlignCenter );
QRegExp coordValidator( "[+-]?\\d+\\.?\\d*\\s*,\\s*[+-]?\\d+\\.?\\d*" );
mCoordsEditValidator = new QRegExpValidator( coordValidator, mCoordsEdit );
mCoordsEdit->setWhatsThis( tr( "Shows the map coordinates at the "
"current cursor position. The display is continuously updated "
"as the mouse is moved. It also allows editing to set the canvas "
"center to a given position." ) );
mCoordsEdit->setToolTip( tr( "Current map coordinate (formatted as x,y)" ) );
statusBar()->addPermanentWidget( mCoordsEdit, 0 );
connect( mCoordsEdit, SIGNAL( editingFinished() ), this, SLOT( userCenter() ) );
// 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);
mActionNewProject->setIcon( getThemeIcon( "/mActionFileNew.png" ) );
mActionOpenProject->setIcon( getThemeIcon( "/mActionFileOpen.png" ) );
mActionSaveProject->setIcon( getThemeIcon( "/mActionFileSave.png" ) );
mActionSaveProjectAs->setIcon( getThemeIcon( "/mActionFileSaveAs.png" ) );
mActionNewPrintComposer->setIcon( getThemeIcon( "/mActionNewComposer.png" ) );
mActionSaveMapAsImage->setIcon( getThemeIcon( "/mActionSaveMapAsImage.png" ) );
mActionExit->setIcon( getThemeIcon( "/mActionFileExit.png" ) );
mActionAddOgrLayer->setIcon( getThemeIcon( "/mActionAddOgrLayer.png" ) );
mActionAddRasterLayer->setIcon( getThemeIcon( "/mActionAddRasterLayer.png" ) );
mActionAddPgLayer->setIcon( getThemeIcon( "/mActionAddLayer.png" ) );
mActionAddSpatiaLiteLayer->setIcon( getThemeIcon( "/mActionAddSpatiaLiteLayer.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" ) );
mActionToggleFullScreen->setIcon( getThemeIcon( "/mActionToggleFullScreen.png" ) );
mActionProjectProperties->setIcon( getThemeIcon( "/mActionProjectProperties.png" ) );
mActionManagePlugins->setIcon( getThemeIcon( "/mActionShowPluginManager.png" ) );
mActionCheckQgisVersion->setIcon( getThemeIcon( "/mActionCheckQgisVersion.png" ) );
mActionOptions->setIcon( getThemeIcon( "/mActionOptions.png" ) );
mActionConfigureShortcuts->setIcon( getThemeIcon( "/mActionOptions.png" ) );
mActionHelpContents->setIcon( getThemeIcon( "/mActionHelpContents.png" ) );
mActionQgisHomePage->setIcon( getThemeIcon( "/mActionQgisHomePage.png" ) );
mActionAbout->setIcon( getThemeIcon( "/mActionHelpAbout.png" ) );
mActionDraw->setIcon( getThemeIcon( "/mActionDraw.png" ) );
mActionToggleEditing->setIcon( getThemeIcon( "/mActionToggleEditing.png" ) );
mActionCutFeatures->setIcon( getThemeIcon( "/mActionEditCut.png" ) );
mActionCopyFeatures->setIcon( getThemeIcon( "/mActionEditCopy.png" ) );
mActionPasteFeatures->setIcon( getThemeIcon( "/mActionEditPaste.png" ) );
mActionCapturePoint->setIcon( getThemeIcon( "/mActionCapturePoint.png" ) );
mActionCaptureLine->setIcon( getThemeIcon( "/mActionCaptureLine.png" ) );
mActionCapturePolygon->setIcon( getThemeIcon( "/mActionCapturePolygon.png" ) );
mActionMoveFeature->setIcon( getThemeIcon( "/mActionMoveFeature.png" ) );
mActionReshapeFeatures->setIcon( getThemeIcon( "/mActionReshape.png" ) );
mActionSplitFeatures->setIcon( getThemeIcon( "/mActionSplitFeatures.png" ) );
mActionDeleteSelected->setIcon( getThemeIcon( "/mActionDeleteSelected.png" ) );
mActionAddVertex->setIcon( getThemeIcon( "/mActionAddVertex.png" ) );
mActionMoveVertex->setIcon( getThemeIcon( "/mActionMoveVertex.png" ) );
mActionDeleteVertex->setIcon( getThemeIcon( "/mActionDeleteVertex.png" ) );
mActionSimplifyFeature->setIcon( getThemeIcon( "/mActionSimplify.png" ) );
mActionUndo->setIcon( getThemeIcon( "/mActionUndo.png" ) );
mActionRedo->setIcon( getThemeIcon( "/mActionRedo.png" ) );
mActionAddRing->setIcon( getThemeIcon( "/mActionAddRing.png" ) );
mActionAddIsland->setIcon( getThemeIcon( "/mActionAddIsland.png" ) );
mActionDeleteRing->setIcon( getThemeIcon( "/mActionDeleteRing.png" ) );
mActionDeletePart->setIcon( getThemeIcon( "/mActionDeletePart.png" ) );
mActionMergeFeatures->setIcon( getThemeIcon( "/mActionMergeFeatures.png" ) );
mActionNodeTool->setIcon( getThemeIcon( "/mActionNodeTool.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" ) );
mActionZoomNext->setIcon( getThemeIcon( "/mActionZoomNext.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" ) );
mActionMapTips->setIcon( getThemeIcon( "/mActionMapTips.png" ) );
mActionShowBookmarks->setIcon( getThemeIcon( "/mActionShowBookmarks.png" ) );
mActionNewBookmark->setIcon( getThemeIcon( "/mActionNewBookmark.png" ) );
mActionCustomProjection->setIcon( getThemeIcon( "/mActionCustomProjection.png" ) );
mActionAddWmsLayer->setIcon( getThemeIcon( "/mActionAddWmsLayer.png" ) );
mActionAddToOverview->setIcon( getThemeIcon( "/mActionInOverview.png" ) );
//change themes of all composers
QMap<QString, QgsComposer*>::iterator composerIt = mPrintComposers.begin();
for ( ; composerIt != mPrintComposers.end(); ++composerIt )
{
composerIt.value()->setupTheme();
}
emit currentThemeChanged( theThemeName );
}
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* ) ) );
connect( mMapLegend, SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
mUndoWidget, SLOT( layerChanged( QgsMapLayer* ) ) );
connect( mMapLegend, SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
mMapTools.mNodeTool, SLOT( currentLayerChanged( QgsMapLayer* ) ) );
//signal when mouse moved over window (coords display in status bar)
connect( mMapCanvas, SIGNAL( xyCoordinates( const QgsPoint & ) ), this, SLOT( showMouseCoordinate( const QgsPoint & ) ) );
connect( mMapCanvas->mapRenderer(), SIGNAL( drawingProgress( int, int ) ), this, SLOT( showProgress( int, int ) ) );
connect( mMapCanvas->mapRenderer(), SIGNAL( hasCrsTransformEnabled( bool ) ), this, SLOT( hasCrsTransformEnabled( 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( mMapCanvas, SIGNAL( selectionChanged( QgsMapLayer * ) ),
this, SLOT( activateDeactivateLayerRelatedActions( QgsMapLayer * ) ) );
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( oldProjectVersionWarning( QString ) ),
this, SLOT( oldProjectVersionWarning( QString ) ) );
connect( QgsProject::instance(), SIGNAL( layerLoaded( int, int ) ), this, SLOT( showProgress( int, int ) ) );
// setup undo/redo actions
connect( mActionUndo, SIGNAL( triggered() ), mUndoWidget, SLOT( undo() ) );
connect( mActionRedo, SIGNAL( triggered() ), mUndoWidget, SLOT( redo() ) );
connect( mUndoWidget, SIGNAL( undoStackChanged() ), this, SLOT( updateUndoActions() ) );
}
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 );
mActionCapturePoint->setVisible( false );
mMapTools.mCaptureLine = new QgsMapToolAddFeature( mMapCanvas, QgsMapToolCapture::CaptureLine );
mMapTools.mCaptureLine->setAction( mActionCaptureLine );
mActionCaptureLine->setVisible( false );
mMapTools.mCapturePolygon = new QgsMapToolAddFeature( mMapCanvas, QgsMapToolCapture::CapturePolygon );
mMapTools.mCapturePolygon->setAction( mActionCapturePolygon );
mActionCapturePolygon->setVisible( false );
mMapTools.mMoveFeature = new QgsMapToolMoveFeature( mMapCanvas );
mMapTools.mMoveFeature->setAction( mActionMoveFeature );
mMapTools.mReshapeFeatures = new QgsMapToolReshape( mMapCanvas );
mMapTools.mReshapeFeatures->setAction( mActionReshapeFeatures );
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 );
mMapTools.mSimplifyFeature = new QgsMapToolSimplify( mMapCanvas );
mMapTools.mSimplifyFeature->setAction( mActionSimplifyFeature );
mMapTools.mDeleteRing = new QgsMapToolDeleteRing( mMapCanvas );
mMapTools.mDeleteRing->setAction( mActionDeleteRing );
mMapTools.mDeletePart = new QgsMapToolDeletePart( mMapCanvas );
mMapTools.mDeletePart->setAction( mActionDeletePart );
mMapTools.mNodeTool = new QgsMapToolNodeTool( mMapCanvas );
mMapTools.mNodeTool->setAction( mActionNodeTool );
mMapTools.mRotatePointSymbolsTool = new QgsMapToolRotatePointSymbols( mMapCanvas );
mMapTools.mRotatePointSymbolsTool->setAction( mActionRotatePointSymbols );
//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, 0, 0 ); //set upper left corner as hot spot - this is better when extent marker is small; hand won't cover the marker
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 );
// add to the Panel submenu
mPanelMenu->addAction( mOverviewDock->toggleViewAction() );
mMapCanvas->enableOverviewMode( 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->useImageToRender( 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 Panel submenu
mPanelMenu->addAction( thepDockWidget->toggleViewAction() );
thepDockWidget->show();
// refresh the map canvas
mMapCanvas->refresh();
}
QToolBar *QgisApp::addToolBar( QString name )
{
QToolBar *toolBar = QMainWindow::addToolBar( name );
// add to the Toolbar submenu
mToolbarMenu->addAction( toolBar->toggleViewAction() );
return toolBar;
}
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( "Layers" ), this );
mLegendDock->setObjectName( "Legend" );
mLegendDock->setAllowedAreas( Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea );
mLegendDock->setWidget( mMapLegend );
addDockWidget( Qt::LeftDockWidgetArea, mLegendDock );
// add to the Panel submenu
mPanelMenu->addAction( mLegendDock->toggleViewAction() );
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", saveState() );
// store window geometry
settings.setValue( "/UI/geometry", saveGeometry() );
QgsPluginRegistry::instance()->unloadAll();
}
static const unsigned char defaultUIgeometry[] =
{
0x01, 0xd9, 0xd0, 0xcb, 0x00, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x04, 0xb8, 0x00, 0x00, 0x03, 0x22, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x02, 0xaf, 0x00, 0x00, 0x02, 0x22, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00
};
static const unsigned char defaultUIstate[] =
{
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x87, 0xfc, 0x02, 0x00, 0x00, 0x00, 0x03, 0xfb, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x4c, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x72, 0x00, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x10, 0x00, 0x4f, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x65, 0x00, 0x77, 0x00, 0x00, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x14, 0x00, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x22, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x43, 0x00, 0x61, 0x00, 0x70, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00, 0x00, 0x00, 0x01, 0x7e, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x03, 0xaf, 0x00, 0x00, 0x02, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x16, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x42, 0x00, 0x61, 0x00, 0x72, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x65, 0x00, 0x72, 0x00, 0x54, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x42, 0x00, 0x61, 0x00, 0x72, 0x01, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x41, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x62, 0x00, 0x75, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x01, 0x00, 0x00, 0x02, 0x4e, 0x00, 0x00, 0x01, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x48, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0xd9, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x75, 0x00, 0x67, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x73, 0x01, 0x00, 0x00, 0x03, 0x75, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x7a, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x4d, 0x00, 0x61, 0x00, 0x70, 0x00, 0x20, 0x00, 0x4e, 0x00, 0x61, 0x00, 0x76, 0x00, 0x69, 0x00, 0x67, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x02, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00
};
void QgisApp::restoreWindowState()
{
// restore the toolbar and dock widgets postions using Qt4 settings API
QSettings settings;
if ( !restoreState( settings.value( "/UI/state", QByteArray::fromRawData(( char * )defaultUIstate, sizeof defaultUIstate ) ).toByteArray() ) )
{
QgsDebugMsg( "restore of UI state failed" );
}
// restore window geometry
if ( !restoreGeometry( settings.value( "/UI/geometry", QByteArray::fromRawData(( char * )defaultUIgeometry, sizeof defaultUIgeometry ) ).toByteArray() ) )
{
QgsDebugMsg( "restore of UI geometry failed" );
}
}
///////////// 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::QGIS_VERSION )
.arg( QGis::QGIS_SVN_VERSION );
#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
#ifdef HAVE_SPATIALITE
versionString += tr( "\nThis copy of QGIS has been built with SpatiaLite support." );
#else
versionString += tr( "\nThis copy of QGIS has been built without SpatiaLite 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>" ;
whatsNew += "<h2>" + tr( "Version" ) + " " + QString( QGis::QGIS_VERSION ) + "</h2>";
whatsNew += "<h3>" + tr( "Whats new in Version 1.3.0?" ) + "</h3>"
+
"<p>"
+ tr( "Please note that this is a release in our 'cutting edge' release series. As "
"such it contains new features and extends the programmatic interface over "
"QGIS 1.0.x and QGIS 1.2.0. If an unchanging user interface, programmatic API "
"and long term support is more important to you then cool new and untested "
"features, we recommend that you use a copy of QGIS from our Long Term Support "
"(LTS)1.0.x release series." )
+
"</p><p>"
+
tr( "This release includes over 30 bug fixes and enhancements "
"over the QGIS 1.2.0 release. In addition we have added "
"the following new features:" )
+ tr( "<p>OSM plugin &amp; provider updates:</p>\n"
"<ul>\n"
" <li>new OSM style files.</li>\n"
" <li>new icons.</li>\n"
" <li>dialog text updated and completed.</li>\n"
" <li>Saving OSM into file functionality was improvements.</li>\n"
" <li>fixed some problems with encoding... ascii to utf-8.</li>\n"
" <li>all OSM layers are automatically removed after disabling OSM plugin in plugin manager.</li>\n"
" <li>other OSM related bugfixes.</li>\n"
"</ul>\n"
"<p>Other notable features and improvements in this release</p>\n"
"<ul>\n"
" <li>Marker size is now configurable when editing a layer.</li>\n"
" <li>Incorporation of the analysis library into the mainstream release.</li>\n"
" <li>Identify features across multiple layers.</li>\n"
" <li>Added a new plugin for carrying out raster terrain analysis (computing slope aspect, steepness etc).</li>\n"
" <li>A reshape tool to apply to line/polygon geometries. The part of a geometry between the first and\n"
" last intersection of the reshape line will be replaced.</li>\n"
" <li>Added snapping to current layer in measure dialog.</li>\n"
" <li>Added ability to select the primary key for views.</li>\n"
" <li>Zoom to a coordinate by entering it in the status bar coordinate display.</li>\n"
"</ul>" )
+ "</body></html>";
abt->setWhatsNew( whatsNew );
QApplication::restoreOverrideCursor();
}
abt->show();
abt->raise();
abt->activateWindow();
}
/**
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 )
{
QgsDebugMsg( QString( "unable to get driver %1" ).arg( 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
QgsDebugMsg( myFileFilters );
// 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.
This method returns true if cancel all was clicked, otherwise false
*/
static bool openFilesRememberingFilter_( QString const &filterName,
QString const &filters, QStringList & selectedFiles, QString& enc, QString &title,
bool cancelAll = false )
{
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();
QgsDebugMsg( "Opening file dialog with filters: " + filters );
if ( !cancelAll )
{
selectedFiles = QFileDialog::getOpenFileNames( 0, title, lastUsedDir, filters, &lastUsedFilter );
}
else //we have to use non-native dialog to add cancel all button
{
QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog( 0, title, lastUsedDir, filters, QString( "" ) );
// 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 );
}
openFileDialog->addCancelAll();
if ( openFileDialog->exec() == QDialog::Accepted )
{
selectedFiles = openFileDialog->selectedFiles();
}
else
{
//cancel or cancel all?
if ( openFileDialog->cancelAll() )
{
return true;
}
}
}
if ( !selectedFiles.isEmpty() )
{
// 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, lastUsedFilter );
settings.setValue( "/UI/" + filterName + "Dir", myPath );
}
return false;
} // openFilesRememberingFilter_
/**
This method prompts the user for a list of vector file names with a dialog.
*/
void QgisApp::addVectorLayer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
mMapCanvas->freeze();
QgsOpenVectorLayerDialog *ovl = new QgsOpenVectorLayerDialog( this );
if ( ovl->exec() )
{
QStringList selectedSources = ovl->dataSources();
QString enc = ovl->encoding();
if ( !selectedSources.isEmpty() )
{
addVectorLayers( selectedSources, enc, ovl->dataSourceType() );
}
}
mMapCanvas->freeze( false );
delete ovl;
// update UI
qApp->processEvents();
}
bool QgisApp::addVectorLayers( QStringList const & theLayerQStringList, const QString& enc, const QString dataSourceType )
{
for ( QStringList::ConstIterator it = theLayerQStringList.begin();
it != theLayerQStringList.end();
++it )
{
QString base;
if ( dataSourceType == "file" )
{
QFileInfo fi( *it );
base = fi.completeBaseName();
}
else if ( dataSourceType == "database" )
{
base = *it;
}
else //directory //protocol
{
QFileInfo fi( *it );
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 );
QStringList sublayers = layer->dataProvider()->subLayers();
// If the newly created layer has more than 1 layer of data available, we show the
// sublayers selection dialog so the user can select the sublayers to actually load.
if ( sublayers.count() > 1 )
{
askUserForSublayers( layer );
// The first layer loaded is not usefull in that case. The user can select it in
// the list if he wants to load it.
delete layer;
}
else // there is 1 layer of data available
{
//set friendly name for datasources with only one layer
QStringList sublayers = layer->dataProvider()->subLayers();
QString ligne = sublayers.at( 0 );
QStringList elements = ligne.split( ":" );
layer->setLayerName( elements.at( 1 ) );
// 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 = tr( "%1 is not a valid or recognized data source" ).arg( *it );
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 method is the method that does the real job. If the layer given in
// parameter is NULL, then the method tries to act on the activeLayer.
void QgisApp::askUserForSublayers( QgsVectorLayer *layer )
{
if ( layer == NULL )
{
if ( activeLayer() == NULL || activeLayer()->type() != QgsMapLayer::VectorLayer )
return;
layer = ( QgsVectorLayer* ) activeLayer();
if ( layer->dataProvider()->name() != "ogr" )
return;
}
QStringList sublayers = layer->dataProvider()->subLayers();
QString layertype = layer->dataProvider()->storageType();
// We initialize a selection dialog and display it.
QgsOGRSublayersDialog chooseSublayersDialog( this );
chooseSublayersDialog.populateLayerTable( sublayers );
if ( chooseSublayersDialog.exec() )
{
QString uri = layer->source();
//the separator char & was changed to | to be compatible
//with url for protocol drivers
if ( uri.contains( '|', Qt::CaseSensitive ) )
{
// If we get here, there are some options added to the filename.
// A valid uri is of the form: filename&option1=value1&option2=value2,...
// We want only the filename here, so we get the first part of the split.
QStringList theURIParts = uri.split( "|" );
uri = theURIParts.at( 0 );
}
QgsDebugMsg( "Layer type " + layertype );
// the user has done his choice
loadOGRSublayers( layertype , uri, chooseSublayersDialog.getSelection() );
}
}
// This method will load with OGR the layers in parameter.
// This method has been conceived to use the new URI
// format of the ogrprovider so as to give precisions about which
// sublayer to load into QGIS. It is normally triggered by the
// sublayer selection dialog.
void QgisApp::loadOGRSublayers( QString layertype, QString uri, QStringList list )
{
// The uri must contain the actual uri of the vectorLayer from which we are
// going to load the sublayers.
QString fileName = QFileInfo( uri ).baseName();
for ( int i = 0; i < list.size(); i++ )
{
QString composedURI;
if ( layertype != "GRASS" )
{
composedURI = uri + "|layername=" + list.at( i );
}
else
{
composedURI = uri + "|layerindex=" + list.at( i );
}
addVectorLayer( composedURI, list.at( i ), "ogr" );
}
}
/** This helper checks to see whether the file name 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
QgsPgSourceSelect *dbs = new QgsPgSourceSelect( 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 connectionInfo = dbs->connectionInfo();
// for each selected table, connect to the database, parse the Wkt geometry,
// and build a canvasitem for it
// readWKB(connectionInfo,tables);
QStringList::Iterator it = tables.begin();
while ( it != tables.end() )
{
// create the layer
//qWarning("creating layer");
QgsVectorLayer *layer = new QgsVectorLayer( connectionInfo + " " + *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
#ifndef HAVE_SPATIALITE
void QgisApp::addSpatiaLiteLayer() {}
#else
void QgisApp::addSpatiaLiteLayer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
// show the SpatiaLite dialog
QgsSpatiaLiteSourceSelect *dbs = new QgsSpatiaLiteSourceSelect( 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 connectionInfo = dbs->connectionInfo();
// for each selected table, connect to the database and build a canvasitem for it
QStringList::Iterator it = tables.begin();
while ( it != tables.end() )
{
// normalizing the layer name
QString layername = *it;
layername = layername.mid( 1 );
int idx = layername.indexOf( "\" (" );
if ( idx > 0 )
layername.truncate( idx );
// create the layer
//qWarning("creating layer");
QgsVectorLayer *layer = new QgsVectorLayer( "dbname='" + connectionInfo + "' table=" + *it + ")", layername, "spatialite" );
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::addSpatiaLiteLayer()
#endif
void QgisApp::addWmsLayer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
// Fudge for now
QgsDebugMsg( "about to addRasterLayer" );
QgsWMSSourceSelect *wmss = new QgsWMSSourceSelect( this );
wmss->exec();
}
/// 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
bool
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 false;
}
// 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 '%1' (original location: %2)?" )
.arg( originalDataSource.fileName() )
.arg( originalDataSource.absoluteFilePath() );
bool retVal = openFilesRememberingFilter_( memoryQualifier,
myFileFilters,
selectedFiles,
enc,
title,
true );
if ( selectedFiles.isEmpty() )
{
return retVal;
}
else
{
setDataSource_( layerNode, selectedFiles.first() );
if ( ! QgsProject::instance()->read( layerNode ) )
{
QgsDebugMsg( "unable to re-read layer" );
}
}
return retVal;
} // 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
bool
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 );
bool retVal = false;
switch ( providerType_( layerNode ) )
{
case IS_FILE:
QgsDebugMsg( "layer is file based" );
retVal = 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;
}
return retVal;
} // 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, std::list<QDomNode> const & layerNodes )
{
for ( std::list<QDomNode>::const_iterator i = layerNodes.begin();
i != layerNodes.end();
++i )
{
if ( findLayer_( fileFilters, *i ) )
{
// If findLayer returns true, the user hit Cancel All button
break;
}
}
} // findLayers_
void QgisApp::fileExit()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
if ( saveDirty() )
{
deletePrintComposers();
mMapCanvas->freeze( true );
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;
}
deletePrintComposers();
if ( thePromptToSaveFlag )
{
if ( !saveDirty() )
{
return; //cancel pressed
}
}
//QgsDebugMsg("erasing project");
mMapCanvas->freeze( true );
removeAllLayers();
mMapCanvas->clear();
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;
QgsNewVectorLayerDialog geomDialog( this );
if ( geomDialog.exec() == QDialog::Rejected )
{
return;
}
geometrytype = geomDialog.selectedType();
fileformat = geomDialog.selectedFileFormat();
QgsDebugMsg( QString( "New file format will be: %1" ).arg( fileformat ) );
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();
QgsDebugMsg( "Saving vector file dialog without filters: " );
QgsEncodingFileDialog* openFileDialog = new QgsEncodingFileDialog( this,
tr( "Save As" ), lastUsedDir, "", QString( "" ) );
// 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() );
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 );
//todo: the last parameter will change accordingly to layer type
addVectorLayers( fileNames, enc, "file" );
}
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();
QString fullPath = QFileDialog::getOpenFileName( this, tr( "Choose a QGIS project file to open" ), lastUsedDir, tr( "QGis files (*.qgs)" ) );
if ( fullPath.isNull() )
{
return;
}
// Fix by Tim - getting the dirPath from the dialog
// directly truncates the last node in the dir path.
// This is a workaround for that
QFileInfo myFI( fullPath );
QString myPath = myFI.path();
// Persist last used project dir
settings.setValue( "/UI/lastProjectDir", myPath );
deletePrintComposers();
// clear out any stuff from previous project
mMapCanvas->freeze( true );
removeAllLayers();
QgsProject::instance()->setFileName( fullPath );
try
{
if ( ! QgsProject::instance()->read() )
{
mMapCanvas->freeze( false );
mMapCanvas->refresh();
return;
}
}
catch ( QgsProjectBadLayerException & e )
{
QMessageBox::critical( this,
tr( "QGIS Project Read Error" ),
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() );
// Tell the legend to update the ordering
mMapLegend->readProject( e.document() );
}
catch ( std::exception & e )
{
QMessageBox::critical( this,
tr( "QGIS Project Read Error" ),
QString::fromLocal8Bit( e.what() ) );
QgsDebugMsg( "BAD QgsMapLayer::LayerType FOUND" );
mMapCanvas->freeze( false );
mMapCanvas->refresh();
return;
}
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
//load the composers in the project
loadComposersFromProject( fullPath );
// add this to the list of recently used project files
saveRecentProjectPath( fullPath, settings );
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 );
QApplication::setOverrideCursor( Qt::WaitCursor );
deletePrintComposers();
// clear the map canvas
removeAllLayers();
try
{
if ( ! QgsProject::instance()->read( projectFile ) )
{
mMapCanvas->freeze( false );
mMapCanvas->refresh();
return false;
}
// Continue after last catch statement
}
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( "%1\nTry to find missing layers?" ).arg( QString::fromLocal8Bit( e.what() ) ),
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?
QApplication::restoreOverrideCursor();
findLayers_( mVectorFileFilter, e.layers() );
QApplication::setOverrideCursor( Qt::WaitCursor );
// Tell the legend to update the ordering
mMapLegend->readProject( e.document() );
}
// Continue after last catch statement
}
catch ( std::exception & e )
{
QgsDebugMsg( "BAD QgsMapLayer::LayerType FOUND" );
QMessageBox::critical( this,
tr( "Unable to open project" ),
QString::fromLocal8Bit( e.what() ) );
QApplication::restoreOverrideCursor();
mMapCanvas->freeze( false );
mMapCanvas->refresh();
return false;
}
// Continue, now with layers found (hopefully)
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..." );
mMapCanvas->updateScale();
QgsDebugMsg( "Scale 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
loadComposersFromProject( projectFile );
// add this to the list of recently used project files
QSettings settings;
saveRecentProjectPath( projectFile, settings );
QApplication::restoreOverrideCursor();
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 file name, 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, 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: %1" ).arg( 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 %1" ).arg( QgsProject::instance()->fileName() ) );
return false;
}
}
catch ( std::exception & e )
{
QMessageBox::critical( this,
tr( "Unable to save project %1" ).arg( QgsProject::instance()->fileName() ),
QString::fromLocal8Bit( e.what() ) );
return false;
}
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();
QString saveFilePath = QFileDialog::getSaveFileName( this, tr( "Choose a file name to save the QGIS project file as" ), lastUsedDir, tr( "QGis files (*.qgs)" ) );
if ( saveFilePath.isNull() ) //canceled
{
return;
}
QFileInfo myFI( saveFilePath );
QString myPath = myFI.path();
settings.setValue( "/UI/lastProjectDir", myPath );
// make sure the .qgs extension is included in the path name. if not, add it...
if ( "qgs" != myFI.suffix() )
{
saveFilePath = myFI.filePath() + ".qgs";
}
try
{
QgsProject::instance()->setFileName( saveFilePath );
if ( QgsProject::instance()->write() )
{
setTitleBarText_( *this ); // update title bar
statusBar()->showMessage( tr( "Saved project to: %1" ).arg( QgsProject::instance()->fileName() ) );
// add this to the list of recently used project files
saveRecentProjectPath( saveFilePath, settings );
}
else
{
QMessageBox::critical( this,
tr( "Unable to save project" ),
tr( "Unable to save project to %1" ).arg( QgsProject::instance()->fileName() ) );
}
}
catch ( std::exception & e )
{
QMessageBox::critical( 0x0,
tr( "Unable to save project %1" ).arg( 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 );
}
}
catch ( QgsIOException & io_exception )
{
Q_UNUSED( io_exception );
QMessageBox::critical( this,
tr( "QGIS: Unable to load project" ),
tr( "Unable to load project %1" ).arg( 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, fileInfo.completeBaseName() );
else // nope - try to load it as a shape/ogr
ok = addVectorLayer( fileName, fileInfo.completeBaseName(), "ogr" );
CPLPopErrorHandler();
if ( !ok )
{
// we have no idea what this file is...
QgsDebugMsg( "Unable to load " + fileName );
}
return ok;
}
void QgisApp::newPrintComposer()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
{
return;
}
//ask user about name
bool composerExists = true;
QString composerId;
while ( composerExists )
{
composerId = QInputDialog::getText( 0, tr( "Enter id string for composer" ), tr( "id:" ) );
if ( composerId.isNull() )
{
return;
}
if ( mPrintComposers.contains( composerId ) )
{
QMessageBox::critical( 0, tr( "Composer id already exists" ), tr( "The entered composer id '%1' already exists. Please enter a different id" ).arg( composerId ) );
}
else
{
composerExists = false;
}
}
//create new composer object
QgsComposer* newComposerObject = new QgsComposer( this, composerId );
//add it to the map of existing print composers
mPrintComposers.insert( composerId, newComposerObject );
//and place action into print composers menu
mPrintComposersMenu->addAction( newComposerObject->windowAction() );
newComposerObject->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 file name 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 %1" ).arg( 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->enableOverviewModeAllLayers( 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->enableOverviewModeAllLayers( false );
}
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::toggleFullScreen()
{
if ( true == mFullScreenMode )
{
if ( true == mPrevScreenModeMaximized )
{
// Change to maximized state. Just calling showMaximized() results in
// the window going to the normal state. Calling showNormal() then
// showMaxmized() is a work-around. Turn off rendering for this as it
// would otherwise cause two re-renders of the map, which can take a
// long time.
bool renderFlag = mapCanvas()->renderFlag();
mapCanvas()->setRenderFlag( false );
showNormal();
showMaximized();
mapCanvas()->setRenderFlag( renderFlag );
mPrevScreenModeMaximized = false;
}
else
{
showNormal();
}
mFullScreenMode = false;
}
else
{
if ( isMaximized() )
{
mPrevScreenModeMaximized = true;
}
showFullScreen();
mFullScreenMode = true;
}
}
void QgisApp::showActiveWindowMinimized()
{
QWidget *window = QApplication::activeWindow();
if ( window )
{
window->showMinimized();
}
}
void QgisApp::toggleActiveWindowMaximized()
{
QWidget *window = QApplication::activeWindow();
if ( window )
{
if ( window->isMaximized() ) window->showNormal();
else window->showMaximized();
}
}
void QgisApp::activate()
{
raise();
setWindowState( windowState() & ~Qt::WindowMinimized );
activateWindow();
}
void QgisApp::bringAllToFront()
{
#ifdef Q_WS_MAC
// Bring forward all open windows while maintaining layering order
ProcessSerialNumber psn;
GetCurrentProcess( &psn );
SetFrontProcess( &psn );
#endif
}
void QgisApp::addWindow( QAction *action )
{
#ifdef Q_WS_MAC
mWindowActions->addAction( action );
mWindowMenu->addAction( action );
action->setCheckable( true );
action->setChecked( true );
#endif
}
void QgisApp::removeWindow( QAction *action )
{
#ifdef Q_WS_MAC
mWindowActions->removeAction( action );
mWindowMenu->removeAction( action );
#endif
}
void QgisApp::stopRendering()
{
if ( mMapCanvas )
{
QgsMapRenderer* mypMapRenderer = mMapCanvas->mapRenderer();
if ( mypMapRenderer )
{
QgsRenderContext* mypRenderContext = mypMapRenderer->rendererContext();
if ( mypRenderContext )
{
mypRenderContext->setRenderingStopped( true );
}
}
}
}
//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->zoomToFullExtent();
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::zoomToPrevious()
{
mMapCanvas->zoomToPreviousExtent();
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::zoomToNext()
{
mMapCanvas->zoomToNextExtent();
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::zoomActualSize()
{
mMapLegend->legendLayerZoomNative();
}
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;
}
QgsVectorLayer * myLayer = qobject_cast<QgsVectorLayer *>( mMapLegend->currentLayer() );
QgsAttributeTableDialog *mDialog = new QgsAttributeTableDialog( myLayer );
mDialog->show();
// the dialog will be deleted by itself on close
}
void QgisApp::saveAsShapefile()
{
mMapLegend->currentLayerFile()->saveAsShapefile();
}
void QgisApp::saveSelectionAsShapefile()
{
mMapLegend->currentLayerFile()->saveSelectionAsShapefile();
}
void QgisApp::layerProperties()
{
mMapLegend->legendLayerShowProperties();
}
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 = qobject_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;
}
//display a warning
int numberOfDeletedFeatures = vlayer->selectedFeaturesIds().size();
if ( QMessageBox::warning( this, tr( "Delete features" ), tr( "Delete %n feature(s)?", "number of features to delete", numberOfDeletedFeatures ), QMessageBox::Ok, QMessageBox::Cancel ) == QMessageBox::Cancel )
{
return;
}
vlayer->beginEditCommand( tr( "Features deleted" ) );
if ( !vlayer->deleteSelectedFeatures() )
{
QMessageBox::information( this, tr( "Problem deleting features" ),
tr( "A problem occured during deletion of features" ) );
}
vlayer->endEditCommand();
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::moveFeature()
{
mMapCanvas->setMapTool( mMapTools.mMoveFeature );
}
void QgisApp::simplifyFeature()
{
mMapCanvas->setMapTool( mMapTools.mSimplifyFeature );
}
void QgisApp::deleteRing()
{
mMapCanvas->setMapTool( mMapTools.mDeleteRing );
}
void QgisApp::deletePart()
{
mMapCanvas->setMapTool( mMapTools.mDeletePart );
}
QgsGeometry* QgisApp::unionGeometries( const QgsVectorLayer* vl, QgsFeatureList& featureList )
{
if ( !vl || featureList.size() < 2 )
{
return 0;
}
QgsGeometry* unionGeom = featureList[0].geometry();
QgsGeometry* backupPtr = 0; //pointer to delete intermediate results
if ( !unionGeom )
{
return 0;
}
QProgressDialog progress( tr( "Merging features..." ), tr( "Abort" ), 0, featureList.size(), this );
progress.setWindowModality( Qt::WindowModal );
QApplication::setOverrideCursor( Qt::WaitCursor );
for ( int i = 1; i < featureList.size(); ++i )
{
if ( progress.wasCanceled() )
{
delete unionGeom;
QApplication::restoreOverrideCursor();
return 0;
}
progress.setValue( i );
QgsGeometry* currentGeom = featureList[i].geometry();
if ( currentGeom )
{
backupPtr = unionGeom;
unionGeom = unionGeom->combine( currentGeom );
if ( i > 1 ) //delete previous intermediate results
{
delete backupPtr;
backupPtr = 0;
}
}
}
QApplication::restoreOverrideCursor();
progress.setValue( featureList.size() );
return unionGeom;
}
QList<QgsComposer*> QgisApp::printComposers()
{
QList<QgsComposer*> composerList;
QMap<QString, QgsComposer*>::iterator it = mPrintComposers.begin();
for ( ; it != mPrintComposers.end(); ++it )
{
composerList.push_back( it.value() );
}
return composerList;
}
void QgisApp::checkOutComposer( QgsComposer* c )
{
if ( !c )
{
return;
}
mPrintComposers.remove( c->id() );
mPrintComposersMenu->removeAction( c->windowAction() );
}
bool QgisApp::loadComposersFromProject( const QString& projectFilePath )
{
//create dom document from file
QDomDocument projectDom;
QFile projectFile( projectFilePath );
if ( !projectFile.open( QIODevice::ReadOnly ) )
{
return false;
}
if ( !projectDom.setContent( &projectFile, false ) )
{
return false;
}
//restore each composer
QDomNodeList composerNodes = projectDom.elementsByTagName( "Composer" );
for ( int i = 0; i < composerNodes.size(); ++i )
{
QgsComposer* composer = new QgsComposer( this, "" );
composer->readXML( composerNodes.at( i ).toElement(), projectDom );
mPrintComposers.insert( composer->id(), composer );
mPrintComposersMenu->addAction( composer->windowAction() );
composer->showMinimized();
composer->zoomFull();
}
}
void QgisApp::deletePrintComposers()
{
QMap<QString, QgsComposer*>::iterator it = mPrintComposers.begin();
for ( ; it != mPrintComposers.end(); ++it )
{
delete it.value();
}
mPrintComposers.clear();
}
void QgisApp::mergeSelectedFeatures()
{
//get active layer (hopefully vector)
QgsMapLayer* activeMapLayer = activeLayer();
if ( !activeMapLayer )
{
QMessageBox::information( 0, tr( "No active layer" ), tr( "No active layer found. Please select a layer in the layer list" ) );
return;
}
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( activeMapLayer );
if ( !vl )
{
QMessageBox::information( 0, tr( "Active layer is not vector" ), tr( "The merge features tool only works on vector layers. Please select a vector layer from the layer list" ) );
return;
}
if ( !vl->isEditable() )
{
QMessageBox::information( 0, tr( "Layer not editable" ), tr( "Merging features can only be done for layers in editing mode. To use the merge tool, go to Layer->Toggle editing" ) );
return;
}
//get selected feature ids (as a QSet<int> )
const QgsFeatureIds& featureIdSet = vl->selectedFeaturesIds();
if ( featureIdSet.size() < 2 )
{
QMessageBox::information( 0, "Not enough features selected", tr( "The merge tool requires at least two selected features" ) );
return;
}
//get initial selection (may be altered by attribute merge dialog later)
QgsFeatureList featureList = vl->selectedFeatures(); //get QList<QgsFeature>
QgsGeometry* unionGeom = unionGeometries( vl, featureList );
if ( !unionGeom )
{
return;
}
//make a first geometry union and notify the user straight away if the union geometry type does not match the layer one
QGis::WkbType originalType = vl->wkbType();
QGis::WkbType newType = unionGeom->wkbType();
if ( unionGeom->wkbType() != vl->wkbType() )
{
QMessageBox::critical( 0, "Union operation canceled", tr( "The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled" ) );
delete unionGeom;
return;
}
//merge the attributes together
QgsMergeAttributesDialog d( featureList, vl, mapCanvas() );
if ( d.exec() == QDialog::Rejected )
{
delete unionGeom;
return;
}
QgsFeatureList featureListAfter = vl->selectedFeatures();
if ( featureListAfter.size() < 2 )
{
QMessageBox::information( 0, "Not enough features selected", tr( "The merge tool requires at least two selected features" ) );
delete unionGeom;
return;
}
//if the user changed the feature selection in the merge dialog, we need to repead the union and check the type
if ( featureList.size() != featureListAfter.size() )
{
delete unionGeom;
unionGeom = unionGeometries( vl, featureListAfter );
if ( !unionGeom )
{
return;
}
originalType = vl->wkbType();
newType = unionGeom->wkbType();
if ( unionGeom->wkbType() != vl->wkbType() )
{
QMessageBox::critical( 0, "Union operation canceled", tr( "The union operation would result in a geometry type that is not compatible with the current layer and therefore is canceled" ) );
delete unionGeom;
return;
}
}
vl->beginEditCommand( tr( "Merged features" ) );
//create new feature
QgsFeature newFeature;
newFeature.setGeometry( unionGeom );
newFeature.setAttributeMap( d.mergedAttributesMap() );
QgsFeatureList::const_iterator feature_it = featureListAfter.constBegin();
for ( ; feature_it != featureListAfter.constEnd(); ++feature_it )
{
vl->deleteFeature( feature_it->id() );
}
vl->addFeature( newFeature, false );
vl->endEditCommand();
if ( mapCanvas() )
{
mapCanvas()->refresh();
}
}
void QgisApp::nodeTool()
{
mMapCanvas->setMapTool( mMapTools.mNodeTool );
}
void QgisApp::rotatePointSymbols()
{
mMapCanvas->setMapTool( mMapTools.mRotatePointSymbolsTool );
}
void QgisApp::splitFeatures()
{
mMapCanvas->setMapTool( mMapTools.mSplitFeatures );
}
void QgisApp::reshapeFeatures()
{
mMapCanvas->setMapTool( mMapTools.mReshapeFeatures );
}
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 = qobject_cast<QgsVectorLayer *>( selectionLayer );
if ( selectionVectorLayer != 0 )
{
QgsFeatureList features = selectionVectorLayer->selectedFeatures();
clipboard()->replaceWithCopyOf( selectionVectorLayer->dataProvider()->fields(), features );
clipboard()->setCRS( selectionVectorLayer->srs() );
selectionVectorLayer->beginEditCommand( tr( "Features cut" ) );
selectionVectorLayer->deleteSelectedFeatures();
selectionVectorLayer->endEditCommand();
}
}
}
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 = qobject_cast<QgsVectorLayer *>( selectionLayer );
if ( selectionVectorLayer != 0 )
{
QgsFeatureList features = selectionVectorLayer->selectedFeatures();
clipboard()->replaceWithCopyOf( selectionVectorLayer->dataProvider()->fields(), features );
clipboard()->setCRS( selectionVectorLayer->srs() );
}
}
}
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 = qobject_cast<QgsVectorLayer *>( pasteLayer );
if ( pasteVectorLayer != 0 )
{
pasteVectorLayer->beginEditCommand( tr( "Features pasted" ) );
if ( mMapCanvas->mapRenderer()->hasCrsTransformEnabled() )
{
pasteVectorLayer->addFeatures( clipboard()->transformedCopyOf( pasteVectorLayer->srs() ) );
}
else
{
pasteVectorLayer->addFeatures( clipboard()->copyOf() );
}
pasteVectorLayer->endEditCommand();
mMapCanvas->refresh();
}
}
}
void QgisApp::pasteTransformations()
{
QgsPasteTransformations *pt = new QgsPasteTransformations();
mMapCanvas->freeze();
pt->exec();
}
void QgisApp::refreshMapCanvas()
{
//clear all caches first
QgsMapLayerRegistry::instance()->clearAllLayerCaches();
//then refresh
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 = qobject_cast<QgsVectorLayer *>( layer );
if ( !vlayer )
return;
if ( !vlayer->isEditable() )
{
vlayer->startEditing();
if ( !( vlayer->dataProvider()->capabilities() & QgsVectorDataProvider::EditingCapabilities ) )
{
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
{
mActionToggleEditing->setChecked( vlayer->isEditable() );
return;
}
}
else //layer not modified
{
vlayer->rollBack();
}
if ( layer == mMapLegend->currentLayer() )
{
activateDeactivateLayerRelatedActions( layer );
}
//ensure the toolbar icon state is consistent with the layer editing state
mActionToggleEditing->setChecked( vlayer->isEditable() );
vlayer->triggerRepaint();
}
void QgisApp::showMouseCoordinate( const 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
{
if ( mMapCanvas->mapUnits() == QGis::DegreesMinutesSeconds )
{
mCoordsEdit->setText( p.toDegreesMinutesSeconds( mMousePrecisionDecimalPlaces ) );
}
else
{
mCoordsEdit->setText( p.toString( mMousePrecisionDecimalPlaces ) );
}
if ( mCoordsEdit->width() > mCoordsEdit->minimumWidth() )
{
mCoordsEdit->setMinimumWidth( mCoordsEdit->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->scale();
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->zoomByFactor( wantedScale / currentScale );
}
}
}
void QgisApp::userCenter()
{
QStringList parts = mCoordsEdit->text().split( ',' );
if ( parts.size() != 2 )
return;
bool xOk;
double x = parts.at( 0 ).toDouble( &xOk );
if ( !xOk )
return;
bool yOk;
double y = parts.at( 1 ).toDouble( &yOk );
if ( !yOk )
return;
QgsRectangle r = mMapCanvas->extent();
mMapCanvas->setExtent(
QgsRectangle(
x - r.width() / 2.0, y - r.height() / 2.0,
x + r.width() / 2.0, y + r.height() / 2.0
)
);
mMapCanvas->refresh();
}
// toggle overview status
void QgisApp::isInOverview()
{
mMapLegend->legendLayerShowInOverview();
}
void QgisApp::removeLayer()
{
mMapLegend->legendLayerRemove();
// notify the project we've made a change
QgsProject::instance()->dirty( true );
}
void QgisApp::removeAllLayers()
{
//iterate through all the layers in order to ask if uncommited changes should be saved
if ( mMapLegend )
{
QMap<QString, QgsMapLayer*> layers = QgsMapLayerRegistry::instance()->mapLayers();
QMap<QString, QgsMapLayer*>::iterator layer_it = layers.begin();
for ( ; layer_it != layers.end(); ++layer_it )
{
mMapLegend->removeLayer( layer_it.value(), false );
}
mMapLegend->removeAll();
}
else //no legend? Remove all the layers from the registry directly in this case
{
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() )
{
QgsPluginRegistry* pRegistry = QgsPluginRegistry::instance();
// 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() )
{
pRegistry->loadPythonPlugin( plugin.fullPath() );
}
else
{
pRegistry->loadCppPlugin( 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
QString version = QString( "%1.%2.%3" ).arg( QGis::QGIS_VERSION_INT / 10000 ).arg( QGis::QGIS_VERSION_INT / 100 % 100 ).arg( QGis::QGIS_VERSION_INT % 100 );
QgsDebugMsg( QString( "load library %1 (%2)" ).arg( pythonlibName ).arg( version ) );
QLibrary pythonlib( pythonlibName, version );
// 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() )
{
//using stderr on purpose because we want end users to see this [TS]
QgsDebugMsg( "Couldn't load Python support library: " + pythonlib.errorString() );
pythonlib.setFileName( pythonlibName );
if ( !pythonlib.load() )
{
qWarning( "Couldn't load Python support library: %s", pythonlib.errorString().toUtf8().data() );
return;
}
}
//QgsDebugMsg("Python support library loaded successfully.");
typedef QgsPythonUtils*( *inst )();
inst pythonlib_inst = ( inst ) cast_to_fptr( pythonlib.resolve( "instance" ) );
if ( !pythonlib_inst )
{
//using stderr on purpose because we want end users to see this [TS]
QgsDebugMsg( "Couldn't resolve python support library's instance() symbol." );
return;
}
//QgsDebugMsg("Python support library's instance() symbol resolved.");
mPythonUtils = pythonlib_inst();
mPythonUtils->initPython( mQgisInterface );
if ( mPythonUtils && mPythonUtils->isEnabled() )
{
QgsPluginRegistry::instance()->setPythonUtils( mPythonUtils );
mActionShowPythonDialog = new QAction( tr( "Python Console" ), this );
QgsShortcutsManager::instance()->registerAction( mActionShowPythonDialog );
connect( mActionShowPythonDialog, SIGNAL( triggered() ), this, SLOT( showPythonDialog() ) );
mActionPluginSeparator2 = mPluginMenu->addSeparator();
mPluginMenu->addAction( mActionShowPythonDialog );
std::cout << "Python support ENABLED :-) " << std::endl; // OK
}
}
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 << QGIS_VERSION << "\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();
// QgsDebugMsg(mVersionMessage);
// QgsDebugMsg(QString("Pos is %1").arg(pos));
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::QGIS_VERSION_INT )
{
// show version message from server
versionInfo = tr( "There is a new version of QGIS available" ) + "\n";
}
else
{
if ( QGis::QGIS_VERSION_INT > 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%1" ).arg( 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::configureShortcuts()
{
QgsConfigureShortcutsDialog dlg;
dlg.exec();
}
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->useImageToRender( 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 );
}
}
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( QgsRectangle 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::changeEvent( QEvent* event )
{
QMainWindow::changeEvent( event );
#ifdef Q_WS_MAC
switch ( event->type() )
{
case QEvent::ActivationChange:
if ( QApplication::activeWindow() == this )
{
mWindowAction->setChecked( true );
}
// this should not be necessary since the action is part of an action group
// however this check is not cleared if PrintComposer is closed and reopened
else
{
mWindowAction->setChecked( false );
}
break;
case QEvent::WindowTitleChange:
mWindowAction->setText( windowTitle() );
break;
default:
break;
}
#endif
}
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 )
{
/* Plugin menu items are below the plugin separator (which may not exist yet
* if no plugins are loaded) and above the python separator. If python is not
* present, there is no python separator and the plugin list is at the bottom
* of the menu.
*/
#ifdef Q_WS_MAC
// Mac doesn't have '&' keyboard shortcuts.
// Other platforms ignore the prefix char when comparing strings.
menuName.remove( QChar( '&' ) );
#endif
QAction *before = mActionPluginSeparator2; // python separator or end of list
if ( !mActionPluginSeparator1 )
{
// First plugin - create plugin list separator
mActionPluginSeparator1 = mPluginMenu->insertSeparator( before );
}
else
{
// Plugins exist - search between plugin separator and python separator or end of list
QList<QAction*> actions = mPluginMenu->actions();
int end = mActionPluginSeparator2 ? actions.indexOf( mActionPluginSeparator2 ) : actions.count();
for ( int i = actions.indexOf( mActionPluginSeparator1 ) + 1; i < end; i++ )
{
int comp = menuName.localeAwareCompare( actions.at( i )->text() );
if ( comp < 0 )
{
// Add item before this one
before = actions.at( i );
break;
}
else if ( comp == 0 )
{
// Plugin menu item already exists
return actions.at( i )->menu();
}
}
}
// 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::addPluginToMenu( 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() );
}
// Remove separator above plugins in Plugin menu if no plugins remain
QList<QAction*> actions = mPluginMenu->actions();
int end = mActionPluginSeparator2 ? actions.indexOf( mActionPluginSeparator2 ) : actions.count();
if ( actions.indexOf( mActionPluginSeparator1 ) + 1 == end )
{
mPluginMenu->removeAction( mActionPluginSeparator1 );
mActionPluginSeparator1 = NULL;
}
}
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::hasCrsTransformEnabled( 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" ) );
mCoordsEdit->setToolTip( tr( "Map coordinates for the current view extents" ) );
mCoordsEdit->setEnabled( false );
showExtents();
}
else
{
//mouse cursor pos view mode!
mToggleExtentsViewButton->setIcon( getThemeIcon( "tracking.png" ) );
mCoordsEdit->setToolTip( tr( "Map coordinates at mouse cursor position" ) );
mCoordsEdit->setEnabled( true );
mCoordsLabel->setText( tr( "Coordinate:" ) );
}
}
void QgisApp::showExtents()
{
if ( !mToggleExtentsViewButton->isChecked() )
{
return;
}
// update the statusbar with the current extents.
QgsRectangle myExtents = mMapCanvas->extent();
mCoordsLabel->setText( tr( "Extents:" ) );
mCoordsEdit->setText( myExtents.toString( true ) );
//ensure the label is big enough
if ( mCoordsEdit->width() > mCoordsEdit->minimumWidth() )
{
mCoordsEdit->setMinimumWidth( mCoordsEdit->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 ( mapCanvas()->mapUnitsPerPixel() != 0.0 )
dp = static_cast<int>( ceil( -1.0 * log10( mapCanvas()->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::VectorLayer )
{
// 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
// Line below was commented out by wonder three years ago (r4949).
// It is needed to refresh scale bar after changing display units.
connect( pp, SIGNAL( refresh() ), mMapCanvas, SLOT( refresh() ) );
QgsMapRenderer* myRender = mMapCanvas->mapRenderer();
bool wasProjected = myRender->hasCrsTransformEnabled();
long oldCRSID = myRender->destinationSrs().srsid();
// Display the modal dialog box.
pp->exec();
long newCRSID = myRender->destinationSrs().srsid();
bool isProjected = myRender->hasCrsTransformEnabled();
// 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 )
{
mActionSelect->setEnabled( false );
mActionIdentify->setEnabled( QSettings().value( "/Map/identifyMode", 0 ).toInt() != 0 );
mActionZoomActualSize->setEnabled( false );
mActionOpenTable->setEnabled( false );
mActionToggleEditing->setEnabled( false );
mActionLayerSaveAs->setEnabled( false );
mActionLayerSelectionSaveAs->setEnabled( false );
mActionRemoveLayer->setEnabled( false );
mActionLayerProperties->setEnabled( false );
mActionAddToOverview->setEnabled( false );
mActionCopyFeatures->setEnabled( false );
mActionUndo->setEnabled( false );
mActionRedo->setEnabled( false );
return;
}
mActionRemoveLayer->setEnabled( true );
mActionLayerProperties->setEnabled( true );
mActionAddToOverview->setEnabled( true );
/***********Vector layers****************/
if ( layer->type() == QgsMapLayer::VectorLayer )
{
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( layer );
const QgsVectorDataProvider* dprovider = vlayer->dataProvider();
bool layerHasSelection = ( vlayer->selectedFeatureCount() != 0 );
mActionSelect->setEnabled( true );
mActionIdentify->setEnabled( true );
mActionZoomActualSize->setEnabled( false );
mActionOpenTable->setEnabled( true );
mActionLayerSaveAs->setEnabled( true );
mActionLayerSelectionSaveAs->setEnabled( true );
mActionCopyFeatures->setEnabled( layerHasSelection );
if ( !vlayer->isEditable() && mMapCanvas->mapTool() && mMapCanvas->mapTool()->isEditTool() )
{
mMapCanvas->setMapTool( mNonEditMapTool );
}
if ( dprovider )
{
//start editing/stop editing
if ( dprovider->capabilities() & QgsVectorDataProvider::EditingCapabilities )
{
mActionToggleEditing->setEnabled( true );
mActionToggleEditing->setChecked( vlayer->isEditable() );
}
else
{
mActionToggleEditing->setEnabled( false );
}
if ( dprovider->capabilities() & QgsVectorDataProvider::AddFeatures )
{
mActionPasteFeatures->setEnabled( vlayer->isEditable() && !clipboard()->empty() );
}
else
{
mActionPasteFeatures->setEnabled( false );
}
//does provider allow deleting of features?
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures )
{
mActionDeleteSelected->setEnabled( layerHasSelection );
mActionCutFeatures->setEnabled( layerHasSelection );
}
else
{
mActionDeleteSelected->setEnabled( false );
mActionCutFeatures->setEnabled( false );
}
//merge tool needs editable layer and provider with the capability of adding and deleting features
if ( vlayer->isEditable() &&
( dprovider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) &&
( dprovider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) &&
( dprovider->capabilities() & QgsVectorDataProvider::AddFeatures ) )
{
mActionMergeFeatures->setEnabled( layerHasSelection );
}
else
{
mActionMergeFeatures->setEnabled( false );
}
// moving enabled if geometry changes are supported
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
mActionMoveFeature->setEnabled( true );
mActionNodeTool->setEnabled( true );
}
else
{
mActionMoveFeature->setEnabled( false );
mActionNodeTool->setEnabled( false );
}
if ( vlayer->geometryType() == QGis::Point )
{
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures )
{
mActionCapturePoint->setEnabled( true );
mActionCapturePoint->setVisible( true );
mActionDeletePart->setEnabled( true );
}
else
{
mActionCapturePoint->setEnabled( false );
mActionCapturePoint->setVisible( false );
mActionDeletePart->setEnabled( false );
}
mActionCaptureLine->setEnabled( false );
mActionCapturePolygon->setEnabled( false );
mActionCaptureLine->setVisible( false );
mActionCapturePolygon->setVisible( false );
mActionAddVertex->setEnabled( false );
mActionDeleteVertex->setEnabled( false );
mActionMoveVertex->setEnabled( false );
mActionAddRing->setEnabled( false );
mActionAddIsland->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
mActionMoveVertex->setEnabled( true );
}
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeAttributeValues )
{
if ( QgsMapToolRotatePointSymbols::layerIsRotatable( vlayer ) )
{
mActionRotatePointSymbols->setEnabled( true );
}
}
return;
}
else if ( vlayer->geometryType() == QGis::Line )
{
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures )
{
mActionCaptureLine->setEnabled( true );
mActionCaptureLine->setVisible( true );
mActionReshapeFeatures->setEnabled( true );
mActionSplitFeatures->setEnabled( true );
mActionSimplifyFeature->setEnabled( true );
mActionDeletePart->setEnabled( true );
}
else
{
mActionCaptureLine->setEnabled( false );
mActionCaptureLine->setVisible( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionDeletePart->setEnabled( false );
}
mActionCapturePoint->setEnabled( false );
mActionCapturePolygon->setEnabled( false );
mActionCapturePoint->setVisible( false );
mActionCapturePolygon->setVisible( false );
mActionAddRing->setEnabled( false );
mActionAddIsland->setEnabled( false );
mActionDeleteRing->setEnabled( false );
}
else if ( vlayer->geometryType() == QGis::Polygon )
{
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::AddFeatures )
{
mActionCapturePolygon->setEnabled( true );
mActionCapturePolygon->setVisible( true );
mActionAddRing->setEnabled( true );
mActionAddIsland->setEnabled( true );
mActionReshapeFeatures->setEnabled( true );
mActionSplitFeatures->setEnabled( true );
mActionSimplifyFeature->setEnabled( true );
mActionDeleteRing->setEnabled( true );
mActionDeletePart->setEnabled( true );
}
else
{
mActionCapturePolygon->setEnabled( false );
mActionCapturePolygon->setVisible( false );
mActionAddRing->setEnabled( false );
mActionAddIsland->setEnabled( false );
mActionReshapeFeatures->setEnabled( false );
mActionSplitFeatures->setEnabled( false );
mActionSimplifyFeature->setEnabled( false );
mActionDeleteRing->setEnabled( false );
mActionDeletePart->setEnabled( false );
}
mActionCapturePoint->setEnabled( false );
mActionCaptureLine->setEnabled( false );
mActionCapturePoint->setVisible( false );
mActionCaptureLine->setVisible( false );
}
//are add/delete/move vertex supported?
if ( vlayer->isEditable() && dprovider->capabilities() & QgsVectorDataProvider::ChangeGeometries )
{
mActionAddVertex->setEnabled( true );
mActionMoveVertex->setEnabled( true );
mActionDeleteVertex->setEnabled( true );
if ( vlayer->geometryType() == 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 );
}
return;
}
}
/*************Raster layers*************/
else if ( layer->type() == QgsMapLayer::RasterLayer )
{
mActionSelect->setEnabled( false );
mActionZoomActualSize->setEnabled( true );
mActionOpenTable->setEnabled( false );
mActionToggleEditing->setEnabled( false );
mActionLayerSaveAs->setEnabled( false );
mActionLayerSelectionSaveAs->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 );
mActionCopyFeatures->setEnabled( false );
mActionCutFeatures->setEnabled( false );
mActionPasteFeatures->setEnabled( false );
mActionRotatePointSymbols->setEnabled( false );
mActionNodeTool->setEnabled( false );
mActionDeletePart->setEnabled( false );
//NOTE: This check does not really add any protection, as it is called on load not on layer select/activate
//If you load a layer with a provider and idenitfy ability then load another without, the tool would be disabled for both
//Enable the Identify tool ( GDAL datasets draw without a provider )
//but turn off if data provider exists and has no Identify capabilities
mActionIdentify->setEnabled( true );
QSettings settings;
int identifyMode = settings.value( "/Map/identifyMode", 0 ).toInt();
if ( identifyMode == 0 )
{
const QgsRasterLayer *rlayer = qobject_cast<const QgsRasterLayer *>( layer );
const QgsRasterDataProvider* dprovider = rlayer->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( statusChanged( 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( tr( "%1 is not a valid or recognized raster data source" ).arg( rasterFile ) );
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 = tr( "%1 is not a supported raster data source" ).arg( *myIterator );
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]
// QgsDebugMsg(QString("%1 (keypress recevied)").arg(e->text()));
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()
{
QgsDebugMsg("Hello from debug hook");
// show the map canvas extent
QgsDebugMsg(mMapCanvas->extent());
}
*/
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->setWindowState( bookmarks->windowState() & ~Qt::WindowMinimized );
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" ) );
}
}
}
// Slot that gets called when the project file was saved with an older
// version of QGIS
void QgisApp::oldProjectVersionWarning( 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."
" When saving this project file, QGIS will update it to the latest version, "
"possibly rendering it useless for older versions of QGIS."
"<p>Even though QGIS developers try to maintain backwards "
"compatibility, some of the information from the old project "
"file might be lost."
" To improve the quality of QGIS, we appreciate "
"if you file a bug report at %3."
" Be sure to include the old project file, and state the version of "
"QGIS you used to discover the error."
"<p>To remove this warning when opening an older project file, "
"uncheck the box '%5' in the %4 menu."
"<p>Version of the project file: %1<br>Current version of QGIS: %2" )
.arg( oldVersion )
.arg( QGis::QGIS_VERSION )
.arg( "<a href=\"https://trac.osgeo.org/qgis\">http://trac.osgeo.org/qgis</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;
}
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 );
}
}
void QgisApp::updateUndoActions()
{
bool canUndo = false, canRedo = false;
QgsMapLayer* layer = activeLayer();
if ( layer )
{
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( vlayer && vlayer->isEditable() )
{
canUndo = vlayer->undoStack()->canUndo();
canRedo = vlayer->undoStack()->canRedo();
}
}
mActionUndo->setEnabled( canUndo );
mActionRedo->setEnabled( canRedo );
}