0.1.4 kwallet optimisation related fix, DnD files into convs, visual fixes

This commit is contained in:
Blue 2020-04-14 19:30:33 +03:00
parent 21c7d65027
commit cb44b12a7e
18 changed files with 162 additions and 47 deletions

View File

@ -1,6 +1,6 @@
# Changelog # Changelog
## Squawk 0.1.4 (UNRELEASED) ## Squawk 0.1.4 (Apr 14, 2020)
### New features ### New features
- message line now is in the same window with roster (new window dialog is still able to opened on context menu) - message line now is in the same window with roster (new window dialog is still able to opened on context menu)
- several new ways to manage your account password: - several new ways to manage your account password:
@ -8,6 +8,7 @@
- store it in config jammed (local hashing with the constant seed, not secure at all but might look like it is) - store it in config jammed (local hashing with the constant seed, not secure at all but might look like it is)
- ask the account password on each program launch - ask the account password on each program launch
- store it in KWallet which is dynamically loaded - store it in KWallet which is dynamically loaded
- dragging into conversation now attach files
### Bug fixes ### Bug fixes
- never updating MUC avatars now get updated - never updating MUC avatars now get updated
@ -15,6 +16,7 @@
- statuses now behave better: they wrap if they don't fit, you can select them, you can follow links from there - statuses now behave better: they wrap if they don't fit, you can select them, you can follow links from there
- messages and statuses don't loose content if you use < ore > symbols - messages and statuses don't loose content if you use < ore > symbols
- now avatars of those who are not in the MUC right now but was also display next to the message - now avatars of those who are not in the MUC right now but was also display next to the message
- fix crash on attempt to attach the same file for the second time
## Squawk 0.1.3 (Mar 31, 2020) ## Squawk 0.1.3 (Mar 31, 2020)

View File

@ -109,9 +109,9 @@ add_dependencies(${CMAKE_PROJECT_NAME} translations)
# Install the executable # Install the executable
install(TARGETS squawk DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS squawk DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/squawk/l10n) install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/squawk/l10n)
install(FILES squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.svg DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps)
install(FILES squawk48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME squawk.png) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk48.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/48x48/apps RENAME squawk.png)
install(FILES squawk64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME squawk.png) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk64.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps RENAME squawk.png)
install(FILES squawk128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME squawk.png) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk128.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/128x128/apps RENAME squawk.png)
install(FILES squawk256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME squawk.png) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk256.png DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/256x256/apps RENAME squawk.png)
install(FILES squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/squawk.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)

View File

@ -4,7 +4,7 @@
[![AUR version](https://img.shields.io/aur/version/squawk?style=flat-square)](https://aur.archlinux.org/packages/squawk/) [![AUR version](https://img.shields.io/aur/version/squawk?style=flat-square)](https://aur.archlinux.org/packages/squawk/)
[![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me) [![Liberapay patrons](https://img.shields.io/liberapay/patrons/macaw.me?logo=liberapay&style=flat-square)](https://liberapay.com/macaw.me)
![Squawk screenshot](https://macaw.me/images/squawk/0.1.3.png) ![Squawk screenshot](https://macaw.me/images/squawk/0.1.4.png)
### Prerequisites ### Prerequisites
@ -13,6 +13,7 @@
- lmdb - lmdb
- CMake 3.0 or higher - CMake 3.0 or higher
- qxmpp 1.1.0 or higher - qxmpp 1.1.0 or higher
- kwallet (optional)
### Getting ### Getting

View File

@ -41,11 +41,6 @@ Core::PSE::KWallet::KWallet():
if (sState == initial) { if (sState == initial) {
lib.load(); lib.load();
if (!lib.isLoaded()) { //fallback from the build directory
lib.setFileName("./core/passwordStorageEngines/libkwalletWrapper.so");
lib.load();
}
if (lib.isLoaded()) { if (lib.isLoaded()) {
openWallet = (OpenWallet) lib.resolve("openWallet"); openWallet = (OpenWallet) lib.resolve("openWallet");
networkWallet = (NetworkWallet) lib.resolve("networkWallet"); networkWallet = (NetworkWallet) lib.resolve("networkWallet");
@ -81,7 +76,9 @@ void Core::PSE::KWallet::open()
{ {
if (sState == success) { if (sState == success) {
if (cState == disconnected) { if (cState == disconnected) {
wallet = openWallet(networkWallet(), 0, ::KWallet::Wallet::Asynchronous); QString name;
networkWallet(name);
wallet = openWallet(name, 0, ::KWallet::Wallet::Asynchronous);
if (wallet) { if (wallet) {
cState = connecting; cState = connecting;
connect(wallet, SIGNAL(walletOpened(bool)), this, SLOT(onWalletOpened(bool))); connect(wallet, SIGNAL(walletOpened(bool)), this, SLOT(onWalletOpened(bool)));
@ -89,6 +86,7 @@ void Core::PSE::KWallet::open()
} else { } else {
everError = true; everError = true;
emit opened(false); emit opened(false);
rejectPending();
} }
} }
} }

View File

@ -79,7 +79,7 @@ private:
private: private:
typedef ::KWallet::Wallet* (*OpenWallet)(const QString &, WId, ::KWallet::Wallet::OpenType); typedef ::KWallet::Wallet* (*OpenWallet)(const QString &, WId, ::KWallet::Wallet::OpenType);
typedef const char* (*NetworkWallet)(); typedef void (*NetworkWallet)(QString&);
typedef void (*DeleteWallet)(::KWallet::Wallet*); typedef void (*DeleteWallet)(::KWallet::Wallet*);
typedef int (*ReadPassword)(::KWallet::Wallet*, const QString&, QString&); typedef int (*ReadPassword)(::KWallet::Wallet*, const QString&, QString&);
typedef int (*WritePassword)(::KWallet::Wallet*, const QString&, const QString&); typedef int (*WritePassword)(::KWallet::Wallet*, const QString&, const QString&);

View File

@ -8,8 +8,8 @@ extern "C" void deleteWallet(KWallet::Wallet* w) {
w->deleteLater(); w->deleteLater();
} }
extern "C" const char* networkWallet() { extern "C" void networkWallet(QString& str) {
return KWallet::Wallet::NetworkWallet().toStdString().c_str(); str = KWallet::Wallet::NetworkWallet();
} }
extern "C" int readPassword(KWallet::Wallet* w, const QString &key, QString &value) { extern "C" int readPassword(KWallet::Wallet* w, const QString &key, QString &value) {

View File

@ -42,7 +42,7 @@ int main(int argc, char *argv[])
QApplication::setApplicationName("squawk"); QApplication::setApplicationName("squawk");
QApplication::setApplicationDisplayName("Squawk"); QApplication::setApplicationDisplayName("Squawk");
QApplication::setApplicationVersion("0.1.3"); QApplication::setApplicationVersion("0.1.4");
QTranslator qtTranslator; QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));

View File

@ -29,7 +29,7 @@ namespace W
template <typename data_type, typename comparator = std::less<data_type>> template <typename data_type, typename comparator = std::less<data_type>>
class Order class Order
{ {
public:
class Duplicates: class Duplicates:
public Utils::Exception public Utils::Exception
{ {

View File

@ -1,6 +1,6 @@
# Maintainer: Yury Gubich <blue@macaw.me> # Maintainer: Yury Gubich <blue@macaw.me>
pkgname=squawk pkgname=squawk
pkgver=0.1.3 pkgver=0.1.4
pkgrel=1 pkgrel=1
pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)" pkgdesc="An XMPP desktop messenger, written on pure c++ (qt)"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
@ -8,8 +8,10 @@ url="https://git.macaw.me/blue/squawk"
license=('GPL3') license=('GPL3')
depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdb' 'qxmpp>=1.1.0') depends=('hicolor-icon-theme' 'desktop-file-utils' 'lmdb' 'qxmpp>=1.1.0')
makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools') makedepends=('cmake>=3.3' 'imagemagick' 'qt5-tools')
optdepends=('kwallet: secure password storage (requires rebuild)')
source=("$pkgname-$pkgver.tar.gz") source=("$pkgname-$pkgver.tar.gz")
sha256sums=('adb172bb7d5b81bd9b83b192481a79ac985877e81604f401b3f2a08613b359bc') sha256sums=('3b290381eaf15a35d24a58a36c29eee375a4ea77b606124982a063d7ecf98870')
build() { build() {
cd "$srcdir/squawk" cd "$srcdir/squawk"
cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release cmake . -D CMAKE_INSTALL_PREFIX=/usr -D CMAKE_BUILD_TYPE=Release

View File

@ -33,9 +33,9 @@ static const QRegularExpression urlReg("(?<!<a\\shref=['\"])(?<!<img\\ssrc=['\"]
"(?:https?|ftp):\\/\\/" "(?:https?|ftp):\\/\\/"
"\\w+" "\\w+"
"(?:" "(?:"
"[\\w\\.\\/\\:\\;\\?\\&\\=\\@\\%\\#\\+\\-]?" "[\\w\\.\\,\\/\\:\\;\\?\\&\\=\\@\\%\\#\\+\\-]?"
"(?:" "(?:"
"\\([\\w\\.\\/\\:\\;\\?\\&\\=\\@\\%\\#\\+\\-]+\\)" "\\([\\w\\.\\,\\/\\:\\;\\?\\&\\=\\@\\%\\#\\+\\-]+\\)"
")?" ")?"
")*" ")*"
")"); ")");

View File

@ -119,6 +119,10 @@ p, li { white-space: pre-wrap; }
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source> &lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Drop files here to attach them to your message</source>
<translation>Бросьте файлы сюда для того что бы прикрепить их к сообщению</translation>
</message>
</context> </context>
<context> <context>
<name>Global</name> <name>Global</name>
@ -637,6 +641,10 @@ to be displayed as %1</source>
<source>Password for account %1</source> <source>Password for account %1</source>
<translation>Пароль для учетной записи %1</translation> <translation>Пароль для учетной записи %1</translation>
</message> </message>
<message>
<source>Please select a contact to start chatting</source>
<translation>Выберите контакт или группу что бы начать переписку</translation>
</message>
</context> </context>
<context> <context>
<name>VCard</name> <name>VCard</name>

View File

@ -34,7 +34,8 @@ Squawk::Squawk(QWidget *parent) :
requestedAccountsForPasswords(), requestedAccountsForPasswords(),
prompt(0), prompt(0),
currentConversation(0), currentConversation(0),
restoreSelection() restoreSelection(),
needToRestore(false)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->roster->setModel(&rosterModel); m_ui->roster->setModel(&rosterModel);
@ -1139,6 +1140,7 @@ void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIn
if (id != 0) { if (id != 0) {
delete id; delete id;
} }
needToRestore = true;
restoreSelection = previous; restoreSelection = previous;
return; return;
} }
@ -1204,5 +1206,8 @@ void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIn
void Squawk::onContextAboutToHide() void Squawk::onContextAboutToHide()
{ {
if (needToRestore) {
needToRestore = false;
m_ui->roster->selectionModel()->setCurrentIndex(restoreSelection, QItemSelectionModel::ClearAndSelect); m_ui->roster->selectionModel()->setCurrentIndex(restoreSelection, QItemSelectionModel::ClearAndSelect);
}
} }

View File

@ -126,6 +126,7 @@ private:
QInputDialog* prompt; QInputDialog* prompt;
Conversation* currentConversation; Conversation* currentConversation;
QModelIndex restoreSelection; QModelIndex restoreSelection;
bool needToRestore;
protected: protected:
void closeEvent(QCloseEvent * event) override; void closeEvent(QCloseEvent * event) override;

View File

@ -129,8 +129,18 @@
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>26</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text"> <property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:26pt;&quot;&gt;Please select a contact to start chatting&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>Please select a contact to start chatting</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>

View File

@ -44,6 +44,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, const QString pJid, c
statusIcon(0), statusIcon(0),
statusLabel(0), statusLabel(0),
filesLayout(0), filesLayout(0),
overlay(new QWidget()),
filesToAttach(), filesToAttach(),
scroll(down), scroll(down),
manualSliderChange(false), manualSliderChange(false),
@ -92,15 +93,26 @@ Conversation::Conversation(bool muc, Models::Account* acc, const QString pJid, c
line->setMyAvatarPath(acc->getAvatarPath()); line->setMyAvatarPath(acc->getAvatarPath());
line->setMyName(acc->getName()); line->setMyName(acc->getName());
QFont nf = m_ui->nameLabel->font(); QGridLayout* gr = static_cast<QGridLayout*>(layout());
nf.setBold(true); QLabel* progressLabel = new QLabel(tr("Drop files here to attach them to your message"));
nf.setPointSize(nf.pointSize() + 2); gr->addWidget(overlay, 0, 0, 2, 1);
m_ui->nameLabel->setFont(nf); QVBoxLayout* nl = new QVBoxLayout();
QGraphicsOpacityEffect* opacity = new QGraphicsOpacityEffect();
QFont sf = statusLabel->font(); opacity->setOpacity(0.8);
sf.setItalic(true); overlay->setLayout(nl);
sf.setPointSize(sf.pointSize() - 2); overlay->setBackgroundRole(QPalette::Base);
statusLabel->setFont(sf); overlay->setAutoFillBackground(true);
overlay->setGraphicsEffect(opacity);
progressLabel->setAlignment(Qt::AlignCenter);
QFont pf = progressLabel->font();
pf.setBold(true);
pf.setPointSize(26);
progressLabel->setWordWrap(true);
progressLabel->setFont(pf);
nl->addStretch();
nl->addWidget(progressLabel);
nl->addStretch();
overlay->hide();
applyVisualEffects(); applyVisualEffects();
} }
@ -362,11 +374,17 @@ void Conversation::addAttachedFile(const QString& path)
Badge* badge = new Badge(path, info.fileName(), QIcon::fromTheme(type.iconName())); Badge* badge = new Badge(path, info.fileName(), QIcon::fromTheme(type.iconName()));
connect(badge, &Badge::close, this, &Conversation::onBadgeClose); connect(badge, &Badge::close, this, &Conversation::onBadgeClose);
filesToAttach.push_back(badge); //TODO neet to check if there are any duplicated ids try {
filesToAttach.push_back(badge);
filesLayout->addWidget(badge); filesLayout->addWidget(badge);
if (filesLayout->count() == 1) { if (filesLayout->count() == 1) {
filesLayout->setContentsMargins(3, 3, 3, 3); filesLayout->setContentsMargins(3, 3, 3, 3);
} }
} catch (const W::Order<Badge*, Badge::Comparator>::Duplicates& e) {
delete badge;
} catch (...) {
throw;
}
} }
void Conversation::removeAttachedFile(Badge* badge) void Conversation::removeAttachedFile(Badge* badge)
@ -421,6 +439,53 @@ void Conversation::setFeedFrames(bool top, bool right, bool bottom, bool left)
static_cast<DropShadowEffect*>(m_ui->scrollArea->graphicsEffect())->setFrame(top, right, bottom, left); static_cast<DropShadowEffect*>(m_ui->scrollArea->graphicsEffect())->setFrame(top, right, bottom, left);
} }
void Conversation::dragEnterEvent(QDragEnterEvent* event)
{
bool accept = false;
if (event->mimeData()->hasUrls()) {
QList<QUrl> list = event->mimeData()->urls();
for (const QUrl& url : list) {
if (url.isLocalFile()) {
QFileInfo info(url.toLocalFile());
if (info.isReadable() && info.isFile()) {
accept = true;
break;
}
}
}
}
if (accept) {
event->acceptProposedAction();
overlay->show();
}
}
void Conversation::dragLeaveEvent(QDragLeaveEvent* event)
{
overlay->hide();
}
void Conversation::dropEvent(QDropEvent* event)
{
bool accept = false;
if (event->mimeData()->hasUrls()) {
QList<QUrl> list = event->mimeData()->urls();
for (const QUrl& url : list) {
if (url.isLocalFile()) {
QFileInfo info(url.toLocalFile());
if (info.isReadable() && info.isFile()) {
addAttachedFile(info.canonicalFilePath());
accept = true;
}
}
}
}
if (accept) {
event->acceptProposedAction();
}
overlay->hide();
}
bool VisibilityCatcher::eventFilter(QObject* obj, QEvent* event) bool VisibilityCatcher::eventFilter(QObject* obj, QEvent* event)
{ {
if (event->type() == QEvent::Show) { if (event->type() == QEvent::Show) {

View File

@ -22,6 +22,8 @@
#include <QWidget> #include <QWidget>
#include <QScopedPointer> #include <QScopedPointer>
#include <QMap> #include <QMap>
#include <QMimeData>
#include <QFileInfo>
#include "shared/message.h" #include "shared/message.h"
#include "order.h" #include "order.h"
@ -105,6 +107,9 @@ protected:
void addAttachedFile(const QString& path); void addAttachedFile(const QString& path);
void removeAttachedFile(Badge* badge); void removeAttachedFile(Badge* badge);
void clearAttachedFiles(); void clearAttachedFiles();
void dragEnterEvent(QDragEnterEvent* event) override;
void dragLeaveEvent(QDragLeaveEvent* event) override;
void dropEvent(QDropEvent* event) override;
protected slots: protected slots:
void onEnterPressed(); void onEnterPressed();
@ -138,6 +143,7 @@ protected:
QLabel* statusIcon; QLabel* statusIcon;
QLabel* statusLabel; QLabel* statusLabel;
FlowLayout* filesLayout; FlowLayout* filesLayout;
QWidget* overlay;
W::Order<Badge*, Badge::Comparator> filesToAttach; W::Order<Badge*, Badge::Comparator> filesToAttach;
Scroll scroll; Scroll scroll;
bool manualSliderChange; bool manualSliderChange;

View File

@ -16,10 +16,10 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QVBoxLayout" name="horizontalLayout"> <property name="acceptDrops">
<property name="spacing"> <bool>true</bool>
<number>0</number>
</property> </property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -32,7 +32,7 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item> <item row="0" column="0">
<widget class="QWidget" name="widget" native="true"> <widget class="QWidget" name="widget" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
@ -115,6 +115,13 @@
</property> </property>
<item> <item>
<widget class="QLabel" name="nameLabel"> <widget class="QLabel" name="nameLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -128,6 +135,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="font">
<font>
<pointsize>8</pointsize>
<italic>true</italic>
</font>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
@ -230,7 +243,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>520</width> <width>520</width>
<height>392</height> <height>385</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
@ -258,7 +271,7 @@
<zorder>widget_3</zorder> <zorder>widget_3</zorder>
</widget> </widget>
</item> </item>
<item> <item row="1" column="0">
<widget class="QWidget" name="widget_2" native="true"> <widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum"> <sizepolicy hsizetype="Preferred" vsizetype="Maximum">

View File

@ -126,7 +126,11 @@ VCard::VCard(const QString& jid, bool edit, QWidget* parent):
overlay->setAutoFillBackground(true); overlay->setAutoFillBackground(true);
overlay->setGraphicsEffect(opacity); overlay->setGraphicsEffect(opacity);
progressLabel->setAlignment(Qt::AlignCenter); progressLabel->setAlignment(Qt::AlignCenter);
progressLabel->setStyleSheet("font: 16pt"); QFont pf = progressLabel->font();
pf.setBold(true);
pf.setPointSize(26);
progressLabel->setFont(pf);
progressLabel->setWordWrap(true);
nl->addStretch(); nl->addStretch();
nl->addWidget(progress); nl->addWidget(progress);
nl->addWidget(progressLabel); nl->addWidget(progressLabel);