mostly worked around annoying Qt bug

This commit is contained in:
Brennen Raimer
2019-05-24 18:23:51 -04:00
parent 806941b3de
commit 76d1121206
2 changed files with 46 additions and 45 deletions

View File

@@ -36,7 +36,12 @@ class InstallerWizard(QtWidgets.QWizard):
self.intro.anchorClicked.connect(self._link_clicked) self.intro.anchorClicked.connect(self._link_clicked)
self.license.anchorClicked.connect(self._link_clicked) self.license.anchorClicked.connect(self._link_clicked)
self.selection_menu.itemClicked.connect(self._enforce_dependencies) self.selection_menu.itemClicked.connect(self._enforce_dependencies)
self.install_location.setValidator(Location_Validator(self)) self._location_validator = Location_Validator(self)
try:
self.install_location.inputRejected.connect(self.install_location.clear)
except AttributeError:
pass #inputRejected signal added in Qt 5.12, I have 5.9
self.install_location.setValidator(self._location_validator)
self.location_page.registerField("Location*", self.install_location) self.location_page.registerField("Location*", self.install_location)
self.browse_button.clicked.connect(self._select_location) self.browse_button.clicked.connect(self._select_location)
self.selection_menu.itemClicked.connect(self._open_homepage) self.selection_menu.itemClicked.connect(self._open_homepage)

View File

@@ -3,21 +3,24 @@ import psutil
import os import os
import platform import platform
from pathlib import Path from pathlib import Path
from threading import Lock, Condition, Event
class Location_Validator(QtGui.QValidator): class Location_Validator(QtGui.QValidator):
_disposition = QtGui.QValidator.Intermediate
_pos = 0
_location = ""
_ntfs_location_selected = False
_previous_location = None
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
"""for some reason on my Linux system, selecting a directory validates the same location repatedly, """for some reason on my Linux system, selecting a directory validates the same location repatedly,
once for each subdir of the location. The only way to keep it from repeatedly validating and potentially once for each subdir of the location. The only way to keep it from repeatedly validating and potentially
opening a warning window for each subdirectory in the location path was to track this and return the same opening a warning window for each subdirectory in the location path was to track this and return the same
value that was returned the last time it was validated.""" value that was returned the last time it was validated."""
self._previous = {"location":"", "disposition":(QtGui.QValidator.Intermediate, "", 0,)}
self._ntfs_location_selected = False
@property @property
def ntfs_location_selected(self): def ntfs_location_selected(self):
return self._ntfs_location_selected return Location_Validator._ntfs_location_selected
def _onNTFSDrive(self, location): def _onNTFSDrive(self, location):
"""Tests if location is a path on an NTFS-formatted drive. Returns True if path is on NTFS-formatted drive. """Tests if location is a path on an NTFS-formatted drive. Returns True if path is on NTFS-formatted drive.
@@ -32,11 +35,10 @@ class Location_Validator(QtGui.QValidator):
#elif platform.system() == "Linux": #elif platform.system() == "Linux":
# pass # pass
else: else:
self._ntfs_location_selected = False if QtWidgets.QApplication.instance().activeModalWidget():
if QtWidgets.QMessageBox.question(self.parent(), "", f"{Path(location)} is not an NTFS-formatted volume. Tools which require a NTFS filesystem to function will not be available. Continue anyway?") in (QtWidgets.QMessageBox.No, 0):
return False return False
else: self._ntfs_location_selected = False
return True return not QtWidgets.QMessageBox.question(self.parent(), "", f"{Path(location)} is not an NTFS-formatted volume. Tools which require a NTFS filesystem to function will not be available. Continue anyway?") in (QtWidgets.QMessageBox.No, 0)
def validate(self, input_, pos): def validate(self, input_, pos):
"""Called by InstallerWizard via QtWidget.QLineEdit.TextChanged signal to validate installation location input of user """Called by InstallerWizard via QtWidget.QLineEdit.TextChanged signal to validate installation location input of user
@@ -46,48 +48,42 @@ class Location_Validator(QtGui.QValidator):
pos {int} -- The current location of the cursor in the QLineEdit widget pos {int} -- The current location of the cursor in the QLineEdit widget
""" """
if not input_.strip(): if not input_.strip():
self._previous["location"] = Path(input_.strip()) _previous_location = input_
self._previous["disposition"] = (QtGui.QValidator.Intermediate, input_, pos,) return (QtGui.QValidator.Intermediate, input_, pos)
return (QtGui.QValidator.Intermediate, input_, pos,)
elif Path(input_.strip()) == self._previous["location"]: elif input_.strip() == self._previous_location:
#I really hate that I have to do this return (self._disposition, self._previous_location, self._pos)
return self._previous["disposition"]
elif input_.strip().endswith(r":"): elif input_.strip().endswith(r":"):
self._previous["location"] = Path(input_.strip()) #if nothing entered or location ends with : e.g. C: which will cause _onNTFSDrive to trigger unwanted messages
self._previous["disposition"] = (QtGui.QValidator.Intermediate, input_, pos,) self._location = input_
# bugfix. _onNTFSDrive triggers when typing the : in a drive name e.g. C:\ self._disposition = QtGui.QValidator.Intermediate
return (QtGui.QValidator.Intermediate, input_, pos,)
else: else:
# because this class method is invoked via signal, it cannot handle python exceptions expanded_input = os.path.expandvars(input_.strip()) # expand any environment variables in input
# testing writability in Python is difficult and involves actually writing a temporary file location = QtCore.QFileInfo(expanded_input)
# to the directory, however, if that fails and raises an exception, it happens in Qt/C++ world
# and the python interpreter can't catch it, the program just crashes without any output,
# therefore, we will use Qt to do checking
input_ = os.path.expandvars(input_.strip()) # expand any environment variables in input
location = QtCore.QFileInfo(input_)
if location.exists() and location.isDir(): if location.exists() and location.isDir():
if input_ and not self._onNTFSDrive(input_): if not self._onNTFSDrive(expanded_input):
self._previous["location"] = Path(input_)
self._previous["disposition"] = (QtGui.QValidator.Intermediate, "", 0)
# clear the location, reset cursor, but allow continued edits # clear the location, reset cursor, but allow continued edits
return (QtGui.QValidator.Intermediate, "", 0) self._location = ""
self._disposition = QtGui.QValidator.Intermediate
test_file = QtCore.QTemporaryFile(f"{Path(input_)/'testXXXXXX.tmp'}")
if test_file.open(QtCore.QIODevice.ReadWrite):
test_file.close()
test_file.remove()
self._previous["location"] = Path(input_)
self._previous["disposition"] = (QtGui.QValidator.Acceptable, input_, pos,)
return (QtGui.QValidator.Acceptable, input_, pos,)
else: else:
self._previous["location"] = Path(input_) test_file = QtCore.QTemporaryFile(f"{Path(expanded_input)/'testXXXXXX.tmp'}")
self._previous["disposition"] = (QtGui.QValidator.Intermediate, input_, pos,)
return (QtGui.QValidator.Intermediate, input_, pos,)
if test_file.open(QtCore.QIODevice.ReadWrite):
test_file.close()
test_file.remove()
self._location = input_
self._disposition = QtGui.QValidator.Acceptable
else:
self._location = input_
self._disposition = QtGui.QValidator.Intermediate
else: else:
self._previous["location"] = Path(input_)
self._previous["disposition"] = (QtGui.QValidator.Intermediate, input_, pos,)
# I wanted to return invalid, but that would prevent input of anything not instantly acceptable # I wanted to return invalid, but that would prevent input of anything not instantly acceptable
# or editing something acceptable to something else acceptable, passing through an invalid on the way # or editing something acceptable to something else acceptable, passing through an invalid on the way
return (QtGui.QValidator.Intermediate, input_, pos,) self._location = input_
self._disposition = QtGui.QValidator.Intermediate
self._pos = pos
self._previous_location = self._location
return (self._disposition, self._location, self._pos,)