File: app.h

package info (click to toggle)
syncthingtray 2.0.9-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,124 kB
  • sloc: cpp: 34,081; xml: 1,705; java: 1,258; sh: 97; javascript: 54; makefile: 25
file content (496 lines) | stat: -rw-r--r-- 19,248 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#ifndef SYNCTHING_TRAY_APP_H
#define SYNCTHING_TRAY_APP_H

#include "./appbase.h"
#include "./quickicon.h"

#ifdef Q_OS_ANDROID
#include "./android.h"
#endif

#include "../misc/diffhighlighter.h"
#include "../misc/internalerror.h"
#include "../misc/otherdialogs.h"
#include "../misc/statusinfo.h"
#include "../misc/syncthinglauncher.h"
#include "../misc/utils.h"

#include <syncthingmodel/syncthingdevicemodel.h>
#include <syncthingmodel/syncthingdirectorymodel.h>
#include <syncthingmodel/syncthingfilemodel.h>
#include <syncthingmodel/syncthingrecentchangesmodel.h>
#include <syncthingmodel/syncthingsortfiltermodel.h>

#include <qtutilities/settingsdialog/qtsettings.h>

#include <QJSValue>
#include <QJsonObject>
#include <QQmlApplicationEngine>
#include <QtVersion>

#include <array>
#include <atomic>
#include <optional>

QT_FORWARD_DECLARE_CLASS(QTextDocument)
QT_FORWARD_DECLARE_CLASS(QUrl)

namespace QtForkAwesome {
class QuickImageProvider;
}

namespace QtGui {

class SYNCTHINGWIDGETS_EXPORT App : public AppBase {
    Q_OBJECT
    Q_PROPERTY(Data::SyncthingDirectoryModel *dirModel READ dirModel CONSTANT)
    Q_PROPERTY(Data::SyncthingSortFilterModel *sortFilterDirModel READ sortFilterDirModel CONSTANT)
    Q_PROPERTY(Data::SyncthingDeviceModel *devModel READ devModel CONSTANT)
    Q_PROPERTY(Data::SyncthingSortFilterModel *sortFilterDevModel READ sortFilterDevModel CONSTANT)
    Q_PROPERTY(Data::SyncthingRecentChangesModel *changesModel READ changesModel CONSTANT)
    Q_PROPERTY(QJsonObject settings READ settings WRITE setSettings NOTIFY settingsChanged)
    Q_PROPERTY(QString faUrlBase READ faUrlBase CONSTANT)
    Q_PROPERTY(bool darkmodeEnabled READ isDarkmodeEnabled NOTIFY darkmodeEnabledChanged)
    Q_PROPERTY(int iconSize READ iconSize CONSTANT)
    Q_PROPERTY(int iconWidthDelegate READ iconWidthDelegate CONSTANT)
    Q_PROPERTY(bool windowPopups READ windowPopups CONSTANT)
    Q_PROPERTY(bool extendedClientArea READ extendedClientArea CONSTANT)
    Q_PROPERTY(QString syncthingVersion READ syncthingVersion CONSTANT)
    Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT)
    Q_PROPERTY(QString readmeUrl READ readmeUrl CONSTANT)
    Q_PROPERTY(QString documentationUrl READ documentationUrl CONSTANT)
    Q_PROPERTY(QString website READ website CONSTANT)
    Q_PROPERTY(bool hasInternalErrors READ hasInternalErrors NOTIFY hasInternalErrorsChanged)
    Q_PROPERTY(QVariantMap statistics READ statistics)
    Q_PROPERTY(bool savingConfig READ isSavingConfig NOTIFY savingConfigChanged)
    Q_PROPERTY(bool syncthingStarting READ isSyncthingStarting NOTIFY syncthingStartingChanged)
    Q_PROPERTY(bool syncthingRunning READ isSyncthingRunning NOTIFY syncthingRunningChanged)
    Q_PROPERTY(QUrl syncthingGuiUrl READ syncthingGuiUrl NOTIFY syncthingGuiUrlChanged)
    Q_PROPERTY(bool usingUnixDomainSocket READ isUsingUnixDomainSocket NOTIFY syncthingGuiUrlChanged)
    Q_PROPERTY(QString syncthingRunningStatus READ syncthingRunningStatus NOTIFY syncthingRunningStatusChanged)
    Q_PROPERTY(QString meteredStatus READ meteredStatus NOTIFY meteredStatusChanged)
    Q_PROPERTY(bool importExportOngoing READ isImportExportOngoing NOTIFY importExportOngoingChanged)
    Q_PROPERTY(QString statusText READ statusText NOTIFY statusInfoChanged)
    Q_PROPERTY(QIcon statusIcon READ statusIcon NOTIFY statusInfoChanged)
    Q_PROPERTY(QString additionalStatusText READ additionalStatusText NOTIFY statusInfoChanged)
    Q_PROPERTY(bool scanSupported READ isScanSupported CONSTANT)
    Q_PROPERTY(bool manualServiceShutdown READ isServiceShutdownManual CONSTANT)
    Q_PROPERTY(QString fontFamily READ fontFamily CONSTANT)
    Q_PROPERTY(qreal fontScale READ fontScale CONSTANT)
    Q_PROPERTY(int fontWeightAdjustment READ fontWeightAdjustment CONSTANT)
    Q_PROPERTY(QFont font READ font CONSTANT)
    Q_PROPERTY(bool storagePermissionGranted READ storagePermissionGranted NOTIFY storagePermissionGrantedChanged)
    Q_PROPERTY(bool notificationPermissionGranted READ notificationPermissionGranted NOTIFY notificationPermissionGrantedChanged)
    Q_PROPERTY(QString currentSyncthingHomeDir READ currentSyncthingHomeDir)
    Q_PROPERTY(QString closePreference READ closePreference)
    Q_PROPERTY(QObject *currentDialog READ currentDialog)
    QML_ELEMENT
    QML_SINGLETON

    enum class ImportExportStatus { None, Checking, Importing, Exporting, CheckingMove, Moving, Cleaning, SavingSupportBundle };

public:
    explicit App(bool insecure, QQmlEngine *engine = nullptr, QObject *parent = nullptr);
    ~App();
    static App *create(QQmlEngine *, QJSEngine *engine);

    // properties
    Data::SyncthingDirectoryModel *dirModel()
    {
        return &m_dirModel;
    }
    Data::SyncthingSortFilterModel *sortFilterDirModel()
    {
        return &m_sortFilterDirModel;
    }
    Data::SyncthingDeviceModel *devModel()
    {
        return &m_devModel;
    }
    Data::SyncthingSortFilterModel *sortFilterDevModel()
    {
        return &m_sortFilterDevModel;
    }
    Data::SyncthingRecentChangesModel *changesModel()
    {
        return &m_changesModel;
    }
    const QString &faUrlBase()
    {
        return m_faUrlBase;
    }
    QJsonObject settings() const
    {
        return m_settings;
    }
    void setSettings(const QJsonObject &settings)
    {
        m_settings = settings;
        applySettings();
        storeSettings();
        emit settingsChanged(m_settings);
    }
#if defined(Q_OS_ANDROID)
    static constexpr bool windowPopups()
    {
        return false;
    }
#else
    bool windowPopups() const;
#endif
    static constexpr bool extendedClientArea()
    {
        // disable extended client areas by default as further tweaking is needed
        // note: Safe areas are not working as expected with Qt 6.9.2 at all but this is fixed with Qt 6.9.3.
#ifdef SYNCTHINGWIDGETS_EXTENDED_CLIENT_AREA
        return true;
#else
        return false;
#endif
    }
    QString syncthingVersion() const
    {
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
        return Data::SyncthingLauncher::libSyncthingVersionInfo().remove(0, 11);
#else
        return tr("not available");
#endif
    }
    QString qtVersion() const
    {
        return QString::fromUtf8(qVersion());
    }
    QString readmeUrl() const
    {
        return QtGui::readmeUrl();
    }
    QString documentationUrl() const
    {
        return QtGui::documentationUrl();
    }
    QString website() const;

    /*!
     * \brief Returns whether darkmode is enabled.
     * \remarks
     * The QML code could just use "Qt.styleHints.colorScheme === Qt.Dark" but this would not be consistent with the approach in
     * QtSettings that also takes the palette into account for platforms without darkmode flag.
     */
    bool isDarkmodeEnabled() const
    {
        return m_darkmodeEnabled;
    }
    int iconSize() const
    {
        return m_iconSize;
    }
    int iconWidthDelegate() const
    {
        return m_iconWidthDelegate;
    }
    const QString &status() override final;
    bool hasInternalErrors() const
    {
        return !m_internalErrors.isEmpty();
    }
    qint64 databaseSize(const QString &path, const QString &extension) const;
    QVariant formattedDatabaseSize(const QString &path, const QString &extension) const;
    QVariantMap statistics() const;
    void statistics(QVariantMap &res) const;
    bool isSavingConfig() const
    {
        return m_pendingConfigChange.reply != nullptr;
    }
    bool isImportExportOngoing() const
    {
        return m_importExportStatus != ImportExportStatus::None;
    }
    bool syncthingStarting() const
    {
        return m_isSyncthingStarting;
    }
    bool isSyncthingStarting() const
    {
        return m_isSyncthingStarting;
    }
    bool isSyncthingRunning() const override final
    {
        return m_isSyncthingRunning;
    }
    bool mayPauseDevicesOnMeteredNetworkConnection() const override final
    {
        return false; // handle pausing of devices on metered network connection only in the service
    }
    const QUrl &syncthingGuiUrl() const
    {
        return m_syncthingGuiUrl;
    }
    bool isUsingUnixDomainSocket() const
    {
        return m_syncthingGuiUrl.scheme() == QLatin1String("unix") && !m_syncthingUnixSocketPath.isEmpty();
    }
    const QString &syncthingRunningStatus() const
    {
        return m_syncthingRunningStatus;
    }
    const QString &meteredStatus() const
    {
        return m_meteredStatus;
    }
    const QString &statusText() const
    {
        return m_statusInfo.statusText();
    }
    const QIcon &statusIcon() const
    {
        return m_statusInfo.statusIcon();
    }
    const QString &additionalStatusText() const
    {
        return m_statusInfo.additionalStatusText();
    }
    /*!
     * \brief Whether scanPath() is available.
     */
    static constexpr bool isScanSupported()
    {
#ifdef Q_OS_ANDROID
        return true;
#else
        return false;
#endif
    }
    /*!
     * \brief Whether the shutdown of the accomanying AppService is manual.
     * \remarks
     * Under Android, the service is supposed to keep running in the background even when the app UI is closed.
     * Hence the service has to be shutdown manually.
     */
    static constexpr bool isServiceShutdownManual()
    {
#ifdef Q_OS_ANDROID
        return true;
#else
        return false;
#endif
    }
    QString fontFamily() const;
    qreal fontScale() const;
    int fontWeightAdjustment() const;
    QFont font() const;
    bool storagePermissionGranted() const;
    bool notificationPermissionGranted() const;
    QString currentSyncthingHomeDir() const;
    QObject *currentDialog();
    const QString &closePreference();

    // helper functions
    Q_INVOKABLE bool initEngine();
#ifdef Q_OS_ANDROID
    Q_INVOKABLE bool destroyEngine();
#endif
    Q_INVOKABLE bool loadMain();
    Q_INVOKABLE bool reloadMain();
    Q_INVOKABLE bool unloadMain();
    Q_INVOKABLE void shutdownService();
    Q_INVOKABLE bool storeSettings();
    Q_INVOKABLE bool applyLauncherSettings();
    Q_INVOKABLE bool applySettings();
    Q_INVOKABLE bool reloadSettings();
    Q_INVOKABLE bool clearLogfile();
    Q_INVOKABLE bool cleanSyncthingHomeDirectory(const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool checkOngoingImportExport();
    Q_INVOKABLE bool openSyncthingConfigFile();
    Q_INVOKABLE bool openSyncthingLogFile();
    Q_INVOKABLE bool openUrlExternally(const QUrl &url, bool viaQt = false);
    Q_INVOKABLE bool checkSettings(QUrl url, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool importSettings(QVariantMap availableSettings, QVariantMap selectedSettings, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool exportSettings(QUrl url, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool checkSyncthingHome(const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool moveSyncthingHome(QString newHomeDir, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool saveSupportBundle(QUrl url, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool openPath(const QString &path);
    Q_INVOKABLE bool openPath(const QString &dirId, const QString &relativePath);
    Q_INVOKABLE bool scanPath(const QString &path);
    Q_INVOKABLE bool copyText(const QString &text);
    Q_INVOKABLE bool copyPath(const QString &dirId, const QString &relativePath);
    Q_INVOKABLE QString getClipboardText() const;
    Q_INVOKABLE bool loadIgnorePatterns(const QString &dirId, QObject *textArea);
    Q_INVOKABLE bool saveIgnorePatterns(const QString &dirId, QObject *textArea);
    Q_INVOKABLE bool openIgnorePatterns(const QString &dirId);
    Q_INVOKABLE bool loadErrors(QObject *listView);
    Q_INVOKABLE bool showLog(QObject *textArea);
    Q_INVOKABLE void clearLog();
    Q_INVOKABLE bool showQrCode(Icon *icon);
    Q_INVOKABLE bool loadDirErrors(const QString &dirId, QObject *view);
    Q_INVOKABLE bool loadStatistics(const QJSValue &callback);
    Q_INVOKABLE bool showError(const QString &errorMessage);
    Q_INVOKABLE void setCurrentControls(bool visible, int tabIndex = -1);
    Q_INVOKABLE bool performHapticFeedback();
    Q_INVOKABLE bool showToast(const QString &message);
    Q_INVOKABLE QString resolveUrl(const QUrl &url);
    Q_INVOKABLE bool shouldIgnorePermissions(const QString &path);
    Q_INVOKABLE Data::SyncthingFileModel *createFileModel(const QString &dirId, QObject *parent);
    Q_INVOKABLE QtGui::DiffHighlighter *createDiffHighlighter(QTextDocument *parent);
    Q_INVOKABLE QVariantList internalErrors() const;
    Q_INVOKABLE void clearInternalErrors();
    Q_INVOKABLE bool postSyncthingConfig(const QJsonObject &rawConfig, const QJSValue &callback = QJSValue());
    Q_INVOKABLE bool invokeDirAction(const QString &dirId, const QString &action);
    Q_INVOKABLE bool requestFromSyncthing(
        const QString &verb, const QString &path, const QVariantMap &parameters, const QJSValue &callback = QJSValue());
    Q_INVOKABLE QString formatDataSize(quint64 size) const;
    Q_INVOKABLE QString formatTraffic(quint64 total, double rate) const;
    Q_INVOKABLE bool hasDevice(const QString &id);
    Q_INVOKABLE bool hasDir(const QString &id);
    Q_INVOKABLE QString deviceDisplayName(const QString &id) const;
    Q_INVOKABLE QString dirDisplayName(const QString &id) const;
    Q_INVOKABLE QVariantList computeDirsNeedingItems(const QModelIndex &devProxyModelIndex) const;
    Q_INVOKABLE QVariant isPopulated(const QString &path) const;
    Q_INVOKABLE bool minimize();
    Q_INVOKABLE void quit();
    Q_INVOKABLE void setPalette(const QColor &foreground, const QColor &background);
    Q_INVOKABLE bool requestStoragePermission();
    Q_INVOKABLE bool requestNotificationPermission();
    Q_INVOKABLE void addDialog(QObject *dialog);
    Q_INVOKABLE void removeDialog(QObject *dialog);
    Q_INVOKABLE void terminateSyncthing();
    Q_INVOKABLE void restartSyncthing();
    Q_INVOKABLE void shutdownSyncthing();
    Q_INVOKABLE void connectToSyncthing();
    Q_INVOKABLE void reconnectToSyncthing();
#ifdef Q_OS_ANDROID
    Q_INVOKABLE void sendMessageToService(ServiceAction action, int arg1 = 0, int arg2 = 0, const QString &str = QString());
    Q_INVOKABLE void handleMessageFromService(ActivityAction action, int arg1, int arg2, const QString &str, const QByteArray &variant);
#endif
    Q_INVOKABLE void handleLauncherStatusBroadcast(const QVariant &status);
    Q_INVOKABLE void requestOpeningUrl(const QUrl &url)
    {
        emit openingUrlRequested(url);
    }

Q_SIGNALS:
    void darkmodeEnabledChanged(bool darkmodeEnabled);
    void internalError(const QtGui::InternalError &error);
    void info(const QString &infoMessage, const QString &details = QString());
    void logsAvailable(const QString &newLogMessages);
    void hasInternalErrorsChanged();
    void internalErrorsRequested();
    void connectionErrorsRequested();
    void savingConfigChanged(bool isSavingConfig);
    void syncthingStartingChanged(bool syncthingStarting);
    void syncthingRunningChanged(bool syncthingRunning);
    void syncthingGuiUrlChanged(const QUrl &syncthingGuiUrl);
    void syncthingRunningStatusChanged(const QString &syncthingRunningStatus);
    void meteredStatusChanged(const QString &meteredStatus);
    void importExportOngoingChanged(bool importExportOngoing);
    void statusInfoChanged();
    void textShared(const QString &text);
    void newDeviceTriggered(const QString &devId);
    void newDirTriggered(const QString &devId, const QString &dirId, const QString &dirLabel);
    void storagePermissionGrantedChanged(bool storagePermissionGranted);
    void notificationPermissionGrantedChanged(bool notificationPermissionGranted);
    void openingUrlRequested(const QUrl &url);
#ifndef Q_OS_ANDROID
    void syncthingTerminationRequested();
    void syncthingRestartRequested();
    void syncthingShutdownRequested();
    void syncthingConnectRequested();
    void syncthingReconnectRequested();
    void settingsReloadRequested();
    void launcherStatusRequested();
    void stoppingLibSyncthingRequested();
    void clearLogRequested();
    void replayLogRequested();
#endif

protected:
    bool eventFilter(QObject *object, QEvent *event) override;

private Q_SLOTS:
    void handleConnectionError(const QString &errorMessage, Data::SyncthingErrorCategory category, int networkError, const QNetworkRequest &request,
        const QByteArray &response);
    void invalidateStatus() override;
    void handleRunningChanged(bool isRunning);
    void handleChangedDevices();
    void handleNewErrors(const std::vector<Data::SyncthingError> &errors);
    void handleStateChanged(Qt::ApplicationState state);
    void handleConnectionStatusChanged(Data::SyncthingStatus newStatus);
#ifdef Q_OS_ANDROID
    void handleAndroidIntent(const QString &page, bool fromNotification);
    void handleStoragePermissionChanged(bool storagePermissionGranted);
    void handleNotificationPermissionChanged(bool notificationPermissionGranted);
#endif

private:
    QString externalFilesDir() const;
    QStringList externalStoragePaths() const;
    void setImportExportStatus(ImportExportStatus importExportStatus);
    void applyDarkmodeChange(bool isDarkColorSchemeEnabled, bool isDarkPaletteEnabled);
    QString locateSettingsExportDir();

    std::optional<QQmlApplicationEngine> m_appEngine;
    QQmlEngine *m_engine;
    QString m_syncthingRunningStatus;
    QUrl m_syncthingGuiUrl;
    QString m_meteredStatus;
    QGuiApplication *m_app;
    QtForkAwesome::QuickImageProvider *m_imageProvider;
    Data::SyncthingDirectoryModel m_dirModel;
    Data::SyncthingSortFilterModel m_sortFilterDirModel;
    Data::SyncthingDeviceModel m_devModel;
    Data::SyncthingSortFilterModel m_sortFilterDevModel;
    Data::SyncthingRecentChangesModel m_changesModel;
    Data::SyncthingConnection::QueryResult m_pendingConfigChange;
#ifdef Q_OS_ANDROID
    mutable std::optional<bool> m_storagePermissionGranted;
    mutable std::optional<bool> m_notificationPermissionGranted;
#endif
    struct {
        QVariantMap availableSettings;
        QVariantMap selectedSettings;
        QJSValue callback;
    } m_settingsImport;
    struct {
        std::optional<QUrl> url;
        QJSValue callback;
    } m_settingsExport;
    struct {
        std::optional<QFile> outputFile;
    } m_download;
    struct {
        std::optional<QString> newHomeDir;
        QJSValue callback;
    } m_homeDirMove;
    std::optional<QString> m_closePreference;
    QtUtilities::QtSettings m_qtSettings;
    QString m_faUrlBase;
    std::array<QObject *, 5> m_uiObjects;
    QObjectList m_dialogs;
    int m_iconSize;
    int m_iconWidthDelegate;
    int m_tabIndex;
    ImportExportStatus m_importExportStatus;
    bool m_clearingLogfile;
    bool m_darkmodeEnabled;
    bool m_darkColorScheme;
    bool m_darkPalette;
    bool m_isGuiLoaded;
    bool m_unloadGuiWhenHidden;
    bool m_isSyncthingStarting;
    bool m_isSyncthingRunning;
    std::atomic_bool m_isManuallyStopped;
};

inline QVariantList App::internalErrors() const
{
    return m_internalErrors;
}

inline QObject *App::currentDialog()
{
    return m_dialogs.isEmpty() ? nullptr : m_dialogs.back();
}

} // namespace QtGui

#endif // SYNCTHING_TRAY_APP_H