mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
3393 lines
90 KiB
C++
3393 lines
90 KiB
C++
/***************************************************************************
|
|
qgsgrasstools.cpp
|
|
-------------------
|
|
begin : March, 2005
|
|
copyright : (C) 2005 by Radim Blazek
|
|
email : blazek@itc.it
|
|
***************************************************************************/
|
|
/***************************************************************************
|
|
* *
|
|
* 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. *
|
|
* *
|
|
***************************************************************************/
|
|
#include "qgsgrassmodule.h"
|
|
#include "qgsgrassmapcalc.h"
|
|
#include "qgsgrassplugin.h"
|
|
#include "qgsgrassselect.h"
|
|
#include "qgsgrasstools.h"
|
|
#include "qgsgrassprovider.h"
|
|
#include "qgsgrassutils.h"
|
|
#include "qgsgrass.h"
|
|
#include "qgsconfig.h"
|
|
|
|
#include "qgisinterface.h"
|
|
#include "qgsapplication.h"
|
|
#include "qgsdataprovider.h"
|
|
#include "qgsdatasourceuri.h"
|
|
#include "qgsfeature.h"
|
|
#include "qgslogger.h"
|
|
#include "qgsmapcanvas.h"
|
|
#include "qgsmaplayer.h"
|
|
#include "qgsvectorlayer.h"
|
|
|
|
#include <typeinfo>
|
|
#include <QComboBox>
|
|
#include <QDomDocument>
|
|
#include <QFileDialog>
|
|
#include <QLineEdit>
|
|
#include <QMessageBox>
|
|
#include <QSvgRenderer>
|
|
|
|
extern "C"
|
|
{
|
|
#include <grass/Vect.h>
|
|
#include <grass/glocale.h>
|
|
}
|
|
|
|
#include <gdal.h> // to collect version information
|
|
|
|
bool QgsGrassModule::mExecPathInited = 0;
|
|
QStringList QgsGrassModule::mExecPath;
|
|
|
|
QString QgsGrassModule::findExec( QString file )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
// Init mExecPath
|
|
// Windows searches first in current directory
|
|
if ( !mExecPathInited )
|
|
{
|
|
QString path = getenv( "PATH" );
|
|
QgsDebugMsg( "path = " + path );
|
|
|
|
#ifdef WIN32
|
|
mExecPath = path.split( ";" );
|
|
mExecPath.prepend( QgsGrass::shortPath( QgsApplication::applicationDirPath() ) );
|
|
#else
|
|
mExecPath = path.split( ":" );
|
|
mExecPath.prepend( QgsApplication::applicationDirPath() );
|
|
#endif
|
|
mExecPathInited = true;
|
|
}
|
|
|
|
if ( QFile::exists( file ) ) return file; // full path
|
|
|
|
#ifdef WIN32
|
|
// On windows try .bat first
|
|
for ( QStringList::iterator it = mExecPath.begin();
|
|
it != mExecPath.end(); ++it )
|
|
{
|
|
QString full = *it + "/" + file + ".bat";
|
|
if ( QFile::exists( full ) )
|
|
{
|
|
return full;
|
|
}
|
|
}
|
|
|
|
// .exe next
|
|
for ( QStringList::iterator it = mExecPath.begin();
|
|
it != mExecPath.end(); ++it )
|
|
{
|
|
QString full = *it + "/" + file + ".exe";
|
|
if ( QFile::exists( full ) )
|
|
{
|
|
return full;
|
|
}
|
|
}
|
|
|
|
// and then try if it's a script (w/o extension)
|
|
#endif
|
|
|
|
// Search for module
|
|
for ( QStringList::iterator it = mExecPath.begin();
|
|
it != mExecPath.end(); ++it )
|
|
{
|
|
QString full = *it + "/" + file;
|
|
if ( QFile::exists( full ) )
|
|
{
|
|
return full;
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
bool QgsGrassModule::inExecPath( QString file )
|
|
{
|
|
return !findExec( file ).isNull();
|
|
}
|
|
|
|
QStringList QgsGrassModule::execArguments( QString module )
|
|
{
|
|
QString exe;
|
|
QStringList arguments;
|
|
|
|
exe = QgsGrassModule::findExec( module );
|
|
if ( exe.isNull() )
|
|
{
|
|
return arguments;
|
|
}
|
|
|
|
#if defined(WIN32)
|
|
if ( exe.endsWith( ".py" ) )
|
|
{
|
|
arguments.append( "python" );
|
|
}
|
|
#endif
|
|
|
|
arguments.append( exe );
|
|
|
|
return arguments;
|
|
}
|
|
|
|
QgsGrassModule::QgsGrassModule( QgsGrassTools *tools, QString moduleName, QgisInterface *iface,
|
|
QString path, QWidget * parent, Qt::WFlags f )
|
|
: QgsGrassModuleBase( ), mSuccess( false )
|
|
{
|
|
QgsDebugMsg( "called" );
|
|
|
|
setupUi( this );
|
|
lblModuleName->setText( tr( "Module: %1" ).arg( moduleName ) );
|
|
mPath = path;
|
|
mTools = tools;
|
|
mIface = iface;
|
|
mCanvas = mIface->mapCanvas();
|
|
mParent = parent;
|
|
|
|
/* Read module description and create options */
|
|
|
|
// Open QGIS module description
|
|
QString mpath = mPath + ".qgm";
|
|
QFile qFile( mpath );
|
|
if ( !qFile.exists() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "The module file (%1) not found." ).arg( mpath ) );
|
|
return;
|
|
}
|
|
if ( ! qFile.open( QIODevice::ReadOnly ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot open module file (%1)" ).arg( mpath ) );
|
|
return;
|
|
}
|
|
QDomDocument qDoc( "qgisgrassmodule" );
|
|
QString err;
|
|
int line, column;
|
|
if ( !qDoc.setContent( &qFile, &err, &line, &column ) )
|
|
{
|
|
QString errmsg = tr( "Cannot read module file (%1)" ).arg( mpath )
|
|
+ tr( "\n%1\nat line %2 column %3" ).arg( err ).arg( line ).arg( column );
|
|
QgsDebugMsg( errmsg );
|
|
QMessageBox::warning( 0, tr( "Warning" ), errmsg );
|
|
qFile.close();
|
|
return;
|
|
}
|
|
qFile.close();
|
|
QDomElement qDocElem = qDoc.documentElement();
|
|
|
|
// Read GRASS module description
|
|
QString xName = qDocElem.attribute( "module" );
|
|
QString xDocName = qDocElem.attribute( "manual" );
|
|
if ( xDocName.isEmpty() )
|
|
{
|
|
xDocName = xName;
|
|
}
|
|
|
|
// Binary modules on windows has .exe extension
|
|
// but not all modules have to be binary (can be scripts)
|
|
// => test if the module is in path and if it is not
|
|
// add .exe and test again
|
|
#ifdef WIN32
|
|
if ( inExecPath( xName ) )
|
|
{
|
|
mXName = xName;
|
|
}
|
|
else if ( inExecPath( xName + ".exe" ) )
|
|
{
|
|
mXName = xName + ".exe";
|
|
}
|
|
else
|
|
{
|
|
QgsDebugMsg( "Module " + xName + " not found" );
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Module %1 not found" ).arg( xName ) );
|
|
return;
|
|
}
|
|
#else
|
|
mXName = xName;
|
|
#endif
|
|
|
|
if ( xName == "r.mapcalc" )
|
|
{
|
|
QGridLayout *layout = new QGridLayout( mTabWidget->widget( 0 ) );
|
|
|
|
mOptions = new QgsGrassMapcalc( mTools, this,
|
|
mIface, mTabWidget->widget( 0 ) );
|
|
|
|
QWidget *w = dynamic_cast<QWidget *>( mOptions );
|
|
|
|
layout->addWidget( w, 0, 0 );
|
|
}
|
|
else
|
|
{
|
|
mOptions = new QgsGrassModuleStandardOptions( mTools, this,
|
|
mIface, mXName, qDocElem, mTabWidget->widget( 0 ) );
|
|
}
|
|
|
|
// Hide display if there is no output
|
|
if ( !mOptions->hasOutput( QgsGrassModuleOption::Vector )
|
|
&& !mOptions->hasOutput( QgsGrassModuleOption::Raster ) )
|
|
{
|
|
mViewButton->hide();
|
|
}
|
|
mViewButton->setEnabled( false );
|
|
|
|
// Create manual if available
|
|
QString gisBase = getenv( "GISBASE" );
|
|
QString manPath = gisBase + "/docs/html/" + xDocName + ".html";
|
|
QFile manFile( manPath );
|
|
if ( manFile.exists() )
|
|
{
|
|
mManualTextBrowser->setOpenExternalLinks( true );
|
|
mManualTextBrowser->setSource( QUrl::fromLocalFile( manPath ) );
|
|
}
|
|
else
|
|
{
|
|
mManualTextBrowser->clear();
|
|
mManualTextBrowser->textCursor().insertImage( ":/grass/error.png" );
|
|
mManualTextBrowser->insertPlainText( tr( "Cannot find man page %1" ).arg( manPath ) );
|
|
mManualTextBrowser->insertPlainText( tr( "Please ensure you have the GRASS documentation installed." ) );
|
|
}
|
|
|
|
connect( &mProcess, SIGNAL( readyReadStandardOutput() ), this, SLOT( readStdout() ) );
|
|
connect( &mProcess, SIGNAL( readyReadStandardError() ), this, SLOT( readStderr() ) );
|
|
connect( &mProcess, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( finished( int, QProcess::ExitStatus ) ) );
|
|
|
|
const char *env = "GRASS_MESSAGE_FORMAT=gui";
|
|
char *envstr = new char[strlen( env )+1];
|
|
strcpy( envstr, env );
|
|
putenv( envstr );
|
|
|
|
mOutputTextBrowser->setReadOnly( true );
|
|
}
|
|
|
|
/******************* QgsGrassModuleOptions *******************/
|
|
|
|
QgsGrassModuleOptions::QgsGrassModuleOptions(
|
|
QgsGrassTools *tools, QgsGrassModule *module,
|
|
QgisInterface *iface )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
mTools = tools;
|
|
mModule = module;
|
|
mIface = iface;
|
|
mCanvas = mIface->mapCanvas();
|
|
}
|
|
|
|
QgsGrassModuleOptions::~QgsGrassModuleOptions()
|
|
{
|
|
}
|
|
|
|
QStringList QgsGrassModuleOptions::arguments()
|
|
{
|
|
return QStringList();
|
|
}
|
|
|
|
/*************** QgsGrassModuleStandardOptions ***********************/
|
|
|
|
QgsGrassModuleStandardOptions::QgsGrassModuleStandardOptions(
|
|
QgsGrassTools *tools, QgsGrassModule *module,
|
|
QgisInterface *iface,
|
|
QString xname, QDomElement qDocElem,
|
|
QWidget * parent, Qt::WFlags f )
|
|
: QWidget( parent, f ),
|
|
QgsGrassModuleOptions( tools, module, iface )
|
|
{
|
|
//QgsDebugMsg( "called." );
|
|
QgsDebugMsg( QString( "PATH = %1" ).arg( getenv( "PATH" ) ) );
|
|
|
|
// Attention!: sh.exe (MSYS) sets $0 in scripts to file name
|
|
// without full path. Strange because when run from msys.bat
|
|
// $0 is set to full path. GRASS scripts call
|
|
// exec g.parser "$0" "$@"
|
|
// and it fails -> find and run with full path
|
|
|
|
mXName = xname;
|
|
mParent = parent;
|
|
|
|
QStringList arguments = QgsGrassModule::execArguments( mXName );
|
|
|
|
if ( arguments.size() == 0 )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find module %1" ).arg( mXName ) );
|
|
return;
|
|
}
|
|
|
|
QString cmd = arguments.takeFirst();
|
|
|
|
arguments.append( "--interface-description" );
|
|
|
|
QProcess process( this );
|
|
process.start( cmd, arguments );
|
|
|
|
// ? Does binary on Win need .exe extension ?
|
|
// Return code 255 (-1) was correct in GRASS < 6.1.0
|
|
if ( !process.waitForStarted()
|
|
|| !process.waitForReadyRead()
|
|
|| !process.waitForFinished()
|
|
|| ( process.exitCode() != 0 && process.exitCode() != 255 ) )
|
|
{
|
|
QgsDebugMsg( "process.exitCode() = " + QString::number( process.exitCode() ) );
|
|
QMessageBox::warning( 0, tr( "Warning" ),
|
|
tr( "Cannot start module %1" ).arg( mXName )
|
|
+ tr( "<br>command: %1 %2<br>%3<br>%4" )
|
|
.arg( cmd ).arg( arguments.join( " " ) )
|
|
.arg( process.readAllStandardOutput().constData() )
|
|
.arg( process.readAllStandardError().constData() ) );
|
|
return;
|
|
}
|
|
|
|
QDomDocument gDoc( "task" );
|
|
QString err;
|
|
int line, column;
|
|
if ( !gDoc.setContent( &process, false, &err, &line, &column ) )
|
|
{
|
|
QString errmsg = tr( "Cannot read module description (%1):" ).arg( mXName )
|
|
+ tr( "\n%1\nat line %2 column %3" ).arg( err ).arg( line ).arg( column );
|
|
QgsDebugMsg( errmsg );
|
|
QMessageBox::warning( 0, tr( "Warning" ), errmsg );
|
|
return;
|
|
}
|
|
QDomElement gDocElem = gDoc.documentElement();
|
|
|
|
// Read QGIS options and create controls
|
|
QDomNode n = qDocElem.firstChild();
|
|
//
|
|
//Set up dynamic inside a scroll box
|
|
//
|
|
QVBoxLayout * mypOuterLayout = new QVBoxLayout( mParent );
|
|
mypOuterLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
QScrollArea * mypScrollArea = new QScrollArea();
|
|
//transfers scroll area ownership so no need to call delete
|
|
mypOuterLayout->addWidget( mypScrollArea );
|
|
QFrame * mypInnerFrame = new QFrame();
|
|
mypInnerFrame->setFrameShape( QFrame::NoFrame );
|
|
mypInnerFrame->setFrameShadow( QFrame::Plain );
|
|
//transfers frame ownership so no need to call delete
|
|
mypScrollArea->setWidget( mypInnerFrame );
|
|
mypScrollArea->setWidgetResizable( true );
|
|
QVBoxLayout *mypInnerFrameLayout = new QVBoxLayout( mypInnerFrame );
|
|
// Add frames for simple/advanced options
|
|
QFrame * mypSimpleFrame = new QFrame();
|
|
mypSimpleFrame->setFrameShape( QFrame::NoFrame );
|
|
mypSimpleFrame->setFrameShadow( QFrame::Plain );
|
|
mAdvancedFrame.setFrameShape( QFrame::NoFrame );
|
|
mAdvancedFrame.setFrameShadow( QFrame::Plain );
|
|
|
|
QFrame * mypAdvancedPushButtonFrame = new QFrame();
|
|
QHBoxLayout *mypAdvancedPushButtonFrameLayout = new QHBoxLayout( mypAdvancedPushButtonFrame );
|
|
connect( &mAdvancedPushButton, SIGNAL( clicked() ), this, SLOT( switchAdvanced() ) );
|
|
mypAdvancedPushButtonFrameLayout->addWidget( &mAdvancedPushButton );
|
|
mypAdvancedPushButtonFrameLayout->addStretch( 1 );
|
|
|
|
mypInnerFrameLayout->addWidget( mypSimpleFrame );
|
|
mypInnerFrameLayout->addWidget( mypAdvancedPushButtonFrame );
|
|
mypInnerFrameLayout->addWidget( &mAdvancedFrame );
|
|
mypInnerFrameLayout->addStretch( 1 );
|
|
|
|
// Hide advanced and set butto next
|
|
switchAdvanced();
|
|
|
|
QVBoxLayout *mypSimpleLayout = new QVBoxLayout( mypSimpleFrame );
|
|
QVBoxLayout *mypAdvancedLayout = new QVBoxLayout( &mAdvancedFrame );
|
|
QVBoxLayout *layout = 0;
|
|
while ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
if ( !e.isNull() )
|
|
{
|
|
QString optionType = e.tagName();
|
|
QgsDebugMsg( "optionType = " + optionType );
|
|
|
|
if ( e.attribute( "advanced", "no" ) == "yes" )
|
|
{
|
|
layout = mypAdvancedLayout;
|
|
}
|
|
else
|
|
{
|
|
layout = mypSimpleLayout;
|
|
}
|
|
|
|
QString key = e.attribute( "key" );
|
|
QgsDebugMsg( "key = " + key );
|
|
|
|
QDomNode gnode = QgsGrassModule::nodeByKey( gDocElem, key );
|
|
if ( gnode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find key %1" ).arg( key ) );
|
|
return;
|
|
}
|
|
|
|
if ( optionType == "option" )
|
|
{
|
|
bool created = false;
|
|
|
|
// Check option type and create appropriate control
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
if ( !promptNode.isNull() )
|
|
{
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
QString age = promptElem.attribute( "age" );
|
|
//QgsDebugMsg("element = " + element + " age = " + age);
|
|
if ( age == "old" && ( element == "vector" || element == "cell" ) )
|
|
{
|
|
QgsGrassModuleInput *mi = new QgsGrassModuleInput(
|
|
mModule, this, key, e, gDocElem, gnode, mParent );
|
|
|
|
layout->addWidget( mi );
|
|
created = true;
|
|
mItems.push_back( mi );
|
|
}
|
|
}
|
|
|
|
if ( !created )
|
|
{
|
|
QgsGrassModuleOption *so = new QgsGrassModuleOption(
|
|
mModule, key, e, gDocElem, gnode, mParent );
|
|
|
|
layout->addWidget( so );
|
|
created = true;
|
|
mItems.push_back( so );
|
|
}
|
|
}
|
|
else if ( optionType == "ogr" )
|
|
{
|
|
QgsGrassModuleGdalInput *mi = new QgsGrassModuleGdalInput(
|
|
mModule, QgsGrassModuleGdalInput::Ogr, key, e,
|
|
gDocElem, gnode, mParent );
|
|
layout->addWidget( mi );
|
|
mItems.push_back( mi );
|
|
}
|
|
else if ( optionType == "gdal" )
|
|
{
|
|
QgsGrassModuleGdalInput *mi = new QgsGrassModuleGdalInput(
|
|
mModule, QgsGrassModuleGdalInput::Gdal, key, e,
|
|
gDocElem, gnode, mParent );
|
|
layout->addWidget( mi );
|
|
mItems.push_back( mi );
|
|
}
|
|
else if ( optionType == "field" )
|
|
{
|
|
QgsGrassModuleField *mi = new QgsGrassModuleField(
|
|
mModule, this, key, e,
|
|
gDocElem, gnode, mParent );
|
|
layout->addWidget( mi );
|
|
mItems.push_back( mi );
|
|
}
|
|
else if ( optionType == "selection" )
|
|
{
|
|
QgsGrassModuleSelection *mi = new QgsGrassModuleSelection(
|
|
mModule, this, key, e,
|
|
gDocElem, gnode, mParent );
|
|
layout->addWidget( mi );
|
|
mItems.push_back( mi );
|
|
}
|
|
else if ( optionType == "file" )
|
|
{
|
|
QgsGrassModuleFile *mi = new QgsGrassModuleFile(
|
|
mModule, key, e, gDocElem, gnode, mParent );
|
|
layout->addWidget( mi );
|
|
mItems.push_back( mi );
|
|
}
|
|
else if ( optionType == "flag" )
|
|
{
|
|
QgsGrassModuleFlag *flag = new QgsGrassModuleFlag(
|
|
mModule, key, e, gDocElem, gnode, mParent );
|
|
|
|
layout->addWidget( flag );
|
|
mItems.push_back( flag );
|
|
}
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
if ( mypAdvancedLayout->count() == 0 )
|
|
{
|
|
mypAdvancedPushButtonFrame->hide();
|
|
}
|
|
|
|
// Create list of flags
|
|
n = gDocElem.firstChild();
|
|
while ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
if ( !e.isNull() )
|
|
{
|
|
QString optionType = e.tagName();
|
|
QgsDebugMsg( "optionType = " + optionType );
|
|
|
|
if ( optionType == "flag" )
|
|
{
|
|
QString name = e.attribute( "name" ).trimmed();
|
|
QgsDebugMsg( "name = " + name );
|
|
mFlagNames.append( name );
|
|
}
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
if ( layout )
|
|
layout->addStretch();
|
|
}
|
|
|
|
void QgsGrassModuleStandardOptions::switchAdvanced()
|
|
{
|
|
if ( mAdvancedFrame.isHidden() )
|
|
{
|
|
mAdvancedFrame.show();
|
|
mAdvancedPushButton.setText( tr( "<< Hide advanced options" ) );
|
|
}
|
|
else
|
|
{
|
|
mAdvancedFrame.hide();
|
|
mAdvancedPushButton.setText( tr( "Show advanced options >>" ) );
|
|
}
|
|
}
|
|
|
|
QStringList QgsGrassModuleStandardOptions::arguments()
|
|
{
|
|
QStringList arg;
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QStringList list = mItems[i]->options();
|
|
|
|
for ( QStringList::Iterator it = list.begin();
|
|
it != list.end(); ++it )
|
|
{
|
|
arg.append( *it );
|
|
}
|
|
}
|
|
return arg;
|
|
}
|
|
|
|
// id is not used in fact, was intended for field, but key is used instead
|
|
QgsGrassModuleItem *QgsGrassModuleStandardOptions::itemByKey( QString key )
|
|
{
|
|
QgsDebugMsg( "key = " + key );
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
if ( mItems[i]->key() == key )
|
|
{
|
|
return mItems[i];
|
|
}
|
|
}
|
|
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Item with key %1 not found" ).arg( key ) );
|
|
return 0;
|
|
}
|
|
|
|
QgsGrassModuleItem *QgsGrassModuleStandardOptions::item( QString id )
|
|
{
|
|
QgsDebugMsg( "id = " + id );
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
if ( mItems[i]->id() == id )
|
|
{
|
|
return mItems[i];
|
|
}
|
|
}
|
|
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Item with id %1 not found" ).arg( id ) );
|
|
return 0;
|
|
}
|
|
|
|
QStringList QgsGrassModuleStandardOptions::checkOutput()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
QStringList list;
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleOption *opt = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( !opt )
|
|
continue;
|
|
|
|
QgsDebugMsg( "opt->key() = " + opt->key() );
|
|
|
|
if ( opt->isOutput() )
|
|
{
|
|
QString out = opt->outputExists();
|
|
if ( !out.isNull() )
|
|
{
|
|
list.append( out );
|
|
}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
void QgsGrassModuleStandardOptions::freezeOutput()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
#ifdef WIN32
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleOption *opt = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( !opt )
|
|
continue;
|
|
|
|
QgsDebugMsg( "opt->key() = " + opt->key() );
|
|
|
|
if ( opt->isOutput()
|
|
&& opt->outputType() == QgsGrassModuleOption::Vector )
|
|
{
|
|
QgsDebugMsg( "freeze vector layers" );
|
|
|
|
QChar sep = '/';
|
|
|
|
int nlayers = mCanvas->layerCount();
|
|
for ( int i = 0; i < nlayers; i++ )
|
|
{
|
|
QgsMapLayer *layer = mCanvas->layer( i );
|
|
|
|
if ( layer->type() != QgsMapLayer::VectorLayer ) continue;
|
|
|
|
QgsVectorLayer *vector = ( QgsVectorLayer* )layer;
|
|
if ( vector->providerType() != "grass" ) continue;
|
|
|
|
//TODO dynamic_cast ?
|
|
QgsGrassProvider *provider = ( QgsGrassProvider * ) vector->dataProvider();
|
|
|
|
// TODO add map() mapset() location() gisbase() to grass provider
|
|
QString source = QDir::cleanPath( provider->dataSourceUri() );
|
|
|
|
QgsDebugMsg( "source = " + source );
|
|
|
|
// Check GISBASE and LOCATION
|
|
QStringList split = source.split( sep );
|
|
|
|
if ( split.size() < 4 ) continue;
|
|
split.pop_back(); // layer
|
|
|
|
QString map = split.last();
|
|
split.pop_back(); // map
|
|
|
|
QString mapset = split.last();
|
|
split.pop_back(); // mapset
|
|
|
|
QString loc = source.remove( QRegExp( "/[^/]+/[^/]+/[^/]+$" ) );
|
|
loc = QDir( loc ).canonicalPath();
|
|
|
|
QDir curlocDir( QgsGrass::getDefaultGisdbase() + sep + QgsGrass::getDefaultLocation() );
|
|
QString curloc = curlocDir.canonicalPath();
|
|
|
|
if ( loc != curloc ) continue;
|
|
|
|
if ( mapset != QgsGrass::getDefaultMapset() ) continue;
|
|
|
|
if ( provider->isFrozen() ) continue;
|
|
|
|
provider->freeze();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void QgsGrassModuleStandardOptions::thawOutput()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
#ifdef WIN32
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleOption *opt = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( !opt )
|
|
continue;
|
|
|
|
QgsDebugMsg( "opt->key() = " + opt->key() );
|
|
|
|
if ( opt->isOutput()
|
|
&& opt->outputType() == QgsGrassModuleOption::Vector )
|
|
{
|
|
QgsDebugMsg( "thaw vector layers" );
|
|
|
|
QChar sep = '/';
|
|
|
|
int nlayers = mCanvas->layerCount();
|
|
for ( int i = 0; i < nlayers; i++ )
|
|
{
|
|
QgsMapLayer *layer = mCanvas->layer( i );
|
|
|
|
if ( layer->type() != QgsMapLayer::VectorLayer ) continue;
|
|
|
|
QgsVectorLayer *vector = ( QgsVectorLayer* )layer;
|
|
if ( vector->providerType() != "grass" ) continue;
|
|
|
|
//TODO dynamic_cast ?
|
|
QgsGrassProvider *provider = ( QgsGrassProvider * ) vector->dataProvider();
|
|
|
|
// TODO add map() mapset() location() gisbase() to grass provider
|
|
QString source = QDir::cleanPath( provider->dataSourceUri() );
|
|
|
|
QgsDebugMsg( "source = " + source );
|
|
|
|
// Check GISBASE and LOCATION
|
|
QStringList split = source.split( sep );
|
|
|
|
if ( split.size() < 4 ) continue;
|
|
split.pop_back(); // layer
|
|
|
|
QString map = split.last();
|
|
split.pop_back(); // map
|
|
|
|
QString mapset = split.last();
|
|
split.pop_back(); // mapset
|
|
|
|
QString loc = source.remove( QRegExp( "/[^/]+/[^/]+/[^/]+$" ) );
|
|
loc = QDir( loc ).canonicalPath();
|
|
|
|
QDir curlocDir( QgsGrass::getDefaultGisdbase() + sep + QgsGrass::getDefaultLocation() );
|
|
QString curloc = curlocDir.canonicalPath();
|
|
|
|
if ( loc != curloc ) continue;
|
|
|
|
if ( mapset != QgsGrass::getDefaultMapset() ) continue;
|
|
|
|
if ( !provider->isFrozen() ) continue;
|
|
|
|
provider->thaw();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
QStringList QgsGrassModuleStandardOptions::output( int type )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
QStringList list;
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleOption *opt = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( !opt )
|
|
continue;
|
|
|
|
QgsDebugMsg( "opt->key() = " + opt->key() );
|
|
|
|
if ( opt->isOutput() )
|
|
{
|
|
if ( opt->outputType() == type )
|
|
{
|
|
QString out = opt->value();
|
|
if ( !out.isEmpty() )
|
|
{
|
|
list.append( out );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
bool QgsGrassModuleStandardOptions::hasOutput( int type )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
QStringList list;
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleOption *opt = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( !opt )
|
|
continue;
|
|
|
|
QgsDebugMsg( "opt->key() = " + opt->key() );
|
|
|
|
if ( opt->isOutput() )
|
|
{
|
|
if ( opt->outputType() == type ) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QStringList QgsGrassModuleStandardOptions::ready()
|
|
{
|
|
QgsDebugMsg( "entered." );
|
|
QStringList list;
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QString err = mItems[i]->ready();
|
|
if ( !err.isNull() )
|
|
{
|
|
list.append( err );
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
QStringList QgsGrassModuleStandardOptions::checkRegion()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
QStringList list;
|
|
|
|
struct Cell_head currentWindow;
|
|
if ( !QgsGrass::region( QgsGrass::getDefaultGisdbase(),
|
|
QgsGrass::getDefaultLocation(),
|
|
QgsGrass::getDefaultMapset(), ¤tWindow ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot get current region" ) );
|
|
return list;
|
|
}
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
struct Cell_head window;
|
|
|
|
QgsGrassModuleInput *item = dynamic_cast<QgsGrassModuleInput *>( mItems[i] );
|
|
if ( !item )
|
|
continue;
|
|
|
|
QgsGrass::MapType mapType = QgsGrass::Vector;
|
|
switch ( item->type() )
|
|
{
|
|
case QgsGrassModuleInput::Raster :
|
|
mapType = QgsGrass::Raster;
|
|
break;
|
|
case QgsGrassModuleInput::Vector :
|
|
mapType = QgsGrass::Vector;
|
|
break;
|
|
}
|
|
|
|
QStringList mm = item->currentMap().split( "@" );
|
|
QString map = mm.at( 0 );
|
|
QString mapset = QgsGrass::getDefaultMapset();
|
|
if ( mm.size() > 1 ) mapset = mm.at( 1 );
|
|
if ( !QgsGrass::mapRegion( mapType,
|
|
QgsGrass::getDefaultGisdbase(),
|
|
QgsGrass::getDefaultLocation(), mapset, map,
|
|
&window ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot check region of map %1" ).arg( item->currentMap() ) );
|
|
continue;
|
|
}
|
|
|
|
if ( G_window_overlap( ¤tWindow,
|
|
window.north, window.south, window.east, window.west ) == 0 )
|
|
{
|
|
list.append( item->currentMap() );
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
bool QgsGrassModuleStandardOptions::inputRegion( struct Cell_head *window, bool all )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
// Get current resolution
|
|
if ( !QgsGrass::region( QgsGrass::getDefaultGisdbase(),
|
|
QgsGrass::getDefaultLocation(),
|
|
QgsGrass::getDefaultMapset(), window ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot get current region" ) );
|
|
return false;
|
|
}
|
|
|
|
int rasterCount = 0;
|
|
int vectorCount = 0;
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
struct Cell_head mapWindow;
|
|
|
|
QgsGrassModuleInput *item = dynamic_cast<QgsGrassModuleInput *>( mItems[i] );
|
|
if ( !item )
|
|
continue;
|
|
|
|
if ( !all && !item->useRegion() ) continue;
|
|
|
|
QgsGrass::MapType mapType = QgsGrass::Vector;
|
|
|
|
switch ( item->type() )
|
|
{
|
|
case QgsGrassModuleInput::Raster :
|
|
mapType = QgsGrass::Raster;
|
|
break;
|
|
case QgsGrassModuleInput::Vector :
|
|
mapType = QgsGrass::Vector;
|
|
break;
|
|
}
|
|
|
|
QStringList mm = item->currentMap().split( "@" );
|
|
QString map = mm.at( 0 );
|
|
QString mapset = QgsGrass::getDefaultMapset();
|
|
if ( mm.size() > 1 ) mapset = mm.at( 1 );
|
|
if ( !QgsGrass::mapRegion( mapType,
|
|
QgsGrass::getDefaultGisdbase(),
|
|
QgsGrass::getDefaultLocation(), mapset, map,
|
|
&mapWindow ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot set region of map %1" ).arg( item->currentMap() ) );
|
|
return false;
|
|
}
|
|
|
|
// TODO: best way to set resolution ?
|
|
if ( item->type() == QgsGrassModuleInput::Raster
|
|
&& rasterCount == 0 )
|
|
{
|
|
QgsGrass::copyRegionResolution( &mapWindow, window );
|
|
}
|
|
if ( rasterCount + vectorCount == 0 )
|
|
{
|
|
QgsGrass::copyRegionExtent( &mapWindow, window );
|
|
}
|
|
else
|
|
{
|
|
QgsGrass::extendRegion( &mapWindow, window );
|
|
}
|
|
|
|
if ( item->type() == QgsGrassModuleInput::Raster )
|
|
rasterCount++;
|
|
else if ( item->type() == QgsGrassModuleInput::Vector )
|
|
vectorCount++;
|
|
}
|
|
|
|
G_adjust_Cell_head3( window, 0, 0, 0 );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool QgsGrassModuleStandardOptions::requestsRegion()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleInput *item = dynamic_cast<QgsGrassModuleInput *>( mItems[i] );
|
|
if ( !item )
|
|
continue;
|
|
|
|
if ( item->useRegion() )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool QgsGrassModuleStandardOptions::usesRegion()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
for ( unsigned int i = 0; i < mItems.size(); i++ )
|
|
{
|
|
QgsGrassModuleInput *input = dynamic_cast<QgsGrassModuleInput *>( mItems[i] );
|
|
if ( input && input->useRegion() )
|
|
return true;
|
|
|
|
/* It only make sense to check input, right?
|
|
* Output has no region yet */
|
|
QgsGrassModuleOption *option = dynamic_cast<QgsGrassModuleOption *>( mItems[i] );
|
|
if ( option && option->usesRegion() )
|
|
return true;
|
|
}
|
|
|
|
QgsDebugMsg( "NO usesRegion()" );
|
|
return false;
|
|
}
|
|
|
|
QgsGrassModuleStandardOptions::~QgsGrassModuleStandardOptions()
|
|
{
|
|
}
|
|
|
|
QString QgsGrassModule::label( QString path )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
// Open QGIS module description
|
|
path.append( ".qgm" );
|
|
QFile qFile( path );
|
|
if ( !qFile.exists() )
|
|
{
|
|
return tr( "Not available, description not found (%1)" ).arg( path );
|
|
}
|
|
if ( ! qFile.open( QIODevice::ReadOnly ) )
|
|
{
|
|
return tr( "Not available, cannot open description (%1)" ).arg( path );
|
|
}
|
|
QDomDocument qDoc( "qgisgrassmodule" );
|
|
QString err;
|
|
int line, column;
|
|
if ( !qDoc.setContent( &qFile, &err, &line, &column ) )
|
|
{
|
|
QString errmsg = tr( "Cannot read module file (%1)" ).arg( path )
|
|
+ tr( "\n%1\nat line %2 column %3" ).arg( err ).arg( line ).arg( column );
|
|
QgsDebugMsg( errmsg );
|
|
QMessageBox::warning( 0, tr( "Warning" ), errmsg );
|
|
qFile.close();
|
|
return tr( "Not available, incorrect description (%1)" ).arg( path );
|
|
}
|
|
qFile.close();
|
|
QDomElement qDocElem = qDoc.documentElement();
|
|
|
|
return QApplication::translate( "grasslabel", qDocElem.attribute( "label" ).trimmed().toUtf8() );
|
|
}
|
|
|
|
QPixmap QgsGrassModule::pixmap( QString path, int height )
|
|
{
|
|
//QgsDebugMsg( QString( "path = %1" ).arg( path ) );
|
|
|
|
std::vector<QPixmap> pixmaps;
|
|
|
|
// Create vector of available pictures
|
|
int cnt = 1;
|
|
while ( 1 )
|
|
{
|
|
// SVG
|
|
QString fpath = path + "." + QString::number( cnt ) + ".svg";
|
|
QFileInfo fi( fpath );
|
|
if ( fi.exists() )
|
|
{
|
|
QSvgRenderer pic;
|
|
if ( ! pic.load( fpath ) ) break;
|
|
|
|
QRect br( QPoint( 0, 0 ), pic.defaultSize() );
|
|
|
|
double scale = 1. * height / br.height();
|
|
|
|
int width = ( int )( scale * br.width() );
|
|
if ( width <= 0 ) width = height; // should not happen
|
|
QPixmap pixmap( width, height );
|
|
pixmap.fill( Qt::transparent );
|
|
//pixmap.fill( QColor( 255, 255, 255 ) );
|
|
QPainter painter( &pixmap );
|
|
painter.setRenderHint( QPainter::Antialiasing );
|
|
|
|
pic.render( &painter );
|
|
painter.end();
|
|
|
|
pixmaps.push_back( pixmap );
|
|
}
|
|
else // PNG
|
|
{
|
|
fpath = path + "." + QString::number( cnt ) + ".png";
|
|
fi.setFile( fpath );
|
|
|
|
if ( !fi.exists() ) break;
|
|
|
|
QPixmap pixmap;
|
|
|
|
if ( ! pixmap.load( fpath, "PNG" ) ) break;
|
|
|
|
double scale = 1. * height / pixmap.height();
|
|
int width = ( int )( scale * pixmap.width() );
|
|
|
|
QImage img = pixmap.toImage();
|
|
img = img.scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
|
pixmap = QPixmap::fromImage( img );
|
|
|
|
pixmaps.push_back( pixmap );
|
|
}
|
|
cnt++;
|
|
}
|
|
|
|
// Get total width
|
|
int width = 0;
|
|
for ( unsigned int i = 0; i < pixmaps.size(); i++ )
|
|
{
|
|
width += pixmaps[i].width();
|
|
}
|
|
|
|
if ( width <= 0 ) width = height; //should not happen
|
|
|
|
QString iconsPath = QgsApplication::pkgDataPath() + "/grass/modules/";
|
|
QFileInfo iconsfi( iconsPath );
|
|
|
|
int plusWidth = 8;
|
|
int arrowWidth = 9;
|
|
|
|
QString arrowPath = iconsPath + "grass_arrow.png";
|
|
QPixmap arrowPixmap;
|
|
iconsfi.setFile( arrowPath );
|
|
if ( iconsfi.exists() && arrowPixmap.load( arrowPath, "PNG" ) )
|
|
{
|
|
double scale = 1. * height / arrowPixmap.height();
|
|
arrowWidth = ( int )( scale * arrowPixmap.width() );
|
|
|
|
QImage img = arrowPixmap.toImage();
|
|
img = img.scaled( arrowWidth, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
|
arrowPixmap = QPixmap::fromImage( img );
|
|
}
|
|
/*if ( iconsfi.exists() )
|
|
{
|
|
QSvgRenderer pic;
|
|
if ( pic.load( arrowPath ) )
|
|
{
|
|
QRect br( QPoint( 0, 0 ), pic.defaultSize() );
|
|
|
|
double scale = 1. * height / br.height();
|
|
|
|
arrowWidth = ( int )( scale * br.width() );
|
|
if ( arrowWidth <= 0 ) arrowWidth = height; // should not happen
|
|
arrowPixmap = QPixmap( arrowWidth, height );
|
|
arrowPixmap.fill( Qt::transparent );
|
|
QPainter painter( &arrowPixmap );
|
|
painter.setRenderHint( QPainter::Antialiasing );
|
|
|
|
pic.render( &painter );
|
|
painter.end();
|
|
}
|
|
}*/
|
|
|
|
QString plusPath = iconsPath + "grass_plus.svg";
|
|
QPixmap plusPixmap;
|
|
iconsfi.setFile( plusPath );
|
|
/*if ( iconsfi.exists() && plusPixmap.load( plusPath, "PNG" ) )
|
|
{
|
|
double scale = 1. * height / plusPixmap.height();
|
|
plusWidth = ( int )( scale * plusPixmap.width() );
|
|
|
|
QImage img = plusPixmap.toImage();
|
|
img = img.scaled( plusWidth, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
|
plusPixmap = QPixmap::fromImage( img );
|
|
}*/
|
|
if ( iconsfi.exists() )
|
|
{
|
|
QSvgRenderer pic;
|
|
if ( pic.load( plusPath ) )
|
|
{
|
|
QRect br( QPoint( 0, 0 ), pic.defaultSize() );
|
|
|
|
double scale = 1. * height / br.height();
|
|
|
|
plusWidth = ( int )( scale * br.width() );
|
|
if ( plusWidth <= 0 ) plusWidth = height; // should not happen
|
|
plusPixmap = QPixmap( plusWidth, height );
|
|
plusPixmap.fill( Qt::transparent );
|
|
QPainter painter( &plusPixmap );
|
|
painter.setRenderHint( QPainter::Antialiasing );
|
|
|
|
pic.render( &painter );
|
|
painter.end();
|
|
}
|
|
}
|
|
int buffer = height / 3; // buffer around a sign
|
|
if ( pixmaps.size() > 1 ) width += arrowWidth + 2 * buffer; // ->
|
|
if ( pixmaps.size() > 2 ) width += plusWidth + 2 * buffer; // +
|
|
|
|
QPixmap pixmap( width, height );
|
|
pixmap.fill( Qt::transparent );
|
|
//pixmap.fill( QColor( 255, 255, 255 ) );
|
|
QPainter painter( &pixmap );
|
|
|
|
//QColor color( 255, 255, 255 );
|
|
//painter.setBrush( QBrush( color ) );
|
|
|
|
painter.setRenderHint( QPainter::Antialiasing );
|
|
|
|
int pos = 0;
|
|
for ( unsigned int i = 0; i < pixmaps.size(); i++ )
|
|
{
|
|
if ( i == 1 && pixmaps.size() == 3 ) // +
|
|
{
|
|
pos += buffer;
|
|
painter.drawPixmap( pos, 0, plusPixmap );
|
|
pos += buffer + plusWidth;
|
|
}
|
|
if (( i == 1 && pixmaps.size() == 2 ) || ( i == 2 && pixmaps.size() == 3 ) ) // ->
|
|
{
|
|
pos += buffer;
|
|
painter.drawPixmap( pos, 0, arrowPixmap );
|
|
pos += buffer + arrowWidth;
|
|
}
|
|
painter.drawPixmap( pos, 0, pixmaps[i] );
|
|
pos += pixmaps[i].width();
|
|
}
|
|
painter.end();
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
void QgsGrassModule::run()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
if ( mProcess.state() == QProcess::Running )
|
|
{
|
|
mProcess.kill();
|
|
mRunButton->setText( tr( "Run" ) );
|
|
}
|
|
else
|
|
{
|
|
//QString command;
|
|
QStringList arguments;
|
|
|
|
//mProcess.clearArguments();
|
|
//mProcess.addArgument( mXName );
|
|
//command = mXName;
|
|
|
|
// Check if options are ready
|
|
QStringList readyErrors = mOptions->ready();
|
|
if ( readyErrors.size() > 0 )
|
|
{
|
|
QString err;
|
|
for ( int i = 0; i < readyErrors.size(); i++ )
|
|
{
|
|
err.append( readyErrors.at( i ) + "<br>" );
|
|
}
|
|
QMessageBox::warning( 0, tr( "Warning" ), err );
|
|
return;
|
|
}
|
|
|
|
// Check/set region
|
|
struct Cell_head tempWindow;
|
|
bool resetRegion = false;
|
|
if ( mOptions->requestsRegion() )
|
|
{
|
|
if ( !mOptions->inputRegion( &tempWindow, false ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot get input region" ) );
|
|
return;
|
|
}
|
|
resetRegion = true;
|
|
}
|
|
else if ( mOptions->usesRegion() )
|
|
{
|
|
QStringList outsideRegion = mOptions->checkRegion();
|
|
if ( outsideRegion.size() > 0 )
|
|
{
|
|
QMessageBox questionBox( QMessageBox::Question, tr( "Warning" ),
|
|
tr( "Input %1 outside current region!" ).arg( outsideRegion.join( "," ) ),
|
|
QMessageBox::Ok | QMessageBox::Cancel );
|
|
QPushButton *resetButton = NULL;
|
|
if ( QgsGrass::versionMajor() > 6 || ( QgsGrass::versionMajor() == 6 && QgsGrass::versionMinor() >= 1 ) )
|
|
{
|
|
resetButton = questionBox.addButton( tr( "Use Input Region" ), QMessageBox::DestructiveRole );
|
|
}
|
|
questionBox.exec();
|
|
QAbstractButton *clicked = questionBox.clickedButton();
|
|
if ( clicked == questionBox.button( QMessageBox::Cancel ) ) return;
|
|
if ( clicked == resetButton ) resetRegion = true;
|
|
|
|
if ( resetRegion )
|
|
{
|
|
if ( !mOptions->inputRegion( &tempWindow, true ) )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot get input region" ) );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if output exists
|
|
QStringList outputExists = mOptions->checkOutput();
|
|
if ( outputExists.size() > 0 )
|
|
{
|
|
QMessageBox::StandardButton ret = QMessageBox::question( 0, "Warning",
|
|
tr( "Output %1 exists! Overwrite?" ).arg( outputExists.join( "," ) ),
|
|
QMessageBox::Ok | QMessageBox::Cancel );
|
|
|
|
if ( ret == QMessageBox::Cancel )
|
|
return;
|
|
|
|
// r.mapcalc does not use standard parser
|
|
if ( typeid( *mOptions ) != typeid( QgsGrassMapcalc ) )
|
|
{
|
|
arguments.append( "--o" );
|
|
//mProcess.addArgument( "--o" );
|
|
//command.append ( " --o" );
|
|
}
|
|
}
|
|
|
|
// Remember output maps
|
|
mOutputVector = mOptions->output( QgsGrassModuleOption::Vector );
|
|
QgsDebugMsg( QString( "mOutputVector.size() = %1" ).arg( mOutputVector.size() ) );
|
|
mOutputRaster = mOptions->output( QgsGrassModuleOption::Raster );
|
|
QgsDebugMsg( QString( "mOutputRaster.size() = %1" ).arg( mOutputRaster.size() ) );
|
|
mSuccess = false;
|
|
mViewButton->setEnabled( false );
|
|
|
|
QStringList list = mOptions->arguments();
|
|
|
|
QStringList argumentsHtml;
|
|
for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
|
|
{
|
|
QgsDebugMsg( "option: " + ( *it ) );
|
|
//command.append ( " " + *it );
|
|
arguments.append( *it );
|
|
//mProcess.addArgument( *it );
|
|
|
|
// Quote options with special characters so that user
|
|
// can copy-paste-run the command
|
|
if ( it->contains( QRegExp( "[ <>\\$|;&]" ) ) )
|
|
{
|
|
argumentsHtml.append( "\"" + *it + "\"" );
|
|
}
|
|
else
|
|
{
|
|
argumentsHtml.append( *it );
|
|
}
|
|
}
|
|
|
|
/* WARNING - TODO: there was a bug in GRASS 6.0.0 / 6.1.CVS (< 2005-04-29):
|
|
* db_start_driver set GISRC_MODE_MEMORY eviroment variable to 1 if
|
|
* G_get_gisrc_mode() == G_GISRC_MODE_MEMORY but the variable wasn't unset
|
|
* if G_get_gisrc_mode() == G_GISRC_MODE_FILE. Because QGIS GRASS provider starts drivers in
|
|
* G_GISRC_MODE_MEMORY mode, the variable remains set in variable when a module is run
|
|
* -> unset GISRC_MODE_MEMORY. Remove later once 6.1.x / 6.0.1 is widespread.
|
|
*/
|
|
putenv(( char* ) "GISRC_MODE_MEMORY" ); // unset
|
|
|
|
mOutputTextBrowser->clear();
|
|
|
|
QString commandHtml = mXName + " " + argumentsHtml.join( " " );
|
|
|
|
QgsDebugMsg( "command: " + commandHtml );
|
|
commandHtml.replace( "&", "&" );
|
|
commandHtml.replace( "<", "<" );
|
|
commandHtml.replace( ">", ">" );
|
|
mOutputTextBrowser->append( "<B>" + commandHtml + "</B>" );
|
|
|
|
QStringList environment = QProcess::systemEnvironment();
|
|
environment.append( "GRASS_HTML_BROWSER=" + QgsApplication::prefixPath() + "/" QGIS_LIBEXEC_SUBDIR "/grass/bin/qgis.g.browser" );
|
|
|
|
// Warning: it is not useful to write requested region to WIND file and
|
|
// reset then to original beacuse it is reset before
|
|
// the region is read by a module even if waitForStarted() is used
|
|
// -> necessary to pass region as environment variable
|
|
// but the feature is available in GRASS 6.1 only since 23.3.2006
|
|
if ( resetRegion )
|
|
{
|
|
QString reg = QgsGrass::regionString( &tempWindow );
|
|
QgsDebugMsg( "reg: " + reg );
|
|
environment.append( "GRASS_REGION=" + reg );
|
|
}
|
|
|
|
// I was not able to get scripts working on Windows
|
|
// via QProcess and sh.exe (MinGW). g.parser runs well
|
|
// and it sets parameters correctly as environment variables
|
|
// but it fails (without error) to re-run the script with
|
|
// execlp(). And I could not figure out why it fails.
|
|
// Because of this problem we simulate here what g.parser
|
|
// normaly does and that way we can avoid it.
|
|
|
|
QStringList execArguments = QgsGrassModule::execArguments( mXName );
|
|
|
|
if ( execArguments.size() == 0 )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find module %1" ).arg( mXName ) );
|
|
return;
|
|
}
|
|
|
|
#if defined(WIN32)
|
|
// we already know it exists from execArguments()
|
|
QString exe = QgsGrassModule::findExec( mXName );
|
|
QFileInfo fi( exe );
|
|
if ( !fi.isExecutable() )
|
|
{
|
|
QStringList usedFlagNames;
|
|
|
|
// Set environment variables
|
|
for ( int i = 0; i < arguments.size(); i++ )
|
|
{
|
|
QString arg = arguments.at( i );
|
|
QString env;
|
|
if ( arg.at( 0 ) == '-' ) //flag
|
|
{
|
|
env = "GIS_FLAG_" + QString( arg.at( 1 ).toUpper() )
|
|
+ "=1";
|
|
usedFlagNames.append( arg.at( 1 ) );
|
|
}
|
|
else // option
|
|
{
|
|
QStringList opt = arg.split( "=" );
|
|
env = "GIS_OPT_" + opt.takeFirst().toUpper();
|
|
env += "=" + opt.join( "=" ); // rejoin rest
|
|
}
|
|
QgsDebugMsg( "set: " + env );
|
|
environment.append( env );
|
|
}
|
|
|
|
// Set remaining flags
|
|
QStringList allFlagNames = mOptions->flagNames();
|
|
for ( int i = 0; i < allFlagNames.size(); i++ )
|
|
{
|
|
bool used = false;
|
|
for ( int j = 0; j < usedFlagNames.size(); j++ )
|
|
{
|
|
if ( usedFlagNames.at( j ) == allFlagNames.at( i ) )
|
|
{
|
|
used = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( used ) continue;
|
|
QString env = "GIS_FLAG_"
|
|
+ QString( allFlagNames.at( i ).toUpper() )
|
|
+ "=0";
|
|
QgsDebugMsg( "set: " + env );
|
|
environment.append( env );
|
|
}
|
|
|
|
arguments.clear();
|
|
arguments.append( "@ARGS_PARSED@" );
|
|
}
|
|
#endif
|
|
|
|
QString cmd = execArguments.takeFirst();
|
|
execArguments += arguments;
|
|
|
|
// Freeze output vector on Windows
|
|
mOptions->freezeOutput();
|
|
|
|
mProcess.setEnvironment( environment );
|
|
mProcess.start( cmd, execArguments );
|
|
|
|
mProcess.waitForStarted();
|
|
if ( mProcess.state() != QProcess::Running )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot start module: %1" ).arg( mProcess.errorString() ) );
|
|
return;
|
|
}
|
|
|
|
mTabWidget->setCurrentIndex( 1 );
|
|
mRunButton->setText( tr( "Stop" ) );
|
|
}
|
|
}
|
|
|
|
void QgsGrassModule::finished( int exitCode, QProcess::ExitStatus exitStatus )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QgsDebugMsg( QString( "exitCode = %1" ).arg( exitCode ) );
|
|
if ( exitStatus == QProcess::NormalExit )
|
|
{
|
|
if ( exitCode == 0 )
|
|
{
|
|
mOutputTextBrowser->append( tr( "<B>Successfully finished</B>" ) );
|
|
mProgressBar->setValue( 100 );
|
|
mSuccess = true;
|
|
mViewButton->setEnabled( true );
|
|
mOptions->thawOutput();
|
|
mCanvas->refresh();
|
|
}
|
|
else
|
|
{
|
|
mOutputTextBrowser->append( tr( "<B>Finished with error</B>" ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mOutputTextBrowser->append( tr( "<B>Module crashed or killed</B>" ) );
|
|
}
|
|
mRunButton->setText( tr( "Run" ) );
|
|
}
|
|
|
|
void QgsGrassModule::readStdout()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString line;
|
|
QRegExp rxpercent( "GRASS_INFO_PERCENT: (\\d+)" );
|
|
|
|
mProcess.setReadChannel( QProcess::StandardOutput );
|
|
while ( mProcess.canReadLine() )
|
|
{
|
|
//line = QString::fromLocal8Bit( mProcess.readLineStdout().ascii() );
|
|
QByteArray ba = mProcess.readLine();
|
|
line = QString::fromUtf8( ba ).replace( '\n', "" );
|
|
//QgsDebugMsg(QString("line: '%1'").arg(line));
|
|
|
|
// GRASS_INFO_PERCENT is catched here only because of bugs in GRASS,
|
|
// normaly it should be printed to stderr
|
|
if ( rxpercent.indexIn( line ) != -1 )
|
|
{
|
|
int progress = rxpercent.cap( 1 ).toInt();
|
|
mProgressBar->setValue( progress );
|
|
}
|
|
else
|
|
{
|
|
mOutputTextBrowser->append( "<pre>" + line + "</pre>" );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsGrassModule::readStderr()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
mProcess.setReadChannel( QProcess::StandardError );
|
|
|
|
QString line;
|
|
QRegExp rxpercent( "GRASS_INFO_PERCENT: (\\d+)" );
|
|
QRegExp rxmessage( "GRASS_INFO_MESSAGE\\(\\d+,\\d+\\): (.*)" );
|
|
QRegExp rxwarning( "GRASS_INFO_WARNING\\(\\d+,\\d+\\): (.*)" );
|
|
QRegExp rxerror( "GRASS_INFO_ERROR\\(\\d+,\\d+\\): (.*)" );
|
|
QRegExp rxend( "GRASS_INFO_END\\(\\d+,\\d+\\)" );
|
|
|
|
|
|
while ( mProcess.canReadLine() )
|
|
{
|
|
//line = QString::fromLocal8Bit( mProcess.readLineStderr().ascii() );
|
|
QByteArray ba = mProcess.readLine();
|
|
line = QString::fromUtf8( ba ).replace( '\n', "" );
|
|
//QgsDebugMsg(QString("line: '%1'").arg(line));
|
|
|
|
if ( rxpercent.indexIn( line ) != -1 )
|
|
{
|
|
int progress = rxpercent.cap( 1 ).toInt();
|
|
mProgressBar->setValue( progress );
|
|
}
|
|
else if ( rxmessage.indexIn( line ) != -1 )
|
|
{
|
|
mOutputTextBrowser->append( "<pre>" + rxmessage.cap( 1 ) + "</pre>" );
|
|
}
|
|
else if ( rxwarning.indexIn( line ) != -1 )
|
|
{
|
|
QString warn = rxwarning.cap( 1 );
|
|
QString img = QgsApplication::pkgDataPath() + "/themes/default/grass/grass_module_warning.png";
|
|
mOutputTextBrowser->append( "<img src=\"" + img + "\">" + warn );
|
|
}
|
|
else if ( rxerror.indexIn( line ) != -1 )
|
|
{
|
|
QString error = rxerror.cap( 1 );
|
|
QString img = QgsApplication::pkgDataPath() + "/themes/default/grass/grass_module_error.png";
|
|
mOutputTextBrowser->append( "<img src=\"" + img + "\">" + error );
|
|
}
|
|
else if ( rxend.indexIn( line ) != -1 )
|
|
{
|
|
// Do nothing
|
|
}
|
|
else
|
|
{
|
|
mOutputTextBrowser->append( "<pre>" + line + "</pre>" );
|
|
}
|
|
}
|
|
}
|
|
|
|
void QgsGrassModule::close()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
void QgsGrassModule::viewOutput()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
if ( !mSuccess ) return;
|
|
|
|
for ( int i = 0; i < mOutputVector.size(); i++ )
|
|
{
|
|
QString map = mOutputVector.at( i );
|
|
|
|
QStringList layers = QgsGrassSelect::vectorLayers(
|
|
QgsGrass::getDefaultGisdbase(),
|
|
QgsGrass::getDefaultLocation(),
|
|
QgsGrass::getDefaultMapset(), map );
|
|
|
|
// check whether there are 1_* layers
|
|
// if so, 0_* layers won't be added
|
|
bool onlyLayer1 = false;
|
|
for ( int j = 0; j < layers.count(); j++ )
|
|
{
|
|
if ( layers[j].left( 1 ) == "1" )
|
|
{
|
|
onlyLayer1 = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO common method for add all layers
|
|
for ( int j = 0; j < layers.count(); j++ )
|
|
{
|
|
QString uri = QgsGrass::getDefaultGisdbase() + "/"
|
|
+ QgsGrass::getDefaultLocation() + "/"
|
|
+ QgsGrass::getDefaultMapset() + "/"
|
|
+ map + "/" + layers[j];
|
|
|
|
// skip 0_* layers
|
|
if ( onlyLayer1 && layers[j].left( 1 ) != "1" )
|
|
continue;
|
|
|
|
QString name = QgsGrassUtils::vectorLayerName(
|
|
map, layers[j], 1 );
|
|
|
|
mIface->addVectorLayer( uri, name, "grass" );
|
|
}
|
|
}
|
|
|
|
for ( int i = 0; i < mOutputRaster.size(); i++ )
|
|
{
|
|
QString map = mOutputRaster.at( i );
|
|
|
|
QString uri = QgsGrass::getDefaultGisdbase() + "/"
|
|
+ QgsGrass::getDefaultLocation() + "/"
|
|
+ QgsGrass::getDefaultMapset()
|
|
+ "/cellhd/" + map;
|
|
|
|
//mIface->addRasterLayer( uri, map );
|
|
mIface->addRasterLayer( uri, map, "grassraster", QStringList(), QStringList(),
|
|
QString(), QString() );
|
|
}
|
|
}
|
|
|
|
QgisInterface *QgsGrassModule::qgisIface() { return mIface; }
|
|
|
|
QgsGrassModule::~QgsGrassModule()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
if ( mProcess.state() == QProcess::Running )
|
|
{
|
|
mProcess.kill();
|
|
}
|
|
}
|
|
|
|
QString QgsGrassModule::translate( QString msg )
|
|
{
|
|
return QString::fromUtf8( G_gettext( "grassmods", msg.trimmed().toUtf8() ) );
|
|
}
|
|
|
|
QDomNode QgsGrassModule::nodeByKey( QDomElement elem, QString key )
|
|
{
|
|
QgsDebugMsg( "called with key=" + key );
|
|
QDomNode n = elem.firstChild();
|
|
|
|
while ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
|
|
if ( !e.isNull() )
|
|
{
|
|
if ( e.tagName() == "parameter" || e.tagName() == "flag" )
|
|
{
|
|
if ( e.attribute( "name" ) == key )
|
|
{
|
|
return n;
|
|
}
|
|
}
|
|
}
|
|
n = n.nextSibling();
|
|
}
|
|
|
|
return QDomNode();
|
|
}
|
|
|
|
/******************* QgsGrassModuleOption ****************************/
|
|
|
|
QgsGrassModuleOption::QgsGrassModuleOption( QgsGrassModule *module, QString key,
|
|
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
|
QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent ),
|
|
mControlType( NoControl ), mValueType( String ), mOutputType( None ), mHaveLimits( false ), mIsOutput( false )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Minimum );
|
|
|
|
if ( mHidden ) hide();
|
|
|
|
mLayout = new QVBoxLayout();
|
|
|
|
// Is it output?
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
if ( !promptNode.isNull() )
|
|
{
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
QString age = promptElem.attribute( "age" );
|
|
|
|
if ( age == "new" )
|
|
{
|
|
mOutputElement = element;
|
|
mIsOutput = true;
|
|
|
|
if ( element == "vector" )
|
|
{
|
|
mOutputType = Vector;
|
|
}
|
|
else if ( element == "cell" )
|
|
{
|
|
mOutputType = Raster;
|
|
}
|
|
}
|
|
}
|
|
|
|
// String without options
|
|
if ( !mHidden )
|
|
{
|
|
QDomElement gelem = gnode.toElement();
|
|
|
|
// Predefined values ?
|
|
QDomNode valuesNode = gnode.namedItem( "values" );
|
|
QDomElement valuesElem = valuesNode.toElement(); // null if valuesNode is null
|
|
|
|
if ( !valuesNode.isNull() && valuesNode.childNodes().count() > 1 )
|
|
{
|
|
setLayout( mLayout );
|
|
// predefined values -> ComboBox or CheckBox
|
|
|
|
// one or many?
|
|
if ( gelem.attribute( "multiple" ) == "yes" )
|
|
{
|
|
mControlType = CheckBoxes;
|
|
}
|
|
else
|
|
{
|
|
mControlType = ComboBox;
|
|
mComboBox = new QComboBox( this );
|
|
mLayout->addWidget( mComboBox );
|
|
}
|
|
|
|
// List of values to be excluded
|
|
QStringList exclude = qdesc.attribute( "exclude" ).split( ',', QString::SkipEmptyParts );
|
|
|
|
QDomNode valueNode = valuesElem.firstChild();
|
|
|
|
while ( !valueNode.isNull() )
|
|
{
|
|
QDomElement valueElem = valueNode.toElement();
|
|
|
|
if ( !valueElem.isNull() && valueElem.tagName() == "value" )
|
|
{
|
|
|
|
QDomNode n = valueNode.namedItem( "name" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
QString val = e.text().trimmed();
|
|
|
|
if ( exclude.contains( val ) == 0 )
|
|
{
|
|
n = valueNode.namedItem( "description" );
|
|
QString desc;
|
|
if ( !n.isNull() )
|
|
{
|
|
e = n.toElement();
|
|
desc = e.text().trimmed();
|
|
}
|
|
else
|
|
{
|
|
desc = val;
|
|
}
|
|
desc.replace( 0, 1, desc.left( 1 ).toUpper() );
|
|
|
|
if ( mControlType == ComboBox )
|
|
{
|
|
mComboBox->addItem( desc );
|
|
if ( mAnswer.length() > 0 && desc == mAnswer )
|
|
{
|
|
mComboBox->setCurrentIndex( mComboBox->count() - 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QgsGrassModuleCheckBox *cb = new QgsGrassModuleCheckBox( desc, this );
|
|
mCheckBoxes.push_back( cb );
|
|
mLayout->addWidget( cb );
|
|
}
|
|
|
|
mValues.push_back( val );
|
|
}
|
|
}
|
|
}
|
|
|
|
valueNode = valueNode.nextSibling();
|
|
}
|
|
}
|
|
else // No values
|
|
{
|
|
// Line edit
|
|
mControlType = LineEdit;
|
|
|
|
if ( gelem.attribute( "type" ) == "integer" )
|
|
{
|
|
mValueType = Integer;
|
|
}
|
|
else if ( gelem.attribute( "type" ) == "float" )
|
|
{
|
|
mValueType = Double;
|
|
}
|
|
|
|
QStringList minMax;
|
|
if ( valuesNode.childNodes().count() == 1 )
|
|
{
|
|
QDomNode valueNode = valuesElem.firstChild();
|
|
|
|
QDomNode n = valueNode.namedItem( "name" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
QString val = e.text().trimmed();
|
|
minMax = val.split( "-" );
|
|
if ( minMax.size() == 2 )
|
|
{
|
|
mHaveLimits = true;
|
|
mMin = minMax.at( 0 ).toDouble();
|
|
mMax = minMax.at( 1 ).toDouble();
|
|
}
|
|
}
|
|
}
|
|
|
|
QDomNode keydescNode = gnode.namedItem( "keydesc" );
|
|
if ( !keydescNode.isNull() )
|
|
{
|
|
// fixed number of line edits
|
|
// Example:
|
|
// <keydesc>
|
|
// <item order="1">rows</item>
|
|
// <item order="2">columns</item>
|
|
// </keydesc>
|
|
|
|
QDomNodeList keydescs = keydescNode.childNodes();
|
|
for ( int k = 0; k < keydescs.count(); k++ )
|
|
{
|
|
QDomNode nodeItem = keydescs.at( k );
|
|
QString itemDesc = nodeItem.toElement().text().trimmed();
|
|
//QString itemDesc = nodeItem.firstChild().toText().data();
|
|
QgsDebugMsg( "keydesc item = " + itemDesc );
|
|
|
|
addLineEdit();
|
|
}
|
|
|
|
setLayout( mLayout );
|
|
}
|
|
else if ( gelem.attribute( "multiple" ) == "yes" )
|
|
{
|
|
// variable number of line edits
|
|
// add/delete buttons for multiple options
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
QVBoxLayout *vl = new QVBoxLayout();
|
|
l->insertLayout( -1, mLayout );
|
|
l->insertLayout( -1, vl );
|
|
|
|
// TODO: how to keep both buttons on the top?
|
|
QPushButton *b = new QPushButton( "+", this );
|
|
connect( b, SIGNAL( clicked() ), this, SLOT( addLineEdit() ) );
|
|
vl->addWidget( b, 0, Qt::AlignTop );
|
|
|
|
b = new QPushButton( "-", this );
|
|
connect( b, SIGNAL( clicked() ), this, SLOT( removeLineEdit() ) );
|
|
vl->addWidget( b, 0, Qt::AlignTop );
|
|
|
|
// Don't enable this, it makes the group box expanding
|
|
// vl->addStretch();
|
|
}
|
|
else
|
|
{
|
|
// only one line edit
|
|
addLineEdit();
|
|
setLayout( mLayout );
|
|
}
|
|
}
|
|
}
|
|
|
|
mUsesRegion = false;
|
|
QString region = qdesc.attribute( "region" );
|
|
if ( region.length() > 0 )
|
|
{
|
|
if ( region == "yes" )
|
|
mUsesRegion = true;
|
|
}
|
|
else
|
|
{
|
|
QgsDebugMsg( "\n\n\n\n**************************" );
|
|
QgsDebugMsg( "isOutput = " + isOutput() );
|
|
QgsDebugMsg( "mOutputType = " + mOutputType );
|
|
if ( isOutput() && mOutputType == Raster )
|
|
mUsesRegion = true;
|
|
}
|
|
QgsDebugMsg( "mUsesRegion = " + mUsesRegion );
|
|
}
|
|
|
|
void QgsGrassModuleOption::addLineEdit()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
// TODO make the widget growing with new lines. HOW???!!!
|
|
QLineEdit *lineEdit = new QLineEdit( this );
|
|
mLineEdits.push_back( lineEdit );
|
|
lineEdit->setText( mAnswer );
|
|
|
|
if ( mValueType == Integer )
|
|
{
|
|
if ( mHaveLimits )
|
|
{
|
|
mValidator = new QIntValidator(( int )mMin, ( int )mMax, this );
|
|
}
|
|
else
|
|
{
|
|
mValidator = new QIntValidator( this );
|
|
}
|
|
lineEdit->setValidator( mValidator );
|
|
}
|
|
else if ( mValueType == Double )
|
|
{
|
|
if ( mHaveLimits )
|
|
{
|
|
mValidator = new QDoubleValidator( mMin, mMax, 10, this );
|
|
}
|
|
else
|
|
{
|
|
mValidator = new QDoubleValidator( this );
|
|
}
|
|
lineEdit->setValidator( mValidator );
|
|
}
|
|
else if ( mIsOutput )
|
|
{
|
|
QRegExp rx;
|
|
if ( mOutputType == Vector )
|
|
{
|
|
rx.setPattern( "[A-Za-z_][A-Za-z0-9_]+" );
|
|
}
|
|
else
|
|
{
|
|
rx.setPattern( "[A-Za-z0-9_.]+" );
|
|
}
|
|
mValidator = new QRegExpValidator( rx, this );
|
|
|
|
lineEdit->setValidator( mValidator );
|
|
}
|
|
|
|
mLayout->addWidget( lineEdit );
|
|
}
|
|
|
|
void QgsGrassModuleOption::removeLineEdit()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
if ( mLineEdits.size() < 2 ) return;
|
|
delete mLineEdits.at( mLineEdits.size() - 1 );
|
|
mLineEdits.pop_back();
|
|
}
|
|
|
|
QString QgsGrassModuleOption::outputExists()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
if ( !mIsOutput ) return QString();
|
|
|
|
QLineEdit *lineEdit = mLineEdits.at( 0 );
|
|
QString value = lineEdit->text().trimmed();
|
|
QgsDebugMsg( "mKey = " + mKey );
|
|
QgsDebugMsg( "value = " + value );
|
|
QgsDebugMsg( "mOutputElement = " + mOutputElement );
|
|
|
|
if ( value.length() == 0 ) return QString();
|
|
|
|
QString path = QgsGrass::getDefaultGisdbase() + "/"
|
|
+ QgsGrass::getDefaultLocation() + "/"
|
|
+ QgsGrass::getDefaultMapset() + "/"
|
|
+ mOutputElement + "/" + value;
|
|
|
|
QFileInfo fi( path );
|
|
|
|
if ( fi.exists() )
|
|
{
|
|
return ( lineEdit->text() );
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
QString QgsGrassModuleOption::value()
|
|
{
|
|
QString value;
|
|
|
|
if ( mControlType == LineEdit )
|
|
{
|
|
for ( unsigned int i = 0; i < mLineEdits.size(); i++ )
|
|
{
|
|
QLineEdit *lineEdit = mLineEdits.at( i );
|
|
if ( lineEdit->text().trimmed().length() > 0 )
|
|
{
|
|
if ( value.length() > 0 ) value.append( "," );
|
|
value.append( lineEdit->text().trimmed() );
|
|
}
|
|
}
|
|
}
|
|
else if ( mControlType == ComboBox )
|
|
{
|
|
value = mValues[mComboBox->currentIndex()];
|
|
}
|
|
else if ( mControlType == CheckBoxes )
|
|
{
|
|
QStringList values;
|
|
for ( unsigned int i = 0; i < mCheckBoxes.size(); ++i )
|
|
{
|
|
if ( mCheckBoxes[i]->isChecked() )
|
|
{
|
|
values.append( mValues[i] );
|
|
}
|
|
}
|
|
value = values.join( "," );
|
|
}
|
|
return value;
|
|
}
|
|
|
|
QStringList QgsGrassModuleOption::options()
|
|
{
|
|
QStringList list;
|
|
|
|
if ( mHidden )
|
|
{
|
|
list.push_back( mKey + "=" + mAnswer );
|
|
}
|
|
else
|
|
{
|
|
QString val = value();
|
|
if ( !val.isEmpty() )
|
|
{
|
|
list.push_back( mKey + "=" + val );
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
QString QgsGrassModuleOption::ready()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString error;
|
|
|
|
if ( mControlType == LineEdit )
|
|
{
|
|
if ( mLineEdits.at( 0 )->text().trimmed().length() == 0 && mRequired )
|
|
{
|
|
error.append( tr( "%1: missing value" ).arg( title() ) );
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
|
|
QgsGrassModuleOption::~QgsGrassModuleOption()
|
|
{
|
|
}
|
|
|
|
QgsGrassModuleFlag::QgsGrassModuleFlag( QgsGrassModule *module, QString key,
|
|
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
|
QWidget * parent )
|
|
: QgsGrassModuleCheckBox( "", parent ), QgsGrassModuleItem( module, key, qdesc, gdesc, gnode )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
if ( mHidden ) hide();
|
|
|
|
if ( mAnswer == "on" )
|
|
setChecked( true );
|
|
else
|
|
setChecked( false );
|
|
|
|
setText( mTitle );
|
|
setToolTip( mToolTip );
|
|
}
|
|
|
|
QStringList QgsGrassModuleFlag::options()
|
|
{
|
|
QStringList list;
|
|
if ( isChecked() )
|
|
{
|
|
list.push_back( "-" + mKey );
|
|
}
|
|
return list;
|
|
}
|
|
|
|
QgsGrassModuleFlag::~QgsGrassModuleFlag()
|
|
{
|
|
}
|
|
|
|
/************************** QgsGrassModuleInput ***************************/
|
|
|
|
QgsGrassModuleInput::QgsGrassModuleInput( QgsGrassModule *module,
|
|
QgsGrassModuleStandardOptions *options, QString key,
|
|
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
|
QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent )
|
|
, mModuleStandardOptions( options )
|
|
, mGeometryTypeOption( "" )
|
|
, mVectorLayerOption( "" )
|
|
, mRegionButton( 0 )
|
|
, mUpdate( false )
|
|
, mRequired( false )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
mGeometryTypeMask = GV_POINT | GV_LINE | GV_AREA;
|
|
|
|
if ( mTitle.isEmpty() )
|
|
{
|
|
mTitle = tr( "Input" );
|
|
}
|
|
adjustTitle();
|
|
|
|
// Check if this parameter is required
|
|
mRequired = gnode.toElement().attribute( "required" ) == "yes";
|
|
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
|
|
if ( element == "vector" )
|
|
{
|
|
mType = Vector;
|
|
|
|
// Read type mask if "typeoption" is defined
|
|
QString opt = qdesc.attribute( "typeoption" );
|
|
if ( ! opt.isNull() )
|
|
{
|
|
|
|
QDomNode optNode = QgsGrassModule::nodeByKey( gdesc, opt );
|
|
|
|
if ( optNode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find typeoption %1" ).arg( opt ) );
|
|
}
|
|
else
|
|
{
|
|
mGeometryTypeOption = opt;
|
|
|
|
QDomNode valuesNode = optNode.namedItem( "values" );
|
|
if ( valuesNode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find values for typeoption %1" ).arg( opt ) );
|
|
}
|
|
else
|
|
{
|
|
mGeometryTypeMask = 0; //GV_POINT | GV_LINE | GV_AREA;
|
|
|
|
QDomElement valuesElem = valuesNode.toElement();
|
|
QDomNode valueNode = valuesElem.firstChild();
|
|
|
|
while ( !valueNode.isNull() )
|
|
{
|
|
QDomElement valueElem = valueNode.toElement();
|
|
|
|
if ( !valueElem.isNull() && valueElem.tagName() == "value" )
|
|
{
|
|
QDomNode n = valueNode.namedItem( "name" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
QString val = e.text().trimmed();
|
|
|
|
if ( val == "point" )
|
|
{
|
|
mGeometryTypeMask |= GV_POINT;
|
|
}
|
|
else if ( val == "line" )
|
|
{
|
|
mGeometryTypeMask |= GV_LINE;
|
|
}
|
|
else if ( val == "area" )
|
|
{
|
|
mGeometryTypeMask |= GV_AREA;
|
|
}
|
|
}
|
|
}
|
|
|
|
valueNode = valueNode.nextSibling();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Read type mask defined in configuration
|
|
opt = qdesc.attribute( "typemask" );
|
|
if ( ! opt.isNull() )
|
|
{
|
|
int mask = 0;
|
|
|
|
if ( opt.indexOf( "point" ) >= 0 )
|
|
{
|
|
mask |= GV_POINT;
|
|
}
|
|
if ( opt.indexOf( "line" ) >= 0 )
|
|
{
|
|
mask |= GV_LINE;
|
|
}
|
|
if ( opt.indexOf( "area" ) >= 0 )
|
|
{
|
|
mask |= GV_AREA;
|
|
}
|
|
|
|
mGeometryTypeMask &= mask;
|
|
}
|
|
|
|
// Read "layeroption" if defined
|
|
opt = qdesc.attribute( "layeroption" );
|
|
if ( ! opt.isNull() )
|
|
{
|
|
|
|
QDomNode optNode = QgsGrassModule::nodeByKey( gdesc, opt );
|
|
|
|
if ( optNode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find layeroption %1" ).arg( opt ) );
|
|
}
|
|
else
|
|
{
|
|
mVectorLayerOption = opt;
|
|
}
|
|
}
|
|
|
|
// Read "mapid"
|
|
mMapId = qdesc.attribute( "mapid" );
|
|
}
|
|
else if ( element == "cell" )
|
|
{
|
|
mType = Raster;
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "GRASS element %1 not supported" ).arg( element ) );
|
|
}
|
|
|
|
if ( qdesc.attribute( "update" ) == "yes" )
|
|
{
|
|
mUpdate = true;
|
|
}
|
|
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
mLayerComboBox = new QComboBox();
|
|
mLayerComboBox->setSizePolicy( QSizePolicy::Expanding,
|
|
QSizePolicy:: Preferred );
|
|
l->addWidget( mLayerComboBox );
|
|
|
|
QString region = qdesc.attribute( "region" );
|
|
if ( mType == Raster
|
|
&& QgsGrass::versionMajor() >= 6 && QgsGrass::versionMinor() >= 1
|
|
&& region != "no"
|
|
)
|
|
{
|
|
|
|
mRegionButton = new QPushButton(
|
|
QgsGrassPlugin::getThemeIcon( "grass_set_region.png" ), "" );
|
|
|
|
mRegionButton->setToolTip( tr( "Use region of this map" ) );
|
|
mRegionButton->setCheckable( true );
|
|
mRegionButton->setSizePolicy( QSizePolicy::Minimum,
|
|
QSizePolicy:: Preferred );
|
|
l->addWidget( mRegionButton );
|
|
}
|
|
|
|
// Of course, activated(int) is not enough, but there is no signal BEFORE the cobo is opened
|
|
//connect ( mLayerComboBox, SIGNAL( activated(int) ), this, SLOT(updateQgisLayers()) );
|
|
|
|
// Connect to canvas
|
|
QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
connect( canvas, SIGNAL( layersChanged() ), this, SLOT( updateQgisLayers() ) );
|
|
|
|
connect( mLayerComboBox, SIGNAL( activated( int ) ), this, SLOT( changed( int ) ) );
|
|
|
|
if ( !mMapId.isEmpty() )
|
|
{
|
|
QgsGrassModuleItem *item = mModuleStandardOptions->item( mMapId );
|
|
if ( item )
|
|
{
|
|
QgsGrassModuleInput *mapInput = dynamic_cast<QgsGrassModuleInput *>( item );
|
|
|
|
connect( mapInput, SIGNAL( valueChanged() ), this, SLOT( updateQgisLayers() ) );
|
|
}
|
|
}
|
|
|
|
mUsesRegion = false;
|
|
if ( region.length() > 0 )
|
|
{
|
|
if ( region == "yes" )
|
|
mUsesRegion = true;
|
|
}
|
|
else
|
|
{
|
|
if ( type() == Raster )
|
|
mUsesRegion = true;
|
|
}
|
|
|
|
// Fill in QGIS layers
|
|
updateQgisLayers();
|
|
}
|
|
|
|
bool QgsGrassModuleInput::useRegion()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
return mUsesRegion && mType == Raster && mRegionButton && mRegionButton->isChecked();
|
|
}
|
|
|
|
void QgsGrassModuleInput::updateQgisLayers()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString current = mLayerComboBox->currentText();
|
|
mLayerComboBox->clear();
|
|
mMaps.clear();
|
|
mGeometryTypes.clear();
|
|
mVectorLayerNames.clear();
|
|
mMapLayers.clear();
|
|
mVectorFields.clear();
|
|
|
|
// If not required, add an empty item to combobox and a padding item into
|
|
// layer containers.
|
|
if ( !mRequired )
|
|
{
|
|
mMaps.push_back( QString( "" ) );
|
|
mVectorLayerNames.push_back( QString( "" ) );
|
|
mMapLayers.push_back( NULL );
|
|
mLayerComboBox->addItem( tr( "Select a layer" ), QVariant() );
|
|
}
|
|
|
|
QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
|
|
// Find map option
|
|
QString sourceMap;
|
|
if ( !mMapId.isEmpty() )
|
|
{
|
|
QgsGrassModuleItem *item = mModuleStandardOptions->item( mMapId );
|
|
if ( item )
|
|
{
|
|
QgsGrassModuleInput *mapInput = dynamic_cast<QgsGrassModuleInput *>( item );
|
|
sourceMap = mapInput->currentMap();
|
|
}
|
|
}
|
|
|
|
// Note: QDir::cleanPath is using '/' also on Windows
|
|
//QChar sep = QDir::separator();
|
|
QChar sep = '/';
|
|
|
|
int nlayers = canvas->layerCount();
|
|
for ( int i = 0; i < nlayers; i++ )
|
|
{
|
|
QgsMapLayer *layer = canvas->layer( i );
|
|
|
|
QgsDebugMsg( "layer->type() = " + QString::number( layer->type() ) );
|
|
|
|
if ( mType == Vector && layer->type() == QgsMapLayer::VectorLayer )
|
|
{
|
|
QgsVectorLayer *vector = ( QgsVectorLayer* )layer;
|
|
QgsDebugMsg( "vector->providerType() = " + vector->providerType() );
|
|
if ( vector->providerType() != "grass" ) continue;
|
|
|
|
//TODO dynamic_cast ?
|
|
QgsGrassProvider *provider = ( QgsGrassProvider * ) vector->dataProvider();
|
|
|
|
// Check type mask
|
|
int geomType = provider->geometryType();
|
|
|
|
if (( geomType == QGis::WKBPoint && !( mGeometryTypeMask & GV_POINT ) ) ||
|
|
( geomType == QGis::WKBLineString && !( mGeometryTypeMask & GV_LINE ) ) ||
|
|
( geomType == QGis::WKBPolygon && !( mGeometryTypeMask & GV_AREA ) )
|
|
)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// TODO add map() mapset() location() gisbase() to grass provider
|
|
QString source = QDir::cleanPath( provider->dataSourceUri() );
|
|
|
|
QgsDebugMsg( "source = " + source );
|
|
|
|
// Check GISBASE and LOCATION
|
|
QStringList split = source.split( sep, QString::SkipEmptyParts );
|
|
|
|
if ( split.size() < 4 ) continue;
|
|
split.pop_back(); // layer
|
|
|
|
QString map = split.last();
|
|
split.pop_back(); // map
|
|
|
|
QString mapset = split.last();
|
|
split.pop_back(); // mapset
|
|
|
|
//QDir locDir ( sep + split.join ( QString(sep) ) ) ;
|
|
//QString loc = locDir.canonicalPath();
|
|
QString loc = source.remove( QRegExp( "/[^/]+/[^/]+/[^/]+$" ) );
|
|
loc = QDir( loc ).canonicalPath();
|
|
|
|
QDir curlocDir( QgsGrass::getDefaultGisdbase() + sep + QgsGrass::getDefaultLocation() );
|
|
QString curloc = curlocDir.canonicalPath();
|
|
|
|
QgsDebugMsg( "loc = " + loc );
|
|
QgsDebugMsg( "curloc = " + curloc );
|
|
QgsDebugMsg( "mapset = " + mapset );
|
|
QgsDebugMsg( "QgsGrass::getDefaultMapset() = " + QgsGrass::getDefaultMapset() );
|
|
|
|
if ( loc != curloc ) continue;
|
|
|
|
if ( mUpdate && mapset != QgsGrass::getDefaultMapset() ) continue;
|
|
|
|
// Check if it comes from source map if necessary
|
|
if ( !mMapId.isEmpty() )
|
|
{
|
|
QString cm = map + "@" + mapset;
|
|
if ( sourceMap != cm ) continue;
|
|
}
|
|
|
|
mMaps.push_back( map + "@" + mapset );
|
|
|
|
QString type;
|
|
if ( geomType == QGis::WKBPoint )
|
|
{
|
|
type = "point";
|
|
}
|
|
else if ( geomType == QGis::WKBLineString )
|
|
{
|
|
type = "line";
|
|
}
|
|
else if ( geomType == QGis::WKBPolygon )
|
|
{
|
|
type = "area";
|
|
}
|
|
else
|
|
{
|
|
type = "unknown";
|
|
}
|
|
|
|
mGeometryTypes.push_back( type );
|
|
|
|
QString grassLayer = QString::number( provider->grassLayer() );
|
|
|
|
QString label = layer->name() + " ( " + map + "@" + mapset
|
|
+ " " + grassLayer + " " + type + " )";
|
|
|
|
mLayerComboBox->addItem( label );
|
|
if ( label == current ) mLayerComboBox->setCurrentIndex( mLayerComboBox->count() - 1 );
|
|
|
|
mMapLayers.push_back( vector );
|
|
mVectorLayerNames.push_back( grassLayer );
|
|
|
|
// convert from QgsFieldMap to std::vector<QgsField>
|
|
QgsFieldMap flds = vector->dataProvider()->fields();
|
|
std::vector<QgsField> fields;
|
|
for ( QgsFieldMap::iterator it = flds.begin(); it != flds.end(); ++it )
|
|
fields.push_back( it.value() );
|
|
mVectorFields.push_back( fields );
|
|
}
|
|
else if ( mType == Raster && layer->type() == QgsMapLayer::RasterLayer )
|
|
{
|
|
// Check if it is GRASS raster
|
|
QString source = QDir::cleanPath( layer->source() );
|
|
|
|
if ( source.contains( "cellhd" ) == 0 ) continue;
|
|
|
|
// Most probably GRASS layer, check GISBASE and LOCATION
|
|
QStringList split = source.split( sep, QString::SkipEmptyParts );
|
|
|
|
if ( split.size() < 4 ) continue;
|
|
|
|
QString map = split.last();
|
|
split.pop_back(); // map
|
|
if ( split.last() != "cellhd" ) continue;
|
|
split.pop_back(); // cellhd
|
|
|
|
QString mapset = split.last();
|
|
split.pop_back(); // mapset
|
|
|
|
//QDir locDir ( sep + split.join ( QString(sep) ) ) ;
|
|
//QString loc = locDir.canonicalPath();
|
|
QString loc = source.remove( QRegExp( "/[^/]+/[^/]+/[^/]+$" ) );
|
|
loc = QDir( loc ).canonicalPath();
|
|
|
|
QDir curlocDir( QgsGrass::getDefaultGisdbase() + sep + QgsGrass::getDefaultLocation() );
|
|
QString curloc = curlocDir.canonicalPath();
|
|
|
|
if ( loc != curloc ) continue;
|
|
|
|
if ( mUpdate && mapset != QgsGrass::getDefaultMapset() ) continue;
|
|
|
|
mMaps.push_back( map + "@" + mapset );
|
|
|
|
QString label = layer->name() + " ( " + map + "@" + mapset + " )";
|
|
|
|
mLayerComboBox->addItem( label );
|
|
if ( label == current ) mLayerComboBox->setCurrentIndex( mLayerComboBox->count() - 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
QStringList QgsGrassModuleInput::options()
|
|
{
|
|
QStringList list;
|
|
QString opt;
|
|
|
|
int current = mLayerComboBox->currentIndex();
|
|
if ( current < 0 ) // not found
|
|
return list;
|
|
|
|
// TODO: this is hack for network nodes, do it somehow better
|
|
if ( mMapId.isEmpty() )
|
|
{
|
|
if ( current < mMaps.size() )
|
|
{
|
|
if ( ! mMaps[current].isEmpty() )
|
|
{
|
|
list.push_back( mKey + "=" + mMaps[current] );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !mGeometryTypeOption.isNull() && current < mGeometryTypes.size() )
|
|
{
|
|
opt = mGeometryTypeOption + "=" + mGeometryTypes[current] ;
|
|
list.push_back( opt );
|
|
}
|
|
|
|
if ( !mVectorLayerOption.isNull() && current < mVectorLayerNames.size() )
|
|
{
|
|
opt = mVectorLayerOption + "=" + mVectorLayerNames[current] ;
|
|
list.push_back( opt );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
std::vector<QgsField> QgsGrassModuleInput::currentFields()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
unsigned int limit = 0;
|
|
if ( !mRequired )
|
|
limit = 1;
|
|
|
|
std::vector<QgsField> fields;
|
|
|
|
unsigned int current = mLayerComboBox->currentIndex();
|
|
if ( current < limit )
|
|
return fields;
|
|
|
|
if ( current >= limit && current < mVectorFields.size() )
|
|
{
|
|
fields = mVectorFields[current];
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
QgsMapLayer * QgsGrassModuleInput::currentLayer()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
unsigned int limit = 0;
|
|
if ( !mRequired )
|
|
limit = 1;
|
|
|
|
unsigned int current = mLayerComboBox->currentIndex();
|
|
if ( current < limit )
|
|
return 0;
|
|
|
|
if ( current >= limit && current < mMapLayers.size() )
|
|
{
|
|
return mMapLayers[current];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
QString QgsGrassModuleInput::currentMap()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
int limit = 0;
|
|
if ( !mRequired )
|
|
limit = 1;
|
|
|
|
int current = mLayerComboBox->currentIndex();
|
|
if ( current < limit )
|
|
return QString();
|
|
|
|
if ( current >= limit && current < mMaps.size() )
|
|
{
|
|
return mMaps[current];
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
void QgsGrassModuleInput::changed( int i )
|
|
{
|
|
emit valueChanged();
|
|
}
|
|
|
|
QString QgsGrassModuleInput::ready()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString error;
|
|
|
|
QgsDebugMsg( QString( "count = %1" ).arg( mLayerComboBox->count() ) );
|
|
if ( mLayerComboBox->count() == 0 )
|
|
{
|
|
error.append( tr( "%1: no input" ).arg( title() ) );
|
|
}
|
|
return error;
|
|
}
|
|
|
|
QgsGrassModuleInput::~QgsGrassModuleInput()
|
|
{
|
|
}
|
|
|
|
/********************** QgsGrassModuleItem *************************/
|
|
|
|
QgsGrassModuleItem::QgsGrassModuleItem( QgsGrassModule *module, QString key,
|
|
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode )
|
|
: mModule( module ),
|
|
mKey( key ),
|
|
mHidden( false ),
|
|
mRequired( false )
|
|
{
|
|
//mAnswer = qdesc.attribute("answer", "");
|
|
|
|
if ( !qdesc.attribute( "answer" ).isNull() )
|
|
{
|
|
mAnswer = qdesc.attribute( "answer" ).trimmed();
|
|
}
|
|
else
|
|
{
|
|
QDomNode n = gnode.namedItem( "default" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
mAnswer = e.text().trimmed();
|
|
}
|
|
}
|
|
|
|
if ( qdesc.attribute( "hidden" ) == "yes" )
|
|
{
|
|
mHidden = true;
|
|
}
|
|
|
|
QString label, description;
|
|
if ( !qdesc.attribute( "label" ).isEmpty() )
|
|
{
|
|
label = QApplication::translate( "grasslabel", qdesc.attribute( "label" ).trimmed().toUtf8() );
|
|
}
|
|
if ( label.isEmpty() )
|
|
{
|
|
QDomNode n = gnode.namedItem( "label" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
label = module->translate( e.text() );
|
|
}
|
|
}
|
|
QDomNode n = gnode.namedItem( "description" );
|
|
if ( !n.isNull() )
|
|
{
|
|
QDomElement e = n.toElement();
|
|
description = module->translate( e.text() );
|
|
}
|
|
|
|
if ( !label.isEmpty() )
|
|
{
|
|
mTitle = label;
|
|
mToolTip = description;
|
|
}
|
|
else
|
|
{
|
|
mTitle = description;
|
|
}
|
|
|
|
if ( gnode.toElement().attribute( "required" ) == "yes" )
|
|
{
|
|
mRequired = true;
|
|
}
|
|
|
|
mId = qdesc.attribute( "id" );
|
|
}
|
|
|
|
bool QgsGrassModuleItem::hidden() { return mHidden; }
|
|
|
|
QStringList QgsGrassModuleItem::options() { return QStringList(); }
|
|
|
|
QgsGrassModuleItem::~QgsGrassModuleItem() {}
|
|
|
|
/***************** QgsGrassModuleGroupBoxItem *********************/
|
|
|
|
QgsGrassModuleGroupBoxItem::QgsGrassModuleGroupBoxItem( QgsGrassModule *module, QString key,
|
|
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
|
QWidget * parent )
|
|
: QGroupBox( parent ),
|
|
QgsGrassModuleItem( module, key, qdesc, gdesc, gnode )
|
|
{
|
|
adjustTitle();
|
|
|
|
setToolTip( mToolTip );
|
|
}
|
|
|
|
QgsGrassModuleGroupBoxItem::~QgsGrassModuleGroupBoxItem() {}
|
|
|
|
void QgsGrassModuleGroupBoxItem::resizeEvent( QResizeEvent * event )
|
|
{
|
|
adjustTitle();
|
|
setToolTip( mToolTip );
|
|
}
|
|
|
|
void QgsGrassModuleGroupBoxItem::adjustTitle()
|
|
{
|
|
QString tit = fontMetrics().elidedText( mTitle, Qt::ElideRight, width() - 20 );
|
|
|
|
setTitle( tit );
|
|
}
|
|
|
|
/***************** QgsGrassModuleGdalInput *********************/
|
|
|
|
QgsGrassModuleGdalInput::QgsGrassModuleGdalInput(
|
|
QgsGrassModule *module, int type, QString key, QDomElement &qdesc,
|
|
QDomElement &gdesc, QDomNode &gnode, QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent )
|
|
, mType( type )
|
|
, mOgrLayerOption( "" )
|
|
, mOgrWhereOption( "" )
|
|
{
|
|
if ( mTitle.isEmpty() )
|
|
{
|
|
mTitle = tr( "OGR/PostGIS/GDAL Input" );
|
|
}
|
|
adjustTitle();
|
|
|
|
// Check if this parameter is required
|
|
mRequired = gnode.toElement().attribute( "required" ) == "yes";
|
|
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
|
|
// Read "layeroption" is defined
|
|
QString opt = qdesc.attribute( "layeroption" );
|
|
if ( ! opt.isNull() )
|
|
{
|
|
|
|
QDomNode optNode = QgsGrassModule::nodeByKey( gdesc, opt );
|
|
|
|
if ( optNode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find layeroption %1" ).arg( opt ) );
|
|
}
|
|
else
|
|
{
|
|
mOgrLayerOption = opt;
|
|
}
|
|
}
|
|
|
|
// Read "whereoption" if defined
|
|
opt = qdesc.attribute( "whereoption" );
|
|
if ( !opt.isNull() )
|
|
{
|
|
QDomNode optNode = QgsGrassModule::nodeByKey( gdesc, opt );
|
|
if ( optNode.isNull() )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "Cannot find whereoption %1" ).arg( opt ) );
|
|
}
|
|
else
|
|
{
|
|
mOgrWhereOption = opt;
|
|
}
|
|
}
|
|
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
mLayerComboBox = new QComboBox();
|
|
mLayerComboBox->setSizePolicy( QSizePolicy::Expanding,
|
|
QSizePolicy:: Preferred );
|
|
l->addWidget( mLayerComboBox );
|
|
|
|
// Of course, activated(int) is not enough, but there is no signal
|
|
// BEFORE the cobo is opened
|
|
// connect ( mLayerComboBox, SIGNAL( activated(int) ), this, SLOT(updateQgisLayers()) );
|
|
|
|
// Connect to canvas
|
|
QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
|
|
// It seems that addedLayer/removedLayer does not work
|
|
//connect ( canvas, SIGNAL(addedLayer(QgsMapLayer *)), this, SLOT(updateQgisLayers()) );
|
|
//connect ( canvas, SIGNAL(removedLayer(QString)), this, SLOT(updateQgisLayers()) );
|
|
connect( canvas, SIGNAL( layersChanged() ), this, SLOT( updateQgisLayers() ) );
|
|
|
|
// Fill in QGIS layers
|
|
updateQgisLayers();
|
|
}
|
|
|
|
void QgsGrassModuleGdalInput::updateQgisLayers()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString current = mLayerComboBox->currentText();
|
|
mLayerComboBox->clear();
|
|
mUri.clear();
|
|
mOgrLayers.clear();
|
|
|
|
// If not required, add an empty item to combobox and a padding item into
|
|
// layer containers.
|
|
if ( !mRequired )
|
|
{
|
|
mUri.push_back( QString() );
|
|
mOgrLayers.push_back( QString() );
|
|
mOgrWheres.push_back( QString() );
|
|
mLayerComboBox->addItem( tr( "Select a layer" ), QVariant() );
|
|
}
|
|
|
|
QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
|
|
int nlayers = canvas->layerCount();
|
|
for ( int i = 0; i < nlayers; i++ )
|
|
{
|
|
QgsMapLayer *layer = canvas->layer( i );
|
|
|
|
if ( mType == Ogr && layer->type() == QgsMapLayer::VectorLayer )
|
|
{
|
|
QgsVectorLayer *vector = qobject_cast<QgsVectorLayer *>( layer );
|
|
if ( !vector ||
|
|
( vector->providerType() != "ogr" && vector->providerType() != "postgres" )
|
|
)
|
|
continue;
|
|
|
|
QgsDataProvider *provider = vector->dataProvider();
|
|
|
|
QString uri;
|
|
QString ogrLayer;
|
|
QString ogrWhere;
|
|
if ( vector->providerType() == "postgres" )
|
|
{
|
|
// Construct OGR DSN
|
|
QgsDataSourceURI dsUri( provider->dataSourceUri() );
|
|
uri = "PG:" + dsUri.connectionInfo();
|
|
|
|
if ( dsUri.schema() != "" )
|
|
{
|
|
ogrLayer = dsUri.schema() + ".";
|
|
}
|
|
|
|
ogrLayer += dsUri.table();
|
|
ogrWhere = dsUri.sql();
|
|
}
|
|
else if ( vector->providerType() == "ogr" )
|
|
{
|
|
QStringList items = provider->dataSourceUri().split( "|" );
|
|
|
|
if ( items.size() > 1 )
|
|
{
|
|
uri = items[0];
|
|
|
|
ogrLayer = "";
|
|
ogrWhere = "";
|
|
|
|
for ( int i = 1; i < items.size(); i++ )
|
|
{
|
|
QStringList args = items[i].split( "=" );
|
|
|
|
if ( args.size() != 2 )
|
|
continue;
|
|
|
|
if ( args[0] == "layername" && args[0] == "layerid" )
|
|
{
|
|
ogrLayer = args[1];
|
|
}
|
|
else if ( args[0] == "subset" )
|
|
{
|
|
ogrWhere = args[1];
|
|
}
|
|
}
|
|
|
|
if ( uri.endsWith( ".shp", Qt::CaseInsensitive ) )
|
|
{
|
|
ogrLayer = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uri = items[0];
|
|
ogrLayer = "";
|
|
ogrWhere = "";
|
|
}
|
|
}
|
|
|
|
QgsDebugMsg( "uri = " + uri );
|
|
QgsDebugMsg( "ogrLayer = " + ogrLayer );
|
|
|
|
mLayerComboBox->addItem( layer->name() );
|
|
if ( layer->name() == current ) mLayerComboBox->setItemText( mLayerComboBox->currentIndex(), current );
|
|
|
|
mUri.push_back( uri );
|
|
mOgrLayers.push_back( ogrLayer );
|
|
mOgrWheres.push_back( ogrWhere );
|
|
}
|
|
else if ( mType == Gdal && layer->type() == QgsMapLayer::RasterLayer )
|
|
{
|
|
QString uri = layer->source();
|
|
mLayerComboBox->addItem( layer->name() );
|
|
if ( layer->name() == current ) mLayerComboBox->setItemText( mLayerComboBox->currentIndex(), current );
|
|
mUri.push_back( uri );
|
|
mOgrLayers.push_back( "" );
|
|
mOgrWheres.push_back( "" );
|
|
}
|
|
}
|
|
}
|
|
|
|
QStringList QgsGrassModuleGdalInput::options()
|
|
{
|
|
QStringList list;
|
|
|
|
int current = mLayerComboBox->currentIndex();
|
|
if ( current < 0 )
|
|
return list;
|
|
|
|
QString opt( mKey + "=" );
|
|
|
|
if ( current >= 0 && current < mUri.size() )
|
|
{
|
|
opt.append( mUri[current] );
|
|
}
|
|
list.push_back( opt );
|
|
|
|
if ( !mOgrLayerOption.isEmpty() && mOgrLayers[current].size() > 0 )
|
|
{
|
|
opt = mOgrLayerOption + "=";
|
|
// GDAL 1.4.0 supports schemas (r9998)
|
|
#if GDAL_VERSION_NUM >= 1400
|
|
opt += mOgrLayers[current];
|
|
#else
|
|
// Handle older versions of gdal gracefully
|
|
// OGR does not support schemas !!!
|
|
if ( current >= 0 && current < mUri.size() )
|
|
{
|
|
QStringList l = mOgrLayers[current].split( "." );
|
|
opt += l.at( 1 );
|
|
|
|
// Currently only PostGIS is using layer
|
|
// -> layer -> PostGIS -> warning
|
|
if ( mOgrLayers[current].length() > 0 )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ),
|
|
tr( "PostGIS driver in OGR does not support schemas!<br>"
|
|
"Only the table name will be used.<br>"
|
|
"It can result in wrong input if more tables of the same name<br>"
|
|
"are present in the database." ) );
|
|
}
|
|
}
|
|
#endif //GDAL_VERSION_NUM
|
|
list.push_back( opt );
|
|
}
|
|
|
|
if ( !mOgrWhereOption.isEmpty() && mOgrWheres[current].length() > 0 )
|
|
{
|
|
list.push_back( mOgrWhereOption + "=" + mOgrWheres[current] );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
QString QgsGrassModuleGdalInput::ready()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString error;
|
|
|
|
QgsDebugMsg( QString( "count = %1" ).arg( mLayerComboBox->count() ) );
|
|
if ( mLayerComboBox->count() == 0 )
|
|
{
|
|
error.append( tr( "%1: no input" ).arg( title() ) );
|
|
}
|
|
return error;
|
|
}
|
|
|
|
QgsGrassModuleGdalInput::~QgsGrassModuleGdalInput()
|
|
{
|
|
}
|
|
|
|
/***************** QgsGrassModuleField *********************/
|
|
|
|
QgsGrassModuleField::QgsGrassModuleField(
|
|
QgsGrassModule *module, QgsGrassModuleStandardOptions *options,
|
|
QString key, QDomElement &qdesc,
|
|
QDomElement &gdesc, QDomNode &gnode, QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent ),
|
|
mModuleStandardOptions( options ), mLayerInput( 0 )
|
|
{
|
|
if ( mTitle.isEmpty() )
|
|
{
|
|
mTitle = tr( "Attribute field" );
|
|
}
|
|
adjustTitle();
|
|
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
|
|
mType = qdesc.attribute( "type" );
|
|
|
|
mLayerKey = qdesc.attribute( "layer" );
|
|
if ( mLayerKey.isNull() || mLayerKey.length() == 0 )
|
|
{
|
|
QMessageBox::warning( 0, tr( "Warning" ), tr( "'layer' attribute in field tag with key= %1 is missing." ).arg( mKey ) );
|
|
}
|
|
else
|
|
{
|
|
QgsGrassModuleItem *item = mModuleStandardOptions->itemByKey( mLayerKey );
|
|
// TODO check type
|
|
if ( item )
|
|
{
|
|
mLayerInput = dynamic_cast<QgsGrassModuleInput *>( item );
|
|
connect( mLayerInput, SIGNAL( valueChanged() ), this, SLOT( updateFields() ) );
|
|
}
|
|
}
|
|
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
mFieldComboBox = new QComboBox( );
|
|
l->addWidget( mFieldComboBox );
|
|
|
|
// Fill in layer current fields
|
|
updateFields();
|
|
}
|
|
|
|
void QgsGrassModuleField::updateFields()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString current = mFieldComboBox->currentText();
|
|
mFieldComboBox->clear();
|
|
|
|
//QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
|
|
if ( mLayerInput == 0 ) return;
|
|
|
|
std::vector<QgsField> fields = mLayerInput->currentFields();
|
|
|
|
for ( unsigned int i = 0; i < fields.size(); i++ )
|
|
{
|
|
if ( mType.contains( fields[i].typeName() ) )
|
|
{
|
|
mFieldComboBox->addItem( fields[i].name() );
|
|
if ( fields[i].name() == current )
|
|
{
|
|
mFieldComboBox->setItemText( mFieldComboBox->currentIndex(), current );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QStringList QgsGrassModuleField::options()
|
|
{
|
|
QStringList list;
|
|
|
|
QString opt( mKey + "=" + mFieldComboBox->currentText() );
|
|
list.push_back( opt );
|
|
|
|
return list;
|
|
}
|
|
|
|
QgsGrassModuleField::~QgsGrassModuleField()
|
|
{
|
|
}
|
|
|
|
/***************** QgsGrassModuleSelection *********************/
|
|
|
|
QgsGrassModuleSelection::QgsGrassModuleSelection(
|
|
QgsGrassModule *module, QgsGrassModuleStandardOptions *options,
|
|
QString key, QDomElement &qdesc,
|
|
QDomElement &gdesc, QDomNode &gnode, QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent ),
|
|
mModuleStandardOptions( options ), mLayerInput( 0 ),
|
|
mVectorLayer( 0 )
|
|
{
|
|
if ( mTitle.isEmpty() )
|
|
{
|
|
mTitle = tr( "Selected categories" );
|
|
}
|
|
adjustTitle();
|
|
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
|
|
mLayerId = qdesc.attribute( "layerid" );
|
|
|
|
mType = qdesc.attribute( "type" );
|
|
|
|
QgsGrassModuleItem *item = mModuleStandardOptions->item( mLayerId );
|
|
// TODO check type
|
|
if ( item )
|
|
{
|
|
mLayerInput = dynamic_cast<QgsGrassModuleInput *>( item );
|
|
connect( mLayerInput, SIGNAL( valueChanged() ), this, SLOT( updateSelection() ) );
|
|
}
|
|
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
mLineEdit = new QLineEdit( this );
|
|
l->addWidget( mLineEdit );
|
|
|
|
// Fill in layer current fields
|
|
updateSelection();
|
|
}
|
|
|
|
void QgsGrassModuleSelection::updateSelection()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
mLineEdit->setText( "" );
|
|
//QgsMapCanvas *canvas = mModule->qgisIface()->mapCanvas();
|
|
if ( mLayerInput == 0 ) return;
|
|
|
|
QgsMapLayer *layer = mLayerInput->currentLayer();
|
|
if ( !layer ) return;
|
|
QgsVectorLayer *vector = qobject_cast<QgsVectorLayer *>( layer );
|
|
|
|
QgsGrassProvider *provider = ( QgsGrassProvider * ) vector->dataProvider();
|
|
QgsAttributeList allAttributes = provider->attributeIndexes();
|
|
const QgsFeatureIds& selected = vector->selectedFeaturesIds();
|
|
int keyField = provider->keyField();
|
|
|
|
if ( keyField < 0 ) return;
|
|
|
|
QString cats;
|
|
provider->select( allAttributes, QgsRectangle(), true );
|
|
QgsFeature feature;
|
|
|
|
int i = 0;
|
|
while ( provider->nextFeature( feature ) )
|
|
{
|
|
if ( !selected.contains( feature.id() ) )
|
|
continue;
|
|
|
|
QgsAttributeMap attr = feature.attributeMap();
|
|
if ( attr.size() > keyField )
|
|
{
|
|
if ( i > 0 ) cats.append( "," );
|
|
cats.append( attr[keyField].toString() );
|
|
i++;
|
|
}
|
|
}
|
|
if ( mVectorLayer != vector )
|
|
{
|
|
if ( mVectorLayer )
|
|
{
|
|
disconnect( mVectorLayer, SIGNAL( selectionChanged() ), this, SLOT( updateSelection() ) );
|
|
}
|
|
|
|
connect( vector, SIGNAL( selectionChanged() ), this, SLOT( updateSelection() ) );
|
|
mVectorLayer = vector;
|
|
}
|
|
|
|
mLineEdit->setText( cats );
|
|
}
|
|
|
|
QStringList QgsGrassModuleSelection::options()
|
|
{
|
|
QStringList list;
|
|
|
|
QString opt( mKey + "=" + mLineEdit->text() );
|
|
list.push_back( opt );
|
|
|
|
return list;
|
|
}
|
|
|
|
QgsGrassModuleSelection::~QgsGrassModuleSelection()
|
|
{
|
|
}
|
|
|
|
/***************** QgsGrassModuleFile *********************/
|
|
|
|
QgsGrassModuleFile::QgsGrassModuleFile(
|
|
QgsGrassModule *module,
|
|
QString key, QDomElement &qdesc,
|
|
QDomElement &gdesc, QDomNode &gnode, QWidget * parent )
|
|
: QgsGrassModuleGroupBoxItem( module, key, qdesc, gdesc, gnode, parent ),
|
|
mType( Old )
|
|
{
|
|
if ( mTitle.isEmpty() )
|
|
{
|
|
mTitle = tr( "File" );
|
|
}
|
|
adjustTitle();
|
|
|
|
QDomNode promptNode = gnode.namedItem( "gisprompt" );
|
|
QDomElement promptElem = promptNode.toElement();
|
|
QString element = promptElem.attribute( "element" );
|
|
|
|
if ( qdesc.attribute( "type" ).toLower() == "new" )
|
|
{
|
|
mType = New;
|
|
}
|
|
if ( qdesc.attribute( "type" ).toLower() == "multiple" )
|
|
{
|
|
mType = Multiple;
|
|
}
|
|
|
|
if ( qdesc.attribute( "type" ).toLower() == "directory" )
|
|
{
|
|
mType = Directory;
|
|
}
|
|
|
|
if ( !qdesc.attribute( "filters" ).isNull() )
|
|
{
|
|
mFilters = qdesc.attribute( "filters" ).split( ";;" );
|
|
|
|
if ( mFilters.size() > 0 )
|
|
{
|
|
QRegExp rx( ".*\\( *..([^ )]*).*" );
|
|
QString ext;
|
|
if ( rx.indexIn( mFilters.at( 0 ) ) == 0 )
|
|
{
|
|
mSuffix = rx.cap( 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
mFileOption = qdesc.attribute( "fileoption" );
|
|
|
|
QHBoxLayout *l = new QHBoxLayout( this );
|
|
mLineEdit = new QLineEdit();
|
|
mBrowseButton = new QPushButton( "..." );
|
|
l->addWidget( mLineEdit );
|
|
l->addWidget( mBrowseButton );
|
|
|
|
connect( mBrowseButton, SIGNAL( clicked() ),
|
|
this, SLOT( browse() ) );
|
|
}
|
|
|
|
QStringList QgsGrassModuleFile::options()
|
|
{
|
|
QStringList list;
|
|
QString path = mLineEdit->text().trimmed();
|
|
|
|
if ( mFileOption.isNull() )
|
|
{
|
|
QString opt( mKey + "=" + path );
|
|
list.push_back( opt );
|
|
}
|
|
else
|
|
{
|
|
QFileInfo fi( path );
|
|
|
|
QString opt( mKey + "=" + fi.path() );
|
|
list.push_back( opt );
|
|
|
|
opt = mFileOption + "=" + fi.baseName();
|
|
list.push_back( opt );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
void QgsGrassModuleFile::browse()
|
|
{
|
|
// TODO: unfortunately QFileDialog does not support 'new' directory
|
|
QFileDialog *fd = new QFileDialog( this, NULL, mLineEdit->text() );
|
|
|
|
static QDir currentDir = QDir::current();
|
|
fd->setDirectory( currentDir );
|
|
|
|
switch ( mType )
|
|
{
|
|
case New:
|
|
fd->setFileMode( QFileDialog::AnyFile );
|
|
fd->setAcceptMode( QFileDialog::AcceptSave );
|
|
break;
|
|
case Multiple:
|
|
fd->setFileMode( QFileDialog::ExistingFiles );
|
|
fd->setAcceptMode( QFileDialog::AcceptOpen );
|
|
break;
|
|
case Directory:
|
|
fd->setFileMode( QFileDialog::Directory );
|
|
fd->setAcceptMode( QFileDialog::AcceptOpen );
|
|
break;
|
|
default:
|
|
fd->setFileMode( QFileDialog::ExistingFile );
|
|
fd->setAcceptMode( QFileDialog::AcceptOpen );
|
|
}
|
|
|
|
if ( mFilters.size() > 0 )
|
|
{
|
|
fd->setFilters( mFilters );
|
|
}
|
|
fd->setDefaultSuffix( mSuffix );
|
|
|
|
if ( fd->exec() == QDialog::Accepted )
|
|
{
|
|
QString selectedFile = fd->selectedFiles().last();
|
|
QFileInfo fi = QFileInfo( selectedFile );
|
|
currentDir = fi.absoluteDir();
|
|
if ( mType == Multiple )
|
|
{
|
|
selectedFile = fd->selectedFiles().join( "," );
|
|
}
|
|
mLineEdit->setText( selectedFile );
|
|
}
|
|
}
|
|
|
|
QString QgsGrassModuleFile::ready()
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
|
|
QString error;
|
|
QString path = mLineEdit->text().trimmed();
|
|
|
|
|
|
if ( path.length() == 0 && mRequired )
|
|
{
|
|
error.append( tr( "%1: missing value" ).arg( title() ) );
|
|
return error;
|
|
}
|
|
|
|
QFileInfo fi( path );
|
|
if ( !fi.dir().exists() )
|
|
{
|
|
error.append( tr( "%1: directory does not exist" ).arg( title() ) );
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
QgsGrassModuleFile::~QgsGrassModuleFile()
|
|
{
|
|
}
|
|
|
|
/***************************** QgsGrassModuleCheckBox *********************************/
|
|
|
|
QgsGrassModuleCheckBox::QgsGrassModuleCheckBox( const QString & text, QWidget * parent )
|
|
: QCheckBox( text, parent ), mText( text )
|
|
{
|
|
QgsDebugMsg( "called." );
|
|
adjustText();
|
|
}
|
|
|
|
QgsGrassModuleCheckBox::~QgsGrassModuleCheckBox()
|
|
{
|
|
}
|
|
|
|
void QgsGrassModuleCheckBox::resizeEvent( QResizeEvent * event )
|
|
{
|
|
adjustText();
|
|
}
|
|
void QgsGrassModuleCheckBox::setText( const QString & text )
|
|
{
|
|
mText = text;
|
|
adjustText();
|
|
}
|
|
void QgsGrassModuleCheckBox::setToolTip( const QString & text )
|
|
{
|
|
mTip = text;
|
|
QWidget::setToolTip( text );
|
|
}
|
|
void QgsGrassModuleCheckBox::adjustText()
|
|
{
|
|
QString t = fontMetrics().elidedText( mText , Qt::ElideRight, width() - iconSize().width() - 20 );
|
|
QCheckBox::setText( t );
|
|
|
|
if ( mTip.isEmpty() )
|
|
{
|
|
QString tt;
|
|
if ( t != mText )
|
|
{
|
|
tt = mText;
|
|
}
|
|
QWidget::setToolTip( tt );
|
|
}
|
|
}
|