244 lines
6.7 KiB
C++
244 lines
6.7 KiB
C++
// Copyright 2020-2023 The Mumble Developers. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file at the root of the
|
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
#include "TalkingUIContainer.h"
|
|
#include "TalkingUIEntry.h"
|
|
|
|
#include <QGroupBox>
|
|
#include <QVBoxLayout>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
struct entry_ptr_less {
|
|
bool operator()(const std::unique_ptr< TalkingUIEntry > &first, const std::unique_ptr< TalkingUIEntry > &second) {
|
|
return *first < *second;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
TalkingUIContainer::TalkingUIContainer(int associatedChannelID, TalkingUI &talkingUI)
|
|
: m_associatedChannelID(associatedChannelID), m_talkingUI(talkingUI) {
|
|
}
|
|
|
|
|
|
int TalkingUIContainer::find(unsigned int associatedUserSession, EntryType type) const {
|
|
for (std::size_t i = 0; i < m_entries.size(); i++) {
|
|
const std::unique_ptr< TalkingUIEntry > ¤tEntry = m_entries[i];
|
|
if (currentEntry->getType() == type && currentEntry->getAssociatedUserSession() == associatedUserSession) {
|
|
return static_cast< int >(i);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int TalkingUIContainer::getAssociatedChannelID() const {
|
|
return m_associatedChannelID;
|
|
}
|
|
|
|
void TalkingUIContainer::addEntry(std::unique_ptr< TalkingUIEntry > entry) {
|
|
// set container
|
|
entry->m_container = this;
|
|
|
|
m_entries.push_back(std::move(entry));
|
|
}
|
|
|
|
std::unique_ptr< TalkingUIEntry > TalkingUIContainer::removeEntry(const TalkingUIEntry *entry) {
|
|
return removeEntry(entry->getAssociatedUserSession(), entry->getType());
|
|
}
|
|
|
|
std::unique_ptr< TalkingUIEntry > TalkingUIContainer::removeEntry(unsigned int associatedUserSession, EntryType type) {
|
|
int index = find(associatedUserSession, type);
|
|
|
|
std::unique_ptr< TalkingUIEntry > entry(nullptr);
|
|
|
|
if (index >= 0) {
|
|
// Move the entry out of the vector
|
|
entry = std::move(m_entries[static_cast< std::size_t >(index)]);
|
|
m_entries.erase(m_entries.begin() + index);
|
|
|
|
// reset container
|
|
entry->m_container = nullptr;
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
std::vector< std::unique_ptr< TalkingUIEntry > > &TalkingUIContainer::getEntries() {
|
|
return m_entries;
|
|
}
|
|
|
|
const std::vector< std::unique_ptr< TalkingUIEntry > > &TalkingUIContainer::getEntries() const {
|
|
return m_entries;
|
|
}
|
|
|
|
bool TalkingUIContainer::contains(unsigned int associatedUserSession, EntryType type) const {
|
|
return find(associatedUserSession, type) >= 0;
|
|
}
|
|
|
|
std::size_t TalkingUIContainer::size() const {
|
|
return m_entries.size();
|
|
}
|
|
|
|
bool TalkingUIContainer::isEmpty() const {
|
|
return size() == 0;
|
|
}
|
|
|
|
void TalkingUIContainer::setPermanent(bool permanent) {
|
|
m_permanent = permanent;
|
|
}
|
|
|
|
bool TalkingUIContainer::isPermanent() const {
|
|
return m_permanent;
|
|
}
|
|
|
|
TalkingUIEntry *TalkingUIContainer::get(unsigned int associatedUserSession, EntryType type) {
|
|
int index = find(associatedUserSession, type);
|
|
|
|
if (index >= 0) {
|
|
return m_entries[static_cast< std::size_t >(index)].get();
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
bool TalkingUIContainer::operator==(const TalkingUIContainer &other) const {
|
|
return compare(other) == 0;
|
|
}
|
|
|
|
bool TalkingUIContainer::operator!=(const TalkingUIContainer &other) const {
|
|
return compare(other) != 0;
|
|
}
|
|
|
|
bool TalkingUIContainer::operator>(const TalkingUIContainer &other) const {
|
|
return compare(other) > 0;
|
|
}
|
|
|
|
bool TalkingUIContainer::operator>=(const TalkingUIContainer &other) const {
|
|
return compare(other) >= 0;
|
|
}
|
|
|
|
bool TalkingUIContainer::operator<(const TalkingUIContainer &other) const {
|
|
return compare(other) < 0;
|
|
}
|
|
|
|
bool TalkingUIContainer::operator<=(const TalkingUIContainer &other) const {
|
|
return compare(other) <= 0;
|
|
}
|
|
|
|
|
|
|
|
const int CHANNEL_LAYOUT_TOP_MARGIN = 10;
|
|
|
|
TalkingUIChannel::TalkingUIChannel(int associatedChannelID, QString name, TalkingUI &talkingUI)
|
|
: TalkingUIContainer(associatedChannelID, talkingUI), m_channelBox(new QGroupBox()),
|
|
m_channelBoxStyleWrapper(m_channelBox) {
|
|
// Set name
|
|
m_channelBox->setTitle(name);
|
|
|
|
// Don't inherit the background color set on the channel box to its children.
|
|
m_channelBoxStyleWrapper.setBackgroundColorSelector("TalkingUI > QGroupBox");
|
|
|
|
// Set layout
|
|
QVBoxLayout *layout = new QVBoxLayout();
|
|
layout->setContentsMargins(0, CHANNEL_LAYOUT_TOP_MARGIN, 0, 0);
|
|
m_channelBox->setLayout(layout);
|
|
}
|
|
|
|
TalkingUIChannel::~TalkingUIChannel() {
|
|
m_channelBox->deleteLater();
|
|
}
|
|
|
|
void TalkingUIChannel::updatePriority() {
|
|
// First reset the priority to the lowest possible value as the loop below
|
|
// will only update it to be higher than the current priority
|
|
m_highestUserPriority = EntryPriority::LOWEST;
|
|
|
|
for (auto ¤tEntry : m_entries) {
|
|
if (currentEntry->getPriority() > m_highestUserPriority) {
|
|
m_highestUserPriority = currentEntry->getPriority();
|
|
}
|
|
}
|
|
}
|
|
|
|
QString TalkingUIChannel::getName() const {
|
|
return m_channelBox->title();
|
|
}
|
|
|
|
void TalkingUIChannel::setName(const QString &name) {
|
|
m_channelBox->setTitle(name);
|
|
}
|
|
|
|
int TalkingUIChannel::compare(const TalkingUIContainer &other) const {
|
|
if (getType() != other.getType()) {
|
|
return static_cast< int >(other.getType()) - static_cast< int >(getType());
|
|
}
|
|
|
|
const TalkingUIChannel &otherChannel = static_cast< const TalkingUIChannel & >(other);
|
|
|
|
if (m_highestUserPriority != otherChannel.m_highestUserPriority) {
|
|
return m_highestUserPriority < otherChannel.m_highestUserPriority ? 1 : -1;
|
|
}
|
|
|
|
int res = getName().localeAwareCompare(otherChannel.getName());
|
|
|
|
if (res == 0) {
|
|
// Only consider channels to be the same if they have the same associated ID
|
|
res = otherChannel.getAssociatedChannelID() - getAssociatedChannelID();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
QWidget *TalkingUIChannel::getWidget() {
|
|
return m_channelBox;
|
|
}
|
|
|
|
const QWidget *TalkingUIChannel::getWidget() const {
|
|
return m_channelBox;
|
|
}
|
|
|
|
MultiStyleWidgetWrapper &TalkingUIChannel::getStylableWidget() {
|
|
return m_channelBoxStyleWrapper;
|
|
}
|
|
|
|
ContainerType TalkingUIChannel::getType() const {
|
|
return ContainerType::CHANNEL;
|
|
}
|
|
|
|
void TalkingUIChannel::addEntry(std::unique_ptr< TalkingUIEntry > entry) {
|
|
if (entry->getPriority() > m_highestUserPriority) {
|
|
m_highestUserPriority = entry->getPriority();
|
|
}
|
|
TalkingUIContainer::addEntry(std::move(entry));
|
|
|
|
// Remove all entries from the layout
|
|
for (const auto ¤tEntry : m_entries) {
|
|
m_channelBox->layout()->removeWidget(currentEntry->getWidget());
|
|
}
|
|
|
|
// Sort entries
|
|
std::sort(m_entries.begin(), m_entries.end(), entry_ptr_less());
|
|
|
|
// Add all entries again (including the new one) in order
|
|
for (auto ¤tEntry : m_entries) {
|
|
m_channelBox->layout()->addWidget(currentEntry->getWidget());
|
|
}
|
|
}
|
|
|
|
std::unique_ptr< TalkingUIEntry > TalkingUIChannel::removeEntry(unsigned int associatedUserSession, EntryType type) {
|
|
std::unique_ptr< TalkingUIEntry > entry = TalkingUIContainer::removeEntry(associatedUserSession, type);
|
|
|
|
if (entry) {
|
|
m_channelBox->layout()->removeWidget(entry->getWidget());
|
|
}
|
|
|
|
updatePriority();
|
|
|
|
return entry;
|
|
}
|