diff -r 0f3a641c5da5 -r 7880b294d1d1 CxFreeze/CxfreezeConfigDialog.py --- a/CxFreeze/CxfreezeConfigDialog.py Thu Jun 03 14:27:52 2021 +0200 +++ b/CxFreeze/CxfreezeConfigDialog.py Thu Jun 03 17:51:56 2021 +0200 @@ -12,14 +12,11 @@ import copy import contextlib -from PyQt5.QtCore import pyqtSlot, QDir, QProcess, QItemSelection -from PyQt5.QtWidgets import ( - QDialog, QListWidgetItem, QFileDialog, QPushButton, QTreeView, QLineEdit, - QFileSystemModel -) +from PyQt6.QtCore import pyqtSlot, QDir, QProcess +from PyQt6.QtWidgets import QDialog, QListWidgetItem -from E5Gui import E5FileDialog -from E5Gui.E5Completers import E5FileCompleter, E5DirCompleter +from EricWidgets.EricPathPicker import EricPathPickerModes +from EricWidgets.EricDirFileDialog import EricDirFileDialog from .Ui_CxfreezeConfigDialog import Ui_CxfreezeConfigDialog @@ -27,113 +24,6 @@ import UI.PixmapCache -class DirFileDialog(QFileDialog): - """ - Derived QFileDialog to select files and folders at once. - - For this purpose the none native filedialog is used. - """ - def __init__(self, parent=None, caption="", directory="", fileFilter=""): - """ - Constructor - - @param parent parent widget of the dialog (QWidget) - @param caption window title of the dialog (string) - @param directory working directory of the dialog (string) - @param fileFilter filter string for the dialog (string) - """ - self.selectedFilesFolders = [] - - super().__init__(parent, caption, directory, fileFilter) - self.setFileMode(QFileDialog.ExistingFiles) - - def exec(self): - """ - Public slot to finalize initialization and start the event loop. - - @return accepted or rejected (QDialog.DialogCode) - """ - self.openBtn = self.findChildren(QPushButton)[0] - self.fileNameEdit = self.findChild(QLineEdit) - self.directoryEntered.connect(self.on_directoryEntered) - self.tree = self.findChild(QTreeView) - self.tree.selectionModel().selectionChanged.connect( - self.on_selectionChanged) - return QFileDialog.exec(self) - - def accept(self): - """ - Public method to update the list with the selected files and folders. - """ - # Avoid to close the dialog if only return is pressed - if not self.openBtn.isEnabled(): - return - - self.selectedFilesFolders = [ - x.data(QFileSystemModel.FilePathRole) - for x in self.tree.selectionModel().selectedIndexes() - if x.column() == 0] - self.hide() - - @pyqtSlot(str) - def on_directoryEntered(self, directory): - """ - Private method to reset selections if another directory was entered. - - @param directory name of the directory entered (string) - """ - self.tree.selectionModel().clear() - self.fileNameEdit.clear() - self.openBtn.setEnabled(False) - - @pyqtSlot(QItemSelection, QItemSelection) - def on_selectionChanged(self, selected, deselected): - """ - Private method to determine the selected files and folders and update - the line edit. - - @param selected newly selected entries (QItemSelection) - @param deselected deselected entries (QItemSelection) - """ - selectedItems = self.tree.selectionModel().selectedIndexes() - if self.tree.rootIndex() in selectedItems or selectedItems == []: - return - selectedFiles = [x.data(QFileSystemModel.FileNameRole) - for x in selectedItems if x.column() == 0] - enteredFiles = self.fileNameEdit.text().split('"') - enteredFiles = [x for x in enteredFiles if x.strip() != ''] - # Check if there is a directory in the selection. Then update the - # lineEdit. - for selectedFile in selectedFiles: - if selectedFile not in enteredFiles: - txt = '" "'.join(selectedFiles) - if len(selectedFiles) > 1: - txt = '"{0}"'.format(txt) - self.fileNameEdit.setText(txt) - break - - @staticmethod - def getOpenFileNames(parent=None, caption="", directory="", - fileFilter="", options=None): - """ - Static method to get the names of files and folders for opening it. - - @param parent parent widget of the dialog (QWidget) - @param caption window title of the dialog (string) - @param directory working directory of the dialog (string) - @param fileFilter filter string for the dialog (string) - @param options various options for the dialog (QFileDialog.Options) - @return names of the selected files and folders (list of strings) - """ - if options is None: - options = QFileDialog.Options() - options |= QFileDialog.DontUseNativeDialog - dlg = DirFileDialog(parent, caption, directory, fileFilter) - dlg.setOptions(options) - dlg.exec() - return dlg.selectedFilesFolders - - class CxfreezeConfigDialog(QDialog, Ui_CxfreezeConfigDialog): """ Class implementing a dialog to enter the parameters for cxfreeze. @@ -142,79 +32,107 @@ """ Constructor - @param project reference to the project object (Project.Project) - @param exe name of the cxfreeze executable (string) + @param project reference to the project object + @type Project + @param exe name of the cxfreeze executable + @type str @param parms parameters to set in the dialog - @param parent parent widget of this dialog (QWidget) + @type dict + @param parent parent widget of this dialog + @type QWidget """ QDialog.__init__(self, parent) self.setupUi(self) - self.targetDirButton.setIcon( - UI.PixmapCache.getIcon("open.png")) - self.iconFileButton.setIcon( - UI.PixmapCache.getIcon("open.png")) - self.extListFileButton.setIcon( - UI.PixmapCache.getIcon("open.png")) self.selectFileOrFolderButton.setIcon( UI.PixmapCache.getIcon("open.png")) - self.project = project + self.targetDirPicker.setMode( + EricPathPickerModes.DIRECTORY_MODE) + self.targetDirPicker.setWindowTitle( + self.tr("Select target directory")) + + iconsI18N = self.tr("Icons") + allFilesI18N = self.tr("All files") + if Utilities.isWindowsPlatform(): + iconFilter = "{0} (*.ico);;{1} (*.*)".format( + iconsI18N, allFilesI18N) + elif Utilities.isMacPlatform(): + iconFilter = "{0} (*.icns *.png);;{1} (*.*)".format( + iconsI18N, allFilesI18N) + else: + iconFilter = "{0} (*.png);;{1} (*.*)".format( + iconsI18N, allFilesI18N) + self.applicationIconPicker.setMode( + EricPathPickerModes.OPEN_FILE_MODE) + self.applicationIconPicker.setWindowTitle( + self.tr("Select the application icon")) + self.applicationIconPicker.setFilters(iconFilter) + + self.extListFilePicker.setMode( + EricPathPickerModes.OPEN_FILE_MODE) + self.extListFilePicker.setWindowTitle( + self.tr("Select external list file")) + + self.__project = project self.__initializeDefaults() # get a copy of the defaults to store the user settings - self.parameters = copy.deepcopy(self.defaults) + self.__parameters = copy.deepcopy(self.defaults) # combine it with the values of parms if parms is not None: - self.parameters.update(parms) + self.__parameters.update(parms) - self.exe = exe self.cxfreezeExecCombo.addItems(exe) # try to set the saved script path with contextlib.suppress(ValueError): - idx = exe.index(self.parameters['script']) + idx = exe.index(self.__parameters['script']) self.cxfreezeExecCombo.setCurrentIndex(idx) - self.targetDirCompleter = E5DirCompleter(self.targetDirEdit) - self.extListFileCompleter = E5FileCompleter(self.extListFileEdit) - # initialize general tab - self.targetDirEdit.setText(self.parameters['targetDirectory']) - self.targetNameEdit.setText(self.parameters['targetName']) - self.basenameCombo.setEditText(self.parameters['baseName']) - self.initscriptCombo.setEditText(self.parameters['initScript']) - self.applicationIconEdit.setText(self.parameters['applicationIcon']) - self.keeppathCheckBox.setChecked(self.parameters['keepPath']) - self.compressCheckBox.setChecked(self.parameters['compress']) - if self.parameters['optimize'] == 0: + self.targetDirPicker.setText( + self.__parameters['targetDirectory']) + self.targetNameEdit.setText( + self.__parameters['targetName']) + self.basenameCombo.setEditText( + self.__parameters['baseName']) + self.initscriptCombo.setEditText( + self.__parameters['initScript']) + self.applicationIconPicker.setText( + self.__parameters['applicationIcon']) + self.keeppathCheckBox.setChecked( + self.__parameters['keepPath']) + self.compressCheckBox.setChecked( + self.__parameters['compress']) + if self.__parameters['optimize'] == 0: self.nooptimizeRadioButton.setChecked(True) - elif self.parameters['optimize'] == 1: + elif self.__parameters['optimize'] == 1: self.optimizeRadioButton.setChecked(True) else: self.optimizeDocRadioButton.setChecked(True) # initialize advanced tab self.defaultPathEdit.setText( - os.pathsep.join(self.parameters['defaultPath'])) + os.pathsep.join(self.__parameters['defaultPath'])) self.includePathEdit.setText( - os.pathsep.join(self.parameters['includePath'])) + os.pathsep.join(self.__parameters['includePath'])) self.replacePathsEdit.setText( - os.pathsep.join(self.parameters['replacePaths'])) + os.pathsep.join(self.__parameters['replacePaths'])) self.includeModulesEdit.setText( - ','.join(self.parameters['includeModules'])) + ','.join(self.__parameters['includeModules'])) self.excludeModulesEdit.setText( - ','.join(self.parameters['excludeModules'])) - self.extListFileEdit.setText(self.parameters['extListFile']) + ','.join(self.__parameters['excludeModules'])) + self.extListFilePicker.setText(self.__parameters['extListFile']) # initialize additional files tab - self.fileOrFolderList.addItems(self.parameters['additionalFiles']) + self.fileOrFolderList.addItems(self.__parameters['additionalFiles']) def __initializeDefaults(self): """ Private method to set the default values. - These are needed later on to generate the commandline parameters. + These are needed later on to generate the command line parameters. """ self.defaults = { # general options @@ -243,20 +161,21 @@ if sys.platform == 'win32': self.defaults['baseName'] = 'Win32GUI' # overwrite 'initScript' if version 3 interpreter - if self.project.getProjectLanguage() == 'Python3': + if self.__project.getProjectLanguage() == 'Python3': self.defaults['initScript'] = 'Console3' def generateParameters(self): """ - Public method that generates the commandline parameters. + Public method that generates the command line parameters. It generates a list of strings to be used to set the QProcess arguments for the cxfreeze call and a list containing the non default parameters. The second list can be passed back upon object generation to overwrite the default settings. - @return a tuple of the commandline parameters and non default - parameters (list of strings, dictionary) + @return a tuple of the command line parameters and non default + parameters + @rtype tuple of (list of str, dict) """ parms = {} args = [] @@ -267,162 +186,90 @@ # 2. the commandline options # 2.1 general options if ( - self.parameters['targetDirectory'] != + self.__parameters['targetDirectory'] != self.defaults['targetDirectory'] ): - parms['targetDirectory'] = self.parameters['targetDirectory'] + parms['targetDirectory'] = self.__parameters['targetDirectory'] args.append('--target-dir={0}'.format( - self.parameters['targetDirectory'])) - if self.parameters['targetName'] != self.defaults['targetName']: - parms['targetName'] = self.parameters['targetName'][:] + self.__parameters['targetDirectory'])) + if self.__parameters['targetName'] != self.defaults['targetName']: + parms['targetName'] = self.__parameters['targetName'][:] args.append('--target-name={0}'.format( - self.parameters['targetName'])) - parms['baseName'] = self.parameters['baseName'][:] - if self.parameters['baseName'] != '': - args.append('--base-name={0}'.format(self.parameters['baseName'])) - parms['initScript'] = self.parameters['initScript'][:] - if self.parameters['initScript'] != '': + self.__parameters['targetName'])) + parms['baseName'] = self.__parameters['baseName'][:] + if self.__parameters['baseName'] != '': + args.append( + '--base-name={0}'.format(self.__parameters['baseName'])) + parms['initScript'] = self.__parameters['initScript'][:] + if self.__parameters['initScript'] != '': args.append('--init-script={0}'.format( - self.parameters['initScript'])) - parms['applicationIcon'] = self.parameters['applicationIcon'][:] + self.__parameters['initScript'])) + parms['applicationIcon'] = self.__parameters['applicationIcon'][:] if ( - self.parameters['applicationIcon'] != + self.__parameters['applicationIcon'] != self.defaults['applicationIcon'] ): args.append('--icon={0}'.format( - self.parameters['applicationIcon'])) - parms['script'] = self.parameters['script'][:] - if self.parameters['keepPath'] != self.defaults['keepPath']: - parms['keepPath'] = self.parameters['keepPath'] + self.__parameters['applicationIcon'])) + parms['script'] = self.__parameters['script'][:] + if self.__parameters['keepPath'] != self.defaults['keepPath']: + parms['keepPath'] = self.__parameters['keepPath'] args.append('--no-copy-deps') - if self.parameters['compress'] != self.defaults['compress']: - parms['compress'] = self.parameters['compress'] + if self.__parameters['compress'] != self.defaults['compress']: + parms['compress'] = self.__parameters['compress'] args.append('--compress') - if self.parameters['optimize'] != self.defaults['optimize']: - parms['optimize'] = self.parameters['optimize'] - if self.parameters['optimize'] == 1: + if self.__parameters['optimize'] != self.defaults['optimize']: + parms['optimize'] = self.__parameters['optimize'] + if self.__parameters['optimize'] == 1: args.append('-O') - elif self.parameters['optimize'] == 2: + elif self.__parameters['optimize'] == 2: args.append('-OO') # 2.2 advanced options - if self.parameters['defaultPath'] != self.defaults['defaultPath']: - parms['defaultPath'] = self.parameters['defaultPath'][:] + if self.__parameters['defaultPath'] != self.defaults['defaultPath']: + parms['defaultPath'] = self.__parameters['defaultPath'][:] args.append('--default-path={0}'.format( - os.pathsep.join(self.parameters['defaultPath']))) - if self.parameters['includePath'] != self.defaults['includePath']: - parms['includePath'] = self.parameters['includePath'][:] + os.pathsep.join(self.__parameters['defaultPath']))) + if self.__parameters['includePath'] != self.defaults['includePath']: + parms['includePath'] = self.__parameters['includePath'][:] args.append('--include-path={0}'.format( - os.pathsep.join(self.parameters['includePath']))) - if self.parameters['replacePaths'] != self.defaults['replacePaths']: - parms['replacePaths'] = self.parameters['replacePaths'][:] + os.pathsep.join(self.__parameters['includePath']))) + if self.__parameters['replacePaths'] != self.defaults['replacePaths']: + parms['replacePaths'] = self.__parameters['replacePaths'][:] args.append('--replace-paths={0}'.format( - os.pathsep.join(self.parameters['replacePaths']))) + os.pathsep.join(self.__parameters['replacePaths']))) if ( - self.parameters['includeModules'] != + self.__parameters['includeModules'] != self.defaults['includeModules'] ): - parms['includeModules'] = self.parameters['includeModules'][:] + parms['includeModules'] = self.__parameters['includeModules'][:] args.append('--include-modules={0}'.format( - ','.join(self.parameters['includeModules']))) + ','.join(self.__parameters['includeModules']))) if ( - self.parameters['excludeModules'] != + self.__parameters['excludeModules'] != self.defaults['excludeModules'] ): - parms['excludeModules'] = self.parameters['excludeModules'][:] + parms['excludeModules'] = self.__parameters['excludeModules'][:] args.append('--exclude-modules={0}'.format( - ','.join(self.parameters['excludeModules']))) - if self.parameters['extListFile'] != self.defaults['extListFile']: - parms['extListFile'] = self.parameters['extListFile'] + ','.join(self.__parameters['excludeModules']))) + if self.__parameters['extListFile'] != self.defaults['extListFile']: + parms['extListFile'] = self.__parameters['extListFile'] args.append('--ext-list-file={0}'.format( - self.parameters['extListFile'])) + self.__parameters['extListFile'])) # 2.3 additional files tab - if self.parameters['additionalFiles'] != []: - parms['additionalFiles'] = self.parameters['additionalFiles'][:] + if self.__parameters['additionalFiles'] != []: + parms['additionalFiles'] = self.__parameters['additionalFiles'][:] return (args, parms) - @pyqtSlot() - def on_extListFileButton_clicked(self): - """ - Private slot to select the external list file. - - It displays a file selection dialog to select the external list file, - the list of include modules is written to. - """ - extList = E5FileDialog.getOpenFileName( - self, - self.tr("Select external list file"), - self.extListFileEdit.text(), - "") - - if extList: - # make it relative, if it is in a subdirectory of the project path - lf = Utilities.toNativeSeparators(extList) - lf = self.project.getRelativePath(lf) - self.extListFileEdit.setText(lf) - - @pyqtSlot() - def on_iconFileButton_clicked(self): - """ - Private slot to select an icon. - - It displays a file selection dialog to select an icon to - include into the executable. - """ - iconsI18N = self.tr("Icons") - allFilesI18N = self.tr("All files") - if Utilities.isWindowsPlatform(): - iconFilter = "{0} (*.ico);;{1} (*.*)".format( - iconsI18N, allFilesI18N) - elif Utilities.isMacPlatform(): - iconFilter = "{0} (*.icns *.png);;{1} (*.*)".format( - iconsI18N, allFilesI18N) - else: - iconFilter = "{0} (*.png);;{1} (*.*)".format( - iconsI18N, allFilesI18N) - - iconList = E5FileDialog.getOpenFileName( - self, - self.tr("Select the application icon"), - self.applicationIconEdit.text(), - iconFilter) - - if iconList: - # make it relative, if it is in a subdirectory of the project path - lf = Utilities.toNativeSeparators(iconList) - lf = self.project.getRelativePath(lf) - self.applicationIconEdit.setText(lf) - - @pyqtSlot() - def on_targetDirButton_clicked(self): - """ - Private slot to select the target directory. - - It displays a directory selection dialog to - select the directory the files are written to. - """ - directory = E5FileDialog.getExistingDirectory( - self, - self.tr("Select target directory"), - self.targetDirEdit.text(), - E5FileDialog.Options(E5FileDialog.ShowDirsOnly)) - - if directory: - # make it relative, if it is a subdirectory of the project path - dn = Utilities.toNativeSeparators(directory) - dn = self.project.getRelativePath(dn) - while dn.endswith(os.sep): - dn = dn[:-1] - self.targetDirEdit.setText(dn) - @pyqtSlot(str) def on_cxfreezeExecCombo_currentIndexChanged(self, text): """ Private slot to handle the selection of a cxfreeze executable. - @param text selected cxfreeze executable (string) + @param text selected cxfreeze executable + @type str """ # version specific setup if Utilities.isWindowsPlatform(): @@ -467,7 +314,7 @@ # populate combo boxes if modpath: d = QDir(os.path.join(modpath, 'bases')) - basesList = d.entryList(QDir.Filters(QDir.Files)) + basesList = d.entryList(QDir.Filter.Files) if Utilities.isWindowsPlatform(): # strip the final '.exe' from the bases tmpBasesList = basesList[:] @@ -494,12 +341,14 @@ [os.path.splitext(i)[0] for i in initList]) self.initscriptCombo.setEditText(currentText) + @pyqtSlot(int) def on_fileOrFolderList_currentRowChanged(self, row): """ Private slot to handle the currentRowChanged signal of the fileOrFolderList. - @param row the current row (integer) + @param row the current row + @type int """ self.deleteSelectedButton.setEnabled(row != -1) if row != -1: @@ -511,7 +360,8 @@ Private slot to handle the itemDoubleClicked signal of the fileOrFolderList. - @param itm the selected row (QListWidgetItem) + @param itm the selected row + @type QListWidgetItem """ self.fileOrFolderEdit.setText(itm.text()) row = self.fileOrFolderList.currentRow() @@ -529,16 +379,17 @@ self.fileOrFolderEdit.clear() row = self.fileOrFolderList.currentRow() self.on_fileOrFolderList_currentRowChanged(row) - + @pyqtSlot(str) def on_fileOrFolderEdit_textChanged(self, txt): """ Private slot to handle the textChanged signal of the directory edit. - @param txt the text of the directory edit (string) + @param txt the text of the directory edit + @type str """ self.addFileOrFolderButton.setEnabled(txt != "") - + @pyqtSlot() def on_deleteSelectedButton_clicked(self): """ @@ -549,26 +400,27 @@ del itm row = self.fileOrFolderList.currentRow() self.on_fileOrFolderList_currentRowChanged(row) - + @pyqtSlot() def on_selectFileOrFolderButton_clicked(self): """ Private slot to select files or folders. It displays a file and directory selection dialog to - select the files and directorys which should copied into - the distribution folder.. + select the files and directories which should be copied + into the distribution folder. """ - items = DirFileDialog.getOpenFileNames( - None, - self.tr("Select files and folders")) - + items = EricDirFileDialog.getOpenFileAndDirNames( + self, + self.tr("Select files and folders"), + self.__project.getProjectPath()) + for itm in items: - itm = self.project.getRelativePath(itm) + itm = self.__project.getRelativePath(itm) self.fileOrFolderList.addItem(Utilities.toNativeSeparators(itm)) row = self.fileOrFolderList.currentRow() self.on_fileOrFolderList_currentRowChanged(row) - + def accept(self): """ Public method called by the Ok button. @@ -576,38 +428,41 @@ It saves the values in the parameters dictionary. """ # get data of general tab - self.parameters['targetDirectory'] = self.targetDirEdit.text() - self.parameters['targetName'] = self.targetNameEdit.text() - self.parameters['baseName'] = self.basenameCombo.currentText() - self.parameters['initScript'] = self.initscriptCombo.currentText() - self.parameters['applicationIcon'] = self.applicationIconEdit.text() - self.parameters['script'] = self.cxfreezeExecCombo.currentText() - self.parameters['keepPath'] = self.keeppathCheckBox.isChecked() - self.parameters['compress'] = self.compressCheckBox.isChecked() + self.__parameters['targetDirectory'] = self.__project.getRelativePath( + self.targetDirPicker.text()) + self.__parameters['targetName'] = self.targetNameEdit.text() + self.__parameters['baseName'] = self.basenameCombo.currentText() + self.__parameters['initScript'] = self.initscriptCombo.currentText() + self.__parameters['applicationIcon'] = self.__project.getRelativePath( + self.applicationIconPicker.text()) + self.__parameters['script'] = self.cxfreezeExecCombo.currentText() + self.__parameters['keepPath'] = self.keeppathCheckBox.isChecked() + self.__parameters['compress'] = self.compressCheckBox.isChecked() if self.nooptimizeRadioButton.isChecked(): - self.parameters['optimize'] = 0 + self.__parameters['optimize'] = 0 elif self.optimizeRadioButton.isChecked(): - self.parameters['optimize'] = 1 + self.__parameters['optimize'] = 1 else: - self.parameters['optimize'] = 2 + self.__parameters['optimize'] = 2 # get data of advanced tab - self.parameters['defaultPath'] = self.__splitIt( + self.__parameters['defaultPath'] = self.__splitIt( self.defaultPathEdit.text(), os.pathsep) - self.parameters['includePath'] = self.__splitIt( + self.__parameters['includePath'] = self.__splitIt( self.includePathEdit.text(), os.pathsep) - self.parameters['replacePaths'] = self.__splitIt( + self.__parameters['replacePaths'] = self.__splitIt( self.replacePathsEdit.text(), os.pathsep) - self.parameters['includeModules'] = self.__splitIt( + self.__parameters['includeModules'] = self.__splitIt( self.includeModulesEdit.text(), ',') - self.parameters['excludeModules'] = self.__splitIt( + self.__parameters['excludeModules'] = self.__splitIt( self.excludeModulesEdit.text(), ',') - self.parameters['extListFile'] = self.extListFileEdit.text() + self.__parameters['extListFile'] = self.__project.getRelativePath( + self.extListFilePicker.text()) # get data of the additional files tab additionalFiles = [self.fileOrFolderList.item(x).text() for x in range(self.fileOrFolderList.count())] - self.parameters['additionalFiles'] = additionalFiles + self.__parameters['additionalFiles'] = additionalFiles # call the accept slot of the base class QDialog.accept(self) @@ -616,9 +471,12 @@ """ Private method to split a string observing various conditions. - @param s string to split (string) - @param sep separator string (string) + @param s string to split + @type str + @param sep separator string + @type str @return list of split values + @rtype list of str """ if s == "" or s is None: return []