1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Multi-window: OS X window list, fix OS X translations

This commit is contained in:
TheSpiritXIII 2015-07-29 19:46:19 -04:00 committed by tux3
parent 23e7f9326e
commit 97bdaa5e5f
11 changed files with 386 additions and 89 deletions

View File

@ -497,7 +497,8 @@ SOURCES += \
src/widget/categorywidget.cpp \
src/widget/tool/removefrienddialog.cpp \
src/widget/contentlayout.cpp \
src/widget/contentdialog.cpp
src/widget/contentdialog.cpp \
src/widget/tool/activatedialog.cpp
HEADERS += \
src/audio/audio.h \
@ -543,4 +544,5 @@ HEADERS += \
src/widget/categorywidget.h \
src/widget/contentlayout.h \
src/widget/contentdialog.h \
src/widget/tool/activatedialog.h \
src/widget/tool/removefrienddialog.h

View File

@ -42,6 +42,8 @@
#ifdef Q_OS_MAC
#include <QWindow>
#include <QMenuBar>
#include <QActionGroup>
#include <QSignalMapper>
#endif
static Nexus* nexus{nullptr};
@ -89,26 +91,44 @@ void Nexus::start()
qRegisterMetaType<ToxFile::FileDirection>("ToxFile::FileDirection");
qRegisterMetaType<std::shared_ptr<VideoFrame>>("std::shared_ptr<VideoFrame>");
loginScreen = new LoginScreen();
#ifdef Q_OS_MAC
globalMenuBar = new QMenuBar(0);
dockMenu = new QMenu(globalMenuBar);
windowMenu = globalMenuBar->addMenu(tr("Window"));
viewMenu = globalMenuBar->addMenu(QString());
windowMenu = globalMenuBar->addMenu(QString());
globalMenuBar->addAction(windowMenu->menuAction());
QAction* minimizeAction = Nexus::getInstance().windowMenu->addAction(tr("Minimize"));
fullscreenAction = viewMenu->addAction(QString());
fullscreenAction->setShortcut(QKeySequence::FullScreen);
connect(fullscreenAction, &QAction::triggered, this, &Nexus::toggleFullscreen);
minimizeAction = windowMenu->addAction(QString());
minimizeAction->setShortcut(Qt::CTRL + Qt::Key_M);
connect(minimizeAction, &QAction::triggered, [minimizeAction]()
connect(minimizeAction, &QAction::triggered, [this]()
{
minimizeAction->setEnabled(false);
QApplication::focusWindow()->showMinimized();
});
Nexus::getInstance().windowMenu->addSeparator();
windowMenu->addSeparator();
frontAction = windowMenu->addAction(QString());
connect(frontAction, &QAction::triggered, this, &Nexus::bringAllToFront);
QAction* quitAction = new QAction(globalMenuBar);
quitAction->setMenuRole(QAction::QuitRole);
connect(quitAction, &QAction::triggered, qApp, &QApplication::quit);
#endif
loginScreen = new LoginScreen();
windowMapper = new QSignalMapper(this);
connect(windowMapper, SIGNAL(mapped(QObject*)), this, SLOT(onOpenWindow(QObject*)));
connect(loginScreen, &LoginScreen::windowStateChanged, this, &Nexus::onWindowStateChanged);
retranslateUi();
#endif
if (profile)
showMainGUI();
@ -278,3 +298,131 @@ bool Nexus::tryRemoveFile(const QString& filepath)
tmp.remove();
return writable;
}
#ifdef Q_OS_MAC
void Nexus::retranslateUi()
{
viewMenu->menuAction()->setText(tr("View", "OS X Menu bar"));
windowMenu->menuAction()->setText(tr("Window", "OS X Menu bar"));
minimizeAction->setText(tr("Minimize", "OS X Menu bar"));
frontAction->setText((tr("Bring All to Front", "OS X Menu bar")));
}
void Nexus::onWindowStateChanged(Qt::WindowStates state)
{
minimizeAction->setEnabled(QApplication::activeWindow() != nullptr);
if (QApplication::activeWindow() != nullptr && sender() == QApplication::activeWindow())
{
if (state & Qt::WindowFullScreen)
minimizeAction->setEnabled(false);
if (state & Qt::WindowFullScreen)
fullscreenAction->setText(tr("Exit Fullscreen"));
else
fullscreenAction->setText(tr("Enter Fullscreen"));
updateWindows();
}
updateWindowsStates();
}
void Nexus::updateWindows()
{
updateWindowsArg(nullptr);
}
void Nexus::updateWindowsArg(QWindow* closedWindow)
{
QWindowList windowList = QApplication::topLevelWindows();
delete windowActions;
windowActions = new QActionGroup(this);
windowMenu->addSeparator();
QAction* dockLast;
if (dockMenu->actions().count() != 0)
dockLast = dockMenu->actions().first();
else
dockLast = nullptr;
QWindow* activeWindow;
if (QApplication::activeWindow())
activeWindow = QApplication::activeWindow()->windowHandle();
else
activeWindow = nullptr;
for (int i = 0; i < windowList.size(); ++i)
{
if (closedWindow == windowList[i])
continue;
QAction* action = windowActions->addAction(windowList[i]->title());
action->setCheckable(true);
action->setChecked(windowList[i] == activeWindow);
connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
windowMapper->setMapping(action, windowList[i]);
windowMenu->addAction(action);
dockMenu->insertAction(dockLast, action);
}
if (!dockLast->isSeparator())
dockMenu->insertSeparator(dockLast);
}
void Nexus::updateWindowsClosed()
{
updateWindowsArg(static_cast<QWidget*>(sender())->windowHandle());
}
void Nexus::updateWindowsStates()
{
bool exists = false;
QWindowList windowList = QApplication::topLevelWindows();
for (QWindow* window : windowList)
{
if (!(window->windowState() & Qt::WindowMinimized))
{
exists = true;
break;
}
}
frontAction->setEnabled(exists);
}
void Nexus::onOpenWindow(QObject* object)
{
QWindow* window = static_cast<QWindow*>(object);
if (window->windowState() & QWindow::Minimized)
window->showNormal();
window->raise();
window->requestActivate();
}
void Nexus::toggleFullscreen()
{
QWidget* window = QApplication::activeWindow();
if (window->isFullScreen())
window->showNormal();
else
window->showFullScreen();
}
void Nexus::bringAllToFront()
{
QWindowList windowList = QApplication::topLevelWindows();
QWindow* focused = QApplication::focusWindow();
for (QWindow* window : windowList)
window->raise();
focused->raise();
}
#endif

View File

@ -32,6 +32,10 @@ class Core;
#ifdef Q_OS_MAC
class QMenuBar;
class QMenu;
class QAction;
class QWindow;
class QActionGroup;
class QSignalMapper;
#endif
/// This class is in charge of connecting various systems together
@ -59,7 +63,28 @@ public:
#ifdef Q_OS_MAC
QMenuBar* globalMenuBar;
QMenu* viewMenu;
QMenu* windowMenu;
QAction* minimizeAction;
QAction* fullscreenAction;
QAction* frontAction;
QMenu* dockMenu;
public slots:
void retranslateUi();
void onWindowStateChanged(Qt::WindowStates state);
void updateWindows();
void updateWindowsClosed();
void updateWindowsStates();
void onOpenWindow(QObject* object);
void toggleFullscreen();
void bringAllToFront();
private:
void updateWindowsArg(QWindow *closedWindow);
QSignalMapper* windowMapper;
QActionGroup* windowActions = nullptr;
#endif
private:

View File

@ -46,7 +46,7 @@ QHash<int, std::tuple<ContentDialog*, GenericChatroomWidget*>> ContentDialog::fr
QHash<int, std::tuple<ContentDialog*, GenericChatroomWidget*>> ContentDialog::groupList;
ContentDialog::ContentDialog(SettingsWidget* settingsWidget, QWidget* parent)
: QDialog(parent, Qt::Window)
: ActivateDialog(parent, Qt::Window)
, activeChatroomWidget(nullptr)
, settingsWidget(settingsWidget)
{
@ -476,11 +476,15 @@ bool ContentDialog::event(QEvent* event)
}
currentDialog = this;
#ifdef Q_OS_MAC
emit activated();
#endif
default:
break;
}
return QWidget::event(event);
return ActivateDialog::event(event);
}
void ContentDialog::dragEnterEvent(QDragEnterEvent *event)

View File

@ -20,7 +20,7 @@
#ifndef CONTENTDIALOG_H
#define CONTENTDIALOG_H
#include <QDialog>
#include "src/widget/tool/activatedialog.h"
#include <tuple>
#include "src/core/corestructs.h"
#include "src/widget/genericchatitemlayout.h"
@ -37,7 +37,7 @@ class GroupWidget;
class FriendListLayout;
class SettingsWidget;
class ContentDialog : public QDialog
class ContentDialog : public ActivateDialog
{
Q_OBJECT
public:
@ -66,6 +66,11 @@ public:
static ContentDialog* getFriendDialog(int friendId);
static ContentDialog* getGroupDialog(int groupId);
#ifdef Q_OS_MAC
signals:
void activated();
#endif
public slots:
void updateTitleUsername(const QString& username);
void updateTitle(GenericChatroomWidget* chatroomWidget);

View File

@ -97,6 +97,16 @@ void LoginScreen::reset()
ui->autoLoginCB->setChecked(Settings::getInstance().getAutoLogin());
}
#ifdef Q_OS_MAC
bool LoginScreen::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate || event->type() == QEvent::WindowStateChange)
emit windowStateChanged(windowState());
return QWidget::event(event);
}
#endif
void LoginScreen::onNewProfilePageClicked()
{
ui->stackedWidget->setCurrentIndex(0);

View File

@ -37,6 +37,13 @@ public:
~LoginScreen();
void reset(); ///< Resets the UI, clears all fields
#ifdef Q_OS_MAC
bool event(QEvent* event) final override;
signals:
void windowStateChanged(Qt::WindowStates states);
#endif
private slots:
void onAutoLoginToggled(int state);
void onLoginUsernameSelected(const QString& name);

View File

@ -0,0 +1,36 @@
/*
Copyright © 2015 by The qTox Project
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include "activatedialog.h"
#include <QEvent>
ActivateDialog::ActivateDialog(QWidget *parent, Qt::WindowFlags f)
: QDialog(parent, f)
{
}
bool ActivateDialog::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate || event->type() == QEvent::WindowStateChange)
emit windowStateChanged(windowState());
return QDialog::event(event);
}

View File

@ -0,0 +1,36 @@
/*
Copyright © 2015 by The qTox Project
This file is part of qTox, a Qt-based graphical interface for Tox.
qTox is libre software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
qTox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTIVATEDIALOG_H
#define ACTIVATEDIALOG_H
#include <QDialog>
class ActivateDialog : public QDialog
{
Q_OBJECT
public:
ActivateDialog(QWidget* parent = 0, Qt::WindowFlags f = 0);
bool event(QEvent* event) override;
signals:
void windowStateChanged(Qt::WindowStates state);
};
#endif // ACTIVATEDIALOG_H

View File

@ -50,6 +50,7 @@
#include "src/widget/form/profileform.h"
#include "src/widget/form/settingswidget.h"
#include "tool/removefrienddialog.h"
#include "src/widget/tool/activatedialog.h"
#include <cassert>
#include <QMessageBox>
#include <QDebug>
@ -76,6 +77,7 @@
#ifdef Q_OS_MAC
#include <QMenuBar>
#include <QWindow>
#include <QSignalMapper>
#endif
#ifdef Q_OS_ANDROID
@ -243,13 +245,17 @@ void Widget::init()
new QShortcut(Qt::CTRL + Qt::Key_PageDown, this, SLOT(nextContact()));
#ifdef Q_OS_MAC
QMenuBar* globalMenu = Nexus::getInstance().globalMenuBar;
QAction* windowMenu = Nexus::getInstance().windowMenu->menuAction();
QAction* fileMenu = Nexus::getInstance().globalMenuBar->insertMenu(windowMenu, new QMenu(tr("File"), this));
QAction* viewMenu = Nexus::getInstance().viewMenu->menuAction();
QAction* frontAction = Nexus::getInstance().frontAction;
QAction* editProfileAction = fileMenu->menu()->addAction(tr("Edit Profile"));
fileMenu = globalMenu->insertMenu(viewMenu, new QMenu(this));
editProfileAction = fileMenu->menu()->addAction(QString());
connect(editProfileAction, &QAction::triggered, this, &Widget::showProfile);
QMenu* changeStatusMenu = fileMenu->menu()->addMenu(tr("Change Status"));
changeStatusMenu = fileMenu->menu()->addMenu(QString());
fileMenu->menu()->addAction(changeStatusMenu->menuAction());
changeStatusMenu->addAction(statusOnline);
changeStatusMenu->addSeparator();
@ -257,50 +263,47 @@ void Widget::init()
changeStatusMenu->addAction(statusBusy);
fileMenu->menu()->addSeparator();
QAction* logoutAction = fileMenu->menu()->addAction(tr("Log out"));
logoutAction = fileMenu->menu()->addAction(QString());
connect(logoutAction, &QAction::triggered, [this]()
{
Nexus::getInstance().showLogin();
});
QAction* editMenu = Nexus::getInstance().globalMenuBar->insertMenu(windowMenu, new QMenu(tr("Edit"), this));
editMenu = globalMenu->insertMenu(viewMenu, new QMenu(this));
editMenu->menu()->addSeparator();
QAction* viewMenu = Nexus::getInstance().globalMenuBar->insertMenu(windowMenu, new QMenu(tr("View"), this));
viewMenu->menu()->insertMenu(Nexus::getInstance().fullscreenAction, filterMenu);
QMenu* filterMenu = viewMenu->menu()->addMenu(tr("Filter..."));
filterMenu->addAction(filterDisplayName);
filterMenu->addAction(filterDisplayActivity);
filterMenu->addSeparator();
filterMenu->addAction(filterAllAction);
filterMenu->addAction(filterOnlineAction);
filterMenu->addAction(filterOfflineAction);
filterMenu->addAction(filterFriendsAction);
filterMenu->addAction(filterGroupsAction);
viewMenu->menu()->insertSeparator(Nexus::getInstance().fullscreenAction);
viewMenu->menu()->addSeparator();
fullscreenAction = viewMenu->menu()->addAction(tr("Enter Fullscreen"));
fullscreenAction->setShortcut(QKeySequence::FullScreen);
connect(fullscreenAction, &QAction::triggered, this, &Widget::toggleFullscreen);
contactMenu = globalMenu->insertMenu(windowMenu, new QMenu(this));
QAction* contactMenu = Nexus::getInstance().globalMenuBar->insertMenu(windowMenu, new QMenu(tr("Contacts"), this));
QAction* addContactAction = contactMenu->menu()->addAction(tr("Add Contact..."));
addContactAction = contactMenu->menu()->addAction(QString());
connect(addContactAction, &QAction::triggered, this, &Widget::onAddClicked);
QAction* nextConversationAction = new QAction(tr("Next Conversation"), this);
Nexus::getInstance().windowMenu->addAction(nextConversationAction);
nextConversationAction = new QAction(this);
Nexus::getInstance().windowMenu->insertAction(frontAction, nextConversationAction);
nextConversationAction->setShortcut(QKeySequence::SelectNextPage);
connect(nextConversationAction, &QAction::triggered, this, &Widget::nextContact);
connect(nextConversationAction, &QAction::triggered, [this]()
{
if (ContentDialog::current() == QApplication::activeWindow())
ContentDialog::current()->cycleContacts(true);
else if (QApplication::activeWindow() == this)
cycleContacts(true);
});
QAction* previousConversationAction = new QAction(tr("Previous Conversation"), this);
Nexus::getInstance().windowMenu->addAction(previousConversationAction);
previousConversationAction = new QAction(this);
Nexus::getInstance().windowMenu->insertAction(frontAction, previousConversationAction);
previousConversationAction->setShortcut(QKeySequence::SelectPreviousPage);
connect(previousConversationAction, &QAction::triggered, this, &Widget::previousContact);
connect(previousConversationAction, &QAction::triggered, [this]
{
if (ContentDialog::current() == QApplication::activeWindow())
ContentDialog::current()->cycleContacts(false);
else if (QApplication::activeWindow() == this)
cycleContacts(false);
});
Nexus::getInstance().windowMenu->addSeparator();
QAction* frontAction = Nexus::getInstance().windowMenu->addAction(tr("Bring All to Front"));
connect(frontAction, &QAction::triggered, this, &Widget::bringAllToFront);
windowMenu->menu()->insertSeparator(frontAction);
QAction* preferencesAction = viewMenu->menu()->addAction(QString());
preferencesAction->setMenuRole(QAction::PreferencesRole);
@ -313,6 +316,16 @@ void Widget::init()
onSettingsClicked();
settingsWidget->showAbout();
});
QMenu* dockChangeStatusMenu = new QMenu(tr("Status"), this);
dockChangeStatusMenu->addAction(statusOnline);
statusOnline->setIconVisibleInMenu(true);
dockChangeStatusMenu->addSeparator();
dockChangeStatusMenu->addAction(statusAway);
dockChangeStatusMenu->addAction(statusBusy);
Nexus::getInstance().dockMenu->addAction(dockChangeStatusMenu->menuAction());
connect(this, &Widget::windowStateChanged, &Nexus::getInstance(), &Nexus::onWindowStateChanged);
#endif
contentLayout = nullptr;
@ -343,6 +356,8 @@ void Widget::init()
if (!Settings::getInstance().getShowSystemTray())
show();
Nexus::getInstance().updateWindows();
}
bool Widget::eventFilter(QObject *obj, QEvent *event)
@ -357,6 +372,8 @@ bool Widget::eventFilter(QObject *obj, QEvent *event)
else
wasMaximized = false;
}
emit windowStateChanged(windowState());
}
return false;
}
@ -1295,16 +1312,24 @@ void Widget::clearContactsList()
ContentDialog* Widget::createContentDialog() const
{
return new ContentDialog(settingsWidget);
ContentDialog* contentDialog = new ContentDialog(settingsWidget);
contentDialog->show();
#ifdef Q_OS_MAC
connect(contentDialog, &ContentDialog::destroyed, &Nexus::getInstance(), &Nexus::updateWindowsClosed);
connect(contentDialog, &ContentDialog::windowStateChanged, &Nexus::getInstance(), &Nexus::onWindowStateChanged);
connect(contentDialog->windowHandle(), &QWindow::windowTitleChanged, &Nexus::getInstance(), &Nexus::updateWindows);
Nexus::getInstance().updateWindows();
#endif
return contentDialog;
}
ContentLayout* Widget::createContentDialog(DialogType type) const
ContentLayout* Widget::createContentDialog(DialogType type)
{
class Dialog : public QDialog
class Dialog : public ActivateDialog
{
public:
Dialog(DialogType type)
: QDialog()
: ActivateDialog()
, type(type)
{
restoreGeometry(Settings::getInstance().getDialogSettingsGeometry());
@ -1343,7 +1368,7 @@ ContentLayout* Widget::createContentDialog(DialogType type) const
DialogType type;
};
QDialog* dialog = new Dialog(type);
Dialog* dialog = new Dialog(type);
dialog->setAttribute(Qt::WA_DeleteOnClose);
ContentLayout* contentLayoutDialog = new ContentLayout(dialog);
@ -1355,6 +1380,13 @@ ContentLayout* Widget::createContentDialog(DialogType type) const
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
#ifdef Q_OS_MAC
connect(dialog, &Dialog::destroyed, &Nexus::getInstance(), &Nexus::updateWindowsClosed);
connect(dialog, &ActivateDialog::windowStateChanged, &Nexus::getInstance(), &Nexus::updateWindowsStates);
connect(dialog->windowHandle(), &QWindow::windowTitleChanged, &Nexus::getInstance(), &Nexus::updateWindows);
Nexus::getInstance().updateWindows();
#endif
return contentLayoutDialog;
}
@ -1549,6 +1581,14 @@ bool Widget::event(QEvent * e)
eventIcon = false;
updateIcons();
}
#ifdef Q_OS_MAC
emit windowStateChanged(windowState());
case QEvent::WindowStateChange:
Nexus::getInstance().updateWindowsStates();
#endif
default:
break;
}
@ -1630,16 +1670,7 @@ void Widget::onTryCreateTrayIcon()
}
#ifdef Q_OS_MAC
QMenu* changeStatusMenu = new QMenu(tr("Status"), this);
changeStatusMenu->addAction(statusOnline);
statusOnline->setIconVisibleInMenu(true);
changeStatusMenu->addSeparator();
changeStatusMenu->addAction(statusAway);
changeStatusMenu->addAction(statusBusy);
QMenu* dockMenu = new QMenu(this);
dockMenu->addAction(changeStatusMenu->menuAction());
qt_mac_set_dock_menu(dockMenu);
qt_mac_set_dock_menu(Nexus::getInstance().dockMenu);
#endif
}
else if (!isVisible())
@ -2003,33 +2034,20 @@ void Widget::retranslateUi()
if (!Settings::getInstance().getSeparateWindow())
setWindowTitle(fromDialogType(SettingDialog));
}
#ifdef Q_OS_MAC
void Widget::bringAllToFront()
{
QWindowList windowList = QApplication::topLevelWindows();
for (QWindow* window : windowList)
{
window->raise();
window->showNormal();
window->requestActivate();
}
}
Nexus::getInstance().retranslateUi();
void Widget::toggleFullscreen()
{
QWidget* window = QApplication::activeWindow();
filterMenu->menuAction()->setText(tr("Filter..."));
if (window->isFullScreen())
{
window->showNormal();
fullscreenAction->setText(tr("Enter Fullscreen"));
}
else
{
window->showFullScreen();
fullscreenAction->setText(tr("Exit Fullscreen"));
}
}
fileMenu->setText(tr("File"));
editMenu->setText(tr("Edit"));
contactMenu->setText(tr("Contacts"));
changeStatusMenu->menuAction()->setText(tr("Change Status"));
editProfileAction->setText(tr("Edit Profile"));
logoutAction->setText(tr("Log out"));
addContactAction->setText(tr("Add Contact..."));
nextConversationAction->setText(tr("Next Conversation"));
previousConversationAction->setText(tr("Previous Conversation"));
#endif
}

View File

@ -83,7 +83,7 @@ public:
static QString fromDialogType(DialogType type);
ContentDialog* createContentDialog() const;
ContentLayout* createContentDialog(DialogType type) const;
ContentLayout* createContentDialog(DialogType type);
static void confirmExecutableOpen(const QFileInfo file);
@ -147,6 +147,9 @@ signals:
void usernameChanged(const QString& username);
void statusMessageChanged(const QString& statusMessage);
void resized();
#ifdef Q_OS_MAC
void windowStateChanged(Qt::WindowStates states);
#endif
protected:
virtual bool eventFilter(QObject *obj, QEvent *event) final override;
@ -178,11 +181,6 @@ private slots:
void processOfflineMsgs();
void friendListContextMenu(const QPoint &pos);
#ifdef Q_OS_MAC
void bringAllToFront();
void toggleFullscreen();
#endif
private:
enum ActiveToolMenuButton {
AddButton,
@ -263,7 +261,15 @@ private:
bool wasMaximized = false;
#ifdef Q_OS_MAC
QAction* fullscreenAction;
QAction* fileMenu;
QAction* editMenu;
QAction* contactMenu;
QMenu* changeStatusMenu;
QAction* editProfileAction;
QAction* logoutAction;
QAction* addContactAction;
QAction* nextConversationAction;
QAction* previousConversationAction;
#endif
};