Other: C++ Code reformat.

This commit is contained in:
Xavier Michelon
2023-01-05 08:37:38 +01:00
parent bb07138fb0
commit 8790d3cfcf
58 changed files with 1348 additions and 1692 deletions

View File

@ -30,8 +30,7 @@ using namespace bridgepp;
//****************************************************************************************************************************************************
/// \return The AppController instance.
//****************************************************************************************************************************************************
AppController &app()
{
AppController &app() {
static AppController app;
return app;
}
@ -43,24 +42,24 @@ AppController &app()
AppController::AppController()
: backend_(std::make_unique<QMLBackend>())
, grpc_(std::make_unique<GRPCClient>())
, log_(std::make_unique<Log>())
{
, log_(std::make_unique<Log>()) {
}
//****************************************************************************************************************************************************
/// \return The bridge worker, which can be null if the application was run in 'attach' mode (-a command-line switch).
//****************************************************************************************************************************************************
ProcessMonitor *AppController::bridgeMonitor() const
{
if (!bridgeOverseer_)
ProcessMonitor *AppController::bridgeMonitor() const {
if (!bridgeOverseer_) {
return nullptr;
}
// null bridgeOverseer is OK, it means we run in 'attached' mode (app attached to an already runnning instance of Bridge).
// but if bridgeOverseer is not null, its attached worker must be a valid ProcessMonitor instance.
auto *monitor = dynamic_cast<ProcessMonitor*>(bridgeOverseer_->worker());
if (!monitor)
auto *monitor = dynamic_cast<ProcessMonitor *>(bridgeOverseer_->worker());
if (!monitor) {
throw Exception("Could not retrieve bridge monitor");
}
return monitor;
}

View File

@ -23,11 +23,16 @@
class QMLBackend;
namespace bridgepp
{
namespace bridgepp {
class Log;
class Overseer;
class GRPCClient;
class ProcessMonitor;
}
@ -35,22 +40,21 @@ class ProcessMonitor;
//****************************************************************************************************************************************************
/// \brief App controller class.
//****************************************************************************************************************************************************
class AppController: public QObject
{
Q_OBJECT
friend AppController& app();
class AppController : public QObject {
Q_OBJECT
friend AppController &app();
public: // member functions.
AppController(AppController const&) = delete; ///< Disabled copy-constructor.
AppController(AppController&&) = delete; ///< Disabled assignment copy-constructor.
AppController(AppController const &) = delete; ///< Disabled copy-constructor.
AppController(AppController &&) = delete; ///< Disabled assignment copy-constructor.
~AppController() override = default; ///< Destructor.
AppController& operator=(AppController const&) = delete; ///< Disabled assignment operator.
AppController& operator=(AppController&&) = delete; ///< Disabled move assignment operator.
QMLBackend& backend() { return *backend_; } ///< Return a reference to the backend.
bridgepp::GRPCClient& grpc() { return *grpc_; } ///< Return a reference to the GRPC client.
bridgepp::Log& log() { return *log_; } ///< Return a reference to the log.
std::unique_ptr<bridgepp::Overseer>& bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer
bridgepp::ProcessMonitor* bridgeMonitor() const; ///< Return the bridge worker.
AppController &operator=(AppController const &) = delete; ///< Disabled assignment operator.
AppController &operator=(AppController &&) = delete; ///< Disabled move assignment operator.
QMLBackend &backend() { return *backend_; } ///< Return a reference to the backend.
bridgepp::GRPCClient &grpc() { return *grpc_; } ///< Return a reference to the GRPC client.
bridgepp::Log &log() { return *log_; } ///< Return a reference to the log.
std::unique_ptr<bridgepp::Overseer> &bridgeOverseer() { return bridgeOverseer_; }; ///< Returns a reference the bridge overseer
bridgepp::ProcessMonitor *bridgeMonitor() const; ///< Return the bridge worker.
private: // member functions
AppController(); ///< Default constructor.
@ -63,7 +67,7 @@ private: // data members
};
AppController& app(); ///< Return a reference to the app controller.
AppController &app(); ///< Return a reference to the app controller.
#endif // BRIDGE_GUI_APP_CONTROLLER_H

View File

@ -23,8 +23,7 @@
using namespace bridgepp;
namespace
{
namespace {
QString const launcherFlag = "--launcher"; ///< launcher flag parameter used for bridge.
@ -37,25 +36,25 @@ QString const softwareRendererFlag = "--software-renderer"; ///< The 'software-r
/// \param[in] argv The list of arguments passed to the application.
/// \param[in] paramNames the list of names for the parameter
//****************************************************************************************************************************************************
QString parseGoCLIStringArgument(int argc, char *argv[], QStringList paramNames)
{
QString parseGoCLIStringArgument(int argc, char *argv[], QStringList paramNames) {
// go cli package is pretty permissive when it comes to parsing arguments. For each name 'param', all the following seems to be accepted:
// -param value
// --param value
// -param=value
// --param=value
for (QString const &paramName: paramNames)
for (qsizetype i = 1; i < argc; ++i)
{
for (QString const &paramName: paramNames) {
for (qsizetype i = 1; i < argc; ++i) {
QString const arg(QString::fromLocal8Bit(argv[i]));
if ((i < argc - 1) && ((arg == "-" + paramName) || (arg == "--" + paramName)))
if ((i < argc - 1) && ((arg == "-" + paramName) || (arg == "--" + paramName))) {
return QString(argv[i + 1]);
}
QRegularExpressionMatch match = QRegularExpression(QString("^-{1,2}%1=(.+)$").arg(paramName)).match(arg);
if (match.hasMatch())
if (match.hasMatch()) {
return match.captured(1);
}
}
}
return QString();
}
@ -68,11 +67,11 @@ QString parseGoCLIStringArgument(int argc, char *argv[], QStringList paramNames)
/// \param[in] argv The list of arguments passed to the application.
/// \return The log level. if not specified on the command-line, the default log level is returned.
//****************************************************************************************************************************************************
Log::Level parseLogLevel(int argc, char *argv[])
{
Log::Level parseLogLevel(int argc, char *argv[]) {
QString levelStr = parseGoCLIStringArgument(argc, argv, { "l", "log-level" });
if (levelStr.isEmpty())
if (levelStr.isEmpty()) {
return Log::defaultLevel;
}
Log::Level level = Log::defaultLevel;
Log::stringToLevel(levelStr, level);
@ -98,33 +97,29 @@ CommandLineOptions parseCommandLine(int argc, char *argv[]) {
QString const &arg = QString::fromLocal8Bit(argv[i]);
// we can't use QCommandLineParser here since it will fail on unknown options.
// Arguments may contain some bridge flags.
if (arg == softwareRendererFlag)
if (arg == softwareRendererFlag) {
options.useSoftwareRenderer = true;
if (arg == noWindowFlag)
{
}
if (arg == noWindowFlag) {
options.noWindow = true;
}
if (arg == launcherFlag)
{
if (arg == launcherFlag) {
options.bridgeArgs.append(arg);
options.launcher = QString::fromLocal8Bit(argv[++i]);
options.bridgeArgs.append(options.launcher);
flagFound = true;
}
#ifdef QT_DEBUG
else if (arg == "--attach" || arg == "-a")
{
else if (arg == "--attach" || arg == "-a") {
// we don't keep the attach mode within the args since we don't need it for Bridge.
options.attach = true;
}
#endif
else
{
else {
options.bridgeArgs.append(arg);
}
}
if (!flagFound)
{
if (!flagFound) {
// add bridge-gui as launcher
options.bridgeArgs.append(launcherFlag);
options.bridgeArgs.append(options.launcher);

View File

@ -22,6 +22,8 @@
void setDockIconVisibleState(bool visible) { Q_UNUSED(visible) }
bool getDockIconVisibleState() { return true; }

View File

@ -30,8 +30,7 @@ using namespace bridgepp;
/// \param[in] parent The parent object.
//****************************************************************************************************************************************************
EventStreamReader::EventStreamReader(QObject *parent)
: Worker(parent)
{
: Worker(parent) {
connect(this, &EventStreamReader::started, this, &EventStreamReader::onStarted);
connect(this, &EventStreamReader::finished, this, &EventStreamReader::onFinished);
connect(this, &EventStreamReader::error, &app().log(), &Log::error);
@ -41,20 +40,18 @@ EventStreamReader::EventStreamReader(QObject *parent)
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void EventStreamReader::run()
{
try
{
void EventStreamReader::run() {
try {
emit started();
grpc::Status const status = app().grpc().runEventStreamReader();
if (!status.ok())
if (!status.ok()) {
throw Exception(QString::fromStdString(status.error_message()));
}
emit finished();
}
catch (Exception const &e)
{
catch (Exception const &e) {
reportSentryException(SENTRY_LEVEL_ERROR, "Error during event stream read", "Exception", e.what());
emit error(e.qwhat());
}
@ -64,8 +61,7 @@ void EventStreamReader::run()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void EventStreamReader::onStarted() const
{
void EventStreamReader::onStarted() const {
app().log().debug("EventStreamReader started");
}
@ -73,11 +69,9 @@ void EventStreamReader::onStarted() const
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void EventStreamReader::onFinished() const
{
void EventStreamReader::onFinished() const {
app().log().debug("EventStreamReader finished");
if (!app().bridgeMonitor())
{
if (!app().bridgeMonitor()) {
// no bridge monitor means we are in a debug environment, running in attached mode. Event stream has terminated, so bridge is shutting
// down. Because we're in attached mode, bridge-gui will not get notified that bridge is going down, so we shutdown manually here.
qApp->exit(EXIT_SUCCESS);

View File

@ -26,16 +26,15 @@
//****************************************************************************************************************************************************
/// \brief Stream reader class.
//****************************************************************************************************************************************************
class EventStreamReader: public bridgepp::Worker
{
Q_OBJECT
class EventStreamReader : public bridgepp::Worker {
Q_OBJECT
public: // member functions
explicit EventStreamReader(QObject *parent); ///< Default constructor.
EventStreamReader(EventStreamReader const&) = delete; ///< Disabled copy-constructor.
EventStreamReader(EventStreamReader&&) = delete; ///< Disabled assignment copy-constructor.
EventStreamReader(EventStreamReader const &) = delete; ///< Disabled copy-constructor.
EventStreamReader(EventStreamReader &&) = delete; ///< Disabled assignment copy-constructor.
~EventStreamReader() override = default; ///< Destructor.
EventStreamReader& operator=(EventStreamReader const&) = delete; ///< Disabled assignment operator.
EventStreamReader& operator=(EventStreamReader&&) = delete; ///< Disabled move assignment operator.
EventStreamReader &operator=(EventStreamReader const &) = delete; ///< Disabled assignment operator.
EventStreamReader &operator=(EventStreamReader &&) = delete; ///< Disabled move assignment operator.
public slots:
void run() override; ///< Run the reader.

View File

@ -31,38 +31,38 @@ using namespace bridgepp;
//
//****************************************************************************************************************************************************
QMLBackend::QMLBackend()
: QObject()
{
: QObject() {
}
//****************************************************************************************************************************************************
/// \param[in] serviceConfig
//****************************************************************************************************************************************************
void QMLBackend::init(GRPCConfig const &serviceConfig)
{
void QMLBackend::init(GRPCConfig const &serviceConfig) {
users_ = new UserList(this);
Log& log = app().log();
Log &log = app().log();
log.info(QString("Connecting to gRPC service"));
app().grpc().setLog(&log);
this->connectGrpcEvents();
QString error;
if (app().grpc().connectToServer(serviceConfig, app().bridgeMonitor(), error))
if (app().grpc().connectToServer(serviceConfig, app().bridgeMonitor(), error)) {
app().log().info("Connected to backend via gRPC service.");
else
} else {
throw Exception(QString("Cannot connectToServer to go backend via gRPC: %1").arg(error));
}
QString bridgeVer;
app().grpc().version(bridgeVer);
if (bridgeVer != PROJECT_VER)
if (bridgeVer != PROJECT_VER) {
throw Exception(QString("Version Mismatched from Bridge (%1) and Bridge-GUI (%2)").arg(bridgeVer, PROJECT_VER));
}
eventStreamOverseer_ = std::make_unique<Overseer>(new EventStreamReader(nullptr), nullptr);
eventStreamOverseer_->startWorker(true);
connect(&app().log(), &Log::entryAdded, [&](Log::Level level, QString const& message) {
connect(&app().log(), &Log::entryAdded, [&](Log::Level level, QString const &message) {
app().grpc().addLogEntry(level, "frontend/bridge-gui", message);
});
@ -87,8 +87,7 @@ void QMLBackend::init(GRPCConfig const &serviceConfig)
/// never times out.
/// \return false if and only if the timeout delay was reached.
//****************************************************************************************************************************************************
bool QMLBackend::waitForEventStreamReaderToFinish(qint32 timeoutMs)
{
bool QMLBackend::waitForEventStreamReaderToFinish(qint32 timeoutMs) {
return eventStreamOverseer_->wait(timeoutMs);
}
@ -96,12 +95,11 @@ bool QMLBackend::waitForEventStreamReaderToFinish(qint32 timeoutMs)
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::connectGrpcEvents()
{
void QMLBackend::connectGrpcEvents() {
GRPCClient *client = &app().grpc();
// app events
connect(client, &GRPCClient::internetStatus, this, [&](bool isOn) { if (isOn) emit internetOn(); else emit internetOff(); });
connect(client, &GRPCClient::internetStatus, this, [&](bool isOn) { if (isOn) { emit internetOn(); } else { emit internetOff(); }});
connect(client, &GRPCClient::toggleAutostartFinished, this, &QMLBackend::toggleAutostartFinished);
connect(client, &GRPCClient::resetFinished, this, &QMLBackend::onResetFinished);
connect(client, &GRPCClient::reportBugFinished, this, &QMLBackend::reportBugFinished);
@ -174,8 +172,7 @@ void QMLBackend::connectGrpcEvents()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::retrieveUserList()
{
void QMLBackend::retrieveUserList() {
QList<SPUser> newUsers;
app().grpc().getUserList(newUsers);
@ -184,23 +181,22 @@ void QMLBackend::retrieveUserList()
// " When data is transferred from C++ to QML, the ownership of the data always remains with C++. The exception to this rule
// is when a QObject is returned from an explicit C++ method call: in this case, the QML engine assumes ownership of the object. "
// This is the case here, so we explicitly indicate that the object is owned by C++.
for (SPUser const& user: newUsers)
for (SPUser const &user: newUsers) {
for (qsizetype i = 0; i < newUsers.size(); ++i)
{
SPUser newUser = newUsers[i];
SPUser existingUser = users_->getUserWithID(newUser->id());
if (!existingUser)
{
// The user is new. We indicate to QML that it is managed by the C++ backend.
QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership);
continue;
for (qsizetype i = 0; i < newUsers.size(); ++i) {
SPUser newUser = newUsers[i];
SPUser existingUser = users_->getUserWithID(newUser->id());
if (!existingUser) {
// The user is new. We indicate to QML that it is managed by the C++ backend.
QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership);
continue;
}
// The user is already listed. QML code may have a pointer because of an ongoing process (for instance in the SetupGuide),
// As a consequence we do not want to replace this existing user, but we want to update it.
existingUser->update(*newUser);
newUsers[i] = existingUser;
}
// The user is already listed. QML code may have a pointer because of an ongoing process (for instance in the SetupGuide),
// As a consequence we do not want to replace this existing user, but we want to update it.
existingUser->update(*newUser);
newUsers[i] = existingUser;
}
users_->reset(newUsers);
@ -210,8 +206,7 @@ void QMLBackend::retrieveUserList()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
QPoint QMLBackend::getCursorPos()
{
QPoint QMLBackend::getCursorPos() {
return QCursor::pos();
}
@ -219,8 +214,7 @@ QPoint QMLBackend::getCursorPos()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
bool QMLBackend::isPortFree(int port)
{
bool QMLBackend::isPortFree(int port) {
bool isFree = false;
app().grpc().isPortFree(port, isFree);
return isFree;
@ -230,8 +224,7 @@ bool QMLBackend::isPortFree(int port)
//****************************************************************************************************************************************************
/// \return true the native local file path of the given URL.
//****************************************************************************************************************************************************
QString QMLBackend::nativePath(QUrl const &url)
{
QString QMLBackend::nativePath(QUrl const &url) {
return QDir::toNativeSeparators(url.toLocalFile());
}
@ -239,8 +232,7 @@ QString QMLBackend::nativePath(QUrl const &url)
//****************************************************************************************************************************************************
/// \return true iff the two URL point to the same local file or folder.
//****************************************************************************************************************************************************
bool QMLBackend::areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs)
{
bool QMLBackend::areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs) {
return QFileInfo(lhs.toLocalFile()) == QFileInfo(rhs.toLocalFile());
}
@ -248,8 +240,7 @@ bool QMLBackend::areSameFileOrFolder(QUrl const &lhs, QUrl const &rhs)
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::guiReady()
{
void QMLBackend::guiReady() {
app().grpc().guiReady();
}
@ -257,8 +248,7 @@ void QMLBackend::guiReady()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::quit()
{
void QMLBackend::quit() {
app().grpc().quit();
qApp->exit(0);
}
@ -267,8 +257,7 @@ void QMLBackend::quit()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::restart()
{
void QMLBackend::restart() {
app().grpc().restart();
}
@ -276,8 +265,7 @@ void QMLBackend::restart()
//****************************************************************************************************************************************************
/// \param[in] launcher The path to the launcher.
//****************************************************************************************************************************************************
void QMLBackend::forceLauncher(QString launcher)
{
void QMLBackend::forceLauncher(QString launcher) {
app().grpc().forceLauncher(launcher);
}
@ -285,8 +273,7 @@ void QMLBackend::forceLauncher(QString launcher)
//****************************************************************************************************************************************************
/// \param[in] active Should we activate autostart.
//****************************************************************************************************************************************************
void QMLBackend::toggleAutostart(bool active)
{
void QMLBackend::toggleAutostart(bool active) {
app().grpc().setIsAutostartOn(active);
emit isAutostartOnChanged(this->isAutostartOn());
}
@ -295,17 +282,16 @@ void QMLBackend::toggleAutostart(bool active)
//****************************************************************************************************************************************************
/// \param[in] active The new state for the beta enabled property.
//****************************************************************************************************************************************************
void QMLBackend::toggleBeta(bool active)
{
void QMLBackend::toggleBeta(bool active) {
app().grpc().setIsBetaEnabled(active);
emit isBetaEnabledChanged(this->isBetaEnabled());
}
//****************************************************************************************************************************************************
/// \param[in] active The new state for the All Mail visibility property.
//****************************************************************************************************************************************************
void QMLBackend::changeIsAllMailVisible(bool isVisible)
{
void QMLBackend::changeIsAllMailVisible(bool isVisible) {
app().grpc().setIsAllMailVisible(isVisible);
emit isAllMailVisibleChanged(this->isAllMailVisible());
}
@ -314,17 +300,16 @@ void QMLBackend::changeIsAllMailVisible(bool isVisible)
//****************************************************************************************************************************************************
/// \param[in] scheme the scheme name
//****************************************************************************************************************************************************
void QMLBackend::changeColorScheme(QString const &scheme)
{
void QMLBackend::changeColorScheme(QString const &scheme) {
app().grpc().setColorSchemeName(scheme);
emit colorSchemeNameChanged(this->colorSchemeName());
}
//****************************************************************************************************************************************************
/// \param[in] path The path of the disk cache.
//****************************************************************************************************************************************************
void QMLBackend::setDiskCachePath(QUrl const &path) const
{
void QMLBackend::setDiskCachePath(QUrl const &path) const {
app().grpc().setDiskCachePath(path);
}
@ -332,8 +317,7 @@ void QMLBackend::setDiskCachePath(QUrl const &path) const
//****************************************************************************************************************************************************
/// \return The IMAP port.
//****************************************************************************************************************************************************
int QMLBackend::imapPort() const
{
int QMLBackend::imapPort() const {
return imapPort_;
}
@ -341,10 +325,10 @@ int QMLBackend::imapPort() const
//****************************************************************************************************************************************************
/// \param[in] port The IMAP port.
//****************************************************************************************************************************************************
void QMLBackend::setIMAPPort(int port)
{
if (port == imapPort_)
void QMLBackend::setIMAPPort(int port) {
if (port == imapPort_) {
return;
}
imapPort_ = port;
emit imapPortChanged(port);
}
@ -353,8 +337,7 @@ void QMLBackend::setIMAPPort(int port)
//****************************************************************************************************************************************************
/// \return The SMTP port.
//****************************************************************************************************************************************************
int QMLBackend::smtpPort() const
{
int QMLBackend::smtpPort() const {
return smtpPort_;
}
@ -362,10 +345,10 @@ int QMLBackend::smtpPort() const
//****************************************************************************************************************************************************
/// \param[in] port The SMTP port.
//****************************************************************************************************************************************************
void QMLBackend::setSMTPPort(int port)
{
if (port == smtpPort_)
void QMLBackend::setSMTPPort(int port) {
if (port == smtpPort_) {
return;
}
smtpPort_ = port;
emit smtpPortChanged(port);
}
@ -374,8 +357,7 @@ void QMLBackend::setSMTPPort(int port)
//****************************************************************************************************************************************************
/// \return The value for the 'Use SSL for IMAP' property.
//****************************************************************************************************************************************************
bool QMLBackend::useSSLForIMAP() const
{
bool QMLBackend::useSSLForIMAP() const {
return useSSLForIMAP_;
}
@ -383,10 +365,10 @@ bool QMLBackend::useSSLForIMAP() const
//****************************************************************************************************************************************************
/// \param[in] value The value for the 'Use SSL for IMAP' property.
//****************************************************************************************************************************************************
void QMLBackend::setUseSSLForIMAP(bool value)
{
if (value == useSSLForIMAP_)
void QMLBackend::setUseSSLForIMAP(bool value) {
if (value == useSSLForIMAP_) {
return;
}
useSSLForIMAP_ = value;
emit useSSLForIMAPChanged(value);
}
@ -395,8 +377,7 @@ void QMLBackend::setUseSSLForIMAP(bool value)
//****************************************************************************************************************************************************
/// \return The value for the 'Use SSL for SMTP' property.
//****************************************************************************************************************************************************
bool QMLBackend::useSSLForSMTP() const
{
bool QMLBackend::useSSLForSMTP() const {
return useSSLForSMTP_;
}
@ -404,10 +385,10 @@ bool QMLBackend::useSSLForSMTP() const
//****************************************************************************************************************************************************
/// \param[in] value The value for the 'Use SSL for SMTP' property.
//****************************************************************************************************************************************************
void QMLBackend::setUseSSLForSMTP(bool value)
{
if (value == useSSLForSMTP_)
void QMLBackend::setUseSSLForSMTP(bool value) {
if (value == useSSLForSMTP_) {
return;
}
useSSLForSMTP_ = value;
emit useSSLForSMTPChanged(value);
}
@ -419,8 +400,7 @@ void QMLBackend::setUseSSLForSMTP(bool value)
/// \param[in] useSSLForIMAP The value for the 'Use SSL for IMAP' property
/// \param[in] useSSLForSMTP The value for the 'Use SSL for SMTP' property
//****************************************************************************************************************************************************
void QMLBackend::setMailServerSettings(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP)
{
void QMLBackend::setMailServerSettings(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP) {
app().grpc().setMailServerSettings(imapPort, smtpPort, useSSLForIMAP, useSSLForSMTP);
}
@ -429,8 +409,7 @@ void QMLBackend::setMailServerSettings(int imapPort, int smtpPort, bool useSSLFo
/// \param[in] userID the userID.
/// \param[in] wasSignedOut Was the user signed-out.
//****************************************************************************************************************************************************
void QMLBackend::onLoginFinished(QString const &userID, bool wasSignedOut)
{
void QMLBackend::onLoginFinished(QString const &userID, bool wasSignedOut) {
this->retrieveUserList();
qint32 const index = users_->rowOfUserID(userID);
emit loginFinished(index, wasSignedOut);
@ -440,19 +419,18 @@ void QMLBackend::onLoginFinished(QString const &userID, bool wasSignedOut)
//****************************************************************************************************************************************************
/// \param[in] userID the userID.
//****************************************************************************************************************************************************
void QMLBackend::onLoginAlreadyLoggedIn(QString const &userID)
{
void QMLBackend::onLoginAlreadyLoggedIn(QString const &userID) {
this->retrieveUserList();
qint32 const index = users_->rowOfUserID(userID);
emit loginAlreadyLoggedIn(index);
}
//****************************************************************************************************************************************************
/// \param[in] useSSLForIMAP The value for the 'Use SSL for IMAP' property
/// \param[in] useSSLForSMTP The value for the 'Use SSL for SMTP' property
//****************************************************************************************************************************************************
void QMLBackend::onMailServerSettingsChanged(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP)
{
void QMLBackend::onMailServerSettingsChanged(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP) {
this->setIMAPPort(imapPort);
this->setSMTPPort(smtpPort);
this->setUseSSLForIMAP(useSSLForIMAP);
@ -463,8 +441,7 @@ void QMLBackend::onMailServerSettingsChanged(int imapPort, int smtpPort, bool us
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::onGenericError(ErrorInfo const &info)
{
void QMLBackend::onGenericError(ErrorInfo const &info) {
emit genericError(info.title, info.description);
}
@ -472,38 +449,37 @@ void QMLBackend::onGenericError(ErrorInfo const &info)
//****************************************************************************************************************************************************
/// \param[in] active Should DoH be active.
//****************************************************************************************************************************************************
void QMLBackend::toggleDoH(bool active)
{
if (app().grpc().setIsDoHEnabled(active).ok())
void QMLBackend::toggleDoH(bool active) {
if (app().grpc().setIsDoHEnabled(active).ok()) {
emit isDoHEnabledChanged(active);
}
}
//****************************************************************************************************************************************************
/// \param[in] keychain The new keychain.
//****************************************************************************************************************************************************
void QMLBackend::changeKeychain(QString const &keychain)
{
if (app().grpc().setCurrentKeychain(keychain).ok())
void QMLBackend::changeKeychain(QString const &keychain) {
if (app().grpc().setCurrentKeychain(keychain).ok()) {
emit currentKeychainChanged(keychain);
}
}
//****************************************************************************************************************************************************
/// \param[in] active Should automatic update be turned on.
//****************************************************************************************************************************************************
void QMLBackend::toggleAutomaticUpdate(bool active)
{
if (app().grpc().setIsAutomaticUpdateOn(active).ok())
void QMLBackend::toggleAutomaticUpdate(bool active) {
if (app().grpc().setIsAutomaticUpdateOn(active).ok()) {
emit isAutomaticUpdateOnChanged(active);
}
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::checkUpdates()
{
void QMLBackend::checkUpdates() {
app().grpc().checkUpdate();
}
@ -511,8 +487,7 @@ void QMLBackend::checkUpdates()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::installUpdate()
{
void QMLBackend::installUpdate() {
app().grpc().installUpdate();
}
@ -520,8 +495,7 @@ void QMLBackend::installUpdate()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::triggerReset()
{
void QMLBackend::triggerReset() {
app().grpc().triggerReset();
}
@ -529,8 +503,7 @@ void QMLBackend::triggerReset()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::onResetFinished()
{
void QMLBackend::onResetFinished() {
emit resetFinished();
this->restart();
}
@ -539,8 +512,7 @@ void QMLBackend::onResetFinished()
//****************************************************************************************************************************************************
// onVersionChanged update dynamic link related to version
//****************************************************************************************************************************************************
void QMLBackend::onVersionChanged()
{
void QMLBackend::onVersionChanged() {
emit releaseNotesLinkChanged(releaseNotesLink());
emit landingPageLinkChanged(landingPageLink());
}
@ -549,10 +521,10 @@ void QMLBackend::onVersionChanged()
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void QMLBackend::exportTLSCertificates()
{
void QMLBackend::exportTLSCertificates() {
QString const folderPath = QFileDialog::getExistingDirectory(nullptr, QObject::tr("Select directory"),
QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
if (!folderPath.isEmpty())
if (!folderPath.isEmpty()) {
app().grpc().exportTLSCertificates(folderPath);
}
}

View File

@ -31,8 +31,7 @@
//****************************************************************************************************************************************************
/// \brief Bridge C++ backend class.
//****************************************************************************************************************************************************
class QMLBackend: public QObject
{
class QMLBackend : public QObject {
Q_OBJECT
public: // member functions.
@ -79,28 +78,109 @@ public: // Qt/QML properties. Note that the NOTIFY-er signal is required even fo
Q_PROPERTY(QString currentEmailClient READ currentEmailClient NOTIFY currentEmailClientChanged)
Q_PROPERTY(QStringList availableKeychain READ availableKeychain NOTIFY availableKeychainChanged)
Q_PROPERTY(QString currentKeychain READ currentKeychain NOTIFY currentKeychainChanged)
Q_PROPERTY(UserList* users MEMBER users_ NOTIFY usersChanged)
Q_PROPERTY(UserList *users MEMBER users_ NOTIFY usersChanged)
Q_PROPERTY(bool dockIconVisible READ dockIconVisible WRITE setDockIconVisible NOTIFY dockIconVisibleChanged)
// Qt Property system setters & getters.
bool showOnStartup() const { bool v = false; app().grpc().showOnStartup(v); return v; };
bool showOnStartup() const {
bool v = false;
app().grpc().showOnStartup(v);
return v;
};
bool showSplashScreen() const { return showSplashScreen_; };
void setShowSplashScreen(bool show) { if (show != showSplashScreen_) { showSplashScreen_ = show; emit showSplashScreenChanged(show); } }
void setShowSplashScreen(bool show) { if (show != showSplashScreen_) { showSplashScreen_ = show; emit showSplashScreenChanged(show); }}
QString goos() { return goos_; }
QUrl logsPath() const { return logsPath_; }
QUrl licensePath() const { return licensePath_; }
QUrl releaseNotesLink() const { QUrl link; app().grpc().releaseNotesPageLink(link); return link; }
QUrl dependencyLicensesLink() const { QUrl link; app().grpc().dependencyLicensesLink(link); return link; }
QUrl landingPageLink() const { QUrl link; app().grpc().landingPageLink(link); return link; }
QUrl releaseNotesLink() const {
QUrl link;
app().grpc().releaseNotesPageLink(link);
return link;
}
QUrl dependencyLicensesLink() const {
QUrl link;
app().grpc().dependencyLicensesLink(link);
return link;
}
QUrl landingPageLink() const {
QUrl link;
app().grpc().landingPageLink(link);
return link;
}
QString appname() const { return QString(PROJECT_FULL_NAME); }
QString vendor() const { return QString(PROJECT_VENDOR); }
QString version() const { QString version; app().grpc().version(version); return version; }
QString hostname() const { QString hostname; app().grpc().hostname(hostname); return hostname; }
bool isAutostartOn() const { bool v; app().grpc().isAutostartOn(v); return v; };
bool isBetaEnabled() const { bool v; app().grpc().isBetaEnabled(v); return v; }
bool isAllMailVisible() const { bool v; app().grpc().isAllMailVisible(v); return v; }
QString colorSchemeName() const { QString name; app().grpc().colorSchemeName(name); return name; }
QUrl diskCachePath() const { QUrl path; app().grpc().diskCachePath(path); return path; }
QString version() const {
QString version;
app().grpc().version(version);
return version;
}
QString hostname() const {
QString hostname;
app().grpc().hostname(hostname);
return hostname;
}
bool isAutostartOn() const {
bool v;
app().grpc().isAutostartOn(v);
return v;
};
bool isBetaEnabled() const {
bool v;
app().grpc().isBetaEnabled(v);
return v;
}
bool isAllMailVisible() const {
bool v;
app().grpc().isAllMailVisible(v);
return v;
}
QString colorSchemeName() const {
QString name;
app().grpc().colorSchemeName(name);
return name;
}
QUrl diskCachePath() const {
QUrl path;
app().grpc().diskCachePath(path);
return path;
}
bool useSSLForIMAP() const;
void setUseSSLForIMAP(bool value);
bool useSSLForSMTP() const;
@ -109,15 +189,56 @@ public: // Qt/QML properties. Note that the NOTIFY-er signal is required even fo
void setIMAPPort(int port);
int smtpPort() const;
void setSMTPPort(int port);
bool isDoHEnabled() const { bool isEnabled; app().grpc().isDoHEnabled(isEnabled); return isEnabled;}
bool isFirstGUIStart() const { bool v; app().grpc().isFirstGUIStart(v); return v; };
bool isAutomaticUpdateOn() const { bool isOn = false; app().grpc().isAutomaticUpdateOn(isOn); return isOn; }
QString currentEmailClient() { QString client; app().grpc().currentEmailClient(client); return client;}
QStringList availableKeychain() const { QStringList keychains; app().grpc().availableKeychains(keychains); return keychains; }
QString currentKeychain() const { QString keychain; app().grpc().currentKeychain(keychain); return keychain; }
bool isDoHEnabled() const {
bool isEnabled;
app().grpc().isDoHEnabled(isEnabled);
return isEnabled;
}
bool isFirstGUIStart() const {
bool v;
app().grpc().isFirstGUIStart(v);
return v;
};
bool isAutomaticUpdateOn() const {
bool isOn = false;
app().grpc().isAutomaticUpdateOn(isOn);
return isOn;
}
QString currentEmailClient() {
QString client;
app().grpc().currentEmailClient(client);
return client;
}
QStringList availableKeychain() const {
QStringList keychains;
app().grpc().availableKeychains(keychains);
return keychains;
}
QString currentKeychain() const {
QString keychain;
app().grpc().currentKeychain(keychain);
return keychain;
}
bool dockIconVisible() const { return getDockIconVisibleState(); };
void setDockIconVisible(bool visible) { setDockIconVisibleState(visible); emit dockIconVisibleChanged(visible); }
signals: // Signal used by the Qt property system. Many of them are unused but required to avoid warning from the QML engine.
void showSplashScreenChanged(bool value);
void showOnStartupChanged(bool value);
@ -145,7 +266,7 @@ signals: // Signal used by the Qt property system. Many of them are unused but r
void availableKeychainChanged(QStringList const &keychains);
void hostnameChanged(QString const &hostname);
void isAutostartOnChanged(bool value);
void usersChanged(UserList* users);
void usersChanged(UserList *users);
void dockIconVisibleChanged(bool value);
public slots: // slot for signals received from QML -> To be forwarded to Bridge via RPC Client calls.
@ -153,14 +274,28 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge
void toggleBeta(bool active);
void changeIsAllMailVisible(bool isVisible);
void changeColorScheme(QString const &scheme);
void setDiskCachePath(QUrl const& path) const;
void login(QString const& username, QString const& password) { app().grpc().login(username, password);}
void login2FA(QString const& username, QString const& code) { app().grpc().login2FA(username, code);}
void login2Password(QString const& username, QString const& password) { app().grpc().login2Passwords(username, password);}
void loginAbort(QString const& username){ app().grpc().loginAbort(username);}
void setDiskCachePath(QUrl const &path) const;
void login(QString const &username, QString const &password) { app().grpc().login(username, password); }
void login2FA(QString const &username, QString const &code) { app().grpc().login2FA(username, code); }
void login2Password(QString const &username, QString const &password) { app().grpc().login2Passwords(username, password); }
void loginAbort(QString const &username) { app().grpc().loginAbort(username); }
void toggleDoH(bool active);
void toggleAutomaticUpdate(bool makeItActive);
void updateCurrentMailClient() { emit currentEmailClientChanged(currentEmailClient()); }
void changeKeychain(QString const &keychain);
void guiReady();
void quit();
@ -169,8 +304,13 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge
void checkUpdates();
void installUpdate();
void triggerReset();
void reportBug(QString const &description, QString const& address, QString const &emailClient, bool includeLogs) {
app().grpc().reportBug(description, address, emailClient, includeLogs); }
void reportBug(QString const &description, QString const &address, QString const &emailClient, bool includeLogs) {
app().grpc().reportBug(description, address, emailClient, includeLogs);
}
void exportTLSCertificates();
void onResetFinished();
void onVersionChanged();
@ -178,7 +318,7 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge
public slots: // slot for signals received from gRPC that need transformation instead of simple forwarding
void onMailServerSettingsChanged(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP); ///< Slot for the ConnectionModeChanged gRPC event.
void onGenericError(bridgepp::ErrorInfo const& info); ///< Slot for generic errors received from the gRPC service.
void onGenericError(bridgepp::ErrorInfo const &info); ///< Slot for generic errors received from the gRPC service.
void onLoginFinished(QString const &userID, bool wasSignedOut); ///< Slot for LoginFinished gRPC event.
void onLoginAlreadyLoggedIn(QString const &userID); ///< Slot for the LoginAlreadyLoggedIn gRPC event.
@ -192,17 +332,17 @@ signals: // Signals received from the Go backend, to be forwarded to QML
void loginFreeUserError();
void loginConnectionError(QString const &errorMsg);
void login2FARequested(QString const &username);
void login2FAError(QString const& errorMsg);
void login2FAErrorAbort(QString const& errorMsg);
void login2FAError(QString const &errorMsg);
void login2FAErrorAbort(QString const &errorMsg);
void login2PasswordRequested();
void login2PasswordError(QString const& errorMsg);
void login2PasswordErrorAbort(QString const& errorMsg);
void login2PasswordError(QString const &errorMsg);
void login2PasswordErrorAbort(QString const &errorMsg);
void loginFinished(int index, bool wasSignedOut);
void loginAlreadyLoggedIn(int index);
void updateManualReady(QString const& version);
void updateManualReady(QString const &version);
void updateManualRestartNeeded();
void updateManualError();
void updateForce(QString const& version);
void updateForce(QString const &version);
void updateForceError();
void updateSilentRestartNeeded();
void updateSilentError();
@ -218,11 +358,11 @@ signals: // Signals received from the Go backend, to be forwarded to QML
void changeKeychainFinished();
void notifyHasNoKeychain();
void notifyRebuildKeychain();
void noActiveKeyForRecipient(QString const& email);
void addressChanged(QString const& address);
void addressChangedLogout(QString const& address);
void noActiveKeyForRecipient(QString const &email);
void addressChanged(QString const &address);
void addressChangedLogout(QString const &address);
void apiCertIssue();
void userDisconnected(QString const& username);
void userDisconnected(QString const &username);
void internetOff();
void internetOn();
void resetFinished();
@ -231,14 +371,14 @@ signals: // Signals received from the Go backend, to be forwarded to QML
void bugReportSendError();
void showMainWindow();
void hideMainWindow();
void genericError(QString const& title, QString const& description);
void genericError(QString const &title, QString const &description);
private: // member functions
void retrieveUserList(); ///< Retrieve the list of users via gRPC.
void connectGrpcEvents(); ///< Connect gRPC that need to be forwarded to QML via backend signals
private: // data members
UserList* users_ { nullptr }; ///< The user list. Owned by backend.
UserList *users_ { nullptr }; ///< The user list. Owned by backend.
std::unique_ptr<bridgepp::Overseer> eventStreamOverseer_; ///< The event stream overseer.
bool showSplashScreen_ { false }; ///< The cached version of show splash screen. Retrieved on startup from bridge, and potentially modified locally.
QString goos_; ///< The cached version of the GOOS variable.

View File

@ -17,14 +17,17 @@
#include "SentryUtils.h"
static constexpr const char* LoggerName = "bridge-gui";
void reportSentryEvent(sentry_level_t level, const char* message) {
static constexpr const char *LoggerName = "bridge-gui";
void reportSentryEvent(sentry_level_t level, const char *message) {
auto event = sentry_value_new_message_event(level, LoggerName, message);
sentry_capture_event(event);
}
void reportSentryException(sentry_level_t level, const char* message, const char* exceptionType, const char* exception) {
void reportSentryException(sentry_level_t level, const char *message, const char *exceptionType, const char *exception) {
auto event = sentry_value_new_message_event(level, LoggerName, message);
sentry_event_add_exception(event, sentry_value_new_exception(exceptionType, exception));
sentry_capture_event(event);

View File

@ -18,9 +18,11 @@
#ifndef BRIDGE_GUI_SENTRYUTILS_H
#define BRIDGE_GUI_SENTRYUTILS_H
#include <sentry.h>
void reportSentryEvent(sentry_level_t level, const char* message);
void reportSentryException(sentry_level_t level, const char* message, const char* exceptionType, const char* exception);
void reportSentryEvent(sentry_level_t level, const char *message);
void reportSentryException(sentry_level_t level, const char *message, const char *exceptionType, const char *exception);
#endif //BRIDGE_GUI_SENTRYUTILS_H

View File

@ -26,8 +26,7 @@ using namespace bridgepp;
/// \param[in] parent The parent object of the user list.
//****************************************************************************************************************************************************
UserList::UserList(QObject *parent)
: QAbstractListModel(parent)
{
: QAbstractListModel(parent) {
/// \todo use mutex to prevent concurrent access
}
@ -35,9 +34,8 @@ UserList::UserList(QObject *parent)
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void UserList::connectGRPCEvents() const
{
GRPCClient& client = app().grpc();
void UserList::connectGRPCEvents() const {
GRPCClient &client = app().grpc();
connect(&client, &GRPCClient::userChanged, this, &UserList::onUserChanged);
connect(&client, &GRPCClient::toggleSplitModeFinished, this, &UserList::onToggleSplitModeFinished);
}
@ -46,8 +44,7 @@ void UserList::connectGRPCEvents() const
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
int UserList::rowCount(QModelIndex const &) const
{
int UserList::rowCount(QModelIndex const &) const {
return users_.size();
}
@ -57,14 +54,14 @@ int UserList::rowCount(QModelIndex const &) const
/// \param[in] role The role to retrieve data for.
/// \return The data at the index for the given role.
//****************************************************************************************************************************************************
QVariant UserList::data(QModelIndex const &index, int role) const
{
QVariant UserList::data(QModelIndex const &index, int role) const {
/// This It does not seem to be used, but the method is required by the base class.
/// From the original QtThe recipe QML backend User model, the User is always returned, regardless of the role.
Q_UNUSED(role)
int const row = index.row();
if ((row < 0) || (row >= users_.size()))
if ((row < 0) || (row >= users_.size())) {
return QVariant();
}
return QVariant::fromValue(users_[row].get());
}
@ -74,11 +71,12 @@ QVariant UserList::data(QModelIndex const &index, int role) const
/// \return the row of the user.
/// \return -1 if the userID is not in the list
//****************************************************************************************************************************************************
int UserList::rowOfUserID(QString const &userID) const
{
for (qint32 row = 0; row < users_.count(); ++row)
if (userID == users_[row]->property("id"))
int UserList::rowOfUserID(QString const &userID) const {
for (qint32 row = 0; row < users_.count(); ++row) {
if (userID == users_[row]->property("id")) {
return row;
}
}
return -1;
}
@ -86,8 +84,7 @@ int UserList::rowOfUserID(QString const &userID) const
//****************************************************************************************************************************************************
/// \param[in] users The new user list.
//****************************************************************************************************************************************************
void UserList::reset(QList<SPUser> const &users)
{
void UserList::reset(QList<SPUser> const &users) {
this->beginResetModel();
users_ = users;
this->endResetModel();
@ -98,8 +95,7 @@ void UserList::reset(QList<SPUser> const &users)
//****************************************************************************************************************************************************
/// \param[in] user The user.
//****************************************************************************************************************************************************
void UserList::appendUser(SPUser const &user)
{
void UserList::appendUser(SPUser const &user) {
int const size = users_.size();
this->beginInsertRows(QModelIndex(), size, size);
users_.append(user);
@ -111,10 +107,10 @@ void UserList::appendUser(SPUser const &user)
//****************************************************************************************************************************************************
/// \param[in] row The row.
//****************************************************************************************************************************************************
void UserList::removeUserAt(int row)
{
if ((row < 0) && (row >= users_.size()))
void UserList::removeUserAt(int row) {
if ((row < 0) && (row >= users_.size())) {
return;
}
this->beginRemoveRows(QModelIndex(), row, row);
users_.removeAt(row);
this->endRemoveRows();
@ -126,10 +122,8 @@ void UserList::removeUserAt(int row)
/// \param[in] row The row.
/// \param[in] user The user.
//****************************************************************************************************************************************************
void UserList::updateUserAtRow(int row, User const &user)
{
if ((row < 0) || (row >= users_.count()))
{
void UserList::updateUserAtRow(int row, User const &user) {
if ((row < 0) || (row >= users_.count())) {
app().log().error(QString("invalid user at row %2 (user userCount = %2)").arg(row).arg(users_.count()));
return;
}
@ -146,10 +140,10 @@ void UserList::updateUserAtRow(int row, User const &user)
/// \return The user with the given ID.
/// \return A null pointer if the user could not be found.
//****************************************************************************************************************************************************
bridgepp::SPUser UserList::getUserWithID(QString const &userID) const
{
QList<SPUser>::const_iterator it = std::find_if(users_.begin(), users_.end(), [userID](SPUser const & user) -> bool {
return user && user->id() == userID; });
bridgepp::SPUser UserList::getUserWithID(QString const &userID) const {
QList<SPUser>::const_iterator it = std::find_if(users_.begin(), users_.end(), [userID](SPUser const &user) -> bool {
return user && user->id() == userID;
});
return (it == users_.end()) ? nullptr : *it;
}
@ -157,10 +151,10 @@ bridgepp::SPUser UserList::getUserWithID(QString const &userID) const
//****************************************************************************************************************************************************
/// \param[in] row The row.
//****************************************************************************************************************************************************
User *UserList::get(int row) const
{
if ((row < 0) || (row >= users_.count()))
User *UserList::get(int row) const {
if ((row < 0) || (row >= users_.count())) {
return nullptr;
}
app().log().trace(QString("Retrieving user at row %1 (user userCount = %2)").arg(row).arg(users_.count()));
return users_[row].get();
@ -170,25 +164,21 @@ User *UserList::get(int row) const
//****************************************************************************************************************************************************
/// \param[in] userID The userID.
//****************************************************************************************************************************************************
void UserList::onUserChanged(QString const &userID)
{
void UserList::onUserChanged(QString const &userID) {
int const index = this->rowOfUserID(userID);
SPUser user;
grpc::Status status = app().grpc().getUser(userID, user);
QQmlEngine::setObjectOwnership(user.get(), QQmlEngine::CppOwnership);
if ((!user) || (!status.ok()))
{
if (index >= 0) // user exists here but not in the go backend. we delete it.
{
if ((!user) || (!status.ok())) {
if (index >= 0) { // user exists here but not in the go backend. we delete it.
app().log().trace(QString("Removing user from user list: %1").arg(userID));
this->removeUserAt(index);
}
return;
}
if (index < 0)
{
if (index < 0) {
app().log().trace(QString("Adding user in user list: %1").arg(userID));
this->appendUser(user);
return;
@ -205,11 +195,9 @@ void UserList::onUserChanged(QString const &userID)
///
/// \param[in] userID the userID.
//****************************************************************************************************************************************************
void UserList::onToggleSplitModeFinished(QString const &userID)
{
void UserList::onToggleSplitModeFinished(QString const &userID) {
int const index = this->rowOfUserID(userID);
if (index < 0)
{
if (index < 0) {
app().log().error(QString("Received toggleSplitModeFinished event for unknown userID %1").arg(userID));
return;
}
@ -221,7 +209,6 @@ void UserList::onToggleSplitModeFinished(QString const &userID)
//****************************************************************************************************************************************************
/// \return THe number of items in the list.
//****************************************************************************************************************************************************
int UserList::count() const
{
int UserList::count() const {
return users_.size();
}

View File

@ -28,8 +28,7 @@
//****************************************************************************************************************************************************
/// \brief User list class.
//****************************************************************************************************************************************************
class UserList : public QAbstractListModel
{
class UserList : public QAbstractListModel {
Q_OBJECT
public: // member functions.
UserList(QObject *parent); ///< Default constructor.
@ -44,7 +43,7 @@ public: // member functions.
void removeUserAt(int row); ///< Remove the user at a given row
void appendUser(bridgepp::SPUser const &user); ///< Add a new user.
void updateUserAtRow(int row, bridgepp::User const &user); ///< Update the user at given row.
bridgepp::SPUser getUserWithID(QString const& userID) const; ///< Retrieve the user with the given ID.
bridgepp::SPUser getUserWithID(QString const &userID) const; ///< Retrieve the user with the given ID.
// the userCount property.
Q_PROPERTY(int count READ count NOTIFY countChanged)

View File

@ -30,18 +30,16 @@
#include <project_sentry_config.h>
using namespace bridgepp;
namespace
{
namespace {
/// \brief The file extension for the bridge executable file.
#ifdef Q_OS_WIN32
QString const exeSuffix = ".exe";
QString const exeSuffix = ".exe";
#else
QString const exeSuffix;
QString const exeSuffix;
#endif
QString const bridgeLock = "bridge-v3-gui.lock"; ///< file name used for the lock file.
@ -56,20 +54,20 @@ qint64 const grpcServiceConfigWaitDelayMs = 180000; ///< The wait delay for the
/// \return The path of the bridge executable.
/// \return A null string if the executable could not be located.
//****************************************************************************************************************************************************
QString locateBridgeExe()
{
QString locateBridgeExe() {
QFileInfo const fileInfo(QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(exeName));
return (fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable()) ? fileInfo.absoluteFilePath() : QString();
return (fileInfo.exists() && fileInfo.isFile() && fileInfo.isExecutable()) ? fileInfo.absoluteFilePath() : QString();
}
//****************************************************************************************************************************************************
/// // initialize the Qt application.
//****************************************************************************************************************************************************
void initQtApplication()
{
void initQtApplication() {
QString const qsgInfo = QProcessEnvironment::systemEnvironment().value("QSG_INFO");
if ((!qsgInfo.isEmpty()) && (qsgInfo != "0"))
if ((!qsgInfo.isEmpty()) && (qsgInfo != "0")) {
QLoggingCategory::setFilterRules("qt.scenegraph.general=true");
}
QGuiApplication::setApplicationName(PROJECT_FULL_NAME);
QGuiApplication::setApplicationVersion(PROJECT_VER);
@ -92,28 +90,30 @@ void initQtApplication()
//****************************************************************************************************************************************************
/// \return A reference to the log.
//****************************************************************************************************************************************************
Log &initLog()
{
Log &initLog() {
Log &log = app().log();
log.registerAsQtMessageHandler();
log.setEchoInConsole(true);
// remove old gui log files
QDir const logsDir(userLogsDir());
for (QFileInfo const fileInfo: logsDir.entryInfoList({ "gui_v*.log" }, QDir::Filter::Files)) // entryInfolist apparently only support wildcards, not regex.
for (QFileInfo const fileInfo: logsDir.entryInfoList({ "gui_v*.log" }, QDir::Filter::Files)) { // entryInfolist apparently only support wildcards, not regex.
QFile(fileInfo.absoluteFilePath()).remove();
}
// create new GUI log file
QString error;
if (!log.startWritingToFile(logsDir.absoluteFilePath(QString("gui_v%1_%2.log").arg(PROJECT_VER).arg(QDateTime::currentSecsSinceEpoch())), &error))
if (!log.startWritingToFile(logsDir.absoluteFilePath(QString("gui_v%1_%2.log").arg(PROJECT_VER).arg(QDateTime::currentSecsSinceEpoch())), &error)) {
log.error(error);
}
log.info("bridge-gui starting");
QString const qtCompileTimeVersion = QT_VERSION_STR;
QString const qtRuntimeVersion = qVersion();
QString msg = QString("Using Qt %1").arg(qtRuntimeVersion);
if (qtRuntimeVersion != qtCompileTimeVersion)
if (qtRuntimeVersion != qtCompileTimeVersion) {
msg += QString(" (compiled against %1)").arg(qtCompileTimeVersion);
}
log.info(msg);
return log;
@ -123,8 +123,7 @@ Log &initLog()
//****************************************************************************************************************************************************
/// \param[in] engine The QML component.
//****************************************************************************************************************************************************
QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine)
{
QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine) {
QString const qrcQmlDir = "qrc:/qml";
qmlRegisterSingletonInstance("Proton", 1, 0, "Backend", &app().backend());
qmlRegisterType<UserList>("Proton", 1, 0, "UserList");
@ -138,8 +137,7 @@ QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine)
QQuickStyle::setStyle("Proton");
rootComponent->loadUrl(QUrl(qrcQmlDir + "/Bridge.qml"));
if (rootComponent->status() != QQmlComponent::Status::Ready)
{
if (rootComponent->status() != QQmlComponent::Status::Ready) {
app().log().error(rootComponent->errorString());
throw Exception("Could not load QML component");
}
@ -151,21 +149,18 @@ QQmlComponent *createRootQmlComponent(QQmlApplicationEngine &engine)
/// \param[in] lock The lock file to be checked.
/// \return True if the lock can be taken, false otherwise.
//****************************************************************************************************************************************************
bool checkSingleInstance(QLockFile &lock)
{
bool checkSingleInstance(QLockFile &lock) {
lock.setStaleLockTime(0);
if (!lock.tryLock())
{
if (!lock.tryLock()) {
qint64 pid;
QString hostname, appName, details;
if (lock.getLockInfo(&pid, &hostname, &appName))
if (lock.getLockInfo(&pid, &hostname, &appName)) {
details = QString("(PID : %1 - Host : %2 - App : %3)").arg(pid).arg(hostname, appName);
}
app().log().error(QString("Instance already exists %1 %2").arg(lock.fileName(), details));
return false;
}
else
{
} else {
app().log().info(QString("lock file created %1").arg(lock.fileName()));
}
return true;
@ -175,8 +170,7 @@ bool checkSingleInstance(QLockFile &lock)
//****************************************************************************************************************************************************
/// \return QUrl to reach the bridge API.
//****************************************************************************************************************************************************
QUrl getApiUrl()
{
QUrl getApiUrl() {
QUrl url;
// use default url.
url.setScheme("http");
@ -185,17 +179,17 @@ QUrl getApiUrl()
// override with what can be found in the prefs.json file.
QFile prefFile(QString("%1/%2").arg(bridgepp::userConfigDir(), "prefs.json"));
if (prefFile.exists())
{
prefFile.open(QIODevice::ReadOnly|QIODevice::Text);
if (prefFile.exists()) {
prefFile.open(QIODevice::ReadOnly | QIODevice::Text);
QByteArray data = prefFile.readAll();
prefFile.close();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (!doc.isNull()) {
QString userPortApi = "user_port_api";
QJsonObject obj = doc.object();
if (!obj.isEmpty() && obj.contains(userPortApi))
if (!obj.isEmpty() && obj.contains(userPortApi)) {
url.setPort(doc.object()[userPortApi].toString().toInt());
}
}
}
return url;
@ -205,8 +199,7 @@ QUrl getApiUrl()
//****************************************************************************************************************************************************
/// \return The URL for the focus endpoint of the bridge API URL.
//****************************************************************************************************************************************************
QUrl getFocusUrl()
{
QUrl getFocusUrl() {
QUrl url = getApiUrl();
url.setPath("/focus");
return url;
@ -216,8 +209,7 @@ QUrl getFocusUrl()
//****************************************************************************************************************************************************
/// \return true if an instance of bridge is already running.
//****************************************************************************************************************************************************
bool isBridgeRunning()
{
bool isBridgeRunning() {
FocusGRPCClient client;
return client.connectToServer(500); // we time out after 1 second and consider no other instance is running;
}
@ -226,19 +218,18 @@ bool isBridgeRunning()
//****************************************************************************************************************************************************
/// \brief Use api to bring focus on existing bridge instance.
//****************************************************************************************************************************************************
void focusOtherInstance()
{
try
{
void focusOtherInstance() {
try {
FocusGRPCClient client;
QString error;
if (!client.connectToServer(5000, &error))
if (!client.connectToServer(5000, &error)) {
throw Exception(QString("Could not connect to bridge focus service for a raise call: %1").arg(error));
if (!client.raise().ok())
}
if (!client.raise().ok()) {
throw Exception(QString("The raise call to the bridge focus service failed."));
}
}
catch (Exception const& e)
{
catch (Exception const &e) {
app().log().error(e.qwhat());
reportSentryException(SENTRY_LEVEL_ERROR, "Exception occurred during focusOtherInstance()", "Exception", e.what());
}
@ -248,22 +239,22 @@ void focusOtherInstance()
//****************************************************************************************************************************************************
/// \param [in] args list of arguments to pass to bridge.
//****************************************************************************************************************************************************
void launchBridge(QStringList const &args)
{
UPOverseer& overseer = app().bridgeOverseer();
void launchBridge(QStringList const &args) {
UPOverseer &overseer = app().bridgeOverseer();
overseer.reset();
const QString bridgeExePath = locateBridgeExe();
if (bridgeExePath.isEmpty())
if (bridgeExePath.isEmpty()) {
throw Exception("Could not locate the bridge executable path");
else
} else {
app().log().debug(QString("Bridge executable path: %1").arg(QDir::toNativeSeparators(bridgeExePath)));
}
qint64 const pid = qApp->applicationPid();
QStringList const params = QStringList { "--grpc", "--parent-pid", QString::number(pid) } + args ;
QStringList const params = QStringList { "--grpc", "--parent-pid", QString::number(pid) } + args;
app().log().info(QString("Launching bridge process with command \"%1\" %2").arg(bridgeExePath, params.join(" ")));
overseer = std::make_unique<Overseer>(new ProcessMonitor(bridgeExePath, params , nullptr), nullptr);
overseer = std::make_unique<Overseer>(new ProcessMonitor(bridgeExePath, params, nullptr), nullptr);
overseer->startWorker(true);
}
@ -271,16 +262,15 @@ void launchBridge(QStringList const &args)
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void closeBridgeApp()
{
void closeBridgeApp() {
app().grpc().quit(); // this will cause the grpc service and the bridge app to close.
UPOverseer& overseer = app().bridgeOverseer();
if (!overseer) // The app was run in 'attach' mode and attached to an existing instance of Bridge. We're not monitoring it.
UPOverseer &overseer = app().bridgeOverseer();
if (!overseer) { // The app was run in 'attach' mode and attached to an existing instance of Bridge. We're not monitoring it.
return;
}
while (!overseer->isFinished())
{
while (!overseer->isFinished()) {
QThread::msleep(20);
}
}
@ -291,10 +281,9 @@ void closeBridgeApp()
/// \param[in] argv The list of command-line arguments.
/// \return The exit code for the application.
//****************************************************************************************************************************************************
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
// Init sentry.
sentry_options_t* sentryOptions = sentry_options_new();
sentry_options_t *sentryOptions = sentry_options_new();
sentry_options_set_dsn(sentryOptions, SentryDNS);
{
const QString sentryCachePath = sentryCacheDir();
@ -307,24 +296,23 @@ int main(int argc, char *argv[])
std::cerr << "Failed to initialize sentry" << std::endl;
}
auto sentryClose = qScopeGuard([]{sentry_close();});
auto sentryClose = qScopeGuard([] { sentry_close(); });
// The application instance is needed to display system message boxes. As we may have to do it in the exception handler,
// application instance is create outside the try/catch clause.
if (QSysInfo::productType() != "windows")
if (QSysInfo::productType() != "windows") {
QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
}
QApplication guiApp(argc, argv);
try
{
try {
initQtApplication();
Log &log = initLog();
QLockFile lock(bridgepp::userCacheDir() + "/" + bridgeLock);
if (!checkSingleInstance(lock))
{
if (!checkSingleInstance(lock)) {
focusOtherInstance();
return EXIT_FAILURE;
}
@ -340,10 +328,10 @@ int main(int argc, char *argv[])
// these outputs and output them on the command-line.
log.setLevel(cliOptions.logLevel);
if (!cliOptions.attach)
{
if (isBridgeRunning())
if (!cliOptions.attach) {
if (isBridgeRunning()) {
throw Exception("An orphan instance of bridge is already running. Please terminate it and relaunch the application.");
}
// before launching bridge, we remove any trailing service config file, because we need to make sure we get a newly generated one.
GRPCClient::removeServiceConfigFile();
@ -352,8 +340,9 @@ int main(int argc, char *argv[])
log.info(QString("Retrieving gRPC service configuration from '%1'").arg(QDir::toNativeSeparators(grpcServerConfigPath())));
app().backend().init(GRPCClient::waitAndRetrieveServiceConfig(cliOptions.attach ? 0 : grpcServiceConfigWaitDelayMs, app().bridgeMonitor()));
if (!cliOptions.attach)
if (!cliOptions.attach) {
GRPCClient::removeServiceConfigFile();
}
// gRPC communication is established. From now on, log events will be sent to bridge via gRPC. bridge will write these to file,
// and will output then on console if appropriate. If we are not running in attached mode we intercept bridge stdout & stderr and
@ -370,19 +359,18 @@ int main(int argc, char *argv[])
QQmlApplicationEngine engine;
std::unique_ptr<QQmlComponent> rootComponent(createRootQmlComponent(engine));
std::unique_ptr<QObject>rootObject(rootComponent->create(engine.rootContext()));
if (!rootObject)
std::unique_ptr<QObject> rootObject(rootComponent->create(engine.rootContext()));
if (!rootObject) {
throw Exception("Could not create root object.");
}
ProcessMonitor *bridgeMonitor = app().bridgeMonitor();
bool bridgeExited = false;
bool startError = false;
QMetaObject::Connection connection;
if (bridgeMonitor)
{
const ProcessMonitor::MonitorStatus& status = bridgeMonitor->getStatus();
if (status.ended && !cliOptions.attach)
{
if (bridgeMonitor) {
const ProcessMonitor::MonitorStatus &status = bridgeMonitor->getStatus();
if (status.ended && !cliOptions.attach) {
// ProcessMonitor already stopped meaning we are attached to an orphan Bridge.
// Restart the full process to be sure there is no more bridge orphans
app().log().error("Found orphan bridge, need to restart.");
@ -390,21 +378,18 @@ int main(int argc, char *argv[])
app().backend().restart();
bridgeExited = true;
startError = true;
}
else
{
} else {
app().log().debug(QString("Monitoring Bridge PID : %1").arg(status.pid));
connection = QObject::connect(bridgeMonitor, &ProcessMonitor::processExited, [&](int returnCode) {
bridgeExited = true;// clazy:exclude=lambda-in-connect
qGuiApp->exit(returnCode);
});
bridgeExited = true;// clazy:exclude=lambda-in-connect
qGuiApp->exit(returnCode);
});
}
}
int result = 0;
if (!startError)
{
if (!startError) {
// we succeeded in launching bridge, so we can be set as mainExecutable.
app().grpc().setMainExecutable(QString::fromLocal8Bit(argv[0]));
result = QGuiApplication::exec();
@ -412,21 +397,22 @@ int main(int argc, char *argv[])
QObject::disconnect(connection);
app().grpc().stopEventStreamReader();
if (!app().backend().waitForEventStreamReaderToFinish(5000))
if (!app().backend().waitForEventStreamReaderToFinish(5000)) {
log.warn("Event stream reader took too long to finish.");
}
// We manually delete the QML components to avoid warnings error due to order of deletion of C++ / JS objects and singletons.
rootObject.reset();
rootComponent.reset();
if (!bridgeExited)
if (!bridgeExited) {
closeBridgeApp();
}
// release the lock file
lock.unlock();
return result;
}
catch (Exception const &e)
{
catch (Exception const &e) {
reportSentryException(SENTRY_LEVEL_ERROR, "Exception occurred during main", "Exception", e.what());
QMessageBox::critical(nullptr, "Error", e.qwhat());
QTextStream(stderr) << e.qwhat() << "\n";