2015-06-06 09:40:08 +08:00
|
|
|
/*
|
2018-04-13 04:02:28 +08:00
|
|
|
Copyright © 2015-2018 by The qTox Project Contributors
|
2015-06-06 09:40:08 +08:00
|
|
|
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
|
|
|
|
qTox is libre software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
qTox 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 General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2015-02-06 19:28:49 +08:00
|
|
|
#include "gui.h"
|
2016-05-12 05:17:36 +08:00
|
|
|
#include "widget.h"
|
2016-12-19 10:26:26 +08:00
|
|
|
#include "src/nexus.h"
|
2016-07-30 17:10:49 +08:00
|
|
|
#include <QApplication>
|
2015-02-06 19:28:49 +08:00
|
|
|
#include <QCoreApplication>
|
2015-02-07 02:01:31 +08:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QDialogButtonBox>
|
2015-02-06 19:28:49 +08:00
|
|
|
#include <QInputDialog>
|
2015-02-07 02:01:31 +08:00
|
|
|
#include <QLabel>
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPushButton>
|
2015-02-06 19:28:49 +08:00
|
|
|
#include <QThread>
|
2017-02-26 19:52:45 +08:00
|
|
|
#include <assert.h>
|
2015-02-06 19:28:49 +08:00
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @class GUI
|
|
|
|
* @brief Abstracts the GUI from the target backend (DesktopGUI, ...)
|
|
|
|
*
|
|
|
|
* All the functions exposed here are thread-safe.
|
|
|
|
* Prefer calling this class to calling a GUI backend directly.
|
|
|
|
*
|
|
|
|
* @fn void GUI::resized()
|
|
|
|
* @brief Emitted when the GUI is resized on supported platforms.
|
|
|
|
*/
|
2016-07-27 06:20:39 +08:00
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
GUI::GUI(QObject* parent)
|
|
|
|
: QObject(parent)
|
2015-02-06 19:28:49 +08:00
|
|
|
{
|
2015-02-07 02:01:31 +08:00
|
|
|
assert(QThread::currentThread() == qApp->thread());
|
|
|
|
assert(Nexus::getDesktopGUI());
|
2015-02-06 19:28:49 +08:00
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Returns the singleton instance.
|
|
|
|
*/
|
2015-02-06 19:28:49 +08:00
|
|
|
GUI& GUI::getInstance()
|
|
|
|
{
|
|
|
|
static GUI gui;
|
|
|
|
return gui;
|
|
|
|
}
|
|
|
|
|
2015-02-07 02:01:31 +08:00
|
|
|
// Implementation of the public clean interface
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Will enable or disable the GUI.
|
|
|
|
* @note A disabled GUI can't be interacted with by the user.
|
|
|
|
* @param state Enable/disable GUI.
|
|
|
|
*/
|
2015-02-07 02:01:31 +08:00
|
|
|
void GUI::setEnabled(bool state)
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-07 02:01:31 +08:00
|
|
|
getInstance()._setEnabled(state);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 02:01:31 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_setEnabled", Qt::BlockingQueuedConnection,
|
|
|
|
Q_ARG(bool, state));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Change the title of the main window.
|
|
|
|
* @param title Titile to set.
|
|
|
|
*
|
|
|
|
* This is usually always visible to the user.
|
|
|
|
*/
|
2015-02-07 02:01:31 +08:00
|
|
|
void GUI::setWindowTitle(const QString& title)
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-07 02:01:31 +08:00
|
|
|
getInstance()._setWindowTitle(title);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 02:01:31 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_setWindowTitle", Qt::BlockingQueuedConnection,
|
|
|
|
Q_ARG(const QString&, title));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Reloads the application theme and redraw the window.
|
|
|
|
*/
|
2015-02-07 02:01:31 +08:00
|
|
|
void GUI::reloadTheme()
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-07 02:01:31 +08:00
|
|
|
getInstance()._reloadTheme();
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 02:01:31 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_reloadTheme", Qt::BlockingQueuedConnection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Show some text to the user.
|
|
|
|
* @param title Title of information window.
|
|
|
|
* @param msg Text in information window.
|
|
|
|
*/
|
2015-02-07 19:46:55 +08:00
|
|
|
void GUI::showInfo(const QString& title, const QString& msg)
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-07 19:46:55 +08:00
|
|
|
getInstance()._showInfo(title, msg);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 19:46:55 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_showInfo", Qt::BlockingQueuedConnection,
|
2017-02-26 19:52:45 +08:00
|
|
|
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
|
2015-02-07 19:46:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Show a warning to the user
|
|
|
|
* @param title Title of warning window.
|
|
|
|
* @param msg Text in warning window.
|
|
|
|
*/
|
2015-02-07 02:01:31 +08:00
|
|
|
void GUI::showWarning(const QString& title, const QString& msg)
|
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-07 02:01:31 +08:00
|
|
|
getInstance()._showWarning(title, msg);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 02:01:31 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_showWarning", Qt::BlockingQueuedConnection,
|
2017-02-26 19:52:45 +08:00
|
|
|
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Show an error to the user.
|
|
|
|
* @param title Title of error window.
|
|
|
|
* @param msg Text in error window.
|
|
|
|
*/
|
2015-02-07 19:46:55 +08:00
|
|
|
void GUI::showError(const QString& title, const QString& msg)
|
2015-02-07 02:01:31 +08:00
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-12-17 18:24:01 +08:00
|
|
|
// If the GUI hasn't started yet and we're on the main thread,
|
|
|
|
// we still want to be able to show error messages
|
|
|
|
if (!Nexus::getDesktopGUI())
|
|
|
|
QMessageBox::critical(nullptr, title, msg);
|
|
|
|
else
|
|
|
|
getInstance()._showError(title, msg);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 19:46:55 +08:00
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_showError", Qt::BlockingQueuedConnection,
|
2017-02-26 19:52:45 +08:00
|
|
|
Q_ARG(const QString&, title), Q_ARG(const QString&, msg));
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Asks the user a question with Ok/Cancel or Yes/No buttons.
|
|
|
|
* @param title Title of question window.
|
|
|
|
* @param msg Text in question window.
|
|
|
|
* @param defaultAns If is true, default was positive answer. Negative otherwise.
|
|
|
|
* @param warning If is true, we will use a special warning style.
|
|
|
|
* @param yesno Show "Yes" and "No" buttons.
|
|
|
|
* @return True if the answer is positive, false otherwise.
|
|
|
|
*/
|
2017-02-26 19:52:45 +08:00
|
|
|
bool GUI::askQuestion(const QString& title, const QString& msg, bool defaultAns, bool warning, bool yesno)
|
2015-02-07 02:01:31 +08:00
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-02-20 23:36:35 +08:00
|
|
|
return getInstance()._askQuestion(title, msg, defaultAns, warning, yesno);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-02-07 02:01:31 +08:00
|
|
|
bool ret;
|
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_askQuestion", Qt::BlockingQueuedConnection,
|
2017-02-26 19:52:45 +08:00
|
|
|
Q_RETURN_ARG(bool, ret), Q_ARG(const QString&, title),
|
|
|
|
Q_ARG(const QString&, msg), Q_ARG(bool, defaultAns),
|
|
|
|
Q_ARG(bool, warning), Q_ARG(bool, yesno));
|
2015-02-07 02:01:31 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Asks the user a question.
|
|
|
|
*
|
|
|
|
* The text for the displayed buttons can be specified.
|
|
|
|
* @param title Title of question window.
|
|
|
|
* @param msg Text in question window.
|
|
|
|
* @param button1 Text of positive button.
|
|
|
|
* @param button2 Text of negative button.
|
|
|
|
* @param defaultAns If is true, default was positive answer. Negative otherwise.
|
|
|
|
* @param warning If is true, we will use a special warning style.
|
|
|
|
* @return True if the answer is positive, false otherwise.
|
|
|
|
*/
|
2017-02-26 19:52:45 +08:00
|
|
|
bool GUI::askQuestion(const QString& title, const QString& msg, const QString& button1,
|
|
|
|
const QString& button2, bool defaultAns, bool warning)
|
2015-03-15 01:26:31 +08:00
|
|
|
{
|
2017-02-26 19:52:45 +08:00
|
|
|
if (QThread::currentThread() == qApp->thread()) {
|
2015-03-15 01:26:31 +08:00
|
|
|
return getInstance()._askQuestion(title, msg, button1, button2, defaultAns, warning);
|
2017-02-26 19:52:45 +08:00
|
|
|
} else {
|
2015-03-15 01:26:31 +08:00
|
|
|
bool ret;
|
|
|
|
QMetaObject::invokeMethod(&getInstance(), "_askQuestion", Qt::BlockingQueuedConnection,
|
2017-02-26 19:52:45 +08:00
|
|
|
Q_RETURN_ARG(bool, ret), Q_ARG(const QString&, title),
|
|
|
|
Q_ARG(const QString&, msg), Q_ARG(bool, defaultAns),
|
|
|
|
Q_ARG(bool, warning));
|
2015-03-15 01:26:31 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-07 02:01:31 +08:00
|
|
|
// Private implementations
|
|
|
|
|
|
|
|
void GUI::_setEnabled(bool state)
|
|
|
|
{
|
2017-02-17 12:55:23 +08:00
|
|
|
Widget* w = Nexus::getDesktopGUI();
|
|
|
|
if (w)
|
|
|
|
w->setEnabled(state);
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GUI::_setWindowTitle(const QString& title)
|
|
|
|
{
|
2017-02-17 12:55:23 +08:00
|
|
|
QWidget* w = getMainWidget();
|
|
|
|
if (!w)
|
|
|
|
return;
|
2015-02-07 02:01:31 +08:00
|
|
|
if (title.isEmpty())
|
2017-02-17 12:55:23 +08:00
|
|
|
w->setWindowTitle("qTox");
|
2015-02-07 02:01:31 +08:00
|
|
|
else
|
2017-02-17 12:55:23 +08:00
|
|
|
w->setWindowTitle("qTox - " + title);
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void GUI::_reloadTheme()
|
|
|
|
{
|
2017-02-17 12:55:23 +08:00
|
|
|
Widget* w = Nexus::getDesktopGUI();
|
|
|
|
if (w)
|
|
|
|
w->reloadTheme();
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 19:46:55 +08:00
|
|
|
void GUI::_showInfo(const QString& title, const QString& msg)
|
|
|
|
{
|
2016-07-30 17:10:49 +08:00
|
|
|
QMessageBox messageBox(QMessageBox::Information, title, msg, QMessageBox::Ok, getMainWidget());
|
|
|
|
messageBox.setButtonText(QMessageBox::Ok, QApplication::tr("Ok"));
|
|
|
|
messageBox.exec();
|
2015-02-07 19:46:55 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 02:01:31 +08:00
|
|
|
void GUI::_showWarning(const QString& title, const QString& msg)
|
|
|
|
{
|
2016-07-30 17:10:49 +08:00
|
|
|
QMessageBox messageBox(QMessageBox::Warning, title, msg, QMessageBox::Ok, getMainWidget());
|
|
|
|
messageBox.setButtonText(QMessageBox::Ok, QApplication::tr("Ok"));
|
|
|
|
messageBox.exec();
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
2015-02-07 19:46:55 +08:00
|
|
|
void GUI::_showError(const QString& title, const QString& msg)
|
2015-02-07 02:01:31 +08:00
|
|
|
{
|
2016-07-30 17:10:49 +08:00
|
|
|
QMessageBox messageBox(QMessageBox::Critical, title, msg, QMessageBox::Ok, getMainWidget());
|
|
|
|
messageBox.setButtonText(QMessageBox::Ok, QApplication::tr("Ok"));
|
|
|
|
messageBox.exec();
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
bool GUI::_askQuestion(const QString& title, const QString& msg, bool defaultAns, bool warning,
|
2015-03-15 01:26:31 +08:00
|
|
|
bool yesno)
|
2015-02-07 02:01:31 +08:00
|
|
|
{
|
2016-07-30 17:10:49 +08:00
|
|
|
QString positiveButton = yesno ? QApplication::tr("Yes") : QApplication::tr("Ok");
|
|
|
|
QString negativeButton = yesno ? QApplication::tr("No") : QApplication::tr("Cancel");
|
2015-02-20 23:36:35 +08:00
|
|
|
|
2016-07-30 17:10:49 +08:00
|
|
|
return _askQuestion(title, msg, positiveButton, negativeButton, defaultAns, warning);
|
2015-02-07 02:01:31 +08:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:52:45 +08:00
|
|
|
bool GUI::_askQuestion(const QString& title, const QString& msg, const QString& button1,
|
|
|
|
const QString& button2, bool defaultAns, bool warning)
|
2015-03-15 01:26:31 +08:00
|
|
|
{
|
2016-07-30 17:10:49 +08:00
|
|
|
QMessageBox::Icon icon = warning ? QMessageBox::Warning : QMessageBox::Question;
|
|
|
|
QMessageBox box(icon, title, msg, QMessageBox::NoButton, getMainWidget());
|
2015-03-15 01:26:31 +08:00
|
|
|
QPushButton* pushButton1 = box.addButton(button1, QMessageBox::AcceptRole);
|
|
|
|
QPushButton* pushButton2 = box.addButton(button2, QMessageBox::RejectRole);
|
|
|
|
box.setDefaultButton(defaultAns ? pushButton1 : pushButton2);
|
|
|
|
box.setEscapeButton(pushButton2);
|
|
|
|
|
|
|
|
box.exec();
|
|
|
|
return box.clickedButton() == pushButton1;
|
|
|
|
}
|
|
|
|
|
2015-02-07 02:01:31 +08:00
|
|
|
// Other
|
|
|
|
|
2016-07-27 06:20:39 +08:00
|
|
|
/**
|
2016-08-01 16:21:23 +08:00
|
|
|
* @brief Get the main widget.
|
|
|
|
* @return The main QWidget* of the application
|
|
|
|
*/
|
2015-02-07 02:01:31 +08:00
|
|
|
QWidget* GUI::getMainWidget()
|
|
|
|
{
|
|
|
|
QWidget* maingui{nullptr};
|
|
|
|
maingui = Nexus::getDesktopGUI();
|
|
|
|
return maingui;
|
|
|
|
}
|