Fix layout issues in CoreConfigWizard; cleanup
authorManuel Nickschas <sputnick@quassel-irc.org>
Wed, 30 Aug 2017 21:43:45 +0000 (23:43 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Wed, 30 Aug 2017 21:55:25 +0000 (23:55 +0200)
Qt has trouble layouting widgets dynamically added to wizard pages,
so switch to using QStackedWidget for storage and authenticator
settings. Add size policies as needed and explicitly set the size of
all pages to fit the largest one to ensure that the wizard is large
enough.

While we're at it, clean up related code a bit.

Closes GH-170.

src/qtui/coreconfigwizard.cpp
src/qtui/coreconfigwizard.h
src/qtui/ui/coreconfigwizardadminuserpage.ui
src/qtui/ui/coreconfigwizardauthenticationselectionpage.ui
src/qtui/ui/coreconfigwizardstorageselectionpage.ui
src/qtui/ui/coreconfigwizardsyncpage.ui

index 18133f0..4324c45 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <QDebug>
 #include <QAbstractButton>
+#include <QCoreApplication>
 #include <QFormLayout>
 #include <QIcon>
 #include <QSpinBox>
 
 namespace {
 
+QGroupBox *createDescriptionBox(const QString &description)
+{
+    auto box = new QGroupBox;
+    auto layout = new QVBoxLayout(box);
+    auto label = new QLabel(description, box);
+    label->setWordWrap(true);
+    layout->addWidget(label);
+    layout->setAlignment(label, Qt::AlignTop);
+    box->setTitle(QCoreApplication::translate("CoreConfigWizard", "Description"));
+    return box;
+}
+
+
 template<typename FieldInfo>
-void createFieldWidgets(QGroupBox *fieldBox, const std::vector<FieldInfo> &fieldInfos)
+QGroupBox *createFieldBox(const QString &title, const std::vector<FieldInfo> &fieldInfos)
 {
     // Create a config UI based on the field types sent from the backend
     // We make some assumptions here (like integer range and password field names) that may not
@@ -40,7 +54,10 @@ void createFieldWidgets(QGroupBox *fieldBox, const std::vector<FieldInfo> &field
     // provide specialized config widgets for those (which may be a good idea anyway, e.g. if we
     // think about client-side translations...)
 
-    QFormLayout *formLayout = new QFormLayout;
+    QGroupBox *fieldBox = new QGroupBox;
+    fieldBox->setTitle(title);
+
+    QFormLayout *formLayout = new QFormLayout(fieldBox);
     for (auto &&fieldInfo : fieldInfos) {
         QWidget *widget {nullptr};
         switch (std::get<2>(fieldInfo).type()) {
@@ -65,7 +82,7 @@ void createFieldWidgets(QGroupBox *fieldBox, const std::vector<FieldInfo> &field
             formLayout->addRow(std::get<1>(fieldInfo) + ":", widget);
         }
     }
-    fieldBox->setLayout(formLayout);
+    return fieldBox;
 }
 
 
@@ -125,11 +142,8 @@ CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QVariantLis
     syncRelayPage = new CoreConfigWizardPages::SyncRelayPage(this);
     connect(syncRelayPage, SIGNAL(startOver()), this, SLOT(startOver()));
     setPage(SyncRelayPage, syncRelayPage);
-    //setPage(Page_StorageDetails, new StorageDetailsPage());
-    //setPage(Page_Conclusion, new ConclusionPage(storageProviders));
 
     setStartId(IntroPage);
-    //setStartId(StorageSelectionPage);
 
 #ifndef Q_OS_MAC
     setWizardStyle(ModernStyle);
@@ -141,7 +155,6 @@ CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QVariantLis
     setOption(HaveFinishButtonOnEarlyPages, false);
     setOption(NoCancelButton, true);
     setOption(IndependentPages, true);
-    //setOption(ExtendedWatermarkPixmap, true);
 
     setModal(true);
 
@@ -150,17 +163,28 @@ CoreConfigWizard::CoreConfigWizard(CoreConnection *connection, const QVariantLis
 
     connect(connection, SIGNAL(coreSetupSuccess()), SLOT(coreSetupSuccess()));
     connect(connection, SIGNAL(coreSetupFailed(QString)), SLOT(coreSetupFailed(QString)));
-    //connect(connection, SIGNAL(loginSuccess()), SLOT(loginSuccess()));
     connect(connection, SIGNAL(synchronized()), SLOT(syncFinished()));
     connect(this, SIGNAL(rejected()), connection, SLOT(disconnectFromCore()));
+
+
+    // Resize all pages to the size hint of the largest one, so the wizard is large enough
+    QSize maxSize;
+    for (int id : pageIds()) {
+        auto p = page(id);
+        p->adjustSize();
+        maxSize = maxSize.expandedTo(p->sizeHint());
+    }
+    for (int id : pageIds()) {
+        page(id)->setFixedSize(maxSize);
+    }
 }
 
 
 void CoreConfigWizard::prepareCoreSetup(const QString &backend, const QVariantMap &properties, const QString &authenticator, const QVariantMap &authProperties)
 {
     // Prevent the user from changing any settings he already specified...
-    foreach(int idx, visitedPages())
-    page(idx)->setEnabled(false);
+    for (auto &&idx : visitedPages())
+        page(idx)->setEnabled(false);
 
     // FIXME? We need to be able to set up older cores that don't have auth backend support.
     // So if the core doesn't support that feature, don't pass those parameters.
@@ -201,15 +225,6 @@ void CoreConfigWizard::startOver()
 }
 
 
-void CoreConfigWizard::loginSuccess()
-{
-    syncPage->setStatus(tr("Your are now logged into your freshly configured Quassel Core!<br>"
-                           "Please remember to configure your identities and networks now."));
-    syncPage->setComplete(true);
-    syncPage->setFinalPage(true);
-}
-
-
 void CoreConfigWizard::syncFinished()
 {
     accept();
@@ -289,13 +304,30 @@ AuthenticationSelectionPage::AuthenticationSelectionPage(const QVariantList &aut
         }
         props.remove("SetupData");
 
-        _authProperties.emplace_back(props);
+        _authProperties.emplace_back(std::move(props));
         _authFields.emplace_back(std::move(fields));
 
-        // Create entry in authenticator selector
-        ui.backendList->addItem(props["DisplayName"].toString(), props["BackendId"].toString());
+        // Create widgets
+        ui.backendList->addItem(_authProperties.back()["DisplayName"].toString(), _authProperties.back()["BackendId"].toString());
+        ui.descriptionStack->addWidget(createDescriptionBox(_authProperties.back()["Description"].toString()));
+        ui.authSettingsStack->addWidget(createFieldBox(tr("Authentication Settings"), _authFields.back()));
     }
 
+    // Do some trickery to make the page large enough
+    setSizePolicy({QSizePolicy::Fixed, QSizePolicy::Fixed});
+
+    QSizePolicy sp{QSizePolicy::MinimumExpanding, QSizePolicy::Fixed};
+#if QT_VERSION >= 0x050200
+    sp.setRetainSizeWhenHidden(true);
+#else
+    ui.authSettingsStack->setVisible(true);  // ugly hack that will show an empty box, but we'll deprecate Qt4 soon anyway
+#endif
+    ui.descriptionStack->setSizePolicy(sp);
+    ui.authSettingsStack->setSizePolicy(sp);
+
+    ui.descriptionStack->adjustSize();
+    ui.authSettingsStack->adjustSize();
+
     ui.backendList->setCurrentIndex(0);
 }
 
@@ -324,25 +356,16 @@ QString AuthenticationSelectionPage::authenticator() const
 
 QVariantMap AuthenticationSelectionPage::authProperties() const
 {
-    return propertiesFromFieldWidgets(_fieldBox, _authFields[ui.backendList->currentIndex()]);
+    return propertiesFromFieldWidgets(qobject_cast<QGroupBox *>(ui.authSettingsStack->currentWidget()),
+                                      _authFields[ui.backendList->currentIndex()]);
 }
 
 
 void AuthenticationSelectionPage::on_backendList_currentIndexChanged(int index)
 {
-    ui.description->setText(_authProperties[index]["Description"].toString());
-
-    if (_fieldBox) {
-        layout()->removeWidget(_fieldBox);
-        _fieldBox->deleteLater();
-        _fieldBox = nullptr;
-    }
-    if (!_authFields[index].empty()) {
-        _fieldBox = new QGroupBox(this);
-        _fieldBox->setTitle(tr("Authentication Settings"));
-        createFieldWidgets(_fieldBox, _authFields[index]);
-        static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, _fieldBox);
-    }
+    ui.descriptionStack->setCurrentIndex(index);
+    ui.authSettingsStack->setCurrentIndex(index);
+    ui.authSettingsStack->setVisible(!_authFields[index].empty());
 }
 
 /*** Storage Selection Page ***/
@@ -387,13 +410,30 @@ StorageSelectionPage::StorageSelectionPage(const QVariantList &backendInfos, QWi
         // Legacy cores (prior to 0.13) don't send the BackendId property
         if (!props.contains("BackendId"))
             props["BackendId"] = props["DisplayName"];
-        _backendProperties.emplace_back(props);
+        _backendProperties.emplace_back(std::move(props));
         _backendFields.emplace_back(std::move(fields));
 
-        // Create entry in backend selector
-        ui.backendList->addItem(props["DisplayName"].toString(), props["BackendId"].toString());
+        // Create widgets
+        ui.backendList->addItem(_backendProperties.back()["DisplayName"].toString(), _backendProperties.back()["BackendId"].toString());
+        ui.descriptionStack->addWidget(createDescriptionBox(_backendProperties.back()["Description"].toString()));
+        ui.storageSettingsStack->addWidget(createFieldBox(tr("Storage Settings"), _backendFields.back()));
     }
 
+    // Do some trickery to make the page large enough
+    setSizePolicy({QSizePolicy::Fixed, QSizePolicy::Fixed});
+
+    QSizePolicy sp{QSizePolicy::MinimumExpanding, QSizePolicy::Fixed};
+#if QT_VERSION >= 0x050200
+    sp.setRetainSizeWhenHidden(true);
+#else
+    ui.storageSettingsStack->setVisible(true);  // ugly hack that will show an empty box, but we'll deprecate Qt4 soon anyway
+#endif
+    ui.descriptionStack->setSizePolicy(sp);
+    ui.storageSettingsStack->setSizePolicy(sp);
+
+    ui.descriptionStack->adjustSize();
+    ui.storageSettingsStack->adjustSize();
+
     ui.backendList->setCurrentIndex(defaultIndex);
 }
 
@@ -422,25 +462,16 @@ QString StorageSelectionPage::backend() const
 
 QVariantMap StorageSelectionPage::backendProperties() const
 {
-    return propertiesFromFieldWidgets(_fieldBox, _backendFields[ui.backendList->currentIndex()]);
+    return propertiesFromFieldWidgets(qobject_cast<QGroupBox *>(ui.storageSettingsStack->currentWidget()),
+                                      _backendFields[ui.backendList->currentIndex()]);
 }
 
 
 void StorageSelectionPage::on_backendList_currentIndexChanged(int index)
 {
-    ui.description->setText(_backendProperties[index]["Description"].toString());
-
-    if (_fieldBox) {
-        layout()->removeWidget(_fieldBox);
-        _fieldBox->deleteLater();
-        _fieldBox = nullptr;
-    }
-    if (!_backendFields[index].empty()) {
-        _fieldBox = new QGroupBox(this);
-        _fieldBox->setTitle(tr("Storage Settings"));
-        createFieldWidgets(_fieldBox, _backendFields[index]);
-        static_cast<QVBoxLayout *>(layout())->insertWidget(layout()->indexOf(ui.descriptionBox) + 1, _fieldBox);
-    }
+    ui.descriptionStack->setCurrentIndex(index);
+    ui.storageSettingsStack->setCurrentIndex(index);
+    ui.storageSettingsStack->setVisible(!_backendFields[index].empty());
 }
 
 
index 5b09a87..6f2f711 100644 (file)
 class CoreConnection;
 
 namespace CoreConfigWizardPages {
+
 class SyncPage;
 class SyncRelayPage;
+
 };
 
 class CoreConfigWizard : public QWizard
@@ -64,7 +66,6 @@ signals:
     void loginToCore(const QString &user, const QString &password, bool rememberPassword);
 
 public slots:
-    void loginSuccess();
     void syncFinished();
 
 private slots:
@@ -82,6 +83,7 @@ private:
 
 
 namespace CoreConfigWizardPages {
+
 class IntroPage : public QWizardPage
 {
     Q_OBJECT
@@ -106,7 +108,7 @@ private:
     Ui::CoreConfigWizardAdminUserPage ui;
 };
 
-// Authentication selection before storage selection.
+
 class AuthenticationSelectionPage : public QWizardPage
 {
     Q_OBJECT
@@ -124,11 +126,11 @@ private slots:
 
 private:
     Ui::CoreConfigWizardAuthenticationSelectionPage ui;
-    QGroupBox *_fieldBox {nullptr};
     std::vector<QVariantMap> _authProperties;
     std::vector<std::vector<FieldInfo>> _authFields;
 };
 
+
 class StorageSelectionPage : public QWizardPage
 {
     Q_OBJECT
@@ -146,11 +148,11 @@ private slots:
 
 private:
     Ui::CoreConfigWizardStorageSelectionPage ui;
-    QGroupBox *_fieldBox {nullptr};
     std::vector<QVariantMap> _backendProperties;
     std::vector<std::vector<FieldInfo>> _backendFields;
 };
 
+
 class SyncPage : public QWizardPage
 {
     Q_OBJECT
@@ -194,4 +196,5 @@ signals:
 private:
     Mode mode;
 };
+
 }
index e55859f..5f8cca2 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>429</width>
-    <height>273</height>
+    <width>505</width>
+    <height>289</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -16,6 +16,9 @@
   <layout class="QVBoxLayout">
    <item>
     <layout class="QGridLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetMinimumSize</enum>
+     </property>
      <item row="0" column="0">
       <widget class="QLabel" name="label_2">
        <property name="text">
index d00c8f0..fca2a0c 100644 (file)
@@ -6,16 +6,19 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>310</width>
-    <height>168</height>
+    <width>377</width>
+    <height>160</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QVBoxLayout">
+  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <layout class="QHBoxLayout">
+     <property name="sizeConstraint">
+      <enum>QLayout::SetMinAndMaxSize</enum>
+     </property>
      <item>
       <widget class="QLabel" name="label">
        <property name="text">
@@ -43,8 +46,8 @@
        </property>
        <property name="sizeHint" stdset="0">
         <size>
-         <width>40</width>
-         <height>20</height>
+         <width>0</width>
+         <height>0</height>
         </size>
        </property>
       </spacer>
     </layout>
    </item>
    <item>
-    <widget class="QGroupBox" name="descriptionBox">
-     <property name="title">
-      <string>Description</string>
+    <widget class="QStackedWidget" name="descriptionStack">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>-1</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QStackedWidget" name="authSettingsStack">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>-1</number>
      </property>
-     <layout class="QVBoxLayout">
-      <item>
-       <widget class="QLabel" name="description">
-        <property name="text">
-         <string notr="true">Foobar</string>
-        </property>
-        <property name="alignment">
-         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-        </property>
-        <property name="wordWrap">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
     </widget>
    </item>
    <item>
@@ -80,8 +87,8 @@
      </property>
      <property name="sizeHint" stdset="0">
       <size>
-       <width>20</width>
-       <height>40</height>
+       <width>0</width>
+       <height>0</height>
       </size>
      </property>
     </spacer>
index 6e71837..c9862cb 100644 (file)
@@ -6,14 +6,14 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>310</width>
-    <height>168</height>
+    <width>402</width>
+    <height>148</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
-  <layout class="QVBoxLayout">
+  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <layout class="QHBoxLayout">
      <item>
@@ -43,8 +43,8 @@
        </property>
        <property name="sizeHint" stdset="0">
         <size>
-         <width>40</width>
-         <height>20</height>
+         <width>0</width>
+         <height>0</height>
         </size>
        </property>
       </spacer>
     </layout>
    </item>
    <item>
-    <widget class="QGroupBox" name="descriptionBox">
-     <property name="title">
-      <string>Description</string>
+    <widget class="QStackedWidget" name="descriptionStack">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>-1</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QStackedWidget" name="storageSettingsStack">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>-1</number>
      </property>
-     <layout class="QVBoxLayout">
-      <item>
-       <widget class="QLabel" name="description">
-        <property name="text">
-         <string notr="true">Foobar</string>
-        </property>
-        <property name="alignment">
-         <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-        </property>
-        <property name="wordWrap">
-         <bool>true</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
     </widget>
    </item>
    <item>
@@ -80,8 +84,8 @@
      </property>
      <property name="sizeHint" stdset="0">
       <size>
-       <width>20</width>
-       <height>40</height>
+       <width>0</width>
+       <height>0</height>
       </size>
      </property>
     </spacer>
index 9894e97..39d8818 100644 (file)
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>400</width>
-    <height>300</height>
+    <height>252</height>
    </rect>
   </property>
   <property name="windowTitle">
      </layout>
     </widget>
    </item>
-   <item>
-    <spacer>
-     <property name="orientation">
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>20</width>
-       <height>40</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
    <item>
     <widget class="QLabel" name="status">
      <property name="text">
      </property>
     </widget>
    </item>
+   <item>
+    <spacer>
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>0</width>
+       <height>0</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
   </layout>
  </widget>
  <resources/>