Skip to content
Permalink
Browse files

Merge pull request #5686 from nyalldawson/encoding

[processing] Don't use crappy Qt file picker dialog
  • Loading branch information
nyalldawson committed Nov 21, 2017
2 parents d62b4e9 + b97c6a8 commit b058df7d1d5d17a14bb8ef18e4fe3515df7260d0
@@ -49,6 +49,46 @@ Returns true if the user clicked 'Cancel All'

};

class QgsEncodingSelectionDialog: QDialog
{
%Docstring
A dialog which presents the user with a choice of file encodings.
.. versionadded:: 3.0
*
%End

%TypeHeaderCode
#include "qgsencodingfiledialog.h"
%End
public:

QgsEncodingSelectionDialog( QWidget *parent /TransferThis/ = 0,
const QString &caption = QString(), const QString &encoding = QString(),
Qt::WindowFlags flags = Qt::WindowFlags() );
%Docstring
Constructor for QgsEncodingSelectionDialog.

If ``caption`` is set, it will be used as the caption within the dialog.

The ``encoding`` argument can be used to specify the encoding initially selected in the dialog.
%End

QString encoding() const;
%Docstring
Returns the encoding selected within the dialog.
.. seealso:: setEncoding()
:rtype: str
%End

void setEncoding( const QString &encoding );
%Docstring
Sets the ``encoding`` selected within the dialog.
see encoding()
%End

};


/************************************************************************
* This file has been generated automatically from *
* *
@@ -33,12 +33,13 @@
from qgis.PyQt.QtCore import QCoreApplication, QDir
from qgis.PyQt.QtWidgets import QDialog, QMenu, QAction, QFileDialog
from qgis.PyQt.QtGui import QCursor
from qgis.gui import QgsEncodingFileDialog, QgsExpressionBuilderDialog
from qgis.gui import QgsEncodingSelectionDialog
from qgis.core import (QgsDataSourceUri,
QgsCredentials,
QgsExpression,
QgsSettings,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterRasterDestination,
QgsProcessingOutputLayerDefinition,
QgsProcessingParameterDefinition,
QgsProcessingParameterFileDestination,
@@ -138,6 +139,11 @@ def selectOutput(self):
actionSaveToPostGIS.setEnabled(bool(names))
popupMenu.addAction(actionSaveToPostGIS)

actionSetEncoding = QAction(
self.tr('Change file encoding ({})...').format(self.encoding), self.btnSelect)
actionSetEncoding.triggered.connect(self.selectEncoding)
popupMenu.addAction(actionSetEncoding)

popupMenu.exec_(QCursor.pos())

def saveToTemporary(self):
@@ -172,71 +178,78 @@ def saveToPostGIS(self):
self.leText.setText("postgis:" + uri.uri())

def saveToSpatialite(self):
fileFilter = self.tr('SpatiaLite files (*.sqlite)', 'OutputFile')
file_filter = self.tr('SpatiaLite files (*.sqlite)', 'OutputFile')

settings = QgsSettings()
if settings.contains('/Processing/LastOutputPath'):
path = settings.value('/Processing/LastOutputPath')
else:
path = ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER)

fileDialog = QgsEncodingFileDialog(
self, self.tr('Save SpatiaLite'), path, fileFilter, self.encoding)
fileDialog.setFileMode(QFileDialog.AnyFile)
fileDialog.setAcceptMode(QFileDialog.AcceptSave)
fileDialog.setOption(QFileDialog.DontConfirmOverwrite, True)
filename, filter = QFileDialog.getSaveFileName(self, self.tr("Save file"), path,
file_filter, options=QFileDialog.DontConfirmOverwrite)

if fileDialog.exec_() == QDialog.Accepted:
if filename is not None:
self.use_temporary = False
files = fileDialog.selectedFiles()
self.encoding = str(fileDialog.encoding())
fileName = str(files[0])
selectedFileFilter = str(fileDialog.selectedNameFilter())
if not fileName.lower().endswith(
tuple(re.findall("\\*(\\.[a-z]{1,10})", fileFilter))):
ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter)
if ext:
fileName += ext.group(1)
if not filename.lower().endswith('.sqlite'):
filename += '.sqlite'
settings.setValue('/Processing/LastOutputPath',
os.path.dirname(fileName))
settings.setValue('/Processing/encoding', self.encoding)
os.path.dirname(filename))

uri = QgsDataSourceUri()
uri.setDatabase(fileName)
uri.setDatabase(filename)
uri.setDataSource('', self.parameter.name().lower(),
'the_geom' if isinstance(self.parameter, QgsProcessingParameterFeatureSink) and self.parameter.hasGeometry() else None)
self.leText.setText("spatialite:" + uri.uri())

def selectFile(self):
fileFilter = getFileFilter(self.parameter)

file_filter = getFileFilter(self.parameter)
settings = QgsSettings()
if isinstance(self.parameter, QgsProcessingParameterFeatureSink):
last_ext_path = '/Processing/LastVectorOutputExt'
last_ext = settings.value(last_ext_path, '.gpkg')
elif isinstance(self.parameter, QgsProcessingParameterRasterDestination):
last_ext_path = '/Processing/LastRasterOutputExt'
last_ext = settings.value(last_ext_path, '.tif')
else:
last_ext_path = None
last_ext = None

# get default filter
filters = file_filter.split(';;')
try:
last_filter = [f for f in filters if '*{}'.format(last_ext) in f.lower()][0]
except:
last_filter = None

if settings.contains('/Processing/LastOutputPath'):
path = settings.value('/Processing/LastOutputPath')
else:
path = ProcessingConfig.getSetting(ProcessingConfig.OUTPUT_FOLDER)

fileDialog = QgsEncodingFileDialog(
self, self.tr('Save file'), path, fileFilter, self.encoding)
fileDialog.setFileMode(QFileDialog.AnyFile)
fileDialog.setAcceptMode(QFileDialog.AcceptSave)
fileDialog.setOption(QFileDialog.DontConfirmOverwrite, False)

if fileDialog.exec_() == QDialog.Accepted:
filename, filter = QFileDialog.getSaveFileName(self, self.tr("Save file"), path,
file_filter, last_filter)
if filename:
self.use_temporary = False
files = fileDialog.selectedFiles()
self.encoding = str(fileDialog.encoding())
fileName = str(files[0])
selectedFileFilter = str(fileDialog.selectedNameFilter())
if not fileName.lower().endswith(
tuple(re.findall("\\*(\\.[a-z]{1,10})", fileFilter))):
ext = re.search("\\*(\\.[a-z]{1,10})", selectedFileFilter)
if not filename.lower().endswith(
tuple(re.findall("\\*(\\.[a-z]{1,10})", file_filter))):
ext = re.search("\\*(\\.[a-z]{1,10})", filter)
if ext:
fileName += ext.group(1)
self.leText.setText(fileName)
filename += ext.group(1)
self.leText.setText(filename)
settings.setValue('/Processing/LastOutputPath',
os.path.dirname(fileName))
os.path.dirname(filename))
if not last_ext_path is None:
settings.setValue(last_ext_path, os.path.splitext(filename)[1].lower())

def selectEncoding(self):
dialog = QgsEncodingSelectionDialog(
self, self.tr('File encoding'), self.encoding)
if dialog.exec_() == QDialog.Accepted:
self.encoding = dialog.encoding()
settings = QgsSettings()
settings.setValue('/Processing/encoding', self.encoding)
dialog.deleteLater()

def selectDirectory(self):
lastDir = self.leText.text()
@@ -24,6 +24,7 @@
#include <QLabel>
#include <QLayout>
#include <QTextCodec>
#include <QDialogButtonBox>

QgsEncodingFileDialog::QgsEncodingFileDialog( QWidget *parent,
const QString &caption, const QString &directory,
@@ -102,3 +103,64 @@ void QgsEncodingFileDialog::pbnCancelAll_clicked()
// Now, continue as the user clicked the cancel button
reject();
}

QgsEncodingSelectionDialog::QgsEncodingSelectionDialog( QWidget *parent, const QString &caption, const QString &encoding, Qt::WindowFlags flags )
: QDialog( parent, flags )
{
QString c = caption;
if ( c.isEmpty() )
c = tr( "Encoding" );

setWindowTitle( tr( "Select Encoding" ) );

QVBoxLayout *layout = new QVBoxLayout();
layout->setMargin( 6 );

mEncodingComboBox = new QComboBox( this );
QLabel *l = new QLabel( c, this );

QHBoxLayout *hLayout = new QHBoxLayout();
hLayout->addWidget( l );
hLayout->addWidget( mEncodingComboBox, 1 );
layout->addLayout( hLayout );

QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal, this );
buttonBox->button( QDialogButtonBox::Ok )->setDefault( true );
connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
layout->addWidget( buttonBox );
setLayout( layout );

mEncodingComboBox->addItem( tr( "System" ) );
mEncodingComboBox->addItems( QgsVectorDataProvider::availableEncodings() );

// Use default encoding if none supplied
QString enc = encoding;
if ( encoding.isEmpty() )
{
QgsSettings settings;
enc = settings.value( QStringLiteral( "UI/encoding" ), "System" ).toString();
}

setEncoding( enc );
}

QString QgsEncodingSelectionDialog::encoding() const
{
return mEncodingComboBox->currentText();
}

void QgsEncodingSelectionDialog::setEncoding( const QString &encoding )
{
// The specified decoding is added if not existing alread, and then set current.
// This should select it.

int encindex = mEncodingComboBox->findText( encoding );
if ( encindex < 0 )
{
mEncodingComboBox->insertItem( 0, encoding );
encindex = 0;
}
mEncodingComboBox->setCurrentIndex( encindex );
}
@@ -61,4 +61,45 @@ class GUI_EXPORT QgsEncodingFileDialog: public QFileDialog
bool mCancelAll;
};

/**
* \ingroup gui
* A dialog which presents the user with a choice of file encodings.
* \since QGIS 3.0
**/
class GUI_EXPORT QgsEncodingSelectionDialog: public QDialog
{
Q_OBJECT

public:

/**
* Constructor for QgsEncodingSelectionDialog.
*
* If \a caption is set, it will be used as the caption within the dialog.
*
* The \a encoding argument can be used to specify the encoding initially selected in the dialog.
*/
QgsEncodingSelectionDialog( QWidget *parent SIP_TRANSFERTHIS = nullptr,
const QString &caption = QString(), const QString &encoding = QString(),
Qt::WindowFlags flags = Qt::WindowFlags() );

/**
* Returns the encoding selected within the dialog.
* \see setEncoding()
*/
QString encoding() const;

/**
* Sets the \a encoding selected within the dialog.
* see encoding()
*/
void setEncoding( const QString &encoding );

private:

QComboBox *mEncodingComboBox = nullptr;

};


#endif
@@ -48,6 +48,7 @@ ADD_PYTHON_TEST(PyQgsDelimitedTextProvider test_qgsdelimitedtextprovider.py)
ADD_PYTHON_TEST(PyQgsDistanceArea test_qgsdistancearea.py)
ADD_PYTHON_TEST(PyQgsEditWidgets test_qgseditwidgets.py)
ADD_PYTHON_TEST(PyQgsEllipsoidUtils test_qgsellipsoidutils.py)
ADD_PYTHON_TEST(PyQgsEncodingSelectionDialog test_qgsencodingselectiondialog.py)
ADD_PYTHON_TEST(PyQgsExpression test_qgsexpression.py)
ADD_PYTHON_TEST(PyQgsExpressionBuilderWidget test_qgsexpressionbuilderwidget.py)
ADD_PYTHON_TEST(PyQgsExpressionLineEdit test_qgsexpressionlineedit.py)
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsEncodingSelectionDialog
.. note:: 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__ = 'Nyall Dawson'
__date__ = '21/11/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis # NOQA

from qgis.gui import QgsEncodingSelectionDialog

from qgis.testing import start_app, unittest

start_app()


class TestQgsEncodingSelectionDialog(unittest.TestCase):

def testGettersSetters(self):
""" test dialog getters/setters """
dlg = qgis.gui.QgsEncodingSelectionDialog(encoding='UTF-16')
self.assertEqual(dlg.encoding(), 'UTF-16')
dlg.setEncoding('UTF-8')
self.assertEqual(dlg.encoding(), 'UTF-8')
# custom encoding option
dlg.setEncoding('trisolarian')
self.assertEqual(dlg.encoding(), 'trisolarian')


if __name__ == '__main__':
unittest.main()

0 comments on commit b058df7

Please sign in to comment.
You can’t perform that action at this time.