Quantum GIS API Documentation  master-693a1fe
src/core/qgsattributeaction.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                                qgsattributeaction.cpp
00003 
00004  A class that stores and controls the managment and execution of actions
00005  associated. Actions are defined to be external programs that are run
00006  with user-specified inputs that can depend on the value of layer
00007  attributes.
00008 
00009                              -------------------
00010     begin                : Oct 24 2004
00011     copyright            : (C) 2004 by Gavin Macaulay
00012     email                : gavin at macaulay dot co dot nz
00013 
00014  ***************************************************************************/
00015 
00016 /***************************************************************************
00017  *                                                                         *
00018  *   This program is free software; you can redistribute it and/or modify  *
00019  *   it under the terms of the GNU General Public License as published by  *
00020  *   the Free Software Foundation; either version 2 of the License, or     *
00021  *   (at your option) any later version.                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 #include "qgsattributeaction.h"
00026 #include "qgspythonrunner.h"
00027 #include "qgsrunprocess.h"
00028 #include "qgsvectorlayer.h"
00029 #include "qgsproject.h"
00030 #include <qgslogger.h>
00031 #include "qgsexpression.h"
00032 
00033 #include <QList>
00034 #include <QStringList>
00035 #include <QDomElement>
00036 #include <QSettings>
00037 #include <QDesktopServices>
00038 #include <QUrl>
00039 #include <QDir>
00040 #include <QFileInfo>
00041 
00042 
00043 void QgsAttributeAction::addAction( QgsAction::ActionType type, QString name, QString action, bool capture )
00044 {
00045   mActions << QgsAction( type, name, action, capture );
00046 }
00047 
00048 void QgsAttributeAction::removeAction( int index )
00049 {
00050   if ( index >= 0 && index < mActions.size() )
00051   {
00052     mActions.removeAt( index );
00053   }
00054 }
00055 
00056 void QgsAttributeAction::doAction( int index, QgsFeature &feat, int defaultValueIndex )
00057 {
00058   QMap<QString, QVariant> substitutionMap;
00059   if ( defaultValueIndex >= 0 )
00060   {
00061     QVariant defaultValue = feat.attribute( defaultValueIndex );
00062     if ( defaultValue.isValid() )
00063       substitutionMap.insert( "$currfield", defaultValue );
00064   }
00065 
00066   doAction( index, feat, &substitutionMap );
00067 }
00068 
00069 void QgsAttributeAction::doAction( int index, QgsFeature &feat,
00070                                    const QMap<QString, QVariant> *substitutionMap )
00071 {
00072   if ( index < 0 || index >= size() )
00073     return;
00074 
00075   const QgsAction &action = at( index );
00076   if ( !action.runable() )
00077     return;
00078 
00079   // search for expressions while expanding actions
00080   QString expandedAction = QgsExpression::replaceExpressionText( action.action(), feat, mLayer , substitutionMap );
00081   if ( expandedAction.isEmpty() )
00082     return;
00083 
00084   QgsAction newAction( action.type(), action.name(), expandedAction, action.capture() );
00085   runAction( newAction );
00086 }
00087 
00088 void QgsAttributeAction::runAction( const QgsAction &action, void ( *executePython )( const QString & ) )
00089 {
00090   if ( action.type() == QgsAction::OpenUrl )
00091   {
00092     QFileInfo finfo( action.action() );
00093     if ( finfo.exists() && finfo.isFile() )
00094       QDesktopServices::openUrl( QUrl::fromLocalFile( action.action() ) );
00095     else
00096       QDesktopServices::openUrl( QUrl( action.action(), QUrl::TolerantMode ) );
00097   }
00098   else if ( action.type() == QgsAction::GenericPython )
00099   {
00100     if ( executePython )
00101     {
00102       // deprecated
00103       executePython( action.action() );
00104     }
00105     else if ( smPythonExecute )
00106     {
00107       // deprecated
00108       smPythonExecute( action.action() );
00109     }
00110     else
00111     {
00112       // TODO: capture output from QgsPythonRunner (like QgsRunProcess does)
00113       QgsPythonRunner::run( action.action() );
00114     }
00115   }
00116   else
00117   {
00118     // The QgsRunProcess instance created by this static function
00119     // deletes itself when no longer needed.
00120     QgsRunProcess::create( action.action(), action.capture() );
00121   }
00122 }
00123 
00124 QString QgsAttributeAction::expandAction( QString action, const QgsAttributeMap &attributes,
00125     uint clickedOnValue )
00126 {
00127   // This function currently replaces all %% characters in the action
00128   // with the value from values[clickedOnValue].second, and then
00129   // searches for all strings that go %attribute_name, where
00130   // attribute_name is found in values[x].first, and replaces any that
00131   // it finds by values[s].second.
00132 
00133   // Additional substitutions could include symbols for $CWD, $HOME,
00134   // etc (and their OSX and Windows equivalents)
00135 
00136   // This function will potentially fall apart if any of the
00137   // substitutions produce text that could match another
00138   // substitution. May be better to adopt a two pass approach - identify
00139   // all matches and their substitutions and then do a second pass
00140   // for the actual substitutions.
00141 
00142   QString expanded_action;
00143   if ( attributes.contains( clickedOnValue ) )
00144     expanded_action = action.replace( "%%", attributes[clickedOnValue].toString() );
00145   else
00146     expanded_action = action;
00147 
00148   const QgsFields &fields = mLayer->pendingFields();
00149 
00150   for ( int i = 0; i < 4; i++ )
00151   {
00152     for ( QgsAttributeMap::const_iterator it = attributes.begin(); it != attributes.end(); it++ )
00153     {
00154       int attrIdx = it.key();
00155       if ( attrIdx < 0 || attrIdx >= fields.count() )
00156         continue;
00157 
00158       QString to_replace;
00159       switch ( i )
00160       {
00161         case 0: to_replace = "[%" + fields[attrIdx].name() + "]"; break;
00162         case 1: to_replace = "[%" + mLayer->attributeDisplayName( attrIdx ) + "]"; break;
00163         case 2: to_replace = "%" + fields[attrIdx].name(); break;
00164         case 3: to_replace = "%" + mLayer->attributeDisplayName( attrIdx ); break;
00165       }
00166 
00167       expanded_action = expanded_action.replace( to_replace, it.value().toString() );
00168     }
00169   }
00170 
00171   return expanded_action;
00172 }
00173 
00174 QString QgsAttributeAction::expandAction( QString action, QgsFeature &feat, const QMap<QString, QVariant> *substitutionMap )
00175 {
00176   // This function currently replaces each expression between [% and %]
00177   // in the action with the result of its evaluation on the feature
00178   // passed as argument.
00179 
00180   // Additional substitutions can be passed through the substitutionMap
00181   // parameter
00182 
00183   QString expr_action;
00184 
00185   int index = 0;
00186   while ( index < action.size() )
00187   {
00188     QRegExp rx = QRegExp( "\\[%([^\\]]+)%\\]" );
00189 
00190     int pos = rx.indexIn( action, index );
00191     if ( pos < 0 )
00192       break;
00193 
00194     int start = index;
00195     index = pos + rx.matchedLength();
00196 
00197     QString to_replace = rx.cap( 1 ).trimmed();
00198     QgsDebugMsg( "Found expression: " + to_replace );
00199 
00200     if ( substitutionMap && substitutionMap->contains( to_replace ) )
00201     {
00202       expr_action += action.mid( start, pos - start ) + substitutionMap->value( to_replace ).toString();
00203       continue;
00204     }
00205 
00206     QgsExpression exp( to_replace );
00207     if ( exp.hasParserError() )
00208     {
00209       QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
00210       expr_action += action.mid( start, index - start );
00211       continue;
00212     }
00213 
00214     QVariant result = exp.evaluate( &feat, mLayer->pendingFields() );
00215     if ( exp.hasEvalError() )
00216     {
00217       QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
00218       expr_action += action.mid( start, index - start );
00219       continue;
00220     }
00221 
00222     QgsDebugMsg( "Expression result is: " + result.toString() );
00223     expr_action += action.mid( start, pos - start ) + result.toString();
00224   }
00225 
00226   expr_action += action.mid( index );
00227   return expr_action;
00228 }
00229 
00230 
00231 bool QgsAttributeAction::writeXML( QDomNode& layer_node, QDomDocument& doc ) const
00232 {
00233   QDomElement aActions = doc.createElement( "attributeactions" );
00234 
00235   for ( int i = 0; i < mActions.size(); i++ )
00236   {
00237     QDomElement actionSetting = doc.createElement( "actionsetting" );
00238     actionSetting.setAttribute( "type", mActions[i].type() );
00239     actionSetting.setAttribute( "name", mActions[i].name() );
00240     actionSetting.setAttribute( "action", mActions[i].action() );
00241     actionSetting.setAttribute( "capture", mActions[i].capture() );
00242     aActions.appendChild( actionSetting );
00243   }
00244   layer_node.appendChild( aActions );
00245 
00246   return true;
00247 }
00248 
00249 bool QgsAttributeAction::readXML( const QDomNode& layer_node )
00250 {
00251   mActions.clear();
00252 
00253   QDomNode aaNode = layer_node.namedItem( "attributeactions" );
00254 
00255   if ( !aaNode.isNull() )
00256   {
00257     QDomNodeList actionsettings = aaNode.childNodes();
00258     for ( unsigned int i = 0; i < actionsettings.length(); ++i )
00259     {
00260       QDomElement setting = actionsettings.item( i ).toElement();
00261       addAction(( QgsAction::ActionType ) setting.attributeNode( "type" ).value().toInt(),
00262                 setting.attributeNode( "name" ).value(),
00263                 setting.attributeNode( "action" ).value(),
00264                 setting.attributeNode( "capture" ).value().toInt() != 0 );
00265     }
00266   }
00267   return true;
00268 }
00269 
00270 void ( *QgsAttributeAction::smPythonExecute )( const QString & ) = 0;
00271 
00272 void QgsAttributeAction::setPythonExecute( void ( *runPython )( const QString & ) )
00273 {
00274   smPythonExecute = runPython;
00275 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines