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

Multi-window: Tabbed interface

This commit is contained in:
TheSpiritXIII 2015-06-19 10:58:48 -04:00 committed by tux3
parent 22fcc3f7a0
commit fa3ab02cec
12 changed files with 359 additions and 10 deletions

View File

@ -496,7 +496,8 @@ SOURCES += \
src/widget/genericchatitemlayout.cpp \
src/widget/categorywidget.cpp \
src/widget/tool/removefrienddialog.cpp \
src/widget/contentlayout.cpp
src/widget/contentlayout.cpp \
src/widget/contentdialog.cpp
HEADERS += \
src/audio/audio.h \
@ -541,4 +542,5 @@ HEADERS += \
src/widget/genericchatitemlayout.h \
src/widget/categorywidget.h \
src/widget/contentlayout.h \
src/widget/contentdialog.h \
src/widget/tool/removefrienddialog.h

View File

@ -175,6 +175,7 @@ void Settings::loadGlobal()
QStandardPaths::locate(QStandardPaths::HomeLocation, QString(), QStandardPaths::LocateDirectory)
).toString();
separateWindow = s.value("separateWindow", false).toBool();
dontGroupWindows = s.value("dontGroupWindows", false).toBool();
groupchatPosition = s.value("groupchatPosition", true).toBool();
s.endGroup();
@ -217,6 +218,8 @@ void Settings::loadGlobal()
windowGeometry = s.value("windowGeometry", QByteArray()).toByteArray();
windowState = s.value("windowState", QByteArray()).toByteArray();
splitterState = s.value("splitterState", QByteArray()).toByteArray();
dialogGeometry = s.value("dialogGeometry", QByteArray()).toByteArray();
dialogSplitterState = s.value("dialogSplitterState", QByteArray()).toByteArray();
s.endGroup();
s.beginGroup("Audio");
@ -377,6 +380,7 @@ void Settings::saveGlobal()
s.setValue("groupAlwaysNotify", groupAlwaysNotify);
s.setValue("fauxOfflineMessaging", fauxOfflineMessaging);
s.setValue("separateWindow", separateWindow);
s.setValue("dontGroupWindows", dontGroupWindows);
s.setValue("groupchatPosition", groupchatPosition);
s.setValue("autoSaveEnabled", autoSaveEnabled);
s.setValue("globalAutoAcceptDir", globalAutoAcceptDir);
@ -1092,6 +1096,30 @@ void Settings::setSplitterState(const QByteArray &value)
splitterState = value;
}
QByteArray Settings::getDialogGeometry() const
{
QMutexLocker locker{&bigLock};
return dialogGeometry;
}
void Settings::setDialogGeometry(const QByteArray &value)
{
QMutexLocker locker{&bigLock};
dialogGeometry = value;
}
QByteArray Settings::getDialogSplitterState() const
{
QMutexLocker locker{&bigLock};
return dialogSplitterState;
}
void Settings::setDialogSplitterState(const QByteArray &value)
{
QMutexLocker locker{&bigLock};
dialogSplitterState = value;
}
bool Settings::isMinimizeOnCloseEnabled() const
{
QMutexLocker locker{&bigLock};
@ -1338,6 +1366,18 @@ void Settings::setSeparateWindow(bool value)
separateWindow = value;
}
bool Settings::getDontGroupWindows() const
{
QMutexLocker locker{&bigLock};
return dontGroupWindows;
}
void Settings::setDontGroupWindows(bool value)
{
QMutexLocker locker{&bigLock};
dontGroupWindows = value;
}
bool Settings::getGroupchatPosition() const
{
QMutexLocker locker{&bigLock};

View File

@ -217,6 +217,12 @@ public:
QByteArray getSplitterState() const;
void setSplitterState(const QByteArray &value);
QByteArray getDialogGeometry() const;
void setDialogGeometry(const QByteArray& value);
QByteArray getDialogSplitterState() const;
void setDialogSplitterState(const QByteArray &value);
QString getFriendAdress(const QString &publicKey) const;
void updateFriendAdress(const QString &newAddr);
@ -240,6 +246,9 @@ public:
bool getSeparateWindow() const;
void setSeparateWindow(bool value);
bool getDontGroupWindows() const;
void setDontGroupWindows(bool value);
bool getGroupchatPosition() const;
void setGroupchatPosition(bool value);
@ -299,6 +308,7 @@ private:
bool compactLayout;
bool groupchatPosition;
bool separateWindow;
bool dontGroupWindows;
bool enableIPv6;
QString translation;
bool makeToxPortable;
@ -338,6 +348,8 @@ private:
QByteArray windowGeometry;
QByteArray windowState;
QByteArray splitterState;
QByteArray dialogGeometry;
QByteArray dialogSplitterState;
QString style;
bool showSystemTray;

View File

@ -0,0 +1,174 @@
/*
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 "contentdialog.h"
#include "contentlayout.h"
#include "friendwidget.h"
#include "style.h"
#include "tool/adjustingscrollarea.h"
#include "src/persistence/settings.h"
#include "src/friend.h"
#include "src/friendlist.h"
#include <QBoxLayout>
#include <QSplitter>
ContentDialog* ContentDialog::currentDialog = nullptr;
QHash<int, std::tuple<ContentDialog*, GenericChatroomWidget*>> ContentDialog::friendList;
ContentDialog::ContentDialog(QWidget* parent)
: QDialog(parent, Qt::Window)
, activeChatroomWidget(nullptr)
{
QVBoxLayout* boxLayout = new QVBoxLayout(this);
boxLayout->setMargin(0);
boxLayout->setSpacing(0);
splitter = new QSplitter(this);
setStyleSheet("QSplitter{color: rgb(255, 255, 255);background-color: rgb(255, 255, 255);alternate-background-color: rgb(255, 255, 255);border-color: rgb(255, 255, 255);gridline-color: rgb(255, 255, 255);selection-color: rgb(255, 255, 255);selection-background-color: rgb(255, 255, 255);}QSplitter:handle{color: rgb(255, 255, 255);background-color: rgb(255, 255, 255);}");
splitter->setHandleWidth(6);
QWidget *friendWidget = new QWidget();
friendWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
friendWidget->setAutoFillBackground(true);
friendLayout = new QVBoxLayout(friendWidget);
friendLayout->setMargin(0);
friendLayout->setSpacing(0);
friendLayout->addStretch();
QScrollArea *friendScroll = new QScrollArea(this);
friendScroll->setMinimumWidth(220);
friendScroll->setFrameStyle(QFrame::NoFrame);
friendScroll->setLayoutDirection(Qt::RightToLeft);
friendScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
friendScroll->setStyleSheet(Style::getStylesheet(":/ui/friendList/friendList.css"));
friendScroll->setWidgetResizable(true);
friendScroll->setWidget(friendWidget);
QWidget* contentWidget = new QWidget(this);
contentWidget->setAutoFillBackground(true);
contentLayout = new ContentLayout(contentWidget);
contentLayout->setMargin(0);
contentLayout->setSpacing(0);
splitter->addWidget(friendScroll);
splitter->addWidget(contentWidget);
splitter->setStretchFactor(1, 1);
splitter->setCollapsible(1, false);
boxLayout->addWidget(splitter);
setMinimumSize(775, 420);
setAttribute(Qt::WA_DeleteOnClose);
//restore window state
restoreGeometry(Settings::getInstance().getDialogGeometry());
splitter->restoreState(Settings::getInstance().getDialogSplitterState());
currentDialog = this;
}
ContentDialog::~ContentDialog()
{
if (currentDialog == this)
currentDialog = nullptr;
auto friendIt = friendList.begin();
while (friendIt != friendList.end())
{
if (std::get<0>(friendIt.value()) == this)
{
friendIt = friendList.erase(friendIt);
continue;
}
++friendIt;
}
}
void ContentDialog::addFriend(int friendId, QString id)
{
FriendWidget* friendWidget = new FriendWidget(friendId, id);
friendLayout->insertWidget(friendLayout->count() - 1, friendWidget);
onChatroomWidgetClicked(friendWidget);
connect(friendWidget, &FriendWidget::chatroomWidgetClicked, this, &ContentDialog::onChatroomWidgetClicked);
friendList.insert(friendId, std::make_tuple(this, friendWidget));
}
ContentDialog* ContentDialog::current()
{
return currentDialog;
}
bool ContentDialog::showChatroomWidget(int friendId)
{
auto widgetIt = friendList.find(friendId);
if (widgetIt == friendList.end())
return false;
std::get<0>(widgetIt.value())->activateWindow();
std::get<0>(widgetIt.value())->onChatroomWidgetClicked(std::get<1>(widgetIt.value()));
return true;
}
void ContentDialog::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
saveDialogGeometry();
}
void ContentDialog::closeEvent(QCloseEvent* event)
{
saveDialogGeometry();
saveSplitterState();
QWidget::closeEvent(event);
}
void ContentDialog::onChatroomWidgetClicked(GenericChatroomWidget *widget)
{
contentLayout->clear();
if (activeChatroomWidget != nullptr)
activeChatroomWidget->setAsInactiveChatroom();
activeChatroomWidget = widget;
widget->setChatForm(contentLayout);
setWindowTitle(widget->getName());
widget->setAsActiveChatroom();
widget->resetEventFlags();
widget->updateStatusLight();
QString windowTitle = widget->getName();
if (!widget->getStatusString().isNull())
windowTitle += " (" + widget->getStatusString() + ")";
setWindowTitle(windowTitle);
}
void ContentDialog::saveDialogGeometry()
{
Settings::getInstance().setDialogGeometry(saveGeometry());
}
void ContentDialog::saveSplitterState()
{
Settings::getInstance().setDialogSplitterState(splitter->saveState());
}

View File

@ -0,0 +1,62 @@
/*
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 CONTENTDIALOG_H
#define CONTENTDIALOG_H
#include <QDialog>
#include <tuple>
template <typename K, typename V> class QHash;
class QSplitter;
class QVBoxLayout;
class ContentLayout;
class GenericChatroomWidget;
class ContentDialog : public QDialog
{
Q_OBJECT
public:
ContentDialog(QWidget* parent = 0);
~ContentDialog();
void addFriend(int friendId, QString id);
static ContentDialog* current();
static bool showChatroomWidget(int friendId);
protected:
void resizeEvent(QResizeEvent* event) override;
void closeEvent(QCloseEvent* event) override;
private slots:
void onChatroomWidgetClicked(GenericChatroomWidget* widget);
private:
void saveDialogGeometry();
void saveSplitterState();
QSplitter* splitter;
QVBoxLayout* friendLayout;
ContentLayout* contentLayout;
GenericChatroomWidget* activeChatroomWidget;
static ContentDialog* currentDialog;
static QHash<int, std::tuple<ContentDialog*, GenericChatroomWidget*>> friendList;
};
#endif // CONTENTDIALOG_H

View File

@ -88,6 +88,8 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
bodyUI->cbFauxOfflineMessaging->setChecked(Settings::getInstance().getFauxOfflineMessaging());
bodyUI->cbCompactLayout->setChecked(Settings::getInstance().getCompactLayout());
bodyUI->cbSeparateWindow->setChecked(Settings::getInstance().getSeparateWindow());
bodyUI->cbDontGroupWindows->setChecked(Settings::getInstance().getDontGroupWindows());
bodyUI->cbDontGroupWindows->setEnabled(bodyUI->cbSeparateWindow->isChecked());
bodyUI->cbGroupchatPosition->setChecked(Settings::getInstance().getGroupchatPosition());
for (auto entry : SmileyPack::listSmileyPacks())
@ -181,6 +183,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
connect(bodyUI->cbFauxOfflineMessaging, &QCheckBox::stateChanged, this, &GeneralForm::onFauxOfflineMessaging);
connect(bodyUI->cbCompactLayout, &QCheckBox::stateChanged, this, &GeneralForm::onCompactLayout);
connect(bodyUI->cbSeparateWindow, &QCheckBox::stateChanged, this, &GeneralForm::onSeparateWindowChanged);
connect(bodyUI->cbDontGroupWindows, &QCheckBox::stateChanged, this, &GeneralForm::onDontGroupWindowsChanged);
connect(bodyUI->cbGroupchatPosition, &QCheckBox::stateChanged, this, &GeneralForm::onGroupchatPositionChanged);
// prevent stealing mouse whell scroll
@ -434,10 +437,16 @@ void GeneralForm::onCompactLayout()
void GeneralForm::onSeparateWindowChanged()
{
bodyUI->cbDontGroupWindows->setEnabled(bodyUI->cbSeparateWindow->isChecked());
Settings::getInstance().setSeparateWindow(bodyUI->cbSeparateWindow->isChecked());
emit parent->separateWindowToggled(bodyUI->cbSeparateWindow->isChecked());
}
void GeneralForm::onDontGroupWindowsChanged()
{
Settings::getInstance().setDontGroupWindows(bodyUI->cbDontGroupWindows->isChecked());
}
void GeneralForm::onGroupchatPositionChanged()
{
Settings::getInstance().setGroupchatPosition(bodyUI->cbGroupchatPosition->isChecked());

View File

@ -68,6 +68,7 @@ private slots:
void onFauxOfflineMessaging();
void onCompactLayout();
void onSeparateWindowChanged();
void onDontGroupWindowsChanged();
void onGroupchatPositionChanged();
void onThemeColorChanged(int);

View File

@ -377,7 +377,17 @@ instead of system taskbar.</string>
<item>
<widget class="QCheckBox" name="cbSeparateWindow">
<property name="text">
<string>Use separate windows for friend list.</string>
<string>Open chats in separate window.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbDontGroupWindows">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Don't group chat wndows.</string>
</property>
</widget>
</item>

View File

@ -26,6 +26,7 @@
#include "src/core/core.h"
#include "form/chatform.h"
#include "maskablepixmapwidget.h"
#include "contentdialog.h"
#include "src/widget/tool/croppinglabel.h"
#include "src/widget/style.h"
#include "src/persistence/settings.h"
@ -67,6 +68,9 @@ void FriendWidget::contextMenuEvent(QContextMenuEvent * event)
ToxId id = FriendList::findFriend(friendId)->getToxId();
QString dir = Settings::getInstance().getAutoAcceptDir(id);
QMenu menu;
menu.addAction(tr("Open Chat"));
menu.addAction(tr("Open Chat in New Window"));
menu.addSeparator();
QMenu* inviteMenu = menu.addMenu(tr("Invite to group","Menu to invite a friend to a groupchat"));
QMap<QAction*, Group*> groupActions;
@ -296,6 +300,11 @@ QString FriendWidget::getStatusString()
return QString::null;
}
Friend* FriendWidget::getFriend() const
{
return FriendList::findFriend(friendId);
}
void FriendWidget::search(const QString &searchString, bool hide)
{
searchName(searchString, hide);
@ -307,7 +316,7 @@ void FriendWidget::search(const QString &searchString, bool hide)
bool FriendWidget::chatFormIsSet() const
{
Friend* f = FriendList::findFriend(friendId);
return f->getChatForm()->isVisible();
return f->getChatForm()->isVisible() || ContentDialog::showChatroomWidget(friendId);
}
void FriendWidget::setChatForm(ContentLayout* contentLayout)

View File

@ -36,6 +36,7 @@ public:
virtual void setChatForm(ContentLayout* contentLayout) override;
virtual void resetEventFlags() override;
virtual QString getStatusString() override;
virtual Friend* getFriend() const override;
void search(const QString &searchString, bool hide = false);
signals:

View File

@ -27,6 +27,7 @@ class MaskablePixmapWidget;
class QVBoxLayout;
class QHBoxLayout;
class ContentLayout;
class Friend;
class GenericChatroomWidget : public GenericChatItemWidget
{
@ -41,6 +42,7 @@ public:
virtual void setChatForm(ContentLayout* contentLayout) = 0;
virtual void resetEventFlags() = 0;
virtual QString getStatusString() = 0;
virtual Friend* getFriend() const{return nullptr;}
virtual bool eventFilter(QObject *, QEvent *) final override;

View File

@ -22,6 +22,7 @@
#include "ui_mainwindow.h"
#include "src/core/core.h"
#include "src/persistence/settings.h"
#include "contentdialog.h"
#include "src/friend.h"
#include "src/friendlist.h"
#include "tool/friendrequestdialog.h"
@ -534,6 +535,7 @@ void Widget::onSeparateWindowChanged(bool separate, bool clicked)
if (!separate)
{
QWindowList windowList = QGuiApplication::topLevelWindows();
for (QWindow* window : windowList)
{
qDebug() << window->objectName();
@ -542,7 +544,6 @@ void Widget::onSeparateWindowChanged(bool separate, bool clicked)
}
QWidget* contentWidget = new QWidget(this);
contentWidget->setObjectName("yolo");
contentLayout = new ContentLayout(contentWidget);
ui->mainSplitter->addWidget(contentWidget);
@ -553,6 +554,8 @@ void Widget::onSeparateWindowChanged(bool separate, bool clicked)
{
if (contentLayout != nullptr)
{
contentLayout->clear();
contentLayout->parentWidget()->setParent(0); // Remove from splitter.
contentLayout->parentWidget()->hide();
contentLayout->parentWidget()->deleteLater();
contentLayout->deleteLater();
@ -563,6 +566,8 @@ void Widget::onSeparateWindowChanged(bool separate, bool clicked)
if (clicked)
resize(ui->statusPanel->width(), height());
setWindowTitle(QString());
}
if (clicked)
@ -571,9 +576,16 @@ void Widget::onSeparateWindowChanged(bool separate, bool clicked)
void Widget::setWindowTitle(const QString& title)
{
QString tmp = title;
/// <[^>]*> Regexp to remove HTML tags, in case someone used them in title
QMainWindow::setWindowTitle("qTox - " + tmp.remove(QRegExp("<[^>]*>")));
if (title.isEmpty())
{
QMainWindow::setWindowTitle(QApplication::applicationName());
}
else
{
QString tmp = title;
/// <[^>]*> Regexp to remove HTML tags, in case someone used them in title
QMainWindow::setWindowTitle(QApplication::applicationName() + QStringLiteral(" - ") + tmp.remove(QRegExp("<[^>]*>")));
}
}
void Widget::forceShow()
@ -941,12 +953,27 @@ void Widget::onChatroomWidgetClicked(GenericChatroomWidget *widget)
if (Settings::getInstance().getSeparateWindow())
{
if (!widget->chatFormIsSet())
widget->setChatForm(createContentDialog(widget->getName()));
{
ContentDialog* dialog = nullptr;
if (!Settings::getInstance().getDontGroupWindows())
dialog = ContentDialog::current();
if (dialog == nullptr)
dialog = new ContentDialog();
dialog->show();
Friend* frnd = widget->getFriend();
if (frnd != nullptr)
{
dialog->addFriend(frnd->getFriendID(), frnd->getDisplayedName());
}
}
}
else
{
hideMainForms(widget);
widget->setChatForm(contentLayout);
setWindowTitle(widget->getName());
widget->setAsActiveChatroom();
widget->resetEventFlags();
widget->updateStatusLight();
@ -1799,7 +1826,7 @@ void Widget::retranslateUi()
statusOnline->setText(tr("Online", "Button to set your status to 'Online'"));
statusAway->setText(tr("Away", "Button to set your status to 'Away'"));
statusBusy->setText(tr("Busy", "Button to set your status to 'Busy'"));
setWindowTitle(tr("Settings"));
//setWindowTitle(tr("Settings"));
}
#ifdef Q_OS_MAC