Move from Qt Quick to Qt Widgets.

Qt Quick is not really usable for desktop programs.
This commit is contained in:
tastytea 2020-02-25 23:15:21 +01:00
parent 90125ac8d4
commit acd3e201a6
Signed by: tastytea
GPG Key ID: CFC39497F1B26E07
13 changed files with 402 additions and 200 deletions

View File

@ -16,7 +16,7 @@
:uri-dpkg: https://packages.qa.debian.org/dpkg
:uri-rpm-build: http://www.rpm.org
:uri-clang-tidy: https://clang.llvm.org/extra/clang-tidy/
:uri-qt-install: https://doc.qt.io/qt-5/gettingstarted.html
:uri-qt: https://doc.qt.io/qt-5/gettingstarted.html
*{project}* is a client for link:{uri-wp-fediverse}[Fediverse] servers.
// It currently supports link:{uri-wp-mastodon}[Mastodon] and
@ -64,7 +64,7 @@
link:{uri-clang}[clang] 6/7)
* link:{uri-cmake}[CMake] (at least: 3.9)
* link:{uri-mastodonpp}[mastodonpp] (at least: 0.5)
* link:{uri-qt-install}[Qt] with QtQuick (at least: 5.10)
* link:{uri-qt}[Qt] (tested: 5.13)
* Optional
** Library documentation: link:{uri-doxygen}[Doxygen] (tested: 1.8)
** Tests: link:{uri-catch}[Catch] (tested: 2.5 / 1.2)

View File

@ -1,8 +1,6 @@
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/">
<file>qml/mainwindow.qml</file>
<file>qml/DialogAbout.qml</file>
<file alias="AUTHORS">../AUTHORS</file>
</qresource>
</RCC>

View File

@ -1,68 +0,0 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
Window
{
id: win_about
title: qsTr("About FediPotato") + " " + QMLBridge.get_version()
flags: Qt.Dialog
modality: Qt.NonModal
minimumWidth: label_description.width * 2
minimumHeight: label_description.width
TabBar
{
id: tabbar_about
width: parent.width
TabButton
{
text: qsTr("About")
}
TabButton
{
text: qsTr("Authors")
}
}
StackLayout {
id: layout_about
anchors.top: tabbar_about.bottom
width: parent.width
currentIndex: tabbar_about.currentIndex
ColumnLayout
{
width: parent.width
Label
{
id: label_description
text: "<b>" + qsTr("Client for Fediverse servers.") + "</b>"
}
Label
{
id: label_license
Layout.fillWidth: true
wrapMode: Text.WordWrap
onLinkActivated: Qt.openUrlExternally(link)
text: qsTr("License AGPL-3.0-only: <a href='" +
"https://www.gnu.org/licenses/agpl-3.0.txt'>" +
"GNU Affero GPL version 3</a>.<br>" +
"This program comes with ABSOLUTELY NO WARRANTY. " +
"This is free software, and you are welcome to " +
"redistribute it under certain conditions.")
}
}
Label
{
id: label_authors
text: QMLBridge.get_authors()
}
}
}

View File

@ -1,50 +0,0 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
ApplicationWindow
{
id: win_main
title: "FediPotato"
visible: true
width: 400
height: 500
menuBar: MenuBar
{
Menu
{
title: "&FediPotato"
MenuItem
{
id: menu_exit
text: qsTr("Exit")
onTriggered: Qt.quit()
Shortcut
{
sequence: "Ctrl+Q"
context: Qt.ApplicationShortcut
onActivated: menu_exit.clicked()
}
}
}
Menu
{
title: qsTr("&Help")
MenuItem
{
text: qsTr("Website")
onTriggered: Qt.openUrlExternally("http://fedipotato.org/")
}
MenuItem
{
text: qsTr("About FediPotato")
onTriggered: win_about.show()
DialogAbout { id: win_about }
}
}
}
}

View File

@ -1,9 +1,10 @@
include(GNUInstallDirs)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 5.10 COMPONENTS Core Gui Qml Quick CONFIG REQUIRED)
find_package(Qt5 COMPONENTS Core Gui Widgets CONFIG REQUIRED)
add_executable(${PROJECT_NAME}GUI)
@ -16,7 +17,7 @@ target_sources(${PROJECT_NAME}GUI
PRIVATE "${sources_gui}" "../${PROJECT_NAME}.qrc")
target_link_libraries(${PROJECT_NAME}GUI
PRIVATE ${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Qml Qt5::Quick)
PRIVATE ${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets)
install(TARGETS ${PROJECT_NAME}GUI
DESTINATION "${CMAKE_INSTALL_BINDIR}")

29
gui/src/dialog_about.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "dialog_about.hpp"
#include <QFile>
namespace FediPotato
{
DialogAbout::DialogAbout(QDialog *parent)
: QDialog(parent)
{
setupUi(this);
display_authors();
}
void DialogAbout::display_authors() const
{
QFile file(":/AUTHORS");
if (file.open(QIODevice::ReadOnly))
{
label_authors->setText(file.readAll());
}
else
{
label_authors->setText(tr("Could not open :/AUTHORS."));
}
}
} // namespace FediPotato

41
gui/src/dialog_about.hpp Normal file
View File

@ -0,0 +1,41 @@
#ifndef FEDIPOTATO_GUI_DIALOG_ABOUT_HPP
#define FEDIPOTATO_GUI_DIALOG_ABOUT_HPP
#include "../ui/ui_dialog_about.h"
#include <QDialog>
#include <QLabel>
namespace FediPotato
{
class DialogAbout : public QDialog, private Ui::DialogAbout
{
public:
//! Default constructor
explicit DialogAbout(QDialog *parent = nullptr);
//! Copy constructor
DialogAbout(const DialogAbout &other) = delete;
//! Move constructor
DialogAbout(DialogAbout &&other) noexcept = delete;
//! Destructor
~DialogAbout() noexcept override = default;
//! Copy assignment operator
DialogAbout& operator=(const DialogAbout &other) = delete;
//! Move assignment operator
DialogAbout& operator=(DialogAbout &&other) noexcept = delete;
public:
private:
void display_authors() const;
};
} // namespace FediPotato
#endif // FEDIPOTATO_GUI_DIALOG_ABOUT_HPP

View File

@ -14,24 +14,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qmlbridge.hpp"
#include "window_main.hpp"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTranslator>
#include <QLibraryInfo>
using namespace FediPotato;
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QApplication app(argc, argv);
QGuiApplication::setApplicationName("FediPotato");
QMLBridge qmlbridge;
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QGuiApplication::installTranslator(&qtTranslator);
QQmlApplicationEngine engine;
// Make qmlbridge callable as QMLBridge in QML files.
engine.rootContext()->setContextProperty("QMLBridge", &qmlbridge);
engine.load(QUrl(QStringLiteral("qrc:/qml/mainwindow.qml")));
QTranslator appTranslator;
appTranslator.load("FediPotato_" + QLocale::system().name(),
QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QGuiApplication::installTranslator(&appTranslator);
WindowMain win;
win.show();
return QGuiApplication::exec();
}

View File

@ -1,50 +0,0 @@
/* This file is part of FediPotato.
* Copyright © 2020 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FEDIPOTATO_GUI_QMLBRIDGE_HPP
#define FEDIPOTATO_GUI_QMLBRIDGE_HPP
#include <QObject>
#include <QString>
namespace FediPotato
{
class QMLBridge : public QObject
{
Q_OBJECT
public:
explicit QMLBridge(QObject *parent = nullptr);
/*!
* @brief Return the version.
*
* @since 0.1.0
*/
Q_INVOKABLE static QString get_version();
/*!
* @brief Return the authors listed in AUTHORS.
*
* @since 0.1.0
*/
Q_INVOKABLE static QString get_authors();
};
} // namespace FediPotato
#endif // FEDIPOTATO_GUI_QMLBRIDGE_HPP

View File

@ -14,32 +14,31 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qmlbridge.hpp"
#include "fedipotato.hpp"
#include "window_main.hpp"
#include "dialog_about.hpp"
#include <QFile>
#include <QDesktopServices>
#include <QUrl>
namespace FediPotato
{
QMLBridge::QMLBridge(QObject *parent)
: QObject(parent)
{}
QString QMLBridge::get_version()
WindowMain::WindowMain(QMainWindow *parent)
: QMainWindow(parent)
{
return FediPotato::get_version().data();
setupUi(this);
}
QString QMLBridge::get_authors()
void WindowMain::show_about()
{
QFile file(":/AUTHORS");
if (file.open(QIODevice::ReadOnly))
{
return file.readAll();
}
return "Could not open :/AUTHORS.";
auto *dlg = new DialogAbout(); // NOLINT(cppcoreguidelines-owning-memory)
dlg->show();
}
void WindowMain::open_website()
{
QDesktopServices::openUrl(QUrl("http://fedipotato.org/"));
}
} // namespace FediPotato

44
gui/src/window_main.hpp Normal file
View File

@ -0,0 +1,44 @@
#ifndef FEDIPOTATO_GUI_WINDOW_MAIN_HPP
#define FEDIPOTATO_GUI_WINDOW_MAIN_HPP
#include "../ui/ui_window_main.h"
#include <QMainWindow>
#include <QLabel>
namespace FediPotato
{
class WindowMain : public QMainWindow, private Ui::WindowMain
{
Q_OBJECT
public:
//! Default constructor
explicit WindowMain(QMainWindow *parent = nullptr);
//! Copy constructor
WindowMain(const WindowMain &other) = delete;
//! Move constructor
WindowMain(WindowMain &&other) noexcept = delete;
//! Destructor
~WindowMain() noexcept override = default;
//! Copy assignment operator
WindowMain& operator=(const WindowMain &other) = delete;
//! Move assignment operator
WindowMain& operator=(WindowMain &&other) noexcept = delete;
public:
private slots:
static void show_about();
static void open_website();
};
} // namespace FediPotato
#endif // FEDIPOTATO_GUI_WINDOW_MAIN_HPP

134
gui/ui/dialog_about.ui Normal file
View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DialogAbout</class>
<widget class="QDialog" name="DialogAbout">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>187</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>About FediPotato</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTabWidget" name="tabs">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_about">
<attribute name="title">
<string>About</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QLabel" name="label_description">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;b&gt;Client for Fediverse servers.&lt;/b&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_license">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>License AGPL-3.0-only: &lt;a href=&quot;https://www.gnu.org/licenses/agpl-3.0.txt&quot;&gt; GNU Affero GPL version 3&lt;/a&gt;.&lt;br&gt;
This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_authors">
<attribute name="title">
<string>Authors</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>116</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_authors">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

117
gui/ui/window_main.ui Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WindowMain</class>
<widget class="QMainWindow" name="WindowMain">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>FediPotato</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuFediPotato">
<property name="title">
<string>&amp;FediPotato</string>
</property>
<addaction name="action_quit"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="action_website"/>
<addaction name="action_about"/>
</widget>
<addaction name="menuFediPotato"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="action_quit">
<property name="text">
<string>Quit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="action_website">
<property name="text">
<string>Website</string>
</property>
</action>
<action name="action_about">
<property name="text">
<string>About FediPotato</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>action_about</sender>
<signal>triggered()</signal>
<receiver>WindowMain</receiver>
<slot>show_about()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>action_quit</sender>
<signal>triggered()</signal>
<receiver>WindowMain</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>action_website</sender>
<signal>triggered()</signal>
<receiver>WindowMain</receiver>
<slot>open_website()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>show_about()</slot>
<slot>open_website()</slot>
</slots>
</ui>