5,786 changes: 3,077 additions & 2,709 deletions i18n/qgis_cs_CZ.ts

Large diffs are not rendered by default.

2,314 changes: 924 additions & 1,390 deletions i18n/qgis_de.ts

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions ms-windows/osgeo4w/browser.bat.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
@echo off

SET OSGEO4W_ROOT=@osgeo4w@
call "%OSGEO4W_ROOT%"\bin\o4w_env.bat
call "~dp0\o4w_env.bat
call "%OSGEO4W_ROOT%"\apps\grass\grass-@grassversion@\etc\env.bat
@echo off
path %PATH%;%OSGEO4W_ROOT%\apps\@package@\bin;%OSGEO4W_ROOT%\apps\grass\grass-@grassversion@\lib
Expand Down
1 change: 0 additions & 1 deletion ms-windows/osgeo4w/package.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,3 @@ if exist %PACKAGENAME%-oracle-provider-%VERSION%-%PACKAGE%.tar.bz2 del %PACKAGEN

:end
echo FINISHED: %DATE% %TIME% >>%LOG% 2>&1

4 changes: 1 addition & 3 deletions ms-windows/osgeo4w/qgis.bat.tmpl
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
@echo off

SET OSGEO4W_ROOT=@osgeo4w@
call "%OSGEO4W_ROOT%"\bin\o4w_env.bat
call "%~dp0\o4w_env.bat"
call "%OSGEO4W_ROOT%"\apps\grass\grass-@grassversion@\etc\env.bat
@echo off
path %PATH%;%OSGEO4W_ROOT%\apps\@package@\bin;%OSGEO4W_ROOT%\apps\grass\grass-@grassversion@\lib
Expand Down
11 changes: 8 additions & 3 deletions python/console/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def __init__(self, parent=None):
#self.splitterObj.addWidget(self.widgetEditor)

# Hide side editor on start up
self.widgetEditor.hide()
self.splitterObj.hide()
self.listClassMethod.hide()

sizes = self.splitter.sizes()
Expand Down Expand Up @@ -474,7 +474,12 @@ def __init__(self, parent=None):

def onClickGoToLine(self, item, column):
linenr = int(item.text(1))
objName = item.text(0)
itemName = str(item.text(0))
charPos = itemName.find(' ')
if charPos != -1:
objName = itemName[0:charPos]
else:
objName = itemName
self.tabEditorWidget.currentWidget().newEditor.goToLine(objName, linenr)

def sextante(self):
Expand All @@ -487,7 +492,7 @@ def qtGui(self):
self.shell.commandConsole('qtGui')

def toggleEditor(self, checked):
self.widgetEditor.show() if checked else self.widgetEditor.hide()
self.splitterObj.show() if checked else self.splitterObj.hide()
self.tabEditorWidget.enableToolBarEditor(checked)

def toggleObjectListWidget(self, checked):
Expand Down
51 changes: 35 additions & 16 deletions python/console/console_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ def __init__(self, parent, parentConsole, filename, *args):
self.newEditor.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.newEditor.modificationChanged.connect(self.modified)
if filename:
self.newEditor.setText(open(unicode(filename), "rt").read())
self.newEditor.setText(open(unicode(filename), "r").read())
self.newEditor.setModified(False)
self.path = filename

Expand Down Expand Up @@ -606,7 +606,10 @@ def __init__(self, parent):
else:
self.newTabEditor(filename=None)

self.setDocumentMode(True)
## Fixes #7653
if sys.platform != 'darwin':
self.setDocumentMode(True)

self.setMovable(True)
#self.setTabsClosable(True)
self.setTabPosition(QTabWidget.South)
Expand Down Expand Up @@ -723,12 +726,18 @@ def closeCurrentWidget(self):

def restoreTabs(self):
for script in self.restoreTabList:
pathFile = unicode(script.toString())
if os.path.exists(pathFile):
tabName = pathFile.split('/')[-1]
self.newTabEditor(tabName, pathFile)
else:
self.newTabEditor(filename=None)
if script != '':
pathFile = unicode(script.toString())
if os.path.exists(pathFile):
tabName = pathFile.split('/')[-1]
self.newTabEditor(tabName, pathFile)
else:
print '## Error: '
s = 'Unable to restore the file: \n%s\n' % pathFile
sys.stderr.write(s)
self.parent.updateTabListScript(pathFile)
if self.count() < 1:
self.newTabEditor(filename=None)
self.topFrame.close()
self.enableToolBarEditor(True)

Expand Down Expand Up @@ -758,16 +767,18 @@ def listObject(self, tab):
if tabWidget.path:
pathFile, file = os.path.split(unicode(tabWidget.path))
module, ext = os.path.splitext(file)
found = False
if pathFile not in sys.path:
sys.path.append(pathFile)
found = True
try:
reload(pyclbr)
dictObject = {}
superClassName = []
readModule = pyclbr.readmodule(module)
readModuleFunction = pyclbr.readmodule_ex(module)
for name, class_data in sorted(readModule.items(), key=lambda x:x[1].lineno):
if class_data.file == tabWidget.path:
if os.path.normpath(str(class_data.file)) == os.path.normpath(str(tabWidget.path)):
for superClass in class_data.super:
if superClass == 'object':
continue
Expand All @@ -784,31 +795,39 @@ def listObject(self, tab):
classItem.setText(0, name)
classItem.setToolTip(0, name)
classItem.setText(1, str(class_data.lineno))
classItem.setIcon(0, QgsApplication.getThemeIcon("console/iconClassTreeWidgetConsole.png"))
iconClass = QgsApplication.getThemeIcon("console/iconClassTreeWidgetConsole.png")
classItem.setIcon(0, iconClass)
dictObject[name] = class_data.lineno
for meth, lineno in sorted(class_data.methods.items(), key=itemgetter(1)):
methodItem = QTreeWidgetItem()
methodItem.setText(0, meth)
methodItem.setText(0, meth + ' ')
methodItem.setText(1, str(lineno))
methodItem.setToolTip(0, meth)
methodItem.setIcon(0, QgsApplication.getThemeIcon("console/iconMethodTreeWidgetConsole.png"))
iconMeth = QgsApplication.getThemeIcon("console/iconMethodTreeWidgetConsole.png")
methodItem.setIcon(0, iconMeth)
classItem.addChild(methodItem)
dictObject[meth] = lineno
# if found:
# sys.path.remove(os.path.split(unicode(str(class_data.file)))[0])
self.parent.listClassMethod.addTopLevelItem(classItem)
for func_name, data in sorted(readModuleFunction.items(), key=lambda x:x[1].lineno):
if isinstance(data, pyclbr.Function) and data.file == tabWidget.path:
if isinstance(data, pyclbr.Function) and \
os.path.normpath(str(data.file)) == os.path.normpath(str(tabWidget.path)):
funcItem = QTreeWidgetItem()
funcItem.setText(0, func_name)
funcItem.setText(0, func_name + ' ')
funcItem.setText(1, str(data.lineno))
funcItem.setToolTip(0, func_name)
funcItem.setIcon(0, QgsApplication.getThemeIcon("console/iconFunctionTreeWidgetConsole.png"))
iconFunc = QgsApplication.getThemeIcon("console/iconFunctionTreeWidgetConsole.png")
funcItem.setIcon(0, iconFunc)
dictObject[func_name] = data.lineno
self.parent.listClassMethod.addTopLevelItem(funcItem)
if found:
sys.path.remove(pathFile)
except:
s = traceback.format_exc()
print '## Error: '
sys.stderr.write(s)

def changeFont(self):
countTab = self.count()
for i in range(countTab):
Expand Down
9 changes: 6 additions & 3 deletions python/console/console_sci.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,16 +416,16 @@ def dropEvent(self, e):
stringDrag = e.mimeData().text()
self.insertFromDropPaste(stringDrag)
self.setFocus()
e.setDropAction(Qt.MoveAction)
e.setDropAction(Qt.CopyAction)
e.accept()
else:
QsciScintillaCompat.dropEvent(self, e)

def insertFromDropPaste(self, textDP):
pasteList = textDP.split("\n")
pasteList = str(textDP).splitlines()
for line in pasteList[:-1]:
line.replace(">>> ", "").replace("... ", "")
self.insert(line)
self.insert(unicode(line))
self.move_cursor_to_end()
self.runCommand(unicode(self.currentCommand()))
if pasteList[-1] != "":
Expand Down Expand Up @@ -493,6 +493,9 @@ def runCommand(self, cmd):
more = self.runsource(src, "<input>")
if not more:
self.buffer = []
## prevents to commands with more lines to break the console
## in the case they have a eol different from '\n'
self.setText('')
self.move_cursor_to_end()
self.displayPrompt(more)

Expand Down
1 change: 1 addition & 0 deletions python/core/core.sip
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
%Include gps/qgsnmeaconnection.sip
%Include gps/qgsqtlocationconnection.sip

%Include raster/qgsraster.sip
%Include raster/qgscliptominmaxenhancement.sip
%Include raster/qgscolorrampshader.sip
%Include raster/qgscontrastenhancement.sip
Expand Down
2 changes: 1 addition & 1 deletion python/core/raster/qgscliptominmaxenhancement.sip
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class QgsClipToMinMaxEnhancement : QgsContrastEnhancementFunction
%End

public:
QgsClipToMinMaxEnhancement( QgsContrastEnhancement::QgsRasterDataType, double, double );
QgsClipToMinMaxEnhancement( QGis::DataType, double, double );

int enhance( double );

Expand Down
30 changes: 3 additions & 27 deletions python/core/raster/qgscontrastenhancement.sip
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,7 @@ class QgsContrastEnhancement
UserDefinedEnhancement
};

/** These are exactly the same as GDAL pixel data types
** This was added so that the python bindings could be built,
** which initially was a problem because GDALDataType was passed
** around as an argument to numerous method, including the constructor.
**
** It seems like there should be a better way to do this...
*/
enum QgsRasterDataType
{
QGS_Unknown = 0,
/*! Eight bit unsigned integer */ QGS_Byte = 1,
/*! Sixteen bit unsigned integer */ QGS_UInt16 = 2,
/*! Sixteen bit signed integer */ QGS_Int16 = 3,
/*! Thirty two bit unsigned integer */ QGS_UInt32 = 4,
/*! Thirty two bit signed integer */ QGS_Int32 = 5,
/*! Thirty two bit floating point */ QGS_Float32 = 6,
/*! Sixty four bit floating point */ QGS_Float64 = 7,
/*! Complex Int16 */ QGS_CInt16 = 8,
/*! Complex Int32 */ QGS_CInt32 = 9,
/*! Complex Float32 */ QGS_CFloat32 = 10,
/*! Complex Float64 */ QGS_CFloat64 = 11,
QGS_TypeCount = 12 /* maximum type # + 1 */
};

QgsContrastEnhancement( QgsContrastEnhancement::QgsRasterDataType theDatatype = QGS_Byte );
QgsContrastEnhancement( QGis::DataType theDatatype = QGis::Byte );
~QgsContrastEnhancement();

/*
Expand All @@ -50,10 +26,10 @@ class QgsContrastEnhancement
*
*/
/** \brief Helper function that returns the maximum possible value for a GDAL data type */
static double maximumValuePossible( QgsRasterDataType );
static double maximumValuePossible( QGis::DataType );

/** \brief Helper function that returns the minimum possible value for a GDAL data type */
static double minimumValuePossible( QgsRasterDataType );
static double minimumValuePossible( QGis::DataType );

/*
*
Expand Down
2 changes: 1 addition & 1 deletion python/core/raster/qgscontrastenhancementfunction.sip
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class QgsContrastEnhancementFunction
%End

public:
QgsContrastEnhancementFunction( QgsContrastEnhancement::QgsRasterDataType, double, double );
QgsContrastEnhancementFunction( QGis::DataType, double, double );
virtual ~QgsContrastEnhancementFunction();

/** \brief Mustator for the maximum value */
Expand Down
2 changes: 1 addition & 1 deletion python/core/raster/qgslinearminmaxenhancement.sip
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class QgsLinearMinMaxEnhancement : QgsContrastEnhancementFunction
%End

public:
QgsLinearMinMaxEnhancement( QgsContrastEnhancement::QgsRasterDataType, double, double );
QgsLinearMinMaxEnhancement( QGis::DataType, double, double );

int enhance( double );

Expand Down
2 changes: 1 addition & 1 deletion python/core/raster/qgslinearminmaxenhancementwithclip.sip
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class QgsLinearMinMaxEnhancementWithClip : QgsContrastEnhancementFunction
%End

public:
QgsLinearMinMaxEnhancementWithClip( QgsContrastEnhancement::QgsRasterDataType, double, double );
QgsLinearMinMaxEnhancementWithClip( QGis::DataType, double, double );

int enhance( double );

Expand Down
77 changes: 77 additions & 0 deletions python/core/raster/qgsraster.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*! \class QgsRaster
*/

class QgsRaster
{
%TypeHeaderCode
#include <qgsraster.h>
%End

public:
// This is modified copy of GDALColorInterp
enum ColorInterpretation
{
UndefinedColorInterpretation = 0,
/*! Greyscale */ GrayIndex = 1,
/*! Paletted (see associated color table) */ PaletteIndex = 2, // indexed color table
/*! Red band of RGBA image */ RedBand = 3,
/*! Green band of RGBA image */ GreenBand = 4,
/*! Blue band of RGBA image */ BlueBand = 5,
/*! Alpha (0=transparent, 255=opaque) */ AlphaBand = 6,
/*! Hue band of HLS image */ HueBand = 7,
/*! Saturation band of HLS image */ SaturationBand = 8,
/*! Lightness band of HLS image */ LightnessBand = 9,
/*! Cyan band of CMYK image */ CyanBand = 10,
/*! Magenta band of CMYK image */ MagentaBand = 11,
/*! Yellow band of CMYK image */ YellowBand = 12,
/*! Black band of CMLY image */ BlackBand = 13,
/*! Y Luminance */ YCbCr_YBand = 14,
/*! Cb Chroma */ YCbCr_CbBand = 15,
/*! Cr Chroma */ YCbCr_CrBand = 16,
/*! Continuous palette, QGIS addition, GRASS */ ContinuousPalette = 17
};
enum IdentifyFormat
{
IdentifyFormatUndefined = 0,
IdentifyFormatValue = 1, // numerical pixel value
IdentifyFormatText = 0x2, // WMS text
IdentifyFormatHtml = 0x4, // WMS HTML
IdentifyFormatFeature = 0x8 // WMS GML -> feature
};

// Progress types
enum RasterProgressType
{
ProgressHistogram = 0,
ProgressPyramids = 1,
ProgressStatistics = 2
};

enum RasterBuildPyramids
{
PyramidsFlagNo = 0,
PyramidsFlagYes = 1,
PyramidsCopyExisting = 2
};

enum RasterPyramidsFormat
{
PyramidsGTiff = 0,
PyramidsInternal = 1,
PyramidsErdas = 2
};

/** \brief Contrast enhancement limits */
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};

static QString contrastEnhancementLimitsAsString( QgsRaster::ContrastEnhancementLimits theLimits );
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( QString theLimits );

};

61 changes: 3 additions & 58 deletions python/core/raster/qgsrasterdataprovider.sip
Original file line number Diff line number Diff line change
Expand Up @@ -16,61 +16,6 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface

public:

// This is modified copy of GDALColorInterp
enum ColorInterpretation
{
UndefinedColorInterpretation = 0,
/*! Greyscale */ GrayIndex = 1,
/*! Paletted (see associated color table) */ PaletteIndex = 2, // indexed color table
/*! Red band of RGBA image */ RedBand = 3,
/*! Green band of RGBA image */ GreenBand = 4,
/*! Blue band of RGBA image */ BlueBand = 5,
/*! Alpha (0=transparent, 255=opaque) */ AlphaBand = 6,
/*! Hue band of HLS image */ HueBand = 7,
/*! Saturation band of HLS image */ SaturationBand = 8,
/*! Lightness band of HLS image */ LightnessBand = 9,
/*! Cyan band of CMYK image */ CyanBand = 10,
/*! Magenta band of CMYK image */ MagentaBand = 11,
/*! Yellow band of CMYK image */ YellowBand = 12,
/*! Black band of CMLY image */ BlackBand = 13,
/*! Y Luminance */ YCbCr_YBand = 14,
/*! Cb Chroma */ YCbCr_CbBand = 15,
/*! Cr Chroma */ YCbCr_CrBand = 16,
/*! Continuous palette, QGIS addition, GRASS */ ContinuousPalette = 17,
/*! Max current value */ ColorInterpretationMax = 17
};

enum IdentifyFormat
{
IdentifyFormatUndefined = 0,
IdentifyFormatValue = 1,
IdentifyFormatText = 2,
IdentifyFormatHtml = 4,
IdentifyFormatFeature = 8
};

// Progress types
enum RasterProgressType
{
ProgressHistogram = 0,
ProgressPyramids = 1,
ProgressStatistics = 2
};

enum RasterBuildPyramids
{
PyramidsFlagNo = 0,
PyramidsFlagYes = 1,
CopyExisting = 2
};

enum RasterPyramidsFormat
{
PyramidsGTiff = 0,
PyramidsInternal = 1,
PyramidsErdas = 2
};

QgsRasterDataProvider();

QgsRasterDataProvider( const QString & uri );
Expand Down Expand Up @@ -148,7 +93,7 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
/** \brief Create pyramid overviews */
virtual QString buildPyramids( const QList<QgsRasterPyramid> & thePyramidList,
const QString & theResamplingMethod = "NEAREST",
RasterPyramidsFormat theFormat = PyramidsGTiff,
QgsRaster::RasterPyramidsFormat theFormat = QgsRaster::PyramidsGTiff,
const QStringList & theConfigOptions = QStringList() );

/** \brief Accessor for ths raster layers pyramid list.
Expand All @@ -169,7 +114,7 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface
*/
virtual QString metadata() = 0;

virtual QgsRasterIdentifyResult identify( const QgsPoint & thePoint, IdentifyFormat theFormat, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );
virtual QgsRasterIdentifyResult identify( const QgsPoint & thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );

//QMap<QString, QString> identify( const QgsPoint & thePoint, const QgsRectangle &theExtent = QgsRectangle(), int theWidth = 0, int theHeight = 0 );

Expand Down Expand Up @@ -252,7 +197,7 @@ class QgsRasterDataProvider : QgsDataProvider, QgsRasterInterface

/** Validates pyramid creation options for a specific dataset and destination format
* @note used by GDAL provider only */
virtual QString validatePyramidsConfigOptions( RasterPyramidsFormat pyramidsFormat,
virtual QString validatePyramidsConfigOptions( QgsRaster::RasterPyramidsFormat pyramidsFormat,
const QStringList & theConfigOptions, const QString & fileFormat );

signals:
Expand Down
8 changes: 4 additions & 4 deletions python/core/raster/qgsrasterfilewriter.sip
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ class QgsRasterFileWriter
void setMaxTileWidth( int w );
int maxTileWidth() const;

QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const;
void setBuildPyramidsFlag( QgsRasterDataProvider::RasterBuildPyramids f );
QgsRaster::RasterBuildPyramids buildPyramidsFlag() const;
void setBuildPyramidsFlag( QgsRaster::RasterBuildPyramids f );

QList< int > pyramidsList() const;
void setPyramidsList( const QList< int > & list );

QString pyramidsResampling() const;
void setPyramidsResampling( const QString & str );

QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const;
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat f );
QgsRaster::RasterPyramidsFormat pyramidsFormat() const;
void setPyramidsFormat( QgsRaster::RasterPyramidsFormat f );

void setMaxTileHeight( int h );
int maxTileHeight() const;
Expand Down
4 changes: 2 additions & 2 deletions python/core/raster/qgsrasteridentifyresult.sip
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ class QgsRasterIdentifyResult
public:
QgsRasterIdentifyResult();

QgsRasterIdentifyResult( QgsRasterDataProvider::IdentifyFormat theFormat, QMap<int, QVariant> theResults );
QgsRasterIdentifyResult( QgsRaster::IdentifyFormat theFormat, QMap<int, QVariant> theResults );

QgsRasterIdentifyResult( QgsError theError );

virtual ~QgsRasterIdentifyResult();

bool isValid() const;

QgsRasterDataProvider::IdentifyFormat format() const;
QgsRaster::IdentifyFormat format() const;

QMap<int, QVariant> results() const;

Expand Down
14 changes: 1 addition & 13 deletions python/core/raster/qgsrasterlayer.sip
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,6 @@ class QgsRasterLayer : QgsMapLayer
ColorLayer
};

/** \brief Contrast enhancement limits */
enum ContrastEnhancementLimits
{
ContrastEnhancementNone,
ContrastEnhancementMinMax,
ContrastEnhancementStdDev,
ContrastEnhancementCumulativeCut
};

//
// Static methods:
//
Expand Down Expand Up @@ -201,9 +192,6 @@ class QgsRasterLayer : QgsMapLayer
/** \brief Returns the number of raster units per each raster pixel. In a world file, this is normally the first row (without the sign) */
double rasterUnitsPerPixel();

static QString contrastEnhancementLimitsAsString( QgsRasterLayer::ContrastEnhancementLimits theLimits );
static ContrastEnhancementLimits contrastEnhancementLimitsFromString( QString theLimits );

/** \brief Mutator for contrast enhancement algorithm
* @param theAlgorithm Contrast enhancement algorithm
* @param theLimits Limits
Expand All @@ -213,7 +201,7 @@ class QgsRasterLayer : QgsMapLayer


void setContrastEnhancementAlgorithm( QgsContrastEnhancement::ContrastEnhancementAlgorithm theAlgorithm,
ContrastEnhancementLimits theLimits = ContrastEnhancementMinMax,
QgsRaster::ContrastEnhancementLimits theLimits = QgsRaster::ContrastEnhancementMinMax,
QgsRectangle theExtent = QgsRectangle(),
int theSampleSize = QgsRasterLayer::SAMPLE_SIZE,
bool theGenerateLookupTableFlag = true );
Expand Down
1 change: 1 addition & 0 deletions python/gui/gui.sip
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
%Include qgisinterface.sip
%Include qgsannotationitem.sip
%Include qgsattributeeditor.sip
%Include qgsattributedialog.sip
%Include qgsbusyindicatordialog.sip
%Include qgscollapsiblegroupbox.sip
%Include qgscolorbutton.sip
Expand Down
2 changes: 2 additions & 0 deletions python/gui/qgisinterface.sip
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ class QgisInterface : QObject
virtual bool openFeatureForm( QgsVectorLayer *l, QgsFeature &f, bool updateFeatureOnly = false ) = 0;

virtual QDialog* getFeatureForm( QgsVectorLayer *l, QgsFeature &f ) = 0;

virtual void preloadForm(QString uifile) = 0;
/** Return vector layers in edit mode
* @param modified whether to return only layers that have been modified
* @returns list of layers in legend order, or empty list
Expand Down
19 changes: 19 additions & 0 deletions python/gui/qgsattributedialog.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class QgsAttributeDialog : QObject
{
%TypeHeaderCode
#include <qgsattributedialog.h>
%End

public:
QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeature, bool featureOwner, QgsDistanceArea myDa, QWidget* parent = 0, bool showDialogButtons = true );
void saveGeometry();
void restoreGeometry();
QDialog *dialog();
QgsFeature* feature();

public slots:
void accept();
int exec();
void show();
void dialogDestroyed();
};
2 changes: 1 addition & 1 deletion python/gui/qgsrasterformatsaveoptionswidget.sip
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class QgsRasterFormatSaveOptionsWidget : QWidget
void setRasterFileName( const QString& file );
QStringList options() const;
void setType( QgsRasterFormatSaveOptionsWidget::Type type = Default );
void setPyramidsFormat( QgsRasterDataProvider::RasterPyramidsFormat format );
void setPyramidsFormat( QgsRaster::RasterPyramidsFormat format );

public slots:

Expand Down
4 changes: 2 additions & 2 deletions python/gui/qgsrasterlayersaveasdialog.sip
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ class QgsRasterLayerSaveAsDialog : QDialog
QList<QgsRasterNuller::NoData> noData() const;

QList< int > pyramidsList() const;
QgsRasterDataProvider::RasterBuildPyramids buildPyramidsFlag() const;
QgsRaster::RasterBuildPyramids buildPyramidsFlag() const;
QString pyramidsResamplingMethod() const;
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const;
QgsRaster::RasterPyramidsFormat pyramidsFormat() const;
QStringList pyramidsConfigOptions() const;

void hideFormat();
Expand Down
2 changes: 1 addition & 1 deletion python/gui/qgsrasterpyramidsoptionswidget.sip
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class QgsRasterPyramidsOptionsWidget: QWidget
QStringList configOptions() const;
QgsRasterFormatSaveOptionsWidget* createOptionsWidget() /Factory/;
const QList<int> overviewList() const;
QgsRasterDataProvider::RasterPyramidsFormat pyramidsFormat() const;
QgsRaster::RasterPyramidsFormat pyramidsFormat() const;
QString resamplingMethod() const;
void setRasterLayer( QgsRasterLayer* rasterLayer );
void setRasterFileName( const QString& file );
Expand Down
3 changes: 1 addition & 2 deletions python/plugins/fTools/tools/doVectorSplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ def run(self):

self.emit(SIGNAL("rangeCalculated(PyQt_PyObject)"), len(unique))

fit = provider.getFeatures()

for i in unique:
check = QFile(baseName + "_" + unicode(i.toString().trimmed()) + ".shp")
Expand All @@ -182,7 +181,7 @@ def run(self):

writer = QgsVectorFileWriter(fName, self.encoding, fieldList, geom, sRs)

fit.rewind()
fit = provider.getFeatures()
while fit.nextFeature(inFeat):
atMap = inFeat.attributes()
if atMap[index] == i:
Expand Down
23 changes: 21 additions & 2 deletions python/plugins/sextante/SextantePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
* *
***************************************************************************
"""
from PyQt4 import QtGui
from sextante.commander.parser import parse
from sextante.commander.CommanderWindow import CommanderWindow

__author__ = 'Victor Olaya'
__date__ = 'August 2012'
Expand Down Expand Up @@ -50,6 +53,7 @@ def __init__(self, iface):
QGisLayers.setInterface(iface)
Sextante.initialize()
Sextante.setInterface(iface)
Sextante.setPlugin(self)

def initGui(self):
self.toolbox = SextanteToolbox(self.iface)
Expand Down Expand Up @@ -90,7 +94,14 @@ def initGui(self):
self.menu.addAction(self.resultsAction)

menuBar = self.iface.mainWindow().menuBar()
menuBar.insertMenu(menuBar.actions()[-1], self.menu)
menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(), self.menu)

self.commanderAction = QAction(QIcon(":/sextante/images/toolbox.png"),
QCoreApplication.translate("SEXTANTE", "&SEXTANTE commander"),
self.iface.mainWindow())
self.commanderAction.triggered.connect(self.openCommander)
self.menu.addAction(self.commanderAction)
self.iface.registerMainWindowAction(self.commanderAction, "Ctrl+Alt+M")

def unload(self):
self.toolbox.setVisible(False)
Expand All @@ -99,7 +110,15 @@ def unload(self):
folder = SextanteUtils.tempFolder()
if QDir(folder).exists():
shutil.rmtree(folder, True)


self.iface.unregisterMainWindowAction(self.commanderAction)

def openCommander(self):
dlg = CommanderWindow(self.iface.mainWindow(), self.iface.mapCanvas())
dlg.show()
dlg.exec_()


def openToolbox(self):
if self.toolbox.isVisible():
self.toolbox.hide()
Expand Down
225 changes: 225 additions & 0 deletions python/plugins/sextante/commander/CommanderWindow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
CommanderWindow.py
---------------------
Date : April 2013
Copyright : (C) 2012 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'April 2013'
__copyright__ = '(C) 2013, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sextante.core.Sextante import Sextante
from sextante.gui.MissingDependencyDialog import MissingDependencyDialog
from sextante.gui.ParametersDialog import ParametersDialog
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteUtils import SextanteUtils, mkdir
import types
import os
import imp

ITEMHEIGHT = 30
OFFSET = 20
HEIGHT = 60

class CommanderWindow(QtGui.QDialog):
def __init__(self, parent, canvas):
self.canvas = canvas
QtGui.QDialog.__init__(self, parent, Qt.FramelessWindowHint)
self.setModal(True)
self.commands = imp.load_source("commands", self.commandsFile())
self.initGui()

def commandsFolder(self):
folder = unicode(os.path.join(SextanteUtils.userFolder(), "commander"))
mkdir(folder)
return os.path.abspath(folder)

def commandsFile(self):
f = os.path.join(self.commandsFolder(), "commands.py")
if not os.path.exists(f):
out = open(f, "w")
out.write("from qgis.core import *\n")
out.write("import sextante\n\n")
out.write("def removeall():\n")
out.write("\tmapreg = QgsMapLayerRegistry.instance()\n")
out.write("\tmapreg.removeAllMapLayers()\n\n")
out.write("def load(*args):\n")
out.write("\tsextante.load(args[0])\n")
out.close()
return f


def initGui(self):
self.combo= ExtendedComboBox()
#add algorithm
for providerName in Sextante.algs.keys():
provider = Sextante.algs[providerName]
algs = provider.values()
for alg in algs:
self.combo.addItem("SEXTANTE algorithm: " + alg.name)
#add functions
for command in dir(self.commands):
if isinstance(self.commands.__dict__.get(command), types.FunctionType):
self.combo.addItem("Command: " + command);
#add menu entries
menuActions = []
actions = Sextante.getInterface().mainWindow().menuBar().actions()
for action in actions:
menuActions.extend(self.getActions(action))
for action in menuActions:
self.combo.addItem("Menu action: " + unicode(action.text()))

self.combo.setEditable(True)
self.combo.setEditText("")
self.label = QtGui.QLabel("Enter command:")
self.errorLabel = QtGui.QLabel("Enter command:")
self.vlayout = QtGui.QVBoxLayout()
self.vlayout.setSpacing(2)
self.vlayout.setMargin(0)
self.vlayout.addSpacerItem(QtGui.QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding));
self.hlayout = QtGui.QHBoxLayout()
self.hlayout.addWidget(self.label)
#self.hlayout.addWidget(self.errorLabel)
self.vlayout.addLayout(self.hlayout)
self.hlayout2 = QtGui.QHBoxLayout()
self.hlayout2.addWidget(self.combo)
self.vlayout.addLayout(self.hlayout2)
self.vlayout.addSpacerItem(QtGui.QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding));
self.setLayout(self.vlayout)
self.combo.lineEdit().returnPressed.connect(self.run)
self.combo.setMaximumSize(QtCore.QSize(self.canvas.rect().width() - 2 * OFFSET, ITEMHEIGHT))
self.combo.view().setStyleSheet("min-height: 150px")
self.combo.setFocus(Qt.OtherFocusReason)
self.label.setMaximumSize(self.combo.maximumSize())
self.label.setVisible(False)
self.adjustSize()
pt = self.canvas.rect().topLeft()
absolutePt = self.canvas.mapToGlobal(pt)
self.move(absolutePt)
self.resize(self.canvas.rect().width(), HEIGHT)
self.setStyleSheet("CommanderWindow { background-color: #e7f5fe; border: 1px solid #b9cfe4; }")


def getActions(self, action):
menuActions = []
menu = action.menu()
if menu is None:
menuActions.append(action)
return menuActions
else:
actions = menu.actions()
for subaction in actions:
if subaction.menu() is not None:
menuActions.extend(self.getActions(subaction))
elif not subaction.isSeparator():
menuActions.append(subaction)

return menuActions

def run(self):
s = unicode(self.combo.currentText())
if s.startswith("SEXTANTE algorithm: "):
algName = s[len("SEXTANTE algorithm: "):]
alg = Sextante.getAlgorithmFromFullName(algName)
if alg is not None:
self.close()
self.runAlgorithm(alg)
elif s.startswith("Command: "):
command = s[len("Command: "):]
try:
self.runCommand(command)
self.close()
except Exception, e:
self.label.setVisible(True)
self.label.setText("Error:" + unicode(e) )

elif s.startswith("Menu action: "):
actionName = s[len("Menu action: "):]
menuActions = []
actions = Sextante.getInterface().mainWindow().menuBar().actions()
for action in actions:
menuActions.extend(self.getActions(action))
for action in menuActions:
if action.text() == actionName:
self.close()
action.trigger()
return
else:
try:
self.runCommand(s)
self.close()
except Exception, e:
self.label.setVisible(True)
self.label.setText("Error:" + unicode(e) )

def runCommand(self, command):
tokens = command.split(" ")
if len(tokens) == 1:
method = self.commands.__dict__.get(command)
if method is not None:
method()
else:
raise Exception("Wrong command")
else:
method = self.commands.__dict__.get(tokens[0])
if method is not None:
method(*tokens[1:])
else:
raise Exception("Wrong command")



def runAlgorithm(self, alg):
alg = alg.getCopy()
message = alg.checkBeforeOpeningParametersDialog()
if message:
dlg = MissingDependencyDialog(message)
dlg.exec_()
return
dlg = alg.getCustomParametersDialog()
if not dlg:
dlg = ParametersDialog(alg)
canvas = QGisLayers.iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool()!=prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)


class ExtendedComboBox(QComboBox):
def __init__(self, parent=None):
super(ExtendedComboBox, self).__init__(parent)

self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.pFilterModel.setSourceModel(self.model())
self.completer = QCompleter(self.pFilterModel, self)
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.completer.popup().setStyleSheet("min-height: 150px")
self.completer.popup().setAlternatingRowColors(True)
self.setCompleter(self.completer)
self.lineEdit().textEdited[unicode].connect(self.pFilterModel.setFilterFixedString)
Empty file.
17 changes: 16 additions & 1 deletion python/plugins/sextante/core/Sextante.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
from sextante.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider
from sextante.modeler.ModelerOnlyAlgorithmProvider import ModelerOnlyAlgorithmProvider
from sextante.algs.QGISAlgorithmProvider import QGISAlgorithmProvider
from sextante.parameters.ParameterSelection import ParameterSelection
from sextante.grass.GrassAlgorithmProvider import GrassAlgorithmProvider
from sextante.lidar.LidarToolsAlgorithmProvider import LidarToolsAlgorithmProvider
from sextante.gdal.GdalOgrAlgorithmProvider import GdalOgrAlgorithmProvider
Expand Down Expand Up @@ -108,6 +107,14 @@ def getInterface():
@staticmethod
def setInterface(iface):
Sextante.iface = iface

@staticmethod
def setPlugin(iface):
Sextante.plugin = iface

@staticmethod
def getPlugin():
return Sextante.plugin

@staticmethod
def initialize():
Expand Down Expand Up @@ -232,6 +239,14 @@ def getAlgorithm(name):
if name in provider:
return provider[name]
return None

@staticmethod
def getAlgorithmFromFullName(name):
for provider in Sextante.algs.values():
for alg in provider.values():
if alg.name == name:
return alg
return None

@staticmethod
def getObject(uri):
Expand Down
13 changes: 13 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.angle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
r.stream.angle
r.stream.angle - Route azimuth, direction and relation to streams of higher order.
Raster (r.*)
ParameterRaster|stream|Input map: stream mask|False
ParameterRaster|dirs|Input map: direction map|False
ParameterRaster|elev|Input map: elevation map|True
ParameterSelection|order|Stream ordering method|none;hack;horton;strahler|0
ParameterNumber|length|Search length to calculat direction|1|None|15
ParameterNumber|skip|Skip segments shorter than|1|None|5
ParameterNumber|treshold|Max angle (degrees) beetwen stream segments to|1.0|360.0|150.0
ParameterBoolean|-r|Output angles in radians|False
ParameterBoolean|-e|Extended topology|False
OutputVector|seg_vector|Vector to store new network with segments
10 changes: 10 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.basins.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
r.stream.basins
r.stream.basins - Calculate basins according user input
Raster (r.*)
ParameterRaster|dir|Input map: flow direction|False
ParameterRaster|stream|Input map: stream network|True
ParameterVector|points|Basins outlets|0|True
ParameterBoolean|-z|Create zero-value background|False
ParameterBoolean|-c|Use unique category sequence|False
ParameterBoolean|-l|Create basins only for last stream links|False
OutputRaster|basins|Output basin map
8 changes: 8 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.del.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
r.stream.del
r.stream.del - Calculate basins according user input
Raster (r.*)
ParameterRaster|stream|Input map: stream mask|False
ParameterRaster|dir|Input map: flow direction|False
ParameterNumber|threshold|Minimum number of cell in stream|1|None|1
ParameterBoolean|-z|Create zero-value background|False
OutputRaster|reduced|Output reduced stream map
12 changes: 12 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.distance.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
r.stream.distance
r.stream.distance - Calculate distance to and elevation above streams and outlets
Raster (r.*)
ParameterRaster|stream|Input map: streams (outlets) mask|False
ParameterRaster|dir|Input map: flow direction|False
ParameterRaster|dem|Input map: elevation map|True
ParameterSelection|method|Calculation method|upstream,downstream|1
ParameterBoolean|-o|Calculate parameters for outlets|False
ParameterBoolean|-s|Calculate parameters for subbasins|False
ParameterBoolean|-n|Calculate nearest local maximum|False
OutputRaster|elevation|Output elevation map
OutputRaster|distance|Output distance map
13 changes: 13 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.extract.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
r.stream.extract
r.stream.extract - Stream network extraction
Raster (r.*)
ParameterRaster|elevation|Input map: elevation map|False
ParameterRaster|accumulation|Input map: accumulation map|True
ParameterRaster|depression|Input map: map with real depressions|True
ParameterNumber|threshold|Minimum flow accumulation for streams|1.0|None|0.1
ParameterNumber|mexp|Montgomery exponent for slope|0|None|0
ParameterNumber|stream_length|Delete stream segments shorter than cells|0|None|0
ParameterNumber|d8cut|Use SFD above this threshold|0|None|0
OutputRaster|stream_rast|Output raster map with unique stream ids
OutputVector|stream_vect|Output vector with unique stream ids
OutputRaster|direction|Output raster map with flow direction
11 changes: 11 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.order.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
r.stream.order
r.stream.order - Calculate Strahler's and Horton's stream order Hack's main streams and Shreeve's stream magnitude
Raster (r.*)
ParameterRaster|stream|Input map: stream mask|False
ParameterRaster|dir|Input map: direction map|False
ParameterBoolean|-z|Create zero-value background|False
OutputRaster|strahler|Output basin map (Strahler)
OutputRaster|shreve|Output basin map (Shreve)
OutputRaster|horton|Output basin map (Horton)
OutputRaster|hack|Output basin map (Hack)
OutputRaster|top|Output basin map (Top)
9 changes: 9 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.pos.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
r.stream.pos
r.stream.pos - Route azimuth, direction and relation to streams of higher order
Raster (r.*)
ParameterRaster|stream|Input map: stream mask|False
ParameterRaster|dir|Input map: flow direction|False
ParameterNumber|multiplier|Multipier to store stream index value|1|None|1000
ParameterBoolean|-s|Create new stream category sequence|False
OutputFile|cells|File to store pixel's position
OutputFile|lengths|File to store current stream length
7 changes: 7 additions & 0 deletions python/plugins/sextante/grass/description/r.stream.stats.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
r.stream.stats
r.stream.stats - Calculate Horton's and optionally Hack's statistics
Raster (r.*)
ParameterRaster|stream|Input map: stream mask|False
ParameterRaster|dir|Input map: flow direction|False
ParameterRaster|dem|Input map: elevation|False
OutputFile|outputtext
2 changes: 1 addition & 1 deletion python/plugins/sextante/grass/description/v.clean.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ v.clean - Toolset for cleaning topology of vector map.
Vector (v.*)
ParameterVector|input|Layer to clean|-1|False
ParameterSelection|tool|Cleaning tool|break;snap;rmdangle;chdangle;rmbridge;chbridge;rmdupl;rmdac;bpol;prune;rmarea;rmline;rmsa
ParameterNumber|thresh|Threshold|None|None|0
ParameterNumber|thresh|Threshold|None|None|0.0
OutputVector|output|Cleaned vector layer
OutputVector|error|Errors layer

84 changes: 52 additions & 32 deletions python/plugins/sextante/grass/grass.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
A short guide for creating and editing GRASS algorithms for SEXTANTE:
-----------------------------------------------------------------------

Each GRASS command, to be executed from a SEXTANTE element such as the toolbox or the graphical modeler, needs to be described to let SEXTANTE know the inputs required by the commands, the output it generates and the parameters that are used to configure it. Each command is described in a separate text file, although some commands might be split in several algorithms, needing thus several files and adding more than one new entry to the algorithms list of SEXTANTE. Splitting a grassc ommand is usually done because SEXTANTE does not support optional parameters, so it will call GRASS using all parameters defined in the description file.

Here is an explanation of the content of these descriptions files, so you can create you own ones or edit current ones to improve them.
Each GRASS command, to be executed from a SEXTANTE element such as the toolbox
or the graphical modeler, needs to be described to let SEXTANTE know the inputs
required by the commands, the output it generates and the parameters that are
used to configure it. Each command is described in a separate text file, although
some commands might be split in several algorithms, needing thus several files
and adding more than one new entry to the algorithms list of SEXTANTE. Splitting
a grassc ommand is usually done because SEXTANTE does not support optional
parameters, so it will call GRASS using all parameters defined in the description
file.

Here is an explanation of the content of these descriptions files, so you can
create you own ones or edit current ones to improve them.

Each file starts with three lines containing:

-The name of the grass command to call to execute the algorithm (e.g. v.buffer)
-The name of the algorithm to show to the user. This is usually the same as the grass command, but it can be different
-The name of the group where you want the command to appear
- The name of the grass command to call to execute the algorithm (e.g. v.buffer)
- The name of the algorithm to show to the user. This is usually the same as the
GRASS command, but it can be different
- The name of the group where you want the command to appear

After this three lines, a variable number of lines appear, describing all inputs and ouputs. Here is a brief explanation of the format of these lines, depending on the type of parameter or output to be described. All declarations are contained in a single line, with elements separated by the symbol "|"
After this three lines, a variable number of lines appear, describing all inputs
and ouputs. Here is a brief explanation of the format of these lines, depending
on the type of parameter or output to be described. All declarations are contained
in a single line, with elements separated by the symbol "|"

-A raster layer
- A raster layer
ParameterRaster|base|base|False

ParameterRaster|[name of GRASS parameter]|[description of parameter to show]|True/False, indicating if the parameter is optional or not

Example: ParameterRaster|base|base|False

-A vector layer
- A vector layer

ParameterVector|[name of GRASS parameter]|[description of parameter to shown]|[A number indicating the type of geometry]|True/False, indicating if the parameter is optional or not

Expand All @@ -33,62 +46,69 @@ To indicate the type of geometry, use the following values:
1: lines
2: polygons

-A numerical value
- A numerical value

ParameterNumericalValue|[name of GRASS parameter]|[description of parameter to show]|[min value]|[max value]|[default value]

"None" can be used for both min and max values to indicate that there is no lower or upper limit.
"None" can be used for both min and max values to indicate that there is no lower
or upper limit.

If the default value is written as a real number (i.e. it contains a decimal point, even if it is an integer value like 4.0), the parameter can take any value, including decimal ones. If it is written as an integer (i.e. 4), the parameter is assumed to accept only integer values
If the default value is written as a real number (i.e. it contains a decimal
point, even if it is an integer value like 4.0), the parameter can take any value,
including decimal ones. If it is written as an integer (i.e. 4), the parameter is
assumed to accept only integer values

Example: ParameterNumber|levels|levels|1|256|32

-A string
- A string

ParameterString|[name of GRASS parameter]|[description of parameter to show]|[default value]

-A value to select from a list
- A value to select from a list

ParameterSelection|[name of GRASS parameter]|[description of parameter to show]|[list of possible values, separated by semicolons]|[zero-based index of default value]

-A boolean value
- A boolean value

Example: ParameterBoolean|-c|-c|True

-Outputs
- Outputs

All outputs are added with the following syntax:

[type of output]|[name of GRASS output]|[description of output to show]

The following types are available

-OutputRaster
-OutputVector
-OutputTable
-OutputFile (for any file that is not a layer or table of a format supported by QGIS)
-OutputRaster
-OutputVector
-OutputTable
-OutputFile (for any file that is not a layer or table of a format supported by QGIS)


-Advanced parameters
- Advanced parameters

to tag a parameter as "advanced", just add "*" before its declaration. For instance:

*ParameterBoolean|-c|-c|True


ADVANCED OUTPUT PROCESSING
-------------------------
--------------------------

In some cases, it might be interesting to take the console otput from GRASS and extract a part of it for saving or formatting.
In some cases, it might be interesting to take the console otput from GRASS and
extract a part of it for saving or formatting.

Two things can be done about this:

-Creating an HTML file with output. Just add an output of type OutputHTML.
It's value will not be passed to GRASS, but you can use it later to create the HTML file from the console output.
You should create a python file in the grass/ext package, with the same name as the grass module, with dots replaced by low hyphens
(for instance r_quantile.py for the r.quantile command), and add a postProcessResults(alg) method. It will be called when the
execution of the GRASS command is finished.
-Creating a text file. Do as above, but adding an otput of type OutputFile. Since some GRASS commands might use this type of output,
and to make sure that the value of this output is not passed to the GRASS comman when calling it, the output has to be named 'outputtext'


- Creating an HTML file with output. Just add an output of type OutputHTML.
It's value will not be passed to GRASS, but you can use it later to create the
HTML file from the console output. You should create a python file in the
grass/ext package, with the same name as the grass module, with dots replaced
by low hyphens (for instance r_quantile.py for the r.quantile command), and
add a postProcessResults(alg) method. It will be called when the execution of
the GRASS command is finished.
- Creating a text file. Do as above, but adding an otput of type OutputFile.
Since some GRASS commands might use this type of output, and to make sure that
the value of this output is not passed to the GRASS comman when calling it,
the output has to be named 'outputtext'
31 changes: 15 additions & 16 deletions python/plugins/sextante/gui/SextanteToolbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
***************************************************************************
"""


__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
Expand Down Expand Up @@ -47,23 +46,22 @@
_fromUtf8 = lambda s: s

class SextanteToolbox(QDockWidget, Ui_SextanteToolbox):

USE_CATEGORIES = "/SextanteQGIS/UseCategories"



def __init__(self, iface):
QDockWidget.__init__(self, None)
self.setupUi(self)
self.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)

self.iface=iface

self.modeComboBox.clear()
self.modeComboBox.addItems(['Simplified interface', 'Advanced interface'])
settings = QSettings()
if not settings.contains(self.USE_CATEGORIES):
settings.setValue(self.USE_CATEGORIES, True)
useCategories = settings.value(self.USE_CATEGORIES).toBool()
settings.setValue(self.USE_CATEGORIES, True)
useCategories = settings.value(self.USE_CATEGORIES).toBool()
if useCategories:
self.modeComboBox.setCurrentIndex(0)
else:
Expand All @@ -79,15 +77,15 @@ def __init__(self, iface):
self.searchBox.setPlaceholderText(self.tr("Search..."))

self.fillTree()

def modeHasChanged(self):
idx = self.modeComboBox.currentIndex()
settings = QSettings()
if idx == 0: #simplified
settings.setValue(self.USE_CATEGORIES, True)
settings.setValue(self.USE_CATEGORIES, True)
else:
settings.setValue(self.USE_CATEGORIES, False)
settings.setValue(self.USE_CATEGORIES, False)

self.fillTree()

def algsListHasChanged(self):
Expand All @@ -111,12 +109,15 @@ def showPopupMenu(self,point):
executeBatchAction = QAction(self.tr("Execute as batch process"), self.algorithmTree)
executeBatchAction.triggered.connect(self.executeAlgorithmAsBatchProcess)
popupmenu.addAction(executeBatchAction)
popupmenu.addSeparator()
editRenderingStylesAction = QAction(self.tr("Edit rendering styles for outputs"), self.algorithmTree)
editRenderingStylesAction.triggered.connect(self.editRenderingStyles)
popupmenu.addAction(editRenderingStylesAction)
actions = Sextante.contextMenuActions
if len(actions) > 0:
popupmenu.addSeparator()
for action in actions:
action.setData(alg,self)
action.setData(alg, self)
if action.isEnabled():
contextMenuAction = QAction(action.name, self.algorithmTree)
contextMenuAction.triggered.connect(action.execute)
Expand Down Expand Up @@ -173,7 +174,7 @@ def executeAlgorithm(self):

def fillTree(self):
settings = QSettings()
useCategories = settings.value(self.USE_CATEGORIES).toBool()
useCategories = settings.value(self.USE_CATEGORIES).toBool()
if useCategories:
self.fillTreeUsingCategories()
else:
Expand Down Expand Up @@ -307,7 +308,7 @@ def fillTreeUsingCategories(self):
if (text != ""):
self.algorithmTree.expandAll()

def fillTreeUsingProviders(self):
def fillTreeUsingProviders(self):
self.algorithmTree.clear()
text = unicode(self.searchBox.text())
for providerName in Sextante.algs.keys():
Expand Down Expand Up @@ -357,8 +358,6 @@ def fillTreeUsingProviders(self):
for groupItem in groups.values():
groupItem.setExpanded(text != "")



class TreeAlgorithmItem(QTreeWidgetItem):

def __init__(self, alg):
Expand Down
Binary file added python/plugins/sextante/images/delete.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/plugins/sextante/images/edit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/plugins/sextante/images/minus.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/plugins/sextante/images/minus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/plugins/sextante/images/plus.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/plugins/sextante/images/plus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion python/plugins/sextante/modeler/ModelerAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ def activateAlgorithm(self, algIndex, update = False):
self.deactivated.remove(algIndex)
dependent = self.getDependentAlgorithms(algIndex)
for alg in dependent:
self.deactivated.remove(alg)
if alg in self.deactivated:
self.deactivated.remove(alg)
if update:
self.updateModelerView()
return True
Expand Down
103 changes: 69 additions & 34 deletions python/plugins/sextante/modeler/ModelerArrowItem.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from PyQt4 import QtCore, QtGui
import math
from sextante.modeler.ModelerGraphicItem import ModelerGraphicItem
from sextante.core.GeoAlgorithm import GeoAlgorithm

#portions of this code have been taken and adapted from PyQt examples, released under the following license terms

Expand Down Expand Up @@ -45,9 +47,11 @@

class ModelerArrowItem(QtGui.QGraphicsLineItem):

def __init__(self, startItem, endItem, parent=None, scene=None):
def __init__(self, startItem, outputIndex, endItem, paramIndex ,parent=None, scene=None):
super(ModelerArrowItem, self).__init__(parent, scene)
self.arrowHead = QtGui.QPolygonF()
self.paramIndex = paramIndex
self.outputIndex = outputIndex
self.myStartItem = startItem
self.myEndItem = endItem
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, False)
Expand All @@ -66,13 +70,7 @@ def endItem(self):
def boundingRect(self):
#this is a quick fix to avoid arrows not being drawn
return QtCore.QRectF(0, 0, 4000,4000)
#=======================================================================
# extra = (self.pen().width() + 20) / 2.0
# p1 = self.line().p1()
# p2 = self.line().p2()
# return QtCore.QRectF(p1, QtCore.QSizeF(p2.x() - p1.x(), p2.y() - p1.y())).normalized().adjusted(-extra, -extra, extra, extra)
#=======================================================================


def shape(self):
path = super(ModelerArrowItem, self).shape()
path.addPolygon(self.arrowHead)
Expand All @@ -82,47 +80,84 @@ def updatePosition(self):
line = QtCore.QLineF(self.mapFromItem(self.myStartItem, 0, 0), self.mapFromItem(self.myEndItem, 0, 0))
self.setLine(line)

def paint(self, painter, option, widget=None):
#if (self.myStartItem.collidesWithItem(self.myEndItem)):
#return

def paint(self, painter, option, widget=None):
myStartItem = self.myStartItem
myEndItem = self.myEndItem
myPen = self.pen()
myPen.setColor(self.myColor)
arrowSize = 6.0
painter.setPen(myPen)
painter.setBrush(self.myColor)

centerLine = QtCore.QLineF(myStartItem.pos(), myEndItem.pos())
endPolygon = myEndItem.polygon()
p1 = endPolygon.first() + myEndItem.pos()

intersectPoint = QtCore.QPointF()
for i in endPolygon:
p2 = i + myEndItem.pos()
polyLine = QtCore.QLineF(p1, p2)
intersectType = polyLine.intersect(centerLine, intersectPoint)
if intersectType == QtCore.QLineF.BoundedIntersection:
break
p1 = p2

self.setLine(QtCore.QLineF(intersectPoint, myStartItem.pos()))
line = self.line()
painter.setBrush(self.myColor)

if isinstance(self.startItem().element, GeoAlgorithm):
if self.startItem().element.outputs:
endPt = self.endItem().getLinkPointForParameter(self.paramIndex)
startPt = self.startItem().getLinkPointForOutput(self.outputIndex)
arrowLine = QtCore.QLineF(myEndItem.pos() + endPt - QtCore.QPointF(endPt.x() + ModelerGraphicItem.BOX_WIDTH /2, 0), myEndItem.pos() + endPt)
painter.drawLine(arrowLine)
tailLine = QtCore.QLineF(myStartItem.pos() + startPt + QtCore.QPointF(ModelerGraphicItem.BOX_WIDTH /2 - startPt.x(),0), myStartItem.pos() + startPt)
painter.drawLine(tailLine)
pt = QtCore.QPointF(myStartItem.pos() + startPt + QtCore.QPointF(- 2, -2))
rect = QtCore.QRectF(pt.x(), pt.y(), 4, 4)
painter.fillRect(rect, QtCore.Qt.gray)
line = QtCore.QLineF(myStartItem.pos() + startPt + QtCore.QPointF(ModelerGraphicItem.BOX_WIDTH /2 - startPt.x(),0),
myEndItem.pos() + endPt - QtCore.QPointF(endPt.x() + ModelerGraphicItem.BOX_WIDTH /2, 0))
else: # case where there is a dependency on an algorithm not on an output
endPolygon = myEndItem.polygon()
p1 = endPolygon.first() + myEndItem.pos()
line = QtCore.QLineF(myStartItem.pos(), myEndItem.pos())
intersectPoint = QtCore.QPointF()
for i in endPolygon:
p2 = i + myEndItem.pos()
polyLine = QtCore.QLineF(p1, p2)
intersectType = polyLine.intersect(line, intersectPoint)
if intersectType == QtCore.QLineF.BoundedIntersection:
break
p1 = p2

self.setLine(QtCore.QLineF(intersectPoint, myStartItem.pos()))
line = self.line()
if line.length() == 0: #division by zero might occur if arrow has no length
return
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = (math.pi * 2.0) - angle

arrowP1 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi / 3.0) * arrowSize,
math.cos(angle + math.pi / 3) * arrowSize)
arrowP2 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrowSize,
math.cos(angle + math.pi - math.pi / 3.0) * arrowSize)

self.arrowHead.clear()
for point in [line.p1(), arrowP1, arrowP2]:
self.arrowHead.append(point)

painter.drawLine(line)
painter.drawPolygon(self.arrowHead)
return;
else:
endPt = self.endItem().getLinkPointForParameter(self.paramIndex)
arrowLine = QtCore.QLineF(myEndItem.pos() + endPt - QtCore.QPointF(endPt.x() + ModelerGraphicItem.BOX_WIDTH /2, 0), myEndItem.pos() + endPt)
painter.drawLine(arrowLine)
line = QtCore.QLineF(myStartItem.pos(),
myEndItem.pos() + endPt - QtCore.QPointF(endPt.x() + ModelerGraphicItem.BOX_WIDTH /2, 0))

self.setLine(line);

if line.length() == 0: #division by zero might occur if arrow has no length
return

angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = (math.pi * 2.0) - angle

arrowP1 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi / 3.0) * arrowSize,
math.cos(angle + math.pi / 3) * arrowSize)
arrowP2 = line.p1() + QtCore.QPointF(math.sin(angle + math.pi - math.pi / 3.0) * arrowSize,
math.cos(angle + math.pi - math.pi / 3.0) * arrowSize)
arrowP1 = arrowLine.p2() + QtCore.QPointF(-math.cos(math.pi / 9.0) * arrowSize,
math.sin(math.pi / 9.0) * arrowSize)
arrowP2 = arrowLine.p2() + QtCore.QPointF(-math.cos(math.pi / 9.0) * arrowSize,
-math.sin(math.pi / 9.0) * arrowSize)

self.arrowHead.clear()
for point in [line.p1(), arrowP1, arrowP2]:
for point in [arrowLine.p2(), arrowP1, arrowP2]:
self.arrowHead.append(point)

painter.drawLine(line)
Expand Down
206 changes: 187 additions & 19 deletions python/plugins/sextante/modeler/ModelerGraphicItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,82 @@

class ModelerGraphicItem(QtGui.QGraphicsItem):

BOX_HEIGHT = 70
BOX_HEIGHT = 30
BOX_WIDTH = 200

def __init__(self, element, elementIndex, model):
super(ModelerGraphicItem, self).__init__(None, None)
self.model = model
self.element = element
self.elementIndex = elementIndex
self.inputFolded = True
self.outputFolded = True
if isinstance(element, Parameter):
icon = QtGui.QIcon(os.path.dirname(__file__) + "/../images/input.png")
self.pixmap = icon.pixmap(20, 20, state=QtGui.QIcon.On)
self.text = element.description
else:
state=QtGui.QIcon.On
if self.elementIndex in self.model.deactivated:
state=QtGui.QIcon.Off
self.text = element.name
self.pixmap = element.getIcon().pixmap(20, 20, state=QtGui.QIcon.On)
self.pixmap = element.getIcon().pixmap(15, 15, state=state)
self.arrows = []
self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True)
self.setFlag(QtGui.QGraphicsItem.ItemIsSelectable, True)
self.setZValue(1000)

icon = QtGui.QIcon(os.path.dirname(__file__) + "/../images/edit.png")
pt = QtCore.QPointF(ModelerGraphicItem.BOX_WIDTH / 2 - FlatButtonGraphicItem.WIDTH / 2, ModelerGraphicItem.BOX_HEIGHT / 2 - FlatButtonGraphicItem.HEIGHT / 2 + 1)
self.editButton = FlatButtonGraphicItem(icon, pt, self.editElement)
self.editButton.setParentItem(self)
icon = QtGui.QIcon(os.path.dirname(__file__) + "/../images/delete.png")
pt = QtCore.QPointF(ModelerGraphicItem.BOX_WIDTH / 2 - FlatButtonGraphicItem.WIDTH / 2, -ModelerGraphicItem.BOX_HEIGHT / 2 + FlatButtonGraphicItem.HEIGHT / 2 + 1)
self.deleteButton = FlatButtonGraphicItem(icon, pt, self.removeElement)
self.deleteButton.setParentItem(self)

if isinstance(element, GeoAlgorithm):
if element.parameters:
pt = self.getLinkPointForParameter(-1)
x = self.getXPositionForFoldButton()
pt = QtCore.QPointF(x, pt.y() + 3)
self.inButton = FoldButtonGraphicItem(pt, self.foldInput)
self.inButton.setParentItem(self)
if element.outputs:
pt = self.getLinkPointForOutput(-1)
x = self.getXPositionForFoldButton()
pt = QtCore.QPointF(x, pt.y() + 3)
self.outButton = FoldButtonGraphicItem(pt, self.foldOutput)
self.outButton.setParentItem(self)


def foldInput(self, folded):
self.inputFolded = folded
self.prepareGeometryChange()
if self.element.outputs:
pt = self.getLinkPointForOutput(-1)
x = self.getXPositionForFoldButton()
pt = QtCore.QPointF(x, pt.y())
self.outButton.position = pt
self.update()

def foldOutput(self, folded):
self.outputFolded = folded
self.prepareGeometryChange()
self.update()

def addArrow(self, arrow):
self.arrows.append(arrow)

def boundingRect(self):
font = QtGui.QFont("Verdana", 8)
fm = QtGui.QFontMetricsF(font)
numParams = 0 if self.inputFolded else len(self.element.parameters)
numOutputs = 0 if self.outputFolded else len(self.element.outputs)
numElements = numParams + numOutputs + 3
h = (fm.height() * 1.2) * numElements
rect = QtCore.QRectF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2,
ModelerGraphicItem.BOX_WIDTH + 2, ModelerGraphicItem.BOX_HEIGHT + 2)
ModelerGraphicItem.BOX_WIDTH + 2, ModelerGraphicItem.BOX_HEIGHT + h)
return rect

def mouseDoubleClickEvent(self, event):
Expand All @@ -79,9 +129,11 @@ def contextMenuEvent(self, event):
popupmenu.exec_(event.screenPos())

def deactivateAlgorithm(self):
self.model.setPositions(self.scene().getParameterPositions(), self.scene().getAlgorithmPositions())
self.model.deactivateAlgorithm(self.elementIndex, True)

def activateAlgorithm(self):
self.model.setPositions(self.scene().getParameterPositions(), self.scene().getAlgorithmPositions())
if not self.model.activateAlgorithm(self.elementIndex, True):
QtGui.QMessageBox.warning(None, "Could not activate Algorithm",
"The selected algorithm depends on other currently non-active algorithms.\nActivate them them before trying to activate it.")
Expand Down Expand Up @@ -119,44 +171,96 @@ def getAdjustedText(self, text):
font = QtGui.QFont("Verdana", 8)
fm = QtGui.QFontMetricsF(font)
w = fm.width(text)
if w < self.BOX_WIDTH:
if w < self.BOX_WIDTH - 25 - FlatButtonGraphicItem.WIDTH:
return text

text = text[0:-3] + "..."
w = fm.width(text)
while(w > self.BOX_WIDTH):
while(w > self.BOX_WIDTH - 25 - FlatButtonGraphicItem.WIDTH):
text = text[0:-4] + "..."
w = fm.width(text)
return text


def paint(self, painter, option, widget=None):

rect = QtCore.QRectF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2,
rect = QtCore.QRectF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2.0, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2.0,
ModelerGraphicItem.BOX_WIDTH + 2, ModelerGraphicItem.BOX_HEIGHT + 2)
painter.setPen(QtGui.QPen(QtCore.Qt.gray, 1))
painter.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
painter.drawRect(rect)
font = QtGui.QFont("Verdana", 8)
painter.setFont(font)
painter.setPen(QtGui.QPen(QtCore.Qt.black))
if self.isSelected():
painter.setPen(QtGui.QPen(QtCore.Qt.blue))
else:
painter.setPen(QtGui.QPen(QtCore.Qt.black))
if isinstance(self.element, GeoAlgorithm):
if self.elementIndex in self.model.deactivated:
painter.setPen(QtGui.QPen(QtCore.Qt.lightGray))
fm = QtGui.QFontMetricsF(font)
text = self.getAdjustedText(self.text)
w = fm.width(QtCore.QString(text))
h = fm.height()
pt = QtCore.QPointF(-w/2, h/2)
pt = QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + 25, h/2.0)
painter.drawText(pt, text)
if isinstance(self.element, GeoAlgorithm):
if self.elementIndex in self.model.deactivated:
painter.setPen(QtGui.QPen(QtCore.Qt.red))
w = fm.width(QtCore.QString("[deactivated]"))
pt = QtCore.QPointF(-w/2, h+h/2)
painter.drawText(pt, "[deactivated]")
painter.drawPixmap(-10 , -(ModelerGraphicItem.BOX_HEIGHT )/3,self.pixmap)
painter.setPen(QtGui.QPen(QtCore.Qt.black))
if isinstance(self.element, GeoAlgorithm):
h = (fm.height() * 1.2)
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
pt = QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + 25, h)
painter.drawText(pt, "In")
i = 1
if not self.inputFolded:
for param in self.element.parameters:
text = self.getAdjustedText(param.description)
h = (fm.height() * 1.2) * (i + 1)
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
pt = QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + 33, h)
painter.drawText(pt, text)
i += 1
h = (fm.height() * 1.2) * (i + 1)
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
pt = QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + 25, h)
painter.drawText(pt, "Out")
i += 1
if not self.outputFolded:
for out in self.element.outputs:
text = self.getAdjustedText(out.description)
h = (fm.height() * 1.2) * (i + 1)
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
pt = QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + 33, h)
painter.drawText(pt, text)
i += 1
painter.drawPixmap(-(ModelerGraphicItem.BOX_WIDTH / 2.0) + 3, -8, self.pixmap)

def getLinkPointForParameter(self, paramIndex):
offsetX = 30
if self.inputFolded:
paramIndex = -1
offsetX = 22
font = QtGui.QFont("Verdana", 8)
fm = QtGui.QFontMetricsF(font)
h = (fm.height() * 1.2) * (paramIndex + 2) - fm.height() / 2.0
h = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
return QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH)/2 + offsetX, h)


def getXPositionForFoldButton(self):
return 0

def getLinkPointForOutput(self, outputIndex):
if isinstance(self.element, GeoAlgorithm):
numParams = 0 if self.inputFolded else len(self.element.parameters)
outputIndex = outputIndex if not self.outputFolded else -1
text = self.getAdjustedText(self.element.outputs[outputIndex].description)
font = QtGui.QFont("Verdana", 8)
fm = QtGui.QFontMetricsF(font)
w = fm.width(QtCore.QString(text))
h = (fm.height() * 1.2) * (outputIndex + 3 + numParams) - fm.height() / 2.0
y = h + ModelerGraphicItem.BOX_HEIGHT / 2.0
x = -(ModelerGraphicItem.BOX_WIDTH)/2 + 33 + w + 5 if not self.outputFolded else 10
return QtCore.QPointF(x, y)
else:
return QtCore.QPointF(0, 0)

def itemChange(self, change, value):
if change == QtGui.QGraphicsItem.ItemPositionChange:
Expand All @@ -166,11 +270,75 @@ def itemChange(self, change, value):
return value

def polygon(self):
font = QtGui.QFont("Verdana", 8)
fm = QtGui.QFontMetricsF(font)
numElements = len(self.element.parameters) + len(self.element.outputs) + 3
h = (fm.height() * 1.2) * numElements
pol = QtGui.QPolygonF([
QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2),
QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, (ModelerGraphicItem.BOX_HEIGHT + 2)/2),
QtCore.QPointF((ModelerGraphicItem.BOX_WIDTH + 2)/2, (ModelerGraphicItem.BOX_HEIGHT + 2)/2),
QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, (ModelerGraphicItem.BOX_HEIGHT + 2)/2 + h),
QtCore.QPointF((ModelerGraphicItem.BOX_WIDTH + 2)/2, (ModelerGraphicItem.BOX_HEIGHT + 2)/2 + h),
QtCore.QPointF((ModelerGraphicItem.BOX_WIDTH + 2)/2, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2),
QtCore.QPointF(-(ModelerGraphicItem.BOX_WIDTH + 2)/2, -(ModelerGraphicItem.BOX_HEIGHT + 2)/2)])
return pol

class FlatButtonGraphicItem(QtGui.QGraphicsItem):

WIDTH = 16
HEIGHT = 16

def __init__(self, icon, position, action):
super(FlatButtonGraphicItem, self).__init__(None, None)
self.setAcceptHoverEvents(True)
self.setFlag(QtGui.QGraphicsItem.ItemIsMovable, False)
self.pixmap = icon.pixmap(self.WIDTH, self.HEIGHT, state=QtGui.QIcon.On)
self.position = position
self.isIn = False
self.action = action

def mousePressEvent(self, event):
self.action()

def paint(self, painter, option, widget=None):
pt = QtCore.QPointF(-self.WIDTH / 2, -self.HEIGHT / 2) + self.position
rect = QtCore.QRectF(pt.x(), pt.y(), self.WIDTH, self.HEIGHT)
if self.isIn:
painter.setPen(QtGui.QPen(QtCore.Qt.transparent, 1))
painter.setBrush(QtGui.QBrush(QtCore.Qt.lightGray, QtCore.Qt.SolidPattern))
else:
painter.setPen(QtGui.QPen(QtCore.Qt.transparent, 1))
painter.setBrush(QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
painter.drawRect(rect)
painter.drawPixmap(pt.x(), pt.y(), self.pixmap)

def boundingRect(self):
rect = QtCore.QRectF(self.position.x() - self.WIDTH / 2, self.position.y() - self.HEIGHT / 2, self.WIDTH, self.HEIGHT)
return rect

def hoverEnterEvent(self, event):
self.isIn = True
self.update()

def hoverLeaveEvent(self, event):
self.isIn = False
self.update()

class FoldButtonGraphicItem(FlatButtonGraphicItem):

WIDTH = 11
HEIGHT = 11

icons = { True : QtGui.QIcon(os.path.dirname(__file__) + "/../images/plus.png"),
False : QtGui.QIcon(os.path.dirname(__file__) + "/../images/minus.png")}

def __init__(self, position, action):
self.folded = True
icon = self.icons[True]
super(FoldButtonGraphicItem, self).__init__(icon, position, action)

def mousePressEvent(self, event):
self.folded = not self.folded
icon = self.icons[self.folded]
self.pixmap = icon.pixmap(self.WIDTH, self.HEIGHT, state=QtGui.QIcon.On)
self.action(self.folded)

21 changes: 14 additions & 7 deletions python/plugins/sextante/modeler/ModelerScene.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,16 @@ def getItemsFromAAP(self, aap, isMultiple):
iModelParam=0
for modelparam in self.model.parameters:
if modelparam.name == aap.param:
items.append(self.paramItems[iModelParam])
items.append((self.paramItems[iModelParam], -1))
break
iModelParam+=1
else:
items.append(self.algItems[start])
idx = 0
for output in self.model.algs[start].outputs:
if output.name == aap.param:
items.append((self.algItems[start], idx))
break
idx += 1

return items

Expand Down Expand Up @@ -110,15 +115,17 @@ def paintModel(self, model):
iAlg=0
for alg in model.algs:
params = model.algParameters[iAlg]
for key in params.keys():
param = params[key]
idx = 0
for parameter in alg.parameters:
param = params[parameter.name]
if param:
sourceItems = self.getItemsFromAAP(param, isinstance(alg.getParameterFromName(key), ParameterMultipleInput))
sourceItems = self.getItemsFromAAP(param, isinstance(alg.getParameterFromName(parameter.name), ParameterMultipleInput))
for sourceItem in sourceItems:
arrow = ModelerArrowItem(sourceItem, self.algItems[iAlg])
arrow = ModelerArrowItem(sourceItem[0], sourceItem[1], self.algItems[iAlg], idx)
self.addItem(arrow)
idx += 1
for depend in model.dependencies[iAlg]:
arrow = ModelerArrowItem(self.algItems[depend], self.algItems[iAlg])
arrow = ModelerArrowItem(self.algItems[depend], -1, self.algItems[iAlg], -1)
self.addItem(arrow)
iAlg+=1

Expand Down
4 changes: 2 additions & 2 deletions resources/cpt-city-qgis-min/VERSION-parent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
version information for cpt-city packages
-->
<archive>
<version>2.02</version>
<version>2.07</version>
<variant>full</variant>
<parent>none</parent>
<creator>J.J. Green</creator>
<created>Thu Aug 16 00:01:37 CEST 2012</created>
<created>Thu Apr 11 20:19:13 BST 2013</created>
</archive>
8 changes: 4 additions & 4 deletions resources/cpt-city-qgis-min/VERSION.xml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<archive>
<!--version information for cpt-city packages-->
<version>2.02.1</version>
<variant>cpt-city-qgis-min</variant>
<version>2.07.2</version>
<variant>cpt-city-qgis-sel</variant>
<parent>
<version>2.02</version>
<version>2.07</version>
<variant>full</variant>
</parent>
<creator>Etienne Tourigny</creator>
<created>Sat Aug 18 11:42:24 2012</created>
<created>Mon Apr 22 14:27:17 2013</created>
</archive>
23 changes: 23 additions & 0 deletions resources/cpt-city-qgis-min/bhw/COPYING.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<copying>
<authors>
<author href="http://blackheartedwolf.deviantart.com/">
<name>Blackheartedworf</name>
</author>
</authors>
<license>
<informal>Attribution required</informal>
<year>2011</year>
<text href="http://creativecommons.org/licenses/by/3.0/"/>
</license>
<src>
<format>Paint Shop Pro gradients</format>
<link href="http://blackheartedwolf.deviantart.com/art/Gradients-1-22145298">Set 1</link>
<link href="http://blackheartedwolf.deviantart.com/art/Gradients-2-33255087">Set 2</link>
<link href="http://blackheartedwolf.deviantart.com/art/Gradients-3-41631439">Set 3</link>
<link href="http://blackheartedwolf.deviantart.com/art/Gradients-Pack-4-50008222">Set 4</link>
</src>
<distribute>
<qgis distribute="yes" license="cc3"/>
</distribute>
</copying>
9 changes: 9 additions & 0 deletions resources/cpt-city-qgis-min/bhw/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>bhw</dir>
<name>Art gradients by Blackheartedwolf</name>
<full>
Art gradients designed by Blackheartedwolf
</full>
<date>01/08/2012</date>
</description>
9 changes: 9 additions & 0 deletions resources/cpt-city-qgis-min/bhw/bhw1/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>bhw1</dir>
<name>Set 1</name>
<full>
Art gradients by Blackheartedwolf: set 1
</full>
<date>01/08/2012</date>
</description>
18 changes: 18 additions & 0 deletions resources/cpt-city-qgis-min/bhw/bhw1/bhw1_w00t.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions resources/cpt-city-qgis-min/bhw/bhw2/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>bhw2</dir>
<name>Set 2</name>
<full>
Art gradients by Blackheartedwolf: set 2
</full>
<date>01/08/2012</date>
</description>
21 changes: 21 additions & 0 deletions resources/cpt-city-qgis-min/bhw/bhw2/bhw2_39.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions resources/cpt-city-qgis-min/dg/COPYING.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0"?>
<copying>
<authors>
<author href="http://www.mrao.cam.ac.uk/~dag/index.html">
<name>Dave Green</name>
<org>Cavendish Laboratory, University of Cambridge</org>
</author>
</authors>
<license>
<informal>
Contributed to the public domain, citation requested.
</informal>
<year>2011</year>
<text>
Contributed to the public domain. Citation of the paper describing
the motivation for and design of the schemes

http://adsabs.harvard.edu/abs/2011BASI...39..289G

requested.
</text>
</license>
<src>
<format>PNG images from cubetry tool</format>
<link href="http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/">Cubehelix page</link>
<link href="http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/cubetry.html">The cubetry tool</link>
<link href="http://adsabs.harvard.edu/abs/2011BASI...39..289G">ADS entry for paper</link>
</src>
<distribute>
<qgis distribute="yes" license="other"/>
</distribute>
</copying>
10 changes: 10 additions & 0 deletions resources/cpt-city-qgis-min/dg/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>dg</dir>
<name>Dave Green's cubehelix for astronomical intensity images</name>
<full>
Dave Green's cubhelix colour scheme which is intended
to be perceived as increasing in intensity.
</full>
<date>01/08/2012</date>
</description>
270 changes: 270 additions & 0 deletions resources/cpt-city-qgis-min/dg/ch05m151008.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
270 changes: 270 additions & 0 deletions resources/cpt-city-qgis-min/dg/ch05m151010.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions resources/cpt-city-qgis-min/ds/COPYING.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<copying>
<authors>
<author href="http://www.myspace.com/dlsdesigns">
<name>Diane Simoni</name>
<alias>Webgoddess</alias>
</author>
</authors>
<license>
<informal>Link requested</informal>
<year>2006</year>
<text href="http://webgoddess.deviantart.com/journal/10627311/">
1. These are the general rules. Any additional rules will be listed
in the individual deviation descriptions.
2. My gradients can be used anywhere anytime.
3. If you use them on dA, I would appreciate a link back to the gradients,
so other people can find them.
4. I would also LOVE to see your piece and I will probably fav it.
</text>
</license>
<src>
<format>GIMP gradient (ggr)</format>
<link href="http://webgoddess.deviantart.com/art/Fuschia-Gradients-For-Gimp-32824719">Fuscia</link>
<link href="http://webgoddess.deviantart.com/art/Reddish-Inspired-Gradients-42208824">Reddish grunge</link>
<link href="http://webgoddess.deviantart.com/art/Gradients-from-Icons-for-Gimp-42207414">Icons</link>
<remark>Contributed via email, Thu, 04 May 2006</remark>
</src>
<distribute>
<qgis distribute="yes" license="other"/>
</distribute>
</copying>
9 changes: 9 additions & 0 deletions resources/cpt-city-qgis-min/ds/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>ds</dir>
<name>Gradients by Diane Simoni</name>
<full>
Gradients for digital art, by Diane Simoni.
</full>
<date>01/08/2012</date>
</description>
9 changes: 9 additions & 0 deletions resources/cpt-city-qgis-min/ds/rgi/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>rgi</dir>
<name>Reddish grunge inspired</name>
<full>
Gradients inpired by reddish grunge.
</full>
<date>01/08/2012</date>
</description>
23 changes: 23 additions & 0 deletions resources/cpt-city-qgis-min/ds/rgi/rgi_15.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions resources/cpt-city-qgis-min/ds9/COPYING.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<copying>
<authors>
<author>
<name>William Joye</name>
</author>
</authors>
<license>
<informal>GPL</informal>
<year>2010</year>
<text href="http://www.gnu.org/copyleft/gpl.html"/>
</license>
<src>
<format>C++ program source</format>
<link href="http://hea-www.harvard.edu/RD/ds9/">DS9 homepage</link>
</src>
<distribute>
<qgis distribute="yes" license="gpl"/>
</distribute>
</copying>
10 changes: 10 additions & 0 deletions resources/cpt-city-qgis-min/ds9/DESC.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<description>
<dir>ds9</dir>
<name>DS9 colour scales for astronomical visualisation</name>
<full>
The palettes used in the DS9 astronomical data
visualization tool.
</full>
<date>01/08/2012</date>
</description>
19 changes: 19 additions & 0 deletions resources/cpt-city-qgis-min/ds9/b.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions resources/cpt-city-qgis-min/ds9/he.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions resources/cpt-city-qgis-min/ds9/red.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading