From d4d38dd44d61a64a56a5bc5e7c0644dfbc17e128 Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Tue, 23 Apr 2019 08:36:35 -0400
Subject: yuzu: Add UI to manage filesystem paths and sizes

---
 src/yuzu/CMakeLists.txt                         |   2 +
 src/yuzu/configuration/configure.ui             |  11 +
 src/yuzu/configuration/configure_dialog.cpp     |   4 +-
 src/yuzu/configuration/configure_filesystem.cpp | 173 +++++++++++
 src/yuzu/configuration/configure_filesystem.h   |  43 +++
 src/yuzu/configuration/configure_filesystem.ui  | 395 ++++++++++++++++++++++++
 6 files changed, 627 insertions(+), 1 deletion(-)
 create mode 100644 src/yuzu/configuration/configure_filesystem.cpp
 create mode 100644 src/yuzu/configuration/configure_filesystem.h
 create mode 100644 src/yuzu/configuration/configure_filesystem.ui

(limited to 'src')

diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f051e17b46..c50ca317d5 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -33,6 +33,8 @@ add_executable(yuzu
     configuration/configure_debug.ui
     configuration/configure_dialog.cpp
     configuration/configure_dialog.h
+    configuration/configure_filesystem.cpp
+    configuration/configure_filesystem.h
     configuration/configure_gamelist.cpp
     configuration/configure_gamelist.h
     configuration/configure_gamelist.ui
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui
index 267717bc97..49fadd0ef7 100644
--- a/src/yuzu/configuration/configure.ui
+++ b/src/yuzu/configuration/configure.ui
@@ -63,6 +63,11 @@
          <string>Profiles</string>
         </attribute>
        </widget>
+       <widget class="ConfigureFilesystem" name="filesystemTab">
+        <attribute name="title">
+         <string>Filesystem</string>
+        </attribute>
+       </widget>
        <widget class="ConfigureInputSimple" name="inputTab">
         <attribute name="title">
          <string>Input</string>
@@ -125,6 +130,12 @@
    <header>configuration/configure_profile_manager.h</header>
    <container>1</container>
   </customwidget>
+  <customwidget>
+   <class>ConfigureFilesystem</class>
+   <extends>QWidget</extends>
+   <header>configuration/configure_filesystem.h</header>
+   <container>1</container>
+  </customwidget>
   <customwidget>
    <class>ConfigureAudio</class>
    <extends>QWidget</extends>
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp
index 775e3f2eac..7c875ae870 100644
--- a/src/yuzu/configuration/configure_dialog.cpp
+++ b/src/yuzu/configuration/configure_dialog.cpp
@@ -37,6 +37,7 @@ void ConfigureDialog::ApplyConfiguration() {
     ui->gameListTab->ApplyConfiguration();
     ui->systemTab->ApplyConfiguration();
     ui->profileManagerTab->ApplyConfiguration();
+    ui->filesystemTab->applyConfiguration();
     ui->inputTab->ApplyConfiguration();
     ui->hotkeysTab->ApplyConfiguration(registry);
     ui->graphicsTab->ApplyConfiguration();
@@ -73,7 +74,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
 void ConfigureDialog::PopulateSelectionList() {
     const std::array<std::pair<QString, QList<QWidget*>>, 4> items{
         {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}},
-         {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->audioTab}},
+         {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->filesystemTab, ui->audioTab}},
          {tr("Graphics"), {ui->graphicsTab}},
          {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
     };
@@ -106,6 +107,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
         {ui->debugTab, tr("Debug")},
         {ui->webTab, tr("Web")},
         {ui->gameListTab, tr("Game List")},
+        {ui->filesystemTab, tr("Filesystem")},
     };
 
     [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget);
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
new file mode 100644
index 0000000000..fabe86e0a3
--- /dev/null
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -0,0 +1,173 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QFileDialog>
+#include <QMessageBox>
+#include "common/common_paths.h"
+#include "common/file_util.h"
+#include "core/settings.h"
+#include "ui_configure_filesystem.h"
+#include "yuzu/configuration/configure_filesystem.h"
+#include "yuzu/ui_settings.h"
+
+namespace {
+
+template <typename T>
+void SetComboBoxFromData(QComboBox* combo_box, T data) {
+    const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
+    if (index >= combo_box->count() || index < 0)
+        return;
+
+    combo_box->setCurrentIndex(index);
+}
+
+} // Anonymous namespace
+
+ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
+    : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
+    ui->setupUi(this);
+    this->setConfiguration();
+
+    connect(ui->nand_directory_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::NAND, ui->nand_directory_edit); });
+    connect(ui->sdmc_directory_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::SD, ui->sdmc_directory_edit); });
+    connect(ui->gamecard_path_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::Gamecard, ui->gamecard_path_edit); });
+    connect(ui->dump_path_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::Dump, ui->dump_path_edit); });
+    connect(ui->load_path_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::Load, ui->load_path_edit); });
+    connect(ui->cache_directory_button, &QToolButton::pressed, this,
+            [this] { SetDirectory(DirectoryTarget::Cache, ui->cache_directory_edit); });
+
+    connect(ui->reset_game_list_cache, &QPushButton::pressed, this,
+            &ConfigureFilesystem::ResetMetadata);
+
+    connect(ui->gamecard_inserted, &QCheckBox::stateChanged, this,
+            &ConfigureFilesystem::UpdateEnabledControls);
+    connect(ui->gamecard_current_game, &QCheckBox::stateChanged, this,
+            &ConfigureFilesystem::UpdateEnabledControls);
+}
+
+ConfigureFilesystem::~ConfigureFilesystem() = default;
+
+void ConfigureFilesystem::setConfiguration() {
+    ui->nand_directory_edit->setText(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
+    ui->sdmc_directory_edit->setText(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
+    ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path));
+    ui->dump_path_edit->setText(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)));
+    ui->load_path_edit->setText(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)));
+    ui->cache_directory_edit->setText(
+        QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)));
+
+    ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted);
+    ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game);
+    ui->dump_exefs->setChecked(Settings::values.dump_exefs);
+    ui->dump_nso->setChecked(Settings::values.dump_nso);
+
+    ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
+
+    SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
+    SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
+    SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
+    SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
+
+    UpdateEnabledControls();
+}
+
+void ConfigureFilesystem::applyConfiguration() {
+    FileUtil::GetUserPath(FileUtil::UserPath::NANDDir,
+                          ui->nand_directory_edit->text().toStdString());
+    FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
+                          ui->sdmc_directory_edit->text().toStdString());
+    FileUtil::GetUserPath(FileUtil::UserPath::DumpDir, ui->dump_path_edit->text().toStdString());
+    FileUtil::GetUserPath(FileUtil::UserPath::LoadDir, ui->load_path_edit->text().toStdString());
+    FileUtil::GetUserPath(FileUtil::UserPath::CacheDir,
+                          ui->cache_directory_edit->text().toStdString());
+    Settings::values.gamecard_path = ui->gamecard_path_edit->text().toStdString();
+
+    Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked();
+    Settings::values.gamecard_current_game = ui->gamecard_current_game->isChecked();
+    Settings::values.dump_exefs = ui->dump_exefs->isChecked();
+    Settings::values.dump_nso = ui->dump_nso->isChecked();
+
+    UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
+
+    Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
+        ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
+    Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
+        ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
+    Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
+        ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
+    Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
+        ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
+}
+
+void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
+    QString caption;
+
+    switch (target) {
+    case DirectoryTarget::NAND:
+        caption = tr("Select Emulated NAND Directory...");
+        break;
+    case DirectoryTarget::SD:
+        caption = tr("Select Emulated SD Directory...");
+        break;
+    case DirectoryTarget::Gamecard:
+        caption = tr("Select Gamecard Path...");
+        break;
+    case DirectoryTarget::Dump:
+        caption = tr("Select Dump Directory...");
+        break;
+    case DirectoryTarget::Load:
+        caption = tr("Select Mod Load Directory...");
+        break;
+    case DirectoryTarget::Cache:
+        caption = tr("Select Cache Directory...");
+        break;
+    }
+
+    QString str;
+    if (target == DirectoryTarget::Gamecard) {
+        str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(),
+                                           "NX Gamecard;*.xci");
+    } else {
+        str = QFileDialog::getExistingDirectory(this, caption, edit->text());
+    }
+
+    if (str.isEmpty())
+        return;
+
+    edit->setText(str);
+}
+
+void ConfigureFilesystem::ResetMetadata() {
+    if (FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
+                                       DIR_SEP + "game_list")) {
+        QMessageBox::information(this, tr("Reset Metadata Cache"),
+                                 tr("The operation completed successfully."));
+        UISettings::values.is_game_list_reload_pending.exchange(true);
+    } else {
+        QMessageBox::warning(
+            this, tr("Reset Metadata Cache"),
+            tr("The metadata cache couldn't be deleted. It might be in use or non-existent."));
+    }
+}
+
+void ConfigureFilesystem::UpdateEnabledControls() {
+    ui->gamecard_current_game->setEnabled(ui->gamecard_inserted->isChecked());
+    ui->gamecard_path_edit->setEnabled(ui->gamecard_inserted->isChecked() &&
+                                       !ui->gamecard_current_game->isChecked());
+    ui->gamecard_path_button->setEnabled(ui->gamecard_inserted->isChecked() &&
+                                         !ui->gamecard_current_game->isChecked());
+}
+
+void ConfigureFilesystem::retranslateUi() {
+    ui->retranslateUi(this);
+}
diff --git a/src/yuzu/configuration/configure_filesystem.h b/src/yuzu/configuration/configure_filesystem.h
new file mode 100644
index 0000000000..a793037604
--- /dev/null
+++ b/src/yuzu/configuration/configure_filesystem.h
@@ -0,0 +1,43 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <QWidget>
+
+class QLineEdit;
+
+namespace Ui {
+class ConfigureFilesystem;
+}
+
+class ConfigureFilesystem : public QWidget {
+    Q_OBJECT
+
+public:
+    explicit ConfigureFilesystem(QWidget* parent = nullptr);
+    ~ConfigureFilesystem() override;
+
+    void applyConfiguration();
+    void retranslateUi();
+
+private:
+    void setConfiguration();
+
+    enum class DirectoryTarget {
+        NAND,
+        SD,
+        Gamecard,
+        Dump,
+        Load,
+        Cache,
+    };
+
+    void SetDirectory(DirectoryTarget target, QLineEdit* edit);
+    void ResetMetadata();
+    void UpdateEnabledControls();
+
+    std::unique_ptr<Ui::ConfigureFilesystem> ui;
+};
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui
new file mode 100644
index 0000000000..58cd07f527
--- /dev/null
+++ b/src/yuzu/configuration/configure_filesystem.ui
@@ -0,0 +1,395 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigureFilesystem</class>
+ <widget class="QWidget" name="ConfigureFilesystem">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>453</width>
+    <height>561</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout_3">
+     <item>
+      <widget class="QGroupBox" name="groupBox">
+       <property name="title">
+        <string>Storage Directories</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label">
+          <property name="text">
+           <string>NAND</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="3">
+         <widget class="QToolButton" name="nand_directory_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLineEdit" name="nand_directory_edit"/>
+        </item>
+        <item row="1" column="2">
+         <widget class="QLineEdit" name="sdmc_directory_edit"/>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_2">
+          <property name="text">
+           <string>SD Card</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="3">
+         <widget class="QToolButton" name="sdmc_directory_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <spacer name="horizontalSpacer">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Maximum</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>60</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_2">
+       <property name="title">
+        <string>Gamecard</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout_2">
+        <item row="2" column="1">
+         <widget class="QLabel" name="label_3">
+          <property name="text">
+           <string>Path</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="2">
+         <widget class="QLineEdit" name="gamecard_path_edit"/>
+        </item>
+        <item row="0" column="1">
+         <widget class="QCheckBox" name="gamecard_inserted">
+          <property name="text">
+           <string>Inserted</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QCheckBox" name="gamecard_current_game">
+          <property name="text">
+           <string>Current Game</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="3">
+         <widget class="QToolButton" name="gamecard_path_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_3">
+       <property name="title">
+        <string>Storage Sizes</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout_3">
+        <item row="3" column="0">
+         <widget class="QLabel" name="label_5">
+          <property name="text">
+           <string>SD Card</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_4">
+          <property name="text">
+           <string>System NAND</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QComboBox" name="sysnand_size">
+          <item>
+           <property name="text">
+            <string>2.5 GB</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QComboBox" name="sdmc_size">
+          <property name="currentText">
+           <string>32 GB</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>1 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>2 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>4 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>8 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>16 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>64 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>128 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>256 GB</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>1 TB</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QComboBox" name="usrnand_size">
+          <item>
+           <property name="text">
+            <string>26 GB</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="label_6">
+          <property name="text">
+           <string>User NAND</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_7">
+          <property name="text">
+           <string>NAND</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QComboBox" name="nand_size">
+          <item>
+           <property name="text">
+            <string>29.1 GB</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_4">
+       <property name="title">
+        <string>Patch Manager</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout_4">
+        <item row="1" column="2">
+         <widget class="QLineEdit" name="load_path_edit"/>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLineEdit" name="dump_path_edit"/>
+        </item>
+        <item row="0" column="3">
+         <widget class="QToolButton" name="dump_path_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="3">
+         <widget class="QToolButton" name="load_path_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0" colspan="4">
+         <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+           <widget class="QCheckBox" name="dump_nso">
+            <property name="text">
+             <string>Dump Decompressed NSOs</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QCheckBox" name="dump_exefs">
+            <property name="text">
+             <string>Dump ExeFS</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="label_9">
+          <property name="text">
+           <string>Mod Load Root</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_8">
+          <property name="text">
+           <string>Dump Root</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <spacer name="horizontalSpacer_2">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Fixed</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_5">
+       <property name="title">
+        <string>Caching</string>
+       </property>
+       <layout class="QGridLayout" name="gridLayout_5">
+        <item row="0" column="0">
+         <widget class="QLabel" name="label_10">
+          <property name="text">
+           <string>Cache Directory</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <spacer name="horizontalSpacer_3">
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Fixed</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="0" column="2">
+         <widget class="QLineEdit" name="cache_directory_edit"/>
+        </item>
+        <item row="0" column="3">
+         <widget class="QToolButton" name="cache_directory_button">
+          <property name="text">
+           <string>...</string>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0" colspan="4">
+         <layout class="QHBoxLayout" name="horizontalLayout_2">
+          <item>
+           <widget class="QCheckBox" name="cache_game_list">
+            <property name="text">
+             <string>Cache Game List Metadata</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="reset_game_list_cache">
+            <property name="text">
+             <string>Reset Metadata Cache</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
-- 
cgit v1.2.3-70-g09d2