Add auto update feature (#889)
* Added auto update feature. * Copied sparkle-readme.md and appcast.example.xml from seadrive-gui.
This commit is contained in:
parent
6b1d4cf111
commit
b5a275e98d
11 changed files with 527 additions and 2 deletions
|
@ -37,6 +37,11 @@ OPTION(BUILD_SHIBBOLETH_SUPPORT "Build Shibboleth support" OFF)
|
|||
|
||||
option(BUILD_ENABLE_WARNINGS "Enable compiler warnings." ON)
|
||||
|
||||
option(BUILD_SPARKLE_SUPPORT "Build Sparkle support" OFF)
|
||||
IF (BUILD_SPARKLE_SUPPORT)
|
||||
ADD_DEFINITIONS(-DHAVE_SPARKLE_SUPPORT)
|
||||
ENDIF()
|
||||
|
||||
MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
## build in PIC mode
|
||||
|
@ -79,8 +84,21 @@ IF (WIN32)
|
|||
IF (${CMAKE_BUILD_TYPE} MATCHES Release)
|
||||
SET(GUI_TYPE WIN32)
|
||||
ENDIF()
|
||||
SET(platform_specific_moc_headers src/ext-handler.h)
|
||||
SET(platform_specific_sources src/ext-handler.cpp)
|
||||
SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/ext-handler.h src/ui/about-dialog.h)
|
||||
SET(platform_specific_sources ${platform_specific_sources} src/ext-handler.cpp src/ui/about-dialog.cpp)
|
||||
SET(platform_specific_ui_files ${platform_specific_ui_files} ui/about-dialog.ui)
|
||||
IF (BUILD_SPARKLE_SUPPORT)
|
||||
IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/WinSparkle.lib")
|
||||
message(FATAL_ERROR "File ${CMAKE_SOURCE_DIR}/WinSparkle.lib not found in current directory. Please setup winsparkle correctly." )
|
||||
ENDIF()
|
||||
SET(SPARKLE_LIBS ${CMAKE_SOURCE_DIR}/WinSparkle.lib)
|
||||
SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/auto-update-service.h)
|
||||
SET(platform_specific_sources ${platform_specific_sources} src/auto-update-service.cpp)
|
||||
IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
|
||||
ADD_DEFINITIONS(-DWINSPARKLE_DEBUG)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
|
||||
INCLUDE_DIRECTORIES(${QT_QTDBUS_INCLUDE_DIR})
|
||||
LINK_DIRECTORIES(${QT_QTDBUS_LIBRARIES})
|
||||
|
@ -702,6 +720,7 @@ ADD_EXECUTABLE(seafile-applet ${GUI_TYPE}
|
|||
INSTALL(TARGETS seafile-applet DESTINATION bin)
|
||||
|
||||
TARGET_LINK_LIBRARIES(seafile-applet
|
||||
${SPARKLE_LIBS}
|
||||
${SC_LIBS}
|
||||
${QT_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
|
|
17
appcast.example.xml
Normal file
17
appcast.example.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
|
||||
<channel>
|
||||
<title>Seafile client updates</title>
|
||||
<description>Appcast for test Seafile client updates.</description>
|
||||
<language>en</language>
|
||||
<item>
|
||||
<title>Version 6.0.4</title>
|
||||
<sparkle:releaseNotesLink>http://localhost/SeafileClientChangeLog.html</sparkle:releaseNotesLink>
|
||||
<pubDate>Tue, 16 Sep 2016 18:11:12 +0200</pubDate>
|
||||
<enclosure url="http://localhost/qt.exe"
|
||||
sparkle:version="6.0.4"
|
||||
length="0"
|
||||
type="application/octet-stream"/>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
39
sparkle-readme.md
Normal file
39
sparkle-readme.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
## Setup WinSparkle environment
|
||||
|
||||
[WinSparkle](https://github.com/vslavik/winsparkle) 是 Mac 上的 Sparkle 框架在 windows 上的实现,用于软件自动更新.
|
||||
|
||||
* 下载 winsparkle 发布包 https://github.com/vslavik/winsparkle/releases/download/v0.5.3/WinSparkle-0.5.3.zip, 并解压
|
||||
* 把 include 下的文件拷贝到 /usr/local/lib
|
||||
* 把 Release/winsparkle.dll 拷贝到 /mingw32/bin
|
||||
* 把 winsparkle.lib 拷贝到 seafile-client 目录下
|
||||
|
||||
在编译时需要加上 `BUILD_SPARKLE_SUPPORT` flag:
|
||||
```sh
|
||||
cmake -DBUILD_SPARKLE_SUPPORT=ON .
|
||||
```
|
||||
|
||||
|
||||
## 更新 appcast.xml
|
||||
|
||||
winsparkle 根据下载下来的 appcast.xml 中的数据:
|
||||
|
||||
- 判断当前是否有更新版本
|
||||
- 新版本的下载地址
|
||||
- 新版本的 release notes (展示给用户看)
|
||||
|
||||
发布新的版本时,需要更新appcast中的哪些字段:
|
||||
|
||||
- pubDate 字段
|
||||
- enclosure 中新版本的下载地址 url 字段
|
||||
- enclosure 中新版本的版本号 sparkle:version 字段
|
||||
|
||||
### 本地开发时如何搭建一个简单的 server 来让 seafile-client 去获取 appcast.xml
|
||||
|
||||
- 将 appcast.example.xml 修改一下
|
||||
- 然后本地启动一个 nginx 服务器
|
||||
- 设置 `SEAFILE_CLIENT_APPCAST_URI` 环境变量, 然后启动 seafile-applet.
|
||||
|
||||
```sh
|
||||
export SEAFILE_CLIENT_APPCAST_URI=http://localhost:8888/appcast.xml
|
||||
./seafile-applet.exe
|
||||
```
|
93
src/auto-update-service.cpp
Normal file
93
src/auto-update-service.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#include <QTimer>
|
||||
|
||||
#include <winsparkle.h>
|
||||
|
||||
#include "api/requests.h"
|
||||
#include "seafile-applet.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "auto-update-service.h"
|
||||
|
||||
SINGLETON_IMPL(AutoUpdateService)
|
||||
|
||||
namespace
|
||||
{
|
||||
const char *kSparkleAppcastURI = "https://seafile.com/api/seafile-client/appcast.xml";
|
||||
const char *kWinSparkleRegistryPath = "SOFTWARE\\Seafile\\Seafile Client\\WinSparkle";
|
||||
} // namespace
|
||||
|
||||
AutoUpdateService::AutoUpdateService(QObject *parent) : QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void AutoUpdateService::start()
|
||||
{
|
||||
// Initialize the updater and possibly show some UI
|
||||
win_sparkle_init();
|
||||
}
|
||||
|
||||
void AutoUpdateService::stop()
|
||||
{
|
||||
win_sparkle_cleanup();
|
||||
}
|
||||
|
||||
|
||||
void AutoUpdateService::checkUpdate()
|
||||
{
|
||||
win_sparkle_check_update_with_ui();
|
||||
}
|
||||
|
||||
void AutoUpdateService::checkAndInstallUpdate() {
|
||||
win_sparkle_check_update_with_ui_and_install();
|
||||
}
|
||||
|
||||
void AutoUpdateService::checkUpdateWithoutUI() {
|
||||
win_sparkle_check_update_without_ui();
|
||||
}
|
||||
|
||||
|
||||
void AutoUpdateService::setRequestParams() {
|
||||
// Note that @param path is relative to HKCU/HKLM root
|
||||
// and the root is not part of it. For example:
|
||||
// @code
|
||||
// win_sparkle_set_registry_path("Software\\My App\\Updates");
|
||||
// @endcode
|
||||
win_sparkle_set_registry_path(kWinSparkleRegistryPath);
|
||||
win_sparkle_set_appcast_url(getAppcastURI().toUtf8().data());
|
||||
win_sparkle_set_app_details(
|
||||
L"Seafile",
|
||||
L"Seafile Client",
|
||||
QString(STRINGIZE(SEAFILE_CLIENT_VERSION)).toStdWString().c_str());
|
||||
}
|
||||
|
||||
bool AutoUpdateService::shouldSupportAutoUpdate() const {
|
||||
// qWarning() << "shouldSupportAutoUpdate =" << (QString(getBrand()) == "Seafile");
|
||||
return QString(getBrand()) == "Seafile";
|
||||
}
|
||||
|
||||
bool AutoUpdateService::autoUpdateEnabled() const {
|
||||
// qWarning() << "autoUpdateEnabled =" << win_sparkle_get_automatic_check_for_updates();
|
||||
return win_sparkle_get_automatic_check_for_updates();
|
||||
}
|
||||
|
||||
void AutoUpdateService::setAutoUpdateEnabled(bool enabled) {
|
||||
// qWarning() << "setAutoUpdateEnabled:" << enabled;
|
||||
win_sparkle_set_automatic_check_for_updates(enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
uint AutoUpdateService::updateCheckInterval() const {
|
||||
return win_sparkle_get_update_check_interval();
|
||||
}
|
||||
|
||||
void AutoUpdateService::setUpdateCheckInterval(uint interval_in_seconds) {
|
||||
win_sparkle_set_update_check_interval(interval_in_seconds);
|
||||
}
|
||||
|
||||
QString AutoUpdateService::getAppcastURI() {
|
||||
#if defined(WINSPARKLE_DEBUG)
|
||||
QString url_from_env = qgetenv("SEAFILE_CLIENT_APPCAST_URI");
|
||||
return url_from_env.isEmpty() ? kSparkleAppcastURI : url_from_env;
|
||||
#else
|
||||
return kSparkleAppcastURI;
|
||||
#endif
|
||||
}
|
37
src/auto-update-service.h
Normal file
37
src/auto-update-service.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
|
||||
#define SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "utils/singleton.h"
|
||||
|
||||
// Auto update seafile client program. Only used on windows.
|
||||
class AutoUpdateService : public QObject
|
||||
{
|
||||
SINGLETON_DEFINE(AutoUpdateService)
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoUpdateService(QObject *parent = 0);
|
||||
|
||||
bool shouldSupportAutoUpdate() const;
|
||||
|
||||
void setRequestParams();
|
||||
bool autoUpdateEnabled() const;
|
||||
void setAutoUpdateEnabled(bool enabled);
|
||||
uint updateCheckInterval() const;
|
||||
void setUpdateCheckInterval(uint interval_in_seconds);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
void checkUpdate();
|
||||
void checkAndInstallUpdate();
|
||||
void checkUpdateWithoutUI();
|
||||
|
||||
private:
|
||||
QString getAppcastURI();
|
||||
};
|
||||
|
||||
#endif // SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
|
|
@ -127,6 +127,11 @@ void handleCommandLineOption(int argc, char *argv[])
|
|||
case 'f':
|
||||
OpenLocalHelper::instance()->handleOpenLocalFromCommandLine(optarg);
|
||||
break;
|
||||
#if defined(HAVE_SPARKLE_SUPPORT) && defined(WINSPARKLE_DEBUG)
|
||||
case 'U':
|
||||
g_setenv ("SEAFILE_CLIENT_APPCAST_URI", optarg, 1);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
#if defined(Q_OS_WIN32)
|
||||
#include "ext-handler.h"
|
||||
#include "utils/registry.h"
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
#include "auto-update-service.h"
|
||||
#endif
|
||||
|
||||
#elif defined(HAVE_FINDER_SYNC_SUPPORT)
|
||||
#include "finder-sync/finder-sync-listener.h"
|
||||
#endif
|
||||
|
@ -262,6 +266,11 @@ SeafileApplet::~SeafileApplet()
|
|||
delete main_win_;
|
||||
#if defined(Q_OS_WIN32)
|
||||
SeafileExtensionHandler::instance()->stop();
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
AutoUpdateService::instance()->stop();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -404,6 +413,14 @@ void SeafileApplet::onDaemonStarted()
|
|||
//
|
||||
#if defined(Q_OS_WIN32)
|
||||
SeafileExtensionHandler::instance()->start();
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
|
||||
AutoUpdateService::instance()->setRequestParams();
|
||||
AutoUpdateService::instance()->start();
|
||||
}
|
||||
#endif // HAVE_SPARKLE_SUPPORT
|
||||
|
||||
#elif defined(HAVE_FINDER_SYNC_SUPPORT)
|
||||
finderSyncListenerStart();
|
||||
#endif
|
||||
|
|
52
src/ui/about-dialog.cpp
Normal file
52
src/ui/about-dialog.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include <QtWidgets>
|
||||
|
||||
#include "seafile-applet.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "about-dialog.h"
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
#include "auto-update-service.h"
|
||||
|
||||
namespace {
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
setWindowTitle(tr("About %1").arg(getBrand()));
|
||||
setWindowIcon(QIcon(":/images/seafile.png"));
|
||||
setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) |
|
||||
Qt::WindowStaysOnTopHint);
|
||||
|
||||
version_text_ = tr("<h4>%1 Client %2</h4>")
|
||||
.arg(getBrand())
|
||||
.arg(STRINGIZE(SEAFILE_CLIENT_VERSION))
|
||||
#ifdef SEAFILE_CLIENT_REVISION
|
||||
.append(tr("<h5> REV %1 </h5>"))
|
||||
.arg(STRINGIZE(SEAFILE_CLIENT_REVISION))
|
||||
#endif
|
||||
;
|
||||
mVersionText->setText(version_text_);
|
||||
|
||||
connect(mOKBtn, SIGNAL(clicked()), this, SLOT(close()));
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
mCheckUpdateBtn->setVisible(true);
|
||||
connect(mCheckUpdateBtn, SIGNAL(clicked()), this, SLOT(checkUpdate()));
|
||||
#else
|
||||
mCheckUpdateBtn->setVisible(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
void AboutDialog::checkUpdate()
|
||||
{
|
||||
AutoUpdateService::instance()->setRequestParams();
|
||||
AutoUpdateService::instance()->checkUpdate();
|
||||
close();
|
||||
}
|
||||
#endif
|
27
src/ui/about-dialog.h
Normal file
27
src/ui/about-dialog.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef SEAFILE_CLIENT_ABOUT_DIALOG_H
|
||||
#define SEAFILE_CLIENT_ABOUT_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_about-dialog.h"
|
||||
|
||||
class AutoUpdateService;
|
||||
|
||||
class AboutDialog : public QDialog,
|
||||
public Ui::AboutDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AboutDialog(QWidget *parent=0);
|
||||
|
||||
#ifdef HAVE_SPARKLE_SUPPORT
|
||||
private slots:
|
||||
void checkUpdate();
|
||||
#endif
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(AboutDialog)
|
||||
|
||||
QString version_text_;
|
||||
};
|
||||
|
||||
#endif // SEAFILE_CLIENT_ABOUT_DIALOG_H
|
|
@ -48,6 +48,10 @@ extern void qt_mac_set_dock_menu(QMenu *menu);
|
|||
#include <QDBusPendingCall>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
#include "src/ui/about-dialog.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
const int kRefreshInterval = 1000;
|
||||
|
@ -488,6 +492,14 @@ void SeafileTrayIcon::showMainWindow()
|
|||
|
||||
void SeafileTrayIcon::about()
|
||||
{
|
||||
#if defined(Q_OS_WIN32)
|
||||
AboutDialog *about_dialog = new AboutDialog();
|
||||
about_dialog->show();
|
||||
about_dialog->raise();
|
||||
about_dialog->activateWindow();
|
||||
return;
|
||||
#endif
|
||||
|
||||
QMessageBox::about(seafApplet->mainWindow(), tr("About %1").arg(getBrand()),
|
||||
tr("<h2>%1 Client %2</h2>").arg(getBrand()).arg(
|
||||
STRINGIZE(SEAFILE_CLIENT_VERSION))
|
||||
|
|
207
ui/about-dialog.ui
Normal file
207
ui/about-dialog.ui
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>AboutDialog</class>
|
||||
<widget class="QDialog" name="AboutDialog">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>296</width>
|
||||
<height>137</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>About</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="mVersionText">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Times New Roman</family>
|
||||
<pointsize>18</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">Current Version</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>7</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QPushButton" name="mCheckUpdateBtn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>92</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check For Updates</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="mOKBtn">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="9"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<designerdata>
|
||||
<property name="gridDeltaX">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridDeltaY">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridSnapX">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridSnapY">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</designerdata>
|
||||
</ui>
|
Loading…
Add table
Add a link
Reference in a new issue