1
0
forked from blue/squawk

some creepy file attaching gui, not sending yet

This commit is contained in:
Blue 2019-09-19 17:31:27 +03:00
parent 2089d6af86
commit 100b2e8943
12 changed files with 424 additions and 6 deletions

View File

@ -25,14 +25,16 @@ set(squawkUI_SRC
widgets/conversation.cpp
widgets/chat.cpp
widgets/room.cpp
widgets/messageline.cpp
widgets/newcontact.cpp
widgets/accounts.cpp
widgets/account.cpp
widgets/joinconference.cpp
widgets/message.cpp
utils/messageline.cpp
utils//message.cpp
utils/resizer.cpp
utils/image.cpp
utils/flowlayout.cpp
utils/badge.cpp
)
# Tell CMake to create the helloworld executable

60
ui/utils/badge.cpp Normal file
View File

@ -0,0 +1,60 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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 "badge.h"
Badge::Badge(const QString& p_id, const QString& p_text, const QIcon& icon, QWidget* parent):
QFrame(parent),
id(p_id),
image(new QLabel()),
text(new QLabel(p_text)),
closeButton(new QPushButton()),
layout(new QHBoxLayout(this))
{
setBackgroundRole(QPalette::Base);
//setAutoFillBackground(true);
setFrameStyle(QFrame::StyledPanel);
setFrameShadow(QFrame::Raised);
image->setPixmap(icon.pixmap(25, 25));
closeButton->setIcon(QIcon::fromTheme("tab-close"));
closeButton->setMaximumHeight(25);
closeButton->setMaximumWidth(25);
layout->addWidget(image);
layout->addWidget(text);
layout->addWidget(closeButton);
layout->setContentsMargins(2, 2, 2, 2);
connect(closeButton, SIGNAL(clicked()), this, SIGNAL(close()));
}
Badge::~Badge()
{
}
bool Badge::Comparator::operator()(const Badge* a, const Badge* b) const
{
return a->id < b->id;
}
bool Badge::Comparator::operator()(const Badge& a, const Badge& b) const
{
return a.id < b.id;
}

56
ui/utils/badge.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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/>.
*/
#ifndef BADGE_H
#define BADGE_H
#include <QFrame>
#include <QLabel>
#include <QHBoxLayout>
#include <QIcon>
#include <QPushButton>
/**
* @todo write docs
*/
class Badge : public QFrame
{
Q_OBJECT
public:
Badge(const QString& id, const QString& text, const QIcon& icon, QWidget* parent = nullptr);
~Badge();
const QString id;
signals:
void close();
private:
QLabel* image;
QLabel* text;
QPushButton* closeButton;
QHBoxLayout* layout;
public:
struct Comparator {
bool operator()(const Badge& a, const Badge& b) const;
bool operator()(const Badge* a, const Badge* b) const;
};
};
#endif // BADGE_H

172
ui/utils/flowlayout.cpp Normal file
View File

@ -0,0 +1,172 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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 "flowlayout.h"
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing):
QLayout(parent),
m_hSpace(hSpacing),
m_vSpace(vSpacing)
{
setContentsMargins(margin, margin, margin, margin);
}
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing):
m_hSpace(hSpacing),
m_vSpace(vSpacing)
{
setContentsMargins(margin, margin, margin, margin);
}
FlowLayout::~FlowLayout()
{
QLayoutItem *item;
while ((item = takeAt(0))) {
delete item;
}
}
void FlowLayout::addItem(QLayoutItem *item)
{
itemList.append(item);
}
int FlowLayout::horizontalSpacing() const
{
if (m_hSpace >= 0) {
return m_hSpace;
} else {
return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
}
}
int FlowLayout::verticalSpacing() const
{
if (m_vSpace >= 0) {
return m_vSpace;
} else {
return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
}
}
int FlowLayout::count() const
{
return itemList.size();
}
QLayoutItem *FlowLayout::itemAt(int index) const
{
return itemList.value(index);
}
QLayoutItem *FlowLayout::takeAt(int index)
{
if (index >= 0 && index < itemList.size()) {
return itemList.takeAt(index);
}
return nullptr;
}
Qt::Orientations FlowLayout::expandingDirections() const
{
return 0;
}
bool FlowLayout::hasHeightForWidth() const
{
return true;
}
int FlowLayout::heightForWidth(int width) const
{
int height = doLayout(QRect(0, 0, width, 0), true);
return height;
}
void FlowLayout::setGeometry(const QRect &rect)
{
QLayout::setGeometry(rect);
doLayout(rect, false);
}
QSize FlowLayout::sizeHint() const
{
return minimumSize();
}
QSize FlowLayout::minimumSize() const
{
QSize size;
for (const QLayoutItem *item : qAsConst(itemList)) {
size = size.expandedTo(item->minimumSize());
}
const QMargins margins = contentsMargins();
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
return size;
}
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
{
int left, top, right, bottom;
getContentsMargins(&left, &top, &right, &bottom);
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
int x = effectiveRect.x();
int y = effectiveRect.y();
int lineHeight = 0;
for (QLayoutItem *item : qAsConst(itemList)) {
const QWidget *wid = item->widget();
int spaceX = horizontalSpacing();
if (spaceX == -1) {
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
}
int spaceY = verticalSpacing();
if (spaceY == -1) {
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
}
int nextX = x + item->sizeHint().width() + spaceX;
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
x = effectiveRect.x();
y = y + lineHeight + spaceY;
nextX = x + item->sizeHint().width() + spaceX;
lineHeight = 0;
}
if (!testOnly) {
item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
}
x = nextX;
lineHeight = qMax(lineHeight, item->sizeHint().height());
}
return y + lineHeight - rect.y() + bottom;
}
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
{
QObject *parent = this->parent();
if (!parent) {
return -1;
} else if (parent->isWidgetType()) {
QWidget *pw = static_cast<QWidget *>(parent);
return pw->style()->pixelMetric(pm, nullptr, pw);
} else {
return static_cast<QLayout *>(parent)->spacing();
}
}

59
ui/utils/flowlayout.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* 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/>.
*/
#ifndef FLOWLAYOUT_H
#define FLOWLAYOUT_H
#include <QLayout>
#include <QWidget>
#include <QStyle>
/**
* @todo write docs
*/
class FlowLayout : public QLayout
{
Q_OBJECT
public:
explicit FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
explicit FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
~FlowLayout();
void addItem(QLayoutItem *item) override;
int horizontalSpacing() const;
int verticalSpacing() const;
Qt::Orientations expandingDirections() const override;
bool hasHeightForWidth() const override;
int heightForWidth(int) const override;
int count() const override;
QLayoutItem *itemAt(int index) const override;
QSize minimumSize() const override;
void setGeometry(const QRect &rect) override;
QSize sizeHint() const override;
QLayoutItem *takeAt(int index) override;
private:
int doLayout(const QRect &rect, bool testOnly) const;
int smartSpacing(QStyle::PixelMetric pm) const;
QList<QLayoutItem *> itemList;
int m_hSpace;
int m_vSpace;
};
#endif // FLOWLAYOUT_H

View File

@ -23,6 +23,7 @@
#include <QTimer>
#include <QGraphicsDropShadowEffect>
#include <QFileDialog>
#include <QMimeDatabase>
Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, const QString pJid, const QString pRes, const QString& acc, QWidget* parent):
QWidget(parent),
@ -40,12 +41,18 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
thread(),
statusIcon(0),
statusLabel(0),
filesLayout(0),
filesToAttach(),
scroll(down),
manualSliderChange(false),
requestingHistory(false),
everShown(false)
{
m_ui->setupUi(this);
filesLayout = new FlowLayout(m_ui->filesPanel, 0);
m_ui->filesPanel->setLayout(filesLayout);
m_ui->splitter->setSizes({300, 0});
m_ui->splitter->setStretchFactor(1, 0);
@ -60,7 +67,7 @@ Conversation::Conversation(bool muc, const QString& mJid, const QString mRes, co
connect(line, SIGNAL(resize(int)), this, SLOT(onMessagesResize(int)));
connect(line, SIGNAL(downloadFile(const QString&, const QString&)), this, SIGNAL(downloadFile(const QString&, const QString&)));
connect(line, SIGNAL(requestLocalFile(const QString&, const QString&)), this, SIGNAL(requestLocalFile(const QString&, const QString&)));
//connect(m_ui->attachButton, SIGNAL(clicked(bool)), this, SLOT(onAttach()));
connect(m_ui->attachButton, SIGNAL(clicked(bool)), this, SLOT(onAttach()));
m_ui->messageEditor->installEventFilter(&ker);
@ -263,7 +270,9 @@ void Conversation::onFileSelected()
{
QFileDialog* d = static_cast<QFileDialog*>(sender());
qDebug() << d->selectedFiles();
for (const QString& path : d->selectedFiles()) {
addAttachedFile(path);
}
d->deleteLater();
}
@ -300,6 +309,49 @@ void Conversation::responseLocalFile(const QString& messageId, const QString& pa
line->responseLocalFile(messageId, path);
}
void Conversation::addAttachedFile(const QString& path)
{
QMimeDatabase db;
QMimeType type = db.mimeTypeForFile(path);
QFileInfo info(path);
Badge* badge = new Badge(path, info.fileName(), QIcon::fromTheme(type.iconName()));
connect(badge, SIGNAL(close()), this, SLOT(onBadgeClose()));
filesToAttach.push_back(badge); //TODO neet to check if there are any duplicated ids
filesLayout->addWidget(badge);
if (filesLayout->count() == 1) {
filesLayout->setContentsMargins(3, 3, 3, 3);
}
}
void Conversation::removeAttachedFile(Badge* badge)
{
W::Order<Badge*, Badge::Comparator>::const_iterator itr = filesToAttach.find(badge);
if (itr != filesToAttach.end()) {
filesToAttach.erase(badge);
if (filesLayout->count() == 1) {
filesLayout->setContentsMargins(0, 0, 0, 0);
}
badge->deleteLater();
}
}
void Conversation::onBadgeClose()
{
Badge* badge = static_cast<Badge*>(sender());
removeAttachedFile(badge);
}
void Conversation::clearAttachedFiles()
{
for (Badge* badge : filesToAttach) {
badge->deleteLater();
}
filesToAttach.clear();
filesLayout->setContentsMargins(0, 0, 0, 0);
}
bool VisibilityCatcher::eventFilter(QObject* obj, QEvent* event)
{
if (event->type() == QEvent::Show) {

View File

@ -22,8 +22,11 @@
#include <QWidget>
#include <QScopedPointer>
#include "../../global.h"
#include "messageline.h"
#include "../../order.h"
#include "../utils/messageline.h"
#include "../utils/resizer.h"
#include "../utils/flowlayout.h"
#include "../utils/badge.h"
namespace Ui
{
@ -87,6 +90,9 @@ protected:
void applyVisualEffects();
virtual void handleSendMessage(const QString& text) = 0;
void setStatus(const QString& status);
void addAttachedFile(const QString& path);
void removeAttachedFile(Badge* badge);
void clearAttachedFiles();
protected slots:
void onEnterPressed();
@ -95,6 +101,7 @@ protected slots:
void onAttach();
void onFileSelected();
void onScrollResize();
void onBadgeClose();
public:
const bool isMuc;
@ -118,6 +125,8 @@ protected:
QString thread;
QLabel* statusIcon;
QLabel* statusLabel;
FlowLayout* filesLayout;
W::Order<Badge*, Badge::Comparator> filesToAttach;
Scroll scroll;
bool manualSliderChange;
bool requestingHistory;

View File

@ -202,7 +202,7 @@
<x>0</x>
<y>0</y>
<width>572</width>
<height>123</height>
<height>118</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
@ -384,6 +384,13 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="filesPanel" native="true">
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="ut" native="true">
<property name="sizePolicy">
@ -443,6 +450,7 @@
</layout>
<zorder>messageEditor</zorder>
<zorder>ut</zorder>
<zorder>filesPanel</zorder>
<zorder>panel</zorder>
</widget>
</widget>