1 /*
2  * SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
3  * SPDX-FileCopyrightText: 2017~2017 xzhao <i@xuzhao.net>
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  */
7 
8 #include "mainwindow.h"
9 #include "fcitxqtconfiguifactory.h"
10 #include "fcitxqtcontrollerproxy.h"
11 #include "fcitxqtwatcher.h"
12 #include <QDebug>
13 #include <QLocale>
14 #include <QMessageBox>
15 #include <QPushButton>
16 #include <QWindow>
17 #include <fcitx-utils/i18n.h>
18 
19 namespace fcitx {
20 
MainWindow(const QString & path,FcitxQtConfigUIWidget * pluginWidget,QWidget * parent)21 MainWindow::MainWindow(const QString &path, FcitxQtConfigUIWidget *pluginWidget,
22                        QWidget *parent)
23     : QDialog(parent), path_(path), watcher_(new FcitxQtWatcher(this)),
24       pluginWidget_(pluginWidget), proxy_(0) {
25     setupUi(this);
26     watcher_->setConnection(QDBusConnection::sessionBus());
27     verticalLayout->insertWidget(0, pluginWidget_);
28     buttonBox->button(QDialogButtonBox::Ok)->setText(_("&Ok"));
29     buttonBox->button(QDialogButtonBox::Apply)->setText(_("&Apply"));
30     buttonBox->button(QDialogButtonBox::Reset)->setText(_("&Reset"));
31     buttonBox->button(QDialogButtonBox::Close)->setText(_("&Close"));
32     buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
33     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
34     buttonBox->button(QDialogButtonBox::Reset)->setEnabled(false);
35     setWindowIcon(QIcon::fromTheme(pluginWidget_->icon()));
36     setWindowTitle(pluginWidget_->title());
37 
38     connect(pluginWidget_, &FcitxQtConfigUIWidget::changed, this,
39             &MainWindow::changed);
40     if (pluginWidget_->asyncSave()) {
41         connect(pluginWidget_, &FcitxQtConfigUIWidget::saveFinished, this,
42                 &MainWindow::saveFinished);
43     }
44     connect(pluginWidget_, &FcitxQtConfigUIWidget::saveSubConfig, this,
45             &MainWindow::saveSubConfig);
46     connect(buttonBox, &QDialogButtonBox::clicked, this, &MainWindow::clicked);
47     connect(watcher_, &FcitxQtWatcher::availabilityChanged, this,
48             &MainWindow::availabilityChanged);
49 
50     watcher_->watch();
51 }
52 
availabilityChanged(bool avail)53 void MainWindow::availabilityChanged(bool avail) {
54     if (!avail) {
55         return;
56     }
57     if (proxy_) {
58         delete proxy_;
59     }
60     proxy_ = new FcitxQtControllerProxy(watcher_->serviceName(),
61                                         QLatin1String("/controller"),
62                                         watcher_->connection(), this);
63 }
64 
clicked(QAbstractButton * button)65 void MainWindow::clicked(QAbstractButton *button) {
66     QDialogButtonBox::StandardButton standardButton =
67         buttonBox->standardButton(button);
68     if (standardButton == QDialogButtonBox::Apply ||
69         standardButton == QDialogButtonBox::Ok) {
70         if (pluginWidget_->asyncSave())
71             pluginWidget_->setEnabled(false);
72         if (standardButton == QDialogButtonBox::Ok) {
73             closeAfterSave_ = true;
74         }
75         pluginWidget_->save();
76         if (!pluginWidget_->asyncSave())
77             saveFinished();
78     } else if (standardButton == QDialogButtonBox::Close) {
79         qApp->quit();
80     } else if (standardButton == QDialogButtonBox::Reset) {
81         pluginWidget_->load();
82     }
83 }
84 
saveFinished()85 void MainWindow::saveFinished() {
86     if (proxy_) {
87         // Pass some arbitrary thing.
88         auto watcher = new QDBusPendingCallWatcher(
89             proxy_->SetConfig(path_, QDBusVariant(0)), this);
90         connect(watcher, &QDBusPendingCallWatcher::finished, this,
91                 &MainWindow::saveFinishedPhase2);
92     } else {
93         saveFinishedPhase2(nullptr);
94     }
95 }
96 
saveFinishedPhase2(QDBusPendingCallWatcher * watcher)97 void MainWindow::saveFinishedPhase2(QDBusPendingCallWatcher *watcher) {
98     if (watcher) {
99         watcher->deleteLater();
100     }
101     if (pluginWidget_->asyncSave()) {
102         pluginWidget_->setEnabled(true);
103     }
104     if (!watcher || watcher->isError()) {
105         QMessageBox::warning(
106             this, _("Failed to notify Fcitx"),
107             _("Failed to notify Fcitx about the configuration change."));
108         closeAfterSave_ = false;
109         return;
110     }
111     if (closeAfterSave_) {
112         qApp->quit();
113     }
114 }
115 
saveSubConfig(const QString & path)116 void MainWindow::saveSubConfig(const QString &path) {
117     if (proxy_) {
118         // Pass some arbitrary thing.
119         proxy_->SetConfig(path, QDBusVariant(0));
120     }
121 }
122 
changed(bool changed)123 void MainWindow::changed(bool changed) {
124     buttonBox->button(QDialogButtonBox::Ok)->setEnabled(changed);
125     buttonBox->button(QDialogButtonBox::Apply)->setEnabled(changed);
126     buttonBox->button(QDialogButtonBox::Reset)->setEnabled(changed);
127 }
128 
setParentWindow(WId id)129 void MainWindow::setParentWindow(WId id) { wid_ = id; }
130 
showEvent(QShowEvent * event)131 void MainWindow::showEvent(QShowEvent *event) {
132     if (!wid_) {
133         return;
134     }
135     setAttribute(Qt::WA_NativeWindow, true);
136     QWindow *subWindow = windowHandle();
137     Q_ASSERT(subWindow);
138 
139     QWindow *mainWindow = QWindow::fromWinId(wid_);
140     wid_ = 0;
141     if (!mainWindow) {
142         // foreign windows not supported on all platforms
143         return;
144     }
145     connect(this, &QObject::destroyed, mainWindow, &QObject::deleteLater);
146     subWindow->setTransientParent(mainWindow);
147 
148     QDialog::showEvent(event);
149 }
150 } // namespace fcitx
151