1
/***************************************************************************
4
A class that stores and controls the managment and execution of actions
5
associated. Actions are defined to be external programs that are run
6
with user-specified inputs that can depend on the value of layer
11
copyright : (C) 2004 by Gavin Macaulay
12
email : gavin at macaulay dot co dot nz
14
***************************************************************************/
16
/***************************************************************************
18
* This program is free software; you can redistribute it and/or modify *
19
* it under the terms of the GNU General Public License as published by *
20
* the Free Software Foundation; either version 2 of the License, or *
21
* (at your option) any later version. *
23
***************************************************************************/
24
/* $Id: qgsattributeaction.cpp,v 1.7 2005/01/19 23:59:10 g_j_m Exp $ */
29
#include <qstringlist.h>
32
#include "qgsattributeaction.h"
33
#include "qgsrunprocess.h"
35
static const char * const ident_ = "$Id: qgsattributeaction.cpp,v 1.7 2005/01/19 23:59:10 g_j_m Exp $";
37
void QgsAttributeAction::addAction(QString name, QString action,
40
mActions.push_back(QgsAction(name, action, capture));
43
void QgsAttributeAction::doAction(unsigned int index, const std::vector<std::pair<QString, QString> >& values,
44
int defaultValueIndex)
46
aIter action = retrieveAction(index);
48
// A couple of extra options for running the action may be
49
// useful. For example,
50
// - run the action inside a terminal (on unix)
51
// - capture the stdout from the process and display in a dialog
54
// The capture stdout one is partially implemented. It just needs
55
// the UI and the code in this function to select on the
56
// action.capture() return value.
60
// The action will be divided into separate arguments that are
61
// passed to a QProcess instance. Spaces are used to delimit
62
// arguments, except for spaces inside pairs of ". A \" will be
63
// replaced by a ". The replacement of the %field_name is done
64
// after the parsing into arguments.
65
bool in_quote = false;
68
QString cmd = action->action();
69
for (int i = 0; i < cmd.length(); ++i)
72
if (i < cmd.length()-1 && cmd[i] == '\\' && cmd[i+1] == '\"')
77
// Found a delimiter, create a new argument
78
else if (cmd[i].isSpace() && !in_quote && current_arg.length() > 0)
80
QString strippedCmd = current_arg.stripWhiteSpace();
81
if (strippedCmd.length() > 0)
82
args << expandAction(strippedCmd, values, defaultValueIndex);
85
// Starting a new quote
86
else if (cmd[i] == '\"' && !in_quote)
89
else if (cmd[i] == '\"' && in_quote)
92
current_arg += cmd[i];
95
// Pick up the last argument if it has something of interest
96
if (!current_arg.stripWhiteSpace().isEmpty())
97
args << expandAction(current_arg.stripWhiteSpace(), values, defaultValueIndex);
99
// The QgsRunProcess instance created by this static function
100
// deletes itself when no longer needed.
101
QgsRunProcess::create(args, action->capture());
105
QgsAttributeAction::aIter QgsAttributeAction::retrieveAction(unsigned int index) const
107
// This function returns an iterator so that it's easy to deal with
108
// an invalid index being given.
109
aIter a_iter = end();
111
if (index >= 0 && index < mActions.size())
113
a_iter = mActions.begin();
114
for (int i = 0; i < index; ++i, ++a_iter)
120
QString QgsAttributeAction::expandAction(QString action, const std::vector<std::pair<QString, QString> >& values,
123
// This function currently replaces all %% characters in the action
124
// with the value from values[clickedOnValue].second, and then
125
// searches for all strings that go %attribite_name, where
126
// attribute_name is found in values[x].first, and replaces any that
127
// it finds by values[s].second.
129
// Additional substitutions could include symbols for $CWD, $HOME,
130
// etc (and their OSX and Windows equivalents)
132
// This function will potentially fall apart if any of the
133
// substitutions produce text that could match another
134
// substitution. May be better to adopt a two pass approach - identify
135
// all matches and their substitutions and then do a second pass
136
// for the actual substitutions.
138
QString expanded_action;
139
if (clickedOnValue >= 0 && clickedOnValue < values.size())
140
expanded_action = action.replace("%%", values[clickedOnValue].second);
142
expanded_action = action;
144
for (int i = 0; i < values.size(); ++i)
146
QString to_replace = "%" + values[i].first;
147
expanded_action = expanded_action.replace(to_replace, values[i].second);
150
return expanded_action;
153
bool QgsAttributeAction::writeXML(QDomNode& layer_node, QDomDocument& doc) const
155
QDomElement aActions = doc.createElement("attributeactions");
157
aIter a_iter = begin();
159
for (; a_iter != end(); ++a_iter)
161
QDomElement actionSetting = doc.createElement("actionsetting");
162
actionSetting.setAttribute("name", a_iter->name());
163
actionSetting.setAttribute("action", a_iter->action());
164
actionSetting.setAttribute("capture", a_iter->capture());
165
aActions.appendChild(actionSetting);
167
layer_node.appendChild(aActions);
172
bool QgsAttributeAction::readXML(QDomNode& layer_node)
174
QDomNode aaNode = layer_node.namedItem("attributeactions");
176
if (!aaNode.isNull())
178
QDomNodeList actionsettings = aaNode.childNodes();
179
for (int i = 0; i < actionsettings.length(); ++i)
181
QDomElement setting = actionsettings.item(i).toElement();
182
int capture = setting.attributeNode("capture").value().toInt();
183
addAction(setting.attributeNode("name").value(),
184
setting.attributeNode("action").value(),
185
capture == 0 ? false : true);