Skip to content

Commit

Permalink
Merge pull request #898 from matty0ung/usability
Browse files Browse the repository at this point in the history
UI fixes
  • Loading branch information
matty0ung authored Nov 27, 2024
2 parents 813f951 + 37757b3 commit 04a4011
Show file tree
Hide file tree
Showing 31 changed files with 2,499 additions and 1,372 deletions.
23 changes: 19 additions & 4 deletions bt
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,18 @@
#
topDir=$(dirname $0)

#
# It's worth knowing exactly which instance of Python we're running as, eg, on MSYS2 on Windows there can be multiple
# versions installed
#
export exe_python=$(which python3)
echo "${exe_python} --version"
${exe_python} --version

# This first Python script, run using the system-wide Python interpreter, will install a few bare necessities and
# (re)create the Python venv
echo "python3 ${topDir}/scripts/btInit.py"
python3 ${topDir}/scripts/btInit.py
echo "${exe_python} ${topDir}/scripts/btInit.py"
${exe_python} ${topDir}/scripts/btInit.py
if [ $? -ne 0 ]; then
exit $?
fi
Expand All @@ -137,6 +145,13 @@ pwd
echo "source ${topDir}/.venv/bin/activate"
source ${topDir}/.venv/bin/activate

#
# And let's reassure ourselves that, with the changed paths of the venve, we're still running the same version of Python
#
export exe_python=$(which python3)
echo "${exe_python} --version"
${exe_python} --version

#
# Uncomment the following to show exported environment variables for debugging.
#
Expand All @@ -149,5 +164,5 @@ source ${topDir}/.venv/bin/activate
#env

# Run the main script, passing in all the command line arguments we received
echo "python3 ${topDir}/scripts/buildTool.py $@"
python3 ${topDir}/scripts/buildTool.py $@
echo "${exe_python} ${topDir}/scripts/buildTool.py $@"
${exe_python} ${topDir}/scripts/buildTool.py $@
5 changes: 5 additions & 0 deletions packaging/linux/control.in
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ Architecture: amd64
# Note too that qt6-translations-l10n is not required in terms of providing any functions that we call, but it does
# ensure the Qt framework's own translation files are installed.
#
# Now that we are on Qt6, we need to explicitly specify as a libqt6svg6 dependency, otherwise .svg files (which we
# use a lot in icons) will not display (see
# https://stackoverflow.com/questions/76047551/icons-shown-in-qt5-not-showing-in-qt6)
#
Depends: \
libc6 (>= 2.35 ), \
libc6-dev (>= 2.35 ), \
Expand All @@ -147,6 +151,7 @@ Depends: \
libqt6network6 | libqt6network6t64 (>= 6.2.4 ), \
libqt6printsupport6 | libqt6printsupport6t64 (>= 6.2.4 ), \
libqt6sql6 | libqt6sql6t64 (>= 6.2.4 ), \
libqt6svg6 (>= 6.2.4 ), \
libqt6widgets6 | libqt6widgets6t64 (>= 6.2.4 ), \
libxalan-c112 | libxalan-c112t64 (>= 1.12 ), \
libxerces-c3.2 | libxerces-c3.2t64 (>= 3.2.3 ), \
Expand Down
1 change: 1 addition & 0 deletions packaging/linux/rpm.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Requires : \
libQt6Network6 >= 6.2.4 , \
libQt6PrintSupport6 >= 6.2.4 , \
libQt6Sql6 >= 6.2.4 , \
libqt6svg6 >= 6.2.4 , \
libQt6Widgets6 >= 6.2.4 , \
libxalan-c112 >= 1.12 , \
libxerces-c-3_2 >= 3.2.3 , \
Expand Down
46 changes: 38 additions & 8 deletions scripts/btInit.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,25 @@
'--overwrite', '*pip*',
os.environ['MINGW_PACKAGE_PREFIX'] + '-python-pip'])
)
# See comment in scripts/buildTool.py about why we have to run pip via Python rather than just invoking pip
# directly eg via `shutil.which('pip3')`.
log.info('python -m pip install setuptools')
btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'pip', 'install', 'setuptools']))
#
# Similarly, in the past, we were able to install setuptools as follows:
#
# # See comment in scripts/buildTool.py about why we have to run pip via Python rather than just invoking pip
# # directly eg via `shutil.which('pip3')`.
# log.info('python -m pip install setuptools')
# btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'pip', 'install', 'setuptools']))
#
# But, as of 2024-11, this gives an error "No module named pip.__main__; 'pip' is a package and cannot be directly
# executed". So now we install via pacman instead.
#
log.info('Install setuptools (' + os.environ['MINGW_PACKAGE_PREFIX'] + '-python-setuptools) via pacman')
btUtils.abortOnRunFail(
subprocess.run(['pacman', '-S',
'--noconfirm',
# '--overwrite', '*python*',
# '--overwrite', '*pip*',
os.environ['MINGW_PACKAGE_PREFIX'] + '-python-setuptools'])
)
case 'Darwin':
# Assuming it was Homebrew that installed Python, then, according to https://docs.brew.sh/Homebrew-and-Python,
# it bundles various packages, including pip. Since Python version 3.12, Homebrew marks itself as package manager
Expand All @@ -127,12 +142,27 @@
log.critical('Unrecognised platform: ' + platform.system())
exit(1)

exe_python = shutil.which('python3')
log.info('sys.version: ' + sys.version + '; exe_python: ' + exe_python + '; ' + sys.executable)

#
# At this point we should have enough installed to set up a virtual environment. In principle, it doesn't matter if the
# virtual environment already exists, as we are only using it to run the scripts/buildTool.py script. In practice, life
# is a lot easier if we always start with a new virtual environment. Partly this is because it makes debugging the
# scripts easier. But more importantly, if there are old versions of Python sitting around in a previously-used venv,
# then some the paths won't get set up correctly, and we won't be able to find modules we install in the venv. There
# will be multiple site-packages directories (one for each version of Python in the venv) but none of them will be in
# the search path for packages.
#
# Fortunately, venv can clear any existing environment for us with the '--clear' parameter
#
# At this point we should have enough installed to set up a virtual environment. (It doesn't matter if the virtual
# environment already exists. We are only using it to run the scripts/buildTool.py script.)
# Once running inside the virtual environment, any packages we need there can be installed directly in the venv with
# Python and Pip.
#
dir_venv = btUtils.getBaseDir().joinpath('.venv')
log.info('Create Python virtual environment in ' + dir_venv.as_posix())
btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'venv', dir_venv.as_posix()]))
log.info('Create new Python virtual environment in ' + dir_venv.as_posix())
btUtils.abortOnRunFail(
subprocess.run([sys.executable, '-m', 'venv', '--clear', dir_venv.as_posix()])
)

# Control now returns to the bt bash script in the parent directory
51 changes: 40 additions & 11 deletions scripts/buildTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
log = btUtils.getLogger()

exe_python = shutil.which('python3')
log.info('sys.version: ' + sys.version + '; exe_python: ' + exe_python + '; ' + sys.executable)

#-----------------------------------------------------------------------------------------------------------------------
# Welcome banner and environment info
Expand Down Expand Up @@ -96,12 +97,29 @@

log.info('Found pip at: ' + exe_pip)

#
# Of course, when you run the pip in the venv, it might complain that it is not up-to-date. So we should ensure that
# first. Note that it is Python we must run to upgrade pip, as pip cannot upgrade itself. (Pip will happily _try_ to
# upgrade itself, but then, on Windows at least, will get stuck when it tries to remove the old version of itself
# because "process cannot access the file because it is being used by another process".)
#
# You might think we could use sys.executable instead of exe_python here. However, on Windows at least, that gives the
# wrong python executable: the "system" one rather than the venv one.
#
log.info('Running ' + exe_python + '-m pip install --upgrade pip')
btUtils.abortOnRunFail(subprocess.run([exe_python, '-m', 'pip', 'install', '--upgrade', 'pip']))

#
# Per https://docs.python.org/3/library/sys.html#sys.path, this is the search path for Python modules, which is useful
# for debugging import problems. Provided that we started with a clean venv (so there is only one version of Python
# installed in it), then the search path for packages should include the directory
# '/some/path/to/.venv/lib/pythonX.yy/site-packages' (where 'X.yy' is the Python version number (eg 3.11, 3.12, etc).
# If there is more than one version of Python in the venv, then none of these site-packages directories will be in the
# path. (We could, in principle, add it manually, but it's a bit fiddly and not necessary since we don't use the venv
# for anything other than running this script.)
#
log.info('Initial module search paths:\n ' + '\n '.join(sys.path))

#
# Mostly, from here on out we'd be fine to invoke pip directly, eg via:
#
Expand All @@ -113,7 +131,8 @@
#
# subprocess.check_call([sys.executable, "-m", "pip", "install", package])
#
# Where package is whatever package you want to install. So that is what we do.
# Where package is whatever package you want to install. However, note comments above that we need exe_python rather
# than sys.executable.
#

#
Expand All @@ -122,18 +141,19 @@
#
# On some platforms, we also need to install setuptools to be able to access packaging.version. (NB: On MacOS,
# setuptools is now installed by default by Homebrew when it installs Python, so we'd get an error if we try to install
# it via pip here.)
# it via pip here. On Windows in MSYS2, packaging and setuptools need to be installed via pacman.)
#
log.info('pip install packaging')
btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'pip', 'install', 'packaging']))
btUtils.abortOnRunFail(subprocess.run([exe_python, '-m', 'pip', 'install', 'packaging']))
from packaging import version
log.info('pip install setuptools')
btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'pip', 'install', 'setuptools']))
btUtils.abortOnRunFail(subprocess.run([exe_python, '-m', 'pip', 'install', 'setuptools']))
import packaging.version

# The requests library (see https://pypi.org/project/requests/) is used for downloading files in a more Pythonic way
# than invoking wget through the shell.
log.info('pip install requests')
btUtils.abortOnRunFail(subprocess.run([sys.executable, '-m', 'pip', 'install', 'requests']))
btUtils.abortOnRunFail(subprocess.run([exe_python, '-m', 'pip', 'install', 'requests']))
import requests

#
Expand Down Expand Up @@ -468,7 +488,6 @@ def installDependencies():
'build-essential',
'cmake',
'coreutils',
'debhelper',
'git',
#
# On Ubuntu 22.04, installing the packages for the Qt GUI module, does not automatically install all its
Expand All @@ -488,7 +507,6 @@ def installDependencies():
'libssl-dev', # For OpenSSL headers
'libxalan-c-dev',
'libxerces-c-dev',
'lintian',
'meson',
'ninja-build',
'pandoc',
Expand All @@ -503,8 +521,13 @@ def installDependencies():
qt6svgDevPackage,
'qttools5-dev-tools', # For Qt5 version of lupdate, per comment above
'qt6-tools-dev-tools',
'rpm',
'rpmlint'
#
# The following are needed to build the install packages (rather than just install locally)
#
'debhelper', # Needed to build .deb packages for Debian/Ubuntu
'lintian' , # Needed to validate .deb packages
'rpm' , # Needed to build RPMs
'rpmlint' # Needed to validate RPMs
]
)
)
Expand Down Expand Up @@ -785,7 +808,6 @@ def installDependencies():
# MINGW64
terminalVersion = unameResult.split(sep='_', maxsplit=1)[0]


if (terminalVersion != 'MINGW64'):
# In the past, we built only 32-bit packages (i686 architecture) on Windows because of problems getting
# 64-bit versions of NSIS plugins to work. However, we now invoke NSIS without plugins, so the 64-bit build
Expand All @@ -798,7 +820,7 @@ def installDependencies():

# Ensure pip is up-to-date. This is what the error message tells you to run if it's not!
log.info('Ensuring Python pip is up-to-date')
btUtils.abortOnRunFail(subprocess.run(['python3.exe', '-m', 'pip', 'install', '--upgrade', 'pip']))
btUtils.abortOnRunFail(subprocess.run([exe_python, '-m', 'pip', 'install', '--upgrade', 'pip']))

#
# When we update packages below, we get "error: failed to commit transaction (conflicting files)" errors for a
Expand Down Expand Up @@ -882,6 +904,7 @@ def installDependencies():
'mingw-w64-' + arch + '-toolchain',
'mingw-w64-' + arch + '-xalan-c',
'mingw-w64-' + arch + '-xerces-c',
# 'mingw-w64-' + arch + '-7zip', # To unzip NSIS plugins
'mingw-w64-' + arch + '-angleproject', # See comment above
'mingw-w64-' + arch + '-ntldd', # Dependency tool useful for running manually -- see below
]
Expand Down Expand Up @@ -2320,6 +2343,12 @@ def doPackage():
#'Qt6PrintSupport',
#'Qt6Sql' ,
#'Qt6Widgets' ,
#
# Following is not handled by windeployqt. The application will install and run without it, but it just
# won't show any icons.
'Qt6Svg' , # Needed to display .svg icons
#
#
'libb2' , # BLAKE hash functions -- https://en.wikipedia.org/wiki/BLAKE_(hash_function)
'libbrotlicommon' , # Brotli compression -- see https://en.wikipedia.org/wiki/Brotli
'libbrotlidec' , # Brotli compression
Expand Down
15 changes: 11 additions & 4 deletions src/model/NamedEntity.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,8 @@ class NamedEntity : public QObject {
* \brief Passes the meta property that has changed about this object.
*
* NOTE: When subclassing, be \em extra careful not to create a member function with the same signature.
* Otherwise, everything will silently break.
* Otherwise, everything will silently break. If this were a virtual member function, we could add the final
* keyword here to enforce this, but it isn't so we can't.
*/
void changed(QMetaProperty, QVariant value = QVariant()) const;
void changedFolder(QString);
Expand Down Expand Up @@ -607,9 +608,15 @@ class NamedEntity : public QObject {
T & memberVariable,
T const newValue) {
if (newValue == memberVariable) {
qDebug() <<
Q_FUNC_INFO << this->metaObject()->className() << "#" << this->key() << ": ignoring call to setter for" <<
propertyName << "as value (" << newValue << ") not changing";
//
// Don't bother with this log whilst we're still in the constructor, otherwise we'll get lots of messages about
// NULL and 0 not changing.
//
if (this->m_propagationAndSignalsEnabled) {
qDebug() <<
Q_FUNC_INFO << this->metaObject()->className() << "#" << this->key() << ": ignoring call to setter for" <<
propertyName << "as value (" << newValue << ") not changing";
}
return true;
}
return false;
Expand Down
6 changes: 6 additions & 0 deletions src/widgets/BtBoolComboBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ void BtBoolComboBox::init(char const * const editorName ,
this->addItem(*this->pimpl->m_setDisplay , trueValue);

this->pimpl->m_initialised = true;

//
// By default, a QComboBox "will adjust to its contents the first time it is shown", which means that, on some
// platforms at least, if it somehow gets shown before it is populated, then it will be far too narrow.
//
this->QComboBox::setSizeAdjustPolicy(QComboBox::AdjustToContents);
return;
}

Expand Down
6 changes: 6 additions & 0 deletions src/widgets/BtComboBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ void BtComboBox::init(char const * const editorName ,
this->autoSetFromControlledField();
}

//
// By default, a QComboBox "will adjust to its contents the first time it is shown", which means that, on some
// platforms at least, if it somehow gets shown before it is populated, then it will be far too narrow.
//
this->QComboBox::setSizeAdjustPolicy(QComboBox::AdjustToContents);

return;
}

Expand Down
Loading

0 comments on commit 04a4011

Please sign in to comment.