mainwindow.cpp 13.4 KB
Newer Older
1
/***************************************************************************
2
 * Copyright (C) 2015-2017 by Savoir-faire Linux                           *
3
 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
4
 * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>          *
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License as published by    *
 * the Free Software Foundation; either version 3 of the License, or       *
 * (at your option) any later version.                                     *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
 **************************************************************************/

#include "mainwindow.h"
#include "ui_mainwindow.h"

23
#include <QDesktopWidget>
Andreas Traczyk's avatar
Andreas Traczyk committed
24
#include <QDir>
25
#include <QScreen>
Andreas Traczyk's avatar
Andreas Traczyk committed
26
#include <QStandardPaths>
27 28
#include <QTimer>
#include <QWindow>
29 30 31

#include "media/text.h"
#include "media/textrecording.h"
32

33
#ifdef Q_OS_WIN
Andreas Traczyk's avatar
Andreas Traczyk committed
34
#include "winsparkle.h"
35 36
#include <QWinThumbnailToolBar>
#include <QWinThumbnailToolButton>
Andreas Traczyk's avatar
Andreas Traczyk committed
37
#include <windows.h>
38 39
#endif

40
#include "aboutdialog.h"
41
#include "callmodel.h"
42
#include "callwidget.h"
Andreas Traczyk's avatar
Andreas Traczyk committed
43
#include "settingskey.h"
44
#include "utils.h"
45
#include "version.h"
46

Andreas Traczyk's avatar
Andreas Traczyk committed
47 48 49
MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    ,
50

51
    ui(new Ui::MainWindow)
52 53
{
    ui->setupUi(this);
54

55 56 57 58
    for (int i = 0; i < ui->navStack->count(); ++i) {
        if (auto navWidget = dynamic_cast<NavWidget*>(ui->navStack->widget(i))) {
            connect(navWidget, &NavWidget::NavigationRequested,
                [this](ScreenEnum scr) {
Andreas Traczyk's avatar
Andreas Traczyk committed
59 60 61 62
                    for (int i = 0; i < ui->navStack->count(); ++i) {
                        if (auto navWidget = dynamic_cast<NavWidget*>(ui->navStack->widget(i))) {
                            navWidget->navigated(scr == i);
                        }
63 64 65 66 67 68 69
                        if (scr == ScreenEnum::WizardScreen) {
                            setWindowTitle(QStringLiteral("Log In"));
                        } else if (scr == ScreenEnum::SetttingsScreen) {
                            setWindowTitle(QStringLiteral("Settings"));
                        } else {
                            setWindowTitle(QStringLiteral("Jami"));
                        }
Andreas Traczyk's avatar
Andreas Traczyk committed
70
                    }
71 72 73 74 75 76
                    Utils::setStackWidget(ui->navStack, ui->navStack->widget(scr));
                });
        }
    }

    connect(ui->navStack, SIGNAL(currentChanged(int)),
Andreas Traczyk's avatar
Andreas Traczyk committed
77 78
        this, SLOT(slotCurrentChanged(int)),
        Qt::QueuedConnection);
79

80
    QIcon icon(":images/jami.png");
81 82
    this->setWindowIcon(icon);

83 84 85
    GlobalSystemTray& sysIcon = GlobalSystemTray::instance();
    sysIcon.setIcon(icon);

86
    QMenu* menu = new QMenu();
87

88 89 90
    auto configAction = new QAction(tr("Settings"), this);
    connect(configAction, &QAction::triggered,
        [this]() {
Andreas Traczyk's avatar
Andreas Traczyk committed
91 92 93 94 95
            if (auto currentWidget = dynamic_cast<NavWidget*>(ui->navStack->currentWidget())) {
                emit currentWidget->NavigationRequested(ScreenEnum::SetttingsScreen);
                setWindowState(Qt::WindowActive);
                showWindow();
            }
96
        });
97 98
    menu->addAction(configAction);

99
    auto exitAction = new QAction(tr("Exit"), this);
100 101 102 103
    connect(exitAction, &QAction::triggered,
        [this]() {
            QCoreApplication::exit();
        });
104 105
    menu->addAction(exitAction);

106 107 108 109
    sysIcon.setContextMenu(menu);
    sysIcon.show();

    connect(&sysIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
Andreas Traczyk's avatar
Andreas Traczyk committed
110
        this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
111

112
#ifdef Q_OS_WIN
Andreas Traczyk's avatar
Andreas Traczyk committed
113
    HMENU sysMenu = ::GetSystemMenu((HWND)winId(), FALSE);
114 115 116
    if (sysMenu != NULL) {
        ::AppendMenuA(sysMenu, MF_SEPARATOR, 0, 0);
        QString aboutTitle = tr("About");
117
        ::AppendMenuW(sysMenu, MF_STRING, IDM_ABOUTBOX, aboutTitle.toStdWString().c_str());
118
    }
119

120
    win_sparkle_set_appcast_url("https://dl.ring.cx/windows/winsparkle-ring.xml");
121
    win_sparkle_set_app_details(L"Savoir-faire Linux", L"Jami", QString(VERSION_STRING).toStdWString().c_str());
122 123
    win_sparkle_set_shutdown_request_callback([]() { QCoreApplication::exit(); });
    win_sparkle_set_did_find_update_callback([]() { MainWindow::instance().showWindow(); });
124 125 126
    win_sparkle_init();

    if (win_sparkle_get_last_check_time() == -1) {
127
        win_sparkle_set_update_check_interval(86400);
128 129 130 131 132
    }

    QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, [=]() {
        win_sparkle_cleanup();
    });
133
#endif
134 135

    setContextMenuPolicy(Qt::NoContextMenu);
136 137

    connect(&GlobalSystemTray::instance(), SIGNAL(messageClicked()), this, SLOT(notificationClicked()));
138 139 140 141 142

    connect(&netManager_, &QNetworkConfigurationManager::onlineStateChanged, [=](bool online) {
        Q_UNUSED(online)
        AccountModel::instance().slotConnectivityChanged();
    });
143

144 145
    auto flags_ = windowFlags();

146
    auto accountList = LRCInstance::accountModel().getAccountList();
147
    lastAccountCount_ = accountList.size();
148
    ScreenEnum startScreen;
149
    if (accountList.size()) {
150 151
        readSettingsFromRegistry();
        startScreen = ScreenEnum::CallScreen;
152
        emit LRCInstance::instance().accountOnBoarded();
153
        setWindowTitle(QStringLiteral("Jami"));
154
    } else {
155
        startScreen = ScreenEnum::WizardScreen;
156
        setWindowTitle(QStringLiteral("Log In"));
157 158 159 160 161
    }

    Utils::setStackWidget(ui->navStack, ui->navStack->widget(startScreen));
    if (startScreen == ScreenEnum::WizardScreen) {
        setWindowSize(startScreen);
162
    }
163 164 165 166 167
    if (auto navWidget = dynamic_cast<NavWidget*>(ui->navStack->widget(startScreen))) {
        navWidget->navigated(true);
    }

    lastScr_ = startScreen;
Andreas Traczyk's avatar
Andreas Traczyk committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185

#ifdef DEBUG_STYLESHEET
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout,
        [this]() {
            QString fileName = "stylesheet.css";
            QDir filePath = QDir(QCoreApplication::applicationDirPath());
            filePath.cdUp();
            filePath.cdUp();
            QFile file(filePath.filePath(fileName));
            if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                auto fileContent = file.readAll();
                setStyleSheet(fileContent);
                file.close();
            }
        });
    timer->start(1000);
#endif
186 187 188 189 190 191 192
}

MainWindow::~MainWindow()
{
    delete ui;
}

Andreas Traczyk's avatar
Andreas Traczyk committed
193
void MainWindow::slotCurrentChanged(int index)
194
{
195
    auto accountList = LRCInstance::accountModel().getAccountList();
Andreas Traczyk's avatar
Andreas Traczyk committed
196 197
    auto firstUse = (accountList.size() == 1 && lastScr_ == ScreenEnum::WizardScreen && lastAccountCount_ < accountList.size()) || !accountList.size();
    if (lastScr_ == ScreenEnum::WizardScreen && lastAccountCount_ < accountList.size()) {
198 199
        lastAccountCount_ = accountList.size();
    }
200

201 202 203 204
    auto scr = Utils::toEnum<ScreenEnum>(index);

    setWindowSize(scr, firstUse);
    lastScr_ = scr;
205 206
}

Andreas Traczyk's avatar
Andreas Traczyk committed
207
void MainWindow::onRingEvent(const QString& uri)
208 209 210 211 212 213 214 215 216
{
    this->showNormal();
    if (not uri.isEmpty()) {
        auto outCall = CallModel::instance().dialingCall();
        outCall->setDialNumber(uri);
        outCall->performAction(Call::Action::ACCEPT);
    }
}

Andreas Traczyk's avatar
Andreas Traczyk committed
217
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
218
{
219
    Q_UNUSED(eventType)
220

221
#ifdef Q_OS_WIN
Andreas Traczyk's avatar
Andreas Traczyk committed
222
    MSG* msg = (MSG*)message;
223 224 225 226 227 228 229 230 231 232

    if (msg->message == WM_SYSCOMMAND) {
        if ((msg->wParam & 0xfff0) == IDM_ABOUTBOX) {
            *result = 0;

            AboutDialog aboutDialog;
            aboutDialog.exec();

            return true;
        }
233
    }
234 235 236
#else
    Q_UNUSED(message)
    Q_UNUSED(result)
237 238
#endif
    return false;
239 240
}

Andreas Traczyk's avatar
Andreas Traczyk committed
241
void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason)
242
{
243 244 245
    if (reason != QSystemTrayIcon::ActivationReason::Context)
        this->show();
}
246

Andreas Traczyk's avatar
Andreas Traczyk committed
247 248
void MainWindow::showWindow()
{
249 250 251 252 253
    if (currentWindowState_ == Qt::WindowMaximized) {
        showMaximized();
    } else {
        showNormal();
    }
254 255
    activateWindow();
    raise();
256 257
}

Andreas Traczyk's avatar
Andreas Traczyk committed
258 259 260 261 262 263 264
void MainWindow::notificationClicked()
{
    if (auto currentWidget = dynamic_cast<NavWidget*>(ui->navStack->currentWidget())) {
        emit currentWidget->NavigationRequested(ScreenEnum::CallScreen);
        setWindowState(Qt::WindowActive);
        showWindow();
    }
265 266
}

Andreas Traczyk's avatar
Andreas Traczyk committed
267
void MainWindow::createThumbBar()
268
{
269 270
#ifdef Q_OS_WIN
    QWinThumbnailToolBar* thumbbar = new QWinThumbnailToolBar(this);
271
    thumbbar->setWindow(this->windowHandle());
272
    QWinThumbnailToolButton* settings = new QWinThumbnailToolButton(thumbbar);
273 274 275 276 277
    settings->setToolTip("Settings");
    QIcon icon(":/images/settings.png");
    settings->setIcon(icon);
    settings->setDismissOnClick(true);
    connect(settings, &QWinThumbnailToolButton::clicked, [this]() {
278
        Utils::setStackWidget(ui->navStack, ui->settingswidget);
279 280 281
    });

    thumbbar->addButton(settings);
282
#endif
283
}
284

Andreas Traczyk's avatar
Andreas Traczyk committed
285
void MainWindow::changeEvent(QEvent* e)
286
{
287 288 289 290 291 292 293 294 295
    if (e->type() == QEvent::WindowStateChange) {
        QWindowStateChangeEvent* event = static_cast<QWindowStateChangeEvent*>(e);
        if (event->oldState() == Qt::WindowNoState && windowState() == Qt::WindowMaximized) {
            currentWindowState_ = Qt::WindowMaximized;
        } else if (event->oldState() == Qt::WindowMaximized && windowState() == Qt::WindowNoState) {
            currentWindowState_ = Qt::WindowNoState;
        }
    }
    QWidget::changeEvent(e);
296
}
Edric Milaret's avatar
Edric Milaret committed
297

Andreas Traczyk's avatar
Andreas Traczyk committed
298
void MainWindow::closeEvent(QCloseEvent* event)
Edric Milaret's avatar
Edric Milaret committed
299
{
300
    Video::PreviewManager::instance().stopPreview();
Andreas Traczyk's avatar
Andreas Traczyk committed
301
    QSettings settings("jami.net", "Jami");
Edric Milaret's avatar
Edric Milaret committed
302 303 304
    if (settings.value(SettingsKey::closeOrMinimized).toBool()) {
        this->hide();
        event->ignore();
305
    } else {
306
        settings.setValue(SettingsKey::geometry, saveGeometry());
307
        settings.setValue(SettingsKey::windowState, saveState());
Andreas Traczyk's avatar
Andreas Traczyk committed
308 309
        this->disconnect(screenChangedConnection_);
        QMainWindow::closeEvent(event);
Edric Milaret's avatar
Edric Milaret committed
310 311
    }
}
312

Andreas Traczyk's avatar
Andreas Traczyk committed
313
void MainWindow::readSettingsFromRegistry()
314
{
Andreas Traczyk's avatar
Andreas Traczyk committed
315 316
    QSettings settings("jami.net", "Jami");

317 318
    restoreGeometry(settings.value(SettingsKey::geometry).toByteArray());
    restoreState(settings.value(SettingsKey::windowState).toByteArray());
319 320

    LRCInstance::editableDataTransferModel()->downloadDirectory = settings.value(SettingsKey::downloadPath,
Andreas Traczyk's avatar
Andreas Traczyk committed
321 322 323 324
                                                                              QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))
                                                                      .toString()
                                                                      .toStdString()
        + "/";
325

326 327
    if (not settings.contains(SettingsKey::enableNotifications)) {
        settings.setValue(SettingsKey::enableNotifications, true);
328
    }
Andreas Traczyk's avatar
Andreas Traczyk committed
329 330 331 332

    if (not settings.contains(SettingsKey::closeOrMinimized)) {
        settings.setValue(SettingsKey::closeOrMinimized, true);
    }
333
}
334

Andreas Traczyk's avatar
Andreas Traczyk committed
335
void MainWindow::setWindowSize(ScreenEnum scr, bool firstUse)
336 337 338 339 340 341
{
    auto screenNumber = qApp->desktop()->screenNumber();
    auto accountList = LRCInstance::accountModel().getAccountList();
    if (scr == ScreenEnum::WizardScreen && !accountList.size()) {
        hide();
        setFixedSize(wizardDialogWidth, wizardDialogHeight);
342 343 344
    } else {
        setMinimumSize(mainWindowMinWidth, mainWindowMinHeight);
        setMaximumSize(QtMaxDimension, QtMaxDimension);
345 346 347 348 349 350 351
    }
    if (firstUse || !accountList.size()) {
        setGeometry(
            QStyle::alignedRect(
                Qt::LeftToRight,
                Qt::AlignCenter,
                size(),
Andreas Traczyk's avatar
Andreas Traczyk committed
352
                qApp->desktop()->screenGeometry(screenNumber)));
353 354 355 356 357 358 359 360 361 362 363 364 365
        if (scr == ScreenEnum::WizardScreen) {
            setWindowFlags(Qt::Dialog);
            setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
            adjustSize();
        } else {
            setWindowFlags(flags_);
        }
        updateGeometry();
        update();
        show();
    }
}

Andreas Traczyk's avatar
Andreas Traczyk committed
366
void MainWindow::show()
367 368 369 370
{
    QMainWindow::show();
    disconnect(screenChangedConnection_);
    screenChangedConnection_ = connect(windowHandle(), &QWindow::screenChanged,
Andreas Traczyk's avatar
Andreas Traczyk committed
371
        this, &MainWindow::slotScreenChanged);
372 373 374
    auto screenNumber = qApp->desktop()->screenNumber();
    QScreen* screen = qApp->screens().at(screenNumber);
    currentScalingRatio_ = screen->logicalDotsPerInchX() / 96;
375
    qobject_cast<NavWidget*>(ui->navStack->currentWidget())->updateCustomUI();
376 377
}

Andreas Traczyk's avatar
Andreas Traczyk committed
378
void MainWindow::slotScreenChanged(QScreen* screen)
379 380 381 382 383 384 385 386 387
{
    adjustSize();
    updateGeometry();
    update();
    currentScalingRatio_ = screen->logicalDotsPerInchX() / 96;
    // a little delay won't hurt ;)
    QTimer::singleShot(100, this,
        [this] {
            qobject_cast<NavWidget*>(ui->navStack->currentWidget())->updateCustomUI();
388 389
        });
}
Andreas Traczyk's avatar
Andreas Traczyk committed
390

Andreas Traczyk's avatar
Andreas Traczyk committed
391
void MainWindow::resizeEvent(QResizeEvent* event)
Andreas Traczyk's avatar
Andreas Traczyk committed
392 393 394 395
{
    Q_UNUSED(event);
    qobject_cast<NavWidget*>(ui->navStack->currentWidget())->updateCustomUI();
}
396

Andreas Traczyk's avatar
Andreas Traczyk committed
397
float MainWindow::getCurrentScalingRatio()
398 399
{
    return currentScalingRatio_;
400 401 402 403 404 405
}

void MainWindow::keyReleaseEvent(QKeyEvent* ke)
{
    emit keyReleased(ke);
    QMainWindow::keyReleaseEvent(ke);
Andreas Traczyk's avatar
Andreas Traczyk committed
406
}